@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.
Files changed (57) hide show
  1. package/dist/cjs/OKXFacilitatorClient-Bqyw9fzj.d.ts +69 -0
  2. package/dist/cjs/client/index.d.ts +1 -1
  3. package/dist/cjs/client/index.js +34 -0
  4. package/dist/cjs/client/index.js.map +1 -1
  5. package/dist/cjs/facilitator/index.d.ts +2 -2
  6. package/dist/cjs/facilitator/index.js +166 -4
  7. package/dist/cjs/facilitator/index.js.map +1 -1
  8. package/dist/cjs/http/index.d.ts +5 -3
  9. package/dist/cjs/http/index.js +1241 -7
  10. package/dist/cjs/http/index.js.map +1 -1
  11. package/dist/cjs/index-2gWfiUbK.d.ts +713 -0
  12. package/dist/cjs/index.d.ts +2 -2
  13. package/dist/cjs/index.js +166 -4
  14. package/dist/cjs/index.js.map +1 -1
  15. package/dist/cjs/{mechanisms-sojpSwWW.d.ts → mechanisms-LhI9qkRo.d.ts} +509 -1
  16. package/dist/cjs/server/index.d.ts +4 -2
  17. package/dist/cjs/server/index.js +1256 -7
  18. package/dist/cjs/server/index.js.map +1 -1
  19. package/dist/cjs/subscription/index.d.ts +3 -0
  20. package/dist/cjs/subscription/index.js +600 -0
  21. package/dist/cjs/subscription/index.js.map +1 -0
  22. package/dist/cjs/types/index.d.ts +1 -1
  23. package/dist/cjs/utils/index.d.ts +1 -1
  24. package/dist/cjs/{x402HTTPResourceServer-CcsAkcgI.d.ts → x402HTTPResourceServer-B0mXzV8r.d.ts} +114 -1
  25. package/dist/esm/OKXFacilitatorClient-z-cCE5Db.d.mts +69 -0
  26. package/dist/esm/chunk-4KASWSSY.mjs +257 -0
  27. package/dist/esm/chunk-4KASWSSY.mjs.map +1 -0
  28. package/dist/esm/chunk-CKXR4QVD.mjs +274 -0
  29. package/dist/esm/chunk-CKXR4QVD.mjs.map +1 -0
  30. package/dist/esm/{chunk-XBQG2CDV.mjs → chunk-EYS4TWVA.mjs} +617 -9
  31. package/dist/esm/chunk-EYS4TWVA.mjs.map +1 -0
  32. package/dist/esm/client/index.d.mts +1 -1
  33. package/dist/esm/client/index.mjs +3 -2
  34. package/dist/esm/client/index.mjs.map +1 -1
  35. package/dist/esm/facilitator/index.d.mts +2 -2
  36. package/dist/esm/facilitator/index.mjs +2 -1
  37. package/dist/esm/facilitator/index.mjs.map +1 -1
  38. package/dist/esm/http/index.d.mts +5 -3
  39. package/dist/esm/http/index.mjs +3 -2
  40. package/dist/esm/index-DKbqlTu_.d.mts +713 -0
  41. package/dist/esm/index.d.mts +2 -2
  42. package/dist/esm/index.mjs +2 -1
  43. package/dist/esm/{mechanisms-sojpSwWW.d.mts → mechanisms-LhI9qkRo.d.mts} +509 -1
  44. package/dist/esm/server/index.d.mts +4 -2
  45. package/dist/esm/server/index.mjs +3 -2
  46. package/dist/esm/subscription/index.d.mts +3 -0
  47. package/dist/esm/subscription/index.mjs +309 -0
  48. package/dist/esm/subscription/index.mjs.map +1 -0
  49. package/dist/esm/types/index.d.mts +1 -1
  50. package/dist/esm/utils/index.d.mts +1 -1
  51. package/dist/esm/{x402HTTPResourceServer-DBeutKxq.d.mts → x402HTTPResourceServer-56Tq3Jup.d.mts} +114 -1
  52. package/package.json +12 -1
  53. package/dist/cjs/OKXFacilitatorClient-BvyQB1QM.d.ts +0 -59
  54. package/dist/esm/OKXFacilitatorClient-D5E3LX50.d.mts +0 -59
  55. package/dist/esm/chunk-O3IYMTNT.mjs +0 -118
  56. package/dist/esm/chunk-O3IYMTNT.mjs.map +0 -1
  57. package/dist/esm/chunk-XBQG2CDV.mjs.map +0 -1
