@accesly/react 1.1.3 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -1
- package/dist/index.cjs +255 -206
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +116 -59
- package/dist/index.d.ts +116 -59
- package/dist/index.js +254 -207
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -11,6 +11,7 @@ var AcceslyContext = react.createContext(null);
|
|
|
11
11
|
var ENVIRONMENT_DEFAULTS = {
|
|
12
12
|
dev: {
|
|
13
13
|
apiUrl: "https://3fki7eiio5.execute-api.us-east-1.amazonaws.com/dev",
|
|
14
|
+
walletStreamUrl: "https://ajlmn37thw7fxen3oyykbfmlrm0eecue.lambda-url.us-east-1.on.aws/",
|
|
14
15
|
cognito: {
|
|
15
16
|
region: "us-east-1",
|
|
16
17
|
userPoolId: "us-east-1_K2Nag1tB1",
|
|
@@ -28,6 +29,7 @@ var ENVIRONMENT_DEFAULTS = {
|
|
|
28
29
|
},
|
|
29
30
|
staging: {
|
|
30
31
|
apiUrl: "https://api-staging.accesly.xyz",
|
|
32
|
+
walletStreamUrl: "",
|
|
31
33
|
cognito: {
|
|
32
34
|
region: "us-east-1",
|
|
33
35
|
userPoolId: "TBD-staging",
|
|
@@ -43,6 +45,7 @@ var ENVIRONMENT_DEFAULTS = {
|
|
|
43
45
|
},
|
|
44
46
|
prod: {
|
|
45
47
|
apiUrl: "https://api.accesly.xyz",
|
|
48
|
+
walletStreamUrl: "",
|
|
46
49
|
cognito: {
|
|
47
50
|
region: "us-east-1",
|
|
48
51
|
userPoolId: "TBD-prod",
|
|
@@ -928,8 +931,133 @@ function base64ToBytes(s) {
|
|
|
928
931
|
for (let i = 0; i < bin.length; i += 1) arr[i] = bin.charCodeAt(i);
|
|
929
932
|
return arr;
|
|
930
933
|
}
|
|
934
|
+
|
|
935
|
+
// src/hooks/walletSubscription.ts
|
|
936
|
+
var ACTIVITY_BUFFER_MAX = 50;
|
|
937
|
+
var subscriptions = /* @__PURE__ */ new Map();
|
|
938
|
+
function buildSubscriptionUrl(streamUrl, walletAddress) {
|
|
939
|
+
const base = streamUrl.replace(/\/$/, "");
|
|
940
|
+
return `${base}/?walletAddress=${encodeURIComponent(walletAddress)}`;
|
|
941
|
+
}
|
|
942
|
+
function openConnection(state) {
|
|
943
|
+
if (state.eventSource) return;
|
|
944
|
+
if (typeof EventSource === "undefined") return;
|
|
945
|
+
let es;
|
|
946
|
+
try {
|
|
947
|
+
es = new EventSource(state.url, { withCredentials: false });
|
|
948
|
+
} catch (err) {
|
|
949
|
+
console.warn("[walletSubscription] EventSource construction failed", err);
|
|
950
|
+
return;
|
|
951
|
+
}
|
|
952
|
+
state.eventSource = es;
|
|
953
|
+
es.addEventListener("status", (ev) => {
|
|
954
|
+
try {
|
|
955
|
+
const data = JSON.parse(ev.data);
|
|
956
|
+
state.lastStatus = data;
|
|
957
|
+
for (const listener of state.listeners.status) listener(data);
|
|
958
|
+
} catch {
|
|
959
|
+
}
|
|
960
|
+
});
|
|
961
|
+
es.addEventListener("balance", (ev) => {
|
|
962
|
+
try {
|
|
963
|
+
const data = JSON.parse(ev.data);
|
|
964
|
+
state.lastBalance = data;
|
|
965
|
+
for (const listener of state.listeners.balance) listener(data);
|
|
966
|
+
} catch {
|
|
967
|
+
}
|
|
968
|
+
});
|
|
969
|
+
es.addEventListener("activity", (ev) => {
|
|
970
|
+
try {
|
|
971
|
+
const data = JSON.parse(ev.data);
|
|
972
|
+
const merged = [...data.events, ...state.activityBuffer];
|
|
973
|
+
const seen = /* @__PURE__ */ new Set();
|
|
974
|
+
const deduped = [];
|
|
975
|
+
for (const item of merged) {
|
|
976
|
+
const key = `${item.txHash}:${item.ledger}`;
|
|
977
|
+
if (seen.has(key)) continue;
|
|
978
|
+
seen.add(key);
|
|
979
|
+
deduped.push(item);
|
|
980
|
+
if (deduped.length >= ACTIVITY_BUFFER_MAX) break;
|
|
981
|
+
}
|
|
982
|
+
state.activityBuffer = deduped;
|
|
983
|
+
for (const listener of state.listeners.activity) {
|
|
984
|
+
listener({ events: state.activityBuffer });
|
|
985
|
+
}
|
|
986
|
+
} catch {
|
|
987
|
+
}
|
|
988
|
+
});
|
|
989
|
+
es.addEventListener("close", () => {
|
|
990
|
+
});
|
|
991
|
+
es.onerror = () => {
|
|
992
|
+
};
|
|
993
|
+
}
|
|
994
|
+
function closeConnection(state) {
|
|
995
|
+
if (!state.eventSource) return;
|
|
996
|
+
state.eventSource.close();
|
|
997
|
+
state.eventSource = null;
|
|
998
|
+
}
|
|
999
|
+
function getOrCreateSubscription(streamUrl, walletAddress) {
|
|
1000
|
+
const existing = subscriptions.get(walletAddress);
|
|
1001
|
+
if (existing) return existing;
|
|
1002
|
+
const state = {
|
|
1003
|
+
walletAddress,
|
|
1004
|
+
url: buildSubscriptionUrl(streamUrl, walletAddress),
|
|
1005
|
+
eventSource: null,
|
|
1006
|
+
listeners: {
|
|
1007
|
+
status: /* @__PURE__ */ new Set(),
|
|
1008
|
+
balance: /* @__PURE__ */ new Set(),
|
|
1009
|
+
activity: /* @__PURE__ */ new Set()
|
|
1010
|
+
},
|
|
1011
|
+
lastStatus: null,
|
|
1012
|
+
lastBalance: null,
|
|
1013
|
+
activityBuffer: [],
|
|
1014
|
+
refCount: 0
|
|
1015
|
+
};
|
|
1016
|
+
subscriptions.set(walletAddress, state);
|
|
1017
|
+
return state;
|
|
1018
|
+
}
|
|
1019
|
+
function subscribeToWalletEvent(streamUrl, walletAddress, eventType, listener) {
|
|
1020
|
+
if (!streamUrl || typeof EventSource === "undefined") return null;
|
|
1021
|
+
const state = getOrCreateSubscription(streamUrl, walletAddress);
|
|
1022
|
+
state.refCount += 1;
|
|
1023
|
+
state.listeners[eventType].add(listener);
|
|
1024
|
+
if (eventType === "status" && state.lastStatus) {
|
|
1025
|
+
listener(state.lastStatus);
|
|
1026
|
+
} else if (eventType === "balance" && state.lastBalance) {
|
|
1027
|
+
listener(state.lastBalance);
|
|
1028
|
+
} else if (eventType === "activity" && state.activityBuffer.length > 0) {
|
|
1029
|
+
listener({
|
|
1030
|
+
events: state.activityBuffer
|
|
1031
|
+
});
|
|
1032
|
+
}
|
|
1033
|
+
if (!state.eventSource) openConnection(state);
|
|
1034
|
+
return () => {
|
|
1035
|
+
state.listeners[eventType].delete(listener);
|
|
1036
|
+
state.refCount -= 1;
|
|
1037
|
+
if (state.refCount <= 0) {
|
|
1038
|
+
closeConnection(state);
|
|
1039
|
+
subscriptions.delete(walletAddress);
|
|
1040
|
+
}
|
|
1041
|
+
};
|
|
1042
|
+
}
|
|
1043
|
+
function closeAllWalletSubscriptions() {
|
|
1044
|
+
for (const state of subscriptions.values()) closeConnection(state);
|
|
1045
|
+
subscriptions.clear();
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
// src/hooks/useWalletStatus.ts
|
|
931
1049
|
var POLL_BACKOFF_MS = [2e3, 5e3, 1e4, 2e4, 3e4];
|
|
932
1050
|
var STALE_THRESHOLD_MS = 6e4;
|
|
1051
|
+
function useStableRef(value) {
|
|
1052
|
+
const ref = react.useRef(value);
|
|
1053
|
+
ref.current = value;
|
|
1054
|
+
return ref;
|
|
1055
|
+
}
|
|
1056
|
+
function deriveStatus(onChain) {
|
|
1057
|
+
if (onChain === true) return "on-chain";
|
|
1058
|
+
if (onChain === false) return "pending-deploy";
|
|
1059
|
+
return "unknown";
|
|
1060
|
+
}
|
|
933
1061
|
function useWalletStatus() {
|
|
934
1062
|
const { wallet, _internal } = useAccesly();
|
|
935
1063
|
const username = _internal.username;
|
|
@@ -938,147 +1066,75 @@ function useWalletStatus() {
|
|
|
938
1066
|
const [onChain, setOnChain] = react.useState(null);
|
|
939
1067
|
const [lastSuccessAt, setLastSuccessAt] = react.useState(0);
|
|
940
1068
|
const [isStale, setIsStale] = react.useState(false);
|
|
941
|
-
const
|
|
942
|
-
const
|
|
943
|
-
|
|
944
|
-
setStatus("no-wallet");
|
|
945
|
-
setWalletAddress(null);
|
|
946
|
-
setOnChain(null);
|
|
947
|
-
setLastSuccessAt(Date.now());
|
|
948
|
-
setIsStale(false);
|
|
949
|
-
return "no-wallet";
|
|
950
|
-
}
|
|
951
|
-
const next = res.onChain === true ? "on-chain" : res.onChain === false ? "pending-deploy" : "unknown";
|
|
952
|
-
setStatus(next);
|
|
953
|
-
setWalletAddress(res.walletAddress);
|
|
954
|
-
setOnChain(res.onChain);
|
|
955
|
-
setLastSuccessAt(Date.now());
|
|
956
|
-
setIsStale(false);
|
|
957
|
-
return next;
|
|
958
|
-
}, []);
|
|
1069
|
+
const envDefaults = ENVIRONMENT_DEFAULTS[_internal.env];
|
|
1070
|
+
const streamUrl = envDefaults.walletStreamUrl;
|
|
1071
|
+
const walletRef = useStableRef(wallet);
|
|
959
1072
|
const doFetch = react.useCallback(async () => {
|
|
960
1073
|
if (!username) return null;
|
|
961
1074
|
try {
|
|
962
|
-
const remote = await
|
|
963
|
-
if (!remote)
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
1075
|
+
const remote = await walletRef.current.fetchRemote();
|
|
1076
|
+
if (!remote) {
|
|
1077
|
+
setStatus("no-wallet");
|
|
1078
|
+
setWalletAddress(null);
|
|
1079
|
+
setOnChain(null);
|
|
1080
|
+
setLastSuccessAt(Date.now());
|
|
1081
|
+
setIsStale(false);
|
|
1082
|
+
return "no-wallet";
|
|
1083
|
+
}
|
|
1084
|
+
const next = deriveStatus(remote.onChain);
|
|
1085
|
+
setStatus(next);
|
|
1086
|
+
setWalletAddress(remote.walletAddress);
|
|
1087
|
+
setOnChain(remote.onChain);
|
|
1088
|
+
setLastSuccessAt(Date.now());
|
|
1089
|
+
setIsStale(false);
|
|
1090
|
+
return next;
|
|
969
1091
|
} catch {
|
|
970
1092
|
return null;
|
|
971
1093
|
}
|
|
972
|
-
}, [username,
|
|
973
|
-
|
|
974
|
-
if (!username || typeof BroadcastChannel === "undefined") return void 0;
|
|
975
|
-
const channel = new BroadcastChannel(`accesly:wallet:${username}`);
|
|
976
|
-
channel.onmessage = (ev) => {
|
|
977
|
-
const data = ev.data;
|
|
978
|
-
if (data && (data.kind === "ok" || data.kind === "not-found")) {
|
|
979
|
-
apply(data);
|
|
980
|
-
}
|
|
981
|
-
};
|
|
982
|
-
return () => channel.close();
|
|
983
|
-
}, [username, apply]);
|
|
984
|
-
const broadcastIfAvailable = react.useCallback(
|
|
985
|
-
(res) => {
|
|
986
|
-
if (!username || typeof BroadcastChannel === "undefined") return;
|
|
987
|
-
try {
|
|
988
|
-
const channel = new BroadcastChannel(`accesly:wallet:${username}`);
|
|
989
|
-
channel.postMessage(res);
|
|
990
|
-
channel.close();
|
|
991
|
-
} catch {
|
|
992
|
-
}
|
|
993
|
-
},
|
|
994
|
-
[username]
|
|
995
|
-
);
|
|
1094
|
+
}, [username, walletRef]);
|
|
1095
|
+
const doFetchRef = useStableRef(doFetch);
|
|
996
1096
|
react.useEffect(() => {
|
|
997
1097
|
if (!username) {
|
|
998
1098
|
setStatus("unknown");
|
|
999
1099
|
return void 0;
|
|
1000
1100
|
}
|
|
1001
1101
|
let cancelled = false;
|
|
1102
|
+
let unsubscribe = null;
|
|
1002
1103
|
let pollTimer = null;
|
|
1003
1104
|
let backoffIndex = 0;
|
|
1004
|
-
let eventSource = null;
|
|
1005
1105
|
const schedulePoll = (delayMs) => {
|
|
1006
1106
|
if (cancelled) return;
|
|
1007
1107
|
pollTimer = setTimeout(async () => {
|
|
1008
1108
|
if (cancelled) return;
|
|
1009
|
-
if (typeof document !== "undefined" && document.hidden)
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
broadcastIfAvailable({
|
|
1015
|
-
kind: next === "no-wallet" ? "not-found" : "ok",
|
|
1016
|
-
walletAddress: walletAddress ?? "",
|
|
1017
|
-
onChain
|
|
1018
|
-
});
|
|
1019
|
-
}
|
|
1020
|
-
if (next !== "on-chain" && next !== "no-wallet") {
|
|
1021
|
-
backoffIndex = Math.min(backoffIndex + 1, POLL_BACKOFF_MS.length - 1);
|
|
1022
|
-
schedulePoll(POLL_BACKOFF_MS[backoffIndex]);
|
|
1023
|
-
}
|
|
1109
|
+
if (typeof document !== "undefined" && document.hidden) return;
|
|
1110
|
+
const next = await doFetchRef.current();
|
|
1111
|
+
if (next === "on-chain" || next === "no-wallet") return;
|
|
1112
|
+
backoffIndex = Math.min(backoffIndex + 1, POLL_BACKOFF_MS.length - 1);
|
|
1113
|
+
schedulePoll(POLL_BACKOFF_MS[backoffIndex]);
|
|
1024
1114
|
}, delayMs);
|
|
1025
1115
|
};
|
|
1026
|
-
const startPolling = () => {
|
|
1027
|
-
backoffIndex = 0;
|
|
1028
|
-
schedulePoll(POLL_BACKOFF_MS[0]);
|
|
1029
|
-
};
|
|
1030
|
-
const stopPolling = () => {
|
|
1031
|
-
if (pollTimer) {
|
|
1032
|
-
clearTimeout(pollTimer);
|
|
1033
|
-
pollTimer = null;
|
|
1034
|
-
}
|
|
1035
|
-
};
|
|
1036
|
-
const tryOpenSse = () => {
|
|
1037
|
-
if (typeof EventSource === "undefined") return false;
|
|
1038
|
-
try {
|
|
1039
|
-
const url = `${_internal.apiUrl.replace(/\/$/, "")}/wallets/stream`;
|
|
1040
|
-
eventSource = new EventSource(url, { withCredentials: false });
|
|
1041
|
-
eventSource.onmessage = (ev) => {
|
|
1042
|
-
try {
|
|
1043
|
-
const data = JSON.parse(ev.data);
|
|
1044
|
-
if (typeof data.walletAddress === "string") {
|
|
1045
|
-
const res = {
|
|
1046
|
-
kind: "ok",
|
|
1047
|
-
walletAddress: data.walletAddress,
|
|
1048
|
-
onChain: data.onChain ?? null
|
|
1049
|
-
};
|
|
1050
|
-
apply(res);
|
|
1051
|
-
broadcastIfAvailable(res);
|
|
1052
|
-
}
|
|
1053
|
-
} catch {
|
|
1054
|
-
}
|
|
1055
|
-
};
|
|
1056
|
-
eventSource.onerror = () => {
|
|
1057
|
-
eventSource?.close();
|
|
1058
|
-
eventSource = null;
|
|
1059
|
-
startPolling();
|
|
1060
|
-
};
|
|
1061
|
-
return true;
|
|
1062
|
-
} catch {
|
|
1063
|
-
return false;
|
|
1064
|
-
}
|
|
1065
|
-
};
|
|
1066
1116
|
void (async () => {
|
|
1067
|
-
const
|
|
1117
|
+
const initial = await doFetchRef.current();
|
|
1068
1118
|
if (cancelled) return;
|
|
1069
|
-
if (
|
|
1070
|
-
|
|
1119
|
+
if (initial === "on-chain" || initial === "no-wallet") return;
|
|
1120
|
+
if (walletAddress) {
|
|
1121
|
+
unsubscribe = subscribeToWalletEvent(streamUrl, walletAddress, "status", (data) => {
|
|
1122
|
+
setWalletAddress(data.walletAddress);
|
|
1123
|
+
setOnChain(data.onChain);
|
|
1124
|
+
setStatus(deriveStatus(data.onChain));
|
|
1125
|
+
setLastSuccessAt(Date.now());
|
|
1126
|
+
setIsStale(false);
|
|
1127
|
+
});
|
|
1128
|
+
}
|
|
1129
|
+
if (!unsubscribe) {
|
|
1130
|
+
backoffIndex = 0;
|
|
1131
|
+
schedulePoll(POLL_BACKOFF_MS[0]);
|
|
1071
1132
|
}
|
|
1072
|
-
const sseOpen = tryOpenSse();
|
|
1073
|
-
if (!sseOpen) startPolling();
|
|
1074
1133
|
})();
|
|
1075
1134
|
const onVisibilityChange = () => {
|
|
1076
1135
|
if (typeof document === "undefined") return;
|
|
1077
|
-
if (document.hidden) {
|
|
1078
|
-
|
|
1079
|
-
} else if (!eventSource && status !== "on-chain" && status !== "no-wallet") {
|
|
1080
|
-
void doFetch();
|
|
1081
|
-
startPolling();
|
|
1136
|
+
if (!document.hidden && !unsubscribe) {
|
|
1137
|
+
void doFetchRef.current();
|
|
1082
1138
|
}
|
|
1083
1139
|
};
|
|
1084
1140
|
if (typeof document !== "undefined") {
|
|
@@ -1089,33 +1145,23 @@ function useWalletStatus() {
|
|
|
1089
1145
|
setIsStale(true);
|
|
1090
1146
|
}
|
|
1091
1147
|
}, 3e4);
|
|
1092
|
-
refreshRef.current = async () => {
|
|
1093
|
-
const next = await doFetch();
|
|
1094
|
-
if (next === "on-chain" || next === "no-wallet") {
|
|
1095
|
-
stopPolling();
|
|
1096
|
-
} else {
|
|
1097
|
-
backoffIndex = 0;
|
|
1098
|
-
stopPolling();
|
|
1099
|
-
startPolling();
|
|
1100
|
-
}
|
|
1101
|
-
};
|
|
1102
1148
|
return () => {
|
|
1103
1149
|
cancelled = true;
|
|
1104
|
-
|
|
1150
|
+
if (unsubscribe) unsubscribe();
|
|
1151
|
+
if (pollTimer) clearTimeout(pollTimer);
|
|
1105
1152
|
clearInterval(staleTimer);
|
|
1106
|
-
eventSource?.close();
|
|
1107
1153
|
if (typeof document !== "undefined") {
|
|
1108
1154
|
document.removeEventListener("visibilitychange", onVisibilityChange);
|
|
1109
1155
|
}
|
|
1110
1156
|
};
|
|
1111
|
-
}, [username,
|
|
1157
|
+
}, [username, streamUrl, walletAddress]);
|
|
1112
1158
|
const refresh = react.useCallback(async () => {
|
|
1113
|
-
await
|
|
1114
|
-
}, []);
|
|
1159
|
+
await doFetchRef.current();
|
|
1160
|
+
}, [doFetchRef]);
|
|
1115
1161
|
return { status, walletAddress, onChain, isStale, refresh };
|
|
1116
1162
|
}
|
|
1117
|
-
var
|
|
1118
|
-
function
|
|
1163
|
+
var POLL_FALLBACK_MS = 1e4;
|
|
1164
|
+
function useStableRef2(value) {
|
|
1119
1165
|
const ref = react.useRef(value);
|
|
1120
1166
|
ref.current = value;
|
|
1121
1167
|
return ref;
|
|
@@ -1130,8 +1176,7 @@ function useBalance(walletAddress) {
|
|
|
1130
1176
|
const [xlm, setXlm] = react.useState(null);
|
|
1131
1177
|
const [isLoading, setIsLoading] = react.useState(true);
|
|
1132
1178
|
const [error, setError] = react.useState(null);
|
|
1133
|
-
const
|
|
1134
|
-
const walletRef = useStableRef(wallet);
|
|
1179
|
+
const walletRef = useStableRef2(wallet);
|
|
1135
1180
|
react.useEffect(() => {
|
|
1136
1181
|
if (walletAddress) {
|
|
1137
1182
|
setResolvedAddress(walletAddress);
|
|
@@ -1155,11 +1200,11 @@ function useBalance(walletAddress) {
|
|
|
1155
1200
|
cancelled = true;
|
|
1156
1201
|
};
|
|
1157
1202
|
}, [walletAddress, username, walletRef]);
|
|
1158
|
-
const
|
|
1159
|
-
const
|
|
1203
|
+
const envDefaults = ENVIRONMENT_DEFAULTS[_internal.env];
|
|
1204
|
+
const streamUrl = envDefaults.walletStreamUrl;
|
|
1205
|
+
const endpointsRef = useStableRef2(_internal.endpoints);
|
|
1206
|
+
const doFetchOnce = react.useCallback(async () => {
|
|
1160
1207
|
if (!resolvedAddress) return;
|
|
1161
|
-
if (fetchInFlight.current) return;
|
|
1162
|
-
fetchInFlight.current = true;
|
|
1163
1208
|
try {
|
|
1164
1209
|
const res = await endpointsRef.current.walletBalance(resolvedAddress);
|
|
1165
1210
|
setStroops(res.xlm.stroops);
|
|
@@ -1169,58 +1214,56 @@ function useBalance(walletAddress) {
|
|
|
1169
1214
|
setError(err);
|
|
1170
1215
|
} finally {
|
|
1171
1216
|
setIsLoading(false);
|
|
1172
|
-
fetchInFlight.current = false;
|
|
1173
1217
|
}
|
|
1174
1218
|
}, [resolvedAddress, endpointsRef]);
|
|
1175
|
-
const doFetchRef =
|
|
1219
|
+
const doFetchRef = useStableRef2(doFetchOnce);
|
|
1176
1220
|
react.useEffect(() => {
|
|
1177
1221
|
if (!resolvedAddress) {
|
|
1178
1222
|
setIsLoading(false);
|
|
1179
1223
|
return void 0;
|
|
1180
1224
|
}
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
const stopInterval = () => {
|
|
1191
|
-
if (interval) {
|
|
1192
|
-
clearInterval(interval);
|
|
1193
|
-
interval = null;
|
|
1225
|
+
const unsubscribe = subscribeToWalletEvent(
|
|
1226
|
+
streamUrl,
|
|
1227
|
+
resolvedAddress,
|
|
1228
|
+
"balance",
|
|
1229
|
+
(data) => {
|
|
1230
|
+
setStroops(data.stroops);
|
|
1231
|
+
setXlm(data.xlm);
|
|
1232
|
+
setError(null);
|
|
1233
|
+
setIsLoading(false);
|
|
1194
1234
|
}
|
|
1195
|
-
|
|
1196
|
-
|
|
1235
|
+
);
|
|
1236
|
+
if (unsubscribe) {
|
|
1237
|
+
void doFetchRef.current();
|
|
1238
|
+
return unsubscribe;
|
|
1239
|
+
}
|
|
1240
|
+
void doFetchRef.current();
|
|
1241
|
+
const interval = setInterval(() => {
|
|
1242
|
+
if (typeof document !== "undefined" && document.hidden) return;
|
|
1243
|
+
void doFetchRef.current();
|
|
1244
|
+
}, POLL_FALLBACK_MS);
|
|
1197
1245
|
const onVisibilityChange = () => {
|
|
1198
1246
|
if (typeof document === "undefined") return;
|
|
1199
|
-
if (document.hidden)
|
|
1200
|
-
stopInterval();
|
|
1201
|
-
} else {
|
|
1202
|
-
void doFetchRef.current();
|
|
1203
|
-
startInterval();
|
|
1204
|
-
}
|
|
1247
|
+
if (!document.hidden) void doFetchRef.current();
|
|
1205
1248
|
};
|
|
1206
1249
|
if (typeof document !== "undefined") {
|
|
1207
1250
|
document.addEventListener("visibilitychange", onVisibilityChange);
|
|
1208
1251
|
}
|
|
1209
1252
|
return () => {
|
|
1210
|
-
|
|
1253
|
+
clearInterval(interval);
|
|
1211
1254
|
if (typeof document !== "undefined") {
|
|
1212
1255
|
document.removeEventListener("visibilitychange", onVisibilityChange);
|
|
1213
1256
|
}
|
|
1214
1257
|
};
|
|
1215
|
-
}, [resolvedAddress, doFetchRef]);
|
|
1258
|
+
}, [resolvedAddress, streamUrl, doFetchRef]);
|
|
1216
1259
|
const refresh = react.useCallback(async () => {
|
|
1217
1260
|
await doFetchRef.current();
|
|
1218
1261
|
}, [doFetchRef]);
|
|
1219
1262
|
return { stroops, xlm, isLoading, error, refresh };
|
|
1220
1263
|
}
|
|
1221
|
-
var
|
|
1264
|
+
var POLL_FALLBACK_MS2 = 25e3;
|
|
1222
1265
|
var DEFAULT_LIMIT = 20;
|
|
1223
|
-
function
|
|
1266
|
+
function useStableRef3(value) {
|
|
1224
1267
|
const ref = react.useRef(value);
|
|
1225
1268
|
ref.current = value;
|
|
1226
1269
|
return ref;
|
|
@@ -1235,8 +1278,7 @@ function useWalletActivity(walletAddress, opts = {}) {
|
|
|
1235
1278
|
const [events, setEvents] = react.useState([]);
|
|
1236
1279
|
const [isLoading, setIsLoading] = react.useState(true);
|
|
1237
1280
|
const [error, setError] = react.useState(null);
|
|
1238
|
-
const
|
|
1239
|
-
const walletRef = useStableRef2(wallet);
|
|
1281
|
+
const walletRef = useStableRef3(wallet);
|
|
1240
1282
|
react.useEffect(() => {
|
|
1241
1283
|
if (walletAddress) {
|
|
1242
1284
|
setResolvedAddress(walletAddress);
|
|
@@ -1260,67 +1302,72 @@ function useWalletActivity(walletAddress, opts = {}) {
|
|
|
1260
1302
|
cancelled = true;
|
|
1261
1303
|
};
|
|
1262
1304
|
}, [walletAddress, username, walletRef]);
|
|
1263
|
-
const
|
|
1264
|
-
const
|
|
1305
|
+
const envDefaults = ENVIRONMENT_DEFAULTS[_internal.env];
|
|
1306
|
+
const streamUrl = envDefaults.walletStreamUrl;
|
|
1307
|
+
const endpointsRef = useStableRef3(_internal.endpoints);
|
|
1308
|
+
const doFetchOnce = react.useCallback(async () => {
|
|
1265
1309
|
if (!resolvedAddress) return;
|
|
1266
|
-
if (fetchInFlight.current) return;
|
|
1267
|
-
fetchInFlight.current = true;
|
|
1268
1310
|
try {
|
|
1269
1311
|
const res = await endpointsRef.current.walletActivity(resolvedAddress, limit);
|
|
1270
|
-
|
|
1312
|
+
const adapted = [];
|
|
1313
|
+
for (const ev of res.events) {
|
|
1314
|
+
const conv = adaptRestEvent(ev);
|
|
1315
|
+
if (conv) adapted.push(conv);
|
|
1316
|
+
}
|
|
1317
|
+
setEvents(adapted.slice(0, limit));
|
|
1271
1318
|
setError(null);
|
|
1272
1319
|
} catch (err) {
|
|
1273
1320
|
setError(err);
|
|
1274
1321
|
} finally {
|
|
1275
1322
|
setIsLoading(false);
|
|
1276
|
-
fetchInFlight.current = false;
|
|
1277
1323
|
}
|
|
1278
1324
|
}, [resolvedAddress, limit, endpointsRef]);
|
|
1279
|
-
const doFetchRef =
|
|
1325
|
+
const doFetchRef = useStableRef3(doFetchOnce);
|
|
1280
1326
|
react.useEffect(() => {
|
|
1281
1327
|
if (!resolvedAddress) {
|
|
1282
1328
|
setIsLoading(false);
|
|
1283
1329
|
return void 0;
|
|
1284
1330
|
}
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
};
|
|
1294
|
-
const stop = () => {
|
|
1295
|
-
if (interval) {
|
|
1296
|
-
clearInterval(interval);
|
|
1297
|
-
interval = null;
|
|
1298
|
-
}
|
|
1299
|
-
};
|
|
1300
|
-
start();
|
|
1301
|
-
const onVisibilityChange = () => {
|
|
1302
|
-
if (typeof document === "undefined") return;
|
|
1303
|
-
if (document.hidden) stop();
|
|
1304
|
-
else {
|
|
1305
|
-
void doFetchRef.current();
|
|
1306
|
-
start();
|
|
1331
|
+
const unsubscribe = subscribeToWalletEvent(
|
|
1332
|
+
streamUrl,
|
|
1333
|
+
resolvedAddress,
|
|
1334
|
+
"activity",
|
|
1335
|
+
(data) => {
|
|
1336
|
+
setEvents(data.events.slice(0, limit));
|
|
1337
|
+
setError(null);
|
|
1338
|
+
setIsLoading(false);
|
|
1307
1339
|
}
|
|
1308
|
-
|
|
1309
|
-
if (
|
|
1310
|
-
|
|
1340
|
+
);
|
|
1341
|
+
if (unsubscribe) {
|
|
1342
|
+
void doFetchRef.current();
|
|
1343
|
+
return unsubscribe;
|
|
1311
1344
|
}
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
if (typeof document !== "undefined")
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
}, [resolvedAddress, doFetchRef]);
|
|
1345
|
+
void doFetchRef.current();
|
|
1346
|
+
const interval = setInterval(() => {
|
|
1347
|
+
if (typeof document !== "undefined" && document.hidden) return;
|
|
1348
|
+
void doFetchRef.current();
|
|
1349
|
+
}, POLL_FALLBACK_MS2);
|
|
1350
|
+
return () => clearInterval(interval);
|
|
1351
|
+
}, [resolvedAddress, streamUrl, limit, doFetchRef]);
|
|
1319
1352
|
const refresh = react.useCallback(async () => {
|
|
1320
1353
|
await doFetchRef.current();
|
|
1321
1354
|
}, [doFetchRef]);
|
|
1322
1355
|
return { events, isLoading, error, refresh };
|
|
1323
1356
|
}
|
|
1357
|
+
function adaptRestEvent(ev) {
|
|
1358
|
+
const t0 = ev.topics[0];
|
|
1359
|
+
if (typeof t0 !== "string") return null;
|
|
1360
|
+
if (t0 === "SignerRotated") {
|
|
1361
|
+
return {
|
|
1362
|
+
type: "signer-rotated",
|
|
1363
|
+
txHash: ev.txHash,
|
|
1364
|
+
ledger: ev.ledger,
|
|
1365
|
+
timestamp: ev.timestamp,
|
|
1366
|
+
newOwnerEd25519Hex: typeof ev.value === "string" ? ev.value : ""
|
|
1367
|
+
};
|
|
1368
|
+
}
|
|
1369
|
+
return null;
|
|
1370
|
+
}
|
|
1324
1371
|
|
|
1325
1372
|
// src/index.ts
|
|
1326
1373
|
var REACT_ADAPTER_VERSION = "0.0.0";
|
|
@@ -1330,6 +1377,8 @@ exports.AcceslyProvider = AcceslyProvider;
|
|
|
1330
1377
|
exports.ENVIRONMENT_DEFAULTS = ENVIRONMENT_DEFAULTS;
|
|
1331
1378
|
exports.NotImplementedYetError = NotImplementedYetError;
|
|
1332
1379
|
exports.REACT_ADAPTER_VERSION = REACT_ADAPTER_VERSION;
|
|
1380
|
+
exports.closeAllWalletSubscriptions = closeAllWalletSubscriptions;
|
|
1381
|
+
exports.subscribeToWalletEvent = subscribeToWalletEvent;
|
|
1333
1382
|
exports.useAccesly = useAccesly;
|
|
1334
1383
|
exports.useBalance = useBalance;
|
|
1335
1384
|
exports.useWalletActivity = useWalletActivity;
|