@unifold/headless-react 0.1.75 → 0.1.76
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/README.md +156 -14
- package/dist/index.d.mts +183 -3
- package/dist/index.d.ts +183 -3
- package/dist/index.js +276 -35
- package/dist/index.mjs +256 -14
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
-
import { UnifoldProvider, useUnifold as
|
|
2
|
+
import { UnifoldProvider, useUnifold as useUnifold10 } from "@unifold/react-provider";
|
|
3
3
|
|
|
4
4
|
// src/use-unifold-client.ts
|
|
5
5
|
import { useMemo } from "react";
|
|
@@ -158,15 +158,231 @@ function useDeposit(options) {
|
|
|
158
158
|
};
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
+
// src/use-onramp.ts
|
|
162
|
+
import { useCallback as useCallback2, useEffect as useEffect2, useMemo as useMemo3, useRef as useRef2, useState as useState2, useSyncExternalStore as useSyncExternalStore2 } from "react";
|
|
163
|
+
import {
|
|
164
|
+
OnrampSession,
|
|
165
|
+
OnrampSessionEventType
|
|
166
|
+
} from "@unifold/core";
|
|
167
|
+
import { useUnifold as useUnifold3 } from "@unifold/react-provider";
|
|
168
|
+
var IDLE_SNAPSHOT2 = {
|
|
169
|
+
status: "idle",
|
|
170
|
+
countryCode: null,
|
|
171
|
+
addresses: [],
|
|
172
|
+
destinationToken: null,
|
|
173
|
+
quotes: [],
|
|
174
|
+
selectedQuote: null,
|
|
175
|
+
isQuoteAutoSelected: true,
|
|
176
|
+
canSelectProvider: false,
|
|
177
|
+
isRefreshingQuotes: false,
|
|
178
|
+
quotesUpdatedAt: null,
|
|
179
|
+
checkout: null,
|
|
180
|
+
executions: [],
|
|
181
|
+
latestExecution: null,
|
|
182
|
+
isCheckingDeposit: false,
|
|
183
|
+
error: null
|
|
184
|
+
};
|
|
185
|
+
function useOnramp(options) {
|
|
186
|
+
const { publishableKey } = useUnifold3();
|
|
187
|
+
const {
|
|
188
|
+
externalUserId,
|
|
189
|
+
destination,
|
|
190
|
+
countryCode,
|
|
191
|
+
subdivisionCode,
|
|
192
|
+
sourceAmount,
|
|
193
|
+
destinationAmount,
|
|
194
|
+
sourceCurrency = "usd",
|
|
195
|
+
paymentMethodType,
|
|
196
|
+
email,
|
|
197
|
+
quoteRefreshIntervalMs,
|
|
198
|
+
quoteDebounceMs = 500,
|
|
199
|
+
autoStart = true
|
|
200
|
+
} = options;
|
|
201
|
+
const callbacksRef = useRef2(options);
|
|
202
|
+
useEffect2(() => {
|
|
203
|
+
callbacksRef.current = options;
|
|
204
|
+
});
|
|
205
|
+
const autoStartRef = useRef2(autoStart);
|
|
206
|
+
autoStartRef.current = autoStart;
|
|
207
|
+
const quoteRequestRef = useRef2({
|
|
208
|
+
countryCode,
|
|
209
|
+
subdivisionCode,
|
|
210
|
+
sourceAmount,
|
|
211
|
+
destinationAmount,
|
|
212
|
+
sourceCurrency
|
|
213
|
+
});
|
|
214
|
+
quoteRequestRef.current = {
|
|
215
|
+
countryCode,
|
|
216
|
+
subdivisionCode,
|
|
217
|
+
sourceAmount,
|
|
218
|
+
destinationAmount,
|
|
219
|
+
sourceCurrency
|
|
220
|
+
};
|
|
221
|
+
const [session, setSession] = useState2(null);
|
|
222
|
+
const sessionKey = [
|
|
223
|
+
publishableKey,
|
|
224
|
+
externalUserId ?? "",
|
|
225
|
+
destination.chainType,
|
|
226
|
+
destination.chainId,
|
|
227
|
+
destination.tokenAddress,
|
|
228
|
+
destination.recipientAddress,
|
|
229
|
+
JSON.stringify(destination.contractCalls ?? null),
|
|
230
|
+
paymentMethodType ?? "",
|
|
231
|
+
email ?? "",
|
|
232
|
+
quoteRefreshIntervalMs ?? ""
|
|
233
|
+
].join("|");
|
|
234
|
+
useEffect2(() => {
|
|
235
|
+
if (!publishableKey || !externalUserId) {
|
|
236
|
+
setSession(null);
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
const nextSession = new OnrampSession({
|
|
240
|
+
publishableKey,
|
|
241
|
+
externalUserId,
|
|
242
|
+
destination,
|
|
243
|
+
quoteRequest: quoteRequestRef.current,
|
|
244
|
+
paymentMethodType,
|
|
245
|
+
email,
|
|
246
|
+
quoteRefreshIntervalMs
|
|
247
|
+
});
|
|
248
|
+
let previousStatus = nextSession.getSnapshot().status;
|
|
249
|
+
const offEvents = nextSession.on("*", (event) => {
|
|
250
|
+
const callbacks = callbacksRef.current;
|
|
251
|
+
callbacks.onEvent?.(event);
|
|
252
|
+
switch (event.type) {
|
|
253
|
+
case OnrampSessionEventType.ADDRESSES_CREATED:
|
|
254
|
+
callbacks.onAddressesReady?.(event.data.object.addresses);
|
|
255
|
+
break;
|
|
256
|
+
case OnrampSessionEventType.QUOTES_UPDATED:
|
|
257
|
+
callbacks.onQuotes?.(event.data.object.quotes, event.data.object.selectedQuote);
|
|
258
|
+
break;
|
|
259
|
+
case OnrampSessionEventType.CHECKOUT_CREATED:
|
|
260
|
+
callbacks.onCheckoutCreated?.({
|
|
261
|
+
externalId: event.data.object.externalId,
|
|
262
|
+
url: event.data.object.url,
|
|
263
|
+
serviceProvider: event.data.object.serviceProvider
|
|
264
|
+
});
|
|
265
|
+
break;
|
|
266
|
+
case OnrampSessionEventType.EXECUTION_DETECTED:
|
|
267
|
+
callbacks.onExecutionDetected?.(event.data.object);
|
|
268
|
+
break;
|
|
269
|
+
case OnrampSessionEventType.EXECUTION_UPDATED:
|
|
270
|
+
callbacks.onExecutionUpdated?.(event.data.object);
|
|
271
|
+
break;
|
|
272
|
+
case OnrampSessionEventType.EXECUTION_SUCCEEDED:
|
|
273
|
+
callbacks.onSuccess?.(event.data.object);
|
|
274
|
+
break;
|
|
275
|
+
case OnrampSessionEventType.EXECUTION_FAILED:
|
|
276
|
+
callbacks.onError?.({
|
|
277
|
+
code: "DEPOSIT_FAILED",
|
|
278
|
+
message: "Deposit failed",
|
|
279
|
+
fatal: false,
|
|
280
|
+
cause: event.data.object
|
|
281
|
+
});
|
|
282
|
+
break;
|
|
283
|
+
case OnrampSessionEventType.SESSION_ERRORED:
|
|
284
|
+
callbacks.onError?.({
|
|
285
|
+
code: event.data.object.code,
|
|
286
|
+
message: event.data.object.message,
|
|
287
|
+
fatal: event.data.object.fatal
|
|
288
|
+
});
|
|
289
|
+
break;
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
const offStatus = nextSession.subscribe(() => {
|
|
293
|
+
const status = nextSession.getSnapshot().status;
|
|
294
|
+
if (status !== previousStatus) {
|
|
295
|
+
previousStatus = status;
|
|
296
|
+
callbacksRef.current.onStatusChange?.(status);
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
setSession(nextSession);
|
|
300
|
+
if (autoStartRef.current) {
|
|
301
|
+
void nextSession.start();
|
|
302
|
+
}
|
|
303
|
+
return () => {
|
|
304
|
+
offEvents();
|
|
305
|
+
offStatus();
|
|
306
|
+
nextSession.destroy();
|
|
307
|
+
};
|
|
308
|
+
}, [sessionKey]);
|
|
309
|
+
const quoteInputKey = [
|
|
310
|
+
countryCode ?? "",
|
|
311
|
+
subdivisionCode ?? "",
|
|
312
|
+
sourceAmount ?? "",
|
|
313
|
+
destinationAmount ?? "",
|
|
314
|
+
sourceCurrency
|
|
315
|
+
].join("|");
|
|
316
|
+
useEffect2(() => {
|
|
317
|
+
if (!session) return;
|
|
318
|
+
const timer = setTimeout(() => {
|
|
319
|
+
session.updateQuoteRequest({
|
|
320
|
+
// undefined keeps the session's value (and IP detection for geo).
|
|
321
|
+
countryCode,
|
|
322
|
+
subdivisionCode,
|
|
323
|
+
sourceAmount,
|
|
324
|
+
destinationAmount,
|
|
325
|
+
sourceCurrency
|
|
326
|
+
});
|
|
327
|
+
}, quoteDebounceMs);
|
|
328
|
+
return () => clearTimeout(timer);
|
|
329
|
+
}, [session, quoteInputKey, quoteDebounceMs]);
|
|
330
|
+
const subscribe = useCallback2(
|
|
331
|
+
(listener) => session ? session.subscribe(listener) : () => {
|
|
332
|
+
},
|
|
333
|
+
[session]
|
|
334
|
+
);
|
|
335
|
+
const getSnapshot = useCallback2(
|
|
336
|
+
() => session ? session.getSnapshot() : IDLE_SNAPSHOT2,
|
|
337
|
+
[session]
|
|
338
|
+
);
|
|
339
|
+
const snapshot = useSyncExternalStore2(subscribe, getSnapshot, () => IDLE_SNAPSHOT2);
|
|
340
|
+
const controls = useMemo3(
|
|
341
|
+
() => ({
|
|
342
|
+
start: () => session?.start() ?? Promise.resolve(),
|
|
343
|
+
refreshQuotes: () => session?.refreshQuotes() ?? Promise.resolve(),
|
|
344
|
+
updateQuoteRequest: (patch) => session?.updateQuoteRequest(patch),
|
|
345
|
+
selectQuote: (serviceProvider) => session?.selectQuote(serviceProvider) ?? null,
|
|
346
|
+
createCheckout: (checkoutOptions) => session ? session.createCheckout(checkoutOptions) : null,
|
|
347
|
+
stop: () => session?.stop(),
|
|
348
|
+
restart: async () => {
|
|
349
|
+
if (!session) return;
|
|
350
|
+
session.stop();
|
|
351
|
+
await session.start();
|
|
352
|
+
}
|
|
353
|
+
}),
|
|
354
|
+
[session]
|
|
355
|
+
);
|
|
356
|
+
return {
|
|
357
|
+
status: snapshot.status,
|
|
358
|
+
countryCode: snapshot.countryCode,
|
|
359
|
+
addresses: snapshot.addresses,
|
|
360
|
+
destinationToken: snapshot.destinationToken,
|
|
361
|
+
quotes: snapshot.quotes,
|
|
362
|
+
selectedQuote: snapshot.selectedQuote,
|
|
363
|
+
isQuoteAutoSelected: snapshot.isQuoteAutoSelected,
|
|
364
|
+
canSelectProvider: snapshot.canSelectProvider,
|
|
365
|
+
isRefreshingQuotes: snapshot.isRefreshingQuotes,
|
|
366
|
+
quotesUpdatedAt: snapshot.quotesUpdatedAt,
|
|
367
|
+
checkout: snapshot.checkout,
|
|
368
|
+
executions: snapshot.executions,
|
|
369
|
+
latestExecution: snapshot.latestExecution,
|
|
370
|
+
isCheckingDeposit: snapshot.isCheckingDeposit,
|
|
371
|
+
error: snapshot.error,
|
|
372
|
+
...controls,
|
|
373
|
+
session
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
|
|
161
377
|
// src/use-deposit-addresses.ts
|
|
162
378
|
import { useQuery } from "@tanstack/react-query";
|
|
163
379
|
import {
|
|
164
380
|
createDepositAddress,
|
|
165
381
|
mapWalletToDepositAddress
|
|
166
382
|
} from "@unifold/core";
|
|
167
|
-
import { useUnifold as
|
|
383
|
+
import { useUnifold as useUnifold4 } from "@unifold/react-provider";
|
|
168
384
|
function useDepositAddresses(options) {
|
|
169
|
-
const { publishableKey } =
|
|
385
|
+
const { publishableKey } = useUnifold4();
|
|
170
386
|
const { externalUserId, destination, actionType, enabled = true } = options;
|
|
171
387
|
return useQuery({
|
|
172
388
|
// Key parity with @unifold/ui-react's useDepositAddress — do not reorder.
|
|
@@ -213,9 +429,9 @@ import { useQuery as useQuery2 } from "@tanstack/react-query";
|
|
|
213
429
|
import {
|
|
214
430
|
getSupportedDepositTokens
|
|
215
431
|
} from "@unifold/core";
|
|
216
|
-
import { useUnifold as
|
|
432
|
+
import { useUnifold as useUnifold5 } from "@unifold/react-provider";
|
|
217
433
|
function useSupportedDepositTokens(options = {}) {
|
|
218
|
-
const { publishableKey } =
|
|
434
|
+
const { publishableKey } = useUnifold5();
|
|
219
435
|
const { destination, productType, enabled = true } = options;
|
|
220
436
|
const completeDestination = destination?.chainType && destination?.chainId && destination?.tokenAddress ? destination : void 0;
|
|
221
437
|
const apiOptions = completeDestination || productType ? {
|
|
@@ -254,9 +470,9 @@ import {
|
|
|
254
470
|
mapDirectExecution,
|
|
255
471
|
ActionType
|
|
256
472
|
} from "@unifold/core";
|
|
257
|
-
import { useUnifold as
|
|
473
|
+
import { useUnifold as useUnifold6 } from "@unifold/react-provider";
|
|
258
474
|
function useExecutions(options) {
|
|
259
|
-
const { publishableKey } =
|
|
475
|
+
const { publishableKey } = useUnifold6();
|
|
260
476
|
const {
|
|
261
477
|
externalUserId,
|
|
262
478
|
refetchInterval = false,
|
|
@@ -279,9 +495,9 @@ function useExecutions(options) {
|
|
|
279
495
|
// src/use-allowed-country.ts
|
|
280
496
|
import { useQuery as useQuery4, keepPreviousData } from "@tanstack/react-query";
|
|
281
497
|
import { getIpAddress, getProjectConfig } from "@unifold/core";
|
|
282
|
-
import { useUnifold as
|
|
498
|
+
import { useUnifold as useUnifold7 } from "@unifold/react-provider";
|
|
283
499
|
function useAllowedCountry() {
|
|
284
|
-
const { publishableKey } =
|
|
500
|
+
const { publishableKey } = useUnifold7();
|
|
285
501
|
const ipQuery = useQuery4({
|
|
286
502
|
// Key parity with @unifold/core's useUserIp.
|
|
287
503
|
queryKey: ["unifold", "userIpInfo"],
|
|
@@ -339,9 +555,9 @@ import { useQuery as useQuery5 } from "@tanstack/react-query";
|
|
|
339
555
|
import {
|
|
340
556
|
verifyRecipientAddress
|
|
341
557
|
} from "@unifold/core";
|
|
342
|
-
import { useUnifold as
|
|
558
|
+
import { useUnifold as useUnifold8 } from "@unifold/react-provider";
|
|
343
559
|
function useAddressValidation(options) {
|
|
344
|
-
const { publishableKey } =
|
|
560
|
+
const { publishableKey } = useUnifold8();
|
|
345
561
|
const { recipientAddress, destination, enabled = true } = options;
|
|
346
562
|
const hasCompleteDestination = !!destination?.chainType && !!destination?.chainId && !!destination?.tokenAddress;
|
|
347
563
|
const shouldValidate = enabled && !!publishableKey && !!recipientAddress && hasCompleteDestination;
|
|
@@ -387,6 +603,24 @@ function useAddressValidation(options) {
|
|
|
387
603
|
};
|
|
388
604
|
}
|
|
389
605
|
|
|
606
|
+
// src/use-fiat-currencies.ts
|
|
607
|
+
import { useQuery as useQuery6 } from "@tanstack/react-query";
|
|
608
|
+
import { getFiatCurrencies } from "@unifold/core";
|
|
609
|
+
import { useUnifold as useUnifold9 } from "@unifold/react-provider";
|
|
610
|
+
function useFiatCurrencies(options = {}) {
|
|
611
|
+
const { publishableKey } = useUnifold9();
|
|
612
|
+
const { enabled = true } = options;
|
|
613
|
+
return useQuery6({
|
|
614
|
+
queryKey: ["unifold", "fiatCurrencies", publishableKey],
|
|
615
|
+
queryFn: () => getFiatCurrencies(publishableKey),
|
|
616
|
+
enabled: enabled && !!publishableKey,
|
|
617
|
+
staleTime: 1e3 * 60 * 5,
|
|
618
|
+
gcTime: 1e3 * 60 * 30,
|
|
619
|
+
refetchOnMount: false,
|
|
620
|
+
refetchOnWindowFocus: false
|
|
621
|
+
});
|
|
622
|
+
}
|
|
623
|
+
|
|
390
624
|
// src/index.ts
|
|
391
625
|
import {
|
|
392
626
|
createUnifoldClient as createUnifoldClient2,
|
|
@@ -394,7 +628,10 @@ import {
|
|
|
394
628
|
DepositSession as DepositSession2,
|
|
395
629
|
DepositSessionEventType as DepositSessionEventType2,
|
|
396
630
|
DepositSessionWaitError,
|
|
397
|
-
|
|
631
|
+
OnrampSession as OnrampSession2,
|
|
632
|
+
OnrampSessionEventType as OnrampSessionEventType2,
|
|
633
|
+
OnrampSessionWaitError,
|
|
634
|
+
ExecutionStatus as ExecutionStatus3,
|
|
398
635
|
ActionType as ActionType2
|
|
399
636
|
} from "@unifold/core";
|
|
400
637
|
export {
|
|
@@ -402,7 +639,10 @@ export {
|
|
|
402
639
|
DepositSession2 as DepositSession,
|
|
403
640
|
DepositSessionEventType2 as DepositSessionEventType,
|
|
404
641
|
DepositSessionWaitError,
|
|
405
|
-
|
|
642
|
+
ExecutionStatus3 as ExecutionStatus,
|
|
643
|
+
OnrampSession2 as OnrampSession,
|
|
644
|
+
OnrampSessionEventType2 as OnrampSessionEventType,
|
|
645
|
+
OnrampSessionWaitError,
|
|
406
646
|
UnifoldClient,
|
|
407
647
|
UnifoldProvider,
|
|
408
648
|
createUnifoldClient2 as createUnifoldClient,
|
|
@@ -411,7 +651,9 @@ export {
|
|
|
411
651
|
useDeposit,
|
|
412
652
|
useDepositAddresses,
|
|
413
653
|
useExecutions,
|
|
654
|
+
useFiatCurrencies,
|
|
655
|
+
useOnramp,
|
|
414
656
|
useSupportedDepositTokens,
|
|
415
|
-
|
|
657
|
+
useUnifold10 as useUnifold,
|
|
416
658
|
useUnifoldClient
|
|
417
659
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unifold/headless-react",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.76",
|
|
4
4
|
"description": "Unifold Headless React SDK - hooks-only (no UI) crypto deposit flows",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"@tanstack/react-query": "^5.90.11",
|
|
24
|
-
"@unifold/core": "0.1.
|
|
25
|
-
"@unifold/react-provider": "0.1.
|
|
24
|
+
"@unifold/core": "0.1.76",
|
|
25
|
+
"@unifold/react-provider": "0.1.76"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@types/react": "^19.0.0",
|