betterstart-cli 0.0.43 → 0.0.45

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 CHANGED
@@ -24889,9 +24889,11 @@ import * as p16 from "@clack/prompts";
24889
24889
  import pc5 from "picocolors";
24890
24890
  var PROVISION_TIMEOUT_MS2 = 18e4;
24891
24891
  var INTERACTIVE_PROVISION_TIMEOUT_MS2 = 6e5;
24892
+ var RESOURCE_CONNECT_TIMEOUT_MS = 6e4;
24893
+ var NEON_FREE_PLAN_ID = "free_v3";
24892
24894
  async function provisionNeonInteractive(runner, cwd, options) {
24893
- const quietSpinner = spinner2();
24894
- quietSpinner.start("Creating your Neon database");
24895
+ const provisionSpinner = spinner2();
24896
+ provisionSpinner.start("Creating your Neon database");
24895
24897
  const quiet = await runVercel(runner, neonAddArgs(options), {
24896
24898
  cwd,
24897
24899
  mode: "capture",
@@ -24899,25 +24901,72 @@ async function provisionNeonInteractive(runner, cwd, options) {
24899
24901
  env: options.env
24900
24902
  });
24901
24903
  if (quiet.success) {
24902
- quietSpinner.clear();
24904
+ provisionSpinner.clear();
24903
24905
  return readNeonProvisionInfo(quiet.stdout);
24904
24906
  }
24905
- quietSpinner.clear();
24906
- p16.log.info(
24907
- `Create your Neon database in the Vercel prompts below ${pc5.dim(
24908
- "(the Free plan is recommended)."
24909
- )}`
24910
- );
24907
+ let promptsShown = false;
24911
24908
  const add = await runVercel(runner, connectedNeonAddArgs(options), {
24912
24909
  cwd,
24913
- mode: "inherit",
24910
+ mode: "stream",
24914
24911
  timeoutMs: INTERACTIVE_PROVISION_TIMEOUT_MS2,
24915
- env: options.env
24912
+ env: options.env,
24913
+ streamLineFilter: (line) => {
24914
+ if (!showNeonSetupLine(line)) return false;
24915
+ if (!promptsShown) {
24916
+ promptsShown = true;
24917
+ provisionSpinner.clear();
24918
+ p16.log.info(
24919
+ `Finish the Neon database setup in the Vercel prompts below ${pc5.dim(
24920
+ "(the Free plan is recommended)."
24921
+ )}`
24922
+ );
24923
+ }
24924
+ return true;
24925
+ }
24916
24926
  });
24927
+ if (!promptsShown) provisionSpinner.clear();
24917
24928
  if (!add.success) {
24918
- return { failure: add.timedOut ? "timeout" : "provision-failed" };
24929
+ const combined = `${add.stdout}
24930
+ ${add.stderr}`.trim();
24931
+ return {
24932
+ failure: add.timedOut ? "timeout" : "provision-failed",
24933
+ // Lines the user already saw are not repeated as detail.
24934
+ detail: promptsShown ? void 0 : combined || void 0
24935
+ };
24919
24936
  }
24920
- return { usedTerminalFallback: true };
24937
+ const info = readNeonFallbackInfo(`${add.stdout}
24938
+ ${add.stderr}`);
24939
+ if (promptsShown) info.usedTerminalFallback = true;
24940
+ return info;
24941
+ }
24942
+ var NEON_SETUP_NOISE = [
24943
+ /^$/,
24944
+ /^Vercel CLI \d/,
24945
+ /^>? ?Installing .+ under /,
24946
+ /^Provisioning resource/,
24947
+ /^Retrieving project/,
24948
+ /^>? ?Success!/,
24949
+ /^>? ?Guide: Run/,
24950
+ /^>? ?Dashboard: https:\/\//,
24951
+ /successfully connected to/i,
24952
+ /^>? ?Overwriting existing \.env/,
24953
+ /^>? ?Downloading/,
24954
+ /^Changes:/,
24955
+ /^\+ [A-Z][A-Z0-9_]*/,
24956
+ /^[✓√] +(Updated|Created)/
24957
+ ];
24958
+ function showNeonSetupLine(line) {
24959
+ return !NEON_SETUP_NOISE.some((pattern) => pattern.test(line));
24960
+ }
24961
+ function readNeonFallbackInfo(output) {
24962
+ const info = {};
24963
+ const provisioned = output.match(/successfully provisioned: (\S+)/i)?.[1];
24964
+ if (provisioned) info.resourceName = provisioned;
24965
+ const dashboard = output.match(/Dashboard: (https:\/\/\S+)/i)?.[1];
24966
+ if (dashboard) info.dashboardUrl = dashboard;
24967
+ if (/failed to connect/i.test(output)) info.connectedToProject = false;
24968
+ else if (/successfully connected to/i.test(output)) info.connectedToProject = true;
24969
+ return info;
24921
24970
  }
24922
24971
  async function provisionNeon(runner, cwd, options) {
24923
24972
  const provisionSpinner = spinner2();
@@ -24953,17 +25002,57 @@ function readNeonProvisionInfo(stdout) {
24953
25002
  const info = {};
24954
25003
  if (meta.dashboardUrl) info.dashboardUrl = meta.dashboardUrl;
24955
25004
  if (meta.ssoUrl?.resource) info.resourceUrl = meta.ssoUrl.resource;
25005
+ if (meta.resource?.name) info.resourceName = meta.resource.name;
25006
+ const connectWarning = (meta.warnings ?? []).some((warning) => /failed to connect/i.test(warning));
25007
+ if (meta.envPulled === false || connectWarning) info.connectedToProject = false;
25008
+ else if (meta.envPulled === true) info.connectedToProject = true;
24956
25009
  return info;
24957
25010
  }
25011
+ async function replaceNeonProjectConnection(runner, cwd, resourceName, env) {
25012
+ const list = await runVercel(runner, ["integration", "list", "--format", "json"], {
25013
+ cwd,
25014
+ mode: "capture",
25015
+ timeoutMs: RESOURCE_CONNECT_TIMEOUT_MS,
25016
+ env
25017
+ });
25018
+ if (list.success) {
25019
+ const payload = parseVercelJson(list.stdout);
25020
+ for (const resource of payload?.resources ?? []) {
25021
+ if (!resource.name || resource.name === resourceName) continue;
25022
+ if (resource.product && !/neon/i.test(resource.product)) continue;
25023
+ await runVercel(runner, ["integration-resource", "disconnect", resource.name, "--yes"], {
25024
+ cwd,
25025
+ mode: "capture",
25026
+ timeoutMs: RESOURCE_CONNECT_TIMEOUT_MS,
25027
+ env
25028
+ });
25029
+ }
25030
+ }
25031
+ const connect = await runVercel(
25032
+ runner,
25033
+ ["integration-resource", "connect", resourceName, "--yes"],
25034
+ {
25035
+ cwd,
25036
+ mode: "capture",
25037
+ timeoutMs: RESOURCE_CONNECT_TIMEOUT_MS,
25038
+ env
25039
+ }
25040
+ );
25041
+ return connect.success;
25042
+ }
24958
25043
  function neonAddArgs(options) {
24959
- const addArgs = ["integration", "add", "neon", "--format", "json"];
24960
- if (options.plan) addArgs.push("--plan", options.plan);
24961
- return addArgs;
25044
+ return [
25045
+ "integration",
25046
+ "add",
25047
+ "neon",
25048
+ "--format",
25049
+ "json",
25050
+ "--plan",
25051
+ options.plan ?? NEON_FREE_PLAN_ID
25052
+ ];
24962
25053
  }
24963
25054
  function connectedNeonAddArgs(options) {
24964
- const addArgs = ["integration", "add", "neon"];
24965
- if (options.plan) addArgs.push("--plan", options.plan);
24966
- return addArgs;
25055
+ return ["integration", "add", "neon", "--plan", options.plan ?? NEON_FREE_PLAN_ID];
24967
25056
  }
24968
25057
 
24969
25058
  // adapters/next/init/vercel/flow.ts
@@ -24980,14 +25069,28 @@ async function runVercelNeonFlow(options) {
24980
25069
  p17.log.warn(authFailureMessage(auth.reason));
24981
25070
  return { ok: false };
24982
25071
  }
25072
+ const linkPreExisted = Boolean(readLinkedProjectId(options.cwd));
24983
25073
  const linkLinePrinted = await ensureLinkedProject(runner, options.cwd, options.projectName, env);
25074
+ const preExistingDbUrl = linkPreExisted ? await pullPreExistingDbUrl(runner, options.cwd, env) : void 0;
24984
25075
  const neon = await provisionNeonForMode(runner, options);
24985
25076
  if (neon.failure) {
24986
25077
  p17.log.warn(neonFailureMessage(neon.failure));
24987
25078
  if (neon.detail) p17.log.message(pc6.dim(neon.detail));
24988
25079
  return { ok: false };
24989
25080
  }
24990
- const databaseUrl = await pullNeonDatabaseUrl(runner, options.cwd, env);
25081
+ if (neon.connectedToProject === false && neon.resourceName) {
25082
+ const connectSpinner = spinner2();
25083
+ connectSpinner.start("Connecting the database to your Vercel project");
25084
+ await replaceNeonProjectConnection(runner, options.cwd, neon.resourceName, env);
25085
+ connectSpinner.clear();
25086
+ }
25087
+ let databaseUrl = await pullNeonDatabaseUrl(runner, options.cwd, env);
25088
+ if (databaseUrl && databaseUrl === preExistingDbUrl) {
25089
+ databaseUrl = void 0;
25090
+ p17.log.warn(
25091
+ "The linked Vercel project still returns its previous DATABASE_URL \u2014 the new database could not be connected."
25092
+ );
25093
+ }
24991
25094
  const dismissSignedInNote = databaseUrl && auth.dismissNote && !neon.usedTerminalFallback ? () => auth.dismissNote?.({ linesBelow: linkLinePrinted ? 1 : 0 }) : void 0;
24992
25095
  return {
24993
25096
  ok: true,
@@ -25083,7 +25186,7 @@ async function runVercelDeployFlow(options) {
25083
25186
  );
25084
25187
  }
25085
25188
  const deploySpinner = spinner2();
25086
- deploySpinner.start("Deploying to Vercel (this may take a few minutes)");
25189
+ deploySpinner.start("Deploying to Vercel, This may take a moment");
25087
25190
  let deploy;
25088
25191
  try {
25089
25192
  deploy = await deployVercelProject(runner, options.cwd, env);
@@ -25121,6 +25224,13 @@ async function ensureLinkedProject(runner, cwd, projectName, env) {
25121
25224
  );
25122
25225
  return true;
25123
25226
  }
25227
+ async function pullPreExistingDbUrl(runner, cwd, env) {
25228
+ const snapshotSpinner = spinner2();
25229
+ snapshotSpinner.start("Checking the linked Vercel project");
25230
+ const url = await pullVercelEnvValue(runner, cwd, readDbUrlFromDotenv, env);
25231
+ snapshotSpinner.clear();
25232
+ return url;
25233
+ }
25124
25234
  async function pullNeonDatabaseUrl(runner, cwd, env) {
25125
25235
  const neonSpinner = spinner2();
25126
25236
  neonSpinner.start("Retrieving DATABASE_URL from Vercel");
@@ -25962,7 +26072,7 @@ async function runInitCommand(name, options) {
25962
26072
  }
25963
26073
  const coreDependencyPlan = getDependencyPlan([], [], project2.linter.type === "none");
25964
26074
  const cliDependencyPlan = getCliDependencySyncPlan(cwd);
25965
- s.start("Installing dependencies (this may take a minute)");
26075
+ s.start("Installing dependencies, This may take a moment");
25966
26076
  const depsResult = await installDependenciesAsync({
25967
26077
  cwd,
25968
26078
  pm,