@4mica/cli 0.2.0 → 0.3.0-alpha.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@4mica/cli",
3
- "version": "0.2.0",
3
+ "version": "0.3.0-alpha.0",
4
4
  "description": "Scaffold, run, and manage 4Mica agents and payment apps from the command line",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/snapshot.json CHANGED
@@ -4,14 +4,25 @@
4
4
  "@biomejs/biome": "^2.4.16",
5
5
  "@changesets/cli": "^2.29.7",
6
6
  "@clack/prompts": "^1.7.0",
7
+ "@clerk/backend": "^2.33.6",
8
+ "@clerk/clerk-react": "^5.61.9",
9
+ "@clerk/nextjs": "^6.39.6",
7
10
  "@coinbase/cdp-sdk": "^1.49.2",
11
+ "@fastify/cors": "^11.3.0",
12
+ "@fastify/rate-limit": "^11.2.0",
13
+ "@fastify/swagger": "^9.8.1",
14
+ "@fastify/swagger-ui": "^6.1.1",
8
15
  "@noble/curves": "^2.2.0",
16
+ "@prisma/adapter-pg": "7.9.1",
17
+ "@prisma/client": "7.9.1",
9
18
  "@quillai-network/wachai-validation-sdk": "^0.1.0",
10
19
  "@radix-ui/react-scroll-area": "^1.2.10",
11
20
  "@radix-ui/react-slot": "^1.2.4",
21
+ "@react-email/ui": "^6.9.2",
12
22
  "@react-google-maps/api": "^2.20.8",
13
23
  "@reown/appkit": "^1.8.20",
14
24
  "@reown/appkit-adapter-wagmi": "^1.8.20",
25
+ "@shikijs/rehype": "^3.23.0",
15
26
  "@tailwindcss/postcss": "^4.3.0",
16
27
  "@tailwindcss/vite": "^4.3.0",
17
28
  "@tanstack/react-query": "^5.100.14",
@@ -24,23 +35,32 @@
24
35
  "@types/react": "^19.2.16",
25
36
  "@types/react-dom": "^19.2.3",
26
37
  "@types/yargs": "^17.0.35",
38
+ "@valibot/to-json-schema": "^1.7.1",
27
39
  "@vitejs/plugin-react": "^6.0.3",
28
40
  "@vitest/coverage-v8": "^4.1.8",
29
41
  "@vitest/ui": "^4.1.8",
30
42
  "@wagmi/connectors": "^8.0.15",
31
43
  "@wagmi/core": "^3.5.0",
32
44
  "@walletconnect/ethereum-provider": "2.23.4",
45
+ "@x402/core": "2.23.0",
46
+ "@x402/extensions": "2.23.0",
47
+ "@x402/fetch": "2.23.0",
33
48
  "accounts": "^0.14.6",
34
49
  "ahooks": "^3.9.7",
35
50
  "autoprefixer": "^10.5.0",
51
+ "axios": "^1.19.0",
36
52
  "changelogen": "^0.6.2",
37
53
  "class-variance-authority": "^0.7.1",
38
54
  "clsx": "^2.1.1",
39
55
  "cross-env": "10.1.0",
56
+ "dotenv": "^17.4.2",
40
57
  "esbuild": "^0.28.0",
41
58
  "execa": "^9.6.1",
42
59
  "express": "^5.1.0",
60
+ "fastify": "^5.10.0",
61
+ "fastify-plugin": "^5.1.0",
43
62
  "find-up": "^8.0.0",
63
+ "gray-matter": "^4.0.3",
44
64
  "framer-motion": "^12.40.0",
45
65
  "hono": "^4.6.0",
46
66
  "husky": "^9.1.7",
@@ -55,46 +75,63 @@
55
75
  "ora": "^9.4.0",
56
76
  "picocolors": "^1.1.1",
57
77
  "postcss": "^8.5.15",
78
+ "prisma": "7.9.1",
58
79
  "publint": "^0.3.14",
59
80
  "react": "^19.2.7",
60
81
  "react-dom": "^19.2.7",
82
+ "react-email": "^6.9.2",
61
83
  "react-i18next": "^17.0.9",
84
+ "react-redux": "^9.3.0",
62
85
  "react-router-dom": "^7.18.1",
86
+ "react-toastify": "^11.1.0",
87
+ "redux": "^5.0.1",
88
+ "redux-saga": "^1.5.1",
63
89
  "read-pkg": "^10.1.0",
