betterstart-cli 0.0.25 → 0.0.26
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 +209 -146
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -5283,14 +5283,14 @@ function buildStepsConstant(steps) {
|
|
|
5283
5283
|
${entries.join(",\n")}
|
|
5284
5284
|
]`;
|
|
5285
5285
|
}
|
|
5286
|
-
function buildComponentSource(
|
|
5286
|
+
function buildComponentSource(p20) {
|
|
5287
5287
|
const providerOpen = ` <NuqsAdapter>
|
|
5288
5288
|
<React.Suspense fallback={null}>
|
|
5289
|
-
<${
|
|
5289
|
+
<${p20.pascal}FormInner />
|
|
5290
5290
|
</React.Suspense>
|
|
5291
5291
|
</NuqsAdapter>`;
|
|
5292
5292
|
const exportWrapper = `
|
|
5293
|
-
export function ${
|
|
5293
|
+
export function ${p20.pascal}Form() {
|
|
5294
5294
|
return (
|
|
5295
5295
|
${providerOpen}
|
|
5296
5296
|
)
|
|
@@ -5299,22 +5299,22 @@ ${providerOpen}
|
|
|
5299
5299
|
return `'use client'
|
|
5300
5300
|
|
|
5301
5301
|
import { standardSchemaResolver } from '@hookform/resolvers/standard-schema'
|
|
5302
|
-
import { ChevronLeft, ChevronRight${
|
|
5302
|
+
import { ChevronLeft, ChevronRight${p20.hasListFields ? ", Trash2" : ""} } from 'lucide-react'
|
|
5303
5303
|
import { createParser, useQueryState } from 'nuqs'
|
|
5304
5304
|
import { NuqsAdapter } from 'nuqs/adapters/next/app'
|
|
5305
5305
|
import * as React from 'react'
|
|
5306
|
-
${
|
|
5306
|
+
${p20.rhfImport}
|
|
5307
5307
|
import { z } from 'zod/v3'
|
|
5308
|
-
import { create${
|
|
5308
|
+
import { create${p20.pascal}Submission } from '@admin/actions/${p20.actionImportPath}'
|
|
5309
5309
|
|
|
5310
5310
|
const formSchema = z.object({
|
|
5311
|
-
${
|
|
5311
|
+
${p20.zodFields}
|
|
5312
5312
|
})
|
|
5313
5313
|
|
|
5314
5314
|
type FormValues = z.infer<typeof formSchema>
|
|
5315
5315
|
${buildFieldErrorHelper()}
|
|
5316
5316
|
|
|
5317
|
-
${
|
|
5317
|
+
${p20.stepsConst}
|
|
5318
5318
|
|
|
5319
5319
|
const stepParser = createParser({
|
|
5320
5320
|
parse(value) {
|
|
@@ -5332,7 +5332,7 @@ const stepParser = createParser({
|
|
|
5332
5332
|
}
|
|
5333
5333
|
}).withDefault(0)
|
|
5334
5334
|
|
|
5335
|
-
function ${
|
|
5335
|
+
function ${p20.pascal}FormInner() {
|
|
5336
5336
|
const [currentStep, setCurrentStep] = useQueryState('step', stepParser)
|
|
5337
5337
|
const [submitted, setSubmitted] = React.useState(false)
|
|
5338
5338
|
const [submitting, startSubmitTransition] = React.useTransition()
|
|
@@ -5340,11 +5340,11 @@ function ${p19.pascal}FormInner() {
|
|
|
5340
5340
|
const form = useForm<FormValues>({
|
|
5341
5341
|
resolver: standardSchemaResolver(formSchema),
|
|
5342
5342
|
defaultValues: {
|
|
5343
|
-
${
|
|
5343
|
+
${p20.defaults}
|
|
5344
5344
|
},
|
|
5345
5345
|
})
|
|
5346
5346
|
|
|
5347
|
-
${
|
|
5347
|
+
${p20.fieldArraySetup}${p20.watchSetup}
|
|
5348
5348
|
async function handleNext() {
|
|
5349
5349
|
const stepFields = STEPS[currentStep].fields as (keyof FormValues)[]
|
|
5350
5350
|
const isValid = await form.trigger(stepFields, { shouldFocus: true })
|
|
@@ -5360,9 +5360,9 @@ ${p19.fieldArraySetup}${p19.watchSetup}
|
|
|
5360
5360
|
function onSubmit(values: FormValues) {
|
|
5361
5361
|
startSubmitTransition(async () => {
|
|
5362
5362
|
try {
|
|
5363
|
-
const result = await create${
|
|
5363
|
+
const result = await create${p20.pascal}Submission(values)
|
|
5364
5364
|
if (result.success) {
|
|
5365
|
-
${
|
|
5365
|
+
${p20.successHandler}
|
|
5366
5366
|
} else {
|
|
5367
5367
|
form.setError('root', { message: result.error || 'Something went wrong' })
|
|
5368
5368
|
}
|
|
@@ -5376,7 +5376,7 @@ ${p19.fieldArraySetup}${p19.watchSetup}
|
|
|
5376
5376
|
return (
|
|
5377
5377
|
<div className="rounded-sm border p-6 text-center">
|
|
5378
5378
|
<h3 className="text-lg font-semibold">Thank you!</h3>
|
|
5379
|
-
<p className="mt-2 text-muted-foreground">${
|
|
5379
|
+
<p className="mt-2 text-muted-foreground">${p20.successMessage}</p>
|
|
5380
5380
|
</div>
|
|
5381
5381
|
)
|
|
5382
5382
|
}
|
|
@@ -5393,7 +5393,7 @@ ${p19.fieldArraySetup}${p19.watchSetup}
|
|
|
5393
5393
|
|
|
5394
5394
|
{/* Step content */}
|
|
5395
5395
|
<div key={currentStep} className="animate-in fade-in duration-300 space-y-6">
|
|
5396
|
-
${
|
|
5396
|
+
${p20.stepContentBlocks}
|
|
5397
5397
|
</div>
|
|
5398
5398
|
|
|
5399
5399
|
{form.formState.errors.root && (
|
|
@@ -5427,7 +5427,7 @@ ${p19.stepContentBlocks}
|
|
|
5427
5427
|
onClick={() => form.handleSubmit(onSubmit)()}
|
|
5428
5428
|
className="inline-flex h-9 items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground shadow-xs transition-colors hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-50"
|
|
5429
5429
|
>
|
|
5430
|
-
{submitting ? 'Submitting...' : ${
|
|
5430
|
+
{submitting ? 'Submitting...' : ${p20.submitText}}
|
|
5431
5431
|
</button>
|
|
5432
5432
|
)}
|
|
5433
5433
|
</div>
|
|
@@ -21743,7 +21743,7 @@ ${validationErrors.map((error) => ` - ${error}`).join("\n")}`
|
|
|
21743
21743
|
import { execFileSync as execFileSync5, spawn as spawn4 } from "child_process";
|
|
21744
21744
|
import fs37 from "fs";
|
|
21745
21745
|
import path48 from "path";
|
|
21746
|
-
import * as
|
|
21746
|
+
import * as p15 from "@clack/prompts";
|
|
21747
21747
|
|
|
21748
21748
|
// adapters/next/init/prompts/database.ts
|
|
21749
21749
|
import { execFileSync as execFileSync4 } from "child_process";
|
|
@@ -23827,7 +23827,7 @@ function scaffoldTsconfig(cwd, config) {
|
|
|
23827
23827
|
}
|
|
23828
23828
|
|
|
23829
23829
|
// adapters/next/init/vercel/flow.ts
|
|
23830
|
-
import * as
|
|
23830
|
+
import * as p14 from "@clack/prompts";
|
|
23831
23831
|
import pc4 from "picocolors";
|
|
23832
23832
|
|
|
23833
23833
|
// adapters/next/init/vercel/auth.ts
|
|
@@ -23956,11 +23956,20 @@ async function checkVercelAuth(runner, cwd, env) {
|
|
|
23956
23956
|
}
|
|
23957
23957
|
async function ensureVercelAuth(runner, cwd, options) {
|
|
23958
23958
|
const env = options.env ?? process.env;
|
|
23959
|
+
const spinner9 = p12.spinner();
|
|
23960
|
+
spinner9.start(
|
|
23961
|
+
runner.source === "npx" ? "Checking Vercel sign-in (first run downloads the Vercel CLI)" : "Checking Vercel sign-in"
|
|
23962
|
+
);
|
|
23959
23963
|
const existing = await checkVercelAuth(runner, cwd, env);
|
|
23960
|
-
if (existing.authed)
|
|
23964
|
+
if (existing.authed) {
|
|
23965
|
+
spinner9.stop(signedInMessage(existing.username));
|
|
23966
|
+
return existing;
|
|
23967
|
+
}
|
|
23961
23968
|
if (env.VERCEL_TOKEN) {
|
|
23969
|
+
spinner9.stop("Could not verify VERCEL_TOKEN with Vercel");
|
|
23962
23970
|
return { authed: false, reason: "login-failed" };
|
|
23963
23971
|
}
|
|
23972
|
+
spinner9.stop("Not signed in to Vercel yet");
|
|
23964
23973
|
p12.log.info(
|
|
23965
23974
|
`Sign in to Vercel to continue \u2014 a browser link and code will appear below. ${pc3.dim(
|
|
23966
23975
|
"(or press Ctrl-C to enter a connection string manually)"
|
|
@@ -23975,14 +23984,25 @@ async function ensureVercelAuth(runner, cwd, options) {
|
|
|
23975
23984
|
if (!login.success) {
|
|
23976
23985
|
return { authed: false, reason: login.timedOut ? "timeout" : "login-cancelled" };
|
|
23977
23986
|
}
|
|
23987
|
+
const verifySpinner = p12.spinner();
|
|
23988
|
+
verifySpinner.start("Verifying Vercel sign-in");
|
|
23978
23989
|
const after = await checkVercelAuth(runner, cwd, env);
|
|
23979
|
-
|
|
23990
|
+
if (after.authed) {
|
|
23991
|
+
verifySpinner.stop(signedInMessage(after.username));
|
|
23992
|
+
return after;
|
|
23993
|
+
}
|
|
23994
|
+
verifySpinner.stop("Could not verify your Vercel sign-in");
|
|
23995
|
+
return { authed: false, reason: "login-failed" };
|
|
23996
|
+
}
|
|
23997
|
+
function signedInMessage(username) {
|
|
23998
|
+
return username ? `Signed in to Vercel as ${pc3.cyan(username)}` : "Signed in to Vercel";
|
|
23980
23999
|
}
|
|
23981
24000
|
|
|
23982
24001
|
// adapters/next/init/vercel/neon.ts
|
|
23983
24002
|
import fs34 from "fs";
|
|
23984
24003
|
import os from "os";
|
|
23985
24004
|
import path45 from "path";
|
|
24005
|
+
import * as p13 from "@clack/prompts";
|
|
23986
24006
|
var PROVISION_TIMEOUT_MS = 18e4;
|
|
23987
24007
|
var INTERACTIVE_PROVISION_TIMEOUT_MS = 6e5;
|
|
23988
24008
|
var ENV_PULL_TIMEOUT_MS = 6e4;
|
|
@@ -23998,13 +24018,21 @@ async function provisionNeonInteractive(runner, cwd, options) {
|
|
|
23998
24018
|
if (!add.success) {
|
|
23999
24019
|
return { failure: add.timedOut ? "timeout" : "provision-failed" };
|
|
24000
24020
|
}
|
|
24021
|
+
const pullSpinner = p13.spinner();
|
|
24022
|
+
pullSpinner.start("Retrieving the database connection string");
|
|
24001
24023
|
const databaseUrl = await pullDatabaseUrl(runner, cwd, options.env);
|
|
24002
|
-
if (!databaseUrl)
|
|
24024
|
+
if (!databaseUrl) {
|
|
24025
|
+
pullSpinner.stop("No DATABASE_URL came back from Vercel");
|
|
24026
|
+
return { failure: "env-pull-empty" };
|
|
24027
|
+
}
|
|
24028
|
+
pullSpinner.stop("Captured the Neon DATABASE_URL");
|
|
24003
24029
|
return { databaseUrl };
|
|
24004
24030
|
}
|
|
24005
24031
|
async function provisionNeon(runner, cwd, options) {
|
|
24006
24032
|
const addArgs = ["integration", "add", "neon", "--no-env-pull", "--format", "json"];
|
|
24007
24033
|
if (options.plan) addArgs.push("--plan", options.plan);
|
|
24034
|
+
const spinner9 = p13.spinner();
|
|
24035
|
+
spinner9.start("Provisioning Neon Postgres via Vercel");
|
|
24008
24036
|
const add = await runVercel(runner, addArgs, {
|
|
24009
24037
|
cwd,
|
|
24010
24038
|
mode: "capture",
|
|
@@ -24012,6 +24040,7 @@ async function provisionNeon(runner, cwd, options) {
|
|
|
24012
24040
|
env: options.env
|
|
24013
24041
|
});
|
|
24014
24042
|
if (!add.success) {
|
|
24043
|
+
spinner9.stop("Neon provisioning did not complete");
|
|
24015
24044
|
const combined = `${add.stdout}
|
|
24016
24045
|
${add.stderr}`.trim();
|
|
24017
24046
|
const detail = combined || void 0;
|
|
@@ -24021,8 +24050,13 @@ ${add.stderr}`.trim();
|
|
|
24021
24050
|
}
|
|
24022
24051
|
const meta = parseVercelJson(add.stdout);
|
|
24023
24052
|
const resourceName = meta?.resourceName ?? meta?.name;
|
|
24053
|
+
spinner9.message("Retrieving the database connection string");
|
|
24024
24054
|
const databaseUrl = await pullDatabaseUrl(runner, cwd, options.env);
|
|
24025
|
-
if (!databaseUrl)
|
|
24055
|
+
if (!databaseUrl) {
|
|
24056
|
+
spinner9.stop("No DATABASE_URL came back from Vercel");
|
|
24057
|
+
return { resourceName, failure: "env-pull-empty" };
|
|
24058
|
+
}
|
|
24059
|
+
spinner9.stop("Captured the Neon DATABASE_URL");
|
|
24026
24060
|
return { databaseUrl, resourceName };
|
|
24027
24061
|
}
|
|
24028
24062
|
async function pullDatabaseUrl(runner, cwd, env) {
|
|
@@ -24073,13 +24107,40 @@ function sanitizeVercelProjectName(name) {
|
|
|
24073
24107
|
const cleaned = name.trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^[-_.]+/, "").replace(/[-_.]+$/, "").slice(0, 100);
|
|
24074
24108
|
return cleaned || "my-app";
|
|
24075
24109
|
}
|
|
24110
|
+
var MAX_NAME_ATTEMPTS = 10;
|
|
24111
|
+
var INSPECT_TIMEOUT_MS = 3e4;
|
|
24112
|
+
function versionedVercelProjectName(base, attempt) {
|
|
24113
|
+
if (attempt <= 1) return base;
|
|
24114
|
+
const suffix = `-v${attempt}`;
|
|
24115
|
+
return `${base.slice(0, 100 - suffix.length)}${suffix}`;
|
|
24116
|
+
}
|
|
24076
24117
|
async function createVercelProject(runner, cwd, name, env) {
|
|
24077
|
-
const
|
|
24078
|
-
|
|
24079
|
-
|
|
24080
|
-
|
|
24081
|
-
|
|
24082
|
-
|
|
24118
|
+
const base = sanitizeVercelProjectName(name);
|
|
24119
|
+
let projectName = base;
|
|
24120
|
+
for (let attempt = 1; attempt <= MAX_NAME_ATTEMPTS; attempt++) {
|
|
24121
|
+
const candidate = versionedVercelProjectName(base, attempt);
|
|
24122
|
+
projectName = candidate;
|
|
24123
|
+
const inspect = await runVercel(runner, ["project", "inspect", candidate], {
|
|
24124
|
+
cwd,
|
|
24125
|
+
mode: "capture",
|
|
24126
|
+
timeoutMs: INSPECT_TIMEOUT_MS,
|
|
24127
|
+
env
|
|
24128
|
+
});
|
|
24129
|
+
if (inspect.success) continue;
|
|
24130
|
+
const add = await runVercel(runner, ["projects", "add", candidate], {
|
|
24131
|
+
cwd,
|
|
24132
|
+
mode: "capture",
|
|
24133
|
+
env
|
|
24134
|
+
});
|
|
24135
|
+
if (add.success) break;
|
|
24136
|
+
if (/already exists/i.test(`${add.stdout}
|
|
24137
|
+
${add.stderr}`)) continue;
|
|
24138
|
+
break;
|
|
24139
|
+
}
|
|
24140
|
+
try {
|
|
24141
|
+
fs35.rmSync(path46.join(cwd, ".vercel", "project.json"), { force: true });
|
|
24142
|
+
} catch {
|
|
24143
|
+
}
|
|
24083
24144
|
const link = await runVercel(runner, ["link", "--project", projectName, "--yes"], {
|
|
24084
24145
|
cwd,
|
|
24085
24146
|
mode: "capture",
|
|
@@ -24106,16 +24167,18 @@ function readLinkedProjectId(cwd) {
|
|
|
24106
24167
|
async function runVercelNeonFlow(options) {
|
|
24107
24168
|
const env = options.env ?? process.env;
|
|
24108
24169
|
try {
|
|
24170
|
+
const runnerSpinner = p14.spinner();
|
|
24171
|
+
runnerSpinner.start("Checking for the Vercel CLI");
|
|
24109
24172
|
const runner = await resolveVercelRunner();
|
|
24173
|
+
runnerSpinner.stop(
|
|
24174
|
+
runner.source === "path" ? "Using the Vercel CLI from your PATH" : `Using ${pc4.cyan(`npx vercel@${VERCEL_CLI_VERSION}`)}`
|
|
24175
|
+
);
|
|
24110
24176
|
const auth = await ensureVercelAuth(runner, options.cwd, { env });
|
|
24111
24177
|
if (!auth.authed) {
|
|
24112
|
-
|
|
24178
|
+
p14.log.warn(authFailureMessage(auth.reason));
|
|
24113
24179
|
return { ok: false };
|
|
24114
24180
|
}
|
|
24115
|
-
|
|
24116
|
-
p13.log.success(`Signed in to Vercel as ${pc4.cyan(auth.username)}`);
|
|
24117
|
-
}
|
|
24118
|
-
const projectSpinner = p13.spinner();
|
|
24181
|
+
const projectSpinner = p14.spinner();
|
|
24119
24182
|
projectSpinner.start(`Creating Vercel project ${pc4.cyan(options.projectName)}`);
|
|
24120
24183
|
const project2 = await createVercelProject(runner, options.cwd, options.projectName, env);
|
|
24121
24184
|
projectSpinner.stop(
|
|
@@ -24123,11 +24186,11 @@ async function runVercelNeonFlow(options) {
|
|
|
24123
24186
|
);
|
|
24124
24187
|
const neon = await provisionNeonForMode(runner, options);
|
|
24125
24188
|
if (neon.failure || !neon.databaseUrl) {
|
|
24126
|
-
|
|
24127
|
-
if (neon.detail)
|
|
24189
|
+
p14.log.warn(neonFailureMessage(neon.failure));
|
|
24190
|
+
if (neon.detail) p14.log.message(pc4.dim(neon.detail));
|
|
24128
24191
|
return { ok: false };
|
|
24129
24192
|
}
|
|
24130
|
-
|
|
24193
|
+
p14.log.success(`Provisioned Neon Postgres for ${pc4.cyan(project2.name)}`);
|
|
24131
24194
|
return {
|
|
24132
24195
|
ok: true,
|
|
24133
24196
|
databaseUrl: neon.databaseUrl,
|
|
@@ -24135,7 +24198,7 @@ async function runVercelNeonFlow(options) {
|
|
|
24135
24198
|
neonResourceName: neon.resourceName
|
|
24136
24199
|
};
|
|
24137
24200
|
} catch (error) {
|
|
24138
|
-
|
|
24201
|
+
p14.log.warn(
|
|
24139
24202
|
`Vercel provisioning failed: ${error instanceof Error ? error.message : String(error)}`
|
|
24140
24203
|
);
|
|
24141
24204
|
return { ok: false };
|
|
@@ -24144,7 +24207,7 @@ async function runVercelNeonFlow(options) {
|
|
|
24144
24207
|
function provisionNeonForMode(runner, options) {
|
|
24145
24208
|
const opts = { plan: options.plan, env: options.env };
|
|
24146
24209
|
if (options.interactive) {
|
|
24147
|
-
|
|
24210
|
+
p14.log.info(
|
|
24148
24211
|
`Create your Neon database in the Vercel prompts below ${pc4.dim("(the Free plan is recommended).")}`
|
|
24149
24212
|
);
|
|
24150
24213
|
return provisionNeonInteractive(runner, options.cwd, opts);
|
|
@@ -24427,13 +24490,13 @@ async function runSeedCommand(options) {
|
|
|
24427
24490
|
}
|
|
24428
24491
|
);
|
|
24429
24492
|
});
|
|
24430
|
-
const
|
|
24431
|
-
|
|
24493
|
+
const spinner9 = clack.spinner();
|
|
24494
|
+
spinner9.start("Creating admin user...");
|
|
24432
24495
|
try {
|
|
24433
24496
|
const result = await runSeed2(false);
|
|
24434
24497
|
if (result.code === 2) {
|
|
24435
24498
|
const existingName = result.stdout.split("\n").find((l) => l.startsWith("EXISTING_USER:"))?.replace("EXISTING_USER:", "")?.trim() || "unknown";
|
|
24436
|
-
|
|
24499
|
+
spinner9.stop(`Account already exists for ${email}`);
|
|
24437
24500
|
const overwrite = await clack.confirm({
|
|
24438
24501
|
message: `An admin account (${existingName}) already exists with this email. Replace it?`
|
|
24439
24502
|
});
|
|
@@ -24445,14 +24508,14 @@ async function runSeedCommand(options) {
|
|
|
24445
24508
|
}
|
|
24446
24509
|
return;
|
|
24447
24510
|
}
|
|
24448
|
-
|
|
24511
|
+
spinner9.start("Replacing admin user...");
|
|
24449
24512
|
await runSeed2(true);
|
|
24450
|
-
|
|
24513
|
+
spinner9.stop("Admin user replaced");
|
|
24451
24514
|
} else {
|
|
24452
|
-
|
|
24515
|
+
spinner9.stop("Admin user created");
|
|
24453
24516
|
}
|
|
24454
24517
|
} catch (err) {
|
|
24455
|
-
|
|
24518
|
+
spinner9.stop("Failed to create admin user");
|
|
24456
24519
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
24457
24520
|
clack.log.error(errMsg);
|
|
24458
24521
|
clack.log.info("You can run the seed script manually:");
|
|
@@ -24552,7 +24615,7 @@ function removeExistingAdminPaths(cwd, namespaces) {
|
|
|
24552
24615
|
return removed;
|
|
24553
24616
|
}
|
|
24554
24617
|
async function runInitCommand(name, options) {
|
|
24555
|
-
|
|
24618
|
+
p15.intro(pc5.bgCyan(pc5.black(" Setup Your Dashboard ")));
|
|
24556
24619
|
let cwd = process.cwd();
|
|
24557
24620
|
let projectName = path48.basename(cwd);
|
|
24558
24621
|
let forceMode = Boolean(options.force);
|
|
@@ -24561,13 +24624,13 @@ async function runInitCommand(name, options) {
|
|
|
24561
24624
|
try {
|
|
24562
24625
|
namespace = validateAdminNamespace(options.namespace);
|
|
24563
24626
|
} catch (error) {
|
|
24564
|
-
|
|
24627
|
+
p15.log.error(error instanceof Error ? error.message : String(error));
|
|
24565
24628
|
process.exit(1);
|
|
24566
24629
|
}
|
|
24567
24630
|
}
|
|
24568
24631
|
if (!options.yes && !options.namespace) {
|
|
24569
24632
|
const defaultDashboardPath = resolveAdminNamespace(DEFAULT_ADMIN_NAMESPACE).routePath;
|
|
24570
|
-
const namespaceInput = await
|
|
24633
|
+
const namespaceInput = await p15.text({
|
|
24571
24634
|
message: "What's the path you want the dashboard to be?",
|
|
24572
24635
|
placeholder: `eg. ${defaultDashboardPath}`,
|
|
24573
24636
|
defaultValue: defaultDashboardPath,
|
|
@@ -24580,8 +24643,8 @@ async function runInitCommand(name, options) {
|
|
|
24580
24643
|
}
|
|
24581
24644
|
}
|
|
24582
24645
|
});
|
|
24583
|
-
if (
|
|
24584
|
-
|
|
24646
|
+
if (p15.isCancel(namespaceInput)) {
|
|
24647
|
+
p15.cancel("Setup cancelled.");
|
|
24585
24648
|
process.exit(0);
|
|
24586
24649
|
}
|
|
24587
24650
|
namespace = validateAdminDashboardPath(namespaceInput);
|
|
@@ -24591,16 +24654,16 @@ async function runInitCommand(name, options) {
|
|
|
24591
24654
|
let isFreshProject = false;
|
|
24592
24655
|
let srcDir;
|
|
24593
24656
|
if (project2.isExisting) {
|
|
24594
|
-
|
|
24657
|
+
p15.log.info(`Next.js app detected ${pc5.dim("\xB7")} ${pc5.cyan(pm)}`);
|
|
24595
24658
|
srcDir = project2.hasSrcDir;
|
|
24596
24659
|
if (!project2.hasTypeScript) {
|
|
24597
|
-
|
|
24660
|
+
p15.log.error("TypeScript is required. Please add a tsconfig.json first.");
|
|
24598
24661
|
process.exit(1);
|
|
24599
24662
|
}
|
|
24600
24663
|
if (forceMode) {
|
|
24601
24664
|
const nuked = removeExistingAdminPaths(cwd, await resolveForceInitNamespaces(cwd, namespace));
|
|
24602
24665
|
if (nuked > 0) {
|
|
24603
|
-
|
|
24666
|
+
p15.log.warn(`${pc5.yellow("Force mode:")} removed ${nuked} existing admin paths`);
|
|
24604
24667
|
}
|
|
24605
24668
|
project2 = detectProject(cwd, namespace);
|
|
24606
24669
|
} else if (project2.conflicts.length > 0) {
|
|
@@ -24609,9 +24672,9 @@ async function runInitCommand(name, options) {
|
|
|
24609
24672
|
"",
|
|
24610
24673
|
pc5.dim(`Use ${pc5.bold("--force")} to remove existing admin files before scaffolding.`)
|
|
24611
24674
|
);
|
|
24612
|
-
|
|
24675
|
+
p15.note(conflictLines.join("\n"), pc5.yellow("Conflicts"));
|
|
24613
24676
|
if (!options.yes) {
|
|
24614
|
-
const proceed = await
|
|
24677
|
+
const proceed = await p15.confirm({
|
|
24615
24678
|
message: [
|
|
24616
24679
|
`Continue with ${pc5.bold(pc5.cyan("--force"))}?`,
|
|
24617
24680
|
`${pc5.cyan("\u2502")} ${pc5.dim("This will force overwrite the existing admin code.")}`,
|
|
@@ -24619,8 +24682,8 @@ async function runInitCommand(name, options) {
|
|
|
24619
24682
|
].join("\n"),
|
|
24620
24683
|
initialValue: true
|
|
24621
24684
|
});
|
|
24622
|
-
if (
|
|
24623
|
-
|
|
24685
|
+
if (p15.isCancel(proceed) || !proceed) {
|
|
24686
|
+
p15.cancel("Setup cancelled.");
|
|
24624
24687
|
process.exit(0);
|
|
24625
24688
|
}
|
|
24626
24689
|
forceMode = true;
|
|
@@ -24629,23 +24692,23 @@ async function runInitCommand(name, options) {
|
|
|
24629
24692
|
await resolveForceInitNamespaces(cwd, namespace)
|
|
24630
24693
|
);
|
|
24631
24694
|
if (nuked > 0) {
|
|
24632
|
-
|
|
24695
|
+
p15.log.warn(`${pc5.yellow("Force mode:")} removed ${nuked} existing admin paths`);
|
|
24633
24696
|
}
|
|
24634
24697
|
project2 = detectProject(cwd, namespace);
|
|
24635
24698
|
}
|
|
24636
24699
|
}
|
|
24637
24700
|
} else {
|
|
24638
|
-
|
|
24701
|
+
p15.log.info("No Next.js app found \u2014 Running the fresh project mode...");
|
|
24639
24702
|
let projectPrompt;
|
|
24640
24703
|
try {
|
|
24641
24704
|
projectPrompt = options.yes ? resolveNonInteractiveProject(name) : await promptProject(name);
|
|
24642
24705
|
} catch (error) {
|
|
24643
|
-
|
|
24706
|
+
p15.log.error(error instanceof Error ? error.message : String(error));
|
|
24644
24707
|
process.exit(1);
|
|
24645
24708
|
}
|
|
24646
24709
|
srcDir = projectPrompt.useSrcDir;
|
|
24647
24710
|
if (!options.yes) {
|
|
24648
|
-
const pmChoice = await
|
|
24711
|
+
const pmChoice = await p15.select({
|
|
24649
24712
|
message: "Which package manager do you want to use?",
|
|
24650
24713
|
options: [
|
|
24651
24714
|
{ value: "pnpm", label: "pnpm", hint: "recommended" },
|
|
@@ -24654,8 +24717,8 @@ async function runInitCommand(name, options) {
|
|
|
24654
24717
|
{ value: "bun", label: "bun" }
|
|
24655
24718
|
]
|
|
24656
24719
|
});
|
|
24657
|
-
if (
|
|
24658
|
-
|
|
24720
|
+
if (p15.isCancel(pmChoice)) {
|
|
24721
|
+
p15.cancel("Setup cancelled.");
|
|
24659
24722
|
process.exit(0);
|
|
24660
24723
|
}
|
|
24661
24724
|
pm = pmChoice;
|
|
@@ -24677,7 +24740,7 @@ async function runInitCommand(name, options) {
|
|
|
24677
24740
|
];
|
|
24678
24741
|
if (srcDir) cnaArgs.push("--src-dir");
|
|
24679
24742
|
else cnaArgs.push("--no-src-dir");
|
|
24680
|
-
const createNextAppSpinner =
|
|
24743
|
+
const createNextAppSpinner = p15.spinner();
|
|
24681
24744
|
createNextAppSpinner.start(`Creating a Next.js app (latest)`);
|
|
24682
24745
|
const createNextAppResult = await runQuietCommand(bin, cnaArgs, {
|
|
24683
24746
|
cwd,
|
|
@@ -24689,8 +24752,8 @@ async function runInitCommand(name, options) {
|
|
|
24689
24752
|
process.stderr.write(`${createNextAppResult.output.trimEnd()}
|
|
24690
24753
|
`);
|
|
24691
24754
|
}
|
|
24692
|
-
|
|
24693
|
-
|
|
24755
|
+
p15.log.error(createNextAppResult.error);
|
|
24756
|
+
p15.log.info(
|
|
24694
24757
|
`You can create the project manually:
|
|
24695
24758
|
${pc5.cyan(`npx create-next-app@latest ${projectPrompt.projectName} --typescript --tailwind --app`)}
|
|
24696
24759
|
Then run ${pc5.cyan("betterstart init")} inside it.`
|
|
@@ -24704,11 +24767,11 @@ async function runInitCommand(name, options) {
|
|
|
24704
24767
|
);
|
|
24705
24768
|
if (!hasPackageJson || !hasNextConfig) {
|
|
24706
24769
|
createNextAppSpinner.stop(`Failed to create Next.js app: ${displayName}`);
|
|
24707
|
-
|
|
24770
|
+
p15.log.error(
|
|
24708
24771
|
"create-next-app completed but the project was not created. This can happen with nested npx calls."
|
|
24709
24772
|
);
|
|
24710
24773
|
const manualCmd = `npx create-next-app@latest ${projectPrompt.projectName} --typescript --tailwind --app`;
|
|
24711
|
-
|
|
24774
|
+
p15.log.info(
|
|
24712
24775
|
`Create the project manually:
|
|
24713
24776
|
${pc5.cyan(manualCmd)}
|
|
24714
24777
|
Then run ${pc5.cyan("betterstart init")} inside it.`
|
|
@@ -24760,7 +24823,7 @@ async function runInitCommand(name, options) {
|
|
|
24760
24823
|
if (options.yes) {
|
|
24761
24824
|
if (options.databaseUrl) {
|
|
24762
24825
|
if (!isValidDbUrl(options.databaseUrl)) {
|
|
24763
|
-
|
|
24826
|
+
p15.log.error(
|
|
24764
24827
|
`Invalid database URL. Must start with ${pc5.cyan("postgres://")} or ${pc5.cyan("postgresql://")}`
|
|
24765
24828
|
);
|
|
24766
24829
|
process.exit(1);
|
|
@@ -24779,12 +24842,12 @@ async function runInitCommand(name, options) {
|
|
|
24779
24842
|
if (flow.ok && flow.databaseUrl) {
|
|
24780
24843
|
databaseUrl = flow.databaseUrl;
|
|
24781
24844
|
} else {
|
|
24782
|
-
|
|
24845
|
+
p15.log.warn("Vercel provisioning did not complete; continuing without a database URL.");
|
|
24783
24846
|
}
|
|
24784
24847
|
}
|
|
24785
24848
|
} else if (existingDbUrl) {
|
|
24786
24849
|
const masked = maskDbUrl(existingDbUrl);
|
|
24787
|
-
|
|
24850
|
+
p15.log.info(`Using existing database URL from .env.local ${pc5.dim(`(${masked})`)}`);
|
|
24788
24851
|
databaseUrl = existingDbUrl;
|
|
24789
24852
|
} else {
|
|
24790
24853
|
const dbResult = await promptDatabase({ allowVercel: options.vercel !== false });
|
|
@@ -24799,7 +24862,7 @@ async function runInitCommand(name, options) {
|
|
|
24799
24862
|
if (flow.ok && flow.databaseUrl) {
|
|
24800
24863
|
databaseUrl = flow.databaseUrl;
|
|
24801
24864
|
} else {
|
|
24802
|
-
|
|
24865
|
+
p15.log.info("Falling back to a manual database connection string.");
|
|
24803
24866
|
openBrowserVercelNeon();
|
|
24804
24867
|
databaseUrl = await promptConnectionString();
|
|
24805
24868
|
}
|
|
@@ -24816,7 +24879,7 @@ async function runInitCommand(name, options) {
|
|
|
24816
24879
|
config.paths = config.frameworkConfig.next.paths;
|
|
24817
24880
|
config.database.migrationsDir = deriveMigrationsDir(namespace);
|
|
24818
24881
|
const results = [];
|
|
24819
|
-
const s =
|
|
24882
|
+
const s = p15.spinner();
|
|
24820
24883
|
s.start("Directory structure");
|
|
24821
24884
|
const baseFiles = scaffoldBase({
|
|
24822
24885
|
cwd,
|
|
@@ -24893,7 +24956,7 @@ async function runInitCommand(name, options) {
|
|
|
24893
24956
|
});
|
|
24894
24957
|
s.stop("");
|
|
24895
24958
|
process.stdout.write("\x1B[2A\x1B[J");
|
|
24896
|
-
|
|
24959
|
+
p15.note(noteLines.join("\n"), "Scaffolded admin");
|
|
24897
24960
|
const drizzleConfigPath = path48.join(cwd, "drizzle.config.ts");
|
|
24898
24961
|
if (!dbFiles.includes("drizzle.config.ts") && fs37.existsSync(drizzleConfigPath)) {
|
|
24899
24962
|
if (forceMode) {
|
|
@@ -24903,20 +24966,20 @@ async function runInitCommand(name, options) {
|
|
|
24903
24966
|
readNamespacedTemplate("drizzle.config.ts", namespace),
|
|
24904
24967
|
"utf-8"
|
|
24905
24968
|
);
|
|
24906
|
-
|
|
24969
|
+
p15.log.success("Updated drizzle.config.ts");
|
|
24907
24970
|
} else if (!options.yes) {
|
|
24908
|
-
const overwrite = await
|
|
24971
|
+
const overwrite = await p15.confirm({
|
|
24909
24972
|
message: "drizzle.config.ts already exists. Overwrite with latest version?",
|
|
24910
24973
|
initialValue: true
|
|
24911
24974
|
});
|
|
24912
|
-
if (!
|
|
24975
|
+
if (!p15.isCancel(overwrite) && overwrite) {
|
|
24913
24976
|
const { readNamespacedTemplate } = await import("./template-reader-X6KFP7B3.js");
|
|
24914
24977
|
fs37.writeFileSync(
|
|
24915
24978
|
drizzleConfigPath,
|
|
24916
24979
|
readNamespacedTemplate("drizzle.config.ts", namespace),
|
|
24917
24980
|
"utf-8"
|
|
24918
24981
|
);
|
|
24919
|
-
|
|
24982
|
+
p15.log.success("Updated drizzle.config.ts");
|
|
24920
24983
|
}
|
|
24921
24984
|
}
|
|
24922
24985
|
}
|
|
@@ -24942,8 +25005,8 @@ async function runInitCommand(name, options) {
|
|
|
24942
25005
|
depsInstalled = true;
|
|
24943
25006
|
} else {
|
|
24944
25007
|
s.stop("Failed to install dependencies");
|
|
24945
|
-
|
|
24946
|
-
|
|
25008
|
+
p15.log.warning(depsResult.error ?? "Unknown error");
|
|
25009
|
+
p15.log.info(
|
|
24947
25010
|
`You can install them manually:
|
|
24948
25011
|
${pc5.cyan(`${pm} add ${depsResult.dependencies.join(" ")}`)}
|
|
24949
25012
|
${pc5.cyan(`${pm} add -D ${depsResult.devDeps.join(" ")}`)}`
|
|
@@ -25032,10 +25095,10 @@ async function runInitCommand(name, options) {
|
|
|
25032
25095
|
` ${pc5.yellow("\u25B2")} Local filesystem storage is only for development or self-hosted persistent-disk deployments. Use Cloudflare R2 or AWS S3 for hosted/serverless production.`
|
|
25033
25096
|
);
|
|
25034
25097
|
}
|
|
25035
|
-
|
|
25098
|
+
p15.note(installLines.join("\n"), "Installed");
|
|
25036
25099
|
let dbPushed = false;
|
|
25037
25100
|
if (depsResult.success && options.skipMigration && hasDbUrl(cwd)) {
|
|
25038
|
-
|
|
25101
|
+
p15.log.info(`Skipping database schema push ${pc5.dim("(--skip-migration)")}`);
|
|
25039
25102
|
} else if (depsResult.success && hasDbUrl(cwd)) {
|
|
25040
25103
|
let driverReady = hasDrizzleKitPostgresDriverDependency(cwd);
|
|
25041
25104
|
if (!driverReady) {
|
|
@@ -25050,8 +25113,8 @@ async function runInitCommand(name, options) {
|
|
|
25050
25113
|
});
|
|
25051
25114
|
if (!driverResult.success) {
|
|
25052
25115
|
s.stop("Database push failed");
|
|
25053
|
-
|
|
25054
|
-
|
|
25116
|
+
p15.log.warning(driverResult.error ?? `Failed to install ${DRIZZLE_KIT_POSTGRES_DRIVER_DEP}`);
|
|
25117
|
+
p15.log.info(
|
|
25055
25118
|
`Install ${DRIZZLE_KIT_POSTGRES_DRIVER_DEP} manually, then run: ${pc5.cyan(drizzlePushCommand(pm))}`
|
|
25056
25119
|
);
|
|
25057
25120
|
} else {
|
|
@@ -25062,7 +25125,7 @@ async function runInitCommand(name, options) {
|
|
|
25062
25125
|
if (driverReady) {
|
|
25063
25126
|
const useTerminalForDbPush = shouldUseTerminalForDbPush(options);
|
|
25064
25127
|
if (useTerminalForDbPush) {
|
|
25065
|
-
|
|
25128
|
+
p15.log.info(`Running ${pc5.cyan("drizzle-kit push --force")}`);
|
|
25066
25129
|
} else {
|
|
25067
25130
|
s.start("Pushing database schema (drizzle-kit push)");
|
|
25068
25131
|
}
|
|
@@ -25071,13 +25134,13 @@ async function runInitCommand(name, options) {
|
|
|
25071
25134
|
if (useTerminalForDbPush) {
|
|
25072
25135
|
const verification = await verifyDatabaseReachable(cwd);
|
|
25073
25136
|
if (!verification.success) {
|
|
25074
|
-
|
|
25075
|
-
|
|
25137
|
+
p15.log.warning(verification.error);
|
|
25138
|
+
p15.log.error("Database was not reachable. Aborting setup.");
|
|
25076
25139
|
process.exit(1);
|
|
25077
25140
|
}
|
|
25078
25141
|
}
|
|
25079
25142
|
if (useTerminalForDbPush) {
|
|
25080
|
-
|
|
25143
|
+
p15.log.success("Database schema pushed");
|
|
25081
25144
|
} else {
|
|
25082
25145
|
s.stop(`${pc5.green("\u2713")} Database schema pushed`);
|
|
25083
25146
|
}
|
|
@@ -25087,12 +25150,12 @@ async function runInitCommand(name, options) {
|
|
|
25087
25150
|
s.stop("Database push failed");
|
|
25088
25151
|
}
|
|
25089
25152
|
const pushError = pushResult.error ?? "Unknown error";
|
|
25090
|
-
|
|
25153
|
+
p15.log.warning(pushError);
|
|
25091
25154
|
if (isDatabaseReachabilityError(pushError)) {
|
|
25092
|
-
|
|
25155
|
+
p15.log.error("Database was not reachable. Aborting setup.");
|
|
25093
25156
|
process.exit(1);
|
|
25094
25157
|
}
|
|
25095
|
-
|
|
25158
|
+
p15.log.info(`You can run it manually: ${pc5.cyan(drizzlePushCommand(pm))}`);
|
|
25096
25159
|
}
|
|
25097
25160
|
}
|
|
25098
25161
|
}
|
|
@@ -25101,7 +25164,7 @@ async function runInitCommand(name, options) {
|
|
|
25101
25164
|
let seedSuccess = false;
|
|
25102
25165
|
let adminAccountReady = false;
|
|
25103
25166
|
if (dbPushed && options.skipAdminCreation) {
|
|
25104
|
-
|
|
25167
|
+
p15.log.info(
|
|
25105
25168
|
`Skipping admin user creation ${pc5.dim(`(use ${betterstartExecCommand(pm, "seed")} later)`)}`
|
|
25106
25169
|
);
|
|
25107
25170
|
}
|
|
@@ -25111,14 +25174,14 @@ async function runInitCommand(name, options) {
|
|
|
25111
25174
|
let replaceExistingAdmin = false;
|
|
25112
25175
|
const adminCheck = await checkExistingAdmin(cwd, adminDir, authBasePath);
|
|
25113
25176
|
if (adminCheck.error) {
|
|
25114
|
-
|
|
25177
|
+
p15.log.warning(`Could not verify existing admin account ${pc5.dim(`(${adminCheck.error})`)}`);
|
|
25115
25178
|
if (isDatabaseReachabilityError(adminCheck.error)) {
|
|
25116
|
-
|
|
25179
|
+
p15.log.error("Database was not reachable. Aborting setup.");
|
|
25117
25180
|
process.exit(1);
|
|
25118
25181
|
}
|
|
25119
25182
|
} else if (adminCheck.existingAdmin) {
|
|
25120
25183
|
const existingAdminLabel = formatAdminIdentity(adminCheck.existingAdmin);
|
|
25121
|
-
const adminAction = await
|
|
25184
|
+
const adminAction = await p15.select({
|
|
25122
25185
|
message: "Found an already existing admin account. Do you want to replace it or skip?",
|
|
25123
25186
|
options: [
|
|
25124
25187
|
{
|
|
@@ -25132,34 +25195,34 @@ async function runInitCommand(name, options) {
|
|
|
25132
25195
|
}
|
|
25133
25196
|
]
|
|
25134
25197
|
});
|
|
25135
|
-
if (
|
|
25136
|
-
|
|
25198
|
+
if (p15.isCancel(adminAction)) {
|
|
25199
|
+
p15.cancel("Setup cancelled.");
|
|
25137
25200
|
process.exit(0);
|
|
25138
25201
|
}
|
|
25139
25202
|
if (adminAction === "skip") {
|
|
25140
25203
|
adminAccountReady = true;
|
|
25141
|
-
|
|
25204
|
+
p15.log.info(`Keeping existing admin account ${pc5.dim(`(${existingAdminLabel})`)}`);
|
|
25142
25205
|
} else {
|
|
25143
25206
|
replaceExistingAdmin = true;
|
|
25144
25207
|
}
|
|
25145
25208
|
}
|
|
25146
25209
|
if (!adminAccountReady) {
|
|
25147
|
-
|
|
25210
|
+
p15.note(
|
|
25148
25211
|
pc5.dim(
|
|
25149
25212
|
replaceExistingAdmin ? "Replace the existing admin account to access the admin." : "Create your first admin user to access the admin."
|
|
25150
25213
|
),
|
|
25151
25214
|
"Admin account"
|
|
25152
25215
|
);
|
|
25153
|
-
const credentials = await
|
|
25216
|
+
const credentials = await p15.group(
|
|
25154
25217
|
{
|
|
25155
|
-
email: () =>
|
|
25218
|
+
email: () => p15.text({
|
|
25156
25219
|
message: "Admin email",
|
|
25157
25220
|
placeholder: "admin@example.com",
|
|
25158
25221
|
validate: (v) => {
|
|
25159
25222
|
if (!v || !v.includes("@")) return "Please enter a valid email";
|
|
25160
25223
|
}
|
|
25161
25224
|
}),
|
|
25162
|
-
password: () =>
|
|
25225
|
+
password: () => p15.password({
|
|
25163
25226
|
message: "Admin password",
|
|
25164
25227
|
validate: (v) => {
|
|
25165
25228
|
if (!v || v.length < 8) return "Password must be at least 8 characters";
|
|
@@ -25168,7 +25231,7 @@ async function runInitCommand(name, options) {
|
|
|
25168
25231
|
},
|
|
25169
25232
|
{
|
|
25170
25233
|
onCancel: () => {
|
|
25171
|
-
|
|
25234
|
+
p15.cancel("Setup cancelled.");
|
|
25172
25235
|
process.exit(0);
|
|
25173
25236
|
}
|
|
25174
25237
|
}
|
|
@@ -25187,11 +25250,11 @@ async function runInitCommand(name, options) {
|
|
|
25187
25250
|
);
|
|
25188
25251
|
if (seedResult.existingUser) {
|
|
25189
25252
|
s.stop(`${pc5.yellow("\u25B2")} An account already exists for ${credentials.email}`);
|
|
25190
|
-
const replace = await
|
|
25253
|
+
const replace = await p15.confirm({
|
|
25191
25254
|
message: "Replace the existing account with this email?",
|
|
25192
25255
|
initialValue: false
|
|
25193
25256
|
});
|
|
25194
|
-
if (!
|
|
25257
|
+
if (!p15.isCancel(replace) && replace) {
|
|
25195
25258
|
seedOverwriteMode = "email";
|
|
25196
25259
|
s.start("Replacing admin user");
|
|
25197
25260
|
seedResult = await runSeed(
|
|
@@ -25212,14 +25275,14 @@ async function runInitCommand(name, options) {
|
|
|
25212
25275
|
adminAccountReady = true;
|
|
25213
25276
|
} else if (seedResult.error) {
|
|
25214
25277
|
s.stop(`${pc5.red("\u2717")} Failed to create admin user`);
|
|
25215
|
-
|
|
25278
|
+
p15.note(
|
|
25216
25279
|
`${pc5.red(seedResult.error)}
|
|
25217
25280
|
|
|
25218
25281
|
Run manually: ${pc5.cyan(betterstartExecCommand(pm, "seed"))}`,
|
|
25219
25282
|
pc5.red("Seed failed")
|
|
25220
25283
|
);
|
|
25221
25284
|
if (isDatabaseReachabilityError(seedResult.error)) {
|
|
25222
|
-
|
|
25285
|
+
p15.log.error("Database was not reachable. Aborting setup.");
|
|
25223
25286
|
process.exit(1);
|
|
25224
25287
|
}
|
|
25225
25288
|
}
|
|
@@ -25273,15 +25336,15 @@ Run manually: ${pc5.cyan(betterstartExecCommand(pm, "seed"))}`,
|
|
|
25273
25336
|
` ${step++}. Run ${pc5.cyan(betterstartExecCommand(pm, "add --integration <name>"))} to install integrations later`
|
|
25274
25337
|
);
|
|
25275
25338
|
summaryLines.push("", "Next steps:", ...nextSteps);
|
|
25276
|
-
|
|
25339
|
+
p15.note(summaryLines.join("\n"), "Admin scaffolded successfully");
|
|
25277
25340
|
if (!options.yes && !options.skipDevServerStart) {
|
|
25278
25341
|
const devCmd = runCommand(pm, "dev");
|
|
25279
|
-
const startDev = await
|
|
25342
|
+
const startDev = await p15.confirm({
|
|
25280
25343
|
message: "Start the development server?",
|
|
25281
25344
|
initialValue: true
|
|
25282
25345
|
});
|
|
25283
|
-
if (!
|
|
25284
|
-
|
|
25346
|
+
if (!p15.isCancel(startDev) && startDev) {
|
|
25347
|
+
p15.outro(`Starting ${pc5.cyan(devCmd)}...`);
|
|
25285
25348
|
await startManagedDevServer(cwd, devCmd, adminLoginUrl, {
|
|
25286
25349
|
email: seedSuccess && seedEmail ? seedEmail : void 0,
|
|
25287
25350
|
password: seedSuccess && seedPassword ? seedPassword : void 0
|
|
@@ -25289,7 +25352,7 @@ Run manually: ${pc5.cyan(betterstartExecCommand(pm, "seed"))}`,
|
|
|
25289
25352
|
return;
|
|
25290
25353
|
}
|
|
25291
25354
|
}
|
|
25292
|
-
|
|
25355
|
+
p15.outro("Done!");
|
|
25293
25356
|
}
|
|
25294
25357
|
function isValidDbUrl(url) {
|
|
25295
25358
|
return url.startsWith("postgres://") || url.startsWith("postgresql://");
|
|
@@ -25676,7 +25739,7 @@ function printAdminReadyNote(state) {
|
|
|
25676
25739
|
lines.unshift(`Password: ${pc5.cyan(state.adminPassword)}`);
|
|
25677
25740
|
lines.unshift(`Admin user: ${pc5.cyan(state.adminEmail)}`);
|
|
25678
25741
|
}
|
|
25679
|
-
|
|
25742
|
+
p15.note(lines.join("\n"), "Admin ready");
|
|
25680
25743
|
}
|
|
25681
25744
|
function shouldSuppressDevServerStartupLine(line) {
|
|
25682
25745
|
const plain = stripAnsi(line).trim();
|
|
@@ -25788,7 +25851,7 @@ function startManagedDevServer(cwd, devCmd, adminLoginUrl, adminCredentials) {
|
|
|
25788
25851
|
|
|
25789
25852
|
// adapters/next/commands/list-integrations.ts
|
|
25790
25853
|
import path49 from "path";
|
|
25791
|
-
import * as
|
|
25854
|
+
import * as p16 from "@clack/prompts";
|
|
25792
25855
|
async function runListIntegrationsCommand(options) {
|
|
25793
25856
|
const cwd = options.cwd ? path49.resolve(options.cwd) : process.cwd();
|
|
25794
25857
|
const config = await resolveConfig(cwd);
|
|
@@ -25797,15 +25860,15 @@ async function runListIntegrationsCommand(options) {
|
|
|
25797
25860
|
const status = installedIntegrations.has(integration.id) ? "installed" : "available";
|
|
25798
25861
|
return `${integration.id.padEnd(10)} ${status.padEnd(10)} ${integration.kind.padEnd(8)} ${integration.description}`;
|
|
25799
25862
|
});
|
|
25800
|
-
|
|
25801
|
-
|
|
25863
|
+
p16.note(lines.join("\n"), "BetterStart integrations");
|
|
25864
|
+
p16.outro(
|
|
25802
25865
|
`${installedIntegrations.size} installed, ${lines.length - installedIntegrations.size} available`
|
|
25803
25866
|
);
|
|
25804
25867
|
}
|
|
25805
25868
|
|
|
25806
25869
|
// adapters/next/commands/list-plugins.ts
|
|
25807
25870
|
import path50 from "path";
|
|
25808
|
-
import * as
|
|
25871
|
+
import * as p17 from "@clack/prompts";
|
|
25809
25872
|
async function runListPluginsCommand(options) {
|
|
25810
25873
|
const cwd = options.cwd ? path50.resolve(options.cwd) : process.cwd();
|
|
25811
25874
|
const config = await resolveConfig(cwd);
|
|
@@ -25814,34 +25877,34 @@ async function runListPluginsCommand(options) {
|
|
|
25814
25877
|
const status = installedPlugins.has(plugin.id) ? "installed" : "available";
|
|
25815
25878
|
return `${plugin.id.padEnd(10)} ${status.padEnd(10)} ${plugin.kind.padEnd(12)} ${plugin.description}`;
|
|
25816
25879
|
});
|
|
25817
|
-
|
|
25818
|
-
|
|
25880
|
+
p17.note(lines.join("\n"), "BetterStart plugins");
|
|
25881
|
+
p17.outro(`${installedPlugins.size} installed, ${lines.length - installedPlugins.size} available`);
|
|
25819
25882
|
}
|
|
25820
25883
|
|
|
25821
25884
|
// adapters/next/commands/remove.ts
|
|
25822
25885
|
import path51 from "path";
|
|
25823
|
-
import * as
|
|
25886
|
+
import * as p18 from "@clack/prompts";
|
|
25824
25887
|
async function runRemoveCommand(items, options) {
|
|
25825
25888
|
const removeIntegrationsMode = Boolean(options.integration);
|
|
25826
25889
|
if (!removeIntegrationsMode && items.includes("core")) {
|
|
25827
|
-
|
|
25890
|
+
p18.log.error("The core Admin cannot be removed.");
|
|
25828
25891
|
process.exit(1);
|
|
25829
25892
|
}
|
|
25830
25893
|
const pluginIds = items.filter(isPluginId);
|
|
25831
25894
|
const integrationIds = items.filter(isIntegrationId);
|
|
25832
25895
|
if (!removeIntegrationsMode && integrationIds.length > 0) {
|
|
25833
|
-
|
|
25896
|
+
p18.log.error(
|
|
25834
25897
|
`Integration IDs require --integration. Run \`betterstart remove --integration ${integrationIds.join(" ")}\`.`
|
|
25835
25898
|
);
|
|
25836
25899
|
process.exit(1);
|
|
25837
25900
|
}
|
|
25838
25901
|
if (removeIntegrationsMode && pluginIds.length > 0) {
|
|
25839
|
-
|
|
25902
|
+
p18.log.error(`Plugin IDs cannot be removed with --integration: ${pluginIds.join(", ")}`);
|
|
25840
25903
|
process.exit(1);
|
|
25841
25904
|
}
|
|
25842
25905
|
const invalidItems = removeIntegrationsMode ? items.filter((integrationId) => !isIntegrationId(integrationId)) : items.filter((pluginId) => !isPluginId(pluginId));
|
|
25843
25906
|
if (invalidItems.length > 0) {
|
|
25844
|
-
|
|
25907
|
+
p18.log.error(
|
|
25845
25908
|
removeIntegrationsMode ? formatUnknownIntegrationMessage(invalidItems) : formatUnknownPluginMessage(invalidItems)
|
|
25846
25909
|
);
|
|
25847
25910
|
process.exit(1);
|
|
@@ -25850,12 +25913,12 @@ async function runRemoveCommand(items, options) {
|
|
|
25850
25913
|
const config = await resolveConfig(cwd);
|
|
25851
25914
|
const pm = detectPackageManager(cwd);
|
|
25852
25915
|
if (!options.force) {
|
|
25853
|
-
const confirmed = await
|
|
25916
|
+
const confirmed = await p18.confirm({
|
|
25854
25917
|
message: `Remove ${removeIntegrationsMode ? "integration" : "plugin"}${items.length === 1 ? "" : "s"} ${items.join(", ")}?`,
|
|
25855
25918
|
initialValue: false
|
|
25856
25919
|
});
|
|
25857
|
-
if (
|
|
25858
|
-
|
|
25920
|
+
if (p18.isCancel(confirmed) || !confirmed) {
|
|
25921
|
+
p18.cancel(`${removeIntegrationsMode ? "Integration" : "Plugin"} removal cancelled.`);
|
|
25859
25922
|
process.exit(0);
|
|
25860
25923
|
}
|
|
25861
25924
|
}
|
|
@@ -25868,13 +25931,13 @@ async function runRemoveCommand(items, options) {
|
|
|
25868
25931
|
});
|
|
25869
25932
|
writeConfigFile(cwd, result2.config);
|
|
25870
25933
|
if (result2.removed.length === 0) {
|
|
25871
|
-
|
|
25934
|
+
p18.outro("No integrations were removed.");
|
|
25872
25935
|
return;
|
|
25873
25936
|
}
|
|
25874
25937
|
if (result2.warnings.length > 0) {
|
|
25875
|
-
|
|
25938
|
+
p18.note(result2.warnings.join("\n"), "Warnings");
|
|
25876
25939
|
}
|
|
25877
|
-
|
|
25940
|
+
p18.outro(
|
|
25878
25941
|
`Removed integration${result2.removed.length === 1 ? "" : "s"}: ${result2.removed.join(", ")}`
|
|
25879
25942
|
);
|
|
25880
25943
|
return;
|
|
@@ -25887,13 +25950,13 @@ async function runRemoveCommand(items, options) {
|
|
|
25887
25950
|
});
|
|
25888
25951
|
writeConfigFile(cwd, result.config);
|
|
25889
25952
|
if (result.removed.length === 0) {
|
|
25890
|
-
|
|
25953
|
+
p18.outro("No plugins were removed.");
|
|
25891
25954
|
return;
|
|
25892
25955
|
}
|
|
25893
25956
|
if (result.warnings.length > 0) {
|
|
25894
|
-
|
|
25957
|
+
p18.note(result.warnings.join("\n"), "Warnings");
|
|
25895
25958
|
}
|
|
25896
|
-
|
|
25959
|
+
p18.outro(`Removed plugin${result.removed.length === 1 ? "" : "s"}: ${result.removed.join(", ")}`);
|
|
25897
25960
|
}
|
|
25898
25961
|
|
|
25899
25962
|
// adapters/next/commands/remove-schema.ts
|
|
@@ -26042,7 +26105,7 @@ async function runRemoveSchemaCommand(schemaName, options) {
|
|
|
26042
26105
|
// adapters/next/commands/uninstall.ts
|
|
26043
26106
|
import fs40 from "fs";
|
|
26044
26107
|
import path53 from "path";
|
|
26045
|
-
import * as
|
|
26108
|
+
import * as p19 from "@clack/prompts";
|
|
26046
26109
|
import pc6 from "picocolors";
|
|
26047
26110
|
|
|
26048
26111
|
// adapters/next/commands/uninstall-cleaners.ts
|
|
@@ -26264,8 +26327,8 @@ function buildUninstallPlan(cwd, namespaceValue) {
|
|
|
26264
26327
|
count: configFiles.length,
|
|
26265
26328
|
unit: configFiles.length === 1 ? "file" : "files",
|
|
26266
26329
|
execute() {
|
|
26267
|
-
for (const
|
|
26268
|
-
if (fs40.existsSync(
|
|
26330
|
+
for (const p20 of configPaths) {
|
|
26331
|
+
if (fs40.existsSync(p20)) fs40.unlinkSync(p20);
|
|
26269
26332
|
}
|
|
26270
26333
|
}
|
|
26271
26334
|
});
|
|
@@ -26329,7 +26392,7 @@ function buildUninstallPlan(cwd, namespaceValue) {
|
|
|
26329
26392
|
}
|
|
26330
26393
|
async function runUninstallCommand(options) {
|
|
26331
26394
|
const cwd = options.cwd ? path53.resolve(options.cwd) : process.cwd();
|
|
26332
|
-
|
|
26395
|
+
p19.intro(pc6.bgRed(pc6.white(" BetterStart Uninstall ")));
|
|
26333
26396
|
let namespace = DEFAULT_ADMIN_NAMESPACE;
|
|
26334
26397
|
try {
|
|
26335
26398
|
const config = await resolveConfig(cwd);
|
|
@@ -26338,8 +26401,8 @@ async function runUninstallCommand(options) {
|
|
|
26338
26401
|
}
|
|
26339
26402
|
const steps = buildUninstallPlan(cwd, namespace);
|
|
26340
26403
|
if (steps.length === 0) {
|
|
26341
|
-
|
|
26342
|
-
|
|
26404
|
+
p19.log.success(`${pc6.green("\u2713")} Nothing to remove \u2014 project is already clean.`);
|
|
26405
|
+
p19.outro("Done");
|
|
26343
26406
|
return;
|
|
26344
26407
|
}
|
|
26345
26408
|
const planLines = steps.map((step) => {
|
|
@@ -26347,18 +26410,18 @@ async function runUninstallCommand(options) {
|
|
|
26347
26410
|
const countLabel = pc6.dim(`${step.count} ${step.unit}`);
|
|
26348
26411
|
return `${pc6.red("\xD7")} ${names} ${countLabel}`;
|
|
26349
26412
|
});
|
|
26350
|
-
|
|
26413
|
+
p19.note(planLines.join("\n"), "Uninstall plan");
|
|
26351
26414
|
if (!options.force) {
|
|
26352
|
-
const confirmed = await
|
|
26415
|
+
const confirmed = await p19.confirm({
|
|
26353
26416
|
message: "Proceed with uninstall?",
|
|
26354
26417
|
initialValue: false
|
|
26355
26418
|
});
|
|
26356
|
-
if (
|
|
26357
|
-
|
|
26419
|
+
if (p19.isCancel(confirmed) || !confirmed) {
|
|
26420
|
+
p19.cancel("Uninstall cancelled.");
|
|
26358
26421
|
process.exit(0);
|
|
26359
26422
|
}
|
|
26360
26423
|
}
|
|
26361
|
-
const s =
|
|
26424
|
+
const s = p19.spinner();
|
|
26362
26425
|
s.start(steps[0].label);
|
|
26363
26426
|
for (const step of steps) {
|
|
26364
26427
|
s.message(step.label);
|
|
@@ -26366,8 +26429,8 @@ async function runUninstallCommand(options) {
|
|
|
26366
26429
|
}
|
|
26367
26430
|
const parts = steps.map((step) => `${step.count} ${step.unit}`);
|
|
26368
26431
|
s.stop(`Removed ${parts.join(", ")}`);
|
|
26369
|
-
|
|
26370
|
-
|
|
26432
|
+
p19.note(pc6.dim("Database tables were NOT dropped \u2014 drop them manually if needed."), "Next steps");
|
|
26433
|
+
p19.outro("Uninstall complete");
|
|
26371
26434
|
}
|
|
26372
26435
|
|
|
26373
26436
|
// adapters/next/commands/update-component.ts
|