x402-engineer 0.1.0 → 0.1.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "x402-engineer",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Claude Code skill pack for adding x402 micropayments to any API endpoint",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -137,21 +137,36 @@ Read [references/patterns.md](references/patterns.md) for the framework-specific
137
137
  For each selected unprotected endpoint:
138
138
 
139
139
  1. **Read the route file** -- always read before editing (never assume file state)
140
- 2. **Add import** -- if `withPayment` or `withX402` is not already imported, add the import:
140
+ 2. **Add imports** -- if `withX402` and `resourceServer` are not already imported, add:
141
141
  ```typescript
142
- import { withPayment } from "{relative_path_to_server}";
142
+ import { withX402, resourceServer } from "{relative_path_to_server}";
143
+ import { PRICE, NETWORK, SERVER_ADDRESS } from "{relative_path_to_config}";
143
144
  ```
144
- Use the path to the x402 server file found in Step 1. Preserve existing imports -- do not duplicate.
145
+ Use the paths to the x402 server and config files found in Step 1. Preserve existing imports -- do not duplicate.
145
146
  3. **Add marker comment** -- add `// x402: payment-protected endpoint` above the handler function
146
- 4. **Wrap the handler** -- wrap the handler's body with `withPayment(req, () => { ... original handler ... })`:
147
+ 4. **Wrap the handler** -- use `withX402(handler, routeConfig, resourceServer)` where `routeConfig` is a **single route config object** (NOT the full RoutesConfig map):
147
148
  ```typescript
148
149
  // x402: payment-protected endpoint
149
- export async function GET(req: Request) {
150
- return withPayment(req, () => {
150
+ export const GET = withX402(
151
+ async (req: Request) => {
151
152
  // ... original handler body ...
152
- });
153
- }
153
+ },
154
+ {
155
+ accepts: [
156
+ {
157
+ scheme: "exact",
158
+ price: PRICE,
159
+ network: NETWORK,
160
+ payTo: SERVER_ADDRESS,
161
+ },
162
+ ],
163
+ description: "Description of endpoint",
164
+ mimeType: "application/json",
165
+ },
166
+ resourceServer,
167
+ );
154
168
  ```
169
+ **IMPORTANT:** `withX402` takes a single `RouteConfig` object as its 2nd argument, NOT the full `RoutesConfig` map. Passing the map will cause `Cannot read properties of undefined (reading 'network')` errors.
155
170
  5. **Use Edit tool** to apply changes to the route file
156
171
 
157
172
  ### Express / Fastify / Hono (middleware)
@@ -12,16 +12,29 @@ Next.js route handlers must be wrapped individually because there is no global m
12
12
 
13
13
  **Using @x402/next (official):**
14
14
 
15
+ `withX402` takes three arguments: `(handler, routeConfig, resourceServer)` where `routeConfig` is a **single route config object** (NOT the full `RoutesConfig` map).
16
+
15
17
  ```typescript
16
- import { withX402 } from "../lib/x402/server";
17
- import { routesConfig, resourceServer } from "../lib/x402/server";
18
+ import { withX402, resourceServer } from "../lib/x402/server";
19
+ import { PRICE, NETWORK, SERVER_ADDRESS } from "../lib/x402/config";
18
20
 
19
21
  // x402: payment-protected endpoint
20
22
  export const GET = withX402(
21
23
  async (req: Request) => {
22
24
  return Response.json({ data: "protected content" });
23
25
  },
24
- routesConfig,
26
+ {
27
+ accepts: [
28
+ {
29
+ scheme: "exact",
30
+ price: PRICE,
31
+ network: NETWORK,
32
+ payTo: SERVER_ADDRESS,
33
+ },
34
+ ],
35
+ description: "Description of endpoint",
36
+ mimeType: "application/json",
37
+ },
25
38
  resourceServer,
26
39
  );
27
40
  ```
@@ -9,7 +9,7 @@ allowed-tools: [Read, Write, Edit, Bash, Grep, Glob]
9
9
 
