@rulebricks/cli 1.9.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.
Files changed (93) hide show
  1. package/README.md +62 -0
  2. package/dist/commands/clone.d.ts +6 -0
  3. package/dist/commands/clone.js +60 -0
  4. package/dist/commands/deploy.d.ts +8 -0
  5. package/dist/commands/deploy.js +409 -0
  6. package/dist/commands/destroy.d.ts +8 -0
  7. package/dist/commands/destroy.js +298 -0
  8. package/dist/commands/init.d.ts +7 -0
  9. package/dist/commands/init.js +201 -0
  10. package/dist/commands/logs.d.ts +9 -0
  11. package/dist/commands/logs.js +222 -0
  12. package/dist/commands/open.d.ts +7 -0
  13. package/dist/commands/open.js +139 -0
  14. package/dist/commands/status.d.ts +5 -0
  15. package/dist/commands/status.js +125 -0
  16. package/dist/commands/upgrade.d.ts +7 -0
  17. package/dist/commands/upgrade.js +239 -0
  18. package/dist/components/DNSWaitScreen.d.ts +9 -0
  19. package/dist/components/DNSWaitScreen.js +73 -0
  20. package/dist/components/Wizard/WizardContext.d.ts +176 -0
  21. package/dist/components/Wizard/WizardContext.js +346 -0
  22. package/dist/components/Wizard/index.d.ts +2 -0
  23. package/dist/components/Wizard/index.js +2 -0
  24. package/dist/components/Wizard/steps/CloudProviderStep.d.ts +6 -0
  25. package/dist/components/Wizard/steps/CloudProviderStep.js +210 -0
  26. package/dist/components/Wizard/steps/CredentialsStep.d.ts +6 -0
  27. package/dist/components/Wizard/steps/CredentialsStep.js +22 -0
  28. package/dist/components/Wizard/steps/DatabaseStep.d.ts +6 -0
  29. package/dist/components/Wizard/steps/DatabaseStep.js +80 -0
  30. package/dist/components/Wizard/steps/DeploymentModeStep.d.ts +5 -0
  31. package/dist/components/Wizard/steps/DeploymentModeStep.js +26 -0
  32. package/dist/components/Wizard/steps/DomainStep.d.ts +6 -0
  33. package/dist/components/Wizard/steps/DomainStep.js +126 -0
  34. package/dist/components/Wizard/steps/FeatureConfigStep.d.ts +6 -0
  35. package/dist/components/Wizard/steps/FeatureConfigStep.js +765 -0
  36. package/dist/components/Wizard/steps/FeaturesStep.d.ts +6 -0
  37. package/dist/components/Wizard/steps/FeaturesStep.js +119 -0
  38. package/dist/components/Wizard/steps/ReviewStep.d.ts +6 -0
  39. package/dist/components/Wizard/steps/ReviewStep.js +56 -0
  40. package/dist/components/Wizard/steps/SMTPStep.d.ts +6 -0
  41. package/dist/components/Wizard/steps/SMTPStep.js +191 -0
  42. package/dist/components/Wizard/steps/SupabaseCredentialsStep.d.ts +6 -0
  43. package/dist/components/Wizard/steps/SupabaseCredentialsStep.js +76 -0
  44. package/dist/components/Wizard/steps/TierStep.d.ts +6 -0
  45. package/dist/components/Wizard/steps/TierStep.js +29 -0
  46. package/dist/components/Wizard/steps/VersionStep.d.ts +6 -0
  47. package/dist/components/Wizard/steps/VersionStep.js +113 -0
  48. package/dist/components/Wizard/steps/index.d.ts +12 -0
  49. package/dist/components/Wizard/steps/index.js +12 -0
  50. package/dist/components/common/AppShell.d.ts +31 -0
  51. package/dist/components/common/AppShell.js +31 -0
  52. package/dist/components/common/Box.d.ts +20 -0
  53. package/dist/components/common/Box.js +20 -0
  54. package/dist/components/common/Logo.d.ts +7 -0
  55. package/dist/components/common/Logo.js +22 -0
  56. package/dist/components/common/Spinner.d.ts +12 -0
  57. package/dist/components/common/Spinner.js +28 -0
  58. package/dist/components/common/index.d.ts +6 -0
  59. package/dist/components/common/index.js +5 -0
  60. package/dist/index.d.ts +2 -0
  61. package/dist/index.js +202 -0
  62. package/dist/lib/cloudCli.d.ts +156 -0
  63. package/dist/lib/cloudCli.js +691 -0
  64. package/dist/lib/config.d.ts +91 -0
  65. package/dist/lib/config.js +278 -0
  66. package/dist/lib/dns.d.ts +41 -0
  67. package/dist/lib/dns.js +235 -0
  68. package/dist/lib/dockerHub.d.ts +57 -0
  69. package/dist/lib/dockerHub.js +128 -0
  70. package/dist/lib/helm.d.ts +53 -0
  71. package/dist/lib/helm.js +209 -0
  72. package/dist/lib/helmValues.d.ts +17 -0
  73. package/dist/lib/helmValues.js +693 -0
  74. package/dist/lib/kubernetes.d.ts +161 -0
  75. package/dist/lib/kubernetes.js +755 -0
  76. package/dist/lib/terraform.d.ts +44 -0
  77. package/dist/lib/terraform.js +230 -0
  78. package/dist/lib/theme.d.ts +81 -0
  79. package/dist/lib/theme.js +115 -0
  80. package/dist/lib/validation.d.ts +47 -0
  81. package/dist/lib/validation.js +164 -0
  82. package/dist/lib/versions.d.ts +69 -0
  83. package/dist/lib/versions.js +139 -0
  84. package/dist/types/index.d.ts +718 -0
  85. package/dist/types/index.js +556 -0
  86. package/email-templates/email_change.html +325 -0
  87. package/email-templates/invite.html +383 -0
  88. package/email-templates/password_change.html +414 -0
  89. package/email-templates/verify.html +396 -0
  90. package/package.json +78 -0
  91. package/terraform/aws/main.tf +327 -0
  92. package/terraform/azure/main.tf +326 -0
  93. package/terraform/gcp/main.tf +369 -0
