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.
- package/README.md +4 -2
- package/dist/index.js +56 -17
- 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": "
|
|
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
|
|
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 ||
|
|
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
|
|
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("
|
|
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: "
|
|
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(
|
|
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.
|
|
4609
|
-
//
|
|
4610
|
-
//
|
|
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
|
-
? `
|
|
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:
|
|
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.
|
|
5340
|
-
|
|
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
|
});
|