run402 1.8.0 → 1.8.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/cli.mjs CHANGED
@@ -17,7 +17,7 @@ Commands:
17
17
  wallet Manage your x402 wallet (create, fund, balance, status)
18
18
  tier Manage tier subscription (status, set)
19
19
  projects Manage projects (provision, list, query, inspect, delete)
20
- deploy Deploy a full-stack app or static site (Postgres + hosting)
20
+ deploy Deploy a full-stack app or static site (requires active tier)
21
21
  functions Manage serverless functions (deploy, invoke, logs, list, delete)
22
22
  secrets Manage project secrets (set, list, delete)
23
23
  storage Manage file storage (upload, download, list, delete)
@@ -33,7 +33,7 @@ Run 'run402 <command> --help' for detailed usage of each command.
33
33
  Examples:
34
34
  run402 wallet create
35
35
  run402 wallet fund
36
- run402 deploy --tier prototype --manifest app.json
36
+ run402 deploy --manifest app.json
37
37
  run402 projects list
38
38
  run402 projects sql <project_id> "SELECT * FROM users LIMIT 5"
39
39
  run402 functions deploy <project_id> my-fn --code handler.ts
@@ -43,7 +43,7 @@ Examples:
43
43
  Getting started:
44
44
  run402 init Set up everything in one command
45
45
  run402 tier set prototype Subscribe to a tier
46
- run402 deploy ... Deploy your app
46
+ run402 deploy --manifest app.json
47
47
  `;
48
48
 
49
49
  if (!cmd || cmd === '--help' || cmd === '-h') {
package/lib/agent.mjs CHANGED
@@ -1,5 +1,4 @@
1
- import { readWallet, API, WALLET_FILE } from "./config.mjs";
2
- import { existsSync } from "fs";
1
+ import { API, walletAuthHeaders } from "./config.mjs";
3
2
 
4
3
  const HELP = `run402 agent — Manage agent identity
5
4
 
@@ -24,32 +23,15 @@ async function contact(args) {
24
23
  if (args[i] === "--webhook" && args[i + 1]) webhook = args[++i];
25
24
  }
26
25
  if (!name) { console.error(JSON.stringify({ status: "error", message: "Missing --name <name>" })); process.exit(1); }
27
- if (!existsSync(WALLET_FILE)) {
28
- console.error(JSON.stringify({ status: "error", message: "No wallet found. Run: run402 wallet create && run402 wallet fund" }));
29
- process.exit(1);
30
- }
31
-
32
- const wallet = readWallet();
33
- const { privateKeyToAccount } = await import("viem/accounts");
34
- const { createPublicClient, http } = await import("viem");
35
- const { baseSepolia } = await import("viem/chains");
36
- const { x402Client, wrapFetchWithPayment } = await import("@x402/fetch");
37
- const { ExactEvmScheme } = await import("@x402/evm/exact/client");
38
- const { toClientEvmSigner } = await import("@x402/evm");
39
- const account = privateKeyToAccount(wallet.privateKey);
40
- const publicClient = createPublicClient({ chain: baseSepolia, transport: http() });
41
- const signer = toClientEvmSigner(account, publicClient);
42
- const client = new x402Client();
43
- client.register("eip155:84532", new ExactEvmScheme(signer));
44
- const fetchPaid = wrapFetchWithPayment(fetch, client);
26
+ const authHeaders = await walletAuthHeaders();
45
27
 
46
28
  const body = { name };
47
29
  if (email) body.email = email;
48
30
  if (webhook) body.webhook = webhook;
49
31
 
