betterstart-cli 0.0.90 → 0.0.92
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +730 -568
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +10 -19
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -22,10 +22,9 @@ import {
|
|
|
22
22
|
|
|
23
23
|
// cli.ts
|
|
24
24
|
import { readFileSync } from "fs";
|
|
25
|
-
import * as
|
|
25
|
+
import * as p31 from "@clack/prompts";
|
|
26
26
|
|
|
27
|
-
// core-engine/commands/
|
|
28
|
-
import path2 from "path";
|
|
27
|
+
// core-engine/commands/default-action.ts
|
|
29
28
|
import * as p from "@clack/prompts";
|
|
30
29
|
|
|
31
30
|
// core-engine/config/resolver.ts
|
|
@@ -49,22 +48,9 @@ async function loadConfigFile(configPath) {
|
|
|
49
48
|
return mod.default || mod;
|
|
50
49
|
}
|
|
51
50
|
|
|
52
|
-
// core-engine/
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const options = command.opts();
|
|
56
|
-
return typeof options.cwd === "string" ? path2.resolve(options.cwd) : process.cwd();
|
|
57
|
-
}
|
|
58
|
-
function requireInitializedProject(command) {
|
|
59
|
-
if (command.name() === INIT_COMMAND) {
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
const cwd = resolveCommandCwd(command);
|
|
63
|
-
if (findConfigFile(cwd)) {
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
p.log.error("Couldn't find betterstart project. Please run `betterstart init` first.");
|
|
67
|
-
process.exit(1);
|
|
51
|
+
// core-engine/utils/interactive.ts
|
|
52
|
+
function isInteractiveSession() {
|
|
53
|
+
return Boolean(process.stdin.isTTY) && process.env.CI !== "true";
|
|
68
54
|
}
|
|
69
55
|
|
|
70
56
|
// core-engine/commands/runtime.ts
|
|
@@ -196,9 +182,142 @@ function createUpdateStylesCommand(runtime) {
|
|
|
196
182
|
return new Command("update-styles").description("Replace admin-globals.css with the latest version from the CLI").option("--cwd <path>", "Project root path").action((options) => runtime.runUpdateStyles(options));
|
|
197
183
|
}
|
|
198
184
|
|
|
185
|
+
// core-engine/commands/default-action.ts
|
|
186
|
+
var ADD_COMMAND = "add";
|
|
187
|
+
var CREATE_COMMAND = "create";
|
|
188
|
+
var INIT_COMMAND = "init";
|
|
189
|
+
var REMOVE_COMMAND = "remove";
|
|
190
|
+
var REMOVE_SCHEMA_COMMAND = "remove-schema";
|
|
191
|
+
var CANCELLED = /* @__PURE__ */ Symbol("cancelled");
|
|
192
|
+
function cancelled(value) {
|
|
193
|
+
return value === CANCELLED;
|
|
194
|
+
}
|
|
195
|
+
async function runDefaultAction(program2, runtime) {
|
|
196
|
+
if (!isInteractiveSession()) {
|
|
197
|
+
program2.outputHelp();
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
const cwd = process.cwd();
|
|
201
|
+
if (!findConfigFile(cwd)) {
|
|
202
|
+
await program2.parseAsync([INIT_COMMAND], { from: "user" });
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
const argv = await promptInvocation(program2, runtime, cwd);
|
|
206
|
+
if (cancelled(argv)) {
|
|
207
|
+
p.cancel("No command selected.");
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
await program2.parseAsync(argv, { from: "user" });
|
|
211
|
+
}
|
|
212
|
+
async function promptInvocation(program2, runtime, cwd) {
|
|
213
|
+
const name = await p.select({
|
|
214
|
+
message: "What do you want to do?",
|
|
215
|
+
options: program2.commands.map((command) => ({
|
|
216
|
+
value: command.name(),
|
|
217
|
+
label: command.name(),
|
|
218
|
+
hint: command.description()
|
|
219
|
+
}))
|
|
220
|
+
});
|
|
221
|
+
if (p.isCancel(name)) {
|
|
222
|
+
return CANCELLED;
|
|
223
|
+
}
|
|
224
|
+
const args = await promptRequiredArguments(name, runtime, cwd);
|
|
225
|
+
if (cancelled(args)) {
|
|
226
|
+
return CANCELLED;
|
|
227
|
+
}
|
|
228
|
+
return [name, ...args];
|
|
229
|
+
}
|
|
230
|
+
async function promptRequiredArguments(name, runtime, cwd) {
|
|
231
|
+
if (name === CREATE_COMMAND) {
|
|
232
|
+
const kind = await p.select({
|
|
233
|
+
message: "Schema kind",
|
|
234
|
+
options: CREATE_SCHEMA_KINDS.map((value) => ({ value, label: value }))
|
|
235
|
+
});
|
|
236
|
+
return p.isCancel(kind) ? CANCELLED : [kind];
|
|
237
|
+
}
|
|
238
|
+
if (name === ADD_COMMAND || name === REMOVE_COMMAND) {
|
|
239
|
+
return promptInstallables(name, runtime, cwd);
|
|
240
|
+
}
|
|
241
|
+
if (name === REMOVE_SCHEMA_COMMAND) {
|
|
242
|
+
const schemas = await runtime.listSchemaChoices(cwd);
|
|
243
|
+
if (schemas.length === 0) {
|
|
244
|
+
p.log.warn("No schemas to remove.");
|
|
245
|
+
return CANCELLED;
|
|
246
|
+
}
|
|
247
|
+
const schema = await p.select({
|
|
248
|
+
message: "Schema to remove",
|
|
249
|
+
options: schemas.map((value) => ({ value, label: value }))
|
|
250
|
+
});
|
|
251
|
+
return p.isCancel(schema) ? CANCELLED : [schema];
|
|
252
|
+
}
|
|
253
|
+
return [];
|
|
254
|
+
}
|
|
255
|
+
async function promptInstallables(name, runtime, cwd) {
|
|
256
|
+
const removing = name === REMOVE_COMMAND;
|
|
257
|
+
const choices = await runtime.listInstallableChoices(cwd);
|
|
258
|
+
const presets = choices.presets.filter((choice) => choice.installed === removing);
|
|
259
|
+
const integrations = choices.integrations.filter((choice) => choice.installed === removing);
|
|
260
|
+
if (presets.length === 0 && integrations.length === 0) {
|
|
261
|
+
p.log.warn(removing ? "Nothing installed to remove." : "Everything available is installed.");
|
|
262
|
+
return CANCELLED;
|
|
263
|
+
}
|
|
264
|
+
const family = await promptInstallableFamily(presets, integrations);
|
|
265
|
+
if (cancelled(family)) {
|
|
266
|
+
return CANCELLED;
|
|
267
|
+
}
|
|
268
|
+
const items = await p.multiselect({
|
|
269
|
+
message: removing ? "Items to remove" : "Items to install",
|
|
270
|
+
options: (family === "integration" ? integrations : presets).map((choice) => ({
|
|
271
|
+
value: choice.id,
|
|
272
|
+
label: choice.id,
|
|
273
|
+
hint: choice.description
|
|
274
|
+
}))
|
|
275
|
+
});
|
|
276
|
+
if (p.isCancel(items)) {
|
|
277
|
+
return CANCELLED;
|
|
278
|
+
}
|
|
279
|
+
return family === "integration" ? ["--integration", ...items] : items;
|
|
280
|
+
}
|
|
281
|
+
async function promptInstallableFamily(presets, integrations) {
|
|
282
|
+
if (integrations.length === 0) {
|
|
283
|
+
return "preset";
|
|
284
|
+
}
|
|
285
|
+
if (presets.length === 0) {
|
|
286
|
+
return "integration";
|
|
287
|
+
}
|
|
288
|
+
const family = await p.select({
|
|
289
|
+
message: "Presets or integrations?",
|
|
290
|
+
options: [
|
|
291
|
+
{ value: "preset", label: "Presets", hint: "content presets (e.g. blog)" },
|
|
292
|
+
{ value: "integration", label: "Integrations", hint: "services (e.g. r2, resend)" }
|
|
293
|
+
]
|
|
294
|
+
});
|
|
295
|
+
return p.isCancel(family) ? CANCELLED : family;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// core-engine/commands/require-init.ts
|
|
299
|
+
import path2 from "path";
|
|
300
|
+
import * as p2 from "@clack/prompts";
|
|
301
|
+
var INIT_COMMAND2 = "init";
|
|
302
|
+
function resolveCommandCwd(command) {
|
|
303
|
+
const options = command.opts();
|
|
304
|
+
return typeof options.cwd === "string" ? path2.resolve(options.cwd) : process.cwd();
|
|
305
|
+
}
|
|
306
|
+
function requireInitializedProject(command) {
|
|
307
|
+
if (command.name() === INIT_COMMAND2) {
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
const cwd = resolveCommandCwd(command);
|
|
311
|
+
if (findConfigFile(cwd)) {
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
p2.log.error("Couldn't find betterstart project. Please run `betterstart init` first.");
|
|
315
|
+
process.exit(1);
|
|
316
|
+
}
|
|
317
|
+
|
|
199
318
|
// adapters/next/commands/add.ts
|
|
200
319
|
import path27 from "path";
|
|
201
|
-
import * as
|
|
320
|
+
import * as p9 from "@clack/prompts";
|
|
202
321
|
|
|
203
322
|
// core-engine/config/serialize.ts
|
|
204
323
|
import fs3 from "fs";
|
|
@@ -747,10 +866,93 @@ async function resolveConfigOrExit(cwd) {
|
|
|
747
866
|
}
|
|
748
867
|
|
|
749
868
|
// adapters/next/generators/post-generate.ts
|
|
750
|
-
import {
|
|
869
|
+
import { execFile } from "child_process";
|
|
751
870
|
import fs8 from "fs";
|
|
752
871
|
import path10 from "path";
|
|
753
|
-
import
|
|
872
|
+
import { promisify } from "util";
|
|
873
|
+
import * as p6 from "@clack/prompts";
|
|
874
|
+
|
|
875
|
+
// core-engine/utils/spinner.ts
|
|
876
|
+
import { stripVTControlCharacters } from "util";
|
|
877
|
+
import * as p3 from "@clack/prompts";
|
|
878
|
+
var RENDER_OVERHEAD = 7;
|
|
879
|
+
var MIN_MESSAGE_WIDTH = 8;
|
|
880
|
+
function fitSpinnerMessage(message) {
|
|
881
|
+
const normalized = message.replace(/\t/g, " ");
|
|
882
|
+
const columns = process.stdout.columns ?? 80;
|
|
883
|
+
const max = Math.max(columns - RENDER_OVERHEAD, MIN_MESSAGE_WIDTH);
|
|
884
|
+
const visible = stripVTControlCharacters(normalized);
|
|
885
|
+
if (visible.length <= max) return normalized;
|
|
886
|
+
return `${visible.slice(0, max - 1)}\u2026`;
|
|
887
|
+
}
|
|
888
|
+
var CLACK_LINE_ROWS = 2;
|
|
889
|
+
var LOG_PREFIX_WIDTH = 3;
|
|
890
|
+
function clackPromptRows(message, value) {
|
|
891
|
+
const columns = process.stdout.columns ?? 80;
|
|
892
|
+
const rows = (text7) => Math.max(1, Math.ceil((stripVTControlCharacters(text7).length + LOG_PREFIX_WIDTH) / columns));
|
|
893
|
+
return 1 + rows(message) + rows(value);
|
|
894
|
+
}
|
|
895
|
+
function clackLogRows(message) {
|
|
896
|
+
const columns = process.stdout.columns ?? 80;
|
|
897
|
+
const width = stripVTControlCharacters(message).length + LOG_PREFIX_WIDTH;
|
|
898
|
+
return 1 + Math.max(1, Math.ceil(width / columns));
|
|
899
|
+
}
|
|
900
|
+
function eraseRows(rows) {
|
|
901
|
+
if (rows <= 0 || !process.stdout.isTTY || process.env.CI === "true") return;
|
|
902
|
+
process.stdout.write(`\x1B[${rows}A\x1B[${rows}M`);
|
|
903
|
+
}
|
|
904
|
+
function eraseRowsAbove(rows, rowsBelow) {
|
|
905
|
+
if (rows <= 0 || rowsBelow < 0 || !process.stdout.isTTY || process.env.CI === "true") {
|
|
906
|
+
return;
|
|
907
|
+
}
|
|
908
|
+
const up = rows + rowsBelow;
|
|
909
|
+
const restore = rowsBelow > 0 ? `\x1B[${rowsBelow}B` : "";
|
|
910
|
+
process.stdout.write(`\x1B[${up}A\x1B[${rows}M${restore}`);
|
|
911
|
+
}
|
|
912
|
+
function eraseClackLine(options = {}) {
|
|
913
|
+
if (!process.stdout.isTTY || process.env.CI === "true") return;
|
|
914
|
+
const below = (options.linesBelow ?? 0) * CLACK_LINE_ROWS;
|
|
915
|
+
const up = below + CLACK_LINE_ROWS;
|
|
916
|
+
const restore = below > 0 ? `\x1B[${below}B` : "";
|
|
917
|
+
process.stdout.write(`\x1B[${up}A\x1B[${CLACK_LINE_ROWS}M${restore}`);
|
|
918
|
+
}
|
|
919
|
+
var activeSpinners = 0;
|
|
920
|
+
function hasActiveSpinner() {
|
|
921
|
+
return activeSpinners > 0;
|
|
922
|
+
}
|
|
923
|
+
function spinner2(options) {
|
|
924
|
+
const inner = p3.spinner({ ...options, cancelMessage: "Setup cancelled." });
|
|
925
|
+
const guided = options?.withGuide !== false;
|
|
926
|
+
let started = false;
|
|
927
|
+
const setStarted = (next) => {
|
|
928
|
+
if (started === next) return;
|
|
929
|
+
started = next;
|
|
930
|
+
activeSpinners += next ? 1 : -1;
|
|
931
|
+
};
|
|
932
|
+
return {
|
|
933
|
+
start: (message = "") => {
|
|
934
|
+
if (started) {
|
|
935
|
+
inner.message(fitSpinnerMessage(message));
|
|
936
|
+
return;
|
|
937
|
+
}
|
|
938
|
+
setStarted(true);
|
|
939
|
+
inner.start(fitSpinnerMessage(message));
|
|
940
|
+
},
|
|
941
|
+
message: (message = "") => inner.message(fitSpinnerMessage(message)),
|
|
942
|
+
stop: (message = "") => {
|
|
943
|
+
setStarted(false);
|
|
944
|
+
inner.stop(message);
|
|
945
|
+
},
|
|
946
|
+
clear: () => {
|
|
947
|
+
if (!started) return;
|
|
948
|
+
setStarted(false);
|
|
949
|
+
inner.clear();
|
|
950
|
+
if (guided && process.stdout.isTTY && process.env.CI !== "true") {
|
|
951
|
+
process.stdout.write("\x1B[1A\x1B[2K");
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
};
|
|
955
|
+
}
|
|
754
956
|
|
|
755
957
|
// adapters/next/init/scaffolders/dependencies.ts
|
|
756
958
|
import { spawn } from "child_process";
|
|
@@ -1633,7 +1835,7 @@ async function syncProjectCliDependency(cwd, pm) {
|
|
|
1633
1835
|
// adapters/next/utils/drizzle-push.ts
|
|
1634
1836
|
import { spawn as spawn2 } from "child_process";
|
|
1635
1837
|
import path9 from "path";
|
|
1636
|
-
import * as
|
|
1838
|
+
import * as p4 from "@clack/prompts";
|
|
1637
1839
|
var PG_SSL_WARNING_START = "Warning: SECURITY WARNING: The SSL modes 'prefer', 'require', and 'verify-ca' are treated as aliases for 'verify-full'.";
|
|
1638
1840
|
var PG_SSL_WARNING_END = "See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode definitions.";
|
|
1639
1841
|
var NODE_TRACE_WARNING_HINT = "(Use `node --trace-warnings";
|
|
@@ -1809,7 +2011,7 @@ function runDrizzlePush(cwd, options = {}) {
|
|
|
1809
2011
|
}
|
|
1810
2012
|
if (stdoutTtySuppressor.sawError() || stderrTtySuppressor.sawError()) {
|
|
1811
2013
|
notifyOutput();
|
|
1812
|
-
|
|
2014
|
+
p4.log.info("Database changes need your input \u2014 continuing in drizzle-kit.");
|
|
1813
2015
|
const attached = spawn2(drizzleBin, ["push", "--force"], {
|
|
1814
2016
|
cwd,
|
|
1815
2017
|
stdio: "inherit",
|
|
@@ -1855,7 +2057,7 @@ ${stderr}`.trim();
|
|
|
1855
2057
|
}
|
|
1856
2058
|
|
|
1857
2059
|
// adapters/next/utils/next-steps.ts
|
|
1858
|
-
import * as
|
|
2060
|
+
import * as p5 from "@clack/prompts";
|
|
1859
2061
|
function printNextSteps(options) {
|
|
1860
2062
|
const steps = [`1. Review ${options.reviewLabel}`];
|
|
1861
2063
|
if (options.needsMigration) {
|
|
@@ -1864,11 +2066,12 @@ function printNextSteps(options) {
|
|
|
1864
2066
|
} else {
|
|
1865
2067
|
steps.push(`2. Start the dev server and visit ${options.route}`);
|
|
1866
2068
|
}
|
|
1867
|
-
|
|
2069
|
+
p5.note(steps.join("\n"), "Next steps");
|
|
1868
2070
|
}
|
|
1869
2071
|
|
|
1870
2072
|
// adapters/next/generators/post-generate.ts
|
|
1871
2073
|
var BIOME_FORMAT_TIMEOUT_MS = 3e4;
|
|
2074
|
+
var execFileAsync = promisify(execFile);
|
|
1872
2075
|
function loadEnvFile(cwd) {
|
|
1873
2076
|
const envPath = path10.join(cwd, ".env.local");
|
|
1874
2077
|
if (!fs8.existsSync(envPath)) return;
|
|
@@ -1892,10 +2095,10 @@ function loadEnvFile(cwd) {
|
|
|
1892
2095
|
}
|
|
1893
2096
|
}
|
|
1894
2097
|
}
|
|
1895
|
-
function runPmScript(pm, script, cwd, timeout) {
|
|
2098
|
+
async function runPmScript(pm, script, cwd, timeout) {
|
|
1896
2099
|
const args = pm === "bun" ? ["run", script] : [script];
|
|
1897
2100
|
try {
|
|
1898
|
-
|
|
2101
|
+
await execFileAsync(pm, args, { cwd, timeout });
|
|
1899
2102
|
return true;
|
|
1900
2103
|
} catch {
|
|
1901
2104
|
return false;
|
|
@@ -1906,7 +2109,7 @@ function getExistingTrackedFilePaths(cwd) {
|
|
|
1906
2109
|
(filePath) => fs8.existsSync(path10.join(cwd, ...filePath.split("/")))
|
|
1907
2110
|
);
|
|
1908
2111
|
}
|
|
1909
|
-
function runBiomeCheckWrite(cwd) {
|
|
2112
|
+
async function runBiomeCheckWrite(cwd) {
|
|
1910
2113
|
const biomeBin = path10.join(cwd, "node_modules", ".bin", "biome");
|
|
1911
2114
|
if (!fs8.existsSync(biomeBin)) {
|
|
1912
2115
|
return false;
|
|
@@ -1925,9 +2128,8 @@ function runBiomeCheckWrite(cwd) {
|
|
|
1925
2128
|
...configPath ? ["--config-path", configPath] : [],
|
|
1926
2129
|
...chunk
|
|
1927
2130
|
];
|
|
1928
|
-
|
|
2131
|
+
await execFileAsync(biomeBin, args, {
|
|
1929
2132
|
cwd,
|
|
1930
|
-
stdio: "pipe",
|
|
1931
2133
|
timeout: BIOME_FORMAT_TIMEOUT_MS
|
|
1932
2134
|
});
|
|
1933
2135
|
}
|
|
@@ -1944,18 +2146,15 @@ function buildAddDependencyArgs(pm, dependency, dev) {
|
|
|
1944
2146
|
return ["install", ...devFlag ? [devFlag] : [], dependency];
|
|
1945
2147
|
}
|
|
1946
2148
|
}
|
|
1947
|
-
function installDependency(cwd, pm, dependency, dev = false) {
|
|
2149
|
+
async function installDependency(cwd, pm, dependency, dev = false) {
|
|
1948
2150
|
try {
|
|
1949
|
-
|
|
1950
|
-
cwd,
|
|
1951
|
-
stdio: "pipe"
|
|
1952
|
-
});
|
|
2151
|
+
await execFileAsync(pm, buildAddDependencyArgs(pm, dependency, dev), { cwd });
|
|
1953
2152
|
return true;
|
|
1954
2153
|
} catch {
|
|
1955
2154
|
return false;
|
|
1956
2155
|
}
|
|
1957
2156
|
}
|
|
1958
|
-
function ensureDatabasePushDependencies(cwd, pm) {
|
|
2157
|
+
async function ensureDatabasePushDependencies(cwd, pm) {
|
|
1959
2158
|
const missing = [];
|
|
1960
2159
|
if (!hasPostgresRuntimeDependency(cwd)) {
|
|
1961
2160
|
missing.push({ name: POSTGRES_RUNTIME_DEP, dev: false });
|
|
@@ -1966,25 +2165,25 @@ function ensureDatabasePushDependencies(cwd, pm) {
|
|
|
1966
2165
|
if (missing.length === 0) {
|
|
1967
2166
|
return true;
|
|
1968
2167
|
}
|
|
1969
|
-
|
|
2168
|
+
p6.log.info(
|
|
1970
2169
|
`Installing database push dependencies (${missing.map((dependency) => dependency.name).join(", ")})...`
|
|
1971
2170
|
);
|
|
1972
2171
|
for (const dependency of missing) {
|
|
1973
|
-
const installed2 = installDependency(cwd, pm, dependency.name, dependency.dev);
|
|
2172
|
+
const installed2 = await installDependency(cwd, pm, dependency.name, dependency.dev);
|
|
1974
2173
|
if (!installed2) {
|
|
1975
|
-
|
|
2174
|
+
p6.log.warn(`Failed to install ${dependency.name}`);
|
|
1976
2175
|
return false;
|
|
1977
2176
|
}
|
|
1978
2177
|
}
|
|
1979
2178
|
const ready = hasPostgresRuntimeDependency(cwd) && hasDrizzleKitPostgresDriverDependency(cwd);
|
|
1980
2179
|
if (ready) {
|
|
1981
|
-
|
|
2180
|
+
p6.log.success("Database push dependencies installed");
|
|
1982
2181
|
} else {
|
|
1983
2182
|
const unresolved = [
|
|
1984
2183
|
!hasPostgresRuntimeDependency(cwd) ? POSTGRES_RUNTIME_DEP : null,
|
|
1985
2184
|
!hasDrizzleKitPostgresDriverDependency(cwd) ? DRIZZLE_KIT_POSTGRES_DRIVER_DEP : null
|
|
1986
2185
|
].filter((dependency) => Boolean(dependency));
|
|
1987
|
-
|
|
2186
|
+
p6.log.warn(`Installed dependencies but could not resolve ${unresolved.join(", ")}`);
|
|
1988
2187
|
}
|
|
1989
2188
|
return ready;
|
|
1990
2189
|
}
|
|
@@ -2027,8 +2226,8 @@ async function runPostGenerate(cwd, schemaName, options = {}) {
|
|
|
2027
2226
|
"Formatting: skipped (biome refuses files with conflict markers)",
|
|
2028
2227
|
...(options.conflictPaths ?? []).map((conflictPath) => ` - ${conflictPath}`)
|
|
2029
2228
|
];
|
|
2030
|
-
|
|
2031
|
-
|
|
2229
|
+
p6.log.warn(lines.join("\n"));
|
|
2230
|
+
p6.log.message(
|
|
2032
2231
|
"Resolve markers in the files above and re-run the BetterStart command that wrote them. Post-write tasks run automatically once every file is clean."
|
|
2033
2232
|
);
|
|
2034
2233
|
return result;
|
|
@@ -2038,62 +2237,83 @@ async function runPostGenerate(cwd, schemaName, options = {}) {
|
|
|
2038
2237
|
const dbUrl = process.env.DATABASE_URL;
|
|
2039
2238
|
if (!dbUrl) {
|
|
2040
2239
|
result.dbPush = "no-db-url";
|
|
2041
|
-
|
|
2240
|
+
p6.log.warn(
|
|
2042
2241
|
[
|
|
2043
2242
|
"Database: skipped (no DATABASE_URL configured)",
|
|
2044
2243
|
" To sync later: run db:push after setting DATABASE_URL"
|
|
2045
2244
|
].join("\n")
|
|
2046
2245
|
);
|
|
2047
|
-
} else if (!ensureDatabasePushDependencies(cwd, pm)) {
|
|
2246
|
+
} else if (!await ensureDatabasePushDependencies(cwd, pm)) {
|
|
2048
2247
|
result.dbPush = "failed";
|
|
2049
|
-
|
|
2248
|
+
p6.log.warn(
|
|
2050
2249
|
"Database push failed (install database dependencies and run drizzle-kit push manually)"
|
|
2051
2250
|
);
|
|
2052
2251
|
} else if (hasPkgScript(cwd, "db:push")) {
|
|
2053
|
-
|
|
2054
|
-
|
|
2252
|
+
const s = spinner2();
|
|
2253
|
+
s.start("Pushing database schema");
|
|
2254
|
+
const ok = await runPmScript(pm, "db:push", cwd);
|
|
2055
2255
|
result.dbPush = ok ? "success" : "failed";
|
|
2056
2256
|
if (ok) {
|
|
2057
|
-
|
|
2257
|
+
s.stop("Database schema synced");
|
|
2058
2258
|
} else {
|
|
2059
|
-
|
|
2259
|
+
s.clear();
|
|
2260
|
+
p6.log.warn("Database push failed (run db:push manually)");
|
|
2060
2261
|
}
|
|
2061
2262
|
} else {
|
|
2062
|
-
|
|
2263
|
+
const s = spinner2();
|
|
2264
|
+
let spinnerVisible = true;
|
|
2265
|
+
const clearSpinner = () => {
|
|
2266
|
+
if (!spinnerVisible) return;
|
|
2267
|
+
spinnerVisible = false;
|
|
2268
|
+
s.clear();
|
|
2269
|
+
};
|
|
2270
|
+
s.start("Pushing database schema");
|
|
2063
2271
|
try {
|
|
2064
|
-
const pushResult = await runDrizzlePush(cwd, {
|
|
2272
|
+
const pushResult = await runDrizzlePush(cwd, {
|
|
2273
|
+
interactive: true,
|
|
2274
|
+
onOutput: clearSpinner
|
|
2275
|
+
});
|
|
2065
2276
|
if (!pushResult.success) {
|
|
2066
2277
|
throw new Error(pushResult.error ?? "drizzle-kit push failed");
|
|
2067
2278
|
}
|
|
2068
2279
|
result.dbPush = "success";
|
|
2069
|
-
|
|
2280
|
+
if (spinnerVisible) {
|
|
2281
|
+
spinnerVisible = false;
|
|
2282
|
+
s.stop("Database schema synced");
|
|
2283
|
+
} else {
|
|
2284
|
+
p6.log.success("Database schema synced");
|
|
2285
|
+
}
|
|
2070
2286
|
} catch {
|
|
2071
2287
|
result.dbPush = "failed";
|
|
2072
|
-
|
|
2288
|
+
clearSpinner();
|
|
2289
|
+
p6.log.warn("Database push failed (run drizzle-kit push manually)");
|
|
2073
2290
|
}
|
|
2074
2291
|
}
|
|
2075
2292
|
} else {
|
|
2076
|
-
|
|
2293
|
+
p6.log.info(`Database: skipped (${options.skipMigrationMessage ?? "--skip-migration"})`);
|
|
2077
2294
|
}
|
|
2295
|
+
const formatSpinner = spinner2();
|
|
2296
|
+
formatSpinner.start("Formatting generated files");
|
|
2078
2297
|
if (hasPkgScript(cwd, "lint:fix")) {
|
|
2079
|
-
|
|
2080
|
-
const ok = runPmScript(pm, "lint:fix", cwd, BIOME_FORMAT_TIMEOUT_MS);
|
|
2298
|
+
const ok = await runPmScript(pm, "lint:fix", cwd, BIOME_FORMAT_TIMEOUT_MS);
|
|
2081
2299
|
result.lintFix = ok ? "success" : "failed";
|
|
2082
2300
|
if (ok) {
|
|
2083
|
-
|
|
2301
|
+
formatSpinner.stop("Code formatted");
|
|
2084
2302
|
} else {
|
|
2085
|
-
|
|
2303
|
+
formatSpinner.clear();
|
|
2304
|
+
p6.log.warn("Lint fix had issues (run lint:fix manually)");
|
|
2086
2305
|
}
|
|
2087
2306
|
} else {
|
|
2088
2307
|
try {
|
|
2089
|
-
if (!runBiomeCheckWrite(cwd)) {
|
|
2308
|
+
if (!await runBiomeCheckWrite(cwd)) {
|
|
2090
2309
|
throw new Error("Biome binary not found");
|
|
2091
2310
|
}
|
|
2092
2311
|
result.lintFix = "success";
|
|
2093
|
-
|
|
2312
|
+
formatSpinner.stop("Code formatted with Biome");
|
|
2094
2313
|
} catch {
|
|
2095
2314
|
result.lintFix = "failed";
|
|
2096
|
-
|
|
2315
|
+
formatSpinner.clear();
|
|
2316
|
+
p6.log.warn("Biome formatting had issues (run biome check --write manually)");
|
|
2097
2317
|
}
|
|
2098
2318
|
}
|
|
2099
2319
|
if (options.showNextSteps !== false) {
|
|
@@ -2110,7 +2330,7 @@ async function runPostGenerate(cwd, schemaName, options = {}) {
|
|
|
2110
2330
|
// adapters/next/integration-runtime.ts
|
|
2111
2331
|
import fs14 from "fs";
|
|
2112
2332
|
import path17 from "path";
|
|
2113
|
-
import * as
|
|
2333
|
+
import * as p7 from "@clack/prompts";
|
|
2114
2334
|
|
|
2115
2335
|
// core-engine/schema/schema-reader.ts
|
|
2116
2336
|
import fs9 from "fs";
|
|
@@ -2916,15 +3136,15 @@ function collectSchemaSlotLayoutErrors(schema, errors) {
|
|
|
2916
3136
|
}
|
|
2917
3137
|
collectSlotLayoutErrors(input.slot, "slot", errors);
|
|
2918
3138
|
}
|
|
2919
|
-
function collectSlotLayoutErrors(value,
|
|
3139
|
+
function collectSlotLayoutErrors(value, path62, errors) {
|
|
2920
3140
|
if (!isRecord(value)) {
|
|
2921
|
-
errors.push(`${
|
|
3141
|
+
errors.push(`${path62} must be an object with "main" and/or "sidebar" field groups.`);
|
|
2922
3142
|
return;
|
|
2923
3143
|
}
|
|
2924
3144
|
const validKeys = /* @__PURE__ */ new Set(["main", "sidebar"]);
|
|
2925
3145
|
for (const key of Object.keys(value)) {
|
|
2926
3146
|
if (!validKeys.has(key)) {
|
|
2927
|
-
errors.push(`${
|
|
3147
|
+
errors.push(`${path62} has unsupported key "${key}". Expected "main" or "sidebar".`);
|
|
2928
3148
|
}
|
|
2929
3149
|
}
|
|
2930
3150
|
const areas = [
|
|
@@ -2935,24 +3155,24 @@ function collectSlotLayoutErrors(value, path61, errors) {
|
|
|
2935
3155
|
for (const [name, area] of areas) {
|
|
2936
3156
|
if (area === void 0) continue;
|
|
2937
3157
|
hasArea = true;
|
|
2938
|
-
collectSlotAreaErrors(area, `${
|
|
3158
|
+
collectSlotAreaErrors(area, `${path62}.${name}`, errors);
|
|
2939
3159
|
}
|
|
2940
3160
|
if (!hasArea) {
|
|
2941
|
-
errors.push(`${
|
|
3161
|
+
errors.push(`${path62} must define at least one of "main" or "sidebar".`);
|
|
2942
3162
|
}
|
|
2943
3163
|
}
|
|
2944
|
-
function collectSlotAreaErrors(value,
|
|
3164
|
+
function collectSlotAreaErrors(value, path62, errors) {
|
|
2945
3165
|
if (!isRecord(value)) {
|
|
2946
|
-
errors.push(`${
|
|
3166
|
+
errors.push(`${path62} must be an object with a "fields" array.`);
|
|
2947
3167
|
return;
|
|
2948
3168
|
}
|
|
2949
3169
|
const fields = value.fields;
|
|
2950
3170
|
if (!Array.isArray(fields)) {
|
|
2951
|
-
errors.push(`${
|
|
3171
|
+
errors.push(`${path62}.fields must be an array.`);
|
|
2952
3172
|
return;
|
|
2953
3173
|
}
|
|
2954
3174
|
for (const field of fields) {
|
|
2955
|
-
walkSlot(field, `${
|
|
3175
|
+
walkSlot(field, `${path62}.fields.${field.name ?? "unnamed"}`, errors);
|
|
2956
3176
|
}
|
|
2957
3177
|
}
|
|
2958
3178
|
function collectInvalidHeightErrors(topLevelFields, rootPath, errors) {
|
|
@@ -3436,12 +3656,12 @@ async function resolveTextEnvValue(options) {
|
|
|
3436
3656
|
if (existingValue) {
|
|
3437
3657
|
return existingValue;
|
|
3438
3658
|
}
|
|
3439
|
-
const result = await
|
|
3659
|
+
const result = await p7.text({
|
|
3440
3660
|
message: options.message,
|
|
3441
3661
|
defaultValue: options.defaultValue,
|
|
3442
3662
|
validate: options.validate
|
|
3443
3663
|
});
|
|
3444
|
-
if (
|
|
3664
|
+
if (p7.isCancel(result)) {
|
|
3445
3665
|
throw new Error(options.cancelMessage);
|
|
3446
3666
|
}
|
|
3447
3667
|
options.overwriteEnvKeys.add(options.key);
|
|
@@ -3452,11 +3672,11 @@ async function resolvePasswordEnvValue(options) {
|
|
|
3452
3672
|
if (existingValue) {
|
|
3453
3673
|
return existingValue;
|
|
3454
3674
|
}
|
|
3455
|
-
const result = await
|
|
3675
|
+
const result = await p7.password({
|
|
3456
3676
|
message: options.message,
|
|
3457
3677
|
validate: options.validate
|
|
3458
3678
|
});
|
|
3459
|
-
if (
|
|
3679
|
+
if (p7.isCancel(result)) {
|
|
3460
3680
|
throw new Error(options.cancelMessage);
|
|
3461
3681
|
}
|
|
3462
3682
|
options.overwriteEnvKeys.add(options.key);
|
|
@@ -4788,9 +5008,9 @@ function getReadFieldType(field) {
|
|
|
4788
5008
|
}
|
|
4789
5009
|
return getFieldType(field, "output");
|
|
4790
5010
|
}
|
|
4791
|
-
function collectReadSelectFields(fields,
|
|
5011
|
+
function collectReadSelectFields(fields, path62 = []) {
|
|
4792
5012
|
const matches = fields.flatMap((field) => {
|
|
4793
|
-
const currentPath = [...
|
|
5013
|
+
const currentPath = [...path62, field.name];
|
|
4794
5014
|
const matches2 = field.type === "select" ? [{ field, path: currentPath }] : [];
|
|
4795
5015
|
if (field.fields) {
|
|
4796
5016
|
matches2.push(...collectReadSelectFields(field.fields, currentPath));
|
|
@@ -5837,14 +6057,14 @@ function buildStepsConstant(steps) {
|
|
|
5837
6057
|
${entries.join(",\n")}
|
|
5838
6058
|
]`;
|
|
5839
6059
|
}
|
|
5840
|
-
function buildComponentSource(
|
|
6060
|
+
function buildComponentSource(p32) {
|
|
5841
6061
|
const providerOpen = ` <NuqsAdapter>
|
|
5842
6062
|
<React.Suspense fallback={null}>
|
|
5843
|
-
<${
|
|
6063
|
+
<${p32.pascal}FormInner />
|
|
5844
6064
|
</React.Suspense>
|
|
5845
6065
|
</NuqsAdapter>`;
|
|
5846
6066
|
const exportWrapper = `
|
|
5847
|
-
export function ${
|
|
6067
|
+
export function ${p32.pascal}Form() {
|
|
5848
6068
|
return (
|
|
5849
6069
|
${providerOpen}
|
|
5850
6070
|
)
|
|
@@ -5853,22 +6073,22 @@ ${providerOpen}
|
|
|
5853
6073
|
return `'use client'
|
|
5854
6074
|
|
|
5855
6075
|
import { standardSchemaResolver } from '@hookform/resolvers/standard-schema'
|
|
5856
|
-
import { ChevronLeft, ChevronRight${
|
|
6076
|
+
import { ChevronLeft, ChevronRight${p32.hasListFields ? ", Trash2" : ""} } from 'lucide-react'
|
|
5857
6077
|
import { createParser, useQueryState } from 'nuqs'
|
|
5858
6078
|
import { NuqsAdapter } from 'nuqs/adapters/next/app'
|
|
5859
6079
|
import * as React from 'react'
|
|
5860
|
-
${
|
|
6080
|
+
${p32.rhfImport}
|
|
5861
6081
|
import { z } from 'zod/v3'
|
|
5862
|
-
import { create${
|
|
6082
|
+
import { create${p32.pascal}Submission } from '@admin/actions/${p32.actionImportPath}'
|
|
5863
6083
|
|
|
5864
6084
|
const formSchema = z.object({
|
|
5865
|
-
${
|
|
6085
|
+
${p32.zodFields}
|
|
5866
6086
|
})
|
|
5867
6087
|
|
|
5868
6088
|
type FormValues = z.infer<typeof formSchema>
|
|
5869
6089
|
${buildFieldErrorHelper()}
|
|
5870
6090
|
|
|
5871
|
-
${
|
|
6091
|
+
${p32.stepsConst}
|
|
5872
6092
|
|
|
5873
6093
|
const stepParser = createParser({
|
|
5874
6094
|
parse(value) {
|
|
@@ -5886,7 +6106,7 @@ const stepParser = createParser({
|
|
|
5886
6106
|
}
|
|
5887
6107
|
}).withDefault(0)
|
|
5888
6108
|
|
|
5889
|
-
function ${
|
|
6109
|
+
function ${p32.pascal}FormInner() {
|
|
5890
6110
|
const [currentStep, setCurrentStep] = useQueryState('step', stepParser)
|
|
5891
6111
|
const [submitted, setSubmitted] = React.useState(false)
|
|
5892
6112
|
const [submitting, startSubmitTransition] = React.useTransition()
|
|
@@ -5894,11 +6114,11 @@ function ${p31.pascal}FormInner() {
|
|
|
5894
6114
|
const form = useForm<FormValues>({
|
|
5895
6115
|
resolver: standardSchemaResolver(formSchema),
|
|
5896
6116
|
defaultValues: {
|
|
5897
|
-
${
|
|
6117
|
+
${p32.defaults}
|
|
5898
6118
|
},
|
|
5899
6119
|
})
|
|
5900
6120
|
|
|
5901
|
-
${
|
|
6121
|
+
${p32.fieldArraySetup}${p32.watchSetup}
|
|
5902
6122
|
async function handleNext() {
|
|
5903
6123
|
const stepFields = STEPS[currentStep].fields as (keyof FormValues)[]
|
|
5904
6124
|
const isValid = await form.trigger(stepFields, { shouldFocus: true })
|
|
@@ -5914,9 +6134,9 @@ ${p31.fieldArraySetup}${p31.watchSetup}
|
|
|
5914
6134
|
function onSubmit(values: FormValues) {
|
|
5915
6135
|
startSubmitTransition(async () => {
|
|
5916
6136
|
try {
|
|
5917
|
-
const result = await create${
|
|
6137
|
+
const result = await create${p32.pascal}Submission(values)
|
|
5918
6138
|
if (result.success) {
|
|
5919
|
-
${
|
|
6139
|
+
${p32.successHandler}
|
|
5920
6140
|
} else {
|
|
5921
6141
|
form.setError('root', { message: result.error || 'Something went wrong' })
|
|
5922
6142
|
}
|
|
@@ -5930,7 +6150,7 @@ ${p31.fieldArraySetup}${p31.watchSetup}
|
|
|
5930
6150
|
return (
|
|
5931
6151
|
<div className="rounded-sm border p-6 text-center">
|
|
5932
6152
|
<h3 className="text-lg font-semibold">Thank you!</h3>
|
|
5933
|
-
<p className="mt-2 text-muted-foreground">${
|
|
6153
|
+
<p className="mt-2 text-muted-foreground">${p32.successMessage}</p>
|
|
5934
6154
|
</div>
|
|
5935
6155
|
)
|
|
5936
6156
|
}
|
|
@@ -5947,7 +6167,7 @@ ${p31.fieldArraySetup}${p31.watchSetup}
|
|
|
5947
6167
|
|
|
5948
6168
|
{/* Step content */}
|
|
5949
6169
|
<div key={currentStep} className="animate-in fade-in duration-300 space-y-6">
|
|
5950
|
-
${
|
|
6170
|
+
${p32.stepContentBlocks}
|
|
5951
6171
|
</div>
|
|
5952
6172
|
|
|
5953
6173
|
{form.formState.errors.root && (
|
|
@@ -5981,7 +6201,7 @@ ${p31.stepContentBlocks}
|
|
|
5981
6201
|
onClick={() => form.handleSubmit(onSubmit)()}
|
|
5982
6202
|
className="inline-flex h-9 items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground shadow-xs transition-colors hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-50"
|
|
5983
6203
|
>
|
|
5984
|
-
{submitting ? 'Submitting...' : ${
|
|
6204
|
+
{submitting ? 'Submitting...' : ${p32.submitText}}
|
|
5985
6205
|
</button>
|
|
5986
6206
|
)}
|
|
5987
6207
|
</div>
|
|
@@ -13997,14 +14217,14 @@ function safeIdentifier(value, fallback) {
|
|
|
13997
14217
|
const base = pascal ? `${pascal.charAt(0).toLowerCase()}${pascal.slice(1)}` : fallback;
|
|
13998
14218
|
return /^[A-Za-z_$]/.test(base) ? base : fallback;
|
|
13999
14219
|
}
|
|
14000
|
-
function pathExpression(
|
|
14001
|
-
return `\`${
|
|
14220
|
+
function pathExpression(path62) {
|
|
14221
|
+
return `\`${path62.map((part) => typeof part === "string" ? part : `\${${part.expression}}`).join(".")}\``;
|
|
14002
14222
|
}
|
|
14003
|
-
function pathNameProp(
|
|
14004
|
-
if (
|
|
14005
|
-
return `"${
|
|
14223
|
+
function pathNameProp(path62) {
|
|
14224
|
+
if (path62.every((part) => typeof part === "string")) {
|
|
14225
|
+
return `"${path62.map((part) => part).join(".")}"`;
|
|
14006
14226
|
}
|
|
14007
|
-
return `{${pathExpression(
|
|
14227
|
+
return `{${pathExpression(path62)}}`;
|
|
14008
14228
|
}
|
|
14009
14229
|
function findTitlePath(fields) {
|
|
14010
14230
|
const stringTypes = ["string", "varchar", "text"];
|
|
@@ -14026,23 +14246,23 @@ function findTitlePath(fields) {
|
|
|
14026
14246
|
function requiredLeafPaths(fields, prefix = []) {
|
|
14027
14247
|
return fields.flatMap((field) => {
|
|
14028
14248
|
if (field.hidden) return [];
|
|
14029
|
-
const
|
|
14249
|
+
const path62 = [...prefix, field.name];
|
|
14030
14250
|
if ((field.type === "group" || field.type === "section") && field.fields?.length) {
|
|
14031
|
-
return requiredLeafPaths(field.fields,
|
|
14251
|
+
return requiredLeafPaths(field.fields, path62);
|
|
14032
14252
|
}
|
|
14033
|
-
if (field.required) return [
|
|
14253
|
+
if (field.required) return [path62.join(".")];
|
|
14034
14254
|
return [];
|
|
14035
14255
|
});
|
|
14036
14256
|
}
|
|
14037
14257
|
function validationTriggerExpression(basePath, requiredPaths) {
|
|
14038
14258
|
if (requiredPaths.length === 0) return `\`${basePath}.\${expandedIndex}\` as never`;
|
|
14039
|
-
const paths = requiredPaths.map((
|
|
14259
|
+
const paths = requiredPaths.map((path62) => `\`${basePath}.\${expandedIndex}.${path62}\``).join(", ");
|
|
14040
14260
|
return `[${paths}] as never`;
|
|
14041
14261
|
}
|
|
14042
|
-
function renderTextInputField(field, indent, label, nestedHint,
|
|
14262
|
+
function renderTextInputField(field, indent, label, nestedHint, path62) {
|
|
14043
14263
|
return `${indent}<FormField
|
|
14044
14264
|
${indent} control={form.control}
|
|
14045
|
-
${indent} name=${pathNameProp(
|
|
14265
|
+
${indent} name=${pathNameProp(path62)}
|
|
14046
14266
|
${indent} render={({ field: formField }) => (
|
|
14047
14267
|
${indent} <FormItem${formItemProps(field)}>
|
|
14048
14268
|
${indent} ${labelWithDescription(formLabel(field, label), nestedHint, `${indent} `)}
|
|
@@ -14054,11 +14274,11 @@ ${indent} </FormItem>
|
|
|
14054
14274
|
${indent} )}
|
|
14055
14275
|
${indent}/>`;
|
|
14056
14276
|
}
|
|
14057
|
-
function renderNestedField(field, indent,
|
|
14277
|
+
function renderNestedField(field, indent, path62, depth) {
|
|
14058
14278
|
const nestedLabel = field.label || field.name;
|
|
14059
14279
|
const nestedHint = field.hint ? `<FormDescription>${field.hint}</FormDescription>` : "";
|
|
14060
14280
|
if ((field.type === "group" || field.type === "section") && field.fields?.length) {
|
|
14061
|
-
const groupFields = field.fields.map((child) => renderNestedField(child, `${indent} `, [...
|
|
14281
|
+
const groupFields = field.fields.map((child) => renderNestedField(child, `${indent} `, [...path62, child.name], depth)).filter(Boolean).join("\n");
|
|
14062
14282
|
if (!groupFields) return "";
|
|
14063
14283
|
const heading = nestedLabel && nestedLabel !== field.name ? `${indent}<h3 className="text-base font-medium">${nestedLabel}</h3>
|
|
14064
14284
|
` : "";
|
|
@@ -14068,7 +14288,7 @@ ${groupFields}
|
|
|
14068
14288
|
${indent}</div>`;
|
|
14069
14289
|
}
|
|
14070
14290
|
if (field.type === "list" && field.fields?.length) {
|
|
14071
|
-
return renderNestedObjectListField(field, indent, nestedLabel,
|
|
14291
|
+
return renderNestedObjectListField(field, indent, nestedLabel, path62, depth);
|
|
14072
14292
|
}
|
|
14073
14293
|
if (field.type === "list") {
|
|
14074
14294
|
const hideLabelProp = field.label ? "" : `
|
|
@@ -14076,7 +14296,7 @@ ${indent} hideLabel`;
|
|
|
14076
14296
|
const descriptionProp = field.hint ? `
|
|
14077
14297
|
${indent} description={${JSON.stringify(field.hint)}}` : "";
|
|
14078
14298
|
return `${indent}<DynamicListField
|
|
14079
|
-
${indent} name={${pathExpression(
|
|
14299
|
+
${indent} name={${pathExpression(path62)}}
|
|
14080
14300
|
${indent} label="${nestedLabel}"${hideLabelProp}${descriptionProp}
|
|
14081
14301
|
${indent} disabled={isPending}${field.maxItems ? `
|
|
14082
14302
|
${indent} maxItems={${field.maxItems}}` : ""}
|
|
@@ -14086,7 +14306,7 @@ ${indent}/>`;
|
|
|
14086
14306
|
if (field.type === "boolean") {
|
|
14087
14307
|
return `${indent}<FormField
|
|
14088
14308
|
${indent} control={form.control}
|
|
14089
|
-
${indent} name=${pathNameProp(
|
|
14309
|
+
${indent} name=${pathNameProp(path62)}
|
|
14090
14310
|
${indent} render={({ field: formField }) => (
|
|
14091
14311
|
${indent} <FormItem${formItemProps(field, "flex flex-row items-start space-x-3 space-y-0")}>
|
|
14092
14312
|
${indent} <FormControl>
|
|
@@ -14101,7 +14321,7 @@ ${indent}/>`;
|
|
|
14101
14321
|
const acceptProp = field.type === "image" ? ' accept="image/*"' : field.type === "video" ? ' accept="video/*"' : "";
|
|
14102
14322
|
return `${indent}<FormField
|
|
14103
14323
|
${indent} control={form.control}
|
|
14104
|
-
${indent} name=${pathNameProp(
|
|
14324
|
+
${indent} name=${pathNameProp(path62)}
|
|
14105
14325
|
${indent} render={({ field: formField }) => (
|
|
14106
14326
|
${indent} <FormItem${formItemProps(field)}>
|
|
14107
14327
|
${indent} ${labelWithDescription(formLabel(field, nestedLabel), nestedHint, `${indent} `)}
|
|
@@ -14116,7 +14336,7 @@ ${indent}/>`;
|
|
|
14116
14336
|
if (field.type === "icon") {
|
|
14117
14337
|
return `${indent}<FormField
|
|
14118
14338
|
${indent} control={form.control}
|
|
14119
|
-
${indent} name=${pathNameProp(
|
|
14339
|
+
${indent} name=${pathNameProp(path62)}
|
|
14120
14340
|
${indent} render={({ field: formField }) => (
|
|
14121
14341
|
${indent} <FormItem${formItemProps(field)}>
|
|
14122
14342
|
${indent} ${labelWithDescription(formLabel(field, nestedLabel), nestedHint, `${indent} `)}
|
|
@@ -14133,7 +14353,7 @@ ${indent}/>`;
|
|
|
14133
14353
|
const emptyValue = field.required ? "undefined" : "null";
|
|
14134
14354
|
return `${indent}<FormField
|
|
14135
14355
|
${indent} control={form.control}
|
|
14136
|
-
${indent} name=${pathNameProp(
|
|
14356
|
+
${indent} name=${pathNameProp(path62)}
|
|
14137
14357
|
${indent} render={({ field: formField }) => (
|
|
14138
14358
|
${indent} <FormItem${formItemProps(field)}>
|
|
14139
14359
|
${indent} ${labelWithDescription(formLabel(field, nestedLabel), nestedHint, `${indent} `)}
|
|
@@ -14158,16 +14378,16 @@ ${indent} </FormItem>
|
|
|
14158
14378
|
${indent} )}
|
|
14159
14379
|
${indent}/>`;
|
|
14160
14380
|
}
|
|
14161
|
-
return renderTextInputField(field, indent, nestedLabel, nestedHint,
|
|
14381
|
+
return renderTextInputField(field, indent, nestedLabel, nestedHint, path62);
|
|
14162
14382
|
}
|
|
14163
|
-
function renderNestedObjectListField(field, indent, label,
|
|
14383
|
+
function renderNestedObjectListField(field, indent, label, path62, depth) {
|
|
14164
14384
|
const singularLabel = singularize(label);
|
|
14165
14385
|
const itemIndexVar = `${safeIdentifier(field.name, "nestedList")}Index${depth}`;
|
|
14166
14386
|
const titlePath = findTitlePath(field.fields ?? []);
|
|
14167
14387
|
const titlePathSuffix = titlePath ? `.${titlePath.join(".")}` : "";
|
|
14168
14388
|
const renderTitleProp = titlePath ? `
|
|
14169
14389
|
${indent} renderTitle={(${itemIndexVar}) =>
|
|
14170
|
-
${indent} String(form.watch(\`${
|
|
14390
|
+
${indent} String(form.watch(\`${path62.map((part) => typeof part === "string" ? part : `\${${part.expression}}`).join(
|
|
14171
14391
|
"."
|
|
14172
14392
|
)}.\${${itemIndexVar}}${titlePathSuffix}\` as never) || \`${singularLabel} \${${itemIndexVar} + 1}\`)
|
|
14173
14393
|
${indent} }` : "";
|
|
@@ -14175,7 +14395,7 @@ ${indent} }` : "";
|
|
|
14175
14395
|
(child) => renderNestedField(
|
|
14176
14396
|
child,
|
|
14177
14397
|
`${indent} `,
|
|
14178
|
-
[...
|
|
14398
|
+
[...path62, { expression: itemIndexVar }, child.name],
|
|
14179
14399
|
depth + 1
|
|
14180
14400
|
)
|
|
14181
14401
|
).filter(Boolean).join("\n");
|
|
@@ -14190,7 +14410,7 @@ ${indent} maxItems={${field.maxItems}}` : "";
|
|
|
14190
14410
|
const validatePathsProp = validatePaths.length > 0 ? `
|
|
14191
14411
|
${indent} validatePaths={${JSON.stringify(validatePaths)}}` : "";
|
|
14192
14412
|
return `${indent}<NestedObjectListField
|
|
14193
|
-
${indent} name={${pathExpression(
|
|
14413
|
+
${indent} name={${pathExpression(path62)}}
|
|
14194
14414
|
${indent} label={${JSON.stringify(label)}}
|
|
14195
14415
|
${indent} singularLabel={${JSON.stringify(singularLabel)}}
|
|
14196
14416
|
${indent} defaultValue={${defaultItem}}
|
|
@@ -17805,7 +18025,7 @@ function readPresetTemplate(presetId, relativePath) {
|
|
|
17805
18025
|
// adapters/next/snapshots/apply.ts
|
|
17806
18026
|
import fs20 from "fs";
|
|
17807
18027
|
import path24 from "path";
|
|
17808
|
-
import * as
|
|
18028
|
+
import * as p8 from "@clack/prompts";
|
|
17809
18029
|
|
|
17810
18030
|
// core-engine/snapshots/ast-substitution.ts
|
|
17811
18031
|
import { Node, Project } from "ts-morph";
|
|
@@ -17826,7 +18046,7 @@ function applyTextEdits(content, edits) {
|
|
|
17826
18046
|
content
|
|
17827
18047
|
);
|
|
17828
18048
|
}
|
|
17829
|
-
function collectPreviewChanges(
|
|
18049
|
+
function collectPreviewChanges(path62, beforeContent, afterContent) {
|
|
17830
18050
|
const beforeLines = beforeContent.split("\n");
|
|
17831
18051
|
const afterLines = afterContent.split("\n");
|
|
17832
18052
|
const maxLength = Math.max(beforeLines.length, afterLines.length);
|
|
@@ -17838,7 +18058,7 @@ function collectPreviewChanges(path61, beforeContent, afterContent) {
|
|
|
17838
18058
|
continue;
|
|
17839
18059
|
}
|
|
17840
18060
|
changes.push({
|
|
17841
|
-
path:
|
|
18061
|
+
path: path62,
|
|
17842
18062
|
line: index + 1,
|
|
17843
18063
|
before: before.trim(),
|
|
17844
18064
|
after: after.trim()
|
|
@@ -18167,7 +18387,7 @@ function hasConflictMarkers(content) {
|
|
|
18167
18387
|
}
|
|
18168
18388
|
|
|
18169
18389
|
// adapters/next/snapshots/format-for-merge.ts
|
|
18170
|
-
import { execFileSync as
|
|
18390
|
+
import { execFileSync as execFileSync2 } from "child_process";
|
|
18171
18391
|
import fs18 from "fs";
|
|
18172
18392
|
import path22 from "path";
|
|
18173
18393
|
var BIOME_FORMAT_TIMEOUT_MS2 = 15e3;
|
|
@@ -18217,7 +18437,7 @@ function formatContentForSnapshotMerge(cwd, filePath, content) {
|
|
|
18217
18437
|
const configPath = findBiomeConfig(cwd);
|
|
18218
18438
|
const targetPath = path22.join(cwd, ...filePath.split("/"));
|
|
18219
18439
|
try {
|
|
18220
|
-
return
|
|
18440
|
+
return execFileSync2(
|
|
18221
18441
|
biomeBin,
|
|
18222
18442
|
[
|
|
18223
18443
|
"check",
|
|
@@ -18468,11 +18688,11 @@ function buildMergeInput(cwd, baseFile, localContent, remoteFile) {
|
|
|
18468
18688
|
}
|
|
18469
18689
|
};
|
|
18470
18690
|
}
|
|
18471
|
-
function
|
|
18691
|
+
function isInteractiveSession2(interactive) {
|
|
18472
18692
|
return interactive && Boolean(process.stdin.isTTY) && process.env.CI !== "true";
|
|
18473
18693
|
}
|
|
18474
18694
|
async function promptNoBaseDecision(filePath) {
|
|
18475
|
-
const answer = await
|
|
18695
|
+
const answer = await p8.select({
|
|
18476
18696
|
message: `File already exists without snapshot base: ${filePath}`,
|
|
18477
18697
|
options: [
|
|
18478
18698
|
{ value: "backup", label: "Backup and overwrite", hint: "recommended" },
|
|
@@ -18481,7 +18701,7 @@ async function promptNoBaseDecision(filePath) {
|
|
|
18481
18701
|
],
|
|
18482
18702
|
initialValue: "backup"
|
|
18483
18703
|
});
|
|
18484
|
-
if (
|
|
18704
|
+
if (p8.isCancel(answer)) {
|
|
18485
18705
|
throw new Error("Generation cancelled.");
|
|
18486
18706
|
}
|
|
18487
18707
|
return answer;
|
|
@@ -18517,7 +18737,7 @@ async function applyGeneratedFiles({
|
|
|
18517
18737
|
const remoteFiles = sortGeneratedFiles(generatedFiles);
|
|
18518
18738
|
const remotePaths = new Set(remoteFiles.map((file) => file.path));
|
|
18519
18739
|
const skipped = new Set(force ? [] : manifest?.skipped ?? []);
|
|
18520
|
-
const interactiveSession =
|
|
18740
|
+
const interactiveSession = isInteractiveSession2(interactive);
|
|
18521
18741
|
const aliasMap = renamePlan ? buildRenamePlanAliasMap(renamePlan) : /* @__PURE__ */ new Map();
|
|
18522
18742
|
const consumedBasePaths = /* @__PURE__ */ new Set();
|
|
18523
18743
|
let baseFiles = /* @__PURE__ */ new Map();
|
|
@@ -19362,18 +19582,18 @@ async function runAddCommand(items, options) {
|
|
|
19362
19582
|
const presetIds = items.filter(isPresetId);
|
|
19363
19583
|
const integrationIds = items.filter(isIntegrationId);
|
|
19364
19584
|
if (!installIntegrationsMode && integrationIds.length > 0) {
|
|
19365
|
-
|
|
19585
|
+
p9.log.error(
|
|
19366
19586
|
`Integration IDs require --integration. Run \`betterstart add --integration ${integrationIds.join(" ")}\`.`
|
|
19367
19587
|
);
|
|
19368
19588
|
process.exit(1);
|
|
19369
19589
|
}
|
|
19370
19590
|
if (installIntegrationsMode && presetIds.length > 0) {
|
|
19371
|
-
|
|
19591
|
+
p9.log.error(`Preset IDs cannot be installed with --integration: ${presetIds.join(", ")}`);
|
|
19372
19592
|
process.exit(1);
|
|
19373
19593
|
}
|
|
19374
19594
|
const invalidItems = installIntegrationsMode ? items.filter((integrationId) => !isIntegrationId(integrationId)) : items.filter((presetId) => !isPresetId(presetId));
|
|
19375
19595
|
if (invalidItems.length > 0) {
|
|
19376
|
-
|
|
19596
|
+
p9.log.error(
|
|
19377
19597
|
installIntegrationsMode ? formatUnknownIntegrationMessage(invalidItems) : formatUnknownPresetMessage(invalidItems)
|
|
19378
19598
|
);
|
|
19379
19599
|
process.exit(1);
|
|
@@ -19384,7 +19604,7 @@ async function runAddCommand(items, options) {
|
|
|
19384
19604
|
const pm = detectPackageManager(cwd);
|
|
19385
19605
|
const cliSyncResult = await syncProjectCliDependency(cwd, pm);
|
|
19386
19606
|
if (cliSyncResult && !cliSyncResult.success) {
|
|
19387
|
-
|
|
19607
|
+
p9.log.error(cliSyncResult.error ?? "Failed to sync betterstart-cli");
|
|
19388
19608
|
process.exit(1);
|
|
19389
19609
|
}
|
|
19390
19610
|
if (installIntegrationsMode) {
|
|
@@ -19398,10 +19618,10 @@ async function runAddCommand(items, options) {
|
|
|
19398
19618
|
});
|
|
19399
19619
|
writeConfigFile(cwd, result2.config);
|
|
19400
19620
|
if (result2.warnings.length > 0) {
|
|
19401
|
-
|
|
19621
|
+
p9.note(result2.warnings.join("\n"), "Warnings");
|
|
19402
19622
|
}
|
|
19403
19623
|
if (result2.installed.length === 0 && result2.activated.length === 0 && result2.skipped.length > 0) {
|
|
19404
|
-
|
|
19624
|
+
p9.outro(`No changes made. Already installed: ${result2.skipped.join(", ")}`);
|
|
19405
19625
|
return;
|
|
19406
19626
|
}
|
|
19407
19627
|
const conflictPaths2 = scanConflictPaths(cwd);
|
|
@@ -19423,12 +19643,12 @@ async function runAddCommand(items, options) {
|
|
|
19423
19643
|
result2.installed.length > 0 ? `Installed integration${result2.installed.length === 1 ? "" : "s"}: ${result2.installed.join(", ")}` : null,
|
|
19424
19644
|
result2.activated.length > 0 ? `Activated integration${result2.activated.length === 1 ? "" : "s"}: ${result2.activated.join(", ")}` : null
|
|
19425
19645
|
].filter(Boolean);
|
|
19426
|
-
|
|
19646
|
+
p9.outro(messages.join("\n"));
|
|
19427
19647
|
return;
|
|
19428
19648
|
}
|
|
19429
19649
|
const invalidPresets = items.filter((presetId) => !isPresetId(presetId));
|
|
19430
19650
|
if (invalidPresets.length > 0) {
|
|
19431
|
-
|
|
19651
|
+
p9.log.error(formatUnknownPresetMessage(invalidPresets));
|
|
19432
19652
|
process.exit(1);
|
|
19433
19653
|
}
|
|
19434
19654
|
const result = await installPresets({
|
|
@@ -19441,11 +19661,11 @@ async function runAddCommand(items, options) {
|
|
|
19441
19661
|
});
|
|
19442
19662
|
writeConfigFile(cwd, result.config);
|
|
19443
19663
|
if (result.installed.length === 0 && result.skipped.length > 0) {
|
|
19444
|
-
|
|
19664
|
+
p9.outro(`No changes made. Already installed: ${result.skipped.join(", ")}`);
|
|
19445
19665
|
return;
|
|
19446
19666
|
}
|
|
19447
19667
|
if (result.warnings.length > 0) {
|
|
19448
|
-
|
|
19668
|
+
p9.note(result.warnings.join("\n"), "Warnings");
|
|
19449
19669
|
}
|
|
19450
19670
|
const installedSchemaNames = result.installed.flatMap(
|
|
19451
19671
|
(presetId) => getPresetDefinition(presetId).schemaFiles.map((schemaFile) => schemaFile.replace(/\.json$/, ""))
|
|
@@ -19462,14 +19682,14 @@ async function runAddCommand(items, options) {
|
|
|
19462
19682
|
if (conflictPaths.length === 0) {
|
|
19463
19683
|
printAddNextSteps("preset", hasSchemaChanges, postGenerateResult, adminRoutePath);
|
|
19464
19684
|
}
|
|
19465
|
-
|
|
19685
|
+
p9.outro(
|
|
19466
19686
|
`Installed preset${result.installed.length === 1 ? "" : "s"}: ${result.installed.join(", ")}`
|
|
19467
19687
|
);
|
|
19468
19688
|
}
|
|
19469
19689
|
|
|
19470
19690
|
// adapters/next/commands/add-field.ts
|
|
19471
19691
|
import path30 from "path";
|
|
19472
|
-
import * as
|
|
19692
|
+
import * as p12 from "@clack/prompts";
|
|
19473
19693
|
|
|
19474
19694
|
// core-engine/schema/add-field.ts
|
|
19475
19695
|
import fs23 from "fs";
|
|
@@ -20121,7 +20341,7 @@ function getTabFields(tab) {
|
|
|
20121
20341
|
// adapters/next/commands/generate.ts
|
|
20122
20342
|
import fs24 from "fs";
|
|
20123
20343
|
import path29 from "path";
|
|
20124
|
-
import * as
|
|
20344
|
+
import * as p10 from "@clack/prompts";
|
|
20125
20345
|
|
|
20126
20346
|
// core-engine/snapshots/rename-detector.ts
|
|
20127
20347
|
function levenshtein(a, b) {
|
|
@@ -20213,90 +20433,8 @@ function diffSchemas(before, after) {
|
|
|
20213
20433
|
};
|
|
20214
20434
|
}
|
|
20215
20435
|
|
|
20216
|
-
// core-engine/utils/spinner.ts
|
|
20217
|
-
import { stripVTControlCharacters } from "util";
|
|
20218
|
-
import * as p8 from "@clack/prompts";
|
|
20219
|
-
var RENDER_OVERHEAD = 7;
|
|
20220
|
-
var MIN_MESSAGE_WIDTH = 8;
|
|
20221
|
-
function fitSpinnerMessage(message) {
|
|
20222
|
-
const normalized = message.replace(/\t/g, " ");
|
|
20223
|
-
const columns = process.stdout.columns ?? 80;
|
|
20224
|
-
const max = Math.max(columns - RENDER_OVERHEAD, MIN_MESSAGE_WIDTH);
|
|
20225
|
-
const visible = stripVTControlCharacters(normalized);
|
|
20226
|
-
if (visible.length <= max) return normalized;
|
|
20227
|
-
return `${visible.slice(0, max - 1)}\u2026`;
|
|
20228
|
-
}
|
|
20229
|
-
var CLACK_LINE_ROWS = 2;
|
|
20230
|
-
var LOG_PREFIX_WIDTH = 3;
|
|
20231
|
-
function clackPromptRows(message, value) {
|
|
20232
|
-
const columns = process.stdout.columns ?? 80;
|
|
20233
|
-
const rows = (text7) => Math.max(1, Math.ceil((stripVTControlCharacters(text7).length + LOG_PREFIX_WIDTH) / columns));
|
|
20234
|
-
return 1 + rows(message) + rows(value);
|
|
20235
|
-
}
|
|
20236
|
-
function clackLogRows(message) {
|
|
20237
|
-
const columns = process.stdout.columns ?? 80;
|
|
20238
|
-
const width = stripVTControlCharacters(message).length + LOG_PREFIX_WIDTH;
|
|
20239
|
-
return 1 + Math.max(1, Math.ceil(width / columns));
|
|
20240
|
-
}
|
|
20241
|
-
function eraseRows(rows) {
|
|
20242
|
-
if (rows <= 0 || !process.stdout.isTTY || process.env.CI === "true") return;
|
|
20243
|
-
process.stdout.write(`\x1B[${rows}A\x1B[${rows}M`);
|
|
20244
|
-
}
|
|
20245
|
-
function eraseRowsAbove(rows, rowsBelow) {
|
|
20246
|
-
if (rows <= 0 || rowsBelow < 0 || !process.stdout.isTTY || process.env.CI === "true") {
|
|
20247
|
-
return;
|
|
20248
|
-
}
|
|
20249
|
-
const up = rows + rowsBelow;
|
|
20250
|
-
const restore = rowsBelow > 0 ? `\x1B[${rowsBelow}B` : "";
|
|
20251
|
-
process.stdout.write(`\x1B[${up}A\x1B[${rows}M${restore}`);
|
|
20252
|
-
}
|
|
20253
|
-
function eraseClackLine(options = {}) {
|
|
20254
|
-
if (!process.stdout.isTTY || process.env.CI === "true") return;
|
|
20255
|
-
const below = (options.linesBelow ?? 0) * CLACK_LINE_ROWS;
|
|
20256
|
-
const up = below + CLACK_LINE_ROWS;
|
|
20257
|
-
const restore = below > 0 ? `\x1B[${below}B` : "";
|
|
20258
|
-
process.stdout.write(`\x1B[${up}A\x1B[${CLACK_LINE_ROWS}M${restore}`);
|
|
20259
|
-
}
|
|
20260
|
-
var activeSpinners = 0;
|
|
20261
|
-
function hasActiveSpinner() {
|
|
20262
|
-
return activeSpinners > 0;
|
|
20263
|
-
}
|
|
20264
|
-
function spinner2(options) {
|
|
20265
|
-
const inner = p8.spinner({ ...options, cancelMessage: "Setup cancelled." });
|
|
20266
|
-
const guided = options?.withGuide !== false;
|
|
20267
|
-
let started = false;
|
|
20268
|
-
const setStarted = (next) => {
|
|
20269
|
-
if (started === next) return;
|
|
20270
|
-
started = next;
|
|
20271
|
-
activeSpinners += next ? 1 : -1;
|
|
20272
|
-
};
|
|
20273
|
-
return {
|
|
20274
|
-
start: (message = "") => {
|
|
20275
|
-
if (started) {
|
|
20276
|
-
inner.message(fitSpinnerMessage(message));
|
|
20277
|
-
return;
|
|
20278
|
-
}
|
|
20279
|
-
setStarted(true);
|
|
20280
|
-
inner.start(fitSpinnerMessage(message));
|
|
20281
|
-
},
|
|
20282
|
-
message: (message = "") => inner.message(fitSpinnerMessage(message)),
|
|
20283
|
-
stop: (message = "") => {
|
|
20284
|
-
setStarted(false);
|
|
20285
|
-
inner.stop(message);
|
|
20286
|
-
},
|
|
20287
|
-
clear: () => {
|
|
20288
|
-
if (!started) return;
|
|
20289
|
-
setStarted(false);
|
|
20290
|
-
inner.clear();
|
|
20291
|
-
if (guided && process.stdout.isTTY && process.env.CI !== "true") {
|
|
20292
|
-
process.stdout.write("\x1B[1A\x1B[2K");
|
|
20293
|
-
}
|
|
20294
|
-
}
|
|
20295
|
-
};
|
|
20296
|
-
}
|
|
20297
|
-
|
|
20298
20436
|
// adapters/next/commands/generate.ts
|
|
20299
|
-
function
|
|
20437
|
+
function isInteractiveSession3() {
|
|
20300
20438
|
return Boolean(process.stdin.isTTY) && process.env.CI !== "true";
|
|
20301
20439
|
}
|
|
20302
20440
|
function isStoredSchemaJson(schemaJson) {
|
|
@@ -20381,7 +20519,7 @@ function assertSnapshotStateOrExit(cwd) {
|
|
|
20381
20519
|
if (snapshotRootExists(cwd)) {
|
|
20382
20520
|
return;
|
|
20383
20521
|
}
|
|
20384
|
-
|
|
20522
|
+
p10.log.error(UNSUPPORTED_PROJECT_STATE_MESSAGE);
|
|
20385
20523
|
process.exit(1);
|
|
20386
20524
|
}
|
|
20387
20525
|
function printSchemaDiff(scope, loaded, cwd) {
|
|
@@ -20416,14 +20554,14 @@ function printSchemaDiff(scope, loaded, cwd) {
|
|
|
20416
20554
|
` custom cells: +[${diff.customComponents.added.join(", ")}] -[${diff.customComponents.removed.join(", ")}]`
|
|
20417
20555
|
);
|
|
20418
20556
|
}
|
|
20419
|
-
|
|
20557
|
+
p10.log.message(lines.join("\n"));
|
|
20420
20558
|
}
|
|
20421
20559
|
async function promptConfirm(message) {
|
|
20422
|
-
const result = await
|
|
20560
|
+
const result = await p10.confirm({
|
|
20423
20561
|
message,
|
|
20424
20562
|
initialValue: true
|
|
20425
20563
|
});
|
|
20426
|
-
if (
|
|
20564
|
+
if (p10.isCancel(result)) {
|
|
20427
20565
|
throw new Error("Generation cancelled.");
|
|
20428
20566
|
}
|
|
20429
20567
|
return Boolean(result);
|
|
@@ -20553,7 +20691,7 @@ async function maybeBuildRenamePlan(loaded, cwd, config, generatedFiles, options
|
|
|
20553
20691
|
};
|
|
20554
20692
|
if (finalPlan.fields.length === 0 && finalPlan.customCells.length === 0) {
|
|
20555
20693
|
if (validatedCustomCells.warnings.length > 0) {
|
|
20556
|
-
|
|
20694
|
+
p10.log.warn(validatedCustomCells.warnings.join("\n"));
|
|
20557
20695
|
}
|
|
20558
20696
|
return void 0;
|
|
20559
20697
|
}
|
|
@@ -20571,10 +20709,10 @@ async function maybeBuildRenamePlan(loaded, cwd, config, generatedFiles, options
|
|
|
20571
20709
|
if (preview.previewLines.length > previewLines.length) {
|
|
20572
20710
|
renameLines.push(` ... ${preview.previewLines.length - previewLines.length} more change(s)`);
|
|
20573
20711
|
}
|
|
20574
|
-
|
|
20712
|
+
p10.log.message(renameLines.join("\n"));
|
|
20575
20713
|
const warnings = [...validatedCustomCells.warnings, ...preview.warnings];
|
|
20576
20714
|
if (warnings.length > 0) {
|
|
20577
|
-
|
|
20715
|
+
p10.log.warn(warnings.join("\n"));
|
|
20578
20716
|
}
|
|
20579
20717
|
const confirmed = await promptConfirm("Apply these rename substitutions before merge?");
|
|
20580
20718
|
return confirmed ? finalPlan : void 0;
|
|
@@ -20685,16 +20823,16 @@ function printApplySummary(schemaName, summary) {
|
|
|
20685
20823
|
if (summary.skippedCleared.length > 0) {
|
|
20686
20824
|
lines.push(` skip entries cleared: ${summary.skippedCleared.join(", ")}`);
|
|
20687
20825
|
}
|
|
20688
|
-
|
|
20826
|
+
p10.log.message(lines.join("\n"));
|
|
20689
20827
|
}
|
|
20690
20828
|
async function runGenerateCommand(schemaName, options) {
|
|
20691
20829
|
const cwd = options.cwd ? path29.resolve(options.cwd) : process.cwd();
|
|
20692
|
-
const interactive = options.all ? options.interactive &&
|
|
20830
|
+
const interactive = options.all ? options.interactive && isInteractiveSession3() : isInteractiveSession3();
|
|
20693
20831
|
let config;
|
|
20694
20832
|
try {
|
|
20695
20833
|
config = await resolveConfig(cwd);
|
|
20696
20834
|
} catch (error) {
|
|
20697
|
-
|
|
20835
|
+
p10.log.error(`Error loading config: ${error instanceof Error ? error.message : String(error)}`);
|
|
20698
20836
|
process.exit(1);
|
|
20699
20837
|
}
|
|
20700
20838
|
assertSnapshotStateOrExit(cwd);
|
|
@@ -20704,7 +20842,7 @@ async function runGenerateCommand(schemaName, options) {
|
|
|
20704
20842
|
if (options.all) {
|
|
20705
20843
|
const schemaNames = listSchemaNames(schemasDir);
|
|
20706
20844
|
if (schemaNames.length === 0) {
|
|
20707
|
-
|
|
20845
|
+
p10.log.error(`No schemas found in ${schemasDir}`);
|
|
20708
20846
|
process.exit(1);
|
|
20709
20847
|
}
|
|
20710
20848
|
const failed = [];
|
|
@@ -20712,14 +20850,14 @@ async function runGenerateCommand(schemaName, options) {
|
|
|
20712
20850
|
const processedRoutes = [];
|
|
20713
20851
|
let markdownDepsChecked = false;
|
|
20714
20852
|
const adminRoutePath2 = resolveAdminNamespace(config.frameworkConfig.next.namespace).routePath;
|
|
20715
|
-
|
|
20853
|
+
p10.intro(`BetterStart Generator \u2014 regenerating ${schemaNames.length} schema(s)`);
|
|
20716
20854
|
for (const name of schemaNames) {
|
|
20717
20855
|
if (hasTombstone(cwd, name)) {
|
|
20718
20856
|
if (loadManifest(cwd, name)) {
|
|
20719
20857
|
clearTombstone(cwd, name);
|
|
20720
|
-
|
|
20858
|
+
p10.log.warn(`${name}: tombstone cleared (manifest present)`);
|
|
20721
20859
|
} else {
|
|
20722
|
-
|
|
20860
|
+
p10.log.message(`${name}: skipped (tombstoned)`);
|
|
20723
20861
|
continue;
|
|
20724
20862
|
}
|
|
20725
20863
|
}
|
|
@@ -20745,7 +20883,7 @@ async function runGenerateCommand(schemaName, options) {
|
|
|
20745
20883
|
processed.push(name);
|
|
20746
20884
|
processedRoutes.push(getGeneratedSchemaRoutePath(loaded2, adminRoutePath2));
|
|
20747
20885
|
} catch (error) {
|
|
20748
|
-
|
|
20886
|
+
p10.log.error(`${name}: ${error instanceof Error ? error.message : String(error)}`);
|
|
20749
20887
|
failed.push(name);
|
|
20750
20888
|
}
|
|
20751
20889
|
}
|
|
@@ -20768,14 +20906,14 @@ async function runGenerateCommand(schemaName, options) {
|
|
|
20768
20906
|
});
|
|
20769
20907
|
}
|
|
20770
20908
|
if (failed.length > 0) {
|
|
20771
|
-
|
|
20909
|
+
p10.log.error(`Failed: ${failed.join(", ")}`);
|
|
20772
20910
|
process.exit(1);
|
|
20773
20911
|
}
|
|
20774
|
-
|
|
20912
|
+
p10.outro(`Regenerated ${processed.length}/${schemaNames.length} schema(s)`);
|
|
20775
20913
|
return;
|
|
20776
20914
|
}
|
|
20777
20915
|
if (!schemaName) {
|
|
20778
|
-
|
|
20916
|
+
p10.log.error("Error: schema name is required (or use --all)");
|
|
20779
20917
|
process.exit(1);
|
|
20780
20918
|
}
|
|
20781
20919
|
let loaded;
|
|
@@ -20783,20 +20921,20 @@ async function runGenerateCommand(schemaName, options) {
|
|
|
20783
20921
|
loaded = loadSchema(schemasDir, schemaName);
|
|
20784
20922
|
} catch (error) {
|
|
20785
20923
|
if (error instanceof SchemaNotFoundError) {
|
|
20786
|
-
|
|
20924
|
+
p10.log.error(error.message);
|
|
20787
20925
|
} else {
|
|
20788
|
-
|
|
20926
|
+
p10.log.error(`Error loading schema: ${error instanceof Error ? error.message : String(error)}`);
|
|
20789
20927
|
}
|
|
20790
20928
|
process.exit(1);
|
|
20791
20929
|
}
|
|
20792
20930
|
const validationErrors = validateLoadedSchema(loaded);
|
|
20793
20931
|
if (validationErrors.length > 0) {
|
|
20794
|
-
|
|
20932
|
+
p10.log.error(
|
|
20795
20933
|
["Schema validation failed:", ...validationErrors.map((error) => ` - ${error}`)].join("\n")
|
|
20796
20934
|
);
|
|
20797
20935
|
process.exit(1);
|
|
20798
20936
|
}
|
|
20799
|
-
|
|
20937
|
+
p10.intro(`BetterStart Generator \u2014 ${loaded.schema.name}`);
|
|
20800
20938
|
const needsMarkdownRenderer = schemaNeedsMarkdownRenderer(loaded);
|
|
20801
20939
|
await ensureMarkdownRendererDependencies(cwd, needsMarkdownRenderer);
|
|
20802
20940
|
const result = await applySchemaGeneration(loaded, cwd, config, {
|
|
@@ -20821,38 +20959,38 @@ async function runGenerateCommand(schemaName, options) {
|
|
|
20821
20959
|
adminRoutePath,
|
|
20822
20960
|
schemaRoutePath: getGeneratedSchemaRoutePath(loaded, adminRoutePath)
|
|
20823
20961
|
});
|
|
20824
|
-
|
|
20962
|
+
p10.outro(`Generated ${loaded.schema.name}`);
|
|
20825
20963
|
}
|
|
20826
20964
|
|
|
20827
20965
|
// adapters/next/commands/schema-prompts.ts
|
|
20828
|
-
import * as
|
|
20829
|
-
function
|
|
20966
|
+
import * as p11 from "@clack/prompts";
|
|
20967
|
+
function isInteractiveSession4() {
|
|
20830
20968
|
return Boolean(process.stdin.isTTY) && process.env.CI !== "true";
|
|
20831
20969
|
}
|
|
20832
20970
|
function fail(message) {
|
|
20833
|
-
|
|
20971
|
+
p11.log.error(message);
|
|
20834
20972
|
process.exit(1);
|
|
20835
20973
|
}
|
|
20836
|
-
function
|
|
20837
|
-
|
|
20974
|
+
function cancel3(context) {
|
|
20975
|
+
p11.cancel(context.cancelMessage);
|
|
20838
20976
|
process.exit(0);
|
|
20839
20977
|
}
|
|
20840
20978
|
function cancelIfNeeded(context, value) {
|
|
20841
|
-
if (
|
|
20842
|
-
|
|
20979
|
+
if (p11.isCancel(value)) {
|
|
20980
|
+
cancel3(context);
|
|
20843
20981
|
}
|
|
20844
20982
|
return value;
|
|
20845
20983
|
}
|
|
20846
20984
|
async function promptConfirm2(context, message, initialValue = true) {
|
|
20847
|
-
const confirmed = await
|
|
20848
|
-
if (
|
|
20849
|
-
|
|
20985
|
+
const confirmed = await p11.confirm({ message, initialValue });
|
|
20986
|
+
if (p11.isCancel(confirmed)) {
|
|
20987
|
+
cancel3(context);
|
|
20850
20988
|
}
|
|
20851
20989
|
return Boolean(confirmed);
|
|
20852
20990
|
}
|
|
20853
20991
|
async function promptText(context, message, optionsOrDefaultValue) {
|
|
20854
20992
|
const options = typeof optionsOrDefaultValue === "string" ? { defaultValue: optionsOrDefaultValue } : optionsOrDefaultValue ?? {};
|
|
20855
|
-
const value = await
|
|
20993
|
+
const value = await p11.text({
|
|
20856
20994
|
message,
|
|
20857
20995
|
defaultValue: options.defaultValue,
|
|
20858
20996
|
placeholder: options.placeholder,
|
|
@@ -20869,7 +21007,7 @@ async function promptText(context, message, optionsOrDefaultValue) {
|
|
|
20869
21007
|
return String(cancelIfNeeded(context, value)).trim();
|
|
20870
21008
|
}
|
|
20871
21009
|
async function promptOptionalText(context, message) {
|
|
20872
|
-
const value = await
|
|
21010
|
+
const value = await p11.text({
|
|
20873
21011
|
message,
|
|
20874
21012
|
placeholder: "Leave blank to skip"
|
|
20875
21013
|
});
|
|
@@ -20877,7 +21015,7 @@ async function promptOptionalText(context, message) {
|
|
|
20877
21015
|
return result || void 0;
|
|
20878
21016
|
}
|
|
20879
21017
|
async function promptSelectValue(context, message, options, initialValue) {
|
|
20880
|
-
const value = await
|
|
21018
|
+
const value = await p11.select({
|
|
20881
21019
|
message,
|
|
20882
21020
|
options,
|
|
20883
21021
|
initialValue
|
|
@@ -21096,7 +21234,7 @@ async function shouldPromptRequired(type) {
|
|
|
21096
21234
|
return !["group", "section", "tabs", "separator"].includes(type);
|
|
21097
21235
|
}
|
|
21098
21236
|
async function promptFormFileOptions(context) {
|
|
21099
|
-
const selected = await
|
|
21237
|
+
const selected = await p11.multiselect({
|
|
21100
21238
|
message: "Field options",
|
|
21101
21239
|
options: [
|
|
21102
21240
|
{ value: "required", label: "Required field?" },
|
|
@@ -21135,7 +21273,7 @@ async function promptFieldOptions(context, kind, type, creatable) {
|
|
|
21135
21273
|
try {
|
|
21136
21274
|
return parseInteractiveOptionsList(value);
|
|
21137
21275
|
} catch (error) {
|
|
21138
|
-
|
|
21276
|
+
p11.log.error(error instanceof Error ? error.message : String(error));
|
|
21139
21277
|
}
|
|
21140
21278
|
}
|
|
21141
21279
|
}
|
|
@@ -21253,7 +21391,7 @@ async function promptChildFields(context, kind, schemasDir, scope, fields, depth
|
|
|
21253
21391
|
const addChild = fields.length === 0 ? await promptConfirm2(context, "Add a child field?", true) : await promptConfirm2(context, "Add another child field?", false);
|
|
21254
21392
|
if (!addChild) {
|
|
21255
21393
|
if (fields.length === 0) {
|
|
21256
|
-
|
|
21394
|
+
p11.log.warn("Containers need at least one child field.");
|
|
21257
21395
|
continue;
|
|
21258
21396
|
}
|
|
21259
21397
|
return;
|
|
@@ -21278,7 +21416,7 @@ async function promptTabsField(context, kind, schemasDir, scope, name, label, de
|
|
|
21278
21416
|
const addTab = field.tabs.length === 0 ? await promptConfirm2(context, "Add a tab?", true) : await promptConfirm2(context, "Add another tab?", false);
|
|
21279
21417
|
if (!addTab) {
|
|
21280
21418
|
if (field.tabs.length === 0) {
|
|
21281
|
-
|
|
21419
|
+
p11.log.warn("Tabs need at least one tab.");
|
|
21282
21420
|
continue;
|
|
21283
21421
|
}
|
|
21284
21422
|
return field;
|
|
@@ -21303,7 +21441,7 @@ async function promptTabsField(context, kind, schemasDir, scope, name, label, de
|
|
|
21303
21441
|
const addChild = mainFields.length + sidebarFields.length === 0 ? await promptConfirm2(context, "Add a tab child field?", true) : await promptConfirm2(context, "Add another tab child field?", false);
|
|
21304
21442
|
if (!addChild) {
|
|
21305
21443
|
if (mainFields.length + sidebarFields.length === 0) {
|
|
21306
|
-
|
|
21444
|
+
p11.log.warn("Tabs need at least one child field.");
|
|
21307
21445
|
continue;
|
|
21308
21446
|
}
|
|
21309
21447
|
break;
|
|
@@ -21374,7 +21512,7 @@ async function applyAdvancedOptions(context, field, kind, type, options) {
|
|
|
21374
21512
|
if (Number.isInteger(parsed) && parsed > 0) {
|
|
21375
21513
|
record.length = parsed;
|
|
21376
21514
|
} else {
|
|
21377
|
-
|
|
21515
|
+
p11.log.warn("Skipped invalid length.");
|
|
21378
21516
|
}
|
|
21379
21517
|
}
|
|
21380
21518
|
}
|
|
@@ -21532,11 +21670,11 @@ function hasNonInteractiveFieldOptions(options) {
|
|
|
21532
21670
|
);
|
|
21533
21671
|
}
|
|
21534
21672
|
function fail2(message) {
|
|
21535
|
-
|
|
21673
|
+
p12.log.error(message);
|
|
21536
21674
|
process.exit(1);
|
|
21537
21675
|
}
|
|
21538
|
-
function
|
|
21539
|
-
|
|
21676
|
+
function cancel5(message = "Add field cancelled.") {
|
|
21677
|
+
p12.cancel(message);
|
|
21540
21678
|
process.exit(0);
|
|
21541
21679
|
}
|
|
21542
21680
|
function schemaNameFromLoaded(loaded) {
|
|
@@ -21641,7 +21779,7 @@ function printPreview(loaded, owner, firstTimeGeneration, insertion, options) {
|
|
|
21641
21779
|
} else {
|
|
21642
21780
|
lines.push("schema integration: none");
|
|
21643
21781
|
}
|
|
21644
|
-
|
|
21782
|
+
p12.note(
|
|
21645
21783
|
`${lines.join("\n")}
|
|
21646
21784
|
|
|
21647
21785
|
${stringifyProjectJson(insertion.field).trim()}`,
|
|
@@ -21674,10 +21812,10 @@ Re-run with --yes to confirm these warning cases.`);
|
|
|
21674
21812
|
}
|
|
21675
21813
|
return;
|
|
21676
21814
|
}
|
|
21677
|
-
|
|
21815
|
+
p12.note(warnings.join("\n"), "Warnings");
|
|
21678
21816
|
const confirmed = await promptConfirm3("Continue with these warnings?", true);
|
|
21679
21817
|
if (!confirmed) {
|
|
21680
|
-
|
|
21818
|
+
cancel5();
|
|
21681
21819
|
}
|
|
21682
21820
|
}
|
|
21683
21821
|
function collectRelationshipTargetWarnings(cwd, owner, field) {
|
|
@@ -21719,7 +21857,7 @@ async function resolveSchemaNameInteractively(schemasDir, schemaName) {
|
|
|
21719
21857
|
if (schemaName) {
|
|
21720
21858
|
return schemaName;
|
|
21721
21859
|
}
|
|
21722
|
-
if (!
|
|
21860
|
+
if (!isInteractiveSession4()) {
|
|
21723
21861
|
fail2("Schema name is required in non-interactive sessions.");
|
|
21724
21862
|
}
|
|
21725
21863
|
const schemaNames = listSchemaNames(schemasDir);
|
|
@@ -21747,7 +21885,7 @@ async function runAddFieldCommand(schemaName, options) {
|
|
|
21747
21885
|
} catch (error) {
|
|
21748
21886
|
fail2(error instanceof Error ? error.message : String(error));
|
|
21749
21887
|
}
|
|
21750
|
-
if (!nonInteractive && !
|
|
21888
|
+
if (!nonInteractive && !isInteractiveSession4()) {
|
|
21751
21889
|
fail2("Interactive add-field requires a TTY. Provide --type, --field, and --label instead.");
|
|
21752
21890
|
}
|
|
21753
21891
|
const owner = resolveSchemaOwner(cwd, schemaNameFromLoaded(loaded));
|
|
@@ -21787,11 +21925,11 @@ ${validationErrors.map((error) => ` - ${error}`).join("\n")}`
|
|
|
21787
21925
|
if (!nonInteractive && !options.yes) {
|
|
21788
21926
|
const confirmed = await promptConfirm3("Write schema JSON and regenerate this schema?", true);
|
|
21789
21927
|
if (!confirmed) {
|
|
21790
|
-
|
|
21928
|
+
cancel5();
|
|
21791
21929
|
}
|
|
21792
21930
|
}
|
|
21793
21931
|
writeAuthoredGeneratedSchema(loaded);
|
|
21794
|
-
|
|
21932
|
+
p12.log.success(`Updated ${path30.relative(cwd, loaded.filePath)}`);
|
|
21795
21933
|
try {
|
|
21796
21934
|
await runGenerateCommand(selectedSchemaName, {
|
|
21797
21935
|
force: false,
|
|
@@ -21802,8 +21940,8 @@ ${validationErrors.map((error) => ` - ${error}`).join("\n")}`
|
|
|
21802
21940
|
cwd
|
|
21803
21941
|
});
|
|
21804
21942
|
} catch (error) {
|
|
21805
|
-
|
|
21806
|
-
|
|
21943
|
+
p12.log.error(error instanceof Error ? error.message : String(error));
|
|
21944
|
+
p12.log.info(
|
|
21807
21945
|
`Schema JSON was kept. Re-run \`betterstart generate ${selectedSchemaName}${options.skipMigration ? " --skip-migration" : ""}\` after resolving the issue.`
|
|
21808
21946
|
);
|
|
21809
21947
|
process.exit(1);
|
|
@@ -21813,7 +21951,7 @@ ${validationErrors.map((error) => ` - ${error}`).join("\n")}`
|
|
|
21813
21951
|
// adapters/next/commands/create.ts
|
|
21814
21952
|
import fs25 from "fs";
|
|
21815
21953
|
import path31 from "path";
|
|
21816
|
-
import * as
|
|
21954
|
+
import * as p13 from "@clack/prompts";
|
|
21817
21955
|
var CREATE_PROMPT_CONTEXT = {
|
|
21818
21956
|
cancelMessage: "Create schema cancelled."
|
|
21819
21957
|
};
|
|
@@ -22004,7 +22142,7 @@ async function promptTabSlotFields(kind, schemasDir, titleField) {
|
|
|
22004
22142
|
);
|
|
22005
22143
|
if (!addField) {
|
|
22006
22144
|
if (!hasFields) {
|
|
22007
|
-
|
|
22145
|
+
p13.log.warn("Tabs need at least one child field.");
|
|
22008
22146
|
continue;
|
|
22009
22147
|
}
|
|
22010
22148
|
return { main, sidebar };
|
|
@@ -22052,7 +22190,7 @@ async function promptSchemaTab(kind, schemasDir, titleField, existingTabs) {
|
|
|
22052
22190
|
while (fields.length === 0) {
|
|
22053
22191
|
await promptAdditionalSchemaFields(kind, schemasDir, fields);
|
|
22054
22192
|
if (fields.length === 0) {
|
|
22055
|
-
|
|
22193
|
+
p13.log.warn("Tabs need at least one child field.");
|
|
22056
22194
|
}
|
|
22057
22195
|
}
|
|
22058
22196
|
}
|
|
@@ -22142,7 +22280,7 @@ async function promptFormSubmissionColumns(schema) {
|
|
|
22142
22280
|
}
|
|
22143
22281
|
const existingColumnNames = schema.columns ? new Set(schema.columns.map((column) => column.accessorKey)) : void 0;
|
|
22144
22282
|
const initialValues = existingColumnNames ? fields.filter((field) => existingColumnNames.has(field.name)).map((field) => field.name) : fields.map((field) => field.name);
|
|
22145
|
-
const selected = await
|
|
22283
|
+
const selected = await p13.multiselect({
|
|
22146
22284
|
message: "Submission table columns",
|
|
22147
22285
|
options: fields.map((field) => ({
|
|
22148
22286
|
value: field.name,
|
|
@@ -22151,8 +22289,8 @@ async function promptFormSubmissionColumns(schema) {
|
|
|
22151
22289
|
initialValues,
|
|
22152
22290
|
required: false
|
|
22153
22291
|
});
|
|
22154
|
-
if (
|
|
22155
|
-
|
|
22292
|
+
if (p13.isCancel(selected)) {
|
|
22293
|
+
cancel3(CREATE_PROMPT_CONTEXT);
|
|
22156
22294
|
}
|
|
22157
22295
|
const selectedNames = new Set(selected);
|
|
22158
22296
|
schema.columns = fields.filter((field) => selectedNames.has(field.name)).map((field) => {
|
|
@@ -22211,7 +22349,7 @@ function schemaFilePath(kind, schemasDir, schemaName) {
|
|
|
22211
22349
|
return kind === "form" ? path31.join(schemasDir, "forms", `${schemaName}.json`) : path31.join(schemasDir, `${schemaName}.json`);
|
|
22212
22350
|
}
|
|
22213
22351
|
function printPreview2(loaded, cwd) {
|
|
22214
|
-
|
|
22352
|
+
p13.note(
|
|
22215
22353
|
`schema: ${loaded.name} (${loaded.kind})
|
|
22216
22354
|
path: ${path31.relative(cwd, loaded.filePath)}
|
|
22217
22355
|
owner: user
|
|
@@ -22226,7 +22364,7 @@ async function runCreateCommand(kindInput, schemaName, options) {
|
|
|
22226
22364
|
if (!snapshotRootExists(cwd)) {
|
|
22227
22365
|
fail(UNSUPPORTED_PROJECT_STATE_MESSAGE);
|
|
22228
22366
|
}
|
|
22229
|
-
if (!
|
|
22367
|
+
if (!isInteractiveSession4()) {
|
|
22230
22368
|
fail("Interactive create requires a TTY.");
|
|
22231
22369
|
}
|
|
22232
22370
|
const config = await resolveConfigOrExit(cwd);
|
|
@@ -22258,13 +22396,13 @@ ${validationErrors.map((error) => ` - ${error}`).join("\n")}`
|
|
|
22258
22396
|
break;
|
|
22259
22397
|
}
|
|
22260
22398
|
if (action === "cancel") {
|
|
22261
|
-
|
|
22399
|
+
cancel3(CREATE_PROMPT_CONTEXT);
|
|
22262
22400
|
}
|
|
22263
22401
|
await promptAdditionalCreateField(kind, schemasDir, schema);
|
|
22264
22402
|
}
|
|
22265
22403
|
fs25.mkdirSync(path31.dirname(filePath), { recursive: true });
|
|
22266
22404
|
writeAuthoredGeneratedSchema(loaded);
|
|
22267
|
-
|
|
22405
|
+
p13.log.success(`Created ${path31.relative(cwd, filePath)}`);
|
|
22268
22406
|
try {
|
|
22269
22407
|
await runGenerateCommand(metadata.name, {
|
|
22270
22408
|
force: false,
|
|
@@ -22275,8 +22413,8 @@ ${validationErrors.map((error) => ` - ${error}`).join("\n")}`
|
|
|
22275
22413
|
cwd
|
|
22276
22414
|
});
|
|
22277
22415
|
} catch (error) {
|
|
22278
|
-
|
|
22279
|
-
|
|
22416
|
+
p13.log.error(error instanceof Error ? error.message : String(error));
|
|
22417
|
+
p13.log.info(
|
|
22280
22418
|
`Schema JSON was kept. Re-run \`betterstart generate ${metadata.name}${options.skipMigration ? " --skip-migration" : ""}\` after resolving the issue.`
|
|
22281
22419
|
);
|
|
22282
22420
|
process.exit(1);
|
|
@@ -22284,18 +22422,18 @@ ${validationErrors.map((error) => ` - ${error}`).join("\n")}`
|
|
|
22284
22422
|
}
|
|
22285
22423
|
|
|
22286
22424
|
// adapters/next/commands/init.ts
|
|
22287
|
-
import { execFileSync as
|
|
22425
|
+
import { execFileSync as execFileSync4, spawn as spawn6 } from "child_process";
|
|
22288
22426
|
import fs41 from "fs";
|
|
22289
22427
|
import path52 from "path";
|
|
22290
22428
|
import { PassThrough } from "stream";
|
|
22291
|
-
import * as
|
|
22429
|
+
import * as p26 from "@clack/prompts";
|
|
22292
22430
|
|
|
22293
22431
|
// core-engine/utils/cancel-guard.ts
|
|
22294
|
-
import * as
|
|
22432
|
+
import * as p14 from "@clack/prompts";
|
|
22295
22433
|
function installSetupCancelGuard() {
|
|
22296
22434
|
const onSignal = () => {
|
|
22297
22435
|
if (!hasActiveSpinner()) {
|
|
22298
|
-
|
|
22436
|
+
p14.cancel("Setup cancelled.");
|
|
22299
22437
|
}
|
|
22300
22438
|
process.exit(0);
|
|
22301
22439
|
};
|
|
@@ -22349,12 +22487,12 @@ function redactSecrets(text7) {
|
|
|
22349
22487
|
}
|
|
22350
22488
|
|
|
22351
22489
|
// adapters/next/init/prompts/database.ts
|
|
22352
|
-
import { execFileSync as
|
|
22353
|
-
import * as
|
|
22490
|
+
import { execFileSync as execFileSync3 } from "child_process";
|
|
22491
|
+
import * as p15 from "@clack/prompts";
|
|
22354
22492
|
import pc from "picocolors";
|
|
22355
22493
|
var VERCEL_NEON_URL = "https://vercel.com/dashboard/integrations/checkout/neon";
|
|
22356
22494
|
async function promptServices() {
|
|
22357
|
-
const choice = await
|
|
22495
|
+
const choice = await p15.select({
|
|
22358
22496
|
message: "Connect a PostgreSQL Database",
|
|
22359
22497
|
options: [
|
|
22360
22498
|
{
|
|
@@ -22375,8 +22513,8 @@ async function promptServices() {
|
|
|
22375
22513
|
],
|
|
22376
22514
|
initialValue: "vercel"
|
|
22377
22515
|
});
|
|
22378
|
-
if (
|
|
22379
|
-
|
|
22516
|
+
if (p15.isCancel(choice)) {
|
|
22517
|
+
p15.cancel("Setup cancelled.");
|
|
22380
22518
|
process.exit(0);
|
|
22381
22519
|
}
|
|
22382
22520
|
if (choice === "vercel") {
|
|
@@ -22390,7 +22528,7 @@ async function promptServices() {
|
|
|
22390
22528
|
}
|
|
22391
22529
|
function openBrowserVercelNeon() {
|
|
22392
22530
|
openBrowser(VERCEL_NEON_URL);
|
|
22393
|
-
|
|
22531
|
+
p15.log.info(
|
|
22394
22532
|
`Opening Vercel... Create a Neon Postgres database, then copy the ${pc.cyan("DATABASE_URL")} from the dashboard.`
|
|
22395
22533
|
);
|
|
22396
22534
|
}
|
|
@@ -22400,12 +22538,12 @@ function openBrowserVercelNeonResource(url) {
|
|
|
22400
22538
|
return;
|
|
22401
22539
|
}
|
|
22402
22540
|
openBrowser(url);
|
|
22403
|
-
|
|
22541
|
+
p15.log.info(
|
|
22404
22542
|
`Opening Vercel... Copy the Neon ${pc.cyan("DATABASE_URL")} from the database dashboard, then paste it below.`
|
|
22405
22543
|
);
|
|
22406
22544
|
}
|
|
22407
22545
|
async function promptConnectionString() {
|
|
22408
|
-
const input = await
|
|
22546
|
+
const input = await p15.text({
|
|
22409
22547
|
message: "Paste your PostgreSQL connection string",
|
|
22410
22548
|
placeholder: "postgres://user:pass@host/db",
|
|
22411
22549
|
validate(val) {
|
|
@@ -22419,8 +22557,8 @@ async function promptConnectionString() {
|
|
|
22419
22557
|
}
|
|
22420
22558
|
}
|
|
22421
22559
|
});
|
|
22422
|
-
if (
|
|
22423
|
-
|
|
22560
|
+
if (p15.isCancel(input)) {
|
|
22561
|
+
p15.cancel("Setup cancelled.");
|
|
22424
22562
|
process.exit(0);
|
|
22425
22563
|
}
|
|
22426
22564
|
return input.replace(/^['"]|['"]$/g, "").trim();
|
|
@@ -22429,18 +22567,18 @@ function openBrowser(url) {
|
|
|
22429
22567
|
try {
|
|
22430
22568
|
const platform = process.platform;
|
|
22431
22569
|
if (platform === "darwin") {
|
|
22432
|
-
|
|
22570
|
+
execFileSync3("open", [url], { stdio: "ignore" });
|
|
22433
22571
|
} else if (platform === "win32") {
|
|
22434
|
-
|
|
22572
|
+
execFileSync3("cmd", ["/c", "start", url], { stdio: "ignore" });
|
|
22435
22573
|
} else {
|
|
22436
|
-
|
|
22574
|
+
execFileSync3("xdg-open", [url], { stdio: "ignore" });
|
|
22437
22575
|
}
|
|
22438
22576
|
} catch {
|
|
22439
22577
|
}
|
|
22440
22578
|
}
|
|
22441
22579
|
|
|
22442
22580
|
// adapters/next/init/prompts/presets.ts
|
|
22443
|
-
import * as
|
|
22581
|
+
import * as p16 from "@clack/prompts";
|
|
22444
22582
|
|
|
22445
22583
|
// adapters/next/init/scaffolders/env.ts
|
|
22446
22584
|
import crypto2 from "crypto";
|
|
@@ -22605,7 +22743,7 @@ async function promptPresets(cwd, options = {}) {
|
|
|
22605
22743
|
overwriteKeys.add(key);
|
|
22606
22744
|
}
|
|
22607
22745
|
};
|
|
22608
|
-
const storage = await
|
|
22746
|
+
const storage = await p16.select({
|
|
22609
22747
|
message: "Choose a file storage",
|
|
22610
22748
|
options: [
|
|
22611
22749
|
{
|
|
@@ -22629,8 +22767,8 @@ async function promptPresets(cwd, options = {}) {
|
|
|
22629
22767
|
],
|
|
22630
22768
|
initialValue: "vercel-blob"
|
|
22631
22769
|
});
|
|
22632
|
-
if (
|
|
22633
|
-
|
|
22770
|
+
if (p16.isCancel(storage)) {
|
|
22771
|
+
p16.cancel("Setup cancelled.");
|
|
22634
22772
|
process.exit(0);
|
|
22635
22773
|
}
|
|
22636
22774
|
if (storage === "r2") {
|
|
@@ -22640,7 +22778,7 @@ async function promptPresets(cwd, options = {}) {
|
|
|
22640
22778
|
if (flow?.ok && flow.config) {
|
|
22641
22779
|
mergeIntegrationConfig(flow.config);
|
|
22642
22780
|
} else if (flow) {
|
|
22643
|
-
|
|
22781
|
+
p16.log.warn(
|
|
22644
22782
|
"Continuing without Railway bucket credentials \u2014 rerun betterstart add --integration railway-bucket after fixing Railway access."
|
|
22645
22783
|
);
|
|
22646
22784
|
} else {
|
|
@@ -22657,7 +22795,7 @@ async function promptPresets(cwd, options = {}) {
|
|
|
22657
22795
|
});
|
|
22658
22796
|
overwriteKeys.add("BLOB_READ_WRITE_TOKEN");
|
|
22659
22797
|
} else if (flow) {
|
|
22660
|
-
|
|
22798
|
+
p16.log.warn(
|
|
22661
22799
|
"Continuing without a Blob token \u2014 add BLOB_READ_WRITE_TOKEN to .env.local from the store on vercel.com/dashboard/stores."
|
|
22662
22800
|
);
|
|
22663
22801
|
sections.push({
|
|
@@ -22666,7 +22804,7 @@ async function promptPresets(cwd, options = {}) {
|
|
|
22666
22804
|
});
|
|
22667
22805
|
} else {
|
|
22668
22806
|
if (existingToken) {
|
|
22669
|
-
|
|
22807
|
+
p16.log.info(
|
|
22670
22808
|
`Using the existing BLOB_READ_WRITE_TOKEN from .env.local ${pc2.dim(
|
|
22671
22809
|
`(${maskBlobToken(existingToken)})`
|
|
22672
22810
|
)}`
|
|
@@ -22675,7 +22813,7 @@ async function promptPresets(cwd, options = {}) {
|
|
|
22675
22813
|
mergeIntegrationConfig(await collectIntegrationConfig(cwd, ["vercel-blob"]));
|
|
22676
22814
|
}
|
|
22677
22815
|
}
|
|
22678
|
-
const selectedPresets = await
|
|
22816
|
+
const selectedPresets = await p16.multiselect({
|
|
22679
22817
|
message: "Select presets",
|
|
22680
22818
|
options: [
|
|
22681
22819
|
{
|
|
@@ -22687,8 +22825,8 @@ async function promptPresets(cwd, options = {}) {
|
|
|
22687
22825
|
required: false,
|
|
22688
22826
|
initialValues: ["blog"]
|
|
22689
22827
|
});
|
|
22690
|
-
if (
|
|
22691
|
-
|
|
22828
|
+
if (p16.isCancel(selectedPresets)) {
|
|
22829
|
+
p16.cancel("Setup cancelled.");
|
|
22692
22830
|
process.exit(0);
|
|
22693
22831
|
}
|
|
22694
22832
|
const integrations = [];
|
|
@@ -22715,9 +22853,9 @@ async function promptPresets(cwd, options = {}) {
|
|
|
22715
22853
|
}
|
|
22716
22854
|
|
|
22717
22855
|
// adapters/next/init/prompts/project.ts
|
|
22718
|
-
import * as
|
|
22856
|
+
import * as p17 from "@clack/prompts";
|
|
22719
22857
|
async function promptProject(defaultName) {
|
|
22720
|
-
const projectName = await
|
|
22858
|
+
const projectName = await p17.text({
|
|
22721
22859
|
message: "What is your project named?",
|
|
22722
22860
|
placeholder: defaultName ?? "(Press Enter to use default)",
|
|
22723
22861
|
defaultValue: defaultName ?? ".",
|
|
@@ -22730,15 +22868,15 @@ async function promptProject(defaultName) {
|
|
|
22730
22868
|
return void 0;
|
|
22731
22869
|
}
|
|
22732
22870
|
});
|
|
22733
|
-
if (
|
|
22734
|
-
|
|
22871
|
+
if (p17.isCancel(projectName)) {
|
|
22872
|
+
p17.cancel("Setup cancelled.");
|
|
22735
22873
|
process.exit(0);
|
|
22736
22874
|
}
|
|
22737
22875
|
return { projectName: projectName.trim() || "." };
|
|
22738
22876
|
}
|
|
22739
22877
|
|
|
22740
22878
|
// adapters/next/init/providers.ts
|
|
22741
|
-
import * as
|
|
22879
|
+
import * as p18 from "@clack/prompts";
|
|
22742
22880
|
var DATABASE_PROVIDERS = ["vercel", "railway", "manual"];
|
|
22743
22881
|
var STORAGE_PROVIDERS = ["vercel-blob", "railway-bucket", "r2", "local"];
|
|
22744
22882
|
var DEPLOY_PROVIDERS = ["vercel", "railway", "none"];
|
|
@@ -22795,7 +22933,7 @@ function validateResolvedDatabaseProvider(provider, options) {
|
|
|
22795
22933
|
}
|
|
22796
22934
|
}
|
|
22797
22935
|
async function promptDeployProvider(initialValue = "none") {
|
|
22798
|
-
const provider = await
|
|
22936
|
+
const provider = await p18.select({
|
|
22799
22937
|
message: "Deploy this project",
|
|
22800
22938
|
options: [
|
|
22801
22939
|
{
|
|
@@ -22813,8 +22951,8 @@ async function promptDeployProvider(initialValue = "none") {
|
|
|
22813
22951
|
],
|
|
22814
22952
|
initialValue
|
|
22815
22953
|
});
|
|
22816
|
-
if (
|
|
22817
|
-
|
|
22954
|
+
if (p18.isCancel(provider)) {
|
|
22955
|
+
p18.cancel("Setup cancelled.");
|
|
22818
22956
|
process.exit(0);
|
|
22819
22957
|
}
|
|
22820
22958
|
return provider;
|
|
@@ -22823,7 +22961,7 @@ async function promptDeployProvider(initialValue = "none") {
|
|
|
22823
22961
|
// adapters/next/init/railway/deploy.ts
|
|
22824
22962
|
import fs28 from "fs";
|
|
22825
22963
|
import path34 from "path";
|
|
22826
|
-
import * as
|
|
22964
|
+
import * as p20 from "@clack/prompts";
|
|
22827
22965
|
|
|
22828
22966
|
// adapters/next/init/deploy/guard.ts
|
|
22829
22967
|
import { spawn as spawn3 } from "child_process";
|
|
@@ -22920,7 +23058,7 @@ function guardBetterstartConfig(cwd, restores) {
|
|
|
22920
23058
|
}
|
|
22921
23059
|
|
|
22922
23060
|
// adapters/next/init/railway/project.ts
|
|
22923
|
-
import * as
|
|
23061
|
+
import * as p19 from "@clack/prompts";
|
|
22924
23062
|
|
|
22925
23063
|
// adapters/next/init/railway/runner.ts
|
|
22926
23064
|
import { spawn as spawn4 } from "child_process";
|
|
@@ -23204,15 +23342,15 @@ async function ensureRailwayProject(runner, options) {
|
|
|
23204
23342
|
createWorkspace = options.workspaces[0]?.id;
|
|
23205
23343
|
} else if (!createWorkspace && options.interactive && options.workspaces?.length) {
|
|
23206
23344
|
projectSpinner.clear();
|
|
23207
|
-
const workspace = await
|
|
23345
|
+
const workspace = await p19.select({
|
|
23208
23346
|
message: "Choose a Railway workspace",
|
|
23209
23347
|
options: options.workspaces.map((candidate) => ({
|
|
23210
23348
|
value: candidate.id,
|
|
23211
23349
|
label: candidate.name
|
|
23212
23350
|
}))
|
|
23213
23351
|
});
|
|
23214
|
-
if (
|
|
23215
|
-
|
|
23352
|
+
if (p19.isCancel(workspace)) {
|
|
23353
|
+
p19.cancel("Setup cancelled.");
|
|
23216
23354
|
process.exit(0);
|
|
23217
23355
|
}
|
|
23218
23356
|
createWorkspace = workspace;
|
|
@@ -23738,7 +23876,7 @@ async function runRailwayDeployFlow(options) {
|
|
|
23738
23876
|
);
|
|
23739
23877
|
envSpinner.clear();
|
|
23740
23878
|
for (const key of sync.failed) {
|
|
23741
|
-
|
|
23879
|
+
p20.log.warn(`Could not set ${pc4.cyan(key)} on Railway.`);
|
|
23742
23880
|
}
|
|
23743
23881
|
if (sync.failed.length > 0) {
|
|
23744
23882
|
return {
|
|
@@ -23753,12 +23891,12 @@ async function runRailwayDeployFlow(options) {
|
|
|
23753
23891
|
const packageGuard = await guardProjectForDeploy(options.cwd);
|
|
23754
23892
|
guardSpinner.clear();
|
|
23755
23893
|
if (packageGuard.lockfile === "failed") {
|
|
23756
|
-
|
|
23894
|
+
p20.log.warn(
|
|
23757
23895
|
"Could not refresh pnpm-lock.yaml after removing betterstart-cli \u2014 the remote install may fail."
|
|
23758
23896
|
);
|
|
23759
23897
|
}
|
|
23760
23898
|
for (const dependency of packageGuard.localSpecDeps) {
|
|
23761
|
-
|
|
23899
|
+
p20.log.warn(
|
|
23762
23900
|
`Dependency ${pc4.cyan(dependency)} uses a local spec that cannot install on Railway.`
|
|
23763
23901
|
);
|
|
23764
23902
|
}
|
|
@@ -23811,7 +23949,7 @@ ${deploy.stderr}`) ?? deploy.errorMessage
|
|
|
23811
23949
|
}
|
|
23812
23950
|
|
|
23813
23951
|
// adapters/next/init/railway/auth.ts
|
|
23814
|
-
import * as
|
|
23952
|
+
import * as p21 from "@clack/prompts";
|
|
23815
23953
|
import pc5 from "picocolors";
|
|
23816
23954
|
var WHOAMI_TIMEOUT_MS = 3e4;
|
|
23817
23955
|
var LOGIN_TIMEOUT_MS = 3e5;
|
|
@@ -23881,7 +24019,7 @@ async function ensureRailwayAuth(runner, cwd, options) {
|
|
|
23881
24019
|
return { authed: false, reason: existing.reason };
|
|
23882
24020
|
}
|
|
23883
24021
|
checkSpinner.clear();
|
|
23884
|
-
|
|
24022
|
+
p21.log.info(
|
|
23885
24023
|
"Sign in to Railway to continue. Railway will open your browser or show a device code."
|
|
23886
24024
|
);
|
|
23887
24025
|
const login = await runRailway(runner, ["login"], {
|
|
@@ -25768,11 +25906,11 @@ function scaffoldTsconfig(cwd, config) {
|
|
|
25768
25906
|
}
|
|
25769
25907
|
|
|
25770
25908
|
// adapters/next/init/vercel/flow.ts
|
|
25771
|
-
import * as
|
|
25909
|
+
import * as p25 from "@clack/prompts";
|
|
25772
25910
|
import pc9 from "picocolors";
|
|
25773
25911
|
|
|
25774
25912
|
// adapters/next/init/vercel/auth.ts
|
|
25775
|
-
import * as
|
|
25913
|
+
import * as p22 from "@clack/prompts";
|
|
25776
25914
|
import pc6 from "picocolors";
|
|
25777
25915
|
|
|
25778
25916
|
// adapters/next/init/vercel/runner.ts
|
|
@@ -26016,7 +26154,7 @@ async function ensureVercelAuth(runner, cwd, options) {
|
|
|
26016
26154
|
checkSpinner.clear();
|
|
26017
26155
|
const signInMessage = `Sign in to Vercel to continue ${pc6.dim("(or press Ctrl-C to enter a connection string manually)")}`;
|
|
26018
26156
|
const signInRows = clackLogRows(signInMessage);
|
|
26019
|
-
|
|
26157
|
+
p22.log.info(signInMessage);
|
|
26020
26158
|
let streamedRows = 0;
|
|
26021
26159
|
const login = await runVercel(runner, ["login"], {
|
|
26022
26160
|
cwd,
|
|
@@ -26048,7 +26186,7 @@ function signedInMessage(username) {
|
|
|
26048
26186
|
}
|
|
26049
26187
|
|
|
26050
26188
|
// adapters/next/init/vercel/blob.ts
|
|
26051
|
-
import * as
|
|
26189
|
+
import * as p23 from "@clack/prompts";
|
|
26052
26190
|
import pc7 from "picocolors";
|
|
26053
26191
|
|
|
26054
26192
|
// adapters/next/init/vercel/env-pull.ts
|
|
@@ -26290,7 +26428,7 @@ async function provisionBlobStoreInteractive(runner, cwd, options) {
|
|
|
26290
26428
|
if (terminalFallbackRan) break;
|
|
26291
26429
|
terminalFallbackRan = true;
|
|
26292
26430
|
quietSpinner.clear();
|
|
26293
|
-
|
|
26431
|
+
p23.log.info(
|
|
26294
26432
|
`Create your Blob store in the Vercel prompts below ${pc7.dim(
|
|
26295
26433
|
"(connect it to all environments)."
|
|
26296
26434
|
)}`
|
|
@@ -26489,7 +26627,7 @@ function guardEnvLocal(cwd) {
|
|
|
26489
26627
|
}
|
|
26490
26628
|
|
|
26491
26629
|
// adapters/next/init/vercel/neon.ts
|
|
26492
|
-
import * as
|
|
26630
|
+
import * as p24 from "@clack/prompts";
|
|
26493
26631
|
import pc8 from "picocolors";
|
|
26494
26632
|
var PROVISION_TIMEOUT_MS2 = 18e4;
|
|
26495
26633
|
var INTERACTIVE_PROVISION_TIMEOUT_MS2 = 6e5;
|
|
@@ -26508,7 +26646,7 @@ async function provisionNeonInteractive(runner, cwd, options) {
|
|
|
26508
26646
|
termsResolved = true;
|
|
26509
26647
|
quietSpinner.clear();
|
|
26510
26648
|
eraseRows(termsNotice.rows);
|
|
26511
|
-
|
|
26649
|
+
p24.log.step(termsNotice.text);
|
|
26512
26650
|
};
|
|
26513
26651
|
const quiet = await runVercel(runner, neonAddArgs(options), {
|
|
26514
26652
|
cwd,
|
|
@@ -26527,7 +26665,7 @@ ${pc8.dim(termsUrl)}`,
|
|
|
26527
26665
|
rows: clackLogRows(message) + clackLogRows(termsUrl) - 1
|
|
26528
26666
|
};
|
|
26529
26667
|
quietSpinner.clear();
|
|
26530
|
-
|
|
26668
|
+
p24.log.info(termsNotice.text);
|
|
26531
26669
|
quietSpinner.start("Waiting for the terms to be accepted");
|
|
26532
26670
|
return;
|
|
26533
26671
|
}
|
|
@@ -26543,7 +26681,7 @@ ${pc8.dim(termsUrl)}`,
|
|
|
26543
26681
|
return readNeonProvisionInfo(quiet.stdout);
|
|
26544
26682
|
}
|
|
26545
26683
|
quietSpinner.clear();
|
|
26546
|
-
|
|
26684
|
+
p24.log.info(
|
|
26547
26685
|
`Create your Neon database in the Vercel prompts below ${pc8.dim(
|
|
26548
26686
|
"(the Free plan is recommended)."
|
|
26549
26687
|
)}`
|
|
@@ -26620,14 +26758,14 @@ async function runVercelNeonFlow(options) {
|
|
|
26620
26758
|
allowLogin: options.interactive
|
|
26621
26759
|
});
|
|
26622
26760
|
if (!auth.authed) {
|
|
26623
|
-
|
|
26761
|
+
p25.log.warn(authFailureMessage(auth.reason));
|
|
26624
26762
|
return { ok: false };
|
|
26625
26763
|
}
|
|
26626
26764
|
await ensureLinkedProject(runner, options.cwd, options.projectName, env, auth.username);
|
|
26627
26765
|
const neon = await provisionNeonForMode(runner, options);
|
|
26628
26766
|
if (neon.failure) {
|
|
26629
|
-
|
|
26630
|
-
if (neon.detail)
|
|
26767
|
+
p25.log.warn(neonFailureMessage(neon.failure));
|
|
26768
|
+
if (neon.detail) p25.log.message(pc9.dim(redactSecrets(neon.detail)));
|
|
26631
26769
|
return { ok: false };
|
|
26632
26770
|
}
|
|
26633
26771
|
const databaseUrl = await pullNeonDatabaseUrl(runner, options.cwd, env);
|
|
@@ -26640,7 +26778,7 @@ async function runVercelNeonFlow(options) {
|
|
|
26640
26778
|
dismissSignedInNote
|
|
26641
26779
|
};
|
|
26642
26780
|
} catch (error) {
|
|
26643
|
-
|
|
26781
|
+
p25.log.warn(
|
|
26644
26782
|
`Vercel provisioning failed: ${error instanceof Error ? error.message : String(error)}`
|
|
26645
26783
|
);
|
|
26646
26784
|
return { ok: false };
|
|
@@ -26662,14 +26800,14 @@ async function runVercelBlobFlow(options) {
|
|
|
26662
26800
|
allowLogin: options.interactive
|
|
26663
26801
|
});
|
|
26664
26802
|
if (!auth.authed) {
|
|
26665
|
-
|
|
26803
|
+
p25.log.warn(authFailureMessage(auth.reason));
|
|
26666
26804
|
return { ok: false };
|
|
26667
26805
|
}
|
|
26668
26806
|
await ensureLinkedProject(runner, options.cwd, options.projectName, env, auth.username);
|
|
26669
26807
|
const blob = await provisionBlobForMode(runner, options);
|
|
26670
26808
|
if (blob.failure || !blob.token) {
|
|
26671
|
-
|
|
26672
|
-
if (blob.detail)
|
|
26809
|
+
p25.log.warn(blobFailureMessage(blob.failure));
|
|
26810
|
+
if (blob.detail) p25.log.message(pc9.dim(redactSecrets(blob.detail)));
|
|
26673
26811
|
return { ok: false };
|
|
26674
26812
|
}
|
|
26675
26813
|
return {
|
|
@@ -26678,7 +26816,7 @@ async function runVercelBlobFlow(options) {
|
|
|
26678
26816
|
blobStoreName: blob.storeName
|
|
26679
26817
|
};
|
|
26680
26818
|
} catch (error) {
|
|
26681
|
-
|
|
26819
|
+
p25.log.warn(
|
|
26682
26820
|
`Vercel provisioning failed: ${error instanceof Error ? error.message : String(error)}`
|
|
26683
26821
|
);
|
|
26684
26822
|
return { ok: false };
|
|
@@ -26700,7 +26838,7 @@ async function runVercelDeployFlow(options) {
|
|
|
26700
26838
|
allowLogin: options.interactive ?? true
|
|
26701
26839
|
});
|
|
26702
26840
|
if (!auth.authed) {
|
|
26703
|
-
|
|
26841
|
+
p25.log.warn(authFailureMessage(auth.reason));
|
|
26704
26842
|
printManualDeployHint();
|
|
26705
26843
|
return { ok: false };
|
|
26706
26844
|
}
|
|
@@ -26710,7 +26848,7 @@ async function runVercelDeployFlow(options) {
|
|
|
26710
26848
|
const sync = await syncVercelProductionEnv(runner, options.cwd, env);
|
|
26711
26849
|
envSpinner.clear();
|
|
26712
26850
|
for (const key of sync.failed) {
|
|
26713
|
-
|
|
26851
|
+
p25.log.warn(
|
|
26714
26852
|
`Could not set ${pc9.cyan(key)} on Vercel \u2014 add it in the project's environment settings.`
|
|
26715
26853
|
);
|
|
26716
26854
|
}
|
|
@@ -26720,12 +26858,12 @@ async function runVercelDeployFlow(options) {
|
|
|
26720
26858
|
const packageGuard = await guardProjectForDeploy(options.cwd);
|
|
26721
26859
|
guardSpinner.clear();
|
|
26722
26860
|
if (packageGuard.lockfile === "failed") {
|
|
26723
|
-
|
|
26861
|
+
p25.log.warn(
|
|
26724
26862
|
"Could not refresh pnpm-lock.yaml after removing betterstart-cli \u2014 the remote install may fail."
|
|
26725
26863
|
);
|
|
26726
26864
|
}
|
|
26727
26865
|
for (const dep of packageGuard.localSpecDeps) {
|
|
26728
|
-
|
|
26866
|
+
p25.log.warn(
|
|
26729
26867
|
`Dependency ${pc9.cyan(dep)} uses a local spec that cannot install on Vercel \u2014 the remote build may fail.`
|
|
26730
26868
|
);
|
|
26731
26869
|
}
|
|
@@ -26742,7 +26880,7 @@ async function runVercelDeployFlow(options) {
|
|
|
26742
26880
|
}
|
|
26743
26881
|
if (deploy.failure) {
|
|
26744
26882
|
deploySpinner.stop(`${pc9.yellow("\u25B2")} ${deployFailureMessage(deploy.failure)}`);
|
|
26745
|
-
if (deploy.detail)
|
|
26883
|
+
if (deploy.detail) p25.log.message(pc9.dim(redactSecrets(deploy.detail)));
|
|
26746
26884
|
printManualDeployHint();
|
|
26747
26885
|
return { ok: false };
|
|
26748
26886
|
}
|
|
@@ -26750,7 +26888,7 @@ async function runVercelDeployFlow(options) {
|
|
|
26750
26888
|
deploySpinner.stop(url ? `Deployed ${pc9.cyan(url)}` : "Deployed to Vercel");
|
|
26751
26889
|
return { ok: true, url, syncedEnvKeys: sync.synced };
|
|
26752
26890
|
} catch (error) {
|
|
26753
|
-
|
|
26891
|
+
p25.log.warn(`Vercel deploy failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
26754
26892
|
printManualDeployHint();
|
|
26755
26893
|
return { ok: false };
|
|
26756
26894
|
} finally {
|
|
@@ -26758,7 +26896,7 @@ async function runVercelDeployFlow(options) {
|
|
|
26758
26896
|
}
|
|
26759
26897
|
}
|
|
26760
26898
|
function printManualDeployHint() {
|
|
26761
|
-
|
|
26899
|
+
p25.log.info(`You can deploy manually: ${pc9.cyan("vercel deploy --prod")}`);
|
|
26762
26900
|
}
|
|
26763
26901
|
async function ensureLinkedProject(runner, cwd, projectName, env, scope) {
|
|
26764
26902
|
if (readLinkedProjectId(cwd)) return;
|
|
@@ -26841,13 +26979,6 @@ import pc10 from "picocolors";
|
|
|
26841
26979
|
import fs40 from "fs";
|
|
26842
26980
|
import path51 from "path";
|
|
26843
26981
|
import * as clack2 from "@clack/prompts";
|
|
26844
|
-
|
|
26845
|
-
// core-engine/utils/interactive.ts
|
|
26846
|
-
function isInteractiveSession4() {
|
|
26847
|
-
return Boolean(process.stdin.isTTY) && process.env.CI !== "true";
|
|
26848
|
-
}
|
|
26849
|
-
|
|
26850
|
-
// adapters/next/commands/seed.ts
|
|
26851
26982
|
function buildSeedScript(authBasePath = "/api/admin/auth") {
|
|
26852
26983
|
return `/**
|
|
26853
26984
|
* BetterStart Admin \u2014 Seed Script
|
|
@@ -27029,7 +27160,7 @@ async function runSeedCommand(options) {
|
|
|
27029
27160
|
process.exit(1);
|
|
27030
27161
|
}
|
|
27031
27162
|
const adminDir = config.paths?.admin ?? "./admin";
|
|
27032
|
-
const interactive =
|
|
27163
|
+
const interactive = isInteractiveSession();
|
|
27033
27164
|
let email;
|
|
27034
27165
|
if (options.email) {
|
|
27035
27166
|
if (!options.email.includes("@")) {
|
|
@@ -27102,10 +27233,10 @@ async function runSeedCommand(options) {
|
|
|
27102
27233
|
}
|
|
27103
27234
|
const namespace = resolveAdminNamespace(config.frameworkConfig.next.namespace);
|
|
27104
27235
|
fs40.writeFileSync(seedPath, buildSeedScript(`${namespace.apiPath}/auth`), "utf-8");
|
|
27105
|
-
const { execFile } = await import("child_process");
|
|
27236
|
+
const { execFile: execFile2 } = await import("child_process");
|
|
27106
27237
|
const tsxBin = path51.join(cwd, "node_modules", ".bin", "tsx");
|
|
27107
27238
|
const runSeed2 = (overwrite) => new Promise((resolve, reject) => {
|
|
27108
|
-
|
|
27239
|
+
execFile2(
|
|
27109
27240
|
tsxBin,
|
|
27110
27241
|
[seedPath],
|
|
27111
27242
|
{
|
|
@@ -27194,16 +27325,16 @@ function addVersionToBoxBottomBorder(box2, version2) {
|
|
|
27194
27325
|
if (!bottomLine) {
|
|
27195
27326
|
return box2;
|
|
27196
27327
|
}
|
|
27197
|
-
const leftCornerIndex = bottomLine.indexOf(
|
|
27198
|
-
const rightCornerIndex = bottomLine.lastIndexOf(
|
|
27328
|
+
const leftCornerIndex = bottomLine.indexOf(p26.S_CORNER_BOTTOM_LEFT);
|
|
27329
|
+
const rightCornerIndex = bottomLine.lastIndexOf(p26.S_CORNER_BOTTOM_RIGHT);
|
|
27199
27330
|
const label = ` v${version2} `;
|
|
27200
|
-
const borderWidth = rightCornerIndex - leftCornerIndex -
|
|
27331
|
+
const borderWidth = rightCornerIndex - leftCornerIndex - p26.S_CORNER_BOTTOM_LEFT.length;
|
|
27201
27332
|
if (leftCornerIndex === -1 || rightCornerIndex === -1 || borderWidth < label.length) {
|
|
27202
27333
|
return box2;
|
|
27203
27334
|
}
|
|
27204
27335
|
const leftBorderWidth = Math.floor((borderWidth - label.length) / 2);
|
|
27205
27336
|
const rightBorderWidth = borderWidth - label.length - leftBorderWidth;
|
|
27206
|
-
lines[bottomLineIndex] = `${bottomLine.slice(0, leftCornerIndex +
|
|
27337
|
+
lines[bottomLineIndex] = `${bottomLine.slice(0, leftCornerIndex + p26.S_CORNER_BOTTOM_LEFT.length)}${p26.S_BAR_H.repeat(leftBorderWidth)}${label}${p26.S_BAR_H.repeat(rightBorderWidth)}${bottomLine.slice(rightCornerIndex)}`;
|
|
27207
27338
|
return lines.join("\n");
|
|
27208
27339
|
}
|
|
27209
27340
|
function renderInitBanner() {
|
|
@@ -27213,7 +27344,7 @@ function renderInitBanner() {
|
|
|
27213
27344
|
output.on("data", (chunk) => {
|
|
27214
27345
|
box2 += chunk.toString();
|
|
27215
27346
|
});
|
|
27216
|
-
|
|
27347
|
+
p26.box(
|
|
27217
27348
|
`
|
|
27218
27349
|
\u2584 \u2597 \u2597 \u2584\u2596\u2597 \u2597
|
|
27219
27350
|
\u2599\u2598\u2588\u258C\u259C\u2598\u259C\u2598\u2588\u258C\u259B\u2598\u259A \u259C\u2598\u2580\u258C\u259B\u2598\u259C\u2598
|
|
@@ -27309,7 +27440,7 @@ async function runInitCommand(name, options) {
|
|
|
27309
27440
|
let restoreStdout;
|
|
27310
27441
|
if (options.json) {
|
|
27311
27442
|
if (!options.yes) {
|
|
27312
|
-
|
|
27443
|
+
p26.log.error("--json requires --yes.");
|
|
27313
27444
|
process.exit(1);
|
|
27314
27445
|
}
|
|
27315
27446
|
restoreStdout = redirectStdoutToStderr();
|
|
@@ -27330,7 +27461,7 @@ async function runInitCommand(name, options) {
|
|
|
27330
27461
|
}
|
|
27331
27462
|
} catch (error) {
|
|
27332
27463
|
disposeCancelGuard();
|
|
27333
|
-
|
|
27464
|
+
p26.log.error(error instanceof Error ? error.message : String(error));
|
|
27334
27465
|
process.exit(1);
|
|
27335
27466
|
}
|
|
27336
27467
|
let cwd = process.cwd();
|
|
@@ -27341,7 +27472,7 @@ async function runInitCommand(name, options) {
|
|
|
27341
27472
|
try {
|
|
27342
27473
|
namespace = validateAdminNamespace(options.namespace);
|
|
27343
27474
|
} catch (error) {
|
|
27344
|
-
|
|
27475
|
+
p26.log.error(error instanceof Error ? error.message : String(error));
|
|
27345
27476
|
process.exit(1);
|
|
27346
27477
|
}
|
|
27347
27478
|
}
|
|
@@ -27350,13 +27481,13 @@ async function runInitCommand(name, options) {
|
|
|
27350
27481
|
try {
|
|
27351
27482
|
projectPrompt = options.yes ? resolveNonInteractiveProject(name) : await promptProject(name);
|
|
27352
27483
|
} catch (error) {
|
|
27353
|
-
|
|
27484
|
+
p26.log.error(error instanceof Error ? error.message : String(error));
|
|
27354
27485
|
process.exit(1);
|
|
27355
27486
|
}
|
|
27356
27487
|
}
|
|
27357
27488
|
if (!options.yes && !options.namespace) {
|
|
27358
27489
|
const defaultDashboardPath = resolveAdminNamespace(DEFAULT_ADMIN_NAMESPACE).routePath;
|
|
27359
|
-
const namespaceInput = await
|
|
27490
|
+
const namespaceInput = await p26.text({
|
|
27360
27491
|
message: "Enter the dashboard path",
|
|
27361
27492
|
placeholder: `eg. ${defaultDashboardPath}`,
|
|
27362
27493
|
defaultValue: defaultDashboardPath,
|
|
@@ -27369,8 +27500,8 @@ async function runInitCommand(name, options) {
|
|
|
27369
27500
|
}
|
|
27370
27501
|
}
|
|
27371
27502
|
});
|
|
27372
|
-
if (
|
|
27373
|
-
|
|
27503
|
+
if (p26.isCancel(namespaceInput)) {
|
|
27504
|
+
p26.cancel("Setup cancelled.");
|
|
27374
27505
|
process.exit(0);
|
|
27375
27506
|
}
|
|
27376
27507
|
namespace = validateAdminDashboardPath(namespaceInput);
|
|
@@ -27382,13 +27513,13 @@ async function runInitCommand(name, options) {
|
|
|
27382
27513
|
if (project2.isExisting) {
|
|
27383
27514
|
srcDir = project2.hasSrcDir;
|
|
27384
27515
|
if (!project2.hasTypeScript) {
|
|
27385
|
-
|
|
27516
|
+
p26.log.error("TypeScript is required. Please add a tsconfig.json first.");
|
|
27386
27517
|
process.exit(1);
|
|
27387
27518
|
}
|
|
27388
27519
|
if (forceMode) {
|
|
27389
27520
|
const nuked = removeExistingAdminPaths(cwd, await resolveForceInitNamespaces(cwd, namespace));
|
|
27390
27521
|
if (nuked > 0) {
|
|
27391
|
-
|
|
27522
|
+
p26.log.warn(`${pc10.yellow("Force mode:")} removed ${nuked} existing admin paths`);
|
|
27392
27523
|
}
|
|
27393
27524
|
project2 = detectProject(cwd, namespace);
|
|
27394
27525
|
} else if (project2.conflicts.length > 0) {
|
|
@@ -27397,14 +27528,14 @@ async function runInitCommand(name, options) {
|
|
|
27397
27528
|
"",
|
|
27398
27529
|
pc10.dim(`Use ${pc10.bold("--force")} to remove existing admin files before scaffolding.`)
|
|
27399
27530
|
);
|
|
27400
|
-
|
|
27531
|
+
p26.note(conflictLines.join("\n"), pc10.yellow("Conflicts"));
|
|
27401
27532
|
if (options.yes) {
|
|
27402
|
-
|
|
27533
|
+
p26.log.error(
|
|
27403
27534
|
"Can't continue with --yes while admin files conflict. Re-run with --force to remove them first."
|
|
27404
27535
|
);
|
|
27405
27536
|
process.exit(1);
|
|
27406
27537
|
}
|
|
27407
|
-
const proceed = await
|
|
27538
|
+
const proceed = await p26.confirm({
|
|
27408
27539
|
message: [
|
|
27409
27540
|
`Continue with ${pc10.bold(pc10.cyan("--force"))}?`,
|
|
27410
27541
|
`${pc10.cyan("\u2502")} ${pc10.dim("This will force overwrite the existing admin code.")}`,
|
|
@@ -27412,14 +27543,14 @@ async function runInitCommand(name, options) {
|
|
|
27412
27543
|
].join("\n"),
|
|
27413
27544
|
initialValue: true
|
|
27414
27545
|
});
|
|
27415
|
-
if (
|
|
27416
|
-
|
|
27546
|
+
if (p26.isCancel(proceed) || !proceed) {
|
|
27547
|
+
p26.cancel("Setup cancelled.");
|
|
27417
27548
|
process.exit(0);
|
|
27418
27549
|
}
|
|
27419
27550
|
forceMode = true;
|
|
27420
27551
|
const nuked = removeExistingAdminPaths(cwd, await resolveForceInitNamespaces(cwd, namespace));
|
|
27421
27552
|
if (nuked > 0) {
|
|
27422
|
-
|
|
27553
|
+
p26.log.warn(`${pc10.yellow("Force mode:")} removed ${nuked} existing admin paths`);
|
|
27423
27554
|
}
|
|
27424
27555
|
project2 = detectProject(cwd, namespace);
|
|
27425
27556
|
}
|
|
@@ -27427,7 +27558,7 @@ async function runInitCommand(name, options) {
|
|
|
27427
27558
|
const freshProject = projectPrompt;
|
|
27428
27559
|
srcDir = false;
|
|
27429
27560
|
if (!options.yes) {
|
|
27430
|
-
const pmChoice = await
|
|
27561
|
+
const pmChoice = await p26.select({
|
|
27431
27562
|
message: "Which package manager do you want to use?",
|
|
27432
27563
|
options: [
|
|
27433
27564
|
{ value: "pnpm", label: "pnpm", hint: "recommended" },
|
|
@@ -27435,8 +27566,8 @@ async function runInitCommand(name, options) {
|
|
|
27435
27566
|
{ value: "bun", label: "bun" }
|
|
27436
27567
|
]
|
|
27437
27568
|
});
|
|
27438
|
-
if (
|
|
27439
|
-
|
|
27569
|
+
if (p26.isCancel(pmChoice)) {
|
|
27570
|
+
p26.cancel("Setup cancelled.");
|
|
27440
27571
|
process.exit(0);
|
|
27441
27572
|
}
|
|
27442
27573
|
pm = pmChoice;
|
|
@@ -27471,8 +27602,8 @@ async function runInitCommand(name, options) {
|
|
|
27471
27602
|
process.stderr.write(`${createNextAppResult.output.trimEnd()}
|
|
27472
27603
|
`);
|
|
27473
27604
|
}
|
|
27474
|
-
|
|
27475
|
-
|
|
27605
|
+
p26.log.error(createNextAppResult.error);
|
|
27606
|
+
p26.log.info(
|
|
27476
27607
|
`You can create the project manually:
|
|
27477
27608
|
${pc10.cyan(`npx create-next-app@latest ${freshProject.projectName} --typescript --tailwind --app`)}
|
|
27478
27609
|
Then run ${pc10.cyan("betterstart init")} inside it.`
|
|
@@ -27486,11 +27617,11 @@ async function runInitCommand(name, options) {
|
|
|
27486
27617
|
);
|
|
27487
27618
|
if (!hasPackageJson || !hasNextConfig) {
|
|
27488
27619
|
createNextAppSpinner.stop(`Failed to create Next.js app: ${displayName}`);
|
|
27489
|
-
|
|
27620
|
+
p26.log.error(
|
|
27490
27621
|
"create-next-app completed but the project was not created. This can happen with nested npx calls."
|
|
27491
27622
|
);
|
|
27492
27623
|
const manualCmd = `npx create-next-app@latest ${freshProject.projectName} --typescript --tailwind --app`;
|
|
27493
|
-
|
|
27624
|
+
p26.log.info(
|
|
27494
27625
|
`Create the project manually:
|
|
27495
27626
|
${pc10.cyan(manualCmd)}
|
|
27496
27627
|
Then run ${pc10.cyan("betterstart init")} inside it.`
|
|
@@ -27539,13 +27670,13 @@ async function runInitCommand(name, options) {
|
|
|
27539
27670
|
try {
|
|
27540
27671
|
validateResolvedDatabaseProvider(databaseProvider, options);
|
|
27541
27672
|
} catch (error) {
|
|
27542
|
-
|
|
27673
|
+
p26.log.error(error instanceof Error ? error.message : String(error));
|
|
27543
27674
|
process.exit(1);
|
|
27544
27675
|
}
|
|
27545
27676
|
if (databaseProvider === "manual") {
|
|
27546
27677
|
const candidate = options.databaseUrl ?? existingDbUrl ?? promptedManualUrl;
|
|
27547
27678
|
if (candidate && !isValidDbUrl(candidate)) {
|
|
27548
|
-
|
|
27679
|
+
p26.log.error(
|
|
27549
27680
|
`Invalid database URL. Must start with ${pc10.cyan("postgres://")} or ${pc10.cyan("postgresql://")}`
|
|
27550
27681
|
);
|
|
27551
27682
|
process.exit(1);
|
|
@@ -27553,7 +27684,7 @@ async function runInitCommand(name, options) {
|
|
|
27553
27684
|
if (candidate) {
|
|
27554
27685
|
databaseUrl = candidate;
|
|
27555
27686
|
if (existingDbUrl === candidate && !options.databaseUrl) {
|
|
27556
|
-
|
|
27687
|
+
p26.log.info(
|
|
27557
27688
|
`Using the existing DATABASE_URL from .env.local ${pc10.dim(`(${maskDbUrl(candidate)})`)}`
|
|
27558
27689
|
);
|
|
27559
27690
|
}
|
|
@@ -27573,7 +27704,7 @@ async function runInitCommand(name, options) {
|
|
|
27573
27704
|
persistDatabaseUrl(cwd, databaseUrl);
|
|
27574
27705
|
dismissVercelSignedInNote = flow.dismissSignedInNote;
|
|
27575
27706
|
} else if (options.yes) {
|
|
27576
|
-
|
|
27707
|
+
p26.log.error(
|
|
27577
27708
|
flow.ok ? "Created a Neon database, but DATABASE_URL could not be retrieved from Vercel." : "Vercel database provisioning did not complete."
|
|
27578
27709
|
);
|
|
27579
27710
|
process.exit(1);
|
|
@@ -27582,7 +27713,7 @@ async function runInitCommand(name, options) {
|
|
|
27582
27713
|
databaseUrl = await promptConnectionString();
|
|
27583
27714
|
persistDatabaseUrl(cwd, databaseUrl);
|
|
27584
27715
|
} else {
|
|
27585
|
-
|
|
27716
|
+
p26.log.info("Falling back to a manual database connection string.");
|
|
27586
27717
|
openBrowserVercelNeon();
|
|
27587
27718
|
databaseUrl = await promptConnectionString();
|
|
27588
27719
|
}
|
|
@@ -27596,11 +27727,11 @@ async function runInitCommand(name, options) {
|
|
|
27596
27727
|
} catch (error) {
|
|
27597
27728
|
const message = error instanceof Error ? error.message : String(error);
|
|
27598
27729
|
if (options.yes) {
|
|
27599
|
-
|
|
27730
|
+
p26.log.error(`Railway database provisioning failed: ${message}`);
|
|
27600
27731
|
process.exit(1);
|
|
27601
27732
|
}
|
|
27602
|
-
|
|
27603
|
-
|
|
27733
|
+
p26.log.warn(`Railway database provisioning failed: ${message}`);
|
|
27734
|
+
p26.log.info("Falling back to a manual database connection string.");
|
|
27604
27735
|
databaseUrl = await promptConnectionString();
|
|
27605
27736
|
}
|
|
27606
27737
|
}
|
|
@@ -27630,7 +27761,7 @@ async function runInitCommand(name, options) {
|
|
|
27630
27761
|
return { ok: true, config: config2 };
|
|
27631
27762
|
} catch (error) {
|
|
27632
27763
|
const message = error instanceof Error ? error.message : String(error);
|
|
27633
|
-
|
|
27764
|
+
p26.log.warn(`Railway bucket provisioning failed: ${message}`);
|
|
27634
27765
|
return { ok: false };
|
|
27635
27766
|
}
|
|
27636
27767
|
};
|
|
@@ -27644,7 +27775,7 @@ async function runInitCommand(name, options) {
|
|
|
27644
27775
|
if (storage === "r2") {
|
|
27645
27776
|
const missingR2Keys = R2_ENV_KEYS.filter((key) => !readEnvVar(cwd, key)?.trim());
|
|
27646
27777
|
if (options.yes && missingR2Keys.length > 0) {
|
|
27647
|
-
|
|
27778
|
+
p26.log.error(
|
|
27648
27779
|
`Cloudflare R2 is missing required environment variables: ${missingR2Keys.join(", ")}.`
|
|
27649
27780
|
);
|
|
27650
27781
|
process.exit(1);
|
|
@@ -27658,7 +27789,7 @@ async function runInitCommand(name, options) {
|
|
|
27658
27789
|
if (flow.ok && flow.config) {
|
|
27659
27790
|
mergeCollectedIntegrationConfig(flow.config);
|
|
27660
27791
|
} else if (options.yes) {
|
|
27661
|
-
|
|
27792
|
+
p26.log.error("Railway bucket provisioning did not complete.");
|
|
27662
27793
|
process.exit(1);
|
|
27663
27794
|
}
|
|
27664
27795
|
}
|
|
@@ -27677,10 +27808,10 @@ async function runInitCommand(name, options) {
|
|
|
27677
27808
|
});
|
|
27678
27809
|
collectedIntegrationConfig.overwriteKeys.add("BLOB_READ_WRITE_TOKEN");
|
|
27679
27810
|
} else if (options.yes) {
|
|
27680
|
-
|
|
27811
|
+
p26.log.error("Vercel Blob provisioning did not complete.");
|
|
27681
27812
|
process.exit(1);
|
|
27682
27813
|
} else {
|
|
27683
|
-
|
|
27814
|
+
p26.log.warn(
|
|
27684
27815
|
"Continuing without a Blob token \u2014 add BLOB_READ_WRITE_TOKEN to .env.local from the store on vercel.com/dashboard/stores."
|
|
27685
27816
|
);
|
|
27686
27817
|
collectedIntegrationConfig.sections.push({
|
|
@@ -27754,7 +27885,7 @@ async function runInitCommand(name, options) {
|
|
|
27754
27885
|
const nextConfigResult = scaffoldNextConfig({ cwd, nextMajorVersion });
|
|
27755
27886
|
s.clear();
|
|
27756
27887
|
if (nextConfigResult.status === "unsupported") {
|
|
27757
|
-
|
|
27888
|
+
p26.log.warn("The Next.js config could not be updated automatically \u2014 review it manually.");
|
|
27758
27889
|
}
|
|
27759
27890
|
const drizzleConfigPath = path52.join(cwd, "drizzle.config.ts");
|
|
27760
27891
|
if (!dbFiles.includes("drizzle.config.ts") && fs41.existsSync(drizzleConfigPath)) {
|
|
@@ -27765,20 +27896,20 @@ async function runInitCommand(name, options) {
|
|
|
27765
27896
|
readNamespacedTemplate("drizzle.config.ts", namespace),
|
|
27766
27897
|
"utf-8"
|
|
27767
27898
|
);
|
|
27768
|
-
|
|
27899
|
+
p26.log.success("Updated drizzle.config.ts");
|
|
27769
27900
|
} else if (!options.yes) {
|
|
27770
|
-
const overwrite = await
|
|
27901
|
+
const overwrite = await p26.confirm({
|
|
27771
27902
|
message: "drizzle.config.ts already exists. Overwrite with latest version?",
|
|
27772
27903
|
initialValue: true
|
|
27773
27904
|
});
|
|
27774
|
-
if (!
|
|
27905
|
+
if (!p26.isCancel(overwrite) && overwrite) {
|
|
27775
27906
|
const { readNamespacedTemplate } = await import("./template-reader-PVN53GS7.js");
|
|
27776
27907
|
fs41.writeFileSync(
|
|
27777
27908
|
drizzleConfigPath,
|
|
27778
27909
|
readNamespacedTemplate("drizzle.config.ts", namespace),
|
|
27779
27910
|
"utf-8"
|
|
27780
27911
|
);
|
|
27781
|
-
|
|
27912
|
+
p26.log.success("Updated drizzle.config.ts");
|
|
27782
27913
|
}
|
|
27783
27914
|
}
|
|
27784
27915
|
}
|
|
@@ -27803,8 +27934,8 @@ async function runInitCommand(name, options) {
|
|
|
27803
27934
|
s.stop("");
|
|
27804
27935
|
} else {
|
|
27805
27936
|
s.stop("Failed to install dependencies");
|
|
27806
|
-
|
|
27807
|
-
|
|
27937
|
+
p26.log.warn(depsResult.error ?? "Unknown error");
|
|
27938
|
+
p26.log.info(
|
|
27808
27939
|
`You can install them manually:
|
|
27809
27940
|
${pc10.cyan(`${pm} add ${depsResult.dependencies.join(" ")}`)}
|
|
27810
27941
|
${pc10.cyan(`${pm} add -D ${depsResult.devDeps.join(" ")}`)}`
|
|
@@ -27860,22 +27991,22 @@ async function runInitCommand(name, options) {
|
|
|
27860
27991
|
writeConfigFile(cwd, resolvedIntegrationInstallResult.config);
|
|
27861
27992
|
const usesLocalStorage = resolvedIntegrationInstallResult.config.storage.provider === "local";
|
|
27862
27993
|
for (const err of coreSchemasResult.errors) {
|
|
27863
|
-
|
|
27994
|
+
p26.log.warn(`Core schemas: ${err}`);
|
|
27864
27995
|
}
|
|
27865
27996
|
for (const warning of resolvedPresetInstallResult.warnings) {
|
|
27866
|
-
|
|
27997
|
+
p26.log.warn(warning);
|
|
27867
27998
|
}
|
|
27868
27999
|
for (const warning of resolvedIntegrationInstallResult.warnings) {
|
|
27869
|
-
|
|
28000
|
+
p26.log.warn(warning);
|
|
27870
28001
|
}
|
|
27871
28002
|
if (usesLocalStorage) {
|
|
27872
|
-
|
|
28003
|
+
p26.log.warn(
|
|
27873
28004
|
"Local filesystem storage is only for development or self-hosted persistent-disk deployments. Use Vercel Blob, Railway Bucket, or Cloudflare R2 for hosted production."
|
|
27874
28005
|
);
|
|
27875
28006
|
}
|
|
27876
28007
|
let dbPushed = false;
|
|
27877
28008
|
if (depsResult.success && options.skipMigration && hasDbUrl(cwd)) {
|
|
27878
|
-
|
|
28009
|
+
p26.log.info(`Skipping database schema push ${pc10.dim("(--skip-migration)")}`);
|
|
27879
28010
|
} else if (depsResult.success && hasDbUrl(cwd)) {
|
|
27880
28011
|
let driverReady = hasDrizzleKitPostgresDriverDependency(cwd);
|
|
27881
28012
|
if (!driverReady) {
|
|
@@ -27890,8 +28021,8 @@ async function runInitCommand(name, options) {
|
|
|
27890
28021
|
});
|
|
27891
28022
|
if (!driverResult.success) {
|
|
27892
28023
|
s.stop("Database push failed");
|
|
27893
|
-
|
|
27894
|
-
|
|
28024
|
+
p26.log.warn(driverResult.error ?? `Failed to install ${DRIZZLE_KIT_POSTGRES_DRIVER_DEP}`);
|
|
28025
|
+
p26.log.info(
|
|
27895
28026
|
`Install ${DRIZZLE_KIT_POSTGRES_DRIVER_DEP} manually, then run: ${pc10.cyan(drizzlePushCommand(pm))}`
|
|
27896
28027
|
);
|
|
27897
28028
|
} else {
|
|
@@ -27919,8 +28050,8 @@ async function runInitCommand(name, options) {
|
|
|
27919
28050
|
const verification = await verifyDatabaseReachable(cwd);
|
|
27920
28051
|
clearDbSpinner();
|
|
27921
28052
|
if (!verification.success) {
|
|
27922
|
-
|
|
27923
|
-
|
|
28053
|
+
p26.log.warn(verification.error);
|
|
28054
|
+
p26.log.error("Database was not reachable. Aborting setup.");
|
|
27924
28055
|
process.exit(1);
|
|
27925
28056
|
}
|
|
27926
28057
|
} else {
|
|
@@ -27933,12 +28064,12 @@ async function runInitCommand(name, options) {
|
|
|
27933
28064
|
s.stop("Database push failed");
|
|
27934
28065
|
}
|
|
27935
28066
|
const pushError = pushResult.error ?? "Unknown error";
|
|
27936
|
-
|
|
28067
|
+
p26.log.warn(pushError);
|
|
27937
28068
|
if (isDatabaseReachabilityError(pushError)) {
|
|
27938
|
-
|
|
28069
|
+
p26.log.error("Database was not reachable. Aborting setup.");
|
|
27939
28070
|
process.exit(1);
|
|
27940
28071
|
}
|
|
27941
|
-
|
|
28072
|
+
p26.log.info(`You can run it manually: ${pc10.cyan(drizzlePushCommand(pm))}`);
|
|
27942
28073
|
}
|
|
27943
28074
|
}
|
|
27944
28075
|
}
|
|
@@ -27947,7 +28078,7 @@ async function runInitCommand(name, options) {
|
|
|
27947
28078
|
let seedSuccess = false;
|
|
27948
28079
|
let adminAccountReady = false;
|
|
27949
28080
|
if (dbPushed && options.skipAdminCreation) {
|
|
27950
|
-
|
|
28081
|
+
p26.log.info(
|
|
27951
28082
|
`Skipping admin user creation ${pc10.dim(`(use ${betterstartExecCommand(pm, "seed")} later)`)}`
|
|
27952
28083
|
);
|
|
27953
28084
|
}
|
|
@@ -27959,14 +28090,14 @@ async function runInitCommand(name, options) {
|
|
|
27959
28090
|
const adminCheck = await checkExistingAdmin(cwd, adminDir, authBasePath);
|
|
27960
28091
|
s.clear();
|
|
27961
28092
|
if (adminCheck.error) {
|
|
27962
|
-
|
|
28093
|
+
p26.log.warn(`Could not verify existing admin account ${pc10.dim(`(${adminCheck.error})`)}`);
|
|
27963
28094
|
if (isDatabaseReachabilityError(adminCheck.error)) {
|
|
27964
|
-
|
|
28095
|
+
p26.log.error("Database was not reachable. Aborting setup.");
|
|
27965
28096
|
process.exit(1);
|
|
27966
28097
|
}
|
|
27967
28098
|
} else if (adminCheck.existingAdmin) {
|
|
27968
28099
|
const existingAdminLabel = formatAdminIdentity(adminCheck.existingAdmin);
|
|
27969
|
-
const adminAction = await
|
|
28100
|
+
const adminAction = await p26.select({
|
|
27970
28101
|
message: "Found an already existing admin account. Do you want to replace it or skip?",
|
|
27971
28102
|
options: [
|
|
27972
28103
|
{
|
|
@@ -27980,28 +28111,28 @@ async function runInitCommand(name, options) {
|
|
|
27980
28111
|
}
|
|
27981
28112
|
]
|
|
27982
28113
|
});
|
|
27983
|
-
if (
|
|
27984
|
-
|
|
28114
|
+
if (p26.isCancel(adminAction)) {
|
|
28115
|
+
p26.cancel("Setup cancelled.");
|
|
27985
28116
|
process.exit(0);
|
|
27986
28117
|
}
|
|
27987
28118
|
if (adminAction === "skip") {
|
|
27988
28119
|
adminAccountReady = true;
|
|
27989
|
-
|
|
28120
|
+
p26.log.info(`Keeping existing admin account ${pc10.dim(`(${existingAdminLabel})`)}`);
|
|
27990
28121
|
} else {
|
|
27991
28122
|
replaceExistingAdmin = true;
|
|
27992
28123
|
}
|
|
27993
28124
|
}
|
|
27994
28125
|
if (!adminAccountReady) {
|
|
27995
|
-
const credentials = await
|
|
28126
|
+
const credentials = await p26.group(
|
|
27996
28127
|
{
|
|
27997
|
-
email: () =>
|
|
28128
|
+
email: () => p26.text({
|
|
27998
28129
|
message: "Admin email",
|
|
27999
28130
|
placeholder: "admin@example.com",
|
|
28000
28131
|
validate: (v) => {
|
|
28001
28132
|
if (!v || !v.includes("@")) return "Please enter a valid email";
|
|
28002
28133
|
}
|
|
28003
28134
|
}),
|
|
28004
|
-
password: () =>
|
|
28135
|
+
password: () => p26.password({
|
|
28005
28136
|
message: "Admin password",
|
|
28006
28137
|
validate: (v) => {
|
|
28007
28138
|
if (!v || v.length < 8) return "Password must be at least 8 characters";
|
|
@@ -28010,14 +28141,14 @@ async function runInitCommand(name, options) {
|
|
|
28010
28141
|
},
|
|
28011
28142
|
{
|
|
28012
28143
|
onCancel: () => {
|
|
28013
|
-
|
|
28144
|
+
p26.cancel("Setup cancelled.");
|
|
28014
28145
|
process.exit(0);
|
|
28015
28146
|
}
|
|
28016
28147
|
}
|
|
28017
28148
|
);
|
|
28018
28149
|
seedEmail = credentials.email;
|
|
28019
28150
|
seedPassword = credentials.password;
|
|
28020
|
-
const credentialPromptRows = clackPromptRows("Admin email", credentials.email) + clackPromptRows("Admin password",
|
|
28151
|
+
const credentialPromptRows = clackPromptRows("Admin email", credentials.email) + clackPromptRows("Admin password", p26.S_PASSWORD_MASK.repeat(credentials.password.length));
|
|
28021
28152
|
let rowsBelowCredentialPrompts = 0;
|
|
28022
28153
|
let seedOverwriteMode = replaceExistingAdmin ? "admin" : void 0;
|
|
28023
28154
|
s.start(replaceExistingAdmin ? "Replacing admin user" : "Creating admin user");
|
|
@@ -28034,7 +28165,7 @@ async function runInitCommand(name, options) {
|
|
|
28034
28165
|
s.stop(existingAccountMessage);
|
|
28035
28166
|
rowsBelowCredentialPrompts += clackLogRows(existingAccountMessage);
|
|
28036
28167
|
const replaceAccountMessage = "Replace the existing account with this email?";
|
|
28037
|
-
const replace = await
|
|
28168
|
+
const replace = await p26.confirm({
|
|
28038
28169
|
message: replaceAccountMessage,
|
|
28039
28170
|
initialValue: false
|
|
28040
28171
|
});
|
|
@@ -28042,7 +28173,7 @@ async function runInitCommand(name, options) {
|
|
|
28042
28173
|
replaceAccountMessage,
|
|
28043
28174
|
replace === true ? "Yes" : "No"
|
|
28044
28175
|
);
|
|
28045
|
-
if (!
|
|
28176
|
+
if (!p26.isCancel(replace) && replace) {
|
|
28046
28177
|
seedOverwriteMode = "email";
|
|
28047
28178
|
s.start("Replacing admin user");
|
|
28048
28179
|
seedResult = await runSeed(
|
|
@@ -28064,14 +28195,14 @@ async function runInitCommand(name, options) {
|
|
|
28064
28195
|
adminAccountReady = true;
|
|
28065
28196
|
} else if (seedResult.error) {
|
|
28066
28197
|
s.stop(`Failed to create admin user`);
|
|
28067
|
-
|
|
28198
|
+
p26.note(
|
|
28068
28199
|
`${pc10.red(seedResult.error)}
|
|
28069
28200
|
|
|
28070
28201
|
Run manually: ${pc10.cyan(betterstartExecCommand(pm, "seed"))}`,
|
|
28071
28202
|
pc10.red("Seed failed")
|
|
28072
28203
|
);
|
|
28073
28204
|
if (isDatabaseReachabilityError(seedResult.error)) {
|
|
28074
|
-
|
|
28205
|
+
p26.log.error("Database was not reachable. Aborting setup.");
|
|
28075
28206
|
process.exit(1);
|
|
28076
28207
|
}
|
|
28077
28208
|
}
|
|
@@ -28080,9 +28211,9 @@ Run manually: ${pc10.cyan(betterstartExecCommand(pm, "seed"))}`,
|
|
|
28080
28211
|
if (isFreshProject) {
|
|
28081
28212
|
s.start("Creating initial git commit");
|
|
28082
28213
|
try {
|
|
28083
|
-
|
|
28084
|
-
|
|
28085
|
-
|
|
28214
|
+
execFileSync4("git", ["init"], { cwd, stdio: "pipe" });
|
|
28215
|
+
execFileSync4("git", ["add", "."], { cwd, stdio: "pipe" });
|
|
28216
|
+
execFileSync4("git", ["commit", "-m", "Initial commit from BetterStart"], {
|
|
28086
28217
|
cwd,
|
|
28087
28218
|
stdio: "pipe"
|
|
28088
28219
|
});
|
|
@@ -28113,10 +28244,10 @@ Run manually: ${pc10.cyan(betterstartExecCommand(pm, "seed"))}`,
|
|
|
28113
28244
|
deployedUrl = deployFlow.url;
|
|
28114
28245
|
if (!deployFlow.ok) {
|
|
28115
28246
|
if (options.yes) {
|
|
28116
|
-
|
|
28247
|
+
p26.log.error("Vercel deploy did not complete.");
|
|
28117
28248
|
process.exit(1);
|
|
28118
28249
|
}
|
|
28119
|
-
|
|
28250
|
+
p26.log.warn("Vercel deploy did not complete; continuing.");
|
|
28120
28251
|
}
|
|
28121
28252
|
} else if (deployProvider === "railway") {
|
|
28122
28253
|
try {
|
|
@@ -28134,29 +28265,29 @@ Run manually: ${pc10.cyan(betterstartExecCommand(pm, "seed"))}`,
|
|
|
28134
28265
|
});
|
|
28135
28266
|
deployedUrl = deployFlow.url;
|
|
28136
28267
|
if (!deployFlow.ok) {
|
|
28137
|
-
if (deployFlow.detail)
|
|
28268
|
+
if (deployFlow.detail) p26.log.message(pc10.dim(redactSecrets(deployFlow.detail)));
|
|
28138
28269
|
if (options.yes) {
|
|
28139
|
-
|
|
28270
|
+
p26.log.error("Railway deploy did not complete.");
|
|
28140
28271
|
process.exit(1);
|
|
28141
28272
|
}
|
|
28142
|
-
|
|
28273
|
+
p26.log.warn("Railway deploy did not complete; continuing.");
|
|
28143
28274
|
}
|
|
28144
28275
|
} catch (error) {
|
|
28145
28276
|
const message = error instanceof Error ? error.message : String(error);
|
|
28146
28277
|
if (options.yes) {
|
|
28147
|
-
|
|
28278
|
+
p26.log.error(`Railway deploy failed: ${message}`);
|
|
28148
28279
|
process.exit(1);
|
|
28149
28280
|
}
|
|
28150
|
-
|
|
28281
|
+
p26.log.warn(`Railway deploy failed: ${message}`);
|
|
28151
28282
|
}
|
|
28152
28283
|
}
|
|
28153
28284
|
if (!options.yes && !options.skipDevServerStart) {
|
|
28154
28285
|
const devCmd = runCommand(pm, "dev");
|
|
28155
|
-
const startDev = await
|
|
28286
|
+
const startDev = await p26.confirm({
|
|
28156
28287
|
message: "Start the development server?",
|
|
28157
28288
|
initialValue: true
|
|
28158
28289
|
});
|
|
28159
|
-
if (!
|
|
28290
|
+
if (!p26.isCancel(startDev) && startDev) {
|
|
28160
28291
|
disposeCancelGuard();
|
|
28161
28292
|
await startManagedDevServer(cwd, devCmd, adminLoginUrl, {
|
|
28162
28293
|
email: seedSuccess && seedEmail ? seedEmail : void 0,
|
|
@@ -28188,7 +28319,7 @@ Run manually: ${pc10.cyan(betterstartExecCommand(pm, "seed"))}`,
|
|
|
28188
28319
|
);
|
|
28189
28320
|
return;
|
|
28190
28321
|
}
|
|
28191
|
-
|
|
28322
|
+
p26.outro(`Admin ready at ${adminNamespace.routePath}`);
|
|
28192
28323
|
}
|
|
28193
28324
|
function isValidDbUrl(url) {
|
|
28194
28325
|
return url.startsWith("postgres://") || url.startsWith("postgresql://");
|
|
@@ -28581,7 +28712,7 @@ function printAdminReadyNote(state) {
|
|
|
28581
28712
|
} else if (state.adminEmail) {
|
|
28582
28713
|
lines.unshift(`Admin user: ${pc10.cyan(state.adminEmail)}`);
|
|
28583
28714
|
}
|
|
28584
|
-
|
|
28715
|
+
p26.note(lines.join("\n"), "Admin ready");
|
|
28585
28716
|
}
|
|
28586
28717
|
function shouldSuppressDevServerStartupLine(line) {
|
|
28587
28718
|
const plain = stripAnsi2(line).trim();
|
|
@@ -28693,7 +28824,7 @@ function startManagedDevServer(cwd, devCmd, adminLoginUrl, adminCredentials) {
|
|
|
28693
28824
|
|
|
28694
28825
|
// adapters/next/commands/list-integrations.ts
|
|
28695
28826
|
import path53 from "path";
|
|
28696
|
-
import * as
|
|
28827
|
+
import * as p27 from "@clack/prompts";
|
|
28697
28828
|
|
|
28698
28829
|
// core-engine/utils/table.ts
|
|
28699
28830
|
function renderTableRows(rows) {
|
|
@@ -28740,15 +28871,15 @@ async function runListIntegrationsCommand(options) {
|
|
|
28740
28871
|
integration.kind,
|
|
28741
28872
|
integration.description
|
|
28742
28873
|
]);
|
|
28743
|
-
|
|
28744
|
-
|
|
28874
|
+
p27.note(renderTableRows(rows).join("\n"), "BetterStart integrations");
|
|
28875
|
+
p27.outro(
|
|
28745
28876
|
`${installedIntegrations.size} installed, ${rows.length - installedIntegrations.size} available`
|
|
28746
28877
|
);
|
|
28747
28878
|
}
|
|
28748
28879
|
|
|
28749
28880
|
// adapters/next/commands/list-presets.ts
|
|
28750
28881
|
import path54 from "path";
|
|
28751
|
-
import * as
|
|
28882
|
+
import * as p28 from "@clack/prompts";
|
|
28752
28883
|
async function runListPresetsCommand(options) {
|
|
28753
28884
|
const cwd = options.cwd ? path54.resolve(options.cwd) : process.cwd();
|
|
28754
28885
|
if (options.json) {
|
|
@@ -28778,48 +28909,73 @@ async function runListPresetsCommand(options) {
|
|
|
28778
28909
|
preset.kind,
|
|
28779
28910
|
preset.description
|
|
28780
28911
|
]);
|
|
28781
|
-
|
|
28782
|
-
|
|
28912
|
+
p28.note(renderTableRows(rows).join("\n"), "BetterStart presets");
|
|
28913
|
+
p28.outro(`${installedPresets.size} installed, ${rows.length - installedPresets.size} available`);
|
|
28783
28914
|
}
|
|
28784
28915
|
|
|
28785
|
-
// adapters/next/commands/
|
|
28916
|
+
// adapters/next/commands/menu-choices.ts
|
|
28786
28917
|
import path55 from "path";
|
|
28787
|
-
|
|
28918
|
+
async function listInstallableChoices(cwd) {
|
|
28919
|
+
const config = await resolveConfigOrExit(cwd);
|
|
28920
|
+
const installedPresets = new Set(config.presets.installed);
|
|
28921
|
+
const installedIntegrations = new Set(config.integrations.installed);
|
|
28922
|
+
return {
|
|
28923
|
+
presets: listAvailablePresets().map((preset) => ({
|
|
28924
|
+
id: preset.id,
|
|
28925
|
+
description: preset.description,
|
|
28926
|
+
installed: installedPresets.has(preset.id)
|
|
28927
|
+
})),
|
|
28928
|
+
integrations: listAvailableIntegrations().map((integration) => ({
|
|
28929
|
+
id: integration.id,
|
|
28930
|
+
description: integration.description,
|
|
28931
|
+
installed: installedIntegrations.has(integration.id)
|
|
28932
|
+
}))
|
|
28933
|
+
};
|
|
28934
|
+
}
|
|
28935
|
+
async function listSchemaChoices(cwd) {
|
|
28936
|
+
const config = await resolveConfigOrExit(cwd);
|
|
28937
|
+
const paths = resolveProjectPaths(config);
|
|
28938
|
+
return listSchemaNames(path55.join(cwd, ...paths.schemasDir.split("/")));
|
|
28939
|
+
}
|
|
28940
|
+
|
|
28941
|
+
// adapters/next/commands/remove.ts
|
|
28942
|
+
import path56 from "path";
|
|
28943
|
+
import * as p29 from "@clack/prompts";
|
|
28788
28944
|
async function runRemoveCommand(items, options) {
|
|
28789
28945
|
const removeIntegrationsMode = Boolean(options.integration);
|
|
28790
28946
|
if (!removeIntegrationsMode && items.includes("core")) {
|
|
28791
|
-
|
|
28947
|
+
p29.log.error("The core Admin cannot be removed.");
|
|
28792
28948
|
process.exit(1);
|
|
28793
28949
|
}
|
|
28794
28950
|
const presetIds = items.filter(isPresetId);
|
|
28795
28951
|
const integrationIds = items.filter(isIntegrationId);
|
|
28796
28952
|
if (!removeIntegrationsMode && integrationIds.length > 0) {
|
|
28797
|
-
|
|
28953
|
+
p29.log.error(
|
|
28798
28954
|
`Integration IDs require --integration. Run \`betterstart remove --integration ${integrationIds.join(" ")}\`.`
|
|
28799
28955
|
);
|
|
28800
28956
|
process.exit(1);
|
|
28801
28957
|
}
|
|
28802
28958
|
if (removeIntegrationsMode && presetIds.length > 0) {
|
|
28803
|
-
|
|
28959
|
+
p29.log.error(`Preset IDs cannot be removed with --integration: ${presetIds.join(", ")}`);
|
|
28804
28960
|
process.exit(1);
|
|
28805
28961
|
}
|
|
28806
28962
|
const invalidItems = removeIntegrationsMode ? items.filter((integrationId) => !isIntegrationId(integrationId)) : items.filter((presetId) => !isPresetId(presetId));
|
|
28807
28963
|
if (invalidItems.length > 0) {
|
|
28808
|
-
|
|
28964
|
+
p29.log.error(
|
|
28809
28965
|
removeIntegrationsMode ? formatUnknownIntegrationMessage(invalidItems) : formatUnknownPresetMessage(invalidItems)
|
|
28810
28966
|
);
|
|
28811
28967
|
process.exit(1);
|
|
28812
28968
|
}
|
|
28813
|
-
const cwd = options.cwd ?
|
|
28969
|
+
const cwd = options.cwd ? path56.resolve(options.cwd) : process.cwd();
|
|
28814
28970
|
const config = await resolveConfigOrExit(cwd);
|
|
28815
28971
|
const pm = detectPackageManager(cwd);
|
|
28816
28972
|
if (!options.force) {
|
|
28817
|
-
const confirmed = await
|
|
28973
|
+
const confirmed = await p29.confirm({
|
|
28818
28974
|
message: `Remove ${removeIntegrationsMode ? "integration" : "preset"}${items.length === 1 ? "" : "s"} ${items.join(", ")}?`,
|
|
28819
28975
|
initialValue: false
|
|
28820
28976
|
});
|
|
28821
|
-
if (
|
|
28822
|
-
|
|
28977
|
+
if (p29.isCancel(confirmed) || !confirmed) {
|
|
28978
|
+
p29.cancel(`${removeIntegrationsMode ? "Integration" : "Preset"} removal cancelled.`);
|
|
28823
28979
|
process.exit(0);
|
|
28824
28980
|
}
|
|
28825
28981
|
}
|
|
@@ -28832,13 +28988,13 @@ async function runRemoveCommand(items, options) {
|
|
|
28832
28988
|
});
|
|
28833
28989
|
writeConfigFile(cwd, result2.config);
|
|
28834
28990
|
if (result2.removed.length === 0) {
|
|
28835
|
-
|
|
28991
|
+
p29.outro("No integrations were removed.");
|
|
28836
28992
|
return;
|
|
28837
28993
|
}
|
|
28838
28994
|
if (result2.warnings.length > 0) {
|
|
28839
|
-
|
|
28995
|
+
p29.note(result2.warnings.join("\n"), "Warnings");
|
|
28840
28996
|
}
|
|
28841
|
-
|
|
28997
|
+
p29.outro(
|
|
28842
28998
|
`Removed integration${result2.removed.length === 1 ? "" : "s"}: ${result2.removed.join(", ")}`
|
|
28843
28999
|
);
|
|
28844
29000
|
return;
|
|
@@ -28851,37 +29007,37 @@ async function runRemoveCommand(items, options) {
|
|
|
28851
29007
|
});
|
|
28852
29008
|
writeConfigFile(cwd, result.config);
|
|
28853
29009
|
if (result.removed.length === 0) {
|
|
28854
|
-
|
|
29010
|
+
p29.outro("No presets were removed.");
|
|
28855
29011
|
return;
|
|
28856
29012
|
}
|
|
28857
29013
|
if (result.warnings.length > 0) {
|
|
28858
|
-
|
|
29014
|
+
p29.note(result.warnings.join("\n"), "Warnings");
|
|
28859
29015
|
}
|
|
28860
|
-
|
|
29016
|
+
p29.outro(`Removed preset${result.removed.length === 1 ? "" : "s"}: ${result.removed.join(", ")}`);
|
|
28861
29017
|
}
|
|
28862
29018
|
|
|
28863
29019
|
// adapters/next/commands/remove-schema.ts
|
|
28864
29020
|
import fs42 from "fs";
|
|
28865
|
-
import
|
|
29021
|
+
import path57 from "path";
|
|
28866
29022
|
import * as clack3 from "@clack/prompts";
|
|
28867
29023
|
function removePath2(cwd, filePath) {
|
|
28868
|
-
const fullPath =
|
|
29024
|
+
const fullPath = path57.join(cwd, ...filePath.split("/"));
|
|
28869
29025
|
const existed = fs42.existsSync(fullPath);
|
|
28870
29026
|
fs42.rmSync(fullPath, { recursive: true, force: true });
|
|
28871
29027
|
return existed;
|
|
28872
29028
|
}
|
|
28873
29029
|
function cleanupEmptyDirs3(cwd, deletedPaths, configPaths) {
|
|
28874
29030
|
const stopRoots = /* @__PURE__ */ new Set([
|
|
28875
|
-
|
|
28876
|
-
|
|
28877
|
-
|
|
28878
|
-
|
|
29031
|
+
path57.join(cwd, ...configPaths.adminDir.split("/")),
|
|
29032
|
+
path57.join(cwd, ...configPaths.adminNavigationDir.split("/")),
|
|
29033
|
+
path57.join(cwd, ...configPaths.adminWebhookEventsDir.split("/")),
|
|
29034
|
+
path57.join(cwd, ...configPaths.pagesDir.split("/"))
|
|
28879
29035
|
]);
|
|
28880
29036
|
for (const deletedPath of deletedPaths) {
|
|
28881
|
-
let current =
|
|
29037
|
+
let current = path57.dirname(path57.join(cwd, ...deletedPath.split("/")));
|
|
28882
29038
|
while (!stopRoots.has(current)) {
|
|
28883
29039
|
if (!fs42.existsSync(current)) {
|
|
28884
|
-
current =
|
|
29040
|
+
current = path57.dirname(current);
|
|
28885
29041
|
continue;
|
|
28886
29042
|
}
|
|
28887
29043
|
const entries = fs42.readdirSync(current);
|
|
@@ -28889,7 +29045,7 @@ function cleanupEmptyDirs3(cwd, deletedPaths, configPaths) {
|
|
|
28889
29045
|
break;
|
|
28890
29046
|
}
|
|
28891
29047
|
fs42.rmdirSync(current);
|
|
28892
|
-
current =
|
|
29048
|
+
current = path57.dirname(current);
|
|
28893
29049
|
}
|
|
28894
29050
|
}
|
|
28895
29051
|
}
|
|
@@ -28905,7 +29061,7 @@ function resolveSchemaOwnerForRemoval(cwd, schemaName) {
|
|
|
28905
29061
|
}
|
|
28906
29062
|
async function runRemoveSchemaCommand(schemaName, options) {
|
|
28907
29063
|
const owner = resolveSchemaOwnerForRemoval(
|
|
28908
|
-
options.cwd ?
|
|
29064
|
+
options.cwd ? path57.resolve(options.cwd) : process.cwd(),
|
|
28909
29065
|
schemaName
|
|
28910
29066
|
);
|
|
28911
29067
|
if (owner === "core") {
|
|
@@ -28918,7 +29074,7 @@ async function runRemoveSchemaCommand(schemaName, options) {
|
|
|
28918
29074
|
clack3.log.error(`"${schemaName}" is owned by ${owner}. Remove the owning preset instead.`);
|
|
28919
29075
|
process.exit(1);
|
|
28920
29076
|
}
|
|
28921
|
-
const cwd = options.cwd ?
|
|
29077
|
+
const cwd = options.cwd ? path57.resolve(options.cwd) : process.cwd();
|
|
28922
29078
|
const config = await resolveConfigOrExit(cwd);
|
|
28923
29079
|
const paths = resolveProjectPaths(config);
|
|
28924
29080
|
const manifest = loadManifest(cwd, schemaName);
|
|
@@ -28931,7 +29087,7 @@ async function runRemoveSchemaCommand(schemaName, options) {
|
|
|
28931
29087
|
process.exit(1);
|
|
28932
29088
|
}
|
|
28933
29089
|
if (!options.force) {
|
|
28934
|
-
if (!
|
|
29090
|
+
if (!isInteractiveSession()) {
|
|
28935
29091
|
clack3.log.error(
|
|
28936
29092
|
`Removing generated files for ${schemaName} needs confirmation. Re-run with --force.`
|
|
28937
29093
|
);
|
|
@@ -28954,7 +29110,7 @@ async function runRemoveSchemaCommand(schemaName, options) {
|
|
|
28954
29110
|
}
|
|
28955
29111
|
const loaded = (() => {
|
|
28956
29112
|
try {
|
|
28957
|
-
return loadSchema(
|
|
29113
|
+
return loadSchema(path57.join(cwd, ...paths.schemasDir.split("/")), schemaName);
|
|
28958
29114
|
} catch {
|
|
28959
29115
|
return null;
|
|
28960
29116
|
}
|
|
@@ -28999,8 +29155,8 @@ Schema JSON preserved.`
|
|
|
28999
29155
|
|
|
29000
29156
|
// adapters/next/commands/uninstall.ts
|
|
29001
29157
|
import fs44 from "fs";
|
|
29002
|
-
import
|
|
29003
|
-
import * as
|
|
29158
|
+
import path58 from "path";
|
|
29159
|
+
import * as p30 from "@clack/prompts";
|
|
29004
29160
|
import pc11 from "picocolors";
|
|
29005
29161
|
|
|
29006
29162
|
// adapters/next/commands/uninstall-cleaners.ts
|
|
@@ -29149,7 +29305,7 @@ function findMainCss2(cwd) {
|
|
|
29149
29305
|
"globals.css"
|
|
29150
29306
|
];
|
|
29151
29307
|
for (const candidate of candidates) {
|
|
29152
|
-
const filePath =
|
|
29308
|
+
const filePath = path58.join(cwd, candidate);
|
|
29153
29309
|
if (fs44.existsSync(filePath)) return filePath;
|
|
29154
29310
|
}
|
|
29155
29311
|
return void 0;
|
|
@@ -29166,13 +29322,13 @@ function isCLICreatedBiome(biomePath) {
|
|
|
29166
29322
|
function buildUninstallPlan(cwd, namespaceValue) {
|
|
29167
29323
|
const steps = [];
|
|
29168
29324
|
const namespace = resolveAdminNamespace(namespaceValue);
|
|
29169
|
-
const hasSrc = fs44.existsSync(
|
|
29325
|
+
const hasSrc = fs44.existsSync(path58.join(cwd, "src"));
|
|
29170
29326
|
const appBase = hasSrc ? "src/app" : "app";
|
|
29171
29327
|
const dirs = [];
|
|
29172
|
-
const adminDir =
|
|
29173
|
-
const legacyAdminDir =
|
|
29174
|
-
const adminRouteGroup =
|
|
29175
|
-
const legacyAdminRouteGroup =
|
|
29328
|
+
const adminDir = path58.join(cwd, namespace.segment);
|
|
29329
|
+
const legacyAdminDir = path58.join(cwd, "admin");
|
|
29330
|
+
const adminRouteGroup = path58.join(cwd, appBase, namespace.routeGroup);
|
|
29331
|
+
const legacyAdminRouteGroup = path58.join(cwd, appBase, "(admin)");
|
|
29176
29332
|
if (fs44.existsSync(adminDir)) dirs.push(`${namespace.segment}/`);
|
|
29177
29333
|
if (namespace.segment !== "admin" && fs44.existsSync(legacyAdminDir)) dirs.push("admin/");
|
|
29178
29334
|
if (fs44.existsSync(adminRouteGroup)) dirs.push(`${appBase}/${namespace.routeGroup}/`);
|
|
@@ -29200,9 +29356,9 @@ function buildUninstallPlan(cwd, namespaceValue) {
|
|
|
29200
29356
|
const configFiles = [];
|
|
29201
29357
|
const configPaths = [];
|
|
29202
29358
|
const candidates = [
|
|
29203
|
-
[CONFIG_FILE_NAME,
|
|
29204
|
-
["drizzle.config.ts",
|
|
29205
|
-
["ADMIN.md",
|
|
29359
|
+
[CONFIG_FILE_NAME, path58.join(cwd, CONFIG_FILE_NAME)],
|
|
29360
|
+
["drizzle.config.ts", path58.join(cwd, "drizzle.config.ts")],
|
|
29361
|
+
["ADMIN.md", path58.join(cwd, "ADMIN.md")]
|
|
29206
29362
|
];
|
|
29207
29363
|
for (const [label, fullPath] of candidates) {
|
|
29208
29364
|
if (fs44.existsSync(fullPath)) {
|
|
@@ -29210,7 +29366,7 @@ function buildUninstallPlan(cwd, namespaceValue) {
|
|
|
29210
29366
|
configPaths.push(fullPath);
|
|
29211
29367
|
}
|
|
29212
29368
|
}
|
|
29213
|
-
const biomePath =
|
|
29369
|
+
const biomePath = path58.join(cwd, "biome.json");
|
|
29214
29370
|
if (isCLICreatedBiome(biomePath)) {
|
|
29215
29371
|
configFiles.push("biome.json (CLI-created)");
|
|
29216
29372
|
configPaths.push(biomePath);
|
|
@@ -29222,13 +29378,13 @@ function buildUninstallPlan(cwd, namespaceValue) {
|
|
|
29222
29378
|
count: configFiles.length,
|
|
29223
29379
|
unit: configFiles.length === 1 ? "file" : "files",
|
|
29224
29380
|
execute() {
|
|
29225
|
-
for (const
|
|
29226
|
-
if (fs44.existsSync(
|
|
29381
|
+
for (const p32 of configPaths) {
|
|
29382
|
+
if (fs44.existsSync(p32)) fs44.unlinkSync(p32);
|
|
29227
29383
|
}
|
|
29228
29384
|
}
|
|
29229
29385
|
});
|
|
29230
29386
|
}
|
|
29231
|
-
const tsconfigPath =
|
|
29387
|
+
const tsconfigPath = path58.join(cwd, "tsconfig.json");
|
|
29232
29388
|
if (fs44.existsSync(tsconfigPath)) {
|
|
29233
29389
|
const content = fs44.readFileSync(tsconfigPath, "utf-8");
|
|
29234
29390
|
const aliasMatches = [
|
|
@@ -29255,7 +29411,7 @@ function buildUninstallPlan(cwd, namespaceValue) {
|
|
|
29255
29411
|
(l) => new RegExp(`^@source\\s+"[^"]*(?:admin|${namespace.segment})[^"]*";\\s*$`).test(l)
|
|
29256
29412
|
);
|
|
29257
29413
|
if (sourceLines.length > 0) {
|
|
29258
|
-
const relCss =
|
|
29414
|
+
const relCss = path58.relative(cwd, cssFile);
|
|
29259
29415
|
steps.push({
|
|
29260
29416
|
label: `CSS @source lines (${relCss})`,
|
|
29261
29417
|
items: [`@source lines in ${relCss}`],
|
|
@@ -29267,7 +29423,7 @@ function buildUninstallPlan(cwd, namespaceValue) {
|
|
|
29267
29423
|
});
|
|
29268
29424
|
}
|
|
29269
29425
|
}
|
|
29270
|
-
const envPath =
|
|
29426
|
+
const envPath = path58.join(cwd, ".env.local");
|
|
29271
29427
|
if (fs44.existsSync(envPath)) {
|
|
29272
29428
|
const envContent = fs44.readFileSync(envPath, "utf-8");
|
|
29273
29429
|
const bsVars = envContent.split("\n").filter((l) => l.trim().match(/^BETTERSTART_\w+=/)).map((l) => l.split("=")[0]);
|
|
@@ -29286,8 +29442,8 @@ function buildUninstallPlan(cwd, namespaceValue) {
|
|
|
29286
29442
|
return steps;
|
|
29287
29443
|
}
|
|
29288
29444
|
async function runUninstallCommand(options) {
|
|
29289
|
-
const cwd = options.cwd ?
|
|
29290
|
-
|
|
29445
|
+
const cwd = options.cwd ? path58.resolve(options.cwd) : process.cwd();
|
|
29446
|
+
p30.intro(pc11.bgRed(pc11.white(" BetterStart Uninstall ")));
|
|
29291
29447
|
let namespace = DEFAULT_ADMIN_NAMESPACE;
|
|
29292
29448
|
try {
|
|
29293
29449
|
const config = await resolveConfig(cwd);
|
|
@@ -29296,8 +29452,8 @@ async function runUninstallCommand(options) {
|
|
|
29296
29452
|
}
|
|
29297
29453
|
const steps = buildUninstallPlan(cwd, namespace);
|
|
29298
29454
|
if (steps.length === 0) {
|
|
29299
|
-
|
|
29300
|
-
|
|
29455
|
+
p30.log.success(`${pc11.green("\u2713")} Nothing to remove \u2014 project is already clean.`);
|
|
29456
|
+
p30.outro("Project already clean");
|
|
29301
29457
|
return;
|
|
29302
29458
|
}
|
|
29303
29459
|
const planLines = steps.map((step) => {
|
|
@@ -29305,14 +29461,14 @@ async function runUninstallCommand(options) {
|
|
|
29305
29461
|
const countLabel = pc11.dim(`${step.count} ${step.unit}`);
|
|
29306
29462
|
return `${pc11.red("\u2717")} ${names} ${countLabel}`;
|
|
29307
29463
|
});
|
|
29308
|
-
|
|
29464
|
+
p30.note(planLines.join("\n"), "Uninstall plan");
|
|
29309
29465
|
if (!options.force) {
|
|
29310
|
-
const confirmed = await
|
|
29466
|
+
const confirmed = await p30.confirm({
|
|
29311
29467
|
message: "Proceed with uninstall?",
|
|
29312
29468
|
initialValue: false
|
|
29313
29469
|
});
|
|
29314
|
-
if (
|
|
29315
|
-
|
|
29470
|
+
if (p30.isCancel(confirmed) || !confirmed) {
|
|
29471
|
+
p30.cancel("Uninstall cancelled.");
|
|
29316
29472
|
process.exit(0);
|
|
29317
29473
|
}
|
|
29318
29474
|
}
|
|
@@ -29324,14 +29480,14 @@ async function runUninstallCommand(options) {
|
|
|
29324
29480
|
}
|
|
29325
29481
|
const parts = steps.map((step) => `${step.count} ${step.unit}`);
|
|
29326
29482
|
s.stop(`Removed ${parts.join(", ")}`);
|
|
29327
|
-
|
|
29328
|
-
|
|
29483
|
+
p30.note(pc11.dim("Database tables were NOT dropped \u2014 drop them manually if needed."), "Next steps");
|
|
29484
|
+
p30.outro("Uninstall complete");
|
|
29329
29485
|
}
|
|
29330
29486
|
|
|
29331
29487
|
// adapters/next/commands/update-component.ts
|
|
29332
|
-
import { execFileSync as
|
|
29488
|
+
import { execFileSync as execFileSync5 } from "child_process";
|
|
29333
29489
|
import fs45 from "fs";
|
|
29334
|
-
import
|
|
29490
|
+
import path59 from "path";
|
|
29335
29491
|
import * as clack4 from "@clack/prompts";
|
|
29336
29492
|
import fsExtra from "fs-extra";
|
|
29337
29493
|
var STATIC_CUSTOM_DEPENDENCIES = {
|
|
@@ -29592,14 +29748,14 @@ function copyNamespacedDirectory(srcDir, destDir, namespace) {
|
|
|
29592
29748
|
const entries = fs45.readdirSync(srcDir, { withFileTypes: true });
|
|
29593
29749
|
for (const entry of entries) {
|
|
29594
29750
|
const namespacedName = applyAdminNamespaceToPath(entry.name, namespace);
|
|
29595
|
-
const srcPath =
|
|
29596
|
-
const destPath =
|
|
29751
|
+
const srcPath = path59.join(srcDir, entry.name);
|
|
29752
|
+
const destPath = path59.join(destDir, namespacedName);
|
|
29597
29753
|
if (entry.isDirectory()) {
|
|
29598
29754
|
fsExtra.ensureDirSync(destPath);
|
|
29599
29755
|
copyNamespacedDirectory(srcPath, destPath, namespace);
|
|
29600
29756
|
continue;
|
|
29601
29757
|
}
|
|
29602
|
-
fsExtra.ensureDirSync(
|
|
29758
|
+
fsExtra.ensureDirSync(path59.dirname(destPath));
|
|
29603
29759
|
writeNamespacedFile(srcPath, destPath, namespace);
|
|
29604
29760
|
}
|
|
29605
29761
|
}
|
|
@@ -29610,7 +29766,7 @@ function hasIntegration(config, integrationId) {
|
|
|
29610
29766
|
return config.integrations.installed.includes(integrationId);
|
|
29611
29767
|
}
|
|
29612
29768
|
function readProjectPackageJson2(cwd) {
|
|
29613
|
-
const pkgPath =
|
|
29769
|
+
const pkgPath = path59.join(cwd, "package.json");
|
|
29614
29770
|
if (!fs45.existsSync(pkgPath)) return null;
|
|
29615
29771
|
try {
|
|
29616
29772
|
return JSON.parse(fs45.readFileSync(pkgPath, "utf-8"));
|
|
@@ -31146,12 +31302,12 @@ function getStaticAssetComponentEntries(assetDirectory) {
|
|
|
31146
31302
|
continue;
|
|
31147
31303
|
}
|
|
31148
31304
|
const indexFile = ["index.tsx", "index.ts"].find(
|
|
31149
|
-
(file) => fs45.existsSync(
|
|
31305
|
+
(file) => fs45.existsSync(path59.join(assetDir, entry.name, file))
|
|
31150
31306
|
);
|
|
31151
31307
|
if (indexFile) {
|
|
31152
31308
|
components.push({
|
|
31153
31309
|
name: entry.name,
|
|
31154
|
-
file:
|
|
31310
|
+
file: path59.join(entry.name, indexFile)
|
|
31155
31311
|
});
|
|
31156
31312
|
}
|
|
31157
31313
|
}
|
|
@@ -31160,20 +31316,20 @@ function getStaticAssetComponentEntries(assetDirectory) {
|
|
|
31160
31316
|
function findStaticAssetFile(assetDir, componentName) {
|
|
31161
31317
|
if (!fs45.existsSync(assetDir)) return void 0;
|
|
31162
31318
|
const isNestedComponentName = /[\\/]/.test(componentName);
|
|
31163
|
-
const nestedComponentName = componentName.split(/[\\/]/).filter(Boolean).join(
|
|
31164
|
-
if (isNestedComponentName && nestedComponentName && !
|
|
31319
|
+
const nestedComponentName = componentName.split(/[\\/]/).filter(Boolean).join(path59.sep);
|
|
31320
|
+
if (isNestedComponentName && nestedComponentName && !path59.isAbsolute(componentName) && !nestedComponentName.split(path59.sep).includes("..")) {
|
|
31165
31321
|
for (const extension of [".tsx", ".ts"]) {
|
|
31166
31322
|
const relPath = `${nestedComponentName}${extension}`;
|
|
31167
|
-
const filePath =
|
|
31323
|
+
const filePath = path59.join(assetDir, relPath);
|
|
31168
31324
|
if (fs45.existsSync(filePath) && fs45.statSync(filePath).isFile()) {
|
|
31169
31325
|
return relPath;
|
|
31170
31326
|
}
|
|
31171
31327
|
}
|
|
31172
31328
|
}
|
|
31173
|
-
if (!isNestedComponentName && !componentName.includes("..") && !
|
|
31329
|
+
if (!isNestedComponentName && !componentName.includes("..") && !path59.isAbsolute(componentName)) {
|
|
31174
31330
|
for (const extension of [".tsx", ".ts"]) {
|
|
31175
|
-
const relPath =
|
|
31176
|
-
const filePath =
|
|
31331
|
+
const relPath = path59.join(componentName, `index${extension}`);
|
|
31332
|
+
const filePath = path59.join(assetDir, relPath);
|
|
31177
31333
|
if (fs45.existsSync(filePath) && fs45.statSync(filePath).isFile()) {
|
|
31178
31334
|
return relPath;
|
|
31179
31335
|
}
|
|
@@ -31198,7 +31354,7 @@ function getAllComponentNamesForConfig(config) {
|
|
|
31198
31354
|
return [.../* @__PURE__ */ new Set([...staticUi, ...staticCustom, ...templateKeys, "tiptap"])].sort();
|
|
31199
31355
|
}
|
|
31200
31356
|
async function runUpdateCommand(components, options) {
|
|
31201
|
-
const cwd = options.cwd ?
|
|
31357
|
+
const cwd = options.cwd ? path59.resolve(options.cwd) : process.cwd();
|
|
31202
31358
|
const normalizedOnly = normalizeShadcnPresetOnly(options.only);
|
|
31203
31359
|
validateShadcnPresetOptions(components, options);
|
|
31204
31360
|
if (options.json && !options.list) {
|
|
@@ -31259,7 +31415,7 @@ async function runUpdateCommand(components, options) {
|
|
|
31259
31415
|
return;
|
|
31260
31416
|
}
|
|
31261
31417
|
const config = await resolveConfigOrExit(cwd);
|
|
31262
|
-
const admin =
|
|
31418
|
+
const admin = path59.resolve(cwd, config.paths.admin);
|
|
31263
31419
|
if (!fs45.existsSync(admin)) {
|
|
31264
31420
|
clack4.cancel(
|
|
31265
31421
|
`Admin directory not found at ${config.paths.admin}. Run 'betterstart init' first.`
|
|
@@ -31314,7 +31470,7 @@ async function runUpdateCommand(components, options) {
|
|
|
31314
31470
|
}
|
|
31315
31471
|
const { relPath, content } = applyNamespaceToTemplateEntry(entry, config, cwd);
|
|
31316
31472
|
const baseDir = entry.base === "cwd" ? cwd : admin;
|
|
31317
|
-
const destPath =
|
|
31473
|
+
const destPath = path59.join(baseDir, relPath);
|
|
31318
31474
|
if (entry.preserveExisting && fs45.existsSync(destPath)) {
|
|
31319
31475
|
clack4.log.info(`Preserved ${relPath}`);
|
|
31320
31476
|
updatedTemplateNames.add(name);
|
|
@@ -31324,7 +31480,7 @@ async function runUpdateCommand(components, options) {
|
|
|
31324
31480
|
pendingWrites.push({
|
|
31325
31481
|
displayPath: relPath,
|
|
31326
31482
|
write: () => {
|
|
31327
|
-
fsExtra.ensureDirSync(
|
|
31483
|
+
fsExtra.ensureDirSync(path59.dirname(destPath));
|
|
31328
31484
|
fs45.writeFileSync(destPath, content, "utf-8");
|
|
31329
31485
|
clack4.log.success(`Updated ${relPath}`);
|
|
31330
31486
|
}
|
|
@@ -31356,20 +31512,20 @@ async function runUpdateCommand(components, options) {
|
|
|
31356
31512
|
}
|
|
31357
31513
|
const namespace = config.frameworkConfig.next.namespace;
|
|
31358
31514
|
const namespacedAssetFile = applyAdminNamespaceToPath(assetFile, namespace);
|
|
31359
|
-
const destPath =
|
|
31515
|
+
const destPath = path59.join(admin, "components", assetDirectory, namespacedAssetFile);
|
|
31360
31516
|
pendingWrites.push({
|
|
31361
31517
|
displayPath: `components/${assetDirectory}/${namespacedAssetFile}`,
|
|
31362
31518
|
write: () => {
|
|
31363
|
-
fsExtra.ensureDirSync(
|
|
31364
|
-
writeNamespacedFile(
|
|
31519
|
+
fsExtra.ensureDirSync(path59.dirname(destPath));
|
|
31520
|
+
writeNamespacedFile(path59.join(assetDir, assetFile), destPath, namespace);
|
|
31365
31521
|
clack4.log.success(`Updated components/${assetDirectory}/${namespacedAssetFile}`);
|
|
31366
31522
|
}
|
|
31367
31523
|
});
|
|
31368
31524
|
if (assetDirectory === "custom") {
|
|
31369
|
-
const assetSubdir =
|
|
31525
|
+
const assetSubdir = path59.join(assetDir, name);
|
|
31370
31526
|
if (fs45.existsSync(assetSubdir) && fs45.statSync(assetSubdir).isDirectory()) {
|
|
31371
31527
|
const namespacedName = applyAdminNamespaceToPath(name, namespace);
|
|
31372
|
-
const destSubdir =
|
|
31528
|
+
const destSubdir = path59.join(admin, "components", assetDirectory, namespacedName);
|
|
31373
31529
|
pendingWrites.push({
|
|
31374
31530
|
displayPath: `components/${assetDirectory}/${namespacedName}/ (template files)`,
|
|
31375
31531
|
write: () => {
|
|
@@ -31404,19 +31560,19 @@ async function runUpdateCommand(components, options) {
|
|
|
31404
31560
|
"content-editor"
|
|
31405
31561
|
);
|
|
31406
31562
|
const namespace = config.frameworkConfig.next.namespace;
|
|
31407
|
-
const destBaseDir =
|
|
31563
|
+
const destBaseDir = path59.join(admin, "components", "custom", "content-editor");
|
|
31408
31564
|
if (!fs45.existsSync(srcBaseDir)) {
|
|
31409
31565
|
return false;
|
|
31410
31566
|
}
|
|
31411
31567
|
const dirsToCopy = [];
|
|
31412
31568
|
for (const directory of TIPTAP_CONTENT_EDITOR_DIRECTORIES) {
|
|
31413
|
-
const srcDir =
|
|
31569
|
+
const srcDir = path59.join(srcBaseDir, directory);
|
|
31414
31570
|
if (!fs45.existsSync(srcDir)) {
|
|
31415
31571
|
continue;
|
|
31416
31572
|
}
|
|
31417
31573
|
dirsToCopy.push({
|
|
31418
31574
|
srcDir,
|
|
31419
|
-
destDir:
|
|
31575
|
+
destDir: path59.join(destBaseDir, applyAdminNamespaceToPath(directory, namespace))
|
|
31420
31576
|
});
|
|
31421
31577
|
}
|
|
31422
31578
|
if (dirsToCopy.length === 0) {
|
|
@@ -31430,7 +31586,7 @@ async function runUpdateCommand(components, options) {
|
|
|
31430
31586
|
copyNamespacedDirectory(srcDir, destDir, namespace);
|
|
31431
31587
|
}
|
|
31432
31588
|
clack4.log.success("Updated components/custom/content-editor/tiptap-*/ (template files)");
|
|
31433
|
-
removeLegacyDirectory(
|
|
31589
|
+
removeLegacyDirectory(path59.join(admin, "components", "custom", "tiptap"));
|
|
31434
31590
|
}
|
|
31435
31591
|
});
|
|
31436
31592
|
updatedStaticNames.add(key);
|
|
@@ -31490,7 +31646,7 @@ async function runUpdateCommand(components, options) {
|
|
|
31490
31646
|
`Overwriting ${displayPaths.length} file${displayPaths.length === 1 ? "" : "s"}`
|
|
31491
31647
|
);
|
|
31492
31648
|
if (!options.yes) {
|
|
31493
|
-
if (!
|
|
31649
|
+
if (!isInteractiveSession()) {
|
|
31494
31650
|
clack4.log.error(
|
|
31495
31651
|
`Overwriting ${displayPaths.length} file${displayPaths.length === 1 ? "" : "s"} needs confirmation. Re-run with --yes.`
|
|
31496
31652
|
);
|
|
@@ -31570,13 +31726,13 @@ function runShadcnPresetUpdate({
|
|
|
31570
31726
|
only
|
|
31571
31727
|
}) {
|
|
31572
31728
|
const namespace = resolveAdminNamespace(config.frameworkConfig.next.namespace);
|
|
31573
|
-
const adminGlobalsPath =
|
|
31574
|
-
const componentsJsonPath =
|
|
31729
|
+
const adminGlobalsPath = path59.join(cwd, config.paths.admin, namespace.globalsFile);
|
|
31730
|
+
const componentsJsonPath = path59.join(cwd, "components.json");
|
|
31575
31731
|
const shadcnBackupPath = `${componentsJsonPath}.bak`;
|
|
31576
31732
|
const restoreAfterApplyPaths = [
|
|
31577
31733
|
componentsJsonPath,
|
|
31578
31734
|
shadcnBackupPath,
|
|
31579
|
-
|
|
31735
|
+
path59.join(cwd, config.paths.admin, "lib", "utils.ts"),
|
|
31580
31736
|
...getHostProjectFilesToRestore(cwd)
|
|
31581
31737
|
];
|
|
31582
31738
|
if (!preset) {
|
|
@@ -31585,7 +31741,7 @@ function runShadcnPresetUpdate({
|
|
|
31585
31741
|
}
|
|
31586
31742
|
if (!fs45.existsSync(adminGlobalsPath)) {
|
|
31587
31743
|
clack4.cancel(
|
|
31588
|
-
`Admin globals file not found at ${
|
|
31744
|
+
`Admin globals file not found at ${path59.relative(cwd, adminGlobalsPath)}. Run 'betterstart update admin-globals' first.`
|
|
31589
31745
|
);
|
|
31590
31746
|
process.exit(1);
|
|
31591
31747
|
}
|
|
@@ -31595,7 +31751,7 @@ function runShadcnPresetUpdate({
|
|
|
31595
31751
|
snapshot: snapshotFile(filePath)
|
|
31596
31752
|
}));
|
|
31597
31753
|
clack4.intro("BetterStart Shadcn Preset");
|
|
31598
|
-
clack4.log.info(`Applying preset to ${
|
|
31754
|
+
clack4.log.info(`Applying preset to ${path59.join(config.paths.admin, "components/ui")}`);
|
|
31599
31755
|
let failed = false;
|
|
31600
31756
|
try {
|
|
31601
31757
|
fs45.writeFileSync(
|
|
@@ -31608,7 +31764,7 @@ function runShadcnPresetUpdate({
|
|
|
31608
31764
|
if (only) {
|
|
31609
31765
|
args.push("--only", only);
|
|
31610
31766
|
}
|
|
31611
|
-
|
|
31767
|
+
execFileSync5(shadcnBin, args, { cwd, stdio: "inherit" });
|
|
31612
31768
|
} catch {
|
|
31613
31769
|
failed = true;
|
|
31614
31770
|
} finally {
|
|
@@ -31654,7 +31810,7 @@ function toPosixPath(value) {
|
|
|
31654
31810
|
}
|
|
31655
31811
|
function resolveLocalShadcnBin(cwd) {
|
|
31656
31812
|
const binName = process.platform === "win32" ? "shadcn.cmd" : "shadcn";
|
|
31657
|
-
const shadcnBin =
|
|
31813
|
+
const shadcnBin = path59.join(cwd, "node_modules", ".bin", binName);
|
|
31658
31814
|
if (!fs45.existsSync(shadcnBin)) {
|
|
31659
31815
|
clack4.cancel(
|
|
31660
31816
|
`shadcn is not installed in this project. Run 'betterstart update-deps' and try again.`
|
|
@@ -31676,7 +31832,7 @@ function getHostProjectFilesToRestore(cwd) {
|
|
|
31676
31832
|
"app/globals.css",
|
|
31677
31833
|
"src/app/globals.css"
|
|
31678
31834
|
];
|
|
31679
|
-
return hostRelativePaths.map((relativePath) =>
|
|
31835
|
+
return hostRelativePaths.map((relativePath) => path59.join(cwd, relativePath));
|
|
31680
31836
|
}
|
|
31681
31837
|
function snapshotFile(filePath) {
|
|
31682
31838
|
if (!fs45.existsSync(filePath)) {
|
|
@@ -31695,10 +31851,10 @@ function restoreFile(filePath, snapshot) {
|
|
|
31695
31851
|
}
|
|
31696
31852
|
|
|
31697
31853
|
// adapters/next/commands/update-deps.ts
|
|
31698
|
-
import
|
|
31854
|
+
import path60 from "path";
|
|
31699
31855
|
import * as clack5 from "@clack/prompts";
|
|
31700
31856
|
async function runUpdateDepsCommand(options) {
|
|
31701
|
-
const cwd = options.cwd ?
|
|
31857
|
+
const cwd = options.cwd ? path60.resolve(options.cwd) : process.cwd();
|
|
31702
31858
|
clack5.intro("BetterStart Update Dependencies");
|
|
31703
31859
|
const pm = detectPackageManager(cwd);
|
|
31704
31860
|
clack5.log.info(`Package manager: ${pm}`);
|
|
@@ -31733,17 +31889,17 @@ async function runUpdateDepsCommand(options) {
|
|
|
31733
31889
|
|
|
31734
31890
|
// adapters/next/commands/update-styles.ts
|
|
31735
31891
|
import fs46 from "fs";
|
|
31736
|
-
import
|
|
31892
|
+
import path61 from "path";
|
|
31737
31893
|
import * as clack6 from "@clack/prompts";
|
|
31738
31894
|
async function runUpdateStylesCommand(options) {
|
|
31739
|
-
const cwd = options.cwd ?
|
|
31895
|
+
const cwd = options.cwd ? path61.resolve(options.cwd) : process.cwd();
|
|
31740
31896
|
clack6.intro("BetterStart Update Styles");
|
|
31741
31897
|
const config = await resolveConfigOrExit(cwd);
|
|
31742
31898
|
const adminDir = config.paths.admin;
|
|
31743
31899
|
const namespace = resolveAdminNamespace(config.frameworkConfig.next.namespace);
|
|
31744
|
-
const targetPath =
|
|
31900
|
+
const targetPath = path61.join(cwd, adminDir, namespace.globalsFile);
|
|
31745
31901
|
if (!fs46.existsSync(targetPath)) {
|
|
31746
|
-
clack6.cancel(`${namespace.globalsFile} not found at ${
|
|
31902
|
+
clack6.cancel(`${namespace.globalsFile} not found at ${path61.relative(cwd, targetPath)}`);
|
|
31747
31903
|
process.exit(1);
|
|
31748
31904
|
}
|
|
31749
31905
|
fs46.writeFileSync(
|
|
@@ -31751,12 +31907,14 @@ async function runUpdateStylesCommand(options) {
|
|
|
31751
31907
|
applyAdminNamespaceToContent(readTemplate("admin-globals.css"), namespace.segment),
|
|
31752
31908
|
"utf-8"
|
|
31753
31909
|
);
|
|
31754
|
-
clack6.log.success(`Updated ${
|
|
31910
|
+
clack6.log.success(`Updated ${path61.relative(cwd, targetPath)}`);
|
|
31755
31911
|
clack6.outro("Styles updated");
|
|
31756
31912
|
}
|
|
31757
31913
|
|
|
31758
31914
|
// adapters/next/commands-runtime.ts
|
|
31759
31915
|
var nextCommandRuntime = {
|
|
31916
|
+
listInstallableChoices,
|
|
31917
|
+
listSchemaChoices,
|
|
31760
31918
|
runAdd: runAddCommand,
|
|
31761
31919
|
runAddField: runAddFieldCommand,
|
|
31762
31920
|
runCreate: runCreateCommand,
|
|
@@ -31780,7 +31938,7 @@ var { version } = JSON.parse(
|
|
|
31780
31938
|
readFileSync(new URL("../package.json", import.meta.url), "utf-8")
|
|
31781
31939
|
);
|
|
31782
31940
|
var program = new Command2();
|
|
31783
|
-
program.name("betterstart").description("
|
|
31941
|
+
program.name("betterstart").description("A production ready dashboard, tailored for you in 5 Minutes.").version(version);
|
|
31784
31942
|
program.hook("preAction", (_command, actionCommand) => {
|
|
31785
31943
|
requireInitializedProject(actionCommand);
|
|
31786
31944
|
});
|
|
@@ -31799,14 +31957,18 @@ program.addCommand(createUpdateCommand(nextCommandRuntime));
|
|
|
31799
31957
|
program.addCommand(createUpdateDepsCommand(nextCommandRuntime));
|
|
31800
31958
|
program.addCommand(createUpdateStylesCommand(nextCommandRuntime));
|
|
31801
31959
|
try {
|
|
31802
|
-
|
|
31960
|
+
if (process.argv.slice(2).length === 0) {
|
|
31961
|
+
await runDefaultAction(program, nextCommandRuntime);
|
|
31962
|
+
} else {
|
|
31963
|
+
await program.parseAsync();
|
|
31964
|
+
}
|
|
31803
31965
|
} catch (error) {
|
|
31804
31966
|
if (process.env.BETTERSTART_DEBUG) {
|
|
31805
31967
|
console.error(error);
|
|
31806
31968
|
} else {
|
|
31807
31969
|
const message = error instanceof Error && error.message ? error.message : String(error);
|
|
31808
|
-
|
|
31809
|
-
|
|
31970
|
+
p31.log.error(message);
|
|
31971
|
+
p31.log.message(pc12.dim("Re-run with BETTERSTART_DEBUG=1 for the full stack trace."));
|
|
31810
31972
|
}
|
|
31811
31973
|
process.exit(1);
|
|
31812
31974
|
}
|