run402 1.69.5 → 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/contracts.mjs CHANGED
@@ -1,5 +1,13 @@
1
1
  import { getSdk } from "./sdk.mjs";
2
2
  import { reportSdkError, fail, parseFlagJson } from "./sdk-errors.mjs";
3
+ import {
4
+ assertAllowedValue,
5
+ assertKnownFlags,
6
+ flagValue,
7
+ normalizeArgv,
8
+ positionalArgs,
9
+ validateEvmAddress,
10
+ } from "./argparse.mjs";
3
11
 
4
12
  const HELP = `run402 contracts — KMS-backed Ethereum wallets for smart-contract calls
5
13
 
@@ -126,12 +134,6 @@ Examples:
126
134
  `,
127
135
  };
128
136
 
129
- function parseFlag(args, flag) {
130
- for (let i = 0; i < args.length; i++) {
131
- if (args[i] === flag && args[i + 1]) return args[i + 1];
132
- }
133
- return null;
134
- }
135
137
  function hasFlag(args, flag) {
136
138
  return args.includes(flag);
137
139
  }
@@ -146,21 +148,30 @@ function validateWeiFlag(flag, value) {
146
148
  }
147
149
 
148
150
  async function provisionWallet(projectId, args) {
149
- const chain = parseFlag(args, "--chain");
151
+ const parsedArgs = normalizeArgv(args);
152
+ const valueFlags = ["--chain", "--recovery"];
153
+ assertKnownFlags(parsedArgs, [...valueFlags, "--yes", "--help", "-h"], valueFlags);
154
+ const extra = positionalArgs(parsedArgs, valueFlags);
155
+ if (extra.length > 0) {
156
+ fail({ code: "BAD_USAGE", message: `Unexpected argument for contracts provision-wallet: ${extra[0]}` });
157
+ }
158
+ const chain = flagValue(parsedArgs, "--chain");
150
159
  if (!chain) {
151
160
  fail({
152
161
  code: "BAD_USAGE",
153
162
  message: "Missing --chain (base-mainnet or base-sepolia)",
154
163
  });
155
164
  }
156
- const recovery = parseFlag(args, "--recovery");
165
+ assertAllowedValue(chain, ["base-mainnet", "base-sepolia"], "--chain");
166
+ const recovery = flagValue(parsedArgs, "--recovery");
167
+ if (recovery) validateEvmAddress(recovery, "--recovery");
157
168
  // Soft default of one wallet — confirm if project already has one.
158
169
  let activeWallets = null;
159
170
  try {
160
171
  const list = await getSdk().contracts.listWallets(projectId);
161
172
  activeWallets = (list.wallets || []).filter((w) => w.status === "active").length;
162
173
  } catch { /* best-effort */ }
163
- if (activeWallets !== null && activeWallets >= 1 && !hasFlag(args, "--yes")) {
174
+ if (activeWallets !== null && activeWallets >= 1 && !hasFlag(parsedArgs, "--yes")) {
164
175
  fail({
165
176
  code: "CONFIRMATION_REQUIRED",
166
177
  message: `This project already has ${activeWallets} active wallet(s). Adding another costs $0.04/day each ($1.20/month). Re-run with --yes to confirm.`,
@@ -179,7 +190,13 @@ async function provisionWallet(projectId, args) {
179
190
  }
180
191
  }
181
192
 
182
- async function getWallet(projectId, walletId) {
193
+ async function getWallet(projectId, walletId, args = []) {
194
+ const parsedArgs = normalizeArgv(args);
195
+ assertKnownFlags(parsedArgs, ["--help", "-h"]);
196
+ const extra = positionalArgs(parsedArgs);
197
+ if (extra.length > 0) {
198
+ fail({ code: "BAD_USAGE", message: `Unexpected argument for contracts get-wallet: ${extra[0]}` });
199
+ }
183
200
  try {
184
201
  const data = await getSdk().contracts.getWallet(projectId, walletId);
185
202
  console.log(JSON.stringify(data, null, 2));
@@ -188,7 +205,13 @@ async function getWallet(projectId, walletId) {
188
205
  }
189
206
  }
190
207
 
191
- async function listWallets(projectId) {
208
+ async function listWallets(projectId, args = []) {
209
+ const parsedArgs = normalizeArgv(args);
210
+ assertKnownFlags(parsedArgs, ["--help", "-h"]);
211
+ const extra = positionalArgs(parsedArgs);
212
+ if (extra.length > 0) {
213
+ fail({ code: "BAD_USAGE", message: `Unexpected argument for contracts list-wallets: ${extra[0]}` });
214
+ }
192
215
  try {
193
216
  const data = await getSdk().contracts.listWallets(projectId);
194
217
  console.log(JSON.stringify(data, null, 2));
@@ -198,14 +221,25 @@ async function listWallets(projectId) {
198
221
  }
199
222
 
200
223
  async function setRecovery(projectId, walletId, args) {
201
- const clear = hasFlag(args, "--clear");
202
- const address = parseFlag(args, "--address");
224
+ const parsedArgs = normalizeArgv(args);
225
+ const valueFlags = ["--address"];
226
+ assertKnownFlags(parsedArgs, [...valueFlags, "--clear", "--help", "-h"], valueFlags);
227
+ const extra = positionalArgs(parsedArgs, valueFlags);
228
+ if (extra.length > 0) {
229
+ fail({ code: "BAD_USAGE", message: `Unexpected argument for contracts set-recovery: ${extra[0]}` });
230
+ }
231
+ const clear = hasFlag(parsedArgs, "--clear");
232
+ const address = flagValue(parsedArgs, "--address");
233
+ if (clear && address) {
234
+ fail({ code: "BAD_USAGE", message: "Provide either --address or --clear, not both." });
235
+ }
203
236
  if (!clear && !address) {
204
237
  fail({
205
238
  code: "BAD_USAGE",
206
239
  message: "Provide --address 0x... or --clear",
207
240
  });
208
241
  }
242
+ if (address) validateEvmAddress(address, "--address");
209
243
  try {
210
244
  await getSdk().contracts.setRecovery(projectId, walletId, clear ? null : address);
211
245
  console.log(JSON.stringify({ status: "ok", wallet_id: walletId, recovery_address: clear ? null : address }));
@@ -215,7 +249,14 @@ async function setRecovery(projectId, walletId, args) {
215
249
  }
216
250
 
217
251
  async function setAlert(projectId, walletId, args) {
218
- const threshold = parseFlag(args, "--threshold-wei");
252
+ const parsedArgs = normalizeArgv(args);
253
+ const valueFlags = ["--threshold-wei"];
254
+ assertKnownFlags(parsedArgs, [...valueFlags, "--help", "-h"], valueFlags);
255
+ const extra = positionalArgs(parsedArgs, valueFlags);
256
+ if (extra.length > 0) {
257
+ fail({ code: "BAD_USAGE", message: `Unexpected argument for contracts set-alert: ${extra[0]}` });
258
+ }
259
+ const threshold = flagValue(parsedArgs, "--threshold-wei");
219
260
  if (!threshold) {
220
261
  fail({ code: "BAD_USAGE", message: "Missing --threshold-wei <n>" });
221
262
  }
@@ -229,13 +270,20 @@ async function setAlert(projectId, walletId, args) {
229
270
  }
230
271
 
231
272
  async function call(projectId, walletId, args) {
232
- const to = parseFlag(args, "--to");
233
- const abi = parseFlag(args, "--abi");
234
- const fn = parseFlag(args, "--fn");
235
- const argsJson = parseFlag(args, "--args");
236
- const value = parseFlag(args, "--value-wei");
237
- const chain = parseFlag(args, "--chain") || "base-mainnet";
238
- const idempotency = parseFlag(args, "--idempotency-key");
273
+ const parsedArgs = normalizeArgv(args);
274
+ const valueFlags = ["--to", "--abi", "--fn", "--args", "--value-wei", "--chain", "--idempotency-key"];
275
+ assertKnownFlags(parsedArgs, [...valueFlags, "--help", "-h"], valueFlags);
276
+ const extra = positionalArgs(parsedArgs, valueFlags);
277
+ if (extra.length > 0) {
278
+ fail({ code: "BAD_USAGE", message: `Unexpected argument for contracts call: ${extra[0]}` });
279
+ }
280
+ const to = flagValue(parsedArgs, "--to");
281
+ const abi = flagValue(parsedArgs, "--abi");
282
+ const fn = flagValue(parsedArgs, "--fn");
283
+ const argsJson = flagValue(parsedArgs, "--args");
284
+ const value = flagValue(parsedArgs, "--value-wei");
285
+ const chain = flagValue(parsedArgs, "--chain") || "base-mainnet";
286
+ const idempotency = flagValue(parsedArgs, "--idempotency-key");
239
287
  if (!to || !abi || !fn || !argsJson) {
240
288
  fail({
241
289
  code: "BAD_USAGE",
@@ -243,9 +291,11 @@ async function call(projectId, walletId, args) {
243
291
  hint: "Cost: chain gas + $0.000005 KMS sign fee.",
244
292
  });
245
293
  }
294
+ assertAllowedValue(chain, ["base-mainnet", "base-sepolia"], "--chain");
246
295
  if (value !== null) validateWeiFlag("--value-wei", value);
247
296
  const abiFragment = parseFlagJson("--abi", abi);
248
297
  const callArgs = parseFlagJson("--args", argsJson);
298
+ validateEvmAddress(to, "--to");
249
299
  try {
250
300
  const data = await getSdk().contracts.call(projectId, {
251
301
  walletId,
@@ -264,19 +314,28 @@ async function call(projectId, walletId, args) {
264
314
  }
265
315
 
266
316
  async function read(args) {
267
- const chain = parseFlag(args, "--chain");
268
- const to = parseFlag(args, "--to");
269
- const abi = parseFlag(args, "--abi");
270
- const fn = parseFlag(args, "--fn");
271
- const argsJson = parseFlag(args, "--args");
317
+ const parsedArgs = normalizeArgv(args);
318
+ const valueFlags = ["--chain", "--to", "--abi", "--fn", "--args"];
319
+ assertKnownFlags(parsedArgs, [...valueFlags, "--help", "-h"], valueFlags);
320
+ const extra = positionalArgs(parsedArgs, valueFlags);
321
+ if (extra.length > 0) {
322
+ fail({ code: "BAD_USAGE", message: `Unexpected argument for contracts read: ${extra[0]}` });
323
+ }
324
+ const chain = flagValue(parsedArgs, "--chain");
325
+ const to = flagValue(parsedArgs, "--to");
326
+ const abi = flagValue(parsedArgs, "--abi");
327
+ const fn = flagValue(parsedArgs, "--fn");
328
+ const argsJson = flagValue(parsedArgs, "--args");
272
329
  if (!chain || !to || !abi || !fn || !argsJson) {
273
330
  fail({
274
331
  code: "BAD_USAGE",
275
332
  message: "Required flags: --chain, --to, --abi, --fn, --args",
276
333
  });
277
334
  }
335
+ assertAllowedValue(chain, ["base-mainnet", "base-sepolia"], "--chain");
278
336
  const abiFragment = parseFlagJson("--abi", abi);
279
337
  const callArgs = parseFlagJson("--args", argsJson);
338
+ validateEvmAddress(to, "--to");
280
339
  try {
281
340
  const data = await getSdk().contracts.read({
282
341
  chain,
@@ -291,7 +350,13 @@ async function read(args) {
291
350
  }
292
351
  }
293
352
 
294
- async function status(projectId, callId) {
353
+ async function status(projectId, callId, args = []) {
354
+ const parsedArgs = normalizeArgv(args);
355
+ assertKnownFlags(parsedArgs, ["--help", "-h"]);
356
+ const extra = positionalArgs(parsedArgs);
357
+ if (extra.length > 0) {
358
+ fail({ code: "BAD_USAGE", message: `Unexpected argument for contracts status: ${extra[0]}` });
359
+ }
295
360
  try {
296
361
  const data = await getSdk().contracts.callStatus(projectId, callId);
297
362
  console.log(JSON.stringify(data, null, 2));
@@ -301,14 +366,22 @@ async function status(projectId, callId) {
301
366
  }
302
367
 
303
368
  async function drain(projectId, walletId, args) {
304
- const to = parseFlag(args, "--to");
305
- if (!to || !hasFlag(args, "--confirm")) {
369
+ const parsedArgs = normalizeArgv(args);
370
+ const valueFlags = ["--to"];
371
+ assertKnownFlags(parsedArgs, [...valueFlags, "--confirm", "--help", "-h"], valueFlags);
372
+ const extra = positionalArgs(parsedArgs, valueFlags);
373
+ if (extra.length > 0) {
374
+ fail({ code: "BAD_USAGE", message: `Unexpected argument for contracts drain: ${extra[0]}` });
375
+ }
376
+ const to = flagValue(parsedArgs, "--to");
377
+ if (!to || !hasFlag(parsedArgs, "--confirm")) {
306
378
  fail({
307
379
  code: "BAD_USAGE",
308
380
  message: "Required: --to 0x... and --confirm.",
309
381
  hint: "Cost: chain gas + $0.000005 KMS sign fee.",
310
382
  });
311
383
  }
384
+ validateEvmAddress(to, "--to");
312
385
  try {
313
386
  const data = await getSdk().contracts.drain(projectId, walletId, to);
314
387
  console.log(JSON.stringify(data, null, 2));
@@ -318,7 +391,13 @@ async function drain(projectId, walletId, args) {
318
391
  }
319
392
 
320
393
  async function deleteWallet(projectId, walletId, args) {
321
- if (!hasFlag(args, "--confirm")) {
394
+ const parsedArgs = normalizeArgv(args);
395
+ assertKnownFlags(parsedArgs, ["--confirm", "--help", "-h"]);
396
+ const extra = positionalArgs(parsedArgs);
397
+ if (extra.length > 0) {
398
+ fail({ code: "BAD_USAGE", message: `Unexpected argument for contracts delete: ${extra[0]}` });
399
+ }
400
+ if (!hasFlag(parsedArgs, "--confirm")) {
322
401
  fail({ code: "BAD_USAGE", message: "Required: --confirm" });
323
402
  }
324
403
  try {
@@ -334,13 +413,13 @@ export async function run(sub, args) {
334
413
  if (Array.isArray(args) && (args.includes("--help") || args.includes("-h"))) { console.log(SUB_HELP[sub] || HELP); process.exit(0); }
335
414
  switch (sub) {
336
415
  case "provision-wallet": await provisionWallet(args[0], args.slice(1)); break;
337
- case "get-wallet": await getWallet(args[0], args[1]); break;
338
- case "list-wallets": await listWallets(args[0]); break;
416
+ case "get-wallet": await getWallet(args[0], args[1], args.slice(2)); break;
417
+ case "list-wallets": await listWallets(args[0], args.slice(1)); break;
339
418
  case "set-recovery": await setRecovery(args[0], args[1], args.slice(2)); break;
340
419
  case "set-alert": await setAlert(args[0], args[1], args.slice(2)); break;
341
420
  case "call": await call(args[0], args[1], args.slice(2)); break;
342
421
  case "read": await read(args); break;
343
- case "status": await status(args[0], args[1]); break;
422
+ case "status": await status(args[0], args[1], args.slice(2)); break;
344
423
  case "drain": await drain(args[0], args[1], args.slice(2)); break;
345
424
  case "delete": await deleteWallet(args[0], args[1], args.slice(2)); break;
346
425
  default:
package/lib/domains.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, flagValue, normalizeArgv, positionalArgs } from "./argparse.mjs";
4
5
 
5
6
  const HELP = `run402 domains — Manage custom domains
6
7
 
@@ -94,14 +95,15 @@ Examples:
94
95
  `,
95
96
  };
96
97
 
97
- function parseProjectFlag(args) {
98
- let project = null;
99
- const rest = [];
100
- for (let i = 0; i < args.length; i++) {
101
- if (args[i] === "--project" && args[i + 1]) { project = args[++i]; }
102
- else { rest.push(args[i]); }
103
- }
104
- return { project, rest };
98
+ function parseProjectFlag(args, extraKnown = []) {
99
+ const parsedArgs = normalizeArgv(args);
100
+ const valueFlags = ["--project"];
101
+ assertKnownFlags(parsedArgs, [...valueFlags, ...extraKnown, "--help", "-h"], valueFlags);
102
+ return {
103
+ project: flagValue(parsedArgs, "--project"),
104
+ rest: positionalArgs(parsedArgs, valueFlags),
105
+ args: parsedArgs,
106
+ };
105
107
  }
106
108
 
107
109
  async function add(args) {
@@ -115,6 +117,9 @@ async function add(args) {
115
117
  hint: "run402 domains add <domain> <subdomain_name> [--project <id>]",
116
118
  });
117
119
  }
120
+ if (rest.length > 2) {
121
+ fail({ code: "BAD_USAGE", message: `Unexpected argument for domains add: ${rest[2]}` });
122
+ }
118
123
  const projectId = resolveProjectId(project);
119
124
  try {
120
125
  const data = await getSdk().domains.add(projectId, domain, subdomainName);
@@ -153,6 +158,9 @@ async function status(args) {
153
158
  hint: "run402 domains status <domain> [--project <id>]",
154
159
  });
155
160
  }
161
+ if (rest.length > 1) {
162
+ fail({ code: "BAD_USAGE", message: `Unexpected argument for domains status: ${rest[1]}` });
163
+ }
156
164
  const projectId = resolveProjectId(project);
157
165
  try {
158
166
  const data = await getSdk().domains.status(projectId, domain);
@@ -163,8 +171,8 @@ async function status(args) {
163
171
  }
164
172
 
165
173
  async function deleteDomain(args) {
166
- const { project, rest } = parseProjectFlag(args);
167
- const domain = rest.find((a) => !a.startsWith("--"));
174
+ const { project, rest, args: parsedArgs } = parseProjectFlag(args, ["--confirm"]);
175
+ const domain = rest[0];
168
176
  if (!domain) {
169
177
  fail({
170
178
  code: "BAD_USAGE",
@@ -172,7 +180,10 @@ async function deleteDomain(args) {
172
180
  hint: "run402 domains delete <domain> --confirm [--project <id>]",
173
181
  });
174
182
  }
175
- if (!Array.isArray(args) || !args.includes("--confirm")) {
183
+ if (rest.length > 1) {
184
+ fail({ code: "BAD_USAGE", message: `Unexpected argument for domains delete: ${rest[1]}` });
185
+ }
186
+ if (!parsedArgs.includes("--confirm")) {
176
187
  fail({
177
188
  code: "CONFIRMATION_REQUIRED",
178
189
  message: `Destructive: releasing custom domain '${domain}' detaches it from this project and clears its DNS/SSL configuration. This is irreversible. Re-run with --confirm to proceed.`,
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