@primitivedotdev/sdk 1.22.1 → 1.24.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.
@@ -1,294 +1,5 @@
1
- import { Address, Hex } from "viem";
1
+ import { C as toPaymentPayload, S as signInteractionPayment, _ as buildExactEvmPaymentPayload, a as NonceBinding, b as computePaymentValidityWindow, c as TokenDomain, d as X402Network, f as X402PaymentPayload, g as X402_INTERACTION_PROTOCOL_VERSION, h as X402_INTERACTION_PROTOCOL, i as InteractionEnvelope, l as TransferAuthorization, m as X402Signer, n as DEFAULT_MAX_WINDOW_SEC, o as PayoutRegistrationMessageInput, p as X402PaymentStepPayload, r as DEFAULT_MIN_SETTLEMENT_HEADROOM_SEC, s as TRANSFER_WITH_AUTHORIZATION_TYPES, t as BuiltPaymentStep, u as TransferWithAuthorizationTypedData, v as buildPaymentStepEnvelope, w as transferWithAuthorizationTypedData, x as deriveEip3009Nonce, y as buildPayoutRegistrationMessage } from "../sign-m3ZStnNw.js";
2
2
 
3
- //#region src/x402/sign.d.ts
4
- interface NonceBinding {
5
- /** The interaction id, including its `@domain`. Lowercased before hashing. */
6
- interactionId: string;
7
- /** The challenge step id (a UUID). Lowercased before hashing. */
8
- challengeStepId: string;
9
- /** The challenger's per-challenge random nonce: 64 lowercase hex chars. */
10
- challengeNonce: string;
11
- }
12
- /**
13
- * Derive the EIP-3009 nonce bound to a specific interaction step:
14
- *
15
- * keccak256( utf8(lower(interaction_id)) || 0x00
16
- * || utf8(lower(challenge_step_id)) || 0x00
17
- * || hexdecode(challenge_nonce) )
18
- *
19
- * The `0x00` separators pin the field boundaries (undelimited concatenation of
20
- * variable-length strings is collision-ambiguous), and the challenge nonce is
21
- * decoded to its 32 raw bytes before hashing. The platform recomputes this and
22
- * rejects a mismatch.
23
- */
24
- declare function deriveEip3009Nonce(input: NonceBinding): Hex;
25
- /**
26
- * The EIP-3009 `TransferWithAuthorization` EIP-712 type. The field order and
27
- * types are part of the on-chain contract and MUST NOT change.
28
- */
29
- declare const TRANSFER_WITH_AUTHORIZATION_TYPES: {
30
- readonly TransferWithAuthorization: readonly [{
31
- readonly name: "from";
32
- readonly type: "address";
33
- }, {
34
- readonly name: "to";
35
- readonly type: "address";
36
- }, {
37
- readonly name: "value";
38
- readonly type: "uint256";
39
- }, {
40
- readonly name: "validAfter";
41
- readonly type: "uint256";
42
- }, {
43
- readonly name: "validBefore";
44
- readonly type: "uint256";
45
- }, {
46
- readonly name: "nonce";
47
- readonly type: "bytes32";
48
- }];
49
- };
50
- /**
51
- * The token's EIP-712 domain. `name`/`version` MUST be the actual token's domain
52
- * params (Base mainnet USDC reports `name: "USD Coin"`, Base Sepolia `"USDC"`;
53
- * both `version: "2"`); they come from the challenge's payment requirements
54
- * `extra`. A wrong name/version produces a signature the verifier rejects.
55
- */
56
- interface TokenDomain {
57
- name: string;
58
- version: string;
59
- chainId: number;
60
- verifyingContract: Address;
61
- }
62
- interface TransferAuthorization {
63
- from: Address;
64
- to: Address;
65
- /** Token base units (USDC has 6 decimals), as a bigint. */
66
- value: bigint;
67
- validAfter: bigint;
68
- validBefore: bigint;
69
- nonce: Hex;
70
- }
71
- interface TransferWithAuthorizationTypedData {
72
- domain: {
73
- name: string;
74
- version: string;
75
- chainId: number;
76
- verifyingContract: Address;
77
- };
78
- types: typeof TRANSFER_WITH_AUTHORIZATION_TYPES;
79
- primaryType: "TransferWithAuthorization";
80
- message: TransferAuthorization;
81
- }
82
- declare function transferWithAuthorizationTypedData(domain: TokenDomain, auth: TransferAuthorization): TransferWithAuthorizationTypedData;
83
- /**
84
- * A customer-held signer. A viem `LocalAccount` satisfies this directly; any
85
- * key source (hardware wallet, injected provider) can be adapted. The key never
86
- * leaves the caller.
87
- */
88
- interface X402Signer {
89
- address: Address;
90
- signTypedData(typedData: TransferWithAuthorizationTypedData): Promise<Hex>;
91
- /**
92
- * `personal_sign` over a UTF-8 string. Only needed for
93
- * `registerPayoutAddress()` (the ownership proof); a viem `LocalAccount`
94
- * provides it directly.
95
- */
96
- signMessage?(args: {
97
- message: string;
98
- }): Promise<Hex>;
99
- }
100
- interface PayoutRegistrationMessageInput {
101
- /** The org id the address is being authorized for. Bound into the signature. */
102
- org: string;
103
- /** The payout address (the signer's own address). Lowercased in the message. */
104
- address: string;
105
- network: string;
106
- /** ISO-8601 timestamp; the server enforces a freshness window against replay. */
107
- issuedAt: string;
108
- }
109
- /**
110
- * Build the payout-address ownership message. This MUST be byte-identical to the
111
- * platform's `buildPayoutRegistrationMessage`, or registration fails the
112
- * ownership proof. The org id is in the signed bytes, so a captured signature
113
- * can never register the address under a different org.
114
- */
115
- declare function buildPayoutRegistrationMessage(input: PayoutRegistrationMessageInput): string;
116
- /** The x402 wire payload (validated server-side against the x402 schema). */
117
- interface X402PaymentPayload {
118
- x402Version: 1;
119
- scheme: "exact";
120
- network: string;
121
- payload: {
122
- signature: Hex;
123
- authorization: {
124
- from: Address;
125
- to: Address;
126
- value: string;
127
- validAfter: string;
128
- validBefore: string;
129
- nonce: Hex;
130
- };
131
- };
132
- }
133
- /**
134
- * The protocol the email-native payment interaction runs (`x402.payment/1`).
135
- * The payer's reply carries the `payment` step of this protocol.
136
- */
137
- declare const X402_INTERACTION_PROTOCOL = "x402.payment";
138
- declare const X402_INTERACTION_PROTOCOL_VERSION = 1;
139
- /**
140
- * The interaction.json envelope for one step of an email-carried interaction.
141
- * The payer's `payment` step is sent as an `interaction.json` MIME attachment
142
- * in the reply; the platform parses this envelope, validates the step against
143
- * the `x402.payment` protocol, and re-verifies the embedded payment.
144
- */
145
- interface InteractionEnvelope<P = unknown> {
146
- interaction_version: 1;
147
- /** The thread id (`uuid@domain`) the step belongs to. */
148
- interaction_id: string;
149
- protocol: string;
150
- protocol_version: number;
151
- /** The protocol step name (e.g. `"payment"`). */
152
- step: string;
153
- /** This step's id (a fresh UUID). */
154
- step_id: string;
155
- /** The id of the step this one answers (the challenge step), or null. */
156
- prev_step_id: string | null;
157
- expires_at: string | null;
158
- payload: P;
159
- }
160
- /** The `payload` of an `x402.payment` `payment` step: the signed x402 payload. */
161
- interface X402PaymentStepPayload {
162
- payment: X402PaymentPayload;
163
- }
164
- /**
165
- * A built, signed payment-step envelope plus its canonical JSON bytes. The
166
- * caller attaches `json` as the `interaction.json` part of the reply email; the
167
- * platform reads `envelope` back from those exact bytes.
168
- */
169
- interface BuiltPaymentStep {
170
- envelope: InteractionEnvelope<X402PaymentStepPayload>;
171
- /** The canonical interaction.json body (what to attach to the reply). */
172
- json: string;
173
- }
174
- /**
175
- * Build the section-2.3 interaction.json envelope for a `payment` step. Pure: no
176
- * I/O. `payment` is the signed exact-EVM payload (from
177
- * `buildExactEvmPaymentPayload`); `prevStepId` is the challenge step id this
178
- * payment answers, and `stepId` is a fresh UUID for the payment step. Returns
179
- * the envelope and its canonical JSON, so the bytes the platform reads back are
180
- * exactly the ones produced here.
181
- */
182
- declare function buildPaymentStepEnvelope(params: {
183
- /** The thread id (`uuid@domain`). */interactionId: string; /** A fresh UUID identifying this payment step. */
184
- stepId: string; /** The challenge step id this payment answers. */
185
- prevStepId: string;
186
- payment: X402PaymentPayload; /** Optional ISO-8601 step expiry. */
187
- expiresAt?: string | null;
188
- }): BuiltPaymentStep;
189
- /** Assemble the wire payload from a signed authorization. */
190
- declare function toPaymentPayload(network: string, auth: TransferAuthorization, signature: Hex): X402PaymentPayload;
191
- /**
192
- * Absolute ceiling on the total signed window (validBefore - validAfter). A
193
- * signed EIP-3009 authorization stays settleable on-chain until validBefore
194
- * regardless of the interaction state, so an unbounded window is a standing
195
- * "funds committed" risk. The real window is minutes; this 24h cap is the hard
196
- * safety ceiling, enforced so a caller-supplied window cannot bypass it.
197
- */
198
- declare const DEFAULT_MAX_WINDOW_SEC: number;
199
- /**
200
- * Minimum headroom between now and `validBefore`. The platform rejects a
201
- * payment whose authorization is about to expire (it needs SMTP + DKIM + verify
202
- * + settle latency to clear), so a `validBefore` less than this far in the
203
- * future is a guaranteed-to-fail signature. The default window is minutes; this
204
- * 60s floor is the absolute minimum the band tolerates.
205
- */
206
- declare const DEFAULT_MIN_SETTLEMENT_HEADROOM_SEC = 60;
207
- /**
208
- * Compute the EIP-3009 validity window for a payment, landing inside the band
209
- * the platform accepts. `validBefore` governs on-chain validity, so it MUST
210
- * stay far enough in the future to settle (>= `minHeadroomSec`) yet not so far
211
- * that the total window exceeds the `maxWindowSec` cap; `validAfter` is set
212
- * generously in the past for clock skew.
213
- *
214
- * Both ends of that band are payer landmines: a too-tight `validBefore` (low
215
- * headroom, e.g. a near-expired challenge) is rejected for being about to
216
- * expire, and a too-wide window (far-future expiry) is rejected as
217
- * "authorization window too wide". By default this clamps the computed window
218
- * into the band so a caller who does not override always gets a signable
219
- * window.
220
- *
221
- * If the caller passes an explicit `validBeforeSec` or `validAfterSec`, that is
222
- * an intent to pin the bound: when it falls outside the band this throws a
223
- * specific error naming which bound was violated (rather than silently signing
224
- * a doomed authorization), unless `clamp` is left enabled, in which case the
225
- * pinned value is clamped into the band like the computed one.
226
- */
227
- declare function computePaymentValidityWindow(params: {
228
- /** The challenge's expires_at, unix seconds. */challengeExpiresAtSec: number; /** Current time, unix seconds. */
229
- nowSec: number; /** Headroom past expiry for verify+settle to complete. Default 5 min. */
230
- settlementMarginSec?: number; /** How far in the past to set validAfter for clock skew. Default 5 min. */
231
- clockSkewSec?: number; /** Hard ceiling on validBefore - validAfter. Default 24h. */
232
- maxWindowSec?: number;
233
- /**
234
- * Minimum `validBefore - nowSec`. Default 60s. A signature with less headroom
235
- * cannot clear the SMTP+DKIM+settle latency and the platform rejects it.
236
- */
237
- minHeadroomSec?: number;
238
- /**
239
- * Explicit override for `validBefore` (unix seconds). When omitted it is
240
- * derived from `challengeExpiresAtSec + settlementMarginSec`.
241
- */
242
- validBeforeSec?: number;
243
- /**
244
- * Explicit override for `validAfter` (unix seconds). When omitted it is
245
- * derived from `nowSec - clockSkewSec`.
246
- */
247
- validAfterSec?: number;
248
- /**
249
- * When true (the default), an out-of-band window is clamped into the accepted
250
- * band instead of throwing. Set `false` to reject a caller-pinned override
251
- * that is out of band with a specific error rather than silently moving it.
252
- */
253
- clamp?: boolean;
254
- }): {
255
- validAfter: bigint;
256
- validBefore: bigint;
257
- };
258
- /** The x402 named networks supported in v1 (testnet first). */
259
- type X402Network = "base-sepolia" | "base";
260
- /**
261
- * The interaction-aware signer: derive the bound nonce, assemble the
262
- * authorization, and sign it. This is the one piece a stock x402 signer cannot
263
- * do (it generates the nonce internally with no injection point), so the payer
264
- * side needs this Primitive-provided helper. The key never leaves the caller.
265
- */
266
- declare function signInteractionPayment(params: {
267
- /** Sign EIP-712 typed data with the caller's own key. */sign: (typedData: TransferWithAuthorizationTypedData) => Promise<Hex>; /** Payer (from) address. */
268
- payer: Address;
269
- domain: TokenDomain; /** Recipient (the challenger's payTo). */
270
- payTo: Address; /** Amount in token base units. */
271
- amount: bigint; /** Inputs that derive the interaction-bound EIP-3009 nonce. */
272
- nonceBinding: NonceBinding;
273
- validAfter: bigint;
274
- validBefore: bigint;
275
- }): Promise<{
276
- authorization: TransferAuthorization;
277
- signature: Hex;
278
- }>;
279
- /**
280
- * Assemble (and validate) the exact-EVM x402 wire payload from an
281
- * interaction-bound, locally-signed authorization. The numeric authorization
282
- * fields are decimal strings in the wire schema, so the bigints are stringified
283
- * here; the nonce passes through as hex. Validation rejects a malformed nonce or
284
- * signature loudly rather than emitting a payload the platform will reject.
285
- */
286
- declare function buildExactEvmPaymentPayload(params: {
287
- network: X402Network;
288
- authorization: TransferAuthorization;
289
- signature: Hex;
290
- }): X402PaymentPayload;
291
- //#endregion
292
3
  //#region src/x402/client.d.ts
