@omiron33/omi-neuron-web 0.1.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 (55) hide show
  1. package/README.md +55 -0
  2. package/dist/api/index.cjs +943 -0
  3. package/dist/api/index.cjs.map +1 -0
  4. package/dist/api/index.d.cts +140 -0
  5. package/dist/api/index.d.ts +140 -0
  6. package/dist/api/index.js +934 -0
  7. package/dist/api/index.js.map +1 -0
  8. package/dist/chunk-BSOSHBDR.cjs +300 -0
  9. package/dist/chunk-BSOSHBDR.cjs.map +1 -0
  10. package/dist/chunk-COO66N7H.cjs +950 -0
  11. package/dist/chunk-COO66N7H.cjs.map +1 -0
  12. package/dist/chunk-FXKXMSLY.cjs +270 -0
  13. package/dist/chunk-FXKXMSLY.cjs.map +1 -0
  14. package/dist/chunk-PSDVPB7Y.js +289 -0
  15. package/dist/chunk-PSDVPB7Y.js.map +1 -0
  16. package/dist/chunk-RQCGONPN.js +937 -0
  17. package/dist/chunk-RQCGONPN.js.map +1 -0
  18. package/dist/chunk-RTSFO7BW.cjs +592 -0
  19. package/dist/chunk-RTSFO7BW.cjs.map +1 -0
  20. package/dist/chunk-TFLMPBX7.js +262 -0
  21. package/dist/chunk-TFLMPBX7.js.map +1 -0
  22. package/dist/chunk-XNR42GCJ.js +547 -0
  23. package/dist/chunk-XNR42GCJ.js.map +1 -0
  24. package/dist/cli/index.cjs +571 -0
  25. package/dist/cli/index.cjs.map +1 -0
  26. package/dist/cli/index.d.cts +1 -0
  27. package/dist/cli/index.d.ts +1 -0
  28. package/dist/cli/index.js +563 -0
  29. package/dist/cli/index.js.map +1 -0
  30. package/dist/database-B0vplyA4.d.cts +41 -0
  31. package/dist/database-B0vplyA4.d.ts +41 -0
  32. package/dist/edge-BzsYe2Ed.d.cts +269 -0
  33. package/dist/edge-BzsYe2Ed.d.ts +269 -0
  34. package/dist/index.cjs +895 -0
  35. package/dist/index.cjs.map +1 -0
  36. package/dist/index.d.cts +1484 -0
  37. package/dist/index.d.ts +1484 -0
  38. package/dist/index.js +654 -0
  39. package/dist/index.js.map +1 -0
  40. package/dist/migration/index.cjs +32 -0
  41. package/dist/migration/index.cjs.map +1 -0
  42. package/dist/migration/index.d.cts +51 -0
  43. package/dist/migration/index.d.ts +51 -0
  44. package/dist/migration/index.js +3 -0
  45. package/dist/migration/index.js.map +1 -0
  46. package/dist/query-helpers-D8po5Mn-.d.cts +777 -0
  47. package/dist/query-helpers-DvQTA2_Z.d.ts +777 -0
  48. package/dist/visualization/index.cjs +485 -0
  49. package/dist/visualization/index.cjs.map +1 -0
  50. package/dist/visualization/index.d.cts +134 -0
  51. package/dist/visualization/index.d.ts +134 -0
  52. package/dist/visualization/index.js +460 -0
  53. package/dist/visualization/index.js.map +1 -0
  54. package/docker/docker-compose.template.yml +28 -0
  55. package/package.json +116 -0
