@swype-org/react-sdk 0.1.45 → 0.1.46
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 +158 -29
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +158 -29
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -657,6 +657,59 @@ function normalizeSignature(sig) {
|
|
|
657
657
|
);
|
|
658
658
|
}
|
|
659
659
|
|
|
660
|
+
// src/passkey-delegation.ts
|
|
661
|
+
function isInCrossOriginIframe() {
|
|
662
|
+
if (typeof window === "undefined") return false;
|
|
663
|
+
if (window.parent === window) return false;
|
|
664
|
+
try {
|
|
665
|
+
void window.parent.location.origin;
|
|
666
|
+
return false;
|
|
667
|
+
} catch {
|
|
668
|
+
return true;
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
var delegationCounter = 0;
|
|
672
|
+
function delegatePasskeyCreate(options) {
|
|
673
|
+
return new Promise((resolve, reject) => {
|
|
674
|
+
const id = `pc-${++delegationCounter}-${Date.now()}`;
|
|
675
|
+
const handler = (event) => {
|
|
676
|
+
const data = event.data;
|
|
677
|
+
if (!data || typeof data !== "object") return;
|
|
678
|
+
if (data.type !== "swype:passkey-create-response" || data.id !== id) return;
|
|
679
|
+
window.removeEventListener("message", handler);
|
|
680
|
+
if (data.error) {
|
|
681
|
+
reject(new Error(data.error));
|
|
682
|
+
} else if (data.result) {
|
|
683
|
+
resolve(data.result);
|
|
684
|
+
} else {
|
|
685
|
+
reject(new Error("Invalid passkey create response."));
|
|
686
|
+
}
|
|
687
|
+
};
|
|
688
|
+
window.addEventListener("message", handler);
|
|
689
|
+
window.parent.postMessage({ type: "swype:passkey-create-request", id, options }, "*");
|
|
690
|
+
});
|
|
691
|
+
}
|
|
692
|
+
function delegatePasskeyGet(options) {
|
|
693
|
+
return new Promise((resolve, reject) => {
|
|
694
|
+
const id = `pg-${++delegationCounter}-${Date.now()}`;
|
|
695
|
+
const handler = (event) => {
|
|
696
|
+
const data = event.data;
|
|
697
|
+
if (!data || typeof data !== "object") return;
|
|
698
|
+
if (data.type !== "swype:passkey-get-response" || data.id !== id) return;
|
|
699
|
+
window.removeEventListener("message", handler);
|
|
700
|
+
if (data.error) {
|
|
701
|
+
reject(new Error(data.error));
|
|
702
|
+
} else if (data.result) {
|
|
703
|
+
resolve(data.result);
|
|
704
|
+
} else {
|
|
705
|
+
reject(new Error("Invalid passkey get response."));
|
|
706
|
+
}
|
|
707
|
+
};
|
|
708
|
+
window.addEventListener("message", handler);
|
|
709
|
+
window.parent.postMessage({ type: "swype:passkey-get-request", id, options }, "*");
|
|
710
|
+
});
|
|
711
|
+
}
|
|
712
|
+
|
|
660
713
|
// src/hooks.ts
|
|
661
714
|
var WALLET_CLIENT_MAX_ATTEMPTS = 15;
|
|
662
715
|
var WALLET_CLIENT_POLL_MS = 200;
|
|
@@ -778,6 +831,26 @@ async function createPasskeyCredential(params) {
|
|
|
778
831
|
const challenge = new Uint8Array(32);
|
|
779
832
|
crypto.getRandomValues(challenge);
|
|
780
833
|
const rpId = resolvePasskeyRpId();
|
|
834
|
+
if (isInCrossOriginIframe()) {
|
|
835
|
+
return delegatePasskeyCreate({
|
|
836
|
+
challenge: toBase64(challenge),
|
|
837
|
+
rpId,
|
|
838
|
+
rpName: "Swype",
|
|
839
|
+
userId: toBase64(new TextEncoder().encode(params.userId)),
|
|
840
|
+
userName: params.displayName,
|
|
841
|
+
userDisplayName: params.displayName,
|
|
842
|
+
pubKeyCredParams: [
|
|
843
|
+
{ alg: -7, type: "public-key" },
|
|
844
|
+
{ alg: -257, type: "public-key" }
|
|
845
|
+
],
|
|
846
|
+
authenticatorSelection: {
|
|
847
|
+
authenticatorAttachment: "platform",
|
|
848
|
+
residentKey: "preferred",
|
|
849
|
+
userVerification: "required"
|
|
850
|
+
},
|
|
851
|
+
timeout: 6e4
|
|
852
|
+
});
|
|
853
|
+
}
|
|
781
854
|
await waitForDocumentFocus();
|
|
782
855
|
const credential = await navigator.credentials.create({
|
|
783
856
|
publicKey: {
|
|
@@ -821,6 +894,16 @@ async function findDevicePasskey(credentialIds) {
|
|
|
821
894
|
try {
|
|
822
895
|
const challenge = new Uint8Array(32);
|
|
823
896
|
crypto.getRandomValues(challenge);
|
|
897
|
+
if (isInCrossOriginIframe()) {
|
|
898
|
+
const result = await delegatePasskeyGet({
|
|
899
|
+
challenge: toBase64(challenge),
|
|
900
|
+
rpId: resolvePasskeyRpId(),
|
|
901
|
+
allowCredentials: credentialIds.map((id) => ({ type: "public-key", id })),
|
|
902
|
+
userVerification: "discouraged",
|
|
903
|
+
timeout: 3e4
|
|
904
|
+
});
|
|
905
|
+
return result.credentialId;
|
|
906
|
+
}
|
|
824
907
|
await waitForDocumentFocus();
|
|
825
908
|
const assertion = await navigator.credentials.get({
|
|
826
909
|
publicKey: {
|
|
@@ -1318,31 +1401,49 @@ function useTransferSigning(pollIntervalMs = 2e3, options) {
|
|
|
1318
1401
|
throw new Error("Timed out waiting for sign payload. Please try again.");
|
|
1319
1402
|
}
|
|
1320
1403
|
const hashBytes = hexToBytes(payload.userOpHash);
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
await waitForDocumentFocus();
|
|
1326
|
-
const assertion = await navigator.credentials.get({
|
|
1327
|
-
publicKey: {
|
|
1328
|
-
challenge: hashBytes,
|
|
1404
|
+
let signedUserOp;
|
|
1405
|
+
if (isInCrossOriginIframe()) {
|
|
1406
|
+
const delegatedResult = await delegatePasskeyGet({
|
|
1407
|
+
challenge: toBase64(hashBytes),
|
|
1329
1408
|
rpId: resolvePasskeyRpId(),
|
|
1330
|
-
allowCredentials,
|
|
1409
|
+
allowCredentials: payload.passkeyCredentialId ? [{ type: "public-key", id: payload.passkeyCredentialId }] : void 0,
|
|
1331
1410
|
userVerification: "required",
|
|
1332
1411
|
timeout: 6e4
|
|
1412
|
+
});
|
|
1413
|
+
signedUserOp = {
|
|
1414
|
+
...payload.userOp,
|
|
1415
|
+
credentialId: delegatedResult.credentialId,
|
|
1416
|
+
signature: delegatedResult.signature,
|
|
1417
|
+
authenticatorData: delegatedResult.authenticatorData,
|
|
1418
|
+
clientDataJSON: delegatedResult.clientDataJSON
|
|
1419
|
+
};
|
|
1420
|
+
} else {
|
|
1421
|
+
const allowCredentials = payload.passkeyCredentialId ? [{
|
|
1422
|
+
type: "public-key",
|
|
1423
|
+
id: base64ToBytes(payload.passkeyCredentialId)
|
|
1424
|
+
}] : void 0;
|
|
1425
|
+
await waitForDocumentFocus();
|
|
1426
|
+
const assertion = await navigator.credentials.get({
|
|
1427
|
+
publicKey: {
|
|
1428
|
+
challenge: hashBytes,
|
|
1429
|
+
rpId: resolvePasskeyRpId(),
|
|
1430
|
+
allowCredentials,
|
|
1431
|
+
userVerification: "required",
|
|
1432
|
+
timeout: 6e4
|
|
1433
|
+
}
|
|
1434
|
+
});
|
|
1435
|
+
if (!assertion) {
|
|
1436
|
+
throw new Error("Passkey authentication was cancelled.");
|
|
1333
1437
|
}
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1438
|
+
const response = assertion.response;
|
|
1439
|
+
signedUserOp = {
|
|
1440
|
+
...payload.userOp,
|
|
1441
|
+
credentialId: toBase64(assertion.rawId),
|
|
1442
|
+
signature: toBase64(response.signature),
|
|
1443
|
+
authenticatorData: toBase64(response.authenticatorData),
|
|
1444
|
+
clientDataJSON: toBase64(response.clientDataJSON)
|
|
1445
|
+
};
|
|
1337
1446
|
}
|
|
1338
|
-
const response = assertion.response;
|
|
1339
|
-
const signedUserOp = {
|
|
1340
|
-
...payload.userOp,
|
|
1341
|
-
credentialId: toBase64(assertion.rawId),
|
|
1342
|
-
signature: toBase64(response.signature),
|
|
1343
|
-
authenticatorData: toBase64(response.authenticatorData),
|
|
1344
|
-
clientDataJSON: toBase64(response.clientDataJSON)
|
|
1345
|
-
};
|
|
1346
1447
|
return await signTransfer(
|
|
1347
1448
|
apiBaseUrl,
|
|
1348
1449
|
token ?? "",
|
|
@@ -3872,6 +3973,7 @@ function SwypePayment({
|
|
|
3872
3973
|
const [mobileFlow, setMobileFlow] = react.useState(false);
|
|
3873
3974
|
const pollingTransferIdRef = react.useRef(null);
|
|
3874
3975
|
const mobileSigningTransferIdRef = react.useRef(null);
|
|
3976
|
+
const mobileSetupFlowRef = react.useRef(false);
|
|
3875
3977
|
const processingStartedAtRef = react.useRef(null);
|
|
3876
3978
|
const [selectSourceChainName, setSelectSourceChainName] = react.useState("");
|
|
3877
3979
|
const [selectSourceTokenSymbol, setSelectSourceTokenSymbol] = react.useState("");
|
|
@@ -3882,7 +3984,7 @@ function SwypePayment({
|
|
|
3882
3984
|
const transferSigning = useTransferSigning();
|
|
3883
3985
|
const sourceType = connectingNewAccount ? "providerId" : selectedWalletId ? "walletId" : selectedAccountId ? "accountId" : "providerId";
|
|
3884
3986
|
const sourceId = connectingNewAccount ? selectedProviderId ?? "" : selectedWalletId ? selectedWalletId : selectedAccountId ? selectedAccountId : selectedProviderId ?? "";
|
|
3885
|
-
react.useCallback(async () => {
|
|
3987
|
+
const reloadAccounts = react.useCallback(async () => {
|
|
3886
3988
|
const token = await getAccessToken();
|
|
3887
3989
|
if (!token || !activeCredentialId) return;
|
|
3888
3990
|
const [accts, prov] = await Promise.all([
|
|
@@ -4113,6 +4215,16 @@ function SwypePayment({
|
|
|
4113
4215
|
if (!mobileFlow) return;
|
|
4114
4216
|
const polledTransfer = polling.transfer;
|
|
4115
4217
|
if (!polledTransfer || polledTransfer.status !== "AUTHORIZED") return;
|
|
4218
|
+
if (mobileSetupFlowRef.current) {
|
|
4219
|
+
mobileSetupFlowRef.current = false;
|
|
4220
|
+
setMobileFlow(false);
|
|
4221
|
+
polling.stopPolling();
|
|
4222
|
+
setTransfer(polledTransfer);
|
|
4223
|
+
reloadAccounts().catch(() => {
|
|
4224
|
+
});
|
|
4225
|
+
setStep("deposit");
|
|
4226
|
+
return;
|
|
4227
|
+
}
|
|
4116
4228
|
if (transferSigning.signing) return;
|
|
4117
4229
|
if (mobileSigningTransferIdRef.current === polledTransfer.id) return;
|
|
4118
4230
|
mobileSigningTransferIdRef.current = polledTransfer.id;
|
|
@@ -4128,7 +4240,7 @@ function SwypePayment({
|
|
|
4128
4240
|
}
|
|
4129
4241
|
};
|
|
4130
4242
|
void sign();
|
|
4131
|
-
}, [mobileFlow, polling.transfer, transferSigning, onError]);
|
|
4243
|
+
}, [mobileFlow, polling.transfer, polling.stopPolling, transferSigning, onError, reloadAccounts]);
|
|
4132
4244
|
react.useEffect(() => {
|
|
4133
4245
|
if (!mobileFlow) return;
|
|
4134
4246
|
const transferIdToResume = pollingTransferIdRef.current ?? transfer?.id;
|
|
@@ -4230,13 +4342,13 @@ function SwypePayment({
|
|
|
4230
4342
|
}
|
|
4231
4343
|
return count;
|
|
4232
4344
|
}, [accounts]);
|
|
4233
|
-
const handlePay = react.useCallback(async (depositAmount2) => {
|
|
4345
|
+
const handlePay = react.useCallback(async (depositAmount2, sourceOverrides) => {
|
|
4234
4346
|
const parsedAmount = depositAmount2;
|
|
4235
4347
|
if (isNaN(parsedAmount) || parsedAmount < MIN_SEND_AMOUNT_USD) {
|
|
4236
4348
|
setError(`Minimum amount is $${MIN_SEND_AMOUNT_USD.toFixed(2)}.`);
|
|
4237
4349
|
return;
|
|
4238
4350
|
}
|
|
4239
|
-
if (!sourceId) {
|
|
4351
|
+
if (!sourceOverrides?.sourceId && !sourceId) {
|
|
4240
4352
|
setError("No account or provider selected.");
|
|
4241
4353
|
return;
|
|
4242
4354
|
}
|
|
@@ -4251,10 +4363,16 @@ function SwypePayment({
|
|
|
4251
4363
|
setCreatingTransfer(true);
|
|
4252
4364
|
setMobileFlow(false);
|
|
4253
4365
|
try {
|
|
4366
|
+
if (transfer?.status === "AUTHORIZED") {
|
|
4367
|
+
const signedTransfer2 = await transferSigning.signTransfer(transfer.id);
|
|
4368
|
+
setTransfer(signedTransfer2);
|
|
4369
|
+
polling.startPolling(transfer.id);
|
|
4370
|
+
return;
|
|
4371
|
+
}
|
|
4254
4372
|
const token = await getAccessToken();
|
|
4255
4373
|
if (!token) throw new Error("Not authenticated");
|
|
4256
|
-
let effectiveSourceType = sourceType;
|
|
4257
|
-
let effectiveSourceId = sourceId;
|
|
4374
|
+
let effectiveSourceType = sourceOverrides?.sourceType ?? sourceType;
|
|
4375
|
+
let effectiveSourceId = sourceOverrides?.sourceId ?? sourceId;
|
|
4258
4376
|
if (effectiveSourceType === "accountId") {
|
|
4259
4377
|
const acct = accounts.find((a) => a.id === effectiveSourceId);
|
|
4260
4378
|
const activeWallet = acct?.wallets.find((w) => w.status === "ACTIVE");
|
|
@@ -4332,7 +4450,8 @@ function SwypePayment({
|
|
|
4332
4450
|
onError,
|
|
4333
4451
|
useWalletConnector,
|
|
4334
4452
|
idempotencyKey,
|
|
4335
|
-
merchantAuthorization
|
|
4453
|
+
merchantAuthorization,
|
|
4454
|
+
transfer
|
|
4336
4455
|
]);
|
|
4337
4456
|
const handleRegisterPasskey = react.useCallback(async () => {
|
|
4338
4457
|
setRegisteringPasskey(true);
|
|
@@ -4376,8 +4495,18 @@ function SwypePayment({
|
|
|
4376
4495
|
setSelectedProviderId(providerId);
|
|
4377
4496
|
setSelectedAccountId(null);
|
|
4378
4497
|
setConnectingNewAccount(true);
|
|
4379
|
-
|
|
4380
|
-
|
|
4498
|
+
const isMobile = !shouldUseWalletConnector({
|
|
4499
|
+
useWalletConnector,
|
|
4500
|
+
userAgent: typeof navigator === "undefined" ? void 0 : navigator.userAgent
|
|
4501
|
+
});
|
|
4502
|
+
if (isMobile) {
|
|
4503
|
+
mobileSetupFlowRef.current = true;
|
|
4504
|
+
const amount2 = depositAmount ?? 5;
|
|
4505
|
+
handlePay(amount2, { sourceType: "providerId", sourceId: providerId });
|
|
4506
|
+
} else {
|
|
4507
|
+
setStep("deposit");
|
|
4508
|
+
}
|
|
4509
|
+
}, [useWalletConnector, depositAmount, handlePay]);
|
|
4381
4510
|
const handleContinueConnection = react.useCallback(
|
|
4382
4511
|
(accountId) => {
|
|
4383
4512
|
const acct = accounts.find((a) => a.id === accountId);
|