run402 1.54.1 → 1.54.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/lib/ai.mjs +6 -6
- package/lib/apps.mjs +9 -9
- package/lib/argparse.mjs +147 -0
- package/lib/auth.mjs +2 -2
- package/lib/blob.mjs +55 -22
- package/lib/functions.mjs +62 -29
- package/lib/projects.mjs +60 -29
- package/lib/secrets.mjs +6 -6
- package/lib/status.mjs +4 -1
- package/lib/subdomains.mjs +2 -2
- package/package.json +1 -1
- package/sdk/dist/index.d.ts +1 -0
- package/sdk/dist/index.d.ts.map +1 -1
- package/sdk/dist/index.js +5 -0
- package/sdk/dist/index.js.map +1 -1
- package/sdk/dist/namespaces/auth.d.ts +7 -0
- package/sdk/dist/namespaces/auth.d.ts.map +1 -1
- package/sdk/dist/namespaces/auth.js +24 -0
- package/sdk/dist/namespaces/auth.js.map +1 -1
- package/sdk/dist/namespaces/billing.d.ts +3 -0
- package/sdk/dist/namespaces/billing.d.ts.map +1 -1
- package/sdk/dist/namespaces/billing.js +6 -0
- package/sdk/dist/namespaces/billing.js.map +1 -1
- package/sdk/dist/namespaces/contracts.d.ts +3 -0
- package/sdk/dist/namespaces/contracts.d.ts.map +1 -1
- package/sdk/dist/namespaces/contracts.js +6 -0
- package/sdk/dist/namespaces/contracts.js.map +1 -1
- package/sdk/dist/namespaces/email.d.ts +4 -0
- package/sdk/dist/namespaces/email.d.ts.map +1 -1
- package/sdk/dist/namespaces/email.js +8 -0
- package/sdk/dist/namespaces/email.js.map +1 -1
- package/sdk/dist/namespaces/projects.d.ts +14 -0
- package/sdk/dist/namespaces/projects.d.ts.map +1 -1
- package/sdk/dist/namespaces/projects.js +72 -0
- package/sdk/dist/namespaces/projects.js.map +1 -1
- package/sdk/dist/namespaces/sender-domain.d.ts +2 -0
- package/sdk/dist/namespaces/sender-domain.d.ts.map +1 -1
- package/sdk/dist/namespaces/sender-domain.js +4 -0
- package/sdk/dist/namespaces/sender-domain.js.map +1 -1
- package/sdk/dist/scoped.d.ts +8 -1
- package/sdk/dist/scoped.d.ts.map +1 -1
- package/sdk/dist/scoped.js +21 -0
- package/sdk/dist/scoped.js.map +1 -1
package/lib/ai.mjs
CHANGED
|
@@ -13,10 +13,10 @@ Subcommands:
|
|
|
13
13
|
usage <project_id>
|
|
14
14
|
|
|
15
15
|
Examples:
|
|
16
|
-
run402 ai translate
|
|
17
|
-
run402 ai translate
|
|
18
|
-
run402 ai moderate
|
|
19
|
-
run402 ai usage
|
|
16
|
+
run402 ai translate prj_abc123 "Hello world" --to es
|
|
17
|
+
run402 ai translate prj_abc123 "Hello" --to ja --from en --context "formal business email"
|
|
18
|
+
run402 ai moderate prj_abc123 "content to check"
|
|
19
|
+
run402 ai usage prj_abc123
|
|
20
20
|
|
|
21
21
|
Notes:
|
|
22
22
|
- translate requires the AI Translation add-on on the project
|
|
@@ -44,8 +44,8 @@ Notes:
|
|
|
44
44
|
- Counts against the project's translation word quota
|
|
45
45
|
|
|
46
46
|
Examples:
|
|
47
|
-
run402 ai translate
|
|
48
|
-
run402 ai translate
|
|
47
|
+
run402 ai translate prj_abc123 "Hello world" --to es
|
|
48
|
+
run402 ai translate prj_abc123 "Hello" --to ja --from en \\
|
|
49
49
|
--context "formal business email"
|
|
50
50
|
`,
|
|
51
51
|
};
|
package/lib/apps.mjs
CHANGED
|
@@ -23,11 +23,11 @@ Examples:
|
|
|
23
23
|
run402 apps browse
|
|
24
24
|
run402 apps browse --tag auth
|
|
25
25
|
run402 apps fork ver_abc123 my-todo --tier prototype
|
|
26
|
-
run402 apps publish
|
|
27
|
-
run402 apps versions
|
|
26
|
+
run402 apps publish prj_abc123 --description "Todo app" --tags todo,auth --visibility public --fork-allowed
|
|
27
|
+
run402 apps versions prj_abc123
|
|
28
28
|
run402 apps inspect ver_abc123
|
|
29
|
-
run402 apps update
|
|
30
|
-
run402 apps delete
|
|
29
|
+
run402 apps update prj_abc123 ver_abc123 --description "Updated" --tags todo
|
|
30
|
+
run402 apps delete prj_abc123 ver_abc123
|
|
31
31
|
`;
|
|
32
32
|
|
|
33
33
|
const SUB_HELP = {
|
|
@@ -76,8 +76,8 @@ Options:
|
|
|
76
76
|
--fork-allowed Allow other users to fork this app
|
|
77
77
|
|
|
78
78
|
Examples:
|
|
79
|
-
run402 apps publish
|
|
80
|
-
run402 apps publish
|
|
79
|
+
run402 apps publish prj_abc123 --description "Todo app" --tags todo,auth
|
|
80
|
+
run402 apps publish prj_abc123 --visibility public --fork-allowed
|
|
81
81
|
`,
|
|
82
82
|
update: `run402 apps update — Update a published version's metadata
|
|
83
83
|
|
|
@@ -96,9 +96,9 @@ Options:
|
|
|
96
96
|
--no-fork Disable forking for this version
|
|
97
97
|
|
|
98
98
|
Examples:
|
|
99
|
-
run402 apps update
|
|
100
|
-
run402 apps update
|
|
101
|
-
run402 apps update
|
|
99
|
+
run402 apps update prj_abc123 ver_abc123 --description "Updated"
|
|
100
|
+
run402 apps update prj_abc123 ver_abc123 --tags todo,auth --fork-allowed
|
|
101
|
+
run402 apps update prj_abc123 ver_abc123 --no-fork
|
|
102
102
|
`,
|
|
103
103
|
};
|
|
104
104
|
|
package/lib/argparse.mjs
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { fail } from "./sdk-errors.mjs";
|
|
2
|
+
|
|
3
|
+
export function normalizeArgv(argv = []) {
|
|
4
|
+
const out = [];
|
|
5
|
+
for (const arg of argv ?? []) {
|
|
6
|
+
if (typeof arg === "string" && arg.startsWith("--") && arg.includes("=")) {
|
|
7
|
+
const eq = arg.indexOf("=");
|
|
8
|
+
out.push(arg.slice(0, eq), arg.slice(eq + 1));
|
|
9
|
+
} else {
|
|
10
|
+
out.push(arg);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return out;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function hasHelp(args = []) {
|
|
17
|
+
return args.includes("--help") || args.includes("-h");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function assertKnownFlags(args = [], knownFlags = [], flagsWithValues = []) {
|
|
21
|
+
const known = new Set(knownFlags);
|
|
22
|
+
const valueFlags = new Set(flagsWithValues);
|
|
23
|
+
for (let i = 0; i < args.length; i++) {
|
|
24
|
+
const arg = args[i];
|
|
25
|
+
if (valueFlags.has(arg)) {
|
|
26
|
+
i += 1;
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
if (typeof arg !== "string" || !arg.startsWith("-") || arg === "-") continue;
|
|
30
|
+
if (known.has(arg)) continue;
|
|
31
|
+
failUnknownFlag(arg, known);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function failUnknownFlag(flag, knownFlags = []) {
|
|
36
|
+
const known = [...knownFlags].filter((f) => typeof f === "string" && f.startsWith("-"));
|
|
37
|
+
const closest = closestFlag(flag, known);
|
|
38
|
+
fail({
|
|
39
|
+
code: "UNKNOWN_FLAG",
|
|
40
|
+
message: closest ? `Unknown flag: ${flag}. Did you mean ${closest}?` : `Unknown flag: ${flag}.`,
|
|
41
|
+
details: { flag, closest: closest ? [closest] : [] },
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function flagValue(args, flag) {
|
|
46
|
+
const idx = args.indexOf(flag);
|
|
47
|
+
if (idx === -1) return null;
|
|
48
|
+
if (idx + 1 >= args.length) {
|
|
49
|
+
fail({
|
|
50
|
+
code: "BAD_FLAG",
|
|
51
|
+
message: `${flag} requires a value`,
|
|
52
|
+
details: { flag },
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
return args[idx + 1];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function parseIntegerFlag(name, value, { min = 1, max = Number.POSITIVE_INFINITY, def } = {}) {
|
|
59
|
+
if (value === undefined || value === null) {
|
|
60
|
+
if (def !== undefined) return def;
|
|
61
|
+
fail({
|
|
62
|
+
code: "BAD_FLAG",
|
|
63
|
+
message: `${name} requires an integer value`,
|
|
64
|
+
details: { flag: name },
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
const raw = String(value);
|
|
68
|
+
if (!/^-?\d+$/.test(raw)) {
|
|
69
|
+
fail({
|
|
70
|
+
code: "BAD_FLAG",
|
|
71
|
+
message: `${name} must be an integer, got: ${raw}`,
|
|
72
|
+
details: { flag: name, value: raw },
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
const n = Number.parseInt(raw, 10);
|
|
76
|
+
if (n < min) {
|
|
77
|
+
fail({
|
|
78
|
+
code: "BAD_FLAG",
|
|
79
|
+
message: `${name} must be >= ${min}, got: ${n}`,
|
|
80
|
+
details: { flag: name, value: n, min },
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
if (n > max) {
|
|
84
|
+
fail({
|
|
85
|
+
code: "BAD_FLAG",
|
|
86
|
+
message: `${name} must be <= ${max}, got: ${n}`,
|
|
87
|
+
details: { flag: name, value: n, max },
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
return n;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function failBadProjectId(value) {
|
|
94
|
+
fail({
|
|
95
|
+
code: "BAD_PROJECT_ID",
|
|
96
|
+
message: `Argument '${value}' is not a project id. Project IDs must start with 'prj_'.`,
|
|
97
|
+
hint: "Omit the project id to use the active project, or pass the full prj_... id.",
|
|
98
|
+
details: { value, expected_prefix: "prj_" },
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function positionalArgs(args = [], flagsWithValues = []) {
|
|
103
|
+
const valueFlags = new Set(flagsWithValues);
|
|
104
|
+
const out = [];
|
|
105
|
+
for (let i = 0; i < args.length; i++) {
|
|
106
|
+
const arg = args[i];
|
|
107
|
+
if (valueFlags.has(arg)) {
|
|
108
|
+
i += 1;
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
if (typeof arg === "string" && arg.startsWith("-")) continue;
|
|
112
|
+
out.push(arg);
|
|
113
|
+
}
|
|
114
|
+
return out;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function closestFlag(flag, candidates) {
|
|
118
|
+
let best = null;
|
|
119
|
+
let bestDistance = Number.POSITIVE_INFINITY;
|
|
120
|
+
for (const candidate of candidates) {
|
|
121
|
+
const d = levenshtein(flag, candidate);
|
|
122
|
+
if (d < bestDistance) {
|
|
123
|
+
best = candidate;
|
|
124
|
+
bestDistance = d;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (!best) return null;
|
|
128
|
+
return bestDistance <= 3 ? best : null;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function levenshtein(a, b) {
|
|
132
|
+
const prev = Array.from({ length: b.length + 1 }, (_, i) => i);
|
|
133
|
+
const curr = Array.from({ length: b.length + 1 }, () => 0);
|
|
134
|
+
for (let i = 1; i <= a.length; i++) {
|
|
135
|
+
curr[0] = i;
|
|
136
|
+
for (let j = 1; j <= b.length; j++) {
|
|
137
|
+
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
138
|
+
curr[j] = Math.min(
|
|
139
|
+
curr[j - 1] + 1,
|
|
140
|
+
prev[j] + 1,
|
|
141
|
+
prev[j - 1] + cost,
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
for (let j = 0; j <= b.length; j++) prev[j] = curr[j];
|
|
145
|
+
}
|
|
146
|
+
return prev[b.length];
|
|
147
|
+
}
|
package/lib/auth.mjs
CHANGED
|
@@ -93,7 +93,7 @@ Notes:
|
|
|
93
93
|
|
|
94
94
|
Examples:
|
|
95
95
|
run402 auth settings --allow-password-set true
|
|
96
|
-
run402 auth settings --allow-password-set false --project
|
|
96
|
+
run402 auth settings --allow-password-set false --project prj_abc123
|
|
97
97
|
`,
|
|
98
98
|
providers: `run402 auth providers — List available auth providers
|
|
99
99
|
|
|
@@ -105,7 +105,7 @@ Options:
|
|
|
105
105
|
|
|
106
106
|
Examples:
|
|
107
107
|
run402 auth providers
|
|
108
|
-
run402 auth providers --project
|
|
108
|
+
run402 auth providers --project prj_abc123
|
|
109
109
|
`,
|
|
110
110
|
};
|
|
111
111
|
|
package/lib/blob.mjs
CHANGED
|
@@ -37,6 +37,7 @@ import { pipeline } from "node:stream/promises";
|
|
|
37
37
|
import { resolveProject, resolveProjectId, API } from "./config.mjs";
|
|
38
38
|
import { getSdk } from "./sdk.mjs";
|
|
39
39
|
import { reportSdkError, fail } from "./sdk-errors.mjs";
|
|
40
|
+
import { assertKnownFlags, hasHelp, normalizeArgv, parseIntegerFlag } from "./argparse.mjs";
|
|
40
41
|
|
|
41
42
|
const HELP = `run402 blob — Direct-to-S3 blob storage
|
|
42
43
|
|
|
@@ -62,13 +63,13 @@ Options:
|
|
|
62
63
|
--ttl <seconds> Signed-URL TTL (sign only; default 3600, max 604800)
|
|
63
64
|
|
|
64
65
|
Examples:
|
|
65
|
-
run402 blob put ./artifact.tgz --project
|
|
66
|
-
run402 blob put ./dist/**/*.png --project
|
|
67
|
-
run402 blob put huge.bin --project
|
|
68
|
-
run402 blob get images/logo.png --output /tmp/logo.png --project
|
|
69
|
-
run402 blob ls --project
|
|
70
|
-
run402 blob rm images/logo.png --project
|
|
71
|
-
run402 blob sign images/logo.png --project
|
|
66
|
+
run402 blob put ./artifact.tgz --project prj_abc123
|
|
67
|
+
run402 blob put ./dist/**/*.png --project prj_abc123 --key assets/
|
|
68
|
+
run402 blob put huge.bin --project prj_abc123 --immutable
|
|
69
|
+
run402 blob get images/logo.png --output /tmp/logo.png --project prj_abc123
|
|
70
|
+
run402 blob ls --project prj_abc123 --prefix images/
|
|
71
|
+
run402 blob rm images/logo.png --project prj_abc123
|
|
72
|
+
run402 blob sign images/logo.png --project prj_abc123 --ttl 600
|
|
72
73
|
`;
|
|
73
74
|
|
|
74
75
|
const SUB_HELP = {
|
|
@@ -90,9 +91,9 @@ Options:
|
|
|
90
91
|
--json Emit NDJSON progress events on stdout (for agent consumption)
|
|
91
92
|
|
|
92
93
|
Examples:
|
|
93
|
-
run402 blob put ./artifact.tgz --project
|
|
94
|
-
run402 blob put ./dist/**/*.png --project
|
|
95
|
-
run402 blob put huge.bin --project
|
|
94
|
+
run402 blob put ./artifact.tgz --project prj_abc123
|
|
95
|
+
run402 blob put ./dist/**/*.png --project prj_abc123 --key assets/
|
|
96
|
+
run402 blob put huge.bin --project prj_abc123 --immutable --concurrency 8
|
|
96
97
|
`,
|
|
97
98
|
get: `run402 blob get — Download a blob by key
|
|
98
99
|
|
|
@@ -107,7 +108,7 @@ Options:
|
|
|
107
108
|
--project <id> Project ID (defaults to active project)
|
|
108
109
|
|
|
109
110
|
Examples:
|
|
110
|
-
run402 blob get images/logo.png --output /tmp/logo.png --project
|
|
111
|
+
run402 blob get images/logo.png --output /tmp/logo.png --project prj_abc123
|
|
111
112
|
`,
|
|
112
113
|
ls: `run402 blob ls — List blob keys in a project
|
|
113
114
|
|
|
@@ -120,8 +121,8 @@ Options:
|
|
|
120
121
|
--limit <n> Max results (default 100, max 1000)
|
|
121
122
|
|
|
122
123
|
Examples:
|
|
123
|
-
run402 blob ls --project
|
|
124
|
-
run402 blob ls --project
|
|
124
|
+
run402 blob ls --project prj_abc123
|
|
125
|
+
run402 blob ls --project prj_abc123 --prefix images/ --limit 500
|
|
125
126
|
`,
|
|
126
127
|
rm: `run402 blob rm — Delete a blob
|
|
127
128
|
|
|
@@ -135,7 +136,7 @@ Options:
|
|
|
135
136
|
--project <id> Project ID (defaults to active project)
|
|
136
137
|
|
|
137
138
|
Examples:
|
|
138
|
-
run402 blob rm images/logo.png --project
|
|
139
|
+
run402 blob rm images/logo.png --project prj_abc123
|
|
139
140
|
`,
|
|
140
141
|
sign: `run402 blob sign — Create a presigned download URL for a blob
|
|
141
142
|
|
|
@@ -150,7 +151,7 @@ Options:
|
|
|
150
151
|
--ttl <seconds> Signed-URL TTL (default 3600, max 604800)
|
|
151
152
|
|
|
152
153
|
Examples:
|
|
153
|
-
run402 blob sign reports/2025-q4.pdf --project
|
|
154
|
+
run402 blob sign reports/2025-q4.pdf --project prj_abc123 --ttl 600
|
|
154
155
|
`,
|
|
155
156
|
diagnose: `run402 blob diagnose — Inspect the live CDN state for a public blob URL
|
|
156
157
|
|
|
@@ -186,7 +187,38 @@ function die(msg, exit_code = 1) {
|
|
|
186
187
|
fail({ code: "BAD_USAGE", message: msg, exit_code });
|
|
187
188
|
}
|
|
188
189
|
|
|
189
|
-
function
|
|
190
|
+
function dieApiFailure(prefix, http, body) {
|
|
191
|
+
if (body && typeof body === "object" && !Array.isArray(body)) {
|
|
192
|
+
const envelope = { status: "error", http, ...body };
|
|
193
|
+
if (!envelope.message && envelope.error) envelope.message = envelope.error;
|
|
194
|
+
console.error(JSON.stringify(envelope));
|
|
195
|
+
process.exit(1);
|
|
196
|
+
}
|
|
197
|
+
fail({
|
|
198
|
+
message: `${prefix}: HTTP ${http}${typeof body === "string" && body ? `: ${body.slice(0, 500)}` : ""}`,
|
|
199
|
+
details: { http },
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function parseArgs(rawArgs) {
|
|
204
|
+
const args = normalizeArgv(rawArgs);
|
|
205
|
+
const valueFlags = ["--project", "--key", "--concurrency", "--prefix", "--limit", "--output", "-o", "--ttl"];
|
|
206
|
+
assertKnownFlags(args, [
|
|
207
|
+
"--project",
|
|
208
|
+
"--key",
|
|
209
|
+
"--private",
|
|
210
|
+
"--immutable",
|
|
211
|
+
"--concurrency",
|
|
212
|
+
"--no-resume",
|
|
213
|
+
"--json",
|
|
214
|
+
"--prefix",
|
|
215
|
+
"--limit",
|
|
216
|
+
"--output",
|
|
217
|
+
"-o",
|
|
218
|
+
"--ttl",
|
|
219
|
+
"--help",
|
|
220
|
+
"-h",
|
|
221
|
+
], valueFlags);
|
|
190
222
|
const out = { positional: [], project: null, key: null, private: false, immutable: false,
|
|
191
223
|
concurrency: 4, resume: true, json: false, prefix: null, limit: null,
|
|
192
224
|
output: null, ttl: null };
|
|
@@ -196,13 +228,13 @@ function parseArgs(args) {
|
|
|
196
228
|
else if (a === "--key") out.key = args[++i];
|
|
197
229
|
else if (a === "--private") out.private = true;
|
|
198
230
|
else if (a === "--immutable") out.immutable = true;
|
|
199
|
-
else if (a === "--concurrency") out.concurrency =
|
|
231
|
+
else if (a === "--concurrency") out.concurrency = parseIntegerFlag("--concurrency", args[++i], { min: 1 });
|
|
200
232
|
else if (a === "--no-resume") out.resume = false;
|
|
201
233
|
else if (a === "--json") out.json = true;
|
|
202
234
|
else if (a === "--prefix") out.prefix = args[++i];
|
|
203
|
-
else if (a === "--limit") out.limit =
|
|
235
|
+
else if (a === "--limit") out.limit = parseIntegerFlag("--limit", args[++i], { min: 1, max: 1000 });
|
|
204
236
|
else if (a === "--output" || a === "-o") out.output = args[++i];
|
|
205
|
-
else if (a === "--ttl") out.ttl =
|
|
237
|
+
else if (a === "--ttl") out.ttl = parseIntegerFlag("--ttl", args[++i], { min: 1, max: 604800 });
|
|
206
238
|
else if (!a.startsWith("--")) out.positional.push(a);
|
|
207
239
|
}
|
|
208
240
|
return out;
|
|
@@ -284,7 +316,7 @@ async function putOne(project, filePath, opts) {
|
|
|
284
316
|
immutable: opts.immutable,
|
|
285
317
|
sha256,
|
|
286
318
|
});
|
|
287
|
-
if (init.status !== 201)
|
|
319
|
+
if (init.status !== 201) dieApiFailure("Init failed", init.status, init.body);
|
|
288
320
|
initRes = init.body;
|
|
289
321
|
saveState({
|
|
290
322
|
upload_id: initRes.upload_id,
|
|
@@ -330,7 +362,7 @@ async function putOne(project, filePath, opts) {
|
|
|
330
362
|
? { parts: etags.map((e, i) => ({ part_number: i + 1, etag: e.etag })) }
|
|
331
363
|
: {};
|
|
332
364
|
const complete = await apiFetch(`${API}/storage/v1/uploads/${state.upload_id}/complete`, "POST", project, body);
|
|
333
|
-
if (complete.status !== 200)
|
|
365
|
+
if (complete.status !== 200) dieApiFailure("Complete failed", complete.status, complete.body);
|
|
334
366
|
|
|
335
367
|
removeState(state.upload_id);
|
|
336
368
|
log(opts, { event: "done", ...complete.body });
|
|
@@ -565,7 +597,8 @@ export async function run(sub, args) {
|
|
|
565
597
|
console.log(HELP);
|
|
566
598
|
process.exit(0);
|
|
567
599
|
}
|
|
568
|
-
|
|
600
|
+
args = normalizeArgv(args);
|
|
601
|
+
if (Array.isArray(args) && hasHelp(args)) {
|
|
569
602
|
console.log(SUB_HELP[sub] || HELP);
|
|
570
603
|
process.exit(0);
|
|
571
604
|
}
|
package/lib/functions.mjs
CHANGED
|
@@ -2,6 +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
6
|
|
|
6
7
|
const HELP = `run402 functions — Manage serverless functions
|
|
7
8
|
|
|
@@ -21,18 +22,18 @@ Subcommands:
|
|
|
21
22
|
delete <id> <name> Delete a function
|
|
22
23
|
|
|
23
24
|
Examples:
|
|
24
|
-
run402 functions deploy
|
|
25
|
-
run402 functions deploy
|
|
26
|
-
run402 functions deploy
|
|
27
|
-
run402 functions invoke
|
|
28
|
-
run402 functions logs
|
|
29
|
-
run402 functions logs
|
|
30
|
-
run402 functions logs
|
|
31
|
-
run402 functions update
|
|
32
|
-
run402 functions update
|
|
33
|
-
run402 functions update
|
|
34
|
-
run402 functions list
|
|
35
|
-
run402 functions delete
|
|
25
|
+
run402 functions deploy prj_abc123 stripe-webhook --file handler.ts
|
|
26
|
+
run402 functions deploy prj_abc123 send-reminders --file remind.ts --schedule '*/15 * * * *'
|
|
27
|
+
run402 functions deploy prj_abc123 send-reminders --file remind.ts --schedule '' # remove schedule
|
|
28
|
+
run402 functions invoke prj_abc123 stripe-webhook --body '{"event":"test"}'
|
|
29
|
+
run402 functions logs prj_abc123 stripe-webhook --tail 100
|
|
30
|
+
run402 functions logs prj_abc123 stripe-webhook --since 2026-03-29T14:00:00Z
|
|
31
|
+
run402 functions logs prj_abc123 stripe-webhook --follow
|
|
32
|
+
run402 functions update prj_abc123 send-reminders --schedule '0 */4 * * *'
|
|
33
|
+
run402 functions update prj_abc123 send-reminders --schedule-remove
|
|
34
|
+
run402 functions update prj_abc123 my-func --timeout 15 --memory 256
|
|
35
|
+
run402 functions list prj_abc123
|
|
36
|
+
run402 functions delete prj_abc123 stripe-webhook
|
|
36
37
|
|
|
37
38
|
Notes:
|
|
38
39
|
- Code must export a default async function: export default async (req: Request) => Response
|
|
@@ -77,10 +78,10 @@ Notes:
|
|
|
77
78
|
notes such as bundle-size advisories
|
|
78
79
|
|
|
79
80
|
Examples:
|
|
80
|
-
run402 functions deploy
|
|
81
|
-
run402 functions deploy
|
|
81
|
+
run402 functions deploy prj_abc123 stripe-webhook --file handler.ts
|
|
82
|
+
run402 functions deploy prj_abc123 send-reminders --file remind.ts \\
|
|
82
83
|
--schedule '*/15 * * * *'
|
|
83
|
-
run402 functions deploy
|
|
84
|
+
run402 functions deploy prj_abc123 send-reminders --file remind.ts --schedule ''
|
|
84
85
|
`,
|
|
85
86
|
invoke: `run402 functions invoke — Invoke a deployed function
|
|
86
87
|
|
|
@@ -96,8 +97,8 @@ Options:
|
|
|
96
97
|
--body <json> Request body (ignored for GET/HEAD)
|
|
97
98
|
|
|
98
99
|
Examples:
|
|
99
|
-
run402 functions invoke
|
|
100
|
-
run402 functions invoke
|
|
100
|
+
run402 functions invoke prj_abc123 stripe-webhook --body '{"event":"test"}'
|
|
101
|
+
run402 functions invoke prj_abc123 ping --method GET
|
|
101
102
|
`,
|
|
102
103
|
logs: `run402 functions logs — Fetch or tail function logs
|
|
103
104
|
|
|
@@ -114,9 +115,9 @@ Options:
|
|
|
114
115
|
--follow Poll every 3s and stream new entries (Ctrl-C to stop)
|
|
115
116
|
|
|
116
117
|
Examples:
|
|
117
|
-
run402 functions logs
|
|
118
|
-
run402 functions logs
|
|
119
|
-
run402 functions logs
|
|
118
|
+
run402 functions logs prj_abc123 stripe-webhook --tail 100
|
|
119
|
+
run402 functions logs prj_abc123 stripe-webhook --since 2026-03-29T14:00:00Z
|
|
120
|
+
run402 functions logs prj_abc123 stripe-webhook --follow
|
|
120
121
|
`,
|
|
121
122
|
update: `run402 functions update — Update function config without re-deploying
|
|
122
123
|
|
|
@@ -137,18 +138,20 @@ Notes:
|
|
|
137
138
|
Must provide at least one of the options above.
|
|
138
139
|
|
|
139
140
|
Examples:
|
|
140
|
-
run402 functions update
|
|
141
|
-
run402 functions update
|
|
142
|
-
run402 functions update
|
|
141
|
+
run402 functions update prj_abc123 send-reminders --schedule '0 */4 * * *'
|
|
142
|
+
run402 functions update prj_abc123 send-reminders --schedule-remove
|
|
143
|
+
run402 functions update prj_abc123 my-func --timeout 15 --memory 256
|
|
143
144
|
`,
|
|
144
145
|
};
|
|
145
146
|
|
|
146
147
|
async function deploy(projectId, name, args) {
|
|
148
|
+
assertRequiredProjectAndName(projectId, name, "run402 functions deploy <project_id> <name> --file <file>");
|
|
149
|
+
assertKnownFlags(args, ["--file", "--timeout", "--memory", "--deps", "--schedule", "--help", "-h"], ["--file", "--timeout", "--memory", "--deps", "--schedule"]);
|
|
147
150
|
const opts = { file: null, timeout: undefined, memory: undefined, deps: undefined, schedule: undefined };
|
|
148
151
|
for (let i = 0; i < args.length; i++) {
|
|
149
152
|
if (args[i] === "--file" && args[i + 1]) opts.file = args[++i];
|
|
150
|
-
if (args[i] === "--timeout"
|
|
151
|
-
if (args[i] === "--memory"
|
|
153
|
+
if (args[i] === "--timeout") opts.timeout = parseIntegerFlag("--timeout", args[++i], { min: 1 });
|
|
154
|
+
if (args[i] === "--memory") opts.memory = parseIntegerFlag("--memory", args[++i], { min: 1 });
|
|
152
155
|
if (args[i] === "--deps" && args[i + 1]) opts.deps = args[++i].split(",");
|
|
153
156
|
if (args[i] === "--schedule" && i + 1 < args.length) opts.schedule = args[++i];
|
|
154
157
|
}
|
|
@@ -175,6 +178,8 @@ async function deploy(projectId, name, args) {
|
|
|
175
178
|
}
|
|
176
179
|
|
|
177
180
|
async function invoke(projectId, name, args) {
|
|
181
|
+
assertRequiredProjectAndName(projectId, name, "run402 functions invoke <project_id> <name> [--method <M>] [--body <json>]");
|
|
182
|
+
assertKnownFlags(args, ["--method", "--body", "--help", "-h"], ["--method", "--body"]);
|
|
178
183
|
const opts = { method: "POST", body: undefined };
|
|
179
184
|
for (let i = 0; i < args.length; i++) {
|
|
180
185
|
if (args[i] === "--method" && args[i + 1]) opts.method = args[++i];
|
|
@@ -198,11 +203,13 @@ async function invoke(projectId, name, args) {
|
|
|
198
203
|
}
|
|
199
204
|
|
|
200
205
|
async function logs(projectId, name, args) {
|
|
206
|
+
assertRequiredProjectAndName(projectId, name, "run402 functions logs <project_id> <name> [--tail <n>]");
|
|
207
|
+
assertKnownFlags(args, ["--tail", "--since", "--follow", "--help", "-h"], ["--tail", "--since"]);
|
|
201
208
|
let tail = 50;
|
|
202
209
|
let since = undefined;
|
|
203
210
|
let follow = false;
|
|
204
211
|
for (let i = 0; i < args.length; i++) {
|
|
205
|
-
if (args[i] === "--tail"
|
|
212
|
+
if (args[i] === "--tail") tail = parseIntegerFlag("--tail", args[++i], { min: 1 });
|
|
206
213
|
if (args[i] === "--since" && args[i + 1]) since = args[++i];
|
|
207
214
|
if (args[i] === "--follow") follow = true;
|
|
208
215
|
}
|
|
@@ -269,6 +276,8 @@ async function logs(projectId, name, args) {
|
|
|
269
276
|
}
|
|
270
277
|
|
|
271
278
|
async function update(projectId, name, args) {
|
|
279
|
+
assertRequiredProjectAndName(projectId, name, "run402 functions update <project_id> <name> [options]");
|
|
280
|
+
assertKnownFlags(args, ["--schedule", "--schedule-remove", "--timeout", "--memory", "--help", "-h"], ["--schedule", "--timeout", "--memory"]);
|
|
272
281
|
let schedule = undefined;
|
|
273
282
|
let scheduleRemove = false;
|
|
274
283
|
let timeout = undefined;
|
|
@@ -276,8 +285,8 @@ async function update(projectId, name, args) {
|
|
|
276
285
|
for (let i = 0; i < args.length; i++) {
|
|
277
286
|
if (args[i] === "--schedule" && i + 1 < args.length) schedule = args[++i];
|
|
278
287
|
if (args[i] === "--schedule-remove") scheduleRemove = true;
|
|
279
|
-
if (args[i] === "--timeout"
|
|
280
|
-
if (args[i] === "--memory"
|
|
288
|
+
if (args[i] === "--timeout") timeout = parseIntegerFlag("--timeout", args[++i], { min: 1 });
|
|
289
|
+
if (args[i] === "--memory") memory = parseIntegerFlag("--memory", args[++i], { min: 1 });
|
|
281
290
|
}
|
|
282
291
|
|
|
283
292
|
const updateOpts = {};
|
|
@@ -305,6 +314,7 @@ async function update(projectId, name, args) {
|
|
|
305
314
|
}
|
|
306
315
|
|
|
307
316
|
async function list(projectId) {
|
|
317
|
+
assertRequiredProject(projectId, "run402 functions list <project_id>");
|
|
308
318
|
try {
|
|
309
319
|
const data = await getSdk().functions.list(projectId);
|
|
310
320
|
console.log(JSON.stringify(data, null, 2));
|
|
@@ -314,6 +324,7 @@ async function list(projectId) {
|
|
|
314
324
|
}
|
|
315
325
|
|
|
316
326
|
async function deleteFunction(projectId, name) {
|
|
327
|
+
assertRequiredProjectAndName(projectId, name, "run402 functions delete <project_id> <name>");
|
|
317
328
|
try {
|
|
318
329
|
await getSdk().functions.delete(projectId, name);
|
|
319
330
|
console.log(JSON.stringify({ status: "ok", message: `Function '${name}' deleted.` }));
|
|
@@ -324,7 +335,8 @@ async function deleteFunction(projectId, name) {
|
|
|
324
335
|
|
|
325
336
|
export async function run(sub, args) {
|
|
326
337
|
if (!sub || sub === '--help' || sub === '-h') { console.log(HELP); process.exit(0); }
|
|
327
|
-
|
|
338
|
+
args = normalizeArgv(args);
|
|
339
|
+
if (Array.isArray(args) && hasHelp(args)) {
|
|
328
340
|
console.log(SUB_HELP[sub] || HELP);
|
|
329
341
|
process.exit(0);
|
|
330
342
|
}
|
|
@@ -341,3 +353,24 @@ export async function run(sub, args) {
|
|
|
341
353
|
process.exit(1);
|
|
342
354
|
}
|
|
343
355
|
}
|
|
356
|
+
|
|
357
|
+
function assertRequiredProject(projectId, usage) {
|
|
358
|
+
if (!projectId || String(projectId).startsWith("-")) {
|
|
359
|
+
fail({
|
|
360
|
+
code: "BAD_USAGE",
|
|
361
|
+
message: "Missing <project_id>.",
|
|
362
|
+
hint: usage,
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
function assertRequiredProjectAndName(projectId, name, usage) {
|
|
368
|
+
assertRequiredProject(projectId, usage);
|
|
369
|
+
if (!name || String(name).startsWith("-")) {
|
|
370
|
+
fail({
|
|
371
|
+
code: "BAD_USAGE",
|
|
372
|
+
message: "Missing <name>.",
|
|
373
|
+
hint: usage,
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
}
|