@@ -0,0 +1,3 @@
1
+ export { A as AccessProof, z as AccessRouteRequirements, C as CancelAuth, x as CancelInitiator, w as ChargeResult, m as FacilitatorCancelData, o as FacilitatorCancelPendingData, l as FacilitatorChangeData, p as FacilitatorChargeData, B as FacilitatorChargeRow, j as FacilitatorEnvelope, q as FacilitatorFinalizeExpiredData, r as FacilitatorGetChargesData, t as FacilitatorGetSubscriptionData, s as FacilitatorPendingChangeRow, k as FacilitatorSubscribeData, O as OnBeforeAccessContext, D as OnBeforeAccessHook, E as OnBeforeAccessResult, n as PendingChangeCancelAuth, G as PendingPlanChange, I as PlanCatalog, J as PlanCatalogEntry, y as PlanInitialCharge, K as SettleCancelOk, L as SettleCancelPendingChangeOk, M as SettleCancelPendingChangeResult, Q as SettleCancelResult, R as SettleChangeOk, T as SettleChangeResult, U as SettleResultFail, W as SettleSubscribeOk, X as SettleSubscribeResult, u as Subscription, v as SubscriptionCapability, Y as SubscriptionFacilitatorClient, Z as SubscriptionState, _ as VerifyAccessOk, $ as VerifyAccessResult, a0 as VerifyChangeOk, a1 as VerifyChangeResult, a2 as VerifyOwnershipOk, a3 as VerifyOwnershipResult, a4 as VerifyResult, a5 as VerifyResultFail, a6 as VerifyResultOk, a7 as hasSubscriptionCapability, a8 as supportsSubscription } from '../mechanisms-LhI9qkRo.js';
2
+ export { A as AccessProofMessageInput, B as BuildCancelAuthTypedDataInput, a as BuildPermit2TypedDataInput, b as BuildSubscriptionTermsTypedDataInput, C as CANCEL_AUTH_TYPES, c as ChangeFromExtra, d as ChargeError, e as ChargeErrorCode, E as EncodePaymentPayloadInput, f as ErrorCode, I as InMemoryStore, P as PENDING_CHANGE_CANCEL_AUTH_TYPES, g as PERMIT2_TYPES, h as PermitSingleData, S as SUBSCRIPTION_TERMS_TYPES, i as SubscriptionClient, j as SubscriptionClientConfig, k as SubscriptionContractAddresses, l as SubscriptionPaymentInner, m as SubscriptionPlanExtra, n as SubscriptionRequirementsExtra, o as SubscriptionStore, p as SubscriptionTerms, T as TypedDataEnvelope, Z as ZERO_BYTES32, q as addCalendarMonths, r as asSubscriptionPaymentInner, s as base64DecodeUtf8, t as base64EncodeUtf8, u as buildAccessProofMessage, v as buildCancelAuthTypedData, w as buildPendingChangeCancelAuthTypedData, x as buildPermit2TypedData, y as buildSubscriptionTermsTypedData, z as computeElapsedPeriods, D as computePermitSingleStructHash, F as decodeAccessProof, G as decodePaymentPayload, H as elapsedCalendarMonths, J as encodeAccessProof, K as encodePaymentPayload, L as parseChainIdFromNetwork, M as parsePaymentRequired, N as verifyTermsBindRequirements } from '../index-2gWfiUbK.js';
3
+ import 'viem';
@@ -0,0 +1,600 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/subscription/index.ts
21
+ var subscription_exports = {};
22
+ __export(subscription_exports, {
23
+ CANCEL_AUTH_TYPES: () => CANCEL_AUTH_TYPES,
24
+ ChargeError: () => ChargeError,
25
+ ChargeErrorCode: () => ChargeErrorCode,
26
+ ErrorCode: () => ErrorCode,
27
+ InMemoryStore: () => InMemoryStore,
28
+ PENDING_CHANGE_CANCEL_AUTH_TYPES: () => PENDING_CHANGE_CANCEL_AUTH_TYPES,
29
+ PERMIT2_TYPES: () => PERMIT2_TYPES,
30
+ SUBSCRIPTION_TERMS_TYPES: () => SUBSCRIPTION_TERMS_TYPES,
31
+ SubscriptionClient: () => SubscriptionClient,
32
+ ZERO_BYTES32: () => ZERO_BYTES32,
33
+ addCalendarMonths: () => addCalendarMonths,
34
+ asSubscriptionPaymentInner: () => asSubscriptionPaymentInner,
35
+ base64DecodeUtf8: () => base64DecodeUtf8,
36
+ base64EncodeUtf8: () => base64EncodeUtf8,
37
+ buildAccessProofMessage: () => buildAccessProofMessage,
38
+ buildCancelAuthTypedData: () => buildCancelAuthTypedData,
39
+ buildPendingChangeCancelAuthTypedData: () => buildPendingChangeCancelAuthTypedData,
40
+ buildPermit2TypedData: () => buildPermit2TypedData,
41
+ buildSubscriptionTermsTypedData: () => buildSubscriptionTermsTypedData,
42
+ computeElapsedPeriods: () => computeElapsedPeriods,
43
+ computePermitSingleStructHash: () => computePermitSingleStructHash,
44
+ decodeAccessProof: () => decodeAccessProof,
45
+ decodePaymentPayload: () => decodePaymentPayload,
46
+ elapsedCalendarMonths: () => elapsedCalendarMonths,
47
+ encodeAccessProof: () => encodeAccessProof,
48
+ encodePaymentPayload: () => encodePaymentPayload,
49
+ hasSubscriptionCapability: () => hasSubscriptionCapability,
50
+ parseChainIdFromNetwork: () => parseChainIdFromNetwork,
51
+ parsePaymentRequired: () => parsePaymentRequired,
52
+ supportsSubscription: () => supportsSubscription,
53
+ verifyTermsBindRequirements: () => verifyTermsBindRequirements
54
+ });
55
+ module.exports = __toCommonJS(subscription_exports);
56
+
57
+ // src/subscription/types.ts
58
+ function hasSubscriptionCapability(scheme) {
59
+ return typeof scheme === "object" && scheme !== null && "verifyAccess" in scheme && "settlementMode" in scheme && scheme.settlementMode === "pre";
60
+ }
61
+
62
+ // src/subscription/errors.ts
63
+ var ErrorCode = {
64
+ // subscribe / change
65
+ TermsBindingInvalid: "terms_binding_invalid",
66
+ AllowanceInsufficient: "allowance_insufficient",
67
+ AllowanceExpired: "allowance_expired",
68
+ // charge
69
+ PeriodNotDue: "period_not_due",
70
+ InsufficientBalance: "insufficient_balance",
71
+ // charge / cancel / access
72
+ SubscriptionNotActive: "subscription_not_active",
73
+ /**
74
+ * SDK-local code. Surfaced by `verifyAccess` when local period math
75
+ * yields `currentCalculatePeriod === 0` — subscription exists but
76
+ * `nowSec < startAt`, i.e. has not yet entered its first chargeable
77
+ * period.
78
+ */
79
+ SubscriptionNotYetActive: "subscription_not_yet_active",
80
+ UnauthorizedCaller: "unauthorized_caller",
81
+ // cancel
82
+ CancelSignatureInvalid: "cancel_signature_invalid",
83
+ CancelNonceUsed: "cancel_nonce_used",
84
+ // change
85
+ TierSame: "tier_same",
86
+ ChangeEffectiveAtMismatch: "change_effective_at_mismatch",
87
+ MerchantMismatch: "merchant_mismatch",
88
+ PayerMismatch: "payer_mismatch",
89
+ PendingChangeExists: "pending_change_exists",
90
+ SubNotActiveForChange: "sub_not_active_for_change",
91
+ // cancel-pending-change
92
+ NoPendingChange: "no_pending_change",
93
+ // all writes
94
+ ConfirmationTimeout: "confirmation_timeout"
95
+ };
96
+ var ChargeErrorCode = {
97
+ PeriodNotDue: ErrorCode.PeriodNotDue,
98
+ SubscriptionNotActive: ErrorCode.SubscriptionNotActive,
99
+ InsufficientBalance: ErrorCode.InsufficientBalance,
100
+ AllowanceExpired: ErrorCode.AllowanceExpired,
101
+ UnauthorizedCaller: ErrorCode.UnauthorizedCaller,
102
+ ConfirmationTimeout: ErrorCode.ConfirmationTimeout
103
+ };
104
+ var ChargeError = class extends Error {
105
+ constructor(code, subId, txHash) {
106
+ super(`charge failed: ${code} (sub=${subId})`);
107
+ this.name = "ChargeError";
108
+ this.code = code;
109
+ this.subId = subId;
110
+ this.txHash = txHash;
111
+ }
112
+ };
113
+
114
+ // src/subscription/store.ts
115
+ var InMemoryStore = class {
116
+ constructor() {
117
+ this.data = /* @__PURE__ */ new Map();
118
+ }
119
+ async get(subId) {
120
+ const sub = this.data.get(subId);
121
+ return sub ? { ...sub } : null;
122
+ }
123
+ async put(sub) {
124
+ this.data.set(sub.subId, { ...sub });
125
+ }
126
+ async delete(subId) {
127
+ this.data.delete(subId);
128
+ }
129
+ /**
130
+ * Return all subscriptions, ordered by `startAt` ascending. Not part of
131
+ * the SubscriptionStore interface — admin/debug helper, not used by the
132
+ * scheme. Production backends should expose paginated equivalents.
133
+ */
134
+ async list() {
135
+ return Array.from(this.data.values()).map((s) => ({ ...s })).sort((a, b) => a.startAt - b.startAt);
136
+ }
137
+ };
138
+
139
+ // src/subscription/client.ts
140
+ var SubscriptionClient = class {
141
+ constructor(config) {
142
+ this.scheme = config.scheme;
143
+ this.store = config.store;
144
+ }
145
+ /**
146
+ * Run one charge period for a subscription. Throws `ChargeError` (one of 6
147
+ * codes) on facilitator-side failure. Internally `scheme.charge` already
148
+ * updates the store on success (and on `planChangeTriggered`); the client is
149
+ * a pass-through.
150
+ */
151
+ async charge(subId) {
152
+ return this.scheme.charge(subId);
153
+ }
154
+ /**
155
+ * Seller-initiated cancel (e.g. ToS violation, fraud, business reason).
156
+ *
157
+ * The SDK does NOT hold the Seller's merchant private key; the Seller must
158
+ * construct + sign a `CancelAuth` with `by=1 (MERCHANT)` outside and pass
159
+ * it in. SDK runs verifyCancel (sanity check on the auth) then settleCancel
160
+ * (facilitator + store mark canceled).
161
+ *
162
+ * Throws on either verify or settle failure.
163
+ */
164
+ async cancelBySeller(subId, auth, _reason) {
165
+ const v = await this.scheme.verifyCancel(auth, subId);
166
+ if (!v.ok) {
167
+ throw new Error(`cancelBySeller.verify failed: ${v.error}`);
168
+ }
169
+ const r = await this.scheme.settleCancel(auth, subId);
170
+ if (!r.success) {
171
+ throw new Error(`cancelBySeller.settle failed: ${r.error}`);
172
+ }
173
+ }
174
+ /**
175
+ * Re-sync a subscription from chain and repair the store. Use when:
176
+ * - `charge` threw `SubscriptionNotActive` (buyer may have cancelled
177
+ * directly via the facilitator or contract)
178
+ * - `charge` threw `ConfirmationTimeout` (network-level failure; chain
179
+ * may or may not have written)
180
+ * - periodic reconciliation
181
+ *
182
+ * If the synced sub is in `"changed"` state, the downstream `changedToSubId`
183
+ * is also fetched and persisted, so the Seller's `dueIndex` can switch over
184
+ * to the new sub without manual intervention.
185
+ */
186
+ async syncFromChain(subId) {
187
+ const latest = await this.scheme.getSubscription(subId);
188
+ if (!latest) return null;
189
+ await this.store.put(latest);
190
+ if (latest.state === "changed" && latest.changedToSubId) {
191
+ const newSub = await this.scheme.getSubscription(latest.changedToSubId);
192
+ if (newSub) await this.store.put(newSub);
193
+ }
194
+ return latest;
195
+ }
196
+ /**
197
+ * Direct store read. Cheap; does NOT touch the chain. Use this for hot-path
198
+ * lookups (e.g. resolving subId to plan/tier for business logic). For chain
199
+ * state of record, use `syncFromChain`.
200
+ */
201
+ async getSubscription(subId) {
202
+ return this.store.get(subId);
203
+ }
204
+ };
205
+
206
+ // src/subscription/codec/typed-data.ts
207
+ var import_viem = require("viem");
208
+ var ZERO_BYTES32 = `0x${"0".repeat(64)}`;
209
+ var PERMIT2_TYPES = {
210
+ PermitSingle: [
211
+ { name: "details", type: "PermitDetails" },
212
+ { name: "spender", type: "address" },
213
+ { name: "sigDeadline", type: "uint256" }
214
+ ],
215
+ PermitDetails: [
216
+ { name: "token", type: "address" },
217
+ { name: "amount", type: "uint160" },
218
+ { name: "expiration", type: "uint48" },
219
+ { name: "nonce", type: "uint48" }
220
+ ]
221
+ };
222
+ var SUBSCRIPTION_TERMS_TYPES = {
223
+ SubscriptionTerms: [
224
+ { name: "payer", type: "address" },
225
+ { name: "merchant", type: "address" },
226
+ { name: "facilitator", type: "address" },
227
+ { name: "token", type: "address" },
228
+ { name: "amountPerPeriod", type: "uint160" },
229
+ { name: "periodSec", type: "uint64" },
230
+ { name: "maxPeriods", type: "uint32" },
231
+ { name: "startAt", type: "uint64" },
232
+ { name: "initialChargePeriods", type: "uint32" },
233
+ { name: "initialChargeAmount", type: "uint160" },
234
+ { name: "termsDeadline", type: "uint64" },
235
+ { name: "permitHash", type: "bytes32" },
236
+ { name: "salt", type: "bytes32" },
237
+ { name: "planTier", type: "uint8" },
238
+ { name: "changeFromSubId", type: "bytes32" },
239
+ { name: "changeEffectiveAt", type: "uint8" },
240
+ { name: "periodMode", type: "uint8" }
241
+ ]
242
+ };
243
+ var CANCEL_AUTH_TYPES = {
244
+ CancelAuth: [
245
+ { name: "action", type: "uint8" },
246
+ { name: "subId", type: "bytes32" },
247
+ { name: "initiator", type: "uint8" },
248
+ { name: "nonce", type: "bytes32" },
249
+ { name: "deadline", type: "uint64" }
250
+ ]
251
+ };
252
+ var PENDING_CHANGE_CANCEL_AUTH_TYPES = {
253
+ PendingChangeCancelAuth: [
254
+ { name: "subId", type: "bytes32" },
255
+ { name: "newSubId", type: "bytes32" },
256
+ { name: "nonce", type: "bytes32" },
257
+ { name: "deadline", type: "uint64" }
258
+ ]
259
+ };
260
+ var CANCEL_INITIATOR_TO_ENUM = {
261
+ payer: 0,
262
+ merchant: 1
263
+ };
264
+ function getSubscriptionExtra(req) {
265
+ const extra = req.extra;
266
+ if (!extra || !extra.contracts || !extra.plan || !extra.domain) {
267
+ throw new Error(
268
+ "subscription codec: PaymentRequirements.extra is missing contracts/plan/domain"
269
+ );
270
+ }
271
+ return extra;
272
+ }
273
+ function defaultPermitAmount(extra) {
274
+ const initialChargePeriods = BigInt(extra.initialCharge?.periodCount ?? 0);
275
+ const initialChargeAmount = BigInt(extra.initialCharge?.totalAmount ?? "0");
276
+ const remainingPeriods = BigInt(extra.maxPeriods) - initialChargePeriods;
277
+ const remainingAmount = remainingPeriods > 0n ? remainingPeriods * BigInt(extra.amountPerPeriod) : 0n;
278
+ return (initialChargeAmount + remainingAmount).toString();
279
+ }
280
+ function buildPermit2TypedData(input) {
281
+ const extra = getSubscriptionExtra(input.selected);
282
+ const amount = input.amount ?? defaultPermitAmount(extra);
283
+ const chainId = parseChainIdFromNetwork(input.selected.network);
284
+ return {
285
+ domain: {
286
+ name: "Permit2",
287
+ chainId,
288
+ verifyingContract: extra.contracts.permit2
289
+ },
290
+ types: PERMIT2_TYPES,
291
+ primaryType: "PermitSingle",
292
+ message: {
293
+ details: {
294
+ token: input.selected.asset,
295
+ amount,
296
+ expiration: input.expiration,
297
+ nonce: input.nonce
298
+ },
299
+ spender: extra.contracts.subscription,
300
+ sigDeadline: input.sigDeadline
301
+ }
302
+ };
303
+ }
304
+ function computePermitSingleStructHash(permit) {
305
+ const PERMIT_DETAILS_TYPEHASH = (0, import_viem.keccak256)(
306
+ new TextEncoder().encode(
307
+ "PermitDetails(address token,uint160 amount,uint48 expiration,uint48 nonce)"
308
+ )
309
+ );
310
+ const detailsHash = (0, import_viem.keccak256)(
311
+ (0, import_viem.encodeAbiParameters)(
312
+ [
313
+ { type: "bytes32" },
314
+ { type: "address" },
315
+ { type: "uint160" },
316
+ { type: "uint48" },
317
+ { type: "uint48" }
318
+ ],
319
+ [
320
+ PERMIT_DETAILS_TYPEHASH,
321
+ permit.details.token,
322
+ BigInt(permit.details.amount),
323
+ Number(permit.details.expiration),
324
+ Number(permit.details.nonce)
325
+ ]
326
+ )
327
+ );
328
+ const PERMIT_SINGLE_TYPEHASH = (0, import_viem.keccak256)(
329
+ new TextEncoder().encode(
330
+ "PermitSingle(PermitDetails details,address spender,uint256 sigDeadline)PermitDetails(address token,uint160 amount,uint48 expiration,uint48 nonce)"
331
+ )
332
+ );
333
+ return (0, import_viem.keccak256)(
334
+ (0, import_viem.encodeAbiParameters)(
335
+ [{ type: "bytes32" }, { type: "bytes32" }, { type: "address" }, { type: "uint256" }],
336
+ [PERMIT_SINGLE_TYPEHASH, detailsHash, permit.spender, BigInt(permit.sigDeadline)]
337
+ )
338
+ );
339
+ }
340
+ function buildSubscriptionTermsTypedData(input) {
341
+ const extra = getSubscriptionExtra(input.selected);
342
+ const domain = input.domain ?? extra.domain;
343
+ let changeEffectiveAt = 0;
344
+ if (input.changeFrom?.effectiveAt === "immediate") changeEffectiveAt = 1;
345
+ else if (input.changeFrom?.effectiveAt === "period_end") changeEffectiveAt = 2;
346
+ const message = {
347
+ payer: input.payer,
348
+ merchant: input.selected.payTo,
349
+ facilitator: extra.facilitator,
350
+ token: input.selected.asset,
351
+ amountPerPeriod: extra.amountPerPeriod,
352
+ periodSec: extra.periodSec,
353
+ maxPeriods: extra.maxPeriods,
354
+ startAt: input.startAt,
355
+ initialChargePeriods: extra.initialCharge?.periodCount ?? 0,
356
+ initialChargeAmount: extra.initialCharge?.totalAmount ?? "0",
357
+ termsDeadline: input.termsDeadline,
358
+ permitHash: input.permitHash,
359
+ salt: input.salt,
360
+ planTier: extra.plan.tier,
361
+ changeFromSubId: input.changeFrom?.fromSubId ?? ZERO_BYTES32,
362
+ changeEffectiveAt,
363
+ periodMode: extra.periodMode ?? 0
364
+ };
365
+ return {
366
+ domain,
367
+ types: SUBSCRIPTION_TERMS_TYPES,
368
+ primaryType: "SubscriptionTerms",
369
+ message
370
+ };
371
+ }
372
+ function buildCancelAuthTypedData(input) {
373
+ return {
374
+ domain: input.domain,
375
+ types: CANCEL_AUTH_TYPES,
376
+ primaryType: "CancelAuth",
377
+ message: {
378
+ action: 0,
379
+ subId: input.subId,
380
+ initiator: CANCEL_INITIATOR_TO_ENUM[input.initiator],
381
+ nonce: input.nonce,
382
+ deadline: input.deadline
383
+ }
384
+ };
385
+ }
386
+ function buildPendingChangeCancelAuthTypedData(input) {
387
+ return {
388
+ domain: input.domain,
389
+ types: PENDING_CHANGE_CANCEL_AUTH_TYPES,
390
+ primaryType: "PendingChangeCancelAuth",
391
+ message: {
392
+ subId: input.subId,
393
+ newSubId: input.newSubId,
394
+ nonce: input.nonce,
395
+ deadline: input.deadline
396
+ }
397
+ };
398
+ }
399
+ function parseChainIdFromNetwork(network) {
400
+ const parts = network.split(":");
401
+ if (parts.length !== 2 || parts[0] !== "eip155") {
402
+ throw new Error(`parseChainIdFromNetwork: expected "eip155:<chainId>", got "${network}"`);
403
+ }
404
+ const id = Number(parts[1]);
405
+ if (!Number.isInteger(id) || id <= 0) {
406
+ throw new Error(`parseChainIdFromNetwork: invalid chainId "${parts[1]}"`);
407
+ }
408
+ return id;
409
+ }
410
+
411
+ // src/subscription/codec/verify-terms.ts
412
+ function addrEq(a, b) {
413
+ return a.toLowerCase() === b.toLowerCase();
414
+ }
415
+ function hexEq(a, b) {
416
+ return !!a && a.toLowerCase() === b.toLowerCase();
417
+ }
418
+ function verifyTermsBindRequirements(terms, requirements) {
419
+ const extra = requirements.extra ?? {};
420
+ if (!extra.plan || extra.amountPerPeriod === void 0 || extra.facilitator === void 0) {
421
+ return ErrorCode.TermsBindingInvalid;
422
+ }
423
+ if (!addrEq(terms.merchant, requirements.payTo)) return ErrorCode.MerchantMismatch;
424
+ if (!addrEq(terms.token, requirements.asset)) return ErrorCode.TermsBindingInvalid;
425
+ if (!addrEq(terms.facilitator, extra.facilitator)) return ErrorCode.TermsBindingInvalid;
426
+ if (terms.amountPerPeriod !== extra.amountPerPeriod) return ErrorCode.TermsBindingInvalid;
427
+ if (terms.periodSec !== extra.periodSec) return ErrorCode.TermsBindingInvalid;
428
+ if (terms.maxPeriods !== extra.maxPeriods) return ErrorCode.TermsBindingInvalid;
429
+ if (terms.periodMode !== (extra.periodMode ?? 0)) return ErrorCode.TermsBindingInvalid;
430
+ if (terms.planTier !== extra.plan.tier) return ErrorCode.TermsBindingInvalid;
431
+ if (extra.startAt !== void 0 && terms.startAt !== extra.startAt) {
432
+ return ErrorCode.TermsBindingInvalid;
433
+ }
434
+ const expectedInitPeriods = extra.initialCharge?.periodCount ?? 0;
435
+ const expectedInitAmount = extra.initialCharge?.totalAmount ?? "0";
436
+ if (terms.initialChargePeriods !== expectedInitPeriods) return ErrorCode.TermsBindingInvalid;
437
+ if (terms.initialChargeAmount !== expectedInitAmount) return ErrorCode.TermsBindingInvalid;
438
+ if (extra.changeFrom) {
439
+ if (!hexEq(terms.changeFromSubId, extra.changeFrom.fromSubId)) {
440
+ return ErrorCode.TermsBindingInvalid;
441
+ }
442
+ const expectedEff = extra.changeFrom.effectiveAt === "immediate" ? 1 : extra.changeFrom.effectiveAt === "period_end" ? 2 : 0;
443
+ if (terms.changeEffectiveAt !== expectedEff) return ErrorCode.TermsBindingInvalid;
444
+ } else {
445
+ if (terms.changeFromSubId !== ZERO_BYTES32) return ErrorCode.TermsBindingInvalid;
446
+ if (terms.changeEffectiveAt !== 0) return ErrorCode.TermsBindingInvalid;
447
+ }
448
+ return null;
449
+ }
450
+
451
+ // src/subscription/codec/period-math.ts
452
+ var PERIOD_MODE_CALENDAR_MONTH = 1;
453
+ function computeElapsedPeriods(periodMode, startAt, billingAnchorAt, periodSec, nowSec) {
454
+ if (nowSec < startAt) return 0;
455
+ if (periodMode === PERIOD_MODE_CALENDAR_MONTH) {
456
+ const anchor = billingAnchorAt > 0 ? billingAnchorAt : startAt;
457
+ const startOffset = elapsedCalendarMonths(anchor, startAt);
458
+ return elapsedCalendarMonths(anchor, nowSec) - startOffset + 1;
459
+ }
460
+ if (periodSec <= 0) return 0;
461
+ return Math.floor((nowSec - startAt) / periodSec) + 1;
462
+ }
463
+ function elapsedCalendarMonths(anchorSec, tsSec) {
464
+ if (tsSec <= anchorSec) return 0;
465
+ const anchor = new Date(anchorSec * 1e3);
466
+ const ts = new Date(tsSec * 1e3);
467
+ let diff = (ts.getUTCFullYear() - anchor.getUTCFullYear()) * 12 + (ts.getUTCMonth() - anchor.getUTCMonth());
468
+ if (diff < 0) return 0;
469
+ if (addCalendarMonths(anchorSec, diff) > tsSec) diff--;
470
+ return Math.max(diff, 0);
471
+ }
472
+ function addCalendarMonths(anchorSec, n) {
473
+ const anchor = new Date(anchorSec * 1e3);
474
+ const targetYear = anchor.getUTCFullYear() + Math.floor((anchor.getUTCMonth() + n) / 12);
475
+ const targetMonth = ((anchor.getUTCMonth() + n) % 12 + 12) % 12;
476
+ const daysInTargetMonth = new Date(Date.UTC(targetYear, targetMonth + 1, 0)).getUTCDate();
477
+ const day = Math.min(anchor.getUTCDate(), daysInTargetMonth);
478
+ const ts = Date.UTC(
479
+ targetYear,
480
+ targetMonth,
481
+ day,
482
+ anchor.getUTCHours(),
483
+ anchor.getUTCMinutes(),
484
+ anchor.getUTCSeconds(),
485
+ anchor.getUTCMilliseconds()
486
+ );
487
+ return Math.floor(ts / 1e3);
488
+ }
489
+
490
+ // src/subscription/codec/base64.ts
491
+ var hasBuffer = typeof Buffer !== "undefined";
492
+ function base64EncodeUtf8(value) {
493
+ if (hasBuffer) return Buffer.from(value, "utf8").toString("base64");
494
+ const binary = unescape(encodeURIComponent(value));
495
+ return globalThis.btoa(binary);
496
+ }
497
+ function base64DecodeUtf8(value) {
498
+ if (hasBuffer) return Buffer.from(value, "base64").toString("utf8");
499
+ const binary = globalThis.atob(value);
500
+ return decodeURIComponent(escape(binary));
501
+ }
502
+
503
+ // src/subscription/codec/payload.ts
504
+ function parsePaymentRequired(headerValue) {
505
+ const json = base64DecodeUtf8(headerValue);
506
+ const parsed = JSON.parse(json);
507
+ if (!parsed || !Array.isArray(parsed.accepts)) {
508
+ throw new Error("parsePaymentRequired: missing or invalid `accepts` array");
509
+ }
510
+ return parsed.accepts;
511
+ }
512
+ function encodePaymentPayload(input) {
513
+ const payload = {
514
+ x402Version: 2,
515
+ accepted: input.selected,
516
+ payload: {
517
+ permitSingle: input.permitSingle,
518
+ permitSingleSignature: input.permitSingleSignature,
519
+ terms: input.terms,
520
+ termsSignature: input.termsSignature
521
+ }
522
+ };
523
+ return base64EncodeUtf8(JSON.stringify(payload));
524
+ }
525
+ function decodePaymentPayload(headerValue) {
526
+ const json = base64DecodeUtf8(headerValue);
527
+ return JSON.parse(json);
528
+ }
529
+ function asSubscriptionPaymentInner(payload) {
530
+ const inner = payload.payload;
531
+ if (!inner || !inner.permitSingle || !inner.terms || !inner.permitSingleSignature || !inner.termsSignature) {
532
+ throw new Error(
533
+ "asSubscriptionPaymentInner: payload.payload is missing required permitSingle/terms fields"
534
+ );
535
+ }
536
+ return inner;
537
+ }
538
+
539
+ // src/subscription/codec/access-proof.ts
540
+ var import_viem2 = require("viem");
541
+ function buildAccessProofMessage(input) {
542
+ return (0, import_viem2.keccak256)(
543
+ (0, import_viem2.encodePacked)(
544
+ ["bytes32", "address", "uint256"],
545
+ [input.subId, input.payer, BigInt(input.timestamp)]
546
+ )
547
+ );
548
+ }
549
+ function encodeAccessProof(proof) {
550
+ return base64EncodeUtf8(JSON.stringify(proof));
551
+ }
552
+ function decodeAccessProof(headerValue) {
553
+ const json = base64DecodeUtf8(headerValue);
554
+ const parsed = JSON.parse(json);
555
+ if (!parsed || parsed.kind !== "subscription-id") {
556
+ throw new Error(`decodeAccessProof: expected kind="subscription-id", got "${parsed?.kind}"`);
557
+ }
558
+ return parsed;
559
+ }
560
+
561
+ // src/subscription/facilitator-client.ts
562
+ function supportsSubscription(client) {
563
+ const c = client;
564
+ return typeof c.subscribe === "function" && typeof c.changeSubscription === "function" && typeof c.cancelSubscription === "function" && typeof c.cancelPendingChange === "function" && typeof c.chargeSubscription === "function" && typeof c.finalizeExpired === "function" && typeof c.getCharges === "function" && typeof c.getPendingChange === "function" && typeof c.getSubscription === "function";
565
+ }
566
+ // Annotate the CommonJS export names for ESM import in node:
567
+ 0 && (module.exports = {
568
+ CANCEL_AUTH_TYPES,
569
+ ChargeError,
570
+ ChargeErrorCode,
571
+ ErrorCode,
572
+ InMemoryStore,
573
+ PENDING_CHANGE_CANCEL_AUTH_TYPES,
574
+ PERMIT2_TYPES,
575
+ SUBSCRIPTION_TERMS_TYPES,
576
+ SubscriptionClient,
577
+ ZERO_BYTES32,
578
+ addCalendarMonths,
579
+ asSubscriptionPaymentInner,
580
+ base64DecodeUtf8,
581
+ base64EncodeUtf8,
582
+ buildAccessProofMessage,
583
+ buildCancelAuthTypedData,
584
+ buildPendingChangeCancelAuthTypedData,
585
+ buildPermit2TypedData,
586
+ buildSubscriptionTermsTypedData,
587
+ computeElapsedPeriods,
588
+ computePermitSingleStructHash,
589
+ decodeAccessProof,
590
+ decodePaymentPayload,
591
+ elapsedCalendarMonths,
592
+ encodeAccessProof,
593
+ encodePaymentPayload,
594
+ hasSubscriptionCapability,
595
+ parseChainIdFromNetwork,
596
+ parsePaymentRequired,
597
+ supportsSubscription,
598
+ verifyTermsBindRequirements
599
+ });
600
+ //# sourceMappingURL=index.js.map