@swype-org/react-sdk 0.1.85 → 0.1.87

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.d.cts CHANGED
@@ -189,11 +189,13 @@ interface UserConfig {
189
189
  passkey?: {
190
190
  credentialId: string;
191
191
  publicKey: string;
192
+ lastVerificationToken?: string | null;
192
193
  } | null;
193
194
  /** All registered WebAuthn passkey credentials for this user */
194
195
  passkeys?: {
195
196
  credentialId: string;
196
197
  publicKey: string;
198
+ lastVerificationToken?: string | null;
197
199
  }[];
198
200
  }
199
201
  /** Theme mode */
@@ -321,6 +323,13 @@ declare function fetchAuthorizationSession(apiBaseUrl: string, sessionId: string
321
323
  * POST /v1/users/config/passkey
322
324
  */
323
325
  declare function registerPasskey(apiBaseUrl: string, token: string, credentialId: string, publicKey: string): Promise<void>;
326
+ /**
327
+ * Reports passkey activity (verification) to update the last_active
328
+ * timestamp server-side. Fire-and-forget — callers should not block on
329
+ * the result.
330
+ * PATCH /v1/users/config/passkey
331
+ */
332
+ declare function reportPasskeyActivity(apiBaseUrl: string, token: string, credentialId: string): Promise<void>;
324
333
  /**
325
334
  * Fetches the authenticated user's config, including passkey status.
326
335
  * GET /v1/users/config
@@ -355,11 +364,12 @@ declare const api_fetchTransfer: typeof fetchTransfer;
355
364
  declare const api_fetchUserConfig: typeof fetchUserConfig;
356
365
  declare const api_registerPasskey: typeof registerPasskey;
357
366
  declare const api_reportActionCompletion: typeof reportActionCompletion;
367
+ declare const api_reportPasskeyActivity: typeof reportPasskeyActivity;
358
368
  declare const api_signTransfer: typeof signTransfer;
359
369
  declare const api_updateUserConfig: typeof updateUserConfig;
360
370
  declare const api_updateUserConfigBySession: typeof updateUserConfigBySession;
361
371
  declare namespace api {
362
- export { type api_CreateTransferParams as CreateTransferParams, api_createTransfer as createTransfer, api_fetchAccounts as fetchAccounts, api_fetchAuthorizationSession as fetchAuthorizationSession, api_fetchChains as fetchChains, api_fetchMerchantPublicKey as fetchMerchantPublicKey, api_fetchProviders as fetchProviders, api_fetchTransfer as fetchTransfer, api_fetchUserConfig as fetchUserConfig, api_registerPasskey as registerPasskey, api_reportActionCompletion as reportActionCompletion, api_signTransfer as signTransfer, api_updateUserConfig as updateUserConfig, api_updateUserConfigBySession as updateUserConfigBySession };
372
+ export { type api_CreateTransferParams as CreateTransferParams, api_createTransfer as createTransfer, api_fetchAccounts as fetchAccounts, api_fetchAuthorizationSession as fetchAuthorizationSession, api_fetchChains as fetchChains, api_fetchMerchantPublicKey as fetchMerchantPublicKey, api_fetchProviders as fetchProviders, api_fetchTransfer as fetchTransfer, api_fetchUserConfig as fetchUserConfig, api_registerPasskey as registerPasskey, api_reportActionCompletion as reportActionCompletion, api_reportPasskeyActivity as reportPasskeyActivity, api_signTransfer as signTransfer, api_updateUserConfig as updateUserConfig, api_updateUserConfigBySession as updateUserConfigBySession };
363
373
  }
364
374
 
365
375
  interface SwypePaymentProps {
@@ -458,6 +468,12 @@ interface PasskeyVerifyPopupOptions {
458
468
  rpId: string;
459
469
  /** Populated by `findDevicePasskeyViaPopup`; not set by callers. */
460
470
  channelId?: string;
471
+ /** Populated by `findDevicePasskeyViaPopup`; not set by callers. */
472
+ verificationToken?: string;
473
+ /** Privy JWT so the popup can report verification server-side. */
474
+ authToken?: string;
475
+ /** Core API base URL for server-side passkey activity reporting. */
476
+ apiBaseUrl?: string;
461
477
  }
