Flatten the repo: move everything out of app/ to the root
Now that the CLI and the Next.js app are one package, nesting it inside app/ served no purpose - the repo root itself becomes the published npm package. Merges app/.gitignore and app/README.md into the root versions, drops the now-duplicate app/LICENSE, and updates path references (README, docs/ARCHITECTURE.md, docs/CONFIG_REFERENCE.md, package.json's repository.directory) that assumed the app/ nesting. Also fixes a real bug this surfaced: the in-app docs viewer resolved docs/ relative to process.cwd(), which only worked by accident when the CLI happened to be invoked from app/'s parent directory. A first attempt at fixing it with import.meta.dirname broke instead, for the same cross-module-graph reason config-path resolution already documented - Next compiles Route Handlers through a separate module graph that doesn't preserve source-relative import.meta paths. Fixed by exposing the app root via TRIGGERSHELL_APP_ROOT (set once in server.ts, where import.meta *does* resolve correctly), the same pattern already used for TRIGGERSHELL_CONFIG_PATH. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
import "./src/bootstrap/async-local-storage-polyfill";
|
||||
import { createServer } from "node:http";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import next from "next";
|
||||
import { WebSocketServer } from "ws";
|
||||
import { getConfig } from "./src/lib/config/load";
|
||||
import { migrateOnBoot } from "./src/lib/db/client";
|
||||
import { syncAuthFromConfig } from "./src/lib/auth/sync";
|
||||
import { reconcileOrphanedRuns } from "./src/lib/runner/engine";
|
||||
import { killAllRuns } from "./src/lib/runner/registry";
|
||||
import { attachWsServer, authenticateUpgrade } from "./src/lib/ws/server";
|
||||
|
||||
const dev = process.env.NODE_ENV !== "production";
|
||||
const { config } = getConfig();
|
||||
|
||||
const port = Number(process.env.PORT ?? config.server.port);
|
||||
const hostname = process.env.HOST ?? config.server.host;
|
||||
|
||||
migrateOnBoot();
|
||||
syncAuthFromConfig();
|
||||
reconcileOrphanedRuns();
|
||||
|
||||
// `dir` must be this file's own directory, not `process.cwd()` - when launched by the installed
|
||||
// `triggershell` CLI, the working directory is wherever the user's config lives, not the package.
|
||||
const dir = path.dirname(fileURLToPath(import.meta.url));
|
||||
// Exposed via `process.env` (not just the local `dir` const) so Route Handlers/Server Components -
|
||||
// compiled through Next's own module graph, separate from this file's - can find it too. See
|
||||
// `docs.ts`'s use of this and the `globalThis` comment in `runner/events.ts` for the same reasoning.
|
||||
process.env.TRIGGERSHELL_APP_ROOT = dir;
|
||||
const app = next({ dev, dir, hostname, port });
|
||||
const handle = app.getRequestHandler();
|
||||
|
||||
app.prepare().then(() => {
|
||||
const nextUpgradeHandler = app.getUpgradeHandler();
|
||||
|
||||
const httpServer = createServer((req, res) => {
|
||||
handle(req, res);
|
||||
});
|
||||
|
||||
const wss = new WebSocketServer({ noServer: true });
|
||||
attachWsServer(wss);
|
||||
|
||||
httpServer.on("upgrade", (req, socket, head) => {
|
||||
const { pathname } = new URL(req.url ?? "/", "http://internal");
|
||||
if (pathname !== "/ws/runs") {
|
||||
// Anything else (e.g. Next's own dev-mode HMR websocket at /_next/hmr) is Next's to handle.
|
||||
nextUpgradeHandler(req, socket, head).catch(() => socket.destroy());
|
||||
return;
|
||||
}
|
||||
|
||||
authenticateUpgrade(req)
|
||||
.then((ok) => {
|
||||
if (!ok) {
|
||||
socket.write("HTTP/1.1 401 Unauthorized\r\n\r\n");
|
||||
socket.destroy();
|
||||
return;
|
||||
}
|
||||
wss.handleUpgrade(req, socket, head, (ws) => {
|
||||
wss.emit("connection", ws, req);
|
||||
});
|
||||
})
|
||||
.catch(() => socket.destroy());
|
||||
});
|
||||
|
||||
httpServer.listen(port, hostname, () => {
|
||||
console.log(
|
||||
`> triggershell ready on http://${hostname}:${port} (${dev ? "development" : "production"})`,
|
||||
);
|
||||
});
|
||||
|
||||
const shutdown = (signal: string) => {
|
||||
console.log(`> received ${signal}, shutting down...`);
|
||||
killAllRuns();
|
||||
httpServer.close(() => process.exit(0));
|
||||
// Force-exit if graceful shutdown hangs (e.g. a stuck WS connection).
|
||||
setTimeout(() => process.exit(1), 5000).unref();
|
||||
};
|
||||
|
||||
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
||||
process.on("SIGINT", () => shutdown("SIGINT"));
|
||||
});
|
||||
Reference in New Issue
Block a user