@warlock.js/devtools 5.29.0 → 5.31.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 (64) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/cjs/index.cjs +14 -14
  3. package/cjs/index.cjs.map +1 -1
  4. package/cjs/{server-6mVWfWkG.cjs → server-CQ0qhO8c.cjs} +13 -13
  5. package/cjs/server-CQ0qhO8c.cjs.map +1 -0
  6. package/esm/caller-location.mjs +1 -1
  7. package/esm/caller-location.mjs.map +1 -1
  8. package/esm/collector.mjs +1 -1
  9. package/esm/collector.mjs.map +1 -1
  10. package/esm/current-request-id.mjs +1 -1
  11. package/esm/current-request-id.mjs.map +1 -1
  12. package/esm/devtools-connector.d.mts +1 -1
  13. package/esm/devtools-connector.d.mts.map +1 -1
  14. package/esm/devtools-connector.mjs +1 -1
  15. package/esm/devtools-connector.mjs.map +1 -1
  16. package/esm/n-plus-one.mjs +1 -1
  17. package/esm/n-plus-one.mjs.map +1 -1
  18. package/esm/options.mjs +1 -1
  19. package/esm/options.mjs.map +1 -1
  20. package/esm/query-shape.mjs +1 -1
  21. package/esm/query-shape.mjs.map +1 -1
  22. package/esm/safe-value.mjs +1 -1
  23. package/esm/safe-value.mjs.map +1 -1
  24. package/esm/server/background-routes.mjs +1 -1
  25. package/esm/server/background-routes.mjs.map +1 -1
  26. package/esm/server/explain-route.mjs +1 -1
  27. package/esm/server/explain-route.mjs.map +1 -1
  28. package/esm/server/guard.mjs +1 -1
  29. package/esm/server/guard.mjs.map +1 -1
  30. package/esm/server/index.mjs +1 -1
  31. package/esm/server/index.mjs.map +1 -1
  32. package/esm/server/log-routes.mjs +1 -1
  33. package/esm/server/log-routes.mjs.map +1 -1
  34. package/esm/server/mail-routes.mjs +1 -1
  35. package/esm/server/mail-routes.mjs.map +1 -1
  36. package/esm/server/openapi-routes.mjs +1 -1
  37. package/esm/server/openapi-routes.mjs.map +1 -1
  38. package/esm/server/requests-routes.mjs +1 -1
  39. package/esm/server/requests-routes.mjs.map +1 -1
  40. package/esm/server/route-routes.mjs +1 -1
  41. package/esm/server/route-routes.mjs.map +1 -1
  42. package/esm/server/stream-route.mjs +1 -1
  43. package/esm/server/stream-route.mjs.map +1 -1
  44. package/esm/server/ui-assets.mjs +1 -1
  45. package/esm/server/ui-assets.mjs.map +1 -1
  46. package/esm/sources/cache-source.mjs +1 -1
  47. package/esm/sources/cache-source.mjs.map +1 -1
  48. package/esm/sources/log-source.mjs +1 -1
  49. package/esm/sources/log-source.mjs.map +1 -1
  50. package/esm/sources/mail-source.mjs +1 -1
  51. package/esm/sources/mail-source.mjs.map +1 -1
  52. package/esm/sources/query-source.mjs +1 -1
  53. package/esm/sources/query-source.mjs.map +1 -1
  54. package/esm/sources/tracing-source.mjs +1 -1
  55. package/esm/sources/tracing-source.mjs.map +1 -1
  56. package/esm/types.d.mts +1 -1
  57. package/esm/types.d.mts.map +1 -1
  58. package/esm/ui-root.mjs +1 -1
  59. package/esm/ui-root.mjs.map +1 -1
  60. package/llms-full.txt +22 -10
  61. package/package.json +7 -6
  62. package/skills/devtools-overview/SKILL.md +22 -10
  63. package/ui/app.css +1 -6
  64. package/cjs/server-6mVWfWkG.cjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"query-source.mjs","names":[],"sources":["../../../../../../../devtools/src/sources/query-source.ts"],"sourcesContent":["import { applyRedact, log } from \"@warlock.js/logger\";\nimport { captureCallerLocation } from \"../caller-location\";\nimport { currentRequestId } from \"../current-request-id\";\nimport { toSafeValue } from \"../safe-value\";\nimport type { DevtoolsCollector, DevtoolsDisposer } from \"../types\";\n\n/** The shape of the event `dataSourceRegistry` emits for `\"query\"`. */\ntype QueryEvent = {\n connection: string;\n driver: \"postgres\" | \"mongodb\";\n sql?: string;\n bindings?: unknown[];\n collection?: string;\n command?: string;\n pipeline?: unknown;\n durationMs: number;\n startedAt: number;\n rowCount?: number;\n error?: unknown;\n};\n\n/** Redacts query bindings through the logger's redaction rules. */\nfunction redactBindings(bindings: unknown[] | undefined): unknown[] | undefined {\n if (!bindings) return bindings;\n\n const redacted = applyRedact(\n {\n type: \"debug\",\n module: \"devtools\",\n action: \"query\",\n message: undefined,\n context: { bindings },\n },\n log.getRedact(),\n );\n\n return (redacted.context as { bindings: unknown[] }).bindings;\n}\n\n/**\n * Feeds every settled database query, from cascade's data source registry,\n * into the collector. A no-op when `@warlock.js/cascade` isn't installed —\n * it is an optional peer.\n */\nexport async function attachQuerySource(collector: DevtoolsCollector): Promise<DevtoolsDisposer> {\n let dataSourceRegistry: {\n on(event: \"query\", listener: (event: QueryEvent) => void): void;\n off(event: \"query\", listener: (event: QueryEvent) => void): void;\n };\n\n try {\n ({ dataSourceRegistry } = await import(\"@warlock.js/cascade\"));\n } catch {\n return () => {};\n }\n\n const listener = (event: QueryEvent) => {\n collector.addQuery(currentRequestId(), {\n connection: event.connection,\n driver: event.driver,\n sql: event.sql,\n bindings: toSafeValue(redactBindings(event.bindings)) as unknown[] | undefined,\n collection: event.collection,\n command: event.command,\n pipeline: event.pipeline,\n startedAt: event.startedAt,\n durationMs: event.durationMs,\n rowCount: event.rowCount,\n error:\n event.error === undefined\n ? undefined\n : event.error instanceof Error\n ? event.error.message\n : String(event.error),\n caller: captureCallerLocation(),\n });\n };\n\n dataSourceRegistry.on(\"query\", listener);\n\n return () => dataSourceRegistry.off(\"query\", listener);\n}\n"],"mappings":";;;;;;;AAsBA,SAAS,eAAe,UAAwD;CAC9E,IAAI,CAAC,UAAU,OAAO;CAatB,OAXiB,YACf;EACE,MAAM;EACN,QAAQ;EACR,QAAQ;EACR,SAAS;EACT,SAAS,EAAE,SAAS;CACtB,GACA,IAAI,UAAU,CAGD,CAAC,CAAC,QAAoC;AACvD;;;;;;AAOA,eAAsB,kBAAkB,WAAyD;CAC/F,IAAI;CAKJ,IAAI;EACF,CAAC,CAAE,sBAAuB,MAAM,OAAO;CACzC,QAAQ;EACN,aAAa,CAAC;CAChB;CAEA,MAAM,YAAY,UAAsB;EACtC,UAAU,SAAS,iBAAiB,GAAG;GACrC,YAAY,MAAM;GAClB,QAAQ,MAAM;GACd,KAAK,MAAM;GACX,UAAU,YAAY,eAAe,MAAM,QAAQ,CAAC;GACpD,YAAY,MAAM;GAClB,SAAS,MAAM;GACf,UAAU,MAAM;GAChB,WAAW,MAAM;GACjB,YAAY,MAAM;GAClB,UAAU,MAAM;GAChB,OACE,MAAM,UAAU,SACZ,SACA,MAAM,iBAAiB,QACrB,MAAM,MAAM,UACZ,OAAO,MAAM,KAAK;GAC1B,QAAQ,sBAAsB;EAChC,CAAC;CACH;CAEA,mBAAmB,GAAG,SAAS,QAAQ;CAEvC,aAAa,mBAAmB,IAAI,SAAS,QAAQ;AACvD"}
