run402 1.53.1 → 1.54.1
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/core-dist/keystore.js +65 -21
- package/lib/agent.mjs +4 -2
- package/lib/ai.mjs +18 -4
- package/lib/allowance.mjs +53 -15
- package/lib/apps.mjs +4 -2
- package/lib/auth.mjs +22 -7
- package/lib/billing.mjs +33 -17
- package/lib/blob.mjs +3 -4
- package/lib/cdn.mjs +3 -4
- package/lib/config.mjs +32 -8
- package/lib/contracts.mjs +38 -21
- package/lib/deploy-v2.mjs +38 -23
- package/lib/deploy.mjs +43 -44
- package/lib/domains.mjs +24 -8
- package/lib/email.mjs +38 -29
- package/lib/functions.mjs +15 -5
- package/lib/image.mjs +8 -2
- package/lib/init.mjs +30 -6
- package/lib/message.mjs +4 -2
- package/lib/projects.mjs +64 -13
- package/lib/sdk-errors.mjs +66 -10
- package/lib/secrets.mjs +8 -2
- package/lib/sender-domain.mjs +11 -5
- package/lib/sites.mjs +9 -7
- package/lib/status.mjs +1 -1
- package/lib/subdomains.mjs +24 -9
- package/lib/tier.mjs +8 -2
- package/lib/webhooks.mjs +27 -13
- package/package.json +1 -1
- package/sdk/core-dist/keystore.js +65 -21
- package/sdk/dist/errors.d.ts +18 -0
- package/sdk/dist/errors.d.ts.map +1 -1
- package/sdk/dist/errors.js +34 -6
- package/sdk/dist/errors.js.map +1 -1
- package/sdk/dist/index.d.ts.map +1 -1
- package/sdk/dist/index.js +13 -0
- package/sdk/dist/index.js.map +1 -1
- package/sdk/dist/namespaces/auth.d.ts.map +1 -1
- package/sdk/dist/namespaces/auth.js +10 -1
- package/sdk/dist/namespaces/auth.js.map +1 -1
- package/sdk/dist/namespaces/deploy.d.ts +5 -4
- package/sdk/dist/namespaces/deploy.d.ts.map +1 -1
- package/sdk/dist/namespaces/deploy.js +13 -7
- package/sdk/dist/namespaces/deploy.js.map +1 -1
- package/sdk/dist/namespaces/subdomains.d.ts +2 -1
- package/sdk/dist/namespaces/subdomains.d.ts.map +1 -1
- package/sdk/dist/namespaces/subdomains.js +22 -17
- package/sdk/dist/namespaces/subdomains.js.map +1 -1
- package/core-dist/wallet-auth.js +0 -62
- package/core-dist/wallet.js +0 -25
- package/sdk/core-dist/wallet-auth.js +0 -62
- package/sdk/core-dist/wallet.js +0 -25
package/lib/init.mjs
CHANGED
|
@@ -10,12 +10,23 @@ const TEMPO_RPC = "https://rpc.moderato.tempo.xyz/";
|
|
|
10
10
|
const HELP = `run402 init — Set up allowance, funding, and check tier status
|
|
11
11
|
|
|
12
12
|
Usage:
|
|
13
|
-
run402 init
|
|
14
|
-
run402 init mpp
|
|
15
|
-
run402 init --
|
|
16
|
-
|
|
13
|
+
run402 init Set up with x402 (Base Sepolia) — default
|
|
14
|
+
run402 init mpp Set up with MPP (Tempo Moderato)
|
|
15
|
+
run402 init <rail> --switch-rail
|
|
16
|
+
Switch the persisted payment rail to <rail>.
|
|
17
|
+
Required when an allowance already exists on
|
|
18
|
+
the other rail; protects scripted re-runs from
|
|
19
|
+
silently flipping billing networks.
|
|
20
|
+
run402 init --json Same as init, but emit a JSON summary on stdout
|
|
21
|
+
(human lines go to stderr — for agent automation)
|
|
17
22
|
|
|
18
|
-
|
|
23
|
+
Options:
|
|
24
|
+
--switch-rail Confirm switching the persisted payment rail. Re-running
|
|
25
|
+
init with the SAME rail as the existing allowance is always
|
|
26
|
+
idempotent and does not need this flag.
|
|
27
|
+
--json Emit a structured JSON summary on stdout.
|
|
28
|
+
|
|
29
|
+
Steps (idempotent when re-run with the same rail; pass --switch-rail to change rails):
|
|
19
30
|
1. Creates config directory (~/.config/run402)
|
|
20
31
|
2. Creates agent allowance if none exists
|
|
21
32
|
3. Checks on-chain balance; requests faucet if zero
|
|
@@ -32,6 +43,19 @@ export async function run(args = []) {
|
|
|
32
43
|
if (args.includes("--help") || args.includes("-h")) { console.log(HELP); process.exit(0); }
|
|
33
44
|
const jsonMode = args.includes("--json");
|
|
34
45
|
const isMpp = args[0] === "mpp";
|
|
46
|
+
const requestedRail = isMpp ? "mpp" : "x402";
|
|
47
|
+
const switchRailConfirmed = args.includes("--switch-rail");
|
|
48
|
+
|
|
49
|
+
const existingAllowance = readAllowance();
|
|
50
|
+
if (existingAllowance?.rail && existingAllowance.rail !== requestedRail && !switchRailConfirmed) {
|
|
51
|
+
console.error(JSON.stringify({
|
|
52
|
+
status: "error",
|
|
53
|
+
code: "RAIL_SWITCH_REQUIRES_CONFIRM",
|
|
54
|
+
message: `Already on rail '${existingAllowance.rail}'. Pass --switch-rail to switch to '${requestedRail}'.`,
|
|
55
|
+
details: { current_rail: existingAllowance.rail, requested_rail: requestedRail },
|
|
56
|
+
}));
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
35
59
|
|
|
36
60
|
// In --json mode, human-readable lines go to stderr so stdout stays clean for
|
|
37
61
|
// agents. We also collect structured data for the final JSON emit.
|
|
@@ -55,7 +79,7 @@ export async function run(args = []) {
|
|
|
55
79
|
line("Config", CONFIG_DIR);
|
|
56
80
|
|
|
57
81
|
// 2. Allowance
|
|
58
|
-
let allowance =
|
|
82
|
+
let allowance = existingAllowance;
|
|
59
83
|
const previousRail = allowance?.rail;
|
|
60
84
|
if (!allowance) {
|
|
61
85
|
const { generatePrivateKey, privateKeyToAccount } = await import("viem/accounts");
|
package/lib/message.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { allowanceAuthHeaders } from "./config.mjs";
|
|
2
2
|
import { getSdk } from "./sdk.mjs";
|
|
3
|
-
import { reportSdkError } from "./sdk-errors.mjs";
|
|
3
|
+
import { reportSdkError, fail } from "./sdk-errors.mjs";
|
|
4
4
|
|
|
5
5
|
const HELP = `run402 message — Send messages to Run402 developers
|
|
6
6
|
|
|
@@ -16,7 +16,9 @@ Examples:
|
|
|
16
16
|
`;
|
|
17
17
|
|
|
18
18
|
async function send(text) {
|
|
19
|
-
if (!text) {
|
|
19
|
+
if (!text) {
|
|
20
|
+
fail({ code: "BAD_USAGE", message: "Missing message text." });
|
|
21
|
+
}
|
|
20
22
|
// Preserve the aggressive early exit when no allowance is configured.
|
|
21
23
|
allowanceAuthHeaders("/message/v1");
|
|
22
24
|
|
package/lib/projects.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { readFileSync } from "fs";
|
|
2
|
-
import { findProject, loadKeyStore, API, allowanceAuthHeaders, resolveProjectId } from "./config.mjs";
|
|
2
|
+
import { findProject, loadKeyStore, API, allowanceAuthHeaders, resolveProjectId, getActiveProjectId } from "./config.mjs";
|
|
3
3
|
import { getSdk } from "./sdk.mjs";
|
|
4
|
-
import { reportSdkError } from "./sdk-errors.mjs";
|
|
4
|
+
import { reportSdkError, fail, parseFlagJson } from "./sdk-errors.mjs";
|
|
5
5
|
|
|
6
6
|
const HELP = `run402 projects — Manage your deployed Run402 projects
|
|
7
7
|
|
|
@@ -128,9 +128,16 @@ async function provision(args) {
|
|
|
128
128
|
// gives the user a more specific prompt than the SDK's 401/402 path.
|
|
129
129
|
allowanceAuthHeaders("/projects/v1");
|
|
130
130
|
|
|
131
|
+
const activeBefore = getActiveProjectId();
|
|
131
132
|
try {
|
|
132
133
|
const data = await getSdk().projects.provision({ tier: opts.tier, name: opts.name });
|
|
133
|
-
|
|
134
|
+
const activeAfter = getActiveProjectId();
|
|
135
|
+
const out = { ...data };
|
|
136
|
+
if (activeBefore && activeAfter && activeBefore !== activeAfter) {
|
|
137
|
+
out.note = `active project changed: ${activeBefore} -> ${activeAfter}`;
|
|
138
|
+
out.previous_active_project_id = activeBefore;
|
|
139
|
+
}
|
|
140
|
+
console.log(JSON.stringify(out, null, 2));
|
|
134
141
|
} catch (err) {
|
|
135
142
|
reportSdkError(err);
|
|
136
143
|
}
|
|
@@ -146,12 +153,21 @@ async function applyExpose(projectId, args = []) {
|
|
|
146
153
|
}
|
|
147
154
|
const raw = file ? readFileSync(file, "utf-8") : inline;
|
|
148
155
|
if (!raw) {
|
|
149
|
-
|
|
150
|
-
|
|
156
|
+
fail({
|
|
157
|
+
code: "BAD_USAGE",
|
|
158
|
+
message: "Missing manifest.",
|
|
159
|
+
hint: "Provide inline JSON or use --file <path>",
|
|
160
|
+
});
|
|
151
161
|
}
|
|
152
162
|
let manifest;
|
|
153
163
|
try { manifest = JSON.parse(raw); }
|
|
154
|
-
catch
|
|
164
|
+
catch (err) {
|
|
165
|
+
fail({
|
|
166
|
+
code: "BAD_USAGE",
|
|
167
|
+
message: "Invalid JSON for manifest",
|
|
168
|
+
details: { parse_error: err.message },
|
|
169
|
+
});
|
|
170
|
+
}
|
|
155
171
|
const res = await fetch(`${API}/projects/v1/admin/${projectId}/expose`, {
|
|
156
172
|
method: "POST",
|
|
157
173
|
headers: { "Authorization": `Bearer ${p.service_key}`, "Content-Type": "application/json" },
|
|
@@ -215,11 +231,22 @@ async function sqlCmd(projectId, args = []) {
|
|
|
215
231
|
else if (!query && !args[i].startsWith("--")) { query = args[i]; }
|
|
216
232
|
}
|
|
217
233
|
const sql = file ? readFileSync(file, "utf-8") : query;
|
|
218
|
-
if (!sql) {
|
|
234
|
+
if (!sql) {
|
|
235
|
+
fail({
|
|
236
|
+
code: "BAD_USAGE",
|
|
237
|
+
message: "Missing SQL query.",
|
|
238
|
+
hint: "Provide inline or use --file <path>",
|
|
239
|
+
});
|
|
240
|
+
}
|
|
219
241
|
let params;
|
|
220
242
|
if (paramsRaw) {
|
|
221
|
-
|
|
222
|
-
if (!Array.isArray(params)) {
|
|
243
|
+
params = parseFlagJson("--params", paramsRaw);
|
|
244
|
+
if (!Array.isArray(params)) {
|
|
245
|
+
fail({
|
|
246
|
+
code: "BAD_USAGE",
|
|
247
|
+
message: "--params must be a JSON array, e.g. '[42, \"hello\"]'",
|
|
248
|
+
});
|
|
249
|
+
}
|
|
223
250
|
}
|
|
224
251
|
const useParams = params && params.length > 0;
|
|
225
252
|
const headers = { "Authorization": `Bearer ${p.service_key}`, "Content-Type": useParams ? "application/json" : "text/plain" };
|
|
@@ -257,7 +284,13 @@ async function schema(projectId) {
|
|
|
257
284
|
}
|
|
258
285
|
|
|
259
286
|
async function use(projectId) {
|
|
260
|
-
if (!projectId) {
|
|
287
|
+
if (!projectId) {
|
|
288
|
+
fail({
|
|
289
|
+
code: "BAD_USAGE",
|
|
290
|
+
message: "Missing <project_id>.",
|
|
291
|
+
hint: "run402 projects use <project_id>",
|
|
292
|
+
});
|
|
293
|
+
}
|
|
261
294
|
try {
|
|
262
295
|
await getSdk().projects.use(projectId);
|
|
263
296
|
console.log(JSON.stringify({ status: "ok", active_project_id: projectId }));
|
|
@@ -267,7 +300,13 @@ async function use(projectId) {
|
|
|
267
300
|
}
|
|
268
301
|
|
|
269
302
|
async function pin(projectId) {
|
|
270
|
-
if (!projectId) {
|
|
303
|
+
if (!projectId) {
|
|
304
|
+
fail({
|
|
305
|
+
code: "BAD_USAGE",
|
|
306
|
+
message: "Missing <project_id>.",
|
|
307
|
+
hint: "run402 projects pin <project_id>",
|
|
308
|
+
});
|
|
309
|
+
}
|
|
271
310
|
try {
|
|
272
311
|
const data = await getSdk().projects.pin(projectId);
|
|
273
312
|
console.log(JSON.stringify(data, null, 2));
|
|
@@ -277,7 +316,13 @@ async function pin(projectId) {
|
|
|
277
316
|
}
|
|
278
317
|
|
|
279
318
|
async function promoteUser(projectId, email) {
|
|
280
|
-
if (!email) {
|
|
319
|
+
if (!email) {
|
|
320
|
+
fail({
|
|
321
|
+
code: "BAD_USAGE",
|
|
322
|
+
message: "Missing <email>.",
|
|
323
|
+
hint: "run402 projects promote-user <project_id> <email>",
|
|
324
|
+
});
|
|
325
|
+
}
|
|
281
326
|
const p = findProject(projectId);
|
|
282
327
|
const res = await fetch(`${API}/projects/v1/admin/${projectId}/promote-user`, {
|
|
283
328
|
method: "POST",
|
|
@@ -290,7 +335,13 @@ async function promoteUser(projectId, email) {
|
|
|
290
335
|
}
|
|
291
336
|
|
|
292
337
|
async function demoteUser(projectId, email) {
|
|
293
|
-
if (!email) {
|
|
338
|
+
if (!email) {
|
|
339
|
+
fail({
|
|
340
|
+
code: "BAD_USAGE",
|
|
341
|
+
message: "Missing <email>.",
|
|
342
|
+
hint: "run402 projects demote-user <project_id> <email>",
|
|
343
|
+
});
|
|
344
|
+
}
|
|
294
345
|
const p = findProject(projectId);
|
|
295
346
|
const res = await fetch(`${API}/projects/v1/admin/${projectId}/demote-user`, {
|
|
296
347
|
method: "POST",
|
package/lib/sdk-errors.mjs
CHANGED
|
@@ -1,25 +1,81 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* CLI-side SDK error translator.
|
|
3
3
|
*
|
|
4
|
-
* Maps SDK `Run402Error` subclasses into the CLI's
|
|
5
|
-
*
|
|
6
|
-
* Preserves specific behaviors:
|
|
7
|
-
* - `ProjectNotFound` →
|
|
8
|
-
*
|
|
9
|
-
*
|
|
4
|
+
* Maps SDK `Run402Error` subclasses into the CLI's canonical error envelope:
|
|
5
|
+
* `{status: "error", code, message, retryable, safe_to_retry, ...}` on stderr,
|
|
6
|
+
* `process.exit(1)`. Preserves specific behaviors:
|
|
7
|
+
* - `ProjectNotFound` → canonical envelope with `code: "PROJECT_NOT_FOUND"`
|
|
8
|
+
* and `details.source: "local_registry"` so callers can distinguish the
|
|
9
|
+
* local-registry miss from a gateway 404.
|
|
10
10
|
* - HTML / non-JSON error bodies → `body_preview` field (first 500 chars),
|
|
11
11
|
* matching GH-84 behavior.
|
|
12
12
|
* - Network errors → `{status: "error", message: "..."}`.
|
|
13
|
+
*
|
|
14
|
+
* For client-side validation failures (missing flags, bad JSON, no-op
|
|
15
|
+
* environments), use `fail()` instead — `reportSdkError` is strictly for
|
|
16
|
+
* thrown `Run402Error` instances.
|
|
13
17
|
*/
|
|
14
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Canonical client-side failure emitter.
|
|
21
|
+
*
|
|
22
|
+
* Writes a single JSON envelope to stderr and exits with `exit_code` (default 1).
|
|
23
|
+
* The envelope shape matches the gateway's structured error contract so callers
|
|
24
|
+
* branching on `code` / `retryable` / `safe_to_retry` work uniformly across
|
|
25
|
+
* client-side validation errors and SDK-thrown errors.
|
|
26
|
+
*
|
|
27
|
+
* `code` defaults to "BAD_USAGE" so the helper is safe to call without one.
|
|
28
|
+
* `retryable: false` and `safe_to_retry: true` are sane defaults for client-side
|
|
29
|
+
* validation: the call wasn't sent, so retrying is safe and won't help unless
|
|
30
|
+
* the user fixes input.
|
|
31
|
+
*/
|
|
32
|
+
export function fail({ message, code, hint, details, next_actions, retryable = false, safe_to_retry = true, exit_code = 1 } = {}) {
|
|
33
|
+
const envelope = {
|
|
34
|
+
status: "error",
|
|
35
|
+
code: code ?? "BAD_USAGE",
|
|
36
|
+
message,
|
|
37
|
+
retryable,
|
|
38
|
+
safe_to_retry,
|
|
39
|
+
};
|
|
40
|
+
if (hint !== undefined) envelope.hint = hint;
|
|
41
|
+
if (details !== undefined) envelope.details = details;
|
|
42
|
+
envelope.next_actions = Array.isArray(next_actions) ? next_actions : [];
|
|
43
|
+
envelope.trace_id = null;
|
|
44
|
+
console.error(JSON.stringify(envelope));
|
|
45
|
+
process.exit(exit_code);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Parse a JSON-bearing CLI flag value, naming the flag in the failure envelope.
|
|
50
|
+
*
|
|
51
|
+
* Wraps `JSON.parse` so the failure says which flag was bad and includes a
|
|
52
|
+
* truncated value preview, instead of leaking a raw V8 `JSON.parse` message
|
|
53
|
+
* that doesn't tell the caller which flag failed.
|
|
54
|
+
*/
|
|
55
|
+
export function parseFlagJson(name, value) {
|
|
56
|
+
try {
|
|
57
|
+
return JSON.parse(value);
|
|
58
|
+
} catch (e) {
|
|
59
|
+
fail({
|
|
60
|
+
code: "BAD_JSON_FLAG",
|
|
61
|
+
message: `${name} value is not valid JSON`,
|
|
62
|
+
details: { flag: name, value_preview: String(value).slice(0, 32), parse_error: e.message },
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
15
67
|
export function reportSdkError(err) {
|
|
16
68
|
if (err?.name === "ProjectNotFound") {
|
|
17
69
|
const id = err.projectId || "";
|
|
18
70
|
const hint = id && !String(id).startsWith("prj_")
|
|
19
|
-
? `
|
|
20
|
-
:
|
|
21
|
-
|
|
22
|
-
|
|
71
|
+
? `project IDs start with "prj_". Check that the argument order is <project_id> <name>.`
|
|
72
|
+
: undefined;
|
|
73
|
+
fail({
|
|
74
|
+
code: "PROJECT_NOT_FOUND",
|
|
75
|
+
message: `Project ${id} not found in local registry.`,
|
|
76
|
+
hint,
|
|
77
|
+
details: { project_id: id, source: "local_registry" },
|
|
78
|
+
});
|
|
23
79
|
}
|
|
24
80
|
|
|
25
81
|
const payload = { status: "error" };
|
package/lib/secrets.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readFileSync } from "fs";
|
|
2
2
|
import { getSdk } from "./sdk.mjs";
|
|
3
|
-
import { reportSdkError } from "./sdk-errors.mjs";
|
|
3
|
+
import { reportSdkError, fail } from "./sdk-errors.mjs";
|
|
4
4
|
|
|
5
5
|
const HELP = `run402 secrets — Manage project secrets
|
|
6
6
|
|
|
@@ -56,7 +56,13 @@ async function set(projectId, key, args = []) {
|
|
|
56
56
|
else if (!value && !args[i].startsWith("--")) { value = args[i]; }
|
|
57
57
|
}
|
|
58
58
|
const val = file ? readFileSync(file, "utf-8") : value;
|
|
59
|
-
if (!val) {
|
|
59
|
+
if (!val) {
|
|
60
|
+
fail({
|
|
61
|
+
code: "BAD_USAGE",
|
|
62
|
+
message: "Missing secret value.",
|
|
63
|
+
hint: "Provide inline or use --file <path>",
|
|
64
|
+
});
|
|
65
|
+
}
|
|
60
66
|
try {
|
|
61
67
|
await getSdk().secrets.set(projectId, key, val);
|
|
62
68
|
console.log(JSON.stringify({ status: "ok", message: `Secret '${key}' set for project ${projectId}.` }));
|
package/lib/sender-domain.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { resolveProjectId } from "./config.mjs";
|
|
2
2
|
import { getSdk } from "./sdk.mjs";
|
|
3
|
-
import { reportSdkError } from "./sdk-errors.mjs";
|
|
3
|
+
import { reportSdkError, fail } from "./sdk-errors.mjs";
|
|
4
4
|
|
|
5
5
|
const HELP = `run402 sender-domain — Manage custom email sender domain
|
|
6
6
|
|
|
@@ -39,8 +39,11 @@ async function register(args) {
|
|
|
39
39
|
const projectId = resolveProjectId(projectOpt);
|
|
40
40
|
|
|
41
41
|
if (!domain) {
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
fail({
|
|
43
|
+
code: "BAD_USAGE",
|
|
44
|
+
message: "Missing domain.",
|
|
45
|
+
hint: "run402 sender-domain register <domain>",
|
|
46
|
+
});
|
|
44
47
|
}
|
|
45
48
|
|
|
46
49
|
try {
|
|
@@ -81,8 +84,11 @@ async function inboundToggle(action, args) {
|
|
|
81
84
|
const projectId = resolveProjectId(projectOpt);
|
|
82
85
|
|
|
83
86
|
if (!domain) {
|
|
84
|
-
|
|
85
|
-
|
|
87
|
+
fail({
|
|
88
|
+
code: "BAD_USAGE",
|
|
89
|
+
message: "Missing domain.",
|
|
90
|
+
hint: `run402 sender-domain inbound-${action} <domain>`,
|
|
91
|
+
});
|
|
86
92
|
}
|
|
87
93
|
|
|
88
94
|
try {
|
package/lib/sites.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import { fileSetFromDir } from "#sdk/node";
|
|
|
5
5
|
import { allowanceAuthHeaders, resolveProjectId, updateProject } from "./config.mjs";
|
|
6
6
|
import { resolveFilePathsInManifest } from "./manifest.mjs";
|
|
7
7
|
import { getSdk } from "./sdk.mjs";
|
|
8
|
-
import { reportSdkError } from "./sdk-errors.mjs";
|
|
8
|
+
import { reportSdkError, fail } from "./sdk-errors.mjs";
|
|
9
9
|
|
|
10
10
|
const SMALL_DIR_THRESHOLD = 5;
|
|
11
11
|
|
|
@@ -244,17 +244,19 @@ async function deployDir(args) {
|
|
|
244
244
|
if (args[i] === "--dry-run") { opts.dryRun = true; continue; }
|
|
245
245
|
if (args[i] === "--confirm-prune") { opts.confirmPrune = true; continue; }
|
|
246
246
|
if (args[i] === "--inherit") {
|
|
247
|
-
|
|
248
|
-
|
|
247
|
+
fail({
|
|
248
|
+
code: "BAD_USAGE",
|
|
249
249
|
message: "--inherit is removed; the SDK now uploads only changed files automatically.",
|
|
250
|
-
})
|
|
251
|
-
process.exit(1);
|
|
250
|
+
});
|
|
252
251
|
}
|
|
253
252
|
if (!args[i].startsWith("-") && opts.dir === null) { opts.dir = args[i]; continue; }
|
|
254
253
|
}
|
|
255
254
|
if (!opts.dir) {
|
|
256
|
-
|
|
257
|
-
|
|
255
|
+
fail({
|
|
256
|
+
code: "BAD_USAGE",
|
|
257
|
+
message: "Missing <path>.",
|
|
258
|
+
hint: "run402 sites deploy-dir <path> --project <id>",
|
|
259
|
+
});
|
|
258
260
|
}
|
|
259
261
|
const projectId = resolveProjectId(opts.project);
|
|
260
262
|
|
package/lib/status.mjs
CHANGED
|
@@ -79,7 +79,7 @@ export async function run(args = []) {
|
|
|
79
79
|
const allowance = readAllowance();
|
|
80
80
|
if (!allowance) {
|
|
81
81
|
console.log(JSON.stringify({ status: "no_allowance", message: "No agent allowance found. Run: run402 init" }));
|
|
82
|
-
|
|
82
|
+
process.exit(1);
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
const wallet = allowance.address.toLowerCase();
|
package/lib/subdomains.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { resolveProject, resolveProjectId } from "./config.mjs";
|
|
2
2
|
import { getSdk } from "./sdk.mjs";
|
|
3
|
-
import { reportSdkError } from "./sdk-errors.mjs";
|
|
3
|
+
import { reportSdkError, fail } from "./sdk-errors.mjs";
|
|
4
4
|
|
|
5
5
|
const HELP = `run402 subdomains — Manage custom subdomains
|
|
6
6
|
|
|
@@ -64,11 +64,25 @@ async function claim(positionalArgs, flagArgs) {
|
|
|
64
64
|
} else if (positionalArgs.length === 1) {
|
|
65
65
|
name = positionalArgs[0];
|
|
66
66
|
}
|
|
67
|
-
if (!name) {
|
|
67
|
+
if (!name) {
|
|
68
|
+
fail({
|
|
69
|
+
code: "BAD_USAGE",
|
|
70
|
+
message: "Missing <name>.",
|
|
71
|
+
hint: "run402 subdomains claim <name> [--project <id>] [--deployment <id>]",
|
|
72
|
+
});
|
|
73
|
+
}
|
|
68
74
|
const projectId = resolveProjectId(opts.project);
|
|
69
75
|
const p = resolveProject(opts.project);
|
|
70
76
|
deploymentId = opts.deployment || deploymentId || p.last_deployment_id;
|
|
71
|
-
if (!deploymentId) {
|
|
77
|
+
if (!deploymentId) {
|
|
78
|
+
fail({
|
|
79
|
+
code: "NO_DEPLOYMENT",
|
|
80
|
+
message: "no deployment_id specified and no recent deployment found.",
|
|
81
|
+
hint: "Deploy a site first or pass --deployment <id>.",
|
|
82
|
+
details: { project_id: projectId },
|
|
83
|
+
next_actions: [{ action: "deploy_site_first" }],
|
|
84
|
+
});
|
|
85
|
+
}
|
|
72
86
|
try {
|
|
73
87
|
const data = await getSdk().subdomains.claim(name, deploymentId, { projectId });
|
|
74
88
|
console.log(JSON.stringify(data, null, 2));
|
|
@@ -86,17 +100,18 @@ async function deleteSubdomain(allArgs) {
|
|
|
86
100
|
else if (!argList[i].startsWith("--") && !name) { name = argList[i]; }
|
|
87
101
|
}
|
|
88
102
|
if (!name) {
|
|
89
|
-
|
|
90
|
-
|
|
103
|
+
fail({
|
|
104
|
+
code: "BAD_USAGE",
|
|
105
|
+
message: "Missing <name>.",
|
|
106
|
+
hint: "run402 subdomains delete <name> --confirm [--project <id>]",
|
|
107
|
+
});
|
|
91
108
|
}
|
|
92
109
|
if (!argList.includes("--confirm")) {
|
|
93
|
-
|
|
94
|
-
status: "error",
|
|
110
|
+
fail({
|
|
95
111
|
code: "CONFIRMATION_REQUIRED",
|
|
96
112
|
message: `Destructive: releasing subdomain '${name}' makes it available for any other project to claim. This is irreversible. Re-run with --confirm to proceed.`,
|
|
97
113
|
details: { name },
|
|
98
|
-
})
|
|
99
|
-
process.exit(1);
|
|
114
|
+
});
|
|
100
115
|
}
|
|
101
116
|
const projectId = resolveProjectId(opts.project);
|
|
102
117
|
try {
|
package/lib/tier.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getSdk } from "./sdk.mjs";
|
|
2
|
-
import { reportSdkError } from "./sdk-errors.mjs";
|
|
2
|
+
import { reportSdkError, fail } from "./sdk-errors.mjs";
|
|
3
3
|
|
|
4
4
|
const HELP = `run402 tier — Manage your Run402 tier subscription
|
|
5
5
|
|
|
@@ -34,7 +34,13 @@ async function status() {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
async function set(tierName) {
|
|
37
|
-
if (!tierName) {
|
|
37
|
+
if (!tierName) {
|
|
38
|
+
fail({
|
|
39
|
+
code: "BAD_USAGE",
|
|
40
|
+
message: "Missing <tier>.",
|
|
41
|
+
hint: "run402 tier set <prototype|hobby|team>",
|
|
42
|
+
});
|
|
43
|
+
}
|
|
38
44
|
try {
|
|
39
45
|
const data = await getSdk().tier.set(tierName);
|
|
40
46
|
console.log(JSON.stringify(data, null, 2));
|
package/lib/webhooks.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { resolveProjectId } from "./config.mjs";
|
|
2
2
|
import { getSdk } from "./sdk.mjs";
|
|
3
|
-
import { reportSdkError } from "./sdk-errors.mjs";
|
|
3
|
+
import { reportSdkError, fail } from "./sdk-errors.mjs";
|
|
4
4
|
|
|
5
5
|
const HELP = `run402 email webhooks — Manage mailbox webhooks
|
|
6
6
|
|
|
@@ -62,8 +62,11 @@ async function get(args) {
|
|
|
62
62
|
}
|
|
63
63
|
const projectId = resolveProjectId(projectOpt);
|
|
64
64
|
if (!webhookId) {
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
fail({
|
|
66
|
+
code: "BAD_USAGE",
|
|
67
|
+
message: "Missing webhook_id.",
|
|
68
|
+
hint: "run402 email webhooks get <webhook_id>",
|
|
69
|
+
});
|
|
67
70
|
}
|
|
68
71
|
try {
|
|
69
72
|
const data = await getSdk().email.webhooks.get(projectId, webhookId);
|
|
@@ -82,8 +85,11 @@ async function del(args) {
|
|
|
82
85
|
}
|
|
83
86
|
const projectId = resolveProjectId(projectOpt);
|
|
84
87
|
if (!webhookId) {
|
|
85
|
-
|
|
86
|
-
|
|
88
|
+
fail({
|
|
89
|
+
code: "BAD_USAGE",
|
|
90
|
+
message: "Missing webhook_id.",
|
|
91
|
+
hint: "run402 email webhooks delete <webhook_id>",
|
|
92
|
+
});
|
|
87
93
|
}
|
|
88
94
|
try {
|
|
89
95
|
await getSdk().email.webhooks.delete(projectId, webhookId);
|
|
@@ -106,12 +112,14 @@ async function update(args) {
|
|
|
106
112
|
}
|
|
107
113
|
const projectId = resolveProjectId(projectOpt);
|
|
108
114
|
if (!webhookId) {
|
|
109
|
-
|
|
110
|
-
|
|
115
|
+
fail({
|
|
116
|
+
code: "BAD_USAGE",
|
|
117
|
+
message: "Missing webhook_id.",
|
|
118
|
+
hint: "run402 email webhooks update <webhook_id> [--url <url>] [--events <e1,e2>]",
|
|
119
|
+
});
|
|
111
120
|
}
|
|
112
121
|
if (!url && !eventsRaw) {
|
|
113
|
-
|
|
114
|
-
process.exit(1);
|
|
122
|
+
fail({ code: "BAD_USAGE", message: "Provide at least --url or --events" });
|
|
115
123
|
}
|
|
116
124
|
|
|
117
125
|
try {
|
|
@@ -132,12 +140,18 @@ async function register(args) {
|
|
|
132
140
|
const projectId = resolveProjectId(projectOpt);
|
|
133
141
|
|
|
134
142
|
if (!url) {
|
|
135
|
-
|
|
136
|
-
|
|
143
|
+
fail({
|
|
144
|
+
code: "BAD_USAGE",
|
|
145
|
+
message: "Missing --url.",
|
|
146
|
+
hint: "run402 email webhooks register --url <url> --events <e1,e2>",
|
|
147
|
+
});
|
|
137
148
|
}
|
|
138
149
|
if (!eventsRaw) {
|
|
139
|
-
|
|
140
|
-
|
|
150
|
+
fail({
|
|
151
|
+
code: "BAD_USAGE",
|
|
152
|
+
message: "Missing --events.",
|
|
153
|
+
hint: "Valid events: delivery, bounced, complained, reply_received",
|
|
154
|
+
});
|
|
141
155
|
}
|
|
142
156
|
|
|
143
157
|
const events = eventsRaw.split(",").map((e) => e.trim());
|
package/package.json
CHANGED