@x12i/memorix-retrieval 1.8.2 → 1.9.2
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/README.md +34 -5
- package/dist/client/types.d.ts +24 -0
- package/dist/client/types.d.ts.map +1 -1
- package/dist/data/collection-parser.d.ts +3 -0
- package/dist/data/collection-parser.d.ts.map +1 -1
- package/dist/data/collection-parser.js +3 -0
- package/dist/data/collection-parser.js.map +1 -1
- package/dist/data/record-identity.d.ts +3 -1
- package/dist/data/record-identity.d.ts.map +1 -1
- package/dist/data/record-identity.js +25 -4
- package/dist/data/record-identity.js.map +1 -1
- package/dist/explorer/collection-inventory.d.ts.map +1 -1
- package/dist/explorer/collection-inventory.js +23 -6
- package/dist/explorer/collection-inventory.js.map +1 -1
- package/dist/explorer/collection-records.d.ts.map +1 -1
- package/dist/explorer/collection-records.js +6 -2
- package/dist/explorer/collection-records.js.map +1 -1
- package/dist/explorer/entity-graph.d.ts +36 -1
- package/dist/explorer/entity-graph.d.ts.map +1 -1
- package/dist/explorer/entity-graph.js +161 -0
- package/dist/explorer/entity-graph.js.map +1 -1
- package/dist/explorer/health.d.ts +54 -0
- package/dist/explorer/health.d.ts.map +1 -1
- package/dist/explorer/health.js +135 -122
- package/dist/explorer/health.js.map +1 -1
- package/dist/explorer/raw-collection-records.d.ts +45 -7
- package/dist/explorer/raw-collection-records.d.ts.map +1 -1
- package/dist/explorer/raw-collection-records.js +46 -7
- package/dist/explorer/raw-collection-records.js.map +1 -1
- package/dist/explorer/unified-inventory.d.ts +80 -17
- package/dist/explorer/unified-inventory.d.ts.map +1 -1
- package/dist/explorer/unified-inventory.js +324 -89
- package/dist/explorer/unified-inventory.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/retrieval/fetch-item.d.ts.map +1 -1
- package/dist/retrieval/fetch-item.js +52 -3
- package/dist/retrieval/fetch-item.js.map +1 -1
- package/dist/retrieval/fetch-list.d.ts.map +1 -1
- package/dist/retrieval/fetch-list.js +46 -0
- package/dist/retrieval/fetch-list.js.map +1 -1
- package/dist/retrieval/fetch-slices.d.ts.map +1 -1
- package/dist/retrieval/fetch-slices.js +30 -9
- package/dist/retrieval/fetch-slices.js.map +1 -1
- package/dist/runtime/source-provenance.d.ts +94 -0
- package/dist/runtime/source-provenance.d.ts.map +1 -0
- package/dist/runtime/source-provenance.js +129 -0
- package/dist/runtime/source-provenance.js.map +1 -0
- package/dist/runtime/target-bindings.d.ts +29 -0
- package/dist/runtime/target-bindings.d.ts.map +1 -0
- package/dist/runtime/target-bindings.js +170 -0
- package/dist/runtime/target-bindings.js.map +1 -0
- package/dist/tests/collection-parser.test.js +8 -1
- package/dist/tests/collection-parser.test.js.map +1 -1
- package/dist/tests/entity-graph.test.js +21 -0
- package/dist/tests/entity-graph.test.js.map +1 -1
- package/dist/tests/source-provenance.test.d.ts +2 -0
- package/dist/tests/source-provenance.test.d.ts.map +1 -0
- package/dist/tests/source-provenance.test.js +94 -0
- package/dist/tests/source-provenance.test.js.map +1 -0
- package/dist/tests/unified-inventory.test.d.ts +2 -0
- package/dist/tests/unified-inventory.test.d.ts.map +1 -0
- package/dist/tests/unified-inventory.test.js +122 -0
- package/dist/tests/unified-inventory.test.js.map +1 -0
- package/docs/DATA-TIER-CONTRACT.md +20 -2
- package/docs/EXPLORER-HOST-APIS.md +21 -5
- package/docs/MEMORIX-CATALOX-CONTRACTS.md +14 -2
- package/docs/MEMORIX-DATABASE-CONVENTIONS.md +10 -5
- package/package.json +2 -2
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { isLegacyCatalogId, legacyCatalogSourceRef, mongoPayloadSourceRef, runtimeProjectionSourceRef, } from "../runtime/source-provenance.js";
|
|
3
|
+
import { parseMemorixCollectionName } from "../data/collection-parser.js";
|
|
4
|
+
import { resolveMemorixRecordIdentity } from "../data/record-identity.js";
|
|
5
|
+
import { resolveMemorixTargetBindings } from "../runtime/target-bindings.js";
|
|
6
|
+
import { createMemorixRetrieval } from "../client/create-client.js";
|
|
7
|
+
describe("source provenance", () => {
|
|
8
|
+
it("creates runtime projection source refs", () => {
|
|
9
|
+
const source = runtimeProjectionSourceRef("buildMemorixUnifiedInventory", {
|
|
10
|
+
appId: "memorix",
|
|
11
|
+
sourceLens: "db-first",
|
|
12
|
+
});
|
|
13
|
+
expect(source.sourceClass).toBe("runtime-projection");
|
|
14
|
+
expect(source.canonicalStatus).toBe("derived");
|
|
15
|
+
expect(source.generatedBy).toBe("buildMemorixUnifiedInventory");
|
|
16
|
+
expect(source.generatedAt).toBeTruthy();
|
|
17
|
+
});
|
|
18
|
+
it("marks legacy catalogs as not used", () => {
|
|
19
|
+
expect(isLegacyCatalogId("memorix-entities")).toBe(true);
|
|
20
|
+
expect(isLegacyCatalogId("memorix-entity-descriptors")).toBe(false);
|
|
21
|
+
const source = legacyCatalogSourceRef("memorix-entities", "memorix");
|
|
22
|
+
expect(source.sourceClass).toBe("legacy-catalog-not-used");
|
|
23
|
+
expect(source.trustWarning).toContain("does not use");
|
|
24
|
+
});
|
|
25
|
+
it("creates mongo payload source refs with target and collection", () => {
|
|
26
|
+
const source = mongoPayloadSourceRef("entity", "memorix-entities", "assets-snapshots", {
|
|
27
|
+
objectType: "assets",
|
|
28
|
+
contentType: "snapshots",
|
|
29
|
+
});
|
|
30
|
+
expect(source.target).toBe("entity");
|
|
31
|
+
expect(source.databaseName).toBe("memorix-entities");
|
|
32
|
+
expect(source.collectionName).toBe("assets-snapshots");
|
|
33
|
+
expect(source.sourceClass).toBe("mongo-payload");
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
describe("parseMemorixCollectionName", () => {
|
|
37
|
+
it("uses last-dash rule and exposes objectType alias", () => {
|
|
38
|
+
const parsed = parseMemorixCollectionName("topology-cidr-graphs-snapshots");
|
|
39
|
+
expect(parsed.ok).toBe(true);
|
|
40
|
+
if (parsed.ok) {
|
|
41
|
+
expect(parsed.objectType).toBe("topology-cidr-graphs");
|
|
42
|
+
expect(parsed.objectName).toBe("topology-cidr-graphs");
|
|
43
|
+
expect(parsed.contentType).toBe("snapshots");
|
|
44
|
+
expect(parsed.parseRule).toBe("last-dash");
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
describe("resolveMemorixRecordIdentity", () => {
|
|
49
|
+
it("prefers recordId before target default", () => {
|
|
50
|
+
const identity = resolveMemorixRecordIdentity("knowledge", {
|
|
51
|
+
recordId: "k1",
|
|
52
|
+
knowledgeId: "k2",
|
|
53
|
+
});
|
|
54
|
+
expect(identity.recordId).toBe("k1");
|
|
55
|
+
expect(identity.source).toBe("recordId");
|
|
56
|
+
});
|
|
57
|
+
it("uses knowledgeId as target default", () => {
|
|
58
|
+
const identity = resolveMemorixRecordIdentity("knowledge", { knowledgeId: "k1" });
|
|
59
|
+
expect(identity.recordId).toBe("k1");
|
|
60
|
+
expect(identity.identityField).toBe("knowledgeId");
|
|
61
|
+
expect(identity.source).toBe("target-default");
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
describe("resolveMemorixTargetBindings", () => {
|
|
65
|
+
it("returns not-configured for missing knowledge DB env", async () => {
|
|
66
|
+
const client = createMemorixRetrieval({
|
|
67
|
+
appId: "memorix",
|
|
68
|
+
catalox: { getCatalogItem: async () => ({ outcome: "not_found" }) },
|
|
69
|
+
processEnv: {
|
|
70
|
+
MEMORIX_ENTITIES_DB: "memorix-entities",
|
|
71
|
+
MEMORIX_EVENTS_DB: "memorix-events",
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
const bindings = await resolveMemorixTargetBindings(client);
|
|
75
|
+
expect(bindings.knowledge.configured).toBe(false);
|
|
76
|
+
expect(bindings.knowledge.status).toBe("not-configured");
|
|
77
|
+
expect(bindings.knowledge.warnings.some((w) => w.code === "TARGET_DB_NOT_CONFIGURED")).toBe(true);
|
|
78
|
+
});
|
|
79
|
+
it("marks shared physical database across targets", async () => {
|
|
80
|
+
const client = createMemorixRetrieval({
|
|
81
|
+
appId: "memorix",
|
|
82
|
+
catalox: { getCatalogItem: async () => ({ outcome: "not_found" }) },
|
|
83
|
+
processEnv: {
|
|
84
|
+
MEMORIX_ENTITIES_DB: "memorix",
|
|
85
|
+
MEMORIX_EVENTS_DB: "memorix",
|
|
86
|
+
MEMORIX_KNOWLEDGE_DB: "memorix",
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
const bindings = await resolveMemorixTargetBindings(client);
|
|
90
|
+
expect(bindings.entity.databaseName).toBe("memorix");
|
|
91
|
+
expect(bindings.event.sharedPhysicalDatabaseWith).toEqual(["entity", "knowledge"]);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
//# sourceMappingURL=source-provenance.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source-provenance.test.js","sourceRoot":"","sources":["../../src/tests/source-provenance.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unified-inventory.test.d.ts","sourceRoot":"","sources":["../../src/tests/unified-inventory.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { createMemorixRetrieval } from "../client/create-client.js";
|
|
3
|
+
import { MEMORIX_ENTITY_DESCRIPTORS_CATALOG } from "../descriptors/catalog-ids.js";
|
|
4
|
+
import { buildMemorixUnifiedInventory } from "../explorer/unified-inventory.js";
|
|
5
|
+
import { assetsEntity, vulnerabilitiesEntity } from "./fixtures.js";
|
|
6
|
+
function mockInventoryCatalox() {
|
|
7
|
+
const entityItems = [
|
|
8
|
+
{ id: "assets", data: assetsEntity, title: "Assets" },
|
|
9
|
+
{ id: "vulnerabilities", data: vulnerabilitiesEntity, title: "Vulnerabilities" },
|
|
10
|
+
];
|
|
11
|
+
return {
|
|
12
|
+
getCatalogItem: vi.fn(async (_ctx, catalogId, itemId) => {
|
|
13
|
+
const map = {
|
|
14
|
+
assets: assetsEntity,
|
|
15
|
+
vulnerabilities: vulnerabilitiesEntity,
|
|
16
|
+
};
|
|
17
|
+
if (catalogId === MEMORIX_ENTITY_DESCRIPTORS_CATALOG && map[itemId]) {
|
|
18
|
+
return { outcome: "found", item: { data: map[itemId] } };
|
|
19
|
+
}
|
|
20
|
+
return { outcome: "not_found" };
|
|
21
|
+
}),
|
|
22
|
+
listCatalogItems: vi.fn(async () => ({
|
|
23
|
+
items: entityItems,
|
|
24
|
+
hasMore: false,
|
|
25
|
+
})),
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function mockInventoryXronox() {
|
|
29
|
+
const entityCollections = ["assets-snapshots", "orphan-bucket"];
|
|
30
|
+
const eventCollections = ["vulnerabilities-snapshots"];
|
|
31
|
+
const counts = {
|
|
32
|
+
"assets-snapshots": 5,
|
|
33
|
+
"orphan-bucket": 2,
|
|
34
|
+
"vulnerabilities-snapshots": 3,
|
|
35
|
+
};
|
|
36
|
+
return {
|
|
37
|
+
listCollections: vi.fn(async (params) => {
|
|
38
|
+
if (params.role === "memorix_events") {
|
|
39
|
+
return { database: "memorix-events", collections: eventCollections.map((name) => ({ name })) };
|
|
40
|
+
}
|
|
41
|
+
return { database: "memorix-entities", collections: entityCollections.map((name) => ({ name })) };
|
|
42
|
+
}),
|
|
43
|
+
countDocuments: vi.fn(async (params) => counts[params.source] ?? 0),
|
|
44
|
+
read: vi.fn(async () => [
|
|
45
|
+
{ entityId: "sample-1", name: "Sample One" },
|
|
46
|
+
{ entityId: "sample-2", name: "Sample Two" },
|
|
47
|
+
]),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function createInventoryClient(processEnv) {
|
|
51
|
+
return createMemorixRetrieval({
|
|
52
|
+
appId: "memorix",
|
|
53
|
+
catalox: mockInventoryCatalox(),
|
|
54
|
+
xronox: mockInventoryXronox(),
|
|
55
|
+
processEnv: {
|
|
56
|
+
MEMORIX_ENTITIES_DB: "memorix-entities",
|
|
57
|
+
MEMORIX_EVENTS_DB: "memorix-events",
|
|
58
|
+
...processEnv,
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
describe("buildMemorixUnifiedInventory", () => {
|
|
63
|
+
it("db_first_toggle_returns_db_first_inventory_not_same_graph", async () => {
|
|
64
|
+
const client = createInventoryClient();
|
|
65
|
+
const inventory = await buildMemorixUnifiedInventory(client, {
|
|
66
|
+
sourceLens: "db-first",
|
|
67
|
+
targets: ["entity", "event"],
|
|
68
|
+
});
|
|
69
|
+
expect(inventory.source.sourceClass).toBe("runtime-projection");
|
|
70
|
+
expect(inventory.sourceLens).toBe("db-first");
|
|
71
|
+
expect(inventory.rows.length).toBeGreaterThan(0);
|
|
72
|
+
expect(inventory.rows.some((row) => row.sources.some((s) => s.sourceClass === "mongo-payload"))).toBe(true);
|
|
73
|
+
const sorted = [...inventory.rows];
|
|
74
|
+
sorted.sort((a, b) => {
|
|
75
|
+
const target = a.target.localeCompare(b.target);
|
|
76
|
+
if (target !== 0)
|
|
77
|
+
return target;
|
|
78
|
+
const db = (a.databaseName ?? "").localeCompare(b.databaseName ?? "");
|
|
79
|
+
if (db !== 0)
|
|
80
|
+
return db;
|
|
81
|
+
return (a.collectionName ?? "").localeCompare(b.collectionName ?? "");
|
|
82
|
+
});
|
|
83
|
+
expect(inventory.rows.map((r) => r.rowId)).toEqual(sorted.map((r) => r.rowId));
|
|
84
|
+
});
|
|
85
|
+
it("target_filter_events_excludes_entity_rows", async () => {
|
|
86
|
+
const client = createInventoryClient();
|
|
87
|
+
const inventory = await buildMemorixUnifiedInventory(client, {
|
|
88
|
+
sourceLens: "db-first",
|
|
89
|
+
targets: ["event"],
|
|
90
|
+
});
|
|
91
|
+
expect(inventory.rows.every((row) => row.target === "event")).toBe(true);
|
|
92
|
+
expect(inventory.rows.some((row) => row.target === "entity")).toBe(false);
|
|
93
|
+
});
|
|
94
|
+
it("knowledge_empty_is_not_fatal", async () => {
|
|
95
|
+
const client = createInventoryClient();
|
|
96
|
+
const inventory = await buildMemorixUnifiedInventory(client, {
|
|
97
|
+
targets: ["entity", "event", "knowledge"],
|
|
98
|
+
});
|
|
99
|
+
expect(inventory.targetBindings.knowledge.status).toMatch(/not-configured|empty|connected/);
|
|
100
|
+
const knowledgeIssues = inventory.issues.filter((issue) => issue.target === "knowledge");
|
|
101
|
+
expect(knowledgeIssues.every((issue) => issue.severity !== "error")).toBe(true);
|
|
102
|
+
expect(inventory.warnings.some((w) => w.code === "TARGET_DB_NOT_CONFIGURED")).toBe(true);
|
|
103
|
+
});
|
|
104
|
+
it("includes source refs on every row", async () => {
|
|
105
|
+
const client = createInventoryClient();
|
|
106
|
+
const inventory = await buildMemorixUnifiedInventory(client);
|
|
107
|
+
for (const row of inventory.rows) {
|
|
108
|
+
expect(row.source.sourceClass).toBeTruthy();
|
|
109
|
+
expect(row.source.generatedAt).toBeTruthy();
|
|
110
|
+
expect(row.objectType ?? row.objectName).toBeDefined();
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
it("attach samples when includeSamples is true", async () => {
|
|
114
|
+
const client = createInventoryClient();
|
|
115
|
+
const inventory = await buildMemorixUnifiedInventory(client, {
|
|
116
|
+
includeSamples: true,
|
|
117
|
+
});
|
|
118
|
+
const withData = inventory.rows.filter((row) => (row.counts.exact ?? row.counts.estimated ?? 0) > 0 && row.collectionName);
|
|
119
|
+
expect(withData.some((row) => (row.samples?.length ?? 0) > 0)).toBe(true);
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
//# sourceMappingURL=unified-inventory.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unified-inventory.test.js","sourceRoot":"","sources":["../../src/tests/unified-inventory.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -44,6 +44,23 @@ Data reads and counts go through **Xronox** (`role: memorix_entities` / `memorix
|
|
|
44
44
|
|
|
45
45
|
---
|
|
46
46
|
|
|
47
|
+
## Source-aware runtime provenance
|
|
48
|
+
|
|
49
|
+
Retrieval is the source-aware read engine for Explorer. Every inventory row, health response, raw read, and list result can carry `MemorixRuntimeSourceRef` metadata.
|
|
50
|
+
|
|
51
|
+
| Export | Purpose |
|
|
52
|
+
|--------|---------|
|
|
53
|
+
| `MemorixRuntimeSourceRef` | Primary runtime provenance type (`sourceClass`, `canonicalStatus`, catalog/Mongo fields) |
|
|
54
|
+
| `RuntimeSourceAware<T>` | Wrapper `{ data, source, sources? }` |
|
|
55
|
+
| `MemorixTargetDbBinding` | Per-target DB status (`connected`, `empty`, `not-configured`, shared physical DB) |
|
|
56
|
+
| `resolveMemorixTargetBindings(client, options?)` | Resolve entity/event/knowledge bindings with warnings |
|
|
57
|
+
| `getSourceAwareMemorixRetrievalHealth(client, options?)` | Full source-aware health (Catalox catalogs, targets, inventory summary) |
|
|
58
|
+
| `legacyCatalogSourceRef` / `isLegacyCatalogId` | Guardrails for legacy catalogs not used in descriptor-driven reads |
|
|
59
|
+
|
|
60
|
+
List/item responses include optional `source`, `sources`, `descriptorRefs`, `target`, `databaseName`, and `collectionNames` (default: source refs enabled).
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
47
64
|
## Descriptor-driven reads (primary)
|
|
48
65
|
|
|
49
66
|
| Export | Purpose |
|
|
@@ -94,11 +111,12 @@ List descriptor `filters` with `operator` + `value` are **always applied**; requ
|
|
|
94
111
|
|
|
95
112
|
| Export | Purpose |
|
|
96
113
|
|--------|---------|
|
|
97
|
-
| `buildMemorixEntityGraph(client, options?)` | Discovery + counts + relation graph + optional
|
|
114
|
+
| `buildMemorixEntityGraph(client, options?)` | Discovery + counts + relation graph + optional `runtimeGraph` (source-aware nodes/edges), `nodes`, `inventory` |
|
|
98
115
|
| `buildMemorixEntitySlices(client, entityName)` | Per–content-type counts for drill-down (includes zero counts) |
|
|
99
116
|
| `buildMemorixCollectionInventory(client, options?)` | Legacy inventory (prefer `buildMemorixUnifiedInventory`) |
|
|
100
117
|
| `orphanNodesFromInventory(entries)` | Group inventory orphans for entity graph canvas |
|
|
101
|
-
| `getMemorixRetrievalHealth(client, options?)` |
|
|
118
|
+
| `getMemorixRetrievalHealth(client, options?)` | Legacy health shape (wraps source-aware health) |
|
|
119
|
+
| `getSourceAwareMemorixRetrievalHealth(client, options?)` | Source-aware Catalox + Mongo + inventory health |
|
|
102
120
|
| `countMemorixEntityContentTypeDocuments` | Count by entity + content type (descriptor-resolved collection) |
|
|
103
121
|
| `listMemorixEntityContentTypeDocuments` | Paginated raw documents (descriptor-resolved) |
|
|
104
122
|
| `getMemorixEntityContentTypeDocument` | Single document by record id |
|
|
@@ -19,12 +19,13 @@ Uses `createCataloxFromEnv` + `createCataloxAdapterFromBound` + `createMemorixRe
|
|
|
19
19
|
## Entity discovery
|
|
20
20
|
|
|
21
21
|
- `discoverMemorixEntities(client)` — lists `memorix-entity-descriptors` via Catalox only (`source: "catalox" | "none"`). No env entity list fallback.
|
|
22
|
-
- `buildMemorixEntityGraph(client, options?)` — discovery + per–content-type counts + relations. Options: `sourceLens`, `targets`, `includeInventory`, `includeOrphans`, `includeCounts`, `includeSlices`. Returns optional `nodes[]` and `
|
|
23
|
-
- `buildMemorixUnifiedInventory(client, options?)` — **preferred** inventory API for Explorer Inventory workspace. Options: `sourceLens` (`catalox-first` \| `db-first`), `targets`, `includeExactCounts`.
|
|
22
|
+
- `buildMemorixEntityGraph(client, options?)` — discovery + per–content-type counts + relations. Options: `sourceLens`, `targets`, `includeInventory`, `includeOrphans`, `includeCounts`, `includeSlices`, `includeSourceRefs`. Returns legacy `entities[]`, optional `nodes[]`, `inventory`, and **`runtimeGraph`** (`MemorixRuntimeGraph` with source refs on every node/edge).
|
|
23
|
+
- `buildMemorixUnifiedInventory(client, options?)` — **preferred** inventory API for Explorer Inventory workspace. Options: `sourceLens` (`catalox-first` \| `db-first`), `targets`, `includeExactCounts`, `includeSamples`.
|
|
24
24
|
- `parseMemorixCollectionName(name)` — last-dash parser for DB-first mode.
|
|
25
25
|
- `fetchMemorixRawCollectionRecords` / `fetchMemorixCollectionRecords` — open records from inventory rows.
|
|
26
|
-
- `fetchMemorixSlices` / `fetchMemorixSliceRecords` — slice descriptor execution.
|
|
27
|
-
- `getMemorixRetrievalHealth(client, { includeInventory })` — operational status for Explorer top bar.
|
|
26
|
+
- `fetchMemorixSlices` / `fetchMemorixSliceRecords` — slice descriptor execution with optional relation expansion per row.
|
|
27
|
+
- `getMemorixRetrievalHealth(client, { includeInventory })` — legacy operational status for Explorer top bar.
|
|
28
|
+
- `getSourceAwareMemorixRetrievalHealth(client, { includeInventory: true })` — source-aware health with target bindings and inventory summary.
|
|
28
29
|
- `buildMemorixCollectionInventory(client, options?)` — legacy inventory (still supported).
|
|
29
30
|
|
|
30
31
|
## Collection inventory
|
|
@@ -112,7 +113,22 @@ Supports `page`, `includeTotal`, `searchText`, and global `sort` (v1: in-memory
|
|
|
112
113
|
|
|
113
114
|
## Health
|
|
114
115
|
|
|
115
|
-
- `getMemorixRetrievalHealth(client)` —
|
|
116
|
+
- `getMemorixRetrievalHealth(client, { includeInventory })` — legacy health shape.
|
|
117
|
+
- `getSourceAwareMemorixRetrievalHealth(client, { includeInventory: true })` — Catalox catalog status, per-target DB bindings (entity/event/knowledge), optional inventory summary, all with `MemorixRuntimeSourceRef`.
|
|
118
|
+
|
|
119
|
+
## Source provenance (Explorer Source Card)
|
|
120
|
+
|
|
121
|
+
Every major retrieval result exposes runtime provenance:
|
|
122
|
+
|
|
123
|
+
| API | Primary `source.sourceClass` |
|
|
124
|
+
|-----|------------------------------|
|
|
125
|
+
| `buildMemorixUnifiedInventory` | `runtime-projection` |
|
|
126
|
+
| `buildMemorixEntityGraph` → `runtimeGraph` | `runtime-projection` |
|
|
127
|
+
| `fetchMemorixList` / `fetchMemorixItem` | `descriptor-backed-runtime-view` |
|
|
128
|
+
| `fetchMemorixRawCollectionRecords` | `raw-db-inspection` |
|
|
129
|
+
| `getSourceAwareMemorixRetrievalHealth` | `runtime-projection` |
|
|
130
|
+
|
|
131
|
+
Inventory rows include `source`, `sources[]`, `objectType`, `mappingStatus`, and optional `samples` when `includeSamples: true`.
|
|
116
132
|
|
|
117
133
|
## Catalox cleanliness
|
|
118
134
|
|
|
@@ -77,7 +77,19 @@ All Memorix descriptor catalogs live under this app. Peers must use the same `ap
|
|
|
77
77
|
|
|
78
78
|
Catalogs use **`sourceMode: "native"`** and **`catalogType: "memorix"`** in seed manifests. Do not introduce parallel catalog names (e.g. `memorix_entity_content_types`) for new work.
|
|
79
79
|
|
|
80
|
-
### 2.
|
|
80
|
+
### 2.4 Legacy catalogs (not used by retrieval)
|
|
81
|
+
|
|
82
|
+
Retrieval **does not** treat these as canonical descriptor sources for read-time composition:
|
|
83
|
+
|
|
84
|
+
| Catalog id | Status |
|
|
85
|
+
|------------|--------|
|
|
86
|
+
| `memorix-entities` | Legacy schema inference — not descriptor-driven retrieval |
|
|
87
|
+
| `memorix_entity_content_types` | Superseded by `contentTypes` on object type descriptors |
|
|
88
|
+
| `knowledge` | Knowledge/skills artifacts — not object type descriptors for `target: knowledge` |
|
|
89
|
+
|
|
90
|
+
If exposed in debug/source-inspector mode, mark with `sourceClass: "legacy-catalog-not-used"`. Normal list/item/inventory APIs load **`memorix-entity-descriptors`**, **`memorix-list-descriptors`**, and **`memorix-item-descriptors`** only.
|
|
91
|
+
|
|
92
|
+
### 2.5 Item shape in Catalox
|
|
81
93
|
|
|
82
94
|
Each catalog item is stored as:
|
|
83
95
|
|
|
@@ -97,7 +109,7 @@ Each catalog item is stored as:
|
|
|
97
109
|
- Descriptor payload lives in the item **`data`** body when read via Catalox APIs.
|
|
98
110
|
- **Seed apply note:** the Catalox seed CLI upserts `row.data` only, so `scripts/apply-seed-manifest.mjs` merges `scope` into the upsert `data` object. Hosts may see `scope` inside `data` until Catalox stores top-level scope natively; retrieval ignores unknown fields when validating descriptors.
|
|
99
111
|
|
|
100
|
-
### 2.
|
|
112
|
+
### 2.6 Expected Catalox client behavior
|
|
101
113
|
|
|
102
114
|
Peers that integrate with Catalox must support:
|
|
103
115
|
|
|
@@ -10,7 +10,7 @@ Memorix uses **three logical database roles**:
|
|
|
10
10
|
|------|---------|------------------------|
|
|
11
11
|
| **Entities** | Canonical entity records (vulnerabilities, assets, groups, …) | `memorix-entities` |
|
|
12
12
|
| **Events** | Event records derived from or linked to entities | `memorix-events` |
|
|
13
|
-
| **
|
|
13
|
+
| **Knowledge** | Knowledge-tier object payloads when configured | `memorix-knowledge` |
|
|
14
14
|
|
|
15
15
|
All three may live on the **same MongoDB cluster** (single `MONGO_URI`). They are separated by **database name**, not by connection string.
|
|
16
16
|
|
|
@@ -46,10 +46,15 @@ Packages resolve `memorix-entities`, `memorix-events`, collection names, and ent
|
|
|
46
46
|
|
|
47
47
|
Every Memorix record belongs to exactly one **target**:
|
|
48
48
|
|
|
49
|
-
| Target | Database | Typical use |
|
|
50
|
-
|
|
51
|
-
| `entity` | `memorix-entities` | Stable domain objects (vulnerability, asset, group, …) |
|
|
52
|
-
| `event` | `memorix-events` | Occurrences, detections, or timeline entries |
|
|
49
|
+
| Target | Database | Typical use | Identity field |
|
|
50
|
+
|--------|----------|-------------|----------------|
|
|
51
|
+
| `entity` | `memorix-entities` | Stable domain objects (vulnerability, asset, group, …) | `entityId` |
|
|
52
|
+
| `event` | `memorix-events` | Occurrences, detections, or timeline entries | `eventId` |
|
|
53
|
+
| `knowledge` | `memorix-knowledge` | Knowledge-tier objects when configured | `knowledgeId` |
|
|
54
|
+
|
|
55
|
+
Multiple logical targets may share one physical database (e.g. `MEMORIX_ENTITIES_DB=memorix`, `MEMORIX_EVENTS_DB=memorix`, `MEMORIX_KNOWLEDGE_DB=memorix`). Retrieval returns separate logical bindings and marks `sharedPhysicalDatabaseWith`.
|
|
56
|
+
|
|
57
|
+
An empty or unconfigured knowledge target is **non-fatal** — inventory and health return `status: "not-configured"` or `"empty"` with informational warnings.
|
|
53
58
|
|
|
54
59
|
Tools must declare which target they read or write. Do not mix entity and event documents in the same collection.
|
|
55
60
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@x12i/memorix-retrieval",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.2",
|
|
4
4
|
"description": "Read-side runtime data tier for Memorix: inventory, lists, items, slices, graph, and health",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@x12i/catalox": "^5.0.0",
|
|
35
35
|
"@x12i/helpers": "^1.7.0",
|
|
36
|
-
"@x12i/memorix-descriptors": "^1.
|
|
36
|
+
"@x12i/memorix-descriptors": "^1.5.0",
|
|
37
37
|
"@x12i/xronox": "^3.9.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|