@swype-org/react-sdk 0.1.79 → 0.1.81

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
@@ -701,13 +701,17 @@ var POPUP_RESULT_TIMEOUT_MS = 12e4;
701
701
  var POPUP_CLOSED_POLL_MS = 500;
702
702
  function createPasskeyViaPopup(options) {
703
703
  return new Promise((resolve, reject) => {
704
- const encoded = btoa(JSON.stringify(options));
704
+ const channelId = `swype-pk-${Date.now()}-${Math.random().toString(36).slice(2)}`;
705
+ const payload = { ...options, channelId };
706
+ const encoded = btoa(JSON.stringify(payload));
705
707
  const popupUrl = `${window.location.origin}/passkey-register#${encoded}`;
706
708
  const popup = window.open(popupUrl, "swype-passkey");
707
709
  if (!popup) {
708
710
  reject(new Error("Pop-up blocked. Please allow pop-ups for this site and try again."));
709
711
  return;
710
712
  }
713
+ let settled = false;
714
+ const channel = typeof BroadcastChannel !== "undefined" ? new BroadcastChannel(channelId) : null;
711
715
  const timer = setTimeout(() => {
712
716
  cleanup();
713
717
  reject(new Error("Passkey creation timed out. Please try again."));
@@ -718,11 +722,11 @@ function createPasskeyViaPopup(options) {
718
722
  reject(new Error("Passkey setup window was closed before completing."));
719
723
  }
720
724
  }, POPUP_CLOSED_POLL_MS);
721
- const handler = (event) => {
722
- if (event.source !== popup) return;
723
- const data = event.data;
725
+ function handleResult(data) {
726
+ if (settled) return;
724
727
  if (!data || typeof data !== "object") return;
725
728
  if (data.type !== "swype:passkey-popup-result") return;
729
+ settled = true;
726
730
  cleanup();
727
731
  if (data.error) {
728
732
  reject(new Error(data.error));
@@ -731,13 +735,21 @@ function createPasskeyViaPopup(options) {
731
735
  } else {
732
736
  reject(new Error("Invalid passkey popup response."));
733
737
  }
738
+ }
739
+ if (channel) {
740
+ channel.onmessage = (event) => handleResult(event.data);
741
+ }
742
+ const postMessageHandler = (event) => {
743
+ if (event.source !== popup) return;
744
+ handleResult(event.data);
734
745
  };
746
+ window.addEventListener("message", postMessageHandler);
735
747
  function cleanup() {
736
748
  clearTimeout(timer);
737
749
  clearInterval(closedPoll);
738
- window.removeEventListener("message", handler);
750
+ window.removeEventListener("message", postMessageHandler);
751
+ channel?.close();
739
752
  }
740
- window.addEventListener("message", handler);
741
753
  });
742
754
  }
743
755
 
@@ -3247,12 +3259,15 @@ function DepositScreen({
3247
3259
  onChangeSource,
3248
3260
  onSwitchWallet,
3249
3261
  onBack,
3250
- onLogout
3262
+ onLogout,
3263
+ onIncreaseLimit,
3264
+ increasingLimit
3251
3265
  }) {
3252
3266
  const { tokens } = useSwypeConfig();
3253
3267
  const amount = initialAmount;
3254
3268
  const isLowBalance = availableBalance < MIN_DEPOSIT;
3255
- const canDeposit = amount >= MIN_DEPOSIT && amount <= remainingLimit && !isLowBalance && !processing;
3269
+ const exceedsLimit = amount > remainingLimit && !isLowBalance;
3270
+ const canDeposit = amount >= MIN_DEPOSIT && !exceedsLimit && !isLowBalance && !processing;
3256
3271
  const headerTitle = merchantName ? `Deposit to ${merchantName}` : "Deposit";
3257
3272
  if (isLowBalance) {
3258
3273
  return /* @__PURE__ */ jsxRuntime.jsxs(
@@ -3310,11 +3325,22 @@ function DepositScreen({
3310
3325
  ScreenLayout,
3311
3326
  {
3312
3327
  footer: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3313
- /* @__PURE__ */ jsxRuntime.jsxs(PrimaryButton, { onClick: () => onDeposit(amount), disabled: !canDeposit, loading: processing, children: [
3314
- "Deposit $",
3315
- amount.toFixed(2)
3328
+ exceedsLimit && onIncreaseLimit ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3329
+ /* @__PURE__ */ jsxRuntime.jsx(PrimaryButton, { onClick: onIncreaseLimit, loading: increasingLimit, children: "Increase limit" }),
3330
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { style: limitExceededHintStyle(tokens.warning), children: [
3331
+ "Your deposit of $",
3332
+ amount.toFixed(2),
3333
+ " exceeds your One-Tap limit of $",
3334
+ remainingLimit.toFixed(2),
3335
+ ". Increase your limit to continue."
3336
+ ] })
3337
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3338
+ /* @__PURE__ */ jsxRuntime.jsxs(PrimaryButton, { onClick: () => onDeposit(amount), disabled: !canDeposit, loading: processing, children: [
3339
+ "Deposit $",
3340
+ amount.toFixed(2)
3341
+ ] }),
3342
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: noApprovalStyle(tokens.textMuted), children: "No approval needed \xB7 within your One-Tap limit" })
3316
3343
  ] }),
3317
- /* @__PURE__ */ jsxRuntime.jsx("p", { style: noApprovalStyle(tokens.textMuted), children: "No approval needed \xB7 within your One-Tap limit" }),
3318
3344
  /* @__PURE__ */ jsxRuntime.jsxs("p", { style: routeStyle(tokens.textMuted), children: [
3319
3345
  "From ",
3320
3346
  sourceName,
@@ -3462,6 +3488,13 @@ var noApprovalStyle = (color) => ({
3462
3488
  color,
3463
3489
  margin: "12px 0 2px"
3464
3490
  });
3491
+ var limitExceededHintStyle = (color) => ({
3492
+ textAlign: "center",
3493
+ fontSize: "0.78rem",
3494
+ color,
3495
+ margin: "12px 0 2px",
3496
+ lineHeight: 1.5
3497
+ });
3465
3498
  var routeStyle = (color) => ({
3466
3499
  textAlign: "center",
3467
3500
  fontSize: "0.75rem",
@@ -5210,6 +5243,81 @@ function SwypePaymentInner({
5210
5243
  merchantAuthorization,
5211
5244
  transfer
5212
5245
  ]);
5246
+ const [increasingLimit, setIncreasingLimit] = react.useState(false);
5247
+ const handleIncreaseLimit = react.useCallback(async () => {
5248
+ const parsedAmount = depositAmount ?? 5;
5249
+ if (!sourceId) {
5250
+ setError("No account or provider selected.");
5251
+ return;
5252
+ }
5253
+ if (!activeCredentialId) {
5254
+ setError("Create a passkey on this device before continuing.");
5255
+ setStep("create-passkey");
5256
+ return;
5257
+ }
5258
+ setError(null);
5259
+ setIncreasingLimit(true);
5260
+ try {
5261
+ const token = await getAccessToken();
5262
+ if (!token) throw new Error("Not authenticated");
5263
+ let effectiveSourceType = sourceType;
5264
+ let effectiveSourceId = sourceId;
5265
+ if (effectiveSourceType === "accountId") {
5266
+ const acct = accounts.find((a) => a.id === effectiveSourceId);
5267
+ const activeWallet = acct?.wallets.find((w) => w.status === "ACTIVE");
5268
+ if (activeWallet) {
5269
+ effectiveSourceType = "walletId";
5270
+ effectiveSourceId = activeWallet.id;
5271
+ }
5272
+ }
5273
+ const t = await createTransfer(apiBaseUrl, token, {
5274
+ id: idempotencyKey,
5275
+ credentialId: activeCredentialId,
5276
+ merchantAuthorization,
5277
+ sourceType: effectiveSourceType,
5278
+ sourceId: effectiveSourceId,
5279
+ destination,
5280
+ amount: parsedAmount
5281
+ });
5282
+ setTransfer(t);
5283
+ if (t.authorizationSessions && t.authorizationSessions.length > 0) {
5284
+ const uri = t.authorizationSessions[0].uri;
5285
+ setMobileFlow(true);
5286
+ pollingTransferIdRef.current = t.id;
5287
+ mobileSetupFlowRef.current = true;
5288
+ handlingMobileReturnRef.current = false;
5289
+ polling.startPolling(t.id);
5290
+ setDeeplinkUri(uri);
5291
+ persistMobileFlowState({
5292
+ transferId: t.id,
5293
+ deeplinkUri: uri,
5294
+ providerId: selectedProviderId,
5295
+ isSetup: true
5296
+ });
5297
+ triggerDeeplink(uri);
5298
+ }
5299
+ } catch (err) {
5300
+ const msg = err instanceof Error ? err.message : "Failed to increase limit";
5301
+ setError(msg);
5302
+ onError?.(msg);
5303
+ } finally {
5304
+ setIncreasingLimit(false);
5305
+ }
5306
+ }, [
5307
+ depositAmount,
5308
+ sourceId,
5309
+ sourceType,
5310
+ activeCredentialId,
5311
+ apiBaseUrl,
5312
+ getAccessToken,
5313
+ accounts,
5314
+ polling,
5315
+ onError,
5316
+ idempotencyKey,
5317
+ merchantAuthorization,
5318
+ destination,
5319
+ selectedProviderId
5320
+ ]);
5213
5321
  const completePasskeyRegistration = react.useCallback(async (credentialId, publicKey) => {
5214
5322
  const token = await getAccessToken();
5215
5323
  if (!token) throw new Error("Not authenticated");
@@ -5471,7 +5579,9 @@ function SwypePaymentInner({
5471
5579
  onChangeSource: () => setStep("wallet-picker"),
5472
5580
  onSwitchWallet: () => setStep("wallet-picker"),
5473
5581
  onBack: onBack ?? (() => handleLogout()),
5474
- onLogout: handleLogout
5582
+ onLogout: handleLogout,
5583
+ onIncreaseLimit: handleIncreaseLimit,
5584
+ increasingLimit
5475
5585
  }
5476
5586
  );
5477
5587
  }