run402 1.54.2 → 1.54.4
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 +18 -0
- package/core-dist/allowance-auth.js +5 -0
- package/core-dist/allowance.js +49 -1
- package/core-dist/config.js +35 -2
- package/core-dist/wallet-auth.js +62 -0
- package/core-dist/wallet.js +25 -0
- package/lib/agent.mjs +29 -1
- package/lib/ai.mjs +113 -37
- package/lib/apps.mjs +34 -0
- package/lib/argparse.mjs +128 -0
- package/lib/auth.mjs +15 -2
- package/lib/billing.mjs +35 -0
- package/lib/config.mjs +20 -1
- package/lib/contracts.mjs +41 -0
- package/lib/deploy-v2.mjs +37 -0
- package/lib/deploy.mjs +125 -58
- package/lib/domains.mjs +79 -5
- package/lib/email.mjs +34 -0
- package/lib/functions.mjs +25 -1
- package/lib/image.mjs +33 -1
- package/lib/message.mjs +50 -3
- package/lib/projects.mjs +43 -33
- package/lib/sdk-errors.mjs +2 -1
- package/lib/secrets.mjs +29 -0
- package/lib/sender-domain.mjs +78 -1
- package/lib/service.mjs +30 -1
- package/lib/subdomains.mjs +49 -4
- package/lib/tier.mjs +41 -1
- package/lib/webhooks.mjs +10 -0
- package/package.json +1 -1
- package/sdk/core-dist/allowance-auth.js +5 -0
- package/sdk/core-dist/allowance.js +49 -1
- package/sdk/core-dist/config.js +35 -2
- package/sdk/core-dist/wallet-auth.js +62 -0
- package/sdk/core-dist/wallet.js +25 -0
- package/sdk/dist/node/paid-fetch.d.ts.map +1 -1
- package/sdk/dist/node/paid-fetch.js +12 -1
- package/sdk/dist/node/paid-fetch.js.map +1 -1
package/lib/email.mjs
CHANGED
|
@@ -115,6 +115,40 @@ compatibility; new code should use 'info'.
|
|
|
115
115
|
|
|
116
116
|
Usage:
|
|
117
117
|
run402 email get-raw <message_id> [--output <file>] [--project <id>]
|
|
118
|
+
`,
|
|
119
|
+
create: `run402 email create — Create a project mailbox
|
|
120
|
+
|
|
121
|
+
Usage:
|
|
122
|
+
run402 email create <slug> [--project <id>]
|
|
123
|
+
|
|
124
|
+
Arguments:
|
|
125
|
+
<slug> Mailbox slug (3-63 chars, lowercase alphanumeric +
|
|
126
|
+
hyphens, no consecutive hyphens). Becomes
|
|
127
|
+
<slug>@mail.run402.com.
|
|
128
|
+
|
|
129
|
+
Options:
|
|
130
|
+
--project <id> Project ID (defaults to the active project)
|
|
131
|
+
|
|
132
|
+
Notes:
|
|
133
|
+
- One mailbox per project
|
|
134
|
+
|
|
135
|
+
Examples:
|
|
136
|
+
run402 email create my-app
|
|
137
|
+
run402 email create my-app --project prj_abc123
|
|
138
|
+
`,
|
|
139
|
+
get: `run402 email get — Get a message with replies
|
|
140
|
+
|
|
141
|
+
Usage:
|
|
142
|
+
run402 email get <message_id> [--project <id>]
|
|
143
|
+
|
|
144
|
+
Arguments:
|
|
145
|
+
<message_id> Message ID to fetch
|
|
146
|
+
|
|
147
|
+
Options:
|
|
148
|
+
--project <id> Project ID (defaults to the active project)
|
|
149
|
+
|
|
150
|
+
Examples:
|
|
151
|
+
run402 email get msg_abc123
|
|
118
152
|
`,
|
|
119
153
|
};
|
|
120
154
|
|
package/lib/functions.mjs
CHANGED
|
@@ -2,7 +2,7 @@ import { readFileSync } from "fs";
|
|
|
2
2
|
import { findProject, API } from "./config.mjs";
|
|
3
3
|
import { getSdk } from "./sdk.mjs";
|
|
4
4
|
import { reportSdkError, fail } from "./sdk-errors.mjs";
|
|
5
|
-
import { assertKnownFlags, hasHelp, normalizeArgv, parseIntegerFlag } from "./argparse.mjs";
|
|
5
|
+
import { assertKnownFlags, hasHelp, normalizeArgv, parseIntegerFlag, validateRegularFile } from "./argparse.mjs";
|
|
6
6
|
|
|
7
7
|
const HELP = `run402 functions — Manage serverless functions
|
|
8
8
|
|
|
@@ -141,6 +141,29 @@ Examples:
|
|
|
141
141
|
run402 functions update prj_abc123 send-reminders --schedule '0 */4 * * *'
|
|
142
142
|
run402 functions update prj_abc123 send-reminders --schedule-remove
|
|
143
143
|
run402 functions update prj_abc123 my-func --timeout 15 --memory 256
|
|
144
|
+
`,
|
|
145
|
+
list: `run402 functions list — List all functions for a project
|
|
146
|
+
|
|
147
|
+
Usage:
|
|
148
|
+
run402 functions list <project_id>
|
|
149
|
+
|
|
150
|
+
Arguments:
|
|
151
|
+
<project_id> Target project ID
|
|
152
|
+
|
|
153
|
+
Examples:
|
|
154
|
+
run402 functions list prj_abc123
|
|
155
|
+
`,
|
|
156
|
+
delete: `run402 functions delete — Delete a function from a project
|
|
157
|
+
|
|
158
|
+
Usage:
|
|
159
|
+
run402 functions delete <project_id> <name>
|
|
160
|
+
|
|
161
|
+
Arguments:
|
|
162
|
+
<project_id> Target project ID
|
|
163
|
+
<name> Function name to delete
|
|
164
|
+
|
|
165
|
+
Examples:
|
|
166
|
+
run402 functions delete prj_abc123 stripe-webhook
|
|
144
167
|
`,
|
|
145
168
|
};
|
|
146
169
|
|
|
@@ -158,6 +181,7 @@ async function deploy(projectId, name, args) {
|
|
|
158
181
|
if (!opts.file) {
|
|
159
182
|
fail({ code: "BAD_USAGE", message: "Missing --file <file>" });
|
|
160
183
|
}
|
|
184
|
+
validateRegularFile(opts.file, "--file");
|
|
161
185
|
const code = readFileSync(opts.file, "utf-8");
|
|
162
186
|
|
|
163
187
|
const deployOpts = { name, code };
|
package/lib/image.mjs
CHANGED
|
@@ -27,12 +27,44 @@ Notes:
|
|
|
27
27
|
- Use --output to save directly to a file instead of printing base64
|
|
28
28
|
`;
|
|
29
29
|
|
|
30
|
+
const SUB_HELP = {
|
|
31
|
+
generate: `run402 image generate — Generate an AI image from a text prompt
|
|
32
|
+
|
|
33
|
+
Usage:
|
|
34
|
+
run402 image generate "<prompt>" [options]
|
|
35
|
+
|
|
36
|
+
Arguments:
|
|
37
|
+
<prompt> Text prompt describing the image (quote it)
|
|
38
|
+
|
|
39
|
+
Options:
|
|
40
|
+
--aspect <ratio> Image aspect ratio: square | landscape | portrait
|
|
41
|
+
(default: square)
|
|
42
|
+
--output <file> Save image to file (e.g. output.png). If omitted,
|
|
43
|
+
returns base64 JSON to stdout.
|
|
44
|
+
|
|
45
|
+
Notes:
|
|
46
|
+
- Requires a funded allowance (run402 allowance create && run402 allowance fund)
|
|
47
|
+
- Payments are processed automatically via x402 micropayments
|
|
48
|
+
- Use --output to save directly to a file instead of printing base64
|
|
49
|
+
|
|
50
|
+
Examples:
|
|
51
|
+
run402 image generate "a startup mascot, pixel art"
|
|
52
|
+
run402 image generate "futuristic city at night" --aspect landscape
|
|
53
|
+
run402 image generate "portrait of a cat CEO" --aspect portrait --output cat.png
|
|
54
|
+
`,
|
|
55
|
+
};
|
|
56
|
+
|
|
30
57
|
export async function run(sub, args) {
|
|
31
58
|
if (!sub || sub === '--help' || sub === '-h') {
|
|
32
59
|
console.log(HELP);
|
|
33
60
|
process.exit(0);
|
|
34
61
|
}
|
|
35
62
|
|
|
63
|
+
if (Array.isArray(args) && (args.includes("--help") || args.includes("-h"))) {
|
|
64
|
+
console.log(SUB_HELP[sub] || HELP);
|
|
65
|
+
process.exit(0);
|
|
66
|
+
}
|
|
67
|
+
|
|
36
68
|
if (sub !== "generate") {
|
|
37
69
|
console.error(`Unknown subcommand: ${sub}\n`);
|
|
38
70
|
console.log(HELP);
|
|
@@ -43,7 +75,7 @@ export async function run(sub, args) {
|
|
|
43
75
|
let i = 0;
|
|
44
76
|
if (i < args.length && !args[i].startsWith("--")) opts.prompt = args[i++];
|
|
45
77
|
while (i < args.length) {
|
|
46
|
-
if (args[i] === "--help" || args[i] === "-h") { console.log(HELP); process.exit(0); }
|
|
78
|
+
if (args[i] === "--help" || args[i] === "-h") { console.log(SUB_HELP[sub] || HELP); process.exit(0); }
|
|
47
79
|
else if (args[i] === "--aspect" && args[i + 1]) { opts.aspect = args[++i]; }
|
|
48
80
|
else if (args[i] === "--output" && args[i + 1]) { opts.output = args[++i]; }
|
|
49
81
|
i++;
|
package/lib/message.mjs
CHANGED
|
@@ -10,21 +10,68 @@ Usage:
|
|
|
10
10
|
Notes:
|
|
11
11
|
- Requires an active tier (run402 tier set <tier>)
|
|
12
12
|
- Requires an allowance (run402 allowance create)
|
|
13
|
+
- Messages are capped at 8 KB (8192 bytes UTF-8) to keep the developer
|
|
14
|
+
inbox useful and prevent payload-dump misuse. Trim or summarize long
|
|
15
|
+
content (e.g. stack traces) before sending.
|
|
13
16
|
|
|
14
17
|
Examples:
|
|
15
18
|
run402 message send "Hello from my agent!"
|
|
16
19
|
`;
|
|
17
20
|
|
|
21
|
+
// Cap message body at a Twitter-ish but engineer-generous size: enough for
|
|
22
|
+
// a few paragraphs and a stack-trace excerpt, small enough that a misbehaving
|
|
23
|
+
// agent script can't dump arbitrary content into the developer inbox in one
|
|
24
|
+
// call. UTF-8 bytes (not characters) — emoji and accented chars count as
|
|
25
|
+
// multiple bytes.
|
|
26
|
+
const MESSAGE_MAX_BYTES = 8192;
|
|
27
|
+
|
|
28
|
+
const SUB_HELP = {
|
|
29
|
+
send: `run402 message send — Send a message to Run402 developers
|
|
30
|
+
|
|
31
|
+
Usage:
|
|
32
|
+
run402 message send <text>
|
|
33
|
+
|
|
34
|
+
Arguments:
|
|
35
|
+
<text> Message body (quote it; remaining args are joined with
|
|
36
|
+
spaces if multiple positional words are provided)
|
|
37
|
+
|
|
38
|
+
Notes:
|
|
39
|
+
- Requires an active tier (run402 tier set <tier>)
|
|
40
|
+
- Requires an allowance (run402 allowance create)
|
|
41
|
+
- Messages are capped at 8 KB (8192 bytes UTF-8) to keep the developer
|
|
42
|
+
inbox useful and prevent payload-dump misuse.
|
|
43
|
+
|
|
44
|
+
Examples:
|
|
45
|
+
run402 message send "Hello from my agent!"
|
|
46
|
+
`,
|
|
47
|
+
};
|
|
48
|
+
|
|
18
49
|
async function send(text) {
|
|
19
|
-
if (!text) {
|
|
50
|
+
if (!text || typeof text !== "string") {
|
|
20
51
|
fail({ code: "BAD_USAGE", message: "Missing message text." });
|
|
21
52
|
}
|
|
53
|
+
// Cap check runs BEFORE the allowance check so oversized payloads surface
|
|
54
|
+
// a structured size error instead of being masked by a missing-allowance
|
|
55
|
+
// exit.
|
|
56
|
+
const bytes = Buffer.byteLength(text, "utf-8");
|
|
57
|
+
if (bytes > MESSAGE_MAX_BYTES) {
|
|
58
|
+
fail({
|
|
59
|
+
code: "MESSAGE_TOO_LONG",
|
|
60
|
+
message: `Message is ${bytes} bytes; maximum is ${MESSAGE_MAX_BYTES} bytes (~8 KB).`,
|
|
61
|
+
hint: "Trim or summarize the message.",
|
|
62
|
+
details: { bytes, max_bytes: MESSAGE_MAX_BYTES },
|
|
63
|
+
});
|
|
64
|
+
}
|
|
22
65
|
// Preserve the aggressive early exit when no allowance is configured.
|
|
23
66
|
allowanceAuthHeaders("/message/v1");
|
|
24
67
|
|
|
25
68
|
try {
|
|
26
69
|
await getSdk().admin.sendMessage(text);
|
|
27
|
-
console.log(JSON.stringify({
|
|
70
|
+
console.log(JSON.stringify({
|
|
71
|
+
status: "ok",
|
|
72
|
+
message: "Message sent to Run402 developers.",
|
|
73
|
+
bytes_sent: bytes,
|
|
74
|
+
}));
|
|
28
75
|
} catch (err) {
|
|
29
76
|
reportSdkError(err);
|
|
30
77
|
}
|
|
@@ -33,7 +80,7 @@ async function send(text) {
|
|
|
33
80
|
export async function run(sub, args) {
|
|
34
81
|
if (!sub || sub === '--help' || sub === '-h') { console.log(HELP); process.exit(0); }
|
|
35
82
|
if (Array.isArray(args) && (args.includes("--help") || args.includes("-h"))) {
|
|
36
|
-
console.log(HELP);
|
|
83
|
+
console.log(SUB_HELP[sub] || HELP);
|
|
37
84
|
process.exit(0);
|
|
38
85
|
}
|
|
39
86
|
if (sub !== "send") {
|
package/lib/projects.mjs
CHANGED
|
@@ -2,7 +2,7 @@ import { readFileSync } from "fs";
|
|
|
2
2
|
import { findProject, loadKeyStore, API, allowanceAuthHeaders, resolveProjectId, getActiveProjectId } from "./config.mjs";
|
|
3
3
|
import { getSdk } from "./sdk.mjs";
|
|
4
4
|
import { reportSdkError, fail, parseFlagJson } from "./sdk-errors.mjs";
|
|
5
|
-
import { assertKnownFlags, failBadProjectId, hasHelp, normalizeArgv, positionalArgs } from "./argparse.mjs";
|
|
5
|
+
import { assertKnownFlags, failBadProjectId, hasHelp, normalizeArgv, positionalArgs, resolvePositionalProject, validateRegularFile } from "./argparse.mjs";
|
|
6
6
|
|
|
7
7
|
const HELP = `run402 projects — Manage your deployed Run402 projects
|
|
8
8
|
|
|
@@ -123,7 +123,37 @@ async function provision(args) {
|
|
|
123
123
|
const opts = { tier: "prototype", name: undefined };
|
|
124
124
|
for (let i = 0; i < args.length; i++) {
|
|
125
125
|
if (args[i] === "--tier" && args[i + 1]) opts.tier = args[++i];
|
|
126
|
-
|
|
126
|
+
// Use !== undefined so an empty-string value is captured (and rejected
|
|
127
|
+
// below) rather than silently dropped by the falsy-check pattern (GH-176).
|
|
128
|
+
if (args[i] === "--name" && args[i + 1] !== undefined) opts.name = args[++i];
|
|
129
|
+
}
|
|
130
|
+
// Validate --name when provided. Omitted --name lets the server pick a
|
|
131
|
+
// default. The same envelope should also be enforced server-side (GH-176).
|
|
132
|
+
if (opts.name !== undefined) {
|
|
133
|
+
if (opts.name === "") {
|
|
134
|
+
fail({
|
|
135
|
+
code: "BAD_PROJECT_NAME",
|
|
136
|
+
message: "--name must not be empty.",
|
|
137
|
+
details: { field: "--name" },
|
|
138
|
+
hint: "Provide a 1-128 character name, or omit --name to use the server-assigned default.",
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
if (opts.name.length > 128) {
|
|
142
|
+
fail({
|
|
143
|
+
code: "BAD_PROJECT_NAME",
|
|
144
|
+
message: `--name must be 1-128 characters, got ${opts.name.length}.`,
|
|
145
|
+
details: { field: "--name", length: opts.name.length, max: 128 },
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
// eslint-disable-next-line no-control-regex
|
|
149
|
+
if (/[\x00-\x1f\x7f]/.test(opts.name)) {
|
|
150
|
+
fail({
|
|
151
|
+
code: "BAD_PROJECT_NAME",
|
|
152
|
+
message: "--name contains control characters (newline, tab, etc).",
|
|
153
|
+
details: { field: "--name" },
|
|
154
|
+
hint: "Project names should be a single-line label.",
|
|
155
|
+
});
|
|
156
|
+
}
|
|
127
157
|
}
|
|
128
158
|
// Preserve the aggressive early exit when no allowance is configured —
|
|
129
159
|
// gives the user a more specific prompt than the SDK's 401/402 path.
|
|
@@ -145,13 +175,14 @@ async function provision(args) {
|
|
|
145
175
|
}
|
|
146
176
|
|
|
147
177
|
async function applyExpose(projectId, args = []) {
|
|
148
|
-
const p = findProject(projectId);
|
|
149
178
|
let file = null;
|
|
150
179
|
let inline = null;
|
|
151
180
|
for (let i = 0; i < args.length; i++) {
|
|
152
181
|
if (args[i] === "--file" && args[i + 1]) { file = args[++i]; }
|
|
153
182
|
else if (!inline && !args[i].startsWith("--")) { inline = args[i]; }
|
|
154
183
|
}
|
|
184
|
+
if (file) validateRegularFile(file, "--file");
|
|
185
|
+
const p = findProject(projectId);
|
|
155
186
|
const raw = file ? readFileSync(file, "utf-8") : inline;
|
|
156
187
|
if (!raw) {
|
|
157
188
|
fail({
|
|
@@ -222,7 +253,6 @@ async function keys(projectId) {
|
|
|
222
253
|
}
|
|
223
254
|
|
|
224
255
|
async function sqlCmd(projectId, args = []) {
|
|
225
|
-
const p = findProject(projectId);
|
|
226
256
|
let file = null;
|
|
227
257
|
let query = null;
|
|
228
258
|
let paramsRaw = null;
|
|
@@ -231,6 +261,8 @@ async function sqlCmd(projectId, args = []) {
|
|
|
231
261
|
else if (args[i] === "--params" && args[i + 1]) { paramsRaw = args[++i]; }
|
|
232
262
|
else if (!query && !args[i].startsWith("--")) { query = args[i]; }
|
|
233
263
|
}
|
|
264
|
+
if (file) validateRegularFile(file, "--file");
|
|
265
|
+
const p = findProject(projectId);
|
|
234
266
|
const sql = file ? readFileSync(file, "utf-8") : query;
|
|
235
267
|
if (!sql) {
|
|
236
268
|
fail({
|
|
@@ -259,6 +291,13 @@ async function sqlCmd(projectId, args = []) {
|
|
|
259
291
|
}
|
|
260
292
|
|
|
261
293
|
async function rest(projectId, table, queryParams) {
|
|
294
|
+
if (!table) {
|
|
295
|
+
fail({
|
|
296
|
+
code: "BAD_USAGE",
|
|
297
|
+
message: "Missing <table> argument. Usage: run402 projects rest [id] <table> [\"<query>\"]",
|
|
298
|
+
hint: "Run 'run402 projects schema <id>' to list tables.",
|
|
299
|
+
});
|
|
300
|
+
}
|
|
262
301
|
const p = findProject(projectId);
|
|
263
302
|
const res = await fetch(`${API}/rest/v1/${table}${queryParams ? '?' + queryParams : ''}`, { headers: { "apikey": p.anon_key } });
|
|
264
303
|
const data = await res.json();
|
|
@@ -373,35 +412,6 @@ async function deleteProject(projectId, args = []) {
|
|
|
373
412
|
}
|
|
374
413
|
}
|
|
375
414
|
|
|
376
|
-
// Resolve a positional project_id argument with active-project fallback (GH-102).
|
|
377
|
-
// Callers can tighten the legacy shorthand when a bare non-prj positional is
|
|
378
|
-
// more likely a mistyped project id than an argument for the active project.
|
|
379
|
-
function resolvePositionalProject(args, opts = {}) {
|
|
380
|
-
const first = Array.isArray(args) ? args[0] : undefined;
|
|
381
|
-
if (typeof first === "string" && first.startsWith("prj_")) {
|
|
382
|
-
return { projectId: first, rest: args.slice(1) };
|
|
383
|
-
}
|
|
384
|
-
if (
|
|
385
|
-
typeof first === "string" &&
|
|
386
|
-
first.length > 0 &&
|
|
387
|
-
!first.startsWith("-") &&
|
|
388
|
-
Array.isArray(opts.rejectBareFirstWhenFlagPresent) &&
|
|
389
|
-
opts.rejectBareFirstWhenFlagPresent.some((flag) => args.includes(flag))
|
|
390
|
-
) {
|
|
391
|
-
failBadProjectId(first);
|
|
392
|
-
}
|
|
393
|
-
if (typeof first === "string" && first.length > 0 && !first.startsWith("-") && opts.rejectBareFirst) {
|
|
394
|
-
failBadProjectId(first);
|
|
395
|
-
}
|
|
396
|
-
if (typeof first === "string" && first.length > 0 && !first.startsWith("-") && opts.maxBarePositionals !== undefined) {
|
|
397
|
-
const bare = positionalArgs(args, opts.valueFlags ?? []);
|
|
398
|
-
if (bare.length > opts.maxBarePositionals) {
|
|
399
|
-
failBadProjectId(first);
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
return { projectId: resolveProjectId(null), rest: Array.isArray(args) ? args : [] };
|
|
403
|
-
}
|
|
404
|
-
|
|
405
415
|
const FLAGS_BY_SUB = {
|
|
406
416
|
provision: { known: ["--tier", "--name"], values: ["--tier", "--name"] },
|
|
407
417
|
sql: { known: ["--file", "--params"], values: ["--file", "--params"] },
|
package/lib/sdk-errors.mjs
CHANGED
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
* validation: the call wasn't sent, so retrying is safe and won't help unless
|
|
30
30
|
* the user fixes input.
|
|
31
31
|
*/
|
|
32
|
-
export function fail({ message, code, hint, details, next_actions, retryable = false, safe_to_retry = true, exit_code = 1 } = {}) {
|
|
32
|
+
export function fail({ message, code, hint, details, next_actions, field, retryable = false, safe_to_retry = true, exit_code = 1 } = {}) {
|
|
33
33
|
const envelope = {
|
|
34
34
|
status: "error",
|
|
35
35
|
code: code ?? "BAD_USAGE",
|
|
@@ -39,6 +39,7 @@ export function fail({ message, code, hint, details, next_actions, retryable = f
|
|
|
39
39
|
};
|
|
40
40
|
if (hint !== undefined) envelope.hint = hint;
|
|
41
41
|
if (details !== undefined) envelope.details = details;
|
|
42
|
+
if (field !== undefined) envelope.field = field;
|
|
42
43
|
envelope.next_actions = Array.isArray(next_actions) ? next_actions : [];
|
|
43
44
|
envelope.trace_id = null;
|
|
44
45
|
console.error(JSON.stringify(envelope));
|
package/lib/secrets.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readFileSync } from "fs";
|
|
2
2
|
import { getSdk } from "./sdk.mjs";
|
|
3
3
|
import { reportSdkError, fail } from "./sdk-errors.mjs";
|
|
4
|
+
import { validateRegularFile } from "./argparse.mjs";
|
|
4
5
|
|
|
5
6
|
const HELP = `run402 secrets — Manage project secrets
|
|
6
7
|
|
|
@@ -45,6 +46,33 @@ Notes:
|
|
|
45
46
|
Examples:
|
|
46
47
|
run402 secrets set prj_abc123 STRIPE_KEY sk-1234
|
|
47
48
|
run402 secrets set prj_abc123 TLS_CERT --file cert.pem
|
|
49
|
+
`,
|
|
50
|
+
list: `run402 secrets list — List all secrets for a project
|
|
51
|
+
|
|
52
|
+
Usage:
|
|
53
|
+
run402 secrets list <id>
|
|
54
|
+
|
|
55
|
+
Arguments:
|
|
56
|
+
<id> Project ID (from 'run402 projects list')
|
|
57
|
+
|
|
58
|
+
Notes:
|
|
59
|
+
- Returns secret keys with a value_hash (first 8 hex chars of SHA-256)
|
|
60
|
+
for verifying the correct value was set; raw values are write-only
|
|
61
|
+
|
|
62
|
+
Examples:
|
|
63
|
+
run402 secrets list prj_abc123
|
|
64
|
+
`,
|
|
65
|
+
delete: `run402 secrets delete — Delete a secret from a project
|
|
66
|
+
|
|
67
|
+
Usage:
|
|
68
|
+
run402 secrets delete <id> <key>
|
|
69
|
+
|
|
70
|
+
Arguments:
|
|
71
|
+
<id> Project ID (from 'run402 projects list')
|
|
72
|
+
<key> Secret key name to remove
|
|
73
|
+
|
|
74
|
+
Examples:
|
|
75
|
+
run402 secrets delete prj_abc123 STRIPE_KEY
|
|
48
76
|
`,
|
|
49
77
|
};
|
|
50
78
|
|
|
@@ -55,6 +83,7 @@ async function set(projectId, key, args = []) {
|
|
|
55
83
|
if (args[i] === "--file" && args[i + 1]) { file = args[++i]; }
|
|
56
84
|
else if (!value && !args[i].startsWith("--")) { value = args[i]; }
|
|
57
85
|
}
|
|
86
|
+
if (file) validateRegularFile(file, "--file");
|
|
58
87
|
const val = file ? readFileSync(file, "utf-8") : value;
|
|
59
88
|
if (!val) {
|
|
60
89
|
fail({
|
package/lib/sender-domain.mjs
CHANGED
|
@@ -22,6 +22,83 @@ Examples:
|
|
|
22
22
|
run402 sender-domain inbound-disable kysigned.com
|
|
23
23
|
`;
|
|
24
24
|
|
|
25
|
+
const SUB_HELP = {
|
|
26
|
+
register: `run402 sender-domain register — Register a custom sender domain
|
|
27
|
+
|
|
28
|
+
Usage:
|
|
29
|
+
run402 sender-domain register <domain> [--project <id>]
|
|
30
|
+
|
|
31
|
+
Arguments:
|
|
32
|
+
<domain> Custom sender domain (e.g. kysigned.com)
|
|
33
|
+
|
|
34
|
+
Options:
|
|
35
|
+
--project <id> Project ID (defaults to the active project)
|
|
36
|
+
|
|
37
|
+
Notes:
|
|
38
|
+
- Returns DNS records (DKIM, SPF, DMARC) to add at your DNS provider
|
|
39
|
+
- Use 'run402 sender-domain status' to poll until verified
|
|
40
|
+
|
|
41
|
+
Examples:
|
|
42
|
+
run402 sender-domain register kysigned.com
|
|
43
|
+
run402 sender-domain register kysigned.com --project prj_abc123
|
|
44
|
+
`,
|
|
45
|
+
status: `run402 sender-domain status — Check verification status of the project's sender domain
|
|
46
|
+
|
|
47
|
+
Usage:
|
|
48
|
+
run402 sender-domain status [--project <id>]
|
|
49
|
+
|
|
50
|
+
Options:
|
|
51
|
+
--project <id> Project ID (defaults to the active project)
|
|
52
|
+
|
|
53
|
+
Examples:
|
|
54
|
+
run402 sender-domain status
|
|
55
|
+
run402 sender-domain status --project prj_abc123
|
|
56
|
+
`,
|
|
57
|
+
remove: `run402 sender-domain remove — Remove the project's custom sender domain
|
|
58
|
+
|
|
59
|
+
Usage:
|
|
60
|
+
run402 sender-domain remove [--project <id>]
|
|
61
|
+
|
|
62
|
+
Options:
|
|
63
|
+
--project <id> Project ID (defaults to the active project)
|
|
64
|
+
|
|
65
|
+
Examples:
|
|
66
|
+
run402 sender-domain remove
|
|
67
|
+
run402 sender-domain remove --project prj_abc123
|
|
68
|
+
`,
|
|
69
|
+
"inbound-enable": `run402 sender-domain inbound-enable — Enable inbound email for a sender domain
|
|
70
|
+
|
|
71
|
+
Usage:
|
|
72
|
+
run402 sender-domain inbound-enable <domain> [--project <id>]
|
|
73
|
+
|
|
74
|
+
Arguments:
|
|
75
|
+
<domain> Custom sender domain to enable inbound on
|
|
76
|
+
|
|
77
|
+
Options:
|
|
78
|
+
--project <id> Project ID (defaults to the active project)
|
|
79
|
+
|
|
80
|
+
Notes:
|
|
81
|
+
- Requires the domain to be DKIM-verified first
|
|
82
|
+
|
|
83
|
+
Examples:
|
|
84
|
+
run402 sender-domain inbound-enable kysigned.com
|
|
85
|
+
`,
|
|
86
|
+
"inbound-disable": `run402 sender-domain inbound-disable — Disable inbound email for a sender domain
|
|
87
|
+
|
|
88
|
+
Usage:
|
|
89
|
+
run402 sender-domain inbound-disable <domain> [--project <id>]
|
|
90
|
+
|
|
91
|
+
Arguments:
|
|
92
|
+
<domain> Custom sender domain to disable inbound on
|
|
93
|
+
|
|
94
|
+
Options:
|
|
95
|
+
--project <id> Project ID (defaults to the active project)
|
|
96
|
+
|
|
97
|
+
Examples:
|
|
98
|
+
run402 sender-domain inbound-disable kysigned.com
|
|
99
|
+
`,
|
|
100
|
+
};
|
|
101
|
+
|
|
25
102
|
function parseFlag(args, flag) {
|
|
26
103
|
for (let i = 0; i < args.length; i++) {
|
|
27
104
|
if (args[i] === flag && args[i + 1]) return args[i + 1];
|
|
@@ -106,7 +183,7 @@ async function inboundToggle(action, args) {
|
|
|
106
183
|
|
|
107
184
|
export async function run(sub, args) {
|
|
108
185
|
if (!sub || sub === "--help" || sub === "-h") { console.log(HELP); process.exit(0); }
|
|
109
|
-
if (Array.isArray(args) && (args.includes("--help") || args.includes("-h"))) { console.log(HELP); process.exit(0); }
|
|
186
|
+
if (Array.isArray(args) && (args.includes("--help") || args.includes("-h"))) { console.log(SUB_HELP[sub] || HELP); process.exit(0); }
|
|
110
187
|
switch (sub) {
|
|
111
188
|
case "register": await register(args); break;
|
|
112
189
|
case "status": await status(args); break;
|
package/lib/service.mjs
CHANGED
|
@@ -13,6 +13,35 @@ Notes:
|
|
|
13
13
|
balance, tier, projects), use 'run402 status'.
|
|
14
14
|
`;
|
|
15
15
|
|
|
16
|
+
const SUB_HELP = {
|
|
17
|
+
status: `run402 service status — Public service availability report
|
|
18
|
+
|
|
19
|
+
Usage:
|
|
20
|
+
run402 service status
|
|
21
|
+
|
|
22
|
+
Notes:
|
|
23
|
+
- Unauthenticated and free; no allowance required
|
|
24
|
+
- Returns uptime, supported capabilities, operator, and deployment info
|
|
25
|
+
- For account state (allowance, balance, tier, projects), use
|
|
26
|
+
'run402 status' instead
|
|
27
|
+
|
|
28
|
+
Examples:
|
|
29
|
+
run402 service status
|
|
30
|
+
`,
|
|
31
|
+
health: `run402 service health — Service liveness check
|
|
32
|
+
|
|
33
|
+
Usage:
|
|
34
|
+
run402 service health
|
|
35
|
+
|
|
36
|
+
Notes:
|
|
37
|
+
- Unauthenticated and free; no allowance required
|
|
38
|
+
- Returns per-dependency status and the deployed version
|
|
39
|
+
|
|
40
|
+
Examples:
|
|
41
|
+
run402 service health
|
|
42
|
+
`,
|
|
43
|
+
};
|
|
44
|
+
|
|
16
45
|
async function status() {
|
|
17
46
|
try {
|
|
18
47
|
const data = await getSdk().service.status();
|
|
@@ -34,7 +63,7 @@ async function health() {
|
|
|
34
63
|
export async function run(sub, args) {
|
|
35
64
|
if (!sub || sub === "--help" || sub === "-h") { console.log(HELP); process.exit(0); }
|
|
36
65
|
if (Array.isArray(args) && (args.includes("--help") || args.includes("-h"))) {
|
|
37
|
-
console.log(HELP);
|
|
66
|
+
console.log(SUB_HELP[sub] || HELP);
|
|
38
67
|
process.exit(0);
|
|
39
68
|
}
|
|
40
69
|
switch (sub) {
|
package/lib/subdomains.mjs
CHANGED
|
@@ -10,7 +10,7 @@ Usage:
|
|
|
10
10
|
Subcommands:
|
|
11
11
|
claim <name> [--project <id>] [--deployment <id>] Claim a subdomain
|
|
12
12
|
delete <name> --confirm [--project <id>] Release a subdomain. Requires --confirm.
|
|
13
|
-
list [<id>]
|
|
13
|
+
list [<id>] | list --project <id> List subdomains for a project
|
|
14
14
|
|
|
15
15
|
Options default to the active project and its last deployment when omitted.
|
|
16
16
|
Legacy syntax 'claim <deployment_id> <name>' is still supported.
|
|
@@ -48,6 +48,35 @@ Notes:
|
|
|
48
48
|
Examples:
|
|
49
49
|
run402 subdomains claim myapp
|
|
50
50
|
run402 subdomains claim myapp --deployment dpl_abc123 --project prj_abc123
|
|
51
|
+
`,
|
|
52
|
+
list: `run402 subdomains list — List subdomains claimed by a project
|
|
53
|
+
|
|
54
|
+
Usage:
|
|
55
|
+
run402 subdomains list [<id>]
|
|
56
|
+
|
|
57
|
+
Arguments:
|
|
58
|
+
<id> Project ID (defaults to the active project)
|
|
59
|
+
|
|
60
|
+
Examples:
|
|
61
|
+
run402 subdomains list
|
|
62
|
+
run402 subdomains list prj_abc123
|
|
63
|
+
`,
|
|
64
|
+
delete: `run402 subdomains delete — Release a claimed subdomain
|
|
65
|
+
|
|
66
|
+
Usage:
|
|
67
|
+
run402 subdomains delete <name> --confirm [--project <id>]
|
|
68
|
+
|
|
69
|
+
Arguments:
|
|
70
|
+
<name> Subdomain name to release
|
|
71
|
+
|
|
72
|
+
Options:
|
|
73
|
+
--confirm Required: releasing a subdomain is irreversible and
|
|
74
|
+
makes it available for any other project to claim
|
|
75
|
+
--project <id> Project ID (defaults to the active project)
|
|
76
|
+
|
|
77
|
+
Examples:
|
|
78
|
+
run402 subdomains delete myapp --confirm
|
|
79
|
+
run402 subdomains delete myapp --confirm --project prj_abc123
|
|
51
80
|
`,
|
|
52
81
|
};
|
|
53
82
|
|
|
@@ -122,8 +151,24 @@ async function deleteSubdomain(allArgs) {
|
|
|
122
151
|
}
|
|
123
152
|
}
|
|
124
153
|
|
|
125
|
-
|
|
126
|
-
|
|
154
|
+
function parseProjectFlag(args) {
|
|
155
|
+
let project = null;
|
|
156
|
+
const rest = [];
|
|
157
|
+
for (let i = 0; i < args.length; i++) {
|
|
158
|
+
if (args[i] === "--project" && args[i + 1]) { project = args[++i]; }
|
|
159
|
+
else { rest.push(args[i]); }
|
|
160
|
+
}
|
|
161
|
+
return { project, rest };
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async function list(args) {
|
|
165
|
+
const argList = Array.isArray(args) ? args : [];
|
|
166
|
+
const { project, rest } = parseProjectFlag(argList);
|
|
167
|
+
// Either --project <id> or a positional id is accepted; --project wins
|
|
168
|
+
// when both are supplied. Falls back to the active project when neither
|
|
169
|
+
// is given. Keeps backward-compat with the legacy `subdomains list <id>`
|
|
170
|
+
// form (GH-231; mirrors the GH-209 fix for `domains list`).
|
|
171
|
+
const projectId = resolveProjectId(project || rest[0]);
|
|
127
172
|
try {
|
|
128
173
|
const data = await getSdk().subdomains.list(projectId);
|
|
129
174
|
console.log(JSON.stringify(data, null, 2));
|
|
@@ -148,7 +193,7 @@ export async function run(sub, args) {
|
|
|
148
193
|
break;
|
|
149
194
|
}
|
|
150
195
|
case "delete": await deleteSubdomain(args); break;
|
|
151
|
-
case "list": await list(args
|
|
196
|
+
case "list": await list(args); break;
|
|
152
197
|
default:
|
|
153
198
|
console.error(`Unknown subcommand: ${sub}\n`);
|
|
154
199
|
console.log(HELP);
|
package/lib/tier.mjs
CHANGED
|
@@ -24,6 +24,46 @@ Examples:
|
|
|
24
24
|
run402 tier set hobby
|
|
25
25
|
`;
|
|
26
26
|
|
|
27
|
+
const SUB_HELP = {
|
|
28
|
+
status: `run402 tier status — Show current tier subscription state
|
|
29
|
+
|
|
30
|
+
Usage:
|
|
31
|
+
run402 tier status
|
|
32
|
+
|
|
33
|
+
Notes:
|
|
34
|
+
- Returns the current tier name, status, and expiry
|
|
35
|
+
- Use 'run402 tier set <tier>' to subscribe, renew, or upgrade
|
|
36
|
+
|
|
37
|
+
Examples:
|
|
38
|
+
run402 tier status
|
|
39
|
+
`,
|
|
40
|
+
set: `run402 tier set — Subscribe, renew, or upgrade your tier
|
|
41
|
+
|
|
42
|
+
Usage:
|
|
43
|
+
run402 tier set <tier>
|
|
44
|
+
|
|
45
|
+
Arguments:
|
|
46
|
+
<tier> One of: prototype, hobby, team
|
|
47
|
+
|
|
48
|
+
Tiers:
|
|
49
|
+
prototype $0.10/7d (free with testnet faucet)
|
|
50
|
+
hobby $5/30d
|
|
51
|
+
team $20/30d
|
|
52
|
+
|
|
53
|
+
Notes:
|
|
54
|
+
Server auto-detects action based on current allowance state:
|
|
55
|
+
- No tier or expired -> subscribe
|
|
56
|
+
- Same tier, active -> renew (extends from expiry)
|
|
57
|
+
- Higher tier -> upgrade (prorated refund to allowance)
|
|
58
|
+
- Lower tier, active -> rejected (wait for expiry)
|
|
59
|
+
Pays via x402 micropayments.
|
|
60
|
+
|
|
61
|
+
Examples:
|
|
62
|
+
run402 tier set prototype
|
|
63
|
+
run402 tier set hobby
|
|
64
|
+
`,
|
|
65
|
+
};
|
|
66
|
+
|
|
27
67
|
async function status() {
|
|
28
68
|
try {
|
|
29
69
|
const data = await getSdk().tier.status();
|
|
@@ -55,7 +95,7 @@ export async function run(sub, args) {
|
|
|
55
95
|
process.exit(0);
|
|
56
96
|
}
|
|
57
97
|
if (Array.isArray(args) && (args.includes("--help") || args.includes("-h"))) {
|
|
58
|
-
console.log(HELP);
|
|
98
|
+
console.log(SUB_HELP[sub] || HELP);
|
|
59
99
|
process.exit(0);
|
|
60
100
|
}
|
|
61
101
|
switch (sub) {
|