hatchkit 0.1.2 → 0.1.3

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 (82) 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/keys.d.ts +6 -2
  10. package/dist/deploy/keys.d.ts.map +1 -1
  11. package/dist/deploy/keys.js +16 -2
  12. package/dist/deploy/keys.js.map +1 -1
  13. package/dist/deploy/pages.d.ts +2 -0
  14. package/dist/deploy/pages.d.ts.map +1 -0
  15. package/dist/deploy/pages.js +537 -0
  16. package/dist/deploy/pages.js.map +1 -0
  17. package/dist/deploy/rename-domain.d.ts +55 -0
  18. package/dist/deploy/rename-domain.d.ts.map +1 -0
  19. package/dist/deploy/rename-domain.js +290 -0
  20. package/dist/deploy/rename-domain.js.map +1 -0
  21. package/dist/deploy/terraform.d.ts.map +1 -1
  22. package/dist/deploy/terraform.js +90 -0
  23. package/dist/deploy/terraform.js.map +1 -1
  24. package/dist/dns.d.ts +7 -0
  25. package/dist/dns.d.ts.map +1 -0
  26. package/dist/dns.js +124 -0
  27. package/dist/dns.js.map +1 -0
  28. package/dist/doctor.d.ts +13 -0
  29. package/dist/doctor.d.ts.map +1 -0
  30. package/dist/doctor.js +368 -0
  31. package/dist/doctor.js.map +1 -0
  32. package/dist/explain.d.ts +4 -0
  33. package/dist/explain.d.ts.map +1 -0
  34. package/dist/explain.js +173 -0
  35. package/dist/explain.js.map +1 -0
  36. package/dist/index.js +477 -46
  37. package/dist/index.js.map +1 -1
  38. package/dist/provision/glitchtip.d.ts +3 -0
  39. package/dist/provision/glitchtip.d.ts.map +1 -1
  40. package/dist/provision/glitchtip.js +18 -0
  41. package/dist/provision/glitchtip.js.map +1 -1
  42. package/dist/provision/index.d.ts +26 -0
  43. package/dist/provision/index.d.ts.map +1 -1
  44. package/dist/provision/index.js +435 -60
  45. package/dist/provision/index.js.map +1 -1
  46. package/dist/provision/openpanel.d.ts +7 -0
  47. package/dist/provision/openpanel.d.ts.map +1 -1
  48. package/dist/provision/openpanel.js +113 -48
  49. package/dist/provision/openpanel.js.map +1 -1
  50. package/dist/provision/resend.d.ts +23 -1
  51. package/dist/provision/resend.d.ts.map +1 -1
  52. package/dist/provision/resend.js +62 -1
  53. package/dist/provision/resend.js.map +1 -1
  54. package/dist/provision/write-env.d.ts +31 -0
  55. package/dist/provision/write-env.d.ts.map +1 -0
  56. package/dist/provision/write-env.js +94 -0
  57. package/dist/provision/write-env.js.map +1 -0
  58. package/dist/scaffold/infra.d.ts.map +1 -1
  59. package/dist/scaffold/infra.js +18 -1
  60. package/dist/scaffold/infra.js.map +1 -1
  61. package/dist/status.d.ts +30 -0
  62. package/dist/status.d.ts.map +1 -0
  63. package/dist/status.js +169 -0
  64. package/dist/status.js.map +1 -0
  65. package/dist/templates/addons/analytics/sentry.ts.hbs +6 -0
  66. package/dist/utils/cloudflare-api.d.ts +30 -0
  67. package/dist/utils/cloudflare-api.d.ts.map +1 -0
  68. package/dist/utils/cloudflare-api.js +85 -0
  69. package/dist/utils/cloudflare-api.js.map +1 -0
  70. package/dist/utils/coolify-api.d.ts +3 -1
  71. package/dist/utils/coolify-api.d.ts.map +1 -1
  72. package/dist/utils/coolify-api.js +29 -4
  73. package/dist/utils/coolify-api.js.map +1 -1
  74. package/dist/utils/inwx-api.d.ts +36 -0
  75. package/dist/utils/inwx-api.d.ts.map +1 -0
  76. package/dist/utils/inwx-api.js +105 -0
  77. package/dist/utils/inwx-api.js.map +1 -0
  78. package/dist/utils/secrets.d.ts +8 -1
  79. package/dist/utils/secrets.d.ts.map +1 -1
  80. package/dist/utils/secrets.js +8 -1
  81. package/dist/utils/secrets.js.map +1 -1
  82. package/package.json +1 -1
