@swype-org/react-sdk 0.1.27 → 0.1.29
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 +392 -84
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +105 -75
- package/dist/index.d.ts +105 -75
- package/dist/index.js +394 -87
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -28,9 +28,9 @@ var darkTheme = {
|
|
|
28
28
|
textMuted: "#7fa4b0",
|
|
29
29
|
textInverse: "#052027",
|
|
30
30
|
border: "#2b4551",
|
|
31
|
-
borderFocus: "#
|
|
32
|
-
accent: "#
|
|
33
|
-
accentHover: "#
|
|
31
|
+
borderFocus: "#28b67a",
|
|
32
|
+
accent: "#28b67a",
|
|
33
|
+
accentHover: "#219866",
|
|
34
34
|
accentText: "#ffffff",
|
|
35
35
|
success: "#0f9d73",
|
|
36
36
|
successBg: "#0f2f2a",
|
|
@@ -52,9 +52,9 @@ var lightTheme = {
|
|
|
52
52
|
textMuted: "#7d97a1",
|
|
53
53
|
textInverse: "#ffffff",
|
|
54
54
|
border: "#d2e4ea",
|
|
55
|
-
borderFocus: "#
|
|
56
|
-
accent: "#
|
|
57
|
-
accentHover: "#
|
|
55
|
+
borderFocus: "#28b67a",
|
|
56
|
+
accent: "#28b67a",
|
|
57
|
+
accentHover: "#219866",
|
|
58
58
|
accentText: "#ffffff",
|
|
59
59
|
success: "#0f9d73",
|
|
60
60
|
successBg: "#e6f7f1",
|
|
@@ -77,26 +77,6 @@ var wagmiConfig = wagmi.createConfig({
|
|
|
77
77
|
[chains.base.id]: wagmi.http()
|
|
78
78
|
}
|
|
79
79
|
});
|
|
80
|
-
var PRIVY_MODAL_CENTER_CSS = `
|
|
81
|
-
@media (max-width: 440px) {
|
|
82
|
-
#privy-dialog [data-headlessui-state] {
|
|
83
|
-
position: static !important;
|
|
84
|
-
bottom: auto !important;
|
|
85
|
-
margin: auto !important;
|
|
86
|
-
width: 360px !important;
|
|
87
|
-
max-width: calc(100vw - 32px) !important;
|
|
88
|
-
box-shadow: 0px 8px 36px rgba(55, 65, 81, 0.15) !important;
|
|
89
|
-
border-radius: var(--privy-border-radius-lg) !important;
|
|
90
|
-
transform: none !important;
|
|
91
|
-
transition: opacity 100ms ease-in !important;
|
|
92
|
-
}
|
|
93
|
-
#privy-dialog [data-headlessui-state].entering,
|
|
94
|
-
#privy-dialog [data-headlessui-state].leaving {
|
|
95
|
-
opacity: 0 !important;
|
|
96
|
-
transform: none !important;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
`;
|
|
100
80
|
var SwypeContext = react.createContext(null);
|
|
101
81
|
function SwypeProvider({
|
|
102
82
|
apiBaseUrl,
|
|
@@ -107,15 +87,6 @@ function SwypeProvider({
|
|
|
107
87
|
if (!queryClientRef.current) {
|
|
108
88
|
queryClientRef.current = new reactQuery.QueryClient();
|
|
109
89
|
}
|
|
110
|
-
react.useEffect(() => {
|
|
111
|
-
const style = document.createElement("style");
|
|
112
|
-
style.setAttribute("data-swype", "privy-modal-center");
|
|
113
|
-
style.textContent = PRIVY_MODAL_CENTER_CSS;
|
|
114
|
-
document.head.appendChild(style);
|
|
115
|
-
return () => {
|
|
116
|
-
style.remove();
|
|
117
|
-
};
|
|
118
|
-
}, []);
|
|
119
90
|
const [depositAmount, setDepositAmountRaw] = react.useState(null);
|
|
120
91
|
const setDepositAmount = react.useCallback((amount) => {
|
|
121
92
|
setDepositAmountRaw(amount);
|
|
@@ -138,6 +109,12 @@ function SwypeProvider({
|
|
|
138
109
|
appearance: {
|
|
139
110
|
theme,
|
|
140
111
|
accentColor: getTheme(theme).accent
|
|
112
|
+
},
|
|
113
|
+
intl: {
|
|
114
|
+
defaultCountry: "US"
|
|
115
|
+
},
|
|
116
|
+
embeddedWallets: {
|
|
117
|
+
showWalletUIs: false
|
|
141
118
|
}
|
|
142
119
|
},
|
|
143
120
|
children: /* @__PURE__ */ jsxRuntime.jsx(SwypeContext.Provider, { value, children })
|
|
@@ -176,6 +153,7 @@ __export(api_exports, {
|
|
|
176
153
|
fetchAccounts: () => fetchAccounts,
|
|
177
154
|
fetchAuthorizationSession: () => fetchAuthorizationSession,
|
|
178
155
|
fetchChains: () => fetchChains,
|
|
156
|
+
fetchMerchantPublicKey: () => fetchMerchantPublicKey,
|
|
179
157
|
fetchProviders: () => fetchProviders,
|
|
180
158
|
fetchTransfer: () => fetchTransfer,
|
|
181
159
|
fetchUserConfig: () => fetchUserConfig,
|
|
@@ -218,9 +196,13 @@ async function fetchAccounts(apiBaseUrl, token, credentialId) {
|
|
|
218
196
|
return data.items;
|
|
219
197
|
}
|
|
220
198
|
async function createTransfer(apiBaseUrl, token, params) {
|
|
199
|
+
if (!params.merchantAuthorization) {
|
|
200
|
+
throw new Error("merchantAuthorization is required for transfer creation.");
|
|
201
|
+
}
|
|
221
202
|
const body = {
|
|
222
|
-
id: crypto.randomUUID(),
|
|
203
|
+
id: params.id ?? crypto.randomUUID(),
|
|
223
204
|
credentialId: params.credentialId,
|
|
205
|
+
merchantAuthorization: params.merchantAuthorization,
|
|
224
206
|
sources: [{ [params.sourceType]: params.sourceId }],
|
|
225
207
|
destinations: [
|
|
226
208
|
{
|
|
@@ -245,6 +227,13 @@ async function createTransfer(apiBaseUrl, token, params) {
|
|
|
245
227
|
if (!res.ok) await throwApiError(res);
|
|
246
228
|
return await res.json();
|
|
247
229
|
}
|
|
230
|
+
async function fetchMerchantPublicKey(apiBaseUrl, merchantId) {
|
|
231
|
+
const res = await fetch(
|
|
232
|
+
`${apiBaseUrl}/v1/merchants/${encodeURIComponent(merchantId)}/public-key`
|
|
233
|
+
);
|
|
234
|
+
if (!res.ok) await throwApiError(res);
|
|
235
|
+
return await res.json();
|
|
236
|
+
}
|
|
248
237
|
async function fetchTransfer(apiBaseUrl, token, transferId, authorizationSessionToken) {
|
|
249
238
|
if (!token && !authorizationSessionToken) {
|
|
250
239
|
throw new Error("Missing auth credentials for transfer fetch.");
|
|
@@ -816,6 +805,11 @@ async function createPasskeyCredential(params) {
|
|
|
816
805
|
};
|
|
817
806
|
}
|
|
818
807
|
async function deviceHasPasskey(credentialId) {
|
|
808
|
+
const found = await findDevicePasskey([credentialId]);
|
|
809
|
+
return found != null;
|
|
810
|
+
}
|
|
811
|
+
async function findDevicePasskey(credentialIds) {
|
|
812
|
+
if (credentialIds.length === 0) return null;
|
|
819
813
|
try {
|
|
820
814
|
const challenge = new Uint8Array(32);
|
|
821
815
|
crypto.getRandomValues(challenge);
|
|
@@ -824,17 +818,18 @@ async function deviceHasPasskey(credentialId) {
|
|
|
824
818
|
publicKey: {
|
|
825
819
|
challenge,
|
|
826
820
|
rpId: resolvePasskeyRpId(),
|
|
827
|
-
allowCredentials:
|
|
821
|
+
allowCredentials: credentialIds.map((id) => ({
|
|
828
822
|
type: "public-key",
|
|
829
|
-
id: base64ToBytes(
|
|
830
|
-
}
|
|
823
|
+
id: base64ToBytes(id)
|
|
824
|
+
})),
|
|
831
825
|
userVerification: "discouraged",
|
|
832
826
|
timeout: 3e4
|
|
833
827
|
}
|
|
834
828
|
});
|
|
835
|
-
|
|
829
|
+
if (!assertion) return null;
|
|
830
|
+
return toBase64(assertion.rawId);
|
|
836
831
|
} catch {
|
|
837
|
-
return
|
|
832
|
+
return null;
|
|
838
833
|
}
|
|
839
834
|
}
|
|
840
835
|
function useTransferPolling(intervalMs = 3e3) {
|
|
@@ -2094,6 +2089,46 @@ function AdvancedSettings({
|
|
|
2094
2089
|
] });
|
|
2095
2090
|
}
|
|
2096
2091
|
|
|
2092
|
+
// src/auth.ts
|
|
2093
|
+
var EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
2094
|
+
var PHONE_DIGIT_PATTERN = /^\d{7,15}$/;
|
|
2095
|
+
function normalizePhoneNumber(rawValue) {
|
|
2096
|
+
const trimmed = rawValue.trim();
|
|
2097
|
+
if (!trimmed) return null;
|
|
2098
|
+
const hasExplicitCountryCode = trimmed.startsWith("+");
|
|
2099
|
+
const digits = trimmed.replace(/\D/g, "");
|
|
2100
|
+
if (!PHONE_DIGIT_PATTERN.test(digits)) return null;
|
|
2101
|
+
return hasExplicitCountryCode ? `+${digits}` : digits;
|
|
2102
|
+
}
|
|
2103
|
+
function normalizeAuthIdentifier(rawValue) {
|
|
2104
|
+
const trimmed = rawValue.trim();
|
|
2105
|
+
if (!trimmed) return null;
|
|
2106
|
+
if (EMAIL_PATTERN.test(trimmed)) {
|
|
2107
|
+
return {
|
|
2108
|
+
kind: "email",
|
|
2109
|
+
value: trimmed.toLowerCase()
|
|
2110
|
+
};
|
|
2111
|
+
}
|
|
2112
|
+
const normalizedPhoneNumber = normalizePhoneNumber(trimmed);
|
|
2113
|
+
if (normalizedPhoneNumber) {
|
|
2114
|
+
return {
|
|
2115
|
+
kind: "phone",
|
|
2116
|
+
value: normalizedPhoneNumber
|
|
2117
|
+
};
|
|
2118
|
+
}
|
|
2119
|
+
return null;
|
|
2120
|
+
}
|
|
2121
|
+
function maskAuthIdentifier(identifier) {
|
|
2122
|
+
if (identifier.kind === "email") {
|
|
2123
|
+
const [localPart, domain = ""] = identifier.value.split("@");
|
|
2124
|
+
const localPrefix = localPart.slice(0, 2);
|
|
2125
|
+
return `${localPrefix}${"*".repeat(Math.max(localPart.length - 2, 0))}@${domain}`;
|
|
2126
|
+
}
|
|
2127
|
+
const digits = identifier.value.replace(/\D/g, "");
|
|
2128
|
+
const visibleSuffix = digits.slice(-4);
|
|
2129
|
+
return `***-***-${visibleSuffix}`;
|
|
2130
|
+
}
|
|
2131
|
+
|
|
2097
2132
|
// src/processingStatus.ts
|
|
2098
2133
|
var PROCESSING_TIMEOUT_MS = 18e4;
|
|
2099
2134
|
function resolvePreferredTransfer(polledTransfer, localTransfer) {
|
|
@@ -2199,10 +2234,22 @@ function SwypePayment({
|
|
|
2199
2234
|
destination,
|
|
2200
2235
|
onComplete,
|
|
2201
2236
|
onError,
|
|
2202
|
-
useWalletConnector
|
|
2237
|
+
useWalletConnector,
|
|
2238
|
+
idempotencyKey,
|
|
2239
|
+
merchantAuthorization
|
|
2203
2240
|
}) {
|
|
2204
2241
|
const { apiBaseUrl, tokens, depositAmount } = useSwypeConfig();
|
|
2205
|
-
const { ready, authenticated, user,
|
|
2242
|
+
const { ready, authenticated, user, logout, getAccessToken } = reactAuth.usePrivy();
|
|
2243
|
+
const {
|
|
2244
|
+
sendCode: sendEmailCode,
|
|
2245
|
+
loginWithCode: loginWithEmailCode,
|
|
2246
|
+
state: emailLoginState
|
|
2247
|
+
} = reactAuth.useLoginWithEmail();
|
|
2248
|
+
const {
|
|
2249
|
+
sendCode: sendSmsCode,
|
|
2250
|
+
loginWithCode: loginWithSmsCode,
|
|
2251
|
+
state: smsLoginState
|
|
2252
|
+
} = reactAuth.useLoginWithSms();
|
|
2206
2253
|
const [step, setStep] = react.useState("login");
|
|
2207
2254
|
const [error, setError] = react.useState(null);
|
|
2208
2255
|
const [providers, setProviders] = react.useState([]);
|
|
@@ -2227,6 +2274,11 @@ function SwypePayment({
|
|
|
2227
2274
|
if (typeof window === "undefined") return null;
|
|
2228
2275
|
return window.localStorage.getItem(ACTIVE_CREDENTIAL_STORAGE_KEY);
|
|
2229
2276
|
});
|
|
2277
|
+
const [authInput, setAuthInput] = react.useState("");
|
|
2278
|
+
const [verificationTarget, setVerificationTarget] = react.useState(
|
|
2279
|
+
null
|
|
2280
|
+
);
|
|
2281
|
+
const [otpCode, setOtpCode] = react.useState("");
|
|
2230
2282
|
const [mobileFlow, setMobileFlow] = react.useState(false);
|
|
2231
2283
|
const pollingTransferIdRef = react.useRef(null);
|
|
2232
2284
|
const mobileSigningTransferIdRef = react.useRef(null);
|
|
@@ -2244,9 +2296,81 @@ function SwypePayment({
|
|
|
2244
2296
|
setAmount(depositAmount.toString());
|
|
2245
2297
|
}
|
|
2246
2298
|
}, [depositAmount]);
|
|
2299
|
+
const resetHeadlessLogin = react.useCallback(() => {
|
|
2300
|
+
setAuthInput("");
|
|
2301
|
+
setVerificationTarget(null);
|
|
2302
|
+
setOtpCode("");
|
|
2303
|
+
}, []);
|
|
2304
|
+
const activeOtpStatus = verificationTarget?.kind === "email" ? emailLoginState.status : verificationTarget?.kind === "phone" ? smsLoginState.status : "initial";
|
|
2305
|
+
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;
|
|
2306
|
+
react.useEffect(() => {
|
|
2307
|
+
if (activeOtpErrorMessage) {
|
|
2308
|
+
setError(activeOtpErrorMessage);
|
|
2309
|
+
}
|
|
2310
|
+
}, [activeOtpErrorMessage]);
|
|
2311
|
+
const handleSendLoginCode = react.useCallback(async () => {
|
|
2312
|
+
const normalizedIdentifier = normalizeAuthIdentifier(authInput);
|
|
2313
|
+
if (!normalizedIdentifier) {
|
|
2314
|
+
setError("Enter a valid email address or phone number.");
|
|
2315
|
+
return;
|
|
2316
|
+
}
|
|
2317
|
+
setError(null);
|
|
2318
|
+
setOtpCode("");
|
|
2319
|
+
try {
|
|
2320
|
+
if (normalizedIdentifier.kind === "email") {
|
|
2321
|
+
await sendEmailCode({ email: normalizedIdentifier.value });
|
|
2322
|
+
} else {
|
|
2323
|
+
await sendSmsCode({ phoneNumber: normalizedIdentifier.value });
|
|
2324
|
+
}
|
|
2325
|
+
setVerificationTarget(normalizedIdentifier);
|
|
2326
|
+
} catch (err) {
|
|
2327
|
+
const msg = err instanceof Error ? err.message : "Failed to send verification code";
|
|
2328
|
+
setError(msg);
|
|
2329
|
+
}
|
|
2330
|
+
}, [authInput, sendEmailCode, sendSmsCode]);
|
|
2331
|
+
const handleVerifyLoginCode = react.useCallback(async () => {
|
|
2332
|
+
if (!verificationTarget) return;
|
|
2333
|
+
const trimmedCode = otpCode.trim();
|
|
2334
|
+
if (!/^\d{6}$/.test(trimmedCode)) {
|
|
2335
|
+
setError("Enter the 6-digit verification code.");
|
|
2336
|
+
return;
|
|
2337
|
+
}
|
|
2338
|
+
setError(null);
|
|
2339
|
+
try {
|
|
2340
|
+
if (verificationTarget.kind === "email") {
|
|
2341
|
+
await loginWithEmailCode({ code: trimmedCode });
|
|
2342
|
+
} else {
|
|
2343
|
+
await loginWithSmsCode({ code: trimmedCode });
|
|
2344
|
+
}
|
|
2345
|
+
} catch (err) {
|
|
2346
|
+
const msg = err instanceof Error ? err.message : "Failed to verify code";
|
|
2347
|
+
setError(msg);
|
|
2348
|
+
}
|
|
2349
|
+
}, [verificationTarget, otpCode, loginWithEmailCode, loginWithSmsCode]);
|
|
2350
|
+
const handleResendLoginCode = react.useCallback(async () => {
|
|
2351
|
+
if (!verificationTarget) return;
|
|
2352
|
+
setError(null);
|
|
2353
|
+
try {
|
|
2354
|
+
if (verificationTarget.kind === "email") {
|
|
2355
|
+
await sendEmailCode({ email: verificationTarget.value });
|
|
2356
|
+
} else {
|
|
2357
|
+
await sendSmsCode({ phoneNumber: verificationTarget.value });
|
|
2358
|
+
}
|
|
2359
|
+
} catch (err) {
|
|
2360
|
+
const msg = err instanceof Error ? err.message : "Failed to resend code";
|
|
2361
|
+
setError(msg);
|
|
2362
|
+
}
|
|
2363
|
+
}, [verificationTarget, sendEmailCode, sendSmsCode]);
|
|
2364
|
+
const handleEditIdentifier = react.useCallback(() => {
|
|
2365
|
+
setError(null);
|
|
2366
|
+
setVerificationTarget(null);
|
|
2367
|
+
setOtpCode("");
|
|
2368
|
+
}, []);
|
|
2247
2369
|
react.useEffect(() => {
|
|
2248
2370
|
if (!ready || !authenticated || step !== "login") return;
|
|
2249
2371
|
let cancelled = false;
|
|
2372
|
+
setError(null);
|
|
2373
|
+
resetHeadlessLogin();
|
|
2250
2374
|
const checkPasskey = async () => {
|
|
2251
2375
|
try {
|
|
2252
2376
|
const token = await getAccessToken();
|
|
@@ -2266,20 +2390,20 @@ function SwypePayment({
|
|
|
2266
2390
|
}
|
|
2267
2391
|
return;
|
|
2268
2392
|
}
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2393
|
+
if (cancelled) return;
|
|
2394
|
+
const credentialIds = allPasskeys.map((p) => p.credentialId);
|
|
2395
|
+
const matched = await findDevicePasskey(credentialIds);
|
|
2396
|
+
if (cancelled) return;
|
|
2397
|
+
if (matched) {
|
|
2398
|
+
setActiveCredentialId(matched);
|
|
2399
|
+
window.localStorage.setItem(ACTIVE_CREDENTIAL_STORAGE_KEY, matched);
|
|
2400
|
+
if (depositAmount != null && depositAmount > 0) {
|
|
2401
|
+
setStep("ready");
|
|
2402
|
+
} else {
|
|
2403
|
+
setStep("enter-amount");
|
|
2280
2404
|
}
|
|
2405
|
+
return;
|
|
2281
2406
|
}
|
|
2282
|
-
if (cancelled) return;
|
|
2283
2407
|
setStep("register-passkey");
|
|
2284
2408
|
} catch {
|
|
2285
2409
|
if (!cancelled) {
|
|
@@ -2295,7 +2419,16 @@ function SwypePayment({
|
|
|
2295
2419
|
return () => {
|
|
2296
2420
|
cancelled = true;
|
|
2297
2421
|
};
|
|
2298
|
-
}, [
|
|
2422
|
+
}, [
|
|
2423
|
+
ready,
|
|
2424
|
+
authenticated,
|
|
2425
|
+
step,
|
|
2426
|
+
depositAmount,
|
|
2427
|
+
apiBaseUrl,
|
|
2428
|
+
getAccessToken,
|
|
2429
|
+
activeCredentialId,
|
|
2430
|
+
resetHeadlessLogin
|
|
2431
|
+
]);
|
|
2299
2432
|
const loadingDataRef = react.useRef(false);
|
|
2300
2433
|
react.useEffect(() => {
|
|
2301
2434
|
if (!authenticated) return;
|
|
@@ -2513,7 +2646,9 @@ function SwypePayment({
|
|
|
2513
2646
|
}
|
|
2514
2647
|
}
|
|
2515
2648
|
const t = await createTransfer(apiBaseUrl, token, {
|
|
2649
|
+
id: idempotencyKey,
|
|
2516
2650
|
credentialId: activeCredentialId,
|
|
2651
|
+
merchantAuthorization,
|
|
2517
2652
|
sourceType: effectiveSourceType,
|
|
2518
2653
|
sourceId: effectiveSourceId,
|
|
2519
2654
|
destination,
|
|
@@ -2603,7 +2738,8 @@ function SwypePayment({
|
|
|
2603
2738
|
processingStartedAtRef.current = null;
|
|
2604
2739
|
pollingTransferIdRef.current = null;
|
|
2605
2740
|
mobileSigningTransferIdRef.current = null;
|
|
2606
|
-
|
|
2741
|
+
resetHeadlessLogin();
|
|
2742
|
+
}, [logout, polling, depositAmount, resetHeadlessLogin]);
|
|
2607
2743
|
const handleConnectNewAccount = (providerId) => {
|
|
2608
2744
|
setSelectedProviderId(providerId);
|
|
2609
2745
|
setSelectedAccountId(null);
|
|
@@ -2640,7 +2776,7 @@ function SwypePayment({
|
|
|
2640
2776
|
cursor: "pointer",
|
|
2641
2777
|
transition: "filter 0.15s ease, transform 0.15s ease",
|
|
2642
2778
|
fontFamily: "inherit",
|
|
2643
|
-
boxShadow: "0 8px 18px rgba(
|
|
2779
|
+
boxShadow: "0 8px 18px rgba(40, 182, 122, 0.28)"
|
|
2644
2780
|
};
|
|
2645
2781
|
const btnDisabled = {
|
|
2646
2782
|
...btnPrimary,
|
|
@@ -2652,6 +2788,33 @@ function SwypePayment({
|
|
|
2652
2788
|
background: tokens.bgCard,
|
|
2653
2789
|
color: tokens.textSecondary,
|
|
2654
2790
|
border: `1px solid ${tokens.border}`});
|
|
2791
|
+
const textFieldStyle = {
|
|
2792
|
+
width: "100%",
|
|
2793
|
+
padding: "15px 16px",
|
|
2794
|
+
borderRadius: "16px",
|
|
2795
|
+
border: `1px solid ${tokens.border}`,
|
|
2796
|
+
background: tokens.bgInput,
|
|
2797
|
+
color: tokens.text,
|
|
2798
|
+
fontSize: "0.98rem",
|
|
2799
|
+
fontFamily: "inherit",
|
|
2800
|
+
outline: "none",
|
|
2801
|
+
boxSizing: "border-box"
|
|
2802
|
+
};
|
|
2803
|
+
const authCaptionStyle = {
|
|
2804
|
+
fontSize: "0.84rem",
|
|
2805
|
+
color: tokens.textSecondary,
|
|
2806
|
+
margin: 0,
|
|
2807
|
+
lineHeight: 1.5
|
|
2808
|
+
};
|
|
2809
|
+
const authTertiaryButtonStyle = {
|
|
2810
|
+
background: "transparent",
|
|
2811
|
+
border: "none",
|
|
2812
|
+
color: tokens.textMuted,
|
|
2813
|
+
cursor: "pointer",
|
|
2814
|
+
fontFamily: "inherit",
|
|
2815
|
+
fontSize: "0.84rem",
|
|
2816
|
+
padding: 0
|
|
2817
|
+
};
|
|
2655
2818
|
const errorStyle = {
|
|
2656
2819
|
background: tokens.errorBg,
|
|
2657
2820
|
border: `1px solid ${tokens.error}66`,
|
|
@@ -2712,6 +2875,7 @@ function SwypePayment({
|
|
|
2712
2875
|
]
|
|
2713
2876
|
}
|
|
2714
2877
|
);
|
|
2878
|
+
const placeholderProviders = ["A", "B", "C", "D", "E"];
|
|
2715
2879
|
const displayedSelectSourceChoices = selectSourceChoices.length > 0 ? selectSourceChoices : [
|
|
2716
2880
|
{
|
|
2717
2881
|
chainName: "Base",
|
|
@@ -2747,43 +2911,186 @@ function SwypePayment({
|
|
|
2747
2911
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: cardStyle, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { textAlign: "center", padding: "24px 0" }, children: /* @__PURE__ */ jsxRuntime.jsx(Spinner, { label: "Initializing..." }) }) });
|
|
2748
2912
|
}
|
|
2749
2913
|
if (step === "login" && !authenticated) {
|
|
2914
|
+
const isAwaitingOtp = verificationTarget !== null;
|
|
2915
|
+
const isSendingCode = activeOtpStatus === "sending-code";
|
|
2916
|
+
const isSubmittingCode = activeOtpStatus === "submitting-code";
|
|
2917
|
+
const continueDisabled = authInput.trim().length === 0 || isSendingCode || isSubmittingCode;
|
|
2918
|
+
const verifyDisabled = otpCode.trim().length !== 6 || isSubmittingCode;
|
|
2750
2919
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: cardStyle, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { textAlign: "center" }, children: [
|
|
2751
|
-
/* @__PURE__ */ jsxRuntime.
|
|
2752
|
-
"
|
|
2920
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2921
|
+
"div",
|
|
2753
2922
|
{
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2923
|
+
style: {
|
|
2924
|
+
width: 56,
|
|
2925
|
+
height: 56,
|
|
2926
|
+
borderRadius: 14,
|
|
2927
|
+
background: tokens.accent,
|
|
2928
|
+
color: tokens.accentText,
|
|
2929
|
+
display: "flex",
|
|
2930
|
+
alignItems: "center",
|
|
2931
|
+
justifyContent: "center",
|
|
2932
|
+
fontWeight: 700,
|
|
2933
|
+
fontSize: "1.35rem",
|
|
2934
|
+
margin: "0 auto 24px",
|
|
2935
|
+
boxShadow: "0 10px 20px rgba(40, 182, 122, 0.22)"
|
|
2936
|
+
},
|
|
2937
|
+
children: "S"
|
|
2938
|
+
}
|
|
2939
|
+
),
|
|
2940
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2941
|
+
"h2",
|
|
2942
|
+
{
|
|
2943
|
+
style: {
|
|
2944
|
+
...headingStyle,
|
|
2945
|
+
fontSize: "2.05rem",
|
|
2946
|
+
lineHeight: 1.15,
|
|
2947
|
+
marginBottom: "10px",
|
|
2948
|
+
whiteSpace: "pre-line"
|
|
2949
|
+
},
|
|
2950
|
+
children: isAwaitingOtp ? "Enter your code." : "One-time setup.\nOne-tap deposits after."
|
|
2771
2951
|
}
|
|
2772
2952
|
),
|
|
2773
|
-
/* @__PURE__ */ jsxRuntime.jsx("h2", { style: { ...headingStyle, marginBottom: "8px" }, children: "Pay with Swype" }),
|
|
2774
2953
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2775
2954
|
"p",
|
|
2776
2955
|
{
|
|
2777
2956
|
style: {
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
lineHeight: 1.5
|
|
2957
|
+
...authCaptionStyle,
|
|
2958
|
+
margin: "0 0 26px 0",
|
|
2959
|
+
whiteSpace: "pre-line"
|
|
2782
2960
|
},
|
|
2783
|
-
children:
|
|
2961
|
+
children: isAwaitingOtp ? `We sent a 6-digit code to ${maskAuthIdentifier(verificationTarget)}.` : "Protected by Face ID."
|
|
2784
2962
|
}
|
|
2785
2963
|
),
|
|
2786
|
-
/* @__PURE__ */ jsxRuntime.jsx("
|
|
2964
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("div", { style: errorStyle, children: error }),
|
|
2965
|
+
isAwaitingOtp ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2966
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2967
|
+
"input",
|
|
2968
|
+
{
|
|
2969
|
+
id: "swype-login-code",
|
|
2970
|
+
type: "text",
|
|
2971
|
+
inputMode: "numeric",
|
|
2972
|
+
autoComplete: "one-time-code",
|
|
2973
|
+
placeholder: "Verification code",
|
|
2974
|
+
value: otpCode,
|
|
2975
|
+
onChange: (event) => {
|
|
2976
|
+
setOtpCode(event.target.value.replace(/\D/g, "").slice(0, 6));
|
|
2977
|
+
},
|
|
2978
|
+
style: {
|
|
2979
|
+
...textFieldStyle,
|
|
2980
|
+
textAlign: "center",
|
|
2981
|
+
letterSpacing: "0.24em",
|
|
2982
|
+
marginBottom: "14px"
|
|
2983
|
+
}
|
|
2984
|
+
}
|
|
2985
|
+
),
|
|
2986
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2987
|
+
"button",
|
|
2988
|
+
{
|
|
2989
|
+
style: verifyDisabled ? btnDisabled : btnPrimary,
|
|
2990
|
+
disabled: verifyDisabled,
|
|
2991
|
+
onClick: handleVerifyLoginCode,
|
|
2992
|
+
children: isSubmittingCode ? "Verifying..." : "Continue"
|
|
2993
|
+
}
|
|
2994
|
+
),
|
|
2995
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2996
|
+
"div",
|
|
2997
|
+
{
|
|
2998
|
+
style: {
|
|
2999
|
+
display: "flex",
|
|
3000
|
+
justifyContent: "space-between",
|
|
3001
|
+
gap: "12px",
|
|
3002
|
+
marginTop: "14px"
|
|
3003
|
+
},
|
|
3004
|
+
children: [
|
|
3005
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", style: authTertiaryButtonStyle, onClick: handleEditIdentifier, children: "Use a different email or phone" }),
|
|
3006
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3007
|
+
"button",
|
|
3008
|
+
{
|
|
3009
|
+
type: "button",
|
|
3010
|
+
style: authTertiaryButtonStyle,
|
|
3011
|
+
onClick: handleResendLoginCode,
|
|
3012
|
+
disabled: isSendingCode || isSubmittingCode,
|
|
3013
|
+
children: isSendingCode ? "Sending..." : "Resend code"
|
|
3014
|
+
}
|
|
3015
|
+
)
|
|
3016
|
+
]
|
|
3017
|
+
}
|
|
3018
|
+
)
|
|
3019
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3020
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3021
|
+
"input",
|
|
3022
|
+
{
|
|
3023
|
+
id: "swype-login-identifier",
|
|
3024
|
+
type: "text",
|
|
3025
|
+
inputMode: "text",
|
|
3026
|
+
autoComplete: "username",
|
|
3027
|
+
placeholder: "Email or phone number",
|
|
3028
|
+
value: authInput,
|
|
3029
|
+
onChange: (event) => setAuthInput(event.target.value),
|
|
3030
|
+
style: { ...textFieldStyle, marginBottom: "14px" }
|
|
3031
|
+
}
|
|
3032
|
+
),
|
|
3033
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3034
|
+
"button",
|
|
3035
|
+
{
|
|
3036
|
+
style: continueDisabled ? btnDisabled : btnPrimary,
|
|
3037
|
+
disabled: continueDisabled,
|
|
3038
|
+
onClick: handleSendLoginCode,
|
|
3039
|
+
children: isSendingCode ? "Sending code..." : "Continue"
|
|
3040
|
+
}
|
|
3041
|
+
),
|
|
3042
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3043
|
+
"div",
|
|
3044
|
+
{
|
|
3045
|
+
style: {
|
|
3046
|
+
display: "flex",
|
|
3047
|
+
alignItems: "center",
|
|
3048
|
+
gap: "10px",
|
|
3049
|
+
margin: "22px 0 14px",
|
|
3050
|
+
color: tokens.textMuted,
|
|
3051
|
+
fontSize: "0.82rem"
|
|
3052
|
+
},
|
|
3053
|
+
children: [
|
|
3054
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { flex: 1, height: 1, background: tokens.border } }),
|
|
3055
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "works with" }),
|
|
3056
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { flex: 1, height: 1, background: tokens.border } })
|
|
3057
|
+
]
|
|
3058
|
+
}
|
|
3059
|
+
),
|
|
3060
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3061
|
+
"div",
|
|
3062
|
+
{
|
|
3063
|
+
"aria-label": "Works with placeholder providers",
|
|
3064
|
+
style: {
|
|
3065
|
+
display: "flex",
|
|
3066
|
+
justifyContent: "center",
|
|
3067
|
+
gap: "12px",
|
|
3068
|
+
marginBottom: "18px"
|
|
3069
|
+
},
|
|
3070
|
+
children: placeholderProviders.map((providerLabel) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
3071
|
+
"div",
|
|
3072
|
+
{
|
|
3073
|
+
style: {
|
|
3074
|
+
width: 34,
|
|
3075
|
+
height: 34,
|
|
3076
|
+
borderRadius: 999,
|
|
3077
|
+
border: `1px solid ${tokens.border}`,
|
|
3078
|
+
background: tokens.bgInput,
|
|
3079
|
+
color: tokens.textMuted,
|
|
3080
|
+
display: "flex",
|
|
3081
|
+
alignItems: "center",
|
|
3082
|
+
justifyContent: "center",
|
|
3083
|
+
fontSize: "0.78rem",
|
|
3084
|
+
fontWeight: 600
|
|
3085
|
+
},
|
|
3086
|
+
children: providerLabel
|
|
3087
|
+
},
|
|
3088
|
+
providerLabel
|
|
3089
|
+
))
|
|
3090
|
+
}
|
|
3091
|
+
),
|
|
3092
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { style: { ...authCaptionStyle, color: tokens.textMuted }, children: "Powered by Swype. Non-custodial." })
|
|
3093
|
+
] })
|
|
2787
3094
|
] }) });
|
|
2788
3095
|
}
|
|
2789
3096
|
if (step === "register-passkey") {
|
|
@@ -3551,6 +3858,7 @@ exports.SwypeProvider = SwypeProvider;
|
|
|
3551
3858
|
exports.createPasskeyCredential = createPasskeyCredential;
|
|
3552
3859
|
exports.darkTheme = darkTheme;
|
|
3553
3860
|
exports.deviceHasPasskey = deviceHasPasskey;
|
|
3861
|
+
exports.findDevicePasskey = findDevicePasskey;
|
|
3554
3862
|
exports.getTheme = getTheme;
|
|
3555
3863
|
exports.lightTheme = lightTheme;
|
|
3556
3864
|
exports.swypeApi = api_exports;
|