@anvia/neo4j 1.0.2 → 1.0.4
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 +41 -35
- package/dist/chunk-PWE3ETSF.js +176 -0
- package/dist/chunk-PWE3ETSF.js.map +1 -0
- package/dist/chunk-QNHOT7P2.js +1486 -0
- package/dist/chunk-QNHOT7P2.js.map +1 -0
- package/dist/chunk-YLW4LCKJ.js +473 -0
- package/dist/chunk-YLW4LCKJ.js.map +1 -0
- package/dist/explore-RA53GFX2.js +8 -0
- package/dist/explore-RA53GFX2.js.map +1 -0
- package/dist/index.d.ts +9 -34
- package/dist/index.js +14 -2207
- package/dist/index.js.map +1 -1
- package/dist/retrieve-QRQHIVRO.js +8 -0
- package/dist/retrieve-QRQHIVRO.js.map +1 -0
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -2,23 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
Schema-first local GraphRAG for Neo4j 2026.01 and newer.
|
|
4
4
|
|
|
5
|
+
Provider-neutral schemas from `@anvia/graph` are accepted alongside the compatibility
|
|
6
|
+
`defineNeo4jGraphSchema()` API. Registered graphs expose `graph.retrieve()`, and the shared
|
|
7
|
+
`createGraphSearchTool()` factory gives Neo4j and Memgraph the same Agent tool API.
|
|
8
|
+
|
|
5
9
|
## Installation
|
|
6
10
|
|
|
7
11
|
```sh
|
|
8
|
-
pnpm add @anvia/neo4j @anvia/core
|
|
12
|
+
pnpm add @anvia/graph @anvia/neo4j @anvia/core
|
|
9
13
|
```
|
|
10
14
|
|
|
11
15
|
## Managed knowledge graph
|
|
12
16
|
|
|
13
17
|
```ts
|
|
14
18
|
import { Agent } from "@anvia/core/agent";
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
Neo4jClient,
|
|
18
|
-
createNeo4jGraphSearchTool,
|
|
19
|
-
defineNeo4jGraphSchema,
|
|
20
|
-
extractGraphFacts,
|
|
21
|
-
} from "@anvia/neo4j";
|
|
19
|
+
import { createGraphSearchTool, ingestGraphText } from "@anvia/graph";
|
|
20
|
+
import { Neo4jClient, defineNeo4jGraphSchema } from "@anvia/neo4j";
|
|
22
21
|
import { z } from "zod";
|
|
23
22
|
|
|
24
23
|
const schema = defineNeo4jGraphSchema({
|
|
@@ -71,34 +70,23 @@ const graph = client.managedKnowledgeGraph({
|
|
|
71
70
|
|
|
72
71
|
await graph.ensure({ indexTimeoutMs: 60_000 });
|
|
73
72
|
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
id: (entity) => entity.key,
|
|
86
|
-
content: (entity) => formatEntity(entity),
|
|
87
|
-
}),
|
|
88
|
-
]);
|
|
89
|
-
|
|
90
|
-
const write = await graph.replaceDocuments({
|
|
91
|
-
documents,
|
|
92
|
-
chunks: embeddedChunks.documents,
|
|
93
|
-
entities: embeddedEntities.documents,
|
|
94
|
-
relationships: facts.output.relationships,
|
|
95
|
-
mentions: facts.output.mentions,
|
|
73
|
+
const ingestion = await ingestGraphText({
|
|
74
|
+
graph,
|
|
75
|
+
document: { id: "incident-42", text },
|
|
76
|
+
extractionModel,
|
|
77
|
+
embeddingModel,
|
|
78
|
+
chunking: {
|
|
79
|
+
strategy: "recursive",
|
|
80
|
+
maxSize: 1_000,
|
|
81
|
+
overlap: 100,
|
|
82
|
+
separators: ["\n\n", "\n", " "],
|
|
83
|
+
},
|
|
96
84
|
conflict: "error",
|
|
97
85
|
orphanEntities: "delete",
|
|
98
86
|
});
|
|
99
|
-
console.log(write);
|
|
87
|
+
console.log(ingestion.write);
|
|
100
88
|
|
|
101
|
-
const searchGraph =
|
|
89
|
+
const searchGraph = createGraphSearchTool({
|
|
102
90
|
name: "search_support_graph",
|
|
103
91
|
description: "Search connected support incidents and products.",
|
|
104
92
|
graph,
|
|
@@ -123,9 +111,10 @@ const searchGraph = createNeo4jGraphSearchTool({
|
|
|
123
111
|
const agent = new Agent({ id: "support", model: chatModel, tools: [searchGraph] });
|
|
124
112
|
```
|
|
125
113
|
|
|
126
|
-
The application owns file discovery, reading,
|
|
127
|
-
|
|
128
|
-
`
|
|
114
|
+
The application owns file discovery, reading, model loading, retry policy, and Agent lifecycle.
|
|
115
|
+
`ingestGraphText()` and `ingestGraphDocuments()` provide the convenient end-to-end path. Advanced
|
|
116
|
+
callers can compose `prepareGraphDocuments()`, `extractGraphFacts()`, `embedDocuments()`, and
|
|
117
|
+
`replaceDocuments()` directly when they need custom orchestration.
|
|
129
118
|
|
|
130
119
|
Graph property schemas must use `z.strictObject()` and must not coerce, default, transform,
|
|
131
120
|
preprocess, catch, trim, or otherwise overwrite values. This keeps extraction, comparison, and
|
|
@@ -181,6 +170,23 @@ const graph = client.knowledgeGraph({
|
|
|
181
170
|
await graph.validate();
|
|
182
171
|
```
|
|
183
172
|
|
|
173
|
+
## Graph explorer
|
|
174
|
+
|
|
175
|
+
Managed and existing graph registrations implement the shared `GraphExplorer` contract:
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
const overview = await graph.explore({ mode: "overview", maxNodes: 100 });
|
|
179
|
+
const neighborhood = await graph.explore({
|
|
180
|
+
mode: "expand",
|
|
181
|
+
nodeIds: [overview.nodes[0]!.id],
|
|
182
|
+
maxDepth: 1,
|
|
183
|
+
});
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
The explorer returns Neo4j element IDs as opaque strings, limits every query, and omits embeddings
|
|
187
|
+
and other `__anvia_*` properties. Use stable graph identity properties for application logic; use the
|
|
188
|
+
opaque IDs only to expand the current view.
|
|
189
|
+
|
|
184
190
|
Existing registrations are read-only and expose no provisioning or write methods. Use
|
|
185
191
|
`client.nativeDriver()` for application-owned Cypher.
|
|
186
192
|
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Neo4jKnowledgeGraphBase,
|
|
3
|
+
parseNeo4jProperties
|
|
4
|
+
} from "./chunk-QNHOT7P2.js";
|
|
5
|
+
|
|
6
|
+
// src/explore.ts
|
|
7
|
+
import {
|
|
8
|
+
resolveGraphExploreOptions
|
|
9
|
+
} from "@anvia/graph";
|
|
10
|
+
import { int } from "neo4j-driver";
|
|
11
|
+
async function exploreGraph(graph, options) {
|
|
12
|
+
if (!(graph instanceof Neo4jKnowledgeGraphBase)) {
|
|
13
|
+
throw new TypeError("exploreGraph requires a Neo4j knowledge graph registration.");
|
|
14
|
+
}
|
|
15
|
+
const resolved = resolveGraphExploreOptions(graph.schema, options);
|
|
16
|
+
const records = resolved.mode === "overview" ? await overviewNodes(graph, resolved) : await expandedNodes(graph, resolved);
|
|
17
|
+
const nodes = uniqueNodes(records.map((record) => nodeFromRecord(record, graph.schema)));
|
|
18
|
+
const visibleNodes = nodes.slice(0, resolved.maxNodes);
|
|
19
|
+
const relationships = await relationshipsBetween(
|
|
20
|
+
graph,
|
|
21
|
+
visibleNodes.map((node) => node.id),
|
|
22
|
+
resolved.relationships,
|
|
23
|
+
resolved.maxRelationships,
|
|
24
|
+
resolved.abortSignal
|
|
25
|
+
);
|
|
26
|
+
return {
|
|
27
|
+
nodes: visibleNodes,
|
|
28
|
+
relationships: relationships.slice(0, resolved.maxRelationships),
|
|
29
|
+
truncated: {
|
|
30
|
+
nodes: records.length > resolved.maxNodes || nodes.length > resolved.maxNodes,
|
|
31
|
+
relationships: relationships.length > resolved.maxRelationships
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
async function overviewNodes(graph, options) {
|
|
36
|
+
const result = await graph.query(
|
|
37
|
+
`MATCH (node)
|
|
38
|
+
WHERE any(type IN labels(node) WHERE type IN $nodeTypes)
|
|
39
|
+
RETURN elementId(node) AS id, labels(node) AS labels, properties(node) AS properties
|
|
40
|
+
ORDER BY elementId(node)
|
|
41
|
+
LIMIT $nodeLimit`,
|
|
42
|
+
{ nodeTypes: options.nodeTypes, nodeLimit: int(options.maxNodes + 1) },
|
|
43
|
+
options.abortSignal
|
|
44
|
+
);
|
|
45
|
+
return result.records;
|
|
46
|
+
}
|
|
47
|
+
async function expandedNodes(graph, options) {
|
|
48
|
+
const roots = await graph.query(
|
|
49
|
+
`MATCH (node)
|
|
50
|
+
WHERE elementId(node) IN $nodeIds
|
|
51
|
+
AND any(type IN labels(node) WHERE type IN $nodeTypes)
|
|
52
|
+
RETURN elementId(node) AS id, labels(node) AS labels, properties(node) AS properties`,
|
|
53
|
+
{ nodeIds: options.nodeIds, nodeTypes: options.nodeTypes },
|
|
54
|
+
options.abortSignal
|
|
55
|
+
);
|
|
56
|
+
if (options.relationships.length === 0) return roots.records;
|
|
57
|
+
const remainingNodeLimit = options.maxNodes + 1 - roots.records.length;
|
|
58
|
+
if (remainingNodeLimit <= 0) return roots.records;
|
|
59
|
+
const pattern = traversalPattern(options.direction, options.maxDepth);
|
|
60
|
+
const neighbors = await graph.query(
|
|
61
|
+
`MATCH (root) WHERE elementId(root) IN $nodeIds
|
|
62
|
+
MATCH path = ${pattern}
|
|
63
|
+
WHERE all(rel IN relationships(path) WHERE type(rel) IN $relationshipTypes)
|
|
64
|
+
AND any(type IN labels(node) WHERE type IN $nodeTypes)
|
|
65
|
+
RETURN elementId(node) AS id, labels(node) AS labels, properties(node) AS properties
|
|
66
|
+
LIMIT $nodeLimit`,
|
|
67
|
+
{
|
|
68
|
+
nodeIds: options.nodeIds,
|
|
69
|
+
nodeTypes: options.nodeTypes,
|
|
70
|
+
relationshipTypes: options.relationships,
|
|
71
|
+
nodeLimit: int(remainingNodeLimit)
|
|
72
|
+
},
|
|
73
|
+
options.abortSignal
|
|
74
|
+
);
|
|
75
|
+
return [...roots.records, ...neighbors.records];
|
|
76
|
+
}
|
|
77
|
+
async function relationshipsBetween(graph, nodeIds, relationshipTypes, maxRelationships, abortSignal) {
|
|
78
|
+
if (nodeIds.length === 0 || relationshipTypes.length === 0) return [];
|
|
79
|
+
const result = await graph.query(
|
|
80
|
+
`MATCH (from)-[relationship]->(to)
|
|
81
|
+
WHERE elementId(from) IN $nodeIds
|
|
82
|
+
AND elementId(to) IN $nodeIds
|
|
83
|
+
AND type(relationship) IN $relationshipTypes
|
|
84
|
+
RETURN elementId(relationship) AS id,
|
|
85
|
+
type(relationship) AS type,
|
|
86
|
+
elementId(from) AS source,
|
|
87
|
+
elementId(to) AS target,
|
|
88
|
+
properties(relationship) AS properties
|
|
89
|
+
ORDER BY elementId(relationship)
|
|
90
|
+
LIMIT $relationshipLimit`,
|
|
91
|
+
{
|
|
92
|
+
nodeIds,
|
|
93
|
+
relationshipTypes,
|
|
94
|
+
relationshipLimit: int(maxRelationships + 1)
|
|
95
|
+
},
|
|
96
|
+
abortSignal
|
|
97
|
+
);
|
|
98
|
+
return result.records.map(relationshipFromRecord);
|
|
99
|
+
}
|
|
100
|
+
function nodeFromRecord(record, schema) {
|
|
101
|
+
const id = stringValue(record.get("id"), "Neo4j explorer node id");
|
|
102
|
+
const labels = stringArray(record.get("labels"), "Neo4j explorer node labels");
|
|
103
|
+
const raw = objectValue(record.get("properties"), "Neo4j explorer node properties");
|
|
104
|
+
const type = labels.find((label) => label in schema.nodes);
|
|
105
|
+
if (type === void 0) throw new TypeError("Neo4j explorer node has no registered type.");
|
|
106
|
+
const properties = applicationProperties(raw, "Neo4j explorer node properties");
|
|
107
|
+
const node = {
|
|
108
|
+
id,
|
|
109
|
+
type,
|
|
110
|
+
identity: identityProperties(schema, type, properties),
|
|
111
|
+
properties
|
|
112
|
+
};
|
|
113
|
+
const key = raw.__anvia_key;
|
|
114
|
+
if (typeof key === "string") node.key = key;
|
|
115
|
+
return node;
|
|
116
|
+
}
|
|
117
|
+
function relationshipFromRecord(record) {
|
|
118
|
+
const raw = objectValue(record.get("properties"), "Neo4j explorer relationship properties");
|
|
119
|
+
const relationship = {
|
|
120
|
+
id: stringValue(record.get("id"), "Neo4j explorer relationship id"),
|
|
121
|
+
type: stringValue(record.get("type"), "Neo4j explorer relationship type"),
|
|
122
|
+
from: stringValue(record.get("source"), "Neo4j explorer relationship source"),
|
|
123
|
+
to: stringValue(record.get("target"), "Neo4j explorer relationship target"),
|
|
124
|
+
properties: applicationProperties(raw, "Neo4j explorer relationship properties")
|
|
125
|
+
};
|
|
126
|
+
const key = raw.__anvia_key;
|
|
127
|
+
if (typeof key === "string") relationship.key = key;
|
|
128
|
+
return relationship;
|
|
129
|
+
}
|
|
130
|
+
function identityProperties(schema, type, properties) {
|
|
131
|
+
const identity = {};
|
|
132
|
+
const definition = schema.nodes[type];
|
|
133
|
+
if (definition === void 0) return identity;
|
|
134
|
+
for (const property of definition.identity) {
|
|
135
|
+
const value = properties[property];
|
|
136
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
137
|
+
identity[property] = value;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return identity;
|
|
141
|
+
}
|
|
142
|
+
function applicationProperties(value, label) {
|
|
143
|
+
return parseNeo4jProperties(
|
|
144
|
+
Object.fromEntries(Object.entries(value).filter(([key]) => !key.startsWith("__anvia_"))),
|
|
145
|
+
label
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
function uniqueNodes(nodes) {
|
|
149
|
+
return [...new Map(nodes.map((node) => [node.id, node])).values()];
|
|
150
|
+
}
|
|
151
|
+
function traversalPattern(direction, maxDepth) {
|
|
152
|
+
if (direction === "outgoing") return `(root)-[*1..${maxDepth}]->(node)`;
|
|
153
|
+
if (direction === "incoming") return `(root)<-[*1..${maxDepth}]-(node)`;
|
|
154
|
+
return `(root)-[*1..${maxDepth}]-(node)`;
|
|
155
|
+
}
|
|
156
|
+
function stringValue(value, label) {
|
|
157
|
+
if (typeof value !== "string") throw new TypeError(`${label} must be a string.`);
|
|
158
|
+
return value;
|
|
159
|
+
}
|
|
160
|
+
function stringArray(value, label) {
|
|
161
|
+
if (!Array.isArray(value) || !value.every((item) => typeof item === "string")) {
|
|
162
|
+
throw new TypeError(`${label} must be a string array.`);
|
|
163
|
+
}
|
|
164
|
+
return value;
|
|
165
|
+
}
|
|
166
|
+
function objectValue(value, label) {
|
|
167
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
168
|
+
throw new TypeError(`${label} must be an object.`);
|
|
169
|
+
}
|
|
170
|
+
return value;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export {
|
|
174
|
+
exploreGraph
|
|
175
|
+
};
|
|
176
|
+
//# sourceMappingURL=chunk-PWE3ETSF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/explore.ts"],"sourcesContent":["import {\n resolveGraphExploreOptions,\n type GraphExploreNode,\n type GraphExploreOptions,\n type GraphExploreRelationship,\n type GraphExploreResult,\n type ResolvedGraphExploreExpandOptions,\n} from \"@anvia/graph\";\nimport { int, type Record as Neo4jRecord } from \"neo4j-driver\";\nimport { Neo4jKnowledgeGraphBase } from \"./graph.js\";\nimport { parseNeo4jProperties } from \"./schema.js\";\nimport type { Neo4jGraphSchema, Neo4jNodeIdentity } from \"./types.js\";\n\nexport async function exploreGraph<Schema extends Neo4jGraphSchema>(\n graph: Neo4jKnowledgeGraphBase<Schema>,\n options: GraphExploreOptions<Schema>,\n): Promise<GraphExploreResult> {\n if (!(graph instanceof Neo4jKnowledgeGraphBase)) {\n throw new TypeError(\"exploreGraph requires a Neo4j knowledge graph registration.\");\n }\n const resolved = resolveGraphExploreOptions(graph.schema, options);\n const records =\n resolved.mode === \"overview\"\n ? await overviewNodes(graph, resolved)\n : await expandedNodes(graph, resolved);\n const nodes = uniqueNodes(records.map((record) => nodeFromRecord(record, graph.schema)));\n const visibleNodes = nodes.slice(0, resolved.maxNodes);\n const relationships = await relationshipsBetween(\n graph,\n visibleNodes.map((node) => node.id),\n resolved.relationships,\n resolved.maxRelationships,\n resolved.abortSignal,\n );\n return {\n nodes: visibleNodes,\n relationships: relationships.slice(0, resolved.maxRelationships),\n truncated: {\n nodes: records.length > resolved.maxNodes || nodes.length > resolved.maxNodes,\n relationships: relationships.length > resolved.maxRelationships,\n },\n };\n}\n\nasync function overviewNodes(\n graph: Neo4jKnowledgeGraphBase,\n options: ReturnType<typeof resolveGraphExploreOptions> & { mode: \"overview\" },\n): Promise<readonly Neo4jRecord[]> {\n const result = await graph.query(\n `MATCH (node)\nWHERE any(type IN labels(node) WHERE type IN $nodeTypes)\nRETURN elementId(node) AS id, labels(node) AS labels, properties(node) AS properties\nORDER BY elementId(node)\nLIMIT $nodeLimit`,\n { nodeTypes: options.nodeTypes, nodeLimit: int(options.maxNodes + 1) },\n options.abortSignal,\n );\n return result.records;\n}\n\nasync function expandedNodes(\n graph: Neo4jKnowledgeGraphBase,\n options: ResolvedGraphExploreExpandOptions,\n): Promise<readonly Neo4jRecord[]> {\n const roots = await graph.query(\n `MATCH (node)\nWHERE elementId(node) IN $nodeIds\n AND any(type IN labels(node) WHERE type IN $nodeTypes)\nRETURN elementId(node) AS id, labels(node) AS labels, properties(node) AS properties`,\n { nodeIds: options.nodeIds, nodeTypes: options.nodeTypes },\n options.abortSignal,\n );\n if (options.relationships.length === 0) return roots.records;\n const remainingNodeLimit = options.maxNodes + 1 - roots.records.length;\n if (remainingNodeLimit <= 0) return roots.records;\n const pattern = traversalPattern(options.direction, options.maxDepth);\n const neighbors = await graph.query(\n `MATCH (root) WHERE elementId(root) IN $nodeIds\nMATCH path = ${pattern}\nWHERE all(rel IN relationships(path) WHERE type(rel) IN $relationshipTypes)\n AND any(type IN labels(node) WHERE type IN $nodeTypes)\nRETURN elementId(node) AS id, labels(node) AS labels, properties(node) AS properties\nLIMIT $nodeLimit`,\n {\n nodeIds: options.nodeIds,\n nodeTypes: options.nodeTypes,\n relationshipTypes: options.relationships,\n nodeLimit: int(remainingNodeLimit),\n },\n options.abortSignal,\n );\n return [...roots.records, ...neighbors.records];\n}\n\nasync function relationshipsBetween(\n graph: Neo4jKnowledgeGraphBase,\n nodeIds: readonly string[],\n relationshipTypes: readonly string[],\n maxRelationships: number,\n abortSignal?: AbortSignal,\n): Promise<GraphExploreRelationship[]> {\n if (nodeIds.length === 0 || relationshipTypes.length === 0) return [];\n const result = await graph.query(\n `MATCH (from)-[relationship]->(to)\nWHERE elementId(from) IN $nodeIds\n AND elementId(to) IN $nodeIds\n AND type(relationship) IN $relationshipTypes\nRETURN elementId(relationship) AS id,\n type(relationship) AS type,\n elementId(from) AS source,\n elementId(to) AS target,\n properties(relationship) AS properties\nORDER BY elementId(relationship)\nLIMIT $relationshipLimit`,\n {\n nodeIds,\n relationshipTypes,\n relationshipLimit: int(maxRelationships + 1),\n },\n abortSignal,\n );\n return result.records.map(relationshipFromRecord);\n}\n\nfunction nodeFromRecord(record: Neo4jRecord, schema: Neo4jGraphSchema): GraphExploreNode {\n const id = stringValue(record.get(\"id\"), \"Neo4j explorer node id\");\n const labels = stringArray(record.get(\"labels\"), \"Neo4j explorer node labels\");\n const raw = objectValue(record.get(\"properties\"), \"Neo4j explorer node properties\");\n const type = labels.find((label) => label in schema.nodes);\n if (type === undefined) throw new TypeError(\"Neo4j explorer node has no registered type.\");\n const properties = applicationProperties(raw, \"Neo4j explorer node properties\");\n const node: {\n id: string;\n key?: string | undefined;\n type: string;\n identity: Neo4jNodeIdentity;\n properties: typeof properties;\n } = {\n id,\n type,\n identity: identityProperties(schema, type, properties),\n properties,\n };\n const key = raw.__anvia_key;\n if (typeof key === \"string\") node.key = key;\n return node;\n}\n\nfunction relationshipFromRecord(record: Neo4jRecord): GraphExploreRelationship {\n const raw = objectValue(record.get(\"properties\"), \"Neo4j explorer relationship properties\");\n const relationship: {\n id: string;\n key?: string | undefined;\n type: string;\n from: string;\n to: string;\n properties: ReturnType<typeof applicationProperties>;\n } = {\n id: stringValue(record.get(\"id\"), \"Neo4j explorer relationship id\"),\n type: stringValue(record.get(\"type\"), \"Neo4j explorer relationship type\"),\n from: stringValue(record.get(\"source\"), \"Neo4j explorer relationship source\"),\n to: stringValue(record.get(\"target\"), \"Neo4j explorer relationship target\"),\n properties: applicationProperties(raw, \"Neo4j explorer relationship properties\"),\n };\n const key = raw.__anvia_key;\n if (typeof key === \"string\") relationship.key = key;\n return relationship;\n}\n\nfunction identityProperties(\n schema: Neo4jGraphSchema,\n type: string,\n properties: ReturnType<typeof applicationProperties>,\n): Neo4jNodeIdentity {\n const identity: Record<string, string | number | boolean> = {};\n const definition = schema.nodes[type];\n if (definition === undefined) return identity;\n for (const property of definition.identity) {\n const value = properties[property];\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n identity[property] = value;\n }\n }\n return identity;\n}\n\nfunction applicationProperties(value: Record<string, unknown>, label: string) {\n return parseNeo4jProperties(\n Object.fromEntries(Object.entries(value).filter(([key]) => !key.startsWith(\"__anvia_\"))),\n label,\n );\n}\n\nfunction uniqueNodes(nodes: readonly GraphExploreNode[]): GraphExploreNode[] {\n return [...new Map(nodes.map((node) => [node.id, node])).values()];\n}\n\nfunction traversalPattern(direction: \"outgoing\" | \"incoming\" | \"both\", maxDepth: number): string {\n if (direction === \"outgoing\") return `(root)-[*1..${maxDepth}]->(node)`;\n if (direction === \"incoming\") return `(root)<-[*1..${maxDepth}]-(node)`;\n return `(root)-[*1..${maxDepth}]-(node)`;\n}\n\nfunction stringValue(value: unknown, label: string): string {\n if (typeof value !== \"string\") throw new TypeError(`${label} must be a string.`);\n return value;\n}\n\nfunction stringArray(value: unknown, label: string): string[] {\n if (!Array.isArray(value) || !value.every((item) => typeof item === \"string\")) {\n throw new TypeError(`${label} must be a string array.`);\n }\n return value;\n}\n\nfunction objectValue(value: unknown, label: string): Record<string, unknown> {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n throw new TypeError(`${label} must be an object.`);\n }\n return value as Record<string, unknown>;\n}\n"],"mappings":"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","names":[]}
|