@provex/extension-react 1.11.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +23 -123
  2. package/dist/ZKTLSContext.cjs +7 -75
  3. package/dist/ZKTLSContext.cjs.map +1 -1
  4. package/dist/ZKTLSContext.d.cts +1 -15
  5. package/dist/ZKTLSContext.d.ts +1 -15
  6. package/dist/ZKTLSContext.js +2 -2
  7. package/dist/adapters/extensionEnclave.cjs.map +1 -1
  8. package/dist/adapters/extensionEnclave.js +1 -1
  9. package/dist/capability.cjs +50 -0
  10. package/dist/capability.cjs.map +1 -0
  11. package/dist/capability.d.cts +95 -0
  12. package/dist/capability.d.ts +95 -0
  13. package/dist/capability.js +3 -0
  14. package/dist/capability.js.map +1 -0
  15. package/dist/{chunk-T42E7EM7.js → chunk-B7RU2WKQ.js} +3 -3
  16. package/dist/{chunk-T42E7EM7.js.map → chunk-B7RU2WKQ.js.map} +1 -1
  17. package/dist/chunk-JMVW4H4H.js +44 -0
  18. package/dist/chunk-JMVW4H4H.js.map +1 -0
  19. package/dist/chunk-JU2T2TGY.js +123 -0
  20. package/dist/chunk-JU2T2TGY.js.map +1 -0
  21. package/dist/chunk-VQFWUZNJ.js +59 -0
  22. package/dist/chunk-VQFWUZNJ.js.map +1 -0
  23. package/dist/{chunk-AMJXMSDV.js → chunk-WSLUOLBW.js} +2 -2
  24. package/dist/chunk-WSLUOLBW.js.map +1 -0
  25. package/dist/index.cjs +101 -187
  26. package/dist/index.cjs.map +1 -1
  27. package/dist/index.d.cts +3 -3
  28. package/dist/index.d.ts +3 -3
  29. package/dist/index.js +5 -3
  30. package/dist/useProofCapability.cjs +104 -0
  31. package/dist/useProofCapability.cjs.map +1 -0
  32. package/dist/useProofCapability.d.cts +27 -0
  33. package/dist/useProofCapability.d.ts +27 -0
  34. package/dist/useProofCapability.js +4 -0
  35. package/dist/useProofCapability.js.map +1 -0
  36. package/dist/useZKTLS.cjs +7 -195
  37. package/dist/useZKTLS.cjs.map +1 -1
  38. package/dist/useZKTLS.d.cts +10 -230
  39. package/dist/useZKTLS.d.ts +10 -230
  40. package/dist/useZKTLS.js +1 -1
  41. package/dist/useZKTLSContext.cjs +0 -5
  42. package/dist/useZKTLSContext.cjs.map +1 -1
  43. package/dist/useZKTLSContext.d.cts +0 -2
  44. package/dist/useZKTLSContext.d.ts +0 -2
  45. package/dist/useZKTLSContext.js +2 -2
  46. package/package.json +15 -4
  47. package/skills/extension-react-integration/SKILL.md +16 -73
  48. package/dist/chunk-AMJXMSDV.js.map +0 -1
  49. package/dist/chunk-TAS2MB4S.js +0 -301
  50. package/dist/chunk-TAS2MB4S.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/useZKTLS.ts","../src/ZKTLSContext.tsx","../src/adapters/extensionEnclave.ts"],"names":["parseAbiParameter","encodeAbiParameters","subProviderConfigs","encodePacked","SeriesProgress","useState","useEffect","useMemo","sleep","extensionPlatforms","providers","convertTokenInputToCurrency","normalizeAmount","parseUnits","createContext","useContext","providerConfigs","ManualSelectionRequired","EnclaveCaptureUnavailable","EnclaveCaptureFailed","PaymentAlreadyUsedError","payment","providerRequiresMetadataIndex","requestBuyerTeeAttestation"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * @fileoverview React hook and utilities for PeerAuth browser extension integration.\n *\n * The PeerAuth extension (formerly ZK-TLS) provides secure proof generation\n * for off-chain payment verification. This module provides:\n *\n * 1. Type definitions for extension API (window.peer)\n * 2. useZKTLS hook for React components\n * 3. Utility functions for transaction matching and proof encoding\n *\n * @remarks\n * The extension exposes `window.peer` (or deprecated `window.zktls`) for:\n * - Requesting connection (OAuth-like flow)\n * - Authenticating with payment providers\n * - Generating notarized proofs\n * - Fetching transaction metadata\n *\n * @see {@link ZKTLSContext} for the React context provider\n */\n\nimport { useEffect, useMemo, useState } from \"react\"\nimport { encodeAbiParameters, encodePacked, parseAbiParameter, parseUnits, type Hex } from \"viem\"\nimport { sleep } from \"@provex/utils/time\"\nimport type { IntentStruct } from \"@provex/utils/intent\"\nimport type { TokenInfo } from \"@provex/utils/tokens\"\nimport { extensionPlatforms, providers, subProviderConfigs, type ActionType, type PlatformKey, type ProviderKey, type SubProviderKey } from \"@provex/utils/payment\"\nimport { convertTokenInputToCurrency } from \"@provex/utils/conversionRates\"\n\ndeclare global {\n interface ZKTLS {\n requestConnection(): Promise<boolean>\n checkConnectionStatus(): Promise<Status>\n getVersion(): Promise<string>\n authenticate(inputs: AuthenticationInputs): Promise<void>\n generateProof(inputs: GenerateProofInputs): Promise<GenerateProofResponse>\n fetchProofById(proofId: string): Promise<ProofResponse>\n fetchProofs(): Promise<FetchProofsResponse>\n openSidebar(route: string): Promise<void>\n onMetadataMessage(fn: (data: MetadataMessageResponse) => void): () => void\n /**\n * Trusted-execution on-ramp (PeerAuth v3+). The extension opens the\n * buyer's bank in a new tab, intercepts the authenticated session, calls\n * the zkp2p trusted-execution attestation service, and returns\n * ready-to-send `fulfillIntent` calldata through the callback. Replaces\n * the retired `authenticate` + `generateProof` Reclaim path.\n *\n * Optional: older extension builds predate the on-ramp API, so guard\n * with a runtime presence check (`supportsOnramp`) before calling.\n *\n * @param queryString serialized on-ramp params (see {@link buildOnrampQuery})\n * @param callback invoked once the prepared transaction is ready\n */\n onramp?(\n queryString: string,\n callback: (result: PeerOnrampPreparedTransaction) => void,\n ): void\n /** Retrieve a previously prepared on-ramp transaction by intent hash. */\n getOnrampTransaction?(intentHash: string): Promise<PeerOnrampPreparedTransaction | null>\n }\n interface Window {\n /** @deprecated Use window.peer instead */\n zktls: ZKTLS | undefined\n /** PeerAuth extension API (replaces window.zktls) */\n peer: ZKTLS | undefined\n }\n}\n\n/** the status of the PeerAuth extension */\nexport type Status = 'connected' | 'disconnected' | 'pending'\n\n/** the individual metadata message sent by the PeerAuth extension */\nexport interface MetadataMessage {\n amount: number\n /** Currency code (e.g., 'USD', 'EUR') */\n currency?: string\n /**\n * Date of the transaction.\n * Can be a string in YYYYMMDD format, a number (YYYYMMDD or timestamp), or Date object.\n * The actual type depends on the extension implementation.\n */\n date: string | number | Date\n hidden: boolean\n originalIndex: number\n paymentId: number\n recipient: string\n}\n\n/** the response from the PeerAuth extension when a metadata message is received */\nexport interface MetadataMessageResponse {\n expiresAt: number\n platform: ProviderKey\n requestId: string\n metadata: MetadataMessage[]\n /**\n * Present only when `authenticate` was called with `captureMode: 'buyerTee'`.\n * Carries the bank session already encrypted toward the enclave — feed\n * `encryptedSessionMaterial` (plus the matched transaction's index) to the\n * trusted-execution verify endpoint. No `generateProof` call is involved.\n */\n buyerTeeCapture?: {\n encryptedSessionMaterial: string\n }\n /** Error surfaced by the extension during capture (e.g. missing platform). */\n errorMessage?: string\n}\n\n/** the response from the PeerAuth extension when fetching proofs */\nexport interface FetchProofsResponse {\n notaryRequests: NotaryRequest[]\n}\n\n/** the inputs for the generateProof function */\nexport type GenerateProofInputsAbstracted = {\n platform: PlatformKey\n provider: ProviderKey\n intentHash: Hex\n originalIndex: number\n}\n\n/** the inputs for the generateProof function */\nexport type GenerateProofInputs = {\n platform: ProviderKey\n originalIndex: number\n proofIndex?: number\n intentHash: string\n}\n\n/**\n * inputs for the generate proof function that requires the intent hash\n * as hex to ensure it can be converted to a bigint string accurately\n */\nexport type HexIntentGenerateProofInputs = Exclude<GenerateProofInputs, 'intentHash'> & { intentHash: Hex }\n\n/** the response from the PeerAuth extension when generating a proof */\nexport type GenerateProofResponse = {\n proofId: string\n platform: ProviderKey\n}\n\n/** the inputs for the authenticate function */\nexport type AuthenticationInputs = {\n actionType: ActionType\n platform: PlatformKey\n /**\n * Session capture mode. `'buyerTee'` makes the extension intercept the bank\n * session and return it encrypted toward the trusted-execution enclave in\n * `MetadataMessageResponse.buyerTeeCapture` — the replacement for the retired\n * Reclaim `generateProof` path. Omit for the legacy Reclaim flow. The\n * extension defaults the attestation service URL when this is set.\n */\n captureMode?: 'buyerTee' | 'sellerCredential'\n /**\n * Enclave the extension establishes the Buyer TEE session with and encrypts\n * the captured session material toward (zkp2p 0.6.0 spec §7). Pass explicitly\n * for newer providers — relying on the extension's built-in default is what\n * left non-Revolut rails with \"no buyerTee capture\".\n */\n attestationServiceUrl?: string\n /** Attestation action type; defaults to `actionType` when omitted (spec §2). */\n attestationActionType?: ActionType\n}\n\n/** the response from the PeerAuth extension when fetching a proof */\nexport interface Proof {\n claimInfo: ClaimInfo\n signedClaim: SignedClaim\n isAppclipProof: boolean\n status: string\n}\n\n/** the response from the PeerAuth extension when fetching a proof */\nexport interface NotarizedProof {\n claim: {\n context: string\n epoch: number\n identifier: Hex\n owner: Hex\n parameters: string\n provider: string\n timestampS: number\n },\n signatures: {\n attestorAddress: Hex\n claimSignature: Record<number, number>\n resultSignature: Record<number, number>\n },\n}\n\n/** the claim info for a proof */\nexport interface ClaimInfo {\n provider: string\n parameters: string\n context: string\n}\n\n/** the complete claim data for a proof */\nexport interface CompleteClaimData {\n identifier: Hex\n owner: Hex\n timestampS: number\n epoch: number\n}\n\n/** the signed claim for a proof */\nexport interface SignedClaim {\n claim: CompleteClaimData\n signatures: Hex[]\n}\n\n/** the reclaim proof for a proof */\nexport type ReclaimProof = {\n claimInfo: ClaimInfo\n signedClaim: SignedClaim\n isAppclipProof: boolean\n}\n\n/** the notary request for a proof */\nexport interface NotaryRequest {\n metadata: (string | number)[]\n actionType: ActionType\n id: string\n status: string\n timestamp: number\n proof: NotarizedProof\n}\n\n/** the response from the PeerAuth extension when fetching a proof */\nexport interface ProofResponse {\n notaryRequest: NotaryRequest\n}\n\n/**\n * Ready-to-send transaction the PeerAuth extension hands back once the\n * trusted-execution attestation service has signed the payment. The `data`\n * already embeds the enclave attestation, so the client signs and sends it\n * verbatim — no client-side proof encoding or gate re-signing.\n */\nexport type PeerOnrampPreparedTransaction = {\n intentHash: Hex\n status: 'calldata_ready'\n transaction: {\n to: Hex\n data: Hex\n /** Wei, as a decimal string (the extension keeps it out of JSON-number range). */\n value: string\n chainId: number\n }\n}\n\n/**\n * Structured on-ramp inputs. The extension looks the intent up from\n * `intentHash` (and the optional context fields) to resolve the chain,\n * contracts, and payment platform — we never pass contract addresses.\n */\nexport type PeerExtensionOnrampParams = {\n intentHash: string\n referrer?: string\n referrerLogo?: string\n inputCurrency?: string\n inputAmount?: string | number\n paymentPlatform?: string\n depositId?: string | number | bigint\n toToken?: string\n amountUsdc?: string | number | bigint\n recipientAddress?: string\n}\n\n/**\n * Serialize on-ramp params into the query string the extension's `onramp`\n * entry point expects. Mirrors the mapping `@zkp2p/sdk`'s\n * `peerExtensionSdk.onramp` performs: every defined field becomes one query\n * parameter, `undefined`/`null` fields are dropped, and `bigint` values are\n * stringified.\n */\nexport const buildOnrampQuery = (params: PeerExtensionOnrampParams): string => {\n const search = new URLSearchParams()\n Object.entries(params).forEach(([key, value]) => {\n if (value === undefined || value === null) return\n search.set(key, String(value))\n })\n return search.toString()\n}\n\n/**\n * Wrap a buyerTee capture (from {@link MetadataMessageResponse.buyerTeeCapture})\n * as a `NotaryRequest` so it flows through the existing submit step, which\n * narrows `proof` to a buyerTee proof and routes it to the enclave verify\n * endpoint. The `index` is the matched transaction's `originalIndex` — the\n * extension keys the captured payment on it.\n *\n * This replaces `generateProof` entirely for migrated providers: the session\n * was already captured + encrypted during `authenticate({ captureMode: 'buyerTee' })`.\n */\nexport const buildBuyerTeeNotaryRequest = ({\n encryptedSessionMaterial,\n index,\n actionType,\n}: {\n encryptedSessionMaterial: string\n index: number\n actionType: ActionType\n}): NotaryRequest => ({\n metadata: [],\n actionType,\n id: `buyer-tee-${index}`,\n status: 'success',\n timestamp: 0,\n // The runtime shape is a buyerTee proof, not a Reclaim NotarizedProof; the\n // submit step narrows it via `asBuyerTeeProof` before use.\n proof: {\n proofType: 'buyerTee',\n encryptedSessionMaterial,\n params: { index },\n } as unknown as NotarizedProof,\n})\n\nexport const extensionUrl = 'https://chromewebstore.google.com/detail/ijpgccednehjpeclfcllnjjcmiohdjih'\n\n/** convert a byte array to a hex string */\nexport const byteArrayToHexString = (byteArray: number[]): Hex => {\n return `0x${byteArray\n .map(byte => byte.toString(16).padStart(2, '0'))\n .join('')}`\n}\n\n/** parse a proof object from the PeerAuth extension */\nexport const parseExtensionProof = (proofObject: NotarizedProof) => {\n return {\n claimInfo: {\n provider: proofObject.claim.provider,\n parameters: proofObject.claim.parameters,\n context: proofObject.claim.context\n },\n signedClaim: {\n claim: {\n identifier: proofObject.claim.identifier as Hex,\n owner: proofObject.claim.owner as Hex,\n timestampS: proofObject.claim.timestampS,\n epoch: proofObject.claim.epoch\n },\n signatures: [byteArrayToHexString(Object.values(proofObject.signatures.claimSignature))]\n },\n isAppclipProof: false\n } as ReclaimProof\n}\n\n/** the abi encoding for a proof */\nexport const PROOF_ENCODING = parseAbiParameter(\"((string provider, string parameters, string context) claimInfo, ((bytes32 identifier, address owner, uint32 timestampS, uint32 epoch) claim, bytes[] signatures) signedClaim, bool isAppclipProof)\")\n\n/** encode a single proof as a bytes array */\nexport function encodeProofAsBytes(proof: ReclaimProof): Hex {\n return encodeAbiParameters([PROOF_ENCODING], [proof])\n}\n\n/** encode two proofs to be passed to the underlying sub-provider */\nexport const encodeTwoProofs = (proof1: ReclaimProof, proof2: ReclaimProof) => {\n return encodeAbiParameters([PROOF_ENCODING, PROOF_ENCODING], [proof1, proof2])\n}\n\n/** a high level function to encode a proof for a given provider and sub-provider */\nexport const encodeProof = ({ extensionProofs, subProvider, provider }: {\n extensionProofs: NotarizedProof[],\n subProvider: PlatformKey | null,\n provider: ProviderKey\n}) => {\n const reclaimProofs = extensionProofs.map((p) => parseExtensionProof(p))\n if (provider === 'zelle') {\n // move this to check the blockchain for the payment method\n const paymentMethod = subProviderConfigs![provider]![subProvider as SubProviderKey]!.paymentMethod\n const twoEncoded = reclaimProofs.length === 2\n ? encodeTwoProofs(reclaimProofs[0]!, reclaimProofs[1]!)\n : encodeProofAsBytes(reclaimProofs[0]!)\n // select between various possible sub-providers\n const withPaymentMethod = encodeProofWithPaymentMethod({\n paymentMethod,\n proof: twoEncoded,\n })\n return withPaymentMethod\n }\n const [reclaimProof] = reclaimProofs\n return encodeProofAsBytes(reclaimProof!)\n}\n\n/**\n * wrap a proof with a payment method and proof\n * this allows us to use a single verifier as an entry point for multiple underlying sub-providers\n */\nexport const encodeProofWithPaymentMethod = ({\n proof,\n paymentMethod\n}: {\n proof: Hex,\n paymentMethod: number\n}): Hex => {\n return encodePacked(['uint8', 'bytes'], [paymentMethod, proof])\n}\n\n/** the progress of a proof series */\nexport enum SeriesProgress {\n Generating,\n Polling,\n Complete,\n}\n\nexport type ProgressInfo = {\n progress: SeriesProgress\n total: number\n step: number | null\n id: string | null\n}\n\n/** the mutations for the generate proof series function */\nexport type GenerateProofSeriesMutations = {\n progress?: ({ progress, step, id }: ProgressInfo) => void\n setOwnerName?: (name: string) => void\n}\n\n/** React hook to interact with the PeerAuth extension */\nexport const useZKTLS = () => {\n const [isInitialized, setIsInitialized] = useState(false)\n useEffect(() => {\n const setup = () => {\n setIsInitialized(true)\n }\n const eventName = 'peer#initialized'\n if (typeof window.peer !== 'undefined') {\n // api is available\n setup()\n } else {\n window.addEventListener(eventName, setup)\n return () => {\n window.removeEventListener(eventName, setup)\n }\n }\n }, [])\n return useMemo(() => {\n /** fetch a proof by its id */\n const fetchProofById = async (proofId: string): Promise<NotaryRequest | null> => {\n const proof = await window.peer!.fetchProofById(proofId)\n if (proof && proof.notaryRequest) return proof.notaryRequest\n const proofs = await window.peer!.fetchProofs()\n const proofFromList = proofs.notaryRequests.find((p) => p.id === proofId)\n if (proofFromList) return proofFromList\n return null\n }\n /** wait for a proof to be generated */\n const waitForProof = async (proofId: string, onCurrent?: (notaryRequest: NotaryRequest | null) => void) => {\n let notaryRequest: NotaryRequest | null = null\n do {\n notaryRequest = await fetchProofById(proofId)\n onCurrent?.(notaryRequest)\n await sleep(1_000)\n } while (!notaryRequest || !notaryRequest.status || notaryRequest.status === 'pending')\n if (notaryRequest.status === 'failed' || notaryRequest.status === 'expired' || notaryRequest.status === 'cancelled' || notaryRequest.status === 'error') {\n console.error('[waitForProof] proof terminal state:', JSON.stringify(notaryRequest, null, 2))\n const req = notaryRequest as unknown as Record<string, unknown>\n const detail = req.errorMessage ?? req.error ?? req.message ?? notaryRequest.status\n throw new Error(`Proof generation failed: ${detail}`)\n }\n return notaryRequest\n }\n /** generate a proof */\n const generateProof = async (inputs: HexIntentGenerateProofInputs): Promise<GenerateProofResponse> => {\n return await window.peer!.generateProof({\n proofIndex: 0,\n ...inputs,\n intentHash: BigInt(inputs.intentHash).toString(),\n })\n }\n return {\n /** check if the PeerAuth extension is initialized */\n isInitialized,\n /** request a connection to the PeerAuth extension */\n requestConnection: async () => {\n if (!window.peer) return false\n return window.peer!.requestConnection()\n },\n /**\n * check the connection status of the PeerAuth extension\n * @returns the connection status\n */\n checkConnectionStatus: async () => {\n return await window.peer!.checkConnectionStatus()\n },\n /** get the version of the PeerAuth extension */\n getVersion: async () => {\n return await window.peer?.getVersion()\n },\n /** authenticate with the PeerAuth extension */\n authenticate: async (inputs: AuthenticationInputs) => {\n // Create promise first to avoid race condition where message arrives before resolver is assigned\n let resolve: (value: MetadataMessageResponse) => void\n const promise = new Promise<MetadataMessageResponse>((resolver) => {\n resolve = resolver\n })\n\n // Now set up the listener - resolve is guaranteed to be the real resolver\n const unsub = window.peer!.onMetadataMessage((data) => {\n if (`transfer_${data.platform}` === inputs.actionType) {\n resolve(data)\n }\n })\n\n await window.peer!.authenticate(inputs)\n\n return await promise.then((data) => {\n unsub()\n return data\n })\n },\n /** generate a proof */\n generateProof,\n /** wait for a proof to be generated */\n waitForProof,\n /** generate a proof series */\n generateProofSeries: async (\n inputs: GenerateProofInputsAbstracted,\n { progress: progressCallback }: GenerateProofSeriesMutations = {},\n ): Promise<NotaryRequest[]> => {\n const { platform, provider, intentHash, originalIndex } = inputs\n const args = {\n platform: provider,\n originalIndex,\n intentHash,\n } as const\n // Chase requires 2 proofs (account verification + transaction)\n // Platform is the bank name (e.g., 'chase') from extensionPlatform config\n const isChase = platform === extensionPlatforms.CHASE\n const isZelle = provider === providers.ZELLE\n const expectedTotal = isZelle && isChase ? 2 : 1\n progressCallback?.({ progress: SeriesProgress.Generating, step: 0, id: null, total: expectedTotal })\n const genProofA = await generateProof({ ...args, proofIndex: 0 })\n progressCallback?.({ progress: SeriesProgress.Polling, step: 0, id: genProofA.proofId, total: expectedTotal })\n const proofA = await waitForProof(genProofA.proofId)\n if (!isChase || !isZelle) {\n progressCallback?.({ progress: SeriesProgress.Complete, step: null, id: null, total: expectedTotal })\n return [proofA]\n }\n progressCallback?.({ progress: SeriesProgress.Generating, step: 1, id: null, total: expectedTotal })\n const genProofB = await generateProof({ ...args, proofIndex: 1 })\n progressCallback?.({ progress: SeriesProgress.Polling, step: 1, id: genProofB.proofId, total: expectedTotal })\n const proofB = await waitForProof(genProofB.proofId)\n progressCallback?.({ progress: SeriesProgress.Complete, step: null, id: null, total: expectedTotal })\n return [proofA, proofB]\n },\n /** subscribe to metadata messages */\n onMetadataMessage: (fn: (data: any) => void) => {\n return window.peer!.onMetadataMessage(fn)\n },\n /** fetch a proof by its id */\n fetchProofById,\n /** fetch generated proofs */\n fetchGeneratedProofs: async (genProofResponses: GenerateProofResponse[]) => {\n return await Promise.all(genProofResponses.map((r) => fetchProofById(r.proofId)))\n },\n /** fetch all proofs */\n fetchProofs: async () => {\n return await window.peer!.fetchProofs()\n },\n /** open the PeerAuth sidebar */\n openSidebar: async (route: string) => {\n return await window.peer!.openSidebar(route)\n },\n /** Whether the connected extension exposes the trusted-execution on-ramp. */\n supportsOnramp: (): boolean => typeof window.peer?.onramp === 'function',\n /**\n * Begin the trusted-execution on-ramp and resolve with ready-to-send\n * `fulfillIntent` calldata once the extension has intercepted the bank\n * session and the zkp2p attestation service has signed the payment.\n *\n * The underlying extension API is callback-only with no error channel:\n * the extension surfaces progress and failures in its own sidebar/tab,\n * and only invokes the callback on success. The returned promise\n * therefore stays pending until the prepared transaction arrives — the\n * caller drives the user toward the PeerAuth window and may offer a\n * cancel affordance rather than racing a timeout against a buyer who is\n * still logging into their bank.\n */\n onramp: async (\n params: PeerExtensionOnrampParams,\n ): Promise<PeerOnrampPreparedTransaction> => {\n if (typeof window.peer?.onramp !== 'function') {\n throw new Error(\n 'This PeerAuth extension version does not support the trusted-execution on-ramp. Please update the extension.',\n )\n }\n const queryString = buildOnrampQuery(params)\n return new Promise<PeerOnrampPreparedTransaction>((resolve) => {\n window.peer!.onramp!(queryString, resolve)\n })\n },\n /**\n * Retrieve a previously prepared on-ramp transaction by intent hash.\n * Returns null when the extension lacks the API or has nothing prepared\n * yet — usable as a poll alongside {@link onramp} to recover a result\n * if the one-shot callback is missed.\n */\n getOnrampTransaction: async (\n intentHash: string,\n ): Promise<PeerOnrampPreparedTransaction | null> => {\n if (typeof window.peer?.getOnrampTransaction !== 'function') return null\n return window.peer.getOnrampTransaction(intentHash)\n },\n }\n }, [isInitialized])\n}\n\n/**\n * Find the metadata message that matches the intent by amount.\n * Returns the first (most recent) transaction in the metadata array that matches the expected amount.\n *\n * Simplified matching: just find transactions with the correct amount.\n * The user can manually select if multiple matches exist.\n */\nexport const findMetadataMessage = ({ metadata, intent, token, centIsInt = false }: {\n metadata: MetadataMessage[],\n intent: IntentStruct,\n token: TokenInfo,\n /** @deprecated No longer used - kept for API compatibility */\n recipient?: string,\n centIsInt?: boolean,\n}): MetadataMessage | null => {\n const currencyAmount = convertTokenInputToCurrency({\n token,\n amountOutInt: intent.amount,\n rate: intent.conversionRate,\n })\n /**\n * Normalize an amount from the extension into a bigint in token base units.\n *\n * The extension sends amounts in different formats per provider:\n * - Venmo: `\"- $1.00\"` (formatted dollar string)\n * - Others: `100` (integer cents) or `1.00` (decimal dollars)\n *\n * We detect the format by checking for currency symbols or decimal points\n * in the raw value. If present, the value is already in dollars and we\n * skip the centIsInt division.\n */\n const normalizeAmount = (amount: number | string): bigint => {\n const raw = String(amount)\n const isFormattedDollars = /[^0-9\\-]/.test(raw) && raw.includes('.')\n const cleaned = raw.replace(/[^0-9.]/g, '')\n let value = parseUnits(cleaned, token.decimals)\n if (centIsInt && !isFormattedDollars) {\n value = value / 100n\n }\n return value\n }\n\n // Skip auto-match when manual selection is forced (dev/testing)\n if (typeof window !== 'undefined' && (window as unknown as Record<string, unknown>).__FORCE_MANUAL_TX_SELECT__) {\n return null\n }\n\n // Find the first transaction that matches the amount (first in array = most recent)\n // Note: We ignore the hidden flag - matching is purely by amount\n const match = metadata.find((m) => {\n const converted = normalizeAmount(m.amount)\n return converted === currencyAmount || converted === (currencyAmount * -1n)\n })\n\n if (!match) {\n // Detect 100x scale mismatch — the most common failure mode when centIsInt\n // is wrong for a provider. Fires loudly so it's obvious in dev/staging logs.\n const hundredxMatch = metadata.find((m) => {\n const converted = normalizeAmount(m.amount)\n const abs = converted < 0n ? -converted : converted\n return abs === currencyAmount * 100n || abs * 100n === currencyAmount\n })\n if (hundredxMatch) {\n console.warn(\n `[findMetadataMessage] tx[0] amount=${String(hundredxMatch.amount)} is 100x off from expected ${currencyAmount.toString()} — centIsInt is likely wrong for this provider (currently ${centIsInt})`\n )\n }\n return null\n }\n\n return match\n}\n","/**\n * @fileoverview React context for PeerAuth extension state.\n *\n * Provides global access to the useZKTLS hook state throughout the\n * component tree, avoiding prop drilling for extension status.\n *\n * @see {@link useZKTLS} for the underlying hook\n */\n\nimport { createContext, useContext, type ReactNode } from 'react'\nimport { useZKTLS } from './useZKTLS'\n\n/**\n * Context type derived from useZKTLS hook return value.\n */\ntype ZKTLSContextType = ReturnType<typeof useZKTLS>\n\nexport const ZKTLSContext = createContext<ZKTLSContextType | undefined>(undefined)\n\ninterface ZKTLSProviderProps {\n children: ReactNode\n}\n\n/**\n * Hook to consume the ZKTLS context.\n * Must be used within a ZKTLSProvider.\n *\n * @throws Error if used outside of ZKTLSProvider\n */\nexport function useZKTLSContext() {\n const context = useContext(ZKTLSContext)\n if (context === undefined) {\n throw new Error('useZKTLSContext must be used within a ZKTLSProvider')\n }\n return context\n}\n\nexport function ZKTLSProvider({ children }: ZKTLSProviderProps) {\n const zktlsHook = useZKTLS()\n\n return (\n <ZKTLSContext.Provider value={zktlsHook}>\n {children}\n </ZKTLSContext.Provider>\n )\n}\n","/**\n * @fileoverview Extension + enclave CaptureAdapter (the v1 capture backend).\n *\n * Mirrors the live AuthenticateStep + GenerateProofStep enclave path\n * (AuthenticateStep.tsx:224-281, GenerateProofStep.tsx:237-251) reduced to\n * the buyerTee branch. Talks to an injected `window.peer`-shaped client so\n * the injected-PeerClient seam is preserved exactly.\n */\n\nimport { parseUnits } from 'viem'\nimport type { Hex } from 'viem'\nimport { providerConfigs, providerRequiresMetadataIndex } from '@provex/utils/payment'\nimport type { ProviderKey, SubProviderKey } from '@provex/utils/payment'\nimport type { ChainId } from '@provex/utils/chain'\nimport { convertTokenInputToCurrency } from '@provex/utils/conversionRates'\nimport {\n EnclaveCaptureUnavailable,\n EnclaveCaptureFailed,\n ManualSelectionRequired,\n PaymentAlreadyUsedError,\n asBuyerTeeProof,\n requestBuyerTeeAttestation,\n type CaptureAdapter,\n type CaptureCandidate,\n type CaptureHandle,\n type CaptureRequest,\n type SelectTransaction,\n type VerifiedAttestation,\n} from '@provex/proving'\n\n/** Minimal shape of the metadata response the extension posts back. */\ninterface MetadataResponse {\n platform: string\n metadata: CaptureCandidate[]\n buyerTeeCapture?: { encryptedSessionMaterial: string }\n}\n\n/**\n * zkp2p enclave used for Buyer TEE capture when the caller doesn't override\n * `ExtensionEnclaveAdapterConfig.attestationServiceUrl`. Matches the gate's\n * `TEE_ATTESTATION_URL` — the enclave the gate forwards to for the re-sign.\n */\nexport const DEFAULT_ATTESTATION_SERVICE_URL = 'https://attestation-service.zkp2p.xyz'\n\n/** Minimal slice of `window.peer` this adapter depends on. */\nexport interface PeerClient {\n authenticate(inputs: {\n actionType: string\n platform: string\n captureMode: 'buyerTee'\n /**\n * Enclave the extension establishes the Buyer TEE session with and encrypts\n * the session material toward. Required by the zkp2p 0.6.0 spec\n * (onramp-llm.md §7) — without it the extension performs no Buyer TEE\n * capture and falls back to the retired Reclaim path.\n */\n attestationServiceUrl?: string\n /** Attestation action type; defaults to `actionType` when omitted (spec §2). */\n attestationActionType?: string\n /** Attestation platform; defaults to `platform` when omitted. */\n attestationPlatform?: string\n }): Promise<void>\n onMetadataMessage(fn: (data: MetadataResponse) => void): () => void\n /** Current extension connection status; `'connected'` means ready. */\n checkConnectionStatus(): Promise<string>\n /** Prompt the user to connect the extension. Resolves true when approved. */\n requestConnection(): Promise<boolean>\n}\n\nexport interface ExtensionEnclaveAdapterConfig {\n /** Resolve the live peer client (e.g. `() => window.peer`). */\n getPeer: () => PeerClient | undefined\n /** Gate/attestation origin handed to requestBuyerTeeAttestation (the re-sign hop). */\n attestationBaseUrl: string\n /**\n * Enclave URL passed to the extension's `authenticate` so it performs the\n * Buyer TEE capture (zkp2p 0.6.0 spec §7). This is the zkp2p enclave the\n * session material is encrypted toward — the SAME enclave the gate forwards\n * to for the re-sign — NOT our gate's re-sign origin (`attestationBaseUrl`).\n * Defaults to {@link DEFAULT_ATTESTATION_SERVICE_URL} when omitted; set it to\n * override the enclave for local testing.\n */\n attestationServiceUrl?: string\n /**\n * Milliseconds before awaitMetadata rejects if the extension never posts a\n * matching metadata message. Mirrors the 60-second timeout in\n * AuthenticateStep.tsx:232-236. Defaults to 60000.\n */\n timeoutMs?: number\n}\n\n/** One bank-history row the attestation may settle this order with. */\ninterface PaymentToTry {\n /** The row's index in the captured bank history. */\n index: number\n /** The row's provider attestation params (spec §4), forwarded to the enclave. */\n params?: Record<string, string | number | boolean>\n}\n\ninterface EnclaveMaterial {\n encryptedSessionMaterial: string\n /**\n * Payments to attest, in order. One entry for a single amount match or a\n * buyer's pick; every amount match (bank order, newest first) when several\n * payments share the order's amount. Bank dates resolve only to the day,\n * so they cannot tell same-day payments apart; the gate can, by refusing a\n * payment that already settled an order.\n */\n payments: PaymentToTry[]\n}\n\n/**\n * Normalize an amount from the extension into a bigint in token base units.\n *\n * Reproduces findMetadataMessage's normalizeAmount (useZKTLS.ts:630-639).\n * The extension sends amounts in different formats per provider:\n * - Venmo: `\"- $1.00\"` (formatted dollar string — isFormattedDollars=true)\n * - Others: `100` (integer cents) or `1.00` (decimal dollars)\n *\n * When `centIsInt` is true and the raw value has no currency symbol or decimal\n * point (i.e. it arrived as integer cents), we divide by 100 to convert to\n * the same base unit scale that parseUnits applied.\n */\nfunction normalizeAmount(amount: number | string, decimals: number, centIsInt: boolean): bigint {\n const raw = String(amount)\n const isFormattedDollars = /[^0-9\\-]/.test(raw) && raw.includes('.')\n const cleaned = raw.replace(/[^0-9.]/g, '')\n let value = parseUnits(cleaned, decimals)\n if (centIsInt && !isFormattedDollars) {\n value = value / 100n\n }\n return value\n}\n\n/**\n * The outcome of matching the bank history against the intent's amount.\n *\n * - `single`: exactly one payment has the intent's amount.\n * - `several`: more than one does (e.g. two $2 Zelle payments to the same\n * seller). All are tried in bank order; the gate refuses any that already\n * settled an order. Taking only the first sent an already-used payment and\n * failed the order with \"This payment has already been verified\".\n * - `none`: no payment has that amount; the buyer picks from the full list.\n */\ntype PaymentMatch =\n | { kind: 'single'; candidate: CaptureCandidate }\n | { kind: 'several'; candidates: CaptureCandidate[] }\n | { kind: 'none' }\n\n/**\n * Match the bank history against the intent's FIAT currency amount,\n * accepting a positive or negative sign as findMetadataMessage does.\n *\n * Uses the same pipeline as the live AuthenticateStep.tsx:147-163:\n * 1. Convert token amount → fiat via convertTokenInputToCurrency.\n * 2. Normalize each candidate with the provider's centIsInt flag.\n * 3. Match equality (or negated equality for debit/refund signs).\n *\n * `centIsInt` is sourced from `providerConfigs(chainId)[provider]?.amountInCents`\n * which mirrors how the live caller derives it:\n * `targetProvider?.amountInCents ?? false`\n * where `targetProvider` is resolved via `useProvider` from the same\n * providerConfigs call. Sub-providers (e.g. zelle-chase) do NOT currently\n * set amountInCents, so the parent-provider lookup is sufficient.\n *\n * Matches keep the bank's own order (newest first for the hosted templates).\n */\nfunction matchPayment(\n candidates: CaptureCandidate[],\n request: CaptureRequest,\n): PaymentMatch {\n const currencyAmount = convertTokenInputToCurrency({\n token: request.token,\n amountOutInt: BigInt(request.intent.amount),\n rate: BigInt(request.intent.conversionRate),\n })\n\n // Resolve centIsInt from the provider config — same source as the live UI.\n // The cast is safe: CaptureRequest.chainId must be a supported chain ID.\n const configs = providerConfigs(request.chainId as ChainId)\n const providerConfig = configs[request.provider as keyof typeof configs]\n const centIsInt = (providerConfig as { amountInCents?: boolean } | undefined)?.amountInCents ?? false\n\n const matches = candidates.filter((candidate) => {\n const converted = normalizeAmount(candidate.amount, request.token.decimals, centIsInt)\n return converted === currencyAmount || converted === currencyAmount * -1n\n })\n if (matches.length === 0) return { kind: 'none' }\n if (matches.length === 1) return { kind: 'single', candidate: matches[0]! }\n return { kind: 'several', candidates: matches }\n}\n\n/** The bank-history row as a payment to try. */\nfunction toPaymentToTry(candidate: CaptureCandidate): PaymentToTry {\n return { index: candidate.originalIndex, params: candidate.params }\n}\n\n/**\n * The payments to attest, in order: the amount matches, else the buyer's pick\n * from the whole history. Throws {@link ManualSelectionRequired} when a pick is\n * needed but no resolver was supplied.\n */\nasync function resolvePaymentsToTry({\n match,\n history,\n selectTransaction,\n}: {\n match: PaymentMatch\n history: CaptureCandidate[]\n selectTransaction?: SelectTransaction\n}): Promise<PaymentToTry[]> {\n if (match.kind === 'single') return [toPaymentToTry(match.candidate)]\n if (match.kind === 'several') return match.candidates.map(toPaymentToTry)\n if (!selectTransaction) throw new ManualSelectionRequired(history)\n const pickedIndex = await selectTransaction(history)\n const picked = history.find((row) => row.originalIndex === pickedIndex)\n return [{ index: pickedIndex, params: picked?.params }]\n}\n\n/**\n * Wait for the metadata message the extension posts for `platform`.\n *\n * Races a configurable timeout (default 60s) against the metadata event,\n * mirroring AuthenticateStep.tsx:232-236. The unsubscribe function is always\n * called on resolution, timeout, or error — no listener leaks.\n *\n * @param peer - Injected extension client.\n * @param platform - The platform handed to `authenticate()` (e.g. 'zelle').\n * Echoed back when the extension could not load a template.\n * @param actionType - The capture action type (e.g. 'transfer_venmo'). Its\n * parent is echoed back when the template DID load. Both are accepted; see\n * the guard below.\n * @param timeoutMs - Reject after this long with no matching message.\n */\nfunction awaitMetadata(\n peer: PeerClient,\n platform: string,\n actionType: string,\n timeoutMs: number,\n): Promise<MetadataResponse> {\n return new Promise<MetadataResponse>((resolve, reject) => {\n let timeoutId: ReturnType<typeof setTimeout> | undefined\n\n const unsub = peer.onMetadataMessage((data) => {\n // The extension echoes the platform from one of two places:\n //\n // - Template loaded (success): the TEMPLATE's own `metadata.platform`.\n // - Template fetch failed: there is no template, so it echoes the\n // platform we passed, alongside an errorMessage such as\n // 'Failed to fetch provider template: 404'.\n //\n // With hosted templates the two agree (generic Zelle: 'zelle' both\n // ways). Accepting either still guards against a template whose\n // metadata.platform is the parent rail rather than the platform we\n // passed, so a successful capture is never dropped into a 60s timeout.\n const echoesCapturePlatform = data.platform === platform\n const echoesActionTypeParent = `transfer_${data.platform}` === actionType\n if (echoesCapturePlatform || echoesActionTypeParent) {\n clearTimeout(timeoutId)\n unsub()\n resolve(data)\n }\n })\n\n timeoutId = setTimeout(() => {\n unsub()\n reject(new Error(`Enclave capture timed out for platform \"${platform}\"`))\n }, timeoutMs)\n })\n}\n\nexport function createExtensionEnclaveAdapter(config: ExtensionEnclaveAdapterConfig): CaptureAdapter {\n const timeoutMs = config.timeoutMs ?? 60000\n\n return {\n kind: 'extension-enclave',\n\n async authenticateAndCapture(\n request: CaptureRequest,\n options?: { selectTransaction?: SelectTransaction },\n ): Promise<CaptureHandle> {\n const peer = config.getPeer()\n if (!peer) {\n throw new EnclaveCaptureUnavailable(request.platform)\n }\n\n // Ensure the extension is connected BEFORE authenticate. A cold\n // authenticate() on a fresh page returns errorMessage \"Peer extension\n // connection required\" with no buyerTeeCapture — which trips the\n // enclave-unavailable path. The legacy AuthenticateStep connects first\n // (and onramp-llm.md §3 `ensurePeerReady` requires it); the adapter must\n // too. This is why a warm local tab worked but a fresh prod session failed.\n const status = await peer.checkConnectionStatus()\n if (status !== 'connected') {\n await peer.requestConnection()\n }\n\n // Register the listener BEFORE authenticate fires to avoid a race where\n // the extension posts metadata before the listener is attached.\n const metadataPromise = awaitMetadata(peer, request.platform, request.actionType, timeoutMs)\n await peer.authenticate({\n actionType: request.actionType,\n platform: request.platform,\n captureMode: 'buyerTee',\n // Required for the extension to actually perform the Buyer TEE capture\n // (zkp2p 0.6.0 spec §7). Omitting these is why non-Revolut rails got\n // \"no buyerTee capture\" and dead-ended on the retired Reclaim path.\n attestationServiceUrl: config.attestationServiceUrl ?? DEFAULT_ATTESTATION_SERVICE_URL,\n // The attestation route equals the capture pair for every rail today\n // (generic Zelle included: zelle/transfer_zelle_chase). No template is\n // passed: extension 0.6.7 always fetches it from api.zkp2p.xyz and\n // ignores a page-supplied one, so the capture pair must be hosted.\n attestationActionType: request.attestationActionType ?? request.actionType,\n attestationPlatform: request.attestationPlatform ?? request.platform,\n })\n const response = await metadataPromise\n\n // No buyerTee capture ⇒ the extension didn't produce an encrypted enclave\n // session. Log WHY before failing — the extension may have surfaced an\n // errorMessage, or returned metadata-only (no capture) for this platform.\n if (!response.buyerTeeCapture) {\n const errorMessage = (response as { errorMessage?: unknown }).errorMessage\n console.warn(\n '[extensionEnclave] no buyerTeeCapture for',\n request.platform,\n '— response keys:', Object.keys(response),\n '| errorMessage:', errorMessage,\n '| metadata rows:', Array.isArray(response.metadata) ? response.metadata.length : '(none)',\n '| buyerTeeCapture:', response.buyerTeeCapture,\n )\n // Two distinct failures share the \"no capture\" shape:\n // - The extension surfaced an `errorMessage` ⇒ it ATTEMPTED the capture\n // but something failed (most often: it could not reach the\n // attestation enclave — a buyer-side network / firewall / ad-blocker\n // issue). Surface that as a retryable EnclaveCaptureFailed carrying\n // the raw reason, so the user sees an actionable message instead of\n // \"provider unsupported\".\n // - No `errorMessage` ⇒ the provider produced no capture path at all\n // (non-migrated). That stays EnclaveCaptureUnavailable, the\n // Reclaim-fallback signal.\n if (typeof errorMessage === 'string' && errorMessage.trim().length > 0) {\n throw new EnclaveCaptureFailed(request.platform, errorMessage)\n }\n throw new EnclaveCaptureUnavailable(request.platform)\n }\n\n const material: EnclaveMaterial = {\n encryptedSessionMaterial: response.buyerTeeCapture.encryptedSessionMaterial,\n payments: await resolvePaymentsToTry({\n match: matchPayment(response.metadata, request),\n history: response.metadata,\n selectTransaction: options?.selectTransaction,\n }),\n }\n return { kind: 'extension-enclave', material }\n },\n\n async attest(handle: CaptureHandle, request: CaptureRequest): Promise<VerifiedAttestation> {\n if (handle.kind !== 'extension-enclave') {\n throw new Error(\n `ExtensionEnclaveAdapter.attest received a handle of kind \"${handle.kind}\"; expected \"extension-enclave\".`,\n )\n }\n const material = handle.material as EnclaveMaterial\n // Try each candidate payment in order. A payment that already settled an\n // order is refused by the gate (PaymentAlreadyUsedError) and skipped;\n // any other failure stops here and surfaces as-is.\n let alreadyUsed: PaymentAlreadyUsedError | undefined\n for (const payment of material.payments) {\n try {\n const attestation = await attestPayment({ payment, material, request })\n // verificationData = enclave signer (SubmitStep.tsx:473-474).\n return { attestation, verificationData: attestation.signer as Hex }\n } catch (error) {\n if (!(error instanceof PaymentAlreadyUsedError)) throw error\n alreadyUsed = error\n }\n }\n throw alreadyUsed ?? new Error('No bank payment was captured for this order.')\n },\n }\n\n /** Attest one candidate payment through the gate. */\n function attestPayment({\n payment,\n material,\n request,\n }: {\n payment: PaymentToTry\n material: EnclaveMaterial\n request: CaptureRequest\n }) {\n // The selected row's params ARE the attestation params (spec §5,\n // buildBuyerTeeProof) and MUST be forwarded — dropping them is why the\n // enclave 400s with \"Invalid <provider> query params\". The metadata\n // `index` is then merged in ONLY for providers that expect it (Venmo /\n // Cash App / Revolut / Zelle) and omitted for the rest (PayPal / Wise /\n // Monzo / Chime). See providerRequiresMetadataIndex.\n const params = {\n ...(payment.params ?? {}),\n ...(providerRequiresMetadataIndex(request.provider as ProviderKey | SubProviderKey)\n ? { index: payment.index }\n : {}),\n }\n return requestBuyerTeeAttestation({\n attestationBaseUrl: config.attestationBaseUrl,\n platform: request.attestationPlatform ?? request.platform,\n actionType: request.attestationActionType ?? request.actionType,\n encryptedSessionMaterial: material.encryptedSessionMaterial,\n params,\n verifyingContract: request.verifyingContract,\n intent: request.intent,\n })\n }\n}\n\n// Re-narrow export so consumers can validate proof shapes if they bypass the\n// adapter (kept for parity with the live SubmitStep check, SubmitStep.tsx:206).\nexport { asBuyerTeeProof }\n"]}