293
4
  interface X402PaymentRequirements {
294
5
  scheme: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@primitivedotdev/sdk",
3
- "version": "1.22.1",
3
+ "version": "1.24.0",
4
4
  "description": "Official Primitive Node.js SDK: webhook, api, openapi, contract, and parser runtime modules.",
5
5
  "type": "module",
6
6
  "module": "./dist/index.js",
@@ -50,6 +50,11 @@
50
50
  "types": "./dist/payloads/index.d.ts",
51
51
  "import": "./dist/payloads/index.js",
52
52
  "default": "./dist/payloads/index.js"
53
+ },
54
+ "./interactions": {
55
+ "types": "./dist/interactions/index.d.ts",
56
+ "import": "./dist/interactions/index.js",
57
+ "default": "./dist/interactions/index.js"
53
58
  }
54
59
  },
55
60
  "sideEffects": false,
@@ -61,13 +66,13 @@
61
66
  "generate:types": "tsx scripts/generate-types.ts",
62
67
  "generate:validator": "tsx scripts/generate-validator.ts",
63
68
  "generate": "pnpm --filter @primitivedotdev/api-core generate && pnpm generate:schema && pnpm generate:types && pnpm generate:validator",
64
- "build": "pnpm generate && NODE_OPTIONS=\"--max-old-space-size=4096\" tsdown",
69
+ "build": "pnpm generate && NODE_OPTIONS=\"--max-old-space-size=6144\" tsdown",
65
70
  "test": "vitest run",
