betterstart-cli 0.0.37 → 0.0.38
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 +317 -223
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -5384,14 +5384,14 @@ function buildStepsConstant(steps) {
|
|
|
5384
5384
|
${entries.join(",\n")}
|
|
5385
5385
|
]`;
|
|
5386
5386
|
}
|
|
5387
|
-
function buildComponentSource(
|
|
5387
|
+
function buildComponentSource(p23) {
|
|
5388
5388
|
const providerOpen = ` <NuqsAdapter>
|
|
5389
5389
|
<React.Suspense fallback={null}>
|
|
5390
|
-
<${
|
|
5390
|
+
<${p23.pascal}FormInner />
|
|
5391
5391
|
</React.Suspense>
|
|
5392
5392
|
</NuqsAdapter>`;
|
|
5393
5393
|
const exportWrapper = `
|
|
5394
|
-
export function ${
|
|
5394
|
+
export function ${p23.pascal}Form() {
|
|
5395
5395
|
return (
|
|
5396
5396
|
${providerOpen}
|
|
5397
5397
|
)
|
|
@@ -5400,22 +5400,22 @@ ${providerOpen}
|
|
|
5400
5400
|
return `'use client'
|
|
5401
5401
|
|
|
5402
5402
|
import { standardSchemaResolver } from '@hookform/resolvers/standard-schema'
|
|
5403
|
-
import { ChevronLeft, ChevronRight${
|
|
5403
|
+
import { ChevronLeft, ChevronRight${p23.hasListFields ? ", Trash2" : ""} } from 'lucide-react'
|
|
5404
5404
|
import { createParser, useQueryState } from 'nuqs'
|
|
5405
5405
|
import { NuqsAdapter } from 'nuqs/adapters/next/app'
|
|
5406
5406
|
import * as React from 'react'
|
|
5407
|
-
${
|
|
5407
|
+
${p23.rhfImport}
|
|
5408
5408
|
import { z } from 'zod/v3'
|
|
5409
|
-
import { create${
|
|
5409
|
+
import { create${p23.pascal}Submission } from '@admin/actions/${p23.actionImportPath}'
|
|
5410
5410
|
|
|
5411
5411
|
const formSchema = z.object({
|
|
5412
|
-
${
|
|
5412
|
+
${p23.zodFields}
|
|
5413
5413
|
})
|
|
5414
5414
|
|
|
5415
5415
|
type FormValues = z.infer<typeof formSchema>
|
|
5416
5416
|
${buildFieldErrorHelper()}
|
|
5417
5417
|
|
|
5418
|
-
${
|
|
5418
|
+
${p23.stepsConst}
|
|
5419
5419
|
|
|
5420
5420
|
const stepParser = createParser({
|
|
5421
5421
|
parse(value) {
|
|
@@ -5433,7 +5433,7 @@ const stepParser = createParser({
|
|
|
5433
5433
|
}
|
|
5434
5434
|
}).withDefault(0)
|
|
5435
5435
|
|
|
5436
|
-
function ${
|
|
5436
|
+
function ${p23.pascal}FormInner() {
|
|
5437
5437
|
const [currentStep, setCurrentStep] = useQueryState('step', stepParser)
|
|
5438
5438
|
const [submitted, setSubmitted] = React.useState(false)
|
|
5439
5439
|
const [submitting, startSubmitTransition] = React.useTransition()
|
|
@@ -5441,11 +5441,11 @@ function ${p22.pascal}FormInner() {
|
|
|
5441
5441
|
const form = useForm<FormValues>({
|
|
5442
5442
|
resolver: standardSchemaResolver(formSchema),
|
|
5443
5443
|
defaultValues: {
|
|
5444
|
-
${
|
|
5444
|
+
${p23.defaults}
|
|
5445
5445
|
},
|
|
5446
5446
|
})
|
|
5447
5447
|
|
|
5448
|
-
${
|
|
5448
|
+
${p23.fieldArraySetup}${p23.watchSetup}
|
|
5449
5449
|
async function handleNext() {
|
|
5450
5450
|
const stepFields = STEPS[currentStep].fields as (keyof FormValues)[]
|
|
5451
5451
|
const isValid = await form.trigger(stepFields, { shouldFocus: true })
|
|
@@ -5461,9 +5461,9 @@ ${p22.fieldArraySetup}${p22.watchSetup}
|
|
|
5461
5461
|
function onSubmit(values: FormValues) {
|
|
5462
5462
|
startSubmitTransition(async () => {
|
|
5463
5463
|
try {
|
|
5464
|
-
const result = await create${
|
|
5464
|
+
const result = await create${p23.pascal}Submission(values)
|
|
5465
5465
|
if (result.success) {
|
|
5466
|
-
${
|
|
5466
|
+
${p23.successHandler}
|
|
5467
5467
|
} else {
|
|
5468
5468
|
form.setError('root', { message: result.error || 'Something went wrong' })
|
|
5469
5469
|
}
|
|
@@ -5477,7 +5477,7 @@ ${p22.fieldArraySetup}${p22.watchSetup}
|
|
|
5477
5477
|
return (
|
|
5478
5478
|
<div className="rounded-sm border p-6 text-center">
|
|
5479
5479
|
<h3 className="text-lg font-semibold">Thank you!</h3>
|
|
5480
|
-
<p className="mt-2 text-muted-foreground">${
|
|
5480
|
+
<p className="mt-2 text-muted-foreground">${p23.successMessage}</p>
|
|
5481
5481
|
</div>
|
|
5482
5482
|
)
|
|
5483
5483
|
}
|
|
@@ -5494,7 +5494,7 @@ ${p22.fieldArraySetup}${p22.watchSetup}
|
|
|
5494
5494
|
|
|
5495
5495
|
{/* Step content */}
|
|
5496
5496
|
<div key={currentStep} className="animate-in fade-in duration-300 space-y-6">
|
|
5497
|
-
${
|
|
5497
|
+
${p23.stepContentBlocks}
|
|
5498
5498
|
</div>
|
|
5499
5499
|
|
|
5500
5500
|
{form.formState.errors.root && (
|
|
@@ -5528,7 +5528,7 @@ ${p22.stepContentBlocks}
|
|
|
5528
5528
|
onClick={() => form.handleSubmit(onSubmit)()}
|
|
5529
5529
|
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"
|
|
5530
5530
|
>
|
|
5531
|
-
{submitting ? 'Submitting...' : ${
|
|
5531
|
+
{submitting ? 'Submitting...' : ${p23.submitText}}
|
|
5532
5532
|
</button>
|
|
5533
5533
|
)}
|
|
5534
5534
|
</div>
|
|
@@ -19793,23 +19793,32 @@ function eraseClackLine(options = {}) {
|
|
|
19793
19793
|
const restore = below > 0 ? `\x1B[${below}B` : "";
|
|
19794
19794
|
process.stdout.write(`\x1B[${up}A\x1B[${CLACK_LINE_ROWS}M${restore}`);
|
|
19795
19795
|
}
|
|
19796
|
+
var activeSpinners = 0;
|
|
19797
|
+
function hasActiveSpinner() {
|
|
19798
|
+
return activeSpinners > 0;
|
|
19799
|
+
}
|
|
19796
19800
|
function spinner2(options) {
|
|
19797
|
-
const inner = p5.spinner(options);
|
|
19801
|
+
const inner = p5.spinner({ ...options, cancelMessage: "Setup cancelled." });
|
|
19798
19802
|
const guided = options?.withGuide !== false;
|
|
19799
19803
|
let started = false;
|
|
19804
|
+
const setStarted = (next) => {
|
|
19805
|
+
if (started === next) return;
|
|
19806
|
+
started = next;
|
|
19807
|
+
activeSpinners += next ? 1 : -1;
|
|
19808
|
+
};
|
|
19800
19809
|
return {
|
|
19801
19810
|
start: (message = "") => {
|
|
19802
|
-
|
|
19811
|
+
setStarted(true);
|
|
19803
19812
|
inner.start(fitSpinnerMessage(message));
|
|
19804
19813
|
},
|
|
19805
19814
|
message: (message = "") => inner.message(fitSpinnerMessage(message)),
|
|
19806
19815
|
stop: (message = "") => {
|
|
19807
|
-
|
|
19816
|
+
setStarted(false);
|
|
19808
19817
|
inner.stop(message);
|
|
19809
19818
|
},
|
|
19810
19819
|
clear: () => {
|
|
19811
19820
|
if (!started) return;
|
|
19812
|
-
|
|
19821
|
+
setStarted(false);
|
|
19813
19822
|
inner.clear();
|
|
19814
19823
|
if (guided && process.stdout.isTTY && process.env.CI !== "true") {
|
|
19815
19824
|
process.stdout.write("\x1B[1A\x1B[2K");
|
|
@@ -21826,7 +21835,24 @@ ${validationErrors.map((error) => ` - ${error}`).join("\n")}`
|
|
|
21826
21835
|
import { execFileSync as execFileSync5, spawn as spawn4 } from "child_process";
|
|
21827
21836
|
import fs39 from "fs";
|
|
21828
21837
|
import path50 from "path";
|
|
21829
|
-
import * as
|
|
21838
|
+
import * as p18 from "@clack/prompts";
|
|
21839
|
+
|
|
21840
|
+
// core-engine/utils/cancel-guard.ts
|
|
21841
|
+
import * as p10 from "@clack/prompts";
|
|
21842
|
+
function installSetupCancelGuard() {
|
|
21843
|
+
const onSignal = () => {
|
|
21844
|
+
if (!hasActiveSpinner()) {
|
|
21845
|
+
p10.cancel("Setup cancelled.");
|
|
21846
|
+
}
|
|
21847
|
+
process.exit(0);
|
|
21848
|
+
};
|
|
21849
|
+
process.on("SIGINT", onSignal);
|
|
21850
|
+
process.on("SIGTERM", onSignal);
|
|
21851
|
+
return () => {
|
|
21852
|
+
process.off("SIGINT", onSignal);
|
|
21853
|
+
process.off("SIGTERM", onSignal);
|
|
21854
|
+
};
|
|
21855
|
+
}
|
|
21830
21856
|
|
|
21831
21857
|
// core-engine/utils/prompt-theme.ts
|
|
21832
21858
|
var GREEN_STEP_SUBMIT = "\x1B[32m\u25C7\x1B[39m";
|
|
@@ -21913,7 +21939,7 @@ function deferNextPromptCheck() {
|
|
|
21913
21939
|
|
|
21914
21940
|
// adapters/next/init/prompts/database.ts
|
|
21915
21941
|
import { execFileSync as execFileSync4 } from "child_process";
|
|
21916
|
-
import * as
|
|
21942
|
+
import * as p11 from "@clack/prompts";
|
|
21917
21943
|
import pc from "picocolors";
|
|
21918
21944
|
var VERCEL_NEON_URL = "https://vercel.com/dashboard/integrations/checkout/neon";
|
|
21919
21945
|
async function promptServices(options) {
|
|
@@ -21921,7 +21947,7 @@ async function promptServices(options) {
|
|
|
21921
21947
|
const url2 = await promptConnectionString();
|
|
21922
21948
|
return { provider: "manual", url: url2 };
|
|
21923
21949
|
}
|
|
21924
|
-
const choice = await
|
|
21950
|
+
const choice = await p11.select({
|
|
21925
21951
|
message: "Connect a PostgreSQL Database",
|
|
21926
21952
|
options: [
|
|
21927
21953
|
{
|
|
@@ -21937,8 +21963,8 @@ async function promptServices(options) {
|
|
|
21937
21963
|
],
|
|
21938
21964
|
initialValue: "vercel"
|
|
21939
21965
|
});
|
|
21940
|
-
if (
|
|
21941
|
-
|
|
21966
|
+
if (p11.isCancel(choice)) {
|
|
21967
|
+
p11.cancel("Setup cancelled.");
|
|
21942
21968
|
process.exit(0);
|
|
21943
21969
|
}
|
|
21944
21970
|
if (choice === "vercel") {
|
|
@@ -21949,7 +21975,7 @@ async function promptServices(options) {
|
|
|
21949
21975
|
}
|
|
21950
21976
|
function openBrowserVercelNeon() {
|
|
21951
21977
|
openBrowser(VERCEL_NEON_URL);
|
|
21952
|
-
|
|
21978
|
+
p11.log.info(
|
|
21953
21979
|
`Opening Vercel... Create a Neon Postgres database, then copy the ${pc.cyan("DATABASE_URL")} from the dashboard.`
|
|
21954
21980
|
);
|
|
21955
21981
|
}
|
|
@@ -21959,12 +21985,12 @@ function openBrowserVercelNeonResource(url) {
|
|
|
21959
21985
|
return;
|
|
21960
21986
|
}
|
|
21961
21987
|
openBrowser(url);
|
|
21962
|
-
|
|
21988
|
+
p11.log.info(
|
|
21963
21989
|
`Opening Vercel... Copy the Neon ${pc.cyan("DATABASE_URL")} from the database dashboard, then paste it below.`
|
|
21964
21990
|
);
|
|
21965
21991
|
}
|
|
21966
21992
|
async function promptConnectionString() {
|
|
21967
|
-
const input = await
|
|
21993
|
+
const input = await p11.text({
|
|
21968
21994
|
message: "Paste your PostgreSQL connection string",
|
|
21969
21995
|
placeholder: "postgres://user:pass@host/db",
|
|
21970
21996
|
validate(val) {
|
|
@@ -21978,8 +22004,8 @@ async function promptConnectionString() {
|
|
|
21978
22004
|
}
|
|
21979
22005
|
}
|
|
21980
22006
|
});
|
|
21981
|
-
if (
|
|
21982
|
-
|
|
22007
|
+
if (p11.isCancel(input)) {
|
|
22008
|
+
p11.cancel("Setup cancelled.");
|
|
21983
22009
|
process.exit(0);
|
|
21984
22010
|
}
|
|
21985
22011
|
return input.replace(/^['"]|['"]$/g, "").trim();
|
|
@@ -22000,7 +22026,7 @@ function openBrowser(url) {
|
|
|
22000
22026
|
|
|
22001
22027
|
// adapters/next/init/prompts/plugins.ts
|
|
22002
22028
|
import { styleText } from "util";
|
|
22003
|
-
import * as
|
|
22029
|
+
import * as p12 from "@clack/prompts";
|
|
22004
22030
|
|
|
22005
22031
|
// adapters/next/init/scaffolders/env.ts
|
|
22006
22032
|
import crypto2 from "crypto";
|
|
@@ -22160,7 +22186,7 @@ async function promptPlugins(cwd, options = {}) {
|
|
|
22160
22186
|
}
|
|
22161
22187
|
};
|
|
22162
22188
|
const storageStep = deferNextPromptCheck();
|
|
22163
|
-
const storage = await
|
|
22189
|
+
const storage = await p12.select({
|
|
22164
22190
|
message: "Choose a file storage",
|
|
22165
22191
|
options: [
|
|
22166
22192
|
{
|
|
@@ -22179,8 +22205,8 @@ async function promptPlugins(cwd, options = {}) {
|
|
|
22179
22205
|
],
|
|
22180
22206
|
initialValue: "vercel-blob"
|
|
22181
22207
|
});
|
|
22182
|
-
if (
|
|
22183
|
-
|
|
22208
|
+
if (p12.isCancel(storage)) {
|
|
22209
|
+
p12.cancel("Setup cancelled.");
|
|
22184
22210
|
process.exit(0);
|
|
22185
22211
|
}
|
|
22186
22212
|
if (storage === "r2") {
|
|
@@ -22191,7 +22217,7 @@ async function promptPlugins(cwd, options = {}) {
|
|
|
22191
22217
|
const flow = !existingToken && options.provisionVercelBlob ? await options.provisionVercelBlob() : void 0;
|
|
22192
22218
|
if (flow?.ok && flow.token) {
|
|
22193
22219
|
persistBlobReadWriteToken(cwd, flow.token);
|
|
22194
|
-
|
|
22220
|
+
p12.log.success("Saved BLOB_READ_WRITE_TOKEN to .env.local");
|
|
22195
22221
|
sections.push({
|
|
22196
22222
|
header: "Storage (Vercel Blob)",
|
|
22197
22223
|
vars: [{ key: "BLOB_READ_WRITE_TOKEN", value: flow.token }]
|
|
@@ -22199,20 +22225,26 @@ async function promptPlugins(cwd, options = {}) {
|
|
|
22199
22225
|
overwriteKeys.add("BLOB_READ_WRITE_TOKEN");
|
|
22200
22226
|
if (flow.usedTerminalFallback) storageStep.skip();
|
|
22201
22227
|
else storageStep.confirm();
|
|
22228
|
+
} else if (flow) {
|
|
22229
|
+
p12.log.warn(
|
|
22230
|
+
"Continuing without a Blob token \u2014 add BLOB_READ_WRITE_TOKEN to .env.local from the store on vercel.com/dashboard/stores."
|
|
22231
|
+
);
|
|
22232
|
+
sections.push({
|
|
22233
|
+
header: "Storage (Vercel Blob)",
|
|
22234
|
+
vars: [{ key: "BLOB_READ_WRITE_TOKEN", value: "" }]
|
|
22235
|
+
});
|
|
22236
|
+
storageStep.skip();
|
|
22202
22237
|
} else {
|
|
22203
22238
|
if (existingToken) {
|
|
22204
|
-
|
|
22205
|
-
} else if (options.provisionVercelBlob) {
|
|
22206
|
-
p11.log.info("Falling back to a manual Vercel Blob token.");
|
|
22239
|
+
p12.log.info("Using the existing Vercel Blob token from .env.local");
|
|
22207
22240
|
}
|
|
22208
22241
|
mergeIntegrationConfig(await collectIntegrationConfig(cwd, ["vercel-blob"]));
|
|
22209
|
-
|
|
22210
|
-
else storageStep.confirm();
|
|
22242
|
+
storageStep.confirm();
|
|
22211
22243
|
}
|
|
22212
22244
|
} else {
|
|
22213
22245
|
storageStep.confirm();
|
|
22214
22246
|
}
|
|
22215
|
-
const selectedPlugins = await
|
|
22247
|
+
const selectedPlugins = await p12.multiselect({
|
|
22216
22248
|
message: "Select presets",
|
|
22217
22249
|
options: [
|
|
22218
22250
|
{
|
|
@@ -22224,12 +22256,12 @@ async function promptPlugins(cwd, options = {}) {
|
|
|
22224
22256
|
required: false,
|
|
22225
22257
|
initialValues: ["blog"]
|
|
22226
22258
|
});
|
|
22227
|
-
if (
|
|
22228
|
-
|
|
22259
|
+
if (p12.isCancel(selectedPlugins)) {
|
|
22260
|
+
p12.cancel("Setup cancelled.");
|
|
22229
22261
|
process.exit(0);
|
|
22230
22262
|
}
|
|
22231
22263
|
const integrations = [];
|
|
22232
|
-
const setupResend = await
|
|
22264
|
+
const setupResend = await p12.confirm({
|
|
22233
22265
|
message: `Do you want to setup resend.com emails?
|
|
22234
22266
|
${styleText(
|
|
22235
22267
|
"dim",
|
|
@@ -22237,8 +22269,8 @@ ${styleText(
|
|
|
22237
22269
|
)}`,
|
|
22238
22270
|
initialValue: true
|
|
22239
22271
|
});
|
|
22240
|
-
if (
|
|
22241
|
-
|
|
22272
|
+
if (p12.isCancel(setupResend)) {
|
|
22273
|
+
p12.cancel("Setup cancelled.");
|
|
22242
22274
|
process.exit(0);
|
|
22243
22275
|
}
|
|
22244
22276
|
if (setupResend) {
|
|
@@ -22267,10 +22299,10 @@ ${styleText(
|
|
|
22267
22299
|
}
|
|
22268
22300
|
|
|
22269
22301
|
// adapters/next/init/prompts/project.ts
|
|
22270
|
-
import * as
|
|
22302
|
+
import * as p13 from "@clack/prompts";
|
|
22271
22303
|
import pc2 from "picocolors";
|
|
22272
22304
|
async function promptProject(defaultName) {
|
|
22273
|
-
const projectName = await
|
|
22305
|
+
const projectName = await p13.text({
|
|
22274
22306
|
message: [
|
|
22275
22307
|
"What is your project name?",
|
|
22276
22308
|
`${pc2.cyan("\u2502")} ${pc2.dim("If you don't want a directory created with the project name, just press `")}${pc2.bold(
|
|
@@ -22289,16 +22321,16 @@ async function promptProject(defaultName) {
|
|
|
22289
22321
|
return void 0;
|
|
22290
22322
|
}
|
|
22291
22323
|
});
|
|
22292
|
-
if (
|
|
22293
|
-
|
|
22324
|
+
if (p13.isCancel(projectName)) {
|
|
22325
|
+
p13.cancel("Setup cancelled.");
|
|
22294
22326
|
process.exit(0);
|
|
22295
22327
|
}
|
|
22296
|
-
const useSrcDir = await
|
|
22328
|
+
const useSrcDir = await p13.confirm({
|
|
22297
22329
|
message: "Use src/ directory?",
|
|
22298
22330
|
initialValue: false
|
|
22299
22331
|
});
|
|
22300
|
-
if (
|
|
22301
|
-
|
|
22332
|
+
if (p13.isCancel(useSrcDir)) {
|
|
22333
|
+
p13.cancel("Setup cancelled.");
|
|
22302
22334
|
process.exit(0);
|
|
22303
22335
|
}
|
|
22304
22336
|
return { projectName: projectName.trim(), useSrcDir };
|
|
@@ -24144,11 +24176,11 @@ function scaffoldTsconfig(cwd, config) {
|
|
|
24144
24176
|
}
|
|
24145
24177
|
|
|
24146
24178
|
// adapters/next/init/vercel/flow.ts
|
|
24147
|
-
import * as
|
|
24179
|
+
import * as p17 from "@clack/prompts";
|
|
24148
24180
|
import pc6 from "picocolors";
|
|
24149
24181
|
|
|
24150
24182
|
// adapters/next/init/vercel/auth.ts
|
|
24151
|
-
import * as
|
|
24183
|
+
import * as p14 from "@clack/prompts";
|
|
24152
24184
|
import pc3 from "picocolors";
|
|
24153
24185
|
|
|
24154
24186
|
// adapters/next/init/vercel/runner.ts
|
|
@@ -24356,7 +24388,7 @@ async function ensureVercelAuth(runner, cwd, options) {
|
|
|
24356
24388
|
checkSpinner.clear();
|
|
24357
24389
|
const signInMessage = `Sign in to Vercel to continue ${pc3.dim("(or press Ctrl-C to enter a connection string manually)")}`;
|
|
24358
24390
|
const signInRows = clackLogRows(signInMessage);
|
|
24359
|
-
|
|
24391
|
+
p14.log.info(signInMessage);
|
|
24360
24392
|
let streamedRows = 0;
|
|
24361
24393
|
const login = await runVercel(runner, ["login"], {
|
|
24362
24394
|
cwd,
|
|
@@ -24388,7 +24420,7 @@ function signedInMessage(username) {
|
|
|
24388
24420
|
}
|
|
24389
24421
|
|
|
24390
24422
|
// adapters/next/init/vercel/blob.ts
|
|
24391
|
-
import * as
|
|
24423
|
+
import * as p15 from "@clack/prompts";
|
|
24392
24424
|
import pc4 from "picocolors";
|
|
24393
24425
|
|
|
24394
24426
|
// adapters/next/init/vercel/env-pull.ts
|
|
@@ -24499,21 +24531,46 @@ function readLinkedProjectJson(cwd) {
|
|
|
24499
24531
|
// adapters/next/init/vercel/blob.ts
|
|
24500
24532
|
var PROVISION_TIMEOUT_MS = 18e4;
|
|
24501
24533
|
var INTERACTIVE_PROVISION_TIMEOUT_MS = 6e5;
|
|
24502
|
-
var MAX_STORE_NAME_ATTEMPTS =
|
|
24534
|
+
var MAX_STORE_NAME_ATTEMPTS = 10;
|
|
24503
24535
|
function blobStoreName(projectName) {
|
|
24504
24536
|
return sanitizeVercelProjectName(`${projectName}-blob`);
|
|
24505
24537
|
}
|
|
24506
24538
|
function isNameTaken(result) {
|
|
24507
|
-
return /already exists|already taken|already in use|name.*taken/i.test(
|
|
24539
|
+
return /already exists|already taken|already in use|name.*taken|conflict|\b409\b/i.test(
|
|
24508
24540
|
`${result.stdout}
|
|
24509
24541
|
${result.stderr}`
|
|
24510
24542
|
);
|
|
24511
24543
|
}
|
|
24544
|
+
function candidateStoreName(baseName, attempt) {
|
|
24545
|
+
if (attempt < MAX_STORE_NAME_ATTEMPTS) return versionedVercelProjectName(baseName, attempt);
|
|
24546
|
+
const suffix = `-${Date.now().toString(36)}`;
|
|
24547
|
+
return `${baseName.slice(0, 100 - suffix.length)}${suffix}`;
|
|
24548
|
+
}
|
|
24549
|
+
function isEnvVarConflict(result) {
|
|
24550
|
+
return /already has an existing environment variable/i.test(`${result.stdout}
|
|
24551
|
+
${result.stderr}`);
|
|
24552
|
+
}
|
|
24553
|
+
function createdStoreId(result) {
|
|
24554
|
+
return /Blob store created:[^(]*\((store_[A-Za-z0-9]+)\)/.exec(
|
|
24555
|
+
`${result.stdout}
|
|
24556
|
+
${result.stderr}`
|
|
24557
|
+
)?.[1];
|
|
24558
|
+
}
|
|
24559
|
+
async function deleteOrphanStore(runner, cwd, createResult, env) {
|
|
24560
|
+
const storeId = createdStoreId(createResult);
|
|
24561
|
+
if (!storeId) return;
|
|
24562
|
+
await runVercel(runner, ["blob", "delete-store", storeId, "--yes"], {
|
|
24563
|
+
cwd,
|
|
24564
|
+
mode: "capture",
|
|
24565
|
+
timeoutMs: PROVISION_TIMEOUT_MS,
|
|
24566
|
+
env
|
|
24567
|
+
});
|
|
24568
|
+
}
|
|
24512
24569
|
async function createStoreQuiet(runner, cwd, baseName, env) {
|
|
24513
24570
|
let result;
|
|
24514
24571
|
let storeName = baseName;
|
|
24515
24572
|
for (let attempt = 1; attempt <= MAX_STORE_NAME_ATTEMPTS; attempt++) {
|
|
24516
|
-
storeName =
|
|
24573
|
+
storeName = candidateStoreName(baseName, attempt);
|
|
24517
24574
|
result = await runVercel(
|
|
24518
24575
|
runner,
|
|
24519
24576
|
["blob", "create-store", storeName, "--access", "public", "--yes"],
|
|
@@ -24526,45 +24583,80 @@ async function createStoreQuiet(runner, cwd, baseName, env) {
|
|
|
24526
24583
|
async function provisionBlobStoreInteractive(runner, cwd, options) {
|
|
24527
24584
|
const quietSpinner = spinner2();
|
|
24528
24585
|
quietSpinner.start("Creating your Vercel Blob store");
|
|
24529
|
-
|
|
24530
|
-
|
|
24531
|
-
|
|
24532
|
-
const
|
|
24533
|
-
if (!
|
|
24534
|
-
|
|
24535
|
-
return { storeName
|
|
24536
|
-
}
|
|
24586
|
+
let terminalFallbackRan = false;
|
|
24587
|
+
let lastResult;
|
|
24588
|
+
const pullToken = async (activeSpinner, storeName) => {
|
|
24589
|
+
const token = await pullBlobToken(runner, cwd, options.env);
|
|
24590
|
+
if (!token) {
|
|
24591
|
+
activeSpinner.stop("No BLOB_READ_WRITE_TOKEN came back from Vercel");
|
|
24592
|
+
return { ...storeName && { storeName }, failure: "env-pull-empty" };
|
|
24593
|
+
}
|
|
24594
|
+
activeSpinner.clear();
|
|
24595
|
+
return {
|
|
24596
|
+
token,
|
|
24597
|
+
...storeName && { storeName },
|
|
24598
|
+
...terminalFallbackRan && { usedTerminalFallback: true }
|
|
24599
|
+
};
|
|
24600
|
+
};
|
|
24601
|
+
for (let attempt = 1; attempt <= MAX_STORE_NAME_ATTEMPTS; attempt++) {
|
|
24602
|
+
const storeName = candidateStoreName(options.name, attempt);
|
|
24603
|
+
const result = await runVercel(
|
|
24604
|
+
runner,
|
|
24605
|
+
["blob", "create-store", storeName, "--access", "public", "--yes"],
|
|
24606
|
+
{ cwd, mode: "capture", timeoutMs: PROVISION_TIMEOUT_MS, env: options.env }
|
|
24607
|
+
);
|
|
24608
|
+
lastResult = result;
|
|
24609
|
+
if (result.success) {
|
|
24610
|
+
quietSpinner.message("Retrieving the Blob read-write token");
|
|
24611
|
+
return pullToken(quietSpinner, storeName);
|
|
24612
|
+
}
|
|
24613
|
+
if (isEnvVarConflict(result)) {
|
|
24614
|
+
await deleteOrphanStore(runner, cwd, result, options.env);
|
|
24615
|
+
quietSpinner.message("Retrieving the Blob read-write token");
|
|
24616
|
+
return pullToken(quietSpinner);
|
|
24617
|
+
}
|
|
24618
|
+
if (isNameTaken(result)) continue;
|
|
24619
|
+
if (terminalFallbackRan) break;
|
|
24620
|
+
terminalFallbackRan = true;
|
|
24537
24621
|
quietSpinner.clear();
|
|
24538
|
-
|
|
24539
|
-
|
|
24540
|
-
|
|
24541
|
-
|
|
24542
|
-
|
|
24543
|
-
|
|
24544
|
-
|
|
24545
|
-
|
|
24546
|
-
|
|
24547
|
-
|
|
24548
|
-
|
|
24549
|
-
|
|
24550
|
-
|
|
24551
|
-
|
|
24552
|
-
|
|
24553
|
-
|
|
24554
|
-
|
|
24555
|
-
|
|
24556
|
-
|
|
24557
|
-
if (!token) {
|
|
24558
|
-
pullSpinner.stop("No BLOB_READ_WRITE_TOKEN came back from Vercel");
|
|
24559
|
-
return { storeName: quiet.storeName, failure: "env-pull-empty" };
|
|
24622
|
+
p15.log.info(
|
|
24623
|
+
`Create your Blob store in the Vercel prompts below ${pc4.dim(
|
|
24624
|
+
"(connect it to all environments)."
|
|
24625
|
+
)}`
|
|
24626
|
+
);
|
|
24627
|
+
const add = await runVercel(runner, ["blob", "create-store", storeName, "--access", "public"], {
|
|
24628
|
+
cwd,
|
|
24629
|
+
mode: "inherit",
|
|
24630
|
+
timeoutMs: INTERACTIVE_PROVISION_TIMEOUT_MS,
|
|
24631
|
+
env: options.env
|
|
24632
|
+
});
|
|
24633
|
+
if (add.success) {
|
|
24634
|
+
const pullSpinner = spinner2();
|
|
24635
|
+
pullSpinner.start("Retrieving the Blob read-write token");
|
|
24636
|
+
return pullToken(pullSpinner, storeName);
|
|
24637
|
+
}
|
|
24638
|
+
if (add.timedOut) return { failure: "timeout" };
|
|
24639
|
+
lastResult = add;
|
|
24640
|
+
quietSpinner.start("Creating your Vercel Blob store");
|
|
24560
24641
|
}
|
|
24561
|
-
|
|
24562
|
-
return {
|
|
24642
|
+
quietSpinner.stop("Vercel Blob provisioning did not complete");
|
|
24643
|
+
return { failure: lastResult?.timedOut ? "timeout" : "provision-failed" };
|
|
24563
24644
|
}
|
|
24564
24645
|
async function provisionBlobStore(runner, cwd, options) {
|
|
24565
24646
|
const provisionSpinner = spinner2();
|
|
24566
24647
|
provisionSpinner.start("Creating your Vercel Blob store");
|
|
24567
24648
|
const { result, storeName } = await createStoreQuiet(runner, cwd, options.name, options.env);
|
|
24649
|
+
if (!result.success && isEnvVarConflict(result)) {
|
|
24650
|
+
await deleteOrphanStore(runner, cwd, result, options.env);
|
|
24651
|
+
provisionSpinner.message("Retrieving the Blob read-write token");
|
|
24652
|
+
const token2 = await pullBlobToken(runner, cwd, options.env);
|
|
24653
|
+
if (!token2) {
|
|
24654
|
+
provisionSpinner.stop("No BLOB_READ_WRITE_TOKEN came back from Vercel");
|
|
24655
|
+
return { failure: "env-pull-empty" };
|
|
24656
|
+
}
|
|
24657
|
+
provisionSpinner.clear();
|
|
24658
|
+
return { token: token2 };
|
|
24659
|
+
}
|
|
24568
24660
|
if (!result.success) {
|
|
24569
24661
|
provisionSpinner.stop("Vercel Blob provisioning did not complete");
|
|
24570
24662
|
const combined = `${result.stdout}
|
|
@@ -24793,7 +24885,7 @@ function guardEnvLocal(cwd) {
|
|
|
24793
24885
|
}
|
|
24794
24886
|
|
|
24795
24887
|
// adapters/next/init/vercel/neon.ts
|
|
24796
|
-
import * as
|
|
24888
|
+
import * as p16 from "@clack/prompts";
|
|
24797
24889
|
import pc5 from "picocolors";
|
|
24798
24890
|
var PROVISION_TIMEOUT_MS2 = 18e4;
|
|
24799
24891
|
var INTERACTIVE_PROVISION_TIMEOUT_MS2 = 6e5;
|
|
@@ -24811,7 +24903,7 @@ async function provisionNeonInteractive(runner, cwd, options) {
|
|
|
24811
24903
|
return readNeonProvisionInfo(quiet.stdout);
|
|
24812
24904
|
}
|
|
24813
24905
|
quietSpinner.clear();
|
|
24814
|
-
|
|
24906
|
+
p16.log.info(
|
|
24815
24907
|
`Create your Neon database in the Vercel prompts below ${pc5.dim(
|
|
24816
24908
|
"(the Free plan is recommended)."
|
|
24817
24909
|
)}`
|
|
@@ -24885,14 +24977,14 @@ async function runVercelNeonFlow(options) {
|
|
|
24885
24977
|
runnerSpinner.clear();
|
|
24886
24978
|
const auth = await ensureVercelAuth(runner, options.cwd, { env });
|
|
24887
24979
|
if (!auth.authed) {
|
|
24888
|
-
|
|
24980
|
+
p17.log.warn(authFailureMessage(auth.reason));
|
|
24889
24981
|
return { ok: false };
|
|
24890
24982
|
}
|
|
24891
24983
|
const linkLinePrinted = await ensureLinkedProject(runner, options.cwd, options.projectName, env);
|
|
24892
24984
|
const neon = await provisionNeonForMode(runner, options);
|
|
24893
24985
|
if (neon.failure) {
|
|
24894
|
-
|
|
24895
|
-
if (neon.detail)
|
|
24986
|
+
p17.log.warn(neonFailureMessage(neon.failure));
|
|
24987
|
+
if (neon.detail) p17.log.message(pc6.dim(neon.detail));
|
|
24896
24988
|
return { ok: false };
|
|
24897
24989
|
}
|
|
24898
24990
|
const databaseUrl = await pullNeonDatabaseUrl(runner, options.cwd, env);
|
|
@@ -24905,7 +24997,7 @@ async function runVercelNeonFlow(options) {
|
|
|
24905
24997
|
dismissSignedInNote
|
|
24906
24998
|
};
|
|
24907
24999
|
} catch (error) {
|
|
24908
|
-
|
|
25000
|
+
p17.log.warn(
|
|
24909
25001
|
`Vercel provisioning failed: ${error instanceof Error ? error.message : String(error)}`
|
|
24910
25002
|
);
|
|
24911
25003
|
return { ok: false };
|
|
@@ -24923,14 +25015,14 @@ async function runVercelBlobFlow(options) {
|
|
|
24923
25015
|
runnerSpinner.clear();
|
|
24924
25016
|
const auth = await ensureVercelAuth(runner, options.cwd, { env, quietIfAuthed: true });
|
|
24925
25017
|
if (!auth.authed) {
|
|
24926
|
-
|
|
25018
|
+
p17.log.warn(authFailureMessage(auth.reason));
|
|
24927
25019
|
return { ok: false };
|
|
24928
25020
|
}
|
|
24929
25021
|
await ensureLinkedProject(runner, options.cwd, options.projectName, env);
|
|
24930
25022
|
const blob = await provisionBlobForMode(runner, options);
|
|
24931
25023
|
if (blob.failure || !blob.token) {
|
|
24932
|
-
|
|
24933
|
-
if (blob.detail)
|
|
25024
|
+
p17.log.warn(blobFailureMessage(blob.failure));
|
|
25025
|
+
if (blob.detail) p17.log.message(pc6.dim(blob.detail));
|
|
24934
25026
|
return { ok: false };
|
|
24935
25027
|
}
|
|
24936
25028
|
return {
|
|
@@ -24940,7 +25032,7 @@ async function runVercelBlobFlow(options) {
|
|
|
24940
25032
|
usedTerminalFallback: blob.usedTerminalFallback
|
|
24941
25033
|
};
|
|
24942
25034
|
} catch (error) {
|
|
24943
|
-
|
|
25035
|
+
p17.log.warn(
|
|
24944
25036
|
`Vercel provisioning failed: ${error instanceof Error ? error.message : String(error)}`
|
|
24945
25037
|
);
|
|
24946
25038
|
return { ok: false };
|
|
@@ -24958,7 +25050,7 @@ async function runVercelDeployFlow(options) {
|
|
|
24958
25050
|
runnerSpinner.clear();
|
|
24959
25051
|
const auth = await ensureVercelAuth(runner, options.cwd, { env, quietIfAuthed: true });
|
|
24960
25052
|
if (!auth.authed) {
|
|
24961
|
-
|
|
25053
|
+
p17.log.warn(authFailureMessage(auth.reason));
|
|
24962
25054
|
printManualDeployHint();
|
|
24963
25055
|
return { ok: false };
|
|
24964
25056
|
}
|
|
@@ -24976,17 +25068,17 @@ async function runVercelDeployFlow(options) {
|
|
|
24976
25068
|
let printedWarnings = false;
|
|
24977
25069
|
for (const key of sync.failed) {
|
|
24978
25070
|
printedWarnings = true;
|
|
24979
|
-
|
|
25071
|
+
p17.log.warn(
|
|
24980
25072
|
`Could not set ${pc6.cyan(key)} on Vercel \u2014 add it in the project's environment settings.`
|
|
24981
25073
|
);
|
|
24982
25074
|
}
|
|
24983
25075
|
if (ensureVercelJsonFramework(options.cwd) === "created") {
|
|
24984
|
-
|
|
25076
|
+
p17.log.success(`Created ${pc6.cyan("vercel.json")} with the Next.js framework preset`);
|
|
24985
25077
|
}
|
|
24986
25078
|
const packageGuard = guardProjectForDeploy(options.cwd);
|
|
24987
25079
|
for (const dep of packageGuard.localSpecDeps) {
|
|
24988
25080
|
printedWarnings = true;
|
|
24989
|
-
|
|
25081
|
+
p17.log.warn(
|
|
24990
25082
|
`Dependency ${pc6.cyan(dep)} uses a local spec that cannot install on Vercel \u2014 the remote build may fail.`
|
|
24991
25083
|
);
|
|
24992
25084
|
}
|
|
@@ -25000,7 +25092,7 @@ async function runVercelDeployFlow(options) {
|
|
|
25000
25092
|
}
|
|
25001
25093
|
if (deploy.failure) {
|
|
25002
25094
|
deploySpinner.stop(`${pc6.yellow("\u25B2")} ${deployFailureMessage(deploy.failure)}`);
|
|
25003
|
-
if (deploy.detail)
|
|
25095
|
+
if (deploy.detail) p17.log.message(pc6.dim(deploy.detail));
|
|
25004
25096
|
printManualDeployHint();
|
|
25005
25097
|
return { ok: false };
|
|
25006
25098
|
}
|
|
@@ -25009,7 +25101,7 @@ async function runVercelDeployFlow(options) {
|
|
|
25009
25101
|
deploySpinner.stop(url ? `Deployed ${pc6.cyan(url)}` : "Deployed to Vercel");
|
|
25010
25102
|
return { ok: true, url, syncedEnvKeys: sync.synced, cleanScreen: !printedWarnings };
|
|
25011
25103
|
} catch (error) {
|
|
25012
|
-
|
|
25104
|
+
p17.log.warn(`Vercel deploy failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
25013
25105
|
printManualDeployHint();
|
|
25014
25106
|
return { ok: false };
|
|
25015
25107
|
} finally {
|
|
@@ -25017,7 +25109,7 @@ async function runVercelDeployFlow(options) {
|
|
|
25017
25109
|
}
|
|
25018
25110
|
}
|
|
25019
25111
|
function printManualDeployHint() {
|
|
25020
|
-
|
|
25112
|
+
p17.log.info(`You can deploy manually: ${pc6.cyan("vercel deploy --prod")}`);
|
|
25021
25113
|
}
|
|
25022
25114
|
async function ensureLinkedProject(runner, cwd, projectName, env) {
|
|
25023
25115
|
if (readLinkedProjectId(cwd)) return false;
|
|
@@ -25065,11 +25157,11 @@ function authFailureMessage(reason) {
|
|
|
25065
25157
|
function blobFailureMessage(reason) {
|
|
25066
25158
|
switch (reason) {
|
|
25067
25159
|
case "env-pull-empty":
|
|
25068
|
-
return "Created a Blob store, but no BLOB_READ_WRITE_TOKEN came back
|
|
25160
|
+
return "Created a Blob store, but no BLOB_READ_WRITE_TOKEN came back from Vercel.";
|
|
25069
25161
|
case "timeout":
|
|
25070
|
-
return "Vercel Blob provisioning timed out
|
|
25162
|
+
return "Vercel Blob provisioning timed out.";
|
|
25071
25163
|
default:
|
|
25072
|
-
return "Vercel Blob provisioning did not complete
|
|
25164
|
+
return "Vercel Blob provisioning did not complete.";
|
|
25073
25165
|
}
|
|
25074
25166
|
}
|
|
25075
25167
|
function deployFailureMessage(reason) {
|
|
@@ -25483,7 +25575,8 @@ function removeExistingAdminPaths(cwd, namespaces) {
|
|
|
25483
25575
|
}
|
|
25484
25576
|
async function runInitCommand(name, options) {
|
|
25485
25577
|
installPromptCheckmarks();
|
|
25486
|
-
|
|
25578
|
+
const disposeCancelGuard = installSetupCancelGuard();
|
|
25579
|
+
p18.box(
|
|
25487
25580
|
`
|
|
25488
25581
|
\u2584 \u2597 \u2597 \u2584\u2596\u2597 \u2597
|
|
25489
25582
|
\u2599\u2598\u2588\u258C\u259C\u2598\u259C\u2598\u2588\u258C\u259B\u2598\u259A \u259C\u2598\u2580\u258C\u259B\u2598\u259C\u2598
|
|
@@ -25504,13 +25597,13 @@ async function runInitCommand(name, options) {
|
|
|
25504
25597
|
try {
|
|
25505
25598
|
namespace = validateAdminNamespace(options.namespace);
|
|
25506
25599
|
} catch (error) {
|
|
25507
|
-
|
|
25600
|
+
p18.log.error(error instanceof Error ? error.message : String(error));
|
|
25508
25601
|
process.exit(1);
|
|
25509
25602
|
}
|
|
25510
25603
|
}
|
|
25511
25604
|
if (!options.yes && !options.namespace) {
|
|
25512
25605
|
const defaultDashboardPath = resolveAdminNamespace(DEFAULT_ADMIN_NAMESPACE).routePath;
|
|
25513
|
-
const namespaceInput = await
|
|
25606
|
+
const namespaceInput = await p18.text({
|
|
25514
25607
|
message: "Enter the dashboard path",
|
|
25515
25608
|
placeholder: `eg. ${defaultDashboardPath}`,
|
|
25516
25609
|
defaultValue: defaultDashboardPath,
|
|
@@ -25523,8 +25616,8 @@ async function runInitCommand(name, options) {
|
|
|
25523
25616
|
}
|
|
25524
25617
|
}
|
|
25525
25618
|
});
|
|
25526
|
-
if (
|
|
25527
|
-
|
|
25619
|
+
if (p18.isCancel(namespaceInput)) {
|
|
25620
|
+
p18.cancel("Setup cancelled.");
|
|
25528
25621
|
process.exit(0);
|
|
25529
25622
|
}
|
|
25530
25623
|
namespace = validateAdminDashboardPath(namespaceInput);
|
|
@@ -25536,13 +25629,13 @@ async function runInitCommand(name, options) {
|
|
|
25536
25629
|
if (project2.isExisting) {
|
|
25537
25630
|
srcDir = project2.hasSrcDir;
|
|
25538
25631
|
if (!project2.hasTypeScript) {
|
|
25539
|
-
|
|
25632
|
+
p18.log.error("TypeScript is required. Please add a tsconfig.json first.");
|
|
25540
25633
|
process.exit(1);
|
|
25541
25634
|
}
|
|
25542
25635
|
if (forceMode) {
|
|
25543
25636
|
const nuked = removeExistingAdminPaths(cwd, await resolveForceInitNamespaces(cwd, namespace));
|
|
25544
25637
|
if (nuked > 0) {
|
|
25545
|
-
|
|
25638
|
+
p18.log.warn(`${pc7.yellow("Force mode:")} removed ${nuked} existing admin paths`);
|
|
25546
25639
|
}
|
|
25547
25640
|
project2 = detectProject(cwd, namespace);
|
|
25548
25641
|
} else if (project2.conflicts.length > 0) {
|
|
@@ -25551,9 +25644,9 @@ async function runInitCommand(name, options) {
|
|
|
25551
25644
|
"",
|
|
25552
25645
|
pc7.dim(`Use ${pc7.bold("--force")} to remove existing admin files before scaffolding.`)
|
|
25553
25646
|
);
|
|
25554
|
-
|
|
25647
|
+
p18.note(conflictLines.join("\n"), pc7.yellow("Conflicts"));
|
|
25555
25648
|
if (!options.yes) {
|
|
25556
|
-
const proceed = await
|
|
25649
|
+
const proceed = await p18.confirm({
|
|
25557
25650
|
message: [
|
|
25558
25651
|
`Continue with ${pc7.bold(pc7.cyan("--force"))}?`,
|
|
25559
25652
|
`${pc7.cyan("\u2502")} ${pc7.dim("This will force overwrite the existing admin code.")}`,
|
|
@@ -25561,8 +25654,8 @@ async function runInitCommand(name, options) {
|
|
|
25561
25654
|
].join("\n"),
|
|
25562
25655
|
initialValue: true
|
|
25563
25656
|
});
|
|
25564
|
-
if (
|
|
25565
|
-
|
|
25657
|
+
if (p18.isCancel(proceed) || !proceed) {
|
|
25658
|
+
p18.cancel("Setup cancelled.");
|
|
25566
25659
|
process.exit(0);
|
|
25567
25660
|
}
|
|
25568
25661
|
forceMode = true;
|
|
@@ -25571,23 +25664,23 @@ async function runInitCommand(name, options) {
|
|
|
25571
25664
|
await resolveForceInitNamespaces(cwd, namespace)
|
|
25572
25665
|
);
|
|
25573
25666
|
if (nuked > 0) {
|
|
25574
|
-
|
|
25667
|
+
p18.log.warn(`${pc7.yellow("Force mode:")} removed ${nuked} existing admin paths`);
|
|
25575
25668
|
}
|
|
25576
25669
|
project2 = detectProject(cwd, namespace);
|
|
25577
25670
|
}
|
|
25578
25671
|
}
|
|
25579
25672
|
} else {
|
|
25580
|
-
|
|
25673
|
+
p18.log.info("No Next.js app found \u2014 Running the fresh project mode...");
|
|
25581
25674
|
let projectPrompt;
|
|
25582
25675
|
try {
|
|
25583
25676
|
projectPrompt = options.yes ? resolveNonInteractiveProject(name) : await promptProject(name);
|
|
25584
25677
|
} catch (error) {
|
|
25585
|
-
|
|
25678
|
+
p18.log.error(error instanceof Error ? error.message : String(error));
|
|
25586
25679
|
process.exit(1);
|
|
25587
25680
|
}
|
|
25588
25681
|
srcDir = projectPrompt.useSrcDir;
|
|
25589
25682
|
if (!options.yes) {
|
|
25590
|
-
const pmChoice = await
|
|
25683
|
+
const pmChoice = await p18.select({
|
|
25591
25684
|
message: "Which package manager do you want to use?",
|
|
25592
25685
|
options: [
|
|
25593
25686
|
{ value: "pnpm", label: "pnpm", hint: "recommended" },
|
|
@@ -25596,8 +25689,8 @@ async function runInitCommand(name, options) {
|
|
|
25596
25689
|
{ value: "bun", label: "bun" }
|
|
25597
25690
|
]
|
|
25598
25691
|
});
|
|
25599
|
-
if (
|
|
25600
|
-
|
|
25692
|
+
if (p18.isCancel(pmChoice)) {
|
|
25693
|
+
p18.cancel("Setup cancelled.");
|
|
25601
25694
|
process.exit(0);
|
|
25602
25695
|
}
|
|
25603
25696
|
pm = pmChoice;
|
|
@@ -25631,8 +25724,8 @@ async function runInitCommand(name, options) {
|
|
|
25631
25724
|
process.stderr.write(`${createNextAppResult.output.trimEnd()}
|
|
25632
25725
|
`);
|
|
25633
25726
|
}
|
|
25634
|
-
|
|
25635
|
-
|
|
25727
|
+
p18.log.error(createNextAppResult.error);
|
|
25728
|
+
p18.log.info(
|
|
25636
25729
|
`You can create the project manually:
|
|
25637
25730
|
${pc7.cyan(`npx create-next-app@latest ${projectPrompt.projectName} --typescript --tailwind --app`)}
|
|
25638
25731
|
Then run ${pc7.cyan("betterstart init")} inside it.`
|
|
@@ -25646,11 +25739,11 @@ async function runInitCommand(name, options) {
|
|
|
25646
25739
|
);
|
|
25647
25740
|
if (!hasPackageJson || !hasNextConfig) {
|
|
25648
25741
|
createNextAppSpinner.stop(`Failed to create Next.js app: ${displayName}`);
|
|
25649
|
-
|
|
25742
|
+
p18.log.error(
|
|
25650
25743
|
"create-next-app completed but the project was not created. This can happen with nested npx calls."
|
|
25651
25744
|
);
|
|
25652
25745
|
const manualCmd = `npx create-next-app@latest ${projectPrompt.projectName} --typescript --tailwind --app`;
|
|
25653
|
-
|
|
25746
|
+
p18.log.info(
|
|
25654
25747
|
`Create the project manually:
|
|
25655
25748
|
${pc7.cyan(manualCmd)}
|
|
25656
25749
|
Then run ${pc7.cyan("betterstart init")} inside it.`
|
|
@@ -25669,7 +25762,7 @@ async function runInitCommand(name, options) {
|
|
|
25669
25762
|
if (options.yes) {
|
|
25670
25763
|
if (options.databaseUrl) {
|
|
25671
25764
|
if (!isValidDbUrl(options.databaseUrl)) {
|
|
25672
|
-
|
|
25765
|
+
p18.log.error(
|
|
25673
25766
|
`Invalid database URL. Must start with ${pc7.cyan("postgres://")} or ${pc7.cyan("postgresql://")}`
|
|
25674
25767
|
);
|
|
25675
25768
|
process.exit(1);
|
|
@@ -25689,24 +25782,24 @@ async function runInitCommand(name, options) {
|
|
|
25689
25782
|
databaseUrl = flow.databaseUrl;
|
|
25690
25783
|
persistDatabaseUrl(cwd, databaseUrl);
|
|
25691
25784
|
} else if (flow.ok) {
|
|
25692
|
-
|
|
25785
|
+
p18.log.warn("Created a Neon database, but DATABASE_URL could not be retrieved from Vercel.");
|
|
25693
25786
|
const resourceUrl = flow.dashboardUrl ?? flow.resourceUrl;
|
|
25694
25787
|
if (resourceUrl) {
|
|
25695
|
-
|
|
25788
|
+
p18.log.info(
|
|
25696
25789
|
`Open ${pc7.cyan(resourceUrl)} to copy DATABASE_URL, then rerun ${pc7.cyan("betterstart init --database-url <url> --yes")}.`
|
|
25697
25790
|
);
|
|
25698
25791
|
} else {
|
|
25699
|
-
|
|
25792
|
+
p18.log.info(
|
|
25700
25793
|
`Rerun ${pc7.cyan("betterstart init --database-url <url> --yes")} with a Postgres connection string.`
|
|
25701
25794
|
);
|
|
25702
25795
|
}
|
|
25703
25796
|
} else {
|
|
25704
|
-
|
|
25797
|
+
p18.log.warn("Vercel provisioning did not complete; continuing without a database URL.");
|
|
25705
25798
|
}
|
|
25706
25799
|
}
|
|
25707
25800
|
} else if (existingDbUrl) {
|
|
25708
25801
|
const masked = maskDbUrl(existingDbUrl);
|
|
25709
|
-
|
|
25802
|
+
p18.log.info(`Using existing database URL from .env.local ${pc7.dim(`(${masked})`)}`);
|
|
25710
25803
|
databaseUrl = existingDbUrl;
|
|
25711
25804
|
} else {
|
|
25712
25805
|
const databaseStep = deferNextPromptCheck();
|
|
@@ -25732,7 +25825,7 @@ async function runInitCommand(name, options) {
|
|
|
25732
25825
|
persistDatabaseUrl(cwd, databaseUrl);
|
|
25733
25826
|
} else {
|
|
25734
25827
|
databaseStep.skip();
|
|
25735
|
-
|
|
25828
|
+
p18.log.info("Falling back to a manual database connection string.");
|
|
25736
25829
|
openBrowserVercelNeon();
|
|
25737
25830
|
databaseUrl = await promptConnectionString();
|
|
25738
25831
|
}
|
|
@@ -25774,21 +25867,20 @@ async function runInitCommand(name, options) {
|
|
|
25774
25867
|
});
|
|
25775
25868
|
if (flow.ok && flow.token) {
|
|
25776
25869
|
persistBlobReadWriteToken(cwd, flow.token);
|
|
25777
|
-
|
|
25870
|
+
p18.log.success(`Saved BLOB_READ_WRITE_TOKEN to ${pc7.cyan(".env.local")}`);
|
|
25778
25871
|
collectedIntegrationConfig.sections.push({
|
|
25779
25872
|
header: "Storage (Vercel Blob)",
|
|
25780
25873
|
vars: [{ key: "BLOB_READ_WRITE_TOKEN", value: flow.token }]
|
|
25781
25874
|
});
|
|
25782
25875
|
collectedIntegrationConfig.overwriteKeys.add("BLOB_READ_WRITE_TOKEN");
|
|
25783
|
-
} else if (!options.yes) {
|
|
25784
|
-
p17.log.info("Falling back to a manual Vercel Blob token.");
|
|
25785
|
-
const collected = await collectIntegrationConfig(cwd, ["vercel-blob"]);
|
|
25786
|
-
collectedIntegrationConfig.sections.push(...collected.sections);
|
|
25787
|
-
for (const key of collected.overwriteKeys) {
|
|
25788
|
-
collectedIntegrationConfig.overwriteKeys.add(key);
|
|
25789
|
-
}
|
|
25790
25876
|
} else {
|
|
25791
|
-
|
|
25877
|
+
p18.log.warn(
|
|
25878
|
+
"Continuing without a Blob token \u2014 add BLOB_READ_WRITE_TOKEN to .env.local from the store on vercel.com/dashboard/stores."
|
|
25879
|
+
);
|
|
25880
|
+
collectedIntegrationConfig.sections.push({
|
|
25881
|
+
header: "Storage (Vercel Blob)",
|
|
25882
|
+
vars: [{ key: "BLOB_READ_WRITE_TOKEN", value: "" }]
|
|
25883
|
+
});
|
|
25792
25884
|
}
|
|
25793
25885
|
}
|
|
25794
25886
|
} else if (options.yes) {
|
|
@@ -25891,7 +25983,7 @@ async function runInitCommand(name, options) {
|
|
|
25891
25983
|
});
|
|
25892
25984
|
s.stop("");
|
|
25893
25985
|
process.stdout.write("\x1B[2A\x1B[J");
|
|
25894
|
-
|
|
25986
|
+
p18.note(noteLines.join("\n"), "Scaffolded admin");
|
|
25895
25987
|
const drizzleConfigPath = path50.join(cwd, "drizzle.config.ts");
|
|
25896
25988
|
if (!dbFiles.includes("drizzle.config.ts") && fs39.existsSync(drizzleConfigPath)) {
|
|
25897
25989
|
if (forceMode) {
|
|
@@ -25901,20 +25993,20 @@ async function runInitCommand(name, options) {
|
|
|
25901
25993
|
readNamespacedTemplate("drizzle.config.ts", namespace),
|
|
25902
25994
|
"utf-8"
|
|
25903
25995
|
);
|
|
25904
|
-
|
|
25996
|
+
p18.log.success("Updated drizzle.config.ts");
|
|
25905
25997
|
} else if (!options.yes) {
|
|
25906
|
-
const overwrite = await
|
|
25998
|
+
const overwrite = await p18.confirm({
|
|
25907
25999
|
message: "drizzle.config.ts already exists. Overwrite with latest version?",
|
|
25908
26000
|
initialValue: true
|
|
25909
26001
|
});
|
|
25910
|
-
if (!
|
|
26002
|
+
if (!p18.isCancel(overwrite) && overwrite) {
|
|
25911
26003
|
const { readNamespacedTemplate } = await import("./template-reader-X6KFP7B3.js");
|
|
25912
26004
|
fs39.writeFileSync(
|
|
25913
26005
|
drizzleConfigPath,
|
|
25914
26006
|
readNamespacedTemplate("drizzle.config.ts", namespace),
|
|
25915
26007
|
"utf-8"
|
|
25916
26008
|
);
|
|
25917
|
-
|
|
26009
|
+
p18.log.success("Updated drizzle.config.ts");
|
|
25918
26010
|
}
|
|
25919
26011
|
}
|
|
25920
26012
|
}
|
|
@@ -25940,8 +26032,8 @@ async function runInitCommand(name, options) {
|
|
|
25940
26032
|
depsInstalled = true;
|
|
25941
26033
|
} else {
|
|
25942
26034
|
s.stop("Failed to install dependencies");
|
|
25943
|
-
|
|
25944
|
-
|
|
26035
|
+
p18.log.warning(depsResult.error ?? "Unknown error");
|
|
26036
|
+
p18.log.info(
|
|
25945
26037
|
`You can install them manually:
|
|
25946
26038
|
${pc7.cyan(`${pm} add ${depsResult.dependencies.join(" ")}`)}
|
|
25947
26039
|
${pc7.cyan(`${pm} add -D ${depsResult.devDeps.join(" ")}`)}`
|
|
@@ -26031,10 +26123,10 @@ async function runInitCommand(name, options) {
|
|
|
26031
26123
|
` ${pc7.yellow("\u25B2")} Local filesystem storage is only for development or self-hosted persistent-disk deployments. Use Vercel Blob or Cloudflare R2 for hosted/serverless production.`
|
|
26032
26124
|
);
|
|
26033
26125
|
}
|
|
26034
|
-
|
|
26126
|
+
p18.note(installLines.join("\n"), "Installed");
|
|
26035
26127
|
let dbPushed = false;
|
|
26036
26128
|
if (depsResult.success && options.skipMigration && hasDbUrl(cwd)) {
|
|
26037
|
-
|
|
26129
|
+
p18.log.info(`Skipping database schema push ${pc7.dim("(--skip-migration)")}`);
|
|
26038
26130
|
} else if (depsResult.success && hasDbUrl(cwd)) {
|
|
26039
26131
|
let driverReady = hasDrizzleKitPostgresDriverDependency(cwd);
|
|
26040
26132
|
if (!driverReady) {
|
|
@@ -26049,8 +26141,8 @@ async function runInitCommand(name, options) {
|
|
|
26049
26141
|
});
|
|
26050
26142
|
if (!driverResult.success) {
|
|
26051
26143
|
s.stop("Database push failed");
|
|
26052
|
-
|
|
26053
|
-
|
|
26144
|
+
p18.log.warning(driverResult.error ?? `Failed to install ${DRIZZLE_KIT_POSTGRES_DRIVER_DEP}`);
|
|
26145
|
+
p18.log.info(
|
|
26054
26146
|
`Install ${DRIZZLE_KIT_POSTGRES_DRIVER_DEP} manually, then run: ${pc7.cyan(drizzlePushCommand(pm))}`
|
|
26055
26147
|
);
|
|
26056
26148
|
} else {
|
|
@@ -26061,7 +26153,7 @@ async function runInitCommand(name, options) {
|
|
|
26061
26153
|
if (driverReady) {
|
|
26062
26154
|
const useTerminalForDbPush = shouldUseTerminalForDbPush(options);
|
|
26063
26155
|
if (useTerminalForDbPush) {
|
|
26064
|
-
|
|
26156
|
+
p18.log.info(`Running ${pc7.cyan("drizzle-kit push --force")}`);
|
|
26065
26157
|
} else {
|
|
26066
26158
|
s.start("Pushing database schema (drizzle-kit push)");
|
|
26067
26159
|
}
|
|
@@ -26070,13 +26162,13 @@ async function runInitCommand(name, options) {
|
|
|
26070
26162
|
if (useTerminalForDbPush) {
|
|
26071
26163
|
const verification = await verifyDatabaseReachable(cwd);
|
|
26072
26164
|
if (!verification.success) {
|
|
26073
|
-
|
|
26074
|
-
|
|
26165
|
+
p18.log.warning(verification.error);
|
|
26166
|
+
p18.log.error("Database was not reachable. Aborting setup.");
|
|
26075
26167
|
process.exit(1);
|
|
26076
26168
|
}
|
|
26077
26169
|
}
|
|
26078
26170
|
if (useTerminalForDbPush) {
|
|
26079
|
-
|
|
26171
|
+
p18.log.success("Database schema pushed");
|
|
26080
26172
|
} else {
|
|
26081
26173
|
s.stop(`${pc7.green("\u2713")} Database schema pushed`);
|
|
26082
26174
|
}
|
|
@@ -26086,12 +26178,12 @@ async function runInitCommand(name, options) {
|
|
|
26086
26178
|
s.stop("Database push failed");
|
|
26087
26179
|
}
|
|
26088
26180
|
const pushError = pushResult.error ?? "Unknown error";
|
|
26089
|
-
|
|
26181
|
+
p18.log.warning(pushError);
|
|
26090
26182
|
if (isDatabaseReachabilityError(pushError)) {
|
|
26091
|
-
|
|
26183
|
+
p18.log.error("Database was not reachable. Aborting setup.");
|
|
26092
26184
|
process.exit(1);
|
|
26093
26185
|
}
|
|
26094
|
-
|
|
26186
|
+
p18.log.info(`You can run it manually: ${pc7.cyan(drizzlePushCommand(pm))}`);
|
|
26095
26187
|
}
|
|
26096
26188
|
}
|
|
26097
26189
|
}
|
|
@@ -26100,7 +26192,7 @@ async function runInitCommand(name, options) {
|
|
|
26100
26192
|
let seedSuccess = false;
|
|
26101
26193
|
let adminAccountReady = false;
|
|
26102
26194
|
if (dbPushed && options.skipAdminCreation) {
|
|
26103
|
-
|
|
26195
|
+
p18.log.info(
|
|
26104
26196
|
`Skipping admin user creation ${pc7.dim(`(use ${betterstartExecCommand(pm, "seed")} later)`)}`
|
|
26105
26197
|
);
|
|
26106
26198
|
}
|
|
@@ -26110,14 +26202,14 @@ async function runInitCommand(name, options) {
|
|
|
26110
26202
|
let replaceExistingAdmin = false;
|
|
26111
26203
|
const adminCheck = await checkExistingAdmin(cwd, adminDir, authBasePath);
|
|
26112
26204
|
if (adminCheck.error) {
|
|
26113
|
-
|
|
26205
|
+
p18.log.warning(`Could not verify existing admin account ${pc7.dim(`(${adminCheck.error})`)}`);
|
|
26114
26206
|
if (isDatabaseReachabilityError(adminCheck.error)) {
|
|
26115
|
-
|
|
26207
|
+
p18.log.error("Database was not reachable. Aborting setup.");
|
|
26116
26208
|
process.exit(1);
|
|
26117
26209
|
}
|
|
26118
26210
|
} else if (adminCheck.existingAdmin) {
|
|
26119
26211
|
const existingAdminLabel = formatAdminIdentity(adminCheck.existingAdmin);
|
|
26120
|
-
const adminAction = await
|
|
26212
|
+
const adminAction = await p18.select({
|
|
26121
26213
|
message: "Found an already existing admin account. Do you want to replace it or skip?",
|
|
26122
26214
|
options: [
|
|
26123
26215
|
{
|
|
@@ -26131,34 +26223,34 @@ async function runInitCommand(name, options) {
|
|
|
26131
26223
|
}
|
|
26132
26224
|
]
|
|
26133
26225
|
});
|
|
26134
|
-
if (
|
|
26135
|
-
|
|
26226
|
+
if (p18.isCancel(adminAction)) {
|
|
26227
|
+
p18.cancel("Setup cancelled.");
|
|
26136
26228
|
process.exit(0);
|
|
26137
26229
|
}
|
|
26138
26230
|
if (adminAction === "skip") {
|
|
26139
26231
|
adminAccountReady = true;
|
|
26140
|
-
|
|
26232
|
+
p18.log.info(`Keeping existing admin account ${pc7.dim(`(${existingAdminLabel})`)}`);
|
|
26141
26233
|
} else {
|
|
26142
26234
|
replaceExistingAdmin = true;
|
|
26143
26235
|
}
|
|
26144
26236
|
}
|
|
26145
26237
|
if (!adminAccountReady) {
|
|
26146
|
-
|
|
26238
|
+
p18.note(
|
|
26147
26239
|
pc7.dim(
|
|
26148
26240
|
replaceExistingAdmin ? "Replace the existing admin account to access the admin." : "Create your first admin user to access the dashboard."
|
|
26149
26241
|
),
|
|
26150
26242
|
"Admin account"
|
|
26151
26243
|
);
|
|
26152
|
-
const credentials = await
|
|
26244
|
+
const credentials = await p18.group(
|
|
26153
26245
|
{
|
|
26154
|
-
email: () =>
|
|
26246
|
+
email: () => p18.text({
|
|
26155
26247
|
message: "Admin email",
|
|
26156
26248
|
placeholder: "admin@example.com",
|
|
26157
26249
|
validate: (v) => {
|
|
26158
26250
|
if (!v || !v.includes("@")) return "Please enter a valid email";
|
|
26159
26251
|
}
|
|
26160
26252
|
}),
|
|
26161
|
-
password: () =>
|
|
26253
|
+
password: () => p18.password({
|
|
26162
26254
|
message: "Admin password",
|
|
26163
26255
|
validate: (v) => {
|
|
26164
26256
|
if (!v || v.length < 8) return "Password must be at least 8 characters";
|
|
@@ -26167,7 +26259,7 @@ async function runInitCommand(name, options) {
|
|
|
26167
26259
|
},
|
|
26168
26260
|
{
|
|
26169
26261
|
onCancel: () => {
|
|
26170
|
-
|
|
26262
|
+
p18.cancel("Setup cancelled.");
|
|
26171
26263
|
process.exit(0);
|
|
26172
26264
|
}
|
|
26173
26265
|
}
|
|
@@ -26186,11 +26278,11 @@ async function runInitCommand(name, options) {
|
|
|
26186
26278
|
);
|
|
26187
26279
|
if (seedResult.existingUser) {
|
|
26188
26280
|
s.stop(`${pc7.yellow("\u25B2")} An account already exists for ${credentials.email}`);
|
|
26189
|
-
const replace = await
|
|
26281
|
+
const replace = await p18.confirm({
|
|
26190
26282
|
message: "Replace the existing account with this email?",
|
|
26191
26283
|
initialValue: false
|
|
26192
26284
|
});
|
|
26193
|
-
if (!
|
|
26285
|
+
if (!p18.isCancel(replace) && replace) {
|
|
26194
26286
|
seedOverwriteMode = "email";
|
|
26195
26287
|
s.start("Replacing admin user");
|
|
26196
26288
|
seedResult = await runSeed(
|
|
@@ -26211,14 +26303,14 @@ async function runInitCommand(name, options) {
|
|
|
26211
26303
|
adminAccountReady = true;
|
|
26212
26304
|
} else if (seedResult.error) {
|
|
26213
26305
|
s.stop(`${pc7.red("\u2717")} Failed to create admin user`);
|
|
26214
|
-
|
|
26306
|
+
p18.note(
|
|
26215
26307
|
`${pc7.red(seedResult.error)}
|
|
26216
26308
|
|
|
26217
26309
|
Run manually: ${pc7.cyan(betterstartExecCommand(pm, "seed"))}`,
|
|
26218
26310
|
pc7.red("Seed failed")
|
|
26219
26311
|
);
|
|
26220
26312
|
if (isDatabaseReachabilityError(seedResult.error)) {
|
|
26221
|
-
|
|
26313
|
+
p18.log.error("Database was not reachable. Aborting setup.");
|
|
26222
26314
|
process.exit(1);
|
|
26223
26315
|
}
|
|
26224
26316
|
}
|
|
@@ -26250,16 +26342,16 @@ Run manually: ${pc7.cyan(betterstartExecCommand(pm, "seed"))}`,
|
|
|
26250
26342
|
`Files created: ${pc7.cyan(String(totalFiles))}`,
|
|
26251
26343
|
`Env vars: ${envResult.added.length} added, ${envResult.skipped.length} skipped`
|
|
26252
26344
|
];
|
|
26253
|
-
|
|
26345
|
+
p18.note(summaryLines.join("\n"), "Admin scaffolded successfully");
|
|
26254
26346
|
if (options.vercel !== false && !options.skipDeploy) {
|
|
26255
26347
|
const linkedVercelProject = Boolean(readLinkedProjectId(cwd));
|
|
26256
26348
|
if (!options.yes) {
|
|
26257
26349
|
const deployStep = deferNextPromptCheck();
|
|
26258
|
-
const deployNow = await
|
|
26350
|
+
const deployNow = await p18.confirm({
|
|
26259
26351
|
message: "Deploy to Vercel now?",
|
|
26260
26352
|
initialValue: linkedVercelProject
|
|
26261
26353
|
});
|
|
26262
|
-
if (!
|
|
26354
|
+
if (!p18.isCancel(deployNow) && deployNow) {
|
|
26263
26355
|
const deployFlow = await runVercelDeployFlow({ cwd, projectName, env: process.env });
|
|
26264
26356
|
if (deployFlow.ok && deployFlow.cleanScreen) deployStep.confirm();
|
|
26265
26357
|
else deployStep.skip();
|
|
@@ -26273,17 +26365,18 @@ Run manually: ${pc7.cyan(betterstartExecCommand(pm, "seed"))}`,
|
|
|
26273
26365
|
env: process.env
|
|
26274
26366
|
});
|
|
26275
26367
|
if (!deployFlow.ok) {
|
|
26276
|
-
|
|
26368
|
+
p18.log.warn("Vercel deploy did not complete; continuing.");
|
|
26277
26369
|
}
|
|
26278
26370
|
}
|
|
26279
26371
|
}
|
|
26280
26372
|
if (!options.yes && !options.skipDevServerStart) {
|
|
26281
26373
|
const devCmd = runCommand(pm, "dev");
|
|
26282
|
-
const startDev = await
|
|
26374
|
+
const startDev = await p18.confirm({
|
|
26283
26375
|
message: "Start the development server?",
|
|
26284
26376
|
initialValue: true
|
|
26285
26377
|
});
|
|
26286
|
-
if (!
|
|
26378
|
+
if (!p18.isCancel(startDev) && startDev) {
|
|
26379
|
+
disposeCancelGuard();
|
|
26287
26380
|
await startManagedDevServer(cwd, devCmd, adminLoginUrl, {
|
|
26288
26381
|
email: seedSuccess && seedEmail ? seedEmail : void 0,
|
|
26289
26382
|
password: seedSuccess && seedPassword ? seedPassword : void 0
|
|
@@ -26291,7 +26384,8 @@ Run manually: ${pc7.cyan(betterstartExecCommand(pm, "seed"))}`,
|
|
|
26291
26384
|
return;
|
|
26292
26385
|
}
|
|
26293
26386
|
}
|
|
26294
|
-
|
|
26387
|
+
disposeCancelGuard();
|
|
26388
|
+
p18.outro("Done!");
|
|
26295
26389
|
}
|
|
26296
26390
|
function isValidDbUrl(url) {
|
|
26297
26391
|
return url.startsWith("postgres://") || url.startsWith("postgresql://");
|
|
@@ -26678,7 +26772,7 @@ function printAdminReadyNote(state) {
|
|
|
26678
26772
|
lines.unshift(`Password: ${pc7.cyan(state.adminPassword)}`);
|
|
26679
26773
|
lines.unshift(`Admin user: ${pc7.cyan(state.adminEmail)}`);
|
|
26680
26774
|
}
|
|
26681
|
-
|
|
26775
|
+
p18.note(lines.join("\n"), "Admin ready");
|
|
26682
26776
|
}
|
|
26683
26777
|
function shouldSuppressDevServerStartupLine(line) {
|
|
26684
26778
|
const plain = stripAnsi2(line).trim();
|
|
@@ -26790,7 +26884,7 @@ function startManagedDevServer(cwd, devCmd, adminLoginUrl, adminCredentials) {
|
|
|
26790
26884
|
|
|
26791
26885
|
// adapters/next/commands/list-integrations.ts
|
|
26792
26886
|
import path51 from "path";
|
|
26793
|
-
import * as
|
|
26887
|
+
import * as p19 from "@clack/prompts";
|
|
26794
26888
|
async function runListIntegrationsCommand(options) {
|
|
26795
26889
|
const cwd = options.cwd ? path51.resolve(options.cwd) : process.cwd();
|
|
26796
26890
|
const config = await resolveConfig(cwd);
|
|
@@ -26799,15 +26893,15 @@ async function runListIntegrationsCommand(options) {
|
|
|
26799
26893
|
const status = installedIntegrations.has(integration.id) ? "installed" : "available";
|
|
26800
26894
|
return `${integration.id.padEnd(12)} ${status.padEnd(10)} ${integration.kind.padEnd(8)} ${integration.description}`;
|
|
26801
26895
|
});
|
|
26802
|
-
|
|
26803
|
-
|
|
26896
|
+
p19.note(lines.join("\n"), "BetterStart integrations");
|
|
26897
|
+
p19.outro(
|
|
26804
26898
|
`${installedIntegrations.size} installed, ${lines.length - installedIntegrations.size} available`
|
|
26805
26899
|
);
|
|
26806
26900
|
}
|
|
26807
26901
|
|
|
26808
26902
|
// adapters/next/commands/list-plugins.ts
|
|
26809
26903
|
import path52 from "path";
|
|
26810
|
-
import * as
|
|
26904
|
+
import * as p20 from "@clack/prompts";
|
|
26811
26905
|
async function runListPluginsCommand(options) {
|
|
26812
26906
|
const cwd = options.cwd ? path52.resolve(options.cwd) : process.cwd();
|
|
26813
26907
|
const config = await resolveConfig(cwd);
|
|
@@ -26816,34 +26910,34 @@ async function runListPluginsCommand(options) {
|
|
|
26816
26910
|
const status = installedPlugins.has(plugin.id) ? "installed" : "available";
|
|
26817
26911
|
return `${plugin.id.padEnd(10)} ${status.padEnd(10)} ${plugin.kind.padEnd(12)} ${plugin.description}`;
|
|
26818
26912
|
});
|
|
26819
|
-
|
|
26820
|
-
|
|
26913
|
+
p20.note(lines.join("\n"), "BetterStart plugins");
|
|
26914
|
+
p20.outro(`${installedPlugins.size} installed, ${lines.length - installedPlugins.size} available`);
|
|
26821
26915
|
}
|
|
26822
26916
|
|
|
26823
26917
|
// adapters/next/commands/remove.ts
|
|
26824
26918
|
import path53 from "path";
|
|
26825
|
-
import * as
|
|
26919
|
+
import * as p21 from "@clack/prompts";
|
|
26826
26920
|
async function runRemoveCommand(items, options) {
|
|
26827
26921
|
const removeIntegrationsMode = Boolean(options.integration);
|
|
26828
26922
|
if (!removeIntegrationsMode && items.includes("core")) {
|
|
26829
|
-
|
|
26923
|
+
p21.log.error("The core Admin cannot be removed.");
|
|
26830
26924
|
process.exit(1);
|
|
26831
26925
|
}
|
|
26832
26926
|
const pluginIds = items.filter(isPluginId);
|
|
26833
26927
|
const integrationIds = items.filter(isIntegrationId);
|
|
26834
26928
|
if (!removeIntegrationsMode && integrationIds.length > 0) {
|
|
26835
|
-
|
|
26929
|
+
p21.log.error(
|
|
26836
26930
|
`Integration IDs require --integration. Run \`betterstart remove --integration ${integrationIds.join(" ")}\`.`
|
|
26837
26931
|
);
|
|
26838
26932
|
process.exit(1);
|
|
26839
26933
|
}
|
|
26840
26934
|
if (removeIntegrationsMode && pluginIds.length > 0) {
|
|
26841
|
-
|
|
26935
|
+
p21.log.error(`Plugin IDs cannot be removed with --integration: ${pluginIds.join(", ")}`);
|
|
26842
26936
|
process.exit(1);
|
|
26843
26937
|
}
|
|
26844
26938
|
const invalidItems = removeIntegrationsMode ? items.filter((integrationId) => !isIntegrationId(integrationId)) : items.filter((pluginId) => !isPluginId(pluginId));
|
|
26845
26939
|
if (invalidItems.length > 0) {
|
|
26846
|
-
|
|
26940
|
+
p21.log.error(
|
|
26847
26941
|
removeIntegrationsMode ? formatUnknownIntegrationMessage(invalidItems) : formatUnknownPluginMessage(invalidItems)
|
|
26848
26942
|
);
|
|
26849
26943
|
process.exit(1);
|
|
@@ -26852,12 +26946,12 @@ async function runRemoveCommand(items, options) {
|
|
|
26852
26946
|
const config = await resolveConfig(cwd);
|
|
26853
26947
|
const pm = detectPackageManager(cwd);
|
|
26854
26948
|
if (!options.force) {
|
|
26855
|
-
const confirmed = await
|
|
26949
|
+
const confirmed = await p21.confirm({
|
|
26856
26950
|
message: `Remove ${removeIntegrationsMode ? "integration" : "plugin"}${items.length === 1 ? "" : "s"} ${items.join(", ")}?`,
|
|
26857
26951
|
initialValue: false
|
|
26858
26952
|
});
|
|
26859
|
-
if (
|
|
26860
|
-
|
|
26953
|
+
if (p21.isCancel(confirmed) || !confirmed) {
|
|
26954
|
+
p21.cancel(`${removeIntegrationsMode ? "Integration" : "Plugin"} removal cancelled.`);
|
|
26861
26955
|
process.exit(0);
|
|
26862
26956
|
}
|
|
26863
26957
|
}
|
|
@@ -26870,13 +26964,13 @@ async function runRemoveCommand(items, options) {
|
|
|
26870
26964
|
});
|
|
26871
26965
|
writeConfigFile(cwd, result2.config);
|
|
26872
26966
|
if (result2.removed.length === 0) {
|
|
26873
|
-
|
|
26967
|
+
p21.outro("No integrations were removed.");
|
|
26874
26968
|
return;
|
|
26875
26969
|
}
|
|
26876
26970
|
if (result2.warnings.length > 0) {
|
|
26877
|
-
|
|
26971
|
+
p21.note(result2.warnings.join("\n"), "Warnings");
|
|
26878
26972
|
}
|
|
26879
|
-
|
|
26973
|
+
p21.outro(
|
|
26880
26974
|
`Removed integration${result2.removed.length === 1 ? "" : "s"}: ${result2.removed.join(", ")}`
|
|
26881
26975
|
);
|
|
26882
26976
|
return;
|
|
@@ -26889,13 +26983,13 @@ async function runRemoveCommand(items, options) {
|
|
|
26889
26983
|
});
|
|
26890
26984
|
writeConfigFile(cwd, result.config);
|
|
26891
26985
|
if (result.removed.length === 0) {
|
|
26892
|
-
|
|
26986
|
+
p21.outro("No plugins were removed.");
|
|
26893
26987
|
return;
|
|
26894
26988
|
}
|
|
26895
26989
|
if (result.warnings.length > 0) {
|
|
26896
|
-
|
|
26990
|
+
p21.note(result.warnings.join("\n"), "Warnings");
|
|
26897
26991
|
}
|
|
26898
|
-
|
|
26992
|
+
p21.outro(`Removed plugin${result.removed.length === 1 ? "" : "s"}: ${result.removed.join(", ")}`);
|
|
26899
26993
|
}
|
|
26900
26994
|
|
|
26901
26995
|
// adapters/next/commands/remove-schema.ts
|
|
@@ -27045,7 +27139,7 @@ async function runRemoveSchemaCommand(schemaName, options) {
|
|
|
27045
27139
|
// adapters/next/commands/uninstall.ts
|
|
27046
27140
|
import fs42 from "fs";
|
|
27047
27141
|
import path55 from "path";
|
|
27048
|
-
import * as
|
|
27142
|
+
import * as p22 from "@clack/prompts";
|
|
27049
27143
|
import pc8 from "picocolors";
|
|
27050
27144
|
|
|
27051
27145
|
// adapters/next/commands/uninstall-cleaners.ts
|
|
@@ -27267,8 +27361,8 @@ function buildUninstallPlan(cwd, namespaceValue) {
|
|
|
27267
27361
|
count: configFiles.length,
|
|
27268
27362
|
unit: configFiles.length === 1 ? "file" : "files",
|
|
27269
27363
|
execute() {
|
|
27270
|
-
for (const
|
|
27271
|
-
if (fs42.existsSync(
|
|
27364
|
+
for (const p23 of configPaths) {
|
|
27365
|
+
if (fs42.existsSync(p23)) fs42.unlinkSync(p23);
|
|
27272
27366
|
}
|
|
27273
27367
|
}
|
|
27274
27368
|
});
|
|
@@ -27332,7 +27426,7 @@ function buildUninstallPlan(cwd, namespaceValue) {
|
|
|
27332
27426
|
}
|
|
27333
27427
|
async function runUninstallCommand(options) {
|
|
27334
27428
|
const cwd = options.cwd ? path55.resolve(options.cwd) : process.cwd();
|
|
27335
|
-
|
|
27429
|
+
p22.intro(pc8.bgRed(pc8.white(" BetterStart Uninstall ")));
|
|
27336
27430
|
let namespace = DEFAULT_ADMIN_NAMESPACE;
|
|
27337
27431
|
try {
|
|
27338
27432
|
const config = await resolveConfig(cwd);
|
|
@@ -27341,8 +27435,8 @@ async function runUninstallCommand(options) {
|
|
|
27341
27435
|
}
|
|
27342
27436
|
const steps = buildUninstallPlan(cwd, namespace);
|
|
27343
27437
|
if (steps.length === 0) {
|
|
27344
|
-
|
|
27345
|
-
|
|
27438
|
+
p22.log.success(`${pc8.green("\u2713")} Nothing to remove \u2014 project is already clean.`);
|
|
27439
|
+
p22.outro("Done");
|
|
27346
27440
|
return;
|
|
27347
27441
|
}
|
|
27348
27442
|
const planLines = steps.map((step) => {
|
|
@@ -27350,14 +27444,14 @@ async function runUninstallCommand(options) {
|
|
|
27350
27444
|
const countLabel = pc8.dim(`${step.count} ${step.unit}`);
|
|
27351
27445
|
return `${pc8.red("\xD7")} ${names} ${countLabel}`;
|
|
27352
27446
|
});
|
|
27353
|
-
|
|
27447
|
+
p22.note(planLines.join("\n"), "Uninstall plan");
|
|
27354
27448
|
if (!options.force) {
|
|
27355
|
-
const confirmed = await
|
|
27449
|
+
const confirmed = await p22.confirm({
|
|
27356
27450
|
message: "Proceed with uninstall?",
|
|
27357
27451
|
initialValue: false
|
|
27358
27452
|
});
|
|
27359
|
-
if (
|
|
27360
|
-
|
|
27453
|
+
if (p22.isCancel(confirmed) || !confirmed) {
|
|
27454
|
+
p22.cancel("Uninstall cancelled.");
|
|
27361
27455
|
process.exit(0);
|
|
27362
27456
|
}
|
|
27363
27457
|
}
|
|
@@ -27369,8 +27463,8 @@ async function runUninstallCommand(options) {
|
|
|
27369
27463
|
}
|
|
27370
27464
|
const parts = steps.map((step) => `${step.count} ${step.unit}`);
|
|
27371
27465
|
s.stop(`Removed ${parts.join(", ")}`);
|
|
27372
|
-
|
|
27373
|
-
|
|
27466
|
+
p22.note(pc8.dim("Database tables were NOT dropped \u2014 drop them manually if needed."), "Next steps");
|
|
27467
|
+
p22.outro("Uninstall complete");
|
|
27374
27468
|
}
|
|
27375
27469
|
|
|
27376
27470
|
// adapters/next/commands/update-component.ts
|