@utaba/deep-memory 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.
@@ -0,0 +1,332 @@
1
+ // src/providers-builtin/conformance.ts
2
+ import { describe, it, expect, beforeEach } from "vitest";
3
+ function makeProvenance() {
4
+ const now = (/* @__PURE__ */ new Date()).toISOString();
5
+ return {
6
+ createdBy: "conformance-test",
7
+ createdByType: "agent",
8
+ createdAt: now,
9
+ modifiedBy: "conformance-test",
10
+ modifiedByType: "agent",
11
+ modifiedAt: now
12
+ };
13
+ }
14
+ function makeEntity(id, type = "test-type", label) {
15
+ return {
16
+ id,
17
+ slug: `${type}:${(label ?? id).toLowerCase().replace(/[^a-z0-9]+/g, "-")}`,
18
+ entityType: type,
19
+ label: label ?? id,
20
+ summary: `Summary for ${id}`,
21
+ properties: { key: "value" },
22
+ provenance: makeProvenance()
23
+ };
24
+ }
25
+ function makeRelationship(id, type, sourceId, targetId, bidirectional = false) {
26
+ return {
27
+ id,
28
+ relationshipType: type,
29
+ sourceEntityId: sourceId,
30
+ targetEntityId: targetId,
31
+ properties: {},
32
+ bidirectional,
33
+ provenance: makeProvenance()
34
+ };
35
+ }
36
+ function runStorageProviderConformanceTests(factory) {
37
+ const repoId = "40000000-0000-4000-a000-000000000001";
38
+ let provider;
39
+ async function setup() {
40
+ provider = await factory();
41
+ if (provider.initialise) await provider.initialise();
42
+ await provider.createRepository({
43
+ repositoryId: repoId,
44
+ label: "Conformance Test",
45
+ governanceConfig: { mode: "open" },
46
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
47
+ createdBy: "conformance-test"
48
+ });
49
+ }
50
+ describe("StorageProvider Conformance Tests", () => {
51
+ beforeEach(async () => {
52
+ await setup();
53
+ });
54
+ describe("repository operations", () => {
55
+ it("creates a repository", async () => {
56
+ const repo = await provider.getRepository(repoId);
57
+ expect(repo).not.toBeNull();
58
+ expect(repo.repositoryId).toBe(repoId);
59
+ expect(repo.label).toBe("Conformance Test");
60
+ });
61
+ it("returns null for non-existent repository", async () => {
62
+ const repo = await provider.getRepository("ffffffff-ffff-4fff-afff-ffffffffffff");
63
+ expect(repo).toBeNull();
64
+ });
65
+ it("lists repositories", async () => {
66
+ const list = await provider.listRepositories();
67
+ expect(list.items.length).toBeGreaterThanOrEqual(1);
68
+ expect(list.items.some((r) => r.repositoryId === repoId)).toBe(true);
69
+ });
70
+ it("updates a repository", async () => {
71
+ const updated = await provider.updateRepository(repoId, {
72
+ label: "Updated Label",
73
+ description: "Updated description",
74
+ governanceConfig: { mode: "open", defaultSimilarityThreshold: 0.4 }
75
+ });
76
+ expect(updated.label).toBe("Updated Label");
77
+ expect(updated.description).toBe("Updated description");
78
+ expect(updated.governanceConfig.defaultSimilarityThreshold).toBe(0.4);
79
+ const fetched = await provider.getRepository(repoId);
80
+ expect(fetched.label).toBe("Updated Label");
81
+ expect(fetched.governanceConfig.defaultSimilarityThreshold).toBe(0.4);
82
+ });
83
+ it("deletes a repository", async () => {
84
+ await provider.deleteRepository(repoId);
85
+ expect(await provider.getRepository(repoId)).toBeNull();
86
+ });
87
+ it("returns repository stats", async () => {
88
+ const stats = await provider.getRepositoryStats(repoId);
89
+ expect(stats.entityCount).toBe(0);
90
+ expect(stats.relationshipCount).toBe(0);
91
+ expect(typeof stats.vocabularyVersion).toBe("string");
92
+ });
93
+ });
94
+ describe("vocabulary operations", () => {
95
+ it("gets and saves vocabulary", async () => {
96
+ const vocab = await provider.getVocabulary(repoId);
97
+ expect(vocab).toBeDefined();
98
+ expect(typeof vocab.version).toBe("string");
99
+ const updated = { ...vocab, version: "1.0.0" };
100
+ await provider.saveVocabulary(repoId, updated);
101
+ const fetched = await provider.getVocabulary(repoId);
102
+ expect(fetched.version).toBe("1.0.0");
103
+ });
104
+ it("returns vocabulary change log", async () => {
105
+ const log = await provider.getVocabularyChangeLog(repoId);
106
+ expect(Array.isArray(log.items)).toBe(true);
107
+ });
108
+ });
109
+ describe("entity operations", () => {
110
+ it("creates and retrieves an entity", async () => {
111
+ const entity = makeEntity("e1");
112
+ await provider.createEntity(repoId, entity);
113
+ const retrieved = await provider.getEntity(repoId, "e1");
114
+ expect(retrieved).not.toBeNull();
115
+ expect(retrieved.id).toBe("e1");
116
+ expect(retrieved.label).toBe("e1");
117
+ });
118
+ it("retrieves an entity by slug", async () => {
119
+ const entity = makeEntity("e1", "test-type", "Alpha");
120
+ await provider.createEntity(repoId, entity);
121
+ const retrieved = await provider.getEntityBySlug(repoId, entity.slug);
122
+ expect(retrieved).not.toBeNull();
123
+ expect(retrieved.id).toBe("e1");
124
+ expect(retrieved.slug).toBe(entity.slug);
125
+ });
126
+ it("returns null for non-existent entity", async () => {
127
+ const result = await provider.getEntity(repoId, "nonexistent");
128
+ expect(result).toBeNull();
129
+ });
130
+ it("returns null for non-existent slug", async () => {
131
+ const result = await provider.getEntityBySlug(repoId, "nonexistent:slug");
132
+ expect(result).toBeNull();
133
+ });
134
+ it("batch retrieves entities", async () => {
135
+ await provider.createEntity(repoId, makeEntity("e1"));
136
+ await provider.createEntity(repoId, makeEntity("e2"));
137
+ const map = await provider.getEntities(repoId, ["e1", "e2", "missing"]);
138
+ expect(map.size).toBe(2);
139
+ expect(map.has("e1")).toBe(true);
140
+ expect(map.has("e2")).toBe(true);
141
+ expect(map.has("missing")).toBe(false);
142
+ });
143
+ it("updates an entity", async () => {
144
+ await provider.createEntity(repoId, makeEntity("e1"));
145
+ const updated = await provider.updateEntity(repoId, "e1", {
146
+ label: "Updated Label",
147
+ provenance: makeProvenance()
148
+ });
149
+ expect(updated.label).toBe("Updated Label");
150
+ const fetched = await provider.getEntity(repoId, "e1");
151
+ expect(fetched.label).toBe("Updated Label");
152
+ });
153
+ it("deletes an entity", async () => {
154
+ await provider.createEntity(repoId, makeEntity("e1"));
155
+ await provider.deleteEntity(repoId, "e1");
156
+ expect(await provider.getEntity(repoId, "e1")).toBeNull();
157
+ });
158
+ it("finds entities by search term", async () => {
159
+ await provider.createEntity(repoId, makeEntity("e1", "test-type", "Alpha"));
160
+ await provider.createEntity(repoId, makeEntity("e2", "test-type", "Beta"));
161
+ const result = await provider.findEntities(repoId, {
162
+ searchTerm: "alpha",
163
+ limit: 10,
164
+ offset: 0
165
+ });
166
+ expect(result.items).toHaveLength(1);
167
+ expect(result.items[0].label).toBe("Alpha");
168
+ });
169
+ it("finds entities by type filter", async () => {
170
+ await provider.createEntity(repoId, makeEntity("e1", "type-a", "A"));
171
+ await provider.createEntity(repoId, makeEntity("e2", "type-b", "B"));
172
+ const result = await provider.findEntities(repoId, {
173
+ entityTypes: ["type-a"],
174
+ limit: 10,
175
+ offset: 0
176
+ });
177
+ expect(result.items).toHaveLength(1);
178
+ expect(result.items[0].entityType).toBe("type-a");
179
+ });
180
+ it("paginates find results", async () => {
181
+ await provider.createEntity(repoId, makeEntity("e1"));
182
+ await provider.createEntity(repoId, makeEntity("e2"));
183
+ await provider.createEntity(repoId, makeEntity("e3"));
184
+ const page1 = await provider.findEntities(repoId, { limit: 2, offset: 0 });
185
+ expect(page1.items).toHaveLength(2);
186
+ expect(page1.hasMore).toBe(true);
187
+ const page2 = await provider.findEntities(repoId, { limit: 2, offset: 2 });
188
+ expect(page2.items).toHaveLength(1);
189
+ expect(page2.hasMore).toBe(false);
190
+ });
191
+ });
192
+ describe("relationship operations", () => {
193
+ beforeEach(async () => {
194
+ await provider.createEntity(repoId, makeEntity("a"));
195
+ await provider.createEntity(repoId, makeEntity("b"));
196
+ await provider.createEntity(repoId, makeEntity("c"));
197
+ });
198
+ it("creates and retrieves a relationship", async () => {
199
+ const rel = makeRelationship("r1", "connects", "a", "b");
200
+ await provider.createRelationship(repoId, rel);
201
+ const retrieved = await provider.getRelationship(repoId, "r1");
202
+ expect(retrieved).not.toBeNull();
203
+ expect(retrieved.sourceEntityId).toBe("a");
204
+ expect(retrieved.targetEntityId).toBe("b");
205
+ });
206
+ it("returns null for non-existent relationship", async () => {
207
+ expect(await provider.getRelationship(repoId, "nonexistent")).toBeNull();
208
+ });
209
+ it("gets entity relationships", async () => {
210
+ await provider.createRelationship(repoId, makeRelationship("r1", "connects", "a", "b"));
211
+ await provider.createRelationship(repoId, makeRelationship("r2", "connects", "c", "a"));
212
+ const result = await provider.getEntityRelationships(repoId, "a");
213
+ expect(result.items).toHaveLength(2);
214
+ });
215
+ it("filters relationships by direction", async () => {
216
+ await provider.createRelationship(repoId, makeRelationship("r1", "connects", "a", "b"));
217
+ await provider.createRelationship(repoId, makeRelationship("r2", "connects", "c", "a"));
218
+ const outbound = await provider.getEntityRelationships(repoId, "a", { direction: "outbound" });
219
+ expect(outbound.items).toHaveLength(1);
220
+ expect(outbound.items[0].targetEntityId).toBe("b");
221
+ const inbound = await provider.getEntityRelationships(repoId, "a", { direction: "inbound" });
222
+ expect(inbound.items).toHaveLength(1);
223
+ expect(inbound.items[0].sourceEntityId).toBe("c");
224
+ });
225
+ it("deletes a relationship", async () => {
226
+ await provider.createRelationship(repoId, makeRelationship("r1", "connects", "a", "b"));
227
+ await provider.deleteRelationship(repoId, "r1");
228
+ expect(await provider.getRelationship(repoId, "r1")).toBeNull();
229
+ });
230
+ });
231
+ describe("graph traversal", () => {
232
+ beforeEach(async () => {
233
+ await provider.createEntity(repoId, makeEntity("a", "node", "A"));
234
+ await provider.createEntity(repoId, makeEntity("b", "node", "B"));
235
+ await provider.createEntity(repoId, makeEntity("c", "node", "C"));
236
+ await provider.createRelationship(repoId, makeRelationship("r1", "links", "a", "b"));
237
+ await provider.createRelationship(repoId, makeRelationship("r2", "links", "b", "c"));
238
+ });
239
+ it("explores neighbourhood at depth 1", async () => {
240
+ const result = await provider.exploreNeighbourhood(repoId, "a", {
241
+ depth: 1,
242
+ direction: "both",
243
+ limitPerType: 10,
244
+ offsetPerType: 0
245
+ });
246
+ expect(result.centreId).toBe("a");
247
+ expect(result.layers).toHaveLength(1);
248
+ });
249
+ it("finds paths between connected entities", async () => {
250
+ const result = await provider.findPaths(repoId, "a", "c", {
251
+ maxDepth: 3,
252
+ limit: 5,
253
+ offset: 0
254
+ });
255
+ expect(result.paths.length).toBeGreaterThanOrEqual(1);
256
+ const firstPath = result.paths[0];
257
+ expect(firstPath.entityIds[0]).toBe("a");
258
+ expect(firstPath.entityIds[firstPath.entityIds.length - 1]).toBe("c");
259
+ });
260
+ it("returns empty paths when no connection", async () => {
261
+ await provider.createEntity(repoId, makeEntity("isolated", "node", "Isolated"));
262
+ const result = await provider.findPaths(repoId, "a", "isolated", {
263
+ maxDepth: 3,
264
+ limit: 5,
265
+ offset: 0
266
+ });
267
+ expect(result.paths).toHaveLength(0);
268
+ });
269
+ it("finds paths through non-bidirectional inbound edges", async () => {
270
+ await provider.createEntity(repoId, makeEntity("d", "node", "D"));
271
+ await provider.createRelationship(repoId, makeRelationship("r3", "links", "d", "b"));
272
+ const result = await provider.findPaths(repoId, "a", "d", {
273
+ maxDepth: 3,
274
+ limit: 5,
275
+ offset: 0
276
+ });
277
+ expect(result.paths.length).toBeGreaterThanOrEqual(1);
278
+ const firstPath = result.paths[0];
279
+ expect(firstPath.entityIds[0]).toBe("a");
280
+ expect(firstPath.entityIds[firstPath.entityIds.length - 1]).toBe("d");
281
+ });
282
+ });
283
+ describe("timeline", () => {
284
+ it("returns timeline events", async () => {
285
+ await provider.createEntity(repoId, makeEntity("e1"));
286
+ const result = await provider.getTimeline(repoId, "e1", {
287
+ limit: 10,
288
+ offset: 0
289
+ });
290
+ expect(result.events.length).toBeGreaterThanOrEqual(1);
291
+ });
292
+ });
293
+ describe("bulk operations", () => {
294
+ it("exports data", async () => {
295
+ await provider.createEntity(repoId, makeEntity("e1"));
296
+ const chunks = [];
297
+ for await (const chunk of provider.exportAll(repoId)) {
298
+ chunks.push(chunk);
299
+ }
300
+ expect(chunks.length).toBeGreaterThanOrEqual(1);
301
+ });
302
+ it("imports data", async () => {
303
+ const result = await provider.importBulk(repoId, [
304
+ { entities: [makeEntity("imported-1"), makeEntity("imported-2")] },
305
+ { relationships: [makeRelationship("ir1", "links", "imported-1", "imported-2")] }
306
+ ]);
307
+ expect(result.entitiesImported).toBe(2);
308
+ expect(result.relationshipsImported).toBe(1);
309
+ const e = await provider.getEntity(repoId, "imported-1");
310
+ expect(e).not.toBeNull();
311
+ });
312
+ });
313
+ describe("stats reflect data", () => {
314
+ it("counts entities and relationships", async () => {
315
+ await provider.createEntity(repoId, makeEntity("e1", "alpha"));
316
+ await provider.createEntity(repoId, makeEntity("e2", "alpha"));
317
+ await provider.createEntity(repoId, makeEntity("e3", "beta"));
318
+ await provider.createRelationship(repoId, makeRelationship("r1", "links", "e1", "e2"));
319
+ const stats = await provider.getRepositoryStats(repoId);
320
+ expect(stats.entityCount).toBe(3);
321
+ expect(stats.relationshipCount).toBe(1);
322
+ expect(stats.entityTypeBreakdown["alpha"]).toBe(2);
323
+ expect(stats.entityTypeBreakdown["beta"]).toBe(1);
324
+ expect(stats.relationshipTypeBreakdown["links"]).toBe(1);
325
+ });
326
+ });
327
+ });
328
+ }
329
+ export {
330
+ runStorageProviderConformanceTests
331
+ };
332
+ //# sourceMappingURL=conformance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/providers-builtin/conformance.ts"],"sourcesContent":["// Provider Conformance Test Suite\n// Any StorageProvider implementer can import and run these tests to verify conformance.\n//\n// Usage:\n// import { runStorageProviderConformanceTests } from '@utaba/deep-memory';\n// runStorageProviderConformanceTests(() => new MyStorageProvider());\n\nimport { describe, it, expect, beforeEach } from 'vitest';\nimport type { StorageProvider } from '../providers/StorageProvider.js';\nimport type { StoredEntity } from '../types/entities.js';\nimport type { StoredRelationship } from '../types/relationships.js';\nimport type { Provenance } from '../types/provenance.js';\n\nfunction makeProvenance(): Provenance {\n const now = new Date().toISOString();\n return {\n createdBy: 'conformance-test',\n createdByType: 'agent',\n createdAt: now,\n modifiedBy: 'conformance-test',\n modifiedByType: 'agent',\n modifiedAt: now,\n };\n}\n\nfunction makeEntity(id: string, type = 'test-type', label?: string): StoredEntity {\n return {\n id,\n slug: `${type}:${(label ?? id).toLowerCase().replace(/[^a-z0-9]+/g, '-')}`,\n entityType: type,\n label: label ?? id,\n summary: `Summary for ${id}`,\n properties: { key: 'value' },\n provenance: makeProvenance(),\n };\n}\n\nfunction makeRelationship(\n id: string,\n type: string,\n sourceId: string,\n targetId: string,\n bidirectional = false,\n): StoredRelationship {\n return {\n id,\n relationshipType: type,\n sourceEntityId: sourceId,\n targetEntityId: targetId,\n properties: {},\n bidirectional,\n provenance: makeProvenance(),\n };\n}\n\n/**\n * Run the full StorageProvider conformance test suite.\n *\n * @param factory - A function that creates a fresh, empty StorageProvider instance.\n * Called before each test to ensure isolation.\n */\nexport function runStorageProviderConformanceTests(\n factory: () => StorageProvider | Promise<StorageProvider>,\n): void {\n // Use a stable GUID so external cleanup scripts can target it\n const repoId = '40000000-0000-4000-a000-000000000001';\n\n let provider: StorageProvider;\n\n async function setup(): Promise<void> {\n provider = await factory();\n if (provider.initialise) await provider.initialise();\n\n await provider.createRepository({\n repositoryId: repoId,\n label: 'Conformance Test',\n governanceConfig: { mode: 'open' },\n createdAt: new Date().toISOString(),\n createdBy: 'conformance-test',\n });\n }\n\n describe('StorageProvider Conformance Tests', () => {\n beforeEach(async () => {\n await setup();\n });\n\n // ─── Repository ─────────────────────────────────────────\n\n describe('repository operations', () => {\n it('creates a repository', async () => {\n const repo = await provider.getRepository(repoId);\n expect(repo).not.toBeNull();\n expect(repo!.repositoryId).toBe(repoId);\n expect(repo!.label).toBe('Conformance Test');\n });\n\n it('returns null for non-existent repository', async () => {\n const repo = await provider.getRepository('ffffffff-ffff-4fff-afff-ffffffffffff');\n expect(repo).toBeNull();\n });\n\n it('lists repositories', async () => {\n const list = await provider.listRepositories();\n expect(list.items.length).toBeGreaterThanOrEqual(1);\n expect(list.items.some((r) => r.repositoryId === repoId)).toBe(true);\n });\n\n it('updates a repository', async () => {\n const updated = await provider.updateRepository(repoId, {\n label: 'Updated Label',\n description: 'Updated description',\n governanceConfig: { mode: 'open', defaultSimilarityThreshold: 0.4 },\n });\n expect(updated.label).toBe('Updated Label');\n expect(updated.description).toBe('Updated description');\n expect(updated.governanceConfig.defaultSimilarityThreshold).toBe(0.4);\n\n // Verify persistence\n const fetched = await provider.getRepository(repoId);\n expect(fetched!.label).toBe('Updated Label');\n expect(fetched!.governanceConfig.defaultSimilarityThreshold).toBe(0.4);\n });\n\n it('deletes a repository', async () => {\n await provider.deleteRepository(repoId);\n expect(await provider.getRepository(repoId)).toBeNull();\n });\n\n it('returns repository stats', async () => {\n const stats = await provider.getRepositoryStats(repoId);\n expect(stats.entityCount).toBe(0);\n expect(stats.relationshipCount).toBe(0);\n expect(typeof stats.vocabularyVersion).toBe('string');\n });\n });\n\n // ─── Vocabulary ─────────────────────────────────────────\n\n describe('vocabulary operations', () => {\n it('gets and saves vocabulary', async () => {\n const vocab = await provider.getVocabulary(repoId);\n expect(vocab).toBeDefined();\n expect(typeof vocab.version).toBe('string');\n\n const updated = { ...vocab, version: '1.0.0' };\n await provider.saveVocabulary(repoId, updated);\n\n const fetched = await provider.getVocabulary(repoId);\n expect(fetched.version).toBe('1.0.0');\n });\n\n it('returns vocabulary change log', async () => {\n const log = await provider.getVocabularyChangeLog(repoId);\n expect(Array.isArray(log.items)).toBe(true);\n });\n });\n\n // ─── Entities ───────────────────────────────────────────\n\n describe('entity operations', () => {\n it('creates and retrieves an entity', async () => {\n const entity = makeEntity('e1');\n await provider.createEntity(repoId, entity);\n\n const retrieved = await provider.getEntity(repoId, 'e1');\n expect(retrieved).not.toBeNull();\n expect(retrieved!.id).toBe('e1');\n expect(retrieved!.label).toBe('e1');\n });\n\n it('retrieves an entity by slug', async () => {\n const entity = makeEntity('e1', 'test-type', 'Alpha');\n await provider.createEntity(repoId, entity);\n\n const retrieved = await provider.getEntityBySlug(repoId, entity.slug);\n expect(retrieved).not.toBeNull();\n expect(retrieved!.id).toBe('e1');\n expect(retrieved!.slug).toBe(entity.slug);\n });\n\n it('returns null for non-existent entity', async () => {\n const result = await provider.getEntity(repoId, 'nonexistent');\n expect(result).toBeNull();\n });\n\n it('returns null for non-existent slug', async () => {\n const result = await provider.getEntityBySlug(repoId, 'nonexistent:slug');\n expect(result).toBeNull();\n });\n\n it('batch retrieves entities', async () => {\n await provider.createEntity(repoId, makeEntity('e1'));\n await provider.createEntity(repoId, makeEntity('e2'));\n\n const map = await provider.getEntities(repoId, ['e1', 'e2', 'missing']);\n expect(map.size).toBe(2);\n expect(map.has('e1')).toBe(true);\n expect(map.has('e2')).toBe(true);\n expect(map.has('missing')).toBe(false);\n });\n\n it('updates an entity', async () => {\n await provider.createEntity(repoId, makeEntity('e1'));\n const updated = await provider.updateEntity(repoId, 'e1', {\n label: 'Updated Label',\n provenance: makeProvenance(),\n });\n expect(updated.label).toBe('Updated Label');\n\n const fetched = await provider.getEntity(repoId, 'e1');\n expect(fetched!.label).toBe('Updated Label');\n });\n\n it('deletes an entity', async () => {\n await provider.createEntity(repoId, makeEntity('e1'));\n await provider.deleteEntity(repoId, 'e1');\n expect(await provider.getEntity(repoId, 'e1')).toBeNull();\n });\n\n it('finds entities by search term', async () => {\n await provider.createEntity(repoId, makeEntity('e1', 'test-type', 'Alpha'));\n await provider.createEntity(repoId, makeEntity('e2', 'test-type', 'Beta'));\n\n const result = await provider.findEntities(repoId, {\n searchTerm: 'alpha',\n limit: 10,\n offset: 0,\n });\n expect(result.items).toHaveLength(1);\n expect(result.items[0]!.label).toBe('Alpha');\n });\n\n it('finds entities by type filter', async () => {\n await provider.createEntity(repoId, makeEntity('e1', 'type-a', 'A'));\n await provider.createEntity(repoId, makeEntity('e2', 'type-b', 'B'));\n\n const result = await provider.findEntities(repoId, {\n entityTypes: ['type-a'],\n limit: 10,\n offset: 0,\n });\n expect(result.items).toHaveLength(1);\n expect(result.items[0]!.entityType).toBe('type-a');\n });\n\n it('paginates find results', async () => {\n await provider.createEntity(repoId, makeEntity('e1'));\n await provider.createEntity(repoId, makeEntity('e2'));\n await provider.createEntity(repoId, makeEntity('e3'));\n\n const page1 = await provider.findEntities(repoId, { limit: 2, offset: 0 });\n expect(page1.items).toHaveLength(2);\n expect(page1.hasMore).toBe(true);\n\n const page2 = await provider.findEntities(repoId, { limit: 2, offset: 2 });\n expect(page2.items).toHaveLength(1);\n expect(page2.hasMore).toBe(false);\n });\n });\n\n // ─── Relationships ──────────────────────────────────────\n\n describe('relationship operations', () => {\n beforeEach(async () => {\n await provider.createEntity(repoId, makeEntity('a'));\n await provider.createEntity(repoId, makeEntity('b'));\n await provider.createEntity(repoId, makeEntity('c'));\n });\n\n it('creates and retrieves a relationship', async () => {\n const rel = makeRelationship('r1', 'connects', 'a', 'b');\n await provider.createRelationship(repoId, rel);\n\n const retrieved = await provider.getRelationship(repoId, 'r1');\n expect(retrieved).not.toBeNull();\n expect(retrieved!.sourceEntityId).toBe('a');\n expect(retrieved!.targetEntityId).toBe('b');\n });\n\n it('returns null for non-existent relationship', async () => {\n expect(await provider.getRelationship(repoId, 'nonexistent')).toBeNull();\n });\n\n it('gets entity relationships', async () => {\n await provider.createRelationship(repoId, makeRelationship('r1', 'connects', 'a', 'b'));\n await provider.createRelationship(repoId, makeRelationship('r2', 'connects', 'c', 'a'));\n\n const result = await provider.getEntityRelationships(repoId, 'a');\n expect(result.items).toHaveLength(2);\n });\n\n it('filters relationships by direction', async () => {\n await provider.createRelationship(repoId, makeRelationship('r1', 'connects', 'a', 'b'));\n await provider.createRelationship(repoId, makeRelationship('r2', 'connects', 'c', 'a'));\n\n const outbound = await provider.getEntityRelationships(repoId, 'a', { direction: 'outbound' });\n expect(outbound.items).toHaveLength(1);\n expect(outbound.items[0]!.targetEntityId).toBe('b');\n\n const inbound = await provider.getEntityRelationships(repoId, 'a', { direction: 'inbound' });\n expect(inbound.items).toHaveLength(1);\n expect(inbound.items[0]!.sourceEntityId).toBe('c');\n });\n\n it('deletes a relationship', async () => {\n await provider.createRelationship(repoId, makeRelationship('r1', 'connects', 'a', 'b'));\n await provider.deleteRelationship(repoId, 'r1');\n expect(await provider.getRelationship(repoId, 'r1')).toBeNull();\n });\n });\n\n // ─── Graph Traversal ────────────────────────────────────\n\n describe('graph traversal', () => {\n beforeEach(async () => {\n await provider.createEntity(repoId, makeEntity('a', 'node', 'A'));\n await provider.createEntity(repoId, makeEntity('b', 'node', 'B'));\n await provider.createEntity(repoId, makeEntity('c', 'node', 'C'));\n await provider.createRelationship(repoId, makeRelationship('r1', 'links', 'a', 'b'));\n await provider.createRelationship(repoId, makeRelationship('r2', 'links', 'b', 'c'));\n });\n\n it('explores neighbourhood at depth 1', async () => {\n const result = await provider.exploreNeighbourhood(repoId, 'a', {\n depth: 1,\n direction: 'both',\n limitPerType: 10,\n offsetPerType: 0,\n });\n expect(result.centreId).toBe('a');\n expect(result.layers).toHaveLength(1);\n });\n\n it('finds paths between connected entities', async () => {\n const result = await provider.findPaths(repoId, 'a', 'c', {\n maxDepth: 3,\n limit: 5,\n offset: 0,\n });\n expect(result.paths.length).toBeGreaterThanOrEqual(1);\n const firstPath = result.paths[0]!;\n expect(firstPath.entityIds[0]).toBe('a');\n expect(firstPath.entityIds[firstPath.entityIds.length - 1]).toBe('c');\n });\n\n it('returns empty paths when no connection', async () => {\n await provider.createEntity(repoId, makeEntity('isolated', 'node', 'Isolated'));\n const result = await provider.findPaths(repoId, 'a', 'isolated', {\n maxDepth: 3,\n limit: 5,\n offset: 0,\n });\n expect(result.paths).toHaveLength(0);\n });\n\n it('finds paths through non-bidirectional inbound edges', async () => {\n // Graph: a → b ← d (both edges are non-bidirectional)\n // Path from a to d should traverse: a →(outbound) b ←(inbound) d\n await provider.createEntity(repoId, makeEntity('d', 'node', 'D'));\n await provider.createRelationship(repoId, makeRelationship('r3', 'links', 'd', 'b'));\n const result = await provider.findPaths(repoId, 'a', 'd', {\n maxDepth: 3,\n limit: 5,\n offset: 0,\n });\n expect(result.paths.length).toBeGreaterThanOrEqual(1);\n const firstPath = result.paths[0]!;\n expect(firstPath.entityIds[0]).toBe('a');\n expect(firstPath.entityIds[firstPath.entityIds.length - 1]).toBe('d');\n });\n });\n\n // ─── Timeline ───────────────────────────────────────────\n\n describe('timeline', () => {\n it('returns timeline events', async () => {\n await provider.createEntity(repoId, makeEntity('e1'));\n const result = await provider.getTimeline(repoId, 'e1', {\n limit: 10,\n offset: 0,\n });\n expect(result.events.length).toBeGreaterThanOrEqual(1);\n });\n });\n\n // ─── Bulk Operations ────────────────────────────────────\n\n describe('bulk operations', () => {\n it('exports data', async () => {\n await provider.createEntity(repoId, makeEntity('e1'));\n\n const chunks = [];\n for await (const chunk of provider.exportAll(repoId)) {\n chunks.push(chunk);\n }\n expect(chunks.length).toBeGreaterThanOrEqual(1);\n });\n\n it('imports data', async () => {\n const result = await provider.importBulk(repoId, [\n { entities: [makeEntity('imported-1'), makeEntity('imported-2')] },\n { relationships: [makeRelationship('ir1', 'links', 'imported-1', 'imported-2')] },\n ]);\n expect(result.entitiesImported).toBe(2);\n expect(result.relationshipsImported).toBe(1);\n\n // Verify imported data is accessible\n const e = await provider.getEntity(repoId, 'imported-1');\n expect(e).not.toBeNull();\n });\n });\n\n // ─── Stats after data ───────────────────────────────────\n\n describe('stats reflect data', () => {\n it('counts entities and relationships', async () => {\n await provider.createEntity(repoId, makeEntity('e1', 'alpha'));\n await provider.createEntity(repoId, makeEntity('e2', 'alpha'));\n await provider.createEntity(repoId, makeEntity('e3', 'beta'));\n await provider.createRelationship(repoId, makeRelationship('r1', 'links', 'e1', 'e2'));\n\n const stats = await provider.getRepositoryStats(repoId);\n expect(stats.entityCount).toBe(3);\n expect(stats.relationshipCount).toBe(1);\n expect(stats.entityTypeBreakdown['alpha']).toBe(2);\n expect(stats.entityTypeBreakdown['beta']).toBe(1);\n expect(stats.relationshipTypeBreakdown['links']).toBe(1);\n });\n });\n });\n}\n"],"mappings":";AAOA,SAAS,UAAU,IAAI,QAAQ,kBAAkB;AAMjD,SAAS,iBAA6B;AACpC,QAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,SAAO;AAAA,IACL,WAAW;AAAA,IACX,eAAe;AAAA,IACf,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,YAAY;AAAA,EACd;AACF;AAEA,SAAS,WAAW,IAAY,OAAO,aAAa,OAA8B;AAChF,SAAO;AAAA,IACL;AAAA,IACA,MAAM,GAAG,IAAI,KAAK,SAAS,IAAI,YAAY,EAAE,QAAQ,eAAe,GAAG,CAAC;AAAA,IACxE,YAAY;AAAA,IACZ,OAAO,SAAS;AAAA,IAChB,SAAS,eAAe,EAAE;AAAA,IAC1B,YAAY,EAAE,KAAK,QAAQ;AAAA,IAC3B,YAAY,eAAe;AAAA,EAC7B;AACF;AAEA,SAAS,iBACP,IACA,MACA,UACA,UACA,gBAAgB,OACI;AACpB,SAAO;AAAA,IACL;AAAA,IACA,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,YAAY,CAAC;AAAA,IACb;AAAA,IACA,YAAY,eAAe;AAAA,EAC7B;AACF;AAQO,SAAS,mCACd,SACM;AAEN,QAAM,SAAS;AAEf,MAAI;AAEJ,iBAAe,QAAuB;AACpC,eAAW,MAAM,QAAQ;AACzB,QAAI,SAAS,WAAY,OAAM,SAAS,WAAW;AAEnD,UAAM,SAAS,iBAAiB;AAAA,MAC9B,cAAc;AAAA,MACd,OAAO;AAAA,MACP,kBAAkB,EAAE,MAAM,OAAO;AAAA,MACjC,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MAClC,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,WAAS,qCAAqC,MAAM;AAClD,eAAW,YAAY;AACrB,YAAM,MAAM;AAAA,IACd,CAAC;AAID,aAAS,yBAAyB,MAAM;AACtC,SAAG,wBAAwB,YAAY;AACrC,cAAM,OAAO,MAAM,SAAS,cAAc,MAAM;AAChD,eAAO,IAAI,EAAE,IAAI,SAAS;AAC1B,eAAO,KAAM,YAAY,EAAE,KAAK,MAAM;AACtC,eAAO,KAAM,KAAK,EAAE,KAAK,kBAAkB;AAAA,MAC7C,CAAC;AAED,SAAG,4CAA4C,YAAY;AACzD,cAAM,OAAO,MAAM,SAAS,cAAc,sCAAsC;AAChF,eAAO,IAAI,EAAE,SAAS;AAAA,MACxB,CAAC;AAED,SAAG,sBAAsB,YAAY;AACnC,cAAM,OAAO,MAAM,SAAS,iBAAiB;AAC7C,eAAO,KAAK,MAAM,MAAM,EAAE,uBAAuB,CAAC;AAClD,eAAO,KAAK,MAAM,KAAK,CAAC,MAAM,EAAE,iBAAiB,MAAM,CAAC,EAAE,KAAK,IAAI;AAAA,MACrE,CAAC;AAED,SAAG,wBAAwB,YAAY;AACrC,cAAM,UAAU,MAAM,SAAS,iBAAiB,QAAQ;AAAA,UACtD,OAAO;AAAA,UACP,aAAa;AAAA,UACb,kBAAkB,EAAE,MAAM,QAAQ,4BAA4B,IAAI;AAAA,QACpE,CAAC;AACD,eAAO,QAAQ,KAAK,EAAE,KAAK,eAAe;AAC1C,eAAO,QAAQ,WAAW,EAAE,KAAK,qBAAqB;AACtD,eAAO,QAAQ,iBAAiB,0BAA0B,EAAE,KAAK,GAAG;AAGpE,cAAM,UAAU,MAAM,SAAS,cAAc,MAAM;AACnD,eAAO,QAAS,KAAK,EAAE,KAAK,eAAe;AAC3C,eAAO,QAAS,iBAAiB,0BAA0B,EAAE,KAAK,GAAG;AAAA,MACvE,CAAC;AAED,SAAG,wBAAwB,YAAY;AACrC,cAAM,SAAS,iBAAiB,MAAM;AACtC,eAAO,MAAM,SAAS,cAAc,MAAM,CAAC,EAAE,SAAS;AAAA,MACxD,CAAC;AAED,SAAG,4BAA4B,YAAY;AACzC,cAAM,QAAQ,MAAM,SAAS,mBAAmB,MAAM;AACtD,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC;AAChC,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC;AACtC,eAAO,OAAO,MAAM,iBAAiB,EAAE,KAAK,QAAQ;AAAA,MACtD,CAAC;AAAA,IACH,CAAC;AAID,aAAS,yBAAyB,MAAM;AACtC,SAAG,6BAA6B,YAAY;AAC1C,cAAM,QAAQ,MAAM,SAAS,cAAc,MAAM;AACjD,eAAO,KAAK,EAAE,YAAY;AAC1B,eAAO,OAAO,MAAM,OAAO,EAAE,KAAK,QAAQ;AAE1C,cAAM,UAAU,EAAE,GAAG,OAAO,SAAS,QAAQ;AAC7C,cAAM,SAAS,eAAe,QAAQ,OAAO;AAE7C,cAAM,UAAU,MAAM,SAAS,cAAc,MAAM;AACnD,eAAO,QAAQ,OAAO,EAAE,KAAK,OAAO;AAAA,MACtC,CAAC;AAED,SAAG,iCAAiC,YAAY;AAC9C,cAAM,MAAM,MAAM,SAAS,uBAAuB,MAAM;AACxD,eAAO,MAAM,QAAQ,IAAI,KAAK,CAAC,EAAE,KAAK,IAAI;AAAA,MAC5C,CAAC;AAAA,IACH,CAAC;AAID,aAAS,qBAAqB,MAAM;AAClC,SAAG,mCAAmC,YAAY;AAChD,cAAM,SAAS,WAAW,IAAI;AAC9B,cAAM,SAAS,aAAa,QAAQ,MAAM;AAE1C,cAAM,YAAY,MAAM,SAAS,UAAU,QAAQ,IAAI;AACvD,eAAO,SAAS,EAAE,IAAI,SAAS;AAC/B,eAAO,UAAW,EAAE,EAAE,KAAK,IAAI;AAC/B,eAAO,UAAW,KAAK,EAAE,KAAK,IAAI;AAAA,MACpC,CAAC;AAED,SAAG,+BAA+B,YAAY;AAC5C,cAAM,SAAS,WAAW,MAAM,aAAa,OAAO;AACpD,cAAM,SAAS,aAAa,QAAQ,MAAM;AAE1C,cAAM,YAAY,MAAM,SAAS,gBAAgB,QAAQ,OAAO,IAAI;AACpE,eAAO,SAAS,EAAE,IAAI,SAAS;AAC/B,eAAO,UAAW,EAAE,EAAE,KAAK,IAAI;AAC/B,eAAO,UAAW,IAAI,EAAE,KAAK,OAAO,IAAI;AAAA,MAC1C,CAAC;AAED,SAAG,wCAAwC,YAAY;AACrD,cAAM,SAAS,MAAM,SAAS,UAAU,QAAQ,aAAa;AAC7D,eAAO,MAAM,EAAE,SAAS;AAAA,MAC1B,CAAC;AAED,SAAG,sCAAsC,YAAY;AACnD,cAAM,SAAS,MAAM,SAAS,gBAAgB,QAAQ,kBAAkB;AACxE,eAAO,MAAM,EAAE,SAAS;AAAA,MAC1B,CAAC;AAED,SAAG,4BAA4B,YAAY;AACzC,cAAM,SAAS,aAAa,QAAQ,WAAW,IAAI,CAAC;AACpD,cAAM,SAAS,aAAa,QAAQ,WAAW,IAAI,CAAC;AAEpD,cAAM,MAAM,MAAM,SAAS,YAAY,QAAQ,CAAC,MAAM,MAAM,SAAS,CAAC;AACtE,eAAO,IAAI,IAAI,EAAE,KAAK,CAAC;AACvB,eAAO,IAAI,IAAI,IAAI,CAAC,EAAE,KAAK,IAAI;AAC/B,eAAO,IAAI,IAAI,IAAI,CAAC,EAAE,KAAK,IAAI;AAC/B,eAAO,IAAI,IAAI,SAAS,CAAC,EAAE,KAAK,KAAK;AAAA,MACvC,CAAC;AAED,SAAG,qBAAqB,YAAY;AAClC,cAAM,SAAS,aAAa,QAAQ,WAAW,IAAI,CAAC;AACpD,cAAM,UAAU,MAAM,SAAS,aAAa,QAAQ,MAAM;AAAA,UACxD,OAAO;AAAA,UACP,YAAY,eAAe;AAAA,QAC7B,CAAC;AACD,eAAO,QAAQ,KAAK,EAAE,KAAK,eAAe;AAE1C,cAAM,UAAU,MAAM,SAAS,UAAU,QAAQ,IAAI;AACrD,eAAO,QAAS,KAAK,EAAE,KAAK,eAAe;AAAA,MAC7C,CAAC;AAED,SAAG,qBAAqB,YAAY;AAClC,cAAM,SAAS,aAAa,QAAQ,WAAW,IAAI,CAAC;AACpD,cAAM,SAAS,aAAa,QAAQ,IAAI;AACxC,eAAO,MAAM,SAAS,UAAU,QAAQ,IAAI,CAAC,EAAE,SAAS;AAAA,MAC1D,CAAC;AAED,SAAG,iCAAiC,YAAY;AAC9C,cAAM,SAAS,aAAa,QAAQ,WAAW,MAAM,aAAa,OAAO,CAAC;AAC1E,cAAM,SAAS,aAAa,QAAQ,WAAW,MAAM,aAAa,MAAM,CAAC;AAEzE,cAAM,SAAS,MAAM,SAAS,aAAa,QAAQ;AAAA,UACjD,YAAY;AAAA,UACZ,OAAO;AAAA,UACP,QAAQ;AAAA,QACV,CAAC;AACD,eAAO,OAAO,KAAK,EAAE,aAAa,CAAC;AACnC,eAAO,OAAO,MAAM,CAAC,EAAG,KAAK,EAAE,KAAK,OAAO;AAAA,MAC7C,CAAC;AAED,SAAG,iCAAiC,YAAY;AAC9C,cAAM,SAAS,aAAa,QAAQ,WAAW,MAAM,UAAU,GAAG,CAAC;AACnE,cAAM,SAAS,aAAa,QAAQ,WAAW,MAAM,UAAU,GAAG,CAAC;AAEnE,cAAM,SAAS,MAAM,SAAS,aAAa,QAAQ;AAAA,UACjD,aAAa,CAAC,QAAQ;AAAA,UACtB,OAAO;AAAA,UACP,QAAQ;AAAA,QACV,CAAC;AACD,eAAO,OAAO,KAAK,EAAE,aAAa,CAAC;AACnC,eAAO,OAAO,MAAM,CAAC,EAAG,UAAU,EAAE,KAAK,QAAQ;AAAA,MACnD,CAAC;AAED,SAAG,0BAA0B,YAAY;AACvC,cAAM,SAAS,aAAa,QAAQ,WAAW,IAAI,CAAC;AACpD,cAAM,SAAS,aAAa,QAAQ,WAAW,IAAI,CAAC;AACpD,cAAM,SAAS,aAAa,QAAQ,WAAW,IAAI,CAAC;AAEpD,cAAM,QAAQ,MAAM,SAAS,aAAa,QAAQ,EAAE,OAAO,GAAG,QAAQ,EAAE,CAAC;AACzE,eAAO,MAAM,KAAK,EAAE,aAAa,CAAC;AAClC,eAAO,MAAM,OAAO,EAAE,KAAK,IAAI;AAE/B,cAAM,QAAQ,MAAM,SAAS,aAAa,QAAQ,EAAE,OAAO,GAAG,QAAQ,EAAE,CAAC;AACzE,eAAO,MAAM,KAAK,EAAE,aAAa,CAAC;AAClC,eAAO,MAAM,OAAO,EAAE,KAAK,KAAK;AAAA,MAClC,CAAC;AAAA,IACH,CAAC;AAID,aAAS,2BAA2B,MAAM;AACxC,iBAAW,YAAY;AACrB,cAAM,SAAS,aAAa,QAAQ,WAAW,GAAG,CAAC;AACnD,cAAM,SAAS,aAAa,QAAQ,WAAW,GAAG,CAAC;AACnD,cAAM,SAAS,aAAa,QAAQ,WAAW,GAAG,CAAC;AAAA,MACrD,CAAC;AAED,SAAG,wCAAwC,YAAY;AACrD,cAAM,MAAM,iBAAiB,MAAM,YAAY,KAAK,GAAG;AACvD,cAAM,SAAS,mBAAmB,QAAQ,GAAG;AAE7C,cAAM,YAAY,MAAM,SAAS,gBAAgB,QAAQ,IAAI;AAC7D,eAAO,SAAS,EAAE,IAAI,SAAS;AAC/B,eAAO,UAAW,cAAc,EAAE,KAAK,GAAG;AAC1C,eAAO,UAAW,cAAc,EAAE,KAAK,GAAG;AAAA,MAC5C,CAAC;AAED,SAAG,8CAA8C,YAAY;AAC3D,eAAO,MAAM,SAAS,gBAAgB,QAAQ,aAAa,CAAC,EAAE,SAAS;AAAA,MACzE,CAAC;AAED,SAAG,6BAA6B,YAAY;AAC1C,cAAM,SAAS,mBAAmB,QAAQ,iBAAiB,MAAM,YAAY,KAAK,GAAG,CAAC;AACtF,cAAM,SAAS,mBAAmB,QAAQ,iBAAiB,MAAM,YAAY,KAAK,GAAG,CAAC;AAEtF,cAAM,SAAS,MAAM,SAAS,uBAAuB,QAAQ,GAAG;AAChE,eAAO,OAAO,KAAK,EAAE,aAAa,CAAC;AAAA,MACrC,CAAC;AAED,SAAG,sCAAsC,YAAY;AACnD,cAAM,SAAS,mBAAmB,QAAQ,iBAAiB,MAAM,YAAY,KAAK,GAAG,CAAC;AACtF,cAAM,SAAS,mBAAmB,QAAQ,iBAAiB,MAAM,YAAY,KAAK,GAAG,CAAC;AAEtF,cAAM,WAAW,MAAM,SAAS,uBAAuB,QAAQ,KAAK,EAAE,WAAW,WAAW,CAAC;AAC7F,eAAO,SAAS,KAAK,EAAE,aAAa,CAAC;AACrC,eAAO,SAAS,MAAM,CAAC,EAAG,cAAc,EAAE,KAAK,GAAG;AAElD,cAAM,UAAU,MAAM,SAAS,uBAAuB,QAAQ,KAAK,EAAE,WAAW,UAAU,CAAC;AAC3F,eAAO,QAAQ,KAAK,EAAE,aAAa,CAAC;AACpC,eAAO,QAAQ,MAAM,CAAC,EAAG,cAAc,EAAE,KAAK,GAAG;AAAA,MACnD,CAAC;AAED,SAAG,0BAA0B,YAAY;AACvC,cAAM,SAAS,mBAAmB,QAAQ,iBAAiB,MAAM,YAAY,KAAK,GAAG,CAAC;AACtF,cAAM,SAAS,mBAAmB,QAAQ,IAAI;AAC9C,eAAO,MAAM,SAAS,gBAAgB,QAAQ,IAAI,CAAC,EAAE,SAAS;AAAA,MAChE,CAAC;AAAA,IACH,CAAC;AAID,aAAS,mBAAmB,MAAM;AAChC,iBAAW,YAAY;AACrB,cAAM,SAAS,aAAa,QAAQ,WAAW,KAAK,QAAQ,GAAG,CAAC;AAChE,cAAM,SAAS,aAAa,QAAQ,WAAW,KAAK,QAAQ,GAAG,CAAC;AAChE,cAAM,SAAS,aAAa,QAAQ,WAAW,KAAK,QAAQ,GAAG,CAAC;AAChE,cAAM,SAAS,mBAAmB,QAAQ,iBAAiB,MAAM,SAAS,KAAK,GAAG,CAAC;AACnF,cAAM,SAAS,mBAAmB,QAAQ,iBAAiB,MAAM,SAAS,KAAK,GAAG,CAAC;AAAA,MACrF,CAAC;AAED,SAAG,qCAAqC,YAAY;AAClD,cAAM,SAAS,MAAM,SAAS,qBAAqB,QAAQ,KAAK;AAAA,UAC9D,OAAO;AAAA,UACP,WAAW;AAAA,UACX,cAAc;AAAA,UACd,eAAe;AAAA,QACjB,CAAC;AACD,eAAO,OAAO,QAAQ,EAAE,KAAK,GAAG;AAChC,eAAO,OAAO,MAAM,EAAE,aAAa,CAAC;AAAA,MACtC,CAAC;AAED,SAAG,0CAA0C,YAAY;AACvD,cAAM,SAAS,MAAM,SAAS,UAAU,QAAQ,KAAK,KAAK;AAAA,UACxD,UAAU;AAAA,UACV,OAAO;AAAA,UACP,QAAQ;AAAA,QACV,CAAC;AACD,eAAO,OAAO,MAAM,MAAM,EAAE,uBAAuB,CAAC;AACpD,cAAM,YAAY,OAAO,MAAM,CAAC;AAChC,eAAO,UAAU,UAAU,CAAC,CAAC,EAAE,KAAK,GAAG;AACvC,eAAO,UAAU,UAAU,UAAU,UAAU,SAAS,CAAC,CAAC,EAAE,KAAK,GAAG;AAAA,MACtE,CAAC;AAED,SAAG,0CAA0C,YAAY;AACvD,cAAM,SAAS,aAAa,QAAQ,WAAW,YAAY,QAAQ,UAAU,CAAC;AAC9E,cAAM,SAAS,MAAM,SAAS,UAAU,QAAQ,KAAK,YAAY;AAAA,UAC/D,UAAU;AAAA,UACV,OAAO;AAAA,UACP,QAAQ;AAAA,QACV,CAAC;AACD,eAAO,OAAO,KAAK,EAAE,aAAa,CAAC;AAAA,MACrC,CAAC;AAED,SAAG,uDAAuD,YAAY;AAGpE,cAAM,SAAS,aAAa,QAAQ,WAAW,KAAK,QAAQ,GAAG,CAAC;AAChE,cAAM,SAAS,mBAAmB,QAAQ,iBAAiB,MAAM,SAAS,KAAK,GAAG,CAAC;AACnF,cAAM,SAAS,MAAM,SAAS,UAAU,QAAQ,KAAK,KAAK;AAAA,UACxD,UAAU;AAAA,UACV,OAAO;AAAA,UACP,QAAQ;AAAA,QACV,CAAC;AACD,eAAO,OAAO,MAAM,MAAM,EAAE,uBAAuB,CAAC;AACpD,cAAM,YAAY,OAAO,MAAM,CAAC;AAChC,eAAO,UAAU,UAAU,CAAC,CAAC,EAAE,KAAK,GAAG;AACvC,eAAO,UAAU,UAAU,UAAU,UAAU,SAAS,CAAC,CAAC,EAAE,KAAK,GAAG;AAAA,MACtE,CAAC;AAAA,IACH,CAAC;AAID,aAAS,YAAY,MAAM;AACzB,SAAG,2BAA2B,YAAY;AACxC,cAAM,SAAS,aAAa,QAAQ,WAAW,IAAI,CAAC;AACpD,cAAM,SAAS,MAAM,SAAS,YAAY,QAAQ,MAAM;AAAA,UACtD,OAAO;AAAA,UACP,QAAQ;AAAA,QACV,CAAC;AACD,eAAO,OAAO,OAAO,MAAM,EAAE,uBAAuB,CAAC;AAAA,MACvD,CAAC;AAAA,IACH,CAAC;AAID,aAAS,mBAAmB,MAAM;AAChC,SAAG,gBAAgB,YAAY;AAC7B,cAAM,SAAS,aAAa,QAAQ,WAAW,IAAI,CAAC;AAEpD,cAAM,SAAS,CAAC;AAChB,yBAAiB,SAAS,SAAS,UAAU,MAAM,GAAG;AACpD,iBAAO,KAAK,KAAK;AAAA,QACnB;AACA,eAAO,OAAO,MAAM,EAAE,uBAAuB,CAAC;AAAA,MAChD,CAAC;AAED,SAAG,gBAAgB,YAAY;AAC7B,cAAM,SAAS,MAAM,SAAS,WAAW,QAAQ;AAAA,UAC/C,EAAE,UAAU,CAAC,WAAW,YAAY,GAAG,WAAW,YAAY,CAAC,EAAE;AAAA,UACjE,EAAE,eAAe,CAAC,iBAAiB,OAAO,SAAS,cAAc,YAAY,CAAC,EAAE;AAAA,QAClF,CAAC;AACD,eAAO,OAAO,gBAAgB,EAAE,KAAK,CAAC;AACtC,eAAO,OAAO,qBAAqB,EAAE,KAAK,CAAC;AAG3C,cAAM,IAAI,MAAM,SAAS,UAAU,QAAQ,YAAY;AACvD,eAAO,CAAC,EAAE,IAAI,SAAS;AAAA,MACzB,CAAC;AAAA,IACH,CAAC;AAID,aAAS,sBAAsB,MAAM;AACnC,SAAG,qCAAqC,YAAY;AAClD,cAAM,SAAS,aAAa,QAAQ,WAAW,MAAM,OAAO,CAAC;AAC7D,cAAM,SAAS,aAAa,QAAQ,WAAW,MAAM,OAAO,CAAC;AAC7D,cAAM,SAAS,aAAa,QAAQ,WAAW,MAAM,MAAM,CAAC;AAC5D,cAAM,SAAS,mBAAmB,QAAQ,iBAAiB,MAAM,SAAS,MAAM,IAAI,CAAC;AAErF,cAAM,QAAQ,MAAM,SAAS,mBAAmB,MAAM;AACtD,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC;AAChC,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC;AACtC,eAAO,MAAM,oBAAoB,OAAO,CAAC,EAAE,KAAK,CAAC;AACjD,eAAO,MAAM,oBAAoB,MAAM,CAAC,EAAE,KAAK,CAAC;AAChD,eAAO,MAAM,0BAA0B,OAAO,CAAC,EAAE,KAAK,CAAC;AAAA,MACzD,CAAC;AAAA,IACH,CAAC;AAAA,EACH,CAAC;AACH;","names":[]}
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
+
16
+ // src/types/index.ts
17
+ var types_exports = {};
18
+ module.exports = __toCommonJS(types_exports);
19
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/types/index.ts"],"sourcesContent":["// Type re-exports — @utaba/deep-memory/types\n\nexport type {\n ProvenanceContext,\n Provenance,\n} from './provenance.js';\n\nexport type {\n PropertyType,\n PropertySchema,\n EntityTypeDefinition,\n RelationshipTypeDefinition,\n MemoryVocabulary,\n GovernanceMode,\n GovernanceConfig,\n VocabularyProposal,\n VocabularyProposalResult,\n VocabularyChangeRecord,\n ResolvedVocabulary,\n EntityTypeInput,\n RelationshipTypeInput,\n VocabularyInput,\n} from './vocabulary.js';\n\nexport type {\n DetailLevel,\n Entity,\n EntitySummary,\n EntityBrief,\n CreateEntityInput,\n UpdateEntityInput,\n StoredEntity,\n StoredEntityUpdate,\n GetEntityOptions,\n GetEntitiesOptions,\n} from './entities.js';\n\nexport type {\n RelationshipDirection,\n Relationship,\n EnrichedRelationship,\n CreateRelationshipInput,\n StoredRelationship,\n RelationshipQueryOptions,\n RelationshipSummary,\n} from './relationships.js';\n\nexport type {\n RepositoryConfig,\n RepositoryMetadata,\n RepositoryUpdate,\n RepositorySummary,\n RepositoryStats,\n StoredRepository,\n StoredRepositorySummary,\n RepositoryFilter,\n StorageRepositoryConfig,\n} from './repositories.js';\n\nexport type {\n PaginationOptions,\n FindEntitiesQuery,\n ExploreOptions,\n PathOptions,\n ConceptSearchOptions,\n TimelineOptions,\n StorageFindQuery,\n StorageExploreOptions,\n StoragePathOptions,\n StorageTimelineOptions,\n SearchOptions,\n PropertyFilter,\n ProvenanceFilter,\n} from './queries.js';\n\nexport type {\n PaginatedResult,\n NeighbourhoodCentre,\n NeighbourhoodGroup,\n NeighbourhoodLayer,\n Neighbourhood,\n Path,\n PathResult,\n ScoredEntity,\n TimelineEntityRef,\n TimelineRelationshipDetail,\n TimelineEvent,\n TimelineResult,\n GraphResult,\n EntityMap,\n StorageNeighbourhoodGroup,\n StorageNeighbourhoodLayer,\n StorageNeighbourhood,\n StoragePath,\n StoragePathResult,\n StorageTimelineEvent,\n StorageTimelineResult,\n SearchHit,\n BulkImportResult,\n ReembedResult,\n} from './results.js';\n\nexport type {\n DeepMemoryEventType,\n EventPayload,\n DeepMemoryEvent,\n EventHandler,\n Unsubscribe,\n HookResult,\n} from './events.js';\n\nexport type {\n ExportManifest,\n ExportArchive,\n ExportChunk,\n ExportStreamItem,\n ImportOptions,\n ImportChunk,\n ImportStreamHeader,\n ImportWarning,\n ImportResult,\n} from './portability.js';\n"],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
@@ -0,0 +1,121 @@
1
+ import { v as ProvenanceContext, C as CreateEntityInput, x as Entity, U as UpdateEntityInput, r as CreateRelationshipInput, H as Relationship, V as VocabularyChangeRecord } from '../portability-DdlNYXGX.cjs';
2
+ export { B as BulkImportResult, W as ConceptSearchOptions, D as DetailLevel, a7 as EnrichedRelationship, z as EntityBrief, a8 as EntityMap, y as EntitySummary, s as EntityTypeDefinition, a9 as EntityTypeInput, N as ExploreOptions, a0 as ExportArchive, E as ExportChunk, aa as ExportManifest, a3 as ExportStreamItem, F as FindEntitiesQuery, ab as GetEntitiesOptions, ac as GetEntityOptions, G as GovernanceConfig, ad as GovernanceMode, L as GraphResult, I as ImportChunk, a1 as ImportOptions, a2 as ImportResult, a4 as ImportStreamHeader, ae as ImportWarning, M as MemoryVocabulary, O as Neighbourhood, af as NeighbourhoodCentre, ag as NeighbourhoodGroup, ah as NeighbourhoodLayer, P as PaginatedResult, e as PaginationOptions, ai as Path, Q as PathOptions, T as PathResult, J as PropertyFilter, aj as PropertySchema, ak as PropertyType, w as Provenance, al as ProvenanceFilter, A as ReembedResult, am as RelationshipDirection, j as RelationshipQueryOptions, K as RelationshipSummary, an as RelationshipTypeDefinition, ao as RelationshipTypeInput, _ as RepositoryConfig, R as RepositoryFilter, ap as RepositoryMetadata, d as RepositoryStats, $ as RepositorySummary, c as RepositoryUpdate, q as ResolvedVocabulary, X as ScoredEntity, a6 as SearchHit, a5 as SearchOptions, k as StorageExploreOptions, h as StorageFindQuery, l as StorageNeighbourhood, aq as StorageNeighbourhoodGroup, ar as StorageNeighbourhoodLayer, as as StoragePath, m as StoragePathOptions, n as StoragePathResult, S as StorageRepositoryConfig, at as StorageTimelineEvent, o as StorageTimelineOptions, p as StorageTimelineResult, f as StoredEntity, g as StoredEntityUpdate, i as StoredRelationship, a as StoredRepository, b as StoredRepositorySummary, au as TimelineEntityRef, av as TimelineEvent, Y as TimelineOptions, aw as TimelineRelationshipDetail, Z as TimelineResult, ax as VocabularyInput, t as VocabularyProposal, u as VocabularyProposalResult } from '../portability-DdlNYXGX.cjs';
3
+
4
+ /** All event types emitted by the Deep Memory engine */
5
+ type DeepMemoryEventType = 'repository:created' | 'repository:opened' | 'repository:updated' | 'repository:deleted' | 'entity:creating' | 'entity:created' | 'entity:updating' | 'entity:updated' | 'entity:deleting' | 'entity:deleted' | 'relationship:creating' | 'relationship:created' | 'relationship:removing' | 'relationship:removed' | 'vocabulary:proposal' | 'vocabulary:approved' | 'vocabulary:rejected' | 'vocabulary:pending' | 'vocabulary:changed' | 'validation:failed' | 'search:executed' | 'reembed:started' | 'reembed:progress' | 'reembed:completed' | 'reembed:failed' | 'export:started' | 'export:progress' | 'export:completed' | 'import:started' | 'import:progress' | 'import:completed' | 'import:failed';
6
+ /** Type-safe event payload mapping */
7
+ type EventPayload<T extends DeepMemoryEventType> = T extends 'repository:created' ? {
8
+ repositoryId: string;
9
+ label: string;
10
+ } : T extends 'repository:opened' ? {
11
+ repositoryId: string;
12
+ } : T extends 'repository:updated' ? {
13
+ repositoryId: string;
14
+ } : T extends 'repository:deleted' ? {
15
+ repositoryId: string;
16
+ } : T extends 'entity:creating' ? {
17
+ input: CreateEntityInput;
18
+ } : T extends 'entity:created' ? {
19
+ entity: Entity;
20
+ } : T extends 'entity:updating' ? {
21
+ id: string;
22
+ updates: UpdateEntityInput;
23
+ } : T extends 'entity:updated' ? {
24
+ entity: Entity;
25
+ } : T extends 'entity:deleting' ? {
26
+ id: string;
27
+ } : T extends 'entity:deleted' ? {
28
+ id: string;
29
+ } : T extends 'relationship:creating' ? {
30
+ input: CreateRelationshipInput;
31
+ } : T extends 'relationship:created' ? {
32
+ relationship: Relationship;
33
+ } : T extends 'relationship:removing' ? {
34
+ id: string;
35
+ } : T extends 'relationship:removed' ? {
36
+ id: string;
37
+ } : T extends 'vocabulary:proposal' ? {
38
+ proposal: VocabularyChangeRecord;
39
+ } : T extends 'vocabulary:approved' ? {
40
+ change: VocabularyChangeRecord;
41
+ } : T extends 'vocabulary:rejected' ? {
42
+ reason: string;
43
+ duplicates?: Array<{
44
+ type: string;
45
+ similarity: number;
46
+ }>;
47
+ } : T extends 'vocabulary:pending' ? {
48
+ proposalId: string;
49
+ } : T extends 'vocabulary:changed' ? {
50
+ previousVersion: string;
51
+ newVersion: string;
52
+ change: VocabularyChangeRecord;
53
+ } : T extends 'validation:failed' ? {
54
+ operation: string;
55
+ error: string;
56
+ suggestions?: string[];
57
+ } : T extends 'search:executed' ? {
58
+ query: string;
59
+ resultCount: number;
60
+ } : T extends 'reembed:started' ? {
61
+ repositoryId: string;
62
+ totalEntities: number;
63
+ } : T extends 'reembed:progress' ? {
64
+ repositoryId: string;
65
+ processed: number;
66
+ totalEntities: number;
67
+ failed: number;
68
+ } : T extends 'reembed:completed' ? {
69
+ repositoryId: string;
70
+ processed: number;
71
+ failed: number;
72
+ modelId: string;
73
+ } : T extends 'reembed:failed' ? {
74
+ repositoryId: string;
75
+ error: string;
76
+ } : T extends 'export:started' ? {
77
+ repositoryId: string;
78
+ } : T extends 'export:progress' ? {
79
+ repositoryId: string;
80
+ entitiesExported: number;
81
+ totalEntities: number;
82
+ } : T extends 'export:completed' ? {
83
+ repositoryId: string;
84
+ entityCount: number;
85
+ relationshipCount: number;
86
+ } : T extends 'import:started' ? {
87
+ repositoryId: string;
88
+ } : T extends 'import:progress' ? {
89
+ repositoryId: string;
90
+ entitiesImported: number;
91
+ totalEntities: number;
92
+ } : T extends 'import:completed' ? {
93
+ repositoryId: string;
94
+ entitiesImported: number;
95
+ relationshipsImported: number;
96
+ } : T extends 'import:failed' ? {
97
+ repositoryId: string;
98
+ error: string;
99
+ } : Record<string, unknown>;
100
+ /** A typed event emitted by the engine */
101
+ interface DeepMemoryEvent<T extends DeepMemoryEventType> {
102
+ type: T;
103
+ timestamp: string;
104
+ repositoryId?: string;
105
+ provenance: ProvenanceContext;
106
+ payload: EventPayload<T>;
107
+ }
108
+ /** Event handler function */
109
+ type EventHandler<T extends DeepMemoryEventType> = (event: DeepMemoryEvent<T>) => void | Promise<void>;
110
+ /** Unsubscribe function returned by on() */
111
+ type Unsubscribe = () => void;
112
+ /**
113
+ * Result from a pre-mutation hook handler.
114
+ * Return `{ cancel: true, reason }` to abort the operation.
115
+ */
116
+ interface HookResult {
117
+ cancel?: boolean;
118
+ reason?: string;
119
+ }
120
+
121
+ export { CreateEntityInput, CreateRelationshipInput, type DeepMemoryEvent, type DeepMemoryEventType, Entity, type EventHandler, type EventPayload, type HookResult, ProvenanceContext, Relationship, type Unsubscribe, UpdateEntityInput, VocabularyChangeRecord };