1
+ {"version":3,"file":"query-source.mjs","names":[],"sources":["../../../../../../../../packages/devtools/src/sources/query-source.ts"],"sourcesContent":["import { applyRedact, log } from \"@warlock.js/logger\";\nimport { captureCallerLocation } from \"../caller-location\";\nimport { currentRequestId } from \"../current-request-id\";\nimport { toSafeValue } from \"../safe-value\";\nimport type { DevtoolsCollector, DevtoolsDisposer } from \"../types\";\n\n/** The shape of the event `dataSourceRegistry` emits for `\"query\"`. */\ntype QueryEvent = {\n connection: string;\n driver: \"postgres\" | \"mongodb\";\n sql?: string;\n bindings?: unknown[];\n collection?: string;\n command?: string;\n pipeline?: unknown;\n durationMs: number;\n startedAt: number;\n rowCount?: number;\n error?: unknown;\n};\n\n/** Redacts query bindings through the logger's redaction rules. */\nfunction redactBindings(bindings: unknown[] | undefined): unknown[] | undefined {\n if (!bindings) return bindings;\n\n const redacted = applyRedact(\n {\n type: \"debug\",\n module: \"devtools\",\n action: \"query\",\n message: undefined,\n context: { bindings },\n },\n log.getRedact(),\n );\n\n return (redacted.context as { bindings: unknown[] }).bindings;\n}\n\n/**\n * Feeds every settled database query, from cascade's data source registry,\n * into the collector. A no-op when `@warlock.js/cascade` isn't installed —\n * it is an optional peer.\n */\nexport async function attachQuerySource(collector: DevtoolsCollector): Promise<DevtoolsDisposer> {\n let dataSourceRegistry: {\n on(event: \"query\", listener: (event: QueryEvent) => void): void;\n off(event: \"query\", listener: (event: QueryEvent) => void): void;\n };\n\n try {\n ({ dataSourceRegistry } = await import(\"@warlock.js/cascade\"));\n } catch {\n return () => {};\n }\n\n const listener = (event: QueryEvent) => {\n collector.addQuery(currentRequestId(), {\n connection: event.connection,\n driver: event.driver,\n sql: event.sql,\n bindings: toSafeValue(redactBindings(event.bindings)) as unknown[] | undefined,\n collection: event.collection,\n command: event.command,\n pipeline: event.pipeline,\n startedAt: event.startedAt,\n durationMs: event.durationMs,\n rowCount: event.rowCount,\n error:\n event.error === undefined\n ? undefined\n : event.error instanceof Error\n ? event.error.message\n : String(event.error),\n caller: captureCallerLocation(),\n });\n };\n\n dataSourceRegistry.on(\"query\", listener);\n\n return () => dataSourceRegistry.off(\"query\", listener);\n}\n"],"mappings":";;;;;;;AAsBA,SAAS,eAAe,UAAwD;CAC9E,IAAI,CAAC,UAAU,OAAO;CAatB,OAXiB,YACf;EACE,MAAM;EACN,QAAQ;EACR,QAAQ;EACR,SAAS;EACT,SAAS,EAAE,SAAS;CACtB,GACA,IAAI,UAAU,CAGD,CAAC,CAAC,QAAoC;AACvD;;;;;;AAOA,eAAsB,kBAAkB,WAAyD;CAC/F,IAAI;CAKJ,IAAI;EACF,CAAC,CAAE,sBAAuB,MAAM,OAAO;CACzC,QAAQ;EACN,aAAa,CAAC;CAChB;CAEA,MAAM,YAAY,UAAsB;EACtC,UAAU,SAAS,iBAAiB,GAAG;GACrC,YAAY,MAAM;GAClB,QAAQ,MAAM;GACd,KAAK,MAAM;GACX,UAAU,YAAY,eAAe,MAAM,QAAQ,CAAC;GACpD,YAAY,MAAM;GAClB,SAAS,MAAM;GACf,UAAU,MAAM;GAChB,WAAW,MAAM;GACjB,YAAY,MAAM;GAClB,UAAU,MAAM;GAChB,OACE,MAAM,UAAU,SACZ,SACA,MAAM,iBAAiB,QACrB,MAAM,MAAM,UACZ,OAAO,MAAM,KAAK;GAC1B,QAAQ,sBAAsB;EAChC,CAAC;CACH;CAEA,mBAAmB,GAAG,SAAS,QAAQ;CAEvC,aAAa,mBAAmB,IAAI,SAAS,QAAQ;AACvD"}
@@ -1,6 +1,6 @@
1
1
  import { toSafeValue } from "../safe-value.mjs";
