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.
Files changed (47) hide show
  1. package/lib/agent.mjs +37 -11
  2. package/lib/ai.mjs +16 -15
  3. package/lib/allowance.mjs +23 -7
  4. package/lib/apps.mjs +92 -40
  5. package/lib/argparse.mjs +60 -1
  6. package/lib/auth.mjs +62 -1
  7. package/lib/billing.mjs +83 -25
  8. package/lib/blob.mjs +2 -2
  9. package/lib/cdn.mjs +21 -8
  10. package/lib/contracts.mjs +123 -33
  11. package/lib/domains.mjs +22 -11
  12. package/lib/email.mjs +68 -61
  13. package/lib/image.mjs +17 -8
  14. package/lib/message.mjs +4 -1
  15. package/lib/secrets.mjs +29 -12
  16. package/lib/sender-domain.mjs +32 -14
  17. package/lib/sites.mjs +39 -16
  18. package/lib/subdomains.mjs +31 -35
  19. package/lib/tier.mjs +26 -4
  20. package/lib/webhooks.mjs +46 -33
  21. package/package.json +1 -1
  22. package/sdk/dist/errors.d.ts +4 -1
  23. package/sdk/dist/errors.d.ts.map +1 -1
  24. package/sdk/dist/errors.js +16 -2
  25. package/sdk/dist/errors.js.map +1 -1
  26. package/sdk/dist/namespaces/ai.d.ts.map +1 -1
  27. package/sdk/dist/namespaces/ai.js +7 -2
  28. package/sdk/dist/namespaces/ai.js.map +1 -1
  29. package/sdk/dist/namespaces/billing.d.ts.map +1 -1
  30. package/sdk/dist/namespaces/billing.js +20 -17
  31. package/sdk/dist/namespaces/billing.js.map +1 -1
  32. package/sdk/dist/namespaces/contracts.d.ts.map +1 -1
  33. package/sdk/dist/namespaces/contracts.js +21 -4
  34. package/sdk/dist/namespaces/contracts.js.map +1 -1
  35. package/sdk/dist/namespaces/deploy.js +9 -0
  36. package/sdk/dist/namespaces/deploy.js.map +1 -1
  37. package/sdk/dist/namespaces/functions.d.ts.map +1 -1
  38. package/sdk/dist/namespaces/functions.js +20 -0
  39. package/sdk/dist/namespaces/functions.js.map +1 -1
  40. package/sdk/dist/retry.d.ts +2 -1
  41. package/sdk/dist/retry.d.ts.map +1 -1
  42. package/sdk/dist/retry.js +2 -1
  43. package/sdk/dist/retry.js.map +1 -1
  44. package/sdk/dist/validation.d.ts +3 -0
  45. package/sdk/dist/validation.d.ts.map +1 -1
  46. package/sdk/dist/validation.js +15 -0
  47. package/sdk/dist/validation.js.map +1 -1
package/lib/email.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, parseFlagJson } from "./sdk-errors.mjs";
4
+ import { assertKnownFlags, flagValue, normalizeArgv, parseIntegerFlag, positionalArgs } from "./argparse.mjs";
4
5
 
5
6
  const HELP = `run402 email — Send emails from your project
6
7
 
@@ -152,17 +153,39 @@ Examples:
152
153
  `,
153
154
  };
154
155
 
