railcode 0.1.16 → 0.1.18

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.
Files changed (3) hide show
  1. package/README.md +4 -2
  2. package/dist/index.js +56 -17
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -78,7 +78,7 @@ token is cleared and you're prompted to `railcode login` again.
78
78
  ```json
79
79
  {
80
80
  "app": "dashboard",
81
- "build": "pnpm build",
81
+ "build": "npm run build",
82
82
  "dist": "dist"
83
83
  }
84
84
  ```
@@ -89,5 +89,7 @@ Deploy output resolution:
89
89
 
90
90
  1. `railcode.json` `dist` wins.
91
91
  2. Otherwise `railcode.json` `build` runs and uploads `dist/`.
92
- 3. Otherwise a `package.json` with a `build` script runs `pnpm run build` and uploads `dist/`.
92
+ 3. Otherwise a `package.json` with a `build` script runs `<pm> run build` and uploads `dist/`,
93
+ where `<pm>` is the project's package manager — detected from a `packageManager` field or
94
+ lockfile (pnpm/yarn/bun), defaulting to `npm` when there's no lockfile.
93
95
  4. Otherwise a root `index.html` can be deployed interactively; for CI set `"dist": "."`.
package/dist/index.js CHANGED
@@ -555,7 +555,13 @@ function shouldSkipDeployPath(root, appRoot, relPath) {
555
555
  const deployingAppRoot = resolve(root) === resolve(appRoot);
556
556
  if (!deployingAppRoot)
557
557
  return false;
558
- return first === MANIFEST_NAME || first === "package.json" || first === "pnpm-lock.yaml";
558
+ return (first === MANIFEST_NAME ||
559
+ first === "package.json" ||
560
+ first === "pnpm-lock.yaml" ||
561
+ first === "package-lock.json" ||
562
+ first === "yarn.lock" ||
563
+ first === "bun.lockb" ||
564
+ first === "bun.lock");
559
565
  }
560
566
  function appLiveUrl(config, appSlug) {
561
567
  const api = new URL(config.apiUrl ?? DEFAULT_API_URL);
@@ -595,6 +601,35 @@ async function resolveDeployPlan(root, manifest) {
595
601
  }
596
602
  throw new CliError(`Could not find deploy output. Set "dist" in ${MANIFEST_NAME}, add a package.json build script, or put index.html at the app root.`, 2);
597
603
  }
