@use-stellar/vue 0.0.0-stage → 0.2.3
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/LICENSE +134 -0
- package/README.md +187 -2
- package/dist/chunk-7ROX7ZPL.mjs +123 -0
- package/dist/chunk-7ROX7ZPL.mjs.map +1 -0
- package/dist/index.d.mts +212 -0
- package/dist/index.d.ts +212 -0
- package/dist/index.js +829 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +713 -0
- package/dist/index.mjs.map +1 -0
- package/dist/nuxt/module.d.mts +15 -0
- package/dist/nuxt/module.d.ts +15 -0
- package/dist/nuxt/module.js +29 -0
- package/dist/nuxt/module.js.map +1 -0
- package/dist/nuxt/module.mjs +23 -0
- package/dist/nuxt/module.mjs.map +1 -0
- package/dist/nuxt/runtime/plugin.d.mts +24 -0
- package/dist/nuxt/runtime/plugin.d.ts +24 -0
- package/dist/nuxt/runtime/plugin.js +140 -0
- package/dist/nuxt/runtime/plugin.js.map +1 -0
- package/dist/nuxt/runtime/plugin.mjs +28 -0
- package/dist/nuxt/runtime/plugin.mjs.map +1 -0
- package/dist/plugin-bXIRDH8_.d.mts +84 -0
- package/dist/plugin-bXIRDH8_.d.ts +84 -0
- package/dist/test-utils.d.mts +27 -0
- package/dist/test-utils.d.ts +27 -0
- package/dist/test-utils.js +97 -0
- package/dist/test-utils.js.map +1 -0
- package/dist/test-utils.mjs +22 -0
- package/dist/test-utils.mjs.map +1 -0
- package/package.json +132 -3
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,713 @@
|
|
|
1
|
+
import { useStellarRuntime } from './chunk-7ROX7ZPL.mjs';
|
|
2
|
+
export { NETWORK_CONFIGS, STELLAR_RUNTIME_KEY, createStellarPlugin, createStellarRuntime, useStellarRuntime } from './chunk-7ROX7ZPL.mjs';
|
|
3
|
+
import { computed, toValue, toRaw, shallowRef, ref, watch, onScopeDispose, reactive, getCurrentInstance, onMounted } from 'vue';
|
|
4
|
+
import { ANONYMOUS_SIMULATION_SOURCE, toStellarError, DEFAULT_BUFFER_SIZE, DEFAULT_POLL_INTERVAL, createContractEventPoller, paymentsKey, serializeKey, filterPayments, onlineManager, offlineError, addTrustline, AddTrustlineAbortedError, isAddTrustlinePreflightError, pathPayment, isPathPaymentPreflightError, normalizePayment, sendPayment, SendPaymentAbortedError, isPreflightError, fetchAccount, accountKey, simulateContractCall, sorobanContractKey, argsKey, fetchClaimableBalances, claimableBalanceKey, fetchPaymentsPage, createQueryObserver } from 'use-stellar/core';
|
|
5
|
+
export { ANONYMOUS_SIMULATION_SOURCE, accountKey, claimableBalanceKey, paymentsKey } from 'use-stellar/core';
|
|
6
|
+
|
|
7
|
+
function useQuery(options) {
|
|
8
|
+
const data = shallowRef(null);
|
|
9
|
+
const loading = ref(false);
|
|
10
|
+
const error = shallowRef(null);
|
|
11
|
+
const updatedAt = ref(null);
|
|
12
|
+
let observer = null;
|
|
13
|
+
let unsubscribe = null;
|
|
14
|
+
const resolved = computed(() => ({
|
|
15
|
+
queryKey: options.queryKey(),
|
|
16
|
+
queryFn: options.queryFn,
|
|
17
|
+
store: options.store,
|
|
18
|
+
enabled: options.enabled?.() ?? true,
|
|
19
|
+
staleTime: toValue(options.staleTime),
|
|
20
|
+
maxRetries: toValue(options.maxRetries)
|
|
21
|
+
}));
|
|
22
|
+
function project(snapshot) {
|
|
23
|
+
data.value = snapshot.data;
|
|
24
|
+
loading.value = snapshot.loading;
|
|
25
|
+
error.value = snapshot.error;
|
|
26
|
+
updatedAt.value = snapshot.updatedAt;
|
|
27
|
+
}
|
|
28
|
+
function start() {
|
|
29
|
+
if (observer) return;
|
|
30
|
+
observer = createQueryObserver(resolved.value);
|
|
31
|
+
unsubscribe = observer.subscribe(project);
|
|
32
|
+
project(observer.getSnapshot());
|
|
33
|
+
}
|
|
34
|
+
watch(
|
|
35
|
+
() => [
|
|
36
|
+
serializeKey(resolved.value.queryKey),
|
|
37
|
+
resolved.value.enabled,
|
|
38
|
+
resolved.value.staleTime,
|
|
39
|
+
resolved.value.maxRetries
|
|
40
|
+
],
|
|
41
|
+
() => {
|
|
42
|
+
observer?.setOptions(resolved.value);
|
|
43
|
+
if (observer) project(observer.getSnapshot());
|
|
44
|
+
}
|
|
45
|
+
// Batched (the default "pre" flush), not "sync": inputs that change in
|
|
46
|
+
// the same tick — a contract id and a method, say — must produce one
|
|
47
|
+
// query for the final combination, not an extra request for every
|
|
48
|
+
// half-updated one in between.
|
|
49
|
+
);
|
|
50
|
+
if (getCurrentInstance()) {
|
|
51
|
+
if (typeof globalThis.window === "undefined" && options.ssr) start();
|
|
52
|
+
else onMounted(start);
|
|
53
|
+
} else {
|
|
54
|
+
start();
|
|
55
|
+
}
|
|
56
|
+
onScopeDispose(() => {
|
|
57
|
+
unsubscribe?.();
|
|
58
|
+
observer?.destroy();
|
|
59
|
+
unsubscribe = null;
|
|
60
|
+
observer = null;
|
|
61
|
+
});
|
|
62
|
+
return {
|
|
63
|
+
data,
|
|
64
|
+
loading,
|
|
65
|
+
error,
|
|
66
|
+
updatedAt,
|
|
67
|
+
rateLimitedUntil: computed(() => observer?.getRateLimitedUntil() ?? null),
|
|
68
|
+
refetch: () => observer?.fetch({ force: true }) ?? Promise.resolve()
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// src/useBalance.ts
|
|
73
|
+
function matchesAsset(balance, asset) {
|
|
74
|
+
if (asset === "XLM") return balance.asset === "XLM";
|
|
75
|
+
if (typeof asset !== "object") return balance.asset === asset;
|
|
76
|
+
return typeof balance.asset === "object" && balance.asset.code === asset.code && balance.asset.issuer === asset.issuer;
|
|
77
|
+
}
|
|
78
|
+
function useBalance(options) {
|
|
79
|
+
const runtime = useStellarRuntime();
|
|
80
|
+
const address = computed(() => toValue(options.address)?.trim() || null);
|
|
81
|
+
const asset = options.asset ?? "XLM";
|
|
82
|
+
const query = useQuery({
|
|
83
|
+
store: runtime.queryStore,
|
|
84
|
+
queryKey: () => accountKey(
|
|
85
|
+
runtime.networkConfig.horizonUrl,
|
|
86
|
+
runtime.networkConfig.network,
|
|
87
|
+
address.value ?? ""
|
|
88
|
+
),
|
|
89
|
+
queryFn: () => fetchAccount(runtime.networkConfig, { address: address.value }),
|
|
90
|
+
enabled: () => address.value !== null,
|
|
91
|
+
staleTime: options.staleTime,
|
|
92
|
+
maxRetries: options.maxRetries
|
|
93
|
+
});
|
|
94
|
+
const balances = computed(() => query.data.value?.balances ?? []);
|
|
95
|
+
return {
|
|
96
|
+
balance: computed(
|
|
97
|
+
() => balances.value.find((item) => matchesAsset(item, asset))?.balance ?? null
|
|
98
|
+
),
|
|
99
|
+
balances,
|
|
100
|
+
loading: computed(() => query.loading.value),
|
|
101
|
+
error: computed(() => query.error.value),
|
|
102
|
+
refetch: query.refetch
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
function unwrapArgs(value) {
|
|
106
|
+
if (!value) return [];
|
|
107
|
+
const raw = toRaw(value);
|
|
108
|
+
return raw.map(
|
|
109
|
+
(argument) => argument !== null && typeof argument === "object" ? toRaw(argument) : argument
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
function useSorobanContract(options) {
|
|
113
|
+
const { networkConfig, queryStore } = useStellarRuntime();
|
|
114
|
+
const call = computed(() => {
|
|
115
|
+
const contractId = toValue(options.contractId)?.trim() ?? "";
|
|
116
|
+
const method = toValue(options.method)?.trim() ?? "";
|
|
117
|
+
if (!contractId || !method) return null;
|
|
118
|
+
const spec = options.spec === void 0 ? void 0 : toValue(options.spec);
|
|
119
|
+
const sourceAccount = (options.sourceAccount === void 0 ? void 0 : toValue(options.sourceAccount))?.trim() || ANONYMOUS_SIMULATION_SOURCE;
|
|
120
|
+
return {
|
|
121
|
+
contractId,
|
|
122
|
+
method,
|
|
123
|
+
args: unwrapArgs(options.args === void 0 ? [] : toValue(options.args)),
|
|
124
|
+
spec: spec ? toRaw(spec) : void 0,
|
|
125
|
+
sourceAccount
|
|
126
|
+
};
|
|
127
|
+
});
|
|
128
|
+
const query = useQuery({
|
|
129
|
+
store: queryStore,
|
|
130
|
+
queryKey: () => {
|
|
131
|
+
const current = call.value;
|
|
132
|
+
if (!current) return ["soroban", "disabled"];
|
|
133
|
+
return sorobanContractKey(
|
|
134
|
+
networkConfig.sorobanUrl,
|
|
135
|
+
networkConfig.network,
|
|
136
|
+
current.contractId,
|
|
137
|
+
current.method,
|
|
138
|
+
argsKey(current.args),
|
|
139
|
+
current.sourceAccount,
|
|
140
|
+
current.spec ? "spec" : "raw"
|
|
141
|
+
);
|
|
142
|
+
},
|
|
143
|
+
queryFn: () => simulateContractCall(networkConfig, call.value),
|
|
144
|
+
enabled: () => call.value !== null,
|
|
145
|
+
staleTime: options.staleTime
|
|
146
|
+
});
|
|
147
|
+
return {
|
|
148
|
+
data: computed(() => query.data.value),
|
|
149
|
+
loading: computed(() => query.loading.value),
|
|
150
|
+
error: computed(
|
|
151
|
+
() => query.error.value ? toStellarError(query.error.value) : null
|
|
152
|
+
),
|
|
153
|
+
refetch: () => {
|
|
154
|
+
void query.refetch();
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
function useContractEvents(options) {
|
|
159
|
+
const { networkConfig } = useStellarRuntime();
|
|
160
|
+
const events = shallowRef([]);
|
|
161
|
+
const latestLedgerState = ref(null);
|
|
162
|
+
const loadingState = ref(false);
|
|
163
|
+
const errorState = shallowRef(null);
|
|
164
|
+
let activePoller = null;
|
|
165
|
+
let activeUnsubscribe = null;
|
|
166
|
+
const input = computed(() => {
|
|
167
|
+
const contractIds = [...toValue(options.contractIds)];
|
|
168
|
+
const rawTopics = options.topics === void 0 ? void 0 : toValue(options.topics);
|
|
169
|
+
const topics = rawTopics?.map((topic) => [...topic]);
|
|
170
|
+
return {
|
|
171
|
+
contractIds,
|
|
172
|
+
contractKey: JSON.stringify(contractIds),
|
|
173
|
+
topics,
|
|
174
|
+
topicKey: JSON.stringify(topics ?? []),
|
|
175
|
+
startLedger: options.startLedger === void 0 ? void 0 : toValue(options.startLedger),
|
|
176
|
+
interval: (options.interval === void 0 ? void 0 : toValue(options.interval)) ?? DEFAULT_POLL_INTERVAL,
|
|
177
|
+
bufferSize: (options.bufferSize === void 0 ? void 0 : toValue(options.bufferSize)) ?? DEFAULT_BUFFER_SIZE,
|
|
178
|
+
enabled: (options.enabled === void 0 ? void 0 : toValue(options.enabled)) ?? true
|
|
179
|
+
};
|
|
180
|
+
});
|
|
181
|
+
function stopActivePoller() {
|
|
182
|
+
activeUnsubscribe?.();
|
|
183
|
+
activeUnsubscribe = null;
|
|
184
|
+
activePoller?.stop();
|
|
185
|
+
activePoller = null;
|
|
186
|
+
}
|
|
187
|
+
watch(
|
|
188
|
+
() => [
|
|
189
|
+
input.value.contractKey,
|
|
190
|
+
input.value.topicKey,
|
|
191
|
+
input.value.startLedger,
|
|
192
|
+
input.value.interval,
|
|
193
|
+
input.value.bufferSize,
|
|
194
|
+
input.value.enabled
|
|
195
|
+
],
|
|
196
|
+
() => {
|
|
197
|
+
stopActivePoller();
|
|
198
|
+
const current = input.value;
|
|
199
|
+
if (!current.enabled || current.contractIds.length === 0) {
|
|
200
|
+
events.value = [];
|
|
201
|
+
latestLedgerState.value = null;
|
|
202
|
+
loadingState.value = false;
|
|
203
|
+
errorState.value = null;
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
const poller = createContractEventPoller(
|
|
207
|
+
{ sorobanUrl: networkConfig.sorobanUrl },
|
|
208
|
+
{
|
|
209
|
+
contractIds: current.contractIds,
|
|
210
|
+
topics: current.topics,
|
|
211
|
+
startLedger: current.startLedger,
|
|
212
|
+
interval: current.interval,
|
|
213
|
+
bufferSize: current.bufferSize
|
|
214
|
+
}
|
|
215
|
+
);
|
|
216
|
+
activePoller = poller;
|
|
217
|
+
activeUnsubscribe = poller.subscribe((snapshot) => {
|
|
218
|
+
events.value = snapshot.events;
|
|
219
|
+
latestLedgerState.value = snapshot.latestLedger;
|
|
220
|
+
loadingState.value = snapshot.loading;
|
|
221
|
+
errorState.value = snapshot.error;
|
|
222
|
+
});
|
|
223
|
+
poller.start();
|
|
224
|
+
},
|
|
225
|
+
{ immediate: true }
|
|
226
|
+
);
|
|
227
|
+
onScopeDispose(stopActivePoller);
|
|
228
|
+
const latestLedger = computed(() => latestLedgerState.value);
|
|
229
|
+
const loading = computed(() => loadingState.value);
|
|
230
|
+
const error = computed(() => errorState.value);
|
|
231
|
+
function clear() {
|
|
232
|
+
activePoller?.clear();
|
|
233
|
+
}
|
|
234
|
+
return { events, latestLedger, loading, error, clear };
|
|
235
|
+
}
|
|
236
|
+
function useSendPayment() {
|
|
237
|
+
const runtime = useStellarRuntime();
|
|
238
|
+
const loading = ref(false);
|
|
239
|
+
const error = shallowRef(null);
|
|
240
|
+
const result = shallowRef(null);
|
|
241
|
+
let operationId = 0;
|
|
242
|
+
let disposed = false;
|
|
243
|
+
const isCurrent = (id) => !disposed && id === operationId;
|
|
244
|
+
async function send(options) {
|
|
245
|
+
if (!onlineManager.isOnline()) throw offlineError();
|
|
246
|
+
const id = ++operationId;
|
|
247
|
+
const previousError = error.value;
|
|
248
|
+
const previousResult = result.value;
|
|
249
|
+
loading.value = true;
|
|
250
|
+
error.value = null;
|
|
251
|
+
result.value = null;
|
|
252
|
+
try {
|
|
253
|
+
const outcome = await sendPayment(
|
|
254
|
+
{
|
|
255
|
+
network: runtime.network,
|
|
256
|
+
networkConfig: runtime.networkConfig,
|
|
257
|
+
wallet: runtime.wallet,
|
|
258
|
+
queryStore: runtime.queryStore
|
|
259
|
+
},
|
|
260
|
+
options
|
|
261
|
+
);
|
|
262
|
+
if (isCurrent(id)) result.value = outcome;
|
|
263
|
+
return outcome;
|
|
264
|
+
} catch (caught) {
|
|
265
|
+
if (caught instanceof SendPaymentAbortedError) {
|
|
266
|
+
return { hash: "", status: "failed", error: caught.message };
|
|
267
|
+
}
|
|
268
|
+
if (isPreflightError(caught)) {
|
|
269
|
+
if (isCurrent(id)) {
|
|
270
|
+
error.value = previousError;
|
|
271
|
+
result.value = previousResult;
|
|
272
|
+
}
|
|
273
|
+
throw caught;
|
|
274
|
+
}
|
|
275
|
+
const stellarError = caught;
|
|
276
|
+
if (isCurrent(id)) {
|
|
277
|
+
if (stellarError.code === "TX_TIMEOUT") {
|
|
278
|
+
result.value = { hash: stellarError.hash ?? "", status: "pending" };
|
|
279
|
+
} else if (stellarError.isSubmissionFailure) {
|
|
280
|
+
result.value = { hash: stellarError.hash ?? "", status: "failed" };
|
|
281
|
+
}
|
|
282
|
+
error.value = stellarError;
|
|
283
|
+
}
|
|
284
|
+
throw caught;
|
|
285
|
+
} finally {
|
|
286
|
+
if (isCurrent(id)) loading.value = false;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
function reset() {
|
|
290
|
+
operationId += 1;
|
|
291
|
+
loading.value = false;
|
|
292
|
+
error.value = null;
|
|
293
|
+
result.value = null;
|
|
294
|
+
}
|
|
295
|
+
onScopeDispose(() => {
|
|
296
|
+
disposed = true;
|
|
297
|
+
operationId += 1;
|
|
298
|
+
});
|
|
299
|
+
return { send, loading, error, result, reset };
|
|
300
|
+
}
|
|
301
|
+
function useAddTrustline() {
|
|
302
|
+
const runtime = useStellarRuntime();
|
|
303
|
+
const loading = ref(false);
|
|
304
|
+
const error = shallowRef(null);
|
|
305
|
+
const result = shallowRef(null);
|
|
306
|
+
let operationId = 0;
|
|
307
|
+
let disposed = false;
|
|
308
|
+
const isCurrent = (id) => !disposed && id === operationId;
|
|
309
|
+
async function addTrustline$1(options) {
|
|
310
|
+
if (!onlineManager.isOnline()) throw offlineError();
|
|
311
|
+
const id = ++operationId;
|
|
312
|
+
const previousError = error.value;
|
|
313
|
+
const previousResult = result.value;
|
|
314
|
+
loading.value = true;
|
|
315
|
+
error.value = null;
|
|
316
|
+
result.value = null;
|
|
317
|
+
try {
|
|
318
|
+
const outcome = await addTrustline(
|
|
319
|
+
{
|
|
320
|
+
network: runtime.network,
|
|
321
|
+
networkConfig: runtime.networkConfig,
|
|
322
|
+
wallet: runtime.wallet,
|
|
323
|
+
queryStore: runtime.queryStore
|
|
324
|
+
},
|
|
325
|
+
options
|
|
326
|
+
);
|
|
327
|
+
if (isCurrent(id)) result.value = outcome;
|
|
328
|
+
return outcome;
|
|
329
|
+
} catch (caught) {
|
|
330
|
+
if (caught instanceof AddTrustlineAbortedError) {
|
|
331
|
+
return { hash: "", status: "failed" };
|
|
332
|
+
}
|
|
333
|
+
if (isAddTrustlinePreflightError(caught)) {
|
|
334
|
+
if (isCurrent(id)) {
|
|
335
|
+
error.value = previousError;
|
|
336
|
+
result.value = previousResult;
|
|
337
|
+
}
|
|
338
|
+
throw caught;
|
|
339
|
+
}
|
|
340
|
+
const stellarError = caught;
|
|
341
|
+
if (isCurrent(id)) {
|
|
342
|
+
if (stellarError.code === "TX_TIMEOUT") {
|
|
343
|
+
result.value = { hash: stellarError.hash ?? "", status: "pending" };
|
|
344
|
+
} else if (stellarError.isSubmissionFailure) {
|
|
345
|
+
result.value = { hash: stellarError.hash ?? "", status: "failed" };
|
|
346
|
+
}
|
|
347
|
+
error.value = stellarError;
|
|
348
|
+
}
|
|
349
|
+
throw caught;
|
|
350
|
+
} finally {
|
|
351
|
+
if (isCurrent(id)) loading.value = false;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
function reset() {
|
|
355
|
+
operationId += 1;
|
|
356
|
+
loading.value = false;
|
|
357
|
+
error.value = null;
|
|
358
|
+
result.value = null;
|
|
359
|
+
}
|
|
360
|
+
onScopeDispose(() => {
|
|
361
|
+
disposed = true;
|
|
362
|
+
operationId += 1;
|
|
363
|
+
});
|
|
364
|
+
return { addTrustline: addTrustline$1, loading, error, result, reset };
|
|
365
|
+
}
|
|
366
|
+
function usePathPayment() {
|
|
367
|
+
const runtime = useStellarRuntime();
|
|
368
|
+
const loading = ref(false);
|
|
369
|
+
const error = shallowRef(null);
|
|
370
|
+
const result = shallowRef(null);
|
|
371
|
+
let operationId = 0;
|
|
372
|
+
let disposed = false;
|
|
373
|
+
const isCurrent = (id) => !disposed && id === operationId;
|
|
374
|
+
async function pathPayment$1(options) {
|
|
375
|
+
if (!onlineManager.isOnline()) throw offlineError();
|
|
376
|
+
const id = ++operationId;
|
|
377
|
+
const previousError = error.value;
|
|
378
|
+
const previousResult = result.value;
|
|
379
|
+
loading.value = true;
|
|
380
|
+
error.value = null;
|
|
381
|
+
result.value = null;
|
|
382
|
+
try {
|
|
383
|
+
const outcome = await pathPayment(
|
|
384
|
+
{
|
|
385
|
+
network: runtime.network,
|
|
386
|
+
networkConfig: runtime.networkConfig,
|
|
387
|
+
wallet: runtime.wallet,
|
|
388
|
+
queryStore: runtime.queryStore
|
|
389
|
+
},
|
|
390
|
+
options
|
|
391
|
+
);
|
|
392
|
+
if (isCurrent(id)) result.value = outcome;
|
|
393
|
+
return outcome;
|
|
394
|
+
} catch (caught) {
|
|
395
|
+
if (isPathPaymentPreflightError(caught)) {
|
|
396
|
+
if (isCurrent(id)) {
|
|
397
|
+
error.value = previousError;
|
|
398
|
+
result.value = previousResult;
|
|
399
|
+
}
|
|
400
|
+
throw caught;
|
|
401
|
+
}
|
|
402
|
+
if (isCurrent(id)) error.value = caught;
|
|
403
|
+
throw caught;
|
|
404
|
+
} finally {
|
|
405
|
+
if (isCurrent(id)) loading.value = false;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
function reset() {
|
|
409
|
+
operationId += 1;
|
|
410
|
+
loading.value = false;
|
|
411
|
+
error.value = null;
|
|
412
|
+
result.value = null;
|
|
413
|
+
}
|
|
414
|
+
onScopeDispose(() => {
|
|
415
|
+
disposed = true;
|
|
416
|
+
operationId += 1;
|
|
417
|
+
});
|
|
418
|
+
return { pathPayment: pathPayment$1, loading, error, result, reset };
|
|
419
|
+
}
|
|
420
|
+
function useClaimableBalance(options = {}) {
|
|
421
|
+
const runtime = useStellarRuntime();
|
|
422
|
+
const address = computed(() => {
|
|
423
|
+
const value = options.address === void 0 ? runtime.walletAddress.value : toValue(options.address);
|
|
424
|
+
return value?.trim() || null;
|
|
425
|
+
});
|
|
426
|
+
const query = useQuery({
|
|
427
|
+
store: runtime.queryStore,
|
|
428
|
+
queryKey: () => claimableBalanceKey(
|
|
429
|
+
runtime.networkConfig.horizonUrl,
|
|
430
|
+
runtime.networkConfig.network,
|
|
431
|
+
address.value ?? ""
|
|
432
|
+
),
|
|
433
|
+
queryFn: () => fetchClaimableBalances(runtime.networkConfig, { address: address.value }),
|
|
434
|
+
enabled: () => address.value !== null,
|
|
435
|
+
staleTime: options.staleTime
|
|
436
|
+
});
|
|
437
|
+
return {
|
|
438
|
+
balances: computed(() => query.data.value ?? []),
|
|
439
|
+
loading: computed(() => query.loading.value),
|
|
440
|
+
error: computed(() => query.error.value),
|
|
441
|
+
refetch: query.refetch
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
function usePayments(options = {}) {
|
|
445
|
+
const runtime = useStellarRuntime();
|
|
446
|
+
const address = computed(() => {
|
|
447
|
+
const value = options.address === void 0 ? runtime.walletAddress.value : toValue(options.address);
|
|
448
|
+
return value?.trim() || null;
|
|
449
|
+
});
|
|
450
|
+
const limit = computed(() => toValue(options.limit) ?? 10);
|
|
451
|
+
const order = computed(() => toValue(options.order) ?? "desc");
|
|
452
|
+
const inputCursor = computed(() => toValue(options.cursor));
|
|
453
|
+
const activeCursor = ref(inputCursor.value);
|
|
454
|
+
watch(inputCursor, (cursor) => activeCursor.value = cursor, { flush: "sync" });
|
|
455
|
+
watch(
|
|
456
|
+
[address, limit, order],
|
|
457
|
+
(_next, previous) => {
|
|
458
|
+
if (previous.length > 0) activeCursor.value = void 0;
|
|
459
|
+
},
|
|
460
|
+
{ flush: "sync" }
|
|
461
|
+
);
|
|
462
|
+
const queryKey = computed(
|
|
463
|
+
() => address.value ? paymentsKey(
|
|
464
|
+
runtime.networkConfig.horizonUrl,
|
|
465
|
+
runtime.networkConfig.network,
|
|
466
|
+
address.value,
|
|
467
|
+
limit.value,
|
|
468
|
+
order.value,
|
|
469
|
+
activeCursor.value
|
|
470
|
+
) : ["payments", "disabled"]
|
|
471
|
+
);
|
|
472
|
+
const query = useQuery({
|
|
473
|
+
store: runtime.queryStore,
|
|
474
|
+
queryKey: () => queryKey.value,
|
|
475
|
+
queryFn: () => fetchPaymentsPage(runtime.networkConfig, {
|
|
476
|
+
address: address.value,
|
|
477
|
+
limit: limit.value,
|
|
478
|
+
order: order.value,
|
|
479
|
+
cursor: activeCursor.value
|
|
480
|
+
}),
|
|
481
|
+
enabled: () => address.value !== null,
|
|
482
|
+
maxRetries: options.maxRetries
|
|
483
|
+
});
|
|
484
|
+
const displayed = shallowRef([]);
|
|
485
|
+
const nextPage = shallowRef(null);
|
|
486
|
+
const prevPage = shallowRef(null);
|
|
487
|
+
const pageHasNext = ref(false);
|
|
488
|
+
const pageHasPrev = ref(false);
|
|
489
|
+
const pageLoading = ref(false);
|
|
490
|
+
const pageError = shallowRef(null);
|
|
491
|
+
let requestId = 0;
|
|
492
|
+
function install(page) {
|
|
493
|
+
displayed.value = page.records;
|
|
494
|
+
nextPage.value = page.nextCursor;
|
|
495
|
+
prevPage.value = page.prevCursor;
|
|
496
|
+
pageHasNext.value = page.hasNext;
|
|
497
|
+
pageHasPrev.value = page.hasPrev;
|
|
498
|
+
pageError.value = null;
|
|
499
|
+
}
|
|
500
|
+
watch(
|
|
501
|
+
query.data,
|
|
502
|
+
(page) => {
|
|
503
|
+
requestId += 1;
|
|
504
|
+
pageLoading.value = false;
|
|
505
|
+
if (page) install(page);
|
|
506
|
+
else {
|
|
507
|
+
displayed.value = [];
|
|
508
|
+
nextPage.value = null;
|
|
509
|
+
prevPage.value = null;
|
|
510
|
+
pageHasNext.value = false;
|
|
511
|
+
pageHasPrev.value = false;
|
|
512
|
+
pageError.value = null;
|
|
513
|
+
}
|
|
514
|
+
},
|
|
515
|
+
{ immediate: true, flush: "sync" }
|
|
516
|
+
);
|
|
517
|
+
watch(
|
|
518
|
+
() => serializeKey(queryKey.value),
|
|
519
|
+
() => {
|
|
520
|
+
requestId += 1;
|
|
521
|
+
displayed.value = [];
|
|
522
|
+
nextPage.value = null;
|
|
523
|
+
prevPage.value = null;
|
|
524
|
+
pageHasNext.value = false;
|
|
525
|
+
pageHasPrev.value = false;
|
|
526
|
+
pageLoading.value = false;
|
|
527
|
+
pageError.value = null;
|
|
528
|
+
},
|
|
529
|
+
{ flush: "sync" }
|
|
530
|
+
);
|
|
531
|
+
async function navigate(direction) {
|
|
532
|
+
const load = direction === "next" ? nextPage.value : prevPage.value;
|
|
533
|
+
if (!load || !address.value) return;
|
|
534
|
+
const id = ++requestId;
|
|
535
|
+
pageLoading.value = true;
|
|
536
|
+
pageError.value = null;
|
|
537
|
+
try {
|
|
538
|
+
const response = await load();
|
|
539
|
+
if (id !== requestId || !address.value) return;
|
|
540
|
+
const hasMore = response.records.length > limit.value;
|
|
541
|
+
const records = hasMore ? response.records.slice(0, limit.value) : response.records;
|
|
542
|
+
const normalized = records.map((record) => normalizePayment(record, address.value));
|
|
543
|
+
if (normalized.length > 0) displayed.value = normalized;
|
|
544
|
+
nextPage.value = () => response.next();
|
|
545
|
+
prevPage.value = () => response.prev();
|
|
546
|
+
pageHasNext.value = direction === "next" ? hasMore : true;
|
|
547
|
+
pageHasPrev.value = direction === "prev" ? hasMore : true;
|
|
548
|
+
} catch (cause) {
|
|
549
|
+
if (id !== requestId) return;
|
|
550
|
+
pageError.value = toStellarError(cause);
|
|
551
|
+
} finally {
|
|
552
|
+
if (id === requestId) pageLoading.value = false;
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
async function refetch() {
|
|
556
|
+
requestId += 1;
|
|
557
|
+
pageError.value = null;
|
|
558
|
+
await query.refetch();
|
|
559
|
+
}
|
|
560
|
+
const error = computed(() => pageError.value ?? query.error.value);
|
|
561
|
+
return {
|
|
562
|
+
payments: computed(() => displayed.value),
|
|
563
|
+
loading: computed(() => pageLoading.value || query.loading.value),
|
|
564
|
+
error,
|
|
565
|
+
isStale: computed(() => error.value !== null && displayed.value.length > 0),
|
|
566
|
+
refetch,
|
|
567
|
+
fetchNext: () => navigate("next"),
|
|
568
|
+
fetchPrev: () => navigate("prev"),
|
|
569
|
+
hasNext: computed(() => pageHasNext.value),
|
|
570
|
+
hasPrev: computed(() => pageHasPrev.value)
|
|
571
|
+
};
|
|
572
|
+
}
|
|
573
|
+
function usePaymentHistory(options = {}) {
|
|
574
|
+
const payments = usePayments({
|
|
575
|
+
address: options.address,
|
|
576
|
+
limit: options.limit,
|
|
577
|
+
order: options.order,
|
|
578
|
+
cursor: options.cursor,
|
|
579
|
+
maxRetries: options.maxRetries
|
|
580
|
+
});
|
|
581
|
+
return {
|
|
582
|
+
...payments,
|
|
583
|
+
payments: computed(
|
|
584
|
+
() => filterPayments(payments.payments.value, {
|
|
585
|
+
direction: toValue(options.direction) ?? "all",
|
|
586
|
+
asset: toValue(options.asset) ?? "all"
|
|
587
|
+
})
|
|
588
|
+
)
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
function normalizeKey(key) {
|
|
592
|
+
return typeof key === "string" ? key : JSON.stringify(key);
|
|
593
|
+
}
|
|
594
|
+
var DEFAULT_STALE_TIME = 3e4;
|
|
595
|
+
var DEFAULT_GC_TIME = 3e5;
|
|
596
|
+
var VueQueryStore = class {
|
|
597
|
+
constructor(config = {}) {
|
|
598
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
599
|
+
this.entries = reactive(/* @__PURE__ */ new Map());
|
|
600
|
+
this.staleTime = config.staleTime ?? DEFAULT_STALE_TIME;
|
|
601
|
+
this.gcTime = config.gcTime ?? DEFAULT_GC_TIME;
|
|
602
|
+
}
|
|
603
|
+
ensure(key) {
|
|
604
|
+
const existing = this.entries.get(key);
|
|
605
|
+
if (existing) return existing;
|
|
606
|
+
const entry = {
|
|
607
|
+
data: null,
|
|
608
|
+
updatedAt: null,
|
|
609
|
+
loading: false,
|
|
610
|
+
error: null,
|
|
611
|
+
promise: null,
|
|
612
|
+
subscribers: 0,
|
|
613
|
+
gcTimer: null
|
|
614
|
+
};
|
|
615
|
+
this.entries.set(key, entry);
|
|
616
|
+
return entry;
|
|
617
|
+
}
|
|
618
|
+
/**
|
|
619
|
+
* The live, reactive entry for a key. Read its fields inside a `computed`
|
|
620
|
+
* or `watchEffect` — Vue tracks the read and re-runs when the store writes
|
|
621
|
+
* to it.
|
|
622
|
+
*/
|
|
623
|
+
getEntry(key) {
|
|
624
|
+
return this.ensure(key);
|
|
625
|
+
}
|
|
626
|
+
/**
|
|
627
|
+
* Registers a subscriber for `key` and cancels any pending GC eviction.
|
|
628
|
+
* Returns the unsubscribe function — call it from `onCleanup` /
|
|
629
|
+
* `onScopeDispose` so an idle entry is eventually evicted.
|
|
630
|
+
*/
|
|
631
|
+
subscribe(key) {
|
|
632
|
+
const entry = this.ensure(key);
|
|
633
|
+
entry.subscribers += 1;
|
|
634
|
+
if (entry.gcTimer !== null) {
|
|
635
|
+
clearTimeout(entry.gcTimer);
|
|
636
|
+
entry.gcTimer = null;
|
|
637
|
+
}
|
|
638
|
+
return () => {
|
|
639
|
+
entry.subscribers = Math.max(0, entry.subscribers - 1);
|
|
640
|
+
if (entry.subscribers === 0) this.scheduleGc(key, entry);
|
|
641
|
+
};
|
|
642
|
+
}
|
|
643
|
+
/** Number of active subscribers for a key. Exposed for tests. */
|
|
644
|
+
subscriberCount(key) {
|
|
645
|
+
return this.entries.get(key)?.subscribers ?? 0;
|
|
646
|
+
}
|
|
647
|
+
scheduleGc(key, entry) {
|
|
648
|
+
if (this.gcTime === 0) {
|
|
649
|
+
this.entries.delete(key);
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
652
|
+
entry.gcTimer = setTimeout(() => {
|
|
653
|
+
if (entry.subscribers === 0) this.entries.delete(key);
|
|
654
|
+
}, this.gcTime);
|
|
655
|
+
}
|
|
656
|
+
isFresh(key, staleTime) {
|
|
657
|
+
const entry = this.entries.get(key);
|
|
658
|
+
if (!entry?.updatedAt) return false;
|
|
659
|
+
return Date.now() - entry.updatedAt < (staleTime ?? this.staleTime);
|
|
660
|
+
}
|
|
661
|
+
/**
|
|
662
|
+
* Runs `queryFn` for `key`, deduplicated: a call made while a fetch for the
|
|
663
|
+
* same key is already in flight awaits that same promise instead of
|
|
664
|
+
* issuing a second request — this is what lets two Vue scopes reading the
|
|
665
|
+
* same query share one network call. Skipped entirely when cached data is
|
|
666
|
+
* still within `staleTime`, unless `force` is set.
|
|
667
|
+
*/
|
|
668
|
+
run(key, queryFn, opts = {}) {
|
|
669
|
+
const entry = this.ensure(key);
|
|
670
|
+
if (!opts.force) {
|
|
671
|
+
if (entry.promise) return entry.promise;
|
|
672
|
+
if (entry.data !== null && this.isFresh(key, opts.staleTime)) {
|
|
673
|
+
return Promise.resolve(entry.data);
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
entry.loading = true;
|
|
677
|
+
entry.error = null;
|
|
678
|
+
const promise = queryFn().then(
|
|
679
|
+
(data) => {
|
|
680
|
+
entry.data = data;
|
|
681
|
+
entry.updatedAt = Date.now();
|
|
682
|
+
entry.loading = false;
|
|
683
|
+
entry.error = null;
|
|
684
|
+
entry.promise = null;
|
|
685
|
+
return data;
|
|
686
|
+
},
|
|
687
|
+
(err) => {
|
|
688
|
+
entry.loading = false;
|
|
689
|
+
entry.error = err;
|
|
690
|
+
entry.promise = null;
|
|
691
|
+
throw err;
|
|
692
|
+
}
|
|
693
|
+
);
|
|
694
|
+
entry.promise = promise;
|
|
695
|
+
return promise;
|
|
696
|
+
}
|
|
697
|
+
/** Marks a cached query stale so its next read fetches fresh data. */
|
|
698
|
+
invalidate(key) {
|
|
699
|
+
const entry = this.entries.get(normalizeKey(key));
|
|
700
|
+
if (entry) entry.updatedAt = null;
|
|
701
|
+
}
|
|
702
|
+
/** Empties the store. Useful in tests; not meant for app code. */
|
|
703
|
+
clear() {
|
|
704
|
+
for (const entry of this.entries.values()) {
|
|
705
|
+
if (entry.gcTimer !== null) clearTimeout(entry.gcTimer);
|
|
706
|
+
}
|
|
707
|
+
this.entries.clear();
|
|
708
|
+
}
|
|
709
|
+
};
|
|
710
|
+
|
|
711
|
+
export { VueQueryStore, useAddTrustline, useBalance, useClaimableBalance, useContractEvents, usePathPayment, usePaymentHistory, usePayments, useSendPayment, useSorobanContract };
|
|
712
|
+
//# sourceMappingURL=index.mjs.map
|
|
713
|
+
//# sourceMappingURL=index.mjs.map
|