betterstart-cli 0.0.39 → 0.0.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +40 -154
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -22176,6 +22176,11 @@ function scaffoldEnv(cwd, options) {
|
|
|
22176
22176
|
}
|
|
22177
22177
|
|
|
22178
22178
|
// adapters/next/init/prompts/plugins.ts
|
|
22179
|
+
function maskBlobToken(token) {
|
|
22180
|
+
const match = /^(vercel_blob_rw_[A-Za-z0-9]+)_/.exec(token);
|
|
22181
|
+
if (match) return `${match[1]}_***`;
|
|
22182
|
+
return `${token.slice(0, 8)}***`;
|
|
22183
|
+
}
|
|
22179
22184
|
async function promptPlugins(cwd, options = {}) {
|
|
22180
22185
|
const sections = [];
|
|
22181
22186
|
const overwriteKeys = /* @__PURE__ */ new Set();
|
|
@@ -22235,7 +22240,12 @@ async function promptPlugins(cwd, options = {}) {
|
|
|
22235
22240
|
storageStep.skip();
|
|
22236
22241
|
} else {
|
|
22237
22242
|
if (existingToken) {
|
|
22238
|
-
p12.log.info(
|
|
22243
|
+
p12.log.info(
|
|
22244
|
+
`Using the existing BLOB_READ_WRITE_TOKEN from .env.local ${styleText(
|
|
22245
|
+
"dim",
|
|
22246
|
+
`(${maskBlobToken(existingToken)})`
|
|
22247
|
+
)}`
|
|
22248
|
+
);
|
|
22239
22249
|
}
|
|
22240
22250
|
mergeIntegrationConfig(await collectIntegrationConfig(cwd, ["vercel-blob"]));
|
|
22241
22251
|
storageStep.confirm();
|
|
@@ -22260,30 +22270,13 @@ async function promptPlugins(cwd, options = {}) {
|
|
|
22260
22270
|
process.exit(0);
|
|
22261
22271
|
}
|
|
22262
22272
|
const integrations = [];
|
|
22263
|
-
|
|
22264
|
-
|
|
22265
|
-
|
|
22266
|
-
"
|
|
22267
|
-
|
|
22268
|
-
|
|
22269
|
-
initialValue: true
|
|
22273
|
+
sections.push({
|
|
22274
|
+
header: "Email (Resend)",
|
|
22275
|
+
vars: [
|
|
22276
|
+
{ key: "BETTERSTART_RESEND_API_KEY", value: "" },
|
|
22277
|
+
{ key: "BETTERSTART_EMAIL_FROM", value: "" }
|
|
22278
|
+
]
|
|
22270
22279
|
});
|
|
22271
|
-
if (p12.isCancel(setupResend)) {
|
|
22272
|
-
p12.cancel("Setup cancelled.");
|
|
22273
|
-
process.exit(0);
|
|
22274
|
-
}
|
|
22275
|
-
if (setupResend) {
|
|
22276
|
-
integrations.push("resend");
|
|
22277
|
-
mergeIntegrationConfig(await collectIntegrationConfig(cwd, ["resend"]));
|
|
22278
|
-
} else {
|
|
22279
|
-
sections.push({
|
|
22280
|
-
header: "Email (Resend)",
|
|
22281
|
-
vars: [
|
|
22282
|
-
{ key: "BETTERSTART_RESEND_API_KEY", value: "" },
|
|
22283
|
-
{ key: "BETTERSTART_EMAIL_FROM", value: "" }
|
|
22284
|
-
]
|
|
22285
|
-
});
|
|
22286
|
-
}
|
|
22287
22280
|
if (storage === "r2") {
|
|
22288
22281
|
integrations.push("r2");
|
|
22289
22282
|
} else if (storage === "vercel-blob") {
|
|
@@ -25495,18 +25488,6 @@ function readNamespaceFromConfigSource(source) {
|
|
|
25495
25488
|
const match = source.match(/\bnamespace\s*:\s*(['"`])([^'"`]+)\1/);
|
|
25496
25489
|
return normalizeNamespaceForRemoval(match?.[2]);
|
|
25497
25490
|
}
|
|
25498
|
-
function formatStorageProviderLabel(provider) {
|
|
25499
|
-
switch (provider) {
|
|
25500
|
-
case "vercel-blob":
|
|
25501
|
-
return "Vercel Blob";
|
|
25502
|
-
case "r2":
|
|
25503
|
-
return "Cloudflare R2";
|
|
25504
|
-
case "local":
|
|
25505
|
-
return "local filesystem";
|
|
25506
|
-
default:
|
|
25507
|
-
return provider;
|
|
25508
|
-
}
|
|
25509
|
-
}
|
|
25510
25491
|
function resolveNonInteractiveProject(name) {
|
|
25511
25492
|
const projectName = name?.trim() || "my-app";
|
|
25512
25493
|
if (projectName !== "." && !/^[a-z0-9_-]+$/i.test(projectName)) {
|
|
@@ -25798,7 +25779,7 @@ async function runInitCommand(name, options) {
|
|
|
25798
25779
|
}
|
|
25799
25780
|
} else if (existingDbUrl) {
|
|
25800
25781
|
const masked = maskDbUrl(existingDbUrl);
|
|
25801
|
-
p18.log.info(`Using existing
|
|
25782
|
+
p18.log.info(`Using the existing DATABASE_URL from .env.local ${pc7.dim(`(${masked})`)}`);
|
|
25802
25783
|
databaseUrl = existingDbUrl;
|
|
25803
25784
|
} else {
|
|
25804
25785
|
const databaseStep = deferNextPromptCheck();
|
|
@@ -25903,35 +25884,21 @@ async function runInitCommand(name, options) {
|
|
|
25903
25884
|
config.frameworkConfig.next.paths = deriveNamespacePaths(namespace, srcDir);
|
|
25904
25885
|
config.paths = config.frameworkConfig.next.paths;
|
|
25905
25886
|
config.database.migrationsDir = deriveMigrationsDir(namespace);
|
|
25906
|
-
const results = [];
|
|
25907
25887
|
const s = spinner2();
|
|
25908
25888
|
s.start("Directory structure");
|
|
25909
|
-
|
|
25889
|
+
scaffoldBase({
|
|
25910
25890
|
cwd,
|
|
25911
25891
|
config,
|
|
25912
25892
|
includeEmailTemplatesDir: pluginSelection.integrations.some(isEmailProviderIntegration)
|
|
25913
25893
|
});
|
|
25914
|
-
results.push({ label: "Directory structure", result: `${baseFiles.length} files` });
|
|
25915
25894
|
s.message("TypeScript aliases");
|
|
25916
|
-
|
|
25917
|
-
results.push({
|
|
25918
|
-
label: "TypeScript aliases",
|
|
25919
|
-
result: tsResult.added.length > 0 ? `${tsResult.added.length} paths` : "already set"
|
|
25920
|
-
});
|
|
25895
|
+
scaffoldTsconfig(cwd, config);
|
|
25921
25896
|
s.message("Tailwind CSS");
|
|
25922
|
-
|
|
25923
|
-
results.push({
|
|
25924
|
-
label: "Tailwind CSS",
|
|
25925
|
-
result: twResult.appended ? "updated" : twResult.file ? "already set" : "no CSS file"
|
|
25926
|
-
});
|
|
25897
|
+
scaffoldTailwind(cwd, srcDir, namespace);
|
|
25927
25898
|
s.message("Dev server");
|
|
25928
|
-
|
|
25929
|
-
results.push({
|
|
25930
|
-
label: "Dev server",
|
|
25931
|
-
result: formatDevServerResult(devServerResult)
|
|
25932
|
-
});
|
|
25899
|
+
ensureDefaultDevScriptPort(cwd);
|
|
25933
25900
|
s.message("Environment variables");
|
|
25934
|
-
|
|
25901
|
+
scaffoldEnv(cwd, { databaseUrl, namespace });
|
|
25935
25902
|
if (collectedIntegrationConfig.sections.length > 0) {
|
|
25936
25903
|
appendEnvVars(
|
|
25937
25904
|
cwd,
|
|
@@ -25939,49 +25906,26 @@ async function runInitCommand(name, options) {
|
|
|
25939
25906
|
collectedIntegrationConfig.overwriteKeys
|
|
25940
25907
|
);
|
|
25941
25908
|
}
|
|
25942
|
-
const envCount = envResult.added.length + envResult.updated.length;
|
|
25943
|
-
results.push({
|
|
25944
|
-
label: "Environment variables",
|
|
25945
|
-
result: envCount > 0 ? `${envCount} vars` : "already set"
|
|
25946
|
-
});
|
|
25947
25909
|
s.message("Database");
|
|
25948
25910
|
const dbFiles = scaffoldDatabase({ cwd, config });
|
|
25949
|
-
results.push({ label: "Database", result: `${dbFiles.length} files` });
|
|
25950
25911
|
s.message("Authentication");
|
|
25951
|
-
|
|
25952
|
-
results.push({ label: "Authentication", result: `${authFiles.length} files` });
|
|
25912
|
+
scaffoldAuth({ cwd, config });
|
|
25953
25913
|
s.message("Components");
|
|
25954
|
-
|
|
25955
|
-
results.push({ label: "Components", result: `${compFiles.length} files` });
|
|
25914
|
+
scaffoldComponents({ cwd, config });
|
|
25956
25915
|
s.message("Pages & layouts");
|
|
25957
|
-
|
|
25958
|
-
results.push({ label: "Pages & layouts", result: `${layoutFiles.length} files` });
|
|
25916
|
+
scaffoldLayout({ cwd, config });
|
|
25959
25917
|
s.message("API routes");
|
|
25960
|
-
|
|
25961
|
-
results.push({ label: "API routes", result: `${apiFiles.length} routes` });
|
|
25918
|
+
scaffoldApiRoutes({ cwd, config });
|
|
25962
25919
|
s.message("Linter");
|
|
25963
|
-
let linterResult;
|
|
25964
25920
|
if (project2.linter.type === "none") {
|
|
25965
|
-
|
|
25966
|
-
linterResult = biomeResult.installed ? "biome (new)" : "none";
|
|
25967
|
-
} else {
|
|
25968
|
-
linterResult = project2.linter.type;
|
|
25921
|
+
scaffoldBiome(cwd, project2.linter);
|
|
25969
25922
|
}
|
|
25970
|
-
results.push({ label: "Linter", result: linterResult });
|
|
25971
25923
|
s.message("Next.js config");
|
|
25972
25924
|
const nextConfigResult = scaffoldNextConfig({ cwd, nextMajorVersion });
|
|
25973
|
-
|
|
25974
|
-
|
|
25975
|
-
|
|
25976
|
-
}
|
|
25977
|
-
const maxLabel = Math.max(...results.map((r) => r.label.length));
|
|
25978
|
-
const noteLines = results.map((r) => {
|
|
25979
|
-
const padded = r.label.padEnd(maxLabel + 3);
|
|
25980
|
-
return `${pc7.green("\u2713")} ${padded}${pc7.dim(r.result)}`;
|
|
25981
|
-
});
|
|
25982
|
-
s.stop("");
|
|
25983
|
-
process.stdout.write("\x1B[2A\x1B[J");
|
|
25984
|
-
p18.note(noteLines.join("\n"), "Scaffolded admin");
|
|
25925
|
+
s.clear();
|
|
25926
|
+
if (nextConfigResult.status === "unsupported") {
|
|
25927
|
+
p18.log.warn("The Next.js config could not be updated automatically \u2014 review it manually.");
|
|
25928
|
+
}
|
|
25985
25929
|
const drizzleConfigPath = path50.join(cwd, "drizzle.config.ts");
|
|
25986
25930
|
if (!dbFiles.includes("drizzle.config.ts") && fs39.existsSync(drizzleConfigPath)) {
|
|
25987
25931
|
if (forceMode) {
|
|
@@ -26086,42 +26030,20 @@ async function runInitCommand(name, options) {
|
|
|
26086
26030
|
}
|
|
26087
26031
|
writeConfigFile(cwd, resolvedIntegrationInstallResult.config);
|
|
26088
26032
|
const usesLocalStorage = resolvedIntegrationInstallResult.config.storage.provider === "local";
|
|
26089
|
-
const
|
|
26090
|
-
|
|
26091
|
-
installLines.push(
|
|
26092
|
-
`${pc7.green("\u2713")} Dependencies ${pc7.dim(`${depsResult.dependencies.length} deps + ${depsResult.devDeps.length} dev deps`)}`
|
|
26093
|
-
);
|
|
26033
|
+
for (const err of coreSchemasResult.errors) {
|
|
26034
|
+
p18.log.warn(`Core schemas: ${err}`);
|
|
26094
26035
|
}
|
|
26095
|
-
if (coreSchemasResult.errors.length > 0) {
|
|
26096
|
-
installLines.push(
|
|
26097
|
-
`${pc7.yellow("\u25B2")} Core schemas ${pc7.dim(`${coreSchemasResult.errors.length} warning(s)`)}`
|
|
26098
|
-
);
|
|
26099
|
-
for (const err of coreSchemasResult.errors) {
|
|
26100
|
-
installLines.push(` ${pc7.dim(err)}`);
|
|
26101
|
-
}
|
|
26102
|
-
} else {
|
|
26103
|
-
installLines.push(
|
|
26104
|
-
`${pc7.green("\u2713")} Core schemas ${pc7.dim(`${coreSchemasResult.schemas.length} schemas, ${coreSchemasResult.generatedFiles.length} files`)}`
|
|
26105
|
-
);
|
|
26106
|
-
}
|
|
26107
|
-
installLines.push(
|
|
26108
|
-
`${pc7.green("\u2713")} Plugins ${pc7.dim(resolvedPluginInstallResult.installed.length > 0 ? resolvedPluginInstallResult.installed.join(", ") : "core only")}`
|
|
26109
|
-
);
|
|
26110
26036
|
for (const warning of resolvedPluginInstallResult.warnings) {
|
|
26111
|
-
|
|
26037
|
+
p18.log.warn(warning);
|
|
26112
26038
|
}
|
|
26113
|
-
installLines.push(
|
|
26114
|
-
`${pc7.green("\u2713")} Integrations ${pc7.dim(resolvedIntegrationInstallResult.installed.length > 0 ? resolvedIntegrationInstallResult.installed.join(", ") : "none")}`
|
|
26115
|
-
);
|
|
26116
26039
|
for (const warning of resolvedIntegrationInstallResult.warnings) {
|
|
26117
|
-
|
|
26040
|
+
p18.log.warn(warning);
|
|
26118
26041
|
}
|
|
26119
26042
|
if (usesLocalStorage) {
|
|
26120
|
-
|
|
26121
|
-
|
|
26043
|
+
p18.log.warn(
|
|
26044
|
+
"Local filesystem storage is only for development or self-hosted persistent-disk deployments. Use Vercel Blob or Cloudflare R2 for hosted/serverless production."
|
|
26122
26045
|
);
|
|
26123
26046
|
}
|
|
26124
|
-
p18.note(installLines.join("\n"), "Installed");
|
|
26125
26047
|
let dbPushed = false;
|
|
26126
26048
|
if (depsResult.success && options.skipMigration && hasDbUrl(cwd)) {
|
|
26127
26049
|
p18.log.info(`Skipping database schema push ${pc7.dim("(--skip-migration)")}`);
|
|
@@ -26150,9 +26072,7 @@ async function runInitCommand(name, options) {
|
|
|
26150
26072
|
}
|
|
26151
26073
|
if (driverReady) {
|
|
26152
26074
|
const useTerminalForDbPush = shouldUseTerminalForDbPush(options);
|
|
26153
|
-
if (useTerminalForDbPush) {
|
|
26154
|
-
p18.log.info(`Running ${pc7.cyan("drizzle-kit push --force")}`);
|
|
26155
|
-
} else {
|
|
26075
|
+
if (!useTerminalForDbPush) {
|
|
26156
26076
|
s.start("Pushing database schema (drizzle-kit push)");
|
|
26157
26077
|
}
|
|
26158
26078
|
const pushResult = await runDrizzlePush(cwd, { interactive: useTerminalForDbPush });
|
|
@@ -26164,11 +26084,8 @@ async function runInitCommand(name, options) {
|
|
|
26164
26084
|
p18.log.error("Database was not reachable. Aborting setup.");
|
|
26165
26085
|
process.exit(1);
|
|
26166
26086
|
}
|
|
26167
|
-
}
|
|
26168
|
-
if (useTerminalForDbPush) {
|
|
26169
|
-
p18.log.success("Database schema pushed");
|
|
26170
26087
|
} else {
|
|
26171
|
-
s.
|
|
26088
|
+
s.clear();
|
|
26172
26089
|
}
|
|
26173
26090
|
dbPushed = true;
|
|
26174
26091
|
} else {
|
|
@@ -26233,12 +26150,6 @@ async function runInitCommand(name, options) {
|
|
|
26233
26150
|
}
|
|
26234
26151
|
}
|
|
26235
26152
|
if (!adminAccountReady) {
|
|
26236
|
-
p18.note(
|
|
26237
|
-
pc7.dim(
|
|
26238
|
-
replaceExistingAdmin ? "Replace the existing admin account to access the admin." : "Create your first admin user to access the dashboard."
|
|
26239
|
-
),
|
|
26240
|
-
"Admin account"
|
|
26241
|
-
);
|
|
26242
26153
|
const credentials = await p18.group(
|
|
26243
26154
|
{
|
|
26244
26155
|
email: () => p18.text({
|
|
@@ -26328,19 +26239,8 @@ Run manually: ${pc7.cyan(betterstartExecCommand(pm, "seed"))}`,
|
|
|
26328
26239
|
s.stop("Git commit skipped");
|
|
26329
26240
|
}
|
|
26330
26241
|
}
|
|
26331
|
-
const totalFiles = baseFiles.length + dbFiles.length + authFiles.length + compFiles.length + layoutFiles.length + apiFiles.length;
|
|
26332
26242
|
const adminNamespace = resolveAdminNamespace(namespace);
|
|
26333
26243
|
const adminLoginUrl = `http://localhost:${detectDevPort(cwd)}${adminNamespace.routePath}/login`;
|
|
26334
|
-
const installedPluginList = resolvedPluginInstallResult.installed.length > 0 ? resolvedPluginInstallResult.installed.join(", ") : "core only";
|
|
26335
|
-
const installedIntegrationList = resolvedIntegrationInstallResult.installed.length > 0 ? resolvedIntegrationInstallResult.installed.join(", ") : "none";
|
|
26336
|
-
const summaryLines = [
|
|
26337
|
-
`Plugins: ${pc7.cyan(installedPluginList)}`,
|
|
26338
|
-
`Integrations: ${pc7.cyan(installedIntegrationList)}`,
|
|
26339
|
-
`Storage: ${pc7.cyan(formatStorageProviderLabel(resolvedIntegrationInstallResult.config.storage.provider))}`,
|
|
26340
|
-
`Files created: ${pc7.cyan(String(totalFiles))}`,
|
|
26341
|
-
`Env vars: ${envResult.added.length} added, ${envResult.skipped.length} skipped`
|
|
26342
|
-
];
|
|
26343
|
-
p18.note(summaryLines.join("\n"), "Admin scaffolded successfully");
|
|
26344
26244
|
if (options.vercel !== false && !options.skipDeploy) {
|
|
26345
26245
|
const linkedVercelProject = Boolean(readLinkedProjectId(cwd));
|
|
26346
26246
|
if (!options.yes) {
|
|
@@ -26453,20 +26353,6 @@ function detectInstalledNextVersion(cwd) {
|
|
|
26453
26353
|
return void 0;
|
|
26454
26354
|
}
|
|
26455
26355
|
}
|
|
26456
|
-
function formatDevServerResult(result) {
|
|
26457
|
-
switch (result.status) {
|
|
26458
|
-
case "updated":
|
|
26459
|
-
return `set to ${result.port}`;
|
|
26460
|
-
case "preserved":
|
|
26461
|
-
return `using ${result.port}`;
|
|
26462
|
-
case "skipped":
|
|
26463
|
-
return `custom script preserved; BetterStart uses ${result.port}`;
|
|
26464
|
-
case "missing-script":
|
|
26465
|
-
return `no dev script; BetterStart uses ${result.port}`;
|
|
26466
|
-
case "missing-package":
|
|
26467
|
-
return `package.json missing; BetterStart uses ${result.port}`;
|
|
26468
|
-
}
|
|
26469
|
-
}
|
|
26470
26356
|
function shouldUseTerminalForDbPush(options) {
|
|
26471
26357
|
return !options.yes && process.env.CI !== "true" && Boolean(process.stdin.isTTY) && Boolean(process.stdout.isTTY);
|
|
26472
26358
|
}
|