10
10
  # /x402:init
11
11
 
12
- > Bootstrap x402 payment protection in your project. I'll detect your framework, install the right packages, and scaffold all config files.
12
+ > Bootstrap x402 payment protection in your project. Works with existing projects (brownfield) or creates a new project from scratch (greenfield). I'll detect your framework, install the right packages, and scaffold all config files.
13
13
 
14
14
  ## Important Rules
15
15
 
@@ -17,6 +17,64 @@ allowed-tools: [Read, Write, Edit, Bash, Grep, Glob]
17
17
  - Server-side `ExactStellarScheme` import path is always `@x402/stellar/exact/server` (NOT `@x402/stellar/exact/client`).
18
18
  - All templates are in this skill's `templates/` directory. Read the template file and use its content as the basis for generated code.
19
19
  - Adapt import paths if needed based on project structure (e.g., relative paths based on file placement).
20
+ - For Next.js greenfield projects, ALWAYS delegate to create-next-app. Do NOT scaffold Next.js manually.
21
+ - Greenfield templates are in this skill's `templates/greenfield/` directory.
22
+
23
+ ## Step 0 -- Detect Greenfield Project (Conditional)
24
+
25
+ Before anything else, determine if this is a greenfield (new/empty) project:
26
+
27
+ 1. **Check for package.json:** Use Read to check if `package.json` exists in the current working directory
28
+ 2. **If package.json exists:** Check if any supported framework (`next`, `express`, `fastify`, `hono`) appears in `dependencies`. If a framework IS found, this is a brownfield project -- skip to Step 1.
29
+ 3. **If no package.json OR no framework in dependencies:** This is a greenfield project. Continue below.
30
+
31
+ ### Greenfield: Verify Empty Directory
32
+
33
+ Before scaffolding, verify the directory is safe to scaffold into:
34
+
35
+ 1. Use Bash to list directory contents: `ls -A`
36
+ 2. **Allowed trivial files:** `.git`, `.gitignore`, `CLAUDE.md`, `.claude/`, `README.md`, `.planning/`
37
+ 3. If the directory contains files OTHER than the trivial list above, warn the user:
38
+ `"Directory is not empty. Found: {non-trivial files}. Greenfield scaffolding expects an empty directory. Continue anyway? (The existing files will be preserved, but conflicts may occur.)"`
39
+ Wait for user confirmation before proceeding. If the user says no, STOP.
40
+
41
+ ### Greenfield: Select Framework
42
+
43
+ 1. **If `$ARGUMENTS` provides a framework** (e.g., `/x402:init express`), use that framework directly. Valid values: `nextjs`, `next`, `express`, `fastify`, `hono`. Normalize `nextjs`/`next` to Next.js.
44
+ 2. **If no argument provided**, ask the user:
45
+ ```
46
+ No framework detected. Which framework would you like to use?
47
+
48
+ 1. Express (default -- simplest for API-only)
49
+ 2. Fastify
50
+ 3. Hono
51
+ 4. Next.js (full-stack with App Router)
52
+
53
+ Enter choice (1-4) or framework name:
54
+ ```
55
+ If the user just presses enter or says "default", use Express.
56
+
57
+ ### Greenfield: Scaffold Project
58
+
59
+ **For Next.js:**
60
+
61
+ 1. Output: `"Scaffolding Next.js project with create-next-app..."`
62
+ 2. Run via Bash: `npx create-next-app@latest . --typescript --app --yes`
63
+ 3. Wait for completion. If it fails (e.g., directory not empty), report the error and STOP.
64
+ 4. Output: `"Next.js project created. Continuing with x402 setup..."`
65
+ 5. Skip to Step 1 (the brownfield flow handles everything from here).
66
+
67
+ **For Express / Fastify / Hono:**
68
+
69
+ 1. Output: `"Scaffolding {Framework} project..."`
70
+ 2. Read `templates/greenfield/{framework}/package.json.md` -- extract JSON from code block, write to `./package.json`
71
+ 3. Read `templates/greenfield/{framework}/tsconfig.json.md` -- extract JSON from code block, write to `./tsconfig.json`
72
+ 4. Create `src/` directory via Bash: `mkdir -p src`
73
+ 5. Read `templates/greenfield/{framework}/server.ts.md` -- extract TypeScript from code block, write to `./src/server.ts`
74
+ 6. Run via Bash: `npm install`
75
+ 7. Output: `"Project scaffolded. Created 3 files: package.json, tsconfig.json, src/server.ts"`
76
+ 8. Output: `"Continuing with x402 setup..."`
77
+ 9. Continue to Step 1 (the existing brownfield flow picks up from here -- it will detect the framework from the newly created package.json).
20
78
 
