@thru/passkey 0.2.28 → 0.2.29

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/auth.cjs CHANGED
@@ -48,7 +48,7 @@ var import_passkey_manager = require("@thru/programs/passkey-manager");
48
48
  function getDefaultConfig(config) {
49
49
  const env = globalThis.process?.env ?? {};
50
50
  return {
51
- rpId: config?.rpId ?? env.EXPO_PUBLIC_PASSKEY_RP_ID ?? "wallet.thru.org",
51
+ rpId: config?.rpId ?? env.EXPO_PUBLIC_PASSKEY_RP_ID ?? "app.tid.sh",
52
52
  rpName: config?.rpName ?? env.EXPO_PUBLIC_PASSKEY_RP_NAME ?? "Thru Wallet"
53
53
  };
54
54
  }
package/dist/auth.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/auth/index.ts","../src/auth/execute-tx.ts","../src/mobile/passkey.ts","../src/mobile/storage.ts","../src/auth/add-device.ts","../src/auth/use-passkey-auth.ts","../src/mobile/errors.ts"],"sourcesContent":["export type {\n PasskeyApiUser,\n PasskeyAuthApiResponse,\n PasskeyUser,\n PasskeyAuthConfig,\n PasskeyAuthState,\n PasskeyAuthActions,\n PasskeyAuthStore,\n PasskeyAuthBoundStore,\n} from './types';\n\nexport { executePasskeyTransaction } from './execute-tx';\n\nexport { addAuthorityToAccount, addDeviceToAccount } from './add-device';\nexport type {\n AddAuthorityParams,\n AddDeviceParams,\n AddDeviceResult,\n AnyThruClient,\n PasskeyChallengeSigner,\n TxExecutor,\n TxExecutorParams,\n TxExecutorResult,\n} from './add-device';\n\nexport {\n createPasskeyAuthStore,\n getPasskeyAuthStore,\n usePasskeyAuth,\n} from './use-passkey-auth';\n","import { base64UrlToBytes, bytesToBase64, bytesToHex } from '@thru/programs/passkey-manager';\nimport { signWithPasskey } from '../mobile/passkey';\nimport { touchPasskeyLastUsedAt } from '../mobile/storage';\n\nasync function readJson(response: Response): Promise<Record<string, unknown>> {\n try {\n return (await response.json()) as Record<string, unknown>;\n } catch {\n throw new Error(`Non-JSON response (HTTP ${response.status})`);\n }\n}\n\nexport async function executePasskeyTransaction<\n P extends Record<string, unknown>,\n R\n>(opts: {\n challengeUrl: string;\n submitUrl: string;\n params: P;\n credentialId: string;\n rpId: string;\n}): Promise<R> {\n let challengeRes: Response;\n try {\n challengeRes = await fetch(opts.challengeUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(opts.params),\n });\n } catch {\n throw new Error('Network request failed (challenge)');\n }\n\n const challengeData = await readJson(challengeRes);\n if (!challengeRes.ok || challengeData.success !== true) {\n throw new Error(\n typeof challengeData.error === 'string'\n ? challengeData.error\n : 'Failed to get challenge'\n );\n }\n\n if (typeof challengeData.challenge !== 'string') {\n throw new Error('Challenge response did not include a challenge');\n }\n\n const challengeBytes = base64UrlToBytes(challengeData.challenge);\n const signature = await signWithPasskey(\n opts.credentialId,\n challengeBytes,\n opts.rpId\n );\n await touchPasskeyLastUsedAt().catch((error) => {\n console.warn('Failed to update passkey last-used timestamp:', error);\n });\n\n const { success: _success, error: _error, ...challengeFields } = challengeData;\n\n let submitRes: Response;\n try {\n submitRes = await fetch(opts.submitUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n ...opts.params,\n ...challengeFields,\n signatureR: bytesToHex(signature.signatureR),\n signatureS: bytesToHex(signature.signatureS),\n authenticatorData: bytesToBase64(signature.authenticatorData),\n clientDataJSON: bytesToBase64(signature.clientDataJSON),\n }),\n });\n } catch {\n throw new Error('Network request failed (submit)');\n }\n\n const submitData = await readJson(submitRes);\n if (!submitRes.ok || submitData.success !== true) {\n throw new Error(\n typeof submitData.error === 'string'\n ? submitData.error\n : 'Failed to submit transaction'\n );\n }\n\n return submitData as R;\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","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","/* Add-passkey-to-account transaction builder, lifted from\n `web/wallet-auth-manager/app/page.tsx` (`runValidateThen`,\n `handleSubmitAddPasskey`) so the wallet's `/embedded` post-connect\n step can reuse the exact same flow.\n\n Builds the on-chain transaction:\n VALIDATE(existingAuthority -> ADD_AUTHORITY(newPasskey))\n or VALIDATE(existingAuthority -> multicall[ADD_AUTHORITY, REGISTER_CREDENTIAL])\n asks the caller's existing passkey to sign the challenge, then asks\n the caller's wallet signer to sign the assembled transaction, sends\n it, and returns the result. */\n\nimport {\n type Authority,\n type AuthorityRecord,\n buildAccountContext,\n createAuthorityRecord,\n createCredentialLookupSeed,\n createValidateChallenge,\n decodeAddress,\n deriveWalletAddress,\n encodeAddAuthorityInstruction,\n encodeLegacyAddAuthorityInstruction,\n encodeRegisterCredentialInstruction,\n encodeValidateInstruction,\n parseWalletAuthorities,\n type ParsedAuthority,\n type WalletSigner,\n} from \"@thru/programs/passkey-manager\";\nimport {\n MULTICALL_PROGRAM_PUBKEY,\n buildMulticallInstruction,\n} from \"@thru/programs/multicall\";\n\n/** Minimal shape required from a passkey signer. Both web's\n `signWithDiscoverablePasskey`/`signWithPasskey` and mobile's\n counterparts conform. */\nexport interface PasskeyChallengeSigner {\n signChallenge: (challenge: Uint8Array) => Promise<{\n signatureR: Uint8Array;\n signatureS: Uint8Array;\n authenticatorData: Uint8Array;\n clientDataJSON: Uint8Array;\n }>;\n}\n\n/** Minimal shape required from a Thru chain client. Loosely-typed\n because @thru/sdk's DTS emit is currently broken in this\n repo. The caller passes the real Thru and we narrow operationally. */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyThruClient = any;\n\nexport interface AddDeviceParams {\n /** Loosely-typed Thru chain client (`@thru/sdk/client`). */\n thru: AnyThruClient;\n /** Wallet (the on-chain WalletAccount) to attach the passkey to. */\n walletAddress: string;\n /** Index of the existing authority that approves this change. Must\n currently be a passkey authority. */\n authIdx: number;\n /** New passkey to attach. tag = 1 (passkey). */\n newAuthority: Authority;\n newAuthorityRecord?: AuthorityRecord;\n /** Optional credential-lookup registration so the new passkey is\n discoverable on subsequent sign-ins. */\n credentialId?: Uint8Array;\n walletName?: string;\n /** Existing-passkey challenge signer (web or mobile). */\n passkey: PasskeyChallengeSigner;\n /** Wallet transaction signer that returns base64(signed bytes). */\n walletSigner: WalletSigner;\n /** Passkey program address (base58). */\n programAddress: string;\n /** Sign-and-send executor (lifted from passkey-transaction.ts in the\n wallet-auth-manager - wallet apps own this because it depends on\n the `Thru` client's transaction builder). */\n executor: TxExecutor;\n /** Optional status callback so UIs can show progress. */\n onStatus?: (message: string) => void;\n}\n\nexport interface TxExecutorParams {\n thru: AnyThruClient;\n walletSigner: WalletSigner;\n instructionData: Uint8Array;\n readWriteAddresses: string[];\n readOnlyAddresses: string[];\n label: string;\n}\n\nexport interface TxExecutorResult {\n signature: string;\n /** Loosely-typed because @thru/sdk types aren't available. */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n execution: any;\n}\n\nexport type TxExecutor = (\n params: TxExecutorParams,\n) => Promise<TxExecutorResult>;\n\nexport interface AddDeviceResult extends TxExecutorResult {\n /** The new passkey's authority index after the transaction lands. */\n newAuthorityIdx: number;\n}\n\nexport interface AddAuthorityParams\n extends Omit<AddDeviceParams, \"newAuthority\" | \"newAuthorityRecord\" | \"credentialId\" | \"walletName\"> {\n /** Complete authority record to append. */\n authorityRecord: AuthorityRecord;\n}\n\n/**\n * Run VALIDATE + ADD_AUTHORITY [+ REGISTER_CREDENTIAL] to attach a new\n * passkey to an on-chain WalletAccount.\n */\nexport async function addDeviceToAccount(\n params: AddDeviceParams,\n): Promise<AddDeviceResult> {\n return addAuthorityToAccount({\n ...params,\n authorityRecord:\n params.newAuthorityRecord ?? createAuthorityRecord(params.newAuthority),\n });\n}\n\n/**\n * Run VALIDATE + ADD_AUTHORITY to attach a complete authority record to an\n * on-chain WalletAccount.\n */\nexport async function addAuthorityToAccount(\n params: AddAuthorityParams & Pick<AddDeviceParams, \"credentialId\" | \"walletName\">,\n): Promise<AddDeviceResult> {\n const status = params.onStatus ?? (() => {});\n\n const walletAccount = await params.thru.accounts.get(params.walletAddress);\n const walletData: Uint8Array | undefined = walletAccount?.data?.data;\n if (!walletData) {\n throw new Error(\"Wallet account data missing\");\n }\n\n const parsed = parseWalletAuthorities(walletData);\n const authorizing: ParsedAuthority | undefined =\n parsed.authorities[params.authIdx];\n if (!authorizing) {\n throw new Error(\"Authorization index out of bounds\");\n }\n if (authorizing.kind !== \"passkey\") {\n throw new Error(\n \"addDeviceToAccount currently requires a passkey authority for VALIDATE\",\n );\n }\n\n /* The new authority will land at the next free slot. */\n const newAuthorityIdx = parsed.authorities.length;\n\n let readWriteAccounts: Uint8Array[] = [];\n let lookupSeed: Uint8Array | undefined;\n let lookupAddressBytes: Uint8Array | undefined;\n let lookupProof: Uint8Array | undefined;\n\n if (params.credentialId) {\n lookupSeed = await createCredentialLookupSeed(params.credentialId);\n lookupAddressBytes = await deriveWalletAddress(\n lookupSeed,\n params.programAddress,\n );\n\n status(\"Fetching state proof for credential lookup...\");\n const proofResult = await params.thru.proofs.generate({\n proofType: 1 /* StateProofType.CREATING */,\n address: lookupAddressBytes,\n });\n lookupProof = proofResult.proof;\n readWriteAccounts = [lookupAddressBytes];\n }\n\n const ctx = buildAccountContext({\n walletAddress: params.walletAddress,\n readWriteAccounts,\n readOnlyAccounts: params.credentialId ? [MULTICALL_PROGRAM_PUBKEY] : [],\n programAddress: params.programAddress,\n });\n\n const passkeyProgramPubkey = decodeAddress(params.programAddress);\n const encodeAuthorityInstruction =\n parsed.layout === \"legacyAuthority\"\n ? encodeLegacyAddAuthorityInstruction\n : encodeAddAuthorityInstruction;\n const addAuthorityInstruction = encodeAuthorityInstruction({\n walletAccountIdx: ctx.walletAccountIdx,\n authorityRecord: params.authorityRecord,\n });\n\n let targetProgramIdx = ctx.getAccountIndex(passkeyProgramPubkey);\n let targetInstructionData = addAuthorityInstruction;\n\n if (params.credentialId) {\n if (!lookupSeed || !lookupAddressBytes || !lookupProof) {\n throw new Error(\"Credential lookup proof data missing\");\n }\n\n const registerCredentialInstruction = encodeRegisterCredentialInstruction({\n walletAccountIdx: ctx.walletAccountIdx,\n lookupAccountIdx: ctx.getAccountIndex(lookupAddressBytes),\n seed: lookupSeed,\n stateProof: lookupProof,\n });\n\n targetProgramIdx = ctx.getAccountIndex(MULTICALL_PROGRAM_PUBKEY);\n targetInstructionData = buildMulticallInstruction([\n {\n programIdx: ctx.getAccountIndex(passkeyProgramPubkey),\n instructionData: addAuthorityInstruction,\n },\n {\n programIdx: ctx.getAccountIndex(passkeyProgramPubkey),\n instructionData: registerCredentialInstruction,\n },\n ]);\n }\n\n /* Build the VALIDATE challenge over the target CPI and ask the caller's passkey to sign. */\n const challenge = await createValidateChallenge(\n parsed.nonce,\n ctx.accountAddresses,\n ctx.walletAccountIdx,\n params.authIdx,\n {\n programIdx: targetProgramIdx,\n instructionData: targetInstructionData,\n },\n );\n\n status(\"Waiting for passkey approval...\");\n const signature = await params.passkey.signChallenge(challenge);\n\n const validateInstruction = encodeValidateInstruction({\n walletAccountIdx: ctx.walletAccountIdx,\n authIdx: params.authIdx,\n targetInstruction: {\n programIdx: targetProgramIdx,\n instructionData: targetInstructionData,\n },\n signatureR: signature.signatureR,\n signatureS: signature.signatureS,\n authenticatorData: signature.authenticatorData,\n clientDataJSON: signature.clientDataJSON,\n });\n\n status(\"Sending transaction...\");\n const result = await params.executor({\n thru: params.thru,\n walletSigner: params.walletSigner,\n instructionData: validateInstruction,\n readWriteAddresses: ctx.readWriteAddresses,\n readOnlyAddresses: ctx.readOnlyAddresses,\n label: params.credentialId\n ? \"VALIDATE -> MULTICALL(ADD_AUTHORITY, REGISTER_CREDENTIAL)\"\n : \"VALIDATE -> ADD_AUTHORITY\",\n });\n\n return { ...result, newAuthorityIdx };\n}\n","import { bytesToHex } from '@thru/programs/passkey-manager';\nimport { create } from 'zustand';\nimport { classifyPasskeyError } from '../mobile/errors';\nimport {\n authenticateWithDiscoverablePasskey,\n registerPasskey,\n signWithPasskey,\n} from '../mobile/passkey';\nimport {\n clearPasskeyMetadata,\n clearSession,\n getStoredAddress,\n getStoredPasskeyMetadata,\n getStoredUserId,\n hasStoredPasskey,\n hasStoredWallet,\n storePasskeyMetadata,\n storeWalletInfo,\n touchPasskeyLastUsedAt,\n} from '../mobile/storage';\nimport type {\n PasskeyAuthApiResponse,\n PasskeyAuthBoundStore,\n PasskeyAuthConfig,\n PasskeyAuthStore,\n PasskeyUser,\n} from './types';\n\nconst storeCache = new Map<string, PasskeyAuthBoundStore<any>>();\n\nfunction createStoreKey(config: PasskeyAuthConfig): string {\n return [config.apiUrl, config.alias ?? '', config.rpId ?? '', config.rpName ?? ''].join('::');\n}\n\nfunction buildDisplayName(address: string): string {\n return `${address.slice(0, 8)}...${address.slice(-4)}`;\n}\n\nfunction toPasskeyUser<TExtra>(\n user: PasskeyAuthApiResponse<TExtra>['user']\n): PasskeyUser<TExtra> {\n return {\n id: user.id,\n displayName: buildDisplayName(user.publicKey),\n tokenAccountAddress: user.tokenAccountAddress ?? null,\n extras: user.extras,\n };\n}\n\nasync function readJson<T>(response: Response): Promise<T> {\n return (await response.json()) as T;\n}\n\nasync function postJson<T>(\n url: string,\n body: Record<string, unknown>\n): Promise<T> {\n const response = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n });\n\n const data = await readJson<Record<string, unknown>>(response);\n if (!response.ok || data.success !== true) {\n throw new Error(\n typeof data.error === 'string' ? data.error : 'Request failed'\n );\n }\n\n return data as unknown as T;\n}\n\nasync function getCurrentUser<TExtra>(\n apiUrl: string,\n address: string\n): Promise<PasskeyAuthApiResponse<TExtra> | null> {\n const response = await fetch(`${apiUrl}/auth/me`, {\n headers: {\n 'Content-Type': 'application/json',\n 'x-wallet-address': address,\n },\n });\n\n if (response.status === 404) return null;\n\n const data = await readJson<Record<string, unknown>>(response);\n if (!response.ok || data.success !== true) {\n throw new Error(\n typeof data.error === 'string' ? data.error : 'Failed to fetch current user'\n );\n }\n\n return data as unknown as PasskeyAuthApiResponse<TExtra>;\n}\n\nexport function createPasskeyAuthStore<TExtra = Record<string, never>>(\n config: PasskeyAuthConfig\n): PasskeyAuthBoundStore<TExtra> {\n const resolvedAlias = config.alias ?? 'Thru Wallet';\n\n return create<PasskeyAuthStore<TExtra>>((set, get) => ({\n isAuthenticated: false,\n isLoading: false,\n isInitialized: false,\n hasExistingPasskey: false,\n needsNewPasskey: false,\n error: null,\n user: null,\n address: null,\n activeCredentialId: null,\n\n initialize: async () => {\n try {\n const hasPasskey = await hasStoredPasskey();\n\n if (hasPasskey) {\n const storedAddress = await getStoredAddress();\n if (storedAddress) {\n const user = await Promise.race([\n getCurrentUser<TExtra>(config.apiUrl, storedAddress),\n new Promise<null>((_, reject) =>\n setTimeout(() => reject(new Error('timeout')), 2000)\n ),\n ]).catch(() => undefined);\n\n if (user === null) {\n await clearSession();\n await clearPasskeyMetadata();\n set({ isInitialized: true, hasExistingPasskey: false });\n return;\n }\n } else {\n const metadata = await getStoredPasskeyMetadata();\n if (metadata && !metadata.publicKeyX && !metadata.publicKeyY) {\n await clearPasskeyMetadata();\n set({ isInitialized: true, hasExistingPasskey: false });\n return;\n }\n }\n }\n\n set({ isInitialized: true, hasExistingPasskey: hasPasskey });\n } catch (error) {\n console.error('Failed to initialize passkey auth:', error);\n set({ isInitialized: true, error: 'Failed to initialize wallet' });\n }\n },\n\n createWallet: async () => {\n set({ isLoading: true, error: null, needsNewPasskey: false });\n\n try {\n const tempId = `user-${Date.now()}`;\n const passkeyLabel = resolvedAlias.trim() || 'Thru Wallet';\n const { credentialId, publicKeyX, publicKeyY, rpId } =\n await registerPasskey(passkeyLabel, tempId, {\n rpId: config.rpId,\n rpName: config.rpName,\n });\n\n const now = new Date().toISOString();\n const pubkeyXHex = bytesToHex(publicKeyX);\n const pubkeyYHex = bytesToHex(publicKeyY);\n\n await storePasskeyMetadata({\n credentialId,\n publicKeyX: pubkeyXHex,\n publicKeyY: pubkeyYHex,\n rpId,\n label: passkeyLabel,\n createdAt: now,\n lastUsedAt: now,\n });\n\n const response = await postJson<PasskeyAuthApiResponse<TExtra>>(\n `${config.apiUrl}/auth/register-passkey-wallet`,\n {\n pubkeyX: pubkeyXHex,\n pubkeyY: pubkeyYHex,\n credentialId,\n }\n );\n\n const walletAddress = response.user.publicKey;\n await storeWalletInfo(\n walletAddress,\n response.user.id,\n response.user.tokenAccountAddress ?? undefined\n );\n\n set({\n isLoading: false,\n isAuthenticated: true,\n hasExistingPasskey: true,\n activeCredentialId: credentialId,\n address: walletAddress,\n user: toPasskeyUser(response.user),\n });\n\n return true;\n } catch (error) {\n if (classifyPasskeyError(error) === 'USER_CANCELLED') {\n set({ isLoading: false });\n return false;\n }\n\n console.error('Failed to create passkey wallet:', error);\n set({\n isLoading: false,\n error: error instanceof Error ? error.message : 'Failed to create wallet',\n });\n return false;\n }\n },\n\n unlockWithPasskey: async () => {\n set({ isLoading: true, error: null, needsNewPasskey: false });\n\n try {\n const metadata = await getStoredPasskeyMetadata();\n if (!metadata) throw new Error('No stored passkey found');\n\n await signWithPasskey(\n metadata.credentialId,\n crypto.getRandomValues(new Uint8Array(32)),\n metadata.rpId\n );\n await touchPasskeyLastUsedAt().catch((error) => {\n console.warn('Failed to update passkey last-used timestamp:', error);\n });\n\n const hasWallet = await hasStoredWallet();\n let walletAddress: string;\n let userId: string;\n let tokenAccountAddress: string | undefined;\n let response: PasskeyAuthApiResponse<TExtra> | null = null;\n\n if (hasWallet) {\n const storedAddress = await getStoredAddress();\n const storedUserId = await getStoredUserId();\n if (!storedAddress || !storedUserId) {\n throw new Error('Incomplete wallet data');\n }\n\n walletAddress = storedAddress;\n userId = storedUserId;\n\n const current = await getCurrentUser<TExtra>(config.apiUrl, walletAddress);\n if (current) {\n response = current;\n tokenAccountAddress = current.user.tokenAccountAddress ?? undefined;\n } else if (metadata.publicKeyX && metadata.publicKeyY) {\n response = await postJson<PasskeyAuthApiResponse<TExtra>>(\n `${config.apiUrl}/auth/register-passkey-wallet`,\n {\n pubkeyX: metadata.publicKeyX,\n pubkeyY: metadata.publicKeyY,\n credentialId: metadata.credentialId,\n }\n );\n walletAddress = response.user.publicKey;\n userId = response.user.id;\n tokenAccountAddress = response.user.tokenAccountAddress ?? undefined;\n await storeWalletInfo(walletAddress, userId, tokenAccountAddress);\n } else {\n await clearSession();\n await clearPasskeyMetadata();\n set({ isLoading: false, hasExistingPasskey: false, error: null });\n return false;\n }\n } else if (metadata.publicKeyX && metadata.publicKeyY) {\n response = await postJson<PasskeyAuthApiResponse<TExtra>>(\n `${config.apiUrl}/auth/register-passkey-wallet`,\n {\n pubkeyX: metadata.publicKeyX,\n pubkeyY: metadata.publicKeyY,\n credentialId: metadata.credentialId,\n }\n );\n walletAddress = response.user.publicKey;\n userId = response.user.id;\n tokenAccountAddress = response.user.tokenAccountAddress ?? undefined;\n await storeWalletInfo(walletAddress, userId, tokenAccountAddress);\n } else {\n const recovered = await postJson<PasskeyAuthApiResponse<TExtra>>(\n `${config.apiUrl}/auth/recover-passkey-wallet`,\n { credentialId: metadata.credentialId }\n ).catch(() => null);\n\n if (!recovered) {\n await clearSession();\n await clearPasskeyMetadata();\n set({ isLoading: false, hasExistingPasskey: false, error: null });\n return false;\n }\n\n response = recovered;\n walletAddress = recovered.user.publicKey;\n userId = recovered.user.id;\n tokenAccountAddress = recovered.user.tokenAccountAddress ?? undefined;\n await storeWalletInfo(walletAddress, userId, tokenAccountAddress);\n }\n\n set({\n isLoading: false,\n isAuthenticated: true,\n activeCredentialId: metadata.credentialId,\n address: walletAddress,\n user: response ? toPasskeyUser(response.user) : get().user,\n });\n\n return true;\n } catch (error) {\n console.error('Failed to unlock with passkey:', error);\n const kind = classifyPasskeyError(error);\n\n if (kind === 'USER_CANCELLED') {\n set({ isLoading: false });\n } else if (kind === 'NOT_FOUND') {\n await clearPasskeyMetadata();\n set({ isLoading: false, hasExistingPasskey: false, error: null });\n } else {\n set({\n isLoading: false,\n error: error instanceof Error ? error.message : 'Failed to unlock',\n });\n }\n\n return false;\n }\n },\n\n recoverWithDiscoverablePasskey: async () => {\n set({ isLoading: true, error: null, needsNewPasskey: false });\n\n try {\n const discovered = await authenticateWithDiscoverablePasskey({\n rpId: config.rpId,\n });\n\n if (!discovered) {\n set({ isLoading: false });\n return false;\n }\n\n const response = await postJson<PasskeyAuthApiResponse<TExtra>>(\n `${config.apiUrl}/auth/recover-passkey-wallet`,\n { credentialId: discovered.credentialId }\n ).catch(() => null);\n\n if (!response) {\n set({ isLoading: false, needsNewPasskey: true });\n return false;\n }\n\n const walletAddress = response.user.publicKey;\n const userId = response.user.id;\n const tokenAccountAddress = response.user.tokenAccountAddress ?? undefined;\n const now = new Date().toISOString();\n\n await storePasskeyMetadata({\n credentialId: discovered.credentialId,\n publicKeyX: '',\n publicKeyY: '',\n rpId: discovered.rpId,\n createdAt: now,\n lastUsedAt: now,\n });\n await storeWalletInfo(walletAddress, userId, tokenAccountAddress);\n\n set({\n isLoading: false,\n isAuthenticated: true,\n hasExistingPasskey: true,\n activeCredentialId: discovered.credentialId,\n address: walletAddress,\n user: toPasskeyUser(response.user),\n });\n\n return true;\n } catch (error) {\n console.error('Failed to recover with discoverable passkey:', error);\n set({\n isLoading: false,\n error:\n error instanceof Error ? error.message : 'Failed to recover wallet',\n });\n return false;\n }\n },\n\n logout: async () => {\n try {\n await clearSession();\n } catch (error) {\n console.error('Failed to clear passkey session:', error);\n }\n\n set({\n isAuthenticated: false,\n needsNewPasskey: false,\n user: null,\n address: null,\n activeCredentialId: null,\n });\n },\n\n clearError: () => set({ error: null }),\n dismissNewPasskey: () => set({ needsNewPasskey: false }),\n }));\n}\n\nexport function getPasskeyAuthStore<TExtra = Record<string, never>>(\n config: PasskeyAuthConfig\n): PasskeyAuthBoundStore<TExtra> {\n const key = createStoreKey(config);\n const cached = storeCache.get(key) as PasskeyAuthBoundStore<TExtra> | undefined;\n if (cached) return cached;\n\n const store = createPasskeyAuthStore<TExtra>(config);\n storeCache.set(key, store);\n return store;\n}\n\nexport function usePasskeyAuth<TExtra = Record<string, never>>(\n config: PasskeyAuthConfig\n): PasskeyAuthStore<TExtra> {\n return getPasskeyAuthStore<TExtra>(config)();\n}\n","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"],"mappings":"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","names":["import_passkey_manager","passkeyCreate","passkeyGet","import_passkey_manager","import_passkey_manager","readJson"]}
1
+ {"version":3,"sources":["../src/auth/index.ts","../src/auth/execute-tx.ts","../src/mobile/passkey.ts","../src/mobile/storage.ts","../src/auth/add-device.ts","../src/auth/use-passkey-auth.ts","../src/mobile/errors.ts"],"sourcesContent":["export type {\n PasskeyApiUser,\n PasskeyAuthApiResponse,\n PasskeyUser,\n PasskeyAuthConfig,\n PasskeyAuthState,\n PasskeyAuthActions,\n PasskeyAuthStore,\n PasskeyAuthBoundStore,\n} from './types';\n\nexport { executePasskeyTransaction } from './execute-tx';\n\nexport { addAuthorityToAccount, addDeviceToAccount } from './add-device';\nexport type {\n AddAuthorityParams,\n AddDeviceParams,\n AddDeviceResult,\n AnyThruClient,\n PasskeyChallengeSigner,\n TxExecutor,\n TxExecutorParams,\n TxExecutorResult,\n} from './add-device';\n\nexport {\n createPasskeyAuthStore,\n getPasskeyAuthStore,\n usePasskeyAuth,\n} from './use-passkey-auth';\n","import { base64UrlToBytes, bytesToBase64, bytesToHex } from '@thru/programs/passkey-manager';\nimport { signWithPasskey } from '../mobile/passkey';\nimport { touchPasskeyLastUsedAt } from '../mobile/storage';\n\nasync function readJson(response: Response): Promise<Record<string, unknown>> {\n try {\n return (await response.json()) as Record<string, unknown>;\n } catch {\n throw new Error(`Non-JSON response (HTTP ${response.status})`);\n }\n}\n\nexport async function executePasskeyTransaction<\n P extends Record<string, unknown>,\n R\n>(opts: {\n challengeUrl: string;\n submitUrl: string;\n params: P;\n credentialId: string;\n rpId: string;\n}): Promise<R> {\n let challengeRes: Response;\n try {\n challengeRes = await fetch(opts.challengeUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(opts.params),\n });\n } catch {\n throw new Error('Network request failed (challenge)');\n }\n\n const challengeData = await readJson(challengeRes);\n if (!challengeRes.ok || challengeData.success !== true) {\n throw new Error(\n typeof challengeData.error === 'string'\n ? challengeData.error\n : 'Failed to get challenge'\n );\n }\n\n if (typeof challengeData.challenge !== 'string') {\n throw new Error('Challenge response did not include a challenge');\n }\n\n const challengeBytes = base64UrlToBytes(challengeData.challenge);\n const signature = await signWithPasskey(\n opts.credentialId,\n challengeBytes,\n opts.rpId\n );\n await touchPasskeyLastUsedAt().catch((error) => {\n console.warn('Failed to update passkey last-used timestamp:', error);\n });\n\n const { success: _success, error: _error, ...challengeFields } = challengeData;\n\n let submitRes: Response;\n try {\n submitRes = await fetch(opts.submitUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n ...opts.params,\n ...challengeFields,\n signatureR: bytesToHex(signature.signatureR),\n signatureS: bytesToHex(signature.signatureS),\n authenticatorData: bytesToBase64(signature.authenticatorData),\n clientDataJSON: bytesToBase64(signature.clientDataJSON),\n }),\n });\n } catch {\n throw new Error('Network request failed (submit)');\n }\n\n const submitData = await readJson(submitRes);\n if (!submitRes.ok || submitData.success !== true) {\n throw new Error(\n typeof submitData.error === 'string'\n ? submitData.error\n : 'Failed to submit transaction'\n );\n }\n\n return submitData as R;\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 ?? 'app.tid.sh',\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","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","/* Add-passkey-to-account transaction builder, lifted from\n `web/wallet-auth-manager/app/page.tsx` (`runValidateThen`,\n `handleSubmitAddPasskey`) so the wallet's `/embedded` post-connect\n step can reuse the exact same flow.\n\n Builds the on-chain transaction:\n VALIDATE(existingAuthority -> ADD_AUTHORITY(newPasskey))\n or VALIDATE(existingAuthority -> multicall[ADD_AUTHORITY, REGISTER_CREDENTIAL])\n asks the caller's existing passkey to sign the challenge, then asks\n the caller's wallet signer to sign the assembled transaction, sends\n it, and returns the result. */\n\nimport {\n type Authority,\n type AuthorityRecord,\n buildAccountContext,\n createAuthorityRecord,\n createCredentialLookupSeed,\n createValidateChallenge,\n decodeAddress,\n deriveWalletAddress,\n encodeAddAuthorityInstruction,\n encodeLegacyAddAuthorityInstruction,\n encodeRegisterCredentialInstruction,\n encodeValidateInstruction,\n parseWalletAuthorities,\n type ParsedAuthority,\n type WalletSigner,\n} from \"@thru/programs/passkey-manager\";\nimport {\n MULTICALL_PROGRAM_PUBKEY,\n buildMulticallInstruction,\n} from \"@thru/programs/multicall\";\n\n/** Minimal shape required from a passkey signer. Both web's\n `signWithDiscoverablePasskey`/`signWithPasskey` and mobile's\n counterparts conform. */\nexport interface PasskeyChallengeSigner {\n signChallenge: (challenge: Uint8Array) => Promise<{\n signatureR: Uint8Array;\n signatureS: Uint8Array;\n authenticatorData: Uint8Array;\n clientDataJSON: Uint8Array;\n }>;\n}\n\n/** Minimal shape required from a Thru chain client. Loosely-typed\n because @thru/sdk's DTS emit is currently broken in this\n repo. The caller passes the real Thru and we narrow operationally. */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyThruClient = any;\n\nexport interface AddDeviceParams {\n /** Loosely-typed Thru chain client (`@thru/sdk/client`). */\n thru: AnyThruClient;\n /** Wallet (the on-chain WalletAccount) to attach the passkey to. */\n walletAddress: string;\n /** Index of the existing authority that approves this change. Must\n currently be a passkey authority. */\n authIdx: number;\n /** New passkey to attach. tag = 1 (passkey). */\n newAuthority: Authority;\n newAuthorityRecord?: AuthorityRecord;\n /** Optional credential-lookup registration so the new passkey is\n discoverable on subsequent sign-ins. */\n credentialId?: Uint8Array;\n walletName?: string;\n /** Existing-passkey challenge signer (web or mobile). */\n passkey: PasskeyChallengeSigner;\n /** Wallet transaction signer that returns base64(signed bytes). */\n walletSigner: WalletSigner;\n /** Passkey program address (base58). */\n programAddress: string;\n /** Sign-and-send executor (lifted from passkey-transaction.ts in the\n wallet-auth-manager - wallet apps own this because it depends on\n the `Thru` client's transaction builder). */\n executor: TxExecutor;\n /** Optional status callback so UIs can show progress. */\n onStatus?: (message: string) => void;\n}\n\nexport interface TxExecutorParams {\n thru: AnyThruClient;\n walletSigner: WalletSigner;\n instructionData: Uint8Array;\n readWriteAddresses: string[];\n readOnlyAddresses: string[];\n label: string;\n}\n\nexport interface TxExecutorResult {\n signature: string;\n /** Loosely-typed because @thru/sdk types aren't available. */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n execution: any;\n}\n\nexport type TxExecutor = (\n params: TxExecutorParams,\n) => Promise<TxExecutorResult>;\n\nexport interface AddDeviceResult extends TxExecutorResult {\n /** The new passkey's authority index after the transaction lands. */\n newAuthorityIdx: number;\n}\n\nexport interface AddAuthorityParams\n extends Omit<AddDeviceParams, \"newAuthority\" | \"newAuthorityRecord\" | \"credentialId\" | \"walletName\"> {\n /** Complete authority record to append. */\n authorityRecord: AuthorityRecord;\n}\n\n/**\n * Run VALIDATE + ADD_AUTHORITY [+ REGISTER_CREDENTIAL] to attach a new\n * passkey to an on-chain WalletAccount.\n */\nexport async function addDeviceToAccount(\n params: AddDeviceParams,\n): Promise<AddDeviceResult> {\n return addAuthorityToAccount({\n ...params,\n authorityRecord:\n params.newAuthorityRecord ?? createAuthorityRecord(params.newAuthority),\n });\n}\n\n/**\n * Run VALIDATE + ADD_AUTHORITY to attach a complete authority record to an\n * on-chain WalletAccount.\n */\nexport async function addAuthorityToAccount(\n params: AddAuthorityParams & Pick<AddDeviceParams, \"credentialId\" | \"walletName\">,\n): Promise<AddDeviceResult> {\n const status = params.onStatus ?? (() => {});\n\n const walletAccount = await params.thru.accounts.get(params.walletAddress);\n const walletData: Uint8Array | undefined = walletAccount?.data?.data;\n if (!walletData) {\n throw new Error(\"Wallet account data missing\");\n }\n\n const parsed = parseWalletAuthorities(walletData);\n const authorizing: ParsedAuthority | undefined =\n parsed.authorities[params.authIdx];\n if (!authorizing) {\n throw new Error(\"Authorization index out of bounds\");\n }\n if (authorizing.kind !== \"passkey\") {\n throw new Error(\n \"addDeviceToAccount currently requires a passkey authority for VALIDATE\",\n );\n }\n\n /* The new authority will land at the next free slot. */\n const newAuthorityIdx = parsed.authorities.length;\n\n let readWriteAccounts: Uint8Array[] = [];\n let lookupSeed: Uint8Array | undefined;\n let lookupAddressBytes: Uint8Array | undefined;\n let lookupProof: Uint8Array | undefined;\n\n if (params.credentialId) {\n lookupSeed = await createCredentialLookupSeed(params.credentialId);\n lookupAddressBytes = await deriveWalletAddress(\n lookupSeed,\n params.programAddress,\n );\n\n status(\"Fetching state proof for credential lookup...\");\n const proofResult = await params.thru.proofs.generate({\n proofType: 1 /* StateProofType.CREATING */,\n address: lookupAddressBytes,\n });\n lookupProof = proofResult.proof;\n readWriteAccounts = [lookupAddressBytes];\n }\n\n const ctx = buildAccountContext({\n walletAddress: params.walletAddress,\n readWriteAccounts,\n readOnlyAccounts: params.credentialId ? [MULTICALL_PROGRAM_PUBKEY] : [],\n programAddress: params.programAddress,\n });\n\n const passkeyProgramPubkey = decodeAddress(params.programAddress);\n const encodeAuthorityInstruction =\n parsed.layout === \"legacyAuthority\"\n ? encodeLegacyAddAuthorityInstruction\n : encodeAddAuthorityInstruction;\n const addAuthorityInstruction = encodeAuthorityInstruction({\n walletAccountIdx: ctx.walletAccountIdx,\n authorityRecord: params.authorityRecord,\n });\n\n let targetProgramIdx = ctx.getAccountIndex(passkeyProgramPubkey);\n let targetInstructionData = addAuthorityInstruction;\n\n if (params.credentialId) {\n if (!lookupSeed || !lookupAddressBytes || !lookupProof) {\n throw new Error(\"Credential lookup proof data missing\");\n }\n\n const registerCredentialInstruction = encodeRegisterCredentialInstruction({\n walletAccountIdx: ctx.walletAccountIdx,\n lookupAccountIdx: ctx.getAccountIndex(lookupAddressBytes),\n seed: lookupSeed,\n stateProof: lookupProof,\n });\n\n targetProgramIdx = ctx.getAccountIndex(MULTICALL_PROGRAM_PUBKEY);\n targetInstructionData = buildMulticallInstruction([\n {\n programIdx: ctx.getAccountIndex(passkeyProgramPubkey),\n instructionData: addAuthorityInstruction,\n },\n {\n programIdx: ctx.getAccountIndex(passkeyProgramPubkey),\n instructionData: registerCredentialInstruction,\n },\n ]);\n }\n\n /* Build the VALIDATE challenge over the target CPI and ask the caller's passkey to sign. */\n const challenge = await createValidateChallenge(\n parsed.nonce,\n ctx.accountAddresses,\n ctx.walletAccountIdx,\n params.authIdx,\n {\n programIdx: targetProgramIdx,\n instructionData: targetInstructionData,\n },\n );\n\n status(\"Waiting for passkey approval...\");\n const signature = await params.passkey.signChallenge(challenge);\n\n const validateInstruction = encodeValidateInstruction({\n walletAccountIdx: ctx.walletAccountIdx,\n authIdx: params.authIdx,\n targetInstruction: {\n programIdx: targetProgramIdx,\n instructionData: targetInstructionData,\n },\n signatureR: signature.signatureR,\n signatureS: signature.signatureS,\n authenticatorData: signature.authenticatorData,\n clientDataJSON: signature.clientDataJSON,\n });\n\n status(\"Sending transaction...\");\n const result = await params.executor({\n thru: params.thru,\n walletSigner: params.walletSigner,\n instructionData: validateInstruction,\n readWriteAddresses: ctx.readWriteAddresses,\n readOnlyAddresses: ctx.readOnlyAddresses,\n label: params.credentialId\n ? \"VALIDATE -> MULTICALL(ADD_AUTHORITY, REGISTER_CREDENTIAL)\"\n : \"VALIDATE -> ADD_AUTHORITY\",\n });\n\n return { ...result, newAuthorityIdx };\n}\n","import { bytesToHex } from '@thru/programs/passkey-manager';\nimport { create } from 'zustand';\nimport { classifyPasskeyError } from '../mobile/errors';\nimport {\n authenticateWithDiscoverablePasskey,\n registerPasskey,\n signWithPasskey,\n} from '../mobile/passkey';\nimport {\n clearPasskeyMetadata,\n clearSession,\n getStoredAddress,\n getStoredPasskeyMetadata,\n getStoredUserId,\n hasStoredPasskey,\n hasStoredWallet,\n storePasskeyMetadata,\n storeWalletInfo,\n touchPasskeyLastUsedAt,\n} from '../mobile/storage';\nimport type {\n PasskeyAuthApiResponse,\n PasskeyAuthBoundStore,\n PasskeyAuthConfig,\n PasskeyAuthStore,\n PasskeyUser,\n} from './types';\n\nconst storeCache = new Map<string, PasskeyAuthBoundStore<any>>();\n\nfunction createStoreKey(config: PasskeyAuthConfig): string {\n return [config.apiUrl, config.alias ?? '', config.rpId ?? '', config.rpName ?? ''].join('::');\n}\n\nfunction buildDisplayName(address: string): string {\n return `${address.slice(0, 8)}...${address.slice(-4)}`;\n}\n\nfunction toPasskeyUser<TExtra>(\n user: PasskeyAuthApiResponse<TExtra>['user']\n): PasskeyUser<TExtra> {\n return {\n id: user.id,\n displayName: buildDisplayName(user.publicKey),\n tokenAccountAddress: user.tokenAccountAddress ?? null,\n extras: user.extras,\n };\n}\n\nasync function readJson<T>(response: Response): Promise<T> {\n return (await response.json()) as T;\n}\n\nasync function postJson<T>(\n url: string,\n body: Record<string, unknown>\n): Promise<T> {\n const response = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n });\n\n const data = await readJson<Record<string, unknown>>(response);\n if (!response.ok || data.success !== true) {\n throw new Error(\n typeof data.error === 'string' ? data.error : 'Request failed'\n );\n }\n\n return data as unknown as T;\n}\n\nasync function getCurrentUser<TExtra>(\n apiUrl: string,\n address: string\n): Promise<PasskeyAuthApiResponse<TExtra> | null> {\n const response = await fetch(`${apiUrl}/auth/me`, {\n headers: {\n 'Content-Type': 'application/json',\n 'x-wallet-address': address,\n },\n });\n\n if (response.status === 404) return null;\n\n const data = await readJson<Record<string, unknown>>(response);\n if (!response.ok || data.success !== true) {\n throw new Error(\n typeof data.error === 'string' ? data.error : 'Failed to fetch current user'\n );\n }\n\n return data as unknown as PasskeyAuthApiResponse<TExtra>;\n}\n\nexport function createPasskeyAuthStore<TExtra = Record<string, never>>(\n config: PasskeyAuthConfig\n): PasskeyAuthBoundStore<TExtra> {\n const resolvedAlias = config.alias ?? 'Thru Wallet';\n\n return create<PasskeyAuthStore<TExtra>>((set, get) => ({\n isAuthenticated: false,\n isLoading: false,\n isInitialized: false,\n hasExistingPasskey: false,\n needsNewPasskey: false,\n error: null,\n user: null,\n address: null,\n activeCredentialId: null,\n\n initialize: async () => {\n try {\n const hasPasskey = await hasStoredPasskey();\n\n if (hasPasskey) {\n const storedAddress = await getStoredAddress();\n if (storedAddress) {\n const user = await Promise.race([\n getCurrentUser<TExtra>(config.apiUrl, storedAddress),\n new Promise<null>((_, reject) =>\n setTimeout(() => reject(new Error('timeout')), 2000)\n ),\n ]).catch(() => undefined);\n\n if (user === null) {\n await clearSession();\n await clearPasskeyMetadata();\n set({ isInitialized: true, hasExistingPasskey: false });\n return;\n }\n } else {\n const metadata = await getStoredPasskeyMetadata();\n if (metadata && !metadata.publicKeyX && !metadata.publicKeyY) {\n await clearPasskeyMetadata();\n set({ isInitialized: true, hasExistingPasskey: false });\n return;\n }\n }\n }\n\n set({ isInitialized: true, hasExistingPasskey: hasPasskey });\n } catch (error) {\n console.error('Failed to initialize passkey auth:', error);\n set({ isInitialized: true, error: 'Failed to initialize wallet' });\n }\n },\n\n createWallet: async () => {\n set({ isLoading: true, error: null, needsNewPasskey: false });\n\n try {\n const tempId = `user-${Date.now()}`;\n const passkeyLabel = resolvedAlias.trim() || 'Thru Wallet';\n const { credentialId, publicKeyX, publicKeyY, rpId } =\n await registerPasskey(passkeyLabel, tempId, {\n rpId: config.rpId,\n rpName: config.rpName,\n });\n\n const now = new Date().toISOString();\n const pubkeyXHex = bytesToHex(publicKeyX);\n const pubkeyYHex = bytesToHex(publicKeyY);\n\n await storePasskeyMetadata({\n credentialId,\n publicKeyX: pubkeyXHex,\n publicKeyY: pubkeyYHex,\n rpId,\n label: passkeyLabel,\n createdAt: now,\n lastUsedAt: now,\n });\n\n const response = await postJson<PasskeyAuthApiResponse<TExtra>>(\n `${config.apiUrl}/auth/register-passkey-wallet`,\n {\n pubkeyX: pubkeyXHex,\n pubkeyY: pubkeyYHex,\n credentialId,\n }\n );\n\n const walletAddress = response.user.publicKey;\n await storeWalletInfo(\n walletAddress,\n response.user.id,\n response.user.tokenAccountAddress ?? undefined\n );\n\n set({\n isLoading: false,\n isAuthenticated: true,\n hasExistingPasskey: true,\n activeCredentialId: credentialId,\n address: walletAddress,\n user: toPasskeyUser(response.user),\n });\n\n return true;\n } catch (error) {\n if (classifyPasskeyError(error) === 'USER_CANCELLED') {\n set({ isLoading: false });\n return false;\n }\n\n console.error('Failed to create passkey wallet:', error);\n set({\n isLoading: false,\n error: error instanceof Error ? error.message : 'Failed to create wallet',\n });\n return false;\n }\n },\n\n unlockWithPasskey: async () => {\n set({ isLoading: true, error: null, needsNewPasskey: false });\n\n try {\n const metadata = await getStoredPasskeyMetadata();\n if (!metadata) throw new Error('No stored passkey found');\n\n await signWithPasskey(\n metadata.credentialId,\n crypto.getRandomValues(new Uint8Array(32)),\n metadata.rpId\n );\n await touchPasskeyLastUsedAt().catch((error) => {\n console.warn('Failed to update passkey last-used timestamp:', error);\n });\n\n const hasWallet = await hasStoredWallet();\n let walletAddress: string;\n let userId: string;\n let tokenAccountAddress: string | undefined;\n let response: PasskeyAuthApiResponse<TExtra> | null = null;\n\n if (hasWallet) {\n const storedAddress = await getStoredAddress();\n const storedUserId = await getStoredUserId();\n if (!storedAddress || !storedUserId) {\n throw new Error('Incomplete wallet data');\n }\n\n walletAddress = storedAddress;\n userId = storedUserId;\n\n const current = await getCurrentUser<TExtra>(config.apiUrl, walletAddress);\n if (current) {\n response = current;\n tokenAccountAddress = current.user.tokenAccountAddress ?? undefined;\n } else if (metadata.publicKeyX && metadata.publicKeyY) {\n response = await postJson<PasskeyAuthApiResponse<TExtra>>(\n `${config.apiUrl}/auth/register-passkey-wallet`,\n {\n pubkeyX: metadata.publicKeyX,\n pubkeyY: metadata.publicKeyY,\n credentialId: metadata.credentialId,\n }\n );\n walletAddress = response.user.publicKey;\n userId = response.user.id;\n tokenAccountAddress = response.user.tokenAccountAddress ?? undefined;\n await storeWalletInfo(walletAddress, userId, tokenAccountAddress);\n } else {\n await clearSession();\n await clearPasskeyMetadata();\n set({ isLoading: false, hasExistingPasskey: false, error: null });\n return false;\n }\n } else if (metadata.publicKeyX && metadata.publicKeyY) {\n response = await postJson<PasskeyAuthApiResponse<TExtra>>(\n `${config.apiUrl}/auth/register-passkey-wallet`,\n {\n pubkeyX: metadata.publicKeyX,\n pubkeyY: metadata.publicKeyY,\n credentialId: metadata.credentialId,\n }\n );\n walletAddress = response.user.publicKey;\n userId = response.user.id;\n tokenAccountAddress = response.user.tokenAccountAddress ?? undefined;\n await storeWalletInfo(walletAddress, userId, tokenAccountAddress);\n } else {\n const recovered = await postJson<PasskeyAuthApiResponse<TExtra>>(\n `${config.apiUrl}/auth/recover-passkey-wallet`,\n { credentialId: metadata.credentialId }\n ).catch(() => null);\n\n if (!recovered) {\n await clearSession();\n await clearPasskeyMetadata();\n set({ isLoading: false, hasExistingPasskey: false, error: null });\n return false;\n }\n\n response = recovered;\n walletAddress = recovered.user.publicKey;\n userId = recovered.user.id;\n tokenAccountAddress = recovered.user.tokenAccountAddress ?? undefined;\n await storeWalletInfo(walletAddress, userId, tokenAccountAddress);\n }\n\n set({\n isLoading: false,\n isAuthenticated: true,\n activeCredentialId: metadata.credentialId,\n address: walletAddress,\n user: response ? toPasskeyUser(response.user) : get().user,\n });\n\n return true;\n } catch (error) {\n console.error('Failed to unlock with passkey:', error);\n const kind = classifyPasskeyError(error);\n\n if (kind === 'USER_CANCELLED') {\n set({ isLoading: false });\n } else if (kind === 'NOT_FOUND') {\n await clearPasskeyMetadata();\n set({ isLoading: false, hasExistingPasskey: false, error: null });\n } else {\n set({\n isLoading: false,\n error: error instanceof Error ? error.message : 'Failed to unlock',\n });\n }\n\n return false;\n }\n },\n\n recoverWithDiscoverablePasskey: async () => {\n set({ isLoading: true, error: null, needsNewPasskey: false });\n\n try {\n const discovered = await authenticateWithDiscoverablePasskey({\n rpId: config.rpId,\n });\n\n if (!discovered) {\n set({ isLoading: false });\n return false;\n }\n\n const response = await postJson<PasskeyAuthApiResponse<TExtra>>(\n `${config.apiUrl}/auth/recover-passkey-wallet`,\n { credentialId: discovered.credentialId }\n ).catch(() => null);\n\n if (!response) {\n set({ isLoading: false, needsNewPasskey: true });\n return false;\n }\n\n const walletAddress = response.user.publicKey;\n const userId = response.user.id;\n const tokenAccountAddress = response.user.tokenAccountAddress ?? undefined;\n const now = new Date().toISOString();\n\n await storePasskeyMetadata({\n credentialId: discovered.credentialId,\n publicKeyX: '',\n publicKeyY: '',\n rpId: discovered.rpId,\n createdAt: now,\n lastUsedAt: now,\n });\n await storeWalletInfo(walletAddress, userId, tokenAccountAddress);\n\n set({\n isLoading: false,\n isAuthenticated: true,\n hasExistingPasskey: true,\n activeCredentialId: discovered.credentialId,\n address: walletAddress,\n user: toPasskeyUser(response.user),\n });\n\n return true;\n } catch (error) {\n console.error('Failed to recover with discoverable passkey:', error);\n set({\n isLoading: false,\n error:\n error instanceof Error ? error.message : 'Failed to recover wallet',\n });\n return false;\n }\n },\n\n logout: async () => {\n try {\n await clearSession();\n } catch (error) {\n console.error('Failed to clear passkey session:', error);\n }\n\n set({\n isAuthenticated: false,\n needsNewPasskey: false,\n user: null,\n address: null,\n activeCredentialId: null,\n });\n },\n\n clearError: () => set({ error: null }),\n dismissNewPasskey: () => set({ needsNewPasskey: false }),\n }));\n}\n\nexport function getPasskeyAuthStore<TExtra = Record<string, never>>(\n config: PasskeyAuthConfig\n): PasskeyAuthBoundStore<TExtra> {\n const key = createStoreKey(config);\n const cached = storeCache.get(key) as PasskeyAuthBoundStore<TExtra> | undefined;\n if (cached) return cached;\n\n const store = createPasskeyAuthStore<TExtra>(config);\n storeCache.set(key, store);\n return store;\n}\n\nexport function usePasskeyAuth<TExtra = Record<string, never>>(\n config: PasskeyAuthConfig\n): PasskeyAuthStore<TExtra> {\n return getPasskeyAuthStore<TExtra>(config)();\n}\n","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"],"mappings":"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","names":["import_passkey_manager","passkeyCreate","passkeyGet","import_passkey_manager","import_passkey_manager","readJson"]}
package/dist/auth.js CHANGED
@@ -13,7 +13,7 @@ import {
13
13
  storePasskeyMetadata,
14
14
  storeWalletInfo,
15
15
  touchPasskeyLastUsedAt
16
- } from "./chunk-ZNBMADOM.js";
16
+ } from "./chunk-L53S4RKQ.js";
17
17
  import {
18
18
  addAuthorityToAccount,
19
19
  addDeviceToAccount
@@ -128,7 +128,7 @@ import {
128
128
  function getDefaultConfig(config) {
129
129
  const env = globalThis.process?.env ?? {};
130
130
  return {
131
- rpId: config?.rpId ?? env.EXPO_PUBLIC_PASSKEY_RP_ID ?? "wallet.thru.org",
131
+ rpId: config?.rpId ?? env.EXPO_PUBLIC_PASSKEY_RP_ID ?? "app.tid.sh",
132
132
  rpName: config?.rpName ?? env.EXPO_PUBLIC_PASSKEY_RP_NAME ?? "Thru Wallet"
133
133
  };
134
134
  }
@@ -247,4 +247,4 @@ export {
247
247
  authenticateWithDiscoverablePasskey,
248
248
  extractP256Coordinates
249
249
  };
250
- //# sourceMappingURL=chunk-ZNBMADOM.js.map
250
+ //# sourceMappingURL=chunk-L53S4RKQ.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 ?? 'app.tid.sh',\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":[]}
package/dist/mobile.cjs CHANGED
@@ -178,7 +178,7 @@ var import_passkey_manager = require("@thru/programs/passkey-manager");
178
178
  function getDefaultConfig(config) {
179
179
  const env = globalThis.process?.env ?? {};
180
180
  return {
181
- rpId: config?.rpId ?? env.EXPO_PUBLIC_PASSKEY_RP_ID ?? "wallet.thru.org",
181
+ rpId: config?.rpId ?? env.EXPO_PUBLIC_PASSKEY_RP_ID ?? "app.tid.sh",
182
182
  rpName: config?.rpName ?? env.EXPO_PUBLIC_PASSKEY_RP_NAME ?? "Thru Wallet"
183
183
  };
184
184
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/mobile/index.ts","../src/mobile/errors.ts","../src/mobile/storage.ts","../src/mobile/passkey.ts"],"sourcesContent":["export type {\n PasskeyMetadata,\n PasskeySigningResult,\n PasskeyMobileConfig,\n PasskeyRegistrationResult,\n DiscoverablePasskeyResult,\n StoredPasskeySigningResult,\n} from './types';\n\nexport { classifyPasskeyError, type PasskeyErrorKind } from './errors';\n\nexport { bytesToBase64 } from '@thru/programs/passkey-manager';\n\nexport {\n storePasskeyMetadata,\n touchPasskeyLastUsedAt,\n getStoredPasskeyMetadata,\n hasStoredPasskey,\n clearPasskeyMetadata,\n storeWalletInfo,\n getStoredAddress,\n getStoredUserId,\n getStoredTokenAccount,\n hasStoredWallet,\n clearSession,\n} from './storage';\n\nexport {\n registerPasskey,\n signWithPasskey,\n authenticateWithDiscoverablePasskey,\n extractP256Coordinates,\n} from './passkey';\n","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":["import_passkey_manager","passkeyCreate","passkeyGet"]}
1
+ {"version":3,"sources":["../src/mobile/index.ts","../src/mobile/errors.ts","../src/mobile/storage.ts","../src/mobile/passkey.ts"],"sourcesContent":["export type {\n PasskeyMetadata,\n PasskeySigningResult,\n PasskeyMobileConfig,\n PasskeyRegistrationResult,\n DiscoverablePasskeyResult,\n StoredPasskeySigningResult,\n} from './types';\n\nexport { classifyPasskeyError, type PasskeyErrorKind } from './errors';\n\nexport { bytesToBase64 } from '@thru/programs/passkey-manager';\n\nexport {\n storePasskeyMetadata,\n touchPasskeyLastUsedAt,\n getStoredPasskeyMetadata,\n hasStoredPasskey,\n clearPasskeyMetadata,\n storeWalletInfo,\n getStoredAddress,\n getStoredUserId,\n getStoredTokenAccount,\n hasStoredWallet,\n clearSession,\n} from './storage';\n\nexport {\n registerPasskey,\n signWithPasskey,\n authenticateWithDiscoverablePasskey,\n extractP256Coordinates,\n} from './passkey';\n","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 ?? 'app.tid.sh',\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":["import_passkey_manager","passkeyCreate","passkeyGet"]}
package/dist/mobile.js CHANGED
@@ -15,7 +15,7 @@ import {
15
15
  storePasskeyMetadata,
16
16
  storeWalletInfo,
17
17
  touchPasskeyLastUsedAt
18
- } from "./chunk-ZNBMADOM.js";
18
+ } from "./chunk-L53S4RKQ.js";
19
19
 
20
20
  // src/mobile/index.ts
21
21
  import { bytesToBase64 } from "@thru/programs/passkey-manager";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thru/passkey",
3
- "version": "0.2.28",
3
+ "version": "0.2.29",
4
4
  "type": "module",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",
@@ -43,8 +43,8 @@
43
43
  }
44
44
  },
45
45
  "dependencies": {
46
- "@thru/programs": "0.2.28",
47
- "@thru/sdk": "0.2.28"
46
+ "@thru/sdk": "0.2.29",
47
+ "@thru/programs": "0.2.29"
48
48
  },
49
49
  "peerDependencies": {
50
50
  "expo-secure-store": "*",
@@ -22,7 +22,7 @@ function getDefaultConfig(config?: PasskeyMobileConfig): Required<PasskeyMobileC
22
22
  const env = (globalThis as ProcessLike).process?.env ?? {};
23
23
 
24
24
  return {
25
- rpId: config?.rpId ?? env.EXPO_PUBLIC_PASSKEY_RP_ID ?? 'wallet.thru.org',
25
+ rpId: config?.rpId ?? env.EXPO_PUBLIC_PASSKEY_RP_ID ?? 'app.tid.sh',
26
26
  rpName: config?.rpName ?? env.EXPO_PUBLIC_PASSKEY_RP_NAME ?? 'Thru Wallet',
27
27
  };
28
28
  }
@@ -1 +0,0 @@
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":[]}