@@ -0,0 +1,943 @@
1
+ 'use strict';
2
+
3
+ var chunkRTSFO7BW_cjs = require('../chunk-RTSFO7BW.cjs');
4
+ var chunkCOO66N7H_cjs = require('../chunk-COO66N7H.cjs');
5
+
6
+ // src/api/repositories/base.ts
7
+ var BaseRepository = class {
8
+ constructor(db, tableName) {
9
+ this.db = db;
10
+ this.tableName = tableName;
11
+ }
12
+ async findById(id) {
13
+ const { sql, values } = chunkRTSFO7BW_cjs.buildSelect(this.tableName, "*", { id });
14
+ const rows = await this.db.query(sql, values);
15
+ return rows[0] ?? null;
16
+ }
17
+ async findAll(options) {
18
+ const { sql, values } = chunkRTSFO7BW_cjs.buildSelect(
19
+ this.tableName,
20
+ "*",
21
+ options?.where,
22
+ options
23
+ );
24
+ return this.db.query(sql, values);
25
+ }
26
+ async create(data) {
27
+ const { sql, values } = chunkRTSFO7BW_cjs.buildInsert(this.tableName, data);
28
+ const rows = await this.db.query(sql, values);
29
+ return rows[0];
30
+ }
31
+ async update(id, data) {
32
+ const { sql, values } = chunkRTSFO7BW_cjs.buildUpdate(this.tableName, data, { id });
33
+ const rows = await this.db.query(sql, values);
34
+ return rows[0] ?? null;
35
+ }
36
+ async delete(id) {
37
+ const { sql, values } = chunkRTSFO7BW_cjs.buildDelete(this.tableName, { id });
38
+ const count = await this.db.execute(sql, values);
39
+ return count > 0;
40
+ }
41
+ async count(where) {
42
+ const whereResult = chunkRTSFO7BW_cjs.buildWhereClause(where);
43
+ const sql = `SELECT COUNT(*)::int as count FROM ${this.tableName} ${whereResult.clause}`;
44
+ const rows = await this.db.query(sql, whereResult.values);
45
+ return Number(rows[0]?.count ?? 0);
46
+ }
47
+ };
48
+
49
+ // src/api/repositories/node-repository.ts
50
+ var mapNodeRow = (row) => ({
51
+ id: row.id,
52
+ slug: row.slug,
53
+ label: row.label,
54
+ nodeType: row.node_type,
55
+ domain: row.domain,
56
+ summary: row.summary ?? null,
57
+ description: row.description ?? null,
58
+ content: row.content ?? null,
59
+ metadata: row.metadata ?? {},
60
+ tier: row.tier ?? void 0,
61
+ visualPriority: row.visual_priority ?? void 0,
62
+ positionOverride: row.position_override ?? null,
63
+ connectionCount: row.connection_count ?? 0,
64
+ inboundCount: row.inbound_count ?? 0,
65
+ outboundCount: row.outbound_count ?? 0,
66
+ analysisStatus: row.analysis_status ?? "pending",
67
+ analysisError: row.analysis_error ?? null,
68
+ embedding: row.embedding ?? null,
69
+ embeddingModel: row.embedding_model ?? null,
70
+ embeddingGeneratedAt: row.embedding_generated_at ?? null,
71
+ clusterId: row.cluster_id ?? null,
72
+ clusterSimilarity: row.cluster_similarity ?? null,
73
+ createdAt: row.created_at,
74
+ updatedAt: row.updated_at
75
+ });
76
+ var NodeRepository = class extends BaseRepository {
77
+ constructor(db) {
78
+ super(db, "nodes");
79
+ }
80
+ async findById(id) {
81
+ const row = await this.db.queryOne("SELECT * FROM nodes WHERE id = $1", [id]);
82
+ return row ? mapNodeRow(row) : null;
83
+ }
84
+ async findAll(options) {
85
+ const rows = await super.findAll(options);
86
+ return rows.map(mapNodeRow);
87
+ }
88
+ async findBySlug(slug) {
89
+ const row = await this.db.queryOne("SELECT * FROM nodes WHERE slug = $1", [slug]);
90
+ return row ? mapNodeRow(row) : null;
91
+ }
92
+ async findByDomain(domain) {
93
+ const rows = await this.db.query("SELECT * FROM nodes WHERE domain = $1", [domain]);
94
+ return rows.map(mapNodeRow);
95
+ }
96
+ async findByCluster(clusterId) {
97
+ const rows = await this.db.query("SELECT * FROM nodes WHERE cluster_id = $1", [clusterId]);
98
+ return rows.map(mapNodeRow);
99
+ }
100
+ async search(query) {
101
+ const rows = await this.db.query(
102
+ `SELECT * FROM nodes WHERE label ILIKE $1 OR summary ILIKE $1 OR content ILIKE $1`,
103
+ [`%${query}%`]
104
+ );
105
+ return rows.map(mapNodeRow);
106
+ }
107
+ async batchCreate(nodes) {
108
+ const created = [];
109
+ for (const node of nodes) {
110
+ const row = await this.db.queryOne(
111
+ `INSERT INTO nodes (slug, label, node_type, domain, summary, description, content, metadata, tier)
112
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
113
+ RETURNING *`,
114
+ [
115
+ node.slug,
116
+ node.label,
117
+ node.nodeType ?? "concept",
118
+ node.domain ?? "general",
119
+ node.summary ?? null,
120
+ node.description ?? null,
121
+ node.content ?? null,
122
+ node.metadata ?? {},
123
+ node.tier ?? null
124
+ ]
125
+ );
126
+ if (row) created.push(mapNodeRow(row));
127
+ }
128
+ return created;
129
+ }
130
+ async updateConnectionCounts(nodeId) {
131
+ const inbound = await this.db.queryOne(
132
+ "SELECT COUNT(*)::int as count FROM edges WHERE to_node_id = $1",
133
+ [nodeId]
134
+ );
135
+ const outbound = await this.db.queryOne(
136
+ "SELECT COUNT(*)::int as count FROM edges WHERE from_node_id = $1",
137
+ [nodeId]
138
+ );
139
+ const inboundCount = Number(inbound?.count ?? 0);
140
+ const outboundCount = Number(outbound?.count ?? 0);
141
+ await this.db.execute(
142
+ "UPDATE nodes SET inbound_count = $1, outbound_count = $2, connection_count = $3 WHERE id = $4",
143
+ [inboundCount, outboundCount, inboundCount + outboundCount, nodeId]
144
+ );
145
+ }
146
+ };
147
+
148
+ // src/api/routes/nodes.ts
149
+ var createNodesRoutes = (config) => {
150
+ const db = chunkRTSFO7BW_cjs.createDatabase(config);
151
+ const repo = new NodeRepository(db);
152
+ return {
153
+ async GET(request) {
154
+ const url = new URL(request.url);
155
+ const params = chunkRTSFO7BW_cjs.listNodesParamsSchema.parse(Object.fromEntries(url.searchParams));
156
+ const nodes = await repo.findAll({
157
+ where: {},
158
+ limit: params.limit,
159
+ offset: params.page ? (params.page - 1) * (params.limit ?? 50) : void 0
160
+ });
161
+ return Response.json({
162
+ nodes,
163
+ pagination: {
164
+ page: params.page ?? 1,
165
+ limit: params.limit ?? nodes.length,
166
+ total: nodes.length,
167
+ totalPages: 1,
168
+ hasNext: false,
169
+ hasPrev: false
170
+ },
171
+ meta: {
172
+ queryTime: 0,
173
+ filters: params
174
+ }
175
+ });
176
+ },
177
+ async POST(request) {
178
+ const body = await request.json();
179
+ const input = chunkRTSFO7BW_cjs.nodeBatchCreateSchema.parse(body);
180
+ const created = await repo.batchCreate(input.nodes);
181
+ return Response.json({ created, skipped: [], analysisJobId: null }, { status: 201 });
182
+ },
183
+ async PATCH(request) {
184
+ const url = new URL(request.url);
185
+ const id = url.pathname.split("/").pop();
186
+ if (!id) return new Response("Missing id", { status: 400 });
187
+ const body = await request.json();
188
+ const input = chunkRTSFO7BW_cjs.nodeUpdateSchema.parse(body);
189
+ const updated = await repo.update(id, input);
190
+ return Response.json(updated);
191
+ },
192
+ async DELETE(request) {
193
+ const url = new URL(request.url);
194
+ const id = url.pathname.split("/").pop();
195
+ if (!id) return new Response("Missing id", { status: 400 });
196
+ const deleted = await repo.delete(id);
197
+ return Response.json({ deleted, edgesRemoved: 0 });
198
+ }
199
+ };
200
+ };
201
+
202
+ // src/api/repositories/edge-repository.ts
203
+ var mapEdgeRow = (row) => ({
204
+ id: row.id,
205
+ fromNodeId: row.from_node_id,
206
+ toNodeId: row.to_node_id,
207
+ relationshipType: row.relationship_type,
208
+ strength: Number(row.strength ?? 0.5),
209
+ confidence: Number(row.confidence ?? 1),
210
+ evidence: row.evidence ?? [],
211
+ label: row.label ?? null,
212
+ description: row.description ?? null,
213
+ metadata: row.metadata ?? {},
214
+ source: row.source,
215
+ sourceModel: row.source_model ?? null,
216
+ createdAt: row.created_at,
217
+ updatedAt: row.updated_at,
218
+ bidirectional: Boolean(row.bidirectional ?? false)
219
+ });
220
+ var EdgeRepository = class extends BaseRepository {
221
+ constructor(db) {
222
+ super(db, "edges");
223
+ }
224
+ async findById(id) {
225
+ const row = await this.db.queryOne("SELECT * FROM edges WHERE id = $1", [id]);
226
+ return row ? mapEdgeRow(row) : null;
227
+ }
228
+ async findAll() {
229
+ const rows = await this.db.query("SELECT * FROM edges");
230
+ return rows.map(mapEdgeRow);
231
+ }
232
+ async findByNodeId(nodeId, direction = "both") {
233
+ let sql = "SELECT * FROM edges WHERE from_node_id = $1 OR to_node_id = $1";
234
+ if (direction === "inbound") {
235
+ sql = "SELECT * FROM edges WHERE to_node_id = $1";
236
+ }
237
+ if (direction === "outbound") {
238
+ sql = "SELECT * FROM edges WHERE from_node_id = $1";
239
+ }
240
+ const rows = await this.db.query(sql, [nodeId]);
241
+ return rows.map(mapEdgeRow);
242
+ }
243
+ async findBetweenNodes(fromId, toId) {
244
+ const rows = await this.db.query(
245
+ "SELECT * FROM edges WHERE from_node_id = $1 AND to_node_id = $2",
246
+ [fromId, toId]
247
+ );
248
+ return rows.map(mapEdgeRow);
249
+ }
250
+ async deleteByNodeId(nodeId) {
251
+ return this.db.execute("DELETE FROM edges WHERE from_node_id = $1 OR to_node_id = $1", [nodeId]);
252
+ }
253
+ async batchCreate(edges) {
254
+ const created = [];
255
+ for (const edge of edges) {
256
+ const row = await this.db.queryOne(
257
+ `INSERT INTO edges (from_node_id, to_node_id, relationship_type, strength, confidence, evidence, label, description, metadata, source, bidirectional)
258
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, 'manual', $10)
259
+ RETURNING *`,
260
+ [
261
+ edge.fromNodeId,
262
+ edge.toNodeId,
263
+ edge.relationshipType ?? "related_to",
264
+ edge.strength ?? 0.5,
265
+ edge.confidence ?? 1,
266
+ edge.evidence ?? [],
267
+ edge.label ?? null,
268
+ edge.description ?? null,
269
+ edge.metadata ?? {},
270
+ edge.bidirectional ?? false
271
+ ]
272
+ );
273
+ if (row) created.push(mapEdgeRow(row));
274
+ }
275
+ return created;
276
+ }
277
+ };
278
+
279
+ // src/api/routes/edges.ts
280
+ var createEdgesRoutes = (config) => {
281
+ const db = chunkRTSFO7BW_cjs.createDatabase(config);
282
+ const repo = new EdgeRepository(db);
283
+ return {
284
+ async GET(request) {
285
+ const url = new URL(request.url);
286
+ const params = chunkRTSFO7BW_cjs.listEdgesParamsSchema.parse(Object.fromEntries(url.searchParams));
287
+ const edges = await repo.findAll();
288
+ return Response.json({
289
+ edges,
290
+ pagination: {
291
+ page: params.page ?? 1,
292
+ limit: params.limit ?? edges.length,
293
+ total: edges.length,
294
+ totalPages: 1,
295
+ hasNext: false,
296
+ hasPrev: false
297
+ }
298
+ });
299
+ },
300
+ async POST(request) {
301
+ const body = await request.json();
302
+ const input = chunkRTSFO7BW_cjs.edgeCreateSchema.array().safeParse(body.edges ?? body);
303
+ if (!input.success) {
304
+ return Response.json({ error: input.error.message }, { status: 400 });
305
+ }
306
+ const created = await repo.batchCreate(input.data);
307
+ return Response.json({ created, errors: [] }, { status: 201 });
308
+ },
309
+ async PATCH(request) {
310
+ const url = new URL(request.url);
311
+ const id = url.pathname.split("/").pop();
312
+ if (!id) return new Response("Missing id", { status: 400 });
313
+ const body = await request.json();
314
+ const input = chunkRTSFO7BW_cjs.edgeUpdateSchema.parse(body);
315
+ const updated = await repo.update(id, input);
316
+ return Response.json(updated);
317
+ },
318
+ async DELETE(request) {
319
+ const url = new URL(request.url);
320
+ const id = url.pathname.split("/").pop();
321
+ if (!id) return new Response("Missing id", { status: 400 });
322
+ const deleted = await repo.delete(id);
323
+ return Response.json({ deleted });
324
+ }
325
+ };
326
+ };
327
+
328
+ // src/api/query-builder.ts
329
+ var mapVisualNode = (row) => ({
330
+ id: row.id,
331
+ slug: row.slug,
332
+ label: row.label,
333
+ domain: row.domain,
334
+ tier: row.tier ?? void 0,
335
+ metadata: row.metadata ?? {},
336
+ ref: row.ref ?? null,
337
+ connectionCount: Number(row.connection_count ?? 0),
338
+ position: row.position_override ?? void 0
339
+ });
340
+ var mapVisualEdge = (row) => ({
341
+ id: row.id,
342
+ from: row.from_slug,
343
+ to: row.to_slug,
344
+ relationshipType: row.relationship_type,
345
+ strength: Number(row.strength ?? 0.5),
346
+ label: row.label ?? null
347
+ });
348
+ var GraphQueryBuilder = class {
349
+ constructor(db) {
350
+ this.db = db;
351
+ }
352
+ buildGraphQuery(params) {
353
+ const values = [];
354
+ const filters = [];
355
+ if (params.domains?.length) {
356
+ values.push(params.domains);
357
+ filters.push(`domain = ANY($${values.length})`);
358
+ }
359
+ if (params.nodeTypes?.length) {
360
+ values.push(params.nodeTypes);
361
+ filters.push(`node_type = ANY($${values.length})`);
362
+ }
363
+ if (params.clusterIds?.length) {
364
+ values.push(params.clusterIds);
365
+ filters.push(`cluster_id = ANY($${values.length})`);
366
+ }
367
+ if (params.nodeIds?.length) {
368
+ values.push(params.nodeIds);
369
+ filters.push(`id = ANY($${values.length})`);
370
+ }
371
+ const where = filters.length ? `WHERE ${filters.join(" AND ")}` : "";
372
+ const limit = params.maxNodes ? `LIMIT ${params.maxNodes}` : "";
373
+ const sql = `
374
+ WITH filtered_nodes AS (
375
+ SELECT * FROM nodes
376
+ ${where}
377
+ ${limit}
378
+ )
379
+ SELECT * FROM filtered_nodes;
380
+ `;
381
+ return { sql, values };
382
+ }
383
+ buildExpansionQuery(params) {
384
+ const values = [params.fromNodeIds, params.depth ?? 1];
385
+ const sql = `
386
+ WITH RECURSIVE expanded AS (
387
+ SELECT id, slug, label, domain, tier, metadata, position_override, connection_count, 1 as depth
388
+ FROM nodes
389
+ WHERE id = ANY($1)
390
+
391
+ UNION ALL
392
+
393
+ SELECT n.id, n.slug, n.label, n.domain, n.tier, n.metadata, n.position_override, n.connection_count, e.depth + 1
394
+ FROM expanded e
395
+ JOIN edges ed ON ed.from_node_id = e.id OR ed.to_node_id = e.id
396
+ JOIN nodes n ON (n.id = ed.from_node_id OR n.id = ed.to_node_id)
397
+ WHERE e.depth < $2
398
+ )
399
+ SELECT DISTINCT * FROM expanded;
400
+ `;
401
+ return { sql, values };
402
+ }
403
+ buildPathQuery(params) {
404
+ const values = [params.fromNodeId, params.toNodeId, params.maxDepth ?? 5];
405
+ const sql = `
406
+ WITH RECURSIVE paths AS (
407
+ SELECT ARRAY[from_node_id, to_node_id] as path,
408
+ ARRAY[id] as edge_ids,
409
+ strength as total_strength,
410
+ 1 as depth
411
+ FROM edges
412
+ WHERE from_node_id = $1
413
+
414
+ UNION ALL
415
+
416
+ SELECT p.path || e.to_node_id,
417
+ p.edge_ids || e.id,
418
+ p.total_strength + e.strength,
419
+ p.depth + 1
420
+ FROM paths p
421
+ JOIN edges e ON e.from_node_id = p.path[array_upper(p.path, 1)]
422
+ WHERE NOT e.to_node_id = ANY(p.path)
423
+ AND p.depth < $3
424
+ )
425
+ SELECT * FROM paths
426
+ WHERE path[array_upper(path, 1)] = $2
427
+ ORDER BY array_length(path, 1), total_strength DESC;
428
+ `;
429
+ return { sql, values };
430
+ }
431
+ async getGraph(params) {
432
+ const { sql, values } = this.buildGraphQuery(params);
433
+ const nodes = await this.db.query(sql, values);
434
+ const nodeIds = nodes.map((node) => node.id);
435
+ const edges = await this.db.query(
436
+ `SELECT e.*, n1.slug as from_slug, n2.slug as to_slug
437
+ FROM edges e
438
+ JOIN nodes n1 ON e.from_node_id = n1.id
439
+ JOIN nodes n2 ON e.to_node_id = n2.id
440
+ WHERE e.from_node_id = ANY($1) AND e.to_node_id = ANY($1)`,
441
+ [nodeIds]
442
+ );
443
+ return {
444
+ nodes: nodes.map(mapVisualNode),
445
+ edges: edges.map(mapVisualEdge),
446
+ clusters: [],
447
+ meta: {
448
+ totalNodes: nodes.length,
449
+ totalEdges: edges.length,
450
+ truncated: Boolean(params.maxNodes && nodes.length >= params.maxNodes),
451
+ queryTime: 0
452
+ }
453
+ };
454
+ }
455
+ async expandGraph(params) {
456
+ const { sql, values } = this.buildExpansionQuery(params);
457
+ const nodes = await this.db.query(sql, values);
458
+ const nodeIds = nodes.map((node) => node.id);
459
+ const edges = await this.db.query(
460
+ `SELECT e.*, n1.slug as from_slug, n2.slug as to_slug
461
+ FROM edges e
462
+ JOIN nodes n1 ON e.from_node_id = n1.id
463
+ JOIN nodes n2 ON e.to_node_id = n2.id
464
+ WHERE e.from_node_id = ANY($1) AND e.to_node_id = ANY($1)`,
465
+ [nodeIds]
466
+ );
467
+ return {
468
+ nodes: nodes.map(mapVisualNode),
469
+ edges: edges.map(mapVisualEdge)
470
+ };
471
+ }
472
+ async findPaths(params) {
473
+ const { sql, values } = this.buildPathQuery(params);
474
+ const rows = await this.db.query(
475
+ sql,
476
+ values
477
+ );
478
+ return {
479
+ paths: rows.map((row) => ({
480
+ nodes: row.path,
481
+ edges: row.edge_ids,
482
+ length: row.path.length,
483
+ totalStrength: row.total_strength
484
+ }))
485
+ };
486
+ }
487
+ };
488
+
489
+ // src/api/routes/graph.ts
490
+ var createGraphRoutes = (config) => {
491
+ const db = chunkRTSFO7BW_cjs.createDatabase(config);
492
+ const builder = new GraphQueryBuilder(db);
493
+ return {
494
+ async GET(request) {
495
+ const url = new URL(request.url);
496
+ const params = chunkRTSFO7BW_cjs.getGraphParamsSchema.parse(Object.fromEntries(url.searchParams));
497
+ const result = await builder.getGraph({
498
+ ...params,
499
+ nodeTypes: params.nodeTypes ? Array.isArray(params.nodeTypes) ? params.nodeTypes : [params.nodeTypes] : void 0,
500
+ domains: params.domains ? Array.isArray(params.domains) ? params.domains : [params.domains] : void 0,
501
+ clusterIds: params.clusterIds ? Array.isArray(params.clusterIds) ? params.clusterIds : [params.clusterIds] : void 0,
502
+ nodeIds: params.nodeIds ? Array.isArray(params.nodeIds) ? params.nodeIds : [params.nodeIds] : void 0,
503
+ relationshipTypes: params.relationshipTypes ? Array.isArray(params.relationshipTypes) ? params.relationshipTypes : [params.relationshipTypes] : void 0
504
+ });
505
+ return Response.json(result);
506
+ },
507
+ async POST(request) {
508
+ const url = new URL(request.url);
509
+ if (url.pathname.endsWith("/expand")) {
510
+ const body = await request.json();
511
+ const input = chunkRTSFO7BW_cjs.expandGraphRequestSchema.parse(body);
512
+ const result = await builder.expandGraph(input);
513
+ return Response.json(result);
514
+ }
515
+ if (url.pathname.endsWith("/path")) {
516
+ const body = await request.json();
517
+ const input = chunkRTSFO7BW_cjs.findPathRequestSchema.parse(body);
518
+ const result = await builder.findPaths(input);
519
+ return Response.json(result);
520
+ }
521
+ return new Response("Unsupported", { status: 404 });
522
+ }
523
+ };
524
+ };
525
+
526
+ // src/api/routes/analyze.ts
527
+ var buildPipeline = (config) => {
528
+ const db = chunkRTSFO7BW_cjs.createDatabase(config);
529
+ const events = new chunkCOO66N7H_cjs.EventBus();
530
+ const embeddings = new chunkCOO66N7H_cjs.EmbeddingsService(
531
+ {
532
+ openaiApiKey: config.openai.apiKey,
533
+ model: config.analysis.embeddingModel,
534
+ batchSize: config.analysis.embeddingBatchSize,
535
+ rateLimit: config.analysis.openaiRateLimit,
536
+ cacheTTL: config.analysis.embeddingCacheTTL,
537
+ maxRetries: config.openai.maxRetries ?? 3
538
+ },
539
+ db
540
+ );
541
+ const clustering = new chunkCOO66N7H_cjs.ClusteringEngine(db, embeddings);
542
+ const relationships = new chunkCOO66N7H_cjs.RelationshipEngine(db, {
543
+ model: config.analysis.relationshipInferenceModel,
544
+ minConfidence: config.analysis.relationshipMinConfidence,
545
+ maxPerNode: config.analysis.relationshipMaxPerNode,
546
+ similarityThreshold: config.analysis.clusterSimilarityThreshold,
547
+ includeExisting: true,
548
+ batchSize: 10,
549
+ rateLimit: config.analysis.openaiRateLimit
550
+ });
551
+ return new chunkCOO66N7H_cjs.AnalysisPipeline(db, embeddings, clustering, relationships, events);
552
+ };
553
+ var createAnalyzeRoutes = (config) => {
554
+ return {
555
+ async POST(request) {
556
+ const url = new URL(request.url);
557
+ if (url.pathname.endsWith("/cancel")) {
558
+ const jobId = url.pathname.split("/").slice(-2)[0];
559
+ const pipeline2 = buildPipeline(config);
560
+ const cancelled = await pipeline2.cancelJob(jobId);
561
+ return Response.json({ cancelled });
562
+ }
563
+ const body = await request.json();
564
+ const input = chunkRTSFO7BW_cjs.analysisRequestSchema.parse(body);
565
+ const pipeline = buildPipeline(config);
566
+ let job;
567
+ if (input.action === "embeddings") {
568
+ job = await pipeline.runEmbeddings(input.options ?? {});
569
+ } else if (input.action === "cluster") {
570
+ job = await pipeline.runClustering(input.options ?? {});
571
+ } else if (input.action === "infer_relationships") {
572
+ job = await pipeline.runRelationships(input.options ?? {});
573
+ } else {
574
+ job = await pipeline.runFull(input.options ?? {});
575
+ }
576
+ return Response.json({ jobId: job.id, status: job.status });
577
+ },
578
+ async GET(request) {
579
+ const url = new URL(request.url);
580
+ if (url.pathname.endsWith("/history")) {
581
+ const pipeline2 = buildPipeline(config);
582
+ const jobs = await pipeline2.listJobs({ limit: 50 });
583
+ return Response.json({ jobs });
584
+ }
585
+ const jobId = url.pathname.split("/").pop();
586
+ if (!jobId) return new Response("Missing job id", { status: 400 });
587
+ const pipeline = buildPipeline(config);
588
+ const job = await pipeline.getJob(jobId);
589
+ return Response.json({ job });
590
+ }
591
+ };
592
+ };
593
+
594
+ // src/api/repositories/settings-repository.ts
595
+ var deepMerge = (target, source) => {
596
+ const output = { ...target };
597
+ Object.entries(source).forEach(([key, value]) => {
598
+ if (value && typeof value === "object" && !Array.isArray(value)) {
599
+ output[key] = deepMerge(output[key] ?? {}, value);
600
+ } else if (value !== void 0) {
601
+ output[key] = value;
602
+ }
603
+ });
604
+ return output;
605
+ };
606
+ var defaultSettings = () => ({
607
+ instance: {
608
+ name: "default",
609
+ version: "0.1.0",
610
+ repoName: "omi-neuron-web"
611
+ },
612
+ visualization: chunkRTSFO7BW_cjs.DEFAULT_VISUALIZATION_SETTINGS,
613
+ analysis: chunkRTSFO7BW_cjs.DEFAULT_ANALYSIS_SETTINGS,
614
+ nodeTypes: [],
615
+ domains: [],
616
+ relationshipTypes: []
617
+ });
618
+ var SettingsRepository = class {
619
+ constructor(db) {
620
+ this.db = db;
621
+ }
622
+ async get() {
623
+ const row = await this.db.queryOne("SELECT visualization, analysis, node_types, domains, relationship_types FROM settings WHERE id = $1", [
624
+ "default"
625
+ ]);
626
+ if (!row) {
627
+ return defaultSettings();
628
+ }
629
+ return {
630
+ ...defaultSettings(),
631
+ visualization: { ...chunkRTSFO7BW_cjs.DEFAULT_VISUALIZATION_SETTINGS, ...row.visualization ?? {} },
632
+ analysis: { ...chunkRTSFO7BW_cjs.DEFAULT_ANALYSIS_SETTINGS, ...row.analysis ?? {} },
633
+ nodeTypes: row.node_types ?? [],
634
+ domains: row.domains ?? [],
635
+ relationshipTypes: row.relationship_types ?? []
636
+ };
637
+ }
638
+ async update(settings) {
639
+ const current = await this.get();
640
+ const merged = deepMerge(current, settings);
641
+ await this.db.execute(
642
+ `INSERT INTO settings (id, visualization, analysis, node_types, domains, relationship_types)
643
+ VALUES ('default', $1, $2, $3, $4, $5)
644
+ ON CONFLICT (id) DO UPDATE SET visualization = $1, analysis = $2, node_types = $3, domains = $4, relationship_types = $5, updated_at = NOW()`,
645
+ [
646
+ merged.visualization,
647
+ merged.analysis,
648
+ merged.nodeTypes,
649
+ merged.domains,
650
+ merged.relationshipTypes
651
+ ]
652
+ );
653
+ return merged;
654
+ }
655
+ async reset(sections) {
656
+ const defaults = defaultSettings();
657
+ if (sections?.length) {
658
+ const current = await this.get();
659
+ const updated = { ...current };
660
+ sections.forEach((section) => {
661
+ updated[section] = defaults[section];
662
+ });
663
+ return this.update(updated);
664
+ }
665
+ await this.db.execute(
666
+ `INSERT INTO settings (id, visualization, analysis, node_types, domains, relationship_types)
667
+ VALUES ('default', $1, $2, $3, $4, $5)
668
+ ON CONFLICT (id) DO UPDATE SET visualization = $1, analysis = $2, node_types = $3, domains = $4, relationship_types = $5, updated_at = NOW()`,
669
+ [
670
+ defaults.visualization,
671
+ defaults.analysis,
672
+ defaults.nodeTypes,
673
+ defaults.domains,
674
+ defaults.relationshipTypes
675
+ ]
676
+ );
677
+ return defaults;
678
+ }
679
+ };
680
+
681
+ // src/api/routes/settings.ts
682
+ var createSettingsRoutes = (config) => {
683
+ const db = chunkRTSFO7BW_cjs.createDatabase(config);
684
+ const repo = new SettingsRepository(db);
685
+ return {
686
+ async GET() {
687
+ const settings = await repo.get();
688
+ return Response.json({ settings });
689
+ },
690
+ async PATCH(request) {
691
+ const body = await request.json();
692
+ const input = chunkRTSFO7BW_cjs.neuronSettingsUpdateSchema.parse(body);
693
+ const settings = await repo.update(input);
694
+ return Response.json({ settings });
695
+ },
696
+ async POST(request) {
697
+ const url = new URL(request.url);
698
+ if (!url.pathname.endsWith("/reset")) {
699
+ return new Response("Not found", { status: 404 });
700
+ }
701
+ const body = await request.json().catch(() => ({}));
702
+ const settings = await repo.reset(body?.sections);
703
+ return Response.json({ settings });
704
+ }
705
+ };
706
+ };
707
+
708
+ // src/api/routes/search.ts
709
+ var createSearchRoutes = (config) => {
710
+ const db = chunkRTSFO7BW_cjs.createDatabase(config);
711
+ const embeddings = new chunkCOO66N7H_cjs.EmbeddingsService(
712
+ {
713
+ openaiApiKey: config.openai.apiKey,
714
+ model: config.analysis.embeddingModel,
715
+ batchSize: config.analysis.embeddingBatchSize,
716
+ rateLimit: config.analysis.openaiRateLimit,
717
+ cacheTTL: config.analysis.embeddingCacheTTL,
718
+ maxRetries: config.openai.maxRetries ?? 3
719
+ },
720
+ db
721
+ );
722
+ const scoring = new chunkRTSFO7BW_cjs.ScoringEngine(db);
723
+ return {
724
+ async POST(request) {
725
+ const url = new URL(request.url);
726
+ if (url.pathname.endsWith("/similar")) {
727
+ const body2 = await request.json();
728
+ const input2 = chunkRTSFO7BW_cjs.findSimilarRequestSchema.parse(body2);
729
+ const results2 = await scoring.findSimilar(input2.nodeId, input2.limit ?? 10, input2.excludeConnected ?? false);
730
+ return Response.json({ results: results2 });
731
+ }
732
+ const body = await request.json();
733
+ const input = chunkRTSFO7BW_cjs.semanticSearchRequestSchema.parse(body);
734
+ const embedding = await embeddings.generateEmbedding(input.query);
735
+ const results = await scoring.scoreForQuery(embedding);
736
+ return Response.json({ results: results.slice(0, input.limit ?? 10) });
737
+ }
738
+ };
739
+ };
740
+
741
+ // src/api/routes/health.ts
742
+ var createHealthRoutes = (config) => {
743
+ const db = chunkRTSFO7BW_cjs.createDatabase(config);
744
+ return {
745
+ async GET() {
746
+ const ok = await db.isConnected();
747
+ return Response.json({ status: ok ? "ok" : "degraded", time: (/* @__PURE__ */ new Date()).toISOString() });
748
+ }
749
+ };
750
+ };
751
+
752
+ // src/api/routes/factory.ts
753
+ function createNeuronRoutes(config) {
754
+ return {
755
+ nodes: createNodesRoutes(config),
756
+ edges: createEdgesRoutes(config),
757
+ graph: createGraphRoutes(config),
758
+ analyze: createAnalyzeRoutes(config),
759
+ settings: createSettingsRoutes(config),
760
+ search: createSearchRoutes(config),
761
+ health: createHealthRoutes(config)
762
+ };
763
+ }
764
+
765
+ // src/api/repositories/cluster-repository.ts
766
+ var mapClusterRow = (row) => ({
767
+ id: row.id,
768
+ label: row.label,
769
+ clusterType: row.cluster_type ?? "topic",
770
+ centroid: row.centroid ?? [],
771
+ memberCount: Number(row.member_count ?? 0),
772
+ avgSimilarity: row.avg_similarity ?? 0,
773
+ cohesion: row.cohesion ?? 0,
774
+ description: row.description ?? null,
775
+ keywords: row.keywords ?? [],
776
+ metadata: row.metadata ?? {},
777
+ createdAt: row.created_at,
778
+ updatedAt: row.updated_at,
779
+ lastRecomputedAt: row.last_recomputed_at ?? null
780
+ });
781
+ var ClusterRepository = class extends BaseRepository {
782
+ constructor(db) {
783
+ super(db, "clusters");
784
+ }
785
+ async findById(id) {
786
+ const row = await this.db.queryOne("SELECT * FROM clusters WHERE id = $1", [id]);
787
+ return row ? mapClusterRow(row) : null;
788
+ }
789
+ async findWithMembers(clusterId) {
790
+ const cluster = await this.findById(clusterId);
791
+ const memberships = await this.db.query(
792
+ "SELECT node_id, similarity_score FROM cluster_memberships WHERE cluster_id = $1",
793
+ [clusterId]
794
+ );
795
+ return {
796
+ cluster,
797
+ members: memberships.map((row) => ({ nodeId: row.node_id, similarityScore: row.similarity_score }))
798
+ };
799
+ }
800
+ async updateCentroid(clusterId, centroid) {
801
+ await this.db.execute("UPDATE clusters SET centroid = $1 WHERE id = $2", [centroid, clusterId]);
802
+ }
803
+ async addMember(clusterId, nodeId, similarity) {
804
+ await this.db.execute(
805
+ "INSERT INTO cluster_memberships (node_id, cluster_id, similarity_score, is_primary) VALUES ($1, $2, $3, true) ON CONFLICT (node_id, cluster_id) DO UPDATE SET similarity_score = $3",
806
+ [nodeId, clusterId, similarity]
807
+ );
808
+ }
809
+ async removeMember(clusterId, nodeId) {
810
+ await this.db.execute("DELETE FROM cluster_memberships WHERE cluster_id = $1 AND node_id = $2", [
811
+ clusterId,
812
+ nodeId
813
+ ]);
814
+ }
815
+ };
816
+
817
+ // src/api/repositories/analysis-run-repository.ts
818
+ var AnalysisRunRepository = class extends BaseRepository {
819
+ constructor(db) {
820
+ super(db, "analysis_runs");
821
+ }
822
+ async findActive() {
823
+ return this.db.query("SELECT * FROM analysis_runs WHERE status = $1", ["running"]);
824
+ }
825
+ async updateProgress(id, progress) {
826
+ await this.db.execute("UPDATE analysis_runs SET progress = $1 WHERE id = $2", [progress, id]);
827
+ }
828
+ async markCompleted(id, results) {
829
+ await this.db.execute(
830
+ "UPDATE analysis_runs SET status = $1, results = $2, completed_at = NOW() WHERE id = $3",
831
+ ["completed", results, id]
832
+ );
833
+ }
834
+ async markFailed(id, error) {
835
+ await this.db.execute(
836
+ "UPDATE analysis_runs SET status = $1, error_message = $2, completed_at = NOW() WHERE id = $3",
837
+ ["failed", error, id]
838
+ );
839
+ }
840
+ };
841
+
842
+ // src/api/middleware/cors.ts
843
+ var withCors = (options) => (handler) => async (request) => {
844
+ if (request.method === "OPTIONS") {
845
+ return new Response(null, {
846
+ status: 204,
847
+ headers: buildCorsHeaders(options)
848
+ });
849
+ }
850
+ const response = await handler(request);
851
+ const headers = new Headers(response.headers);
852
+ const corsHeaders = buildCorsHeaders(options);
853
+ corsHeaders.forEach((value, key) => headers.set(key, value));
854
+ return new Response(response.body, { status: response.status, headers });
855
+ };
856
+ var buildCorsHeaders = (options) => {
857
+ const headers = new Headers();
858
+ headers.set("Access-Control-Allow-Origin", options?.origins?.join(",") ?? "*");
859
+ headers.set("Access-Control-Allow-Methods", "GET,POST,PATCH,DELETE,OPTIONS");
860
+ headers.set("Access-Control-Allow-Headers", "Content-Type,Authorization");
861
+ return headers;
862
+ };
863
+
864
+ // src/api/middleware/error-handler.ts
865
+ var ApiError = class extends Error {
866
+ constructor(message, code, statusCode, details) {
867
+ super(message);
868
+ this.code = code;
869
+ this.statusCode = statusCode;
870
+ this.details = details;
871
+ }
872
+ };
873
+ var handleError = (error) => {
874
+ if (error instanceof ApiError) {
875
+ return Response.json(
876
+ {
877
+ error: error.message,
878
+ code: error.code,
879
+ statusCode: error.statusCode,
880
+ details: error.details
881
+ },
882
+ { status: error.statusCode }
883
+ );
884
+ }
885
+ const message = error instanceof Error ? error.message : "Internal error";
886
+ return Response.json(
887
+ {
888
+ error: message,
889
+ code: "INTERNAL_ERROR",
890
+ statusCode: 500
891
+ },
892
+ { status: 500 }
893
+ );
894
+ };
895
+ var withErrorHandler = (handler) => async (request) => {
896
+ try {
897
+ return await handler(request);
898
+ } catch (error) {
899
+ return handleError(error);
900
+ }
901
+ };
902
+
903
+ // src/api/middleware/logging.ts
904
+ var withLogging = (handler) => async (request) => {
905
+ const start = Date.now();
906
+ const response = await handler(request);
907
+ const duration = Date.now() - start;
908
+ console.log(`[omi-neuron] ${request.method} ${request.url} -> ${response.status} (${duration}ms)`);
909
+ return response;
910
+ };
911
+
912
+ // src/api/middleware/timing.ts
913
+ var withTiming = (handler) => async (request) => {
914
+ const start = Date.now();
915
+ const response = await handler(request);
916
+ const duration = Date.now() - start;
917
+ const headers = new Headers(response.headers);
918
+ headers.set("X-Response-Time", `${duration}ms`);
919
+ return new Response(response.body, { status: response.status, headers });
920
+ };
921
+
922
+ // src/api/middleware/index.ts
923
+ var compose = (...handlers) => {
924
+ return (handler) => handlers.reduceRight((acc, fn) => fn(acc), handler);
925
+ };
926
+ var withNeuronMiddleware = (handler, options) => {
927
+ const chain = [withErrorHandler, withLogging, withTiming];
928
+ if (options?.cors) {
929
+ chain.push(withCors(options.cors));
930
+ }
931
+ return compose(...chain)(handler);
932
+ };
933
+
934
+ exports.AnalysisRunRepository = AnalysisRunRepository;
935
+ exports.ClusterRepository = ClusterRepository;
936
+ exports.EdgeRepository = EdgeRepository;
937
+ exports.GraphQueryBuilder = GraphQueryBuilder;
938
+ exports.NodeRepository = NodeRepository;
939
+ exports.SettingsRepository = SettingsRepository;
940
+ exports.createNeuronRoutes = createNeuronRoutes;
941
+ exports.withNeuronMiddleware = withNeuronMiddleware;
942
+ //# sourceMappingURL=index.cjs.map
943
+ //# sourceMappingURL=index.cjs.map