2
2
 
3
- //#region ../devtools/src/sources/tracing-source.ts
3
+ //#region ../../packages/devtools/src/sources/tracing-source.ts
4
4
  /**
5
5
  * Feeds request timelines from core's tracing hooks into the collector: one
6
6
  * `startRequest`/`endRequest` pair per HTTP request, with every named phase
@@ -1 +1 @@
1
- {"version":3,"file":"tracing-source.mjs","names":[],"sources":["../../../../../../../devtools/src/sources/tracing-source.ts"],"sourcesContent":["import type { TracingContext, TracingPhaseInfo, TracingRequestEndInfo } from \"@warlock.js/core\";\nimport { toSafeValue } from \"../safe-value\";\nimport type { DevtoolsCollector, DevtoolsDisposer, ResolvedDevtoolsOptions } from \"../types\";\n\n/**\n * Feeds request timelines from core's tracing hooks into the collector: one\n * `startRequest`/`endRequest` pair per HTTP request, with every named phase\n * in between. Requests to the dashboard's own path are never recorded, so\n * the dashboard never watches itself.\n */\nexport async function attachTracingSource(\n collector: DevtoolsCollector,\n options: ResolvedDevtoolsOptions,\n): Promise<DevtoolsDisposer> {\n const { registerTracingHooks } = await import(\"@warlock.js/core\");\n\n const isDashboardPath = (path: string): boolean => path.startsWith(options.path);\n\n return registerTracingHooks({\n onRequestStart(ctx: TracingContext) {\n if (isDashboardPath(ctx.path)) return;\n\n collector.startRequest({\n id: ctx.requestId,\n method: ctx.method,\n path: ctx.path,\n route: ctx.route,\n startedAt: performance.timeOrigin + performance.now(),\n });\n },\n onPhase(ctx: TracingContext, phase: TracingPhaseInfo) {\n if (isDashboardPath(ctx.path)) return;\n\n collector.addPhase(ctx.requestId, {\n name: phase.name,\n durationMs: phase.durationMs,\n startedAt: phase.startedAt ?? performance.timeOrigin + performance.now() - phase.durationMs,\n attrs: phase.attrs === undefined ? undefined : (toSafeValue(phase.attrs) as Record<string, unknown>),\n });\n },\n onRequestEnd(ctx: TracingContext, result: TracingRequestEndInfo) {\n if (isDashboardPath(ctx.path)) return;\n\n collector.endRequest(ctx.requestId, {\n status: result.status,\n durationMs: result.durationMs,\n error:\n result.error === undefined\n ? undefined\n : result.error instanceof Error\n ? result.error.message\n : String(result.error),\n route: ctx.route,\n });\n },\n });\n}\n"],"mappings":";;;;;;;;;AAUA,eAAsB,oBACpB,WACA,SAC2B;CAC3B,MAAM,EAAE,yBAAyB,MAAM,OAAO;CAE9C,MAAM,mBAAmB,SAA0B,KAAK,WAAW,QAAQ,IAAI;CAE/E,OAAO,qBAAqB;EAC1B,eAAe,KAAqB;GAClC,IAAI,gBAAgB,IAAI,IAAI,GAAG;GAE/B,UAAU,aAAa;IACrB,IAAI,IAAI;IACR,QAAQ,IAAI;IACZ,MAAM,IAAI;IACV,OAAO,IAAI;IACX,WAAW,YAAY,aAAa,YAAY,IAAI;GACtD,CAAC;EACH;EACA,QAAQ,KAAqB,OAAyB;GACpD,IAAI,gBAAgB,IAAI,IAAI,GAAG;GAE/B,UAAU,SAAS,IAAI,WAAW;IAChC,MAAM,MAAM;IACZ,YAAY,MAAM;IAClB,WAAW,MAAM,aAAa,YAAY,aAAa,YAAY,IAAI,IAAI,MAAM;IACjF,OAAO,MAAM,UAAU,SAAY,SAAa,YAAY,MAAM,KAAK;GACzE,CAAC;EACH;EACA,aAAa,KAAqB,QAA+B;GAC/D,IAAI,gBAAgB,IAAI,IAAI,GAAG;GAE/B,UAAU,WAAW,IAAI,WAAW;IAClC,QAAQ,OAAO;IACf,YAAY,OAAO;IACnB,OACE,OAAO,UAAU,SACb,SACA,OAAO,iBAAiB,QACtB,OAAO,MAAM,UACb,OAAO,OAAO,KAAK;IAC3B,OAAO,IAAI;GACb,CAAC;EACH;CACF,CAAC;AACH"}
1
+ {"version":3,"file":"tracing-source.mjs","names":[],"sources":["../../../../../../../../packages/devtools/src/sources/tracing-source.ts"],"sourcesContent":["import type { TracingContext, TracingPhaseInfo, TracingRequestEndInfo } from \"@warlock.js/core\";\nimport { toSafeValue } from \"../safe-value\";\nimport type { DevtoolsCollector, DevtoolsDisposer, ResolvedDevtoolsOptions } from \"../types\";\n\n/**\n * Feeds request timelines from core's tracing hooks into the collector: one\n * `startRequest`/`endRequest` pair per HTTP request, with every named phase\n * in between. Requests to the dashboard's own path are never recorded, so\n * the dashboard never watches itself.\n */\nexport async function attachTracingSource(\n collector: DevtoolsCollector,\n options: ResolvedDevtoolsOptions,\n): Promise<DevtoolsDisposer> {\n const { registerTracingHooks } = await import(\"@warlock.js/core\");\n\n const isDashboardPath = (path: string): boolean => path.startsWith(options.path);\n\n return registerTracingHooks({\n onRequestStart(ctx: TracingContext) {\n if (isDashboardPath(ctx.path)) return;\n\n collector.startRequest({\n id: ctx.requestId,\n method: ctx.method,\n path: ctx.path,\n route: ctx.route,\n startedAt: performance.timeOrigin + performance.now(),\n });\n },\n onPhase(ctx: TracingContext, phase: TracingPhaseInfo) {\n if (isDashboardPath(ctx.path)) return;\n\n collector.addPhase(ctx.requestId, {\n name: phase.name,\n durationMs: phase.durationMs,\n startedAt: phase.startedAt ?? performance.timeOrigin + performance.now() - phase.durationMs,\n attrs:\n phase.attrs === undefined\n ? undefined\n : (toSafeValue(phase.attrs) as Record<string, unknown>),\n });\n },\n onRequestEnd(ctx: TracingContext, result: TracingRequestEndInfo) {\n if (isDashboardPath(ctx.path)) return;\n\n collector.endRequest(ctx.requestId, {\n status: result.status,\n durationMs: result.durationMs,\n error:\n result.error === undefined\n ? undefined\n : result.error instanceof Error\n ? result.error.message\n : String(result.error),\n route: ctx.route,\n });\n },\n });\n}\n"],"mappings":";;;;;;;;;AAUA,eAAsB,oBACpB,WACA,SAC2B;CAC3B,MAAM,EAAE,yBAAyB,MAAM,OAAO;CAE9C,MAAM,mBAAmB,SAA0B,KAAK,WAAW,QAAQ,IAAI;CAE/E,OAAO,qBAAqB;EAC1B,eAAe,KAAqB;GAClC,IAAI,gBAAgB,IAAI,IAAI,GAAG;GAE/B,UAAU,aAAa;IACrB,IAAI,IAAI;IACR,QAAQ,IAAI;IACZ,MAAM,IAAI;IACV,OAAO,IAAI;IACX,WAAW,YAAY,aAAa,YAAY,IAAI;GACtD,CAAC;EACH;EACA,QAAQ,KAAqB,OAAyB;GACpD,IAAI,gBAAgB,IAAI,IAAI,GAAG;GAE/B,UAAU,SAAS,IAAI,WAAW;IAChC,MAAM,MAAM;IACZ,YAAY,MAAM;IAClB,WAAW,MAAM,aAAa,YAAY,aAAa,YAAY,IAAI,IAAI,MAAM;IACjF,OACE,MAAM,UAAU,SACZ,SACC,YAAY,MAAM,KAAK;GAChC,CAAC;EACH;EACA,aAAa,KAAqB,QAA+B;GAC/D,IAAI,gBAAgB,IAAI,IAAI,GAAG;GAE/B,UAAU,WAAW,IAAI,WAAW;IAClC,QAAQ,OAAO;IACf,YAAY,OAAO;IACnB,OACE,OAAO,UAAU,SACb,SACA,OAAO,iBAAiB,QACtB,OAAO,MAAM,UACb,OAAO,OAAO,KAAK;IAC3B,OAAO,IAAI;GACb,CAAC;EACH;CACF,CAAC;AACH"}
package/esm/types.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- //#region ../devtools/src/types.d.ts
1
+ //#region ../../packages/devtools/src/types.d.ts
2
2
  /**
3
3
  * The records the devtools collector keeps and the dashboard API returns.
4
4
  *
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.mts","names":[],"sources":["../../../../../../devtools/src/types.ts"],"mappings":"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"}
1
+ {"version":3,"file":"types.d.mts","names":[],"sources":["../../../../../../../packages/devtools/src/types.ts"],"mappings":"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"}
package/esm/ui-root.mjs CHANGED
@@ -2,7 +2,7 @@ import { fileURLToPath } from "node:url";
2
2
  import path from "node:path";
3
3
  import { existsSync, readFileSync } from "node:fs";
4
4
 
5
- //#region ../devtools/src/ui-root.ts
5
+ //#region ../../packages/devtools/src/ui-root.ts
6
6
  let cachedUiRoot;
7
7
  /** Whether `dir` is this package's root: it has `ui/index.html` beside a `package.json` named `@warlock.js/devtools`. */
