@swype-org/react-sdk 0.1.45 → 0.1.47
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 +162 -30
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +162 -30
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -654,6 +654,59 @@ function normalizeSignature(sig) {
|
|
|
654
654
|
);
|
|
655
655
|
}
|
|
656
656
|
|
|
657
|
+
// src/passkey-delegation.ts
|
|
658
|
+
function isInCrossOriginIframe() {
|
|
659
|
+
if (typeof window === "undefined") return false;
|
|
660
|
+
if (window.parent === window) return false;
|
|
661
|
+
try {
|
|
662
|
+
void window.parent.location.origin;
|
|
663
|
+
return false;
|
|
664
|
+
} catch {
|
|
665
|
+
return true;
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
var delegationCounter = 0;
|
|
669
|
+
function delegatePasskeyCreate(options) {
|
|
670
|
+
return new Promise((resolve, reject) => {
|
|
671
|
+
const id = `pc-${++delegationCounter}-${Date.now()}`;
|
|
672
|
+
const handler = (event) => {
|
|
673
|
+
const data = event.data;
|
|
674
|
+
if (!data || typeof data !== "object") return;
|
|
675
|
+
if (data.type !== "swype:passkey-create-response" || data.id !== id) return;
|
|
676
|
+
window.removeEventListener("message", handler);
|
|
677
|
+
if (data.error) {
|
|
678
|
+
reject(new Error(data.error));
|
|
679
|
+
} else if (data.result) {
|
|
680
|
+
resolve(data.result);
|
|
681
|
+
} else {
|
|
682
|
+
reject(new Error("Invalid passkey create response."));
|
|
683
|
+
}
|
|
684
|
+
};
|
|
685
|
+
window.addEventListener("message", handler);
|
|
686
|
+
window.parent.postMessage({ type: "swype:passkey-create-request", id, options }, "*");
|
|
687
|
+
});
|
|
688
|
+
}
|
|
689
|
+
function delegatePasskeyGet(options) {
|
|
690
|
+
return new Promise((resolve, reject) => {
|
|
691
|
+
const id = `pg-${++delegationCounter}-${Date.now()}`;
|
|
692
|
+
const handler = (event) => {
|
|
693
|
+
const data = event.data;
|
|
694
|
+
if (!data || typeof data !== "object") return;
|
|
695
|
+
if (data.type !== "swype:passkey-get-response" || data.id !== id) return;
|
|
696
|
+
window.removeEventListener("message", handler);
|
|
697
|
+
if (data.error) {
|
|
698
|
+
reject(new Error(data.error));
|
|
699
|
+
} else if (data.result) {
|
|
700
|
+
resolve(data.result);
|
|
701
|
+
} else {
|
|
702
|
+
reject(new Error("Invalid passkey get response."));
|
|
703
|
+
}
|
|
704
|
+
};
|
|
705
|
+
window.addEventListener("message", handler);
|
|
706
|
+
window.parent.postMessage({ type: "swype:passkey-get-request", id, options }, "*");
|
|
707
|
+
});
|
|
708
|
+
}
|
|
709
|
+
|
|
657
710
|
// src/hooks.ts
|
|
658
711
|
var WALLET_CLIENT_MAX_ATTEMPTS = 15;
|
|
659
712
|
var WALLET_CLIENT_POLL_MS = 200;
|
|
@@ -775,6 +828,26 @@ async function createPasskeyCredential(params) {
|
|
|
775
828
|
const challenge = new Uint8Array(32);
|
|
776
829
|
crypto.getRandomValues(challenge);
|
|
777
830
|
const rpId = resolvePasskeyRpId();
|
|
831
|
+
if (isInCrossOriginIframe()) {
|
|
832
|
+
return delegatePasskeyCreate({
|
|
833
|
+
challenge: toBase64(challenge),
|
|
834
|
+
rpId,
|
|
835
|
+
rpName: "Swype",
|
|
836
|
+
userId: toBase64(new TextEncoder().encode(params.userId)),
|
|
837
|
+
userName: params.displayName,
|
|
838
|
+
userDisplayName: params.displayName,
|
|
839
|
+
pubKeyCredParams: [
|
|
840
|
+
{ alg: -7, type: "public-key" },
|
|
841
|
+
{ alg: -257, type: "public-key" }
|
|
842
|
+
],
|
|
843
|
+
authenticatorSelection: {
|
|
844
|
+
authenticatorAttachment: "platform",
|
|
845
|
+
residentKey: "preferred",
|
|
846
|
+
userVerification: "required"
|
|
847
|
+
},
|
|
848
|
+
timeout: 6e4
|
|
849
|
+
});
|
|
850
|
+
}
|
|
778
851
|
await waitForDocumentFocus();
|
|
779
852
|
const credential = await navigator.credentials.create({
|
|
780
853
|
publicKey: {
|
|
@@ -818,6 +891,16 @@ async function findDevicePasskey(credentialIds) {
|
|
|
818
891
|
try {
|
|
819
892
|
const challenge = new Uint8Array(32);
|
|
820
893
|
crypto.getRandomValues(challenge);
|
|
894
|
+
if (isInCrossOriginIframe()) {
|
|
895
|
+
const result = await delegatePasskeyGet({
|
|
896
|
+
challenge: toBase64(challenge),
|
|
897
|
+
rpId: resolvePasskeyRpId(),
|
|
898
|
+
allowCredentials: credentialIds.map((id) => ({ type: "public-key", id })),
|
|
899
|
+
userVerification: "discouraged",
|
|
900
|
+
timeout: 3e4
|
|
901
|
+
});
|
|
902
|
+
return result.credentialId;
|
|
903
|
+
}
|
|
821
904
|
await waitForDocumentFocus();
|
|
822
905
|
const assertion = await navigator.credentials.get({
|
|
823
906
|
publicKey: {
|
|
@@ -1315,31 +1398,49 @@ function useTransferSigning(pollIntervalMs = 2e3, options) {
|
|
|
1315
1398
|
throw new Error("Timed out waiting for sign payload. Please try again.");
|
|
1316
1399
|
}
|
|
1317
1400
|
const hashBytes = hexToBytes(payload.userOpHash);
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
await waitForDocumentFocus();
|
|
1323
|
-
const assertion = await navigator.credentials.get({
|
|
1324
|
-
publicKey: {
|
|
1325
|
-
challenge: hashBytes,
|
|
1401
|
+
let signedUserOp;
|
|
1402
|
+
if (isInCrossOriginIframe()) {
|
|
1403
|
+
const delegatedResult = await delegatePasskeyGet({
|
|
1404
|
+
challenge: toBase64(hashBytes),
|
|
1326
1405
|
rpId: resolvePasskeyRpId(),
|
|
1327
|
-
allowCredentials,
|
|
1406
|
+
allowCredentials: payload.passkeyCredentialId ? [{ type: "public-key", id: payload.passkeyCredentialId }] : void 0,
|
|
1328
1407
|
userVerification: "required",
|
|
1329
1408
|
timeout: 6e4
|
|
1409
|
+
});
|
|
1410
|
+
signedUserOp = {
|
|
1411
|
+
...payload.userOp,
|
|
1412
|
+
credentialId: delegatedResult.credentialId,
|
|
1413
|
+
signature: delegatedResult.signature,
|
|
1414
|
+
authenticatorData: delegatedResult.authenticatorData,
|
|
1415
|
+
clientDataJSON: delegatedResult.clientDataJSON
|
|
1416
|
+
};
|
|
1417
|
+
} else {
|
|
1418
|
+
const allowCredentials = payload.passkeyCredentialId ? [{
|
|
1419
|
+
type: "public-key",
|
|
1420
|
+
id: base64ToBytes(payload.passkeyCredentialId)
|
|
1421
|
+
}] : void 0;
|
|
1422
|
+
await waitForDocumentFocus();
|
|
1423
|
+
const assertion = await navigator.credentials.get({
|
|
1424
|
+
publicKey: {
|
|
1425
|
+
challenge: hashBytes,
|
|
1426
|
+
rpId: resolvePasskeyRpId(),
|
|
1427
|
+
allowCredentials,
|
|
1428
|
+
userVerification: "required",
|
|
1429
|
+
timeout: 6e4
|
|
1430
|
+
}
|
|
1431
|
+
});
|
|
1432
|
+
if (!assertion) {
|
|
1433
|
+
throw new Error("Passkey authentication was cancelled.");
|
|
1330
1434
|
}
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1435
|
+
const response = assertion.response;
|
|
1436
|
+
signedUserOp = {
|
|
1437
|
+
...payload.userOp,
|
|
1438
|
+
credentialId: toBase64(assertion.rawId),
|
|
1439
|
+
signature: toBase64(response.signature),
|
|
1440
|
+
authenticatorData: toBase64(response.authenticatorData),
|
|
1441
|
+
clientDataJSON: toBase64(response.clientDataJSON)
|
|
1442
|
+
};
|
|
1334
1443
|
}
|
|
1335
|
-
const response = assertion.response;
|
|
1336
|
-
const signedUserOp = {
|
|
1337
|
-
...payload.userOp,
|
|
1338
|
-
credentialId: toBase64(assertion.rawId),
|
|
1339
|
-
signature: toBase64(response.signature),
|
|
1340
|
-
authenticatorData: toBase64(response.authenticatorData),
|
|
1341
|
-
clientDataJSON: toBase64(response.clientDataJSON)
|
|
1342
|
-
};
|
|
1343
1444
|
return await signTransfer(
|
|
1344
1445
|
apiBaseUrl,
|
|
1345
1446
|
token ?? "",
|
|
@@ -3869,6 +3970,7 @@ function SwypePayment({
|
|
|
3869
3970
|
const [mobileFlow, setMobileFlow] = useState(false);
|
|
3870
3971
|
const pollingTransferIdRef = useRef(null);
|
|
3871
3972
|
const mobileSigningTransferIdRef = useRef(null);
|
|
3973
|
+
const mobileSetupFlowRef = useRef(false);
|
|
3872
3974
|
const processingStartedAtRef = useRef(null);
|
|
3873
3975
|
const [selectSourceChainName, setSelectSourceChainName] = useState("");
|
|
3874
3976
|
const [selectSourceTokenSymbol, setSelectSourceTokenSymbol] = useState("");
|
|
@@ -3879,7 +3981,7 @@ function SwypePayment({
|
|
|
3879
3981
|
const transferSigning = useTransferSigning();
|
|
3880
3982
|
const sourceType = connectingNewAccount ? "providerId" : selectedWalletId ? "walletId" : selectedAccountId ? "accountId" : "providerId";
|
|
3881
3983
|
const sourceId = connectingNewAccount ? selectedProviderId ?? "" : selectedWalletId ? selectedWalletId : selectedAccountId ? selectedAccountId : selectedProviderId ?? "";
|
|
3882
|
-
useCallback(async () => {
|
|
3984
|
+
const reloadAccounts = useCallback(async () => {
|
|
3883
3985
|
const token = await getAccessToken();
|
|
3884
3986
|
if (!token || !activeCredentialId) return;
|
|
3885
3987
|
const [accts, prov] = await Promise.all([
|
|
@@ -4110,6 +4212,16 @@ function SwypePayment({
|
|
|
4110
4212
|
if (!mobileFlow) return;
|
|
4111
4213
|
const polledTransfer = polling.transfer;
|
|
4112
4214
|
if (!polledTransfer || polledTransfer.status !== "AUTHORIZED") return;
|
|
4215
|
+
if (mobileSetupFlowRef.current) {
|
|
4216
|
+
mobileSetupFlowRef.current = false;
|
|
4217
|
+
setMobileFlow(false);
|
|
4218
|
+
polling.stopPolling();
|
|
4219
|
+
setTransfer(polledTransfer);
|
|
4220
|
+
reloadAccounts().catch(() => {
|
|
4221
|
+
});
|
|
4222
|
+
setStep("deposit");
|
|
4223
|
+
return;
|
|
4224
|
+
}
|
|
4113
4225
|
if (transferSigning.signing) return;
|
|
4114
4226
|
if (mobileSigningTransferIdRef.current === polledTransfer.id) return;
|
|
4115
4227
|
mobileSigningTransferIdRef.current = polledTransfer.id;
|
|
@@ -4125,7 +4237,7 @@ function SwypePayment({
|
|
|
4125
4237
|
}
|
|
4126
4238
|
};
|
|
4127
4239
|
void sign();
|
|
4128
|
-
}, [mobileFlow, polling.transfer, transferSigning, onError]);
|
|
4240
|
+
}, [mobileFlow, polling.transfer, polling.stopPolling, transferSigning, onError, reloadAccounts]);
|
|
4129
4241
|
useEffect(() => {
|
|
4130
4242
|
if (!mobileFlow) return;
|
|
4131
4243
|
const transferIdToResume = pollingTransferIdRef.current ?? transfer?.id;
|
|
@@ -4227,13 +4339,13 @@ function SwypePayment({
|
|
|
4227
4339
|
}
|
|
4228
4340
|
return count;
|
|
4229
4341
|
}, [accounts]);
|
|
4230
|
-
const handlePay = useCallback(async (depositAmount2) => {
|
|
4342
|
+
const handlePay = useCallback(async (depositAmount2, sourceOverrides) => {
|
|
4231
4343
|
const parsedAmount = depositAmount2;
|
|
4232
4344
|
if (isNaN(parsedAmount) || parsedAmount < MIN_SEND_AMOUNT_USD) {
|
|
4233
4345
|
setError(`Minimum amount is $${MIN_SEND_AMOUNT_USD.toFixed(2)}.`);
|
|
4234
4346
|
return;
|
|
4235
4347
|
}
|
|
4236
|
-
if (!sourceId) {
|
|
4348
|
+
if (!sourceOverrides?.sourceId && !sourceId) {
|
|
4237
4349
|
setError("No account or provider selected.");
|
|
4238
4350
|
return;
|
|
4239
4351
|
}
|
|
@@ -4242,16 +4354,25 @@ function SwypePayment({
|
|
|
4242
4354
|
setStep("create-passkey");
|
|
4243
4355
|
return;
|
|
4244
4356
|
}
|
|
4245
|
-
|
|
4357
|
+
const isSetupRedirect = mobileSetupFlowRef.current;
|
|
4358
|
+
if (!isSetupRedirect) {
|
|
4359
|
+
setStep("processing");
|
|
4360
|
+
}
|
|
4246
4361
|
processingStartedAtRef.current = Date.now();
|
|
4247
4362
|
setError(null);
|
|
4248
4363
|
setCreatingTransfer(true);
|
|
4249
4364
|
setMobileFlow(false);
|
|
4250
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
|
+
}
|
|
4251
4372
|
const token = await getAccessToken();
|
|
4252
4373
|
if (!token) throw new Error("Not authenticated");
|
|
4253
|
-
let effectiveSourceType = sourceType;
|
|
4254
|
-
let effectiveSourceId = sourceId;
|
|
4374
|
+
let effectiveSourceType = sourceOverrides?.sourceType ?? sourceType;
|
|
4375
|
+
let effectiveSourceId = sourceOverrides?.sourceId ?? sourceId;
|
|
4255
4376
|
if (effectiveSourceType === "accountId") {
|
|
4256
4377
|
const acct = accounts.find((a) => a.id === effectiveSourceId);
|
|
4257
4378
|
const activeWallet = acct?.wallets.find((w) => w.status === "ACTIVE");
|
|
@@ -4329,7 +4450,8 @@ function SwypePayment({
|
|
|
4329
4450
|
onError,
|
|
4330
4451
|
useWalletConnector,
|
|
4331
4452
|
idempotencyKey,
|
|
4332
|
-
merchantAuthorization
|
|
4453
|
+
merchantAuthorization,
|
|
4454
|
+
transfer
|
|
4333
4455
|
]);
|
|
4334
4456
|
const handleRegisterPasskey = useCallback(async () => {
|
|
4335
4457
|
setRegisteringPasskey(true);
|
|
@@ -4373,8 +4495,18 @@ function SwypePayment({
|
|
|
4373
4495
|
setSelectedProviderId(providerId);
|
|
4374
4496
|
setSelectedAccountId(null);
|
|
4375
4497
|
setConnectingNewAccount(true);
|
|
4376
|
-
|
|
4377
|
-
|
|
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]);
|
|
4378
4510
|
const handleContinueConnection = useCallback(
|
|
4379
4511
|
(accountId) => {
|
|
4380
4512
|
const acct = accounts.find((a) => a.id === accountId);
|