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
package/lib/image.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { writeFileSync } from "fs";
|
|
2
2
|
import { getSdk } from "./sdk.mjs";
|
|
3
3
|
import { reportSdkError, fail } from "./sdk-errors.mjs";
|
|
4
|
-
import { assertAllowedValue, assertKnownFlags, flagValue, normalizeArgv, positionalArgs } from "./argparse.mjs";
|
|
4
|
+
import { assertAllowedValue, assertKnownFlags, flagValue, normalizeArgv, positionalArgs, failUnknownSubcommand } from "./argparse.mjs";
|
|
5
5
|
|
|
6
6
|
const HELP = `run402 image — Generate AI images via x402 micropayments
|
|
7
7
|
|
|
@@ -67,7 +67,7 @@ export async function run(sub, args) {
|
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
if (sub !== "generate") {
|
|
70
|
-
|
|
70
|
+
failUnknownSubcommand("image", sub);
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
const parsedArgs = normalizeArgv(args);
|
package/lib/jobs.mjs
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
positionalArgs,
|
|
15
15
|
requirePositionalCount,
|
|
16
16
|
validateRegularFile,
|
|
17
|
+
failUnknownSubcommand,
|
|
17
18
|
} from "./argparse.mjs";
|
|
18
19
|
|
|
19
20
|
const HELP = `run402 jobs — Submit and inspect platform-managed jobs
|
|
@@ -27,7 +28,7 @@ Subcommands:
|
|
|
27
28
|
logs <job_id> Read job logs
|
|
28
29
|
cancel <job_id> Cancel a queued or running job
|
|
29
30
|
purge Purge all job runs for the project
|
|
30
|
-
artifacts get <job_id> <
|
|
31
|
+
artifacts get <job_id> --file <name> Download a completed job's artifact (legacy: <job_id> <file>)
|
|
31
32
|
|
|
32
33
|
Examples:
|
|
33
34
|
run402 jobs submit --file job.json
|
|
@@ -120,6 +121,9 @@ recorded filenames on a given run.
|
|
|
120
121
|
"artifacts get": `run402 jobs artifacts get — Download a completed job's artifact
|
|
121
122
|
|
|
122
123
|
Usage:
|
|
124
|
+
run402 jobs artifacts get <job_id> --file <name> --output <path> [--project <id>]
|
|
125
|
+
|
|
126
|
+
Legacy (still supported):
|
|
123
127
|
run402 jobs artifacts get <job_id> <file> --output <path> [--project <id>]
|
|
124
128
|
|
|
125
129
|
Options:
|
|
@@ -355,24 +359,27 @@ async function artifactsGet(args = []) {
|
|
|
355
359
|
process.exit(0);
|
|
356
360
|
}
|
|
357
361
|
const parsed = normalizeArgv(args);
|
|
358
|
-
const valueFlags = ["--project", "--output", "-o"];
|
|
359
|
-
assertKnownFlags(parsed, ["--project", "--output", "-o", "--help", "-h"], valueFlags);
|
|
362
|
+
const valueFlags = ["--project", "--output", "-o", "--file"];
|
|
363
|
+
assertKnownFlags(parsed, ["--project", "--output", "-o", "--file", "--help", "-h"], valueFlags);
|
|
364
|
+
const fileFlag = flagValue(parsed, "--file");
|
|
365
|
+
const expected = fileFlag ? 1 : 2;
|
|
360
366
|
const positionals = positionalArgs(parsed, valueFlags);
|
|
361
|
-
if (positionals.length <
|
|
367
|
+
if (positionals.length < expected) {
|
|
362
368
|
fail({
|
|
363
369
|
code: "BAD_USAGE",
|
|
364
370
|
message: "Missing job_id and/or artifact filename.",
|
|
365
|
-
hint: "Use `run402 jobs artifacts get <job_id> <
|
|
371
|
+
hint: "Use `run402 jobs artifacts get <job_id> --file <name> --output <path>`.",
|
|
366
372
|
});
|
|
367
373
|
}
|
|
368
|
-
if (positionals.length >
|
|
374
|
+
if (positionals.length > expected) {
|
|
369
375
|
fail({
|
|
370
376
|
code: "BAD_USAGE",
|
|
371
|
-
message: `Unexpected argument: ${positionals[
|
|
372
|
-
hint: "Use `run402 jobs artifacts get <job_id> <
|
|
377
|
+
message: `Unexpected argument: ${positionals[expected]}`,
|
|
378
|
+
hint: "Use `run402 jobs artifacts get <job_id> --file <name> --output <path>`.",
|
|
373
379
|
});
|
|
374
380
|
}
|
|
375
|
-
const
|
|
381
|
+
const jobId = positionals[0];
|
|
382
|
+
const filename = fileFlag ?? positionals[1];
|
|
376
383
|
const output = flagValue(parsed, "--output") ?? flagValue(parsed, "-o");
|
|
377
384
|
if (!output) {
|
|
378
385
|
fail({
|
|
@@ -421,7 +428,7 @@ async function artifacts(args = []) {
|
|
|
421
428
|
await artifactsGet(args.slice(1));
|
|
422
429
|
return;
|
|
423
430
|
}
|
|
424
|
-
|
|
431
|
+
failUnknownSubcommand("jobs artifacts", action);
|
|
425
432
|
}
|
|
426
433
|
|
|
427
434
|
function splitJobIdArg(args = [], valueFlags = []) {
|
|
@@ -484,6 +491,6 @@ export async function run(sub, args = []) {
|
|
|
484
491
|
await purge(args);
|
|
485
492
|
break;
|
|
486
493
|
default:
|
|
487
|
-
|
|
494
|
+
failUnknownSubcommand("jobs", sub);
|
|
488
495
|
}
|
|
489
496
|
}
|
package/lib/message.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { allowanceAuthHeaders } from "./config.mjs";
|
|
2
2
|
import { getSdk } from "./sdk.mjs";
|
|
3
3
|
import { reportSdkError, fail } from "./sdk-errors.mjs";
|
|
4
|
-
import { assertKnownFlags, normalizeArgv } from "./argparse.mjs";
|
|
4
|
+
import { assertKnownFlags, normalizeArgv, failUnknownSubcommand } from "./argparse.mjs";
|
|
5
5
|
|
|
6
6
|
const HELP = `run402 message — Send messages to Run402 developers
|
|
7
7
|
|
|
@@ -84,7 +84,7 @@ export async function run(sub, args) {
|
|
|
84
84
|
process.exit(0);
|
|
85
85
|
}
|
|
86
86
|
if (sub !== "send") {
|
|
87
|
-
|
|
87
|
+
failUnknownSubcommand("message", sub);
|
|
88
88
|
}
|
|
89
89
|
const parsedArgs = normalizeArgv(args);
|
|
90
90
|
assertKnownFlags(parsedArgs, ["--help", "-h"]);
|
package/lib/notifications.mjs
CHANGED
|
@@ -40,6 +40,7 @@ import {
|
|
|
40
40
|
normalizeArgv,
|
|
41
41
|
positionalArgs,
|
|
42
42
|
requirePositionalCount,
|
|
43
|
+
failUnknownSubcommand,
|
|
43
44
|
} from "./argparse.mjs";
|
|
44
45
|
|
|
45
46
|
const HELP = `run402 notifications — Operator health notifications + Telegram channel/rules
|
|
@@ -435,9 +436,8 @@ async function runChannels(args) {
|
|
|
435
436
|
await channelsRevoke(rest);
|
|
436
437
|
return;
|
|
437
438
|
}
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
message: `Unknown 'notifications channels' action: ${channelsAction}. Try connect | list | revoke.`,
|
|
439
|
+
failUnknownSubcommand("notifications channels", channelsAction, {
|
|
440
|
+
hint: "Run `run402 notifications channels --help` for usage.",
|
|
441
441
|
});
|
|
442
442
|
}
|
|
443
443
|
|
|
@@ -539,9 +539,8 @@ async function runRules(args) {
|
|
|
539
539
|
await rulesRm(rest);
|
|
540
540
|
return;
|
|
541
541
|
}
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
message: `Unknown 'notifications rules' action: ${rulesAction}. Try add | list | rm.`,
|
|
542
|
+
failUnknownSubcommand("notifications rules", rulesAction, {
|
|
543
|
+
hint: "Run `run402 notifications rules --help` for usage.",
|
|
545
544
|
});
|
|
546
545
|
}
|
|
547
546
|
|
|
@@ -586,12 +585,7 @@ export async function run(sub, args) {
|
|
|
586
585
|
await test(args);
|
|
587
586
|
return;
|
|
588
587
|
default:
|
|
589
|
-
|
|
590
|
-
code: "UNKNOWN_SUBCOMMAND",
|
|
591
|
-
message: `Unknown notifications subcommand: ${sub}`,
|
|
592
|
-
hint: "Run `run402 notifications --help` for usage.",
|
|
593
|
-
details: { command: "notifications", subcommand: sub },
|
|
594
|
-
});
|
|
588
|
+
failUnknownSubcommand("notifications", sub);
|
|
595
589
|
}
|
|
596
590
|
}
|
|
597
591
|
|
package/lib/operator.mjs
CHANGED
|
@@ -24,7 +24,7 @@ import { randomBytes, createHash } from "node:crypto";
|
|
|
24
24
|
import { fail, reportSdkError } from "./sdk-errors.mjs";
|
|
25
25
|
import { getSdk } from "./sdk.mjs";
|
|
26
26
|
import { claimWalletOrg, isStepUpRequired, isOperatorApprovalRequired } from "#sdk/node";
|
|
27
|
-
import { normalizeArgv, hasHelp, assertKnownFlags, flagValue } from "./argparse.mjs";
|
|
27
|
+
import { normalizeArgv, hasHelp, assertKnownFlags, flagValue, failUnknownSubcommand } from "./argparse.mjs";
|
|
28
28
|
import {
|
|
29
29
|
saveOperatorSession,
|
|
30
30
|
clearOperatorSession,
|
|
@@ -766,11 +766,6 @@ export async function run(sub, args = []) {
|
|
|
766
766
|
await status(args);
|
|
767
767
|
break;
|
|
768
768
|
default:
|
|
769
|
-
|
|
770
|
-
code: "UNKNOWN_SUBCOMMAND",
|
|
771
|
-
message: `Unknown operator subcommand: ${sub}`,
|
|
772
|
-
hint: "Run `run402 operator --help` for usage.",
|
|
773
|
-
details: { command: "operator", subcommand: sub },
|
|
774
|
-
});
|
|
769
|
+
failUnknownSubcommand("operator", sub, { extraSubcommands: ["status"] });
|
|
775
770
|
}
|
|
776
771
|
}
|
package/lib/org.mjs
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
flagValue,
|
|
7
7
|
parseIntegerFlag,
|
|
8
8
|
requirePositionalCount,
|
|
9
|
+
failUnknownSubcommand,
|
|
9
10
|
} from "./argparse.mjs";
|
|
10
11
|
|
|
11
12
|
const ROLE_LIST = "owner | admin | developer | billing | viewer";
|
|
@@ -16,17 +17,20 @@ Usage:
|
|
|
16
17
|
run402 org create [--name <label>]
|
|
17
18
|
run402 org list
|
|
18
19
|
run402 org get <org_id>
|
|
19
|
-
run402 org rename <org_id> <display_name> (or: --clear to remove the label)
|
|
20
|
-
run402 org payout-wallet <org_id> <wallet_address> (or: --clear to remove the explicit default)
|
|
20
|
+
run402 org rename <org_id> --name <display_name> (or: --clear to remove the label)
|
|
21
|
+
run402 org payout-wallet <org_id> --wallet <wallet_address> (or: --clear to remove the explicit default)
|
|
21
22
|
run402 org whoami
|
|
22
23
|
run402 org audit <org_id> [--limit N] [--after <cursor>] [--before <cursor>]
|
|
23
24
|
run402 org member list <org_id>
|
|
24
|
-
run402 org member add <org_id> <wallet_address> [--role <role>]
|
|
25
|
-
run402 org member role <org_id> <principal_id> <role>
|
|
26
|
-
run402 org member rm <org_id> <principal_id>
|
|
25
|
+
run402 org member add <org_id> --wallet <wallet_address> [--role <role>]
|
|
26
|
+
run402 org member role <org_id> --principal <principal_id> --role <role>
|
|
27
|
+
run402 org member rm <org_id> --principal <principal_id>
|
|
27
28
|
run402 org invite list <org_id>
|
|
28
|
-
run402 org invite create <org_id> <email> [--role <role>] [--ttl-hours N]
|
|
29
|
-
run402 org invite rm <org_id> <principal_id>
|
|
29
|
+
run402 org invite create <org_id> --email <email> [--role <role>] [--ttl-hours N]
|
|
30
|
+
run402 org invite rm <org_id> --principal <principal_id>
|
|
31
|
+
|
|
32
|
+
Legacy (still supported): the second attribute may also be passed positionally,
|
|
33
|
+
e.g. run402 org member add <org_id> <wallet_address>.
|
|
30
34
|
|
|
31
35
|
Subcommands:
|
|
32
36
|
create Create an empty org on the prototype tier (you become owner)
|
|
@@ -87,18 +91,24 @@ non-revealing 403.
|
|
|
87
91
|
rename: `run402 org rename — set or clear an org's display label (owner-only)
|
|
88
92
|
|
|
89
93
|
Usage:
|
|
90
|
-
run402 org rename <org_id> <display_name>
|
|
94
|
+
run402 org rename <org_id> --name <display_name>
|
|
91
95
|
run402 org rename <org_id> --clear
|
|
92
96
|
|
|
97
|
+
Legacy (still supported):
|
|
98
|
+
run402 org rename <org_id> <display_name>
|
|
99
|
+
|
|
93
100
|
Owner-only + step-up gated. Pass --clear (or an empty display_name) to remove
|
|
94
101
|
the label. Output includes the updated tier and lease timestamps.
|
|
95
102
|
`,
|
|
96
103
|
"payout-wallet": `run402 org payout-wallet — set or clear the tenant route payout wallet
|
|
97
104
|
|
|
98
105
|
Usage:
|
|
99
|
-
run402 org payout-wallet <org_id> <wallet_address>
|
|
106
|
+
run402 org payout-wallet <org_id> --wallet <wallet_address>
|
|
100
107
|
run402 org payout-wallet <org_id> --clear
|
|
101
108
|
|
|
109
|
+
Legacy (still supported):
|
|
110
|
+
run402 org payout-wallet <org_id> <wallet_address>
|
|
111
|
+
|
|
102
112
|
Admin/owner-only + step-up gated. The wallet must already be active and linked
|
|
103
113
|
to the same org. This wallet receives x402 settlement for function web routes
|
|
104
114
|
that declare pricing.pay_to = "org_default_payout". Pass --clear to remove the
|
|
@@ -120,9 +130,9 @@ for local wallet/profile state use 'run402 status'.
|
|
|
120
130
|
|
|
121
131
|
Usage:
|
|
122
132
|
run402 org member list <org_id>
|
|
123
|
-
run402 org member add <org_id> <wallet_address> [--role <role>]
|
|
124
|
-
run402 org member role <org_id> <principal_id> <role>
|
|
125
|
-
run402 org member rm <org_id> <principal_id>
|
|
133
|
+
run402 org member add <org_id> --wallet <wallet_address> [--role <role>]
|
|
134
|
+
run402 org member role <org_id> --principal <principal_id> --role <role>
|
|
135
|
+
run402 org member rm <org_id> --principal <principal_id>
|
|
126
136
|
|
|
127
137
|
Roles: ${ROLE_LIST} (add defaults to developer). Mutations require an active owner.
|
|
128
138
|
Demoting/removing the org's only active owner fails with 409 LAST_OWNER.
|
|
@@ -131,8 +141,11 @@ Demoting/removing the org's only active owner fails with 409 LAST_OWNER.
|
|
|
131
141
|
|
|
132
142
|
Usage:
|
|
133
143
|
run402 org invite list <org_id>
|
|
134
|
-
run402 org invite create <org_id> <email> [--role <role>] [--ttl-hours N]
|
|
135
|
-
run402 org invite rm <org_id> <principal_id>
|
|
144
|
+
run402 org invite create <org_id> --email <email> [--role <role>] [--ttl-hours N]
|
|
145
|
+
run402 org invite rm <org_id> --principal <principal_id>
|
|
146
|
+
|
|
147
|
+
Legacy (still supported): the second attribute may also be passed positionally,
|
|
148
|
+
e.g. run402 org member add <org_id> <wallet_address>.
|
|
136
149
|
|
|
137
150
|
An invite is claimed at the recipient's first login. Mutations require an active owner
|
|
138
151
|
(plus step-up when driven by a control-plane session).
|
|
@@ -200,16 +213,18 @@ async function get(args) {
|
|
|
200
213
|
|
|
201
214
|
async function rename(args) {
|
|
202
215
|
const a = normalizeArgv(args);
|
|
203
|
-
assertKnownFlags(a, ["--clear", "--help", "-h"]);
|
|
216
|
+
assertKnownFlags(a, ["--name", "--clear", "--help", "-h"], ["--name"]);
|
|
204
217
|
const clear = a.includes("--clear");
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
218
|
+
const nameFlag = flagValue(a, "--name");
|
|
219
|
+
const single = clear || nameFlag !== null;
|
|
220
|
+
const positionals = requirePositionalCount(a, ["--name"], {
|
|
221
|
+
min: single ? 1 : 2,
|
|
222
|
+
max: single ? 1 : 2,
|
|
223
|
+
command: "run402 org rename <org_id> --name <display_name>",
|
|
224
|
+
missing: single ? "Missing <org_id>." : "Missing <org_id> and/or <display_name> (use --name, or pass --clear).",
|
|
210
225
|
});
|
|
211
226
|
const org = positionals[0];
|
|
212
|
-
const displayName = clear ? null : positionals[1];
|
|
227
|
+
const displayName = clear ? null : (nameFlag ?? positionals[1]);
|
|
213
228
|
try {
|
|
214
229
|
console.log(JSON.stringify(await getSdk().org(org).rename(displayName), null, 2));
|
|
215
230
|
} catch (err) {
|
|
@@ -219,16 +234,18 @@ async function rename(args) {
|
|
|
219
234
|
|
|
220
235
|
async function payoutWallet(args) {
|
|
221
236
|
const a = normalizeArgv(args);
|
|
222
|
-
assertKnownFlags(a, ["--clear", "--help", "-h"]);
|
|
237
|
+
assertKnownFlags(a, ["--wallet", "--clear", "--help", "-h"], ["--wallet"]);
|
|
223
238
|
const clear = a.includes("--clear");
|
|
224
|
-
const
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
239
|
+
const walletFlag = flagValue(a, "--wallet");
|
|
240
|
+
const single = clear || walletFlag !== null;
|
|
241
|
+
const positionals = requirePositionalCount(a, ["--wallet"], {
|
|
242
|
+
min: single ? 1 : 2,
|
|
243
|
+
max: single ? 1 : 2,
|
|
244
|
+
command: "run402 org payout-wallet <org_id> --wallet <wallet_address>",
|
|
245
|
+
missing: single ? "Missing <org_id>." : "Missing <org_id> and/or <wallet_address> (use --wallet, or pass --clear).",
|
|
229
246
|
});
|
|
230
247
|
const org = positionals[0];
|
|
231
|
-
const walletAddress = clear ? null : positionals[1];
|
|
248
|
+
const walletAddress = clear ? null : (walletFlag ?? positionals[1]);
|
|
232
249
|
try {
|
|
233
250
|
console.log(JSON.stringify(await getSdk().org(org).setPayoutWallet({ walletAddress }), null, 2));
|
|
234
251
|
} catch (err) {
|
|
@@ -292,12 +309,16 @@ async function runMember(args) {
|
|
|
292
309
|
|
|
293
310
|
if (memberAction === "add") {
|
|
294
311
|
const a = normalizeArgv(rest);
|
|
295
|
-
assertKnownFlags(a, ["--role", "--help", "-h"], ["--role"]);
|
|
312
|
+
assertKnownFlags(a, ["--role", "--wallet", "--help", "-h"], ["--role", "--wallet"]);
|
|
296
313
|
const role = flagValue(a, "--role");
|
|
297
|
-
const
|
|
298
|
-
|
|
299
|
-
|
|
314
|
+
const walletFlag = flagValue(a, "--wallet");
|
|
315
|
+
const count = walletFlag ? 1 : 2;
|
|
316
|
+
const pos = requirePositionalCount(a, ["--role", "--wallet"], {
|
|
317
|
+
min: count, max: count, command: "run402 org member add <org_id> --wallet <wallet_address> [--role <role>]",
|
|
318
|
+
missing: walletFlag ? "Missing <org_id>." : "Missing <org_id> and/or <wallet_address> (use --wallet).",
|
|
300
319
|
});
|
|
320
|
+
const org = pos[0];
|
|
321
|
+
const wallet = walletFlag ?? pos[1];
|
|
301
322
|
try {
|
|
302
323
|
const res = await getSdk().org(org).members.add({ wallet, role: role || undefined });
|
|
303
324
|
console.log(JSON.stringify(res, null, 2));
|
|
@@ -309,11 +330,17 @@ async function runMember(args) {
|
|
|
309
330
|
|
|
310
331
|
if (memberAction === "role") {
|
|
311
332
|
const a = normalizeArgv(rest);
|
|
312
|
-
assertKnownFlags(a, ["--help", "-h"]);
|
|
313
|
-
const
|
|
314
|
-
|
|
315
|
-
|
|
333
|
+
assertKnownFlags(a, ["--principal", "--role", "--help", "-h"], ["--principal", "--role"]);
|
|
334
|
+
const principalFlag = flagValue(a, "--principal");
|
|
335
|
+
const roleFlag = flagValue(a, "--role");
|
|
336
|
+
const count = 3 - (principalFlag ? 1 : 0) - (roleFlag ? 1 : 0);
|
|
337
|
+
const pos = requirePositionalCount(a, ["--principal", "--role"], {
|
|
338
|
+
min: count, max: count, command: "run402 org member role <org_id> --principal <principal_id> --role <role>",
|
|
339
|
+
missing: "Missing <org_id>, <principal_id> (--principal), and/or <role> (--role).",
|
|
316
340
|
});
|
|
341
|
+
const org = pos[0];
|
|
342
|
+
const principalId = principalFlag ?? pos[1];
|
|
343
|
+
const role = roleFlag ?? (principalFlag ? pos[1] : pos[2]);
|
|
317
344
|
try {
|
|
318
345
|
console.log(JSON.stringify(await getSdk().org(org).members.setRole(principalId, { role }), null, 2));
|
|
319
346
|
} catch (err) {
|
|
@@ -324,11 +351,15 @@ async function runMember(args) {
|
|
|
324
351
|
|
|
325
352
|
if (memberAction === "rm") {
|
|
326
353
|
const a = normalizeArgv(rest);
|
|
327
|
-
assertKnownFlags(a, ["--help", "-h"]);
|
|
328
|
-
const
|
|
329
|
-
|
|
330
|
-
|
|
354
|
+
assertKnownFlags(a, ["--principal", "--help", "-h"], ["--principal"]);
|
|
355
|
+
const principalFlag = flagValue(a, "--principal");
|
|
356
|
+
const count = principalFlag ? 1 : 2;
|
|
357
|
+
const pos = requirePositionalCount(a, ["--principal"], {
|
|
358
|
+
min: count, max: count, command: "run402 org member rm <org_id> --principal <principal_id>",
|
|
359
|
+
missing: principalFlag ? "Missing <org_id>." : "Missing <org_id> and/or <principal_id> (use --principal).",
|
|
331
360
|
});
|
|
361
|
+
const org = pos[0];
|
|
362
|
+
const principalId = principalFlag ?? pos[1];
|
|
332
363
|
try {
|
|
333
364
|
console.log(JSON.stringify(await getSdk().org(org).members.revoke(principalId), null, 2));
|
|
334
365
|
} catch (err) {
|
|
@@ -370,14 +401,18 @@ async function runInvite(args) {
|
|
|
370
401
|
|
|
371
402
|
if (inviteAction === "create") {
|
|
372
403
|
const a = normalizeArgv(rest);
|
|
373
|
-
const valueFlags = ["--role", "--ttl-hours"];
|
|
404
|
+
const valueFlags = ["--role", "--ttl-hours", "--email"];
|
|
374
405
|
assertKnownFlags(a, [...valueFlags, "--help", "-h"], valueFlags);
|
|
375
406
|
const role = flagValue(a, "--role");
|
|
376
407
|
const ttlFlag = flagValue(a, "--ttl-hours");
|
|
377
|
-
const
|
|
378
|
-
|
|
379
|
-
|
|
408
|
+
const emailFlag = flagValue(a, "--email");
|
|
409
|
+
const count = emailFlag ? 1 : 2;
|
|
410
|
+
const pos = requirePositionalCount(a, valueFlags, {
|
|
411
|
+
min: count, max: count, command: "run402 org invite create <org_id> --email <email> [--role <role>]",
|
|
412
|
+
missing: emailFlag ? "Missing <org_id>." : "Missing <org_id> and/or <email> (use --email).",
|
|
380
413
|
});
|
|
414
|
+
const org = pos[0];
|
|
415
|
+
const email = emailFlag ?? pos[1];
|
|
381
416
|
const inviteTtlHours = ttlFlag === null ? undefined : parseIntegerFlag("--ttl-hours", ttlFlag, { min: 1, max: 8760 });
|
|
382
417
|
try {
|
|
383
418
|
const res = await getSdk().org(org).invites.create({ email, role: role || "developer", inviteTtlHours });
|
|
@@ -390,11 +425,15 @@ async function runInvite(args) {
|
|
|
390
425
|
|
|
391
426
|
if (inviteAction === "rm") {
|
|
392
427
|
const a = normalizeArgv(rest);
|
|
393
|
-
assertKnownFlags(a, ["--help", "-h"]);
|
|
394
|
-
const
|
|
395
|
-
|
|
396
|
-
|
|
428
|
+
assertKnownFlags(a, ["--principal", "--help", "-h"], ["--principal"]);
|
|
429
|
+
const principalFlag = flagValue(a, "--principal");
|
|
430
|
+
const count = principalFlag ? 1 : 2;
|
|
431
|
+
const pos = requirePositionalCount(a, ["--principal"], {
|
|
432
|
+
min: count, max: count, command: "run402 org invite rm <org_id> --principal <principal_id>",
|
|
433
|
+
missing: principalFlag ? "Missing <org_id>." : "Missing <org_id> and/or <principal_id> (use --principal).",
|
|
397
434
|
});
|
|
435
|
+
const org = pos[0];
|
|
436
|
+
const principalId = principalFlag ?? pos[1];
|
|
398
437
|
try {
|
|
399
438
|
console.log(JSON.stringify(await getSdk().org(org).invites.revoke(principalId), null, 2));
|
|
400
439
|
} catch (err) {
|
|
@@ -434,6 +473,6 @@ export async function run(sub, args) {
|
|
|
434
473
|
case "whoami": await whoami(args); break;
|
|
435
474
|
case "audit": await audit(args); break;
|
|
436
475
|
default:
|
|
437
|
-
|
|
476
|
+
failUnknownSubcommand("org", sub);
|
|
438
477
|
}
|
|
439
478
|
}
|
package/lib/projects.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import { loadLiveControlPlaneSession } from "../core-dist/control-plane-session.
|
|
|
5
5
|
import { withAutoApprove } from "./operator.mjs";
|
|
6
6
|
import { getSdk } from "./sdk.mjs";
|
|
7
7
|
import { reportSdkError, fail, parseFlagJson } from "./sdk-errors.mjs";
|
|
8
|
-
import { assertKnownFlags, failBadProjectId, flagValue, hasHelp, normalizeArgv, positionalArgs,
|
|
8
|
+
import { assertKnownFlags, failBadProjectId, flagValue, hasHelp, normalizeArgv, positionalArgs, resolveProjectSelector, validateRegularFile, failUnknownSubcommand } from "./argparse.mjs";
|
|
9
9
|
|
|
10
10
|
const HELP = `run402 projects — Manage your deployed Run402 projects
|
|
11
11
|
|
|
@@ -21,8 +21,8 @@ Subcommands:
|
|
|
21
21
|
tenant-payments [project_id] [--status <s>] List redacted tenant x402 payments for priced routes
|
|
22
22
|
get [id] Authoritative server read: status, org, tier, active deploy, mailbox, usage vs limits (live; no keys)
|
|
23
23
|
current Show the active project pointer and validation status
|
|
24
|
-
sql
|
|
25
|
-
rest
|
|
24
|
+
sql "<query>" [--project <id>] [--file <path>] [--params '<json>'] Run a SQL query (supports parameterized queries)
|
|
25
|
+
rest <table> [--query "<params>"] [--project <id>] Query a table via the REST API (PostgREST)
|
|
26
26
|
usage [id] Show compute/storage usage for a project
|
|
27
27
|
costs [id] [--window <w>] Show admin-only per-project revenue/cost/margin
|
|
28
28
|
schema [id] Inspect the database schema
|
|
@@ -210,23 +210,25 @@ Examples:
|
|
|
210
210
|
sql: `run402 projects sql — Run a SQL query against a project's database
|
|
211
211
|
|
|
212
212
|
Usage:
|
|
213
|
-
run402 projects sql
|
|
214
|
-
run402 projects sql
|
|
213
|
+
run402 projects sql "<query>" [--project <id>] [options]
|
|
214
|
+
run402 projects sql --file <path> [--project <id>] [options]
|
|
215
|
+
|
|
216
|
+
Legacy (still supported):
|
|
217
|
+
run402 projects sql <prj_id> "<query>" [options]
|
|
215
218
|
|
|
216
219
|
Arguments:
|
|
217
|
-
[id] Project ID (defaults to the active project if omitted;
|
|
218
|
-
must start with 'prj_' — any other first arg is treated
|
|
219
|
-
as the query instead)
|
|
220
220
|
<query> Inline SQL query (quote it to preserve spaces)
|
|
221
221
|
|
|
222
222
|
Options:
|
|
223
|
+
--project <id> Project ID (defaults to the active project; a leading
|
|
224
|
+
prj_... positional is also still accepted)
|
|
223
225
|
--file <path> Read SQL from a file instead of an inline query
|
|
224
226
|
--params '<json>' JSON array of parameters for a parameterized query
|
|
225
227
|
|
|
226
228
|
Examples:
|
|
227
|
-
run402 projects sql
|
|
228
|
-
run402 projects sql
|
|
229
|
-
run402 projects sql
|
|
229
|
+
run402 projects sql "SELECT * FROM users LIMIT 5" --project prj_abc123
|
|
230
|
+
run402 projects sql "SELECT * FROM users WHERE id = $1" --params '[42]'
|
|
231
|
+
run402 projects sql --file setup.sql --project prj_abc123
|
|
230
232
|
`,
|
|
231
233
|
costs: `run402 projects costs — Show admin-only per-project finance
|
|
232
234
|
|
|
@@ -411,6 +413,12 @@ async function applyExpose(projectId, args = []) {
|
|
|
411
413
|
|
|
412
414
|
async function validateExpose(args = []) {
|
|
413
415
|
let projectId = null;
|
|
416
|
+
let projectFlag = null;
|
|
417
|
+
if (args.includes("--project")) {
|
|
418
|
+
projectFlag = flagValue(args, "--project");
|
|
419
|
+
const idx = args.indexOf("--project");
|
|
420
|
+
args = [...args.slice(0, idx), ...args.slice(idx + 2)];
|
|
421
|
+
}
|
|
414
422
|
let file = null;
|
|
415
423
|
let inline = null;
|
|
416
424
|
let migrationFile = null;
|
|
@@ -473,8 +481,15 @@ async function validateExpose(args = []) {
|
|
|
473
481
|
});
|
|
474
482
|
}
|
|
475
483
|
|
|
484
|
+
if (projectFlag !== null && projectId !== null && projectFlag !== projectId) {
|
|
485
|
+
fail({
|
|
486
|
+
code: "BAD_USAGE",
|
|
487
|
+
message: `Conflicting project ids: --project ${projectFlag} vs positional ${projectId}`,
|
|
488
|
+
details: { project_flag: projectFlag, positional: projectId },
|
|
489
|
+
});
|
|
490
|
+
}
|
|
476
491
|
const activeProjectId = getActiveProjectId();
|
|
477
|
-
const project = projectId || activeProjectId || undefined;
|
|
492
|
+
const project = projectFlag || projectId || activeProjectId || undefined;
|
|
478
493
|
if (!project) allowanceAuthHeaders("/projects/v1/expose/validate");
|
|
479
494
|
const migration = migrationFile ? readFileSync(migrationFile, "utf-8") : migrationSql;
|
|
480
495
|
|
|
@@ -697,6 +712,10 @@ function toCliExposeValidationResult(data) {
|
|
|
697
712
|
return { has_errors: hasErrors, ...rest };
|
|
698
713
|
}
|
|
699
714
|
|
|
715
|
+
// The SDK now returns the gateway SQL envelope verbatim (snake_case
|
|
716
|
+
// row_count) — the wire shape is uniform end-to-end. This shim survives one
|
|
717
|
+
// release as belt-and-braces against a stale local SDK build that still
|
|
718
|
+
// camelCases, then can be deleted.
|
|
700
719
|
function toCliSqlResult(data) {
|
|
701
720
|
if (!data || typeof data !== "object" || Array.isArray(data)) return data;
|
|
702
721
|
if ("row_count" in data) return data;
|
|
@@ -705,12 +724,15 @@ function toCliSqlResult(data) {
|
|
|
705
724
|
return { ...rest, row_count: rowCount };
|
|
706
725
|
}
|
|
707
726
|
|
|
708
|
-
async function rest(projectId,
|
|
727
|
+
async function rest(projectId, restArgs = []) {
|
|
728
|
+
const positionals = positionalArgs(restArgs, FLAGS_BY_SUB.rest.values);
|
|
729
|
+
const table = positionals[0];
|
|
730
|
+
const queryParams = flagValue(restArgs, "--query") ?? positionals[1];
|
|
709
731
|
if (!table) {
|
|
710
732
|
fail({
|
|
711
733
|
code: "BAD_USAGE",
|
|
712
|
-
message: "Missing <table> argument. Usage: run402 projects rest
|
|
713
|
-
hint: "Run 'run402 projects schema
|
|
734
|
+
message: "Missing <table> argument. Usage: run402 projects rest <table> [--query \"<query>\"] [--project <id>]",
|
|
735
|
+
hint: "Run 'run402 projects schema' to list tables.",
|
|
714
736
|
});
|
|
715
737
|
}
|
|
716
738
|
try {
|
|
@@ -841,19 +863,26 @@ const FLAGS_BY_SUB = {
|
|
|
841
863
|
values: ["--tier", "--name", "--org", "--idempotency-key"],
|
|
842
864
|
},
|
|
843
865
|
list: { known: ["--org", "--all"], values: ["--org"] },
|
|
844
|
-
rename: { known: ["--name"], values: ["--name"] },
|
|
845
|
-
"tenant-payments": { known: ["--status", "--limit", "--after"], values: ["--status", "--limit", "--after"] },
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
866
|
+
rename: { known: ["--project", "--name"], values: ["--project", "--name"] },
|
|
867
|
+
"tenant-payments": { known: ["--project", "--status", "--limit", "--after"], values: ["--project", "--status", "--limit", "--after"] },
|
|
868
|
+
get: { known: ["--project"], values: ["--project"] },
|
|
869
|
+
rest: { known: ["--project", "--query"], values: ["--project", "--query"] },
|
|
870
|
+
usage: { known: ["--project"], values: ["--project"] },
|
|
871
|
+
schema: { known: ["--project"], values: ["--project"] },
|
|
872
|
+
"get-expose": { known: ["--project"], values: ["--project"] },
|
|
873
|
+
"promote-user": { known: ["--project"], values: ["--project"] },
|
|
874
|
+
"demote-user": { known: ["--project"], values: ["--project"] },
|
|
875
|
+
sql: { known: ["--project", "--file", "--params"], values: ["--project", "--file", "--params"] },
|
|
876
|
+
costs: { known: ["--project", "--window"], values: ["--project", "--window"] },
|
|
877
|
+
"apply-expose": { known: ["--project", "--file"], values: ["--project", "--file"] },
|
|
849
878
|
"validate-expose": {
|
|
850
|
-
known: ["--file", "--migration-file", "--migration-sql"],
|
|
851
|
-
values: ["--file", "--migration-file", "--migration-sql"],
|
|
879
|
+
known: ["--project", "--file", "--migration-file", "--migration-sql"],
|
|
880
|
+
values: ["--project", "--file", "--migration-file", "--migration-sql"],
|
|
852
881
|
},
|
|
853
|
-
delete: { known: ["--confirm"], values: [] },
|
|
882
|
+
delete: { known: ["--project", "--confirm"], values: ["--project"] },
|
|
854
883
|
export: {
|
|
855
|
-
known: ["--scope", "--auth", "--consistency", "--idempotency-key", "--output", "--poll-interval", "--timeout", "--wait", "--json", "--json-stream"],
|
|
856
|
-
values: ["--scope", "--auth", "--consistency", "--idempotency-key", "--output", "--poll-interval", "--timeout"],
|
|
884
|
+
known: ["--project", "--scope", "--auth", "--consistency", "--idempotency-key", "--output", "--poll-interval", "--timeout", "--wait", "--json", "--json-stream"],
|
|
885
|
+
values: ["--project", "--scope", "--auth", "--consistency", "--idempotency-key", "--output", "--poll-interval", "--timeout"],
|
|
857
886
|
},
|
|
858
887
|
};
|
|
859
888
|
|
|
@@ -888,28 +917,28 @@ export async function run(sub, args) {
|
|
|
888
917
|
case "use": await use(args[0]); break;
|
|
889
918
|
case "list": await list(args); break;
|
|
890
919
|
case "current": await current(); break;
|
|
891
|
-
case "rename": { const { projectId, rest } =
|
|
892
|
-
case "tenant-payments": { const { projectId, rest } =
|
|
893
|
-
case "get": { const { projectId } =
|
|
920
|
+
case "rename": { const { projectId, rest } = resolveProjectSelector(args, { rejectBareFirst: true, valueFlags: FLAGS_BY_SUB.rename.values }); await rename(projectId, rest); break; }
|
|
921
|
+
case "tenant-payments": { const { projectId, rest } = resolveProjectSelector(args, { rejectBareFirst: true, valueFlags: FLAGS_BY_SUB["tenant-payments"].values }); await tenantPayments(projectId, rest); break; }
|
|
922
|
+
case "get": { const { projectId } = resolveProjectSelector(args, { rejectBareFirst: true }); await get(projectId); break; }
|
|
894
923
|
case "info": commandMoved("info"); break;
|
|
895
924
|
case "keys": commandMoved("keys"); break;
|
|
896
|
-
case "sql": { const { projectId, rest } =
|
|
897
|
-
case "rest": { const { projectId, rest: restArgs } =
|
|
898
|
-
case "usage": { const { projectId } =
|
|
899
|
-
case "costs": { const { projectId, rest } =
|
|
900
|
-
case "schema": { const { projectId } =
|
|
901
|
-
case "apply-expose": { const { projectId, rest } =
|
|
925
|
+
case "sql": { const { projectId, rest } = resolveProjectSelector(args, { maxBarePositionals: 1, valueFlags: FLAGS_BY_SUB.sql.values, rejectBareFirstWhenFlagPresent: ["--file"] }); await sqlCmd(projectId, rest); break; }
|
|
926
|
+
case "rest": { const { projectId, rest: restArgs } = resolveProjectSelector(args, { valueFlags: FLAGS_BY_SUB.rest.values }); await rest(projectId, restArgs); break; }
|
|
927
|
+
case "usage": { const { projectId } = resolveProjectSelector(args, { rejectBareFirst: true }); await usage(projectId); break; }
|
|
928
|
+
case "costs": { const { projectId, rest } = resolveProjectSelector(args, { rejectBareFirst: true, valueFlags: FLAGS_BY_SUB.costs.values }); await costs(projectId, rest); break; }
|
|
929
|
+
case "schema": { const { projectId } = resolveProjectSelector(args, { rejectBareFirst: true }); await schema(projectId); break; }
|
|
930
|
+
case "apply-expose": { const { projectId, rest } = resolveProjectSelector(args, { maxBarePositionals: 1, valueFlags: FLAGS_BY_SUB["apply-expose"].values, rejectBareFirstWhenFlagPresent: ["--file"] }); await applyExpose(projectId, rest); break; }
|
|
902
931
|
case "validate-expose": await validateExpose(args); break;
|
|
903
|
-
case "get-expose": { const { projectId } =
|
|
904
|
-
case "delete": { const { projectId, rest } =
|
|
932
|
+
case "get-expose": { const { projectId } = resolveProjectSelector(args, { rejectBareFirst: true }); await getExpose(projectId); break; }
|
|
933
|
+
case "delete": { const { projectId, rest } = resolveProjectSelector(args, { rejectBareFirst: true }); await deleteProject(projectId, rest); break; }
|
|
905
934
|
case "export": {
|
|
906
935
|
const { run } = await import("./cloud.mjs");
|
|
907
936
|
await run("archives", ["create", ...args]);
|
|
908
937
|
break;
|
|
909
938
|
}
|
|
910
|
-
case "promote-user": { const { projectId, rest } =
|
|
911
|
-
case "demote-user": { const { projectId, rest } =
|
|
939
|
+
case "promote-user": { const { projectId, rest } = resolveProjectSelector(args); await promoteUser(projectId, rest[0]); break; }
|
|
940
|
+
case "demote-user": { const { projectId, rest } = resolveProjectSelector(args); await demoteUser(projectId, rest[0]); break; }
|
|
912
941
|
default:
|
|
913
|
-
|
|
942
|
+
failUnknownSubcommand("projects", sub);
|
|
914
943
|
}
|
|
915
944
|
}
|