@rubric-protocol/decision-verify 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,56 @@
1
+ /**
2
+ * x402 discovery + settlement (tasks/P4.md). An unpaid request is answered with
3
+ * `svcSend402`: HTTP 402 carrying a "bazaar blob" — the discoverable payment
4
+ * requirements — computed with zero downstream (index/store) work. A settled
5
+ * (paid) response carries `extensions.bazaar`.
6
+ */
7
+ import { type VerifyResponse } from "./http.js";
8
+ export interface BazaarConfig {
9
+ resource: string;
10
+ network: string;
11
+ asset: string;
12
+ maxAmountRequired: string;
13
+ payTo: string;
14
+ description?: string;
15
+ discoveryUrl?: string;
16
+ category?: string;
17
+ }
18
+ export interface X402Accept {
19
+ scheme: "exact";
20
+ network: string;
21
+ maxAmountRequired: string;
22
+ resource: string;
23
+ description: string;
24
+ payTo: string;
25
+ asset: string;
26
+ mimeType: "application/json";
27
+ }
28
+ export interface BazaarBlob {
29
+ x402Version: 1;
30
+ accepts: X402Accept[];
31
+ bazaar: {
32
+ discoverable: true;
33
+ resource: string;
34
+ category: string;
35
+ url?: string;
36
+ };
37
+ }
38
+ /** The discoverable 402 challenge body. */
39
+ export declare function buildBazaarBlob(cfg: BazaarConfig): BazaarBlob;
40
+ /** Instant 402 (no downstream work): the discovery response. */
41
+ export declare function svcSend402(cfg: BazaarConfig): VerifyResponse;
42
+ export interface SettlementBlob {
43
+ settled: true;
44
+ resource: string;
45
+ network: string;
46
+ asset: string;
47
+ amount: string;
48
+ payer?: string;
49
+ settlementId?: string;
50
+ }
51
+ /** The `extensions.bazaar` payload attached to a settled response. */
52
+ export declare function settlementBlob(cfg: BazaarConfig, payment: {
53
+ payer?: string;
54
+ settlementId?: string;
55
+ }): SettlementBlob;
56
+ //# sourceMappingURL=bazaar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bazaar.d.ts","sourceRoot":"","sources":["../src/bazaar.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAQ,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AAEtD,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,iBAAiB,EAAE,MAAM,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,kBAAkB,CAAC;CAC9B;AAED,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,CAAC,CAAC;IACf,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,MAAM,EAAE;QAAE,YAAY,EAAE,IAAI,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAClF;AAED,2CAA2C;AAC3C,wBAAgB,eAAe,CAAC,GAAG,EAAE,YAAY,GAAG,UAAU,CAkB7D;AAED,gEAAgE;AAChE,wBAAgB,UAAU,CAAC,GAAG,EAAE,YAAY,GAAG,cAAc,CAE5D;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,IAAI,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,sEAAsE;AACtE,wBAAgB,cAAc,CAC5B,GAAG,EAAE,YAAY,EACjB,OAAO,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,GACjD,cAAc,CAWhB"}
package/dist/bazaar.js ADDED
@@ -0,0 +1,48 @@
1
+ /**
2
+ * x402 discovery + settlement (tasks/P4.md). An unpaid request is answered with
3
+ * `svcSend402`: HTTP 402 carrying a "bazaar blob" — the discoverable payment
4
+ * requirements — computed with zero downstream (index/store) work. A settled
5
+ * (paid) response carries `extensions.bazaar`.
6
+ */
7
+ import { json } from "./http.js";
8
+ /** The discoverable 402 challenge body. */
9
+ export function buildBazaarBlob(cfg) {
10
+ const accept = {
11
+ scheme: "exact",
12
+ network: cfg.network,
13
+ maxAmountRequired: cfg.maxAmountRequired,
14
+ resource: cfg.resource,
15
+ description: cfg.description ?? "Rubric decision-verify",
16
+ payTo: cfg.payTo,
17
+ asset: cfg.asset,
18
+ mimeType: "application/json",
19
+ };
20
+ const bazaar = {
21
+ discoverable: true,
22
+ resource: cfg.resource,
23
+ category: cfg.category ?? "attestation.verify",
24
+ };
25
+ if (cfg.discoveryUrl !== undefined)
26
+ bazaar.url = cfg.discoveryUrl;
27
+ return { x402Version: 1, accepts: [accept], bazaar };
28
+ }
29
+ /** Instant 402 (no downstream work): the discovery response. */
30
+ export function svcSend402(cfg) {
31
+ return json(402, buildBazaarBlob(cfg), { "www-authenticate": `x402 resource="${cfg.resource}"` });
32
+ }
33
+ /** The `extensions.bazaar` payload attached to a settled response. */
34
+ export function settlementBlob(cfg, payment) {
35
+ const blob = {
36
+ settled: true,
37
+ resource: cfg.resource,
38
+ network: cfg.network,
39
+ asset: cfg.asset,
40
+ amount: cfg.maxAmountRequired,
41
+ };
42
+ if (payment.payer !== undefined)
43
+ blob.payer = payment.payer;
44
+ if (payment.settlementId !== undefined)
45
+ blob.settlementId = payment.settlementId;
46
+ return blob;
47
+ }
48
+ //# sourceMappingURL=bazaar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bazaar.js","sourceRoot":"","sources":["../src/bazaar.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,IAAI,EAAuB,MAAM,WAAW,CAAC;AA8BtD,2CAA2C;AAC3C,MAAM,UAAU,eAAe,CAAC,GAAiB;IAC/C,MAAM,MAAM,GAAe;QACzB,MAAM,EAAE,OAAO;QACf,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,iBAAiB,EAAE,GAAG,CAAC,iBAAiB;QACxC,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,WAAW,EAAE,GAAG,CAAC,WAAW,IAAI,wBAAwB;QACxD,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,QAAQ,EAAE,kBAAkB;KAC7B,CAAC;IACF,MAAM,MAAM,GAAyB;QACnC,YAAY,EAAE,IAAI;QAClB,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,QAAQ,EAAE,GAAG,CAAC,QAAQ,IAAI,oBAAoB;KAC/C,CAAC;IACF,IAAI,GAAG,CAAC,YAAY,KAAK,SAAS;QAAE,MAAM,CAAC,GAAG,GAAG,GAAG,CAAC,YAAY,CAAC;IAClE,OAAO,EAAE,WAAW,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;AACvD,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,UAAU,CAAC,GAAiB;IAC1C,OAAO,IAAI,CAAC,GAAG,EAAE,eAAe,CAAC,GAAG,CAAC,EAAE,EAAE,kBAAkB,EAAE,kBAAkB,GAAG,CAAC,QAAQ,GAAG,EAAE,CAAC,CAAC;AACpG,CAAC;AAYD,sEAAsE;AACtE,MAAM,UAAU,cAAc,CAC5B,GAAiB,EACjB,OAAkD;IAElD,MAAM,IAAI,GAAmB;QAC3B,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,MAAM,EAAE,GAAG,CAAC,iBAAiB;KAC9B,CAAC;IACF,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS;QAAE,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IAC5D,IAAI,OAAO,CAAC,YAAY,KAAK,SAAS;QAAE,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;IACjF,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Chain-check: build a continuity report for an agent's per-agent `prev` chain
3
+ * (tasks/P4.md). Forks (a decision with >1 child) are reported as branches, and
4
+ * are explicitly NOT treated as tampering — a legitimately branched history is
5
+ * still authentic. Gaps (a `prev` pointing at an absent decision) are surfaced
6
+ * too. Actual tampering is detected per-record via the drift flag (see verify).
7
+ */
8
+ import type { ContinuityReport, IndexRow } from "./ports.js";
9
+ export declare function chainCheck(agentId: string, rows: IndexRow[]): ContinuityReport;
10
+ //# sourceMappingURL=chain.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chain.d.ts","sourceRoot":"","sources":["../src/chain.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAI7D,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,gBAAgB,CA4C9E"}
package/dist/chain.js ADDED
@@ -0,0 +1,39 @@
1
+ const byId = (rows) => new Map(rows.map((r) => [r.decisionId, r]));
2
+ export function chainCheck(agentId, rows) {
3
+ const present = byId(rows);
4
+ const childrenOf = new Map();
5
+ const referenced = new Set();
6
+ for (const r of rows) {
7
+ if (r.prev !== null) {
8
+ referenced.add(r.prev);
9
+ (childrenOf.get(r.prev) ?? childrenOf.set(r.prev, []).get(r.prev)).push(r.decisionId);
10
+ }
11
+ }
12
+ const sorted = (xs) => xs.slice().sort();
13
+ const genesis = sorted(rows.filter((r) => r.prev === null).map((r) => r.decisionId));
14
+ const heads = sorted(rows.filter((r) => !referenced.has(r.decisionId)).map((r) => r.decisionId));
15
+ const branches = [...childrenOf.entries()]
16
+ .filter(([, kids]) => kids.length > 1)
17
+ .map(([parent, kids]) => ({ parent, children: sorted(kids) }))
18
+ .sort((a, b) => (a.parent < b.parent ? -1 : 1));
19
+ const gaps = rows
20
+ .filter((r) => r.prev !== null && !present.has(r.prev))
21
+ .map((r) => ({ decisionId: r.decisionId, missingPrev: r.prev }))
22
+ .sort((a, b) => (a.decisionId < b.decisionId ? -1 : 1));
23
+ const linear = rows.length > 0 &&
24
+ genesis.length === 1 &&
25
+ heads.length === 1 &&
26
+ branches.length === 0 &&
27
+ gaps.length === 0;
28
+ return {
29
+ agentId,
30
+ count: rows.length,
31
+ genesis,
32
+ heads,
33
+ branches,
34
+ gaps,
35
+ linear,
36
+ tampering: false,
37
+ };
38
+ }
39
+ //# sourceMappingURL=chain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chain.js","sourceRoot":"","sources":["../src/chain.ts"],"names":[],"mappings":"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"}
package/dist/gate.d.ts ADDED
@@ -0,0 +1,24 @@
1
+ /**
2
+ * x402 payment gate (tasks/P4.md). Fronts a handler: an unpaid request is
3
+ * answered instantly with `svcSend402` (the bazaar discovery blob) — the wrapped
4
+ * handler, which does the index/store work, is NEVER invoked until payment is
5
+ * present, so discovery does zero DB work. A settled response carries
6
+ * `extensions.bazaar` (and an `x-payment-response` header).
7
+ */
8
+ import { type BazaarConfig } from "./bazaar.js";
9
+ import type { Handler, VerifyRequest } from "./http.js";
10
+ export declare const X402_PAYMENT_HEADER = "x-payment";
11
+ export interface PaymentResult {
12
+ paid: boolean;
13
+ payer?: string;
14
+ settlementId?: string;
15
+ }
16
+ /** Verifies a payment header. Injected + mockable; MUST NOT do DB work. */
17
+ export type PaymentVerifier = (paymentHeader: string | undefined, req: VerifyRequest) => PaymentResult;
18
+ export interface GateOptions {
19
+ bazaar: BazaarConfig;
20
+ verifyPayment: PaymentVerifier;
21
+ paymentHeader?: string;
22
+ }
23
+ export declare function gate(handler: Handler, opts: GateOptions): Handler;
24
+ //# sourceMappingURL=gate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../src/gate.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAA8B,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAC5E,OAAO,KAAK,EAAE,OAAO,EAAE,aAAa,EAAkB,MAAM,WAAW,CAAC;AAExE,eAAO,MAAM,mBAAmB,cAAc,CAAC;AAE/C,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,2EAA2E;AAC3E,MAAM,MAAM,eAAe,GAAG,CAC5B,aAAa,EAAE,MAAM,GAAG,SAAS,EACjC,GAAG,EAAE,aAAa,KACf,aAAa,CAAC;AAEnB,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,YAAY,CAAC;IACrB,aAAa,EAAE,eAAe,CAAC;IAC/B,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAMD,wBAAgB,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAoBjE"}
package/dist/gate.js ADDED
@@ -0,0 +1,32 @@
1
+ /**
2
+ * x402 payment gate (tasks/P4.md). Fronts a handler: an unpaid request is
3
+ * answered instantly with `svcSend402` (the bazaar discovery blob) — the wrapped
4
+ * handler, which does the index/store work, is NEVER invoked until payment is
5
+ * present, so discovery does zero DB work. A settled response carries
6
+ * `extensions.bazaar` (and an `x-payment-response` header).
7
+ */
8
+ import { svcSend402, settlementBlob } from "./bazaar.js";
9
+ export const X402_PAYMENT_HEADER = "x-payment";
10
+ function isObject(v) {
11
+ return typeof v === "object" && v !== null && !Array.isArray(v);
12
+ }
13
+ export function gate(handler, opts) {
14
+ const headerName = (opts.paymentHeader ?? X402_PAYMENT_HEADER).toLowerCase();
15
+ return async (req) => {
16
+ const payment = opts.verifyPayment(req.headers[headerName], req);
17
+ if (!payment.paid) {
18
+ // Discovery: instant 402 with the bazaar blob, before any downstream work.
19
+ return svcSend402(opts.bazaar);
20
+ }
21
+ const res = await handler(req);
22
+ // Settle path: attach extensions.bazaar to a successful JSON body.
23
+ if (res.status >= 200 && res.status < 300 && isObject(res.body)) {
24
+ const settle = settlementBlob(opts.bazaar, payment);
25
+ const existingExt = isObject(res.body.extensions) ? res.body.extensions : {};
26
+ res.body = { ...res.body, extensions: { ...existingExt, bazaar: settle } };
27
+ res.headers["x-payment-response"] = Buffer.from(JSON.stringify(settle), "utf8").toString("base64");
28
+ }
29
+ return res;
30
+ };
31
+ }
32
+ //# sourceMappingURL=gate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gate.js","sourceRoot":"","sources":["../src/gate.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,UAAU,EAAE,cAAc,EAAqB,MAAM,aAAa,CAAC;AAG5E,MAAM,CAAC,MAAM,mBAAmB,GAAG,WAAW,CAAC;AAoB/C,SAAS,QAAQ,CAAC,CAAU;IAC1B,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAClE,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,OAAgB,EAAE,IAAiB;IACtD,MAAM,UAAU,GAAG,CAAC,IAAI,CAAC,aAAa,IAAI,mBAAmB,CAAC,CAAC,WAAW,EAAE,CAAC;IAC7E,OAAO,KAAK,EAAE,GAAkB,EAA2B,EAAE;QAC3D,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,GAAG,CAAC,CAAC;QACjE,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YAClB,2EAA2E;YAC3E,OAAO,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACjC,CAAC;QAED,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC;QAE/B,mEAAmE;QACnE,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,MAAM,GAAG,GAAG,IAAI,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAChE,MAAM,MAAM,GAAG,cAAc,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YACpD,MAAM,WAAW,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;YAC7E,GAAG,CAAC,IAAI,GAAG,EAAE,GAAG,GAAG,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,GAAG,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC;YAC3E,GAAG,CAAC,OAAO,CAAC,oBAAoB,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACrG,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC,CAAC;AACJ,CAAC"}
package/dist/http.d.ts ADDED
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Framework-agnostic request/response shapes for the route, plus a thin Node
3
+ * `http` adapter. The route is a pure `Handler` so tests drive it directly; the
4
+ * adapter is for running it as a real server.
5
+ */
6
+ import type { IncomingMessage, ServerResponse } from "node:http";
7
+ export interface VerifyRequest {
8
+ method: string;
9
+ path: string;
10
+ query: Record<string, string | undefined>;
11
+ headers: Record<string, string | undefined>;
12
+ }
13
+ export interface VerifyResponse {
14
+ status: number;
15
+ headers: Record<string, string>;
16
+ body: unknown;
17
+ }
18
+ export type Handler = (req: VerifyRequest) => VerifyResponse | Promise<VerifyResponse>;
19
+ /** Build a JSON response. */
20
+ export declare function json(status: number, body: unknown, headers?: Record<string, string>): VerifyResponse;
21
+ /** Adapt a Handler to a Node `http` request listener. */
22
+ export declare function toNodeListener(handler: Handler): (req: IncomingMessage, res: ServerResponse) => void;
23
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEjE,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IAC1C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;CAC7C;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,MAAM,OAAO,GAAG,CAAC,GAAG,EAAE,aAAa,KAAK,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;AAEvF,6BAA6B;AAC7B,wBAAgB,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GAAG,cAAc,CAExG;AAMD,yDAAyD;AACzD,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,IACrC,KAAK,eAAe,EAAE,KAAK,cAAc,KAAG,IAAI,CAmBzD"}
package/dist/http.js ADDED
@@ -0,0 +1,30 @@
1
+ /** Build a JSON response. */
2
+ export function json(status, body, headers = {}) {
3
+ return { status, headers: { "content-type": "application/json", ...headers }, body };
4
+ }
5
+ function firstHeader(v) {
6
+ return Array.isArray(v) ? v[0] : v;
7
+ }
8
+ /** Adapt a Handler to a Node `http` request listener. */
9
+ export function toNodeListener(handler) {
10
+ return (req, res) => {
11
+ const url = new URL(req.url ?? "/", "http://localhost");
12
+ const query = {};
13
+ for (const [k, val] of url.searchParams)
14
+ query[k] = val;
15
+ const headers = {};
16
+ for (const [k, val] of Object.entries(req.headers))
17
+ headers[k.toLowerCase()] = firstHeader(val);
18
+ const request = { method: req.method ?? "GET", path: url.pathname, query, headers };
19
+ Promise.resolve(handler(request))
20
+ .then((r) => {
21
+ res.writeHead(r.status, r.headers);
22
+ res.end(typeof r.body === "string" ? r.body : JSON.stringify(r.body));
23
+ })
24
+ .catch(() => {
25
+ res.writeHead(500, { "content-type": "application/json" });
26
+ res.end(JSON.stringify({ error: "internal error" }));
27
+ });
28
+ };
29
+ }
30
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAsBA,6BAA6B;AAC7B,MAAM,UAAU,IAAI,CAAC,MAAc,EAAE,IAAa,EAAE,UAAkC,EAAE;IACtF,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,GAAG,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC;AACvF,CAAC;AAED,SAAS,WAAW,CAAC,CAAgC;IACnD,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrC,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,cAAc,CAAC,OAAgB;IAC7C,OAAO,CAAC,GAAoB,EAAE,GAAmB,EAAQ,EAAE;QACzD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,kBAAkB,CAAC,CAAC;QACxD,MAAM,KAAK,GAAuC,EAAE,CAAC;QACrD,KAAK,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,GAAG,CAAC,YAAY;YAAE,KAAK,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;QACxD,MAAM,OAAO,GAAuC,EAAE,CAAC;QACvD,KAAK,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;YAAE,OAAO,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;QAEhG,MAAM,OAAO,GAAkB,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,IAAI,KAAK,EAAE,IAAI,EAAE,GAAG,CAAC,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;QAEnG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;aAC9B,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE;YACV,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;YACnC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QACxE,CAAC,CAAC;aACD,KAAK,CAAC,GAAG,EAAE;YACV,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;YAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC,CAAC,CAAC;QACvD,CAAC,CAAC,CAAC;IACP,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @rubric-protocol/decision-verify — the x402-gated decision-verify route (tasks/P4.md).
3
+ *
4
+ * A framework-agnostic Handler that, once payment is present, verifies a DAR
5
+ * against its Merkle inclusion proof, HCS anchor ref, and service signature
6
+ * (surfacing a drift flag), or produces a chain-check continuity report.
7
+ */
8
+ export { createDecisionVerifyRoute, DECISION_VERIFY_PATH, type VerifyRouteDeps } from "./route.js";
9
+ export { gate, X402_PAYMENT_HEADER, type GateOptions, type PaymentVerifier, type PaymentResult } from "./gate.js";
10
+ export { svcSend402, buildBazaarBlob, settlementBlob, type BazaarConfig, type BazaarBlob, type SettlementBlob, } from "./bazaar.js";
11
+ export { assembleVerification } from "./verify.js";
12
+ export { chainCheck } from "./chain.js";
13
+ export { verifyMerkleProof, buildMerkleTree, nodeHash } from "./merkle.js";
14
+ export { json, toNodeListener, type VerifyRequest, type VerifyResponse, type Handler } from "./http.js";
15
+ export type { IndexPort, StorePort, SignatureVerifier, SignatureResult, VerifiableBundle, VerificationResult, VerifyStatus, MerkleProof, MerkleProofStep, AnchorRef, BatchSignature, ContinuityReport, ChainBranch, ChainGap, IndexRow, } from "./ports.js";
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,yBAAyB,EAAE,oBAAoB,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AACnG,OAAO,EAAE,IAAI,EAAE,mBAAmB,EAAE,KAAK,WAAW,EAAE,KAAK,eAAe,EAAE,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AAClH,OAAO,EACL,UAAU,EACV,eAAe,EACf,cAAc,EACd,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,cAAc,GACpB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC3E,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,aAAa,EAAE,KAAK,cAAc,EAAE,KAAK,OAAO,EAAE,MAAM,WAAW,CAAC;AACxG,YAAY,EACV,SAAS,EACT,SAAS,EACT,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EAClB,YAAY,EACZ,WAAW,EACX,eAAe,EACf,SAAS,EACT,cAAc,EACd,gBAAgB,EAChB,WAAW,EACX,QAAQ,EACR,QAAQ,GACT,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,15 @@
1
+ /**
2
+ * @rubric-protocol/decision-verify — the x402-gated decision-verify route (tasks/P4.md).
3
+ *
4
+ * A framework-agnostic Handler that, once payment is present, verifies a DAR
5
+ * against its Merkle inclusion proof, HCS anchor ref, and service signature
6
+ * (surfacing a drift flag), or produces a chain-check continuity report.
7
+ */
8
+ export { createDecisionVerifyRoute, DECISION_VERIFY_PATH } from "./route.js";
9
+ export { gate, X402_PAYMENT_HEADER } from "./gate.js";
10
+ export { svcSend402, buildBazaarBlob, settlementBlob, } from "./bazaar.js";
11
+ export { assembleVerification } from "./verify.js";
12
+ export { chainCheck } from "./chain.js";
13
+ export { verifyMerkleProof, buildMerkleTree, nodeHash } from "./merkle.js";
14
+ export { json, toNodeListener } from "./http.js";
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,yBAAyB,EAAE,oBAAoB,EAAwB,MAAM,YAAY,CAAC;AACnG,OAAO,EAAE,IAAI,EAAE,mBAAmB,EAA8D,MAAM,WAAW,CAAC;AAClH,OAAO,EACL,UAAU,EACV,eAAe,EACf,cAAc,GAIf,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC3E,OAAO,EAAE,IAAI,EAAE,cAAc,EAAyD,MAAM,WAAW,CAAC"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Merkle inclusion proofs over SHA3-256 (tasks/P4.md; interior-node hashing is
3
+ * defined by the attestation service per spec/dar-0.1.md §4.3). Leaves are DAR
4
+ * leaf hashes; interior nodes are domain-separated to prevent second-preimage
5
+ * ambiguity between leaves and internal nodes.
6
+ */
7
+ import { type HashString } from "@rubric-protocol/attest-decision";
8
+ import type { MerkleProofStep } from "./ports.js";
9
+ /** Hash an interior node from its ordered children. */
10
+ export declare function nodeHash(left: HashString, right: HashString): HashString;
11
+ /** Fold a leaf up through its proof steps and check it reproduces `root`. */
12
+ export declare function verifyMerkleProof(leaf: HashString, steps: MerkleProofStep[], root: HashString): boolean;
13
+ /**
14
+ * Build a Merkle root and an inclusion proof for every leaf. Odd levels promote
15
+ * the last node by pairing it with itself. Utility for constructing anchored
16
+ * bundles (and test fixtures); the route only needs verifyMerkleProof.
17
+ */
18
+ export declare function buildMerkleTree(leaves: HashString[]): {
19
+ root: HashString;
20
+ proofs: MerkleProofStep[][];
21
+ };
22
+ //# sourceMappingURL=merkle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merkle.d.ts","sourceRoot":"","sources":["../src/merkle.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAY,KAAK,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAC7E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAIlD,uDAAuD;AACvD,wBAAgB,QAAQ,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,GAAG,UAAU,CAExE;AAED,6EAA6E;AAC7E,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,eAAe,EAAE,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAMvG;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,eAAe,EAAE,EAAE,CAAA;CAAE,CAgCvG"}
package/dist/merkle.js ADDED
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Merkle inclusion proofs over SHA3-256 (tasks/P4.md; interior-node hashing is
3
+ * defined by the attestation service per spec/dar-0.1.md §4.3). Leaves are DAR
4
+ * leaf hashes; interior nodes are domain-separated to prevent second-preimage
5
+ * ambiguity between leaves and internal nodes.
6
+ */
7
+ import { sha3_256 } from "@rubric-protocol/attest-decision";
8
+ const NODE_DOMAIN = "rubric-merkle-node/1\n";
9
+ /** Hash an interior node from its ordered children. */
10
+ export function nodeHash(left, right) {
11
+ return sha3_256(`${NODE_DOMAIN}${left}\n${right}`);
12
+ }
13
+ /** Fold a leaf up through its proof steps and check it reproduces `root`. */
14
+ export function verifyMerkleProof(leaf, steps, root) {
15
+ let acc = leaf;
16
+ for (const step of steps) {
17
+ acc = step.position === "left" ? nodeHash(step.sibling, acc) : nodeHash(acc, step.sibling);
18
+ }
19
+ return acc === root;
20
+ }
21
+ /**
22
+ * Build a Merkle root and an inclusion proof for every leaf. Odd levels promote
23
+ * the last node by pairing it with itself. Utility for constructing anchored
24
+ * bundles (and test fixtures); the route only needs verifyMerkleProof.
25
+ */
26
+ export function buildMerkleTree(leaves) {
27
+ if (leaves.length === 0)
28
+ throw new Error("merkle: cannot build a tree over zero leaves");
29
+ const proofs = leaves.map(() => []);
30
+ // indexAtLevel[i] tracks where original leaf i currently sits in `level`.
31
+ let level = leaves.slice();
32
+ let positions = leaves.map((_, i) => i);
33
+ while (level.length > 1) {
34
+ const next = [];
35
+ const nextPositions = positions.map(() => 0);
36
+ for (let i = 0; i < level.length; i += 2) {
37
+ const left = level[i];
38
+ const right = i + 1 < level.length ? level[i + 1] : level[i]; // promote odd tail
39
+ const parent = nodeHash(left, right);
40
+ const parentIdx = next.length;
41
+ next.push(parent);
42
+ for (let li = 0; li < positions.length; li++) {
43
+ if (positions[li] === i) {
44
+ proofs[li].push({ sibling: right, position: "right" });
45
+ nextPositions[li] = parentIdx;
46
+ }
47
+ else if (positions[li] === i + 1) {
48
+ proofs[li].push({ sibling: left, position: "left" });
49
+ nextPositions[li] = parentIdx;
50
+ }
51
+ }
52
+ }
53
+ level = next;
54
+ positions = nextPositions;
55
+ }
56
+ return { root: level[0], proofs };
57
+ }
58
+ //# sourceMappingURL=merkle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merkle.js","sourceRoot":"","sources":["../src/merkle.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Ports and wire types for the decision-verify route (tasks/P4.md).
3
+ *
4
+ * The route depends only on these interfaces, so tests inject in-memory mocks
5
+ * for the index and store ("route tests green on mocked index+store").
6
+ */
7
+ import type { DarCore, HashString } from "@rubric-protocol/attest-decision";
8
+ import type { IndexRow } from "@rubric-protocol/attest-index";
9
+ export type { IndexRow };
10
+ /** A Merkle inclusion proof step: a sibling hash and which side it sits on. */
11
+ export interface MerkleProofStep {
12
+ sibling: HashString;
13
+ position: "left" | "right";
14
+ }
15
+ /** Inclusion proof from a leaf up to a published root. */
16
+ export interface MerkleProof {
17
+ leaf: HashString;
18
+ steps: MerkleProofStep[];
19
+ root: HashString;
20
+ }
21
+ /** Reference to the on-chain (HCS) anchor that committed a Merkle root. */
22
+ export interface AnchorRef {
23
+ network: string;
24
+ topicId: string;
25
+ sequenceNumber: number;
26
+ root: HashString;
27
+ consensusTimestamp?: string;
28
+ }
29
+ /** Service signature over an anchored root. */
30
+ export interface BatchSignature {
31
+ alg: string;
32
+ keyRef: string;
33
+ signature: string;
34
+ over: HashString;
35
+ }
36
+ /** A stored bundle: the DAR core plus the attestation envelope (spec §6). */
37
+ export interface VerifiableBundle {
38
+ attestationId: string;
39
+ dar: DarCore;
40
+ merkleProof: MerkleProof;
41
+ anchorRef: AnchorRef;
42
+ signature: BatchSignature;
43
+ }
44
+ /** Index port — row lookups by decisionId/decisionHash and per-agent chains. */
45
+ export interface IndexPort {
46
+ byDecisionId(decisionId: string): IndexRow | undefined;
47
+ byDecisionHash(decisionHash: string): IndexRow | undefined;
48
+ agentChain(agentId: string): IndexRow[];
49
+ }
50
+ /** Store port — load a full bundle by its path. */
51
+ export interface StorePort {
52
+ get(bundlePath: string): VerifiableBundle | undefined;
53
+ }
54
+ export interface SignatureResult {
55
+ verified: boolean;
56
+ keyRef: string;
57
+ }
58
+ /** Verifies a service signature over an anchored root. Injected (mockable). */
59
+ export type SignatureVerifier = (signature: BatchSignature, root: HashString) => SignatureResult;
60
+ /** Version gate outcome (spec §5.1). */
61
+ export type VerifyStatus = "ok" | "needs-upgrade" | "rejected";
62
+ /** The decision-verify result body. */
63
+ export interface VerificationResult {
64
+ decisionId: string;
65
+ dar: DarCore;
66
+ merkleProof: MerkleProof;
67
+ anchorRef: AnchorRef;
68
+ signature: SignatureResult;
69
+ /** True when the record no longer matches the proof/root carried in its bundle (tampering). */
70
+ drift: boolean;
71
+ /**
72
+ * Version gate per spec §5.1: `rejected` (unknown DAR major or bad leafType),
73
+ * `needs-upgrade` (known major but a newer minor this verifier can't fully
74
+ * check), or `ok` (this verifier fully understands the record's version).
75
+ */
76
+ status: VerifyStatus;
77
+ /**
78
+ * INTERNAL CONSISTENCY ONLY. True iff status is `ok`, there is no drift, and
79
+ * the supplied signature verified. This attests that the bundle is internally
80
+ * self-consistent — it is NOT proof that the Merkle root was anchored on HCS,
81
+ * nor that the signing key is trusted. Those require the (out-of-scope)
82
+ * attestation service; this route does not contact any ledger.
83
+ */
84
+ consistencyVerified: boolean;
85
+ }
86
+ /** A fork point: a decision with more than one child in the chain. */
87
+ export interface ChainBranch {
88
+ parent: string;
89
+ children: string[];
90
+ }
91
+ /** A break where a record's `prev` points at a decision absent from the index. */
92
+ export interface ChainGap {
93
+ decisionId: string;
94
+ missingPrev: string;
95
+ }
96
+ /** Continuity report for an agent's chain (tasks/P4.md). */
97
+ export interface ContinuityReport {
98
+ agentId: string;
99
+ count: number;
100
+ genesis: string[];
101
+ heads: string[];
102
+ branches: ChainBranch[];
103
+ gaps: ChainGap[];
104
+ /** True iff a single unbroken linear chain (one genesis, one head, no forks/gaps). */
105
+ linear: boolean;
106
+ /** Forks and gaps are structural, not tampering — always false here. */
107
+ tampering: false;
108
+ }
109
+ //# sourceMappingURL=ports.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ports.d.ts","sourceRoot":"","sources":["../src/ports.ts"],"names":[],"mappings":"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"}
package/dist/ports.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ports.js","sourceRoot":"","sources":["../src/ports.ts"],"names":[],"mappings":""}
@@ -0,0 +1,15 @@
1
+ import { type PaymentVerifier } from "./gate.js";
2
+ import { type Handler } from "./http.js";
3
+ import type { BazaarConfig } from "./bazaar.js";
4
+ import type { IndexPort, SignatureVerifier, StorePort } from "./ports.js";
5
+ export declare const DECISION_VERIFY_PATH = "/v1/x402/decision-verify";
6
+ export interface VerifyRouteDeps {
7
+ index: IndexPort;
8
+ store: StorePort;
9
+ verifySignature: SignatureVerifier;
10
+ bazaar: BazaarConfig;
11
+ verifyPayment: PaymentVerifier;
12
+ }
13
+ /** Build the gate()-fronted route handler. */
14
+ export declare function createDecisionVerifyRoute(deps: VerifyRouteDeps): Handler;
15
+ //# sourceMappingURL=route.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../src/route.ts"],"names":[],"mappings":"AASA,OAAO,EAAQ,KAAK,eAAe,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAQ,KAAK,OAAO,EAA2C,MAAM,WAAW,CAAC;AACxF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE1E,eAAO,MAAM,oBAAoB,6BAA6B,CAAC;AAE/D,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,SAAS,CAAC;IACjB,KAAK,EAAE,SAAS,CAAC;IACjB,eAAe,EAAE,iBAAiB,CAAC;IACnC,MAAM,EAAE,YAAY,CAAC;IACrB,aAAa,EAAE,eAAe,CAAC;CAChC;AA4BD,8CAA8C;AAC9C,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAGxE"}
package/dist/route.js ADDED
@@ -0,0 +1,41 @@
1
+ /**
2
+ * The gate()-fronted /v1/x402/decision-verify route (tasks/P4.md).
3
+ *
4
+ * Query:
5
+ * ?decisionId=... | ?decisionHash=... -> single-record verification
6
+ * ?agentId=... (or ?mode=chain) -> chain-check continuity report
7
+ */
8
+ import { assembleVerification } from "./verify.js";
9
+ import { chainCheck } from "./chain.js";
10
+ import { gate } from "./gate.js";
11
+ import { json } from "./http.js";
12
+ export const DECISION_VERIFY_PATH = "/v1/x402/decision-verify";
13
+ /** The paid handler — this is where index/store work happens. */
14
+ function decisionVerify(req, deps) {
15
+ const { decisionId, decisionHash, agentId, mode } = req.query;
16
+ if (mode === "chain" || agentId) {
17
+ if (!agentId)
18
+ return json(400, { error: "agentId is required for chain-check" });
19
+ return json(200, chainCheck(agentId, deps.index.agentChain(agentId)));
20
+ }
21
+ const row = decisionId
22
+ ? deps.index.byDecisionId(decisionId)
23
+ : decisionHash
24
+ ? deps.index.byDecisionHash(decisionHash)
25
+ : undefined;
26
+ if (!decisionId && !decisionHash) {
27
+ return json(400, { error: "decisionId or decisionHash is required" });
28
+ }
29
+ if (!row)
30
+ return json(404, { error: "decision not found" });
31
+ const bundle = deps.store.get(row.bundlePath);
32
+ if (!bundle)
33
+ return json(502, { error: "bundle missing from store", bundlePath: row.bundlePath });
34
+ return json(200, assembleVerification(bundle, deps.verifySignature));
35
+ }
36
+ /** Build the gate()-fronted route handler. */
37
+ export function createDecisionVerifyRoute(deps) {
38
+ const handler = (req) => decisionVerify(req, deps);
39
+ return gate(handler, { bazaar: deps.bazaar, verifyPayment: deps.verifyPayment });
40
+ }
41
+ //# sourceMappingURL=route.js.map