1
+ {"version":3,"sources":["../src/useZKTLS.ts","../src/capability.ts","../src/useProofCapability.ts","../src/ZKTLSContext.tsx","../src/adapters/extensionEnclave.ts"],"names":["useState","useEffect","useMemo","createContext","useContext","parseUnits","convertTokenInputToCurrency","providerConfigs","ManualSelectionRequired","EnclaveCaptureUnavailable","EnclaveCaptureFailed","PaymentAlreadyUsedError","payment","providerRequiresMetadataIndex","requestBuyerTeeAttestation"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * @fileoverview React hook and utilities for PeerAuth browser extension integration.\n *\n * The PeerAuth extension (formerly ZK-TLS) provides secure proof generation\n * for off-chain payment verification. This module provides:\n *\n * 1. Type definitions for extension API (window.peer)\n * 2. useZKTLS hook for React components\n * 3. The trusted-execution on-ramp helpers\n *\n * @remarks\n * The extension exposes `window.peer` (or deprecated `window.zktls`) for:\n * - Requesting connection (OAuth-like flow)\n * - Authenticating with payment providers (buyer trusted-execution capture)\n * - Fetching transaction metadata\n *\n * The Reclaim proof path (generateProof, proof encoding, proof types) was\n * removed in the next major version.\n *\n * @see {@link ZKTLSContext} for the React context provider\n */\n\nimport { useEffect, useMemo, useState } from \"react\"\nimport { type Hex } from \"viem\"\nimport { type ActionType, type PlatformKey, type ProviderKey } from \"@provex/utils/payment\"\n\ndeclare global {\n interface ZKTLS {\n requestConnection(): Promise<boolean>\n checkConnectionStatus(): Promise<Status>\n getVersion(): Promise<string>\n authenticate(inputs: AuthenticationInputs): Promise<void>\n openSidebar(route: string): Promise<void>\n onMetadataMessage(fn: (data: MetadataMessageResponse) => void): () => void\n /**\n * Trusted-execution on-ramp (PeerAuth v3+). The extension opens the\n * buyer's bank in a new tab, intercepts the authenticated session, calls\n * the zkp2p trusted-execution attestation service, and returns\n * ready-to-send `fulfillIntent` calldata through the callback. Replaces\n * the retired Reclaim proof path.\n *\n * Optional: older extension builds predate the on-ramp API, so guard\n * with a runtime presence check (`supportsOnramp`) before calling.\n *\n * @param queryString serialized on-ramp params (see {@link buildOnrampQuery})\n * @param callback invoked once the prepared transaction is ready\n */\n onramp?(\n queryString: string,\n callback: (result: PeerOnrampPreparedTransaction) => void,\n ): void\n /** Retrieve a previously prepared on-ramp transaction by intent hash. */\n getOnrampTransaction?(intentHash: string): Promise<PeerOnrampPreparedTransaction | null>\n }\n interface Window {\n /** @deprecated Use window.peer instead */\n zktls: ZKTLS | undefined\n /** PeerAuth extension API (replaces window.zktls) */\n peer: ZKTLS | undefined\n }\n}\n\n/** the status of the PeerAuth extension */\nexport type Status = 'connected' | 'disconnected' | 'pending'\n\n/** the individual metadata message sent by the PeerAuth extension */\nexport interface MetadataMessage {\n amount: number\n /** Currency code (e.g., 'USD', 'EUR') */\n currency?: string\n /**\n * Date of the transaction.\n * Can be a string in YYYYMMDD format, a number (YYYYMMDD or timestamp), or Date object.\n * The actual type depends on the extension implementation.\n */\n date: string | number | Date\n hidden: boolean\n originalIndex: number\n paymentId: number\n recipient: string\n}\n\n/** the response from the PeerAuth extension when a metadata message is received */\nexport interface MetadataMessageResponse {\n expiresAt: number\n platform: ProviderKey\n requestId: string\n metadata: MetadataMessage[]\n /**\n * Present only when `authenticate` was called with `captureMode: 'buyerTee'`.\n * Carries the bank session already encrypted toward the enclave — feed\n * `encryptedSessionMaterial` (plus the matched transaction's index) to the\n * trusted-execution verify endpoint.\n */\n buyerTeeCapture?: {\n encryptedSessionMaterial: string\n }\n /** Error surfaced by the extension during capture (e.g. missing platform). */\n errorMessage?: string\n}\n\n/** the inputs for the authenticate function */\nexport type AuthenticationInputs = {\n actionType: ActionType\n platform: PlatformKey\n /**\n * Session capture mode. `'buyerTee'` makes the extension intercept the bank\n * session and return it encrypted toward the trusted-execution enclave in\n * `MetadataMessageResponse.buyerTeeCapture`. The extension defaults the\n * attestation service URL when this is set.\n */\n captureMode?: 'buyerTee' | 'sellerCredential'\n /**\n * Enclave the extension establishes the Buyer TEE session with and encrypts\n * the captured session material toward (zkp2p 0.6.0 spec §7). Pass explicitly\n * for newer providers — relying on the extension's built-in default is what\n * left non-Revolut rails with \"no buyerTee capture\".\n */\n attestationServiceUrl?: string\n /** Attestation action type; defaults to `actionType` when omitted (spec §2). */\n attestationActionType?: ActionType\n}\n\n/**\n * Ready-to-send transaction the PeerAuth extension hands back once the\n * trusted-execution attestation service has signed the payment. The `data`\n * already embeds the enclave attestation, so the client signs and sends it\n * verbatim — no client-side proof encoding or gate re-signing.\n */\nexport type PeerOnrampPreparedTransaction = {\n intentHash: Hex\n status: 'calldata_ready'\n transaction: {\n to: Hex\n data: Hex\n /** Wei, as a decimal string (the extension keeps it out of JSON-number range). */\n value: string\n chainId: number\n }\n}\n\n/**\n * Structured on-ramp inputs. The extension looks the intent up from\n * `intentHash` (and the optional context fields) to resolve the chain,\n * contracts, and payment platform — we never pass contract addresses.\n */\nexport type PeerExtensionOnrampParams = {\n intentHash: string\n referrer?: string\n referrerLogo?: string\n inputCurrency?: string\n inputAmount?: string | number\n paymentPlatform?: string\n depositId?: string | number | bigint\n toToken?: string\n amountUsdc?: string | number | bigint\n recipientAddress?: string\n}\n\n/**\n * Serialize on-ramp params into the query string the extension's `onramp`\n * entry point expects. Mirrors the mapping `@zkp2p/sdk`'s\n * `peerExtensionSdk.onramp` performs: every defined field becomes one query\n * parameter, `undefined`/`null` fields are dropped, and `bigint` values are\n * stringified.\n */\nexport const buildOnrampQuery = (params: PeerExtensionOnrampParams): string => {\n const search = new URLSearchParams()\n Object.entries(params).forEach(([key, value]) => {\n if (value === undefined || value === null) return\n search.set(key, String(value))\n })\n return search.toString()\n}\n\nexport const extensionUrl = 'https://chromewebstore.google.com/detail/ijpgccednehjpeclfcllnjjcmiohdjih'\n\n/** React hook to interact with the PeerAuth extension */\nexport const useZKTLS = () => {\n const [isInitialized, setIsInitialized] = useState(false)\n useEffect(() => {\n const setup = () => {\n setIsInitialized(true)\n }\n const eventName = 'peer#initialized'\n if (typeof window.peer !== 'undefined') {\n // api is available\n setup()\n } else {\n window.addEventListener(eventName, setup)\n return () => {\n window.removeEventListener(eventName, setup)\n }\n }\n }, [])\n return useMemo(() => {\n return {\n /** check if the PeerAuth extension is initialized */\n isInitialized,\n /** request a connection to the PeerAuth extension */\n requestConnection: async () => {\n if (!window.peer) return false\n return window.peer!.requestConnection()\n },\n /**\n * check the connection status of the PeerAuth extension\n * @returns the connection status\n */\n checkConnectionStatus: async () => {\n return await window.peer!.checkConnectionStatus()\n },\n /** get the version of the PeerAuth extension */\n getVersion: async () => {\n return await window.peer?.getVersion()\n },\n /** authenticate with the PeerAuth extension */\n authenticate: async (inputs: AuthenticationInputs) => {\n // Create promise first to avoid race condition where message arrives before resolver is assigned\n let resolve: (value: MetadataMessageResponse) => void\n const promise = new Promise<MetadataMessageResponse>((resolver) => {\n resolve = resolver\n })\n\n // Now set up the listener - resolve is guaranteed to be the real resolver\n const unsub = window.peer!.onMetadataMessage((data) => {\n if (`transfer_${data.platform}` === inputs.actionType) {\n resolve(data)\n }\n })\n\n await window.peer!.authenticate(inputs)\n\n return await promise.then((data) => {\n unsub()\n return data\n })\n },\n /** subscribe to metadata messages */\n onMetadataMessage: (fn: (data: any) => void) => {\n return window.peer!.onMetadataMessage(fn)\n },\n /** open the PeerAuth sidebar */\n openSidebar: async (route: string) => {\n return await window.peer!.openSidebar(route)\n },\n /* v8 ignore start -- @preserve\n * Excluded from coverage on purpose: the extension's `window.peer.onramp`\n * API is retired (the buyer flow verifies through the zkp2p enclave\n * adapter instead) and no caller in this repository invokes\n * supportsOnramp, onramp or getOnrampTransaction. Testing them would\n * assert behaviour production never reaches. */\n /** Whether the connected extension exposes the trusted-execution on-ramp. */\n supportsOnramp: (): boolean => typeof window.peer?.onramp === 'function',\n /**\n * Begin the trusted-execution on-ramp and resolve with ready-to-send\n * `fulfillIntent` calldata once the extension has intercepted the bank\n * session and the zkp2p attestation service has signed the payment.\n *\n * The underlying extension API is callback-only with no error channel:\n * the extension surfaces progress and failures in its own sidebar/tab,\n * and only invokes the callback on success. The returned promise\n * therefore stays pending until the prepared transaction arrives — the\n * caller drives the user toward the PeerAuth window and may offer a\n * cancel affordance rather than racing a timeout against a buyer who is\n * still logging into their bank.\n */\n onramp: async (\n params: PeerExtensionOnrampParams,\n ): Promise<PeerOnrampPreparedTransaction> => {\n if (typeof window.peer?.onramp !== 'function') {\n throw new Error(\n 'This PeerAuth extension version does not support the trusted-execution on-ramp. Please update the extension.',\n )\n }\n const queryString = buildOnrampQuery(params)\n return new Promise<PeerOnrampPreparedTransaction>((resolve) => {\n window.peer!.onramp!(queryString, resolve)\n })\n },\n /**\n * Retrieve a previously prepared on-ramp transaction by intent hash.\n * Returns null when the extension lacks the API or has nothing prepared\n * yet — usable as a poll alongside {@link onramp} to recover a result\n * if the one-shot callback is missed.\n */\n getOnrampTransaction: async (\n intentHash: string,\n ): Promise<PeerOnrampPreparedTransaction | null> => {\n if (typeof window.peer?.getOnrampTransaction !== 'function') return null\n return window.peer.getOnrampTransaction(intentHash)\n },\n /* v8 ignore stop -- @preserve */\n }\n }, [isInitialized])\n}\n","/**\n * @fileoverview Pure functions that decide whether this browser can make a\n * Provex payment proof.\n *\n * A browser can make a proof when it is a desktop browser and the Peer\n * extension (version 0.6.0 or later) injects `window.peer`. The functions here\n * hold no state and read no globals, so every branch can be tested directly.\n */\n\n/**\n * The first extension version that works with the enclave-only proof path.\n * Version 0.6.0 removed `generateProof`.\n */\nexport const MINIMUM_EXTENSION_VERSION = '0.6.0'\n\n/** Default wait, in milliseconds, before a missing `window.peer` counts as missing. */\nexport const DEFAULT_INJECTION_WAIT_MS = 1_500\n\n/**\n * Whether the page can count on the extension to inject `window.peer`.\n * - `guaranteed`: the page runs on an origin where the extension injects.\n * - `not-guaranteed`: third-party origin or iframe. No `window.peer` proves nothing.\n */\nexport type InjectionGuarantee = 'guaranteed' | 'not-guaranteed'\n\n/** Browser facts used to detect a mobile device. */\nexport interface MobileDeviceSignals {\n userAgent: string\n maxTouchPoints: number\n platform: string\n}\n\n/** The result of a proof capability check. */\nexport type ProofCapability =\n | { status: 'mobile' }\n | { status: 'checking' }\n | { status: 'no-extension' }\n | { status: 'unknown' }\n | { status: 'outdated'; version: string }\n | { status: 'ready'; version: string }\n\n/** The facts that `resolveProofCapability` combines. */\nexport interface ProofCapabilitySignals {\n /** True when the device is a phone or tablet. */\n isMobileDevice: boolean\n /** True once `window.peer` exists. */\n isPeerPresent: boolean\n /** True once the wait for injection has passed. */\n hasInjectionWaitElapsed: boolean\n /** How the page gets the extension. */\n injection: InjectionGuarantee\n /**\n * The extension version. `undefined` while the lookup runs.\n * `null` when the lookup failed or returned nothing.\n */\n version: string | null | undefined\n}\n\nconst MOBILE_USER_AGENT_PATTERN = /Android|iPhone|iPad|iPod|Mobile|Windows Phone|IEMobile|BlackBerry|Opera Mini/i\n\n/**\n * Detect a phone or tablet from the user agent and touch support.\n * It does not look at the viewport width. A narrow desktop window is not mobile.\n * iPadOS 13 and later sends a desktop Mac user agent, so a \"MacIntel\"\n * platform with touch points counts as a tablet. Desktop Macs report zero.\n *\n * @param signals - user agent, touch point count, and platform string\n * @returns true when the device is mobile\n */\nexport const detectMobileDevice = ({ userAgent, maxTouchPoints, platform }: MobileDeviceSignals): boolean => {\n if (MOBILE_USER_AGENT_PATTERN.test(userAgent)) return true\n return platform === 'MacIntel' && maxTouchPoints > 0\n}\n\n/** Read up to three numeric parts. A missing or invalid part counts as zero. */\nconst parseVersionParts = (version: string): number[] => {\n const parts = version.trim().replace(/^v/i, '').split('.')\n return [0, 1, 2].map((index) => {\n const parsed = Number.parseInt(parts[index] ?? '', 10)\n return Number.isNaN(parsed) ? 0 : parsed\n })\n}\n\n/**\n * Compare two dotted versions numerically, so 0.10.0 is later than 0.6.0.\n * Missing parts count as zero, so \"0.6\" equals \"0.6.0\".\n *\n * @param options.current - the version to test\n * @param options.minimum - the lowest accepted version\n * @returns true when `current` is the same as or later than `minimum`\n */\nexport const isVersionAtLeast = ({ current, minimum }: { current: string; minimum: string }): boolean => {\n const currentParts = parseVersionParts(current)\n const minimumParts = parseVersionParts(minimum)\n const firstDifference = currentParts.findIndex((part, index) => part !== minimumParts[index])\n if (firstDifference === -1) return true\n return currentParts[firstDifference] > minimumParts[firstDifference]\n}\n\n/**\n * Combine device, extension, and timing facts into one capability result.\n *\n * Off-origin pages cannot prove that the extension is missing, so with\n * `not-guaranteed` injection a missing `window.peer` gives `unknown`.\n * With `guaranteed` injection it gives `checking` until the wait passes,\n * then `no-extension`.\n *\n * @param signals - the facts to combine\n * @returns the discriminated capability result\n */\nexport const resolveProofCapability = ({\n isMobileDevice,\n isPeerPresent,\n hasInjectionWaitElapsed,\n injection,\n version,\n}: ProofCapabilitySignals): ProofCapability => {\n if (isMobileDevice) return { status: 'mobile' }\n if (!isPeerPresent && injection === 'not-guaranteed') return { status: 'unknown' }\n if (!isPeerPresent && !hasInjectionWaitElapsed) return { status: 'checking' }\n if (!isPeerPresent) return { status: 'no-extension' }\n if (version === undefined) return { status: 'checking' }\n if (version === null) return { status: 'unknown' }\n if (!isVersionAtLeast({ current: version, minimum: MINIMUM_EXTENSION_VERSION })) {\n return { status: 'outdated', version }\n }\n return { status: 'ready', version }\n}\n","/**\n * @fileoverview React hook that reports whether this browser can make a\n * Provex payment proof. See `capability.ts` for the decision rules.\n */\n\nimport { useEffect, useState } from 'react'\nimport {\n DEFAULT_INJECTION_WAIT_MS,\n detectMobileDevice,\n resolveProofCapability,\n type InjectionGuarantee,\n type ProofCapability,\n} from './capability.js'\n\n/** Options for {@link useProofCapability}. */\nexport interface UseProofCapabilityOptions {\n /** Default `not-guaranteed`. Pass `guaranteed` on origins where the extension injects. */\n injection?: InjectionGuarantee\n /** Wait before a missing `window.peer` counts as missing. Default 1500 ms. */\n injectionWaitMs?: number\n}\n\nconst PEER_INITIALIZED_EVENT = 'peer#initialized'\n\n/** Read the device signals from `navigator`. Returns false on the server. */\nconst readIsMobileDevice = (): boolean => {\n if (typeof navigator === 'undefined') return false\n return detectMobileDevice({\n userAgent: navigator.userAgent ?? '',\n maxTouchPoints: navigator.maxTouchPoints ?? 0,\n platform: navigator.platform ?? '',\n })\n}\n\n/** Ask the extension for its version. Returns null when it cannot answer. */\nconst readExtensionVersion = async (): Promise<string | null> => {\n try {\n const version = await window.peer?.getVersion?.()\n return version ? version : null\n } catch {\n return null\n }\n}\n\n/**\n * Report whether this browser can make a Provex payment proof.\n *\n * The first render, on the server and in the browser, assumes a desktop device\n * with no extension seen. The real values load in effects, so server and\n * client markup match.\n *\n * @param options - injection guarantee and wait time\n * @returns the current {@link ProofCapability}\n */\nexport const useProofCapability = ({\n injection = 'not-guaranteed',\n injectionWaitMs = DEFAULT_INJECTION_WAIT_MS,\n}: UseProofCapabilityOptions = {}): ProofCapability => {\n const [isMobileDevice, setIsMobileDevice] = useState(false)\n const [isPeerPresent, setIsPeerPresent] = useState(false)\n const [hasInjectionWaitElapsed, setHasInjectionWaitElapsed] = useState(false)\n const [version, setVersion] = useState<string | null | undefined>(undefined)\n\n useEffect(() => {\n setIsMobileDevice(readIsMobileDevice())\n }, [])\n\n useEffect(() => {\n let isCancelled = false\n const markPresent = () => {\n setIsPeerPresent(true)\n void readExtensionVersion().then((found) => {\n if (!isCancelled) setVersion(found)\n })\n }\n if (typeof window.peer !== 'undefined') {\n markPresent()\n return () => {\n isCancelled = true\n }\n }\n window.addEventListener(PEER_INITIALIZED_EVENT, markPresent)\n const timer = setTimeout(() => setHasInjectionWaitElapsed(true), injectionWaitMs)\n return () => {\n isCancelled = true\n clearTimeout(timer)\n window.removeEventListener(PEER_INITIALIZED_EVENT, markPresent)\n }\n }, [injectionWaitMs])\n\n return resolveProofCapability({ isMobileDevice, isPeerPresent, hasInjectionWaitElapsed, injection, version })\n}\n","/**\n * @fileoverview React context for PeerAuth extension state.\n *\n * Provides global access to the useZKTLS hook state throughout the\n * component tree, avoiding prop drilling for extension status.\n *\n * @see {@link useZKTLS} for the underlying hook\n */\n\nimport { createContext, useContext, type ReactNode } from 'react'\nimport { useZKTLS } from './useZKTLS'\n\n/**\n * Context type derived from useZKTLS hook return value.\n */\ntype ZKTLSContextType = ReturnType<typeof useZKTLS>\n\nexport const ZKTLSContext = createContext<ZKTLSContextType | undefined>(undefined)\n\ninterface ZKTLSProviderProps {\n children: ReactNode\n}\n\n/**\n * Hook to consume the ZKTLS context.\n * Must be used within a ZKTLSProvider.\n *\n * @throws Error if used outside of ZKTLSProvider\n */\nexport function useZKTLSContext() {\n const context = useContext(ZKTLSContext)\n if (context === undefined) {\n throw new Error('useZKTLSContext must be used within a ZKTLSProvider')\n }\n return context\n}\n\nexport function ZKTLSProvider({ children }: ZKTLSProviderProps) {\n const zktlsHook = useZKTLS()\n\n return (\n <ZKTLSContext.Provider value={zktlsHook}>\n {children}\n </ZKTLSContext.Provider>\n )\n}\n","/**\n * @fileoverview Extension + enclave CaptureAdapter (the v1 capture backend).\n *\n * Mirrors the live AuthenticateStep + GenerateProofStep enclave path\n * (AuthenticateStep.tsx:224-281, GenerateProofStep.tsx:237-251) reduced to\n * the buyerTee branch. Talks to an injected `window.peer`-shaped client so\n * the injected-PeerClient seam is preserved exactly.\n */\n\nimport { parseUnits } from 'viem'\nimport type { Hex } from 'viem'\nimport { providerConfigs, providerRequiresMetadataIndex } from '@provex/utils/payment'\nimport type { ProviderKey, SubProviderKey } from '@provex/utils/payment'\nimport type { ChainId } from '@provex/utils/chain'\nimport { convertTokenInputToCurrency } from '@provex/utils/conversionRates'\nimport {\n EnclaveCaptureUnavailable,\n EnclaveCaptureFailed,\n ManualSelectionRequired,\n PaymentAlreadyUsedError,\n asBuyerTeeProof,\n requestBuyerTeeAttestation,\n type CaptureAdapter,\n type CaptureCandidate,\n type CaptureHandle,\n type CaptureRequest,\n type SelectTransaction,\n type VerifiedAttestation,\n} from '@provex/proving'\n\n/** Minimal shape of the metadata response the extension posts back. */\ninterface MetadataResponse {\n platform: string\n metadata: CaptureCandidate[]\n buyerTeeCapture?: { encryptedSessionMaterial: string }\n}\n\n/**\n * zkp2p enclave used for Buyer TEE capture when the caller doesn't override\n * `ExtensionEnclaveAdapterConfig.attestationServiceUrl`. Matches the gate's\n * `TEE_ATTESTATION_URL` — the enclave the gate forwards to for the re-sign.\n */\nexport const DEFAULT_ATTESTATION_SERVICE_URL = 'https://attestation-service.zkp2p.xyz'\n\n/** Minimal slice of `window.peer` this adapter depends on. */\nexport interface PeerClient {\n authenticate(inputs: {\n actionType: string\n platform: string\n captureMode: 'buyerTee'\n /**\n * Enclave the extension establishes the Buyer TEE session with and encrypts\n * the session material toward. Required by the zkp2p 0.6.0 spec\n * (onramp-llm.md §7) — without it the extension performs no Buyer TEE\n * capture and falls back to the retired Reclaim path.\n */\n attestationServiceUrl?: string\n /** Attestation action type; defaults to `actionType` when omitted (spec §2). */\n attestationActionType?: string\n /** Attestation platform; defaults to `platform` when omitted. */\n attestationPlatform?: string\n }): Promise<void>\n onMetadataMessage(fn: (data: MetadataResponse) => void): () => void\n /** Current extension connection status; `'connected'` means ready. */\n checkConnectionStatus(): Promise<string>\n /** Prompt the user to connect the extension. Resolves true when approved. */\n requestConnection(): Promise<boolean>\n}\n\nexport interface ExtensionEnclaveAdapterConfig {\n /** Resolve the live peer client (e.g. `() => window.peer`). */\n getPeer: () => PeerClient | undefined\n /** Gate/attestation origin handed to requestBuyerTeeAttestation (the re-sign hop). */\n attestationBaseUrl: string\n /**\n * Enclave URL passed to the extension's `authenticate` so it performs the\n * Buyer TEE capture (zkp2p 0.6.0 spec §7). This is the zkp2p enclave the\n * session material is encrypted toward — the SAME enclave the gate forwards\n * to for the re-sign — NOT our gate's re-sign origin (`attestationBaseUrl`).\n * Defaults to {@link DEFAULT_ATTESTATION_SERVICE_URL} when omitted; set it to\n * override the enclave for local testing.\n */\n attestationServiceUrl?: string\n /**\n * Milliseconds before awaitMetadata rejects if the extension never posts a\n * matching metadata message. Mirrors the 60-second timeout in\n * AuthenticateStep.tsx:232-236. Defaults to 60000.\n */\n timeoutMs?: number\n}\n\n/** One bank-history row the attestation may settle this order with. */\ninterface PaymentToTry {\n /** The row's index in the captured bank history. */\n index: number\n /** The row's provider attestation params (spec §4), forwarded to the enclave. */\n params?: Record<string, string | number | boolean>\n}\n\ninterface EnclaveMaterial {\n encryptedSessionMaterial: string\n /**\n * Payments to attest, in order. One entry for a single amount match or a\n * buyer's pick; every amount match (bank order, newest first) when several\n * payments share the order's amount. Bank dates resolve only to the day,\n * so they cannot tell same-day payments apart; the gate can, by refusing a\n * payment that already settled an order.\n */\n payments: PaymentToTry[]\n}\n\n/**\n * Normalize an amount from the extension into a bigint in token base units.\n *\n * This is the only amount normalizer; the retired `findMetadataMessage` was removed.\n * The extension sends amounts in different formats per provider:\n * - Venmo: `\"- $1.00\"` (formatted dollar string — isFormattedDollars=true)\n * - Others: `100` (integer cents) or `1.00` (decimal dollars)\n *\n * When `centIsInt` is true and the raw value has no currency symbol or decimal\n * point (i.e. it arrived as integer cents), we divide by 100 to convert to\n * the same base unit scale that parseUnits applied.\n */\nfunction normalizeAmount(amount: number | string, decimals: number, centIsInt: boolean): bigint {\n const raw = String(amount)\n const isFormattedDollars = /[^0-9\\-]/.test(raw) && raw.includes('.')\n const cleaned = raw.replace(/[^0-9.]/g, '')\n let value = parseUnits(cleaned, decimals)\n if (centIsInt && !isFormattedDollars) {\n value = value / 100n\n }\n return value\n}\n\n/**\n * The outcome of matching the bank history against the intent's amount.\n *\n * - `single`: exactly one payment has the intent's amount.\n * - `several`: more than one does (e.g. two $2 Zelle payments to the same\n * seller). All are tried in bank order; the gate refuses any that already\n * settled an order. Taking only the first sent an already-used payment and\n * failed the order with \"This payment has already been verified\".\n * - `none`: no payment has that amount; the buyer picks from the full list.\n */\ntype PaymentMatch =\n | { kind: 'single'; candidate: CaptureCandidate }\n | { kind: 'several'; candidates: CaptureCandidate[] }\n | { kind: 'none' }\n\n/**\n * Match the bank history against the intent's FIAT currency amount,\n * accepting a positive or negative sign.\n *\n * Uses the same pipeline as the live AuthenticateStep.tsx:147-163:\n * 1. Convert token amount → fiat via convertTokenInputToCurrency.\n * 2. Normalize each candidate with the provider's centIsInt flag.\n * 3. Match equality (or negated equality for debit/refund signs).\n *\n * `centIsInt` is sourced from `providerConfigs(chainId)[provider]?.amountInCents`\n * which mirrors how the live caller derives it:\n * `targetProvider?.amountInCents ?? false`\n * where `targetProvider` is resolved via `useProvider` from the same\n * providerConfigs call. Sub-providers (e.g. zelle-chase) do NOT currently\n * set amountInCents, so the parent-provider lookup is sufficient.\n *\n * Matches keep the bank's own order (newest first for the hosted templates).\n */\nfunction matchPayment(\n candidates: CaptureCandidate[],\n request: CaptureRequest,\n): PaymentMatch {\n const currencyAmount = convertTokenInputToCurrency({\n token: request.token,\n amountOutInt: BigInt(request.intent.amount),\n rate: BigInt(request.intent.conversionRate),\n })\n\n // Resolve centIsInt from the provider config — same source as the live UI.\n // The cast is safe: CaptureRequest.chainId must be a supported chain ID.\n const configs = providerConfigs(request.chainId as ChainId)\n const providerConfig = configs[request.provider as keyof typeof configs]\n const centIsInt = (providerConfig as { amountInCents?: boolean } | undefined)?.amountInCents ?? false\n\n const matches = candidates.filter((candidate) => {\n const converted = normalizeAmount(candidate.amount, request.token.decimals, centIsInt)\n return converted === currencyAmount || converted === currencyAmount * -1n\n })\n if (matches.length === 0) return { kind: 'none' }\n if (matches.length === 1) return { kind: 'single', candidate: matches[0]! }\n return { kind: 'several', candidates: matches }\n}\n\n/** The bank-history row as a payment to try. */\nfunction toPaymentToTry(candidate: CaptureCandidate): PaymentToTry {\n return { index: candidate.originalIndex, params: candidate.params }\n}\n\n/**\n * The payments to attest, in order: the amount matches, else the buyer's pick\n * from the whole history. Throws {@link ManualSelectionRequired} when a pick is\n * needed but no resolver was supplied.\n */\nasync function resolvePaymentsToTry({\n match,\n history,\n selectTransaction,\n}: {\n match: PaymentMatch\n history: CaptureCandidate[]\n selectTransaction?: SelectTransaction\n}): Promise<PaymentToTry[]> {\n if (match.kind === 'single') return [toPaymentToTry(match.candidate)]\n if (match.kind === 'several') return match.candidates.map(toPaymentToTry)\n if (!selectTransaction) throw new ManualSelectionRequired(history)\n const pickedIndex = await selectTransaction(history)\n const picked = history.find((row) => row.originalIndex === pickedIndex)\n return [{ index: pickedIndex, params: picked?.params }]\n}\n\n/**\n * Wait for the metadata message the extension posts for `platform`.\n *\n * Races a configurable timeout (default 60s) against the metadata event,\n * mirroring AuthenticateStep.tsx:232-236. The unsubscribe function is always\n * called on resolution, timeout, or error — no listener leaks.\n *\n * @param peer - Injected extension client.\n * @param platform - The platform handed to `authenticate()` (e.g. 'zelle').\n * Echoed back when the extension could not load a template.\n * @param actionType - The capture action type (e.g. 'transfer_venmo'). Its\n * parent is echoed back when the template DID load. Both are accepted; see\n * the guard below.\n * @param timeoutMs - Reject after this long with no matching message.\n */\nfunction awaitMetadata(\n peer: PeerClient,\n platform: string,\n actionType: string,\n timeoutMs: number,\n): Promise<MetadataResponse> {\n return new Promise<MetadataResponse>((resolve, reject) => {\n let timeoutId: ReturnType<typeof setTimeout> | undefined\n\n const unsub = peer.onMetadataMessage((data) => {\n // The extension echoes the platform from one of two places:\n //\n // - Template loaded (success): the TEMPLATE's own `metadata.platform`.\n // - Template fetch failed: there is no template, so it echoes the\n // platform we passed, alongside an errorMessage such as\n // 'Failed to fetch provider template: 404'.\n //\n // With hosted templates the two agree (generic Zelle: 'zelle' both\n // ways). Accepting either still guards against a template whose\n // metadata.platform is the parent rail rather than the platform we\n // passed, so a successful capture is never dropped into a 60s timeout.\n const echoesCapturePlatform = data.platform === platform\n const echoesActionTypeParent = `transfer_${data.platform}` === actionType\n if (echoesCapturePlatform || echoesActionTypeParent) {\n clearTimeout(timeoutId)\n unsub()\n resolve(data)\n }\n })\n\n timeoutId = setTimeout(() => {\n unsub()\n reject(new Error(`Enclave capture timed out for platform \"${platform}\"`))\n }, timeoutMs)\n })\n}\n\nexport function createExtensionEnclaveAdapter(config: ExtensionEnclaveAdapterConfig): CaptureAdapter {\n const timeoutMs = config.timeoutMs ?? 60000\n\n return {\n kind: 'extension-enclave',\n\n async authenticateAndCapture(\n request: CaptureRequest,\n options?: { selectTransaction?: SelectTransaction },\n ): Promise<CaptureHandle> {\n const peer = config.getPeer()\n if (!peer) {\n throw new EnclaveCaptureUnavailable(request.platform)\n }\n\n // Ensure the extension is connected BEFORE authenticate. A cold\n // authenticate() on a fresh page returns errorMessage \"Peer extension\n // connection required\" with no buyerTeeCapture — which trips the\n // enclave-unavailable path. The legacy AuthenticateStep connects first\n // (and onramp-llm.md §3 `ensurePeerReady` requires it); the adapter must\n // too. This is why a warm local tab worked but a fresh prod session failed.\n const status = await peer.checkConnectionStatus()\n if (status !== 'connected') {\n await peer.requestConnection()\n }\n\n // Register the listener BEFORE authenticate fires to avoid a race where\n // the extension posts metadata before the listener is attached.\n const metadataPromise = awaitMetadata(peer, request.platform, request.actionType, timeoutMs)\n await peer.authenticate({\n actionType: request.actionType,\n platform: request.platform,\n captureMode: 'buyerTee',\n // Required for the extension to actually perform the Buyer TEE capture\n // (zkp2p 0.6.0 spec §7). Omitting these is why non-Revolut rails got\n // \"no buyerTee capture\" and dead-ended on the retired Reclaim path.\n attestationServiceUrl: config.attestationServiceUrl ?? DEFAULT_ATTESTATION_SERVICE_URL,\n // The attestation route equals the capture pair for every rail today\n // (generic Zelle included: zelle/transfer_zelle_chase). No template is\n // passed: extension 0.6.7 always fetches it from api.zkp2p.xyz and\n // ignores a page-supplied one, so the capture pair must be hosted.\n attestationActionType: request.attestationActionType ?? request.actionType,\n attestationPlatform: request.attestationPlatform ?? request.platform,\n })\n const response = await metadataPromise\n\n // No buyerTee capture ⇒ the extension didn't produce an encrypted enclave\n // session. Log WHY before failing — the extension may have surfaced an\n // errorMessage, or returned metadata-only (no capture) for this platform.\n if (!response.buyerTeeCapture) {\n const errorMessage = (response as { errorMessage?: unknown }).errorMessage\n console.warn(\n '[extensionEnclave] no buyerTeeCapture for',\n request.platform,\n '— response keys:', Object.keys(response),\n '| errorMessage:', errorMessage,\n '| metadata rows:', Array.isArray(response.metadata) ? response.metadata.length : '(none)',\n '| buyerTeeCapture:', response.buyerTeeCapture,\n )\n // Two distinct failures share the \"no capture\" shape:\n // - The extension surfaced an `errorMessage` ⇒ it ATTEMPTED the capture\n // but something failed (most often: it could not reach the\n // attestation enclave — a buyer-side network / firewall / ad-blocker\n // issue). Surface that as a retryable EnclaveCaptureFailed carrying\n // the raw reason, so the user sees an actionable message instead of\n // \"provider unsupported\".\n // - No `errorMessage` ⇒ the provider produced no capture path at all\n // (non-migrated). That stays EnclaveCaptureUnavailable, the\n // Reclaim-fallback signal.\n if (typeof errorMessage === 'string' && errorMessage.trim().length > 0) {\n throw new EnclaveCaptureFailed(request.platform, errorMessage)\n }\n throw new EnclaveCaptureUnavailable(request.platform)\n }\n\n const material: EnclaveMaterial = {\n encryptedSessionMaterial: response.buyerTeeCapture.encryptedSessionMaterial,\n payments: await resolvePaymentsToTry({\n match: matchPayment(response.metadata, request),\n history: response.metadata,\n selectTransaction: options?.selectTransaction,\n }),\n }\n return { kind: 'extension-enclave', material }\n },\n\n async attest(handle: CaptureHandle, request: CaptureRequest): Promise<VerifiedAttestation> {\n if (handle.kind !== 'extension-enclave') {\n throw new Error(\n `ExtensionEnclaveAdapter.attest received a handle of kind \"${handle.kind}\"; expected \"extension-enclave\".`,\n )\n }\n const material = handle.material as EnclaveMaterial\n // Try each candidate payment in order. A payment that already settled an\n // order is refused by the gate (PaymentAlreadyUsedError) and skipped;\n // any other failure stops here and surfaces as-is.\n let alreadyUsed: PaymentAlreadyUsedError | undefined\n for (const payment of material.payments) {\n try {\n const attestation = await attestPayment({ payment, material, request })\n // verificationData = enclave signer (SubmitStep.tsx:473-474).\n return { attestation, verificationData: attestation.signer as Hex }\n } catch (error) {\n if (!(error instanceof PaymentAlreadyUsedError)) throw error\n alreadyUsed = error\n }\n }\n throw alreadyUsed ?? new Error('No bank payment was captured for this order.')\n },\n }\n\n /** Attest one candidate payment through the gate. */\n function attestPayment({\n payment,\n material,\n request,\n }: {\n payment: PaymentToTry\n material: EnclaveMaterial\n request: CaptureRequest\n }) {\n // The selected row's params ARE the attestation params (spec §5,\n // buildBuyerTeeProof) and MUST be forwarded — dropping them is why the\n // enclave 400s with \"Invalid <provider> query params\". The metadata\n // `index` is then merged in ONLY for providers that expect it (Venmo /\n // Cash App / Revolut / Zelle) and omitted for the rest (PayPal / Wise /\n // Monzo / Chime). See providerRequiresMetadataIndex.\n const params = {\n ...(payment.params ?? {}),\n ...(providerRequiresMetadataIndex(request.provider as ProviderKey | SubProviderKey)\n ? { index: payment.index }\n : {}),\n }\n return requestBuyerTeeAttestation({\n attestationBaseUrl: config.attestationBaseUrl,\n platform: request.attestationPlatform ?? request.platform,\n actionType: request.attestationActionType ?? request.actionType,\n encryptedSessionMaterial: material.encryptedSessionMaterial,\n params,\n verifyingContract: request.verifyingContract,\n intent: request.intent,\n })\n }\n}\n\n// Re-narrow export so consumers can validate proof shapes if they bypass the\n// adapter (kept for parity with the live SubmitStep check, SubmitStep.tsx:206).\nexport { asBuyerTeeProof }\n"]}
package/dist/index.d.cts CHANGED
@@ -1,9 +1,9 @@
1
- export { AuthenticationInputs, ClaimInfo, CompleteClaimData, FetchProofsResponse, GenerateProofInputs, GenerateProofInputsAbstracted, GenerateProofResponse, GenerateProofSeriesMutations, HexIntentGenerateProofInputs, MetadataMessage, MetadataMessageResponse, NotarizedProof, NotaryRequest, PROOF_ENCODING, PeerExtensionOnrampParams, PeerOnrampPreparedTransaction, ProgressInfo, Proof, ProofResponse, ReclaimProof, SeriesProgress, SignedClaim, Status, buildBuyerTeeNotaryRequest, buildOnrampQuery, byteArrayToHexString, encodeProof, encodeProofAsBytes, encodeProofWithPaymentMethod, encodeTwoProofs, extensionUrl, findMetadataMessage, parseExtensionProof, useZKTLS } from './useZKTLS.cjs';
1
+ export { AuthenticationInputs, MetadataMessage, MetadataMessageResponse, PeerExtensionOnrampParams, PeerOnrampPreparedTransaction, Status, buildOnrampQuery, extensionUrl, useZKTLS } from './useZKTLS.cjs';
2
+ export { DEFAULT_INJECTION_WAIT_MS, InjectionGuarantee, MINIMUM_EXTENSION_VERSION, MobileDeviceSignals, ProofCapability, ProofCapabilitySignals, detectMobileDevice, isVersionAtLeast, resolveProofCapability } from './capability.cjs';
3
+ export { UseProofCapabilityOptions, useProofCapability } from './useProofCapability.cjs';
2
4
  export { ZKTLSContext, ZKTLSProvider, useZKTLSContext } from './ZKTLSContext.cjs';
