flightdeck 0.4.10 → 0.4.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,6 +3,7 @@
3
3
  lightweight process manager and updater for Node.js applications.
4
4
 
5
5
  ## flightdeck's cycle
6
+
6
7
  - install an application
7
8
  - spawn a process running the application
8
9
  - await a web hook that says "a new version is ready!"
@@ -1 +1 @@
1
- {"version":3,"file":"flightdeck.lib-Dfs4xGO7.js","names":[],"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,\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,\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
+ {"version":3,"file":"flightdeck.lib-Dfs4xGO7.js","names":[],"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,\n\temptyStringAsUndefined: true,\n})\n","/* oxlint-disable typescript/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,\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 implements Pick<\n\tConsole,\n\t`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 +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.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({\n\t\t\tschema: null,\n\t\t\tkill: optional({ $configPath: null }),\n\t\t\t$configPath: null,\n\t\t}),\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\t\"kill/$configPath\": 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\tlet idx = 0\n\t\t\tif (args[0] === `kill`) {\n\t\t\t\tidx = 1\n\t\t\t}\n\t\t\tconst configPath =\n\t\t\t\targs[idx] ?? 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\tcase `kill/$configPath`:\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,KAAA,GAAW,EAC1E,aAAa,KACd,CAAC;AACD,OAAO,OAAO,SAAS;CACtB,KAAK,WAAW,KAAK,KAAK,UAAU;CACpC,MAAM,WAAW,KAAK,KAAK,UAAU;CACrC,MAAM,WAAW,KAAK,KAAK,UAAU;CACrC,OAAO,WAAW,MAAM,KAAK,UAAU;AACxC,CAAC;AAED,MAAM,oBAAoB,QACzB,uCACA,KAAK;CACJ,SAAS;CACT,aAAa;CACb,UAAU,EAAE,YAAY;EAAE,KAAK;EAAU,SAAS;CAAU,EAAE;CAC9D,mBAAmB;CACnB,SAAS;EACR,UAAU;EACV,SAAS;EACT,mBAAmB;CACpB;CACA,gBAAgB;AACjB,CAAC,GACD;CACC,MAAM;EACL,MAAM;EACN,UAAU;EACV,aAAa;EACb,SAAS;EACT,OAAO;CACR;CACA,aAAa;EACZ,MAAM;EACN,UAAU;EACV,aAAa;EACb,SAAS;CACV;CACA,UAAU;EACT,MAAM;EACN,UAAU;EACV,aAAa;EACb,SAAS;EACT,OAAO,KAAK;CACb;CACA,mBAAmB;EAClB,MAAM;EACN,UAAU;EACV,aAAa;EACb,SAAS;CACV;CACA,SAAS;EACR,MAAM;EACN,UAAU;EACV,aAAa;EACb,SAAS;EACT,OAAO,KAAK;CACb;CACA,aAAa;EACZ,MAAM;EACN,UAAU;EACV,aAAa;EACb,SAAS;EACT,OAAO;CACR;AACD,CACD;AAEA,MAAM,cAAc,QACnB,gCACA,KAAK;CAAE,mBAAmB;CAAU,aAAa;AAAS,CAAC,GAC3D;CACC,mBAAmB;EAClB,MAAM;EACN,UAAU;EACV,aAAa;EACb,SAAS;CACV;CACA,aAAa;EACZ,MAAM;EACN,UAAU;EACV,aAAa;EACb,SAAS;CACV;AACD,CACD;AAEA,MAAM,gBAAgB,QACrB,mDACA,KAAK,EAAE,WAAW,SAAS,CAAC,GAC5B,EACC,QAAQ;CACP,MAAM;CACN,UAAU;CACV,aAAa;CACb,SAAS;AACV,EACD,CACD;AAkCA,MAAM,EAAE,QAAQ,oBAhCF,IACb;CACC,SAAS;CACT,QAAQ,SAAS;EAChB,QAAQ;EACR,MAAM,SAAS,EAAE,aAAa,KAAK,CAAC;EACpC,aAAa;CACd,CAAC;CACD,cAAc;EACb,IAAI;EACJ,aAAa;EACb,MAAM;EACN,oBAAoB;EACpB,QAAQ;CACT;CACA,aAAa;CACb,qBAAqB,SAAS;EAC7B,IAAI,KAAK,OAAO,UACf;EAED,IAAI,MAAM;EACV,IAAI,KAAK,OAAO,QACf,MAAM;EAIP,OADC,KAAK,QAAQ,KAAK,KAAK,QAAQ,IAAI,GAAG,wBAAwB;CAEhE;AACD,GACA,OAGuC,EAAE,QAAQ,IAAI;AAEtD,QAAQ,OAAO,MAAf;CACC,KAAK;EACJ;GACC,MAAM,EAAE,WAAW,OAAO;GAC1B,gBAAgB,UAAU,GAAG;EAC9B;EACA;CACD,KAAK;CACL,KAAK;EACJ;GACC,MAAM,EAAE,mBAAmB,gBAAgB,OAAO;GAClD,MAAM,WAAW,KAAK,mBAAmB,WAAW;EACrD;EACA;CACD,KAAK;CACL,KAAK,eACJ,IAAI,WAAW,OAAO,IAAI;AAE5B"}
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({\n\t\t\tschema: null,\n\t\t\tkill: optional({ $configPath: null }),\n\t\t\t$configPath: null,\n\t\t}),\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\t\"kill/$configPath\": 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\tlet idx = 0\n\t\t\tif (args[0] === `kill`) {\n\t\t\t\tidx = 1\n\t\t\t}\n\t\t\tconst configPath =\n\t\t\t\targs[idx] ?? 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\tcase `kill/$configPath`:\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,KAAA,GAAW,EAC1E,aAAa,KACd,CAAC;AACD,OAAO,OAAO,SAAS;CACtB,KAAK,WAAW,KAAK,KAAK,UAAU;CACpC,MAAM,WAAW,KAAK,KAAK,UAAU;CACrC,MAAM,WAAW,KAAK,KAAK,UAAU;CACrC,OAAO,WAAW,MAAM,KAAK,UAAU;AACxC,CAAC;AAED,MAAM,oBAAoB,QACzB,uCACA,KAAK;CACJ,SAAS;CACT,aAAa;CACb,UAAU,EAAE,YAAY;EAAE,KAAK;EAAU,SAAS;CAAU,EAAE;CAC9D,mBAAmB;CACnB,SAAS;EACR,UAAU;EACV,SAAS;EACT,mBAAmB;CACpB;CACA,gBAAgB;AACjB,CAAC,GACD;CACC,MAAM;EACL,MAAM;EACN,UAAU;EACV,aAAa;EACb,SAAS;EACT,OAAO;CACR;CACA,aAAa;EACZ,MAAM;EACN,UAAU;EACV,aAAa;EACb,SAAS;CACV;CACA,UAAU;EACT,MAAM;EACN,UAAU;EACV,aAAa;EACb,SAAS;EACT,OAAO,KAAK;CACb;CACA,mBAAmB;EAClB,MAAM;EACN,UAAU;EACV,aAAa;EACb,SAAS;CACV;CACA,SAAS;EACR,MAAM;EACN,UAAU;EACV,aAAa;EACb,SAAS;EACT,OAAO,KAAK;CACb;CACA,aAAa;EACZ,MAAM;EACN,UAAU;EACV,aAAa;EACb,SAAS;EACT,OAAO;CACR;AACD,CACD;AAEA,MAAM,cAAc,QACnB,gCACA,KAAK;CAAE,mBAAmB;CAAU,aAAa;AAAS,CAAC,GAC3D;CACC,mBAAmB;EAClB,MAAM;EACN,UAAU;EACV,aAAa;EACb,SAAS;CACV;CACA,aAAa;EACZ,MAAM;EACN,UAAU;EACV,aAAa;EACb,SAAS;CACV;AACD,CACD;AAEA,MAAM,gBAAgB,QACrB,mDACA,KAAK,EAAE,WAAW,SAAS,CAAC,GAC5B,EACC,QAAQ;CACP,MAAM;CACN,UAAU;CACV,aAAa;CACb,SAAS;AACV,EACD,CACD;AAkCA,MAAM,EAAE,QAAQ,oBAhCF,IACb;CACC,SAAS;CACT,QAAQ,SAAS;EAChB,QAAQ;EACR,MAAM,SAAS,EAAE,aAAa,KAAK,CAAC;EACpC,aAAa;CACd,CAAC;CACD,cAAc;EACb,IAAI;EACJ,aAAa;EACb,MAAM;EACN,oBAAoB;EACpB,QAAQ;CACT;CACA,aAAa;CACb,qBAAqB,SAAS;EAC7B,IAAI,KAAK,OAAO,UACf;EAED,IAAI,MAAM;EACV,IAAI,KAAK,OAAO,QACf,MAAM;EAIP,OADC,KAAK,QAAQ,KAAK,KAAK,QAAQ,IAAI,GAAG,wBAAwB;CAEhE;AACD,GACA,OAGuC,CAAC,CAAC,QAAQ,IAAI;AAEtD,QAAQ,OAAO,MAAf;CACC,KAAK;EACJ;GACC,MAAM,EAAE,WAAW,OAAO;GAC1B,gBAAgB,UAAU,GAAG;EAC9B;EACA;CACD,KAAK;CACL,KAAK;EACJ;GACC,MAAM,EAAE,mBAAmB,gBAAgB,OAAO;GAClD,MAAM,WAAW,KAAK,mBAAmB,WAAW;EACrD;EACA;CACD,KAAK;CACL,KAAK,eACJ,IAAI,WAAW,OAAO,IAAI;AAE5B"}
@@ -1 +1 @@
1
- {"version":3,"file":"klaxon.lib-Bgs1Mbca.js","names":[],"sources":["../src/klaxon.lib.ts"],"sourcesContent":["export type AlertOptions = {\n\tsecret: string\n\tendpoint: string\n\tversion: string\n}\n\nexport async function alert({\n\tsecret,\n\tendpoint,\n\tversion,\n}: AlertOptions): Promise<Response> {\n\tconst response = await fetch(endpoint, {\n\t\tmethod: `POST`,\n\t\theaders: {\n\t\t\t\"Content-Type\": `text/plain;charset=UTF-8`,\n\t\t\tAuthorization: `Bearer ${secret}`,\n\t\t},\n\t\tbody: version,\n\t})\n\n\treturn response\n}\n\n/**\n * @see https://github.com/changesets/action/blob/main/src/run.ts\n */\nexport type ChangesetsPublishedPackage = {\n\tname: string\n\tversion: string\n}\n\n/**\n * @see https://github.com/changesets/action/blob/main/src/run.ts\n */\nexport type ChangesetsPublishResult =\n\t| {\n\t\t\tpublished: true\n\t\t\tpublishedPackages: ChangesetsPublishedPackage[]\n\t }\n\t| { published: false }\n\nexport type PackageConfig<K extends string> = {\n\t[key in K]: { endpoint: string }\n}\nexport type SecretsConfig<K extends string> = {\n\t[key in K]: string\n}\n\nexport type ScrambleOptions<K extends string = string> = {\n\tpackageConfig: PackageConfig<K>\n\tsecretsConfig: SecretsConfig<K>\n\tpublishedPackages: ChangesetsPublishedPackage[]\n}\n\nexport type ScrambleResult<K extends string = string> = {\n\t[key in K]: Response\n}\n\nexport async function scramble<K extends string = string>({\n\tpackageConfig,\n\tsecretsConfig,\n\tpublishedPackages,\n}: ScrambleOptions<K>): Promise<ScrambleResult<K>> {\n\tconst alertResults: Promise<readonly [K, Response]>[] = []\n\tfor (const publishedPackage of publishedPackages) {\n\t\tif (publishedPackage.name in packageConfig) {\n\t\t\tconst name = publishedPackage.name as K\n\t\t\tconst { endpoint } = packageConfig[name]\n\t\t\tconst secret = secretsConfig[name]\n\t\t\tconst version = publishedPackage.version\n\t\t\tconst alertResultPromise = alert({ secret, endpoint, version }).then(\n\t\t\t\t(alertResult) => [name, alertResult] as const,\n\t\t\t)\n\t\t\talertResults.push(alertResultPromise)\n\t\t}\n\t}\n\tconst alertResultsResolved = await Promise.all(alertResults)\n\tconst scrambleResult = Object.fromEntries(\n\t\talertResultsResolved,\n\t) as ScrambleResult<K>\n\treturn scrambleResult\n}\n"],"mappings":";;;;;;AAMA,eAAsB,MAAM,EAC3B,QACA,UACA,WACmC;CAUnC,OAAO,MATgB,MAAM,UAAU;EACtC,QAAQ;EACR,SAAS;GACR,gBAAgB;GAChB,eAAe,UAAU;EAC1B;EACA,MAAM;CACP,CAAC;AAGF;AAqCA,eAAsB,SAAoC,EACzD,eACA,eACA,qBACkD;CAClD,MAAM,eAAkD,CAAC;CACzD,KAAK,MAAM,oBAAoB,mBAC9B,IAAI,iBAAiB,QAAQ,eAAe;EAC3C,MAAM,OAAO,iBAAiB;EAC9B,MAAM,EAAE,aAAa,cAAc;EACnC,MAAM,SAAS,cAAc;EAC7B,MAAM,UAAU,iBAAiB;EACjC,MAAM,qBAAqB,MAAM;GAAE;GAAQ;GAAU;EAAQ,CAAC,EAAE,MAC9D,gBAAgB,CAAC,MAAM,WAAW,CACpC;EACA,aAAa,KAAK,kBAAkB;CACrC;CAED,MAAM,uBAAuB,MAAM,QAAQ,IAAI,YAAY;CAI3D,OAHuB,OAAO,YAC7B,oBAEmB;AACrB"}
1
+ {"version":3,"file":"klaxon.lib-Bgs1Mbca.js","names":[],"sources":["../src/klaxon.lib.ts"],"sourcesContent":["export type AlertOptions = {\n\tsecret: string\n\tendpoint: string\n\tversion: string\n}\n\nexport async function alert({\n\tsecret,\n\tendpoint,\n\tversion,\n}: AlertOptions): Promise<Response> {\n\tconst response = await fetch(endpoint, {\n\t\tmethod: `POST`,\n\t\theaders: {\n\t\t\t\"Content-Type\": `text/plain;charset=UTF-8`,\n\t\t\tAuthorization: `Bearer ${secret}`,\n\t\t},\n\t\tbody: version,\n\t})\n\n\treturn response\n}\n\n/**\n * @see https://github.com/changesets/action/blob/main/src/run.ts\n */\nexport type ChangesetsPublishedPackage = {\n\tname: string\n\tversion: string\n}\n\n/**\n * @see https://github.com/changesets/action/blob/main/src/run.ts\n */\nexport type ChangesetsPublishResult =\n\t| {\n\t\t\tpublished: true\n\t\t\tpublishedPackages: ChangesetsPublishedPackage[]\n\t }\n\t| { published: false }\n\nexport type PackageConfig<K extends string> = {\n\t[key in K]: { endpoint: string }\n}\nexport type SecretsConfig<K extends string> = {\n\t[key in K]: string\n}\n\nexport type ScrambleOptions<K extends string = string> = {\n\tpackageConfig: PackageConfig<K>\n\tsecretsConfig: SecretsConfig<K>\n\tpublishedPackages: ChangesetsPublishedPackage[]\n}\n\nexport type ScrambleResult<K extends string = string> = {\n\t[key in K]: Response\n}\n\nexport async function scramble<K extends string = string>({\n\tpackageConfig,\n\tsecretsConfig,\n\tpublishedPackages,\n}: ScrambleOptions<K>): Promise<ScrambleResult<K>> {\n\tconst alertResults: Promise<readonly [K, Response]>[] = []\n\tfor (const publishedPackage of publishedPackages) {\n\t\tif (publishedPackage.name in packageConfig) {\n\t\t\tconst name = publishedPackage.name as K\n\t\t\tconst { endpoint } = packageConfig[name]\n\t\t\tconst secret = secretsConfig[name]\n\t\t\tconst version = publishedPackage.version\n\t\t\tconst alertResultPromise = alert({ secret, endpoint, version }).then(\n\t\t\t\t(alertResult) => [name, alertResult] as const,\n\t\t\t)\n\t\t\talertResults.push(alertResultPromise)\n\t\t}\n\t}\n\tconst alertResultsResolved = await Promise.all(alertResults)\n\tconst scrambleResult = Object.fromEntries(\n\t\talertResultsResolved,\n\t) as ScrambleResult<K>\n\treturn scrambleResult\n}\n"],"mappings":";;;;;;AAMA,eAAsB,MAAM,EAC3B,QACA,UACA,WACmC;CAUnC,OAAO,MATgB,MAAM,UAAU;EACtC,QAAQ;EACR,SAAS;GACR,gBAAgB;GAChB,eAAe,UAAU;EAC1B;EACA,MAAM;CACP,CAAC;AAGF;AAqCA,eAAsB,SAAoC,EACzD,eACA,eACA,qBACkD;CAClD,MAAM,eAAkD,CAAC;CACzD,KAAK,MAAM,oBAAoB,mBAC9B,IAAI,iBAAiB,QAAQ,eAAe;EAC3C,MAAM,OAAO,iBAAiB;EAC9B,MAAM,EAAE,aAAa,cAAc;EACnC,MAAM,SAAS,cAAc;EAC7B,MAAM,UAAU,iBAAiB;EACjC,MAAM,qBAAqB,MAAM;GAAE;GAAQ;GAAU;EAAQ,CAAC,CAAC,CAAC,MAC9D,gBAAgB,CAAC,MAAM,WAAW,CACpC;EACA,aAAa,KAAK,kBAAkB;CACrC;CAED,MAAM,uBAAuB,MAAM,QAAQ,IAAI,YAAY;CAI3D,OAHuB,OAAO,YAC7B,oBAEmB;AACrB"}
@@ -1 +1 @@
1
- {"version":3,"file":"klaxon.x.js","names":["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,MAAM,oCAAkE,KAAK;CAC5E,eAAe,EAAE,YAAY,EAAE,UAAU,SAAS,EAAE;CACpD,eAAe,EAAE,YAAY,SAAS;CACtC,mBAAmB,CAAC;EAAE,MAAM;EAAU,SAAS;CAAS,GAAG,IAAI;AAChE,CAAC;AAkCD,MAAM,EAAE,WAhCO,IAAI;CAClB,SAAS;CACT,QAAQ,SAAS,EAChB,UAAU,KACX,CAAC;CACD,cAAc,EACb,UAAU,QAAQ,IAAI,mCAAmC;EACxD,eAAe;GACd,aAAa;GACb,SAAS;GACT,MAAM;GACN,OAAO,KAAK;GACZ,UAAU;EACX;EACA,eAAe;GACd,aAAa;GACb,SAAS;GACT,MAAM;GACN,OAAO,KAAK;GACZ,UAAU;EACX;EACA,mBAAmB;GAClB,aAAa;GACb,SAAS;GACT,MAAM;GACN,OAAO,KAAK;GACZ,UAAU;EACX;CACD,CAAC,EACF;AACD,CAEwB,EAAE,QAAQ,IAAI;AACtC,MAAMA,SAAgB,OAAO,IAAI,EAAE,MAAM,mBAAmB;CAC3D,QAAQ,IAAI,cAAc;AAC3B,CAAC"}
1
+ {"version":3,"file":"klaxon.x.js","names":["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,MAAM,oCAAkE,KAAK;CAC5E,eAAe,EAAE,YAAY,EAAE,UAAU,SAAS,EAAE;CACpD,eAAe,EAAE,YAAY,SAAS;CACtC,mBAAmB,CAAC;EAAE,MAAM;EAAU,SAAS;CAAS,GAAG,IAAI;AAChE,CAAC;AAkCD,MAAM,EAAE,WAhCO,IAAI;CAClB,SAAS;CACT,QAAQ,SAAS,EAChB,UAAU,KACX,CAAC;CACD,cAAc,EACb,UAAU,QAAQ,IAAI,mCAAmC;EACxD,eAAe;GACd,aAAa;GACb,SAAS;GACT,MAAM;GACN,OAAO,KAAK;GACZ,UAAU;EACX;EACA,eAAe;GACd,aAAa;GACb,SAAS;GACT,MAAM;GACN,OAAO,KAAK;GACZ,UAAU;EACX;EACA,mBAAmB;GAClB,aAAa;GACb,SAAS;GACT,MAAM;GACN,OAAO,KAAK;GACZ,UAAU;EACX;CACD,CAAC,EACF;AACD,CAEwB,CAAC,CAAC,QAAQ,IAAI;AACtC,MAAMA,SAAgB,OAAO,IAAI,CAAC,CAAC,MAAM,mBAAmB;CAC3D,QAAQ,IAAI,cAAc;AAC3B,CAAC"}
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"],"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"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { z } from "zod";
1
+ import { z } from "zod"
2
2
 
3
3
  export const lnavFormatSchema = z
4
4
  .object({
@@ -29,9 +29,9 @@ export const lnavFormatSchema = z
29
29
  )
30
30
  .superRefine((value, ctx) => {
31
31
  for (const key in value) {
32
- let evaluated = false;
33
- if (key.match(/^(.+)$/)) {
34
- evaluated = true;
32
+ let evaluated = false
33
+ if (key.match(new RegExp("^(.+)$"))) {
34
+ evaluated = true
35
35
  const result = z
36
36
  .object({
37
37
  pattern: z
@@ -50,7 +50,7 @@ export const lnavFormatSchema = z
50
50
  })
51
51
  .strict()
52
52
  .describe("The set of patterns used to match log messages")
53
- .safeParse(value[key]);
53
+ .safeParse(value[key])
54
54
  if (!result.success) {
55
55
  ctx.addIssue({
56
56
  path: [key],
@@ -59,11 +59,11 @@ export const lnavFormatSchema = z
59
59
  params: {
60
60
  issues: result.error.issues,
61
61
  },
62
- });
62
+ })
63
63
  }
64
64
  }
65
65
  if (!evaluated) {
66
- const result = z.never().safeParse(value[key]);
66
+ const result = z.never().safeParse(value[key])
67
67
  if (!result.success) {
68
68
  ctx.addIssue({
69
69
  path: [key],
@@ -72,7 +72,7 @@ export const lnavFormatSchema = z
72
72
  params: {
73
73
  issues: result.error.issues,
74
74
  },
75
- });
75
+ })
76
76
  }
77
77
  }
78
78
  }
@@ -106,14 +106,10 @@ export const lnavFormatSchema = z
106
106
  z
107
107
  .number()
108
108
  .int()
109
- .describe(
110
- "The value to divide a numeric timestamp by in a JSON log.",
111
- ),
109
+ .describe("The value to divide a numeric timestamp by in a JSON log."),
112
110
  z
113
111
  .number()
114
- .describe(
115
- "The value to divide a numeric timestamp by in a JSON log.",
116
- ),
112
+ .describe("The value to divide a numeric timestamp by in a JSON log."),
117
113
  ])