8
8
  function isPackageRoot(dir) {
@@ -1 +1 @@
1
- {"version":3,"file":"ui-root.mjs","names":[],"sources":["../../../../../../devtools/src/ui-root.ts"],"sourcesContent":["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"],"mappings":";;;;;AAIA,IAAI;;AAGJ,SAAS,cAAc,KAAsB;CAC3C,MAAM,YAAY,KAAK,KAAK,KAAK,MAAM,YAAY;CACnD,MAAM,cAAc,KAAK,KAAK,KAAK,cAAc;CAEjD,IAAI,CAAC,WAAW,SAAS,KAAK,CAAC,WAAW,WAAW,GACnD,OAAO;CAGT,IAAI;EAEF,OADe,KAAK,MAAM,aAAa,aAAa,MAAM,CAC9C,CAAC,CAAC,SAAS;CACzB,QAAQ;EACN,OAAO;CACT;AACF;;;;;;;AAQA,SAAgB,gBAAwB;CACtC,IAAI,cACF,OAAO;CAGT,IAAI,MAAM,KAAK,QAAQ,cAAc,OAAO,KAAK,GAAG,CAAC;CAErD,OAAO,MAAM;EACX,IAAI,cAAc,GAAG,GAAG;GACtB,eAAe,KAAK,KAAK,KAAK,IAAI;GAClC,OAAO;EACT;EAEA,MAAM,SAAS,KAAK,QAAQ,GAAG;EAC/B,IAAI,WAAW,KACb,MAAM,IAAI,MACR,8IAGF;EAGF,MAAM;CACR;AACF"}
1
+ {"version":3,"file":"ui-root.mjs","names":[],"sources":["../../../../../../../packages/devtools/src/ui-root.ts"],"sourcesContent":["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"],"mappings":";;;;;AAIA,IAAI;;AAGJ,SAAS,cAAc,KAAsB;CAC3C,MAAM,YAAY,KAAK,KAAK,KAAK,MAAM,YAAY;CACnD,MAAM,cAAc,KAAK,KAAK,KAAK,cAAc;CAEjD,IAAI,CAAC,WAAW,SAAS,KAAK,CAAC,WAAW,WAAW,GACnD,OAAO;CAGT,IAAI;EAEF,OADe,KAAK,MAAM,aAAa,aAAa,MAAM,CAC9C,CAAC,CAAC,SAAS;CACzB,QAAQ;EACN,OAAO;CACT;AACF;;;;;;;AAQA,SAAgB,gBAAwB;CACtC,IAAI,cACF,OAAO;CAGT,IAAI,MAAM,KAAK,QAAQ,cAAc,OAAO,KAAK,GAAG,CAAC;CAErD,OAAO,MAAM;EACX,IAAI,cAAc,GAAG,GAAG;GACtB,eAAe,KAAK,KAAK,KAAK,IAAI;GAClC,OAAO;EACT;EAEA,MAAM,SAAS,KAAK,QAAQ,GAAG;EAC/B,IAAI,WAAW,KACb,MAAM,IAAI,MACR,8IAGF;EAGF,MAAM;CACR;AACF"}
package/llms-full.txt CHANGED
@@ -44,16 +44,16 @@ of it would fail to resolve there.
44
44
 
45
45
  ## What each panel shows
46
46
 
47
- | Panel | What you see | Where it comes from |
48
- |---|---|---|
49
- | **Requests** | Each request with its status, duration and query count. Click one for a waterfall: router middleware, `page.middleware`, loaders, `page.cache` hit/miss, `render.shell`, `defer.settle`, with queries and cache ops placed on the same time axis. | core `registerTracingHooks()` |
50
- | **Queries** | SQL + bindings or the Mongo command, duration, rows, and an **Explain** button (Postgres `SELECT` only; runs `EXPLAIN (FORMAT JSON)`, never `ANALYZE`) | cascade `dataSourceRegistry.on("query")` |
51
- | **N+1** | `⚠ N+1: 12× "select … where post_id = $1" — src/app/posts/services/list-posts.service.ts:18`, shown on the request and printed in the terminal | same query shape ≥ 5 times in one request |
52
- | **Mail** | Every mail sent in development: headers, HTML (sandboxed) and text, attachment names | core `mailEvents.onCaptured()` |
53
- | **Logs** | Log entries per request, filterable by level and module | a logger channel |
54
- | **Cache** | hit / miss / set / removed / `invalidated` (tags, keys removed) | cache `cache.on(...)` |
55
- | **Routes** | Every HTTP route with its method, path, name and middleware | core router |
56
- | **API** | The app's API reference: every route with its parameters, request body, responses and auth | core `getDevelopmentOpenApiDocument()` |
47
+ | Panel | What you see | Where it comes from |
48
+ | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------- |
49
+ | **Requests** | Each request with its status, duration and query count. Click one for a waterfall: router middleware, `page.middleware`, loaders, `page.cache` hit/miss, `render.shell`, `defer.settle`, with queries and cache ops placed on the same time axis. | core `registerTracingHooks()` |
50
+ | **Queries** | SQL + bindings or the Mongo command, duration, rows, and an **Explain** button (Postgres `SELECT` only; runs `EXPLAIN (FORMAT JSON)`, never `ANALYZE`) | cascade `dataSourceRegistry.on("query")` |
51
+ | **N+1** | `⚠ N+1: 12× "select … where post_id = $1" — src/app/posts/services/list-posts.service.ts:18`, shown on the request and printed in the terminal | same query shape ≥ 5 times in one request |
52
+ | **Mail** | Every mail sent in development: headers, HTML (sandboxed) and text, attachment names | core `mailEvents.onCaptured()` |
53
+ | **Logs** | Log entries per request, filterable by level and module | a logger channel |
54
+ | **Cache** | hit / miss / set / removed / `invalidated` (tags, keys removed) | cache `cache.on(...)` |
55
+ | **Routes** | Every HTTP route with its method, path, name and middleware | core router |
56
+ | **API** | The app's API reference: every route with its parameters, request body, responses and auth | core `getDevelopmentOpenApiDocument()` |
57
57
 
58
58
  Work outside a request (boot, scheduler ticks, queue jobs) goes to a separate
59
59
  background list, so it never clutters a request's timeline.
@@ -75,6 +75,18 @@ background list, so it never clutters a request's timeline.
75
75
  kept, and an N+1 threshold of 5. Everything lives in memory and is gone on
76
76
  restart.
77
77
 
78
+ ## From the terminal (agents)
79
+
80
+ `npx warlock trace POST /posts --body '{"title":"Hi"}' --json` sends one
81
+ request to the running dev server and prints this dashboard's record of it as
82
+ JSON — middleware, validation result, queries with N+1 flags, logs, response
83
+ and timings. See the `warlock-trace` skill of `@warlock.js/core`.
84
+
85
+ `npx warlock mcp` (or `npx warlock dev --mcp`) gives a coding agent the same
86
+ records through its `requests_recent` tool: the newest requests with their
87
+ phases, queries flagged `nPlusOne`, warnings, logs and timings. See the
88
+ `warlock-mcp` skill of `@warlock.js/core`.
89
+
78
90
  ## Secrets
79
91
 
80
92
  Query bindings and log context go through the logger's redaction rules
package/package.json CHANGED
@@ -5,10 +5,10 @@
5
5
  "environment": "server"
6
6
  },
