betterstart-cli 0.0.29 → 0.0.30
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 +141 -66
- 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,
|
|
@@ -24691,21 +24693,19 @@ async function provisionNeonInteractive(runner, cwd, options) {
|
|
|
24691
24693
|
return { failure: add.timedOut ? "timeout" : "provision-failed" };
|
|
24692
24694
|
}
|
|
24693
24695
|
const pullSpinner = spinner2();
|
|
24694
|
-
pullSpinner.start("Retrieving
|
|
24695
|
-
const databaseUrl = await
|
|
24696
|
+
pullSpinner.start("Retrieving DATABASE_URL from Vercel");
|
|
24697
|
+
const databaseUrl = await pullVercelEnvValue(runner, cwd, readDbUrlFromDotenv, options.env);
|
|
24696
24698
|
if (!databaseUrl) {
|
|
24697
|
-
pullSpinner.stop("No DATABASE_URL came back from Vercel
|
|
24698
|
-
return {
|
|
24699
|
+
pullSpinner.stop(`${pc5.yellow("\u25B2")} No DATABASE_URL came back from Vercel`);
|
|
24700
|
+
return {};
|
|
24699
24701
|
}
|
|
24700
24702
|
pullSpinner.clear();
|
|
24701
24703
|
return { databaseUrl };
|
|
24702
24704
|
}
|
|
24703
24705
|
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
24706
|
const provisionSpinner = spinner2();
|
|
24707
24707
|
provisionSpinner.start("Creating your Neon database");
|
|
24708
|
-
const add = await runVercel(runner,
|
|
24708
|
+
const add = await runVercel(runner, neonAddArgs(options), {
|
|
24709
24709
|
cwd,
|
|
24710
24710
|
mode: "capture",
|
|
24711
24711
|
timeoutMs: PROVISION_TIMEOUT_MS2,
|
|
@@ -24720,33 +24720,49 @@ ${add.stderr}`.trim();
|
|
|
24720
24720
|
if (/claim/i.test(combined)) return { failure: "claim-required", detail };
|
|
24721
24721
|
return { failure: add.timedOut ? "timeout" : "provision-failed", detail };
|
|
24722
24722
|
}
|
|
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
24723
|
provisionSpinner.clear();
|
|
24732
|
-
return
|
|
24724
|
+
return readNeonProvisionInfo(add.stdout);
|
|
24733
24725
|
}
|
|
24734
|
-
function
|
|
24735
|
-
|
|
24726
|
+
async function connectNeonResourceToProject(runner, cwd, resourceName, env) {
|
|
24727
|
+
const connect = await runVercel(
|
|
24728
|
+
runner,
|
|
24729
|
+
["integration", "resource", "connect", resourceName, "--yes", "--format", "json"],
|
|
24730
|
+
{ cwd, mode: "capture", timeoutMs: PROVISION_TIMEOUT_MS2, env }
|
|
24731
|
+
);
|
|
24732
|
+
if (connect.success) return { ok: true };
|
|
24733
|
+
const detail = `${connect.stdout}
|
|
24734
|
+
${connect.stderr}`.trim();
|
|
24735
|
+
if (/already connected/i.test(detail)) {
|
|
24736
|
+
return { ok: true, alreadyConnected: true, detail: detail || void 0 };
|
|
24737
|
+
}
|
|
24738
|
+
return { ok: false, detail: detail || void 0 };
|
|
24736
24739
|
}
|
|
24737
24740
|
function readDbUrlFromDotenv(filePath) {
|
|
24738
24741
|
const vars = parseDotenvFile(filePath);
|
|
24739
24742
|
const isPg = (v) => !!v && (v.startsWith("postgres://") || v.startsWith("postgresql://"));
|
|
24740
24743
|
if (isPg(vars.get("DATABASE_URL"))) return vars.get("DATABASE_URL");
|
|
24741
24744
|
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
24745
|
return void 0;
|
|
24749
24746
|
}
|
|
24747
|
+
function readNeonProvisionInfo(stdout) {
|
|
24748
|
+
const meta = parseVercelJson(stdout);
|
|
24749
|
+
if (!meta) return {};
|
|
24750
|
+
return {
|
|
24751
|
+
resourceName: meta.resource?.name,
|
|
24752
|
+
dashboardUrl: meta.dashboardUrl,
|
|
24753
|
+
resourceUrl: meta.ssoUrl?.resource
|
|
24754
|
+
};
|
|
24755
|
+
}
|
|
24756
|
+
function neonAddArgs(options) {
|
|
24757
|
+
const addArgs = ["integration", "add", "neon", "--no-connect", "--format", "json"];
|
|
24758
|
+
if (options.plan) addArgs.push("--plan", options.plan);
|
|
24759
|
+
return addArgs;
|
|
24760
|
+
}
|
|
24761
|
+
function connectedNeonAddArgs(options) {
|
|
24762
|
+
const addArgs = ["integration", "add", "neon"];
|
|
24763
|
+
if (options.plan) addArgs.push("--plan", options.plan);
|
|
24764
|
+
return addArgs;
|
|
24765
|
+
}
|
|
24750
24766
|
|
|
24751
24767
|
// adapters/next/init/vercel/flow.ts
|
|
24752
24768
|
async function runVercelNeonFlow(options) {
|
|
@@ -24762,23 +24778,29 @@ async function runVercelNeonFlow(options) {
|
|
|
24762
24778
|
p16.log.warn(authFailureMessage(auth.reason));
|
|
24763
24779
|
return { ok: false };
|
|
24764
24780
|
}
|
|
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
|
-
);
|
|
24781
|
+
await ensureLinkedProject(runner, options.cwd, options.projectName, env);
|
|
24771
24782
|
const neon = await provisionNeonForMode(runner, options);
|
|
24772
|
-
if (neon.failure
|
|
24783
|
+
if (neon.failure) {
|
|
24773
24784
|
p16.log.warn(neonFailureMessage(neon.failure));
|
|
24774
24785
|
if (neon.detail) p16.log.message(pc6.dim(neon.detail));
|
|
24775
24786
|
return { ok: false };
|
|
24776
24787
|
}
|
|
24788
|
+
let databaseUrl = neon.databaseUrl;
|
|
24789
|
+
if (neon.resourceName) {
|
|
24790
|
+
const pulledDatabaseUrl = await connectNeonAndPullDatabaseUrl(
|
|
24791
|
+
runner,
|
|
24792
|
+
options.cwd,
|
|
24793
|
+
neon.resourceName,
|
|
24794
|
+
env
|
|
24795
|
+
);
|
|
24796
|
+
databaseUrl = pulledDatabaseUrl ?? databaseUrl;
|
|
24797
|
+
}
|
|
24777
24798
|
return {
|
|
24778
24799
|
ok: true,
|
|
24779
|
-
databaseUrl
|
|
24780
|
-
|
|
24781
|
-
|
|
24800
|
+
databaseUrl,
|
|
24801
|
+
neonResourceName: neon.resourceName,
|
|
24802
|
+
dashboardUrl: neon.dashboardUrl,
|
|
24803
|
+
resourceUrl: neon.resourceUrl
|
|
24782
24804
|
};
|
|
24783
24805
|
} catch (error) {
|
|
24784
24806
|
p16.log.warn(
|
|
@@ -24802,16 +24824,7 @@ async function runVercelBlobFlow(options) {
|
|
|
24802
24824
|
p16.log.warn(authFailureMessage(auth.reason));
|
|
24803
24825
|
return { ok: false };
|
|
24804
24826
|
}
|
|
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
|
-
}
|
|
24827
|
+
await ensureLinkedProject(runner, options.cwd, options.projectName, env);
|
|
24815
24828
|
const blob = await provisionBlobForMode(runner, options);
|
|
24816
24829
|
if (blob.failure || !blob.token) {
|
|
24817
24830
|
p16.log.warn(blobFailureMessage(blob.failure));
|
|
@@ -24821,7 +24834,6 @@ async function runVercelBlobFlow(options) {
|
|
|
24821
24834
|
return {
|
|
24822
24835
|
ok: true,
|
|
24823
24836
|
token: blob.token,
|
|
24824
|
-
vercelProjectId: projectId,
|
|
24825
24837
|
blobStoreName: blob.storeName
|
|
24826
24838
|
};
|
|
24827
24839
|
} catch (error) {
|
|
@@ -24847,13 +24859,24 @@ async function runVercelDeployFlow(options) {
|
|
|
24847
24859
|
printManualDeployHint();
|
|
24848
24860
|
return { ok: false };
|
|
24849
24861
|
}
|
|
24850
|
-
|
|
24851
|
-
|
|
24852
|
-
|
|
24853
|
-
|
|
24854
|
-
|
|
24855
|
-
|
|
24862
|
+
await ensureLinkedProject(runner, options.cwd, options.projectName, env);
|
|
24863
|
+
if (options.neonResourceName) {
|
|
24864
|
+
const neonSpinner = spinner2();
|
|
24865
|
+
neonSpinner.start("Connecting Neon database to Vercel project");
|
|
24866
|
+
const connect = await connectNeonResourceToProject(
|
|
24867
|
+
runner,
|
|
24868
|
+
options.cwd,
|
|
24869
|
+
options.neonResourceName,
|
|
24870
|
+
env
|
|
24856
24871
|
);
|
|
24872
|
+
if (connect.ok) {
|
|
24873
|
+
neonSpinner.stop(
|
|
24874
|
+
connect.alreadyConnected ? "Neon database already connected to Vercel project" : "Connected Neon database to Vercel project"
|
|
24875
|
+
);
|
|
24876
|
+
} else {
|
|
24877
|
+
neonSpinner.stop(`${pc6.yellow("\u25B2")} Could not connect Neon database to Vercel project`);
|
|
24878
|
+
if (connect.detail) p16.log.message(pc6.dim(connect.detail));
|
|
24879
|
+
}
|
|
24857
24880
|
}
|
|
24858
24881
|
const envSpinner = spinner2();
|
|
24859
24882
|
envSpinner.start("Syncing environment variables to Vercel");
|
|
@@ -24908,6 +24931,33 @@ async function runVercelDeployFlow(options) {
|
|
|
24908
24931
|
function printManualDeployHint() {
|
|
24909
24932
|
p16.log.info(`You can deploy manually: ${pc6.cyan("vercel deploy --prod")}`);
|
|
24910
24933
|
}
|
|
24934
|
+
async function ensureLinkedProject(runner, cwd, projectName, env) {
|
|
24935
|
+
if (readLinkedProjectId(cwd)) return;
|
|
24936
|
+
const projectSpinner = spinner2();
|
|
24937
|
+
projectSpinner.start(`Creating a Vercel project ${pc6.cyan(projectName)}`);
|
|
24938
|
+
const project2 = await createVercelProject(runner, cwd, projectName, env);
|
|
24939
|
+
projectSpinner.stop(
|
|
24940
|
+
project2.linked ? `Linked Vercel project ${pc6.cyan(project2.name)}` : `Using Vercel project ${pc6.cyan(project2.name)}`
|
|
24941
|
+
);
|
|
24942
|
+
}
|
|
24943
|
+
async function connectNeonAndPullDatabaseUrl(runner, cwd, resourceName, env) {
|
|
24944
|
+
const neonSpinner = spinner2();
|
|
24945
|
+
neonSpinner.start("Connecting Neon database to Vercel project");
|
|
24946
|
+
const connect = await connectNeonResourceToProject(runner, cwd, resourceName, env);
|
|
24947
|
+
if (!connect.ok) {
|
|
24948
|
+
neonSpinner.stop(`${pc6.yellow("\u25B2")} Could not connect Neon database to Vercel project`);
|
|
24949
|
+
if (connect.detail) p16.log.message(pc6.dim(connect.detail));
|
|
24950
|
+
return void 0;
|
|
24951
|
+
}
|
|
24952
|
+
neonSpinner.message("Retrieving DATABASE_URL from Vercel");
|
|
24953
|
+
const databaseUrl = await pullVercelEnvValue(runner, cwd, readDbUrlFromDotenv, env);
|
|
24954
|
+
if (!databaseUrl) {
|
|
24955
|
+
neonSpinner.stop(`${pc6.yellow("\u25B2")} No DATABASE_URL came back from Vercel`);
|
|
24956
|
+
return void 0;
|
|
24957
|
+
}
|
|
24958
|
+
neonSpinner.clear();
|
|
24959
|
+
return databaseUrl;
|
|
24960
|
+
}
|
|
24911
24961
|
function provisionBlobForMode(runner, options) {
|
|
24912
24962
|
const opts = { name: blobStoreName(options.projectName), env: options.env };
|
|
24913
24963
|
return options.interactive ? provisionBlobStoreInteractive(runner, options.cwd, opts) : provisionBlobStore(runner, options.cwd, opts);
|
|
@@ -24954,8 +25004,6 @@ function neonFailureMessage(reason) {
|
|
|
24954
25004
|
return "Provisioning needs the Neon marketplace terms accepted \u2014 falling back to manual entry.";
|
|
24955
25005
|
case "claim-required":
|
|
24956
25006
|
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
25007
|
case "timeout":
|
|
24960
25008
|
return "Neon provisioning timed out \u2014 falling back to manual entry.";
|
|
24961
25009
|
default:
|
|
@@ -25533,6 +25581,7 @@ async function runInitCommand(name, options) {
|
|
|
25533
25581
|
isFreshProject = true;
|
|
25534
25582
|
}
|
|
25535
25583
|
let databaseUrl;
|
|
25584
|
+
let neonResourceName;
|
|
25536
25585
|
const existingDbUrl = readExistingDbUrl(cwd);
|
|
25537
25586
|
if (options.yes) {
|
|
25538
25587
|
if (options.databaseUrl) {
|
|
@@ -25554,9 +25603,23 @@ async function runInitCommand(name, options) {
|
|
|
25554
25603
|
env: process.env
|
|
25555
25604
|
});
|
|
25556
25605
|
if (flow.ok && flow.databaseUrl) {
|
|
25606
|
+
neonResourceName = flow.neonResourceName;
|
|
25557
25607
|
databaseUrl = flow.databaseUrl;
|
|
25558
25608
|
persistDatabaseUrl(cwd, databaseUrl);
|
|
25559
25609
|
p17.log.success(`Saved DATABASE_URL to ${pc7.cyan(".env.local")}`);
|
|
25610
|
+
} else if (flow.ok) {
|
|
25611
|
+
neonResourceName = flow.neonResourceName;
|
|
25612
|
+
p17.log.warn("Created a Neon database, but DATABASE_URL could not be retrieved from Vercel.");
|
|
25613
|
+
const resourceUrl = flow.resourceUrl ?? flow.dashboardUrl;
|
|
25614
|
+
if (resourceUrl) {
|
|
25615
|
+
p17.log.info(
|
|
25616
|
+
`Open ${pc7.cyan(resourceUrl)} to copy DATABASE_URL, then rerun ${pc7.cyan("betterstart init --database-url <url> --yes")}.`
|
|
25617
|
+
);
|
|
25618
|
+
} else {
|
|
25619
|
+
p17.log.info(
|
|
25620
|
+
`Rerun ${pc7.cyan("betterstart init --database-url <url> --yes")} with a Postgres connection string.`
|
|
25621
|
+
);
|
|
25622
|
+
}
|
|
25560
25623
|
} else {
|
|
25561
25624
|
p17.log.warn("Vercel provisioning did not complete; continuing without a database URL.");
|
|
25562
25625
|
}
|
|
@@ -25576,9 +25639,16 @@ async function runInitCommand(name, options) {
|
|
|
25576
25639
|
env: process.env
|
|
25577
25640
|
});
|
|
25578
25641
|
if (flow.ok && flow.databaseUrl) {
|
|
25642
|
+
neonResourceName = flow.neonResourceName;
|
|
25579
25643
|
databaseUrl = flow.databaseUrl;
|
|
25580
25644
|
persistDatabaseUrl(cwd, databaseUrl);
|
|
25581
25645
|
p17.log.success(`Saved DATABASE_URL to ${pc7.cyan(".env.local")}`);
|
|
25646
|
+
} else if (flow.ok) {
|
|
25647
|
+
neonResourceName = flow.neonResourceName;
|
|
25648
|
+
openBrowserVercelNeonResource(flow.resourceUrl ?? flow.dashboardUrl);
|
|
25649
|
+
databaseUrl = await promptConnectionString();
|
|
25650
|
+
persistDatabaseUrl(cwd, databaseUrl);
|
|
25651
|
+
p17.log.success(`Saved DATABASE_URL to ${pc7.cyan(".env.local")}`);
|
|
25582
25652
|
} else {
|
|
25583
25653
|
p17.log.info("Falling back to a manual database connection string.");
|
|
25584
25654
|
openBrowserVercelNeon();
|
|
@@ -26102,10 +26172,15 @@ Run manually: ${pc7.cyan(betterstartExecCommand(pm, "seed"))}`,
|
|
|
26102
26172
|
initialValue: linkedVercelProject
|
|
26103
26173
|
});
|
|
26104
26174
|
if (!p17.isCancel(deployNow) && deployNow) {
|
|
26105
|
-
await runVercelDeployFlow({ cwd, projectName, env: process.env });
|
|
26175
|
+
await runVercelDeployFlow({ cwd, projectName, neonResourceName, env: process.env });
|
|
26106
26176
|
}
|
|
26107
26177
|
} else if (linkedVercelProject && process.env.VERCEL_TOKEN) {
|
|
26108
|
-
const deployFlow = await runVercelDeployFlow({
|
|
26178
|
+
const deployFlow = await runVercelDeployFlow({
|
|
26179
|
+
cwd,
|
|
26180
|
+
projectName,
|
|
26181
|
+
neonResourceName,
|
|
26182
|
+
env: process.env
|
|
26183
|
+
});
|
|
26109
26184
|
if (!deployFlow.ok) {
|
|
26110
26185
|
p17.log.warn("Vercel deploy did not complete; continuing.");
|
|
26111
26186
|
}
|