@thru/passkey 0.2.21 → 0.2.23

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.
Files changed (80) hide show
  1. package/dist/auth/add-device.cjs +139 -0
  2. package/dist/auth/add-device.cjs.map +1 -0
  3. package/dist/auth/add-device.d.cts +69 -0
  4. package/dist/auth/add-device.d.ts +69 -0
  5. package/dist/auth/add-device.js +7 -0
  6. package/dist/auth/add-device.js.map +1 -0
  7. package/dist/auth.cjs +121 -6
  8. package/dist/auth.cjs.map +1 -1
  9. package/dist/auth.d.cts +2 -0
  10. package/dist/auth.d.ts +2 -0
  11. package/dist/auth.js +10 -4
  12. package/dist/auth.js.map +1 -1
  13. package/dist/chunk-KASTJBBY.js +128 -0
  14. package/dist/chunk-KASTJBBY.js.map +1 -0
  15. package/dist/{chunk-75G2FPYW.js → chunk-OULTQZT7.js} +4 -3
  16. package/dist/chunk-OULTQZT7.js.map +1 -0
  17. package/dist/{chunk-B5SN7AS7.js → chunk-TW7HANJM.js} +99 -49
  18. package/dist/chunk-TW7HANJM.js.map +1 -0
  19. package/dist/{chunk-2JHC7OOH.js → chunk-ZNBMADOM.js} +2 -2
  20. package/dist/chunk-ZNBMADOM.js.map +1 -0
  21. package/dist/index.cjs +102 -50
  22. package/dist/index.cjs.map +1 -1
  23. package/dist/index.d.cts +3 -3
  24. package/dist/index.d.ts +3 -3
  25. package/dist/index.js +4 -2
  26. package/dist/mobile.cjs +2 -2
  27. package/dist/mobile.cjs.map +1 -1
  28. package/dist/mobile.d.cts +2 -2
  29. package/dist/mobile.d.ts +2 -2
  30. package/dist/mobile.js +2 -2
  31. package/dist/mobile.js.map +1 -1
  32. package/dist/popup.cjs +3 -2
  33. package/dist/popup.cjs.map +1 -1
  34. package/dist/popup.d.cts +3 -3
  35. package/dist/popup.d.ts +3 -3
  36. package/dist/popup.js +1 -1
  37. package/dist/server.cjs +54 -66
  38. package/dist/server.cjs.map +1 -1
  39. package/dist/server.d.cts +14 -6
  40. package/dist/server.d.ts +14 -6
  41. package/dist/server.js +58 -69
  42. package/dist/server.js.map +1 -1
  43. package/dist/{types-_HRzmn-j.d.cts → types-BTTlCVrw.d.cts} +25 -2
  44. package/dist/{types-_HRzmn-j.d.ts → types-BTTlCVrw.d.ts} +25 -2
  45. package/dist/web.cjs +99 -48
  46. package/dist/web.cjs.map +1 -1
  47. package/dist/web.d.cts +14 -7
  48. package/dist/web.d.ts +14 -7
  49. package/dist/web.js +3 -1
  50. package/package.json +11 -6
  51. package/src/auth/add-device.ts +236 -0
  52. package/src/auth/execute-tx.ts +1 -1
  53. package/src/auth/index.ts +11 -0
  54. package/src/auth/use-passkey-auth.ts +4 -2
  55. package/src/capabilities.ts +2 -1
  56. package/src/index.ts +4 -0
  57. package/src/label.test.ts +21 -0
  58. package/src/label.ts +14 -0
  59. package/src/mobile/index.ts +1 -1
  60. package/src/mobile/passkey.ts +1 -1
  61. package/src/mobile/storage.ts +1 -1
  62. package/src/mobile/types.ts +2 -2
  63. package/src/popup-service.ts +2 -1
  64. package/src/register.ts +23 -8
  65. package/src/server/challenge.ts +15 -4
  66. package/src/server/create-wallet.test.ts +2 -2
  67. package/src/server/create-wallet.ts +24 -16
  68. package/src/server/handlers.ts +6 -2
  69. package/src/server/submit.test.ts +24 -6
  70. package/src/server/submit.ts +41 -10
  71. package/src/server/types.ts +5 -3
  72. package/src/server/utils.ts +1 -1
  73. package/src/sign.ts +127 -37
  74. package/src/types.ts +27 -2
  75. package/src/web.ts +6 -2
  76. package/tsconfig.json +3 -2
  77. package/tsup.config.ts +1 -0
  78. package/dist/chunk-2JHC7OOH.js.map +0 -1
  79. package/dist/chunk-75G2FPYW.js.map +0 -1
  80. package/dist/chunk-B5SN7AS7.js.map +0 -1
@@ -5,10 +5,11 @@ import {
5
5
  } from "./chunk-LNDWK3FA.js";
6
6
 
7
7
  // src/register.ts
8
- import { arrayBufferToBase64Url, bytesToHex } from "@thru/passkey-manager";
8
+ import { arrayBufferToBase64Url, bytesToHex } from "@thru/programs/passkey-manager";
9
9
 
10
10
  // src/capabilities.ts
11
- var DEBUG = typeof process !== "undefined" && process.env?.NEXT_PUBLIC_PASSKEY_DEBUG === "1";
11
+ var globalProcess = globalThis.process;
12
+ var DEBUG = globalProcess?.env?.NEXT_PUBLIC_PASSKEY_DEBUG === "1";
12
13
  var cachedClientCapabilities;
13
14
  var clientCapabilitiesPromise = null;
