betterstart-cli 0.0.91 → 0.0.93
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/assets/adapters/next/templates/init/pages/settings/forms/form-notifications-drawer.tsx +146 -0
- package/dist/assets/adapters/next/templates/init/pages/settings/forms/forms-settings-columns.tsx +31 -0
- package/dist/assets/adapters/next/templates/init/pages/settings/forms/forms-settings-page-content.tsx +39 -90
- package/dist/assets/adapters/next/templates/init/pages/settings/forms/forms-settings-table.tsx +87 -0
- package/dist/cli.js +1328 -1220
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
- package/dist/assets/adapters/next/templates/init/pages/settings/forms/edit-form-notifications-dialog.tsx +0 -128
package/dist/cli.js
CHANGED
|
@@ -52,6 +52,9 @@ async function loadConfigFile(configPath) {
|
|
|
52
52
|
function isInteractiveSession() {
|
|
53
53
|
return Boolean(process.stdin.isTTY) && process.env.CI !== "true";
|
|
54
54
|
}
|
|
55
|
+
function isInteractiveTerminalSession() {
|
|
56
|
+
return isInteractiveSession() && Boolean(process.stdout.isTTY);
|
|
57
|
+
}
|
|
55
58
|
|
|
56
59
|
// core-engine/commands/runtime.ts
|
|
57
60
|
import { Argument, Command } from "commander";
|
|
@@ -185,15 +188,18 @@ function createUpdateStylesCommand(runtime) {
|
|
|
185
188
|
// core-engine/commands/default-action.ts
|
|
186
189
|
var ADD_COMMAND = "add";
|
|
187
190
|
var CREATE_COMMAND = "create";
|
|
191
|
+
var GENERATE_COMMAND = "generate";
|
|
188
192
|
var INIT_COMMAND = "init";
|
|
189
193
|
var REMOVE_COMMAND = "remove";
|
|
190
194
|
var REMOVE_SCHEMA_COMMAND = "remove-schema";
|
|
195
|
+
var UPDATE_COMMAND = "update";
|
|
196
|
+
var ALL_FLAG = "--all";
|
|
191
197
|
var CANCELLED = /* @__PURE__ */ Symbol("cancelled");
|
|
192
198
|
function cancelled(value) {
|
|
193
199
|
return value === CANCELLED;
|
|
194
200
|
}
|
|
195
201
|
async function runDefaultAction(program2, runtime) {
|
|
196
|
-
if (!
|
|
202
|
+
if (!isInteractiveTerminalSession()) {
|
|
197
203
|
program2.outputHelp();
|
|
198
204
|
return;
|
|
199
205
|
}
|
|
@@ -238,6 +244,24 @@ async function promptRequiredArguments(name, runtime, cwd) {
|
|
|
238
244
|
if (name === ADD_COMMAND || name === REMOVE_COMMAND) {
|
|
239
245
|
return promptInstallables(name, runtime, cwd);
|
|
240
246
|
}
|
|
247
|
+
if (name === GENERATE_COMMAND) {
|
|
248
|
+
const schemas = await runtime.listSchemaChoices(cwd);
|
|
249
|
+
if (schemas.length === 0) {
|
|
250
|
+
p.log.warn("No schemas to generate.");
|
|
251
|
+
return CANCELLED;
|
|
252
|
+
}
|
|
253
|
+
const target = await p.select({
|
|
254
|
+
message: "What do you want to generate?",
|
|
255
|
+
options: [
|
|
256
|
+
...schemas.map((value) => ({ value, label: value })),
|
|
257
|
+
{ value: ALL_FLAG, label: "All schemas", hint: "regenerate everything" }
|
|
258
|
+
]
|
|
259
|
+
});
|
|
260
|
+
return p.isCancel(target) ? CANCELLED : [target];
|
|
261
|
+
}
|
|
262
|
+
if (name === UPDATE_COMMAND) {
|
|
263
|
+
return promptComponents(runtime, cwd);
|
|
264
|
+
}
|
|
241
265
|
if (name === REMOVE_SCHEMA_COMMAND) {
|
|
242
266
|
const schemas = await runtime.listSchemaChoices(cwd);
|
|
243
267
|
if (schemas.length === 0) {
|
|
@@ -252,6 +276,31 @@ async function promptRequiredArguments(name, runtime, cwd) {
|
|
|
252
276
|
}
|
|
253
277
|
return [];
|
|
254
278
|
}
|
|
279
|
+
async function promptComponents(runtime, cwd) {
|
|
280
|
+
const scope = await p.select({
|
|
281
|
+
message: "What do you want to update?",
|
|
282
|
+
options: [
|
|
283
|
+
{ value: ALL_FLAG, label: "All components", hint: "every installed component" },
|
|
284
|
+
{ value: "pick", label: "Choose components" }
|
|
285
|
+
]
|
|
286
|
+
});
|
|
287
|
+
if (p.isCancel(scope)) {
|
|
288
|
+
return CANCELLED;
|
|
289
|
+
}
|
|
290
|
+
if (scope === ALL_FLAG) {
|
|
291
|
+
return [ALL_FLAG];
|
|
292
|
+
}
|
|
293
|
+
const components = await runtime.listComponentChoices(cwd);
|
|
294
|
+
if (components.length === 0) {
|
|
295
|
+
p.log.warn("No components available to update.");
|
|
296
|
+
return CANCELLED;
|
|
297
|
+
}
|
|
298
|
+
const selected = await p.multiselect({
|
|
299
|
+
message: "Components to update",
|
|
300
|
+
options: components.map((value) => ({ value, label: value }))
|
|
301
|
+
});
|
|
302
|
+
return p.isCancel(selected) ? CANCELLED : selected;
|
|
303
|
+
}
|
|
255
304
|
async function promptInstallables(name, runtime, cwd) {
|
|
256
305
|
const removing = name === REMOVE_COMMAND;
|
|
257
306
|
const choices = await runtime.listInstallableChoices(cwd);
|
|
@@ -317,7 +366,7 @@ function requireInitializedProject(command) {
|
|
|
317
366
|
|
|
318
367
|
// adapters/next/commands/add.ts
|
|
319
368
|
import path27 from "path";
|
|
320
|
-
import * as
|
|
369
|
+
import * as p9 from "@clack/prompts";
|
|
321
370
|
|
|
322
371
|
// core-engine/config/serialize.ts
|
|
323
372
|
import fs3 from "fs";
|
|
@@ -866,10 +915,93 @@ async function resolveConfigOrExit(cwd) {
|
|
|
866
915
|
}
|
|
867
916
|
|
|
868
917
|
// adapters/next/generators/post-generate.ts
|
|
869
|
-
import {
|
|
918
|
+
import { execFile } from "child_process";
|
|
870
919
|
import fs8 from "fs";
|
|
871
920
|
import path10 from "path";
|
|
872
|
-
import
|
|
921
|
+
import { promisify } from "util";
|
|
922
|
+
import * as p6 from "@clack/prompts";
|
|
923
|
+
|
|
924
|
+
// core-engine/utils/spinner.ts
|
|
925
|
+
import { stripVTControlCharacters } from "util";
|
|
926
|
+
import * as p3 from "@clack/prompts";
|
|
927
|
+
var RENDER_OVERHEAD = 7;
|
|
928
|
+
var MIN_MESSAGE_WIDTH = 8;
|
|
929
|
+
function fitSpinnerMessage(message) {
|
|
930
|
+
const normalized = message.replace(/\t/g, " ");
|
|
931
|
+
const columns = process.stdout.columns ?? 80;
|
|
932
|
+
const max = Math.max(columns - RENDER_OVERHEAD, MIN_MESSAGE_WIDTH);
|
|
933
|
+
const visible = stripVTControlCharacters(normalized);
|
|
934
|
+
if (visible.length <= max) return normalized;
|
|
935
|
+
return `${visible.slice(0, max - 1)}\u2026`;
|
|
936
|
+
}
|
|
937
|
+
var CLACK_LINE_ROWS = 2;
|
|
938
|
+
var LOG_PREFIX_WIDTH = 3;
|
|
939
|
+
function clackPromptRows(message, value) {
|
|
940
|
+
const columns = process.stdout.columns ?? 80;
|
|
941
|
+
const rows = (text7) => Math.max(1, Math.ceil((stripVTControlCharacters(text7).length + LOG_PREFIX_WIDTH) / columns));
|
|
942
|
+
return 1 + rows(message) + rows(value);
|
|
943
|
+
}
|
|
944
|
+
function clackLogRows(message) {
|
|
945
|
+
const columns = process.stdout.columns ?? 80;
|
|
946
|
+
const width = stripVTControlCharacters(message).length + LOG_PREFIX_WIDTH;
|
|
947
|
+
return 1 + Math.max(1, Math.ceil(width / columns));
|
|
948
|
+
}
|
|
949
|
+
function eraseRows(rows) {
|
|
950
|
+
if (rows <= 0 || !process.stdout.isTTY || process.env.CI === "true") return;
|
|
951
|
+
process.stdout.write(`\x1B[${rows}A\x1B[${rows}M`);
|
|
952
|
+
}
|
|
953
|
+
function eraseRowsAbove(rows, rowsBelow) {
|
|
954
|
+
if (rows <= 0 || rowsBelow < 0 || !process.stdout.isTTY || process.env.CI === "true") {
|
|
955
|
+
return;
|
|
956
|
+
}
|
|
957
|
+
const up = rows + rowsBelow;
|
|
958
|
+
const restore = rowsBelow > 0 ? `\x1B[${rowsBelow}B` : "";
|
|
959
|
+
process.stdout.write(`\x1B[${up}A\x1B[${rows}M${restore}`);
|
|
960
|
+
}
|
|
961
|
+
function eraseClackLine(options = {}) {
|
|
962
|
+
if (!process.stdout.isTTY || process.env.CI === "true") return;
|
|
963
|
+
const below = (options.linesBelow ?? 0) * CLACK_LINE_ROWS;
|
|
964
|
+
const up = below + CLACK_LINE_ROWS;
|
|
965
|
+
const restore = below > 0 ? `\x1B[${below}B` : "";
|
|
966
|
+
process.stdout.write(`\x1B[${up}A\x1B[${CLACK_LINE_ROWS}M${restore}`);
|
|
967
|
+
}
|
|
968
|
+
var activeSpinners = 0;
|
|
969
|
+
function hasActiveSpinner() {
|
|
970
|
+
return activeSpinners > 0;
|
|
971
|
+
}
|
|
972
|
+
function spinner2(options) {
|
|
973
|
+
const inner = p3.spinner({ ...options, cancelMessage: "Setup cancelled." });
|
|
974
|
+
const guided = options?.withGuide !== false;
|
|
975
|
+
let started = false;
|
|
976
|
+
const setStarted = (next) => {
|
|
977
|
+
if (started === next) return;
|
|
978
|
+
started = next;
|
|
979
|
+
activeSpinners += next ? 1 : -1;
|
|
980
|
+
};
|
|
981
|
+
return {
|
|
982
|
+
start: (message = "") => {
|
|
983
|
+
if (started) {
|
|
984
|
+
inner.message(fitSpinnerMessage(message));
|
|
985
|
+
return;
|
|
986
|
+
}
|
|
987
|
+
setStarted(true);
|
|
988
|
+
inner.start(fitSpinnerMessage(message));
|
|
989
|
+
},
|
|
990
|
+
message: (message = "") => inner.message(fitSpinnerMessage(message)),
|
|
991
|
+
stop: (message = "") => {
|
|
992
|
+
setStarted(false);
|
|
993
|
+
inner.stop(message);
|
|
994
|
+
},
|
|
995
|
+
clear: () => {
|
|
996
|
+
if (!started) return;
|
|
997
|
+
setStarted(false);
|
|
998
|
+
inner.clear();
|
|
999
|
+
if (guided && process.stdout.isTTY && process.env.CI !== "true") {
|
|
1000
|
+
process.stdout.write("\x1B[1A\x1B[2K");
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
};
|
|
1004
|
+
}
|
|
873
1005
|
|
|
874
1006
|
// adapters/next/init/scaffolders/dependencies.ts
|
|
875
1007
|
import { spawn } from "child_process";
|
|
@@ -1752,7 +1884,7 @@ async function syncProjectCliDependency(cwd, pm) {
|
|
|
1752
1884
|
// adapters/next/utils/drizzle-push.ts
|
|
1753
1885
|
import { spawn as spawn2 } from "child_process";
|
|
1754
1886
|
import path9 from "path";
|
|
1755
|
-
import * as
|
|
1887
|
+
import * as p4 from "@clack/prompts";
|
|
1756
1888
|
var PG_SSL_WARNING_START = "Warning: SECURITY WARNING: The SSL modes 'prefer', 'require', and 'verify-ca' are treated as aliases for 'verify-full'.";
|
|
1757
1889
|
var PG_SSL_WARNING_END = "See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode definitions.";
|
|
1758
1890
|
var NODE_TRACE_WARNING_HINT = "(Use `node --trace-warnings";
|
|
@@ -1928,7 +2060,7 @@ function runDrizzlePush(cwd, options = {}) {
|
|
|
1928
2060
|
}
|
|
1929
2061
|
if (stdoutTtySuppressor.sawError() || stderrTtySuppressor.sawError()) {
|
|
1930
2062
|
notifyOutput();
|
|
1931
|
-
|
|
2063
|
+
p4.log.info("Database changes need your input \u2014 continuing in drizzle-kit.");
|
|
1932
2064
|
const attached = spawn2(drizzleBin, ["push", "--force"], {
|
|
1933
2065
|
cwd,
|
|
1934
2066
|
stdio: "inherit",
|
|
@@ -1974,7 +2106,7 @@ ${stderr}`.trim();
|
|
|
1974
2106
|
}
|
|
1975
2107
|
|
|
1976
2108
|
// adapters/next/utils/next-steps.ts
|
|
1977
|
-
import * as
|
|
2109
|
+
import * as p5 from "@clack/prompts";
|
|
1978
2110
|
function printNextSteps(options) {
|
|
1979
2111
|
const steps = [`1. Review ${options.reviewLabel}`];
|
|
1980
2112
|
if (options.needsMigration) {
|
|
@@ -1983,11 +2115,12 @@ function printNextSteps(options) {
|
|
|
1983
2115
|
} else {
|
|
1984
2116
|
steps.push(`2. Start the dev server and visit ${options.route}`);
|
|
1985
2117
|
}
|
|
1986
|
-
|
|
2118
|
+
p5.note(steps.join("\n"), "Next steps");
|
|
1987
2119
|
}
|
|
1988
2120
|
|
|
1989
2121
|
// adapters/next/generators/post-generate.ts
|
|
1990
2122
|
var BIOME_FORMAT_TIMEOUT_MS = 3e4;
|
|
2123
|
+
var execFileAsync = promisify(execFile);
|
|
1991
2124
|
function loadEnvFile(cwd) {
|
|
1992
2125
|
const envPath = path10.join(cwd, ".env.local");
|
|
1993
2126
|
if (!fs8.existsSync(envPath)) return;
|
|
@@ -2011,10 +2144,10 @@ function loadEnvFile(cwd) {
|
|
|
2011
2144
|
}
|
|
2012
2145
|
}
|
|
2013
2146
|
}
|
|
2014
|
-
function runPmScript(pm, script, cwd, timeout) {
|
|
2147
|
+
async function runPmScript(pm, script, cwd, timeout) {
|
|
2015
2148
|
const args = pm === "bun" ? ["run", script] : [script];
|
|
2016
2149
|
try {
|
|
2017
|
-
|
|
2150
|
+
await execFileAsync(pm, args, { cwd, timeout });
|
|
2018
2151
|
return true;
|
|
2019
2152
|
} catch {
|
|
2020
2153
|
return false;
|
|
@@ -2025,7 +2158,7 @@ function getExistingTrackedFilePaths(cwd) {
|
|
|
2025
2158
|
(filePath) => fs8.existsSync(path10.join(cwd, ...filePath.split("/")))
|
|
2026
2159
|
);
|
|
2027
2160
|
}
|
|
2028
|
-
function runBiomeCheckWrite(cwd) {
|
|
2161
|
+
async function runBiomeCheckWrite(cwd) {
|
|
2029
2162
|
const biomeBin = path10.join(cwd, "node_modules", ".bin", "biome");
|
|
2030
2163
|
if (!fs8.existsSync(biomeBin)) {
|
|
2031
2164
|
return false;
|
|
@@ -2044,9 +2177,8 @@ function runBiomeCheckWrite(cwd) {
|
|
|
2044
2177
|
...configPath ? ["--config-path", configPath] : [],
|
|
2045
2178
|
...chunk
|
|
2046
2179
|
];
|
|
2047
|
-
|
|
2180
|
+
await execFileAsync(biomeBin, args, {
|
|
2048
2181
|
cwd,
|
|
2049
|
-
stdio: "pipe",
|
|
2050
2182
|
timeout: BIOME_FORMAT_TIMEOUT_MS
|
|
2051
2183
|
});
|
|
2052
2184
|
}
|
|
@@ -2063,18 +2195,15 @@ function buildAddDependencyArgs(pm, dependency, dev) {
|
|
|
2063
2195
|
return ["install", ...devFlag ? [devFlag] : [], dependency];
|
|
2064
2196
|
}
|
|
2065
2197
|
}
|
|
2066
|
-
function installDependency(cwd, pm, dependency, dev = false) {
|
|
2198
|
+
async function installDependency(cwd, pm, dependency, dev = false) {
|
|
2067
2199
|
try {
|
|
2068
|
-
|
|
2069
|
-
cwd,
|
|
2070
|
-
stdio: "pipe"
|
|
2071
|
-
});
|
|
2200
|
+
await execFileAsync(pm, buildAddDependencyArgs(pm, dependency, dev), { cwd });
|
|
2072
2201
|
return true;
|
|
2073
2202
|
} catch {
|
|
2074
2203
|
return false;
|
|
2075
2204
|
}
|
|
2076
2205
|
}
|
|
2077
|
-
function ensureDatabasePushDependencies(cwd, pm) {
|
|
2206
|
+
async function ensureDatabasePushDependencies(cwd, pm) {
|
|
2078
2207
|
const missing = [];
|
|
2079
2208
|
if (!hasPostgresRuntimeDependency(cwd)) {
|
|
2080
2209
|
missing.push({ name: POSTGRES_RUNTIME_DEP, dev: false });
|
|
@@ -2085,25 +2214,25 @@ function ensureDatabasePushDependencies(cwd, pm) {
|
|
|
2085
2214
|
if (missing.length === 0) {
|
|
2086
2215
|
return true;
|
|
2087
2216
|
}
|
|
2088
|
-
|
|
2217
|
+
p6.log.info(
|
|
2089
2218
|
`Installing database push dependencies (${missing.map((dependency) => dependency.name).join(", ")})...`
|
|
2090
2219
|
);
|
|
2091
2220
|
for (const dependency of missing) {
|
|
2092
|
-
const installed2 = installDependency(cwd, pm, dependency.name, dependency.dev);
|
|
2221
|
+
const installed2 = await installDependency(cwd, pm, dependency.name, dependency.dev);
|
|
2093
2222
|
if (!installed2) {
|
|
2094
|
-
|
|
2223
|
+
p6.log.warn(`Failed to install ${dependency.name}`);
|
|
2095
2224
|
return false;
|
|
2096
2225
|
}
|
|
2097
2226
|
}
|
|
2098
2227
|
const ready = hasPostgresRuntimeDependency(cwd) && hasDrizzleKitPostgresDriverDependency(cwd);
|
|
2099
2228
|
if (ready) {
|
|
2100
|
-
|
|
2229
|
+
p6.log.success("Database push dependencies installed");
|
|
2101
2230
|
} else {
|
|
2102
2231
|
const unresolved = [
|
|
2103
2232
|
!hasPostgresRuntimeDependency(cwd) ? POSTGRES_RUNTIME_DEP : null,
|
|
2104
2233
|
!hasDrizzleKitPostgresDriverDependency(cwd) ? DRIZZLE_KIT_POSTGRES_DRIVER_DEP : null
|
|
2105
2234
|
].filter((dependency) => Boolean(dependency));
|
|
2106
|
-
|
|
2235
|
+
p6.log.warn(`Installed dependencies but could not resolve ${unresolved.join(", ")}`);
|
|
2107
2236
|
}
|
|
2108
2237
|
return ready;
|
|
2109
2238
|
}
|
|
@@ -2146,8 +2275,8 @@ async function runPostGenerate(cwd, schemaName, options = {}) {
|
|
|
2146
2275
|
"Formatting: skipped (biome refuses files with conflict markers)",
|
|
2147
2276
|
...(options.conflictPaths ?? []).map((conflictPath) => ` - ${conflictPath}`)
|
|
2148
2277
|
];
|
|
2149
|
-
|
|
2150
|
-
|
|
2278
|
+
p6.log.warn(lines.join("\n"));
|
|
2279
|
+
p6.log.message(
|
|
2151
2280
|
"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."
|
|
2152
2281
|
);
|
|
2153
2282
|
return result;
|
|
@@ -2157,62 +2286,83 @@ async function runPostGenerate(cwd, schemaName, options = {}) {
|
|
|
2157
2286
|
const dbUrl = process.env.DATABASE_URL;
|
|
2158
2287
|
if (!dbUrl) {
|
|
2159
2288
|
result.dbPush = "no-db-url";
|
|
2160
|
-
|
|
2289
|
+
p6.log.warn(
|
|
2161
2290
|
[
|
|
2162
2291
|
"Database: skipped (no DATABASE_URL configured)",
|
|
2163
2292
|
" To sync later: run db:push after setting DATABASE_URL"
|
|
2164
2293
|
].join("\n")
|
|
2165
2294
|
);
|
|
2166
|
-
} else if (!ensureDatabasePushDependencies(cwd, pm)) {
|
|
2295
|
+
} else if (!await ensureDatabasePushDependencies(cwd, pm)) {
|
|
2167
2296
|
result.dbPush = "failed";
|
|
2168
|
-
|
|
2297
|
+
p6.log.warn(
|
|
2169
2298
|
"Database push failed (install database dependencies and run drizzle-kit push manually)"
|
|
2170
2299
|
);
|
|
2171
2300
|
} else if (hasPkgScript(cwd, "db:push")) {
|
|
2172
|
-
|
|
2173
|
-
|
|
2301
|
+
const s = spinner2();
|
|
2302
|
+
s.start("Pushing database schema");
|
|
2303
|
+
const ok = await runPmScript(pm, "db:push", cwd);
|
|
2174
2304
|
result.dbPush = ok ? "success" : "failed";
|
|
2175
2305
|
if (ok) {
|
|
2176
|
-
|
|
2306
|
+
s.stop("Database schema synced");
|
|
2177
2307
|
} else {
|
|
2178
|
-
|
|
2308
|
+
s.clear();
|
|
2309
|
+
p6.log.warn("Database push failed (run db:push manually)");
|
|
2179
2310
|
}
|
|
2180
2311
|
} else {
|
|
2181
|
-
|
|
2312
|
+
const s = spinner2();
|
|
2313
|
+
let spinnerVisible = true;
|
|
2314
|
+
const clearSpinner = () => {
|
|
2315
|
+
if (!spinnerVisible) return;
|
|
2316
|
+
spinnerVisible = false;
|
|
2317
|
+
s.clear();
|
|
2318
|
+
};
|
|
2319
|
+
s.start("Pushing database schema");
|
|
2182
2320
|
try {
|
|
2183
|
-
const pushResult = await runDrizzlePush(cwd, {
|
|
2321
|
+
const pushResult = await runDrizzlePush(cwd, {
|
|
2322
|
+
interactive: true,
|
|
2323
|
+
onOutput: clearSpinner
|
|
2324
|
+
});
|
|
2184
2325
|
if (!pushResult.success) {
|
|
2185
2326
|
throw new Error(pushResult.error ?? "drizzle-kit push failed");
|
|
2186
2327
|
}
|
|
2187
2328
|
result.dbPush = "success";
|
|
2188
|
-
|
|
2329
|
+
if (spinnerVisible) {
|
|
2330
|
+
spinnerVisible = false;
|
|
2331
|
+
s.stop("Database schema synced");
|
|
2332
|
+
} else {
|
|
2333
|
+
p6.log.success("Database schema synced");
|
|
2334
|
+
}
|
|
2189
2335
|
} catch {
|
|
2190
2336
|
result.dbPush = "failed";
|
|
2191
|
-
|
|
2337
|
+
clearSpinner();
|
|
2338
|
+
p6.log.warn("Database push failed (run drizzle-kit push manually)");
|
|
2192
2339
|
}
|
|
2193
2340
|
}
|
|
2194
2341
|
} else {
|
|
2195
|
-
|
|
2342
|
+
p6.log.info(`Database: skipped (${options.skipMigrationMessage ?? "--skip-migration"})`);
|
|
2196
2343
|
}
|
|
2344
|
+
const formatSpinner = spinner2();
|
|
2345
|
+
formatSpinner.start("Formatting generated files");
|
|
2197
2346
|
if (hasPkgScript(cwd, "lint:fix")) {
|
|
2198
|
-
|
|
2199
|
-
const ok = runPmScript(pm, "lint:fix", cwd, BIOME_FORMAT_TIMEOUT_MS);
|
|
2347
|
+
const ok = await runPmScript(pm, "lint:fix", cwd, BIOME_FORMAT_TIMEOUT_MS);
|
|
2200
2348
|
result.lintFix = ok ? "success" : "failed";
|
|
2201
2349
|
if (ok) {
|
|
2202
|
-
|
|
2350
|
+
formatSpinner.stop("Code formatted");
|
|
2203
2351
|
} else {
|
|
2204
|
-
|
|
2352
|
+
formatSpinner.clear();
|
|
2353
|
+
p6.log.warn("Lint fix had issues (run lint:fix manually)");
|
|
2205
2354
|
}
|
|
2206
2355
|
} else {
|
|
2207
2356
|
try {
|
|
2208
|
-
if (!runBiomeCheckWrite(cwd)) {
|
|
2357
|
+
if (!await runBiomeCheckWrite(cwd)) {
|
|
2209
2358
|
throw new Error("Biome binary not found");
|
|
2210
2359
|
}
|
|
2211
2360
|
result.lintFix = "success";
|
|
2212
|
-
|
|
2361
|
+
formatSpinner.stop("Code formatted with Biome");
|
|
2213
2362
|
} catch {
|
|
2214
2363
|
result.lintFix = "failed";
|
|
2215
|
-
|
|
2364
|
+
formatSpinner.clear();
|
|
2365
|
+
p6.log.warn("Biome formatting had issues (run biome check --write manually)");
|
|
2216
2366
|
}
|
|
2217
2367
|
}
|
|
2218
2368
|
if (options.showNextSteps !== false) {
|
|
@@ -2229,7 +2379,7 @@ async function runPostGenerate(cwd, schemaName, options = {}) {
|
|
|
2229
2379
|
// adapters/next/integration-runtime.ts
|
|
2230
2380
|
import fs14 from "fs";
|
|
2231
2381
|
import path17 from "path";
|
|
2232
|
-
import * as
|
|
2382
|
+
import * as p7 from "@clack/prompts";
|
|
2233
2383
|
|
|
2234
2384
|
// core-engine/schema/schema-reader.ts
|
|
2235
2385
|
import fs9 from "fs";
|
|
@@ -3555,12 +3705,12 @@ async function resolveTextEnvValue(options) {
|
|
|
3555
3705
|
if (existingValue) {
|
|
3556
3706
|
return existingValue;
|
|
3557
3707
|
}
|
|
3558
|
-
const result = await
|
|
3708
|
+
const result = await p7.text({
|
|
3559
3709
|
message: options.message,
|
|
3560
3710
|
defaultValue: options.defaultValue,
|
|
3561
3711
|
validate: options.validate
|
|
3562
3712
|
});
|
|
3563
|
-
if (
|
|
3713
|
+
if (p7.isCancel(result)) {
|
|
3564
3714
|
throw new Error(options.cancelMessage);
|
|
3565
3715
|
}
|
|
3566
3716
|
options.overwriteEnvKeys.add(options.key);
|
|
@@ -3571,11 +3721,11 @@ async function resolvePasswordEnvValue(options) {
|
|
|
3571
3721
|
if (existingValue) {
|
|
3572
3722
|
return existingValue;
|
|
3573
3723
|
}
|
|
3574
|
-
const result = await
|
|
3724
|
+
const result = await p7.password({
|
|
3575
3725
|
message: options.message,
|
|
3576
3726
|
validate: options.validate
|
|
3577
3727
|
});
|
|
3578
|
-
if (
|
|
3728
|
+
if (p7.isCancel(result)) {
|
|
3579
3729
|
throw new Error(options.cancelMessage);
|
|
3580
3730
|
}
|
|
3581
3731
|
options.overwriteEnvKeys.add(options.key);
|
|
@@ -17924,7 +18074,7 @@ function readPresetTemplate(presetId, relativePath) {
|
|
|
17924
18074
|
// adapters/next/snapshots/apply.ts
|
|
17925
18075
|
import fs20 from "fs";
|
|
17926
18076
|
import path24 from "path";
|
|
17927
|
-
import * as
|
|
18077
|
+
import * as p8 from "@clack/prompts";
|
|
17928
18078
|
|
|
17929
18079
|
// core-engine/snapshots/ast-substitution.ts
|
|
17930
18080
|
import { Node, Project } from "ts-morph";
|
|
@@ -18286,7 +18436,7 @@ function hasConflictMarkers(content) {
|
|
|
18286
18436
|
}
|
|
18287
18437
|
|
|
18288
18438
|
// adapters/next/snapshots/format-for-merge.ts
|
|
18289
|
-
import { execFileSync as
|
|
18439
|
+
import { execFileSync as execFileSync2 } from "child_process";
|
|
18290
18440
|
import fs18 from "fs";
|
|
18291
18441
|
import path22 from "path";
|
|
18292
18442
|
var BIOME_FORMAT_TIMEOUT_MS2 = 15e3;
|
|
@@ -18336,7 +18486,7 @@ function formatContentForSnapshotMerge(cwd, filePath, content) {
|
|
|
18336
18486
|
const configPath = findBiomeConfig(cwd);
|
|
18337
18487
|
const targetPath = path22.join(cwd, ...filePath.split("/"));
|
|
18338
18488
|
try {
|
|
18339
|
-
return
|
|
18489
|
+
return execFileSync2(
|
|
18340
18490
|
biomeBin,
|
|
18341
18491
|
[
|
|
18342
18492
|
"check",
|
|
@@ -18591,7 +18741,7 @@ function isInteractiveSession2(interactive) {
|
|
|
18591
18741
|
return interactive && Boolean(process.stdin.isTTY) && process.env.CI !== "true";
|
|
18592
18742
|
}
|
|
18593
18743
|
async function promptNoBaseDecision(filePath) {
|
|
18594
|
-
const answer = await
|
|
18744
|
+
const answer = await p8.select({
|
|
18595
18745
|
message: `File already exists without snapshot base: ${filePath}`,
|
|
18596
18746
|
options: [
|
|
18597
18747
|
{ value: "backup", label: "Backup and overwrite", hint: "recommended" },
|
|
@@ -18600,7 +18750,7 @@ async function promptNoBaseDecision(filePath) {
|
|
|
18600
18750
|
],
|
|
18601
18751
|
initialValue: "backup"
|
|
18602
18752
|
});
|
|
18603
|
-
if (
|
|
18753
|
+
if (p8.isCancel(answer)) {
|
|
18604
18754
|
throw new Error("Generation cancelled.");
|
|
18605
18755
|
}
|
|
18606
18756
|
return answer;
|
|
@@ -19481,18 +19631,18 @@ async function runAddCommand(items, options) {
|
|
|
19481
19631
|
const presetIds = items.filter(isPresetId);
|
|
19482
19632
|
const integrationIds = items.filter(isIntegrationId);
|
|
19483
19633
|
if (!installIntegrationsMode && integrationIds.length > 0) {
|
|
19484
|
-
|
|
19634
|
+
p9.log.error(
|
|
19485
19635
|
`Integration IDs require --integration. Run \`betterstart add --integration ${integrationIds.join(" ")}\`.`
|
|
19486
19636
|
);
|
|
19487
19637
|
process.exit(1);
|
|
19488
19638
|
}
|
|
19489
19639
|
if (installIntegrationsMode && presetIds.length > 0) {
|
|
19490
|
-
|
|
19640
|
+
p9.log.error(`Preset IDs cannot be installed with --integration: ${presetIds.join(", ")}`);
|
|
19491
19641
|
process.exit(1);
|
|
19492
19642
|
}
|
|
19493
19643
|
const invalidItems = installIntegrationsMode ? items.filter((integrationId) => !isIntegrationId(integrationId)) : items.filter((presetId) => !isPresetId(presetId));
|
|
19494
19644
|
if (invalidItems.length > 0) {
|
|
19495
|
-
|
|
19645
|
+
p9.log.error(
|
|
19496
19646
|
installIntegrationsMode ? formatUnknownIntegrationMessage(invalidItems) : formatUnknownPresetMessage(invalidItems)
|
|
19497
19647
|
);
|
|
19498
19648
|
process.exit(1);
|
|
@@ -19503,7 +19653,7 @@ async function runAddCommand(items, options) {
|
|
|
19503
19653
|
const pm = detectPackageManager(cwd);
|
|
19504
19654
|
const cliSyncResult = await syncProjectCliDependency(cwd, pm);
|
|
19505
19655
|
if (cliSyncResult && !cliSyncResult.success) {
|
|
19506
|
-
|
|
19656
|
+
p9.log.error(cliSyncResult.error ?? "Failed to sync betterstart-cli");
|
|
19507
19657
|
process.exit(1);
|
|
19508
19658
|
}
|
|
19509
19659
|
if (installIntegrationsMode) {
|
|
@@ -19517,10 +19667,10 @@ async function runAddCommand(items, options) {
|
|
|
19517
19667
|
});
|
|
19518
19668
|
writeConfigFile(cwd, result2.config);
|
|
19519
19669
|
if (result2.warnings.length > 0) {
|
|
19520
|
-
|
|
19670
|
+
p9.note(result2.warnings.join("\n"), "Warnings");
|
|
19521
19671
|
}
|
|
19522
19672
|
if (result2.installed.length === 0 && result2.activated.length === 0 && result2.skipped.length > 0) {
|
|
19523
|
-
|
|
19673
|
+
p9.outro(`No changes made. Already installed: ${result2.skipped.join(", ")}`);
|
|
19524
19674
|
return;
|
|
19525
19675
|
}
|
|
19526
19676
|
const conflictPaths2 = scanConflictPaths(cwd);
|
|
@@ -19542,12 +19692,12 @@ async function runAddCommand(items, options) {
|
|
|
19542
19692
|
result2.installed.length > 0 ? `Installed integration${result2.installed.length === 1 ? "" : "s"}: ${result2.installed.join(", ")}` : null,
|
|
19543
19693
|
result2.activated.length > 0 ? `Activated integration${result2.activated.length === 1 ? "" : "s"}: ${result2.activated.join(", ")}` : null
|
|
19544
19694
|
].filter(Boolean);
|
|
19545
|
-
|
|
19695
|
+
p9.outro(messages.join("\n"));
|
|
19546
19696
|
return;
|
|
19547
19697
|
}
|
|
19548
19698
|
const invalidPresets = items.filter((presetId) => !isPresetId(presetId));
|
|
19549
19699
|
if (invalidPresets.length > 0) {
|
|
19550
|
-
|
|
19700
|
+
p9.log.error(formatUnknownPresetMessage(invalidPresets));
|
|
19551
19701
|
process.exit(1);
|
|
19552
19702
|
}
|
|
19553
19703
|
const result = await installPresets({
|
|
@@ -19560,11 +19710,11 @@ async function runAddCommand(items, options) {
|
|
|
19560
19710
|
});
|
|
19561
19711
|
writeConfigFile(cwd, result.config);
|
|
19562
19712
|
if (result.installed.length === 0 && result.skipped.length > 0) {
|
|
19563
|
-
|
|
19713
|
+
p9.outro(`No changes made. Already installed: ${result.skipped.join(", ")}`);
|
|
19564
19714
|
return;
|
|
19565
19715
|
}
|
|
19566
19716
|
if (result.warnings.length > 0) {
|
|
19567
|
-
|
|
19717
|
+
p9.note(result.warnings.join("\n"), "Warnings");
|
|
19568
19718
|
}
|
|
19569
19719
|
const installedSchemaNames = result.installed.flatMap(
|
|
19570
19720
|
(presetId) => getPresetDefinition(presetId).schemaFiles.map((schemaFile) => schemaFile.replace(/\.json$/, ""))
|
|
@@ -19581,7 +19731,7 @@ async function runAddCommand(items, options) {
|
|
|
19581
19731
|
if (conflictPaths.length === 0) {
|
|
19582
19732
|
printAddNextSteps("preset", hasSchemaChanges, postGenerateResult, adminRoutePath);
|
|
19583
19733
|
}
|
|
19584
|
-
|
|
19734
|
+
p9.outro(
|
|
19585
19735
|
`Installed preset${result.installed.length === 1 ? "" : "s"}: ${result.installed.join(", ")}`
|
|
19586
19736
|
);
|
|
19587
19737
|
}
|
|
@@ -20332,88 +20482,6 @@ function diffSchemas(before, after) {
|
|
|
20332
20482
|
};
|
|
20333
20483
|
}
|
|
20334
20484
|
|
|
20335
|
-
// core-engine/utils/spinner.ts
|
|
20336
|
-
import { stripVTControlCharacters } from "util";
|
|
20337
|
-
import * as p9 from "@clack/prompts";
|
|
20338
|
-
var RENDER_OVERHEAD = 7;
|
|
20339
|
-
var MIN_MESSAGE_WIDTH = 8;
|
|
20340
|
-
function fitSpinnerMessage(message) {
|
|
20341
|
-
const normalized = message.replace(/\t/g, " ");
|
|
20342
|
-
const columns = process.stdout.columns ?? 80;
|
|
20343
|
-
const max = Math.max(columns - RENDER_OVERHEAD, MIN_MESSAGE_WIDTH);
|
|
20344
|
-
const visible = stripVTControlCharacters(normalized);
|
|
20345
|
-
if (visible.length <= max) return normalized;
|
|
20346
|
-
return `${visible.slice(0, max - 1)}\u2026`;
|
|
20347
|
-
}
|
|
20348
|
-
var CLACK_LINE_ROWS = 2;
|
|
20349
|
-
var LOG_PREFIX_WIDTH = 3;
|
|
20350
|
-
function clackPromptRows(message, value) {
|
|
20351
|
-
const columns = process.stdout.columns ?? 80;
|
|
20352
|
-
const rows = (text7) => Math.max(1, Math.ceil((stripVTControlCharacters(text7).length + LOG_PREFIX_WIDTH) / columns));
|
|
20353
|
-
return 1 + rows(message) + rows(value);
|
|
20354
|
-
}
|
|
20355
|
-
function clackLogRows(message) {
|
|
20356
|
-
const columns = process.stdout.columns ?? 80;
|
|
20357
|
-
const width = stripVTControlCharacters(message).length + LOG_PREFIX_WIDTH;
|
|
20358
|
-
return 1 + Math.max(1, Math.ceil(width / columns));
|
|
20359
|
-
}
|
|
20360
|
-
function eraseRows(rows) {
|
|
20361
|
-
if (rows <= 0 || !process.stdout.isTTY || process.env.CI === "true") return;
|
|
20362
|
-
process.stdout.write(`\x1B[${rows}A\x1B[${rows}M`);
|
|
20363
|
-
}
|
|
20364
|
-
function eraseRowsAbove(rows, rowsBelow) {
|
|
20365
|
-
if (rows <= 0 || rowsBelow < 0 || !process.stdout.isTTY || process.env.CI === "true") {
|
|
20366
|
-
return;
|
|
20367
|
-
}
|
|
20368
|
-
const up = rows + rowsBelow;
|
|
20369
|
-
const restore = rowsBelow > 0 ? `\x1B[${rowsBelow}B` : "";
|
|
20370
|
-
process.stdout.write(`\x1B[${up}A\x1B[${rows}M${restore}`);
|
|
20371
|
-
}
|
|
20372
|
-
function eraseClackLine(options = {}) {
|
|
20373
|
-
if (!process.stdout.isTTY || process.env.CI === "true") return;
|
|
20374
|
-
const below = (options.linesBelow ?? 0) * CLACK_LINE_ROWS;
|
|
20375
|
-
const up = below + CLACK_LINE_ROWS;
|
|
20376
|
-
const restore = below > 0 ? `\x1B[${below}B` : "";
|
|
20377
|
-
process.stdout.write(`\x1B[${up}A\x1B[${CLACK_LINE_ROWS}M${restore}`);
|
|
20378
|
-
}
|
|
20379
|
-
var activeSpinners = 0;
|
|
20380
|
-
function hasActiveSpinner() {
|
|
20381
|
-
return activeSpinners > 0;
|
|
20382
|
-
}
|
|
20383
|
-
function spinner2(options) {
|
|
20384
|
-
const inner = p9.spinner({ ...options, cancelMessage: "Setup cancelled." });
|
|
20385
|
-
const guided = options?.withGuide !== false;
|
|
20386
|
-
let started = false;
|
|
20387
|
-
const setStarted = (next) => {
|
|
20388
|
-
if (started === next) return;
|
|
20389
|
-
started = next;
|
|
20390
|
-
activeSpinners += next ? 1 : -1;
|
|
20391
|
-
};
|
|
20392
|
-
return {
|
|
20393
|
-
start: (message = "") => {
|
|
20394
|
-
if (started) {
|
|
20395
|
-
inner.message(fitSpinnerMessage(message));
|
|
20396
|
-
return;
|
|
20397
|
-
}
|
|
20398
|
-
setStarted(true);
|
|
20399
|
-
inner.start(fitSpinnerMessage(message));
|
|
20400
|
-
},
|
|
20401
|
-
message: (message = "") => inner.message(fitSpinnerMessage(message)),
|
|
20402
|
-
stop: (message = "") => {
|
|
20403
|
-
setStarted(false);
|
|
20404
|
-
inner.stop(message);
|
|
20405
|
-
},
|
|
20406
|
-
clear: () => {
|
|
20407
|
-
if (!started) return;
|
|
20408
|
-
setStarted(false);
|
|
20409
|
-
inner.clear();
|
|
20410
|
-
if (guided && process.stdout.isTTY && process.env.CI !== "true") {
|
|
20411
|
-
process.stdout.write("\x1B[1A\x1B[2K");
|
|
20412
|
-
}
|
|
20413
|
-
}
|
|
20414
|
-
};
|
|
20415
|
-
}
|
|
20416
|
-
|
|
20417
20485
|
// adapters/next/commands/generate.ts
|
|
20418
20486
|
function isInteractiveSession3() {
|
|
20419
20487
|
return Boolean(process.stdin.isTTY) && process.env.CI !== "true";
|
|
@@ -22403,7 +22471,7 @@ ${validationErrors.map((error) => ` - ${error}`).join("\n")}`
|
|
|
22403
22471
|
}
|
|
22404
22472
|
|
|
22405
22473
|
// adapters/next/commands/init.ts
|
|
22406
|
-
import { execFileSync as
|
|
22474
|
+
import { execFileSync as execFileSync4, spawn as spawn6 } from "child_process";
|
|
22407
22475
|
import fs41 from "fs";
|
|
22408
22476
|
import path52 from "path";
|
|
22409
22477
|
import { PassThrough } from "stream";
|
|
@@ -22468,7 +22536,7 @@ function redactSecrets(text7) {
|
|
|
22468
22536
|
}
|
|
22469
22537
|
|
|
22470
22538
|
// adapters/next/init/prompts/database.ts
|
|
22471
|
-
import { execFileSync as
|
|
22539
|
+
import { execFileSync as execFileSync3 } from "child_process";
|
|
22472
22540
|
import * as p15 from "@clack/prompts";
|
|
22473
22541
|
import pc from "picocolors";
|
|
22474
22542
|
var VERCEL_NEON_URL = "https://vercel.com/dashboard/integrations/checkout/neon";
|
|
@@ -22548,11 +22616,11 @@ function openBrowser(url) {
|
|
|
22548
22616
|
try {
|
|
22549
22617
|
const platform = process.platform;
|
|
22550
22618
|
if (platform === "darwin") {
|
|
22551
|
-
|
|
22619
|
+
execFileSync3("open", [url], { stdio: "ignore" });
|
|
22552
22620
|
} else if (platform === "win32") {
|
|
22553
|
-
|
|
22621
|
+
execFileSync3("cmd", ["/c", "start", url], { stdio: "ignore" });
|
|
22554
22622
|
} else {
|
|
22555
|
-
|
|
22623
|
+
execFileSync3("xdg-open", [url], { stdio: "ignore" });
|
|
22556
22624
|
}
|
|
22557
22625
|
} catch {
|
|
22558
22626
|
}
|
|
@@ -25036,8 +25104,16 @@ function scaffoldLayout({ cwd, config }) {
|
|
|
25036
25104
|
readTemplate("pages/settings/forms/forms-settings-page-content.tsx")
|
|
25037
25105
|
);
|
|
25038
25106
|
write(
|
|
25039
|
-
path43.join(settingsFormsDir, "
|
|
25040
|
-
readTemplate("pages/settings/forms/
|
|
25107
|
+
path43.join(settingsFormsDir, "forms-settings-columns.tsx"),
|
|
25108
|
+
readTemplate("pages/settings/forms/forms-settings-columns.tsx")
|
|
25109
|
+
);
|
|
25110
|
+
write(
|
|
25111
|
+
path43.join(settingsFormsDir, "forms-settings-table.tsx"),
|
|
25112
|
+
readTemplate("pages/settings/forms/forms-settings-table.tsx")
|
|
25113
|
+
);
|
|
25114
|
+
write(
|
|
25115
|
+
path43.join(settingsFormsDir, "form-notifications-drawer.tsx"),
|
|
25116
|
+
readTemplate("pages/settings/forms/form-notifications-drawer.tsx")
|
|
25041
25117
|
);
|
|
25042
25118
|
const settingsWebhooksDir = path43.join(settingsDir, "webhooks");
|
|
25043
25119
|
write(
|
|
@@ -27214,10 +27290,10 @@ async function runSeedCommand(options) {
|
|
|
27214
27290
|
}
|
|
27215
27291
|
const namespace = resolveAdminNamespace(config.frameworkConfig.next.namespace);
|
|
27216
27292
|
fs40.writeFileSync(seedPath, buildSeedScript(`${namespace.apiPath}/auth`), "utf-8");
|
|
27217
|
-
const { execFile } = await import("child_process");
|
|
27293
|
+
const { execFile: execFile2 } = await import("child_process");
|
|
27218
27294
|
const tsxBin = path51.join(cwd, "node_modules", ".bin", "tsx");
|
|
27219
27295
|
const runSeed2 = (overwrite) => new Promise((resolve, reject) => {
|
|
27220
|
-
|
|
27296
|
+
execFile2(
|
|
27221
27297
|
tsxBin,
|
|
27222
27298
|
[seedPath],
|
|
27223
27299
|
{
|
|
@@ -28192,9 +28268,9 @@ Run manually: ${pc10.cyan(betterstartExecCommand(pm, "seed"))}`,
|
|
|
28192
28268
|
if (isFreshProject) {
|
|
28193
28269
|
s.start("Creating initial git commit");
|
|
28194
28270
|
try {
|
|
28195
|
-
|
|
28196
|
-
|
|
28197
|
-
|
|
28271
|
+
execFileSync4("git", ["init"], { cwd, stdio: "pipe" });
|
|
28272
|
+
execFileSync4("git", ["add", "."], { cwd, stdio: "pipe" });
|
|
28273
|
+
execFileSync4("git", ["commit", "-m", "Initial commit from BetterStart"], {
|
|
28198
28274
|
cwd,
|
|
28199
28275
|
stdio: "pipe"
|
|
28200
28276
|
});
|
|
@@ -28895,581 +28971,13 @@ async function runListPresetsCommand(options) {
|
|
|
28895
28971
|
}
|
|
28896
28972
|
|
|
28897
28973
|
// adapters/next/commands/menu-choices.ts
|
|
28898
|
-
import path55 from "path";
|
|
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
28974
|
import path56 from "path";
|
|
28924
|
-
import * as p29 from "@clack/prompts";
|
|
28925
|
-
async function runRemoveCommand(items, options) {
|
|
28926
|
-
const removeIntegrationsMode = Boolean(options.integration);
|
|
28927
|
-
if (!removeIntegrationsMode && items.includes("core")) {
|
|
28928
|
-
p29.log.error("The core Admin cannot be removed.");
|
|
28929
|
-
process.exit(1);
|
|
28930
|
-
}
|
|
28931
|
-
const presetIds = items.filter(isPresetId);
|
|
28932
|
-
const integrationIds = items.filter(isIntegrationId);
|
|
28933
|
-
if (!removeIntegrationsMode && integrationIds.length > 0) {
|
|
28934
|
-
p29.log.error(
|
|
28935
|
-
`Integration IDs require --integration. Run \`betterstart remove --integration ${integrationIds.join(" ")}\`.`
|
|
28936
|
-
);
|
|
28937
|
-
process.exit(1);
|
|
28938
|
-
}
|
|
28939
|
-
if (removeIntegrationsMode && presetIds.length > 0) {
|
|
28940
|
-
p29.log.error(`Preset IDs cannot be removed with --integration: ${presetIds.join(", ")}`);
|
|
28941
|
-
process.exit(1);
|
|
28942
|
-
}
|
|
28943
|
-
const invalidItems = removeIntegrationsMode ? items.filter((integrationId) => !isIntegrationId(integrationId)) : items.filter((presetId) => !isPresetId(presetId));
|
|
28944
|
-
if (invalidItems.length > 0) {
|
|
28945
|
-
p29.log.error(
|
|
28946
|
-
removeIntegrationsMode ? formatUnknownIntegrationMessage(invalidItems) : formatUnknownPresetMessage(invalidItems)
|
|
28947
|
-
);
|
|
28948
|
-
process.exit(1);
|
|
28949
|
-
}
|
|
28950
|
-
const cwd = options.cwd ? path56.resolve(options.cwd) : process.cwd();
|
|
28951
|
-
const config = await resolveConfigOrExit(cwd);
|
|
28952
|
-
const pm = detectPackageManager(cwd);
|
|
28953
|
-
if (!options.force) {
|
|
28954
|
-
const confirmed = await p29.confirm({
|
|
28955
|
-
message: `Remove ${removeIntegrationsMode ? "integration" : "preset"}${items.length === 1 ? "" : "s"} ${items.join(", ")}?`,
|
|
28956
|
-
initialValue: false
|
|
28957
|
-
});
|
|
28958
|
-
if (p29.isCancel(confirmed) || !confirmed) {
|
|
28959
|
-
p29.cancel(`${removeIntegrationsMode ? "Integration" : "Preset"} removal cancelled.`);
|
|
28960
|
-
process.exit(0);
|
|
28961
|
-
}
|
|
28962
|
-
}
|
|
28963
|
-
if (removeIntegrationsMode) {
|
|
28964
|
-
const result2 = await removeIntegrations({
|
|
28965
|
-
cwd,
|
|
28966
|
-
config,
|
|
28967
|
-
pm,
|
|
28968
|
-
integrationIds
|
|
28969
|
-
});
|
|
28970
|
-
writeConfigFile(cwd, result2.config);
|
|
28971
|
-
if (result2.removed.length === 0) {
|
|
28972
|
-
p29.outro("No integrations were removed.");
|
|
28973
|
-
return;
|
|
28974
|
-
}
|
|
28975
|
-
if (result2.warnings.length > 0) {
|
|
28976
|
-
p29.note(result2.warnings.join("\n"), "Warnings");
|
|
28977
|
-
}
|
|
28978
|
-
p29.outro(
|
|
28979
|
-
`Removed integration${result2.removed.length === 1 ? "" : "s"}: ${result2.removed.join(", ")}`
|
|
28980
|
-
);
|
|
28981
|
-
return;
|
|
28982
|
-
}
|
|
28983
|
-
const result = await removePresets({
|
|
28984
|
-
cwd,
|
|
28985
|
-
config,
|
|
28986
|
-
pm,
|
|
28987
|
-
presetIds
|
|
28988
|
-
});
|
|
28989
|
-
writeConfigFile(cwd, result.config);
|
|
28990
|
-
if (result.removed.length === 0) {
|
|
28991
|
-
p29.outro("No presets were removed.");
|
|
28992
|
-
return;
|
|
28993
|
-
}
|
|
28994
|
-
if (result.warnings.length > 0) {
|
|
28995
|
-
p29.note(result.warnings.join("\n"), "Warnings");
|
|
28996
|
-
}
|
|
28997
|
-
p29.outro(`Removed preset${result.removed.length === 1 ? "" : "s"}: ${result.removed.join(", ")}`);
|
|
28998
|
-
}
|
|
28999
28975
|
|
|
29000
|
-
// adapters/next/commands/
|
|
28976
|
+
// adapters/next/commands/update-component.ts
|
|
28977
|
+
import { execFileSync as execFileSync5 } from "child_process";
|
|
29001
28978
|
import fs42 from "fs";
|
|
29002
|
-
import
|
|
28979
|
+
import path55 from "path";
|
|
29003
28980
|
import * as clack3 from "@clack/prompts";
|
|
29004
|
-
function removePath2(cwd, filePath) {
|
|
29005
|
-
const fullPath = path57.join(cwd, ...filePath.split("/"));
|
|
29006
|
-
const existed = fs42.existsSync(fullPath);
|
|
29007
|
-
fs42.rmSync(fullPath, { recursive: true, force: true });
|
|
29008
|
-
return existed;
|
|
29009
|
-
}
|
|
29010
|
-
function cleanupEmptyDirs3(cwd, deletedPaths, configPaths) {
|
|
29011
|
-
const stopRoots = /* @__PURE__ */ new Set([
|
|
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("/"))
|
|
29016
|
-
]);
|
|
29017
|
-
for (const deletedPath of deletedPaths) {
|
|
29018
|
-
let current = path57.dirname(path57.join(cwd, ...deletedPath.split("/")));
|
|
29019
|
-
while (!stopRoots.has(current)) {
|
|
29020
|
-
if (!fs42.existsSync(current)) {
|
|
29021
|
-
current = path57.dirname(current);
|
|
29022
|
-
continue;
|
|
29023
|
-
}
|
|
29024
|
-
const entries = fs42.readdirSync(current);
|
|
29025
|
-
if (entries.length > 0) {
|
|
29026
|
-
break;
|
|
29027
|
-
}
|
|
29028
|
-
fs42.rmdirSync(current);
|
|
29029
|
-
current = path57.dirname(current);
|
|
29030
|
-
}
|
|
29031
|
-
}
|
|
29032
|
-
}
|
|
29033
|
-
function resolveSchemaOwnerForRemoval(cwd, schemaName) {
|
|
29034
|
-
const explicitOwner = getSchemaOwner(cwd, schemaName);
|
|
29035
|
-
if (explicitOwner) {
|
|
29036
|
-
return explicitOwner;
|
|
29037
|
-
}
|
|
29038
|
-
if (schemaName === "settings") {
|
|
29039
|
-
return "core";
|
|
29040
|
-
}
|
|
29041
|
-
return "user";
|
|
29042
|
-
}
|
|
29043
|
-
async function runRemoveSchemaCommand(schemaName, options) {
|
|
29044
|
-
const owner = resolveSchemaOwnerForRemoval(
|
|
29045
|
-
options.cwd ? path57.resolve(options.cwd) : process.cwd(),
|
|
29046
|
-
schemaName
|
|
29047
|
-
);
|
|
29048
|
-
if (owner === "core") {
|
|
29049
|
-
clack3.log.error(
|
|
29050
|
-
`"${schemaName}" is a core Admin module and cannot be removed with remove-schema.`
|
|
29051
|
-
);
|
|
29052
|
-
process.exit(1);
|
|
29053
|
-
}
|
|
29054
|
-
if (owner.startsWith("preset:")) {
|
|
29055
|
-
clack3.log.error(`"${schemaName}" is owned by ${owner}. Remove the owning preset instead.`);
|
|
29056
|
-
process.exit(1);
|
|
29057
|
-
}
|
|
29058
|
-
const cwd = options.cwd ? path57.resolve(options.cwd) : process.cwd();
|
|
29059
|
-
const config = await resolveConfigOrExit(cwd);
|
|
29060
|
-
const paths = resolveProjectPaths(config);
|
|
29061
|
-
const manifest = loadManifest(cwd, schemaName);
|
|
29062
|
-
if (!snapshotRootExists(cwd)) {
|
|
29063
|
-
clack3.log.error(UNSUPPORTED_PROJECT_STATE_MESSAGE);
|
|
29064
|
-
process.exit(1);
|
|
29065
|
-
}
|
|
29066
|
-
if (!manifest) {
|
|
29067
|
-
clack3.log.error(UNSUPPORTED_PROJECT_STATE_MESSAGE);
|
|
29068
|
-
process.exit(1);
|
|
29069
|
-
}
|
|
29070
|
-
if (!options.force) {
|
|
29071
|
-
if (!isInteractiveSession()) {
|
|
29072
|
-
clack3.log.error(
|
|
29073
|
-
`Removing generated files for ${schemaName} needs confirmation. Re-run with --force.`
|
|
29074
|
-
);
|
|
29075
|
-
process.exit(1);
|
|
29076
|
-
}
|
|
29077
|
-
const confirmed = await clack3.confirm({
|
|
29078
|
-
message: `Remove generated files for ${schemaName}?`,
|
|
29079
|
-
initialValue: false
|
|
29080
|
-
});
|
|
29081
|
-
if (clack3.isCancel(confirmed) || !confirmed) {
|
|
29082
|
-
clack3.cancel("Cancelled.");
|
|
29083
|
-
return;
|
|
29084
|
-
}
|
|
29085
|
-
}
|
|
29086
|
-
const deletedPaths = [];
|
|
29087
|
-
for (const file of [...manifest.files.map((entry) => entry.path), ...manifest.skipped]) {
|
|
29088
|
-
if (removePath2(cwd, file)) {
|
|
29089
|
-
deletedPaths.push(file);
|
|
29090
|
-
}
|
|
29091
|
-
}
|
|
29092
|
-
const loaded = (() => {
|
|
29093
|
-
try {
|
|
29094
|
-
return loadSchema(path57.join(cwd, ...paths.schemasDir.split("/")), schemaName);
|
|
29095
|
-
} catch {
|
|
29096
|
-
return null;
|
|
29097
|
-
}
|
|
29098
|
-
})();
|
|
29099
|
-
const kebabName = toKebabCase(schemaName);
|
|
29100
|
-
if (loaded?.type === "form") {
|
|
29101
|
-
if (removePath2(cwd, `${paths.adminActionsDir}/${schemaName}`)) {
|
|
29102
|
-
deletedPaths.push(`${paths.adminActionsDir}/${schemaName}`);
|
|
29103
|
-
}
|
|
29104
|
-
if (removePath2(cwd, `${paths.pagesDir}/forms/${kebabName}`)) {
|
|
29105
|
-
deletedPaths.push(`${paths.pagesDir}/forms/${kebabName}`);
|
|
29106
|
-
}
|
|
29107
|
-
} else {
|
|
29108
|
-
if (removePath2(cwd, `${paths.adminActionsDir}/${schemaName}`)) {
|
|
29109
|
-
deletedPaths.push(`${paths.adminActionsDir}/${schemaName}`);
|
|
29110
|
-
}
|
|
29111
|
-
if (removePath2(cwd, `${paths.pagesDir}/${schemaName}`)) {
|
|
29112
|
-
deletedPaths.push(`${paths.pagesDir}/${schemaName}`);
|
|
29113
|
-
}
|
|
29114
|
-
}
|
|
29115
|
-
cleanupEmptyDirs3(cwd, deletedPaths, paths);
|
|
29116
|
-
deleteSnapshot(cwd, schemaName);
|
|
29117
|
-
if (hasTombstone(cwd, schemaName)) {
|
|
29118
|
-
clearTombstone(cwd, schemaName);
|
|
29119
|
-
}
|
|
29120
|
-
writeTombstone(cwd, schemaName);
|
|
29121
|
-
await applyGeneratedFiles({
|
|
29122
|
-
cwd,
|
|
29123
|
-
config,
|
|
29124
|
-
scope: BARREL_SCOPE,
|
|
29125
|
-
schemaJson: { name: BARREL_SCOPE },
|
|
29126
|
-
generatedFiles: renderBarrelFiles(cwd, config),
|
|
29127
|
-
force: false,
|
|
29128
|
-
interactive: false
|
|
29129
|
-
});
|
|
29130
|
-
clack3.log.info(
|
|
29131
|
-
`Tombstone written: .betterstart/snapshots/_removed/${schemaName}
|
|
29132
|
-
Schema JSON preserved.`
|
|
29133
|
-
);
|
|
29134
|
-
clack3.outro(`Removed generated files for ${schemaName}`);
|
|
29135
|
-
}
|
|
29136
|
-
|
|
29137
|
-
// adapters/next/commands/uninstall.ts
|
|
29138
|
-
import fs44 from "fs";
|
|
29139
|
-
import path58 from "path";
|
|
29140
|
-
import * as p30 from "@clack/prompts";
|
|
29141
|
-
import pc11 from "picocolors";
|
|
29142
|
-
|
|
29143
|
-
// adapters/next/commands/uninstall-cleaners.ts
|
|
29144
|
-
import fs43 from "fs";
|
|
29145
|
-
function stripJsonComments2(input) {
|
|
29146
|
-
let result = "";
|
|
29147
|
-
let i = 0;
|
|
29148
|
-
while (i < input.length) {
|
|
29149
|
-
if (input[i] === '"') {
|
|
29150
|
-
let j = i + 1;
|
|
29151
|
-
while (j < input.length) {
|
|
29152
|
-
if (input[j] === "\\") {
|
|
29153
|
-
j += 2;
|
|
29154
|
-
continue;
|
|
29155
|
-
}
|
|
29156
|
-
if (input[j] === '"') {
|
|
29157
|
-
j++;
|
|
29158
|
-
break;
|
|
29159
|
-
}
|
|
29160
|
-
j++;
|
|
29161
|
-
}
|
|
29162
|
-
result += input.slice(i, j);
|
|
29163
|
-
i = j;
|
|
29164
|
-
} else if (input[i] === "/" && input[i + 1] === "/") {
|
|
29165
|
-
const nl = input.indexOf("\n", i);
|
|
29166
|
-
i = nl === -1 ? input.length : nl;
|
|
29167
|
-
} else if (input[i] === "/" && input[i + 1] === "*") {
|
|
29168
|
-
const end = input.indexOf("*/", i + 2);
|
|
29169
|
-
i = end === -1 ? input.length : end + 2;
|
|
29170
|
-
} else {
|
|
29171
|
-
result += input[i];
|
|
29172
|
-
i++;
|
|
29173
|
-
}
|
|
29174
|
-
}
|
|
29175
|
-
return result;
|
|
29176
|
-
}
|
|
29177
|
-
function cleanTsconfig(tsconfigPath, aliasRoot = "@admin") {
|
|
29178
|
-
if (!fs43.existsSync(tsconfigPath)) return [];
|
|
29179
|
-
const raw = fs43.readFileSync(tsconfigPath, "utf-8");
|
|
29180
|
-
const stripped = stripJsonComments2(raw).replace(/,\s*([\]}])/g, "$1");
|
|
29181
|
-
let tsconfig;
|
|
29182
|
-
try {
|
|
29183
|
-
tsconfig = JSON.parse(stripped);
|
|
29184
|
-
} catch {
|
|
29185
|
-
return [];
|
|
29186
|
-
}
|
|
29187
|
-
const compilerOptions = tsconfig.compilerOptions ?? {};
|
|
29188
|
-
const paths = compilerOptions.paths ?? {};
|
|
29189
|
-
const removed = [];
|
|
29190
|
-
for (const key of Object.keys(paths)) {
|
|
29191
|
-
if (key.startsWith("@admin/") || key === "@admin/*" || key.startsWith(`${aliasRoot}/`) || key === `${aliasRoot}/*`) {
|
|
29192
|
-
removed.push(key);
|
|
29193
|
-
delete paths[key];
|
|
29194
|
-
}
|
|
29195
|
-
}
|
|
29196
|
-
if (removed.length === 0) return [];
|
|
29197
|
-
if (Object.keys(paths).length === 0) {
|
|
29198
|
-
compilerOptions.paths = void 0;
|
|
29199
|
-
} else {
|
|
29200
|
-
compilerOptions.paths = paths;
|
|
29201
|
-
}
|
|
29202
|
-
tsconfig.compilerOptions = compilerOptions;
|
|
29203
|
-
fs43.writeFileSync(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}
|
|
29204
|
-
`, "utf-8");
|
|
29205
|
-
return removed;
|
|
29206
|
-
}
|
|
29207
|
-
function cleanCss(cssPath, namespace = "admin") {
|
|
29208
|
-
if (!fs43.existsSync(cssPath)) return [];
|
|
29209
|
-
const content = fs43.readFileSync(cssPath, "utf-8");
|
|
29210
|
-
const lines = content.split("\n");
|
|
29211
|
-
const sourcePattern = new RegExp(`^@source\\s+"[^"]*(?:admin|${namespace})[^"]*";\\s*$`);
|
|
29212
|
-
const removed = [];
|
|
29213
|
-
const kept = [];
|
|
29214
|
-
for (const line of lines) {
|
|
29215
|
-
if (sourcePattern.test(line)) {
|
|
29216
|
-
removed.push(line.trim());
|
|
29217
|
-
} else {
|
|
29218
|
-
kept.push(line);
|
|
29219
|
-
}
|
|
29220
|
-
}
|
|
29221
|
-
if (removed.length === 0) return [];
|
|
29222
|
-
const cleaned = kept.join("\n").replace(/\n{3,}/g, "\n\n");
|
|
29223
|
-
fs43.writeFileSync(cssPath, cleaned, "utf-8");
|
|
29224
|
-
return removed;
|
|
29225
|
-
}
|
|
29226
|
-
function cleanEnvFile(envPath) {
|
|
29227
|
-
if (!fs43.existsSync(envPath)) return [];
|
|
29228
|
-
const content = fs43.readFileSync(envPath, "utf-8");
|
|
29229
|
-
const lines = content.split("\n");
|
|
29230
|
-
const removed = [];
|
|
29231
|
-
const kept = [];
|
|
29232
|
-
const headerPattern = /^# =+$/;
|
|
29233
|
-
const headerTextPattern = /^# BetterStart Admin$/;
|
|
29234
|
-
for (let i = 0; i < lines.length; i++) {
|
|
29235
|
-
const line = lines[i];
|
|
29236
|
-
const trimmed = line.trim();
|
|
29237
|
-
if (trimmed.match(/^BETTERSTART_\w+=/)) {
|
|
29238
|
-
const key = trimmed.split("=")[0];
|
|
29239
|
-
removed.push(key);
|
|
29240
|
-
continue;
|
|
29241
|
-
}
|
|
29242
|
-
if (headerPattern.test(trimmed)) {
|
|
29243
|
-
const next = lines[i + 1]?.trim();
|
|
29244
|
-
const afterNext = lines[i + 2]?.trim();
|
|
29245
|
-
if (next && headerTextPattern.test(next) && afterNext && headerPattern.test(afterNext)) {
|
|
29246
|
-
i += 2;
|
|
29247
|
-
continue;
|
|
29248
|
-
}
|
|
29249
|
-
}
|
|
29250
|
-
if (trimmed.startsWith("#") && !headerPattern.test(trimmed)) {
|
|
29251
|
-
const nextNonEmpty = findNextNonEmptyLine(lines, i + 1);
|
|
29252
|
-
if (nextNonEmpty?.match(/^BETTERSTART_\w+=/)) {
|
|
29253
|
-
continue;
|
|
29254
|
-
}
|
|
29255
|
-
}
|
|
29256
|
-
kept.push(line);
|
|
29257
|
-
}
|
|
29258
|
-
if (removed.length === 0) return [];
|
|
29259
|
-
const result = kept.join("\n").replace(/\n{3,}/g, "\n\n").trim();
|
|
29260
|
-
if (result === "") {
|
|
29261
|
-
fs43.unlinkSync(envPath);
|
|
29262
|
-
} else {
|
|
29263
|
-
fs43.writeFileSync(envPath, `${result}
|
|
29264
|
-
`, "utf-8");
|
|
29265
|
-
}
|
|
29266
|
-
return removed;
|
|
29267
|
-
}
|
|
29268
|
-
function findNextNonEmptyLine(lines, startIndex) {
|
|
29269
|
-
for (let i = startIndex; i < lines.length; i++) {
|
|
29270
|
-
const trimmed = lines[i].trim();
|
|
29271
|
-
if (trimmed !== "") return trimmed;
|
|
29272
|
-
}
|
|
29273
|
-
return null;
|
|
29274
|
-
}
|
|
29275
|
-
|
|
29276
|
-
// adapters/next/commands/uninstall.ts
|
|
29277
|
-
function findMainCss2(cwd) {
|
|
29278
|
-
const candidates = [
|
|
29279
|
-
"src/app/globals.css",
|
|
29280
|
-
"app/globals.css",
|
|
29281
|
-
"src/app/global.css",
|
|
29282
|
-
"app/global.css",
|
|
29283
|
-
"src/app/app.css",
|
|
29284
|
-
"app/app.css",
|
|
29285
|
-
"src/globals.css",
|
|
29286
|
-
"globals.css"
|
|
29287
|
-
];
|
|
29288
|
-
for (const candidate of candidates) {
|
|
29289
|
-
const filePath = path58.join(cwd, candidate);
|
|
29290
|
-
if (fs44.existsSync(filePath)) return filePath;
|
|
29291
|
-
}
|
|
29292
|
-
return void 0;
|
|
29293
|
-
}
|
|
29294
|
-
function isCLICreatedBiome(biomePath) {
|
|
29295
|
-
if (!fs44.existsSync(biomePath)) return false;
|
|
29296
|
-
try {
|
|
29297
|
-
const content = JSON.parse(fs44.readFileSync(biomePath, "utf-8"));
|
|
29298
|
-
return content.$schema?.includes("biomejs.dev") && content.formatter?.indentStyle === "space" && content.javascript?.formatter?.quoteStyle === "single" && Array.isArray(content.files?.ignore) && content.files.ignore.includes(".next");
|
|
29299
|
-
} catch {
|
|
29300
|
-
return false;
|
|
29301
|
-
}
|
|
29302
|
-
}
|
|
29303
|
-
function buildUninstallPlan(cwd, namespaceValue) {
|
|
29304
|
-
const steps = [];
|
|
29305
|
-
const namespace = resolveAdminNamespace(namespaceValue);
|
|
29306
|
-
const hasSrc = fs44.existsSync(path58.join(cwd, "src"));
|
|
29307
|
-
const appBase = hasSrc ? "src/app" : "app";
|
|
29308
|
-
const dirs = [];
|
|
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)");
|
|
29313
|
-
if (fs44.existsSync(adminDir)) dirs.push(`${namespace.segment}/`);
|
|
29314
|
-
if (namespace.segment !== "admin" && fs44.existsSync(legacyAdminDir)) dirs.push("admin/");
|
|
29315
|
-
if (fs44.existsSync(adminRouteGroup)) dirs.push(`${appBase}/${namespace.routeGroup}/`);
|
|
29316
|
-
if (namespace.segment !== "admin" && fs44.existsSync(legacyAdminRouteGroup))
|
|
29317
|
-
dirs.push(`${appBase}/(admin)/`);
|
|
29318
|
-
if (dirs.length > 0) {
|
|
29319
|
-
steps.push({
|
|
29320
|
-
label: "Admin directories",
|
|
29321
|
-
items: dirs,
|
|
29322
|
-
count: dirs.length,
|
|
29323
|
-
unit: dirs.length === 1 ? "directory" : "directories",
|
|
29324
|
-
execute() {
|
|
29325
|
-
if (fs44.existsSync(adminDir)) fs44.rmSync(adminDir, { recursive: true, force: true });
|
|
29326
|
-
if (fs44.existsSync(legacyAdminDir))
|
|
29327
|
-
fs44.rmSync(legacyAdminDir, { recursive: true, force: true });
|
|
29328
|
-
if (fs44.existsSync(adminRouteGroup)) {
|
|
29329
|
-
fs44.rmSync(adminRouteGroup, { recursive: true, force: true });
|
|
29330
|
-
}
|
|
29331
|
-
if (fs44.existsSync(legacyAdminRouteGroup)) {
|
|
29332
|
-
fs44.rmSync(legacyAdminRouteGroup, { recursive: true, force: true });
|
|
29333
|
-
}
|
|
29334
|
-
}
|
|
29335
|
-
});
|
|
29336
|
-
}
|
|
29337
|
-
const configFiles = [];
|
|
29338
|
-
const configPaths = [];
|
|
29339
|
-
const candidates = [
|
|
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")]
|
|
29343
|
-
];
|
|
29344
|
-
for (const [label, fullPath] of candidates) {
|
|
29345
|
-
if (fs44.existsSync(fullPath)) {
|
|
29346
|
-
configFiles.push(label);
|
|
29347
|
-
configPaths.push(fullPath);
|
|
29348
|
-
}
|
|
29349
|
-
}
|
|
29350
|
-
const biomePath = path58.join(cwd, "biome.json");
|
|
29351
|
-
if (isCLICreatedBiome(biomePath)) {
|
|
29352
|
-
configFiles.push("biome.json (CLI-created)");
|
|
29353
|
-
configPaths.push(biomePath);
|
|
29354
|
-
}
|
|
29355
|
-
if (configFiles.length > 0) {
|
|
29356
|
-
steps.push({
|
|
29357
|
-
label: "Config files",
|
|
29358
|
-
items: configFiles,
|
|
29359
|
-
count: configFiles.length,
|
|
29360
|
-
unit: configFiles.length === 1 ? "file" : "files",
|
|
29361
|
-
execute() {
|
|
29362
|
-
for (const p32 of configPaths) {
|
|
29363
|
-
if (fs44.existsSync(p32)) fs44.unlinkSync(p32);
|
|
29364
|
-
}
|
|
29365
|
-
}
|
|
29366
|
-
});
|
|
29367
|
-
}
|
|
29368
|
-
const tsconfigPath = path58.join(cwd, "tsconfig.json");
|
|
29369
|
-
if (fs44.existsSync(tsconfigPath)) {
|
|
29370
|
-
const content = fs44.readFileSync(tsconfigPath, "utf-8");
|
|
29371
|
-
const aliasMatches = [
|
|
29372
|
-
...content.match(/"@admin\//g) ?? [],
|
|
29373
|
-
...content.match(new RegExp(`"${namespace.alias}/`, "g")) ?? []
|
|
29374
|
-
];
|
|
29375
|
-
if (aliasMatches && aliasMatches.length > 0) {
|
|
29376
|
-
const aliasCount = aliasMatches.length;
|
|
29377
|
-
steps.push({
|
|
29378
|
-
label: "tsconfig.json path aliases",
|
|
29379
|
-
items: [`${namespace.alias}/* aliases in tsconfig.json`],
|
|
29380
|
-
count: aliasCount,
|
|
29381
|
-
unit: aliasCount === 1 ? "alias" : "aliases",
|
|
29382
|
-
execute() {
|
|
29383
|
-
cleanTsconfig(tsconfigPath, namespace.alias);
|
|
29384
|
-
}
|
|
29385
|
-
});
|
|
29386
|
-
}
|
|
29387
|
-
}
|
|
29388
|
-
const cssFile = findMainCss2(cwd);
|
|
29389
|
-
if (cssFile) {
|
|
29390
|
-
const cssContent = fs44.readFileSync(cssFile, "utf-8");
|
|
29391
|
-
const sourceLines = cssContent.split("\n").filter(
|
|
29392
|
-
(l) => new RegExp(`^@source\\s+"[^"]*(?:admin|${namespace.segment})[^"]*";\\s*$`).test(l)
|
|
29393
|
-
);
|
|
29394
|
-
if (sourceLines.length > 0) {
|
|
29395
|
-
const relCss = path58.relative(cwd, cssFile);
|
|
29396
|
-
steps.push({
|
|
29397
|
-
label: `CSS @source lines (${relCss})`,
|
|
29398
|
-
items: [`@source lines in ${relCss}`],
|
|
29399
|
-
count: sourceLines.length,
|
|
29400
|
-
unit: sourceLines.length === 1 ? "line" : "lines",
|
|
29401
|
-
execute() {
|
|
29402
|
-
cleanCss(cssFile, namespace.segment);
|
|
29403
|
-
}
|
|
29404
|
-
});
|
|
29405
|
-
}
|
|
29406
|
-
}
|
|
29407
|
-
const envPath = path58.join(cwd, ".env.local");
|
|
29408
|
-
if (fs44.existsSync(envPath)) {
|
|
29409
|
-
const envContent = fs44.readFileSync(envPath, "utf-8");
|
|
29410
|
-
const bsVars = envContent.split("\n").filter((l) => l.trim().match(/^BETTERSTART_\w+=/)).map((l) => l.split("=")[0]);
|
|
29411
|
-
if (bsVars.length > 0) {
|
|
29412
|
-
steps.push({
|
|
29413
|
-
label: ".env.local variables",
|
|
29414
|
-
items: ["BETTERSTART_* vars in .env.local"],
|
|
29415
|
-
count: bsVars.length,
|
|
29416
|
-
unit: bsVars.length === 1 ? "variable" : "variables",
|
|
29417
|
-
execute() {
|
|
29418
|
-
cleanEnvFile(envPath);
|
|
29419
|
-
}
|
|
29420
|
-
});
|
|
29421
|
-
}
|
|
29422
|
-
}
|
|
29423
|
-
return steps;
|
|
29424
|
-
}
|
|
29425
|
-
async function runUninstallCommand(options) {
|
|
29426
|
-
const cwd = options.cwd ? path58.resolve(options.cwd) : process.cwd();
|
|
29427
|
-
p30.intro(pc11.bgRed(pc11.white(" BetterStart Uninstall ")));
|
|
29428
|
-
let namespace = DEFAULT_ADMIN_NAMESPACE;
|
|
29429
|
-
try {
|
|
29430
|
-
const config = await resolveConfig(cwd);
|
|
29431
|
-
namespace = config.frameworkConfig.next.namespace;
|
|
29432
|
-
} catch {
|
|
29433
|
-
}
|
|
29434
|
-
const steps = buildUninstallPlan(cwd, namespace);
|
|
29435
|
-
if (steps.length === 0) {
|
|
29436
|
-
p30.log.success(`${pc11.green("\u2713")} Nothing to remove \u2014 project is already clean.`);
|
|
29437
|
-
p30.outro("Project already clean");
|
|
29438
|
-
return;
|
|
29439
|
-
}
|
|
29440
|
-
const planLines = steps.map((step) => {
|
|
29441
|
-
const names = step.items.join(" ");
|
|
29442
|
-
const countLabel = pc11.dim(`${step.count} ${step.unit}`);
|
|
29443
|
-
return `${pc11.red("\u2717")} ${names} ${countLabel}`;
|
|
29444
|
-
});
|
|
29445
|
-
p30.note(planLines.join("\n"), "Uninstall plan");
|
|
29446
|
-
if (!options.force) {
|
|
29447
|
-
const confirmed = await p30.confirm({
|
|
29448
|
-
message: "Proceed with uninstall?",
|
|
29449
|
-
initialValue: false
|
|
29450
|
-
});
|
|
29451
|
-
if (p30.isCancel(confirmed) || !confirmed) {
|
|
29452
|
-
p30.cancel("Uninstall cancelled.");
|
|
29453
|
-
process.exit(0);
|
|
29454
|
-
}
|
|
29455
|
-
}
|
|
29456
|
-
const s = spinner2();
|
|
29457
|
-
s.start(steps[0].label);
|
|
29458
|
-
for (const step of steps) {
|
|
29459
|
-
s.message(step.label);
|
|
29460
|
-
step.execute();
|
|
29461
|
-
}
|
|
29462
|
-
const parts = steps.map((step) => `${step.count} ${step.unit}`);
|
|
29463
|
-
s.stop(`Removed ${parts.join(", ")}`);
|
|
29464
|
-
p30.note(pc11.dim("Database tables were NOT dropped \u2014 drop them manually if needed."), "Next steps");
|
|
29465
|
-
p30.outro("Uninstall complete");
|
|
29466
|
-
}
|
|
29467
|
-
|
|
29468
|
-
// adapters/next/commands/update-component.ts
|
|
29469
|
-
import { execFileSync as execFileSync6 } from "child_process";
|
|
29470
|
-
import fs45 from "fs";
|
|
29471
|
-
import path59 from "path";
|
|
29472
|
-
import * as clack4 from "@clack/prompts";
|
|
29473
28981
|
import fsExtra from "fs-extra";
|
|
29474
28982
|
var STATIC_CUSTOM_DEPENDENCIES = {
|
|
29475
28983
|
"content-editor": [
|
|
@@ -29719,24 +29227,24 @@ function applyNamespaceToTemplateEntry(entry, config, cwd) {
|
|
|
29719
29227
|
};
|
|
29720
29228
|
}
|
|
29721
29229
|
function writeNamespacedFile(srcPath, destPath, namespace) {
|
|
29722
|
-
|
|
29230
|
+
fs42.writeFileSync(
|
|
29723
29231
|
destPath,
|
|
29724
|
-
applyAdminNamespaceToContent(
|
|
29232
|
+
applyAdminNamespaceToContent(fs42.readFileSync(srcPath, "utf-8"), namespace),
|
|
29725
29233
|
"utf-8"
|
|
29726
29234
|
);
|
|
29727
29235
|
}
|
|
29728
29236
|
function copyNamespacedDirectory(srcDir, destDir, namespace) {
|
|
29729
|
-
const entries =
|
|
29237
|
+
const entries = fs42.readdirSync(srcDir, { withFileTypes: true });
|
|
29730
29238
|
for (const entry of entries) {
|
|
29731
29239
|
const namespacedName = applyAdminNamespaceToPath(entry.name, namespace);
|
|
29732
|
-
const srcPath =
|
|
29733
|
-
const destPath =
|
|
29240
|
+
const srcPath = path55.join(srcDir, entry.name);
|
|
29241
|
+
const destPath = path55.join(destDir, namespacedName);
|
|
29734
29242
|
if (entry.isDirectory()) {
|
|
29735
29243
|
fsExtra.ensureDirSync(destPath);
|
|
29736
29244
|
copyNamespacedDirectory(srcPath, destPath, namespace);
|
|
29737
29245
|
continue;
|
|
29738
29246
|
}
|
|
29739
|
-
fsExtra.ensureDirSync(
|
|
29247
|
+
fsExtra.ensureDirSync(path55.dirname(destPath));
|
|
29740
29248
|
writeNamespacedFile(srcPath, destPath, namespace);
|
|
29741
29249
|
}
|
|
29742
29250
|
}
|
|
@@ -29747,10 +29255,10 @@ function hasIntegration(config, integrationId) {
|
|
|
29747
29255
|
return config.integrations.installed.includes(integrationId);
|
|
29748
29256
|
}
|
|
29749
29257
|
function readProjectPackageJson2(cwd) {
|
|
29750
|
-
const pkgPath =
|
|
29751
|
-
if (!
|
|
29258
|
+
const pkgPath = path55.join(cwd, "package.json");
|
|
29259
|
+
if (!fs42.existsSync(pkgPath)) return null;
|
|
29752
29260
|
try {
|
|
29753
|
-
return JSON.parse(
|
|
29261
|
+
return JSON.parse(fs42.readFileSync(pkgPath, "utf-8"));
|
|
29754
29262
|
} catch {
|
|
29755
29263
|
return null;
|
|
29756
29264
|
}
|
|
@@ -30634,13 +30142,38 @@ var TEMPLATE_REGISTRY = {
|
|
|
30634
30142
|
relPath: "app/(admin)/admin/(authenticated)/settings/forms/forms-settings-page-content.tsx",
|
|
30635
30143
|
content: () => readTemplate("pages/settings/forms/forms-settings-page-content.tsx"),
|
|
30636
30144
|
base: "cwd",
|
|
30637
|
-
dependencies: [
|
|
30145
|
+
dependencies: [
|
|
30146
|
+
"form-notifications-drawer",
|
|
30147
|
+
"forms-settings-columns",
|
|
30148
|
+
"forms-settings-table",
|
|
30149
|
+
"page-header",
|
|
30150
|
+
"use-webhooks"
|
|
30151
|
+
]
|
|
30152
|
+
},
|
|
30153
|
+
"forms-settings-columns": {
|
|
30154
|
+
relPath: "app/(admin)/admin/(authenticated)/settings/forms/forms-settings-columns.tsx",
|
|
30155
|
+
content: () => readTemplate("pages/settings/forms/forms-settings-columns.tsx"),
|
|
30156
|
+
base: "cwd"
|
|
30157
|
+
},
|
|
30158
|
+
"forms-settings-table": {
|
|
30159
|
+
relPath: "app/(admin)/admin/(authenticated)/settings/forms/forms-settings-table.tsx",
|
|
30160
|
+
content: () => readTemplate("pages/settings/forms/forms-settings-table.tsx"),
|
|
30161
|
+
base: "cwd",
|
|
30162
|
+
dependencies: ["data-grid"]
|
|
30638
30163
|
},
|
|
30639
|
-
"
|
|
30640
|
-
relPath: "app/(admin)/admin/(authenticated)/settings/forms/
|
|
30641
|
-
content: () => readTemplate("pages/settings/forms/
|
|
30164
|
+
"form-notifications-drawer": {
|
|
30165
|
+
relPath: "app/(admin)/admin/(authenticated)/settings/forms/form-notifications-drawer.tsx",
|
|
30166
|
+
content: () => readTemplate("pages/settings/forms/form-notifications-drawer.tsx"),
|
|
30642
30167
|
base: "cwd",
|
|
30643
|
-
dependencies: [
|
|
30168
|
+
dependencies: [
|
|
30169
|
+
"button",
|
|
30170
|
+
"card",
|
|
30171
|
+
"drawer",
|
|
30172
|
+
"form",
|
|
30173
|
+
"form-settings-action",
|
|
30174
|
+
"scroll-area",
|
|
30175
|
+
"textarea"
|
|
30176
|
+
]
|
|
30644
30177
|
},
|
|
30645
30178
|
"webhooks-page": {
|
|
30646
30179
|
relPath: "app/(admin)/admin/(authenticated)/settings/webhooks/page.tsx",
|
|
@@ -31269,9 +30802,9 @@ function getStaticAssetComponents(assetDirectory) {
|
|
|
31269
30802
|
}
|
|
31270
30803
|
function getStaticAssetComponentEntries(assetDirectory) {
|
|
31271
30804
|
const assetDir = resolveCliAssetPath("shared-assets", "react-admin", assetDirectory);
|
|
31272
|
-
if (!
|
|
30805
|
+
if (!fs42.existsSync(assetDir)) return [];
|
|
31273
30806
|
const components = [];
|
|
31274
|
-
for (const entry of
|
|
30807
|
+
for (const entry of fs42.readdirSync(assetDir, { withFileTypes: true })) {
|
|
31275
30808
|
if (entry.isFile() && (entry.name.endsWith(".tsx") || entry.name.endsWith(".ts"))) {
|
|
31276
30809
|
components.push({
|
|
31277
30810
|
name: entry.name.replace(/\.(tsx|ts)$/, ""),
|
|
@@ -31279,556 +30812,1130 @@ function getStaticAssetComponentEntries(assetDirectory) {
|
|
|
31279
30812
|
});
|
|
31280
30813
|
continue;
|
|
31281
30814
|
}
|
|
31282
|
-
if (!entry.isDirectory()) {
|
|
30815
|
+
if (!entry.isDirectory()) {
|
|
30816
|
+
continue;
|
|
30817
|
+
}
|
|
30818
|
+
const indexFile = ["index.tsx", "index.ts"].find(
|
|
30819
|
+
(file) => fs42.existsSync(path55.join(assetDir, entry.name, file))
|
|
30820
|
+
);
|
|
30821
|
+
if (indexFile) {
|
|
30822
|
+
components.push({
|
|
30823
|
+
name: entry.name,
|
|
30824
|
+
file: path55.join(entry.name, indexFile)
|
|
30825
|
+
});
|
|
30826
|
+
}
|
|
30827
|
+
}
|
|
30828
|
+
return components.sort((a, b) => a.name.localeCompare(b.name));
|
|
30829
|
+
}
|
|
30830
|
+
function findStaticAssetFile(assetDir, componentName) {
|
|
30831
|
+
if (!fs42.existsSync(assetDir)) return void 0;
|
|
30832
|
+
const isNestedComponentName = /[\\/]/.test(componentName);
|
|
30833
|
+
const nestedComponentName = componentName.split(/[\\/]/).filter(Boolean).join(path55.sep);
|
|
30834
|
+
if (isNestedComponentName && nestedComponentName && !path55.isAbsolute(componentName) && !nestedComponentName.split(path55.sep).includes("..")) {
|
|
30835
|
+
for (const extension of [".tsx", ".ts"]) {
|
|
30836
|
+
const relPath = `${nestedComponentName}${extension}`;
|
|
30837
|
+
const filePath = path55.join(assetDir, relPath);
|
|
30838
|
+
if (fs42.existsSync(filePath) && fs42.statSync(filePath).isFile()) {
|
|
30839
|
+
return relPath;
|
|
30840
|
+
}
|
|
30841
|
+
}
|
|
30842
|
+
}
|
|
30843
|
+
if (!isNestedComponentName && !componentName.includes("..") && !path55.isAbsolute(componentName)) {
|
|
30844
|
+
for (const extension of [".tsx", ".ts"]) {
|
|
30845
|
+
const relPath = path55.join(componentName, `index${extension}`);
|
|
30846
|
+
const filePath = path55.join(assetDir, relPath);
|
|
30847
|
+
if (fs42.existsSync(filePath) && fs42.statSync(filePath).isFile()) {
|
|
30848
|
+
return relPath;
|
|
30849
|
+
}
|
|
30850
|
+
}
|
|
30851
|
+
}
|
|
30852
|
+
return fs42.readdirSync(assetDir, { withFileTypes: true }).find(
|
|
30853
|
+
(entry) => entry.isFile() && (entry.name.endsWith(".tsx") || entry.name.endsWith(".ts")) && entry.name.replace(/\.(tsx|ts)$/, "") === componentName
|
|
30854
|
+
)?.name;
|
|
30855
|
+
}
|
|
30856
|
+
function getAllComponentNames() {
|
|
30857
|
+
const staticUi = getStaticUiComponents();
|
|
30858
|
+
const staticCustom = getStaticCustomComponents();
|
|
30859
|
+
const templateKeys = Object.keys(TEMPLATE_REGISTRY);
|
|
30860
|
+
return [.../* @__PURE__ */ new Set([...staticUi, ...staticCustom, ...templateKeys, "tiptap"])].sort();
|
|
30861
|
+
}
|
|
30862
|
+
function getAllComponentNamesForConfig(config) {
|
|
30863
|
+
const staticUi = getStaticUiComponents();
|
|
30864
|
+
const staticCustom = getStaticCustomComponents();
|
|
30865
|
+
const templateKeys = Object.entries(TEMPLATE_REGISTRY).filter(
|
|
30866
|
+
([, entry]) => (!entry.requiredPreset || hasPreset(config, entry.requiredPreset)) && (!entry.requiredIntegration || hasIntegration(config, entry.requiredIntegration))
|
|
30867
|
+
).map(([name]) => name);
|
|
30868
|
+
return [.../* @__PURE__ */ new Set([...staticUi, ...staticCustom, ...templateKeys, "tiptap"])].sort();
|
|
30869
|
+
}
|
|
30870
|
+
async function runUpdateCommand(components, options) {
|
|
30871
|
+
const cwd = options.cwd ? path55.resolve(options.cwd) : process.cwd();
|
|
30872
|
+
const normalizedOnly = normalizeShadcnPresetOnly(options.only);
|
|
30873
|
+
validateShadcnPresetOptions(components, options);
|
|
30874
|
+
if (options.json && !options.list) {
|
|
30875
|
+
clack3.cancel("--json can only be used with --list.");
|
|
30876
|
+
process.exit(1);
|
|
30877
|
+
}
|
|
30878
|
+
if (options.list) {
|
|
30879
|
+
const uiComponents = getStaticUiComponentEntries();
|
|
30880
|
+
const customComponents = getStaticCustomComponentEntries();
|
|
30881
|
+
const templateKeys = Object.keys(TEMPLATE_REGISTRY).sort();
|
|
30882
|
+
const templatePath = (name) => {
|
|
30883
|
+
const entry = TEMPLATE_REGISTRY[name];
|
|
30884
|
+
return entry.displayPath ?? (typeof entry.relPath === "string" ? entry.relPath : "");
|
|
30885
|
+
};
|
|
30886
|
+
if (options.json) {
|
|
30887
|
+
const items = [
|
|
30888
|
+
...uiComponents.map((component) => ({
|
|
30889
|
+
name: component.name,
|
|
30890
|
+
path: `components/ui/${component.file}`,
|
|
30891
|
+
kind: "ui"
|
|
30892
|
+
})),
|
|
30893
|
+
...customComponents.map((component) => ({
|
|
30894
|
+
name: component.name,
|
|
30895
|
+
path: `components/custom/${component.file}`,
|
|
30896
|
+
kind: "custom"
|
|
30897
|
+
})),
|
|
30898
|
+
...templateKeys.map((name) => ({ name, path: templatePath(name), kind: "template" })),
|
|
30899
|
+
{ name: "tiptap", path: "components/custom/content-editor/tiptap-*/", kind: "special" }
|
|
30900
|
+
];
|
|
30901
|
+
console.log(JSON.stringify(items, null, 2));
|
|
30902
|
+
return;
|
|
30903
|
+
}
|
|
30904
|
+
const all = getAllComponentNames();
|
|
30905
|
+
clack3.intro("Available components");
|
|
30906
|
+
clack3.note(
|
|
30907
|
+
renderTableRows(
|
|
30908
|
+
uiComponents.map((component) => [component.name, `components/ui/${component.file}`])
|
|
30909
|
+
).join("\n"),
|
|
30910
|
+
`Shadcn UI Components (${uiComponents.length})`
|
|
30911
|
+
);
|
|
30912
|
+
clack3.note(
|
|
30913
|
+
renderTableRows(
|
|
30914
|
+
customComponents.map((component) => [component.name, `components/custom/${component.file}`])
|
|
30915
|
+
).join("\n"),
|
|
30916
|
+
`Custom Components (${customComponents.length})`
|
|
30917
|
+
);
|
|
30918
|
+
clack3.note(
|
|
30919
|
+
renderTableRows(templateKeys.map((name) => [name, templatePath(name)])).join("\n"),
|
|
30920
|
+
`Template Components (${templateKeys.length})`
|
|
30921
|
+
);
|
|
30922
|
+
clack3.note(
|
|
30923
|
+
renderTableRows([["tiptap", "components/custom/content-editor/tiptap-*/ (all files)"]]).join(
|
|
30924
|
+
"\n"
|
|
30925
|
+
),
|
|
30926
|
+
"Special"
|
|
30927
|
+
);
|
|
30928
|
+
clack3.outro(`${all.length} components available`);
|
|
30929
|
+
return;
|
|
30930
|
+
}
|
|
30931
|
+
const config = await resolveConfigOrExit(cwd);
|
|
30932
|
+
const admin = path55.resolve(cwd, config.paths.admin);
|
|
30933
|
+
if (!fs42.existsSync(admin)) {
|
|
30934
|
+
clack3.cancel(
|
|
30935
|
+
`Admin directory not found at ${config.paths.admin}. Run 'betterstart init' first.`
|
|
30936
|
+
);
|
|
30937
|
+
process.exit(1);
|
|
30938
|
+
}
|
|
30939
|
+
if (options.shadcnPreset) {
|
|
30940
|
+
runShadcnPresetUpdate({
|
|
30941
|
+
cwd,
|
|
30942
|
+
config,
|
|
30943
|
+
preset: options.shadcnPreset.trim(),
|
|
30944
|
+
only: normalizedOnly
|
|
30945
|
+
});
|
|
30946
|
+
return;
|
|
30947
|
+
}
|
|
30948
|
+
if (!options.all && components.length === 0) {
|
|
30949
|
+
clack3.log.error(
|
|
30950
|
+
"Provide component names or use --all. Run with --list to see available components."
|
|
30951
|
+
);
|
|
30952
|
+
process.exit(1);
|
|
30953
|
+
}
|
|
30954
|
+
clack3.intro("BetterStart Update Components");
|
|
30955
|
+
const toUpdate = options.all ? getAllComponentNamesForConfig(config) : components;
|
|
30956
|
+
const uiDir = resolveCliAssetPath("shared-assets", "react-admin", "ui");
|
|
30957
|
+
const customDir = resolveCliAssetPath("shared-assets", "react-admin", "custom");
|
|
30958
|
+
let updated = 0;
|
|
30959
|
+
let skipped = 0;
|
|
30960
|
+
const updatedTemplateNames = /* @__PURE__ */ new Set();
|
|
30961
|
+
const updatedStaticNames = /* @__PURE__ */ new Set();
|
|
30962
|
+
const requiredPackageDependencies = /* @__PURE__ */ new Set();
|
|
30963
|
+
const pendingWrites = [];
|
|
30964
|
+
function trackPackageDependencies(name) {
|
|
30965
|
+
for (const dependency of COMPONENT_PACKAGE_DEPENDENCIES[name] ?? []) {
|
|
30966
|
+
requiredPackageDependencies.add(dependency);
|
|
30967
|
+
}
|
|
30968
|
+
}
|
|
30969
|
+
function writeTemplateEntry(name, entry) {
|
|
30970
|
+
if (updatedTemplateNames.has(name)) {
|
|
30971
|
+
return false;
|
|
30972
|
+
}
|
|
30973
|
+
if (entry.requiredPreset && !hasPreset(config, entry.requiredPreset)) {
|
|
30974
|
+
clack3.log.warn(`${name} requires the ${entry.requiredPreset} preset and was skipped.`);
|
|
30975
|
+
skipped++;
|
|
30976
|
+
return false;
|
|
30977
|
+
}
|
|
30978
|
+
if (entry.requiredIntegration && !hasIntegration(config, entry.requiredIntegration)) {
|
|
30979
|
+
clack3.log.warn(
|
|
30980
|
+
`${name} requires the ${entry.requiredIntegration} integration and was skipped.`
|
|
30981
|
+
);
|
|
30982
|
+
skipped++;
|
|
30983
|
+
return false;
|
|
30984
|
+
}
|
|
30985
|
+
const { relPath, content } = applyNamespaceToTemplateEntry(entry, config, cwd);
|
|
30986
|
+
const baseDir = entry.base === "cwd" ? cwd : admin;
|
|
30987
|
+
const destPath = path55.join(baseDir, relPath);
|
|
30988
|
+
if (entry.preserveExisting && fs42.existsSync(destPath)) {
|
|
30989
|
+
clack3.log.info(`Preserved ${relPath}`);
|
|
30990
|
+
updatedTemplateNames.add(name);
|
|
30991
|
+
skipped++;
|
|
30992
|
+
return false;
|
|
30993
|
+
}
|
|
30994
|
+
pendingWrites.push({
|
|
30995
|
+
displayPath: relPath,
|
|
30996
|
+
write: () => {
|
|
30997
|
+
fsExtra.ensureDirSync(path55.dirname(destPath));
|
|
30998
|
+
fs42.writeFileSync(destPath, content, "utf-8");
|
|
30999
|
+
clack3.log.success(`Updated ${relPath}`);
|
|
31000
|
+
}
|
|
31001
|
+
});
|
|
31002
|
+
updatedTemplateNames.add(name);
|
|
31003
|
+
trackPackageDependencies(name);
|
|
31004
|
+
updated++;
|
|
31005
|
+
return true;
|
|
31006
|
+
}
|
|
31007
|
+
function writeTemplateEntryWithDependencies(name, entry) {
|
|
31008
|
+
const wroteEntry = writeTemplateEntry(name, entry);
|
|
31009
|
+
if (!wroteEntry) {
|
|
31010
|
+
return false;
|
|
31011
|
+
}
|
|
31012
|
+
for (const dependencyName of entry.dependencies ?? []) {
|
|
31013
|
+
writeNamedDependency(dependencyName);
|
|
31014
|
+
}
|
|
31015
|
+
return true;
|
|
31016
|
+
}
|
|
31017
|
+
function writeStaticAssetEntry(assetDirectory, name) {
|
|
31018
|
+
const key = `${assetDirectory}:${name}`;
|
|
31019
|
+
if (updatedStaticNames.has(key)) {
|
|
31020
|
+
return false;
|
|
31021
|
+
}
|
|
31022
|
+
const assetDir = assetDirectory === "ui" ? uiDir : customDir;
|
|
31023
|
+
const assetFile = findStaticAssetFile(assetDir, name);
|
|
31024
|
+
if (!assetFile) {
|
|
31025
|
+
return false;
|
|
31026
|
+
}
|
|
31027
|
+
const namespace = config.frameworkConfig.next.namespace;
|
|
31028
|
+
const namespacedAssetFile = applyAdminNamespaceToPath(assetFile, namespace);
|
|
31029
|
+
const destPath = path55.join(admin, "components", assetDirectory, namespacedAssetFile);
|
|
31030
|
+
pendingWrites.push({
|
|
31031
|
+
displayPath: `components/${assetDirectory}/${namespacedAssetFile}`,
|
|
31032
|
+
write: () => {
|
|
31033
|
+
fsExtra.ensureDirSync(path55.dirname(destPath));
|
|
31034
|
+
writeNamespacedFile(path55.join(assetDir, assetFile), destPath, namespace);
|
|
31035
|
+
clack3.log.success(`Updated components/${assetDirectory}/${namespacedAssetFile}`);
|
|
31036
|
+
}
|
|
31037
|
+
});
|
|
31038
|
+
if (assetDirectory === "custom") {
|
|
31039
|
+
const assetSubdir = path55.join(assetDir, name);
|
|
31040
|
+
if (fs42.existsSync(assetSubdir) && fs42.statSync(assetSubdir).isDirectory()) {
|
|
31041
|
+
const namespacedName = applyAdminNamespaceToPath(name, namespace);
|
|
31042
|
+
const destSubdir = path55.join(admin, "components", assetDirectory, namespacedName);
|
|
31043
|
+
pendingWrites.push({
|
|
31044
|
+
displayPath: `components/${assetDirectory}/${namespacedName}/ (template files)`,
|
|
31045
|
+
write: () => {
|
|
31046
|
+
fsExtra.ensureDirSync(destSubdir);
|
|
31047
|
+
copyNamespacedDirectory(assetSubdir, destSubdir, namespace);
|
|
31048
|
+
clack3.log.success(
|
|
31049
|
+
`Updated components/${assetDirectory}/${namespacedName}/ (template files)`
|
|
31050
|
+
);
|
|
31051
|
+
}
|
|
31052
|
+
});
|
|
31053
|
+
}
|
|
31054
|
+
}
|
|
31055
|
+
updatedStaticNames.add(key);
|
|
31056
|
+
trackPackageDependencies(name);
|
|
31057
|
+
updated++;
|
|
31058
|
+
if (assetDirectory === "custom") {
|
|
31059
|
+
for (const dependencyName of STATIC_CUSTOM_DEPENDENCIES[name] ?? []) {
|
|
31060
|
+
writeNamedDependency(dependencyName);
|
|
31061
|
+
}
|
|
31062
|
+
}
|
|
31063
|
+
return true;
|
|
31064
|
+
}
|
|
31065
|
+
function writeTiptapTemplates() {
|
|
31066
|
+
const key = "custom:tiptap";
|
|
31067
|
+
if (updatedStaticNames.has(key)) {
|
|
31068
|
+
return true;
|
|
31069
|
+
}
|
|
31070
|
+
const srcBaseDir = resolveCliAssetPath(
|
|
31071
|
+
"shared-assets",
|
|
31072
|
+
"react-admin",
|
|
31073
|
+
"custom",
|
|
31074
|
+
"content-editor"
|
|
31075
|
+
);
|
|
31076
|
+
const namespace = config.frameworkConfig.next.namespace;
|
|
31077
|
+
const destBaseDir = path55.join(admin, "components", "custom", "content-editor");
|
|
31078
|
+
if (!fs42.existsSync(srcBaseDir)) {
|
|
31079
|
+
return false;
|
|
31080
|
+
}
|
|
31081
|
+
const dirsToCopy = [];
|
|
31082
|
+
for (const directory of TIPTAP_CONTENT_EDITOR_DIRECTORIES) {
|
|
31083
|
+
const srcDir = path55.join(srcBaseDir, directory);
|
|
31084
|
+
if (!fs42.existsSync(srcDir)) {
|
|
31085
|
+
continue;
|
|
31086
|
+
}
|
|
31087
|
+
dirsToCopy.push({
|
|
31088
|
+
srcDir,
|
|
31089
|
+
destDir: path55.join(destBaseDir, applyAdminNamespaceToPath(directory, namespace))
|
|
31090
|
+
});
|
|
31091
|
+
}
|
|
31092
|
+
if (dirsToCopy.length === 0) {
|
|
31093
|
+
return false;
|
|
31094
|
+
}
|
|
31095
|
+
pendingWrites.push({
|
|
31096
|
+
displayPath: "components/custom/content-editor/tiptap-*/ (template files)",
|
|
31097
|
+
write: () => {
|
|
31098
|
+
for (const { srcDir, destDir } of dirsToCopy) {
|
|
31099
|
+
fsExtra.ensureDirSync(destDir);
|
|
31100
|
+
copyNamespacedDirectory(srcDir, destDir, namespace);
|
|
31101
|
+
}
|
|
31102
|
+
clack3.log.success("Updated components/custom/content-editor/tiptap-*/ (template files)");
|
|
31103
|
+
removeLegacyDirectory(path55.join(admin, "components", "custom", "tiptap"));
|
|
31104
|
+
}
|
|
31105
|
+
});
|
|
31106
|
+
updatedStaticNames.add(key);
|
|
31107
|
+
trackPackageDependencies("tiptap");
|
|
31108
|
+
updated++;
|
|
31109
|
+
for (const dependencyName of TIPTAP_TEMPLATE_DEPENDENCIES) {
|
|
31110
|
+
writeNamedDependency(dependencyName);
|
|
31111
|
+
}
|
|
31112
|
+
return true;
|
|
31113
|
+
}
|
|
31114
|
+
function writeNamedDependency(name) {
|
|
31115
|
+
const entry = TEMPLATE_REGISTRY[name];
|
|
31116
|
+
if (entry) {
|
|
31117
|
+
writeTemplateEntryWithDependencies(name, entry);
|
|
31118
|
+
return;
|
|
31119
|
+
}
|
|
31120
|
+
if (writeStaticAssetEntry("ui", name)) {
|
|
31121
|
+
return;
|
|
31122
|
+
}
|
|
31123
|
+
if (writeStaticAssetEntry("custom", name)) {
|
|
31124
|
+
return;
|
|
31125
|
+
}
|
|
31126
|
+
if (name === "tiptap") {
|
|
31127
|
+
writeTiptapTemplates();
|
|
31128
|
+
}
|
|
31129
|
+
}
|
|
31130
|
+
for (const name of toUpdate) {
|
|
31131
|
+
if (TEMPLATE_REGISTRY[name]) {
|
|
31132
|
+
const entry = TEMPLATE_REGISTRY[name];
|
|
31133
|
+
writeTemplateEntryWithDependencies(name, entry);
|
|
31134
|
+
continue;
|
|
31135
|
+
}
|
|
31136
|
+
if (writeStaticAssetEntry("ui", name)) {
|
|
31283
31137
|
continue;
|
|
31284
31138
|
}
|
|
31285
|
-
|
|
31286
|
-
|
|
31287
|
-
);
|
|
31288
|
-
if (indexFile) {
|
|
31289
|
-
components.push({
|
|
31290
|
-
name: entry.name,
|
|
31291
|
-
file: path59.join(entry.name, indexFile)
|
|
31292
|
-
});
|
|
31139
|
+
if (writeStaticAssetEntry("custom", name)) {
|
|
31140
|
+
continue;
|
|
31293
31141
|
}
|
|
31294
|
-
|
|
31295
|
-
|
|
31296
|
-
|
|
31297
|
-
|
|
31298
|
-
if (!fs45.existsSync(assetDir)) return void 0;
|
|
31299
|
-
const isNestedComponentName = /[\\/]/.test(componentName);
|
|
31300
|
-
const nestedComponentName = componentName.split(/[\\/]/).filter(Boolean).join(path59.sep);
|
|
31301
|
-
if (isNestedComponentName && nestedComponentName && !path59.isAbsolute(componentName) && !nestedComponentName.split(path59.sep).includes("..")) {
|
|
31302
|
-
for (const extension of [".tsx", ".ts"]) {
|
|
31303
|
-
const relPath = `${nestedComponentName}${extension}`;
|
|
31304
|
-
const filePath = path59.join(assetDir, relPath);
|
|
31305
|
-
if (fs45.existsSync(filePath) && fs45.statSync(filePath).isFile()) {
|
|
31306
|
-
return relPath;
|
|
31142
|
+
if (name === "tiptap") {
|
|
31143
|
+
if (!writeTiptapTemplates()) {
|
|
31144
|
+
clack3.log.warn("tiptap templates not found");
|
|
31145
|
+
skipped++;
|
|
31307
31146
|
}
|
|
31147
|
+
continue;
|
|
31308
31148
|
}
|
|
31149
|
+
clack3.log.warn(`Unknown component: ${name}`);
|
|
31150
|
+
skipped++;
|
|
31309
31151
|
}
|
|
31310
|
-
if (
|
|
31311
|
-
|
|
31312
|
-
|
|
31313
|
-
|
|
31314
|
-
|
|
31315
|
-
|
|
31152
|
+
if (pendingWrites.length > 0) {
|
|
31153
|
+
const displayPaths = pendingWrites.map((entry) => entry.displayPath);
|
|
31154
|
+
const preview = displayPaths.slice(0, MAX_OVERWRITE_PREVIEW_ROWS);
|
|
31155
|
+
if (displayPaths.length > preview.length) {
|
|
31156
|
+
preview.push(`\u2026 and ${displayPaths.length - preview.length} more`);
|
|
31157
|
+
}
|
|
31158
|
+
clack3.note(
|
|
31159
|
+
preview.join("\n"),
|
|
31160
|
+
`Overwriting ${displayPaths.length} file${displayPaths.length === 1 ? "" : "s"}`
|
|
31161
|
+
);
|
|
31162
|
+
if (!options.yes) {
|
|
31163
|
+
if (!isInteractiveSession()) {
|
|
31164
|
+
clack3.log.error(
|
|
31165
|
+
`Overwriting ${displayPaths.length} file${displayPaths.length === 1 ? "" : "s"} needs confirmation. Re-run with --yes.`
|
|
31166
|
+
);
|
|
31167
|
+
process.exit(1);
|
|
31168
|
+
}
|
|
31169
|
+
const proceed = await clack3.confirm({
|
|
31170
|
+
message: "Overwrite these files with the latest templates?",
|
|
31171
|
+
initialValue: true
|
|
31172
|
+
});
|
|
31173
|
+
if (clack3.isCancel(proceed) || !proceed) {
|
|
31174
|
+
clack3.cancel("Update cancelled.");
|
|
31175
|
+
process.exit(0);
|
|
31316
31176
|
}
|
|
31317
31177
|
}
|
|
31178
|
+
for (const entry of pendingWrites) {
|
|
31179
|
+
entry.write();
|
|
31180
|
+
}
|
|
31318
31181
|
}
|
|
31319
|
-
|
|
31320
|
-
|
|
31321
|
-
)
|
|
31322
|
-
|
|
31323
|
-
|
|
31324
|
-
|
|
31325
|
-
|
|
31326
|
-
|
|
31327
|
-
|
|
31182
|
+
syncInstalledPresetManifests(cwd, config);
|
|
31183
|
+
syncInstalledIntegrationManifests(cwd, config);
|
|
31184
|
+
const projectPackageJson = readProjectPackageJson2(cwd);
|
|
31185
|
+
const missingPackageDependencies = Array.from(requiredPackageDependencies).filter(
|
|
31186
|
+
(dependency) => !hasDeclaredPackage2(projectPackageJson, dependency)
|
|
31187
|
+
);
|
|
31188
|
+
if (missingPackageDependencies.length > 0) {
|
|
31189
|
+
clack3.log.warn(
|
|
31190
|
+
`Updated components require package dependencies that are not declared: ${missingPackageDependencies.join(", ")}. Run 'pnpm betterstart update-deps' before building.`
|
|
31191
|
+
);
|
|
31192
|
+
}
|
|
31193
|
+
clack3.outro(
|
|
31194
|
+
`Updated ${updated} component${updated !== 1 ? "s" : ""}${skipped > 0 ? `, ${skipped} skipped` : ""}`
|
|
31195
|
+
);
|
|
31328
31196
|
}
|
|
31329
|
-
function
|
|
31330
|
-
|
|
31331
|
-
|
|
31332
|
-
|
|
31333
|
-
([, entry]) => (!entry.requiredPreset || hasPreset(config, entry.requiredPreset)) && (!entry.requiredIntegration || hasIntegration(config, entry.requiredIntegration))
|
|
31334
|
-
).map(([name]) => name);
|
|
31335
|
-
return [.../* @__PURE__ */ new Set([...staticUi, ...staticCustom, ...templateKeys, "tiptap"])].sort();
|
|
31197
|
+
function removeLegacyDirectory(dirPath) {
|
|
31198
|
+
if (fs42.existsSync(dirPath)) {
|
|
31199
|
+
fs42.rmSync(dirPath, { recursive: true, force: true });
|
|
31200
|
+
}
|
|
31336
31201
|
}
|
|
31337
|
-
|
|
31338
|
-
|
|
31339
|
-
|
|
31340
|
-
validateShadcnPresetOptions(components, options);
|
|
31341
|
-
if (options.json && !options.list) {
|
|
31342
|
-
clack4.cancel("--json can only be used with --list.");
|
|
31202
|
+
function validateShadcnPresetOptions(components, options) {
|
|
31203
|
+
if (options.only && !options.shadcnPreset) {
|
|
31204
|
+
clack3.cancel("--only can only be used with --shadcn-preset.");
|
|
31343
31205
|
process.exit(1);
|
|
31344
31206
|
}
|
|
31207
|
+
if (!options.shadcnPreset) {
|
|
31208
|
+
return;
|
|
31209
|
+
}
|
|
31345
31210
|
if (options.list) {
|
|
31346
|
-
|
|
31347
|
-
|
|
31348
|
-
|
|
31349
|
-
|
|
31350
|
-
|
|
31351
|
-
|
|
31352
|
-
|
|
31353
|
-
|
|
31354
|
-
|
|
31355
|
-
|
|
31356
|
-
|
|
31357
|
-
|
|
31358
|
-
|
|
31359
|
-
|
|
31360
|
-
|
|
31361
|
-
|
|
31362
|
-
|
|
31363
|
-
|
|
31364
|
-
|
|
31365
|
-
|
|
31366
|
-
{ name: "tiptap", path: "components/custom/content-editor/tiptap-*/", kind: "special" }
|
|
31367
|
-
];
|
|
31368
|
-
console.log(JSON.stringify(items, null, 2));
|
|
31369
|
-
return;
|
|
31370
|
-
}
|
|
31371
|
-
const all = getAllComponentNames();
|
|
31372
|
-
clack4.intro("Available components");
|
|
31373
|
-
clack4.note(
|
|
31374
|
-
renderTableRows(
|
|
31375
|
-
uiComponents.map((component) => [component.name, `components/ui/${component.file}`])
|
|
31376
|
-
).join("\n"),
|
|
31377
|
-
`Shadcn UI Components (${uiComponents.length})`
|
|
31211
|
+
clack3.cancel("--list cannot be combined with --shadcn-preset.");
|
|
31212
|
+
process.exit(1);
|
|
31213
|
+
}
|
|
31214
|
+
if (options.all) {
|
|
31215
|
+
clack3.cancel("--all cannot be combined with --shadcn-preset.");
|
|
31216
|
+
process.exit(1);
|
|
31217
|
+
}
|
|
31218
|
+
if (components.length > 0) {
|
|
31219
|
+
clack3.cancel("Component names cannot be combined with --shadcn-preset.");
|
|
31220
|
+
process.exit(1);
|
|
31221
|
+
}
|
|
31222
|
+
}
|
|
31223
|
+
function normalizeShadcnPresetOnly(value) {
|
|
31224
|
+
if (!value) {
|
|
31225
|
+
return void 0;
|
|
31226
|
+
}
|
|
31227
|
+
const parts = value.split(",").map((part) => part.trim().toLowerCase()).filter(Boolean);
|
|
31228
|
+
if (parts.length !== 1 || parts[0] !== "theme") {
|
|
31229
|
+
clack3.cancel(
|
|
31230
|
+
"Admin-only shadcn preset updates currently support --only theme. Omit --only to apply the full preset."
|
|
31378
31231
|
);
|
|
31379
|
-
|
|
31380
|
-
|
|
31381
|
-
|
|
31382
|
-
|
|
31383
|
-
|
|
31232
|
+
process.exit(1);
|
|
31233
|
+
}
|
|
31234
|
+
return "theme";
|
|
31235
|
+
}
|
|
31236
|
+
function runShadcnPresetUpdate({
|
|
31237
|
+
cwd,
|
|
31238
|
+
config,
|
|
31239
|
+
preset,
|
|
31240
|
+
only
|
|
31241
|
+
}) {
|
|
31242
|
+
const namespace = resolveAdminNamespace(config.frameworkConfig.next.namespace);
|
|
31243
|
+
const adminGlobalsPath = path55.join(cwd, config.paths.admin, namespace.globalsFile);
|
|
31244
|
+
const componentsJsonPath = path55.join(cwd, "components.json");
|
|
31245
|
+
const shadcnBackupPath = `${componentsJsonPath}.bak`;
|
|
31246
|
+
const restoreAfterApplyPaths = [
|
|
31247
|
+
componentsJsonPath,
|
|
31248
|
+
shadcnBackupPath,
|
|
31249
|
+
path55.join(cwd, config.paths.admin, "lib", "utils.ts"),
|
|
31250
|
+
...getHostProjectFilesToRestore(cwd)
|
|
31251
|
+
];
|
|
31252
|
+
if (!preset) {
|
|
31253
|
+
clack3.cancel("--shadcn-preset requires a preset code, preset name, or preset URL.");
|
|
31254
|
+
process.exit(1);
|
|
31255
|
+
}
|
|
31256
|
+
if (!fs42.existsSync(adminGlobalsPath)) {
|
|
31257
|
+
clack3.cancel(
|
|
31258
|
+
`Admin globals file not found at ${path55.relative(cwd, adminGlobalsPath)}. Run 'betterstart update admin-globals' first.`
|
|
31384
31259
|
);
|
|
31385
|
-
|
|
31386
|
-
|
|
31387
|
-
|
|
31260
|
+
process.exit(1);
|
|
31261
|
+
}
|
|
31262
|
+
const shadcnBin = resolveLocalShadcnBin(cwd);
|
|
31263
|
+
const restoreSnapshots = restoreAfterApplyPaths.map((filePath) => ({
|
|
31264
|
+
filePath,
|
|
31265
|
+
snapshot: snapshotFile(filePath)
|
|
31266
|
+
}));
|
|
31267
|
+
clack3.intro("BetterStart Shadcn Preset");
|
|
31268
|
+
clack3.log.info(`Applying preset to ${path55.join(config.paths.admin, "components/ui")}`);
|
|
31269
|
+
let failed = false;
|
|
31270
|
+
try {
|
|
31271
|
+
fs42.writeFileSync(
|
|
31272
|
+
componentsJsonPath,
|
|
31273
|
+
`${JSON.stringify(createAdminShadcnComponentsJson(config), null, 2)}
|
|
31274
|
+
`,
|
|
31275
|
+
"utf-8"
|
|
31388
31276
|
);
|
|
31389
|
-
|
|
31390
|
-
|
|
31391
|
-
|
|
31392
|
-
|
|
31393
|
-
|
|
31277
|
+
const args = ["apply", "--preset", preset, "--cwd", cwd, "--yes"];
|
|
31278
|
+
if (only) {
|
|
31279
|
+
args.push("--only", only);
|
|
31280
|
+
}
|
|
31281
|
+
execFileSync5(shadcnBin, args, { cwd, stdio: "inherit" });
|
|
31282
|
+
} catch {
|
|
31283
|
+
failed = true;
|
|
31284
|
+
} finally {
|
|
31285
|
+
for (const { filePath, snapshot } of restoreSnapshots.reverse()) {
|
|
31286
|
+
restoreFile(filePath, snapshot);
|
|
31287
|
+
}
|
|
31288
|
+
}
|
|
31289
|
+
if (failed) {
|
|
31290
|
+
clack3.cancel("shadcn preset application failed.");
|
|
31291
|
+
process.exit(1);
|
|
31292
|
+
}
|
|
31293
|
+
clack3.outro(
|
|
31294
|
+
only ? `Applied shadcn preset parts (${only}) to the Admin.` : "Applied shadcn preset to Admin UI components and styles."
|
|
31295
|
+
);
|
|
31296
|
+
}
|
|
31297
|
+
function createAdminShadcnComponentsJson(config) {
|
|
31298
|
+
const adminPath = toPosixPath(config.paths.admin);
|
|
31299
|
+
const namespace = resolveAdminNamespace(config.frameworkConfig.next.namespace);
|
|
31300
|
+
return {
|
|
31301
|
+
$schema: "https://ui.shadcn.com/schema.json",
|
|
31302
|
+
style: "new-york",
|
|
31303
|
+
rsc: true,
|
|
31304
|
+
tsx: true,
|
|
31305
|
+
tailwind: {
|
|
31306
|
+
config: "",
|
|
31307
|
+
css: `${adminPath}/${namespace.globalsFile}`,
|
|
31308
|
+
baseColor: "neutral",
|
|
31309
|
+
cssVariables: true,
|
|
31310
|
+
prefix: ""
|
|
31311
|
+
},
|
|
31312
|
+
iconLibrary: "lucide",
|
|
31313
|
+
aliases: {
|
|
31314
|
+
components: `${namespace.alias}/components`,
|
|
31315
|
+
ui: `${namespace.alias}/components/ui`,
|
|
31316
|
+
hooks: `${namespace.alias}/hooks`,
|
|
31317
|
+
lib: `${namespace.alias}/lib`,
|
|
31318
|
+
utils: `${namespace.alias}/utils/shared/cn`
|
|
31319
|
+
}
|
|
31320
|
+
};
|
|
31321
|
+
}
|
|
31322
|
+
function toPosixPath(value) {
|
|
31323
|
+
return value.replace(/\\/g, "/");
|
|
31324
|
+
}
|
|
31325
|
+
function resolveLocalShadcnBin(cwd) {
|
|
31326
|
+
const binName = process.platform === "win32" ? "shadcn.cmd" : "shadcn";
|
|
31327
|
+
const shadcnBin = path55.join(cwd, "node_modules", ".bin", binName);
|
|
31328
|
+
if (!fs42.existsSync(shadcnBin)) {
|
|
31329
|
+
clack3.cancel(
|
|
31330
|
+
`shadcn is not installed in this project. Run 'betterstart update-deps' and try again.`
|
|
31394
31331
|
);
|
|
31395
|
-
|
|
31332
|
+
process.exit(1);
|
|
31333
|
+
}
|
|
31334
|
+
return shadcnBin;
|
|
31335
|
+
}
|
|
31336
|
+
function getHostProjectFilesToRestore(cwd) {
|
|
31337
|
+
const hostRelativePaths = [
|
|
31338
|
+
"app/layout.tsx",
|
|
31339
|
+
"app/layout.ts",
|
|
31340
|
+
"app/layout.jsx",
|
|
31341
|
+
"app/layout.js",
|
|
31342
|
+
"src/app/layout.tsx",
|
|
31343
|
+
"src/app/layout.ts",
|
|
31344
|
+
"src/app/layout.jsx",
|
|
31345
|
+
"src/app/layout.js",
|
|
31346
|
+
"app/globals.css",
|
|
31347
|
+
"src/app/globals.css"
|
|
31348
|
+
];
|
|
31349
|
+
return hostRelativePaths.map((relativePath) => path55.join(cwd, relativePath));
|
|
31350
|
+
}
|
|
31351
|
+
function snapshotFile(filePath) {
|
|
31352
|
+
if (!fs42.existsSync(filePath)) {
|
|
31353
|
+
return { existed: false };
|
|
31354
|
+
}
|
|
31355
|
+
return { existed: true, content: fs42.readFileSync(filePath, "utf-8") };
|
|
31356
|
+
}
|
|
31357
|
+
function restoreFile(filePath, snapshot) {
|
|
31358
|
+
if (snapshot.existed) {
|
|
31359
|
+
fs42.writeFileSync(filePath, snapshot.content ?? "", "utf-8");
|
|
31396
31360
|
return;
|
|
31397
31361
|
}
|
|
31362
|
+
if (fs42.existsSync(filePath)) {
|
|
31363
|
+
fs42.rmSync(filePath, { force: true });
|
|
31364
|
+
}
|
|
31365
|
+
}
|
|
31366
|
+
|
|
31367
|
+
// adapters/next/commands/menu-choices.ts
|
|
31368
|
+
async function listInstallableChoices(cwd) {
|
|
31398
31369
|
const config = await resolveConfigOrExit(cwd);
|
|
31399
|
-
const
|
|
31400
|
-
|
|
31401
|
-
|
|
31402
|
-
|
|
31370
|
+
const installedPresets = new Set(config.presets.installed);
|
|
31371
|
+
const installedIntegrations = new Set(config.integrations.installed);
|
|
31372
|
+
return {
|
|
31373
|
+
presets: listAvailablePresets().map((preset) => ({
|
|
31374
|
+
id: preset.id,
|
|
31375
|
+
description: preset.description,
|
|
31376
|
+
installed: installedPresets.has(preset.id)
|
|
31377
|
+
})),
|
|
31378
|
+
integrations: listAvailableIntegrations().map((integration) => ({
|
|
31379
|
+
id: integration.id,
|
|
31380
|
+
description: integration.description,
|
|
31381
|
+
installed: installedIntegrations.has(integration.id)
|
|
31382
|
+
}))
|
|
31383
|
+
};
|
|
31384
|
+
}
|
|
31385
|
+
async function listSchemaChoices(cwd) {
|
|
31386
|
+
const config = await resolveConfigOrExit(cwd);
|
|
31387
|
+
const paths = resolveProjectPaths(config);
|
|
31388
|
+
return listSchemaNames(path56.join(cwd, ...paths.schemasDir.split("/")));
|
|
31389
|
+
}
|
|
31390
|
+
async function listComponentChoices(cwd) {
|
|
31391
|
+
const config = await resolveConfigOrExit(cwd);
|
|
31392
|
+
return getAllComponentNamesForConfig(config);
|
|
31393
|
+
}
|
|
31394
|
+
|
|
31395
|
+
// adapters/next/commands/remove.ts
|
|
31396
|
+
import path57 from "path";
|
|
31397
|
+
import * as p29 from "@clack/prompts";
|
|
31398
|
+
async function runRemoveCommand(items, options) {
|
|
31399
|
+
const removeIntegrationsMode = Boolean(options.integration);
|
|
31400
|
+
if (!removeIntegrationsMode && items.includes("core")) {
|
|
31401
|
+
p29.log.error("The core Admin cannot be removed.");
|
|
31402
|
+
process.exit(1);
|
|
31403
|
+
}
|
|
31404
|
+
const presetIds = items.filter(isPresetId);
|
|
31405
|
+
const integrationIds = items.filter(isIntegrationId);
|
|
31406
|
+
if (!removeIntegrationsMode && integrationIds.length > 0) {
|
|
31407
|
+
p29.log.error(
|
|
31408
|
+
`Integration IDs require --integration. Run \`betterstart remove --integration ${integrationIds.join(" ")}\`.`
|
|
31403
31409
|
);
|
|
31404
31410
|
process.exit(1);
|
|
31405
31411
|
}
|
|
31406
|
-
if (
|
|
31407
|
-
|
|
31408
|
-
|
|
31409
|
-
config,
|
|
31410
|
-
preset: options.shadcnPreset.trim(),
|
|
31411
|
-
only: normalizedOnly
|
|
31412
|
-
});
|
|
31413
|
-
return;
|
|
31412
|
+
if (removeIntegrationsMode && presetIds.length > 0) {
|
|
31413
|
+
p29.log.error(`Preset IDs cannot be removed with --integration: ${presetIds.join(", ")}`);
|
|
31414
|
+
process.exit(1);
|
|
31414
31415
|
}
|
|
31415
|
-
|
|
31416
|
-
|
|
31417
|
-
|
|
31416
|
+
const invalidItems = removeIntegrationsMode ? items.filter((integrationId) => !isIntegrationId(integrationId)) : items.filter((presetId) => !isPresetId(presetId));
|
|
31417
|
+
if (invalidItems.length > 0) {
|
|
31418
|
+
p29.log.error(
|
|
31419
|
+
removeIntegrationsMode ? formatUnknownIntegrationMessage(invalidItems) : formatUnknownPresetMessage(invalidItems)
|
|
31418
31420
|
);
|
|
31419
31421
|
process.exit(1);
|
|
31420
31422
|
}
|
|
31421
|
-
|
|
31422
|
-
const
|
|
31423
|
-
const
|
|
31424
|
-
|
|
31425
|
-
|
|
31426
|
-
|
|
31427
|
-
|
|
31428
|
-
const updatedStaticNames = /* @__PURE__ */ new Set();
|
|
31429
|
-
const requiredPackageDependencies = /* @__PURE__ */ new Set();
|
|
31430
|
-
const pendingWrites = [];
|
|
31431
|
-
function trackPackageDependencies(name) {
|
|
31432
|
-
for (const dependency of COMPONENT_PACKAGE_DEPENDENCIES[name] ?? []) {
|
|
31433
|
-
requiredPackageDependencies.add(dependency);
|
|
31434
|
-
}
|
|
31435
|
-
}
|
|
31436
|
-
function writeTemplateEntry(name, entry) {
|
|
31437
|
-
if (updatedTemplateNames.has(name)) {
|
|
31438
|
-
return false;
|
|
31439
|
-
}
|
|
31440
|
-
if (entry.requiredPreset && !hasPreset(config, entry.requiredPreset)) {
|
|
31441
|
-
clack4.log.warn(`${name} requires the ${entry.requiredPreset} preset and was skipped.`);
|
|
31442
|
-
skipped++;
|
|
31443
|
-
return false;
|
|
31444
|
-
}
|
|
31445
|
-
if (entry.requiredIntegration && !hasIntegration(config, entry.requiredIntegration)) {
|
|
31446
|
-
clack4.log.warn(
|
|
31447
|
-
`${name} requires the ${entry.requiredIntegration} integration and was skipped.`
|
|
31448
|
-
);
|
|
31449
|
-
skipped++;
|
|
31450
|
-
return false;
|
|
31451
|
-
}
|
|
31452
|
-
const { relPath, content } = applyNamespaceToTemplateEntry(entry, config, cwd);
|
|
31453
|
-
const baseDir = entry.base === "cwd" ? cwd : admin;
|
|
31454
|
-
const destPath = path59.join(baseDir, relPath);
|
|
31455
|
-
if (entry.preserveExisting && fs45.existsSync(destPath)) {
|
|
31456
|
-
clack4.log.info(`Preserved ${relPath}`);
|
|
31457
|
-
updatedTemplateNames.add(name);
|
|
31458
|
-
skipped++;
|
|
31459
|
-
return false;
|
|
31460
|
-
}
|
|
31461
|
-
pendingWrites.push({
|
|
31462
|
-
displayPath: relPath,
|
|
31463
|
-
write: () => {
|
|
31464
|
-
fsExtra.ensureDirSync(path59.dirname(destPath));
|
|
31465
|
-
fs45.writeFileSync(destPath, content, "utf-8");
|
|
31466
|
-
clack4.log.success(`Updated ${relPath}`);
|
|
31467
|
-
}
|
|
31423
|
+
const cwd = options.cwd ? path57.resolve(options.cwd) : process.cwd();
|
|
31424
|
+
const config = await resolveConfigOrExit(cwd);
|
|
31425
|
+
const pm = detectPackageManager(cwd);
|
|
31426
|
+
if (!options.force) {
|
|
31427
|
+
const confirmed = await p29.confirm({
|
|
31428
|
+
message: `Remove ${removeIntegrationsMode ? "integration" : "preset"}${items.length === 1 ? "" : "s"} ${items.join(", ")}?`,
|
|
31429
|
+
initialValue: false
|
|
31468
31430
|
});
|
|
31469
|
-
|
|
31470
|
-
|
|
31471
|
-
|
|
31472
|
-
return true;
|
|
31473
|
-
}
|
|
31474
|
-
function writeTemplateEntryWithDependencies(name, entry) {
|
|
31475
|
-
const wroteEntry = writeTemplateEntry(name, entry);
|
|
31476
|
-
if (!wroteEntry) {
|
|
31477
|
-
return false;
|
|
31478
|
-
}
|
|
31479
|
-
for (const dependencyName of entry.dependencies ?? []) {
|
|
31480
|
-
writeNamedDependency(dependencyName);
|
|
31431
|
+
if (p29.isCancel(confirmed) || !confirmed) {
|
|
31432
|
+
p29.cancel(`${removeIntegrationsMode ? "Integration" : "Preset"} removal cancelled.`);
|
|
31433
|
+
process.exit(0);
|
|
31481
31434
|
}
|
|
31482
|
-
return true;
|
|
31483
31435
|
}
|
|
31484
|
-
|
|
31485
|
-
const
|
|
31486
|
-
|
|
31487
|
-
|
|
31488
|
-
|
|
31489
|
-
|
|
31490
|
-
const assetFile = findStaticAssetFile(assetDir, name);
|
|
31491
|
-
if (!assetFile) {
|
|
31492
|
-
return false;
|
|
31493
|
-
}
|
|
31494
|
-
const namespace = config.frameworkConfig.next.namespace;
|
|
31495
|
-
const namespacedAssetFile = applyAdminNamespaceToPath(assetFile, namespace);
|
|
31496
|
-
const destPath = path59.join(admin, "components", assetDirectory, namespacedAssetFile);
|
|
31497
|
-
pendingWrites.push({
|
|
31498
|
-
displayPath: `components/${assetDirectory}/${namespacedAssetFile}`,
|
|
31499
|
-
write: () => {
|
|
31500
|
-
fsExtra.ensureDirSync(path59.dirname(destPath));
|
|
31501
|
-
writeNamespacedFile(path59.join(assetDir, assetFile), destPath, namespace);
|
|
31502
|
-
clack4.log.success(`Updated components/${assetDirectory}/${namespacedAssetFile}`);
|
|
31503
|
-
}
|
|
31436
|
+
if (removeIntegrationsMode) {
|
|
31437
|
+
const result2 = await removeIntegrations({
|
|
31438
|
+
cwd,
|
|
31439
|
+
config,
|
|
31440
|
+
pm,
|
|
31441
|
+
integrationIds
|
|
31504
31442
|
});
|
|
31505
|
-
|
|
31506
|
-
|
|
31507
|
-
|
|
31508
|
-
|
|
31509
|
-
const destSubdir = path59.join(admin, "components", assetDirectory, namespacedName);
|
|
31510
|
-
pendingWrites.push({
|
|
31511
|
-
displayPath: `components/${assetDirectory}/${namespacedName}/ (template files)`,
|
|
31512
|
-
write: () => {
|
|
31513
|
-
fsExtra.ensureDirSync(destSubdir);
|
|
31514
|
-
copyNamespacedDirectory(assetSubdir, destSubdir, namespace);
|
|
31515
|
-
clack4.log.success(
|
|
31516
|
-
`Updated components/${assetDirectory}/${namespacedName}/ (template files)`
|
|
31517
|
-
);
|
|
31518
|
-
}
|
|
31519
|
-
});
|
|
31520
|
-
}
|
|
31521
|
-
}
|
|
31522
|
-
updatedStaticNames.add(key);
|
|
31523
|
-
trackPackageDependencies(name);
|
|
31524
|
-
updated++;
|
|
31525
|
-
if (assetDirectory === "custom") {
|
|
31526
|
-
for (const dependencyName of STATIC_CUSTOM_DEPENDENCIES[name] ?? []) {
|
|
31527
|
-
writeNamedDependency(dependencyName);
|
|
31528
|
-
}
|
|
31443
|
+
writeConfigFile(cwd, result2.config);
|
|
31444
|
+
if (result2.removed.length === 0) {
|
|
31445
|
+
p29.outro("No integrations were removed.");
|
|
31446
|
+
return;
|
|
31529
31447
|
}
|
|
31530
|
-
|
|
31531
|
-
|
|
31532
|
-
function writeTiptapTemplates() {
|
|
31533
|
-
const key = "custom:tiptap";
|
|
31534
|
-
if (updatedStaticNames.has(key)) {
|
|
31535
|
-
return true;
|
|
31448
|
+
if (result2.warnings.length > 0) {
|
|
31449
|
+
p29.note(result2.warnings.join("\n"), "Warnings");
|
|
31536
31450
|
}
|
|
31537
|
-
|
|
31538
|
-
"
|
|
31539
|
-
"react-admin",
|
|
31540
|
-
"custom",
|
|
31541
|
-
"content-editor"
|
|
31451
|
+
p29.outro(
|
|
31452
|
+
`Removed integration${result2.removed.length === 1 ? "" : "s"}: ${result2.removed.join(", ")}`
|
|
31542
31453
|
);
|
|
31543
|
-
|
|
31544
|
-
|
|
31545
|
-
|
|
31546
|
-
|
|
31547
|
-
|
|
31548
|
-
|
|
31549
|
-
|
|
31550
|
-
|
|
31551
|
-
|
|
31454
|
+
return;
|
|
31455
|
+
}
|
|
31456
|
+
const result = await removePresets({
|
|
31457
|
+
cwd,
|
|
31458
|
+
config,
|
|
31459
|
+
pm,
|
|
31460
|
+
presetIds
|
|
31461
|
+
});
|
|
31462
|
+
writeConfigFile(cwd, result.config);
|
|
31463
|
+
if (result.removed.length === 0) {
|
|
31464
|
+
p29.outro("No presets were removed.");
|
|
31465
|
+
return;
|
|
31466
|
+
}
|
|
31467
|
+
if (result.warnings.length > 0) {
|
|
31468
|
+
p29.note(result.warnings.join("\n"), "Warnings");
|
|
31469
|
+
}
|
|
31470
|
+
p29.outro(`Removed preset${result.removed.length === 1 ? "" : "s"}: ${result.removed.join(", ")}`);
|
|
31471
|
+
}
|
|
31472
|
+
|
|
31473
|
+
// adapters/next/commands/remove-schema.ts
|
|
31474
|
+
import fs43 from "fs";
|
|
31475
|
+
import path58 from "path";
|
|
31476
|
+
import * as clack4 from "@clack/prompts";
|
|
31477
|
+
function removePath2(cwd, filePath) {
|
|
31478
|
+
const fullPath = path58.join(cwd, ...filePath.split("/"));
|
|
31479
|
+
const existed = fs43.existsSync(fullPath);
|
|
31480
|
+
fs43.rmSync(fullPath, { recursive: true, force: true });
|
|
31481
|
+
return existed;
|
|
31482
|
+
}
|
|
31483
|
+
function cleanupEmptyDirs3(cwd, deletedPaths, configPaths) {
|
|
31484
|
+
const stopRoots = /* @__PURE__ */ new Set([
|
|
31485
|
+
path58.join(cwd, ...configPaths.adminDir.split("/")),
|
|
31486
|
+
path58.join(cwd, ...configPaths.adminNavigationDir.split("/")),
|
|
31487
|
+
path58.join(cwd, ...configPaths.adminWebhookEventsDir.split("/")),
|
|
31488
|
+
path58.join(cwd, ...configPaths.pagesDir.split("/"))
|
|
31489
|
+
]);
|
|
31490
|
+
for (const deletedPath of deletedPaths) {
|
|
31491
|
+
let current = path58.dirname(path58.join(cwd, ...deletedPath.split("/")));
|
|
31492
|
+
while (!stopRoots.has(current)) {
|
|
31493
|
+
if (!fs43.existsSync(current)) {
|
|
31494
|
+
current = path58.dirname(current);
|
|
31552
31495
|
continue;
|
|
31553
31496
|
}
|
|
31554
|
-
|
|
31555
|
-
|
|
31556
|
-
|
|
31557
|
-
}
|
|
31558
|
-
|
|
31559
|
-
|
|
31560
|
-
return false;
|
|
31561
|
-
}
|
|
31562
|
-
pendingWrites.push({
|
|
31563
|
-
displayPath: "components/custom/content-editor/tiptap-*/ (template files)",
|
|
31564
|
-
write: () => {
|
|
31565
|
-
for (const { srcDir, destDir } of dirsToCopy) {
|
|
31566
|
-
fsExtra.ensureDirSync(destDir);
|
|
31567
|
-
copyNamespacedDirectory(srcDir, destDir, namespace);
|
|
31568
|
-
}
|
|
31569
|
-
clack4.log.success("Updated components/custom/content-editor/tiptap-*/ (template files)");
|
|
31570
|
-
removeLegacyDirectory(path59.join(admin, "components", "custom", "tiptap"));
|
|
31571
|
-
}
|
|
31572
|
-
});
|
|
31573
|
-
updatedStaticNames.add(key);
|
|
31574
|
-
trackPackageDependencies("tiptap");
|
|
31575
|
-
updated++;
|
|
31576
|
-
for (const dependencyName of TIPTAP_TEMPLATE_DEPENDENCIES) {
|
|
31577
|
-
writeNamedDependency(dependencyName);
|
|
31578
|
-
}
|
|
31579
|
-
return true;
|
|
31580
|
-
}
|
|
31581
|
-
function writeNamedDependency(name) {
|
|
31582
|
-
const entry = TEMPLATE_REGISTRY[name];
|
|
31583
|
-
if (entry) {
|
|
31584
|
-
writeTemplateEntryWithDependencies(name, entry);
|
|
31585
|
-
return;
|
|
31497
|
+
const entries = fs43.readdirSync(current);
|
|
31498
|
+
if (entries.length > 0) {
|
|
31499
|
+
break;
|
|
31500
|
+
}
|
|
31501
|
+
fs43.rmdirSync(current);
|
|
31502
|
+
current = path58.dirname(current);
|
|
31586
31503
|
}
|
|
31587
|
-
|
|
31588
|
-
|
|
31504
|
+
}
|
|
31505
|
+
}
|
|
31506
|
+
function resolveSchemaOwnerForRemoval(cwd, schemaName) {
|
|
31507
|
+
const explicitOwner = getSchemaOwner(cwd, schemaName);
|
|
31508
|
+
if (explicitOwner) {
|
|
31509
|
+
return explicitOwner;
|
|
31510
|
+
}
|
|
31511
|
+
if (schemaName === "settings") {
|
|
31512
|
+
return "core";
|
|
31513
|
+
}
|
|
31514
|
+
return "user";
|
|
31515
|
+
}
|
|
31516
|
+
async function runRemoveSchemaCommand(schemaName, options) {
|
|
31517
|
+
const owner = resolveSchemaOwnerForRemoval(
|
|
31518
|
+
options.cwd ? path58.resolve(options.cwd) : process.cwd(),
|
|
31519
|
+
schemaName
|
|
31520
|
+
);
|
|
31521
|
+
if (owner === "core") {
|
|
31522
|
+
clack4.log.error(
|
|
31523
|
+
`"${schemaName}" is a core Admin module and cannot be removed with remove-schema.`
|
|
31524
|
+
);
|
|
31525
|
+
process.exit(1);
|
|
31526
|
+
}
|
|
31527
|
+
if (owner.startsWith("preset:")) {
|
|
31528
|
+
clack4.log.error(`"${schemaName}" is owned by ${owner}. Remove the owning preset instead.`);
|
|
31529
|
+
process.exit(1);
|
|
31530
|
+
}
|
|
31531
|
+
const cwd = options.cwd ? path58.resolve(options.cwd) : process.cwd();
|
|
31532
|
+
const config = await resolveConfigOrExit(cwd);
|
|
31533
|
+
const paths = resolveProjectPaths(config);
|
|
31534
|
+
const manifest = loadManifest(cwd, schemaName);
|
|
31535
|
+
if (!snapshotRootExists(cwd)) {
|
|
31536
|
+
clack4.log.error(UNSUPPORTED_PROJECT_STATE_MESSAGE);
|
|
31537
|
+
process.exit(1);
|
|
31538
|
+
}
|
|
31539
|
+
if (!manifest) {
|
|
31540
|
+
clack4.log.error(UNSUPPORTED_PROJECT_STATE_MESSAGE);
|
|
31541
|
+
process.exit(1);
|
|
31542
|
+
}
|
|
31543
|
+
if (!options.force) {
|
|
31544
|
+
if (!isInteractiveSession()) {
|
|
31545
|
+
clack4.log.error(
|
|
31546
|
+
`Removing generated files for ${schemaName} needs confirmation. Re-run with --force.`
|
|
31547
|
+
);
|
|
31548
|
+
process.exit(1);
|
|
31589
31549
|
}
|
|
31590
|
-
|
|
31550
|
+
const confirmed = await clack4.confirm({
|
|
31551
|
+
message: `Remove generated files for ${schemaName}?`,
|
|
31552
|
+
initialValue: false
|
|
31553
|
+
});
|
|
31554
|
+
if (clack4.isCancel(confirmed) || !confirmed) {
|
|
31555
|
+
clack4.cancel("Cancelled.");
|
|
31591
31556
|
return;
|
|
31592
31557
|
}
|
|
31593
|
-
if (name === "tiptap") {
|
|
31594
|
-
writeTiptapTemplates();
|
|
31595
|
-
}
|
|
31596
31558
|
}
|
|
31597
|
-
|
|
31598
|
-
|
|
31599
|
-
|
|
31600
|
-
|
|
31601
|
-
continue;
|
|
31602
|
-
}
|
|
31603
|
-
if (writeStaticAssetEntry("ui", name)) {
|
|
31604
|
-
continue;
|
|
31559
|
+
const deletedPaths = [];
|
|
31560
|
+
for (const file of [...manifest.files.map((entry) => entry.path), ...manifest.skipped]) {
|
|
31561
|
+
if (removePath2(cwd, file)) {
|
|
31562
|
+
deletedPaths.push(file);
|
|
31605
31563
|
}
|
|
31606
|
-
|
|
31607
|
-
|
|
31564
|
+
}
|
|
31565
|
+
const loaded = (() => {
|
|
31566
|
+
try {
|
|
31567
|
+
return loadSchema(path58.join(cwd, ...paths.schemasDir.split("/")), schemaName);
|
|
31568
|
+
} catch {
|
|
31569
|
+
return null;
|
|
31608
31570
|
}
|
|
31609
|
-
|
|
31610
|
-
|
|
31611
|
-
|
|
31612
|
-
|
|
31613
|
-
}
|
|
31614
|
-
continue;
|
|
31571
|
+
})();
|
|
31572
|
+
const kebabName = toKebabCase(schemaName);
|
|
31573
|
+
if (loaded?.type === "form") {
|
|
31574
|
+
if (removePath2(cwd, `${paths.adminActionsDir}/${schemaName}`)) {
|
|
31575
|
+
deletedPaths.push(`${paths.adminActionsDir}/${schemaName}`);
|
|
31615
31576
|
}
|
|
31616
|
-
|
|
31617
|
-
|
|
31618
|
-
}
|
|
31619
|
-
if (pendingWrites.length > 0) {
|
|
31620
|
-
const displayPaths = pendingWrites.map((entry) => entry.displayPath);
|
|
31621
|
-
const preview = displayPaths.slice(0, MAX_OVERWRITE_PREVIEW_ROWS);
|
|
31622
|
-
if (displayPaths.length > preview.length) {
|
|
31623
|
-
preview.push(`\u2026 and ${displayPaths.length - preview.length} more`);
|
|
31577
|
+
if (removePath2(cwd, `${paths.pagesDir}/forms/${kebabName}`)) {
|
|
31578
|
+
deletedPaths.push(`${paths.pagesDir}/forms/${kebabName}`);
|
|
31624
31579
|
}
|
|
31625
|
-
|
|
31626
|
-
|
|
31627
|
-
|
|
31628
|
-
);
|
|
31629
|
-
if (!options.yes) {
|
|
31630
|
-
if (!isInteractiveSession()) {
|
|
31631
|
-
clack4.log.error(
|
|
31632
|
-
`Overwriting ${displayPaths.length} file${displayPaths.length === 1 ? "" : "s"} needs confirmation. Re-run with --yes.`
|
|
31633
|
-
);
|
|
31634
|
-
process.exit(1);
|
|
31635
|
-
}
|
|
31636
|
-
const proceed = await clack4.confirm({
|
|
31637
|
-
message: "Overwrite these files with the latest templates?",
|
|
31638
|
-
initialValue: true
|
|
31639
|
-
});
|
|
31640
|
-
if (clack4.isCancel(proceed) || !proceed) {
|
|
31641
|
-
clack4.cancel("Update cancelled.");
|
|
31642
|
-
process.exit(0);
|
|
31643
|
-
}
|
|
31580
|
+
} else {
|
|
31581
|
+
if (removePath2(cwd, `${paths.adminActionsDir}/${schemaName}`)) {
|
|
31582
|
+
deletedPaths.push(`${paths.adminActionsDir}/${schemaName}`);
|
|
31644
31583
|
}
|
|
31645
|
-
|
|
31646
|
-
|
|
31584
|
+
if (removePath2(cwd, `${paths.pagesDir}/${schemaName}`)) {
|
|
31585
|
+
deletedPaths.push(`${paths.pagesDir}/${schemaName}`);
|
|
31647
31586
|
}
|
|
31648
31587
|
}
|
|
31649
|
-
|
|
31650
|
-
|
|
31651
|
-
|
|
31652
|
-
|
|
31653
|
-
(dependency) => !hasDeclaredPackage2(projectPackageJson, dependency)
|
|
31654
|
-
);
|
|
31655
|
-
if (missingPackageDependencies.length > 0) {
|
|
31656
|
-
clack4.log.warn(
|
|
31657
|
-
`Updated components require package dependencies that are not declared: ${missingPackageDependencies.join(", ")}. Run 'pnpm betterstart update-deps' before building.`
|
|
31658
|
-
);
|
|
31588
|
+
cleanupEmptyDirs3(cwd, deletedPaths, paths);
|
|
31589
|
+
deleteSnapshot(cwd, schemaName);
|
|
31590
|
+
if (hasTombstone(cwd, schemaName)) {
|
|
31591
|
+
clearTombstone(cwd, schemaName);
|
|
31659
31592
|
}
|
|
31660
|
-
|
|
31661
|
-
|
|
31593
|
+
writeTombstone(cwd, schemaName);
|
|
31594
|
+
await applyGeneratedFiles({
|
|
31595
|
+
cwd,
|
|
31596
|
+
config,
|
|
31597
|
+
scope: BARREL_SCOPE,
|
|
31598
|
+
schemaJson: { name: BARREL_SCOPE },
|
|
31599
|
+
generatedFiles: renderBarrelFiles(cwd, config),
|
|
31600
|
+
force: false,
|
|
31601
|
+
interactive: false
|
|
31602
|
+
});
|
|
31603
|
+
clack4.log.info(
|
|
31604
|
+
`Tombstone written: .betterstart/snapshots/_removed/${schemaName}
|
|
31605
|
+
Schema JSON preserved.`
|
|
31662
31606
|
);
|
|
31607
|
+
clack4.outro(`Removed generated files for ${schemaName}`);
|
|
31663
31608
|
}
|
|
31664
|
-
|
|
31665
|
-
|
|
31666
|
-
|
|
31609
|
+
|
|
31610
|
+
// adapters/next/commands/uninstall.ts
|
|
31611
|
+
import fs45 from "fs";
|
|
31612
|
+
import path59 from "path";
|
|
31613
|
+
import * as p30 from "@clack/prompts";
|
|
31614
|
+
import pc11 from "picocolors";
|
|
31615
|
+
|
|
31616
|
+
// adapters/next/commands/uninstall-cleaners.ts
|
|
31617
|
+
import fs44 from "fs";
|
|
31618
|
+
function stripJsonComments2(input) {
|
|
31619
|
+
let result = "";
|
|
31620
|
+
let i = 0;
|
|
31621
|
+
while (i < input.length) {
|
|
31622
|
+
if (input[i] === '"') {
|
|
31623
|
+
let j = i + 1;
|
|
31624
|
+
while (j < input.length) {
|
|
31625
|
+
if (input[j] === "\\") {
|
|
31626
|
+
j += 2;
|
|
31627
|
+
continue;
|
|
31628
|
+
}
|
|
31629
|
+
if (input[j] === '"') {
|
|
31630
|
+
j++;
|
|
31631
|
+
break;
|
|
31632
|
+
}
|
|
31633
|
+
j++;
|
|
31634
|
+
}
|
|
31635
|
+
result += input.slice(i, j);
|
|
31636
|
+
i = j;
|
|
31637
|
+
} else if (input[i] === "/" && input[i + 1] === "/") {
|
|
31638
|
+
const nl = input.indexOf("\n", i);
|
|
31639
|
+
i = nl === -1 ? input.length : nl;
|
|
31640
|
+
} else if (input[i] === "/" && input[i + 1] === "*") {
|
|
31641
|
+
const end = input.indexOf("*/", i + 2);
|
|
31642
|
+
i = end === -1 ? input.length : end + 2;
|
|
31643
|
+
} else {
|
|
31644
|
+
result += input[i];
|
|
31645
|
+
i++;
|
|
31646
|
+
}
|
|
31667
31647
|
}
|
|
31648
|
+
return result;
|
|
31668
31649
|
}
|
|
31669
|
-
function
|
|
31670
|
-
if (
|
|
31671
|
-
|
|
31672
|
-
|
|
31650
|
+
function cleanTsconfig(tsconfigPath, aliasRoot = "@admin") {
|
|
31651
|
+
if (!fs44.existsSync(tsconfigPath)) return [];
|
|
31652
|
+
const raw = fs44.readFileSync(tsconfigPath, "utf-8");
|
|
31653
|
+
const stripped = stripJsonComments2(raw).replace(/,\s*([\]}])/g, "$1");
|
|
31654
|
+
let tsconfig;
|
|
31655
|
+
try {
|
|
31656
|
+
tsconfig = JSON.parse(stripped);
|
|
31657
|
+
} catch {
|
|
31658
|
+
return [];
|
|
31673
31659
|
}
|
|
31674
|
-
|
|
31675
|
-
|
|
31660
|
+
const compilerOptions = tsconfig.compilerOptions ?? {};
|
|
31661
|
+
const paths = compilerOptions.paths ?? {};
|
|
31662
|
+
const removed = [];
|
|
31663
|
+
for (const key of Object.keys(paths)) {
|
|
31664
|
+
if (key.startsWith("@admin/") || key === "@admin/*" || key.startsWith(`${aliasRoot}/`) || key === `${aliasRoot}/*`) {
|
|
31665
|
+
removed.push(key);
|
|
31666
|
+
delete paths[key];
|
|
31667
|
+
}
|
|
31676
31668
|
}
|
|
31677
|
-
if (
|
|
31678
|
-
|
|
31679
|
-
|
|
31669
|
+
if (removed.length === 0) return [];
|
|
31670
|
+
if (Object.keys(paths).length === 0) {
|
|
31671
|
+
compilerOptions.paths = void 0;
|
|
31672
|
+
} else {
|
|
31673
|
+
compilerOptions.paths = paths;
|
|
31680
31674
|
}
|
|
31681
|
-
|
|
31682
|
-
|
|
31683
|
-
|
|
31675
|
+
tsconfig.compilerOptions = compilerOptions;
|
|
31676
|
+
fs44.writeFileSync(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}
|
|
31677
|
+
`, "utf-8");
|
|
31678
|
+
return removed;
|
|
31679
|
+
}
|
|
31680
|
+
function cleanCss(cssPath, namespace = "admin") {
|
|
31681
|
+
if (!fs44.existsSync(cssPath)) return [];
|
|
31682
|
+
const content = fs44.readFileSync(cssPath, "utf-8");
|
|
31683
|
+
const lines = content.split("\n");
|
|
31684
|
+
const sourcePattern = new RegExp(`^@source\\s+"[^"]*(?:admin|${namespace})[^"]*";\\s*$`);
|
|
31685
|
+
const removed = [];
|
|
31686
|
+
const kept = [];
|
|
31687
|
+
for (const line of lines) {
|
|
31688
|
+
if (sourcePattern.test(line)) {
|
|
31689
|
+
removed.push(line.trim());
|
|
31690
|
+
} else {
|
|
31691
|
+
kept.push(line);
|
|
31692
|
+
}
|
|
31684
31693
|
}
|
|
31685
|
-
if (
|
|
31686
|
-
|
|
31687
|
-
|
|
31694
|
+
if (removed.length === 0) return [];
|
|
31695
|
+
const cleaned = kept.join("\n").replace(/\n{3,}/g, "\n\n");
|
|
31696
|
+
fs44.writeFileSync(cssPath, cleaned, "utf-8");
|
|
31697
|
+
return removed;
|
|
31698
|
+
}
|
|
31699
|
+
function cleanEnvFile(envPath) {
|
|
31700
|
+
if (!fs44.existsSync(envPath)) return [];
|
|
31701
|
+
const content = fs44.readFileSync(envPath, "utf-8");
|
|
31702
|
+
const lines = content.split("\n");
|
|
31703
|
+
const removed = [];
|
|
31704
|
+
const kept = [];
|
|
31705
|
+
const headerPattern = /^# =+$/;
|
|
31706
|
+
const headerTextPattern = /^# BetterStart Admin$/;
|
|
31707
|
+
for (let i = 0; i < lines.length; i++) {
|
|
31708
|
+
const line = lines[i];
|
|
31709
|
+
const trimmed = line.trim();
|
|
31710
|
+
if (trimmed.match(/^BETTERSTART_\w+=/)) {
|
|
31711
|
+
const key = trimmed.split("=")[0];
|
|
31712
|
+
removed.push(key);
|
|
31713
|
+
continue;
|
|
31714
|
+
}
|
|
31715
|
+
if (headerPattern.test(trimmed)) {
|
|
31716
|
+
const next = lines[i + 1]?.trim();
|
|
31717
|
+
const afterNext = lines[i + 2]?.trim();
|
|
31718
|
+
if (next && headerTextPattern.test(next) && afterNext && headerPattern.test(afterNext)) {
|
|
31719
|
+
i += 2;
|
|
31720
|
+
continue;
|
|
31721
|
+
}
|
|
31722
|
+
}
|
|
31723
|
+
if (trimmed.startsWith("#") && !headerPattern.test(trimmed)) {
|
|
31724
|
+
const nextNonEmpty = findNextNonEmptyLine(lines, i + 1);
|
|
31725
|
+
if (nextNonEmpty?.match(/^BETTERSTART_\w+=/)) {
|
|
31726
|
+
continue;
|
|
31727
|
+
}
|
|
31728
|
+
}
|
|
31729
|
+
kept.push(line);
|
|
31688
31730
|
}
|
|
31689
|
-
|
|
31690
|
-
|
|
31691
|
-
if (
|
|
31692
|
-
|
|
31731
|
+
if (removed.length === 0) return [];
|
|
31732
|
+
const result = kept.join("\n").replace(/\n{3,}/g, "\n\n").trim();
|
|
31733
|
+
if (result === "") {
|
|
31734
|
+
fs44.unlinkSync(envPath);
|
|
31735
|
+
} else {
|
|
31736
|
+
fs44.writeFileSync(envPath, `${result}
|
|
31737
|
+
`, "utf-8");
|
|
31693
31738
|
}
|
|
31694
|
-
|
|
31695
|
-
|
|
31696
|
-
|
|
31697
|
-
|
|
31698
|
-
);
|
|
31699
|
-
|
|
31739
|
+
return removed;
|
|
31740
|
+
}
|
|
31741
|
+
function findNextNonEmptyLine(lines, startIndex) {
|
|
31742
|
+
for (let i = startIndex; i < lines.length; i++) {
|
|
31743
|
+
const trimmed = lines[i].trim();
|
|
31744
|
+
if (trimmed !== "") return trimmed;
|
|
31700
31745
|
}
|
|
31701
|
-
return
|
|
31746
|
+
return null;
|
|
31702
31747
|
}
|
|
31703
|
-
|
|
31704
|
-
|
|
31705
|
-
|
|
31706
|
-
|
|
31707
|
-
|
|
31708
|
-
|
|
31709
|
-
|
|
31710
|
-
|
|
31711
|
-
|
|
31712
|
-
|
|
31713
|
-
|
|
31714
|
-
|
|
31715
|
-
shadcnBackupPath,
|
|
31716
|
-
path59.join(cwd, config.paths.admin, "lib", "utils.ts"),
|
|
31717
|
-
...getHostProjectFilesToRestore(cwd)
|
|
31748
|
+
|
|
31749
|
+
// adapters/next/commands/uninstall.ts
|
|
31750
|
+
function findMainCss2(cwd) {
|
|
31751
|
+
const candidates = [
|
|
31752
|
+
"src/app/globals.css",
|
|
31753
|
+
"app/globals.css",
|
|
31754
|
+
"src/app/global.css",
|
|
31755
|
+
"app/global.css",
|
|
31756
|
+
"src/app/app.css",
|
|
31757
|
+
"app/app.css",
|
|
31758
|
+
"src/globals.css",
|
|
31759
|
+
"globals.css"
|
|
31718
31760
|
];
|
|
31719
|
-
|
|
31720
|
-
|
|
31721
|
-
|
|
31722
|
-
}
|
|
31723
|
-
if (!fs45.existsSync(adminGlobalsPath)) {
|
|
31724
|
-
clack4.cancel(
|
|
31725
|
-
`Admin globals file not found at ${path59.relative(cwd, adminGlobalsPath)}. Run 'betterstart update admin-globals' first.`
|
|
31726
|
-
);
|
|
31727
|
-
process.exit(1);
|
|
31761
|
+
for (const candidate of candidates) {
|
|
31762
|
+
const filePath = path59.join(cwd, candidate);
|
|
31763
|
+
if (fs45.existsSync(filePath)) return filePath;
|
|
31728
31764
|
}
|
|
31729
|
-
|
|
31730
|
-
|
|
31731
|
-
|
|
31732
|
-
|
|
31733
|
-
}));
|
|
31734
|
-
clack4.intro("BetterStart Shadcn Preset");
|
|
31735
|
-
clack4.log.info(`Applying preset to ${path59.join(config.paths.admin, "components/ui")}`);
|
|
31736
|
-
let failed = false;
|
|
31765
|
+
return void 0;
|
|
31766
|
+
}
|
|
31767
|
+
function isCLICreatedBiome(biomePath) {
|
|
31768
|
+
if (!fs45.existsSync(biomePath)) return false;
|
|
31737
31769
|
try {
|
|
31738
|
-
fs45.
|
|
31739
|
-
|
|
31740
|
-
`${JSON.stringify(createAdminShadcnComponentsJson(config), null, 2)}
|
|
31741
|
-
`,
|
|
31742
|
-
"utf-8"
|
|
31743
|
-
);
|
|
31744
|
-
const args = ["apply", "--preset", preset, "--cwd", cwd, "--yes"];
|
|
31745
|
-
if (only) {
|
|
31746
|
-
args.push("--only", only);
|
|
31747
|
-
}
|
|
31748
|
-
execFileSync6(shadcnBin, args, { cwd, stdio: "inherit" });
|
|
31770
|
+
const content = JSON.parse(fs45.readFileSync(biomePath, "utf-8"));
|
|
31771
|
+
return content.$schema?.includes("biomejs.dev") && content.formatter?.indentStyle === "space" && content.javascript?.formatter?.quoteStyle === "single" && Array.isArray(content.files?.ignore) && content.files.ignore.includes(".next");
|
|
31749
31772
|
} catch {
|
|
31750
|
-
|
|
31751
|
-
}
|
|
31752
|
-
|
|
31753
|
-
|
|
31773
|
+
return false;
|
|
31774
|
+
}
|
|
31775
|
+
}
|
|
31776
|
+
function buildUninstallPlan(cwd, namespaceValue) {
|
|
31777
|
+
const steps = [];
|
|
31778
|
+
const namespace = resolveAdminNamespace(namespaceValue);
|
|
31779
|
+
const hasSrc = fs45.existsSync(path59.join(cwd, "src"));
|
|
31780
|
+
const appBase = hasSrc ? "src/app" : "app";
|
|
31781
|
+
const dirs = [];
|
|
31782
|
+
const adminDir = path59.join(cwd, namespace.segment);
|
|
31783
|
+
const legacyAdminDir = path59.join(cwd, "admin");
|
|
31784
|
+
const adminRouteGroup = path59.join(cwd, appBase, namespace.routeGroup);
|
|
31785
|
+
const legacyAdminRouteGroup = path59.join(cwd, appBase, "(admin)");
|
|
31786
|
+
if (fs45.existsSync(adminDir)) dirs.push(`${namespace.segment}/`);
|
|
31787
|
+
if (namespace.segment !== "admin" && fs45.existsSync(legacyAdminDir)) dirs.push("admin/");
|
|
31788
|
+
if (fs45.existsSync(adminRouteGroup)) dirs.push(`${appBase}/${namespace.routeGroup}/`);
|
|
31789
|
+
if (namespace.segment !== "admin" && fs45.existsSync(legacyAdminRouteGroup))
|
|
31790
|
+
dirs.push(`${appBase}/(admin)/`);
|
|
31791
|
+
if (dirs.length > 0) {
|
|
31792
|
+
steps.push({
|
|
31793
|
+
label: "Admin directories",
|
|
31794
|
+
items: dirs,
|
|
31795
|
+
count: dirs.length,
|
|
31796
|
+
unit: dirs.length === 1 ? "directory" : "directories",
|
|
31797
|
+
execute() {
|
|
31798
|
+
if (fs45.existsSync(adminDir)) fs45.rmSync(adminDir, { recursive: true, force: true });
|
|
31799
|
+
if (fs45.existsSync(legacyAdminDir))
|
|
31800
|
+
fs45.rmSync(legacyAdminDir, { recursive: true, force: true });
|
|
31801
|
+
if (fs45.existsSync(adminRouteGroup)) {
|
|
31802
|
+
fs45.rmSync(adminRouteGroup, { recursive: true, force: true });
|
|
31803
|
+
}
|
|
31804
|
+
if (fs45.existsSync(legacyAdminRouteGroup)) {
|
|
31805
|
+
fs45.rmSync(legacyAdminRouteGroup, { recursive: true, force: true });
|
|
31806
|
+
}
|
|
31807
|
+
}
|
|
31808
|
+
});
|
|
31809
|
+
}
|
|
31810
|
+
const configFiles = [];
|
|
31811
|
+
const configPaths = [];
|
|
31812
|
+
const candidates = [
|
|
31813
|
+
[CONFIG_FILE_NAME, path59.join(cwd, CONFIG_FILE_NAME)],
|
|
31814
|
+
["drizzle.config.ts", path59.join(cwd, "drizzle.config.ts")],
|
|
31815
|
+
["ADMIN.md", path59.join(cwd, "ADMIN.md")]
|
|
31816
|
+
];
|
|
31817
|
+
for (const [label, fullPath] of candidates) {
|
|
31818
|
+
if (fs45.existsSync(fullPath)) {
|
|
31819
|
+
configFiles.push(label);
|
|
31820
|
+
configPaths.push(fullPath);
|
|
31754
31821
|
}
|
|
31755
31822
|
}
|
|
31756
|
-
|
|
31757
|
-
|
|
31758
|
-
|
|
31823
|
+
const biomePath = path59.join(cwd, "biome.json");
|
|
31824
|
+
if (isCLICreatedBiome(biomePath)) {
|
|
31825
|
+
configFiles.push("biome.json (CLI-created)");
|
|
31826
|
+
configPaths.push(biomePath);
|
|
31759
31827
|
}
|
|
31760
|
-
|
|
31761
|
-
|
|
31762
|
-
|
|
31763
|
-
|
|
31764
|
-
|
|
31765
|
-
|
|
31766
|
-
|
|
31767
|
-
|
|
31768
|
-
|
|
31769
|
-
|
|
31770
|
-
|
|
31771
|
-
|
|
31772
|
-
|
|
31773
|
-
|
|
31774
|
-
|
|
31775
|
-
|
|
31776
|
-
|
|
31777
|
-
|
|
31778
|
-
|
|
31779
|
-
|
|
31780
|
-
|
|
31781
|
-
|
|
31782
|
-
|
|
31783
|
-
|
|
31784
|
-
|
|
31785
|
-
|
|
31828
|
+
if (configFiles.length > 0) {
|
|
31829
|
+
steps.push({
|
|
31830
|
+
label: "Config files",
|
|
31831
|
+
items: configFiles,
|
|
31832
|
+
count: configFiles.length,
|
|
31833
|
+
unit: configFiles.length === 1 ? "file" : "files",
|
|
31834
|
+
execute() {
|
|
31835
|
+
for (const p32 of configPaths) {
|
|
31836
|
+
if (fs45.existsSync(p32)) fs45.unlinkSync(p32);
|
|
31837
|
+
}
|
|
31838
|
+
}
|
|
31839
|
+
});
|
|
31840
|
+
}
|
|
31841
|
+
const tsconfigPath = path59.join(cwd, "tsconfig.json");
|
|
31842
|
+
if (fs45.existsSync(tsconfigPath)) {
|
|
31843
|
+
const content = fs45.readFileSync(tsconfigPath, "utf-8");
|
|
31844
|
+
const aliasMatches = [
|
|
31845
|
+
...content.match(/"@admin\//g) ?? [],
|
|
31846
|
+
...content.match(new RegExp(`"${namespace.alias}/`, "g")) ?? []
|
|
31847
|
+
];
|
|
31848
|
+
if (aliasMatches && aliasMatches.length > 0) {
|
|
31849
|
+
const aliasCount = aliasMatches.length;
|
|
31850
|
+
steps.push({
|
|
31851
|
+
label: "tsconfig.json path aliases",
|
|
31852
|
+
items: [`${namespace.alias}/* aliases in tsconfig.json`],
|
|
31853
|
+
count: aliasCount,
|
|
31854
|
+
unit: aliasCount === 1 ? "alias" : "aliases",
|
|
31855
|
+
execute() {
|
|
31856
|
+
cleanTsconfig(tsconfigPath, namespace.alias);
|
|
31857
|
+
}
|
|
31858
|
+
});
|
|
31786
31859
|
}
|
|
31787
|
-
}
|
|
31788
|
-
|
|
31789
|
-
|
|
31790
|
-
|
|
31791
|
-
|
|
31792
|
-
|
|
31793
|
-
const binName = process.platform === "win32" ? "shadcn.cmd" : "shadcn";
|
|
31794
|
-
const shadcnBin = path59.join(cwd, "node_modules", ".bin", binName);
|
|
31795
|
-
if (!fs45.existsSync(shadcnBin)) {
|
|
31796
|
-
clack4.cancel(
|
|
31797
|
-
`shadcn is not installed in this project. Run 'betterstart update-deps' and try again.`
|
|
31860
|
+
}
|
|
31861
|
+
const cssFile = findMainCss2(cwd);
|
|
31862
|
+
if (cssFile) {
|
|
31863
|
+
const cssContent = fs45.readFileSync(cssFile, "utf-8");
|
|
31864
|
+
const sourceLines = cssContent.split("\n").filter(
|
|
31865
|
+
(l) => new RegExp(`^@source\\s+"[^"]*(?:admin|${namespace.segment})[^"]*";\\s*$`).test(l)
|
|
31798
31866
|
);
|
|
31799
|
-
|
|
31867
|
+
if (sourceLines.length > 0) {
|
|
31868
|
+
const relCss = path59.relative(cwd, cssFile);
|
|
31869
|
+
steps.push({
|
|
31870
|
+
label: `CSS @source lines (${relCss})`,
|
|
31871
|
+
items: [`@source lines in ${relCss}`],
|
|
31872
|
+
count: sourceLines.length,
|
|
31873
|
+
unit: sourceLines.length === 1 ? "line" : "lines",
|
|
31874
|
+
execute() {
|
|
31875
|
+
cleanCss(cssFile, namespace.segment);
|
|
31876
|
+
}
|
|
31877
|
+
});
|
|
31878
|
+
}
|
|
31800
31879
|
}
|
|
31801
|
-
|
|
31802
|
-
|
|
31803
|
-
|
|
31804
|
-
|
|
31805
|
-
|
|
31806
|
-
|
|
31807
|
-
|
|
31808
|
-
|
|
31809
|
-
|
|
31810
|
-
|
|
31811
|
-
|
|
31812
|
-
|
|
31813
|
-
|
|
31814
|
-
|
|
31815
|
-
|
|
31816
|
-
return hostRelativePaths.map((relativePath) => path59.join(cwd, relativePath));
|
|
31817
|
-
}
|
|
31818
|
-
function snapshotFile(filePath) {
|
|
31819
|
-
if (!fs45.existsSync(filePath)) {
|
|
31820
|
-
return { existed: false };
|
|
31880
|
+
const envPath = path59.join(cwd, ".env.local");
|
|
31881
|
+
if (fs45.existsSync(envPath)) {
|
|
31882
|
+
const envContent = fs45.readFileSync(envPath, "utf-8");
|
|
31883
|
+
const bsVars = envContent.split("\n").filter((l) => l.trim().match(/^BETTERSTART_\w+=/)).map((l) => l.split("=")[0]);
|
|
31884
|
+
if (bsVars.length > 0) {
|
|
31885
|
+
steps.push({
|
|
31886
|
+
label: ".env.local variables",
|
|
31887
|
+
items: ["BETTERSTART_* vars in .env.local"],
|
|
31888
|
+
count: bsVars.length,
|
|
31889
|
+
unit: bsVars.length === 1 ? "variable" : "variables",
|
|
31890
|
+
execute() {
|
|
31891
|
+
cleanEnvFile(envPath);
|
|
31892
|
+
}
|
|
31893
|
+
});
|
|
31894
|
+
}
|
|
31821
31895
|
}
|
|
31822
|
-
return
|
|
31896
|
+
return steps;
|
|
31823
31897
|
}
|
|
31824
|
-
function
|
|
31825
|
-
|
|
31826
|
-
|
|
31898
|
+
async function runUninstallCommand(options) {
|
|
31899
|
+
const cwd = options.cwd ? path59.resolve(options.cwd) : process.cwd();
|
|
31900
|
+
p30.intro(pc11.bgRed(pc11.white(" BetterStart Uninstall ")));
|
|
31901
|
+
let namespace = DEFAULT_ADMIN_NAMESPACE;
|
|
31902
|
+
try {
|
|
31903
|
+
const config = await resolveConfig(cwd);
|
|
31904
|
+
namespace = config.frameworkConfig.next.namespace;
|
|
31905
|
+
} catch {
|
|
31906
|
+
}
|
|
31907
|
+
const steps = buildUninstallPlan(cwd, namespace);
|
|
31908
|
+
if (steps.length === 0) {
|
|
31909
|
+
p30.log.success(`${pc11.green("\u2713")} Nothing to remove \u2014 project is already clean.`);
|
|
31910
|
+
p30.outro("Project already clean");
|
|
31827
31911
|
return;
|
|
31828
31912
|
}
|
|
31829
|
-
|
|
31830
|
-
|
|
31913
|
+
const planLines = steps.map((step) => {
|
|
31914
|
+
const names = step.items.join(" ");
|
|
31915
|
+
const countLabel = pc11.dim(`${step.count} ${step.unit}`);
|
|
31916
|
+
return `${pc11.red("\u2717")} ${names} ${countLabel}`;
|
|
31917
|
+
});
|
|
31918
|
+
p30.note(planLines.join("\n"), "Uninstall plan");
|
|
31919
|
+
if (!options.force) {
|
|
31920
|
+
const confirmed = await p30.confirm({
|
|
31921
|
+
message: "Proceed with uninstall?",
|
|
31922
|
+
initialValue: false
|
|
31923
|
+
});
|
|
31924
|
+
if (p30.isCancel(confirmed) || !confirmed) {
|
|
31925
|
+
p30.cancel("Uninstall cancelled.");
|
|
31926
|
+
process.exit(0);
|
|
31927
|
+
}
|
|
31928
|
+
}
|
|
31929
|
+
const s = spinner2();
|
|
31930
|
+
s.start(steps[0].label);
|
|
31931
|
+
for (const step of steps) {
|
|
31932
|
+
s.message(step.label);
|
|
31933
|
+
step.execute();
|
|
31831
31934
|
}
|
|
31935
|
+
const parts = steps.map((step) => `${step.count} ${step.unit}`);
|
|
31936
|
+
s.stop(`Removed ${parts.join(", ")}`);
|
|
31937
|
+
p30.note(pc11.dim("Database tables were NOT dropped \u2014 drop them manually if needed."), "Next steps");
|
|
31938
|
+
p30.outro("Uninstall complete");
|
|
31832
31939
|
}
|
|
31833
31940
|
|
|
31834
31941
|
// adapters/next/commands/update-deps.ts
|
|
@@ -31894,6 +32001,7 @@ async function runUpdateStylesCommand(options) {
|
|
|
31894
32001
|
|
|
31895
32002
|
// adapters/next/commands-runtime.ts
|
|
31896
32003
|
var nextCommandRuntime = {
|
|
32004
|
+
listComponentChoices,
|
|
31897
32005
|
listInstallableChoices,
|
|
31898
32006
|
listSchemaChoices,
|
|
31899
32007
|
runAdd: runAddCommand,
|