@ruvector/graph-node 0.1.15
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 +106 -0
- package/index.d.ts +370 -0
- package/index.js +322 -0
- package/package.json +67 -0
package/README.md
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# @ruvector/graph-node
|
|
2
|
+
|
|
3
|
+
Native Node.js bindings for RuVector Graph Database with hypergraph support, Cypher queries, and persistence. **10x faster than WASM**.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Native Performance**: Direct NAPI-RS bindings - no WASM overhead
|
|
8
|
+
- **Hypergraph Support**: Multi-node relationships with vector embeddings
|
|
9
|
+
- **Cypher Queries**: Neo4j-compatible query language
|
|
10
|
+
- **Persistence**: ACID-compliant storage with redb backend
|
|
11
|
+
- **Vector Similarity Search**: Fast k-NN search on embeddings
|
|
12
|
+
- **Graph Traversal**: k-hop neighbor discovery
|
|
13
|
+
- **Transactions**: Full ACID support with begin/commit/rollback
|
|
14
|
+
- **Batch Operations**: High-throughput bulk inserts (131K+ ops/sec)
|
|
15
|
+
- **Zero-Copy**: Efficient Float32Array handling
|
|
16
|
+
- **TypeScript**: Full type definitions included
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install @ruvector/graph-node
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Quick Start
|
|
25
|
+
|
|
26
|
+
```javascript
|
|
27
|
+
const { GraphDatabase } = require('@ruvector/graph-node');
|
|
28
|
+
|
|
29
|
+
// Create an in-memory database
|
|
30
|
+
const db = new GraphDatabase({
|
|
31
|
+
distanceMetric: 'Cosine',
|
|
32
|
+
dimensions: 384
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// Or create a persistent database
|
|
36
|
+
const persistentDb = new GraphDatabase({
|
|
37
|
+
distanceMetric: 'Cosine',
|
|
38
|
+
dimensions: 384,
|
|
39
|
+
storagePath: './my-graph.db'
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// Or open an existing database
|
|
43
|
+
const existingDb = GraphDatabase.open('./my-graph.db');
|
|
44
|
+
|
|
45
|
+
// Create nodes
|
|
46
|
+
await db.createNode({
|
|
47
|
+
id: 'alice',
|
|
48
|
+
embedding: new Float32Array([1.0, 0.0, 0.0, /* ... */]),
|
|
49
|
+
labels: ['Person', 'Employee'],
|
|
50
|
+
properties: { name: 'Alice', age: '30' }
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Create edges
|
|
54
|
+
await db.createEdge({
|
|
55
|
+
from: 'alice',
|
|
56
|
+
to: 'bob',
|
|
57
|
+
description: 'KNOWS',
|
|
58
|
+
embedding: new Float32Array([0.5, 0.5, 0.0, /* ... */]),
|
|
59
|
+
confidence: 0.95
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// Create hyperedges (multi-node relationships)
|
|
63
|
+
await db.createHyperedge({
|
|
64
|
+
nodes: ['alice', 'bob', 'charlie'],
|
|
65
|
+
description: 'COLLABORATED_ON_PROJECT',
|
|
66
|
+
embedding: new Float32Array([0.33, 0.33, 0.33, /* ... */]),
|
|
67
|
+
confidence: 0.85
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// Query with Cypher
|
|
71
|
+
const results = await db.query('MATCH (n:Person) RETURN n');
|
|
72
|
+
|
|
73
|
+
// Vector similarity search
|
|
74
|
+
const similar = await db.searchHyperedges({
|
|
75
|
+
embedding: new Float32Array([0.3, 0.3, 0.3, /* ... */]),
|
|
76
|
+
k: 10
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// Get statistics
|
|
80
|
+
const stats = await db.stats();
|
|
81
|
+
console.log(\`Nodes: \${stats.totalNodes}, Edges: \${stats.totalEdges}\`);
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Benchmarks
|
|
85
|
+
|
|
86
|
+
| Operation | Throughput | Latency |
|
|
87
|
+
|-----------|------------|---------|
|
|
88
|
+
| Node Creation | 9.17K ops/sec | 109ms |
|
|
89
|
+
| Batch Node Creation | 131.10K ops/sec | 7.63ms |
|
|
90
|
+
| Edge Creation | 9.30K ops/sec | 107ms |
|
|
91
|
+
| Vector Search (k=10) | 2.35K ops/sec | 42ms |
|
|
92
|
+
| k-hop Traversal | 10.28K ops/sec | 9.73ms |
|
|
93
|
+
|
|
94
|
+
## Platform Support
|
|
95
|
+
|
|
96
|
+
| Platform | Architecture | Status |
|
|
97
|
+
|----------|--------------|--------|
|
|
98
|
+
| Linux | x64 (glibc) | Supported |
|
|
99
|
+
| Linux | arm64 (glibc) | Supported |
|
|
100
|
+
| macOS | x64 | Supported |
|
|
101
|
+
| macOS | arm64 (M1/M2) | Supported |
|
|
102
|
+
| Windows | x64 | Supported |
|
|
103
|
+
|
|
104
|
+
## License
|
|
105
|
+
|
|
106
|
+
MIT
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
|
|
4
|
+
/* auto-generated by NAPI-RS */
|
|
5
|
+
|
|
6
|
+
/** Distance metric for similarity calculation */
|
|
7
|
+
export const enum JsDistanceMetric {
|
|
8
|
+
Euclidean = 'Euclidean',
|
|
9
|
+
Cosine = 'Cosine',
|
|
10
|
+
DotProduct = 'DotProduct',
|
|
11
|
+
Manhattan = 'Manhattan'
|
|
12
|
+
}
|
|
13
|
+
/** Graph database configuration options */
|
|
14
|
+
export interface JsGraphOptions {
|
|
15
|
+
/** Distance metric for embeddings */
|
|
16
|
+
distanceMetric?: JsDistanceMetric
|
|
17
|
+
/** Vector dimensions */
|
|
18
|
+
dimensions?: number
|
|
19
|
+
/** Storage path */
|
|
20
|
+
storagePath?: string
|
|
21
|
+
}
|
|
22
|
+
/** Node in the graph */
|
|
23
|
+
export interface JsNode {
|
|
24
|
+
/** Node ID */
|
|
25
|
+
id: string
|
|
26
|
+
/** Node embedding */
|
|
27
|
+
embedding: Float32Array
|
|
28
|
+
/** Node labels (e.g., ["Person", "Employee"]) */
|
|
29
|
+
labels?: Array<string>
|
|
30
|
+
/** Optional properties */
|
|
31
|
+
properties?: Record<string, string>
|
|
32
|
+
}
|
|
33
|
+
/** Edge between two nodes */
|
|
34
|
+
export interface JsEdge {
|
|
35
|
+
/** Source node ID */
|
|
36
|
+
from: string
|
|
37
|
+
/** Target node ID */
|
|
38
|
+
to: string
|
|
39
|
+
/** Edge description/label */
|
|
40
|
+
description: string
|
|
41
|
+
/** Edge embedding */
|
|
42
|
+
embedding: Float32Array
|
|
43
|
+
/** Confidence score (0.0-1.0) */
|
|
44
|
+
confidence?: number
|
|
45
|
+
/** Optional metadata */
|
|
46
|
+
metadata?: Record<string, string>
|
|
47
|
+
}
|
|
48
|
+
/** Hyperedge connecting multiple nodes */
|
|
49
|
+
export interface JsHyperedge {
|
|
50
|
+
/** Node IDs connected by this hyperedge */
|
|
51
|
+
nodes: Array<string>
|
|
52
|
+
/** Natural language description of the relationship */
|
|
53
|
+
description: string
|
|
54
|
+
/** Embedding of the hyperedge description */
|
|
55
|
+
embedding: Float32Array
|
|
56
|
+
/** Confidence weight (0.0-1.0) */
|
|
57
|
+
confidence?: number
|
|
58
|
+
/** Optional metadata */
|
|
59
|
+
metadata?: Record<string, string>
|
|
60
|
+
}
|
|
61
|
+
/** Query for searching hyperedges */
|
|
62
|
+
export interface JsHyperedgeQuery {
|
|
63
|
+
/** Query embedding */
|
|
64
|
+
embedding: Float32Array
|
|
65
|
+
/** Number of results to return */
|
|
66
|
+
k: number
|
|
67
|
+
}
|
|
68
|
+
/** Hyperedge search result */
|
|
69
|
+
export interface JsHyperedgeResult {
|
|
70
|
+
/** Hyperedge ID */
|
|
71
|
+
id: string
|
|
72
|
+
/** Similarity score */
|
|
73
|
+
score: number
|
|
74
|
+
}
|
|
75
|
+
/** Node result from query (without embedding) */
|
|
76
|
+
export interface JsNodeResult {
|
|
77
|
+
/** Node ID */
|
|
78
|
+
id: string
|
|
79
|
+
/** Node labels */
|
|
80
|
+
labels: Array<string>
|
|
81
|
+
/** Node properties */
|
|
82
|
+
properties: Record<string, string>
|
|
83
|
+
}
|
|
84
|
+
/** Edge result from query */
|
|
85
|
+
export interface JsEdgeResult {
|
|
86
|
+
/** Edge ID */
|
|
87
|
+
id: string
|
|
88
|
+
/** Source node ID */
|
|
89
|
+
from: string
|
|
90
|
+
/** Target node ID */
|
|
91
|
+
to: string
|
|
92
|
+
/** Edge type/label */
|
|
93
|
+
edgeType: string
|
|
94
|
+
/** Edge properties */
|
|
95
|
+
properties: Record<string, string>
|
|
96
|
+
}
|
|
97
|
+
/** Query result */
|
|
98
|
+
export interface JsQueryResult {
|
|
99
|
+
/** Nodes returned by the query */
|
|
100
|
+
nodes: Array<JsNodeResult>
|
|
101
|
+
/** Edges returned by the query */
|
|
102
|
+
edges: Array<JsEdgeResult>
|
|
103
|
+
/** Optional statistics */
|
|
104
|
+
stats?: JsGraphStats
|
|
105
|
+
}
|
|
106
|
+
/** Graph statistics */
|
|
107
|
+
export interface JsGraphStats {
|
|
108
|
+
/** Total number of nodes */
|
|
109
|
+
totalNodes: number
|
|
110
|
+
/** Total number of edges */
|
|
111
|
+
totalEdges: number
|
|
112
|
+
/** Average node degree */
|
|
113
|
+
avgDegree: number
|
|
114
|
+
}
|
|
115
|
+
/** Batch insert data */
|
|
116
|
+
export interface JsBatchInsert {
|
|
117
|
+
/** Nodes to insert */
|
|
118
|
+
nodes: Array<JsNode>
|
|
119
|
+
/** Edges to insert */
|
|
120
|
+
edges: Array<JsEdge>
|
|
121
|
+
}
|
|
122
|
+
/** Batch insert result */
|
|
123
|
+
export interface JsBatchResult {
|
|
124
|
+
/** IDs of inserted nodes */
|
|
125
|
+
nodeIds: Array<string>
|
|
126
|
+
/** IDs of inserted edges */
|
|
127
|
+
edgeIds: Array<string>
|
|
128
|
+
}
|
|
129
|
+
/** Temporal granularity */
|
|
130
|
+
export const enum JsTemporalGranularity {
|
|
131
|
+
Hourly = 'Hourly',
|
|
132
|
+
Daily = 'Daily',
|
|
133
|
+
Monthly = 'Monthly',
|
|
134
|
+
Yearly = 'Yearly'
|
|
135
|
+
}
|
|
136
|
+
/** Temporal hyperedge */
|
|
137
|
+
export interface JsTemporalHyperedge {
|
|
138
|
+
/** Base hyperedge */
|
|
139
|
+
hyperedge: JsHyperedge
|
|
140
|
+
/** Creation timestamp (Unix epoch seconds) */
|
|
141
|
+
timestamp: number
|
|
142
|
+
/** Optional expiration timestamp */
|
|
143
|
+
expiresAt?: number
|
|
144
|
+
/** Temporal context */
|
|
145
|
+
granularity: JsTemporalGranularity
|
|
146
|
+
}
|
|
147
|
+
/** Get the version of the library */
|
|
148
|
+
export declare function version(): string
|
|
149
|
+
/** Test function to verify bindings */
|
|
150
|
+
export declare function hello(): string
|
|
151
|
+
/** Streaming query result iterator */
|
|
152
|
+
export declare class QueryResultStream {
|
|
153
|
+
/**
|
|
154
|
+
* Get the next result from the stream
|
|
155
|
+
*
|
|
156
|
+
* # Example
|
|
157
|
+
* ```javascript
|
|
158
|
+
* const stream = await db.queryStream('MATCH (n) RETURN n');
|
|
159
|
+
* while (true) {
|
|
160
|
+
* const result = await stream.next();
|
|
161
|
+
* if (!result) break;
|
|
162
|
+
* console.log(result);
|
|
163
|
+
* }
|
|
164
|
+
* ```
|
|
165
|
+
*/
|
|
166
|
+
next(): JsQueryResult | null
|
|
167
|
+
}
|
|
168
|
+
/** Streaming hyperedge result iterator */
|
|
169
|
+
export declare class HyperedgeStream {
|
|
170
|
+
/**
|
|
171
|
+
* Get the next hyperedge result
|
|
172
|
+
*
|
|
173
|
+
* # Example
|
|
174
|
+
* ```javascript
|
|
175
|
+
* const stream = await db.searchHyperedgesStream(query);
|
|
176
|
+
* for await (const result of stream) {
|
|
177
|
+
* console.log(result);
|
|
178
|
+
* }
|
|
179
|
+
* ```
|
|
180
|
+
*/
|
|
181
|
+
next(): JsHyperedgeResult | null
|
|
182
|
+
/** Collect all remaining results */
|
|
183
|
+
collect(): Array<JsHyperedgeResult>
|
|
184
|
+
}
|
|
185
|
+
/** Node stream iterator */
|
|
186
|
+
export declare class NodeStream {
|
|
187
|
+
/** Get the next node */
|
|
188
|
+
next(): JsNode | null
|
|
189
|
+
/** Collect all remaining nodes */
|
|
190
|
+
collect(): Array<JsNode>
|
|
191
|
+
}
|
|
192
|
+
/** Graph database for complex relationship queries */
|
|
193
|
+
export declare class GraphDatabase {
|
|
194
|
+
/**
|
|
195
|
+
* Create a new graph database
|
|
196
|
+
*
|
|
197
|
+
* # Example
|
|
198
|
+
* ```javascript
|
|
199
|
+
* const db = new GraphDatabase({
|
|
200
|
+
* distanceMetric: 'Cosine',
|
|
201
|
+
* dimensions: 384
|
|
202
|
+
* });
|
|
203
|
+
* ```
|
|
204
|
+
*/
|
|
205
|
+
constructor(options?: JsGraphOptions | undefined | null)
|
|
206
|
+
/**
|
|
207
|
+
* Open an existing graph database from disk
|
|
208
|
+
*
|
|
209
|
+
* # Example
|
|
210
|
+
* ```javascript
|
|
211
|
+
* const db = GraphDatabase.open('./my-graph.db');
|
|
212
|
+
* ```
|
|
213
|
+
*/
|
|
214
|
+
static open(path: string): GraphDatabase
|
|
215
|
+
/**
|
|
216
|
+
* Check if persistence is enabled
|
|
217
|
+
*
|
|
218
|
+
* # Example
|
|
219
|
+
* ```javascript
|
|
220
|
+
* if (db.isPersistent()) {
|
|
221
|
+
* console.log('Data is being saved to:', db.getStoragePath());
|
|
222
|
+
* }
|
|
223
|
+
* ```
|
|
224
|
+
*/
|
|
225
|
+
isPersistent(): boolean
|
|
226
|
+
/** Get the storage path (if persisted) */
|
|
227
|
+
getStoragePath(): string | null
|
|
228
|
+
/**
|
|
229
|
+
* Create a node in the graph
|
|
230
|
+
*
|
|
231
|
+
* # Example
|
|
232
|
+
* ```javascript
|
|
233
|
+
* const nodeId = await db.createNode({
|
|
234
|
+
* id: 'node1',
|
|
235
|
+
* embedding: new Float32Array([1, 2, 3]),
|
|
236
|
+
* properties: { name: 'Alice', age: 30 }
|
|
237
|
+
* });
|
|
238
|
+
* ```
|
|
239
|
+
*/
|
|
240
|
+
createNode(node: JsNode): Promise<string>
|
|
241
|
+
/**
|
|
242
|
+
* Create an edge between two nodes
|
|
243
|
+
*
|
|
244
|
+
* # Example
|
|
245
|
+
* ```javascript
|
|
246
|
+
* const edgeId = await db.createEdge({
|
|
247
|
+
* from: 'node1',
|
|
248
|
+
* to: 'node2',
|
|
249
|
+
* description: 'knows',
|
|
250
|
+
* embedding: new Float32Array([0.5, 0.5, 0.5]),
|
|
251
|
+
* confidence: 0.95
|
|
252
|
+
* });
|
|
253
|
+
* ```
|
|
254
|
+
*/
|
|
255
|
+
createEdge(edge: JsEdge): Promise<string>
|
|
256
|
+
/**
|
|
257
|
+
* Create a hyperedge connecting multiple nodes
|
|
258
|
+
*
|
|
259
|
+
* # Example
|
|
260
|
+
* ```javascript
|
|
261
|
+
* const hyperedgeId = await db.createHyperedge({
|
|
262
|
+
* nodes: ['node1', 'node2', 'node3'],
|
|
263
|
+
* description: 'collaborated_on_project',
|
|
264
|
+
* embedding: new Float32Array([0.3, 0.6, 0.9]),
|
|
265
|
+
* confidence: 0.85,
|
|
266
|
+
* metadata: { project: 'AI Research' }
|
|
267
|
+
* });
|
|
268
|
+
* ```
|
|
269
|
+
*/
|
|
270
|
+
createHyperedge(hyperedge: JsHyperedge): Promise<string>
|
|
271
|
+
/**
|
|
272
|
+
* Query the graph using Cypher-like syntax
|
|
273
|
+
*
|
|
274
|
+
* # Example
|
|
275
|
+
* ```javascript
|
|
276
|
+
* const results = await db.query('MATCH (n) RETURN n LIMIT 10');
|
|
277
|
+
* ```
|
|
278
|
+
*/
|
|
279
|
+
query(cypher: string): Promise<JsQueryResult>
|
|
280
|
+
/**
|
|
281
|
+
* Query the graph synchronously
|
|
282
|
+
*
|
|
283
|
+
* # Example
|
|
284
|
+
* ```javascript
|
|
285
|
+
* const results = db.querySync('MATCH (n) RETURN n LIMIT 10');
|
|
286
|
+
* ```
|
|
287
|
+
*/
|
|
288
|
+
querySync(cypher: string): JsQueryResult
|
|
289
|
+
/**
|
|
290
|
+
* Search for similar hyperedges
|
|
291
|
+
*
|
|
292
|
+
* # Example
|
|
293
|
+
* ```javascript
|
|
294
|
+
* const results = await db.searchHyperedges({
|
|
295
|
+
* embedding: new Float32Array([0.5, 0.5, 0.5]),
|
|
296
|
+
* k: 10
|
|
297
|
+
* });
|
|
298
|
+
* ```
|
|
299
|
+
*/
|
|
300
|
+
searchHyperedges(query: JsHyperedgeQuery): Promise<Array<JsHyperedgeResult>>
|
|
301
|
+
/**
|
|
302
|
+
* Get k-hop neighbors from a starting node
|
|
303
|
+
*
|
|
304
|
+
* # Example
|
|
305
|
+
* ```javascript
|
|
306
|
+
* const neighbors = await db.kHopNeighbors('node1', 2);
|
|
307
|
+
* ```
|
|
308
|
+
*/
|
|
309
|
+
kHopNeighbors(startNode: string, k: number): Promise<Array<string>>
|
|
310
|
+
/**
|
|
311
|
+
* Begin a new transaction
|
|
312
|
+
*
|
|
313
|
+
* # Example
|
|
314
|
+
* ```javascript
|
|
315
|
+
* const txId = await db.begin();
|
|
316
|
+
* ```
|
|
317
|
+
*/
|
|
318
|
+
begin(): Promise<string>
|
|
319
|
+
/**
|
|
320
|
+
* Commit a transaction
|
|
321
|
+
*
|
|
322
|
+
* # Example
|
|
323
|
+
* ```javascript
|
|
324
|
+
* await db.commit(txId);
|
|
325
|
+
* ```
|
|
326
|
+
*/
|
|
327
|
+
commit(txId: string): Promise<void>
|
|
328
|
+
/**
|
|
329
|
+
* Rollback a transaction
|
|
330
|
+
*
|
|
331
|
+
* # Example
|
|
332
|
+
* ```javascript
|
|
333
|
+
* await db.rollback(txId);
|
|
334
|
+
* ```
|
|
335
|
+
*/
|
|
336
|
+
rollback(txId: string): Promise<void>
|
|
337
|
+
/**
|
|
338
|
+
* Batch insert nodes and edges
|
|
339
|
+
*
|
|
340
|
+
* # Example
|
|
341
|
+
* ```javascript
|
|
342
|
+
* await db.batchInsert({
|
|
343
|
+
* nodes: [{ id: 'n1', embedding: new Float32Array([1, 2]) }],
|
|
344
|
+
* edges: [{ from: 'n1', to: 'n2', description: 'knows' }]
|
|
345
|
+
* });
|
|
346
|
+
* ```
|
|
347
|
+
*/
|
|
348
|
+
batchInsert(batch: JsBatchInsert): Promise<JsBatchResult>
|
|
349
|
+
/**
|
|
350
|
+
* Subscribe to graph changes (returns a change stream)
|
|
351
|
+
*
|
|
352
|
+
* # Example
|
|
353
|
+
* ```javascript
|
|
354
|
+
* const unsubscribe = db.subscribe((change) => {
|
|
355
|
+
* console.log('Graph changed:', change);
|
|
356
|
+
* });
|
|
357
|
+
* ```
|
|
358
|
+
*/
|
|
359
|
+
subscribe(callback: (...args: any[]) => any): void
|
|
360
|
+
/**
|
|
361
|
+
* Get graph statistics
|
|
362
|
+
*
|
|
363
|
+
* # Example
|
|
364
|
+
* ```javascript
|
|
365
|
+
* const stats = await db.stats();
|
|
366
|
+
* console.log(`Nodes: ${stats.totalNodes}, Edges: ${stats.totalEdges}`);
|
|
367
|
+
* ```
|
|
368
|
+
*/
|
|
369
|
+
stats(): Promise<JsGraphStats>
|
|
370
|
+
}
|
package/index.js
ADDED
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
/* prettier-ignore */
|
|
4
|
+
|
|
5
|
+
/* auto-generated by NAPI-RS */
|
|
6
|
+
|
|
7
|
+
const { existsSync, readFileSync } = require('fs')
|
|
8
|
+
const { join } = require('path')
|
|
9
|
+
|
|
10
|
+
const { platform, arch } = process
|
|
11
|
+
|
|
12
|
+
let nativeBinding = null
|
|
13
|
+
let localFileExisted = false
|
|
14
|
+
let loadError = null
|
|
15
|
+
|
|
16
|
+
function isMusl() {
|
|
17
|
+
// For Node 10
|
|
18
|
+
if (!process.report || typeof process.report.getReport !== 'function') {
|
|
19
|
+
try {
|
|
20
|
+
const lddPath = require('child_process').execSync('which ldd').toString().trim()
|
|
21
|
+
return readFileSync(lddPath, 'utf8').includes('musl')
|
|
22
|
+
} catch (e) {
|
|
23
|
+
return true
|
|
24
|
+
}
|
|
25
|
+
} else {
|
|
26
|
+
const { glibcVersionRuntime } = process.report.getReport().header
|
|
27
|
+
return !glibcVersionRuntime
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
switch (platform) {
|
|
32
|
+
case 'android':
|
|
33
|
+
switch (arch) {
|
|
34
|
+
case 'arm64':
|
|
35
|
+
localFileExisted = existsSync(join(__dirname, 'index.android-arm64.node'))
|
|
36
|
+
try {
|
|
37
|
+
if (localFileExisted) {
|
|
38
|
+
nativeBinding = require('./index.android-arm64.node')
|
|
39
|
+
} else {
|
|
40
|
+
nativeBinding = require('@ruvector/graph-node-android-arm64')
|
|
41
|
+
}
|
|
42
|
+
} catch (e) {
|
|
43
|
+
loadError = e
|
|
44
|
+
}
|
|
45
|
+
break
|
|
46
|
+
case 'arm':
|
|
47
|
+
localFileExisted = existsSync(join(__dirname, 'index.android-arm-eabi.node'))
|
|
48
|
+
try {
|
|
49
|
+
if (localFileExisted) {
|
|
50
|
+
nativeBinding = require('./index.android-arm-eabi.node')
|
|
51
|
+
} else {
|
|
52
|
+
nativeBinding = require('@ruvector/graph-node-android-arm-eabi')
|
|
53
|
+
}
|
|
54
|
+
} catch (e) {
|
|
55
|
+
loadError = e
|
|
56
|
+
}
|
|
57
|
+
break
|
|
58
|
+
default:
|
|
59
|
+
throw new Error(`Unsupported architecture on Android ${arch}`)
|
|
60
|
+
}
|
|
61
|
+
break
|
|
62
|
+
case 'win32':
|
|
63
|
+
switch (arch) {
|
|
64
|
+
case 'x64':
|
|
65
|
+
localFileExisted = existsSync(
|
|
66
|
+
join(__dirname, 'index.win32-x64-msvc.node')
|
|
67
|
+
)
|
|
68
|
+
try {
|
|
69
|
+
if (localFileExisted) {
|
|
70
|
+
nativeBinding = require('./index.win32-x64-msvc.node')
|
|
71
|
+
} else {
|
|
72
|
+
nativeBinding = require('@ruvector/graph-node-win32-x64-msvc')
|
|
73
|
+
}
|
|
74
|
+
} catch (e) {
|
|
75
|
+
loadError = e
|
|
76
|
+
}
|
|
77
|
+
break
|
|
78
|
+
case 'ia32':
|
|
79
|
+
localFileExisted = existsSync(
|
|
80
|
+
join(__dirname, 'index.win32-ia32-msvc.node')
|
|
81
|
+
)
|
|
82
|
+
try {
|
|
83
|
+
if (localFileExisted) {
|
|
84
|
+
nativeBinding = require('./index.win32-ia32-msvc.node')
|
|
85
|
+
} else {
|
|
86
|
+
nativeBinding = require('@ruvector/graph-node-win32-ia32-msvc')
|
|
87
|
+
}
|
|
88
|
+
} catch (e) {
|
|
89
|
+
loadError = e
|
|
90
|
+
}
|
|
91
|
+
break
|
|
92
|
+
case 'arm64':
|
|
93
|
+
localFileExisted = existsSync(
|
|
94
|
+
join(__dirname, 'index.win32-arm64-msvc.node')
|
|
95
|
+
)
|
|
96
|
+
try {
|
|
97
|
+
if (localFileExisted) {
|
|
98
|
+
nativeBinding = require('./index.win32-arm64-msvc.node')
|
|
99
|
+
} else {
|
|
100
|
+
nativeBinding = require('@ruvector/graph-node-win32-arm64-msvc')
|
|
101
|
+
}
|
|
102
|
+
} catch (e) {
|
|
103
|
+
loadError = e
|
|
104
|
+
}
|
|
105
|
+
break
|
|
106
|
+
default:
|
|
107
|
+
throw new Error(`Unsupported architecture on Windows: ${arch}`)
|
|
108
|
+
}
|
|
109
|
+
break
|
|
110
|
+
case 'darwin':
|
|
111
|
+
localFileExisted = existsSync(join(__dirname, 'index.darwin-universal.node'))
|
|
112
|
+
try {
|
|
113
|
+
if (localFileExisted) {
|
|
114
|
+
nativeBinding = require('./index.darwin-universal.node')
|
|
115
|
+
} else {
|
|
116
|
+
nativeBinding = require('@ruvector/graph-node-darwin-universal')
|
|
117
|
+
}
|
|
118
|
+
break
|
|
119
|
+
} catch {}
|
|
120
|
+
switch (arch) {
|
|
121
|
+
case 'x64':
|
|
122
|
+
localFileExisted = existsSync(join(__dirname, 'index.darwin-x64.node'))
|
|
123
|
+
try {
|
|
124
|
+
if (localFileExisted) {
|
|
125
|
+
nativeBinding = require('./index.darwin-x64.node')
|
|
126
|
+
} else {
|
|
127
|
+
nativeBinding = require('@ruvector/graph-node-darwin-x64')
|
|
128
|
+
}
|
|
129
|
+
} catch (e) {
|
|
130
|
+
loadError = e
|
|
131
|
+
}
|
|
132
|
+
break
|
|
133
|
+
case 'arm64':
|
|
134
|
+
localFileExisted = existsSync(
|
|
135
|
+
join(__dirname, 'index.darwin-arm64.node')
|
|
136
|
+
)
|
|
137
|
+
try {
|
|
138
|
+
if (localFileExisted) {
|
|
139
|
+
nativeBinding = require('./index.darwin-arm64.node')
|
|
140
|
+
} else {
|
|
141
|
+
nativeBinding = require('@ruvector/graph-node-darwin-arm64')
|
|
142
|
+
}
|
|
143
|
+
} catch (e) {
|
|
144
|
+
loadError = e
|
|
145
|
+
}
|
|
146
|
+
break
|
|
147
|
+
default:
|
|
148
|
+
throw new Error(`Unsupported architecture on macOS: ${arch}`)
|
|
149
|
+
}
|
|
150
|
+
break
|
|
151
|
+
case 'freebsd':
|
|
152
|
+
if (arch !== 'x64') {
|
|
153
|
+
throw new Error(`Unsupported architecture on FreeBSD: ${arch}`)
|
|
154
|
+
}
|
|
155
|
+
localFileExisted = existsSync(join(__dirname, 'index.freebsd-x64.node'))
|
|
156
|
+
try {
|
|
157
|
+
if (localFileExisted) {
|
|
158
|
+
nativeBinding = require('./index.freebsd-x64.node')
|
|
159
|
+
} else {
|
|
160
|
+
nativeBinding = require('@ruvector/graph-node-freebsd-x64')
|
|
161
|
+
}
|
|
162
|
+
} catch (e) {
|
|
163
|
+
loadError = e
|
|
164
|
+
}
|
|
165
|
+
break
|
|
166
|
+
case 'linux':
|
|
167
|
+
switch (arch) {
|
|
168
|
+
case 'x64':
|
|
169
|
+
if (isMusl()) {
|
|
170
|
+
localFileExisted = existsSync(
|
|
171
|
+
join(__dirname, 'index.linux-x64-musl.node')
|
|
172
|
+
)
|
|
173
|
+
try {
|
|
174
|
+
if (localFileExisted) {
|
|
175
|
+
nativeBinding = require('./index.linux-x64-musl.node')
|
|
176
|
+
} else {
|
|
177
|
+
nativeBinding = require('@ruvector/graph-node-linux-x64-musl')
|
|
178
|
+
}
|
|
179
|
+
} catch (e) {
|
|
180
|
+
loadError = e
|
|
181
|
+
}
|
|
182
|
+
} else {
|
|
183
|
+
localFileExisted = existsSync(
|
|
184
|
+
join(__dirname, 'index.linux-x64-gnu.node')
|
|
185
|
+
)
|
|
186
|
+
try {
|
|
187
|
+
if (localFileExisted) {
|
|
188
|
+
nativeBinding = require('./index.linux-x64-gnu.node')
|
|
189
|
+
} else {
|
|
190
|
+
nativeBinding = require('@ruvector/graph-node-linux-x64-gnu')
|
|
191
|
+
}
|
|
192
|
+
} catch (e) {
|
|
193
|
+
loadError = e
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
break
|
|
197
|
+
case 'arm64':
|
|
198
|
+
if (isMusl()) {
|
|
199
|
+
localFileExisted = existsSync(
|
|
200
|
+
join(__dirname, 'index.linux-arm64-musl.node')
|
|
201
|
+
)
|
|
202
|
+
try {
|
|
203
|
+
if (localFileExisted) {
|
|
204
|
+
nativeBinding = require('./index.linux-arm64-musl.node')
|
|
205
|
+
} else {
|
|
206
|
+
nativeBinding = require('@ruvector/graph-node-linux-arm64-musl')
|
|
207
|
+
}
|
|
208
|
+
} catch (e) {
|
|
209
|
+
loadError = e
|
|
210
|
+
}
|
|
211
|
+
} else {
|
|
212
|
+
localFileExisted = existsSync(
|
|
213
|
+
join(__dirname, 'index.linux-arm64-gnu.node')
|
|
214
|
+
)
|
|
215
|
+
try {
|
|
216
|
+
if (localFileExisted) {
|
|
217
|
+
nativeBinding = require('./index.linux-arm64-gnu.node')
|
|
218
|
+
} else {
|
|
219
|
+
nativeBinding = require('@ruvector/graph-node-linux-arm64-gnu')
|
|
220
|
+
}
|
|
221
|
+
} catch (e) {
|
|
222
|
+
loadError = e
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
break
|
|
226
|
+
case 'arm':
|
|
227
|
+
if (isMusl()) {
|
|
228
|
+
localFileExisted = existsSync(
|
|
229
|
+
join(__dirname, 'index.linux-arm-musleabihf.node')
|
|
230
|
+
)
|
|
231
|
+
try {
|
|
232
|
+
if (localFileExisted) {
|
|
233
|
+
nativeBinding = require('./index.linux-arm-musleabihf.node')
|
|
234
|
+
} else {
|
|
235
|
+
nativeBinding = require('@ruvector/graph-node-linux-arm-musleabihf')
|
|
236
|
+
}
|
|
237
|
+
} catch (e) {
|
|
238
|
+
loadError = e
|
|
239
|
+
}
|
|
240
|
+
} else {
|
|
241
|
+
localFileExisted = existsSync(
|
|
242
|
+
join(__dirname, 'index.linux-arm-gnueabihf.node')
|
|
243
|
+
)
|
|
244
|
+
try {
|
|
245
|
+
if (localFileExisted) {
|
|
246
|
+
nativeBinding = require('./index.linux-arm-gnueabihf.node')
|
|
247
|
+
} else {
|
|
248
|
+
nativeBinding = require('@ruvector/graph-node-linux-arm-gnueabihf')
|
|
249
|
+
}
|
|
250
|
+
} catch (e) {
|
|
251
|
+
loadError = e
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
break
|
|
255
|
+
case 'riscv64':
|
|
256
|
+
if (isMusl()) {
|
|
257
|
+
localFileExisted = existsSync(
|
|
258
|
+
join(__dirname, 'index.linux-riscv64-musl.node')
|
|
259
|
+
)
|
|
260
|
+
try {
|
|
261
|
+
if (localFileExisted) {
|
|
262
|
+
nativeBinding = require('./index.linux-riscv64-musl.node')
|
|
263
|
+
} else {
|
|
264
|
+
nativeBinding = require('@ruvector/graph-node-linux-riscv64-musl')
|
|
265
|
+
}
|
|
266
|
+
} catch (e) {
|
|
267
|
+
loadError = e
|
|
268
|
+
}
|
|
269
|
+
} else {
|
|
270
|
+
localFileExisted = existsSync(
|
|
271
|
+
join(__dirname, 'index.linux-riscv64-gnu.node')
|
|
272
|
+
)
|
|
273
|
+
try {
|
|
274
|
+
if (localFileExisted) {
|
|
275
|
+
nativeBinding = require('./index.linux-riscv64-gnu.node')
|
|
276
|
+
} else {
|
|
277
|
+
nativeBinding = require('@ruvector/graph-node-linux-riscv64-gnu')
|
|
278
|
+
}
|
|
279
|
+
} catch (e) {
|
|
280
|
+
loadError = e
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
break
|
|
284
|
+
case 's390x':
|
|
285
|
+
localFileExisted = existsSync(
|
|
286
|
+
join(__dirname, 'index.linux-s390x-gnu.node')
|
|
287
|
+
)
|
|
288
|
+
try {
|
|
289
|
+
if (localFileExisted) {
|
|
290
|
+
nativeBinding = require('./index.linux-s390x-gnu.node')
|
|
291
|
+
} else {
|
|
292
|
+
nativeBinding = require('@ruvector/graph-node-linux-s390x-gnu')
|
|
293
|
+
}
|
|
294
|
+
} catch (e) {
|
|
295
|
+
loadError = e
|
|
296
|
+
}
|
|
297
|
+
break
|
|
298
|
+
default:
|
|
299
|
+
throw new Error(`Unsupported architecture on Linux: ${arch}`)
|
|
300
|
+
}
|
|
301
|
+
break
|
|
302
|
+
default:
|
|
303
|
+
throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`)
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (!nativeBinding) {
|
|
307
|
+
if (loadError) {
|
|
308
|
+
throw loadError
|
|
309
|
+
}
|
|
310
|
+
throw new Error(`Failed to load native binding`)
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const { QueryResultStream, HyperedgeStream, NodeStream, JsDistanceMetric, JsTemporalGranularity, GraphDatabase, version, hello } = nativeBinding
|
|
314
|
+
|
|
315
|
+
module.exports.QueryResultStream = QueryResultStream
|
|
316
|
+
module.exports.HyperedgeStream = HyperedgeStream
|
|
317
|
+
module.exports.NodeStream = NodeStream
|
|
318
|
+
module.exports.JsDistanceMetric = JsDistanceMetric
|
|
319
|
+
module.exports.JsTemporalGranularity = JsTemporalGranularity
|
|
320
|
+
module.exports.GraphDatabase = GraphDatabase
|
|
321
|
+
module.exports.version = version
|
|
322
|
+
module.exports.hello = hello
|
package/package.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ruvector/graph-node",
|
|
3
|
+
"version": "0.1.15",
|
|
4
|
+
"description": "Native Node.js bindings for RuVector Graph Database with hypergraph support, Cypher queries, and persistence - 10x faster than WASM",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"types": "index.d.ts",
|
|
7
|
+
"author": "ruv.io Team <info@ruv.io> (https://ruv.io)",
|
|
8
|
+
"homepage": "https://ruv.io",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://github.com/ruvnet/ruvector.git",
|
|
12
|
+
"directory": "npm/packages/graph-node"
|
|
13
|
+
},
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/ruvnet/ruvector/issues"
|
|
16
|
+
},
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">=18.0.0"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"index.js",
|
|
23
|
+
"index.d.ts",
|
|
24
|
+
"README.md"
|
|
25
|
+
],
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build:napi": "napi build --platform --release --cargo-cwd ../../../crates/ruvector-graph-node",
|
|
28
|
+
"test": "node test.js",
|
|
29
|
+
"benchmark": "node benchmark.js",
|
|
30
|
+
"publish:platforms": "node scripts/publish-platforms.js"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@napi-rs/cli": "^2.18.0"
|
|
34
|
+
},
|
|
35
|
+
"optionalDependencies": {
|
|
36
|
+
"@ruvector/graph-node-linux-x64-gnu": "0.1.15",
|
|
37
|
+
"@ruvector/graph-node-linux-arm64-gnu": "0.1.15",
|
|
38
|
+
"@ruvector/graph-node-darwin-x64": "0.1.15",
|
|
39
|
+
"@ruvector/graph-node-darwin-arm64": "0.1.15",
|
|
40
|
+
"@ruvector/graph-node-win32-x64-msvc": "0.1.15"
|
|
41
|
+
},
|
|
42
|
+
"publishConfig": {
|
|
43
|
+
"access": "public"
|
|
44
|
+
},
|
|
45
|
+
"keywords": [
|
|
46
|
+
"graph-database",
|
|
47
|
+
"graph",
|
|
48
|
+
"hypergraph",
|
|
49
|
+
"cypher",
|
|
50
|
+
"neo4j",
|
|
51
|
+
"vector-database",
|
|
52
|
+
"graph-query",
|
|
53
|
+
"knowledge-graph",
|
|
54
|
+
"property-graph",
|
|
55
|
+
"native",
|
|
56
|
+
"napi",
|
|
57
|
+
"rust",
|
|
58
|
+
"fast",
|
|
59
|
+
"performance",
|
|
60
|
+
"zero-copy",
|
|
61
|
+
"ai",
|
|
62
|
+
"machine-learning",
|
|
63
|
+
"rag",
|
|
64
|
+
"ruv",
|
|
65
|
+
"ruvector"
|
|
66
|
+
]
|
|
67
|
+
}
|