twzrd-x402-gate 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +207 -47
  2. package/dist/config.d.ts +2 -1
  3. package/dist/config.d.ts.map +1 -1
  4. package/dist/config.js +16 -6
  5. package/dist/config.js.map +1 -1
  6. package/dist/evaluate.d.ts +77 -0
  7. package/dist/evaluate.d.ts.map +1 -0
  8. package/dist/evaluate.js +114 -0
  9. package/dist/evaluate.js.map +1 -0
  10. package/dist/gate.d.ts +13 -0
  11. package/dist/gate.d.ts.map +1 -1
  12. package/dist/gate.js +22 -0
  13. package/dist/gate.js.map +1 -1
  14. package/dist/index.d.ts +6 -2
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +9 -1
  17. package/dist/index.js.map +1 -1
  18. package/dist/mcp-hook.d.ts.map +1 -1
  19. package/dist/mcp-hook.js +27 -18
  20. package/dist/mcp-hook.js.map +1 -1
  21. package/dist/payto.d.ts +6 -0
  22. package/dist/payto.d.ts.map +1 -1
  23. package/dist/payto.js +17 -0
  24. package/dist/payto.js.map +1 -1
  25. package/dist/policy.d.ts +1 -1
  26. package/dist/policy.d.ts.map +1 -1
  27. package/dist/policy.js +46 -7
  28. package/dist/policy.js.map +1 -1
  29. package/dist/quick.d.ts +48 -0
  30. package/dist/quick.d.ts.map +1 -0
  31. package/dist/quick.js +49 -0
  32. package/dist/quick.js.map +1 -0
  33. package/dist/sponsored.d.ts +51 -0
  34. package/dist/sponsored.d.ts.map +1 -0
  35. package/dist/sponsored.js +55 -0
  36. package/dist/sponsored.js.map +1 -0
  37. package/dist/types.d.ts +37 -0
  38. package/dist/types.d.ts.map +1 -1
  39. package/dist/with-guard.d.ts +23 -0
  40. package/dist/with-guard.d.ts.map +1 -0
  41. package/dist/with-guard.js +72 -0
  42. package/dist/with-guard.js.map +1 -0
  43. package/dist/wrap-fetch.js +2 -2
  44. package/dist/wrap-fetch.js.map +1 -1
  45. package/package.json +6 -3
package/README.md CHANGED
@@ -1,17 +1,14 @@
1
1
  # twzrd-x402-gate
2
2
 
