twzrd-x402-gate 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +96 -0
- package/dist/config.d.ts +11 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +36 -0
- package/dist/config.js.map +1 -0
- package/dist/gate.d.ts +19 -0
- package/dist/gate.d.ts.map +1 -0
- package/dist/gate.js +22 -0
- package/dist/gate.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-hook.d.ts +8 -0
- package/dist/mcp-hook.d.ts.map +1 -0
- package/dist/mcp-hook.js +30 -0
- package/dist/mcp-hook.js.map +1 -0
- package/dist/payto.d.ts +8 -0
- package/dist/payto.d.ts.map +1 -0
- package/dist/payto.js +14 -0
- package/dist/payto.js.map +1 -0
- package/dist/policy.d.ts +17 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/policy.js +75 -0
- package/dist/policy.js.map +1 -0
- package/dist/types.d.ts +76 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/wrap-fetch.d.ts +7 -0
- package/dist/wrap-fetch.d.ts.map +1 -0
- package/dist/wrap-fetch.js +41 -0
- package/dist/wrap-fetch.js.map +1 -0
- package/package.json +47 -0
package/README.md
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# twzrd-x402-gate
|
|
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.
|
|
6
|
+
|
|
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).
|
|
9
|
+
|
|
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.
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install twzrd-x402-gate
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
### Wrap any fetch that may receive a 402
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
import { wrapFetchWithTwzrdGate, resolveConfig } from "twzrd-x402-gate";
|
|
28
|
+
|
|
29
|
+
const gatedFetch = wrapFetchWithTwzrdGate(fetch, resolveConfig());
|
|
30
|
+
|
|
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");
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### As the @x402/mcp payment hook
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import { defaultGate } from "twzrd-x402-gate";
|
|
41
|
+
|
|
42
|
+
const client = createX402MCPClient({
|
|
43
|
+
onPaymentRequested: defaultGate.onPaymentRequested, // returns false to deny
|
|
44
|
+
});
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Direct decision (no network wiring)
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
import { createTwzrdGate } from "twzrd-x402-gate";
|
|
51
|
+
|
|
52
|
+
const gate = createTwzrdGate();
|
|
53
|
+
const { approved, reason, card } = await gate.approvePayment({
|
|
54
|
+
payTo: "SELLER_WALLET_FROM_402",
|
|
55
|
+
resourceUrl: "https://merchant.example/paid",
|
|
56
|
+
priceUsdc: 0.003,
|
|
57
|
+
});
|
|
58
|
+
if (!approved) abort(reason);
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Policy
|
|
62
|
+
|
|
63
|
+
A payment is **denied** when any of these hold (mirrors `scripts/twzrd_gate_agentcash_fetch.sh`):
|
|
64
|
+
|
|
65
|
+
1. `decision ∈ blockDecisions` (default: `block`)
|
|
66
|
+
2. `can_spend === false` — **only when `gateOnCanSpend` is true (default)**
|
|
67
|
+
3. `trust_score < preflightMinScore` (default: `40`)
|
|
68
|
+
|
|
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.
|
|
71
|
+
|
|
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`).
|
|
76
|
+
|
|
77
|
+
## Config (overrides or env)
|
|
78
|
+
|
|
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` |
|
|
87
|
+
|
|
88
|
+
## Why pre-spend, not post-pay
|
|
89
|
+
|
|
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.
|
|
93
|
+
|
|
94
|
+
## License
|
|
95
|
+
|
|
96
|
+
MIT
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { TwzrdGateConfig } from "./types.js";
|
|
2
|
+
export type ResolvedTwzrdGateConfig = {
|
|
3
|
+
intelBase: string;
|
|
4
|
+
preflightMinScore: number;
|
|
5
|
+
blockDecisions: Set<string>;
|
|
6
|
+
failOpen: boolean;
|
|
7
|
+
gateOnCanSpend: boolean;
|
|
8
|
+
fetch: typeof fetch;
|
|
9
|
+
};
|
|
10
|
+
export declare function resolveConfig(overrides?: TwzrdGateConfig): ResolvedTwzrdGateConfig;
|
|
11
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +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"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
function parseBlockDecisions(raw) {
|
|
2
|
+
const source = raw ?? "block";
|
|
3
|
+
return new Set(source
|
|
4
|
+
.split(",")
|
|
5
|
+
.map((s) => s.trim())
|
|
6
|
+
.filter(Boolean));
|
|
7
|
+
}
|
|
8
|
+
export function resolveConfig(overrides) {
|
|
9
|
+
const intelBase = (overrides?.intelBase ??
|
|
10
|
+
process.env.TWZRD_INTEL_BASE ??
|
|
11
|
+
"https://intel.twzrd.xyz").replace(/\/+$/, "");
|
|
12
|
+
const preflightMinScore = overrides?.preflightMinScore ??
|
|
13
|
+
Number(process.env.TWZRD_PREFLIGHT_MIN_SCORE ?? "40");
|
|
14
|
+
const blockDecisions = overrides?.blockDecisions != null
|
|
15
|
+
? new Set([...overrides.blockDecisions].map((s) => s.trim()).filter(Boolean))
|
|
16
|
+
: parseBlockDecisions(process.env.TWZRD_BLOCK_DECISIONS);
|
|
17
|
+
const failOpen = overrides?.failOpen ??
|
|
18
|
+
(process.env.TWZRD_FAIL_OPEN !== "false" &&
|
|
19
|
+
process.env.TWZRD_FAIL_OPEN !== "0");
|
|
20
|
+
const gateOnCanSpend = overrides?.gateOnCanSpend ??
|
|
21
|
+
(process.env.TWZRD_GATE_ON_CAN_SPEND !== "false" &&
|
|
22
|
+
process.env.TWZRD_GATE_ON_CAN_SPEND !== "0");
|
|
23
|
+
const fetchFn = overrides?.fetch ?? globalThis.fetch;
|
|
24
|
+
if (typeof fetchFn !== "function") {
|
|
25
|
+
throw new Error("[twzrd-x402-gate] fetch is not available; pass config.fetch");
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
intelBase,
|
|
29
|
+
preflightMinScore,
|
|
30
|
+
blockDecisions,
|
|
31
|
+
failOpen,
|
|
32
|
+
gateOnCanSpend,
|
|
33
|
+
fetch: fetchFn,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +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"}
|
package/dist/gate.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type ResolvedTwzrdGateConfig } from "./config.js";
|
|
2
|
+
import { buildPreflightInput, evaluateReadinessCard, twzrdApprovePayment, twzrdPreflight } from "./policy.js";
|
|
3
|
+
import { payToFromRequirements, priceUsdcFromAmountMicro } from "./payto.js";
|
|
4
|
+
import type { TwzrdApproveContext, TwzrdGateConfig, TwzrdPreflightInput, X402McpPaymentRequest } from "./types.js";
|
|
5
|
+
export type TwzrdGate = {
|
|
6
|
+
readonly config: ResolvedTwzrdGateConfig;
|
|
7
|
+
preflight: (input: TwzrdPreflightInput) => ReturnType<typeof twzrdPreflight>;
|
|
8
|
+
approvePayment: (ctx: TwzrdApproveContext) => ReturnType<typeof twzrdApprovePayment>;
|
|
9
|
+
onPaymentRequested: (req: X402McpPaymentRequest) => Promise<boolean>;
|
|
10
|
+
wrapFetch: (innerFetch: typeof fetch) => typeof fetch;
|
|
11
|
+
evaluateReadinessCard: typeof evaluateReadinessCard;
|
|
12
|
+
buildPreflightInput: typeof buildPreflightInput;
|
|
13
|
+
payToFromRequirements: typeof payToFromRequirements;
|
|
14
|
+
priceUsdcFromAmountMicro: typeof priceUsdcFromAmountMicro;
|
|
15
|
+
};
|
|
16
|
+
export declare function createTwzrdGate(overrides?: TwzrdGateConfig): TwzrdGate;
|
|
17
|
+
/** Default gate using process.env / global fetch */
|
|
18
|
+
export declare const defaultGate: TwzrdGate;
|
|
19
|
+
//# sourceMappingURL=gate.d.ts.map
|
|
@@ -0,0 +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"}
|
package/dist/gate.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { resolveConfig } from "./config.js";
|
|
2
|
+
import { twzrdOnPaymentRequested } from "./mcp-hook.js";
|
|
3
|
+
import { buildPreflightInput, evaluateReadinessCard, twzrdApprovePayment, twzrdPreflight, } from "./policy.js";
|
|
4
|
+
import { payToFromRequirements, priceUsdcFromAmountMicro } from "./payto.js";
|
|
5
|
+
import { wrapFetchWithTwzrdGate } from "./wrap-fetch.js";
|
|
6
|
+
export function createTwzrdGate(overrides) {
|
|
7
|
+
const config = resolveConfig(overrides);
|
|
8
|
+
return {
|
|
9
|
+
config,
|
|
10
|
+
preflight: (input) => twzrdPreflight(input, config),
|
|
11
|
+
approvePayment: (ctx) => twzrdApprovePayment(ctx, config),
|
|
12
|
+
onPaymentRequested: (req) => twzrdOnPaymentRequested(req, config),
|
|
13
|
+
wrapFetch: (inner) => wrapFetchWithTwzrdGate(inner, config),
|
|
14
|
+
evaluateReadinessCard,
|
|
15
|
+
buildPreflightInput,
|
|
16
|
+
payToFromRequirements,
|
|
17
|
+
priceUsdcFromAmountMicro,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/** Default gate using process.env / global fetch */
|
|
21
|
+
export const defaultGate = createTwzrdGate();
|
|
22
|
+
//# sourceMappingURL=gate.js.map
|
package/dist/gate.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate.js","sourceRoot":"","sources":["../src/gate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAgC,MAAM,aAAa,CAAC;AAC1E,OAAO,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,mBAAmB,EACnB,cAAc,GACf,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAC7E,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAezD,MAAM,UAAU,eAAe,CAAC,SAA2B;IACzD,MAAM,MAAM,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC;IACxC,OAAO;QACL,MAAM;QACN,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC;QACnD,cAAc,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,mBAAmB,CAAC,GAAG,EAAE,MAAM,CAAC;QACzD,kBAAkB,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,uBAAuB,CAAC,GAAG,EAAE,MAAM,CAAC;QACjE,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,sBAAsB,CAAC,KAAK,EAAE,MAAM,CAAC;QAC3D,qBAAqB;QACrB,mBAAmB;QACnB,qBAAqB;QACrB,wBAAwB;KACzB,CAAC;AACJ,CAAC;AAED,oDAAoD;AACpD,MAAM,CAAC,MAAM,WAAW,GAAc,eAAe,EAAE,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { createTwzrdGate, defaultGate, type TwzrdGate } from "./gate.js";
|
|
2
|
+
export { resolveConfig, type ResolvedTwzrdGateConfig } from "./config.js";
|
|
3
|
+
export { evaluateReadinessCard, buildPreflightInput, twzrdPreflight, twzrdApprovePayment, type PolicyEvaluateInput, } from "./policy.js";
|
|
4
|
+
export { payToFromRequirements, priceUsdcFromAmountMicro } from "./payto.js";
|
|
5
|
+
export { twzrdOnPaymentRequested } from "./mcp-hook.js";
|
|
6
|
+
export { wrapFetchWithTwzrdGate } from "./wrap-fetch.js";
|
|
7
|
+
export type { TwzrdDecision, TwzrdReadinessCard, TwzrdPreflightInput, TwzrdGateConfig, TwzrdApproveContext, TwzrdApprovalResult, X402PaymentRequirements, X402PaymentRequiredBody, X402McpPaymentRequest, } from "./types.js";
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,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,MAAM,YAAY,CAAC;AAC7E,OAAO,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACzD,YAAY,EACV,aAAa,EACb,kBAAkB,EAClB,mBAAmB,EACnB,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,uBAAuB,EACvB,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { createTwzrdGate, defaultGate } from "./gate.js";
|
|
2
|
+
export { resolveConfig } from "./config.js";
|
|
3
|
+
export { evaluateReadinessCard, buildPreflightInput, twzrdPreflight, twzrdApprovePayment, } from "./policy.js";
|
|
4
|
+
export { payToFromRequirements, priceUsdcFromAmountMicro } from "./payto.js";
|
|
5
|
+
export { twzrdOnPaymentRequested } from "./mcp-hook.js";
|
|
6
|
+
export { wrapFetchWithTwzrdGate } from "./wrap-fetch.js";
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,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,MAAM,YAAY,CAAC;AAC7E,OAAO,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ResolvedTwzrdGateConfig } from "./config.js";
|
|
2
|
+
import type { X402McpPaymentRequest } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* x402 MCP client hook. Wire as `onPaymentRequested` on createX402MCPClient.
|
|
5
|
+
* Returns false to deny the payment, true to allow.
|
|
6
|
+
*/
|
|
7
|
+
export declare function twzrdOnPaymentRequested(req: X402McpPaymentRequest, config?: ResolvedTwzrdGateConfig): Promise<boolean>;
|
|
8
|
+
//# sourceMappingURL=mcp-hook.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-hook.d.ts","sourceRoot":"","sources":["../src/mcp-hook.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAG3D,OAAO,KAAK,EAAE,qBAAqB,EAA2B,MAAM,YAAY,CAAC;AAEjF;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,GAAG,EAAE,qBAAqB,EAC1B,MAAM,CAAC,EAAE,uBAAuB,GAC/B,OAAO,CAAC,OAAO,CAAC,CA2BlB"}
|
package/dist/mcp-hook.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { payToFromRequirements, priceUsdcFromAmountMicro } from "./payto.js";
|
|
2
|
+
import { twzrdApprovePayment } from "./policy.js";
|
|
3
|
+
/**
|
|
4
|
+
* x402 MCP client hook. Wire as `onPaymentRequested` on createX402MCPClient.
|
|
5
|
+
* Returns false to deny the payment, true to allow.
|
|
6
|
+
*/
|
|
7
|
+
export async function twzrdOnPaymentRequested(req, config) {
|
|
8
|
+
const first = (req.accepts?.[0] ?? {});
|
|
9
|
+
const { payTo, amountMicro, resource } = payToFromRequirements(first);
|
|
10
|
+
const priceUsdc = priceUsdcFromAmountMicro(amountMicro);
|
|
11
|
+
const { approved, card, reason } = await twzrdApprovePayment({
|
|
12
|
+
resourceUrl: req.context?.resource ?? resource,
|
|
13
|
+
resourceName: req.context?.toolName,
|
|
14
|
+
sellerWallet: req.context?.sellerWallet,
|
|
15
|
+
payTo,
|
|
16
|
+
priceUsdc,
|
|
17
|
+
buyerWallet: req.context?.buyerWallet,
|
|
18
|
+
agentIntent: "x402_mcp_onPaymentRequested",
|
|
19
|
+
}, config);
|
|
20
|
+
if (!approved) {
|
|
21
|
+
console.warn("[twzrd] blocked x402 payment:", reason, {
|
|
22
|
+
payTo,
|
|
23
|
+
resource,
|
|
24
|
+
decision: card.decision,
|
|
25
|
+
trust_score: card.trust_score,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
return approved;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=mcp-hook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-hook.js","sourceRoot":"","sources":["../src/mcp-hook.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAC7E,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAGlD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,GAA0B,EAC1B,MAAgC;IAEhC,MAAM,KAAK,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAA4B,CAAC;IAClE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;IACtE,MAAM,SAAS,GAAG,wBAAwB,CAAC,WAAW,CAAC,CAAC;IAExD,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,mBAAmB,CAC1D;QACE,WAAW,EAAE,GAAG,CAAC,OAAO,EAAE,QAAQ,IAAI,QAAQ;QAC9C,YAAY,EAAE,GAAG,CAAC,OAAO,EAAE,QAAQ;QACnC,YAAY,EAAE,GAAG,CAAC,OAAO,EAAE,YAAY;QACvC,KAAK;QACL,SAAS;QACT,WAAW,EAAE,GAAG,CAAC,OAAO,EAAE,WAAW;QACrC,WAAW,EAAE,6BAA6B;KAC3C,EACD,MAAM,CACP,CAAC;IAEF,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,CAAC,IAAI,CAAC,+BAA+B,EAAE,MAAM,EAAE;YACpD,KAAK;YACL,QAAQ;YACR,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,WAAW,EAAE,IAAI,CAAC,WAAW;SAC9B,CAAC,CAAC;IACL,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
package/dist/payto.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { X402PaymentRequirements } from "./types.js";
|
|
2
|
+
export declare function payToFromRequirements(req: X402PaymentRequirements): {
|
|
3
|
+
payTo: string | undefined;
|
|
4
|
+
amountMicro: string | undefined;
|
|
5
|
+
resource: string | undefined;
|
|
6
|
+
};
|
|
7
|
+
export declare function priceUsdcFromAmountMicro(amountMicro: string | undefined): number | undefined;
|
|
8
|
+
//# sourceMappingURL=payto.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"payto.d.ts","sourceRoot":"","sources":["../src/payto.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAE1D,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,uBAAuB,GAAG;IACnE,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;CAC9B,CAIA;AAED,wBAAgB,wBAAwB,CACtC,WAAW,EAAE,MAAM,GAAG,SAAS,GAC9B,MAAM,GAAG,SAAS,CAKpB"}
|
package/dist/payto.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function payToFromRequirements(req) {
|
|
2
|
+
const payTo = req.payTo ?? req.pay_to;
|
|
3
|
+
const amountMicro = req.maxAmountRequired ?? req.amount;
|
|
4
|
+
return { payTo, amountMicro, resource: req.resource };
|
|
5
|
+
}
|
|
6
|
+
export function priceUsdcFromAmountMicro(amountMicro) {
|
|
7
|
+
if (amountMicro == null || amountMicro === "")
|
|
8
|
+
return undefined;
|
|
9
|
+
const n = Number(amountMicro);
|
|
10
|
+
if (!Number.isFinite(n))
|
|
11
|
+
return undefined;
|
|
12
|
+
return n / 1_000_000;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=payto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"payto.js","sourceRoot":"","sources":["../src/payto.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,qBAAqB,CAAC,GAA4B;IAKhE,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,MAAM,CAAC;IACtC,MAAM,WAAW,GAAG,GAAG,CAAC,iBAAiB,IAAI,GAAG,CAAC,MAAM,CAAC;IACxD,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC;AACxD,CAAC;AAED,MAAM,UAAU,wBAAwB,CACtC,WAA+B;IAE/B,IAAI,WAAW,IAAI,IAAI,IAAI,WAAW,KAAK,EAAE;QAAE,OAAO,SAAS,CAAC;IAChE,MAAM,CAAC,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC;IAC9B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IAC1C,OAAO,CAAC,GAAG,SAAS,CAAC;AACvB,CAAC"}
|
package/dist/policy.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type ResolvedTwzrdGateConfig } from "./config.js";
|
|
2
|
+
import type { TwzrdApprovalResult, TwzrdApproveContext, TwzrdPreflightInput, TwzrdReadinessCard } from "./types.js";
|
|
3
|
+
export type PolicyEvaluateInput = {
|
|
4
|
+
card: TwzrdReadinessCard;
|
|
5
|
+
preflightMinScore: number;
|
|
6
|
+
blockDecisions: Set<string>;
|
|
7
|
+
/** Deny on can_spend=false. Default true when omitted. */
|
|
8
|
+
gateOnCanSpend?: boolean;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Pure policy — no network. Mirrors scripts/twzrd_gate_agentcash_fetch.sh semantics.
|
|
12
|
+
*/
|
|
13
|
+
export declare function evaluateReadinessCard(input: PolicyEvaluateInput): TwzrdApprovalResult;
|
|
14
|
+
export declare function buildPreflightInput(context: TwzrdApproveContext): TwzrdPreflightInput;
|
|
15
|
+
export declare function twzrdPreflight(input: TwzrdPreflightInput, config?: ResolvedTwzrdGateConfig): Promise<TwzrdReadinessCard>;
|
|
16
|
+
export declare function twzrdApprovePayment(context: TwzrdApproveContext, config?: ResolvedTwzrdGateConfig): Promise<TwzrdApprovalResult>;
|
|
17
|
+
//# sourceMappingURL=policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAC1E,OAAO,KAAK,EACV,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,kBAAkB,EACnB,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,kBAAkB,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC5B,0DAA0D;IAC1D,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,CAAC;AAEF;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,mBAAmB,GAAG,mBAAmB,CAuBrF;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,mBAAmB,GAAG,mBAAmB,CAWrF;AAED,wBAAsB,cAAc,CAClC,KAAK,EAAE,mBAAmB,EAC1B,MAAM,CAAC,EAAE,uBAAuB,GAC/B,OAAO,CAAC,kBAAkB,CAAC,CAc7B;AAED,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,mBAAmB,EAC5B,MAAM,CAAC,EAAE,uBAAuB,GAC/B,OAAO,CAAC,mBAAmB,CAAC,CAoB9B"}
|
package/dist/policy.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { resolveConfig } from "./config.js";
|
|
2
|
+
/**
|
|
3
|
+
* Pure policy — no network. Mirrors scripts/twzrd_gate_agentcash_fetch.sh semantics.
|
|
4
|
+
*/
|
|
5
|
+
export function evaluateReadinessCard(input) {
|
|
6
|
+
const { card, preflightMinScore, blockDecisions, gateOnCanSpend } = input;
|
|
7
|
+
const decision = card.decision ?? "warn";
|
|
8
|
+
const score = card.trust_score ?? 0;
|
|
9
|
+
if (blockDecisions.has(decision)) {
|
|
10
|
+
return { approved: false, card, reason: `twzrd_decision_${decision}` };
|
|
11
|
+
}
|
|
12
|
+
if (gateOnCanSpend !== false && card.can_spend === false) {
|
|
13
|
+
return { approved: false, card, reason: "twzrd_can_spend_false" };
|
|
14
|
+
}
|
|
15
|
+
if (score < preflightMinScore) {
|
|
16
|
+
return {
|
|
17
|
+
approved: false,
|
|
18
|
+
card,
|
|
19
|
+
reason: `twzrd_score_${score}_below_${preflightMinScore}`,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
approved: true,
|
|
24
|
+
card,
|
|
25
|
+
reason: decision === "warn" ? "twzrd_warn_allowed" : "twzrd_allow",
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export function buildPreflightInput(context) {
|
|
29
|
+
const seller = context.sellerWallet ?? context.payTo;
|
|
30
|
+
return {
|
|
31
|
+
resource_name: context.resourceName ?? context.resourceUrl ?? "unknown_x402_resource",
|
|
32
|
+
seller_wallet: seller,
|
|
33
|
+
resource_url: context.resourceUrl,
|
|
34
|
+
price_usdc: context.priceUsdc,
|
|
35
|
+
buyer_wallet: context.buyerWallet,
|
|
36
|
+
agent_intent: context.agentIntent ?? "x402_payment_gate",
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export async function twzrdPreflight(input, config) {
|
|
40
|
+
const cfg = config ?? resolveConfig();
|
|
41
|
+
const resp = await cfg.fetch(`${cfg.intelBase}/v1/intel/preflight`, {
|
|
42
|
+
method: "POST",
|
|
43
|
+
headers: { "content-type": "application/json" },
|
|
44
|
+
body: JSON.stringify(input),
|
|
45
|
+
});
|
|
46
|
+
if (!resp.ok) {
|
|
47
|
+
throw new Error(`[twzrd] preflight HTTP ${resp.status}`);
|
|
48
|
+
}
|
|
49
|
+
const data = (await resp.json());
|
|
50
|
+
return data.readiness_card ?? data;
|
|
51
|
+
}
|
|
52
|
+
export async function twzrdApprovePayment(context, config) {
|
|
53
|
+
const cfg = config ?? resolveConfig();
|
|
54
|
+
try {
|
|
55
|
+
const card = await twzrdPreflight(buildPreflightInput(context), cfg);
|
|
56
|
+
return evaluateReadinessCard({
|
|
57
|
+
card,
|
|
58
|
+
preflightMinScore: cfg.preflightMinScore,
|
|
59
|
+
blockDecisions: cfg.blockDecisions,
|
|
60
|
+
gateOnCanSpend: cfg.gateOnCanSpend,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
if (!cfg.failOpen)
|
|
65
|
+
throw err;
|
|
66
|
+
// fail-open: preflight unreachable must not hard-block the agent's payment
|
|
67
|
+
return {
|
|
68
|
+
approved: true,
|
|
69
|
+
card: {},
|
|
70
|
+
reason: "twzrd_fail_open",
|
|
71
|
+
failOpen: true,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
export type TwzrdDecision = "allow" | "warn" | "block";
|
|
2
|
+
export type TwzrdReadinessCard = {
|
|
3
|
+
decision?: TwzrdDecision;
|
|
4
|
+
trust_score?: number;
|
|
5
|
+
can_spend?: boolean;
|
|
6
|
+
proof?: unknown;
|
|
7
|
+
caveats?: string[];
|
|
8
|
+
resource_name?: string;
|
|
9
|
+
seller_wallet?: string;
|
|
10
|
+
};
|
|
11
|
+
export type TwzrdPreflightInput = {
|
|
12
|
+
resource_name: string;
|
|
13
|
+
seller_wallet?: string;
|
|
14
|
+
resource_url?: string;
|
|
15
|
+
price_usdc?: number;
|
|
16
|
+
buyer_wallet?: string;
|
|
17
|
+
agent_intent?: string;
|
|
18
|
+
};
|
|
19
|
+
export type TwzrdGateConfig = {
|
|
20
|
+
/** Base URL without trailing slash. Default: TWZRD_INTEL_BASE or https://intel.twzrd.xyz */
|
|
21
|
+
intelBase?: string;
|
|
22
|
+
/** Block when trust_score is below this. Default: 40 */
|
|
23
|
+
preflightMinScore?: number;
|
|
24
|
+
/** decision values that deny payment. Default: ["block"] */
|
|
25
|
+
blockDecisions?: Iterable<string>;
|
|
26
|
+
/** On preflight HTTP/network failure, approve payment. Default: true */
|
|
27
|
+
failOpen?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Deny when the card reports can_spend=false. Default: true.
|
|
30
|
+
* Free-tier preflight returns can_spend=false for most sellers (including
|
|
31
|
+
* well-known ones), so set false to follow the "gate only on decision=block"
|
|
32
|
+
* policy documented for ClawRouter/BlockRun in the twzrd-clawrouter skill.
|
|
33
|
+
*/
|
|
34
|
+
gateOnCanSpend?: boolean;
|
|
35
|
+
/** Custom fetch (for tests or non-Node runtimes). Default: global fetch */
|
|
36
|
+
fetch?: typeof fetch;
|
|
37
|
+
};
|
|
38
|
+
export type TwzrdApproveContext = {
|
|
39
|
+
resourceUrl?: string;
|
|
40
|
+
resourceName?: string;
|
|
41
|
+
sellerWallet?: string;
|
|
42
|
+
payTo?: string;
|
|
43
|
+
priceUsdc?: number;
|
|
44
|
+
buyerWallet?: string;
|
|
45
|
+
agentIntent?: string;
|
|
46
|
+
};
|
|
47
|
+
export type TwzrdApprovalResult = {
|
|
48
|
+
approved: boolean;
|
|
49
|
+
card: TwzrdReadinessCard;
|
|
50
|
+
reason: string;
|
|
51
|
+
/** true when fail-open allowed payment after preflight error */
|
|
52
|
+
failOpen?: boolean;
|
|
53
|
+
};
|
|
54
|
+
export type X402PaymentRequirements = {
|
|
55
|
+
payTo?: string;
|
|
56
|
+
pay_to?: string;
|
|
57
|
+
maxAmountRequired?: string;
|
|
58
|
+
amount?: string;
|
|
59
|
+
resource?: string;
|
|
60
|
+
description?: string;
|
|
61
|
+
};
|
|
62
|
+
export type X402PaymentRequiredBody = {
|
|
63
|
+
accepts?: Array<Record<string, unknown>>;
|
|
64
|
+
x402Version?: number;
|
|
65
|
+
};
|
|
66
|
+
export type X402McpPaymentRequest = {
|
|
67
|
+
accepts?: Array<Record<string, unknown>>;
|
|
68
|
+
context?: {
|
|
69
|
+
resource?: string;
|
|
70
|
+
toolName?: string;
|
|
71
|
+
counterparty?: string;
|
|
72
|
+
sellerWallet?: string;
|
|
73
|
+
buyerWallet?: string;
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC;AAEvD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,4FAA4F;IAC5F,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wDAAwD;IACxD,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,4DAA4D;IAC5D,cAAc,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAClC,wEAAwE;IACxE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,2EAA2E;IAC3E,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,kBAAkB,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,OAAO,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACzC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACzC,OAAO,CAAC,EAAE;QACR,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;CACH,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ResolvedTwzrdGateConfig } from "./config.js";
|
|
2
|
+
/**
|
|
3
|
+
* Wrap fetch: on HTTP 402, run TWZRD preflight on payTo before caller retries with payment.
|
|
4
|
+
* Throws if policy denies; returns original 402 if approved (caller attaches payment).
|
|
5
|
+
*/
|
|
6
|
+
export declare function wrapFetchWithTwzrdGate(innerFetch: typeof fetch, config?: ResolvedTwzrdGateConfig): typeof fetch;
|
|
7
|
+
//# sourceMappingURL=wrap-fetch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wrap-fetch.d.ts","sourceRoot":"","sources":["../src/wrap-fetch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAc3D;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,OAAO,KAAK,EACxB,MAAM,CAAC,EAAE,uBAAuB,GAC/B,OAAO,KAAK,CA+Bd"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { payToFromRequirements } from "./payto.js";
|
|
2
|
+
import { twzrdApprovePayment } from "./policy.js";
|
|
3
|
+
function requestUrl(input) {
|
|
4
|
+
if (typeof input === "string")
|
|
5
|
+
return input;
|
|
6
|
+
if (input instanceof URL)
|
|
7
|
+
return input.href;
|
|
8
|
+
return input.url;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Wrap fetch: on HTTP 402, run TWZRD preflight on payTo before caller retries with payment.
|
|
12
|
+
* Throws if policy denies; returns original 402 if approved (caller attaches payment).
|
|
13
|
+
*/
|
|
14
|
+
export function wrapFetchWithTwzrdGate(innerFetch, config) {
|
|
15
|
+
return async (input, init) => {
|
|
16
|
+
const resp = await innerFetch(input, init);
|
|
17
|
+
if (resp.status !== 402)
|
|
18
|
+
return resp;
|
|
19
|
+
let body = {};
|
|
20
|
+
try {
|
|
21
|
+
body = (await resp.clone().json());
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
// 402 without a parseable x402 body — nothing to gate on; pass through
|
|
25
|
+
return resp;
|
|
26
|
+
}
|
|
27
|
+
const first = (body.accepts?.[0] ?? {});
|
|
28
|
+
const { payTo, resource } = payToFromRequirements(first);
|
|
29
|
+
const url = requestUrl(input);
|
|
30
|
+
const { approved, reason } = await twzrdApprovePayment({
|
|
31
|
+
resourceUrl: resource ?? url,
|
|
32
|
+
payTo,
|
|
33
|
+
agentIntent: "wrapFetch_402_gate",
|
|
34
|
+
}, config);
|
|
35
|
+
if (!approved) {
|
|
36
|
+
throw new Error(`[twzrd] payment blocked: ${reason} payTo=${payTo} url=${url}`);
|
|
37
|
+
}
|
|
38
|
+
return resp;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=wrap-fetch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wrap-fetch.js","sourceRoot":"","sources":["../src/wrap-fetch.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAMlD,SAAS,UAAU,CAAC,KAAiB;IACnC,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,IAAI,KAAK,YAAY,GAAG;QAAE,OAAO,KAAK,CAAC,IAAI,CAAC;IAC5C,OAAO,KAAK,CAAC,GAAG,CAAC;AACnB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CACpC,UAAwB,EACxB,MAAgC;IAEhC,OAAO,KAAK,EAAE,KAAiB,EAAE,IAAgB,EAAqB,EAAE;QACtE,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QAC3C,IAAI,IAAI,CAAC,MAAM,KAAK,GAAG;YAAE,OAAO,IAAI,CAAC;QAErC,IAAI,IAAI,GAA4B,EAAE,CAAC;QACvC,IAAI,CAAC;YACH,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,CAA4B,CAAC;QAChE,CAAC;QAAC,MAAM,CAAC;YACP,uEAAuE;YACvE,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAA4B,CAAC;QACnE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;QACzD,MAAM,GAAG,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;QAE9B,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,mBAAmB,CACpD;YACE,WAAW,EAAE,QAAQ,IAAI,GAAG;YAC5B,KAAK;YACL,WAAW,EAAE,oBAAoB;SAClC,EACD,MAAM,CACP,CAAC;QAEF,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CAAC,4BAA4B,MAAM,UAAU,KAAK,QAAQ,GAAG,EAAE,CAAC,CAAC;QAClF,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;AACJ,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "twzrd-x402-gate",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Buyer-side x402 trust gate. Run a free TWZRD preflight (ReadinessCard) before signing USDC to any x402 merchant. Wraps fetch (HTTP 402) and the @x402/mcp onPaymentRequested hook; fail-open on preflight unavailability.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"README.md"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsc",
|
|
20
|
+
"prepublishOnly": "tsc",
|
|
21
|
+
"typecheck": "tsc --noEmit",
|
|
22
|
+
"test": "tsx test/policy.test.ts && tsx test/wrap-fetch.test.ts && tsx test/mcp-hook.test.ts"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"x402",
|
|
26
|
+
"twzrd",
|
|
27
|
+
"preflight",
|
|
28
|
+
"trust",
|
|
29
|
+
"readiness-card",
|
|
30
|
+
"solana",
|
|
31
|
+
"usdc",
|
|
32
|
+
"clawrouter",
|
|
33
|
+
"blockrun",
|
|
34
|
+
"agent",
|
|
35
|
+
"mcp"
|
|
36
|
+
],
|
|
37
|
+
"homepage": "https://intel.twzrd.xyz",
|
|
38
|
+
"license": "MIT",
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">=18"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@types/node": "^20.11.0",
|
|
44
|
+
"tsx": "^4.7.0",
|
|
45
|
+
"typescript": "^5.4.0"
|
|
46
|
+
}
|
|
47
|
+
}
|