7
7
  "peerDependencies": {
8
- "@warlock.js/cache": "5.29.0",
9
- "@warlock.js/cascade": "5.29.0",
10
- "@warlock.js/core": "5.29.0",
11
- "@warlock.js/logger": "5.29.0"
8
+ "@warlock.js/cache": "5.31.0",
9
+ "@warlock.js/cascade": "5.31.0",
10
+ "@warlock.js/core": "5.31.0",
11
+ "@warlock.js/logger": "5.31.0"
12
12
  },
13
13
  "peerDependenciesMeta": {
14
14
  "@warlock.js/cache": {
@@ -20,7 +20,8 @@
20
20
  },
21
21
  "repository": {
22
22
  "type": "git",
23
- "url": "https://github.com/warlockjs/devtools"
23
+ "url": "git+https://github.com/warlockjs/framework.git",
24
+ "directory": "packages/devtools"
24
25
  },
25
26
  "keywords": [
26
27
  "warlock.js",
@@ -33,7 +34,7 @@
33
34
  ],
34
35
  "author": "hassanzohdy",
35
36
  "license": "MIT",
36
- "version": "5.29.0",
37
+ "version": "5.31.0",
37
38
  "main": "./cjs/index.cjs",
38
39
  "module": "./esm/index.mjs",
39
40
  "types": "./esm/index.d.mts",
@@ -36,16 +36,16 @@ of it would fail to resolve there.
36
36
 
37
37
  ## What each panel shows
38
38
 
39
- | Panel | What you see | Where it comes from |
40
- |---|---|---|
41
- | **Requests** | Each request with its status, duration and query count. Click one for a waterfall: router middleware, `page.middleware`, loaders, `page.cache` hit/miss, `render.shell`, `defer.settle`, with queries and cache ops placed on the same time axis. | core `registerTracingHooks()` |
42
- | **Queries** | SQL + bindings or the Mongo command, duration, rows, and an **Explain** button (Postgres `SELECT` only; runs `EXPLAIN (FORMAT JSON)`, never `ANALYZE`) | cascade `dataSourceRegistry.on("query")` |
43
- | **N+1** | `⚠ N+1: 12× "select … where post_id = $1" — src/app/posts/services/list-posts.service.ts:18`, shown on the request and printed in the terminal | same query shape ≥ 5 times in one request |
44
- | **Mail** | Every mail sent in development: headers, HTML (sandboxed) and text, attachment names | core `mailEvents.onCaptured()` |
45
- | **Logs** | Log entries per request, filterable by level and module | a logger channel |
46
- | **Cache** | hit / miss / set / removed / `invalidated` (tags, keys removed) | cache `cache.on(...)` |
47
- | **Routes** | Every HTTP route with its method, path, name and middleware | core router |
48
- | **API** | The app's API reference: every route with its parameters, request body, responses and auth | core `getDevelopmentOpenApiDocument()` |
39
+ | Panel | What you see | Where it comes from |
40
+ | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------- |
41
+ | **Requests** | Each request with its status, duration and query count. Click one for a waterfall: router middleware, `page.middleware`, loaders, `page.cache` hit/miss, `render.shell`, `defer.settle`, with queries and cache ops placed on the same time axis. | core `registerTracingHooks()` |
42
+ | **Queries** | SQL + bindings or the Mongo command, duration, rows, and an **Explain** button (Postgres `SELECT` only; runs `EXPLAIN (FORMAT JSON)`, never `ANALYZE`) | cascade `dataSourceRegistry.on("query")` |
43
+ | **N+1** | `⚠ N+1: 12× "select … where post_id = $1" — src/app/posts/services/list-posts.service.ts:18`, shown on the request and printed in the terminal | same query shape ≥ 5 times in one request |
44
+ | **Mail** | Every mail sent in development: headers, HTML (sandboxed) and text, attachment names | core `mailEvents.onCaptured()` |
45
+ | **Logs** | Log entries per request, filterable by level and module | a logger channel |
46
+ | **Cache** | hit / miss / set / removed / `invalidated` (tags, keys removed) | cache `cache.on(...)` |
47
+ | **Routes** | Every HTTP route with its method, path, name and middleware | core router |
48
+ | **API** | The app's API reference: every route with its parameters, request body, responses and auth | core `getDevelopmentOpenApiDocument()` |
49
49
 
50
50
  Work outside a request (boot, scheduler ticks, queue jobs) goes to a separate
51
51
  background list, so it never clutters a request's timeline.
@@ -67,6 +67,18 @@ background list, so it never clutters a request's timeline.
67
67
  kept, and an N+1 threshold of 5. Everything lives in memory and is gone on
68
68
  restart.
69
69
 
70
+ ## From the terminal (agents)
71
+
72
+ `npx warlock trace POST /posts --body '{"title":"Hi"}' --json` sends one
73
+ request to the running dev server and prints this dashboard's record of it as
74
+ JSON — middleware, validation result, queries with N+1 flags, logs, response
75
+ and timings. See the `warlock-trace` skill of `@warlock.js/core`.
76
+
77
+ `npx warlock mcp` (or `npx warlock dev --mcp`) gives a coding agent the same
78
+ records through its `requests_recent` tool: the newest requests with their
79
+ phases, queries flagged `nPlusOne`, warnings, logs and timings. See the
80
+ `warlock-mcp` skill of `@warlock.js/core`.
81
+
70
82
  ## Secrets
71
83
 
72
84
  Query bindings and log context go through the logger's redaction rules
package/ui/app.css CHANGED
@@ -11,12 +11,7 @@
11
11
  --bad: #b42318;
12
12
  --code: #20242d;
13
13
  --bar: #5b7cfa;
14
- font-family:
15
- system-ui,
16
- -apple-system,
17
- BlinkMacSystemFont,
18
- "Segoe UI",
19
- sans-serif;
14
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
20
15
  }
21
16
  @media (prefers-color-scheme: dark) {
22
17
  :root {
@@ -1 +0,0 @@
1
- {"version":3,"file":"server-6mVWfWkG.cjs","names":["path","path","path"],"sources":["../../../../../../devtools/src/server/background-routes.ts","../../../../../../devtools/src/server/explain-route.ts","../../../../../../devtools/src/server/guard.ts","../../../../../../devtools/src/server/log-routes.ts","../../../../../../devtools/src/server/mail-routes.ts","../../../../../../devtools/src/ui-root.ts","../../../../../../devtools/src/server/ui-assets.ts","../../../../../../devtools/src/server/openapi-routes.ts","../../../../../../devtools/src/server/requests-routes.ts","../../../../../../devtools/src/server/route-routes.ts","../../../../../../devtools/src/server/stream-route.ts","../../../../../../devtools/src/server/index.ts"],"sourcesContent":["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\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 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 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 });\n });\n}\n","import type { FastifyError, FastifyInstance } from \"fastify\";\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 { 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 registerBackgroundRoutes(instance, deps);\n registerMailRoutes(instance, deps);\n registerLogRoutes(instance, deps);\n registerRouteRoutes(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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"}