66
71
  "test:coverage": "vitest run --coverage",
67
72
  "test:watch": "vitest",
68
73
  "typecheck": "pnpm generate && tsc --noEmit -p tsconfig.typecheck.json",
69
- "lint": "biome check --error-on-warnings src/index.ts src/validation.ts src/types.ts src/webhook src/contract src/parser src/api/index.ts src/x402 src/openapi/index.ts src/payloads tests/",
70
- "lint:fix": "biome check --write --error-on-warnings src/index.ts src/validation.ts src/types.ts src/webhook src/contract src/parser src/api/index.ts src/x402 src/openapi/index.ts src/payloads tests/",
74
+ "lint": "biome check --error-on-warnings src/index.ts src/validation.ts src/types.ts src/webhook src/contract src/parser src/api/index.ts src/x402 src/openapi/index.ts src/payloads src/interactions tests/",
75
+ "lint:fix": "biome check --write --error-on-warnings src/index.ts src/validation.ts src/types.ts src/webhook src/contract src/parser src/api/index.ts src/x402 src/openapi/index.ts src/payloads src/interactions tests/",
71
76
  "prepublishOnly": "pnpm build"
72
77
  },
73
78
  "keywords": [
@@ -97,9 +102,9 @@
97
102
  },
98
103
  "dependencies": {
99
104
  "ajv": "^8.17.1",
100
- "mailparser": "^3.9.0",
101
- "nodemailer": "^9.0.1",
102
- "sanitize-html": "^2.14.0",
105
+ "mailparser": "^3.9.14",
106
+ "nodemailer": "^9.1.1",
107
+ "sanitize-html": "^2.17.5",
103
108
  "tar-stream": "^3.1.8",
104
109
  "validator": "^13.15.35",
105
110
  "viem": "^2.21.0"
@@ -114,13 +119,13 @@
114
119
  "@types/sanitize-html": "^2.13.0",
115
120
  "@types/tar-stream": "^3.1.4",
116
121
  "@types/validator": "^13.15.10",
117
- "@vitest/coverage-v8": "^4.1.4",
122
+ "@vitest/coverage-v8": "^4.1.11",
118
123
  "esbuild": "^0.27.0",
119
124
  "json-schema-to-typescript": "^15.0.4",
120
125
  "tsdown": "^0.21.10",
121
126
  "tsx": "^4.21.0",
122
127
  "typescript": "^5.7.2",
123
128
  "vite": "^8.0.8",
124
- "vitest": "^4.1.4"
129
+ "vitest": "^4.1.11"
125
130
  }
126
131
  }