@@ -1,66 +1,131 @@
1
1
  /*
2
- * OpenPanel provisioning — creates a project + a client (write key
3
- * pair) inside an existing self-hosted OpenPanel instance.
2
+ * OpenPanel provisioning — uses the Management API (authenticated with a
3
+ * root-mode client) to create a project + a write client for <clientName>.
4
4
  *
5
- * OpenPanel's self-hosted API is still evolving, so this uses a
6
- * best-effort path and falls back to a paste-in flow if the API call
7
- * fails. Either way the resulting client id/secret are cached in the
8
- * keychain under `openpanel:<name>:client-secret` so re-runs are idempotent.
5
+ * Auth model: custom headers `openpanel-client-id` / `openpanel-client-secret`,
6
+ * NOT Authorization: Bearer. See https://openpanel.dev/docs/api/authentication.
7
+ *
8
+ * Endpoint shapes (from the OpenPanel source):
9
+ * POST {apiUrl}/manage/projects body: { name } ->
10
+ * { data: { id, ..., client: { id, secret } } }
11
+ * POST {apiUrl}/manage/clients body: { name, projectId, type: "write" } ->
12
+ * { data: { id, secret, ... } }
13
+ * DELETE {apiUrl}/manage/projects/{projectId}
14
+ *
15
+ * Per-project ids + secrets are cached in the keychain so re-runs are
16
+ * idempotent and `delete` can target the exact upstream project.
9
17
  */
10
- import { input, password as passwordPrompt } from "@inquirer/prompts";
11
18
  import { ensureOpenpanel } from "../config.js";