118
114
  .describe("The value to divide a numeric timestamp by in a JSON log.")
119
115
  .optional(),
@@ -135,13 +131,13 @@ export const lnavFormatSchema = z
135
131
  )
136
132
  .superRefine((value, ctx) => {
137
133
  for (const key in value) {
138
- let evaluated = false;
139
- if (key.match(/^(\w+)$/)) {
140
- evaluated = true;
134
+ let evaluated = false
135
+ if (key.match(new RegExp("^(\\w+)$"))) {
136
+ evaluated = true
141
137
  const result = z
142
138
  .string()
143
139
  .describe("SQLite expression")
144
- .safeParse(value[key]);
140
+ .safeParse(value[key])
145
141
  if (!result.success) {
146
142
  ctx.addIssue({
147
143
  path: [key],
@@ -150,11 +146,11 @@ export const lnavFormatSchema = z
150
146
  params: {
151
147
  issues: result.error.issues,
152
148
  },
153
- });
149
+ })
154
150
  }
155
151
  }
156
152
  if (!evaluated) {
157
- const result = z.never().safeParse(value[key]);
153
+ const result = z.never().safeParse(value[key])
158
154
  if (!result.success) {
159
155
  ctx.addIssue({
160
156
  path: [key],
@@ -163,7 +159,7 @@ export const lnavFormatSchema = z
163
159
  params: {
164
160
  issues: result.error.issues,
165
161
  },
166
- });
162
+ })
167
163
  }
168
164
  }
