@neat.is/core 0.2.9 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-IRPH6KL4.js → chunk-B7UUGIXB.js} +3 -1
- package/dist/chunk-B7UUGIXB.js.map +1 -0
- package/dist/chunk-DGUM43GV.js +11 -0
- package/dist/{chunk-BVF7MVR5.js → chunk-I5KODOJV.js} +2 -2
- package/dist/{chunk-5KX7EI4F.js → chunk-NVCEZXL7.js} +331 -20
- package/dist/chunk-NVCEZXL7.js.map +1 -0
- package/dist/{chunk-I5IMCXRO.js → chunk-QYUB3FQL.js} +2 -2
- package/dist/cli.cjs +443 -42
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.d.cts +2 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +111 -13
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +323 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -12
- package/dist/index.d.ts +4 -12
- package/dist/index.js +5 -4
- package/dist/neatd.cjs +106 -5
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +112 -6
- package/dist/neatd.js.map +1 -1
- package/dist/{otel-grpc-B4XBSI4W.js → otel-grpc-USFL3OI3.js} +3 -2
- package/dist/otel-grpc-USFL3OI3.js.map +1 -0
- package/dist/server.cjs +431 -125
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +4 -3
- package/dist/server.js.map +1 -1
- package/package.json +2 -2
- package/dist/chunk-5KX7EI4F.js.map +0 -1
- package/dist/chunk-IRPH6KL4.js.map +0 -1
- /package/dist/{otel-grpc-B4XBSI4W.js.map → chunk-DGUM43GV.js.map} +0 -0
- /package/dist/{chunk-BVF7MVR5.js.map → chunk-I5KODOJV.js.map} +0 -0
- /package/dist/{chunk-I5IMCXRO.js.map → chunk-QYUB3FQL.js.map} +0 -0
package/dist/server.js
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
} from "./chunk-XOOCA5T7.js";
|
|
4
4
|
import {
|
|
5
5
|
buildApi
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-NVCEZXL7.js";
|
|
7
7
|
import {
|
|
8
8
|
DEFAULT_PROJECT,
|
|
9
9
|
Projects,
|
|
@@ -15,11 +15,12 @@ import {
|
|
|
15
15
|
pathsForProject,
|
|
16
16
|
startPersistLoop,
|
|
17
17
|
startStalenessLoop
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-B7UUGIXB.js";
|
|
19
19
|
import {
|
|
20
20
|
buildOtelReceiver,
|
|
21
21
|
startOtelGrpcReceiver
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-QYUB3FQL.js";
|
|
23
|
+
import "./chunk-DGUM43GV.js";
|
|
23
24
|
|
|
24
25
|
// src/server.ts
|
|
25
26
|
import path from "path";
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/server.ts"],"sourcesContent":["import path from 'node:path'\nimport { DEFAULT_PROJECT, getGraph } from './graph.js'\nimport { buildApi } from './api.js'\nimport { extractFromDirectory } from './extract.js'\nimport { loadGraphFromDisk, startPersistLoop } from './persist.js'\nimport { buildOtelReceiver } from './otel.js'\nimport { startOtelGrpcReceiver } from './otel-grpc.js'\nimport { makeSpanHandler, startStalenessLoop } from './ingest.js'\nimport { buildSearchIndex } from './search.js'\nimport { Projects, parseExtraProjects, pathsForProject } from './projects.js'\n\nasync function bootProject(\n registry: Projects,\n name: string,\n scanPath: string | undefined,\n baseDir: string,\n): Promise<void> {\n const paths = pathsForProject(name, baseDir)\n const graph = getGraph(name)\n await loadGraphFromDisk(graph, paths.snapshotPath)\n\n if (scanPath) {\n const r = await extractFromDirectory(graph, scanPath)\n console.log(\n `[${name}] extract: ${r.nodesAdded} new nodes, ${r.edgesAdded} new edges (graph total ${graph.order}/${graph.size})`,\n )\n } else {\n console.log(`[${name}] loaded ${graph.order} nodes / ${graph.size} edges from snapshot`)\n }\n\n startPersistLoop(graph, paths.snapshotPath)\n startStalenessLoop(graph, { staleEventsPath: paths.staleEventsPath })\n\n const searchIndex = await buildSearchIndex(graph, {\n cachePath: paths.embeddingsCachePath,\n }).catch((err) => {\n console.warn(\n `[${name}] semantic_search: index build failed (${(err as Error).message}); falling back to inline substring`,\n )\n return undefined\n })\n if (searchIndex) {\n console.log(`[${name}] semantic_search: ${searchIndex.provider} provider`)\n }\n\n registry.set(name, {\n scanPath,\n paths,\n searchIndex,\n })\n}\n\nasync function main(): Promise<void> {\n const baseDirEnv = process.env.NEAT_OUT_DIR\n const legacyOutPath = process.env.NEAT_OUT_PATH\n const baseDir = baseDirEnv\n ? path.resolve(baseDirEnv)\n : legacyOutPath\n ? path.resolve(path.dirname(legacyOutPath))\n : path.resolve('./neat-out')\n\n const defaultScanPath = path.resolve(process.env.NEAT_SCAN_PATH ?? './demo')\n const registry = new Projects()\n\n // Default project always exists. NEAT_SCAN_PATH still wires it to a scan\n // root so existing single-project users see no behaviour change.\n await bootProject(registry, DEFAULT_PROJECT, defaultScanPath, baseDir)\n\n // Extra projects come from NEAT_PROJECTS=a,b,c. Their snapshots load from\n // <baseDir>/<name>.json; they have no scan path by default (callers can\n // POST /projects/<name>/graph/scan after wiring NEAT_PROJECT_SCAN_PATH_<NAME>).\n for (const name of parseExtraProjects(process.env.NEAT_PROJECTS)) {\n const envKey = `NEAT_PROJECT_SCAN_PATH_${name.toUpperCase().replace(/[^A-Z0-9]/g, '_')}`\n const projectScan = process.env[envKey]\n await bootProject(registry, name, projectScan ? path.resolve(projectScan) : undefined, baseDir)\n }\n\n const host = process.env.HOST ?? '0.0.0.0'\n const port = Number(process.env.PORT ?? 8080)\n const otelPort = Number(process.env.OTEL_PORT ?? 4318)\n\n const app = await buildApi({ projects: registry })\n await app.listen({ port, host })\n console.log(`neat-core listening on http://${host}:${port}`)\n console.log(` base dir: ${baseDir}`)\n console.log(` projects: ${registry.list().join(', ')}`)\n\n // OTel ingest stays single-project for now: spans always land in the\n // default project's graph + errors log. Multi-project routing for spans\n // is a future concern (would need a header / resource attr).\n const defaultCtx = registry.get(DEFAULT_PROJECT)\n if (defaultCtx) {\n const onSpan = makeSpanHandler({\n graph: defaultCtx.graph,\n errorsPath: defaultCtx.paths.errorsPath,\n })\n const otelApp = await buildOtelReceiver({ onSpan })\n await otelApp.listen({ port: otelPort, host })\n console.log(`neat-core OTLP receiver on http://${host}:${otelPort}/v1/traces`)\n\n if (process.env.NEAT_OTLP_GRPC === 'true') {\n const grpcPort = Number(process.env.NEAT_OTLP_GRPC_PORT ?? 4317)\n const grpcReceiver = await startOtelGrpcReceiver({ onSpan, host, port: grpcPort })\n console.log(`neat-core OTLP/gRPC receiver on ${grpcReceiver.address}`)\n }\n }\n}\n\nmain().catch((err) => {\n console.error(err)\n process.exit(1)\n})\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/server.ts"],"sourcesContent":["import path from 'node:path'\nimport { DEFAULT_PROJECT, getGraph } from './graph.js'\nimport { buildApi } from './api.js'\nimport { extractFromDirectory } from './extract.js'\nimport { loadGraphFromDisk, startPersistLoop } from './persist.js'\nimport { buildOtelReceiver } from './otel.js'\nimport { startOtelGrpcReceiver } from './otel-grpc.js'\nimport { makeSpanHandler, startStalenessLoop } from './ingest.js'\nimport { buildSearchIndex } from './search.js'\nimport { Projects, parseExtraProjects, pathsForProject } from './projects.js'\n\nasync function bootProject(\n registry: Projects,\n name: string,\n scanPath: string | undefined,\n baseDir: string,\n): Promise<void> {\n const paths = pathsForProject(name, baseDir)\n const graph = getGraph(name)\n await loadGraphFromDisk(graph, paths.snapshotPath)\n\n if (scanPath) {\n const r = await extractFromDirectory(graph, scanPath)\n console.log(\n `[${name}] extract: ${r.nodesAdded} new nodes, ${r.edgesAdded} new edges (graph total ${graph.order}/${graph.size})`,\n )\n } else {\n console.log(`[${name}] loaded ${graph.order} nodes / ${graph.size} edges from snapshot`)\n }\n\n startPersistLoop(graph, paths.snapshotPath)\n startStalenessLoop(graph, { staleEventsPath: paths.staleEventsPath })\n\n const searchIndex = await buildSearchIndex(graph, {\n cachePath: paths.embeddingsCachePath,\n }).catch((err) => {\n console.warn(\n `[${name}] semantic_search: index build failed (${(err as Error).message}); falling back to inline substring`,\n )\n return undefined\n })\n if (searchIndex) {\n console.log(`[${name}] semantic_search: ${searchIndex.provider} provider`)\n }\n\n registry.set(name, {\n scanPath,\n paths,\n searchIndex,\n })\n}\n\nasync function main(): Promise<void> {\n const baseDirEnv = process.env.NEAT_OUT_DIR\n const legacyOutPath = process.env.NEAT_OUT_PATH\n const baseDir = baseDirEnv\n ? path.resolve(baseDirEnv)\n : legacyOutPath\n ? path.resolve(path.dirname(legacyOutPath))\n : path.resolve('./neat-out')\n\n const defaultScanPath = path.resolve(process.env.NEAT_SCAN_PATH ?? './demo')\n const registry = new Projects()\n\n // Default project always exists. NEAT_SCAN_PATH still wires it to a scan\n // root so existing single-project users see no behaviour change.\n await bootProject(registry, DEFAULT_PROJECT, defaultScanPath, baseDir)\n\n // Extra projects come from NEAT_PROJECTS=a,b,c. Their snapshots load from\n // <baseDir>/<name>.json; they have no scan path by default (callers can\n // POST /projects/<name>/graph/scan after wiring NEAT_PROJECT_SCAN_PATH_<NAME>).\n for (const name of parseExtraProjects(process.env.NEAT_PROJECTS)) {\n const envKey = `NEAT_PROJECT_SCAN_PATH_${name.toUpperCase().replace(/[^A-Z0-9]/g, '_')}`\n const projectScan = process.env[envKey]\n await bootProject(registry, name, projectScan ? path.resolve(projectScan) : undefined, baseDir)\n }\n\n const host = process.env.HOST ?? '0.0.0.0'\n const port = Number(process.env.PORT ?? 8080)\n const otelPort = Number(process.env.OTEL_PORT ?? 4318)\n\n const app = await buildApi({ projects: registry })\n await app.listen({ port, host })\n console.log(`neat-core listening on http://${host}:${port}`)\n console.log(` base dir: ${baseDir}`)\n console.log(` projects: ${registry.list().join(', ')}`)\n\n // OTel ingest stays single-project for now: spans always land in the\n // default project's graph + errors log. Multi-project routing for spans\n // is a future concern (would need a header / resource attr).\n const defaultCtx = registry.get(DEFAULT_PROJECT)\n if (defaultCtx) {\n const onSpan = makeSpanHandler({\n graph: defaultCtx.graph,\n errorsPath: defaultCtx.paths.errorsPath,\n })\n const otelApp = await buildOtelReceiver({ onSpan })\n await otelApp.listen({ port: otelPort, host })\n console.log(`neat-core OTLP receiver on http://${host}:${otelPort}/v1/traces`)\n\n if (process.env.NEAT_OTLP_GRPC === 'true') {\n const grpcPort = Number(process.env.NEAT_OTLP_GRPC_PORT ?? 4317)\n const grpcReceiver = await startOtelGrpcReceiver({ onSpan, host, port: grpcPort })\n console.log(`neat-core OTLP/gRPC receiver on ${grpcReceiver.address}`)\n }\n }\n}\n\nmain().catch((err) => {\n console.error(err)\n process.exit(1)\n})\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neat.is/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "NEAT graph engine: tree-sitter extraction, OTel ingest, REST API",
|
|
5
5
|
"license": "BUSL-1.1",
|
|
6
6
|
"homepage": "https://neat.is",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"@fastify/cors": "^10.0.0",
|
|
51
51
|
"@grpc/grpc-js": "^1.14.3",
|
|
52
52
|
"@grpc/proto-loader": "^0.8.0",
|
|
53
|
-
"@neat.is/types": "^0.
|
|
53
|
+
"@neat.is/types": "^0.3.0",
|
|
54
54
|
"chokidar": "^4.0.3",
|
|
55
55
|
"fastify": "^5.0.0",
|
|
56
56
|
"graphology": "^0.25.4",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/diff.ts","../src/api.ts","../src/streaming.ts"],"sourcesContent":["import { promises as fs } from 'node:fs'\nimport type { GraphEdge, GraphNode } from '@neat.is/types'\nimport type { NeatGraph } from './graph.js'\n\n// Diff a snapshot on disk (or fetched over HTTP) against the live in-memory\n// graph. The \"base\" is the snapshot you supplied; the \"current\" is whatever\n// the server has loaded right now. Symmetric in shape, but consumers usually\n// want to read it as \"what changed since base.\"\n//\n// The shape mirrors the issue's spec (#77):\n// { added: { nodes, edges }, removed: { nodes, edges },\n// changed: { nodes: [{id, before, after}], edges: [{id, before, after}] } }\n//\n// Both timestamps are echoed back so the caller doesn't have to track them\n// separately.\n\ninterface PersistedNodeEntry {\n key?: string\n attributes?: Record<string, unknown>\n}\n\ninterface PersistedEdgeEntry {\n key?: string\n source?: string\n target?: string\n attributes?: Record<string, unknown>\n}\n\nexport interface PersistedSnapshot {\n schemaVersion?: number\n exportedAt?: string\n graph?: {\n nodes?: PersistedNodeEntry[]\n edges?: PersistedEdgeEntry[]\n }\n}\n\nexport interface GraphDiff {\n base: { exportedAt?: string }\n current: { exportedAt: string }\n added: { nodes: GraphNode[]; edges: GraphEdge[] }\n removed: { nodes: GraphNode[]; edges: GraphEdge[] }\n changed: {\n nodes: { id: string; before: GraphNode; after: GraphNode }[]\n edges: { id: string; before: GraphEdge; after: GraphEdge }[]\n }\n}\n\nexport async function loadSnapshotForDiff(target: string): Promise<PersistedSnapshot> {\n if (/^https?:\\/\\//i.test(target)) {\n const res = await fetch(target)\n if (!res.ok) {\n throw new Error(`fetch ${target} failed: ${res.status} ${res.statusText}`)\n }\n return (await res.json()) as PersistedSnapshot\n }\n const raw = await fs.readFile(target, 'utf8')\n return JSON.parse(raw) as PersistedSnapshot\n}\n\nfunction indexEntries<T>(\n entries: { key?: string; attributes?: Record<string, unknown> }[] | undefined,\n): Map<string, T> {\n const m = new Map<string, T>()\n if (!entries) return m\n for (const entry of entries) {\n const id = (entry.attributes?.id as string | undefined) ?? entry.key\n if (!id) continue\n m.set(id, entry.attributes as T)\n }\n return m\n}\n\nexport function computeGraphDiff(\n liveGraph: NeatGraph,\n baseSnapshot: PersistedSnapshot,\n currentExportedAt: string = new Date().toISOString(),\n): GraphDiff {\n const baseNodes = indexEntries<GraphNode>(baseSnapshot.graph?.nodes)\n const baseEdges = indexEntries<GraphEdge>(baseSnapshot.graph?.edges)\n\n const liveNodes = new Map<string, GraphNode>()\n liveGraph.forEachNode((id, attrs) => liveNodes.set(id, attrs as GraphNode))\n const liveEdges = new Map<string, GraphEdge>()\n liveGraph.forEachEdge((id, attrs) => liveEdges.set(id, attrs as GraphEdge))\n\n const result: GraphDiff = {\n base: { exportedAt: baseSnapshot.exportedAt },\n current: { exportedAt: currentExportedAt },\n added: { nodes: [], edges: [] },\n removed: { nodes: [], edges: [] },\n changed: { nodes: [], edges: [] },\n }\n\n for (const [id, after] of liveNodes) {\n const before = baseNodes.get(id)\n if (!before) {\n result.added.nodes.push(after)\n } else if (!shallowEqual(before, after)) {\n result.changed.nodes.push({ id, before, after })\n }\n }\n for (const [id, before] of baseNodes) {\n if (!liveNodes.has(id)) result.removed.nodes.push(before)\n }\n for (const [id, after] of liveEdges) {\n const before = baseEdges.get(id)\n if (!before) {\n result.added.edges.push(after)\n } else if (!shallowEqual(before, after)) {\n result.changed.edges.push({ id, before, after })\n }\n }\n for (const [id, before] of baseEdges) {\n if (!liveEdges.has(id)) result.removed.edges.push(before)\n }\n\n return result\n}\n\n// Stable JSON comparison. Snapshot order isn't guaranteed, so canonicalising\n// keys before stringify keeps the comparison robust against re-ordered fields.\nfunction shallowEqual(a: unknown, b: unknown): boolean {\n return canonicalJson(a) === canonicalJson(b)\n}\n\nfunction canonicalJson(value: unknown): string {\n return JSON.stringify(value, (_key, v) => {\n if (v && typeof v === 'object' && !Array.isArray(v)) {\n return Object.keys(v as Record<string, unknown>)\n .sort()\n .reduce<Record<string, unknown>>((acc, k) => {\n acc[k] = (v as Record<string, unknown>)[k]\n return acc\n }, {})\n }\n return v\n })\n}\n","import Fastify, {\n type FastifyInstance,\n type FastifyReply,\n type FastifyRequest,\n} from 'fastify'\nimport cors from '@fastify/cors'\nimport type {\n ErrorEvent,\n GraphEdge,\n GraphNode,\n Policy,\n PolicyViolation,\n} from '@neat.is/types'\nimport { PoliciesCheckBodySchema, PolicySeveritySchema } from '@neat.is/types'\nimport {\n evaluateAllPolicies,\n loadPolicyFile,\n PolicyViolationsLog,\n} from './policy.js'\nimport type { NeatGraph } from './graph.js'\nimport { DEFAULT_PROJECT } from './graph.js'\nimport { extractFromDirectory } from './extract.js'\nimport { readErrorEvents, readStaleEvents } from './ingest.js'\nimport {\n getBlastRadius,\n getRootCause,\n getTransitiveDependencies,\n TRANSITIVE_DEPENDENCIES_DEFAULT_DEPTH,\n TRANSITIVE_DEPENDENCIES_MAX_DEPTH,\n} from './traverse.js'\nimport { computeGraphDiff, loadSnapshotForDiff } from './diff.js'\nimport type { SearchIndex } from './search.js'\nimport type { Projects, ProjectContext } from './projects.js'\nimport { Projects as ProjectsClass, pathsForProject } from './projects.js'\nimport { listProjects as listRegistryProjects } from './registry.js'\nimport { handleSse } from './streaming.js'\n\nexport interface BuildApiOptions {\n // Multi-project shape. Optional — when absent we synthesise a single-\n // project registry from the legacy fields below so existing callers\n // (mainly tests) keep working unchanged.\n projects?: Projects\n startedAt?: number\n\n // Legacy single-project shape. Mapped to project=`default` if `projects`\n // isn't provided.\n graph?: NeatGraph\n scanPath?: string\n errorsPath?: string\n staleEventsPath?: string\n searchIndex?: SearchIndex\n}\n\ninterface SerializedGraph {\n nodes: GraphNode[]\n edges: GraphEdge[]\n}\n\nfunction serializeGraph(graph: NeatGraph): SerializedGraph {\n const nodes: GraphNode[] = []\n graph.forEachNode((_id, attrs) => {\n nodes.push(attrs)\n })\n const edges: GraphEdge[] = []\n graph.forEachEdge((_id, attrs) => {\n edges.push(attrs)\n })\n return { nodes, edges }\n}\n\nfunction projectFromReq(req: FastifyRequest): string {\n // `:project` is optional in the URL — the request hits either\n // /projects/:project/X or /X (which means default). Coerce the missing\n // param to DEFAULT_PROJECT here so handlers don't repeat the fallback.\n const params = req.params as { project?: string }\n return params.project ?? DEFAULT_PROJECT\n}\n\nfunction resolveProject(\n registry: Projects,\n req: FastifyRequest,\n reply: FastifyReply,\n): ProjectContext | null {\n const name = projectFromReq(req)\n const ctx = registry.get(name)\n if (!ctx) {\n void reply.code(404).send({ error: 'project not found', project: name })\n return null\n }\n return ctx\n}\n\nfunction buildLegacyRegistry(opts: BuildApiOptions): Projects {\n if (opts.projects) return opts.projects\n if (!opts.graph) {\n throw new Error('buildApi: either `projects` or `graph` must be provided')\n }\n const registry = new ProjectsClass()\n // pathsForProject only matters here for the snapshot/embeddings paths\n // routes never read; the ingest paths come from explicit options below.\n const paths = pathsForProject(DEFAULT_PROJECT, '')\n registry.set(DEFAULT_PROJECT, {\n graph: opts.graph,\n scanPath: opts.scanPath,\n paths: {\n snapshotPath: paths.snapshotPath,\n errorsPath: opts.errorsPath ?? paths.errorsPath,\n staleEventsPath: opts.staleEventsPath ?? paths.staleEventsPath,\n embeddingsCachePath: paths.embeddingsCachePath,\n policyViolationsPath: paths.policyViolationsPath,\n },\n searchIndex: opts.searchIndex,\n })\n return registry\n}\n\ninterface RouteContext {\n registry: Projects\n startedAt: number\n // Legacy callers passed `errorsPath`/`staleEventsPath` explicitly and\n // expected absent values to disable the read. Track that intent so the\n // /incidents handlers don't accidentally read a phantom file.\n errorsPathFor: (ctx: ProjectContext) => string | undefined\n staleEventsPathFor: (ctx: ProjectContext) => string | undefined\n // policy.json lives at the project root (per ADR-042 §File location), not\n // under neat-out/. Routes that read it map a project context to the path.\n policyFilePathFor: (ctx: ProjectContext) => string | undefined\n}\n\n// Registers every project-scoped route on `scope`. Called twice from\n// buildApi: once on the root app (so /graph etc. land at default), once\n// inside a `register(_, { prefix: '/projects/:project' })` plugin so the\n// same handlers run when the URL names a project explicitly.\nfunction registerRoutes(scope: FastifyInstance, ctx: RouteContext): void {\n const { registry, startedAt, errorsPathFor, staleEventsPathFor } = ctx\n\n // SSE event stream (ADR-051 #1). Dual-mounted: hits /events for default\n // project and /projects/:project/events when scoped. The handler keeps\n // the connection open and writes one frame per bus envelope whose\n // `project` matches.\n scope.get<{ Params: { project?: string } }>('/events', (req, reply) => {\n const proj = resolveProject(registry, req, reply)\n if (!proj) return\n handleSse(req, reply, { project: proj.name })\n })\n\n scope.get<{ Params: { project?: string } }>('/health', async (req, reply) => {\n const proj = resolveProject(registry, req, reply)\n if (!proj) return\n return {\n uptime: Math.floor((Date.now() - startedAt) / 1000),\n project: proj.name,\n nodeCount: proj.graph.order,\n edgeCount: proj.graph.size,\n lastUpdated: new Date().toISOString(),\n }\n })\n\n scope.get<{ Params: { project?: string } }>('/graph', async (req, reply) => {\n const proj = resolveProject(registry, req, reply)\n if (!proj) return\n return serializeGraph(proj.graph)\n })\n\n scope.get<{ Params: { project?: string; id: string } }>(\n '/graph/node/:id',\n async (req, reply) => {\n const proj = resolveProject(registry, req, reply)\n if (!proj) return\n const { id } = req.params\n if (!proj.graph.hasNode(id)) {\n return reply.code(404).send({ error: 'node not found', id })\n }\n return proj.graph.getNodeAttributes(id) as GraphNode\n },\n )\n\n scope.get<{ Params: { project?: string; id: string } }>(\n '/graph/edges/:id',\n async (req, reply) => {\n const proj = resolveProject(registry, req, reply)\n if (!proj) return\n const { id } = req.params\n if (!proj.graph.hasNode(id)) {\n return reply.code(404).send({ error: 'node not found', id })\n }\n const inbound = proj.graph\n .inboundEdges(id)\n .map((e) => proj.graph.getEdgeAttributes(e) as GraphEdge)\n const outbound = proj.graph\n .outboundEdges(id)\n .map((e) => proj.graph.getEdgeAttributes(e) as GraphEdge)\n return { inbound, outbound }\n },\n )\n\n // Transitive dependencies (issue #144). BFS outbound to depth N, returning\n // a flat list with distance + edgeType + provenance per dependency.\n // Default depth 3, max 10. The MCP get_dependencies tool calls this.\n scope.get<{\n Params: { project?: string; id: string }\n Querystring: { depth?: string }\n }>('/graph/node/:id/dependencies', async (req, reply) => {\n const proj = resolveProject(registry, req, reply)\n if (!proj) return\n const { id } = req.params\n if (!proj.graph.hasNode(id)) {\n return reply.code(404).send({ error: 'node not found', id })\n }\n const depth = req.query.depth ? Number(req.query.depth) : TRANSITIVE_DEPENDENCIES_DEFAULT_DEPTH\n if (!Number.isFinite(depth) || depth < 1 || depth > TRANSITIVE_DEPENDENCIES_MAX_DEPTH) {\n return reply.code(400).send({\n error: `depth must be an integer in [1, ${TRANSITIVE_DEPENDENCIES_MAX_DEPTH}]`,\n })\n }\n return getTransitiveDependencies(proj.graph, id, depth)\n })\n\n scope.get<{ Params: { project?: string } }>('/incidents', async (req, reply) => {\n const proj = resolveProject(registry, req, reply)\n if (!proj) return\n const epath = errorsPathFor(proj)\n if (!epath) return []\n return readErrorEvents(epath)\n })\n\n scope.get<{\n Params: { project?: string }\n Querystring: { limit?: string; edgeType?: string }\n }>('/incidents/stale', async (req, reply) => {\n const proj = resolveProject(registry, req, reply)\n if (!proj) return\n const spath = staleEventsPathFor(proj)\n if (!spath) return []\n const events = await readStaleEvents(spath)\n const filtered = req.query.edgeType\n ? events.filter((e) => e.edgeType === req.query.edgeType)\n : events\n const ordered = [...filtered].reverse()\n const limit = req.query.limit ? Number(req.query.limit) : 50\n return ordered.slice(0, Number.isFinite(limit) && limit > 0 ? limit : 50)\n })\n\n scope.get<{ Params: { project?: string; nodeId: string } }>(\n '/incidents/:nodeId',\n async (req, reply) => {\n const proj = resolveProject(registry, req, reply)\n if (!proj) return\n const { nodeId } = req.params\n if (!proj.graph.hasNode(nodeId)) {\n return reply.code(404).send({ error: 'node not found', id: nodeId })\n }\n const epath = errorsPathFor(proj)\n if (!epath) return []\n const events = await readErrorEvents(epath)\n return events.filter(\n (e) =>\n e.affectedNode === nodeId || e.service === nodeId.replace(/^service:/, ''),\n )\n },\n )\n\n scope.get<{\n Params: { project?: string; nodeId: string }\n Querystring: { errorId?: string }\n }>('/traverse/root-cause/:nodeId', async (req, reply) => {\n const proj = resolveProject(registry, req, reply)\n if (!proj) return\n const { nodeId } = req.params\n if (!proj.graph.hasNode(nodeId)) {\n return reply.code(404).send({ error: 'node not found', id: nodeId })\n }\n let errorEvent: ErrorEvent | undefined\n const epath = errorsPathFor(proj)\n if (req.query.errorId && epath) {\n const events = await readErrorEvents(epath)\n errorEvent = events.find((e) => e.id === req.query.errorId)\n if (!errorEvent) {\n return reply\n .code(404)\n .send({ error: 'error event not found', id: req.query.errorId })\n }\n }\n const result = getRootCause(proj.graph, nodeId, errorEvent)\n if (!result) return reply.code(404).send({ error: 'no root cause found', id: nodeId })\n return result\n })\n\n scope.get<{\n Params: { project?: string; nodeId: string }\n Querystring: { depth?: string }\n }>('/traverse/blast-radius/:nodeId', async (req, reply) => {\n const proj = resolveProject(registry, req, reply)\n if (!proj) return\n const { nodeId } = req.params\n if (!proj.graph.hasNode(nodeId)) {\n return reply.code(404).send({ error: 'node not found', id: nodeId })\n }\n const depth = req.query.depth ? Number(req.query.depth) : undefined\n if (depth !== undefined && (!Number.isFinite(depth) || depth < 0)) {\n return reply.code(400).send({ error: 'depth must be a non-negative number' })\n }\n return getBlastRadius(proj.graph, nodeId, depth)\n })\n\n scope.get<{\n Params: { project?: string }\n Querystring: { q?: string; limit?: string }\n }>('/search', async (req, reply) => {\n const proj = resolveProject(registry, req, reply)\n if (!proj) return\n const raw = (req.query.q ?? '').trim()\n if (!raw) return reply.code(400).send({ error: 'query parameter `q` is required' })\n const limit = req.query.limit ? Number(req.query.limit) : undefined\n const safeLimit =\n limit !== undefined && Number.isFinite(limit) && limit > 0 ? limit : undefined\n if (proj.searchIndex) {\n const result = await proj.searchIndex.search(raw, safeLimit)\n return {\n query: result.query,\n provider: result.provider,\n matches: result.matches.map((m) => ({ ...m.node, score: m.score })),\n }\n }\n const q = raw.toLowerCase()\n const matches: (GraphNode & { score: number })[] = []\n proj.graph.forEachNode((id, attrs) => {\n const name = (attrs as { name?: string }).name ?? ''\n if (id.toLowerCase().includes(q) || name.toLowerCase().includes(q)) {\n matches.push({ ...(attrs as GraphNode), score: 1 })\n }\n })\n return {\n query: q,\n provider: 'substring' as const,\n matches: matches.slice(0, safeLimit),\n }\n })\n\n scope.get<{ Params: { project?: string }; Querystring: { against?: string } }>(\n '/graph/diff',\n async (req, reply) => {\n const proj = resolveProject(registry, req, reply)\n if (!proj) return\n const against = req.query.against\n if (!against) {\n return reply.code(400).send({ error: 'query parameter `against` is required' })\n }\n try {\n const snapshot = await loadSnapshotForDiff(against)\n return computeGraphDiff(proj.graph, snapshot)\n } catch (err) {\n return reply\n .code(400)\n .send({ error: 'failed to load snapshot', against, detail: (err as Error).message })\n }\n },\n )\n\n scope.post<{ Params: { project?: string } }>('/graph/scan', async (req, reply) => {\n const proj = resolveProject(registry, req, reply)\n if (!proj) return\n if (!proj.scanPath) {\n return reply\n .code(409)\n .send({ error: 'scan path not configured for this project', project: proj.name })\n }\n const result = await extractFromDirectory(proj.graph, proj.scanPath)\n return {\n project: proj.name,\n scanned: proj.scanPath,\n nodesAdded: result.nodesAdded,\n edgesAdded: result.edgesAdded,\n nodeCount: proj.graph.order,\n edgeCount: proj.graph.size,\n }\n })\n\n // Policy surface (ADR-045 / contract #18). /policies returns the parsed\n // policy.json; /policies/violations is the persistent log; /policies/check\n // is dry-run evaluation. All dual-mounted via registerRoutes.\n scope.get<{ Params: { project?: string } }>('/policies', async (req, reply) => {\n const proj = resolveProject(registry, req, reply)\n if (!proj) return\n const policyPath = ctx.policyFilePathFor(proj)\n if (!policyPath) {\n // No policy file configured for this project — return the empty file\n // shape so consumers don't have to special-case \"no policies yet.\"\n return { version: 1, policies: [] }\n }\n try {\n const policies = await loadPolicyFile(policyPath)\n return { version: 1, policies }\n } catch (err) {\n return reply.code(400).send({\n error: 'policy.json failed to parse',\n details: (err as Error).message,\n })\n }\n })\n\n scope.get<{\n Params: { project?: string }\n Querystring: { severity?: string; policyId?: string }\n }>('/policies/violations', async (req, reply) => {\n const proj = resolveProject(registry, req, reply)\n if (!proj) return\n const log = new PolicyViolationsLog(proj.paths.policyViolationsPath)\n let violations = await log.readAll()\n if (req.query.severity) {\n const sev = PolicySeveritySchema.safeParse(req.query.severity)\n if (!sev.success) {\n return reply.code(400).send({\n error: 'invalid severity',\n details: sev.error.format(),\n })\n }\n violations = violations.filter((v) => v.severity === sev.data)\n }\n if (req.query.policyId) {\n violations = violations.filter((v) => v.policyId === req.query.policyId)\n }\n return violations\n })\n\n scope.post<{\n Params: { project?: string }\n Body: { hypotheticalAction?: unknown }\n }>('/policies/check', async (req, reply) => {\n const proj = resolveProject(registry, req, reply)\n if (!proj) return\n const parsed = PoliciesCheckBodySchema.safeParse(req.body ?? {})\n if (!parsed.success) {\n return reply.code(400).send({\n error: 'invalid /policies/check body',\n details: parsed.error.format(),\n })\n }\n\n const policyPath = ctx.policyFilePathFor(proj)\n let policies: Policy[] = []\n if (policyPath) {\n try {\n policies = await loadPolicyFile(policyPath)\n } catch (err) {\n return reply.code(400).send({\n error: 'policy.json failed to parse',\n details: (err as Error).message,\n })\n }\n }\n\n // No hypothetical → return current violations against the live graph.\n // With a hypothetical → simulate the action against a deep-copy graph\n // (avoids mutation authority concerns), evaluate, return the delta.\n const evalCtx = { now: () => Date.now() }\n if (!parsed.data.hypotheticalAction) {\n const violations = evaluateAllPolicies(proj.graph, policies, evalCtx)\n const blocking = violations.filter((v) => v.onViolation === 'block')\n return { allowed: blocking.length === 0, violations }\n }\n\n // For now the dry-run simulation re-uses evaluateAllPolicies on the\n // current graph. Full hypothetical simulation (e.g. \"what if I added\n // this OBSERVED edge?\") is the v0.2.4-δ scope; #117 ships the surface,\n // #118 fills in the action shapes' simulation logic.\n const violations = evaluateAllPolicies(proj.graph, policies, evalCtx)\n const blocking = violations.filter((v) => v.onViolation === 'block')\n return {\n allowed: blocking.length === 0,\n hypotheticalAction: parsed.data.hypotheticalAction,\n violations,\n } as { allowed: boolean; hypotheticalAction: unknown; violations: PolicyViolation[] }\n })\n}\n\nexport async function buildApi(opts: BuildApiOptions): Promise<FastifyInstance> {\n const app = Fastify({ logger: false })\n await app.register(cors, { origin: true })\n\n const startedAt = opts.startedAt ?? Date.now()\n const registry = buildLegacyRegistry(opts)\n\n const legacyErrorsExplicit = !opts.projects && opts.errorsPath !== undefined\n const legacyStaleExplicit = !opts.projects && opts.staleEventsPath !== undefined\n\n const errorsPathFor = (proj: ProjectContext): string | undefined => {\n if (proj.name === DEFAULT_PROJECT && !opts.projects) {\n return legacyErrorsExplicit ? opts.errorsPath : undefined\n }\n return proj.paths.errorsPath\n }\n const staleEventsPathFor = (proj: ProjectContext): string | undefined => {\n if (proj.name === DEFAULT_PROJECT && !opts.projects) {\n return legacyStaleExplicit ? opts.staleEventsPath : undefined\n }\n return proj.paths.staleEventsPath\n }\n\n // policy.json lives at the project's scanPath root per ADR-042. Without a\n // scanPath we have nowhere to read it from — those projects show as\n // \"no policies configured\" via the empty-file response.\n const policyFilePathFor = (proj: ProjectContext): string | undefined => {\n if (!proj.scanPath) return undefined\n return `${proj.scanPath}/policy.json`\n }\n\n const routeCtx: RouteContext = {\n registry,\n startedAt,\n errorsPathFor,\n staleEventsPathFor,\n policyFilePathFor,\n }\n\n // Multi-project switcher (ADR-051 #4). Direct passthrough of the\n // machine-level registry from registry.ts (ADR-048) — distinct from the\n // dual-mount routing in ADR-026, which exposes per-project endpoints.\n // Returns Array<{ name, path, status, registeredAt, lastSeenAt?, languages }>.\n app.get('/projects', async (_req, reply) => {\n try {\n return await listRegistryProjects()\n } catch (err) {\n return reply.code(500).send({\n error: 'failed to read project registry',\n details: (err as Error).message,\n })\n }\n })\n\n // Default mount: /health, /graph, /incidents, etc. all hit project=default.\n registerRoutes(app, routeCtx)\n\n // Project-scoped mount: same handlers, URL params include `:project`.\n await app.register(\n async (scope) => {\n registerRoutes(scope, routeCtx)\n },\n { prefix: '/projects/:project' },\n )\n\n return app\n}\n","// SSE handler for the frontend-facing event stream (ADR-051 #1).\n// Subscribes to the bus in events.ts, filters by project, writes\n// `event: <type>\\ndata: <json>\\n\\n` frames to the client.\n//\n// Backpressure: per-connection queue cap of 1000 outstanding writes; once\n// hit, the connection is dropped with `event: error data: { reason:\n// 'backpressure' }` per ADR-051 #8. Heartbeat: comment line every 30s\n// keeps proxies from idle-timing out (ADR-051 #3).\n\nimport type { FastifyReply, FastifyRequest } from 'fastify'\nimport {\n EVENT_BUS_CHANNEL,\n eventBus,\n type NeatEventEnvelope,\n} from './events.js'\n\nexport const SSE_HEARTBEAT_MS = 30_000\nexport const SSE_BACKPRESSURE_CAP = 1000\n\nexport interface HandleSseOptions {\n project: string\n heartbeatMs?: number\n backpressureCap?: number\n}\n\nexport function handleSse(\n req: FastifyRequest,\n reply: FastifyReply,\n opts: HandleSseOptions,\n): void {\n const heartbeatMs = opts.heartbeatMs ?? SSE_HEARTBEAT_MS\n const backpressureCap = opts.backpressureCap ?? SSE_BACKPRESSURE_CAP\n\n reply.raw.setHeader('Content-Type', 'text/event-stream')\n reply.raw.setHeader('Cache-Control', 'no-cache, no-transform')\n reply.raw.setHeader('Connection', 'keep-alive')\n reply.raw.setHeader('X-Accel-Buffering', 'no')\n reply.raw.flushHeaders?.()\n\n let pending = 0\n let dropped = false\n\n const closeConnection = (): void => {\n if (dropped) return\n dropped = true\n eventBus.off(EVENT_BUS_CHANNEL, listener)\n clearInterval(heartbeat)\n if (!reply.raw.writableEnded) reply.raw.end()\n }\n\n const writeFrame = (frame: string): void => {\n if (dropped) return\n if (pending >= backpressureCap) {\n // Past the cap — emit one final error frame and drop. Don't try to\n // gracefully drain; a slow consumer that's already 1000 frames behind\n // is not going to catch up.\n const errFrame = `event: error\\ndata: ${JSON.stringify({ reason: 'backpressure' })}\\n\\n`\n reply.raw.write(errFrame)\n closeConnection()\n return\n }\n pending++\n reply.raw.write(frame, () => {\n pending = Math.max(0, pending - 1)\n })\n }\n\n const listener = (envelope: NeatEventEnvelope): void => {\n if (envelope.project !== opts.project) return\n writeFrame(`event: ${envelope.type}\\ndata: ${JSON.stringify(envelope.payload)}\\n\\n`)\n }\n\n eventBus.on(EVENT_BUS_CHANNEL, listener)\n\n const heartbeat = setInterval(() => {\n if (dropped) return\n reply.raw.write(':heartbeat\\n\\n')\n }, heartbeatMs)\n if (typeof heartbeat.unref === 'function') heartbeat.unref()\n\n req.raw.on('close', closeConnection)\n reply.raw.on('close', closeConnection)\n reply.raw.on('error', closeConnection)\n}\n"],"mappings":"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","names":["violations","blocking"]}
|