@swype-org/react-sdk 0.1.220 → 0.1.222

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.cjs CHANGED
@@ -459,6 +459,7 @@ async function waitForTransactionReceipt(config, parameters) {
459
459
  // src/api.ts
460
460
  var api_exports = {};
461
461
  __export(api_exports, {
462
+ claimAccount: () => claimAccount,
462
463
  createAccount: () => createAccount,
463
464
  createAccountAuthorizationSession: () => createAccountAuthorizationSession,
464
465
  createGuestTransfer: () => createGuestTransfer,
@@ -467,6 +468,7 @@ __export(api_exports, {
467
468
  fetchAccounts: () => fetchAccounts,
468
469
  fetchAuthorizationSession: () => fetchAuthorizationSession,
469
470
  fetchChains: () => fetchChains,
471
+ fetchGuestPreauthAccount: () => fetchGuestPreauthAccount,
470
472
  fetchGuestTransferBalances: () => fetchGuestTransferBalances,
471
473
  fetchMerchantPublicKey: () => fetchMerchantPublicKey,
472
474
  fetchProviders: () => fetchProviders,
@@ -766,6 +768,25 @@ async function fetchGuestTransferBalances(apiBaseUrl, transferId, guestSessionTo
766
768
  const data = await res.json();
767
769
  return data.items;
768
770
  }
771
+ async function fetchGuestPreauthAccount(apiBaseUrl, guestToken) {
772
+ const params = new URLSearchParams({ guestToken });
773
+ const res = await fetch(`${apiBaseUrl}/v1/guest-preauth?${params.toString()}`);
774
+ if (res.status === 404) return null;
775
+ if (!res.ok) await throwApiError(res);
776
+ return await res.json();
777
+ }
778
+ async function claimAccount(apiBaseUrl, accessToken, accountId, body) {
779
+ const res = await fetch(`${apiBaseUrl}/v1/accounts/${accountId}/claim`, {
780
+ method: "POST",
781
+ headers: {
782
+ "Content-Type": "application/json",
783
+ "Authorization": `Bearer ${accessToken}`
784
+ },
785
+ body: JSON.stringify(body)
786
+ });
787
+ if (!res.ok) await throwApiError(res);
788
+ return await res.json();
789
+ }
769
790
  async function reportActionCompletion(apiBaseUrl, actionId, result) {
770
791
  const res = await fetch(
771
792
  `${apiBaseUrl}/v1/authorization-actions/${actionId}`,
@@ -1940,7 +1961,9 @@ function createInitialState(config) {
1940
1961
  previousStep: null,
1941
1962
  isGuestFlow: false,
1942
1963
  guestTransferId: null,
1943
- guestSessionToken: null
1964
+ guestSessionToken: null,
1965
+ guestPreauthAccountId: null,
1966
+ activePublicKey: null
1944
1967
  };
1945
1968
  }
1946
1969
  function paymentReducer(state, action) {
@@ -1971,6 +1994,7 @@ function paymentReducer(state, action) {
1971
1994
  return {
1972
1995
  ...state,
1973
1996
  activeCredentialId: action.credentialId,
1997
+ activePublicKey: action.publicKey ?? state.activePublicKey,
1974
1998
  passkeyPopupNeeded: false
1975
1999
  };
1976
2000
  case "SET_PASSKEY_POPUP_NEEDED":
@@ -2184,6 +2208,20 @@ function paymentReducer(state, action) {
2184
2208
  mobileFlow: false,
2185
2209
  deeplinkUri: null
2186
2210
  };
2211
+ case "GUEST_PREAUTH_DETECTED":
2212
+ return {
2213
+ ...state,
2214
+ guestPreauthAccountId: action.accountId,
2215
+ step: "login"
2216
+ };
2217
+ case "GUEST_PREAUTH_CLAIMED":
2218
+ return {
2219
+ ...state,
2220
+ guestPreauthAccountId: null,
2221
+ activePublicKey: null,
2222
+ step: "deposit",
2223
+ error: null
2224
+ };
2187
2225
  // ── Navigation & error ───────────────────────────────────────
2188
2226
  case "NAVIGATE":
2189
2227
  return { ...state, step: action.step, previousStep: state.step, error: null };
@@ -2204,7 +2242,9 @@ function paymentReducer(state, action) {
2204
2242
  selectedAccountId: action.firstAccountId,
2205
2243
  isGuestFlow: false,
2206
2244
  guestTransferId: null,
2207
- guestSessionToken: null
2245
+ guestSessionToken: null,
2246
+ guestPreauthAccountId: null,
2247
+ activePublicKey: null
2208
2248
  };
2209
2249
  case "LOGOUT":
2210
2250
  return {
@@ -4448,45 +4488,23 @@ function SuccessScreen({
4448
4488
  onLogout,
4449
4489
  onIncreaseLimits,
4450
4490
  onManageAccount,
4451
- autoCloseSeconds
4491
+ onPreauthorize
4452
4492
  }) {
4453
4493
  const { tokens } = useBlinkConfig();
4454
- const effectiveAutoClose = succeeded ? autoCloseSeconds : void 0;
4455
- const [countdown, setCountdown] = react.useState(effectiveAutoClose ?? 0);
4456
- const doneCalledRef = react.useRef(false);
4457
- const handleDone = react.useCallback(() => {
4458
- if (doneCalledRef.current) return;
4459
- doneCalledRef.current = true;
4460
- onDone();
4461
- }, [onDone]);
4462
- react.useEffect(() => {
4463
- if (!effectiveAutoClose || effectiveAutoClose <= 0) return;
4464
- const intervalId = window.setInterval(() => {
4465
- setCountdown((prev) => {
4466
- if (prev <= 1) {
4467
- window.clearInterval(intervalId);
4468
- return 0;
4469
- }
4470
- return prev - 1;
4471
- });
4472
- }, 1e3);
4473
- return () => window.clearInterval(intervalId);
4474
- }, [effectiveAutoClose]);
4475
- react.useEffect(() => {
4476
- if (effectiveAutoClose && countdown === 0) {
4477
- handleDone();
4478
- }
4479
- }, [effectiveAutoClose, countdown, handleDone]);
4480
4494
  return /* @__PURE__ */ jsxRuntime.jsxs(
4481
4495
  ScreenLayout,
4482
4496
  {
4483
4497
  footer: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4484
- /* @__PURE__ */ jsxRuntime.jsx(PrimaryButton, { onClick: handleDone, children: succeeded ? "Done" : "Try again" }),
4485
- effectiveAutoClose != null && effectiveAutoClose > 0 && /* @__PURE__ */ jsxRuntime.jsxs("p", { style: countdownStyle(tokens.textMuted), children: [
4486
- "Returning to app in ",
4487
- countdown,
4488
- "s\u2026"
4489
- ] }),
4498
+ /* @__PURE__ */ jsxRuntime.jsx(PrimaryButton, { onClick: onDone, children: succeeded ? "Done" : "Try again" }),
4499
+ succeeded && onPreauthorize && /* @__PURE__ */ jsxRuntime.jsx(
4500
+ "button",
4501
+ {
4502
+ type: "button",
4503
+ onClick: onPreauthorize,
4504
+ style: preauthorizeStyle(tokens.accent, tokens.border),
4505
+ children: "Preauthorize future transfers"
4506
+ }
4507
+ ),
4490
4508
  onManageAccount && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: onManageAccount, style: manageStyle(tokens.textMuted), children: "Manage Blink account \u2192" }),
4491
4509
  /* @__PURE__ */ jsxRuntime.jsx(PoweredByFooter, {})
4492
4510
  ] }),
@@ -4611,11 +4629,18 @@ var upsellLinkStyle = (color) => ({
4611
4629
  fontFamily: "inherit",
4612
4630
  padding: 0
4613
4631
  });
4614
- var countdownStyle = (color) => ({
4615
- fontSize: "0.82rem",
4616
- color,
4617
- margin: "10px 0 0",
4618
- textAlign: "center"
4632
+ var preauthorizeStyle = (accentColor, borderColor) => ({
4633
+ width: "100%",
4634
+ padding: "14px 0",
4635
+ marginTop: 8,
4636
+ background: "transparent",
4637
+ border: `1px solid ${borderColor}`,
4638
+ borderRadius: 20,
4639
+ color: accentColor,
4640
+ fontWeight: 600,
4641
+ fontSize: "0.92rem",
4642
+ cursor: "pointer",
4643
+ fontFamily: "inherit"
4619
4644
  });
4620
4645
  var manageStyle = (color) => ({
4621
4646
  background: "transparent",
@@ -5812,7 +5837,6 @@ function StepRendererContent({
5812
5837
  merchantName,
5813
5838
  onBack,
5814
5839
  onDismiss,
5815
- autoCloseSeconds,
5816
5840
  depositAmount,
5817
5841
  handlers
5818
5842
  }) {
@@ -6089,7 +6113,7 @@ function StepRendererContent({
6089
6113
  })() : void 0,
6090
6114
  onDone: onDismiss ?? handlers.onNewPayment,
6091
6115
  onLogout: handlers.onLogout,
6092
- autoCloseSeconds
6116
+ onPreauthorize: state.isGuestFlow ? handlers.onPreauthorize : void 0
6093
6117
  }
6094
6118
  );
6095
6119
  }
@@ -6401,7 +6425,7 @@ function resolveRestoredMobileFlow(transferStatus, isSetup) {
6401
6425
  }
6402
6426
 
6403
6427
  // src/hooks/usePasskeyHandlers.ts
6404
- function usePasskeyHandlers(dispatch, apiBaseUrl, accounts, knownCredentialIds, mobileSetupFlowRef) {
6428
+ function usePasskeyHandlers(dispatch, apiBaseUrl, accounts, knownCredentialIds, mobileSetupFlowRef, guestPreauthAccountId) {
6405
6429
  const { user, getAccessToken } = reactAuth.usePrivy();
6406
6430
  const checkingPasskeyRef = react.useRef(false);
6407
6431
  const activateExistingCredential = react.useCallback(async (credentialId) => {
@@ -6426,8 +6450,11 @@ function usePasskeyHandlers(dispatch, apiBaseUrl, accounts, knownCredentialIds,
6426
6450
  const token = await getAccessToken();
6427
6451
  if (!token) throw new Error("Not authenticated");
6428
6452
  await registerPasskey(apiBaseUrl, token, credentialId, publicKey);
6429
- dispatch({ type: "PASSKEY_ACTIVATED", credentialId });
6453
+ dispatch({ type: "PASSKEY_ACTIVATED", credentialId, publicKey });
6430
6454
  window.localStorage.setItem(ACTIVE_CREDENTIAL_STORAGE_KEY, credentialId);
6455
+ if (guestPreauthAccountId) {
6456
+ return;
6457
+ }
6431
6458
  const resolved = resolvePostAuthStep({
6432
6459
  hasPasskey: true,
6433
6460
  accounts,
@@ -6437,7 +6464,7 @@ function usePasskeyHandlers(dispatch, apiBaseUrl, accounts, knownCredentialIds,
6437
6464
  });
6438
6465
  if (resolved.clearPersistedFlow) clearMobileFlowState();
6439
6466
  dispatch({ type: "NAVIGATE", step: resolved.step });
6440
- }, [getAccessToken, apiBaseUrl, accounts, mobileSetupFlowRef, dispatch]);
6467
+ }, [getAccessToken, apiBaseUrl, accounts, mobileSetupFlowRef, guestPreauthAccountId, dispatch]);
6441
6468
  const handleRegisterPasskey = react.useCallback(async () => {
6442
6469
  dispatch({ type: "SET_REGISTERING_PASSKEY", value: true });
6443
6470
  dispatch({ type: "SET_ERROR", error: null });
@@ -8274,6 +8301,77 @@ function usePaymentEffects(deps) {
8274
8301
  preOneTapSetupStepRef.current = null;
8275
8302
  }
8276
8303
  }, [pendingOneTapSetupAction, state.step, reloadAccounts, authExecutor, dispatch, oneTapLimitSavedDuringSetupRef]);
8304
+ react.useEffect(() => {
8305
+ if (state.step !== "success") return;
8306
+ if (!state.guestSessionToken) return;
8307
+ if (state.guestPreauthAccountId) return;
8308
+ let cancelled = false;
8309
+ const checkPreauth = async () => {
8310
+ try {
8311
+ const result = await fetchGuestPreauthAccount(apiBaseUrl, state.guestSessionToken);
8312
+ if (cancelled) return;
8313
+ if (result && !result.hasPasskey) {
8314
+ dispatch({ type: "GUEST_PREAUTH_DETECTED", accountId: result.accountId });
8315
+ }
8316
+ } catch {
8317
+ }
8318
+ };
8319
+ checkPreauth();
8320
+ return () => {
8321
+ cancelled = true;
8322
+ };
8323
+ }, [state.step, state.guestSessionToken, state.guestPreauthAccountId, apiBaseUrl, dispatch]);
8324
+ const claimingRef = react.useRef(false);
8325
+ react.useEffect(() => {
8326
+ if (!state.guestPreauthAccountId) return;
8327
+ if (!state.activeCredentialId) return;
8328
+ if (!state.activePublicKey) return;
8329
+ if (!authenticated) return;
8330
+ if (!state.guestSessionToken) return;
8331
+ if (claimingRef.current) return;
8332
+ claimingRef.current = true;
8333
+ let cancelled = false;
8334
+ const claimPreauth = async () => {
8335
+ try {
8336
+ const token = await getAccessTokenRef.current();
8337
+ if (!token || cancelled) return;
8338
+ await claimAccount(apiBaseUrl, token, state.guestPreauthAccountId, {
8339
+ guestToken: state.guestSessionToken,
8340
+ credentialId: state.activeCredentialId,
8341
+ publicKey: state.activePublicKey
8342
+ });
8343
+ if (cancelled) return;
8344
+ try {
8345
+ await reloadAccounts();
8346
+ } catch {
8347
+ }
8348
+ if (cancelled) return;
8349
+ dispatch({ type: "GUEST_PREAUTH_CLAIMED" });
8350
+ } catch (err) {
8351
+ if (cancelled) return;
8352
+ captureException(err);
8353
+ dispatch({
8354
+ type: "SET_ERROR",
8355
+ error: err instanceof Error ? err.message : "Failed to claim account"
8356
+ });
8357
+ } finally {
8358
+ claimingRef.current = false;
8359
+ }
8360
+ };
8361
+ claimPreauth();
8362
+ return () => {
8363
+ cancelled = true;
8364
+ };
8365
+ }, [
8366
+ state.guestPreauthAccountId,
8367
+ state.activeCredentialId,
8368
+ state.activePublicKey,
8369
+ state.guestSessionToken,
8370
+ authenticated,
8371
+ apiBaseUrl,
8372
+ dispatch,
8373
+ reloadAccounts
8374
+ ]);
8277
8375
  }
8278
8376
  function BlinkPayment(props) {
8279
8377
  const resetKey = react.useRef(0);
@@ -8291,8 +8389,7 @@ function BlinkPaymentInner({
8291
8389
  merchantAuthorization,
8292
8390
  merchantName,
8293
8391
  onBack,
8294
- onDismiss,
8295
- autoCloseSeconds
8392
+ onDismiss
8296
8393
  }) {
8297
8394
  const { apiBaseUrl, depositAmount } = useBlinkConfig();
8298
8395
  const { ready, authenticated, logout, getAccessToken } = reactAuth.usePrivy();
@@ -8324,7 +8421,8 @@ function BlinkPaymentInner({
8324
8421
  apiBaseUrl,
8325
8422
  state.accounts,
8326
8423
  state.knownCredentialIds,
8327
- mobileFlowRefs.mobileSetupFlowRef
8424
+ mobileFlowRefs.mobileSetupFlowRef,
8425
+ state.guestPreauthAccountId
8328
8426
  );
8329
8427
  const transfer = useTransferHandlers({
8330
8428
  dispatch,
@@ -8500,7 +8598,8 @@ function BlinkPaymentInner({
8500
8598
  onSelectAuthorizedToken: provider.handleSelectAuthorizedToken,
8501
8599
  onAuthorizeToken: provider.handleAuthorizeToken,
8502
8600
  onSelectGuestToken: guestTransfer.handleSelectGuestToken,
8503
- onLogin: () => dispatch({ type: "NAVIGATE", step: "login" })
8601
+ onLogin: () => dispatch({ type: "NAVIGATE", step: "login" }),
8602
+ onPreauthorize: () => dispatch({ type: "NAVIGATE", step: "login" })
8504
8603
  }), [
8505
8604
  auth,
8506
8605
  passkey,
@@ -8546,7 +8645,6 @@ function BlinkPaymentInner({
8546
8645
  merchantName,
8547
8646
  onBack,
8548
8647
  onDismiss,
8549
- autoCloseSeconds,
8550
8648
  depositAmount,
8551
8649
  handlers
8552
8650
  }