155
- function parseFlag(args, flag) {
156
+ function strictFlagValue(args, flag) {
157
+ const value = flagValue(args, flag);
158
+ if (typeof value === "string" && value.startsWith("--")) {
159
+ fail({
160
+ code: "BAD_FLAG",
161
+ message: `${flag} requires a value`,
162
+ details: { flag },
163
+ });
164
+ }
165
+ return value;
166
+ }
167
+
168
+ function validateArgs(args, knownFlags, flagsWithValues = knownFlags) {
169
+ assertKnownFlags(args, knownFlags, flagsWithValues);
170
+ const valueFlags = new Set(flagsWithValues);
156
171
  for (let i = 0; i < args.length; i++) {
157
- if (args[i] === flag && args[i + 1]) return args[i + 1];
172
+ const flag = args[i];
173
+ if (!valueFlags.has(flag)) continue;
174
+ if (i + 1 >= args.length || (typeof args[i + 1] === "string" && args[i + 1].startsWith("--"))) {
175
+ fail({
176
+ code: "BAD_FLAG",
177
+ message: `${flag} requires a value`,
178
+ details: { flag },
179
+ });
180
+ }
181
+ i += 1;
158
182
  }
159
- return null;
160
183
  }
161
184
 
162
185
  function parseVars(args) {
163
186
  const vars = {};
164
187
  for (let i = 0; i < args.length; i++) {
165
- if (args[i] === "--vars" && args[i + 1]) {
188
+ if (args[i] === "--vars") {
166
189
  const raw = args[++i];
167
190
  const parsed = parseFlagJson("--vars", raw);
168
191
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
@@ -175,7 +198,7 @@ function parseVars(args) {
175
198
  }
176
199
  }
177
200
  for (let i = 0; i < args.length; i++) {
178
- if (args[i] === "--var" && args[i + 1]) {
201
+ if (args[i] === "--var") {
179
202
  const raw = args[++i];
180
203
  const eq = raw.indexOf("=");
181
204
  if (eq > 0) vars[raw.slice(0, eq)] = raw.slice(eq + 1);
@@ -185,12 +208,9 @@ function parseVars(args) {
185
208
  }
186
209
 
187
210
  async function create(args) {
188
- let slug = null;
189
- let projectOpt = null;
190
- for (let i = 0; i < args.length; i++) {
191
- if (args[i] === "--project" && args[i + 1]) { projectOpt = args[++i]; }
192
- else if (!args[i].startsWith("--") && !slug) { slug = args[i]; }
193
- }
211
+ validateArgs(args, ["--project"]);
212
+ const slug = positionalArgs(args, ["--project"])[0] ?? null;
213
+ const projectOpt = strictFlagValue(args, "--project");
194
214
  const projectId = resolveProjectId(projectOpt);
195
215
  if (!slug) {
196
216
  fail({
@@ -209,13 +229,15 @@ async function create(args) {
209
229
  }
210
230
 
211
231
  async function send(args) {
212
- const template = parseFlag(args, "--template");
213
- const to = parseFlag(args, "--to");
214
- const subject = parseFlag(args, "--subject");
215
- const html = parseFlag(args, "--html");
216
- const text = parseFlag(args, "--text");
217
- const fromName = parseFlag(args, "--from-name");
218
- const projectId = resolveProjectId(parseFlag(args, "--project"));
232
+ const valueFlags = ["--template", "--to", "--subject", "--html", "--text", "--from-name", "--project", "--vars", "--var"];
233
+ validateArgs(args, valueFlags);
234
+ const template = strictFlagValue(args, "--template");
235
+ const to = strictFlagValue(args, "--to");
236
+ const subject = strictFlagValue(args, "--subject");
237
+ const html = strictFlagValue(args, "--html");
238
+ const text = strictFlagValue(args, "--text");
239
+ const fromName = strictFlagValue(args, "--from-name");
240
+ const projectId = resolveProjectId(strictFlagValue(args, "--project"));
219
241
  const variables = parseVars(args);
220
242
 
221
243
  if (!to) {
@@ -239,12 +261,14 @@ async function send(args) {
239
261
  }
240
262
 
241
263
  async function list(args) {
242
- const projectId = resolveProjectId(parseFlag(args, "--project"));
243
- const limit = parseFlag(args, "--limit");
244
- const after = parseFlag(args, "--after");
264
+ const valueFlags = ["--project", "--limit", "--after"];
265
+ validateArgs(args, valueFlags);
266
+ const projectId = resolveProjectId(strictFlagValue(args, "--project"));
267
+ const limit = strictFlagValue(args, "--limit");
268
+ const after = strictFlagValue(args, "--after");
245
269
  try {
246
270
  const data = await getSdk().email.list(projectId, {
247
- limit: limit ? Number(limit) : undefined,
271
+ limit: limit ? parseIntegerFlag("--limit", limit) : undefined,
248
272
  after: after ?? undefined,
249
273
  });
250
274
  console.log(JSON.stringify(data, null, 2));
@@ -254,13 +278,9 @@ async function list(args) {
254
278
  }
255
279
 
256
280
  async function get(args) {
257
- let messageId = null;
258
- let projectOpt = null;
259
- for (let i = 0; i < args.length; i++) {
260
- if (args[i] === "--project" && args[i + 1]) { projectOpt = args[++i]; }
261
- else if (!args[i].startsWith("--") && !messageId) { messageId = args[i]; }
262
- }
263
- const projectId = resolveProjectId(projectOpt);
281
+ validateArgs(args, ["--project"]);
282
+ const messageId = positionalArgs(args, ["--project"])[0] ?? null;
283
+ const projectId = resolveProjectId(strictFlagValue(args, "--project"));
264
284
  if (!messageId) {
265
285
  fail({
266
286
  code: "BAD_USAGE",
@@ -277,15 +297,11 @@ async function get(args) {
277
297
  }
278
298
 
279
299
  async function getRaw(args) {
280
- let messageId = null;
281
- let projectOpt = null;
282
- let outputFile = null;
283
- for (let i = 0; i < args.length; i++) {
284
- if (args[i] === "--project" && args[i + 1]) { projectOpt = args[++i]; }
285
- else if (args[i] === "--output" && args[i + 1]) { outputFile = args[++i]; }
286
- else if (!args[i].startsWith("--") && !messageId) { messageId = args[i]; }
287
- }
288
- const projectId = resolveProjectId(projectOpt);
300
+ const valueFlags = ["--project", "--output"];
301
+ validateArgs(args, valueFlags);
302
+ const messageId = positionalArgs(args, valueFlags)[0] ?? null;
303
+ const outputFile = strictFlagValue(args, "--output");
304
+ const projectId = resolveProjectId(strictFlagValue(args, "--project"));
289
305
  if (!messageId) {
290
306
  fail({
291
307
  code: "BAD_USAGE",
@@ -311,19 +327,14 @@ async function getRaw(args) {
311
327
  }
312
328
 
313
329
  async function reply(args) {
314
- let messageId = null;
315
- let projectOpt = null;
316
- for (let i = 0; i < args.length; i++) {
317
- const a = args[i];
318
- if (a === "--project" && args[i + 1]) { projectOpt = args[++i]; }
319
- else if (a === "--html" || a === "--text" || a === "--subject" || a === "--from-name") { i++; }
320
- else if (!a.startsWith("--") && !messageId) { messageId = a; }
321
- }
322
- const html = parseFlag(args, "--html");
323
- const text = parseFlag(args, "--text");
324
- const subjectOverride = parseFlag(args, "--subject");
325
- const fromName = parseFlag(args, "--from-name");
326
- const projectId = resolveProjectId(projectOpt);
330
+ const valueFlags = ["--project", "--html", "--text", "--subject", "--from-name"];
331
+ validateArgs(args, valueFlags);
332
+ const messageId = positionalArgs(args, valueFlags)[0] ?? null;
333
+ const html = strictFlagValue(args, "--html");
334
+ const text = strictFlagValue(args, "--text");
335
+ const subjectOverride = strictFlagValue(args, "--subject");
336
+ const fromName = strictFlagValue(args, "--from-name");
337
+ const projectId = resolveProjectId(strictFlagValue(args, "--project"));
327
338
 
328
339
  if (!messageId) {
329
340
  fail({
@@ -371,15 +382,9 @@ async function reply(args) {
371
382
  }
372
383
 
373
384
  async function deleteMailbox(args) {
374
- let positional = null;
375
- let projectOpt = null;
376
- for (let i = 0; i < args.length; i++) {
377
- const a = args[i];
378
- if (a === "--project" && args[i + 1]) { projectOpt = args[++i]; }
379
- else if (a === "--confirm") { /* flag */ }
380
- else if (!a.startsWith("--") && !positional) { positional = a; }
381
- }
382
- const projectId = resolveProjectId(projectOpt);
385
+ validateArgs(args, ["--project", "--confirm"], ["--project"]);
386
+ const positional = positionalArgs(args, ["--project"])[0] ?? null;
387
+ const projectId = resolveProjectId(strictFlagValue(args, "--project"));
383
388
  const confirmed = args.includes("--confirm");
384
389
 
385
390
  if (!confirmed) {
@@ -398,7 +403,8 @@ async function deleteMailbox(args) {
398
403
  }
399
404
 
400
405
  async function status(args) {
401
- const projectId = resolveProjectId(parseFlag(args, "--project"));
406
+ validateArgs(args, ["--project"]);
407
+ const projectId = resolveProjectId(strictFlagValue(args, "--project"));
402
408
  try {
403
409
  const mb = await getSdk().email.getMailbox(projectId);
404
410
  console.log(JSON.stringify({ status: "ok", mailbox_id: mb.mailbox_id, address: mb.address, slug: mb.slug }));
@@ -408,6 +414,7 @@ async function status(args) {
408
414
  }
409
415
 
410
416
  export async function run(sub, args) {
417
+ args = normalizeArgv(args);
411
418
  if (!sub || sub === '--help' || sub === '-h') { console.log(HELP); process.exit(0); }
412
419
  if (Array.isArray(args) && (args.includes("--help") || args.includes("-h")) && sub !== "webhooks") { console.log(SUB_HELP[sub] || HELP); process.exit(0); }
413
420
  switch (sub) {
package/lib/image.mjs CHANGED
@@ -1,6 +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
5
 
5
6
  const HELP = `run402 image — Generate AI images via x402 micropayments
6
7
 
@@ -71,15 +72,22 @@ export async function run(sub, args) {
71
72
  process.exit(1);
72
73
  }
73
74
 
74
- const opts = { prompt: null, aspect: "square", output: null };
75
- let i = 0;
76
- if (i < args.length && !args[i].startsWith("--")) opts.prompt = args[i++];
77
- while (i < args.length) {
78
- if (args[i] === "--help" || args[i] === "-h") { console.log(SUB_HELP[sub] || HELP); process.exit(0); }
79
- else if (args[i] === "--aspect" && args[i + 1]) { opts.aspect = args[++i]; }
80
- else if (args[i] === "--output" && args[i + 1]) { opts.output = args[++i]; }
81
- i++;
75
+ const parsedArgs = normalizeArgv(args);
76
+ const valueFlags = ["--aspect", "--output"];
77
+ assertKnownFlags(parsedArgs, [...valueFlags, "--help", "-h"], valueFlags);
78
+ const positionals = positionalArgs(parsedArgs, valueFlags);
79
+ if (positionals.length > 1) {
80
+ fail({
81
+ code: "BAD_USAGE",
82
+ message: `Unexpected argument for image generate: ${positionals[1]}`,
83
+ hint: 'Quote multi-word prompts, e.g. run402 image generate "your prompt".',
84
+ });
82
85
  }
86
+ const opts = {
87
+ prompt: positionals[0] ?? null,
88
+ aspect: flagValue(parsedArgs, "--aspect") ?? "square",
89
+ output: flagValue(parsedArgs, "--output"),
90
+ };
83
91
 
84
92
  if (!opts.prompt) {
85
93
  fail({
@@ -88,6 +96,7 @@ export async function run(sub, args) {
88
96
  hint: 'run402 image generate "your prompt"',
89
97
  });
90
98
  }
99
+ assertAllowedValue(opts.aspect, ["square", "landscape", "portrait"], "--aspect");
91
100
 
92
101
  try {
93
102
  const data = await getSdk().ai.generateImage({ prompt: opts.prompt, aspect: opts.aspect });
package/lib/message.mjs CHANGED
@@ -1,6 +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
5
 
5
6
  const HELP = `run402 message — Send messages to Run402 developers
6
7
 
@@ -88,5 +89,7 @@ export async function run(sub, args) {
88
89
  console.log(HELP);
89
90
  process.exit(1);
90
91
  }
91
- await send(args.join(" "));
92
+ const parsedArgs = normalizeArgv(args);
93
+ assertKnownFlags(parsedArgs, ["--help", "-h"]);
94
+ await send(parsedArgs.join(" "));
92
95
  }
package/lib/secrets.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { readFileSync } from "fs";
2
2
  import { getSdk } from "./sdk.mjs";
3
3
  import { reportSdkError, fail } from "./sdk-errors.mjs";
4
- import { validateRegularFile } from "./argparse.mjs";
4
+ import { assertKnownFlags, flagValue, normalizeArgv, positionalArgs, validateRegularFile } from "./argparse.mjs";
5
5
 
6
6
  const HELP = `run402 secrets — Manage project secrets
7
7
 
@@ -78,15 +78,20 @@ Examples:
78
78
  };
79
79
 
80
80
  async function set(projectId, key, args = []) {
81
- let file = null;
82
- let value = null;
83
- for (let i = 0; i < args.length; i++) {
84
- if (args[i] === "--file" && args[i + 1]) { file = args[++i]; }
85
- else if (!value && !args[i].startsWith("--")) { value = args[i]; }
81
+ const parsedArgs = normalizeArgv(args);
82
+ const valueFlags = ["--file"];
83
+ assertKnownFlags(parsedArgs, [...valueFlags, "--help", "-h"], valueFlags);
84
+ const values = positionalArgs(parsedArgs, valueFlags);
85
+ if (values.length > 1) {
86
+ fail({ code: "BAD_USAGE", message: `Unexpected argument for secrets set: ${values[1]}` });
87
+ }
88
+ const file = flagValue(parsedArgs, "--file");
89
+ if (file && values.length > 0) {
90
+ fail({ code: "BAD_USAGE", message: "Provide either an inline value or --file, not both." });
86
91
  }
87
92
  if (file) validateRegularFile(file, "--file");
88
- const val = file ? readFileSync(file, "utf-8") : value;
89
- if (!val) {
93
+ const val = file ? readFileSync(file, "utf-8") : values.length === 1 ? values[0] : undefined;
94
+ if (val === undefined) {
90
95
  fail({
91
96
  code: "BAD_USAGE",
92
97
  message: "Missing secret value.",
@@ -101,7 +106,13 @@ async function set(projectId, key, args = []) {
101
106
  }
102
107
  }
103
108
 
104
- async function list(projectId) {
109
+ async function list(projectId, args = []) {
110
+ const parsedArgs = normalizeArgv(args);
111
+ assertKnownFlags(parsedArgs, ["--help", "-h"]);
112
+ const extra = positionalArgs(parsedArgs);
113
+ if (extra.length > 0) {
114
+ fail({ code: "BAD_USAGE", message: `Unexpected argument for secrets list: ${extra[0]}` });
115
+ }
105
116
  try {
106
117
  const data = await getSdk().secrets.list(projectId);
107
118
  const sanitized = {
@@ -117,7 +128,13 @@ async function list(projectId) {
117
128
  }
118
129
  }
119
130
 
120
- async function deleteSecret(projectId, key) {
131
+ async function deleteSecret(projectId, key, args = []) {
132
+ const parsedArgs = normalizeArgv(args);
133
+ assertKnownFlags(parsedArgs, ["--help", "-h"]);
134
+ const extra = positionalArgs(parsedArgs);
135
+ if (extra.length > 0) {
136
+ fail({ code: "BAD_USAGE", message: `Unexpected argument for secrets delete: ${extra[0]}` });
137
+ }
121
138
  try {
122
139
  await getSdk().secrets.delete(projectId, key);
123
140
  console.log(JSON.stringify({ status: "ok", message: `Secret '${key}' deleted.` }));
@@ -134,8 +151,8 @@ export async function run(sub, args) {
134
151
  }
135
152
  switch (sub) {
136
153
  case "set": await set(args[0], args[1], args.slice(2)); break;
137
- case "list": await list(args[0]); break;
138
- case "delete": await deleteSecret(args[0], args[1]); break;
154
+ case "list": await list(args[0], args.slice(1)); break;
155
+ case "delete": await deleteSecret(args[0], args[1], args.slice(2)); break;
139
156
  default:
140
157
  console.error(`Unknown subcommand: ${sub}\n`);
141
158
  console.log(HELP);
@@ -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, flagValue, normalizeArgv, positionalArgs } from "./argparse.mjs";
4
5
 
5
6
  const HELP = `run402 sender-domain — Manage custom email sender domain
6
7
 
@@ -100,18 +101,18 @@ Examples:
100
101
  };
101
102
 
102
103
  function parseFlag(args, flag) {
103
- for (let i = 0; i < args.length; i++) {
104
- if (args[i] === flag && args[i + 1]) return args[i + 1];
105
- }
106
- return null;
104
+ return flagValue(normalizeArgv(args), flag);
107
105
  }
108
106
 
109
107
  async function register(args) {
110
- let domain = null;
111
- let projectOpt = null;
112
- for (let i = 0; i < args.length; i++) {
113
- if (args[i] === "--project" && args[i + 1]) { projectOpt = args[++i]; }
114
- else if (!args[i].startsWith("--") && !domain) { domain = args[i]; }
108
+ const parsedArgs = normalizeArgv(args);
109
+ const valueFlags = ["--project"];
110
+ assertKnownFlags(parsedArgs, [...valueFlags, "--help", "-h"], valueFlags);
111
+ const positionals = positionalArgs(parsedArgs, valueFlags);
112
+ let domain = positionals[0] ?? null;
113
+ let projectOpt = flagValue(parsedArgs, "--project");
114
+ if (positionals.length > 1) {
115
+ fail({ code: "BAD_USAGE", message: `Unexpected argument for sender-domain register: ${positionals[1]}` });
115
116
  }
116
117
  const projectId = resolveProjectId(projectOpt);
117
118
 
@@ -132,6 +133,13 @@ async function register(args) {
132
133
  }
133
134
 
134
135
  async function status(args) {
136
+ const parsedArgs = normalizeArgv(args);
137
+ const valueFlags = ["--project"];
138
+ assertKnownFlags(parsedArgs, [...valueFlags, "--help", "-h"], valueFlags);
139
+ const extra = positionalArgs(parsedArgs, valueFlags);
140
+ if (extra.length > 0) {
141
+ fail({ code: "BAD_USAGE", message: `Unexpected argument for sender-domain status: ${extra[0]}` });
142
+ }
135
143
  const projectId = resolveProjectId(parseFlag(args, "--project"));
136
144
  try {
137
145
  const data = await getSdk().senderDomain.status(projectId);
@@ -142,6 +150,13 @@ async function status(args) {
142
150
  }
143
151
 
144
152
  async function remove(args) {
153
+ const parsedArgs = normalizeArgv(args);
154
+ const valueFlags = ["--project"];
155
+ assertKnownFlags(parsedArgs, [...valueFlags, "--help", "-h"], valueFlags);
156
+ const extra = positionalArgs(parsedArgs, valueFlags);
157
+ if (extra.length > 0) {
158
+ fail({ code: "BAD_USAGE", message: `Unexpected argument for sender-domain remove: ${extra[0]}` });
159
+ }
145
160
  const projectId = resolveProjectId(parseFlag(args, "--project"));
146
161
  try {
147
162
  await getSdk().senderDomain.remove(projectId);
@@ -152,11 +167,14 @@ async function remove(args) {
152
167
  }
153
168
 
154
169
  async function inboundToggle(action, args) {
155
- let domain = null;
156
- let projectOpt = null;
157
- for (let i = 0; i < args.length; i++) {
158
- if (args[i] === "--project" && args[i + 1]) { projectOpt = args[++i]; }
159
- else if (!args[i].startsWith("--") && !domain) { domain = args[i]; }
170
+ const parsedArgs = normalizeArgv(args);
171
+ const valueFlags = ["--project"];
172
+ assertKnownFlags(parsedArgs, [...valueFlags, "--help", "-h"], valueFlags);
173
+ const positionals = positionalArgs(parsedArgs, valueFlags);
174
+ let domain = positionals[0] ?? null;
175
+ let projectOpt = flagValue(parsedArgs, "--project");
176
+ if (positionals.length > 1) {
177
+ fail({ code: "BAD_USAGE", message: `Unexpected argument for sender-domain inbound-${action}: ${positionals[1]}` });
160
178
  }
161
179
  const projectId = resolveProjectId(projectOpt);
162
180
 
package/lib/sites.mjs CHANGED
@@ -6,6 +6,7 @@ import { allowanceAuthHeaders, resolveProjectId, updateProject } from "./config.
6
6
  import { resolveFilePathsInManifest } from "./manifest.mjs";
7
7
  import { getSdk } from "./sdk.mjs";
8
8
  import { reportSdkError, fail } from "./sdk-errors.mjs";
9
+ import { assertKnownFlags, flagValue, normalizeArgv, positionalArgs } from "./argparse.mjs";
9
10
 
10
11
  const SMALL_DIR_THRESHOLD = 5;
11
12
 
@@ -187,14 +188,25 @@ function failUnsupportedTarget() {
187
188
  }
188
189
 
189
190
  async function deploy(args) {
191
+ const parsedArgs = normalizeArgv(args);
192
+ const valueFlags = ["--manifest", "--project", "--target"];
193
+ assertKnownFlags(parsedArgs, [...valueFlags, "--quiet", "--inherit", "--help", "-h"], valueFlags);
194
+ const extra = positionalArgs(parsedArgs, valueFlags);
195
+ if (extra.length > 0) {
196
+ fail({
197
+ code: "BAD_USAGE",
198
+ message: `Unexpected argument for sites deploy: ${extra[0]}`,
199
+ hint: "Use `run402 sites deploy --manifest <file> [--project <id>]`.",
200
+ });
201
+ }
190
202
  const opts = { manifest: null, project: undefined, target: undefined, quiet: false };
191
- for (let i = 0; i < args.length; i++) {
192
- if (args[i] === "--help" || args[i] === "-h") { console.log(HELP); process.exit(0); }
193
- if (args[i] === "--manifest" && args[i + 1]) opts.manifest = args[++i];
194
- if (args[i] === "--project" && args[i + 1]) opts.project = args[++i];
195
- if (args[i] === "--target" && args[i + 1]) opts.target = args[++i];
196
- if (args[i] === "--quiet") opts.quiet = true;
197
- if (args[i] === "--inherit") {
203
+ opts.manifest = flagValue(parsedArgs, "--manifest");
204
+ opts.project = flagValue(parsedArgs, "--project") ?? undefined;
205
+ opts.target = flagValue(parsedArgs, "--target") ?? undefined;
206
+ opts.quiet = parsedArgs.includes("--quiet");
207
+ for (let i = 0; i < parsedArgs.length; i++) {
208
+ if (parsedArgs[i] === "--help" || parsedArgs[i] === "-h") { console.log(HELP); process.exit(0); }
209
+ if (parsedArgs[i] === "--inherit") {
198
210
  console.error(JSON.stringify({
199
211
  status: "error",
200
212
  message: "--inherit is removed; the SDK now uploads only changed files automatically.",
@@ -231,6 +243,17 @@ async function deploy(args) {
231
243
  }
232
244
 
233
245
  async function deployDir(args) {
246
+ const parsedArgs = normalizeArgv(args);
247
+ const valueFlags = ["--project", "--target"];
248
+ assertKnownFlags(parsedArgs, [...valueFlags, "--quiet", "--dry-run", "--confirm-prune", "--inherit", "--help", "-h"], valueFlags);
249
+ const positionals = positionalArgs(parsedArgs, valueFlags);
250
+ if (positionals.length > 1) {
251
+ fail({
252
+ code: "BAD_USAGE",
253
+ message: `Unexpected argument for sites deploy-dir: ${positionals[1]}`,
254
+ hint: "Use `run402 sites deploy-dir <path> --project <id>`.",
255
+ });
256
+ }
234
257
  const opts = {
235
258
  dir: null,
236
259
  project: undefined,
@@ -239,20 +262,20 @@ async function deployDir(args) {
239
262
  dryRun: false,
240
263
  confirmPrune: false,
241
264
  };
242
- for (let i = 0; i < args.length; i++) {
243
- if (args[i] === "--help" || args[i] === "-h") { console.log(SUB_HELP["deploy-dir"]); process.exit(0); }
244
- if (args[i] === "--project" && args[i + 1]) { opts.project = args[++i]; continue; }
245
- if (args[i] === "--target" && args[i + 1]) { opts.target = args[++i]; continue; }
246
- if (args[i] === "--quiet") { opts.quiet = true; continue; }
247
- if (args[i] === "--dry-run") { opts.dryRun = true; continue; }
248
- if (args[i] === "--confirm-prune") { opts.confirmPrune = true; continue; }
249
- if (args[i] === "--inherit") {
265
+ opts.dir = positionals[0] ?? null;
266
+ opts.project = flagValue(parsedArgs, "--project") ?? undefined;
267
+ opts.target = flagValue(parsedArgs, "--target") ?? undefined;
268
+ opts.quiet = parsedArgs.includes("--quiet");
269
+ opts.dryRun = parsedArgs.includes("--dry-run");
270
+ opts.confirmPrune = parsedArgs.includes("--confirm-prune");
271
+ for (let i = 0; i < parsedArgs.length; i++) {
272
+ if (parsedArgs[i] === "--help" || parsedArgs[i] === "-h") { console.log(SUB_HELP["deploy-dir"]); process.exit(0); }
273
+ if (parsedArgs[i] === "--inherit") {
250
274
  fail({
251
275
  code: "BAD_USAGE",
252
276
  message: "--inherit is removed; the SDK now uploads only changed files automatically.",
253
277
  });
254
278
  }
255
- if (!args[i].startsWith("-") && opts.dir === null) { opts.dir = args[i]; continue; }
256
279
  }
257
280
  if (!opts.dir) {
258
281
  fail({
@@ -1,6 +1,7 @@
1
1
  import { resolveProject, resolveProjectId } from "./config.mjs";
2
2
  import { getSdk } from "./sdk.mjs";
3
3
  import { reportSdkError, fail } from "./sdk-errors.mjs";
4
+ import { assertKnownFlags, flagValue, normalizeArgv, positionalArgs } from "./argparse.mjs";
4
5
 
5
6
  const HELP = `run402 subdomains — Manage custom subdomains
6
7
 
@@ -78,22 +79,25 @@ Examples:
78
79
  `,
79
80
  };
80
81
 
81
- async function claim(positionalArgs, flagArgs) {
82
- const opts = { project: null, deployment: null };
83
- for (let i = 0; i < flagArgs.length; i++) {
84
- if (flagArgs[i] === "--project" && flagArgs[i + 1]) opts.project = flagArgs[++i];
85
- if (flagArgs[i] === "--deployment" && flagArgs[i + 1]) opts.deployment = flagArgs[++i];
86
- }
82
+ async function claim(args) {
83
+ const parsedArgs = normalizeArgv(args);
84
+ const valueFlags = ["--project", "--deployment"];
85
+ assertKnownFlags(parsedArgs, [...valueFlags, "--help", "-h"], valueFlags);
86
+ const opts = {
87
+ project: flagValue(parsedArgs, "--project"),
88
+ deployment: flagValue(parsedArgs, "--deployment"),
89
+ };
87
90
  let name, deploymentId;
88
- if (positionalArgs.length > 1) {
91
+ const positionals = positionalArgs(parsedArgs, valueFlags);
92
+ if (positionals.length > 1) {
89
93
  fail({
90
94
  code: "BAD_USAGE",
91
- message: `Unexpected argument for subdomains claim: ${positionalArgs[1]}`,
95
+ message: `Unexpected argument for subdomains claim: ${positionals[1]}`,
92
96
  hint: "Use `run402 subdomains claim <name> --deployment <deployment_id>`.",
93
97
  });
94
98
  }
95
- if (positionalArgs.length === 1) {
96
- name = positionalArgs[0];
99
+ if (positionals.length === 1) {
100
+ name = positionals[0];
97
101
  }
98
102
  if (!name) {
99
103
  fail({
@@ -123,13 +127,12 @@ async function claim(positionalArgs, flagArgs) {
123
127
  }
124
128
 
125
129
  async function deleteSubdomain(allArgs) {
126
- const argList = Array.isArray(allArgs) ? allArgs : [];
127
- let opts = { project: null };
128
- let name = null;
129
- for (let i = 0; i < argList.length; i++) {
130
- if (argList[i] === "--project" && argList[i + 1]) { opts.project = argList[++i]; }
131
- else if (!argList[i].startsWith("--") && !name) { name = argList[i]; }
132
- }
130
+ const argList = normalizeArgv(Array.isArray(allArgs) ? allArgs : []);
131
+ const valueFlags = ["--project"];
132
+ assertKnownFlags(argList, [...valueFlags, "--confirm", "--help", "-h"], valueFlags);
133
+ const opts = { project: flagValue(argList, "--project") };
134
+ const positionals = positionalArgs(argList, valueFlags);
135
+ let name = positionals[0] ?? null;
133
136
  if (!name) {
134
137
  fail({
135
138
  code: "BAD_USAGE",
@@ -137,6 +140,9 @@ async function deleteSubdomain(allArgs) {
137
140
  hint: "run402 subdomains delete <name> --confirm [--project <id>]",
138
141
  });
139
142
  }
143
+ if (positionals.length > 1) {
144
+ fail({ code: "BAD_USAGE", message: `Unexpected argument for subdomains delete: ${positionals[1]}` });
145
+ }
140
146
  if (!argList.includes("--confirm")) {
141
147
  fail({
142
148
  code: "CONFIRMATION_REQUIRED",
@@ -154,13 +160,13 @@ async function deleteSubdomain(allArgs) {
154
160
  }
155
161
 
156
162
  function parseProjectFlag(args) {
157
- let project = null;
158
- const rest = [];
159
- for (let i = 0; i < args.length; i++) {
160
- if (args[i] === "--project" && args[i + 1]) { project = args[++i]; }
161
- else { rest.push(args[i]); }
162
- }
163
- return { project, rest };
163
+ const parsedArgs = normalizeArgv(args);
164
+ const valueFlags = ["--project"];
165
+ assertKnownFlags(parsedArgs, [...valueFlags, "--help", "-h"], valueFlags);
166
+ return {
167
+ project: flagValue(parsedArgs, "--project"),
168
+ rest: positionalArgs(parsedArgs, valueFlags),
169
+ };
164
170
  }
165
171
 
166
172
  async function list(args) {
@@ -186,17 +192,7 @@ export async function run(sub, args) {
186
192
  if (!sub || sub === '--help' || sub === '-h') { console.log(HELP); process.exit(0); }
187
193
  if (Array.isArray(args) && (args.includes("--help") || args.includes("-h"))) { console.log(SUB_HELP[sub] || HELP); process.exit(0); }
188
194
  switch (sub) {
189
- case "claim": {
190
- const positional = [];
191
- const flags = [];
192
- let i = 0;
193
- while (i < args.length) {
194
- if (args[i].startsWith("--")) { flags.push(args[i], args[i + 1]); i += 2; }
195
- else { positional.push(args[i]); i++; }
196
- }
197
- await claim(positional, flags);
198
- break;
199
- }
195
+ case "claim": await claim(args); break;
200
196
  case "delete": await deleteSubdomain(args); break;
201
197
  case "list": await list(args); break;
202
198
  default: