@warlock.js/devtools 5.31.0 → 5.33.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/cjs/ai-source-lia4YS30.cjs +212 -0
  3. package/cjs/ai-source-lia4YS30.cjs.map +1 -0
  4. package/cjs/index.cjs +2 -727
  5. package/cjs/{server-CQ0qhO8c.cjs → server-BNlyhwiR.cjs} +62 -3
  6. package/cjs/server-BNlyhwiR.cjs.map +1 -0
  7. package/cjs/src-CiNStw0i.cjs +699 -0
  8. package/cjs/src-CiNStw0i.cjs.map +1 -0
  9. package/esm/caller-location.mjs.map +1 -1
  10. package/esm/devtools-connector.d.mts +2 -4
  11. package/esm/devtools-connector.d.mts.map +1 -1
  12. package/esm/devtools-connector.mjs +6 -0
  13. package/esm/devtools-connector.mjs.map +1 -1
  14. package/esm/index.d.mts +2 -1
  15. package/esm/process-panel.mjs +16 -0
  16. package/esm/process-panel.mjs.map +1 -0
  17. package/esm/server/ai-routes.mjs +32 -0
  18. package/esm/server/ai-routes.mjs.map +1 -0
  19. package/esm/server/guard.mjs +1 -1
  20. package/esm/server/guard.mjs.map +1 -1
  21. package/esm/server/index.mjs +4 -0
  22. package/esm/server/index.mjs.map +1 -1
  23. package/esm/server/process-routes.mjs +11 -0
  24. package/esm/server/process-routes.mjs.map +1 -0
  25. package/esm/server/requests-routes.mjs +1 -0
  26. package/esm/server/requests-routes.mjs.map +1 -1
  27. package/esm/server/stream-route.mjs +4 -0
  28. package/esm/server/stream-route.mjs.map +1 -1
  29. package/esm/sources/ai-source.d.mts +29 -0
  30. package/esm/sources/ai-source.d.mts.map +1 -0
  31. package/esm/sources/ai-source.mjs +136 -0
  32. package/esm/sources/ai-source.mjs.map +1 -0
  33. package/esm/sources/log-source.mjs +1 -1
  34. package/esm/sources/query-source.mjs +1 -1
  35. package/esm/types.d.mts +45 -30
  36. package/esm/types.d.mts.map +1 -1
  37. package/esm/ui-root.mjs.map +1 -1
  38. package/llms-full.txt +85 -1
  39. package/llms.txt +1 -1
  40. package/package.json +9 -5
  41. package/skills/devtools-overview/SKILL.md +85 -1
  42. package/ui/app.css +13 -0
  43. package/ui/app.js +213 -16
  44. package/ui/index.html +2 -0
  45. package/cjs/index.cjs.map +0 -1
  46. package/cjs/server-CQ0qhO8c.cjs.map +0 -1
@@ -5,6 +5,19 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __exportAll = (all, no_symbols) => {
9
+ let target = {};
10
+ for (var name in all) {
11
+ __defProp(target, name, {
12
+ get: all[name],
13
+ enumerable: true
14
+ });
15
+ }
16
+ if (!no_symbols) {
17
+ __defProp(target, Symbol.toStringTag, { value: "Module" });
18
+ }
19
+ return target;
20
+ };
8
21
  var __copyProps = (to, from, except, desc) => {
9
22
  if (from && typeof from === "object" || typeof from === "function") {
10
23
  for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
@@ -19,17 +32,46 @@ var __copyProps = (to, from, except, desc) => {
19
32
  }
20
33
  return to;
21
34
  };
22
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
35
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
23
36
  value: mod,
24
37
  enumerable: true
25
38
  }) : target, mod));
26
39
 
27
40
  //#endregion
41
+ const require_ai_source = require("./ai-source-lia4YS30.cjs");
28
42
  let node_url = require("node:url");
29
43
  let node_path = require("node:path");
30
44
  node_path = __toESM(node_path, 1);
31
45
  let node_fs = require("node:fs");
32
46
 
