diff --git a/package.json b/package.json
index 1fef3a44..70e95077 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@stellar/wallet-sdk",
- "version": "0.0.6-rc.12",
+ "version": "0.0.6-rc.13",
"description": "Libraries to help you write Stellar-enabled wallets in Javascript",
"main": "dist/index.js",
"types": "dist/index.d.ts",
diff --git a/playground/package.json b/playground/package.json
index a9183bc1..43ff47a0 100644
--- a/playground/package.json
+++ b/playground/package.json
@@ -5,6 +5,7 @@
"dependencies": {
"@stellar/elements": "^0.0.0",
"lodash": "^4.17.14",
+ "moment": "^2.24.0",
"react": "^16.8.5",
"react-dom": "^16.8.5",
"react-json-view": "^1.19.1",
diff --git a/playground/src/components/Transfers.js b/playground/src/components/Transfers.js
index cdbd0c34..6ac3c7c0 100644
--- a/playground/src/components/Transfers.js
+++ b/playground/src/components/Transfers.js
@@ -1,4 +1,6 @@
import React, { Component } from "react";
+import moment from "moment";
+import Json from "react-json-view";
class Transfers extends Component {
state = {
@@ -42,25 +44,25 @@ class Transfers extends Component {
streamEnder: null,
});
- // const streamEnder = dataProvider.watchTransfers({
- // onMessage: (transfer) => {
- // this.setState({
- // transfers: [
- // { transfer, updateTime: new Date() },
- // ...this.state.transfers,
- // ],
- // });
- // },
- // onError: (err) => {
- // console.log("error: ", err);
- // this.setState({ err });
- // streamEnder();
- // },
- // });
+ const streamEnder = dataProvider.watchTransfers({
+ onMessage: (transfer) => {
+ this.setState({
+ transfers: [
+ { transfer, updateTime: new Date() },
+ ...this.state.transfers,
+ ],
+ });
+ },
+ onError: (err) => {
+ console.log("error: ", err);
+ this.setState({ err });
+ streamEnder();
+ },
+ });
- // this.setState({
- // streamEnder,
- // });
+ this.setState({
+ streamEnder,
+ });
};
render() {
@@ -68,19 +70,28 @@ class Transfers extends Component {
return (
Transfers
-
-
- not implemented yet
-
-
{err &&
Error: {err.toString()}
}
diff --git a/playground/yarn.lock b/playground/yarn.lock
index b599b440..c49e45ac 100644
--- a/playground/yarn.lock
+++ b/playground/yarn.lock
@@ -6598,6 +6598,11 @@ mkdirp@0.5.1, mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1:
dependencies:
minimist "0.0.8"
+moment@^2.24.0:
+ version "2.24.0"
+ resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b"
+ integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==
+
move-concurrently@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"
diff --git a/src/data/DataProvider.ts b/src/data/DataProvider.ts
index 704422e0..25c08537 100644
--- a/src/data/DataProvider.ts
+++ b/src/data/DataProvider.ts
@@ -30,16 +30,22 @@ function isAccount(obj: any): obj is Account {
interface CallbacksObject {
accountDetails?: () => void;
+ transfers?: () => void;
}
interface ErrorHandlersObject {
accountDetails?: (error: any) => void;
+ transfers?: (error: any) => void;
+}
+
+interface WatcherTimeoutsObject {
+ [name: string]: ReturnType
;
}
export class DataProvider {
private accountKey: string;
private serverUrl: string;
- private unfundedWatcherTimeout: any;
+ private _watcherTimeouts: WatcherTimeoutsObject;
private effectStreamEnder?: () => void;
private callbacks: CallbacksObject;
@@ -69,7 +75,7 @@ export class DataProvider {
this.errorHandlers = {};
this.serverUrl = params.serverUrl;
this.accountKey = accountKey;
- this.unfundedWatcherTimeout = null;
+ this._watcherTimeouts = {};
}
/**
@@ -209,7 +215,7 @@ export class DataProvider {
// otherwise, if it's a 404, try again in a bit.
.catch((err) => {
if (err.isUnfunded) {
- this.unfundedWatcherTimeout = setTimeout(() => {
+ this._watcherTimeouts.watchAccountDetails = setTimeout(() => {
this.watchAccountDetails(params);
}, 2000);
} else {
@@ -219,8 +225,68 @@ export class DataProvider {
// if they exec this function, don't make the balance callback do anything
return () => {
- if (this.unfundedWatcherTimeout) {
- clearTimeout(this.unfundedWatcherTimeout);
+ if (this._watcherTimeouts.watchAccountDetails) {
+ clearTimeout(this._watcherTimeouts.watchAccountDetails);
+ }
+
+ delete this.callbacks.accountDetails;
+ delete this.errorHandlers.accountDetails;
+ };
+ }
+
+ /**
+ * Fetch transfers, then re-fetch whenever the details update.
+ * Returns a function you can execute to stop the watcher.
+ */
+ public watchTransfers(params: WatcherParams): () => void {
+ const { onMessage, onError } = params;
+
+ let getNextTransfers: () => Promise>;
+
+ this.fetchTransfers()
+
+ // if the account is funded, watch for effects.
+ .then((res) => {
+ // reset the transfer cache
+ getNextTransfers = res.prev;
+
+ // onMessage each transfer separately
+ res.records.forEach(onMessage);
+
+ this.callbacks.transfers = debounce(() => {
+ getNextTransfers()
+ .then((nextRes) => {
+ getNextTransfers = nextRes.prev;
+
+ // get new things
+ if (nextRes.records.length) {
+ nextRes.records.forEach(onMessage);
+ }
+ })
+ .catch(onError);
+ }, 2000);
+ this.errorHandlers.transfers = onError;
+
+ this._startEffectWatcher().catch((err) => {
+ onError(err);
+ });
+ })
+
+ // otherwise, if it's a 404, try again in a bit.
+ .catch((err) => {
+ if (err.isUnfunded) {
+ this._watcherTimeouts.watchTransfers = setTimeout(() => {
+ this.watchTransfers(params);
+ }, 2000);
+ } else {
+ onError(err);
+ }
+ });
+
+ // if they exec this function, don't make the balance callback do anything
+ return () => {
+ if (this._watcherTimeouts.watchTransfers) {
+ clearTimeout(this._watcherTimeouts.watchTransfers);
}
delete this.callbacks.accountDetails;
@@ -244,8 +310,8 @@ export class DataProvider {
const tradeResponses = await Promise.all(tradeRequests);
return {
- next: () => offers.next().then(this._processOpenOffers),
- prev: () => offers.prev().then(this._processOpenOffers),
+ next: () => offers.next().then((res) => this._processOpenOffers(res)),
+ prev: () => offers.prev().then((res) => this._processOpenOffers(res)),
records: makeDisplayableOffers(
{ publicKey: this.accountKey },
{
@@ -263,8 +329,8 @@ export class DataProvider {
trades: ServerApi.CollectionPage,
): Promise> {
return {
- next: () => trades.next().then(this._processTrades),
- prev: () => trades.prev().then(this._processTrades),
+ next: () => trades.next().then((res) => this._processTrades(res)),
+ prev: () => trades.prev().then((res) => this._processTrades(res)),
records: makeDisplayableTrades(
{ publicKey: this.accountKey },
trades.records,
@@ -280,8 +346,8 @@ export class DataProvider {
>,
): Promise> {
return {
- next: () => transfers.next().then(this._processTransfers),
- prev: () => transfers.prev().then(this._processTransfers),
+ next: () => transfers.next().then((res) => this._processTransfers(res)),
+ prev: () => transfers.prev().then((res) => this._processTransfers(res)),
records: makeDisplayableTransfers(
{ publicKey: this.accountKey },
transfers.records,