run402 1.23.1 → 1.24.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.
Files changed (3) hide show
  1. package/cli.mjs +6 -0
  2. package/lib/domains.mjs +105 -0
  3. package/package.json +1 -1
package/cli.mjs CHANGED
@@ -31,6 +31,7 @@ Commands:
31
31
  storage Manage file storage (upload, download, list, delete)
32
32
  sites Deploy static sites
33
33
  subdomains Manage custom subdomains (claim, list, delete)
34
+ domains Manage custom domains (add, list, status, delete)
34
35
  apps Browse and manage the app marketplace
35
36
  image Generate AI images via x402 or MPP micropayments
36
37
  email Send template-based emails from your project
@@ -122,6 +123,11 @@ switch (cmd) {
122
123
  await run(sub, rest);
123
124
  break;
124
125
  }
126
+ case "domains": {
127
+ const { run } = await import("./lib/domains.mjs");
128
+ await run(sub, rest);
129
+ break;
130
+ }
125
131
  case "apps": {
126
132
  const { run } = await import("./lib/apps.mjs");
127
133
  await run(sub, rest);
@@ -0,0 +1,105 @@
1
+ import { resolveProject, API } from "./config.mjs";
2
+
3
+ const HELP = `run402 domains — Manage custom domains
4
+
5
+ Usage:
6
+ run402 domains <subcommand> [args...]
7
+
8
+ Subcommands:
9
+ add <domain> <subdomain_name> [--project <id>] Register a custom domain
10
+ list [<id>] List custom domains for a project
11
+ status <domain> [--project <id>] Check domain DNS/SSL status
12
+ delete <domain> [--project <id>] Release a custom domain
13
+
14
+ Examples:
15
+ run402 domains add example.com myapp
16
+ run402 domains add example.com myapp --project prj_123
17
+ run402 domains list
18
+ run402 domains status example.com
19
+ run402 domains delete example.com
20
+
21
+ Notes:
22
+ - After adding a domain, configure DNS as shown in the response
23
+ - Poll 'status' until the domain is active (DNS propagation ~60s)
24
+ - The domain must CNAME to domains.run402.com (or ALIAS for apex domains)
25
+ `;
26
+
27
+ function parseProjectFlag(args) {
28
+ let project = null;
29
+ const rest = [];
30
+ for (let i = 0; i < args.length; i++) {
31
+ if (args[i] === "--project" && args[i + 1]) { project = args[++i]; }
32
+ else { rest.push(args[i]); }
33
+ }
34
+ return { project, rest };
35
+ }
36
+
37
+ async function add(args) {
38
+ const { project, rest } = parseProjectFlag(args);
39
+ const domain = rest[0];
40
+ const subdomainName = rest[1];
41
+ if (!domain || !subdomainName) { console.error("Usage: run402 domains add <domain> <subdomain_name> [--project <id>]"); process.exit(1); }
42
+ const p = resolveProject(project);
43
+ const res = await fetch(`${API}/domains/v1`, {
44
+ method: "POST",
45
+ headers: { "Authorization": `Bearer ${p.service_key}`, "Content-Type": "application/json" },
46
+ body: JSON.stringify({ domain, subdomain_name: subdomainName }),
47
+ });
48
+ const data = await res.json();
49
+ if (!res.ok) { console.error(JSON.stringify({ status: "error", http: res.status, ...data })); process.exit(1); }
50
+ console.log(JSON.stringify(data, null, 2));
51
+ }
52
+
53
+ async function list(projectId) {
54
+ const p = resolveProject(projectId);
55
+ const res = await fetch(`${API}/domains/v1`, {
56
+ headers: { "Authorization": `Bearer ${p.service_key}` },
57
+ });
58
+ const data = await res.json();
59
+ if (!res.ok) { console.error(JSON.stringify({ status: "error", http: res.status, ...data })); process.exit(1); }
60
+ console.log(JSON.stringify(data, null, 2));
61
+ }
62
+
63
+ async function status(args) {
64
+ const { project, rest } = parseProjectFlag(args);
65
+ const domain = rest[0];
66
+ if (!domain) { console.error("Usage: run402 domains status <domain> [--project <id>]"); process.exit(1); }
67
+ const p = resolveProject(project);
68
+ const res = await fetch(`${API}/domains/v1/${encodeURIComponent(domain)}`, {
69
+ headers: { "Authorization": `Bearer ${p.service_key}` },
70
+ });
71
+ const data = await res.json();
72
+ if (!res.ok) { console.error(JSON.stringify({ status: "error", http: res.status, ...data })); process.exit(1); }
73
+ console.log(JSON.stringify(data, null, 2));
74
+ }
75
+
76
+ async function deleteDomain(args) {
77
+ const { project, rest } = parseProjectFlag(args);
78
+ const domain = rest[0];
79
+ if (!domain) { console.error("Usage: run402 domains delete <domain> [--project <id>]"); process.exit(1); }
80
+ const p = resolveProject(project);
81
+ const res = await fetch(`${API}/domains/v1/${encodeURIComponent(domain)}`, {
82
+ method: "DELETE",
83
+ headers: { "Authorization": `Bearer ${p.service_key}` },
84
+ });
85
+ if (res.status === 204 || res.ok) {
86
+ console.log(JSON.stringify({ status: "ok", message: `Domain '${domain}' released.` }));
87
+ } else {
88
+ const data = await res.json().catch(() => ({}));
89
+ console.error(JSON.stringify({ status: "error", http: res.status, ...data })); process.exit(1);
90
+ }
91
+ }
92
+
93
+ export async function run(sub, args) {
94
+ if (!sub || sub === '--help' || sub === '-h') { console.log(HELP); process.exit(0); }
95
+ switch (sub) {
96
+ case "add": await add(args); break;
97
+ case "list": await list(args[0]); break;
98
+ case "status": await status(args); break;
99
+ case "delete": await deleteDomain(args); break;
100
+ default:
101
+ console.error(`Unknown subcommand: ${sub}\n`);
102
+ console.log(HELP);
103
+ process.exit(1);
104
+ }
105
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "run402",
3
- "version": "1.23.1",
3
+ "version": "1.24.0",
4
4
  "description": "CLI for Run402 — provision Postgres databases, deploy static sites, generate images, and manage wallets via x402 and MPP micropayments.",
5
5
  "type": "module",
6
6
  "bin": {