@fatstack/x402 0.0.1 → 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.
@@ -0,0 +1,99 @@
1
+ import { RouteConfig, FacilitatorClient } from '@x402/core/server';
2
+ export { FacilitatorClient, RouteConfig } from '@x402/core/server';
3
+ import { z } from 'zod';
4
+
5
+ declare const optionsSchema: z.ZodObject<{
6
+ /** Price per call in USD, as a decimal string: "0.002". */
7
+ price: z.ZodString;
8
+ /** The provider's own wallet. Under FEE_MODE=direct this is the sole payee. */
9
+ wallet: z.ZodString;
10
+ toolId: z.ZodString;
11
+ network: z.ZodDefault<z.ZodEnum<["base", "base-sepolia"]>>;
12
+ description: z.ZodOptional<z.ZodString>;
13
+ docsUrl: z.ZodDefault<z.ZodString>;
14
+ mimeType: z.ZodDefault<z.ZodString>;
15
+ maxTimeoutSeconds: z.ZodDefault<z.ZodNumber>;
16
+ }, "strip", z.ZodTypeAny, {
17
+ network: "base" | "base-sepolia";
18
+ price: string;
19
+ wallet: string;
20
+ toolId: string;
21
+ docsUrl: string;
22
+ mimeType: string;
23
+ maxTimeoutSeconds: number;
24
+ description?: string | undefined;
25
+ }, {
26
+ price: string;
27
+ wallet: string;
28
+ toolId: string;
29
+ network?: "base" | "base-sepolia" | undefined;
30
+ description?: string | undefined;
31
+ docsUrl?: string | undefined;
32
+ mimeType?: string | undefined;
33
+ maxTimeoutSeconds?: number | undefined;
34
+ }>;
35
+ interface PaywallOptions extends z.input<typeof optionsSchema> {
36
+ /** Defaults to process.env. */
37
+ env?: Record<string, string | undefined>;
38
+ /** Injects a facilitator instead of building an HTTP one. Used by tests. */
39
+ facilitator?: FacilitatorClient;
40
+ }
41
+ /** The 402 body an agent reads before deciding to pay. */
42
+ interface UnpaidBody {
43
+ error: 'payment_required';
44
+ tool: string;
45
+ price: {
46
+ usdc: string;
47
+ amountAtomic: string;
48
+ asset: string;
49
+ network: string;
50
+ };
51
+ payTo: string;
52
+ terms: {
53
+ refundable: false;
54
+ notice: string;
55
+ };
56
+ docs: string;
57
+ message: string;
58
+ }
59
+ /** Structurally compatible with Hono's `MiddlewareHandler`, without importing hono. */
60
+ interface HonoContextLike {
61
+ json: (body: unknown, status?: number) => Response;
62
+ res: Response;
63
+ req: {
64
+ raw: Request;
65
+ };
66
+ }
67
+ type HonoMiddleware = (c: HonoContextLike, next: () => Promise<void>) => Promise<Response | void>;
68
+ /** Structurally compatible with an Express request handler. */
69
+ interface ExpressResponseLike {
70
+ status: (code: number) => {
71
+ json: (body: unknown) => void;
72
+ };
73
+ setHeader: (name: string, value: string | number | readonly string[]) => unknown;
74
+ }
75
+ type ExpressMiddleware = (req: unknown, res: ExpressResponseLike, next: (err?: unknown) => void) => Promise<void>;
76
+ interface Paywall {
77
+ /** Hono middleware. Requires @x402/hono. */
78
+ hono(): HonoMiddleware;
79
+ /** Express middleware. Requires @x402/express. */
80
+ express(): ExpressMiddleware;
81
+ /** Wraps a Next.js route handler. Requires @x402/next (which needs Next >= 16.2.6). */
82
+ next<T>(handler: (request: never) => Promise<T>): (request: never) => Promise<T>;
83
+ /** The x402 route config, for advanced use with the official adapters directly. */
84
+ routeConfig: RouteConfig;
85
+ /** Resolved payee. Always the provider wallet while FEE_MODE=direct. */
86
+ payTo: string;
87
+ }
88
+ /**
89
+ * Paywalls a route with x402: USDC on Base, paid directly to the provider's wallet.
90
+ *
91
+ * Verification and settlement are delegated to the official x402 packages against the
92
+ * hosted facilitator — this module does not sign or verify anything itself.
93
+ *
94
+ * Throws immediately when FEE_MODE=splitter: there is no splitter contract in this build,
95
+ * and silently falling back to `direct` would pay the wrong party.
96
+ */
97
+ declare function paywall(options: PaywallOptions): Paywall;
98
+
99
+ export { type ExpressMiddleware, type ExpressResponseLike, type HonoContextLike, type HonoMiddleware, type Paywall, type PaywallOptions, type UnpaidBody, paywall };
@@ -0,0 +1,8 @@
1
+ import {
2
+ paywall
3
+ } from "./chunk-7DVR574O.js";
4
+ import "./chunk-6LSPHKJ7.js";
5
+ export {
6
+ paywall
7
+ };
8
+ //# sourceMappingURL=provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/testing.ts
21
+ var testing_exports = {};
22
+ __export(testing_exports, {
23
+ createMockFacilitator: () => createMockFacilitator
24
+ });
25
+ module.exports = __toCommonJS(testing_exports);
26
+ function createMockFacilitator(options = {}) {
27
+ let verifyCalls = 0;
28
+ let settleCalls = 0;
29
+ return {
30
+ async verify() {
31
+ verifyCalls += 1;
32
+ return options.invalidReason ? { isValid: false, invalidReason: options.invalidReason } : { isValid: true, payer: options.payer ?? "0x2222222222222222222222222222222222222222" };
33
+ },
34
+ async settle() {
35
+ settleCalls += 1;
36
+ if (options.settleErrorReason) {
37
+ return {
38
+ success: false,
39
+ errorReason: options.settleErrorReason,
40
+ transaction: "",
41
+ network: "eip155:8453"
42
+ };
43
+ }
44
+ return {
45
+ success: true,
46
+ transaction: options.transaction ?? `0x${"ab".repeat(32)}`,
47
+ network: "eip155:8453",
48
+ payer: options.payer ?? "0x2222222222222222222222222222222222222222"
49
+ };
50
+ },
51
+ async getSupported() {
52
+ return {
53
+ kinds: [
54
+ { x402Version: 2, scheme: "exact", network: "eip155:8453" },
55
+ { x402Version: 2, scheme: "exact", network: "eip155:84532" }
56
+ ],
57
+ extensions: [],
58
+ signers: {}
59
+ };
60
+ },
61
+ get verifyCalls() {
62
+ return verifyCalls;
63
+ },
64
+ get settleCalls() {
65
+ return settleCalls;
66
+ }
67
+ };
68
+ }
69
+ // Annotate the CommonJS export names for ESM import in node:
70
+ 0 && (module.exports = {
71
+ createMockFacilitator
72
+ });
73
+ //# sourceMappingURL=testing.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/testing.ts"],"sourcesContent":["import type { FacilitatorClient } from '@x402/core/server';\n\nexport interface MockFacilitatorOptions {\n /** Reject verification with this reason instead of accepting. */\n invalidReason?: string;\n /** Fail settlement with this reason after a successful verify. */\n settleErrorReason?: string;\n transaction?: string;\n payer?: string;\n}\n\nexport interface MockFacilitator extends FacilitatorClient {\n readonly verifyCalls: number;\n readonly settleCalls: number;\n}\n\n/**\n * A facilitator stand-in for tests. Nothing here talks to a chain or a network: the\n * official packages own signing and verification, so what we exercise is our own\n * behaviour around their results.\n */\nexport function createMockFacilitator(options: MockFacilitatorOptions = {}): MockFacilitator {\n let verifyCalls = 0;\n let settleCalls = 0;\n\n return {\n async verify() {\n verifyCalls += 1;\n return options.invalidReason\n ? { isValid: false, invalidReason: options.invalidReason }\n : { isValid: true, payer: options.payer ?? '0x2222222222222222222222222222222222222222' };\n },\n async settle() {\n settleCalls += 1;\n if (options.settleErrorReason) {\n return {\n success: false,\n errorReason: options.settleErrorReason,\n transaction: '',\n network: 'eip155:8453',\n };\n }\n return {\n success: true,\n transaction: options.transaction ?? `0x${'ab'.repeat(32)}`,\n network: 'eip155:8453',\n payer: options.payer ?? '0x2222222222222222222222222222222222222222',\n };\n },\n async getSupported() {\n return {\n kinds: [\n { x402Version: 2, scheme: 'exact', network: 'eip155:8453' },\n { x402Version: 2, scheme: 'exact', network: 'eip155:84532' },\n ],\n extensions: [],\n signers: {},\n };\n },\n get verifyCalls() {\n return verifyCalls;\n },\n get settleCalls() {\n return settleCalls;\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAqBO,SAAS,sBAAsB,UAAkC,CAAC,GAAoB;AAC3F,MAAI,cAAc;AAClB,MAAI,cAAc;AAElB,SAAO;AAAA,IACL,MAAM,SAAS;AACb,qBAAe;AACf,aAAO,QAAQ,gBACX,EAAE,SAAS,OAAO,eAAe,QAAQ,cAAc,IACvD,EAAE,SAAS,MAAM,OAAO,QAAQ,SAAS,6CAA6C;AAAA,IAC5F;AAAA,IACA,MAAM,SAAS;AACb,qBAAe;AACf,UAAI,QAAQ,mBAAmB;AAC7B,eAAO;AAAA,UACL,SAAS;AAAA,UACT,aAAa,QAAQ;AAAA,UACrB,aAAa;AAAA,UACb,SAAS;AAAA,QACX;AAAA,MACF;AACA,aAAO;AAAA,QACL,SAAS;AAAA,QACT,aAAa,QAAQ,eAAe,KAAK,KAAK,OAAO,EAAE,CAAC;AAAA,QACxD,SAAS;AAAA,QACT,OAAO,QAAQ,SAAS;AAAA,MAC1B;AAAA,IACF;AAAA,IACA,MAAM,eAAe;AACnB,aAAO;AAAA,QACL,OAAO;AAAA,UACL,EAAE,aAAa,GAAG,QAAQ,SAAS,SAAS,cAAc;AAAA,UAC1D,EAAE,aAAa,GAAG,QAAQ,SAAS,SAAS,eAAe;AAAA,QAC7D;AAAA,QACA,YAAY,CAAC;AAAA,QACb,SAAS,CAAC;AAAA,MACZ;AAAA,IACF;AAAA,IACA,IAAI,cAAc;AAChB,aAAO;AAAA,IACT;AAAA,IACA,IAAI,cAAc;AAChB,aAAO;AAAA,IACT;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,22 @@
1
+ import { FacilitatorClient } from '@x402/core/server';
2
+
3
+ interface MockFacilitatorOptions {
4
+ /** Reject verification with this reason instead of accepting. */
5
+ invalidReason?: string;
6
+ /** Fail settlement with this reason after a successful verify. */
7
+ settleErrorReason?: string;
8
+ transaction?: string;
9
+ payer?: string;
10
+ }
11
+ interface MockFacilitator extends FacilitatorClient {
12
+ readonly verifyCalls: number;
13
+ readonly settleCalls: number;
14
+ }
15
+ /**
16
+ * A facilitator stand-in for tests. Nothing here talks to a chain or a network: the
17
+ * official packages own signing and verification, so what we exercise is our own
18
+ * behaviour around their results.
19
+ */
20
+ declare function createMockFacilitator(options?: MockFacilitatorOptions): MockFacilitator;
21
+
22
+ export { type MockFacilitator, type MockFacilitatorOptions, createMockFacilitator };
@@ -0,0 +1,22 @@
1
+ import { FacilitatorClient } from '@x402/core/server';
2
+
3
+ interface MockFacilitatorOptions {
4
+ /** Reject verification with this reason instead of accepting. */
5
+ invalidReason?: string;
6
+ /** Fail settlement with this reason after a successful verify. */
7
+ settleErrorReason?: string;
8
+ transaction?: string;
9
+ payer?: string;
10
+ }
11
+ interface MockFacilitator extends FacilitatorClient {
12
+ readonly verifyCalls: number;
13
+ readonly settleCalls: number;
14
+ }
15
+ /**
16
+ * A facilitator stand-in for tests. Nothing here talks to a chain or a network: the
17
+ * official packages own signing and verification, so what we exercise is our own
18
+ * behaviour around their results.
19
+ */
20
+ declare function createMockFacilitator(options?: MockFacilitatorOptions): MockFacilitator;
21
+
22
+ export { type MockFacilitator, type MockFacilitatorOptions, createMockFacilitator };
@@ -0,0 +1,48 @@
1
+ // src/testing.ts
2
+ function createMockFacilitator(options = {}) {
3
+ let verifyCalls = 0;
4
+ let settleCalls = 0;
5
+ return {
6
+ async verify() {
7
+ verifyCalls += 1;
8
+ return options.invalidReason ? { isValid: false, invalidReason: options.invalidReason } : { isValid: true, payer: options.payer ?? "0x2222222222222222222222222222222222222222" };
9
+ },
10
+ async settle() {
11
+ settleCalls += 1;
12
+ if (options.settleErrorReason) {
13
+ return {
14
+ success: false,
15
+ errorReason: options.settleErrorReason,
16
+ transaction: "",
17
+ network: "eip155:8453"
18
+ };
19
+ }
20
+ return {
21
+ success: true,
22
+ transaction: options.transaction ?? `0x${"ab".repeat(32)}`,
23
+ network: "eip155:8453",
24
+ payer: options.payer ?? "0x2222222222222222222222222222222222222222"
25
+ };
26
+ },
27
+ async getSupported() {
28
+ return {
29
+ kinds: [
30
+ { x402Version: 2, scheme: "exact", network: "eip155:8453" },
31
+ { x402Version: 2, scheme: "exact", network: "eip155:84532" }
32
+ ],
33
+ extensions: [],
34
+ signers: {}
35
+ };
36
+ },
37
+ get verifyCalls() {
38
+ return verifyCalls;
39
+ },
40
+ get settleCalls() {
41
+ return settleCalls;
42
+ }
43
+ };
44
+ }
45
+ export {
46
+ createMockFacilitator
47
+ };
48
+ //# sourceMappingURL=testing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/testing.ts"],"sourcesContent":["import type { FacilitatorClient } from '@x402/core/server';\n\nexport interface MockFacilitatorOptions {\n /** Reject verification with this reason instead of accepting. */\n invalidReason?: string;\n /** Fail settlement with this reason after a successful verify. */\n settleErrorReason?: string;\n transaction?: string;\n payer?: string;\n}\n\nexport interface MockFacilitator extends FacilitatorClient {\n readonly verifyCalls: number;\n readonly settleCalls: number;\n}\n\n/**\n * A facilitator stand-in for tests. Nothing here talks to a chain or a network: the\n * official packages own signing and verification, so what we exercise is our own\n * behaviour around their results.\n */\nexport function createMockFacilitator(options: MockFacilitatorOptions = {}): MockFacilitator {\n let verifyCalls = 0;\n let settleCalls = 0;\n\n return {\n async verify() {\n verifyCalls += 1;\n return options.invalidReason\n ? { isValid: false, invalidReason: options.invalidReason }\n : { isValid: true, payer: options.payer ?? '0x2222222222222222222222222222222222222222' };\n },\n async settle() {\n settleCalls += 1;\n if (options.settleErrorReason) {\n return {\n success: false,\n errorReason: options.settleErrorReason,\n transaction: '',\n network: 'eip155:8453',\n };\n }\n return {\n success: true,\n transaction: options.transaction ?? `0x${'ab'.repeat(32)}`,\n network: 'eip155:8453',\n payer: options.payer ?? '0x2222222222222222222222222222222222222222',\n };\n },\n async getSupported() {\n return {\n kinds: [\n { x402Version: 2, scheme: 'exact', network: 'eip155:8453' },\n { x402Version: 2, scheme: 'exact', network: 'eip155:84532' },\n ],\n extensions: [],\n signers: {},\n };\n },\n get verifyCalls() {\n return verifyCalls;\n },\n get settleCalls() {\n return settleCalls;\n },\n };\n}\n"],"mappings":";AAqBO,SAAS,sBAAsB,UAAkC,CAAC,GAAoB;AAC3F,MAAI,cAAc;AAClB,MAAI,cAAc;AAElB,SAAO;AAAA,IACL,MAAM,SAAS;AACb,qBAAe;AACf,aAAO,QAAQ,gBACX,EAAE,SAAS,OAAO,eAAe,QAAQ,cAAc,IACvD,EAAE,SAAS,MAAM,OAAO,QAAQ,SAAS,6CAA6C;AAAA,IAC5F;AAAA,IACA,MAAM,SAAS;AACb,qBAAe;AACf,UAAI,QAAQ,mBAAmB;AAC7B,eAAO;AAAA,UACL,SAAS;AAAA,UACT,aAAa,QAAQ;AAAA,UACrB,aAAa;AAAA,UACb,SAAS;AAAA,QACX;AAAA,MACF;AACA,aAAO;AAAA,QACL,SAAS;AAAA,QACT,aAAa,QAAQ,eAAe,KAAK,KAAK,OAAO,EAAE,CAAC;AAAA,QACxD,SAAS;AAAA,QACT,OAAO,QAAQ,SAAS;AAAA,MAC1B;AAAA,IACF;AAAA,IACA,MAAM,eAAe;AACnB,aAAO;AAAA,QACL,OAAO;AAAA,UACL,EAAE,aAAa,GAAG,QAAQ,SAAS,SAAS,cAAc;AAAA,UAC1D,EAAE,aAAa,GAAG,QAAQ,SAAS,SAAS,eAAe;AAAA,QAC7D;AAAA,QACA,YAAY,CAAC;AAAA,QACb,SAAS,CAAC;AAAA,MACZ;AAAA,IACF;AAAA,IACA,IAAI,cAAc;AAChB,aAAO;AAAA,IACT;AAAA,IACA,IAAI,cAAc;AAChB,aAAO;AAAA,IACT;AAAA,EACF;AACF;","names":[]}
package/package.json CHANGED
@@ -1,9 +1,89 @@
1
1
  {
2
2
  "name": "@fatstack/x402",
3
- "version": "0.0.1",
4
- "description": "Reserved for Fatstack — x402 provider middleware and paying agent client for USDC on Base. Launching soon.",
3
+ "version": "0.1.0",
4
+ "description": "x402 paywall middleware and a spend-guarded paying fetch for AI agents. USDC on Base.",
5
5
  "license": "UNLICENSED",
6
6
  "homepage": "https://fatstack.net",
7
- "keywords": ["x402", "usdc", "base", "mcp", "ai-agents"],
8
- "files": ["README.md"]
7
+ "keywords": [
8
+ "x402",
9
+ "usdc",
10
+ "base",
11
+ "mcp",
12
+ "ai-agents",
13
+ "micropayments"
14
+ ],
15
+ "type": "module",
16
+ "main": "./dist/index.js",
17
+ "types": "./dist/index.d.ts",
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "import": "./dist/index.js",
22
+ "require": "./dist/index.cjs"
23
+ },
24
+ "./provider": {
25
+ "types": "./dist/provider.d.ts",
26
+ "import": "./dist/provider.js",
27
+ "require": "./dist/provider.cjs"
28
+ },
29
+ "./client": {
30
+ "types": "./dist/client.d.ts",
31
+ "import": "./dist/client.js",
32
+ "require": "./dist/client.cjs"
33
+ },
34
+ "./testing": {
35
+ "types": "./dist/testing.d.ts",
36
+ "import": "./dist/testing.js",
37
+ "require": "./dist/testing.cjs"
38
+ }
39
+ },
40
+ "files": [
41
+ "dist",
42
+ "README.md"
43
+ ],
44
+ "sideEffects": false,
45
+ "scripts": {
46
+ "build": "tsup",
47
+ "dev": "tsup --watch",
48
+ "test": "vitest run",
49
+ "typecheck": "tsc -p tsconfig.json",
50
+ "lint": "eslint src --config ../eslint.config.mjs"
51
+ },
52
+ "dependencies": {
53
+ "@x402/core": "^2.24.0",
54
+ "@x402/evm": "^2.24.0",
55
+ "@x402/fetch": "^2.24.0",
56
+ "zod": "^3.24.1"
57
+ },
58
+ "peerDependencies": {
59
+ "@x402/express": "^2.24.0",
60
+ "@x402/hono": "^2.24.0",
61
+ "@x402/next": "^2.24.0"
62
+ },
63
+ "peerDependenciesMeta": {
64
+ "@x402/hono": {
65
+ "optional": true
66
+ },
67
+ "@x402/express": {
68
+ "optional": true
69
+ },
70
+ "@x402/next": {
71
+ "optional": true
72
+ }
73
+ },
74
+ "devDependencies": {
75
+ "@types/express": "^5.0.0",
76
+ "@types/node": "^22.10.2",
77
+ "@x402/express": "^2.24.0",
78
+ "@x402/hono": "^2.24.0",
79
+ "@x402/next": "^2.24.0",
80
+ "express": "^4.21.2",
81
+ "hono": "^4.6.14",
82
+ "next": "^16.2.6",
83
+ "react": "^19.0.0",
84
+ "tsup": "^8.3.5",
85
+ "typescript": "^5.7.2",
86
+ "viem": "^2.21.55",
87
+ "vitest": "^2.1.8"
88
+ }
9
89
  }