run402 1.8.2 → 1.9.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/lib/apps.mjs +5 -9
- package/lib/config.mjs +19 -35
- package/lib/deploy.mjs +10 -11
- package/lib/image.mjs +4 -17
- package/lib/init.mjs +3 -3
- package/lib/paid-fetch.mjs +27 -0
- package/lib/projects.mjs +10 -13
- package/lib/tier.mjs +1 -21
- package/package.json +1 -1
package/lib/apps.mjs
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { findProject,
|
|
2
|
-
import { mkdirSync, writeFileSync } from "fs";
|
|
1
|
+
import { findProject, API, walletAuthHeaders, saveProject } from "./config.mjs";
|
|
3
2
|
|
|
4
3
|
const HELP = `run402 apps — Browse and manage the app marketplace
|
|
5
4
|
|
|
@@ -63,15 +62,12 @@ async function fork(versionId, name, args) {
|
|
|
63
62
|
|
|
64
63
|
// Save project credentials locally
|
|
65
64
|
if (data.project_id) {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
project_id: data.project_id, anon_key: data.anon_key, service_key: data.service_key,
|
|
65
|
+
saveProject(data.project_id, {
|
|
66
|
+
anon_key: data.anon_key, service_key: data.service_key,
|
|
69
67
|
tier: data.tier, lease_expires_at: data.lease_expires_at,
|
|
70
|
-
site_url: data.site_url || data.subdomain_url,
|
|
68
|
+
site_url: data.site_url || data.subdomain_url,
|
|
69
|
+
deployed_at: new Date().toISOString(),
|
|
71
70
|
});
|
|
72
|
-
const dir = PROJECTS_FILE.replace(/\/[^/]+$/, "");
|
|
73
|
-
mkdirSync(dir, { recursive: true });
|
|
74
|
-
writeFileSync(PROJECTS_FILE, JSON.stringify(projects, null, 2), { mode: 0o600 });
|
|
75
71
|
}
|
|
76
72
|
console.log(JSON.stringify(data, null, 2));
|
|
77
73
|
}
|
package/lib/config.mjs
CHANGED
|
@@ -1,53 +1,37 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Run402 config loader —
|
|
3
|
-
*
|
|
2
|
+
* Run402 config loader — thin wrapper over core/ shared modules.
|
|
3
|
+
* Adds CLI-specific behavior: process.exit() on errors.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
6
|
+
import { getApiBase, getConfigDir, getKeystorePath, getWalletPath } from "../../core/dist/config.js";
|
|
7
|
+
import { readWallet as coreReadWallet, saveWallet as coreSaveWallet } from "../../core/dist/wallet.js";
|
|
8
|
+
import { getWalletAuthHeaders } from "../../core/dist/wallet-auth.js";
|
|
9
|
+
import { loadKeyStore, getProject, saveProject, removeProject, saveKeyStore } from "../../core/dist/keystore.js";
|
|
10
10
|
|
|
11
|
-
export const CONFIG_DIR =
|
|
12
|
-
export const WALLET_FILE =
|
|
13
|
-
export const PROJECTS_FILE =
|
|
14
|
-
export const API =
|
|
11
|
+
export const CONFIG_DIR = getConfigDir();
|
|
12
|
+
export const WALLET_FILE = getWalletPath();
|
|
13
|
+
export const PROJECTS_FILE = getKeystorePath();
|
|
14
|
+
export const API = getApiBase();
|
|
15
15
|
|
|
16
16
|
export function readWallet() {
|
|
17
|
-
|
|
18
|
-
return JSON.parse(readFileSync(WALLET_FILE, "utf-8"));
|
|
17
|
+
return coreReadWallet();
|
|
19
18
|
}
|
|
20
19
|
|
|
21
20
|
export function saveWallet(data) {
|
|
22
|
-
|
|
23
|
-
const tmp = join(CONFIG_DIR, `.wallet.${randomBytes(4).toString("hex")}.tmp`);
|
|
24
|
-
writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 0o600 });
|
|
25
|
-
renameSync(tmp, WALLET_FILE);
|
|
26
|
-
chmodSync(WALLET_FILE, 0o600);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export function loadProjects() {
|
|
30
|
-
if (!existsSync(PROJECTS_FILE)) return [];
|
|
31
|
-
return JSON.parse(readFileSync(PROJECTS_FILE, "utf-8"));
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export function saveProjects(projects) {
|
|
35
|
-
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
36
|
-
writeFileSync(PROJECTS_FILE, JSON.stringify(projects, null, 2), { mode: 0o600 });
|
|
21
|
+
coreSaveWallet(data);
|
|
37
22
|
}
|
|
38
23
|
|
|
39
24
|
export async function walletAuthHeaders() {
|
|
40
|
-
const
|
|
41
|
-
if (!
|
|
42
|
-
|
|
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 };
|
|
25
|
+
const headers = getWalletAuthHeaders();
|
|
26
|
+
if (!headers) { console.error(JSON.stringify({ status: "error", message: "No wallet found. Run: run402 wallet create" })); process.exit(1); }
|
|
27
|
+
return headers;
|
|
47
28
|
}
|
|
48
29
|
|
|
49
30
|
export function findProject(id) {
|
|
50
|
-
const p =
|
|
31
|
+
const p = getProject(id);
|
|
51
32
|
if (!p) { console.error(`Project ${id} not found in local registry.`); process.exit(1); }
|
|
52
33
|
return p;
|
|
53
34
|
}
|
|
35
|
+
|
|
36
|
+
// Re-export core keystore functions for direct use
|
|
37
|
+
export { loadKeyStore, saveProject, removeProject, saveKeyStore };
|
package/lib/deploy.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { readFileSync
|
|
2
|
-
import {
|
|
1
|
+
import { readFileSync } from "fs";
|
|
2
|
+
import { API, walletAuthHeaders, saveProject } from "./config.mjs";
|
|
3
3
|
|
|
4
4
|
const HELP = `run402 deploy — Deploy a full-stack app or static site on Run402
|
|
5
5
|
|
|
@@ -39,14 +39,6 @@ async function readStdin() {
|
|
|
39
39
|
return Buffer.concat(chunks).toString("utf-8");
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
function saveProject(project) {
|
|
43
|
-
const projects = loadProjects();
|
|
44
|
-
projects.push({ project_id: project.project_id, anon_key: project.anon_key, service_key: project.service_key, tier: project.tier, lease_expires_at: project.lease_expires_at, site_url: project.site_url || project.subdomain_url, deployed_at: new Date().toISOString() });
|
|
45
|
-
const dir = PROJECTS_FILE.replace(/\/[^/]+$/, "");
|
|
46
|
-
mkdirSync(dir, { recursive: true });
|
|
47
|
-
writeFileSync(PROJECTS_FILE, JSON.stringify(projects, null, 2), { mode: 0o600 });
|
|
48
|
-
}
|
|
49
|
-
|
|
50
42
|
export async function run(args) {
|
|
51
43
|
const opts = { manifest: null };
|
|
52
44
|
for (let i = 0; i < args.length; i++) {
|
|
@@ -60,6 +52,13 @@ export async function run(args) {
|
|
|
60
52
|
const res = await fetch(`${API}/deploy/v1`, { method: "POST", headers: { "Content-Type": "application/json", ...authHeaders }, body: JSON.stringify(manifest) });
|
|
61
53
|
const result = await res.json();
|
|
62
54
|
if (!res.ok) { console.error(JSON.stringify({ status: "error", http: res.status, ...result })); process.exit(1); }
|
|
63
|
-
|
|
55
|
+
if (result.project_id) {
|
|
56
|
+
saveProject(result.project_id, {
|
|
57
|
+
anon_key: result.anon_key, service_key: result.service_key,
|
|
58
|
+
tier: result.tier, lease_expires_at: result.lease_expires_at,
|
|
59
|
+
site_url: result.site_url || result.subdomain_url,
|
|
60
|
+
deployed_at: new Date().toISOString(),
|
|
61
|
+
});
|
|
62
|
+
}
|
|
64
63
|
console.log(JSON.stringify(result, null, 2));
|
|
65
64
|
}
|
package/lib/image.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { writeFileSync
|
|
2
|
-
import {
|
|
1
|
+
import { writeFileSync } from "fs";
|
|
2
|
+
import { API, WALLET_FILE } from "./config.mjs";
|
|
3
|
+
import { setupPaidFetch } from "./paid-fetch.mjs";
|
|
3
4
|
|
|
4
5
|
const HELP = `run402 image — Generate AI images via x402 micropayments
|
|
5
6
|
|
|
@@ -49,22 +50,8 @@ export async function run(sub, args) {
|
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
if (!opts.prompt) { console.error(JSON.stringify({ status: "error", message: "Prompt required. Usage: run402 image generate \"your prompt\"" })); process.exit(1); }
|
|
52
|
-
if (!existsSync(WALLET_FILE)) { console.error(JSON.stringify({ status: "error", message: "No wallet found. Run: run402 wallet create && run402 wallet fund" })); process.exit(1); }
|
|
53
53
|
|
|
54
|
-
const
|
|
55
|
-
const { privateKeyToAccount } = await import("viem/accounts");
|
|
56
|
-
const { createPublicClient, http } = await import("viem");
|
|
57
|
-
const { baseSepolia } = await import("viem/chains");
|
|
58
|
-
const { x402Client, wrapFetchWithPayment } = await import("@x402/fetch");
|
|
59
|
-
const { ExactEvmScheme } = await import("@x402/evm/exact/client");
|
|
60
|
-
const { toClientEvmSigner } = await import("@x402/evm");
|
|
61
|
-
|
|
62
|
-
const account = privateKeyToAccount(wallet.privateKey);
|
|
63
|
-
const publicClient = createPublicClient({ chain: baseSepolia, transport: http() });
|
|
64
|
-
const signer = toClientEvmSigner(account, publicClient);
|
|
65
|
-
const client = new x402Client();
|
|
66
|
-
client.register("eip155:84532", new ExactEvmScheme(signer));
|
|
67
|
-
const fetchPaid = wrapFetchWithPayment(fetch, client);
|
|
54
|
+
const fetchPaid = await setupPaidFetch();
|
|
68
55
|
|
|
69
56
|
const res = await fetchPaid(`${API}/generate-image/v1`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ prompt: opts.prompt, aspect: opts.aspect }) });
|
|
70
57
|
const data = await res.json();
|
package/lib/init.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readWallet, saveWallet,
|
|
1
|
+
import { readWallet, saveWallet, loadKeyStore, CONFIG_DIR, WALLET_FILE, API } from "./config.mjs";
|
|
2
2
|
import { mkdirSync } from "fs";
|
|
3
3
|
|
|
4
4
|
const USDC_ABI = [{ name: "balanceOf", type: "function", stateMutability: "view", inputs: [{ name: "account", type: "address" }], outputs: [{ name: "", type: "uint256" }] }];
|
|
@@ -91,8 +91,8 @@ export async function run() {
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
// 5. Projects
|
|
94
|
-
const
|
|
95
|
-
line("Projects", `${projects.length} active`);
|
|
94
|
+
const store = loadKeyStore();
|
|
95
|
+
line("Projects", `${Object.keys(store.projects).length} active`);
|
|
96
96
|
|
|
97
97
|
// 6. Next step
|
|
98
98
|
console.log();
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared x402 payment wrapper for CLI commands that need paid fetch.
|
|
3
|
+
* Uses viem for wallet signing + @x402/fetch for payment wrapping.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { readWallet, WALLET_FILE } from "./config.mjs";
|
|
7
|
+
import { existsSync } from "fs";
|
|
8
|
+
|
|
9
|
+
export async function setupPaidFetch() {
|
|
10
|
+
if (!existsSync(WALLET_FILE)) {
|
|
11
|
+
console.error(JSON.stringify({ status: "error", message: "No wallet found. Run: run402 wallet create && run402 wallet fund" }));
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
const wallet = readWallet();
|
|
15
|
+
const { privateKeyToAccount } = await import("viem/accounts");
|
|
16
|
+
const { createPublicClient, http } = await import("viem");
|
|
17
|
+
const { baseSepolia } = await import("viem/chains");
|
|
18
|
+
const { x402Client, wrapFetchWithPayment } = await import("@x402/fetch");
|
|
19
|
+
const { ExactEvmScheme } = await import("@x402/evm/exact/client");
|
|
20
|
+
const { toClientEvmSigner } = await import("@x402/evm");
|
|
21
|
+
const account = privateKeyToAccount(wallet.privateKey);
|
|
22
|
+
const publicClient = createPublicClient({ chain: baseSepolia, transport: http() });
|
|
23
|
+
const signer = toClientEvmSigner(account, publicClient);
|
|
24
|
+
const client = new x402Client();
|
|
25
|
+
client.register("eip155:84532", new ExactEvmScheme(signer));
|
|
26
|
+
return wrapFetchWithPayment(fetch, client);
|
|
27
|
+
}
|
package/lib/projects.mjs
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { findProject,
|
|
2
|
-
import { mkdirSync, writeFileSync } from "fs";
|
|
1
|
+
import { findProject, loadKeyStore, saveProject, removeProject, API, walletAuthHeaders } from "./config.mjs";
|
|
3
2
|
|
|
4
3
|
const HELP = `run402 projects — Manage your deployed Run402 projects
|
|
5
4
|
|
|
@@ -61,14 +60,11 @@ async function provision(args) {
|
|
|
61
60
|
if (!res.ok) { console.error(JSON.stringify({ status: "error", http: res.status, ...data })); process.exit(1); }
|
|
62
61
|
// Save project credentials locally
|
|
63
62
|
if (data.project_id) {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
63
|
+
saveProject(data.project_id, {
|
|
64
|
+
anon_key: data.anon_key, service_key: data.service_key,
|
|
65
|
+
tier: data.tier, lease_expires_at: data.lease_expires_at,
|
|
66
|
+
deployed_at: new Date().toISOString(),
|
|
68
67
|
});
|
|
69
|
-
const dir = PROJECTS_FILE.replace(/\/[^/]+$/, "");
|
|
70
|
-
mkdirSync(dir, { recursive: true });
|
|
71
|
-
writeFileSync(PROJECTS_FILE, JSON.stringify(projects, null, 2), { mode: 0o600 });
|
|
72
68
|
}
|
|
73
69
|
console.log(JSON.stringify(data, null, 2));
|
|
74
70
|
}
|
|
@@ -87,9 +83,10 @@ async function rls(projectId, template, tablesJson) {
|
|
|
87
83
|
}
|
|
88
84
|
|
|
89
85
|
async function list() {
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
console.log(JSON.stringify(
|
|
86
|
+
const store = loadKeyStore();
|
|
87
|
+
const entries = Object.entries(store.projects);
|
|
88
|
+
if (entries.length === 0) { console.log(JSON.stringify({ status: "ok", projects: [], message: "No projects yet." })); return; }
|
|
89
|
+
console.log(JSON.stringify(entries.map(([id, p]) => ({ project_id: id, tier: p.tier, site_url: p.site_url, lease_expires_at: p.lease_expires_at, deployed_at: p.deployed_at })), null, 2));
|
|
93
90
|
}
|
|
94
91
|
|
|
95
92
|
async function sqlCmd(projectId, query) {
|
|
@@ -124,7 +121,7 @@ async function deleteProject(projectId) {
|
|
|
124
121
|
const p = findProject(projectId);
|
|
125
122
|
const res = await fetch(`${API}/projects/v1/${projectId}`, { method: "DELETE", headers: { "Authorization": `Bearer ${p.service_key}` } });
|
|
126
123
|
if (res.status === 204 || res.ok) {
|
|
127
|
-
|
|
124
|
+
removeProject(projectId);
|
|
128
125
|
console.log(JSON.stringify({ status: "ok", message: `Project ${projectId} deleted.` }));
|
|
129
126
|
} else {
|
|
130
127
|
const data = await res.json().catch(() => ({}));
|
package/lib/tier.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { readWallet, WALLET_FILE, API } from "./config.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { setupPaidFetch } from "./paid-fetch.mjs";
|
|
3
3
|
|
|
4
4
|
const HELP = `run402 tier — Manage your Run402 tier subscription
|
|
5
5
|
|
|
@@ -24,26 +24,6 @@ Examples:
|
|
|
24
24
|
run402 tier set hobby
|
|
25
25
|
`;
|
|
26
26
|
|
|
27
|
-
async function setupPaidFetch() {
|
|
28
|
-
if (!existsSync(WALLET_FILE)) {
|
|
29
|
-
console.error(JSON.stringify({ status: "error", message: "No wallet found. Run: run402 wallet create && run402 wallet fund" }));
|
|
30
|
-
process.exit(1);
|
|
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
|
-
return wrapFetchWithPayment(fetch, client);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
27
|
async function status() {
|
|
48
28
|
const w = readWallet();
|
|
49
29
|
if (!w) { console.log(JSON.stringify({ status: "error", message: "No wallet. Run: run402 wallet create" })); process.exit(1); }
|
package/package.json
CHANGED