14
15
  function isWebAuthnSupported() {
@@ -183,19 +184,21 @@ function shouldFallbackToPopup(error) {
183
184
  }
184
185
 
185
186
  // src/register.ts
186
- async function registerPasskey(alias, userId, rpId) {
187
+ async function registerPasskey(alias, userId, rpId, options = {}) {
187
188
  if (!isWebAuthnSupported()) {
188
189
  throw new Error("WebAuthn is not supported in this browser");
189
190
  }
190
191
  return runWithPromptMode(
191
192
  "create",
192
193
  () => registerPasskeyInline(alias, userId, rpId),
193
- (preopenedPopup) => registerPasskeyViaPopup(alias, userId, rpId, preopenedPopup)
194
+ (preopenedPopup) => registerPasskeyViaPopup(alias, userId, rpId, preopenedPopup),
195
+ options
194
196
  );
195
197
  }
196
- async function runWithPromptMode(action, inlineFn, popupFn) {
197
- const preopenedPopup = maybePreopenPopup(action, openPasskeyPopupWindow);
198
- const promptMode = await getPasskeyPromptMode(action);
198
+ async function runWithPromptMode(action, inlineFn, popupFn, options = {}) {
199
+ const allowPopupFallback = options.allowPopupFallback ?? true;
200
+ const preopenedPopup = allowPopupFallback ? maybePreopenPopup(action, openPasskeyPopupWindow) : null;
201
+ const promptMode = allowPopupFallback ? await getPasskeyPromptMode(action) : "inline";
199
202
  if (promptMode === "popup") {
200
203
  return popupFn(preopenedPopup);
201
204
  }
@@ -203,7 +206,7 @@ async function runWithPromptMode(action, inlineFn, popupFn) {
203
206
  try {
204
207
  return await inlineFn();
205
208
  } catch (error) {
206
- if (shouldFallbackToPopup(error)) {
209
+ if (allowPopupFallback && shouldFallbackToPopup(error)) {
207
210
  return popupFn();
208
211
  }
209
212
  throw error;
@@ -245,11 +248,13 @@ async function registerPasskeyInline(alias, userId, rpId) {
245
248
  }
246
249
  const response = credential.response;
247
250
  const { x, y } = extractP256PublicKey(response);
251
+ const authenticatorAttachment = credential.authenticatorAttachment ?? null;
248
252
  return {
249
253
  credentialId: arrayBufferToBase64Url(credential.rawId),
250
254
  publicKeyX: bytesToHex(x),
251
255
  publicKeyY: bytesToHex(y),
252
- rpId
256
+ rpId,
257
+ authenticatorAttachment
253
258
  };
254
259
  }
255
260
  async function registerPasskeyViaPopup(alias, userId, rpId, preopenedPopup) {
@@ -343,6 +348,12 @@ function extractFromCoseKey(coseKey) {
343
348
  return { x, y };
344
349
  }
345
350
 
351
+ // src/label.ts
352
+ var DEFAULT_LABEL = "Thru Wallet passkey";
353
+ function createDistinctPasskeyLabel(baseLabel, _options = {}) {
354
+ return baseLabel.trim() || DEFAULT_LABEL;
355
+ }
356
+
346
357
  // src/sign.ts
347
358
  import {
348
359
  arrayBufferToBase64Url as arrayBufferToBase64Url2,
@@ -351,7 +362,7 @@ import {
351
362
  base64UrlToBytes,
352
363
  parseDerSignature,
353
364
  normalizeLowS
354
- } from "@thru/passkey-manager";
365
+ } from "@thru/programs/passkey-manager";
355
366
  async function signWithPasskey(credentialId, challenge, rpId) {
356
367
  if (!isWebAuthnSupported()) {
357
368
  throw new Error("WebAuthn is not supported in this browser");
@@ -362,49 +373,51 @@ async function signWithPasskey(credentialId, challenge, rpId) {
362
373
  (preopenedPopup) => signWithPasskeyViaPopup(credentialId, challenge, rpId, preopenedPopup)
363
374
  );
364
375
  }
365
- async function signWithStoredPasskey(challenge, rpId, preferredPasskey, allPasskeys, context) {
376
+ async function signWithStoredPasskey(challenge, rpId, preferredPasskey, allPasskeys, context, options = {}) {
366
377
  if (!isWebAuthnSupported()) {
367
378
  throw new Error("WebAuthn is not supported in this browser");
368
379
  }
369
- const preopenedPopup = maybePreopenPopup("get", openPasskeyPopupWindow);
370
- const promptMode = await getPasskeyPromptMode("get");
380
+ const allowPopupFallback = options.allowPopupFallback ?? true;
381
+ const preopenedPopup = allowPopupFallback ? maybePreopenPopup("get", openPasskeyPopupWindow) : null;
382
+ const promptMode = allowPopupFallback ? await getPasskeyPromptMode("get") : "inline";
371
383
  const storedPasskey = preferredPasskey;
372
- const canUsePopup = isInIframe();
384
+ const canUsePopup = allowPopupFallback && isInIframe();
385
+ if (options.preferDiscoverable) {
386
+ closePopup(preopenedPopup);
387
+ return signWithDiscoverableStoredPasskey(
388
+ challenge,
389
+ storedPasskey?.rpId ?? rpId,
390
+ allPasskeys
391
+ );
392
+ }
373
393
  if (promptMode === "popup" || canUsePopup && !storedPasskey) {
374
394
  return requestStoredPasskeyPopup(challenge, preopenedPopup, context);
375
395
  }
376
396
  closePopup(preopenedPopup);
377
397
  try {
378
398
  if (storedPasskey) {
379
- const result = await signWithPasskeyInline(
380
- storedPasskey.credentialId,
381
- challenge,
382
- storedPasskey.rpId
383
- );
384
- return {
385
- ...result,
386
- passkey: storedPasskey
387
- };
399
+ try {
400
+ const result = await signWithPasskeyInline(
401
+ storedPasskey.credentialId,
402
+ challenge,
403
+ storedPasskey.rpId
404
+ );
405
+ return {
406
+ ...result,
407
+ passkey: storedPasskey
408
+ };
409
+ } catch (error) {
410
+ if (!shouldFallbackToDiscoverable(error)) {
411
+ throw error;
412
+ }
413
+ return signWithDiscoverableStoredPasskey(
414
+ challenge,
415
+ storedPasskey.rpId,
416
+ allPasskeys
417
+ );
418
+ }
388
419
  }
389
- const discoverable = await signWithDiscoverablePasskey(challenge, rpId);
390
- const matchingPasskey = allPasskeys.find((p) => p.credentialId === discoverable.credentialId) ?? null;
391
- const now = (/* @__PURE__ */ new Date()).toISOString();
392
- const passkey = matchingPasskey ?? {
393
- credentialId: discoverable.credentialId,
394
- publicKeyX: "",
395
- publicKeyY: "",
396
- rpId: discoverable.rpId,
397
- createdAt: now,
398
- lastUsedAt: now
399
- };
400
- return {
401
- signature: discoverable.signature,
402
- authenticatorData: discoverable.authenticatorData,
403
- clientDataJSON: discoverable.clientDataJSON,
404
- signatureR: discoverable.signatureR,
405
- signatureS: discoverable.signatureS,
406
- passkey
407
- };
420
+ return signWithDiscoverableStoredPasskey(challenge, rpId, allPasskeys);
408
421
  } catch (error) {
409
422
  if (canUsePopup && shouldFallbackToPopup(error)) {
410
423
  return requestStoredPasskeyPopup(challenge, void 0, context);
@@ -412,6 +425,37 @@ async function signWithStoredPasskey(challenge, rpId, preferredPasskey, allPassk
412
425
  throw error;
413
426
  }
414
427
  }
428
+ async function signWithDiscoverableStoredPasskey(challenge, rpId, allPasskeys) {
429
+ const discoverable = await signWithDiscoverablePasskey(challenge, rpId);
430
+ const matchingPasskey = allPasskeys.find((p) => p.credentialId === discoverable.credentialId) ?? null;
431
+ const now = (/* @__PURE__ */ new Date()).toISOString();
432
+ const passkey = matchingPasskey ?? {
433
+ credentialId: discoverable.credentialId,
434
+ publicKeyX: "",
435
+ publicKeyY: "",
436
+ rpId: discoverable.rpId,
437
+ createdAt: now,
438
+ lastUsedAt: now
439
+ };
440
+ return {
441
+ signature: discoverable.signature,
442
+ authenticatorData: discoverable.authenticatorData,
443
+ clientDataJSON: discoverable.clientDataJSON,
444
+ signatureR: discoverable.signatureR,
445
+ signatureS: discoverable.signatureS,
446
+ authenticatorAttachment: discoverable.authenticatorAttachment,
447
+ passkey
448
+ };
449
+ }
450
+ function shouldFallbackToDiscoverable(error) {
451
+ const name = error && typeof error === "object" && "name" in error ? String(error.name) : "";
452
+ const message = error && typeof error === "object" && "message" in error ? String(error.message) : "";
453
+ const normalized = `${name} ${message}`.toLowerCase();
454
+ if (normalized.includes("user rejected") || normalized.includes("user canceled") || normalized.includes("user cancelled")) {
455
+ return false;
456
+ }
457
+ return normalized.includes("notallowederror") || normalized.includes("invalidstateerror") || normalized.includes("notfounderror") || normalized.includes("not found") || normalized.includes("no passkey") || normalized.includes("no credential") || normalized.includes("saved for this app");
458
+ }
415
459
  async function signWithDiscoverablePasskey(challenge, rpId) {
416
460
  if (!isWebAuthnSupported()) {
417
461
  throw new Error("WebAuthn is not supported in this browser");
@@ -425,7 +469,8 @@ async function signWithDiscoverablePasskey(challenge, rpId) {
425
469
  signatureR: result.signatureR,
426
470
  signatureS: result.signatureS,
427
471
  credentialId: result.credentialId,
428
- rpId: resolvedRpId
472
+ rpId: resolvedRpId,
473
+ authenticatorAttachment: result.authenticatorAttachment
429
474
  };
430
475
  }
431
476
  async function runWithPromptMode2(action, inlineFn, popupFn) {
@@ -451,7 +496,8 @@ async function signWithPasskeyInline(credentialId, challenge, rpId) {
451
496
  authenticatorData: result.authenticatorData,
452
497
  clientDataJSON: result.clientDataJSON,
453
498
  signatureR: result.signatureR,
454
- signatureS: result.signatureS
499
+ signatureS: result.signatureS,
500
+ authenticatorAttachment: result.authenticatorAttachment
455
501
  };
456
502
  }
457
503
  async function signWithPasskeyAssertion(challenge, rpId, credentialId) {
@@ -482,13 +528,15 @@ async function signWithPasskeyAssertion(challenge, rpId, credentialId) {
482
528
  const signature = new Uint8Array(response.signature);
483
529
  let { r, s } = parseDerSignature(signature);
484
530
  s = normalizeLowS(s);
531
+ const rawAttachment = assertion.authenticatorAttachment ?? null;
485
532
  return {
486
533
  signature: new Uint8Array([...r, ...s]),
487
534
  authenticatorData: new Uint8Array(response.authenticatorData),
488
535
  clientDataJSON: new Uint8Array(response.clientDataJSON),
489
536
  signatureR: r,
490
537
  signatureS: s,
491
- credentialId: arrayBufferToBase64Url2(assertion.rawId)
538
+ credentialId: arrayBufferToBase64Url2(assertion.rawId),
539
+ authenticatorAttachment: rawAttachment
492
540
  };
493
541
  }
494
542
  async function signWithPasskeyViaPopup(credentialId, challenge, rpId, preopenedPopup) {
@@ -520,7 +568,8 @@ function decodePopupSigningResult(result) {
520
568
  authenticatorData: base64UrlToBytes(result.authenticatorDataBase64Url),
521
569
  clientDataJSON: base64UrlToBytes(result.clientDataJSONBase64Url),
522
570
  signatureR: base64UrlToBytes(result.signatureRBase64Url),
523
- signatureS: base64UrlToBytes(result.signatureSBase64Url)
571
+ signatureS: base64UrlToBytes(result.signatureSBase64Url),
572
+ authenticatorAttachment: result.authenticatorAttachment ?? null
524
573
  };
525
574
  }
526
575
  function decodePopupStoredSigningResult(result) {
@@ -540,7 +589,7 @@ import {
540
589
  P256_HALF_N,
541
590
  bytesToBigIntBE,
542
591
  bigIntToBytesBE
543
- } from "@thru/passkey-manager";
592
+ } from "@thru/programs/passkey-manager";
544
593
  import {
545
594
  arrayBufferToBase64Url as arrayBufferToBase64Url3,
546
595
  base64UrlToArrayBuffer as base64UrlToArrayBuffer2,
@@ -552,7 +601,7 @@ import {
552
601
  bytesEqual,
553
602
  compareBytes,
554
603
  uniqueAccounts
555
- } from "@thru/passkey-manager";
604
+ } from "@thru/programs/passkey-manager";
556
605
 
557
606
  export {
558
607
  isWebAuthnSupported,
@@ -562,6 +611,7 @@ export {
562
611
  isInIframe,
563
612
  shouldUsePasskeyPopup,
564
613
  registerPasskey,
614
+ createDistinctPasskeyLabel,
565
615
  signWithPasskey,
566
616
  signWithStoredPasskey,
567
617
  signWithDiscoverablePasskey,
@@ -583,4 +633,4 @@ export {
583
633
  compareBytes,
584
634
  uniqueAccounts
585
635
  };
586
- //# sourceMappingURL=chunk-B5SN7AS7.js.map
636
+ //# sourceMappingURL=chunk-TW7HANJM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/register.ts","../src/capabilities.ts","../src/label.ts","../src/sign.ts","../src/web.ts"],"sourcesContent":["import type {\n PasskeyRegistrationOptions,\n PasskeyRegistrationResult,\n PasskeyPopupRegistrationResult,\n} from './types';\nimport { arrayBufferToBase64Url, bytesToHex } from '@thru/programs/passkey-manager';\nimport {\n isWebAuthnSupported,\n getPasskeyPromptMode,\n maybePreopenPopup,\n shouldFallbackToPopup,\n type PasskeyPromptAction,\n} from './capabilities';\nimport { requestPasskeyPopup, openPasskeyPopupWindow, closePopup } from './popup';\n\n/**\n * Register a new passkey for a profile.\n */\nexport async function registerPasskey(\n alias: string,\n userId: string,\n rpId: string,\n options: PasskeyRegistrationOptions = {}\n): Promise<PasskeyRegistrationResult> {\n if (!isWebAuthnSupported()) {\n throw new Error('WebAuthn is not supported in this browser');\n }\n\n return runWithPromptMode(\n 'create',\n () => registerPasskeyInline(alias, userId, rpId),\n (preopenedPopup) => registerPasskeyViaPopup(alias, userId, rpId, preopenedPopup),\n options\n );\n}\n\nasync function runWithPromptMode<T>(\n action: PasskeyPromptAction,\n inlineFn: () => Promise<T>,\n popupFn: (preopenedPopup?: Window | null) => Promise<T>,\n options: PasskeyRegistrationOptions = {}\n): Promise<T> {\n const allowPopupFallback = options.allowPopupFallback ?? true;\n const preopenedPopup = allowPopupFallback ? maybePreopenPopup(action, openPasskeyPopupWindow) : null;\n const promptMode = allowPopupFallback ? await getPasskeyPromptMode(action) : 'inline';\n if (promptMode === 'popup') {\n return popupFn(preopenedPopup);\n }\n\n closePopup(preopenedPopup);\n\n try {\n return await inlineFn();\n } catch (error) {\n if (allowPopupFallback && shouldFallbackToPopup(error)) {\n return popupFn();\n }\n throw error;\n }\n}\n\nasync function registerPasskeyInline(\n alias: string,\n userId: string,\n rpId: string\n): Promise<PasskeyRegistrationResult> {\n const rpName = 'Thru Wallet';\n\n const userIdBytes = new TextEncoder().encode(userId);\n const userIdBuffer = userIdBytes.slice(0, 64);\n\n const challenge = crypto.getRandomValues(new Uint8Array(32));\n\n const createOptions: PublicKeyCredentialCreationOptions = {\n challenge,\n rp: {\n id: rpId,\n name: rpName,\n },\n user: {\n id: userIdBuffer,\n name: alias,\n displayName: alias,\n },\n pubKeyCredParams: [\n { type: 'public-key', alg: -7 },\n ],\n authenticatorSelection: {\n authenticatorAttachment: 'platform',\n userVerification: 'required',\n residentKey: 'required',\n requireResidentKey: true,\n },\n attestation: 'none',\n timeout: 60000,\n };\n\n const credential = (await navigator.credentials.create({\n publicKey: createOptions,\n })) as PublicKeyCredential | null;\n\n if (!credential) {\n throw new Error('Passkey registration was cancelled');\n }\n\n const response = credential.response as AuthenticatorAttestationResponse;\n const { x, y } = extractP256PublicKey(response);\n const authenticatorAttachment =\n (\n credential as PublicKeyCredential & {\n authenticatorAttachment?: AuthenticatorAttachment | null;\n }\n ).authenticatorAttachment ?? null;\n\n return {\n credentialId: arrayBufferToBase64Url(credential.rawId),\n publicKeyX: bytesToHex(x),\n publicKeyY: bytesToHex(y),\n rpId,\n authenticatorAttachment,\n };\n}\n\nasync function registerPasskeyViaPopup(\n alias: string,\n userId: string,\n rpId: string,\n preopenedPopup?: Window | null\n): Promise<PasskeyRegistrationResult> {\n const result = await requestPasskeyPopup<PasskeyPopupRegistrationResult>(\n 'create',\n { alias, userId, rpId },\n preopenedPopup\n );\n return result;\n}\n\n// Key extraction helpers\n\nfunction extractP256PublicKey(\n response: AuthenticatorAttestationResponse\n): { x: Uint8Array; y: Uint8Array } {\n if (typeof response.getPublicKey === 'function') {\n const spkiKey = response.getPublicKey();\n if (spkiKey) {\n return extractFromSpki(new Uint8Array(spkiKey));\n }\n }\n\n if (typeof response.getAuthenticatorData === 'function') {\n const authData = new Uint8Array(response.getAuthenticatorData());\n return extractFromAuthenticatorData(authData);\n }\n\n throw new Error('Unable to extract public key: browser does not support required WebAuthn methods');\n}\n\nfunction extractFromSpki(spki: Uint8Array): { x: Uint8Array; y: Uint8Array } {\n const pointStart = spki.length - 65;\n\n if (spki[pointStart] !== 0x04) {\n throw new Error('Invalid SPKI format: expected uncompressed point');\n }\n\n const x = spki.slice(pointStart + 1, pointStart + 33);\n const y = spki.slice(pointStart + 33, pointStart + 65);\n\n if (x.length !== 32 || y.length !== 32) {\n throw new Error('Invalid SPKI format: incorrect coordinate length');\n }\n\n return { x, y };\n}\n\nfunction extractFromAuthenticatorData(authData: Uint8Array): { x: Uint8Array; y: Uint8Array } {\n const rpIdHashLength = 32;\n const flagsLength = 1;\n const counterLength = 4;\n const offset = rpIdHashLength + flagsLength + counterLength;\n const aaguidLength = 16;\n const credIdLenOffset = offset + aaguidLength;\n const credIdLength = (authData[credIdLenOffset] << 8) | authData[credIdLenOffset + 1];\n const coseKeyOffset = credIdLenOffset + 2 + credIdLength;\n const coseKey = authData.slice(coseKeyOffset);\n\n return extractFromCoseKey(coseKey);\n}\n\nfunction extractFromCoseKey(coseKey: Uint8Array): { x: Uint8Array; y: Uint8Array } {\n const mapStart = coseKey[0];\n if (mapStart !== 0xa5 && mapStart !== 0xa4) {\n throw new Error('Invalid COSE key format');\n }\n\n let offset = 1;\n let x: Uint8Array | null = null;\n let y: Uint8Array | null = null;\n\n while (offset < coseKey.length) {\n const key = coseKey[offset++];\n const valueType = coseKey[offset++];\n\n if (key === 0x21) {\n const length = valueType & 0x1f;\n x = coseKey.slice(offset, offset + length);\n offset += length;\n continue;\n }\n\n if (key === 0x22) {\n const length = valueType & 0x1f;\n y = coseKey.slice(offset, offset + length);\n offset += length;\n continue;\n }\n\n if (valueType >= 0x40 && valueType <= 0x5f) {\n const length = valueType & 0x1f;\n offset += length;\n continue;\n }\n\n if (valueType === 0x01 || valueType === 0x02 || valueType === 0x03) {\n continue;\n }\n\n if (valueType >= 0x18 && valueType <= 0x1b) {\n const size = 1 << (valueType - 0x18);\n offset += size;\n continue;\n }\n }\n\n if (!x || !y) {\n throw new Error('Failed to extract P-256 public key from COSE data');\n }\n\n if (x.length !== 32 || y.length !== 32) {\n throw new Error('Invalid COSE key: incorrect coordinate length');\n }\n\n return { x, y };\n}\n","import type { PasskeyClientCapabilities } from './types';\n\nconst globalProcess = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process;\nconst DEBUG = globalProcess?.env?.NEXT_PUBLIC_PASSKEY_DEBUG === '1';\n\nlet cachedClientCapabilities: PasskeyClientCapabilities | null | undefined;\nlet clientCapabilitiesPromise: Promise<PasskeyClientCapabilities | null> | null = null;\n\nexport function isWebAuthnSupported(): boolean {\n const supported =\n typeof window !== 'undefined' &&\n typeof window.PublicKeyCredential !== 'undefined' &&\n typeof navigator.credentials !== 'undefined';\n\n if (DEBUG) {\n console.log('[Passkey] WebAuthn support check:', {\n window: typeof window !== 'undefined',\n PublicKeyCredential:\n typeof window !== 'undefined' && typeof window.PublicKeyCredential !== 'undefined',\n credentials:\n typeof window !== 'undefined' &&\n typeof navigator !== 'undefined' &&\n typeof navigator.credentials !== 'undefined',\n supported,\n });\n }\n\n return supported;\n}\n\nasync function fetchPasskeyClientCapabilities(): Promise<PasskeyClientCapabilities | null> {\n if (typeof window === 'undefined' || typeof window.PublicKeyCredential === 'undefined') {\n return null;\n }\n\n const getClientCapabilities = (window.PublicKeyCredential as {\n getClientCapabilities?: () => Promise<PasskeyClientCapabilities>;\n }).getClientCapabilities;\n\n if (typeof getClientCapabilities !== 'function') {\n return null;\n }\n\n try {\n const capabilities = await getClientCapabilities.call(window.PublicKeyCredential);\n if (DEBUG) {\n console.log('[Passkey] WebAuthn client capabilities:', capabilities);\n }\n return capabilities ?? null;\n } catch (error) {\n if (DEBUG) {\n console.warn('[Passkey] Failed to read client capabilities:', error);\n }\n return null;\n }\n}\n\nexport function preloadPasskeyClientCapabilities(): void {\n if (cachedClientCapabilities !== undefined || clientCapabilitiesPromise) {\n return;\n }\n\n clientCapabilitiesPromise = fetchPasskeyClientCapabilities().then((capabilities) => {\n cachedClientCapabilities = capabilities;\n return capabilities;\n });\n}\n\nexport async function getPasskeyClientCapabilities(): Promise<PasskeyClientCapabilities | null> {\n if (cachedClientCapabilities !== undefined) {\n return cachedClientCapabilities;\n }\n\n if (!clientCapabilitiesPromise) {\n preloadPasskeyClientCapabilities();\n }\n\n if (!clientCapabilitiesPromise) {\n cachedClientCapabilities = null;\n return null;\n }\n\n const capabilities = await clientCapabilitiesPromise;\n cachedClientCapabilities = capabilities;\n return capabilities;\n}\n\nexport function getCachedPasskeyClientCapabilities(): PasskeyClientCapabilities | null | undefined {\n return cachedClientCapabilities;\n}\n\nexport function isInIframe(): boolean {\n if (typeof window === 'undefined') {\n return false;\n }\n try {\n return window.self !== window.top;\n } catch {\n return true;\n }\n}\n\nexport type PasskeyPromptAction = 'get' | 'create';\n\nexport async function shouldUsePasskeyPopup(action: PasskeyPromptAction): Promise<boolean> {\n if (!isInIframe()) {\n return false;\n }\n const mode = await getPasskeyPromptMode(action);\n return mode === 'popup';\n}\n\ntype PasskeyPromptMode = 'inline' | 'popup';\n\nfunction getPermissionsPolicyAllowsFeature(feature: string): boolean | null {\n if (typeof document === 'undefined') {\n return null;\n }\n\n const policy = (document as { permissionsPolicy?: { allowsFeature?: (name: string) => boolean } })\n .permissionsPolicy;\n const featurePolicy = (document as { featurePolicy?: { allowsFeature?: (name: string) => boolean } })\n .featurePolicy;\n const allowsFeature = policy?.allowsFeature || featurePolicy?.allowsFeature;\n\n if (typeof allowsFeature !== 'function') {\n return null;\n }\n\n try {\n return allowsFeature(feature);\n } catch {\n return null;\n }\n}\n\nfunction getCachedPromptMode(action: PasskeyPromptAction): PasskeyPromptMode | 'unknown' {\n if (!isInIframe()) {\n return 'inline';\n }\n\n if (cachedClientCapabilities === undefined && !clientCapabilitiesPromise) {\n preloadPasskeyClientCapabilities();\n }\n\n const feature =\n action === 'create' ? 'publickey-credentials-create' : 'publickey-credentials-get';\n const policyAllows = getPermissionsPolicyAllowsFeature(feature);\n const capabilities = getCachedPasskeyClientCapabilities();\n const supportsInline =\n capabilities?.passkeyPlatformAuthenticator === true ||\n capabilities?.userVerifyingPlatformAuthenticator === true;\n\n if (policyAllows === false) {\n return 'popup';\n }\n\n if (capabilities === undefined) {\n return 'unknown';\n }\n\n if (!supportsInline) {\n return 'popup';\n }\n\n return 'inline';\n}\n\nexport async function getPasskeyPromptMode(action: PasskeyPromptAction): Promise<PasskeyPromptMode> {\n if (!isInIframe()) {\n return 'inline';\n }\n\n const feature =\n action === 'create' ? 'publickey-credentials-create' : 'publickey-credentials-get';\n const policyAllows = getPermissionsPolicyAllowsFeature(feature);\n const capabilities = await getPasskeyClientCapabilities();\n const supportsInline =\n capabilities?.passkeyPlatformAuthenticator === true ||\n capabilities?.userVerifyingPlatformAuthenticator === true;\n\n if (DEBUG) {\n console.log('[Passkey] Prompt mode check:', {\n action,\n policyAllows,\n supportsInline,\n capabilities,\n });\n }\n\n if (!supportsInline) {\n return 'popup';\n }\n\n if (policyAllows === false) {\n return 'popup';\n }\n\n return 'inline';\n}\n\nexport function maybePreopenPopup(action: PasskeyPromptAction, openPopupFn: () => Window): Window | null {\n const cachedMode = getCachedPromptMode(action);\n if (cachedMode !== 'popup') {\n return null;\n }\n\n try {\n return openPopupFn();\n } catch {\n return null;\n }\n}\n\nexport function shouldFallbackToPopup(error: unknown): boolean {\n if (!isInIframe()) {\n return false;\n }\n\n const name =\n error && typeof error === 'object' && 'name' in error ? String((error as { name?: unknown }).name) : '';\n const message =\n error && typeof error === 'object' && 'message' in error\n ? String((error as { message?: unknown }).message)\n : '';\n const normalized = `${name} ${message}`.toLowerCase();\n\n if (\n normalized.includes('cancel') ||\n normalized.includes('canceled') ||\n normalized.includes('cancelled') ||\n normalized.includes('user canceled') ||\n normalized.includes('user cancelled') ||\n normalized.includes('aborted')\n ) {\n return false;\n }\n\n if (normalized.includes('securityerror')) {\n return true;\n }\n\n if (normalized.includes('notallowederror')) {\n if (\n normalized.includes('permission') ||\n normalized.includes('policy') ||\n normalized.includes('iframe') ||\n normalized.includes('frame')\n ) {\n return true;\n }\n }\n\n return false;\n}\n","const DEFAULT_LABEL = 'Thru Wallet passkey';\n\nexport interface DistinctPasskeyLabelOptions {\n existingLabels?: Iterable<string | null | undefined>;\n maxAttempts?: number;\n suffixFactory?: () => string;\n}\n\nexport function createDistinctPasskeyLabel(\n baseLabel: string,\n _options: DistinctPasskeyLabelOptions = {}\n): string {\n return baseLabel.trim() || DEFAULT_LABEL;\n}\n","import type {\n PasskeySigningResult,\n PasskeyStoredSigningResult,\n PasskeyDiscoverableSigningResult,\n PasskeyMetadata,\n PasskeyPopupContext,\n PasskeyPopupSigningResult,\n PasskeyPopupStoredSigningResult,\n PasskeyStoredSigningOptions,\n} from './types';\nimport {\n arrayBufferToBase64Url,\n base64UrlToArrayBuffer,\n bytesToBase64Url,\n base64UrlToBytes,\n parseDerSignature,\n normalizeLowS,\n} from '@thru/programs/passkey-manager';\nimport {\n isWebAuthnSupported,\n getPasskeyPromptMode,\n isInIframe,\n maybePreopenPopup,\n shouldFallbackToPopup,\n type PasskeyPromptAction,\n} from './capabilities';\nimport {\n requestPasskeyPopup,\n openPasskeyPopupWindow,\n closePopup,\n} from './popup';\n\n/**\n * Sign a challenge with an existing passkey (by credential ID).\n */\nexport async function signWithPasskey(\n credentialId: string,\n challenge: Uint8Array,\n rpId: string\n): Promise<PasskeySigningResult> {\n if (!isWebAuthnSupported()) {\n throw new Error('WebAuthn is not supported in this browser');\n }\n\n return runWithPromptMode(\n 'get',\n () => signWithPasskeyInline(credentialId, challenge, rpId),\n (preopenedPopup) =>\n signWithPasskeyViaPopup(credentialId, challenge, rpId, preopenedPopup)\n );\n}\n\n/**\n * Sign with stored passkey (for embedded/popup contexts).\n */\nexport async function signWithStoredPasskey(\n challenge: Uint8Array,\n rpId: string,\n preferredPasskey: PasskeyMetadata | null,\n allPasskeys: PasskeyMetadata[],\n context?: PasskeyPopupContext,\n options: PasskeyStoredSigningOptions = {}\n): Promise<PasskeyStoredSigningResult> {\n if (!isWebAuthnSupported()) {\n throw new Error('WebAuthn is not supported in this browser');\n }\n\n const allowPopupFallback = options.allowPopupFallback ?? true;\n const preopenedPopup = allowPopupFallback\n ? maybePreopenPopup('get', openPasskeyPopupWindow)\n : null;\n const promptMode = allowPopupFallback\n ? await getPasskeyPromptMode('get')\n : 'inline';\n const storedPasskey = preferredPasskey;\n const canUsePopup = allowPopupFallback && isInIframe();\n\n if (options.preferDiscoverable) {\n closePopup(preopenedPopup);\n return signWithDiscoverableStoredPasskey(\n challenge,\n storedPasskey?.rpId ?? rpId,\n allPasskeys\n );\n }\n\n if (promptMode === 'popup' || (canUsePopup && !storedPasskey)) {\n return requestStoredPasskeyPopup(challenge, preopenedPopup, context);\n }\n\n closePopup(preopenedPopup);\n\n try {\n if (storedPasskey) {\n try {\n const result = await signWithPasskeyInline(\n storedPasskey.credentialId,\n challenge,\n storedPasskey.rpId\n );\n return {\n ...result,\n passkey: storedPasskey,\n };\n } catch (error) {\n if (!shouldFallbackToDiscoverable(error)) {\n throw error;\n }\n return signWithDiscoverableStoredPasskey(\n challenge,\n storedPasskey.rpId,\n allPasskeys\n );\n }\n }\n\n return signWithDiscoverableStoredPasskey(challenge, rpId, allPasskeys);\n } catch (error) {\n if (canUsePopup && shouldFallbackToPopup(error)) {\n return requestStoredPasskeyPopup(challenge, undefined, context);\n }\n\n throw error;\n }\n}\n\nasync function signWithDiscoverableStoredPasskey(\n challenge: Uint8Array,\n rpId: string,\n allPasskeys: PasskeyMetadata[]\n): Promise<PasskeyStoredSigningResult> {\n const discoverable = await signWithDiscoverablePasskey(challenge, rpId);\n const matchingPasskey =\n allPasskeys.find((p) => p.credentialId === discoverable.credentialId) ??\n null;\n const now = new Date().toISOString();\n const passkey = matchingPasskey ?? {\n credentialId: discoverable.credentialId,\n publicKeyX: '',\n publicKeyY: '',\n rpId: discoverable.rpId,\n createdAt: now,\n lastUsedAt: now,\n };\n\n return {\n signature: discoverable.signature,\n authenticatorData: discoverable.authenticatorData,\n clientDataJSON: discoverable.clientDataJSON,\n signatureR: discoverable.signatureR,\n signatureS: discoverable.signatureS,\n authenticatorAttachment: discoverable.authenticatorAttachment,\n passkey,\n };\n}\n\nfunction shouldFallbackToDiscoverable(error: unknown): boolean {\n const name =\n error && typeof error === 'object' && 'name' in error\n ? String((error as { name?: unknown }).name)\n : '';\n const message =\n error && typeof error === 'object' && 'message' in error\n ? String((error as { message?: unknown }).message)\n : '';\n const normalized = `${name} ${message}`.toLowerCase();\n\n if (\n normalized.includes('user rejected') ||\n normalized.includes('user canceled') ||\n normalized.includes('user cancelled')\n ) {\n return false;\n }\n\n return (\n normalized.includes('notallowederror') ||\n normalized.includes('invalidstateerror') ||\n normalized.includes('notfounderror') ||\n normalized.includes('not found') ||\n normalized.includes('no passkey') ||\n normalized.includes('no credential') ||\n normalized.includes('saved for this app')\n );\n}\n\n/**\n * Sign with a discoverable passkey (no credential ID - browser prompts user to select).\n */\nexport async function signWithDiscoverablePasskey(\n challenge: Uint8Array,\n rpId: string\n): Promise<PasskeyDiscoverableSigningResult> {\n if (!isWebAuthnSupported()) {\n throw new Error('WebAuthn is not supported in this browser');\n }\n\n const resolvedRpId = rpId;\n const result = await signWithPasskeyAssertion(challenge, resolvedRpId);\n\n return {\n signature: result.signature,\n authenticatorData: result.authenticatorData,\n clientDataJSON: result.clientDataJSON,\n signatureR: result.signatureR,\n signatureS: result.signatureS,\n credentialId: result.credentialId,\n rpId: resolvedRpId,\n authenticatorAttachment: result.authenticatorAttachment,\n };\n}\n\n// Internal helpers\n\nasync function runWithPromptMode<T>(\n action: PasskeyPromptAction,\n inlineFn: () => Promise<T>,\n popupFn: (preopenedPopup?: Window | null) => Promise<T>\n): Promise<T> {\n const preopenedPopup = maybePreopenPopup(action, openPasskeyPopupWindow);\n const promptMode = await getPasskeyPromptMode(action);\n if (promptMode === 'popup') {\n return popupFn(preopenedPopup);\n }\n\n closePopup(preopenedPopup);\n\n try {\n return await inlineFn();\n } catch (error) {\n if (shouldFallbackToPopup(error)) {\n return popupFn();\n }\n throw error;\n }\n}\n\nasync function signWithPasskeyInline(\n credentialId: string,\n challenge: Uint8Array,\n rpId: string\n): Promise<PasskeySigningResult> {\n const result = await signWithPasskeyAssertion(challenge, rpId, credentialId);\n return {\n signature: result.signature,\n authenticatorData: result.authenticatorData,\n clientDataJSON: result.clientDataJSON,\n signatureR: result.signatureR,\n signatureS: result.signatureS,\n authenticatorAttachment: result.authenticatorAttachment,\n };\n}\n\nasync function signWithPasskeyAssertion(\n challenge: Uint8Array,\n rpId: string,\n credentialId?: string\n): Promise<PasskeySigningResult & { credentialId: string }> {\n const challengeBytes = new Uint8Array(challenge);\n const getOptions: PublicKeyCredentialRequestOptions = {\n challenge: challengeBytes,\n rpId,\n userVerification: 'required',\n timeout: 60000,\n };\n\n if (credentialId) {\n const credentialIdBuffer = base64UrlToArrayBuffer(credentialId);\n getOptions.allowCredentials = [\n {\n type: 'public-key',\n id: credentialIdBuffer,\n transports: ['internal', 'hybrid', 'usb', 'ble', 'nfc'],\n },\n ];\n }\n\n const assertion = (await navigator.credentials.get({\n publicKey: getOptions,\n })) as PublicKeyCredential | null;\n\n if (!assertion) {\n throw new Error('Passkey authentication was cancelled');\n }\n\n const response = assertion.response as AuthenticatorAssertionResponse;\n\n const signature = new Uint8Array(response.signature);\n let { r, s } = parseDerSignature(signature);\n s = normalizeLowS(s);\n\n /* `authenticatorAttachment` distinguishes a same-device passkey\n ('platform') from a cross-device one signed via QR / hybrid\n transport ('cross-platform'). Drives the wallet's add-device\n prompt. Browsers may report null. */\n const rawAttachment =\n (\n assertion as PublicKeyCredential & {\n authenticatorAttachment?: AuthenticatorAttachment | null;\n }\n ).authenticatorAttachment ?? null;\n\n return {\n signature: new Uint8Array([...r, ...s]),\n authenticatorData: new Uint8Array(response.authenticatorData),\n clientDataJSON: new Uint8Array(response.clientDataJSON),\n signatureR: r,\n signatureS: s,\n credentialId: arrayBufferToBase64Url(assertion.rawId),\n authenticatorAttachment: rawAttachment,\n };\n}\n\nasync function signWithPasskeyViaPopup(\n credentialId: string,\n challenge: Uint8Array,\n rpId: string,\n preopenedPopup?: Window | null\n): Promise<PasskeySigningResult> {\n const result = await requestPasskeyPopup<PasskeyPopupSigningResult>(\n 'get',\n {\n credentialId,\n challengeBase64Url: bytesToBase64Url(challenge),\n rpId,\n },\n preopenedPopup\n );\n\n return decodePopupSigningResult(result);\n}\n\nasync function requestStoredPasskeyPopup(\n challenge: Uint8Array,\n preopenedPopup?: Window | null,\n context?: PasskeyPopupContext\n): Promise<PasskeyStoredSigningResult> {\n const result = await requestPasskeyPopup<PasskeyPopupStoredSigningResult>(\n 'getStored',\n {\n challengeBase64Url: bytesToBase64Url(challenge),\n context,\n },\n preopenedPopup\n );\n return decodePopupStoredSigningResult(result);\n}\n\nfunction decodePopupSigningResult(\n result: PasskeyPopupSigningResult\n): PasskeySigningResult {\n return {\n signature: base64UrlToBytes(result.signatureBase64Url),\n authenticatorData: base64UrlToBytes(result.authenticatorDataBase64Url),\n clientDataJSON: base64UrlToBytes(result.clientDataJSONBase64Url),\n signatureR: base64UrlToBytes(result.signatureRBase64Url),\n signatureS: base64UrlToBytes(result.signatureSBase64Url),\n authenticatorAttachment: result.authenticatorAttachment ?? null,\n };\n}\n\nfunction decodePopupStoredSigningResult(\n result: PasskeyPopupStoredSigningResult\n): PasskeyStoredSigningResult {\n return {\n ...decodePopupSigningResult(result),\n passkey: result.passkey,\n accounts: result.accounts,\n };\n}\n","export type {\n PasskeyRegistrationResult,\n PasskeySigningResult,\n PasskeyDiscoverableSigningResult,\n PasskeyStoredSigningResult,\n PasskeyMetadata,\n PasskeyClientCapabilities,\n PasskeyPopupContext,\n PasskeyPopupAccount,\n PasskeyStoredSigningOptions,\n PasskeyRegistrationOptions,\n} from './types';\n\nexport { registerPasskey } from './register';\nexport { createDistinctPasskeyLabel } from './label';\nexport type { DistinctPasskeyLabelOptions } from './label';\n\nexport {\n signWithPasskey,\n signWithStoredPasskey,\n signWithDiscoverablePasskey,\n} from './sign';\n\nexport {\n parseDerSignature,\n normalizeLowS,\n normalizeSignatureComponent,\n P256_N,\n P256_HALF_N,\n bytesToBigIntBE,\n bigIntToBytesBE,\n} from '@thru/programs/passkey-manager';\n\nexport {\n isWebAuthnSupported,\n preloadPasskeyClientCapabilities,\n getPasskeyClientCapabilities,\n getCachedPasskeyClientCapabilities,\n shouldUsePasskeyPopup,\n isInIframe,\n type PasskeyPromptAction,\n} from './capabilities';\n\nexport {\n arrayBufferToBase64Url,\n base64UrlToArrayBuffer,\n bytesToBase64,\n bytesToBase64Url,\n base64UrlToBytes,\n bytesToHex,\n hexToBytes,\n bytesEqual,\n compareBytes,\n uniqueAccounts,\n} from '@thru/programs/passkey-manager';\n"],"mappings":"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","names":["arrayBufferToBase64Url","runWithPromptMode","arrayBufferToBase64Url","parseDerSignature","normalizeLowS","arrayBufferToBase64Url","base64UrlToArrayBuffer","bytesToBase64Url","base64UrlToBytes","bytesToHex"]}
@@ -124,7 +124,7 @@ import {
124
124
  base64UrlToBytes,
125
125
  normalizeLowS,
126
126
  parseDerSignature
127
- } from "@thru/passkey-manager";
127
+ } from "@thru/programs/passkey-manager";
128
128
  function getDefaultConfig(config) {
129
129
  const env = globalThis.process?.env ?? {};
130
130
  return {
@@ -247,4 +247,4 @@ export {
247
247
  authenticateWithDiscoverablePasskey,
248
248
  extractP256Coordinates
249
249
  };
250
- //# sourceMappingURL=chunk-2JHC7OOH.js.map
250
+ //# sourceMappingURL=chunk-ZNBMADOM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/mobile/errors.ts","../src/mobile/storage.ts","../src/mobile/passkey.ts"],"sourcesContent":["const PASSKEY_ERRORS = {\n USER_CANCELLED: [\n 'error 1001',\n 'UserCancelled',\n 'Passkey authentication was cancelled',\n 'Passkey registration was cancelled',\n ],\n NOT_FOUND: [\n 'not found',\n 'No credentials available',\n 'no passkey',\n 'NoCredentials',\n ],\n} as const;\n\nexport type PasskeyErrorKind = keyof typeof PASSKEY_ERRORS;\n\nexport function classifyPasskeyError(error: unknown): PasskeyErrorKind | null {\n const message =\n error instanceof Error ? error.message : typeof error === 'string' ? error : null;\n\n if (!message) return null;\n\n for (const [kind, patterns] of Object.entries(PASSKEY_ERRORS)) {\n if (patterns.some((pattern) => message.includes(pattern))) {\n return kind as PasskeyErrorKind;\n }\n }\n\n return null;\n}\n","import * as SecureStore from 'expo-secure-store';\nimport type { PasskeyMetadata } from '@thru/programs/passkey-manager';\n\nconst SECURE_STORE_OPTS = {\n keychainAccessible: SecureStore.WHEN_UNLOCKED_THIS_DEVICE_ONLY,\n} as const;\n\nconst PASSKEY_CREDENTIAL_ID_KEY = 'thru_passkey_credential_id';\nconst PASSKEY_PUBLIC_KEY_X_KEY = 'thru_passkey_pubkey_x';\nconst PASSKEY_PUBLIC_KEY_Y_KEY = 'thru_passkey_pubkey_y';\nconst PASSKEY_RP_ID_KEY = 'thru_passkey_rp_id';\nconst PASSKEY_LABEL_KEY = 'thru_passkey_label';\nconst PASSKEY_CREATED_AT_KEY = 'thru_passkey_created_at';\nconst PASSKEY_LAST_USED_AT_KEY = 'thru_passkey_last_used_at';\n\nconst ADDRESS_KEY = 'thru_address';\nconst USER_ID_KEY = 'thru_user_id';\nconst TOKEN_ACCOUNT_KEY = 'thru_token_account';\n\nexport async function storePasskeyMetadata(metadata: PasskeyMetadata): Promise<void> {\n await Promise.all([\n SecureStore.setItemAsync(PASSKEY_CREDENTIAL_ID_KEY, metadata.credentialId, SECURE_STORE_OPTS),\n SecureStore.setItemAsync(PASSKEY_PUBLIC_KEY_X_KEY, metadata.publicKeyX, SECURE_STORE_OPTS),\n SecureStore.setItemAsync(PASSKEY_PUBLIC_KEY_Y_KEY, metadata.publicKeyY, SECURE_STORE_OPTS),\n SecureStore.setItemAsync(PASSKEY_RP_ID_KEY, metadata.rpId, SECURE_STORE_OPTS),\n SecureStore.setItemAsync(PASSKEY_LABEL_KEY, metadata.label ?? '', SECURE_STORE_OPTS),\n SecureStore.setItemAsync(PASSKEY_CREATED_AT_KEY, metadata.createdAt, SECURE_STORE_OPTS),\n SecureStore.setItemAsync(PASSKEY_LAST_USED_AT_KEY, metadata.lastUsedAt, SECURE_STORE_OPTS),\n ]);\n}\n\nexport async function getStoredPasskeyMetadata(): Promise<PasskeyMetadata | null> {\n const credentialId = await SecureStore.getItemAsync(PASSKEY_CREDENTIAL_ID_KEY);\n if (!credentialId) return null;\n\n const [publicKeyX, publicKeyY, rpId, label, createdAt, lastUsedAt] = await Promise.all([\n SecureStore.getItemAsync(PASSKEY_PUBLIC_KEY_X_KEY),\n SecureStore.getItemAsync(PASSKEY_PUBLIC_KEY_Y_KEY),\n SecureStore.getItemAsync(PASSKEY_RP_ID_KEY),\n SecureStore.getItemAsync(PASSKEY_LABEL_KEY),\n SecureStore.getItemAsync(PASSKEY_CREATED_AT_KEY),\n SecureStore.getItemAsync(PASSKEY_LAST_USED_AT_KEY),\n ]);\n\n if (!rpId || !createdAt) return null;\n\n return {\n credentialId,\n publicKeyX: publicKeyX ?? '',\n publicKeyY: publicKeyY ?? '',\n rpId,\n label: label || undefined,\n createdAt,\n lastUsedAt: lastUsedAt ?? createdAt,\n };\n}\n\nexport async function touchPasskeyLastUsedAt(lastUsedAt = new Date().toISOString()): Promise<string> {\n await SecureStore.setItemAsync(PASSKEY_LAST_USED_AT_KEY, lastUsedAt, SECURE_STORE_OPTS);\n return lastUsedAt;\n}\n\nexport async function hasStoredPasskey(): Promise<boolean> {\n return (await SecureStore.getItemAsync(PASSKEY_CREDENTIAL_ID_KEY)) !== null;\n}\n\nexport async function clearPasskeyMetadata(): Promise<void> {\n await Promise.all([\n SecureStore.deleteItemAsync(PASSKEY_CREDENTIAL_ID_KEY),\n SecureStore.deleteItemAsync(PASSKEY_PUBLIC_KEY_X_KEY),\n SecureStore.deleteItemAsync(PASSKEY_PUBLIC_KEY_Y_KEY),\n SecureStore.deleteItemAsync(PASSKEY_RP_ID_KEY),\n SecureStore.deleteItemAsync(PASSKEY_LABEL_KEY),\n SecureStore.deleteItemAsync(PASSKEY_CREATED_AT_KEY),\n SecureStore.deleteItemAsync(PASSKEY_LAST_USED_AT_KEY),\n ]);\n}\n\nexport async function storeWalletInfo(\n address: string,\n userId: string,\n tokenAccountAddress?: string\n): Promise<void> {\n await Promise.all([\n SecureStore.setItemAsync(ADDRESS_KEY, address, SECURE_STORE_OPTS),\n SecureStore.setItemAsync(USER_ID_KEY, userId, SECURE_STORE_OPTS),\n tokenAccountAddress\n ? SecureStore.setItemAsync(TOKEN_ACCOUNT_KEY, tokenAccountAddress, SECURE_STORE_OPTS)\n : SecureStore.deleteItemAsync(TOKEN_ACCOUNT_KEY),\n ]);\n}\n\nexport async function hasStoredWallet(): Promise<boolean> {\n return (await SecureStore.getItemAsync(ADDRESS_KEY)) !== null;\n}\n\nexport async function getStoredAddress(): Promise<string | null> {\n return SecureStore.getItemAsync(ADDRESS_KEY);\n}\n\nexport async function getStoredUserId(): Promise<string | null> {\n return SecureStore.getItemAsync(USER_ID_KEY);\n}\n\nexport async function getStoredTokenAccount(): Promise<string | null> {\n return SecureStore.getItemAsync(TOKEN_ACCOUNT_KEY);\n}\n\nexport async function clearSession(): Promise<void> {\n await Promise.all([\n SecureStore.deleteItemAsync(ADDRESS_KEY),\n SecureStore.deleteItemAsync(USER_ID_KEY),\n SecureStore.deleteItemAsync(TOKEN_ACCOUNT_KEY),\n ]);\n}\n","import { create as passkeyCreate, get as passkeyGet } from 'react-native-passkeys';\nimport {\n bytesToBase64Url,\n base64UrlToBytes,\n normalizeLowS,\n parseDerSignature,\n type PasskeySigningResult,\n} from '@thru/programs/passkey-manager';\nimport type {\n DiscoverablePasskeyResult,\n PasskeyMobileConfig,\n PasskeyRegistrationResult,\n} from './types';\n\ntype ProcessLike = typeof globalThis & {\n process?: {\n env?: Record<string, string | undefined>;\n };\n};\n\nfunction getDefaultConfig(config?: PasskeyMobileConfig): Required<PasskeyMobileConfig> {\n const env = (globalThis as ProcessLike).process?.env ?? {};\n\n return {\n rpId: config?.rpId ?? env.EXPO_PUBLIC_PASSKEY_RP_ID ?? 'wallet.thru.org',\n rpName: config?.rpName ?? env.EXPO_PUBLIC_PASSKEY_RP_NAME ?? 'Thru Wallet',\n };\n}\n\nexport async function registerPasskey(\n alias: string,\n userId: string,\n config?: PasskeyMobileConfig\n): Promise<PasskeyRegistrationResult> {\n const { rpId, rpName } = getDefaultConfig(config);\n const challenge = bytesToBase64Url(crypto.getRandomValues(new Uint8Array(32)));\n const userIdB64 = bytesToBase64Url(new TextEncoder().encode(userId));\n\n const result = await passkeyCreate({\n challenge,\n rp: { id: rpId, name: rpName },\n user: { id: userIdB64, name: alias, displayName: alias },\n pubKeyCredParams: [{ type: 'public-key', alg: -7 }],\n authenticatorSelection: {\n authenticatorAttachment: 'platform',\n userVerification: 'required',\n residentKey: 'required',\n },\n attestation: 'none',\n timeout: 60000,\n });\n\n if (!result) {\n throw new Error('Passkey registration was cancelled');\n }\n\n const publicKeyB64 = result.response.getPublicKey?.();\n if (!publicKeyB64) {\n throw new Error('Failed to retrieve public key from registration');\n }\n\n const keyBytes = base64UrlToBytes(publicKeyB64);\n const { x, y } = extractP256Coordinates(keyBytes);\n\n return {\n credentialId: result.id,\n publicKeyX: x,\n publicKeyY: y,\n rpId,\n };\n}\n\nexport async function signWithPasskey(\n credentialId: string,\n challenge: Uint8Array,\n rpId?: string\n): Promise<PasskeySigningResult> {\n const resolvedRpId = rpId ?? getDefaultConfig().rpId;\n const challengeB64 = bytesToBase64Url(challenge);\n\n const result = await passkeyGet({\n challenge: challengeB64,\n rpId: resolvedRpId,\n allowCredentials: [{ type: 'public-key', id: credentialId }],\n userVerification: 'required',\n timeout: 60000,\n });\n\n if (!result) {\n throw new Error('Passkey authentication was cancelled');\n }\n\n const derSignature = base64UrlToBytes(result.response.signature);\n let { r, s } = parseDerSignature(derSignature);\n s = normalizeLowS(s);\n\n return {\n signature: new Uint8Array([...r, ...s]),\n authenticatorData: base64UrlToBytes(result.response.authenticatorData),\n clientDataJSON: base64UrlToBytes(result.response.clientDataJSON),\n signatureR: r,\n signatureS: s,\n };\n}\n\nexport async function authenticateWithDiscoverablePasskey(\n config?: Pick<PasskeyMobileConfig, 'rpId'>\n): Promise<DiscoverablePasskeyResult | null> {\n const { rpId } = getDefaultConfig(config);\n\n try {\n const challenge = bytesToBase64Url(crypto.getRandomValues(new Uint8Array(32)));\n const result = await passkeyGet({\n challenge,\n rpId,\n userVerification: 'required',\n timeout: 60000,\n });\n\n return result ? { credentialId: result.id, rpId } : null;\n } catch {\n return null;\n }\n}\n\nexport function extractP256Coordinates(\n keyBytes: Uint8Array\n): { x: Uint8Array; y: Uint8Array } {\n if (keyBytes.length === 64) {\n return {\n x: keyBytes.slice(0, 32),\n y: keyBytes.slice(32, 64),\n };\n }\n\n if (keyBytes.length === 65 && keyBytes[0] === 0x04) {\n return {\n x: keyBytes.slice(1, 33),\n y: keyBytes.slice(33, 65),\n };\n }\n\n const pointStart = keyBytes.length - 65;\n if (pointStart > 0 && keyBytes[pointStart] === 0x04) {\n return {\n x: keyBytes.slice(pointStart + 1, pointStart + 33),\n y: keyBytes.slice(pointStart + 33, pointStart + 65),\n };\n }\n\n throw new Error(\n `Unsupported public key format (${keyBytes.length} bytes). Expected raw X||Y (64), uncompressed point (65), or SPKI DER (91).`\n );\n}\n"],"mappings":"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","names":[]}