169
165
  }
@@ -183,7 +179,7 @@ export const lnavFormatSchema = z
183
179
  .optional(),
184
180
  command: z
185
181
  .string()
186
- .regex(/[\w.-]+/)
182
+ .regex(new RegExp("[\\w\\.\\-]+"))
187
183
  .describe("The script used to convert the file")
188
184
  .optional(),
189
185
  })
@@ -231,9 +227,7 @@ export const lnavFormatSchema = z
231
227
  z
232
228
  .array(z.string())
233
229
  .describe("A URL with more information about this log format"),
234
- z
235
- .string()
236
- .describe("A URL with more information about this log format"),
230
+ z.string().describe("A URL with more information about this log format"),
237
231
  ])
238
232
  .describe("A URL with more information about this log format")
239
233
  .optional(),
@@ -318,9 +312,9 @@ export const lnavFormatSchema = z
318
312
  )
319
313
  .superRefine((value, ctx) => {
320
314
  for (const key in value) {
321
- let evaluated = false;
322
- if (key.match(/^([\w.-]+)$/)) {
323
- evaluated = true;
315
+ let evaluated = false
316
+ if (key.match(new RegExp("^([\\w\\.\\-]+)$"))) {
317
+ evaluated = true
324
318
  const result = z
325
319
  .object({
326
320
  format: z
@@ -367,7 +361,7 @@ export const lnavFormatSchema = z
367
361
  })
368
362
  .strict()
369
363
  .describe("A type of description for this operation")
370
- .safeParse(value[key]);
364
+ .safeParse(value[key])
371
365
  if (!result.success) {
372
366
  ctx.addIssue({
373
367
  path: [key],
@@ -376,11 +370,11 @@ export const lnavFormatSchema = z
376
370
  params: {
377
371
  issues: result.error.issues,
378
372
  },
379
- });
373
+ })
380
374
  }
381
375
  }
382
376
  if (!evaluated) {
383
- const result = z.never().safeParse(value[key]);
377
+ const result = z.never().safeParse(value[key])
384
378
  if (!result.success) {
385
379
  ctx.addIssue({
386
380
  path: [key],
@@ -389,7 +383,7 @@ export const lnavFormatSchema = z
389
383
  params: {
390
384
  issues: result.error.issues,
391
385
  },
392
- });
386
+ })
393
387
  }
394
388
  }
