@swype-org/react-sdk 0.1.83 → 0.1.84
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 +40 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -1
- package/dist/index.d.ts +20 -1
- package/dist/index.js +40 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -422,6 +422,10 @@ interface PasskeyPopupOptions {
|
|
|
422
422
|
timeout?: number;
|
|
423
423
|
/** Populated by `createPasskeyViaPopup`; not set by callers. */
|
|
424
424
|
channelId?: string;
|
|
425
|
+
/** Privy JWT so the popup can register the passkey server-side. */
|
|
426
|
+
authToken?: string;
|
|
427
|
+
/** Core API base URL for server-side passkey registration. */
|
|
428
|
+
apiBaseUrl?: string;
|
|
425
429
|
}
|
|
426
430
|
/**
|
|
427
431
|
* Opens a same-origin pop-up window on the Swype domain to perform
|
|
@@ -433,10 +437,19 @@ interface PasskeyPopupOptions {
|
|
|
433
437
|
* Falls back to `window.postMessage` for browsers that preserve the
|
|
434
438
|
* opener reference.
|
|
435
439
|
*
|
|
440
|
+
* When both client-side channels are blocked (Safari ITP partitions
|
|
441
|
+
* BroadcastChannel by top-level origin), the popup registers the
|
|
442
|
+
* passkey directly with the backend. On popup close, this function
|
|
443
|
+
* checks the server for newly registered passkeys as a final fallback.
|
|
444
|
+
*
|
|
436
445
|
* Must be called from a user-gesture handler (e.g. button click) to
|
|
437
446
|
* avoid the browser's pop-up blocker.
|
|
447
|
+
*
|
|
448
|
+
* @param existingCredentialIds - Credential IDs known before the popup
|
|
449
|
+
* opens. Used to diff against server state when the popup closes
|
|
450
|
+
* without delivering a client-side result.
|
|
438
451
|
*/
|
|
439
|
-
declare function createPasskeyViaPopup(options: PasskeyPopupOptions): Promise<{
|
|
452
|
+
declare function createPasskeyViaPopup(options: PasskeyPopupOptions, existingCredentialIds?: string[]): Promise<{
|
|
440
453
|
credentialId: string;
|
|
441
454
|
publicKey: string;
|
|
442
455
|
}>;
|
|
@@ -464,10 +477,16 @@ declare function createPasskeyCredential(params: {
|
|
|
464
477
|
* Builds the {@link PasskeyPopupOptions} for a user. Called by the UI
|
|
465
478
|
* layer when it needs to open the passkey creation pop-up after
|
|
466
479
|
* `createPasskeyCredential` throws {@link PasskeyIframeBlockedError}.
|
|
480
|
+
*
|
|
481
|
+
* @param params.authToken - Privy JWT so the popup can register the
|
|
482
|
+
* passkey server-side (Safari fallback when BroadcastChannel is blocked).
|
|
483
|
+
* @param params.apiBaseUrl - Core API base URL for server-side registration.
|
|
467
484
|
*/
|
|
468
485
|
declare function buildPasskeyPopupOptions(params: {
|
|
469
486
|
userId: string;
|
|
470
487
|
displayName: string;
|
|
488
|
+
authToken?: string;
|
|
489
|
+
apiBaseUrl?: string;
|
|
471
490
|
}): PasskeyPopupOptions;
|
|
472
491
|
/**
|
|
473
492
|
* @deprecated Use {@link findDevicePasskey} instead, which checks all
|
package/dist/index.d.ts
CHANGED
|
@@ -422,6 +422,10 @@ interface PasskeyPopupOptions {
|
|
|
422
422
|
timeout?: number;
|
|
423
423
|
/** Populated by `createPasskeyViaPopup`; not set by callers. */
|
|
424
424
|
channelId?: string;
|
|
425
|
+
/** Privy JWT so the popup can register the passkey server-side. */
|
|
426
|
+
authToken?: string;
|
|
427
|
+
/** Core API base URL for server-side passkey registration. */
|
|
428
|
+
apiBaseUrl?: string;
|
|
425
429
|
}
|
|
426
430
|
/**
|
|
427
431
|
* Opens a same-origin pop-up window on the Swype domain to perform
|
|
@@ -433,10 +437,19 @@ interface PasskeyPopupOptions {
|
|
|
433
437
|
* Falls back to `window.postMessage` for browsers that preserve the
|
|
434
438
|
* opener reference.
|
|
435
439
|
*
|
|
440
|
+
* When both client-side channels are blocked (Safari ITP partitions
|
|
441
|
+
* BroadcastChannel by top-level origin), the popup registers the
|
|
442
|
+
* passkey directly with the backend. On popup close, this function
|
|
443
|
+
* checks the server for newly registered passkeys as a final fallback.
|
|
444
|
+
*
|
|
436
445
|
* Must be called from a user-gesture handler (e.g. button click) to
|
|
437
446
|
* avoid the browser's pop-up blocker.
|
|
447
|
+
*
|
|
448
|
+
* @param existingCredentialIds - Credential IDs known before the popup
|
|
449
|
+
* opens. Used to diff against server state when the popup closes
|
|
450
|
+
* without delivering a client-side result.
|
|
438
451
|
*/
|
|
439
|
-
declare function createPasskeyViaPopup(options: PasskeyPopupOptions): Promise<{
|
|
452
|
+
declare function createPasskeyViaPopup(options: PasskeyPopupOptions, existingCredentialIds?: string[]): Promise<{
|
|
440
453
|
credentialId: string;
|
|
441
454
|
publicKey: string;
|
|
442
455
|
}>;
|
|
@@ -464,10 +477,16 @@ declare function createPasskeyCredential(params: {
|
|
|
464
477
|
* Builds the {@link PasskeyPopupOptions} for a user. Called by the UI
|
|
465
478
|
* layer when it needs to open the passkey creation pop-up after
|
|
466
479
|
* `createPasskeyCredential` throws {@link PasskeyIframeBlockedError}.
|
|
480
|
+
*
|
|
481
|
+
* @param params.authToken - Privy JWT so the popup can register the
|
|
482
|
+
* passkey server-side (Safari fallback when BroadcastChannel is blocked).
|
|
483
|
+
* @param params.apiBaseUrl - Core API base URL for server-side registration.
|
|
467
484
|
*/
|
|
468
485
|
declare function buildPasskeyPopupOptions(params: {
|
|
469
486
|
userId: string;
|
|
470
487
|
displayName: string;
|
|
488
|
+
authToken?: string;
|
|
489
|
+
apiBaseUrl?: string;
|
|
471
490
|
}): PasskeyPopupOptions;
|
|
472
491
|
/**
|
|
473
492
|
* @deprecated Use {@link findDevicePasskey} instead, which checks all
|
package/dist/index.js
CHANGED
|
@@ -713,7 +713,7 @@ function isSafari() {
|
|
|
713
713
|
var POPUP_RESULT_TIMEOUT_MS = 12e4;
|
|
714
714
|
var POPUP_CLOSED_POLL_MS = 500;
|
|
715
715
|
var POPUP_CLOSED_GRACE_MS = 1e3;
|
|
716
|
-
function createPasskeyViaPopup(options) {
|
|
716
|
+
function createPasskeyViaPopup(options, existingCredentialIds = []) {
|
|
717
717
|
return new Promise((resolve, reject) => {
|
|
718
718
|
const channelId = `swype-pk-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
719
719
|
const payload = { ...options, channelId };
|
|
@@ -737,7 +737,19 @@ function createPasskeyViaPopup(options) {
|
|
|
737
737
|
closedGraceTimer = setTimeout(() => {
|
|
738
738
|
if (!settled) {
|
|
739
739
|
cleanup();
|
|
740
|
-
|
|
740
|
+
checkServerForNewPasskey(
|
|
741
|
+
options.authToken,
|
|
742
|
+
options.apiBaseUrl,
|
|
743
|
+
existingCredentialIds
|
|
744
|
+
).then((result) => {
|
|
745
|
+
if (result) {
|
|
746
|
+
resolve(result);
|
|
747
|
+
} else {
|
|
748
|
+
reject(new Error("Passkey setup window was closed before completing."));
|
|
749
|
+
}
|
|
750
|
+
}).catch(() => {
|
|
751
|
+
reject(new Error("Passkey setup window was closed before completing."));
|
|
752
|
+
});
|
|
741
753
|
}
|
|
742
754
|
}, POPUP_CLOSED_GRACE_MS);
|
|
743
755
|
}
|
|
@@ -773,6 +785,18 @@ function createPasskeyViaPopup(options) {
|
|
|
773
785
|
}
|
|
774
786
|
});
|
|
775
787
|
}
|
|
788
|
+
async function checkServerForNewPasskey(authToken, apiBaseUrl, existingCredentialIds) {
|
|
789
|
+
if (!authToken || !apiBaseUrl) return null;
|
|
790
|
+
const res = await fetch(`${apiBaseUrl}/v1/users/config`, {
|
|
791
|
+
headers: { Authorization: `Bearer ${authToken}` }
|
|
792
|
+
});
|
|
793
|
+
if (!res.ok) return null;
|
|
794
|
+
const body = await res.json();
|
|
795
|
+
const passkeys = body.config.passkeys ?? [];
|
|
796
|
+
const existingSet = new Set(existingCredentialIds);
|
|
797
|
+
const newPasskey = passkeys.find((p) => !existingSet.has(p.credentialId));
|
|
798
|
+
return newPasskey ?? null;
|
|
799
|
+
}
|
|
776
800
|
|
|
777
801
|
// src/hooks.ts
|
|
778
802
|
var WALLET_CLIENT_MAX_ATTEMPTS = 15;
|
|
@@ -967,7 +991,9 @@ function buildPasskeyPopupOptions(params) {
|
|
|
967
991
|
residentKey: "preferred",
|
|
968
992
|
userVerification: "required"
|
|
969
993
|
},
|
|
970
|
-
timeout: 6e4
|
|
994
|
+
timeout: 6e4,
|
|
995
|
+
authToken: params.authToken,
|
|
996
|
+
apiBaseUrl: params.apiBaseUrl
|
|
971
997
|
};
|
|
972
998
|
}
|
|
973
999
|
async function deviceHasPasskey(credentialId) {
|
|
@@ -4586,6 +4612,7 @@ function SwypePaymentInner({
|
|
|
4586
4612
|
if (typeof window === "undefined") return null;
|
|
4587
4613
|
return window.localStorage.getItem(ACTIVE_CREDENTIAL_STORAGE_KEY);
|
|
4588
4614
|
});
|
|
4615
|
+
const [knownCredentialIds, setKnownCredentialIds] = useState([]);
|
|
4589
4616
|
const [authInput, setAuthInput] = useState("");
|
|
4590
4617
|
const [verificationTarget, setVerificationTarget] = useState(null);
|
|
4591
4618
|
const [otpCode, setOtpCode] = useState("");
|
|
@@ -4875,6 +4902,7 @@ function SwypePaymentInner({
|
|
|
4875
4902
|
setOneTapLimit(config.defaultAllowance);
|
|
4876
4903
|
}
|
|
4877
4904
|
const allPasskeys = config.passkeys ?? (config.passkey ? [config.passkey] : []);
|
|
4905
|
+
setKnownCredentialIds(allPasskeys.map((p) => p.credentialId));
|
|
4878
4906
|
if (allPasskeys.length === 0) {
|
|
4879
4907
|
setStep("create-passkey");
|
|
4880
4908
|
return;
|
|
@@ -5391,12 +5419,18 @@ function SwypePaymentInner({
|
|
|
5391
5419
|
setRegisteringPasskey(true);
|
|
5392
5420
|
setError(null);
|
|
5393
5421
|
try {
|
|
5422
|
+
const token = await getAccessToken();
|
|
5394
5423
|
const passkeyDisplayName = user?.email?.address ?? user?.google?.name ?? user?.id ?? "Swype User";
|
|
5395
5424
|
const popupOptions = buildPasskeyPopupOptions({
|
|
5396
5425
|
userId: user?.id ?? "unknown",
|
|
5397
|
-
displayName: passkeyDisplayName
|
|
5426
|
+
displayName: passkeyDisplayName,
|
|
5427
|
+
authToken: token ?? void 0,
|
|
5428
|
+
apiBaseUrl
|
|
5398
5429
|
});
|
|
5399
|
-
const { credentialId, publicKey } = await createPasskeyViaPopup(
|
|
5430
|
+
const { credentialId, publicKey } = await createPasskeyViaPopup(
|
|
5431
|
+
popupOptions,
|
|
5432
|
+
knownCredentialIds
|
|
5433
|
+
);
|
|
5400
5434
|
await completePasskeyRegistration(credentialId, publicKey);
|
|
5401
5435
|
} catch (err) {
|
|
5402
5436
|
captureException(err);
|
|
@@ -5404,7 +5438,7 @@ function SwypePaymentInner({
|
|
|
5404
5438
|
} finally {
|
|
5405
5439
|
setRegisteringPasskey(false);
|
|
5406
5440
|
}
|
|
5407
|
-
}, [user, completePasskeyRegistration]);
|
|
5441
|
+
}, [user, completePasskeyRegistration, getAccessToken, apiBaseUrl, knownCredentialIds]);
|
|
5408
5442
|
const handleSelectProvider = useCallback((providerId) => {
|
|
5409
5443
|
setSelectedProviderId(providerId);
|
|
5410
5444
|
setSelectedAccountId(null);
|