21
79
  ## Step 1 -- Check for Existing x402 Setup (Idempotency)
22
80
 
@@ -50,7 +108,7 @@ Report which pieces are already present. Skip those. Only create the missing pie
50
108
 
51
109
  **Edge cases:**
52
110
  - If `@nestjs/core` is found in dependencies, warn: `"NestJS detected, using underlying Express/Fastify adapter"` and detect which underlying framework NestJS uses (check for `@nestjs/platform-express` or `@nestjs/platform-fastify`)
53
- - If no supported framework is detected, output: `"Could not detect framework from package.json. Supported: Next.js, Express, Fastify, Hono."` and STOP
111
+ - If no supported framework is detected AND Step 0 was skipped (package.json exists but has no framework): output `"Could not detect framework from package.json. Supported: Next.js, Express, Fastify, Hono."` and STOP
54
112
 
55
113
  ## Step 3 -- Detect Project Structure
56
114
 
@@ -0,0 +1,24 @@
1
+ # Express Greenfield package.json
2
+
3
+ Minimal package.json for a new Express + TypeScript project.
4
+
5
+ ```json
6
+ {
7
+ "name": "x402-server",
8
+ "version": "0.1.0",
9
+ "type": "module",
10
+ "scripts": {
11
+ "dev": "tsx watch src/server.ts",
12
+ "build": "tsc",
13
+ "start": "node dist/server.js"
14
+ },
15
+ "dependencies": {
16
+ "express": "latest"
17
+ },
18
+ "devDependencies": {
19
+ "@types/express": "latest",
20
+ "tsx": "latest",
21
+ "typescript": "latest"
22
+ }
23
+ }
24
+ ```
@@ -0,0 +1,18 @@
1
+ # Express Greenfield Server
2
+
3
+ Minimal Express server with a single `/api/hello` endpoint.
4
+
5
+ ```typescript
6
+ import express from "express";
7
+
8
+ const app = express();
9
+ const port = process.env.PORT || 3000;
10
+
11
+ app.get("/api/hello", (_req, res) => {
12
+ res.json({ message: "Hello from x402!" });
13
+ });
14
+
15
+ app.listen(port, () => {
16
+ console.log(`Server running on http://localhost:${port}`);
17
+ });
18
+ ```
@@ -0,0 +1,19 @@
1
+ # Express Greenfield tsconfig.json
2
+
3
+ Minimal TypeScript configuration for a new Express project.
4
+
5
+ ```json
6
+ {
7
+ "compilerOptions": {
8
+ "target": "ES2022",
9
+ "module": "Node16",
10
+ "moduleResolution": "Node16",
11
+ "outDir": "dist",
12
+ "rootDir": "src",
13
+ "strict": true,
14
+ "esModuleInterop": true,
15
+ "skipLibCheck": true
16
+ },
17
+ "include": ["src"]
18
+ }
19
+ ```
@@ -0,0 +1,23 @@
1
+ # Fastify Greenfield package.json
2
+
3
+ Minimal package.json for a new Fastify + TypeScript project.
4
+
5
+ ```json
6
+ {
7
+ "name": "x402-server",
8
+ "version": "0.1.0",
9
+ "type": "module",
10
+ "scripts": {
11
+ "dev": "tsx watch src/server.ts",
12
+ "build": "tsc",
13
+ "start": "node dist/server.js"
14
+ },
15
+ "dependencies": {
16
+ "fastify": "latest"
17
+ },
18
+ "devDependencies": {
19
+ "tsx": "latest",
20
+ "typescript": "latest"
21
+ }
22
+ }
23
+ ```
@@ -0,0 +1,22 @@
1
+ # Fastify Greenfield Server
2
+
3
+ Minimal Fastify server with a single `/api/hello` endpoint.
4
+
5
+ ```typescript
6
+ import Fastify from "fastify";
7
+
8
+ const fastify = Fastify();
9
+ const port = Number(process.env.PORT) || 3000;
10
+
11
+ fastify.get("/api/hello", async () => {
12
+ return { message: "Hello from x402!" };
13
+ });
14
+
15
+ fastify.listen({ port, host: "0.0.0.0" }, (err, address) => {
16
+ if (err) {
17
+ console.error(err);
18
+ process.exit(1);
19
+ }
20
+ console.log(`Server running on http://localhost:${port}`);
21
+ });
22
+ ```
@@ -0,0 +1,19 @@
1
+ # Fastify Greenfield tsconfig.json
2
+
3
+ Minimal TypeScript configuration for a new Fastify project.
4
+
5
+ ```json
6
+ {
7
+ "compilerOptions": {
8
+ "target": "ES2022",
9
+ "module": "Node16",
10
+ "moduleResolution": "Node16",
11
+ "outDir": "dist",
12
+ "rootDir": "src",
13
+ "strict": true,
14
+ "esModuleInterop": true,
15
+ "skipLibCheck": true
16
+ },
17
+ "include": ["src"]
18
+ }
19
+ ```
@@ -0,0 +1,24 @@
1
+ # Hono Greenfield package.json
2
+
3
+ Minimal package.json for a new Hono + TypeScript project.
4
+
5
+ ```json
6
+ {
7
+ "name": "x402-server",
8
+ "version": "0.1.0",
9
+ "type": "module",
10
+ "scripts": {
11
+ "dev": "tsx watch src/server.ts",
12
+ "build": "tsc",
13
+ "start": "node dist/server.js"
14
+ },
15
+ "dependencies": {
16
+ "@hono/node-server": "latest",
17
+ "hono": "latest"
18
+ },
19
+ "devDependencies": {
20
+ "tsx": "latest",
21
+ "typescript": "latest"
22
+ }
23
+ }
24
+ ```
@@ -0,0 +1,19 @@
1
+ # Hono Greenfield Server
2
+
3
+ Minimal Hono server with a single `/api/hello` endpoint.
4
+
5
+ ```typescript
6
+ import { Hono } from "hono";
7
+ import { serve } from "@hono/node-server";
8
+
9
+ const app = new Hono();
10
+ const port = Number(process.env.PORT) || 3000;
11
+
12
+ app.get("/api/hello", (c) => {
13
+ return c.json({ message: "Hello from x402!" });
14
+ });
15
+
16
+ serve({ fetch: app.fetch, port }, () => {
17
+ console.log(`Server running on http://localhost:${port}`);
18
+ });
19
+ ```
@@ -0,0 +1,19 @@
1
+ # Hono Greenfield tsconfig.json
2
+
3
+ Minimal TypeScript configuration for a new Hono project.
4
+
5
+ ```json
6
+ {
7
+ "compilerOptions": {
8
+ "target": "ES2022",
9
+ "module": "Node16",
10
+ "moduleResolution": "Node16",
11
+ "outDir": "dist",
12
+ "rootDir": "src",
13
+ "strict": true,
14
+ "esModuleInterop": true,
15
+ "skipLibCheck": true
16
+ },
17
+ "include": ["src"]
18
+ }
19
+ ```