395
389
  }
@@ -451,9 +445,9 @@ export const lnavFormatSchema = z
451
445
  )
452
446
  .superRefine((value, ctx) => {
453
447
  for (const key in value) {
454
- let evaluated = false;
455
- if (key.match(/^([\w.-]+)$/)) {
456
- evaluated = true;
448
+ let evaluated = false
449
+ if (key.match(new RegExp("^([\\w\\.\\-]+)$"))) {
450
+ evaluated = true
457
451
  const result = z
458
452
  .object({
459
453
  format: z
@@ -500,7 +494,7 @@ export const lnavFormatSchema = z
500
494
  })
501
495
  .strict()
502
496
  .describe("A type of description for this sub-operation")
503
- .safeParse(value[key]);
497
+ .safeParse(value[key])
504
498
  if (!result.success) {
505
499
  ctx.addIssue({
506
500
  path: [key],
@@ -509,11 +503,11 @@ export const lnavFormatSchema = z
509
503
  params: {
510
504
  issues: result.error.issues,
511
505
  },
512
- });
506
+ })
513
507
  }
514
508
  }
515
509
  if (!evaluated) {
516
- const result = z.never().safeParse(value[key]);
510
+ const result = z.never().safeParse(value[key])
517
511
  if (!result.success) {
518
512
  ctx.addIssue({
519
513
  path: [key],
@@ -522,7 +516,7 @@ export const lnavFormatSchema = z
522
516
  params: {
523
517
  issues: result.error.issues,
524
518
  },
525
- });
519
+ })
526
520
  }
527
521
  }