47
+ //#region ../../packages/devtools/src/server/ai-routes.ts
48
+ /** Read-only AI metadata, inside the same development/loopback guard as every panel. */
49
+ function registerAiRoutes(server, deps) {
50
+ server.get("/api/ai", async (request, reply) => {
51
+ reply.header("Cache-Control", "no-store");
52
+ const source = deps.ai;
53
+ if (!source?.available) return {
54
+ available: false,
55
+ message: source?.message ?? "Install @warlock.js/ai and @warlock.js/ai-panoptic, then restart warlock dev. Import @warlock.js/ai-panoptic and enable ai.config({ panoptic: { observeAll: true } }). If already installed, check that both packages are compatible and can be loaded.",
56
+ runs: []
57
+ };
58
+ const filter = request.query.requestId === void 0 ? void 0 : { requestId: request.query.requestId };
59
+ return {
60
+ available: true,
61
+ runs: source.store.query(filter).map(source.summarize),
62
+ aggregate: source.store.aggregate(filter)
63
+ };
64
+ });
65
+ server.get("/api/ai/runs/:id", async (request, reply) => {
66
+ reply.header("Cache-Control", "no-store");
67
+ const source = deps.ai;
68
+ const trace = source?.available ? source.store.get(request.params.id) : void 0;
69
+ if (!trace) return reply.code(404).send();
70
+ return trace;
71
+ });
72
+ }
73
+
74
+ //#endregion
33
75
  //#region ../../packages/devtools/src/server/background-routes.ts
34
76
  /** Registers the route that returns work recorded outside any request. */
35
77
  function registerBackgroundRoutes(server, deps) {
@@ -73,7 +115,7 @@ function registerExplainRoute(server, deps) {
73
115
 
74
116
  //#endregion
75
117
  //#region ../../packages/devtools/src/server/guard.ts
76
- const LOOPBACK_ADDRESSES = new Set([
118
+ const LOOPBACK_ADDRESSES = /* @__PURE__ */ new Set([
77
119
  "127.0.0.1",
78
120
  "::1",
79
121
  "::ffff:127.0.0.1"
@@ -256,6 +298,15 @@ function registerOpenApiRoutes(server, deps) {
256
298
  });
257
299
  }
258
300
 
301
+ //#endregion
302
+ //#region ../../packages/devtools/src/server/process-routes.ts
303
+ function registerProcessRoutes(server, deps) {
304
+ server.get("/api/processes", async (_request, reply) => {
305
+ reply.header("cache-control", "no-store");
306
+ return deps.processPanel ? await deps.processPanel.list() : [];
307
+ });
308
+ }
309
+
259
310
  //#endregion
260
311
  //#region ../../packages/devtools/src/server/requests-routes.ts
261
312
  /** Registers the request list, single-request detail, and clear routes. */
@@ -271,6 +322,7 @@ function registerRequestsRoutes(server, deps) {
271
322
  });
272
323
  server.delete("/api/requests", async (_request, reply) => {
273
324
  deps.collector.clear();
325
+ if (deps.ai?.available) deps.ai.store.clear();
274
326
  reply.code(204).send();
275
327
  });
276
328
  }
@@ -303,11 +355,15 @@ function registerStreamRoute(server, deps) {
303
355
  const dispose = deps.collector.subscribe((event) => {
304
356
  res.write(`event: ${event.type}\ndata: ${JSON.stringify(event.data)}\n\n`);
305
357
  });
358
+ const disposeAi = deps.ai?.available ? deps.ai.subscribe((event) => {
359
+ res.write(`event: ai\ndata: ${JSON.stringify(event)}\n\n`);
360
+ }) : void 0;
306
361
  const pingTimer = setInterval(() => res.write(": ping\n\n"), PING_INTERVAL_MS);
307
362
  pingTimer.unref();
308
363
  request.raw.on("close", () => {
309
364
  clearInterval(pingTimer);
310
365
  dispose();
366
+ disposeAi?.();
311
367
  });
312
368
  });
313
369
  }
@@ -328,10 +384,12 @@ function mountDevtoolsRoutes(server, deps) {
328
384
  });
329
385
  registerUiAssets(instance);
330
386
  registerRequestsRoutes(instance, deps);
387
+ registerAiRoutes(instance, deps);
331
388
  registerBackgroundRoutes(instance, deps);
332
389
  registerMailRoutes(instance, deps);
