@okxweb3/app-x402-core 0.1.2 → 0.2.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.
- package/dist/cjs/OKXFacilitatorClient-Bqyw9fzj.d.ts +69 -0
- package/dist/cjs/client/index.d.ts +1 -1
- package/dist/cjs/client/index.js +34 -0
- package/dist/cjs/client/index.js.map +1 -1
- package/dist/cjs/facilitator/index.d.ts +2 -2
- package/dist/cjs/facilitator/index.js +166 -4
- package/dist/cjs/facilitator/index.js.map +1 -1
- package/dist/cjs/http/index.d.ts +5 -3
- package/dist/cjs/http/index.js +1241 -7
- package/dist/cjs/http/index.js.map +1 -1
- package/dist/cjs/index-2gWfiUbK.d.ts +713 -0
- package/dist/cjs/index.d.ts +2 -2
- package/dist/cjs/index.js +166 -4
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/{mechanisms-sojpSwWW.d.ts → mechanisms-LhI9qkRo.d.ts} +509 -1
- package/dist/cjs/server/index.d.ts +4 -2
- package/dist/cjs/server/index.js +1256 -7
- package/dist/cjs/server/index.js.map +1 -1
- package/dist/cjs/subscription/index.d.ts +3 -0
- package/dist/cjs/subscription/index.js +600 -0
- package/dist/cjs/subscription/index.js.map +1 -0
- package/dist/cjs/types/index.d.ts +1 -1
- package/dist/cjs/utils/index.d.ts +1 -1
- package/dist/cjs/{x402HTTPResourceServer-CcsAkcgI.d.ts → x402HTTPResourceServer-B0mXzV8r.d.ts} +114 -1
- package/dist/esm/OKXFacilitatorClient-z-cCE5Db.d.mts +69 -0
- package/dist/esm/chunk-4KASWSSY.mjs +257 -0
- package/dist/esm/chunk-4KASWSSY.mjs.map +1 -0
- package/dist/esm/chunk-CKXR4QVD.mjs +274 -0
- package/dist/esm/chunk-CKXR4QVD.mjs.map +1 -0
- package/dist/esm/{chunk-XBQG2CDV.mjs → chunk-EYS4TWVA.mjs} +617 -9
- package/dist/esm/chunk-EYS4TWVA.mjs.map +1 -0
- package/dist/esm/client/index.d.mts +1 -1
- package/dist/esm/client/index.mjs +3 -2
- package/dist/esm/client/index.mjs.map +1 -1
- package/dist/esm/facilitator/index.d.mts +2 -2
- package/dist/esm/facilitator/index.mjs +2 -1
- package/dist/esm/facilitator/index.mjs.map +1 -1
- package/dist/esm/http/index.d.mts +5 -3
- package/dist/esm/http/index.mjs +3 -2
- package/dist/esm/index-DKbqlTu_.d.mts +713 -0
- package/dist/esm/index.d.mts +2 -2
- package/dist/esm/index.mjs +2 -1
- package/dist/esm/{mechanisms-sojpSwWW.d.mts → mechanisms-LhI9qkRo.d.mts} +509 -1
- package/dist/esm/server/index.d.mts +4 -2
- package/dist/esm/server/index.mjs +3 -2
- package/dist/esm/subscription/index.d.mts +3 -0
- package/dist/esm/subscription/index.mjs +309 -0
- package/dist/esm/subscription/index.mjs.map +1 -0
- package/dist/esm/types/index.d.mts +1 -1
- package/dist/esm/utils/index.d.mts +1 -1
- package/dist/esm/{x402HTTPResourceServer-DBeutKxq.d.mts → x402HTTPResourceServer-56Tq3Jup.d.mts} +114 -1
- package/package.json +12 -1
- package/dist/cjs/OKXFacilitatorClient-BvyQB1QM.d.ts +0 -59
- package/dist/esm/OKXFacilitatorClient-D5E3LX50.d.mts +0 -59
- package/dist/esm/chunk-O3IYMTNT.mjs +0 -118
- package/dist/esm/chunk-O3IYMTNT.mjs.map +0 -1
- package/dist/esm/chunk-XBQG2CDV.mjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/subscription/index.ts","../../../src/subscription/types.ts","../../../src/subscription/errors.ts","../../../src/subscription/store.ts","../../../src/subscription/client.ts","../../../src/subscription/codec/typed-data.ts","../../../src/subscription/codec/verify-terms.ts","../../../src/subscription/codec/period-math.ts","../../../src/subscription/codec/base64.ts","../../../src/subscription/codec/payload.ts","../../../src/subscription/codec/access-proof.ts","../../../src/subscription/facilitator-client.ts"],"sourcesContent":["export type {\n AccessProof,\n AccessRouteRequirements,\n CancelAuth,\n PendingChangeCancelAuth,\n CancelInitiator,\n ChargeResult,\n PendingPlanChange,\n PlanCatalog,\n PlanCatalogEntry,\n PlanInitialCharge,\n OnBeforeAccessContext,\n OnBeforeAccessHook,\n OnBeforeAccessResult,\n SettleCancelOk,\n SettleCancelPendingChangeOk,\n SettleCancelPendingChangeResult,\n SettleCancelResult,\n SettleChangeOk,\n SettleChangeResult,\n SettleResultFail,\n SettleSubscribeOk,\n SettleSubscribeResult,\n Subscription,\n SubscriptionCapability,\n SubscriptionState,\n VerifyAccessOk,\n VerifyAccessResult,\n VerifyOwnershipOk,\n VerifyOwnershipResult,\n VerifyChangeOk,\n VerifyChangeResult,\n VerifyResult,\n VerifyResultFail,\n VerifyResultOk,\n} from \"./types\";\nexport { hasSubscriptionCapability } from \"./types\";\n\nexport { ChargeError, ChargeErrorCode, ErrorCode } from \"./errors\";\n\nexport type { SubscriptionStore } from \"./store\";\nexport { InMemoryStore } from \"./store\";\n\nexport type { SubscriptionClientConfig } from \"./client\";\nexport { SubscriptionClient } from \"./client\";\n\nexport type {\n AccessProofMessageInput,\n BuildCancelAuthTypedDataInput,\n BuildPermit2TypedDataInput,\n BuildSubscriptionTermsTypedDataInput,\n ChangeFromExtra,\n EncodePaymentPayloadInput,\n PermitSingleData,\n SubscriptionContractAddresses,\n SubscriptionPaymentInner,\n SubscriptionPlanExtra,\n SubscriptionRequirementsExtra,\n SubscriptionTerms,\n TypedDataEnvelope,\n} from \"./codec\";\nexport {\n asSubscriptionPaymentInner,\n addCalendarMonths,\n base64DecodeUtf8,\n base64EncodeUtf8,\n buildAccessProofMessage,\n buildCancelAuthTypedData,\n buildPendingChangeCancelAuthTypedData,\n buildPermit2TypedData,\n buildSubscriptionTermsTypedData,\n CANCEL_AUTH_TYPES,\n computeElapsedPeriods,\n computePermitSingleStructHash,\n decodeAccessProof,\n decodePaymentPayload,\n elapsedCalendarMonths,\n encodeAccessProof,\n encodePaymentPayload,\n parseChainIdFromNetwork,\n parsePaymentRequired,\n PENDING_CHANGE_CANCEL_AUTH_TYPES,\n PERMIT2_TYPES,\n SUBSCRIPTION_TERMS_TYPES,\n verifyTermsBindRequirements,\n ZERO_BYTES32,\n} from \"./codec\";\n\nexport type {\n FacilitatorCancelData,\n FacilitatorCancelPendingData,\n FacilitatorChangeData,\n FacilitatorChargeData,\n FacilitatorChargeRow,\n FacilitatorEnvelope,\n FacilitatorFinalizeExpiredData,\n FacilitatorGetChargesData,\n FacilitatorGetSubscriptionData,\n FacilitatorPendingChangeRow,\n FacilitatorSubscribeData,\n SubscriptionFacilitatorClient,\n} from \"./facilitator-client\";\nexport { supportsSubscription } from \"./facilitator-client\";\n","import type { PaymentPayload, PaymentRequirements } from \"../types/payments\";\n\n/**\n * Subscription state: `active`, `canceled`, `completed`, `changed`.\n */\n/**\n * Local mirror of facilitator's SubscriptionState enum. Numeric mapping:\n * 0 pending / 1 active / 2 completed / 3 canceled / 4 changed / 99 failed\n */\nexport type SubscriptionState =\n | \"pending\"\n | \"active\"\n | \"completed\"\n | \"canceled\"\n | \"changed\"\n | \"failed\";\n\n/**\n * Set on an ACTIVE sub when a downgrade has been scheduled but not yet\n * activated. `state` lets the seller observe the terminal disposition\n * (PENDING / ACTIVATED / CANCELED / EXPIRED) via GET /pending.\n */\nexport interface PendingPlanChange {\n subId: string;\n newSubId: string;\n effectiveFromPeriod: number;\n /** 0 pending / 1 activated / 2 canceled / 3 expired. */\n state: number;\n}\n\n/**\n * Seller-side projection of a subscription. All fields come from the\n * facilitator GET /subscriptions/detail endpoint; the store never holds\n * data the facilitator can't refresh.\n *\n * Snapshot fields (`isActive` / `serviceEnded` / `currentPeriod` /\n * `elapsedPeriods` / `nextChargeableAt`) are valid as of the last sync\n * only; they drift with wall-clock time.\n */\nexport interface Subscription {\n subId: string;\n payer: string;\n merchant: string;\n token: string;\n amountPerPeriod: string;\n /** 0 fixed_seconds / 1 calendar_month. */\n periodMode: number;\n periodSec: number;\n /** Calendar-month billing anchor (Unix s). Undefined or 0 in fixed_seconds mode. */\n billingAnchorAt?: number;\n maxPeriods: number;\n startAt: number;\n state: SubscriptionState;\n lastChargedPeriod: number;\n totalPulled: string;\n planId: string;\n planTier: number;\n changedToSubId?: string;\n pendingPlanChange?: PendingPlanChange;\n /** Derived snapshot — true iff state==ACTIVE && now < endAt. */\n isActive?: boolean;\n /** Derived snapshot — true iff state==ACTIVE && !isActive (expired, not yet finalized). */\n serviceEnded?: boolean;\n /** Derived snapshot — current period number, clamped to maxPeriods. */\n currentPeriod?: number;\n /** Derived snapshot — real elapsed period count, NOT clamped (use this for expiry checks). */\n elapsedPeriods?: number;\n /** Derived snapshot — next chargeable boundary (Unix s); null when all periods are charged. */\n nextChargeableAt?: number;\n}\n\nexport interface AccessProof {\n kind: \"subscription-id\";\n subId: string;\n payer: string;\n timestamp: number;\n signature: string;\n}\n\n/**\n * `CancelAuth.initiator` enum — only payer / merchant.\n */\nexport type CancelInitiator = \"payer\" | \"merchant\";\n\n/**\n * EIP-712 `CancelAuth` payload (subscription contract domain):\n * `CancelAuth(uint8 action, bytes32 subId, uint8 initiator, bytes32 nonce, uint64 deadline)`\n *\n * `action` is locked to `0 = cancel_subscription`. `cancel_pending_change`\n * uses the standalone `cancel-pending-change` endpoint with its own\n * `PendingChangeCancelAuth` signature.\n */\nexport interface CancelAuth {\n action: 0;\n subId: string;\n initiator: 0 | 1;\n nonce: string;\n deadline: number;\n signature: string;\n}\n\n/**\n * EIP-712 `PendingChangeCancelAuth` payload (subscription contract domain).\n * Payer-only.\n *\n * TypeHash:\n * keccak256(\"PendingChangeCancelAuth(bytes32 subId,bytes32 newSubId,bytes32 nonce,uint64 deadline)\")\n *\n * `newSubId` MUST equal the currently-PENDING `pendingPlanChange.newSubId`\n * (the to-be-cancelled downgrade target); facilitator rejects with\n * `pending_cancel_target_mismatch` otherwise.\n */\nexport interface PendingChangeCancelAuth {\n subId: string;\n newSubId: string;\n nonce: string;\n deadline: number;\n signature: string;\n}\n\nexport interface PlanInitialCharge {\n periodCount: number;\n totalAmount: string;\n}\n\nexport interface PlanCatalogEntry {\n id: string;\n tier: number;\n amountPerPeriod: string;\n /** 0 fixed_seconds (default) / 1 calendar_month. */\n periodMode?: 0 | 1;\n periodSec: number;\n maxPeriods: number;\n /**\n * ERC-20 token address. Optional — if omitted, the EVM scheme fills from\n * `getDefaultAsset(network)` (same per-network map exact / upto /\n * aggr_deferred consume).\n */\n asset?: string;\n payTo: string;\n initialCharge?: PlanInitialCharge;\n name?: string;\n}\n\nexport type PlanCatalog = Record<string, PlanCatalogEntry>;\n\nexport interface AccessRouteRequirements {\n /**\n * PlanIds that satisfy this route. Derived from the route's `accepts`\n * payment options (`accepts[].extra.plan.id`). A subscription is allowed\n * access iff its `planId` appears in this list.\n *\n * `undefined` means \"no plan restriction\" — any active subscription on\n * the route passes (use sparingly).\n */\n acceptedPlanIds?: string[];\n\n /**\n * Full `PaymentRequirements` for every plan the route accepts — the same\n * list the seller declared as `RouteConfig.accepts`, resolved to wire\n * format. Each entry carries the plan metadata in `extra.plan`\n * (`{ id, tier, name }`) plus `extra.amountPerPeriod`, `extra.periodSec`,\n * `extra.periodMode`, `extra.maxPeriods`, etc. — everything an\n * `onBeforeAccess` hook needs to decide policy against catalog details\n * (upgrade offers, tier ceilings, per-plan feature flags) without joining\n * an external catalog table.\n */\n accepts?: PaymentRequirements[];\n}\n\n/**\n * Context passed to `OnBeforeAccessHook`. Carries the full stored\n * `Subscription` (so the seller can inspect any field — payer, planId,\n * lastChargedPeriod, changedToSubId, etc. — for arbitrary policy) plus\n * the incoming HTTP request shape and route metadata.\n */\nexport interface OnBeforeAccessContext {\n subscription: Subscription;\n request: {\n path: string;\n method: string;\n headers: Record<string, string>;\n };\n route: AccessRouteRequirements;\n}\n\n/**\n * Result of an `OnBeforeAccessHook`:\n * - `{ ok: true }` → allow the request through\n * - `{ ok: false }` → deny; `error` shows up in the 402 body, `retryAfter`\n * (seconds) becomes a `Retry-After` header hint, `upgradeOffers` lets\n * the seller point the buyer at an alternate plan\n *\n * Denial use cases: rate-limiting, quota exhaustion, bans / blacklists,\n * per-plan feature gating beyond the simple `acceptedPlanIds` allowlist.\n */\nexport type OnBeforeAccessResult =\n | { ok: true }\n | {\n ok: false;\n error?: string;\n retryAfter?: number;\n upgradeOffers?: PaymentRequirements[];\n };\n\n/**\n * Route-level hook fired AFTER `verifyAccess` succeeded (signature +\n * payer + plan-allowlist + period math) but BEFORE the handler runs.\n * The seller uses it to implement custom access policy — e.g. a ban list\n * keyed by subId or payer, per-plan feature flags, or dynamic quota.\n */\nexport type OnBeforeAccessHook = (ctx: OnBeforeAccessContext) => Promise<OnBeforeAccessResult>;\n\nexport type VerifyResultOk = { ok: true };\nexport type VerifyResultFail = { ok: false; error: string };\nexport type VerifyResult = VerifyResultOk | VerifyResultFail;\n\nexport interface VerifyChangeOk {\n ok: true;\n oldSubId: string;\n direction: \"upgrade\" | \"downgrade\";\n}\nexport type VerifyChangeResult = VerifyChangeOk | VerifyResultFail;\n\nexport interface VerifyAccessOk {\n ok: true;\n subscription: Subscription;\n}\nexport type VerifyAccessResult = VerifyAccessOk | VerifyResultFail;\n\n/**\n * Result of `verifyOwnership` — used by the change-route sniff path to\n * confirm the AccessProof signer owns the named subscription, without\n * imposing the plan-allowlist / period-math gating that `verifyAccess`\n * applies for resource consumption.\n */\nexport interface VerifyOwnershipOk {\n ok: true;\n subId: string;\n payer: string;\n subscription: Subscription;\n}\nexport type VerifyOwnershipResult = VerifyOwnershipOk | VerifyResultFail;\n\nexport type SettleResultFail = {\n success: false;\n error: string;\n /**\n * Set when the chain operation may still complete asynchronously: the\n * facilitator accepted the write call but returned `state=pending`, and the\n * SDK's client-side polling (5×1s) timed out before settlement. Seller\n * should remember `subId` and call `syncFromChain(subId)` later.\n */\n subId?: string;\n pending?: boolean;\n};\n\nexport interface SettleSubscribeOk {\n success: true;\n subId: string;\n subscription: Subscription;\n headers: Record<string, string>;\n}\nexport type SettleSubscribeResult = SettleSubscribeOk | SettleResultFail;\n\nexport interface SettleChangeOk {\n success: true;\n oldSubId: string;\n newSubId: string;\n operationType: \"upgrade\" | \"downgrade\";\n scheduledFromPeriod?: number;\n headers: Record<string, string>;\n}\nexport type SettleChangeResult = SettleChangeOk | SettleResultFail;\n\nexport interface SettleCancelOk {\n success: true;\n subId: string;\n headers: Record<string, string>;\n}\nexport type SettleCancelResult = SettleCancelOk | SettleResultFail;\n\n/**\n * Result of `settleCancelPendingChange` — cancels a scheduled downgrade\n * (removes `pendingPlanChange` on the old sub while the sub itself stays\n * ACTIVE). No refund, no state transition on the sub itself.\n */\nexport interface SettleCancelPendingChangeOk {\n success: true;\n subId: string;\n headers: Record<string, string>;\n}\nexport type SettleCancelPendingChangeResult = SettleCancelPendingChangeOk | SettleResultFail;\n\nexport interface ChargeResult {\n success: true;\n period: number;\n amount: string;\n txHash?: string;\n planChangeTriggered?: boolean;\n newSubId?: string;\n}\n\nexport interface SubscriptionCapability {\n readonly settlementMode: \"pre\";\n\n verifySubscribe(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n ): Promise<VerifyResult>;\n\n settleSubscribe(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n ): Promise<SettleSubscribeResult>;\n\n /**\n * Inject `extra.changeFrom = { fromSubId, fromPlanId, fromPlanTier,\n * direction, effectiveAt }` into each accept of a change route's 402\n * accepts. Direction / effectiveAt are derived per-accept by comparing\n * `accept.extra.plan.tier` against the stored `oldSub.planTier`. Same-tier\n * accepts are dropped (a change to the same tier is illegal —\n * `tier_same`).\n *\n * Returns `null` when the seller's local store has no record of\n * `currentSubId` — middleware then 404s the GET so buyers see the misuse.\n */\n enrichAcceptsForChange(\n accepts: PaymentRequirements[],\n currentSubId: string,\n ): Promise<PaymentRequirements[] | null>;\n\n verifyChange(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n ): Promise<VerifyChangeResult>;\n\n settleChange(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n ): Promise<SettleChangeResult>;\n\n verifyCancel(auth: CancelAuth, subId: string): Promise<VerifyResult>;\n\n settleCancel(auth: CancelAuth, subId: string): Promise<SettleCancelResult>;\n\n /**\n * Verify a `PendingChangeCancelAuth` before facilitator submission.\n * Requires `auth.subId == body.subId` and `auth.newSubId` equal to the\n * currently PENDING `pendingPlanChange.newSubId` — the SDK checks the\n * former; facilitator enforces the latter as\n * `pending_cancel_target_mismatch`.\n */\n verifyCancelPendingChange(auth: PendingChangeCancelAuth, subId: string): Promise<VerifyResult>;\n\n /**\n * Cancel a scheduled downgrade (`pendingPlanChange`) — the current sub\n * stays ACTIVE, only the pending row is retired. Facilitator returns the\n * new state; SDK re-pulls GET /detail to refresh the store entry.\n */\n settleCancelPendingChange(\n auth: PendingChangeCancelAuth,\n subId: string,\n ): Promise<SettleCancelPendingChangeResult>;\n\n verifyAccess(proof: AccessProof, route: AccessRouteRequirements): Promise<VerifyAccessResult>;\n\n /**\n * Lightweight ownership check for the change-route sniff path. Verifies\n * the AccessProof signature, looks up the sub in the store, and confirms\n * `sub.payer == proof.payer`. Deliberately does NOT enforce plan\n * allowlist or period math — the caller is identifying themselves to\n * receive change offers, not consuming a protected resource.\n */\n verifyOwnership(proof: AccessProof): Promise<VerifyOwnershipResult>;\n\n charge(subId: string): Promise<ChargeResult>;\n\n getSubscription(subId: string): Promise<Subscription | null>;\n}\n\nexport function hasSubscriptionCapability(scheme: unknown): scheme is SubscriptionCapability {\n return (\n typeof scheme === \"object\" &&\n scheme !== null &&\n \"verifyAccess\" in scheme &&\n \"settlementMode\" in scheme &&\n (scheme as { settlementMode: unknown }).settlementMode === \"pre\"\n );\n}\n","/**\n * Canonical facilitator error reasons. The SDK uses these literal strings\n * verbatim in verify / settle / charge return values so seller code can\n * switch on a single set of codes regardless of whether the rejection\n * originated in the SDK pre-check or in the facilitator response.\n */\nexport const ErrorCode = {\n // subscribe / change\n TermsBindingInvalid: \"terms_binding_invalid\",\n AllowanceInsufficient: \"allowance_insufficient\",\n AllowanceExpired: \"allowance_expired\",\n // charge\n PeriodNotDue: \"period_not_due\",\n InsufficientBalance: \"insufficient_balance\",\n // charge / cancel / access\n SubscriptionNotActive: \"subscription_not_active\",\n /**\n * SDK-local code. Surfaced by `verifyAccess` when local period math\n * yields `currentCalculatePeriod === 0` — subscription exists but\n * `nowSec < startAt`, i.e. has not yet entered its first chargeable\n * period.\n */\n SubscriptionNotYetActive: \"subscription_not_yet_active\",\n UnauthorizedCaller: \"unauthorized_caller\",\n // cancel\n CancelSignatureInvalid: \"cancel_signature_invalid\",\n CancelNonceUsed: \"cancel_nonce_used\",\n // change\n TierSame: \"tier_same\",\n ChangeEffectiveAtMismatch: \"change_effective_at_mismatch\",\n MerchantMismatch: \"merchant_mismatch\",\n PayerMismatch: \"payer_mismatch\",\n PendingChangeExists: \"pending_change_exists\",\n SubNotActiveForChange: \"sub_not_active_for_change\",\n // cancel-pending-change\n NoPendingChange: \"no_pending_change\",\n // all writes\n ConfirmationTimeout: \"confirmation_timeout\",\n} as const;\n\nexport type ErrorCode = (typeof ErrorCode)[keyof typeof ErrorCode];\n\n/**\n * Charge-flow subset of ErrorCode. Seller scheduler switches on these 6\n * codes.\n */\nexport const ChargeErrorCode = {\n PeriodNotDue: ErrorCode.PeriodNotDue,\n SubscriptionNotActive: ErrorCode.SubscriptionNotActive,\n InsufficientBalance: ErrorCode.InsufficientBalance,\n AllowanceExpired: ErrorCode.AllowanceExpired,\n UnauthorizedCaller: ErrorCode.UnauthorizedCaller,\n ConfirmationTimeout: ErrorCode.ConfirmationTimeout,\n} as const;\n\nexport type ChargeErrorCode = (typeof ChargeErrorCode)[keyof typeof ChargeErrorCode];\n\nexport class ChargeError extends Error {\n public readonly code: ChargeErrorCode;\n public readonly subId: string;\n public readonly txHash?: string;\n\n constructor(code: ChargeErrorCode, subId: string, txHash?: string) {\n super(`charge failed: ${code} (sub=${subId})`);\n this.name = \"ChargeError\";\n this.code = code;\n this.subId = subId;\n this.txHash = txHash;\n }\n}\n","import type { Subscription } from \"./types\";\n\n/**\n * Persistence abstraction for subscription state.\n *\n * Intentionally minimal — every state transition is performed by `put`-ing\n * the full Subscription object, and every lookup is by `subId`. Address /\n * payer-indexed queries are deliberately NOT part of this contract: the\n * seller's own data model should own that (e.g. by mapping wallet →\n * subId(s) in its user table), keeping the SDK store free of any secondary\n * index requirement.\n */\nexport interface SubscriptionStore {\n get(subId: string): Promise<Subscription | null>;\n put(sub: Subscription): Promise<void>;\n delete(subId: string): Promise<void>;\n}\n\n/**\n * In-memory reference implementation. Suitable for development / unit tests /\n * single-process demos only — multi-process deployments must replace this\n * with a shared persistent backend.\n */\nexport class InMemoryStore implements SubscriptionStore {\n private readonly data = new Map<string, Subscription>();\n\n async get(subId: string): Promise<Subscription | null> {\n const sub = this.data.get(subId);\n return sub ? { ...sub } : null;\n }\n\n async put(sub: Subscription): Promise<void> {\n this.data.set(sub.subId, { ...sub });\n }\n\n async delete(subId: string): Promise<void> {\n this.data.delete(subId);\n }\n\n /**\n * Return all subscriptions, ordered by `startAt` ascending. Not part of\n * the SubscriptionStore interface — admin/debug helper, not used by the\n * scheme. Production backends should expose paginated equivalents.\n */\n async list(): Promise<Subscription[]> {\n return Array.from(this.data.values())\n .map(s => ({ ...s }))\n .sort((a, b) => a.startAt - b.startAt);\n }\n}\n","import type { CancelAuth, ChargeResult, Subscription, SubscriptionCapability } from \"./types\";\nimport type { SubscriptionStore } from \"./store\";\n\nexport interface SubscriptionClientConfig {\n /**\n * The scheme instance to delegate facilitator-touching operations to.\n * Typically the same `PermitSubscriptionScheme` instance that is registered\n * to `x402ResourceServer`, so HTTP main-line state and out-of-band charge\n * state share one source of truth.\n */\n scheme: SubscriptionCapability;\n /**\n * The store the scheme writes to. Required here because `getSubscription`\n * reads from the store (fast path) while `syncFromChain` writes to it after\n * re-fetching from chain.\n */\n store: SubscriptionStore;\n}\n\n/**\n * Out-of-band primitives for Seller scheduler / business code. SDK ships the\n * per-call atoms (charge / cancelBySeller / syncFromChain / etc.) but NOT a\n * scheduler — cron, due index, retry policy, distributed locks are all\n * Seller infrastructure.\n *\n * All methods are thin wrappers:\n * - `charge` delegates to scheme.charge (throws ChargeError on fail)\n * - `cancelBySeller` delegates to scheme.settleCancel with a Seller-built\n * CancelAuth\n * - `syncFromChain` re-pulls Subscription via scheme.getSubscription and\n * repairs the store; connects with the `state===\"changed\"`\n * chain to also sync the downstream new sub\n * - `getSubscription` direct store read (does NOT touch the chain)\n */\nexport class SubscriptionClient {\n protected readonly scheme: SubscriptionCapability;\n protected readonly store: SubscriptionStore;\n\n constructor(config: SubscriptionClientConfig) {\n this.scheme = config.scheme;\n this.store = config.store;\n }\n\n /**\n * Run one charge period for a subscription. Throws `ChargeError` (one of 6\n * codes) on facilitator-side failure. Internally `scheme.charge` already\n * updates the store on success (and on `planChangeTriggered`); the client is\n * a pass-through.\n */\n async charge(subId: string): Promise<ChargeResult> {\n return this.scheme.charge(subId);\n }\n\n /**\n * Seller-initiated cancel (e.g. ToS violation, fraud, business reason).\n *\n * The SDK does NOT hold the Seller's merchant private key; the Seller must\n * construct + sign a `CancelAuth` with `by=1 (MERCHANT)` outside and pass\n * it in. SDK runs verifyCancel (sanity check on the auth) then settleCancel\n * (facilitator + store mark canceled).\n *\n * Throws on either verify or settle failure.\n */\n async cancelBySeller(subId: string, auth: CancelAuth, _reason?: string): Promise<void> {\n const v = await this.scheme.verifyCancel(auth, subId);\n if (!v.ok) {\n throw new Error(`cancelBySeller.verify failed: ${v.error}`);\n }\n const r = await this.scheme.settleCancel(auth, subId);\n if (!r.success) {\n throw new Error(`cancelBySeller.settle failed: ${r.error}`);\n }\n }\n\n /**\n * Re-sync a subscription from chain and repair the store. Use when:\n * - `charge` threw `SubscriptionNotActive` (buyer may have cancelled\n * directly via the facilitator or contract)\n * - `charge` threw `ConfirmationTimeout` (network-level failure; chain\n * may or may not have written)\n * - periodic reconciliation\n *\n * If the synced sub is in `\"changed\"` state, the downstream `changedToSubId`\n * is also fetched and persisted, so the Seller's `dueIndex` can switch over\n * to the new sub without manual intervention.\n */\n async syncFromChain(subId: string): Promise<Subscription | null> {\n const latest = await this.scheme.getSubscription(subId);\n if (!latest) return null;\n await this.store.put(latest);\n\n if (latest.state === \"changed\" && latest.changedToSubId) {\n const newSub = await this.scheme.getSubscription(latest.changedToSubId);\n if (newSub) await this.store.put(newSub);\n }\n return latest;\n }\n\n /**\n * Direct store read. Cheap; does NOT touch the chain. Use this for hot-path\n * lookups (e.g. resolving subId to plan/tier for business logic). For chain\n * state of record, use `syncFromChain`.\n */\n async getSubscription(subId: string): Promise<Subscription | null> {\n return this.store.get(subId);\n }\n}\n","import { encodeAbiParameters, keccak256, type Hex, type TypedDataDomain } from \"viem\";\n\nimport type { PaymentRequirements } from \"../../types/payments\";\nimport type { CancelInitiator, PlanInitialCharge } from \"../types\";\nimport type { PermitSingleData, SubscriptionTerms } from \"./payload\";\n\n/** 32-byte zero hash, used as the sentinel for empty bytes32 fields. */\nexport const ZERO_BYTES32: Hex = `0x${\"0\".repeat(64)}`;\n\n/**\n * Permit2 PermitSingle (AllowanceTransfer) EIP-712 schema. Used for the\n * continuous-pull authorization signed by the buyer. The Permit2 domain has\n * NO `version` field — only `name=\"Permit2\"`, `chainId`, `verifyingContract`.\n */\nexport const PERMIT2_TYPES = {\n PermitSingle: [\n { name: \"details\", type: \"PermitDetails\" },\n { name: \"spender\", type: \"address\" },\n { name: \"sigDeadline\", type: \"uint256\" },\n ],\n PermitDetails: [\n { name: \"token\", type: \"address\" },\n { name: \"amount\", type: \"uint160\" },\n { name: \"expiration\", type: \"uint48\" },\n { name: \"nonce\", type: \"uint48\" },\n ],\n} as const;\n\n/**\n * SubscriptionTerms EIP-712 schema. 17 fields; field ORDER + integer widths\n * must mirror the contract. TypeHash:\n * 0xa5223de56e7694cf776c7d4f74c0323f42bf9e65655fe49affefbdfd40ec97ae\n * (verify against contract `SUBSCRIPTION_TERMS_TYPEHASH()`)\n */\nexport const SUBSCRIPTION_TERMS_TYPES = {\n SubscriptionTerms: [\n { name: \"payer\", type: \"address\" },\n { name: \"merchant\", type: \"address\" },\n { name: \"facilitator\", type: \"address\" },\n { name: \"token\", type: \"address\" },\n { name: \"amountPerPeriod\", type: \"uint160\" },\n { name: \"periodSec\", type: \"uint64\" },\n { name: \"maxPeriods\", type: \"uint32\" },\n { name: \"startAt\", type: \"uint64\" },\n { name: \"initialChargePeriods\", type: \"uint32\" },\n { name: \"initialChargeAmount\", type: \"uint160\" },\n { name: \"termsDeadline\", type: \"uint64\" },\n { name: \"permitHash\", type: \"bytes32\" },\n { name: \"salt\", type: \"bytes32\" },\n { name: \"planTier\", type: \"uint8\" },\n { name: \"changeFromSubId\", type: \"bytes32\" },\n { name: \"changeEffectiveAt\", type: \"uint8\" },\n { name: \"periodMode\", type: \"uint8\" },\n ],\n} as const;\n\n/**\n * CancelAuth EIP-712 schema (subscription contract domain):\n * `CancelAuth(uint8 action, bytes32 subId, uint8 initiator, bytes32 nonce, uint64 deadline)`\n */\nexport const CANCEL_AUTH_TYPES = {\n CancelAuth: [\n { name: \"action\", type: \"uint8\" },\n { name: \"subId\", type: \"bytes32\" },\n { name: \"initiator\", type: \"uint8\" },\n { name: \"nonce\", type: \"bytes32\" },\n { name: \"deadline\", type: \"uint64\" },\n ],\n} as const;\n\n/**\n * PendingChangeCancelAuth EIP-712 schema (subscription contract domain):\n * `PendingChangeCancelAuth(bytes32 subId, bytes32 newSubId, bytes32 nonce, uint64 deadline)`\n */\nexport const PENDING_CHANGE_CANCEL_AUTH_TYPES = {\n PendingChangeCancelAuth: [\n { name: \"subId\", type: \"bytes32\" },\n { name: \"newSubId\", type: \"bytes32\" },\n { name: \"nonce\", type: \"bytes32\" },\n { name: \"deadline\", type: \"uint64\" },\n ],\n} as const;\n\nexport interface SubscriptionPlanExtra {\n id: string;\n tier: number;\n name?: string;\n}\n\n/**\n * Buyer's intent to switch from `fromSubId` to a new plan. Present on\n * PaymentRequirements.extra ONLY when the requirements are a change offer\n * for an upgrade/downgrade.\n */\nexport interface ChangeFromExtra {\n fromSubId: Hex;\n fromPlanId: Hex;\n fromPlanTier: number;\n direction: \"upgrade\" | \"downgrade\";\n effectiveAt: \"immediate\" | \"period_end\";\n}\n\nexport interface SubscriptionContractAddresses {\n subscription: string;\n permit2: string;\n}\n\n/**\n * Typed view of the `extra` field on subscription PaymentRequirements. The\n * evm scheme is responsible for producing PaymentRequirements whose `extra`\n * matches this shape; codec helpers consume it via this type rather than\n * Record<string, unknown> to keep field access type-safe.\n *\n * Index signature lets this be assigned directly to\n * `PaymentRequirements.extra: Record<string, unknown>` without a cast.\n */\nexport interface SubscriptionRequirementsExtra {\n contracts: SubscriptionContractAddresses;\n facilitator: string;\n amountPerPeriod: string;\n periodSec: number;\n /** uint8 — 0 fixed_seconds (default) / 1 calendar_month. */\n periodMode?: number;\n maxPeriods: number;\n startAt?: number;\n initialCharge?: PlanInitialCharge | null;\n plan: SubscriptionPlanExtra;\n changeFrom?: ChangeFromExtra;\n domain: TypedDataDomain;\n [key: string]: unknown;\n}\n\nexport interface TypedDataEnvelope<TPrimary extends string, TMessage> {\n domain: TypedDataDomain;\n types: Record<string, ReadonlyArray<{ name: string; type: string }>>;\n primaryType: TPrimary;\n message: TMessage;\n}\n\nexport interface BuildPermit2TypedDataInput {\n /** PaymentRequirements with subscription `extra`. */\n selected: PaymentRequirements;\n /** uint48 — current nonce from allowance-status (NOT +1). */\n nonce: number;\n /** uint48 unix seconds — Permit2 allowance expiration. */\n expiration: number;\n /** uint256 decimal — outer signature expiry. */\n sigDeadline: string;\n /** Override amount; default = initialChargeAmount + (maxPeriods - initialChargePeriods) * amountPerPeriod. */\n amount?: string;\n}\n\nexport interface BuildSubscriptionTermsTypedDataInput {\n selected: PaymentRequirements;\n payer: string;\n startAt: number;\n /** uint64 unix seconds — terms signature validity. */\n termsDeadline: number;\n /** bytes32 — random anti-replay; reuse the same hex string ≤ once. */\n salt: Hex;\n /** bytes32 — keccak256 of the PermitSingle struct hash; bind permit. */\n permitHash: Hex;\n changeFrom?: ChangeFromExtra;\n /** Override domain for special cases; defaults to `selected.extra.domain`. */\n domain?: TypedDataDomain;\n}\n\nexport interface BuildCancelAuthTypedDataInput {\n subId: Hex;\n initiator: CancelInitiator;\n /** uint64 unix seconds. */\n deadline: number;\n /** bytes32. */\n nonce: Hex;\n domain: TypedDataDomain;\n}\n\nexport interface BuildPendingChangeCancelAuthTypedDataInput {\n subId: Hex;\n /** The pending change's target newSubId — must match `pendingPlanChange.newSubId`. */\n newSubId: Hex;\n deadline: number;\n nonce: Hex;\n domain: TypedDataDomain;\n}\n\nconst CANCEL_INITIATOR_TO_ENUM: Record<CancelInitiator, 0 | 1> = {\n payer: 0,\n merchant: 1,\n};\n\nfunction getSubscriptionExtra(req: PaymentRequirements): SubscriptionRequirementsExtra {\n const extra = req.extra as Partial<SubscriptionRequirementsExtra> | undefined;\n if (!extra || !extra.contracts || !extra.plan || !extra.domain) {\n throw new Error(\n \"subscription codec: PaymentRequirements.extra is missing contracts/plan/domain\",\n );\n }\n return extra as SubscriptionRequirementsExtra;\n}\n\n/**\n * Default permit.amount:\n * amount ≥ reservedAmount + newCommit\n * newCommit = initialChargeAmount + (maxPeriods - initialChargePeriods) * amountPerPeriod\n *\n * `reservedAmount` (existing on-chain commitments) is NOT included here —\n * Buyer SDK should add it on top from `allowance-status.reservedAmount` if a\n * concurrent sub already holds budget against the same (payer, token).\n */\nfunction defaultPermitAmount(extra: SubscriptionRequirementsExtra): string {\n const initialChargePeriods = BigInt(extra.initialCharge?.periodCount ?? 0);\n const initialChargeAmount = BigInt(extra.initialCharge?.totalAmount ?? \"0\");\n const remainingPeriods = BigInt(extra.maxPeriods) - initialChargePeriods;\n const remainingAmount =\n remainingPeriods > 0n ? remainingPeriods * BigInt(extra.amountPerPeriod) : 0n;\n return (initialChargeAmount + remainingAmount).toString();\n}\n\n/**\n * Build the Permit2 PermitSingle (AllowanceTransfer) typed data the wallet\n * signs. `spender = subscription contract`; `amount` covers the entire\n * remaining commitment (default), so the subscription contract can pull from\n * the same Permit2 allowance on every charge without re-signing.\n *\n * Permit2's EIP-712 domain has NO `version` field.\n */\nexport function buildPermit2TypedData(\n input: BuildPermit2TypedDataInput,\n): TypedDataEnvelope<\"PermitSingle\", Record<string, unknown>> {\n const extra = getSubscriptionExtra(input.selected);\n const amount = input.amount ?? defaultPermitAmount(extra);\n const chainId = parseChainIdFromNetwork(input.selected.network);\n\n return {\n domain: {\n name: \"Permit2\",\n chainId,\n verifyingContract: extra.contracts.permit2 as Hex,\n },\n types: PERMIT2_TYPES as unknown as TypedDataEnvelope<\n \"PermitSingle\",\n Record<string, unknown>\n >[\"types\"],\n primaryType: \"PermitSingle\",\n message: {\n details: {\n token: input.selected.asset,\n amount,\n expiration: input.expiration,\n nonce: input.nonce,\n },\n spender: extra.contracts.subscription,\n sigDeadline: input.sigDeadline,\n },\n };\n}\n\n/**\n * Compute the EIP-712 struct hash of a PermitSingle message — what\n * `terms.permitHash` must equal byte-for-byte. The facilitator verifies this\n * via `permit_hash_mismatch`.\n *\n * permitDetailsHash = keccak256(\n * PERMIT_DETAILS_TYPEHASH ‖ token ‖ amount ‖ expiration ‖ nonce\n * )\n * permitSingleHash = keccak256(\n * PERMIT_SINGLE_TYPEHASH ‖ permitDetailsHash ‖ spender ‖ sigDeadline\n * )\n */\nexport function computePermitSingleStructHash(permit: PermitSingleData): Hex {\n // PermitDetails(address token,uint160 amount,uint48 expiration,uint48 nonce)\n const PERMIT_DETAILS_TYPEHASH = keccak256(\n new TextEncoder().encode(\n \"PermitDetails(address token,uint160 amount,uint48 expiration,uint48 nonce)\",\n ),\n );\n const detailsHash = keccak256(\n encodeAbiParameters(\n [\n { type: \"bytes32\" },\n { type: \"address\" },\n { type: \"uint160\" },\n { type: \"uint48\" },\n { type: \"uint48\" },\n ],\n [\n PERMIT_DETAILS_TYPEHASH,\n permit.details.token as Hex,\n BigInt(permit.details.amount),\n Number(permit.details.expiration),\n Number(permit.details.nonce),\n ],\n ),\n );\n\n // PermitSingle(PermitDetails details,address spender,uint256 sigDeadline)PermitDetails(...)\n const PERMIT_SINGLE_TYPEHASH = keccak256(\n new TextEncoder().encode(\n \"PermitSingle(PermitDetails details,address spender,uint256 sigDeadline)\" +\n \"PermitDetails(address token,uint160 amount,uint48 expiration,uint48 nonce)\",\n ),\n );\n return keccak256(\n encodeAbiParameters(\n [{ type: \"bytes32\" }, { type: \"bytes32\" }, { type: \"address\" }, { type: \"uint256\" }],\n [PERMIT_SINGLE_TYPEHASH, detailsHash, permit.spender as Hex, BigInt(permit.sigDeadline)],\n ),\n );\n}\n\n/**\n * Build the EIP-712 typed-data object the wallet signs to commit to the\n * subscription terms (17 fields). `permitHash` MUST be the struct hash of\n * the PermitSingle the buyer signed for permit2 (compute it via\n * `computePermitSingleStructHash`) — the contract verifies this binding to\n * defeat detached-signature swap attacks.\n */\nexport function buildSubscriptionTermsTypedData(\n input: BuildSubscriptionTermsTypedDataInput,\n): TypedDataEnvelope<\"SubscriptionTerms\", SubscriptionTerms> {\n const extra = getSubscriptionExtra(input.selected);\n const domain = input.domain ?? extra.domain;\n\n // changeEffectiveAt: 0=none(create), 1=immediate(upgrade), 2=period_end(downgrade)\n let changeEffectiveAt = 0;\n if (input.changeFrom?.effectiveAt === \"immediate\") changeEffectiveAt = 1;\n else if (input.changeFrom?.effectiveAt === \"period_end\") changeEffectiveAt = 2;\n\n const message: SubscriptionTerms = {\n payer: input.payer,\n merchant: input.selected.payTo,\n facilitator: extra.facilitator,\n token: input.selected.asset,\n amountPerPeriod: extra.amountPerPeriod,\n periodSec: extra.periodSec,\n maxPeriods: extra.maxPeriods,\n startAt: input.startAt,\n initialChargePeriods: extra.initialCharge?.periodCount ?? 0,\n initialChargeAmount: extra.initialCharge?.totalAmount ?? \"0\",\n termsDeadline: input.termsDeadline,\n permitHash: input.permitHash,\n salt: input.salt,\n planTier: extra.plan.tier,\n changeFromSubId: input.changeFrom?.fromSubId ?? ZERO_BYTES32,\n changeEffectiveAt,\n periodMode: extra.periodMode ?? 0,\n };\n\n return {\n domain,\n types: SUBSCRIPTION_TERMS_TYPES as unknown as TypedDataEnvelope<\n \"SubscriptionTerms\",\n SubscriptionTerms\n >[\"types\"],\n primaryType: \"SubscriptionTerms\",\n message,\n };\n}\n\nexport function buildCancelAuthTypedData(\n input: BuildCancelAuthTypedDataInput,\n): TypedDataEnvelope<\"CancelAuth\", Record<string, unknown>> {\n return {\n domain: input.domain,\n types: CANCEL_AUTH_TYPES as unknown as TypedDataEnvelope<\n \"CancelAuth\",\n Record<string, unknown>\n >[\"types\"],\n primaryType: \"CancelAuth\",\n message: {\n action: 0,\n subId: input.subId,\n initiator: CANCEL_INITIATOR_TO_ENUM[input.initiator],\n nonce: input.nonce,\n deadline: input.deadline,\n },\n };\n}\n\nexport function buildPendingChangeCancelAuthTypedData(\n input: BuildPendingChangeCancelAuthTypedDataInput,\n): TypedDataEnvelope<\"PendingChangeCancelAuth\", Record<string, unknown>> {\n return {\n domain: input.domain,\n types: PENDING_CHANGE_CANCEL_AUTH_TYPES as unknown as TypedDataEnvelope<\n \"PendingChangeCancelAuth\",\n Record<string, unknown>\n >[\"types\"],\n primaryType: \"PendingChangeCancelAuth\",\n message: {\n subId: input.subId,\n newSubId: input.newSubId,\n nonce: input.nonce,\n deadline: input.deadline,\n },\n };\n}\n\n/**\n * Parse the chainId from a CAIP-2 network identifier (`eip155:<chainId>`).\n * Throws if not an EVM CAIP — the subscription scheme is EVM-only.\n */\nexport function parseChainIdFromNetwork(network: string): number {\n const parts = network.split(\":\");\n if (parts.length !== 2 || parts[0] !== \"eip155\") {\n throw new Error(`parseChainIdFromNetwork: expected \"eip155:<chainId>\", got \"${network}\"`);\n }\n const id = Number(parts[1]);\n if (!Number.isInteger(id) || id <= 0) {\n throw new Error(`parseChainIdFromNetwork: invalid chainId \"${parts[1]}\"`);\n }\n return id;\n}\n","import type { Hex } from \"viem\";\n\nimport type { PaymentRequirements } from \"../../types/payments\";\nimport { ErrorCode } from \"../errors\";\nimport type { SubscriptionTerms } from \"./payload\";\nimport { ZERO_BYTES32, type SubscriptionRequirementsExtra } from \"./typed-data\";\n\nfunction addrEq(a: string, b: string): boolean {\n return a.toLowerCase() === b.toLowerCase();\n}\n\nfunction hexEq(a: Hex | undefined, b: Hex): boolean {\n return !!a && a.toLowerCase() === b.toLowerCase();\n}\n\n/**\n * Verify that buyer-signed `terms` bind to the server-advertised\n * PaymentRequirements. Without this field-by-field check a buyer could sign\n * a basic-tier accepted but submit terms claiming enterprise-tier access at\n * basic price. The contract verifies the signature but cannot see what the\n * seller offered in 402 — only the SDK can enforce this binding.\n *\n * All mismatches collapse to `terms_binding_invalid` so the caller's switch\n * statement stays compact.\n *\n * Returns `null` on match, an `ErrorCode` on first mismatch.\n */\nexport function verifyTermsBindRequirements(\n terms: SubscriptionTerms,\n requirements: PaymentRequirements,\n): ErrorCode | null {\n const extra = (requirements.extra ?? {}) as Partial<SubscriptionRequirementsExtra>;\n if (!extra.plan || extra.amountPerPeriod === undefined || extra.facilitator === undefined) {\n return ErrorCode.TermsBindingInvalid;\n }\n\n if (!addrEq(terms.merchant, requirements.payTo)) return ErrorCode.MerchantMismatch;\n if (!addrEq(terms.token, requirements.asset)) return ErrorCode.TermsBindingInvalid;\n if (!addrEq(terms.facilitator, extra.facilitator)) return ErrorCode.TermsBindingInvalid;\n\n if (terms.amountPerPeriod !== extra.amountPerPeriod) return ErrorCode.TermsBindingInvalid;\n if (terms.periodSec !== extra.periodSec) return ErrorCode.TermsBindingInvalid;\n if (terms.maxPeriods !== extra.maxPeriods) return ErrorCode.TermsBindingInvalid;\n if (terms.periodMode !== (extra.periodMode ?? 0)) return ErrorCode.TermsBindingInvalid;\n if (terms.planTier !== extra.plan.tier) return ErrorCode.TermsBindingInvalid;\n\n // Server-pinned startAt must be honored; if server left it unset (==undefined),\n // accept whatever the buyer signed (contract resolves 0 → block.timestamp).\n if (extra.startAt !== undefined && terms.startAt !== extra.startAt) {\n return ErrorCode.TermsBindingInvalid;\n }\n\n const expectedInitPeriods = extra.initialCharge?.periodCount ?? 0;\n const expectedInitAmount = extra.initialCharge?.totalAmount ?? \"0\";\n if (terms.initialChargePeriods !== expectedInitPeriods) return ErrorCode.TermsBindingInvalid;\n if (terms.initialChargeAmount !== expectedInitAmount) return ErrorCode.TermsBindingInvalid;\n\n // planId itself isn't compared here — the other field-level checks\n // (planTier / amountPerPeriod / merchant / …) already pin down the\n // economic effect of the subscription.\n\n // changeFrom binding — direction encoded in changeEffectiveAt:\n // undefined → create (changeFromSubId==0 / changeEffectiveAt==0)\n // immediate → upgrade (changeEffectiveAt==1)\n // period_end → downgrade (changeEffectiveAt==2)\n if (extra.changeFrom) {\n if (!hexEq(terms.changeFromSubId, extra.changeFrom.fromSubId)) {\n return ErrorCode.TermsBindingInvalid;\n }\n const expectedEff =\n extra.changeFrom.effectiveAt === \"immediate\"\n ? 1\n : extra.changeFrom.effectiveAt === \"period_end\"\n ? 2\n : 0;\n if (terms.changeEffectiveAt !== expectedEff) return ErrorCode.TermsBindingInvalid;\n } else {\n if (terms.changeFromSubId !== ZERO_BYTES32) return ErrorCode.TermsBindingInvalid;\n if (terms.changeEffectiveAt !== 0) return ErrorCode.TermsBindingInvalid;\n }\n\n return null;\n}\n","/**\n * Local mirror of the facilitator's elapsed-period math. Used by\n * `verifyAccess` to decide whether `lastChargedPeriod` is current without\n * hitting the facilitator on every request — only when the local\n * computation says we're behind does the SDK fall through to a GET /detail\n * refresh.\n *\n * MUST stay bit-for-bit equivalent to the backend implementation. Returns\n * `0` when the subscription has not yet started — caller treats this as a\n * special \"pre-start\" state.\n */\n\nconst PERIOD_MODE_CALENDAR_MONTH = 1;\n\n/**\n * Compute the real elapsed period count at `nowSec`, NOT clamped to\n * `maxPeriods`. Period 1 is the first chargeable period; `0` means\n * pre-start (subscription not yet effective).\n */\nexport function computeElapsedPeriods(\n periodMode: number,\n startAt: number,\n billingAnchorAt: number,\n periodSec: number,\n nowSec: number,\n): number {\n if (nowSec < startAt) return 0;\n if (periodMode === PERIOD_MODE_CALENDAR_MONTH) {\n const anchor = billingAnchorAt > 0 ? billingAnchorAt : startAt;\n const startOffset = elapsedCalendarMonths(anchor, startAt);\n return elapsedCalendarMonths(anchor, nowSec) - startOffset + 1;\n }\n if (periodSec <= 0) return 0;\n return Math.floor((nowSec - startAt) / periodSec) + 1;\n}\n\n/**\n * Number of calendar-month boundaries crossed between `anchorSec` (exclusive)\n * and `tsSec` (inclusive). Each boundary is `addCalendarMonths(anchor, n)`\n * for n=1,2,…, with month-end truncation (1/31 + 1m → 2/28/29).\n */\nexport function elapsedCalendarMonths(anchorSec: number, tsSec: number): number {\n if (tsSec <= anchorSec) return 0;\n const anchor = new Date(anchorSec * 1000);\n const ts = new Date(tsSec * 1000);\n let diff =\n (ts.getUTCFullYear() - anchor.getUTCFullYear()) * 12 +\n (ts.getUTCMonth() - anchor.getUTCMonth());\n if (diff < 0) return 0;\n if (addCalendarMonths(anchorSec, diff) > tsSec) diff--;\n return Math.max(diff, 0);\n}\n\n/**\n * Add `n` calendar months to `anchorSec`, keeping the anchor's day-of-month\n * but truncating to month-end when overflowing (1/31 + 1m → 2/28 or 2/29).\n * Returned timestamp preserves the anchor's hour / minute / second / ms in UTC.\n */\nexport function addCalendarMonths(anchorSec: number, n: number): number {\n const anchor = new Date(anchorSec * 1000);\n const targetYear = anchor.getUTCFullYear() + Math.floor((anchor.getUTCMonth() + n) / 12);\n const targetMonth = (((anchor.getUTCMonth() + n) % 12) + 12) % 12;\n // Days in target month (UTC) — day 0 of month+1 is the last day of month.\n const daysInTargetMonth = new Date(Date.UTC(targetYear, targetMonth + 1, 0)).getUTCDate();\n const day = Math.min(anchor.getUTCDate(), daysInTargetMonth);\n const ts = Date.UTC(\n targetYear,\n targetMonth,\n day,\n anchor.getUTCHours(),\n anchor.getUTCMinutes(),\n anchor.getUTCSeconds(),\n anchor.getUTCMilliseconds(),\n );\n return Math.floor(ts / 1000);\n}\n","/**\n * Isomorphic UTF-8 ↔ base64 helpers.\n *\n * Buyers may run this code in a browser; Buffer is preferred on Node so the\n * built CJS bundle stays free of `globalThis.atob` polyfills, but we fall back\n * to atob/btoa when Buffer is unavailable.\n */\n\nconst hasBuffer = typeof Buffer !== \"undefined\";\n\nexport function base64EncodeUtf8(value: string): string {\n if (hasBuffer) return Buffer.from(value, \"utf8\").toString(\"base64\");\n const binary = unescape(encodeURIComponent(value));\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (globalThis as any).btoa(binary);\n}\n\nexport function base64DecodeUtf8(value: string): string {\n if (hasBuffer) return Buffer.from(value, \"base64\").toString(\"utf8\");\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const binary: string = (globalThis as any).atob(value);\n return decodeURIComponent(escape(binary));\n}\n","import type { Hex } from \"viem\";\n\nimport type { PaymentPayload, PaymentRequired, PaymentRequirements } from \"../../types/payments\";\nimport { base64DecodeUtf8, base64EncodeUtf8 } from \"./base64\";\n\n/**\n * Permit2 PermitSingle (AllowanceTransfer) — what the buyer signs to authorize\n * the subscription contract to pull tokens on every charge.\n *\n * PermitSingle(PermitDetails details, address spender, uint256 sigDeadline)\n * PermitDetails(address token, uint160 amount, uint48 expiration, uint48 nonce)\n */\nexport interface PermitSingleData {\n details: {\n token: string;\n /** uint160 as decimal string — covers entire remaining commitment. */\n amount: string;\n /** uint48 unix seconds — Permit2 allowance expiration. */\n expiration: number;\n /** uint48 — Permit2 nonce (current value from allowance-status, NOT +1). */\n nonce: number;\n };\n /** Subscription contract address. */\n spender: string;\n /** uint256 as decimal string — outer signature expiry. */\n sigDeadline: string;\n}\n\n/**\n * SubscriptionTerms — what the buyer's EIP-712 signature commits to. 17\n * fields. Field ORDER MATTERS because it determines the EIP-712 TypeHash:\n * 0xa5223de56e7694cf776c7d4f74c0323f42bf9e65655fe49affefbdfd40ec97ae\n */\nexport interface SubscriptionTerms {\n payer: string;\n merchant: string;\n facilitator: string;\n token: string;\n /** uint160 (atomic units). */\n amountPerPeriod: string;\n /** uint64 seconds; MUST be 0 when periodMode=1 (calendar_month). */\n periodSec: number;\n /** uint32. */\n maxPeriods: number;\n /** uint64 unix seconds; 0 means \"use block.timestamp on-chain\". */\n startAt: number;\n /** uint32; 0 = no separate initial charge. */\n initialChargePeriods: number;\n /** uint160; atomic units. */\n initialChargeAmount: string;\n /** uint64 unix seconds — terms signature validity window. */\n termsDeadline: number;\n /** bytes32 — keccak256 of the PermitSingle EIP-712 struct hash, binds terms to permit. */\n permitHash: Hex;\n /** bytes32 — buyer-generated random anti-replay value. */\n salt: Hex;\n /** uint8 (>0) — plan tier for upgrade/downgrade comparison. */\n planTier: number;\n /** bytes32 — old subId on change, zero on create. */\n changeFromSubId: Hex;\n /** uint8 — 0 none(create) / 1 immediate(upgrade) / 2 period_end(downgrade). */\n changeEffectiveAt: number;\n /** uint8 — 0 fixed_seconds / 1 calendar_month. */\n periodMode: number;\n /**\n * bytes32 — keccak256(utf8(plan.id)). Buyer SDKs sign it as a terms field\n * and the facilitator persists it as the on-chain `planId`. Seller verify\n * MUST cross-check this hash equals `keccak256(utf8(accepted.extra.plan.id))`\n * to defeat plan-spoof attacks.\n */\n planId?: Hex;\n}\n\n/**\n * Concrete payload nested inside `PaymentPayload.payload` for the `period`\n * scheme.\n */\nexport interface SubscriptionPaymentInner {\n permitSingle: PermitSingleData;\n permitSingleSignature: Hex;\n terms: SubscriptionTerms;\n termsSignature: Hex;\n}\n\nexport interface EncodePaymentPayloadInput {\n selected: PaymentRequirements;\n permitSingle: PermitSingleData;\n permitSingleSignature: Hex;\n terms: SubscriptionTerms;\n termsSignature: Hex;\n}\n\n/**\n * Decode the `APP-PAYMENT-REQUIRED` header into the underlying\n * `PaymentRequired.accepts` array. Throws on invalid base64 / JSON.\n */\nexport function parsePaymentRequired(headerValue: string): PaymentRequirements[] {\n const json = base64DecodeUtf8(headerValue);\n const parsed = JSON.parse(json) as PaymentRequired;\n if (!parsed || !Array.isArray(parsed.accepts)) {\n throw new Error(\"parsePaymentRequired: missing or invalid `accepts` array\");\n }\n return parsed.accepts;\n}\n\n/**\n * Build the `PAYMENT-SIGNATURE` header value (base64-encoded JSON). Buyer side.\n */\nexport function encodePaymentPayload(input: EncodePaymentPayloadInput): string {\n const payload: PaymentPayload = {\n x402Version: 2,\n accepted: input.selected,\n payload: {\n permitSingle: input.permitSingle,\n permitSingleSignature: input.permitSingleSignature,\n terms: input.terms,\n termsSignature: input.termsSignature,\n },\n };\n return base64EncodeUtf8(JSON.stringify(payload));\n}\n\n/**\n * Decode the `PAYMENT-SIGNATURE` header value back into a typed PaymentPayload.\n * Throws on invalid base64 / JSON; does not validate field shapes (that is the\n * responsibility of the scheme verify step).\n */\nexport function decodePaymentPayload(headerValue: string): PaymentPayload {\n const json = base64DecodeUtf8(headerValue);\n return JSON.parse(json) as PaymentPayload;\n}\n\n/**\n * Narrow a generic PaymentPayload's `.payload` to the subscription inner.\n * Throws if required fields are missing — single chokepoint between base64\n * decode and verify.\n */\nexport function asSubscriptionPaymentInner(payload: PaymentPayload): SubscriptionPaymentInner {\n const inner = payload.payload as Partial<SubscriptionPaymentInner>;\n if (\n !inner ||\n !inner.permitSingle ||\n !inner.terms ||\n !inner.permitSingleSignature ||\n !inner.termsSignature\n ) {\n throw new Error(\n \"asSubscriptionPaymentInner: payload.payload is missing required permitSingle/terms fields\",\n );\n }\n return inner as SubscriptionPaymentInner;\n}\n","import { encodePacked, keccak256, type Hex } from \"viem\";\n\nimport type { AccessProof } from \"../types\";\nimport { base64DecodeUtf8, base64EncodeUtf8 } from \"./base64\";\n\nexport interface AccessProofMessageInput {\n subId: Hex; // bytes32\n payer: Hex; // address\n timestamp: number; // uint64, unix seconds\n}\n\n/**\n * Returns the inner 32-byte hash that wallets sign via EIP-191 personal_sign.\n *\n * Layout:\n * inner = keccak256(abi.encodePacked(bytes32 subId, address payer, uint256 timestamp))\n *\n * `timestamp` is encoded as `uint256` (32 bytes). Switching to anything\n * narrower yields a different digest and silently produces\n * `signature_invalid` on every access call.\n *\n * IMPORTANT: callers must NOT prepend the EIP-191 envelope themselves —\n * `wallet.signMessage(buildAccessProofMessage(...))` will add the\n * `\\x19Ethereum Signed Message:\\n32` prefix automatically. The recover step on\n * the server must mirror this (verify EIP-191 signature, not raw keccak).\n */\nexport function buildAccessProofMessage(input: AccessProofMessageInput): Hex {\n return keccak256(\n encodePacked(\n [\"bytes32\", \"address\", \"uint256\"],\n [input.subId, input.payer, BigInt(input.timestamp)],\n ),\n );\n}\n\nexport function encodeAccessProof(proof: AccessProof): string {\n return base64EncodeUtf8(JSON.stringify(proof));\n}\n\nexport function decodeAccessProof(headerValue: string): AccessProof {\n const json = base64DecodeUtf8(headerValue);\n const parsed = JSON.parse(json) as AccessProof;\n if (!parsed || parsed.kind !== \"subscription-id\") {\n throw new Error(`decodeAccessProof: expected kind=\"subscription-id\", got \"${parsed?.kind}\"`);\n }\n return parsed;\n}\n","import type { FacilitatorClient } from \"../http/httpFacilitatorClient\";\nimport type { PaymentPayload, PaymentRequirements } from \"../types/payments\";\nimport type { CancelAuth, PendingChangeCancelAuth, Subscription } from \"./types\";\n\n/**\n * Standard OKX facilitator response envelope. `code === 0` means success\n * (NUMBER, not string).\n */\nexport interface FacilitatorEnvelope<T> {\n code: number;\n msg?: string | null;\n data?: T;\n}\n\n/** POST /api/v6/pay/x402/subscriptions response data. */\nexport interface FacilitatorSubscribeData {\n subId: string;\n txHash?: string;\n state: number;\n}\n\n/** POST /api/v6/pay/x402/subscriptions/change response data. */\nexport interface FacilitatorChangeData {\n newSubId: string;\n txHash?: string;\n state: number;\n}\n\n/** POST /api/v6/pay/x402/subscriptions/{id}/cancel response data. */\nexport interface FacilitatorCancelData {\n subId: string;\n txHash?: string;\n state: number;\n}\n\n/** POST /api/v6/pay/x402/subscriptions/{id}/cancel-pending-change response data. */\nexport interface FacilitatorCancelPendingData {\n subId: string;\n txHash?: string;\n state: number;\n}\n\n/** POST /api/v6/pay/x402/subscriptions/{id}/charge response data. */\nexport interface FacilitatorChargeData {\n subId: string;\n period: number;\n txHash?: string;\n /** SubscriptionChargeState — 0 pending / 1 success / 2 failed. */\n state: number;\n planChangeTriggered?: boolean;\n newSubId?: string | null;\n}\n\n/** POST /api/v6/pay/x402/subscriptions/{id}/finalize-expired response data. */\nexport interface FacilitatorFinalizeExpiredData {\n subId: string;\n txHash?: string;\n state: number;\n}\n\n/** One row of the charges feed (GET /api/v6/pay/x402/subscriptions/charges). */\nexport interface FacilitatorChargeRow {\n subId: string;\n period: number;\n /** 1 initial / 2 periodic / 3 downgrade_first_period / 4 finalize_expired_marker. */\n chargeType: number;\n amount: string;\n /** 0 pending / 1 success / 2 failed. */\n state: number;\n txHash?: string;\n planChangeTriggered?: boolean;\n newSubId?: string | null;\n}\n\n/** GET /api/v6/pay/x402/subscriptions/charges response data. */\nexport interface FacilitatorGetChargesData {\n charges: FacilitatorChargeRow[];\n}\n\n/** GET /api/v6/pay/x402/subscriptions/pending response data (most recent row). */\nexport interface FacilitatorPendingChangeRow {\n subId: string;\n newSubId: string;\n effectiveFromPeriod: number;\n /** 0 pending / 1 activated / 2 canceled / 3 expired. */\n state: number;\n}\n\n/** GET /api/v6/pay/x402/subscriptions/{id} response data. */\nexport interface FacilitatorGetSubscriptionData {\n subId: string;\n state: number;\n payer: string;\n merchant: string;\n token: string;\n amountPerPeriod: string;\n periodSec: number;\n /** 0 fixed_seconds / 1 calendar_month. */\n periodMode: number;\n maxPeriods: number;\n startAt: number;\n /** Calendar-month billing anchor (Unix s); 0/undefined in fixed_seconds mode. */\n billingAnchorAt?: number;\n /** Seller-side business identifier (NOT on-chain); facilitator echoes from its DB. */\n planId?: string;\n /** Plan tier from on-chain terms.planTier. */\n planTier?: number;\n lastChargedPeriod: number;\n totalPulled: string;\n changedToSubId?: string | null;\n isActive?: boolean;\n serviceEnded?: boolean;\n /** Mode-aware current period, clamped to maxPeriods (boundary = next period). */\n currentPeriod?: number;\n /**\n * Real elapsed period number, NOT clamped — `elapsedPeriods > maxPeriods`\n * means the service window already ended. SDK polls until\n * `lastChargedPeriod >= elapsedPeriods` to confirm a write settled.\n */\n elapsedPeriods?: number;\n nextChargeableAt?: number;\n pendingPlanChange?: {\n subId: string;\n newSubId: string;\n effectiveFromPeriod: number;\n state: number;\n } | null;\n}\n\n/**\n * Subscription write-flow request body shared by subscribe / change. The\n * facilitator parses these field-by-field — DO NOT wrap in an x402 envelope\n * (no `paymentPayload` / `paymentRequirements` wrapping).\n */\nexport interface SubscriptionWriteRequest {\n chainIndex: number;\n terms: PaymentPayload[\"payload\"] extends { terms: infer T } ? T : unknown;\n permit: PaymentPayload[\"payload\"] extends { permit: infer P } ? P : unknown;\n termsSig: string;\n permitSig: string;\n syncSettle?: boolean;\n}\n\n/** Subscription-aware facilitator client. Extends the base FacilitatorClient. */\nexport interface SubscriptionFacilitatorClient extends FacilitatorClient {\n /** POST /api/v6/pay/x402/subscriptions */\n subscribe(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n syncSettle?: boolean,\n ): Promise<FacilitatorEnvelope<FacilitatorSubscribeData>>;\n\n /** POST /api/v6/pay/x402/subscriptions/change */\n changeSubscription(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n oldSubId: string,\n syncSettle?: boolean,\n ): Promise<FacilitatorEnvelope<FacilitatorChangeData>>;\n\n /** POST /api/v6/pay/x402/subscriptions/{subId}/cancel */\n cancelSubscription(\n subId: string,\n cancelAuth: CancelAuth,\n syncSettle?: boolean,\n ): Promise<FacilitatorEnvelope<FacilitatorCancelData>>;\n\n /** POST /api/v6/pay/x402/subscriptions/{subId}/cancel-pending-change */\n cancelPendingChange(\n subId: string,\n cancelAuth: PendingChangeCancelAuth,\n syncSettle?: boolean,\n ): Promise<FacilitatorEnvelope<FacilitatorCancelPendingData>>;\n\n /** POST /api/v6/pay/x402/subscriptions/{subId}/charge */\n chargeSubscription(\n subId: string,\n syncSettle?: boolean,\n ): Promise<FacilitatorEnvelope<FacilitatorChargeData>>;\n\n /** POST /api/v6/pay/x402/subscriptions/finalize-expired — cleans up an ACTIVE sub whose service window has ended. */\n finalizeExpired(\n subId: string,\n syncSettle?: boolean,\n ): Promise<FacilitatorEnvelope<FacilitatorFinalizeExpiredData>>;\n\n /** GET /api/v6/pay/x402/subscriptions/charges — paginated charge feed. */\n getCharges(\n subId: string,\n limit?: number,\n offset?: number,\n ): Promise<FacilitatorEnvelope<FacilitatorGetChargesData>>;\n\n /** GET /api/v6/pay/x402/subscriptions/pending — most recent pendingPlanChange row (any state). */\n getPendingChange(subId: string): Promise<FacilitatorEnvelope<FacilitatorPendingChangeRow | null>>;\n\n /** GET /api/v6/pay/x402/subscriptions/{subId} */\n getSubscription(subId: string): Promise<FacilitatorEnvelope<FacilitatorGetSubscriptionData>>;\n}\n\n/**\n * Type guard: does this FacilitatorClient implement the subscription\n * endpoints?\n */\nexport function supportsSubscription(\n client: FacilitatorClient,\n): client is SubscriptionFacilitatorClient {\n const c = client as Partial<SubscriptionFacilitatorClient>;\n return (\n typeof c.subscribe === \"function\" &&\n typeof c.changeSubscription === \"function\" &&\n typeof c.cancelSubscription === \"function\" &&\n typeof c.cancelPendingChange === \"function\" &&\n typeof c.chargeSubscription === \"function\" &&\n typeof c.finalizeExpired === \"function\" &&\n typeof c.getCharges === \"function\" &&\n typeof c.getPendingChange === \"function\" &&\n typeof c.getSubscription === \"function\"\n );\n}\n\n/** Re-export `Subscription` so consumers don't have to import from `./types`. */\nexport type { Subscription };\n"],"mappings":"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","names":["import_viem"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { ai as AssetAmount, aj as FacilitatorContext, F as FacilitatorExtension, f as FacilitatorResponseError, ak as Money, al as MoneyParser, N as Network, P as PaymentPayload, am as PaymentPayloadContext, an as PaymentPayloadResult, c as PaymentRequired, ao as PaymentRequiredContext, a as PaymentRequirements, ah as Price, ap as ResourceInfo, aq as ResourceServerExtension, a9 as SchemeNetworkClient, b as SchemeNetworkFacilitator, ar as SchemeNetworkServer, as as SettleError, at as SettleRequest, S as SettleResponse, ae as SettleResultContext, i as SettleStatusResponse, h as SupportedResponse, au as VerifyError, av as VerifyRequest, V as VerifyResponse, g as getFacilitatorResponseError } from '../mechanisms-LhI9qkRo.js';
|
package/dist/cjs/{x402HTTPResourceServer-CcsAkcgI.d.ts → x402HTTPResourceServer-B0mXzV8r.d.ts}
RENAMED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ah as Price, N as Network, S as SettleResponse, D as OnBeforeAccessHook, P as PaymentPayload, a as PaymentRequirements, u as Subscription, c as PaymentRequired, ag as x402ResourceServer, af as SettlementOverrides, v as SubscriptionCapability } from './mechanisms-LhI9qkRo.js';
|
|
2
|
+
import { _ as ___subscription } from './index-2gWfiUbK.js';
|
|
2
3
|
|
|
3
4
|
declare const SETTLEMENT_OVERRIDES_HEADER = "settlement-overrides";
|
|
4
5
|
/**
|
|
@@ -12,6 +13,12 @@ interface HTTPAdapter {
|
|
|
12
13
|
getUrl(): string;
|
|
13
14
|
getAcceptHeader(): string;
|
|
14
15
|
getUserAgent(): string;
|
|
16
|
+
/**
|
|
17
|
+
* Return the full request headers as a plain lowercase-keyed record.
|
|
18
|
+
* Optional; adapters that don't implement it cause hooks like
|
|
19
|
+
* `onBeforeAccess` to receive an empty headers map.
|
|
20
|
+
*/
|
|
21
|
+
getHeaders?(): Record<string, string>;
|
|
15
22
|
/**
|
|
16
23
|
* Get query parameters from the request URL
|
|
17
24
|
*
|
|
@@ -128,6 +135,22 @@ interface RouteConfig {
|
|
|
128
135
|
*/
|
|
129
136
|
settlementFailedResponseBody?: SettlementFailedResponseBody;
|
|
130
137
|
extensions?: Record<string, unknown>;
|
|
138
|
+
/**
|
|
139
|
+
* When set, the route is a special-operation endpoint for the subscription
|
|
140
|
+
* scheme:
|
|
141
|
+
* - "change": two-stage upgrade/downgrade flow
|
|
142
|
+
* - "cancel": cancel-subscription flow
|
|
143
|
+
* Ignored by non-subscription schemes.
|
|
144
|
+
*/
|
|
145
|
+
operation?: "change" | "cancel" | "cancel-pending-change";
|
|
146
|
+
/**
|
|
147
|
+
* Route-level hook fired AFTER `verifyAccess` succeeded (signature +
|
|
148
|
+
* payer + plan allowlist + period math) but BEFORE the handler runs.
|
|
149
|
+
* Seller uses it for custom access policy: rate limiting, quota, feature
|
|
150
|
+
* flags, bans / blacklists (return `{ok:false, error:"banned"}`). Full
|
|
151
|
+
* `Subscription` object is on the context so any field is inspectable.
|
|
152
|
+
*/
|
|
153
|
+
onBeforeAccess?: OnBeforeAccessHook;
|
|
131
154
|
}
|
|
132
155
|
/**
|
|
133
156
|
* Routes configuration - maps path patterns to route configs
|
|
@@ -200,6 +223,22 @@ type HTTPProcessResult = {
|
|
|
200
223
|
} | {
|
|
201
224
|
type: "payment-error";
|
|
202
225
|
response: HTTPResponseInstructions;
|
|
226
|
+
} | {
|
|
227
|
+
type: "payment-presettle";
|
|
228
|
+
paymentPayload: PaymentPayload;
|
|
229
|
+
paymentRequirements: PaymentRequirements;
|
|
230
|
+
/** Settle action to run AFTER verify; bound to scheme + operation. */
|
|
231
|
+
settle: () => Promise<{
|
|
232
|
+
success: boolean;
|
|
233
|
+
headers?: Record<string, string>;
|
|
234
|
+
data?: any;
|
|
235
|
+
error?: string;
|
|
236
|
+
}>;
|
|
237
|
+
operation: "subscribe" | "change" | "cancel" | "cancel-pending-change";
|
|
238
|
+
} | {
|
|
239
|
+
type: "access-verified";
|
|
240
|
+
subscription: Subscription;
|
|
241
|
+
headers?: Record<string, string>;
|
|
203
242
|
};
|
|
204
243
|
/**
|
|
205
244
|
* Result of processSettlement
|
|
@@ -264,6 +303,7 @@ declare class x402HTTPResourceServer {
|
|
|
264
303
|
private paywallProvider?;
|
|
265
304
|
private protectedRequestHooks;
|
|
266
305
|
private timeoutRecoveryHook?;
|
|
306
|
+
private beforeAccessHooks;
|
|
267
307
|
private pollDeadlineMs;
|
|
268
308
|
/**
|
|
269
309
|
* Creates a new x402HTTPResourceServer instance.
|
|
@@ -316,6 +356,19 @@ declare class x402HTTPResourceServer {
|
|
|
316
356
|
* @returns The x402HTTPResourceServer instance for chaining
|
|
317
357
|
*/
|
|
318
358
|
onProtectedRequest(hook: ProtectedRequestHook): this;
|
|
359
|
+
/**
|
|
360
|
+
* Register a seller-global `onBeforeAccess` hook fired on every access-
|
|
361
|
+
* verified subscription request, AFTER `verifyAccess` (signature + payer
|
|
362
|
+
* + plan allowlist + period math) but BEFORE the handler runs. Seller
|
|
363
|
+
* uses it for cross-cutting access policy (quota / ban list / feature
|
|
364
|
+
* gating). Hooks are executed in order of registration; the first one
|
|
365
|
+
* to return `{ ok: false }` denies (→ 402). Route-level
|
|
366
|
+
* `RouteConfig.onBeforeAccess` runs AFTER all global hooks.
|
|
367
|
+
*
|
|
368
|
+
* @param hook - The hook function
|
|
369
|
+
* @returns The x402HTTPResourceServer instance for chaining
|
|
370
|
+
*/
|
|
371
|
+
onBeforeAccess(hook: OnBeforeAccessHook): this;
|
|
319
372
|
/**
|
|
320
373
|
* Register a hook to call when the facilitator returns status="timeout".
|
|
321
374
|
* The hook should verify the tx on-chain and return { confirmed: boolean }.
|
|
@@ -360,6 +413,60 @@ declare class x402HTTPResourceServer {
|
|
|
360
413
|
* @returns True if the route requires payment, false otherwise
|
|
361
414
|
*/
|
|
362
415
|
requiresPayment(context: HTTPRequestContext): boolean;
|
|
416
|
+
/**
|
|
417
|
+
* Lazy loader for the subscription submodule. The `import()` cache makes
|
|
418
|
+
* this effectively free after the first hit; isolating it in one place
|
|
419
|
+
* keeps dispatch helpers free of dynamic-import boilerplate and lets
|
|
420
|
+
* bundlers tree-shake the entire subscription path when no caller touches
|
|
421
|
+
* it.
|
|
422
|
+
*/
|
|
423
|
+
protected loadSubscriptionModule(): Promise<typeof ___subscription>;
|
|
424
|
+
/**
|
|
425
|
+
* Single chokepoint for "is this (network, scheme) backed by a
|
|
426
|
+
* SubscriptionCapability-implementing scheme?". Returns the narrowed
|
|
427
|
+
* capability (so callers get full typing on `verifyAccess` / `verifySubscribe`
|
|
428
|
+
* / etc.) or null if not registered or not a subscription scheme.
|
|
429
|
+
*/
|
|
430
|
+
protected resolveSubscriptionScheme(network: Network, schemeName: string): Promise<SubscriptionCapability | null>;
|
|
431
|
+
/**
|
|
432
|
+
* period dispatch helper — Access flow.
|
|
433
|
+
*
|
|
434
|
+
* Returns an `access-verified` (or `payment-error`) HTTPProcessResult when
|
|
435
|
+
* the request carries `APP-Access` AND a subscription-capable scheme is
|
|
436
|
+
* registered for one of the route's accepted (scheme, network) pairs.
|
|
437
|
+
* Returns `null` to indicate the dispatcher should fall through to classic
|
|
438
|
+
* pay-per-request handling.
|
|
439
|
+
*/
|
|
440
|
+
protected tryDispatchAccessFlow(adapter: HTTPAdapter, routeConfig: RouteConfig, paymentOptions: PaymentOption[], paymentRequired: PaymentRequired): Promise<HTTPProcessResult | null>;
|
|
441
|
+
/**
|
|
442
|
+
* period dispatch helper — Subscribe presettle flow.
|
|
443
|
+
*
|
|
444
|
+
* When the buyer presents a PaymentPayload whose `accepted.scheme` is a
|
|
445
|
+
* subscription scheme with `settlementMode === "pre"`, this runs verify +
|
|
446
|
+
* (settle on demand) and returns `payment-presettle`. The middleware is
|
|
447
|
+
* expected to call `result.settle()` AFTER decision-time but BEFORE
|
|
448
|
+
* `next()` so handler only runs when the chain creation succeeded.
|
|
449
|
+
*
|
|
450
|
+
* Returns `null` to fall through to classic post-settle path-verified flow.
|
|
451
|
+
*/
|
|
452
|
+
protected tryDispatchSubscriptionPresettle(paymentPayload: PaymentPayload, serverAccepts: PaymentRequirements[], operation: "subscribe" | "change"): Promise<HTTPProcessResult | null>;
|
|
453
|
+
/**
|
|
454
|
+
* period dispatch helper — Cancel flow.
|
|
455
|
+
*
|
|
456
|
+
* Reads JSON body { auth: CancelAuth, subId: string }, runs verifyCancel
|
|
457
|
+
* then wraps settleCancel as a payment-presettle (settle-before-handler so
|
|
458
|
+
* the cancelation is on-chain before the seller's response).
|
|
459
|
+
*/
|
|
460
|
+
protected tryDispatchCancelFlow(adapter: HTTPAdapter, routeConfig: RouteConfig, paymentOptions: PaymentOption[]): Promise<HTTPProcessResult | null>;
|
|
461
|
+
/**
|
|
462
|
+
* period dispatch helper — Cancel-Pending-Change flow.
|
|
463
|
+
*
|
|
464
|
+
* Reads JSON body `{ auth: PendingChangeCancelAuth, subId: string }`. The
|
|
465
|
+
* auth must carry `newSubId` (matches the currently PENDING downgrade
|
|
466
|
+
* target). Runs verifyCancelPendingChange then wraps
|
|
467
|
+
* settleCancelPendingChange as a payment-presettle.
|
|
468
|
+
*/
|
|
469
|
+
protected tryDispatchCancelPendingChangeFlow(adapter: HTTPAdapter, routeConfig: RouteConfig, paymentOptions: PaymentOption[]): Promise<HTTPProcessResult | null>;
|
|
363
470
|
/**
|
|
364
471
|
* Build HTTPResponseInstructions for settlement failure.
|
|
365
472
|
* Uses settlementFailedResponseBody hook if configured, otherwise defaults to empty body.
|
|
@@ -399,6 +506,12 @@ declare class x402HTTPResourceServer {
|
|
|
399
506
|
* @returns Decoded payment payload or null
|
|
400
507
|
*/
|
|
401
508
|
private extractPayment;
|
|
509
|
+
/**
|
|
510
|
+
* Extract `APP-Access` header (subscription access-flow). Returns the raw
|
|
511
|
+
* base64 string so callers can pass it through to `decodeAccessProof` in
|
|
512
|
+
* the subscription codec.
|
|
513
|
+
*/
|
|
514
|
+
private extractAccessProofHeader;
|
|
402
515
|
/**
|
|
403
516
|
* Check if request is from a web browser
|
|
404
517
|
*
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { d as FacilitatorClient, h as SupportedResponse, P as PaymentPayload, a as PaymentRequirements, V as VerifyResponse, S as SettleResponse, i as SettleStatusResponse, j as FacilitatorEnvelope, k as FacilitatorSubscribeData, l as FacilitatorChangeData, C as CancelAuth, m as FacilitatorCancelData, n as PendingChangeCancelAuth, o as FacilitatorCancelPendingData, p as FacilitatorChargeData, q as FacilitatorFinalizeExpiredData, r as FacilitatorGetChargesData, s as FacilitatorPendingChangeRow, t as FacilitatorGetSubscriptionData } from './mechanisms-LhI9qkRo.mjs';
|
|
2
|
+
|
|
3
|
+
interface OKXConfig {
|
|
4
|
+
apiKey: string;
|
|
5
|
+
secretKey: string;
|
|
6
|
+
passphrase: string;
|
|
7
|
+
baseUrl?: string;
|
|
8
|
+
/**
|
|
9
|
+
* OKX exact-scheme extension: when true, the settle call tells the facilitator to
|
|
10
|
+
* wait for on-chain confirmation before responding (syncSettle=true in request body).
|
|
11
|
+
* The facilitator then returns status="success" directly (no polling needed).
|
|
12
|
+
* When false (default), the facilitator responds with status="pending" immediately.
|
|
13
|
+
*/
|
|
14
|
+
syncSettle?: boolean;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* OKX facilitator client implementing the FacilitatorClient interface.
|
|
18
|
+
* Uses HMAC-SHA256 signing per OKX REST API authentication spec.
|
|
19
|
+
*/
|
|
20
|
+
declare class OKXFacilitatorClient implements FacilitatorClient {
|
|
21
|
+
private config;
|
|
22
|
+
constructor(config: OKXConfig);
|
|
23
|
+
/**
|
|
24
|
+
*
|
|
25
|
+
* @param method
|
|
26
|
+
* @param path
|
|
27
|
+
* @param body
|
|
28
|
+
*/
|
|
29
|
+
private createHeaders;
|
|
30
|
+
/**
|
|
31
|
+
*
|
|
32
|
+
*/
|
|
33
|
+
getSupported(): Promise<SupportedResponse>;
|
|
34
|
+
/**
|
|
35
|
+
*
|
|
36
|
+
* @param payload
|
|
37
|
+
* @param requirements
|
|
38
|
+
*/
|
|
39
|
+
verify(payload: PaymentPayload, requirements: PaymentRequirements): Promise<VerifyResponse>;
|
|
40
|
+
/**
|
|
41
|
+
*
|
|
42
|
+
* @param payload
|
|
43
|
+
* @param requirements
|
|
44
|
+
*/
|
|
45
|
+
settle(payload: PaymentPayload, requirements: PaymentRequirements): Promise<SettleResponse>;
|
|
46
|
+
/**
|
|
47
|
+
* Query on-chain settlement status by transaction hash.
|
|
48
|
+
*
|
|
49
|
+
* @param txHash - The transaction hash to query
|
|
50
|
+
* @returns Settlement status response
|
|
51
|
+
*/
|
|
52
|
+
getSettleStatus(txHash: string): Promise<SettleStatusResponse>;
|
|
53
|
+
/**
|
|
54
|
+
* Build `{chainIndex, terms, permit, termsSig, permitSig, syncSettle}` —
|
|
55
|
+
* request body shared by subscribe / change endpoints.
|
|
56
|
+
*/
|
|
57
|
+
private buildWriteBody;
|
|
58
|
+
subscribe(paymentPayload: PaymentPayload, paymentRequirements: PaymentRequirements, syncSettle?: boolean): Promise<FacilitatorEnvelope<FacilitatorSubscribeData>>;
|
|
59
|
+
changeSubscription(paymentPayload: PaymentPayload, paymentRequirements: PaymentRequirements, oldSubId: string, syncSettle?: boolean): Promise<FacilitatorEnvelope<FacilitatorChangeData>>;
|
|
60
|
+
cancelSubscription(subId: string, cancelAuth: CancelAuth, syncSettle?: boolean): Promise<FacilitatorEnvelope<FacilitatorCancelData>>;
|
|
61
|
+
cancelPendingChange(subId: string, cancelAuth: PendingChangeCancelAuth, syncSettle?: boolean): Promise<FacilitatorEnvelope<FacilitatorCancelPendingData>>;
|
|
62
|
+
chargeSubscription(subId: string, syncSettle?: boolean): Promise<FacilitatorEnvelope<FacilitatorChargeData>>;
|
|
63
|
+
finalizeExpired(subId: string, syncSettle?: boolean): Promise<FacilitatorEnvelope<FacilitatorFinalizeExpiredData>>;
|
|
64
|
+
getCharges(subId: string, limit?: number, offset?: number): Promise<FacilitatorEnvelope<FacilitatorGetChargesData>>;
|
|
65
|
+
getPendingChange(subId: string): Promise<FacilitatorEnvelope<FacilitatorPendingChangeRow | null>>;
|
|
66
|
+
getSubscription(subId: string): Promise<FacilitatorEnvelope<FacilitatorGetSubscriptionData>>;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export { type OKXConfig as O, OKXFacilitatorClient as a };
|