50
- const res = await fetchPaid(`${API}/agent/v1/contact`, {
32
+ const res = await fetch(`${API}/agent/v1/contact`, {
51
33
  method: "POST",
52
- headers: { "Content-Type": "application/json" },
34
+ headers: { "Content-Type": "application/json", ...authHeaders },
53
35
  body: JSON.stringify(body),
54
36
  });
55
37
  const data = await res.json();
package/lib/apps.mjs CHANGED
@@ -1,5 +1,4 @@
1
- import { existsSync } from "fs";
2
- import { findProject, readWallet, loadProjects, saveProjects, API, WALLET_FILE, PROJECTS_FILE } from "./config.mjs";
1
+ import { findProject, loadProjects, saveProjects, API, PROJECTS_FILE, walletAuthHeaders } from "./config.mjs";
3
2
  import { mkdirSync, writeFileSync } from "fs";
4
3
 
5
4
  const HELP = `run402 apps — Browse and manage the app marketplace
@@ -49,31 +48,14 @@ async function fork(versionId, name, args) {
49
48
  if (args[i] === "--tier" && args[i + 1]) opts.tier = args[++i];
50
49
  if (args[i] === "--subdomain" && args[i + 1]) opts.subdomain = args[++i];
51
50
  }
52
- if (!existsSync(WALLET_FILE)) {
53
- console.error(JSON.stringify({ status: "error", message: "No wallet found. Run: run402 wallet create && run402 wallet fund" }));
54
- process.exit(1);
55
- }
56
-
57
- const wallet = readWallet();
58
- const { privateKeyToAccount } = await import("viem/accounts");
59
- const { createPublicClient, http } = await import("viem");
60
- const { baseSepolia } = await import("viem/chains");
61
- const { x402Client, wrapFetchWithPayment } = await import("@x402/fetch");
62
- const { ExactEvmScheme } = await import("@x402/evm/exact/client");
63
- const { toClientEvmSigner } = await import("@x402/evm");
64
- const account = privateKeyToAccount(wallet.privateKey);
65
- const publicClient = createPublicClient({ chain: baseSepolia, transport: http() });
66
- const signer = toClientEvmSigner(account, publicClient);
67
- const client = new x402Client();
68
- client.register("eip155:84532", new ExactEvmScheme(signer));
69
- const fetchPaid = wrapFetchWithPayment(fetch, client);
51
+ const authHeaders = await walletAuthHeaders();
70
52
 
71
53
  const body = { version_id: versionId, name };
72
54
  if (opts.subdomain) body.subdomain = opts.subdomain;
73
55
 
74
- const res = await fetchPaid(`${API}/fork/v1`, {
56
+ const res = await fetch(`${API}/fork/v1`, {
75
57
  method: "POST",
76
- headers: { "Content-Type": "application/json" },
58
+ headers: { "Content-Type": "application/json", ...authHeaders },
77
59
  body: JSON.stringify(body),
78
60
  });
79
61
  const data = await res.json();
package/lib/config.mjs CHANGED
@@ -36,6 +36,16 @@ export function saveProjects(projects) {
36
36
  writeFileSync(PROJECTS_FILE, JSON.stringify(projects, null, 2), { mode: 0o600 });
37
37
  }
38
38
 
39
+ export async function walletAuthHeaders() {
40
+ const w = readWallet();
41
+ if (!w) { console.error(JSON.stringify({ status: "error", message: "No wallet found. Run: run402 wallet create" })); process.exit(1); }
42
+ const { privateKeyToAccount } = await import("viem/accounts");
43
+ const account = privateKeyToAccount(w.privateKey);
44
+ const timestamp = Math.floor(Date.now() / 1000).toString();
45
+ const signature = await account.signMessage({ message: `run402:${timestamp}` });
46
+ return { "X-Run402-Wallet": account.address, "X-Run402-Signature": signature, "X-Run402-Timestamp": timestamp };
47
+ }
48
+
39
49
  export function findProject(id) {
40
50
  const p = loadProjects().find(p => p.project_id === id);
41
51
  if (!p) { console.error(`Project ${id} not found in local registry.`); process.exit(1); }
package/lib/deploy.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { readFileSync, existsSync, mkdirSync, writeFileSync } from "fs";
2
- import { readWallet, loadProjects, API, WALLET_FILE, PROJECTS_FILE } from "./config.mjs";
1
+ import { readFileSync, mkdirSync, writeFileSync } from "fs";
2
+ import { loadProjects, API, PROJECTS_FILE, walletAuthHeaders } from "./config.mjs";
3
3
 
4
4
  const HELP = `run402 deploy — Deploy a full-stack app or static site on Run402
5
5
 
@@ -8,35 +8,27 @@ Usage:
8
8
  cat manifest.json | run402 deploy [options]
9
9
 
10
10
  Options:
11
- --tier <tier> Deployment tier: prototype | hobby | team (default: prototype)
12
11
  --manifest <file> Path to manifest JSON file (default: read from stdin)
13
12
  --help, -h Show this help message
14
13
 
15
- Tiers:
16
- prototype Smallest, cheapest — great for demos and experiments
17
- hobby Mid-tier — personal projects and side hustles
18
- team Full power — production-ready, shared team access
19
-
20
14
  Manifest format (JSON):
21
15
  {
22
16
  "name": "my-app",
23
- "files": {
24
- "index.html": "<html>...</html>",
25
- "style.css": "body { margin: 0; }"
26
- },
27
- "env": {
28
- "MY_VAR": "value"
29
- }
17
+ "migrations": "CREATE TABLE items ...",
18
+ "site": [{ "file": "index.html", "data": "<html>...</html>" }],
19
+ "subdomain": "my-app"
30
20
  }
31
21
 
32
22
  Examples:
33
- run402 deploy --tier prototype --manifest app.json
34
- run402 deploy --tier hobby --manifest app.json
35
- cat app.json | run402 deploy --tier team
23
+ run402 deploy --manifest app.json
24
+ cat app.json | run402 deploy
25
+
26
+ Prerequisites:
27
+ - run402 init Set up wallet and funding
28
+ - run402 tier set prototype Subscribe to a tier
36
29
 
37
30
  Notes:
38
- - Requires a funded wallet (run402 wallet create && run402 wallet fund)
39
- - Payments are processed automatically via x402 micropayments (Base Sepolia USDC)
31
+ - Requires an active tier subscription (run402 tier set <tier>)
40
32
  - Project credentials (project_id, keys, URL) are saved locally after deploy
41
33
  - Use 'run402 projects list' to see all deployed projects
42
34
  `;
@@ -56,35 +48,16 @@ function saveProject(project) {
56
48
  }
57
49
 
58
50
  export async function run(args) {
59
- const opts = { tier: "prototype", manifest: null };
51
+ const opts = { manifest: null };
60
52
  for (let i = 0; i < args.length; i++) {
61
53
  if (args[i] === "--help" || args[i] === "-h") { console.log(HELP); process.exit(0); }
62
- if (args[i] === "--tier" && args[i + 1]) opts.tier = args[++i];
63
54
  if (args[i] === "--manifest" && args[i + 1]) opts.manifest = args[++i];
64
55
  }
65
56
 
66
- if (!existsSync(WALLET_FILE)) {
67
- console.error(JSON.stringify({ status: "error", message: "No wallet found. Run: run402 wallet create && run402 wallet fund" }));
68
- process.exit(1);
69
- }
70
- const wallet = readWallet();
71
57
  const manifest = opts.manifest ? JSON.parse(readFileSync(opts.manifest, "utf-8")) : JSON.parse(await readStdin());
72
58
 
73
- const { privateKeyToAccount } = await import("viem/accounts");
74
- const { createPublicClient, http } = await import("viem");
75
- const { baseSepolia } = await import("viem/chains");
76
- const { x402Client, wrapFetchWithPayment } = await import("@x402/fetch");
77
- const { ExactEvmScheme } = await import("@x402/evm/exact/client");
78
- const { toClientEvmSigner } = await import("@x402/evm");
79
-
80
- const account = privateKeyToAccount(wallet.privateKey);
81
- const publicClient = createPublicClient({ chain: baseSepolia, transport: http() });
82
- const signer = toClientEvmSigner(account, publicClient);
83
- const client = new x402Client();
84
- client.register("eip155:84532", new ExactEvmScheme(signer));
85
- const fetchPaid = wrapFetchWithPayment(fetch, client);
86
-
87
- const res = await fetchPaid(`${API}/deploy/v1`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(manifest) });
59
+ const authHeaders = await walletAuthHeaders();
60
+ const res = await fetch(`${API}/deploy/v1`, { method: "POST", headers: { "Content-Type": "application/json", ...authHeaders }, body: JSON.stringify(manifest) });
88
61
  const result = await res.json();
89
62
  if (!res.ok) { console.error(JSON.stringify({ status: "error", http: res.status, ...result })); process.exit(1); }
90
63
  saveProject(result);
package/lib/init.mjs CHANGED
@@ -99,7 +99,7 @@ export async function run() {
99
99
  if (!tierInfo || !tierInfo.tier || tierInfo.status !== "active") {
100
100
  console.log(" Next: run402 tier set prototype");
101
101
  } else {
102
- console.log(" Ready to deploy. Run: run402 deploy --tier prototype --manifest app.json");
102
+ console.log(" Ready to deploy. Run: run402 deploy --manifest app.json");
103
103
  }
104
104
  console.log();
105
105
  }
package/lib/message.mjs CHANGED
@@ -1,5 +1,4 @@
1
- import { readWallet, API, WALLET_FILE } from "./config.mjs";
2
- import { existsSync } from "fs";
1
+ import { API, walletAuthHeaders } from "./config.mjs";
3
2
 
4
3
  const HELP = `run402 message — Send messages to Run402 developers
5
4
 
@@ -16,28 +15,11 @@ Examples:
16
15
 
17
16
  async function send(text) {
18
17
  if (!text) { console.error(JSON.stringify({ status: "error", message: "Missing message text" })); process.exit(1); }
19
- if (!existsSync(WALLET_FILE)) {
20
- console.error(JSON.stringify({ status: "error", message: "No wallet found. Run: run402 wallet create && run402 wallet fund" }));
21
- process.exit(1);
22
- }
23
-
24
- const wallet = readWallet();
25
- const { privateKeyToAccount } = await import("viem/accounts");
26
- const { createPublicClient, http } = await import("viem");
27
- const { baseSepolia } = await import("viem/chains");
28
- const { x402Client, wrapFetchWithPayment } = await import("@x402/fetch");
29
- const { ExactEvmScheme } = await import("@x402/evm/exact/client");
30
- const { toClientEvmSigner } = await import("@x402/evm");
31
- const account = privateKeyToAccount(wallet.privateKey);
32
- const publicClient = createPublicClient({ chain: baseSepolia, transport: http() });
33
- const signer = toClientEvmSigner(account, publicClient);
34
- const client = new x402Client();
35
- client.register("eip155:84532", new ExactEvmScheme(signer));
36
- const fetchPaid = wrapFetchWithPayment(fetch, client);
18
+ const authHeaders = await walletAuthHeaders();
37
19
 
38
- const res = await fetchPaid(`${API}/message/v1`, {
20
+ const res = await fetch(`${API}/message/v1`, {
39
21
  method: "POST",
40
- headers: { "Content-Type": "application/json" },
22
+ headers: { "Content-Type": "application/json", ...authHeaders },
41
23
  body: JSON.stringify({ message: text }),
42
24
  });
43
25
  const data = await res.json();
package/lib/projects.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { findProject, loadProjects, saveProjects, readWallet, API, WALLET_FILE, PROJECTS_FILE } from "./config.mjs";
2
- import { existsSync, mkdirSync, writeFileSync } from "fs";
1
+ import { findProject, loadProjects, saveProjects, API, PROJECTS_FILE, walletAuthHeaders } from "./config.mjs";
2
+ import { mkdirSync, writeFileSync } from "fs";
3
3
 
4
4
  const HELP = `run402 projects — Manage your deployed Run402 projects
5
5
 
@@ -36,26 +36,6 @@ Notes:
36
36
  - RLS templates: user_owns_rows, public_read, public_read_write
37
37
  `;
38
38
 
39
- async function setupPaidFetch() {
40
- if (!existsSync(WALLET_FILE)) {
41
- console.error(JSON.stringify({ status: "error", message: "No wallet found. Run: run402 wallet create && run402 wallet fund" }));
42
- process.exit(1);
43
- }
44
- const wallet = readWallet();
45
- const { privateKeyToAccount } = await import("viem/accounts");
46
- const { createPublicClient, http } = await import("viem");
47
- const { baseSepolia } = await import("viem/chains");
48
- const { x402Client, wrapFetchWithPayment } = await import("@x402/fetch");
49
- const { ExactEvmScheme } = await import("@x402/evm/exact/client");
50
- const { toClientEvmSigner } = await import("@x402/evm");
51
- const account = privateKeyToAccount(wallet.privateKey);
52
- const publicClient = createPublicClient({ chain: baseSepolia, transport: http() });
53
- const signer = toClientEvmSigner(account, publicClient);
54
- const client = new x402Client();
55
- client.register("eip155:84532", new ExactEvmScheme(signer));
56
- return wrapFetchWithPayment(fetch, client);
57
- }
58
-
59
39
  async function quote() {
60
40
  const res = await fetch(`${API}/tiers/v1`);
61
41
  const data = await res.json();
@@ -69,12 +49,12 @@ async function provision(args) {
69
49
  if (args[i] === "--tier" && args[i + 1]) opts.tier = args[++i];
70
50
  if (args[i] === "--name" && args[i + 1]) opts.name = args[++i];
71
51
  }
72
- const fetchPaid = await setupPaidFetch();
52
+ const authHeaders = await walletAuthHeaders();
73
53
  const body = { tier: opts.tier };
74
54
  if (opts.name) body.name = opts.name;
75
- const res = await fetchPaid(`${API}/projects/v1`, {
55
+ const res = await fetch(`${API}/projects/v1`, {
76
56
  method: "POST",
77
- headers: { "Content-Type": "application/json" },
57
+ headers: { "Content-Type": "application/json", ...authHeaders },
78
58
  body: JSON.stringify(body),
79
59
  });
80
60
  const data = await res.json();
package/lib/sites.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { readFileSync, existsSync } from "fs";
2
- import { readWallet, API, WALLET_FILE } from "./config.mjs";
1
+ import { readFileSync } from "fs";
2
+ import { API, walletAuthHeaders } from "./config.mjs";
3
3
 
4
4
  const HELP = `run402 sites — Deploy and manage static sites
5
5
 
@@ -53,33 +53,15 @@ async function deploy(args) {
53
53
  if (args[i] === "--target" && args[i + 1]) opts.target = args[++i];
54
54
  }
55
55
  if (!opts.name) { console.error(JSON.stringify({ status: "error", message: "Missing --name <name>" })); process.exit(1); }
56
- if (!existsSync(WALLET_FILE)) {
57
- console.error(JSON.stringify({ status: "error", message: "No wallet found. Run: run402 wallet create && run402 wallet fund" }));
58
- process.exit(1);
59
- }
60
-
61
56
  const manifest = opts.manifest ? JSON.parse(readFileSync(opts.manifest, "utf-8")) : JSON.parse(await readStdin());
62
57
  const body = { name: opts.name, files: manifest.files };
63
58
  if (opts.project) body.project = opts.project;
64
59
  if (opts.target) body.target = opts.target;
65
60
 
66
- const wallet = readWallet();
67
- const { privateKeyToAccount } = await import("viem/accounts");
68
- const { createPublicClient, http } = await import("viem");
69
- const { baseSepolia } = await import("viem/chains");
70
- const { x402Client, wrapFetchWithPayment } = await import("@x402/fetch");
71
- const { ExactEvmScheme } = await import("@x402/evm/exact/client");
72
- const { toClientEvmSigner } = await import("@x402/evm");
73
- const account = privateKeyToAccount(wallet.privateKey);
74
- const publicClient = createPublicClient({ chain: baseSepolia, transport: http() });
75
- const signer = toClientEvmSigner(account, publicClient);
76
- const client = new x402Client();
77
- client.register("eip155:84532", new ExactEvmScheme(signer));
78
- const fetchPaid = wrapFetchWithPayment(fetch, client);
79
-
80
- const res = await fetchPaid(`${API}/deployments/v1`, {
61
+ const authHeaders = await walletAuthHeaders();
62
+ const res = await fetch(`${API}/deployments/v1`, {
81
63
  method: "POST",
82
- headers: { "Content-Type": "application/json" },
64
+ headers: { "Content-Type": "application/json", ...authHeaders },
83
65
  body: JSON.stringify(body),
84
66
  });
85
67
  const data = await res.json();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "run402",
3
- "version": "1.8.0",
3
+ "version": "1.8.2",
4
4
  "description": "CLI for Run402 — provision Postgres databases, deploy static sites, generate images, and manage wallets via x402 micropayments.",
5
5
  "type": "module",
6
6
  "bin": {