@swype-org/react-sdk 0.1.230 → 0.1.232

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/index.js CHANGED
@@ -155,6 +155,322 @@ function useBlinkDepositAmount() {
155
155
  };
156
156
  }
157
157
 
158
+ // src/passkey-delegation.ts
159
+ var PasskeyIframeBlockedError = class extends Error {
160
+ constructor(message = "Passkey creation is not supported in this browser context.") {
161
+ super(message);
162
+ this.name = "PasskeyIframeBlockedError";
163
+ }
164
+ };
165
+ function isInCrossOriginIframe() {
166
+ if (typeof window === "undefined") return false;
167
+ if (window.parent === window) return false;
168
+ try {
169
+ void window.parent.location.origin;
170
+ return false;
171
+ } catch {
172
+ return true;
173
+ }
174
+ }
175
+ function isSafari() {
176
+ if (typeof navigator === "undefined") return false;
177
+ const ua = navigator.userAgent;
178
+ return /Safari/i.test(ua) && !/Chrome|CriOS|Chromium|Edg|OPR|Firefox/i.test(ua);
179
+ }
180
+ var POPUP_RESULT_TIMEOUT_MS = 12e4;
181
+ var POPUP_CLOSED_POLL_MS = 500;
182
+ var POPUP_CLOSED_GRACE_MS = 1e3;
183
+ function createPasskeyViaPopup(options) {
184
+ return new Promise((resolve, reject) => {
185
+ const verificationToken = crypto.randomUUID();
186
+ const payload = { ...options, verificationToken };
187
+ const encoded = btoa(JSON.stringify(payload));
188
+ const popupUrl = `${window.location.origin}/passkey-register#${encoded}`;
189
+ const popup = window.open(popupUrl, "blink-passkey");
190
+ if (!popup) {
191
+ reject(new Error("Pop-up blocked. Please allow pop-ups for this site and try again."));
192
+ return;
193
+ }
194
+ let settled = false;
195
+ const timer = setTimeout(() => {
196
+ cleanup();
197
+ reject(new Error("Passkey creation timed out. Please try again."));
198
+ }, POPUP_RESULT_TIMEOUT_MS);
199
+ const closedPoll = setInterval(() => {
200
+ if (popup.closed) {
201
+ clearInterval(closedPoll);
202
+ setTimeout(() => {
203
+ if (!settled) {
204
+ settled = true;
205
+ cleanup();
206
+ checkServerForPasskeyByToken(
207
+ options.authToken,
208
+ options.apiBaseUrl,
209
+ verificationToken
210
+ ).then((result) => {
211
+ if (result) {
212
+ resolve(result);
213
+ } else {
214
+ reject(new Error("Passkey window was closed before completing."));
215
+ }
216
+ }).catch(() => {
217
+ reject(new Error("Passkey window was closed before completing."));
218
+ });
219
+ }
220
+ }, POPUP_CLOSED_GRACE_MS);
221
+ }
222
+ }, POPUP_CLOSED_POLL_MS);
223
+ function cleanup() {
224
+ clearTimeout(timer);
225
+ clearInterval(closedPoll);
226
+ }
227
+ });
228
+ }
229
+ var VERIFY_POPUP_TIMEOUT_MS = 6e4;
230
+ function findDevicePasskeyViaPopup(options) {
231
+ return new Promise((resolve, reject) => {
232
+ const verificationToken = crypto.randomUUID();
233
+ const payload = {
234
+ ...options,
235
+ verificationToken
236
+ };
237
+ const encoded = btoa(JSON.stringify(payload));
238
+ const popupUrl = `${window.location.origin}/passkey-verify#${encoded}`;
239
+ const popup = window.open(popupUrl, "blink-passkey-verify");
240
+ if (!popup) {
241
+ reject(new Error("Pop-up blocked. Please allow pop-ups for this site and try again."));
242
+ return;
243
+ }
244
+ let settled = false;
245
+ const timer = setTimeout(() => {
246
+ cleanup();
247
+ resolve(null);
248
+ }, VERIFY_POPUP_TIMEOUT_MS);
249
+ const closedPoll = setInterval(() => {
250
+ if (popup.closed && !settled) {
251
+ clearInterval(closedPoll);
252
+ setTimeout(() => {
253
+ if (!settled) {
254
+ settled = true;
255
+ cleanup();
256
+ checkServerForPasskeyByToken(
257
+ options.authToken,
258
+ options.apiBaseUrl,
259
+ verificationToken
260
+ ).then((result) => {
261
+ resolve(result?.credentialId ?? null);
262
+ }).catch(() => {
263
+ resolve(null);
264
+ });
265
+ }
266
+ }, POPUP_CLOSED_GRACE_MS);
267
+ }
268
+ }, POPUP_CLOSED_POLL_MS);
269
+ function cleanup() {
270
+ clearTimeout(timer);
271
+ clearInterval(closedPoll);
272
+ }
273
+ });
274
+ }
275
+ async function checkServerForPasskeyByToken(authToken, apiBaseUrl, verificationToken) {
276
+ if (!authToken || !apiBaseUrl) return null;
277
+ const res = await fetch(`${apiBaseUrl}/v1/users/config`, {
278
+ headers: { Authorization: `Bearer ${authToken}` }
279
+ });
280
+ if (!res.ok) return null;
281
+ const body = await res.json();
282
+ const passkeys = body.config.passkeys ?? [];
283
+ const matched = passkeys.find((p) => p.lastVerificationToken === verificationToken);
284
+ return matched ? { credentialId: matched.credentialId, publicKey: matched.publicKey } : null;
285
+ }
286
+
287
+ // src/passkeyRpId.ts
288
+ function normalizeConfiguredDomain(value) {
289
+ return value.replace(/^https?:\/\//, "").replace(/\/.*$/, "").replace(/^\./, "").trim();
290
+ }
291
+ function resolveRootDomainFromHostname(hostname) {
292
+ const trimmedHostname = hostname.trim().toLowerCase();
293
+ if (!trimmedHostname) {
294
+ return "localhost";
295
+ }
296
+ if (trimmedHostname === "localhost" || /^\d{1,3}(?:\.\d{1,3}){3}$/.test(trimmedHostname)) {
297
+ return trimmedHostname;
298
+ }
299
+ const parts = trimmedHostname.split(".").filter(Boolean);
300
+ if (parts.length < 2) {
301
+ return trimmedHostname;
302
+ }
303
+ return parts.slice(-2).join(".");
304
+ }
305
+
306
+ // src/hooks/passkeyPublic.ts
307
+ function waitForDocumentFocus(timeoutMs = 5e3, intervalMs = 100) {
308
+ return new Promise((resolve, reject) => {
309
+ if (typeof document === "undefined") {
310
+ resolve();
311
+ return;
312
+ }
313
+ if (document.hasFocus()) {
314
+ resolve();
315
+ return;
316
+ }
317
+ const deadline = Date.now() + timeoutMs;
318
+ const timer = setInterval(() => {
319
+ if (document.hasFocus()) {
320
+ clearInterval(timer);
321
+ resolve();
322
+ } else if (Date.now() >= deadline) {
323
+ clearInterval(timer);
324
+ resolve();
325
+ }
326
+ }, intervalMs);
327
+ });
328
+ }
329
+ function toBase64(buffer) {
330
+ return btoa(String.fromCharCode(...new Uint8Array(buffer)));
331
+ }
332
+ function base64ToBytes(value) {
333
+ const normalized = value.replace(/-/g, "+").replace(/_/g, "/");
334
+ const padded = normalized + "=".repeat((4 - normalized.length % 4) % 4);
335
+ const raw = atob(padded);
336
+ const bytes = new Uint8Array(raw.length);
337
+ for (let i = 0; i < raw.length; i++) {
338
+ bytes[i] = raw.charCodeAt(i);
339
+ }
340
+ return bytes;
341
+ }
342
+ function readEnvValue(name) {
343
+ const meta = import.meta;
344
+ const metaValue = meta.env?.[name];
345
+ if (typeof metaValue === "string" && metaValue.trim().length > 0) {
346
+ return metaValue.trim();
347
+ }
348
+ const processValue = globalThis.process?.env?.[name];
349
+ if (typeof processValue === "string" && processValue.trim().length > 0) {
350
+ return processValue.trim();
351
+ }
352
+ return void 0;
353
+ }
354
+ function resolvePasskeyRpId() {
355
+ const configuredDomain = readEnvValue("VITE_DOMAIN") ?? readEnvValue("BLINK_DOMAIN");
356
+ if (configuredDomain) {
357
+ return normalizeConfiguredDomain(configuredDomain);
358
+ }
359
+ if (typeof window !== "undefined") {
360
+ return resolveRootDomainFromHostname(window.location.hostname);
361
+ }
362
+ return "localhost";
363
+ }
364
+ async function createPasskeyCredential(params) {
365
+ const challenge = new Uint8Array(32);
366
+ crypto.getRandomValues(challenge);
367
+ const rpId = resolvePasskeyRpId();
368
+ const publicKeyOptions = {
369
+ challenge,
370
+ rp: { name: "Blink", id: rpId },
371
+ user: {
372
+ id: new TextEncoder().encode(params.userId),
373
+ name: params.displayName,
374
+ displayName: params.displayName
375
+ },
376
+ pubKeyCredParams: [
377
+ { alg: -7, type: "public-key" },
378
+ { alg: -257, type: "public-key" }
379
+ ],
380
+ authenticatorSelection: {
381
+ authenticatorAttachment: "platform",
382
+ residentKey: "preferred",
383
+ userVerification: "required"
384
+ },
385
+ timeout: 6e4
386
+ };
387
+ if (isInCrossOriginIframe()) {
388
+ try {
389
+ await waitForDocumentFocus();
390
+ const credential2 = await navigator.credentials.create({
391
+ publicKey: publicKeyOptions
392
+ });
393
+ if (!credential2) {
394
+ throw new Error("Passkey creation was cancelled.");
395
+ }
396
+ return extractPasskeyResult(credential2);
397
+ } catch (err) {
398
+ if (err instanceof PasskeyIframeBlockedError) throw err;
399
+ if (err instanceof Error && err.message === "Passkey creation was cancelled.") throw err;
400
+ throw new PasskeyIframeBlockedError();
401
+ }
402
+ }
403
+ await waitForDocumentFocus();
404
+ const credential = await navigator.credentials.create({
405
+ publicKey: publicKeyOptions
406
+ });
407
+ if (!credential) {
408
+ throw new Error("Passkey creation was cancelled.");
409
+ }
410
+ return extractPasskeyResult(credential);
411
+ }
412
+ function extractPasskeyResult(credential) {
413
+ const response = credential.response;
414
+ const publicKeyBytes = response.getPublicKey?.();
415
+ return {
416
+ credentialId: toBase64(credential.rawId),
417
+ publicKey: publicKeyBytes ? toBase64(publicKeyBytes) : ""
418
+ };
419
+ }
420
+ function buildPasskeyPopupOptions(params) {
421
+ const challenge = new Uint8Array(32);
422
+ crypto.getRandomValues(challenge);
423
+ const rpId = resolvePasskeyRpId();
424
+ return {
425
+ challenge: toBase64(challenge),
426
+ rpId,
427
+ rpName: "Blink",
428
+ userId: toBase64(new TextEncoder().encode(params.userId)),
429
+ userName: params.displayName,
430
+ userDisplayName: params.displayName,
431
+ pubKeyCredParams: [
432
+ { alg: -7, type: "public-key" },
433
+ { alg: -257, type: "public-key" }
434
+ ],
435
+ authenticatorSelection: {
436
+ authenticatorAttachment: "platform",
437
+ residentKey: "preferred",
438
+ userVerification: "required"
439
+ },
440
+ timeout: 6e4,
441
+ authToken: params.authToken,
442
+ apiBaseUrl: params.apiBaseUrl
443
+ };
444
+ }
445
+ async function deviceHasPasskey(credentialId) {
446
+ const found = await findDevicePasskey([credentialId]);
447
+ return found != null;
448
+ }
449
+ async function findDevicePasskey(credentialIds) {
450
+ if (credentialIds.length === 0) return null;
451
+ try {
452
+ const challenge = new Uint8Array(32);
453
+ crypto.getRandomValues(challenge);
454
+ await waitForDocumentFocus();
455
+ const assertion = await navigator.credentials.get({
456
+ publicKey: {
457
+ challenge,
458
+ rpId: resolvePasskeyRpId(),
459
+ allowCredentials: credentialIds.map((id) => ({
460
+ type: "public-key",
461
+ id: base64ToBytes(id)
462
+ })),
463
+ userVerification: "discouraged",
464
+ timeout: 3e4
465
+ }
466
+ });
467
+ if (!assertion) return null;
468
+ return toBase64(assertion.rawId);
469
+ } catch {
470
+ return null;
471
+ }
472
+ }
473
+
158
474
  // src/api.ts
159
475
  var api_exports = {};
160
476
  __export(api_exports, {
@@ -166,6 +482,7 @@ __export(api_exports, {
166
482
  fetchAccount: () => fetchAccount,
167
483
  fetchAccounts: () => fetchAccounts,
168
484
  fetchAuthorizationSession: () => fetchAuthorizationSession,
485
+ fetchAuthorizationSessionByToken: () => fetchAuthorizationSessionByToken,
169
486
  fetchChains: () => fetchChains,
170
487
  fetchGuestAccount: () => fetchGuestAccount,
171
488
  fetchGuestTransferBalances: () => fetchGuestTransferBalances,
@@ -345,6 +662,13 @@ async function fetchAuthorizationSession(apiBaseUrl, sessionId) {
345
662
  if (!res.ok) await throwApiError(res);
346
663
  return await res.json();
347
664
  }
665
+ async function fetchAuthorizationSessionByToken(apiBaseUrl, token) {
666
+ const res = await fetch(
667
+ `${apiBaseUrl}/v1/authorization-sessions?token=${encodeURIComponent(token)}`
668
+ );
669
+ if (!res.ok) await throwApiError(res);
670
+ return await res.json();
671
+ }
348
672
  async function registerPasskey(apiBaseUrl, token, credentialId, publicKey) {
349
673
  const res = await fetch(`${apiBaseUrl}/v1/users/config/passkey`, {
350
674
  method: "POST",
@@ -501,17 +825,87 @@ async function setAccountOwner(apiBaseUrl, accessToken, accountId, guestSessionT
501
825
  if (!res.ok) await throwApiError(res);
502
826
  return await res.json();
503
827
  }
504
- async function reportActionCompletion(apiBaseUrl, actionId, result) {
505
- const res = await fetch(
506
- `${apiBaseUrl}/v1/authorization-actions/${actionId}`,
507
- {
508
- method: "PATCH",
509
- headers: { "Content-Type": "application/json" },
510
- body: JSON.stringify({ status: "COMPLETED", result })
828
+ async function reportActionCompletion(apiBaseUrl, actionId, result) {
829
+ const res = await fetch(
830
+ `${apiBaseUrl}/v1/authorization-actions/${actionId}`,
831
+ {
832
+ method: "PATCH",
833
+ headers: { "Content-Type": "application/json" },
834
+ body: JSON.stringify({ status: "COMPLETED", result })
835
+ }
836
+ );
837
+ if (!res.ok) await throwApiError(res);
838
+ return await res.json();
839
+ }
840
+
841
+ // src/transferPolling.ts
842
+ async function pollTransferTick(params) {
843
+ const fetchTransfer2 = params.fetchTransfer ?? fetchTransfer;
844
+ const token = await params.getAccessToken();
845
+ if (!token) {
846
+ return { kind: "retry" };
847
+ }
848
+ try {
849
+ const transfer = await fetchTransfer2(params.apiBaseUrl, token, params.transferId);
850
+ return { kind: "success", transfer };
851
+ } catch (err) {
852
+ return {
853
+ kind: "error",
854
+ message: err instanceof Error ? err.message : "Polling error"
855
+ };
856
+ }
857
+ }
858
+
859
+ // src/hooks/useTransferPolling.ts
860
+ function useTransferPolling(intervalMs = 3e3) {
861
+ const { apiBaseUrl } = useBlinkConfig();
862
+ const { getAccessToken } = usePrivy();
863
+ const [transfer, setTransfer] = useState(null);
864
+ const [error, setError] = useState(null);
865
+ const [isPolling, setIsPolling] = useState(false);
866
+ const intervalRef = useRef(null);
867
+ const transferIdRef = useRef(null);
868
+ const stopPolling = useCallback(() => {
869
+ if (intervalRef.current) {
870
+ clearInterval(intervalRef.current);
871
+ intervalRef.current = null;
872
+ }
873
+ setIsPolling(false);
874
+ }, []);
875
+ const poll = useCallback(async () => {
876
+ if (!transferIdRef.current) return;
877
+ const result = await pollTransferTick({
878
+ apiBaseUrl,
879
+ transferId: transferIdRef.current,
880
+ getAccessToken
881
+ });
882
+ if (result.kind === "retry") {
883
+ return;
884
+ }
885
+ if (result.kind === "error") {
886
+ setError(result.message);
887
+ stopPolling();
888
+ return;
511
889
  }
890
+ setError(null);
891
+ setTransfer(result.transfer);
892
+ if (result.transfer.status === "COMPLETED" || result.transfer.status === "FAILED") {
893
+ stopPolling();
894
+ }
895
+ }, [apiBaseUrl, getAccessToken, stopPolling]);
896
+ const startPolling = useCallback(
897
+ (transferId) => {
898
+ stopPolling();
899
+ transferIdRef.current = transferId;
900
+ setIsPolling(true);
901
+ setError(null);
902
+ poll();
903
+ intervalRef.current = setInterval(poll, intervalMs);
904
+ },
905
+ [poll, intervalMs, stopPolling]
512
906
  );
513
- if (!res.ok) await throwApiError(res);
514
- return await res.json();
907
+ useEffect(() => () => stopPolling(), [stopPolling]);
908
+ return { transfer, error, isPolling, startPolling, stopPolling };
515
909
  }
516
910
 
517
911
  // node_modules/@wagmi/core/dist/esm/utils/getAction.js
@@ -811,250 +1205,61 @@ async function waitForTransactionReceipt(config, parameters) {
811
1205
  chainId: client.chain.id
812
1206
  };
813
1207
  }
814
-
815
- // src/passkeyRpId.ts
816
- function normalizeConfiguredDomain(value) {
817
- return value.replace(/^https?:\/\//, "").replace(/\/.*$/, "").replace(/^\./, "").trim();
818
- }
819
- function resolveRootDomainFromHostname(hostname) {
820
- const trimmedHostname = hostname.trim().toLowerCase();
821
- if (!trimmedHostname) {
822
- return "localhost";
823
- }
824
- if (trimmedHostname === "localhost" || /^\d{1,3}(?:\.\d{1,3}){3}$/.test(trimmedHostname)) {
825
- return trimmedHostname;
826
- }
827
- const parts = trimmedHostname.split(".").filter(Boolean);
828
- if (parts.length < 2) {
829
- return trimmedHostname;
830
- }
831
- return parts.slice(-2).join(".");
832
- }
833
1208
  var ERC_6492_MAGIC_SUFFIX = "6492649264926492649264926492649264926492649264926492649264926492";
834
1209
  function normalizeSignature(sig) {
835
1210
  const hex = sig.startsWith("0x") ? sig.slice(2) : sig;
836
1211
  if (hex.length === 130) {
837
1212
  return `0x${hex}`;
838
1213
  }
839
- if (hex.length === 128) {
840
- const r = hex.slice(0, 64);
841
- const yParityAndS = hex.slice(64, 128);
842
- const highByte = parseInt(yParityAndS.slice(0, 2), 16);
843
- const v = (highByte & 128) !== 0 ? 28 : 27;
844
- const sFirstByte = (highByte & 127).toString(16).padStart(2, "0");
845
- const s = sFirstByte + yParityAndS.slice(2);
846
- return `0x${r}${s}${v.toString(16)}`;
847
- }
848
- if (hex.length > 64 && hex.endsWith(ERC_6492_MAGIC_SUFFIX)) {
849
- const { signature: inner } = parseErc6492Signature(
850
- `0x${hex}`
851
- );
852
- return normalizeSignature(inner);
853
- }
854
- if (hex.length > 130) {
855
- try {
856
- const [, innerBytes] = decodeAbiParameters(
857
- [{ type: "uint256" }, { type: "bytes" }],
858
- `0x${hex}`
859
- );
860
- return normalizeSignature(innerBytes);
861
- } catch {
862
- try {
863
- const [wrapper] = decodeAbiParameters(
864
- [{
865
- type: "tuple",
866
- components: [{ type: "uint8" }, { type: "bytes" }]
867
- }],
868
- `0x${hex}`
869
- );
870
- return normalizeSignature(wrapper[1]);
871
- } catch {
872
- return `0x${hex}`;
873
- }
874
- }
875
- }
876
- throw new Error(
877
- `Invalid signature: unable to normalize. Length=${hex.length / 2} bytes. Expected 65, 64, ERC-6492 wrapped, or ABI-encoded SignatureWrapper.`
878
- );
879
- }
880
-
881
- // src/transferPolling.ts
882
- async function pollTransferTick(params) {
883
- const fetchTransfer2 = params.fetchTransfer ?? fetchTransfer;
884
- const token = await params.getAccessToken();
885
- if (!token) {
886
- return { kind: "retry" };
887
- }
888
- try {
889
- const transfer = await fetchTransfer2(params.apiBaseUrl, token, params.transferId);
890
- return { kind: "success", transfer };
891
- } catch (err) {
892
- return {
893
- kind: "error",
894
- message: err instanceof Error ? err.message : "Polling error"
895
- };
896
- }
897
- }
898
-
899
- // src/passkey-delegation.ts
900
- var PasskeyIframeBlockedError = class extends Error {
901
- constructor(message = "Passkey creation is not supported in this browser context.") {
902
- super(message);
903
- this.name = "PasskeyIframeBlockedError";
904
- }
905
- };
906
- function isInCrossOriginIframe() {
907
- if (typeof window === "undefined") return false;
908
- if (window.parent === window) return false;
909
- try {
910
- void window.parent.location.origin;
911
- return false;
912
- } catch {
913
- return true;
914
- }
915
- }
916
- function isSafari() {
917
- if (typeof navigator === "undefined") return false;
918
- const ua = navigator.userAgent;
919
- return /Safari/i.test(ua) && !/Chrome|CriOS|Chromium|Edg|OPR|Firefox/i.test(ua);
920
- }
921
- var POPUP_RESULT_TIMEOUT_MS = 12e4;
922
- var POPUP_CLOSED_POLL_MS = 500;
923
- var POPUP_CLOSED_GRACE_MS = 1e3;
924
- function createPasskeyViaPopup(options) {
925
- return new Promise((resolve, reject) => {
926
- const verificationToken = crypto.randomUUID();
927
- const payload = { ...options, verificationToken };
928
- const encoded = btoa(JSON.stringify(payload));
929
- const popupUrl = `${window.location.origin}/passkey-register#${encoded}`;
930
- const popup = window.open(popupUrl, "blink-passkey");
931
- if (!popup) {
932
- reject(new Error("Pop-up blocked. Please allow pop-ups for this site and try again."));
933
- return;
934
- }
935
- let settled = false;
936
- const timer = setTimeout(() => {
937
- cleanup();
938
- reject(new Error("Passkey creation timed out. Please try again."));
939
- }, POPUP_RESULT_TIMEOUT_MS);
940
- const closedPoll = setInterval(() => {
941
- if (popup.closed) {
942
- clearInterval(closedPoll);
943
- setTimeout(() => {
944
- if (!settled) {
945
- settled = true;
946
- cleanup();
947
- checkServerForPasskeyByToken(
948
- options.authToken,
949
- options.apiBaseUrl,
950
- verificationToken
951
- ).then((result) => {
952
- if (result) {
953
- resolve(result);
954
- } else {
955
- reject(new Error("Passkey window was closed before completing."));
956
- }
957
- }).catch(() => {
958
- reject(new Error("Passkey window was closed before completing."));
959
- });
960
- }
961
- }, POPUP_CLOSED_GRACE_MS);
962
- }
963
- }, POPUP_CLOSED_POLL_MS);
964
- function cleanup() {
965
- clearTimeout(timer);
966
- clearInterval(closedPoll);
967
- }
968
- });
969
- }
970
- var VERIFY_POPUP_TIMEOUT_MS = 6e4;
971
- function findDevicePasskeyViaPopup(options) {
972
- return new Promise((resolve, reject) => {
973
- const verificationToken = crypto.randomUUID();
974
- const payload = {
975
- ...options,
976
- verificationToken
977
- };
978
- const encoded = btoa(JSON.stringify(payload));
979
- const popupUrl = `${window.location.origin}/passkey-verify#${encoded}`;
980
- const popup = window.open(popupUrl, "blink-passkey-verify");
981
- if (!popup) {
982
- reject(new Error("Pop-up blocked. Please allow pop-ups for this site and try again."));
983
- return;
984
- }
985
- let settled = false;
986
- const timer = setTimeout(() => {
987
- cleanup();
988
- resolve(null);
989
- }, VERIFY_POPUP_TIMEOUT_MS);
990
- const closedPoll = setInterval(() => {
991
- if (popup.closed && !settled) {
992
- clearInterval(closedPoll);
993
- setTimeout(() => {
994
- if (!settled) {
995
- settled = true;
996
- cleanup();
997
- checkServerForPasskeyByToken(
998
- options.authToken,
999
- options.apiBaseUrl,
1000
- verificationToken
1001
- ).then((result) => {
1002
- resolve(result?.credentialId ?? null);
1003
- }).catch(() => {
1004
- resolve(null);
1005
- });
1006
- }
1007
- }, POPUP_CLOSED_GRACE_MS);
1214
+ if (hex.length === 128) {
1215
+ const r = hex.slice(0, 64);
1216
+ const yParityAndS = hex.slice(64, 128);
1217
+ const highByte = parseInt(yParityAndS.slice(0, 2), 16);
1218
+ const v = (highByte & 128) !== 0 ? 28 : 27;
1219
+ const sFirstByte = (highByte & 127).toString(16).padStart(2, "0");
1220
+ const s = sFirstByte + yParityAndS.slice(2);
1221
+ return `0x${r}${s}${v.toString(16)}`;
1222
+ }
1223
+ if (hex.length > 64 && hex.endsWith(ERC_6492_MAGIC_SUFFIX)) {
1224
+ const { signature: inner } = parseErc6492Signature(
1225
+ `0x${hex}`
1226
+ );
1227
+ return normalizeSignature(inner);
1228
+ }
1229
+ if (hex.length > 130) {
1230
+ try {
1231
+ const [, innerBytes] = decodeAbiParameters(
1232
+ [{ type: "uint256" }, { type: "bytes" }],
1233
+ `0x${hex}`
1234
+ );
1235
+ return normalizeSignature(innerBytes);
1236
+ } catch {
1237
+ try {
1238
+ const [wrapper] = decodeAbiParameters(
1239
+ [{
1240
+ type: "tuple",
1241
+ components: [{ type: "uint8" }, { type: "bytes" }]
1242
+ }],
1243
+ `0x${hex}`
1244
+ );
1245
+ return normalizeSignature(wrapper[1]);
1246
+ } catch {
1247
+ return `0x${hex}`;
1008
1248
  }
1009
- }, POPUP_CLOSED_POLL_MS);
1010
- function cleanup() {
1011
- clearTimeout(timer);
1012
- clearInterval(closedPoll);
1013
1249
  }
1014
- });
1015
- }
1016
- async function checkServerForPasskeyByToken(authToken, apiBaseUrl, verificationToken) {
1017
- if (!authToken || !apiBaseUrl) return null;
1018
- const res = await fetch(`${apiBaseUrl}/v1/users/config`, {
1019
- headers: { Authorization: `Bearer ${authToken}` }
1020
- });
1021
- if (!res.ok) return null;
1022
- const body = await res.json();
1023
- const passkeys = body.config.passkeys ?? [];
1024
- const matched = passkeys.find((p) => p.lastVerificationToken === verificationToken);
1025
- return matched ? { credentialId: matched.credentialId, publicKey: matched.publicKey } : null;
1250
+ }
1251
+ throw new Error(
1252
+ `Invalid signature: unable to normalize. Length=${hex.length / 2} bytes. Expected 65, 64, ERC-6492 wrapped, or ABI-encoded SignatureWrapper.`
1253
+ );
1026
1254
  }
1027
1255
 
1028
- // src/hooks.ts
1256
+ // src/hooks/authorizationExecutor.ts
1029
1257
  var WALLET_CLIENT_MAX_ATTEMPTS = 25;
1030
1258
  var WALLET_CLIENT_POLL_MS = 400;
1031
1259
  var ACTION_POLL_INTERVAL_MS = 500;
1032
1260
  var ACTION_POLL_MAX_RETRIES = 20;
1033
1261
  var SIGN_PERMIT2_POLL_MS = 1e3;
1034
1262
  var SIGN_PERMIT2_MAX_POLLS = 15;
1035
- var TRANSFER_SIGN_MAX_POLLS = 60;
1036
- function waitForDocumentFocus(timeoutMs = 5e3, intervalMs = 100) {
1037
- return new Promise((resolve, reject) => {
1038
- if (typeof document === "undefined") {
1039
- resolve();
1040
- return;
1041
- }
1042
- if (document.hasFocus()) {
1043
- resolve();
1044
- return;
1045
- }
1046
- const deadline = Date.now() + timeoutMs;
1047
- const timer = setInterval(() => {
1048
- if (document.hasFocus()) {
1049
- clearInterval(timer);
1050
- resolve();
1051
- } else if (Date.now() >= deadline) {
1052
- clearInterval(timer);
1053
- resolve();
1054
- }
1055
- }, intervalMs);
1056
- });
1057
- }
1058
1263
  function actionSuccess(action, message, data) {
1059
1264
  return { actionId: action.id, type: action.type, status: "success", message, data };
1060
1265
  }
@@ -1065,243 +1270,44 @@ function isUserRejection(msg) {
1065
1270
  const lower = msg.toLowerCase();
1066
1271
  return lower.includes("rejected") || lower.includes("denied");
1067
1272
  }
1068
- function hexToBytes(hex) {
1069
- const clean = hex.startsWith("0x") ? hex.slice(2) : hex;
1070
- const bytes = clean.match(/.{1,2}/g).map((b) => parseInt(b, 16));
1071
- return new Uint8Array(bytes);
1072
- }
1073
- function toBase64(buffer) {
1074
- return btoa(String.fromCharCode(...new Uint8Array(buffer)));
1075
- }
1076
- function base64ToBytes(value) {
1077
- const normalized = value.replace(/-/g, "+").replace(/_/g, "/");
1078
- const padded = normalized + "=".repeat((4 - normalized.length % 4) % 4);
1079
- const raw = atob(padded);
1080
- const bytes = new Uint8Array(raw.length);
1081
- for (let i = 0; i < raw.length; i++) {
1082
- bytes[i] = raw.charCodeAt(i);
1083
- }
1084
- return bytes;
1085
- }
1086
- function readEnvValue(name) {
1087
- const meta = import.meta;
1088
- const metaValue = meta.env?.[name];
1089
- if (typeof metaValue === "string" && metaValue.trim().length > 0) {
1090
- return metaValue.trim();
1091
- }
1092
- const processValue = globalThis.process?.env?.[name];
1093
- if (typeof processValue === "string" && processValue.trim().length > 0) {
1094
- return processValue.trim();
1095
- }
1096
- return void 0;
1097
- }
1098
- function resolvePasskeyRpId() {
1099
- const configuredDomain = readEnvValue("VITE_DOMAIN") ?? readEnvValue("BLINK_DOMAIN");
1100
- if (configuredDomain) {
1101
- return normalizeConfiguredDomain(configuredDomain);
1102
- }
1103
- if (typeof window !== "undefined") {
1104
- return resolveRootDomainFromHostname(window.location.hostname);
1105
- }
1106
- return "localhost";
1107
- }
1108
1273
  async function waitForWalletClient(wagmiConfig2, params = {}) {
1109
- for (let i = 0; i < WALLET_CLIENT_MAX_ATTEMPTS; i++) {
1110
- try {
1111
- const account = getAccount(wagmiConfig2);
1112
- const enrichedParams = account.connector ? { ...params, connector: account.connector } : params;
1113
- return await getWalletClient(wagmiConfig2, enrichedParams);
1114
- } catch {
1115
- if (i === WALLET_CLIENT_MAX_ATTEMPTS - 1) {
1116
- throw new Error("Wallet not ready. Please try again.");
1117
- }
1118
- await new Promise((r) => setTimeout(r, WALLET_CLIENT_POLL_MS));
1119
- }
1120
- }
1121
- throw new Error("Wallet not ready. Please try again.");
1122
- }
1123
- function parseSignTypedDataPayload(typedData) {
1124
- const { domain, types, primaryType, message } = typedData;
1125
- if (!domain || typeof domain !== "object" || Array.isArray(domain)) {
1126
- throw new Error("SIGN_PERMIT2 typedData is missing a valid domain object.");
1127
- }
1128
- if (!types || typeof types !== "object" || Array.isArray(types)) {
1129
- throw new Error("SIGN_PERMIT2 typedData is missing a valid types object.");
1130
- }
1131
- if (typeof primaryType !== "string") {
1132
- throw new Error("SIGN_PERMIT2 typedData is missing primaryType.");
1133
- }
1134
- if (!message || typeof message !== "object" || Array.isArray(message)) {
1135
- throw new Error("SIGN_PERMIT2 typedData is missing a valid message object.");
1136
- }
1137
- return {
1138
- domain,
1139
- types,
1140
- primaryType,
1141
- message
1142
- };
1143
- }
1144
- function getPendingActions(session, completedIds) {
1145
- return session.actions.filter((a) => a.status === "PENDING" && !completedIds.has(a.id)).sort((a, b) => a.orderIndex - b.orderIndex);
1146
- }
1147
- async function createPasskeyCredential(params) {
1148
- const challenge = new Uint8Array(32);
1149
- crypto.getRandomValues(challenge);
1150
- const rpId = resolvePasskeyRpId();
1151
- const publicKeyOptions = {
1152
- challenge,
1153
- rp: { name: "Blink", id: rpId },
1154
- user: {
1155
- id: new TextEncoder().encode(params.userId),
1156
- name: params.displayName,
1157
- displayName: params.displayName
1158
- },
1159
- pubKeyCredParams: [
1160
- { alg: -7, type: "public-key" },
1161
- { alg: -257, type: "public-key" }
1162
- ],
1163
- authenticatorSelection: {
1164
- authenticatorAttachment: "platform",
1165
- residentKey: "preferred",
1166
- userVerification: "required"
1167
- },
1168
- timeout: 6e4
1169
- };
1170
- if (isInCrossOriginIframe()) {
1171
- try {
1172
- await waitForDocumentFocus();
1173
- const credential2 = await navigator.credentials.create({
1174
- publicKey: publicKeyOptions
1175
- });
1176
- if (!credential2) {
1177
- throw new Error("Passkey creation was cancelled.");
1178
- }
1179
- return extractPasskeyResult(credential2);
1180
- } catch (err) {
1181
- if (err instanceof PasskeyIframeBlockedError) throw err;
1182
- if (err instanceof Error && err.message === "Passkey creation was cancelled.") throw err;
1183
- throw new PasskeyIframeBlockedError();
1184
- }
1185
- }
1186
- await waitForDocumentFocus();
1187
- const credential = await navigator.credentials.create({
1188
- publicKey: publicKeyOptions
1189
- });
1190
- if (!credential) {
1191
- throw new Error("Passkey creation was cancelled.");
1192
- }
1193
- return extractPasskeyResult(credential);
1194
- }
1195
- function extractPasskeyResult(credential) {
1196
- const response = credential.response;
1197
- const publicKeyBytes = response.getPublicKey?.();
1198
- return {
1199
- credentialId: toBase64(credential.rawId),
1200
- publicKey: publicKeyBytes ? toBase64(publicKeyBytes) : ""
1201
- };
1202
- }
1203
- function buildPasskeyPopupOptions(params) {
1204
- const challenge = new Uint8Array(32);
1205
- crypto.getRandomValues(challenge);
1206
- const rpId = resolvePasskeyRpId();
1207
- return {
1208
- challenge: toBase64(challenge),
1209
- rpId,
1210
- rpName: "Blink",
1211
- userId: toBase64(new TextEncoder().encode(params.userId)),
1212
- userName: params.displayName,
1213
- userDisplayName: params.displayName,
1214
- pubKeyCredParams: [
1215
- { alg: -7, type: "public-key" },
1216
- { alg: -257, type: "public-key" }
1217
- ],
1218
- authenticatorSelection: {
1219
- authenticatorAttachment: "platform",
1220
- residentKey: "preferred",
1221
- userVerification: "required"
1222
- },
1223
- timeout: 6e4,
1224
- authToken: params.authToken,
1225
- apiBaseUrl: params.apiBaseUrl
1226
- };
1227
- }
1228
- async function deviceHasPasskey(credentialId) {
1229
- const found = await findDevicePasskey([credentialId]);
1230
- return found != null;
1231
- }
1232
- async function findDevicePasskey(credentialIds) {
1233
- if (credentialIds.length === 0) return null;
1234
- try {
1235
- const challenge = new Uint8Array(32);
1236
- crypto.getRandomValues(challenge);
1237
- await waitForDocumentFocus();
1238
- const assertion = await navigator.credentials.get({
1239
- publicKey: {
1240
- challenge,
1241
- rpId: resolvePasskeyRpId(),
1242
- allowCredentials: credentialIds.map((id) => ({
1243
- type: "public-key",
1244
- id: base64ToBytes(id)
1245
- })),
1246
- userVerification: "discouraged",
1247
- timeout: 3e4
1274
+ for (let i = 0; i < WALLET_CLIENT_MAX_ATTEMPTS; i++) {
1275
+ try {
1276
+ const account = getAccount(wagmiConfig2);
1277
+ const enrichedParams = account.connector ? { ...params, connector: account.connector } : params;
1278
+ return await getWalletClient(wagmiConfig2, enrichedParams);
1279
+ } catch {
1280
+ if (i === WALLET_CLIENT_MAX_ATTEMPTS - 1) {
1281
+ throw new Error("Wallet not ready. Please try again.");
1248
1282
  }
1249
- });
1250
- if (!assertion) return null;
1251
- return toBase64(assertion.rawId);
1252
- } catch {
1253
- return null;
1283
+ await new Promise((r) => setTimeout(r, WALLET_CLIENT_POLL_MS));
1284
+ }
1254
1285
  }
1286
+ throw new Error("Wallet not ready. Please try again.");
1255
1287
  }
1256
- function useTransferPolling(intervalMs = 3e3) {
1257
- const { apiBaseUrl } = useBlinkConfig();
1258
- const { getAccessToken } = usePrivy();
1259
- const [transfer, setTransfer] = useState(null);
1260
- const [error, setError] = useState(null);
1261
- const [isPolling, setIsPolling] = useState(false);
1262
- const intervalRef = useRef(null);
1263
- const transferIdRef = useRef(null);
1264
- const stopPolling = useCallback(() => {
1265
- if (intervalRef.current) {
1266
- clearInterval(intervalRef.current);
1267
- intervalRef.current = null;
1268
- }
1269
- setIsPolling(false);
1270
- }, []);
1271
- const poll = useCallback(async () => {
1272
- if (!transferIdRef.current) return;
1273
- const result = await pollTransferTick({
1274
- apiBaseUrl,
1275
- transferId: transferIdRef.current,
1276
- getAccessToken
1277
- });
1278
- if (result.kind === "retry") {
1279
- return;
1280
- }
1281
- if (result.kind === "error") {
1282
- setError(result.message);
1283
- stopPolling();
1284
- return;
1285
- }
1286
- setError(null);
1287
- setTransfer(result.transfer);
1288
- if (result.transfer.status === "COMPLETED" || result.transfer.status === "FAILED") {
1289
- stopPolling();
1290
- }
1291
- }, [apiBaseUrl, getAccessToken, stopPolling]);
1292
- const startPolling = useCallback(
1293
- (transferId) => {
1294
- stopPolling();
1295
- transferIdRef.current = transferId;
1296
- setIsPolling(true);
1297
- setError(null);
1298
- poll();
1299
- intervalRef.current = setInterval(poll, intervalMs);
1300
- },
1301
- [poll, intervalMs, stopPolling]
1302
- );
1303
- useEffect(() => () => stopPolling(), [stopPolling]);
1304
- return { transfer, error, isPolling, startPolling, stopPolling };
1288
+ function parseSignTypedDataPayload(typedData) {
1289
+ const { domain, types, primaryType, message } = typedData;
1290
+ if (!domain || typeof domain !== "object" || Array.isArray(domain)) {
1291
+ throw new Error("SIGN_PERMIT2 typedData is missing a valid domain object.");
1292
+ }
1293
+ if (!types || typeof types !== "object" || Array.isArray(types)) {
1294
+ throw new Error("SIGN_PERMIT2 typedData is missing a valid types object.");
1295
+ }
1296
+ if (typeof primaryType !== "string") {
1297
+ throw new Error("SIGN_PERMIT2 typedData is missing primaryType.");
1298
+ }
1299
+ if (!message || typeof message !== "object" || Array.isArray(message)) {
1300
+ throw new Error("SIGN_PERMIT2 typedData is missing a valid message object.");
1301
+ }
1302
+ return {
1303
+ domain,
1304
+ types,
1305
+ primaryType,
1306
+ message
1307
+ };
1308
+ }
1309
+ function getPendingActions(session, completedIds) {
1310
+ return session.actions.filter((a) => a.status === "PENDING" && !completedIds.has(a.id)).sort((a, b) => a.orderIndex - b.orderIndex);
1305
1311
  }
1306
1312
  async function executeOpenProvider(action, wagmiConfig2, connectors, connectAsync) {
1307
1313
  try {
@@ -1699,6 +1705,47 @@ function useAuthorizationExecutor(options) {
1699
1705
  executeSessionById
1700
1706
  };
1701
1707
  }
1708
+ var TRANSFER_SIGN_MAX_POLLS = 60;
1709
+ function waitForDocumentFocus2(timeoutMs = 5e3, intervalMs = 100) {
1710
+ return new Promise((resolve, reject) => {
1711
+ if (typeof document === "undefined") {
1712
+ resolve();
1713
+ return;
1714
+ }
1715
+ if (document.hasFocus()) {
1716
+ resolve();
1717
+ return;
1718
+ }
1719
+ const deadline = Date.now() + timeoutMs;
1720
+ const timer = setInterval(() => {
1721
+ if (document.hasFocus()) {
1722
+ clearInterval(timer);
1723
+ resolve();
1724
+ } else if (Date.now() >= deadline) {
1725
+ clearInterval(timer);
1726
+ resolve();
1727
+ }
1728
+ }, intervalMs);
1729
+ });
1730
+ }
1731
+ function hexToBytes(hex) {
1732
+ const clean = hex.startsWith("0x") ? hex.slice(2) : hex;
1733
+ const bytes = clean.match(/.{1,2}/g).map((b) => parseInt(b, 16));
1734
+ return new Uint8Array(bytes);
1735
+ }
1736
+ function toBase642(buffer) {
1737
+ return btoa(String.fromCharCode(...new Uint8Array(buffer)));
1738
+ }
1739
+ function base64ToBytes2(value) {
1740
+ const normalized = value.replace(/-/g, "+").replace(/_/g, "/");
1741
+ const padded = normalized + "=".repeat((4 - normalized.length % 4) % 4);
1742
+ const raw = atob(padded);
1743
+ const bytes = new Uint8Array(raw.length);
1744
+ for (let i = 0; i < raw.length; i++) {
1745
+ bytes[i] = raw.charCodeAt(i);
1746
+ }
1747
+ return bytes;
1748
+ }
1702
1749
  function useTransferSigning(pollIntervalMs = 2e3, options) {
1703
1750
  const blinkConfig = useOptionalBlinkConfig();
1704
1751
  const apiBaseUrl = options?.apiBaseUrl ?? blinkConfig?.apiBaseUrl;
@@ -1754,9 +1801,9 @@ function useTransferSigning(pollIntervalMs = 2e3, options) {
1754
1801
  let signedUserOp;
1755
1802
  const allowCredentials = payload.passkeyCredentialId ? [{
1756
1803
  type: "public-key",
1757
- id: base64ToBytes(payload.passkeyCredentialId)
1804
+ id: base64ToBytes2(payload.passkeyCredentialId)
1758
1805
  }] : void 0;
1759
- await waitForDocumentFocus();
1806
+ await waitForDocumentFocus2();
1760
1807
  const assertion = await navigator.credentials.get({
1761
1808
  publicKey: {
1762
1809
  challenge: hashBytes,
@@ -1772,10 +1819,10 @@ function useTransferSigning(pollIntervalMs = 2e3, options) {
1772
1819
  const response = assertion.response;
1773
1820
  signedUserOp = {
1774
1821
  ...payload.userOp,
1775
- credentialId: toBase64(assertion.rawId),
1776
- signature: toBase64(response.signature),
1777
- authenticatorData: toBase64(response.authenticatorData),
1778
- clientDataJSON: toBase64(response.clientDataJSON)
1822
+ credentialId: toBase642(assertion.rawId),
1823
+ signature: toBase642(response.signature),
1824
+ authenticatorData: toBase642(response.authenticatorData),
1825
+ clientDataJSON: toBase642(response.clientDataJSON)
1779
1826
  };
1780
1827
  return await signTransfer(
1781
1828
  apiBaseUrl,
@@ -1934,6 +1981,87 @@ function buildSelectSourceChoices(options) {
1934
1981
  })).filter((chain) => chain.tokens.length > 0).sort((a, b) => b.balance - a.balance);
1935
1982
  }
1936
1983
 
1984
+ // src/walletFlow.ts
1985
+ var MOBILE_USER_AGENT_PATTERN = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i;
1986
+ function isMobileUserAgent(userAgent) {
1987
+ if (!userAgent) {
1988
+ return false;
1989
+ }
1990
+ return MOBILE_USER_AGENT_PATTERN.test(userAgent);
1991
+ }
1992
+ function shouldUseWalletConnector(options) {
1993
+ return options.useWalletConnector ?? !isMobileUserAgent(options.userAgent);
1994
+ }
1995
+
1996
+ // src/paymentResolvePhase.ts
1997
+ function hasActiveWallet(accounts) {
1998
+ return accounts.some((a) => a.wallets.some((w) => w.status === "ACTIVE"));
1999
+ }
2000
+ function isTransferInFlight(transfer) {
2001
+ if (!transfer) return false;
2002
+ return ["CREATED", "SENDING", "SENT"].includes(transfer.status);
2003
+ }
2004
+ function resolvePhase(state) {
2005
+ const p = state.phase;
2006
+ if (p.step === "select-source" && state.transfer?.status === "COMPLETED" && state.guestPreauthorizing) {
2007
+ return p;
2008
+ }
2009
+ if (state.transfer?.status === "COMPLETED" && state.guestPreauthorizing) {
2010
+ return { step: "processing", transfer: state.transfer };
2011
+ }
2012
+ if (state.transfer?.status === "COMPLETED") {
2013
+ return { step: "completed", transfer: state.transfer };
2014
+ }
2015
+ if (state.transfer?.status === "FAILED") {
2016
+ return { step: "failed", transfer: state.transfer, error: state.error ?? "Transfer failed." };
2017
+ }
2018
+ if (state.creatingTransfer || isTransferInFlight(state.transfer)) {
2019
+ return { step: "processing", transfer: state.transfer };
2020
+ }
2021
+ if (p.step === "token-picker" || p.step === "one-tap-setup" || p.step === "select-source" || p.step === "confirm-sign" || p.step === "guest-token-picker") {
2022
+ return p;
2023
+ }
2024
+ if (p.step === "wallet-setup") return p;
2025
+ if (state.mobileFlow && state.deeplinkUri) {
2026
+ return {
2027
+ step: "wallet-setup",
2028
+ mobile: { deeplinkUri: state.deeplinkUri, providerId: state.selectedProviderId },
2029
+ accountId: null
2030
+ };
2031
+ }
2032
+ if (!state.activeCredentialId && !state.passkeyConfigLoaded) {
2033
+ return { step: "initializing" };
2034
+ }
2035
+ if (state.verificationTarget) {
2036
+ return { step: "otp-verify", target: state.verificationTarget };
2037
+ }
2038
+ if (state.loginRequested) {
2039
+ return { step: "login" };
2040
+ }
2041
+ if (state.passkeyConfigLoaded && !state.activeCredentialId) {
2042
+ if (state.knownCredentialIds.length > 0 && state.passkeyPopupNeeded) {
2043
+ return { step: "passkey-verify" };
2044
+ }
2045
+ return { step: "passkey-create", popupFallback: state.passkeyPopupNeeded };
2046
+ }
2047
+ if (state.loadingData && state.activeCredentialId && hasActiveWallet(state.accounts)) {
2048
+ return { step: "data-loading" };
2049
+ }
2050
+ if (state.isGuestFlow && state.selectedProviderId != null && !state.transfer) {
2051
+ return { step: "guest-token-picker" };
2052
+ }
2053
+ if (state.activeCredentialId && !hasActiveWallet(state.accounts) && !state.mobileFlow) {
2054
+ return { step: "wallet-picker", reason: "link" };
2055
+ }
2056
+ if (state.activeCredentialId && hasActiveWallet(state.accounts) && !state.loadingData) {
2057
+ return { step: "deposit" };
2058
+ }
2059
+ if (state.isGuestFlow) {
2060
+ return { step: "wallet-picker", reason: "guest-entry" };
2061
+ }
2062
+ return { step: "wallet-picker", reason: "entry" };
2063
+ }
2064
+
1937
2065
  // src/paymentReducer.ts
1938
2066
  function deriveSourceTypeAndId(state) {
1939
2067
  if (state.selectedWalletId) {
@@ -1946,6 +2074,7 @@ function deriveSourceTypeAndId(state) {
1946
2074
  }
1947
2075
  function createInitialState(config) {
1948
2076
  return {
2077
+ phase: { step: "initializing" },
1949
2078
  error: null,
1950
2079
  providers: [],
1951
2080
  accounts: [],
@@ -1966,6 +2095,7 @@ function createInitialState(config) {
1966
2095
  knownCredentialIds: [],
1967
2096
  verificationTarget: null,
1968
2097
  oneTapLimit: 100,
2098
+ oneTapLimitSavedDuringSetup: false,
1969
2099
  mobileFlow: false,
1970
2100
  deeplinkUri: null,
1971
2101
  increasingLimit: false,
@@ -1973,12 +2103,17 @@ function createInitialState(config) {
1973
2103
  guestTransferId: null,
1974
2104
  guestSessionToken: null,
1975
2105
  guestPreauthAccountId: null,
2106
+ guestPreauthSessionId: null,
1976
2107
  activePublicKey: null,
1977
- userIntent: null,
1978
- loginRequested: false
2108
+ loginRequested: false,
2109
+ guestPreauthorizing: false
1979
2110
  };
1980
2111
  }
1981
2112
  function paymentReducer(state, action) {
2113
+ const next = applyAction(state, action);
2114
+ return { ...next, phase: resolvePhase(next) };
2115
+ }
2116
+ function applyAction(state, action) {
1982
2117
  switch (action.type) {
1983
2118
  // ── Auth ──────────────────────────────────────────────────────
1984
2119
  case "CODE_SENT":
@@ -2056,23 +2191,20 @@ function paymentReducer(state, action) {
2056
2191
  selectedProviderId: action.providerId,
2057
2192
  selectedAccountId: null,
2058
2193
  selectedWalletId: null,
2059
- selectedTokenSymbol: null,
2060
- userIntent: null
2194
+ selectedTokenSymbol: null
2061
2195
  };
2062
2196
  case "SELECT_ACCOUNT":
2063
2197
  return {
2064
2198
  ...state,
2065
2199
  selectedAccountId: action.accountId,
2066
2200
  selectedWalletId: action.walletId,
2067
- selectedTokenSymbol: null,
2068
- userIntent: null
2201
+ selectedTokenSymbol: null
2069
2202
  };
2070
2203
  case "SELECT_TOKEN":
2071
2204
  return {
2072
2205
  ...state,
2073
2206
  selectedWalletId: action.walletId,
2074
- selectedTokenSymbol: action.tokenSymbol,
2075
- userIntent: null
2207
+ selectedTokenSymbol: action.tokenSymbol
2076
2208
  };
2077
2209
  // ── Transfer lifecycle ───────────────────────────────────────
2078
2210
  case "PAY_STARTED":
@@ -2081,8 +2213,7 @@ function paymentReducer(state, action) {
2081
2213
  error: null,
2082
2214
  creatingTransfer: true,
2083
2215
  deeplinkUri: null,
2084
- mobileFlow: false,
2085
- userIntent: null
2216
+ mobileFlow: false
2086
2217
  };
2087
2218
  case "PAY_ENDED":
2088
2219
  return { ...state, creatingTransfer: false };
@@ -2146,7 +2277,8 @@ function paymentReducer(state, action) {
2146
2277
  transfer: action.transfer,
2147
2278
  error: null,
2148
2279
  mobileFlow: false,
2149
- deeplinkUri: null
2280
+ deeplinkUri: null,
2281
+ phase: { step: "confirm-sign", transfer: action.transfer }
2150
2282
  };
2151
2283
  case "CLEAR_MOBILE_STATE":
2152
2284
  return { ...state, mobileFlow: false, deeplinkUri: null };
@@ -2216,29 +2348,37 @@ function paymentReducer(state, action) {
2216
2348
  case "GUEST_PREAUTH_DETECTED":
2217
2349
  return {
2218
2350
  ...state,
2219
- guestPreauthAccountId: action.accountId
2351
+ guestPreauthAccountId: action.accountId,
2352
+ guestPreauthSessionId: action.sessionId ?? state.guestPreauthSessionId
2220
2353
  };
2354
+ case "GUEST_PREAUTH_BEGIN":
2355
+ return { ...state, guestPreauthorizing: true, error: null };
2356
+ case "GUEST_PREAUTH_END":
2357
+ return { ...state, guestPreauthorizing: false };
2221
2358
  case "ACCOUNT_OWNER_SET":
2222
2359
  return {
2223
2360
  ...state,
2224
2361
  guestPreauthAccountId: null,
2362
+ guestPreauthSessionId: null,
2225
2363
  activePublicKey: null,
2226
2364
  error: null,
2227
- userIntent: "configure-one-tap"
2365
+ guestPreauthorizing: false,
2366
+ phase: { step: "one-tap-setup", action: null }
2228
2367
  };
2229
2368
  // ── User intent & error ──────────────────────────────────────
2230
2369
  case "SET_USER_INTENT":
2231
- return { ...state, userIntent: action.intent };
2370
+ return { ...state, phase: action.intent };
2232
2371
  case "REQUEST_LOGIN":
2233
2372
  return {
2234
2373
  ...state,
2235
2374
  loginRequested: true,
2236
2375
  transfer: null,
2237
- isGuestFlow: false,
2238
2376
  creatingTransfer: false
2239
2377
  };
2240
2378
  case "SET_ERROR":
2241
2379
  return { ...state, error: action.error };
2380
+ case "SET_ONE_TAP_LIMIT_SAVED_DURING_SETUP":
2381
+ return { ...state, oneTapLimitSavedDuringSetup: action.saved };
2242
2382
  // ── Lifecycle ────────────────────────────────────────────────
2243
2383
  case "NEW_PAYMENT":
2244
2384
  return {
@@ -2255,9 +2395,11 @@ function paymentReducer(state, action) {
2255
2395
  guestTransferId: null,
2256
2396
  guestSessionToken: null,
2257
2397
  guestPreauthAccountId: null,
2398
+ guestPreauthSessionId: null,
2258
2399
  activePublicKey: null,
2259
- userIntent: null,
2260
- loginRequested: false
2400
+ loginRequested: false,
2401
+ oneTapLimitSavedDuringSetup: false,
2402
+ guestPreauthorizing: false
2261
2403
  };
2262
2404
  case "LOGOUT":
2263
2405
  return {
@@ -2272,139 +2414,85 @@ function paymentReducer(state, action) {
2272
2414
  default:
2273
2415
  return state;
2274
2416
  }
2275
- }
2276
-
2277
- // src/auth.ts
2278
- var EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
2279
- var PHONE_DIGIT_PATTERN = /^\d{7,15}$/;
2280
- function normalizePhoneNumber(rawValue) {
2281
- const trimmed = rawValue.trim();
2282
- if (!trimmed) return null;
2283
- const hasExplicitCountryCode = trimmed.startsWith("+");
2284
- const digits = trimmed.replace(/\D/g, "");
2285
- if (!PHONE_DIGIT_PATTERN.test(digits)) return null;
2286
- return hasExplicitCountryCode ? `+${digits}` : digits;
2287
- }
2288
- function normalizeAuthIdentifier(rawValue) {
2289
- const trimmed = rawValue.trim();
2290
- if (!trimmed) return null;
2291
- if (EMAIL_PATTERN.test(trimmed)) {
2292
- return {
2293
- kind: "email",
2294
- value: trimmed.toLowerCase()
2295
- };
2296
- }
2297
- const normalizedPhoneNumber = normalizePhoneNumber(trimmed);
2298
- if (normalizedPhoneNumber) {
2299
- return {
2300
- kind: "phone",
2301
- value: normalizedPhoneNumber
2302
- };
2303
- }
2304
- return null;
2305
- }
2306
- function maskAuthIdentifier(identifier) {
2307
- if (identifier.kind === "email") {
2308
- const [localPart, domain = ""] = identifier.value.split("@");
2309
- const localPrefix = localPart.slice(0, 2);
2310
- return `${localPrefix}${"*".repeat(Math.max(localPart.length - 2, 0))}@${domain}`;
2311
- }
2312
- const digits = identifier.value.replace(/\D/g, "");
2313
- const visibleSuffix = digits.slice(-4);
2314
- return `***-***-${visibleSuffix}`;
2315
- }
2316
-
2317
- // src/walletFlow.ts
2318
- var MOBILE_USER_AGENT_PATTERN = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i;
2319
- function isMobileUserAgent(userAgent) {
2320
- if (!userAgent) {
2321
- return false;
2322
- }
2323
- return MOBILE_USER_AGENT_PATTERN.test(userAgent);
2324
- }
2325
- function shouldUseWalletConnector(options) {
2326
- return options.useWalletConnector ?? !isMobileUserAgent(options.userAgent);
2327
- }
2328
-
2329
- // src/resolveScreen.ts
2330
- function hasActiveWallet(accounts) {
2331
- return accounts.some((a) => a.wallets.some((w) => w.status === "ACTIVE"));
2332
- }
2333
- function isTransferTerminal(transfer) {
2334
- return transfer?.status === "COMPLETED" || transfer?.status === "FAILED";
2335
- }
2336
- function isTransferInFlight(transfer) {
2337
- if (!transfer) return false;
2338
- return ["CREATED", "SENDING", "SENT"].includes(transfer.status);
2339
- }
2340
- function isSetupTransfer(transfer) {
2341
- if (!transfer) return false;
2342
- return transfer.sources?.some(
2343
- (s) => s.wallets && Array.isArray(s.wallets) && s.wallets.length === 0
2344
- ) ?? false;
2345
- }
2346
- function resolveScreen(state) {
2347
- if (!state.privyReady) {
2348
- return "loading";
2349
- }
2350
- if (state.authenticated && !state.activeCredentialId && !state.passkeyConfigLoaded) {
2351
- return "loading";
2352
- }
2353
- if (!state.authenticated && !state.verificationTarget && !state.isGuestFlow && (state.isReturningUser || state.guestPreauthRedirect || state.loginRequested)) {
2354
- return "login";
2355
- }
2356
- if (!state.authenticated && state.verificationTarget != null) {
2357
- return "otp-verify";
2358
- }
2359
- if (state.authenticated && !state.activeCredentialId && state.passkeyConfigLoaded && (state.knownCredentialIds.length === 0 || !state.passkeyPopupNeeded)) {
2360
- return "create-passkey";
2361
- }
2362
- if (state.authenticated && !state.activeCredentialId && state.passkeyConfigLoaded && state.knownCredentialIds.length > 0 && state.passkeyPopupNeeded) {
2363
- return "verify-passkey";
2364
- }
2365
- if (isTransferTerminal(state.transfer)) {
2366
- return "success";
2367
- }
2368
- if (state.creatingTransfer || state.transfer != null && isTransferInFlight(state.transfer)) {
2369
- return "processing";
2370
- }
2371
- if (state.transfer?.status === "AUTHORIZED" && !state.isDesktop && !isSetupTransfer(state.transfer)) {
2372
- return "confirm-sign";
2373
- }
2374
- if (state.pendingSelectSource != null) {
2375
- return state.isDesktop ? "setup" : "select-source";
2376
- }
2377
- if (state.pendingOneTapSetup != null && !state.oneTapLimitAlreadySaved) {
2378
- return "setup";
2379
- }
2380
- if (state.mobileFlow || state.inlineAuthorizationExecuting) {
2381
- return state.isDesktop ? "setup-status" : "open-wallet";
2382
- }
2383
- if (state.isGuestFlow && state.selectedProviderId != null && !state.transfer && !state.guestSettingSender) {
2384
- return "guest-token-picker";
2385
- }
2386
- if (state.activeCredentialId && !hasActiveWallet(state.accounts) && !state.mobileFlow || !state.authenticated && !state.isReturningUser && !state.isGuestFlow) {
2387
- return "wallet-picker";
2388
- }
2389
- if (state.loadingData && state.activeCredentialId != null && hasActiveWallet(state.accounts)) {
2390
- return "loading";
2391
- }
2392
- if (state.userIntent === "pick-token" && state.selectedAccount != null) {
2393
- return "token-picker";
2394
- }
2395
- if (state.userIntent === "configure-one-tap") {
2396
- return "setup";
2417
+ }
2418
+
2419
+ // src/auth.ts
2420
+ var EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
2421
+ var PHONE_DIGIT_PATTERN = /^\d{7,15}$/;
2422
+ function normalizePhoneNumber(rawValue) {
2423
+ const trimmed = rawValue.trim();
2424
+ if (!trimmed) return null;
2425
+ const hasExplicitCountryCode = trimmed.startsWith("+");
2426
+ const digits = trimmed.replace(/\D/g, "");
2427
+ if (!PHONE_DIGIT_PATTERN.test(digits)) return null;
2428
+ return hasExplicitCountryCode ? `+${digits}` : digits;
2429
+ }
2430
+ function normalizeAuthIdentifier(rawValue) {
2431
+ const trimmed = rawValue.trim();
2432
+ if (!trimmed) return null;
2433
+ if (EMAIL_PATTERN.test(trimmed)) {
2434
+ return {
2435
+ kind: "email",
2436
+ value: trimmed.toLowerCase()
2437
+ };
2397
2438
  }
2398
- if (state.userIntent === "switch-wallet") {
2399
- return "wallet-picker";
2439
+ const normalizedPhoneNumber = normalizePhoneNumber(trimmed);
2440
+ if (normalizedPhoneNumber) {
2441
+ return {
2442
+ kind: "phone",
2443
+ value: normalizedPhoneNumber
2444
+ };
2400
2445
  }
2401
- if (state.activeCredentialId != null && hasActiveWallet(state.accounts) && !state.loadingData) {
2402
- return "deposit";
2446
+ return null;
2447
+ }
2448
+ function maskAuthIdentifier(identifier) {
2449
+ if (identifier.kind === "email") {
2450
+ const [localPart, domain = ""] = identifier.value.split("@");
2451
+ const localPrefix = localPart.slice(0, 2);
2452
+ return `${localPrefix}${"*".repeat(Math.max(localPart.length - 2, 0))}@${domain}`;
2403
2453
  }
2404
- if (state.isGuestFlow) {
2405
- return "wallet-picker";
2454
+ const digits = identifier.value.replace(/\D/g, "");
2455
+ const visibleSuffix = digits.slice(-4);
2456
+ return `***-***-${visibleSuffix}`;
2457
+ }
2458
+
2459
+ // src/resolveScreen.ts
2460
+ function screenForPhase(phase) {
2461
+ switch (phase.step) {
2462
+ case "initializing":
2463
+ case "data-loading":
2464
+ return "loading";
2465
+ case "login":
2466
+ return "login";
2467
+ case "otp-verify":
2468
+ return "otp-verify";
2469
+ case "passkey-create":
2470
+ return "create-passkey";
2471
+ case "passkey-verify":
2472
+ return "verify-passkey";
2473
+ case "wallet-picker":
2474
+ return "wallet-picker";
2475
+ case "wallet-setup":
2476
+ return phase.mobile ? "open-wallet" : "setup-status";
2477
+ case "select-source":
2478
+ if (phase.skipOneTapLimit) return "select-source";
2479
+ return phase.isDesktop ? "setup" : "select-source";
2480
+ case "one-tap-setup":
2481
+ return "setup";
2482
+ case "guest-token-picker":
2483
+ return "guest-token-picker";
2484
+ case "token-picker":
2485
+ return "token-picker";
2486
+ case "deposit":
2487
+ return "deposit";
2488
+ case "processing":
2489
+ return "processing";
2490
+ case "confirm-sign":
2491
+ return "confirm-sign";
2492
+ case "completed":
2493
+ case "failed":
2494
+ return "success";
2406
2495
  }
2407
- return "wallet-picker";
2408
2496
  }
2409
2497
  var MUTED = "#7fa4b0";
2410
2498
  var LOGO_SIZE = 48;
@@ -5887,85 +5975,66 @@ var DEPOSIT_SCREENS = /* @__PURE__ */ new Set([
5887
5975
  "processing",
5888
5976
  "success"
5889
5977
  ]);
5890
- function getFlowPhase(screen, userIntent) {
5978
+ function getFlowPhase(screen, phase) {
5891
5979
  if (LINK_SCREENS.has(screen)) return "link";
5892
5980
  if (DEPOSIT_SCREENS.has(screen)) return "deposit";
5893
5981
  if (screen === "token-picker" || screen === "select-source" || screen === "guest-token-picker") {
5894
- return userIntent === "configure-one-tap" ? "link" : "deposit";
5982
+ return phase.step === "one-tap-setup" ? "link" : "deposit";
5895
5983
  }
5896
5984
  return null;
5897
5985
  }
5898
5986
  function StepRenderer(props) {
5899
- const isDesktop = shouldUseWalletConnector({
5900
- userAgent: typeof navigator === "undefined" ? void 0 : navigator.userAgent
5901
- });
5902
- const isReturningUser = props.state.activeCredentialId != null || typeof window !== "undefined" && window.localStorage.getItem("blink_active_credential") != null;
5903
- const screenState = {
5904
- privyReady: props.ready,
5905
- authenticated: props.authenticated,
5906
- verificationTarget: props.state.verificationTarget,
5907
- activeCredentialId: props.state.activeCredentialId,
5908
- knownCredentialIds: props.state.knownCredentialIds,
5909
- passkeyConfigLoaded: props.state.passkeyConfigLoaded,
5910
- passkeyPopupNeeded: props.state.passkeyPopupNeeded,
5911
- accounts: props.state.accounts,
5912
- isGuestFlow: props.state.isGuestFlow,
5913
- selectedProviderId: props.state.selectedProviderId,
5914
- mobileFlow: props.state.mobileFlow,
5915
- inlineAuthorizationExecuting: props.inlineAuthorizationExecuting,
5916
- creatingTransfer: props.state.creatingTransfer,
5917
- transfer: props.state.transfer,
5918
- pendingSelectSource: props.pendingSelectSource,
5919
- pendingOneTapSetup: props.pendingOneTapSetup,
5920
- oneTapLimitAlreadySaved: props.oneTapLimitAlreadySaved,
5921
- loadingData: props.state.loadingData,
5922
- isDesktop,
5923
- isReturningUser,
5924
- guestPreauthRedirect: props.state.guestPreauthAccountId != null,
5925
- loginRequested: props.state.loginRequested,
5926
- userIntent: props.state.userIntent,
5927
- selectedAccount: props.selectedAccount,
5928
- guestSettingSender: props.guestSettingSender
5929
- };
5930
- const screen = resolveScreen(screenState);
5931
- const phase = getFlowPhase(screen, props.state.userIntent);
5932
- return /* @__PURE__ */ jsx(FlowPhaseProvider, { phase, children: /* @__PURE__ */ jsx(StepRendererContent, { ...props, screen, isDesktop }) });
5987
+ const screen = screenForPhase(props.flow.state.phase);
5988
+ const flowPhase = getFlowPhase(screen, props.flow.state.phase);
5989
+ return /* @__PURE__ */ jsx(FlowPhaseProvider, { phase: flowPhase, children: /* @__PURE__ */ jsx(StepRendererContent, { ...props, screen }) });
5933
5990
  }
5934
5991
  function StepRendererContent({
5935
- state,
5936
- authenticated,
5937
- activeOtpStatus,
5938
- pollingTransfer,
5939
- pollingError,
5940
- authExecutorError,
5941
- transferSigningSigning,
5942
- transferSigningError,
5943
- pendingConnections,
5944
- depositEligibleAccounts,
5945
- sourceName,
5946
- maxSourceBalance,
5947
- tokenCount,
5948
- selectedAccount,
5949
- selectedSource,
5950
- selectSourceChoices,
5951
- selectSourceRecommended,
5952
- selectSourceAvailableBalance,
5953
- guestTokenEntries,
5954
- guestLoadingBalances,
5955
- guestSettingSender,
5956
- authInput,
5957
- otpCode,
5958
- selectSourceChainName,
5959
- selectSourceTokenSymbol,
5960
- savingOneTapLimit,
5961
- merchantName,
5962
- onBack,
5963
- onDismiss,
5964
- depositAmount,
5992
+ flow,
5993
+ remote,
5994
+ derived,
5995
+ forms,
5965
5996
  handlers,
5966
- screen,
5967
- isDesktop
5997
+ screen
5968
5998
  }) {
5999
+ const {
6000
+ state,
6001
+ authenticated,
6002
+ activeOtpStatus,
6003
+ isDesktop,
6004
+ merchantName,
6005
+ onBack,
6006
+ onDismiss,
6007
+ depositAmount
6008
+ } = flow;
6009
+ const {
6010
+ pollingTransfer,
6011
+ pollingError,
6012
+ authExecutorError,
6013
+ transferSigningSigning,
6014
+ transferSigningError
6015
+ } = remote;
6016
+ const {
6017
+ pendingConnections,
6018
+ depositEligibleAccounts,
6019
+ sourceName,
6020
+ maxSourceBalance,
6021
+ tokenCount,
6022
+ selectedAccount,
6023
+ selectedSource,
6024
+ selectSourceChoices,
6025
+ selectSourceRecommended,
6026
+ selectSourceAvailableBalance
6027
+ } = derived;
6028
+ const {
6029
+ guestTokenEntries,
6030
+ guestLoadingBalances,
6031
+ guestSettingSender,
6032
+ authInput,
6033
+ otpCode,
6034
+ selectSourceChainName,
6035
+ selectSourceTokenSymbol,
6036
+ savingOneTapLimit
6037
+ } = forms;
5969
6038
  const selectedWallet = selectedAccount?.wallets.find((w) => w.id === state.selectedWalletId);
5970
6039
  const selectedSourceLabel = selectedSource && selectedWallet ? `${selectedSource.token.symbol} on ${selectedWallet.chain.name}` : void 0;
5971
6040
  switch (screen) {
@@ -6038,7 +6107,7 @@ function StepRendererContent({
6038
6107
  onPrepareProvider: handlers.onPrepareProvider,
6039
6108
  onSelectProvider: handlers.onSelectProvider,
6040
6109
  onContinueConnection: handlers.onContinueConnection,
6041
- onBack: isEntryPoint ? onBack : () => handlers.onSetUserIntent(null),
6110
+ onBack: isEntryPoint ? onBack : () => handlers.onSetPhase({ step: "deposit" }),
6042
6111
  onLogout: authenticated ? handlers.onLogout : void 0,
6043
6112
  onLogin: handlers.onLogin,
6044
6113
  showLoginOption: isEntryPoint
@@ -6069,7 +6138,7 @@ function StepRendererContent({
6069
6138
  limit: state.oneTapLimit,
6070
6139
  tokensApproved: 0,
6071
6140
  merchantName,
6072
- onContinue: () => handlers.onSetUserIntent("configure-one-tap"),
6141
+ onContinue: () => handlers.onSetPhase({ step: "one-tap-setup", action: null }),
6073
6142
  onLogout: handlers.onLogout,
6074
6143
  error: state.error || authExecutorError
6075
6144
  }
@@ -6088,7 +6157,7 @@ function StepRendererContent({
6088
6157
  tokenCount: effectiveTokenCount,
6089
6158
  sourceName,
6090
6159
  onSetupOneTap: handlers.onSetupOneTap,
6091
- onBack: () => handlers.onSetUserIntent(null),
6160
+ onBack: () => handlers.onSetPhase({ step: "deposit" }),
6092
6161
  onLogout: handlers.onLogout,
6093
6162
  onAdvanced: handlers.onSelectToken,
6094
6163
  selectedSourceLabel: effectiveSourceLabel,
@@ -6124,7 +6193,7 @@ function StepRendererContent({
6124
6193
  processing: state.creatingTransfer,
6125
6194
  error: state.error,
6126
6195
  onDeposit: handlers.onPay,
6127
- onSwitchWallet: () => handlers.onSetUserIntent("switch-wallet"),
6196
+ onSwitchWallet: () => handlers.onSetPhase({ step: "wallet-picker", reason: "switch" }),
6128
6197
  onBack: onBack ?? (() => handlers.onLogout()),
6129
6198
  onLogout: handlers.onLogout,
6130
6199
  onIncreaseLimit: handlers.onIncreaseLimit,
@@ -6133,7 +6202,7 @@ function StepRendererContent({
6133
6202
  selectedAccountId: state.selectedAccountId,
6134
6203
  onSelectAccount: handlers.onSelectAccount,
6135
6204
  onAuthorizeAccount: handlers.onContinueConnection,
6136
- onAddProvider: () => handlers.onSetUserIntent("switch-wallet"),
6205
+ onAddProvider: () => handlers.onSetPhase({ step: "wallet-picker", reason: "switch" }),
6137
6206
  onSelectToken: handlers.onSelectToken,
6138
6207
  selectedSourceLabel,
6139
6208
  selectedTokenSymbol: selectedSource?.token.symbol
@@ -6151,7 +6220,7 @@ function StepRendererContent({
6151
6220
  chains: state.chains,
6152
6221
  onSelectAuthorized: handlers.onSelectAuthorizedToken,
6153
6222
  onAuthorizeToken: handlers.onAuthorizeToken,
6154
- onBack: () => handlers.onSetUserIntent(null),
6223
+ onBack: () => handlers.onSetPhase({ step: "deposit" }),
6155
6224
  onLogout: handlers.onLogout,
6156
6225
  depositAmount: depositAmount ?? void 0,
6157
6226
  selectedTokenSymbol: selectedSource?.token.symbol,
@@ -6169,7 +6238,7 @@ function StepRendererContent({
6169
6238
  depositAmount: depositAmount ?? void 0,
6170
6239
  error: state.error,
6171
6240
  onSelect: handlers.onSelectGuestToken,
6172
- onBack: () => handlers.onSetUserIntent(null)
6241
+ onBack: () => handlers.onSetPhase({ step: "wallet-picker", reason: "guest-entry" })
6173
6242
  }
6174
6243
  );
6175
6244
  case "processing": {
@@ -6308,56 +6377,41 @@ var buttonStyle3 = {
6308
6377
  fontFamily: "inherit",
6309
6378
  cursor: "pointer"
6310
6379
  };
6311
- function useDerivedState(state) {
6380
+ function selectedSourceForWallet(selectedWallet, selectedTokenSymbol) {
6381
+ if (!selectedWallet) return null;
6382
+ if (selectedTokenSymbol) {
6383
+ return selectedWallet.sources.find((s) => s.token.symbol === selectedTokenSymbol) ?? null;
6384
+ }
6385
+ return selectedWallet.sources.find((s) => s.token.status === "AUTHORIZED") ?? selectedWallet.sources[0] ?? null;
6386
+ }
6387
+ function computeDerivedState(state) {
6312
6388
  const { sourceType, sourceId } = deriveSourceTypeAndId(state);
6313
6389
  const selectedAccount = state.accounts.find((a) => a.id === state.selectedAccountId);
6314
6390
  const selectedWallet = selectedAccount?.wallets.find(
6315
6391
  (w) => w.id === state.selectedWalletId
6316
6392
  );
6317
- const selectedSource = useMemo(() => {
6318
- if (!selectedWallet) return null;
6319
- if (state.selectedTokenSymbol) {
6320
- return selectedWallet.sources.find(
6321
- (s) => s.token.symbol === state.selectedTokenSymbol
6322
- ) ?? null;
6323
- }
6324
- return selectedWallet.sources.find((s) => s.token.status === "AUTHORIZED") ?? selectedWallet.sources[0] ?? null;
6325
- }, [selectedWallet, state.selectedTokenSymbol]);
6393
+ const selectedSource = selectedSourceForWallet(selectedWallet, state.selectedTokenSymbol);
6326
6394
  const sourceName = selectedAccount?.name ?? selectedWallet?.chain.name ?? "Wallet";
6327
- const pendingConnections = useMemo(
6328
- () => state.accounts.filter(
6329
- (a) => a.wallets.length > 0 && !a.wallets.some((w) => w.status === "ACTIVE")
6330
- ),
6331
- [state.accounts]
6332
- );
6333
- const depositEligibleAccounts = useMemo(
6334
- () => getDepositEligibleAccounts(state.accounts),
6335
- [state.accounts]
6395
+ const pendingConnections = state.accounts.filter(
6396
+ (a) => a.wallets.length > 0 && !a.wallets.some((w) => w.status === "ACTIVE")
6336
6397
  );
6337
- const maxSourceBalance = useMemo(() => {
6338
- let max = 0;
6339
- for (const acct of state.accounts) {
6340
- for (const wallet of acct.wallets) {
6341
- for (const source of wallet.sources) {
6342
- if (source.balance.available.amount > max) {
6343
- max = source.balance.available.amount;
6344
- }
6398
+ const depositEligibleAccounts = getDepositEligibleAccounts(state.accounts);
6399
+ let maxSourceBalance = 0;
6400
+ for (const acct of state.accounts) {
6401
+ for (const wallet of acct.wallets) {
6402
+ for (const source of wallet.sources) {
6403
+ if (source.balance.available.amount > maxSourceBalance) {
6404
+ maxSourceBalance = source.balance.available.amount;
6345
6405
  }
6346
6406
  }
6347
6407
  }
6348
- return max;
6349
- }, [state.accounts]);
6350
- const tokenCount = useMemo(() => {
6351
- let count = 0;
6352
- for (const acct of state.accounts) {
6353
- for (const wallet of acct.wallets) {
6354
- count += wallet.sources.filter(
6355
- (s) => s.balance.available.amount > 0
6356
- ).length;
6357
- }
6408
+ }
6409
+ let tokenCount = 0;
6410
+ for (const acct of state.accounts) {
6411
+ for (const wallet of acct.wallets) {
6412
+ tokenCount += wallet.sources.filter((s) => s.balance.available.amount > 0).length;
6358
6413
  }
6359
- return count;
6360
- }, [state.accounts]);
6414
+ }
6361
6415
  return {
6362
6416
  sourceType,
6363
6417
  sourceId,
@@ -6371,6 +6425,9 @@ function useDerivedState(state) {
6371
6425
  tokenCount
6372
6426
  };
6373
6427
  }
6428
+ function useDerivedState(state) {
6429
+ return useMemo(() => computeDerivedState(state), [state]);
6430
+ }
6374
6431
  function useAuthHandlers(dispatch, verificationTarget) {
6375
6432
  const {
6376
6433
  sendCode: sendEmailCode,
@@ -6936,7 +6993,9 @@ function useProviderHandlers(deps) {
6936
6993
  reauthTokenRef,
6937
6994
  authenticated,
6938
6995
  merchantAuthorization,
6939
- destination
6996
+ destination,
6997
+ guestSessionToken,
6998
+ selectedProviderId
6940
6999
  } = deps;
6941
7000
  const wagmiConfig2 = useConfig();
6942
7001
  const { connectAsync, connectors } = useConnect();
@@ -7249,7 +7308,7 @@ function useProviderHandlers(deps) {
7249
7308
  reauthTokenRef
7250
7309
  ]);
7251
7310
  const handleNavigateToTokenPicker = useCallback(() => {
7252
- dispatch({ type: "SET_USER_INTENT", intent: "pick-token" });
7311
+ dispatch({ type: "SET_USER_INTENT", intent: { step: "token-picker" } });
7253
7312
  }, [dispatch]);
7254
7313
  const handleSelectAuthorizedToken = useCallback((walletId, tokenSymbol) => {
7255
7314
  dispatch({ type: "SELECT_TOKEN", walletId, tokenSymbol });
@@ -7332,6 +7391,76 @@ function useProviderHandlers(deps) {
7332
7391
  reauthSessionIdRef,
7333
7392
  reauthTokenRef
7334
7393
  ]);
7394
+ const handlePreauthorize = useCallback(async () => {
7395
+ if (!guestSessionToken || !selectedProviderId) {
7396
+ dispatch({
7397
+ type: "SET_ERROR",
7398
+ error: "Missing guest session or wallet provider. Try again from the payment screen."
7399
+ });
7400
+ return;
7401
+ }
7402
+ const isMobile = !shouldUseWalletConnector({
7403
+ useWalletConnector: useWalletConnectorProp,
7404
+ userAgent: typeof navigator === "undefined" ? void 0 : navigator.userAgent
7405
+ });
7406
+ const providerName = providers.find((p) => p.id === selectedProviderId)?.name ?? "Wallet";
7407
+ if (!isMobile) {
7408
+ dispatch({ type: "GUEST_PREAUTH_BEGIN" });
7409
+ }
7410
+ try {
7411
+ const created = await createGuestAccount(
7412
+ apiBaseUrl,
7413
+ guestSessionToken,
7414
+ selectedProviderId,
7415
+ providerName
7416
+ );
7417
+ const session = await fetchAuthorizationSessionByToken(
7418
+ apiBaseUrl,
7419
+ created.sessionToken
7420
+ );
7421
+ if (isMobile) {
7422
+ handlingMobileReturnRef.current = false;
7423
+ mobileSetupFlowRef.current = true;
7424
+ setupAccountIdRef.current = created.accountId;
7425
+ persistMobileFlowState({
7426
+ accountId: created.accountId,
7427
+ sessionId: session.id,
7428
+ deeplinkUri: created.sessionUri,
7429
+ providerId: selectedProviderId,
7430
+ isSetup: true,
7431
+ guestSessionToken
7432
+ });
7433
+ triggerDeeplink(created.sessionUri);
7434
+ dispatch({ type: "MOBILE_DEEPLINK_READY", deeplinkUri: created.sessionUri });
7435
+ }
7436
+ dispatch({
7437
+ type: "GUEST_PREAUTH_DETECTED",
7438
+ accountId: created.accountId,
7439
+ sessionId: session.id
7440
+ });
7441
+ } catch (err) {
7442
+ captureException(err);
7443
+ if (!isMobile) {
7444
+ dispatch({ type: "GUEST_PREAUTH_END" });
7445
+ }
7446
+ dispatch({
7447
+ type: "SET_ERROR",
7448
+ error: err instanceof Error ? err.message : "Failed to start preauthorization"
7449
+ });
7450
+ onError?.(err instanceof Error ? err.message : "Failed to start preauthorization");
7451
+ }
7452
+ }, [
7453
+ guestSessionToken,
7454
+ selectedProviderId,
7455
+ providers,
7456
+ apiBaseUrl,
7457
+ dispatch,
7458
+ onError,
7459
+ useWalletConnectorProp,
7460
+ mobileSetupFlowRef,
7461
+ handlingMobileReturnRef,
7462
+ setupAccountIdRef
7463
+ ]);
7335
7464
  return {
7336
7465
  handlePrepareProvider,
7337
7466
  handleSelectProvider,
@@ -7340,7 +7469,8 @@ function useProviderHandlers(deps) {
7340
7469
  handleIncreaseLimit,
7341
7470
  handleNavigateToTokenPicker,
7342
7471
  handleSelectAuthorizedToken,
7343
- handleAuthorizeToken
7472
+ handleAuthorizeToken,
7473
+ handlePreauthorize
7344
7474
  };
7345
7475
  }
7346
7476
 
@@ -7561,7 +7691,6 @@ function useOneTapSetupHandlers(deps) {
7561
7691
  selectSourceTokenSymbol
7562
7692
  } = deps;
7563
7693
  const [savingOneTapLimit, setSavingOneTapLimit] = useState(false);
7564
- const oneTapLimitSavedDuringSetupRef = useRef(false);
7565
7694
  const handleSetupOneTap = useCallback(async (limit) => {
7566
7695
  setSavingOneTapLimit(true);
7567
7696
  try {
@@ -7582,12 +7711,12 @@ function useOneTapSetupHandlers(deps) {
7582
7711
  chainName = recommended?.chainName ?? choices[0]?.chainName ?? "Base";
7583
7712
  tokenSymbol = recommended?.tokenSymbol ?? choices[0]?.tokens[0]?.tokenSymbol ?? "USDC";
7584
7713
  }
7585
- oneTapLimitSavedDuringSetupRef.current = true;
7714
+ dispatch({ type: "SET_ONE_TAP_LIMIT_SAVED_DURING_SETUP", saved: true });
7586
7715
  authExecutor.resolveSelectSource({ chainName, tokenSymbol });
7587
7716
  } else if (authExecutor.pendingOneTapSetup) {
7588
7717
  authExecutor.resolveOneTapSetup();
7589
7718
  }
7590
- dispatch({ type: "SET_USER_INTENT", intent: null });
7719
+ dispatch({ type: "SET_USER_INTENT", intent: { step: "deposit" } });
7591
7720
  } catch (err) {
7592
7721
  captureException(err);
7593
7722
  dispatch({
@@ -7600,124 +7729,63 @@ function useOneTapSetupHandlers(deps) {
7600
7729
  }, [getAccessToken, apiBaseUrl, authExecutor, dispatch, selectSourceChainName, selectSourceTokenSymbol]);
7601
7730
  return {
7602
7731
  handleSetupOneTap,
7603
- savingOneTapLimit,
7604
- oneTapLimitSavedDuringSetupRef
7732
+ savingOneTapLimit
7605
7733
  };
7606
7734
  }
7607
-
7608
- // src/dataLoading.ts
7609
- function resolveDataLoadAction({
7610
- authenticated,
7611
- accountsCount,
7612
- hasActiveCredential,
7613
- loading
7614
- }) {
7615
- if (!authenticated || accountsCount > 0 || !hasActiveCredential) {
7616
- return "reset";
7617
- }
7618
- if (loading) {
7619
- return "wait";
7620
- }
7621
- return "load";
7622
- }
7623
-
7624
- // src/processingStatus.ts
7625
- var PROCESSING_TIMEOUT_MS = 18e4;
7626
- function resolvePreferredTransfer(polledTransfer, localTransfer) {
7627
- return polledTransfer ?? localTransfer;
7628
- }
7629
- function getTransferStatus(polledTransfer, localTransfer) {
7630
- const transfer = resolvePreferredTransfer(polledTransfer, localTransfer);
7631
- return transfer?.status ?? "UNKNOWN";
7632
- }
7633
- function hasProcessingTimedOut(processingStartedAtMs, nowMs) {
7634
- if (!processingStartedAtMs) return false;
7635
- return nowMs - processingStartedAtMs >= PROCESSING_TIMEOUT_MS;
7636
- }
7637
- var STATUS_DISPLAY_LABELS = {
7638
- CREATED: "created",
7639
- AUTHORIZED: "authorized",
7640
- SENDING: "sending",
7641
- SENT: "confirming delivery",
7642
- COMPLETED: "completed",
7643
- FAILED: "failed"
7644
- };
7645
- function getStatusDisplayLabel(status) {
7646
- return STATUS_DISPLAY_LABELS[status] ?? status;
7647
- }
7648
- function buildProcessingTimeoutMessage(status) {
7649
- const label = getStatusDisplayLabel(status);
7650
- return `Payment is taking longer than expected (status: ${label}). Please try again.`;
7651
- }
7652
-
7653
- // src/hooks/usePaymentEffects.ts
7654
- function usePaymentEffects(deps) {
7735
+ function useOtpEffects(deps) {
7655
7736
  const {
7656
7737
  state,
7657
7738
  dispatch,
7658
- ready,
7659
7739
  authenticated,
7660
- apiBaseUrl,
7661
- depositAmount,
7662
- onComplete,
7663
- onError,
7664
- polling,
7665
- authExecutor,
7666
- reloadAccounts,
7667
7740
  activeOtpStatus,
7668
7741
  activeOtpErrorMessage,
7669
7742
  otpCode,
7670
- handleVerifyLoginCode,
7743
+ handleVerifyLoginCode
7744
+ } = deps;
7745
+ useEffect(() => {
7746
+ if (authenticated || !state.verificationTarget) return;
7747
+ if (activeOtpErrorMessage) dispatch({ type: "SET_ERROR", error: activeOtpErrorMessage });
7748
+ }, [activeOtpErrorMessage, authenticated, state.verificationTarget, dispatch]);
7749
+ useEffect(() => {
7750
+ if (state.verificationTarget && !authenticated && /^\d{6}$/.test(otpCode.trim()) && activeOtpStatus === "awaiting-code-input") {
7751
+ handleVerifyLoginCode();
7752
+ }
7753
+ }, [otpCode, state.verificationTarget, authenticated, activeOtpStatus, handleVerifyLoginCode]);
7754
+ }
7755
+ function usePasskeyCheckEffect(deps) {
7756
+ const {
7757
+ dispatch,
7758
+ ready,
7759
+ authenticated,
7760
+ apiBaseUrl,
7761
+ activeCredentialId,
7762
+ passkeyConfigLoaded,
7763
+ checkingPasskeyRef,
7671
7764
  setAuthInput,
7672
7765
  setOtpCode,
7766
+ polling,
7673
7767
  mobileSetupFlowRef,
7674
7768
  handlingMobileReturnRef,
7675
7769
  setupAccountIdRef,
7676
7770
  reauthSessionIdRef,
7677
7771
  reauthTokenRef,
7678
- loadingDataRef,
7679
- pollingTransferIdRef,
7680
- processingStartedAtRef,
7681
- checkingPasskeyRef,
7682
- pendingSelectSourceAction,
7683
- selectSourceChoices,
7684
- selectSourceRecommended,
7685
- setSelectSourceChainName,
7686
- setSelectSourceTokenSymbol,
7687
- initializedSelectSourceActionRef,
7688
- oneTapLimitSavedDuringSetupRef,
7689
- handleAuthorizedMobileReturn
7772
+ pollingTransferIdRef
7690
7773
  } = deps;
7691
7774
  const { getAccessToken } = usePrivy();
7692
- const onCompleteRef = useRef(onComplete);
7693
- onCompleteRef.current = onComplete;
7775
+ const onCompleteRef = useRef(deps.onComplete);
7776
+ onCompleteRef.current = deps.onComplete;
7694
7777
  const getAccessTokenRef = useRef(getAccessToken);
7695
7778
  getAccessTokenRef.current = getAccessToken;
7696
7779
  const pollingRef = useRef(polling);
7697
7780
  pollingRef.current = polling;
7698
- const handleAuthorizedMobileReturnRef = useRef(handleAuthorizedMobileReturn);
7699
- handleAuthorizedMobileReturnRef.current = handleAuthorizedMobileReturn;
7700
- const lastAccountFetchRef = useRef(0);
7701
- useEffect(() => {
7702
- if (depositAmount != null) {
7703
- dispatch({ type: "SYNC_AMOUNT", amount: depositAmount.toString() });
7704
- }
7705
- }, [depositAmount, dispatch]);
7706
- useEffect(() => {
7707
- if (authenticated || !state.verificationTarget) return;
7708
- if (activeOtpErrorMessage) dispatch({ type: "SET_ERROR", error: activeOtpErrorMessage });
7709
- }, [activeOtpErrorMessage, authenticated, state.verificationTarget, dispatch]);
7710
- useEffect(() => {
7711
- if (state.verificationTarget && !authenticated && /^\d{6}$/.test(otpCode.trim()) && activeOtpStatus === "awaiting-code-input") {
7712
- handleVerifyLoginCode();
7713
- }
7714
- }, [otpCode, state.verificationTarget, authenticated, activeOtpStatus, handleVerifyLoginCode]);
7781
+ const handleAuthorizedMobileReturnRef = useRef(deps.handleAuthorizedMobileReturn);
7782
+ handleAuthorizedMobileReturnRef.current = deps.handleAuthorizedMobileReturn;
7715
7783
  useEffect(() => {
7716
7784
  if (!ready || !authenticated) {
7717
7785
  checkingPasskeyRef.current = false;
7718
7786
  return;
7719
7787
  }
7720
- if (state.passkeyConfigLoaded || state.activeCredentialId) return;
7788
+ if (passkeyConfigLoaded || activeCredentialId) return;
7721
7789
  if (checkingPasskeyRef.current) return;
7722
7790
  checkingPasskeyRef.current = true;
7723
7791
  let cancelled = false;
@@ -7815,11 +7883,7 @@ function usePaymentEffects(deps) {
7815
7883
  return;
7816
7884
  }
7817
7885
  if (existingTransfer.status === "AUTHORIZED") {
7818
- if (persisted.isSetup) {
7819
- await handleAuthorizedMobileReturnRef.current(existingTransfer, true);
7820
- } else {
7821
- await handleAuthorizedMobileReturnRef.current(existingTransfer, false);
7822
- }
7886
+ await handleAuthorizedMobileReturnRef.current(existingTransfer, !!persisted.isSetup);
7823
7887
  return;
7824
7888
  }
7825
7889
  if (persisted.isSetup) {
@@ -7870,11 +7934,9 @@ function usePaymentEffects(deps) {
7870
7934
  knownIds: allPasskeys.map((p) => p.credentialId),
7871
7935
  oneTapLimit: config.defaultAllowance ?? void 0
7872
7936
  });
7873
- if (allPasskeys.length === 0) {
7874
- return;
7875
- }
7876
- if (state.activeCredentialId && allPasskeys.some((p) => p.credentialId === state.activeCredentialId)) {
7877
- await restoreState(state.activeCredentialId, token);
7937
+ if (allPasskeys.length === 0) return;
7938
+ if (activeCredentialId && allPasskeys.some((p) => p.credentialId === activeCredentialId)) {
7939
+ await restoreState(activeCredentialId, token);
7878
7940
  return;
7879
7941
  }
7880
7942
  if (cancelled) return;
@@ -7906,7 +7968,39 @@ function usePaymentEffects(deps) {
7906
7968
  cancelled = true;
7907
7969
  checkingPasskeyRef.current = false;
7908
7970
  };
7909
- }, [ready, authenticated, apiBaseUrl, state.activeCredentialId, state.passkeyConfigLoaded]);
7971
+ }, [ready, authenticated, apiBaseUrl, activeCredentialId, passkeyConfigLoaded]);
7972
+ }
7973
+
7974
+ // src/dataLoading.ts
7975
+ function resolveDataLoadAction({
7976
+ authenticated,
7977
+ accountsCount,
7978
+ hasActiveCredential,
7979
+ loading
7980
+ }) {
7981
+ if (!authenticated || accountsCount > 0 || !hasActiveCredential) {
7982
+ return "reset";
7983
+ }
7984
+ if (loading) {
7985
+ return "wait";
7986
+ }
7987
+ return "load";
7988
+ }
7989
+
7990
+ // src/hooks/useDataLoadEffect.ts
7991
+ function useDataLoadEffect(deps) {
7992
+ const {
7993
+ state,
7994
+ dispatch,
7995
+ authenticated,
7996
+ apiBaseUrl,
7997
+ depositAmount,
7998
+ loadingDataRef
7999
+ } = deps;
8000
+ const { getAccessToken } = usePrivy();
8001
+ const getAccessTokenRef = useRef(getAccessToken);
8002
+ getAccessTokenRef.current = getAccessToken;
8003
+ const lastAccountFetchRef = useRef(0);
7910
8004
  useEffect(() => {
7911
8005
  const loadAction = resolveDataLoadAction({
7912
8006
  authenticated,
@@ -8006,6 +8100,61 @@ function usePaymentEffects(deps) {
8006
8100
  cancelled = true;
8007
8101
  };
8008
8102
  }, [authenticated, state.providers.length, state.activeCredentialId, apiBaseUrl]);
8103
+ useEffect(() => {
8104
+ if (state.accounts.length > 0 && state.activeCredentialId && !state.loadingData && !state.transfer && authenticated && Date.now() - lastAccountFetchRef.current > 15e3) {
8105
+ lastAccountFetchRef.current = Date.now();
8106
+ deps.reloadAccounts();
8107
+ }
8108
+ }, [
8109
+ state.accounts.length,
8110
+ state.activeCredentialId,
8111
+ state.loadingData,
8112
+ state.transfer,
8113
+ authenticated,
8114
+ deps
8115
+ ]);
8116
+ }
8117
+
8118
+ // src/processingStatus.ts
8119
+ var PROCESSING_TIMEOUT_MS = 18e4;
8120
+ function resolvePreferredTransfer(polledTransfer, localTransfer) {
8121
+ return polledTransfer ?? localTransfer;
8122
+ }
8123
+ function getTransferStatus(polledTransfer, localTransfer) {
8124
+ const transfer = resolvePreferredTransfer(polledTransfer, localTransfer);
8125
+ return transfer?.status ?? "UNKNOWN";
8126
+ }
8127
+ function hasProcessingTimedOut(processingStartedAtMs, nowMs) {
8128
+ if (!processingStartedAtMs) return false;
8129
+ return nowMs - processingStartedAtMs >= PROCESSING_TIMEOUT_MS;
8130
+ }
8131
+ var STATUS_DISPLAY_LABELS = {
8132
+ CREATED: "created",
8133
+ AUTHORIZED: "authorized",
8134
+ SENDING: "sending",
8135
+ SENT: "confirming delivery",
8136
+ COMPLETED: "completed",
8137
+ FAILED: "failed"
8138
+ };
8139
+ function getStatusDisplayLabel(status) {
8140
+ return STATUS_DISPLAY_LABELS[status] ?? status;
8141
+ }
8142
+ function buildProcessingTimeoutMessage(status) {
8143
+ const label = getStatusDisplayLabel(status);
8144
+ return `Payment is taking longer than expected (status: ${label}). Please try again.`;
8145
+ }
8146
+
8147
+ // src/hooks/useProcessingEffect.ts
8148
+ function useProcessingEffect(deps) {
8149
+ const {
8150
+ state,
8151
+ dispatch,
8152
+ polling,
8153
+ processingStartedAtRef,
8154
+ onComplete,
8155
+ onError,
8156
+ reloadAccounts
8157
+ } = deps;
8009
8158
  useEffect(() => {
8010
8159
  if (!polling.transfer) return;
8011
8160
  if (polling.transfer.status === "COMPLETED") {
@@ -8018,19 +8167,6 @@ function usePaymentEffects(deps) {
8018
8167
  dispatch({ type: "TRANSFER_FAILED", transfer: polling.transfer, error: "Transfer failed." });
8019
8168
  }
8020
8169
  }, [polling.transfer, onComplete, dispatch, reloadAccounts]);
8021
- useEffect(() => {
8022
- if (state.accounts.length > 0 && state.activeCredentialId && !state.loadingData && !state.transfer && authenticated && Date.now() - lastAccountFetchRef.current > 15e3) {
8023
- lastAccountFetchRef.current = Date.now();
8024
- reloadAccounts();
8025
- }
8026
- }, [
8027
- state.accounts.length,
8028
- state.activeCredentialId,
8029
- state.loadingData,
8030
- state.transfer,
8031
- authenticated,
8032
- reloadAccounts
8033
- ]);
8034
8170
  useEffect(() => {
8035
8171
  const isProcessing = state.creatingTransfer || state.transfer != null && ["CREATED", "SENDING", "SENT"].includes(state.transfer.status);
8036
8172
  if (!isProcessing) {
@@ -8066,6 +8202,26 @@ function usePaymentEffects(deps) {
8066
8202
  dispatch,
8067
8203
  processingStartedAtRef
8068
8204
  ]);
8205
+ }
8206
+ function useMobilePollingEffect(deps) {
8207
+ const {
8208
+ state,
8209
+ dispatch,
8210
+ polling,
8211
+ mobileSetupFlowRef,
8212
+ handlingMobileReturnRef,
8213
+ setupAccountIdRef,
8214
+ reauthSessionIdRef,
8215
+ reauthTokenRef,
8216
+ pollingTransferIdRef,
8217
+ reloadAccounts,
8218
+ apiBaseUrl
8219
+ } = deps;
8220
+ const { getAccessToken } = usePrivy();
8221
+ const getAccessTokenRef = useRef(getAccessToken);
8222
+ getAccessTokenRef.current = getAccessToken;
8223
+ const handleAuthorizedMobileReturnRef = useRef(deps.handleAuthorizedMobileReturn);
8224
+ handleAuthorizedMobileReturnRef.current = deps.handleAuthorizedMobileReturn;
8069
8225
  useEffect(() => {
8070
8226
  if (!state.mobileFlow) {
8071
8227
  handlingMobileReturnRef.current = false;
@@ -8074,8 +8230,8 @@ function usePaymentEffects(deps) {
8074
8230
  if (handlingMobileReturnRef.current) return;
8075
8231
  const polledTransfer = polling.transfer;
8076
8232
  if (!polledTransfer || polledTransfer.status !== "AUTHORIZED") return;
8077
- void handleAuthorizedMobileReturn(polledTransfer, mobileSetupFlowRef.current);
8078
- }, [state.mobileFlow, polling.transfer, handleAuthorizedMobileReturn, handlingMobileReturnRef, mobileSetupFlowRef]);
8233
+ void handleAuthorizedMobileReturnRef.current(polledTransfer, mobileSetupFlowRef.current);
8234
+ }, [state.mobileFlow, polling.transfer, handlingMobileReturnRef, mobileSetupFlowRef]);
8079
8235
  useEffect(() => {
8080
8236
  if (!state.mobileFlow || !mobileSetupFlowRef.current) return;
8081
8237
  if (!state.activeCredentialId || !setupAccountIdRef.current) return;
@@ -8151,14 +8307,10 @@ function usePaymentEffects(deps) {
8151
8307
  poll();
8152
8308
  const intervalId = window.setInterval(poll, POLL_INTERVAL_MS);
8153
8309
  const handleVisibility = () => {
8154
- if (document.visibilityState === "visible" && !cancelled) {
8155
- poll();
8156
- }
8310
+ if (document.visibilityState === "visible" && !cancelled) poll();
8157
8311
  };
8158
8312
  const handlePageShow = (e) => {
8159
- if (e.persisted && !cancelled) {
8160
- poll();
8161
- }
8313
+ if (e.persisted && !cancelled) poll();
8162
8314
  };
8163
8315
  document.addEventListener("visibilitychange", handleVisibility);
8164
8316
  window.addEventListener("pageshow", handlePageShow);
@@ -8209,6 +8361,16 @@ function usePaymentEffects(deps) {
8209
8361
  handlingMobileReturnRef,
8210
8362
  pollingTransferIdRef
8211
8363
  ]);
8364
+ }
8365
+ function useSelectSourceEffect(deps) {
8366
+ const {
8367
+ pendingSelectSourceAction,
8368
+ selectSourceChoices,
8369
+ selectSourceRecommended,
8370
+ setSelectSourceChainName,
8371
+ setSelectSourceTokenSymbol,
8372
+ initializedSelectSourceActionRef
8373
+ } = deps;
8212
8374
  useEffect(() => {
8213
8375
  if (!pendingSelectSourceAction) {
8214
8376
  initializedSelectSourceActionRef.current = null;
@@ -8239,38 +8401,27 @@ function usePaymentEffects(deps) {
8239
8401
  setSelectSourceTokenSymbol,
8240
8402
  initializedSelectSourceActionRef
8241
8403
  ]);
8404
+ }
8405
+ function useOneTapAutoResolveEffect(deps) {
8406
+ const { authExecutor, dispatch, oneTapLimitSavedDuringSetup, reloadAccounts } = deps;
8242
8407
  const pendingOneTapSetupAction = authExecutor.pendingOneTapSetup;
8243
8408
  useEffect(() => {
8244
- if (pendingOneTapSetupAction && oneTapLimitSavedDuringSetupRef.current) {
8245
- oneTapLimitSavedDuringSetupRef.current = false;
8409
+ if (pendingOneTapSetupAction && oneTapLimitSavedDuringSetup) {
8410
+ dispatch({ type: "SET_ONE_TAP_LIMIT_SAVED_DURING_SETUP", saved: false });
8246
8411
  authExecutor.resolveOneTapSetup();
8247
8412
  }
8248
- }, [pendingOneTapSetupAction, authExecutor, oneTapLimitSavedDuringSetupRef]);
8413
+ }, [pendingOneTapSetupAction, authExecutor, dispatch, oneTapLimitSavedDuringSetup]);
8249
8414
  useEffect(() => {
8250
- if (pendingOneTapSetupAction && !oneTapLimitSavedDuringSetupRef.current) {
8415
+ if (pendingOneTapSetupAction && !oneTapLimitSavedDuringSetup) {
8251
8416
  reloadAccounts();
8252
8417
  }
8253
- }, [pendingOneTapSetupAction, reloadAccounts, oneTapLimitSavedDuringSetupRef]);
8254
- useEffect(() => {
8255
- if (!state.guestSessionToken) return;
8256
- if (state.guestPreauthAccountId) return;
8257
- if (!state.transfer || state.transfer.status !== "COMPLETED") return;
8258
- let cancelled = false;
8259
- const checkGuestAccount = async () => {
8260
- try {
8261
- const result = await fetchGuestAccount(apiBaseUrl, state.guestSessionToken);
8262
- if (cancelled) return;
8263
- if (result && !result.hasPasskey) {
8264
- dispatch({ type: "GUEST_PREAUTH_DETECTED", accountId: result.accountId });
8265
- }
8266
- } catch {
8267
- }
8268
- };
8269
- checkGuestAccount();
8270
- return () => {
8271
- cancelled = true;
8272
- };
8273
- }, [state.transfer, state.guestSessionToken, state.guestPreauthAccountId, apiBaseUrl, dispatch]);
8418
+ }, [pendingOneTapSetupAction, reloadAccounts, oneTapLimitSavedDuringSetup]);
8419
+ }
8420
+ function useGuestPreauthEffect(deps) {
8421
+ const { state, dispatch, authenticated, apiBaseUrl, reloadAccounts } = deps;
8422
+ const { getAccessToken } = usePrivy();
8423
+ const getAccessTokenRef = useRef(getAccessToken);
8424
+ getAccessTokenRef.current = getAccessToken;
8274
8425
  const settingOwnerRef = useRef(false);
8275
8426
  useEffect(() => {
8276
8427
  if (!state.guestPreauthAccountId) return;
@@ -8279,6 +8430,8 @@ function usePaymentEffects(deps) {
8279
8430
  if (!authenticated) return;
8280
8431
  if (!state.guestSessionToken) return;
8281
8432
  if (settingOwnerRef.current) return;
8433
+ const hasActive = state.accounts.some((a) => a.wallets.some((w) => w.status === "ACTIVE"));
8434
+ if (!hasActive) return;
8282
8435
  settingOwnerRef.current = true;
8283
8436
  let cancelled = false;
8284
8437
  const setOwner = async () => {
@@ -8316,12 +8469,73 @@ function usePaymentEffects(deps) {
8316
8469
  state.activeCredentialId,
8317
8470
  state.activePublicKey,
8318
8471
  state.guestSessionToken,
8472
+ state.accounts,
8319
8473
  authenticated,
8320
8474
  apiBaseUrl,
8321
8475
  dispatch,
8322
8476
  reloadAccounts
8323
8477
  ]);
8324
8478
  }
8479
+ function useGuestDesktopPreauthSessionEffect(deps) {
8480
+ const { state, authExecutor, reloadAccounts, dispatch, desktopGuestPreauth } = deps;
8481
+ const preauthExecutingRef = useRef(false);
8482
+ useEffect(() => {
8483
+ if (!desktopGuestPreauth) return;
8484
+ if (!state.guestPreauthorizing) return;
8485
+ if (!state.guestPreauthSessionId || preauthExecutingRef.current) return;
8486
+ preauthExecutingRef.current = true;
8487
+ const runPreauthSession = async () => {
8488
+ try {
8489
+ await authExecutor.executeSessionById(state.guestPreauthSessionId);
8490
+ await reloadAccounts();
8491
+ } catch {
8492
+ } finally {
8493
+ preauthExecutingRef.current = false;
8494
+ dispatch({ type: "GUEST_PREAUTH_END" });
8495
+ }
8496
+ };
8497
+ void runPreauthSession();
8498
+ }, [
8499
+ desktopGuestPreauth,
8500
+ state.guestPreauthorizing,
8501
+ state.guestPreauthSessionId,
8502
+ authExecutor,
8503
+ reloadAccounts,
8504
+ dispatch
8505
+ ]);
8506
+ }
8507
+ function useGuestPreauthPhaseSyncEffect(deps) {
8508
+ const { state, dispatch, authExecutor, isDesktop } = deps;
8509
+ useEffect(() => {
8510
+ if (!state.guestPreauthorizing || !isDesktop) return;
8511
+ const pending = authExecutor.pendingSelectSource;
8512
+ if (pending) {
8513
+ const intent = {
8514
+ step: "select-source",
8515
+ action: pending,
8516
+ isDesktop,
8517
+ skipOneTapLimit: true
8518
+ };
8519
+ if (state.phase.step === "select-source") {
8520
+ const ph = state.phase;
8521
+ if (ph.skipOneTapLimit && ph.action.id === pending.id) {
8522
+ return;
8523
+ }
8524
+ }
8525
+ dispatch({ type: "SET_USER_INTENT", intent });
8526
+ return;
8527
+ }
8528
+ if (state.phase.step === "select-source" && state.phase.skipOneTapLimit === true) {
8529
+ dispatch({ type: "SET_USER_INTENT", intent: { step: "one-tap-setup", action: null } });
8530
+ }
8531
+ }, [
8532
+ state.guestPreauthorizing,
8533
+ state.phase,
8534
+ isDesktop,
8535
+ authExecutor.pendingSelectSource,
8536
+ dispatch
8537
+ ]);
8538
+ }
8325
8539
  function BlinkPayment(props) {
8326
8540
  const resetKey = useRef(0);
8327
8541
  const handleBoundaryReset = useCallback(() => {
@@ -8343,6 +8557,10 @@ function BlinkPaymentInner({
8343
8557
  const { apiBaseUrl, depositAmount } = useBlinkConfig();
8344
8558
  const { ready, authenticated, logout, getAccessToken } = usePrivy();
8345
8559
  useLoginWithOAuth();
8560
+ const isDesktop = shouldUseWalletConnector({
8561
+ useWalletConnector: useWalletConnectorProp,
8562
+ userAgent: typeof navigator === "undefined" ? void 0 : navigator.userAgent
8563
+ });
8346
8564
  const [state, dispatch] = useReducer(
8347
8565
  paymentReducer,
8348
8566
  {
@@ -8426,7 +8644,9 @@ function BlinkPaymentInner({
8426
8644
  reauthTokenRef: mobileFlowRefs.reauthTokenRef,
8427
8645
  authenticated,
8428
8646
  merchantAuthorization,
8429
- destination
8647
+ destination,
8648
+ guestSessionToken: state.guestSessionToken,
8649
+ selectedProviderId: state.selectedProviderId
8430
8650
  });
8431
8651
  const oneTapSetup = useOneTapSetupHandlers({
8432
8652
  dispatch,
@@ -8448,13 +8668,12 @@ function BlinkPaymentInner({
8448
8668
  clearMobileFlowState();
8449
8669
  transfer.processingStartedAtRef.current = null;
8450
8670
  transfer.pollingTransferIdRef.current = null;
8451
- oneTapSetup.oneTapLimitSavedDuringSetupRef.current = false;
8452
8671
  dispatch({
8453
8672
  type: "NEW_PAYMENT",
8454
8673
  depositAmount,
8455
8674
  firstAccountId: state.accounts.length > 0 ? state.accounts[0].id : null
8456
8675
  });
8457
- }, [depositAmount, state.accounts, transfer, oneTapSetup]);
8676
+ }, [depositAmount, state.accounts, transfer]);
8458
8677
  const handleLogout = useCallback(async () => {
8459
8678
  try {
8460
8679
  await logout();
@@ -8466,65 +8685,112 @@ function BlinkPaymentInner({
8466
8685
  }
8467
8686
  polling.stopPolling();
8468
8687
  passkey.checkingPasskeyRef.current = false;
8469
- oneTapSetup.oneTapLimitSavedDuringSetupRef.current = false;
8470
8688
  auth.setAuthInput("");
8471
8689
  auth.setOtpCode("");
8472
8690
  dispatch({ type: "LOGOUT", depositAmount });
8473
- }, [logout, polling, depositAmount, auth, passkey, oneTapSetup]);
8474
- usePaymentEffects({
8691
+ }, [logout, polling, depositAmount, auth, passkey]);
8692
+ useEffect(() => {
8693
+ if (depositAmount != null) {
8694
+ dispatch({ type: "SYNC_AMOUNT", amount: depositAmount.toString() });
8695
+ }
8696
+ }, [depositAmount, dispatch]);
8697
+ useOtpEffects({
8475
8698
  state,
8476
8699
  dispatch,
8477
- ready,
8478
8700
  authenticated,
8479
- apiBaseUrl,
8480
- depositAmount,
8481
- onComplete,
8482
- onError,
8483
- polling,
8484
- authExecutor,
8485
- reloadAccounts: transfer.reloadAccounts,
8486
8701
  activeOtpStatus: auth.activeOtpStatus,
8487
8702
  activeOtpErrorMessage: auth.activeOtpErrorMessage,
8488
8703
  otpCode: auth.otpCode,
8489
8704
  handleVerifyLoginCode: auth.handleVerifyLoginCode,
8490
8705
  setAuthInput: auth.setAuthInput,
8706
+ setOtpCode: auth.setOtpCode
8707
+ });
8708
+ usePasskeyCheckEffect({
8709
+ dispatch,
8710
+ ready,
8711
+ authenticated,
8712
+ apiBaseUrl,
8713
+ activeCredentialId: state.activeCredentialId,
8714
+ passkeyConfigLoaded: state.passkeyConfigLoaded,
8715
+ checkingPasskeyRef: passkey.checkingPasskeyRef,
8716
+ setAuthInput: auth.setAuthInput,
8491
8717
  setOtpCode: auth.setOtpCode,
8718
+ polling,
8492
8719
  mobileSetupFlowRef: mobileFlowRefs.mobileSetupFlowRef,
8493
8720
  handlingMobileReturnRef: mobileFlowRefs.handlingMobileReturnRef,
8494
8721
  setupAccountIdRef: mobileFlowRefs.setupAccountIdRef,
8495
8722
  reauthSessionIdRef: mobileFlowRefs.reauthSessionIdRef,
8496
8723
  reauthTokenRef: mobileFlowRefs.reauthTokenRef,
8497
- loadingDataRef: mobileFlowRefs.loadingDataRef,
8498
8724
  pollingTransferIdRef: transfer.pollingTransferIdRef,
8725
+ handleAuthorizedMobileReturn: mobileFlow.handleAuthorizedMobileReturn,
8726
+ onComplete
8727
+ });
8728
+ useDataLoadEffect({
8729
+ state,
8730
+ dispatch,
8731
+ authenticated,
8732
+ apiBaseUrl,
8733
+ depositAmount,
8734
+ loadingDataRef: mobileFlowRefs.loadingDataRef,
8735
+ reloadAccounts: transfer.reloadAccounts
8736
+ });
8737
+ useProcessingEffect({
8738
+ state,
8739
+ dispatch,
8740
+ polling,
8499
8741
  processingStartedAtRef: transfer.processingStartedAtRef,
8500
- checkingPasskeyRef: passkey.checkingPasskeyRef,
8742
+ onComplete,
8743
+ onError,
8744
+ reloadAccounts: transfer.reloadAccounts
8745
+ });
8746
+ useMobilePollingEffect({
8747
+ state,
8748
+ dispatch,
8749
+ polling,
8750
+ mobileSetupFlowRef: mobileFlowRefs.mobileSetupFlowRef,
8751
+ handlingMobileReturnRef: mobileFlowRefs.handlingMobileReturnRef,
8752
+ setupAccountIdRef: mobileFlowRefs.setupAccountIdRef,
8753
+ reauthSessionIdRef: mobileFlowRefs.reauthSessionIdRef,
8754
+ reauthTokenRef: mobileFlowRefs.reauthTokenRef,
8755
+ pollingTransferIdRef: transfer.pollingTransferIdRef,
8756
+ reloadAccounts: transfer.reloadAccounts,
8757
+ handleAuthorizedMobileReturn: mobileFlow.handleAuthorizedMobileReturn,
8758
+ apiBaseUrl
8759
+ });
8760
+ useSelectSourceEffect({
8501
8761
  pendingSelectSourceAction: sourceSelection.pendingSelectSourceAction,
8502
8762
  selectSourceChoices: sourceSelection.selectSourceChoices,
8503
8763
  selectSourceRecommended: sourceSelection.selectSourceRecommended,
8504
8764
  setSelectSourceChainName: sourceSelection.setSelectSourceChainName,
8505
8765
  setSelectSourceTokenSymbol: sourceSelection.setSelectSourceTokenSymbol,
8506
- initializedSelectSourceActionRef: sourceSelection.initializedSelectSourceActionRef,
8507
- oneTapLimitSavedDuringSetupRef: oneTapSetup.oneTapLimitSavedDuringSetupRef,
8508
- handleAuthorizedMobileReturn: mobileFlow.handleAuthorizedMobileReturn
8766
+ initializedSelectSourceActionRef: sourceSelection.initializedSelectSourceActionRef
8509
8767
  });
8510
- const autoSelectingRef = useRef(false);
8511
- useEffect(() => {
8512
- if (!state.isGuestFlow || !state.selectedProviderId || !state.activeCredentialId || !authenticated || autoSelectingRef.current || state.transfer != null) return;
8513
- const hasActive = state.accounts.some((a) => a.wallets.some((w) => w.status === "ACTIVE"));
8514
- if (hasActive) return;
8515
- autoSelectingRef.current = true;
8516
- provider.handleSelectProvider(state.selectedProviderId).finally(() => {
8517
- autoSelectingRef.current = false;
8518
- });
8519
- }, [
8520
- state.isGuestFlow,
8521
- state.selectedProviderId,
8522
- state.activeCredentialId,
8523
- state.transfer,
8524
- state.accounts,
8768
+ useOneTapAutoResolveEffect({
8769
+ authExecutor,
8770
+ dispatch,
8771
+ oneTapLimitSavedDuringSetup: state.oneTapLimitSavedDuringSetup,
8772
+ reloadAccounts: transfer.reloadAccounts
8773
+ });
8774
+ useGuestPreauthEffect({
8775
+ state,
8776
+ dispatch,
8525
8777
  authenticated,
8526
- provider
8527
- ]);
8778
+ apiBaseUrl,
8779
+ reloadAccounts: transfer.reloadAccounts
8780
+ });
8781
+ useGuestPreauthPhaseSyncEffect({
8782
+ state,
8783
+ dispatch,
8784
+ authExecutor,
8785
+ isDesktop
8786
+ });
8787
+ useGuestDesktopPreauthSessionEffect({
8788
+ state,
8789
+ authExecutor,
8790
+ reloadAccounts: transfer.reloadAccounts,
8791
+ dispatch,
8792
+ desktopGuestPreauth: isDesktop
8793
+ });
8528
8794
  const handlers = useMemo(() => ({
8529
8795
  onSendLoginCode: auth.handleSendLoginCode,
8530
8796
  onVerifyLoginCode: auth.handleVerifyLoginCode,
@@ -8547,7 +8813,7 @@ function BlinkPaymentInner({
8547
8813
  onBackFromOpenWallet: () => dispatch({ type: "CLEAR_MOBILE_STATE" }),
8548
8814
  onLogout: handleLogout,
8549
8815
  onNewPayment: handleNewPayment,
8550
- onSetUserIntent: (intent) => dispatch({ type: "SET_USER_INTENT", intent }),
8816
+ onSetPhase: (phase) => dispatch({ type: "SET_USER_INTENT", intent: phase }),
8551
8817
  onSetAuthInput: auth.setAuthInput,
8552
8818
  onSetOtpCode: (code) => {
8553
8819
  auth.setOtpCode(code);
@@ -8562,29 +8828,7 @@ function BlinkPaymentInner({
8562
8828
  onAuthorizeToken: provider.handleAuthorizeToken,
8563
8829
  onSelectGuestToken: guestTransfer.handleSelectGuestToken,
8564
8830
  onLogin: () => dispatch({ type: "REQUEST_LOGIN" }),
8565
- onPreauthorize: async () => {
8566
- if (state.guestPreauthAccountId) {
8567
- dispatch({ type: "REQUEST_LOGIN" });
8568
- return;
8569
- }
8570
- if (!state.guestSessionToken || !state.selectedProviderId) {
8571
- dispatch({ type: "REQUEST_LOGIN" });
8572
- return;
8573
- }
8574
- try {
8575
- const providerName = state.providers.find((p) => p.id === state.selectedProviderId)?.name ?? "Wallet";
8576
- const created = await createGuestAccount(
8577
- apiBaseUrl,
8578
- state.guestSessionToken,
8579
- state.selectedProviderId,
8580
- providerName
8581
- );
8582
- dispatch({ type: "GUEST_PREAUTH_DETECTED", accountId: created.accountId });
8583
- dispatch({ type: "REQUEST_LOGIN" });
8584
- } catch {
8585
- dispatch({ type: "REQUEST_LOGIN" });
8586
- }
8587
- }
8831
+ onPreauthorize: provider.handlePreauthorize
8588
8832
  }), [
8589
8833
  auth,
8590
8834
  passkey,
@@ -8595,56 +8839,57 @@ function BlinkPaymentInner({
8595
8839
  oneTapSetup,
8596
8840
  guestTransfer,
8597
8841
  handleLogout,
8598
- handleNewPayment,
8599
- state.guestPreauthAccountId,
8600
- state.guestSessionToken,
8601
- state.selectedProviderId,
8602
- state.providers,
8603
- apiBaseUrl
8842
+ handleNewPayment
8604
8843
  ]);
8605
8844
  return /* @__PURE__ */ jsx(
8606
8845
  StepRenderer,
8607
8846
  {
8608
- state,
8609
- ready,
8610
- authenticated,
8611
- activeOtpStatus: auth.activeOtpStatus,
8612
- pollingTransfer: polling.transfer,
8613
- pollingError: polling.error,
8614
- authExecutorError: authExecutor.error,
8615
- inlineAuthorizationExecuting: authExecutor.executing,
8616
- transferSigningSigning: transferSigning.signing,
8617
- transferSigningError: transferSigning.error,
8618
- pendingSelectSource: authExecutor.pendingSelectSource,
8619
- pendingOneTapSetup: authExecutor.pendingOneTapSetup,
8620
- oneTapLimitAlreadySaved: oneTapSetup.oneTapLimitSavedDuringSetupRef.current,
8621
- pendingConnections: derived.pendingConnections,
8622
- depositEligibleAccounts: derived.depositEligibleAccounts,
8623
- sourceName: derived.sourceName,
8624
- maxSourceBalance: derived.maxSourceBalance,
8625
- tokenCount: derived.tokenCount,
8626
- selectedAccount: derived.selectedAccount,
8627
- selectedSource: derived.selectedSource,
8628
- selectSourceChoices: sourceSelection.selectSourceChoices,
8629
- selectSourceRecommended: sourceSelection.selectSourceRecommended,
8630
- selectSourceAvailableBalance: sourceSelection.selectSourceAvailableBalance,
8631
- guestTokenEntries: guestTransfer.guestTokenEntries,
8632
- guestLoadingBalances: guestTransfer.loadingBalances,
8633
- guestSettingSender: guestTransfer.settingSender,
8634
- authInput: auth.authInput,
8635
- otpCode: auth.otpCode,
8636
- selectSourceChainName: sourceSelection.selectSourceChainName,
8637
- selectSourceTokenSymbol: sourceSelection.selectSourceTokenSymbol,
8638
- savingOneTapLimit: oneTapSetup.savingOneTapLimit,
8639
- merchantName,
8640
- onBack,
8641
- onDismiss,
8642
- depositAmount,
8847
+ flow: {
8848
+ state,
8849
+ authenticated,
8850
+ activeOtpStatus: auth.activeOtpStatus,
8851
+ isDesktop,
8852
+ merchantName,
8853
+ onBack,
8854
+ onDismiss,
8855
+ depositAmount
8856
+ },
8857
+ remote: {
8858
+ pollingTransfer: polling.transfer,
8859
+ pollingError: polling.error,
8860
+ authExecutorError: authExecutor.error,
8861
+ transferSigningSigning: transferSigning.signing,
8862
+ transferSigningError: transferSigning.error,
8863
+ pendingSelectSource: authExecutor.pendingSelectSource,
8864
+ pendingOneTapSetup: authExecutor.pendingOneTapSetup
8865
+ },
8866
+ derived: {
8867
+ pendingConnections: derived.pendingConnections,
8868
+ depositEligibleAccounts: derived.depositEligibleAccounts,
8869
+ sourceName: derived.sourceName,
8870
+ maxSourceBalance: derived.maxSourceBalance,
8871
+ tokenCount: derived.tokenCount,
8872
+ selectedAccount: derived.selectedAccount,
8873
+ selectedSource: derived.selectedSource,
8874
+ selectSourceChoices: sourceSelection.selectSourceChoices,
8875
+ selectSourceRecommended: sourceSelection.selectSourceRecommended,
8876
+ selectSourceAvailableBalance: sourceSelection.selectSourceAvailableBalance
8877
+ },
8878
+ forms: {
8879
+ authInput: auth.authInput,
8880
+ otpCode: auth.otpCode,
8881
+ selectSourceChainName: sourceSelection.selectSourceChainName,
8882
+ selectSourceTokenSymbol: sourceSelection.selectSourceTokenSymbol,
8883
+ savingOneTapLimit: oneTapSetup.savingOneTapLimit,
8884
+ guestTokenEntries: guestTransfer.guestTokenEntries,
8885
+ guestLoadingBalances: guestTransfer.loadingBalances,
8886
+ guestSettingSender: guestTransfer.settingSender
8887
+ },
8643
8888
  handlers
8644
8889
  }
8645
8890
  );
8646
8891
  }
8647
8892
 
8648
- export { AdvancedSourceScreen, BLINK_LOGO, BLINK_MASCOT, BlinkLoadingScreen, BlinkPayment, BlinkProvider, FlowPhaseProvider, IconCircle, InfoBanner, OutlineButton, PasskeyIframeBlockedError, PasskeyScreen, PoweredByFooter, PrimaryButton, ScreenHeader, ScreenLayout, SelectSourceScreen, SettingsMenu, SetupScreen, Spinner, StepList, TokenPickerScreen, api_exports as blinkApi, buildPasskeyPopupOptions, createPasskeyCredential, createPasskeyViaPopup, darkTheme, deviceHasPasskey, findDevicePasskey, findDevicePasskeyViaPopup, getTheme, lightTheme, resolvePasskeyRpId, resolveScreen, useAuthorizationExecutor, useBlinkConfig, useBlinkDepositAmount, useTransferPolling, useTransferSigning };
8893
+ export { AdvancedSourceScreen, BLINK_LOGO, BLINK_MASCOT, BlinkLoadingScreen, BlinkPayment, BlinkProvider, FlowPhaseProvider, IconCircle, InfoBanner, OutlineButton, PasskeyIframeBlockedError, PasskeyScreen, PoweredByFooter, PrimaryButton, ScreenHeader, ScreenLayout, SelectSourceScreen, SettingsMenu, SetupScreen, Spinner, StepList, TokenPickerScreen, api_exports as blinkApi, buildPasskeyPopupOptions, createPasskeyCredential, createPasskeyViaPopup, darkTheme, deviceHasPasskey, findDevicePasskey, findDevicePasskeyViaPopup, getTheme, lightTheme, resolvePasskeyRpId, screenForPhase, useAuthorizationExecutor, useBlinkConfig, useBlinkDepositAmount, useTransferPolling, useTransferSigning };
8649
8894
  //# sourceMappingURL=index.js.map
8650
8895
  //# sourceMappingURL=index.js.map