528
522
  }
@@ -565,13 +559,15 @@ export const lnavFormatSchema = z
565
559
  )
566
560
  .superRefine((value, ctx) => {
567
561
  for (const key in value) {
568
- let evaluated = false;
562
+ let evaluated = false
569
563
  if (
570
564
  key.match(
571
- /^(trace|debug[2345]?|info|stats|notice|warning|error|critical|fatal)$/,
565
+ new RegExp(
566
+ "^(trace|debug[2345]?|info|stats|notice|warning|error|critical|fatal)$",
567
+ ),
572
568
  )
573
569
  ) {
574
- evaluated = true;
570
+ evaluated = true
575
571
  const result = z
576
572
  .union([
577
573
  z
@@ -589,7 +585,7 @@ export const lnavFormatSchema = z
589
585
  .describe(
590
586
  "The regular expression used to match the log text for this level. For JSON logs with numeric levels, this should be the number for the corresponding level.",
591
587
  )
592
- .safeParse(value[key]);
588
+ .safeParse(value[key])
593
589
  if (!result.success) {
594
590
  ctx.addIssue({
595
591
  path: [key],
@@ -598,11 +594,11 @@ export const lnavFormatSchema = z
598
594
  params: {
599
595
  issues: result.error.issues,
600
596
  },
601
- });
597
+ })
602
598
  }
603
599
  }
604
600
  if (!evaluated) {
605
- const result = z.never().safeParse(value[key]);
601
+ const result = z.never().safeParse(value[key])
606
602
  if (!result.success) {
607
603
  ctx.addIssue({
608
604
  path: [key],
@@ -611,7 +607,7 @@ export const lnavFormatSchema = z
611
607
  params: {
612
608
  issues: result.error.issues,
613
609
  },
614
- });
610
+ })
615
611
  }
616
612
  }
617
613
  }
