@swype-org/react-sdk 0.1.32 → 0.1.33

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
@@ -1,5 +1,5 @@
1
1
  import { createContext, useRef, useState, useCallback, useMemo, useContext, useEffect } from 'react';
2
- import { PrivyProvider, usePrivy, useLoginWithEmail, useLoginWithSms } from '@privy-io/react-auth';
2
+ import { PrivyProvider, usePrivy, useLoginWithEmail, useLoginWithSms, useLoginWithOAuth } from '@privy-io/react-auth';
3
3
  import { createConfig, http, WagmiProvider, useConfig, useConnect, useSwitchChain } from 'wagmi';
4
4
  import { mainnet, arbitrum, base } from 'wagmi/chains';
5
5
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
@@ -1448,8 +1448,20 @@ function hasProcessingTimedOut(processingStartedAtMs, nowMs) {
1448
1448
  if (!processingStartedAtMs) return false;
1449
1449
  return nowMs - processingStartedAtMs >= PROCESSING_TIMEOUT_MS;
1450
1450
  }
1451
+ var STATUS_DISPLAY_LABELS = {
1452
+ CREATED: "created",
1453
+ AUTHORIZED: "authorized",
1454
+ SENDING: "sending",
1455
+ SENT: "confirming delivery",
1456
+ COMPLETED: "completed",
1457
+ FAILED: "failed"
1458
+ };
1459
+ function getStatusDisplayLabel(status) {
1460
+ return STATUS_DISPLAY_LABELS[status] ?? status;
1461
+ }
1451
1462
  function buildProcessingTimeoutMessage(status) {
1452
- return `Payment is taking longer than expected (status: ${status}). Please try again.`;
1463
+ const label = getStatusDisplayLabel(status);
1464
+ return `Payment is taking longer than expected (status: ${label}). Please try again.`;
1453
1465
  }
1454
1466
 
1455
1467
  // src/walletFlow.ts
