betterstart-cli 0.0.31 → 0.0.33
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 +275 -243
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -19775,6 +19775,14 @@ function fitSpinnerMessage(message) {
|
|
|
19775
19775
|
if (visible.length <= max) return message;
|
|
19776
19776
|
return `${visible.slice(0, max - 1)}\u2026`;
|
|
19777
19777
|
}
|
|
19778
|
+
var CLACK_LINE_ROWS = 2;
|
|
19779
|
+
function eraseClackLine(options = {}) {
|
|
19780
|
+
if (!process.stdout.isTTY || process.env.CI === "true") return;
|
|
19781
|
+
const below = (options.linesBelow ?? 0) * CLACK_LINE_ROWS;
|
|
19782
|
+
const up = below + CLACK_LINE_ROWS;
|
|
19783
|
+
const restore = below > 0 ? `\x1B[${below}B` : "";
|
|
19784
|
+
process.stdout.write(`\x1B[${up}A\x1B[${CLACK_LINE_ROWS}M${restore}`);
|
|
19785
|
+
}
|
|
19778
19786
|
function spinner2(options) {
|
|
19779
19787
|
const inner = p5.spinner(options);
|
|
19780
19788
|
const guided = options?.withGuide !== false;
|
|
@@ -21900,6 +21908,155 @@ function openBrowser(url) {
|
|
|
21900
21908
|
// adapters/next/init/prompts/plugins.ts
|
|
21901
21909
|
import { styleText } from "util";
|
|
21902
21910
|
import * as p11 from "@clack/prompts";
|
|
21911
|
+
|
|
21912
|
+
// adapters/next/init/scaffolders/env.ts
|
|
21913
|
+
import crypto2 from "crypto";
|
|
21914
|
+
|
|
21915
|
+
// adapters/next/init/scaffolders/dev-server.ts
|
|
21916
|
+
import fs26 from "fs";
|
|
21917
|
+
import path32 from "path";
|
|
21918
|
+
var DEFAULT_DEV_PORT = 4242;
|
|
21919
|
+
var DEV_PORT_FLAG_PATTERN = /(?:^|\s)(?:--port(?:=|\s+)|-p(?:=|\s+)?)(\d+)(?=\s|$)/;
|
|
21920
|
+
var DEV_PORT_ENV_PATTERN = /(?:^|\s)PORT=(\d+)(?=\s|$)/;
|
|
21921
|
+
function detectDevPort(cwd) {
|
|
21922
|
+
const pkg = readPackageJson2(cwd);
|
|
21923
|
+
if (!pkg) return DEFAULT_DEV_PORT;
|
|
21924
|
+
return detectDevPortFromScript(pkg.scripts?.dev) ?? DEFAULT_DEV_PORT;
|
|
21925
|
+
}
|
|
21926
|
+
function detectDevPortFromScript(devScript) {
|
|
21927
|
+
if (typeof devScript !== "string") return void 0;
|
|
21928
|
+
const trimmed = devScript.trim();
|
|
21929
|
+
if (trimmed.length === 0) return void 0;
|
|
21930
|
+
const flagMatch = trimmed.match(DEV_PORT_FLAG_PATTERN);
|
|
21931
|
+
const envMatch = trimmed.match(DEV_PORT_ENV_PATTERN);
|
|
21932
|
+
const rawPort = flagMatch?.[1] ?? envMatch?.[1];
|
|
21933
|
+
if (!rawPort) return void 0;
|
|
21934
|
+
const port = Number.parseInt(rawPort, 10);
|
|
21935
|
+
return isValidPort(port) ? port : void 0;
|
|
21936
|
+
}
|
|
21937
|
+
function ensureDefaultDevScriptPort(cwd) {
|
|
21938
|
+
const pkgPath = path32.join(cwd, "package.json");
|
|
21939
|
+
if (!fs26.existsSync(pkgPath)) {
|
|
21940
|
+
return { status: "missing-package", port: DEFAULT_DEV_PORT };
|
|
21941
|
+
}
|
|
21942
|
+
const raw = fs26.readFileSync(pkgPath, "utf-8");
|
|
21943
|
+
let pkg;
|
|
21944
|
+
try {
|
|
21945
|
+
pkg = JSON.parse(raw);
|
|
21946
|
+
} catch {
|
|
21947
|
+
return { status: "missing-package", port: DEFAULT_DEV_PORT };
|
|
21948
|
+
}
|
|
21949
|
+
const devScript = pkg.scripts?.dev;
|
|
21950
|
+
if (typeof devScript !== "string" || devScript.trim().length === 0) {
|
|
21951
|
+
return { status: "missing-script", port: DEFAULT_DEV_PORT };
|
|
21952
|
+
}
|
|
21953
|
+
const explicitPort = detectDevPortFromScript(devScript);
|
|
21954
|
+
if (explicitPort) {
|
|
21955
|
+
return { status: "preserved", port: explicitPort };
|
|
21956
|
+
}
|
|
21957
|
+
if (!isPlainNextDevScript(devScript)) {
|
|
21958
|
+
return { status: "skipped", port: DEFAULT_DEV_PORT };
|
|
21959
|
+
}
|
|
21960
|
+
const normalizedScript = `${normalizeWhitespace(devScript)} --port ${DEFAULT_DEV_PORT}`;
|
|
21961
|
+
pkg.scripts = {
|
|
21962
|
+
...pkg.scripts,
|
|
21963
|
+
dev: normalizedScript
|
|
21964
|
+
};
|
|
21965
|
+
const newline = raw.includes("\r\n") ? "\r\n" : "\n";
|
|
21966
|
+
const indent = detectIndent(raw);
|
|
21967
|
+
fs26.writeFileSync(pkgPath, `${JSON.stringify(pkg, null, indent)}${newline}`, "utf-8");
|
|
21968
|
+
return { status: "updated", port: DEFAULT_DEV_PORT };
|
|
21969
|
+
}
|
|
21970
|
+
function readPackageJson2(cwd) {
|
|
21971
|
+
const pkgPath = path32.join(cwd, "package.json");
|
|
21972
|
+
if (!fs26.existsSync(pkgPath)) return void 0;
|
|
21973
|
+
try {
|
|
21974
|
+
return JSON.parse(fs26.readFileSync(pkgPath, "utf-8"));
|
|
21975
|
+
} catch {
|
|
21976
|
+
return void 0;
|
|
21977
|
+
}
|
|
21978
|
+
}
|
|
21979
|
+
function isPlainNextDevScript(devScript) {
|
|
21980
|
+
const normalized = normalizeWhitespace(devScript);
|
|
21981
|
+
return normalized === "next dev" || normalized === "next dev --turbopack" || normalized === "next dev --turbo";
|
|
21982
|
+
}
|
|
21983
|
+
function normalizeWhitespace(value) {
|
|
21984
|
+
return value.trim().replace(/\s+/g, " ");
|
|
21985
|
+
}
|
|
21986
|
+
function detectIndent(raw) {
|
|
21987
|
+
const indentMatch = raw.match(/^[ \t]+(?=")/m);
|
|
21988
|
+
return indentMatch?.[0] ?? 2;
|
|
21989
|
+
}
|
|
21990
|
+
function isValidPort(port) {
|
|
21991
|
+
return Number.isInteger(port) && port > 0 && port <= 65535;
|
|
21992
|
+
}
|
|
21993
|
+
|
|
21994
|
+
// adapters/next/init/scaffolders/env.ts
|
|
21995
|
+
var LEGACY_DEFAULT_AUTH_URL = "http://localhost:3000";
|
|
21996
|
+
function getCoreEnvSections(databaseUrl, devPort, namespace) {
|
|
21997
|
+
const authSecret = crypto2.randomBytes(32).toString("base64");
|
|
21998
|
+
return [
|
|
21999
|
+
{
|
|
22000
|
+
header: "Database (PostgreSQL)",
|
|
22001
|
+
vars: [{ key: "DATABASE_URL", value: databaseUrl ?? "postgresql://..." }]
|
|
22002
|
+
},
|
|
22003
|
+
{
|
|
22004
|
+
header: "Authentication",
|
|
22005
|
+
vars: [
|
|
22006
|
+
{ key: "BETTERSTART_AUTH_SECRET", value: authSecret },
|
|
22007
|
+
{ key: "BETTERSTART_AUTH_URL", value: `http://localhost:${devPort}` },
|
|
22008
|
+
{ key: "BETTERSTART_AUTH_BASE_PATH", value: `/api/${namespace}/auth` }
|
|
22009
|
+
]
|
|
22010
|
+
}
|
|
22011
|
+
];
|
|
22012
|
+
}
|
|
22013
|
+
function shouldOverwriteAuthUrl(cwd, devPort) {
|
|
22014
|
+
const existingAuthUrl = readEnvVar(cwd, "BETTERSTART_AUTH_URL");
|
|
22015
|
+
if (!existingAuthUrl) return false;
|
|
22016
|
+
return existingAuthUrl === LEGACY_DEFAULT_AUTH_URL && existingAuthUrl !== `http://localhost:${devPort}`;
|
|
22017
|
+
}
|
|
22018
|
+
function persistDatabaseUrl(cwd, databaseUrl) {
|
|
22019
|
+
appendEnvVars(
|
|
22020
|
+
cwd,
|
|
22021
|
+
[
|
|
22022
|
+
{
|
|
22023
|
+
header: "Database (PostgreSQL)",
|
|
22024
|
+
vars: [{ key: "DATABASE_URL", value: databaseUrl }]
|
|
22025
|
+
}
|
|
22026
|
+
],
|
|
22027
|
+
/* @__PURE__ */ new Set(["DATABASE_URL"])
|
|
22028
|
+
);
|
|
22029
|
+
}
|
|
22030
|
+
function persistBlobReadWriteToken(cwd, token) {
|
|
22031
|
+
appendEnvVars(
|
|
22032
|
+
cwd,
|
|
22033
|
+
[
|
|
22034
|
+
{
|
|
22035
|
+
header: "Storage (Vercel Blob)",
|
|
22036
|
+
vars: [{ key: "BLOB_READ_WRITE_TOKEN", value: token }]
|
|
22037
|
+
}
|
|
22038
|
+
],
|
|
22039
|
+
/* @__PURE__ */ new Set(["BLOB_READ_WRITE_TOKEN"])
|
|
22040
|
+
);
|
|
22041
|
+
}
|
|
22042
|
+
function scaffoldEnv(cwd, options) {
|
|
22043
|
+
const devPort = detectDevPort(cwd);
|
|
22044
|
+
const sections = getCoreEnvSections(options.databaseUrl, devPort, options.namespace ?? "admin");
|
|
22045
|
+
const authBasePath = `/api/${options.namespace ?? "admin"}/auth`;
|
|
22046
|
+
const overwrite = /* @__PURE__ */ new Set();
|
|
22047
|
+
if (options.databaseUrl) {
|
|
22048
|
+
overwrite.add("DATABASE_URL");
|
|
22049
|
+
}
|
|
22050
|
+
if (shouldOverwriteAuthUrl(cwd, devPort)) {
|
|
22051
|
+
overwrite.add("BETTERSTART_AUTH_URL");
|
|
22052
|
+
}
|
|
22053
|
+
if (readEnvVar(cwd, "BETTERSTART_AUTH_BASE_PATH") !== authBasePath) {
|
|
22054
|
+
overwrite.add("BETTERSTART_AUTH_BASE_PATH");
|
|
22055
|
+
}
|
|
22056
|
+
return appendEnvVars(cwd, sections, overwrite);
|
|
22057
|
+
}
|
|
22058
|
+
|
|
22059
|
+
// adapters/next/init/prompts/plugins.ts
|
|
21903
22060
|
async function promptPlugins(cwd, options = {}) {
|
|
21904
22061
|
const sections = [];
|
|
21905
22062
|
const overwriteKeys = /* @__PURE__ */ new Set();
|
|
@@ -21938,6 +22095,8 @@ async function promptPlugins(cwd, options = {}) {
|
|
|
21938
22095
|
const existingToken = readEnvVar(cwd, "BLOB_READ_WRITE_TOKEN")?.trim();
|
|
21939
22096
|
const flow = !existingToken && options.provisionVercelBlob ? await options.provisionVercelBlob() : void 0;
|
|
21940
22097
|
if (flow?.ok && flow.token) {
|
|
22098
|
+
persistBlobReadWriteToken(cwd, flow.token);
|
|
22099
|
+
p11.log.success("Saved BLOB_READ_WRITE_TOKEN to .env.local");
|
|
21941
22100
|
sections.push({
|
|
21942
22101
|
header: "Storage (Vercel Blob)",
|
|
21943
22102
|
vars: [{ key: "BLOB_READ_WRITE_TOKEN", value: flow.token }]
|
|
@@ -22045,53 +22204,53 @@ async function promptProject(defaultName) {
|
|
|
22045
22204
|
}
|
|
22046
22205
|
|
|
22047
22206
|
// adapters/next/init/scaffolders/api-routes.ts
|
|
22048
|
-
import
|
|
22207
|
+
import path34 from "path";
|
|
22049
22208
|
|
|
22050
22209
|
// core-engine/utils/fs.ts
|
|
22051
|
-
import
|
|
22052
|
-
import
|
|
22210
|
+
import fs27 from "fs";
|
|
22211
|
+
import path33 from "path";
|
|
22053
22212
|
import fse from "fs-extra";
|
|
22054
22213
|
function ensureDir(dirPath) {
|
|
22055
22214
|
fse.ensureDirSync(dirPath);
|
|
22056
22215
|
}
|
|
22057
22216
|
function safeWriteFile(filePath, content, force = false) {
|
|
22058
|
-
if (!force &&
|
|
22217
|
+
if (!force && fs27.existsSync(filePath)) {
|
|
22059
22218
|
return false;
|
|
22060
22219
|
}
|
|
22061
|
-
ensureDir(
|
|
22062
|
-
|
|
22220
|
+
ensureDir(path33.dirname(filePath));
|
|
22221
|
+
fs27.writeFileSync(filePath, content, "utf-8");
|
|
22063
22222
|
return true;
|
|
22064
22223
|
}
|
|
22065
22224
|
|
|
22066
22225
|
// adapters/next/init/scaffolders/api-routes.ts
|
|
22067
22226
|
function scaffoldApiRoutes({ cwd, config }) {
|
|
22068
22227
|
const created = [];
|
|
22069
|
-
const apiDir =
|
|
22228
|
+
const apiDir = path34.resolve(cwd, config.paths.api);
|
|
22070
22229
|
const namespace = config.frameworkConfig.next.namespace;
|
|
22071
22230
|
function write(relPath, content) {
|
|
22072
|
-
const fullPath =
|
|
22073
|
-
ensureDir(
|
|
22231
|
+
const fullPath = path34.join(apiDir, relPath);
|
|
22232
|
+
ensureDir(path34.dirname(fullPath));
|
|
22074
22233
|
const versionedContent = applyNextCacheApiForVersion(content, config.nextMajorVersion);
|
|
22075
22234
|
if (safeWriteFile(fullPath, applyAdminNamespaceToContent(versionedContent, namespace))) {
|
|
22076
|
-
created.push(
|
|
22235
|
+
created.push(path34.join(config.paths.api, relPath));
|
|
22077
22236
|
}
|
|
22078
22237
|
}
|
|
22079
|
-
write(
|
|
22080
|
-
write(
|
|
22238
|
+
write(path34.join("auth", "[...all]", "route.ts"), readTemplate("api/auth-route.ts"));
|
|
22239
|
+
write(path34.join("upload", "route.ts"), readTemplate("api/upload-route.ts"));
|
|
22081
22240
|
return created;
|
|
22082
22241
|
}
|
|
22083
22242
|
|
|
22084
22243
|
// adapters/next/init/scaffolders/auth.ts
|
|
22085
|
-
import
|
|
22244
|
+
import path35 from "path";
|
|
22086
22245
|
function scaffoldAuth({ cwd, config }) {
|
|
22087
22246
|
const created = [];
|
|
22088
|
-
const authDir =
|
|
22247
|
+
const authDir = path35.resolve(cwd, config.paths.admin, "lib", "actions", "auth");
|
|
22089
22248
|
const namespace = config.frameworkConfig.next.namespace;
|
|
22090
22249
|
function write(filename, content) {
|
|
22091
22250
|
const outputFile = applyAdminNamespaceToPath(filename, namespace);
|
|
22092
|
-
const fullPath =
|
|
22251
|
+
const fullPath = path35.join(authDir, outputFile);
|
|
22093
22252
|
if (safeWriteFile(fullPath, applyAdminNamespaceToContent(content, namespace))) {
|
|
22094
|
-
created.push(
|
|
22253
|
+
created.push(path35.join(config.paths.admin, "lib", "actions", "auth", outputFile));
|
|
22095
22254
|
}
|
|
22096
22255
|
}
|
|
22097
22256
|
write("server.ts", readTemplate("lib/actions/auth/auth.ts"));
|
|
@@ -22101,7 +22260,7 @@ function scaffoldAuth({ cwd, config }) {
|
|
|
22101
22260
|
}
|
|
22102
22261
|
|
|
22103
22262
|
// adapters/next/init/scaffolders/base.ts
|
|
22104
|
-
import
|
|
22263
|
+
import path36 from "path";
|
|
22105
22264
|
function scaffoldBase({
|
|
22106
22265
|
cwd,
|
|
22107
22266
|
config,
|
|
@@ -22111,58 +22270,58 @@ function scaffoldBase({
|
|
|
22111
22270
|
const adminDirs = [
|
|
22112
22271
|
config.paths.admin,
|
|
22113
22272
|
config.paths.schemas,
|
|
22114
|
-
|
|
22115
|
-
|
|
22116
|
-
|
|
22117
|
-
|
|
22118
|
-
|
|
22119
|
-
|
|
22120
|
-
|
|
22121
|
-
|
|
22122
|
-
|
|
22123
|
-
|
|
22124
|
-
|
|
22125
|
-
|
|
22126
|
-
|
|
22127
|
-
|
|
22128
|
-
|
|
22129
|
-
|
|
22130
|
-
|
|
22131
|
-
|
|
22132
|
-
|
|
22133
|
-
|
|
22134
|
-
|
|
22135
|
-
|
|
22136
|
-
|
|
22137
|
-
|
|
22138
|
-
|
|
22273
|
+
path36.join(config.paths.admin, "lib"),
|
|
22274
|
+
path36.join(config.paths.admin, "lib", "db"),
|
|
22275
|
+
path36.join(config.paths.admin, "lib", "db", "core"),
|
|
22276
|
+
path36.join(config.paths.admin, "lib", "db", "migrations"),
|
|
22277
|
+
path36.join(config.paths.admin, "lib", "actions"),
|
|
22278
|
+
path36.join(config.paths.admin, "lib", "actions", "auth"),
|
|
22279
|
+
path36.join(config.paths.admin, "lib", "actions", "email"),
|
|
22280
|
+
path36.join(config.paths.admin, "lib", "actions", "forms"),
|
|
22281
|
+
path36.join(config.paths.admin, "lib", "actions", "media"),
|
|
22282
|
+
path36.join(config.paths.admin, "lib", "actions", "profile"),
|
|
22283
|
+
path36.join(config.paths.admin, "lib", "actions", "storage"),
|
|
22284
|
+
path36.join(config.paths.admin, "lib", "actions", "upload"),
|
|
22285
|
+
path36.join(config.paths.admin, "lib", "actions", "users"),
|
|
22286
|
+
path36.join(config.paths.admin, "hooks"),
|
|
22287
|
+
path36.join(config.paths.admin, "components", "ui"),
|
|
22288
|
+
path36.join(config.paths.admin, "components", "custom"),
|
|
22289
|
+
path36.join(config.paths.admin, "components", "layouts"),
|
|
22290
|
+
path36.join(config.paths.admin, "components", "shared"),
|
|
22291
|
+
path36.join(config.paths.admin, "components", "shared", "data-table"),
|
|
22292
|
+
path36.join(config.paths.admin, "components", "shared", "media"),
|
|
22293
|
+
path36.join(config.paths.admin, "data"),
|
|
22294
|
+
path36.join(config.paths.admin, "data", "navigation"),
|
|
22295
|
+
path36.join(config.paths.admin, "types"),
|
|
22296
|
+
path36.join(config.paths.admin, "utils"),
|
|
22297
|
+
path36.join(config.paths.admin, "utils", "core")
|
|
22139
22298
|
];
|
|
22140
22299
|
if (includeEmailTemplatesDir) {
|
|
22141
|
-
adminDirs.push(
|
|
22300
|
+
adminDirs.push(path36.join(config.paths.admin, "components", "email-templates"));
|
|
22142
22301
|
}
|
|
22143
22302
|
for (const dir of adminDirs) {
|
|
22144
|
-
ensureDir(
|
|
22303
|
+
ensureDir(path36.resolve(cwd, dir));
|
|
22145
22304
|
}
|
|
22146
|
-
const adminDir =
|
|
22305
|
+
const adminDir = path36.dirname(config.paths.pages);
|
|
22147
22306
|
const appDirs = [
|
|
22148
22307
|
config.paths.pages,
|
|
22149
22308
|
config.paths.login,
|
|
22150
22309
|
config.paths.api,
|
|
22151
|
-
|
|
22310
|
+
path36.join(adminDir, "(account)", "profile")
|
|
22152
22311
|
];
|
|
22153
22312
|
for (const dir of appDirs) {
|
|
22154
|
-
ensureDir(
|
|
22313
|
+
ensureDir(path36.resolve(cwd, dir));
|
|
22155
22314
|
}
|
|
22156
22315
|
const configContent = serializeConfig(config);
|
|
22157
|
-
if (safeWriteFile(
|
|
22316
|
+
if (safeWriteFile(path36.resolve(cwd, "admin.config.ts"), configContent)) {
|
|
22158
22317
|
created.push("admin.config.ts");
|
|
22159
22318
|
}
|
|
22160
22319
|
return created;
|
|
22161
22320
|
}
|
|
22162
22321
|
|
|
22163
22322
|
// adapters/next/init/scaffolders/biome.ts
|
|
22164
|
-
import
|
|
22165
|
-
import
|
|
22323
|
+
import fs28 from "fs";
|
|
22324
|
+
import path37 from "path";
|
|
22166
22325
|
function scaffoldBiome(cwd, linter) {
|
|
22167
22326
|
if (linter.type !== "none") {
|
|
22168
22327
|
return {
|
|
@@ -22170,8 +22329,8 @@ function scaffoldBiome(cwd, linter) {
|
|
|
22170
22329
|
skippedReason: `${linter.type} already configured (${linter.configFile})`
|
|
22171
22330
|
};
|
|
22172
22331
|
}
|
|
22173
|
-
const configPath =
|
|
22174
|
-
if (
|
|
22332
|
+
const configPath = path37.join(cwd, "biome.json");
|
|
22333
|
+
if (fs28.existsSync(configPath)) {
|
|
22175
22334
|
return { installed: false, skippedReason: "biome.json already exists" };
|
|
22176
22335
|
}
|
|
22177
22336
|
const config = {
|
|
@@ -22234,13 +22393,13 @@ function scaffoldBiome(cwd, linter) {
|
|
|
22234
22393
|
]
|
|
22235
22394
|
}
|
|
22236
22395
|
};
|
|
22237
|
-
|
|
22396
|
+
fs28.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}
|
|
22238
22397
|
`, "utf-8");
|
|
22239
22398
|
return { installed: true, skippedReason: null };
|
|
22240
22399
|
}
|
|
22241
22400
|
|
|
22242
22401
|
// adapters/next/init/scaffolders/components.ts
|
|
22243
|
-
import
|
|
22402
|
+
import path38 from "path";
|
|
22244
22403
|
|
|
22245
22404
|
// adapters/next/init/templates/app/admin.ts
|
|
22246
22405
|
function adminDataTemplate(projectName, namespaceValue = DEFAULT_ADMIN_NAMESPACE) {
|
|
@@ -22252,17 +22411,17 @@ function adminDataTemplate(projectName, namespaceValue = DEFAULT_ADMIN_NAMESPACE
|
|
|
22252
22411
|
}
|
|
22253
22412
|
|
|
22254
22413
|
// adapters/next/init/scaffolders/components.ts
|
|
22255
|
-
import
|
|
22414
|
+
import fs29 from "fs-extra";
|
|
22256
22415
|
function scaffoldComponents({ cwd, config }) {
|
|
22257
|
-
const admin =
|
|
22416
|
+
const admin = path38.resolve(cwd, config.paths.admin);
|
|
22258
22417
|
const created = [];
|
|
22259
22418
|
const namespace = config.frameworkConfig.next.namespace;
|
|
22260
22419
|
function write(relPath, content) {
|
|
22261
22420
|
const namespacedRelPath = applyAdminNamespaceToPath(relPath, namespace);
|
|
22262
|
-
const fullPath =
|
|
22421
|
+
const fullPath = path38.join(admin, namespacedRelPath);
|
|
22263
22422
|
const versionedContent = applyNextCacheApiForVersion(content, config.nextMajorVersion);
|
|
22264
22423
|
if (safeWriteFile(fullPath, applyAdminNamespaceToContent(versionedContent, namespace))) {
|
|
22265
|
-
created.push(
|
|
22424
|
+
created.push(path38.join(config.paths.admin, namespacedRelPath));
|
|
22266
22425
|
}
|
|
22267
22426
|
}
|
|
22268
22427
|
write("admin-globals.css", readTemplate("admin-globals.css"));
|
|
@@ -22695,49 +22854,49 @@ function copyCustomTemplates(cwd, config) {
|
|
|
22695
22854
|
}
|
|
22696
22855
|
function copyStaticComponentTemplates(cwd, config, sourceDirectory, targetDirectory) {
|
|
22697
22856
|
const created = [];
|
|
22698
|
-
const destDir =
|
|
22857
|
+
const destDir = path38.resolve(cwd, config.paths.admin, "components", targetDirectory);
|
|
22699
22858
|
const srcDir = resolveCliAssetPath("shared-assets", "react-admin", sourceDirectory);
|
|
22700
|
-
if (!
|
|
22859
|
+
if (!fs29.existsSync(srcDir)) {
|
|
22701
22860
|
return created;
|
|
22702
22861
|
}
|
|
22703
|
-
|
|
22862
|
+
fs29.ensureDirSync(destDir);
|
|
22704
22863
|
if (sourceDirectory === "custom") {
|
|
22705
22864
|
copyStaticComponentTemplatesRecursive(
|
|
22706
22865
|
srcDir,
|
|
22707
22866
|
destDir,
|
|
22708
22867
|
"",
|
|
22709
|
-
|
|
22868
|
+
path38.join(config.paths.admin, "components", targetDirectory),
|
|
22710
22869
|
config.frameworkConfig.next.namespace,
|
|
22711
22870
|
created
|
|
22712
22871
|
);
|
|
22713
22872
|
return created;
|
|
22714
22873
|
}
|
|
22715
|
-
const files =
|
|
22874
|
+
const files = fs29.readdirSync(srcDir, { withFileTypes: true }).filter(
|
|
22716
22875
|
(entry) => entry.isFile() && (entry.name.endsWith(".tsx") || entry.name.endsWith(".ts"))
|
|
22717
22876
|
).map((entry) => entry.name);
|
|
22718
22877
|
for (const file of files) {
|
|
22719
22878
|
const namespacedFile = applyAdminNamespaceToPath(file, config.frameworkConfig.next.namespace);
|
|
22720
|
-
const destPath =
|
|
22721
|
-
if (!
|
|
22722
|
-
const content =
|
|
22723
|
-
|
|
22879
|
+
const destPath = path38.join(destDir, namespacedFile);
|
|
22880
|
+
if (!fs29.existsSync(destPath)) {
|
|
22881
|
+
const content = fs29.readFileSync(path38.join(srcDir, file), "utf-8");
|
|
22882
|
+
fs29.writeFileSync(
|
|
22724
22883
|
destPath,
|
|
22725
22884
|
applyAdminNamespaceToContent(content, config.frameworkConfig.next.namespace),
|
|
22726
22885
|
"utf-8"
|
|
22727
22886
|
);
|
|
22728
|
-
created.push(
|
|
22887
|
+
created.push(path38.join(config.paths.admin, "components", targetDirectory, namespacedFile));
|
|
22729
22888
|
}
|
|
22730
22889
|
}
|
|
22731
22890
|
return created;
|
|
22732
22891
|
}
|
|
22733
22892
|
function copyStaticComponentTemplatesRecursive(srcDir, destDir, relBase, createdPrefix, namespace, created) {
|
|
22734
|
-
const entries =
|
|
22893
|
+
const entries = fs29.readdirSync(srcDir, { withFileTypes: true });
|
|
22735
22894
|
for (const entry of entries) {
|
|
22736
|
-
const rel =
|
|
22737
|
-
const srcPath =
|
|
22738
|
-
const destPath =
|
|
22895
|
+
const rel = path38.join(relBase, entry.name);
|
|
22896
|
+
const srcPath = path38.join(srcDir, entry.name);
|
|
22897
|
+
const destPath = path38.join(destDir, entry.name);
|
|
22739
22898
|
if (entry.isDirectory()) {
|
|
22740
|
-
const namespacedDestPath2 =
|
|
22899
|
+
const namespacedDestPath2 = path38.join(
|
|
22741
22900
|
destDir,
|
|
22742
22901
|
applyAdminNamespaceToPath(entry.name, namespace)
|
|
22743
22902
|
);
|
|
@@ -22755,37 +22914,37 @@ function copyStaticComponentTemplatesRecursive(srcDir, destDir, relBase, created
|
|
|
22755
22914
|
continue;
|
|
22756
22915
|
}
|
|
22757
22916
|
const namespacedRel = applyAdminNamespaceToPath(rel, namespace);
|
|
22758
|
-
const namespacedDestPath =
|
|
22759
|
-
|
|
22917
|
+
const namespacedDestPath = path38.join(
|
|
22918
|
+
path38.dirname(destPath),
|
|
22760
22919
|
applyAdminNamespaceToPath(entry.name, namespace)
|
|
22761
22920
|
);
|
|
22762
|
-
if (!
|
|
22763
|
-
|
|
22764
|
-
const content =
|
|
22765
|
-
|
|
22921
|
+
if (!fs29.existsSync(namespacedDestPath)) {
|
|
22922
|
+
fs29.ensureDirSync(path38.dirname(namespacedDestPath));
|
|
22923
|
+
const content = fs29.readFileSync(srcPath, "utf-8");
|
|
22924
|
+
fs29.writeFileSync(
|
|
22766
22925
|
namespacedDestPath,
|
|
22767
22926
|
applyAdminNamespaceToContent(content, namespace),
|
|
22768
22927
|
"utf-8"
|
|
22769
22928
|
);
|
|
22770
|
-
created.push(
|
|
22929
|
+
created.push(path38.join(createdPrefix, namespacedRel));
|
|
22771
22930
|
}
|
|
22772
22931
|
}
|
|
22773
22932
|
}
|
|
22774
22933
|
function copySchemaMetaschema(cwd, config) {
|
|
22775
22934
|
const created = [];
|
|
22776
22935
|
const srcPath = resolveCliAssetPath("shared-assets", "react-admin", "schema.json");
|
|
22777
|
-
const destPath =
|
|
22778
|
-
if (
|
|
22779
|
-
|
|
22780
|
-
|
|
22781
|
-
created.push(
|
|
22936
|
+
const destPath = path38.resolve(cwd, config.paths.schemas, "schema.json");
|
|
22937
|
+
if (fs29.existsSync(srcPath) && !fs29.existsSync(destPath)) {
|
|
22938
|
+
fs29.ensureDirSync(path38.dirname(destPath));
|
|
22939
|
+
fs29.copyFileSync(srcPath, destPath);
|
|
22940
|
+
created.push(path38.join(config.paths.schemas, "schema.json"));
|
|
22782
22941
|
}
|
|
22783
22942
|
return created;
|
|
22784
22943
|
}
|
|
22785
22944
|
|
|
22786
22945
|
// adapters/next/init/scaffolders/core-schemas.ts
|
|
22787
|
-
import
|
|
22788
|
-
import
|
|
22946
|
+
import fs30 from "fs";
|
|
22947
|
+
import path39 from "path";
|
|
22789
22948
|
|
|
22790
22949
|
// adapters/next/init/templates/core/default-settings.ts
|
|
22791
22950
|
function defaultSettingsSchema() {
|
|
@@ -22865,9 +23024,9 @@ function scaffoldCoreSchemas({
|
|
|
22865
23024
|
};
|
|
22866
23025
|
const schemaContent = defaultSettingsSchema();
|
|
22867
23026
|
const schemaName = "settings";
|
|
22868
|
-
const schemaPath =
|
|
22869
|
-
|
|
22870
|
-
|
|
23027
|
+
const schemaPath = path39.join(cwd, config.paths.schemas, `${schemaName}.json`);
|
|
23028
|
+
fs30.mkdirSync(path39.dirname(schemaPath), { recursive: true });
|
|
23029
|
+
fs30.writeFileSync(schemaPath, schemaContent, "utf-8");
|
|
22871
23030
|
result.schemas.push(`${schemaName}.json`);
|
|
22872
23031
|
ensureSnapshotGitFiles(cwd);
|
|
22873
23032
|
try {
|
|
@@ -22912,21 +23071,21 @@ function scaffoldCoreSchemas({
|
|
|
22912
23071
|
}
|
|
22913
23072
|
|
|
22914
23073
|
// adapters/next/init/scaffolders/database.ts
|
|
22915
|
-
import
|
|
23074
|
+
import path40 from "path";
|
|
22916
23075
|
function scaffoldDatabase({ cwd, config }) {
|
|
22917
23076
|
const created = [];
|
|
22918
|
-
const dbDir =
|
|
23077
|
+
const dbDir = path40.resolve(cwd, config.paths.admin, "lib", "db");
|
|
22919
23078
|
const namespace = config.frameworkConfig.next.namespace;
|
|
22920
23079
|
function write(filename, content) {
|
|
22921
|
-
const fullPath =
|
|
23080
|
+
const fullPath = path40.join(dbDir, filename);
|
|
22922
23081
|
if (safeWriteFile(fullPath, applyAdminNamespaceToContent(content, namespace))) {
|
|
22923
|
-
created.push(
|
|
23082
|
+
created.push(path40.join(config.paths.admin, "lib", "db", filename));
|
|
22924
23083
|
}
|
|
22925
23084
|
}
|
|
22926
23085
|
write("client.ts", readTemplate("lib/db/client.ts"));
|
|
22927
23086
|
write("core/schema.ts", readTemplate("lib/db/core/schema.ts"));
|
|
22928
23087
|
write("schema.ts", readTemplate("lib/db/schema.ts"));
|
|
22929
|
-
const drizzleConfigPath =
|
|
23088
|
+
const drizzleConfigPath = path40.resolve(cwd, "drizzle.config.ts");
|
|
22930
23089
|
if (safeWriteFile(
|
|
22931
23090
|
drizzleConfigPath,
|
|
22932
23091
|
applyAdminNamespaceToContent(readTemplate("drizzle.config.ts"), namespace)
|
|
@@ -22936,139 +23095,6 @@ function scaffoldDatabase({ cwd, config }) {
|
|
|
22936
23095
|
return created;
|
|
22937
23096
|
}
|
|
22938
23097
|
|
|
22939
|
-
// adapters/next/init/scaffolders/dev-server.ts
|
|
22940
|
-
import fs30 from "fs";
|
|
22941
|
-
import path40 from "path";
|
|
22942
|
-
var DEFAULT_DEV_PORT = 4242;
|
|
22943
|
-
var DEV_PORT_FLAG_PATTERN = /(?:^|\s)(?:--port(?:=|\s+)|-p(?:=|\s+)?)(\d+)(?=\s|$)/;
|
|
22944
|
-
var DEV_PORT_ENV_PATTERN = /(?:^|\s)PORT=(\d+)(?=\s|$)/;
|
|
22945
|
-
function detectDevPort(cwd) {
|
|
22946
|
-
const pkg = readPackageJson2(cwd);
|
|
22947
|
-
if (!pkg) return DEFAULT_DEV_PORT;
|
|
22948
|
-
return detectDevPortFromScript(pkg.scripts?.dev) ?? DEFAULT_DEV_PORT;
|
|
22949
|
-
}
|
|
22950
|
-
function detectDevPortFromScript(devScript) {
|
|
22951
|
-
if (typeof devScript !== "string") return void 0;
|
|
22952
|
-
const trimmed = devScript.trim();
|
|
22953
|
-
if (trimmed.length === 0) return void 0;
|
|
22954
|
-
const flagMatch = trimmed.match(DEV_PORT_FLAG_PATTERN);
|
|
22955
|
-
const envMatch = trimmed.match(DEV_PORT_ENV_PATTERN);
|
|
22956
|
-
const rawPort = flagMatch?.[1] ?? envMatch?.[1];
|
|
22957
|
-
if (!rawPort) return void 0;
|
|
22958
|
-
const port = Number.parseInt(rawPort, 10);
|
|
22959
|
-
return isValidPort(port) ? port : void 0;
|
|
22960
|
-
}
|
|
22961
|
-
function ensureDefaultDevScriptPort(cwd) {
|
|
22962
|
-
const pkgPath = path40.join(cwd, "package.json");
|
|
22963
|
-
if (!fs30.existsSync(pkgPath)) {
|
|
22964
|
-
return { status: "missing-package", port: DEFAULT_DEV_PORT };
|
|
22965
|
-
}
|
|
22966
|
-
const raw = fs30.readFileSync(pkgPath, "utf-8");
|
|
22967
|
-
let pkg;
|
|
22968
|
-
try {
|
|
22969
|
-
pkg = JSON.parse(raw);
|
|
22970
|
-
} catch {
|
|
22971
|
-
return { status: "missing-package", port: DEFAULT_DEV_PORT };
|
|
22972
|
-
}
|
|
22973
|
-
const devScript = pkg.scripts?.dev;
|
|
22974
|
-
if (typeof devScript !== "string" || devScript.trim().length === 0) {
|
|
22975
|
-
return { status: "missing-script", port: DEFAULT_DEV_PORT };
|
|
22976
|
-
}
|
|
22977
|
-
const explicitPort = detectDevPortFromScript(devScript);
|
|
22978
|
-
if (explicitPort) {
|
|
22979
|
-
return { status: "preserved", port: explicitPort };
|
|
22980
|
-
}
|
|
22981
|
-
if (!isPlainNextDevScript(devScript)) {
|
|
22982
|
-
return { status: "skipped", port: DEFAULT_DEV_PORT };
|
|
22983
|
-
}
|
|
22984
|
-
const normalizedScript = `${normalizeWhitespace(devScript)} --port ${DEFAULT_DEV_PORT}`;
|
|
22985
|
-
pkg.scripts = {
|
|
22986
|
-
...pkg.scripts,
|
|
22987
|
-
dev: normalizedScript
|
|
22988
|
-
};
|
|
22989
|
-
const newline = raw.includes("\r\n") ? "\r\n" : "\n";
|
|
22990
|
-
const indent = detectIndent(raw);
|
|
22991
|
-
fs30.writeFileSync(pkgPath, `${JSON.stringify(pkg, null, indent)}${newline}`, "utf-8");
|
|
22992
|
-
return { status: "updated", port: DEFAULT_DEV_PORT };
|
|
22993
|
-
}
|
|
22994
|
-
function readPackageJson2(cwd) {
|
|
22995
|
-
const pkgPath = path40.join(cwd, "package.json");
|
|
22996
|
-
if (!fs30.existsSync(pkgPath)) return void 0;
|
|
22997
|
-
try {
|
|
22998
|
-
return JSON.parse(fs30.readFileSync(pkgPath, "utf-8"));
|
|
22999
|
-
} catch {
|
|
23000
|
-
return void 0;
|
|
23001
|
-
}
|
|
23002
|
-
}
|
|
23003
|
-
function isPlainNextDevScript(devScript) {
|
|
23004
|
-
const normalized = normalizeWhitespace(devScript);
|
|
23005
|
-
return normalized === "next dev" || normalized === "next dev --turbopack" || normalized === "next dev --turbo";
|
|
23006
|
-
}
|
|
23007
|
-
function normalizeWhitespace(value) {
|
|
23008
|
-
return value.trim().replace(/\s+/g, " ");
|
|
23009
|
-
}
|
|
23010
|
-
function detectIndent(raw) {
|
|
23011
|
-
const indentMatch = raw.match(/^[ \t]+(?=")/m);
|
|
23012
|
-
return indentMatch?.[0] ?? 2;
|
|
23013
|
-
}
|
|
23014
|
-
function isValidPort(port) {
|
|
23015
|
-
return Number.isInteger(port) && port > 0 && port <= 65535;
|
|
23016
|
-
}
|
|
23017
|
-
|
|
23018
|
-
// adapters/next/init/scaffolders/env.ts
|
|
23019
|
-
import crypto2 from "crypto";
|
|
23020
|
-
var LEGACY_DEFAULT_AUTH_URL = "http://localhost:3000";
|
|
23021
|
-
function getCoreEnvSections(databaseUrl, devPort, namespace) {
|
|
23022
|
-
const authSecret = crypto2.randomBytes(32).toString("base64");
|
|
23023
|
-
return [
|
|
23024
|
-
{
|
|
23025
|
-
header: "Database (PostgreSQL)",
|
|
23026
|
-
vars: [{ key: "DATABASE_URL", value: databaseUrl ?? "postgresql://..." }]
|
|
23027
|
-
},
|
|
23028
|
-
{
|
|
23029
|
-
header: "Authentication",
|
|
23030
|
-
vars: [
|
|
23031
|
-
{ key: "BETTERSTART_AUTH_SECRET", value: authSecret },
|
|
23032
|
-
{ key: "BETTERSTART_AUTH_URL", value: `http://localhost:${devPort}` },
|
|
23033
|
-
{ key: "BETTERSTART_AUTH_BASE_PATH", value: `/api/${namespace}/auth` }
|
|
23034
|
-
]
|
|
23035
|
-
}
|
|
23036
|
-
];
|
|
23037
|
-
}
|
|
23038
|
-
function shouldOverwriteAuthUrl(cwd, devPort) {
|
|
23039
|
-
const existingAuthUrl = readEnvVar(cwd, "BETTERSTART_AUTH_URL");
|
|
23040
|
-
if (!existingAuthUrl) return false;
|
|
23041
|
-
return existingAuthUrl === LEGACY_DEFAULT_AUTH_URL && existingAuthUrl !== `http://localhost:${devPort}`;
|
|
23042
|
-
}
|
|
23043
|
-
function persistDatabaseUrl(cwd, databaseUrl) {
|
|
23044
|
-
appendEnvVars(
|
|
23045
|
-
cwd,
|
|
23046
|
-
[
|
|
23047
|
-
{
|
|
23048
|
-
header: "Database (PostgreSQL)",
|
|
23049
|
-
vars: [{ key: "DATABASE_URL", value: databaseUrl }]
|
|
23050
|
-
}
|
|
23051
|
-
],
|
|
23052
|
-
/* @__PURE__ */ new Set(["DATABASE_URL"])
|
|
23053
|
-
);
|
|
23054
|
-
}
|
|
23055
|
-
function scaffoldEnv(cwd, options) {
|
|
23056
|
-
const devPort = detectDevPort(cwd);
|
|
23057
|
-
const sections = getCoreEnvSections(options.databaseUrl, devPort, options.namespace ?? "admin");
|
|
23058
|
-
const authBasePath = `/api/${options.namespace ?? "admin"}/auth`;
|
|
23059
|
-
const overwrite = /* @__PURE__ */ new Set();
|
|
23060
|
-
if (options.databaseUrl) {
|
|
23061
|
-
overwrite.add("DATABASE_URL");
|
|
23062
|
-
}
|
|
23063
|
-
if (shouldOverwriteAuthUrl(cwd, devPort)) {
|
|
23064
|
-
overwrite.add("BETTERSTART_AUTH_URL");
|
|
23065
|
-
}
|
|
23066
|
-
if (readEnvVar(cwd, "BETTERSTART_AUTH_BASE_PATH") !== authBasePath) {
|
|
23067
|
-
overwrite.add("BETTERSTART_AUTH_BASE_PATH");
|
|
23068
|
-
}
|
|
23069
|
-
return appendEnvVars(cwd, sections, overwrite);
|
|
23070
|
-
}
|
|
23071
|
-
|
|
23072
23098
|
// adapters/next/init/scaffolders/layout.ts
|
|
23073
23099
|
import path41 from "path";
|
|
23074
23100
|
function scaffoldLayout({ cwd, config }) {
|
|
@@ -24217,10 +24243,10 @@ async function ensureVercelAuth(runner, cwd, options) {
|
|
|
24217
24243
|
if (existing.authed) {
|
|
24218
24244
|
if (options.quietIfAuthed) {
|
|
24219
24245
|
checkSpinner.clear();
|
|
24220
|
-
|
|
24221
|
-
checkSpinner.stop(signedInMessage(existing.username));
|
|
24246
|
+
return existing;
|
|
24222
24247
|
}
|
|
24223
|
-
|
|
24248
|
+
checkSpinner.stop(signedInMessage(existing.username));
|
|
24249
|
+
return { ...existing, dismissNote: eraseClackLine };
|
|
24224
24250
|
}
|
|
24225
24251
|
if (env.VERCEL_TOKEN) {
|
|
24226
24252
|
checkSpinner.stop("Could not verify VERCEL_TOKEN with Vercel");
|
|
@@ -24245,7 +24271,7 @@ async function ensureVercelAuth(runner, cwd, options) {
|
|
|
24245
24271
|
const after = await checkVercelAuth(runner, cwd, env);
|
|
24246
24272
|
if (after.authed) {
|
|
24247
24273
|
verifySpinner.stop(signedInMessage(after.username));
|
|
24248
|
-
return after;
|
|
24274
|
+
return { ...after, dismissNote: eraseClackLine };
|
|
24249
24275
|
}
|
|
24250
24276
|
verifySpinner.stop("Could not verify your Vercel sign-in");
|
|
24251
24277
|
return { authed: false, reason: "login-failed" };
|
|
@@ -24692,7 +24718,7 @@ async function provisionNeonInteractive(runner, cwd, options) {
|
|
|
24692
24718
|
if (!add.success) {
|
|
24693
24719
|
return { failure: add.timedOut ? "timeout" : "provision-failed" };
|
|
24694
24720
|
}
|
|
24695
|
-
return {};
|
|
24721
|
+
return { usedTerminalFallback: true };
|
|
24696
24722
|
}
|
|
24697
24723
|
async function provisionNeon(runner, cwd, options) {
|
|
24698
24724
|
const provisionSpinner = spinner2();
|
|
@@ -24755,7 +24781,7 @@ async function runVercelNeonFlow(options) {
|
|
|
24755
24781
|
p16.log.warn(authFailureMessage(auth.reason));
|
|
24756
24782
|
return { ok: false };
|
|
24757
24783
|
}
|
|
24758
|
-
await ensureLinkedProject(runner, options.cwd, options.projectName, env);
|
|
24784
|
+
const linkLinePrinted = await ensureLinkedProject(runner, options.cwd, options.projectName, env);
|
|
24759
24785
|
const neon = await provisionNeonForMode(runner, options);
|
|
24760
24786
|
if (neon.failure) {
|
|
24761
24787
|
p16.log.warn(neonFailureMessage(neon.failure));
|
|
@@ -24763,11 +24789,13 @@ async function runVercelNeonFlow(options) {
|
|
|
24763
24789
|
return { ok: false };
|
|
24764
24790
|
}
|
|
24765
24791
|
const databaseUrl = await pullNeonDatabaseUrl(runner, options.cwd, env);
|
|
24792
|
+
const dismissSignedInNote = databaseUrl && auth.dismissNote && !neon.usedTerminalFallback ? () => auth.dismissNote?.({ linesBelow: linkLinePrinted ? 1 : 0 }) : void 0;
|
|
24766
24793
|
return {
|
|
24767
24794
|
ok: true,
|
|
24768
24795
|
databaseUrl,
|
|
24769
24796
|
dashboardUrl: neon.dashboardUrl,
|
|
24770
|
-
resourceUrl: neon.resourceUrl
|
|
24797
|
+
resourceUrl: neon.resourceUrl,
|
|
24798
|
+
dismissSignedInNote
|
|
24771
24799
|
};
|
|
24772
24800
|
} catch (error) {
|
|
24773
24801
|
p16.log.warn(
|
|
@@ -24881,13 +24909,14 @@ function printManualDeployHint() {
|
|
|
24881
24909
|
p16.log.info(`You can deploy manually: ${pc6.cyan("vercel deploy --prod")}`);
|
|
24882
24910
|
}
|
|
24883
24911
|
async function ensureLinkedProject(runner, cwd, projectName, env) {
|
|
24884
|
-
if (readLinkedProjectId(cwd)) return;
|
|
24912
|
+
if (readLinkedProjectId(cwd)) return false;
|
|
24885
24913
|
const projectSpinner = spinner2();
|
|
24886
24914
|
projectSpinner.start(`Creating a Vercel project ${pc6.cyan(projectName)}`);
|
|
24887
24915
|
const project2 = await createVercelProject(runner, cwd, projectName, env);
|
|
24888
24916
|
projectSpinner.stop(
|
|
24889
24917
|
project2.linked ? `Linked Vercel project ${pc6.cyan(project2.name)}` : `Using Vercel project ${pc6.cyan(project2.name)}`
|
|
24890
24918
|
);
|
|
24919
|
+
return true;
|
|
24891
24920
|
}
|
|
24892
24921
|
async function pullNeonDatabaseUrl(runner, cwd, env) {
|
|
24893
24922
|
const neonSpinner = spinner2();
|
|
@@ -25523,6 +25552,7 @@ async function runInitCommand(name, options) {
|
|
|
25523
25552
|
isFreshProject = true;
|
|
25524
25553
|
}
|
|
25525
25554
|
let databaseUrl;
|
|
25555
|
+
let dismissVercelSignedInNote;
|
|
25526
25556
|
const existingDbUrl = readExistingDbUrl(cwd);
|
|
25527
25557
|
if (options.yes) {
|
|
25528
25558
|
if (options.databaseUrl) {
|
|
@@ -25546,10 +25576,9 @@ async function runInitCommand(name, options) {
|
|
|
25546
25576
|
if (flow.ok && flow.databaseUrl) {
|
|
25547
25577
|
databaseUrl = flow.databaseUrl;
|
|
25548
25578
|
persistDatabaseUrl(cwd, databaseUrl);
|
|
25549
|
-
p17.log.success(`Saved DATABASE_URL to ${pc7.cyan(".env.local")}`);
|
|
25550
25579
|
} else if (flow.ok) {
|
|
25551
25580
|
p17.log.warn("Created a Neon database, but DATABASE_URL could not be retrieved from Vercel.");
|
|
25552
|
-
const resourceUrl = flow.
|
|
25581
|
+
const resourceUrl = flow.dashboardUrl ?? flow.resourceUrl;
|
|
25553
25582
|
if (resourceUrl) {
|
|
25554
25583
|
p17.log.info(
|
|
25555
25584
|
`Open ${pc7.cyan(resourceUrl)} to copy DATABASE_URL, then rerun ${pc7.cyan("betterstart init --database-url <url> --yes")}.`
|
|
@@ -25580,12 +25609,11 @@ async function runInitCommand(name, options) {
|
|
|
25580
25609
|
if (flow.ok && flow.databaseUrl) {
|
|
25581
25610
|
databaseUrl = flow.databaseUrl;
|
|
25582
25611
|
persistDatabaseUrl(cwd, databaseUrl);
|
|
25583
|
-
|
|
25612
|
+
dismissVercelSignedInNote = flow.dismissSignedInNote;
|
|
25584
25613
|
} else if (flow.ok) {
|
|
25585
|
-
openBrowserVercelNeonResource(flow.
|
|
25614
|
+
openBrowserVercelNeonResource(flow.dashboardUrl ?? flow.resourceUrl);
|
|
25586
25615
|
databaseUrl = await promptConnectionString();
|
|
25587
25616
|
persistDatabaseUrl(cwd, databaseUrl);
|
|
25588
|
-
p17.log.success(`Saved DATABASE_URL to ${pc7.cyan(".env.local")}`);
|
|
25589
25617
|
} else {
|
|
25590
25618
|
p17.log.info("Falling back to a manual database connection string.");
|
|
25591
25619
|
openBrowserVercelNeon();
|
|
@@ -25627,6 +25655,8 @@ async function runInitCommand(name, options) {
|
|
|
25627
25655
|
env: process.env
|
|
25628
25656
|
});
|
|
25629
25657
|
if (flow.ok && flow.token) {
|
|
25658
|
+
persistBlobReadWriteToken(cwd, flow.token);
|
|
25659
|
+
p17.log.success(`Saved BLOB_READ_WRITE_TOKEN to ${pc7.cyan(".env.local")}`);
|
|
25630
25660
|
collectedIntegrationConfig.sections.push({
|
|
25631
25661
|
header: "Storage (Vercel Blob)",
|
|
25632
25662
|
vars: [{ key: "BLOB_READ_WRITE_TOKEN", value: flow.token }]
|
|
@@ -25646,6 +25676,7 @@ async function runInitCommand(name, options) {
|
|
|
25646
25676
|
} else if (options.yes) {
|
|
25647
25677
|
pluginSelection = { plugins: [], integrations: [], storage: "local" };
|
|
25648
25678
|
} else {
|
|
25679
|
+
dismissVercelSignedInNote?.();
|
|
25649
25680
|
const promptResult = await promptPlugins(cwd, {
|
|
25650
25681
|
provisionVercelBlob: vercelBlobAllowed ? () => runVercelBlobFlow({ cwd, projectName, interactive: true, env: process.env }) : void 0
|
|
25651
25682
|
});
|
|
@@ -25828,8 +25859,9 @@ async function runInitCommand(name, options) {
|
|
|
25828
25859
|
config: resolvedPluginInstallResult.config,
|
|
25829
25860
|
pm,
|
|
25830
25861
|
integrationIds: pluginSelection.integrations,
|
|
25831
|
-
// Secrets were already collected up front and written to
|
|
25832
|
-
// so the install runs without prompting (rule: no
|
|
25862
|
+
// Secrets were already collected up front and persisted/written to
|
|
25863
|
+
// .env.local, so the install runs without prompting (rule: no
|
|
25864
|
+
// mid-scaffold input).
|
|
25833
25865
|
interactive: false,
|
|
25834
25866
|
includeBiome: project2.linter.type === "none"
|
|
25835
25867
|
});
|