@studiometa/trafic-agent 0.1.19 → 0.1.20

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
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { _ as validateConfig, c as info, d as success, f as warn, h as loadConfig, i as runPendingMigrations, l as isRoot, n as setup, p as startIdleScheduler, r as listMigrations, s as exec, t as audit, u as step } from "./setup-BNJ5RVn9.js";
3
3
  import { o as closeDb, t as startServer } from "./server-D6zlodZz.js";
4
+ import { readFileSync } from "node:fs";
4
5
  import { execSync, spawnSync } from "node:child_process";
5
6
  import { parseArgs } from "node:util";
6
7
  /**
@@ -38,9 +39,31 @@ function isNewer(current, next) {
38
39
  }
39
40
  /**
40
41
  * Install the latest version of @studiometa/trafic-agent globally via npm.
42
+ * Uses --prefer-online to bypass the local npm cache and always fetch the
43
+ * latest published tarball.
41
44
  */
42
45
  function installLatestAgent(dryRun) {
43
- exec("npm install -g @studiometa/trafic-agent@latest", { silent: !dryRun });
46
+ exec("npm install -g @studiometa/trafic-agent@latest --prefer-online", { silent: !dryRun });
47
+ }
48
+ /**
49
+ * Read the actual installed version of @studiometa/trafic-agent from its
50
+ * package.json on disk — not from __VERSION__ which is baked in at build time.
51
+ * Returns null if the file can't be read.
52
+ */
53
+ function getInstalledVersion() {
54
+ try {
55
+ execSync("which trafic-agent", {
56
+ encoding: "utf-8",
57
+ stdio: "pipe"
58
+ }).trim();
59
+ const pkgJson = execSync(`node -e "console.log(require.resolve('@studiometa/trafic-agent/package.json'))"`, {
60
+ encoding: "utf-8",
61
+ stdio: "pipe"
62
+ }).trim();
63
+ return JSON.parse(readFileSync(pkgJson, "utf-8")).version;
64
+ } catch {
65
+ return null;
66
+ }
44
67
  }