@@ -666,9 +662,9 @@ export const lnavFormatSchema = z
666
662
  )
667
663
  .superRefine((value, ctx) => {
668
664
  for (const key in value) {
669
- let evaluated = false;
670
- if (key.match(/^(.+)$/)) {
671
- evaluated = true;
665
+ let evaluated = false
666
+ if (key.match(new RegExp("^(.+)$"))) {
667
+ evaluated = true
672
668
  const result = z
673
669
  .object({
674
670
  op: z
@@ -677,7 +673,7 @@ export const lnavFormatSchema = z
677
673
  value: z.number().optional(),
678
674
  })
679
675
  .strict()
680
- .safeParse(value[key]);
676
+ .safeParse(value[key])
681
677
  if (!result.success) {
682
678
  ctx.addIssue({
683
679
  path: [key],
@@ -686,11 +682,11 @@ export const lnavFormatSchema = z
686
682
  params: {
687
683
  issues: result.error.issues,
688
684
  },
689
- });
685
+ })
690
686
  }
691
687
  }
692
688
  if (!evaluated) {
693
- const result = z.never().safeParse(value[key]);
689
+ const result = z.never().safeParse(value[key])
694
690
  if (!result.success) {
695
691
  ctx.addIssue({
696
692
  path: [key],
@@ -699,14 +695,12 @@ export const lnavFormatSchema = z
699
695
  params: {
700
696
  issues: result.error.issues,
701
697
  },
702
- });
698
+ })
703
699
  }
704
700
  }
705
701
  }
706
702
  })
707
- .describe(
708
- "Transforms the numeric value by the given factor",
709
- )
703
+ .describe("Transforms the numeric value by the given factor")
710
704
  .optional(),
711
705
  })
712
706
  .strict()
@@ -726,9 +720,7 @@ export const lnavFormatSchema = z
726
720
  .optional(),
727
721
  hidden: z
728
722
  .boolean()
729
- .describe(
730
- "Indicates whether or not this field should be hidden",
731
- )
723
+ .describe("Indicates whether or not this field should be hidden")
732
724
  .optional(),
733
725
  "action-list": z
734
726
  .array(z.string())
@@ -752,9 +744,9 @@ export const lnavFormatSchema = z
752
744
  )
753
745
  .superRefine((value, ctx) => {
754
746
  for (const key in value) {
755
- let evaluated = false;
756
- if (key.match(/^(.+)$/)) {
757
- evaluated = true;
747
+ let evaluated = false
748
+ if (key.match(new RegExp("^(.+)$"))) {
749
+ evaluated = true
758
750
  const result = z
759
751
  .object({
760
752
  kind: z
@@ -799,9 +791,9 @@ export const lnavFormatSchema = z
799
791
  )
800
792
  .superRefine((value, ctx) => {
801
793
  for (const key in value) {
802
- let evaluated = false;
803
- if (key.match(/^(.+)$/)) {
804
- evaluated = true;
794
+ let evaluated = false
795
+ if (key.match(new RegExp("^(.+)$"))) {
796
+ evaluated = true
805
797
  const result = z
806
798
  .object({
807
799
  op: z
@@ -810,7 +802,7 @@ export const lnavFormatSchema = z
810
802
  value: z.number().optional(),
811
803
  })
812
804
  .strict()
813
- .safeParse(value[key]);
805
+ .safeParse(value[key])
814
806
  if (!result.success) {
815
807
  ctx.addIssue({
816
808
  path: [key],
@@ -819,11 +811,11 @@ export const lnavFormatSchema = z
819
811
  params: {
820
812
  issues: result.error.issues,
821
813
  },
822
- });
814
+ })
823
815
  }
824
816
  }
825
817
  if (!evaluated) {
826
- const result = z.never().safeParse(value[key]);
818
+ const result = z.never().safeParse(value[key])
827
819
  if (!result.success) {
828
820
  ctx.addIssue({
829
821
  path: [key],
@@ -832,7 +824,7 @@ export const lnavFormatSchema = z
832
824
  params: {
833
825
  issues: result.error.issues,
834
826
  },
835
- });
827
+ })
836
828
  }
837
829
  }
838
830
  }
@@ -879,10 +871,8 @@ export const lnavFormatSchema = z
879
871
  .optional(),
880
872
  })
881
873
  .strict()
882
- .describe(
883
- "The set of values captured by the log message patterns",
884
- )
885
- .safeParse(value[key]);
874
+ .describe("The set of values captured by the log message patterns")
875
+ .safeParse(value[key])
886
876
  if (!result.success) {
887
877
  ctx.addIssue({
888
878
  path: [key],
@@ -891,11 +881,11 @@ export const lnavFormatSchema = z
891
881
  params: {
892
882
  issues: result.error.issues,
893
883
  },
894
- });
884
+ })
895
885
  }
896
886
  }
897
887
  if (!evaluated) {
898
- const result = z.never().safeParse(value[key]);
888
+ const result = z.never().safeParse(value[key])
899
889
  if (!result.success) {
900
890
  ctx.addIssue({
901
891
  path: [key],
@@ -904,7 +894,7 @@ export const lnavFormatSchema = z
904
894
  params: {
905
895
  issues: result.error.issues,
906
896
  },
907
- });
897
+ })
908
898
  }
909
899
  }
910
900
  }
@@ -966,9 +956,9 @@ export const lnavFormatSchema = z
966
956
  )
