x402-engineer 0.1.1 → 0.1.3
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 +1 -1
- package/skills/x402-init/SKILL.md +152 -6
- package/skills/x402-init/templates/greenfield/express/package.json.md +24 -0
- package/skills/x402-init/templates/greenfield/express/server.ts.md +18 -0
- package/skills/x402-init/templates/greenfield/express/tsconfig.json.md +19 -0
- package/skills/x402-init/templates/greenfield/fastify/package.json.md +23 -0
- package/skills/x402-init/templates/greenfield/fastify/server.ts.md +22 -0
- package/skills/x402-init/templates/greenfield/fastify/tsconfig.json.md +19 -0
- package/skills/x402-init/templates/greenfield/hono/package.json.md +24 -0
- package/skills/x402-init/templates/greenfield/hono/server.ts.md +19 -0
- package/skills/x402-init/templates/greenfield/hono/tsconfig.json.md +19 -0
package/package.json
CHANGED
|
@@ -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
|
|
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
|
|
|
@@ -90,7 +148,6 @@ Run the framework-specific install command via Bash:
|
|
|
90
148
|
6. Check if `.env.example` already exists at the project root:
|
|
91
149
|
- If it does NOT exist: create `.env.example` with the template content
|
|
92
150
|
- If it DOES exist: check if it already contains `SERVER_STELLAR_ADDRESS`. If not, append the x402 section to the existing file
|
|
93
|
-
7. Output: `"Created .env.example with required variables. Copy to .env.local and fill in your values."`
|
|
94
151
|
|
|
95
152
|
## Step 6 -- Scaffold Server/Middleware Files
|
|
96
153
|
|
|
@@ -103,7 +160,94 @@ Run the framework-specific install command via Bash:
|
|
|
103
160
|
5. Extract the TypeScript code from the template's fenced code block
|
|
104
161
|
6. Write to `{base_dir}/x402/adapter.ts`
|
|
105
162
|
|
|
106
|
-
## Step 7 --
|
|
163
|
+
## Step 7 -- Configure Environment (Interactive)
|
|
164
|
+
|
|
165
|
+
Guide the user through setting up `.env.local` with the required values. Check if `.env.local` already exists and has values before prompting.
|
|
166
|
+
|
|
167
|
+
### 7a -- Check existing .env.local
|
|
168
|
+
|
|
169
|
+
1. Use Read to check if `.env.local` exists
|
|
170
|
+
2. If it exists and already contains `SERVER_STELLAR_ADDRESS` with a non-empty value, output:
|
|
171
|
+
`"Environment already configured in .env.local. Skipping setup."`
|
|
172
|
+
Skip to Step 8.
|
|
173
|
+
|
|
174
|
+
### 7b -- SERVER_STELLAR_ADDRESS
|
|
175
|
+
|
|
176
|
+
Output the following explanation:
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
To receive payments, you need a Stellar account address.
|
|
180
|
+
This is a public key that starts with "G" (56 characters).
|
|
181
|
+
|
|
182
|
+
How to get one:
|
|
183
|
+
1. Go to https://laboratory.stellar.org/#account-creator?network=test
|
|
184
|
+
2. Click "Generate Keypair"
|
|
185
|
+
3. Save both keys -- you'll use the Public Key (G...) here
|
|
186
|
+
4. Click "Fund account on testnet" to get test XLM
|
|
187
|
+
|
|
188
|
+
If you already have a Stellar address, paste it below.
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Ask the user for the value. Accept any input that:
|
|
192
|
+
- Starts with `G` and is 56 characters long
|
|
193
|
+
- OR is empty (user wants to skip for now)
|
|
194
|
+
|
|
195
|
+
If the user provides an invalid format, warn once: `"Stellar addresses start with G and are 56 characters. This doesn't look right, but I'll use it anyway."` and proceed.
|
|
196
|
+
|
|
197
|
+
If the user skips (empty), set `SERVER_STELLAR_ADDRESS=` (empty value).
|
|
198
|
+
|
|
199
|
+
### 7c -- FACILITATOR_API_KEY
|
|
200
|
+
|
|
201
|
+
Output the following explanation:
|
|
202
|
+
|
|
203
|
+
```
|
|
204
|
+
The facilitator is a service (by OpenZeppelin) that verifies and settles
|
|
205
|
+
x402 payments on your behalf. You need an API key to use it.
|
|
206
|
+
|
|
207
|
+
How to get one:
|
|
208
|
+
1. Go to https://channels.openzeppelin.com/testnet/gen
|
|
209
|
+
2. Generate a new API key
|
|
210
|
+
3. Paste it below
|
|
211
|
+
|
|
212
|
+
This takes ~30 seconds. I'll wait.
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Ask the user for the value. Accept any non-empty string, or empty to skip.
|
|
216
|
+
|
|
217
|
+
If the user skips (empty), set `FACILITATOR_API_KEY=` (empty value).
|
|
218
|
+
|
|
219
|
+
### 7d -- Write .env.local
|
|
220
|
+
|
|
221
|
+
Write `.env.local` with the collected values:
|
|
222
|
+
|
|
223
|
+
```env
|
|
224
|
+
# x402 Payment Configuration
|
|
225
|
+
|
|
226
|
+
# Stellar public key (G...) that receives USDC payments
|
|
227
|
+
SERVER_STELLAR_ADDRESS={collected_value}
|
|
228
|
+
|
|
229
|
+
# OpenZeppelin facilitator endpoint
|
|
230
|
+
FACILITATOR_URL=https://channels.openzeppelin.com/x402/testnet
|
|
231
|
+
|
|
232
|
+
# API key from https://channels.openzeppelin.com/testnet/gen
|
|
233
|
+
FACILITATOR_API_KEY={collected_value}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
**Rules:**
|
|
237
|
+
- Always set `FACILITATOR_URL` to the testnet endpoint (no need to ask -- testnet is the right default for init)
|
|
238
|
+
- If `.env.local` already exists with OTHER variables (not x402-related), append the x402 section. Do not overwrite existing content.
|
|
239
|
+
- Add `.env.local` to `.gitignore` if not already present (check first for idempotency)
|
|
240
|
+
|
|
241
|
+
### 7e -- Report status
|
|
242
|
+
|
|
243
|
+
If both values were provided:
|
|
244
|
+
`"Environment configured. .env.local is ready."`
|
|
245
|
+
|
|
246
|
+
If one or both were skipped:
|
|
247
|
+
`"Created .env.local with partial configuration. Fill in the missing values before testing:"`
|
|
248
|
+
Then list which variables are still empty.
|
|
249
|
+
|
|
250
|
+
## Step 8 -- Summary
|
|
107
251
|
|
|
108
252
|
Count the files created during this run and output:
|
|
109
253
|
|
|
@@ -112,18 +256,20 @@ Count the files created during this run and output:
|
|
|
112
256
|
List each file with its relative path from the project root, for example:
|
|
113
257
|
|
|
114
258
|
```
|
|
115
|
-
x402 initialized. Created
|
|
259
|
+
x402 initialized. Created 4 files:
|
|
116
260
|
- lib/x402/config.ts
|
|
117
261
|
- lib/x402/server.ts
|
|
118
262
|
- .env.example
|
|
263
|
+
- .env.local
|
|
119
264
|
```
|
|
120
265
|
|
|
121
266
|
For Fastify projects, the adapter file is also listed:
|
|
122
267
|
|
|
123
268
|
```
|
|
124
|
-
x402 initialized. Created
|
|
269
|
+
x402 initialized. Created 5 files:
|
|
125
270
|
- lib/x402/config.ts
|
|
126
271
|
- lib/x402/server.ts
|
|
127
272
|
- lib/x402/adapter.ts
|
|
128
273
|
- .env.example
|
|
274
|
+
- .env.local
|
|
129
275
|
```
|
|
@@ -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
|
+
```
|