void 0.20.0 → 0.20.2
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/README.md +5 -1
- package/dist/{auth-W9WII-mN.mjs → auth-DPl6kck4.mjs} +46 -26
- package/dist/{auth-cmd-CYVhSNFy.mjs → auth-cmd-gniL2fNt.mjs} +5 -4
- package/dist/auth-link-NZdjCmSc.mjs +28 -0
- package/dist/{build-cmd-CkVD1uOh.mjs → build-cmd-sI18tX_O.mjs} +3 -3
- package/dist/{cache-QcUfR-ff.mjs → cache-IHn5MwBC.mjs} +3 -3
- package/dist/{cancel-deploy-DsvWKFTe.mjs → cancel-deploy-C5qTOdLi.mjs} +3 -3
- package/dist/cf-access-DRsQRe6k.mjs +75 -0
- package/dist/cli/cli.mjs +364 -1883
- package/dist/cli/env-schema-probe.mjs +11 -2
- package/dist/{client-CyCHWSO_.mjs → client-dHfSJvAN.mjs} +336 -58
- package/dist/{cloudflare-auth-DRkGe7-s.mjs → cloudflare-auth-6M5llVPC.mjs} +53 -6
- package/dist/{cloudflare-cmd-D3ME2GAe.mjs → cloudflare-cmd-4RPGN3KB.mjs} +2 -2
- package/dist/{cloudflare-connect-BivMefMA.mjs → cloudflare-connect-t1UU5svD.mjs} +2 -2
- package/dist/{cloudflare-operations-CPTpRW6d.mjs → cloudflare-operations-BzWnlC1_.mjs} +1 -1
- package/dist/{config-BQFq7QvD.mjs → config-uNGuFsI2.mjs} +1 -1
- package/dist/{connect-D9Yr-T5f.mjs → connect-Bfk31O_8.mjs} +6 -6
- package/dist/{create-project-DMV-csEm.mjs → create-project-Bk9Z0-Jg.mjs} +6 -5
- package/dist/{db-BxoUWL0F.mjs → db-BkRoptAt.mjs} +75 -48
- package/dist/{delete-iJOqxBz1.mjs → delete-DouASY9P.mjs} +3 -3
- package/dist/{deploy-CcDoeBIf.mjs → deploy-DTaWUS1S.mjs} +137 -128
- package/dist/{dev-inbox-DkgRWLkW.mjs → dev-inbox-P0u4tM8Y.mjs} +1 -1
- package/dist/{domain-gu_iaHmn.mjs → domain-1RhhOVrC.mjs} +4 -4
- package/dist/email-C-lGh51B.mjs +795 -0
- package/dist/{env-D4Emu-M_.mjs → env-DBKmK4vc.mjs} +1 -0
- package/dist/{env-DmU2To0C.mjs → env-DJHsPE7Z.mjs} +5 -5
- package/dist/{env-validation-ENpMy6Ez.mjs → env-validation-CF6KvTRf.mjs} +3 -1
- package/dist/{gen-BKw6qHIg.mjs → gen-B_wPnVTK.mjs} +3 -3
- package/dist/generate-RTK8_kK1.mjs +47 -0
- package/dist/{github-cmd-DJS5Ab-H.mjs → github-cmd-PW7ZnWTp.mjs} +3 -3
- package/dist/{headers-D8QfRX9Y.mjs → headers-BAHwgHdW.mjs} +1 -1
- package/dist/help-CwOX-zmI.mjs +2216 -0
- package/dist/{inbound-BJ70in1n.d.mts → inbound-CH5Mksyy.d.mts} +37 -42
- package/dist/{inbound-CNKxb3FY.mjs → inbound-aVHEUhKo.mjs} +143 -101
- package/dist/index.mjs +69 -30
- package/dist/{init-Dx5cgKqK.mjs → init-BWZ7q5Z4.mjs} +11 -11
- package/dist/{link-D_rm5sRH.mjs → link-Rmvu2Wl_.mjs} +4 -4
- package/dist/{list-M8XShti7.mjs → list-DEE2S6mY.mjs} +4 -4
- package/dist/{local-d1-BE8KBbMy.mjs → local-d1-D2I6Ox5F.mjs} +1 -1
- package/dist/{login-C8-UuLnp.mjs → login-Uvferzmm.mjs} +28 -10
- package/dist/{logs-DwFU7dMW.mjs → logs-27FenuiC.mjs} +4 -4
- package/dist/{mime-BJD7d_qL.mjs → mime-D5Nmdzf7.mjs} +23 -9
- package/dist/{node-BkaXcpAc.mjs → node-Ez5KW5rn.mjs} +3 -3
- package/dist/operator-auth-B3e08unv.mjs +52 -0
- package/dist/operator-client-LUZnlnYk.mjs +82 -0
- package/dist/{operator-cmd-DYWRbWUA.mjs → operator-cmd-CjOTmAYE.mjs} +35 -55
- package/dist/{output-tFQLLj26.mjs → output-B0cfNSx5.mjs} +316 -2
- package/dist/pages/index.mjs +2 -2
- package/dist/platform-auth-config-DrbQXXiW.mjs +368 -0
- package/dist/platform-auth-protection-Bhtvp0B_.mjs +219 -0
- package/dist/platform-auth-recovery-CeOKGVeJ.mjs +310 -0
- package/dist/{platform-cmd-BEOVv1PN.mjs → platform-cmd-BFhieCdV.mjs} +16 -6
- package/dist/{platform-domain-BszUfiS8.mjs → platform-domain-C74PULqV.mjs} +4 -4
- package/dist/{platform-lifecycle-CjSr6xf0.mjs → platform-lifecycle-BwAIgz-t.mjs} +1667 -191
- package/dist/{platform-management-W30iCaTL.mjs → platform-management-COogu_Se.mjs} +33 -7
- package/dist/{platform-recovery-pHHv4ZSg.mjs → platform-recovery-ewqLefp1.mjs} +6 -5
- package/dist/{prepare-CBetXvsN.mjs → prepare-CtDJjoOj.mjs} +2 -2
- package/dist/{prepare-BfJvFUtJ.mjs → prepare-blNRQvQl.mjs} +2 -2
- package/dist/prerender-render.d.mts +11 -0
- package/dist/prerender-render.mjs +111 -0
- package/dist/{project-cmd-DCpk1cDt.mjs → project-cmd-DmZK9Hxf.mjs} +32 -14
- package/dist/project-team-D8jOJMUJ.mjs +130 -0
- package/dist/project-token-DA34bf-C.mjs +75 -0
- package/dist/{provision-Blnstcm2.mjs → provision-CSJOjjQk.mjs} +2 -0
- package/dist/{requests-Dn8Vheh1.mjs → requests-CUExwGQQ.mjs} +3 -3
- package/dist/{rollback-CtlPXEBi.mjs → rollback-CDNGU1gr.mjs} +4 -4
- package/dist/{runner-mysql-CgRFl3s6.mjs → runner-mysql-7BPUNGmL.mjs} +1 -1
- package/dist/{runner-pg-DCkWPsWS.mjs → runner-pg-BkEza-dX.mjs} +1 -1
- package/dist/runtime/ai.mjs +3 -2
- package/dist/runtime/email/testing.d.mts +1 -1
- package/dist/runtime/email/testing.mjs +3 -3
- package/dist/runtime/email-protocol.d.mts +15 -0
- package/dist/runtime/email-protocol.mjs +70 -0
- package/dist/runtime/email.d.mts +2 -2
- package/dist/runtime/email.mjs +189 -96
- package/dist/runtime/remote/index.mjs +5 -3
- package/dist/{secret-BqTxGqki.mjs → secret-Bzzi2e9E.mjs} +5 -5
- package/dist/{skills-Q46GZMO-.mjs → skills-C0RvGjeE.mjs} +1 -1
- package/dist/sqlite-validation-BzKMWnO4.mjs +25 -0
- package/dist/{subcommand-prompt-WfySCQ7S.mjs → subcommand-prompt-Bmyn5Rlc.mjs} +1 -1
- package/dist/{validate-Bihr8WBi.mjs → validate-tBBN_dXH.mjs} +1 -0
- package/package.json +12 -7
- package/skills/void/SKILL.md +35 -4
- package/skills/void/docs/guide/deployment.md +2 -0
- package/skills/void/docs/guide/email.md +121 -98
- package/skills/void/docs/guide/platform-administration.md +214 -2
- package/skills/void/docs/guide/platform-development.md +93 -2
- package/skills/void/docs/guide/project-collaboration.md +94 -0
- package/skills/void/docs/guide/self-hosted-platform.md +184 -30
- package/skills/void/docs/reference/cli.md +294 -15
- package/dist/cf-access-AJ1ehiFR.mjs +0 -42
- package/dist/cf-access-DsSsZUPr.mjs +0 -67
- package/dist/email-r6DHJyAB.mjs +0 -262
package/dist/email-r6DHJyAB.mjs
DELETED
|
@@ -1,262 +0,0 @@
|
|
|
1
|
-
import { D as log, F as isCancel, O as note, c as import_picocolors, w as confirm } from "./output-tFQLLj26.mjs";
|
|
2
|
-
import { C as renderAddressMap, S as preflightEmail, a as isWranglerNonInteractiveOrCI, b as createNodeEmailDns, i as discoverRootWranglerConfig, o as loadProvisionModule, r as deriveWorkerName, s as resolveDeployTransport, t as createDeployWranglerRunner, u as runWranglerAuthToken, w as renderEmailChecklist, x as findEmailConfigConflicts, y as applyEmailSetup } from "./deploy-CcDoeBIf.mjs";
|
|
3
|
-
import { n as readProjectPaths } from "./project-paths-SK8nMHPp.mjs";
|
|
4
|
-
import { c as getToken, x as readProjectConfig } from "./auth-W9WII-mN.mjs";
|
|
5
|
-
import { k as writeProvisionedWranglerConfig } from "./wrangler--imS8n0d.mjs";
|
|
6
|
-
import { f as readConfig } from "./config-BQFq7QvD.mjs";
|
|
7
|
-
import { a as scanEmailHandlersSync } from "./email-Ce6SQq-i.mjs";
|
|
8
|
-
import { n as PlatformClient } from "./client-CyCHWSO_.mjs";
|
|
9
|
-
import { parseRootWranglerConfig, readWranglerTopLevelString } from "@void/deploy-cloudflare";
|
|
10
|
-
//#region src/cli/email.ts
|
|
11
|
-
async function runEmailCommand(root, args) {
|
|
12
|
-
if (args.platform === "cloudflare") return runEmailCloudflareCommand(root, args);
|
|
13
|
-
if (args.subcommand === "setup") {
|
|
14
|
-
log.error("email: `void email setup` sets email up on your OWN Cloudflare account — run it with `--platform cloudflare`. The Void platform needs no setup: deploy, and `void email usage` shows your address.");
|
|
15
|
-
process.exit(1);
|
|
16
|
-
}
|
|
17
|
-
if (args.subcommand === "status") {
|
|
18
|
-
log.error("email: `void email status` is available with `--platform cloudflare` today. On the Void platform use `void email usage` and `void email destinations`.");
|
|
19
|
-
process.exit(1);
|
|
20
|
-
}
|
|
21
|
-
const token = getToken(root);
|
|
22
|
-
if (!token) {
|
|
23
|
-
log.error("Not logged in. Run `void auth login` first.");
|
|
24
|
-
process.exit(1);
|
|
25
|
-
}
|
|
26
|
-
const client = new PlatformClient(token, { root });
|
|
27
|
-
const requestedSlug = args.projectSlug ?? process.env.VOID_PROJECT?.trim();
|
|
28
|
-
let projectId;
|
|
29
|
-
if (requestedSlug) {
|
|
30
|
-
const project = (await client.listProjects()).find((p) => p.slug === requestedSlug);
|
|
31
|
-
if (!project) {
|
|
32
|
-
log.error(`project: No project found with slug '${requestedSlug}'.`);
|
|
33
|
-
process.exit(1);
|
|
34
|
-
}
|
|
35
|
-
projectId = project.id;
|
|
36
|
-
} else {
|
|
37
|
-
const config = readProjectConfig(root);
|
|
38
|
-
if (!config) {
|
|
39
|
-
log.error("No linked project. Run `void project link` or pass --project <name>.");
|
|
40
|
-
process.exit(1);
|
|
41
|
-
}
|
|
42
|
-
projectId = config.projectId;
|
|
43
|
-
}
|
|
44
|
-
switch (args.subcommand) {
|
|
45
|
-
case "usage": return emailUsage(client, projectId);
|
|
46
|
-
case "logs": return emailLogs(client, projectId, args.limit);
|
|
47
|
-
case "destinations": return emailDestinations(client, projectId);
|
|
48
|
-
case "allow": return emailAllow(client, projectId, args.address);
|
|
49
|
-
case "disallow": return emailDisallow(client, projectId, args.address);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
async function emailUsage(client, projectId) {
|
|
53
|
-
const usage = await client.getEmailUsage(projectId);
|
|
54
|
-
const status = usage.suspended ? import_picocolors.default.red("SUSPENDED") : import_picocolors.default.green("active");
|
|
55
|
-
const lines = [
|
|
56
|
-
`Month: ${usage.month}`,
|
|
57
|
-
`Status: ${status}`,
|
|
58
|
-
`Outbound: ${usage.sent} / ${usage.limit} (${usage.remaining} remaining)`,
|
|
59
|
-
`Inbound: ${usage.received}`
|
|
60
|
-
];
|
|
61
|
-
note(lines.join("\n"), "Email Usage");
|
|
62
|
-
}
|
|
63
|
-
async function emailDestinations(client, projectId) {
|
|
64
|
-
const rows = await client.listEmailDestinations(projectId);
|
|
65
|
-
if (rows.length === 0) {
|
|
66
|
-
log.info("No verified destinations. Run `void email allow <address>` to add one — Cloudflare will email the recipient with a verification link.");
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
const lines = rows.map((d) => {
|
|
70
|
-
const status = d.status === "verified" ? import_picocolors.default.green("verified") : d.status === "pending" ? import_picocolors.default.yellow("pending") : import_picocolors.default.red("failed");
|
|
71
|
-
return ` ${d.address.padEnd(40)} ${status}`;
|
|
72
|
-
});
|
|
73
|
-
note(lines.join("\n"), "Email Destinations");
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* `void email allow <address>` — exported for the unit test; the command
|
|
77
|
-
* entry (`runEmailCommand`) resolves the client and project first.
|
|
78
|
-
*/
|
|
79
|
-
async function emailAllow(client, projectId, address) {
|
|
80
|
-
const dest = await client.addEmailDestination(projectId, address);
|
|
81
|
-
const sent = dest.verificationSent !== false && (dest.created || dest.platformVerificationPending);
|
|
82
|
-
if (dest.status === "verified") log.success(`${dest.address} is already verified.`);
|
|
83
|
-
else if (sent) {
|
|
84
|
-
log.success(`Verification email sent to ${dest.address}.`);
|
|
85
|
-
log.info("They click the link in their inbox — no Void or Cloudflare account needed. `void email destinations` to poll status.");
|
|
86
|
-
} else if (dest.created) log.warn(`${dest.address} is on this project's list now, but Cloudflare already had the address pending (added by another project, or by hand), so no new verification email was sent — the link it mailed when the address was first added is the one to click. ${freshLinkHint(dest.address)}`);
|
|
87
|
-
else log.info(`${dest.address} is still pending — Cloudflare emailed them a verification link when the address was first added, and a repeat add sends nothing new. ${freshLinkHint(dest.address)}`);
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* Cloudflare has no API to resend its verification mail; the only fresh link
|
|
91
|
-
* is a fresh registration, and the platform deletes the Cloudflare-side
|
|
92
|
-
* address only once no project still lists it.
|
|
93
|
-
*/
|
|
94
|
-
function freshLinkHint(address) {
|
|
95
|
-
return `For a fresh link, remove the address from every project that lists it (\`void email disallow ${address}\`), then \`void email allow ${address}\` — Cloudflare mails a new link only when it registers the address anew.`;
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* `void email disallow <address>` — exported for the unit test; the command
|
|
99
|
-
* entry (`runEmailCommand`) resolves the client and project first.
|
|
100
|
-
*
|
|
101
|
-
* No deploy is involved: the api tightens the proxy's `email-allowlist`
|
|
102
|
-
* KV mirror inside the DELETE (and answers 503 if that write fails), and
|
|
103
|
-
* the proxy re-reads the mirror with a 60s `cacheTtl` on both the send
|
|
104
|
-
* path and inbound forward/reply — so the address is refused once that
|
|
105
|
-
* per-colo cache turns over.
|
|
106
|
-
*/
|
|
107
|
-
async function emailDisallow(client, projectId, address) {
|
|
108
|
-
const dest = (await client.listEmailDestinations(projectId)).find((d) => d.address.toLowerCase() === address.toLowerCase());
|
|
109
|
-
if (!dest) {
|
|
110
|
-
log.error(`destination: '${address}' is not in the project's allowlist.`);
|
|
111
|
-
process.exit(1);
|
|
112
|
-
}
|
|
113
|
-
await client.removeEmailDestination(projectId, dest.id);
|
|
114
|
-
log.success(`Removed ${dest.address}. Sends to it are refused within about a minute.`);
|
|
115
|
-
}
|
|
116
|
-
/**
|
|
117
|
-
* `void email logs` — exported for the unit test; the command entry
|
|
118
|
-
* (`runEmailCommand`) resolves the client and project first.
|
|
119
|
-
*/
|
|
120
|
-
async function emailLogs(client, projectId, limit) {
|
|
121
|
-
const result = await client.getEmailLogs(projectId, limit);
|
|
122
|
-
if (result.pending) {
|
|
123
|
-
log.info(result.note ?? "Persistent log storage is not yet wired up.");
|
|
124
|
-
log.info("Email activity logs are not available yet. Console output from your email handler appears in `void project logs`.");
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
if (result.logs.length === 0) {
|
|
128
|
-
log.info("No email activity recorded.");
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
const lines = result.logs.map((entry) => {
|
|
132
|
-
const ts = new Date(entry.timestamp).toISOString();
|
|
133
|
-
const dir = entry.direction === "sent" ? "→" : "←";
|
|
134
|
-
const subject = entry.subject ? ` "${entry.subject}"` : "";
|
|
135
|
-
return `${ts} ${dir} ${entry.from} → ${entry.to} ${entry.status}${subject}`;
|
|
136
|
-
});
|
|
137
|
-
note(lines.join("\n"), "Email Logs");
|
|
138
|
-
}
|
|
139
|
-
/**
|
|
140
|
-
* `void email setup --platform cloudflare` and `void email status --platform cloudflare`.
|
|
141
|
-
*
|
|
142
|
-
* `setup` is the deploy's step 3b-ii on its own: preflight → checklist → the one Enter →
|
|
143
|
-
* apply → write the root wrangler.jsonc. It exists for CI: a non-interactive deploy that
|
|
144
|
-
* finds email not ready prints the checklist and says to run this once, commit
|
|
145
|
-
* wrangler.jsonc, and redeploy. Rules and the catch-all stay wrangler's job — the next
|
|
146
|
-
* `void deploy --platform cloudflare` applies the plan from the written `addresses`. It
|
|
147
|
-
* is also the ONLY place a sending onboarding the committed binding remembers as refused
|
|
148
|
-
* (Workers Free) is retried — on its own prompt, after a Workers Paid upgrade; the deploy
|
|
149
|
-
* reads that row as settled and never retries it.
|
|
150
|
-
*
|
|
151
|
-
* `status` is the preflight alone, printed, exit 1 when not ready.
|
|
152
|
-
*/
|
|
153
|
-
async function runEmailCloudflareCommand(root, args, deps = {}) {
|
|
154
|
-
const exit = deps.exit ?? ((code) => process.exit(code));
|
|
155
|
-
const print = deps.print ?? ((block) => log.message(block));
|
|
156
|
-
const fail = (message) => {
|
|
157
|
-
log.error(message);
|
|
158
|
-
return exit(1);
|
|
159
|
-
};
|
|
160
|
-
const from = readConfig(root).email?.from;
|
|
161
|
-
if (!from) return fail("email: no sender configured. Add \"email\": { \"from\": \"you@mail.acme.com\" } to void.json — its host is the domain email is set up on.");
|
|
162
|
-
const paths = readProjectPaths(root);
|
|
163
|
-
const handlers = scanEmailHandlersSync(paths.sourceRoot);
|
|
164
|
-
const configPath = discoverRootWranglerConfig(root);
|
|
165
|
-
const rootConfig = parseRootWranglerConfig(configPath);
|
|
166
|
-
await loadProvisionModule();
|
|
167
|
-
let apiBaseUrl;
|
|
168
|
-
try {
|
|
169
|
-
apiBaseUrl = resolveDeployTransport(root, rootConfig);
|
|
170
|
-
} catch (err) {
|
|
171
|
-
return fail(`email: ${err instanceof Error ? err.message : String(err)}`);
|
|
172
|
-
}
|
|
173
|
-
const accountId = readWranglerTopLevelString(rootConfig, "account_id") ?? (process.env.CLOUDFLARE_ACCOUNT_ID?.trim() || void 0);
|
|
174
|
-
if (!accountId) return fail([
|
|
175
|
-
"email: no Cloudflare account is pinned.",
|
|
176
|
-
"Set `account_id` in your root wrangler.jsonc, or export CLOUDFLARE_ACCOUNT_ID —",
|
|
177
|
-
"the same pin `void deploy --platform cloudflare` needs."
|
|
178
|
-
].join("\n"));
|
|
179
|
-
const workerName = readWranglerTopLevelString(rootConfig, "name") ?? deriveWorkerName(root);
|
|
180
|
-
const runWrangler = deps.runWrangler ?? createDeployWranglerRunner(root, accountId, apiBaseUrl);
|
|
181
|
-
const getSessionBearer = deps.getSessionBearer ?? (() => runWranglerAuthToken(runWrangler, configPath));
|
|
182
|
-
const sendEmail = rootConfig.send_email;
|
|
183
|
-
const inputs = {
|
|
184
|
-
handlers,
|
|
185
|
-
from,
|
|
186
|
-
workerName,
|
|
187
|
-
accountId,
|
|
188
|
-
existingSendEmail: Array.isArray(sendEmail) ? sendEmail : null,
|
|
189
|
-
existingAddresses: rootConfig.addresses,
|
|
190
|
-
existingVars: rootConfig.vars && typeof rootConfig.vars === "object" && !Array.isArray(rootConfig.vars) ? rootConfig.vars : null,
|
|
191
|
-
configConflicts: findEmailConfigConflicts(rootConfig),
|
|
192
|
-
wranglerArgs: [
|
|
193
|
-
"-c",
|
|
194
|
-
configPath,
|
|
195
|
-
"--env="
|
|
196
|
-
],
|
|
197
|
-
apiBaseUrl,
|
|
198
|
-
runWrangler,
|
|
199
|
-
getSessionBearer,
|
|
200
|
-
fetchImpl: deps.fetchImpl ?? fetch,
|
|
201
|
-
dns: deps.dns ?? await createNodeEmailDns()
|
|
202
|
-
};
|
|
203
|
-
let pre;
|
|
204
|
-
try {
|
|
205
|
-
pre = await preflightEmail(inputs);
|
|
206
|
-
} catch (err) {
|
|
207
|
-
return fail(`email: ${err instanceof Error ? err.message : String(err)}`);
|
|
208
|
-
}
|
|
209
|
-
print(renderEmailChecklist(pre));
|
|
210
|
-
if (args.subcommand === "status") {
|
|
211
|
-
print(renderAddressMap({
|
|
212
|
-
from,
|
|
213
|
-
routes: pre.derived.routes,
|
|
214
|
-
addresses: pre.rules.mine,
|
|
215
|
-
sendingReady: pre.sending.state === "ready",
|
|
216
|
-
pendingLabel: "(no rule yet)"
|
|
217
|
-
}));
|
|
218
|
-
if (pre.ready) {
|
|
219
|
-
log.success(`Email is set up on ${pre.domain}.`);
|
|
220
|
-
return;
|
|
221
|
-
}
|
|
222
|
-
log.warn(`Email is not set up on ${pre.domain} yet — run \`void email setup --platform cloudflare\`.`);
|
|
223
|
-
return exit(1);
|
|
224
|
-
}
|
|
225
|
-
if (pre.blockers.some((b) => b.scope === "all")) return fail("email: nothing was changed — fix the ✘ rows above and rerun.");
|
|
226
|
-
if (!pre.ready || pre.sendingRetryable) {
|
|
227
|
-
if (!(deps.isInteractive ?? !isWranglerNonInteractiveOrCI())) return fail("email: `void email setup` changes your Cloudflare account, so it needs an interactive terminal. Run it locally once, commit wrangler.jsonc, then redeploy.");
|
|
228
|
-
if (!await (deps.confirm ?? (async (message) => {
|
|
229
|
-
const answer = await confirm({
|
|
230
|
-
message,
|
|
231
|
-
initialValue: true
|
|
232
|
-
});
|
|
233
|
-
return !isCancel(answer) && answer === true;
|
|
234
|
-
}))(pre.ready ? `Onboard ${pre.domain} for Email Sending? Inbound already works; onboarding needs Workers Paid.` : `Set up email on ${pre.domain}?`)) {
|
|
235
|
-
log.info("Nothing changed.");
|
|
236
|
-
return;
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
const out = await applyEmailSetup(pre, inputs);
|
|
240
|
-
if (out.lines.length > 0) print(out.lines.join("\n"));
|
|
241
|
-
try {
|
|
242
|
-
writeProvisionedWranglerConfig(root, out.patch, { configPath });
|
|
243
|
-
} catch (err) {
|
|
244
|
-
return fail(`email: could not update ${configPath} — ${err instanceof Error ? err.message : String(err)}`);
|
|
245
|
-
}
|
|
246
|
-
print(renderAddressMap({
|
|
247
|
-
from,
|
|
248
|
-
routes: pre.derived.routes,
|
|
249
|
-
addresses: out.patch.addresses ?? [],
|
|
250
|
-
sendingReady: out.sendingReady,
|
|
251
|
-
pendingLabel: "(no rule yet)"
|
|
252
|
-
}));
|
|
253
|
-
if (!out.inboundReady) {
|
|
254
|
-
const missing = !out.routingReady ? `Email Routing on ${pre.domain} is not ready` : !out.subaddressingReady ? `subaddressing on ${pre.apex} is still off (support+anything@ would not reach support@)` : "`addresses` was withheld";
|
|
255
|
-
log.warn(`Email is not set up on ${pre.domain} yet — ${missing}; no routing rule is created until it is. Finish the step above, then rerun \`void email setup --platform cloudflare\`.`);
|
|
256
|
-
return exit(1);
|
|
257
|
-
}
|
|
258
|
-
if ((out.patch.addresses ?? []).length > 0) log.info("Routing rules are created by the next `void deploy --platform cloudflare`, which applies the Email Routing plan from `addresses`.");
|
|
259
|
-
log.success(`Email set up on ${pre.domain}.`);
|
|
260
|
-
}
|
|
261
|
-
//#endregion
|
|
262
|
-
export { runEmailCommand };
|