@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,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
|