betterstart-cli 0.0.29 → 0.0.31
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 +84 -73
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -21852,6 +21852,16 @@ function openBrowserVercelNeon() {
|
|
|
21852
21852
|
`Opening Vercel... Create a Neon Postgres database, then copy the ${pc.cyan("DATABASE_URL")} from the dashboard.`
|
|
21853
21853
|
);
|
|
21854
21854
|
}
|
|
21855
|
+
function openBrowserVercelNeonResource(url) {
|
|
21856
|
+
if (!url) {
|
|
21857
|
+
openBrowserVercelNeon();
|
|
21858
|
+
return;
|
|
21859
|
+
}
|
|
21860
|
+
openBrowser(url);
|
|
21861
|
+
p10.log.info(
|
|
21862
|
+
`Opening Vercel... Copy the Neon ${pc.cyan("DATABASE_URL")} from the database dashboard, then paste it below.`
|
|
21863
|
+
);
|
|
21864
|
+
}
|
|
21855
21865
|
async function promptConnectionString() {
|
|
21856
21866
|
const input = await p10.text({
|
|
21857
21867
|
message: "Paste your PostgreSQL connection string",
|
|
@@ -24655,25 +24665,17 @@ import pc5 from "picocolors";
|
|
|
24655
24665
|
var PROVISION_TIMEOUT_MS2 = 18e4;
|
|
24656
24666
|
var INTERACTIVE_PROVISION_TIMEOUT_MS2 = 6e5;
|
|
24657
24667
|
async function provisionNeonInteractive(runner, cwd, options) {
|
|
24658
|
-
const addArgs = ["integration", "add", "neon", "--no-env-pull"];
|
|
24659
|
-
if (options.plan) addArgs.push("--plan", options.plan);
|
|
24660
24668
|
const quietSpinner = spinner2();
|
|
24661
24669
|
quietSpinner.start("Creating your Neon database");
|
|
24662
|
-
const quiet = await runVercel(runner,
|
|
24670
|
+
const quiet = await runVercel(runner, neonAddArgs(options), {
|
|
24663
24671
|
cwd,
|
|
24664
24672
|
mode: "capture",
|
|
24665
24673
|
timeoutMs: PROVISION_TIMEOUT_MS2,
|
|
24666
24674
|
env: options.env
|
|
24667
24675
|
});
|
|
24668
24676
|
if (quiet.success) {
|
|
24669
|
-
quietSpinner.message("Retrieving the database connection string");
|
|
24670
|
-
const databaseUrl2 = await pullDatabaseUrl(runner, cwd, options.env);
|
|
24671
|
-
if (!databaseUrl2) {
|
|
24672
|
-
quietSpinner.stop("No DATABASE_URL came back from Vercel");
|
|
24673
|
-
return { failure: "env-pull-empty" };
|
|
24674
|
-
}
|
|
24675
24677
|
quietSpinner.clear();
|
|
24676
|
-
return
|
|
24678
|
+
return readNeonProvisionInfo(quiet.stdout);
|
|
24677
24679
|
}
|
|
24678
24680
|
quietSpinner.clear();
|
|
24679
24681
|
p15.log.info(
|
|
@@ -24681,7 +24683,7 @@ async function provisionNeonInteractive(runner, cwd, options) {
|
|
|
24681
24683
|
"(the Free plan is recommended)."
|
|
24682
24684
|
)}`
|
|
24683
24685
|
);
|
|
24684
|
-
const add = await runVercel(runner,
|
|
24686
|
+
const add = await runVercel(runner, connectedNeonAddArgs(options), {
|
|
24685
24687
|
cwd,
|
|
24686
24688
|
mode: "inherit",
|
|
24687
24689
|
timeoutMs: INTERACTIVE_PROVISION_TIMEOUT_MS2,
|
|
@@ -24690,22 +24692,12 @@ async function provisionNeonInteractive(runner, cwd, options) {
|
|
|
24690
24692
|
if (!add.success) {
|
|
24691
24693
|
return { failure: add.timedOut ? "timeout" : "provision-failed" };
|
|
24692
24694
|
}
|
|
24693
|
-
|
|
24694
|
-
pullSpinner.start("Retrieving the database connection string");
|
|
24695
|
-
const databaseUrl = await pullDatabaseUrl(runner, cwd, options.env);
|
|
24696
|
-
if (!databaseUrl) {
|
|
24697
|
-
pullSpinner.stop("No DATABASE_URL came back from Vercel");
|
|
24698
|
-
return { failure: "env-pull-empty" };
|
|
24699
|
-
}
|
|
24700
|
-
pullSpinner.clear();
|
|
24701
|
-
return { databaseUrl };
|
|
24695
|
+
return {};
|
|
24702
24696
|
}
|
|
24703
24697
|
async function provisionNeon(runner, cwd, options) {
|
|
24704
|
-
const addArgs = ["integration", "add", "neon", "--no-env-pull", "--format", "json"];
|
|
24705
|
-
if (options.plan) addArgs.push("--plan", options.plan);
|
|
24706
24698
|
const provisionSpinner = spinner2();
|
|
24707
24699
|
provisionSpinner.start("Creating your Neon database");
|
|
24708
|
-
const add = await runVercel(runner,
|
|
24700
|
+
const add = await runVercel(runner, neonAddArgs(options), {
|
|
24709
24701
|
cwd,
|
|
24710
24702
|
mode: "capture",
|
|
24711
24703
|
timeoutMs: PROVISION_TIMEOUT_MS2,
|
|
@@ -24720,33 +24712,34 @@ ${add.stderr}`.trim();
|
|
|
24720
24712
|
if (/claim/i.test(combined)) return { failure: "claim-required", detail };
|
|
24721
24713
|
return { failure: add.timedOut ? "timeout" : "provision-failed", detail };
|
|
24722
24714
|
}
|
|
24723
|
-
const meta = parseVercelJson(add.stdout);
|
|
24724
|
-
const resourceName = meta?.resourceName ?? meta?.name;
|
|
24725
|
-
provisionSpinner.message("Retrieving the database connection string");
|
|
24726
|
-
const databaseUrl = await pullDatabaseUrl(runner, cwd, options.env);
|
|
24727
|
-
if (!databaseUrl) {
|
|
24728
|
-
provisionSpinner.stop("No DATABASE_URL came back from Vercel");
|
|
24729
|
-
return { resourceName, failure: "env-pull-empty" };
|
|
24730
|
-
}
|
|
24731
24715
|
provisionSpinner.clear();
|
|
24732
|
-
return
|
|
24733
|
-
}
|
|
24734
|
-
function pullDatabaseUrl(runner, cwd, env) {
|
|
24735
|
-
return pullVercelEnvValue(runner, cwd, readDbUrlFromDotenv, env);
|
|
24716
|
+
return readNeonProvisionInfo(add.stdout);
|
|
24736
24717
|
}
|
|
24737
24718
|
function readDbUrlFromDotenv(filePath) {
|
|
24738
24719
|
const vars = parseDotenvFile(filePath);
|
|
24739
24720
|
const isPg = (v) => !!v && (v.startsWith("postgres://") || v.startsWith("postgresql://"));
|
|
24740
24721
|
if (isPg(vars.get("DATABASE_URL"))) return vars.get("DATABASE_URL");
|
|
24741
24722
|
if (isPg(vars.get("POSTGRES_URL"))) return vars.get("POSTGRES_URL");
|
|
24742
|
-
for (const [key, value] of vars) {
|
|
24743
|
-
if (/DATABASE_URL$/.test(key) && isPg(value)) return value;
|
|
24744
|
-
}
|
|
24745
|
-
for (const value of vars.values()) {
|
|
24746
|
-
if (isPg(value)) return value;
|
|
24747
|
-
}
|
|
24748
24723
|
return void 0;
|
|
24749
24724
|
}
|
|
24725
|
+
function readNeonProvisionInfo(stdout) {
|
|
24726
|
+
const meta = parseVercelJson(stdout);
|
|
24727
|
+
if (!meta) return {};
|
|
24728
|
+
const info = {};
|
|
24729
|
+
if (meta.dashboardUrl) info.dashboardUrl = meta.dashboardUrl;
|
|
24730
|
+
if (meta.ssoUrl?.resource) info.resourceUrl = meta.ssoUrl.resource;
|
|
24731
|
+
return info;
|
|
24732
|
+
}
|
|
24733
|
+
function neonAddArgs(options) {
|
|
24734
|
+
const addArgs = ["integration", "add", "neon", "--format", "json"];
|
|
24735
|
+
if (options.plan) addArgs.push("--plan", options.plan);
|
|
24736
|
+
return addArgs;
|
|
24737
|
+
}
|
|
24738
|
+
function connectedNeonAddArgs(options) {
|
|
24739
|
+
const addArgs = ["integration", "add", "neon"];
|
|
24740
|
+
if (options.plan) addArgs.push("--plan", options.plan);
|
|
24741
|
+
return addArgs;
|
|
24742
|
+
}
|
|
24750
24743
|
|
|
24751
24744
|
// adapters/next/init/vercel/flow.ts
|
|
24752
24745
|
async function runVercelNeonFlow(options) {
|
|
@@ -24762,23 +24755,19 @@ async function runVercelNeonFlow(options) {
|
|
|
24762
24755
|
p16.log.warn(authFailureMessage(auth.reason));
|
|
24763
24756
|
return { ok: false };
|
|
24764
24757
|
}
|
|
24765
|
-
|
|
24766
|
-
projectSpinner.start(`Creating a Vercel project ${pc6.cyan(options.projectName)}`);
|
|
24767
|
-
const project2 = await createVercelProject(runner, options.cwd, options.projectName, env);
|
|
24768
|
-
projectSpinner.stop(
|
|
24769
|
-
project2.linked ? `Linked Vercel project ${pc6.cyan(project2.name)}` : `Using Vercel project ${pc6.cyan(project2.name)}`
|
|
24770
|
-
);
|
|
24758
|
+
await ensureLinkedProject(runner, options.cwd, options.projectName, env);
|
|
24771
24759
|
const neon = await provisionNeonForMode(runner, options);
|
|
24772
|
-
if (neon.failure
|
|
24760
|
+
if (neon.failure) {
|
|
24773
24761
|
p16.log.warn(neonFailureMessage(neon.failure));
|
|
24774
24762
|
if (neon.detail) p16.log.message(pc6.dim(neon.detail));
|
|
24775
24763
|
return { ok: false };
|
|
24776
24764
|
}
|
|
24765
|
+
const databaseUrl = await pullNeonDatabaseUrl(runner, options.cwd, env);
|
|
24777
24766
|
return {
|
|
24778
24767
|
ok: true,
|
|
24779
|
-
databaseUrl
|
|
24780
|
-
|
|
24781
|
-
|
|
24768
|
+
databaseUrl,
|
|
24769
|
+
dashboardUrl: neon.dashboardUrl,
|
|
24770
|
+
resourceUrl: neon.resourceUrl
|
|
24782
24771
|
};
|
|
24783
24772
|
} catch (error) {
|
|
24784
24773
|
p16.log.warn(
|
|
@@ -24802,16 +24791,7 @@ async function runVercelBlobFlow(options) {
|
|
|
24802
24791
|
p16.log.warn(authFailureMessage(auth.reason));
|
|
24803
24792
|
return { ok: false };
|
|
24804
24793
|
}
|
|
24805
|
-
|
|
24806
|
-
if (!projectId) {
|
|
24807
|
-
const projectSpinner = spinner2();
|
|
24808
|
-
projectSpinner.start(`Creating a Vercel project ${pc6.cyan(options.projectName)}`);
|
|
24809
|
-
const project2 = await createVercelProject(runner, options.cwd, options.projectName, env);
|
|
24810
|
-
projectSpinner.stop(
|
|
24811
|
-
project2.linked ? `Linked Vercel project ${pc6.cyan(project2.name)}` : `Using Vercel project ${pc6.cyan(project2.name)}`
|
|
24812
|
-
);
|
|
24813
|
-
projectId = project2.projectId;
|
|
24814
|
-
}
|
|
24794
|
+
await ensureLinkedProject(runner, options.cwd, options.projectName, env);
|
|
24815
24795
|
const blob = await provisionBlobForMode(runner, options);
|
|
24816
24796
|
if (blob.failure || !blob.token) {
|
|
24817
24797
|
p16.log.warn(blobFailureMessage(blob.failure));
|
|
@@ -24821,7 +24801,6 @@ async function runVercelBlobFlow(options) {
|
|
|
24821
24801
|
return {
|
|
24822
24802
|
ok: true,
|
|
24823
24803
|
token: blob.token,
|
|
24824
|
-
vercelProjectId: projectId,
|
|
24825
24804
|
blobStoreName: blob.storeName
|
|
24826
24805
|
};
|
|
24827
24806
|
} catch (error) {
|
|
@@ -24847,14 +24826,7 @@ async function runVercelDeployFlow(options) {
|
|
|
24847
24826
|
printManualDeployHint();
|
|
24848
24827
|
return { ok: false };
|
|
24849
24828
|
}
|
|
24850
|
-
|
|
24851
|
-
const projectSpinner = spinner2();
|
|
24852
|
-
projectSpinner.start(`Creating a Vercel project ${pc6.cyan(options.projectName)}`);
|
|
24853
|
-
const project2 = await createVercelProject(runner, options.cwd, options.projectName, env);
|
|
24854
|
-
projectSpinner.stop(
|
|
24855
|
-
project2.linked ? `Linked Vercel project ${pc6.cyan(project2.name)}` : `Using Vercel project ${pc6.cyan(project2.name)}`
|
|
24856
|
-
);
|
|
24857
|
-
}
|
|
24829
|
+
await ensureLinkedProject(runner, options.cwd, options.projectName, env);
|
|
24858
24830
|
const envSpinner = spinner2();
|
|
24859
24831
|
envSpinner.start("Syncing environment variables to Vercel");
|
|
24860
24832
|
const sync = await syncVercelProductionEnv(runner, options.cwd, env);
|
|
@@ -24908,6 +24880,26 @@ async function runVercelDeployFlow(options) {
|
|
|
24908
24880
|
function printManualDeployHint() {
|
|
24909
24881
|
p16.log.info(`You can deploy manually: ${pc6.cyan("vercel deploy --prod")}`);
|
|
24910
24882
|
}
|
|
24883
|
+
async function ensureLinkedProject(runner, cwd, projectName, env) {
|
|
24884
|
+
if (readLinkedProjectId(cwd)) return;
|
|
24885
|
+
const projectSpinner = spinner2();
|
|
24886
|
+
projectSpinner.start(`Creating a Vercel project ${pc6.cyan(projectName)}`);
|
|
24887
|
+
const project2 = await createVercelProject(runner, cwd, projectName, env);
|
|
24888
|
+
projectSpinner.stop(
|
|
24889
|
+
project2.linked ? `Linked Vercel project ${pc6.cyan(project2.name)}` : `Using Vercel project ${pc6.cyan(project2.name)}`
|
|
24890
|
+
);
|
|
24891
|
+
}
|
|
24892
|
+
async function pullNeonDatabaseUrl(runner, cwd, env) {
|
|
24893
|
+
const neonSpinner = spinner2();
|
|
24894
|
+
neonSpinner.start("Retrieving DATABASE_URL from Vercel");
|
|
24895
|
+
const databaseUrl = await pullVercelEnvValue(runner, cwd, readDbUrlFromDotenv, env);
|
|
24896
|
+
if (!databaseUrl) {
|
|
24897
|
+
neonSpinner.stop(`${pc6.yellow("\u25B2")} No DATABASE_URL came back from Vercel`);
|
|
24898
|
+
return void 0;
|
|
24899
|
+
}
|
|
24900
|
+
neonSpinner.clear();
|
|
24901
|
+
return databaseUrl;
|
|
24902
|
+
}
|
|
24911
24903
|
function provisionBlobForMode(runner, options) {
|
|
24912
24904
|
const opts = { name: blobStoreName(options.projectName), env: options.env };
|
|
24913
24905
|
return options.interactive ? provisionBlobStoreInteractive(runner, options.cwd, opts) : provisionBlobStore(runner, options.cwd, opts);
|
|
@@ -24954,8 +24946,6 @@ function neonFailureMessage(reason) {
|
|
|
24954
24946
|
return "Provisioning needs the Neon marketplace terms accepted \u2014 falling back to manual entry.";
|
|
24955
24947
|
case "claim-required":
|
|
24956
24948
|
return "The Neon resource needs to be claimed \u2014 falling back to manual entry.";
|
|
24957
|
-
case "env-pull-empty":
|
|
24958
|
-
return "Provisioned Neon, but no DATABASE_URL came back \u2014 falling back to manual entry.";
|
|
24959
24949
|
case "timeout":
|
|
24960
24950
|
return "Neon provisioning timed out \u2014 falling back to manual entry.";
|
|
24961
24951
|
default:
|
|
@@ -25557,6 +25547,18 @@ async function runInitCommand(name, options) {
|
|
|
25557
25547
|
databaseUrl = flow.databaseUrl;
|
|
25558
25548
|
persistDatabaseUrl(cwd, databaseUrl);
|
|
25559
25549
|
p17.log.success(`Saved DATABASE_URL to ${pc7.cyan(".env.local")}`);
|
|
25550
|
+
} else if (flow.ok) {
|
|
25551
|
+
p17.log.warn("Created a Neon database, but DATABASE_URL could not be retrieved from Vercel.");
|
|
25552
|
+
const resourceUrl = flow.resourceUrl ?? flow.dashboardUrl;
|
|
25553
|
+
if (resourceUrl) {
|
|
25554
|
+
p17.log.info(
|
|
25555
|
+
`Open ${pc7.cyan(resourceUrl)} to copy DATABASE_URL, then rerun ${pc7.cyan("betterstart init --database-url <url> --yes")}.`
|
|
25556
|
+
);
|
|
25557
|
+
} else {
|
|
25558
|
+
p17.log.info(
|
|
25559
|
+
`Rerun ${pc7.cyan("betterstart init --database-url <url> --yes")} with a Postgres connection string.`
|
|
25560
|
+
);
|
|
25561
|
+
}
|
|
25560
25562
|
} else {
|
|
25561
25563
|
p17.log.warn("Vercel provisioning did not complete; continuing without a database URL.");
|
|
25562
25564
|
}
|
|
@@ -25579,6 +25581,11 @@ async function runInitCommand(name, options) {
|
|
|
25579
25581
|
databaseUrl = flow.databaseUrl;
|
|
25580
25582
|
persistDatabaseUrl(cwd, databaseUrl);
|
|
25581
25583
|
p17.log.success(`Saved DATABASE_URL to ${pc7.cyan(".env.local")}`);
|
|
25584
|
+
} else if (flow.ok) {
|
|
25585
|
+
openBrowserVercelNeonResource(flow.resourceUrl ?? flow.dashboardUrl);
|
|
25586
|
+
databaseUrl = await promptConnectionString();
|
|
25587
|
+
persistDatabaseUrl(cwd, databaseUrl);
|
|
25588
|
+
p17.log.success(`Saved DATABASE_URL to ${pc7.cyan(".env.local")}`);
|
|
25582
25589
|
} else {
|
|
25583
25590
|
p17.log.info("Falling back to a manual database connection string.");
|
|
25584
25591
|
openBrowserVercelNeon();
|
|
@@ -26105,7 +26112,11 @@ Run manually: ${pc7.cyan(betterstartExecCommand(pm, "seed"))}`,
|
|
|
26105
26112
|
await runVercelDeployFlow({ cwd, projectName, env: process.env });
|
|
26106
26113
|
}
|
|
26107
26114
|
} else if (linkedVercelProject && process.env.VERCEL_TOKEN) {
|
|
26108
|
-
const deployFlow = await runVercelDeployFlow({
|
|
26115
|
+
const deployFlow = await runVercelDeployFlow({
|
|
26116
|
+
cwd,
|
|
26117
|
+
projectName,
|
|
26118
|
+
env: process.env
|
|
26119
|
+
});
|
|
26109
26120
|
if (!deployFlow.ok) {
|
|
26110
26121
|
p17.log.warn("Vercel deploy did not complete; continuing.");
|
|
26111
26122
|
}
|