run402 1.29.1 → 1.31.0
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/email.mjs +45 -0
- package/lib/sender-domain.mjs +35 -0
- package/package.json +1 -1
package/lib/email.mjs
CHANGED
|
@@ -11,6 +11,8 @@ Subcommands:
|
|
|
11
11
|
send --to <email> [mode flags] Send an email (template or raw HTML)
|
|
12
12
|
list [--project <id>] List sent emails
|
|
13
13
|
get <message_id> [--project <id>] Get a message with replies
|
|
14
|
+
get-raw <message_id> [--project <id>] [--output <file>]
|
|
15
|
+
Fetch raw RFC-822 bytes (inbound only)
|
|
14
16
|
|
|
15
17
|
Send modes:
|
|
16
18
|
Template: --template <name> --var key=value [--var ...]
|
|
@@ -32,6 +34,7 @@ Examples:
|
|
|
32
34
|
--var project_name="My App" --var message="Deploy complete"
|
|
33
35
|
run402 email list
|
|
34
36
|
run402 email get msg_abc123
|
|
37
|
+
run402 email get-raw msg_abc123 --output reply.eml
|
|
35
38
|
|
|
36
39
|
Notes:
|
|
37
40
|
- One mailbox per project
|
|
@@ -246,6 +249,47 @@ async function get(args) {
|
|
|
246
249
|
console.log(JSON.stringify(data, null, 2));
|
|
247
250
|
}
|
|
248
251
|
|
|
252
|
+
async function getRaw(args) {
|
|
253
|
+
let messageId = null;
|
|
254
|
+
let projectOpt = null;
|
|
255
|
+
let outputFile = null;
|
|
256
|
+
for (let i = 0; i < args.length; i++) {
|
|
257
|
+
if (args[i] === "--project" && args[i + 1]) { projectOpt = args[++i]; }
|
|
258
|
+
else if (args[i] === "--output" && args[i + 1]) { outputFile = args[++i]; }
|
|
259
|
+
else if (!args[i].startsWith("--") && !messageId) { messageId = args[i]; }
|
|
260
|
+
}
|
|
261
|
+
const projectId = resolveProjectId(projectOpt);
|
|
262
|
+
const p = findProject(projectId);
|
|
263
|
+
|
|
264
|
+
if (!messageId) {
|
|
265
|
+
console.error(JSON.stringify({ status: "error", message: "Missing message_id. Usage: run402 email get-raw <message_id> [--output <file>]" }));
|
|
266
|
+
process.exit(1);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
const mailboxId = await requireMailboxId(projectId, p.service_key);
|
|
270
|
+
|
|
271
|
+
const res = await fetch(`${API}/mailboxes/v1/${mailboxId}/messages/${messageId}/raw`, {
|
|
272
|
+
headers: { "Authorization": `Bearer ${p.service_key}` },
|
|
273
|
+
});
|
|
274
|
+
if (!res.ok) {
|
|
275
|
+
let errBody;
|
|
276
|
+
try { errBody = await res.json(); } catch { errBody = { error: await res.text().catch(() => "Unknown error") }; }
|
|
277
|
+
console.error(JSON.stringify({ status: "error", http: res.status, ...errBody }));
|
|
278
|
+
process.exit(1);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const buf = Buffer.from(await res.arrayBuffer());
|
|
282
|
+
|
|
283
|
+
if (outputFile) {
|
|
284
|
+
const { writeFileSync } = await import("node:fs");
|
|
285
|
+
writeFileSync(outputFile, buf);
|
|
286
|
+
console.log(JSON.stringify({ status: "ok", message_id: messageId, bytes: buf.length, output: outputFile }));
|
|
287
|
+
} else {
|
|
288
|
+
// Write raw bytes to stdout (no JSON wrapping — binary pipe-friendly)
|
|
289
|
+
process.stdout.write(buf);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
249
293
|
async function status(args) {
|
|
250
294
|
const projectId = resolveProjectId(parseFlag(args, "--project"));
|
|
251
295
|
const p = findProject(projectId);
|
|
@@ -277,6 +321,7 @@ export async function run(sub, args) {
|
|
|
277
321
|
case "send": await send(args); break;
|
|
278
322
|
case "list": await list(args); break;
|
|
279
323
|
case "get": await get(args); break;
|
|
324
|
+
case "get-raw": await getRaw(args); break;
|
|
280
325
|
default:
|
|
281
326
|
console.error(`Unknown subcommand: ${sub}\n`);
|
|
282
327
|
console.log(HELP);
|
package/lib/sender-domain.mjs
CHANGED
|
@@ -9,11 +9,15 @@ Subcommands:
|
|
|
9
9
|
register <domain> [--project <id>] Register a custom sender domain (returns DNS records)
|
|
10
10
|
status [--project <id>] Check domain verification status
|
|
11
11
|
remove [--project <id>] Remove custom sender domain
|
|
12
|
+
inbound-enable <domain> [--project <id>] Enable inbound email (requires DKIM-verified)
|
|
13
|
+
inbound-disable <domain> [--project <id>] Disable inbound email
|
|
12
14
|
|
|
13
15
|
Examples:
|
|
14
16
|
run402 sender-domain register kysigned.com
|
|
15
17
|
run402 sender-domain status
|
|
16
18
|
run402 sender-domain remove
|
|
19
|
+
run402 sender-domain inbound-enable kysigned.com
|
|
20
|
+
run402 sender-domain inbound-disable kysigned.com
|
|
17
21
|
`;
|
|
18
22
|
|
|
19
23
|
function parseFlag(args, flag) {
|
|
@@ -82,12 +86,43 @@ async function remove(args) {
|
|
|
82
86
|
console.log(JSON.stringify(data));
|
|
83
87
|
}
|
|
84
88
|
|
|
89
|
+
async function inboundToggle(action, args) {
|
|
90
|
+
let domain = null;
|
|
91
|
+
let projectOpt = null;
|
|
92
|
+
for (let i = 0; i < args.length; i++) {
|
|
93
|
+
if (args[i] === "--project" && args[i + 1]) { projectOpt = args[++i]; }
|
|
94
|
+
else if (!args[i].startsWith("--") && !domain) { domain = args[i]; }
|
|
95
|
+
}
|
|
96
|
+
const projectId = resolveProjectId(projectOpt);
|
|
97
|
+
const p = findProject(projectId);
|
|
98
|
+
|
|
99
|
+
if (!domain) {
|
|
100
|
+
console.error(JSON.stringify({ status: "error", message: `Missing domain. Usage: run402 sender-domain inbound-${action} <domain>` }));
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const method = action === "enable" ? "POST" : "DELETE";
|
|
105
|
+
const res = await fetch(`${API}/email/v1/domains/inbound`, {
|
|
106
|
+
method,
|
|
107
|
+
headers: { apikey: p.service_key, "Content-Type": "application/json" },
|
|
108
|
+
body: JSON.stringify({ domain }),
|
|
109
|
+
});
|
|
110
|
+
const data = await res.json();
|
|
111
|
+
if (!res.ok) {
|
|
112
|
+
console.error(JSON.stringify({ status: "error", http: res.status, ...data }));
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
console.log(JSON.stringify(data, null, 2));
|
|
116
|
+
}
|
|
117
|
+
|
|
85
118
|
export async function run(sub, args) {
|
|
86
119
|
if (!sub || sub === "--help" || sub === "-h") { console.log(HELP); process.exit(0); }
|
|
87
120
|
switch (sub) {
|
|
88
121
|
case "register": await register(args); break;
|
|
89
122
|
case "status": await status(args); break;
|
|
90
123
|
case "remove": await remove(args); break;
|
|
124
|
+
case "inbound-enable": await inboundToggle("enable", args); break;
|
|
125
|
+
case "inbound-disable": await inboundToggle("disable", args); break;
|
|
91
126
|
default:
|
|
92
127
|
console.error(`Unknown subcommand: ${sub}\n`);
|
|
93
128
|
console.log(HELP);
|
package/package.json
CHANGED