@@ -0,0 +1,239 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState, useEffect, useCallback } from "react";
3
+ import { Box, Text, useApp, useInput } from "ink";
4
+ import SelectInput from "ink-select-input";
5
+ import { BorderBox, Spinner, ThemeProvider, useTheme, Logo, } from "../components/common/index.js";
6
+ import { loadDeploymentConfig, loadDeploymentState, updateDeploymentStatus, getHelmValuesPath, } from "../lib/config.js";
7
+ import { upgradeChart, dryRunUpgrade } from "../lib/helm.js";
8
+ import { formatDate, getAppVersionInfo, } from "../lib/versions.js";
9
+ import { formatVersionDisplay, normalizeVersion } from "../lib/dockerHub.js";
10
+ import { CHANGELOG_URL, getNamespace, getReleaseName, } from "../types/index.js";
11
+ import { getDeployedImageVersions, rolloutRestart } from "../lib/kubernetes.js";
12
+ import fs from "fs/promises";
13
+ import YAML from "yaml";
14
+ function UpgradeCommandInner({ name, targetVersion, dryRun, }) {
15
+ const { exit } = useApp();
16
+ const { colors } = useTheme();
17
+ const [step, setStep] = useState("loading");
18
+ const [config, setConfig] = useState(null);
19
+ const [versionInfo, setVersionInfo] = useState(null);
20
+ const [selectedVersion, setSelectedVersion] = useState(null);
21
+ const [error, setError] = useState(null);
22
+ const [dryRunOutput, setDryRunOutput] = useState(null);
23
+ // Store actual deployed HPS version separately (may differ from expected)
24
+ const [deployedHpsVersion, setDeployedHpsVersion] = useState(null);
25
+ useEffect(() => {
26
+ loadVersions();
27
+ }, []);
28
+ async function loadVersions() {
29
+ try {
30
+ const cfg = await loadDeploymentConfig(name);
31
+ setConfig(cfg);
32
+ const state = await loadDeploymentState(name);
33
+ // Get actual deployed versions from Kubernetes
34
+ const namespace = state?.application?.namespace || getNamespace(name);
35
+ const releaseName = getReleaseName(name);
36
+ const deployedVersions = await getDeployedImageVersions(releaseName, namespace);
37
+ // Use deployed version from K8s, fall back to state file if K8s query fails
38
+ const currentAppVersion = deployedVersions.appVersion || state?.application?.appVersion || null;
39
+ // Store actual deployed HPS version for display
40
+ setDeployedHpsVersion(deployedVersions.hpsVersion || state?.application?.hpsVersion || null);
41
+ const info = await getAppVersionInfo(cfg.licenseKey, currentAppVersion);
42
+ setVersionInfo(info);
43
+ if (targetVersion) {
44
+ // Find the version in available list
45
+ const targetVer = info.available.find((v) => v.version === targetVersion);
46
+ if (targetVer) {
47
+ setSelectedVersion(targetVer);
48
+ if (dryRun) {
49
+ await performDryRun(targetVer);
50
+ }
51
+ else {
52
+ setStep("confirm");
53
+ }
54
+ }
55
+ else {
56
+ setError(`Version ${targetVersion} not found`);
57
+ setStep("error");
58
+ }
59
+ }
60
+ else {
61
+ setStep("select");
62
+ }
63
+ }
64
+ catch (err) {
65
+ setError(err instanceof Error ? err.message : "Failed to load versions");
66
+ setStep("error");
67
+ }
68
+ }
69
+ async function performDryRun(version) {
70
+ try {
71
+ // Update helm values with new image tags before dry run
72
+ await updateHelmValuesWithVersion(version);
73
+ const state = await loadDeploymentState(name);
74
+ // Use namespace from state if available (backwards compat), otherwise compute from deployment name
75
+ const namespace = state?.application?.namespace || getNamespace(name);
76
+ const releaseName = getReleaseName(name);
77
+ const output = await dryRunUpgrade(name, { releaseName, namespace });
78
+ setDryRunOutput(output);
79
+ setStep("complete");
80
+ }
81
+ catch (err) {
82
+ setError(err instanceof Error ? err.message : "Dry run failed");
83
+ setStep("error");
84
+ }
85
+ }
86
+ async function updateHelmValuesWithVersion(version) {
87
+ const valuesPath = getHelmValuesPath(name);
88
+ try {
89
+ const content = await fs.readFile(valuesPath, "utf8");
90
+ const values = YAML.parse(content);
91
+ // Update image tags
92
+ if (!values.rulebricks) {
93
+ values.rulebricks = {};
94
+ }
95
+ const rulebricks = values.rulebricks;
96
+ // Update app image tag
97
+ if (!rulebricks.app) {
98
+ rulebricks.app = {};
99
+ }
100
+ const app = rulebricks.app;
101
+ if (!app.image) {
102
+ app.image = {};
103
+ }
104
+ app.image.tag = version.version;
105
+ // Update HPS image tag
106
+ if (!rulebricks.hps) {
107
+ rulebricks.hps = {};
108
+ }
109
+ const hps = rulebricks.hps;
110
+ if (!hps.image) {
111
+ hps.image = {};
112
+ }
113
+ hps.image.tag =
114
+ version.hpsVersion || version.version;
115
+ // Save updated values
116
+ await fs.writeFile(valuesPath, YAML.stringify(values), "utf8");
117
+ }
118
+ catch (err) {
119
+ throw new Error(`Failed to update Helm values: ${err}`);
120
+ }
121
+ }
122
+ async function performUpgrade() {
123
+ if (!selectedVersion || !config)
124
+ return;
125
+ setStep("upgrading");
126
+ try {
127
+ // Update helm values with new image tags
128
+ await updateHelmValuesWithVersion(selectedVersion);
129
+ const state = await loadDeploymentState(name);
130
+ // Use namespace from state if available (backwards compat), otherwise compute from deployment name
131
+ const namespace = state?.application?.namespace || getNamespace(name);
132
+ const releaseName = getReleaseName(name);
133
+ // Perform the upgrade
134
+ await upgradeChart(name, { releaseName, namespace, wait: true });
135
+ // Force restart HPS statefulsets to ensure fresh images are pulled
136
+ // (pullPolicy: Always only pulls on pod restart, not on unchanged spec)
137
+ await rolloutRestart("statefulset", `${releaseName}-hps`, namespace);
138
+ await rolloutRestart("statefulset", `${releaseName}-hps-worker`, namespace);
139
+ // Update deployment state
140
+ await updateDeploymentStatus(name, "running", {
141
+ application: {
142
+ appVersion: selectedVersion.version,
143
+ hpsVersion: selectedVersion.hpsVersion || selectedVersion.version,
144
+ namespace,
145
+ url: `https://${config.domain}`,
146
+ },
147
+ });
148
+ setStep("complete");
149
+ setTimeout(() => exit(), 5000);
150
+ }
151
+ catch (err) {
152
+ setError(err instanceof Error ? err.message : "Upgrade failed");
153
+ setStep("error");
154
+ }
155
+ }
156
+ const handleVersionSelect = useCallback((item) => {
157
+ const version = versionInfo?.available.find((v) => v.version === item.value);
158
+ if (version) {
159
+ setSelectedVersion(version);
160
+ if (dryRun) {
161
+ performDryRun(version);
162
+ }
163
+ else {
164
+ setStep("confirm");
165
+ }
166
+ }
167
+ }, [versionInfo, dryRun]);
168
+ useInput((input, key) => {
169
+ if (step === "confirm") {
170
+ if (key.return) {
171
+ performUpgrade();
172
+ }
173
+ else if (key.escape) {
174
+ setStep("select");
175
+ }
176
+ }
177
+ });
178
+ if (step === "loading") {
179
+ return (_jsx(BorderBox, { title: "Version Manager", children: _jsx(Box, { marginY: 1, children: _jsx(Spinner, { label: "Loading version information..." }) }) }));
180
+ }
181
+ if (step === "error") {
182
+ return (_jsx(BorderBox, { title: "Upgrade Failed", children: _jsx(Box, { flexDirection: "column", marginY: 1, children: _jsxs(Text, { color: colors.error, children: ["\u2717 ", error] }) }) }));
183
+ }
184
+ if (step === "complete") {
185
+ if (dryRun && dryRunOutput) {
186
+ return (_jsx(BorderBox, { title: "Dry Run Results", children: _jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { color: colors.accent, children: "Preview of changes (no changes made):" }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: colors.muted, children: [dryRunOutput.substring(0, 500), "..."] }) })] }) }));
187
+ }
188
+ return (_jsx(BorderBox, { title: "Upgrade Complete", children: _jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsxs(Text, { color: colors.success, bold: true, children: ["\u2713 Upgraded to ", formatVersionDisplay(selectedVersion?.version || "")] }), selectedVersion?.hpsVersion && (_jsxs(Text, { color: colors.muted, children: ["HPS version: ", formatVersionDisplay(selectedVersion.hpsVersion)] })), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { children: ["Run `rulebricks status ", name, "` to verify the deployment"] }) })] }) }));
189
+ }
190
+ if (step === "upgrading") {
191
+ return (_jsx(BorderBox, { title: "Upgrading", children: _jsx(Box, { marginY: 1, children: _jsx(Spinner, { label: `Installing ${formatVersionDisplay(selectedVersion?.version || "")}...` }) }) }));
192
+ }
193
+ if (step === "confirm") {
194
+ return (_jsx(BorderBox, { title: "Confirm Upgrade", children: _jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsxs(Text, { children: ["Current:", " ", _jsx(Text, { color: colors.accent, children: versionInfo?.current
195
+ ? formatVersionDisplay(versionInfo.current.version)
196
+ : "Not installed" }), deployedHpsVersion && (_jsxs(Text, { color: colors.muted, children: [" ", "(Solver: ", formatVersionDisplay(deployedHpsVersion), ")"] }))] }), _jsxs(Text, { children: ["Target:", " ", _jsx(Text, { color: colors.success, children: formatVersionDisplay(selectedVersion?.version || "") }), selectedVersion?.hpsVersion && (_jsxs(Text, { color: colors.muted, children: [" ", "(Solver: ", formatVersionDisplay(selectedVersion.hpsVersion), ")"] }))] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: colors.warning, children: "\u26A0 This will upgrade your Rulebricks deployment." }), _jsx(Text, { color: colors.muted, children: "Pods will be restarted and there may be brief downtime." })] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: colors.success, bold: true, children: "Press Enter to continue, Esc to go back" }) })] }) }));
197
+ }
198
+ // Version selection screen
199
+ const versionItems = versionInfo?.available.map((v) => ({
200
+ label: formatVersionDisplay(v.version),
201
+ value: v.version,
202
+ hpsVersion: v.hpsVersion,
203
+ date: v.releaseDate,
204
+ // Only mark as "current" if both app AND HPS versions match what's deployed
205
+ isCurrent: versionInfo.current?.version === v.version &&
206
+ (!deployedHpsVersion ||
207
+ !v.hpsVersion ||
208
+ normalizeVersion(deployedHpsVersion) ===
209
+ normalizeVersion(v.hpsVersion)),
210
+ isLatest: versionInfo.latest?.version === v.version,
211
+ })) || [];
212
+ return (_jsx(BorderBox, { title: "Rulebricks Version Manager", children: _jsxs(Box, { flexDirection: "column", marginY: 1, children: [(() => {
213
+ // Check if HPS has an update available (even if app version is current)
214
+ const latestHps = versionInfo?.latest?.hpsVersion;
215
+ const hasHpsUpdate = deployedHpsVersion &&
216
+ latestHps &&
217
+ normalizeVersion(deployedHpsVersion) !==
218
+ normalizeVersion(latestHps);
219
+ const hasAnyUpdate = versionInfo?.hasUpdate || hasHpsUpdate;
220
+ return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsxs(Text, { children: ["Current:", " ", _jsx(Text, { color: colors.accent, children: versionInfo?.current
221
+ ? formatVersionDisplay(versionInfo.current.version)
222
+ : "Not installed" }), deployedHpsVersion && (_jsxs(Text, { color: hasHpsUpdate ? colors.accent : colors.muted, children: [" ", "(Solver: ", formatVersionDisplay(deployedHpsVersion), ")"] }))] }), _jsxs(Text, { children: ["Latest:", " ", _jsx(Text, { color: hasAnyUpdate ? colors.success : colors.accent, children: versionInfo?.latest
223
+ ? formatVersionDisplay(versionInfo.latest.version)
224
+ : "Unknown" }), versionInfo?.latest?.hpsVersion && (_jsxs(Text, { color: hasHpsUpdate ? colors.success : colors.muted, children: [" ", "(Solver:", " ", formatVersionDisplay(versionInfo.latest.hpsVersion), ")"] }))] }), hasAnyUpdate && (_jsx(Text, { color: colors.muted, dimColor: true, children: "Update available" }))] }));
225
+ })(), _jsxs(Box, { marginBottom: 1, paddingX: 1, borderStyle: "single", borderColor: colors.accent, alignSelf: "flex-start", children: [_jsx(Text, { children: "\uD83D\uDCDA What's new: " }), _jsx(Text, { color: colors.accent, underline: true, children: CHANGELOG_URL })] }), _jsx(Text, { bold: true, children: "Select app version to install:" }), _jsx(Box, { marginTop: 1, children: _jsx(SelectInput, { items: versionItems, onSelect: handleVersionSelect, limit: 8, itemComponent: ({ isSelected, label }) => {
226
+ const vItem = versionItems.find((v) => v.label === label) || versionItems[0];
227
+ // Highlight latest in green when there's an update available
228
+ const isLatestWithUpdate = vItem.isLatest && !vItem.isCurrent;
229
+ const labelColor = isSelected
230
+ ? colors.accent
231
+ : isLatestWithUpdate
232
+ ? colors.success
233
+ : undefined;
234
+ return (_jsxs(Box, { children: [_jsx(Text, { color: labelColor, children: label }), vItem.hpsVersion && (_jsxs(Text, { color: isLatestWithUpdate ? colors.success : colors.muted, children: [" ", "(Solver: ", formatVersionDisplay(vItem.hpsVersion), ")"] })), vItem.isCurrent && (_jsx(Text, { color: colors.warning, children: " current" })), _jsxs(Text, { color: colors.muted, children: [" ", formatDate(vItem.date)] })] }));
235
+ } }) })] }) }));
236
+ }
237
+ export function UpgradeCommand(props) {
238
+ return (_jsxs(ThemeProvider, { theme: "upgrade", children: [_jsx(Logo, {}), _jsx(UpgradeCommandInner, { ...props })] }));
239
+ }
@@ -0,0 +1,9 @@
1
+ interface DNSWaitScreenProps {
2
+ domain: string;
3
+ selfHostedSupabase: boolean;
4
+ namespace: string;
5
+ onComplete: () => void;
6
+ onSkip?: () => void;
7
+ }
8
+ export declare function DNSWaitScreen({ domain, selfHostedSupabase, namespace, onComplete, onSkip, }: DNSWaitScreenProps): import("react/jsx-runtime").JSX.Element;
9
+ export {};
@@ -0,0 +1,73 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState, useEffect, useRef } from "react";
3
+ import { Box, Text, useInput } from "ink";
4
+ import InkSpinner from "ink-spinner";
5
+ import { BorderBox, Spinner, useTheme } from "./common/index.js";
6
+ import { getLoadBalancerAddress, getRequiredDNSRecords, checkDNSRecord, isDNSComplete, } from "../lib/dns.js";
7
+ export function DNSWaitScreen({ domain, selfHostedSupabase, namespace, onComplete, onSkip, }) {
8
+ const { colors } = useTheme();
9
+ const [status, setStatus] = useState("loading-lb");
10
+ const [loadBalancer, setLoadBalancer] = useState(null);
11
+ const [records, setRecords] = useState([]);
12
+ const [error, setError] = useState(null);
13
+ const [pollCount, setPollCount] = useState(0);
14
+ // Use ref to avoid stale closure in polling interval
15
+ const recordsRef = useRef(records);
16
+ recordsRef.current = records;
17
+ useInput((input, key) => {
18
+ if (key.escape || input.toLowerCase() === "s") {
19
+ onSkip?.();
20
+ }
21
+ if (key.return && status === "complete") {
22
+ onComplete();
23
+ }
24
+ });
25
+ // Fetch load balancer address
26
+ useEffect(() => {
27
+ const fetchLB = async () => {
28
+ const result = await getLoadBalancerAddress(namespace);
29
+ if (!result.address) {
30
+ setError("Could not determine load balancer address. Make sure the deployment is running.");
31
+ setStatus("error");
32
+ return;
33
+ }
34
+ setLoadBalancer({ address: result.address, type: result.type });
35
+ const dnsRecords = getRequiredDNSRecords(domain, result.address, result.type, selfHostedSupabase);
36
+ setRecords(dnsRecords);
37
+ setStatus("waiting-dns");
38
+ };
39
+ fetchLB();
40
+ }, [domain, selfHostedSupabase, namespace]);
41
+ // Poll DNS records
42
+ useEffect(() => {
43
+ if (status !== "waiting-dns")
44
+ return;
45
+ const pollDNS = async () => {
46
+ // Use ref to get current records, avoiding stale closure
47
+ const currentRecords = recordsRef.current;
48
+ const updatedRecords = await Promise.all(currentRecords.map(async (record) => {
49
+ if (record.verified)
50
+ return record;
51
+ const result = await checkDNSRecord(record.hostname, record.target);
52
+ return {
53
+ ...record,
54
+ verified: result.resolved && result.matchesTarget,
55
+ };
56
+ }));
57
+ setRecords(updatedRecords);
58
+ setPollCount((c) => c + 1);
59
+ if (isDNSComplete(updatedRecords)) {
60
+ setStatus("complete");
61
+ }
62
+ };
63
+ // Initial check
64
+ pollDNS();
65
+ // Poll every 5 seconds
66
+ const interval = setInterval(pollDNS, 5000);
67
+ return () => clearInterval(interval);
68
+ }, [status]);
69
+ const verifiedCount = records.filter((r) => r.verified).length;
70
+ return (_jsxs(BorderBox, { title: "Configure DNS Records", children: [status === "loading-lb" && (_jsx(Box, { flexDirection: "column", marginY: 1, children: _jsx(Spinner, { label: "Getting load balancer address..." }) })), status === "error" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { color: colors.error, bold: true, children: "\u2717 Error" }), _jsx(Text, { color: colors.error, children: error }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: colors.muted, children: "Press Esc to skip DNS validation" }) })] })), (status === "waiting-dns" || status === "complete") && loadBalancer && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Your load balancer address:" }), _jsx(Box, { marginY: 1, children: _jsx(Text, { color: colors.accent, bold: true, children: loadBalancer.address }) }), _jsx(Text, { children: "Please add the following DNS records:" }), _jsx(Box, { marginTop: 1, flexDirection: "column", children: records.map((record, idx) => (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsxs(Box, { children: [record.verified ? (_jsx(Text, { color: colors.success, children: "\u2713" })) : (_jsx(Text, { color: colors.accent, children: _jsx(InkSpinner, { type: "dots" }) })), _jsx(Text, { children: " " }), _jsx(Text, { color: record.verified ? colors.success : undefined, children: record.hostname })] }), _jsxs(Box, { marginLeft: 2, children: [_jsx(Text, { color: colors.accent, children: record.type }), _jsx(Text, { color: colors.muted, children: " \u2192 " }), _jsx(Text, { color: colors.accent, children: record.target })] })] }, idx))) }), _jsx(Box, { marginTop: 2, children: status === "waiting-dns" ? (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { children: _jsx(Spinner, { label: `Checking DNS propagation... (${verifiedCount}/${records.length} complete)` }) }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: colors.muted, dimColor: true, children: ["Poll #", pollCount, " \u2022 DNS changes can take up to 48 hours to propagate"] }) })] })) : (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: colors.success, bold: true, children: "\u2713 All DNS records verified!" }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: colors.muted, children: "Press Enter to continue with TLS setup" }) })] })) })] })), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: colors.muted, dimColor: true, children: status === "complete"
71
+ ? "Enter to continue"
72
+ : "S or Esc to skip DNS validation (not recommended)" }) })] }));
73
+ }
@@ -0,0 +1,176 @@
1
+ import React, { ReactNode } from "react";
2
+ import { DeploymentConfig, CloudProvider, DatabaseType, PerformanceTier, SSOProvider, DnsProvider, LoggingSink, EmailSubjects, EmailTemplates, ProfileConfig } from "../../types/index.js";
3
+ export interface WizardState {
4
+ step: number;
5
+ name: string;
6
+ infrastructureMode: "existing" | "provision" | null;
7
+ provider: CloudProvider | null;
8
+ region: string;
9
+ clusterName: string;
10
+ gcpProjectId: string;
11
+ azureResourceGroup: string;
12
+ domain: string;
13
+ adminEmail: string;
14
+ tlsEmail: string;
15
+ dnsProvider: DnsProvider;
16
+ dnsAutoManage: boolean;
17
+ existingExternalDns: boolean;
18
+ smtpHost: string;
19
+ smtpPort: number;
20
+ smtpUser: string;
21
+ smtpPass: string;
22
+ smtpFrom: string;
23
+ smtpFromName: string;
24
+ databaseType: DatabaseType | null;
25
+ supabaseUrl: string;
26
+ supabaseAnonKey: string;
27
+ supabaseServiceKey: string;
28
+ supabaseAccessToken: string;
29
+ supabaseProjectRef: string;
30
+ supabaseJwtSecret: string;
31
+ supabaseDbPassword: string;
32
+ supabaseDashboardUser: string;
33
+ supabaseDashboardPass: string;
34
+ tier: PerformanceTier | null;
35
+ aiEnabled: boolean;
36
+ openaiApiKey: string;
37
+ ssoEnabled: boolean;
38
+ ssoProvider: SSOProvider | null;
39
+ ssoUrl: string;
40
+ ssoClientId: string;
41
+ ssoClientSecret: string;
42
+ monitoringEnabled: boolean;
43
+ prometheusRemoteWriteUrl: string;
44
+ loggingSink: LoggingSink;
45
+ loggingBucket: string;
46
+ loggingRegion: string;
47
+ customEmailsEnabled: boolean;
48
+ emailSubjects: EmailSubjects;
49
+ emailTemplates: EmailTemplates;
50
+ licenseKey: string;
51
+ appVersion: string;
52
+ hpsVersion: string;
53
+ chartVersion: string;
54
+ }
55
+ type WizardAction = {
56
+ type: "SET_STEP";
57
+ step: number;
58
+ } | {
59
+ type: "SET_NAME";
60
+ name: string;
61
+ } | {
62
+ type: "SET_INFRA_MODE";
63
+ mode: "existing" | "provision";
64
+ } | {
65
+ type: "SET_PROVIDER";
66
+ provider: CloudProvider;
67
+ } | {
68
+ type: "SET_REGION";
69
+ region: string;
70
+ } | {
71
+ type: "SET_CLUSTER_NAME";
72
+ clusterName: string;
73
+ } | {
74
+ type: "SET_GCP_PROJECT";
75
+ projectId: string;
76
+ } | {
77
+ type: "SET_AZURE_RG";
78
+ resourceGroup: string;
79
+ } | {
80
+ type: "SET_DOMAIN";
81
+ domain: string;
82
+ } | {
83
+ type: "SET_ADMIN_EMAIL";
84
+ email: string;
85
+ } | {
86
+ type: "SET_TLS_EMAIL";
87
+ email: string;
88
+ } | {
89
+ type: "SET_DNS_PROVIDER";
90
+ provider: DnsProvider;
91
+ } | {
92
+ type: "SET_DNS_AUTO_MANAGE";
93
+ autoManage: boolean;
94
+ } | {
95
+ type: "SET_EXISTING_EXTERNAL_DNS";
96
+ exists: boolean;
97
+ } | {
98
+ type: "SET_SMTP";
99
+ config: Partial<Pick<WizardState, "smtpHost" | "smtpPort" | "smtpUser" | "smtpPass" | "smtpFrom" | "smtpFromName">>;
100
+ } | {
101
+ type: "SET_DATABASE_TYPE";
102
+ dbType: DatabaseType;
103
+ } | {
104
+ type: "SET_SUPABASE_CONFIG";
105
+ config: Partial<WizardState>;
106
+ } | {
107
+ type: "SET_SUPABASE_SELF_HOSTED";
108
+ config: Partial<Pick<WizardState, "supabaseJwtSecret" | "supabaseDbPassword" | "supabaseDashboardUser" | "supabaseDashboardPass">>;
109
+ } | {
110
+ type: "SET_TIER";
111
+ tier: PerformanceTier;
112
+ } | {
113
+ type: "SET_AI_ENABLED";
114
+ enabled: boolean;
115
+ } | {
116
+ type: "SET_OPENAI_KEY";
117
+ key: string;
118
+ } | {
119
+ type: "SET_SSO_ENABLED";
120
+ enabled: boolean;
121
+ } | {
122
+ type: "SET_SSO_CONFIG";
123
+ config: Partial<Pick<WizardState, "ssoProvider" | "ssoUrl" | "ssoClientId" | "ssoClientSecret">>;
124
+ } | {
125
+ type: "SET_MONITORING";
126
+ enabled: boolean;
127
+ } | {
128
+ type: "SET_PROMETHEUS_REMOTE_WRITE";
129
+ url: string;
130
+ } | {
131
+ type: "SET_LOGGING_SINK";
132
+ sink: LoggingSink;
133
+ } | {
134
+ type: "SET_LOGGING_CONFIG";
135
+ config: Partial<Pick<WizardState, "loggingBucket" | "loggingRegion">>;
136
+ } | {
137
+ type: "SET_CUSTOM_EMAILS_ENABLED";
138
+ enabled: boolean;
139
+ } | {
140
+ type: "SET_EMAIL_SUBJECTS";
141
+ subjects: Partial<EmailSubjects>;
142
+ } | {
143
+ type: "SET_EMAIL_TEMPLATES";
144
+ templates: Partial<EmailTemplates>;
145
+ } | {
146
+ type: "SET_LICENSE_KEY";
147
+ key: string;
148
+ } | {
149
+ type: "SET_APP_VERSION";
150
+ appVersion: string;
151
+ hpsVersion: string;
152
+ } | {
153
+ type: "SET_CHART_VERSION";
154
+ version: string;
155
+ } | {
156
+ type: "NEXT_STEP";
157
+ } | {
158
+ type: "PREV_STEP";
159
+ };
160
+ interface WizardContextValue {
161
+ state: WizardState;
162
+ dispatch: React.Dispatch<WizardAction>;
163
+ toConfig: () => DeploymentConfig | null;
164
+ skipToStep: (stepId: string) => void;
165
+ profile: ProfileConfig | null;
166
+ /** Suggests a domain based on the profile's domain suffix and deployment name */
167
+ suggestDomain: (name: string) => string;
168
+ }
169
+ interface WizardProviderProps {
170
+ children: ReactNode;
171
+ initialName?: string;
172
+ profile?: ProfileConfig | null;
173
+ }
174
+ export declare function WizardProvider({ children, initialName, profile, }: WizardProviderProps): import("react/jsx-runtime").JSX.Element;
175
+ export declare function useWizard(): WizardContextValue;
176
+ export {};