333
390
  registerLogRoutes(instance, deps);
334
391
  registerRouteRoutes(instance, deps);
392
+ registerProcessRoutes(instance, deps);
335
393
  registerOpenApiRoutes(instance, deps);
336
394
  registerExplainRoute(instance, deps);
337
395
  registerStreamRoute(instance, deps);
@@ -339,5 +397,6 @@ function mountDevtoolsRoutes(server, deps) {
339
397
  }
340
398
 
341
399
  //#endregion
400
+ exports.__exportAll = __exportAll;
342
401
  exports.mountDevtoolsRoutes = mountDevtoolsRoutes;
343
- //# sourceMappingURL=server-CQ0qhO8c.cjs.map
402
+ //# sourceMappingURL=server-BNlyhwiR.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-BNlyhwiR.cjs","names":["path","existsSync","readFileSync","fileURLToPath","path","readFileSync","path"],"sources":["../../../../../../../packages/devtools/src/server/ai-routes.ts","../../../../../../../packages/devtools/src/server/background-routes.ts","../../../../../../../packages/devtools/src/server/explain-route.ts","../../../../../../../packages/devtools/src/server/guard.ts","../../../../../../../packages/devtools/src/server/log-routes.ts","../../../../../../../packages/devtools/src/server/mail-routes.ts","../../../../../../../packages/devtools/src/ui-root.ts","../../../../../../../packages/devtools/src/server/ui-assets.ts","../../../../../../../packages/devtools/src/server/openapi-routes.ts","../../../../../../../packages/devtools/src/server/process-routes.ts","../../../../../../../packages/devtools/src/server/requests-routes.ts","../../../../../../../packages/devtools/src/server/route-routes.ts","../../../../../../../packages/devtools/src/server/stream-route.ts","../../../../../../../packages/devtools/src/server/index.ts"],"sourcesContent":["import type { FastifyInstance } from \"fastify\";\nimport { AI_INSTALL_GUIDANCE } from \"../sources/ai-source\";\nimport type { MountDevtoolsRoutesDeps } from \"./types\";\n\n/** Read-only AI metadata, inside the same development/loopback guard as every panel. */\nexport function registerAiRoutes(server: FastifyInstance, deps: MountDevtoolsRoutesDeps): void {\n server.get<{ Querystring: { requestId?: string } }>(\"/api/ai\", async (request, reply) => {\n reply.header(\"Cache-Control\", \"no-store\");\n const source = deps.ai;\n if (!source?.available) {\n return { available: false, message: source?.message ?? AI_INSTALL_GUIDANCE, runs: [] };\n }\n const filter =\n request.query.requestId === undefined ? undefined : { requestId: request.query.requestId };\n return {\n available: true,\n runs: source.store.query(filter).map(source.summarize),\n aggregate: source.store.aggregate(filter),\n };\n });\n\n server.get<{ Params: { id: string } }>(\"/api/ai/runs/:id\", async (request, reply) => {\n reply.header(\"Cache-Control\", \"no-store\");\n const source = deps.ai;\n const trace = source?.available ? source.store.get(request.params.id) : undefined;\n if (!trace) return reply.code(404).send();\n return trace;\n });\n}\n","import type { FastifyInstance } from \"fastify\";\nimport type { MountDevtoolsRoutesDeps } from \"./types\";\n\n/** Registers the route that returns work recorded outside any request. */\nexport function registerBackgroundRoutes(\n server: FastifyInstance,\n deps: MountDevtoolsRoutesDeps,\n): void {\n server.get(\"/api/background\", async () => deps.collector.getBackground());\n}\n","import type { FastifyInstance } from \"fastify\";\nimport type { MountDevtoolsRoutesDeps } from \"./types\";\n\n/**\n * The value the logger's redaction substitutes for a censored leaf\n * (`logger/src/redact/redact.ts`, `DEFAULT_CENSOR`). Not exported from\n * `@warlock.js/logger`, so matched by literal here.\n */\nconst REDACTED_PLACEHOLDER = \"[REDACTED]\";\n\nfunction isExplainableSql(sql: string | undefined): boolean {\n return /^\\s*(select|with)\\b/i.test(sql ?? \"\");\n}\n\n/** Registers the EXPLAIN route: Postgres `SELECT`/`WITH` queries only. */\nexport function registerExplainRoute(server: FastifyInstance, deps: MountDevtoolsRoutesDeps): void {\n server.post<{ Params: { requestId: string; queryId: string } }>(\n \"/api/requests/:requestId/queries/:queryId/explain\",\n async (request, reply) => {\n const found = deps.collector.getRequest(request.params.requestId);\n const query = found?.queries.find((item) => item.id === request.params.queryId);\n\n if (!query) {\n reply.code(404).send();\n return;\n }\n\n if (query.driver !== \"postgres\" || !isExplainableSql(query.sql) || !deps.explain) {\n reply.code(400).send({ error: \"Only Postgres SELECT or WITH queries can be explained\" });\n return;\n }\n\n if (query.bindings?.some((binding) => binding === REDACTED_PLACEHOLDER)) {\n reply.code(400).send({ error: \"bindings redacted\" });\n return;\n }\n\n try {\n const plan = await deps.explain(query);\n return { plan };\n } catch (error) {\n reply.code(500).send({ error: error instanceof Error ? error.message : String(error) });\n }\n },\n );\n}\n","import type { FastifyInstance, FastifyReply, FastifyRequest } from \"fastify\";\nimport type { MountDevtoolsRoutesDeps } from \"./types\";\n\nconst LOOPBACK_ADDRESSES = new Set([\"127.0.0.1\", \"::1\", \"::ffff:127.0.0.1\"]);\n\n/**\n * Whether `address` is a loopback address. Deliberately reads\n * `request.socket.remoteAddress` rather than `request.ip`, which honours\n * `X-Forwarded-For` when the app trusts a proxy — a header any client can\n * set.\n */\nfunction isLoopbackAddress(address: string | undefined): boolean {\n return address !== undefined && LOOPBACK_ADDRESSES.has(address);\n}\n\n/**\n * Registers the dev-only, loopback-only guard as an `onRequest` hook on\n * `server`. Callers must register this inside an encapsulated Fastify\n * context (a plugin/prefix) so the hook never reaches routes outside the\n * dashboard.\n */\nexport function registerDevtoolsGuard(\n server: FastifyInstance,\n deps: MountDevtoolsRoutesDeps,\n): void {\n server.addHook(\"onRequest\", async (request: FastifyRequest, reply: FastifyReply) => {\n if (!deps.isDevelopment() || !isLoopbackAddress(request.socket.remoteAddress)) {\n // Returning the reply is what stops the lifecycle in an async hook;\n // without it Fastify still runs the handler after the 404 is sent.\n return reply.code(404).send();\n }\n });\n}\n","import type { FastifyInstance } from \"fastify\";\nimport type { DevtoolsLogEntry } from \"../types\";\nimport type { MountDevtoolsRoutesDeps } from \"./types\";\n\ntype LogsQuery = { level?: DevtoolsLogEntry[\"level\"]; module?: string };\n\n/** Registers the log listing route, filterable by `level` and `module`. */\nexport function registerLogRoutes(server: FastifyInstance, deps: MountDevtoolsRoutesDeps): void {\n server.get<{ Querystring: LogsQuery }>(\"/api/logs\", async (request) =>\n deps.collector.listLogs({ level: request.query.level, module: request.query.module }),\n );\n}\n","import type { FastifyInstance } from \"fastify\";\nimport type { MountDevtoolsRoutesDeps } from \"./types\";\n\nconst MAIL_HTML_CSP =\n \"sandbox; default-src 'none'; img-src data: https: http:; style-src 'unsafe-inline'\";\n\n/** Registers the mailbox list, single-mail detail, and mail HTML routes. */\nexport function registerMailRoutes(server: FastifyInstance, deps: MountDevtoolsRoutesDeps): void {\n server.get(\"/api/mails\", async () => deps.collector.listMails());\n\n server.get<{ Params: { id: string } }>(\"/api/mails/:id\", async (request, reply) => {\n const mail = deps.collector.getMail(request.params.id);\n\n if (!mail) {\n reply.code(404).send();\n return;\n }\n\n const { html, ...rest } = mail;\n return rest;\n });\n\n server.get<{ Params: { id: string } }>(\"/api/mails/:id/html\", async (request, reply) => {\n const mail = deps.collector.getMail(request.params.id);\n\n if (!mail || !mail.html) {\n reply.code(404).send();\n return;\n }\n\n reply\n .header(\"Content-Security-Policy\", MAIL_HTML_CSP)\n .header(\"X-Content-Type-Options\", \"nosniff\")\n .header(\"Content-Type\", \"text/html; charset=utf-8\")\n .send(mail.html);\n });\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nlet cachedUiRoot: string | undefined;\n\n/** Whether `dir` is this package's root: it has `ui/index.html` beside a `package.json` named `@warlock.js/devtools`. */\nfunction isPackageRoot(dir: string): boolean {\n const indexHtml = path.join(dir, \"ui\", \"index.html\");\n const packageJson = path.join(dir, \"package.json\");\n\n if (!existsSync(indexHtml) || !existsSync(packageJson)) {\n return false;\n }\n\n try {\n const parsed = JSON.parse(readFileSync(packageJson, \"utf8\")) as { name?: string };\n return parsed.name === \"@warlock.js/devtools\";\n } catch {\n return false;\n }\n}\n\n/**\n * Locate this package's `ui/` directory by walking up from the current\n * module's directory. Works from `src/` in development and from the built\n * `esm/`/`cjs/` output, since both sit beside `ui/` and `package.json` at\n * the package root.\n */\nexport function resolveUiRoot(): string {\n if (cachedUiRoot) {\n return cachedUiRoot;\n }\n\n let dir = path.dirname(fileURLToPath(import.meta.url));\n\n while (true) {\n if (isPackageRoot(dir)) {\n cachedUiRoot = path.join(dir, \"ui\");\n return cachedUiRoot;\n }\n\n const parent = path.dirname(dir);\n if (parent === dir) {\n throw new Error(\n \"Could not locate the devtools UI directory: no ancestor of \" +\n \"this module has a ui/index.html beside a package.json named \" +\n \"@warlock.js/devtools.\",\n );\n }\n\n dir = parent;\n }\n}\n","import { readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport type { FastifyInstance, FastifyReply } from \"fastify\";\nimport { resolveUiRoot } from \"../ui-root\";\n\n/**\n * Where an asset's bytes come from: a file in this package's `ui/` folder.\n */\ntype UiAsset = {\n contentType: string;\n file: () => string;\n};\n\nconst uiFile = (name: string) => () => path.join(resolveUiRoot(), name);\n\n/**\n * The only assets that can be requested. The request's asset name is looked\n * up here and never joined into a filesystem path.\n */\nconst UI_ASSETS: Record<string, UiAsset> = {\n \"app.js\": { contentType: \"text/javascript; charset=utf-8\", file: uiFile(\"app.js\") },\n \"app.css\": { contentType: \"text/css; charset=utf-8\", file: uiFile(\"app.css\") },\n \"scalar.js\": {\n contentType: \"text/javascript; charset=utf-8\",\n file: uiFile(\"vendor/scalar/standalone.js\"),\n },\n \"swagger-ui-bundle.js\": {\n contentType: \"text/javascript; charset=utf-8\",\n file: uiFile(\"vendor/swagger-ui/swagger-ui-bundle.js\"),\n },\n \"swagger-ui.css\": {\n contentType: \"text/css; charset=utf-8\",\n file: uiFile(\"vendor/swagger-ui/swagger-ui.css\"),\n },\n \"docs-swagger.js\": {\n contentType: \"text/javascript; charset=utf-8\",\n file: uiFile(\"docs-swagger.js\"),\n },\n};\n\n/** Sends `file` with `contentType` and no caching. */\nexport function sendFile(reply: FastifyReply, file: string, contentType: string): void {\n reply\n .header(\"Cache-Control\", \"no-store\")\n .header(\"Content-Type\", contentType)\n .send(readFileSync(file));\n}\n\n/**\n * Serves the static dashboard: `index.html` at the dashboard root and the\n * whitelisted assets (`app.js`, `app.css`, the vendored Scalar bundle as\n * `scalar.js`, and the vendored Swagger UI files plus their init script). The asset name is matched against a fixed whitelist — never\n * joined into a filesystem path — so no request can traverse outside it.\n */\nexport function registerUiAssets(server: FastifyInstance): void {\n const serveIndex = (_request: unknown, reply: FastifyReply): void => {\n sendFile(reply, path.join(resolveUiRoot(), \"index.html\"), \"text/html; charset=utf-8\");\n };\n\n server.get(\"/\", serveIndex);\n\n server.get<{ Params: { name: string } }>(\"/assets/:name\", (request, reply) => {\n const asset = Object.hasOwn(UI_ASSETS, request.params.name)\n ? UI_ASSETS[request.params.name]\n : undefined;\n\n if (!asset) {\n reply.code(404).header(\"Cache-Control\", \"no-store\").send();\n return;\n }\n\n sendFile(reply, asset.file(), asset.contentType);\n });\n}\n","import path from \"node:path\";\nimport type { FastifyInstance } from \"fastify\";\nimport { resolveUiRoot } from \"../ui-root\";\nimport type { MountDevtoolsRoutesDeps } from \"./types\";\nimport { sendFile } from \"./ui-assets\";\n\n/**\n * Registers the API docs: `GET /api/openapi.json` returns the document core\n * builds from the registered routes (`deps.getOpenApiDocument`), and\n * `GET /docs` serves the page that renders it with Scalar and\n * `GET /docs/swagger` the same document in Swagger UI;\n * `GET /api/postman.json` returns the Postman collection core builds\n * (`deps.getPostmanCollection`). The pages use relative URLs, so it works under whatever base path the dashboard is\n * mounted on.\n */\nexport function registerOpenApiRoutes(\n server: FastifyInstance,\n deps: MountDevtoolsRoutesDeps,\n): void {\n server.get(\"/api/openapi.json\", async (_request, reply) => {\n if (!deps.getOpenApiDocument) {\n return reply.code(503).header(\"Cache-Control\", \"no-store\").send({\n error: \"The OpenAPI document is not available: the host did not provide a generator.\",\n });\n }\n\n reply.header(\"Cache-Control\", \"no-store\");\n\n return deps.getOpenApiDocument();\n });\n\n server.get(\"/api/postman.json\", async (_request, reply) => {\n if (!deps.getPostmanCollection) {\n return reply.code(503).header(\"Cache-Control\", \"no-store\").send({\n error: \"The Postman collection is not available: the host did not provide a generator.\",\n });\n }\n\n reply.header(\"Cache-Control\", \"no-store\");\n\n return deps.getPostmanCollection();\n });\n\n server.get(\"/docs\", (_request, reply) => {\n sendFile(reply, path.join(resolveUiRoot(), \"docs.html\"), \"text/html; charset=utf-8\");\n });\n\n server.get(\"/docs/swagger\", (_request, reply) => {\n sendFile(reply, path.join(resolveUiRoot(), \"docs-swagger.html\"), \"text/html; charset=utf-8\");\n });\n}\n","import type { FastifyInstance } from \"fastify\";\nimport type { MountDevtoolsRoutesDeps } from \"./types\";\n\nexport function registerProcessRoutes(\n server: FastifyInstance,\n deps: MountDevtoolsRoutesDeps,\n): void {\n server.get(\"/api/processes\", async (_request, reply) => {\n reply.header(\"cache-control\", \"no-store\");\n return deps.processPanel ? await deps.processPanel.list() : [];\n });\n}\n","import type { FastifyInstance } from \"fastify\";\nimport type { MountDevtoolsRoutesDeps } from \"./types\";\n\n/** Registers the request list, single-request detail, and clear routes. */\nexport function registerRequestsRoutes(\n server: FastifyInstance,\n deps: MountDevtoolsRoutesDeps,\n): void {\n server.get(\"/api/requests\", async () => deps.collector.listRequests());\n\n server.get<{ Params: { id: string } }>(\"/api/requests/:id\", async (request, reply) => {\n const found = deps.collector.getRequest(request.params.id);\n\n if (!found) {\n reply.code(404).send();\n return;\n }\n\n return found;\n });\n\n server.delete(\"/api/requests\", async (_request, reply) => {\n deps.collector.clear();\n if (deps.ai?.available) deps.ai.store.clear();\n reply.code(204).send();\n });\n}\n","import type { FastifyInstance } from \"fastify\";\nimport type { MountDevtoolsRoutesDeps } from \"./types\";\n\n/** Registers the route map, sourced from core's router via `deps.listRoutes`. */\nexport function registerRouteRoutes(server: FastifyInstance, deps: MountDevtoolsRoutesDeps): void {\n server.get(\"/api/routes\", async () => (deps.listRoutes ? deps.listRoutes() : []));\n}\n","import type { FastifyInstance } from \"fastify\";\nimport type { MountDevtoolsRoutesDeps } from \"./types\";\n\nconst PING_INTERVAL_MS = 15_000;\n\n/**\n * Registers the SSE stream: one `event: <type>\\ndata: <json>\\n\\n` frame per\n * collector event, plus a `: ping` comment every 15s to keep intermediaries\n * from closing an idle connection. The reply is hijacked so Fastify never\n * tries to serialize or close the response itself.\n */\nexport function registerStreamRoute(server: FastifyInstance, deps: MountDevtoolsRoutesDeps): void {\n server.get(\"/api/stream\", async (request, reply) => {\n reply.hijack();\n const res = reply.raw;\n\n res.writeHead(200, {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-store\",\n Connection: \"keep-alive\",\n });\n\n const dispose = deps.collector.subscribe((event) => {\n res.write(`event: ${event.type}\\ndata: ${JSON.stringify(event.data)}\\n\\n`);\n });\n\n const disposeAi = deps.ai?.available\n ? deps.ai.subscribe((event) => {\n res.write(`event: ai\\ndata: ${JSON.stringify(event)}\\n\\n`);\n })\n : undefined;\n\n const pingTimer = setInterval(() => res.write(\": ping\\n\\n\"), PING_INTERVAL_MS);\n pingTimer.unref();\n\n request.raw.on(\"close\", () => {\n clearInterval(pingTimer);\n dispose();\n disposeAi?.();\n });\n });\n}\n","import type { FastifyError, FastifyInstance } from \"fastify\";\nimport { registerAiRoutes } from \"./ai-routes\";\nimport { registerBackgroundRoutes } from \"./background-routes\";\nimport { registerExplainRoute } from \"./explain-route\";\nimport { registerDevtoolsGuard } from \"./guard\";\nimport { registerLogRoutes } from \"./log-routes\";\nimport { registerMailRoutes } from \"./mail-routes\";\nimport { registerOpenApiRoutes } from \"./openapi-routes\";\nimport { registerProcessRoutes } from \"./process-routes\";\nimport { registerRequestsRoutes } from \"./requests-routes\";\nimport { registerRouteRoutes } from \"./route-routes\";\nimport { registerStreamRoute } from \"./stream-route\";\nimport type { MountDevtoolsRoutesDeps } from \"./types\";\nimport { registerUiAssets } from \"./ui-assets\";\n\nexport type { DevtoolsRouteRow, MountDevtoolsRoutesDeps } from \"./types\";\n\n/**\n * Mounts the devtools dashboard and its API under `deps.options.path` on\n * `server`. Every route is registered inside a single encapsulated Fastify\n * context so the dev-only, loopback-only guard never reaches the app's\n * other routes.\n */\nexport function mountDevtoolsRoutes(server: FastifyInstance, deps: MountDevtoolsRoutesDeps): void {\n server.register(\n async (instance) => {\n registerDevtoolsGuard(instance, deps);\n\n instance.setErrorHandler((error: FastifyError, _request, reply) => {\n reply.code(error.statusCode ?? 500).send({ error: error.message });\n });\n\n registerUiAssets(instance);\n registerRequestsRoutes(instance, deps);\n registerAiRoutes(instance, deps);\n registerBackgroundRoutes(instance, deps);\n registerMailRoutes(instance, deps);\n registerLogRoutes(instance, deps);\n registerRouteRoutes(instance, deps);\n registerProcessRoutes(instance, deps);\n registerOpenApiRoutes(instance, deps);\n registerExplainRoute(instance, deps);\n registerStreamRoute(instance, deps);\n },\n { prefix: deps.options.path },\n );\n}\n"],"mappings":"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"}