3
5
  export { ExtensionEnclaveAdapterConfig, PeerClient, createExtensionEnclaveAdapter } from './adapters/extensionEnclave.cjs';
4
6
  import 'viem';
5
- import '@provex/utils/intent';
6
- import '@provex/utils/tokens';
7
7
  import '@provex/utils/payment';
8
8
  import 'react/jsx-runtime';
9
9
  import 'react';
package/dist/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- export { AuthenticationInputs, ClaimInfo, CompleteClaimData, FetchProofsResponse, GenerateProofInputs, GenerateProofInputsAbstracted, GenerateProofResponse, GenerateProofSeriesMutations, HexIntentGenerateProofInputs, MetadataMessage, MetadataMessageResponse, NotarizedProof, NotaryRequest, PROOF_ENCODING, PeerExtensionOnrampParams, PeerOnrampPreparedTransaction, ProgressInfo, Proof, ProofResponse, ReclaimProof, SeriesProgress, SignedClaim, Status, buildBuyerTeeNotaryRequest, buildOnrampQuery, byteArrayToHexString, encodeProof, encodeProofAsBytes, encodeProofWithPaymentMethod, encodeTwoProofs, extensionUrl, findMetadataMessage, parseExtensionProof, useZKTLS } from './useZKTLS.js';
1
+ export { AuthenticationInputs, MetadataMessage, MetadataMessageResponse, PeerExtensionOnrampParams, PeerOnrampPreparedTransaction, Status, buildOnrampQuery, extensionUrl, useZKTLS } from './useZKTLS.js';
2
+ export { DEFAULT_INJECTION_WAIT_MS, InjectionGuarantee, MINIMUM_EXTENSION_VERSION, MobileDeviceSignals, ProofCapability, ProofCapabilitySignals, detectMobileDevice, isVersionAtLeast, resolveProofCapability } from './capability.js';
3
+ export { UseProofCapabilityOptions, useProofCapability } from './useProofCapability.js';
2
4
  export { ZKTLSContext, ZKTLSProvider, useZKTLSContext } from './ZKTLSContext.js';
