inputlayer-js-dev 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.
package/dist/index.js ADDED
@@ -0,0 +1,2145 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from2, except, desc) => {
13
+ if (from2 && typeof from2 === "object" || typeof from2 === "function") {
14
+ for (let key of __getOwnPropNames(from2))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from2[key], enumerable: !(desc = __getOwnPropDesc(from2, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ AND: () => AND,
34
+ AuthenticationError: () => AuthenticationError,
35
+ CannotDropError: () => CannotDropError,
36
+ ColumnProxy: () => ColumnProxy,
37
+ Connection: () => Connection,
38
+ ConnectionError: () => ConnectionError,
39
+ HnswIndex: () => HnswIndex,
40
+ IndexNotFoundError: () => IndexNotFoundError,
41
+ InputLayer: () => InputLayer,
42
+ InputLayerError: () => InputLayerError,
43
+ InternalError: () => InternalError,
44
+ KnowledgeGraph: () => KnowledgeGraph,
45
+ KnowledgeGraphExistsError: () => KnowledgeGraphExistsError,
46
+ KnowledgeGraphNotFoundError: () => KnowledgeGraphNotFoundError,
47
+ NOT: () => NOT,
48
+ NotificationDispatcher: () => NotificationDispatcher,
49
+ OR: () => OR,
50
+ PermissionError: () => PermissionError,
51
+ QueryTimeoutError: () => QueryTimeoutError,
52
+ RelationDef: () => RelationDef,
53
+ RelationNotFoundError: () => RelationNotFoundError,
54
+ RelationProxy: () => RelationProxy,
55
+ RelationRef: () => RelationRef,
56
+ ResultSet: () => ResultSet,
57
+ RuleNotFoundError: () => RuleNotFoundError,
58
+ SchemaConflictError: () => SchemaConflictError,
59
+ Session: () => Session,
60
+ Timestamp: () => Timestamp,
61
+ ValidationError: () => ValidationError,
62
+ avg: () => avg,
63
+ camelToSnake: () => camelToSnake,
64
+ columnToVariable: () => columnToVariable,
65
+ compileBoolExpr: () => compileBoolExpr,
66
+ compileBulkInsert: () => compileBulkInsert,
67
+ compileConditionalDelete: () => compileConditionalDelete,
68
+ compileDelete: () => compileDelete,
69
+ compileExpr: () => compileExpr,
70
+ compileInsert: () => compileInsert,
71
+ compileQuery: () => compileQuery,
72
+ compileRule: () => compileRule,
73
+ compileSchema: () => compileSchema,
74
+ compileValue: () => compileValue,
75
+ count: () => count,
76
+ countDistinct: () => countDistinct,
77
+ deserializeMessage: () => deserializeMessage,
78
+ from: () => from,
79
+ getColumnTypes: () => getColumnTypes,
80
+ getColumns: () => getColumns,
81
+ max: () => max,
82
+ min: () => min,
83
+ relation: () => relation,
84
+ resolveRelationName: () => resolveRelationName,
85
+ serializeMessage: () => serializeMessage,
86
+ snakeToCamel: () => snakeToCamel,
87
+ sum: () => sum,
88
+ topK: () => topK,
89
+ topKThreshold: () => topKThreshold,
90
+ withinRadius: () => withinRadius,
91
+ wrap: () => wrap
92
+ });
93
+ module.exports = __toCommonJS(index_exports);
94
+
95
+ // src/types.ts
96
+ var Timestamp = class _Timestamp {
97
+ constructor(ms) {
98
+ this.ms = Math.floor(ms);
99
+ }
100
+ static now() {
101
+ return new _Timestamp(Date.now());
102
+ }
103
+ static fromDate(date) {
104
+ return new _Timestamp(date.getTime());
105
+ }
106
+ toDate() {
107
+ return new Date(this.ms);
108
+ }
109
+ valueOf() {
110
+ return this.ms;
111
+ }
112
+ toString() {
113
+ return String(this.ms);
114
+ }
115
+ };
116
+
117
+ // src/naming.ts
118
+ function camelToSnake(name) {
119
+ let s = name.replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2");
120
+ s = s.replace(/([a-z0-9])([A-Z])/g, "$1_$2");
121
+ return s.toLowerCase();
122
+ }
123
+ function snakeToCamel(name) {
124
+ return name.split("_").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
125
+ }
126
+ function columnToVariable(columnName) {
127
+ return snakeToCamel(columnName);
128
+ }
129
+
130
+ // src/ast.ts
131
+ function column(relation2, name, refAlias) {
132
+ return { _tag: "Column", relation: relation2, name, refAlias };
133
+ }
134
+ function literal(value) {
135
+ return { _tag: "Literal", value };
136
+ }
137
+ function arithmetic(op, left, right) {
138
+ return { _tag: "Arithmetic", op, left, right };
139
+ }
140
+ function aggExpr(opts) {
141
+ return {
142
+ _tag: "AggExpr",
143
+ func: opts.func,
144
+ column: opts.column,
145
+ params: opts.params ?? [],
146
+ passthrough: opts.passthrough ?? [],
147
+ orderColumn: opts.orderColumn,
148
+ desc: opts.desc ?? true
149
+ };
150
+ }
151
+ function orderedColumn(col, descending) {
152
+ return { _tag: "OrderedColumn", column: col, descending };
153
+ }
154
+ function comparison(op, left, right) {
155
+ return { _tag: "Comparison", op, left, right };
156
+ }
157
+ function and(left, right) {
158
+ return { _tag: "And", left, right };
159
+ }
160
+ function or(left, right) {
161
+ return { _tag: "Or", left, right };
162
+ }
163
+ function not(operand) {
164
+ return { _tag: "Not", operand };
165
+ }
166
+ function inExpr(col, target) {
167
+ return { _tag: "InExpr", column: col, targetColumn: target };
168
+ }
169
+ function negatedIn(col, target) {
170
+ return { _tag: "NegatedIn", column: col, targetColumn: target };
171
+ }
172
+ function matchExpr(relation2, bindings, negated) {
173
+ return { _tag: "MatchExpr", relation: relation2, bindings, negated };
174
+ }
175
+ function isColumn(e) {
176
+ return e._tag === "Column";
177
+ }
178
+ function isLiteral(e) {
179
+ return e._tag === "Literal";
180
+ }
181
+ function isArithmetic(e) {
182
+ return e._tag === "Arithmetic";
183
+ }
184
+ function isFuncCall(e) {
185
+ return e._tag === "FuncCall";
186
+ }
187
+ function isAggExpr(e) {
188
+ return e._tag === "AggExpr";
189
+ }
190
+ function isOrderedColumn(e) {
191
+ return e._tag === "OrderedColumn";
192
+ }
193
+ function isComparison(e) {
194
+ return e._tag === "Comparison";
195
+ }
196
+ function isAnd(e) {
197
+ return e._tag === "And";
198
+ }
199
+ function isOr(e) {
200
+ return e._tag === "Or";
201
+ }
202
+ function isNot(e) {
203
+ return e._tag === "Not";
204
+ }
205
+ function isInExpr(e) {
206
+ return e._tag === "InExpr";
207
+ }
208
+ function isNegatedIn(e) {
209
+ return e._tag === "NegatedIn";
210
+ }
211
+ function isMatchExpr(e) {
212
+ return e._tag === "MatchExpr";
213
+ }
214
+
215
+ // src/proxy.ts
216
+ function wrap(value) {
217
+ if (value instanceof ColumnProxy) {
218
+ return value.toAst();
219
+ }
220
+ if (value !== null && typeof value === "object" && "_tag" in value) {
221
+ return value;
222
+ }
223
+ return literal(value);
224
+ }
225
+ var ColumnProxy = class {
226
+ constructor(relation2, name, refAlias) {
227
+ this.relation = relation2;
228
+ this.name = name;
229
+ this.refAlias = refAlias;
230
+ }
231
+ toAst() {
232
+ return column(this.relation, this.name, this.refAlias);
233
+ }
234
+ // ── Comparison operators -> BoolExpr ────────────────────────────
235
+ eq(other) {
236
+ return comparison("=", this.toAst(), wrap(other));
237
+ }
238
+ ne(other) {
239
+ return comparison("!=", this.toAst(), wrap(other));
240
+ }
241
+ lt(other) {
242
+ return comparison("<", this.toAst(), wrap(other));
243
+ }
244
+ le(other) {
245
+ return comparison("<=", this.toAst(), wrap(other));
246
+ }
247
+ gt(other) {
248
+ return comparison(">", this.toAst(), wrap(other));
249
+ }
250
+ ge(other) {
251
+ return comparison(">=", this.toAst(), wrap(other));
252
+ }
253
+ // ── Arithmetic operators -> Expr ────────────────────────────────
254
+ add(other) {
255
+ return arithmetic("+", this.toAst(), wrap(other));
256
+ }
257
+ sub(other) {
258
+ return arithmetic("-", this.toAst(), wrap(other));
259
+ }
260
+ mul(other) {
261
+ return arithmetic("*", this.toAst(), wrap(other));
262
+ }
263
+ div(other) {
264
+ return arithmetic("/", this.toAst(), wrap(other));
265
+ }
266
+ mod(other) {
267
+ return arithmetic("%", this.toAst(), wrap(other));
268
+ }
269
+ // ── Membership ──────────────────────────────────────────────────
270
+ in(other) {
271
+ return inExpr(this.toAst(), other.toAst());
272
+ }
273
+ notIn(other) {
274
+ return negatedIn(this.toAst(), other.toAst());
275
+ }
276
+ // ── Ordering ────────────────────────────────────────────────────
277
+ asc() {
278
+ return orderedColumn(this.toAst(), false);
279
+ }
280
+ desc() {
281
+ return orderedColumn(this.toAst(), true);
282
+ }
283
+ // ── Multi-column match ──────────────────────────────────────────
284
+ matches(relationName, on) {
285
+ const bindings = {};
286
+ for (const [targetCol, sourceColName] of Object.entries(on)) {
287
+ bindings[targetCol] = column(this.relation, sourceColName, this.refAlias);
288
+ }
289
+ return matchExpr(relationName, bindings, false);
290
+ }
291
+ notMatches(relationName, on) {
292
+ const bindings = {};
293
+ for (const [targetCol, sourceColName] of Object.entries(on)) {
294
+ bindings[targetCol] = column(this.relation, sourceColName, this.refAlias);
295
+ }
296
+ return matchExpr(relationName, bindings, true);
297
+ }
298
+ };
299
+ function AND(left, right) {
300
+ return and(left, right);
301
+ }
302
+ function OR(left, right) {
303
+ return or(left, right);
304
+ }
305
+ function NOT(operand) {
306
+ return not(operand);
307
+ }
308
+ var RelationProxy = class {
309
+ constructor(relationName, refAlias) {
310
+ this.relationName = relationName;
311
+ this.refAlias = refAlias;
312
+ }
313
+ /** Get a ColumnProxy for the named column. */
314
+ col(name) {
315
+ return new ColumnProxy(this.relationName, name, this.refAlias);
316
+ }
317
+ };
318
+ var RelationRef = class {
319
+ constructor(schema, alias) {
320
+ this.schema = schema;
321
+ this.alias = alias;
322
+ this.relationName = schema.name ?? camelToSnake(alias);
323
+ }
324
+ /** Get a ColumnProxy for the named column. */
325
+ col(name) {
326
+ return new ColumnProxy(this.relationName, name, this.alias);
327
+ }
328
+ };
329
+
330
+ // src/relation.ts
331
+ var RelationDef = class {
332
+ constructor(className, columnTypes, name) {
333
+ this.className = className;
334
+ this.relationName = name ?? camelToSnake(className);
335
+ this.columns = Object.keys(columnTypes);
336
+ this.columnTypes = { ...columnTypes };
337
+ }
338
+ /** Get a ColumnProxy for a column (for query building). */
339
+ col(name) {
340
+ if (!(name in this.columnTypes)) {
341
+ throw new Error(
342
+ `Column '${name}' does not exist on relation '${this.relationName}'. Available: ${this.columns.join(", ")}`
343
+ );
344
+ }
345
+ return new ColumnProxy(this.relationName, name);
346
+ }
347
+ /**
348
+ * Create multiple independent references for self-joins.
349
+ *
350
+ * Usage:
351
+ * const [r1, r2] = Follow.refs(2);
352
+ * kg.query({ select: [r1.col("follower"), r2.col("followee")], join: [r1, r2], ... });
353
+ */
354
+ refs(n) {
355
+ const refs = [];
356
+ for (let i = 1; i <= n; i++) {
357
+ refs.push(
358
+ new RelationRef(
359
+ { name: this.relationName, columns: this.columns.map((c) => ({ name: c, type: this.columnTypes[c] })) },
360
+ `${this.relationName}_${i}`
361
+ )
362
+ );
363
+ }
364
+ return refs;
365
+ }
366
+ };
367
+ function relation(className, columnTypes, opts) {
368
+ return new RelationDef(className, columnTypes, opts?.name);
369
+ }
370
+ function compileValue(value) {
371
+ if (value === null || value === void 0) {
372
+ return "null";
373
+ }
374
+ if (typeof value === "boolean") {
375
+ return value ? "true" : "false";
376
+ }
377
+ if (value instanceof Timestamp) {
378
+ return String(value.ms);
379
+ }
380
+ if (typeof value === "number") {
381
+ if (Number.isInteger(value)) {
382
+ return String(value);
383
+ }
384
+ return String(value);
385
+ }
386
+ if (typeof value === "string") {
387
+ const escaped = value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
388
+ return `"${escaped}"`;
389
+ }
390
+ if (Array.isArray(value)) {
391
+ const inner = value.map(compileValue).join(", ");
392
+ return `[${inner}]`;
393
+ }
394
+ throw new TypeError(
395
+ `Cannot compile value of type ${typeof value}: ${String(value)}`
396
+ );
397
+ }
398
+ function resolveRelationName(r) {
399
+ if (typeof r === "string") return r;
400
+ return r.relationName;
401
+ }
402
+ function getColumns(r) {
403
+ return r.columns;
404
+ }
405
+ function getColumnTypes(r) {
406
+ return r.columnTypes;
407
+ }
408
+
409
+ // src/derived.ts
410
+ var FromWhere = class {
411
+ constructor(relations, condition) {
412
+ this.relations = relations;
413
+ this.condition = condition;
414
+ }
415
+ /**
416
+ * Map derived columns to body expressions.
417
+ * Keys must match the derived relation's column names.
418
+ */
419
+ select(columns) {
420
+ const selectMap = {};
421
+ for (const [name, val] of Object.entries(columns)) {
422
+ if (val instanceof ColumnProxy) {
423
+ selectMap[name] = val.toAst();
424
+ } else {
425
+ selectMap[name] = val;
426
+ }
427
+ }
428
+ return {
429
+ relations: this.relations,
430
+ selectMap,
431
+ condition: this.condition
432
+ };
433
+ }
434
+ };
435
+ var FromBuilder = class {
436
+ constructor(rels) {
437
+ this.relations = rels.map((r) => {
438
+ if (r instanceof RelationDef) {
439
+ return { name: r.relationName, def: r, alias: void 0 };
440
+ }
441
+ return {
442
+ name: r.relationName,
443
+ def: {
444
+ relationName: r.relationName,
445
+ columns: r.schema.columns.map((c) => c.name),
446
+ columnTypes: {}
447
+ },
448
+ alias: r.alias
449
+ };
450
+ });
451
+ }
452
+ /**
453
+ * Add a filter/join condition.
454
+ * Accepts a BoolExpr or a callback receiving RelationProxy objects.
455
+ */
456
+ where(condition) {
457
+ let resolved;
458
+ if (typeof condition === "function") {
459
+ const proxies = this.relations.map(
460
+ (r) => new RelationProxy(r.name, r.alias)
461
+ );
462
+ resolved = condition(...proxies);
463
+ } else {
464
+ resolved = condition;
465
+ }
466
+ return new FromWhere(this.relations, resolved);
467
+ }
468
+ /**
469
+ * Map derived columns to body expressions (no filter).
470
+ * Keys must match the derived relation's column names.
471
+ */
472
+ select(columns) {
473
+ const selectMap = {};
474
+ for (const [name, val] of Object.entries(columns)) {
475
+ if (val instanceof ColumnProxy) {
476
+ selectMap[name] = val.toAst();
477
+ } else {
478
+ selectMap[name] = val;
479
+ }
480
+ }
481
+ return {
482
+ relations: this.relations,
483
+ selectMap,
484
+ condition: void 0
485
+ };
486
+ }
487
+ };
488
+ function from(...relations) {
489
+ return new FromBuilder(relations);
490
+ }
491
+
492
+ // src/aggregations.ts
493
+ function toExpr(col) {
494
+ if ("toAst" in col && typeof col.toAst === "function") {
495
+ return col.toAst();
496
+ }
497
+ return col;
498
+ }
499
+ function count(column2) {
500
+ if (column2 === void 0) {
501
+ return aggExpr({ func: "count" });
502
+ }
503
+ return aggExpr({ func: "count", column: toExpr(column2) });
504
+ }
505
+ function countDistinct(column2) {
506
+ return aggExpr({ func: "count_distinct", column: toExpr(column2) });
507
+ }
508
+ function sum(column2) {
509
+ return aggExpr({ func: "sum", column: toExpr(column2) });
510
+ }
511
+ function min(column2) {
512
+ return aggExpr({ func: "min", column: toExpr(column2) });
513
+ }
514
+ function max(column2) {
515
+ return aggExpr({ func: "max", column: toExpr(column2) });
516
+ }
517
+ function avg(column2) {
518
+ return aggExpr({ func: "avg", column: toExpr(column2) });
519
+ }
520
+ function topK(opts) {
521
+ return aggExpr({
522
+ func: "top_k",
523
+ params: [opts.k],
524
+ passthrough: (opts.passthrough ?? []).map(toExpr),
525
+ orderColumn: toExpr(opts.orderBy),
526
+ desc: opts.desc ?? true
527
+ });
528
+ }
529
+ function topKThreshold(opts) {
530
+ return aggExpr({
531
+ func: "top_k_threshold",
532
+ params: [opts.k, opts.threshold],
533
+ passthrough: (opts.passthrough ?? []).map(toExpr),
534
+ orderColumn: toExpr(opts.orderBy),
535
+ desc: opts.desc ?? true
536
+ });
537
+ }
538
+ function withinRadius(opts) {
539
+ return aggExpr({
540
+ func: "within_radius",
541
+ params: [opts.maxDistance],
542
+ passthrough: (opts.passthrough ?? []).map(toExpr),
543
+ orderColumn: toExpr(opts.distance),
544
+ desc: !(opts.asc ?? true)
545
+ });
546
+ }
547
+
548
+ // src/index-def.ts
549
+ var HnswIndex = class {
550
+ constructor(opts) {
551
+ this.name = opts.name;
552
+ this.relation = opts.relation;
553
+ this.column = opts.column;
554
+ this.metric = opts.metric ?? "cosine";
555
+ this.m = opts.m ?? 16;
556
+ this.efConstruction = opts.efConstruction ?? 100;
557
+ this.efSearch = opts.efSearch ?? 50;
558
+ }
559
+ /** Compile this index definition to an IQL meta command. */
560
+ toIQL() {
561
+ const relName = resolveRelationName(this.relation);
562
+ return `.index create ${this.name} on ${relName}(${this.column}) type hnsw metric ${this.metric} m ${this.m} ef_construction ${this.efConstruction} ef_search ${this.efSearch}`;
563
+ }
564
+ };
565
+
566
+ // src/errors.ts
567
+ var InputLayerError = class extends Error {
568
+ constructor(message) {
569
+ super(message);
570
+ this.name = "InputLayerError";
571
+ }
572
+ };
573
+ var ConnectionError = class extends InputLayerError {
574
+ constructor(message) {
575
+ super(message);
576
+ this.name = "ConnectionError";
577
+ }
578
+ };
579
+ var AuthenticationError = class extends InputLayerError {
580
+ constructor(message) {
581
+ super(message);
582
+ this.name = "AuthenticationError";
583
+ }
584
+ };
585
+ var SchemaConflictError = class extends InputLayerError {
586
+ constructor(message, opts) {
587
+ super(message);
588
+ this.name = "SchemaConflictError";
589
+ this.existingSchema = opts?.existingSchema;
590
+ this.proposedSchema = opts?.proposedSchema;
591
+ this.conflicts = opts?.conflicts ?? [];
592
+ }
593
+ };
594
+ var ValidationError = class extends InputLayerError {
595
+ constructor(message, opts) {
596
+ super(message);
597
+ this.name = "ValidationError";
598
+ this.details = opts?.details ?? [];
599
+ }
600
+ };
601
+ var QueryTimeoutError = class extends InputLayerError {
602
+ constructor(message) {
603
+ super(message);
604
+ this.name = "QueryTimeoutError";
605
+ }
606
+ };
607
+ var PermissionError = class extends InputLayerError {
608
+ constructor(message) {
609
+ super(message);
610
+ this.name = "PermissionError";
611
+ }
612
+ };
613
+ var KnowledgeGraphNotFoundError = class extends InputLayerError {
614
+ constructor(message) {
615
+ super(message);
616
+ this.name = "KnowledgeGraphNotFoundError";
617
+ }
618
+ };
619
+ var KnowledgeGraphExistsError = class extends InputLayerError {
620
+ constructor(message) {
621
+ super(message);
622
+ this.name = "KnowledgeGraphExistsError";
623
+ }
624
+ };
625
+ var CannotDropError = class extends InputLayerError {
626
+ constructor(message) {
627
+ super(message);
628
+ this.name = "CannotDropError";
629
+ }
630
+ };
631
+ var RelationNotFoundError = class extends InputLayerError {
632
+ constructor(message) {
633
+ super(message);
634
+ this.name = "RelationNotFoundError";
635
+ }
636
+ };
637
+ var RuleNotFoundError = class extends InputLayerError {
638
+ constructor(message) {
639
+ super(message);
640
+ this.name = "RuleNotFoundError";
641
+ }
642
+ };
643
+ var IndexNotFoundError = class extends InputLayerError {
644
+ constructor(message) {
645
+ super(message);
646
+ this.name = "IndexNotFoundError";
647
+ }
648
+ };
649
+ var InternalError = class extends InputLayerError {
650
+ constructor(message) {
651
+ super(message);
652
+ this.name = "InternalError";
653
+ }
654
+ };
655
+
656
+ // src/result.ts
657
+ var ResultSet = class {
658
+ constructor(opts) {
659
+ this.columns = opts.columns;
660
+ this.rows = opts.rows;
661
+ this.rowCount = opts.rowCount ?? opts.rows.length;
662
+ this.totalCount = opts.totalCount ?? this.rowCount;
663
+ this.truncated = opts.truncated ?? false;
664
+ this.executionTimeMs = opts.executionTimeMs ?? 0;
665
+ this.rowProvenance = opts.rowProvenance;
666
+ this.hasEphemeral = opts.hasEphemeral ?? false;
667
+ this.ephemeralSources = opts.ephemeralSources ?? [];
668
+ this.warnings = opts.warnings ?? [];
669
+ }
670
+ /** Number of result rows. */
671
+ get length() {
672
+ return this.rowCount;
673
+ }
674
+ /** True if there are any results. */
675
+ get isEmpty() {
676
+ return this.rowCount === 0;
677
+ }
678
+ /** Get a single row as a keyed object. */
679
+ get(index) {
680
+ return this.rowToObj(this.rows[index]);
681
+ }
682
+ /** Get the first row or undefined if empty. */
683
+ first() {
684
+ if (this.rows.length === 0) return void 0;
685
+ return this.rowToObj(this.rows[0]);
686
+ }
687
+ /** Return the single value from a 1x1 result. */
688
+ scalar() {
689
+ if (this.rows.length === 0 || this.rows[0].length === 0) {
690
+ throw new Error("No results to extract scalar from");
691
+ }
692
+ return this.rows[0][0];
693
+ }
694
+ /** Convert all rows to a list of keyed objects. */
695
+ toDicts() {
696
+ return this.rows.map((row) => this.rowToObj(row));
697
+ }
698
+ /** Convert all rows to a list of tuples (arrays). */
699
+ toTuples() {
700
+ return this.rows.map((row) => [...row]);
701
+ }
702
+ /** Iterate over rows as keyed objects. */
703
+ [Symbol.iterator]() {
704
+ let i = 0;
705
+ const self = this;
706
+ return {
707
+ next() {
708
+ if (i < self.rows.length) {
709
+ return { value: self.rowToObj(self.rows[i++]), done: false };
710
+ }
711
+ return { value: void 0, done: true };
712
+ }
713
+ };
714
+ }
715
+ rowToObj(row) {
716
+ const obj = {};
717
+ for (let i = 0; i < this.columns.length && i < row.length; i++) {
718
+ obj[this.columns[i]] = row[i];
719
+ }
720
+ return obj;
721
+ }
722
+ };
723
+
724
+ // src/connection.ts
725
+ var import_ws = __toESM(require("ws"));
726
+
727
+ // src/protocol.ts
728
+ function serializeMessage(msg) {
729
+ return JSON.stringify(msg);
730
+ }
731
+ function deserializeMessage(data) {
732
+ const obj = JSON.parse(data);
733
+ const type = obj.type;
734
+ if (type === "authenticated") {
735
+ return obj;
736
+ }
737
+ if (type === "auth_error") {
738
+ return obj;
739
+ }
740
+ if (type === "result") {
741
+ return obj;
742
+ }
743
+ if (type === "error") {
744
+ return obj;
745
+ }
746
+ if (type === "result_start") {
747
+ return obj;
748
+ }
749
+ if (type === "result_chunk") {
750
+ return obj;
751
+ }
752
+ if (type === "result_end") {
753
+ return obj;
754
+ }
755
+ if (type === "pong") {
756
+ return obj;
757
+ }
758
+ if (type === "persistent_update" || type === "rule_change" || type === "kg_change" || type === "schema_change") {
759
+ return obj;
760
+ }
761
+ throw new Error(`Unknown message type: ${type}`);
762
+ }
763
+
764
+ // src/notifications.ts
765
+ var NotificationDispatcher = class {
766
+ constructor() {
767
+ this.callbacks = [];
768
+ this._lastSeq = 0;
769
+ this.waiters = [];
770
+ }
771
+ get lastSeq() {
772
+ return this._lastSeq;
773
+ }
774
+ /**
775
+ * Register a callback for notifications.
776
+ *
777
+ * @param eventType - Filter by event type (e.g. "persistent_update")
778
+ * @param opts - Additional filters
779
+ * @param callback - Function to call when a matching event arrives
780
+ */
781
+ on(eventType, opts, callback) {
782
+ this.callbacks.push({
783
+ eventType,
784
+ relation: opts.relation,
785
+ knowledgeGraph: opts.knowledgeGraph,
786
+ callback
787
+ });
788
+ }
789
+ /** Remove a previously registered callback. */
790
+ off(callback) {
791
+ this.callbacks = this.callbacks.filter((e) => e.callback !== callback);
792
+ }
793
+ /** Dispatch a notification to matching callbacks. */
794
+ dispatch(event) {
795
+ this._lastSeq = Math.max(this._lastSeq, event.seq);
796
+ for (const waiter of this.waiters) {
797
+ waiter(event);
798
+ }
799
+ this.waiters = [];
800
+ for (const entry of this.callbacks) {
801
+ if (entry.eventType !== void 0 && event.type !== entry.eventType) continue;
802
+ if (entry.relation !== void 0 && event.relation !== entry.relation) continue;
803
+ if (entry.knowledgeGraph !== void 0 && event.knowledgeGraph !== entry.knowledgeGraph) continue;
804
+ try {
805
+ entry.callback(event);
806
+ } catch {
807
+ }
808
+ }
809
+ }
810
+ /** Wait for the next notification event. */
811
+ next() {
812
+ return new Promise((resolve) => {
813
+ this.waiters.push(resolve);
814
+ });
815
+ }
816
+ /**
817
+ * Create an async iterable of notification events.
818
+ *
819
+ * Usage:
820
+ * for await (const event of dispatcher.events()) { ... }
821
+ */
822
+ async *events() {
823
+ while (true) {
824
+ yield await this.next();
825
+ }
826
+ }
827
+ };
828
+
829
+ // src/connection.ts
830
+ var Connection = class {
831
+ constructor(opts) {
832
+ this.ws = null;
833
+ this._connected = false;
834
+ this._dispatcher = new NotificationDispatcher();
835
+ this.url = opts.url;
836
+ this.username = opts.username;
837
+ this.password = opts.password;
838
+ this.apiKey = opts.apiKey;
839
+ this.autoReconnect = opts.autoReconnect ?? true;
840
+ this.reconnectDelay = opts.reconnectDelay ?? 1;
841
+ this.maxReconnectAttempts = opts.maxReconnectAttempts ?? 10;
842
+ this.initialKg = opts.initialKg;
843
+ this._lastSeq = opts.lastSeq;
844
+ }
845
+ // ── Properties ──────────────────────────────────────────────────
846
+ get connected() {
847
+ return this._connected;
848
+ }
849
+ get sessionId() {
850
+ return this._sessionId;
851
+ }
852
+ get serverVersion() {
853
+ return this._serverVersion;
854
+ }
855
+ get role() {
856
+ return this._role;
857
+ }
858
+ get currentKg() {
859
+ return this._currentKg;
860
+ }
861
+ get dispatcher() {
862
+ return this._dispatcher;
863
+ }
864
+ get lastSeq() {
865
+ return this._dispatcher.lastSeq;
866
+ }
867
+ // ── Connection lifecycle ────────────────────────────────────────
868
+ async connect() {
869
+ let wsUrl = this.url;
870
+ const params = [];
871
+ if (this.initialKg) {
872
+ params.push(`kg=${this.initialKg}`);
873
+ }
874
+ if (this._lastSeq !== void 0) {
875
+ params.push(`last_seq=${this._lastSeq}`);
876
+ }
877
+ if (params.length > 0) {
878
+ const separator = wsUrl.includes("?") ? "&" : "?";
879
+ wsUrl = `${wsUrl}${separator}${params.join("&")}`;
880
+ }
881
+ try {
882
+ this.ws = await this.createWebSocket(wsUrl);
883
+ } catch (e) {
884
+ throw new ConnectionError(`Failed to connect to ${wsUrl}: ${e}`);
885
+ }
886
+ await this.authenticate();
887
+ this._connected = true;
888
+ this.ws.on("message", (data) => {
889
+ try {
890
+ const msg = deserializeMessage(String(data));
891
+ if (this.pendingResolve) {
892
+ this.pendingResolve(msg);
893
+ this.pendingResolve = void 0;
894
+ } else if (this.isNotification(msg)) {
895
+ this.dispatchNotification(msg);
896
+ }
897
+ } catch {
898
+ }
899
+ });
900
+ this.ws.on("close", () => {
901
+ this._connected = false;
902
+ if (this.autoReconnect) {
903
+ this.reconnect().catch(() => {
904
+ });
905
+ }
906
+ });
907
+ this.ws.on("error", () => {
908
+ });
909
+ }
910
+ async close() {
911
+ this._connected = false;
912
+ if (this.ws) {
913
+ this.ws.removeAllListeners();
914
+ this.ws.close();
915
+ this.ws = null;
916
+ }
917
+ }
918
+ // ── Authentication ──────────────────────────────────────────────
919
+ async authenticate() {
920
+ if (!this.ws) throw new ConnectionError("Not connected");
921
+ let msg;
922
+ if (this.apiKey) {
923
+ msg = { type: "authenticate", api_key: this.apiKey };
924
+ } else if (this.username && this.password) {
925
+ msg = { type: "login", username: this.username, password: this.password };
926
+ } else {
927
+ throw new AuthenticationError(
928
+ "No credentials provided (need username/password or apiKey)"
929
+ );
930
+ }
931
+ this.ws.send(serializeMessage(msg));
932
+ const response = await this.receiveOne();
933
+ if (response.type === "auth_error") {
934
+ throw new AuthenticationError(response.message);
935
+ }
936
+ if (response.type === "authenticated") {
937
+ this._sessionId = response.session_id;
938
+ this._serverVersion = response.version;
939
+ this._role = response.role;
940
+ this._currentKg = response.knowledge_graph;
941
+ return;
942
+ }
943
+ throw new AuthenticationError(`Unexpected auth response: ${JSON.stringify(response)}`);
944
+ }
945
+ // ── Command execution ───────────────────────────────────────────
946
+ /**
947
+ * Send a program/command and wait for the result.
948
+ * Transparently assembles streamed results (result_start -> chunks -> result_end).
949
+ */
950
+ async execute(program) {
951
+ if (!this._connected || !this.ws) {
952
+ throw new ConnectionError("Not connected");
953
+ }
954
+ const msg = { type: "execute", program };
955
+ this.ws.send(serializeMessage(msg));
956
+ return this.readResult();
957
+ }
958
+ async readResult() {
959
+ while (true) {
960
+ const response = await this.receiveMessage();
961
+ if (this.isNotification(response)) {
962
+ this.dispatchNotification(response);
963
+ continue;
964
+ }
965
+ if (response.type === "pong") {
966
+ continue;
967
+ }
968
+ if (response.type === "result") {
969
+ if (response.switched_kg) {
970
+ this._currentKg = response.switched_kg;
971
+ }
972
+ return response;
973
+ }
974
+ if (response.type === "error") {
975
+ return {
976
+ type: "result",
977
+ columns: ["error"],
978
+ rows: [[response.message]],
979
+ row_count: 1,
980
+ total_count: 1,
981
+ truncated: false,
982
+ execution_time_ms: 0
983
+ };
984
+ }
985
+ if (response.type === "result_start") {
986
+ return this.assembleStream(response);
987
+ }
988
+ throw new InternalError(
989
+ `Unexpected message during result read: ${JSON.stringify(response)}`
990
+ );
991
+ }
992
+ }
993
+ async assembleStream(start) {
994
+ const allRows = [];
995
+ const allProvenance = [];
996
+ while (true) {
997
+ const response = await this.receiveMessage();
998
+ if (this.isNotification(response)) {
999
+ this.dispatchNotification(response);
1000
+ continue;
1001
+ }
1002
+ if (response.type === "result_chunk") {
1003
+ allRows.push(...response.rows);
1004
+ if (response.row_provenance) {
1005
+ allProvenance.push(...response.row_provenance);
1006
+ }
1007
+ continue;
1008
+ }
1009
+ if (response.type === "result_end") {
1010
+ if (start.switched_kg) {
1011
+ this._currentKg = start.switched_kg;
1012
+ }
1013
+ return {
1014
+ type: "result",
1015
+ columns: start.columns,
1016
+ rows: allRows,
1017
+ row_count: response.row_count,
1018
+ total_count: start.total_count,
1019
+ truncated: start.truncated,
1020
+ execution_time_ms: start.execution_time_ms,
1021
+ row_provenance: allProvenance.length > 0 ? allProvenance : void 0,
1022
+ metadata: start.metadata,
1023
+ switched_kg: start.switched_kg
1024
+ };
1025
+ }
1026
+ throw new InternalError(
1027
+ `Unexpected message during streaming: ${JSON.stringify(response)}`
1028
+ );
1029
+ }
1030
+ }
1031
+ // ── Notification handling ───────────────────────────────────────
1032
+ isNotification(msg) {
1033
+ return msg.type === "persistent_update" || msg.type === "rule_change" || msg.type === "kg_change" || msg.type === "schema_change";
1034
+ }
1035
+ dispatchNotification(notif) {
1036
+ const event = {
1037
+ type: notif.type,
1038
+ seq: notif.seq,
1039
+ timestampMs: notif.timestamp_ms,
1040
+ sessionId: notif.session_id,
1041
+ knowledgeGraph: notif.knowledge_graph,
1042
+ relation: notif.relation,
1043
+ operation: notif.operation,
1044
+ count: notif.count,
1045
+ ruleName: notif.rule_name,
1046
+ entity: notif.entity
1047
+ };
1048
+ this._dispatcher.dispatch(event);
1049
+ }
1050
+ // ── Reconnection ────────────────────────────────────────────────
1051
+ async reconnect() {
1052
+ let delay = this.reconnectDelay;
1053
+ for (let attempt = 0; attempt < this.maxReconnectAttempts; attempt++) {
1054
+ await sleep(delay * 1e3);
1055
+ try {
1056
+ this._lastSeq = this._dispatcher.lastSeq;
1057
+ await this.connect();
1058
+ return;
1059
+ } catch {
1060
+ delay = Math.min(delay * 2, 60);
1061
+ }
1062
+ }
1063
+ throw new ConnectionError(
1064
+ `Failed to reconnect after ${this.maxReconnectAttempts} attempts`
1065
+ );
1066
+ }
1067
+ // ── Keep-alive ──────────────────────────────────────────────────
1068
+ async ping() {
1069
+ if (!this.ws) throw new ConnectionError("Not connected");
1070
+ this.ws.send(serializeMessage({ type: "ping" }));
1071
+ }
1072
+ // ── WebSocket helpers ───────────────────────────────────────────
1073
+ createWebSocket(url) {
1074
+ return new Promise((resolve, reject) => {
1075
+ const ws = new import_ws.default(url);
1076
+ ws.once("open", () => resolve(ws));
1077
+ ws.once("error", (err) => reject(err));
1078
+ });
1079
+ }
1080
+ /** Receive exactly one message (used during auth before handler is set up). */
1081
+ receiveOne() {
1082
+ return new Promise((resolve, reject) => {
1083
+ if (!this.ws) return reject(new ConnectionError("Not connected"));
1084
+ const handler = (data) => {
1085
+ this.ws?.removeListener("message", handler);
1086
+ try {
1087
+ resolve(deserializeMessage(String(data)));
1088
+ } catch (e) {
1089
+ reject(e);
1090
+ }
1091
+ };
1092
+ this.ws.on("message", handler);
1093
+ });
1094
+ }
1095
+ /** Receive the next message via the pendingResolve mechanism. */
1096
+ receiveMessage() {
1097
+ return new Promise((resolve) => {
1098
+ this.pendingResolve = resolve;
1099
+ });
1100
+ }
1101
+ };
1102
+ function sleep(ms) {
1103
+ return new Promise((resolve) => setTimeout(resolve, ms));
1104
+ }
1105
+
1106
+ // src/compiler.ts
1107
+ var VarEnv = class {
1108
+ constructor() {
1109
+ this.map = /* @__PURE__ */ new Map();
1110
+ this.counter = 0;
1111
+ this.parent = /* @__PURE__ */ new Map();
1112
+ }
1113
+ find(key) {
1114
+ let current = key;
1115
+ while (true) {
1116
+ const p = this.parent.get(current) ?? current;
1117
+ if (p === current) return current;
1118
+ const gp = this.parent.get(p) ?? p;
1119
+ this.parent.set(current, gp);
1120
+ current = gp;
1121
+ }
1122
+ }
1123
+ union(a, b) {
1124
+ const ra = this.find(a);
1125
+ const rb = this.find(b);
1126
+ if (ra !== rb) {
1127
+ this.parent.set(rb, ra);
1128
+ }
1129
+ }
1130
+ getVar(col) {
1131
+ const key = `${col.refAlias ?? col.relation}.${col.name}`;
1132
+ const root = this.find(key);
1133
+ const existing = this.map.get(root);
1134
+ if (existing !== void 0) return existing;
1135
+ let varName = columnToVariable(col.name);
1136
+ const usedVars = new Set(this.map.values());
1137
+ if (usedVars.has(varName)) {
1138
+ this.counter++;
1139
+ varName = `${varName}_${this.counter}`;
1140
+ }
1141
+ this.map.set(root, varName);
1142
+ return varName;
1143
+ }
1144
+ unify(colA, colB) {
1145
+ const keyA = `${colA.refAlias ?? colA.relation}.${colA.name}`;
1146
+ const keyB = `${colB.refAlias ?? colB.relation}.${colB.name}`;
1147
+ this.union(keyA, keyB);
1148
+ const root = this.find(keyA);
1149
+ const existing = this.map.get(root);
1150
+ if (existing !== void 0) return existing;
1151
+ let varName = columnToVariable(colA.name);
1152
+ const usedVars = new Set(this.map.values());
1153
+ if (usedVars.has(varName)) {
1154
+ this.counter++;
1155
+ varName = `${varName}_${this.counter}`;
1156
+ }
1157
+ this.map.set(root, varName);
1158
+ return varName;
1159
+ }
1160
+ lookup(col) {
1161
+ const key = `${col.refAlias ?? col.relation}.${col.name}`;
1162
+ const root = this.find(key);
1163
+ return this.map.get(root);
1164
+ }
1165
+ /** Direct-set a variable for conditional delete setup. */
1166
+ set(key, varName) {
1167
+ this.map.set(key, varName);
1168
+ }
1169
+ };
1170
+ function compileExpr(expr, env) {
1171
+ if (isColumn(expr)) {
1172
+ return env.getVar(expr);
1173
+ }
1174
+ if (isLiteral(expr)) {
1175
+ return compileValue(expr.value);
1176
+ }
1177
+ if (isArithmetic(expr)) {
1178
+ const left = compileExpr(expr.left, env);
1179
+ const right = compileExpr(expr.right, env);
1180
+ return `${left} ${expr.op} ${right}`;
1181
+ }
1182
+ if (isFuncCall(expr)) {
1183
+ const args = expr.args.map((a) => compileExpr(a, env)).join(", ");
1184
+ return `${expr.name}(${args})`;
1185
+ }
1186
+ if (isOrderedColumn(expr)) {
1187
+ const varStr = compileExpr(expr.column, env);
1188
+ const suffix = expr.descending ? ":desc" : ":asc";
1189
+ return `${varStr}${suffix}`;
1190
+ }
1191
+ if (isAggExpr(expr)) {
1192
+ return compileAggExpr(expr, env);
1193
+ }
1194
+ throw new TypeError(`Cannot compile expression: ${JSON.stringify(expr)}`);
1195
+ }
1196
+ function compileAggExpr(agg, env) {
1197
+ const parts = [];
1198
+ for (const p of agg.params) {
1199
+ parts.push(compileValue(p));
1200
+ }
1201
+ for (const pt of agg.passthrough) {
1202
+ parts.push(compileExpr(pt, env));
1203
+ }
1204
+ if (agg.orderColumn !== void 0) {
1205
+ const orderVar = compileExpr(agg.orderColumn, env);
1206
+ const suffix = agg.desc ? ":desc" : ":asc";
1207
+ parts.push(`${orderVar}${suffix}`);
1208
+ } else if (agg.column !== void 0) {
1209
+ parts.push(compileExpr(agg.column, env));
1210
+ }
1211
+ const inner = parts.join(", ");
1212
+ return `${agg.func}<${inner}>`;
1213
+ }
1214
+ function compileBoolExpr(expr, env) {
1215
+ if (isComparison(expr)) {
1216
+ return [compileComparison(expr, env)];
1217
+ }
1218
+ if (isAnd(expr)) {
1219
+ return [...compileBoolExpr(expr.left, env), ...compileBoolExpr(expr.right, env)];
1220
+ }
1221
+ if (isOr(expr)) {
1222
+ throw new Error(
1223
+ "OR conditions require query splitting. Use compileOrBranches() instead."
1224
+ );
1225
+ }
1226
+ if (isNot(expr)) {
1227
+ const innerParts = compileBoolExpr(expr.operand, env);
1228
+ return [`!(${innerParts.join(", ")})`];
1229
+ }
1230
+ if (isInExpr(expr)) {
1231
+ return [compileIn(expr.column, expr.targetColumn, false, env)];
1232
+ }
1233
+ if (isNegatedIn(expr)) {
1234
+ return [compileIn(expr.column, expr.targetColumn, true, env)];
1235
+ }
1236
+ if (isMatchExpr(expr)) {
1237
+ return [compileMatch(expr, env)];
1238
+ }
1239
+ throw new TypeError(`Cannot compile boolean expression: ${JSON.stringify(expr)}`);
1240
+ }
1241
+ function compileComparison(comp, env) {
1242
+ if (comp.op === "=" && isColumn(comp.left) && isColumn(comp.right)) {
1243
+ env.unify(comp.left, comp.right);
1244
+ return "";
1245
+ }
1246
+ const left = compileExpr(comp.left, env);
1247
+ const right = compileExpr(comp.right, env);
1248
+ return `${left} ${comp.op} ${right}`;
1249
+ }
1250
+ function compileIn(col, target, negated, env) {
1251
+ if (isColumn(col) && isColumn(target)) {
1252
+ env.unify(col, target);
1253
+ const tgtVar = env.getVar(target);
1254
+ const prefix2 = negated ? "!" : "";
1255
+ return `${prefix2}${target.relation}(..., ${tgtVar}, ...)`;
1256
+ }
1257
+ const srcVar = compileExpr(col, env);
1258
+ const prefix = negated ? "!" : "";
1259
+ return `${prefix}(..., ${srcVar}, ...)`;
1260
+ }
1261
+ function compileMatch(match, env) {
1262
+ const parts = [];
1263
+ for (const [, sourceExpr] of Object.entries(match.bindings)) {
1264
+ parts.push(compileExpr(sourceExpr, env));
1265
+ }
1266
+ const prefix = match.negated ? "!" : "";
1267
+ return `${prefix}${match.relation}(${parts.join(", ")})`;
1268
+ }
1269
+ function compileOrBranches(expr, env) {
1270
+ if (isOr(expr)) {
1271
+ return [
1272
+ ...compileOrBranches(expr.left, env),
1273
+ ...compileOrBranches(expr.right, env)
1274
+ ];
1275
+ }
1276
+ return [compileBoolExpr(expr, env)];
1277
+ }
1278
+ function compileSchema(rel) {
1279
+ const name = rel.relationName;
1280
+ const cols = rel.columns;
1281
+ const colTypes = rel.columnTypes;
1282
+ const parts = cols.map((c) => `${c}: ${colTypes[c]}`);
1283
+ return `+${name}(${parts.join(", ")})`;
1284
+ }
1285
+ function compileInsert(rel, fact, persistent = true) {
1286
+ const name = rel.relationName;
1287
+ const values = rel.columns.map((c) => compileValue(fact[c]));
1288
+ const prefix = persistent ? "+" : "";
1289
+ return `${prefix}${name}(${values.join(", ")})`;
1290
+ }
1291
+ function compileBulkInsert(rel, facts, persistent = true) {
1292
+ const name = rel.relationName;
1293
+ const tuples = facts.map((fact) => {
1294
+ const values = rel.columns.map((c) => compileValue(fact[c]));
1295
+ return `(${values.join(", ")})`;
1296
+ });
1297
+ const prefix = persistent ? "+" : "";
1298
+ return `${prefix}${name}[${tuples.join(", ")}]`;
1299
+ }
1300
+ function compileDelete(rel, fact) {
1301
+ const name = rel.relationName;
1302
+ const values = rel.columns.map((c) => compileValue(fact[c]));
1303
+ return `-${name}(${values.join(", ")})`;
1304
+ }
1305
+ function compileConditionalDelete(rel, condition) {
1306
+ const name = rel.relationName;
1307
+ const cols = rel.columns;
1308
+ const vars = cols.map((_, i) => `X${i}`);
1309
+ const head = `-${name}(${vars.join(", ")})`;
1310
+ const env = new VarEnv();
1311
+ for (let i = 0; i < cols.length; i++) {
1312
+ env.set(`${name}.${cols[i]}`, vars[i]);
1313
+ }
1314
+ const bodyRel = `${name}(${vars.join(", ")})`;
1315
+ const condParts = compileBoolExpr(condition, env).filter((p) => p !== "");
1316
+ const allBody = [bodyRel, ...condParts];
1317
+ return `${head} <- ${allBody.join(", ")}`;
1318
+ }
1319
+ function hasOr(expr) {
1320
+ if (isOr(expr)) return true;
1321
+ if (isAnd(expr)) return hasOr(expr.left) || hasOr(expr.right);
1322
+ if (isNot(expr)) return hasOr(expr.operand);
1323
+ return false;
1324
+ }
1325
+ function processJoinCondition(condition, env) {
1326
+ if (isComparison(condition) && condition.op === "=") {
1327
+ if (isColumn(condition.left) && isColumn(condition.right)) {
1328
+ env.unify(condition.left, condition.right);
1329
+ return;
1330
+ }
1331
+ }
1332
+ if (isAnd(condition)) {
1333
+ processJoinCondition(condition.left, env);
1334
+ processJoinCondition(condition.right, env);
1335
+ }
1336
+ }
1337
+ function compileQuery(opts) {
1338
+ const env = new VarEnv();
1339
+ const allRelations = [];
1340
+ if (opts.join) {
1341
+ for (const r of opts.join) {
1342
+ if (r instanceof RelationDef) {
1343
+ allRelations.push({ name: r.relationName, def: r, alias: void 0 });
1344
+ } else {
1345
+ allRelations.push({
1346
+ name: r.relationName,
1347
+ def: {
1348
+ relationName: r.relationName,
1349
+ columns: r.schema.columns.map((c) => c.name),
1350
+ columnTypes: {}
1351
+ },
1352
+ alias: r.alias
1353
+ });
1354
+ }
1355
+ }
1356
+ }
1357
+ if (opts.on) {
1358
+ processJoinCondition(opts.on, env);
1359
+ }
1360
+ let whereParts = [];
1361
+ let orBranches;
1362
+ if (opts.where) {
1363
+ if (hasOr(opts.where)) {
1364
+ orBranches = compileOrBranches(opts.where, env);
1365
+ } else {
1366
+ whereParts = compileBoolExpr(opts.where, env).filter((p) => p !== "");
1367
+ }
1368
+ }
1369
+ const hasAgg = opts.select.some((s) => isAggExpr(s));
1370
+ const computed = opts.computed ?? {};
1371
+ const hasComputedAgg = Object.values(computed).some((v) => isAggExpr(v));
1372
+ if (hasAgg || hasComputedAgg) {
1373
+ return compileAggQuery(
1374
+ opts.select,
1375
+ env,
1376
+ allRelations,
1377
+ whereParts,
1378
+ orBranches,
1379
+ opts.orderBy,
1380
+ opts.limit,
1381
+ opts.offset,
1382
+ computed
1383
+ );
1384
+ }
1385
+ const headParts = [];
1386
+ const bodyAtoms = [];
1387
+ const fullRelations = [];
1388
+ for (const s of opts.select) {
1389
+ if (s instanceof RelationDef) {
1390
+ fullRelations.push({ name: s.relationName, def: s, alias: void 0 });
1391
+ }
1392
+ }
1393
+ if (fullRelations.length > 0) {
1394
+ for (const { name, def, alias } of fullRelations) {
1395
+ for (const col of def.columns) {
1396
+ const astCol = column(name, col, alias);
1397
+ headParts.push(env.getVar(astCol));
1398
+ }
1399
+ if (!allRelations.some((r) => r.name === name && r.alias === alias)) {
1400
+ allRelations.push({ name, def, alias });
1401
+ }
1402
+ }
1403
+ }
1404
+ for (const s of opts.select) {
1405
+ if (!(s instanceof RelationDef) && isColumn(s)) {
1406
+ headParts.push(env.getVar(s));
1407
+ } else if (!(s instanceof RelationDef) && !isColumn(s) && "_tag" in s) {
1408
+ headParts.push(compileExpr(s, env));
1409
+ }
1410
+ }
1411
+ for (const [, expr] of Object.entries(computed)) {
1412
+ headParts.push(compileExpr(expr, env));
1413
+ }
1414
+ if (opts.orderBy !== void 0) {
1415
+ if (isOrderedColumn(opts.orderBy)) {
1416
+ const orderVar = compileExpr(opts.orderBy.column, env);
1417
+ const suffix = opts.orderBy.descending ? ":desc" : ":asc";
1418
+ for (let i = 0; i < headParts.length; i++) {
1419
+ if (headParts[i] === orderVar) {
1420
+ headParts[i] = `${orderVar}${suffix}`;
1421
+ break;
1422
+ }
1423
+ }
1424
+ } else if (isColumn(opts.orderBy)) {
1425
+ const orderVar = env.getVar(opts.orderBy);
1426
+ for (let i = 0; i < headParts.length; i++) {
1427
+ if (headParts[i] === orderVar) {
1428
+ headParts[i] = `${orderVar}:asc`;
1429
+ break;
1430
+ }
1431
+ }
1432
+ }
1433
+ }
1434
+ for (const { name, def, alias } of allRelations) {
1435
+ const cols = def.columns;
1436
+ const atomParts = cols.map((col) => {
1437
+ const astCol = column(name, col, alias);
1438
+ return env.lookup(astCol) ?? "_";
1439
+ });
1440
+ bodyAtoms.push(`${name}(${atomParts.join(", ")})`);
1441
+ }
1442
+ const allBody = [...bodyAtoms, ...whereParts];
1443
+ if (opts.limit !== void 0) {
1444
+ if (opts.offset !== void 0) {
1445
+ allBody.push(`limit(${opts.limit}, ${opts.offset})`);
1446
+ } else {
1447
+ allBody.push(`limit(${opts.limit})`);
1448
+ }
1449
+ }
1450
+ const headStr = headParts.join(", ");
1451
+ if (orBranches !== void 0) {
1452
+ return orBranches.map((branchParts) => {
1453
+ const filtered = branchParts.filter((p) => p !== "");
1454
+ const branchBody = [...bodyAtoms, ...filtered];
1455
+ if (opts.limit !== void 0) {
1456
+ if (opts.offset !== void 0) {
1457
+ branchBody.push(`limit(${opts.limit}, ${opts.offset})`);
1458
+ } else {
1459
+ branchBody.push(`limit(${opts.limit})`);
1460
+ }
1461
+ }
1462
+ return `?${headStr} <- ${branchBody.join(", ")}`;
1463
+ });
1464
+ }
1465
+ if (allBody.length > 0) {
1466
+ return `?${headStr} <- ${allBody.join(", ")}`;
1467
+ }
1468
+ return `?${headStr}`;
1469
+ }
1470
+ function compileAggQuery(select, env, allRelations, whereParts, orBranches, orderBy, limit, offset, computed) {
1471
+ const headParts = [];
1472
+ const aggParts = [];
1473
+ for (const s of select) {
1474
+ if (s instanceof RelationDef) {
1475
+ for (const col of s.columns) {
1476
+ const astCol = column(s.relationName, col);
1477
+ headParts.push(env.getVar(astCol));
1478
+ }
1479
+ } else if (isAggExpr(s)) {
1480
+ aggParts.push(compileExpr(s, env));
1481
+ } else if (isColumn(s)) {
1482
+ headParts.push(env.getVar(s));
1483
+ }
1484
+ }
1485
+ for (const [, expr] of Object.entries(computed)) {
1486
+ if (isAggExpr(expr)) {
1487
+ aggParts.push(compileExpr(expr, env));
1488
+ } else {
1489
+ headParts.push(compileExpr(expr, env));
1490
+ }
1491
+ }
1492
+ const bodyAtoms = [];
1493
+ for (const { name, def, alias } of allRelations) {
1494
+ const cols = def.columns;
1495
+ const atomParts = cols.map((col) => {
1496
+ const astCol = column(name, col, alias);
1497
+ return env.lookup(astCol) ?? "_";
1498
+ });
1499
+ bodyAtoms.push(`${name}(${atomParts.join(", ")})`);
1500
+ }
1501
+ const allBody = [...bodyAtoms, ...whereParts];
1502
+ if (limit !== void 0) {
1503
+ if (offset !== void 0) {
1504
+ allBody.push(`limit(${limit}, ${offset})`);
1505
+ } else {
1506
+ allBody.push(`limit(${limit})`);
1507
+ }
1508
+ }
1509
+ const allHead = [...headParts, ...aggParts];
1510
+ const headStr = allHead.join(", ");
1511
+ if (allBody.length > 0) {
1512
+ return `?${headStr} <- ${allBody.join(", ")}`;
1513
+ }
1514
+ return `?${headStr}`;
1515
+ }
1516
+ function compileRule(headName, headColumns, clause, persistent = true) {
1517
+ const env = new VarEnv();
1518
+ if (clause.condition) {
1519
+ processJoinCondition(clause.condition, env);
1520
+ }
1521
+ const headParts = headColumns.map((col) => {
1522
+ const expr = clause.selectMap[col];
1523
+ if (expr !== void 0) {
1524
+ return compileExpr(expr, env);
1525
+ }
1526
+ return columnToVariable(col);
1527
+ });
1528
+ const bodyAtoms = [];
1529
+ for (const { name, def, alias } of clause.relations) {
1530
+ const cols = def.columns;
1531
+ const atomParts = cols.map((col) => {
1532
+ const astCol = column(name, col, alias);
1533
+ return env.lookup(astCol) ?? "_";
1534
+ });
1535
+ bodyAtoms.push(`${name}(${atomParts.join(", ")})`);
1536
+ }
1537
+ let condParts = [];
1538
+ if (clause.condition) {
1539
+ condParts = compileBoolExpr(clause.condition, env).filter((p) => p !== "");
1540
+ }
1541
+ const allBody = [...bodyAtoms, ...condParts];
1542
+ const prefix = persistent ? "+" : "";
1543
+ const headStr = `${prefix}${headName}(${headParts.join(", ")})`;
1544
+ return `${headStr} <- ${allBody.join(", ")}`;
1545
+ }
1546
+
1547
+ // src/session.ts
1548
+ var Session = class {
1549
+ constructor(connection) {
1550
+ this.conn = connection;
1551
+ }
1552
+ /** Insert ephemeral session facts (no + prefix). */
1553
+ async insert(rel, facts) {
1554
+ const factList = Array.isArray(facts) ? facts : [facts];
1555
+ if (factList.length === 0) return;
1556
+ let iql;
1557
+ if (factList.length === 1) {
1558
+ iql = compileInsert(rel, factList[0], false);
1559
+ } else {
1560
+ iql = compileBulkInsert(rel, factList, false);
1561
+ }
1562
+ await this.conn.execute(iql);
1563
+ }
1564
+ /** Define session-scoped rules (no + prefix). */
1565
+ async defineRules(headName, headColumns, clauses) {
1566
+ for (const clause of clauses) {
1567
+ const iql = compileRule(headName, headColumns, clause, false);
1568
+ await this.conn.execute(iql);
1569
+ }
1570
+ }
1571
+ /** List session rules. */
1572
+ async listRules() {
1573
+ const result = await this.conn.execute(".session list");
1574
+ return result.rows.length > 0 ? result.rows.map((row) => String(row[0])) : [];
1575
+ }
1576
+ /** Drop a session rule by name, or a specific clause by index. */
1577
+ async dropRule(name, index) {
1578
+ if (index !== void 0) {
1579
+ await this.conn.execute(`.session remove ${name} ${index}`);
1580
+ } else {
1581
+ await this.conn.execute(`.session drop ${name}`);
1582
+ }
1583
+ }
1584
+ /** Clear all session facts and rules. */
1585
+ async clear() {
1586
+ await this.conn.execute(".session clear");
1587
+ }
1588
+ };
1589
+
1590
+ // src/knowledge-graph.ts
1591
+ var KnowledgeGraph = class {
1592
+ constructor(name, connection) {
1593
+ this._name = name;
1594
+ this.conn = connection;
1595
+ this._session = new Session(connection);
1596
+ }
1597
+ get name() {
1598
+ return this._name;
1599
+ }
1600
+ get session() {
1601
+ return this._session;
1602
+ }
1603
+ // ── Schema ──────────────────────────────────────────────────────
1604
+ /** Deploy schema definitions. Idempotent. */
1605
+ async define(...relations) {
1606
+ for (const rel of relations) {
1607
+ const iql = compileSchema(rel);
1608
+ await this.conn.execute(iql);
1609
+ }
1610
+ }
1611
+ /** List all relations in this KG. */
1612
+ async relations() {
1613
+ const result = await this.conn.execute(".rel");
1614
+ return result.rows.map((row) => ({
1615
+ name: String(row[0]),
1616
+ rowCount: row.length > 1 ? Number(row[1]) : 0
1617
+ }));
1618
+ }
1619
+ /** Describe a relation's schema. */
1620
+ async describe(relation2) {
1621
+ const name = typeof relation2 === "string" ? relation2 : relation2.relationName;
1622
+ const result = await this.conn.execute(`.rel ${name}`);
1623
+ const columns = result.rows.map((row) => ({
1624
+ name: String(row[0]),
1625
+ type: String(row[1])
1626
+ }));
1627
+ return { name, columns, rowCount: 0, sample: [] };
1628
+ }
1629
+ /** Drop a relation and all its data. */
1630
+ async dropRelation(relation2) {
1631
+ const name = typeof relation2 === "string" ? relation2 : relation2.relationName;
1632
+ await this.conn.execute(`.rel drop ${name}`);
1633
+ }
1634
+ // ── Insert ──────────────────────────────────────────────────────
1635
+ /** Insert facts into the knowledge graph. */
1636
+ async insert(rel, facts) {
1637
+ const factList = Array.isArray(facts) ? facts : [facts];
1638
+ if (factList.length === 0) return { count: 0 };
1639
+ let iql;
1640
+ if (factList.length === 1) {
1641
+ iql = compileInsert(rel, factList[0]);
1642
+ } else {
1643
+ iql = compileBulkInsert(rel, factList);
1644
+ }
1645
+ const result = await this.conn.execute(iql);
1646
+ return { count: result.rows.length };
1647
+ }
1648
+ // ── Delete ──────────────────────────────────────────────────────
1649
+ /**
1650
+ * Delete facts from the knowledge graph.
1651
+ *
1652
+ * @param rel - The relation definition
1653
+ * @param factsOrCondition - Either specific facts to delete, or a BoolExpr condition
1654
+ */
1655
+ async delete(rel, factsOrCondition) {
1656
+ if (typeof factsOrCondition === "object" && factsOrCondition !== null && "_tag" in factsOrCondition) {
1657
+ const iql = compileConditionalDelete(rel, factsOrCondition);
1658
+ const result = await this.conn.execute(iql);
1659
+ return { count: result.rows.length };
1660
+ }
1661
+ const facts = Array.isArray(factsOrCondition) ? factsOrCondition : [factsOrCondition];
1662
+ for (const fact of facts) {
1663
+ const iql = compileDelete(rel, fact);
1664
+ await this.conn.execute(iql);
1665
+ }
1666
+ return { count: facts.length };
1667
+ }
1668
+ // ── Query ───────────────────────────────────────────────────────
1669
+ /**
1670
+ * Query the knowledge graph.
1671
+ *
1672
+ * @example
1673
+ * // Simple query
1674
+ * const result = await kg.query({ select: [Employee] });
1675
+ *
1676
+ * // Filter
1677
+ * const result = await kg.query({
1678
+ * select: [Employee.col("name"), Employee.col("salary")],
1679
+ * join: [Employee],
1680
+ * where: Employee.col("department").eq("eng"),
1681
+ * });
1682
+ *
1683
+ * // Join
1684
+ * const result = await kg.query({
1685
+ * select: [Employee.col("name"), Department.col("budget")],
1686
+ * join: [Employee, Department],
1687
+ * on: Employee.col("department").eq(Department.col("name")),
1688
+ * });
1689
+ */
1690
+ async query(opts) {
1691
+ const iql = compileQuery(opts);
1692
+ if (Array.isArray(iql)) {
1693
+ const allRows = [];
1694
+ let columns = [];
1695
+ for (const q of iql) {
1696
+ const result2 = await this.conn.execute(q);
1697
+ if (columns.length === 0) {
1698
+ columns = result2.columns;
1699
+ }
1700
+ allRows.push(...result2.rows);
1701
+ }
1702
+ return new ResultSet({ columns, rows: allRows });
1703
+ }
1704
+ const result = await this.conn.execute(iql);
1705
+ const rs = new ResultSet({
1706
+ columns: result.columns,
1707
+ rows: result.rows,
1708
+ rowCount: result.row_count,
1709
+ totalCount: result.total_count,
1710
+ truncated: result.truncated,
1711
+ executionTimeMs: result.execution_time_ms,
1712
+ rowProvenance: result.row_provenance
1713
+ });
1714
+ if (result.metadata) {
1715
+ rs.hasEphemeral = result.metadata.has_ephemeral ?? false;
1716
+ rs.ephemeralSources = result.metadata.ephemeral_sources ?? [];
1717
+ rs.warnings = result.metadata.warnings ?? [];
1718
+ }
1719
+ return rs;
1720
+ }
1721
+ /**
1722
+ * Stream query results in batches.
1723
+ *
1724
+ * Returns an async generator yielding arrays of rows.
1725
+ */
1726
+ async *queryStream(opts) {
1727
+ const batchSize = opts.batchSize ?? 1e3;
1728
+ const result = await this.query(opts);
1729
+ for (let i = 0; i < result.rows.length; i += batchSize) {
1730
+ const batch = result.rows.slice(i, i + batchSize);
1731
+ yield batch.map((row) => {
1732
+ const obj = {};
1733
+ for (let j = 0; j < result.columns.length && j < row.length; j++) {
1734
+ obj[result.columns[j]] = row[j];
1735
+ }
1736
+ return obj;
1737
+ });
1738
+ }
1739
+ }
1740
+ // ── Vector search ───────────────────────────────────────────────
1741
+ /**
1742
+ * Perform a vector similarity search.
1743
+ */
1744
+ async vectorSearch(opts) {
1745
+ const rel = opts.relation;
1746
+ const relName = rel.relationName;
1747
+ const cols = rel.columns;
1748
+ let vecColumn = opts.column;
1749
+ if (!vecColumn) {
1750
+ for (const [name, type] of Object.entries(rel.columnTypes)) {
1751
+ if (type === "vector" || type.startsWith("vector[")) {
1752
+ vecColumn = name;
1753
+ break;
1754
+ }
1755
+ }
1756
+ if (!vecColumn) {
1757
+ throw new Error(`No vector column found in ${relName}`);
1758
+ }
1759
+ }
1760
+ const vecStr = `[${opts.queryVec.join(", ")}]`;
1761
+ const distFn = {
1762
+ cosine: "cosine",
1763
+ euclidean: "euclidean",
1764
+ manhattan: "manhattan",
1765
+ dot_product: "dot"
1766
+ };
1767
+ const fnName = distFn[opts.metric ?? "cosine"] ?? "cosine";
1768
+ const colVars = cols.map((_, i) => `X${i}`).join(", ");
1769
+ const vecVar = `X${cols.indexOf(vecColumn)}`;
1770
+ const distAssign = `Dist = ${fnName}(${vecVar}, ${vecStr})`;
1771
+ let query;
1772
+ if (opts.k !== void 0) {
1773
+ query = `?top_k<${opts.k}, ${colVars}, Dist:asc> <- ${relName}(${colVars}), ${distAssign}`;
1774
+ } else if (opts.radius !== void 0) {
1775
+ query = `?within_radius<${opts.radius}, ${colVars}, Dist:asc> <- ${relName}(${colVars}), ${distAssign}`;
1776
+ } else {
1777
+ throw new Error("Must specify either k or radius");
1778
+ }
1779
+ const result = await this.conn.execute(query);
1780
+ return new ResultSet({
1781
+ columns: result.columns,
1782
+ rows: result.rows,
1783
+ rowCount: result.row_count,
1784
+ totalCount: result.total_count,
1785
+ truncated: result.truncated,
1786
+ executionTimeMs: result.execution_time_ms
1787
+ });
1788
+ }
1789
+ // ── Rules ───────────────────────────────────────────────────────
1790
+ /** Deploy persistent rule definitions. */
1791
+ async defineRules(headName, headColumns, clauses) {
1792
+ for (const clause of clauses) {
1793
+ const iql = compileRule(headName, headColumns, clause, true);
1794
+ await this.conn.execute(iql);
1795
+ }
1796
+ }
1797
+ /** List all rules in this KG. */
1798
+ async listRules() {
1799
+ const result = await this.conn.execute(".rule list");
1800
+ return result.rows.map((row) => ({
1801
+ name: String(row[0]),
1802
+ clauseCount: row.length > 1 ? Number(row[1]) : 1
1803
+ }));
1804
+ }
1805
+ /** Get the IQL definition of a rule. */
1806
+ async ruleDefinition(name) {
1807
+ const result = await this.conn.execute(`.rule show ${name}`);
1808
+ return result.rows.map((row) => String(row[0]));
1809
+ }
1810
+ /** Drop all clauses of a rule. */
1811
+ async dropRule(name) {
1812
+ await this.conn.execute(`.rule drop ${name}`);
1813
+ }
1814
+ /** Remove a specific clause from a rule (1-based index). */
1815
+ async dropRuleClause(name, index) {
1816
+ await this.conn.execute(`.rule remove ${name} ${index}`);
1817
+ }
1818
+ /** Replace a specific rule clause (remove + re-add). */
1819
+ async editRuleClause(name, index, headColumns, clause) {
1820
+ await this.dropRuleClause(name, index);
1821
+ const iql = compileRule(name, headColumns, clause, true);
1822
+ await this.conn.execute(iql);
1823
+ }
1824
+ /** Clear a rule's materialized data. */
1825
+ async clearRule(name) {
1826
+ await this.conn.execute(`.rule clear ${name}`);
1827
+ }
1828
+ /** Drop all rules whose names start with prefix. */
1829
+ async dropRulesByPrefix(prefix) {
1830
+ await this.conn.execute(`.rule drop prefix ${prefix}`);
1831
+ }
1832
+ // ── Indexes ─────────────────────────────────────────────────────
1833
+ /** Create an HNSW vector index. */
1834
+ async createIndex(index) {
1835
+ await this.conn.execute(index.toIQL());
1836
+ }
1837
+ /** List all indexes. */
1838
+ async listIndexes() {
1839
+ const result = await this.conn.execute(".index list");
1840
+ return result.rows.map((row) => ({
1841
+ name: String(row[0]),
1842
+ relation: row.length > 1 ? String(row[1]) : "",
1843
+ column: row.length > 2 ? String(row[2]) : "",
1844
+ metric: row.length > 3 ? String(row[3]) : "",
1845
+ rowCount: row.length > 4 ? Number(row[4]) : 0
1846
+ }));
1847
+ }
1848
+ /** Get statistics for an index. */
1849
+ async indexStats(name) {
1850
+ const result = await this.conn.execute(`.index stats ${name}`);
1851
+ const row = result.rows[0] ?? [name, 0, 0, 0];
1852
+ return {
1853
+ name: String(row[0]),
1854
+ rowCount: row.length > 1 ? Number(row[1]) : 0,
1855
+ layers: row.length > 2 ? Number(row[2]) : 0,
1856
+ memoryBytes: row.length > 3 ? Number(row[3]) : 0
1857
+ };
1858
+ }
1859
+ /** Drop an index. */
1860
+ async dropIndex(name) {
1861
+ await this.conn.execute(`.index drop ${name}`);
1862
+ }
1863
+ /** Rebuild an index. */
1864
+ async rebuildIndex(name) {
1865
+ await this.conn.execute(`.index rebuild ${name}`);
1866
+ }
1867
+ // ── ACL ─────────────────────────────────────────────────────────
1868
+ /** Grant per-KG access. */
1869
+ async grantAccess(username, role) {
1870
+ await this.conn.execute(`.kg acl grant ${this._name} ${username} ${role}`);
1871
+ }
1872
+ /** Revoke per-KG access. */
1873
+ async revokeAccess(username) {
1874
+ await this.conn.execute(`.kg acl revoke ${this._name} ${username}`);
1875
+ }
1876
+ /** List ACL entries. */
1877
+ async listAcl() {
1878
+ const result = await this.conn.execute(`.kg acl list ${this._name}`);
1879
+ return result.rows.filter((row) => row.length >= 2).map((row) => ({
1880
+ username: String(row[0]),
1881
+ role: String(row[1])
1882
+ }));
1883
+ }
1884
+ // ── Meta ────────────────────────────────────────────────────────
1885
+ /** Show the query plan without executing. */
1886
+ async explain(opts) {
1887
+ let iql = compileQuery(opts);
1888
+ if (Array.isArray(iql)) {
1889
+ iql = iql[0];
1890
+ }
1891
+ const result = await this.conn.execute(`.explain ${iql}`);
1892
+ const planText = result.rows.map((row) => String(row[0])).join("\n");
1893
+ return { iql, plan: planText };
1894
+ }
1895
+ /** Trigger storage compaction. */
1896
+ async compact() {
1897
+ await this.conn.execute(".compact");
1898
+ }
1899
+ /** Get server status. */
1900
+ async status() {
1901
+ const result = await this.conn.execute(".status");
1902
+ const row = result.rows[0] ?? ["unknown", "unknown"];
1903
+ return {
1904
+ version: row.length > 0 ? String(row[0]) : "unknown",
1905
+ knowledgeGraph: row.length > 1 ? String(row[1]) : this._name
1906
+ };
1907
+ }
1908
+ /** Load data from a file on the server. */
1909
+ async load(path, mode) {
1910
+ let cmd = `.load ${path}`;
1911
+ if (mode) cmd += ` ${mode}`;
1912
+ await this.conn.execute(cmd);
1913
+ }
1914
+ /** Clear all relations matching a prefix. */
1915
+ async clearPrefix(prefix) {
1916
+ const result = await this.conn.execute(`.clear prefix ${prefix}`);
1917
+ const details = result.rows.filter((row) => row.length > 1).map((row) => [String(row[0]), Number(row[1])]);
1918
+ return {
1919
+ relationsCleared: result.rows.length,
1920
+ factsCleared: details.reduce((sum2, [, count2]) => sum2 + count2, 0),
1921
+ details
1922
+ };
1923
+ }
1924
+ /** Execute raw IQL. */
1925
+ async execute(iql) {
1926
+ const result = await this.conn.execute(iql);
1927
+ return new ResultSet({
1928
+ columns: result.columns,
1929
+ rows: result.rows,
1930
+ rowCount: result.row_count,
1931
+ totalCount: result.total_count,
1932
+ truncated: result.truncated,
1933
+ executionTimeMs: result.execution_time_ms
1934
+ });
1935
+ }
1936
+ };
1937
+
1938
+ // src/auth.ts
1939
+ function compileCreateUser(username, password, role = "viewer") {
1940
+ return `.user create ${username} ${password} ${role}`;
1941
+ }
1942
+ function compileDropUser(username) {
1943
+ return `.user drop ${username}`;
1944
+ }
1945
+ function compileSetPassword(username, newPassword) {
1946
+ return `.user password ${username} ${newPassword}`;
1947
+ }
1948
+ function compileSetRole(username, role) {
1949
+ return `.user role ${username} ${role}`;
1950
+ }
1951
+ function compileListUsers() {
1952
+ return ".user list";
1953
+ }
1954
+ function compileCreateApiKey(label) {
1955
+ return `.apikey create ${label}`;
1956
+ }
1957
+ function compileListApiKeys() {
1958
+ return ".apikey list";
1959
+ }
1960
+ function compileRevokeApiKey(label) {
1961
+ return `.apikey revoke ${label}`;
1962
+ }
1963
+
1964
+ // src/client.ts
1965
+ var InputLayer = class {
1966
+ constructor(opts) {
1967
+ this.kgs = /* @__PURE__ */ new Map();
1968
+ this.conn = new Connection({
1969
+ url: opts.url,
1970
+ username: opts.username,
1971
+ password: opts.password,
1972
+ apiKey: opts.apiKey,
1973
+ autoReconnect: opts.autoReconnect,
1974
+ reconnectDelay: opts.reconnectDelay,
1975
+ maxReconnectAttempts: opts.maxReconnectAttempts,
1976
+ initialKg: opts.initialKg,
1977
+ lastSeq: opts.lastSeq
1978
+ });
1979
+ }
1980
+ // ── Connection lifecycle ────────────────────────────────────────
1981
+ /** Connect and authenticate. */
1982
+ async connect() {
1983
+ await this.conn.connect();
1984
+ }
1985
+ /** Close the connection. */
1986
+ async close() {
1987
+ await this.conn.close();
1988
+ }
1989
+ // ── Properties ──────────────────────────────────────────────────
1990
+ get connected() {
1991
+ return this.conn.connected;
1992
+ }
1993
+ get sessionId() {
1994
+ return this.conn.sessionId;
1995
+ }
1996
+ get serverVersion() {
1997
+ return this.conn.serverVersion;
1998
+ }
1999
+ get role() {
2000
+ return this.conn.role;
2001
+ }
2002
+ get lastSeq() {
2003
+ return this.conn.lastSeq;
2004
+ }
2005
+ // ── KG management ───────────────────────────────────────────────
2006
+ /** Get a KnowledgeGraph handle. Switches the session's active KG. */
2007
+ knowledgeGraph(name) {
2008
+ let kg = this.kgs.get(name);
2009
+ if (!kg) {
2010
+ kg = new KnowledgeGraph(name, this.conn);
2011
+ this.kgs.set(name, kg);
2012
+ }
2013
+ return kg;
2014
+ }
2015
+ /** List all knowledge graphs. */
2016
+ async listKnowledgeGraphs() {
2017
+ const result = await this.conn.execute(".kg list");
2018
+ return result.rows.length > 0 ? result.rows.map((row) => String(row[0])) : [];
2019
+ }
2020
+ /** Drop a knowledge graph. */
2021
+ async dropKnowledgeGraph(name) {
2022
+ await this.conn.execute(`.kg drop ${name}`);
2023
+ this.kgs.delete(name);
2024
+ }
2025
+ // ── User management ─────────────────────────────────────────────
2026
+ async createUser(username, password, role = "viewer") {
2027
+ await this.conn.execute(compileCreateUser(username, password, role));
2028
+ }
2029
+ async dropUser(username) {
2030
+ await this.conn.execute(compileDropUser(username));
2031
+ }
2032
+ async setPassword(username, newPassword) {
2033
+ await this.conn.execute(compileSetPassword(username, newPassword));
2034
+ }
2035
+ async setRole(username, role) {
2036
+ await this.conn.execute(compileSetRole(username, role));
2037
+ }
2038
+ async listUsers() {
2039
+ const result = await this.conn.execute(compileListUsers());
2040
+ return result.rows.filter((row) => row.length >= 2).map((row) => ({
2041
+ username: String(row[0]),
2042
+ role: String(row[1])
2043
+ }));
2044
+ }
2045
+ // ── API key management ──────────────────────────────────────────
2046
+ /** Create an API key. Returns the key string. */
2047
+ async createApiKey(label) {
2048
+ const result = await this.conn.execute(compileCreateApiKey(label));
2049
+ if (result.rows.length > 0 && result.rows[0].length > 0) {
2050
+ return String(result.rows[0][0]);
2051
+ }
2052
+ return "";
2053
+ }
2054
+ async listApiKeys() {
2055
+ const result = await this.conn.execute(compileListApiKeys());
2056
+ return result.rows.map((row) => ({
2057
+ label: String(row[0]),
2058
+ createdAt: row.length > 1 ? String(row[1]) : ""
2059
+ }));
2060
+ }
2061
+ async revokeApiKey(label) {
2062
+ await this.conn.execute(compileRevokeApiKey(label));
2063
+ }
2064
+ // ── Notifications ───────────────────────────────────────────────
2065
+ /**
2066
+ * Register a notification callback.
2067
+ *
2068
+ * @param eventType - Filter by event type (e.g. "persistent_update")
2069
+ * @param callback - Function to call when event arrives
2070
+ * @param opts - Additional filters
2071
+ */
2072
+ on(eventType, callback, opts) {
2073
+ this.conn.dispatcher.on(eventType, opts ?? {}, callback);
2074
+ }
2075
+ /** Remove a notification callback. */
2076
+ off(callback) {
2077
+ this.conn.dispatcher.off(callback);
2078
+ }
2079
+ /** Async iterator yielding notification events. */
2080
+ async *notifications() {
2081
+ yield* this.conn.dispatcher.events();
2082
+ }
2083
+ };
2084
+ // Annotate the CommonJS export names for ESM import in node:
2085
+ 0 && (module.exports = {
2086
+ AND,
2087
+ AuthenticationError,
2088
+ CannotDropError,
2089
+ ColumnProxy,
2090
+ Connection,
2091
+ ConnectionError,
2092
+ HnswIndex,
2093
+ IndexNotFoundError,
2094
+ InputLayer,
2095
+ InputLayerError,
2096
+ InternalError,
2097
+ KnowledgeGraph,
2098
+ KnowledgeGraphExistsError,
2099
+ KnowledgeGraphNotFoundError,
2100
+ NOT,
2101
+ NotificationDispatcher,
2102
+ OR,
2103
+ PermissionError,
2104
+ QueryTimeoutError,
2105
+ RelationDef,
2106
+ RelationNotFoundError,
2107
+ RelationProxy,
2108
+ RelationRef,
2109
+ ResultSet,
2110
+ RuleNotFoundError,
2111
+ SchemaConflictError,
2112
+ Session,
2113
+ Timestamp,
2114
+ ValidationError,
2115
+ avg,
2116
+ camelToSnake,
2117
+ columnToVariable,
2118
+ compileBoolExpr,
2119
+ compileBulkInsert,
2120
+ compileConditionalDelete,
2121
+ compileDelete,
2122
+ compileExpr,
2123
+ compileInsert,
2124
+ compileQuery,
2125
+ compileRule,
2126
+ compileSchema,
2127
+ compileValue,
2128
+ count,
2129
+ countDistinct,
2130
+ deserializeMessage,
2131
+ from,
2132
+ getColumnTypes,
2133
+ getColumns,
2134
+ max,
2135
+ min,
2136
+ relation,
2137
+ resolveRelationName,
2138
+ serializeMessage,
2139
+ snakeToCamel,
2140
+ sum,
2141
+ topK,
2142
+ topKThreshold,
2143
+ withinRadius,
2144
+ wrap
2145
+ });