run402 4.8.0 → 4.10.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/cli.mjs +20 -8
- package/lib/admin.mjs +18 -25
- package/lib/agent.mjs +2 -2
- package/lib/ai.mjs +2 -2
- package/lib/allowance.mjs +2 -2
- package/lib/apps.mjs +69 -51
- package/lib/archives.mjs +2 -7
- package/lib/argparse.mjs +131 -3
- package/lib/asset-wire.mjs +59 -0
- package/lib/assets.mjs +14 -12
- package/lib/auth.mjs +2 -2
- package/lib/billing.mjs +17 -13
- package/lib/branches.mjs +22 -23
- package/lib/cache.mjs +2 -6
- package/lib/cdn.mjs +2 -2
- package/lib/ci.mjs +4 -1
- package/lib/cloud.mjs +27 -28
- package/lib/command-manifest.mjs +352 -0
- package/lib/contracts.mjs +49 -11
- package/lib/core.mjs +3 -13
- package/lib/credentials.mjs +3 -13
- package/lib/deploy-v2.mjs +21 -8
- package/lib/deploy.mjs +2 -5
- package/lib/doctor.mjs +32 -4
- package/lib/domains.mjs +2 -2
- package/lib/email.mjs +2 -2
- package/lib/functions.mjs +100 -55
- package/lib/grants.mjs +42 -22
- package/lib/image.mjs +2 -2
- package/lib/jobs.mjs +18 -11
- package/lib/message.mjs +2 -2
- package/lib/notifications.mjs +6 -12
- package/lib/operator.mjs +2 -7
- package/lib/org.mjs +88 -49
- package/lib/projects.mjs +68 -39
- package/lib/secrets.mjs +99 -41
- package/lib/service.mjs +3 -2
- package/lib/sites.mjs +2 -2
- package/lib/snapshots.mjs +22 -24
- package/lib/subdomains.mjs +2 -2
- package/lib/tier.mjs +2 -2
- package/lib/transfer.mjs +2 -1
- package/lib/up.mjs +12 -6
- package/lib/wallets.mjs +6 -9
- package/lib/webhook-secret.mjs +3 -8
- package/lib/webhooks.mjs +2 -2
- package/package.json +1 -1
- package/sdk/dist/actions.d.ts +20 -1
- package/sdk/dist/actions.d.ts.map +1 -1
- package/sdk/dist/actions.js.map +1 -1
- package/sdk/dist/namespaces/projects.d.ts +2 -1
- package/sdk/dist/namespaces/projects.d.ts.map +1 -1
- package/sdk/dist/namespaces/projects.js +8 -12
- package/sdk/dist/namespaces/projects.js.map +1 -1
- package/sdk/dist/node/actions-node.d.ts.map +1 -1
- package/sdk/dist/node/actions-node.js +114 -8
- package/sdk/dist/node/actions-node.js.map +1 -1
- package/sdk/dist/node/deploy-manifest.d.ts +36 -0
- package/sdk/dist/node/deploy-manifest.d.ts.map +1 -1
- package/sdk/dist/node/deploy-manifest.js +112 -3
- package/sdk/dist/node/deploy-manifest.js.map +1 -1
- package/sdk/dist/node/index.d.ts +1 -1
- package/sdk/dist/node/index.d.ts.map +1 -1
- package/sdk/dist/node/index.js.map +1 -1
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* toWireAssetRef — project an SDK AssetRef (which carries camelCase TS
|
|
3
|
+
* conveniences like `cdnUrl`, `immutableUrl`, `contentSha256`, `size`) onto
|
|
4
|
+
* the CANONICAL gateway wire shape: snake_case keys only, no duplicate
|
|
5
|
+
* values under two casings.
|
|
6
|
+
*
|
|
7
|
+
* Canonical key set (gateway asset envelope):
|
|
8
|
+
* key, sha256, size_bytes, content_type, visibility, immutable,
|
|
9
|
+
* url, immutable_url, cdn_url, cdn_immutable_url, sri, etag,
|
|
10
|
+
* content_digest, + the v1.49/v1.50/v1.54 image fields
|
|
11
|
+
* (width_px, height_px, blurhash, variant_spec_version, display_url,
|
|
12
|
+
* display_immutable_url, variants, metadata, image_format, image_info,
|
|
13
|
+
* image_exif, image_exif_policy, blurhash_data_url, asset_schema).
|
|
14
|
+
*
|
|
15
|
+
* Unknown snake_case keys from newer gateways are preserved as-is; every
|
|
16
|
+
* camelCase key (the documented SDK aliases and any future ones) is dropped,
|
|
17
|
+
* with the aliases mapped back to their canonical snake twin when the snake
|
|
18
|
+
* form is missing from the input.
|
|
19
|
+
*
|
|
20
|
+
* The SDK keeps its camelCase conveniences for typed consumers (e.g.
|
|
21
|
+
* @run402/astro reads `cdnUrl`); this projector is the CLI/MCP output
|
|
22
|
+
* boundary only.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
// SDK-only convenience keys that must never appear in wire output. `size`
|
|
26
|
+
// and `cdn` are lowercase but still SDK-only: `size` duplicates
|
|
27
|
+
// `size_bytes`, `cdn` is the SDK's invalidation envelope (camelCase inner
|
|
28
|
+
// keys, locally synthesized).
|
|
29
|
+
const SDK_ONLY_KEYS = new Set(["size", "cdn"]);
|
|
30
|
+
|
|
31
|
+
export function toWireAssetRef(ref) {
|
|
32
|
+
if (!ref || typeof ref !== "object" || Array.isArray(ref)) return ref;
|
|
33
|
+
const out = {};
|
|
34
|
+
for (const [key, value] of Object.entries(ref)) {
|
|
35
|
+
if (typeof value === "function") continue; // tag emitters (scriptTag, …)
|
|
36
|
+
if (SDK_ONLY_KEYS.has(key)) continue;
|
|
37
|
+
if (/[A-Z]/.test(key)) continue; // camelCase SDK aliases/conveniences
|
|
38
|
+
out[key] = value;
|
|
39
|
+
}
|
|
40
|
+
// Canonical fields whose only SDK source is a camelCase convenience.
|
|
41
|
+
if (out.content_type === undefined && typeof ref.contentType === "string") {
|
|
42
|
+
out.content_type = ref.contentType;
|
|
43
|
+
}
|
|
44
|
+
// SDK naming vs wire naming: `cdnUrl` is the IMMUTABLE cdn url,
|
|
45
|
+
// `cdnMutableUrl` the mutable one.
|
|
46
|
+
if (out.cdn_url === undefined && ref.cdnMutableUrl !== undefined) {
|
|
47
|
+
out.cdn_url = ref.cdnMutableUrl;
|
|
48
|
+
}
|
|
49
|
+
if (out.cdn_immutable_url === undefined && ref.cdnUrl !== undefined) {
|
|
50
|
+
out.cdn_immutable_url = ref.cdnUrl;
|
|
51
|
+
}
|
|
52
|
+
if (out.content_digest === undefined && ref.contentDigest !== undefined) {
|
|
53
|
+
out.content_digest = ref.contentDigest;
|
|
54
|
+
}
|
|
55
|
+
if (out.immutable === undefined) {
|
|
56
|
+
out.immutable = ref.immutable_url !== null && ref.immutable_url !== undefined;
|
|
57
|
+
}
|
|
58
|
+
return out;
|
|
59
|
+
}
|
package/lib/assets.mjs
CHANGED
|
@@ -31,7 +31,8 @@ import { pipeline } from "node:stream/promises";
|
|
|
31
31
|
import { resolveProjectId } from "./config.mjs";
|
|
32
32
|
import { getSdk } from "./sdk.mjs";
|
|
33
33
|
import { reportSdkError, fail } from "./sdk-errors.mjs";
|
|
34
|
-
import { assertKnownFlags, hasHelp, normalizeArgv, parseIntegerFlag } from "./argparse.mjs";
|
|
34
|
+
import { assertKnownFlags, hasHelp, normalizeArgv, parseIntegerFlag, failUnknownSubcommand } from "./argparse.mjs";
|
|
35
|
+
import { toWireAssetRef } from "./asset-wire.mjs";
|
|
35
36
|
|
|
36
37
|
const HELP = `run402 blob — Direct-to-S3 blob storage
|
|
37
38
|
|
|
@@ -54,7 +55,7 @@ Options:
|
|
|
54
55
|
--exif-policy keep|strip v1.50: EXIF retention policy for image uploads (default keep).
|
|
55
56
|
--stream NDJSON per-file progress events (for agent consumption).
|
|
56
57
|
Without --stream, only the final results array is
|
|
57
|
-
printed. --json is
|
|
58
|
+
printed. --json is an accepted alias for --stream.
|
|
58
59
|
--prefix <p> Prefix filter (ls only)
|
|
59
60
|
--limit <n> Max results (ls only; default 100, max 1000)
|
|
60
61
|
--sort <key> v1.50 ls only: key:asc | createdAt:asc | createdAt:desc (default key:asc).
|
|
@@ -103,7 +104,7 @@ Options:
|
|
|
103
104
|
from the stored bytes and the image_exif response field.
|
|
104
105
|
--stream Emit NDJSON per-file progress events on stdout (for
|
|
105
106
|
agent consumption). Default: emit only the final
|
|
106
|
-
results array (also JSON). --json is
|
|
107
|
+
results array (also JSON). --json is an accepted
|
|
107
108
|
alias for --stream.
|
|
108
109
|
|
|
109
110
|
Examples:
|
|
@@ -256,12 +257,10 @@ function parseArgs(rawArgs) {
|
|
|
256
257
|
else if (a === "--concurrency") out.concurrency = parseIntegerFlag("--concurrency", args[++i], { min: 1 });
|
|
257
258
|
else if (a === "--no-resume") out.resume = false;
|
|
258
259
|
else if (a === "--stream") out.stream = true;
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
);
|
|
264
|
-
}
|
|
260
|
+
// `--json` and `--stream` are permanent aliases on `assets put` (both mean
|
|
261
|
+
// NDJSON progress events on stdout); elsewhere `--json` is a no-op since
|
|
262
|
+
// stdout is already JSON.
|
|
263
|
+
else if (a === "--json") { out.stream = true; }
|
|
265
264
|
else if (a === "--prefix") out.prefix = args[++i];
|
|
266
265
|
else if (a === "--limit") out.limit = parseIntegerFlag("--limit", args[++i], { min: 1, max: 1000 });
|
|
267
266
|
else if (a === "--output" || a === "-o") out.output = args[++i];
|
|
@@ -460,8 +459,11 @@ async function putOne(projectId, filePath, opts) {
|
|
|
460
459
|
...(opts.metadata ? { metadata: opts.metadata } : {}),
|
|
461
460
|
...(opts.exifPolicy ? { exifPolicy: opts.exifPolicy } : {}),
|
|
462
461
|
});
|
|
463
|
-
|
|
464
|
-
|
|
462
|
+
// Canonical wire shape only on stdout: snake_case keys, no camelCase
|
|
463
|
+
// duplicates (the SDK's AssetRef carries both; toWireAssetRef projects).
|
|
464
|
+
const wire = toWireAssetRef(result);
|
|
465
|
+
log(opts, { event: "done", ...wire });
|
|
466
|
+
return wire;
|
|
465
467
|
}
|
|
466
468
|
|
|
467
469
|
function computeDestKey(filePath, keyOpt) {
|
|
@@ -683,6 +685,6 @@ export async function run(sub, args) {
|
|
|
683
685
|
case "sign": await sign(defaultProject, args); break;
|
|
684
686
|
case "diagnose": await diagnose(defaultProject, args); break;
|
|
685
687
|
default:
|
|
686
|
-
|
|
688
|
+
failUnknownSubcommand("assets", sub);
|
|
687
689
|
}
|
|
688
690
|
}
|
package/lib/auth.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { resolveProjectId } from "./config.mjs";
|
|
2
2
|
import { getSdk } from "./sdk.mjs";
|
|
3
3
|
import { reportSdkError, fail } from "./sdk-errors.mjs";
|
|
4
|
-
import { assertKnownFlags, hasHelp, normalizeArgv } from "./argparse.mjs";
|
|
4
|
+
import { assertKnownFlags, hasHelp, normalizeArgv, failUnknownSubcommand } from "./argparse.mjs";
|
|
5
5
|
|
|
6
6
|
const HELP = `run402 auth — Manage project user authentication
|
|
7
7
|
|
|
@@ -757,6 +757,6 @@ export async function run(sub, args) {
|
|
|
757
757
|
case "providers": await providers(args); break;
|
|
758
758
|
case "scaffold-roles": scaffoldRoles(args); break;
|
|
759
759
|
default:
|
|
760
|
-
|
|
760
|
+
failUnknownSubcommand("auth", sub);
|
|
761
761
|
}
|
|
762
762
|
}
|
package/lib/billing.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getSdk } from "./sdk.mjs";
|
|
2
2
|
import { reportSdkError, fail } from "./sdk-errors.mjs";
|
|
3
|
-
import { assertKnownFlags, flagValue, normalizeArgv, parseIntegerFlag, positionalArgs } from "./argparse.mjs";
|
|
3
|
+
import { assertKnownFlags, flagValue, normalizeArgv, parseIntegerFlag, positionalArgs, failUnknownSubcommand } from "./argparse.mjs";
|
|
4
4
|
|
|
5
5
|
const HELP = `run402 billing — Email organizations and org checkouts
|
|
6
6
|
|
|
@@ -232,18 +232,20 @@ async function createEmail(args) {
|
|
|
232
232
|
|
|
233
233
|
async function linkWallet(args) {
|
|
234
234
|
const parsedArgs = normalizeArgv(args);
|
|
235
|
-
assertKnownFlags(parsedArgs, ["--help", "-h"]);
|
|
236
|
-
const
|
|
235
|
+
assertKnownFlags(parsedArgs, ["--wallet", "--help", "-h"], ["--wallet"]);
|
|
236
|
+
const walletFlag = flagValue(parsedArgs, "--wallet");
|
|
237
|
+
const positionals = positionalArgs(parsedArgs, ["--wallet"]);
|
|
237
238
|
const organizationId = positionals[0];
|
|
238
|
-
const wallet = positionals[1];
|
|
239
|
-
|
|
240
|
-
|
|
239
|
+
const wallet = walletFlag ?? positionals[1];
|
|
240
|
+
const max = walletFlag ? 1 : 2;
|
|
241
|
+
if (positionals.length > max) {
|
|
242
|
+
fail({ code: "BAD_USAGE", message: `Unexpected argument for billing link-wallet: ${positionals[max]}` });
|
|
241
243
|
}
|
|
242
244
|
if (!organizationId || !wallet) {
|
|
243
245
|
fail({
|
|
244
246
|
code: "BAD_USAGE",
|
|
245
247
|
message: "Missing <org_id> and/or <wallet_address>.",
|
|
246
|
-
hint: "run402 billing link-wallet <org_id> <wallet_address>",
|
|
248
|
+
hint: "run402 billing link-wallet <org_id> --wallet <wallet_address>",
|
|
247
249
|
});
|
|
248
250
|
}
|
|
249
251
|
try {
|
|
@@ -262,19 +264,21 @@ async function linkWallet(args) {
|
|
|
262
264
|
|
|
263
265
|
async function autoRecharge(args) {
|
|
264
266
|
const parsedArgs = normalizeArgv(args);
|
|
265
|
-
const valueFlags = ["--threshold"];
|
|
267
|
+
const valueFlags = ["--threshold", "--state"];
|
|
266
268
|
assertKnownFlags(parsedArgs, [...valueFlags, "--help", "-h"], valueFlags);
|
|
269
|
+
const stateFlag = flagValue(parsedArgs, "--state");
|
|
267
270
|
const positionals = positionalArgs(parsedArgs, valueFlags);
|
|
268
271
|
const organizationId = positionals[0];
|
|
269
|
-
const state = positionals[1];
|
|
270
|
-
|
|
271
|
-
|
|
272
|
+
const state = stateFlag ?? positionals[1];
|
|
273
|
+
const max = stateFlag ? 1 : 2;
|
|
274
|
+
if (positionals.length > max) {
|
|
275
|
+
fail({ code: "BAD_USAGE", message: `Unexpected argument for billing auto-recharge: ${positionals[max]}` });
|
|
272
276
|
}
|
|
273
277
|
if (!organizationId || !state || !["on", "off"].includes(state)) {
|
|
274
278
|
fail({
|
|
275
279
|
code: "BAD_USAGE",
|
|
276
280
|
message: "Missing <org_id> and/or <on|off>.",
|
|
277
|
-
hint: "run402 billing auto-recharge <org_id> <on|off> [--threshold <n>]",
|
|
281
|
+
hint: "run402 billing auto-recharge <org_id> --state <on|off> [--threshold <n>]",
|
|
278
282
|
});
|
|
279
283
|
}
|
|
280
284
|
const thresholdStr = flagValue(parsedArgs, "--threshold");
|
|
@@ -355,6 +359,6 @@ export async function run(sub, args) {
|
|
|
355
359
|
case "balance": await balance(args); break;
|
|
356
360
|
case "history": await history(args); break;
|
|
357
361
|
default:
|
|
358
|
-
|
|
362
|
+
failUnknownSubcommand("billing", sub);
|
|
359
363
|
}
|
|
360
364
|
}
|
package/lib/branches.mjs
CHANGED
|
@@ -8,19 +8,24 @@ import {
|
|
|
8
8
|
normalizeArgv,
|
|
9
9
|
parseIntegerFlag,
|
|
10
10
|
positionalArgs,
|
|
11
|
+
resolveProjectSelector,
|
|
12
|
+
failUnknownSubcommand,
|
|
11
13
|
} from "./argparse.mjs";
|
|
12
|
-
import { resolveProjectId } from "./config.mjs";
|
|
13
14
|
|
|
14
15
|
const HELP = `run402 branches — Contained project data branches
|
|
15
16
|
|
|
16
17
|
Usage:
|
|
17
|
-
run402 branches create [project
|
|
18
|
-
run402 branches list [project
|
|
19
|
-
run402 branches renew
|
|
20
|
-
run402 branches delete
|
|
18
|
+
run402 branches create [--project <id>] [--from-snapshot <snapshot-id>] [--name <label>] [--email-mode sandbox|off] [--enable-cron] [--ttl-days <n>] [--json]
|
|
19
|
+
run402 branches list [--project <id>] [--json]
|
|
20
|
+
run402 branches renew <branch-project-id> [--project <id>] [--ttl-days <n>] [--json]
|
|
21
|
+
run402 branches delete <branch-project-id> [--project <id>] [--json]
|
|
22
|
+
|
|
23
|
+
Legacy (still supported): a leading prj_... parent-project positional,
|
|
24
|
+
e.g. run402 branches renew prj_parent prj_branch. --project defaults to the
|
|
25
|
+
active project.
|
|
21
26
|
`;
|
|
22
27
|
|
|
23
|
-
const FLAG_VALUES = ["--from-snapshot", "--name", "--email-mode", "--ttl-days"];
|
|
28
|
+
const FLAG_VALUES = ["--project", "--from-snapshot", "--name", "--email-mode", "--ttl-days"];
|
|
24
29
|
const FLAGS = new Set([...FLAG_VALUES, "--enable-cron", "--json", "--help", "-h"]);
|
|
25
30
|
|
|
26
31
|
export async function run(sub, args = []) {
|
|
@@ -37,17 +42,12 @@ export async function run(sub, args = []) {
|
|
|
37
42
|
case "renew": return renew(rest);
|
|
38
43
|
case "delete": return deleteBranch(rest);
|
|
39
44
|
default:
|
|
40
|
-
|
|
41
|
-
code: "UNKNOWN_SUBCOMMAND",
|
|
42
|
-
message: `Unknown branches subcommand: ${sub}`,
|
|
43
|
-
hint: "Run `run402 branches --help` for usage.",
|
|
44
|
-
details: { command: "branches", subcommand: sub },
|
|
45
|
-
});
|
|
45
|
+
failUnknownSubcommand("branches", sub);
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
async function create(args) {
|
|
50
|
-
const projectId =
|
|
50
|
+
const { projectId } = resolveProjectSelector(args, { valueFlags: FLAG_VALUES });
|
|
51
51
|
const emailMode = flagValue(args, "--email-mode") ?? undefined;
|
|
52
52
|
if (emailMode !== undefined) assertAllowedValue(emailMode, ["sandbox", "off"], "--email-mode");
|
|
53
53
|
const ttlDaysFlag = flagValue(args, "--ttl-days");
|
|
@@ -67,7 +67,7 @@ async function create(args) {
|
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
async function list(args) {
|
|
70
|
-
const projectId =
|
|
70
|
+
const { projectId } = resolveProjectSelector(args, { valueFlags: FLAG_VALUES });
|
|
71
71
|
try {
|
|
72
72
|
const result = await getSdk().branches.list(projectId);
|
|
73
73
|
console.log(JSON.stringify({ project_id: projectId, ...result }, null, 2));
|
|
@@ -100,14 +100,13 @@ async function deleteBranch(args) {
|
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
function resolveOptionalProject(value) {
|
|
104
|
-
if (value && String(value).startsWith("prj_")) return value;
|
|
105
|
-
return resolveProjectId(null);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
103
|
function resolveProjectAndBranch(args, usage) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
104
|
+
// Canonical: `<branch-project-id> [--project <parent-id>]`. Branch ids are
|
|
105
|
+
// themselves prj_..., so a leading prj_ positional is only treated as the
|
|
106
|
+
// PARENT project when a second positional follows (requireRestPositional) —
|
|
107
|
+
// the legacy `renew prj_parent prj_branch` form.
|
|
108
|
+
const { projectId, rest } = resolveProjectSelector(args, { valueFlags: FLAG_VALUES, requireRestPositional: true });
|
|
109
|
+
const pos = positionalArgs(rest, FLAG_VALUES);
|
|
110
|
+
if (pos.length !== 1) fail({ code: "BAD_USAGE", message: `Usage: ${usage}` });
|
|
111
|
+
return { projectId, branchProjectId: pos[0] };
|
|
113
112
|
}
|
package/lib/cache.mjs
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
|
|
19
19
|
import { getSdk } from "./sdk.mjs";
|
|
20
20
|
import { reportSdkError, fail } from "./sdk-errors.mjs";
|
|
21
|
-
import { assertKnownFlags, flagValue, normalizeArgv } from "./argparse.mjs";
|
|
21
|
+
import { assertKnownFlags, flagValue, normalizeArgv, failUnknownSubcommand } from "./argparse.mjs";
|
|
22
22
|
import { editRequestAction } from "./next-actions.mjs";
|
|
23
23
|
|
|
24
24
|
// Locally-defined helpers — argparse.mjs's normalized form is a flat
|
|
@@ -99,11 +99,7 @@ export async function run(sub, args) {
|
|
|
99
99
|
await invalidate(args);
|
|
100
100
|
break;
|
|
101
101
|
default:
|
|
102
|
-
|
|
103
|
-
code: "UNKNOWN_SUBCOMMAND",
|
|
104
|
-
message: `Unknown cache subcommand: ${sub}`,
|
|
105
|
-
hint: "Run `run402 cache --help` for usage.",
|
|
106
|
-
details: { command: "cache", subcommand: sub },
|
|
102
|
+
failUnknownSubcommand("cache", sub, {
|
|
107
103
|
next_actions: [editRequestAction("run402 cache --help", "Choose a supported cache subcommand.")],
|
|
108
104
|
});
|
|
109
105
|
}
|
package/lib/cdn.mjs
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
import { resolveProjectId } from "./config.mjs";
|
|
17
17
|
import { getSdk } from "./sdk.mjs";
|
|
18
18
|
import { reportSdkError, fail } from "./sdk-errors.mjs";
|
|
19
|
-
import { assertKnownFlags, flagValue, normalizeArgv, parseIntegerFlag, positionalArgs } from "./argparse.mjs";
|
|
19
|
+
import { assertKnownFlags, flagValue, normalizeArgv, parseIntegerFlag, positionalArgs, failUnknownSubcommand } from "./argparse.mjs";
|
|
20
20
|
|
|
21
21
|
const HELP = `run402 cdn — CloudFront CDN diagnostics for public blob URLs
|
|
22
22
|
|
|
@@ -135,6 +135,6 @@ export async function run(sub, args) {
|
|
|
135
135
|
await waitFresh(defaultProject, args);
|
|
136
136
|
break;
|
|
137
137
|
default:
|
|
138
|
-
|
|
138
|
+
failUnknownSubcommand("cdn", sub);
|
|
139
139
|
}
|
|
140
140
|
}
|
package/lib/ci.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { failUnknownSubcommand } from "./argparse.mjs";
|
|
2
3
|
import { randomBytes } from "node:crypto";
|
|
3
4
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
4
5
|
import { dirname, resolve } from "node:path";
|
|
@@ -96,6 +97,8 @@ function parseFlags(args, allowed, { repeatable = new Set() } = {}) {
|
|
|
96
97
|
positional.push(arg);
|
|
97
98
|
continue;
|
|
98
99
|
}
|
|
100
|
+
// CLI-wide convention: --json is accepted everywhere (stdout is already JSON).
|
|
101
|
+
if (arg === "--json") continue;
|
|
99
102
|
if (!allowed.has(arg)) {
|
|
100
103
|
fail({
|
|
101
104
|
code: "BAD_USAGE",
|
|
@@ -457,6 +460,6 @@ export async function run(sub, args) {
|
|
|
457
460
|
case "revoke": await revoke(args); break;
|
|
458
461
|
case "set-asset-scopes": await setAssetScopes(args); break;
|
|
459
462
|
default:
|
|
460
|
-
|
|
463
|
+
failUnknownSubcommand("ci", sub);
|
|
461
464
|
}
|
|
462
465
|
}
|
package/lib/cloud.mjs
CHANGED
|
@@ -3,14 +3,18 @@ import { dirname, resolve } from "node:path";
|
|
|
3
3
|
|
|
4
4
|
import { getSdk } from "./sdk.mjs";
|
|
5
5
|
import { fail, reportSdkError } from "./sdk-errors.mjs";
|
|
6
|
-
import { assertAllowedValue, assertKnownFlags, flagValue, hasHelp, normalizeArgv, parseIntegerFlag, positionalArgs } from "./argparse.mjs";
|
|
6
|
+
import { assertAllowedValue, assertKnownFlags, flagValue, hasHelp, normalizeArgv, parseIntegerFlag, positionalArgs, resolveProjectSelector, failUnknownSubcommand } from "./argparse.mjs";
|
|
7
7
|
|
|
8
8
|
const HELP = `run402 cloud — Run402 Cloud portability commands
|
|
9
9
|
|
|
10
10
|
Usage:
|
|
11
|
-
run402 cloud archives create <
|
|
12
|
-
run402 cloud archives download <
|
|
13
|
-
run402 cloud archives status <
|
|
11
|
+
run402 cloud archives create [--project <id>] [options]
|
|
12
|
+
run402 cloud archives download <archive-id> --output <file> [--project <id>] [--json]
|
|
13
|
+
run402 cloud archives status <archive-id> [--project <id>] [--json]
|
|
14
|
+
|
|
15
|
+
Legacy (still supported): a leading prj_... positional selects the project,
|
|
16
|
+
e.g. run402 cloud archives download <project-id> <archive-id> --output <file>.
|
|
17
|
+
--project defaults to the active project.
|
|
14
18
|
|
|
15
19
|
Canonical agent path:
|
|
16
20
|
run402 cloud archives create prj_... \\
|
|
@@ -31,6 +35,7 @@ Options for create:
|
|
|
31
35
|
`;
|
|
32
36
|
|
|
33
37
|
const FLAG_VALUES = [
|
|
38
|
+
"--project",
|
|
34
39
|
"--scope",
|
|
35
40
|
"--auth",
|
|
36
41
|
"--consistency",
|
|
@@ -55,11 +60,7 @@ export async function run(sub, args = []) {
|
|
|
55
60
|
return;
|
|
56
61
|
}
|
|
57
62
|
if (sub !== "archives") {
|
|
58
|
-
|
|
59
|
-
code: "UNKNOWN_SUBCOMMAND",
|
|
60
|
-
message: `Unknown cloud subcommand: ${sub}`,
|
|
61
|
-
hint: "Run `run402 cloud --help` for usage.",
|
|
62
|
-
details: { command: "cloud", subcommand: sub },
|
|
63
|
+
failUnknownSubcommand("cloud", sub, {
|
|
63
64
|
next_actions: [{ type: "run_command", command: "run402 cloud archives --help" }],
|
|
64
65
|
});
|
|
65
66
|
}
|
|
@@ -68,11 +69,7 @@ export async function run(sub, args = []) {
|
|
|
68
69
|
if (action === "create") return create(rest);
|
|
69
70
|
if (action === "download") return download(rest);
|
|
70
71
|
if (action === "status") return status(rest);
|
|
71
|
-
|
|
72
|
-
code: "UNKNOWN_SUBCOMMAND",
|
|
73
|
-
message: `Unknown cloud archives subcommand: ${action}`,
|
|
74
|
-
hint: "Run `run402 cloud archives --help` for usage.",
|
|
75
|
-
details: { command: "cloud archives", subcommand: action },
|
|
72
|
+
failUnknownSubcommand("cloud archives", action, {
|
|
76
73
|
next_actions: [{ type: "run_command", command: "run402 cloud archives --help" }],
|
|
77
74
|
});
|
|
78
75
|
}
|
|
@@ -80,10 +77,10 @@ export async function run(sub, args = []) {
|
|
|
80
77
|
async function create(rawArgs) {
|
|
81
78
|
const args = normalizeArgv(rawArgs);
|
|
82
79
|
assertKnownFlags(args, [...FLAGS], FLAG_VALUES);
|
|
83
|
-
const
|
|
84
|
-
const
|
|
85
|
-
if (
|
|
86
|
-
fail({ code: "
|
|
80
|
+
const { projectId, rest } = resolveProjectSelector(args, { valueFlags: FLAG_VALUES });
|
|
81
|
+
const extraPos = positionalArgs(rest, FLAG_VALUES);
|
|
82
|
+
if (extraPos.length > 0) {
|
|
83
|
+
fail({ code: "BAD_USAGE", message: `Unexpected argument for cloud archives create: ${extraPos[0]}` });
|
|
87
84
|
}
|
|
88
85
|
const scope = flagValue(args, "--scope") ?? "portable-runtime-v1";
|
|
89
86
|
const auth = flagValue(args, "--auth") ?? "stubs";
|
|
@@ -170,12 +167,13 @@ async function create(rawArgs) {
|
|
|
170
167
|
|
|
171
168
|
async function download(rawArgs) {
|
|
172
169
|
const args = normalizeArgv(rawArgs);
|
|
173
|
-
assertKnownFlags(args, ["--output", "--json", "--help", "-h"], ["--output"]);
|
|
174
|
-
const
|
|
175
|
-
const [
|
|
170
|
+
assertKnownFlags(args, ["--project", "--output", "--json", "--help", "-h"], ["--project", "--output"]);
|
|
171
|
+
const { projectId, rest } = resolveProjectSelector(args, { valueFlags: ["--project", "--output"] });
|
|
172
|
+
const pos = positionalArgs(rest, ["--project", "--output"]);
|
|
173
|
+
const [archiveId] = pos;
|
|
176
174
|
const output = flagValue(args, "--output");
|
|
177
|
-
if (!
|
|
178
|
-
fail({ code: "BAD_USAGE", message: "Usage: run402 cloud archives download <
|
|
175
|
+
if (!archiveId || pos.length > 1 || !output) {
|
|
176
|
+
fail({ code: "BAD_USAGE", message: "Usage: run402 cloud archives download <archive-id> --output <file> [--project <id>] [--json]" });
|
|
179
177
|
}
|
|
180
178
|
try {
|
|
181
179
|
const download = await getSdk().archives.download(projectId, archiveId);
|
|
@@ -200,11 +198,12 @@ async function download(rawArgs) {
|
|
|
200
198
|
|
|
201
199
|
async function status(rawArgs) {
|
|
202
200
|
const args = normalizeArgv(rawArgs);
|
|
203
|
-
assertKnownFlags(args, ["--json", "--help", "-h"], []);
|
|
204
|
-
const
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
|
|
201
|
+
assertKnownFlags(args, ["--project", "--json", "--help", "-h"], ["--project"]);
|
|
202
|
+
const { projectId, rest } = resolveProjectSelector(args, { valueFlags: ["--project"] });
|
|
203
|
+
const pos = positionalArgs(rest, ["--project"]);
|
|
204
|
+
const [archiveId] = pos;
|
|
205
|
+
if (!archiveId || pos.length > 1) {
|
|
206
|
+
fail({ code: "BAD_USAGE", message: "Usage: run402 cloud archives status <archive-id> [--project <id>] [--json]" });
|
|
208
207
|
}
|
|
209
208
|
try {
|
|
210
209
|
const archive = await getSdk().archives.get(projectId, archiveId);
|