967
957
  .superRefine((value, ctx) => {
968
958
  for (const key in value) {
969
- let evaluated = false;
970
- if (key.match(/^([\w:;._-]+)$/)) {
971
- evaluated = true;
959
+ let evaluated = false
960
+ if (key.match(new RegExp("^([\\w:;\\._\\-]+)$"))) {
961
+ evaluated = true
972
962
  const result = z
973
963
  .object({
974
964
  paths: z
@@ -1015,7 +1005,7 @@ export const lnavFormatSchema = z
1015
1005
  })
1016
1006
  .strict()
1017
1007
  .describe("The name of the tag to apply")
1018
- .safeParse(value[key]);
1008
+ .safeParse(value[key])
1019
1009
  if (!result.success) {
1020
1010
  ctx.addIssue({
1021
1011
  path: [key],
@@ -1024,11 +1014,11 @@ export const lnavFormatSchema = z
1024
1014
  params: {
1025
1015
  issues: result.error.issues,
1026
1016
  },
1027
- });
1017
+ })
1028
1018
  }
1029
1019
  }
1030
1020
  if (!evaluated) {
1031
- const result = z.never().safeParse(value[key]);
1021
+ const result = z.never().safeParse(value[key])
1032
1022
  if (!result.success) {
1033
1023
  ctx.addIssue({
1034
1024
  path: [key],
@@ -1037,7 +1027,7 @@ export const lnavFormatSchema = z
1037
1027
  params: {
1038
1028
  issues: result.error.issues,
1039
1029
  },
1040
- });
1030
+ })
1041
1031
  }
1042
1032
  }
1043
1033
  }
@@ -1099,9 +1089,9 @@ export const lnavFormatSchema = z
1099
1089
  )
1100
1090
  .superRefine((value, ctx) => {
1101
1091
  for (const key in value) {
1102
- let evaluated = false;
1103
- if (key.match(/^([\w:;._-]+)$/)) {
1104
- evaluated = true;
1092
+ let evaluated = false
1093
+ if (key.match(new RegExp("^([\\w:;\\._\\-]+)$"))) {
1094
+ evaluated = true
1105
1095
  const result = z
1106
1096
  .object({
1107
1097
  paths: z
@@ -1148,7 +1138,7 @@ export const lnavFormatSchema = z
1148
1138
  })
1149
1139
  .strict()
1150
1140
  .describe("The type of partition to apply")
1151
- .safeParse(value[key]);
1141
+ .safeParse(value[key])
1152
1142
  if (!result.success) {
1153
1143
  ctx.addIssue({
1154
1144
  path: [key],
@@ -1157,11 +1147,11 @@ export const lnavFormatSchema = z
1157
1147
  params: {
1158
1148
  issues: result.error.issues,
1159
1149
  },
1160
- });
1150
+ })
1161
1151
  }
1162
1152
  }
1163
1153
  if (!evaluated) {
1164
- const result = z.never().safeParse(value[key]);
1154
+ const result = z.never().safeParse(value[key])
1165
1155
  if (!result.success) {
1166
1156
  ctx.addIssue({
1167
1157
  path: [key],
@@ -1170,7 +1160,7 @@ export const lnavFormatSchema = z
1170
1160
  params: {
1171
1161
  issues: result.error.issues,
1172
1162
  },
1173
- });
1163
+ })
1174
1164
  }
1175
1165
  }
1176
1166
  }
@@ -1196,9 +1186,9 @@ export const lnavFormatSchema = z
1196
1186
  )
1197
1187
  .superRefine((value, ctx) => {
1198
1188
  for (const key in value) {
1199
- let evaluated = false;
1200
- if (key.match(/^(\w+)$/)) {
1201
- evaluated = true;
1189
+ let evaluated = false
1190
+ if (key.match(new RegExp("^(\\w+)$"))) {
1191
+ evaluated = true
1202
1192
  const result = z
1203
1193
  .union([
1204
1194
  z.string(),
@@ -1210,7 +1200,7 @@ export const lnavFormatSchema = z
1210
1200
  })
1211
1201
  .strict(),
1212
1202
  ])
1213
- .safeParse(value[key]);
1203
+ .safeParse(value[key])
1214
1204
  if (!result.success) {
1215
1205
  ctx.addIssue({
1216
1206
  path: [key],
@@ -1219,11 +1209,11 @@ export const lnavFormatSchema = z
1219
1209
  params: {
1220
1210
  issues: result.error.issues,
1221
1211
  },
1222
- });
1212
+ })
1223
1213
  }
1224
1214
  }
1225
1215
  if (!evaluated) {
1226
- const result = z.never().safeParse(value[key]);
1216
+ const result = z.never().safeParse(value[key])
1227
1217
  if (!result.success) {
1228
1218
  ctx.addIssue({
1229
1219
  path: [key],
@@ -1232,7 +1222,7 @@ export const lnavFormatSchema = z
1232
1222
  params: {
1233
1223
  issues: result.error.issues,
1234
1224
  },
1235
- });
1225
+ })
1236
1226
  }
1237
1227
  }
1238
1228
  }
@@ -1285,9 +1275,7 @@ export const lnavFormatSchema = z
1285
1275
  .object({
1286
1276
  field: z
1287
1277
  .string()
1288
- .describe(
1289
- "The name of the field to substitute at this position",
1290
- )
1278
+ .describe("The name of the field to substitute at this position")
1291
1279
  .optional(),
1292
1280
  "default-value": z
1293
1281
  .string()
@@ -1388,9 +1376,9 @@ export const lnavFormatSchema = z
1388
1376
  )
1389
1377
  .superRefine((value, ctx) => {
1390
1378
  for (const key in value) {
1391
- let evaluated = false;
1392
- if (key.match(/^(\w+)$/)) {
1393
- evaluated = true;
1379
+ let evaluated = false
1380
+ if (key.match(new RegExp("^(\\w+)$"))) {
1381
+ evaluated = true
1394
1382
  const result = z
1395
1383
  .object({
1396
1384
  pattern: z
@@ -1424,7 +1412,7 @@ export const lnavFormatSchema = z
1424
1412
  })
1425
1413
  .strict()
1426
1414
  .describe("The set of search tables to be automatically defined")
1427
- .safeParse(value[key]);
1415
+ .safeParse(value[key])
1428
1416
  if (!result.success) {
1429
1417
  ctx.addIssue({
1430
1418
  path: [key],
@@ -1433,11 +1421,11 @@ export const lnavFormatSchema = z
1433
1421
  params: {
1434
1422
  issues: result.error.issues,
1435
1423
  },
1436
- });
1424
+ })
1437
1425
  }
1438
1426
  }
1439
1427
  if (!evaluated) {
1440
- const result = z.never().safeParse(value[key]);
1428
+ const result = z.never().safeParse(value[key])
1441
1429
  if (!result.success) {
1442
1430
  ctx.addIssue({
1443
1431
  path: [key],
@@ -1446,7 +1434,7 @@ export const lnavFormatSchema = z
1446
1434
  params: {
1447
1435
  issues: result.error.issues,
1448
1436
  },
1449
- });
1437
+ })
1450
1438
  }
1451
1439
  }
1452
1440
  }
