flightdeck 0.2.96 → 0.3.0

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.
@@ -28,7 +28,52 @@ const FLIGHTDECK_UPDATE_PHASES = [`notified`, `confirmed`];
28
28
  function isVersionNumber(version) {
29
29
  return /^\d+\.\d+\.\d+$/.test(version) || !Number.isNaN(Number.parseFloat(version));
30
30
  }
31
+ async function waitForPidExit(pid, timeoutMs = 5e3, intervalMs = 100) {
32
+ return new Promise((pass, fail) => {
33
+ const start = Date.now();
34
+ const check = () => {
35
+ process.stdout.write(`.`);
36
+ try {
37
+ process.kill(pid, 0);
38
+ if (Date.now() - start > timeoutMs) {
39
+ fail(/* @__PURE__ */ new Error(`Timeout waiting for PID ${pid}`));
40
+ return;
41
+ }
42
+ setTimeout(check, intervalMs);
43
+ } catch (err) {
44
+ if (err instanceof Error && `code` in err) {
45
+ if (err.code === `ESRCH`) {
46
+ pass();
47
+ return;
48
+ }
49
+ if (err.code === `EPERM`) {
50
+ if (Date.now() - start > timeoutMs) {
51
+ fail(/* @__PURE__ */ new Error(`Timeout waiting for PID ${pid} (EPERM; still alive)`));
52
+ return;
53
+ }
54
+ return setTimeout(check, intervalMs);
55
+ }
56
+ }
57
+ fail(err);
58
+ return;
59
+ }
60
+ };
61
+ check();
62
+ });
63
+ }
31
64
  var FlightDeck = class {
65
+ static async kill(flightdeckRootDir, packageName) {
66
+ console.info(`Killing FlightDeck instance of "${packageName}"`);
67
+ const currentPid = new FilesystemStorage({ path: resolve(flightdeckRootDir, `storage`, packageName) }).getItem(`currentPid`);
68
+ if (currentPid === null) throw new Error(`No pid for "${packageName}" found in storage`);
69
+ const pid = Number(currentPid);
70
+ const now = Date.now();
71
+ process.kill(pid, `SIGTERM`);
72
+ await waitForPidExit(pid, 5e3, 5);
73
+ const elapsed = Date.now() - now;
74
+ process.stdout.write(`🌜 "${packageName}" (running as process ${pid}) exited in ${elapsed}ms\n`);
75
+ return pid;
76
+ }
32
77
  options;
33
78
  safety = 0;
34
79
  storage;
@@ -64,6 +109,7 @@ var FlightDeck = class {
64
109
  this.live.use(Promise.all(this.servicesLive));
65
110
  this.dead.use(Promise.all(this.servicesDead));
66
111
  this.storage = new FilesystemStorage({ path: resolve(flightdeckRootDir, `storage`, options.packageName) });
112
+ this.storage.setItem(`currentPid`, `${process.pid}`);
67
113
  if (FLIGHTDECK_SECRET === void 0) this.logger.warn(`No FLIGHTDECK_SECRET environment variable found. FlightDeck will not run an update server.`);
68
114
  else createServer((req, res) => {
69
115
  let data = [];
@@ -117,6 +163,12 @@ var FlightDeck = class {
117
163
  }).catch((thrown) => {
118
164
  if (thrown instanceof Error) this.logger.error(`Failed to start all services:`, thrown.message);
119
165
  });
166
+ process.on(`SIGTERM`, async () => {
167
+ console.info(`Killed by SIGTERM`);
168
+ await this.stopAllServices();
169
+ this.storage.removeItem(`currentPid`);
170
+ process.exit(0);
171
+ });
120
172
  }
121
173
  async seekUpdate(version) {
122
174
  this.logger.info(`Checking for updates...`);
@@ -212,7 +264,7 @@ var FlightDeck = class {
212
264
  this.logger.info(`Auto-respawn saw "${serviceName}" exit with code ${exitCode}`);
213
265
  this.services[serviceName] = null;
214
266
  if (!this.autoRespawnDeadServices) {
215
- this.logger.info(`Auto-respawn is off; "${serviceName}" rests.`);
267
+ this.logger.info(`😴 Auto-respawn is off; "${serviceName}" rests.`);
216
268
  return;
217
269
  }
218
270
  const updatePhase = this.storage.getItem(`updatePhase`);
@@ -390,4 +442,4 @@ var FlightDeckLogger = class {
390
442
 
391
443
  //#endregion
392
444
  export { FLIGHTDECK_UPDATE_PHASES as a, FlightDeckLogger as c, FLIGHTDECK_SETUP_PHASES as i, isVersionNumber as l, FLIGHTDECK_INFO as n, FLIGHTDECK_WARN as o, FLIGHTDECK_LNAV_FORMAT as r, FlightDeck as s, FLIGHTDECK_ERROR as t };
393
- //# sourceMappingURL=flightdeck.lib-DMlmcPLR.js.map
445
+ //# sourceMappingURL=flightdeck.lib-DneT-dY9.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flightdeck.lib-DneT-dY9.js","names":["data: Uint8Array[]","log: FlightDeckLog"],"sources":["../src/flightdeck.env.ts","../src/flightdeck.lib.ts"],"sourcesContent":["import { createEnv } from \"@t3-oss/env-core\"\nimport { type } from \"arktype\"\n\nexport const env = createEnv({\n\tserver: { FLIGHTDECK_SECRET: type(`string`, `|`, `undefined`) },\n\tclientPrefix: `NEVER`,\n\tclient: {},\n\truntimeEnv: import.meta.env as Record<string, string>,\n\temptyStringAsUndefined: true,\n})\n","/* eslint-disable @typescript-eslint/only-throw-error */\nimport type { ChildProcessWithoutNullStreams } from \"node:child_process\"\nimport { execSync, spawn } from \"node:child_process\"\nimport { createServer } from \"node:http\"\nimport { homedir } from \"node:os\"\nimport { resolve } from \"node:path\"\nimport { inspect } from \"node:util\"\n\nimport { Future } from \"atom.io/internal\"\nimport { discoverType } from \"atom.io/introspection\"\nimport { fromEntries, toEntries } from \"atom.io/json\"\nimport { ChildSocket } from \"atom.io/realtime-server\"\nimport { CronJob } from \"cron\"\nimport { FilesystemStorage } from \"safedeposit\"\n\nimport type { LnavFormat } from \"../gen/lnav-format-schema.gen.ts\"\nimport { env } from \"./flightdeck.env.ts\"\n\nexport const FLIGHTDECK_SETUP_PHASES = [`downloaded`, `installed`] as const\n\nexport type FlightDeckSetupPhase = (typeof FLIGHTDECK_SETUP_PHASES)[number]\n\nexport const FLIGHTDECK_UPDATE_PHASES = [`notified`, `confirmed`] as const\n\nexport type FlightDeckUpdatePhase = (typeof FLIGHTDECK_UPDATE_PHASES)[number]\n\nexport function isVersionNumber(version: string): boolean {\n\treturn (\n\t\t/^\\d+\\.\\d+\\.\\d+$/.test(version) || !Number.isNaN(Number.parseFloat(version))\n\t)\n}\n\nexport type FlightDeckSaveData = {\n\tcurrentPid: `${number}`\n\tsetupPhase: FlightDeckSetupPhase\n\tupdatePhase: FlightDeckUpdatePhase\n\tupdateAwaitedVersion: string\n}\n\nexport type FlightDeckOptions<S extends string = string> = {\n\treadonly packageName: string\n\treadonly services: { [service in S]: { run: string; waitFor: boolean } }\n\treadonly scripts: {\n\t\treadonly download: string\n\t\treadonly install: string\n\t\treadonly checkAvailability?: string\n\t}\n\treadonly port?: number | undefined\n\treadonly flightdeckRootDir?: string | undefined\n\treadonly jsonLogging?: boolean | undefined\n}\n\nasync function waitForPidExit(pid: number, timeoutMs = 5000, intervalMs = 100) {\n\treturn new Promise<void>((pass, fail) => {\n\t\tconst start = Date.now()\n\n\t\tconst check = () => {\n\t\t\tprocess.stdout.write(`.`)\n\t\t\ttry {\n\t\t\t\t// check existence\n\t\t\t\tprocess.kill(pid, 0)\n\t\t\t\t// process still alive\n\t\t\t\tif (Date.now() - start > timeoutMs) {\n\t\t\t\t\tfail(new Error(`Timeout waiting for PID ${pid}`))\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tsetTimeout(check, intervalMs)\n\t\t\t} catch (err) {\n\t\t\t\tif (err instanceof Error && `code` in err) {\n\t\t\t\t\tif (err.code === `ESRCH`) {\n\t\t\t\t\t\tpass()\n\t\t\t\t\t\treturn // exited\n\t\t\t\t\t}\n\t\t\t\t\tif (err.code === `EPERM`) {\n\t\t\t\t\t\t// process is alive but protected\n\t\t\t\t\t\tif (Date.now() - start > timeoutMs) {\n\t\t\t\t\t\t\tfail(\n\t\t\t\t\t\t\t\tnew Error(`Timeout waiting for PID ${pid} (EPERM; still alive)`),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn setTimeout(check, intervalMs)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfail(err)\n\t\t\t\treturn // unexpected error\n\t\t\t}\n\t\t}\n\n\t\tcheck()\n\t})\n}\n\nexport class FlightDeck<S extends string = string> {\n\tpublic static async kill(\n\t\tflightdeckRootDir: string,\n\t\tpackageName: string,\n\t): Promise<number> {\n\t\tconsole.info(`Killing FlightDeck instance of \"${packageName}\"`)\n\t\tconst storage = new FilesystemStorage<FlightDeckSaveData>({\n\t\t\tpath: resolve(flightdeckRootDir, `storage`, packageName),\n\t\t})\n\t\tconst currentPid = storage.getItem(`currentPid`)\n\t\tif (currentPid === null) {\n\t\t\tthrow new Error(`No pid for \"${packageName}\" found in storage`)\n\t\t}\n\t\tconst pid = Number(currentPid)\n\t\tconst now = Date.now()\n\t\tprocess.kill(pid, `SIGTERM`)\n\t\tawait waitForPidExit(pid, 5000, 5)\n\t\tconst elapsed = Date.now() - now\n\t\tprocess.stdout.write(\n\t\t\t`🌜 \"${packageName}\" (running as process ${pid}) exited in ${elapsed}ms\\n`,\n\t\t)\n\t\treturn pid\n\t}\n\n\tpublic readonly options: FlightDeckOptions<S>\n\tprotected safety = 0\n\n\tprotected storage: FilesystemStorage<FlightDeckSaveData>\n\tprotected services: {\n\t\t[service in S]: ChildSocket<\n\t\t\t{ timeToStop: []; updatesReady: [] },\n\t\t\t{ readyToUpdate: []; alive: [] },\n\t\t\tChildProcessWithoutNullStreams\n\t\t> | null\n\t}\n\tprotected serviceIdx: { readonly [service in S]: number }\n\tpublic defaultServicesReadyToUpdate: { readonly [service in S]: boolean }\n\tpublic servicesReadyToUpdate: { [service in S]: boolean }\n\tpublic autoRespawnDeadServices: boolean\n\n\tprotected logger: Pick<Console, `error` | `info` | `warn`>\n\tprotected serviceLoggers: {\n\t\treadonly [service in S]: FlightDeckLogger\n\t}\n\n\tprotected updateAvailabilityChecker: CronJob | null = null\n\n\tpublic servicesLive: Future<void>[]\n\tpublic servicesDead: Future<void>[]\n\tpublic live = new Future(() => {})\n\tpublic dead = new Future(() => {})\n\n\tprotected restartTimes: number[] = []\n\n\tpublic constructor(options: FlightDeckOptions<S>) {\n\t\tthis.options = options\n\t\tconst { FLIGHTDECK_SECRET } = env\n\t\tconst { flightdeckRootDir = resolve(homedir(), `.flightdeck`) } = options\n\t\tconst port = options.port ?? 8080\n\t\tconst origin = `http://localhost:${port}`\n\n\t\tconst servicesEntries = toEntries(options.services)\n\t\tthis.services = fromEntries(\n\t\t\tservicesEntries.map(([serviceName]) => [serviceName, null]),\n\t\t)\n\t\tthis.serviceIdx = fromEntries(\n\t\t\tservicesEntries.map(([serviceName], idx) => [serviceName, idx]),\n\t\t)\n\t\tthis.defaultServicesReadyToUpdate = fromEntries(\n\t\t\tservicesEntries.map(([serviceName, { waitFor }]) => [\n\t\t\t\tserviceName,\n\t\t\t\t!waitFor,\n\t\t\t]),\n\t\t)\n\t\tthis.servicesReadyToUpdate = { ...this.defaultServicesReadyToUpdate }\n\t\tthis.autoRespawnDeadServices = true\n\n\t\tthis.logger = new FlightDeckLogger(\n\t\t\tthis.options.packageName,\n\t\t\tprocess.pid,\n\t\t\tundefined,\n\t\t\t{ jsonLogging: this.options.jsonLogging ?? false },\n\t\t)\n\t\tthis.serviceLoggers = fromEntries(\n\t\t\tservicesEntries.map(([serviceName]) => [\n\t\t\t\tserviceName,\n\t\t\t\tnew FlightDeckLogger(\n\t\t\t\t\tthis.options.packageName,\n\t\t\t\t\tprocess.pid,\n\t\t\t\t\tserviceName,\n\t\t\t\t\t{ jsonLogging: this.options.jsonLogging ?? false },\n\t\t\t\t),\n\t\t\t]),\n\t\t)\n\n\t\tthis.servicesLive = servicesEntries.map(() => new Future(() => {}))\n\t\tthis.servicesDead = servicesEntries.map(() => new Future(() => {}))\n\t\tthis.live.use(Promise.all(this.servicesLive))\n\t\tthis.dead.use(Promise.all(this.servicesDead))\n\n\t\tthis.storage = new FilesystemStorage({\n\t\t\tpath: resolve(flightdeckRootDir, `storage`, options.packageName),\n\t\t})\n\n\t\tthis.storage.setItem(`currentPid`, `${process.pid}`)\n\n\t\tif (FLIGHTDECK_SECRET === undefined) {\n\t\t\tthis.logger.warn(\n\t\t\t\t`No FLIGHTDECK_SECRET environment variable found. FlightDeck will not run an update server.`,\n\t\t\t)\n\t\t} else {\n\t\t\tcreateServer((req, res) => {\n\t\t\t\tlet data: Uint8Array[] = []\n\t\t\t\treq\n\t\t\t\t\t.on(`data`, (chunk) => {\n\t\t\t\t\t\tdata.push(chunk instanceof Buffer ? chunk : Buffer.from(chunk))\n\t\t\t\t\t})\n\t\t\t\t\t.on(`end`, async () => {\n\t\t\t\t\t\tconst authHeader = req.headers.authorization\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tif (typeof req.url === `undefined`) throw 400\n\t\t\t\t\t\t\tconst expectedAuthHeader = `Bearer ${FLIGHTDECK_SECRET}`\n\t\t\t\t\t\t\tif (authHeader !== `Bearer ${FLIGHTDECK_SECRET}`) {\n\t\t\t\t\t\t\t\tthis.logger.info(\n\t\t\t\t\t\t\t\t\t`Unauthorized: needed \\`${expectedAuthHeader}\\`, got \\`${authHeader}\\``,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\tthrow 401\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst url = new URL(req.url, origin)\n\t\t\t\t\t\t\tthis.logger.info(req.method, url.pathname)\n\n\t\t\t\t\t\t\tconst versionForeignInput = Buffer.concat(data).toString()\n\t\t\t\t\t\t\tif (!isVersionNumber(versionForeignInput)) {\n\t\t\t\t\t\t\t\tthrow 400\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tres.writeHead(200)\n\t\t\t\t\t\t\tres.end()\n\n\t\t\t\t\t\t\tthis.storage.setItem(`updatePhase`, `notified`)\n\t\t\t\t\t\t\tthis.storage.setItem(`updateAwaitedVersion`, versionForeignInput)\n\t\t\t\t\t\t\tconst { checkAvailability } = options.scripts\n\t\t\t\t\t\t\tif (checkAvailability) {\n\t\t\t\t\t\t\t\tawait this.updateAvailabilityChecker?.stop()\n\t\t\t\t\t\t\t\tawait this.seekUpdate(versionForeignInput)\n\t\t\t\t\t\t\t\tconst updatePhase = this.storage.getItem(`updatePhase`)\n\t\t\t\t\t\t\t\tthis.logger.info(`> storage(\"updatePhase\") >`, updatePhase)\n\t\t\t\t\t\t\t\tif (updatePhase === `notified`) {\n\t\t\t\t\t\t\t\t\tthis.updateAvailabilityChecker = new CronJob(\n\t\t\t\t\t\t\t\t\t\t`*/30 * * * * *`,\n\t\t\t\t\t\t\t\t\t\tasync () => {\n\t\t\t\t\t\t\t\t\t\t\tawait this.seekUpdate(versionForeignInput)\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\tthis.updateAvailabilityChecker.start()\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthis.downloadPackage()\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch (thrown) {\n\t\t\t\t\t\t\tthis.logger.error(thrown, req.url)\n\t\t\t\t\t\t\tif (typeof thrown === `number`) {\n\t\t\t\t\t\t\t\tres.writeHead(thrown)\n\t\t\t\t\t\t\t\tres.end()\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} finally {\n\t\t\t\t\t\t\tdata = []\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t}).listen(port, () => {\n\t\t\t\tthis.logger.info(`Server started on port ${port}`)\n\t\t\t})\n\t\t}\n\n\t\tthis.startAllServices()\n\t\t\t.then(() => {\n\t\t\t\tthis.logger.info(`All services started.`)\n\t\t\t})\n\t\t\t.catch((thrown) => {\n\t\t\t\tif (thrown instanceof Error) {\n\t\t\t\t\tthis.logger.error(`Failed to start all services:`, thrown.message)\n\t\t\t\t}\n\t\t\t})\n\n\t\tprocess.on(`SIGTERM`, async () => {\n\t\t\tconsole.info(`Killed by SIGTERM`)\n\t\t\tawait this.stopAllServices()\n\t\t\tthis.storage.removeItem(`currentPid`)\n\t\t\tprocess.exit(0)\n\t\t})\n\t}\n\n\tprotected async seekUpdate(version: string): Promise<void> {\n\t\tthis.logger.info(`Checking for updates...`)\n\t\tconst { checkAvailability } = this.options.scripts\n\t\tif (!checkAvailability) {\n\t\t\tthis.logger.info(`No checkAvailability script found.`)\n\t\t\treturn\n\t\t}\n\t\ttry {\n\t\t\tconst out = execSync(`${checkAvailability} ${version}`)\n\t\t\tthis.logger.info(`Check stdout:`, out.toString())\n\t\t\tawait this.updateAvailabilityChecker?.stop()\n\t\t\tthis.storage.setItem(`updatePhase`, `confirmed`)\n\t\t\tthis.downloadPackage()\n\t\t\tthis.announceUpdate()\n\t\t} catch (thrown) {\n\t\t\tif (thrown instanceof Error) {\n\t\t\t\tthis.logger.error(`Check failed:`, thrown.message)\n\t\t\t} else {\n\t\t\t\tconst thrownType = discoverType(thrown)\n\t\t\t\tthis.logger.error(`Check threw`, thrownType, thrown)\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected announceUpdate(): void {\n\t\tfor (const entry of toEntries(this.services)) {\n\t\t\tconst [serviceName, service] = entry\n\t\t\tif (service) {\n\t\t\t\tif (this.options.services[serviceName].waitFor) {\n\t\t\t\t\tservice.emit(`updatesReady`)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.startService(serviceName)\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected tryUpdate(): void {\n\t\tif (toEntries(this.servicesReadyToUpdate).every(([, isReady]) => isReady)) {\n\t\t\tthis.logger.info(`All services are ready to update.`)\n\t\t\tthis.stopAllServices()\n\t\t\t\t.then(() => {\n\t\t\t\t\tthis.logger.info(`All services stopped; starting up fresh...`)\n\t\t\t\t\tthis.startAllServices()\n\t\t\t\t\t\t.then(() => {\n\t\t\t\t\t\t\tthis.logger.info(`All services started; we're back online.`)\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.catch((thrown) => {\n\t\t\t\t\t\t\tif (thrown instanceof Error) {\n\t\t\t\t\t\t\t\tthis.logger.error(\n\t\t\t\t\t\t\t\t\t`Failed to start all services:`,\n\t\t\t\t\t\t\t\t\tthrown.message,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t})\n\t\t\t\t})\n\t\t\t\t.catch((thrown) => {\n\t\t\t\t\tif (thrown instanceof Error) {\n\t\t\t\t\t\tthis.logger.error(`Failed to stop all services:`, thrown.message)\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t}\n\t}\n\n\tprotected startAllServices(): Future<unknown> {\n\t\tthis.logger.info(`Starting all services...`)\n\t\tthis.autoRespawnDeadServices = true\n\t\tconst setupPhase = this.storage.getItem(`setupPhase`)\n\t\tthis.logger.info(`> storage(\"setupPhase\") >`, setupPhase)\n\t\tswitch (setupPhase) {\n\t\t\tcase null:\n\t\t\t\tthis.logger.info(`Starting from scratch.`)\n\t\t\t\tthis.downloadPackage()\n\t\t\t\tthis.installPackage()\n\t\t\t\treturn this.startAllServices()\n\t\t\tcase `downloaded`:\n\t\t\t\tthis.logger.info(`Found package downloaded but not installed.`)\n\t\t\t\tthis.installPackage()\n\t\t\t\treturn this.startAllServices()\n\t\t\tcase `installed`: {\n\t\t\t\tfor (const [serviceName] of toEntries(this.services)) {\n\t\t\t\t\tthis.startService(serviceName)\n\t\t\t\t}\n\t\t\t\treturn this.live\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected startService(serviceName: S): void {\n\t\tthis.logger.info(\n\t\t\t`Starting service ${this.options.packageName}::${serviceName}, try ${this.safety}/2...`,\n\t\t)\n\t\tif (this.safety >= 2) {\n\t\t\tthrow new Error(`Out of tries...`)\n\t\t}\n\t\tthis.safety++\n\n\t\tconst [exe, ...args] = this.options.services[serviceName].run.split(` `)\n\t\tconst serviceProcess = spawn(exe, args, {\n\t\t\tcwd: this.options.flightdeckRootDir,\n\t\t\tenv: import.meta.env as Record<string, string>,\n\t\t})\n\t\tconst serviceLogger = this.serviceLoggers[serviceName]\n\t\tconst service = (this.services[serviceName] = new ChildSocket(\n\t\t\tserviceProcess,\n\t\t\t`${this.options.packageName}::${serviceName}`,\n\t\t\tserviceLogger,\n\t\t))\n\t\tserviceLogger.processCode = service.proc.pid ?? -1\n\t\tthis.services[serviceName].onAny((...messages) => {\n\t\t\tserviceLogger.info(`💬`, ...messages)\n\t\t})\n\t\tthis.services[serviceName].on(`readyToUpdate`, () => {\n\t\t\tthis.logger.info(`Service \"${serviceName}\" is ready to update.`)\n\t\t\tthis.servicesReadyToUpdate[serviceName] = true\n\t\t\tthis.tryUpdate()\n\t\t})\n\t\tthis.services[serviceName].on(`alive`, () => {\n\t\t\tthis.servicesLive[this.serviceIdx[serviceName]].use(Promise.resolve())\n\t\t\tthis.servicesDead[this.serviceIdx[serviceName]] = new Future(() => {})\n\t\t\tif (this.dead.done) {\n\t\t\t\tthis.dead = new Future(() => {})\n\t\t\t}\n\t\t\tthis.dead.use(Promise.all(this.servicesDead))\n\t\t})\n\t\tthis.services[serviceName].proc.once(`close`, (exitCode) => {\n\t\t\tthis.logger.info(\n\t\t\t\t`Auto-respawn saw \"${serviceName}\" exit with code ${exitCode}`,\n\t\t\t)\n\t\t\tthis.services[serviceName] = null\n\t\t\tif (!this.autoRespawnDeadServices) {\n\t\t\t\tthis.logger.info(`😴 Auto-respawn is off; \"${serviceName}\" rests.`)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst updatePhase = this.storage.getItem(`updatePhase`)\n\t\t\tthis.logger.info(`> storage(\"updatePhase\") >`, updatePhase)\n\t\t\tconst updatesAreReady = updatePhase === `confirmed`\n\t\t\tif (updatesAreReady) {\n\t\t\t\tthis.serviceLoggers[serviceName].info(`Updating before startup...`)\n\t\t\t\tthis.restartTimes = []\n\t\t\t\tthis.installPackage()\n\t\t\t\tthis.startService(serviceName)\n\t\t\t} else {\n\t\t\t\tconst now = Date.now()\n\t\t\t\tconst fiveMinutesAgo = now - 5 * 60 * 1000\n\t\t\t\tthis.restartTimes = this.restartTimes.filter(\n\t\t\t\t\t(time) => time > fiveMinutesAgo,\n\t\t\t\t)\n\t\t\t\tthis.restartTimes.push(now)\n\n\t\t\t\tif (this.restartTimes.length < 5) {\n\t\t\t\t\tthis.serviceLoggers[serviceName].info(`Crashed. Restarting...`)\n\t\t\t\t\tthis.startService(serviceName)\n\t\t\t\t} else {\n\t\t\t\t\tthis.serviceLoggers[serviceName].info(\n\t\t\t\t\t\t`Crashed 5 times in 5 minutes. Not restarting.`,\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t\tthis.safety = 0\n\t}\n\n\tprotected downloadPackage(): void {\n\t\tthis.logger.info(`Downloading...`)\n\t\ttry {\n\t\t\tconst out = execSync(this.options.scripts.download)\n\t\t\tthis.logger.info(`Download stdout:`, out.toString())\n\t\t\tthis.storage.setItem(`setupPhase`, `downloaded`)\n\t\t\tthis.logger.info(`Downloaded!`)\n\t\t} catch (thrown) {\n\t\t\tif (thrown instanceof Error) {\n\t\t\t\tthis.logger.error(`Failed to get the latest release: ${thrown.message}`)\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t}\n\n\tprotected installPackage(): void {\n\t\tthis.logger.info(`Installing...`)\n\n\t\ttry {\n\t\t\tconst out = execSync(this.options.scripts.install)\n\t\t\tthis.logger.info(`Install stdout:`, out.toString())\n\t\t\tthis.storage.setItem(`setupPhase`, `installed`)\n\t\t\tthis.logger.info(`Installed!`)\n\t\t} catch (thrown) {\n\t\t\tif (thrown instanceof Error) {\n\t\t\t\tthis.logger.error(`Failed to get the latest release: ${thrown.message}`)\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t}\n\n\tpublic stopAllServices(): Future<unknown> {\n\t\tthis.logger.info(`Stopping all services... auto-respawn disabled.`)\n\t\tthis.autoRespawnDeadServices = false\n\t\tfor (const [serviceName] of toEntries(this.services)) {\n\t\t\tthis.stopService(serviceName)\n\t\t}\n\t\treturn this.dead\n\t}\n\n\tpublic stopService(serviceName: S): void {\n\t\tconst service = this.services[serviceName]\n\t\tif (service) {\n\t\t\tthis.logger.info(`Stopping service \"${serviceName}\"...`)\n\t\t\tthis.servicesDead[this.serviceIdx[serviceName]].use(\n\t\t\t\tnew Promise((pass) => {\n\t\t\t\t\tservice.emit(`timeToStop`)\n\t\t\t\t\tservice.proc.once(`close`, (exitCode) => {\n\t\t\t\t\t\tthis.logger.info(\n\t\t\t\t\t\t\t`Stopped service \"${serviceName}\"; exited with code ${exitCode}`,\n\t\t\t\t\t\t)\n\t\t\t\t\t\tthis.services[serviceName] = null\n\t\t\t\t\t\tpass()\n\t\t\t\t\t})\n\t\t\t\t}),\n\t\t\t)\n\t\t\tthis.dead.use(Promise.all(this.servicesDead))\n\t\t\tthis.servicesLive[this.serviceIdx[serviceName]] = new Future(() => {})\n\t\t\tif (this.live.done) {\n\t\t\t\tthis.live = new Future(() => {})\n\t\t\t}\n\t\t\tthis.live.use(Promise.all(this.servicesLive))\n\t\t} else {\n\t\t\tthis.serviceLoggers[serviceName].error(\n\t\t\t\t`Tried to stop service, but it wasn't running.`,\n\t\t\t)\n\t\t}\n\t}\n}\n\nexport const FLIGHTDECK_INFO = `info`\nexport const FLIGHTDECK_WARN = `warn`\nexport const FLIGHTDECK_ERROR = `ERR!`\n\nexport type FlightDeckLog = {\n\tlevel:\n\t\t| typeof FLIGHTDECK_ERROR\n\t\t| typeof FLIGHTDECK_INFO\n\t\t| typeof FLIGHTDECK_WARN\n\ttimestamp: number\n\tpackage: string\n\tservice?: string\n\tprocess: number\n\tbody: string\n}\n\nconst LINE_FORMAT = `line-format` satisfies keyof LnavFormat\nconst VALUE = `value` satisfies keyof LnavFormat\n\nexport type LnavFormatVisualComponent = Exclude<\n\tExclude<LnavFormat[`line-format`], undefined>[number],\n\tstring\n>\n\nexport type LnavFormatBreakdown = Exclude<LnavFormat[`value`], undefined>\nexport type MemberOf<T> = T[keyof T]\nexport type LnavFormatValueDefinition = MemberOf<LnavFormatBreakdown>\n\nexport type FlightDeckFormat = {\n\t[LINE_FORMAT]: (\n\t\t| string\n\t\t| (LnavFormatVisualComponent & {\n\t\t\t\tfield: keyof FlightDeckLog | `__level__` | `__timestamp__`\n\t\t })\n\t)[]\n\t[VALUE]: {\n\t\t[K in keyof FlightDeckLog]: LnavFormatValueDefinition & {\n\t\t\tkind: FlightDeckLog[K] extends number | undefined\n\t\t\t\t? `integer`\n\t\t\t\t: FlightDeckLog[K] extends string | undefined\n\t\t\t\t\t? `string`\n\t\t\t\t\t: never\n\t\t}\n\t}\n}\n\nexport const FLIGHTDECK_LNAV_FORMAT = {\n\ttitle: `FlightDeck Log`,\n\tdescription: `Format for events logged by the FlightDeck process manager.`,\n\t\"file-type\": `json`,\n\t\"timestamp-field\": `timestamp`,\n\t\"timestamp-divisor\": 1000,\n\t\"module-field\": `package`,\n\t\"opid-field\": `service`,\n\t\"level-field\": `level`,\n\tlevel: {\n\t\tinfo: FLIGHTDECK_INFO,\n\t\twarning: FLIGHTDECK_WARN,\n\t\terror: FLIGHTDECK_ERROR,\n\t},\n\n\t[LINE_FORMAT]: [\n\t\t{\n\t\t\tfield: `level`,\n\t\t},\n\t\t{\n\t\t\tprefix: ` `,\n\t\t\tfield: `__timestamp__`,\n\t\t\t\"timestamp-format\": `%Y-%m-%dT%H:%M:%S.%L%Z`,\n\t\t},\n\t\t{\n\t\t\tprefix: ` `,\n\t\t\tfield: `process`,\n\t\t\t\"min-width\": 5,\n\t\t},\n\t\t{\n\t\t\tprefix: `:`,\n\t\t\tfield: `package`,\n\t\t},\n\t\t{\n\t\t\tprefix: `:`,\n\t\t\tfield: `service`,\n\t\t\t\"default-value\": ``,\n\t\t},\n\t\t{\n\t\t\tprefix: `: `,\n\t\t\tfield: `body`,\n\t\t},\n\t],\n\n\t[VALUE]: {\n\t\ttimestamp: {\n\t\t\tkind: `integer`,\n\t\t},\n\t\tlevel: {\n\t\t\tkind: `string`,\n\t\t},\n\t\tpackage: {\n\t\t\tkind: `string`,\n\t\t},\n\t\tservice: {\n\t\t\tkind: `string`,\n\t\t},\n\t\tprocess: {\n\t\t\tkind: `integer`,\n\t\t},\n\t\tbody: {\n\t\t\tkind: `string`,\n\t\t},\n\t},\n} as const satisfies FlightDeckFormat & LnavFormat\n\nexport class FlightDeckLogger\n\timplements Pick<Console, `error` | `info` | `warn`>\n{\n\tpublic readonly packageName: string\n\tpublic readonly serviceName?: string\n\tpublic readonly jsonLogging: boolean\n\tpublic processCode: number\n\tpublic constructor(\n\t\tpackageName: string,\n\t\tprocessCode: number,\n\t\tserviceName?: string,\n\t\toptions?: { jsonLogging: boolean },\n\t) {\n\t\tthis.packageName = packageName\n\t\tif (serviceName) {\n\t\t\tthis.serviceName = serviceName\n\t\t}\n\t\tthis.processCode = processCode\n\t\tthis.jsonLogging = options?.jsonLogging ?? false\n\t}\n\tprotected log(\n\t\tlevel:\n\t\t\t| typeof FLIGHTDECK_ERROR\n\t\t\t| typeof FLIGHTDECK_INFO\n\t\t\t| typeof FLIGHTDECK_WARN,\n\t\t...messages: unknown[]\n\t): void {\n\t\tif (this.jsonLogging) {\n\t\t\tlet body = messages\n\t\t\t\t.map((message) =>\n\t\t\t\t\ttypeof message === `string`\n\t\t\t\t\t\t? message\n\t\t\t\t\t\t: inspect(message, false, null, true),\n\t\t\t\t)\n\t\t\t\t.join(` `)\n\t\t\tif (body.includes(`\\n`)) {\n\t\t\t\tbody = `\\n ${body.split(`\\n`).join(`\\n `)}`\n\t\t\t}\n\t\t\tconst log: FlightDeckLog = {\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t\tlevel,\n\t\t\t\tprocess: this.processCode,\n\t\t\t\tpackage: this.packageName,\n\t\t\t\tbody,\n\t\t\t}\n\t\t\tif (this.serviceName) {\n\t\t\t\tlog.service = this.serviceName\n\t\t\t}\n\t\t\tprocess.stdout.write(JSON.stringify(log) + `\\n`)\n\t\t} else {\n\t\t\tconst source = this.serviceName\n\t\t\t\t? `${this.packageName}:${this.serviceName}`\n\t\t\t\t: this.packageName\n\t\t\tswitch (level) {\n\t\t\t\tcase FLIGHTDECK_INFO:\n\t\t\t\t\tconsole.log(`${source}:`, ...messages)\n\t\t\t\t\tbreak\n\t\t\t\tcase FLIGHTDECK_WARN:\n\t\t\t\t\tconsole.warn(`${source}:`, ...messages)\n\t\t\t\t\tbreak\n\t\t\t\tcase FLIGHTDECK_ERROR:\n\t\t\t\t\tconsole.error(`${source}:`, ...messages)\n\t\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\tpublic info(...messages: unknown[]): void {\n\t\tthis.log(FLIGHTDECK_INFO, ...messages)\n\t}\n\n\tpublic warn(...messages: unknown[]): void {\n\t\tthis.log(FLIGHTDECK_WARN, ...messages)\n\t}\n\n\tpublic error(...messages: unknown[]): void {\n\t\tthis.log(FLIGHTDECK_ERROR, ...messages)\n\t}\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { c as FlightDeckLogger, s as FlightDeck } from "./flightdeck.lib-DMlmcPLR.js";
2
+ import { c as FlightDeckLogger, s as FlightDeck } from "./flightdeck.lib-DneT-dY9.js";
3
3
  import * as path from "node:path";
4
4
  import { type } from "arktype";
5
5
  import { cli, optional, options, parseBooleanOption, parseNumberOption } from "comline";
@@ -68,6 +68,23 @@ const FLIGHTDECK_MANUAL = options(`Run the FlightDeck process manager.`, type({
68
68
  parse: parseBooleanOption
69
69
  }
70
70
  });
71
+ const KILL_MANUAL = options(`Kill the FlightDeck process.`, type({
72
+ flightdeckRootDir: `string`,
73
+ packageName: `string`
74
+ }), {
75
+ flightdeckRootDir: {
76
+ flag: `d`,
77
+ required: true,
78
+ description: `Directory where the service is stored.`,
79
+ example: `--flightdeckRootDir="./services/sample/repo/my-app/current"`
80
+ },
81
+ packageName: {
82
+ flag: `n`,
83
+ required: true,
84
+ description: `Name of the package.`,
85
+ example: `--packageName="my-app"`
86
+ }
87
+ });
71
88
  const SCHEMA_MANUAL = options(`Write a json schema for the FlightDeck options.`, type({ "outdir?": `string` }), { outdir: {
72
89
  flag: `o`,
73
90
  required: false,
@@ -83,6 +100,7 @@ const { inputs, writeJsonSchema } = cli({
83
100
  routeOptions: {
84
101
  "": FLIGHTDECK_MANUAL,
85
102
  $configPath: FLIGHTDECK_MANUAL,
103
+ kill: KILL_MANUAL,
86
104
  schema: SCHEMA_MANUAL
87
105
  },
88
106
  debugOutput: true,
@@ -98,13 +116,14 @@ switch (inputs.case) {
98
116
  writeJsonSchema(outdir ?? `.`);
99
117
  }
100
118
  break;
119
+ case `kill`:
120
+ {
121
+ const { flightdeckRootDir, packageName } = inputs.opts;
122
+ await FlightDeck.kill(flightdeckRootDir, packageName);
123
+ }
124
+ break;
101
125
  case ``:
102
- case `$configPath`: {
103
- const flightDeck = new FlightDeck(inputs.opts);
104
- process.on(`close`, async () => {
105
- await flightDeck.stopAllServices();
106
- });
107
- }
126
+ case `$configPath`: new FlightDeck(inputs.opts);
108
127
  }
109
128
 
110
129
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"flightdeck.x.js","names":[],"sources":["../src/flightdeck.x.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport * as path from \"node:path\"\n\nimport { type } from \"arktype\"\nimport type { OptionsGroup } from \"comline\"\nimport {\n\tcli,\n\toptional,\n\toptions,\n\tparseBooleanOption,\n\tparseNumberOption,\n} from \"comline\"\n\nimport type { FlightDeckOptions } from \"./flightdeck.lib\"\nimport { FlightDeck, FlightDeckLogger } from \"./flightdeck.lib\"\n\nconst CLI_LOGGER = new FlightDeckLogger(`comline`, process.pid, undefined, {\n\tjsonLogging: true,\n})\nObject.assign(console, {\n\tlog: CLI_LOGGER.info.bind(CLI_LOGGER),\n\tinfo: CLI_LOGGER.info.bind(CLI_LOGGER),\n\twarn: CLI_LOGGER.warn.bind(CLI_LOGGER),\n\terror: CLI_LOGGER.error.bind(CLI_LOGGER),\n})\n\nconst FLIGHTDECK_MANUAL = options(\n\t`Run the FlightDeck process manager.`,\n\ttype({\n\t\t\"port?\": `number`,\n\t\tpackageName: `string`,\n\t\tservices: { \"[string]\": { run: `string`, waitFor: `boolean` } },\n\t\tflightdeckRootDir: `string`,\n\t\tscripts: {\n\t\t\tdownload: `string`,\n\t\t\tinstall: `string`,\n\t\t\tcheckAvailability: `string`,\n\t\t},\n\t\t\"jsonLogging?\": `boolean`,\n\t}),\n\t{\n\t\tport: {\n\t\t\tflag: `p`,\n\t\t\trequired: false,\n\t\t\tdescription: `Port to run the flightdeck server on.`,\n\t\t\texample: `--port=8080`,\n\t\t\tparse: parseNumberOption,\n\t\t},\n\t\tpackageName: {\n\t\t\tflag: `n`,\n\t\t\trequired: true,\n\t\t\tdescription: `Name of the package.`,\n\t\t\texample: `--packageName=\"my-app\"`,\n\t\t},\n\t\tservices: {\n\t\t\tflag: `s`,\n\t\t\trequired: true,\n\t\t\tdescription: `Map of service names to executables.`,\n\t\t\texample: `--services=\"{\\\\\"frontend\\\\\":{\\\\\"run\\\\\":\\\\\"./frontend\\\\\",\\\\\"waitFor\\\\\":false},\\\\\"backend\\\\\":{\\\\\"run\\\\\":\\\\\"./backend\\\\\",\\\\\"waitFor\\\\\":true}}\"`,\n\t\t\tparse: JSON.parse,\n\t\t},\n\t\tflightdeckRootDir: {\n\t\t\tflag: `d`,\n\t\t\trequired: true,\n\t\t\tdescription: `Directory where the service is stored.`,\n\t\t\texample: `--flightdeckRootDir=\"./services/sample/repo/my-app/current\"`,\n\t\t},\n\t\tscripts: {\n\t\t\tflag: `r`,\n\t\t\trequired: true,\n\t\t\tdescription: `Map of scripts to run.`,\n\t\t\texample: `--scripts=\"{\\\\\"download\\\\\":\\\\\"npm i\",\\\\\"install\\\\\":\\\\\"npm run build\\\\\"}\"`,\n\t\t\tparse: JSON.parse,\n\t\t},\n\t\tjsonLogging: {\n\t\t\tflag: `j`,\n\t\t\trequired: false,\n\t\t\tdescription: `Enable json logging.`,\n\t\t\texample: `--jsonLogging`,\n\t\t\tparse: parseBooleanOption,\n\t\t},\n\t},\n) satisfies OptionsGroup<FlightDeckOptions>\n\nconst SCHEMA_MANUAL = options(\n\t`Write a json schema for the FlightDeck options.`,\n\ttype({ \"outdir?\": `string` }),\n\t{\n\t\toutdir: {\n\t\t\tflag: `o`,\n\t\t\trequired: false,\n\t\t\tdescription: `Directory to write the schema to.`,\n\t\t\texample: `--outdir=./dist`,\n\t\t},\n\t},\n) satisfies OptionsGroup<{ outdir?: string | undefined }>\n\nconst parse = cli(\n\t{\n\t\tcliName: `flightdeck`,\n\t\troutes: optional({ schema: null, $configPath: null }),\n\t\trouteOptions: {\n\t\t\t\"\": FLIGHTDECK_MANUAL,\n\t\t\t$configPath: FLIGHTDECK_MANUAL,\n\t\t\tschema: SCHEMA_MANUAL,\n\t\t},\n\t\tdebugOutput: true,\n\t\tdiscoverConfigPath: (args) => {\n\t\t\tif (args[0] === `schema`) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst configPath =\n\t\t\t\targs[0] ?? path.join(process.cwd(), `flightdeck.config.json`)\n\t\t\treturn configPath\n\t\t},\n\t},\n\tconsole,\n)\n\nconst { inputs, writeJsonSchema } = parse(process.argv)\n\nswitch (inputs.case) {\n\tcase `schema`:\n\t\t{\n\t\t\tconst { outdir } = inputs.opts\n\t\t\twriteJsonSchema(outdir ?? `.`)\n\t\t}\n\t\tbreak\n\tcase ``:\n\tcase `$configPath`: {\n\t\tconst flightDeck = new FlightDeck(inputs.opts)\n\t\tprocess.on(`close`, async () => {\n\t\t\tawait flightDeck.stopAllServices()\n\t\t})\n\t}\n}\n"],"mappings":";;;;;;;AAiBA,MAAM,aAAa,IAAI,iBAAiB,WAAW,QAAQ,KAAK,QAAW,EAC1E,aAAa,MACb,CAAC;AACF,OAAO,OAAO,SAAS;CACtB,KAAK,WAAW,KAAK,KAAK,WAAW;CACrC,MAAM,WAAW,KAAK,KAAK,WAAW;CACtC,MAAM,WAAW,KAAK,KAAK,WAAW;CACtC,OAAO,WAAW,MAAM,KAAK,WAAW;CACxC,CAAC;AAEF,MAAM,oBAAoB,QACzB,uCACA,KAAK;CACJ,SAAS;CACT,aAAa;CACb,UAAU,EAAE,YAAY;EAAE,KAAK;EAAU,SAAS;EAAW,EAAE;CAC/D,mBAAmB;CACnB,SAAS;EACR,UAAU;EACV,SAAS;EACT,mBAAmB;EACnB;CACD,gBAAgB;CAChB,CAAC,EACF;CACC,MAAM;EACL,MAAM;EACN,UAAU;EACV,aAAa;EACb,SAAS;EACT,OAAO;EACP;CACD,aAAa;EACZ,MAAM;EACN,UAAU;EACV,aAAa;EACb,SAAS;EACT;CACD,UAAU;EACT,MAAM;EACN,UAAU;EACV,aAAa;EACb,SAAS;EACT,OAAO,KAAK;EACZ;CACD,mBAAmB;EAClB,MAAM;EACN,UAAU;EACV,aAAa;EACb,SAAS;EACT;CACD,SAAS;EACR,MAAM;EACN,UAAU;EACV,aAAa;EACb,SAAS;EACT,OAAO,KAAK;EACZ;CACD,aAAa;EACZ,MAAM;EACN,UAAU;EACV,aAAa;EACb,SAAS;EACT,OAAO;EACP;CACD,CACD;AAED,MAAM,gBAAgB,QACrB,mDACA,KAAK,EAAE,WAAW,UAAU,CAAC,EAC7B,EACC,QAAQ;CACP,MAAM;CACN,UAAU;CACV,aAAa;CACb,SAAS;CACT,EACD,CACD;AAwBD,MAAM,EAAE,QAAQ,oBAtBF,IACb;CACC,SAAS;CACT,QAAQ,SAAS;EAAE,QAAQ;EAAM,aAAa;EAAM,CAAC;CACrD,cAAc;EACb,IAAI;EACJ,aAAa;EACb,QAAQ;EACR;CACD,aAAa;CACb,qBAAqB,SAAS;AAC7B,MAAI,KAAK,OAAO,SACf;AAID,SADC,KAAK,MAAM,KAAK,KAAK,QAAQ,KAAK,EAAE,yBAAyB;;CAG/D,EACD,QACA,CAEyC,QAAQ,KAAK;AAEvD,QAAQ,OAAO,MAAf;CACC,KAAK;EACJ;GACC,MAAM,EAAE,WAAW,OAAO;AAC1B,mBAAgB,UAAU,IAAI;;AAE/B;CACD,KAAK;CACL,KAAK,eAAe;EACnB,MAAM,aAAa,IAAI,WAAW,OAAO,KAAK;AAC9C,UAAQ,GAAG,SAAS,YAAY;AAC/B,SAAM,WAAW,iBAAiB;IACjC"}
1
+ {"version":3,"file":"flightdeck.x.js","names":[],"sources":["../src/flightdeck.x.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport * as path from \"node:path\"\n\nimport { type } from \"arktype\"\nimport type { OptionsGroup } from \"comline\"\nimport {\n\tcli,\n\toptional,\n\toptions,\n\tparseBooleanOption,\n\tparseNumberOption,\n} from \"comline\"\n\nimport type { FlightDeckOptions } from \"./flightdeck.lib.ts\"\nimport { FlightDeck, FlightDeckLogger } from \"./flightdeck.lib.ts\"\n\nconst CLI_LOGGER = new FlightDeckLogger(`comline`, process.pid, undefined, {\n\tjsonLogging: true,\n})\nObject.assign(console, {\n\tlog: CLI_LOGGER.info.bind(CLI_LOGGER),\n\tinfo: CLI_LOGGER.info.bind(CLI_LOGGER),\n\twarn: CLI_LOGGER.warn.bind(CLI_LOGGER),\n\terror: CLI_LOGGER.error.bind(CLI_LOGGER),\n})\n\nconst FLIGHTDECK_MANUAL = options(\n\t`Run the FlightDeck process manager.`,\n\ttype({\n\t\t\"port?\": `number`,\n\t\tpackageName: `string`,\n\t\tservices: { \"[string]\": { run: `string`, waitFor: `boolean` } },\n\t\tflightdeckRootDir: `string`,\n\t\tscripts: {\n\t\t\tdownload: `string`,\n\t\t\tinstall: `string`,\n\t\t\tcheckAvailability: `string`,\n\t\t},\n\t\t\"jsonLogging?\": `boolean`,\n\t}),\n\t{\n\t\tport: {\n\t\t\tflag: `p`,\n\t\t\trequired: false,\n\t\t\tdescription: `Port to run the flightdeck server on.`,\n\t\t\texample: `--port=8080`,\n\t\t\tparse: parseNumberOption,\n\t\t},\n\t\tpackageName: {\n\t\t\tflag: `n`,\n\t\t\trequired: true,\n\t\t\tdescription: `Name of the package.`,\n\t\t\texample: `--packageName=\"my-app\"`,\n\t\t},\n\t\tservices: {\n\t\t\tflag: `s`,\n\t\t\trequired: true,\n\t\t\tdescription: `Map of service names to executables.`,\n\t\t\texample: `--services=\"{\\\\\"frontend\\\\\":{\\\\\"run\\\\\":\\\\\"./frontend\\\\\",\\\\\"waitFor\\\\\":false},\\\\\"backend\\\\\":{\\\\\"run\\\\\":\\\\\"./backend\\\\\",\\\\\"waitFor\\\\\":true}}\"`,\n\t\t\tparse: JSON.parse,\n\t\t},\n\t\tflightdeckRootDir: {\n\t\t\tflag: `d`,\n\t\t\trequired: true,\n\t\t\tdescription: `Directory where the service is stored.`,\n\t\t\texample: `--flightdeckRootDir=\"./services/sample/repo/my-app/current\"`,\n\t\t},\n\t\tscripts: {\n\t\t\tflag: `r`,\n\t\t\trequired: true,\n\t\t\tdescription: `Map of scripts to run.`,\n\t\t\texample: `--scripts=\"{\\\\\"download\\\\\":\\\\\"npm i\",\\\\\"install\\\\\":\\\\\"npm run build\\\\\"}\"`,\n\t\t\tparse: JSON.parse,\n\t\t},\n\t\tjsonLogging: {\n\t\t\tflag: `j`,\n\t\t\trequired: false,\n\t\t\tdescription: `Enable json logging.`,\n\t\t\texample: `--jsonLogging`,\n\t\t\tparse: parseBooleanOption,\n\t\t},\n\t},\n) satisfies OptionsGroup<FlightDeckOptions>\n\nconst KILL_MANUAL = options(\n\t`Kill the FlightDeck process.`,\n\ttype({ flightdeckRootDir: `string`, packageName: `string` }),\n\t{\n\t\tflightdeckRootDir: {\n\t\t\tflag: `d`,\n\t\t\trequired: true,\n\t\t\tdescription: `Directory where the service is stored.`,\n\t\t\texample: `--flightdeckRootDir=\"./services/sample/repo/my-app/current\"`,\n\t\t},\n\t\tpackageName: {\n\t\t\tflag: `n`,\n\t\t\trequired: true,\n\t\t\tdescription: `Name of the package.`,\n\t\t\texample: `--packageName=\"my-app\"`,\n\t\t},\n\t},\n)\n\nconst SCHEMA_MANUAL = options(\n\t`Write a json schema for the FlightDeck options.`,\n\ttype({ \"outdir?\": `string` }),\n\t{\n\t\toutdir: {\n\t\t\tflag: `o`,\n\t\t\trequired: false,\n\t\t\tdescription: `Directory to write the schema to.`,\n\t\t\texample: `--outdir=./dist`,\n\t\t},\n\t},\n) satisfies OptionsGroup<{ outdir?: string | undefined }>\n\nconst parse = cli(\n\t{\n\t\tcliName: `flightdeck`,\n\t\troutes: optional({ schema: null, $configPath: null }),\n\t\trouteOptions: {\n\t\t\t\"\": FLIGHTDECK_MANUAL,\n\t\t\t$configPath: FLIGHTDECK_MANUAL,\n\t\t\tkill: KILL_MANUAL,\n\t\t\tschema: SCHEMA_MANUAL,\n\t\t},\n\t\tdebugOutput: true,\n\t\tdiscoverConfigPath: (args) => {\n\t\t\tif (args[0] === `schema`) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst configPath =\n\t\t\t\targs[0] ?? path.join(process.cwd(), `flightdeck.config.json`)\n\t\t\treturn configPath\n\t\t},\n\t},\n\tconsole,\n)\n\nconst { inputs, writeJsonSchema } = parse(process.argv)\n\nswitch (inputs.case) {\n\tcase `schema`:\n\t\t{\n\t\t\tconst { outdir } = inputs.opts\n\t\t\twriteJsonSchema(outdir ?? `.`)\n\t\t}\n\t\tbreak\n\tcase `kill`:\n\t\t{\n\t\t\tconst { flightdeckRootDir, packageName } = inputs.opts\n\t\t\tawait FlightDeck.kill(flightdeckRootDir, packageName)\n\t\t}\n\t\tbreak\n\tcase ``:\n\tcase `$configPath`: {\n\t\tnew FlightDeck(inputs.opts)\n\t}\n}\n"],"mappings":";;;;;;;AAiBA,MAAM,aAAa,IAAI,iBAAiB,WAAW,QAAQ,KAAK,QAAW,EAC1E,aAAa,MACb,CAAC;AACF,OAAO,OAAO,SAAS;CACtB,KAAK,WAAW,KAAK,KAAK,WAAW;CACrC,MAAM,WAAW,KAAK,KAAK,WAAW;CACtC,MAAM,WAAW,KAAK,KAAK,WAAW;CACtC,OAAO,WAAW,MAAM,KAAK,WAAW;CACxC,CAAC;AAEF,MAAM,oBAAoB,QACzB,uCACA,KAAK;CACJ,SAAS;CACT,aAAa;CACb,UAAU,EAAE,YAAY;EAAE,KAAK;EAAU,SAAS;EAAW,EAAE;CAC/D,mBAAmB;CACnB,SAAS;EACR,UAAU;EACV,SAAS;EACT,mBAAmB;EACnB;CACD,gBAAgB;CAChB,CAAC,EACF;CACC,MAAM;EACL,MAAM;EACN,UAAU;EACV,aAAa;EACb,SAAS;EACT,OAAO;EACP;CACD,aAAa;EACZ,MAAM;EACN,UAAU;EACV,aAAa;EACb,SAAS;EACT;CACD,UAAU;EACT,MAAM;EACN,UAAU;EACV,aAAa;EACb,SAAS;EACT,OAAO,KAAK;EACZ;CACD,mBAAmB;EAClB,MAAM;EACN,UAAU;EACV,aAAa;EACb,SAAS;EACT;CACD,SAAS;EACR,MAAM;EACN,UAAU;EACV,aAAa;EACb,SAAS;EACT,OAAO,KAAK;EACZ;CACD,aAAa;EACZ,MAAM;EACN,UAAU;EACV,aAAa;EACb,SAAS;EACT,OAAO;EACP;CACD,CACD;AAED,MAAM,cAAc,QACnB,gCACA,KAAK;CAAE,mBAAmB;CAAU,aAAa;CAAU,CAAC,EAC5D;CACC,mBAAmB;EAClB,MAAM;EACN,UAAU;EACV,aAAa;EACb,SAAS;EACT;CACD,aAAa;EACZ,MAAM;EACN,UAAU;EACV,aAAa;EACb,SAAS;EACT;CACD,CACD;AAED,MAAM,gBAAgB,QACrB,mDACA,KAAK,EAAE,WAAW,UAAU,CAAC,EAC7B,EACC,QAAQ;CACP,MAAM;CACN,UAAU;CACV,aAAa;CACb,SAAS;CACT,EACD,CACD;AAyBD,MAAM,EAAE,QAAQ,oBAvBF,IACb;CACC,SAAS;CACT,QAAQ,SAAS;EAAE,QAAQ;EAAM,aAAa;EAAM,CAAC;CACrD,cAAc;EACb,IAAI;EACJ,aAAa;EACb,MAAM;EACN,QAAQ;EACR;CACD,aAAa;CACb,qBAAqB,SAAS;AAC7B,MAAI,KAAK,OAAO,SACf;AAID,SADC,KAAK,MAAM,KAAK,KAAK,QAAQ,KAAK,EAAE,yBAAyB;;CAG/D,EACD,QACA,CAEyC,QAAQ,KAAK;AAEvD,QAAQ,OAAO,MAAf;CACC,KAAK;EACJ;GACC,MAAM,EAAE,WAAW,OAAO;AAC1B,mBAAgB,UAAU,IAAI;;AAE/B;CACD,KAAK;EACJ;GACC,MAAM,EAAE,mBAAmB,gBAAgB,OAAO;AAClD,SAAM,WAAW,KAAK,mBAAmB,YAAY;;AAEtD;CACD,KAAK;CACL,KAAK,cACJ,KAAI,WAAW,OAAO,KAAK"}
@@ -1 +1 @@
1
- {"version":3,"file":"klaxon.x.js","names":["changesetsPublishedPackagesSchema: Type<Klaxon.ScrambleOptions>","Klaxon.scramble"],"sources":["../src/klaxon.x.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { type Type, type } from \"arktype\"\nimport { cli, options, required } from \"comline\"\n\nimport * as Klaxon from \"./klaxon.lib\"\n\nconst changesetsPublishedPackagesSchema: Type<Klaxon.ScrambleOptions> = type({\n\tpackageConfig: { \"[string]\": { endpoint: `string` } },\n\tsecretsConfig: { \"[string]\": `string` },\n\tpublishedPackages: [{ name: `string`, version: `string` }, `[]`],\n})\n\nconst klaxon = cli({\n\tcliName: `klaxon`,\n\troutes: required({\n\t\tscramble: null,\n\t}),\n\trouteOptions: {\n\t\tscramble: options(``, changesetsPublishedPackagesSchema, {\n\t\t\tpackageConfig: {\n\t\t\t\tdescription: `Maps the names of your packages to the endpoints that klaxon will POST to.`,\n\t\t\t\texample: `--packageConfig=\"{\\\\\"my-app\\\\\":{\\\\\"endpoint\\\\\":\\\\\"https://my-app.com\\\\\"}}\"`,\n\t\t\t\tflag: `c`,\n\t\t\t\tparse: JSON.parse,\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t\tsecretsConfig: {\n\t\t\t\tdescription: `Maps the names of your packages to the secrets that klaxon will use to authenticate with their respective endpoints.`,\n\t\t\t\texample: `--secretsConfig=\"{\\\\\"my-app\\\\\":\\\\\"XXXX-XXXX-XXXX\\\\\"}\"`,\n\t\t\t\tflag: `s`,\n\t\t\t\tparse: JSON.parse,\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t\tpublishedPackages: {\n\t\t\t\tdescription: `The output of the \"Publish\" step in Changesets.`,\n\t\t\t\texample: `--publishedPackages=\"[{\\\\\"name\\\\\":\\\\\"my-app\\\\\",\\\\\"version\\\\\":\\\\\"0.0.0\\\\\"}]\"`,\n\t\t\t\tflag: `p`,\n\t\t\t\tparse: JSON.parse,\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t}),\n\t},\n})\n\nconst { inputs } = klaxon(process.argv)\nawait Klaxon.scramble(inputs.opts).then((scrambleResult) => {\n\tconsole.log(scrambleResult)\n})\n"],"mappings":";;;;;;AAOA,MAAMA,oCAAkE,KAAK;CAC5E,eAAe,EAAE,YAAY,EAAE,UAAU,UAAU,EAAE;CACrD,eAAe,EAAE,YAAY,UAAU;CACvC,mBAAmB,CAAC;EAAE,MAAM;EAAU,SAAS;EAAU,EAAE,KAAK;CAChE,CAAC;AAkCF,MAAM,EAAE,WAhCO,IAAI;CAClB,SAAS;CACT,QAAQ,SAAS,EAChB,UAAU,MACV,CAAC;CACF,cAAc,EACb,UAAU,QAAQ,IAAI,mCAAmC;EACxD,eAAe;GACd,aAAa;GACb,SAAS;GACT,MAAM;GACN,OAAO,KAAK;GACZ,UAAU;GACV;EACD,eAAe;GACd,aAAa;GACb,SAAS;GACT,MAAM;GACN,OAAO,KAAK;GACZ,UAAU;GACV;EACD,mBAAmB;GAClB,aAAa;GACb,SAAS;GACT,MAAM;GACN,OAAO,KAAK;GACZ,UAAU;GACV;EACD,CAAC,EACF;CACD,CAAC,CAEwB,QAAQ,KAAK;AACvC,MAAMC,SAAgB,OAAO,KAAK,CAAC,MAAM,mBAAmB;AAC3D,SAAQ,IAAI,eAAe;EAC1B"}
1
+ {"version":3,"file":"klaxon.x.js","names":["changesetsPublishedPackagesSchema: Type<Klaxon.ScrambleOptions>","Klaxon.scramble"],"sources":["../src/klaxon.x.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { type Type, type } from \"arktype\"\nimport { cli, options, required } from \"comline\"\n\nimport * as Klaxon from \"./klaxon.lib.ts\"\n\nconst changesetsPublishedPackagesSchema: Type<Klaxon.ScrambleOptions> = type({\n\tpackageConfig: { \"[string]\": { endpoint: `string` } },\n\tsecretsConfig: { \"[string]\": `string` },\n\tpublishedPackages: [{ name: `string`, version: `string` }, `[]`],\n})\n\nconst klaxon = cli({\n\tcliName: `klaxon`,\n\troutes: required({\n\t\tscramble: null,\n\t}),\n\trouteOptions: {\n\t\tscramble: options(``, changesetsPublishedPackagesSchema, {\n\t\t\tpackageConfig: {\n\t\t\t\tdescription: `Maps the names of your packages to the endpoints that klaxon will POST to.`,\n\t\t\t\texample: `--packageConfig=\"{\\\\\"my-app\\\\\":{\\\\\"endpoint\\\\\":\\\\\"https://my-app.com\\\\\"}}\"`,\n\t\t\t\tflag: `c`,\n\t\t\t\tparse: JSON.parse,\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t\tsecretsConfig: {\n\t\t\t\tdescription: `Maps the names of your packages to the secrets that klaxon will use to authenticate with their respective endpoints.`,\n\t\t\t\texample: `--secretsConfig=\"{\\\\\"my-app\\\\\":\\\\\"XXXX-XXXX-XXXX\\\\\"}\"`,\n\t\t\t\tflag: `s`,\n\t\t\t\tparse: JSON.parse,\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t\tpublishedPackages: {\n\t\t\t\tdescription: `The output of the \"Publish\" step in Changesets.`,\n\t\t\t\texample: `--publishedPackages=\"[{\\\\\"name\\\\\":\\\\\"my-app\\\\\",\\\\\"version\\\\\":\\\\\"0.0.0\\\\\"}]\"`,\n\t\t\t\tflag: `p`,\n\t\t\t\tparse: JSON.parse,\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t}),\n\t},\n})\n\nconst { inputs } = klaxon(process.argv)\nawait Klaxon.scramble(inputs.opts).then((scrambleResult) => {\n\tconsole.log(scrambleResult)\n})\n"],"mappings":";;;;;;AAOA,MAAMA,oCAAkE,KAAK;CAC5E,eAAe,EAAE,YAAY,EAAE,UAAU,UAAU,EAAE;CACrD,eAAe,EAAE,YAAY,UAAU;CACvC,mBAAmB,CAAC;EAAE,MAAM;EAAU,SAAS;EAAU,EAAE,KAAK;CAChE,CAAC;AAkCF,MAAM,EAAE,WAhCO,IAAI;CAClB,SAAS;CACT,QAAQ,SAAS,EAChB,UAAU,MACV,CAAC;CACF,cAAc,EACb,UAAU,QAAQ,IAAI,mCAAmC;EACxD,eAAe;GACd,aAAa;GACb,SAAS;GACT,MAAM;GACN,OAAO,KAAK;GACZ,UAAU;GACV;EACD,eAAe;GACd,aAAa;GACb,SAAS;GACT,MAAM;GACN,OAAO,KAAK;GACZ,UAAU;GACV;EACD,mBAAmB;GAClB,aAAa;GACb,SAAS;GACT,MAAM;GACN,OAAO,KAAK;GACZ,UAAU;GACV;EACD,CAAC,EACF;CACD,CAAC,CAEwB,QAAQ,KAAK;AACvC,MAAMC,SAAgB,OAAO,KAAK,CAAC,MAAM,mBAAmB;AAC3D,SAAQ,IAAI,eAAe;EAC1B"}
package/dist/lib.d.ts CHANGED
@@ -790,29 +790,32 @@ type FlightDeckSetupPhase = (typeof FLIGHTDECK_SETUP_PHASES)[number];
790
790
  declare const FLIGHTDECK_UPDATE_PHASES: readonly ["notified", "confirmed"];
791
791
  type FlightDeckUpdatePhase = (typeof FLIGHTDECK_UPDATE_PHASES)[number];
792
792
  declare function isVersionNumber(version: string): boolean;
793
+ type FlightDeckSaveData = {
794
+ currentPid: `${number}`;
795
+ setupPhase: FlightDeckSetupPhase;
796
+ updatePhase: FlightDeckUpdatePhase;
797
+ updateAwaitedVersion: string;
798
+ };
793
799
  type FlightDeckOptions<S extends string = string> = {
794
- packageName: string;
795
- services: { [service in S]: {
800
+ readonly packageName: string;
801
+ readonly services: { [service in S]: {
796
802
  run: string;
797
803
  waitFor: boolean;
798
804
  } };
799
- scripts: {
800
- download: string;
801
- install: string;
802
- checkAvailability?: string;
805
+ readonly scripts: {
806
+ readonly download: string;
807
+ readonly install: string;
808
+ readonly checkAvailability?: string;
803
809
  };
804
- port?: number | undefined;
805
- flightdeckRootDir?: string | undefined;
806
- jsonLogging?: boolean | undefined;
810
+ readonly port?: number | undefined;
811
+ readonly flightdeckRootDir?: string | undefined;
812
+ readonly jsonLogging?: boolean | undefined;
807
813
  };
808
814
  declare class FlightDeck<S extends string = string> {
815
+ static kill(flightdeckRootDir: string, packageName: string): Promise<number>;
809
816
  readonly options: FlightDeckOptions<S>;
810
817
  protected safety: number;
811
- protected storage: FilesystemStorage<{
812
- setupPhase: FlightDeckSetupPhase;
813
- updatePhase: FlightDeckUpdatePhase;
814
- updateAwaitedVersion: string;
815
- }>;
818
+ protected storage: FilesystemStorage<FlightDeckSaveData>;
816
819
  protected services: { [service in S]: ChildSocket<{
817
820
  timeToStop: [];
818
821
  updatesReady: [];
@@ -982,5 +985,5 @@ declare function scramble<K$1 extends string = string>({
982
985
  publishedPackages
983
986
  }: ScrambleOptions<K$1>): Promise<ScrambleResult<K$1>>;
984
987
  //#endregion
985
- export { FLIGHTDECK_ERROR, FLIGHTDECK_INFO, FLIGHTDECK_LNAV_FORMAT, FLIGHTDECK_SETUP_PHASES, FLIGHTDECK_UPDATE_PHASES, FLIGHTDECK_WARN, FlightDeck, FlightDeckFormat, FlightDeckLog, FlightDeckLogger, FlightDeckOptions, FlightDeckSetupPhase, FlightDeckUpdatePhase, klaxon_lib_d_exports as Klaxon, LnavFormatBreakdown, LnavFormatValueDefinition, LnavFormatVisualComponent, MemberOf, isVersionNumber };
988
+ export { FLIGHTDECK_ERROR, FLIGHTDECK_INFO, FLIGHTDECK_LNAV_FORMAT, FLIGHTDECK_SETUP_PHASES, FLIGHTDECK_UPDATE_PHASES, FLIGHTDECK_WARN, FlightDeck, FlightDeckFormat, FlightDeckLog, FlightDeckLogger, FlightDeckOptions, FlightDeckSaveData, FlightDeckSetupPhase, FlightDeckUpdatePhase, klaxon_lib_d_exports as Klaxon, LnavFormatBreakdown, LnavFormatValueDefinition, LnavFormatVisualComponent, MemberOf, isVersionNumber };
986
989
  //# sourceMappingURL=lib.d.ts.map
package/dist/lib.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"lib.d.ts","names":[],"sources":["../gen/lnav-format-schema.gen.ts","../src/flightdeck.lib.ts","../src/klaxon.lib.ts"],"sourcesContent":[],"mappings":"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"}
1
+ {"version":3,"file":"lib.d.ts","names":[],"sources":["../gen/lnav-format-schema.gen.ts","../src/flightdeck.lib.ts","../src/klaxon.lib.ts"],"sourcesContent":[],"mappings":"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"}
package/dist/lib.js CHANGED
@@ -1,4 +1,4 @@
1
- import { a as FLIGHTDECK_UPDATE_PHASES, c as FlightDeckLogger, i as FLIGHTDECK_SETUP_PHASES, l as isVersionNumber, n as FLIGHTDECK_INFO, o as FLIGHTDECK_WARN, r as FLIGHTDECK_LNAV_FORMAT, s as FlightDeck, t as FLIGHTDECK_ERROR } from "./flightdeck.lib-DMlmcPLR.js";
1
+ import { a as FLIGHTDECK_UPDATE_PHASES, c as FlightDeckLogger, i as FLIGHTDECK_SETUP_PHASES, l as isVersionNumber, n as FLIGHTDECK_INFO, o as FLIGHTDECK_WARN, r as FLIGHTDECK_LNAV_FORMAT, s as FlightDeck, t as FLIGHTDECK_ERROR } from "./flightdeck.lib-DneT-dY9.js";
2
2
  import { t as klaxon_lib_exports } from "./klaxon.lib-C5FWJaIY.js";
3
3
 
4
4
  export { FLIGHTDECK_ERROR, FLIGHTDECK_INFO, FLIGHTDECK_LNAV_FORMAT, FLIGHTDECK_SETUP_PHASES, FLIGHTDECK_UPDATE_PHASES, FLIGHTDECK_WARN, FlightDeck, FlightDeckLogger, klaxon_lib_exports as Klaxon, isVersionNumber };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flightdeck",
3
- "version": "0.2.96",
3
+ "version": "0.3.0",
4
4
  "license": "MIT",
5
5
  "author": {
6
6
  "name": "Jeremy Banka",
@@ -37,17 +37,17 @@
37
37
  "devDependencies": {
38
38
  "@biomejs/js-api": "4.0.0",
39
39
  "@biomejs/wasm-nodejs": "2.3.4",
40
- "@types/bun": "npm:bun-types@1.3.1",
40
+ "@types/bun": "npm:bun-types@1.3.2",
41
41
  "@types/node": "24.10.0",
42
42
  "@types/tmp": "0.2.6",
43
- "@typescript/native-preview": "7.0.0-dev.20251106.1",
43
+ "@typescript/native-preview": "7.0.0-dev.20251108.1",
44
44
  "concurrently": "9.2.1",
45
45
  "eslint": "9.39.1",
46
46
  "json-schema-to-zod": "2.6.1",
47
47
  "rimraf": "6.1.0",
48
48
  "tmp": "0.2.5",
49
- "tsdown": "0.16.0",
50
- "vitest": "4.0.7",
49
+ "tsdown": "0.16.1",
50
+ "vitest": "4.0.8",
51
51
  "zod": "4.1.12",
52
52
  "varmint": "0.5.11"
53
53
  },
@@ -13,8 +13,8 @@ import { ChildSocket } from "atom.io/realtime-server"
13
13
  import { CronJob } from "cron"
14
14
  import { FilesystemStorage } from "safedeposit"
15
15
 
16
- import type { LnavFormat } from "../gen/lnav-format-schema.gen"
17
- import { env } from "./flightdeck.env"
16
+ import type { LnavFormat } from "../gen/lnav-format-schema.gen.ts"
17
+ import { env } from "./flightdeck.env.ts"
18
18
 
19
19
  export const FLIGHTDECK_SETUP_PHASES = [`downloaded`, `installed`] as const
20
20
 
@@ -30,28 +30,95 @@ export function isVersionNumber(version: string): boolean {
30
30
  )
31
31
  }
32
32
 
33
+ export type FlightDeckSaveData = {
34
+ currentPid: `${number}`
35
+ setupPhase: FlightDeckSetupPhase
36
+ updatePhase: FlightDeckUpdatePhase
37
+ updateAwaitedVersion: string
38
+ }
39
+
33
40
  export type FlightDeckOptions<S extends string = string> = {
34
- packageName: string
35
- services: { [service in S]: { run: string; waitFor: boolean } }
36
- scripts: {
37
- download: string
38
- install: string
39
- checkAvailability?: string
41
+ readonly packageName: string
42
+ readonly services: { [service in S]: { run: string; waitFor: boolean } }
43
+ readonly scripts: {
44
+ readonly download: string
45
+ readonly install: string
46
+ readonly checkAvailability?: string
40
47
  }
41
- port?: number | undefined
42
- flightdeckRootDir?: string | undefined
43
- jsonLogging?: boolean | undefined
48
+ readonly port?: number | undefined
49
+ readonly flightdeckRootDir?: string | undefined
50
+ readonly jsonLogging?: boolean | undefined
51
+ }
52
+
53
+ async function waitForPidExit(pid: number, timeoutMs = 5000, intervalMs = 100) {
54
+ return new Promise<void>((pass, fail) => {
55
+ const start = Date.now()
56
+
57
+ const check = () => {
58
+ process.stdout.write(`.`)
59
+ try {
60
+ // check existence
61
+ process.kill(pid, 0)
62
+ // process still alive
63
+ if (Date.now() - start > timeoutMs) {
64
+ fail(new Error(`Timeout waiting for PID ${pid}`))
65
+ return
66
+ }
67
+ setTimeout(check, intervalMs)
68
+ } catch (err) {
69
+ if (err instanceof Error && `code` in err) {
70
+ if (err.code === `ESRCH`) {
71
+ pass()
72
+ return // exited
73
+ }
74
+ if (err.code === `EPERM`) {
75
+ // process is alive but protected
76
+ if (Date.now() - start > timeoutMs) {
77
+ fail(
78
+ new Error(`Timeout waiting for PID ${pid} (EPERM; still alive)`),
79
+ )
80
+ return
81
+ }
82
+ return setTimeout(check, intervalMs)
83
+ }
84
+ }
85
+ fail(err)
86
+ return // unexpected error
87
+ }
88
+ }
89
+
90
+ check()
91
+ })
44
92
  }
45
93
 
46
94
  export class FlightDeck<S extends string = string> {
95
+ public static async kill(
96
+ flightdeckRootDir: string,
97
+ packageName: string,
98
+ ): Promise<number> {
99
+ console.info(`Killing FlightDeck instance of "${packageName}"`)
100
+ const storage = new FilesystemStorage<FlightDeckSaveData>({
101
+ path: resolve(flightdeckRootDir, `storage`, packageName),
102
+ })
103
+ const currentPid = storage.getItem(`currentPid`)
104
+ if (currentPid === null) {
105
+ throw new Error(`No pid for "${packageName}" found in storage`)
106
+ }
107
+ const pid = Number(currentPid)
108
+ const now = Date.now()
109
+ process.kill(pid, `SIGTERM`)
110
+ await waitForPidExit(pid, 5000, 5)
111
+ const elapsed = Date.now() - now
112
+ process.stdout.write(
113
+ `🌜 "${packageName}" (running as process ${pid}) exited in ${elapsed}ms\n`,
114
+ )
115
+ return pid
116
+ }
117
+
47
118
  public readonly options: FlightDeckOptions<S>
48
119
  protected safety = 0
49
120
 
50
- protected storage: FilesystemStorage<{
51
- setupPhase: FlightDeckSetupPhase
52
- updatePhase: FlightDeckUpdatePhase
53
- updateAwaitedVersion: string
54
- }>
121
+ protected storage: FilesystemStorage<FlightDeckSaveData>
55
122
  protected services: {
56
123
  [service in S]: ChildSocket<
57
124
  { timeToStop: []; updatesReady: [] },
@@ -128,6 +195,8 @@ export class FlightDeck<S extends string = string> {
128
195
  path: resolve(flightdeckRootDir, `storage`, options.packageName),
129
196
  })
130
197
 
198
+ this.storage.setItem(`currentPid`, `${process.pid}`)
199
+
131
200
  if (FLIGHTDECK_SECRET === undefined) {
132
201
  this.logger.warn(
133
202
  `No FLIGHTDECK_SECRET environment variable found. FlightDeck will not run an update server.`,
@@ -205,6 +274,13 @@ export class FlightDeck<S extends string = string> {
205
274
  this.logger.error(`Failed to start all services:`, thrown.message)
206
275
  }
207
276
  })
277
+
278
+ process.on(`SIGTERM`, async () => {
279
+ console.info(`Killed by SIGTERM`)
280
+ await this.stopAllServices()
281
+ this.storage.removeItem(`currentPid`)
282
+ process.exit(0)
283
+ })
208
284
  }
209
285
 
210
286
  protected async seekUpdate(version: string): Promise<void> {
@@ -338,7 +414,7 @@ export class FlightDeck<S extends string = string> {
338
414
  )
339
415
  this.services[serviceName] = null
340
416
  if (!this.autoRespawnDeadServices) {
341
- this.logger.info(`Auto-respawn is off; "${serviceName}" rests.`)
417
+ this.logger.info(`😴 Auto-respawn is off; "${serviceName}" rests.`)
342
418
  return
343
419
  }
344
420
  const updatePhase = this.storage.getItem(`updatePhase`)
@@ -12,8 +12,8 @@ import {
12
12
  parseNumberOption,
13
13
  } from "comline"
14
14
 
15
- import type { FlightDeckOptions } from "./flightdeck.lib"
16
- import { FlightDeck, FlightDeckLogger } from "./flightdeck.lib"
15
+ import type { FlightDeckOptions } from "./flightdeck.lib.ts"
16
+ import { FlightDeck, FlightDeckLogger } from "./flightdeck.lib.ts"
17
17
 
18
18
  const CLI_LOGGER = new FlightDeckLogger(`comline`, process.pid, undefined, {
19
19
  jsonLogging: true,
@@ -83,6 +83,25 @@ const FLIGHTDECK_MANUAL = options(
83
83
  },
84
84
  ) satisfies OptionsGroup<FlightDeckOptions>
85
85
 
86
+ const KILL_MANUAL = options(
87
+ `Kill the FlightDeck process.`,
88
+ type({ flightdeckRootDir: `string`, packageName: `string` }),
89
+ {
90
+ flightdeckRootDir: {
91
+ flag: `d`,
92
+ required: true,
93
+ description: `Directory where the service is stored.`,
94
+ example: `--flightdeckRootDir="./services/sample/repo/my-app/current"`,
95
+ },
96
+ packageName: {
97
+ flag: `n`,
98
+ required: true,
99
+ description: `Name of the package.`,
100
+ example: `--packageName="my-app"`,
101
+ },
102
+ },
103
+ )
104
+
86
105
  const SCHEMA_MANUAL = options(
87
106
  `Write a json schema for the FlightDeck options.`,
88
107
  type({ "outdir?": `string` }),
@@ -103,6 +122,7 @@ const parse = cli(
103
122
  routeOptions: {
104
123
  "": FLIGHTDECK_MANUAL,
105
124
  $configPath: FLIGHTDECK_MANUAL,
125
+ kill: KILL_MANUAL,
106
126
  schema: SCHEMA_MANUAL,
107
127
  },
108
128
  debugOutput: true,
@@ -127,11 +147,14 @@ switch (inputs.case) {
127
147
  writeJsonSchema(outdir ?? `.`)
128
148
  }
129
149
  break
150
+ case `kill`:
151
+ {
152
+ const { flightdeckRootDir, packageName } = inputs.opts
153
+ await FlightDeck.kill(flightdeckRootDir, packageName)
154
+ }
155
+ break
130
156
  case ``:
131
157
  case `$configPath`: {
132
- const flightDeck = new FlightDeck(inputs.opts)
133
- process.on(`close`, async () => {
134
- await flightDeck.stopAllServices()
135
- })
158
+ new FlightDeck(inputs.opts)
136
159
  }
137
160
  }
package/src/klaxon.x.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  import { type Type, type } from "arktype"
4
4
  import { cli, options, required } from "comline"
5
5
 
6
- import * as Klaxon from "./klaxon.lib"
6
+ import * as Klaxon from "./klaxon.lib.ts"
7
7
 
8
8
  const changesetsPublishedPackagesSchema: Type<Klaxon.ScrambleOptions> = type({
9
9
  packageConfig: { "[string]": { endpoint: `string` } },
package/src/lib.ts CHANGED
@@ -1,4 +1,4 @@
1
- export * from "./flightdeck.lib"
2
- import * as Klaxon from "./klaxon.lib"
1
+ export * from "./flightdeck.lib.ts"
2
+ import * as Klaxon from "./klaxon.lib.ts"
3
3
 
4
4
  export { Klaxon }
@@ -1 +0,0 @@
1
- {"version":3,"file":"flightdeck.lib-DMlmcPLR.js","names":["data: Uint8Array[]","log: FlightDeckLog"],"sources":["../src/flightdeck.env.ts","../src/flightdeck.lib.ts"],"sourcesContent":["import { createEnv } from \"@t3-oss/env-core\"\nimport { type } from \"arktype\"\n\nexport const env = createEnv({\n\tserver: { FLIGHTDECK_SECRET: type(`string`, `|`, `undefined`) },\n\tclientPrefix: `NEVER`,\n\tclient: {},\n\truntimeEnv: import.meta.env as Record<string, string>,\n\temptyStringAsUndefined: true,\n})\n","/* eslint-disable @typescript-eslint/only-throw-error */\nimport type { ChildProcessWithoutNullStreams } from \"node:child_process\"\nimport { execSync, spawn } from \"node:child_process\"\nimport { createServer } from \"node:http\"\nimport { homedir } from \"node:os\"\nimport { resolve } from \"node:path\"\nimport { inspect } from \"node:util\"\n\nimport { Future } from \"atom.io/internal\"\nimport { discoverType } from \"atom.io/introspection\"\nimport { fromEntries, toEntries } from \"atom.io/json\"\nimport { ChildSocket } from \"atom.io/realtime-server\"\nimport { CronJob } from \"cron\"\nimport { FilesystemStorage } from \"safedeposit\"\n\nimport type { LnavFormat } from \"../gen/lnav-format-schema.gen\"\nimport { env } from \"./flightdeck.env\"\n\nexport const FLIGHTDECK_SETUP_PHASES = [`downloaded`, `installed`] as const\n\nexport type FlightDeckSetupPhase = (typeof FLIGHTDECK_SETUP_PHASES)[number]\n\nexport const FLIGHTDECK_UPDATE_PHASES = [`notified`, `confirmed`] as const\n\nexport type FlightDeckUpdatePhase = (typeof FLIGHTDECK_UPDATE_PHASES)[number]\n\nexport function isVersionNumber(version: string): boolean {\n\treturn (\n\t\t/^\\d+\\.\\d+\\.\\d+$/.test(version) || !Number.isNaN(Number.parseFloat(version))\n\t)\n}\n\nexport type FlightDeckOptions<S extends string = string> = {\n\tpackageName: string\n\tservices: { [service in S]: { run: string; waitFor: boolean } }\n\tscripts: {\n\t\tdownload: string\n\t\tinstall: string\n\t\tcheckAvailability?: string\n\t}\n\tport?: number | undefined\n\tflightdeckRootDir?: string | undefined\n\tjsonLogging?: boolean | undefined\n}\n\nexport class FlightDeck<S extends string = string> {\n\tpublic readonly options: FlightDeckOptions<S>\n\tprotected safety = 0\n\n\tprotected storage: FilesystemStorage<{\n\t\tsetupPhase: FlightDeckSetupPhase\n\t\tupdatePhase: FlightDeckUpdatePhase\n\t\tupdateAwaitedVersion: string\n\t}>\n\tprotected services: {\n\t\t[service in S]: ChildSocket<\n\t\t\t{ timeToStop: []; updatesReady: [] },\n\t\t\t{ readyToUpdate: []; alive: [] },\n\t\t\tChildProcessWithoutNullStreams\n\t\t> | null\n\t}\n\tprotected serviceIdx: { readonly [service in S]: number }\n\tpublic defaultServicesReadyToUpdate: { readonly [service in S]: boolean }\n\tpublic servicesReadyToUpdate: { [service in S]: boolean }\n\tpublic autoRespawnDeadServices: boolean\n\n\tprotected logger: Pick<Console, `error` | `info` | `warn`>\n\tprotected serviceLoggers: {\n\t\treadonly [service in S]: FlightDeckLogger\n\t}\n\n\tprotected updateAvailabilityChecker: CronJob | null = null\n\n\tpublic servicesLive: Future<void>[]\n\tpublic servicesDead: Future<void>[]\n\tpublic live = new Future(() => {})\n\tpublic dead = new Future(() => {})\n\n\tprotected restartTimes: number[] = []\n\n\tpublic constructor(options: FlightDeckOptions<S>) {\n\t\tthis.options = options\n\t\tconst { FLIGHTDECK_SECRET } = env\n\t\tconst { flightdeckRootDir = resolve(homedir(), `.flightdeck`) } = options\n\t\tconst port = options.port ?? 8080\n\t\tconst origin = `http://localhost:${port}`\n\n\t\tconst servicesEntries = toEntries(options.services)\n\t\tthis.services = fromEntries(\n\t\t\tservicesEntries.map(([serviceName]) => [serviceName, null]),\n\t\t)\n\t\tthis.serviceIdx = fromEntries(\n\t\t\tservicesEntries.map(([serviceName], idx) => [serviceName, idx]),\n\t\t)\n\t\tthis.defaultServicesReadyToUpdate = fromEntries(\n\t\t\tservicesEntries.map(([serviceName, { waitFor }]) => [\n\t\t\t\tserviceName,\n\t\t\t\t!waitFor,\n\t\t\t]),\n\t\t)\n\t\tthis.servicesReadyToUpdate = { ...this.defaultServicesReadyToUpdate }\n\t\tthis.autoRespawnDeadServices = true\n\n\t\tthis.logger = new FlightDeckLogger(\n\t\t\tthis.options.packageName,\n\t\t\tprocess.pid,\n\t\t\tundefined,\n\t\t\t{ jsonLogging: this.options.jsonLogging ?? false },\n\t\t)\n\t\tthis.serviceLoggers = fromEntries(\n\t\t\tservicesEntries.map(([serviceName]) => [\n\t\t\t\tserviceName,\n\t\t\t\tnew FlightDeckLogger(\n\t\t\t\t\tthis.options.packageName,\n\t\t\t\t\tprocess.pid,\n\t\t\t\t\tserviceName,\n\t\t\t\t\t{ jsonLogging: this.options.jsonLogging ?? false },\n\t\t\t\t),\n\t\t\t]),\n\t\t)\n\n\t\tthis.servicesLive = servicesEntries.map(() => new Future(() => {}))\n\t\tthis.servicesDead = servicesEntries.map(() => new Future(() => {}))\n\t\tthis.live.use(Promise.all(this.servicesLive))\n\t\tthis.dead.use(Promise.all(this.servicesDead))\n\n\t\tthis.storage = new FilesystemStorage({\n\t\t\tpath: resolve(flightdeckRootDir, `storage`, options.packageName),\n\t\t})\n\n\t\tif (FLIGHTDECK_SECRET === undefined) {\n\t\t\tthis.logger.warn(\n\t\t\t\t`No FLIGHTDECK_SECRET environment variable found. FlightDeck will not run an update server.`,\n\t\t\t)\n\t\t} else {\n\t\t\tcreateServer((req, res) => {\n\t\t\t\tlet data: Uint8Array[] = []\n\t\t\t\treq\n\t\t\t\t\t.on(`data`, (chunk) => {\n\t\t\t\t\t\tdata.push(chunk instanceof Buffer ? chunk : Buffer.from(chunk))\n\t\t\t\t\t})\n\t\t\t\t\t.on(`end`, async () => {\n\t\t\t\t\t\tconst authHeader = req.headers.authorization\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tif (typeof req.url === `undefined`) throw 400\n\t\t\t\t\t\t\tconst expectedAuthHeader = `Bearer ${FLIGHTDECK_SECRET}`\n\t\t\t\t\t\t\tif (authHeader !== `Bearer ${FLIGHTDECK_SECRET}`) {\n\t\t\t\t\t\t\t\tthis.logger.info(\n\t\t\t\t\t\t\t\t\t`Unauthorized: needed \\`${expectedAuthHeader}\\`, got \\`${authHeader}\\``,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\tthrow 401\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst url = new URL(req.url, origin)\n\t\t\t\t\t\t\tthis.logger.info(req.method, url.pathname)\n\n\t\t\t\t\t\t\tconst versionForeignInput = Buffer.concat(data).toString()\n\t\t\t\t\t\t\tif (!isVersionNumber(versionForeignInput)) {\n\t\t\t\t\t\t\t\tthrow 400\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tres.writeHead(200)\n\t\t\t\t\t\t\tres.end()\n\n\t\t\t\t\t\t\tthis.storage.setItem(`updatePhase`, `notified`)\n\t\t\t\t\t\t\tthis.storage.setItem(`updateAwaitedVersion`, versionForeignInput)\n\t\t\t\t\t\t\tconst { checkAvailability } = options.scripts\n\t\t\t\t\t\t\tif (checkAvailability) {\n\t\t\t\t\t\t\t\tawait this.updateAvailabilityChecker?.stop()\n\t\t\t\t\t\t\t\tawait this.seekUpdate(versionForeignInput)\n\t\t\t\t\t\t\t\tconst updatePhase = this.storage.getItem(`updatePhase`)\n\t\t\t\t\t\t\t\tthis.logger.info(`> storage(\"updatePhase\") >`, updatePhase)\n\t\t\t\t\t\t\t\tif (updatePhase === `notified`) {\n\t\t\t\t\t\t\t\t\tthis.updateAvailabilityChecker = new CronJob(\n\t\t\t\t\t\t\t\t\t\t`*/30 * * * * *`,\n\t\t\t\t\t\t\t\t\t\tasync () => {\n\t\t\t\t\t\t\t\t\t\t\tawait this.seekUpdate(versionForeignInput)\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\tthis.updateAvailabilityChecker.start()\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthis.downloadPackage()\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch (thrown) {\n\t\t\t\t\t\t\tthis.logger.error(thrown, req.url)\n\t\t\t\t\t\t\tif (typeof thrown === `number`) {\n\t\t\t\t\t\t\t\tres.writeHead(thrown)\n\t\t\t\t\t\t\t\tres.end()\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} finally {\n\t\t\t\t\t\t\tdata = []\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t}).listen(port, () => {\n\t\t\t\tthis.logger.info(`Server started on port ${port}`)\n\t\t\t})\n\t\t}\n\n\t\tthis.startAllServices()\n\t\t\t.then(() => {\n\t\t\t\tthis.logger.info(`All services started.`)\n\t\t\t})\n\t\t\t.catch((thrown) => {\n\t\t\t\tif (thrown instanceof Error) {\n\t\t\t\t\tthis.logger.error(`Failed to start all services:`, thrown.message)\n\t\t\t\t}\n\t\t\t})\n\t}\n\n\tprotected async seekUpdate(version: string): Promise<void> {\n\t\tthis.logger.info(`Checking for updates...`)\n\t\tconst { checkAvailability } = this.options.scripts\n\t\tif (!checkAvailability) {\n\t\t\tthis.logger.info(`No checkAvailability script found.`)\n\t\t\treturn\n\t\t}\n\t\ttry {\n\t\t\tconst out = execSync(`${checkAvailability} ${version}`)\n\t\t\tthis.logger.info(`Check stdout:`, out.toString())\n\t\t\tawait this.updateAvailabilityChecker?.stop()\n\t\t\tthis.storage.setItem(`updatePhase`, `confirmed`)\n\t\t\tthis.downloadPackage()\n\t\t\tthis.announceUpdate()\n\t\t} catch (thrown) {\n\t\t\tif (thrown instanceof Error) {\n\t\t\t\tthis.logger.error(`Check failed:`, thrown.message)\n\t\t\t} else {\n\t\t\t\tconst thrownType = discoverType(thrown)\n\t\t\t\tthis.logger.error(`Check threw`, thrownType, thrown)\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected announceUpdate(): void {\n\t\tfor (const entry of toEntries(this.services)) {\n\t\t\tconst [serviceName, service] = entry\n\t\t\tif (service) {\n\t\t\t\tif (this.options.services[serviceName].waitFor) {\n\t\t\t\t\tservice.emit(`updatesReady`)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.startService(serviceName)\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected tryUpdate(): void {\n\t\tif (toEntries(this.servicesReadyToUpdate).every(([, isReady]) => isReady)) {\n\t\t\tthis.logger.info(`All services are ready to update.`)\n\t\t\tthis.stopAllServices()\n\t\t\t\t.then(() => {\n\t\t\t\t\tthis.logger.info(`All services stopped; starting up fresh...`)\n\t\t\t\t\tthis.startAllServices()\n\t\t\t\t\t\t.then(() => {\n\t\t\t\t\t\t\tthis.logger.info(`All services started; we're back online.`)\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.catch((thrown) => {\n\t\t\t\t\t\t\tif (thrown instanceof Error) {\n\t\t\t\t\t\t\t\tthis.logger.error(\n\t\t\t\t\t\t\t\t\t`Failed to start all services:`,\n\t\t\t\t\t\t\t\t\tthrown.message,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t})\n\t\t\t\t})\n\t\t\t\t.catch((thrown) => {\n\t\t\t\t\tif (thrown instanceof Error) {\n\t\t\t\t\t\tthis.logger.error(`Failed to stop all services:`, thrown.message)\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t}\n\t}\n\n\tprotected startAllServices(): Future<unknown> {\n\t\tthis.logger.info(`Starting all services...`)\n\t\tthis.autoRespawnDeadServices = true\n\t\tconst setupPhase = this.storage.getItem(`setupPhase`)\n\t\tthis.logger.info(`> storage(\"setupPhase\") >`, setupPhase)\n\t\tswitch (setupPhase) {\n\t\t\tcase null:\n\t\t\t\tthis.logger.info(`Starting from scratch.`)\n\t\t\t\tthis.downloadPackage()\n\t\t\t\tthis.installPackage()\n\t\t\t\treturn this.startAllServices()\n\t\t\tcase `downloaded`:\n\t\t\t\tthis.logger.info(`Found package downloaded but not installed.`)\n\t\t\t\tthis.installPackage()\n\t\t\t\treturn this.startAllServices()\n\t\t\tcase `installed`: {\n\t\t\t\tfor (const [serviceName] of toEntries(this.services)) {\n\t\t\t\t\tthis.startService(serviceName)\n\t\t\t\t}\n\t\t\t\treturn this.live\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected startService(serviceName: S): void {\n\t\tthis.logger.info(\n\t\t\t`Starting service ${this.options.packageName}::${serviceName}, try ${this.safety}/2...`,\n\t\t)\n\t\tif (this.safety >= 2) {\n\t\t\tthrow new Error(`Out of tries...`)\n\t\t}\n\t\tthis.safety++\n\n\t\tconst [exe, ...args] = this.options.services[serviceName].run.split(` `)\n\t\tconst serviceProcess = spawn(exe, args, {\n\t\t\tcwd: this.options.flightdeckRootDir,\n\t\t\tenv: import.meta.env as Record<string, string>,\n\t\t})\n\t\tconst serviceLogger = this.serviceLoggers[serviceName]\n\t\tconst service = (this.services[serviceName] = new ChildSocket(\n\t\t\tserviceProcess,\n\t\t\t`${this.options.packageName}::${serviceName}`,\n\t\t\tserviceLogger,\n\t\t))\n\t\tserviceLogger.processCode = service.proc.pid ?? -1\n\t\tthis.services[serviceName].onAny((...messages) => {\n\t\t\tserviceLogger.info(`💬`, ...messages)\n\t\t})\n\t\tthis.services[serviceName].on(`readyToUpdate`, () => {\n\t\t\tthis.logger.info(`Service \"${serviceName}\" is ready to update.`)\n\t\t\tthis.servicesReadyToUpdate[serviceName] = true\n\t\t\tthis.tryUpdate()\n\t\t})\n\t\tthis.services[serviceName].on(`alive`, () => {\n\t\t\tthis.servicesLive[this.serviceIdx[serviceName]].use(Promise.resolve())\n\t\t\tthis.servicesDead[this.serviceIdx[serviceName]] = new Future(() => {})\n\t\t\tif (this.dead.done) {\n\t\t\t\tthis.dead = new Future(() => {})\n\t\t\t}\n\t\t\tthis.dead.use(Promise.all(this.servicesDead))\n\t\t})\n\t\tthis.services[serviceName].proc.once(`close`, (exitCode) => {\n\t\t\tthis.logger.info(\n\t\t\t\t`Auto-respawn saw \"${serviceName}\" exit with code ${exitCode}`,\n\t\t\t)\n\t\t\tthis.services[serviceName] = null\n\t\t\tif (!this.autoRespawnDeadServices) {\n\t\t\t\tthis.logger.info(`Auto-respawn is off; \"${serviceName}\" rests.`)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst updatePhase = this.storage.getItem(`updatePhase`)\n\t\t\tthis.logger.info(`> storage(\"updatePhase\") >`, updatePhase)\n\t\t\tconst updatesAreReady = updatePhase === `confirmed`\n\t\t\tif (updatesAreReady) {\n\t\t\t\tthis.serviceLoggers[serviceName].info(`Updating before startup...`)\n\t\t\t\tthis.restartTimes = []\n\t\t\t\tthis.installPackage()\n\t\t\t\tthis.startService(serviceName)\n\t\t\t} else {\n\t\t\t\tconst now = Date.now()\n\t\t\t\tconst fiveMinutesAgo = now - 5 * 60 * 1000\n\t\t\t\tthis.restartTimes = this.restartTimes.filter(\n\t\t\t\t\t(time) => time > fiveMinutesAgo,\n\t\t\t\t)\n\t\t\t\tthis.restartTimes.push(now)\n\n\t\t\t\tif (this.restartTimes.length < 5) {\n\t\t\t\t\tthis.serviceLoggers[serviceName].info(`Crashed. Restarting...`)\n\t\t\t\t\tthis.startService(serviceName)\n\t\t\t\t} else {\n\t\t\t\t\tthis.serviceLoggers[serviceName].info(\n\t\t\t\t\t\t`Crashed 5 times in 5 minutes. Not restarting.`,\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t\tthis.safety = 0\n\t}\n\n\tprotected downloadPackage(): void {\n\t\tthis.logger.info(`Downloading...`)\n\t\ttry {\n\t\t\tconst out = execSync(this.options.scripts.download)\n\t\t\tthis.logger.info(`Download stdout:`, out.toString())\n\t\t\tthis.storage.setItem(`setupPhase`, `downloaded`)\n\t\t\tthis.logger.info(`Downloaded!`)\n\t\t} catch (thrown) {\n\t\t\tif (thrown instanceof Error) {\n\t\t\t\tthis.logger.error(`Failed to get the latest release: ${thrown.message}`)\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t}\n\n\tprotected installPackage(): void {\n\t\tthis.logger.info(`Installing...`)\n\n\t\ttry {\n\t\t\tconst out = execSync(this.options.scripts.install)\n\t\t\tthis.logger.info(`Install stdout:`, out.toString())\n\t\t\tthis.storage.setItem(`setupPhase`, `installed`)\n\t\t\tthis.logger.info(`Installed!`)\n\t\t} catch (thrown) {\n\t\t\tif (thrown instanceof Error) {\n\t\t\t\tthis.logger.error(`Failed to get the latest release: ${thrown.message}`)\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t}\n\n\tpublic stopAllServices(): Future<unknown> {\n\t\tthis.logger.info(`Stopping all services... auto-respawn disabled.`)\n\t\tthis.autoRespawnDeadServices = false\n\t\tfor (const [serviceName] of toEntries(this.services)) {\n\t\t\tthis.stopService(serviceName)\n\t\t}\n\t\treturn this.dead\n\t}\n\n\tpublic stopService(serviceName: S): void {\n\t\tconst service = this.services[serviceName]\n\t\tif (service) {\n\t\t\tthis.logger.info(`Stopping service \"${serviceName}\"...`)\n\t\t\tthis.servicesDead[this.serviceIdx[serviceName]].use(\n\t\t\t\tnew Promise((pass) => {\n\t\t\t\t\tservice.emit(`timeToStop`)\n\t\t\t\t\tservice.proc.once(`close`, (exitCode) => {\n\t\t\t\t\t\tthis.logger.info(\n\t\t\t\t\t\t\t`Stopped service \"${serviceName}\"; exited with code ${exitCode}`,\n\t\t\t\t\t\t)\n\t\t\t\t\t\tthis.services[serviceName] = null\n\t\t\t\t\t\tpass()\n\t\t\t\t\t})\n\t\t\t\t}),\n\t\t\t)\n\t\t\tthis.dead.use(Promise.all(this.servicesDead))\n\t\t\tthis.servicesLive[this.serviceIdx[serviceName]] = new Future(() => {})\n\t\t\tif (this.live.done) {\n\t\t\t\tthis.live = new Future(() => {})\n\t\t\t}\n\t\t\tthis.live.use(Promise.all(this.servicesLive))\n\t\t} else {\n\t\t\tthis.serviceLoggers[serviceName].error(\n\t\t\t\t`Tried to stop service, but it wasn't running.`,\n\t\t\t)\n\t\t}\n\t}\n}\n\nexport const FLIGHTDECK_INFO = `info`\nexport const FLIGHTDECK_WARN = `warn`\nexport const FLIGHTDECK_ERROR = `ERR!`\n\nexport type FlightDeckLog = {\n\tlevel:\n\t\t| typeof FLIGHTDECK_ERROR\n\t\t| typeof FLIGHTDECK_INFO\n\t\t| typeof FLIGHTDECK_WARN\n\ttimestamp: number\n\tpackage: string\n\tservice?: string\n\tprocess: number\n\tbody: string\n}\n\nconst LINE_FORMAT = `line-format` satisfies keyof LnavFormat\nconst VALUE = `value` satisfies keyof LnavFormat\n\nexport type LnavFormatVisualComponent = Exclude<\n\tExclude<LnavFormat[`line-format`], undefined>[number],\n\tstring\n>\n\nexport type LnavFormatBreakdown = Exclude<LnavFormat[`value`], undefined>\nexport type MemberOf<T> = T[keyof T]\nexport type LnavFormatValueDefinition = MemberOf<LnavFormatBreakdown>\n\nexport type FlightDeckFormat = {\n\t[LINE_FORMAT]: (\n\t\t| string\n\t\t| (LnavFormatVisualComponent & {\n\t\t\t\tfield: keyof FlightDeckLog | `__level__` | `__timestamp__`\n\t\t })\n\t)[]\n\t[VALUE]: {\n\t\t[K in keyof FlightDeckLog]: LnavFormatValueDefinition & {\n\t\t\tkind: FlightDeckLog[K] extends number | undefined\n\t\t\t\t? `integer`\n\t\t\t\t: FlightDeckLog[K] extends string | undefined\n\t\t\t\t\t? `string`\n\t\t\t\t\t: never\n\t\t}\n\t}\n}\n\nexport const FLIGHTDECK_LNAV_FORMAT = {\n\ttitle: `FlightDeck Log`,\n\tdescription: `Format for events logged by the FlightDeck process manager.`,\n\t\"file-type\": `json`,\n\t\"timestamp-field\": `timestamp`,\n\t\"timestamp-divisor\": 1000,\n\t\"module-field\": `package`,\n\t\"opid-field\": `service`,\n\t\"level-field\": `level`,\n\tlevel: {\n\t\tinfo: FLIGHTDECK_INFO,\n\t\twarning: FLIGHTDECK_WARN,\n\t\terror: FLIGHTDECK_ERROR,\n\t},\n\n\t[LINE_FORMAT]: [\n\t\t{\n\t\t\tfield: `level`,\n\t\t},\n\t\t{\n\t\t\tprefix: ` `,\n\t\t\tfield: `__timestamp__`,\n\t\t\t\"timestamp-format\": `%Y-%m-%dT%H:%M:%S.%L%Z`,\n\t\t},\n\t\t{\n\t\t\tprefix: ` `,\n\t\t\tfield: `process`,\n\t\t\t\"min-width\": 5,\n\t\t},\n\t\t{\n\t\t\tprefix: `:`,\n\t\t\tfield: `package`,\n\t\t},\n\t\t{\n\t\t\tprefix: `:`,\n\t\t\tfield: `service`,\n\t\t\t\"default-value\": ``,\n\t\t},\n\t\t{\n\t\t\tprefix: `: `,\n\t\t\tfield: `body`,\n\t\t},\n\t],\n\n\t[VALUE]: {\n\t\ttimestamp: {\n\t\t\tkind: `integer`,\n\t\t},\n\t\tlevel: {\n\t\t\tkind: `string`,\n\t\t},\n\t\tpackage: {\n\t\t\tkind: `string`,\n\t\t},\n\t\tservice: {\n\t\t\tkind: `string`,\n\t\t},\n\t\tprocess: {\n\t\t\tkind: `integer`,\n\t\t},\n\t\tbody: {\n\t\t\tkind: `string`,\n\t\t},\n\t},\n} as const satisfies FlightDeckFormat & LnavFormat\n\nexport class FlightDeckLogger\n\timplements Pick<Console, `error` | `info` | `warn`>\n{\n\tpublic readonly packageName: string\n\tpublic readonly serviceName?: string\n\tpublic readonly jsonLogging: boolean\n\tpublic processCode: number\n\tpublic constructor(\n\t\tpackageName: string,\n\t\tprocessCode: number,\n\t\tserviceName?: string,\n\t\toptions?: { jsonLogging: boolean },\n\t) {\n\t\tthis.packageName = packageName\n\t\tif (serviceName) {\n\t\t\tthis.serviceName = serviceName\n\t\t}\n\t\tthis.processCode = processCode\n\t\tthis.jsonLogging = options?.jsonLogging ?? false\n\t}\n\tprotected log(\n\t\tlevel:\n\t\t\t| typeof FLIGHTDECK_ERROR\n\t\t\t| typeof FLIGHTDECK_INFO\n\t\t\t| typeof FLIGHTDECK_WARN,\n\t\t...messages: unknown[]\n\t): void {\n\t\tif (this.jsonLogging) {\n\t\t\tlet body = messages\n\t\t\t\t.map((message) =>\n\t\t\t\t\ttypeof message === `string`\n\t\t\t\t\t\t? message\n\t\t\t\t\t\t: inspect(message, false, null, true),\n\t\t\t\t)\n\t\t\t\t.join(` `)\n\t\t\tif (body.includes(`\\n`)) {\n\t\t\t\tbody = `\\n ${body.split(`\\n`).join(`\\n `)}`\n\t\t\t}\n\t\t\tconst log: FlightDeckLog = {\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t\tlevel,\n\t\t\t\tprocess: this.processCode,\n\t\t\t\tpackage: this.packageName,\n\t\t\t\tbody,\n\t\t\t}\n\t\t\tif (this.serviceName) {\n\t\t\t\tlog.service = this.serviceName\n\t\t\t}\n\t\t\tprocess.stdout.write(JSON.stringify(log) + `\\n`)\n\t\t} else {\n\t\t\tconst source = this.serviceName\n\t\t\t\t? `${this.packageName}:${this.serviceName}`\n\t\t\t\t: this.packageName\n\t\t\tswitch (level) {\n\t\t\t\tcase FLIGHTDECK_INFO:\n\t\t\t\t\tconsole.log(`${source}:`, ...messages)\n\t\t\t\t\tbreak\n\t\t\t\tcase FLIGHTDECK_WARN:\n\t\t\t\t\tconsole.warn(`${source}:`, ...messages)\n\t\t\t\t\tbreak\n\t\t\t\tcase FLIGHTDECK_ERROR:\n\t\t\t\t\tconsole.error(`${source}:`, ...messages)\n\t\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\tpublic info(...messages: unknown[]): void {\n\t\tthis.log(FLIGHTDECK_INFO, ...messages)\n\t}\n\n\tpublic warn(...messages: unknown[]): void {\n\t\tthis.log(FLIGHTDECK_WARN, ...messages)\n\t}\n\n\tpublic error(...messages: unknown[]): void {\n\t\tthis.log(FLIGHTDECK_ERROR, ...messages)\n\t}\n}\n"],"mappings":"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"}