45
68
  /**
46
69
  * Re-exec the newly installed trafic-agent binary with the same arguments.
@@ -51,7 +74,13 @@ function reExecNewBinary(args) {
51
74
  const result = spawnSync(execSync("which trafic-agent", {
52
75
  encoding: "utf-8",
53
76
  stdio: "pipe"
54
- }).trim(), args, { stdio: "inherit" });
77
+ }).trim(), args, {
78
+ stdio: "inherit",
79
+ env: {
80
+ ...process.env,
81
+ TRAFIC_UPGRADE_REEXEC: "1"
82
+ }
83
+ });
55
84
  process.exit(result.status ?? 0);
56
85
  }
57
86
  /**
@@ -74,8 +103,9 @@ function runUpgrade(dryRun = false, reExecArgs) {
74
103
  console.log(" Run: sudo trafic-agent upgrade");
75
104
  process.exit(1);
76
105
  }
106
+ const alreadyReExeced = process.env["TRAFIC_UPGRADE_REEXEC"] === "1";
77
107
  step("Check for updates");
78
- const current = "0.1.19";
108
+ const current = "0.1.20";
79
109
  info(`Current version: ${current}`);
80
110
  const latest = fetchLatestVersion();
81
111
  if (!latest) warn("Could not reach npm registry — skipping version check");
@@ -84,8 +114,11 @@ function runUpgrade(dryRun = false, reExecArgs) {
84
114
  step("Install latest version");
85
115
  installLatestAgent(dryRun);
86
116
  if (!dryRun) {
87
- success(`Installed @studiometa/trafic-agent@${latest}`);
88
- reExecNewBinary(reExecArgs ?? ["upgrade"]);
117
+ const installedVersion = getInstalledVersion();
118
+ if (!alreadyReExeced && installedVersion && isNewer(current, installedVersion)) {
119
+ success(`Installed @studiometa/trafic-agent@${installedVersion}`);
120
+ reExecNewBinary(reExecArgs ?? ["upgrade"]);
121
+ } else if (installedVersion) success(`Installed @studiometa/trafic-agent@${installedVersion}`);
89
122
  }
90
123
  } else success(`Already up to date (${current})`);
91
124
  step("Run pending migrations");
@@ -149,7 +182,7 @@ function printHelp() {
149
182
  console.log(HELP.trim());
150
183
  }
151
184
  function printVersion() {
152
- console.log("0.1.19");
185
+ console.log("0.1.20");
153
186
  }
154
187
  async function runStart(values) {
155
188
  const config = loadConfig(values.config);
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","names":[],"sources":["../src/setup/upgrade.ts","../src/cli.ts"],"sourcesContent":["import { execSync, spawnSync } from \"node:child_process\";\nimport { step, success, info, warn, exec, isRoot } from \"./steps.js\";\nimport { runPendingMigrations } from \"./migrations/index.js\";\n\ndeclare const __VERSION__: string;\n\n/**\n * Fetch the latest published version of @studiometa/trafic-agent from the npm registry.\n * Returns null if the registry is unreachable.\n */\nexport function fetchLatestVersion(): string | null {\n try {\n return execSync(\"npm show @studiometa/trafic-agent version\", {\n encoding: \"utf-8\",\n stdio: \"pipe\",\n }).trim();\n } catch {\n return null;\n }\n}\n\n/**\n * Compare two semver strings. Returns true if `next` is strictly greater than `current`.\n * Handles simple MAJOR.MINOR.PATCH without pre-release suffixes.\n */\nexport function isNewer(current: string, next: string): boolean {\n const parse = (v: string): [number, number, number] => {\n const parts = v.replace(/^v/, \"\").split(\".\").map(Number);\n return [parts[0] ?? 0, parts[1] ?? 0, parts[2] ?? 0];\n };\n\n const [cMaj, cMin, cPat] = parse(current);\n const [nMaj, nMin, nPat] = parse(next);\n\n if (nMaj !== cMaj) return nMaj > cMaj;\n if (nMin !== cMin) return nMin > cMin;\n return nPat > cPat;\n}\n\n/**\n * Install the latest version of @studiometa/trafic-agent globally via npm.\n */\nexport function installLatestAgent(dryRun: boolean): void {\n exec(\"npm install -g @studiometa/trafic-agent@latest\", { silent: !dryRun });\n}\n\n/**\n * Re-exec the newly installed trafic-agent binary with the same arguments.\n * Used after a self-update so the new binary runs its own migrations.\n * This function never returns — it replaces the current process.\n */\nexport function reExecNewBinary(args: string[]): never {\n const binary = execSync(\"which trafic-agent\", { encoding: \"utf-8\", stdio: \"pipe\" }).trim();\n const result = spawnSync(binary, args, { stdio: \"inherit\" });\n process.exit(result.status ?? 0);\n}\n\n/**\n * Restart the trafic-agent systemd service.\n */\nexport function restartAgentService(dryRun: boolean): void {\n exec(\"systemctl restart trafic-agent\", { silent: !dryRun });\n}\n\n/**\n * Full upgrade sequence:\n * 1. Check for a new version on npm\n * 2. Install it globally if one is found — then re-exec the new binary\n * so that steps 3 and 4 run with the new migration registry\n * 3. Run pending migrations\n * 4. Restart the systemd service\n */\nexport function runUpgrade(dryRun = false, reExecArgs?: string[]): void {\n if (!isRoot() && !dryRun) {\n console.error(\" \\x1b[31m✗\\x1b[0m This command must be run as root\");\n console.log(\" Run: sudo trafic-agent upgrade\");\n process.exit(1);\n }\n\n // ── Step 1: Check for updates ─────────────────────────────────────────────\n step(\"Check for updates\");\n\n const current = __VERSION__;\n info(`Current version: ${current}`);\n\n const latest = fetchLatestVersion();\n\n if (!latest) {\n warn(\"Could not reach npm registry — skipping version check\");\n } else if (isNewer(current, latest)) {\n success(`New version available: ${latest}`);\n\n // ── Step 2: Install ───────────────────────────────────────────────────\n step(\"Install latest version\");\n installLatestAgent(dryRun);\n if (!dryRun) {\n success(`Installed @studiometa/trafic-agent@${latest}`);\n // Re-exec the newly installed binary so steps 3 and 4 run with the\n // new migration registry — the current process only knows about\n // migrations that existed at the time it was compiled.\n reExecNewBinary(reExecArgs ?? [\"upgrade\"]);\n }\n } else {\n success(`Already up to date (${current})`);\n }\n\n // ── Step 3: Run pending migrations ───────────────────────────────────────\n step(\"Run pending migrations\");\n runPendingMigrations(dryRun);\n\n // ── Step 4: Restart service ───────────────────────────────────────────────\n step(\"Restart trafic-agent service\");\n restartAgentService(dryRun);\n if (!dryRun) {\n success(\"Service restarted\");\n }\n}\n","#!/usr/bin/env node\n\nimport { parseArgs } from \"node:util\";\nimport { loadConfig, validateConfig } from \"./utils/config.js\";\nimport { startServer } from \"./server.js\";\nimport { startIdleScheduler } from \"./tasks/stop-idle.js\";\nimport { closeDb } from \"./utils/db.js\";\nimport { setup, audit } from \"./setup/index.js\";\nimport { listMigrations } from \"./setup/migrations/index.js\";\nimport { runUpgrade } from \"./setup/upgrade.js\";\n\ndeclare const __VERSION__: string;\n\nconst HELP = `\ntrafic-agent — Server agent for DDEV preview environments\n\nUsage:\n trafic-agent <command> [options]\n\nCommands:\n start Start the agent server\n setup Setup a new server (Docker, DDEV, hardening)\n upgrade Check for a new version, install it, run migrations, restart the service\n update Alias for upgrade\n audit Run security audit checks\n version Show version\n help Show this help\n\nStart options:\n -c, --config <path> Path to config file (default: /etc/trafic/config.toml)\n -p, --port <port> Override port from config\n\nSetup options:\n --tld <domain> TLD for DDEV projects (required on first run, reused from config on re-runs)\n --email <email> Email for Let's Encrypt certificates\n --no-hardening Skip server hardening steps\n --no-docker Skip Docker installation\n --no-ddev Skip DDEV installation\n --ssh-users <users> Comma-separated list of SSH users to allow (default: ddev)\n --dry-run Show what would be done without making changes\n\nUpgrade/update options:\n --dry-run Show what would be done without making changes\n --list List all migrations and their status (no install or restart)\n\nExamples:\n # Start the agent\n trafic-agent start\n trafic-agent start --config /path/to/config.toml\n\n # Setup a new server\n sudo trafic-agent setup --tld=previews.example.com\n sudo trafic-agent setup --tld=previews.example.com --email=admin@example.com\n sudo trafic-agent setup --tld=previews.example.com --no-hardening --dry-run\n\n # Upgrade: install latest version, run migrations, restart service\n sudo trafic-agent upgrade\n sudo trafic-agent upgrade --dry-run\n trafic-agent upgrade --list\n sudo trafic-agent update # alias for upgrade\n\n # Run security audit\n trafic-agent audit\n`;\n\nfunction printHelp(): void {\n console.log(HELP.trim());\n}\n\nfunction printVersion(): void {\n console.log(__VERSION__);\n}\n\nasync function runStart(values: Record<string, unknown>): Promise<void> {\n // Load config\n const config = loadConfig(values.config as string | undefined);\n\n // Override port if specified\n if (values.port) {\n config.port = parseInt(values.port as string, 10);\n }\n\n // Validate config\n const errors = validateConfig(config);\n if (errors.length > 0) {\n console.error(\"Configuration errors:\");\n for (const error of errors) {\n console.error(` - ${error}`);\n }\n process.exit(1);\n }\n\n // Graceful shutdown\n const shutdown = (): void => {\n console.log(\"\\nShutting down...\");\n closeDb();\n process.exit(0);\n };\n\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n\n // Start server and scheduler\n startServer(config);\n startIdleScheduler(config);\n}\n\nfunction handleUpgrade(values: Record<string, unknown>): void {\n const dryRun = values[\"dry-run\"] as boolean | undefined;\n const list = values.list as boolean | undefined;\n\n if (list) {\n const entries = listMigrations();\n console.log(\"\\nMigrations:\\n\");\n\n for (const { migration, status } of entries) {\n const icon = status === \"applied\" ? \"\\x1b[32m✓\\x1b[0m\" : \"\\x1b[36m→\\x1b[0m\";\n const label = status === \"applied\" ? \"\\x1b[90m(applied)\\x1b[0m\" : \"(pending)\";\n console.log(` ${icon} \\x1b[1m${migration.id.padEnd(30)}\\x1b[0m ${migration.description.padEnd(55)} ${label}`);\n }\n\n console.log(\"\");\n return;\n }\n\n console.log(\"\\n\\x1b[1m🚦 Trafic Server Upgrade\\x1b[0m\\n\");\n\n if (dryRun) {\n console.log(\"\\x1b[33m⚠ Dry-run mode: no changes will be made\\x1b[0m\\n\");\n }\n\n // Build re-exec args so flags survive the binary swap after a self-update\n const reExecArgs = [\"upgrade\", ...(dryRun ? [\"--dry-run\"] : [])];\n runUpgrade(dryRun ?? false, reExecArgs);\n\n if (!dryRun) {\n console.log(\"\\n\\x1b[32m✓ Upgrade complete!\\x1b[0m\\n\");\n }\n}\n\nasync function runSetup(values: Record<string, unknown>): Promise<void> {\n // Load existing config to use as defaults on re-runs\n const existingConfig = loadConfig();\n const tld = (values.tld as string | undefined) ?? (existingConfig.tld || undefined);\n\n if (!tld) {\n console.error(\"Error: --tld is required for setup\");\n console.error(\"Example: trafic-agent setup --tld=previews.example.com\");\n process.exit(1);\n }\n\n await setup({\n tld,\n email: values.email as string | undefined,\n noHardening: values[\"no-hardening\"] as boolean | undefined,\n noDocker: values[\"no-docker\"] as boolean | undefined,\n noDdev: values[\"no-ddev\"] as boolean | undefined,\n sshUsers: values[\"ssh-users\"]\n ? (values[\"ssh-users\"] as string).split(\",\").map((s) => s.trim())\n : undefined,\n dryRun: values[\"dry-run\"] as boolean | undefined,\n });\n}\n\nasync function main(): Promise<void> {\n const { values, positionals } = parseArgs({\n allowPositionals: true,\n options: {\n // Common\n help: { type: \"boolean\", short: \"h\" },\n\n // Start options\n config: { type: \"string\", short: \"c\" },\n port: { type: \"string\", short: \"p\" },\n\n // Setup options\n tld: { type: \"string\" },\n email: { type: \"string\" },\n \"no-hardening\": { type: \"boolean\" },\n \"no-docker\": { type: \"boolean\" },\n \"no-ddev\": { type: \"boolean\" },\n \"ssh-users\": { type: \"string\" },\n \"dry-run\": { type: \"boolean\" },\n\n // Upgrade options\n list: { type: \"boolean\" },\n },\n });\n\n const command = positionals[0] ?? \"help\";\n\n if (values.help) {\n printHelp();\n process.exit(0);\n }\n\n switch (command) {\n case \"help\":\n printHelp();\n break;\n\n case \"version\":\n printVersion();\n break;\n\n case \"start\":\n await runStart(values);\n break;\n\n case \"setup\":\n await runSetup(values);\n break;\n\n case \"upgrade\":\n case \"update\":\n handleUpgrade(values);\n break;\n\n case \"audit\":\n await audit();\n break;\n\n default:\n console.error(`Unknown command: ${command}`);\n printHelp();\n process.exit(1);\n }\n}\n\nmain().catch((error) => {\n console.error(\"Fatal error:\", error);\n process.exit(1);\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","names":[],"sources":["../src/setup/upgrade.ts","../src/cli.ts"],"sourcesContent":["import { execSync, spawnSync } from \"node:child_process\";\nimport { readFileSync } from \"node:fs\";\nimport { step, success, info, warn, exec, isRoot } from \"./steps.js\";\nimport { runPendingMigrations } from \"./migrations/index.js\";\n\ndeclare const __VERSION__: string;\n\n/**\n * Fetch the latest published version of @studiometa/trafic-agent from the npm registry.\n * Returns null if the registry is unreachable.\n */\nexport function fetchLatestVersion(): string | null {\n try {\n return execSync(\"npm show @studiometa/trafic-agent version\", {\n encoding: \"utf-8\",\n stdio: \"pipe\",\n }).trim();\n } catch {\n return null;\n }\n}\n\n/**\n * Compare two semver strings. Returns true if `next` is strictly greater than `current`.\n * Handles simple MAJOR.MINOR.PATCH without pre-release suffixes.\n */\nexport function isNewer(current: string, next: string): boolean {\n const parse = (v: string): [number, number, number] => {\n const parts = v.replace(/^v/, \"\").split(\".\").map(Number);\n return [parts[0] ?? 0, parts[1] ?? 0, parts[2] ?? 0];\n };\n\n const [cMaj, cMin, cPat] = parse(current);\n const [nMaj, nMin, nPat] = parse(next);\n\n if (nMaj !== cMaj) return nMaj > cMaj;\n if (nMin !== cMin) return nMin > cMin;\n return nPat > cPat;\n}\n\n/**\n * Install the latest version of @studiometa/trafic-agent globally via npm.\n * Uses --prefer-online to bypass the local npm cache and always fetch the\n * latest published tarball.\n */\nexport function installLatestAgent(dryRun: boolean): void {\n exec(\"npm install -g @studiometa/trafic-agent@latest --prefer-online\", { silent: !dryRun });\n}\n\n/**\n * Read the actual installed version of @studiometa/trafic-agent from its\n * package.json on disk — not from __VERSION__ which is baked in at build time.\n * Returns null if the file can't be read.\n */\nexport function getInstalledVersion(): string | null {\n try {\n const binary = execSync(\"which trafic-agent\", { encoding: \"utf-8\", stdio: \"pipe\" }).trim();\n // binary is e.g. /usr/bin/trafic-agent -> ../lib/node_modules/.../dist/cli.js\n // resolve to the package root: two levels up from dist/cli.js\n const pkgJson = execSync(`node -e \"console.log(require.resolve('@studiometa/trafic-agent/package.json'))\"`,\n { encoding: \"utf-8\", stdio: \"pipe\" }\n ).trim();\n const pkg = JSON.parse(readFileSync(pkgJson, \"utf-8\")) as { version: string };\n return pkg.version;\n } catch {\n return null;\n }\n}\n\n/**\n * Re-exec the newly installed trafic-agent binary with the same arguments.\n * Used after a self-update so the new binary runs its own migrations.\n * This function never returns — it replaces the current process.\n */\nexport function reExecNewBinary(args: string[]): never {\n const binary = execSync(\"which trafic-agent\", { encoding: \"utf-8\", stdio: \"pipe\" }).trim();\n const result = spawnSync(binary, args, {\n stdio: \"inherit\",\n env: { ...process.env, TRAFIC_UPGRADE_REEXEC: \"1\" },\n });\n process.exit(result.status ?? 0);\n}\n\n/**\n * Restart the trafic-agent systemd service.\n */\nexport function restartAgentService(dryRun: boolean): void {\n exec(\"systemctl restart trafic-agent\", { silent: !dryRun });\n}\n\n/**\n * Full upgrade sequence:\n * 1. Check for a new version on npm\n * 2. Install it globally if one is found — then re-exec the new binary\n * so that steps 3 and 4 run with the new migration registry\n * 3. Run pending migrations\n * 4. Restart the systemd service\n */\nexport function runUpgrade(dryRun = false, reExecArgs?: string[]): void {\n if (!isRoot() && !dryRun) {\n console.error(\" \\x1b[31m✗\\x1b[0m This command must be run as root\");\n console.log(\" Run: sudo trafic-agent upgrade\");\n process.exit(1);\n }\n\n // Guard against infinite re-exec loops: only re-exec once per upgrade run.\n const alreadyReExeced = process.env[\"TRAFIC_UPGRADE_REEXEC\"] === \"1\";\n\n // ── Step 1: Check for updates ─────────────────────────────────────────────\n step(\"Check for updates\");\n\n const current = __VERSION__;\n info(`Current version: ${current}`);\n\n const latest = fetchLatestVersion();\n\n if (!latest) {\n warn(\"Could not reach npm registry — skipping version check\");\n } else if (isNewer(current, latest)) {\n success(`New version available: ${latest}`);\n\n // ── Step 2: Install ───────────────────────────────────────────────────\n step(\"Install latest version\");\n installLatestAgent(dryRun);\n\n if (!dryRun) {\n // Verify the installed version actually changed before re-execing —\n // npm can serve stale cache and leave the old binary in place.\n const installedVersion = getInstalledVersion();\n\n if (!alreadyReExeced && installedVersion && isNewer(current, installedVersion)) {\n success(`Installed @studiometa/trafic-agent@${installedVersion}`);\n // Re-exec the newly installed binary so steps 3 and 4 run with the\n // new migration registry — the current process only knows about\n // migrations that existed at the time it was compiled.\n reExecNewBinary(reExecArgs ?? [\"upgrade\"]);\n } else if (installedVersion) {\n success(`Installed @studiometa/trafic-agent@${installedVersion}`);\n }\n }\n } else {\n success(`Already up to date (${current})`);\n }\n\n // ── Step 3: Run pending migrations ───────────────────────────────────────\n step(\"Run pending migrations\");\n runPendingMigrations(dryRun);\n\n // ── Step 4: Restart service ───────────────────────────────────────────────\n step(\"Restart trafic-agent service\");\n restartAgentService(dryRun);\n if (!dryRun) {\n success(\"Service restarted\");\n }\n}\n","#!/usr/bin/env node\n\nimport { parseArgs } from \"node:util\";\nimport { loadConfig, validateConfig } from \"./utils/config.js\";\nimport { startServer } from \"./server.js\";\nimport { startIdleScheduler } from \"./tasks/stop-idle.js\";\nimport { closeDb } from \"./utils/db.js\";\nimport { setup, audit } from \"./setup/index.js\";\nimport { listMigrations } from \"./setup/migrations/index.js\";\nimport { runUpgrade } from \"./setup/upgrade.js\";\n\ndeclare const __VERSION__: string;\n\nconst HELP = `\ntrafic-agent — Server agent for DDEV preview environments\n\nUsage:\n trafic-agent <command> [options]\n\nCommands:\n start Start the agent server\n setup Setup a new server (Docker, DDEV, hardening)\n upgrade Check for a new version, install it, run migrations, restart the service\n update Alias for upgrade\n audit Run security audit checks\n version Show version\n help Show this help\n\nStart options:\n -c, --config <path> Path to config file (default: /etc/trafic/config.toml)\n -p, --port <port> Override port from config\n\nSetup options:\n --tld <domain> TLD for DDEV projects (required on first run, reused from config on re-runs)\n --email <email> Email for Let's Encrypt certificates\n --no-hardening Skip server hardening steps\n --no-docker Skip Docker installation\n --no-ddev Skip DDEV installation\n --ssh-users <users> Comma-separated list of SSH users to allow (default: ddev)\n --dry-run Show what would be done without making changes\n\nUpgrade/update options:\n --dry-run Show what would be done without making changes\n --list List all migrations and their status (no install or restart)\n\nExamples:\n # Start the agent\n trafic-agent start\n trafic-agent start --config /path/to/config.toml\n\n # Setup a new server\n sudo trafic-agent setup --tld=previews.example.com\n sudo trafic-agent setup --tld=previews.example.com --email=admin@example.com\n sudo trafic-agent setup --tld=previews.example.com --no-hardening --dry-run\n\n # Upgrade: install latest version, run migrations, restart service\n sudo trafic-agent upgrade\n sudo trafic-agent upgrade --dry-run\n trafic-agent upgrade --list\n sudo trafic-agent update # alias for upgrade\n\n # Run security audit\n trafic-agent audit\n`;\n\nfunction printHelp(): void {\n console.log(HELP.trim());\n}\n\nfunction printVersion(): void {\n console.log(__VERSION__);\n}\n\nasync function runStart(values: Record<string, unknown>): Promise<void> {\n // Load config\n const config = loadConfig(values.config as string | undefined);\n\n // Override port if specified\n if (values.port) {\n config.port = parseInt(values.port as string, 10);\n }\n\n // Validate config\n const errors = validateConfig(config);\n if (errors.length > 0) {\n console.error(\"Configuration errors:\");\n for (const error of errors) {\n console.error(` - ${error}`);\n }\n process.exit(1);\n }\n\n // Graceful shutdown\n const shutdown = (): void => {\n console.log(\"\\nShutting down...\");\n closeDb();\n process.exit(0);\n };\n\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n\n // Start server and scheduler\n startServer(config);\n startIdleScheduler(config);\n}\n\nfunction handleUpgrade(values: Record<string, unknown>): void {\n const dryRun = values[\"dry-run\"] as boolean | undefined;\n const list = values.list as boolean | undefined;\n\n if (list) {\n const entries = listMigrations();\n console.log(\"\\nMigrations:\\n\");\n\n for (const { migration, status } of entries) {\n const icon = status === \"applied\" ? \"\\x1b[32m✓\\x1b[0m\" : \"\\x1b[36m→\\x1b[0m\";\n const label = status === \"applied\" ? \"\\x1b[90m(applied)\\x1b[0m\" : \"(pending)\";\n console.log(` ${icon} \\x1b[1m${migration.id.padEnd(30)}\\x1b[0m ${migration.description.padEnd(55)} ${label}`);\n }\n\n console.log(\"\");\n return;\n }\n\n console.log(\"\\n\\x1b[1m🚦 Trafic Server Upgrade\\x1b[0m\\n\");\n\n if (dryRun) {\n console.log(\"\\x1b[33m⚠ Dry-run mode: no changes will be made\\x1b[0m\\n\");\n }\n\n // Build re-exec args so flags survive the binary swap after a self-update\n const reExecArgs = [\"upgrade\", ...(dryRun ? [\"--dry-run\"] : [])];\n runUpgrade(dryRun ?? false, reExecArgs);\n\n if (!dryRun) {\n console.log(\"\\n\\x1b[32m✓ Upgrade complete!\\x1b[0m\\n\");\n }\n}\n\nasync function runSetup(values: Record<string, unknown>): Promise<void> {\n // Load existing config to use as defaults on re-runs\n const existingConfig = loadConfig();\n const tld = (values.tld as string | undefined) ?? (existingConfig.tld || undefined);\n\n if (!tld) {\n console.error(\"Error: --tld is required for setup\");\n console.error(\"Example: trafic-agent setup --tld=previews.example.com\");\n process.exit(1);\n }\n\n await setup({\n tld,\n email: values.email as string | undefined,\n noHardening: values[\"no-hardening\"] as boolean | undefined,\n noDocker: values[\"no-docker\"] as boolean | undefined,\n noDdev: values[\"no-ddev\"] as boolean | undefined,\n sshUsers: values[\"ssh-users\"]\n ? (values[\"ssh-users\"] as string).split(\",\").map((s) => s.trim())\n : undefined,\n dryRun: values[\"dry-run\"] as boolean | undefined,\n });\n}\n\nasync function main(): Promise<void> {\n const { values, positionals } = parseArgs({\n allowPositionals: true,\n options: {\n // Common\n help: { type: \"boolean\", short: \"h\" },\n\n // Start options\n config: { type: \"string\", short: \"c\" },\n port: { type: \"string\", short: \"p\" },\n\n // Setup options\n tld: { type: \"string\" },\n email: { type: \"string\" },\n \"no-hardening\": { type: \"boolean\" },\n \"no-docker\": { type: \"boolean\" },\n \"no-ddev\": { type: \"boolean\" },\n \"ssh-users\": { type: \"string\" },\n \"dry-run\": { type: \"boolean\" },\n\n // Upgrade options\n list: { type: \"boolean\" },\n },\n });\n\n const command = positionals[0] ?? \"help\";\n\n if (values.help) {\n printHelp();\n process.exit(0);\n }\n\n switch (command) {\n case \"help\":\n printHelp();\n break;\n\n case \"version\":\n printVersion();\n break;\n\n case \"start\":\n await runStart(values);\n break;\n\n case \"setup\":\n await runSetup(values);\n break;\n\n case \"upgrade\":\n case \"update\":\n handleUpgrade(values);\n break;\n\n case \"audit\":\n await audit();\n break;\n\n default:\n console.error(`Unknown command: ${command}`);\n printHelp();\n process.exit(1);\n }\n}\n\nmain().catch((error) => {\n console.error(\"Fatal error:\", error);\n process.exit(1);\n});\n"],"mappings":"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"}
@@ -10,8 +10,16 @@ export declare function fetchLatestVersion(): string | null;
10
10
  export declare function isNewer(current: string, next: string): boolean;
11
11
  /**
12
12
  * Install the latest version of @studiometa/trafic-agent globally via npm.
13
+ * Uses --prefer-online to bypass the local npm cache and always fetch the
14
+ * latest published tarball.
13
15
  */
14
16
  export declare function installLatestAgent(dryRun: boolean): void;
17
+ /**
18
+ * Read the actual installed version of @studiometa/trafic-agent from its
19
+ * package.json on disk — not from __VERSION__ which is baked in at build time.
20
+ * Returns null if the file can't be read.
21
+ */
22
+ export declare function getInstalledVersion(): string | null;
15
23
  /**
16
24
  * Re-exec the newly installed trafic-agent binary with the same arguments.
17
25
  * Used after a self-update so the new binary runs its own migrations.
@@ -1 +1 @@
1
- {"version":3,"file":"upgrade.d.ts","sourceRoot":"","sources":["../../src/setup/upgrade.ts"],"names":[],"mappings":"AAMA;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,GAAG,IAAI,CASlD;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAY9D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAExD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,KAAK,CAIrD;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAEzD;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,MAAM,UAAQ,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CA4CtE"}
1
+ {"version":3,"file":"upgrade.d.ts","sourceRoot":"","sources":["../../src/setup/upgrade.ts"],"names":[],"mappings":"AAOA;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,GAAG,IAAI,CASlD;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAY9D;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAExD;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,GAAG,IAAI,CAanD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,KAAK,CAOrD;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAEzD;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,MAAM,UAAQ,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAwDtE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@studiometa/trafic-agent",
3
- "version": "0.1.19",
3
+ "version": "0.1.20",
4
4
  "description": "Server agent for DDEV preview environments — auth, scale-to-zero, auto-start",
5
5
  "keywords": [
6
6
  "agent",