604
+ // Which package manager to drive for an app dir. We never want to force a
605
+ // particular one onto users, so we detect what the project already declares —
606
+ // the corepack `packageManager` field first, then a lockfile — and fall back to
607
+ // npm, the only manager guaranteed to ship with Node. A fresh scaffold (no
608
+ // lockfile) therefore uses npm; a user who adopts pnpm/yarn/bun is respected via
609
+ // their lockfile.
610
+ function detectPackageManager(root) {
611
+ const packagePath = join(root, "package.json");
612
+ if (existsSync(packagePath)) {
613
+ try {
614
+ const pkg = JSON.parse(readFileSync(packagePath, "utf8"));
615
+ if (typeof pkg.packageManager === "string") {
616
+ const name = pkg.packageManager.split("@")[0];
617
+ if (name === "npm" || name === "pnpm" || name === "yarn" || name === "bun")
618
+ return name;
619
+ }
620
+ }
621
+ catch {
622
+ // Malformed package.json — fall through to lockfile / npm default.
623
+ }
624
+ }
625
+ if (existsSync(join(root, "pnpm-lock.yaml")))
626
+ return "pnpm";
627
+ if (existsSync(join(root, "yarn.lock")))
628
+ return "yarn";
629
+ if (existsSync(join(root, "bun.lockb")) || existsSync(join(root, "bun.lock")))
630
+ return "bun";
631
+ return "npm";
632
+ }
598
633
  function packageBuildCommand(root) {
599
634
  const packagePath = join(root, "package.json");
600
635
  if (!existsSync(packagePath))
@@ -609,7 +644,7 @@ function packageBuildCommand(root) {
609
644
  if (typeof pkg.scripts?.build !== "string") {
610
645
  throw new CliError(`Found package.json but no build script. Add "build", or set "dist" in ${MANIFEST_NAME}.`, 2);
611
646
  }
612
- return "pnpm run build";
647
+ return `${detectPackageManager(root)} run build`;
613
648
  }
614
649
  // ---------------------------------------------------------------------------
615
650
  // init
@@ -635,7 +670,7 @@ async function commandInit(args) {
635
670
  console.log("Next:");
636
671
  console.log(` cd ${app}`);
637
672
  if (template === "react") {
638
- console.log(" pnpm install");
673
+ console.log(" npm install");
639
674
  }
640
675
  console.log(" railcode deploy");
641
676
  }
@@ -654,7 +689,7 @@ function writeStaticStarter(target, app) {
654
689
  writeFileSync(join(target, "index.html"), starterIndexHtml(app));
655
690
  }
656
691
  function writeReactStarter(target, app) {
657
- writeFileSync(join(target, MANIFEST_NAME), `${JSON.stringify({ app, build: "pnpm run build", dist: "dist" }, null, 2)}\n`);
692
+ writeFileSync(join(target, MANIFEST_NAME), `${JSON.stringify({ app, build: "npm run build", dist: "dist" }, null, 2)}\n`);
658
693
  writeFileSync(join(target, "package.json"), reactPackageJson(app));
659
694
  writeFileSync(join(target, "index.html"), reactIndexHtml(app));
660
695
  writeFileSync(join(target, "tsconfig.json"), reactTsConfig());
@@ -1606,8 +1641,6 @@ const LLM_LOGOS: LogoItem[] = [
1606
1641
  const DATA_LOGO_ITEMS: LogoItem[] = [
1607
1642
  { name: "postgres", src: postgresLogo },
1608
1643
  { name: "bigquery", src: bigqueryLogo },
1609
- { name: "snowflake" },
1610
- { name: "saved queries" },
1611
1644
  ];
1612
1645
 
1613
1646
  const CONNECTOR_LOGO_ITEMS: LogoItem[] = [
@@ -4595,7 +4628,7 @@ function assetServerPort(args, manifest) {
4595
4628
  // Print the install command and stop — never mutate the app dir on `railcode dev`.
4596
4629
  function ensureAppDeps(cwd) {
4597
4630
  if (!existsSync(join(cwd, "node_modules"))) {
4598
- throw new CliError("Dependencies are not installed. Run `pnpm install` here, then `railcode dev` again.", 1);
4631
+ throw new CliError(`Dependencies are not installed. Run \`${detectPackageManager(cwd)} install\` here, then \`railcode dev\` again.`, 1);
4599
4632
  }
4600
4633
  }
4601
4634
  async function startAssetServer(plan, cwd, startPort, devProxyPort) {
@@ -4605,11 +4638,14 @@ async function startAssetServer(plan, cwd, startPort, devProxyPort) {
4605
4638
  const reservation = await reserveAvailablePort(startPort, "asset");
4606
4639
  const assetPort = reservation.port;
4607
4640
  // For the detected Vite case, run the local vite binary directly with pinned
4608
- // host/port so the proxy target is known. (Going through `pnpm dev -- …` would
4609
- // forward the `--` separator to vite, which then ignores the flags.) A custom
4610
- // command gets the ports via env and is expected to honour PORT.
4641
+ // host/port so the proxy target is known. `npx` resolves the vite already in
4642
+ // the app's node_modules (deps are guaranteed present ensureAppDeps runs
4643
+ // first) and is package-manager-agnostic, so we don't force pnpm on the user.
4644
+ // (Going through `<pm> dev -- …` would forward the `--` separator to vite,
4645
+ // which then ignores the flags.) A custom command gets the ports via env and
4646
+ // is expected to honour PORT.
4611
4647
  const command = plan.vite
4612
- ? `pnpm exec vite --host 127.0.0.1 --port ${assetPort} --strictPort --clearScreen false`
4648
+ ? `npx vite --host 127.0.0.1 --port ${assetPort} --strictPort --clearScreen false`
4613
4649
  : plan.command;
4614
4650
  console.log(` asset server: ${command}`);
4615
4651
  try {
@@ -4738,7 +4774,7 @@ function resolveDevPlan(cwd, manifest) {
4738
4774
  try {
4739
4775
  const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
4740
4776
  if (typeof pkg.scripts?.dev === "string") {
4741
- return { mode: "asset", root, command: "pnpm dev", vite: true };
4777
+ return { mode: "asset", root, command: `${detectPackageManager(cwd)} run dev`, vite: true };
4742
4778
  }
4743
4779
  }
4744
4780
  catch {
@@ -5322,11 +5358,16 @@ function serveStatic(root, pathname, res) {
5322
5358
  }
5323
5359
  serveFile(res, fp, inferContentType(fp));
5324
5360
  }
5325
- function listenLoopback(server, port, limit = 50) {
5361
+ export function listenLoopback(server, port, limit = 50) {
5326
5362
  return new Promise((resolvePromise, reject) => {
5327
5363
  let attempt = 0;
5328
5364
  const tryListen = (p) => {
5365
+ const onListening = () => {
5366
+ server.removeListener("error", onError);
5367
+ resolvePromise(p);
5368
+ };
5329
5369
  const onError = (err) => {
5370
+ server.removeListener("listening", onListening);
5330
5371
  if (err.code === "EADDRINUSE" && attempt < limit) {
5331
5372
  attempt += 1;
5332
5373
  tryListen(p + 1);
@@ -5336,10 +5377,8 @@ function listenLoopback(server, port, limit = 50) {
5336
5377
  }
5337
5378
  };
5338
5379
  server.once("error", onError);
5339
- server.listen(p, "127.0.0.1", () => {
5340
- server.removeListener("error", onError);
5341
- resolvePromise(p);
5342
- });
5380
+ server.once("listening", onListening);
5381
+ server.listen(p, "127.0.0.1");
5343
5382
  };
5344
5383
  tryListen(port);
5345
5384
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "railcode",
3
- "version": "0.1.16",
3
+ "version": "0.1.18",
4
4
  "description": "Developer CLI for the multi-tenant Railcode platform: log in, scaffold, and deploy static apps.",
5
5
  "license": "MIT",
6
6
  "type": "module",