betterstart-cli 0.0.90 → 0.0.91
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 +599 -456
- 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 p8 from "@clack/prompts";
|
|
202
321
|
|
|
203
322
|
// core-engine/config/serialize.ts
|
|
204
323
|
import fs3 from "fs";
|
|
@@ -750,7 +869,7 @@ async function resolveConfigOrExit(cwd) {
|
|
|
750
869
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
751
870
|
import fs8 from "fs";
|
|
752
871
|
import path10 from "path";
|
|
753
|
-
import * as
|
|
872
|
+
import * as p5 from "@clack/prompts";
|
|
754
873
|
|
|
755
874
|
// adapters/next/init/scaffolders/dependencies.ts
|
|
756
875
|
import { spawn } from "child_process";
|
|
@@ -1633,7 +1752,7 @@ async function syncProjectCliDependency(cwd, pm) {
|
|
|
1633
1752
|
// adapters/next/utils/drizzle-push.ts
|
|
1634
1753
|
import { spawn as spawn2 } from "child_process";
|
|
1635
1754
|
import path9 from "path";
|
|
1636
|
-
import * as
|
|
1755
|
+
import * as p3 from "@clack/prompts";
|
|
1637
1756
|
var PG_SSL_WARNING_START = "Warning: SECURITY WARNING: The SSL modes 'prefer', 'require', and 'verify-ca' are treated as aliases for 'verify-full'.";
|
|
1638
1757
|
var PG_SSL_WARNING_END = "See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode definitions.";
|
|
1639
1758
|
var NODE_TRACE_WARNING_HINT = "(Use `node --trace-warnings";
|
|
@@ -1809,7 +1928,7 @@ function runDrizzlePush(cwd, options = {}) {
|
|
|
1809
1928
|
}
|
|
1810
1929
|
if (stdoutTtySuppressor.sawError() || stderrTtySuppressor.sawError()) {
|
|
1811
1930
|
notifyOutput();
|
|
1812
|
-
|
|
1931
|
+
p3.log.info("Database changes need your input \u2014 continuing in drizzle-kit.");
|
|
1813
1932
|
const attached = spawn2(drizzleBin, ["push", "--force"], {
|
|
1814
1933
|
cwd,
|
|
1815
1934
|
stdio: "inherit",
|
|
@@ -1855,7 +1974,7 @@ ${stderr}`.trim();
|
|
|
1855
1974
|
}
|
|
1856
1975
|
|
|
1857
1976
|
// adapters/next/utils/next-steps.ts
|
|
1858
|
-
import * as
|
|
1977
|
+
import * as p4 from "@clack/prompts";
|
|
1859
1978
|
function printNextSteps(options) {
|
|
1860
1979
|
const steps = [`1. Review ${options.reviewLabel}`];
|
|
1861
1980
|
if (options.needsMigration) {
|
|
@@ -1864,7 +1983,7 @@ function printNextSteps(options) {
|
|
|
1864
1983
|
} else {
|
|
1865
1984
|
steps.push(`2. Start the dev server and visit ${options.route}`);
|
|
1866
1985
|
}
|
|
1867
|
-
|
|
1986
|
+
p4.note(steps.join("\n"), "Next steps");
|
|
1868
1987
|
}
|
|
1869
1988
|
|
|
1870
1989
|
// adapters/next/generators/post-generate.ts
|
|
@@ -1966,25 +2085,25 @@ function ensureDatabasePushDependencies(cwd, pm) {
|
|
|
1966
2085
|
if (missing.length === 0) {
|
|
1967
2086
|
return true;
|
|
1968
2087
|
}
|
|
1969
|
-
|
|
2088
|
+
p5.log.info(
|
|
1970
2089
|
`Installing database push dependencies (${missing.map((dependency) => dependency.name).join(", ")})...`
|
|
1971
2090
|
);
|
|
1972
2091
|
for (const dependency of missing) {
|
|
1973
2092
|
const installed2 = installDependency(cwd, pm, dependency.name, dependency.dev);
|
|
1974
2093
|
if (!installed2) {
|
|
1975
|
-
|
|
2094
|
+
p5.log.warn(`Failed to install ${dependency.name}`);
|
|
1976
2095
|
return false;
|
|
1977
2096
|
}
|
|
1978
2097
|
}
|
|
1979
2098
|
const ready = hasPostgresRuntimeDependency(cwd) && hasDrizzleKitPostgresDriverDependency(cwd);
|
|
1980
2099
|
if (ready) {
|
|
1981
|
-
|
|
2100
|
+
p5.log.success("Database push dependencies installed");
|
|
1982
2101
|
} else {
|
|
1983
2102
|
const unresolved = [
|
|
1984
2103
|
!hasPostgresRuntimeDependency(cwd) ? POSTGRES_RUNTIME_DEP : null,
|
|
1985
2104
|
!hasDrizzleKitPostgresDriverDependency(cwd) ? DRIZZLE_KIT_POSTGRES_DRIVER_DEP : null
|
|
1986
2105
|
].filter((dependency) => Boolean(dependency));
|
|
1987
|
-
|
|
2106
|
+
p5.log.warn(`Installed dependencies but could not resolve ${unresolved.join(", ")}`);
|
|
1988
2107
|
}
|
|
1989
2108
|
return ready;
|
|
1990
2109
|
}
|
|
@@ -2027,8 +2146,8 @@ async function runPostGenerate(cwd, schemaName, options = {}) {
|
|
|
2027
2146
|
"Formatting: skipped (biome refuses files with conflict markers)",
|
|
2028
2147
|
...(options.conflictPaths ?? []).map((conflictPath) => ` - ${conflictPath}`)
|
|
2029
2148
|
];
|
|
2030
|
-
|
|
2031
|
-
|
|
2149
|
+
p5.log.warn(lines.join("\n"));
|
|
2150
|
+
p5.log.message(
|
|
2032
2151
|
"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
2152
|
);
|
|
2034
2153
|
return result;
|
|
@@ -2038,7 +2157,7 @@ async function runPostGenerate(cwd, schemaName, options = {}) {
|
|
|
2038
2157
|
const dbUrl = process.env.DATABASE_URL;
|
|
2039
2158
|
if (!dbUrl) {
|
|
2040
2159
|
result.dbPush = "no-db-url";
|
|
2041
|
-
|
|
2160
|
+
p5.log.warn(
|
|
2042
2161
|
[
|
|
2043
2162
|
"Database: skipped (no DATABASE_URL configured)",
|
|
2044
2163
|
" To sync later: run db:push after setting DATABASE_URL"
|
|
@@ -2046,43 +2165,43 @@ async function runPostGenerate(cwd, schemaName, options = {}) {
|
|
|
2046
2165
|
);
|
|
2047
2166
|
} else if (!ensureDatabasePushDependencies(cwd, pm)) {
|
|
2048
2167
|
result.dbPush = "failed";
|
|
2049
|
-
|
|
2168
|
+
p5.log.warn(
|
|
2050
2169
|
"Database push failed (install database dependencies and run drizzle-kit push manually)"
|
|
2051
2170
|
);
|
|
2052
2171
|
} else if (hasPkgScript(cwd, "db:push")) {
|
|
2053
|
-
|
|
2172
|
+
p5.log.info("Running db:push...");
|
|
2054
2173
|
const ok = runPmScript(pm, "db:push", cwd);
|
|
2055
2174
|
result.dbPush = ok ? "success" : "failed";
|
|
2056
2175
|
if (ok) {
|
|
2057
|
-
|
|
2176
|
+
p5.log.success("Database schema synced");
|
|
2058
2177
|
} else {
|
|
2059
|
-
|
|
2178
|
+
p5.log.warn("Database push failed (run db:push manually)");
|
|
2060
2179
|
}
|
|
2061
2180
|
} else {
|
|
2062
|
-
|
|
2181
|
+
p5.log.info("Running drizzle-kit push...");
|
|
2063
2182
|
try {
|
|
2064
2183
|
const pushResult = await runDrizzlePush(cwd, { interactive: true });
|
|
2065
2184
|
if (!pushResult.success) {
|
|
2066
2185
|
throw new Error(pushResult.error ?? "drizzle-kit push failed");
|
|
2067
2186
|
}
|
|
2068
2187
|
result.dbPush = "success";
|
|
2069
|
-
|
|
2188
|
+
p5.log.success("Database schema synced");
|
|
2070
2189
|
} catch {
|
|
2071
2190
|
result.dbPush = "failed";
|
|
2072
|
-
|
|
2191
|
+
p5.log.warn("Database push failed (run drizzle-kit push manually)");
|
|
2073
2192
|
}
|
|
2074
2193
|
}
|
|
2075
2194
|
} else {
|
|
2076
|
-
|
|
2195
|
+
p5.log.info(`Database: skipped (${options.skipMigrationMessage ?? "--skip-migration"})`);
|
|
2077
2196
|
}
|
|
2078
2197
|
if (hasPkgScript(cwd, "lint:fix")) {
|
|
2079
|
-
|
|
2198
|
+
p5.log.info("Running lint:fix...");
|
|
2080
2199
|
const ok = runPmScript(pm, "lint:fix", cwd, BIOME_FORMAT_TIMEOUT_MS);
|
|
2081
2200
|
result.lintFix = ok ? "success" : "failed";
|
|
2082
2201
|
if (ok) {
|
|
2083
|
-
|
|
2202
|
+
p5.log.success("Code formatted");
|
|
2084
2203
|
} else {
|
|
2085
|
-
|
|
2204
|
+
p5.log.warn("Lint fix had issues (run lint:fix manually)");
|
|
2086
2205
|
}
|
|
2087
2206
|
} else {
|
|
2088
2207
|
try {
|
|
@@ -2090,10 +2209,10 @@ async function runPostGenerate(cwd, schemaName, options = {}) {
|
|
|
2090
2209
|
throw new Error("Biome binary not found");
|
|
2091
2210
|
}
|
|
2092
2211
|
result.lintFix = "success";
|
|
2093
|
-
|
|
2212
|
+
p5.log.success("Code formatted with Biome");
|
|
2094
2213
|
} catch {
|
|
2095
2214
|
result.lintFix = "failed";
|
|
2096
|
-
|
|
2215
|
+
p5.log.warn("Biome formatting had issues (run biome check --write manually)");
|
|
2097
2216
|
}
|
|
2098
2217
|
}
|
|
2099
2218
|
if (options.showNextSteps !== false) {
|
|
@@ -2110,7 +2229,7 @@ async function runPostGenerate(cwd, schemaName, options = {}) {
|
|
|
2110
2229
|
// adapters/next/integration-runtime.ts
|
|
2111
2230
|
import fs14 from "fs";
|
|
2112
2231
|
import path17 from "path";
|
|
2113
|
-
import * as
|
|
2232
|
+
import * as p6 from "@clack/prompts";
|
|
2114
2233
|
|
|
2115
2234
|
// core-engine/schema/schema-reader.ts
|
|
2116
2235
|
import fs9 from "fs";
|
|
@@ -2916,15 +3035,15 @@ function collectSchemaSlotLayoutErrors(schema, errors) {
|
|
|
2916
3035
|
}
|
|
2917
3036
|
collectSlotLayoutErrors(input.slot, "slot", errors);
|
|
2918
3037
|
}
|
|
2919
|
-
function collectSlotLayoutErrors(value,
|
|
3038
|
+
function collectSlotLayoutErrors(value, path62, errors) {
|
|
2920
3039
|
if (!isRecord(value)) {
|
|
2921
|
-
errors.push(`${
|
|
3040
|
+
errors.push(`${path62} must be an object with "main" and/or "sidebar" field groups.`);
|
|
2922
3041
|
return;
|
|
2923
3042
|
}
|
|
2924
3043
|
const validKeys = /* @__PURE__ */ new Set(["main", "sidebar"]);
|
|
2925
3044
|
for (const key of Object.keys(value)) {
|
|
2926
3045
|
if (!validKeys.has(key)) {
|
|
2927
|
-
errors.push(`${
|
|
3046
|
+
errors.push(`${path62} has unsupported key "${key}". Expected "main" or "sidebar".`);
|
|
2928
3047
|
}
|
|
2929
3048
|
}
|
|
2930
3049
|
const areas = [
|
|
@@ -2935,24 +3054,24 @@ function collectSlotLayoutErrors(value, path61, errors) {
|
|
|
2935
3054
|
for (const [name, area] of areas) {
|
|
2936
3055
|
if (area === void 0) continue;
|
|
2937
3056
|
hasArea = true;
|
|
2938
|
-
collectSlotAreaErrors(area, `${
|
|
3057
|
+
collectSlotAreaErrors(area, `${path62}.${name}`, errors);
|
|
2939
3058
|
}
|
|
2940
3059
|
if (!hasArea) {
|
|
2941
|
-
errors.push(`${
|
|
3060
|
+
errors.push(`${path62} must define at least one of "main" or "sidebar".`);
|
|
2942
3061
|
}
|
|
2943
3062
|
}
|
|
2944
|
-
function collectSlotAreaErrors(value,
|
|
3063
|
+
function collectSlotAreaErrors(value, path62, errors) {
|
|
2945
3064
|
if (!isRecord(value)) {
|
|
2946
|
-
errors.push(`${
|
|
3065
|
+
errors.push(`${path62} must be an object with a "fields" array.`);
|
|
2947
3066
|
return;
|
|
2948
3067
|
}
|
|
2949
3068
|
const fields = value.fields;
|
|
2950
3069
|
if (!Array.isArray(fields)) {
|
|
2951
|
-
errors.push(`${
|
|
3070
|
+
errors.push(`${path62}.fields must be an array.`);
|
|
2952
3071
|
return;
|
|
2953
3072
|
}
|
|
2954
3073
|
for (const field of fields) {
|
|
2955
|
-
walkSlot(field, `${
|
|
3074
|
+
walkSlot(field, `${path62}.fields.${field.name ?? "unnamed"}`, errors);
|
|
2956
3075
|
}
|
|
2957
3076
|
}
|
|
2958
3077
|
function collectInvalidHeightErrors(topLevelFields, rootPath, errors) {
|
|
@@ -3436,12 +3555,12 @@ async function resolveTextEnvValue(options) {
|
|
|
3436
3555
|
if (existingValue) {
|
|
3437
3556
|
return existingValue;
|
|
3438
3557
|
}
|
|
3439
|
-
const result = await
|
|
3558
|
+
const result = await p6.text({
|
|
3440
3559
|
message: options.message,
|
|
3441
3560
|
defaultValue: options.defaultValue,
|
|
3442
3561
|
validate: options.validate
|
|
3443
3562
|
});
|
|
3444
|
-
if (
|
|
3563
|
+
if (p6.isCancel(result)) {
|
|
3445
3564
|
throw new Error(options.cancelMessage);
|
|
3446
3565
|
}
|
|
3447
3566
|
options.overwriteEnvKeys.add(options.key);
|
|
@@ -3452,11 +3571,11 @@ async function resolvePasswordEnvValue(options) {
|
|
|
3452
3571
|
if (existingValue) {
|
|
3453
3572
|
return existingValue;
|
|
3454
3573
|
}
|
|
3455
|
-
const result = await
|
|
3574
|
+
const result = await p6.password({
|
|
3456
3575
|
message: options.message,
|
|
3457
3576
|
validate: options.validate
|
|
3458
3577
|
});
|
|
3459
|
-
if (
|
|
3578
|
+
if (p6.isCancel(result)) {
|
|
3460
3579
|
throw new Error(options.cancelMessage);
|
|
3461
3580
|
}
|
|
3462
3581
|
options.overwriteEnvKeys.add(options.key);
|
|
@@ -4788,9 +4907,9 @@ function getReadFieldType(field) {
|
|
|
4788
4907
|
}
|
|
4789
4908
|
return getFieldType(field, "output");
|
|
4790
4909
|
}
|
|
4791
|
-
function collectReadSelectFields(fields,
|
|
4910
|
+
function collectReadSelectFields(fields, path62 = []) {
|
|
4792
4911
|
const matches = fields.flatMap((field) => {
|
|
4793
|
-
const currentPath = [...
|
|
4912
|
+
const currentPath = [...path62, field.name];
|
|
4794
4913
|
const matches2 = field.type === "select" ? [{ field, path: currentPath }] : [];
|
|
4795
4914
|
if (field.fields) {
|
|
4796
4915
|
matches2.push(...collectReadSelectFields(field.fields, currentPath));
|
|
@@ -5837,14 +5956,14 @@ function buildStepsConstant(steps) {
|
|
|
5837
5956
|
${entries.join(",\n")}
|
|
5838
5957
|
]`;
|
|
5839
5958
|
}
|
|
5840
|
-
function buildComponentSource(
|
|
5959
|
+
function buildComponentSource(p32) {
|
|
5841
5960
|
const providerOpen = ` <NuqsAdapter>
|
|
5842
5961
|
<React.Suspense fallback={null}>
|
|
5843
|
-
<${
|
|
5962
|
+
<${p32.pascal}FormInner />
|
|
5844
5963
|
</React.Suspense>
|
|
5845
5964
|
</NuqsAdapter>`;
|
|
5846
5965
|
const exportWrapper = `
|
|
5847
|
-
export function ${
|
|
5966
|
+
export function ${p32.pascal}Form() {
|
|
5848
5967
|
return (
|
|
5849
5968
|
${providerOpen}
|
|
5850
5969
|
)
|
|
@@ -5853,22 +5972,22 @@ ${providerOpen}
|
|
|
5853
5972
|
return `'use client'
|
|
5854
5973
|
|
|
5855
5974
|
import { standardSchemaResolver } from '@hookform/resolvers/standard-schema'
|
|
5856
|
-
import { ChevronLeft, ChevronRight${
|
|
5975
|
+
import { ChevronLeft, ChevronRight${p32.hasListFields ? ", Trash2" : ""} } from 'lucide-react'
|
|
5857
5976
|
import { createParser, useQueryState } from 'nuqs'
|
|
5858
5977
|
import { NuqsAdapter } from 'nuqs/adapters/next/app'
|
|
5859
5978
|
import * as React from 'react'
|
|
5860
|
-
${
|
|
5979
|
+
${p32.rhfImport}
|
|
5861
5980
|
import { z } from 'zod/v3'
|
|
5862
|
-
import { create${
|
|
5981
|
+
import { create${p32.pascal}Submission } from '@admin/actions/${p32.actionImportPath}'
|
|
5863
5982
|
|
|
5864
5983
|
const formSchema = z.object({
|
|
5865
|
-
${
|
|
5984
|
+
${p32.zodFields}
|
|
5866
5985
|
})
|
|
5867
5986
|
|
|
5868
5987
|
type FormValues = z.infer<typeof formSchema>
|
|
5869
5988
|
${buildFieldErrorHelper()}
|
|
5870
5989
|
|
|
5871
|
-
${
|
|
5990
|
+
${p32.stepsConst}
|
|
5872
5991
|
|
|
5873
5992
|
const stepParser = createParser({
|
|
5874
5993
|
parse(value) {
|
|
@@ -5886,7 +6005,7 @@ const stepParser = createParser({
|
|
|
5886
6005
|
}
|
|
5887
6006
|
}).withDefault(0)
|
|
5888
6007
|
|
|
5889
|
-
function ${
|
|
6008
|
+
function ${p32.pascal}FormInner() {
|
|
5890
6009
|
const [currentStep, setCurrentStep] = useQueryState('step', stepParser)
|
|
5891
6010
|
const [submitted, setSubmitted] = React.useState(false)
|
|
5892
6011
|
const [submitting, startSubmitTransition] = React.useTransition()
|
|
@@ -5894,11 +6013,11 @@ function ${p31.pascal}FormInner() {
|
|
|
5894
6013
|
const form = useForm<FormValues>({
|
|
5895
6014
|
resolver: standardSchemaResolver(formSchema),
|
|
5896
6015
|
defaultValues: {
|
|
5897
|
-
${
|
|
6016
|
+
${p32.defaults}
|
|
5898
6017
|
},
|
|
5899
6018
|
})
|
|
5900
6019
|
|
|
5901
|
-
${
|
|
6020
|
+
${p32.fieldArraySetup}${p32.watchSetup}
|
|
5902
6021
|
async function handleNext() {
|
|
5903
6022
|
const stepFields = STEPS[currentStep].fields as (keyof FormValues)[]
|
|
5904
6023
|
const isValid = await form.trigger(stepFields, { shouldFocus: true })
|
|
@@ -5914,9 +6033,9 @@ ${p31.fieldArraySetup}${p31.watchSetup}
|
|
|
5914
6033
|
function onSubmit(values: FormValues) {
|
|
5915
6034
|
startSubmitTransition(async () => {
|
|
5916
6035
|
try {
|
|
5917
|
-
const result = await create${
|
|
6036
|
+
const result = await create${p32.pascal}Submission(values)
|
|
5918
6037
|
if (result.success) {
|
|
5919
|
-
${
|
|
6038
|
+
${p32.successHandler}
|
|
5920
6039
|
} else {
|
|
5921
6040
|
form.setError('root', { message: result.error || 'Something went wrong' })
|
|
5922
6041
|
}
|
|
@@ -5930,7 +6049,7 @@ ${p31.fieldArraySetup}${p31.watchSetup}
|
|
|
5930
6049
|
return (
|
|
5931
6050
|
<div className="rounded-sm border p-6 text-center">
|
|
5932
6051
|
<h3 className="text-lg font-semibold">Thank you!</h3>
|
|
5933
|
-
<p className="mt-2 text-muted-foreground">${
|
|
6052
|
+
<p className="mt-2 text-muted-foreground">${p32.successMessage}</p>
|
|
5934
6053
|
</div>
|
|
5935
6054
|
)
|
|
5936
6055
|
}
|
|
@@ -5947,7 +6066,7 @@ ${p31.fieldArraySetup}${p31.watchSetup}
|
|
|
5947
6066
|
|
|
5948
6067
|
{/* Step content */}
|
|
5949
6068
|
<div key={currentStep} className="animate-in fade-in duration-300 space-y-6">
|
|
5950
|
-
${
|
|
6069
|
+
${p32.stepContentBlocks}
|
|
5951
6070
|
</div>
|
|
5952
6071
|
|
|
5953
6072
|
{form.formState.errors.root && (
|
|
@@ -5981,7 +6100,7 @@ ${p31.stepContentBlocks}
|
|
|
5981
6100
|
onClick={() => form.handleSubmit(onSubmit)()}
|
|
5982
6101
|
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
6102
|
>
|
|
5984
|
-
{submitting ? 'Submitting...' : ${
|
|
6103
|
+
{submitting ? 'Submitting...' : ${p32.submitText}}
|
|
5985
6104
|
</button>
|
|
5986
6105
|
)}
|
|
5987
6106
|
</div>
|
|
@@ -13997,14 +14116,14 @@ function safeIdentifier(value, fallback) {
|
|
|
13997
14116
|
const base = pascal ? `${pascal.charAt(0).toLowerCase()}${pascal.slice(1)}` : fallback;
|
|
13998
14117
|
return /^[A-Za-z_$]/.test(base) ? base : fallback;
|
|
13999
14118
|
}
|
|
14000
|
-
function pathExpression(
|
|
14001
|
-
return `\`${
|
|
14119
|
+
function pathExpression(path62) {
|
|
14120
|
+
return `\`${path62.map((part) => typeof part === "string" ? part : `\${${part.expression}}`).join(".")}\``;
|
|
14002
14121
|
}
|
|
14003
|
-
function pathNameProp(
|
|
14004
|
-
if (
|
|
14005
|
-
return `"${
|
|
14122
|
+
function pathNameProp(path62) {
|
|
14123
|
+
if (path62.every((part) => typeof part === "string")) {
|
|
14124
|
+
return `"${path62.map((part) => part).join(".")}"`;
|
|
14006
14125
|
}
|
|
14007
|
-
return `{${pathExpression(
|
|
14126
|
+
return `{${pathExpression(path62)}}`;
|
|
14008
14127
|
}
|
|
14009
14128
|
function findTitlePath(fields) {
|
|
14010
14129
|
const stringTypes = ["string", "varchar", "text"];
|
|
@@ -14026,23 +14145,23 @@ function findTitlePath(fields) {
|
|
|
14026
14145
|
function requiredLeafPaths(fields, prefix = []) {
|
|
14027
14146
|
return fields.flatMap((field) => {
|
|
14028
14147
|
if (field.hidden) return [];
|
|
14029
|
-
const
|
|
14148
|
+
const path62 = [...prefix, field.name];
|
|
14030
14149
|
if ((field.type === "group" || field.type === "section") && field.fields?.length) {
|
|
14031
|
-
return requiredLeafPaths(field.fields,
|
|
14150
|
+
return requiredLeafPaths(field.fields, path62);
|
|
14032
14151
|
}
|
|
14033
|
-
if (field.required) return [
|
|
14152
|
+
if (field.required) return [path62.join(".")];
|
|
14034
14153
|
return [];
|
|
14035
14154
|
});
|
|
14036
14155
|
}
|
|
14037
14156
|
function validationTriggerExpression(basePath, requiredPaths) {
|
|
14038
14157
|
if (requiredPaths.length === 0) return `\`${basePath}.\${expandedIndex}\` as never`;
|
|
14039
|
-
const paths = requiredPaths.map((
|
|
14158
|
+
const paths = requiredPaths.map((path62) => `\`${basePath}.\${expandedIndex}.${path62}\``).join(", ");
|
|
14040
14159
|
return `[${paths}] as never`;
|
|
14041
14160
|
}
|
|
14042
|
-
function renderTextInputField(field, indent, label, nestedHint,
|
|
14161
|
+
function renderTextInputField(field, indent, label, nestedHint, path62) {
|
|
14043
14162
|
return `${indent}<FormField
|
|
14044
14163
|
${indent} control={form.control}
|
|
14045
|
-
${indent} name=${pathNameProp(
|
|
14164
|
+
${indent} name=${pathNameProp(path62)}
|
|
14046
14165
|
${indent} render={({ field: formField }) => (
|
|
14047
14166
|
${indent} <FormItem${formItemProps(field)}>
|
|
14048
14167
|
${indent} ${labelWithDescription(formLabel(field, label), nestedHint, `${indent} `)}
|
|
@@ -14054,11 +14173,11 @@ ${indent} </FormItem>
|
|
|
14054
14173
|
${indent} )}
|
|
14055
14174
|
${indent}/>`;
|
|
14056
14175
|
}
|
|
14057
|
-
function renderNestedField(field, indent,
|
|
14176
|
+
function renderNestedField(field, indent, path62, depth) {
|
|
14058
14177
|
const nestedLabel = field.label || field.name;
|
|
14059
14178
|
const nestedHint = field.hint ? `<FormDescription>${field.hint}</FormDescription>` : "";
|
|
14060
14179
|
if ((field.type === "group" || field.type === "section") && field.fields?.length) {
|
|
14061
|
-
const groupFields = field.fields.map((child) => renderNestedField(child, `${indent} `, [...
|
|
14180
|
+
const groupFields = field.fields.map((child) => renderNestedField(child, `${indent} `, [...path62, child.name], depth)).filter(Boolean).join("\n");
|
|
14062
14181
|
if (!groupFields) return "";
|
|
14063
14182
|
const heading = nestedLabel && nestedLabel !== field.name ? `${indent}<h3 className="text-base font-medium">${nestedLabel}</h3>
|
|
14064
14183
|
` : "";
|
|
@@ -14068,7 +14187,7 @@ ${groupFields}
|
|
|
14068
14187
|
${indent}</div>`;
|
|
14069
14188
|
}
|
|
14070
14189
|
if (field.type === "list" && field.fields?.length) {
|
|
14071
|
-
return renderNestedObjectListField(field, indent, nestedLabel,
|
|
14190
|
+
return renderNestedObjectListField(field, indent, nestedLabel, path62, depth);
|
|
14072
14191
|
}
|
|
14073
14192
|
if (field.type === "list") {
|
|
14074
14193
|
const hideLabelProp = field.label ? "" : `
|
|
@@ -14076,7 +14195,7 @@ ${indent} hideLabel`;
|
|
|
14076
14195
|
const descriptionProp = field.hint ? `
|
|
14077
14196
|
${indent} description={${JSON.stringify(field.hint)}}` : "";
|
|
14078
14197
|
return `${indent}<DynamicListField
|
|
14079
|
-
${indent} name={${pathExpression(
|
|
14198
|
+
${indent} name={${pathExpression(path62)}}
|
|
14080
14199
|
${indent} label="${nestedLabel}"${hideLabelProp}${descriptionProp}
|
|
14081
14200
|
${indent} disabled={isPending}${field.maxItems ? `
|
|
14082
14201
|
${indent} maxItems={${field.maxItems}}` : ""}
|
|
@@ -14086,7 +14205,7 @@ ${indent}/>`;
|
|
|
14086
14205
|
if (field.type === "boolean") {
|
|
14087
14206
|
return `${indent}<FormField
|
|
14088
14207
|
${indent} control={form.control}
|
|
14089
|
-
${indent} name=${pathNameProp(
|
|
14208
|
+
${indent} name=${pathNameProp(path62)}
|
|
14090
14209
|
${indent} render={({ field: formField }) => (
|
|
14091
14210
|
${indent} <FormItem${formItemProps(field, "flex flex-row items-start space-x-3 space-y-0")}>
|
|
14092
14211
|
${indent} <FormControl>
|
|
@@ -14101,7 +14220,7 @@ ${indent}/>`;
|
|
|
14101
14220
|
const acceptProp = field.type === "image" ? ' accept="image/*"' : field.type === "video" ? ' accept="video/*"' : "";
|
|
14102
14221
|
return `${indent}<FormField
|
|
14103
14222
|
${indent} control={form.control}
|
|
14104
|
-
${indent} name=${pathNameProp(
|
|
14223
|
+
${indent} name=${pathNameProp(path62)}
|
|
14105
14224
|
${indent} render={({ field: formField }) => (
|
|
14106
14225
|
${indent} <FormItem${formItemProps(field)}>
|
|
14107
14226
|
${indent} ${labelWithDescription(formLabel(field, nestedLabel), nestedHint, `${indent} `)}
|
|
@@ -14116,7 +14235,7 @@ ${indent}/>`;
|
|
|
14116
14235
|
if (field.type === "icon") {
|
|
14117
14236
|
return `${indent}<FormField
|
|
14118
14237
|
${indent} control={form.control}
|
|
14119
|
-
${indent} name=${pathNameProp(
|
|
14238
|
+
${indent} name=${pathNameProp(path62)}
|
|
14120
14239
|
${indent} render={({ field: formField }) => (
|
|
14121
14240
|
${indent} <FormItem${formItemProps(field)}>
|
|
14122
14241
|
${indent} ${labelWithDescription(formLabel(field, nestedLabel), nestedHint, `${indent} `)}
|
|
@@ -14133,7 +14252,7 @@ ${indent}/>`;
|
|
|
14133
14252
|
const emptyValue = field.required ? "undefined" : "null";
|
|
14134
14253
|
return `${indent}<FormField
|
|
14135
14254
|
${indent} control={form.control}
|
|
14136
|
-
${indent} name=${pathNameProp(
|
|
14255
|
+
${indent} name=${pathNameProp(path62)}
|
|
14137
14256
|
${indent} render={({ field: formField }) => (
|
|
14138
14257
|
${indent} <FormItem${formItemProps(field)}>
|
|
14139
14258
|
${indent} ${labelWithDescription(formLabel(field, nestedLabel), nestedHint, `${indent} `)}
|
|
@@ -14158,16 +14277,16 @@ ${indent} </FormItem>
|
|
|
14158
14277
|
${indent} )}
|
|
14159
14278
|
${indent}/>`;
|
|
14160
14279
|
}
|
|
14161
|
-
return renderTextInputField(field, indent, nestedLabel, nestedHint,
|
|
14280
|
+
return renderTextInputField(field, indent, nestedLabel, nestedHint, path62);
|
|
14162
14281
|
}
|
|
14163
|
-
function renderNestedObjectListField(field, indent, label,
|
|
14282
|
+
function renderNestedObjectListField(field, indent, label, path62, depth) {
|
|
14164
14283
|
const singularLabel = singularize(label);
|
|
14165
14284
|
const itemIndexVar = `${safeIdentifier(field.name, "nestedList")}Index${depth}`;
|
|
14166
14285
|
const titlePath = findTitlePath(field.fields ?? []);
|
|
14167
14286
|
const titlePathSuffix = titlePath ? `.${titlePath.join(".")}` : "";
|
|
14168
14287
|
const renderTitleProp = titlePath ? `
|
|
14169
14288
|
${indent} renderTitle={(${itemIndexVar}) =>
|
|
14170
|
-
${indent} String(form.watch(\`${
|
|
14289
|
+
${indent} String(form.watch(\`${path62.map((part) => typeof part === "string" ? part : `\${${part.expression}}`).join(
|
|
14171
14290
|
"."
|
|
14172
14291
|
)}.\${${itemIndexVar}}${titlePathSuffix}\` as never) || \`${singularLabel} \${${itemIndexVar} + 1}\`)
|
|
14173
14292
|
${indent} }` : "";
|
|
@@ -14175,7 +14294,7 @@ ${indent} }` : "";
|
|
|
14175
14294
|
(child) => renderNestedField(
|
|
14176
14295
|
child,
|
|
14177
14296
|
`${indent} `,
|
|
14178
|
-
[...
|
|
14297
|
+
[...path62, { expression: itemIndexVar }, child.name],
|
|
14179
14298
|
depth + 1
|
|
14180
14299
|
)
|
|
14181
14300
|
).filter(Boolean).join("\n");
|
|
@@ -14190,7 +14309,7 @@ ${indent} maxItems={${field.maxItems}}` : "";
|
|
|
14190
14309
|
const validatePathsProp = validatePaths.length > 0 ? `
|
|
14191
14310
|
${indent} validatePaths={${JSON.stringify(validatePaths)}}` : "";
|
|
14192
14311
|
return `${indent}<NestedObjectListField
|
|
14193
|
-
${indent} name={${pathExpression(
|
|
14312
|
+
${indent} name={${pathExpression(path62)}}
|
|
14194
14313
|
${indent} label={${JSON.stringify(label)}}
|
|
14195
14314
|
${indent} singularLabel={${JSON.stringify(singularLabel)}}
|
|
14196
14315
|
${indent} defaultValue={${defaultItem}}
|
|
@@ -17805,7 +17924,7 @@ function readPresetTemplate(presetId, relativePath) {
|
|
|
17805
17924
|
// adapters/next/snapshots/apply.ts
|
|
17806
17925
|
import fs20 from "fs";
|
|
17807
17926
|
import path24 from "path";
|
|
17808
|
-
import * as
|
|
17927
|
+
import * as p7 from "@clack/prompts";
|
|
17809
17928
|
|
|
17810
17929
|
// core-engine/snapshots/ast-substitution.ts
|
|
17811
17930
|
import { Node, Project } from "ts-morph";
|
|
@@ -17826,7 +17945,7 @@ function applyTextEdits(content, edits) {
|
|
|
17826
17945
|
content
|
|
17827
17946
|
);
|
|
17828
17947
|
}
|
|
17829
|
-
function collectPreviewChanges(
|
|
17948
|
+
function collectPreviewChanges(path62, beforeContent, afterContent) {
|
|
17830
17949
|
const beforeLines = beforeContent.split("\n");
|
|
17831
17950
|
const afterLines = afterContent.split("\n");
|
|
17832
17951
|
const maxLength = Math.max(beforeLines.length, afterLines.length);
|
|
@@ -17838,7 +17957,7 @@ function collectPreviewChanges(path61, beforeContent, afterContent) {
|
|
|
17838
17957
|
continue;
|
|
17839
17958
|
}
|
|
17840
17959
|
changes.push({
|
|
17841
|
-
path:
|
|
17960
|
+
path: path62,
|
|
17842
17961
|
line: index + 1,
|
|
17843
17962
|
before: before.trim(),
|
|
17844
17963
|
after: after.trim()
|
|
@@ -18468,11 +18587,11 @@ function buildMergeInput(cwd, baseFile, localContent, remoteFile) {
|
|
|
18468
18587
|
}
|
|
18469
18588
|
};
|
|
18470
18589
|
}
|
|
18471
|
-
function
|
|
18590
|
+
function isInteractiveSession2(interactive) {
|
|
18472
18591
|
return interactive && Boolean(process.stdin.isTTY) && process.env.CI !== "true";
|
|
18473
18592
|
}
|
|
18474
18593
|
async function promptNoBaseDecision(filePath) {
|
|
18475
|
-
const answer = await
|
|
18594
|
+
const answer = await p7.select({
|
|
18476
18595
|
message: `File already exists without snapshot base: ${filePath}`,
|
|
18477
18596
|
options: [
|
|
18478
18597
|
{ value: "backup", label: "Backup and overwrite", hint: "recommended" },
|
|
@@ -18481,7 +18600,7 @@ async function promptNoBaseDecision(filePath) {
|
|
|
18481
18600
|
],
|
|
18482
18601
|
initialValue: "backup"
|
|
18483
18602
|
});
|
|
18484
|
-
if (
|
|
18603
|
+
if (p7.isCancel(answer)) {
|
|
18485
18604
|
throw new Error("Generation cancelled.");
|
|
18486
18605
|
}
|
|
18487
18606
|
return answer;
|
|
@@ -18517,7 +18636,7 @@ async function applyGeneratedFiles({
|
|
|
18517
18636
|
const remoteFiles = sortGeneratedFiles(generatedFiles);
|
|
18518
18637
|
const remotePaths = new Set(remoteFiles.map((file) => file.path));
|
|
18519
18638
|
const skipped = new Set(force ? [] : manifest?.skipped ?? []);
|
|
18520
|
-
const interactiveSession =
|
|
18639
|
+
const interactiveSession = isInteractiveSession2(interactive);
|
|
18521
18640
|
const aliasMap = renamePlan ? buildRenamePlanAliasMap(renamePlan) : /* @__PURE__ */ new Map();
|
|
18522
18641
|
const consumedBasePaths = /* @__PURE__ */ new Set();
|
|
18523
18642
|
let baseFiles = /* @__PURE__ */ new Map();
|
|
@@ -19362,18 +19481,18 @@ async function runAddCommand(items, options) {
|
|
|
19362
19481
|
const presetIds = items.filter(isPresetId);
|
|
19363
19482
|
const integrationIds = items.filter(isIntegrationId);
|
|
19364
19483
|
if (!installIntegrationsMode && integrationIds.length > 0) {
|
|
19365
|
-
|
|
19484
|
+
p8.log.error(
|
|
19366
19485
|
`Integration IDs require --integration. Run \`betterstart add --integration ${integrationIds.join(" ")}\`.`
|
|
19367
19486
|
);
|
|
19368
19487
|
process.exit(1);
|
|
19369
19488
|
}
|
|
19370
19489
|
if (installIntegrationsMode && presetIds.length > 0) {
|
|
19371
|
-
|
|
19490
|
+
p8.log.error(`Preset IDs cannot be installed with --integration: ${presetIds.join(", ")}`);
|
|
19372
19491
|
process.exit(1);
|
|
19373
19492
|
}
|
|
19374
19493
|
const invalidItems = installIntegrationsMode ? items.filter((integrationId) => !isIntegrationId(integrationId)) : items.filter((presetId) => !isPresetId(presetId));
|
|
19375
19494
|
if (invalidItems.length > 0) {
|
|
19376
|
-
|
|
19495
|
+
p8.log.error(
|
|
19377
19496
|
installIntegrationsMode ? formatUnknownIntegrationMessage(invalidItems) : formatUnknownPresetMessage(invalidItems)
|
|
19378
19497
|
);
|
|
19379
19498
|
process.exit(1);
|
|
@@ -19384,7 +19503,7 @@ async function runAddCommand(items, options) {
|
|
|
19384
19503
|
const pm = detectPackageManager(cwd);
|
|
19385
19504
|
const cliSyncResult = await syncProjectCliDependency(cwd, pm);
|
|
19386
19505
|
if (cliSyncResult && !cliSyncResult.success) {
|
|
19387
|
-
|
|
19506
|
+
p8.log.error(cliSyncResult.error ?? "Failed to sync betterstart-cli");
|
|
19388
19507
|
process.exit(1);
|
|
19389
19508
|
}
|
|
19390
19509
|
if (installIntegrationsMode) {
|
|
@@ -19398,10 +19517,10 @@ async function runAddCommand(items, options) {
|
|
|
19398
19517
|
});
|
|
19399
19518
|
writeConfigFile(cwd, result2.config);
|
|
19400
19519
|
if (result2.warnings.length > 0) {
|
|
19401
|
-
|
|
19520
|
+
p8.note(result2.warnings.join("\n"), "Warnings");
|
|
19402
19521
|
}
|
|
19403
19522
|
if (result2.installed.length === 0 && result2.activated.length === 0 && result2.skipped.length > 0) {
|
|
19404
|
-
|
|
19523
|
+
p8.outro(`No changes made. Already installed: ${result2.skipped.join(", ")}`);
|
|
19405
19524
|
return;
|
|
19406
19525
|
}
|
|
19407
19526
|
const conflictPaths2 = scanConflictPaths(cwd);
|
|
@@ -19423,12 +19542,12 @@ async function runAddCommand(items, options) {
|
|
|
19423
19542
|
result2.installed.length > 0 ? `Installed integration${result2.installed.length === 1 ? "" : "s"}: ${result2.installed.join(", ")}` : null,
|
|
19424
19543
|
result2.activated.length > 0 ? `Activated integration${result2.activated.length === 1 ? "" : "s"}: ${result2.activated.join(", ")}` : null
|
|
19425
19544
|
].filter(Boolean);
|
|
19426
|
-
|
|
19545
|
+
p8.outro(messages.join("\n"));
|
|
19427
19546
|
return;
|
|
19428
19547
|
}
|
|
19429
19548
|
const invalidPresets = items.filter((presetId) => !isPresetId(presetId));
|
|
19430
19549
|
if (invalidPresets.length > 0) {
|
|
19431
|
-
|
|
19550
|
+
p8.log.error(formatUnknownPresetMessage(invalidPresets));
|
|
19432
19551
|
process.exit(1);
|
|
19433
19552
|
}
|
|
19434
19553
|
const result = await installPresets({
|
|
@@ -19441,11 +19560,11 @@ async function runAddCommand(items, options) {
|
|
|
19441
19560
|
});
|
|
19442
19561
|
writeConfigFile(cwd, result.config);
|
|
19443
19562
|
if (result.installed.length === 0 && result.skipped.length > 0) {
|
|
19444
|
-
|
|
19563
|
+
p8.outro(`No changes made. Already installed: ${result.skipped.join(", ")}`);
|
|
19445
19564
|
return;
|
|
19446
19565
|
}
|
|
19447
19566
|
if (result.warnings.length > 0) {
|
|
19448
|
-
|
|
19567
|
+
p8.note(result.warnings.join("\n"), "Warnings");
|
|
19449
19568
|
}
|
|
19450
19569
|
const installedSchemaNames = result.installed.flatMap(
|
|
19451
19570
|
(presetId) => getPresetDefinition(presetId).schemaFiles.map((schemaFile) => schemaFile.replace(/\.json$/, ""))
|
|
@@ -19462,14 +19581,14 @@ async function runAddCommand(items, options) {
|
|
|
19462
19581
|
if (conflictPaths.length === 0) {
|
|
19463
19582
|
printAddNextSteps("preset", hasSchemaChanges, postGenerateResult, adminRoutePath);
|
|
19464
19583
|
}
|
|
19465
|
-
|
|
19584
|
+
p8.outro(
|
|
19466
19585
|
`Installed preset${result.installed.length === 1 ? "" : "s"}: ${result.installed.join(", ")}`
|
|
19467
19586
|
);
|
|
19468
19587
|
}
|
|
19469
19588
|
|
|
19470
19589
|
// adapters/next/commands/add-field.ts
|
|
19471
19590
|
import path30 from "path";
|
|
19472
|
-
import * as
|
|
19591
|
+
import * as p12 from "@clack/prompts";
|
|
19473
19592
|
|
|
19474
19593
|
// core-engine/schema/add-field.ts
|
|
19475
19594
|
import fs23 from "fs";
|
|
@@ -20121,7 +20240,7 @@ function getTabFields(tab) {
|
|
|
20121
20240
|
// adapters/next/commands/generate.ts
|
|
20122
20241
|
import fs24 from "fs";
|
|
20123
20242
|
import path29 from "path";
|
|
20124
|
-
import * as
|
|
20243
|
+
import * as p10 from "@clack/prompts";
|
|
20125
20244
|
|
|
20126
20245
|
// core-engine/snapshots/rename-detector.ts
|
|
20127
20246
|
function levenshtein(a, b) {
|
|
@@ -20215,7 +20334,7 @@ function diffSchemas(before, after) {
|
|
|
20215
20334
|
|
|
20216
20335
|
// core-engine/utils/spinner.ts
|
|
20217
20336
|
import { stripVTControlCharacters } from "util";
|
|
20218
|
-
import * as
|
|
20337
|
+
import * as p9 from "@clack/prompts";
|
|
20219
20338
|
var RENDER_OVERHEAD = 7;
|
|
20220
20339
|
var MIN_MESSAGE_WIDTH = 8;
|
|
20221
20340
|
function fitSpinnerMessage(message) {
|
|
@@ -20262,7 +20381,7 @@ function hasActiveSpinner() {
|
|
|
20262
20381
|
return activeSpinners > 0;
|
|
20263
20382
|
}
|
|
20264
20383
|
function spinner2(options) {
|
|
20265
|
-
const inner =
|
|
20384
|
+
const inner = p9.spinner({ ...options, cancelMessage: "Setup cancelled." });
|
|
20266
20385
|
const guided = options?.withGuide !== false;
|
|
20267
20386
|
let started = false;
|
|
20268
20387
|
const setStarted = (next) => {
|
|
@@ -20296,7 +20415,7 @@ function spinner2(options) {
|
|
|
20296
20415
|
}
|
|
20297
20416
|
|
|
20298
20417
|
// adapters/next/commands/generate.ts
|
|
20299
|
-
function
|
|
20418
|
+
function isInteractiveSession3() {
|
|
20300
20419
|
return Boolean(process.stdin.isTTY) && process.env.CI !== "true";
|
|
20301
20420
|
}
|
|
20302
20421
|
function isStoredSchemaJson(schemaJson) {
|
|
@@ -20381,7 +20500,7 @@ function assertSnapshotStateOrExit(cwd) {
|
|
|
20381
20500
|
if (snapshotRootExists(cwd)) {
|
|
20382
20501
|
return;
|
|
20383
20502
|
}
|
|
20384
|
-
|
|
20503
|
+
p10.log.error(UNSUPPORTED_PROJECT_STATE_MESSAGE);
|
|
20385
20504
|
process.exit(1);
|
|
20386
20505
|
}
|
|
20387
20506
|
function printSchemaDiff(scope, loaded, cwd) {
|
|
@@ -20416,14 +20535,14 @@ function printSchemaDiff(scope, loaded, cwd) {
|
|
|
20416
20535
|
` custom cells: +[${diff.customComponents.added.join(", ")}] -[${diff.customComponents.removed.join(", ")}]`
|
|
20417
20536
|
);
|
|
20418
20537
|
}
|
|
20419
|
-
|
|
20538
|
+
p10.log.message(lines.join("\n"));
|
|
20420
20539
|
}
|
|
20421
20540
|
async function promptConfirm(message) {
|
|
20422
|
-
const result = await
|
|
20541
|
+
const result = await p10.confirm({
|
|
20423
20542
|
message,
|
|
20424
20543
|
initialValue: true
|
|
20425
20544
|
});
|
|
20426
|
-
if (
|
|
20545
|
+
if (p10.isCancel(result)) {
|
|
20427
20546
|
throw new Error("Generation cancelled.");
|
|
20428
20547
|
}
|
|
20429
20548
|
return Boolean(result);
|
|
@@ -20553,7 +20672,7 @@ async function maybeBuildRenamePlan(loaded, cwd, config, generatedFiles, options
|
|
|
20553
20672
|
};
|
|
20554
20673
|
if (finalPlan.fields.length === 0 && finalPlan.customCells.length === 0) {
|
|
20555
20674
|
if (validatedCustomCells.warnings.length > 0) {
|
|
20556
|
-
|
|
20675
|
+
p10.log.warn(validatedCustomCells.warnings.join("\n"));
|
|
20557
20676
|
}
|
|
20558
20677
|
return void 0;
|
|
20559
20678
|
}
|
|
@@ -20571,10 +20690,10 @@ async function maybeBuildRenamePlan(loaded, cwd, config, generatedFiles, options
|
|
|
20571
20690
|
if (preview.previewLines.length > previewLines.length) {
|
|
20572
20691
|
renameLines.push(` ... ${preview.previewLines.length - previewLines.length} more change(s)`);
|
|
20573
20692
|
}
|
|
20574
|
-
|
|
20693
|
+
p10.log.message(renameLines.join("\n"));
|
|
20575
20694
|
const warnings = [...validatedCustomCells.warnings, ...preview.warnings];
|
|
20576
20695
|
if (warnings.length > 0) {
|
|
20577
|
-
|
|
20696
|
+
p10.log.warn(warnings.join("\n"));
|
|
20578
20697
|
}
|
|
20579
20698
|
const confirmed = await promptConfirm("Apply these rename substitutions before merge?");
|
|
20580
20699
|
return confirmed ? finalPlan : void 0;
|
|
@@ -20685,16 +20804,16 @@ function printApplySummary(schemaName, summary) {
|
|
|
20685
20804
|
if (summary.skippedCleared.length > 0) {
|
|
20686
20805
|
lines.push(` skip entries cleared: ${summary.skippedCleared.join(", ")}`);
|
|
20687
20806
|
}
|
|
20688
|
-
|
|
20807
|
+
p10.log.message(lines.join("\n"));
|
|
20689
20808
|
}
|
|
20690
20809
|
async function runGenerateCommand(schemaName, options) {
|
|
20691
20810
|
const cwd = options.cwd ? path29.resolve(options.cwd) : process.cwd();
|
|
20692
|
-
const interactive = options.all ? options.interactive &&
|
|
20811
|
+
const interactive = options.all ? options.interactive && isInteractiveSession3() : isInteractiveSession3();
|
|
20693
20812
|
let config;
|
|
20694
20813
|
try {
|
|
20695
20814
|
config = await resolveConfig(cwd);
|
|
20696
20815
|
} catch (error) {
|
|
20697
|
-
|
|
20816
|
+
p10.log.error(`Error loading config: ${error instanceof Error ? error.message : String(error)}`);
|
|
20698
20817
|
process.exit(1);
|
|
20699
20818
|
}
|
|
20700
20819
|
assertSnapshotStateOrExit(cwd);
|
|
@@ -20704,7 +20823,7 @@ async function runGenerateCommand(schemaName, options) {
|
|
|
20704
20823
|
if (options.all) {
|
|
20705
20824
|
const schemaNames = listSchemaNames(schemasDir);
|
|
20706
20825
|
if (schemaNames.length === 0) {
|
|
20707
|
-
|
|
20826
|
+
p10.log.error(`No schemas found in ${schemasDir}`);
|
|
20708
20827
|
process.exit(1);
|
|
20709
20828
|
}
|
|
20710
20829
|
const failed = [];
|
|
@@ -20712,14 +20831,14 @@ async function runGenerateCommand(schemaName, options) {
|
|
|
20712
20831
|
const processedRoutes = [];
|
|
20713
20832
|
let markdownDepsChecked = false;
|
|
20714
20833
|
const adminRoutePath2 = resolveAdminNamespace(config.frameworkConfig.next.namespace).routePath;
|
|
20715
|
-
|
|
20834
|
+
p10.intro(`BetterStart Generator \u2014 regenerating ${schemaNames.length} schema(s)`);
|
|
20716
20835
|
for (const name of schemaNames) {
|
|
20717
20836
|
if (hasTombstone(cwd, name)) {
|
|
20718
20837
|
if (loadManifest(cwd, name)) {
|
|
20719
20838
|
clearTombstone(cwd, name);
|
|
20720
|
-
|
|
20839
|
+
p10.log.warn(`${name}: tombstone cleared (manifest present)`);
|
|
20721
20840
|
} else {
|
|
20722
|
-
|
|
20841
|
+
p10.log.message(`${name}: skipped (tombstoned)`);
|
|
20723
20842
|
continue;
|
|
20724
20843
|
}
|
|
20725
20844
|
}
|
|
@@ -20745,7 +20864,7 @@ async function runGenerateCommand(schemaName, options) {
|
|
|
20745
20864
|
processed.push(name);
|
|
20746
20865
|
processedRoutes.push(getGeneratedSchemaRoutePath(loaded2, adminRoutePath2));
|
|
20747
20866
|
} catch (error) {
|
|
20748
|
-
|
|
20867
|
+
p10.log.error(`${name}: ${error instanceof Error ? error.message : String(error)}`);
|
|
20749
20868
|
failed.push(name);
|
|
20750
20869
|
}
|
|
20751
20870
|
}
|
|
@@ -20768,14 +20887,14 @@ async function runGenerateCommand(schemaName, options) {
|
|
|
20768
20887
|
});
|
|
20769
20888
|
}
|
|
20770
20889
|
if (failed.length > 0) {
|
|
20771
|
-
|
|
20890
|
+
p10.log.error(`Failed: ${failed.join(", ")}`);
|
|
20772
20891
|
process.exit(1);
|
|
20773
20892
|
}
|
|
20774
|
-
|
|
20893
|
+
p10.outro(`Regenerated ${processed.length}/${schemaNames.length} schema(s)`);
|
|
20775
20894
|
return;
|
|
20776
20895
|
}
|
|
20777
20896
|
if (!schemaName) {
|
|
20778
|
-
|
|
20897
|
+
p10.log.error("Error: schema name is required (or use --all)");
|
|
20779
20898
|
process.exit(1);
|
|
20780
20899
|
}
|
|
20781
20900
|
let loaded;
|
|
@@ -20783,20 +20902,20 @@ async function runGenerateCommand(schemaName, options) {
|
|
|
20783
20902
|
loaded = loadSchema(schemasDir, schemaName);
|
|
20784
20903
|
} catch (error) {
|
|
20785
20904
|
if (error instanceof SchemaNotFoundError) {
|
|
20786
|
-
|
|
20905
|
+
p10.log.error(error.message);
|
|
20787
20906
|
} else {
|
|
20788
|
-
|
|
20907
|
+
p10.log.error(`Error loading schema: ${error instanceof Error ? error.message : String(error)}`);
|
|
20789
20908
|
}
|
|
20790
20909
|
process.exit(1);
|
|
20791
20910
|
}
|
|
20792
20911
|
const validationErrors = validateLoadedSchema(loaded);
|
|
20793
20912
|
if (validationErrors.length > 0) {
|
|
20794
|
-
|
|
20913
|
+
p10.log.error(
|
|
20795
20914
|
["Schema validation failed:", ...validationErrors.map((error) => ` - ${error}`)].join("\n")
|
|
20796
20915
|
);
|
|
20797
20916
|
process.exit(1);
|
|
20798
20917
|
}
|
|
20799
|
-
|
|
20918
|
+
p10.intro(`BetterStart Generator \u2014 ${loaded.schema.name}`);
|
|
20800
20919
|
const needsMarkdownRenderer = schemaNeedsMarkdownRenderer(loaded);
|
|
20801
20920
|
await ensureMarkdownRendererDependencies(cwd, needsMarkdownRenderer);
|
|
20802
20921
|
const result = await applySchemaGeneration(loaded, cwd, config, {
|
|
@@ -20821,38 +20940,38 @@ async function runGenerateCommand(schemaName, options) {
|
|
|
20821
20940
|
adminRoutePath,
|
|
20822
20941
|
schemaRoutePath: getGeneratedSchemaRoutePath(loaded, adminRoutePath)
|
|
20823
20942
|
});
|
|
20824
|
-
|
|
20943
|
+
p10.outro(`Generated ${loaded.schema.name}`);
|
|
20825
20944
|
}
|
|
20826
20945
|
|
|
20827
20946
|
// adapters/next/commands/schema-prompts.ts
|
|
20828
|
-
import * as
|
|
20829
|
-
function
|
|
20947
|
+
import * as p11 from "@clack/prompts";
|
|
20948
|
+
function isInteractiveSession4() {
|
|
20830
20949
|
return Boolean(process.stdin.isTTY) && process.env.CI !== "true";
|
|
20831
20950
|
}
|
|
20832
20951
|
function fail(message) {
|
|
20833
|
-
|
|
20952
|
+
p11.log.error(message);
|
|
20834
20953
|
process.exit(1);
|
|
20835
20954
|
}
|
|
20836
|
-
function
|
|
20837
|
-
|
|
20955
|
+
function cancel3(context) {
|
|
20956
|
+
p11.cancel(context.cancelMessage);
|
|
20838
20957
|
process.exit(0);
|
|
20839
20958
|
}
|
|
20840
20959
|
function cancelIfNeeded(context, value) {
|
|
20841
|
-
if (
|
|
20842
|
-
|
|
20960
|
+
if (p11.isCancel(value)) {
|
|
20961
|
+
cancel3(context);
|
|
20843
20962
|
}
|
|
20844
20963
|
return value;
|
|
20845
20964
|
}
|
|
20846
20965
|
async function promptConfirm2(context, message, initialValue = true) {
|
|
20847
|
-
const confirmed = await
|
|
20848
|
-
if (
|
|
20849
|
-
|
|
20966
|
+
const confirmed = await p11.confirm({ message, initialValue });
|
|
20967
|
+
if (p11.isCancel(confirmed)) {
|
|
20968
|
+
cancel3(context);
|
|
20850
20969
|
}
|
|
20851
20970
|
return Boolean(confirmed);
|
|
20852
20971
|
}
|
|
20853
20972
|
async function promptText(context, message, optionsOrDefaultValue) {
|
|
20854
20973
|
const options = typeof optionsOrDefaultValue === "string" ? { defaultValue: optionsOrDefaultValue } : optionsOrDefaultValue ?? {};
|
|
20855
|
-
const value = await
|
|
20974
|
+
const value = await p11.text({
|
|
20856
20975
|
message,
|
|
20857
20976
|
defaultValue: options.defaultValue,
|
|
20858
20977
|
placeholder: options.placeholder,
|
|
@@ -20869,7 +20988,7 @@ async function promptText(context, message, optionsOrDefaultValue) {
|
|
|
20869
20988
|
return String(cancelIfNeeded(context, value)).trim();
|
|
20870
20989
|
}
|
|
20871
20990
|
async function promptOptionalText(context, message) {
|
|
20872
|
-
const value = await
|
|
20991
|
+
const value = await p11.text({
|
|
20873
20992
|
message,
|
|
20874
20993
|
placeholder: "Leave blank to skip"
|
|
20875
20994
|
});
|
|
@@ -20877,7 +20996,7 @@ async function promptOptionalText(context, message) {
|
|
|
20877
20996
|
return result || void 0;
|
|
20878
20997
|
}
|
|
20879
20998
|
async function promptSelectValue(context, message, options, initialValue) {
|
|
20880
|
-
const value = await
|
|
20999
|
+
const value = await p11.select({
|
|
20881
21000
|
message,
|
|
20882
21001
|
options,
|
|
20883
21002
|
initialValue
|
|
@@ -21096,7 +21215,7 @@ async function shouldPromptRequired(type) {
|
|
|
21096
21215
|
return !["group", "section", "tabs", "separator"].includes(type);
|
|
21097
21216
|
}
|
|
21098
21217
|
async function promptFormFileOptions(context) {
|
|
21099
|
-
const selected = await
|
|
21218
|
+
const selected = await p11.multiselect({
|
|
21100
21219
|
message: "Field options",
|
|
21101
21220
|
options: [
|
|
21102
21221
|
{ value: "required", label: "Required field?" },
|
|
@@ -21135,7 +21254,7 @@ async function promptFieldOptions(context, kind, type, creatable) {
|
|
|
21135
21254
|
try {
|
|
21136
21255
|
return parseInteractiveOptionsList(value);
|
|
21137
21256
|
} catch (error) {
|
|
21138
|
-
|
|
21257
|
+
p11.log.error(error instanceof Error ? error.message : String(error));
|
|
21139
21258
|
}
|
|
21140
21259
|
}
|
|
21141
21260
|
}
|
|
@@ -21253,7 +21372,7 @@ async function promptChildFields(context, kind, schemasDir, scope, fields, depth
|
|
|
21253
21372
|
const addChild = fields.length === 0 ? await promptConfirm2(context, "Add a child field?", true) : await promptConfirm2(context, "Add another child field?", false);
|
|
21254
21373
|
if (!addChild) {
|
|
21255
21374
|
if (fields.length === 0) {
|
|
21256
|
-
|
|
21375
|
+
p11.log.warn("Containers need at least one child field.");
|
|
21257
21376
|
continue;
|
|
21258
21377
|
}
|
|
21259
21378
|
return;
|
|
@@ -21278,7 +21397,7 @@ async function promptTabsField(context, kind, schemasDir, scope, name, label, de
|
|
|
21278
21397
|
const addTab = field.tabs.length === 0 ? await promptConfirm2(context, "Add a tab?", true) : await promptConfirm2(context, "Add another tab?", false);
|
|
21279
21398
|
if (!addTab) {
|
|
21280
21399
|
if (field.tabs.length === 0) {
|
|
21281
|
-
|
|
21400
|
+
p11.log.warn("Tabs need at least one tab.");
|
|
21282
21401
|
continue;
|
|
21283
21402
|
}
|
|
21284
21403
|
return field;
|
|
@@ -21303,7 +21422,7 @@ async function promptTabsField(context, kind, schemasDir, scope, name, label, de
|
|
|
21303
21422
|
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
21423
|
if (!addChild) {
|
|
21305
21424
|
if (mainFields.length + sidebarFields.length === 0) {
|
|
21306
|
-
|
|
21425
|
+
p11.log.warn("Tabs need at least one child field.");
|
|
21307
21426
|
continue;
|
|
21308
21427
|
}
|
|
21309
21428
|
break;
|
|
@@ -21374,7 +21493,7 @@ async function applyAdvancedOptions(context, field, kind, type, options) {
|
|
|
21374
21493
|
if (Number.isInteger(parsed) && parsed > 0) {
|
|
21375
21494
|
record.length = parsed;
|
|
21376
21495
|
} else {
|
|
21377
|
-
|
|
21496
|
+
p11.log.warn("Skipped invalid length.");
|
|
21378
21497
|
}
|
|
21379
21498
|
}
|
|
21380
21499
|
}
|
|
@@ -21532,11 +21651,11 @@ function hasNonInteractiveFieldOptions(options) {
|
|
|
21532
21651
|
);
|
|
21533
21652
|
}
|
|
21534
21653
|
function fail2(message) {
|
|
21535
|
-
|
|
21654
|
+
p12.log.error(message);
|
|
21536
21655
|
process.exit(1);
|
|
21537
21656
|
}
|
|
21538
|
-
function
|
|
21539
|
-
|
|
21657
|
+
function cancel5(message = "Add field cancelled.") {
|
|
21658
|
+
p12.cancel(message);
|
|
21540
21659
|
process.exit(0);
|
|
21541
21660
|
}
|
|
21542
21661
|
function schemaNameFromLoaded(loaded) {
|
|
@@ -21641,7 +21760,7 @@ function printPreview(loaded, owner, firstTimeGeneration, insertion, options) {
|
|
|
21641
21760
|
} else {
|
|
21642
21761
|
lines.push("schema integration: none");
|
|
21643
21762
|
}
|
|
21644
|
-
|
|
21763
|
+
p12.note(
|
|
21645
21764
|
`${lines.join("\n")}
|
|
21646
21765
|
|
|
21647
21766
|
${stringifyProjectJson(insertion.field).trim()}`,
|
|
@@ -21674,10 +21793,10 @@ Re-run with --yes to confirm these warning cases.`);
|
|
|
21674
21793
|
}
|
|
21675
21794
|
return;
|
|
21676
21795
|
}
|
|
21677
|
-
|
|
21796
|
+
p12.note(warnings.join("\n"), "Warnings");
|
|
21678
21797
|
const confirmed = await promptConfirm3("Continue with these warnings?", true);
|
|
21679
21798
|
if (!confirmed) {
|
|
21680
|
-
|
|
21799
|
+
cancel5();
|
|
21681
21800
|
}
|
|
21682
21801
|
}
|
|
21683
21802
|
function collectRelationshipTargetWarnings(cwd, owner, field) {
|
|
@@ -21719,7 +21838,7 @@ async function resolveSchemaNameInteractively(schemasDir, schemaName) {
|
|
|
21719
21838
|
if (schemaName) {
|
|
21720
21839
|
return schemaName;
|
|
21721
21840
|
}
|
|
21722
|
-
if (!
|
|
21841
|
+
if (!isInteractiveSession4()) {
|
|
21723
21842
|
fail2("Schema name is required in non-interactive sessions.");
|
|
21724
21843
|
}
|
|
21725
21844
|
const schemaNames = listSchemaNames(schemasDir);
|
|
@@ -21747,7 +21866,7 @@ async function runAddFieldCommand(schemaName, options) {
|
|
|
21747
21866
|
} catch (error) {
|
|
21748
21867
|
fail2(error instanceof Error ? error.message : String(error));
|
|
21749
21868
|
}
|
|
21750
|
-
if (!nonInteractive && !
|
|
21869
|
+
if (!nonInteractive && !isInteractiveSession4()) {
|
|
21751
21870
|
fail2("Interactive add-field requires a TTY. Provide --type, --field, and --label instead.");
|
|
21752
21871
|
}
|
|
21753
21872
|
const owner = resolveSchemaOwner(cwd, schemaNameFromLoaded(loaded));
|
|
@@ -21787,11 +21906,11 @@ ${validationErrors.map((error) => ` - ${error}`).join("\n")}`
|
|
|
21787
21906
|
if (!nonInteractive && !options.yes) {
|
|
21788
21907
|
const confirmed = await promptConfirm3("Write schema JSON and regenerate this schema?", true);
|
|
21789
21908
|
if (!confirmed) {
|
|
21790
|
-
|
|
21909
|
+
cancel5();
|
|
21791
21910
|
}
|
|
21792
21911
|
}
|
|
21793
21912
|
writeAuthoredGeneratedSchema(loaded);
|
|
21794
|
-
|
|
21913
|
+
p12.log.success(`Updated ${path30.relative(cwd, loaded.filePath)}`);
|
|
21795
21914
|
try {
|
|
21796
21915
|
await runGenerateCommand(selectedSchemaName, {
|
|
21797
21916
|
force: false,
|
|
@@ -21802,8 +21921,8 @@ ${validationErrors.map((error) => ` - ${error}`).join("\n")}`
|
|
|
21802
21921
|
cwd
|
|
21803
21922
|
});
|
|
21804
21923
|
} catch (error) {
|
|
21805
|
-
|
|
21806
|
-
|
|
21924
|
+
p12.log.error(error instanceof Error ? error.message : String(error));
|
|
21925
|
+
p12.log.info(
|
|
21807
21926
|
`Schema JSON was kept. Re-run \`betterstart generate ${selectedSchemaName}${options.skipMigration ? " --skip-migration" : ""}\` after resolving the issue.`
|
|
21808
21927
|
);
|
|
21809
21928
|
process.exit(1);
|
|
@@ -21813,7 +21932,7 @@ ${validationErrors.map((error) => ` - ${error}`).join("\n")}`
|
|
|
21813
21932
|
// adapters/next/commands/create.ts
|
|
21814
21933
|
import fs25 from "fs";
|
|
21815
21934
|
import path31 from "path";
|
|
21816
|
-
import * as
|
|
21935
|
+
import * as p13 from "@clack/prompts";
|
|
21817
21936
|
var CREATE_PROMPT_CONTEXT = {
|
|
21818
21937
|
cancelMessage: "Create schema cancelled."
|
|
21819
21938
|
};
|
|
@@ -22004,7 +22123,7 @@ async function promptTabSlotFields(kind, schemasDir, titleField) {
|
|
|
22004
22123
|
);
|
|
22005
22124
|
if (!addField) {
|
|
22006
22125
|
if (!hasFields) {
|
|
22007
|
-
|
|
22126
|
+
p13.log.warn("Tabs need at least one child field.");
|
|
22008
22127
|
continue;
|
|
22009
22128
|
}
|
|
22010
22129
|
return { main, sidebar };
|
|
@@ -22052,7 +22171,7 @@ async function promptSchemaTab(kind, schemasDir, titleField, existingTabs) {
|
|
|
22052
22171
|
while (fields.length === 0) {
|
|
22053
22172
|
await promptAdditionalSchemaFields(kind, schemasDir, fields);
|
|
22054
22173
|
if (fields.length === 0) {
|
|
22055
|
-
|
|
22174
|
+
p13.log.warn("Tabs need at least one child field.");
|
|
22056
22175
|
}
|
|
22057
22176
|
}
|
|
22058
22177
|
}
|
|
@@ -22142,7 +22261,7 @@ async function promptFormSubmissionColumns(schema) {
|
|
|
22142
22261
|
}
|
|
22143
22262
|
const existingColumnNames = schema.columns ? new Set(schema.columns.map((column) => column.accessorKey)) : void 0;
|
|
22144
22263
|
const initialValues = existingColumnNames ? fields.filter((field) => existingColumnNames.has(field.name)).map((field) => field.name) : fields.map((field) => field.name);
|
|
22145
|
-
const selected = await
|
|
22264
|
+
const selected = await p13.multiselect({
|
|
22146
22265
|
message: "Submission table columns",
|
|
22147
22266
|
options: fields.map((field) => ({
|
|
22148
22267
|
value: field.name,
|
|
@@ -22151,8 +22270,8 @@ async function promptFormSubmissionColumns(schema) {
|
|
|
22151
22270
|
initialValues,
|
|
22152
22271
|
required: false
|
|
22153
22272
|
});
|
|
22154
|
-
if (
|
|
22155
|
-
|
|
22273
|
+
if (p13.isCancel(selected)) {
|
|
22274
|
+
cancel3(CREATE_PROMPT_CONTEXT);
|
|
22156
22275
|
}
|
|
22157
22276
|
const selectedNames = new Set(selected);
|
|
22158
22277
|
schema.columns = fields.filter((field) => selectedNames.has(field.name)).map((field) => {
|
|
@@ -22211,7 +22330,7 @@ function schemaFilePath(kind, schemasDir, schemaName) {
|
|
|
22211
22330
|
return kind === "form" ? path31.join(schemasDir, "forms", `${schemaName}.json`) : path31.join(schemasDir, `${schemaName}.json`);
|
|
22212
22331
|
}
|
|
22213
22332
|
function printPreview2(loaded, cwd) {
|
|
22214
|
-
|
|
22333
|
+
p13.note(
|
|
22215
22334
|
`schema: ${loaded.name} (${loaded.kind})
|
|
22216
22335
|
path: ${path31.relative(cwd, loaded.filePath)}
|
|
22217
22336
|
owner: user
|
|
@@ -22226,7 +22345,7 @@ async function runCreateCommand(kindInput, schemaName, options) {
|
|
|
22226
22345
|
if (!snapshotRootExists(cwd)) {
|
|
22227
22346
|
fail(UNSUPPORTED_PROJECT_STATE_MESSAGE);
|
|
22228
22347
|
}
|
|
22229
|
-
if (!
|
|
22348
|
+
if (!isInteractiveSession4()) {
|
|
22230
22349
|
fail("Interactive create requires a TTY.");
|
|
22231
22350
|
}
|
|
22232
22351
|
const config = await resolveConfigOrExit(cwd);
|
|
@@ -22258,13 +22377,13 @@ ${validationErrors.map((error) => ` - ${error}`).join("\n")}`
|
|
|
22258
22377
|
break;
|
|
22259
22378
|
}
|
|
22260
22379
|
if (action === "cancel") {
|
|
22261
|
-
|
|
22380
|
+
cancel3(CREATE_PROMPT_CONTEXT);
|
|
22262
22381
|
}
|
|
22263
22382
|
await promptAdditionalCreateField(kind, schemasDir, schema);
|
|
22264
22383
|
}
|
|
22265
22384
|
fs25.mkdirSync(path31.dirname(filePath), { recursive: true });
|
|
22266
22385
|
writeAuthoredGeneratedSchema(loaded);
|
|
22267
|
-
|
|
22386
|
+
p13.log.success(`Created ${path31.relative(cwd, filePath)}`);
|
|
22268
22387
|
try {
|
|
22269
22388
|
await runGenerateCommand(metadata.name, {
|
|
22270
22389
|
force: false,
|
|
@@ -22275,8 +22394,8 @@ ${validationErrors.map((error) => ` - ${error}`).join("\n")}`
|
|
|
22275
22394
|
cwd
|
|
22276
22395
|
});
|
|
22277
22396
|
} catch (error) {
|
|
22278
|
-
|
|
22279
|
-
|
|
22397
|
+
p13.log.error(error instanceof Error ? error.message : String(error));
|
|
22398
|
+
p13.log.info(
|
|
22280
22399
|
`Schema JSON was kept. Re-run \`betterstart generate ${metadata.name}${options.skipMigration ? " --skip-migration" : ""}\` after resolving the issue.`
|
|
22281
22400
|
);
|
|
22282
22401
|
process.exit(1);
|
|
@@ -22288,14 +22407,14 @@ import { execFileSync as execFileSync5, spawn as spawn6 } from "child_process";
|
|
|
22288
22407
|
import fs41 from "fs";
|
|
22289
22408
|
import path52 from "path";
|
|
22290
22409
|
import { PassThrough } from "stream";
|
|
22291
|
-
import * as
|
|
22410
|
+
import * as p26 from "@clack/prompts";
|
|
22292
22411
|
|
|
22293
22412
|
// core-engine/utils/cancel-guard.ts
|
|
22294
|
-
import * as
|
|
22413
|
+
import * as p14 from "@clack/prompts";
|
|
22295
22414
|
function installSetupCancelGuard() {
|
|
22296
22415
|
const onSignal = () => {
|
|
22297
22416
|
if (!hasActiveSpinner()) {
|
|
22298
|
-
|
|
22417
|
+
p14.cancel("Setup cancelled.");
|
|
22299
22418
|
}
|
|
22300
22419
|
process.exit(0);
|
|
22301
22420
|
};
|
|
@@ -22350,11 +22469,11 @@ function redactSecrets(text7) {
|
|
|
22350
22469
|
|
|
22351
22470
|
// adapters/next/init/prompts/database.ts
|
|
22352
22471
|
import { execFileSync as execFileSync4 } from "child_process";
|
|
22353
|
-
import * as
|
|
22472
|
+
import * as p15 from "@clack/prompts";
|
|
22354
22473
|
import pc from "picocolors";
|
|
22355
22474
|
var VERCEL_NEON_URL = "https://vercel.com/dashboard/integrations/checkout/neon";
|
|
22356
22475
|
async function promptServices() {
|
|
22357
|
-
const choice = await
|
|
22476
|
+
const choice = await p15.select({
|
|
22358
22477
|
message: "Connect a PostgreSQL Database",
|
|
22359
22478
|
options: [
|
|
22360
22479
|
{
|
|
@@ -22375,8 +22494,8 @@ async function promptServices() {
|
|
|
22375
22494
|
],
|
|
22376
22495
|
initialValue: "vercel"
|
|
22377
22496
|
});
|
|
22378
|
-
if (
|
|
22379
|
-
|
|
22497
|
+
if (p15.isCancel(choice)) {
|
|
22498
|
+
p15.cancel("Setup cancelled.");
|
|
22380
22499
|
process.exit(0);
|
|
22381
22500
|
}
|
|
22382
22501
|
if (choice === "vercel") {
|
|
@@ -22390,7 +22509,7 @@ async function promptServices() {
|
|
|
22390
22509
|
}
|
|
22391
22510
|
function openBrowserVercelNeon() {
|
|
22392
22511
|
openBrowser(VERCEL_NEON_URL);
|
|
22393
|
-
|
|
22512
|
+
p15.log.info(
|
|
22394
22513
|
`Opening Vercel... Create a Neon Postgres database, then copy the ${pc.cyan("DATABASE_URL")} from the dashboard.`
|
|
22395
22514
|
);
|
|
22396
22515
|
}
|
|
@@ -22400,12 +22519,12 @@ function openBrowserVercelNeonResource(url) {
|
|
|
22400
22519
|
return;
|
|
22401
22520
|
}
|
|
22402
22521
|
openBrowser(url);
|
|
22403
|
-
|
|
22522
|
+
p15.log.info(
|
|
22404
22523
|
`Opening Vercel... Copy the Neon ${pc.cyan("DATABASE_URL")} from the database dashboard, then paste it below.`
|
|
22405
22524
|
);
|
|
22406
22525
|
}
|
|
22407
22526
|
async function promptConnectionString() {
|
|
22408
|
-
const input = await
|
|
22527
|
+
const input = await p15.text({
|
|
22409
22528
|
message: "Paste your PostgreSQL connection string",
|
|
22410
22529
|
placeholder: "postgres://user:pass@host/db",
|
|
22411
22530
|
validate(val) {
|
|
@@ -22419,8 +22538,8 @@ async function promptConnectionString() {
|
|
|
22419
22538
|
}
|
|
22420
22539
|
}
|
|
22421
22540
|
});
|
|
22422
|
-
if (
|
|
22423
|
-
|
|
22541
|
+
if (p15.isCancel(input)) {
|
|
22542
|
+
p15.cancel("Setup cancelled.");
|
|
22424
22543
|
process.exit(0);
|
|
22425
22544
|
}
|
|
22426
22545
|
return input.replace(/^['"]|['"]$/g, "").trim();
|
|
@@ -22440,7 +22559,7 @@ function openBrowser(url) {
|
|
|
22440
22559
|
}
|
|
22441
22560
|
|
|
22442
22561
|
// adapters/next/init/prompts/presets.ts
|
|
22443
|
-
import * as
|
|
22562
|
+
import * as p16 from "@clack/prompts";
|
|
22444
22563
|
|
|
22445
22564
|
// adapters/next/init/scaffolders/env.ts
|
|
22446
22565
|
import crypto2 from "crypto";
|
|
@@ -22605,7 +22724,7 @@ async function promptPresets(cwd, options = {}) {
|
|
|
22605
22724
|
overwriteKeys.add(key);
|
|
22606
22725
|
}
|
|
22607
22726
|
};
|
|
22608
|
-
const storage = await
|
|
22727
|
+
const storage = await p16.select({
|
|
22609
22728
|
message: "Choose a file storage",
|
|
22610
22729
|
options: [
|
|
22611
22730
|
{
|
|
@@ -22629,8 +22748,8 @@ async function promptPresets(cwd, options = {}) {
|
|
|
22629
22748
|
],
|
|
22630
22749
|
initialValue: "vercel-blob"
|
|
22631
22750
|
});
|
|
22632
|
-
if (
|
|
22633
|
-
|
|
22751
|
+
if (p16.isCancel(storage)) {
|
|
22752
|
+
p16.cancel("Setup cancelled.");
|
|
22634
22753
|
process.exit(0);
|
|
22635
22754
|
}
|
|
22636
22755
|
if (storage === "r2") {
|
|
@@ -22640,7 +22759,7 @@ async function promptPresets(cwd, options = {}) {
|
|
|
22640
22759
|
if (flow?.ok && flow.config) {
|
|
22641
22760
|
mergeIntegrationConfig(flow.config);
|
|
22642
22761
|
} else if (flow) {
|
|
22643
|
-
|
|
22762
|
+
p16.log.warn(
|
|
22644
22763
|
"Continuing without Railway bucket credentials \u2014 rerun betterstart add --integration railway-bucket after fixing Railway access."
|
|
22645
22764
|
);
|
|
22646
22765
|
} else {
|
|
@@ -22657,7 +22776,7 @@ async function promptPresets(cwd, options = {}) {
|
|
|
22657
22776
|
});
|
|
22658
22777
|
overwriteKeys.add("BLOB_READ_WRITE_TOKEN");
|
|
22659
22778
|
} else if (flow) {
|
|
22660
|
-
|
|
22779
|
+
p16.log.warn(
|
|
22661
22780
|
"Continuing without a Blob token \u2014 add BLOB_READ_WRITE_TOKEN to .env.local from the store on vercel.com/dashboard/stores."
|
|
22662
22781
|
);
|
|
22663
22782
|
sections.push({
|
|
@@ -22666,7 +22785,7 @@ async function promptPresets(cwd, options = {}) {
|
|
|
22666
22785
|
});
|
|
22667
22786
|
} else {
|
|
22668
22787
|
if (existingToken) {
|
|
22669
|
-
|
|
22788
|
+
p16.log.info(
|
|
22670
22789
|
`Using the existing BLOB_READ_WRITE_TOKEN from .env.local ${pc2.dim(
|
|
22671
22790
|
`(${maskBlobToken(existingToken)})`
|
|
22672
22791
|
)}`
|
|
@@ -22675,7 +22794,7 @@ async function promptPresets(cwd, options = {}) {
|
|
|
22675
22794
|
mergeIntegrationConfig(await collectIntegrationConfig(cwd, ["vercel-blob"]));
|
|
22676
22795
|
}
|
|
22677
22796
|
}
|
|
22678
|
-
const selectedPresets = await
|
|
22797
|
+
const selectedPresets = await p16.multiselect({
|
|
22679
22798
|
message: "Select presets",
|
|
22680
22799
|
options: [
|
|
22681
22800
|
{
|
|
@@ -22687,8 +22806,8 @@ async function promptPresets(cwd, options = {}) {
|
|
|
22687
22806
|
required: false,
|
|
22688
22807
|
initialValues: ["blog"]
|
|
22689
22808
|
});
|
|
22690
|
-
if (
|
|
22691
|
-
|
|
22809
|
+
if (p16.isCancel(selectedPresets)) {
|
|
22810
|
+
p16.cancel("Setup cancelled.");
|
|
22692
22811
|
process.exit(0);
|
|
22693
22812
|
}
|
|
22694
22813
|
const integrations = [];
|
|
@@ -22715,9 +22834,9 @@ async function promptPresets(cwd, options = {}) {
|
|
|
22715
22834
|
}
|
|
22716
22835
|
|
|
22717
22836
|
// adapters/next/init/prompts/project.ts
|
|
22718
|
-
import * as
|
|
22837
|
+
import * as p17 from "@clack/prompts";
|
|
22719
22838
|
async function promptProject(defaultName) {
|
|
22720
|
-
const projectName = await
|
|
22839
|
+
const projectName = await p17.text({
|
|
22721
22840
|
message: "What is your project named?",
|
|
22722
22841
|
placeholder: defaultName ?? "(Press Enter to use default)",
|
|
22723
22842
|
defaultValue: defaultName ?? ".",
|
|
@@ -22730,15 +22849,15 @@ async function promptProject(defaultName) {
|
|
|
22730
22849
|
return void 0;
|
|
22731
22850
|
}
|
|
22732
22851
|
});
|
|
22733
|
-
if (
|
|
22734
|
-
|
|
22852
|
+
if (p17.isCancel(projectName)) {
|
|
22853
|
+
p17.cancel("Setup cancelled.");
|
|
22735
22854
|
process.exit(0);
|
|
22736
22855
|
}
|
|
22737
22856
|
return { projectName: projectName.trim() || "." };
|
|
22738
22857
|
}
|
|
22739
22858
|
|
|
22740
22859
|
// adapters/next/init/providers.ts
|
|
22741
|
-
import * as
|
|
22860
|
+
import * as p18 from "@clack/prompts";
|
|
22742
22861
|
var DATABASE_PROVIDERS = ["vercel", "railway", "manual"];
|
|
22743
22862
|
var STORAGE_PROVIDERS = ["vercel-blob", "railway-bucket", "r2", "local"];
|
|
22744
22863
|
var DEPLOY_PROVIDERS = ["vercel", "railway", "none"];
|
|
@@ -22795,7 +22914,7 @@ function validateResolvedDatabaseProvider(provider, options) {
|
|
|
22795
22914
|
}
|
|
22796
22915
|
}
|
|
22797
22916
|
async function promptDeployProvider(initialValue = "none") {
|
|
22798
|
-
const provider = await
|
|
22917
|
+
const provider = await p18.select({
|
|
22799
22918
|
message: "Deploy this project",
|
|
22800
22919
|
options: [
|
|
22801
22920
|
{
|
|
@@ -22813,8 +22932,8 @@ async function promptDeployProvider(initialValue = "none") {
|
|
|
22813
22932
|
],
|
|
22814
22933
|
initialValue
|
|
22815
22934
|
});
|
|
22816
|
-
if (
|
|
22817
|
-
|
|
22935
|
+
if (p18.isCancel(provider)) {
|
|
22936
|
+
p18.cancel("Setup cancelled.");
|
|
22818
22937
|
process.exit(0);
|
|
22819
22938
|
}
|
|
22820
22939
|
return provider;
|
|
@@ -22823,7 +22942,7 @@ async function promptDeployProvider(initialValue = "none") {
|
|
|
22823
22942
|
// adapters/next/init/railway/deploy.ts
|
|
22824
22943
|
import fs28 from "fs";
|
|
22825
22944
|
import path34 from "path";
|
|
22826
|
-
import * as
|
|
22945
|
+
import * as p20 from "@clack/prompts";
|
|
22827
22946
|
|
|
22828
22947
|
// adapters/next/init/deploy/guard.ts
|
|
22829
22948
|
import { spawn as spawn3 } from "child_process";
|
|
@@ -22920,7 +23039,7 @@ function guardBetterstartConfig(cwd, restores) {
|
|
|
22920
23039
|
}
|
|
22921
23040
|
|
|
22922
23041
|
// adapters/next/init/railway/project.ts
|
|
22923
|
-
import * as
|
|
23042
|
+
import * as p19 from "@clack/prompts";
|
|
22924
23043
|
|
|
22925
23044
|
// adapters/next/init/railway/runner.ts
|
|
22926
23045
|
import { spawn as spawn4 } from "child_process";
|
|
@@ -23204,15 +23323,15 @@ async function ensureRailwayProject(runner, options) {
|
|
|
23204
23323
|
createWorkspace = options.workspaces[0]?.id;
|
|
23205
23324
|
} else if (!createWorkspace && options.interactive && options.workspaces?.length) {
|
|
23206
23325
|
projectSpinner.clear();
|
|
23207
|
-
const workspace = await
|
|
23326
|
+
const workspace = await p19.select({
|
|
23208
23327
|
message: "Choose a Railway workspace",
|
|
23209
23328
|
options: options.workspaces.map((candidate) => ({
|
|
23210
23329
|
value: candidate.id,
|
|
23211
23330
|
label: candidate.name
|
|
23212
23331
|
}))
|
|
23213
23332
|
});
|
|
23214
|
-
if (
|
|
23215
|
-
|
|
23333
|
+
if (p19.isCancel(workspace)) {
|
|
23334
|
+
p19.cancel("Setup cancelled.");
|
|
23216
23335
|
process.exit(0);
|
|
23217
23336
|
}
|
|
23218
23337
|
createWorkspace = workspace;
|
|
@@ -23738,7 +23857,7 @@ async function runRailwayDeployFlow(options) {
|
|
|
23738
23857
|
);
|
|
23739
23858
|
envSpinner.clear();
|
|
23740
23859
|
for (const key of sync.failed) {
|
|
23741
|
-
|
|
23860
|
+
p20.log.warn(`Could not set ${pc4.cyan(key)} on Railway.`);
|
|
23742
23861
|
}
|
|
23743
23862
|
if (sync.failed.length > 0) {
|
|
23744
23863
|
return {
|
|
@@ -23753,12 +23872,12 @@ async function runRailwayDeployFlow(options) {
|
|
|
23753
23872
|
const packageGuard = await guardProjectForDeploy(options.cwd);
|
|
23754
23873
|
guardSpinner.clear();
|
|
23755
23874
|
if (packageGuard.lockfile === "failed") {
|
|
23756
|
-
|
|
23875
|
+
p20.log.warn(
|
|
23757
23876
|
"Could not refresh pnpm-lock.yaml after removing betterstart-cli \u2014 the remote install may fail."
|
|
23758
23877
|
);
|
|
23759
23878
|
}
|
|
23760
23879
|
for (const dependency of packageGuard.localSpecDeps) {
|
|
23761
|
-
|
|
23880
|
+
p20.log.warn(
|
|
23762
23881
|
`Dependency ${pc4.cyan(dependency)} uses a local spec that cannot install on Railway.`
|
|
23763
23882
|
);
|
|
23764
23883
|
}
|
|
@@ -23811,7 +23930,7 @@ ${deploy.stderr}`) ?? deploy.errorMessage
|
|
|
23811
23930
|
}
|
|
23812
23931
|
|
|
23813
23932
|
// adapters/next/init/railway/auth.ts
|
|
23814
|
-
import * as
|
|
23933
|
+
import * as p21 from "@clack/prompts";
|
|
23815
23934
|
import pc5 from "picocolors";
|
|
23816
23935
|
var WHOAMI_TIMEOUT_MS = 3e4;
|
|
23817
23936
|
var LOGIN_TIMEOUT_MS = 3e5;
|
|
@@ -23881,7 +24000,7 @@ async function ensureRailwayAuth(runner, cwd, options) {
|
|
|
23881
24000
|
return { authed: false, reason: existing.reason };
|
|
23882
24001
|
}
|
|
23883
24002
|
checkSpinner.clear();
|
|
23884
|
-
|
|
24003
|
+
p21.log.info(
|
|
23885
24004
|
"Sign in to Railway to continue. Railway will open your browser or show a device code."
|
|
23886
24005
|
);
|
|
23887
24006
|
const login = await runRailway(runner, ["login"], {
|
|
@@ -25768,11 +25887,11 @@ function scaffoldTsconfig(cwd, config) {
|
|
|
25768
25887
|
}
|
|
25769
25888
|
|
|
25770
25889
|
// adapters/next/init/vercel/flow.ts
|
|
25771
|
-
import * as
|
|
25890
|
+
import * as p25 from "@clack/prompts";
|
|
25772
25891
|
import pc9 from "picocolors";
|
|
25773
25892
|
|
|
25774
25893
|
// adapters/next/init/vercel/auth.ts
|
|
25775
|
-
import * as
|
|
25894
|
+
import * as p22 from "@clack/prompts";
|
|
25776
25895
|
import pc6 from "picocolors";
|
|
25777
25896
|
|
|
25778
25897
|
// adapters/next/init/vercel/runner.ts
|
|
@@ -26016,7 +26135,7 @@ async function ensureVercelAuth(runner, cwd, options) {
|
|
|
26016
26135
|
checkSpinner.clear();
|
|
26017
26136
|
const signInMessage = `Sign in to Vercel to continue ${pc6.dim("(or press Ctrl-C to enter a connection string manually)")}`;
|
|
26018
26137
|
const signInRows = clackLogRows(signInMessage);
|
|
26019
|
-
|
|
26138
|
+
p22.log.info(signInMessage);
|
|
26020
26139
|
let streamedRows = 0;
|
|
26021
26140
|
const login = await runVercel(runner, ["login"], {
|
|
26022
26141
|
cwd,
|
|
@@ -26048,7 +26167,7 @@ function signedInMessage(username) {
|
|
|
26048
26167
|
}
|
|
26049
26168
|
|
|
26050
26169
|
// adapters/next/init/vercel/blob.ts
|
|
26051
|
-
import * as
|
|
26170
|
+
import * as p23 from "@clack/prompts";
|
|
26052
26171
|
import pc7 from "picocolors";
|
|
26053
26172
|
|
|
26054
26173
|
// adapters/next/init/vercel/env-pull.ts
|
|
@@ -26290,7 +26409,7 @@ async function provisionBlobStoreInteractive(runner, cwd, options) {
|
|
|
26290
26409
|
if (terminalFallbackRan) break;
|
|
26291
26410
|
terminalFallbackRan = true;
|
|
26292
26411
|
quietSpinner.clear();
|
|
26293
|
-
|
|
26412
|
+
p23.log.info(
|
|
26294
26413
|
`Create your Blob store in the Vercel prompts below ${pc7.dim(
|
|
26295
26414
|
"(connect it to all environments)."
|
|
26296
26415
|
)}`
|
|
@@ -26489,7 +26608,7 @@ function guardEnvLocal(cwd) {
|
|
|
26489
26608
|
}
|
|
26490
26609
|
|
|
26491
26610
|
// adapters/next/init/vercel/neon.ts
|
|
26492
|
-
import * as
|
|
26611
|
+
import * as p24 from "@clack/prompts";
|
|
26493
26612
|
import pc8 from "picocolors";
|
|
26494
26613
|
var PROVISION_TIMEOUT_MS2 = 18e4;
|
|
26495
26614
|
var INTERACTIVE_PROVISION_TIMEOUT_MS2 = 6e5;
|
|
@@ -26508,7 +26627,7 @@ async function provisionNeonInteractive(runner, cwd, options) {
|
|
|
26508
26627
|
termsResolved = true;
|
|
26509
26628
|
quietSpinner.clear();
|
|
26510
26629
|
eraseRows(termsNotice.rows);
|
|
26511
|
-
|
|
26630
|
+
p24.log.step(termsNotice.text);
|
|
26512
26631
|
};
|
|
26513
26632
|
const quiet = await runVercel(runner, neonAddArgs(options), {
|
|
26514
26633
|
cwd,
|
|
@@ -26527,7 +26646,7 @@ ${pc8.dim(termsUrl)}`,
|
|
|
26527
26646
|
rows: clackLogRows(message) + clackLogRows(termsUrl) - 1
|
|
26528
26647
|
};
|
|
26529
26648
|
quietSpinner.clear();
|
|
26530
|
-
|
|
26649
|
+
p24.log.info(termsNotice.text);
|
|
26531
26650
|
quietSpinner.start("Waiting for the terms to be accepted");
|
|
26532
26651
|
return;
|
|
26533
26652
|
}
|
|
@@ -26543,7 +26662,7 @@ ${pc8.dim(termsUrl)}`,
|
|
|
26543
26662
|
return readNeonProvisionInfo(quiet.stdout);
|
|
26544
26663
|
}
|
|
26545
26664
|
quietSpinner.clear();
|
|
26546
|
-
|
|
26665
|
+
p24.log.info(
|
|
26547
26666
|
`Create your Neon database in the Vercel prompts below ${pc8.dim(
|
|
26548
26667
|
"(the Free plan is recommended)."
|
|
26549
26668
|
)}`
|
|
@@ -26620,14 +26739,14 @@ async function runVercelNeonFlow(options) {
|
|
|
26620
26739
|
allowLogin: options.interactive
|
|
26621
26740
|
});
|
|
26622
26741
|
if (!auth.authed) {
|
|
26623
|
-
|
|
26742
|
+
p25.log.warn(authFailureMessage(auth.reason));
|
|
26624
26743
|
return { ok: false };
|
|
26625
26744
|
}
|
|
26626
26745
|
await ensureLinkedProject(runner, options.cwd, options.projectName, env, auth.username);
|
|
26627
26746
|
const neon = await provisionNeonForMode(runner, options);
|
|
26628
26747
|
if (neon.failure) {
|
|
26629
|
-
|
|
26630
|
-
if (neon.detail)
|
|
26748
|
+
p25.log.warn(neonFailureMessage(neon.failure));
|
|
26749
|
+
if (neon.detail) p25.log.message(pc9.dim(redactSecrets(neon.detail)));
|
|
26631
26750
|
return { ok: false };
|
|
26632
26751
|
}
|
|
26633
26752
|
const databaseUrl = await pullNeonDatabaseUrl(runner, options.cwd, env);
|
|
@@ -26640,7 +26759,7 @@ async function runVercelNeonFlow(options) {
|
|
|
26640
26759
|
dismissSignedInNote
|
|
26641
26760
|
};
|
|
26642
26761
|
} catch (error) {
|
|
26643
|
-
|
|
26762
|
+
p25.log.warn(
|
|
26644
26763
|
`Vercel provisioning failed: ${error instanceof Error ? error.message : String(error)}`
|
|
26645
26764
|
);
|
|
26646
26765
|
return { ok: false };
|
|
@@ -26662,14 +26781,14 @@ async function runVercelBlobFlow(options) {
|
|
|
26662
26781
|
allowLogin: options.interactive
|
|
26663
26782
|
});
|
|
26664
26783
|
if (!auth.authed) {
|
|
26665
|
-
|
|
26784
|
+
p25.log.warn(authFailureMessage(auth.reason));
|
|
26666
26785
|
return { ok: false };
|
|
26667
26786
|
}
|
|
26668
26787
|
await ensureLinkedProject(runner, options.cwd, options.projectName, env, auth.username);
|
|
26669
26788
|
const blob = await provisionBlobForMode(runner, options);
|
|
26670
26789
|
if (blob.failure || !blob.token) {
|
|
26671
|
-
|
|
26672
|
-
if (blob.detail)
|
|
26790
|
+
p25.log.warn(blobFailureMessage(blob.failure));
|
|
26791
|
+
if (blob.detail) p25.log.message(pc9.dim(redactSecrets(blob.detail)));
|
|
26673
26792
|
return { ok: false };
|
|
26674
26793
|
}
|
|
26675
26794
|
return {
|
|
@@ -26678,7 +26797,7 @@ async function runVercelBlobFlow(options) {
|
|
|
26678
26797
|
blobStoreName: blob.storeName
|
|
26679
26798
|
};
|
|
26680
26799
|
} catch (error) {
|
|
26681
|
-
|
|
26800
|
+
p25.log.warn(
|
|
26682
26801
|
`Vercel provisioning failed: ${error instanceof Error ? error.message : String(error)}`
|
|
26683
26802
|
);
|
|
26684
26803
|
return { ok: false };
|
|
@@ -26700,7 +26819,7 @@ async function runVercelDeployFlow(options) {
|
|
|
26700
26819
|
allowLogin: options.interactive ?? true
|
|
26701
26820
|
});
|
|
26702
26821
|
if (!auth.authed) {
|
|
26703
|
-
|
|
26822
|
+
p25.log.warn(authFailureMessage(auth.reason));
|
|
26704
26823
|
printManualDeployHint();
|
|
26705
26824
|
return { ok: false };
|
|
26706
26825
|
}
|
|
@@ -26710,7 +26829,7 @@ async function runVercelDeployFlow(options) {
|
|
|
26710
26829
|
const sync = await syncVercelProductionEnv(runner, options.cwd, env);
|
|
26711
26830
|
envSpinner.clear();
|
|
26712
26831
|
for (const key of sync.failed) {
|
|
26713
|
-
|
|
26832
|
+
p25.log.warn(
|
|
26714
26833
|
`Could not set ${pc9.cyan(key)} on Vercel \u2014 add it in the project's environment settings.`
|
|
26715
26834
|
);
|
|
26716
26835
|
}
|
|
@@ -26720,12 +26839,12 @@ async function runVercelDeployFlow(options) {
|
|
|
26720
26839
|
const packageGuard = await guardProjectForDeploy(options.cwd);
|
|
26721
26840
|
guardSpinner.clear();
|
|
26722
26841
|
if (packageGuard.lockfile === "failed") {
|
|
26723
|
-
|
|
26842
|
+
p25.log.warn(
|
|
26724
26843
|
"Could not refresh pnpm-lock.yaml after removing betterstart-cli \u2014 the remote install may fail."
|
|
26725
26844
|
);
|
|
26726
26845
|
}
|
|
26727
26846
|
for (const dep of packageGuard.localSpecDeps) {
|
|
26728
|
-
|
|
26847
|
+
p25.log.warn(
|
|
26729
26848
|
`Dependency ${pc9.cyan(dep)} uses a local spec that cannot install on Vercel \u2014 the remote build may fail.`
|
|
26730
26849
|
);
|
|
26731
26850
|
}
|
|
@@ -26742,7 +26861,7 @@ async function runVercelDeployFlow(options) {
|
|
|
26742
26861
|
}
|
|
26743
26862
|
if (deploy.failure) {
|
|
26744
26863
|
deploySpinner.stop(`${pc9.yellow("\u25B2")} ${deployFailureMessage(deploy.failure)}`);
|
|
26745
|
-
if (deploy.detail)
|
|
26864
|
+
if (deploy.detail) p25.log.message(pc9.dim(redactSecrets(deploy.detail)));
|
|
26746
26865
|
printManualDeployHint();
|
|
26747
26866
|
return { ok: false };
|
|
26748
26867
|
}
|
|
@@ -26750,7 +26869,7 @@ async function runVercelDeployFlow(options) {
|
|
|
26750
26869
|
deploySpinner.stop(url ? `Deployed ${pc9.cyan(url)}` : "Deployed to Vercel");
|
|
26751
26870
|
return { ok: true, url, syncedEnvKeys: sync.synced };
|
|
26752
26871
|
} catch (error) {
|
|
26753
|
-
|
|
26872
|
+
p25.log.warn(`Vercel deploy failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
26754
26873
|
printManualDeployHint();
|
|
26755
26874
|
return { ok: false };
|
|
26756
26875
|
} finally {
|
|
@@ -26758,7 +26877,7 @@ async function runVercelDeployFlow(options) {
|
|
|
26758
26877
|
}
|
|
26759
26878
|
}
|
|
26760
26879
|
function printManualDeployHint() {
|
|
26761
|
-
|
|
26880
|
+
p25.log.info(`You can deploy manually: ${pc9.cyan("vercel deploy --prod")}`);
|
|
26762
26881
|
}
|
|
26763
26882
|
async function ensureLinkedProject(runner, cwd, projectName, env, scope) {
|
|
26764
26883
|
if (readLinkedProjectId(cwd)) return;
|
|
@@ -26841,13 +26960,6 @@ import pc10 from "picocolors";
|
|
|
26841
26960
|
import fs40 from "fs";
|
|
26842
26961
|
import path51 from "path";
|
|
26843
26962
|
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
26963
|
function buildSeedScript(authBasePath = "/api/admin/auth") {
|
|
26852
26964
|
return `/**
|
|
26853
26965
|
* BetterStart Admin \u2014 Seed Script
|
|
@@ -27029,7 +27141,7 @@ async function runSeedCommand(options) {
|
|
|
27029
27141
|
process.exit(1);
|
|
27030
27142
|
}
|
|
27031
27143
|
const adminDir = config.paths?.admin ?? "./admin";
|
|
27032
|
-
const interactive =
|
|
27144
|
+
const interactive = isInteractiveSession();
|
|
27033
27145
|
let email;
|
|
27034
27146
|
if (options.email) {
|
|
27035
27147
|
if (!options.email.includes("@")) {
|
|
@@ -27194,16 +27306,16 @@ function addVersionToBoxBottomBorder(box2, version2) {
|
|
|
27194
27306
|
if (!bottomLine) {
|
|
27195
27307
|
return box2;
|
|
27196
27308
|
}
|
|
27197
|
-
const leftCornerIndex = bottomLine.indexOf(
|
|
27198
|
-
const rightCornerIndex = bottomLine.lastIndexOf(
|
|
27309
|
+
const leftCornerIndex = bottomLine.indexOf(p26.S_CORNER_BOTTOM_LEFT);
|
|
27310
|
+
const rightCornerIndex = bottomLine.lastIndexOf(p26.S_CORNER_BOTTOM_RIGHT);
|
|
27199
27311
|
const label = ` v${version2} `;
|
|
27200
|
-
const borderWidth = rightCornerIndex - leftCornerIndex -
|
|
27312
|
+
const borderWidth = rightCornerIndex - leftCornerIndex - p26.S_CORNER_BOTTOM_LEFT.length;
|
|
27201
27313
|
if (leftCornerIndex === -1 || rightCornerIndex === -1 || borderWidth < label.length) {
|
|
27202
27314
|
return box2;
|
|
27203
27315
|
}
|
|
27204
27316
|
const leftBorderWidth = Math.floor((borderWidth - label.length) / 2);
|
|
27205
27317
|
const rightBorderWidth = borderWidth - label.length - leftBorderWidth;
|
|
27206
|
-
lines[bottomLineIndex] = `${bottomLine.slice(0, leftCornerIndex +
|
|
27318
|
+
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
27319
|
return lines.join("\n");
|
|
27208
27320
|
}
|
|
27209
27321
|
function renderInitBanner() {
|
|
@@ -27213,7 +27325,7 @@ function renderInitBanner() {
|
|
|
27213
27325
|
output.on("data", (chunk) => {
|
|
27214
27326
|
box2 += chunk.toString();
|
|
27215
27327
|
});
|
|
27216
|
-
|
|
27328
|
+
p26.box(
|
|
27217
27329
|
`
|
|
27218
27330
|
\u2584 \u2597 \u2597 \u2584\u2596\u2597 \u2597
|
|
27219
27331
|
\u2599\u2598\u2588\u258C\u259C\u2598\u259C\u2598\u2588\u258C\u259B\u2598\u259A \u259C\u2598\u2580\u258C\u259B\u2598\u259C\u2598
|
|
@@ -27309,7 +27421,7 @@ async function runInitCommand(name, options) {
|
|
|
27309
27421
|
let restoreStdout;
|
|
27310
27422
|
if (options.json) {
|
|
27311
27423
|
if (!options.yes) {
|
|
27312
|
-
|
|
27424
|
+
p26.log.error("--json requires --yes.");
|
|
27313
27425
|
process.exit(1);
|
|
27314
27426
|
}
|
|
27315
27427
|
restoreStdout = redirectStdoutToStderr();
|
|
@@ -27330,7 +27442,7 @@ async function runInitCommand(name, options) {
|
|
|
27330
27442
|
}
|
|
27331
27443
|
} catch (error) {
|
|
27332
27444
|
disposeCancelGuard();
|
|
27333
|
-
|
|
27445
|
+
p26.log.error(error instanceof Error ? error.message : String(error));
|
|
27334
27446
|
process.exit(1);
|
|
27335
27447
|
}
|
|
27336
27448
|
let cwd = process.cwd();
|
|
@@ -27341,7 +27453,7 @@ async function runInitCommand(name, options) {
|
|
|
27341
27453
|
try {
|
|
27342
27454
|
namespace = validateAdminNamespace(options.namespace);
|
|
27343
27455
|
} catch (error) {
|
|
27344
|
-
|
|
27456
|
+
p26.log.error(error instanceof Error ? error.message : String(error));
|
|
27345
27457
|
process.exit(1);
|
|
27346
27458
|
}
|
|
27347
27459
|
}
|
|
@@ -27350,13 +27462,13 @@ async function runInitCommand(name, options) {
|
|
|
27350
27462
|
try {
|
|
27351
27463
|
projectPrompt = options.yes ? resolveNonInteractiveProject(name) : await promptProject(name);
|
|
27352
27464
|
} catch (error) {
|
|
27353
|
-
|
|
27465
|
+
p26.log.error(error instanceof Error ? error.message : String(error));
|
|
27354
27466
|
process.exit(1);
|
|
27355
27467
|
}
|
|
27356
27468
|
}
|
|
27357
27469
|
if (!options.yes && !options.namespace) {
|
|
27358
27470
|
const defaultDashboardPath = resolveAdminNamespace(DEFAULT_ADMIN_NAMESPACE).routePath;
|
|
27359
|
-
const namespaceInput = await
|
|
27471
|
+
const namespaceInput = await p26.text({
|
|
27360
27472
|
message: "Enter the dashboard path",
|
|
27361
27473
|
placeholder: `eg. ${defaultDashboardPath}`,
|
|
27362
27474
|
defaultValue: defaultDashboardPath,
|
|
@@ -27369,8 +27481,8 @@ async function runInitCommand(name, options) {
|
|
|
27369
27481
|
}
|
|
27370
27482
|
}
|
|
27371
27483
|
});
|
|
27372
|
-
if (
|
|
27373
|
-
|
|
27484
|
+
if (p26.isCancel(namespaceInput)) {
|
|
27485
|
+
p26.cancel("Setup cancelled.");
|
|
27374
27486
|
process.exit(0);
|
|
27375
27487
|
}
|
|
27376
27488
|
namespace = validateAdminDashboardPath(namespaceInput);
|
|
@@ -27382,13 +27494,13 @@ async function runInitCommand(name, options) {
|
|
|
27382
27494
|
if (project2.isExisting) {
|
|
27383
27495
|
srcDir = project2.hasSrcDir;
|
|
27384
27496
|
if (!project2.hasTypeScript) {
|
|
27385
|
-
|
|
27497
|
+
p26.log.error("TypeScript is required. Please add a tsconfig.json first.");
|
|
27386
27498
|
process.exit(1);
|
|
27387
27499
|
}
|
|
27388
27500
|
if (forceMode) {
|
|
27389
27501
|
const nuked = removeExistingAdminPaths(cwd, await resolveForceInitNamespaces(cwd, namespace));
|
|
27390
27502
|
if (nuked > 0) {
|
|
27391
|
-
|
|
27503
|
+
p26.log.warn(`${pc10.yellow("Force mode:")} removed ${nuked} existing admin paths`);
|
|
27392
27504
|
}
|
|
27393
27505
|
project2 = detectProject(cwd, namespace);
|
|
27394
27506
|
} else if (project2.conflicts.length > 0) {
|
|
@@ -27397,14 +27509,14 @@ async function runInitCommand(name, options) {
|
|
|
27397
27509
|
"",
|
|
27398
27510
|
pc10.dim(`Use ${pc10.bold("--force")} to remove existing admin files before scaffolding.`)
|
|
27399
27511
|
);
|
|
27400
|
-
|
|
27512
|
+
p26.note(conflictLines.join("\n"), pc10.yellow("Conflicts"));
|
|
27401
27513
|
if (options.yes) {
|
|
27402
|
-
|
|
27514
|
+
p26.log.error(
|
|
27403
27515
|
"Can't continue with --yes while admin files conflict. Re-run with --force to remove them first."
|
|
27404
27516
|
);
|
|
27405
27517
|
process.exit(1);
|
|
27406
27518
|
}
|
|
27407
|
-
const proceed = await
|
|
27519
|
+
const proceed = await p26.confirm({
|
|
27408
27520
|
message: [
|
|
27409
27521
|
`Continue with ${pc10.bold(pc10.cyan("--force"))}?`,
|
|
27410
27522
|
`${pc10.cyan("\u2502")} ${pc10.dim("This will force overwrite the existing admin code.")}`,
|
|
@@ -27412,14 +27524,14 @@ async function runInitCommand(name, options) {
|
|
|
27412
27524
|
].join("\n"),
|
|
27413
27525
|
initialValue: true
|
|
27414
27526
|
});
|
|
27415
|
-
if (
|
|
27416
|
-
|
|
27527
|
+
if (p26.isCancel(proceed) || !proceed) {
|
|
27528
|
+
p26.cancel("Setup cancelled.");
|
|
27417
27529
|
process.exit(0);
|
|
27418
27530
|
}
|
|
27419
27531
|
forceMode = true;
|
|
27420
27532
|
const nuked = removeExistingAdminPaths(cwd, await resolveForceInitNamespaces(cwd, namespace));
|
|
27421
27533
|
if (nuked > 0) {
|
|
27422
|
-
|
|
27534
|
+
p26.log.warn(`${pc10.yellow("Force mode:")} removed ${nuked} existing admin paths`);
|
|
27423
27535
|
}
|
|
27424
27536
|
project2 = detectProject(cwd, namespace);
|
|
27425
27537
|
}
|
|
@@ -27427,7 +27539,7 @@ async function runInitCommand(name, options) {
|
|
|
27427
27539
|
const freshProject = projectPrompt;
|
|
27428
27540
|
srcDir = false;
|
|
27429
27541
|
if (!options.yes) {
|
|
27430
|
-
const pmChoice = await
|
|
27542
|
+
const pmChoice = await p26.select({
|
|
27431
27543
|
message: "Which package manager do you want to use?",
|
|
27432
27544
|
options: [
|
|
27433
27545
|
{ value: "pnpm", label: "pnpm", hint: "recommended" },
|
|
@@ -27435,8 +27547,8 @@ async function runInitCommand(name, options) {
|
|
|
27435
27547
|
{ value: "bun", label: "bun" }
|
|
27436
27548
|
]
|
|
27437
27549
|
});
|
|
27438
|
-
if (
|
|
27439
|
-
|
|
27550
|
+
if (p26.isCancel(pmChoice)) {
|
|
27551
|
+
p26.cancel("Setup cancelled.");
|
|
27440
27552
|
process.exit(0);
|
|
27441
27553
|
}
|
|
27442
27554
|
pm = pmChoice;
|
|
@@ -27471,8 +27583,8 @@ async function runInitCommand(name, options) {
|
|
|
27471
27583
|
process.stderr.write(`${createNextAppResult.output.trimEnd()}
|
|
27472
27584
|
`);
|
|
27473
27585
|
}
|
|
27474
|
-
|
|
27475
|
-
|
|
27586
|
+
p26.log.error(createNextAppResult.error);
|
|
27587
|
+
p26.log.info(
|
|
27476
27588
|
`You can create the project manually:
|
|
27477
27589
|
${pc10.cyan(`npx create-next-app@latest ${freshProject.projectName} --typescript --tailwind --app`)}
|
|
27478
27590
|
Then run ${pc10.cyan("betterstart init")} inside it.`
|
|
@@ -27486,11 +27598,11 @@ async function runInitCommand(name, options) {
|
|
|
27486
27598
|
);
|
|
27487
27599
|
if (!hasPackageJson || !hasNextConfig) {
|
|
27488
27600
|
createNextAppSpinner.stop(`Failed to create Next.js app: ${displayName}`);
|
|
27489
|
-
|
|
27601
|
+
p26.log.error(
|
|
27490
27602
|
"create-next-app completed but the project was not created. This can happen with nested npx calls."
|
|
27491
27603
|
);
|
|
27492
27604
|
const manualCmd = `npx create-next-app@latest ${freshProject.projectName} --typescript --tailwind --app`;
|
|
27493
|
-
|
|
27605
|
+
p26.log.info(
|
|
27494
27606
|
`Create the project manually:
|
|
27495
27607
|
${pc10.cyan(manualCmd)}
|
|
27496
27608
|
Then run ${pc10.cyan("betterstart init")} inside it.`
|
|
@@ -27539,13 +27651,13 @@ async function runInitCommand(name, options) {
|
|
|
27539
27651
|
try {
|
|
27540
27652
|
validateResolvedDatabaseProvider(databaseProvider, options);
|
|
27541
27653
|
} catch (error) {
|
|
27542
|
-
|
|
27654
|
+
p26.log.error(error instanceof Error ? error.message : String(error));
|
|
27543
27655
|
process.exit(1);
|
|
27544
27656
|
}
|
|
27545
27657
|
if (databaseProvider === "manual") {
|
|
27546
27658
|
const candidate = options.databaseUrl ?? existingDbUrl ?? promptedManualUrl;
|
|
27547
27659
|
if (candidate && !isValidDbUrl(candidate)) {
|
|
27548
|
-
|
|
27660
|
+
p26.log.error(
|
|
27549
27661
|
`Invalid database URL. Must start with ${pc10.cyan("postgres://")} or ${pc10.cyan("postgresql://")}`
|
|
27550
27662
|
);
|
|
27551
27663
|
process.exit(1);
|
|
@@ -27553,7 +27665,7 @@ async function runInitCommand(name, options) {
|
|
|
27553
27665
|
if (candidate) {
|
|
27554
27666
|
databaseUrl = candidate;
|
|
27555
27667
|
if (existingDbUrl === candidate && !options.databaseUrl) {
|
|
27556
|
-
|
|
27668
|
+
p26.log.info(
|
|
27557
27669
|
`Using the existing DATABASE_URL from .env.local ${pc10.dim(`(${maskDbUrl(candidate)})`)}`
|
|
27558
27670
|
);
|
|
27559
27671
|
}
|
|
@@ -27573,7 +27685,7 @@ async function runInitCommand(name, options) {
|
|
|
27573
27685
|
persistDatabaseUrl(cwd, databaseUrl);
|
|
27574
27686
|
dismissVercelSignedInNote = flow.dismissSignedInNote;
|
|
27575
27687
|
} else if (options.yes) {
|
|
27576
|
-
|
|
27688
|
+
p26.log.error(
|
|
27577
27689
|
flow.ok ? "Created a Neon database, but DATABASE_URL could not be retrieved from Vercel." : "Vercel database provisioning did not complete."
|
|
27578
27690
|
);
|
|
27579
27691
|
process.exit(1);
|
|
@@ -27582,7 +27694,7 @@ async function runInitCommand(name, options) {
|
|
|
27582
27694
|
databaseUrl = await promptConnectionString();
|
|
27583
27695
|
persistDatabaseUrl(cwd, databaseUrl);
|
|
27584
27696
|
} else {
|
|
27585
|
-
|
|
27697
|
+
p26.log.info("Falling back to a manual database connection string.");
|
|
27586
27698
|
openBrowserVercelNeon();
|
|
27587
27699
|
databaseUrl = await promptConnectionString();
|
|
27588
27700
|
}
|
|
@@ -27596,11 +27708,11 @@ async function runInitCommand(name, options) {
|
|
|
27596
27708
|
} catch (error) {
|
|
27597
27709
|
const message = error instanceof Error ? error.message : String(error);
|
|
27598
27710
|
if (options.yes) {
|
|
27599
|
-
|
|
27711
|
+
p26.log.error(`Railway database provisioning failed: ${message}`);
|
|
27600
27712
|
process.exit(1);
|
|
27601
27713
|
}
|
|
27602
|
-
|
|
27603
|
-
|
|
27714
|
+
p26.log.warn(`Railway database provisioning failed: ${message}`);
|
|
27715
|
+
p26.log.info("Falling back to a manual database connection string.");
|
|
27604
27716
|
databaseUrl = await promptConnectionString();
|
|
27605
27717
|
}
|
|
27606
27718
|
}
|
|
@@ -27630,7 +27742,7 @@ async function runInitCommand(name, options) {
|
|
|
27630
27742
|
return { ok: true, config: config2 };
|
|
27631
27743
|
} catch (error) {
|
|
27632
27744
|
const message = error instanceof Error ? error.message : String(error);
|
|
27633
|
-
|
|
27745
|
+
p26.log.warn(`Railway bucket provisioning failed: ${message}`);
|
|
27634
27746
|
return { ok: false };
|
|
27635
27747
|
}
|
|
27636
27748
|
};
|
|
@@ -27644,7 +27756,7 @@ async function runInitCommand(name, options) {
|
|
|
27644
27756
|
if (storage === "r2") {
|
|
27645
27757
|
const missingR2Keys = R2_ENV_KEYS.filter((key) => !readEnvVar(cwd, key)?.trim());
|
|
27646
27758
|
if (options.yes && missingR2Keys.length > 0) {
|
|
27647
|
-
|
|
27759
|
+
p26.log.error(
|
|
27648
27760
|
`Cloudflare R2 is missing required environment variables: ${missingR2Keys.join(", ")}.`
|
|
27649
27761
|
);
|
|
27650
27762
|
process.exit(1);
|
|
@@ -27658,7 +27770,7 @@ async function runInitCommand(name, options) {
|
|
|
27658
27770
|
if (flow.ok && flow.config) {
|
|
27659
27771
|
mergeCollectedIntegrationConfig(flow.config);
|
|
27660
27772
|
} else if (options.yes) {
|
|
27661
|
-
|
|
27773
|
+
p26.log.error("Railway bucket provisioning did not complete.");
|
|
27662
27774
|
process.exit(1);
|
|
27663
27775
|
}
|
|
27664
27776
|
}
|
|
@@ -27677,10 +27789,10 @@ async function runInitCommand(name, options) {
|
|
|
27677
27789
|
});
|
|
27678
27790
|
collectedIntegrationConfig.overwriteKeys.add("BLOB_READ_WRITE_TOKEN");
|
|
27679
27791
|
} else if (options.yes) {
|
|
27680
|
-
|
|
27792
|
+
p26.log.error("Vercel Blob provisioning did not complete.");
|
|
27681
27793
|
process.exit(1);
|
|
27682
27794
|
} else {
|
|
27683
|
-
|
|
27795
|
+
p26.log.warn(
|
|
27684
27796
|
"Continuing without a Blob token \u2014 add BLOB_READ_WRITE_TOKEN to .env.local from the store on vercel.com/dashboard/stores."
|
|
27685
27797
|
);
|
|
27686
27798
|
collectedIntegrationConfig.sections.push({
|
|
@@ -27754,7 +27866,7 @@ async function runInitCommand(name, options) {
|
|
|
27754
27866
|
const nextConfigResult = scaffoldNextConfig({ cwd, nextMajorVersion });
|
|
27755
27867
|
s.clear();
|
|
27756
27868
|
if (nextConfigResult.status === "unsupported") {
|
|
27757
|
-
|
|
27869
|
+
p26.log.warn("The Next.js config could not be updated automatically \u2014 review it manually.");
|
|
27758
27870
|
}
|
|
27759
27871
|
const drizzleConfigPath = path52.join(cwd, "drizzle.config.ts");
|
|
27760
27872
|
if (!dbFiles.includes("drizzle.config.ts") && fs41.existsSync(drizzleConfigPath)) {
|
|
@@ -27765,20 +27877,20 @@ async function runInitCommand(name, options) {
|
|
|
27765
27877
|
readNamespacedTemplate("drizzle.config.ts", namespace),
|
|
27766
27878
|
"utf-8"
|
|
27767
27879
|
);
|
|
27768
|
-
|
|
27880
|
+
p26.log.success("Updated drizzle.config.ts");
|
|
27769
27881
|
} else if (!options.yes) {
|
|
27770
|
-
const overwrite = await
|
|
27882
|
+
const overwrite = await p26.confirm({
|
|
27771
27883
|
message: "drizzle.config.ts already exists. Overwrite with latest version?",
|
|
27772
27884
|
initialValue: true
|
|
27773
27885
|
});
|
|
27774
|
-
if (!
|
|
27886
|
+
if (!p26.isCancel(overwrite) && overwrite) {
|
|
27775
27887
|
const { readNamespacedTemplate } = await import("./template-reader-PVN53GS7.js");
|
|
27776
27888
|
fs41.writeFileSync(
|
|
27777
27889
|
drizzleConfigPath,
|
|
27778
27890
|
readNamespacedTemplate("drizzle.config.ts", namespace),
|
|
27779
27891
|
"utf-8"
|
|
27780
27892
|
);
|
|
27781
|
-
|
|
27893
|
+
p26.log.success("Updated drizzle.config.ts");
|
|
27782
27894
|
}
|
|
27783
27895
|
}
|
|
27784
27896
|
}
|
|
@@ -27803,8 +27915,8 @@ async function runInitCommand(name, options) {
|
|
|
27803
27915
|
s.stop("");
|
|
27804
27916
|
} else {
|
|
27805
27917
|
s.stop("Failed to install dependencies");
|
|
27806
|
-
|
|
27807
|
-
|
|
27918
|
+
p26.log.warn(depsResult.error ?? "Unknown error");
|
|
27919
|
+
p26.log.info(
|
|
27808
27920
|
`You can install them manually:
|
|
27809
27921
|
${pc10.cyan(`${pm} add ${depsResult.dependencies.join(" ")}`)}
|
|
27810
27922
|
${pc10.cyan(`${pm} add -D ${depsResult.devDeps.join(" ")}`)}`
|
|
@@ -27860,22 +27972,22 @@ async function runInitCommand(name, options) {
|
|
|
27860
27972
|
writeConfigFile(cwd, resolvedIntegrationInstallResult.config);
|
|
27861
27973
|
const usesLocalStorage = resolvedIntegrationInstallResult.config.storage.provider === "local";
|
|
27862
27974
|
for (const err of coreSchemasResult.errors) {
|
|
27863
|
-
|
|
27975
|
+
p26.log.warn(`Core schemas: ${err}`);
|
|
27864
27976
|
}
|
|
27865
27977
|
for (const warning of resolvedPresetInstallResult.warnings) {
|
|
27866
|
-
|
|
27978
|
+
p26.log.warn(warning);
|
|
27867
27979
|
}
|
|
27868
27980
|
for (const warning of resolvedIntegrationInstallResult.warnings) {
|
|
27869
|
-
|
|
27981
|
+
p26.log.warn(warning);
|
|
27870
27982
|
}
|
|
27871
27983
|
if (usesLocalStorage) {
|
|
27872
|
-
|
|
27984
|
+
p26.log.warn(
|
|
27873
27985
|
"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
27986
|
);
|
|
27875
27987
|
}
|
|
27876
27988
|
let dbPushed = false;
|
|
27877
27989
|
if (depsResult.success && options.skipMigration && hasDbUrl(cwd)) {
|
|
27878
|
-
|
|
27990
|
+
p26.log.info(`Skipping database schema push ${pc10.dim("(--skip-migration)")}`);
|
|
27879
27991
|
} else if (depsResult.success && hasDbUrl(cwd)) {
|
|
27880
27992
|
let driverReady = hasDrizzleKitPostgresDriverDependency(cwd);
|
|
27881
27993
|
if (!driverReady) {
|
|
@@ -27890,8 +28002,8 @@ async function runInitCommand(name, options) {
|
|
|
27890
28002
|
});
|
|
27891
28003
|
if (!driverResult.success) {
|
|
27892
28004
|
s.stop("Database push failed");
|
|
27893
|
-
|
|
27894
|
-
|
|
28005
|
+
p26.log.warn(driverResult.error ?? `Failed to install ${DRIZZLE_KIT_POSTGRES_DRIVER_DEP}`);
|
|
28006
|
+
p26.log.info(
|
|
27895
28007
|
`Install ${DRIZZLE_KIT_POSTGRES_DRIVER_DEP} manually, then run: ${pc10.cyan(drizzlePushCommand(pm))}`
|
|
27896
28008
|
);
|
|
27897
28009
|
} else {
|
|
@@ -27919,8 +28031,8 @@ async function runInitCommand(name, options) {
|
|
|
27919
28031
|
const verification = await verifyDatabaseReachable(cwd);
|
|
27920
28032
|
clearDbSpinner();
|
|
27921
28033
|
if (!verification.success) {
|
|
27922
|
-
|
|
27923
|
-
|
|
28034
|
+
p26.log.warn(verification.error);
|
|
28035
|
+
p26.log.error("Database was not reachable. Aborting setup.");
|
|
27924
28036
|
process.exit(1);
|
|
27925
28037
|
}
|
|
27926
28038
|
} else {
|
|
@@ -27933,12 +28045,12 @@ async function runInitCommand(name, options) {
|
|
|
27933
28045
|
s.stop("Database push failed");
|
|
27934
28046
|
}
|
|
27935
28047
|
const pushError = pushResult.error ?? "Unknown error";
|
|
27936
|
-
|
|
28048
|
+
p26.log.warn(pushError);
|
|
27937
28049
|
if (isDatabaseReachabilityError(pushError)) {
|
|
27938
|
-
|
|
28050
|
+
p26.log.error("Database was not reachable. Aborting setup.");
|
|
27939
28051
|
process.exit(1);
|
|
27940
28052
|
}
|
|
27941
|
-
|
|
28053
|
+
p26.log.info(`You can run it manually: ${pc10.cyan(drizzlePushCommand(pm))}`);
|
|
27942
28054
|
}
|
|
27943
28055
|
}
|
|
27944
28056
|
}
|
|
@@ -27947,7 +28059,7 @@ async function runInitCommand(name, options) {
|
|
|
27947
28059
|
let seedSuccess = false;
|
|
27948
28060
|
let adminAccountReady = false;
|
|
27949
28061
|
if (dbPushed && options.skipAdminCreation) {
|
|
27950
|
-
|
|
28062
|
+
p26.log.info(
|
|
27951
28063
|
`Skipping admin user creation ${pc10.dim(`(use ${betterstartExecCommand(pm, "seed")} later)`)}`
|
|
27952
28064
|
);
|
|
27953
28065
|
}
|
|
@@ -27959,14 +28071,14 @@ async function runInitCommand(name, options) {
|
|
|
27959
28071
|
const adminCheck = await checkExistingAdmin(cwd, adminDir, authBasePath);
|
|
27960
28072
|
s.clear();
|
|
27961
28073
|
if (adminCheck.error) {
|
|
27962
|
-
|
|
28074
|
+
p26.log.warn(`Could not verify existing admin account ${pc10.dim(`(${adminCheck.error})`)}`);
|
|
27963
28075
|
if (isDatabaseReachabilityError(adminCheck.error)) {
|
|
27964
|
-
|
|
28076
|
+
p26.log.error("Database was not reachable. Aborting setup.");
|
|
27965
28077
|
process.exit(1);
|
|
27966
28078
|
}
|
|
27967
28079
|
} else if (adminCheck.existingAdmin) {
|
|
27968
28080
|
const existingAdminLabel = formatAdminIdentity(adminCheck.existingAdmin);
|
|
27969
|
-
const adminAction = await
|
|
28081
|
+
const adminAction = await p26.select({
|
|
27970
28082
|
message: "Found an already existing admin account. Do you want to replace it or skip?",
|
|
27971
28083
|
options: [
|
|
27972
28084
|
{
|
|
@@ -27980,28 +28092,28 @@ async function runInitCommand(name, options) {
|
|
|
27980
28092
|
}
|
|
27981
28093
|
]
|
|
27982
28094
|
});
|
|
27983
|
-
if (
|
|
27984
|
-
|
|
28095
|
+
if (p26.isCancel(adminAction)) {
|
|
28096
|
+
p26.cancel("Setup cancelled.");
|
|
27985
28097
|
process.exit(0);
|
|
27986
28098
|
}
|
|
27987
28099
|
if (adminAction === "skip") {
|
|
27988
28100
|
adminAccountReady = true;
|
|
27989
|
-
|
|
28101
|
+
p26.log.info(`Keeping existing admin account ${pc10.dim(`(${existingAdminLabel})`)}`);
|
|
27990
28102
|
} else {
|
|
27991
28103
|
replaceExistingAdmin = true;
|
|
27992
28104
|
}
|
|
27993
28105
|
}
|
|
27994
28106
|
if (!adminAccountReady) {
|
|
27995
|
-
const credentials = await
|
|
28107
|
+
const credentials = await p26.group(
|
|
27996
28108
|
{
|
|
27997
|
-
email: () =>
|
|
28109
|
+
email: () => p26.text({
|
|
27998
28110
|
message: "Admin email",
|
|
27999
28111
|
placeholder: "admin@example.com",
|
|
28000
28112
|
validate: (v) => {
|
|
28001
28113
|
if (!v || !v.includes("@")) return "Please enter a valid email";
|
|
28002
28114
|
}
|
|
28003
28115
|
}),
|
|
28004
|
-
password: () =>
|
|
28116
|
+
password: () => p26.password({
|
|
28005
28117
|
message: "Admin password",
|
|
28006
28118
|
validate: (v) => {
|
|
28007
28119
|
if (!v || v.length < 8) return "Password must be at least 8 characters";
|
|
@@ -28010,14 +28122,14 @@ async function runInitCommand(name, options) {
|
|
|
28010
28122
|
},
|
|
28011
28123
|
{
|
|
28012
28124
|
onCancel: () => {
|
|
28013
|
-
|
|
28125
|
+
p26.cancel("Setup cancelled.");
|
|
28014
28126
|
process.exit(0);
|
|
28015
28127
|
}
|
|
28016
28128
|
}
|
|
28017
28129
|
);
|
|
28018
28130
|
seedEmail = credentials.email;
|
|
28019
28131
|
seedPassword = credentials.password;
|
|
28020
|
-
const credentialPromptRows = clackPromptRows("Admin email", credentials.email) + clackPromptRows("Admin password",
|
|
28132
|
+
const credentialPromptRows = clackPromptRows("Admin email", credentials.email) + clackPromptRows("Admin password", p26.S_PASSWORD_MASK.repeat(credentials.password.length));
|
|
28021
28133
|
let rowsBelowCredentialPrompts = 0;
|
|
28022
28134
|
let seedOverwriteMode = replaceExistingAdmin ? "admin" : void 0;
|
|
28023
28135
|
s.start(replaceExistingAdmin ? "Replacing admin user" : "Creating admin user");
|
|
@@ -28034,7 +28146,7 @@ async function runInitCommand(name, options) {
|
|
|
28034
28146
|
s.stop(existingAccountMessage);
|
|
28035
28147
|
rowsBelowCredentialPrompts += clackLogRows(existingAccountMessage);
|
|
28036
28148
|
const replaceAccountMessage = "Replace the existing account with this email?";
|
|
28037
|
-
const replace = await
|
|
28149
|
+
const replace = await p26.confirm({
|
|
28038
28150
|
message: replaceAccountMessage,
|
|
28039
28151
|
initialValue: false
|
|
28040
28152
|
});
|
|
@@ -28042,7 +28154,7 @@ async function runInitCommand(name, options) {
|
|
|
28042
28154
|
replaceAccountMessage,
|
|
28043
28155
|
replace === true ? "Yes" : "No"
|
|
28044
28156
|
);
|
|
28045
|
-
if (!
|
|
28157
|
+
if (!p26.isCancel(replace) && replace) {
|
|
28046
28158
|
seedOverwriteMode = "email";
|
|
28047
28159
|
s.start("Replacing admin user");
|
|
28048
28160
|
seedResult = await runSeed(
|
|
@@ -28064,14 +28176,14 @@ async function runInitCommand(name, options) {
|
|
|
28064
28176
|
adminAccountReady = true;
|
|
28065
28177
|
} else if (seedResult.error) {
|
|
28066
28178
|
s.stop(`Failed to create admin user`);
|
|
28067
|
-
|
|
28179
|
+
p26.note(
|
|
28068
28180
|
`${pc10.red(seedResult.error)}
|
|
28069
28181
|
|
|
28070
28182
|
Run manually: ${pc10.cyan(betterstartExecCommand(pm, "seed"))}`,
|
|
28071
28183
|
pc10.red("Seed failed")
|
|
28072
28184
|
);
|
|
28073
28185
|
if (isDatabaseReachabilityError(seedResult.error)) {
|
|
28074
|
-
|
|
28186
|
+
p26.log.error("Database was not reachable. Aborting setup.");
|
|
28075
28187
|
process.exit(1);
|
|
28076
28188
|
}
|
|
28077
28189
|
}
|
|
@@ -28113,10 +28225,10 @@ Run manually: ${pc10.cyan(betterstartExecCommand(pm, "seed"))}`,
|
|
|
28113
28225
|
deployedUrl = deployFlow.url;
|
|
28114
28226
|
if (!deployFlow.ok) {
|
|
28115
28227
|
if (options.yes) {
|
|
28116
|
-
|
|
28228
|
+
p26.log.error("Vercel deploy did not complete.");
|
|
28117
28229
|
process.exit(1);
|
|
28118
28230
|
}
|
|
28119
|
-
|
|
28231
|
+
p26.log.warn("Vercel deploy did not complete; continuing.");
|
|
28120
28232
|
}
|
|
28121
28233
|
} else if (deployProvider === "railway") {
|
|
28122
28234
|
try {
|
|
@@ -28134,29 +28246,29 @@ Run manually: ${pc10.cyan(betterstartExecCommand(pm, "seed"))}`,
|
|
|
28134
28246
|
});
|
|
28135
28247
|
deployedUrl = deployFlow.url;
|
|
28136
28248
|
if (!deployFlow.ok) {
|
|
28137
|
-
if (deployFlow.detail)
|
|
28249
|
+
if (deployFlow.detail) p26.log.message(pc10.dim(redactSecrets(deployFlow.detail)));
|
|
28138
28250
|
if (options.yes) {
|
|
28139
|
-
|
|
28251
|
+
p26.log.error("Railway deploy did not complete.");
|
|
28140
28252
|
process.exit(1);
|
|
28141
28253
|
}
|
|
28142
|
-
|
|
28254
|
+
p26.log.warn("Railway deploy did not complete; continuing.");
|
|
28143
28255
|
}
|
|
28144
28256
|
} catch (error) {
|
|
28145
28257
|
const message = error instanceof Error ? error.message : String(error);
|
|
28146
28258
|
if (options.yes) {
|
|
28147
|
-
|
|
28259
|
+
p26.log.error(`Railway deploy failed: ${message}`);
|
|
28148
28260
|
process.exit(1);
|
|
28149
28261
|
}
|
|
28150
|
-
|
|
28262
|
+
p26.log.warn(`Railway deploy failed: ${message}`);
|
|
28151
28263
|
}
|
|
28152
28264
|
}
|
|
28153
28265
|
if (!options.yes && !options.skipDevServerStart) {
|
|
28154
28266
|
const devCmd = runCommand(pm, "dev");
|
|
28155
|
-
const startDev = await
|
|
28267
|
+
const startDev = await p26.confirm({
|
|
28156
28268
|
message: "Start the development server?",
|
|
28157
28269
|
initialValue: true
|
|
28158
28270
|
});
|
|
28159
|
-
if (!
|
|
28271
|
+
if (!p26.isCancel(startDev) && startDev) {
|
|
28160
28272
|
disposeCancelGuard();
|
|
28161
28273
|
await startManagedDevServer(cwd, devCmd, adminLoginUrl, {
|
|
28162
28274
|
email: seedSuccess && seedEmail ? seedEmail : void 0,
|
|
@@ -28188,7 +28300,7 @@ Run manually: ${pc10.cyan(betterstartExecCommand(pm, "seed"))}`,
|
|
|
28188
28300
|
);
|
|
28189
28301
|
return;
|
|
28190
28302
|
}
|
|
28191
|
-
|
|
28303
|
+
p26.outro(`Admin ready at ${adminNamespace.routePath}`);
|
|
28192
28304
|
}
|
|
28193
28305
|
function isValidDbUrl(url) {
|
|
28194
28306
|
return url.startsWith("postgres://") || url.startsWith("postgresql://");
|
|
@@ -28581,7 +28693,7 @@ function printAdminReadyNote(state) {
|
|
|
28581
28693
|
} else if (state.adminEmail) {
|
|
28582
28694
|
lines.unshift(`Admin user: ${pc10.cyan(state.adminEmail)}`);
|
|
28583
28695
|
}
|
|
28584
|
-
|
|
28696
|
+
p26.note(lines.join("\n"), "Admin ready");
|
|
28585
28697
|
}
|
|
28586
28698
|
function shouldSuppressDevServerStartupLine(line) {
|
|
28587
28699
|
const plain = stripAnsi2(line).trim();
|
|
@@ -28693,7 +28805,7 @@ function startManagedDevServer(cwd, devCmd, adminLoginUrl, adminCredentials) {
|
|
|
28693
28805
|
|
|
28694
28806
|
// adapters/next/commands/list-integrations.ts
|
|
28695
28807
|
import path53 from "path";
|
|
28696
|
-
import * as
|
|
28808
|
+
import * as p27 from "@clack/prompts";
|
|
28697
28809
|
|
|
28698
28810
|
// core-engine/utils/table.ts
|
|
28699
28811
|
function renderTableRows(rows) {
|
|
@@ -28740,15 +28852,15 @@ async function runListIntegrationsCommand(options) {
|
|
|
28740
28852
|
integration.kind,
|
|
28741
28853
|
integration.description
|
|
28742
28854
|
]);
|
|
28743
|
-
|
|
28744
|
-
|
|
28855
|
+
p27.note(renderTableRows(rows).join("\n"), "BetterStart integrations");
|
|
28856
|
+
p27.outro(
|
|
28745
28857
|
`${installedIntegrations.size} installed, ${rows.length - installedIntegrations.size} available`
|
|
28746
28858
|
);
|
|
28747
28859
|
}
|
|
28748
28860
|
|
|
28749
28861
|
// adapters/next/commands/list-presets.ts
|
|
28750
28862
|
import path54 from "path";
|
|
28751
|
-
import * as
|
|
28863
|
+
import * as p28 from "@clack/prompts";
|
|
28752
28864
|
async function runListPresetsCommand(options) {
|
|
28753
28865
|
const cwd = options.cwd ? path54.resolve(options.cwd) : process.cwd();
|
|
28754
28866
|
if (options.json) {
|
|
@@ -28778,48 +28890,73 @@ async function runListPresetsCommand(options) {
|
|
|
28778
28890
|
preset.kind,
|
|
28779
28891
|
preset.description
|
|
28780
28892
|
]);
|
|
28781
|
-
|
|
28782
|
-
|
|
28893
|
+
p28.note(renderTableRows(rows).join("\n"), "BetterStart presets");
|
|
28894
|
+
p28.outro(`${installedPresets.size} installed, ${rows.length - installedPresets.size} available`);
|
|
28783
28895
|
}
|
|
28784
28896
|
|
|
28785
|
-
// adapters/next/commands/
|
|
28897
|
+
// adapters/next/commands/menu-choices.ts
|
|
28786
28898
|
import path55 from "path";
|
|
28787
|
-
|
|
28899
|
+
async function listInstallableChoices(cwd) {
|
|
28900
|
+
const config = await resolveConfigOrExit(cwd);
|
|
28901
|
+
const installedPresets = new Set(config.presets.installed);
|
|
28902
|
+
const installedIntegrations = new Set(config.integrations.installed);
|
|
28903
|
+
return {
|
|
28904
|
+
presets: listAvailablePresets().map((preset) => ({
|
|
28905
|
+
id: preset.id,
|
|
28906
|
+
description: preset.description,
|
|
28907
|
+
installed: installedPresets.has(preset.id)
|
|
28908
|
+
})),
|
|
28909
|
+
integrations: listAvailableIntegrations().map((integration) => ({
|
|
28910
|
+
id: integration.id,
|
|
28911
|
+
description: integration.description,
|
|
28912
|
+
installed: installedIntegrations.has(integration.id)
|
|
28913
|
+
}))
|
|
28914
|
+
};
|
|
28915
|
+
}
|
|
28916
|
+
async function listSchemaChoices(cwd) {
|
|
28917
|
+
const config = await resolveConfigOrExit(cwd);
|
|
28918
|
+
const paths = resolveProjectPaths(config);
|
|
28919
|
+
return listSchemaNames(path55.join(cwd, ...paths.schemasDir.split("/")));
|
|
28920
|
+
}
|
|
28921
|
+
|
|
28922
|
+
// adapters/next/commands/remove.ts
|
|
28923
|
+
import path56 from "path";
|
|
28924
|
+
import * as p29 from "@clack/prompts";
|
|
28788
28925
|
async function runRemoveCommand(items, options) {
|
|
28789
28926
|
const removeIntegrationsMode = Boolean(options.integration);
|
|
28790
28927
|
if (!removeIntegrationsMode && items.includes("core")) {
|
|
28791
|
-
|
|
28928
|
+
p29.log.error("The core Admin cannot be removed.");
|
|
28792
28929
|
process.exit(1);
|
|
28793
28930
|
}
|
|
28794
28931
|
const presetIds = items.filter(isPresetId);
|
|
28795
28932
|
const integrationIds = items.filter(isIntegrationId);
|
|
28796
28933
|
if (!removeIntegrationsMode && integrationIds.length > 0) {
|
|
28797
|
-
|
|
28934
|
+
p29.log.error(
|
|
28798
28935
|
`Integration IDs require --integration. Run \`betterstart remove --integration ${integrationIds.join(" ")}\`.`
|
|
28799
28936
|
);
|
|
28800
28937
|
process.exit(1);
|
|
28801
28938
|
}
|
|
28802
28939
|
if (removeIntegrationsMode && presetIds.length > 0) {
|
|
28803
|
-
|
|
28940
|
+
p29.log.error(`Preset IDs cannot be removed with --integration: ${presetIds.join(", ")}`);
|
|
28804
28941
|
process.exit(1);
|
|
28805
28942
|
}
|
|
28806
28943
|
const invalidItems = removeIntegrationsMode ? items.filter((integrationId) => !isIntegrationId(integrationId)) : items.filter((presetId) => !isPresetId(presetId));
|
|
28807
28944
|
if (invalidItems.length > 0) {
|
|
28808
|
-
|
|
28945
|
+
p29.log.error(
|
|
28809
28946
|
removeIntegrationsMode ? formatUnknownIntegrationMessage(invalidItems) : formatUnknownPresetMessage(invalidItems)
|
|
28810
28947
|
);
|
|
28811
28948
|
process.exit(1);
|
|
28812
28949
|
}
|
|
28813
|
-
const cwd = options.cwd ?
|
|
28950
|
+
const cwd = options.cwd ? path56.resolve(options.cwd) : process.cwd();
|
|
28814
28951
|
const config = await resolveConfigOrExit(cwd);
|
|
28815
28952
|
const pm = detectPackageManager(cwd);
|
|
28816
28953
|
if (!options.force) {
|
|
28817
|
-
const confirmed = await
|
|
28954
|
+
const confirmed = await p29.confirm({
|
|
28818
28955
|
message: `Remove ${removeIntegrationsMode ? "integration" : "preset"}${items.length === 1 ? "" : "s"} ${items.join(", ")}?`,
|
|
28819
28956
|
initialValue: false
|
|
28820
28957
|
});
|
|
28821
|
-
if (
|
|
28822
|
-
|
|
28958
|
+
if (p29.isCancel(confirmed) || !confirmed) {
|
|
28959
|
+
p29.cancel(`${removeIntegrationsMode ? "Integration" : "Preset"} removal cancelled.`);
|
|
28823
28960
|
process.exit(0);
|
|
28824
28961
|
}
|
|
28825
28962
|
}
|
|
@@ -28832,13 +28969,13 @@ async function runRemoveCommand(items, options) {
|
|
|
28832
28969
|
});
|
|
28833
28970
|
writeConfigFile(cwd, result2.config);
|
|
28834
28971
|
if (result2.removed.length === 0) {
|
|
28835
|
-
|
|
28972
|
+
p29.outro("No integrations were removed.");
|
|
28836
28973
|
return;
|
|
28837
28974
|
}
|
|
28838
28975
|
if (result2.warnings.length > 0) {
|
|
28839
|
-
|
|
28976
|
+
p29.note(result2.warnings.join("\n"), "Warnings");
|
|
28840
28977
|
}
|
|
28841
|
-
|
|
28978
|
+
p29.outro(
|
|
28842
28979
|
`Removed integration${result2.removed.length === 1 ? "" : "s"}: ${result2.removed.join(", ")}`
|
|
28843
28980
|
);
|
|
28844
28981
|
return;
|
|
@@ -28851,37 +28988,37 @@ async function runRemoveCommand(items, options) {
|
|
|
28851
28988
|
});
|
|
28852
28989
|
writeConfigFile(cwd, result.config);
|
|
28853
28990
|
if (result.removed.length === 0) {
|
|
28854
|
-
|
|
28991
|
+
p29.outro("No presets were removed.");
|
|
28855
28992
|
return;
|
|
28856
28993
|
}
|
|
28857
28994
|
if (result.warnings.length > 0) {
|
|
28858
|
-
|
|
28995
|
+
p29.note(result.warnings.join("\n"), "Warnings");
|
|
28859
28996
|
}
|
|
28860
|
-
|
|
28997
|
+
p29.outro(`Removed preset${result.removed.length === 1 ? "" : "s"}: ${result.removed.join(", ")}`);
|
|
28861
28998
|
}
|
|
28862
28999
|
|
|
28863
29000
|
// adapters/next/commands/remove-schema.ts
|
|
28864
29001
|
import fs42 from "fs";
|
|
28865
|
-
import
|
|
29002
|
+
import path57 from "path";
|
|
28866
29003
|
import * as clack3 from "@clack/prompts";
|
|
28867
29004
|
function removePath2(cwd, filePath) {
|
|
28868
|
-
const fullPath =
|
|
29005
|
+
const fullPath = path57.join(cwd, ...filePath.split("/"));
|
|
28869
29006
|
const existed = fs42.existsSync(fullPath);
|
|
28870
29007
|
fs42.rmSync(fullPath, { recursive: true, force: true });
|
|
28871
29008
|
return existed;
|
|
28872
29009
|
}
|
|
28873
29010
|
function cleanupEmptyDirs3(cwd, deletedPaths, configPaths) {
|
|
28874
29011
|
const stopRoots = /* @__PURE__ */ new Set([
|
|
28875
|
-
|
|
28876
|
-
|
|
28877
|
-
|
|
28878
|
-
|
|
29012
|
+
path57.join(cwd, ...configPaths.adminDir.split("/")),
|
|
29013
|
+
path57.join(cwd, ...configPaths.adminNavigationDir.split("/")),
|
|
29014
|
+
path57.join(cwd, ...configPaths.adminWebhookEventsDir.split("/")),
|
|
29015
|
+
path57.join(cwd, ...configPaths.pagesDir.split("/"))
|
|
28879
29016
|
]);
|
|
28880
29017
|
for (const deletedPath of deletedPaths) {
|
|
28881
|
-
let current =
|
|
29018
|
+
let current = path57.dirname(path57.join(cwd, ...deletedPath.split("/")));
|
|
28882
29019
|
while (!stopRoots.has(current)) {
|
|
28883
29020
|
if (!fs42.existsSync(current)) {
|
|
28884
|
-
current =
|
|
29021
|
+
current = path57.dirname(current);
|
|
28885
29022
|
continue;
|
|
28886
29023
|
}
|
|
28887
29024
|
const entries = fs42.readdirSync(current);
|
|
@@ -28889,7 +29026,7 @@ function cleanupEmptyDirs3(cwd, deletedPaths, configPaths) {
|
|
|
28889
29026
|
break;
|
|
28890
29027
|
}
|
|
28891
29028
|
fs42.rmdirSync(current);
|
|
28892
|
-
current =
|
|
29029
|
+
current = path57.dirname(current);
|
|
28893
29030
|
}
|
|
28894
29031
|
}
|
|
28895
29032
|
}
|
|
@@ -28905,7 +29042,7 @@ function resolveSchemaOwnerForRemoval(cwd, schemaName) {
|
|
|
28905
29042
|
}
|
|
28906
29043
|
async function runRemoveSchemaCommand(schemaName, options) {
|
|
28907
29044
|
const owner = resolveSchemaOwnerForRemoval(
|
|
28908
|
-
options.cwd ?
|
|
29045
|
+
options.cwd ? path57.resolve(options.cwd) : process.cwd(),
|
|
28909
29046
|
schemaName
|
|
28910
29047
|
);
|
|
28911
29048
|
if (owner === "core") {
|
|
@@ -28918,7 +29055,7 @@ async function runRemoveSchemaCommand(schemaName, options) {
|
|
|
28918
29055
|
clack3.log.error(`"${schemaName}" is owned by ${owner}. Remove the owning preset instead.`);
|
|
28919
29056
|
process.exit(1);
|
|
28920
29057
|
}
|
|
28921
|
-
const cwd = options.cwd ?
|
|
29058
|
+
const cwd = options.cwd ? path57.resolve(options.cwd) : process.cwd();
|
|
28922
29059
|
const config = await resolveConfigOrExit(cwd);
|
|
28923
29060
|
const paths = resolveProjectPaths(config);
|
|
28924
29061
|
const manifest = loadManifest(cwd, schemaName);
|
|
@@ -28931,7 +29068,7 @@ async function runRemoveSchemaCommand(schemaName, options) {
|
|
|
28931
29068
|
process.exit(1);
|
|
28932
29069
|
}
|
|
28933
29070
|
if (!options.force) {
|
|
28934
|
-
if (!
|
|
29071
|
+
if (!isInteractiveSession()) {
|
|
28935
29072
|
clack3.log.error(
|
|
28936
29073
|
`Removing generated files for ${schemaName} needs confirmation. Re-run with --force.`
|
|
28937
29074
|
);
|
|
@@ -28954,7 +29091,7 @@ async function runRemoveSchemaCommand(schemaName, options) {
|
|
|
28954
29091
|
}
|
|
28955
29092
|
const loaded = (() => {
|
|
28956
29093
|
try {
|
|
28957
|
-
return loadSchema(
|
|
29094
|
+
return loadSchema(path57.join(cwd, ...paths.schemasDir.split("/")), schemaName);
|
|
28958
29095
|
} catch {
|
|
28959
29096
|
return null;
|
|
28960
29097
|
}
|
|
@@ -28999,8 +29136,8 @@ Schema JSON preserved.`
|
|
|
28999
29136
|
|
|
29000
29137
|
// adapters/next/commands/uninstall.ts
|
|
29001
29138
|
import fs44 from "fs";
|
|
29002
|
-
import
|
|
29003
|
-
import * as
|
|
29139
|
+
import path58 from "path";
|
|
29140
|
+
import * as p30 from "@clack/prompts";
|
|
29004
29141
|
import pc11 from "picocolors";
|
|
29005
29142
|
|
|
29006
29143
|
// adapters/next/commands/uninstall-cleaners.ts
|
|
@@ -29149,7 +29286,7 @@ function findMainCss2(cwd) {
|
|
|
29149
29286
|
"globals.css"
|
|
29150
29287
|
];
|
|
29151
29288
|
for (const candidate of candidates) {
|
|
29152
|
-
const filePath =
|
|
29289
|
+
const filePath = path58.join(cwd, candidate);
|
|
29153
29290
|
if (fs44.existsSync(filePath)) return filePath;
|
|
29154
29291
|
}
|
|
29155
29292
|
return void 0;
|
|
@@ -29166,13 +29303,13 @@ function isCLICreatedBiome(biomePath) {
|
|
|
29166
29303
|
function buildUninstallPlan(cwd, namespaceValue) {
|
|
29167
29304
|
const steps = [];
|
|
29168
29305
|
const namespace = resolveAdminNamespace(namespaceValue);
|
|
29169
|
-
const hasSrc = fs44.existsSync(
|
|
29306
|
+
const hasSrc = fs44.existsSync(path58.join(cwd, "src"));
|
|
29170
29307
|
const appBase = hasSrc ? "src/app" : "app";
|
|
29171
29308
|
const dirs = [];
|
|
29172
|
-
const adminDir =
|
|
29173
|
-
const legacyAdminDir =
|
|
29174
|
-
const adminRouteGroup =
|
|
29175
|
-
const legacyAdminRouteGroup =
|
|
29309
|
+
const adminDir = path58.join(cwd, namespace.segment);
|
|
29310
|
+
const legacyAdminDir = path58.join(cwd, "admin");
|
|
29311
|
+
const adminRouteGroup = path58.join(cwd, appBase, namespace.routeGroup);
|
|
29312
|
+
const legacyAdminRouteGroup = path58.join(cwd, appBase, "(admin)");
|
|
29176
29313
|
if (fs44.existsSync(adminDir)) dirs.push(`${namespace.segment}/`);
|
|
29177
29314
|
if (namespace.segment !== "admin" && fs44.existsSync(legacyAdminDir)) dirs.push("admin/");
|
|
29178
29315
|
if (fs44.existsSync(adminRouteGroup)) dirs.push(`${appBase}/${namespace.routeGroup}/`);
|
|
@@ -29200,9 +29337,9 @@ function buildUninstallPlan(cwd, namespaceValue) {
|
|
|
29200
29337
|
const configFiles = [];
|
|
29201
29338
|
const configPaths = [];
|
|
29202
29339
|
const candidates = [
|
|
29203
|
-
[CONFIG_FILE_NAME,
|
|
29204
|
-
["drizzle.config.ts",
|
|
29205
|
-
["ADMIN.md",
|
|
29340
|
+
[CONFIG_FILE_NAME, path58.join(cwd, CONFIG_FILE_NAME)],
|
|
29341
|
+
["drizzle.config.ts", path58.join(cwd, "drizzle.config.ts")],
|
|
29342
|
+
["ADMIN.md", path58.join(cwd, "ADMIN.md")]
|
|
29206
29343
|
];
|
|
29207
29344
|
for (const [label, fullPath] of candidates) {
|
|
29208
29345
|
if (fs44.existsSync(fullPath)) {
|
|
@@ -29210,7 +29347,7 @@ function buildUninstallPlan(cwd, namespaceValue) {
|
|
|
29210
29347
|
configPaths.push(fullPath);
|
|
29211
29348
|
}
|
|
29212
29349
|
}
|
|
29213
|
-
const biomePath =
|
|
29350
|
+
const biomePath = path58.join(cwd, "biome.json");
|
|
29214
29351
|
if (isCLICreatedBiome(biomePath)) {
|
|
29215
29352
|
configFiles.push("biome.json (CLI-created)");
|
|
29216
29353
|
configPaths.push(biomePath);
|
|
@@ -29222,13 +29359,13 @@ function buildUninstallPlan(cwd, namespaceValue) {
|
|
|
29222
29359
|
count: configFiles.length,
|
|
29223
29360
|
unit: configFiles.length === 1 ? "file" : "files",
|
|
29224
29361
|
execute() {
|
|
29225
|
-
for (const
|
|
29226
|
-
if (fs44.existsSync(
|
|
29362
|
+
for (const p32 of configPaths) {
|
|
29363
|
+
if (fs44.existsSync(p32)) fs44.unlinkSync(p32);
|
|
29227
29364
|
}
|
|
29228
29365
|
}
|
|
29229
29366
|
});
|
|
29230
29367
|
}
|
|
29231
|
-
const tsconfigPath =
|
|
29368
|
+
const tsconfigPath = path58.join(cwd, "tsconfig.json");
|
|
29232
29369
|
if (fs44.existsSync(tsconfigPath)) {
|
|
29233
29370
|
const content = fs44.readFileSync(tsconfigPath, "utf-8");
|
|
29234
29371
|
const aliasMatches = [
|
|
@@ -29255,7 +29392,7 @@ function buildUninstallPlan(cwd, namespaceValue) {
|
|
|
29255
29392
|
(l) => new RegExp(`^@source\\s+"[^"]*(?:admin|${namespace.segment})[^"]*";\\s*$`).test(l)
|
|
29256
29393
|
);
|
|
29257
29394
|
if (sourceLines.length > 0) {
|
|
29258
|
-
const relCss =
|
|
29395
|
+
const relCss = path58.relative(cwd, cssFile);
|
|
29259
29396
|
steps.push({
|
|
29260
29397
|
label: `CSS @source lines (${relCss})`,
|
|
29261
29398
|
items: [`@source lines in ${relCss}`],
|
|
@@ -29267,7 +29404,7 @@ function buildUninstallPlan(cwd, namespaceValue) {
|
|
|
29267
29404
|
});
|
|
29268
29405
|
}
|
|
29269
29406
|
}
|
|
29270
|
-
const envPath =
|
|
29407
|
+
const envPath = path58.join(cwd, ".env.local");
|
|
29271
29408
|
if (fs44.existsSync(envPath)) {
|
|
29272
29409
|
const envContent = fs44.readFileSync(envPath, "utf-8");
|
|
29273
29410
|
const bsVars = envContent.split("\n").filter((l) => l.trim().match(/^BETTERSTART_\w+=/)).map((l) => l.split("=")[0]);
|
|
@@ -29286,8 +29423,8 @@ function buildUninstallPlan(cwd, namespaceValue) {
|
|
|
29286
29423
|
return steps;
|
|
29287
29424
|
}
|
|
29288
29425
|
async function runUninstallCommand(options) {
|
|
29289
|
-
const cwd = options.cwd ?
|
|
29290
|
-
|
|
29426
|
+
const cwd = options.cwd ? path58.resolve(options.cwd) : process.cwd();
|
|
29427
|
+
p30.intro(pc11.bgRed(pc11.white(" BetterStart Uninstall ")));
|
|
29291
29428
|
let namespace = DEFAULT_ADMIN_NAMESPACE;
|
|
29292
29429
|
try {
|
|
29293
29430
|
const config = await resolveConfig(cwd);
|
|
@@ -29296,8 +29433,8 @@ async function runUninstallCommand(options) {
|
|
|
29296
29433
|
}
|
|
29297
29434
|
const steps = buildUninstallPlan(cwd, namespace);
|
|
29298
29435
|
if (steps.length === 0) {
|
|
29299
|
-
|
|
29300
|
-
|
|
29436
|
+
p30.log.success(`${pc11.green("\u2713")} Nothing to remove \u2014 project is already clean.`);
|
|
29437
|
+
p30.outro("Project already clean");
|
|
29301
29438
|
return;
|
|
29302
29439
|
}
|
|
29303
29440
|
const planLines = steps.map((step) => {
|
|
@@ -29305,14 +29442,14 @@ async function runUninstallCommand(options) {
|
|
|
29305
29442
|
const countLabel = pc11.dim(`${step.count} ${step.unit}`);
|
|
29306
29443
|
return `${pc11.red("\u2717")} ${names} ${countLabel}`;
|
|
29307
29444
|
});
|
|
29308
|
-
|
|
29445
|
+
p30.note(planLines.join("\n"), "Uninstall plan");
|
|
29309
29446
|
if (!options.force) {
|
|
29310
|
-
const confirmed = await
|
|
29447
|
+
const confirmed = await p30.confirm({
|
|
29311
29448
|
message: "Proceed with uninstall?",
|
|
29312
29449
|
initialValue: false
|
|
29313
29450
|
});
|
|
29314
|
-
if (
|
|
29315
|
-
|
|
29451
|
+
if (p30.isCancel(confirmed) || !confirmed) {
|
|
29452
|
+
p30.cancel("Uninstall cancelled.");
|
|
29316
29453
|
process.exit(0);
|
|
29317
29454
|
}
|
|
29318
29455
|
}
|
|
@@ -29324,14 +29461,14 @@ async function runUninstallCommand(options) {
|
|
|
29324
29461
|
}
|
|
29325
29462
|
const parts = steps.map((step) => `${step.count} ${step.unit}`);
|
|
29326
29463
|
s.stop(`Removed ${parts.join(", ")}`);
|
|
29327
|
-
|
|
29328
|
-
|
|
29464
|
+
p30.note(pc11.dim("Database tables were NOT dropped \u2014 drop them manually if needed."), "Next steps");
|
|
29465
|
+
p30.outro("Uninstall complete");
|
|
29329
29466
|
}
|
|
29330
29467
|
|
|
29331
29468
|
// adapters/next/commands/update-component.ts
|
|
29332
29469
|
import { execFileSync as execFileSync6 } from "child_process";
|
|
29333
29470
|
import fs45 from "fs";
|
|
29334
|
-
import
|
|
29471
|
+
import path59 from "path";
|
|
29335
29472
|
import * as clack4 from "@clack/prompts";
|
|
29336
29473
|
import fsExtra from "fs-extra";
|
|
29337
29474
|
var STATIC_CUSTOM_DEPENDENCIES = {
|
|
@@ -29592,14 +29729,14 @@ function copyNamespacedDirectory(srcDir, destDir, namespace) {
|
|
|
29592
29729
|
const entries = fs45.readdirSync(srcDir, { withFileTypes: true });
|
|
29593
29730
|
for (const entry of entries) {
|
|
29594
29731
|
const namespacedName = applyAdminNamespaceToPath(entry.name, namespace);
|
|
29595
|
-
const srcPath =
|
|
29596
|
-
const destPath =
|
|
29732
|
+
const srcPath = path59.join(srcDir, entry.name);
|
|
29733
|
+
const destPath = path59.join(destDir, namespacedName);
|
|
29597
29734
|
if (entry.isDirectory()) {
|
|
29598
29735
|
fsExtra.ensureDirSync(destPath);
|
|
29599
29736
|
copyNamespacedDirectory(srcPath, destPath, namespace);
|
|
29600
29737
|
continue;
|
|
29601
29738
|
}
|
|
29602
|
-
fsExtra.ensureDirSync(
|
|
29739
|
+
fsExtra.ensureDirSync(path59.dirname(destPath));
|
|
29603
29740
|
writeNamespacedFile(srcPath, destPath, namespace);
|
|
29604
29741
|
}
|
|
29605
29742
|
}
|
|
@@ -29610,7 +29747,7 @@ function hasIntegration(config, integrationId) {
|
|
|
29610
29747
|
return config.integrations.installed.includes(integrationId);
|
|
29611
29748
|
}
|
|
29612
29749
|
function readProjectPackageJson2(cwd) {
|
|
29613
|
-
const pkgPath =
|
|
29750
|
+
const pkgPath = path59.join(cwd, "package.json");
|
|
29614
29751
|
if (!fs45.existsSync(pkgPath)) return null;
|
|
29615
29752
|
try {
|
|
29616
29753
|
return JSON.parse(fs45.readFileSync(pkgPath, "utf-8"));
|
|
@@ -31146,12 +31283,12 @@ function getStaticAssetComponentEntries(assetDirectory) {
|
|
|
31146
31283
|
continue;
|
|
31147
31284
|
}
|
|
31148
31285
|
const indexFile = ["index.tsx", "index.ts"].find(
|
|
31149
|
-
(file) => fs45.existsSync(
|
|
31286
|
+
(file) => fs45.existsSync(path59.join(assetDir, entry.name, file))
|
|
31150
31287
|
);
|
|
31151
31288
|
if (indexFile) {
|
|
31152
31289
|
components.push({
|
|
31153
31290
|
name: entry.name,
|
|
31154
|
-
file:
|
|
31291
|
+
file: path59.join(entry.name, indexFile)
|
|
31155
31292
|
});
|
|
31156
31293
|
}
|
|
31157
31294
|
}
|
|
@@ -31160,20 +31297,20 @@ function getStaticAssetComponentEntries(assetDirectory) {
|
|
|
31160
31297
|
function findStaticAssetFile(assetDir, componentName) {
|
|
31161
31298
|
if (!fs45.existsSync(assetDir)) return void 0;
|
|
31162
31299
|
const isNestedComponentName = /[\\/]/.test(componentName);
|
|
31163
|
-
const nestedComponentName = componentName.split(/[\\/]/).filter(Boolean).join(
|
|
31164
|
-
if (isNestedComponentName && nestedComponentName && !
|
|
31300
|
+
const nestedComponentName = componentName.split(/[\\/]/).filter(Boolean).join(path59.sep);
|
|
31301
|
+
if (isNestedComponentName && nestedComponentName && !path59.isAbsolute(componentName) && !nestedComponentName.split(path59.sep).includes("..")) {
|
|
31165
31302
|
for (const extension of [".tsx", ".ts"]) {
|
|
31166
31303
|
const relPath = `${nestedComponentName}${extension}`;
|
|
31167
|
-
const filePath =
|
|
31304
|
+
const filePath = path59.join(assetDir, relPath);
|
|
31168
31305
|
if (fs45.existsSync(filePath) && fs45.statSync(filePath).isFile()) {
|
|
31169
31306
|
return relPath;
|
|
31170
31307
|
}
|
|
31171
31308
|
}
|
|
31172
31309
|
}
|
|
31173
|
-
if (!isNestedComponentName && !componentName.includes("..") && !
|
|
31310
|
+
if (!isNestedComponentName && !componentName.includes("..") && !path59.isAbsolute(componentName)) {
|
|
31174
31311
|
for (const extension of [".tsx", ".ts"]) {
|
|
31175
|
-
const relPath =
|
|
31176
|
-
const filePath =
|
|
31312
|
+
const relPath = path59.join(componentName, `index${extension}`);
|
|
31313
|
+
const filePath = path59.join(assetDir, relPath);
|
|
31177
31314
|
if (fs45.existsSync(filePath) && fs45.statSync(filePath).isFile()) {
|
|
31178
31315
|
return relPath;
|
|
31179
31316
|
}
|
|
@@ -31198,7 +31335,7 @@ function getAllComponentNamesForConfig(config) {
|
|
|
31198
31335
|
return [.../* @__PURE__ */ new Set([...staticUi, ...staticCustom, ...templateKeys, "tiptap"])].sort();
|
|
31199
31336
|
}
|
|
31200
31337
|
async function runUpdateCommand(components, options) {
|
|
31201
|
-
const cwd = options.cwd ?
|
|
31338
|
+
const cwd = options.cwd ? path59.resolve(options.cwd) : process.cwd();
|
|
31202
31339
|
const normalizedOnly = normalizeShadcnPresetOnly(options.only);
|
|
31203
31340
|
validateShadcnPresetOptions(components, options);
|
|
31204
31341
|
if (options.json && !options.list) {
|
|
@@ -31259,7 +31396,7 @@ async function runUpdateCommand(components, options) {
|
|
|
31259
31396
|
return;
|
|
31260
31397
|
}
|
|
31261
31398
|
const config = await resolveConfigOrExit(cwd);
|
|
31262
|
-
const admin =
|
|
31399
|
+
const admin = path59.resolve(cwd, config.paths.admin);
|
|
31263
31400
|
if (!fs45.existsSync(admin)) {
|
|
31264
31401
|
clack4.cancel(
|
|
31265
31402
|
`Admin directory not found at ${config.paths.admin}. Run 'betterstart init' first.`
|
|
@@ -31314,7 +31451,7 @@ async function runUpdateCommand(components, options) {
|
|
|
31314
31451
|
}
|
|
31315
31452
|
const { relPath, content } = applyNamespaceToTemplateEntry(entry, config, cwd);
|
|
31316
31453
|
const baseDir = entry.base === "cwd" ? cwd : admin;
|
|
31317
|
-
const destPath =
|
|
31454
|
+
const destPath = path59.join(baseDir, relPath);
|
|
31318
31455
|
if (entry.preserveExisting && fs45.existsSync(destPath)) {
|
|
31319
31456
|
clack4.log.info(`Preserved ${relPath}`);
|
|
31320
31457
|
updatedTemplateNames.add(name);
|
|
@@ -31324,7 +31461,7 @@ async function runUpdateCommand(components, options) {
|
|
|
31324
31461
|
pendingWrites.push({
|
|
31325
31462
|
displayPath: relPath,
|
|
31326
31463
|
write: () => {
|
|
31327
|
-
fsExtra.ensureDirSync(
|
|
31464
|
+
fsExtra.ensureDirSync(path59.dirname(destPath));
|
|
31328
31465
|
fs45.writeFileSync(destPath, content, "utf-8");
|
|
31329
31466
|
clack4.log.success(`Updated ${relPath}`);
|
|
31330
31467
|
}
|
|
@@ -31356,20 +31493,20 @@ async function runUpdateCommand(components, options) {
|
|
|
31356
31493
|
}
|
|
31357
31494
|
const namespace = config.frameworkConfig.next.namespace;
|
|
31358
31495
|
const namespacedAssetFile = applyAdminNamespaceToPath(assetFile, namespace);
|
|
31359
|
-
const destPath =
|
|
31496
|
+
const destPath = path59.join(admin, "components", assetDirectory, namespacedAssetFile);
|
|
31360
31497
|
pendingWrites.push({
|
|
31361
31498
|
displayPath: `components/${assetDirectory}/${namespacedAssetFile}`,
|
|
31362
31499
|
write: () => {
|
|
31363
|
-
fsExtra.ensureDirSync(
|
|
31364
|
-
writeNamespacedFile(
|
|
31500
|
+
fsExtra.ensureDirSync(path59.dirname(destPath));
|
|
31501
|
+
writeNamespacedFile(path59.join(assetDir, assetFile), destPath, namespace);
|
|
31365
31502
|
clack4.log.success(`Updated components/${assetDirectory}/${namespacedAssetFile}`);
|
|
31366
31503
|
}
|
|
31367
31504
|
});
|
|
31368
31505
|
if (assetDirectory === "custom") {
|
|
31369
|
-
const assetSubdir =
|
|
31506
|
+
const assetSubdir = path59.join(assetDir, name);
|
|
31370
31507
|
if (fs45.existsSync(assetSubdir) && fs45.statSync(assetSubdir).isDirectory()) {
|
|
31371
31508
|
const namespacedName = applyAdminNamespaceToPath(name, namespace);
|
|
31372
|
-
const destSubdir =
|
|
31509
|
+
const destSubdir = path59.join(admin, "components", assetDirectory, namespacedName);
|
|
31373
31510
|
pendingWrites.push({
|
|
31374
31511
|
displayPath: `components/${assetDirectory}/${namespacedName}/ (template files)`,
|
|
31375
31512
|
write: () => {
|
|
@@ -31404,19 +31541,19 @@ async function runUpdateCommand(components, options) {
|
|
|
31404
31541
|
"content-editor"
|
|
31405
31542
|
);
|
|
31406
31543
|
const namespace = config.frameworkConfig.next.namespace;
|
|
31407
|
-
const destBaseDir =
|
|
31544
|
+
const destBaseDir = path59.join(admin, "components", "custom", "content-editor");
|
|
31408
31545
|
if (!fs45.existsSync(srcBaseDir)) {
|
|
31409
31546
|
return false;
|
|
31410
31547
|
}
|
|
31411
31548
|
const dirsToCopy = [];
|
|
31412
31549
|
for (const directory of TIPTAP_CONTENT_EDITOR_DIRECTORIES) {
|
|
31413
|
-
const srcDir =
|
|
31550
|
+
const srcDir = path59.join(srcBaseDir, directory);
|
|
31414
31551
|
if (!fs45.existsSync(srcDir)) {
|
|
31415
31552
|
continue;
|
|
31416
31553
|
}
|
|
31417
31554
|
dirsToCopy.push({
|
|
31418
31555
|
srcDir,
|
|
31419
|
-
destDir:
|
|
31556
|
+
destDir: path59.join(destBaseDir, applyAdminNamespaceToPath(directory, namespace))
|
|
31420
31557
|
});
|
|
31421
31558
|
}
|
|
31422
31559
|
if (dirsToCopy.length === 0) {
|
|
@@ -31430,7 +31567,7 @@ async function runUpdateCommand(components, options) {
|
|
|
31430
31567
|
copyNamespacedDirectory(srcDir, destDir, namespace);
|
|
31431
31568
|
}
|
|
31432
31569
|
clack4.log.success("Updated components/custom/content-editor/tiptap-*/ (template files)");
|
|
31433
|
-
removeLegacyDirectory(
|
|
31570
|
+
removeLegacyDirectory(path59.join(admin, "components", "custom", "tiptap"));
|
|
31434
31571
|
}
|
|
31435
31572
|
});
|
|
31436
31573
|
updatedStaticNames.add(key);
|
|
@@ -31490,7 +31627,7 @@ async function runUpdateCommand(components, options) {
|
|
|
31490
31627
|
`Overwriting ${displayPaths.length} file${displayPaths.length === 1 ? "" : "s"}`
|
|
31491
31628
|
);
|
|
31492
31629
|
if (!options.yes) {
|
|
31493
|
-
if (!
|
|
31630
|
+
if (!isInteractiveSession()) {
|
|
31494
31631
|
clack4.log.error(
|
|
31495
31632
|
`Overwriting ${displayPaths.length} file${displayPaths.length === 1 ? "" : "s"} needs confirmation. Re-run with --yes.`
|
|
31496
31633
|
);
|
|
@@ -31570,13 +31707,13 @@ function runShadcnPresetUpdate({
|
|
|
31570
31707
|
only
|
|
31571
31708
|
}) {
|
|
31572
31709
|
const namespace = resolveAdminNamespace(config.frameworkConfig.next.namespace);
|
|
31573
|
-
const adminGlobalsPath =
|
|
31574
|
-
const componentsJsonPath =
|
|
31710
|
+
const adminGlobalsPath = path59.join(cwd, config.paths.admin, namespace.globalsFile);
|
|
31711
|
+
const componentsJsonPath = path59.join(cwd, "components.json");
|
|
31575
31712
|
const shadcnBackupPath = `${componentsJsonPath}.bak`;
|
|
31576
31713
|
const restoreAfterApplyPaths = [
|
|
31577
31714
|
componentsJsonPath,
|
|
31578
31715
|
shadcnBackupPath,
|
|
31579
|
-
|
|
31716
|
+
path59.join(cwd, config.paths.admin, "lib", "utils.ts"),
|
|
31580
31717
|
...getHostProjectFilesToRestore(cwd)
|
|
31581
31718
|
];
|
|
31582
31719
|
if (!preset) {
|
|
@@ -31585,7 +31722,7 @@ function runShadcnPresetUpdate({
|
|
|
31585
31722
|
}
|
|
31586
31723
|
if (!fs45.existsSync(adminGlobalsPath)) {
|
|
31587
31724
|
clack4.cancel(
|
|
31588
|
-
`Admin globals file not found at ${
|
|
31725
|
+
`Admin globals file not found at ${path59.relative(cwd, adminGlobalsPath)}. Run 'betterstart update admin-globals' first.`
|
|
31589
31726
|
);
|
|
31590
31727
|
process.exit(1);
|
|
31591
31728
|
}
|
|
@@ -31595,7 +31732,7 @@ function runShadcnPresetUpdate({
|
|
|
31595
31732
|
snapshot: snapshotFile(filePath)
|
|
31596
31733
|
}));
|
|
31597
31734
|
clack4.intro("BetterStart Shadcn Preset");
|
|
31598
|
-
clack4.log.info(`Applying preset to ${
|
|
31735
|
+
clack4.log.info(`Applying preset to ${path59.join(config.paths.admin, "components/ui")}`);
|
|
31599
31736
|
let failed = false;
|
|
31600
31737
|
try {
|
|
31601
31738
|
fs45.writeFileSync(
|
|
@@ -31654,7 +31791,7 @@ function toPosixPath(value) {
|
|
|
31654
31791
|
}
|
|
31655
31792
|
function resolveLocalShadcnBin(cwd) {
|
|
31656
31793
|
const binName = process.platform === "win32" ? "shadcn.cmd" : "shadcn";
|
|
31657
|
-
const shadcnBin =
|
|
31794
|
+
const shadcnBin = path59.join(cwd, "node_modules", ".bin", binName);
|
|
31658
31795
|
if (!fs45.existsSync(shadcnBin)) {
|
|
31659
31796
|
clack4.cancel(
|
|
31660
31797
|
`shadcn is not installed in this project. Run 'betterstart update-deps' and try again.`
|
|
@@ -31676,7 +31813,7 @@ function getHostProjectFilesToRestore(cwd) {
|
|
|
31676
31813
|
"app/globals.css",
|
|
31677
31814
|
"src/app/globals.css"
|
|
31678
31815
|
];
|
|
31679
|
-
return hostRelativePaths.map((relativePath) =>
|
|
31816
|
+
return hostRelativePaths.map((relativePath) => path59.join(cwd, relativePath));
|
|
31680
31817
|
}
|
|
31681
31818
|
function snapshotFile(filePath) {
|
|
31682
31819
|
if (!fs45.existsSync(filePath)) {
|
|
@@ -31695,10 +31832,10 @@ function restoreFile(filePath, snapshot) {
|
|
|
31695
31832
|
}
|
|
31696
31833
|
|
|
31697
31834
|
// adapters/next/commands/update-deps.ts
|
|
31698
|
-
import
|
|
31835
|
+
import path60 from "path";
|
|
31699
31836
|
import * as clack5 from "@clack/prompts";
|
|
31700
31837
|
async function runUpdateDepsCommand(options) {
|
|
31701
|
-
const cwd = options.cwd ?
|
|
31838
|
+
const cwd = options.cwd ? path60.resolve(options.cwd) : process.cwd();
|
|
31702
31839
|
clack5.intro("BetterStart Update Dependencies");
|
|
31703
31840
|
const pm = detectPackageManager(cwd);
|
|
31704
31841
|
clack5.log.info(`Package manager: ${pm}`);
|
|
@@ -31733,17 +31870,17 @@ async function runUpdateDepsCommand(options) {
|
|
|
31733
31870
|
|
|
31734
31871
|
// adapters/next/commands/update-styles.ts
|
|
31735
31872
|
import fs46 from "fs";
|
|
31736
|
-
import
|
|
31873
|
+
import path61 from "path";
|
|
31737
31874
|
import * as clack6 from "@clack/prompts";
|
|
31738
31875
|
async function runUpdateStylesCommand(options) {
|
|
31739
|
-
const cwd = options.cwd ?
|
|
31876
|
+
const cwd = options.cwd ? path61.resolve(options.cwd) : process.cwd();
|
|
31740
31877
|
clack6.intro("BetterStart Update Styles");
|
|
31741
31878
|
const config = await resolveConfigOrExit(cwd);
|
|
31742
31879
|
const adminDir = config.paths.admin;
|
|
31743
31880
|
const namespace = resolveAdminNamespace(config.frameworkConfig.next.namespace);
|
|
31744
|
-
const targetPath =
|
|
31881
|
+
const targetPath = path61.join(cwd, adminDir, namespace.globalsFile);
|
|
31745
31882
|
if (!fs46.existsSync(targetPath)) {
|
|
31746
|
-
clack6.cancel(`${namespace.globalsFile} not found at ${
|
|
31883
|
+
clack6.cancel(`${namespace.globalsFile} not found at ${path61.relative(cwd, targetPath)}`);
|
|
31747
31884
|
process.exit(1);
|
|
31748
31885
|
}
|
|
31749
31886
|
fs46.writeFileSync(
|
|
@@ -31751,12 +31888,14 @@ async function runUpdateStylesCommand(options) {
|
|
|
31751
31888
|
applyAdminNamespaceToContent(readTemplate("admin-globals.css"), namespace.segment),
|
|
31752
31889
|
"utf-8"
|
|
31753
31890
|
);
|
|
31754
|
-
clack6.log.success(`Updated ${
|
|
31891
|
+
clack6.log.success(`Updated ${path61.relative(cwd, targetPath)}`);
|
|
31755
31892
|
clack6.outro("Styles updated");
|
|
31756
31893
|
}
|
|
31757
31894
|
|
|
31758
31895
|
// adapters/next/commands-runtime.ts
|
|
31759
31896
|
var nextCommandRuntime = {
|
|
31897
|
+
listInstallableChoices,
|
|
31898
|
+
listSchemaChoices,
|
|
31760
31899
|
runAdd: runAddCommand,
|
|
31761
31900
|
runAddField: runAddFieldCommand,
|
|
31762
31901
|
runCreate: runCreateCommand,
|
|
@@ -31780,7 +31919,7 @@ var { version } = JSON.parse(
|
|
|
31780
31919
|
readFileSync(new URL("../package.json", import.meta.url), "utf-8")
|
|
31781
31920
|
);
|
|
31782
31921
|
var program = new Command2();
|
|
31783
|
-
program.name("betterstart").description("
|
|
31922
|
+
program.name("betterstart").description("A production ready dashboard, tailored for you in 5 Minutes.").version(version);
|
|
31784
31923
|
program.hook("preAction", (_command, actionCommand) => {
|
|
31785
31924
|
requireInitializedProject(actionCommand);
|
|
31786
31925
|
});
|
|
@@ -31799,14 +31938,18 @@ program.addCommand(createUpdateCommand(nextCommandRuntime));
|
|
|
31799
31938
|
program.addCommand(createUpdateDepsCommand(nextCommandRuntime));
|
|
31800
31939
|
program.addCommand(createUpdateStylesCommand(nextCommandRuntime));
|
|
31801
31940
|
try {
|
|
31802
|
-
|
|
31941
|
+
if (process.argv.slice(2).length === 0) {
|
|
31942
|
+
await runDefaultAction(program, nextCommandRuntime);
|
|
31943
|
+
} else {
|
|
31944
|
+
await program.parseAsync();
|
|
31945
|
+
}
|
|
31803
31946
|
} catch (error) {
|
|
31804
31947
|
if (process.env.BETTERSTART_DEBUG) {
|
|
31805
31948
|
console.error(error);
|
|
31806
31949
|
} else {
|
|
31807
31950
|
const message = error instanceof Error && error.message ? error.message : String(error);
|
|
31808
|
-
|
|
31809
|
-
|
|
31951
|
+
p31.log.error(message);
|
|
31952
|
+
p31.log.message(pc12.dim("Re-run with BETTERSTART_DEBUG=1 for the full stack trace."));
|
|
31810
31953
|
}
|
|
31811
31954
|
process.exit(1);
|
|
31812
31955
|
}
|