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/billing.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { getSdk } from "./sdk.mjs";
|
|
2
2
|
import { reportSdkError, fail } from "./sdk-errors.mjs";
|
|
3
|
+
import { assertKnownFlags, flagValue, normalizeArgv, parseIntegerFlag, positionalArgs } from "./argparse.mjs";
|
|
3
4
|
|
|
4
5
|
const HELP = `run402 billing — Email billing accounts, Stripe tier checkout, email packs
|
|
5
6
|
|
|
@@ -121,15 +122,31 @@ Examples:
|
|
|
121
122
|
`,
|
|
122
123
|
};
|
|
123
124
|
|
|
124
|
-
function
|
|
125
|
-
|
|
126
|
-
|
|
125
|
+
function requireSingleBillingIdentifier(email, wallet) {
|
|
126
|
+
if (email && wallet) {
|
|
127
|
+
fail({
|
|
128
|
+
code: "BAD_USAGE",
|
|
129
|
+
message: "Provide either --email or --wallet, not both.",
|
|
130
|
+
hint: "[--email <e> | --wallet <w>]",
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
if (!email && !wallet) {
|
|
134
|
+
fail({
|
|
135
|
+
code: "BAD_USAGE",
|
|
136
|
+
message: "Must provide --email or --wallet",
|
|
137
|
+
hint: "[--email <e> | --wallet <w>]",
|
|
138
|
+
});
|
|
127
139
|
}
|
|
128
|
-
return null;
|
|
129
140
|
}
|
|
130
141
|
|
|
131
142
|
async function createEmail(args) {
|
|
132
|
-
const
|
|
143
|
+
const parsedArgs = normalizeArgv(args);
|
|
144
|
+
assertKnownFlags(parsedArgs, ["--help", "-h"]);
|
|
145
|
+
const positionals = positionalArgs(parsedArgs);
|
|
146
|
+
const email = positionals[0];
|
|
147
|
+
if (positionals.length > 1) {
|
|
148
|
+
fail({ code: "BAD_USAGE", message: `Unexpected argument for billing create-email: ${positionals[1]}` });
|
|
149
|
+
}
|
|
133
150
|
if (!email) {
|
|
134
151
|
fail({
|
|
135
152
|
code: "BAD_USAGE",
|
|
@@ -146,8 +163,14 @@ async function createEmail(args) {
|
|
|
146
163
|
}
|
|
147
164
|
|
|
148
165
|
async function linkWallet(args) {
|
|
149
|
-
const
|
|
150
|
-
|
|
166
|
+
const parsedArgs = normalizeArgv(args);
|
|
167
|
+
assertKnownFlags(parsedArgs, ["--help", "-h"]);
|
|
168
|
+
const positionals = positionalArgs(parsedArgs);
|
|
169
|
+
const accountId = positionals[0];
|
|
170
|
+
const wallet = positionals[1];
|
|
171
|
+
if (positionals.length > 2) {
|
|
172
|
+
fail({ code: "BAD_USAGE", message: `Unexpected argument for billing link-wallet: ${positionals[2]}` });
|
|
173
|
+
}
|
|
151
174
|
if (!accountId || !wallet) {
|
|
152
175
|
fail({
|
|
153
176
|
code: "BAD_USAGE",
|
|
@@ -164,7 +187,14 @@ async function linkWallet(args) {
|
|
|
164
187
|
}
|
|
165
188
|
|
|
166
189
|
async function tierCheckout(args) {
|
|
167
|
-
const
|
|
190
|
+
const parsedArgs = normalizeArgv(args);
|
|
191
|
+
const valueFlags = ["--email", "--wallet"];
|
|
192
|
+
assertKnownFlags(parsedArgs, [...valueFlags, "--help", "-h"], valueFlags);
|
|
193
|
+
const positionals = positionalArgs(parsedArgs, valueFlags);
|
|
194
|
+
const tier = positionals[0];
|
|
195
|
+
if (positionals.length > 1) {
|
|
196
|
+
fail({ code: "BAD_USAGE", message: `Unexpected argument for billing tier-checkout: ${positionals[1]}` });
|
|
197
|
+
}
|
|
168
198
|
if (!tier) {
|
|
169
199
|
fail({
|
|
170
200
|
code: "BAD_USAGE",
|
|
@@ -172,11 +202,9 @@ async function tierCheckout(args) {
|
|
|
172
202
|
hint: "run402 billing tier-checkout <tier> [--email <e> | --wallet <w>]",
|
|
173
203
|
});
|
|
174
204
|
}
|
|
175
|
-
const email =
|
|
176
|
-
const wallet =
|
|
177
|
-
|
|
178
|
-
fail({ code: "BAD_USAGE", message: "Must provide --email or --wallet" });
|
|
179
|
-
}
|
|
205
|
+
const email = flagValue(parsedArgs, "--email");
|
|
206
|
+
const wallet = flagValue(parsedArgs, "--wallet");
|
|
207
|
+
requireSingleBillingIdentifier(email, wallet);
|
|
180
208
|
try {
|
|
181
209
|
const data = await getSdk().billing.tierCheckout(tier, { email: email ?? undefined, wallet: wallet ?? undefined });
|
|
182
210
|
console.log(JSON.stringify(data, null, 2));
|
|
@@ -186,11 +214,16 @@ async function tierCheckout(args) {
|
|
|
186
214
|
}
|
|
187
215
|
|
|
188
216
|
async function buyPack(args) {
|
|
189
|
-
const
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
|
|
217
|
+
const parsedArgs = normalizeArgv(args);
|
|
218
|
+
const valueFlags = ["--email", "--wallet"];
|
|
219
|
+
assertKnownFlags(parsedArgs, [...valueFlags, "--help", "-h"], valueFlags);
|
|
220
|
+
const extra = positionalArgs(parsedArgs, valueFlags);
|
|
221
|
+
if (extra.length > 0) {
|
|
222
|
+
fail({ code: "BAD_USAGE", message: `Unexpected argument for billing buy-email-pack: ${extra[0]}` });
|
|
193
223
|
}
|
|
224
|
+
const email = flagValue(parsedArgs, "--email");
|
|
225
|
+
const wallet = flagValue(parsedArgs, "--wallet");
|
|
226
|
+
requireSingleBillingIdentifier(email, wallet);
|
|
194
227
|
try {
|
|
195
228
|
const data = await getSdk().billing.buyEmailPack({ email: email ?? undefined, wallet: wallet ?? undefined });
|
|
196
229
|
console.log(JSON.stringify(data, null, 2));
|
|
@@ -200,8 +233,15 @@ async function buyPack(args) {
|
|
|
200
233
|
}
|
|
201
234
|
|
|
202
235
|
async function autoRecharge(args) {
|
|
203
|
-
const
|
|
204
|
-
const
|
|
236
|
+
const parsedArgs = normalizeArgv(args);
|
|
237
|
+
const valueFlags = ["--threshold"];
|
|
238
|
+
assertKnownFlags(parsedArgs, [...valueFlags, "--help", "-h"], valueFlags);
|
|
239
|
+
const positionals = positionalArgs(parsedArgs, valueFlags);
|
|
240
|
+
const accountId = positionals[0];
|
|
241
|
+
const state = positionals[1];
|
|
242
|
+
if (positionals.length > 2) {
|
|
243
|
+
fail({ code: "BAD_USAGE", message: `Unexpected argument for billing auto-recharge: ${positionals[2]}` });
|
|
244
|
+
}
|
|
205
245
|
if (!accountId || !state || !["on", "off"].includes(state)) {
|
|
206
246
|
fail({
|
|
207
247
|
code: "BAD_USAGE",
|
|
@@ -209,12 +249,15 @@ async function autoRecharge(args) {
|
|
|
209
249
|
hint: "run402 billing auto-recharge <account_id> <on|off> [--threshold <n>]",
|
|
210
250
|
});
|
|
211
251
|
}
|
|
212
|
-
const thresholdStr =
|
|
252
|
+
const thresholdStr = flagValue(parsedArgs, "--threshold");
|
|
253
|
+
const threshold = parsedArgs.includes("--threshold")
|
|
254
|
+
? parseIntegerFlag("--threshold", thresholdStr, { min: 0 })
|
|
255
|
+
: undefined;
|
|
213
256
|
try {
|
|
214
257
|
await getSdk().billing.setAutoRecharge({
|
|
215
258
|
billingAccountId: accountId,
|
|
216
259
|
enabled: state === "on",
|
|
217
|
-
threshold
|
|
260
|
+
threshold,
|
|
218
261
|
});
|
|
219
262
|
console.log(JSON.stringify({ status: "ok", billing_account_id: accountId, enabled: state === "on" }));
|
|
220
263
|
} catch (err) {
|
|
@@ -223,7 +266,13 @@ async function autoRecharge(args) {
|
|
|
223
266
|
}
|
|
224
267
|
|
|
225
268
|
async function balance(args) {
|
|
226
|
-
const
|
|
269
|
+
const parsedArgs = normalizeArgv(args);
|
|
270
|
+
assertKnownFlags(parsedArgs, ["--help", "-h"]);
|
|
271
|
+
const positionals = positionalArgs(parsedArgs);
|
|
272
|
+
const id = positionals[0];
|
|
273
|
+
if (positionals.length > 1) {
|
|
274
|
+
fail({ code: "BAD_USAGE", message: `Unexpected argument for billing balance: ${positionals[1]}` });
|
|
275
|
+
}
|
|
227
276
|
if (!id) {
|
|
228
277
|
fail({
|
|
229
278
|
code: "BAD_USAGE",
|
|
@@ -240,7 +289,14 @@ async function balance(args) {
|
|
|
240
289
|
}
|
|
241
290
|
|
|
242
291
|
async function history(args) {
|
|
243
|
-
const
|
|
292
|
+
const parsedArgs = normalizeArgv(args);
|
|
293
|
+
const valueFlags = ["--limit"];
|
|
294
|
+
assertKnownFlags(parsedArgs, [...valueFlags, "--help", "-h"], valueFlags);
|
|
295
|
+
const positionals = positionalArgs(parsedArgs, valueFlags);
|
|
296
|
+
const id = positionals[0];
|
|
297
|
+
if (positionals.length > 1) {
|
|
298
|
+
fail({ code: "BAD_USAGE", message: `Unexpected argument for billing history: ${positionals[1]}` });
|
|
299
|
+
}
|
|
244
300
|
if (!id) {
|
|
245
301
|
fail({
|
|
246
302
|
code: "BAD_USAGE",
|
|
@@ -248,9 +304,11 @@ async function history(args) {
|
|
|
248
304
|
hint: "run402 billing history <email-or-wallet> [--limit <n>]",
|
|
249
305
|
});
|
|
250
306
|
}
|
|
251
|
-
const limit =
|
|
307
|
+
const limit = parsedArgs.includes("--limit")
|
|
308
|
+
? parseIntegerFlag("--limit", flagValue(parsedArgs, "--limit"), { min: 1 })
|
|
309
|
+
: 50;
|
|
252
310
|
try {
|
|
253
|
-
const data = await getSdk().billing.getHistory(id,
|
|
311
|
+
const data = await getSdk().billing.getHistory(id, limit);
|
|
254
312
|
console.log(JSON.stringify(data, null, 2));
|
|
255
313
|
} catch (err) {
|
|
256
314
|
reportSdkError(err);
|
package/lib/blob.mjs
CHANGED
|
@@ -438,8 +438,8 @@ async function put(projectId, argv) {
|
|
|
438
438
|
const resolvedId = resolveProjectId(opts.project);
|
|
439
439
|
|
|
440
440
|
if (opts.positional.length === 0) die("At least one file path is required");
|
|
441
|
-
if (opts.
|
|
442
|
-
die("--key
|
|
441
|
+
if (opts.positional.length > 1 && opts.key && !opts.key.endsWith("/")) {
|
|
442
|
+
die("--key across multiple files requires a directory prefix (ending with /)");
|
|
443
443
|
}
|
|
444
444
|
|
|
445
445
|
const results = [];
|
package/lib/cdn.mjs
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
import { resolveProjectId } from "./config.mjs";
|
|
17
17
|
import { getSdk } from "./sdk.mjs";
|
|
18
18
|
import { reportSdkError, fail } from "./sdk-errors.mjs";
|
|
19
|
+
import { assertKnownFlags, flagValue, normalizeArgv, parseIntegerFlag, positionalArgs } from "./argparse.mjs";
|
|
19
20
|
|
|
20
21
|
const HELP = `run402 cdn — CloudFront CDN diagnostics for public blob URLs
|
|
21
22
|
|
|
@@ -73,14 +74,19 @@ function die(msg, exit_code = 1) {
|
|
|
73
74
|
}
|
|
74
75
|
|
|
75
76
|
function parseArgs(args) {
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
77
|
+
const normalized = normalizeArgv(args);
|
|
78
|
+
const valueFlags = ["--sha", "--timeout", "--project"];
|
|
79
|
+
assertKnownFlags(normalized, [...valueFlags, "--help", "-h"], valueFlags);
|
|
80
|
+
const opts = {
|
|
81
|
+
positional: positionalArgs(normalized, valueFlags),
|
|
82
|
+
sha: flagValue(normalized, "--sha"),
|
|
83
|
+
timeout: normalized.includes("--timeout")
|
|
84
|
+
? parseIntegerFlag("--timeout", flagValue(normalized, "--timeout"), { min: 1 })
|
|
85
|
+
: undefined,
|
|
86
|
+
project: flagValue(normalized, "--project"),
|
|
87
|
+
};
|
|
88
|
+
if (opts.positional.length > 1) {
|
|
89
|
+
die(`Unexpected argument for cdn wait-fresh: ${opts.positional[1]}`);
|
|
84
90
|
}
|
|
85
91
|
return opts;
|
|
86
92
|
}
|
|
@@ -92,6 +98,13 @@ async function waitFresh(projectId, argv) {
|
|
|
92
98
|
if (opts.positional.length === 0) die("URL required");
|
|
93
99
|
const url = opts.positional[0];
|
|
94
100
|
if (!opts.sha) die("--sha is required");
|
|
101
|
+
if (!/^[a-fA-F0-9]{64}$/.test(opts.sha)) {
|
|
102
|
+
fail({
|
|
103
|
+
code: "BAD_FLAG",
|
|
104
|
+
message: "--sha must be a 64-character hex SHA-256 digest",
|
|
105
|
+
details: { flag: "--sha", value: opts.sha },
|
|
106
|
+
});
|
|
107
|
+
}
|
|
95
108
|
|
|
96
109
|
const timeoutMs = (opts.timeout ?? 60) * 1000;
|
|
97
110
|
try {
|
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,32 +134,44 @@ 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
|
}
|
|
140
|
+
function validateWeiFlag(flag, value) {
|
|
141
|
+
if (!/^\d+$/.test(String(value))) {
|
|
142
|
+
fail({
|
|
143
|
+
code: "BAD_FLAG",
|
|
144
|
+
message: `${flag} must be a decimal non-negative integer string in wei`,
|
|
145
|
+
details: { flag, value: String(value) },
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
}
|
|
138
149
|
|
|
139
150
|
async function provisionWallet(projectId, args) {
|
|
140
|
-
const
|
|
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");
|
|
141
159
|
if (!chain) {
|
|
142
160
|
fail({
|
|
143
161
|
code: "BAD_USAGE",
|
|
144
162
|
message: "Missing --chain (base-mainnet or base-sepolia)",
|
|
145
163
|
});
|
|
146
164
|
}
|
|
147
|
-
|
|
165
|
+
assertAllowedValue(chain, ["base-mainnet", "base-sepolia"], "--chain");
|
|
166
|
+
const recovery = flagValue(parsedArgs, "--recovery");
|
|
167
|
+
if (recovery) validateEvmAddress(recovery, "--recovery");
|
|
148
168
|
// Soft default of one wallet — confirm if project already has one.
|
|
149
169
|
let activeWallets = null;
|
|
150
170
|
try {
|
|
151
171
|
const list = await getSdk().contracts.listWallets(projectId);
|
|
152
172
|
activeWallets = (list.wallets || []).filter((w) => w.status === "active").length;
|
|
153
173
|
} catch { /* best-effort */ }
|
|
154
|
-
if (activeWallets !== null && activeWallets >= 1 && !hasFlag(
|
|
174
|
+
if (activeWallets !== null && activeWallets >= 1 && !hasFlag(parsedArgs, "--yes")) {
|
|
155
175
|
fail({
|
|
156
176
|
code: "CONFIRMATION_REQUIRED",
|
|
157
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.`,
|
|
@@ -170,7 +190,13 @@ async function provisionWallet(projectId, args) {
|
|
|
170
190
|
}
|
|
171
191
|
}
|
|
172
192
|
|
|
173
|
-
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
|
+
}
|
|
174
200
|
try {
|
|
175
201
|
const data = await getSdk().contracts.getWallet(projectId, walletId);
|
|
176
202
|
console.log(JSON.stringify(data, null, 2));
|
|
@@ -179,7 +205,13 @@ async function getWallet(projectId, walletId) {
|
|
|
179
205
|
}
|
|
180
206
|
}
|
|
181
207
|
|
|
182
|
-
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
|
+
}
|
|
183
215
|
try {
|
|
184
216
|
const data = await getSdk().contracts.listWallets(projectId);
|
|
185
217
|
console.log(JSON.stringify(data, null, 2));
|
|
@@ -189,14 +221,25 @@ async function listWallets(projectId) {
|
|
|
189
221
|
}
|
|
190
222
|
|
|
191
223
|
async function setRecovery(projectId, walletId, args) {
|
|
192
|
-
const
|
|
193
|
-
const
|
|
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
|
+
}
|
|
194
236
|
if (!clear && !address) {
|
|
195
237
|
fail({
|
|
196
238
|
code: "BAD_USAGE",
|
|
197
239
|
message: "Provide --address 0x... or --clear",
|
|
198
240
|
});
|
|
199
241
|
}
|
|
242
|
+
if (address) validateEvmAddress(address, "--address");
|
|
200
243
|
try {
|
|
201
244
|
await getSdk().contracts.setRecovery(projectId, walletId, clear ? null : address);
|
|
202
245
|
console.log(JSON.stringify({ status: "ok", wallet_id: walletId, recovery_address: clear ? null : address }));
|
|
@@ -206,10 +249,18 @@ async function setRecovery(projectId, walletId, args) {
|
|
|
206
249
|
}
|
|
207
250
|
|
|
208
251
|
async function setAlert(projectId, walletId, args) {
|
|
209
|
-
const
|
|
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");
|
|
210
260
|
if (!threshold) {
|
|
211
261
|
fail({ code: "BAD_USAGE", message: "Missing --threshold-wei <n>" });
|
|
212
262
|
}
|
|
263
|
+
validateWeiFlag("--threshold-wei", threshold);
|
|
213
264
|
try {
|
|
214
265
|
await getSdk().contracts.setLowBalanceAlert(projectId, walletId, threshold);
|
|
215
266
|
console.log(JSON.stringify({ status: "ok", wallet_id: walletId, threshold_wei: threshold }));
|
|
@@ -219,13 +270,20 @@ async function setAlert(projectId, walletId, args) {
|
|
|
219
270
|
}
|
|
220
271
|
|
|
221
272
|
async function call(projectId, walletId, args) {
|
|
222
|
-
const
|
|
223
|
-
const
|
|
224
|
-
|
|
225
|
-
const
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
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");
|
|
229
287
|
if (!to || !abi || !fn || !argsJson) {
|
|
230
288
|
fail({
|
|
231
289
|
code: "BAD_USAGE",
|
|
@@ -233,8 +291,11 @@ async function call(projectId, walletId, args) {
|
|
|
233
291
|
hint: "Cost: chain gas + $0.000005 KMS sign fee.",
|
|
234
292
|
});
|
|
235
293
|
}
|
|
294
|
+
assertAllowedValue(chain, ["base-mainnet", "base-sepolia"], "--chain");
|
|
295
|
+
if (value !== null) validateWeiFlag("--value-wei", value);
|
|
236
296
|
const abiFragment = parseFlagJson("--abi", abi);
|
|
237
297
|
const callArgs = parseFlagJson("--args", argsJson);
|
|
298
|
+
validateEvmAddress(to, "--to");
|
|
238
299
|
try {
|
|
239
300
|
const data = await getSdk().contracts.call(projectId, {
|
|
240
301
|
walletId,
|
|
@@ -253,19 +314,28 @@ async function call(projectId, walletId, args) {
|
|
|
253
314
|
}
|
|
254
315
|
|
|
255
316
|
async function read(args) {
|
|
256
|
-
const
|
|
257
|
-
const
|
|
258
|
-
|
|
259
|
-
const
|
|
260
|
-
|
|
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");
|
|
261
329
|
if (!chain || !to || !abi || !fn || !argsJson) {
|
|
262
330
|
fail({
|
|
263
331
|
code: "BAD_USAGE",
|
|
264
332
|
message: "Required flags: --chain, --to, --abi, --fn, --args",
|
|
265
333
|
});
|
|
266
334
|
}
|
|
335
|
+
assertAllowedValue(chain, ["base-mainnet", "base-sepolia"], "--chain");
|
|
267
336
|
const abiFragment = parseFlagJson("--abi", abi);
|
|
268
337
|
const callArgs = parseFlagJson("--args", argsJson);
|
|
338
|
+
validateEvmAddress(to, "--to");
|
|
269
339
|
try {
|
|
270
340
|
const data = await getSdk().contracts.read({
|
|
271
341
|
chain,
|
|
@@ -280,7 +350,13 @@ async function read(args) {
|
|
|
280
350
|
}
|
|
281
351
|
}
|
|
282
352
|
|
|
283
|
-
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
|
+
}
|
|
284
360
|
try {
|
|
285
361
|
const data = await getSdk().contracts.callStatus(projectId, callId);
|
|
286
362
|
console.log(JSON.stringify(data, null, 2));
|
|
@@ -290,14 +366,22 @@ async function status(projectId, callId) {
|
|
|
290
366
|
}
|
|
291
367
|
|
|
292
368
|
async function drain(projectId, walletId, args) {
|
|
293
|
-
const
|
|
294
|
-
|
|
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")) {
|
|
295
378
|
fail({
|
|
296
379
|
code: "BAD_USAGE",
|
|
297
380
|
message: "Required: --to 0x... and --confirm.",
|
|
298
381
|
hint: "Cost: chain gas + $0.000005 KMS sign fee.",
|
|
299
382
|
});
|
|
300
383
|
}
|
|
384
|
+
validateEvmAddress(to, "--to");
|
|
301
385
|
try {
|
|
302
386
|
const data = await getSdk().contracts.drain(projectId, walletId, to);
|
|
303
387
|
console.log(JSON.stringify(data, null, 2));
|
|
@@ -307,7 +391,13 @@ async function drain(projectId, walletId, args) {
|
|
|
307
391
|
}
|
|
308
392
|
|
|
309
393
|
async function deleteWallet(projectId, walletId, args) {
|
|
310
|
-
|
|
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")) {
|
|
311
401
|
fail({ code: "BAD_USAGE", message: "Required: --confirm" });
|
|
312
402
|
}
|
|
313
403
|
try {
|
|
@@ -323,13 +413,13 @@ export async function run(sub, args) {
|
|
|
323
413
|
if (Array.isArray(args) && (args.includes("--help") || args.includes("-h"))) { console.log(SUB_HELP[sub] || HELP); process.exit(0); }
|
|
324
414
|
switch (sub) {
|
|
325
415
|
case "provision-wallet": await provisionWallet(args[0], args.slice(1)); break;
|
|
326
|
-
case "get-wallet": await getWallet(args[0], args[1]); break;
|
|
327
|
-
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;
|
|
328
418
|
case "set-recovery": await setRecovery(args[0], args[1], args.slice(2)); break;
|
|
329
419
|
case "set-alert": await setAlert(args[0], args[1], args.slice(2)); break;
|
|
330
420
|
case "call": await call(args[0], args[1], args.slice(2)); break;
|
|
331
421
|
case "read": await read(args); break;
|
|
332
|
-
case "status": await status(args[0], args[1]); break;
|
|
422
|
+
case "status": await status(args[0], args[1], args.slice(2)); break;
|
|
333
423
|
case "drain": await drain(args[0], args[1], args.slice(2)); break;
|
|
334
424
|
case "delete": await deleteWallet(args[0], args[1], args.slice(2)); break;
|
|
335
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
|
-
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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
|
|
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 (
|
|
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.`,
|