@@ -1491,9 +1479,9 @@ export const lnavFormatSchema = z
1491
1479
  )
1492
1480
  .superRefine((value, ctx) => {
1493
1481
  for (const key in value) {
1494
- let evaluated = false;
1495
- if (key.match(/^(.+)$/)) {
1496
- evaluated = true;
1482
+ let evaluated = false
1483
+ if (key.match(new RegExp("^(.+)$"))) {
1484
+ evaluated = true
1497
1485
  const result = z
1498
1486
  .object({
1499
1487
  pattern: z
@@ -1523,7 +1511,7 @@ export const lnavFormatSchema = z
1523
1511
  })
1524
1512
  .strict()
1525
1513
  .describe("The definition of a highlight")
1526
- .safeParse(value[key]);
1514
+ .safeParse(value[key])
1527
1515
  if (!result.success) {
1528
1516
  ctx.addIssue({
1529
1517
  path: [key],
@@ -1532,11 +1520,11 @@ export const lnavFormatSchema = z
1532
1520
  params: {
1533
1521
  issues: result.error.issues,
1534
1522
  },
1535
- });
1523
+ })
1536
1524
  }
1537
1525
  }
1538
1526
  if (!evaluated) {
1539
- const result = z.never().safeParse(value[key]);
1527
+ const result = z.never().safeParse(value[key])
1540
1528
  if (!result.success) {
1541
1529
  ctx.addIssue({
1542
1530
  path: [key],
@@ -1545,7 +1533,7 @@ export const lnavFormatSchema = z
1545
1533
  params: {
1546
1534
  issues: result.error.issues,
1547
1535
  },
1548
- });
1536
+ })
1549
1537
  }
1550
1538
  }
1551
1539
  }
@@ -1566,6 +1554,6 @@ export const lnavFormatSchema = z
1566
1554
  .optional(),
1567
1555
  })
1568
1556
  .strict()
1569
- .describe("The definition of a log file format.");
1557
+ .describe("The definition of a log file format.")
1570
1558
 
1571
- export type LnavFormat = z.infer<typeof lnavFormatSchema>;
1559
+ export type LnavFormat = z.infer<typeof lnavFormatSchema>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flightdeck",
3
- "version": "0.4.10",
3
+ "version": "0.4.12",
4
4
  "license": "MIT",
5
5
  "author": {
6
6
  "name": "Jeremy Banka",
@@ -32,36 +32,36 @@
32
32
  "dependencies": {
33
33
  "@t3-oss/env-core": "0.13.11",
34
34
  "arktype": "2.2.0",
35
+ "atom.io": "0.47.3",
35
36
  "cron": "4.4.0",
36
- "comline": "0.4.6",
37
- "safedeposit": "0.1.2",
38
- "atom.io": "0.47.1"
37
+ "comline": "0.4.7",
38
+ "safedeposit": "0.1.2"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@biomejs/js-api": "4.0.0",
42
42
  "@biomejs/wasm-nodejs": "2.4.16",
43
43
  "@types/bun": "npm:bun-types@1.3.14",
44
- "@types/node": "25.9.1",
45
- "@typescript/native-preview": "7.0.0-dev.20260603.1",
44
+ "@types/node": "25.9.2",
45
+ "@typescript/native-preview": "7.0.0-dev.20260611.2",
46
46
  "concurrently": "10.0.3",
47
47
  "eslint": "10.4.1",
48
48
  "json-schema-to-zod": "2.8.1",
49
- "tsdown": "0.22.1",
49
+ "tsdown": "0.22.2",
50
50
  "vitest": "4.1.8",
51
51
  "zod": "4.4.3",
52
- "varmint": "0.5.14"
52
+ "varmint": "0.5.15"
53
53
  },
54
54
  "scripts": {
55
55
  "gen": "bun ./__scripts__/gen.bun.ts",
56
56
  "build": "tsdown && rm -f dist/*.x.d.ts && bun ./__scripts__/build-lnav.bun.ts",
57
57
  "schema:flightdeck": "bun ./src/flightdeck.bin.ts --outdir=dist -- schema",
58
- "lint:biome": "biome check -- .",
59
58
  "lint:eslint": "eslint -- .",
59
+ "lint:oxlint": "oxlint --type-aware -c ../../.oxlintrc.jsonc .",
60
60
  "lint:types": "tsgo --noEmit",
61
61
  "watch:types": "tsgo --watch --noEmit",
62
62
  "lint": "concurrently \"bun:lint:*\"",
63
63
  "test": "vitest",
64
64
  "test:once": "vitest run",
65
- "postversion": "biome format --write package.json"
65
+ "postversion": "dprint fmt package.json"
66
66
  }
67
67
  }
@@ -1,4 +1,4 @@
1
- /* eslint-disable @typescript-eslint/only-throw-error */
1
+ /* oxlint-disable typescript/only-throw-error */
2
2
  import type { ChildProcessWithoutNullStreams } from "node:child_process"
3
3
  import { execSync, spawn } from "node:child_process"
4
4
  import { createServer } from "node:http"
@@ -628,9 +628,10 @@ export const FLIGHTDECK_LNAV_FORMAT = {
628
628
  },
629
629
  } as const satisfies FlightDeckFormat & LnavFormat
630
630
 
631
- export class FlightDeckLogger
632
- implements Pick<Console, `error` | `info` | `warn`>
633
- {
631
+ export class FlightDeckLogger implements Pick<
632
+ Console,
633
+ `error` | `info` | `warn`
634
+ > {
634
635
  public readonly packageName: string
635
636
  public readonly serviceName?: string
636
637
  public readonly jsonLogging: boolean