hatchkit 0.1.2 → 0.1.4

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.
Files changed (113) hide show
  1. package/dist/completion.d.ts +2 -0
  2. package/dist/completion.d.ts.map +1 -0
  3. package/dist/completion.js +207 -0
  4. package/dist/completion.js.map +1 -0
  5. package/dist/config.d.ts +33 -1
  6. package/dist/config.d.ts.map +1 -1
  7. package/dist/config.js +439 -127
  8. package/dist/config.js.map +1 -1
  9. package/dist/deploy/coolify-mongo.d.ts +12 -0
  10. package/dist/deploy/coolify-mongo.d.ts.map +1 -0
  11. package/dist/deploy/coolify-mongo.js +109 -0
  12. package/dist/deploy/coolify-mongo.js.map +1 -0
  13. package/dist/deploy/gpu.d.ts +9 -2
  14. package/dist/deploy/gpu.d.ts.map +1 -1
  15. package/dist/deploy/gpu.js +63 -39
  16. package/dist/deploy/gpu.js.map +1 -1
  17. package/dist/deploy/keys.d.ts +6 -2
  18. package/dist/deploy/keys.d.ts.map +1 -1
  19. package/dist/deploy/keys.js +16 -2
  20. package/dist/deploy/keys.js.map +1 -1
  21. package/dist/deploy/pages.d.ts +2 -0
  22. package/dist/deploy/pages.d.ts.map +1 -0
  23. package/dist/deploy/pages.js +537 -0
  24. package/dist/deploy/pages.js.map +1 -0
  25. package/dist/deploy/rename-domain.d.ts +55 -0
  26. package/dist/deploy/rename-domain.d.ts.map +1 -0
  27. package/dist/deploy/rename-domain.js +290 -0
  28. package/dist/deploy/rename-domain.js.map +1 -0
  29. package/dist/deploy/terraform.d.ts.map +1 -1
  30. package/dist/deploy/terraform.js +90 -0
  31. package/dist/deploy/terraform.js.map +1 -1
  32. package/dist/dns.d.ts +7 -0
  33. package/dist/dns.d.ts.map +1 -0
  34. package/dist/dns.js +124 -0
  35. package/dist/dns.js.map +1 -0
  36. package/dist/doctor.d.ts +13 -0
  37. package/dist/doctor.d.ts.map +1 -0
  38. package/dist/doctor.js +368 -0
  39. package/dist/doctor.js.map +1 -0
  40. package/dist/explain.d.ts +4 -0
  41. package/dist/explain.d.ts.map +1 -0
  42. package/dist/explain.js +173 -0
  43. package/dist/explain.js.map +1 -0
  44. package/dist/index.js +521 -61
  45. package/dist/index.js.map +1 -1
  46. package/dist/prompts.d.ts +15 -2
  47. package/dist/prompts.d.ts.map +1 -1
  48. package/dist/prompts.js +52 -7
  49. package/dist/prompts.js.map +1 -1
  50. package/dist/provision/glitchtip.d.ts +3 -0
  51. package/dist/provision/glitchtip.d.ts.map +1 -1
  52. package/dist/provision/glitchtip.js +18 -0
  53. package/dist/provision/glitchtip.js.map +1 -1
  54. package/dist/provision/index.d.ts +26 -0
  55. package/dist/provision/index.d.ts.map +1 -1
  56. package/dist/provision/index.js +435 -60
  57. package/dist/provision/index.js.map +1 -1
  58. package/dist/provision/openpanel.d.ts +7 -0
  59. package/dist/provision/openpanel.d.ts.map +1 -1
  60. package/dist/provision/openpanel.js +113 -48
  61. package/dist/provision/openpanel.js.map +1 -1
  62. package/dist/provision/resend.d.ts +23 -1
  63. package/dist/provision/resend.d.ts.map +1 -1
  64. package/dist/provision/resend.js +62 -1
  65. package/dist/provision/resend.js.map +1 -1
  66. package/dist/provision/write-env.d.ts +31 -0
  67. package/dist/provision/write-env.d.ts.map +1 -0
  68. package/dist/provision/write-env.js +94 -0
  69. package/dist/provision/write-env.js.map +1 -0
  70. package/dist/scaffold/app.js +8 -0
  71. package/dist/scaffold/app.js.map +1 -1
  72. package/dist/scaffold/dotenvx.d.ts.map +1 -1
  73. package/dist/scaffold/dotenvx.js +8 -1
  74. package/dist/scaffold/dotenvx.js.map +1 -1
  75. package/dist/scaffold/infra.d.ts.map +1 -1
  76. package/dist/scaffold/infra.js +18 -1
  77. package/dist/scaffold/infra.js.map +1 -1
  78. package/dist/scaffold/manifest.d.ts +4 -2
  79. package/dist/scaffold/manifest.d.ts.map +1 -1
  80. package/dist/scaffold/manifest.js +1 -1
  81. package/dist/scaffold/manifest.js.map +1 -1
  82. package/dist/scaffold/ml-client.d.ts +9 -2
  83. package/dist/scaffold/ml-client.d.ts.map +1 -1
  84. package/dist/scaffold/ml-client.js +11 -1
  85. package/dist/scaffold/ml-client.js.map +1 -1
  86. package/dist/status.d.ts +30 -0
  87. package/dist/status.d.ts.map +1 -0
  88. package/dist/status.js +169 -0
  89. package/dist/status.js.map +1 -0
  90. package/dist/templates/addons/analytics/sentry.ts.hbs +6 -0
  91. package/dist/templates/base/env.example.hbs +10 -0
  92. package/dist/templates/base/src/config.ts.hbs +24 -4
  93. package/dist/utils/cloudflare-api.d.ts +30 -0
  94. package/dist/utils/cloudflare-api.d.ts.map +1 -0
  95. package/dist/utils/cloudflare-api.js +85 -0
  96. package/dist/utils/cloudflare-api.js.map +1 -0
  97. package/dist/utils/coolify-api.d.ts +47 -1
  98. package/dist/utils/coolify-api.d.ts.map +1 -1
  99. package/dist/utils/coolify-api.js +75 -4
  100. package/dist/utils/coolify-api.js.map +1 -1
  101. package/dist/utils/flags.d.ts.map +1 -1
  102. package/dist/utils/flags.js +4 -0
  103. package/dist/utils/flags.js.map +1 -1
  104. package/dist/utils/inwx-api.d.ts +36 -0
  105. package/dist/utils/inwx-api.d.ts.map +1 -0
  106. package/dist/utils/inwx-api.js +105 -0
  107. package/dist/utils/inwx-api.js.map +1 -0
  108. package/dist/utils/secrets.d.ts +8 -1
  109. package/dist/utils/secrets.d.ts.map +1 -1
  110. package/dist/utils/secrets.js +8 -1
  111. package/dist/utils/secrets.js.map +1 -1
  112. package/package.json +5 -4
  113. package/scripts/release-prep.mjs +130 -0
