feat: add dev-runner script with tailscale-auth mode

Replace inline env vars in package.json dev scripts with a dedicated
node script that supports --tailscale-auth for private-network dev.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Forgotten
2026-02-23 16:08:17 -06:00
parent d2d927bd2f
commit 7f58e783dd
3 changed files with 70 additions and 2 deletions

View File

@@ -29,6 +29,14 @@ This starts:
- API server: `http://localhost:3100`
- UI: served by the API server in dev middleware mode (same origin as API)
Tailscale/private-auth dev mode:
```sh
pnpm dev --tailscale-auth
```
This runs dev as `authenticated/private` and binds the server to `0.0.0.0` for private-network access.
## One-Command Local Run
For a first-time local install, you can bootstrap and run in one command:

View File

@@ -3,8 +3,8 @@
"private": true,
"type": "module",
"scripts": {
"dev": "PAPERCLIP_UI_DEV_MIDDLEWARE=true pnpm --filter @paperclip/server dev",
"dev:watch": "PAPERCLIP_UI_DEV_MIDDLEWARE=true PAPERCLIP_MIGRATION_PROMPT=never pnpm --filter @paperclip/server dev:watch",
"dev": "node scripts/dev-runner.mjs dev",
"dev:watch": "PAPERCLIP_MIGRATION_PROMPT=never node scripts/dev-runner.mjs watch",
"dev:server": "pnpm --filter @paperclip/server dev",
"dev:ui": "pnpm --filter @paperclip/ui dev",
"build": "pnpm -r build",

60
scripts/dev-runner.mjs Normal file
View File

@@ -0,0 +1,60 @@
#!/usr/bin/env node
import { spawn } from "node:child_process";
const mode = process.argv[2] === "watch" ? "watch" : "dev";
const cliArgs = process.argv.slice(3);
const tailscaleAuthFlagNames = new Set([
"--tailscale-auth",
"--authenticated-private",
]);
let tailscaleAuth = false;
const forwardedArgs = [];
for (const arg of cliArgs) {
if (tailscaleAuthFlagNames.has(arg)) {
tailscaleAuth = true;
continue;
}
forwardedArgs.push(arg);
}
if (process.env.npm_config_tailscale_auth === "true") {
tailscaleAuth = true;
}
if (process.env.npm_config_authenticated_private === "true") {
tailscaleAuth = true;
}
const env = {
...process.env,
PAPERCLIP_UI_DEV_MIDDLEWARE: "true",
};
if (tailscaleAuth) {
env.PAPERCLIP_DEPLOYMENT_MODE = "authenticated";
env.PAPERCLIP_DEPLOYMENT_EXPOSURE = "private";
env.PAPERCLIP_AUTH_BASE_URL_MODE = "auto";
env.HOST = "0.0.0.0";
console.log("[paperclip] dev mode: authenticated/private (tailscale-friendly) on 0.0.0.0");
} else {
console.log("[paperclip] dev mode: local_trusted (default)");
}
const pnpmBin = process.platform === "win32" ? "pnpm.cmd" : "pnpm";
const serverScript = mode === "watch" ? "dev:watch" : "dev";
const child = spawn(
pnpmBin,
["--filter", "@paperclip/server", serverScript, ...forwardedArgs],
{ stdio: "inherit", env },
);
child.on("exit", (code, signal) => {
if (signal) {
process.kill(process.pid, signal);
return;
}
process.exit(code ?? 0);
});