yieldagentx402-verify 1.0.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/LICENSE ADDED
@@ -0,0 +1,9 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 YieldAgentX402
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,72 @@
1
+ # yieldagentx402-verify
2
+
3
+ > Zero-dependency verifier for YieldAgentX402 receipts and webhook signatures.
4
+ > Works in **browser, Node 18+, Cloudflare Workers, Deno**.
5
+
6
+ [Docs](https://yieldagentx402.app/mcp-server) · [Verify page](https://yieldagentx402.app/verify) · [npm](https://www.npmjs.com/package/yieldagentx402-verify)
7
+
8
+ ## Install
9
+
10
+ ```bash
11
+ npm install yieldagentx402-verify
12
+ ```
13
+
14
+ ## Verify a receipt
15
+
16
+ ```js
17
+ import { verifyReceipt } from "yieldagentx402-verify";
18
+
19
+ const result = await verifyReceipt({
20
+ secret: process.env.YAX_WEBHOOK_SECRET,
21
+ receipt: receiptObjectFromGateway,
22
+ signature: receiptObjectFromGateway.receipt_signature,
23
+ });
24
+
25
+ if (result.ok) console.log("Receipt is genuine ✓");
26
+ else console.warn("Receipt failed verification:", result);
27
+ ```
28
+
29
+ ## Verify a webhook
30
+
31
+ ```js
32
+ import { verifyWebhook } from "yieldagentx402-verify";
33
+
34
+ // In your webhook handler:
35
+ const rawBody = await request.text();
36
+ const result = await verifyWebhook({
37
+ secret: process.env.YAX_WEBHOOK_SECRET,
38
+ body: rawBody,
39
+ signature: request.headers, // pass Headers directly
40
+ });
41
+
42
+ if (!result.ok) return new Response("invalid sig", { status: 401 });
43
+ const event = JSON.parse(rawBody);
44
+ // process event.run_id, event.status, event.receipt_signature ...
45
+ ```
46
+
47
+ ## Fetch + verify in one call
48
+
49
+ ```js
50
+ import { fetchAndVerifyReceipt } from "yieldagentx402-verify";
51
+
52
+ const { verified, receipt } = await fetchAndVerifyReceipt({
53
+ runId: "run_abc123",
54
+ secret: process.env.YAX_WEBHOOK_SECRET,
55
+ apiKey: process.env.YAX_API_KEY,
56
+ });
57
+
58
+ console.log(verified ? "✓ anchored + signed" : "⚠ not verified");
59
+ ```
60
+
61
+ ## Why this lib exists
62
+
63
+ YieldAgentX402 receipts are HMAC-SHA256 signatures over canonical receipt JSON. The signing happens inside an Intel TDX TEE, and the proof is anchored to Filecoin + BTFS. This package gives you a tiny, audit-able client to verify the signature yourself — **no trust in the YAX gateway required**.
64
+
65
+ - **0 runtime deps** — uses WebCrypto only
66
+ - **Timing-safe equality** — no leaks
67
+ - **TypeScript types included**
68
+ - **Works everywhere** — browser, Node, Workers, Deno
69
+
70
+ ## License
71
+
72
+ MIT
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "yieldagentx402-verify",
3
+ "version": "1.0.0",
4
+ "description": "Zero-dependency verifier for YieldAgentX402 receipts and webhook signatures. Works in browser, Node 18+, Cloudflare Workers, and Deno.",
5
+ "type": "module",
6
+ "main": "./src/index.js",
7
+ "module": "./src/index.js",
8
+ "types": "./src/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./src/index.d.ts",
12
+ "import": "./src/index.js"
13
+ }
14
+ },
15
+ "files": ["src", "README.md", "LICENSE"],
16
+ "scripts": {
17
+ "test": "node --test test/*.test.js"
18
+ },
19
+ "keywords": [
20
+ "yieldagentx402","yax","mcp","x402","receipt","verify","hmac","filecoin","webhook","agent-payments"
21
+ ],
22
+ "author": "YieldAgentX402",
23
+ "license": "MIT",
24
+ "homepage": "https://yieldagentx402.app/mcp-server",
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "git+https://github.com/Fabio662/Yieldagenticx402-Hub.git",
28
+ "directory": "integrations/verify-lib"
29
+ },
30
+ "publishConfig": { "access": "public" },
31
+ "engines": { "node": ">=18" }
32
+ }
package/src/index.d.ts ADDED
@@ -0,0 +1,33 @@
1
+ export interface VerifyResult {
2
+ ok: boolean;
3
+ computed: string;
4
+ provided: string;
5
+ reason?: string;
6
+ }
7
+
8
+ export interface VerifyReceiptOpts {
9
+ secret: string;
10
+ receipt: Record<string, unknown> | string;
11
+ signature: string;
12
+ }
13
+ export function verifyReceipt(opts: VerifyReceiptOpts): Promise<VerifyResult>;
14
+
15
+ export interface VerifyWebhookOpts {
16
+ secret: string;
17
+ body: string | ArrayBuffer | Uint8Array;
18
+ signature: string | Headers;
19
+ }
20
+ export function verifyWebhook(opts: VerifyWebhookOpts): Promise<VerifyResult>;
21
+
22
+ export interface FetchAndVerifyOpts {
23
+ runId: string;
24
+ secret: string;
25
+ apiKey?: string;
26
+ endpoint?: string;
27
+ }
28
+ export function fetchAndVerifyReceipt(opts: FetchAndVerifyOpts): Promise<{
29
+ ok: boolean;
30
+ receipt: Record<string, unknown> | null;
31
+ verified: boolean;
32
+ reason?: string;
33
+ }>;
package/src/index.js ADDED
@@ -0,0 +1,116 @@
1
+ // @yieldagentx402/verify — zero-dep receipt + webhook signature verifier.
2
+ // Browser-safe (WebCrypto), Node 18+, Cloudflare Workers, Deno.
3
+
4
+ const enc = new TextEncoder();
5
+
6
+ function hexToBytes(hex) {
7
+ const h = String(hex || "").replace(/^0x/i, "").toLowerCase();
8
+ if (h.length % 2 !== 0 || /[^0-9a-f]/.test(h)) throw new Error("invalid hex");
9
+ const out = new Uint8Array(h.length / 2);
10
+ for (let i = 0; i < out.length; i++) out[i] = parseInt(h.slice(i*2, i*2+2), 16);
11
+ return out;
12
+ }
13
+ function bytesToHex(buf) {
14
+ return Array.from(new Uint8Array(buf), b => b.toString(16).padStart(2, "0")).join("");
15
+ }
16
+ function timingSafeEqualHex(a, b) {
17
+ const A = String(a || "").toLowerCase();
18
+ const B = String(b || "").toLowerCase();
19
+ if (A.length !== B.length) return false;
20
+ let diff = 0;
21
+ for (let i = 0; i < A.length; i++) diff |= A.charCodeAt(i) ^ B.charCodeAt(i);
22
+ return diff === 0;
23
+ }
24
+
25
+ async function hmacSha256Hex(secret, message) {
26
+ const key = await crypto.subtle.importKey(
27
+ "raw", enc.encode(String(secret)),
28
+ { name: "HMAC", hash: "SHA-256" }, false, ["sign"]
29
+ );
30
+ const sig = await crypto.subtle.sign("HMAC", key,
31
+ typeof message === "string" ? enc.encode(message) : message
32
+ );
33
+ return bytesToHex(sig);
34
+ }
35
+
36
+ /**
37
+ * Verify a YAX receipt signature.
38
+ *
39
+ * @param {object} opts
40
+ * @param {string} opts.secret - The shared HMAC secret. Issued with your prod API key.
41
+ * @param {object|string} opts.receipt - Receipt payload. If an object, JSON-stringified canonically.
42
+ * @param {string} opts.signature - Signature string from receipt_signature. Accepts:
43
+ * "hmac-sha256=<hex>", "<hex>", or "0x<hex>".
44
+ * @returns {Promise<{ok:boolean, computed:string, provided:string, reason?:string}>}
45
+ */
46
+ export async function verifyReceipt({ secret, receipt, signature }) {
47
+ if (!secret) return { ok: false, computed: "", provided: "", reason: "missing secret" };
48
+ if (!signature) return { ok: false, computed: "", provided: "", reason: "missing signature" };
49
+
50
+ const body = typeof receipt === "string"
51
+ ? receipt
52
+ : JSON.stringify(receipt, Object.keys(receipt).sort());
53
+ const sig = String(signature).replace(/^hmac-sha256=/i, "").replace(/^0x/, "").toLowerCase();
54
+ const computed = await hmacSha256Hex(secret, body);
55
+ return {
56
+ ok: timingSafeEqualHex(computed, sig),
57
+ computed,
58
+ provided: sig,
59
+ };
60
+ }
61
+
62
+ /**
63
+ * Verify an incoming webhook from YieldAgentX402.
64
+ * Reads the X-YAX-Signature header (or `signature` opt) and checks against the raw body.
65
+ *
66
+ * @param {object} opts
67
+ * @param {string} opts.secret - YAX_WEBHOOK_SECRET shared with you on production key issuance.
68
+ * @param {string|ArrayBuffer|Uint8Array} opts.body - Raw HTTP body (string preferred).
69
+ * @param {string|Headers} opts.signature - Either "hmac-sha256=<hex>" or a Headers object containing X-YAX-Signature.
70
+ * @returns {Promise<{ok:boolean, computed:string, provided:string, reason?:string}>}
71
+ */
72
+ export async function verifyWebhook({ secret, body, signature }) {
73
+ if (!secret) return { ok: false, computed: "", provided: "", reason: "missing secret" };
74
+ let sigStr = signature;
75
+ if (signature && typeof signature === "object" && typeof signature.get === "function") {
76
+ sigStr = signature.get("X-YAX-Signature") || signature.get("x-yax-signature");
77
+ }
78
+ if (!sigStr) return { ok: false, computed: "", provided: "", reason: "missing X-YAX-Signature header" };
79
+ const sig = String(sigStr).replace(/^hmac-sha256=/i, "").replace(/^0x/, "").toLowerCase();
80
+ const bodyStr = typeof body === "string" ? body :
81
+ body instanceof Uint8Array ? new TextDecoder().decode(body) :
82
+ body instanceof ArrayBuffer ? new TextDecoder().decode(new Uint8Array(body)) :
83
+ String(body);
84
+ const computed = await hmacSha256Hex(secret, bodyStr);
85
+ return {
86
+ ok: timingSafeEqualHex(computed, sig),
87
+ computed,
88
+ provided: sig,
89
+ };
90
+ }
91
+
92
+ /**
93
+ * Convenience: fetch a receipt from the YAX gateway and verify it in one call.
94
+ *
95
+ * @param {object} opts
96
+ * @param {string} opts.runId
97
+ * @param {string} opts.secret
98
+ * @param {string} [opts.apiKey] - Required for non-public receipts.
99
+ * @param {string} [opts.endpoint] - Defaults to https://api.yieldagentx402.app
100
+ * @returns {Promise<{ok:boolean, receipt:object|null, verified:boolean, reason?:string}>}
101
+ */
102
+ export async function fetchAndVerifyReceipt({ runId, secret, apiKey, endpoint }) {
103
+ const base = String(endpoint || "https://api.yieldagentx402.app").replace(/\/+$/, "");
104
+ const headers = { "Content-Type": "application/json" };
105
+ if (apiKey) headers["Authorization"] = `Bearer ${apiKey}`;
106
+ const r = await fetch(`${base}/api/orchestration/runs/${encodeURIComponent(runId)}`, { headers });
107
+ if (!r.ok) return { ok: false, receipt: null, verified: false, reason: `HTTP ${r.status}` };
108
+ const d = await r.json();
109
+ const run = d.run || d;
110
+ const sig = run.receipt_signature;
111
+ if (!sig) return { ok: true, receipt: run, verified: false, reason: "receipt has no signature yet" };
112
+ const v = await verifyReceipt({ secret, receipt: run, signature: sig });
113
+ return { ok: true, receipt: run, verified: v.ok };
114
+ }
115
+
116
+ export default { verifyReceipt, verifyWebhook, fetchAndVerifyReceipt };