64
90
  "recharts": "^3.8.1",
91
+ "remark-frontmatter": "^5.0.0",
92
+ "remark-gfm": "^4.0.1",
93
+ "resend": "^6.19.0",
65
94
  "rimraf": "^6.1.3",
95
+ "server-only": "^0.0.1",
66
96
  "shiki": "^3.0.0",
67
97
  "tailwind-merge": "^3.6.0",
68
98
  "tailwindcss": "^4.3.0",
69
99
  "tailwindcss-animate": "^1.0.7",
70
100
  "taze": "^19.14.1",
71
101
  "terminal-link": "^5.0.0",
102
+ "ts-node": "^10.9.2",
72
103
  "tsup": "^8.5.1",
73
104
  "tsx": "^4.22.4",
74
105
  "turbo": "latest",
75
106
  "typescript": "^5.9.0",
107
+ "valibot": "^1.4.2",
76
108
  "viem": "2.x",
77
109
  "vite": "^8.1.4",
78
110
  "vitest": "^4.1.8",
79
111
  "wagmi": "^3.6.16",
112
+ "winston": "^3.19.0",
113
+ "winston-daily-rotate-file": "^5.0.0",
80
114
  "yargs": "^18.0.0"
81
115
  },
82
116
  "catalogs": {
83
117
  "node24": {
84
118
  "@types/node": "^24.10.1"
85
119
  },
120
+ "node26": {
121
+ "@types/node": "^26.1.1"
122
+ },
86
123
  "typescript-latest": {
87
124
  "typescript": "^5.9.0"
88
125
  }
89
126
  },
90
127
  "fourMica": {
91
- "@4mica/cli": "0.2.0",
92
- "@4mica/sdk": "1.3.1",
93
- "@4mica/sdk-bun": "1.3.1",
94
- "@4mica/sdk-deno": "1.3.1",
95
- "@4mica/sdk-express": "1.3.1",
96
- "@4mica/sdk-hono": "1.3.1",
97
- "@4mica/sdk-next": "1.3.1",
98
- "@4mica/sdk-node": "1.3.1"
128
+ "@4mica/cli": "0.3.0-alpha.0",
129
+ "@4mica/sdk": "2.0.0-alpha.0",
130
+ "@4mica/sdk-bun": "2.0.0-alpha.0",
131
+ "@4mica/sdk-deno": "2.0.0-alpha.0",
132
+ "@4mica/sdk-express": "2.0.0-alpha.0",
133
+ "@4mica/sdk-hono": "2.0.0-alpha.0",
134
+ "@4mica/sdk-next": "2.0.0-alpha.0",
135
+ "@4mica/sdk-node": "2.0.0-alpha.0"
99
136
  }
100
137
  }
@@ -4,12 +4,18 @@ type Requirement = {
4
4
  asset: string;
5
5
  amount: string;
6
6
  payTo: string;
7
- extra?: { tabEndpoint?: string };
7
+ extra?: Record<string, unknown>;
8
8
  };
9
9
 
10
10
  type Required402 = { x402Version: number; accepts: Requirement[] };
11
11
 
