s402 0.1.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.
@@ -0,0 +1,192 @@
1
+ import { createS402Error, s402Error, s402ErrorCode, s402ErrorCodeType, s402ErrorInfo } from "./errors.mjs";
2
+ import { S402_HEADERS, S402_VERSION, s402Discovery, s402EscrowExtra, s402EscrowPayload, s402ExactPayload, s402Mandate, s402MandateRequirements, s402PaymentPayload, s402PaymentPayloadBase, s402PaymentRequirements, s402PrepaidExtra, s402PrepaidPayload, s402Scheme, s402SettleResponse, s402SettlementMode, s402StreamExtra, s402StreamPayload, s402UnlockExtra, s402UnlockPayload, s402VerifyResponse } from "./types.mjs";
3
+ import { decodePaymentPayload, decodePaymentRequired, decodeSettleResponse, detectProtocol, encodePaymentPayload, encodePaymentRequired, encodeSettleResponse, extractRequirementsFromResponse, isValidAmount, validateRequirementsShape } from "./http.mjs";
4
+
5
+ //#region src/scheme.d.ts
6
+ /** Implemented by each scheme on the client side */
7
+ interface s402ClientScheme {
8
+ /** Which scheme this implements */
9
+ readonly scheme: s402Scheme;
10
+ /** Create a signed payment payload from server requirements */
11
+ createPayment(requirements: s402PaymentRequirements): Promise<s402PaymentPayload>;
12
+ }
13
+ /** Implemented by each scheme on the server side */
14
+ interface s402ServerScheme {
15
+ readonly scheme: s402Scheme;
16
+ /** Build payment requirements from route config */
17
+ buildRequirements(config: s402RouteConfig): s402PaymentRequirements;
18
+ }
19
+ /**
20
+ * Implemented by each scheme in the facilitator.
21
+ *
22
+ * Critical: each scheme has its OWN verify logic.
23
+ * - Exact: signature recovery + dry-run simulation + balance check
24
+ * - Stream: stream creation PTB validation + deposit check
25
+ * - Escrow: escrow creation PTB validation + arbiter/deadline check
26
+ * - Unlock: escrow validation (key release is separate PTB)
27
+ */
28
+ interface s402FacilitatorScheme {
29
+ readonly scheme: s402Scheme;
30
+ /** Verify a payment payload without broadcasting */
31
+ verify(payload: s402PaymentPayload, requirements: s402PaymentRequirements): Promise<s402VerifyResponse>;
32
+ /** Verify and broadcast the transaction */
33
+ settle(payload: s402PaymentPayload, requirements: s402PaymentRequirements): Promise<s402SettleResponse>;
34
+ }
35
+ /**
36
+ * For self-sovereign agents that hold their own keys.
37
+ * Builds, signs, and broadcasts in one step — no facilitator needed.
38
+ *
39
+ * MUST call waitForTransaction() before returning success.
40
+ * Without finality confirmation, server could grant access for a
41
+ * transaction that gets reverted.
42
+ */
43
+ interface s402DirectScheme {
44
+ readonly scheme: s402Scheme;
45
+ /** Build, sign, broadcast, and wait for finality */
46
+ settleDirectly(requirements: s402PaymentRequirements): Promise<s402SettleResponse>;
47
+ }
48
+ /** Per-route payment configuration for the server middleware */
49
+ interface s402RouteConfig {
50
+ /** Which payment scheme(s) to accept. Always includes "exact" for x402 compat. */
51
+ schemes: s402Scheme[];
52
+ /** Amount in base units, same as wire format (e.g., "1000000" for 0.001 SUI in MIST) */
53
+ price: string;
54
+ /** Sui network */
55
+ network: string;
56
+ /** Recipient address */
57
+ payTo: string;
58
+ /** Move coin type */
59
+ asset?: string;
60
+ /** Facilitator URL (optional for direct settlement) */
61
+ facilitatorUrl?: string;
62
+ /** Settlement mode preference */
63
+ settlementMode?: s402SettlementMode;
64
+ /** AP2 mandate requirements */
65
+ mandate?: {
66
+ required: boolean;
67
+ minPerTx?: string;
68
+ };
69
+ /** Protocol fee in basis points */
70
+ protocolFeeBps?: number;
71
+ /** Require on-chain receipt */
72
+ receiptRequired?: boolean;
73
+ stream?: {
74
+ ratePerSecond: string;
75
+ budgetCap: string;
76
+ minDeposit: string;
77
+ };
78
+ escrow?: {
79
+ seller: string;
80
+ arbiter?: string;
81
+ deadlineMs: string;
82
+ };
83
+ unlock?: {
84
+ encryptionId: string;
85
+ walrusBlobId: string;
86
+ encryptionPackageId: string;
87
+ };
88
+ prepaid?: {
89
+ ratePerCall: string;
90
+ maxCalls?: string;
91
+ minDeposit: string;
92
+ withdrawalDelayMs: string;
93
+ };
94
+ }
95
+ //#endregion
96
+ //#region src/client.d.ts
97
+ declare class s402Client {
98
+ private schemes;
99
+ /**
100
+ * Register a scheme implementation for a network.
101
+ *
102
+ * @param network - Sui network (e.g., "sui:testnet")
103
+ * @param scheme - Scheme implementation
104
+ */
105
+ register(network: string, scheme: s402ClientScheme): this;
106
+ /**
107
+ * Create a payment payload for the given requirements.
108
+ *
109
+ * Auto-selects the best scheme: prefers the first scheme in the server's
110
+ * `accepts` array that we have a registered implementation for.
111
+ *
112
+ * Accepts typed s402PaymentRequirements only. For x402 input, normalize
113
+ * first via `normalizeRequirements()` from 's402/compat'.
114
+ */
115
+ createPayment(requirements: s402PaymentRequirements): Promise<s402PaymentPayload>;
116
+ /**
117
+ * Check if we can handle requirements for a given network.
118
+ */
119
+ supports(network: string, scheme: s402Scheme): boolean;
120
+ }
121
+ //#endregion
122
+ //#region src/facilitator.d.ts
123
+ declare class s402Facilitator {
124
+ private schemes;
125
+ /**
126
+ * Register a scheme-specific facilitator for a network.
127
+ */
128
+ register(network: string, scheme: s402FacilitatorScheme): this;
129
+ /**
130
+ * Verify a payment payload by dispatching to the correct scheme.
131
+ */
132
+ verify(payload: s402PaymentPayload, requirements: s402PaymentRequirements): Promise<s402VerifyResponse>;
133
+ /**
134
+ * Settle a payment by dispatching to the correct scheme.
135
+ */
136
+ settle(payload: s402PaymentPayload, requirements: s402PaymentRequirements): Promise<s402SettleResponse>;
137
+ /**
138
+ * Expiration-guarded verify + settle in one call.
139
+ * Rejects expired requirements, verifies the payload, then settles.
140
+ *
141
+ * Note: True atomicity comes from Sui's PTBs in the scheme implementation,
142
+ * not from this method. This method provides the expiration guard and
143
+ * sequential verify→settle orchestration.
144
+ */
145
+ process(payload: s402PaymentPayload, requirements: s402PaymentRequirements): Promise<s402SettleResponse>;
146
+ /**
147
+ * Check if a scheme is supported for a network.
148
+ */
149
+ supports(network: string, scheme: s402Scheme): boolean;
150
+ /**
151
+ * List supported schemes for a network.
152
+ */
153
+ supportedSchemes(network: string): s402Scheme[];
154
+ private resolveScheme;
155
+ }
156
+ //#endregion
157
+ //#region src/server.d.ts
158
+ declare class s402ResourceServer {
159
+ private schemes;
160
+ private facilitator;
161
+ /**
162
+ * Register a server-side scheme for building requirements.
163
+ */
164
+ register(network: string, scheme: s402ServerScheme): this;
165
+ /**
166
+ * Set the facilitator for verify + settle.
167
+ */
168
+ setFacilitator(facilitator: s402Facilitator): this;
169
+ /**
170
+ * Build payment requirements for a route.
171
+ * Uses the first scheme in the config's schemes array.
172
+ * Always includes "exact" in accepts for x402 compat.
173
+ */
174
+ buildRequirements(config: s402RouteConfig): s402PaymentRequirements;
175
+ /**
176
+ * Verify a payment payload.
177
+ */
178
+ verify(payload: s402PaymentPayload, requirements: s402PaymentRequirements): Promise<s402VerifyResponse>;
179
+ /**
180
+ * Settle a pre-verified payment payload (no verify, no expiration check).
181
+ * Prefer `process()` for the full guarded path.
182
+ */
183
+ settle(payload: s402PaymentPayload, requirements: s402PaymentRequirements): Promise<s402SettleResponse>;
184
+ /**
185
+ * Expiration-guarded verify + settle. This is the recommended path.
186
+ * Rejects expired requirements, verifies the payload, then settles.
187
+ * True atomicity comes from Sui PTBs in the scheme implementation.
188
+ */
189
+ process(payload: s402PaymentPayload, requirements: s402PaymentRequirements): Promise<s402SettleResponse>;
190
+ }
191
+ //#endregion
192
+ export { S402_HEADERS, S402_VERSION, createS402Error, decodePaymentPayload, decodePaymentRequired, decodeSettleResponse, detectProtocol, encodePaymentPayload, encodePaymentRequired, encodeSettleResponse, extractRequirementsFromResponse, isValidAmount, s402Client, type s402ClientScheme, type s402DirectScheme, type s402Discovery, s402Error, s402ErrorCode, type s402ErrorCodeType, type s402ErrorInfo, type s402EscrowExtra, type s402EscrowPayload, type s402ExactPayload, s402Facilitator, type s402FacilitatorScheme, type s402Mandate, type s402MandateRequirements, type s402PaymentPayload, type s402PaymentPayloadBase, type s402PaymentRequirements, type s402PrepaidExtra, type s402PrepaidPayload, s402ResourceServer, type s402RouteConfig, type s402Scheme, type s402ServerScheme, type s402SettleResponse, type s402SettlementMode, type s402StreamExtra, type s402StreamPayload, type s402UnlockExtra, type s402UnlockPayload, type s402VerifyResponse, validateRequirementsShape };
package/dist/index.mjs ADDED
@@ -0,0 +1,209 @@
1
+ import { S402_HEADERS, S402_VERSION } from "./types.mjs";
2
+ import { createS402Error, s402Error, s402ErrorCode } from "./errors.mjs";
3
+ import { decodePaymentPayload, decodePaymentRequired, decodeSettleResponse, detectProtocol, encodePaymentPayload, encodePaymentRequired, encodeSettleResponse, extractRequirementsFromResponse, isValidAmount, validateRequirementsShape } from "./http.mjs";
4
+
5
+ //#region src/client.ts
6
+ var s402Client = class {
7
+ schemes = /* @__PURE__ */ new Map();
8
+ /**
9
+ * Register a scheme implementation for a network.
10
+ *
11
+ * @param network - Sui network (e.g., "sui:testnet")
12
+ * @param scheme - Scheme implementation
13
+ */
14
+ register(network, scheme) {
15
+ if (!this.schemes.has(network)) this.schemes.set(network, /* @__PURE__ */ new Map());
16
+ this.schemes.get(network).set(scheme.scheme, scheme);
17
+ return this;
18
+ }
19
+ /**
20
+ * Create a payment payload for the given requirements.
21
+ *
22
+ * Auto-selects the best scheme: prefers the first scheme in the server's
23
+ * `accepts` array that we have a registered implementation for.
24
+ *
25
+ * Accepts typed s402PaymentRequirements only. For x402 input, normalize
26
+ * first via `normalizeRequirements()` from 's402/compat'.
27
+ */
28
+ async createPayment(requirements) {
29
+ const networkSchemes = this.schemes.get(requirements.network);
30
+ if (!networkSchemes) throw new s402Error("NETWORK_MISMATCH", `No schemes registered for network "${requirements.network}"`);
31
+ for (const accepted of requirements.accepts) {
32
+ const scheme = networkSchemes.get(accepted);
33
+ if (scheme) return scheme.createPayment(requirements);
34
+ }
35
+ throw new s402Error("SCHEME_NOT_SUPPORTED", `No registered scheme matches server's accepts: [${requirements.accepts.join(", ")}]`);
36
+ }
37
+ /**
38
+ * Check if we can handle requirements for a given network.
39
+ */
40
+ supports(network, scheme) {
41
+ return this.schemes.get(network)?.has(scheme) ?? false;
42
+ }
43
+ };
44
+
45
+ //#endregion
46
+ //#region src/server.ts
47
+ var s402ResourceServer = class {
48
+ schemes = /* @__PURE__ */ new Map();
49
+ facilitator = null;
50
+ /**
51
+ * Register a server-side scheme for building requirements.
52
+ */
53
+ register(network, scheme) {
54
+ if (!this.schemes.has(network)) this.schemes.set(network, /* @__PURE__ */ new Map());
55
+ this.schemes.get(network).set(scheme.scheme, scheme);
56
+ return this;
57
+ }
58
+ /**
59
+ * Set the facilitator for verify + settle.
60
+ */
61
+ setFacilitator(facilitator) {
62
+ this.facilitator = facilitator;
63
+ return this;
64
+ }
65
+ /**
66
+ * Build payment requirements for a route.
67
+ * Uses the first scheme in the config's schemes array.
68
+ * Always includes "exact" in accepts for x402 compat.
69
+ */
70
+ buildRequirements(config) {
71
+ if (!isValidAmount(config.price)) throw new s402Error("INVALID_PAYLOAD", `Invalid price "${config.price}": must be a non-negative integer string`);
72
+ const networkSchemes = this.schemes.get(config.network);
73
+ const primaryScheme = config.schemes[0] ?? "exact";
74
+ const schemeImpl = networkSchemes?.get(primaryScheme);
75
+ if (schemeImpl) {
76
+ const requirements = schemeImpl.buildRequirements(config);
77
+ if (!requirements.accepts.includes("exact")) requirements.accepts = [...requirements.accepts, "exact"];
78
+ return requirements;
79
+ }
80
+ return {
81
+ s402Version: S402_VERSION,
82
+ accepts: [...new Set([...config.schemes, "exact"])],
83
+ network: config.network,
84
+ asset: config.asset ?? "0x2::sui::SUI",
85
+ amount: config.price,
86
+ payTo: config.payTo,
87
+ facilitatorUrl: config.facilitatorUrl,
88
+ mandate: config.mandate ? {
89
+ required: config.mandate.required,
90
+ minPerTx: config.mandate.minPerTx
91
+ } : void 0,
92
+ protocolFeeBps: config.protocolFeeBps,
93
+ receiptRequired: config.receiptRequired,
94
+ settlementMode: config.settlementMode,
95
+ stream: config.stream,
96
+ escrow: config.escrow,
97
+ unlock: config.unlock,
98
+ prepaid: config.prepaid
99
+ };
100
+ }
101
+ /**
102
+ * Verify a payment payload.
103
+ */
104
+ async verify(payload, requirements) {
105
+ if (!this.facilitator) throw new s402Error("FACILITATOR_UNAVAILABLE", "No facilitator configured on this server");
106
+ return this.facilitator.verify(payload, requirements);
107
+ }
108
+ /**
109
+ * Settle a pre-verified payment payload (no verify, no expiration check).
110
+ * Prefer `process()` for the full guarded path.
111
+ */
112
+ async settle(payload, requirements) {
113
+ if (!this.facilitator) throw new s402Error("FACILITATOR_UNAVAILABLE", "No facilitator configured on this server");
114
+ return this.facilitator.settle(payload, requirements);
115
+ }
116
+ /**
117
+ * Expiration-guarded verify + settle. This is the recommended path.
118
+ * Rejects expired requirements, verifies the payload, then settles.
119
+ * True atomicity comes from Sui PTBs in the scheme implementation.
120
+ */
121
+ async process(payload, requirements) {
122
+ if (!this.facilitator) throw new s402Error("FACILITATOR_UNAVAILABLE", "No facilitator configured on this server");
123
+ return this.facilitator.process(payload, requirements);
124
+ }
125
+ };
126
+
127
+ //#endregion
128
+ //#region src/facilitator.ts
129
+ var s402Facilitator = class {
130
+ schemes = /* @__PURE__ */ new Map();
131
+ /**
132
+ * Register a scheme-specific facilitator for a network.
133
+ */
134
+ register(network, scheme) {
135
+ if (!this.schemes.has(network)) this.schemes.set(network, /* @__PURE__ */ new Map());
136
+ this.schemes.get(network).set(scheme.scheme, scheme);
137
+ return this;
138
+ }
139
+ /**
140
+ * Verify a payment payload by dispatching to the correct scheme.
141
+ */
142
+ async verify(payload, requirements) {
143
+ return this.resolveScheme(payload.scheme, requirements.network).verify(payload, requirements);
144
+ }
145
+ /**
146
+ * Settle a payment by dispatching to the correct scheme.
147
+ */
148
+ async settle(payload, requirements) {
149
+ return this.resolveScheme(payload.scheme, requirements.network).settle(payload, requirements);
150
+ }
151
+ /**
152
+ * Expiration-guarded verify + settle in one call.
153
+ * Rejects expired requirements, verifies the payload, then settles.
154
+ *
155
+ * Note: True atomicity comes from Sui's PTBs in the scheme implementation,
156
+ * not from this method. This method provides the expiration guard and
157
+ * sequential verify→settle orchestration.
158
+ */
159
+ async process(payload, requirements) {
160
+ if (requirements.expiresAt != null) {
161
+ if (typeof requirements.expiresAt !== "number" || !Number.isFinite(requirements.expiresAt)) return {
162
+ success: false,
163
+ error: `Invalid expiresAt value: expected finite number, got ${typeof requirements.expiresAt}`,
164
+ errorCode: "INVALID_PAYLOAD"
165
+ };
166
+ if (Date.now() > requirements.expiresAt) return {
167
+ success: false,
168
+ error: `Payment requirements expired at ${new Date(requirements.expiresAt).toISOString()}`,
169
+ errorCode: "REQUIREMENTS_EXPIRED"
170
+ };
171
+ }
172
+ const scheme = this.resolveScheme(payload.scheme, requirements.network);
173
+ const verifyResult = await scheme.verify(payload, requirements);
174
+ if (!verifyResult.valid) return {
175
+ success: false,
176
+ error: verifyResult.invalidReason ?? "Payment verification failed",
177
+ errorCode: "VERIFICATION_FAILED"
178
+ };
179
+ if (typeof requirements.expiresAt === "number" && Date.now() > requirements.expiresAt) return {
180
+ success: false,
181
+ error: `Payment requirements expired during verification at ${new Date(requirements.expiresAt).toISOString()}`,
182
+ errorCode: "REQUIREMENTS_EXPIRED"
183
+ };
184
+ return scheme.settle(payload, requirements);
185
+ }
186
+ /**
187
+ * Check if a scheme is supported for a network.
188
+ */
189
+ supports(network, scheme) {
190
+ return this.schemes.get(network)?.has(scheme) ?? false;
191
+ }
192
+ /**
193
+ * List supported schemes for a network.
194
+ */
195
+ supportedSchemes(network) {
196
+ const networkSchemes = this.schemes.get(network);
197
+ return networkSchemes ? [...networkSchemes.keys()] : [];
198
+ }
199
+ resolveScheme(scheme, network) {
200
+ const networkSchemes = this.schemes.get(network);
201
+ if (!networkSchemes) throw new s402Error("NETWORK_MISMATCH", `No facilitator schemes registered for network "${network}"`);
202
+ const impl = networkSchemes.get(scheme);
203
+ if (!impl) throw new s402Error("SCHEME_NOT_SUPPORTED", `Scheme "${scheme}" is not supported on network "${network}". Supported: [${[...networkSchemes.keys()].join(", ")}]`);
204
+ return impl;
205
+ }
206
+ };
207
+
208
+ //#endregion
209
+ export { S402_HEADERS, S402_VERSION, createS402Error, decodePaymentPayload, decodePaymentRequired, decodeSettleResponse, detectProtocol, encodePaymentPayload, encodePaymentRequired, encodeSettleResponse, extractRequirementsFromResponse, isValidAmount, s402Client, s402Error, s402ErrorCode, s402Facilitator, s402ResourceServer, validateRequirementsShape };
@@ -0,0 +1,252 @@
1
+ import { s402ErrorCodeType } from "./errors.mjs";
2
+
3
+ //#region src/types.d.ts
4
+ /** Current protocol version. Always lowercase s. */
5
+ declare const S402_VERSION: "1";
6
+ /** The five s402 payment schemes */
7
+ type s402Scheme = 'exact' | 'stream' | 'escrow' | 'unlock' | 'prepaid';
8
+ /** Settlement mode: facilitator-mediated or direct on-chain */
9
+ type s402SettlementMode = 'facilitator' | 'direct';
10
+ /**
11
+ * Base payment requirements — included in every 402 response.
12
+ * Wire-compatible with x402 PaymentRequirements where fields overlap.
13
+ */
14
+ interface s402PaymentRequirements {
15
+ /** Protocol version (always "1") */
16
+ s402Version: typeof S402_VERSION;
17
+ /** Which payment schemes the server accepts. Always includes "exact" for x402 compat. */
18
+ accepts: s402Scheme[];
19
+ /** Sui network (e.g., "sui:testnet", "sui:mainnet") */
20
+ network: string;
21
+ /** Move coin type (e.g., "0x2::sui::SUI") */
22
+ asset: string;
23
+ /** Amount in base units (MIST for SUI, 6-decimal for USDC) */
24
+ amount: string;
25
+ /** Recipient address */
26
+ payTo: string;
27
+ /** Facilitator URL (optional for direct settlement) */
28
+ facilitatorUrl?: string;
29
+ /** AP2 mandate requirements (if agent spending authorization is needed) */
30
+ mandate?: s402MandateRequirements;
31
+ /** Protocol fee in basis points (0-10000). 0 = no fee. */
32
+ protocolFeeBps?: number;
33
+ /** Address that receives the protocol fee. Defaults to payTo if omitted. */
34
+ protocolFeeAddress?: string;
35
+ /** Whether the server requires an on-chain receipt NFT */
36
+ receiptRequired?: boolean;
37
+ /** Settlement mode preference */
38
+ settlementMode?: s402SettlementMode;
39
+ /** When these requirements expire (Unix timestamp ms). Facilitator MUST reject after this. */
40
+ expiresAt?: number;
41
+ /** Extra fields for stream scheme */
42
+ stream?: s402StreamExtra;
43
+ /** Extra fields for escrow scheme */
44
+ escrow?: s402EscrowExtra;
45
+ /** Extra fields for unlock scheme (pay-to-decrypt encrypted content) */
46
+ unlock?: s402UnlockExtra;
47
+ /** Extra fields for prepaid scheme */
48
+ prepaid?: s402PrepaidExtra;
49
+ /** Arbitrary extension data (forward-compatible extensibility) */
50
+ extensions?: Record<string, unknown>;
51
+ }
52
+ /** Stream-specific requirements */
53
+ interface s402StreamExtra {
54
+ /** Rate in base units per second */
55
+ ratePerSecond: string;
56
+ /** Maximum budget cap in base units */
57
+ budgetCap: string;
58
+ /** Minimum initial deposit in base units */
59
+ minDeposit: string;
60
+ /** URL for stream status checks (phase 2) */
61
+ streamSetupUrl?: string;
62
+ }
63
+ /** Escrow-specific requirements */
64
+ interface s402EscrowExtra {
65
+ /** Seller/payee address */
66
+ seller: string;
67
+ /** Arbiter address for dispute resolution */
68
+ arbiter?: string;
69
+ /** Escrow deadline in milliseconds since epoch */
70
+ deadlineMs: string;
71
+ }
72
+ /** Unlock-specific requirements (pay-to-decrypt encrypted content) */
73
+ interface s402UnlockExtra {
74
+ /** Encryption ID for key servers */
75
+ encryptionId: string;
76
+ /** Walrus blob ID containing the encrypted content */
77
+ walrusBlobId: string;
78
+ /** Encryption package ID on Sui */
79
+ encryptionPackageId: string;
80
+ }
81
+ /**
82
+ * Prepaid-specific requirements.
83
+ *
84
+ * NOTE: Prepaid inverts the normal s402 flow — the PROVIDER signs claims,
85
+ * not the CLIENT. The deposit phase uses the standard client→facilitator flow,
86
+ * but claims are provider-initiated. Full HTTP flow integration is Phase 2+.
87
+ *
88
+ * TRUST MODEL: Trust-bounded, not trustless. The provider submits call_count —
89
+ * Move cannot verify calls actually happened. Agent's protection: rate cap,
90
+ * max_calls, deposit ceiling, small deposits + short refill cycles, reputation.
91
+ * v0.2 adds signed usage receipts for cryptographic fraud proofs. See ADR-007.
92
+ */
93
+ interface s402PrepaidExtra {
94
+ /** Maximum base units per API call (rate cap) */
95
+ ratePerCall: string;
96
+ /** Max calls cap. Omit for unlimited (u64::MAX on-chain). */
97
+ maxCalls?: string;
98
+ /** Minimum deposit amount in base units */
99
+ minDeposit: string;
100
+ /** Withdrawal delay in ms. Agent must wait this long after last claim. Min 60s, max 7d. */
101
+ withdrawalDelayMs: string;
102
+ }
103
+ /** Mandate requirements in a 402 response — tells client what mandate is needed */
104
+ interface s402MandateRequirements {
105
+ /** Whether a mandate is required (true) or optional (false = speeds up if present) */
106
+ required: boolean;
107
+ /** Minimum per-transaction limit needed */
108
+ minPerTx?: string;
109
+ /** Mandate coin type (must match payment asset) */
110
+ coinType?: string;
111
+ }
112
+ /** On-chain mandate reference — included in payment payload when agent has authorization */
113
+ interface s402Mandate {
114
+ /** Mandate object ID on Sui */
115
+ mandateId: string;
116
+ /** Delegator (human) address */
117
+ delegator: string;
118
+ /** Delegate (agent) address */
119
+ delegate: string;
120
+ /** Per-transaction spending limit */
121
+ maxPerTx: string;
122
+ /** Lifetime spending cap */
123
+ maxTotal: string;
124
+ /** Amount already spent */
125
+ totalSpent: string;
126
+ /** Expiry timestamp (ms since epoch) */
127
+ expiresAtMs: string;
128
+ }
129
+ /** Base payload — all schemes include these fields */
130
+ interface s402PaymentPayloadBase {
131
+ /** Protocol version */
132
+ s402Version: typeof S402_VERSION;
133
+ /** Which scheme is being used */
134
+ scheme: s402Scheme;
135
+ }
136
+ /** Exact payment: signed transaction bytes */
137
+ interface s402ExactPayload extends s402PaymentPayloadBase {
138
+ scheme: 'exact';
139
+ payload: {
140
+ /** Base64-encoded signed transaction bytes */transaction: string; /** Base64-encoded signature */
141
+ signature: string;
142
+ };
143
+ }
144
+ /** Stream payment: signed stream creation transaction */
145
+ interface s402StreamPayload extends s402PaymentPayloadBase {
146
+ scheme: 'stream';
147
+ payload: {
148
+ transaction: string;
149
+ signature: string;
150
+ };
151
+ }
152
+ /** Escrow payment: signed escrow creation transaction */
153
+ interface s402EscrowPayload extends s402PaymentPayloadBase {
154
+ scheme: 'escrow';
155
+ payload: {
156
+ transaction: string;
157
+ signature: string;
158
+ };
159
+ }
160
+ /**
161
+ * Unlock payment: escrow creation + encryption-gated decryption.
162
+ *
163
+ * Implementation note: The encryption key release function requires all arguments
164
+ * to be `Argument::Input` (not results of prior commands), so the unlock flow is
165
+ * two-stage: TX1 creates the escrow receipt, TX2 passes that receipt as
166
+ * input to the key release for decryption. The `transaction` field here is
167
+ * TX1 (escrow creation). TX2 is built by the facilitator after TX1 settles.
168
+ */
169
+ interface s402UnlockPayload extends s402PaymentPayloadBase {
170
+ scheme: 'unlock';
171
+ payload: {
172
+ /** Escrow creation transaction (TX1 of two-stage unlock flow) */transaction: string;
173
+ signature: string; /** Encryption ID for key servers */
174
+ encryptionId: string;
175
+ };
176
+ }
177
+ /**
178
+ * Prepaid payment: agent deposits into a PrepaidBalance shared object.
179
+ * This is the deposit phase only — claims are provider-initiated (not via HTTP 402).
180
+ */
181
+ interface s402PrepaidPayload extends s402PaymentPayloadBase {
182
+ scheme: 'prepaid';
183
+ payload: {
184
+ /** Base64-encoded deposit PTB */transaction: string; /** Agent's signature */
185
+ signature: string; /** Committed rate per call (must match requirements) */
186
+ ratePerCall: string; /** Committed max calls cap (must match requirements) */
187
+ maxCalls?: string;
188
+ };
189
+ }
190
+ /** Discriminated union of all payment payloads */
191
+ type s402PaymentPayload = s402ExactPayload | s402StreamPayload | s402EscrowPayload | s402UnlockPayload | s402PrepaidPayload;
192
+ interface s402SettleResponse {
193
+ /** Whether settlement was successful */
194
+ success: boolean;
195
+ /** Transaction digest on Sui */
196
+ txDigest?: string;
197
+ /** On-chain receipt object ID (if receipt was minted) */
198
+ receiptId?: string;
199
+ /** Time to finality in milliseconds */
200
+ finalityMs?: number;
201
+ /** Stream object ID (for stream scheme) */
202
+ streamId?: string;
203
+ /** Escrow object ID (for escrow scheme) */
204
+ escrowId?: string;
205
+ /** PrepaidBalance object ID (for prepaid scheme) */
206
+ balanceId?: string;
207
+ /** Error message if settlement failed */
208
+ error?: string;
209
+ /** Typed error code for programmatic failure handling */
210
+ errorCode?: s402ErrorCodeType;
211
+ }
212
+ interface s402VerifyResponse {
213
+ /** Whether the payment payload is valid */
214
+ valid: boolean;
215
+ /** Reason for rejection */
216
+ invalidReason?: string;
217
+ /** Payer address (recovered from signature) */
218
+ payerAddress?: string;
219
+ }
220
+ interface s402Discovery {
221
+ /** Protocol version */
222
+ s402Version: typeof S402_VERSION;
223
+ /** Supported schemes */
224
+ schemes: s402Scheme[];
225
+ /** Supported Sui networks */
226
+ networks: string[];
227
+ /** Supported coin types */
228
+ assets: string[];
229
+ /** Facilitator URL */
230
+ facilitatorUrl?: string;
231
+ /** Whether direct settlement is supported */
232
+ directSettlement: boolean;
233
+ /** Whether mandates are supported */
234
+ mandateSupport: boolean;
235
+ /** Protocol fee in basis points */
236
+ protocolFeeBps: number;
237
+ /** Address that receives the protocol fee */
238
+ protocolFeeAddress?: string;
239
+ }
240
+ /**
241
+ * HTTP headers used by s402 (same names as x402 for compatibility).
242
+ * All lowercase per HTTP/2 spec (RFC 9113 §8.2.1). The Headers API
243
+ * normalizes casing for HTTP/1.1, so lowercase works everywhere.
244
+ */
245
+ declare const S402_HEADERS: {
246
+ /** Server → client: payment requirements (base64 JSON in 402 response) */readonly PAYMENT_REQUIRED: "payment-required"; /** Client → server: payment payload (base64 JSON) */
247
+ readonly PAYMENT: "x-payment"; /** Server → client: settlement result (base64 JSON) */
248
+ readonly PAYMENT_RESPONSE: "payment-response"; /** Client → server: active stream ID (phase 2 of stream protocol) */
249
+ readonly STREAM_ID: "x-stream-id";
250
+ };
251
+ //#endregion
252
+ export { S402_HEADERS, S402_VERSION, s402Discovery, s402EscrowExtra, s402EscrowPayload, s402ExactPayload, s402Mandate, s402MandateRequirements, s402PaymentPayload, s402PaymentPayloadBase, s402PaymentRequirements, s402PrepaidExtra, s402PrepaidPayload, s402Scheme, s402SettleResponse, s402SettlementMode, s402StreamExtra, s402StreamPayload, s402UnlockExtra, s402UnlockPayload, s402VerifyResponse };
package/dist/types.mjs ADDED
@@ -0,0 +1,17 @@
1
+ //#region src/types.ts
2
+ /** Current protocol version. Always lowercase s. */
3
+ const S402_VERSION = "1";
4
+ /**
5
+ * HTTP headers used by s402 (same names as x402 for compatibility).
6
+ * All lowercase per HTTP/2 spec (RFC 9113 §8.2.1). The Headers API
7
+ * normalizes casing for HTTP/1.1, so lowercase works everywhere.
8
+ */
9
+ const S402_HEADERS = {
10
+ PAYMENT_REQUIRED: "payment-required",
11
+ PAYMENT: "x-payment",
12
+ PAYMENT_RESPONSE: "payment-response",
13
+ STREAM_ID: "x-stream-id"
14
+ };
15
+
16
+ //#endregion
17
+ export { S402_HEADERS, S402_VERSION };