462
478
  /**
463
479
  * Opens a same-origin pop-up window on the Swype domain to check whether
@@ -467,6 +483,11 @@ interface PasskeyVerifyPopupOptions {
467
483
  * inside a cross-origin iframe. The popup runs on the Swype domain where
468
484
  * the rpId matches, so WebAuthn works.
469
485
  *
486
+ * When `authToken` and `apiBaseUrl` are provided, the popup also writes a
487
+ * verification token to the backend. If Safari's ITP blocks both
488
+ * BroadcastChannel and window.opener.postMessage, the opener falls back to
489
+ * checking the server for the matching token after the popup closes.
490
+ *
470
491
  * Must be called from a user-gesture handler (e.g. button click) to
471
492
  * avoid the browser's pop-up blocker.
472
493
  *
package/dist/index.d.ts CHANGED
@@ -189,11 +189,13 @@ interface UserConfig {
189
189
  passkey?: {
190
190
  credentialId: string;
191
191
  publicKey: string;
192
+ lastVerificationToken?: string | null;
192
193
  } | null;
193
194
  /** All registered WebAuthn passkey credentials for this user */
194
195
  passkeys?: {
195
196
  credentialId: string;
196
197
  publicKey: string;
198
+ lastVerificationToken?: string | null;
197
199
  }[];
198
200
  }
199
201
  /** Theme mode */
@@ -321,6 +323,13 @@ declare function fetchAuthorizationSession(apiBaseUrl: string, sessionId: string
321
323
  * POST /v1/users/config/passkey
322
324
  */
323
325
  declare function registerPasskey(apiBaseUrl: string, token: string, credentialId: string, publicKey: string): Promise<void>;
326
+ /**
327
+ * Reports passkey activity (verification) to update the last_active
328
+ * timestamp server-side. Fire-and-forget — callers should not block on
329
+ * the result.
330
+ * PATCH /v1/users/config/passkey
331
+ */
332
+ declare function reportPasskeyActivity(apiBaseUrl: string, token: string, credentialId: string): Promise<void>;
324
333
  /**
325
334
  * Fetches the authenticated user's config, including passkey status.
326
335
  * GET /v1/users/config
@@ -355,11 +364,12 @@ declare const api_fetchTransfer: typeof fetchTransfer;
355
364
  declare const api_fetchUserConfig: typeof fetchUserConfig;
356
365
  declare const api_registerPasskey: typeof registerPasskey;
357
366
  declare const api_reportActionCompletion: typeof reportActionCompletion;
367
+ declare const api_reportPasskeyActivity: typeof reportPasskeyActivity;
358
368
  declare const api_signTransfer: typeof signTransfer;
359
369
  declare const api_updateUserConfig: typeof updateUserConfig;
360
370
  declare const api_updateUserConfigBySession: typeof updateUserConfigBySession;
361
371
  declare namespace api {
362
- export { type api_CreateTransferParams as CreateTransferParams, api_createTransfer as createTransfer, api_fetchAccounts as fetchAccounts, api_fetchAuthorizationSession as fetchAuthorizationSession, api_fetchChains as fetchChains, api_fetchMerchantPublicKey as fetchMerchantPublicKey, api_fetchProviders as fetchProviders, api_fetchTransfer as fetchTransfer, api_fetchUserConfig as fetchUserConfig, api_registerPasskey as registerPasskey, api_reportActionCompletion as reportActionCompletion, api_signTransfer as signTransfer, api_updateUserConfig as updateUserConfig, api_updateUserConfigBySession as updateUserConfigBySession };
372
+ export { type api_CreateTransferParams as CreateTransferParams, api_createTransfer as createTransfer, api_fetchAccounts as fetchAccounts, api_fetchAuthorizationSession as fetchAuthorizationSession, api_fetchChains as fetchChains, api_fetchMerchantPublicKey as fetchMerchantPublicKey, api_fetchProviders as fetchProviders, api_fetchTransfer as fetchTransfer, api_fetchUserConfig as fetchUserConfig, api_registerPasskey as registerPasskey, api_reportActionCompletion as reportActionCompletion, api_reportPasskeyActivity as reportPasskeyActivity, api_signTransfer as signTransfer, api_updateUserConfig as updateUserConfig, api_updateUserConfigBySession as updateUserConfigBySession };
363
373
  }
364
374
 
365
375
  interface SwypePaymentProps {
@@ -458,6 +468,12 @@ interface PasskeyVerifyPopupOptions {
458
468
  rpId: string;
459
469
  /** Populated by `findDevicePasskeyViaPopup`; not set by callers. */
460
470
  channelId?: string;
471
+ /** Populated by `findDevicePasskeyViaPopup`; not set by callers. */
472
+ verificationToken?: string;
473
+ /** Privy JWT so the popup can report verification server-side. */
474
+ authToken?: string;
475
+ /** Core API base URL for server-side passkey activity reporting. */
476
+ apiBaseUrl?: string;
461
477
  }