@@ -2115,34 +2127,50 @@ function LoginScreen({
2115
2127
  onSubmit,
2116
2128
  sending,
2117
2129
  error,
2118
- onBack
2130
+ onBack,
2131
+ merchantInitials,
2132
+ onSocialLogin
2119
2133
  }) {
2120
2134
  const { tokens } = useSwypeConfig();
2121
2135
  const disabled = authInput.trim().length === 0 || sending;
2122
- const walletLogos = ["MM", "R", "O", "P", "+"];
2123
2136
  return /* @__PURE__ */ jsxs(
2124
2137
  ScreenLayout,
2125
2138
  {
2126
2139
  footer: /* @__PURE__ */ jsxs(Fragment, { children: [
2127
2140
  /* @__PURE__ */ jsx(PrimaryButton, { onClick: onSubmit, disabled, loading: sending, children: "Continue" }),
2128
- /* @__PURE__ */ jsxs("div", { style: dividerStyle(tokens), children: [
2129
- /* @__PURE__ */ jsx("div", { style: dividerLineStyle(tokens.border) }),
2130
- /* @__PURE__ */ jsx("span", { children: "works with" }),
2131
- /* @__PURE__ */ jsx("div", { style: dividerLineStyle(tokens.border) })
2141
+ onSocialLogin && /* @__PURE__ */ jsxs(Fragment, { children: [
2142
+ /* @__PURE__ */ jsxs("div", { style: dividerStyle(tokens), children: [
2143
+ /* @__PURE__ */ jsx("div", { style: dividerLineStyle(tokens.border) }),
2144
+ /* @__PURE__ */ jsx("span", { children: "or continue with" }),
2145
+ /* @__PURE__ */ jsx("div", { style: dividerLineStyle(tokens.border) })
2146
+ ] }),
2147
+ /* @__PURE__ */ jsx("div", { style: socialRowStyle, children: ["google", "apple", "twitter"].map((provider) => /* @__PURE__ */ jsx(
2148
+ "button",
2149
+ {
2150
+ type: "button",
2151
+ onClick: () => onSocialLogin(provider),
2152
+ style: socialButtonStyle(tokens),
2153
+ children: socialLabel(provider)
2154
+ },
2155
+ provider
2156
+ )) })
2157
+ ] }),
2158
+ /* @__PURE__ */ jsxs("div", { style: walletSectionStyle, children: [
2159
+ /* @__PURE__ */ jsx("span", { style: walletLabelStyle(tokens.textMuted), children: "Works with" }),
2160
+ /* @__PURE__ */ jsx("div", { style: walletLogosStyle, children: walletIcons.map(({ key, emoji }) => /* @__PURE__ */ jsx("span", { style: walletEmojiStyle, children: emoji }, key)) })
2132
2161
  ] }),
2133
- /* @__PURE__ */ jsx("div", { style: logosRowStyle, children: walletLogos.map((label) => /* @__PURE__ */ jsx("div", { style: logoCircleStyle(tokens), children: label }, label)) }),
2134
2162
  /* @__PURE__ */ jsx(PoweredByFooter, {})
2135
2163
  ] }),
2136
2164
  children: [
2137
- /* @__PURE__ */ jsx(ScreenHeader, { onBack }),
2165
+ /* @__PURE__ */ jsx(
2166
+ ScreenHeader,
2167
+ {
2168
+ onBack,
2169
+ right: merchantInitials ? /* @__PURE__ */ jsx("div", { style: avatarStyle(tokens), children: merchantInitials }) : void 0
2170
+ }
2171
+ ),
2138
2172
  /* @__PURE__ */ jsxs("div", { style: contentStyle, children: [
2139
- /* @__PURE__ */ jsx(IconCircle, { variant: "accent", size: 56, children: /* @__PURE__ */ jsx("svg", { width: "28", height: "28", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx(
2140
- "path",
2141
- {
2142
- d: "M12 1L3 5v6c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12V5l-9-4z",
2143
- fill: tokens.accent
2144
- }
2145
- ) }) }),
2173
+ /* @__PURE__ */ jsx("div", { style: iconBoxStyle(tokens.accent), children: /* @__PURE__ */ jsx("span", { style: iconLetterStyle, children: "S" }) }),
2146
2174
  /* @__PURE__ */ jsx("h2", { style: headingStyle(tokens.text), children: "One-time setup.\nOne-tap deposits after." }),
2147
2175
  /* @__PURE__ */ jsx("p", { style: subtitleStyle(tokens.textSecondary), children: "Protected by Face ID." }),
2148
2176
  error && /* @__PURE__ */ jsx("div", { style: errorStyle(tokens), children: error }),
@@ -2167,6 +2195,23 @@ function LoginScreen({
2167
2195
  }
2168
2196
  );
2169
2197
  }
2198
+ var walletIcons = [
2199
+ { key: "metamask", emoji: "\u{1F98A}" },
2200
+ { key: "rabby", emoji: "\u{1F430}" },
2201
+ { key: "phantom", emoji: "\u25C6" },
2202
+ { key: "rainbow", emoji: "\u{1F439}" },
2203
+ { key: "coinbase", emoji: "\u{1F535}" }
2204
+ ];
2205
+ function socialLabel(provider) {
2206
+ switch (provider) {
2207
+ case "google":
2208
+ return "Google";
2209
+ case "apple":
2210
+ return "Apple";
2211
+ case "twitter":
2212
+ return "X";
2213
+ }
2214
+ }
2170
2215
  var contentStyle = {
2171
2216
  textAlign: "center",
2172
2217
  flex: 1,
@@ -2175,10 +2220,25 @@ var contentStyle = {
2175
2220
  alignItems: "center",
2176
2221
  paddingTop: 24
2177
2222
  };
2223
+ var iconBoxStyle = (accent) => ({
2224
+ width: 56,
2225
+ height: 56,
2226
+ borderRadius: 16,
2227
+ background: accent,
2228
+ display: "flex",
2229
+ alignItems: "center",
2230
+ justifyContent: "center"
2231
+ });
2232
+ var iconLetterStyle = {
2233
+ color: "#fff",
2234
+ fontSize: "1.5rem",
2235
+ fontWeight: 700,
2236
+ lineHeight: 1
2237
+ };
2178
2238
  var headingStyle = (color) => ({
2179
- fontSize: "1.65rem",
2239
+ fontSize: "1.45rem",
2180
2240
  fontWeight: 700,
2181
- lineHeight: 1.2,
2241
+ lineHeight: 1.25,
2182
2242
  letterSpacing: "-0.02em",
2183
2243
  color,
2184
2244
  margin: "20px 0 8px",
@@ -2227,24 +2287,55 @@ var dividerLineStyle = (color) => ({
2227
2287
  height: 1,
2228
2288
  background: color
2229
2289
  });
2230
- var logosRowStyle = {
2290
+ var socialRowStyle = {
2291
+ display: "flex",
2292
+ gap: 10,
2293
+ marginBottom: 20
2294
+ };
2295
+ var socialButtonStyle = (tokens) => ({
2296
+ flex: 1,
2297
+ padding: "12px 0",
2298
+ borderRadius: 12,
2299
+ border: `1px solid ${tokens.border}`,
2300
+ background: "transparent",
2301
+ color: tokens.text,
2302
+ fontSize: "0.88rem",
2303
+ fontWeight: 600,
2304
+ fontFamily: "inherit",
2305
+ cursor: "pointer"
2306
+ });
2307
+ var walletSectionStyle = {
2308
+ textAlign: "center",
2309
+ marginBottom: 8,
2310
+ marginTop: 4
2311
+ };
2312
+ var walletLabelStyle = (color) => ({
2313
+ fontSize: "0.78rem",
2314
+ color,
2315
+ display: "block",
2316
+ marginBottom: 10
2317
+ });
2318
+ var walletLogosStyle = {
2231
2319
  display: "flex",
2232
2320
  justifyContent: "center",
2233
- gap: 12,
2234
- marginBottom: 8
2321
+ gap: 16
2235
2322
  };
2236
- var logoCircleStyle = (tokens) => ({
2237
- width: 34,
2238
- height: 34,
2239
- borderRadius: 999,
2323
+ var walletEmojiStyle = {
2324
+ fontSize: "1.4rem",
2325
+ lineHeight: 1
2326
+ };
2327
+ var avatarStyle = (tokens) => ({
2328
+ width: 28,
2329
+ height: 28,
2330
+ borderRadius: "50%",
2240
2331
  border: `1px solid ${tokens.border}`,
2241
- background: tokens.bgInput,
2242
- color: tokens.textMuted,
2243
2332
  display: "flex",
2244
2333
  alignItems: "center",
2245
2334
  justifyContent: "center",
2246
- fontSize: "0.72rem",
2247
- fontWeight: 600
2335
+ fontSize: "0.6rem",
2336
+ fontWeight: 700,
2337
+ color: tokens.textMuted,
2338
+ background: "transparent"
2248
2339
  });
2249
2340
  var RESEND_COOLDOWN_SECONDS = 30;
2250
2341
  function OtpVerifyScreen({
@@ -2896,7 +2987,7 @@ var swipeHintStyle = (color) => ({
2896
2987
  color,
2897
2988
  margin: "12px 0 0"
2898
2989
  });
2899
- var MIN_DEPOSIT = 1;
2990
+ var MIN_DEPOSIT = 0.25;
2900
2991
  function DepositScreen({
2901
2992
  merchantName,
2902
2993
  sourceName,
@@ -3037,7 +3128,7 @@ function DepositScreen({
3037
3128
  min: MIN_DEPOSIT,
3038
3129
  max: sliderMax > MIN_DEPOSIT ? sliderMax : 20,
3039
3130
  step: 0.5,
3040
- ticks: [MIN_DEPOSIT, 5, 10, 20].filter((t) => t <= sliderMax || t <= 20),
3131
+ ticks: [MIN_DEPOSIT, 1, 5, 10, 20].filter((t) => t <= sliderMax || t <= 20),
3041
3132
  onChange: setAmount
3042
3133
  }
3043
3134
  ),
@@ -3049,13 +3140,13 @@ function DepositScreen({
3049
3140
  remainingLimit.toFixed(2)
3050
3141
  ] })
3051
3142
  ] }),
3052
- estimatedFeeUsd != null && estimatedFeePct != null && /* @__PURE__ */ jsxs("div", { style: detailRowStyle(tokens.textMuted), children: [
3143
+ estimatedFeeUsd != null && estimatedFeePct != null ? /* @__PURE__ */ jsxs("div", { style: detailRowStyle(tokens.textMuted), children: [
3053
3144
  "Fee: ~$",
3054
3145
  estimatedFeeUsd.toFixed(2),
3055
3146
  " (",
3056
3147
  estimatedFeePct.toFixed(1),
3057
3148
  "%)"
3058
- ] })
3149
+ ] }) : /* @__PURE__ */ jsx("div", { style: detailRowStyle(tokens.textMuted), children: "Fees calculated at time of transfer" })
3059
3150
  ] }),
3060
3151
  error && /* @__PURE__ */ jsx("div", { style: errorBannerStyle5(tokens), children: error })
3061
3152
  ]
@@ -3401,6 +3492,7 @@ function SwypePayment({
3401
3492
  loginWithCode: loginWithSmsCode,
3402
3493
  state: smsLoginState
3403
3494
  } = useLoginWithSms();
3495
+ const { initOAuth } = useLoginWithOAuth();
3404
3496
  const [step, setStep] = useState("login");
3405
3497
  const [error, setError] = useState(null);
3406
3498
  const [providers, setProviders] = useState([]);
@@ -3449,6 +3541,14 @@ function SwypePayment({
3449
3541
  setVerificationTarget(null);
3450
3542
  setOtpCode("");
3451
3543
  }, []);
3544
+ const handleSocialLogin = useCallback(async (provider) => {
3545
+ setError(null);
3546
+ try {
3547
+ await initOAuth({ provider });
3548
+ } catch (err) {
3549
+ setError(err instanceof Error ? err.message : "Social login failed");
3550
+ }
3551
+ }, [initOAuth]);
3452
3552
  const activeOtpStatus = verificationTarget?.kind === "email" ? emailLoginState.status : verificationTarget?.kind === "phone" ? smsLoginState.status : "initial";
3453
3553
  const activeOtpErrorMessage = verificationTarget?.kind === "email" && emailLoginState.status === "error" ? emailLoginState.error?.message ?? "Failed to continue with email." : verificationTarget?.kind === "phone" && smsLoginState.status === "error" ? smsLoginState.error?.message ?? "Failed to continue with phone number." : null;
3454
3554
  useEffect(() => {
@@ -3517,6 +3617,9 @@ function SwypePayment({
3517
3617
  if (!token || cancelled) return;
3518
3618
  const { config } = await fetchUserConfig(apiBaseUrl, token);
3519
3619
  if (cancelled) return;
3620
+ if (config.defaultAllowance != null) {
3621
+ setOneTapLimit(config.defaultAllowance);
3622
+ }
3520
3623
  const allPasskeys = config.passkeys ?? (config.passkey ? [config.passkey] : []);
3521
3624
  if (allPasskeys.length === 0) {
3522
3625
  setStep("create-passkey");
@@ -3876,6 +3979,7 @@ function SwypePayment({
3876
3979
  }
3877
3980
  const setupAmount = depositAmount ?? MIN_SEND_AMOUNT_USD;
3878
3981
  const t = await createTransfer(apiBaseUrl, token, {
3982
+ id: idempotencyKey,
3879
3983
  credentialId: activeCredentialId ?? "",
3880
3984
  merchantAuthorization,
3881
3985
  sourceType,
@@ -3904,6 +4008,7 @@ function SwypePayment({
3904
4008
  }
3905
4009
  }, [
3906
4010
  getAccessToken,
4011
+ idempotencyKey,
3907
4012
  sourceId,
3908
4013
  sourceType,
3909
4014
  activeCredentialId,
@@ -3974,7 +4079,9 @@ function SwypePayment({
3974
4079
  onSubmit: handleSendLoginCode,
3975
4080
  sending: activeOtpStatus === "sending-code",
3976
4081
  error,
3977
- onBack
4082
+ onBack,
4083
+ merchantInitials: merchantName ? merchantName.slice(0, 2).toUpperCase() : void 0,
4084
+ onSocialLogin: handleSocialLogin
3978
4085
  }
3979
4086
  );
3980
4087
  }
@@ -4069,8 +4176,6 @@ function SwypePayment({
4069
4176
  remainingLimit: oneTapLimit,
4070
4177
  tokenCount,
4071
4178
  initialAmount: parsedAmt,
4072
- estimatedFeePct: 0.6,
4073
- estimatedFeeUsd: parsedAmt * 6e-3,
4074
4179
  processing: creatingTransfer,
4075
4180
  error,
4076
4181
  onDeposit: handlePay,
@@ -4083,7 +4188,8 @@ function SwypePayment({
4083
4188
  }
4084
4189
  if (step === "processing") {
4085
4190
  const currentActionType = authExecutor.currentAction?.type;
4086
- const statusLabel = creatingTransfer ? "Creating Transfer" : mobileFlow ? "Waiting for Authorization" : authExecutor.executing ? currentActionType?.replace(/_/g, " ") ?? "Authorizing" : transferSigning.signing ? "Sending transfer" : polling.isPolling ? "Transfer Sent" : "Please wait...";
4191
+ const polledStatus = polling.transfer?.status;
4192
+ const statusLabel = creatingTransfer ? "Creating Transfer" : mobileFlow ? "Waiting for Authorization" : authExecutor.executing ? currentActionType?.replace(/_/g, " ") ?? "Authorizing" : transferSigning.signing ? "Sending transfer" : polledStatus === "SENDING" ? "Sending transfer..." : polledStatus === "SENT" ? "Confirming delivery..." : polling.isPolling ? "Transfer Sent" : "Please wait...";
4087
4193
  return /* @__PURE__ */ jsx(ScreenLayout, { children: /* @__PURE__ */ jsxs("div", { style: { textAlign: "center", padding: "48px 0", flex: 1, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center" }, children: [
4088
4194
  /* @__PURE__ */ jsx(Spinner, { size: 48 }),
4089
4195
  /* @__PURE__ */ jsx("h2", { style: { fontSize: "1.4rem", fontWeight: 700, color: tokens.text, marginTop: 20, marginBottom: 8 }, children: statusLabel }),