3
- Buyer-side x402 **trust gate**. Run a free [TWZRD preflight](https://intel.twzrd.xyz) (`ReadinessCard`)
4
- **before** signing USDC to any x402 merchant. Wraps `fetch` (HTTP 402) and the `@x402/mcp`
5
- `onPaymentRequested` hook. Fail-open by default so an unreachable preflight never hard-blocks a payment.
3
+ Agent-side x402 **firewall**. TWZRD sits in the path before any 402 payment leaves your
4
+ agent's wallet free preflight decides `allow / warn / block` before USDC moves.
6
5
 
7
- This is the independent **pre-spend** layer — it does not settle, route, or hold funds. It works where
8
- your code receives an exposed 402 (e.g. direct `@x402/fetch` or raw merchant calls).
6
+ ```typescript
7
+ import { withTwzrdGuard } from "twzrd-x402-gate";
9
8
 
10
- **ClawRouter / `@blockrun/clawrouter` note:** The local :8402 proxy signs internally and returns 200 (no
11
- outer 402 is visible). Use the pre-proxy hook from the `twzrd-clawrouter` skill (explicit call before the
12
- proxy) or an upstream `onBeforePayment` if ClawRouter exposes one. Same internalization applies to
13
- AgentCash's `fetch` (it handles 402 internally) — verify before assuming a wrapper sees it. The MCP
14
- `onPaymentRequested` hook covers clients that expose a payment callback.
9
+ const safeFetch = withTwzrdGuard(myX402Fetch);
10
+ // Every 402 intercepted free TWZRD preflight throws on block, proceeds on warn/allow.
11
+ ```
15
12
 
16
13
  ## Install
17
14
 
@@ -19,34 +16,167 @@ AgentCash's `fetch` (it handles 402 internally) — verify before assuming a wra
19
16
  npm install twzrd-x402-gate
20
17
  ```
21
18
 
22
- ## Usage
19
+ ## Quickstart: `withTwzrdGuard`
23
20
 
24
- ### Wrap any fetch that may receive a 402
21
+ Wrap any fetch that will receive x402 responses. The guard intercepts every HTTP 402, runs a
22
+ free TWZRD preflight on the seller wallet, and throws `[twzrd] blocked: ...` before your
23
+ wallet signs anything.
25
24
 
26
- ```ts
27
- import { wrapFetchWithTwzrdGate, resolveConfig } from "twzrd-x402-gate";
25
+ ```typescript
26
+ import { withTwzrdGuard } from "twzrd-x402-gate";
27
+ import { createAgentcashFetch } from "agentcash";
28
28
 
29
- const gatedFetch = wrapFetchWithTwzrdGate(fetch, resolveConfig());
29
+ // Pass the x402-capable fetch IN — the guard sits upstream of it.
30
+ const x402Fetch = createAgentcashFetch({ apiKey: process.env.AGENTCASH_API_KEY });
31
+ const safeFetch = withTwzrdGuard(x402Fetch);
30
32
 
31
- // On HTTP 402, the gate reads payTo from the x402 `accepts[0]`, runs preflight,
32
- // and THROWS if policy denies. On allow it returns the original 402 so your
33
- // x402 client attaches payment and retries as usual.
34
- const res = await gatedFetch("https://merchant.example/paid");
33
+ // Use safeFetch everywhere you'd call a paid resource:
34
+ const response = await safeFetch("https://api.exa.ai/search");
35
35
  ```
36
36
 
37
- ### As the @x402/mcp payment hook
37
+ What the guard does on HTTP 402:
38
+ 1. Reads the Solana-network entry from `accepts[]` (falls back to first entry) to get the seller wallet.
39
+ 2. Calls `POST /v1/intel/preflight` — free, no auth.
40
+ 3. `decision=block` - throws `[twzrd] blocked: ...`.
41
+ 4. `decision=warn` or `allow` - returns the original 402 for the x402 client to pay.
38
42
 
39
- ```ts
40
- import { defaultGate } from "twzrd-x402-gate";
43
+ Non-402 responses pass through unchanged.
41
44
 
42
- const client = createX402MCPClient({
43
- onPaymentRequested: defaultGate.onPaymentRequested, // returns false to deny
45
+ ### Auto-receipt on warn (revenue path)
46
+
47
+ ```typescript
48
+ const safeFetch = withTwzrdGuard(x402Fetch, {
49
+ autoReceipt: true, // on warn or allow, auto-buy the $0.05 TWZRD trust receipt
50
+ x402Fetch, // the paying fetch — TWZRD earns the fee on-chain
51
+ onReceipt: (receipt, tx) => {
52
+ // receipt is a twzrd_receipt (V6 + ERC-8004 reputation_credential)
53
+ console.log("Trust receipt captured:", tx);
54
+ },
44
55
  });
45
56
  ```
46
57
 
47
- ### Direct decision (no network wiring)
58
+ `autoReceipt` is **off by default** — it spends the **buyer's** USDC, so you opt in. When on,
59
+ every warn/allow verdict settles $0.05 USDC to TWZRD and returns a signed V6 trust credential
60
+ for the counterparty before you pay the resource.
61
+
62
+ **`x402Fetch` is yours to supply** (this package is dependency-free). Wire the proven
63
+ `@x402/svm` sponsored-feePayer client — the same one `twzrd-mcp-server` uses:
64
+
65
+ ```typescript
66
+ import { wrapFetchWithPayment } from "@x402/svm";
67
+ const x402Fetch = wrapFetchWithPayment(fetch, buyerWallet); // settles 402 challenges
68
+ ```
69
+
70
+ Gate it behind your own ROI policy (e.g. only auto-buy the receipt for payments above a
71
+ threshold). Runnable, no-spend demo: [`examples/auto-receipt.ts`](./examples/auto-receipt.ts)
72
+ (`npm run autoreceipt-demo`). A bundled/sponsored `x402Fetch` (so integrators need no wallet)
73
+ is the next step.
74
+
75
+ ### Quick tier ($0.001) — cheap paid qualify
76
+
77
+ The reputation ladder has three rungs: **free** preflight (`allow/warn/block`), **$0.001**
78
+ `quickCheck` (tier + score, no receipt), **$0.05** `autoReceipt` (full intel + signed V6
79
+ receipt). When the free preflight is inconclusive (`warn` / unknown seller) and you want a
80
+ cheap *paid* confirmation before committing — without paying 50× for the portable receipt —
81
+ use `quickCheck`:
82
+
83
+ ```typescript
84
+ import { quickCheck } from "twzrd-x402-gate";
85
+
86
+ const q = await quickCheck(sellerWallet, { x402Fetch }); // settles $0.001 to /v1/intel/quick
87
+ if (q.available && (q.tier === "Gold" || q.tier === "Platinum")) {
88
+ // tier is high enough — proceed with the larger payment
89
+ }
90
+ ```
91
+
92
+ `quickCheck` is **fail-soft** — it never throws; any gap (no `x402Fetch`, unreachable, settle
93
+ failure) returns `available: false`, so a quick-tier hiccup can't break your flow. The hard
94
+ allow/warn/block decision stays the free preflight's job.
95
+
96
+ ### Autonomous risk-escalation — `escalateOnWarn` (pay-to-confirm on warn)
97
+
98
+ The free preflight leaves an unknown/uncertain seller at `warn`, which **proceeds** by
99
+ default. `escalateOnWarn` closes the loop autonomously: on a proceeding `warn`, the guard
100
+ settles the cheap **$0.001** quick tier and **re-decides on the paid score** — below the
101
+ floor the payment is **blocked**, at/above it proceeds. The paid call fires from your
102
+ agent's own risk policy (no human), and the paid signal actually gates the spend (unlike
103
+ `autoReceipt`, which is upsell-only and never changes the decision).
48
104
 
49
105
  ```ts
106
+ const safeFetch = withTwzrdGuard(x402Fetch, {
107
+ escalateOnWarn: {
108
+ minSpendUsdc: 0.01, // don't pay $0.001 to vet a sub-cent buy
109
+ blockBelowScore: 40, // block when the paid quick score is below this (default: preflightMinScore)
110
+ },
111
+ x402Fetch, // settles the $0.001 quick charge
112
+ });
113
+ // warn + paid score < 40 -> throws "[twzrd-guard] payment blocked: twzrd_escalated_warn_block ..."
114
+ // warn + paid score >= 40 -> proceeds (result.escalated=true, result.escalatedScore set)
115
+ ```
116
+
117
+ Opt-in, **fail-soft** (if the quick tier can't answer, the base `warn` is preserved), and it
118
+ **only tightens** — a `warn` may become a block, but an `allow` or `block` is never changed.
119
+ This is the autonomous demand loop: an uncertain counterparty is vetted with real paid intel,
120
+ automatically, before your agent commits.
121
+
122
+ ### Sponsored payer — use the paid rungs with no wallet (prototype)
123
+
124
+ `createSponsoredX402Fetch` lets a **sponsor** settle the paid rungs on the agent's behalf, so
125
+ an integrator can call `quickCheck` / `autoReceipt` with **no wallet of their own**:
126
+
127
+ ```typescript
128
+ import { createSponsoredX402Fetch, quickCheck } from "twzrd-x402-gate";
129
+
130
+ // `settle` = the funded backend (your @x402/svm fetch, or a TWZRD treasury sponsor endpoint).
131
+ const x402Fetch = createSponsoredX402Fetch({ settle });
132
+ const q = await quickCheck(seller, { x402Fetch }); // sponsor pays — caller holds no wallet
133
+ ```
134
+
135
+ Two backends plug into `settle`: **gas-sponsored** (live via `@x402/svm` — agent pays USDC, the
136
+ resource server's `feePayer` covers SOL gas, the model `twzrd-mcp-server` uses) and
137
+ **full-sponsor** (a TWZRD treasury endpoint pays on the agent's behalf — the true no-wallet
138
+ path). The full-sponsor endpoint + treasury is **founder-gated** (who funds it + per-agent
139
+ budget caps); this ships the client seam + a dry-run so the wiring is ready.
140
+ No-spend demo: [`examples/sponsored-payer.ts`](./examples/sponsored-payer.ts) (`npm run sponsored-demo`).
141
+
142
+ ## `evaluate_x402_resource` — standalone preflight
143
+
144
+ Use when you already have the `paymentRequirements` object from a parsed 402 body:
145
+
146
+ ```typescript
147
+ import { evaluate_x402_resource } from "twzrd-x402-gate";
148
+
149
+ const result = await evaluate_x402_resource(
150
+ "https://api.exa.ai/search",
151
+ paymentRequirements, // X402PaymentRequirements from the 402 body
152
+ );
153
+
154
+ console.log(result.decision); // "allow" | "warn" | "block"
155
+ console.log(result.trustScore); // number | null
156
+ console.log(result.approved); // boolean
157
+ console.log(result.receiptUrl); // "https://intel.twzrd.xyz/v1/intel/trust/<payTo>"
158
+
159
+ if (!result.approved) throw new Error(`Blocked: ${result.reason}`);
160
+ ```
161
+
162
+ With `autoReceipt`:
163
+
164
+ ```typescript
165
+ const result = await evaluate_x402_resource(url, requirements, {
166
+ autoReceipt: true,
167
+ x402Fetch: myPayingFetch,
168
+ onReceipt: (receipt, tx) => storeCredential(receipt),
169
+ });
170
+ // result.receipt — twzrd_receipt (V6 + ERC-8004 reputation_credential)
171
+ // result.receiptTx — on-chain settlement tx
172
+ // result.receiptFeeCaptured — true when fee landed
173
+ ```
174
+
175
+ ## Lower-level APIs
176
+
177
+ ### Direct approval call
178
+
179
+ ```typescript
50
180
  import { createTwzrdGate } from "twzrd-x402-gate";
51
181
 
52
182
  const gate = createTwzrdGate();
@@ -58,38 +188,68 @@ const { approved, reason, card } = await gate.approvePayment({
58
188
  if (!approved) abort(reason);
59
189
  ```
60
190
 
191
+ ### `@x402/mcp` payment hook
192
+
193
+ ```typescript
194
+ import { defaultGate } from "twzrd-x402-gate";
195
+
196
+ const client = createX402MCPClient({
197
+ onPaymentRequested: defaultGate.onPaymentRequested, // returns false to deny
198
+ });
199
+ ```
200
+
201
+ ### `wrapFetchWithTwzrdGate`
202
+
203
+ ```typescript
204
+ import { wrapFetchWithTwzrdGate, resolveConfig } from "twzrd-x402-gate";
205
+
206
+ // Alternative fetch wrapper — same interception logic, no autoReceipt.
207
+ const gatedFetch = wrapFetchWithTwzrdGate(fetch, resolveConfig());
208
+ ```
209
+
210
+ `withTwzrdGuard` is preferred — it composes with `autoReceipt` and `onReceipt`.
211
+ `wrapFetchWithTwzrdGate` remains for codebases that can't migrate.
212
+
61
213
  ## Policy
62
214
 
63
- A payment is **denied** when any of these hold (mirrors `scripts/twzrd_gate_agentcash_fetch.sh`):
215
+ A payment is **blocked** when:
216
+ 1. `decision ∈ blockDecisions` (default: `["block"]`)
217
+ 2. `trust_score < preflightMinScore` (default: `40`)
218
+ 3. `can_spend === false` — **only** when `gateOnCanSpend: true` (default `false`, opt-in)
219
+
220
+ `warn` is allowed unless overridden. Preflight network failure **fails closed** by default (a preflight outage blocks the payment, so an intel hiccup never silently approves a spend); set `failOpen: true` / `TWZRD_FAIL_OPEN=true` to opt into legacy allow-on-outage.
64
221
 
65
- 1. `decision blockDecisions` (default: `block`)
66
- 2. `can_spend === false` **only when `gateOnCanSpend` is true (default)**
67
- 3. `trust_score < preflightMinScore` (default: `40`)
222
+ > **`can_spend` note:** the free preflight returns `can_spend=false` for most sellers
223
+ > not yet in the TWZRD corpus, including legitimate ones. The default is decision-only
224
+ > gating so unknown sellers on platforms like Agentic.Market are not blocked by default.
225
+ > Set `gateOnCanSpend: true` for strict mode.
68
226
 
69
- Otherwise approved (`warn` is allowed with reason `twzrd_warn_allowed`). On preflight HTTP/network
70
- failure the gate **fails open** (approves) unless `failOpen` is disabled.
227
+ ## Config
71
228
 
72
- > **ClawRouter / free-tier note:** the free preflight returns `can_spend=false` for most sellers
73
- > (including well-known ones), so the default policy will deny most unknown ClawRouter/BlockRun
74
- > sellers. To follow the "gate only on `decision=block`" policy documented in the `twzrd-clawrouter`
75
- > skill, set `gateOnCanSpend: false` (or `TWZRD_GATE_ON_CAN_SPEND=false`).
229
+ | Option | Env | Default | Description |
230
+ |---|---|---|---|
231
+ | `intelBase` | `TWZRD_INTEL_BASE` | `https://intel.twzrd.xyz` | Preflight API base |
232
+ | `preflightMinScore` | `TWZRD_PREFLIGHT_MIN_SCORE` | `40` | Block below this score |
233
+ | `blockDecisions` | `TWZRD_BLOCK_DECISIONS` | `block` | Decisions that throw |
234
+ | `failOpen` | `TWZRD_FAIL_OPEN` | `false` | `true` opts into legacy allow-on-outage; default blocks (fail-closed) |
235
+ | `gateOnCanSpend` | `TWZRD_GATE_ON_CAN_SPEND` | `false` | Also block when `can_spend=false` |
236
+ | `autoReceipt` | — | `false` | Auto-buy $0.05 TWZRD receipt on warn/allow |
237
+ | `x402Fetch` | — | — | x402-capable fetch for `autoReceipt` |
238
+ | `onReceipt` | — | — | Callback after receipt is captured |
76
239
 
77
- ## Config (overrides or env)
240
+ ## Compatibility note
78
241
 
79
- | Option | Env | Default |
80
- |---|---|---|
81
- | `intelBase` | `TWZRD_INTEL_BASE` | `https://intel.twzrd.xyz` |
82
- | `preflightMinScore` | `TWZRD_PREFLIGHT_MIN_SCORE` | `40` |
83
- | `blockDecisions` | `TWZRD_BLOCK_DECISIONS` | `block` |
84
- | `failOpen` | `TWZRD_FAIL_OPEN` | `true` (`false`/`0` to disable) |
85
- | `gateOnCanSpend` | `TWZRD_GATE_ON_CAN_SPEND` | `true` (`false`/`0` = gate only on `decision`) |
86
- | `fetch` | — | global `fetch` |
242
+ **Proxied x402 clients** (AgentCash's `.fetch`, ClawRouter `:8402`): these clients handle
243
+ 402 internally and return 200. The guard never sees a 402. Pass the raw (non-paying) fetch
244
+ to `withTwzrdGuard`, then wrap its output in your x402 client. Or call
245
+ `evaluate_x402_resource` explicitly before routing through the proxy.
87
246
 
88
247
  ## Why pre-spend, not post-pay
89
248
 
90
- `GET /v1/intel/trust/{wallet}` is the **paid** (0.05 USDC) deep-intel surface — it is *not* a gate.
91
- `POST /v1/intel/preflight` is the **free** `ReadinessCard` for the pre-spend decision. This package
92
- only ever calls the free preflight; you decide whether to proceed before any USDC leaves your wallet.
249
+ `GET /v1/intel/trust/{wallet}` is the **paid** ($0.05 USDC) deep-intel surface — not a gate.
250
+ `POST /v1/intel/preflight` is the **free** `ReadinessCard` for the pre-spend decision.
251
+ This package only ever calls the free preflight; you decide whether to proceed before any
252
+ USDC leaves your wallet.
93
253
 
94
254
  ## License
95
255
 
package/dist/config.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { TwzrdGateConfig } from "./types.js";
1
+ import type { TwzrdGateConfig, TwzrdUpsellContext } from "./types.js";
2
2
  export type ResolvedTwzrdGateConfig = {
3
3
  intelBase: string;
4
4
  preflightMinScore: number;
@@ -6,6 +6,7 @@ export type ResolvedTwzrdGateConfig = {
6
6
  failOpen: boolean;
7
7
  gateOnCanSpend: boolean;
8
8
  fetch: typeof fetch;
9
+ onWarnUpsell?: (ctx: TwzrdUpsellContext) => void | Promise<void>;
9
10
  };
10
11
  export declare function resolveConfig(overrides?: TwzrdGateConfig): ResolvedTwzrdGateConfig;
11
12
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,MAAM,MAAM,uBAAuB,GAAG;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC5B,QAAQ,EAAE,OAAO,CAAC;IAClB,cAAc,EAAE,OAAO,CAAC;IACxB,KAAK,EAAE,OAAO,KAAK,CAAC;CACrB,CAAC;AAYF,wBAAgB,aAAa,CAAC,SAAS,CAAC,EAAE,eAAe,GAAG,uBAAuB,CAuClF"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEtE,MAAM,MAAM,uBAAuB,GAAG;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC5B,QAAQ,EAAE,OAAO,CAAC;IAClB,cAAc,EAAE,OAAO,CAAC;IACxB,KAAK,EAAE,OAAO,KAAK,CAAC;IACpB,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,kBAAkB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAClE,CAAC;AAYF,wBAAgB,aAAa,CAAC,SAAS,CAAC,EAAE,eAAe,GAAG,uBAAuB,CAiDlF"}
package/dist/config.js CHANGED
@@ -1,5 +1,5 @@
1
1
  function parseBlockDecisions(raw) {
2
- const source = raw ?? "block";
2
+ const source = raw?.trim() || "block";
3
3
  return new Set(source
4
4
  .split(",")
5
5
  .map((s) => s.trim())
@@ -9,17 +9,26 @@ export function resolveConfig(overrides) {
9
9
  const intelBase = (overrides?.intelBase ??
10
10
  process.env.TWZRD_INTEL_BASE ??
11
11
  "https://intel.twzrd.xyz").replace(/\/+$/, "");
12
- const preflightMinScore = overrides?.preflightMinScore ??
12
+ const rawMin = overrides?.preflightMinScore ??
13
13
  Number(process.env.TWZRD_PREFLIGHT_MIN_SCORE ?? "40");
14
+ const preflightMinScore = (Number.isFinite(rawMin) && rawMin >= 0) ? rawMin : 40;
14
15
  const blockDecisions = overrides?.blockDecisions != null
15
16
  ? new Set([...overrides.blockDecisions].map((s) => s.trim()).filter(Boolean))
16
17
  : parseBlockDecisions(process.env.TWZRD_BLOCK_DECISIONS);
18
+ // Default false (fail-closed): block and log loudly on preflight outage.
19
+ // Opt in to legacy fail-open with TWZRD_FAIL_OPEN=true or TWZRD_FAIL_OPEN=1.
17
20
  const failOpen = overrides?.failOpen ??
18
- (process.env.TWZRD_FAIL_OPEN !== "false" &&
19
- process.env.TWZRD_FAIL_OPEN !== "0");
21
+ (process.env.TWZRD_FAIL_OPEN === "true" ||
22
+ process.env.TWZRD_FAIL_OPEN === "1");
23
+ // Default false (decision-only): an unknown seller (warn / can_spend=false,
24
+ // which is EVERY not-yet-seen merchant at score 45) is NOT blocked by default —
25
+ // only an explicit decision=block (a real wash/sybil flag) blocks. This matches
26
+ // the sister package @wzrd_sol/plugin-trustgate and the preflight's own
27
+ // warn-not-block intent, and keeps the gate usable for discovery. Opt in to
28
+ // strict can_spend gating with TWZRD_GATE_ON_CAN_SPEND=true or =1.
20
29
  const gateOnCanSpend = overrides?.gateOnCanSpend ??
21
- (process.env.TWZRD_GATE_ON_CAN_SPEND !== "false" &&
22
- process.env.TWZRD_GATE_ON_CAN_SPEND !== "0");
30
+ (process.env.TWZRD_GATE_ON_CAN_SPEND === "true" ||
31
+ process.env.TWZRD_GATE_ON_CAN_SPEND === "1");
23
32
  const fetchFn = overrides?.fetch ?? globalThis.fetch;
24
33
  if (typeof fetchFn !== "function") {
25
34
  throw new Error("[twzrd-x402-gate] fetch is not available; pass config.fetch");
@@ -31,6 +40,7 @@ export function resolveConfig(overrides) {
31
40
  failOpen,
32
41
  gateOnCanSpend,
33
42
  fetch: fetchFn,
43
+ onWarnUpsell: overrides?.onWarnUpsell,
34
44
  };
35
45
  }
36
46
  //# sourceMappingURL=config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAWA,SAAS,mBAAmB,CAAC,GAAuB;IAClD,MAAM,MAAM,GAAG,GAAG,IAAI,OAAO,CAAC;IAC9B,OAAO,IAAI,GAAG,CACZ,MAAM;SACH,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SACpB,MAAM,CAAC,OAAO,CAAC,CACnB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,SAA2B;IACvD,MAAM,SAAS,GAAG,CAChB,SAAS,EAAE,SAAS;QACpB,OAAO,CAAC,GAAG,CAAC,gBAAgB;QAC5B,yBAAyB,CAC1B,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAEtB,MAAM,iBAAiB,GACrB,SAAS,EAAE,iBAAiB;QAC5B,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,yBAAyB,IAAI,IAAI,CAAC,CAAC;IAExD,MAAM,cAAc,GAClB,SAAS,EAAE,cAAc,IAAI,IAAI;QAC/B,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC,cAAc,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC7E,CAAC,CAAC,mBAAmB,CAAC,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;IAE7D,MAAM,QAAQ,GACZ,SAAS,EAAE,QAAQ;QACnB,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,KAAK,OAAO;YACtC,OAAO,CAAC,GAAG,CAAC,eAAe,KAAK,GAAG,CAAC,CAAC;IAEzC,MAAM,cAAc,GAClB,SAAS,EAAE,cAAc;QACzB,CAAC,OAAO,CAAC,GAAG,CAAC,uBAAuB,KAAK,OAAO;YAC9C,OAAO,CAAC,GAAG,CAAC,uBAAuB,KAAK,GAAG,CAAC,CAAC;IAEjD,MAAM,OAAO,GAAG,SAAS,EAAE,KAAK,IAAI,UAAU,CAAC,KAAK,CAAC;IACrD,IAAI,OAAO,OAAO,KAAK,UAAU,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,6DAA6D,CAAC,CAAC;IACjF,CAAC;IAED,OAAO;QACL,SAAS;QACT,iBAAiB;QACjB,cAAc;QACd,QAAQ;QACR,cAAc;QACd,KAAK,EAAE,OAAO;KACf,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAYA,SAAS,mBAAmB,CAAC,GAAuB;IAClD,MAAM,MAAM,GAAG,GAAG,EAAE,IAAI,EAAE,IAAI,OAAO,CAAC;IACtC,OAAO,IAAI,GAAG,CACZ,MAAM;SACH,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SACpB,MAAM,CAAC,OAAO,CAAC,CACnB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,SAA2B;IACvD,MAAM,SAAS,GAAG,CAChB,SAAS,EAAE,SAAS;QACpB,OAAO,CAAC,GAAG,CAAC,gBAAgB;QAC5B,yBAAyB,CAC1B,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAEtB,MAAM,MAAM,GACV,SAAS,EAAE,iBAAiB;QAC5B,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,yBAAyB,IAAI,IAAI,CAAC,CAAC;IACxD,MAAM,iBAAiB,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IAEjF,MAAM,cAAc,GAClB,SAAS,EAAE,cAAc,IAAI,IAAI;QAC/B,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC,cAAc,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC7E,CAAC,CAAC,mBAAmB,CAAC,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;IAE7D,yEAAyE;IACzE,6EAA6E;IAC7E,MAAM,QAAQ,GACZ,SAAS,EAAE,QAAQ;QACnB,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,KAAK,MAAM;YACrC,OAAO,CAAC,GAAG,CAAC,eAAe,KAAK,GAAG,CAAC,CAAC;IAEzC,4EAA4E;IAC5E,gFAAgF;IAChF,gFAAgF;IAChF,wEAAwE;IACxE,4EAA4E;IAC5E,mEAAmE;IACnE,MAAM,cAAc,GAClB,SAAS,EAAE,cAAc;QACzB,CAAC,OAAO,CAAC,GAAG,CAAC,uBAAuB,KAAK,MAAM;YAC7C,OAAO,CAAC,GAAG,CAAC,uBAAuB,KAAK,GAAG,CAAC,CAAC;IAEjD,MAAM,OAAO,GAAG,SAAS,EAAE,KAAK,IAAI,UAAU,CAAC,KAAK,CAAC;IACrD,IAAI,OAAO,OAAO,KAAK,UAAU,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,6DAA6D,CAAC,CAAC;IACjF,CAAC;IAED,OAAO;QACL,SAAS;QACT,iBAAiB;QACjB,cAAc;QACd,QAAQ;QACR,cAAc;QACd,KAAK,EAAE,OAAO;QACd,YAAY,EAAE,SAAS,EAAE,YAAY;KACtC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,77 @@
1
+ import { type TwzrdTier } from "./quick.js";
2
+ import type { TwzrdDecision, TwzrdGateConfig, TwzrdReadinessCard, X402PaymentRequirements } from "./types.js";
3
+ export type EvaluateX402Options = TwzrdGateConfig & {
4
+ /**
5
+ * When true, automatically fetches the paid TWZRD trust receipt (via x402)
6
+ * after a warn/allow decision. Requires x402Fetch to be provided.
7
+ * Default: false.
8
+ */
9
+ autoReceipt?: boolean;
10
+ /**
11
+ * x402-capable fetch that can settle USDC payments. Used by autoReceipt (the
12
+ * $0.05 receipt) and by escalateOnWarn (the $0.001 quick tier). The caller wires
13
+ * in a Solana wallet + x402 payer.
14
+ */
15
+ x402Fetch?: typeof fetch;
16
+ /**
17
+ * Called immediately after a receipt is captured on-chain.
18
+ * Provides the raw twzrd_receipt object and the settlement tx hash (if present).
19
+ */
20
+ onReceipt?: (receipt: unknown, tx: string | undefined) => void;
21
+ /**
22
+ * Autonomous risk-escalation. When the free preflight is inconclusive
23
+ * (decision="warn" and otherwise proceeding), the gate autonomously settles the
24
+ * cheap $0.001 quick tier and RE-DECIDES on the paid score: below `blockBelowScore`
25
+ * (default: preflightMinScore) the payment is denied (approved=false); at/above it
26
+ * proceeds. The paid call fires from the agent's own risk policy - no human - and
27
+ * the paid signal actually gates the spend (unlike autoReceipt, which is upsell-only
28
+ * and never changes the decision). Opt-in; requires x402Fetch. Fail-soft: if the
29
+ * quick tier cannot answer, the base warn decision is preserved. Only tightens
30
+ * (warn -> maybe block); never loosens a block or allow. Short-circuits the
31
+ * autoReceipt path for the warn case (no double settle).
32
+ */
33
+ escalateOnWarn?: {
34
+ /** Skip escalation when the resource price is below this - don't pay $0.001 to vet a sub-cent buy. Default 0. */
35
+ minSpendUsdc?: number;
36
+ /** Deny when the paid quick score is below this. Default: preflightMinScore (40). */
37
+ blockBelowScore?: number;
38
+ };
39
+ };
40
+ export type EvaluateX402Result = {
41
+ decision: TwzrdDecision | "unknown";
42
+ trustScore: number | null;
43
+ approved: boolean;
44
+ reason: string;
45
+ card: TwzrdReadinessCard;
46
+ /** true when the preflight was unreachable and fail-open allowed the resource */
47
+ failOpen?: boolean;
48
+ /** URL of the paid TWZRD trust endpoint for this seller (for manual upsell) */
49
+ receiptUrl?: string;
50
+ /** Present when autoReceipt=true and the x402 trust call succeeded */
51
+ receipt?: unknown;
52
+ /** On-chain settlement tx from the receipt payment */
53
+ receiptTx?: string;
54
+ /** true when a fee was captured on-chain */
55
+ receiptFeeCaptured?: boolean;
56
+ /** true when a `warn` triggered an autonomous paid quick-tier re-decision (escalateOnWarn) */
57
+ escalated?: boolean;
58
+ /** the paid quick-tier score that drove the escalated decision; null when the quick tier could not answer */
59
+ escalatedScore?: number | null;
60
+ /** the paid quick-tier label (Bronze/Silver/Gold/Platinum) from the escalation */
61
+ escalatedTier?: TwzrdTier | null;
62
+ };
63
+ /**
64
+ * Evaluate an x402 resource before the buyer pays:
65
+ * 1. Run free TWZRD preflight on the seller (no auth, no cost).
66
+ * 2. Return decision + trust score.
67
+ * 3. If escalateOnWarn is set and decision=warn: autonomously settle the cheap
68
+ * $0.001 quick tier and re-decide on the paid score (the autonomous risk loop).
69
+ * 4. Else if autoReceipt=true and decision !== block: auto-fetch the paid TWZRD
70
+ * trust receipt via x402Fetch (TWZRD earns the receipt fee on-chain).
71
+ *
72
+ * Defaults to gateOnCanSpend=false (decision-only) — the free-tier preflight
73
+ * returns can_spend=false for most unknown sellers, which would block too eagerly
74
+ * on platforms like Agentic.Market where sellers are not yet in the corpus.
75
+ */
76
+ export declare function evaluate_x402_resource(resourceUrl: string, paymentRequirements: X402PaymentRequirements, opts?: EvaluateX402Options): Promise<EvaluateX402Result>;
77
+ //# sourceMappingURL=evaluate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evaluate.d.ts","sourceRoot":"","sources":["../src/evaluate.ts"],"names":[],"mappings":"AAGA,OAAO,EAAc,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,KAAK,EACV,aAAa,EACb,eAAe,EACf,kBAAkB,EAClB,uBAAuB,EACxB,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,mBAAmB,GAAG,eAAe,GAAG;IAClD;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB;;;OAGG;IACH,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;IAC/D;;;;;;;;;;;OAWG;IACH,cAAc,CAAC,EAAE;QACf,iHAAiH;QACjH,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,qFAAqF;QACrF,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,EAAE,aAAa,GAAG,SAAS,CAAC;IACpC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,kBAAkB,CAAC;IACzB,iFAAiF;IACjF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sEAAsE;IACtE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4CAA4C;IAC5C,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,8FAA8F;IAC9F,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,6GAA6G;IAC7G,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,kFAAkF;IAClF,aAAa,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;CAClC,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,wBAAsB,sBAAsB,CAC1C,WAAW,EAAE,MAAM,EACnB,mBAAmB,EAAE,uBAAuB,EAC5C,IAAI,GAAE,mBAAwB,GAC7B,OAAO,CAAC,kBAAkB,CAAC,CAmH7B"}
@@ -0,0 +1,114 @@
1
+ import { resolveConfig } from "./config.js";
2
+ import { twzrdApprovePayment } from "./policy.js";
3
+ import { payToFromRequirements, priceUsdcFromAmountMicro } from "./payto.js";
4
+ import { quickCheck } from "./quick.js";
5
+ /**
6
+ * Evaluate an x402 resource before the buyer pays:
7
+ * 1. Run free TWZRD preflight on the seller (no auth, no cost).
8
+ * 2. Return decision + trust score.
9
+ * 3. If escalateOnWarn is set and decision=warn: autonomously settle the cheap
10
+ * $0.001 quick tier and re-decide on the paid score (the autonomous risk loop).
11
+ * 4. Else if autoReceipt=true and decision !== block: auto-fetch the paid TWZRD
12
+ * trust receipt via x402Fetch (TWZRD earns the receipt fee on-chain).
13
+ *
14
+ * Defaults to gateOnCanSpend=false (decision-only) — the free-tier preflight
15
+ * returns can_spend=false for most unknown sellers, which would block too eagerly
16
+ * on platforms like Agentic.Market where sellers are not yet in the corpus.
17
+ */
18
+ export async function evaluate_x402_resource(resourceUrl, paymentRequirements, opts = {}) {
19
+ const config = resolveConfig({
20
+ intelBase: opts.intelBase,
21
+ preflightMinScore: opts.preflightMinScore,
22
+ blockDecisions: opts.blockDecisions,
23
+ failOpen: opts.failOpen,
24
+ // Decision-only gate: unknown sellers score warn (~45), not block.
25
+ // Gating on can_spend would block every Agentic.Market seller not in corpus.
26
+ gateOnCanSpend: opts.gateOnCanSpend,
27
+ fetch: opts.fetch,
28
+ });
29
+ const { payTo, amountMicro, resource } = payToFromRequirements(paymentRequirements);
30
+ const priceUsdc = priceUsdcFromAmountMicro(amountMicro);
31
+ const approval = await twzrdApprovePayment({
32
+ resourceUrl: resource ?? resourceUrl,
33
+ payTo,
34
+ priceUsdc,
35
+ agentIntent: "evaluate_x402_resource",
36
+ }, config);
37
+ const decision = (approval.card.decision ?? "unknown");
38
+ const receiptUrl = payTo
39
+ ? `${config.intelBase}/v1/intel/trust/${encodeURIComponent(payTo)}`
40
+ : undefined;
41
+ const base = {
42
+ decision,
43
+ trustScore: approval.card.trust_score ?? null,
44
+ approved: approval.approved,
45
+ reason: approval.reason,
46
+ card: approval.card,
47
+ failOpen: approval.failOpen,
48
+ receiptUrl,
49
+ };
50
+ // Autonomous risk-escalation: a *proceeding* `warn` (uncertain / unknown seller)
51
+ // is vetted by settling the cheap $0.001 quick tier and re-deciding on the paid
52
+ // score. This is the autonomous demand loop - the paid call fires from the agent's
53
+ // own risk policy, and the paid signal gates the spend (only tightens). Fail-soft:
54
+ // if the quick tier cannot answer, the base warn decision is preserved.
55
+ if (opts.escalateOnWarn &&
56
+ typeof opts.x402Fetch === "function" &&
57
+ payTo &&
58
+ decision === "warn" &&
59
+ base.approved &&
60
+ (priceUsdc ?? 0) >= (opts.escalateOnWarn.minSpendUsdc ?? 0)) {
61
+ const floor = opts.escalateOnWarn.blockBelowScore ?? config.preflightMinScore;
62
+ const quick = await quickCheck(payTo, {
63
+ intelBase: config.intelBase,
64
+ fetch: config.fetch,
65
+ x402Fetch: opts.x402Fetch,
66
+ });
67
+ if (quick.available && quick.score !== null) {
68
+ const escApproved = quick.score >= floor;
69
+ return {
70
+ ...base,
71
+ approved: escApproved,
72
+ trustScore: quick.score,
73
+ escalated: true,
74
+ escalatedScore: quick.score,
75
+ escalatedTier: quick.tier,
76
+ reason: escApproved
77
+ ? `twzrd_escalated_warn_allow (paid quick score ${quick.score} >= ${floor})`
78
+ : `twzrd_escalated_warn_block (paid quick score ${quick.score} < ${floor})`,
79
+ };
80
+ }
81
+ // Quick tier could not answer (fail-soft) - preserve the base warn decision.
82
+ return { ...base, escalated: true, escalatedScore: null };
83
+ }
84
+ // Auto-upsell: on warn or allow, fetch the paid TWZRD trust receipt.
85
+ // This is the revenue capture path: x402Fetch settles $0.05 USDC to TWZRD.
86
+ if (opts.autoReceipt &&
87
+ typeof opts.x402Fetch === "function" &&
88
+ payTo &&
89
+ decision !== "block") {
90
+ try {
91
+ // Echo the verify->act funnel link so this paid call is attributed to its preflight.
92
+ const headers = { accept: "application/json" };
93
+ if (typeof approval.preflightId === "number") {
94
+ headers["x-twzrd-preflight-id"] = String(approval.preflightId);
95
+ }
96
+ const resp = await opts.x402Fetch(`${config.intelBase}/v1/intel/trust/${encodeURIComponent(payTo)}`, { method: "GET", headers });
97
+ if (resp.ok) {
98
+ const body = (await resp.json());
99
+ const receipt = body.twzrd_receipt;
100
+ const preimage = receipt?.preimage;
101
+ const tx = body.tx ?? body.tx_pending ?? (typeof preimage?.settlement_tx === "string" ? preimage.settlement_tx : undefined);
102
+ const feeCaptured = !!tx || body.charged === true;
103
+ if (opts.onReceipt)
104
+ opts.onReceipt(receipt, tx);
105
+ return { ...base, receipt, receiptTx: tx, receiptFeeCaptured: feeCaptured };
106
+ }
107
+ }
108
+ catch {
109
+ // Fail-open: receipt upsell failure does not block access to the resource.
110
+ }
111
+ }
112
+ return base;
113
+ }
114
+ //# sourceMappingURL=evaluate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evaluate.js","sourceRoot":"","sources":["../src/evaluate.ts"],"names":[],"mappings":"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"}
package/dist/gate.d.ts CHANGED
@@ -16,4 +16,17 @@ export type TwzrdGate = {
16
16
  export declare function createTwzrdGate(overrides?: TwzrdGateConfig): TwzrdGate;
17
17
  /** Default gate using process.env / global fetch */
18
18
  export declare const defaultGate: TwzrdGate;
19
+ /**
20
+ * Decorator-style guard for agent payment flows.
21
+ * Runs TWZRD preflight on the seller before invoking `fn`.
22
+ * Throws if policy denies; passes through on allow/warn.
23
+ *
24
+ * @example
25
+ * const safePay = withTwzrdGuard(
26
+ * (seller) => agentcashFetch(`https://api.seller.xyz/paid`),
27
+ * { preflightMinScore: 50 }
28
+ * );
29
+ * const result = await safePay("SELLER_WALLET_BASE58");
30
+ */
31
+ export declare function withTwzrdGuard<TArgs extends unknown[], TReturn>(fn: (sellerWallet: string, ...args: TArgs) => Promise<TReturn>, config?: TwzrdGateConfig): (sellerWallet: string, ...args: TArgs) => Promise<TReturn>;
19
32
  //# sourceMappingURL=gate.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../src/gate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAE1E,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,mBAAmB,EACnB,cAAc,EACf,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAE7E,OAAO,KAAK,EAAE,mBAAmB,EAAE,eAAe,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAEnH,MAAM,MAAM,SAAS,GAAG;IACtB,QAAQ,CAAC,MAAM,EAAE,uBAAuB,CAAC;IACzC,SAAS,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;IAC7E,cAAc,EAAE,CAAC,GAAG,EAAE,mBAAmB,KAAK,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC;IACrF,kBAAkB,EAAE,CAAC,GAAG,EAAE,qBAAqB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACrE,SAAS,EAAE,CAAC,UAAU,EAAE,OAAO,KAAK,KAAK,OAAO,KAAK,CAAC;IACtD,qBAAqB,EAAE,OAAO,qBAAqB,CAAC;IACpD,mBAAmB,EAAE,OAAO,mBAAmB,CAAC;IAChD,qBAAqB,EAAE,OAAO,qBAAqB,CAAC;IACpD,wBAAwB,EAAE,OAAO,wBAAwB,CAAC;CAC3D,CAAC;AAEF,wBAAgB,eAAe,CAAC,SAAS,CAAC,EAAE,eAAe,GAAG,SAAS,CAatE;AAED,oDAAoD;AACpD,eAAO,MAAM,WAAW,EAAE,SAA6B,CAAC"}
1
+ {"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../src/gate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAE1E,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,mBAAmB,EACnB,cAAc,EACf,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAE7E,OAAO,KAAK,EAAE,mBAAmB,EAAE,eAAe,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAEnH,MAAM,MAAM,SAAS,GAAG;IACtB,QAAQ,CAAC,MAAM,EAAE,uBAAuB,CAAC;IACzC,SAAS,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;IAC7E,cAAc,EAAE,CAAC,GAAG,EAAE,mBAAmB,KAAK,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC;IACrF,kBAAkB,EAAE,CAAC,GAAG,EAAE,qBAAqB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACrE,SAAS,EAAE,CAAC,UAAU,EAAE,OAAO,KAAK,KAAK,OAAO,KAAK,CAAC;IACtD,qBAAqB,EAAE,OAAO,qBAAqB,CAAC;IACpD,mBAAmB,EAAE,OAAO,mBAAmB,CAAC;IAChD,qBAAqB,EAAE,OAAO,qBAAqB,CAAC;IACpD,wBAAwB,EAAE,OAAO,wBAAwB,CAAC;CAC3D,CAAC;AAEF,wBAAgB,eAAe,CAAC,SAAS,CAAC,EAAE,eAAe,GAAG,SAAS,CAatE;AAED,oDAAoD;AACpD,eAAO,MAAM,WAAW,EAAE,SAA6B,CAAC;AAExD;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,KAAK,SAAS,OAAO,EAAE,EAAE,OAAO,EAC7D,EAAE,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,KAAK,KAAK,OAAO,CAAC,OAAO,CAAC,EAC9D,MAAM,CAAC,EAAE,eAAe,GACvB,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,KAAK,KAAK,OAAO,CAAC,OAAO,CAAC,CAc5D"}
package/dist/gate.js CHANGED
@@ -19,4 +19,26 @@ export function createTwzrdGate(overrides) {
19
19
  }
20
20
  /** Default gate using process.env / global fetch */
21
21
  export const defaultGate = createTwzrdGate();
22
+ /**
23
+ * Decorator-style guard for agent payment flows.
24
+ * Runs TWZRD preflight on the seller before invoking `fn`.
25
+ * Throws if policy denies; passes through on allow/warn.
26
+ *
27
+ * @example
28
+ * const safePay = withTwzrdGuard(
29
+ * (seller) => agentcashFetch(`https://api.seller.xyz/paid`),
30
+ * { preflightMinScore: 50 }
31
+ * );
32
+ * const result = await safePay("SELLER_WALLET_BASE58");
33
+ */
34
+ export function withTwzrdGuard(fn, config) {
35
+ const cfg = resolveConfig(config);
36
+ return async (sellerWallet, ...args) => {
37
+ const { approved, verdict, score, reason } = await twzrdApprovePayment({ sellerWallet, agentIntent: "withTwzrdGuard" }, cfg);
38
+ if (!approved) {
39
+ throw new Error(`[twzrd] withTwzrdGuard blocked: ${reason} (verdict=${verdict}, score=${score})`);
40
+ }
41
+ return fn(sellerWallet, ...args);
42
+ };
43
+ }
22
44
  //# sourceMappingURL=gate.js.map