462
478
  /**
463
479
  * Opens a same-origin pop-up window on the Swype domain to check whether
@@ -467,6 +483,11 @@ interface PasskeyVerifyPopupOptions {
467
483
  * inside a cross-origin iframe. The popup runs on the Swype domain where
468
484
  * the rpId matches, so WebAuthn works.
469
485
  *
486
+ * When `authToken` and `apiBaseUrl` are provided, the popup also writes a
487
+ * verification token to the backend. If Safari's ITP blocks both
488
+ * BroadcastChannel and window.opener.postMessage, the opener falls back to
489
+ * checking the server for the matching token after the popup closes.
490
+ *
470
491
  * Must be called from a user-gesture handler (e.g. button click) to
471
492
  * avoid the browser's pop-up blocker.
472
493
  *
package/dist/index.js CHANGED
@@ -164,6 +164,7 @@ __export(api_exports, {
164
164
  fetchUserConfig: () => fetchUserConfig,
165
165
  registerPasskey: () => registerPasskey,
166
166
  reportActionCompletion: () => reportActionCompletion,
167
+ reportPasskeyActivity: () => reportPasskeyActivity,
167
168
  signTransfer: () => signTransfer,
168
169
  updateUserConfig: () => updateUserConfig,
169
170
  updateUserConfigBySession: () => updateUserConfigBySession
@@ -286,6 +287,17 @@ async function registerPasskey(apiBaseUrl, token, credentialId, publicKey) {
286
287
  });
287
288
  if (!res.ok) await throwApiError(res);
288
289
  }
290
+ async function reportPasskeyActivity(apiBaseUrl, token, credentialId) {
291
+ const res = await fetch(`${apiBaseUrl}/v1/users/config/passkey`, {
292
+ method: "PATCH",
293
+ headers: {
294
+ "Content-Type": "application/json",
295
+ Authorization: `Bearer ${token}`
296
+ },
297
+ body: JSON.stringify({ credentialId })
298
+ });
299
+ if (!res.ok) await throwApiError(res);
300
+ }
289
301
  async function fetchUserConfig(apiBaseUrl, token) {
290
302
  const res = await fetch(`${apiBaseUrl}/v1/users/config`, {
291
303
  headers: { Authorization: `Bearer ${token}` }
@@ -789,7 +801,12 @@ var VERIFY_POPUP_TIMEOUT_MS = 6e4;
789
801
  function findDevicePasskeyViaPopup(options) {
790
802
  return new Promise((resolve, reject) => {
791
803
  const channelId = `swype-pv-${Date.now()}-${Math.random().toString(36).slice(2)}`;
792
- const payload = { ...options, channelId };
804
+ const verificationToken = crypto.randomUUID();
805
+ const payload = {
806
+ ...options,
807
+ channelId,
808
+ verificationToken
809
+ };
793
810
  const encoded = btoa(JSON.stringify(payload));
794
811
  const popupUrl = `${window.location.origin}/passkey-verify#${encoded}`;
795
812
  const popup = window.open(popupUrl, "swype-passkey-verify");
@@ -809,7 +826,15 @@ function findDevicePasskeyViaPopup(options) {
809
826
  setTimeout(() => {
810
827
  if (!settled) {
811
828
  cleanup();
812
- resolve(null);
829
+ checkServerForVerifiedPasskey(
830
+ options.authToken,
831
+ options.apiBaseUrl,
832
+ verificationToken
833
+ ).then((credentialId) => {
834
+ resolve(credentialId);
835
+ }).catch(() => {
836
+ resolve(null);
837
+ });
813
838
  }
814
839
  }, POPUP_CLOSED_GRACE_MS);
815
840
  }
@@ -845,6 +870,17 @@ function findDevicePasskeyViaPopup(options) {
845
870
  }
846
871
  });
847
872
  }
873
+ async function checkServerForVerifiedPasskey(authToken, apiBaseUrl, verificationToken) {
874
+ if (!authToken || !apiBaseUrl) return null;
875
+ const res = await fetch(`${apiBaseUrl}/v1/users/config`, {
876
+ headers: { Authorization: `Bearer ${authToken}` }
877
+ });
878
+ if (!res.ok) return null;
879
+ const body = await res.json();
880
+ const passkeys = body.config.passkeys ?? [];
881
+ const matched = passkeys.find((p) => p.lastVerificationToken === verificationToken);
882
+ return matched?.credentialId ?? null;
883
+ }
848
884
  async function checkServerForNewPasskey(authToken, apiBaseUrl, existingCredentialIds) {
849
885
  if (!authToken || !apiBaseUrl) return null;
850
886
  const res = await fetch(`${apiBaseUrl}/v1/users/config`, {
@@ -5049,6 +5085,8 @@ function SwypePaymentInner({
5049
5085
  if (matched) {
5050
5086
  setActiveCredentialId(matched);
5051
5087
  window.localStorage.setItem(ACTIVE_CREDENTIAL_STORAGE_KEY, matched);
5088
+ reportPasskeyActivity(apiBaseUrl, token, matched).catch(() => {
5089
+ });
5052
5090
  await restoreOrDeposit(matched, token);
5053
5091
  return;
5054
5092
  }
@@ -5574,13 +5612,20 @@ function SwypePaymentInner({
5574
5612
  setVerifyingPasskeyPopup(true);
5575
5613
  setError(null);
5576
5614
  try {
5615
+ const token = await getAccessToken();
5577
5616
  const matched = await findDevicePasskeyViaPopup({
5578
5617
  credentialIds: knownCredentialIds,
5579
- rpId: resolvePasskeyRpId()
5618
+ rpId: resolvePasskeyRpId(),
5619
+ authToken: token ?? void 0,
5620
+ apiBaseUrl
5580
5621
  });
5581
5622
  if (matched) {
5582
5623
  setActiveCredentialId(matched);
5583
5624
  window.localStorage.setItem(ACTIVE_CREDENTIAL_STORAGE_KEY, matched);
5625
+ if (token) {
5626
+ reportPasskeyActivity(apiBaseUrl, token, matched).catch(() => {
5627
+ });
5628
+ }
5584
5629
  setStep("login");
5585
5630
  } else {
5586
5631
  setStep("create-passkey");
@@ -5590,7 +5635,7 @@ function SwypePaymentInner({
5590
5635
  } finally {
5591
5636
  setVerifyingPasskeyPopup(false);
5592
5637
  }
5593
- }, [knownCredentialIds]);
5638
+ }, [knownCredentialIds, getAccessToken, apiBaseUrl]);
5594
5639
  const handleSelectProvider = useCallback((providerId) => {
5595
5640
  setSelectedProviderId(providerId);
5596
5641
  setSelectedAccountId(null);