12
- import { SECRET_KEYS, getSecret, setSecret } from "../utils/secrets.js";
19
+ import { SECRET_KEYS, deleteSecret, getSecret, setSecret } from "../utils/secrets.js";
20
+ /** Extra cache slot for the upstream project id, used by `deleteOpenpanelClient`
21
+ * — separate from the client id slot so we can target the right row. */
22
+ const projectIdKey = (clientName) => SECRET_KEYS.openpanelClientSecret(`${clientName}:project-id`);
23
+ const clientIdKey = (clientName) => SECRET_KEYS.openpanelClientSecret(`${clientName}:id`);
24
+ function buildHeaders(rootClientId, rootClientSecret) {
25
+ return {
26
+ "openpanel-client-id": rootClientId,
27
+ "openpanel-client-secret": rootClientSecret,
28
+ "Content-Type": "application/json",
29
+ Accept: "application/json",
30
+ };
31
+ }
32
+ function resolveManageBase(url, apiUrl) {
33
+ return `${(apiUrl ?? url).replace(/\/$/, "")}/manage`;
34
+ }
13
35
  export async function provisionOpenpanelClient(clientName) {
14
36
  const cfg = await ensureOpenpanel();
15
- const { url, organizationSlug, token } = cfg;
16
- if (!organizationSlug) {
17
- throw new Error("OpenPanel config is missing organization slug. Re-run `hatchkit config add openpanel`.");
18
- }
19
- // Reuse a previously-provisioned client for the same name if one
20
- // exists — lets you re-run the command without creating duplicates.
37
+ const { url, apiUrl, rootClientId, rootClientSecret } = cfg;
38
+ const manageBase = resolveManageBase(url, apiUrl);
39
+ // Reuse a previously-provisioned client so re-runs don't mint duplicates.
21
40
  const cachedSecret = await getSecret(SECRET_KEYS.openpanelClientSecret(clientName));
22
- const cachedIdKey = SECRET_KEYS.openpanelClientSecret(`${clientName}:id`);
23
- const cachedId = await getSecret(cachedIdKey);
41
+ const cachedId = await getSecret(clientIdKey(clientName));
24
42
  if (cachedSecret && cachedId) {
25
- return { projectName: clientName, clientId: cachedId, clientSecret: cachedSecret, apiUrl: url };
43
+ return {
44
+ projectName: clientName,
45
+ clientId: cachedId,
46
+ clientSecret: cachedSecret,
47
+ apiUrl: manageBase,
48
+ };
49
+ }
50
+ const headers = buildHeaders(rootClientId, rootClientSecret);
51
+ // Step 1: create the project. The API authenticates the organization
52
+ // from the root client's auth — don't send organizationSlug.
53
+ const projectRes = await fetch(`${manageBase}/projects`, {
54
+ method: "POST",
55
+ headers,
56
+ body: JSON.stringify({ name: clientName }),
57
+ });
58
+ if (!projectRes.ok) {
59
+ const text = await projectRes.text().catch(() => "");
60
+ throw new Error(`OpenPanel create project failed: ${projectRes.status} ${projectRes.statusText}${text ? ` — ${text}` : ""}`);
61
+ }
62
+ const projectBody = (await projectRes.json());
63
+ const project = projectBody.data;
64
+ const projectId = project?.id;
65
+ let clientId = project?.client?.id;
66
+ let clientSecret = project?.client?.secret;
67
+ if (!projectId) {
68
+ throw new Error(`OpenPanel: project created but response lacked a project id (got ${JSON.stringify(projectBody).slice(0, 300)}).`);
26
69
  }
27
- // Try the API first (best-effort). If it fails, prompt the user to
28
- // paste the values from the OpenPanel dashboard.
29
- let clientId = null;
30
- let clientSecret = null;
31
- try {
32
- const res = await fetch(`${url}/api/client`, {
70
+ // Step 2 (fallback): some self-hosted configurations disable the
71
+ // default-client on project creation. Mint one explicitly so the env
72
+ // block always has real credentials.
73
+ if (!clientId || !clientSecret) {
74
+ const clientRes = await fetch(`${manageBase}/clients`, {
33
75
  method: "POST",
34
- headers: {
35
- Authorization: `Bearer ${token}`,
36
- "Content-Type": "application/json",
37
- },
38
- body: JSON.stringify({
39
- organizationSlug,
40
- project: { name: clientName },
41
- client: { name: clientName, type: "write" },
42
- }),
76
+ headers,
77
+ body: JSON.stringify({ name: clientName, type: "write", projectId }),
43
78
  });
44
- if (res.ok) {
45
- const body = (await res.json());
46
- if (body.clientId && body.clientSecret) {
47
- clientId = body.clientId;
48
- clientSecret = body.clientSecret;
49
- }
79
+ if (!clientRes.ok) {
80
+ const text = await clientRes.text().catch(() => "");
81
+ throw new Error(`OpenPanel create client failed: ${clientRes.status} ${clientRes.statusText}${text ? ` — ${text}` : ""}`);
50
82
  }
51
- }
52
- catch {
53
- // fall through to paste flow
83
+ const clientBody = (await clientRes.json());
84
+ clientId = clientBody.data?.id;
85
+ clientSecret = clientBody.data?.secret;
54
86
  }
55
87
  if (!clientId || !clientSecret) {
56
- console.log(` OpenPanel API couldn't auto-create the client for '${clientName}'.\n` +
57
- ` Open ${url}/${organizationSlug} → create a project named "${clientName}" →\n` +
58
- ` add a write client, then paste the credentials below.`);
59
- clientId = await input({ message: `OpenPanel clientId for ${clientName}:` });
60
- clientSecret = await passwordPrompt({ message: `OpenPanel clientSecret for ${clientName}:` });
88
+ throw new Error("OpenPanel: client created but response lacked id/secret.");
61
89
  }
62
90
  await setSecret(SECRET_KEYS.openpanelClientSecret(clientName), clientSecret);
63
- await setSecret(cachedIdKey, clientId);
64
- return { projectName: clientName, clientId, clientSecret, apiUrl: url };
91
+ await setSecret(clientIdKey(clientName), clientId);
92
+ await setSecret(projectIdKey(clientName), projectId);
93
+ return { projectName: clientName, clientId, clientSecret, apiUrl: manageBase };
94
+ }
95
+ /**
96
+ * Delete an OpenPanel project created by `provisionOpenpanelClient`.
97
+ * Also wipes the cached id + secret from the keychain so a future
98
+ * provision round won't hand back stale creds.
99
+ */
100
+ export async function deleteOpenpanelClient(clientName) {
101
+ const cfg = await ensureOpenpanel();
102
+ const { url, apiUrl, rootClientId, rootClientSecret } = cfg;
103
+ const cachedProjectId = await getSecret(projectIdKey(clientName));
104
+ const manageBase = resolveManageBase(url, apiUrl);
105
+ const headers = buildHeaders(rootClientId, rootClientSecret);
106
+ // With no cached project id there's nothing to target — OpenPanel
107
+ // projects are keyed by id (not name), so bail out quietly and let
108
+ // the caller move on.
109
+ if (!cachedProjectId) {
110
+ await deleteSecret(SECRET_KEYS.openpanelClientSecret(clientName));
111
+ await deleteSecret(clientIdKey(clientName));
112
+ return "not-found";
113
+ }
114
+ const res = await fetch(`${manageBase}/projects/${cachedProjectId}`, {
115
+ method: "DELETE",
116
+ headers,
117
+ });
118
+ // Always clear cached creds — if the upstream project is gone (or
119
+ // already-gone), the local secrets have no reason to linger.
120
+ await deleteSecret(SECRET_KEYS.openpanelClientSecret(clientName));
121
+ await deleteSecret(clientIdKey(clientName));
122
+ await deleteSecret(projectIdKey(clientName));
123
+ if (res.status === 404)
124
+ return "not-found";
125
+ if (!res.ok) {
126
+ const text = await res.text().catch(() => "");
127
+ throw new Error(`OpenPanel delete project failed: ${res.status} ${res.statusText}${text ? ` — ${text}` : ""}`);
128
+ }
129
+ return "deleted";
65
130
  }
66
131
  //# sourceMappingURL=openpanel.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"openpanel.js","sourceRoot":"","sources":["../../src/provision/openpanel.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"openpanel.js","sourceRoot":"","sources":["../../src/provision/openpanel.ts"],"names":[],"mappings":"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"}
@@ -7,10 +7,32 @@ export interface ResendClient {
7
7
  raw: string;
8
8
  }
9
9
  export declare function provisionResendClient(clientName: string, domainId?: string): Promise<ResendClient>;
10
- /** List verified Resend domains so the caller can pick one. */
10
+ /** List Resend domains so the caller can pick one. */
11
11
  export declare function listResendDomains(): Promise<Array<{
12
12
  id: string;
13
13
  name: string;
14
14
  status: string;
15
15
  }>>;
16
+ /** Create a new Resend sending domain. `name` must be a bare domain
17
+ * (no scheme, no path) — e.g. "playtiao.com" or "mail.playtiao.com".
18
+ * Newly created domains start unverified; DNS records must be added
19
+ * before keys scoped to it can send. */
20
+ export declare function createResendDomain(name: string): Promise<{
21
+ id: string;
22
+ name: string;
23
+ status: string;
24
+ }>;
25
+ export type DeleteResult = "deleted" | "not-found";
26
+ /**
27
+ * Delete the Resend API key named `clientName`.
28
+ *
29
+ * Resend's create response only gives us the token, not the key's id,
30
+ * and we don't persist the id locally. So: list keys, find the one with
31
+ * the matching name, DELETE /api-keys/:id. If zero match, treat as
32
+ * already-gone; if more than one matches (rare — same name re-used),
33
+ * delete them all so the undo is total.
34
+ */
35
+ export declare function deleteResendClient(clientName: string): Promise<DeleteResult>;
36
+ /** Normalize user-pasted domain input: strip scheme, path, whitespace. */
37
+ export declare function normalizeDomainInput(raw: string): string;
16
38
  //# sourceMappingURL=resend.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"resend.d.ts","sourceRoot":"","sources":["../../src/provision/resend.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;+DAC2D;IAC3D,GAAG,EAAE,MAAM,CAAC;CACb;AAED,wBAAsB,qBAAqB,CACzC,UAAU,EAAE,MAAM,EAClB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,YAAY,CAAC,CAsBvB;AAED,+DAA+D;AAC/D,wBAAsB,iBAAiB,IAAI,OAAO,CAChD,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CACpD,CAQA"}
1
+ {"version":3,"file":"resend.d.ts","sourceRoot":"","sources":["../../src/provision/resend.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;+DAC2D;IAC3D,GAAG,EAAE,MAAM,CAAC;CACb;AAED,wBAAsB,qBAAqB,CACzC,UAAU,EAAE,MAAM,EAClB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,YAAY,CAAC,CAsBvB;AAED,sDAAsD;AACtD,wBAAsB,iBAAiB,IAAI,OAAO,CAChD,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CACpD,CAQA;AAED;;;yCAGyC;AACzC,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,GACX,OAAO,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAevD;AAED,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,WAAW,CAAC;AAEnD;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAyBlF;AAED,0EAA0E;AAC1E,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAMxD"}
@@ -29,7 +29,7 @@ export async function provisionResendClient(clientName, domainId) {
29
29
  const data = (await res.json());
30
30
  return { keyName: clientName, apiKey: data.token, domainId, raw: data.token };
31
31
  }
32
- /** List verified Resend domains so the caller can pick one. */
32
+ /** List Resend domains so the caller can pick one. */
33
33
  export async function listResendDomains() {
34
34
  const cfg = await ensureResend();
35
35
  const res = await fetch("https://api.resend.com/domains", {
@@ -40,4 +40,65 @@ export async function listResendDomains() {
40
40
  const body = (await res.json());
41
41
  return body.data ?? [];
42
42
  }
43
+ /** Create a new Resend sending domain. `name` must be a bare domain
44
+ * (no scheme, no path) — e.g. "playtiao.com" or "mail.playtiao.com".
45
+ * Newly created domains start unverified; DNS records must be added
46
+ * before keys scoped to it can send. */
47
+ export async function createResendDomain(name) {
48
+ const cfg = await ensureResend();
49
+ const res = await fetch("https://api.resend.com/domains", {
50
+ method: "POST",
51
+ headers: {
52
+ Authorization: `Bearer ${cfg.apiKey}`,
53
+ "Content-Type": "application/json",
54
+ },
55
+ body: JSON.stringify({ name }),
56
+ });
57
+ if (!res.ok) {
58
+ throw new Error(`Resend create domain failed: HTTP ${res.status} ${await res.text()}`);
59
+ }
60
+ const data = (await res.json());
61
+ return { id: data.id, name: data.name, status: data.status ?? "not_started" };
62
+ }
63
+ /**
64
+ * Delete the Resend API key named `clientName`.
65
+ *
66
+ * Resend's create response only gives us the token, not the key's id,
67
+ * and we don't persist the id locally. So: list keys, find the one with
68
+ * the matching name, DELETE /api-keys/:id. If zero match, treat as
69
+ * already-gone; if more than one matches (rare — same name re-used),
70
+ * delete them all so the undo is total.
71
+ */
72
+ export async function deleteResendClient(clientName) {
73
+ const cfg = await ensureResend();
74
+ const auth = { Authorization: `Bearer ${cfg.apiKey}` };
75
+ const listRes = await fetch("https://api.resend.com/api-keys", { headers: auth });
76
+ if (!listRes.ok) {
77
+ throw new Error(`Resend list keys failed: HTTP ${listRes.status}`);
78
+ }
79
+ const body = (await listRes.json());
80
+ const matches = (body.data ?? []).filter((k) => k.name === clientName);
81
+ if (matches.length === 0)
82
+ return "not-found";
83
+ for (const key of matches) {
84
+ const delRes = await fetch(`https://api.resend.com/api-keys/${key.id}`, {
85
+ method: "DELETE",
86
+ headers: auth,
87
+ });
88
+ if (delRes.status === 404)
89
+ continue;
90
+ if (!delRes.ok) {
91
+ throw new Error(`Resend delete key ${key.id} failed: HTTP ${delRes.status} ${await delRes.text()}`);
92
+ }
93
+ }
94
+ return "deleted";
95
+ }
96
+ /** Normalize user-pasted domain input: strip scheme, path, whitespace. */
97
+ export function normalizeDomainInput(raw) {
98
+ let s = raw.trim().toLowerCase();
99
+ s = s.replace(/^https?:\/\//, "");
100
+ s = s.replace(/\/.*$/, "");
101
+ s = s.replace(/^www\./, "");
102
+ return s;
103
+ }
43
104
  //# sourceMappingURL=resend.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"resend.js","sourceRoot":"","sources":["../../src/provision/resend.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAW5C,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,UAAkB,EAClB,QAAiB;IAEjB,MAAM,GAAG,GAAG,MAAM,YAAY,EAAE,CAAC;IAEjC,MAAM,IAAI,GAA4B;QACpC,IAAI,EAAE,UAAU;QAChB,UAAU,EAAE,gBAAgB;KAC7B,CAAC;IACF,IAAI,QAAQ;QAAE,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC;IAExC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,iCAAiC,EAAE;QACzD,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,aAAa,EAAE,UAAU,GAAG,CAAC,MAAM,EAAE;YACrC,cAAc,EAAE,kBAAkB;SACnC;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;KAC3B,CAAC,CAAC;IACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,kCAAkC,GAAG,CAAC,MAAM,IAAI,MAAM,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACtF,CAAC;IACD,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAkC,CAAC;IACjE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;AAChF,CAAC;AAED,+DAA+D;AAC/D,MAAM,CAAC,KAAK,UAAU,iBAAiB;IAGrC,MAAM,GAAG,GAAG,MAAM,YAAY,EAAE,CAAC;IACjC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,gCAAgC,EAAE;QACxD,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,GAAG,CAAC,MAAM,EAAE,EAAE;KACnD,CAAC,CAAC;IACH,IAAI,CAAC,GAAG,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,oCAAoC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;IAC/E,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAkE,CAAC;IACjG,OAAO,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC;AACzB,CAAC"}
1
+ {"version":3,"file":"resend.js","sourceRoot":"","sources":["../../src/provision/resend.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /** One `KEY=VALUE` pair parsed out of a provisioned env block. */
2
+ export interface EnvPair {
3
+ key: string;
4
+ value: string;
5
+ }
6
+ export interface WriteResult {
7
+ devPath: string;
8
+ prodPath: string;
9
+ devWrittenKeys: string[];
10
+ prodEncryptedKeys: string[];
11
+ }
12
+ /** Parse a list of `KEY=VALUE` lines into structured pairs. Blank
13
+ * lines and comments are ignored, which matches the format the
14
+ * provision orchestrator emits today. */
15
+ export declare function parseEnvLines(lines: string[]): EnvPair[];
16
+ /** Resolve where `.env.{development,production}` should live. The
17
+ * starter keeps them under `packages/server/`; other layouts (a
18
+ * hand-maintained project root, a monorepo not from the starter) are
19
+ * also accepted. */
20
+ export declare function resolveEnvTarget(projectDir: string): {
21
+ baseDir: string;
22
+ layout: "starter" | "root";
23
+ };
24
+ /** Upsert plain-text KEY=VALUE entries into `.env.development`. If the
25
+ * file already has a line for a given key, we replace it in place so
26
+ * re-runs don't duplicate entries. */
27
+ export declare function writeDevEnv(envPath: string, pairs: EnvPair[]): string[];
28
+ /** Encrypt each KEY into `.env.production` via dotenvx. First call
29
+ * generates the keypair and writes `.env.keys`. */
30
+ export declare function writeProdEnv(envPath: string, pairs: EnvPair[]): string[];
31
+ //# sourceMappingURL=write-env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write-env.d.ts","sourceRoot":"","sources":["../../src/provision/write-env.ts"],"names":[],"mappings":"AAmBA,kEAAkE;AAClE,MAAM,WAAW,OAAO;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,iBAAiB,EAAE,MAAM,EAAE,CAAC;CAC7B;AAED;;0CAE0C;AAC1C,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,EAAE,CAUxD;AAED;;;qBAGqB;AACrB,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG;IACpD,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,SAAS,GAAG,MAAM,CAAC;CAC5B,CAMA;AAED;;uCAEuC;AACvC,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,MAAM,EAAE,CAqBvE;AAED;oDACoD;AACpD,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,MAAM,EAAE,CAQxE"}
@@ -0,0 +1,94 @@
1
+ /*
2
+ * write-env — write provisioned credentials directly into a project's
3
+ * `.env.development` (plain) and `.env.production` (dotenvx-encrypted).
4
+ *
5
+ * Motivation: printing env blocks to stdout leaks secret values into
6
+ * the user's terminal scrollback / shell history / any process log
7
+ * capturing the CLI. Writing straight into the project repo means:
8
+ * · dev values land in a gitignored `.env.development`
9
+ * · prod values land in a commit-safe encrypted `.env.production`
10
+ * · nothing with a live secret crosses stdout
11
+ *
12
+ * The starter lays env files under `packages/server/`; we detect that
13
+ * layout first and fall back to the project root otherwise.
14
+ */
15
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
16
+ import { dirname, join } from "node:path";
17
+ import { set as dotenvxSet } from "@dotenvx/dotenvx";
18
+ /** Parse a list of `KEY=VALUE` lines into structured pairs. Blank
19
+ * lines and comments are ignored, which matches the format the
20
+ * provision orchestrator emits today. */
21
+ export function parseEnvLines(lines) {
22
+ const out = [];
23
+ for (const raw of lines) {
24
+ const line = raw.trim();
25
+ if (!line || line.startsWith("#"))
26
+ continue;
27
+ const eq = line.indexOf("=");
28
+ if (eq < 0)
29
+ continue;
30
+ out.push({ key: line.slice(0, eq).trim(), value: line.slice(eq + 1) });
31
+ }
32
+ return out;
33
+ }
34
+ /** Resolve where `.env.{development,production}` should live. The
35
+ * starter keeps them under `packages/server/`; other layouts (a
36
+ * hand-maintained project root, a monorepo not from the starter) are
37
+ * also accepted. */
38
+ export function resolveEnvTarget(projectDir) {
39
+ const starterDir = join(projectDir, "packages/server");
40
+ if (existsSync(starterDir)) {
41
+ return { baseDir: starterDir, layout: "starter" };
42
+ }
43
+ return { baseDir: projectDir, layout: "root" };
44
+ }
45
+ /** Upsert plain-text KEY=VALUE entries into `.env.development`. If the
46
+ * file already has a line for a given key, we replace it in place so
47
+ * re-runs don't duplicate entries. */
48
+ export function writeDevEnv(envPath, pairs) {
49
+ ensureParent(envPath);
50
+ const existing = existsSync(envPath) ? readFileSync(envPath, "utf-8") : "";
51
+ const lines = existing === "" ? [] : existing.split("\n");
52
+ const wroteKeys = [];
53
+ for (const { key, value } of pairs) {
54
+ const idx = lines.findIndex((l) => l.startsWith(`${key}=`));
55
+ const line = `${key}=${serializeDevValue(value)}`;
56
+ if (idx >= 0) {
57
+ lines[idx] = line;
58
+ }
59
+ else {
60
+ lines.push(line);
61
+ }
62
+ wroteKeys.push(key);
63
+ }
64
+ // Trim trailing newlines then re-add exactly one so diffs stay clean.
65
+ while (lines.length > 0 && lines[lines.length - 1] === "")
66
+ lines.pop();
67
+ writeFileSync(envPath, `${lines.join("\n")}\n`, { mode: 0o600 });
68
+ return wroteKeys;
69
+ }
70
+ /** Encrypt each KEY into `.env.production` via dotenvx. First call
71
+ * generates the keypair and writes `.env.keys`. */
72
+ export function writeProdEnv(envPath, pairs) {
73
+ ensureParent(envPath);
74
+ const encrypted = [];
75
+ for (const { key, value } of pairs) {
76
+ dotenvxSet(key, value, { path: envPath, encrypt: true });
77
+ encrypted.push(key);
78
+ }
79
+ return encrypted;
80
+ }
81
+ function ensureParent(filePath) {
82
+ const parent = dirname(filePath);
83
+ if (!existsSync(parent))
84
+ mkdirSync(parent, { recursive: true });
85
+ }
86
+ /** Quote a dev-env value if it contains whitespace or shell-special
87
+ * characters. Plain alphanumerics / common URL/token shapes stay
88
+ * unquoted so the file reads naturally. */
89
+ function serializeDevValue(value) {
90
+ if (/^[A-Za-z0-9_\-./:=+@]*$/.test(value))
91
+ return value;
92
+ return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
93
+ }
94
+ //# sourceMappingURL=write-env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write-env.js","sourceRoot":"","sources":["../../src/provision/write-env.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"infra.d.ts","sourceRoot":"","sources":["../../src/scaffold/infra.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAGnD,iDAAiD;AACjD,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAkC5D;AAED,mDAAmD;AACnD,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,aAAa,EACrB,MAAM,GAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAO,GAC1E,MAAM,CAqBR;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,gCAAgC;AAChC,wBAAgB,aAAa,CAC3B,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,oBAAyB,GACjC,IAAI,CA0CN"}
1
+ {"version":3,"file":"infra.d.ts","sourceRoot":"","sources":["../../src/scaffold/infra.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAGnD,iDAAiD;AACjD,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CA8C5D;AAED,mDAAmD;AACnD,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,aAAa,EACrB,MAAM,GAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAO,GAC1E,MAAM,CAqBR;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,gCAAgC;AAChC,wBAAgB,aAAa,CAC3B,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,oBAAyB,GACjC,IAAI,CA0CN"}
@@ -19,6 +19,13 @@ export function generateTfvars(config) {
19
19
  addSubdomain(config.subdomain, "Web app + API paths");
20
20
  addSubdomain(`api.${config.subdomain}`, "REST API");
21
21
  addSubdomain("admin", "Coolify dashboard");
22
+ // The stack-level dns_provider defaults to "inwx" for backward compat,
23
+ // but the user's CLI config is the source of truth — emit whichever
24
+ // provider they configured. "manual" maps to "inwx" because the stack
25
+ // only accepts "inwx" | "cloudflare"; manual DNS skips Terraform DNS
26
+ // entirely and is handled upstream.
27
+ const cfgProvider = getConfig().providers.dns?.provider ?? "inwx";
28
+ const stackDnsProvider = cfgProvider === "cloudflare" ? "cloudflare" : "inwx";
22
29
  if (config.deployTarget === "new") {
23
30
  return renderString(TFVARS_TEMPLATE, {
24
31
  name: config.name,
@@ -26,6 +33,8 @@ export function generateTfvars(config) {
26
33
  serverLocation: config.serverLocation || "nbg1",
27
34
  domain: config.baseDomain,
28
35
  subdomains,
36
+ dnsProvider: stackDnsProvider,
37
+ cloudflareProxied: true,
29
38
  s3Enabled: config.features.includes("s3") && config.s3Provider !== "existing",
30
39
  s3BucketName: `${config.name}-assets`,
31
40
  s3Location: config.serverLocation || "nbg1",
@@ -35,6 +44,8 @@ export function generateTfvars(config) {
35
44
  return renderString(DNS_ONLY_TFVARS_TEMPLATE, {
36
45
  domain: config.baseDomain,
37
46
  subdomains,
47
+ dnsProvider: stackDnsProvider,
48
+ cloudflareProxied: true,
38
49
  targetIpv4: config.serverIp || "",
39
50
  targetIpv6: "",
40
51
  });
@@ -127,6 +138,9 @@ server_location = "{{serverLocation}}"
127
138
  ssh_key_name = "deploy-key"
128
139
  ssh_public_key = "ssh-ed25519 CHANGE_ME"
129
140
 
141
+ dns_provider = "{{dnsProvider}}"
142
+ cloudflare_proxied = {{cloudflareProxied}}
143
+
130
144
  domain = "{{domain}}"
131
145
  subdomains = {
132
146
  {{#each subdomains}}
@@ -146,7 +160,10 @@ s3_location = "{{s3Location}}"
146
160
  s3_enabled = false
147
161
  {{/if}}
148
162
  `;
149
- const DNS_ONLY_TFVARS_TEMPLATE = `domain = "{{domain}}"
163
+ const DNS_ONLY_TFVARS_TEMPLATE = `dns_provider = "{{dnsProvider}}"
164
+ cloudflare_proxied = {{cloudflareProxied}}
165
+
166
+ domain = "{{domain}}"
150
167
  subdomains = {
151
168
  {{#each subdomains}}
152
169
  "{{@key}}" = "{{this}}"
@@ -1 +1 @@
1
- {"version":3,"file":"infra.js","sourceRoot":"","sources":["../../src/scaffold/infra.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"infra.js","sourceRoot":"","sources":["../../src/scaffold/infra.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ export interface ProviderSnapshot {
2
+ key: string;
3
+ label: string;
4
+ configured: boolean;
5
+ detail?: string;
6
+ /** If not configured, how to configure it. */
7
+ configureCommand?: string;
8
+ }
9
+ export interface StatusSnapshot {
10
+ version: string;
11
+ configPath: string;
12
+ providers: ProviderSnapshot[];
13
+ mlServiceCount: number;
14
+ mlServices: Array<{
15
+ name: string;
16
+ endpoint: string;
17
+ platform: string;
18
+ }>;
19
+ /** One-line next-best-step based on what's missing. */
20
+ nextStep: string;
21
+ /** Ordered suggestions for discoverability in the menu. */
22
+ suggestions: Array<{
23
+ command: string;
24
+ why: string;
25
+ }>;
26
+ }
27
+ export declare function collectStatus(): StatusSnapshot;
28
+ export declare function renderStatusHuman(s: StatusSnapshot): string;
29
+ export declare function renderMenu(s: StatusSnapshot): string;
30
+ //# sourceMappingURL=status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../src/status.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8CAA8C;IAC9C,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,gBAAgB,EAAE,CAAC;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxE,uDAAuD;IACvD,QAAQ,EAAE,MAAM,CAAC;IACjB,2DAA2D;IAC3D,WAAW,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACtD;AAED,wBAAgB,aAAa,IAAI,cAAc,CAuF9C;AA6CD,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,cAAc,GAAG,MAAM,CAwB3D;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,cAAc,GAAG,MAAM,CAyBpD"}