3
5
  export { ExtensionEnclaveAdapterConfig, PeerClient, createExtensionEnclaveAdapter } from './adapters/extensionEnclave.js';
4
6
  import 'viem';
5
- import '@provex/utils/intent';
6
- import '@provex/utils/tokens';
7
7
  import '@provex/utils/payment';
8
8
  import 'react/jsx-runtime';
9
9
  import 'react';
package/dist/index.js CHANGED
@@ -1,5 +1,7 @@
1
- export { ZKTLSContext, ZKTLSProvider, useZKTLSContext } from './chunk-T42E7EM7.js';
2
- export { PROOF_ENCODING, SeriesProgress, buildBuyerTeeNotaryRequest, buildOnrampQuery, byteArrayToHexString, encodeProof, encodeProofAsBytes, encodeProofWithPaymentMethod, encodeTwoProofs, extensionUrl, findMetadataMessage, parseExtensionProof, useZKTLS } from './chunk-TAS2MB4S.js';
3
- export { createExtensionEnclaveAdapter } from './chunk-AMJXMSDV.js';
1
+ export { ZKTLSContext, ZKTLSProvider, useZKTLSContext } from './chunk-B7RU2WKQ.js';
2
+ export { buildOnrampQuery, extensionUrl, useZKTLS } from './chunk-JU2T2TGY.js';
3
+ export { useProofCapability } from './chunk-VQFWUZNJ.js';
4
+ export { DEFAULT_INJECTION_WAIT_MS, MINIMUM_EXTENSION_VERSION, detectMobileDevice, isVersionAtLeast, resolveProofCapability } from './chunk-JMVW4H4H.js';
5
+ export { createExtensionEnclaveAdapter } from './chunk-WSLUOLBW.js';
4
6
  //# sourceMappingURL=index.js.map
