betterstart-cli 0.0.37 → 0.0.39
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 +315 -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,6 @@ 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
|
-
p11.log.success("Saved BLOB_READ_WRITE_TOKEN to .env.local");
|
|
22195
22220
|
sections.push({
|
|
22196
22221
|
header: "Storage (Vercel Blob)",
|
|
22197
22222
|
vars: [{ key: "BLOB_READ_WRITE_TOKEN", value: flow.token }]
|
|
@@ -22199,20 +22224,26 @@ async function promptPlugins(cwd, options = {}) {
|
|
|
22199
22224
|
overwriteKeys.add("BLOB_READ_WRITE_TOKEN");
|
|
22200
22225
|
if (flow.usedTerminalFallback) storageStep.skip();
|
|
22201
22226
|
else storageStep.confirm();
|
|
22227
|
+
} else if (flow) {
|
|
22228
|
+
p12.log.warn(
|
|
22229
|
+
"Continuing without a Blob token \u2014 add BLOB_READ_WRITE_TOKEN to .env.local from the store on vercel.com/dashboard/stores."
|
|
22230
|
+
);
|
|
22231
|
+
sections.push({
|
|
22232
|
+
header: "Storage (Vercel Blob)",
|
|
22233
|
+
vars: [{ key: "BLOB_READ_WRITE_TOKEN", value: "" }]
|
|
22234
|
+
});
|
|
22235
|
+
storageStep.skip();
|
|
22202
22236
|
} else {
|
|
22203
22237
|
if (existingToken) {
|
|
22204
|
-
|
|
22205
|
-
} else if (options.provisionVercelBlob) {
|
|
22206
|
-
p11.log.info("Falling back to a manual Vercel Blob token.");
|
|
22238
|
+
p12.log.info("Using the existing Vercel Blob token from .env.local");
|
|
22207
22239
|
}
|
|
22208
22240
|
mergeIntegrationConfig(await collectIntegrationConfig(cwd, ["vercel-blob"]));
|
|
22209
|
-
|
|
22210
|
-
else storageStep.confirm();
|
|
22241
|
+
storageStep.confirm();
|
|
22211
22242
|
}
|
|
22212
22243
|
} else {
|
|
22213
22244
|
storageStep.confirm();
|
|
22214
22245
|
}
|
|
22215
|
-
const selectedPlugins = await
|
|
22246
|
+
const selectedPlugins = await p12.multiselect({
|
|
22216
22247
|
message: "Select presets",
|
|
22217
22248
|
options: [
|
|
22218
22249
|
{
|
|
@@ -22224,12 +22255,12 @@ async function promptPlugins(cwd, options = {}) {
|
|
|
22224
22255
|
required: false,
|
|
22225
22256
|
initialValues: ["blog"]
|
|
22226
22257
|
});
|
|
22227
|
-
if (
|
|
22228
|
-
|
|
22258
|
+
if (p12.isCancel(selectedPlugins)) {
|
|
22259
|
+
p12.cancel("Setup cancelled.");
|
|
22229
22260
|
process.exit(0);
|
|
22230
22261
|
}
|
|
22231
22262
|
const integrations = [];
|
|
22232
|
-
const setupResend = await
|
|
22263
|
+
const setupResend = await p12.confirm({
|
|
22233
22264
|
message: `Do you want to setup resend.com emails?
|
|
22234
22265
|
${styleText(
|
|
22235
22266
|
"dim",
|
|
@@ -22237,8 +22268,8 @@ ${styleText(
|
|
|
22237
22268
|
)}`,
|
|
22238
22269
|
initialValue: true
|
|
22239
22270
|
});
|
|
22240
|
-
if (
|
|
22241
|
-
|
|
22271
|
+
if (p12.isCancel(setupResend)) {
|
|
22272
|
+
p12.cancel("Setup cancelled.");
|
|
22242
22273
|
process.exit(0);
|
|
22243
22274
|
}
|
|
22244
22275
|
if (setupResend) {
|
|
@@ -22267,10 +22298,10 @@ ${styleText(
|
|
|
22267
22298
|
}
|
|
22268
22299
|
|
|
22269
22300
|
// adapters/next/init/prompts/project.ts
|
|
22270
|
-
import * as
|
|
22301
|
+
import * as p13 from "@clack/prompts";
|
|
22271
22302
|
import pc2 from "picocolors";
|
|
22272
22303
|
async function promptProject(defaultName) {
|
|
22273
|
-
const projectName = await
|
|
22304
|
+
const projectName = await p13.text({
|
|
22274
22305
|
message: [
|
|
22275
22306
|
"What is your project name?",
|
|
22276
22307
|
`${pc2.cyan("\u2502")} ${pc2.dim("If you don't want a directory created with the project name, just press `")}${pc2.bold(
|
|
@@ -22289,16 +22320,16 @@ async function promptProject(defaultName) {
|
|
|
22289
22320
|
return void 0;
|
|
22290
22321
|
}
|
|
22291
22322
|
});
|
|
22292
|
-
if (
|
|
22293
|
-
|
|
22323
|
+
if (p13.isCancel(projectName)) {
|
|
22324
|
+
p13.cancel("Setup cancelled.");
|
|
22294
22325
|
process.exit(0);
|
|
22295
22326
|
}
|
|
22296
|
-
const useSrcDir = await
|
|
22327
|
+
const useSrcDir = await p13.confirm({
|
|
22297
22328
|
message: "Use src/ directory?",
|
|
22298
22329
|
initialValue: false
|
|
22299
22330
|
});
|
|
22300
|
-
if (
|
|
22301
|
-
|
|
22331
|
+
if (p13.isCancel(useSrcDir)) {
|
|
22332
|
+
p13.cancel("Setup cancelled.");
|
|
22302
22333
|
process.exit(0);
|
|
22303
22334
|
}
|
|
22304
22335
|
return { projectName: projectName.trim(), useSrcDir };
|
|
@@ -24144,11 +24175,11 @@ function scaffoldTsconfig(cwd, config) {
|
|
|
24144
24175
|
}
|
|
24145
24176
|
|
|
24146
24177
|
// adapters/next/init/vercel/flow.ts
|
|
24147
|
-
import * as
|
|
24178
|
+
import * as p17 from "@clack/prompts";
|
|
24148
24179
|
import pc6 from "picocolors";
|
|
24149
24180
|
|
|
24150
24181
|
// adapters/next/init/vercel/auth.ts
|
|
24151
|
-
import * as
|
|
24182
|
+
import * as p14 from "@clack/prompts";
|
|
24152
24183
|
import pc3 from "picocolors";
|
|
24153
24184
|
|
|
24154
24185
|
// adapters/next/init/vercel/runner.ts
|
|
@@ -24356,7 +24387,7 @@ async function ensureVercelAuth(runner, cwd, options) {
|
|
|
24356
24387
|
checkSpinner.clear();
|
|
24357
24388
|
const signInMessage = `Sign in to Vercel to continue ${pc3.dim("(or press Ctrl-C to enter a connection string manually)")}`;
|
|
24358
24389
|
const signInRows = clackLogRows(signInMessage);
|
|
24359
|
-
|
|
24390
|
+
p14.log.info(signInMessage);
|
|
24360
24391
|
let streamedRows = 0;
|
|
24361
24392
|
const login = await runVercel(runner, ["login"], {
|
|
24362
24393
|
cwd,
|
|
@@ -24388,7 +24419,7 @@ function signedInMessage(username) {
|
|
|
24388
24419
|
}
|
|
24389
24420
|
|
|
24390
24421
|
// adapters/next/init/vercel/blob.ts
|
|
24391
|
-
import * as
|
|
24422
|
+
import * as p15 from "@clack/prompts";
|
|
24392
24423
|
import pc4 from "picocolors";
|
|
24393
24424
|
|
|
24394
24425
|
// adapters/next/init/vercel/env-pull.ts
|
|
@@ -24499,21 +24530,46 @@ function readLinkedProjectJson(cwd) {
|
|
|
24499
24530
|
// adapters/next/init/vercel/blob.ts
|
|
24500
24531
|
var PROVISION_TIMEOUT_MS = 18e4;
|
|
24501
24532
|
var INTERACTIVE_PROVISION_TIMEOUT_MS = 6e5;
|
|
24502
|
-
var MAX_STORE_NAME_ATTEMPTS =
|
|
24533
|
+
var MAX_STORE_NAME_ATTEMPTS = 10;
|
|
24503
24534
|
function blobStoreName(projectName) {
|
|
24504
24535
|
return sanitizeVercelProjectName(`${projectName}-blob`);
|
|
24505
24536
|
}
|
|
24506
24537
|
function isNameTaken(result) {
|
|
24507
|
-
return /already exists|already taken|already in use|name.*taken/i.test(
|
|
24538
|
+
return /already exists|already taken|already in use|name.*taken|conflict|\b409\b/i.test(
|
|
24508
24539
|
`${result.stdout}
|
|
24509
24540
|
${result.stderr}`
|
|
24510
24541
|
);
|
|
24511
24542
|
}
|
|
24543
|
+
function candidateStoreName(baseName, attempt) {
|
|
24544
|
+
if (attempt < MAX_STORE_NAME_ATTEMPTS) return versionedVercelProjectName(baseName, attempt);
|
|
24545
|
+
const suffix = `-${Date.now().toString(36)}`;
|
|
24546
|
+
return `${baseName.slice(0, 100 - suffix.length)}${suffix}`;
|
|
24547
|
+
}
|
|
24548
|
+
function isEnvVarConflict(result) {
|
|
24549
|
+
return /already has an existing environment variable/i.test(`${result.stdout}
|
|
24550
|
+
${result.stderr}`);
|
|
24551
|
+
}
|
|
24552
|
+
function createdStoreId(result) {
|
|
24553
|
+
return /Blob store created:[^(]*\((store_[A-Za-z0-9]+)\)/.exec(
|
|
24554
|
+
`${result.stdout}
|
|
24555
|
+
${result.stderr}`
|
|
24556
|
+
)?.[1];
|
|
24557
|
+
}
|
|
24558
|
+
async function deleteOrphanStore(runner, cwd, createResult, env) {
|
|
24559
|
+
const storeId = createdStoreId(createResult);
|
|
24560
|
+
if (!storeId) return;
|
|
24561
|
+
await runVercel(runner, ["blob", "delete-store", storeId, "--yes"], {
|
|
24562
|
+
cwd,
|
|
24563
|
+
mode: "capture",
|
|
24564
|
+
timeoutMs: PROVISION_TIMEOUT_MS,
|
|
24565
|
+
env
|
|
24566
|
+
});
|
|
24567
|
+
}
|
|
24512
24568
|
async function createStoreQuiet(runner, cwd, baseName, env) {
|
|
24513
24569
|
let result;
|
|
24514
24570
|
let storeName = baseName;
|
|
24515
24571
|
for (let attempt = 1; attempt <= MAX_STORE_NAME_ATTEMPTS; attempt++) {
|
|
24516
|
-
storeName =
|
|
24572
|
+
storeName = candidateStoreName(baseName, attempt);
|
|
24517
24573
|
result = await runVercel(
|
|
24518
24574
|
runner,
|
|
24519
24575
|
["blob", "create-store", storeName, "--access", "public", "--yes"],
|
|
@@ -24526,45 +24582,80 @@ async function createStoreQuiet(runner, cwd, baseName, env) {
|
|
|
24526
24582
|
async function provisionBlobStoreInteractive(runner, cwd, options) {
|
|
24527
24583
|
const quietSpinner = spinner2();
|
|
24528
24584
|
quietSpinner.start("Creating your Vercel Blob store");
|
|
24529
|
-
|
|
24530
|
-
|
|
24531
|
-
|
|
24532
|
-
const
|
|
24533
|
-
if (!
|
|
24534
|
-
|
|
24535
|
-
return { storeName
|
|
24536
|
-
}
|
|
24585
|
+
let terminalFallbackRan = false;
|
|
24586
|
+
let lastResult;
|
|
24587
|
+
const pullToken = async (activeSpinner, storeName) => {
|
|
24588
|
+
const token = await pullBlobToken(runner, cwd, options.env);
|
|
24589
|
+
if (!token) {
|
|
24590
|
+
activeSpinner.stop("No BLOB_READ_WRITE_TOKEN came back from Vercel");
|
|
24591
|
+
return { ...storeName && { storeName }, failure: "env-pull-empty" };
|
|
24592
|
+
}
|
|
24593
|
+
activeSpinner.clear();
|
|
24594
|
+
return {
|
|
24595
|
+
token,
|
|
24596
|
+
...storeName && { storeName },
|
|
24597
|
+
...terminalFallbackRan && { usedTerminalFallback: true }
|
|
24598
|
+
};
|
|
24599
|
+
};
|
|
24600
|
+
for (let attempt = 1; attempt <= MAX_STORE_NAME_ATTEMPTS; attempt++) {
|
|
24601
|
+
const storeName = candidateStoreName(options.name, attempt);
|
|
24602
|
+
const result = await runVercel(
|
|
24603
|
+
runner,
|
|
24604
|
+
["blob", "create-store", storeName, "--access", "public", "--yes"],
|
|
24605
|
+
{ cwd, mode: "capture", timeoutMs: PROVISION_TIMEOUT_MS, env: options.env }
|
|
24606
|
+
);
|
|
24607
|
+
lastResult = result;
|
|
24608
|
+
if (result.success) {
|
|
24609
|
+
quietSpinner.message("Retrieving the Blob read-write token");
|
|
24610
|
+
return pullToken(quietSpinner, storeName);
|
|
24611
|
+
}
|
|
24612
|
+
if (isEnvVarConflict(result)) {
|
|
24613
|
+
await deleteOrphanStore(runner, cwd, result, options.env);
|
|
24614
|
+
quietSpinner.message("Retrieving the Blob read-write token");
|
|
24615
|
+
return pullToken(quietSpinner);
|
|
24616
|
+
}
|
|
24617
|
+
if (isNameTaken(result)) continue;
|
|
24618
|
+
if (terminalFallbackRan) break;
|
|
24619
|
+
terminalFallbackRan = true;
|
|
24537
24620
|
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" };
|
|
24621
|
+
p15.log.info(
|
|
24622
|
+
`Create your Blob store in the Vercel prompts below ${pc4.dim(
|
|
24623
|
+
"(connect it to all environments)."
|
|
24624
|
+
)}`
|
|
24625
|
+
);
|
|
24626
|
+
const add = await runVercel(runner, ["blob", "create-store", storeName, "--access", "public"], {
|
|
24627
|
+
cwd,
|
|
24628
|
+
mode: "inherit",
|
|
24629
|
+
timeoutMs: INTERACTIVE_PROVISION_TIMEOUT_MS,
|
|
24630
|
+
env: options.env
|
|
24631
|
+
});
|
|
24632
|
+
if (add.success) {
|
|
24633
|
+
const pullSpinner = spinner2();
|
|
24634
|
+
pullSpinner.start("Retrieving the Blob read-write token");
|
|
24635
|
+
return pullToken(pullSpinner, storeName);
|
|
24636
|
+
}
|
|
24637
|
+
if (add.timedOut) return { failure: "timeout" };
|
|
24638
|
+
lastResult = add;
|
|
24639
|
+
quietSpinner.start("Creating your Vercel Blob store");
|
|
24560
24640
|
}
|
|
24561
|
-
|
|
24562
|
-
return {
|
|
24641
|
+
quietSpinner.stop("Vercel Blob provisioning did not complete");
|
|
24642
|
+
return { failure: lastResult?.timedOut ? "timeout" : "provision-failed" };
|
|
24563
24643
|
}
|
|
24564
24644
|
async function provisionBlobStore(runner, cwd, options) {
|
|
24565
24645
|
const provisionSpinner = spinner2();
|
|
24566
24646
|
provisionSpinner.start("Creating your Vercel Blob store");
|
|
24567
24647
|
const { result, storeName } = await createStoreQuiet(runner, cwd, options.name, options.env);
|
|
24648
|
+
if (!result.success && isEnvVarConflict(result)) {
|
|
24649
|
+
await deleteOrphanStore(runner, cwd, result, options.env);
|
|
24650
|
+
provisionSpinner.message("Retrieving the Blob read-write token");
|
|
24651
|
+
const token2 = await pullBlobToken(runner, cwd, options.env);
|
|
24652
|
+
if (!token2) {
|
|
24653
|
+
provisionSpinner.stop("No BLOB_READ_WRITE_TOKEN came back from Vercel");
|
|
24654
|
+
return { failure: "env-pull-empty" };
|
|
24655
|
+
}
|
|
24656
|
+
provisionSpinner.clear();
|
|
24657
|
+
return { token: token2 };
|
|
24658
|
+
}
|
|
24568
24659
|
if (!result.success) {
|
|
24569
24660
|
provisionSpinner.stop("Vercel Blob provisioning did not complete");
|
|
24570
24661
|
const combined = `${result.stdout}
|
|
@@ -24793,7 +24884,7 @@ function guardEnvLocal(cwd) {
|
|
|
24793
24884
|
}
|
|
24794
24885
|
|
|
24795
24886
|
// adapters/next/init/vercel/neon.ts
|
|
24796
|
-
import * as
|
|
24887
|
+
import * as p16 from "@clack/prompts";
|
|
24797
24888
|
import pc5 from "picocolors";
|
|
24798
24889
|
var PROVISION_TIMEOUT_MS2 = 18e4;
|
|
24799
24890
|
var INTERACTIVE_PROVISION_TIMEOUT_MS2 = 6e5;
|
|
@@ -24811,7 +24902,7 @@ async function provisionNeonInteractive(runner, cwd, options) {
|
|
|
24811
24902
|
return readNeonProvisionInfo(quiet.stdout);
|
|
24812
24903
|
}
|
|
24813
24904
|
quietSpinner.clear();
|
|
24814
|
-
|
|
24905
|
+
p16.log.info(
|
|
24815
24906
|
`Create your Neon database in the Vercel prompts below ${pc5.dim(
|
|
24816
24907
|
"(the Free plan is recommended)."
|
|
24817
24908
|
)}`
|
|
@@ -24885,14 +24976,14 @@ async function runVercelNeonFlow(options) {
|
|
|
24885
24976
|
runnerSpinner.clear();
|
|
24886
24977
|
const auth = await ensureVercelAuth(runner, options.cwd, { env });
|
|
24887
24978
|
if (!auth.authed) {
|
|
24888
|
-
|
|
24979
|
+
p17.log.warn(authFailureMessage(auth.reason));
|
|
24889
24980
|
return { ok: false };
|
|
24890
24981
|
}
|
|
24891
24982
|
const linkLinePrinted = await ensureLinkedProject(runner, options.cwd, options.projectName, env);
|
|
24892
24983
|
const neon = await provisionNeonForMode(runner, options);
|
|
24893
24984
|
if (neon.failure) {
|
|
24894
|
-
|
|
24895
|
-
if (neon.detail)
|
|
24985
|
+
p17.log.warn(neonFailureMessage(neon.failure));
|
|
24986
|
+
if (neon.detail) p17.log.message(pc6.dim(neon.detail));
|
|
24896
24987
|
return { ok: false };
|
|
24897
24988
|
}
|
|
24898
24989
|
const databaseUrl = await pullNeonDatabaseUrl(runner, options.cwd, env);
|
|
@@ -24905,7 +24996,7 @@ async function runVercelNeonFlow(options) {
|
|
|
24905
24996
|
dismissSignedInNote
|
|
24906
24997
|
};
|
|
24907
24998
|
} catch (error) {
|
|
24908
|
-
|
|
24999
|
+
p17.log.warn(
|
|
24909
25000
|
`Vercel provisioning failed: ${error instanceof Error ? error.message : String(error)}`
|
|
24910
25001
|
);
|
|
24911
25002
|
return { ok: false };
|
|
@@ -24923,14 +25014,14 @@ async function runVercelBlobFlow(options) {
|
|
|
24923
25014
|
runnerSpinner.clear();
|
|
24924
25015
|
const auth = await ensureVercelAuth(runner, options.cwd, { env, quietIfAuthed: true });
|
|
24925
25016
|
if (!auth.authed) {
|
|
24926
|
-
|
|
25017
|
+
p17.log.warn(authFailureMessage(auth.reason));
|
|
24927
25018
|
return { ok: false };
|
|
24928
25019
|
}
|
|
24929
25020
|
await ensureLinkedProject(runner, options.cwd, options.projectName, env);
|
|
24930
25021
|
const blob = await provisionBlobForMode(runner, options);
|
|
24931
25022
|
if (blob.failure || !blob.token) {
|
|
24932
|
-
|
|
24933
|
-
if (blob.detail)
|
|
25023
|
+
p17.log.warn(blobFailureMessage(blob.failure));
|
|
25024
|
+
if (blob.detail) p17.log.message(pc6.dim(blob.detail));
|
|
24934
25025
|
return { ok: false };
|
|
24935
25026
|
}
|
|
24936
25027
|
return {
|
|
@@ -24940,7 +25031,7 @@ async function runVercelBlobFlow(options) {
|
|
|
24940
25031
|
usedTerminalFallback: blob.usedTerminalFallback
|
|
24941
25032
|
};
|
|
24942
25033
|
} catch (error) {
|
|
24943
|
-
|
|
25034
|
+
p17.log.warn(
|
|
24944
25035
|
`Vercel provisioning failed: ${error instanceof Error ? error.message : String(error)}`
|
|
24945
25036
|
);
|
|
24946
25037
|
return { ok: false };
|
|
@@ -24958,7 +25049,7 @@ async function runVercelDeployFlow(options) {
|
|
|
24958
25049
|
runnerSpinner.clear();
|
|
24959
25050
|
const auth = await ensureVercelAuth(runner, options.cwd, { env, quietIfAuthed: true });
|
|
24960
25051
|
if (!auth.authed) {
|
|
24961
|
-
|
|
25052
|
+
p17.log.warn(authFailureMessage(auth.reason));
|
|
24962
25053
|
printManualDeployHint();
|
|
24963
25054
|
return { ok: false };
|
|
24964
25055
|
}
|
|
@@ -24976,17 +25067,17 @@ async function runVercelDeployFlow(options) {
|
|
|
24976
25067
|
let printedWarnings = false;
|
|
24977
25068
|
for (const key of sync.failed) {
|
|
24978
25069
|
printedWarnings = true;
|
|
24979
|
-
|
|
25070
|
+
p17.log.warn(
|
|
24980
25071
|
`Could not set ${pc6.cyan(key)} on Vercel \u2014 add it in the project's environment settings.`
|
|
24981
25072
|
);
|
|
24982
25073
|
}
|
|
24983
25074
|
if (ensureVercelJsonFramework(options.cwd) === "created") {
|
|
24984
|
-
|
|
25075
|
+
p17.log.success(`Created ${pc6.cyan("vercel.json")} with the Next.js framework preset`);
|
|
24985
25076
|
}
|
|
24986
25077
|
const packageGuard = guardProjectForDeploy(options.cwd);
|
|
24987
25078
|
for (const dep of packageGuard.localSpecDeps) {
|
|
24988
25079
|
printedWarnings = true;
|
|
24989
|
-
|
|
25080
|
+
p17.log.warn(
|
|
24990
25081
|
`Dependency ${pc6.cyan(dep)} uses a local spec that cannot install on Vercel \u2014 the remote build may fail.`
|
|
24991
25082
|
);
|
|
24992
25083
|
}
|
|
@@ -25000,7 +25091,7 @@ async function runVercelDeployFlow(options) {
|
|
|
25000
25091
|
}
|
|
25001
25092
|
if (deploy.failure) {
|
|
25002
25093
|
deploySpinner.stop(`${pc6.yellow("\u25B2")} ${deployFailureMessage(deploy.failure)}`);
|
|
25003
|
-
if (deploy.detail)
|
|
25094
|
+
if (deploy.detail) p17.log.message(pc6.dim(deploy.detail));
|
|
25004
25095
|
printManualDeployHint();
|
|
25005
25096
|
return { ok: false };
|
|
25006
25097
|
}
|
|
@@ -25009,7 +25100,7 @@ async function runVercelDeployFlow(options) {
|
|
|
25009
25100
|
deploySpinner.stop(url ? `Deployed ${pc6.cyan(url)}` : "Deployed to Vercel");
|
|
25010
25101
|
return { ok: true, url, syncedEnvKeys: sync.synced, cleanScreen: !printedWarnings };
|
|
25011
25102
|
} catch (error) {
|
|
25012
|
-
|
|
25103
|
+
p17.log.warn(`Vercel deploy failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
25013
25104
|
printManualDeployHint();
|
|
25014
25105
|
return { ok: false };
|
|
25015
25106
|
} finally {
|
|
@@ -25017,7 +25108,7 @@ async function runVercelDeployFlow(options) {
|
|
|
25017
25108
|
}
|
|
25018
25109
|
}
|
|
25019
25110
|
function printManualDeployHint() {
|
|
25020
|
-
|
|
25111
|
+
p17.log.info(`You can deploy manually: ${pc6.cyan("vercel deploy --prod")}`);
|
|
25021
25112
|
}
|
|
25022
25113
|
async function ensureLinkedProject(runner, cwd, projectName, env) {
|
|
25023
25114
|
if (readLinkedProjectId(cwd)) return false;
|
|
@@ -25065,11 +25156,11 @@ function authFailureMessage(reason) {
|
|
|
25065
25156
|
function blobFailureMessage(reason) {
|
|
25066
25157
|
switch (reason) {
|
|
25067
25158
|
case "env-pull-empty":
|
|
25068
|
-
return "Created a Blob store, but no BLOB_READ_WRITE_TOKEN came back
|
|
25159
|
+
return "Created a Blob store, but no BLOB_READ_WRITE_TOKEN came back from Vercel.";
|
|
25069
25160
|
case "timeout":
|
|
25070
|
-
return "Vercel Blob provisioning timed out
|
|
25161
|
+
return "Vercel Blob provisioning timed out.";
|
|
25071
25162
|
default:
|
|
25072
|
-
return "Vercel Blob provisioning did not complete
|
|
25163
|
+
return "Vercel Blob provisioning did not complete.";
|
|
25073
25164
|
}
|
|
25074
25165
|
}
|
|
25075
25166
|
function deployFailureMessage(reason) {
|
|
@@ -25483,7 +25574,8 @@ function removeExistingAdminPaths(cwd, namespaces) {
|
|
|
25483
25574
|
}
|
|
25484
25575
|
async function runInitCommand(name, options) {
|
|
25485
25576
|
installPromptCheckmarks();
|
|
25486
|
-
|
|
25577
|
+
const disposeCancelGuard = installSetupCancelGuard();
|
|
25578
|
+
p18.box(
|
|
25487
25579
|
`
|
|
25488
25580
|
\u2584 \u2597 \u2597 \u2584\u2596\u2597 \u2597
|
|
25489
25581
|
\u2599\u2598\u2588\u258C\u259C\u2598\u259C\u2598\u2588\u258C\u259B\u2598\u259A \u259C\u2598\u2580\u258C\u259B\u2598\u259C\u2598
|
|
@@ -25504,13 +25596,13 @@ async function runInitCommand(name, options) {
|
|
|
25504
25596
|
try {
|
|
25505
25597
|
namespace = validateAdminNamespace(options.namespace);
|
|
25506
25598
|
} catch (error) {
|
|
25507
|
-
|
|
25599
|
+
p18.log.error(error instanceof Error ? error.message : String(error));
|
|
25508
25600
|
process.exit(1);
|
|
25509
25601
|
}
|
|
25510
25602
|
}
|
|
25511
25603
|
if (!options.yes && !options.namespace) {
|
|
25512
25604
|
const defaultDashboardPath = resolveAdminNamespace(DEFAULT_ADMIN_NAMESPACE).routePath;
|
|
25513
|
-
const namespaceInput = await
|
|
25605
|
+
const namespaceInput = await p18.text({
|
|
25514
25606
|
message: "Enter the dashboard path",
|
|
25515
25607
|
placeholder: `eg. ${defaultDashboardPath}`,
|
|
25516
25608
|
defaultValue: defaultDashboardPath,
|
|
@@ -25523,8 +25615,8 @@ async function runInitCommand(name, options) {
|
|
|
25523
25615
|
}
|
|
25524
25616
|
}
|
|
25525
25617
|
});
|
|
25526
|
-
if (
|
|
25527
|
-
|
|
25618
|
+
if (p18.isCancel(namespaceInput)) {
|
|
25619
|
+
p18.cancel("Setup cancelled.");
|
|
25528
25620
|
process.exit(0);
|
|
25529
25621
|
}
|
|
25530
25622
|
namespace = validateAdminDashboardPath(namespaceInput);
|
|
@@ -25536,13 +25628,13 @@ async function runInitCommand(name, options) {
|
|
|
25536
25628
|
if (project2.isExisting) {
|
|
25537
25629
|
srcDir = project2.hasSrcDir;
|
|
25538
25630
|
if (!project2.hasTypeScript) {
|
|
25539
|
-
|
|
25631
|
+
p18.log.error("TypeScript is required. Please add a tsconfig.json first.");
|
|
25540
25632
|
process.exit(1);
|
|
25541
25633
|
}
|
|
25542
25634
|
if (forceMode) {
|
|
25543
25635
|
const nuked = removeExistingAdminPaths(cwd, await resolveForceInitNamespaces(cwd, namespace));
|
|
25544
25636
|
if (nuked > 0) {
|
|
25545
|
-
|
|
25637
|
+
p18.log.warn(`${pc7.yellow("Force mode:")} removed ${nuked} existing admin paths`);
|
|
25546
25638
|
}
|
|
25547
25639
|
project2 = detectProject(cwd, namespace);
|
|
25548
25640
|
} else if (project2.conflicts.length > 0) {
|
|
@@ -25551,9 +25643,9 @@ async function runInitCommand(name, options) {
|
|
|
25551
25643
|
"",
|
|
25552
25644
|
pc7.dim(`Use ${pc7.bold("--force")} to remove existing admin files before scaffolding.`)
|
|
25553
25645
|
);
|
|
25554
|
-
|
|
25646
|
+
p18.note(conflictLines.join("\n"), pc7.yellow("Conflicts"));
|
|
25555
25647
|
if (!options.yes) {
|
|
25556
|
-
const proceed = await
|
|
25648
|
+
const proceed = await p18.confirm({
|
|
25557
25649
|
message: [
|
|
25558
25650
|
`Continue with ${pc7.bold(pc7.cyan("--force"))}?`,
|
|
25559
25651
|
`${pc7.cyan("\u2502")} ${pc7.dim("This will force overwrite the existing admin code.")}`,
|
|
@@ -25561,8 +25653,8 @@ async function runInitCommand(name, options) {
|
|
|
25561
25653
|
].join("\n"),
|
|
25562
25654
|
initialValue: true
|
|
25563
25655
|
});
|
|
25564
|
-
if (
|
|
25565
|
-
|
|
25656
|
+
if (p18.isCancel(proceed) || !proceed) {
|
|
25657
|
+
p18.cancel("Setup cancelled.");
|
|
25566
25658
|
process.exit(0);
|
|
25567
25659
|
}
|
|
25568
25660
|
forceMode = true;
|
|
@@ -25571,23 +25663,23 @@ async function runInitCommand(name, options) {
|
|
|
25571
25663
|
await resolveForceInitNamespaces(cwd, namespace)
|
|
25572
25664
|
);
|
|
25573
25665
|
if (nuked > 0) {
|
|
25574
|
-
|
|
25666
|
+
p18.log.warn(`${pc7.yellow("Force mode:")} removed ${nuked} existing admin paths`);
|
|
25575
25667
|
}
|
|
25576
25668
|
project2 = detectProject(cwd, namespace);
|
|
25577
25669
|
}
|
|
25578
25670
|
}
|
|
25579
25671
|
} else {
|
|
25580
|
-
|
|
25672
|
+
p18.log.info("No Next.js app found \u2014 Running the fresh project mode...");
|
|
25581
25673
|
let projectPrompt;
|
|
25582
25674
|
try {
|
|
25583
25675
|
projectPrompt = options.yes ? resolveNonInteractiveProject(name) : await promptProject(name);
|
|
25584
25676
|
} catch (error) {
|
|
25585
|
-
|
|
25677
|
+
p18.log.error(error instanceof Error ? error.message : String(error));
|
|
25586
25678
|
process.exit(1);
|
|
25587
25679
|
}
|
|
25588
25680
|
srcDir = projectPrompt.useSrcDir;
|
|
25589
25681
|
if (!options.yes) {
|
|
25590
|
-
const pmChoice = await
|
|
25682
|
+
const pmChoice = await p18.select({
|
|
25591
25683
|
message: "Which package manager do you want to use?",
|
|
25592
25684
|
options: [
|
|
25593
25685
|
{ value: "pnpm", label: "pnpm", hint: "recommended" },
|
|
@@ -25596,8 +25688,8 @@ async function runInitCommand(name, options) {
|
|
|
25596
25688
|
{ value: "bun", label: "bun" }
|
|
25597
25689
|
]
|
|
25598
25690
|
});
|
|
25599
|
-
if (
|
|
25600
|
-
|
|
25691
|
+
if (p18.isCancel(pmChoice)) {
|
|
25692
|
+
p18.cancel("Setup cancelled.");
|
|
25601
25693
|
process.exit(0);
|
|
25602
25694
|
}
|
|
25603
25695
|
pm = pmChoice;
|
|
@@ -25631,8 +25723,8 @@ async function runInitCommand(name, options) {
|
|
|
25631
25723
|
process.stderr.write(`${createNextAppResult.output.trimEnd()}
|
|
25632
25724
|
`);
|
|
25633
25725
|
}
|
|
25634
|
-
|
|
25635
|
-
|
|
25726
|
+
p18.log.error(createNextAppResult.error);
|
|
25727
|
+
p18.log.info(
|
|
25636
25728
|
`You can create the project manually:
|
|
25637
25729
|
${pc7.cyan(`npx create-next-app@latest ${projectPrompt.projectName} --typescript --tailwind --app`)}
|
|
25638
25730
|
Then run ${pc7.cyan("betterstart init")} inside it.`
|
|
@@ -25646,11 +25738,11 @@ async function runInitCommand(name, options) {
|
|
|
25646
25738
|
);
|
|
25647
25739
|
if (!hasPackageJson || !hasNextConfig) {
|
|
25648
25740
|
createNextAppSpinner.stop(`Failed to create Next.js app: ${displayName}`);
|
|
25649
|
-
|
|
25741
|
+
p18.log.error(
|
|
25650
25742
|
"create-next-app completed but the project was not created. This can happen with nested npx calls."
|
|
25651
25743
|
);
|
|
25652
25744
|
const manualCmd = `npx create-next-app@latest ${projectPrompt.projectName} --typescript --tailwind --app`;
|
|
25653
|
-
|
|
25745
|
+
p18.log.info(
|
|
25654
25746
|
`Create the project manually:
|
|
25655
25747
|
${pc7.cyan(manualCmd)}
|
|
25656
25748
|
Then run ${pc7.cyan("betterstart init")} inside it.`
|
|
@@ -25669,7 +25761,7 @@ async function runInitCommand(name, options) {
|
|
|
25669
25761
|
if (options.yes) {
|
|
25670
25762
|
if (options.databaseUrl) {
|
|
25671
25763
|
if (!isValidDbUrl(options.databaseUrl)) {
|
|
25672
|
-
|
|
25764
|
+
p18.log.error(
|
|
25673
25765
|
`Invalid database URL. Must start with ${pc7.cyan("postgres://")} or ${pc7.cyan("postgresql://")}`
|
|
25674
25766
|
);
|
|
25675
25767
|
process.exit(1);
|
|
@@ -25689,24 +25781,24 @@ async function runInitCommand(name, options) {
|
|
|
25689
25781
|
databaseUrl = flow.databaseUrl;
|
|
25690
25782
|
persistDatabaseUrl(cwd, databaseUrl);
|
|
25691
25783
|
} else if (flow.ok) {
|
|
25692
|
-
|
|
25784
|
+
p18.log.warn("Created a Neon database, but DATABASE_URL could not be retrieved from Vercel.");
|
|
25693
25785
|
const resourceUrl = flow.dashboardUrl ?? flow.resourceUrl;
|
|
25694
25786
|
if (resourceUrl) {
|
|
25695
|
-
|
|
25787
|
+
p18.log.info(
|
|
25696
25788
|
`Open ${pc7.cyan(resourceUrl)} to copy DATABASE_URL, then rerun ${pc7.cyan("betterstart init --database-url <url> --yes")}.`
|
|
25697
25789
|
);
|
|
25698
25790
|
} else {
|
|
25699
|
-
|
|
25791
|
+
p18.log.info(
|
|
25700
25792
|
`Rerun ${pc7.cyan("betterstart init --database-url <url> --yes")} with a Postgres connection string.`
|
|
25701
25793
|
);
|
|
25702
25794
|
}
|
|
25703
25795
|
} else {
|
|
25704
|
-
|
|
25796
|
+
p18.log.warn("Vercel provisioning did not complete; continuing without a database URL.");
|
|
25705
25797
|
}
|
|
25706
25798
|
}
|
|
25707
25799
|
} else if (existingDbUrl) {
|
|
25708
25800
|
const masked = maskDbUrl(existingDbUrl);
|
|
25709
|
-
|
|
25801
|
+
p18.log.info(`Using existing database URL from .env.local ${pc7.dim(`(${masked})`)}`);
|
|
25710
25802
|
databaseUrl = existingDbUrl;
|
|
25711
25803
|
} else {
|
|
25712
25804
|
const databaseStep = deferNextPromptCheck();
|
|
@@ -25732,7 +25824,7 @@ async function runInitCommand(name, options) {
|
|
|
25732
25824
|
persistDatabaseUrl(cwd, databaseUrl);
|
|
25733
25825
|
} else {
|
|
25734
25826
|
databaseStep.skip();
|
|
25735
|
-
|
|
25827
|
+
p18.log.info("Falling back to a manual database connection string.");
|
|
25736
25828
|
openBrowserVercelNeon();
|
|
25737
25829
|
databaseUrl = await promptConnectionString();
|
|
25738
25830
|
}
|
|
@@ -25774,21 +25866,19 @@ async function runInitCommand(name, options) {
|
|
|
25774
25866
|
});
|
|
25775
25867
|
if (flow.ok && flow.token) {
|
|
25776
25868
|
persistBlobReadWriteToken(cwd, flow.token);
|
|
25777
|
-
p17.log.success(`Saved BLOB_READ_WRITE_TOKEN to ${pc7.cyan(".env.local")}`);
|
|
25778
25869
|
collectedIntegrationConfig.sections.push({
|
|
25779
25870
|
header: "Storage (Vercel Blob)",
|
|
25780
25871
|
vars: [{ key: "BLOB_READ_WRITE_TOKEN", value: flow.token }]
|
|
25781
25872
|
});
|
|
25782
25873
|
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
25874
|
} else {
|
|
25791
|
-
|
|
25875
|
+
p18.log.warn(
|
|
25876
|
+
"Continuing without a Blob token \u2014 add BLOB_READ_WRITE_TOKEN to .env.local from the store on vercel.com/dashboard/stores."
|
|
25877
|
+
);
|
|
25878
|
+
collectedIntegrationConfig.sections.push({
|
|
25879
|
+
header: "Storage (Vercel Blob)",
|
|
25880
|
+
vars: [{ key: "BLOB_READ_WRITE_TOKEN", value: "" }]
|
|
25881
|
+
});
|
|
25792
25882
|
}
|
|
25793
25883
|
}
|
|
25794
25884
|
} else if (options.yes) {
|
|
@@ -25891,7 +25981,7 @@ async function runInitCommand(name, options) {
|
|
|
25891
25981
|
});
|
|
25892
25982
|
s.stop("");
|
|
25893
25983
|
process.stdout.write("\x1B[2A\x1B[J");
|
|
25894
|
-
|
|
25984
|
+
p18.note(noteLines.join("\n"), "Scaffolded admin");
|
|
25895
25985
|
const drizzleConfigPath = path50.join(cwd, "drizzle.config.ts");
|
|
25896
25986
|
if (!dbFiles.includes("drizzle.config.ts") && fs39.existsSync(drizzleConfigPath)) {
|
|
25897
25987
|
if (forceMode) {
|
|
@@ -25901,20 +25991,20 @@ async function runInitCommand(name, options) {
|
|
|
25901
25991
|
readNamespacedTemplate("drizzle.config.ts", namespace),
|
|
25902
25992
|
"utf-8"
|
|
25903
25993
|
);
|
|
25904
|
-
|
|
25994
|
+
p18.log.success("Updated drizzle.config.ts");
|
|
25905
25995
|
} else if (!options.yes) {
|
|
25906
|
-
const overwrite = await
|
|
25996
|
+
const overwrite = await p18.confirm({
|
|
25907
25997
|
message: "drizzle.config.ts already exists. Overwrite with latest version?",
|
|
25908
25998
|
initialValue: true
|
|
25909
25999
|
});
|
|
25910
|
-
if (!
|
|
26000
|
+
if (!p18.isCancel(overwrite) && overwrite) {
|
|
25911
26001
|
const { readNamespacedTemplate } = await import("./template-reader-X6KFP7B3.js");
|
|
25912
26002
|
fs39.writeFileSync(
|
|
25913
26003
|
drizzleConfigPath,
|
|
25914
26004
|
readNamespacedTemplate("drizzle.config.ts", namespace),
|
|
25915
26005
|
"utf-8"
|
|
25916
26006
|
);
|
|
25917
|
-
|
|
26007
|
+
p18.log.success("Updated drizzle.config.ts");
|
|
25918
26008
|
}
|
|
25919
26009
|
}
|
|
25920
26010
|
}
|
|
@@ -25940,8 +26030,8 @@ async function runInitCommand(name, options) {
|
|
|
25940
26030
|
depsInstalled = true;
|
|
25941
26031
|
} else {
|
|
25942
26032
|
s.stop("Failed to install dependencies");
|
|
25943
|
-
|
|
25944
|
-
|
|
26033
|
+
p18.log.warning(depsResult.error ?? "Unknown error");
|
|
26034
|
+
p18.log.info(
|
|
25945
26035
|
`You can install them manually:
|
|
25946
26036
|
${pc7.cyan(`${pm} add ${depsResult.dependencies.join(" ")}`)}
|
|
25947
26037
|
${pc7.cyan(`${pm} add -D ${depsResult.devDeps.join(" ")}`)}`
|
|
@@ -26031,10 +26121,10 @@ async function runInitCommand(name, options) {
|
|
|
26031
26121
|
` ${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
26122
|
);
|
|
26033
26123
|
}
|
|
26034
|
-
|
|
26124
|
+
p18.note(installLines.join("\n"), "Installed");
|
|
26035
26125
|
let dbPushed = false;
|
|
26036
26126
|
if (depsResult.success && options.skipMigration && hasDbUrl(cwd)) {
|
|
26037
|
-
|
|
26127
|
+
p18.log.info(`Skipping database schema push ${pc7.dim("(--skip-migration)")}`);
|
|
26038
26128
|
} else if (depsResult.success && hasDbUrl(cwd)) {
|
|
26039
26129
|
let driverReady = hasDrizzleKitPostgresDriverDependency(cwd);
|
|
26040
26130
|
if (!driverReady) {
|
|
@@ -26049,8 +26139,8 @@ async function runInitCommand(name, options) {
|
|
|
26049
26139
|
});
|
|
26050
26140
|
if (!driverResult.success) {
|
|
26051
26141
|
s.stop("Database push failed");
|
|
26052
|
-
|
|
26053
|
-
|
|
26142
|
+
p18.log.warning(driverResult.error ?? `Failed to install ${DRIZZLE_KIT_POSTGRES_DRIVER_DEP}`);
|
|
26143
|
+
p18.log.info(
|
|
26054
26144
|
`Install ${DRIZZLE_KIT_POSTGRES_DRIVER_DEP} manually, then run: ${pc7.cyan(drizzlePushCommand(pm))}`
|
|
26055
26145
|
);
|
|
26056
26146
|
} else {
|
|
@@ -26061,7 +26151,7 @@ async function runInitCommand(name, options) {
|
|
|
26061
26151
|
if (driverReady) {
|
|
26062
26152
|
const useTerminalForDbPush = shouldUseTerminalForDbPush(options);
|
|
26063
26153
|
if (useTerminalForDbPush) {
|
|
26064
|
-
|
|
26154
|
+
p18.log.info(`Running ${pc7.cyan("drizzle-kit push --force")}`);
|
|
26065
26155
|
} else {
|
|
26066
26156
|
s.start("Pushing database schema (drizzle-kit push)");
|
|
26067
26157
|
}
|
|
@@ -26070,13 +26160,13 @@ async function runInitCommand(name, options) {
|
|
|
26070
26160
|
if (useTerminalForDbPush) {
|
|
26071
26161
|
const verification = await verifyDatabaseReachable(cwd);
|
|
26072
26162
|
if (!verification.success) {
|
|
26073
|
-
|
|
26074
|
-
|
|
26163
|
+
p18.log.warning(verification.error);
|
|
26164
|
+
p18.log.error("Database was not reachable. Aborting setup.");
|
|
26075
26165
|
process.exit(1);
|
|
26076
26166
|
}
|
|
26077
26167
|
}
|
|
26078
26168
|
if (useTerminalForDbPush) {
|
|
26079
|
-
|
|
26169
|
+
p18.log.success("Database schema pushed");
|
|
26080
26170
|
} else {
|
|
26081
26171
|
s.stop(`${pc7.green("\u2713")} Database schema pushed`);
|
|
26082
26172
|
}
|
|
@@ -26086,12 +26176,12 @@ async function runInitCommand(name, options) {
|
|
|
26086
26176
|
s.stop("Database push failed");
|
|
26087
26177
|
}
|
|
26088
26178
|
const pushError = pushResult.error ?? "Unknown error";
|
|
26089
|
-
|
|
26179
|
+
p18.log.warning(pushError);
|
|
26090
26180
|
if (isDatabaseReachabilityError(pushError)) {
|
|
26091
|
-
|
|
26181
|
+
p18.log.error("Database was not reachable. Aborting setup.");
|
|
26092
26182
|
process.exit(1);
|
|
26093
26183
|
}
|
|
26094
|
-
|
|
26184
|
+
p18.log.info(`You can run it manually: ${pc7.cyan(drizzlePushCommand(pm))}`);
|
|
26095
26185
|
}
|
|
26096
26186
|
}
|
|
26097
26187
|
}
|
|
@@ -26100,7 +26190,7 @@ async function runInitCommand(name, options) {
|
|
|
26100
26190
|
let seedSuccess = false;
|
|
26101
26191
|
let adminAccountReady = false;
|
|
26102
26192
|
if (dbPushed && options.skipAdminCreation) {
|
|
26103
|
-
|
|
26193
|
+
p18.log.info(
|
|
26104
26194
|
`Skipping admin user creation ${pc7.dim(`(use ${betterstartExecCommand(pm, "seed")} later)`)}`
|
|
26105
26195
|
);
|
|
26106
26196
|
}
|
|
@@ -26110,14 +26200,14 @@ async function runInitCommand(name, options) {
|
|
|
26110
26200
|
let replaceExistingAdmin = false;
|
|
26111
26201
|
const adminCheck = await checkExistingAdmin(cwd, adminDir, authBasePath);
|
|
26112
26202
|
if (adminCheck.error) {
|
|
26113
|
-
|
|
26203
|
+
p18.log.warning(`Could not verify existing admin account ${pc7.dim(`(${adminCheck.error})`)}`);
|
|
26114
26204
|
if (isDatabaseReachabilityError(adminCheck.error)) {
|
|
26115
|
-
|
|
26205
|
+
p18.log.error("Database was not reachable. Aborting setup.");
|
|
26116
26206
|
process.exit(1);
|
|
26117
26207
|
}
|
|
26118
26208
|
} else if (adminCheck.existingAdmin) {
|
|
26119
26209
|
const existingAdminLabel = formatAdminIdentity(adminCheck.existingAdmin);
|
|
26120
|
-
const adminAction = await
|
|
26210
|
+
const adminAction = await p18.select({
|
|
26121
26211
|
message: "Found an already existing admin account. Do you want to replace it or skip?",
|
|
26122
26212
|
options: [
|
|
26123
26213
|
{
|
|
@@ -26131,34 +26221,34 @@ async function runInitCommand(name, options) {
|
|
|
26131
26221
|
}
|
|
26132
26222
|
]
|
|
26133
26223
|
});
|
|
26134
|
-
if (
|
|
26135
|
-
|
|
26224
|
+
if (p18.isCancel(adminAction)) {
|
|
26225
|
+
p18.cancel("Setup cancelled.");
|
|
26136
26226
|
process.exit(0);
|
|
26137
26227
|
}
|
|
26138
26228
|
if (adminAction === "skip") {
|
|
26139
26229
|
adminAccountReady = true;
|
|
26140
|
-
|
|
26230
|
+
p18.log.info(`Keeping existing admin account ${pc7.dim(`(${existingAdminLabel})`)}`);
|
|
26141
26231
|
} else {
|
|
26142
26232
|
replaceExistingAdmin = true;
|
|
26143
26233
|
}
|
|
26144
26234
|
}
|
|
26145
26235
|
if (!adminAccountReady) {
|
|
26146
|
-
|
|
26236
|
+
p18.note(
|
|
26147
26237
|
pc7.dim(
|
|
26148
26238
|
replaceExistingAdmin ? "Replace the existing admin account to access the admin." : "Create your first admin user to access the dashboard."
|
|
26149
26239
|
),
|
|
26150
26240
|
"Admin account"
|
|
26151
26241
|
);
|
|
26152
|
-
const credentials = await
|
|
26242
|
+
const credentials = await p18.group(
|
|
26153
26243
|
{
|
|
26154
|
-
email: () =>
|
|
26244
|
+
email: () => p18.text({
|
|
26155
26245
|
message: "Admin email",
|
|
26156
26246
|
placeholder: "admin@example.com",
|
|
26157
26247
|
validate: (v) => {
|
|
26158
26248
|
if (!v || !v.includes("@")) return "Please enter a valid email";
|
|
26159
26249
|
}
|
|
26160
26250
|
}),
|
|
26161
|
-
password: () =>
|
|
26251
|
+
password: () => p18.password({
|
|
26162
26252
|
message: "Admin password",
|
|
26163
26253
|
validate: (v) => {
|
|
26164
26254
|
if (!v || v.length < 8) return "Password must be at least 8 characters";
|
|
@@ -26167,7 +26257,7 @@ async function runInitCommand(name, options) {
|
|
|
26167
26257
|
},
|
|
26168
26258
|
{
|
|
26169
26259
|
onCancel: () => {
|
|
26170
|
-
|
|
26260
|
+
p18.cancel("Setup cancelled.");
|
|
26171
26261
|
process.exit(0);
|
|
26172
26262
|
}
|
|
26173
26263
|
}
|
|
@@ -26186,11 +26276,11 @@ async function runInitCommand(name, options) {
|
|
|
26186
26276
|
);
|
|
26187
26277
|
if (seedResult.existingUser) {
|
|
26188
26278
|
s.stop(`${pc7.yellow("\u25B2")} An account already exists for ${credentials.email}`);
|
|
26189
|
-
const replace = await
|
|
26279
|
+
const replace = await p18.confirm({
|
|
26190
26280
|
message: "Replace the existing account with this email?",
|
|
26191
26281
|
initialValue: false
|
|
26192
26282
|
});
|
|
26193
|
-
if (!
|
|
26283
|
+
if (!p18.isCancel(replace) && replace) {
|
|
26194
26284
|
seedOverwriteMode = "email";
|
|
26195
26285
|
s.start("Replacing admin user");
|
|
26196
26286
|
seedResult = await runSeed(
|
|
@@ -26211,14 +26301,14 @@ async function runInitCommand(name, options) {
|
|
|
26211
26301
|
adminAccountReady = true;
|
|
26212
26302
|
} else if (seedResult.error) {
|
|
26213
26303
|
s.stop(`${pc7.red("\u2717")} Failed to create admin user`);
|
|
26214
|
-
|
|
26304
|
+
p18.note(
|
|
26215
26305
|
`${pc7.red(seedResult.error)}
|
|
26216
26306
|
|
|
26217
26307
|
Run manually: ${pc7.cyan(betterstartExecCommand(pm, "seed"))}`,
|
|
26218
26308
|
pc7.red("Seed failed")
|
|
26219
26309
|
);
|
|
26220
26310
|
if (isDatabaseReachabilityError(seedResult.error)) {
|
|
26221
|
-
|
|
26311
|
+
p18.log.error("Database was not reachable. Aborting setup.");
|
|
26222
26312
|
process.exit(1);
|
|
26223
26313
|
}
|
|
26224
26314
|
}
|
|
@@ -26250,16 +26340,16 @@ Run manually: ${pc7.cyan(betterstartExecCommand(pm, "seed"))}`,
|
|
|
26250
26340
|
`Files created: ${pc7.cyan(String(totalFiles))}`,
|
|
26251
26341
|
`Env vars: ${envResult.added.length} added, ${envResult.skipped.length} skipped`
|
|
26252
26342
|
];
|
|
26253
|
-
|
|
26343
|
+
p18.note(summaryLines.join("\n"), "Admin scaffolded successfully");
|
|
26254
26344
|
if (options.vercel !== false && !options.skipDeploy) {
|
|
26255
26345
|
const linkedVercelProject = Boolean(readLinkedProjectId(cwd));
|
|
26256
26346
|
if (!options.yes) {
|
|
26257
26347
|
const deployStep = deferNextPromptCheck();
|
|
26258
|
-
const deployNow = await
|
|
26348
|
+
const deployNow = await p18.confirm({
|
|
26259
26349
|
message: "Deploy to Vercel now?",
|
|
26260
26350
|
initialValue: linkedVercelProject
|
|
26261
26351
|
});
|
|
26262
|
-
if (!
|
|
26352
|
+
if (!p18.isCancel(deployNow) && deployNow) {
|
|
26263
26353
|
const deployFlow = await runVercelDeployFlow({ cwd, projectName, env: process.env });
|
|
26264
26354
|
if (deployFlow.ok && deployFlow.cleanScreen) deployStep.confirm();
|
|
26265
26355
|
else deployStep.skip();
|
|
@@ -26273,17 +26363,18 @@ Run manually: ${pc7.cyan(betterstartExecCommand(pm, "seed"))}`,
|
|
|
26273
26363
|
env: process.env
|
|
26274
26364
|
});
|
|
26275
26365
|
if (!deployFlow.ok) {
|
|
26276
|
-
|
|
26366
|
+
p18.log.warn("Vercel deploy did not complete; continuing.");
|
|
26277
26367
|
}
|
|
26278
26368
|
}
|
|
26279
26369
|
}
|
|
26280
26370
|
if (!options.yes && !options.skipDevServerStart) {
|
|
26281
26371
|
const devCmd = runCommand(pm, "dev");
|
|
26282
|
-
const startDev = await
|
|
26372
|
+
const startDev = await p18.confirm({
|
|
26283
26373
|
message: "Start the development server?",
|
|
26284
26374
|
initialValue: true
|
|
26285
26375
|
});
|
|
26286
|
-
if (!
|
|
26376
|
+
if (!p18.isCancel(startDev) && startDev) {
|
|
26377
|
+
disposeCancelGuard();
|
|
26287
26378
|
await startManagedDevServer(cwd, devCmd, adminLoginUrl, {
|
|
26288
26379
|
email: seedSuccess && seedEmail ? seedEmail : void 0,
|
|
26289
26380
|
password: seedSuccess && seedPassword ? seedPassword : void 0
|
|
@@ -26291,7 +26382,8 @@ Run manually: ${pc7.cyan(betterstartExecCommand(pm, "seed"))}`,
|
|
|
26291
26382
|
return;
|
|
26292
26383
|
}
|
|
26293
26384
|
}
|
|
26294
|
-
|
|
26385
|
+
disposeCancelGuard();
|
|
26386
|
+
p18.outro("Done!");
|
|
26295
26387
|
}
|
|
26296
26388
|
function isValidDbUrl(url) {
|
|
26297
26389
|
return url.startsWith("postgres://") || url.startsWith("postgresql://");
|
|
@@ -26678,7 +26770,7 @@ function printAdminReadyNote(state) {
|
|
|
26678
26770
|
lines.unshift(`Password: ${pc7.cyan(state.adminPassword)}`);
|
|
26679
26771
|
lines.unshift(`Admin user: ${pc7.cyan(state.adminEmail)}`);
|
|
26680
26772
|
}
|
|
26681
|
-
|
|
26773
|
+
p18.note(lines.join("\n"), "Admin ready");
|
|
26682
26774
|
}
|
|
26683
26775
|
function shouldSuppressDevServerStartupLine(line) {
|
|
26684
26776
|
const plain = stripAnsi2(line).trim();
|
|
@@ -26790,7 +26882,7 @@ function startManagedDevServer(cwd, devCmd, adminLoginUrl, adminCredentials) {
|
|
|
26790
26882
|
|
|
26791
26883
|
// adapters/next/commands/list-integrations.ts
|
|
26792
26884
|
import path51 from "path";
|
|
26793
|
-
import * as
|
|
26885
|
+
import * as p19 from "@clack/prompts";
|
|
26794
26886
|
async function runListIntegrationsCommand(options) {
|
|
26795
26887
|
const cwd = options.cwd ? path51.resolve(options.cwd) : process.cwd();
|
|
26796
26888
|
const config = await resolveConfig(cwd);
|
|
@@ -26799,15 +26891,15 @@ async function runListIntegrationsCommand(options) {
|
|
|
26799
26891
|
const status = installedIntegrations.has(integration.id) ? "installed" : "available";
|
|
26800
26892
|
return `${integration.id.padEnd(12)} ${status.padEnd(10)} ${integration.kind.padEnd(8)} ${integration.description}`;
|
|
26801
26893
|
});
|
|
26802
|
-
|
|
26803
|
-
|
|
26894
|
+
p19.note(lines.join("\n"), "BetterStart integrations");
|
|
26895
|
+
p19.outro(
|
|
26804
26896
|
`${installedIntegrations.size} installed, ${lines.length - installedIntegrations.size} available`
|
|
26805
26897
|
);
|
|
26806
26898
|
}
|
|
26807
26899
|
|
|
26808
26900
|
// adapters/next/commands/list-plugins.ts
|
|
26809
26901
|
import path52 from "path";
|
|
26810
|
-
import * as
|
|
26902
|
+
import * as p20 from "@clack/prompts";
|
|
26811
26903
|
async function runListPluginsCommand(options) {
|
|
26812
26904
|
const cwd = options.cwd ? path52.resolve(options.cwd) : process.cwd();
|
|
26813
26905
|
const config = await resolveConfig(cwd);
|
|
@@ -26816,34 +26908,34 @@ async function runListPluginsCommand(options) {
|
|
|
26816
26908
|
const status = installedPlugins.has(plugin.id) ? "installed" : "available";
|
|
26817
26909
|
return `${plugin.id.padEnd(10)} ${status.padEnd(10)} ${plugin.kind.padEnd(12)} ${plugin.description}`;
|
|
26818
26910
|
});
|
|
26819
|
-
|
|
26820
|
-
|
|
26911
|
+
p20.note(lines.join("\n"), "BetterStart plugins");
|
|
26912
|
+
p20.outro(`${installedPlugins.size} installed, ${lines.length - installedPlugins.size} available`);
|
|
26821
26913
|
}
|
|
26822
26914
|
|
|
26823
26915
|
// adapters/next/commands/remove.ts
|
|
26824
26916
|
import path53 from "path";
|
|
26825
|
-
import * as
|
|
26917
|
+
import * as p21 from "@clack/prompts";
|
|
26826
26918
|
async function runRemoveCommand(items, options) {
|
|
26827
26919
|
const removeIntegrationsMode = Boolean(options.integration);
|
|
26828
26920
|
if (!removeIntegrationsMode && items.includes("core")) {
|
|
26829
|
-
|
|
26921
|
+
p21.log.error("The core Admin cannot be removed.");
|
|
26830
26922
|
process.exit(1);
|
|
26831
26923
|
}
|
|
26832
26924
|
const pluginIds = items.filter(isPluginId);
|
|
26833
26925
|
const integrationIds = items.filter(isIntegrationId);
|
|
26834
26926
|
if (!removeIntegrationsMode && integrationIds.length > 0) {
|
|
26835
|
-
|
|
26927
|
+
p21.log.error(
|
|
26836
26928
|
`Integration IDs require --integration. Run \`betterstart remove --integration ${integrationIds.join(" ")}\`.`
|
|
26837
26929
|
);
|
|
26838
26930
|
process.exit(1);
|
|
26839
26931
|
}
|
|
26840
26932
|
if (removeIntegrationsMode && pluginIds.length > 0) {
|
|
26841
|
-
|
|
26933
|
+
p21.log.error(`Plugin IDs cannot be removed with --integration: ${pluginIds.join(", ")}`);
|
|
26842
26934
|
process.exit(1);
|
|
26843
26935
|
}
|
|
26844
26936
|
const invalidItems = removeIntegrationsMode ? items.filter((integrationId) => !isIntegrationId(integrationId)) : items.filter((pluginId) => !isPluginId(pluginId));
|
|
26845
26937
|
if (invalidItems.length > 0) {
|
|
26846
|
-
|
|
26938
|
+
p21.log.error(
|
|
26847
26939
|
removeIntegrationsMode ? formatUnknownIntegrationMessage(invalidItems) : formatUnknownPluginMessage(invalidItems)
|
|
26848
26940
|
);
|
|
26849
26941
|
process.exit(1);
|
|
@@ -26852,12 +26944,12 @@ async function runRemoveCommand(items, options) {
|
|
|
26852
26944
|
const config = await resolveConfig(cwd);
|
|
26853
26945
|
const pm = detectPackageManager(cwd);
|
|
26854
26946
|
if (!options.force) {
|
|
26855
|
-
const confirmed = await
|
|
26947
|
+
const confirmed = await p21.confirm({
|
|
26856
26948
|
message: `Remove ${removeIntegrationsMode ? "integration" : "plugin"}${items.length === 1 ? "" : "s"} ${items.join(", ")}?`,
|
|
26857
26949
|
initialValue: false
|
|
26858
26950
|
});
|
|
26859
|
-
if (
|
|
26860
|
-
|
|
26951
|
+
if (p21.isCancel(confirmed) || !confirmed) {
|
|
26952
|
+
p21.cancel(`${removeIntegrationsMode ? "Integration" : "Plugin"} removal cancelled.`);
|
|
26861
26953
|
process.exit(0);
|
|
26862
26954
|
}
|
|
26863
26955
|
}
|
|
@@ -26870,13 +26962,13 @@ async function runRemoveCommand(items, options) {
|
|
|
26870
26962
|
});
|
|
26871
26963
|
writeConfigFile(cwd, result2.config);
|
|
26872
26964
|
if (result2.removed.length === 0) {
|
|
26873
|
-
|
|
26965
|
+
p21.outro("No integrations were removed.");
|
|
26874
26966
|
return;
|
|
26875
26967
|
}
|
|
26876
26968
|
if (result2.warnings.length > 0) {
|
|
26877
|
-
|
|
26969
|
+
p21.note(result2.warnings.join("\n"), "Warnings");
|
|
26878
26970
|
}
|
|
26879
|
-
|
|
26971
|
+
p21.outro(
|
|
26880
26972
|
`Removed integration${result2.removed.length === 1 ? "" : "s"}: ${result2.removed.join(", ")}`
|
|
26881
26973
|
);
|
|
26882
26974
|
return;
|
|
@@ -26889,13 +26981,13 @@ async function runRemoveCommand(items, options) {
|
|
|
26889
26981
|
});
|
|
26890
26982
|
writeConfigFile(cwd, result.config);
|
|
26891
26983
|
if (result.removed.length === 0) {
|
|
26892
|
-
|
|
26984
|
+
p21.outro("No plugins were removed.");
|
|
26893
26985
|
return;
|
|
26894
26986
|
}
|
|
26895
26987
|
if (result.warnings.length > 0) {
|
|
26896
|
-
|
|
26988
|
+
p21.note(result.warnings.join("\n"), "Warnings");
|
|
26897
26989
|
}
|
|
26898
|
-
|
|
26990
|
+
p21.outro(`Removed plugin${result.removed.length === 1 ? "" : "s"}: ${result.removed.join(", ")}`);
|
|
26899
26991
|
}
|
|
26900
26992
|
|
|
26901
26993
|
// adapters/next/commands/remove-schema.ts
|
|
@@ -27045,7 +27137,7 @@ async function runRemoveSchemaCommand(schemaName, options) {
|
|
|
27045
27137
|
// adapters/next/commands/uninstall.ts
|
|
27046
27138
|
import fs42 from "fs";
|
|
27047
27139
|
import path55 from "path";
|
|
27048
|
-
import * as
|
|
27140
|
+
import * as p22 from "@clack/prompts";
|
|
27049
27141
|
import pc8 from "picocolors";
|
|
27050
27142
|
|
|
27051
27143
|
// adapters/next/commands/uninstall-cleaners.ts
|
|
@@ -27267,8 +27359,8 @@ function buildUninstallPlan(cwd, namespaceValue) {
|
|
|
27267
27359
|
count: configFiles.length,
|
|
27268
27360
|
unit: configFiles.length === 1 ? "file" : "files",
|
|
27269
27361
|
execute() {
|
|
27270
|
-
for (const
|
|
27271
|
-
if (fs42.existsSync(
|
|
27362
|
+
for (const p23 of configPaths) {
|
|
27363
|
+
if (fs42.existsSync(p23)) fs42.unlinkSync(p23);
|
|
27272
27364
|
}
|
|
27273
27365
|
}
|
|
27274
27366
|
});
|
|
@@ -27332,7 +27424,7 @@ function buildUninstallPlan(cwd, namespaceValue) {
|
|
|
27332
27424
|
}
|
|
27333
27425
|
async function runUninstallCommand(options) {
|
|
27334
27426
|
const cwd = options.cwd ? path55.resolve(options.cwd) : process.cwd();
|
|
27335
|
-
|
|
27427
|
+
p22.intro(pc8.bgRed(pc8.white(" BetterStart Uninstall ")));
|
|
27336
27428
|
let namespace = DEFAULT_ADMIN_NAMESPACE;
|
|
27337
27429
|
try {
|
|
27338
27430
|
const config = await resolveConfig(cwd);
|
|
@@ -27341,8 +27433,8 @@ async function runUninstallCommand(options) {
|
|
|
27341
27433
|
}
|
|
27342
27434
|
const steps = buildUninstallPlan(cwd, namespace);
|
|
27343
27435
|
if (steps.length === 0) {
|
|
27344
|
-
|
|
27345
|
-
|
|
27436
|
+
p22.log.success(`${pc8.green("\u2713")} Nothing to remove \u2014 project is already clean.`);
|
|
27437
|
+
p22.outro("Done");
|
|
27346
27438
|
return;
|
|
27347
27439
|
}
|
|
27348
27440
|
const planLines = steps.map((step) => {
|
|
@@ -27350,14 +27442,14 @@ async function runUninstallCommand(options) {
|
|
|
27350
27442
|
const countLabel = pc8.dim(`${step.count} ${step.unit}`);
|
|
27351
27443
|
return `${pc8.red("\xD7")} ${names} ${countLabel}`;
|
|
27352
27444
|
});
|
|
27353
|
-
|
|
27445
|
+
p22.note(planLines.join("\n"), "Uninstall plan");
|
|
27354
27446
|
if (!options.force) {
|
|
27355
|
-
const confirmed = await
|
|
27447
|
+
const confirmed = await p22.confirm({
|
|
27356
27448
|
message: "Proceed with uninstall?",
|
|
27357
27449
|
initialValue: false
|
|
27358
27450
|
});
|
|
27359
|
-
if (
|
|
27360
|
-
|
|
27451
|
+
if (p22.isCancel(confirmed) || !confirmed) {
|
|
27452
|
+
p22.cancel("Uninstall cancelled.");
|
|
27361
27453
|
process.exit(0);
|
|
27362
27454
|
}
|
|
27363
27455
|
}
|
|
@@ -27369,8 +27461,8 @@ async function runUninstallCommand(options) {
|
|
|
27369
27461
|
}
|
|
27370
27462
|
const parts = steps.map((step) => `${step.count} ${step.unit}`);
|
|
27371
27463
|
s.stop(`Removed ${parts.join(", ")}`);
|
|
27372
|
-
|
|
27373
|
-
|
|
27464
|
+
p22.note(pc8.dim("Database tables were NOT dropped \u2014 drop them manually if needed."), "Next steps");
|
|
27465
|
+
p22.outro("Uninstall complete");
|
|
27374
27466
|
}
|
|
27375
27467
|
|
|
27376
27468
|
// adapters/next/commands/update-component.ts
|