twzrd-x402-gate 0.5.4 → 0.6.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/README.md CHANGED
@@ -18,7 +18,11 @@ const client = new x402Client();
18
18
  client.register("solana:*", new ExactSvmScheme(svmSigner));
19
19
  // Optional: client.register("eip155:*", new ExactEvmScheme(evmSigner));
20
20
 
21
- installTwzrdX402ClientHook(client, { gateOnCanSpend: true });
21
+ installTwzrdX402ClientHook(client, {
22
+ gateOnCanSpend: false, // decision-only default (warn allowed)
23
+ refuseWashFlagged: true,
24
+ });
25
+ // Strict opt-in: gateOnCanSpend: true — also block when can_spend=false
22
26
  // → onBeforePaymentCreation: scores selectedRequirements, abort if policy denies
23
27
 
24
28
  const fetchWithPayment = wrapFetchWithPayment(fetch, client);
@@ -89,6 +93,92 @@ Dogfood:
89
93
  npm install twzrd-x402-gate
90
94
  ```
91
95
 
96
+ ## TWZRD Payment Control (protocol-neutral authorization core)
97
+
98
+ The gate now ships a protocol-neutral policy runtime underneath the x402 surface.
99
+ Defining invariant: **a signer path that calls `assertIntentApproved` will not sign
100
+ an intent that differs from what TWZRD evaluated.** (Honest scope: TWZRD does not
101
+ own third-party wallets - the binding is enforceable exactly where the check runs
102
+ before the signer, not as a claim over arbitrary wallet internals.)
103
+
104
+ ```typescript
105
+ import {
106
+ evaluateIntent,
107
+ assertIntentApproved,
108
+ createLocalDecisionSigner,
109
+ createDecisionRegistry,
110
+ x402RequirementsToIntent, // or ap2CheckoutToIntent
111
+ } from "twzrd-x402-gate";
112
+
113
+ const signer = createLocalDecisionSigner();
114
+ const registry = createDecisionRegistry(); // consume-once
115
+
116
+ const intent = x402RequirementsToIntent(selectedRequirements, { resourceUrl });
117
+ const token = await evaluateIntent(intent, {
118
+ signer,
119
+ mandate, // user/company mandate (purpose, ceilings, resource scope)
120
+ policy, // local hard controls (caps, lists, recurring checks)
121
+ intelligence: twzrdIntel, // optional remote counterparty intelligence
122
+ });
123
+
124
+ // Wallet-side, immediately before signing the EXACT intent:
125
+ assertIntentApproved(intentBeingSigned, token, {
126
+ registry, // replay / consume-once
127
+ publicKeyPem: signer.publicKeyPem, // signature verification
128
+ });
129
+ // throws INTENT_HASH_MISMATCH | DECISION_EXPIRED | DECISION_NOT_ALLOW |
130
+ // DECISION_REPLAYED | BAD_SIGNATURE -> the signer is never invoked
131
+ ```
132
+
133
+ - `PaymentIntent` v1 (frozen): protocol `x402 | ap2 | ucp | mpp | direct` +
134
+ network/asset/amount/payTo + resource + facilitator + mandate + recurrence
135
+ context, bound into one canonical `tiv1:` intent hash.
136
+ - Decisions are signed, expiring `DecisionToken`s - "policy version X approved
137
+ this exact transaction at this timestamp", auditable offline.
138
+ - A **block is a signed decision**, not an exception - refusals audit the same
139
+ way approvals do.
140
+ - Local hard controls (mandate scope, ceilings, allow/blocklists, cumulative
141
+ caps, recurring price checks) never depend on API availability; remote
142
+ intelligence (wash/fleet, counterparty score) plugs in via a provider.
143
+ - The category test lives in
144
+ [`test/payment-control.test.ts`](./test/payment-control.test.ts): a mandate
145
+ permits software under $100, a $12 checkout is approved, orchestration
146
+ mutates `payTo` after approval, the wallet refuses on hash mismatch,
147
+ `signerInvocationCount === 0`, and both the decision and the refusal verify
148
+ from audit records alone.
149
+
150
+ ### On the client hook (opt-in)
151
+
152
+ `installTwzrdX402ClientHook` wires the runtime into the official
153
+ `onBeforePaymentCreation` seat. Pass `paymentControl` to build the canonical
154
+ intent, run the policy runtime (with the hook's own preflight fed in as remote
155
+ intelligence), and surface a signed, intent-bound `PaymentDecision`:
156
+
157
+ ```typescript
158
+ import { installTwzrdX402ClientHook, createLocalDecisionSigner } from "twzrd-x402-gate";
159
+
160
+ const signer = createLocalDecisionSigner();
161
+ installTwzrdX402ClientHook(client, {
162
+ paymentControl: {
163
+ signer,
164
+ mandate, // optional user/company mandate
165
+ policy: { maxAmountUsd: "50" }, // optional local hard controls
166
+ },
167
+ onDecision: ({ intent, decision }) => handOff(intent, decision), // → assertIntentApproved
168
+ });
169
+ ```
170
+
171
+ - **Tighten-only composition:** a `paymentControl` block aborts even when the
172
+ legacy preflight allowed; it never loosens a legacy denial.
173
+ - **Opt-in:** with `paymentControl` unset the hook behaves exactly as before.
174
+ - x402 wire amounts (USDC micro units) are converted to the decimal USD the
175
+ runtime expects before policy evaluation. (The `x402RequirementsToIntent`
176
+ adapter still passes the raw wire amount through into the decimal `amount`
177
+ field — a latent unit bug fixed at the hook boundary here; the adapter fix is
178
+ a follow-up.)
179
+ - Hook binding test:
180
+ [`test/intent-binding.test.ts`](./test/intent-binding.test.ts).
181
+
92
182
  ### Experimental CLI: `twzrd-safe-fetch` (AgentCash advisory pre-check)
93
183
 
94
184
  > **Not a challenge-bound firewall.** Classification: `advisory_precheck`.
@@ -0,0 +1,80 @@
1
+ /**
2
+ * TWZRD Payment Control — signed, expiring DecisionTokens + intent binding.
3
+ *
4
+ * A DecisionToken is not "we checked this merchant earlier". It is:
5
+ * "at this timestamp, policy version X approved this EXACT transaction".
6
+ * The wallet (or payment client) must verify, before signing:
7
+ *
8
+ * hash(intent being signed) === token.intentHash
9
+ *
10
+ * plus expiry, decision === allow, signature, and consume-once. Any mismatch
11
+ * means refuse — the signer is never invoked.
12
+ */
13
+ import { type PaymentIntent } from "./intent.js";
14
+ export type PaymentDecisionVerdict = "allow" | "warn" | "block";
15
+ export type DecisionConstraints = {
16
+ maxAmount?: string;
17
+ allowedAssets?: string[];
18
+ requireHumanApproval?: boolean;
19
+ };
20
+ export type PaymentDecision = {
21
+ decision: PaymentDecisionVerdict;
22
+ reasonCodes: string[];
23
+ intentHash: string;
24
+ policyVersion: string;
25
+ decisionId: string;
26
+ /** ISO-8601. Tokens are short-lived by design. */
27
+ expiresAt: string;
28
+ constraints?: DecisionConstraints;
29
+ /** Signer key identifier (for rotation / audit). */
30
+ keyId: string;
31
+ /** base64 Ed25519 signature over the domain-separated canonical payload. */
32
+ signature: string;
33
+ };
34
+ export type DecisionSigner = {
35
+ keyId: string;
36
+ sign(preimage: Uint8Array): Uint8Array | Promise<Uint8Array>;
37
+ /** PEM (SPKI) for local verification; remote signers publish theirs. */
38
+ publicKeyPem?: string;
39
+ };
40
+ /** Everything signed — the token minus the signature itself. */
41
+ export declare function decisionPreimage(token: Omit<PaymentDecision, "signature">): Buffer;
42
+ /**
43
+ * Local Ed25519 decision signer. Pass a PKCS#8 PEM to pin a key; otherwise an
44
+ * ephemeral keypair is generated (fine for tests and per-process runtimes).
45
+ */
46
+ export declare function createLocalDecisionSigner(options?: {
47
+ privateKeyPem?: string;
48
+ keyId?: string;
49
+ }): DecisionSigner & {
50
+ publicKeyPem: string;
51
+ };
52
+ export declare function signDecision(unsigned: Omit<PaymentDecision, "signature" | "keyId">, signer: DecisionSigner): Promise<PaymentDecision>;
53
+ export declare function verifyDecisionSignature(token: PaymentDecision, publicKeyPem: string): boolean;
54
+ export type BindingErrorCode = "INTENT_HASH_MISMATCH" | "DECISION_EXPIRED" | "DECISION_NOT_ALLOW" | "DECISION_REPLAYED" | "BAD_SIGNATURE";
55
+ export declare class TwzrdIntentBindingError extends Error {
56
+ readonly code: BindingErrorCode;
57
+ readonly decisionId: string;
58
+ constructor(code: BindingErrorCode, decisionId: string, detail: string);
59
+ }
60
+ export type DecisionRegistry = {
61
+ /** True exactly once per decisionId; false on every replay. */
62
+ consume(decisionId: string): boolean;
63
+ };
64
+ /** In-process consume-once ledger. Entries expire with the tokens. */
65
+ export declare function createDecisionRegistry(): DecisionRegistry;
66
+ export type AssertIntentApprovedOptions = {
67
+ now?: number;
68
+ /** Enforce consume-once semantics (recommended for anything non-idempotent). */
69
+ registry?: DecisionRegistry;
70
+ /** Verify the token signature against this key before trusting it. */
71
+ publicKeyPem?: string;
72
+ };
73
+ /**
74
+ * The wallet-side check. Call with the EXACT intent about to be signed.
75
+ * Throws TwzrdIntentBindingError on any violation; returns void when the
76
+ * signature may proceed. A caught error means: do not invoke the signer.
77
+ */
78
+ export declare function assertIntentApproved(intent: PaymentIntent, token: PaymentDecision, options?: AssertIntentApprovedOptions): void;
79
+ export declare function newDecisionId(): string;
80
+ //# sourceMappingURL=decision-token.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decision-token.d.ts","sourceRoot":"","sources":["../src/decision-token.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAYH,OAAO,EAA6B,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAI5E,MAAM,MAAM,sBAAsB,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC;AAEhE,MAAM,MAAM,mBAAmB,GAAG;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,EAAE,sBAAsB,CAAC;IACjC,WAAW,EAAE,MAAM,EAAE,CAAC;IAEtB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,kDAAkD;IAClD,SAAS,EAAE,MAAM,CAAC;IAElB,WAAW,CAAC,EAAE,mBAAmB,CAAC;IAElC,oDAAoD;IACpD,KAAK,EAAE,MAAM,CAAC;IACd,4EAA4E;IAC5E,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,QAAQ,EAAE,UAAU,GAAG,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC7D,wEAAwE;IACxE,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,gEAAgE;AAChE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,IAAI,CAAC,eAAe,EAAE,WAAW,CAAC,GAAG,MAAM,CAKlF;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,CAAC,EAAE;IAClD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,cAAc,GAAG;IAAE,YAAY,EAAE,MAAM,CAAA;CAAE,CAe5C;AAED,wBAAsB,YAAY,CAChC,QAAQ,EAAE,IAAI,CAAC,eAAe,EAAE,WAAW,GAAG,OAAO,CAAC,EACtD,MAAM,EAAE,cAAc,GACrB,OAAO,CAAC,eAAe,CAAC,CAM1B;AAED,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,eAAe,EACtB,YAAY,EAAE,MAAM,GACnB,OAAO,CAYT;AAMD,MAAM,MAAM,gBAAgB,GACxB,sBAAsB,GACtB,kBAAkB,GAClB,oBAAoB,GACpB,mBAAmB,GACnB,eAAe,CAAC;AAEpB,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;gBAChB,IAAI,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAMvE;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,+DAA+D;IAC/D,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;CACtC,CAAC;AAEF,sEAAsE;AACtE,wBAAgB,sBAAsB,IAAI,gBAAgB,CASzD;AAED,MAAM,MAAM,2BAA2B,GAAG;IACxC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,gFAAgF;IAChF,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,sEAAsE;IACtE,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,aAAa,EACrB,KAAK,EAAE,eAAe,EACtB,OAAO,CAAC,EAAE,2BAA2B,GACpC,IAAI,CA2CN;AAED,wBAAgB,aAAa,IAAI,MAAM,CAEtC"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * TWZRD Payment Control — signed, expiring DecisionTokens + intent binding.
3
+ *
4
+ * A DecisionToken is not "we checked this merchant earlier". It is:
5
+ * "at this timestamp, policy version X approved this EXACT transaction".
6
+ * The wallet (or payment client) must verify, before signing:
7
+ *
8
+ * hash(intent being signed) === token.intentHash
9
+ *
10
+ * plus expiry, decision === allow, signature, and consume-once. Any mismatch
11
+ * means refuse — the signer is never invoked.
12
+ */
13
+ import { createPrivateKey, createPublicKey, generateKeyPairSync, randomUUID, sign as edSign, verify as edVerify, } from "node:crypto";
14
+ import { canonicalJson, intentHash } from "./intent.js";
15
+ const DECISION_DOMAIN = "twzrd-decision-v1\n";
16
+ /** Everything signed — the token minus the signature itself. */
17
+ export function decisionPreimage(token) {
18
+ return Buffer.concat([
19
+ Buffer.from(DECISION_DOMAIN, "utf8"),
20
+ Buffer.from(canonicalJson(token), "utf8"),
21
+ ]);
22
+ }
23
+ /**
24
+ * Local Ed25519 decision signer. Pass a PKCS#8 PEM to pin a key; otherwise an
25
+ * ephemeral keypair is generated (fine for tests and per-process runtimes).
26
+ */
27
+ export function createLocalDecisionSigner(options) {
28
+ let privateKey;
29
+ if (options?.privateKeyPem) {
30
+ privateKey = createPrivateKey(options.privateKeyPem);
31
+ }
32
+ else {
33
+ ({ privateKey } = generateKeyPairSync("ed25519"));
34
+ }
35
+ const publicKeyPem = createPublicKey(privateKey)
36
+ .export({ type: "spki", format: "pem" })
37
+ .toString();
38
+ return {
39
+ keyId: options?.keyId ?? "local-ed25519",
40
+ publicKeyPem,
41
+ sign: (preimage) => edSign(null, Buffer.from(preimage), privateKey),
42
+ };
43
+ }
44
+ export async function signDecision(unsigned, signer) {
45
+ const payload = { ...unsigned, keyId: signer.keyId };
46
+ const signature = Buffer.from(await signer.sign(decisionPreimage(payload))).toString("base64");
47
+ return { ...payload, signature };
48
+ }
49
+ export function verifyDecisionSignature(token, publicKeyPem) {
50
+ const { signature, ...payload } = token;
51
+ try {
52
+ return edVerify(null, decisionPreimage(payload), createPublicKey(publicKeyPem), Buffer.from(signature, "base64"));
53
+ }
54
+ catch {
55
+ return false;
56
+ }
57
+ }
58
+ export class TwzrdIntentBindingError extends Error {
59
+ code;
60
+ decisionId;
61
+ constructor(code, decisionId, detail) {
62
+ super(`[twzrd] ${code}: ${detail} (decisionId=${decisionId})`);
63
+ this.name = "TwzrdIntentBindingError";
64
+ this.code = code;
65
+ this.decisionId = decisionId;
66
+ }
67
+ }
68
+ /** In-process consume-once ledger. Entries expire with the tokens. */
69
+ export function createDecisionRegistry() {
70
+ const consumed = new Set();
71
+ return {
72
+ consume(decisionId) {
73
+ if (consumed.has(decisionId))
74
+ return false;
75
+ consumed.add(decisionId);
76
+ return true;
77
+ },
78
+ };
79
+ }
80
+ /**
81
+ * The wallet-side check. Call with the EXACT intent about to be signed.
82
+ * Throws TwzrdIntentBindingError on any violation; returns void when the
83
+ * signature may proceed. A caught error means: do not invoke the signer.
84
+ */
85
+ export function assertIntentApproved(intent, token, options) {
86
+ const now = options?.now ?? Date.now();
87
+ if (options?.publicKeyPem && !verifyDecisionSignature(token, options.publicKeyPem)) {
88
+ throw new TwzrdIntentBindingError("BAD_SIGNATURE", token.decisionId, "decision token signature did not verify");
89
+ }
90
+ if (token.decision !== "allow" && token.decision !== "warn") {
91
+ throw new TwzrdIntentBindingError("DECISION_NOT_ALLOW", token.decisionId, `decision is ${token.decision}`);
92
+ }
93
+ if (now >= Date.parse(token.expiresAt)) {
94
+ throw new TwzrdIntentBindingError("DECISION_EXPIRED", token.decisionId, `expired at ${token.expiresAt}`);
95
+ }
96
+ const actual = intentHash(intent);
97
+ if (actual !== token.intentHash) {
98
+ throw new TwzrdIntentBindingError("INTENT_HASH_MISMATCH", token.decisionId, `approved ${token.intentHash} but signing ${actual}`);
99
+ }
100
+ if (options?.registry && !options.registry.consume(token.decisionId)) {
101
+ throw new TwzrdIntentBindingError("DECISION_REPLAYED", token.decisionId, "decision token already consumed");
102
+ }
103
+ }
104
+ export function newDecisionId() {
105
+ return randomUUID();
106
+ }
107
+ //# sourceMappingURL=decision-token.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decision-token.js","sourceRoot":"","sources":["../src/decision-token.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -11,8 +11,12 @@ export { evaluate_x402_resource, type EvaluateX402Options, type EvaluateX402Resu
11
11
  export { withTwzrdGuard, type TwzrdGuardOptions } from "./with-guard.js";
12
12
  export { installTwzrdAutoGate, type PayWrap, type InstallAutoGateOptions, } from "./auto-gate.js";
13
13
  export { safeFetch, runAgentcashFetch, main as safeFetchMain, type SafeFetchOptions, type SafeFetchResult, } from "./safe-fetch.js";
14
- export { installTwzrdX402ClientHook, twzrdBeforePaymentCreation, type X402ClientLike, type X402SelectedRequirements, type BeforePaymentCreationContext, type BeforePaymentCreationResult, type InstallX402ClientHookOptions, } from "./x402-client-hook.js";
14
+ export { installTwzrdX402ClientHook, twzrdBeforePaymentCreation, type X402ClientLike, type X402SelectedRequirements, type BeforePaymentCreationContext, type BeforePaymentCreationResult, type InstallX402ClientHookOptions, type X402PaymentControlOptions, } from "./x402-client-hook.js";
15
15
  export { quickCheck, QUICK_PRICE_USDC, type QuickCheckResult, type QuickCheckOptions, type TwzrdTier, } from "./quick.js";
16
16
  export { createSponsoredX402Fetch, type SponsorSettle, type SponsoredX402Options, } from "./sponsored.js";
17
17
  export type { TwzrdDecision, TwzrdReadinessCard, TwzrdPreflightInput, TwzrdGateConfig, TwzrdApproveContext, TwzrdApprovalResult, TwzrdUpsellContext, X402PaymentRequirements, X402PaymentRequiredBody, X402McpPaymentRequest, X402McpPaymentRequestedContext, } from "./types.js";
18
+ export { canonicalJson, intentHash, toMicroUsd, INTENT_HASH_PREFIX, type PaymentIntent, type PaymentProtocol, } from "./intent.js";
19
+ export { assertIntentApproved, createDecisionRegistry, createLocalDecisionSigner, decisionPreimage, newDecisionId, signDecision, verifyDecisionSignature, TwzrdIntentBindingError, type AssertIntentApprovedOptions, type BindingErrorCode, type DecisionConstraints, type DecisionRegistry, type DecisionSigner, type PaymentDecision, type PaymentDecisionVerdict, } from "./decision-token.js";
20
+ export { createMemorySpendLedger, evaluateIntent, POLICY_VERSION, type CounterpartyIntelligence, type EvaluateIntentOptions, type IntelligenceProvider, type Mandate, type SpendLedger, type SpendPolicy, } from "./policy-runtime.js";
21
+ export { ap2CheckoutToIntent, x402RequirementsToIntent, type Ap2Cart, type Ap2UserMandate, type X402IntentContext, } from "./intent-adapters.js";
18
22
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AACzE,OAAO,EAAE,aAAa,EAAE,KAAK,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAC1E,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,cAAc,EACd,mBAAmB,EACnB,KAAK,mBAAmB,GACzB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC/F,OAAO,EACL,eAAe,EACf,wBAAwB,EACxB,YAAY,EACZ,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,sBAAsB,EAC3B,KAAK,0BAA0B,GAChC,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EACL,iBAAiB,EACjB,sBAAsB,EACtB,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,gBAAgB,GACtB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EACL,sBAAsB,EACtB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,GACxB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,cAAc,EAAE,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzE,OAAO,EACL,oBAAoB,EACpB,KAAK,OAAO,EACZ,KAAK,sBAAsB,GAC5B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,SAAS,EACT,iBAAiB,EACjB,IAAI,IAAI,aAAa,EACrB,KAAK,gBAAgB,EACrB,KAAK,eAAe,GACrB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,0BAA0B,EAC1B,0BAA0B,EAC1B,KAAK,cAAc,EACnB,KAAK,wBAAwB,EAC7B,KAAK,4BAA4B,EACjC,KAAK,2BAA2B,EAChC,KAAK,4BAA4B,GAClC,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,UAAU,EACV,gBAAgB,EAChB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,SAAS,GACf,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,wBAAwB,EACxB,KAAK,aAAa,EAClB,KAAK,oBAAoB,GAC1B,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,aAAa,EACb,kBAAkB,EAClB,mBAAmB,EACnB,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,kBAAkB,EAClB,uBAAuB,EACvB,uBAAuB,EACvB,qBAAqB,EACrB,8BAA8B,GAC/B,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -17,4 +17,9 @@ export { safeFetch, runAgentcashFetch, main as safeFetchMain, } from "./safe-fet
17
17
  export { installTwzrdX402ClientHook, twzrdBeforePaymentCreation, } from "./x402-client-hook.js";
18
18
  export { quickCheck, QUICK_PRICE_USDC, } from "./quick.js";
19
19
  export { createSponsoredX402Fetch, } from "./sponsored.js";
20
+ /* ── TWZRD Payment Control (protocol-neutral authorization core) ── */
21
+ export { canonicalJson, intentHash, toMicroUsd, INTENT_HASH_PREFIX, } from "./intent.js";
22
+ export { assertIntentApproved, createDecisionRegistry, createLocalDecisionSigner, decisionPreimage, newDecisionId, signDecision, verifyDecisionSignature, TwzrdIntentBindingError, } from "./decision-token.js";
23
+ export { createMemorySpendLedger, evaluateIntent, POLICY_VERSION, } from "./policy-runtime.js";
24
+ export { ap2CheckoutToIntent, x402RequirementsToIntent, } from "./intent-adapters.js";
20
25
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,qFAAqF;AACrF,uFAAuF;AACvF,qFAAqF;AACrF,OAAO,EAAE,eAAe,EAAE,WAAW,EAAkB,MAAM,WAAW,CAAC;AACzE,OAAO,EAAE,aAAa,EAAgC,MAAM,aAAa,CAAC;AAC1E,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,cAAc,EACd,mBAAmB,GAEpB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC/F,OAAO,EACL,eAAe,EACf,wBAAwB,EACxB,YAAY,GAKb,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,iBAAiB,EACjB,sBAAsB,GAIvB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EACL,sBAAsB,GAGvB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,cAAc,EAA0B,MAAM,iBAAiB,CAAC;AACzE,OAAO,EACL,oBAAoB,GAGrB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,SAAS,EACT,iBAAiB,EACjB,IAAI,IAAI,aAAa,GAGtB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,0BAA0B,EAC1B,0BAA0B,GAM3B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,UAAU,EACV,gBAAgB,GAIjB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,wBAAwB,GAGzB,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,qFAAqF;AACrF,uFAAuF;AACvF,qFAAqF;AACrF,OAAO,EAAE,eAAe,EAAE,WAAW,EAAkB,MAAM,WAAW,CAAC;AACzE,OAAO,EAAE,aAAa,EAAgC,MAAM,aAAa,CAAC;AAC1E,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,cAAc,EACd,mBAAmB,GAEpB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC/F,OAAO,EACL,eAAe,EACf,wBAAwB,EACxB,YAAY,GAKb,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,iBAAiB,EACjB,sBAAsB,GAIvB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EACL,sBAAsB,GAGvB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,cAAc,EAA0B,MAAM,iBAAiB,CAAC;AACzE,OAAO,EACL,oBAAoB,GAGrB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,SAAS,EACT,iBAAiB,EACjB,IAAI,IAAI,aAAa,GAGtB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,0BAA0B,EAC1B,0BAA0B,GAO3B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,UAAU,EACV,gBAAgB,GAIjB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,wBAAwB,GAGzB,MAAM,gBAAgB,CAAC;AAexB,uEAAuE;AACvE,OAAO,EACL,aAAa,EACb,UAAU,EACV,UAAU,EACV,kBAAkB,GAGnB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,yBAAyB,EACzB,gBAAgB,EAChB,aAAa,EACb,YAAY,EACZ,uBAAuB,EACvB,uBAAuB,GAQxB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,uBAAuB,EACvB,cAAc,EACd,cAAc,GAOf,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,mBAAmB,EACnB,wBAAwB,GAIzB,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * TWZRD Payment Control — protocol adapters into PaymentIntent v1.
3
+ *
4
+ * Adapters normalize protocol-specific payment shapes into the one canonical
5
+ * intent the policy runtime evaluates. The x402 adapter keeps the existing
6
+ * gate's behavior available on the new core; the AP2/UCP adapter is the
7
+ * non-x402 reference — it exists to prove the runtime combines a USER MANDATE
8
+ * with counterparty risk, not merely that it parses another crypto request.
9
+ */
10
+ import type { PaymentIntent } from "./intent.js";
11
+ import type { Mandate } from "./policy-runtime.js";
12
+ import type { X402SelectedRequirements } from "./x402-client-hook.js";
13
+ export type X402IntentContext = {
14
+ /** Resource URL when the requirement omits `resource` (v2 top-level). */
15
+ resourceUrl?: string;
16
+ method?: string;
17
+ facilitator?: string;
18
+ agent?: PaymentIntent["agent"];
19
+ purpose?: string;
20
+ };
21
+ /** Normalize a selected x402 payment requirement (v1 or v2 field names). */
22
+ export declare function x402RequirementsToIntent(req: X402SelectedRequirements, ctx?: X402IntentContext): PaymentIntent;
23
+ /**
24
+ * Minimal AP2-style cart: what an agent is about to check out under a user
25
+ * mandate. Field names follow the AP2 mandate/cart split — the mandate says
26
+ * what MAY be spent; the cart is the concrete transaction.
27
+ */
28
+ export type Ap2Cart = {
29
+ merchantId: string;
30
+ /** Settlement destination (merchant account / wallet). */
31
+ payTo: string;
32
+ currency: string;
33
+ total: string;
34
+ items?: Array<{
35
+ sku?: string;
36
+ description?: string;
37
+ price?: string;
38
+ }>;
39
+ checkoutUrl?: string;
40
+ category?: string;
41
+ recurring?: boolean;
42
+ priorCharge?: string;
43
+ };
44
+ export type Ap2UserMandate = {
45
+ mandateId: string;
46
+ /** Purchase categories the user authorized (e.g. ["software"]). */
47
+ categories?: string[];
48
+ maxPerTransaction?: string;
49
+ monthlyCeiling?: string;
50
+ merchantAllowPrefixes?: string[];
51
+ expiresAt?: string;
52
+ };
53
+ /** Cart -> canonical intent. The mandate rides along for the policy runtime. */
54
+ export declare function ap2CheckoutToIntent(cart: Ap2Cart, mandate: Ap2UserMandate, options?: {
55
+ network?: string;
56
+ agentId?: string;
57
+ organization?: string;
58
+ }): {
59
+ intent: PaymentIntent;
60
+ mandate: Mandate;
61
+ };
62
+ //# sourceMappingURL=intent-adapters.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"intent-adapters.d.ts","sourceRoot":"","sources":["../src/intent-adapters.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAMtE,MAAM,MAAM,iBAAiB,GAAG;IAC9B,yEAAyE;IACzE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,4EAA4E;AAC5E,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,wBAAwB,EAC7B,GAAG,CAAC,EAAE,iBAAiB,GACtB,aAAa,CAmBf;AAMD;;;;GAIG;AACH,MAAM,MAAM,OAAO,GAAG;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,0DAA0D;IAC1D,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,KAAK,CAAC;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACtE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,gFAAgF;AAChF,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,OAAO,EACb,OAAO,EAAE,cAAc,EACvB,OAAO,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,GACtE;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CA+B7C"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * TWZRD Payment Control — protocol adapters into PaymentIntent v1.
3
+ *
4
+ * Adapters normalize protocol-specific payment shapes into the one canonical
5
+ * intent the policy runtime evaluates. The x402 adapter keeps the existing
6
+ * gate's behavior available on the new core; the AP2/UCP adapter is the
7
+ * non-x402 reference — it exists to prove the runtime combines a USER MANDATE
8
+ * with counterparty risk, not merely that it parses another crypto request.
9
+ */
10
+ /** Normalize a selected x402 payment requirement (v1 or v2 field names). */
11
+ export function x402RequirementsToIntent(req, ctx) {
12
+ const payTo = req.payTo ?? req.pay_to;
13
+ const amount = req.amount ?? req.maxAmountRequired;
14
+ if (!payTo)
15
+ throw new Error("[twzrd] x402 requirement missing payTo");
16
+ if (!amount)
17
+ throw new Error("[twzrd] x402 requirement missing amount");
18
+ return {
19
+ protocol: "x402",
20
+ network: req.network ?? "unknown",
21
+ asset: req.asset ?? "unknown",
22
+ amount,
23
+ payTo,
24
+ resource: {
25
+ url: req.resource ?? ctx?.resourceUrl,
26
+ method: ctx?.method,
27
+ },
28
+ facilitator: ctx?.facilitator,
29
+ agent: ctx?.agent,
30
+ context: ctx?.purpose ? { purpose: ctx.purpose } : undefined,
31
+ };
32
+ }
33
+ /** Cart -> canonical intent. The mandate rides along for the policy runtime. */
34
+ export function ap2CheckoutToIntent(cart, mandate, options) {
35
+ const intent = {
36
+ protocol: "ap2",
37
+ network: options?.network ?? "fiat:card",
38
+ asset: cart.currency,
39
+ amount: cart.total,
40
+ payTo: cart.payTo,
41
+ resource: {
42
+ url: cart.checkoutUrl,
43
+ operation: `checkout:${cart.merchantId}`,
44
+ },
45
+ agent: {
46
+ id: options?.agentId,
47
+ organization: options?.organization,
48
+ mandateId: mandate.mandateId,
49
+ },
50
+ context: {
51
+ purpose: cart.category,
52
+ recurring: cart.recurring,
53
+ priorSpend: cart.priorCharge,
54
+ },
55
+ };
56
+ const normalizedMandate = {
57
+ mandateId: mandate.mandateId,
58
+ purposes: mandate.categories,
59
+ maxPerTransactionUsd: mandate.maxPerTransaction,
60
+ monthlyCeilingUsd: mandate.monthlyCeiling,
61
+ resourceAllow: mandate.merchantAllowPrefixes,
62
+ expiresAt: mandate.expiresAt,
63
+ };
64
+ return { intent, mandate: normalizedMandate };
65
+ }
66
+ //# sourceMappingURL=intent-adapters.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"intent-adapters.js","sourceRoot":"","sources":["../src/intent-adapters.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAmBH,4EAA4E;AAC5E,MAAM,UAAU,wBAAwB,CACtC,GAA6B,EAC7B,GAAuB;IAEvB,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,MAAM,CAAC;IACtC,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,iBAAiB,CAAC;IACnD,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;IACtE,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;IACxE,OAAO;QACL,QAAQ,EAAE,MAAM;QAChB,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,SAAS;QACjC,KAAK,EAAE,GAAG,CAAC,KAAK,IAAI,SAAS;QAC7B,MAAM;QACN,KAAK;QACL,QAAQ,EAAE;YACR,GAAG,EAAE,GAAG,CAAC,QAAQ,IAAI,GAAG,EAAE,WAAW;YACrC,MAAM,EAAE,GAAG,EAAE,MAAM;SACpB;QACD,WAAW,EAAE,GAAG,EAAE,WAAW;QAC7B,KAAK,EAAE,GAAG,EAAE,KAAK;QACjB,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,SAAS;KAC7D,CAAC;AACJ,CAAC;AAkCD,gFAAgF;AAChF,MAAM,UAAU,mBAAmB,CACjC,IAAa,EACb,OAAuB,EACvB,OAAuE;IAEvE,MAAM,MAAM,GAAkB;QAC5B,QAAQ,EAAE,KAAK;QACf,OAAO,EAAE,OAAO,EAAE,OAAO,IAAI,WAAW;QACxC,KAAK,EAAE,IAAI,CAAC,QAAQ;QACpB,MAAM,EAAE,IAAI,CAAC,KAAK;QAClB,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,QAAQ,EAAE;YACR,GAAG,EAAE,IAAI,CAAC,WAAW;YACrB,SAAS,EAAE,YAAY,IAAI,CAAC,UAAU,EAAE;SACzC;QACD,KAAK,EAAE;YACL,EAAE,EAAE,OAAO,EAAE,OAAO;YACpB,YAAY,EAAE,OAAO,EAAE,YAAY;YACnC,SAAS,EAAE,OAAO,CAAC,SAAS;SAC7B;QACD,OAAO,EAAE;YACP,OAAO,EAAE,IAAI,CAAC,QAAQ;YACtB,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,UAAU,EAAE,IAAI,CAAC,WAAW;SAC7B;KACF,CAAC;IACF,MAAM,iBAAiB,GAAY;QACjC,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,QAAQ,EAAE,OAAO,CAAC,UAAU;QAC5B,oBAAoB,EAAE,OAAO,CAAC,iBAAiB;QAC/C,iBAAiB,EAAE,OAAO,CAAC,cAAc;QACzC,aAAa,EAAE,OAAO,CAAC,qBAAqB;QAC5C,SAAS,EAAE,OAAO,CAAC,SAAS;KAC7B,CAAC;IACF,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,EAAE,CAAC;AAChD,CAAC"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * TWZRD Payment Control — PaymentIntent v1 (FROZEN).
3
+ *
4
+ * The canonical, protocol-neutral description of one autonomous payment,
5
+ * evaluated exactly once at the last deterministic checkpoint before signing.
6
+ *
7
+ * Defining invariant (honest scope): a signer path that calls
8
+ * assertIntentApproved will not sign an intent that differs from what TWZRD
9
+ * evaluated. TWZRD does not own third-party wallets - the binding holds
10
+ * exactly where the check runs before the signer. Everything that
11
+ * identifies the transaction — payee, resource, amount, asset, network,
12
+ * facilitator, method, mandate, recurrence context — is bound into ONE
13
+ * canonical intent hash. `hash(intent being signed) === decision.intentHash`
14
+ * or the wallet refuses.
15
+ *
16
+ * v1 is frozen: field additions require a new hash prefix (tiv2:), never a
17
+ * silent change to canonicalization.
18
+ */
19
+ export type PaymentProtocol = "x402" | "ap2" | "ucp" | "mpp" | "direct";
20
+ export type PaymentIntent = {
21
+ protocol: PaymentProtocol;
22
+ /** CAIP-2 where applicable (e.g. "solana:5eykt4...", "eip155:8453"). */
23
+ network: string;
24
+ /** Asset identifier (mint / contract / ISO code for fiat-denominated mandates). */
25
+ asset: string;
26
+ /** Decimal string. Money is NEVER a float. */
27
+ amount: string;
28
+ /** Receiving counterparty (wallet, contract, merchant account). */
29
+ payTo: string;
30
+ resource?: {
31
+ url?: string;
32
+ method?: string;
33
+ operation?: string;
34
+ /** Hash of the exact request body when the resource is request-bound. */
35
+ requestHash?: string;
36
+ };
37
+ facilitator?: string;
38
+ agent?: {
39
+ id?: string;
40
+ organization?: string;
41
+ mandateId?: string;
42
+ };
43
+ context?: {
44
+ purpose?: string;
45
+ recurring?: boolean;
46
+ /** Prior charge for this recurring counterparty, decimal string. */
47
+ priorSpend?: string;
48
+ /** ISO-8601 expiry of the intent itself. */
49
+ expiresAt?: string;
50
+ };
51
+ };
52
+ export declare const INTENT_HASH_PREFIX = "tiv1:";
53
+ /**
54
+ * Canonical JSON (frozen with v1):
55
+ * - object keys sorted lexicographically (code-unit order)
56
+ * - `undefined` and `null` members omitted
57
+ * - arrays keep order; `undefined`/`null` elements are rejected
58
+ * - numbers must be finite (money fields are strings by type)
59
+ * - no insignificant whitespace
60
+ */
61
+ export declare function canonicalJson(value: unknown): string;
62
+ /** sha256 over the domain-separated canonical form, `tiv1:`-prefixed hex. */
63
+ export declare function intentHash(intent: PaymentIntent): string;
64
+ /**
65
+ * Parse a decimal money string into micro-units (6dp) as bigint.
66
+ * Rejects floats-by-stealth: only `[digits].[<=6 digits]` accepted.
67
+ */
68
+ export declare function toMicroUsd(amount: string): bigint;
69
+ //# sourceMappingURL=intent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"intent.d.ts","sourceRoot":"","sources":["../src/intent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,QAAQ,CAAC;AAExE,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,EAAE,eAAe,CAAC;IAC1B,wEAAwE;IACxE,OAAO,EAAE,MAAM,CAAC;IAChB,mFAAmF;IACnF,KAAK,EAAE,MAAM,CAAC;IACd,8CAA8C;IAC9C,MAAM,EAAE,MAAM,CAAC;IACf,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAC;IAEd,QAAQ,CAAC,EAAE;QACT,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,yEAAyE;QACzE,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IAEF,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,KAAK,CAAC,EAAE;QACN,EAAE,CAAC,EAAE,MAAM,CAAC;QACZ,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IAEF,OAAO,CAAC,EAAE;QACR,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,SAAS,CAAC,EAAE,OAAO,CAAC;QACpB,oEAAoE;QACpE,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,4CAA4C;QAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;CACH,CAAC;AAEF,eAAO,MAAM,kBAAkB,UAAU,CAAC;AAG1C;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAKpD;AA2BD,6EAA6E;AAC7E,wBAAgB,UAAU,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAOxD;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAMjD"}
package/dist/intent.js ADDED
@@ -0,0 +1,82 @@
1
+ /**
2
+ * TWZRD Payment Control — PaymentIntent v1 (FROZEN).
3
+ *
4
+ * The canonical, protocol-neutral description of one autonomous payment,
5
+ * evaluated exactly once at the last deterministic checkpoint before signing.
6
+ *
7
+ * Defining invariant (honest scope): a signer path that calls
8
+ * assertIntentApproved will not sign an intent that differs from what TWZRD
9
+ * evaluated. TWZRD does not own third-party wallets - the binding holds
10
+ * exactly where the check runs before the signer. Everything that
11
+ * identifies the transaction — payee, resource, amount, asset, network,
12
+ * facilitator, method, mandate, recurrence context — is bound into ONE
13
+ * canonical intent hash. `hash(intent being signed) === decision.intentHash`
14
+ * or the wallet refuses.
15
+ *
16
+ * v1 is frozen: field additions require a new hash prefix (tiv2:), never a
17
+ * silent change to canonicalization.
18
+ */
19
+ import { createHash } from "node:crypto";
20
+ export const INTENT_HASH_PREFIX = "tiv1:";
21
+ const INTENT_DOMAIN = "twzrd-intent-v1\n";
22
+ /**
23
+ * Canonical JSON (frozen with v1):
24
+ * - object keys sorted lexicographically (code-unit order)
25
+ * - `undefined` and `null` members omitted
26
+ * - arrays keep order; `undefined`/`null` elements are rejected
27
+ * - numbers must be finite (money fields are strings by type)
28
+ * - no insignificant whitespace
29
+ */
30
+ export function canonicalJson(value) {
31
+ if (value === null || value === undefined) {
32
+ throw new Error("[twzrd] canonicalJson: top-level null/undefined");
33
+ }
34
+ return serialize(value);
35
+ }
36
+ function serialize(value) {
37
+ if (value === null || value === undefined) {
38
+ throw new Error("[twzrd] canonicalJson: null/undefined array element");
39
+ }
40
+ const t = typeof value;
41
+ if (t === "string" || t === "boolean")
42
+ return JSON.stringify(value);
43
+ if (t === "number") {
44
+ if (!Number.isFinite(value)) {
45
+ throw new Error("[twzrd] canonicalJson: non-finite number");
46
+ }
47
+ return JSON.stringify(value);
48
+ }
49
+ if (Array.isArray(value)) {
50
+ return `[${value.map(serialize).join(",")}]`;
51
+ }
52
+ if (t === "object") {
53
+ const entries = Object.entries(value)
54
+ .filter(([, v]) => v !== undefined && v !== null)
55
+ .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
56
+ .map(([k, v]) => `${JSON.stringify(k)}:${serialize(v)}`);
57
+ return `{${entries.join(",")}}`;
58
+ }
59
+ throw new Error(`[twzrd] canonicalJson: unsupported type ${t}`);
60
+ }
61
+ /** sha256 over the domain-separated canonical form, `tiv1:`-prefixed hex. */
62
+ export function intentHash(intent) {
63
+ const canonical = canonicalJson(intent);
64
+ const digest = createHash("sha256")
65
+ .update(INTENT_DOMAIN)
66
+ .update(canonical)
67
+ .digest("hex");
68
+ return `${INTENT_HASH_PREFIX}${digest}`;
69
+ }
70
+ /**
71
+ * Parse a decimal money string into micro-units (6dp) as bigint.
72
+ * Rejects floats-by-stealth: only `[digits].[<=6 digits]` accepted.
73
+ */
74
+ export function toMicroUsd(amount) {
75
+ const m = /^(\d+)(?:\.(\d{1,6}))?$/.exec(amount.trim());
76
+ if (!m)
77
+ throw new Error(`[twzrd] bad decimal amount: ${JSON.stringify(amount)}`);
78
+ const whole = BigInt(m[1]);
79
+ const frac = BigInt((m[2] ?? "").padEnd(6, "0") || "0");
80
+ return whole * 1000000n + frac;
81
+ }
82
+ //# sourceMappingURL=intent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"intent.js","sourceRoot":"","sources":["../src/intent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * TWZRD Payment Control — the protocol-neutral policy runtime.
3
+ *
4
+ * `evaluateIntent(intent, { policy, mandate, intelligence })` combines:
5
+ * - LOCAL hard controls (ceilings, network/asset restrictions, allow/block
6
+ * lists, mandate validation, cumulative caps, recurring price checks) —
7
+ * deterministic, no network, keeps working through an API outage;
8
+ * - REMOTE intelligence (counterparty score, wash/fleet detection) via an
9
+ * injectable async provider;
10
+ * and returns a signed, expiring DecisionToken bound to the intent hash.
11
+ *
12
+ * Deliberately NOT a policy language. Five concrete policies, evaluated in a
13
+ * fixed order with stable reason codes.
14
+ */
15
+ import { type DecisionSigner, type PaymentDecision } from "./decision-token.js";
16
+ import { type PaymentIntent } from "./intent.js";
17
+ export declare const POLICY_VERSION = "twzrd-pc-v1";
18
+ export type SpendPolicy = {
19
+ /** Refuse wash-flagged counterparties (default true when intelligence runs). */
20
+ refuseWashFlagged?: boolean;
21
+ /** Unknown merchant: allow small spend, act above the line. */
22
+ unknownCounterparty?: {
23
+ allowUnderUsd: string;
24
+ aboveAction?: "block" | "warn";
25
+ };
26
+ /** New counterparty: cumulative cap over a rolling window. */
27
+ newCounterpartyCap?: {
28
+ capUsd: string;
29
+ windowHours: number;
30
+ };
31
+ /** Recurring service: block a price increase above this percentage. */
32
+ recurringMaxPriceIncreasePct?: number;
33
+ allowedNetworks?: string[];
34
+ allowedAssets?: string[];
35
+ maxAmountUsd?: string;
36
+ blocklist?: string[];
37
+ allowlist?: string[];
38
+ };
39
+ export type Mandate = {
40
+ mandateId: string;
41
+ /** Allowed spend purposes (e.g. ["software", "research_api"]). */
42
+ purposes?: string[];
43
+ maxPerTransactionUsd?: string;
44
+ monthlyCeilingUsd?: string;
45
+ /**
46
+ * Resource binding: URL prefixes this mandate may pay for.
47
+ * Approval for /weather cannot pay /admin/export.
48
+ */
49
+ resourceAllow?: string[];
50
+ /** Explicitly forbidden payees (e.g. personal wallets). */
51
+ payeeBlocklist?: string[];
52
+ expiresAt?: string;
53
+ };
54
+ /** What remote intelligence contributes. All fields optional; absent = unknown. */
55
+ export type CounterpartyIntelligence = {
56
+ known?: boolean;
57
+ washFlagged?: boolean;
58
+ decision?: "allow" | "warn" | "block";
59
+ trustScore?: number;
60
+ };
61
+ export type IntelligenceProvider = (intent: PaymentIntent) => Promise<CounterpartyIntelligence> | CounterpartyIntelligence;
62
+ export type SpendLedger = {
63
+ /** Total recorded spend (micro-USD) for a scope key within the window. */
64
+ spentMicro(scopeKey: string, windowMs: number, now: number): bigint;
65
+ record(scopeKey: string, amountMicro: bigint, at: number): void;
66
+ /** First time this scope key was seen, if ever. */
67
+ firstSeen(scopeKey: string): number | undefined;
68
+ };
69
+ export declare function createMemorySpendLedger(): SpendLedger;
70
+ export type EvaluateIntentOptions = {
71
+ policy?: SpendPolicy;
72
+ mandate?: Mandate;
73
+ intelligence?: IntelligenceProvider;
74
+ ledger?: SpendLedger;
75
+ signer: DecisionSigner;
76
+ /** Token time-to-live in ms (default 120s — decisions are point-in-time). */
77
+ ttlMs?: number;
78
+ now?: number;
79
+ /** Record allowed spend into the ledger (default true). */
80
+ recordSpend?: boolean;
81
+ };
82
+ /**
83
+ * Evaluate one PaymentIntent. Never throws on a policy outcome — a block is a
84
+ * signed block decision (auditable), not an exception. Throws only on
85
+ * malformed input (bad amounts) or signer failure.
86
+ */
87
+ export declare function evaluateIntent(intent: PaymentIntent, options: EvaluateIntentOptions): Promise<PaymentDecision>;
88
+ //# sourceMappingURL=policy-runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy-runtime.d.ts","sourceRoot":"","sources":["../src/policy-runtime.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,169 @@
1
+ /**
2
+ * TWZRD Payment Control — the protocol-neutral policy runtime.
3
+ *
4
+ * `evaluateIntent(intent, { policy, mandate, intelligence })` combines:
5
+ * - LOCAL hard controls (ceilings, network/asset restrictions, allow/block
6
+ * lists, mandate validation, cumulative caps, recurring price checks) —
7
+ * deterministic, no network, keeps working through an API outage;
8
+ * - REMOTE intelligence (counterparty score, wash/fleet detection) via an
9
+ * injectable async provider;
10
+ * and returns a signed, expiring DecisionToken bound to the intent hash.
11
+ *
12
+ * Deliberately NOT a policy language. Five concrete policies, evaluated in a
13
+ * fixed order with stable reason codes.
14
+ */
15
+ import { newDecisionId, signDecision, } from "./decision-token.js";
16
+ import { intentHash, toMicroUsd } from "./intent.js";
17
+ export const POLICY_VERSION = "twzrd-pc-v1";
18
+ export function createMemorySpendLedger() {
19
+ const entries = new Map();
20
+ const first = new Map();
21
+ return {
22
+ spentMicro(scopeKey, windowMs, now) {
23
+ const list = entries.get(scopeKey) ?? [];
24
+ let total = 0n;
25
+ for (const e of list)
26
+ if (now - e.at <= windowMs)
27
+ total += e.micro;
28
+ return total;
29
+ },
30
+ record(scopeKey, amountMicro, at) {
31
+ const list = entries.get(scopeKey) ?? [];
32
+ list.push({ at, micro: amountMicro });
33
+ entries.set(scopeKey, list);
34
+ if (!first.has(scopeKey))
35
+ first.set(scopeKey, at);
36
+ },
37
+ firstSeen(scopeKey) {
38
+ return first.get(scopeKey);
39
+ },
40
+ };
41
+ }
42
+ const MONTH_MS = 30 * 24 * 60 * 60 * 1000;
43
+ /**
44
+ * Evaluate one PaymentIntent. Never throws on a policy outcome — a block is a
45
+ * signed block decision (auditable), not an exception. Throws only on
46
+ * malformed input (bad amounts) or signer failure.
47
+ */
48
+ export async function evaluateIntent(intent, options) {
49
+ const now = options.now ?? Date.now();
50
+ const { policy, mandate } = options;
51
+ const amountMicro = toMicroUsd(intent.amount);
52
+ const reasons = [];
53
+ let blocked = false;
54
+ let warned = false;
55
+ const block = (code) => {
56
+ blocked = true;
57
+ reasons.push(code);
58
+ };
59
+ const warn = (code) => {
60
+ warned = true;
61
+ reasons.push(code);
62
+ };
63
+ /* 1. Mandate validation (local, deterministic) */
64
+ if (mandate) {
65
+ if (mandate.expiresAt && now >= Date.parse(mandate.expiresAt)) {
66
+ block("MANDATE_EXPIRED");
67
+ }
68
+ if (mandate.purposes && !mandate.purposes.includes(intent.context?.purpose ?? "")) {
69
+ block("MANDATE_PURPOSE");
70
+ }
71
+ if (mandate.resourceAllow) {
72
+ const url = intent.resource?.url ?? "";
73
+ if (!mandate.resourceAllow.some((prefix) => url.startsWith(prefix))) {
74
+ block("MANDATE_RESOURCE_SCOPE");
75
+ }
76
+ }
77
+ if (mandate.payeeBlocklist?.includes(intent.payTo)) {
78
+ block("MANDATE_PAYEE_BLOCKED");
79
+ }
80
+ if (mandate.maxPerTransactionUsd !== undefined &&
81
+ amountMicro > toMicroUsd(mandate.maxPerTransactionUsd)) {
82
+ block("MANDATE_MAX_PER_TX");
83
+ }
84
+ if (mandate.monthlyCeilingUsd !== undefined && options.ledger) {
85
+ const spent = options.ledger.spentMicro(`mandate:${mandate.mandateId}`, MONTH_MS, now);
86
+ if (spent + amountMicro > toMicroUsd(mandate.monthlyCeilingUsd)) {
87
+ block("MANDATE_MONTHLY_CEILING");
88
+ }
89
+ }
90
+ }
91
+ /* 2. Company policy — local hard controls */
92
+ if (policy) {
93
+ if (policy.blocklist?.includes(intent.payTo))
94
+ block("POLICY_BLOCKLIST");
95
+ if (policy.allowlist && !policy.allowlist.includes(intent.payTo)) {
96
+ block("POLICY_NOT_ALLOWLISTED");
97
+ }
98
+ if (policy.allowedNetworks && !policy.allowedNetworks.includes(intent.network)) {
99
+ block("POLICY_NETWORK");
100
+ }
101
+ if (policy.allowedAssets && !policy.allowedAssets.includes(intent.asset)) {
102
+ block("POLICY_ASSET");
103
+ }
104
+ if (policy.maxAmountUsd !== undefined && amountMicro > toMicroUsd(policy.maxAmountUsd)) {
105
+ block("POLICY_MAX_AMOUNT");
106
+ }
107
+ if (policy.recurringMaxPriceIncreasePct !== undefined &&
108
+ intent.context?.recurring &&
109
+ intent.context.priorSpend) {
110
+ const prior = toMicroUsd(intent.context.priorSpend);
111
+ const ceiling = prior + (prior * BigInt(Math.round(policy.recurringMaxPriceIncreasePct * 100))) / 10000n;
112
+ if (amountMicro > ceiling)
113
+ block("RECURRING_PRICE_INCREASE");
114
+ }
115
+ if (policy.newCounterpartyCap && options.ledger) {
116
+ const windowMs = policy.newCounterpartyCap.windowHours * 3_600_000;
117
+ const scope = `counterparty:${intent.payTo}`;
118
+ const seen = options.ledger.firstSeen(scope);
119
+ const isNew = seen === undefined || now - seen <= windowMs;
120
+ if (isNew) {
121
+ const spent = options.ledger.spentMicro(scope, windowMs, now);
122
+ if (spent + amountMicro > toMicroUsd(policy.newCounterpartyCap.capUsd)) {
123
+ block("NEW_COUNTERPARTY_CAP");
124
+ }
125
+ }
126
+ }
127
+ }
128
+ /* 3. Remote intelligence (skipped when already blocked locally) */
129
+ if (!blocked && options.intelligence) {
130
+ const intel = await options.intelligence(intent);
131
+ if (intel.washFlagged && policy?.refuseWashFlagged !== false) {
132
+ block("WASH_FLAGGED");
133
+ }
134
+ if (intel.decision === "block")
135
+ block("INTEL_BLOCK");
136
+ if (intel.decision === "warn")
137
+ warn("INTEL_WARN");
138
+ if (policy?.unknownCounterparty && intel.known === false) {
139
+ if (amountMicro <= toMicroUsd(policy.unknownCounterparty.allowUnderUsd)) {
140
+ warn("UNKNOWN_UNDER_LIMIT");
141
+ }
142
+ else if (policy.unknownCounterparty.aboveAction === "warn") {
143
+ warn("UNKNOWN_ABOVE_LIMIT");
144
+ }
145
+ else {
146
+ block("UNKNOWN_ABOVE_LIMIT");
147
+ }
148
+ }
149
+ }
150
+ const verdict = blocked ? "block" : warned ? "warn" : "allow";
151
+ if (verdict === "allow" && reasons.length === 0)
152
+ reasons.push("ALLOW");
153
+ /* 4. Record spend that will be permitted (feeds cumulative/monthly caps) */
154
+ if (!blocked && options.ledger && options.recordSpend !== false) {
155
+ options.ledger.record(`counterparty:${intent.payTo}`, amountMicro, now);
156
+ if (mandate)
157
+ options.ledger.record(`mandate:${mandate.mandateId}`, amountMicro, now);
158
+ }
159
+ /* 5. Signed, expiring token bound to the exact intent */
160
+ return signDecision({
161
+ decision: verdict,
162
+ reasonCodes: reasons,
163
+ intentHash: intentHash(intent),
164
+ policyVersion: POLICY_VERSION,
165
+ decisionId: newDecisionId(),
166
+ expiresAt: new Date(now + (options.ttlMs ?? 120_000)).toISOString(),
167
+ }, options.signer);
168
+ }
169
+ //# sourceMappingURL=policy-runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy-runtime.js","sourceRoot":"","sources":["../src/policy-runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EACL,aAAa,EACb,YAAY,GAIb,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,UAAU,EAAsB,MAAM,aAAa,CAAC;AAEzE,MAAM,CAAC,MAAM,cAAc,GAAG,aAAa,CAAC;AAoE5C,MAAM,UAAU,uBAAuB;IACrC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAgD,CAAC;IACxE,MAAM,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;IACxC,OAAO;QACL,UAAU,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG;YAChC,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;YACzC,IAAI,KAAK,GAAG,EAAE,CAAC;YACf,KAAK,MAAM,CAAC,IAAI,IAAI;gBAAE,IAAI,GAAG,GAAG,CAAC,CAAC,EAAE,IAAI,QAAQ;oBAAE,KAAK,IAAI,CAAC,CAAC,KAAK,CAAC;YACnE,OAAO,KAAK,CAAC;QACf,CAAC;QACD,MAAM,CAAC,QAAQ,EAAE,WAAW,EAAE,EAAE;YAC9B,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;YACzC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;YACtC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YAC5B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC;gBAAE,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QACpD,CAAC;QACD,SAAS,CAAC,QAAQ;YAChB,OAAO,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC7B,CAAC;KACF,CAAC;AACJ,CAAC;AAmBD,MAAM,QAAQ,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAE1C;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,MAAqB,EACrB,OAA8B;IAE9B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;IACtC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;IACpC,MAAM,WAAW,GAAG,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC9C,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,MAAM,KAAK,GAAG,CAAC,IAAY,EAAE,EAAE;QAC7B,OAAO,GAAG,IAAI,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACrB,CAAC,CAAC;IACF,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,EAAE;QAC5B,MAAM,GAAG,IAAI,CAAC;QACd,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACrB,CAAC,CAAC;IAEF,kDAAkD;IAClD,IAAI,OAAO,EAAE,CAAC;QACZ,IAAI,OAAO,CAAC,SAAS,IAAI,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;YAC9D,KAAK,CAAC,iBAAiB,CAAC,CAAC;QAC3B,CAAC;QACD,IAAI,OAAO,CAAC,QAAQ,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,IAAI,EAAE,CAAC,EAAE,CAAC;YAClF,KAAK,CAAC,iBAAiB,CAAC,CAAC;QAC3B,CAAC;QACD,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;YAC1B,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,EAAE,GAAG,IAAI,EAAE,CAAC;YACvC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;gBACpE,KAAK,CAAC,wBAAwB,CAAC,CAAC;YAClC,CAAC;QACH,CAAC;QACD,IAAI,OAAO,CAAC,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;YACnD,KAAK,CAAC,uBAAuB,CAAC,CAAC;QACjC,CAAC;QACD,IACE,OAAO,CAAC,oBAAoB,KAAK,SAAS;YAC1C,WAAW,GAAG,UAAU,CAAC,OAAO,CAAC,oBAAoB,CAAC,EACtD,CAAC;YACD,KAAK,CAAC,oBAAoB,CAAC,CAAC;QAC9B,CAAC;QACD,IAAI,OAAO,CAAC,iBAAiB,KAAK,SAAS,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YAC9D,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,WAAW,OAAO,CAAC,SAAS,EAAE,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAC;YACvF,IAAI,KAAK,GAAG,WAAW,GAAG,UAAU,CAAC,OAAO,CAAC,iBAAiB,CAAC,EAAE,CAAC;gBAChE,KAAK,CAAC,yBAAyB,CAAC,CAAC;YACnC,CAAC;QACH,CAAC;IACH,CAAC;IAED,6CAA6C;IAC7C,IAAI,MAAM,EAAE,CAAC;QACX,IAAI,MAAM,CAAC,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC;YAAE,KAAK,CAAC,kBAAkB,CAAC,CAAC;QACxE,IAAI,MAAM,CAAC,SAAS,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;YACjE,KAAK,CAAC,wBAAwB,CAAC,CAAC;QAClC,CAAC;QACD,IAAI,MAAM,CAAC,eAAe,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;YAC/E,KAAK,CAAC,gBAAgB,CAAC,CAAC;QAC1B,CAAC;QACD,IAAI,MAAM,CAAC,aAAa,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;YACzE,KAAK,CAAC,cAAc,CAAC,CAAC;QACxB,CAAC;QACD,IAAI,MAAM,CAAC,YAAY,KAAK,SAAS,IAAI,WAAW,GAAG,UAAU,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;YACvF,KAAK,CAAC,mBAAmB,CAAC,CAAC;QAC7B,CAAC;QACD,IACE,MAAM,CAAC,4BAA4B,KAAK,SAAS;YACjD,MAAM,CAAC,OAAO,EAAE,SAAS;YACzB,MAAM,CAAC,OAAO,CAAC,UAAU,EACzB,CAAC;YACD,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;YACpD,MAAM,OAAO,GACX,KAAK,GAAG,CAAC,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,4BAA4B,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,MAAO,CAAC;YAC5F,IAAI,WAAW,GAAG,OAAO;gBAAE,KAAK,CAAC,0BAA0B,CAAC,CAAC;QAC/D,CAAC;QACD,IAAI,MAAM,CAAC,kBAAkB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YAChD,MAAM,QAAQ,GAAG,MAAM,CAAC,kBAAkB,CAAC,WAAW,GAAG,SAAS,CAAC;YACnE,MAAM,KAAK,GAAG,gBAAgB,MAAM,CAAC,KAAK,EAAE,CAAC;YAC7C,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;YAC7C,MAAM,KAAK,GAAG,IAAI,KAAK,SAAS,IAAI,GAAG,GAAG,IAAI,IAAI,QAAQ,CAAC;YAC3D,IAAI,KAAK,EAAE,CAAC;gBACV,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAC;gBAC9D,IAAI,KAAK,GAAG,WAAW,GAAG,UAAU,CAAC,MAAM,CAAC,kBAAkB,CAAC,MAAM,CAAC,EAAE,CAAC;oBACvE,KAAK,CAAC,sBAAsB,CAAC,CAAC;gBAChC,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,mEAAmE;IACnE,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QACjD,IAAI,KAAK,CAAC,WAAW,IAAI,MAAM,EAAE,iBAAiB,KAAK,KAAK,EAAE,CAAC;YAC7D,KAAK,CAAC,cAAc,CAAC,CAAC;QACxB,CAAC;QACD,IAAI,KAAK,CAAC,QAAQ,KAAK,OAAO;YAAE,KAAK,CAAC,aAAa,CAAC,CAAC;QACrD,IAAI,KAAK,CAAC,QAAQ,KAAK,MAAM;YAAE,IAAI,CAAC,YAAY,CAAC,CAAC;QAClD,IAAI,MAAM,EAAE,mBAAmB,IAAI,KAAK,CAAC,KAAK,KAAK,KAAK,EAAE,CAAC;YACzD,IAAI,WAAW,IAAI,UAAU,CAAC,MAAM,CAAC,mBAAmB,CAAC,aAAa,CAAC,EAAE,CAAC;gBACxE,IAAI,CAAC,qBAAqB,CAAC,CAAC;YAC9B,CAAC;iBAAM,IAAI,MAAM,CAAC,mBAAmB,CAAC,WAAW,KAAK,MAAM,EAAE,CAAC;gBAC7D,IAAI,CAAC,qBAAqB,CAAC,CAAC;YAC9B,CAAC;iBAAM,CAAC;gBACN,KAAK,CAAC,qBAAqB,CAAC,CAAC;YAC/B,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,OAAO,GAA2B,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;IACtF,IAAI,OAAO,KAAK,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAEvE,4EAA4E;IAC5E,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,WAAW,KAAK,KAAK,EAAE,CAAC;QAChE,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,gBAAgB,MAAM,CAAC,KAAK,EAAE,EAAE,WAAW,EAAE,GAAG,CAAC,CAAC;QACxE,IAAI,OAAO;YAAE,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,WAAW,OAAO,CAAC,SAAS,EAAE,EAAE,WAAW,EAAE,GAAG,CAAC,CAAC;IACvF,CAAC;IAED,yDAAyD;IACzD,OAAO,YAAY,CACjB;QACE,QAAQ,EAAE,OAAO;QACjB,WAAW,EAAE,OAAO;QACpB,UAAU,EAAE,UAAU,CAAC,MAAM,CAAC;QAC9B,aAAa,EAAE,cAAc;QAC7B,UAAU,EAAE,aAAa,EAAE;QAC3B,SAAS,EAAE,IAAI,IAAI,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,CAAC,CAAC,WAAW,EAAE;KACpE,EACD,OAAO,CAAC,MAAM,CACf,CAAC;AACJ,CAAC"}
@@ -10,6 +10,9 @@
10
10
  * @see https://docs.x402.org/advanced-concepts/lifecycle-hooks
11
11
  */
12
12
  import type { TwzrdGateConfig } from "./types.js";
13
+ import { type Mandate, type SpendLedger, type SpendPolicy } from "./policy-runtime.js";
14
+ import type { DecisionSigner, PaymentDecision } from "./decision-token.js";
15
+ import type { PaymentIntent } from "./intent.js";
13
16
  /** Minimal shape of x402 payment requirements used by the hook. */
14
17
  export type X402SelectedRequirements = {
15
18
  payTo?: string;
@@ -43,7 +46,38 @@ export type BeforePaymentCreationResult = {
43
46
  export type X402ClientLike = {
44
47
  onBeforePaymentCreation: (hook: (context: BeforePaymentCreationContext) => Promise<BeforePaymentCreationResult> | BeforePaymentCreationResult) => X402ClientLike | void;
45
48
  };
49
+ /**
50
+ * Opt-in TWZRD Payment Control on the client hook. When set, the hook builds a
51
+ * canonical PaymentIntent from the selected requirement and runs the policy
52
+ * runtime — local mandate + company policy as deterministic hard controls, with
53
+ * the hook's own preflight fed in as remote intelligence — producing a signed,
54
+ * expiring PaymentDecision bound to the exact intent (surfaced on
55
+ * onDecision.decision). A downstream cooperating signer re-checks it with
56
+ * assertIntentApproved and refuses if the intent changed after approval.
57
+ *
58
+ * The decision can only TIGHTEN the legacy gate: a policy/mandate block aborts
59
+ * even when preflight allowed; it never loosens a legacy denial. Leaving
60
+ * paymentControl unset preserves the exact prior behavior.
61
+ */
62
+ export type X402PaymentControlOptions = {
63
+ /** Ed25519 decision signer (createLocalDecisionSigner() or a remote signer). */
64
+ signer: DecisionSigner;
65
+ policy?: SpendPolicy;
66
+ mandate?: Mandate;
67
+ ledger?: SpendLedger;
68
+ /** Token time-to-live in ms (default 120s). */
69
+ ttlMs?: number;
70
+ /** Spend purpose bound into the intent (matched against mandate.purposes). */
71
+ purpose?: string;
72
+ facilitator?: string;
73
+ /** Resource method bound into the intent (GET/POST/…). */
74
+ method?: string;
75
+ };
46
76
  export type InstallX402ClientHookOptions = TwzrdGateConfig & {
77
+ /** Opt-in Payment Control: signed intent-bound decisions + local policy/mandate. */
78
+ paymentControl?: X402PaymentControlOptions;
79
+ /** Clock for decision issue time, Unix ms. Injectable for tests. Default Date.now. */
80
+ now?: () => number;
47
81
  /**
48
82
  * Optional callback after each policy decision (telemetry / logging).
49
83
  * Never throws into the payment path.
@@ -57,6 +91,10 @@ export type InstallX402ClientHookOptions = TwzrdGateConfig & {
57
91
  amountMicro?: string;
58
92
  reputationScored?: boolean;
59
93
  policyAction?: string;
94
+ /** Canonical evaluated intent (present when paymentControl is set). */
95
+ intent?: PaymentIntent;
96
+ /** Signed, intent-bound decision (present when paymentControl is set). */
97
+ decision?: PaymentDecision;
60
98
  }) => void;
61
99
  };
62
100
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"x402-client-hook.d.ts","sourceRoot":"","sources":["../src/x402-client-hook.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,mEAAmE;AACnE,MAAM,MAAM,wBAAwB,GAAG;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,4BAA4B,GAAG;IACzC,oBAAoB,EAAE,wBAAwB,CAAC;IAC/C,uDAAuD;IACvD,YAAY,CAAC,EAAE,wBAAwB,CAAC;CACzC,CAAC;AAEF,MAAM,MAAM,2BAA2B,GACnC;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC/B;IAAE,KAAK,CAAC,EAAE,KAAK,CAAA;CAAE,GACjB,IAAI,CAAC;AAET;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,uBAAuB,EAAE,CACvB,IAAI,EAAE,CACJ,OAAO,EAAE,4BAA4B,KAClC,OAAO,CAAC,2BAA2B,CAAC,GAAG,2BAA2B,KACpE,cAAc,GAAG,IAAI,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG,eAAe,GAAG;IAC3D;;;OAGG;IACH,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE;QACpB,QAAQ,EAAE,OAAO,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,gBAAgB,CAAC,EAAE,OAAO,CAAC;QAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,KAAK,IAAI,CAAC;CACZ,CAAC;AAMF;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,cAAc,EACtB,OAAO,CAAC,EAAE,4BAA4B,GACrC,cAAc,CA8ChB;AAED;;;;GAIG;AACH,wBAAsB,0BAA0B,CAC9C,oBAAoB,EAAE,wBAAwB,EAC9C,OAAO,CAAC,EAAE,4BAA4B,GACrC,OAAO,CAAC,2BAA2B,CAAC,CAyBtC"}
1
+ {"version":3,"file":"x402-client-hook.d.ts","sourceRoot":"","sources":["../src/x402-client-hook.ts"],"names":[],"mappings":"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"}
@@ -12,9 +12,33 @@
12
12
  import { resolveConfig } from "./config.js";
13
13
  import { priceUsdcFromAmountMicro } from "./payto.js";
14
14
  import { twzrdApprovePayment } from "./policy.js";
15
+ import { x402RequirementsToIntent } from "./intent-adapters.js";
16
+ import { evaluateIntent } from "./policy-runtime.js";
15
17
  function pickReq(ctx) {
16
18
  return ctx.selectedRequirements ?? ctx.requirements ?? {};
17
19
  }
20
+ /**
21
+ * x402 wire amounts are integer base units (USDC = 6-decimal micro), but
22
+ * PaymentIntent.amount is a DECIMAL USD string (the policy runtime runs it
23
+ * through toMicroUsd). Convert precisely with bigint so amount-based policies
24
+ * are not mis-scaled by 1e6. USDC 6dp matches the gate's existing
25
+ * priceUsdcFromAmountMicro assumption.
26
+ *
27
+ * NOTE: `x402RequirementsToIntent` itself still passes the raw wire amount
28
+ * through into the decimal field — a latent unit bug when that adapter feeds
29
+ * evaluateIntent directly. Corrected here at the hook boundary; the adapter
30
+ * fix belongs in a follow-up (it changes a merged test contract).
31
+ */
32
+ function microToDecimalUsd(micro, decimals = 6) {
33
+ const m = /^\d+$/.exec(micro.trim());
34
+ if (!m)
35
+ return micro; // non-integer wire amount: leave as-is, let toMicroUsd validate
36
+ const scale = 10n ** BigInt(decimals);
37
+ const value = BigInt(micro.trim());
38
+ const whole = value / scale;
39
+ const frac = (value % scale).toString().padStart(decimals, "0").replace(/0+$/, "");
40
+ return frac ? `${whole}.${frac}` : `${whole}`;
41
+ }
18
42
  /**
19
43
  * Install TWZRD as the default onBeforePaymentCreation policy engine.
20
44
  *
@@ -48,6 +72,40 @@ export function installTwzrdX402ClientHook(client, options) {
48
72
  agentIntent: "x402_onBeforePaymentCreation",
49
73
  chain: network,
50
74
  }, cfg);
75
+ // Opt-in Payment Control: build the canonical intent and run the policy
76
+ // runtime, feeding the preflight result in as remote intelligence. Skipped
77
+ // when payTo/amount are missing — the legacy gate already denies those.
78
+ let intent;
79
+ let decision;
80
+ if (options?.paymentControl && payTo && amountMicro) {
81
+ const pc = options.paymentControl;
82
+ const rawIntent = x402RequirementsToIntent(req, {
83
+ resourceUrl: req.resource,
84
+ method: pc.method,
85
+ facilitator: pc.facilitator,
86
+ purpose: pc.purpose,
87
+ });
88
+ // Correct the wire micro-amount into the decimal USD the runtime expects.
89
+ intent = { ...rawIntent, amount: microToDecimalUsd(amountMicro) };
90
+ decision = await evaluateIntent(intent, {
91
+ signer: pc.signer,
92
+ policy: pc.policy,
93
+ mandate: pc.mandate,
94
+ ledger: pc.ledger,
95
+ ttlMs: pc.ttlMs,
96
+ now: options.now?.(),
97
+ intelligence: () => ({
98
+ known: approval.reputationScored ? true : undefined,
99
+ washFlagged: approval.washFlagged ?? undefined,
100
+ decision: approval.verdict === "allow" ||
101
+ approval.verdict === "warn" ||
102
+ approval.verdict === "block"
103
+ ? approval.verdict
104
+ : undefined,
105
+ trustScore: approval.score ?? undefined,
106
+ }),
107
+ });
108
+ }
51
109
  try {
52
110
  options?.onDecision?.({
53
111
  approved: approval.approved,
@@ -58,16 +116,21 @@ export function installTwzrdX402ClientHook(client, options) {
58
116
  amountMicro,
59
117
  reputationScored: approval.reputationScored,
60
118
  policyAction: approval.policyAction,
119
+ intent,
120
+ decision,
61
121
  });
62
122
  }
63
123
  catch {
64
124
  // never break payment path on telemetry
65
125
  }
66
- if (!approval.approved) {
67
- return {
68
- abort: true,
69
- reason: `[twzrd] ${approval.reason} payTo=${payTo ?? "unknown"} network=${network ?? "unknown"}`,
70
- };
126
+ // Payment Control can only TIGHTEN: abort if the legacy gate denied OR the
127
+ // signed decision blocks. Never loosen a legacy denial.
128
+ const pcBlocks = decision?.decision === "block";
129
+ if (!approval.approved || pcBlocks) {
130
+ const reason = pcBlocks && approval.approved
131
+ ? `[twzrd] payment_control_block:${decision?.reasonCodes.join(",")} payTo=${payTo ?? "unknown"}`
132
+ : `[twzrd] ${approval.reason} payTo=${payTo ?? "unknown"} network=${network ?? "unknown"}`;
133
+ return { abort: true, reason };
71
134
  }
72
135
  // void / undefined → proceed to payment payload creation (same selectedRequirements)
73
136
  });
@@ -1 +1 @@
1
- {"version":3,"file":"x402-client-hook.js","sourceRoot":"","sources":["../src/x402-client-hook.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"x402-client-hook.js","sourceRoot":"","sources":["../src/x402-client-hook.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "twzrd-x402-gate",
3
- "version": "0.5.4",
4
- "description": "Buyer-side x402 trust gate. Run a free TWZRD preflight (ReadinessCard) before signing USDC to any x402 merchant, and autonomously escalate a `warn` to a $0.001 paid trust check that re-decides blocking the spend on bad paid intel, no human in the loop. Default refuse when free merchant_card.wash_flagged (opt out TWZRD_REFUSE_WASH_FLAGGED=0). A 402 with no extractable payTo fails closed (twzrd_unidentifiable_payment_recipient) instead of falling through to the generic unknown-seller warn. Wraps fetch (HTTP 402) and the @x402/mcp onPaymentRequested hook fixed in 0.5.2 to read the real @x402/mcp v2 nested `paymentRequired.accepts` shape (verified against @x402/mcp@2.17.0; previously only the flat legacy shape was read, causing a silent 100%-false-block once wired into a real runtime). installTwzrdAutoGate(payWrap) is the default-on one-liner: guards the raw fetch, then hands it to your x402 client, so the correct guard-before-pay composition can't be built backwards. BREAKING(0.2.0): fail-closed by default set TWZRD_FAIL_OPEN=true to restore legacy allow-on-outage behavior.",
3
+ "version": "0.6.0",
4
+ "description": "Buyer-side x402 trust gate. Run a free TWZRD preflight (ReadinessCard) before signing USDC to any x402 merchant, and autonomously escalate a `warn` to a $0.001 paid trust check that re-decides \u2014 blocking the spend on bad paid intel, no human in the loop. Default refuse when free merchant_card.wash_flagged (opt out TWZRD_REFUSE_WASH_FLAGGED=0). A 402 with no extractable payTo fails closed (twzrd_unidentifiable_payment_recipient) instead of falling through to the generic unknown-seller warn. Wraps fetch (HTTP 402) and the @x402/mcp onPaymentRequested hook \u2014 fixed in 0.5.2 to read the real @x402/mcp v2 nested `paymentRequired.accepts` shape (verified against @x402/mcp@2.17.0; previously only the flat legacy shape was read, causing a silent 100%-false-block once wired into a real runtime). installTwzrdAutoGate(payWrap) is the default-on one-liner: guards the raw fetch, then hands it to your x402 client, so the correct guard-before-pay composition can't be built backwards. BREAKING(0.2.0): fail-closed by default \u2014 set TWZRD_FAIL_OPEN=true to restore legacy allow-on-outage behavior.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
@@ -27,7 +27,7 @@
27
27
  "build": "tsc",
28
28
  "prepublishOnly": "tsc",
29
29
  "typecheck": "tsc --noEmit",
30
- "test": "tsx test/policy.test.ts && tsx test/wrap-fetch.test.ts && tsx test/mcp-hook.test.ts && tsx test/attribution.test.ts && tsx test/auto-receipt.test.ts && tsx test/quick.test.ts && tsx test/sponsored.test.ts && tsx test/escalation.test.ts && tsx test/wash-refuse.test.ts && tsx test/auto-gate.test.ts && tsx test/network.test.ts && tsx test/safe-fetch.test.ts && tsx test/challenge-swap.test.ts && tsx test/x402-client-hook.test.ts && tsx test/run-attribution.test.ts",
30
+ "test": "tsx test/policy.test.ts && tsx test/wrap-fetch.test.ts && tsx test/mcp-hook.test.ts && tsx test/attribution.test.ts && tsx test/auto-receipt.test.ts && tsx test/quick.test.ts && tsx test/sponsored.test.ts && tsx test/escalation.test.ts && tsx test/wash-refuse.test.ts && tsx test/auto-gate.test.ts && tsx test/network.test.ts && tsx test/safe-fetch.test.ts && tsx test/challenge-swap.test.ts && tsx test/x402-client-hook.test.ts && tsx test/run-attribution.test.ts && tsx test/payment-control.test.ts && tsx test/intent-binding.test.ts",
31
31
  "safe-fetch": "tsx src/safe-fetch.ts",
32
32
  "guard-demo": "tsx examples/agentic-market-gate.ts",
33
33
  "autoreceipt-demo": "tsx examples/auto-receipt.ts --dry-run",
@@ -69,11 +69,21 @@
69
69
  "@x402/svm": ">=2.0.0"
70
70
  },
71
71
  "peerDependenciesMeta": {
72
- "@scure/base": { "optional": true },
73
- "@solana/kit": { "optional": true },
74
- "@x402/core": { "optional": true },
75
- "@x402/fetch": { "optional": true },
76
- "@x402/svm": { "optional": true }
72
+ "@scure/base": {
73
+ "optional": true
74
+ },
75
+ "@solana/kit": {
76
+ "optional": true
77
+ },
78
+ "@x402/core": {
79
+ "optional": true
80
+ },
81
+ "@x402/fetch": {
82
+ "optional": true
83
+ },
84
+ "@x402/svm": {
85
+ "optional": true
86
+ }
77
87
  },
78
88
  "devDependencies": {
79
89
  "@scure/base": "^1.2.0",