5
7
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,104 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+
5
+ // src/useProofCapability.ts
6
+
7
+ // src/capability.ts
8
+ var MINIMUM_EXTENSION_VERSION = "0.6.0";
9
+ var DEFAULT_INJECTION_WAIT_MS = 1500;
10
+ var MOBILE_USER_AGENT_PATTERN = /Android|iPhone|iPad|iPod|Mobile|Windows Phone|IEMobile|BlackBerry|Opera Mini/i;
11
+ var detectMobileDevice = ({ userAgent, maxTouchPoints, platform }) => {
12
+ if (MOBILE_USER_AGENT_PATTERN.test(userAgent)) return true;
13
+ return platform === "MacIntel" && maxTouchPoints > 0;
14
+ };
15
+ var parseVersionParts = (version) => {
16
+ const parts = version.trim().replace(/^v/i, "").split(".");
17
+ return [0, 1, 2].map((index) => {
18
+ const parsed = Number.parseInt(parts[index] ?? "", 10);
19
+ return Number.isNaN(parsed) ? 0 : parsed;
20
+ });
21
+ };
22
+ var isVersionAtLeast = ({ current, minimum }) => {
23
+ const currentParts = parseVersionParts(current);
24
+ const minimumParts = parseVersionParts(minimum);
25
+ const firstDifference = currentParts.findIndex((part, index) => part !== minimumParts[index]);
26
+ if (firstDifference === -1) return true;
27
+ return currentParts[firstDifference] > minimumParts[firstDifference];
28
+ };
29
+ var resolveProofCapability = ({
30
+ isMobileDevice,
31
+ isPeerPresent,
32
+ hasInjectionWaitElapsed,
33
+ injection,
34
+ version
35
+ }) => {
36
+ if (isMobileDevice) return { status: "mobile" };
37
+ if (!isPeerPresent && injection === "not-guaranteed") return { status: "unknown" };
38
+ if (!isPeerPresent && !hasInjectionWaitElapsed) return { status: "checking" };
39
+ if (!isPeerPresent) return { status: "no-extension" };
40
+ if (version === void 0) return { status: "checking" };
41
+ if (version === null) return { status: "unknown" };
42
+ if (!isVersionAtLeast({ current: version, minimum: MINIMUM_EXTENSION_VERSION })) {
43
+ return { status: "outdated", version };
44
+ }
45
+ return { status: "ready", version };
46
+ };
47
+
48
+ // src/useProofCapability.ts
49
+ var PEER_INITIALIZED_EVENT = "peer#initialized";
50
+ var readIsMobileDevice = () => {
51
+ if (typeof navigator === "undefined") return false;
52
+ return detectMobileDevice({
53
+ userAgent: navigator.userAgent ?? "",
54
+ maxTouchPoints: navigator.maxTouchPoints ?? 0,
55
+ platform: navigator.platform ?? ""
56
+ });
57
+ };
58
+ var readExtensionVersion = async () => {
59
+ try {
60
+ const version = await window.peer?.getVersion?.();
61
+ return version ? version : null;
62
+ } catch {
63
+ return null;
64
+ }
65
+ };
66
+ var useProofCapability = ({
67
+ injection = "not-guaranteed",
68
+ injectionWaitMs = DEFAULT_INJECTION_WAIT_MS
69
+ } = {}) => {
70
+ const [isMobileDevice, setIsMobileDevice] = react.useState(false);
71
+ const [isPeerPresent, setIsPeerPresent] = react.useState(false);
72
+ const [hasInjectionWaitElapsed, setHasInjectionWaitElapsed] = react.useState(false);
73
+ const [version, setVersion] = react.useState(void 0);
74
+ react.useEffect(() => {
75
+ setIsMobileDevice(readIsMobileDevice());
76
+ }, []);
77
+ react.useEffect(() => {
78
+ let isCancelled = false;
79
+ const markPresent = () => {
80
+ setIsPeerPresent(true);
81
+ void readExtensionVersion().then((found) => {
82
+ if (!isCancelled) setVersion(found);
83
+ });
84
+ };
85
+ if (typeof window.peer !== "undefined") {
86
+ markPresent();
87
+ return () => {
88
+ isCancelled = true;
89
+ };
90
+ }
91
+ window.addEventListener(PEER_INITIALIZED_EVENT, markPresent);
92
+ const timer = setTimeout(() => setHasInjectionWaitElapsed(true), injectionWaitMs);
93
+ return () => {
94
+ isCancelled = true;
95
+ clearTimeout(timer);
96
+ window.removeEventListener(PEER_INITIALIZED_EVENT, markPresent);
97
+ };
98
+ }, [injectionWaitMs]);
99
+ return resolveProofCapability({ isMobileDevice, isPeerPresent, hasInjectionWaitElapsed, injection, version });
100
+ };
101
+
102
+ exports.useProofCapability = useProofCapability;
103
+ //# sourceMappingURL=useProofCapability.cjs.map
104
+ //# sourceMappingURL=useProofCapability.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/capability.ts","../src/useProofCapability.ts"],"names":["useState","useEffect"],"mappings":"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","file":"useProofCapability.cjs","sourcesContent":["/**\n * @fileoverview Pure functions that decide whether this browser can make a\n * Provex payment proof.\n *\n * A browser can make a proof when it is a desktop browser and the Peer\n * extension (version 0.6.0 or later) injects `window.peer`. The functions here\n * hold no state and read no globals, so every branch can be tested directly.\n */\n\n/**\n * The first extension version that works with the enclave-only proof path.\n * Version 0.6.0 removed `generateProof`.\n */\nexport const MINIMUM_EXTENSION_VERSION = '0.6.0'\n\n/** Default wait, in milliseconds, before a missing `window.peer` counts as missing. */\nexport const DEFAULT_INJECTION_WAIT_MS = 1_500\n\n/**\n * Whether the page can count on the extension to inject `window.peer`.\n * - `guaranteed`: the page runs on an origin where the extension injects.\n * - `not-guaranteed`: third-party origin or iframe. No `window.peer` proves nothing.\n */\nexport type InjectionGuarantee = 'guaranteed' | 'not-guaranteed'\n\n/** Browser facts used to detect a mobile device. */\nexport interface MobileDeviceSignals {\n userAgent: string\n maxTouchPoints: number\n platform: string\n}\n\n/** The result of a proof capability check. */\nexport type ProofCapability =\n | { status: 'mobile' }\n | { status: 'checking' }\n | { status: 'no-extension' }\n | { status: 'unknown' }\n | { status: 'outdated'; version: string }\n | { status: 'ready'; version: string }\n\n/** The facts that `resolveProofCapability` combines. */\nexport interface ProofCapabilitySignals {\n /** True when the device is a phone or tablet. */\n isMobileDevice: boolean\n /** True once `window.peer` exists. */\n isPeerPresent: boolean\n /** True once the wait for injection has passed. */\n hasInjectionWaitElapsed: boolean\n /** How the page gets the extension. */\n injection: InjectionGuarantee\n /**\n * The extension version. `undefined` while the lookup runs.\n * `null` when the lookup failed or returned nothing.\n */\n version: string | null | undefined\n}\n\nconst MOBILE_USER_AGENT_PATTERN = /Android|iPhone|iPad|iPod|Mobile|Windows Phone|IEMobile|BlackBerry|Opera Mini/i\n\n/**\n * Detect a phone or tablet from the user agent and touch support.\n * It does not look at the viewport width. A narrow desktop window is not mobile.\n * iPadOS 13 and later sends a desktop Mac user agent, so a \"MacIntel\"\n * platform with touch points counts as a tablet. Desktop Macs report zero.\n *\n * @param signals - user agent, touch point count, and platform string\n * @returns true when the device is mobile\n */\nexport const detectMobileDevice = ({ userAgent, maxTouchPoints, platform }: MobileDeviceSignals): boolean => {\n if (MOBILE_USER_AGENT_PATTERN.test(userAgent)) return true\n return platform === 'MacIntel' && maxTouchPoints > 0\n}\n\n/** Read up to three numeric parts. A missing or invalid part counts as zero. */\nconst parseVersionParts = (version: string): number[] => {\n const parts = version.trim().replace(/^v/i, '').split('.')\n return [0, 1, 2].map((index) => {\n const parsed = Number.parseInt(parts[index] ?? '', 10)\n return Number.isNaN(parsed) ? 0 : parsed\n })\n}\n\n/**\n * Compare two dotted versions numerically, so 0.10.0 is later than 0.6.0.\n * Missing parts count as zero, so \"0.6\" equals \"0.6.0\".\n *\n * @param options.current - the version to test\n * @param options.minimum - the lowest accepted version\n * @returns true when `current` is the same as or later than `minimum`\n */\nexport const isVersionAtLeast = ({ current, minimum }: { current: string; minimum: string }): boolean => {\n const currentParts = parseVersionParts(current)\n const minimumParts = parseVersionParts(minimum)\n const firstDifference = currentParts.findIndex((part, index) => part !== minimumParts[index])\n if (firstDifference === -1) return true\n return currentParts[firstDifference] > minimumParts[firstDifference]\n}\n\n/**\n * Combine device, extension, and timing facts into one capability result.\n *\n * Off-origin pages cannot prove that the extension is missing, so with\n * `not-guaranteed` injection a missing `window.peer` gives `unknown`.\n * With `guaranteed` injection it gives `checking` until the wait passes,\n * then `no-extension`.\n *\n * @param signals - the facts to combine\n * @returns the discriminated capability result\n */\nexport const resolveProofCapability = ({\n isMobileDevice,\n isPeerPresent,\n hasInjectionWaitElapsed,\n injection,\n version,\n}: ProofCapabilitySignals): ProofCapability => {\n if (isMobileDevice) return { status: 'mobile' }\n if (!isPeerPresent && injection === 'not-guaranteed') return { status: 'unknown' }\n if (!isPeerPresent && !hasInjectionWaitElapsed) return { status: 'checking' }\n if (!isPeerPresent) return { status: 'no-extension' }\n if (version === undefined) return { status: 'checking' }\n if (version === null) return { status: 'unknown' }\n if (!isVersionAtLeast({ current: version, minimum: MINIMUM_EXTENSION_VERSION })) {\n return { status: 'outdated', version }\n }\n return { status: 'ready', version }\n}\n","/**\n * @fileoverview React hook that reports whether this browser can make a\n * Provex payment proof. See `capability.ts` for the decision rules.\n */\n\nimport { useEffect, useState } from 'react'\nimport {\n DEFAULT_INJECTION_WAIT_MS,\n detectMobileDevice,\n resolveProofCapability,\n type InjectionGuarantee,\n type ProofCapability,\n} from './capability.js'\n\n/** Options for {@link useProofCapability}. */\nexport interface UseProofCapabilityOptions {\n /** Default `not-guaranteed`. Pass `guaranteed` on origins where the extension injects. */\n injection?: InjectionGuarantee\n /** Wait before a missing `window.peer` counts as missing. Default 1500 ms. */\n injectionWaitMs?: number\n}\n\nconst PEER_INITIALIZED_EVENT = 'peer#initialized'\n\n/** Read the device signals from `navigator`. Returns false on the server. */\nconst readIsMobileDevice = (): boolean => {\n if (typeof navigator === 'undefined') return false\n return detectMobileDevice({\n userAgent: navigator.userAgent ?? '',\n maxTouchPoints: navigator.maxTouchPoints ?? 0,\n platform: navigator.platform ?? '',\n })\n}\n\n/** Ask the extension for its version. Returns null when it cannot answer. */\nconst readExtensionVersion = async (): Promise<string | null> => {\n try {\n const version = await window.peer?.getVersion?.()\n return version ? version : null\n } catch {\n return null\n }\n}\n\n/**\n * Report whether this browser can make a Provex payment proof.\n *\n * The first render, on the server and in the browser, assumes a desktop device\n * with no extension seen. The real values load in effects, so server and\n * client markup match.\n *\n * @param options - injection guarantee and wait time\n * @returns the current {@link ProofCapability}\n */\nexport const useProofCapability = ({\n injection = 'not-guaranteed',\n injectionWaitMs = DEFAULT_INJECTION_WAIT_MS,\n}: UseProofCapabilityOptions = {}): ProofCapability => {\n const [isMobileDevice, setIsMobileDevice] = useState(false)\n const [isPeerPresent, setIsPeerPresent] = useState(false)\n const [hasInjectionWaitElapsed, setHasInjectionWaitElapsed] = useState(false)\n const [version, setVersion] = useState<string | null | undefined>(undefined)\n\n useEffect(() => {\n setIsMobileDevice(readIsMobileDevice())\n }, [])\n\n useEffect(() => {\n let isCancelled = false\n const markPresent = () => {\n setIsPeerPresent(true)\n void readExtensionVersion().then((found) => {\n if (!isCancelled) setVersion(found)\n })\n }\n if (typeof window.peer !== 'undefined') {\n markPresent()\n return () => {\n isCancelled = true\n }\n }\n window.addEventListener(PEER_INITIALIZED_EVENT, markPresent)\n const timer = setTimeout(() => setHasInjectionWaitElapsed(true), injectionWaitMs)\n return () => {\n isCancelled = true\n clearTimeout(timer)\n window.removeEventListener(PEER_INITIALIZED_EVENT, markPresent)\n }\n }, [injectionWaitMs])\n\n return resolveProofCapability({ isMobileDevice, isPeerPresent, hasInjectionWaitElapsed, injection, version })\n}\n"]}
@@ -0,0 +1,27 @@
1
+ import { InjectionGuarantee, ProofCapability } from './capability.cjs';
2
+
3
+ /**
4
+ * @fileoverview React hook that reports whether this browser can make a
5
+ * Provex payment proof. See `capability.ts` for the decision rules.
6
+ */
7
+
8
+ /** Options for {@link useProofCapability}. */
9
+ interface UseProofCapabilityOptions {
10
+ /** Default `not-guaranteed`. Pass `guaranteed` on origins where the extension injects. */
11
+ injection?: InjectionGuarantee;
12
+ /** Wait before a missing `window.peer` counts as missing. Default 1500 ms. */
13
+ injectionWaitMs?: number;
14
+ }
15
+ /**
16
+ * Report whether this browser can make a Provex payment proof.
17
+ *
18
+ * The first render, on the server and in the browser, assumes a desktop device
19
+ * with no extension seen. The real values load in effects, so server and
20
+ * client markup match.
21
+ *
22
+ * @param options - injection guarantee and wait time
23
+ * @returns the current {@link ProofCapability}
24
+ */
25
+ declare const useProofCapability: ({ injection, injectionWaitMs, }?: UseProofCapabilityOptions) => ProofCapability;
26
+
27
+ export { type UseProofCapabilityOptions, useProofCapability };
@@ -0,0 +1,27 @@
1
+ import { InjectionGuarantee, ProofCapability } from './capability.js';
2
+
3
+ /**
4
+ * @fileoverview React hook that reports whether this browser can make a
5
+ * Provex payment proof. See `capability.ts` for the decision rules.
6
+ */
7
+
8
+ /** Options for {@link useProofCapability}. */
9
+ interface UseProofCapabilityOptions {
10
+ /** Default `not-guaranteed`. Pass `guaranteed` on origins where the extension injects. */
11
+ injection?: InjectionGuarantee;
12
+ /** Wait before a missing `window.peer` counts as missing. Default 1500 ms. */
13
+ injectionWaitMs?: number;
14
+ }
15
+ /**
16
+ * Report whether this browser can make a Provex payment proof.
17
+ *
18
+ * The first render, on the server and in the browser, assumes a desktop device
19
+ * with no extension seen. The real values load in effects, so server and
20
+ * client markup match.
21
+ *
22
+ * @param options - injection guarantee and wait time
23
+ * @returns the current {@link ProofCapability}
24
+ */
25
+ declare const useProofCapability: ({ injection, injectionWaitMs, }?: UseProofCapabilityOptions) => ProofCapability;
26
+
27
+ export { type UseProofCapabilityOptions, useProofCapability };
@@ -0,0 +1,4 @@
1
+ export { useProofCapability } from './chunk-VQFWUZNJ.js';
2
+ import './chunk-JMVW4H4H.js';
3
+ //# sourceMappingURL=useProofCapability.js.map
4
+ //# sourceMappingURL=useProofCapability.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"useProofCapability.js"}