run402 1.69.4 → 1.69.6
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/agent.mjs +37 -11
- package/lib/ai.mjs +16 -15
- package/lib/allowance.mjs +23 -7
- package/lib/apps.mjs +92 -40
- package/lib/argparse.mjs +60 -1
- package/lib/auth.mjs +62 -1
- package/lib/billing.mjs +83 -25
- package/lib/blob.mjs +2 -2
- package/lib/cdn.mjs +21 -8
- package/lib/contracts.mjs +123 -33
- package/lib/domains.mjs +22 -11
- package/lib/email.mjs +68 -61
- package/lib/image.mjs +17 -8
- package/lib/message.mjs +4 -1
- package/lib/secrets.mjs +29 -12
- package/lib/sender-domain.mjs +32 -14
- package/lib/sites.mjs +39 -16
- package/lib/subdomains.mjs +31 -35
- package/lib/tier.mjs +26 -4
- package/lib/webhooks.mjs +46 -33
- package/package.json +1 -1
- package/sdk/dist/errors.d.ts +4 -1
- package/sdk/dist/errors.d.ts.map +1 -1
- package/sdk/dist/errors.js +16 -2
- package/sdk/dist/errors.js.map +1 -1
- package/sdk/dist/namespaces/ai.d.ts.map +1 -1
- package/sdk/dist/namespaces/ai.js +7 -2
- package/sdk/dist/namespaces/ai.js.map +1 -1
- package/sdk/dist/namespaces/billing.d.ts.map +1 -1
- package/sdk/dist/namespaces/billing.js +20 -17
- package/sdk/dist/namespaces/billing.js.map +1 -1
- package/sdk/dist/namespaces/contracts.d.ts.map +1 -1
- package/sdk/dist/namespaces/contracts.js +21 -4
- package/sdk/dist/namespaces/contracts.js.map +1 -1
- package/sdk/dist/namespaces/deploy.js +9 -0
- package/sdk/dist/namespaces/deploy.js.map +1 -1
- package/sdk/dist/namespaces/functions.d.ts.map +1 -1
- package/sdk/dist/namespaces/functions.js +20 -0
- package/sdk/dist/namespaces/functions.js.map +1 -1
- package/sdk/dist/retry.d.ts +2 -1
- package/sdk/dist/retry.d.ts.map +1 -1
- package/sdk/dist/retry.js +2 -1
- package/sdk/dist/retry.js.map +1 -1
- package/sdk/dist/validation.d.ts +3 -0
- package/sdk/dist/validation.d.ts.map +1 -1
- package/sdk/dist/validation.js +15 -0
- package/sdk/dist/validation.js.map +1 -1
package/lib/agent.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 { validateWebhookUrl } from "./argparse.mjs";
|
|
4
|
+
import { assertKnownFlags, flagValue, normalizeArgv, positionalArgs, validateWebhookUrl } from "./argparse.mjs";
|
|
5
5
|
|
|
6
6
|
const HELP = `run402 agent — Manage agent identity
|
|
7
7
|
|
|
@@ -76,12 +76,20 @@ contact email. Requires assurance_level=email_verified first.
|
|
|
76
76
|
};
|
|
77
77
|
|
|
78
78
|
async function contact(args) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
79
|
+
const parsedArgs = normalizeArgv(args);
|
|
80
|
+
const valueFlags = ["--name", "--email", "--webhook"];
|
|
81
|
+
assertKnownFlags(parsedArgs, [...valueFlags, "--help", "-h"], valueFlags);
|
|
82
|
+
const extra = positionalArgs(parsedArgs, valueFlags);
|
|
83
|
+
if (extra.length > 0) {
|
|
84
|
+
fail({
|
|
85
|
+
code: "BAD_USAGE",
|
|
86
|
+
message: `Unexpected argument for agent contact: ${extra[0]}`,
|
|
87
|
+
hint: "Use `run402 agent contact --name <name> [--email <email>] [--webhook <url>]`.",
|
|
88
|
+
});
|
|
84
89
|
}
|
|
90
|
+
const name = flagValue(parsedArgs, "--name");
|
|
91
|
+
const email = flagValue(parsedArgs, "--email");
|
|
92
|
+
const webhook = flagValue(parsedArgs, "--webhook");
|
|
85
93
|
if (!name) {
|
|
86
94
|
fail({ code: "BAD_USAGE", message: "Missing --name <name>" });
|
|
87
95
|
}
|
|
@@ -104,7 +112,13 @@ async function contact(args) {
|
|
|
104
112
|
}
|
|
105
113
|
}
|
|
106
114
|
|
|
107
|
-
async function status() {
|
|
115
|
+
async function status(args = []) {
|
|
116
|
+
const parsedArgs = normalizeArgv(args);
|
|
117
|
+
assertKnownFlags(parsedArgs, ["--help", "-h"]);
|
|
118
|
+
const extra = positionalArgs(parsedArgs);
|
|
119
|
+
if (extra.length > 0) {
|
|
120
|
+
fail({ code: "BAD_USAGE", message: `Unexpected argument for agent status: ${extra[0]}` });
|
|
121
|
+
}
|
|
108
122
|
allowanceAuthHeaders("/agent/v1/contact/status");
|
|
109
123
|
|
|
110
124
|
try {
|
|
@@ -115,7 +129,13 @@ async function status() {
|
|
|
115
129
|
}
|
|
116
130
|
}
|
|
117
131
|
|
|
118
|
-
async function verifyEmail() {
|
|
132
|
+
async function verifyEmail(args = []) {
|
|
133
|
+
const parsedArgs = normalizeArgv(args);
|
|
134
|
+
assertKnownFlags(parsedArgs, ["--help", "-h"]);
|
|
135
|
+
const extra = positionalArgs(parsedArgs);
|
|
136
|
+
if (extra.length > 0) {
|
|
137
|
+
fail({ code: "BAD_USAGE", message: `Unexpected argument for agent verify-email: ${extra[0]}` });
|
|
138
|
+
}
|
|
119
139
|
allowanceAuthHeaders("/agent/v1/contact/verify-email");
|
|
120
140
|
|
|
121
141
|
try {
|
|
@@ -127,7 +147,13 @@ async function verifyEmail() {
|
|
|
127
147
|
}
|
|
128
148
|
|
|
129
149
|
async function passkey(args) {
|
|
130
|
-
const
|
|
150
|
+
const parsedArgs = normalizeArgv(args);
|
|
151
|
+
assertKnownFlags(parsedArgs, ["--help", "-h"]);
|
|
152
|
+
const positionals = positionalArgs(parsedArgs);
|
|
153
|
+
const action = positionals[0];
|
|
154
|
+
if (positionals.length > 1) {
|
|
155
|
+
fail({ code: "BAD_USAGE", message: `Unexpected argument for agent passkey: ${positionals[1]}` });
|
|
156
|
+
}
|
|
131
157
|
if (action !== "enroll") {
|
|
132
158
|
fail({ code: "BAD_USAGE", message: "Usage: run402 agent passkey enroll" });
|
|
133
159
|
}
|
|
@@ -152,10 +178,10 @@ export async function run(sub, args) {
|
|
|
152
178
|
await contact(args);
|
|
153
179
|
return;
|
|
154
180
|
case "status":
|
|
155
|
-
await status();
|
|
181
|
+
await status(args);
|
|
156
182
|
return;
|
|
157
183
|
case "verify-email":
|
|
158
|
-
await verifyEmail();
|
|
184
|
+
await verifyEmail(args);
|
|
159
185
|
return;
|
|
160
186
|
case "passkey":
|
|
161
187
|
await passkey(args);
|
package/lib/ai.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 { resolvePositionalProject } from "./argparse.mjs";
|
|
4
|
+
import { assertKnownFlags, flagValue, normalizeArgv, resolvePositionalProject } from "./argparse.mjs";
|
|
5
5
|
|
|
6
6
|
const HELP = `run402 ai — AI translation and moderation tools
|
|
7
7
|
|
|
@@ -103,20 +103,19 @@ Examples:
|
|
|
103
103
|
`,
|
|
104
104
|
};
|
|
105
105
|
|
|
106
|
-
function parseFlag(args, flag) {
|
|
107
|
-
for (let i = 0; i < args.length; i++) {
|
|
108
|
-
if (args[i] === flag && args[i + 1]) return args[i + 1];
|
|
109
|
-
}
|
|
110
|
-
return null;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
106
|
// translate has value-bearing flags (--to, --from, --context, --project) that
|
|
114
107
|
// must not be mistaken for positional bare args when prefix-matching.
|
|
115
108
|
const TRANSLATE_VALUE_FLAGS = ["--to", "--from", "--context", "--project"];
|
|
116
109
|
|
|
117
110
|
async function translate(args) {
|
|
111
|
+
args = normalizeArgv(args);
|
|
112
|
+
assertKnownFlags(args, TRANSLATE_VALUE_FLAGS, TRANSLATE_VALUE_FLAGS);
|
|
113
|
+
|
|
118
114
|
// --project <id> wins over positional, mirroring previous behavior.
|
|
119
|
-
const projectOpt =
|
|
115
|
+
const projectOpt = flagValue(args, "--project");
|
|
116
|
+
const to = flagValue(args, "--to");
|
|
117
|
+
const from = flagValue(args, "--from");
|
|
118
|
+
const context = flagValue(args, "--context");
|
|
120
119
|
let projectId;
|
|
121
120
|
let rest;
|
|
122
121
|
if (projectOpt) {
|
|
@@ -139,10 +138,6 @@ async function translate(args) {
|
|
|
139
138
|
break;
|
|
140
139
|
}
|
|
141
140
|
|
|
142
|
-
const to = parseFlag(args, "--to");
|
|
143
|
-
const from = parseFlag(args, "--from");
|
|
144
|
-
const context = parseFlag(args, "--context");
|
|
145
|
-
|
|
146
141
|
if (!text) {
|
|
147
142
|
fail({
|
|
148
143
|
code: "BAD_USAGE",
|
|
@@ -165,7 +160,10 @@ async function translate(args) {
|
|
|
165
160
|
const MODERATE_VALUE_FLAGS = ["--project"];
|
|
166
161
|
|
|
167
162
|
async function moderate(args) {
|
|
168
|
-
|
|
163
|
+
args = normalizeArgv(args);
|
|
164
|
+
assertKnownFlags(args, MODERATE_VALUE_FLAGS, MODERATE_VALUE_FLAGS);
|
|
165
|
+
|
|
166
|
+
const projectOpt = flagValue(args, "--project");
|
|
169
167
|
let projectId;
|
|
170
168
|
let rest;
|
|
171
169
|
if (projectOpt) {
|
|
@@ -203,7 +201,10 @@ async function moderate(args) {
|
|
|
203
201
|
}
|
|
204
202
|
|
|
205
203
|
async function usage(args) {
|
|
206
|
-
|
|
204
|
+
args = normalizeArgv(args);
|
|
205
|
+
assertKnownFlags(args, MODERATE_VALUE_FLAGS, MODERATE_VALUE_FLAGS);
|
|
206
|
+
|
|
207
|
+
const projectOpt = flagValue(args, "--project");
|
|
207
208
|
let projectId;
|
|
208
209
|
if (projectOpt) {
|
|
209
210
|
projectId = resolveProjectId(projectOpt);
|
package/lib/allowance.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readAllowance, saveAllowance, ALLOWANCE_FILE } from "./config.mjs";
|
|
2
2
|
import { getSdk } from "./sdk.mjs";
|
|
3
3
|
import { reportSdkError, fail } from "./sdk-errors.mjs";
|
|
4
|
+
import { assertKnownFlags, flagValue, normalizeArgv, parseIntegerFlag, positionalArgs } from "./argparse.mjs";
|
|
4
5
|
|
|
5
6
|
const HELP = `run402 allowance — Manage your agent allowance
|
|
6
7
|
|
|
@@ -258,17 +259,25 @@ async function checkout(args) {
|
|
|
258
259
|
hint: "Run: run402 allowance create",
|
|
259
260
|
});
|
|
260
261
|
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
262
|
+
const parsedArgs = normalizeArgv(args);
|
|
263
|
+
assertKnownFlags(parsedArgs, ["--amount", "--help", "-h"], ["--amount"]);
|
|
264
|
+
const bare = positionalArgs(parsedArgs, ["--amount"]);
|
|
265
|
+
if (bare.length > 0) {
|
|
266
|
+
fail({
|
|
267
|
+
code: "BAD_USAGE",
|
|
268
|
+
message: `Unexpected argument for allowance checkout: ${bare[0]}`,
|
|
269
|
+
details: { argument: bare[0] },
|
|
270
|
+
});
|
|
264
271
|
}
|
|
265
|
-
|
|
272
|
+
const amountRaw = flagValue(parsedArgs, "--amount");
|
|
273
|
+
if (amountRaw === null) {
|
|
266
274
|
fail({
|
|
267
275
|
code: "BAD_USAGE",
|
|
268
276
|
message: "Missing --amount <usd_micros>",
|
|
269
277
|
hint: "e.g. --amount 5000000 for $5",
|
|
270
278
|
});
|
|
271
279
|
}
|
|
280
|
+
const amount = parseIntegerFlag("--amount", amountRaw, { min: 1 });
|
|
272
281
|
try {
|
|
273
282
|
const data = await getSdk().billing.createCheckout(w.address, amount);
|
|
274
283
|
console.log(JSON.stringify(data, null, 2));
|
|
@@ -286,10 +295,17 @@ async function history(args) {
|
|
|
286
295
|
hint: "Run: run402 allowance create",
|
|
287
296
|
});
|
|
288
297
|
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
298
|
+
const parsedArgs = normalizeArgv(args);
|
|
299
|
+
assertKnownFlags(parsedArgs, ["--limit", "--help", "-h"], ["--limit"]);
|
|
300
|
+
const bare = positionalArgs(parsedArgs, ["--limit"]);
|
|
301
|
+
if (bare.length > 0) {
|
|
302
|
+
fail({
|
|
303
|
+
code: "BAD_USAGE",
|
|
304
|
+
message: `Unexpected argument for allowance history: ${bare[0]}`,
|
|
305
|
+
details: { argument: bare[0] },
|
|
306
|
+
});
|
|
292
307
|
}
|
|
308
|
+
const limit = parseIntegerFlag("--limit", flagValue(parsedArgs, "--limit"), { min: 1, def: 20 });
|
|
293
309
|
try {
|
|
294
310
|
const data = await getSdk().billing.history(w.address, limit);
|
|
295
311
|
console.log(JSON.stringify(data, null, 2));
|
package/lib/apps.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { allowanceAuthHeaders, saveProject } from "./config.mjs";
|
|
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
5
|
|
|
5
6
|
const HELP = `run402 apps — Browse and manage the app marketplace
|
|
6
7
|
|
|
@@ -9,7 +10,7 @@ Usage:
|
|
|
9
10
|
|
|
10
11
|
Subcommands:
|
|
11
12
|
browse [--tag <tag>] Browse public apps
|
|
12
|
-
fork <version_id> <name> [--
|
|
13
|
+
fork <version_id> <name> [--subdomain <name>]
|
|
13
14
|
Fork a published app into your own project
|
|
14
15
|
publish <id> [--description <desc>] [--tags <t1,t2>] [--visibility <v>] [--fork-allowed]
|
|
15
16
|
Publish a project as an app
|
|
@@ -22,7 +23,7 @@ Subcommands:
|
|
|
22
23
|
Examples:
|
|
23
24
|
run402 apps browse
|
|
24
25
|
run402 apps browse --tag auth
|
|
25
|
-
run402 apps fork ver_abc123 my-todo
|
|
26
|
+
run402 apps fork ver_abc123 my-todo
|
|
26
27
|
run402 apps publish prj_abc123 --description "Todo app" --tags todo,auth --visibility public --fork-allowed
|
|
27
28
|
run402 apps versions prj_abc123
|
|
28
29
|
run402 apps inspect ver_abc123
|
|
@@ -54,12 +55,11 @@ Arguments:
|
|
|
54
55
|
<name> Name for the forked project
|
|
55
56
|
|
|
56
57
|
Options:
|
|
57
|
-
--tier <tier> Tier for the new project (default: prototype)
|
|
58
58
|
--subdomain <name> Claim a subdomain for the forked project
|
|
59
59
|
|
|
60
60
|
Examples:
|
|
61
61
|
run402 apps fork ver_abc123 my-todo
|
|
62
|
-
run402 apps fork ver_abc123 my-todo --
|
|
62
|
+
run402 apps fork ver_abc123 my-todo --subdomain todo-v2
|
|
63
63
|
`,
|
|
64
64
|
publish: `run402 apps publish — Publish a project as an app
|
|
65
65
|
|
|
@@ -137,9 +137,16 @@ Examples:
|
|
|
137
137
|
};
|
|
138
138
|
|
|
139
139
|
async function browse(args) {
|
|
140
|
+
const parsedArgs = normalizeArgv(args);
|
|
141
|
+
const valueFlags = ["--tag"];
|
|
142
|
+
assertKnownFlags(parsedArgs, [...valueFlags, "--help", "-h"], valueFlags);
|
|
143
|
+
const extra = positionalArgs(parsedArgs, valueFlags);
|
|
144
|
+
if (extra.length > 0) {
|
|
145
|
+
fail({ code: "BAD_USAGE", message: `Unexpected argument for apps browse: ${extra[0]}` });
|
|
146
|
+
}
|
|
140
147
|
const tags = [];
|
|
141
|
-
for (let i = 0; i <
|
|
142
|
-
if (
|
|
148
|
+
for (let i = 0; i < parsedArgs.length; i++) {
|
|
149
|
+
if (parsedArgs[i] === "--tag") tags.push(parsedArgs[++i]);
|
|
143
150
|
}
|
|
144
151
|
try {
|
|
145
152
|
const data = await getSdk().apps.browse(tags.length > 0 ? tags : undefined);
|
|
@@ -150,18 +157,24 @@ async function browse(args) {
|
|
|
150
157
|
}
|
|
151
158
|
|
|
152
159
|
async function fork(versionId, name, args) {
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
160
|
+
const parsedArgs = normalizeArgv([versionId, name, ...args].filter((arg) => arg !== undefined));
|
|
161
|
+
const valueFlags = ["--subdomain"];
|
|
162
|
+
assertKnownFlags(parsedArgs, [...valueFlags, "--help", "-h"], valueFlags);
|
|
163
|
+
const positionals = positionalArgs(parsedArgs, valueFlags);
|
|
164
|
+
if (positionals.length < 2) {
|
|
165
|
+
fail({ code: "BAD_USAGE", message: "Missing <version_id> and/or <name>." });
|
|
157
166
|
}
|
|
167
|
+
if (positionals.length > 2) {
|
|
168
|
+
fail({ code: "BAD_USAGE", message: `Unexpected argument for apps fork: ${positionals[2]}` });
|
|
169
|
+
}
|
|
170
|
+
const opts = { subdomain: flagValue(parsedArgs, "--subdomain") ?? undefined };
|
|
158
171
|
// Preserve the aggressive early exit when no allowance is configured.
|
|
159
172
|
allowanceAuthHeaders("/fork/v1");
|
|
160
173
|
|
|
161
174
|
try {
|
|
162
175
|
const data = await getSdk().apps.fork({
|
|
163
|
-
versionId,
|
|
164
|
-
name,
|
|
176
|
+
versionId: positionals[0],
|
|
177
|
+
name: positionals[1],
|
|
165
178
|
subdomain: opts.subdomain,
|
|
166
179
|
});
|
|
167
180
|
|
|
@@ -181,15 +194,24 @@ async function fork(versionId, name, args) {
|
|
|
181
194
|
}
|
|
182
195
|
|
|
183
196
|
async function publish(projectId, args) {
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
197
|
+
const parsedArgs = normalizeArgv([projectId, ...args].filter((arg) => arg !== undefined));
|
|
198
|
+
const valueFlags = ["--description", "--tags", "--visibility"];
|
|
199
|
+
assertKnownFlags(parsedArgs, [...valueFlags, "--fork-allowed", "--help", "-h"], valueFlags);
|
|
200
|
+
const positionals = positionalArgs(parsedArgs, valueFlags);
|
|
201
|
+
if (positionals.length < 1) {
|
|
202
|
+
fail({ code: "BAD_USAGE", message: "Missing <id>." });
|
|
190
203
|
}
|
|
204
|
+
if (positionals.length > 1) {
|
|
205
|
+
fail({ code: "BAD_USAGE", message: `Unexpected argument for apps publish: ${positionals[1]}` });
|
|
206
|
+
}
|
|
207
|
+
const opts = { description: undefined, tags: undefined, visibility: undefined, forkAllowed: undefined };
|
|
208
|
+
opts.description = flagValue(parsedArgs, "--description") ?? undefined;
|
|
209
|
+
opts.tags = flagValue(parsedArgs, "--tags")?.split(",");
|
|
210
|
+
opts.visibility = flagValue(parsedArgs, "--visibility") ?? undefined;
|
|
211
|
+
if (opts.visibility) assertAllowedValue(opts.visibility, ["public", "unlisted", "private"], "--visibility");
|
|
212
|
+
if (parsedArgs.includes("--fork-allowed")) opts.forkAllowed = true;
|
|
191
213
|
try {
|
|
192
|
-
const data = await getSdk().apps.publish(
|
|
214
|
+
const data = await getSdk().apps.publish(positionals[0], {
|
|
193
215
|
description: opts.description,
|
|
194
216
|
tags: opts.tags,
|
|
195
217
|
visibility: opts.visibility,
|
|
@@ -201,21 +223,30 @@ async function publish(projectId, args) {
|
|
|
201
223
|
}
|
|
202
224
|
}
|
|
203
225
|
|
|
204
|
-
async function versions(projectId) {
|
|
226
|
+
async function versions(projectId, args = []) {
|
|
227
|
+
const parsedArgs = normalizeArgv([projectId, ...args].filter((arg) => arg !== undefined));
|
|
228
|
+
assertKnownFlags(parsedArgs, ["--help", "-h"]);
|
|
229
|
+
const positionals = positionalArgs(parsedArgs);
|
|
230
|
+
if (positionals.length !== 1) {
|
|
231
|
+
fail({ code: "BAD_USAGE", message: positionals.length === 0 ? "Missing <id>." : `Unexpected argument for apps versions: ${positionals[1]}` });
|
|
232
|
+
}
|
|
205
233
|
try {
|
|
206
|
-
const data = await getSdk().apps.listVersions(
|
|
234
|
+
const data = await getSdk().apps.listVersions(positionals[0]);
|
|
207
235
|
console.log(JSON.stringify(data, null, 2));
|
|
208
236
|
} catch (err) {
|
|
209
237
|
reportSdkError(err);
|
|
210
238
|
}
|
|
211
239
|
}
|
|
212
240
|
|
|
213
|
-
async function inspect(versionId) {
|
|
214
|
-
|
|
215
|
-
|
|
241
|
+
async function inspect(versionId, args = []) {
|
|
242
|
+
const parsedArgs = normalizeArgv([versionId, ...args].filter((arg) => arg !== undefined));
|
|
243
|
+
assertKnownFlags(parsedArgs, ["--help", "-h"]);
|
|
244
|
+
const positionals = positionalArgs(parsedArgs);
|
|
245
|
+
if (positionals.length !== 1) {
|
|
246
|
+
fail({ code: "BAD_USAGE", message: positionals.length === 0 ? "Missing version ID" : `Unexpected argument for apps inspect: ${positionals[1]}` });
|
|
216
247
|
}
|
|
217
248
|
try {
|
|
218
|
-
const data = await getSdk().apps.getApp(
|
|
249
|
+
const data = await getSdk().apps.getApp(positionals[0]);
|
|
219
250
|
console.log(JSON.stringify(data, null, 2));
|
|
220
251
|
} catch (err) {
|
|
221
252
|
reportSdkError(err);
|
|
@@ -223,26 +254,47 @@ async function inspect(versionId) {
|
|
|
223
254
|
}
|
|
224
255
|
|
|
225
256
|
async function update(projectId, versionId, args) {
|
|
226
|
-
const
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
257
|
+
const parsedArgs = normalizeArgv([projectId, versionId, ...args].filter((arg) => arg !== undefined));
|
|
258
|
+
const valueFlags = ["--description", "--tags", "--visibility"];
|
|
259
|
+
assertKnownFlags(parsedArgs, [...valueFlags, "--fork-allowed", "--no-fork", "--help", "-h"], valueFlags);
|
|
260
|
+
const positionals = positionalArgs(parsedArgs, valueFlags);
|
|
261
|
+
if (positionals.length < 2) {
|
|
262
|
+
fail({ code: "BAD_USAGE", message: "Missing <project_id> and/or <version_id>." });
|
|
263
|
+
}
|
|
264
|
+
if (positionals.length > 2) {
|
|
265
|
+
fail({ code: "BAD_USAGE", message: `Unexpected argument for apps update: ${positionals[2]}` });
|
|
266
|
+
}
|
|
267
|
+
if (parsedArgs.includes("--fork-allowed") && parsedArgs.includes("--no-fork")) {
|
|
268
|
+
fail({ code: "BAD_USAGE", message: "Provide either --fork-allowed or --no-fork, not both." });
|
|
233
269
|
}
|
|
270
|
+
const opts = {};
|
|
271
|
+
opts.description = flagValue(parsedArgs, "--description") ?? undefined;
|
|
272
|
+
opts.tags = flagValue(parsedArgs, "--tags")?.split(",");
|
|
273
|
+
opts.visibility = flagValue(parsedArgs, "--visibility") ?? undefined;
|
|
274
|
+
if (opts.visibility) assertAllowedValue(opts.visibility, ["public", "unlisted", "private"], "--visibility");
|
|
275
|
+
if (parsedArgs.includes("--fork-allowed")) opts.fork_allowed = true;
|
|
276
|
+
if (parsedArgs.includes("--no-fork")) opts.fork_allowed = false;
|
|
234
277
|
try {
|
|
235
|
-
await getSdk().apps.updateVersion(
|
|
236
|
-
console.log(JSON.stringify({ status: "ok", project_id:
|
|
278
|
+
await getSdk().apps.updateVersion(positionals[0], positionals[1], opts);
|
|
279
|
+
console.log(JSON.stringify({ status: "ok", project_id: positionals[0], version_id: positionals[1] }));
|
|
237
280
|
} catch (err) {
|
|
238
281
|
reportSdkError(err);
|
|
239
282
|
}
|
|
240
283
|
}
|
|
241
284
|
|
|
242
|
-
async function deleteVersion(projectId, versionId) {
|
|
285
|
+
async function deleteVersion(projectId, versionId, args = []) {
|
|
286
|
+
const parsedArgs = normalizeArgv([projectId, versionId, ...args].filter((arg) => arg !== undefined));
|
|
287
|
+
assertKnownFlags(parsedArgs, ["--help", "-h"]);
|
|
288
|
+
const positionals = positionalArgs(parsedArgs);
|
|
289
|
+
if (positionals.length < 2) {
|
|
290
|
+
fail({ code: "BAD_USAGE", message: "Missing <project_id> and/or <version_id>." });
|
|
291
|
+
}
|
|
292
|
+
if (positionals.length > 2) {
|
|
293
|
+
fail({ code: "BAD_USAGE", message: `Unexpected argument for apps delete: ${positionals[2]}` });
|
|
294
|
+
}
|
|
243
295
|
try {
|
|
244
|
-
await getSdk().apps.deleteVersion(
|
|
245
|
-
console.log(JSON.stringify({ status: "ok", message: `Version ${
|
|
296
|
+
await getSdk().apps.deleteVersion(positionals[0], positionals[1]);
|
|
297
|
+
console.log(JSON.stringify({ status: "ok", message: `Version ${positionals[1]} deleted.` }));
|
|
246
298
|
} catch (err) {
|
|
247
299
|
reportSdkError(err);
|
|
248
300
|
}
|
|
@@ -255,10 +307,10 @@ export async function run(sub, args) {
|
|
|
255
307
|
case "browse": await browse(args); break;
|
|
256
308
|
case "fork": await fork(args[0], args[1], args.slice(2)); break;
|
|
257
309
|
case "publish": await publish(args[0], args.slice(1)); break;
|
|
258
|
-
case "versions": await versions(args[0]); break;
|
|
259
|
-
case "inspect": await inspect(args[0]); break;
|
|
310
|
+
case "versions": await versions(args[0], args.slice(1)); break;
|
|
311
|
+
case "inspect": await inspect(args[0], args.slice(1)); break;
|
|
260
312
|
case "update": await update(args[0], args[1], args.slice(2)); break;
|
|
261
|
-
case "delete": await deleteVersion(args[0], args[1]); break;
|
|
313
|
+
case "delete": await deleteVersion(args[0], args[1], args.slice(2)); break;
|
|
262
314
|
default:
|
|
263
315
|
console.error(`Unknown subcommand: ${sub}\n`);
|
|
264
316
|
console.log(HELP);
|
package/lib/argparse.mjs
CHANGED
|
@@ -25,6 +25,13 @@ export function assertKnownFlags(args = [], knownFlags = [], flagsWithValues = [
|
|
|
25
25
|
for (let i = 0; i < args.length; i++) {
|
|
26
26
|
const arg = args[i];
|
|
27
27
|
if (valueFlags.has(arg)) {
|
|
28
|
+
if (i + 1 >= args.length || (typeof args[i + 1] === "string" && args[i + 1].startsWith("--"))) {
|
|
29
|
+
fail({
|
|
30
|
+
code: "BAD_FLAG",
|
|
31
|
+
message: `${arg} requires a value`,
|
|
32
|
+
details: { flag: arg },
|
|
33
|
+
});
|
|
34
|
+
}
|
|
28
35
|
i += 1;
|
|
29
36
|
continue;
|
|
30
37
|
}
|
|
@@ -47,7 +54,7 @@ export function failUnknownFlag(flag, knownFlags = []) {
|
|
|
47
54
|
export function flagValue(args, flag) {
|
|
48
55
|
const idx = args.indexOf(flag);
|
|
49
56
|
if (idx === -1) return null;
|
|
50
|
-
if (idx + 1 >= args.length) {
|
|
57
|
+
if (idx + 1 >= args.length || (typeof args[idx + 1] === "string" && args[idx + 1].startsWith("--"))) {
|
|
51
58
|
fail({
|
|
52
59
|
code: "BAD_FLAG",
|
|
53
60
|
message: `${flag} requires a value`,
|
|
@@ -75,6 +82,13 @@ export function parseIntegerFlag(name, value, { min = 1, max = Number.POSITIVE_I
|
|
|
75
82
|
});
|
|
76
83
|
}
|
|
77
84
|
const n = Number.parseInt(raw, 10);
|
|
85
|
+
if (!Number.isSafeInteger(n)) {
|
|
86
|
+
fail({
|
|
87
|
+
code: "BAD_FLAG",
|
|
88
|
+
message: `${name} must be a safe integer, got: ${raw}`,
|
|
89
|
+
details: { flag: name, value: raw },
|
|
90
|
+
});
|
|
91
|
+
}
|
|
78
92
|
if (n < min) {
|
|
79
93
|
fail({
|
|
80
94
|
code: "BAD_FLAG",
|
|
@@ -92,6 +106,26 @@ export function parseIntegerFlag(name, value, { min = 1, max = Number.POSITIVE_I
|
|
|
92
106
|
return n;
|
|
93
107
|
}
|
|
94
108
|
|
|
109
|
+
export function assertAllowedValue(value, allowed, fieldName) {
|
|
110
|
+
if (!allowed.includes(value)) {
|
|
111
|
+
fail({
|
|
112
|
+
code: "BAD_FLAG",
|
|
113
|
+
message: `${fieldName} must be one of: ${allowed.join(", ")}`,
|
|
114
|
+
details: { field: fieldName, value, allowed },
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function validateEvmAddress(value, fieldName = "address") {
|
|
120
|
+
if (typeof value !== "string" || !/^0x[a-fA-F0-9]{40}$/.test(value)) {
|
|
121
|
+
fail({
|
|
122
|
+
code: "BAD_FLAG",
|
|
123
|
+
message: `${fieldName} must be a 0x-prefixed 20-byte EVM address`,
|
|
124
|
+
details: { field: fieldName, value },
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
95
129
|
export function failBadProjectId(value) {
|
|
96
130
|
fail({
|
|
97
131
|
code: "BAD_PROJECT_ID",
|
|
@@ -199,6 +233,31 @@ export function positionalArgs(args = [], flagsWithValues = []) {
|
|
|
199
233
|
return out;
|
|
200
234
|
}
|
|
201
235
|
|
|
236
|
+
export function requirePositionalCount(args = [], flagsWithValues = [], opts = {}) {
|
|
237
|
+
const {
|
|
238
|
+
min = 0,
|
|
239
|
+
max = min,
|
|
240
|
+
command = "command",
|
|
241
|
+
missing = "Missing required argument.",
|
|
242
|
+
} = opts;
|
|
243
|
+
const pos = positionalArgs(args, flagsWithValues);
|
|
244
|
+
if (pos.length < min) {
|
|
245
|
+
fail({
|
|
246
|
+
code: "BAD_USAGE",
|
|
247
|
+
message: missing,
|
|
248
|
+
hint: command,
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
if (pos.length > max) {
|
|
252
|
+
fail({
|
|
253
|
+
code: "BAD_USAGE",
|
|
254
|
+
message: `Unexpected argument for ${command}: ${pos[max]}`,
|
|
255
|
+
hint: `Use \`${command}\`.`,
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
return pos;
|
|
259
|
+
}
|
|
260
|
+
|
|
202
261
|
// Resolve a positional project_id argument with active-project fallback (GH-102, GH-187).
|
|
203
262
|
// If the first positional starts with "prj_", treat it as the project id and
|
|
204
263
|
// strip it from the rest. Otherwise, fall through to the active project from
|
package/lib/auth.mjs
CHANGED
|
@@ -1,6 +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
5
|
|
|
5
6
|
const HELP = `run402 auth — Manage project user authentication
|
|
6
7
|
|
|
@@ -230,6 +231,61 @@ Examples:
|
|
|
230
231
|
`,
|
|
231
232
|
};
|
|
232
233
|
|
|
234
|
+
const AUTH_FLAGS = {
|
|
235
|
+
"magic-link": {
|
|
236
|
+
known: ["--email", "--redirect", "--intent", "--state", "--project", "--help", "-h"],
|
|
237
|
+
values: ["--email", "--redirect", "--intent", "--state", "--project"],
|
|
238
|
+
},
|
|
239
|
+
"create-user": {
|
|
240
|
+
known: ["--email", "--admin", "--invite", "--redirect", "--state", "--project", "--help", "-h"],
|
|
241
|
+
values: ["--email", "--admin", "--redirect", "--state", "--project"],
|
|
242
|
+
},
|
|
243
|
+
"invite-user": {
|
|
244
|
+
known: ["--email", "--redirect", "--admin", "--state", "--project", "--help", "-h"],
|
|
245
|
+
values: ["--email", "--redirect", "--admin", "--state", "--project"],
|
|
246
|
+
},
|
|
247
|
+
verify: {
|
|
248
|
+
known: ["--token", "--project", "--help", "-h"],
|
|
249
|
+
values: ["--token", "--project"],
|
|
250
|
+
},
|
|
251
|
+
"set-password": {
|
|
252
|
+
known: ["--token", "--new", "--current", "--project", "--help", "-h"],
|
|
253
|
+
values: ["--token", "--new", "--current", "--project"],
|
|
254
|
+
},
|
|
255
|
+
settings: {
|
|
256
|
+
known: ["--allow-password-set", "--preferred", "--public-signup", "--require-admin-passkey", "--project", "--help", "-h"],
|
|
257
|
+
values: ["--allow-password-set", "--preferred", "--public-signup", "--require-admin-passkey", "--project"],
|
|
258
|
+
},
|
|
259
|
+
"passkey-register-options": {
|
|
260
|
+
known: ["--token", "--app-origin", "--project", "--help", "-h"],
|
|
261
|
+
values: ["--token", "--app-origin", "--project"],
|
|
262
|
+
},
|
|
263
|
+
"passkey-register-verify": {
|
|
264
|
+
known: ["--token", "--challenge", "--response", "--label", "--project", "--help", "-h"],
|
|
265
|
+
values: ["--token", "--challenge", "--response", "--label", "--project"],
|
|
266
|
+
},
|
|
267
|
+
"passkey-login-options": {
|
|
268
|
+
known: ["--app-origin", "--email", "--project", "--help", "-h"],
|
|
269
|
+
values: ["--app-origin", "--email", "--project"],
|
|
270
|
+
},
|
|
271
|
+
"passkey-login-verify": {
|
|
272
|
+
known: ["--challenge", "--response", "--project", "--help", "-h"],
|
|
273
|
+
values: ["--challenge", "--response", "--project"],
|
|
274
|
+
},
|
|
275
|
+
passkeys: {
|
|
276
|
+
known: ["--token", "--project", "--help", "-h"],
|
|
277
|
+
values: ["--token", "--project"],
|
|
278
|
+
},
|
|
279
|
+
"delete-passkey": {
|
|
280
|
+
known: ["--token", "--id", "--project", "--help", "-h"],
|
|
281
|
+
values: ["--token", "--id", "--project"],
|
|
282
|
+
},
|
|
283
|
+
providers: {
|
|
284
|
+
known: ["--project", "--help", "-h"],
|
|
285
|
+
values: ["--project"],
|
|
286
|
+
},
|
|
287
|
+
};
|
|
288
|
+
|
|
233
289
|
function parseFlag(args, flag) {
|
|
234
290
|
for (let i = 0; i < args.length; i++) {
|
|
235
291
|
if (args[i] === flag && args[i + 1]) return args[i + 1];
|
|
@@ -557,10 +613,15 @@ async function providers(args) {
|
|
|
557
613
|
|
|
558
614
|
export async function run(sub, args) {
|
|
559
615
|
if (!sub || sub === "--help" || sub === "-h") { console.log(HELP); process.exit(0); }
|
|
560
|
-
|
|
616
|
+
args = normalizeArgv(args);
|
|
617
|
+
if (Array.isArray(args) && hasHelp(args)) {
|
|
561
618
|
console.log(SUB_HELP[sub] || HELP);
|
|
562
619
|
process.exit(0);
|
|
563
620
|
}
|
|
621
|
+
const flagSpec = AUTH_FLAGS[sub];
|
|
622
|
+
if (flagSpec) {
|
|
623
|
+
assertKnownFlags(args, flagSpec.known, flagSpec.values);
|
|
624
|
+
}
|
|
564
625
|
switch (sub) {
|
|
565
626
|
case "magic-link": await magicLink(args); break;
|
|
566
627
|
case "verify": await verify(args); break;
|