@@ -0,0 +1,290 @@
1
+ /*
2
+ * rename-domain — move a scaffolded project from one domain to another.
3
+ *
4
+ * Rewrites every file hatchkit owns that hard-codes the old domain:
5
+ *
6
+ * <project>/.hatchkit.json — manifest `domain` field
7
+ * <infra>/terraform/stacks/<stack>/<name>.tfvars
8
+ * — `domain` + remapped
9
+ * `subdomains` keys
10
+ * <infra>/stacks/<name>.env (Coolify env) — APP_DOMAIN + any other
11
+ * line containing the old
12
+ * full-domain string
13
+ *
14
+ * Intentionally does NOT run `terraform apply` or touch Coolify's live
15
+ * app state. Those are destructive, out-of-band operations the user
16
+ * should review the planned diff for first. A detailed follow-up
17
+ * checklist is printed at the end covering:
18
+ * - terraform apply (destroys old records, creates new in new zone)
19
+ * - the Coolify app's FQDN + env (update in dashboard or via API)
20
+ * - gh-pages CNAME (if applicable)
21
+ * - OAuth redirect URIs at Google / GitHub / Stripe / Resend
22
+ * - any hardcoded URLs in the app's own code
23
+ */
24
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
25
+ import { basename, join, resolve } from "node:path";
26
+ import { confirm, input } from "@inquirer/prompts";
27
+ import chalk from "chalk";
28
+ import { readManifest } from "../scaffold/manifest.js";
29
+ import { parseDomain, validateDomain } from "../utils/validate.js";
30
+ export async function runRenameDomain(opts) {
31
+ const { projectDir, monorepoRoot } = opts;
32
+ // 1. Manifest
33
+ const manifest = readManifest(projectDir);
34
+ if (!manifest) {
35
+ throw new Error(`No .hatchkit.json found in ${projectDir}. Run rename-domain from the project root (or pass --dir).`);
36
+ }
37
+ const oldDomain = manifest.domain;
38
+ // 2. Target domain
39
+ const newDomain = opts.newDomain ??
40
+ (await input({
41
+ message: `New domain for ${chalk.cyan(manifest.name)} (was ${chalk.dim(oldDomain)}):`,
42
+ validate: validateDomain,
43
+ }));
44
+ const newValid = validateDomain(newDomain);
45
+ if (newValid !== true)
46
+ throw new Error(`--to invalid: ${newValid}`);
47
+ if (newDomain === oldDomain) {
48
+ console.log(chalk.yellow(` ${oldDomain} is already the current domain — nothing to do.`));
49
+ return;
50
+ }
51
+ const { baseDomain: oldBase, subdomain: oldSub } = parseDomain(oldDomain);
52
+ const { baseDomain: newBase, subdomain: newSub } = parseDomain(newDomain);
53
+ console.log(chalk.bold("\n ── hatchkit rename-domain ─────────────────────────────────\n"));
54
+ console.log(` Project: ${chalk.cyan(manifest.name)}`);
55
+ console.log(` From → To: ${chalk.dim(oldDomain)} → ${chalk.green(newDomain)}`);
56
+ if (!newSub) {
57
+ console.log(chalk.yellow(` Note: ${newDomain} has no subdomain prefix. Apex DNS records are required — verify your terraform module supports them before applying.`));
58
+ }
59
+ // 3. Collect edit plan
60
+ const edits = [];
61
+ // 3a. Manifest — just swap the `domain` field.
62
+ const manifestPath = join(projectDir, ".hatchkit.json");
63
+ edits.push(rewriteManifest(manifestPath, manifest, newDomain));
64
+ // 3b. Terraform tfvars — `dns-only` if deployTarget === "existing",
65
+ // else `node-realtime`. Mirror the logic in deploy/terraform.ts.
66
+ const stackDirName = manifest.deployTarget === "existing" ? "dns-only" : "node-realtime";
67
+ const tfvarsPath = join(monorepoRoot, "infra", "terraform", "stacks", stackDirName, `${manifest.name}.tfvars`);
68
+ if (existsSync(tfvarsPath)) {
69
+ edits.push(rewriteTfvars(tfvarsPath, oldDomain, newDomain, oldSub, newSub, newBase, oldBase));
70
+ }
71
+ else {
72
+ console.log(chalk.yellow(` ! No tfvars at ${tfvarsPath.slice(monorepoRoot.length + 1)} — skipping terraform bit.`));
73
+ }
74
+ // 3c. Coolify stack env — at `<infra>/stacks/<name>.env` or
75
+ // `<monorepo>/stacks/<name>.env`. Match infra.ts's write path.
76
+ const stacksPath = findStacksEnv(monorepoRoot, manifest.name);
77
+ if (stacksPath) {
78
+ edits.push(rewriteStacksEnv(stacksPath, oldDomain, newDomain, oldBase, newBase));
79
+ }
80
+ else {
81
+ console.log(chalk.yellow(` ! No stacks/${manifest.name}.env found — skipping Coolify env bit. (You may need to set APP_DOMAIN manually in the Coolify dashboard.)`));
82
+ }
83
+ // 4. Plan
84
+ console.log(chalk.bold("\n ── Planned file changes ───────────────────────────────────\n"));
85
+ for (const edit of edits) {
86
+ console.log(` ${chalk.cyan(edit.label)}`);
87
+ for (const change of edit.changes) {
88
+ console.log(chalk.dim(` - ${change}`));
89
+ }
90
+ }
91
+ if (opts.dryRun) {
92
+ console.log(chalk.yellow("\n [dry-run] No files written."));
93
+ printChecklist(manifest, oldDomain, newDomain, stackDirName);
94
+ return;
95
+ }
96
+ // 5. Confirm
97
+ if (!opts.yes) {
98
+ const ok = await confirm({
99
+ message: `Rewrite ${edits.length} file(s)?`,
100
+ default: true,
101
+ });
102
+ if (!ok) {
103
+ console.log(chalk.dim(" Cancelled."));
104
+ return;
105
+ }
106
+ }
107
+ // 6. Apply
108
+ for (const edit of edits) {
109
+ writeFileSync(edit.path, edit.after);
110
+ console.log(chalk.green(` ✓ wrote ${edit.label}`));
111
+ }
112
+ printChecklist(manifest, oldDomain, newDomain, stackDirName);
113
+ }
114
+ function rewriteManifest(path, m, newDomain) {
115
+ const next = { ...m, domain: newDomain };
116
+ return {
117
+ label: basename(path),
118
+ path,
119
+ after: `${JSON.stringify(next, null, 2)}\n`,
120
+ changes: [`domain: "${m.domain}" → "${newDomain}"`],
121
+ };
122
+ }
123
+ /**
124
+ * Edit the tfvars file. Two surgical changes + a remap of subdomain keys.
125
+ *
126
+ * The tfvars file was generated from a template, so the format is
127
+ * predictable. Matching `domain = "..."` and the opening of the
128
+ * `subdomains = { ... }` block with regex is safer than a full parser
129
+ * for this narrow use.
130
+ */
131
+ function rewriteTfvars(path, oldDomain, newDomain, oldSub, newSub, newBase, oldBase) {
132
+ const before = readFileSync(path, "utf8");
133
+ let after = before;
134
+ const changes = [];
135
+ // domain = "OLD" → domain = "NEWBASE"
136
+ const domainRe = /(\bdomain\s*=\s*")([^"]+)(")/;
137
+ if (domainRe.test(after)) {
138
+ after = after.replace(domainRe, (_m, pre, _val, post) => `${pre}${newBase}${post}`);
139
+ changes.push(`domain: "${oldBase}" → "${newBase}"`);
140
+ }
141
+ // subdomains map remapping. Old key "OLDSUB" or "api.OLDSUB" maps to
142
+ // the new subdomain prefix. Keys that don't involve the old subdomain
143
+ // (e.g. "admin") pass through untouched.
144
+ const keyRemap = {
145
+ [oldSub]: newSub || "@",
146
+ [`api.${oldSub}`]: newSub ? `api.${newSub}` : "api",
147
+ };
148
+ // Match `"KEY" = "VALUE"` lines inside the subdomains block.
149
+ const entryRe = /"([^"]+)"\s*=\s*"([^"]+)"/g;
150
+ after = after.replace(entryRe, (full, key, val) => {
151
+ // Only remap keys we know about — leave anything else alone.
152
+ if (keyRemap[key] !== undefined) {
153
+ const newKey = keyRemap[key];
154
+ if (newKey !== key) {
155
+ changes.push(`subdomains key "${key}" → "${newKey}"`);
156
+ return `"${newKey}" = "${val}"`;
157
+ }
158
+ }
159
+ return full;
160
+ });
161
+ // Belt and braces: any lingering mention of the old full domain in a
162
+ // comment line gets swapped for clarity. Safe because tfvars doesn't
163
+ // use the old domain as a string value anywhere else.
164
+ if (after.includes(oldDomain)) {
165
+ const count = after.split(oldDomain).length - 1;
166
+ after = after.split(oldDomain).join(newDomain);
167
+ changes.push(`${count} stray "${oldDomain}" → "${newDomain}"`);
168
+ }
169
+ return {
170
+ label: path.split("/").slice(-4).join("/"),
171
+ path,
172
+ after,
173
+ changes: changes.length > 0 ? changes : ["(no changes detected)"],
174
+ };
175
+ }
176
+ /**
177
+ * Edit the Coolify stack env file. This is a plain KEY="VALUE" block,
178
+ * not a strict format — do line-by-line substitution so we don't clobber
179
+ * unrelated lines and keep the diff obvious.
180
+ *
181
+ * Swaps:
182
+ * - APP_DOMAIN="OLD" → "NEW"
183
+ * - Any other line whose value contains the old full domain gets the
184
+ * old-full-domain → new-full-domain swap (catches FRONTEND_URL,
185
+ * BETTER_AUTH_URL, TRUSTED_ORIGINS, etc).
186
+ * - Lines with the old base domain (but not the old full domain) are
187
+ * left alone — those usually refer to someone else's URL.
188
+ *
189
+ * COOLIFY_URL is explicitly skipped — that's the Coolify dashboard URL,
190
+ * not the project's public domain.
191
+ */
192
+ function rewriteStacksEnv(path, oldDomain, newDomain, _oldBase, _newBase) {
193
+ const before = readFileSync(path, "utf8");
194
+ const lines = before.split("\n");
195
+ const changes = [];
196
+ const next = lines.map((line) => {
197
+ // Skip comments, blanks, and Coolify's own dashboard URL.
198
+ if (line.trim().startsWith("#") || line.trim() === "")
199
+ return line;
200
+ if (line.startsWith("COOLIFY_URL"))
201
+ return line;
202
+ if (line.includes(oldDomain)) {
203
+ const replaced = line.split(oldDomain).join(newDomain);
204
+ const key = line.split("=")[0];
205
+ changes.push(`${key}: swapped "${oldDomain}" → "${newDomain}"`);
206
+ return replaced;
207
+ }
208
+ return line;
209
+ });
210
+ return {
211
+ label: path.split("/").slice(-2).join("/"),
212
+ path,
213
+ after: next.join("\n"),
214
+ changes: changes.length > 0 ? changes : ["(no changes detected)"],
215
+ };
216
+ }
217
+ /**
218
+ * Locate the stacks/<name>.env file. During scaffold it's written
219
+ * under `infra/stacks/` (the infra submodule). Some layouts put it
220
+ * under `<monorepo>/stacks/` instead — check both.
221
+ */
222
+ function findStacksEnv(monorepoRoot, name) {
223
+ const candidates = [
224
+ join(monorepoRoot, "infra", "stacks", `${name}.env`),
225
+ join(monorepoRoot, "stacks", `${name}.env`),
226
+ ];
227
+ for (const c of candidates) {
228
+ if (existsSync(c))
229
+ return c;
230
+ }
231
+ return null;
232
+ }
233
+ // ---------------------------------------------------------------------------
234
+ // Follow-up checklist
235
+ // ---------------------------------------------------------------------------
236
+ function printChecklist(manifest, oldDomain, newDomain, stackDirName) {
237
+ const { baseDomain: newBase } = parseDomain(newDomain);
238
+ console.log(chalk.bold("\n ── Follow-up (hatchkit won't do these for you) ────────────\n"));
239
+ console.log(chalk.bold(" 1. DNS prerequisites"));
240
+ console.log(` Ensure the new zone ${chalk.cyan(newBase)} exists at your DNS provider.`);
241
+ console.log(chalk.dim(" For Cloudflare: add the zone in the CF dashboard (or via API), then"));
242
+ console.log(chalk.dim(" `hatchkit dns link-to-cloudflare` to flip INWX NS if relevant."));
243
+ console.log(chalk.bold("\n 2. Terraform"));
244
+ console.log(chalk.dim(` cd infra/terraform/stacks/${stackDirName}`));
245
+ console.log(chalk.dim(` terraform plan -var-file=${manifest.name}.tfvars`));
246
+ console.log(chalk.dim(` terraform apply -var-file=${manifest.name}.tfvars`));
247
+ console.log(chalk.dim(` (Destroys old records at ${oldDomain}, creates new ones at ${newDomain}.)`));
248
+ console.log(chalk.bold("\n 3. Coolify app"));
249
+ console.log(` Update the FQDN on the ${chalk.cyan(manifest.name)} app (Coolify dashboard → General),`);
250
+ console.log(` and confirm env vars like ${chalk.dim("FRONTEND_URL / BETTER_AUTH_URL / TRUSTED_ORIGINS")}`);
251
+ console.log(` moved across. Redeploy after updating — new TLS cert takes 1-3 min.`);
252
+ if (manifest.features.includes("stripe")) {
253
+ console.log(chalk.bold("\n 4. External integrations"));
254
+ console.log(` Update webhook URLs:`);
255
+ console.log(chalk.dim(` - Stripe dashboard → Developers → Webhooks (new URL)`));
256
+ console.log(chalk.dim(` - Any OAuth redirect URIs (Google, GitHub, Discord…)`));
257
+ }
258
+ else {
259
+ console.log(chalk.bold("\n 4. External integrations"));
260
+ console.log(chalk.dim(` Any OAuth redirect URIs (Google, GitHub, Discord…)`));
261
+ }
262
+ console.log(chalk.bold("\n 5. App code"));
263
+ console.log(chalk.dim(` grep -r "${oldDomain}" . and update any hardcoded references (README, OG tags, sitemap).`));
264
+ console.log();
265
+ }
266
+ // Re-export for testability.
267
+ export const _internals = {
268
+ rewriteTfvars,
269
+ rewriteStacksEnv,
270
+ rewriteManifest,
271
+ };
272
+ // ---------------------------------------------------------------------------
273
+ // CLI glue — thin wrapper the dispatcher calls.
274
+ // ---------------------------------------------------------------------------
275
+ export async function runRenameDomainCli(args, monorepoRoot) {
276
+ const positional = args.filter((a) => !a.startsWith("--"));
277
+ const flagValue = (name) => {
278
+ const i = args.findIndex((a) => a === `--${name}`);
279
+ if (i >= 0 && args[i + 1])
280
+ return args[i + 1];
281
+ return undefined;
282
+ };
283
+ const newDomain = flagValue("to") ?? positional[0];
284
+ const dirArg = flagValue("dir");
285
+ const dryRun = args.includes("--dry-run");
286
+ const yes = args.includes("--yes") || args.includes("-y");
287
+ const projectDir = dirArg ? resolve(dirArg) : resolve(".");
288
+ await runRenameDomain({ projectDir, monorepoRoot, newDomain, dryRun, yes });
289
+ }
290
+ //# sourceMappingURL=rename-domain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rename-domain.js","sourceRoot":"","sources":["../../src/deploy/rename-domain.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"terraform.d.ts","sourceRoot":"","sources":["../../src/deploy/terraform.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAGnD,qCAAqC;AACrC,wBAAsB,YAAY,CAAC,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAkEzF"}
1
+ {"version":3,"file":"terraform.d.ts","sourceRoot":"","sources":["../../src/deploy/terraform.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAInD,qCAAqC;AACrC,wBAAsB,YAAY,CAAC,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA2FzF"}
@@ -2,6 +2,7 @@ import { join } from "node:path";
2
2
  import chalk from "chalk";
3
3
  import { getDnsConfig, getHetznerToken, getS3Config } from "../config.js";
4
4
  import { exec, execStream } from "../utils/exec.js";
5
+ import { InwxApi } from "../utils/inwx-api.js";
5
6
  /** Run Terraform for the project. */
6
7
  export async function runTerraform(config, repoRoot) {
7
8
  const hetznerToken = await getHetznerToken();
@@ -15,10 +16,24 @@ export async function runTerraform(config, repoRoot) {
15
16
  if (hetznerToken) {
16
17
  env.TF_VAR_hcloud_token = hetznerToken;
17
18
  }
19
+ // DNS credentials. The stack's dns_provider variable decides which
20
+ // provider actually *applies* records, but the INWX Terraform provider
21
+ // calls account.login during Configure() regardless, so valid INWX
22
+ // creds must always be passed through when we have them. Either the
23
+ // primary DNS creds (provider = "inwx") or the registrar creds
24
+ // (provider = "cloudflare" with INWX still holding the domain) satisfy
25
+ // that requirement.
18
26
  if (dnsConfig?.provider === "inwx") {
19
27
  env.TF_VAR_inwx_username = dnsConfig.username || "";
20
28
  env.TF_VAR_inwx_password = dnsConfig.password || "";
21
29
  }
30
+ else if (dnsConfig?.provider === "cloudflare") {
31
+ env.TF_VAR_cloudflare_api_token = dnsConfig.apiToken || "";
32
+ if (dnsConfig.registrarUsername && dnsConfig.registrarPassword) {
33
+ env.TF_VAR_inwx_username = dnsConfig.registrarUsername;
34
+ env.TF_VAR_inwx_password = dnsConfig.registrarPassword;
35
+ }
36
+ }
22
37
  if (config.features.includes("s3") &&
23
38
  config.s3Provider !== "existing" &&
24
39
  config.s3Provider !== "none") {
@@ -51,5 +66,80 @@ export async function runTerraform(config, repoRoot) {
51
66
  throw new Error("Terraform apply failed");
52
67
  }
53
68
  console.log(chalk.green("\n ✓ Terraform apply complete"));
69
+ // Post-apply: if we just deployed to Cloudflare but the domain is
70
+ // still registered at INWX, update INWX's delegated NS to point at
71
+ // Cloudflare. This is the "auto-wire" step that would otherwise
72
+ // require clicking through the INWX web UI for every domain.
73
+ if (dnsConfig?.provider === "cloudflare" &&
74
+ dnsConfig.registrarUsername &&
75
+ dnsConfig.registrarPassword) {
76
+ await updateInwxNameserversFromTfOutput(stackDir, env, dnsConfig);
77
+ }
78
+ }
79
+ /**
80
+ * Read the stack's dns_provider + dns_domain + dns_nameservers outputs
81
+ * and push them to INWX as the new delegated NS for that domain. No-op
82
+ * if the stack didn't actually apply a Cloudflare zone (e.g. user kept
83
+ * dns_provider = "inwx" in tfvars even though their CLI config says
84
+ * Cloudflare).
85
+ */
86
+ async function updateInwxNameserversFromTfOutput(stackDir, env, dnsConfig) {
87
+ const out = await exec("terraform", ["output", "-json"], {
88
+ cwd: stackDir,
89
+ env,
90
+ silent: true,
91
+ });
92
+ if (out.exitCode !== 0) {
93
+ console.log(chalk.yellow(" ! Could not read terraform outputs — skipping INWX NS update"));
94
+ return;
95
+ }
96
+ let parsed;
97
+ try {
98
+ parsed = JSON.parse(out.stdout);
99
+ }
100
+ catch {
101
+ console.log(chalk.yellow(" ! terraform output -json was not valid JSON — skipping INWX NS update"));
102
+ return;
103
+ }
104
+ const appliedProvider = parsed.dns_provider?.value;
105
+ const domain = parsed.dns_domain?.value;
106
+ const nameservers = parsed.dns_nameservers?.value ?? [];
107
+ if (appliedProvider !== "cloudflare") {
108
+ // User explicitly picked INWX for this stack in tfvars — don't touch
109
+ // the registrar even though their CLI config defaults to Cloudflare.
110
+ return;
111
+ }
112
+ if (!domain || nameservers.length === 0) {
113
+ console.log(chalk.yellow(" ! No Cloudflare nameservers in terraform output — skipping INWX NS update"));
114
+ return;
115
+ }
116
+ console.log(chalk.bold("\n ── INWX registrar: pointing NS at Cloudflare ────────────\n"));
117
+ console.log(chalk.dim(` Domain: ${domain}`));
118
+ console.log(chalk.dim(` New NS: ${nameservers.join(", ")}`));
119
+ // registrarUsername/Password presence is guaranteed by the caller's
120
+ // guard — assert here to keep the types clean.
121
+ if (!dnsConfig.registrarUsername || !dnsConfig.registrarPassword) {
122
+ return;
123
+ }
124
+ const inwx = new InwxApi({
125
+ username: dnsConfig.registrarUsername,
126
+ password: dnsConfig.registrarPassword,
127
+ sandbox: process.env.INWX_SANDBOX === "1",
128
+ });
129
+ try {
130
+ await inwx.login();
131
+ await inwx.setDomainNameservers(domain, nameservers);
132
+ console.log(chalk.green(` ✓ INWX: ${domain} now delegated to ${nameservers.length} Cloudflare nameservers`));
133
+ console.log(chalk.dim(" (TLD propagation can take 5 min to a few hours)"));
134
+ }
135
+ catch (error) {
136
+ // Don't fail the whole deploy for an NS-update hiccup — the CF zone
137
+ // is fine, the user can retry via `hatchkit dns link-to-cloudflare`.
138
+ console.log(chalk.yellow(` ! INWX NS update failed: ${error.message}`));
139
+ console.log(chalk.dim(` Retry with: hatchkit dns link-to-cloudflare ${domain}`));
140
+ }
141
+ finally {
142
+ await inwx.logout().catch(() => { });
143
+ }
54
144
  }
55
145
  //# sourceMappingURL=terraform.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"terraform.js","sourceRoot":"","sources":["../../src/deploy/terraform.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"terraform.js","sourceRoot":"","sources":["../../src/deploy/terraform.ts"],"names":[],"mappings":"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"}
package/dist/dns.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ export interface DnsLinkOptions {
2
+ /** Empty = all zones. */
3
+ domains: string[];
4
+ dryRun: boolean;
5
+ }
6
+ export declare function runDnsLinkToCloudflare(options: DnsLinkOptions): Promise<void>;
7
+ //# sourceMappingURL=dns.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dns.d.ts","sourceRoot":"","sources":["../src/dns.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,cAAc;IAC7B,yBAAyB;IACzB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,wBAAsB,sBAAsB,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CA+HnF"}
package/dist/dns.js ADDED
@@ -0,0 +1,124 @@
1
+ // `hatchkit dns link-to-cloudflare [domain...]`
2
+ //
3
+ // Standalone migration helper. For each domain (or all zones if none
4
+ // given), look up the Cloudflare nameservers and push them to INWX as
5
+ // the registrar-level delegation. Useful after importing zones into
6
+ // Cloudflare when you don't want to click through INWX per-domain.
7
+ //
8
+ // Usage:
9
+ // hatchkit dns link-to-cloudflare # all matching zones
10
+ // hatchkit dns link-to-cloudflare fractal.garden # just one
11
+ // hatchkit dns link-to-cloudflare --dry-run ... # print only
12
+ // INWX_SANDBOX=1 hatchkit dns link-to-cloudflare ... # against OTE sandbox
13
+ import chalk from "chalk";
14
+ import { getDnsConfig } from "./config.js";
15
+ import { CloudflareApi } from "./utils/cloudflare-api.js";
16
+ import { InwxApi } from "./utils/inwx-api.js";
17
+ export async function runDnsLinkToCloudflare(options) {
18
+ const dns = await getDnsConfig();
19
+ if (!dns) {
20
+ throw new Error("No DNS config found. Run `hatchkit config add dns` and choose Cloudflare first.");
21
+ }
22
+ if (dns.provider !== "cloudflare") {
23
+ throw new Error(`DNS provider is set to "${dns.provider}", not "cloudflare". This command only makes sense when hosting DNS on Cloudflare.`);
24
+ }
25
+ if (!dns.apiToken) {
26
+ throw new Error("Cloudflare API token is missing from the keychain.");
27
+ }
28
+ if (!dns.registrarUsername || !dns.registrarPassword) {
29
+ throw new Error("INWX registrar credentials are not configured. Re-run `hatchkit config add dns` and answer yes when asked about INWX as registrar.");
30
+ }
31
+ const cf = new CloudflareApi({ token: dns.apiToken, accountId: dns.accountId });
32
+ console.log(chalk.bold("\n ── Verifying Cloudflare token ─────────────────────────\n"));
33
+ const status = await cf.verifyToken();
34
+ if (status !== "active") {
35
+ throw new Error(`Cloudflare token status is "${status}", expected "active".`);
36
+ }
37
+ console.log(chalk.green(" ✓ Token active"));
38
+ console.log(chalk.bold("\n ── Listing Cloudflare zones ───────────────────────────\n"));
39
+ const allZones = await cf.listZones();
40
+ console.log(chalk.dim(` Found ${allZones.length} zone(s) in Cloudflare`));
41
+ // Filter to the requested domains, or all zones if none were given.
42
+ let zones;
43
+ if (options.domains.length > 0) {
44
+ const wanted = new Set(options.domains);
45
+ zones = allZones.filter((z) => wanted.has(z.name));
46
+ const missing = [...wanted].filter((d) => !zones.find((z) => z.name === d));
47
+ if (missing.length > 0) {
48
+ console.log(chalk.yellow(` ! Not found in Cloudflare: ${missing.join(", ")}`));
49
+ }
50
+ }
51
+ else {
52
+ zones = allZones;
53
+ }
54
+ if (zones.length === 0) {
55
+ console.log(chalk.yellow("\n Nothing to do."));
56
+ return;
57
+ }
58
+ console.log(chalk.bold(`\n ── Updating INWX delegation for ${zones.length} domain(s) ────\n`));
59
+ const inwx = new InwxApi({
60
+ username: dns.registrarUsername,
61
+ password: dns.registrarPassword,
62
+ sandbox: process.env.INWX_SANDBOX === "1",
63
+ });
64
+ if (options.dryRun) {
65
+ console.log(chalk.yellow(" [dry-run: no changes will be made]\n"));
66
+ }
67
+ else {
68
+ await inwx.login();
69
+ }
70
+ let successes = 0;
71
+ let failures = 0;
72
+ let skipped = 0;
73
+ try {
74
+ for (const zone of zones) {
75
+ const ns = zone.name_servers;
76
+ console.log(chalk.bold(` ${zone.name}`));
77
+ console.log(chalk.dim(` zone_id: ${zone.id}`));
78
+ console.log(chalk.dim(` ns: ${ns.join(", ")}`));
79
+ if (zone.status !== "active") {
80
+ console.log(chalk.yellow(` ! Zone status is "${zone.status}", skipping (activate it in CF first)`));
81
+ skipped += 1;
82
+ continue;
83
+ }
84
+ if (options.dryRun) {
85
+ console.log(chalk.dim(" would call domain.update { ns: [...] }"));
86
+ continue;
87
+ }
88
+ try {
89
+ // Skip if INWX already has the right NS — saves a write and
90
+ // avoids logging a misleading "updated" message.
91
+ const current = await inwx.getDomainInfo(zone.name);
92
+ const same = current.ns.length === ns.length && current.ns.every((n) => ns.includes(n.toLowerCase()));
93
+ if (same) {
94
+ console.log(chalk.dim(" already matches — no change"));
95
+ skipped += 1;
96
+ continue;
97
+ }
98
+ await inwx.setDomainNameservers(zone.name, ns);
99
+ console.log(chalk.green(" ✓ updated at INWX"));
100
+ successes += 1;
101
+ }
102
+ catch (error) {
103
+ console.log(chalk.red(` ✗ failed: ${error.message}`));
104
+ failures += 1;
105
+ }
106
+ }
107
+ }
108
+ finally {
109
+ if (!options.dryRun) {
110
+ await inwx.logout().catch(() => { });
111
+ }
112
+ }
113
+ console.log(chalk.bold("\n ── Summary ──────────────────────────────────────────────\n"));
114
+ console.log(` Updated: ${chalk.green(successes)}`);
115
+ console.log(` Skipped: ${chalk.dim(skipped)}`);
116
+ console.log(` Failed: ${failures > 0 ? chalk.red(failures) : chalk.dim(failures)}`);
117
+ if (!options.dryRun && successes > 0) {
118
+ console.log(chalk.dim("\n TLD propagation can take 5 min to a few hours."));
119
+ }
120
+ if (failures > 0) {
121
+ process.exit(1);
122
+ }
123
+ }
124
+ //# sourceMappingURL=dns.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dns.js","sourceRoot":"","sources":["../src/dns.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ interface CheckResult {
2
+ name: string;
3
+ status: "ok" | "fail" | "skip";
4
+ detail?: string;
5
+ /** Multi-line troubleshooting hint, shown under a failing check. */
6
+ hint?: string[];
7
+ }
8
+ export declare function collectDoctorResults(): Promise<CheckResult[]>;
9
+ export declare function runDoctor(opts?: {
10
+ json?: boolean;
11
+ }): Promise<void>;
12
+ export {};
13
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"AAsBA,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAkVD,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,CAYnE;AAED,wBAAsB,SAAS,CAAC,IAAI,GAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CA8C5E"}