12
12
  function demoPaymentHeader(req: Requirement): string {
13
+ // Mint a random 32-byte req_id — uniqueness is all core asks of it.
14
+ const reqIdBytes = new Uint8Array(32);
15
+ crypto.getRandomValues(reqIdBytes);
16
+ const reqId = `0x${Array.from(reqIdBytes, (b) =>
17
+ b.toString(16).padStart(2, "0"),
18
+ ).join("")}`;
13
19
  const envelope = {
14
20
  x402Version: 1,
15
21
  scheme: req.scheme,
@@ -19,7 +25,7 @@ function demoPaymentHeader(req: Requirement): string {
19
25
  version: "v1",
20
26
  user_address: "0x2222222222222222222222222222222222222222",
21
27
  recipient_address: req.payTo,
22
- req_id: "0x1",
28
+ req_id: reqId,
23
29
  amount: `0x${BigInt(req.amount).toString(16)}`,
24
30
  asset_address: req.asset,
25
31
  timestamp: Math.floor(Date.now() / 1000),
@@ -23,7 +23,7 @@ const verifier: PaywallVerifier = {
23
23
  },
24
24
  };
25
25
 
26
- const CONFIG_BASE: Omit<PaywallConfig, "amount" | "tabEndpoint"> = {
26
+ const CONFIG_BASE: Omit<PaywallConfig, "amount"> = {
27
27
  payTo: "0x1111111111111111111111111111111111111111",
28
28
  asset: "0x0000000000000000000000000000000000000000",
29
29
  network: "base-sepolia",
@@ -79,7 +79,6 @@ app.get("/punchline", async (req, res) => {
79
79
  const config: PaywallConfig = {
80
80
  ...CONFIG_BASE,
81
81
  amount: String(listing.price),
82
- tabEndpoint: `${baseUrl}/session`,
83
82
  };
84
83
  const paywall = createPaywall(verifier, config);
85
84
  const decision = await paywall.protect({
@@ -118,13 +117,6 @@ app.post("/rating", (req, res) => {
118
117
  res.json({ ok: true });
119
118
  });
120
119
 
121
- app.post("/session", (_req, res) => {
122
- res.json({
123
- userAddress: "0x2222222222222222222222222222222222222222",
124
- nextReqId: "0x1",
125
- });
126
- });
127
-
128
120
  function listen(port: number, attemptsLeft = 20) {
129
121
  const server = app.listen(port);
130
122
  server.once("listening", () => {
@@ -26,13 +26,19 @@ type X402PaymentRequired = {
26
26
  asset: string;
27
27
  amount: string;
28
28
  payTo: string;
29
- extra?: { tabEndpoint?: string };
29
+ extra?: Record<string, unknown>;
30
30
  }>;
31
31
  };
32
32
 
33
33
  function demoPaymentHeader(
34
34
  requirement: X402PaymentRequired["accepts"][number],
35
35
  ) {
36
+ // Mint a random 32-byte req_id — uniqueness is all core asks of it.
37
+ const reqIdBytes = new Uint8Array(32);
38
+ crypto.getRandomValues(reqIdBytes);
39
+ const reqId = `0x${Array.from(reqIdBytes, (b) =>
40
+ b.toString(16).padStart(2, "0"),
41
+ ).join("")}`;
36
42
  const envelope = {
37
43
  x402Version: 1,
38
44
  scheme: requirement.scheme,
@@ -42,7 +48,7 @@ function demoPaymentHeader(
42
48
  version: "v1",
43
49
  user_address: "0x2222222222222222222222222222222222222222",
44
50
  recipient_address: requirement.payTo,
45
- req_id: "0x1",
51
+ req_id: reqId,
46
52
  amount: `0x${BigInt(requirement.amount).toString(16)}`,
47
53
  asset_address: requirement.asset,
48
54
  timestamp: Math.floor(Date.now() / 1000),
@@ -26,13 +26,19 @@ type X402PaymentRequired = {
26
26
  asset: string;
27
27
  amount: string;
28
28
  payTo: string;
29
- extra?: { tabEndpoint?: string };
29
+ extra?: Record<string, unknown>;
30
30
  }>;
31
31
  };
32
32
 
33
33
  function demoPaymentHeader(
34
34
  requirement: X402PaymentRequired["accepts"][number],
35
35
  ) {
36
+ // Mint a random 32-byte req_id — uniqueness is all core asks of it.
37
+ const reqIdBytes = new Uint8Array(32);
38
+ crypto.getRandomValues(reqIdBytes);
39
+ const reqId = `0x${Array.from(reqIdBytes, (b) =>
40
+ b.toString(16).padStart(2, "0"),
41
+ ).join("")}`;
36
42
  const envelope = {
37
43
  x402Version: 1,
38
44
  scheme: requirement.scheme,
@@ -42,7 +48,7 @@ function demoPaymentHeader(
42
48
  version: "v1",
43
49
  user_address: "0x2222222222222222222222222222222222222222",
44
50
  recipient_address: requirement.payTo,
45
- req_id: "0x1",
51
+ req_id: reqId,
46
52
  amount: `0x${BigInt(requirement.amount).toString(16)}`,
47
53
  asset_address: requirement.asset,
48
54
  timestamp: Math.floor(Date.now() / 1000),
@@ -26,13 +26,19 @@ type X402PaymentRequired = {
26
26
  asset: string;
27
27
  amount: string;
28
28
  payTo: string;
29
- extra?: { tabEndpoint?: string };
29
+ extra?: Record<string, unknown>;
30
30
  }>;
31
31
  };
32
32
 
33
33
  function demoPaymentHeader(
34
34
  requirement: X402PaymentRequired["accepts"][number],
35
35
  ) {
36
+ // Mint a random 32-byte req_id — uniqueness is all core asks of it.
37
+ const reqIdBytes = new Uint8Array(32);
38
+ crypto.getRandomValues(reqIdBytes);
39
+ const reqId = `0x${Array.from(reqIdBytes, (b) =>
40
+ b.toString(16).padStart(2, "0"),
41
+ ).join("")}`;
36
42
  const envelope = {
37
43
  x402Version: 1,
38
44
  scheme: requirement.scheme,
@@ -42,7 +48,7 @@ function demoPaymentHeader(
42
48
  version: "v1",
43
49
  user_address: "0x2222222222222222222222222222222222222222",
44
50
  recipient_address: requirement.payTo,
45
- req_id: "0x1",
51
+ req_id: reqId,
46
52
  amount: `0x${BigInt(requirement.amount).toString(16)}`,
47
53
  asset_address: requirement.asset,
48
54
  timestamp: Math.floor(Date.now() / 1000),
@@ -19,20 +19,12 @@ export const PAYWALL_CONFIG: PaywallConfig = {
19
19
  asset: "0x0000000000000000000000000000000000000000",
20
20
  network: "base-sepolia",
21
21
  amount: "1000",
22
- tabEndpoint: "http://localhost:__PORT__/session",
23
22
  description: "Premium market data feed",
24
23
  };
25
24
 
26
25
  const app = express();
27
26
  app.use(express.json());
28
27
 
29
- app.post("/session", (_req, res) => {
30
- res.json({
31
- userAddress: "0x2222222222222222222222222222222222222222",
32
- nextReqId: "0x1",
33
- });
34
- });
35
-
36
28
  app.get("/premium", paywall(verifier, PAYWALL_CONFIG), (_req, res) => {
37
29
  res.json({ ok: true, data: "🔓 premium market data unlocked" });
38
30
  });
@@ -41,7 +33,6 @@ function listen(port: number, attemptsLeft = 20) {
41
33
  const server = app.listen(port);
42
34
  server.once("listening", () => {
43
35
  const url = `http://localhost:${port}`;
44
- PAYWALL_CONFIG.tabEndpoint = `${url}/session`;
45
36
  writeFileSync(PORT_FILE, url);
46
37
  console.log(`[seller-express] listening on ${url}`);
47
38
  console.log(` GET /premium is paywalled — run the buyer to pay for it.`);
@@ -20,19 +20,11 @@ export const PAYWALL_CONFIG: PaywallConfig = {
20
20
  asset: "0x0000000000000000000000000000000000000000",
21
21
  network: "base-sepolia",
22
22
  amount: "1000",
23
- tabEndpoint: "http://localhost:__PORT__/session",
24
23
  description: "Premium market data feed",
25
24
  };
26
25
 
27
26
  const app = new Hono();
28
27
 
29
- app.post("/session", (c) =>
30
- c.json({
31
- userAddress: "0x2222222222222222222222222222222222222222",
32
- nextReqId: "0x1",
33
- }),
34
- );
35
-
36
28
  app.use("/premium", paywall(verifier, PAYWALL_CONFIG));
37
29
  app.get("/premium", (c) => {
38
30
  const guarantee = c.get("paymentGuarantee");
@@ -46,7 +38,6 @@ app.get("/premium", (c) => {
46
38
  function listen(port: number, attemptsLeft = 20) {
47
39
  const server = serve({ fetch: app.fetch, port }, (info) => {
48
40
  const url = `http://localhost:${info.port}`;
49
- PAYWALL_CONFIG.tabEndpoint = `${url}/session`;
50
41
  writeFileSync(PORT_FILE, url);
51
42
  console.log(`[seller-hono] listening on ${url}`);
52
43
  console.log(` GET /premium is paywalled — run the buyer to pay for it.`);
@@ -15,7 +15,6 @@ const PAYWALL_CONFIG: PaywallConfig = {
15
15
  asset: "0x0000000000000000000000000000000000000000",
16
16
  network: "base-sepolia",
17
17
  amount: "1000",
18
- tabEndpoint: `${process.env.EXAMPLE_BASE_URL ?? "http://localhost:__PORT__"}/api/session`,
19
18
  description: "Premium market data feed",
20
19
  };
21
20
 
@@ -1,8 +0,0 @@
1
- export const dynamic = "force-dynamic";
2
-
3
- export async function POST() {
4
- return Response.json({
5
- userAddress: "0x2222222222222222222222222222222222222222",
6
- nextReqId: "0x1",
7
- });
8
- }