@grafema/rfdb-client 0.1.0-alpha.4 → 0.1.1-alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.d.ts CHANGED
@@ -41,14 +41,9 @@ export declare class RFDBClient extends EventEmitter implements IRFDBClient {
41
41
  }>): Promise<RFDBResponse>;
42
42
  /**
43
43
  * Add edges to the graph
44
+ * Extra properties beyond src/dst/type are merged into metadata
44
45
  */
45
- addEdges(edges: Array<Partial<WireEdge> & {
46
- src: string;
47
- dst: string;
48
- type?: string;
49
- edge_type?: string;
50
- edgeType?: string;
51
- }>, skipValidation?: boolean): Promise<RFDBResponse>;
46
+ addEdges(edges: WireEdge[], skipValidation?: boolean): Promise<RFDBResponse>;
52
47
  /**
53
48
  * Delete a node
54
49
  */
@@ -85,14 +80,20 @@ export declare class RFDBClient extends EventEmitter implements IRFDBClient {
85
80
  * Depth-first search
86
81
  */
87
82
  dfs(startIds: string[], maxDepth: number, edgeTypes?: EdgeType[]): Promise<string[]>;
83
+ /**
84
+ * Reachability query - find all nodes reachable from start nodes
85
+ */
86
+ reachability(startIds: string[], maxDepth: number, edgeTypes?: EdgeType[], backward?: boolean): Promise<string[]>;
88
87
  /**
89
88
  * Get outgoing edges from a node
89
+ * Parses metadata JSON and spreads it onto the edge object for convenience
90
90
  */
91
- getOutgoingEdges(id: string, edgeTypes?: EdgeType[] | null): Promise<WireEdge[]>;
91
+ getOutgoingEdges(id: string, edgeTypes?: EdgeType[] | null): Promise<(WireEdge & Record<string, unknown>)[]>;
92
92
  /**
93
93
  * Get incoming edges to a node
94
+ * Parses metadata JSON and spreads it onto the edge object for convenience
94
95
  */
95
- getIncomingEdges(id: string, edgeTypes?: EdgeType[] | null): Promise<WireEdge[]>;
96
+ getIncomingEdges(id: string, edgeTypes?: EdgeType[] | null): Promise<(WireEdge & Record<string, unknown>)[]>;
96
97
  /**
97
98
  * Get node count
98
99
  */
@@ -131,8 +132,9 @@ export declare class RFDBClient extends EventEmitter implements IRFDBClient {
131
132
  getAllNodes(query?: AttrQuery): Promise<WireNode[]>;
132
133
  /**
133
134
  * Get all edges
135
+ * Parses metadata JSON and spreads it onto the edge object for convenience
134
136
  */
135
- getAllEdges(): Promise<WireEdge[]>;
137
+ getAllEdges(): Promise<(WireEdge & Record<string, unknown>)[]>;
136
138
  /**
137
139
  * Check if node is an endpoint (has no outgoing edges)
138
140
  */
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../ts/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../ts/client.ts"],"names":[],"mappings":"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"}
package/dist/client.js CHANGED
@@ -138,14 +138,24 @@ export class RFDBClient extends EventEmitter {
138
138
  }
139
139
  /**
140
140
  * Add edges to the graph
141
+ * Extra properties beyond src/dst/type are merged into metadata
141
142
  */
142
143
  async addEdges(edges, skipValidation = false) {
143
- const wireEdges = edges.map(e => ({
144
- src: String(e.src),
145
- dst: String(e.dst),
146
- edgeType: (e.edge_type || e.edgeType || e.type || 'UNKNOWN'),
147
- metadata: typeof e.metadata === 'string' ? e.metadata : JSON.stringify(e.metadata || {}),
148
- }));
144
+ const wireEdges = edges.map(e => {
145
+ // Cast to unknown first then to Record to allow extra properties
146
+ const edge = e;
147
+ // Extract known fields, rest goes to metadata
148
+ const { src, dst, type, edge_type, edgeType, metadata, ...rest } = edge;
149
+ // Merge explicit metadata with extra properties
150
+ const existingMeta = typeof metadata === 'string' ? JSON.parse(metadata) : (metadata || {});
151
+ const combinedMeta = { ...existingMeta, ...rest };
152
+ return {
153
+ src: String(src),
154
+ dst: String(dst),
155
+ edgeType: (edge_type || edgeType || type || e.edgeType || 'UNKNOWN'),
156
+ metadata: JSON.stringify(combinedMeta),
157
+ };
158
+ });
149
159
  return this._send('addEdges', { edges: wireEdges, skipValidation });
150
160
  }
151
161
  /**
@@ -230,25 +240,61 @@ export class RFDBClient extends EventEmitter {
230
240
  });
231
241
  return response.ids || [];
232
242
  }
243
+ /**
244
+ * Reachability query - find all nodes reachable from start nodes
245
+ */
246
+ async reachability(startIds, maxDepth, edgeTypes = [], backward = false) {
247
+ const response = await this._send('reachability', {
248
+ startIds: startIds.map(String),
249
+ maxDepth,
250
+ edgeTypes,
251
+ backward
252
+ });
253
+ return response.ids || [];
254
+ }
233
255
  /**
234
256
  * Get outgoing edges from a node
257
+ * Parses metadata JSON and spreads it onto the edge object for convenience
235
258
  */
236
259
  async getOutgoingEdges(id, edgeTypes = null) {
237
260
  const response = await this._send('getOutgoingEdges', {
238
261
  id: String(id),
239
262
  edgeTypes
240
263
  });
241
- return response.edges || [];
264
+ const edges = response.edges || [];
265
+ // Parse metadata and spread onto edge for convenience
266
+ return edges.map(e => {
267
+ let meta = {};
268
+ try {
269
+ meta = e.metadata ? JSON.parse(e.metadata) : {};
270
+ }
271
+ catch {
272
+ // Keep empty metadata on parse error
273
+ }
274
+ return { ...e, type: e.edgeType, ...meta };
275
+ });
242
276
  }
243
277
  /**
244
278
  * Get incoming edges to a node
279
+ * Parses metadata JSON and spreads it onto the edge object for convenience
245
280
  */
246
281
  async getIncomingEdges(id, edgeTypes = null) {
247
282
  const response = await this._send('getIncomingEdges', {
248
283
  id: String(id),
249
284
  edgeTypes
250
285
  });
251
- return response.edges || [];
286
+ const edges = response.edges || [];
287
+ // Parse metadata and spread onto edge for convenience
288
+ return edges.map(e => {
289
+ let meta = {};
290
+ try {
291
+ meta = e.metadata ? JSON.parse(e.metadata) : {};
292
+ }
293
+ catch {
294
+ // Keep empty metadata on parse error
295
+ }
296
+ return { ...e, type: e.edgeType, ...meta };
297
+ });
252
298
  }
253
299
  // ===========================================================================
254
300
  // Stats
@@ -338,10 +384,22 @@ export class RFDBClient extends EventEmitter {
338
384
  }
339
385
  /**
340
386
  * Get all edges
387
+ * Parses metadata JSON and spreads it onto the edge object for convenience
341
388
  */
342
389
  async getAllEdges() {
343
390
  const response = await this._send('getAllEdges');
344
- return response.edges || [];
391
+ const edges = response.edges || [];
392
+ // Parse metadata and spread onto edge for convenience
393
+ return edges.map(e => {
394
+ let meta = {};
395
+ try {
396
+ meta = e.metadata ? JSON.parse(e.metadata) : {};
397
+ }
398
+ catch {
399
+ // Keep empty metadata on parse error
400
+ }
401
+ return { ...e, type: e.edgeType, ...meta };
402
+ });
345
403
  }
346
404
  // ===========================================================================
347
405
  // Node Utility Methods
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grafema/rfdb-client",
3
- "version": "0.1.0-alpha.4",
3
+ "version": "0.1.1-alpha",
4
4
  "description": "TypeScript client for RFDB graph database",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -38,7 +38,7 @@
38
38
  },
39
39
  "dependencies": {
40
40
  "@msgpack/msgpack": "^3.1.3",
41
- "@grafema/types": "0.1.0-alpha.4"
41
+ "@grafema/types": "0.1.1-alpha"
42
42
  },
43
43
  "devDependencies": {
44
44
  "@types/node": "^25.0.8",
package/ts/client.ts CHANGED
@@ -177,17 +177,30 @@ export class RFDBClient extends EventEmitter implements IRFDBClient {
177
177
 
178
178
  /**
179
179
  * Add edges to the graph
180
+ * Extra properties beyond src/dst/type are merged into metadata
180
181
  */
181
182
  async addEdges(
182
- edges: Array<Partial<WireEdge> & { src: string; dst: string; type?: string; edge_type?: string; edgeType?: string }>,
183
+ edges: WireEdge[],
183
184
  skipValidation: boolean = false
184
185
  ): Promise<RFDBResponse> {
185
- const wireEdges: WireEdge[] = edges.map(e => ({
186
- src: String(e.src),
187
- dst: String(e.dst),
188
- edgeType: (e.edge_type || e.edgeType || e.type || 'UNKNOWN') as EdgeType,
189
- metadata: typeof e.metadata === 'string' ? e.metadata : JSON.stringify(e.metadata || {}),
190
- }));
186
+ const wireEdges: WireEdge[] = edges.map(e => {
187
+ // Cast to unknown first then to Record to allow extra properties
188
+ const edge = e as unknown as Record<string, unknown>;
189
+
190
+ // Extract known fields, rest goes to metadata
191
+ const { src, dst, type, edge_type, edgeType, metadata, ...rest } = edge;
192
+
193
+ // Merge explicit metadata with extra properties
194
+ const existingMeta = typeof metadata === 'string' ? JSON.parse(metadata as string) : (metadata || {});
195
+ const combinedMeta = { ...existingMeta, ...rest };
196
+
197
+ return {
198
+ src: String(src),
199
+ dst: String(dst),
200
+ edgeType: (edge_type || edgeType || type || e.edgeType || 'UNKNOWN') as EdgeType,
201
+ metadata: JSON.stringify(combinedMeta),
202
+ };
203
+ });
191
204
 
192
205
  return this._send('addEdges', { edges: wireEdges, skipValidation });
193
206
  }
@@ -285,26 +298,68 @@ export class RFDBClient extends EventEmitter implements IRFDBClient {
285
298
  return (response as { ids?: string[] }).ids || [];
286
299
  }
287
300
 
301
+ /**
302
+ * Reachability query - find all nodes reachable from start nodes
303
+ */
304
+ async reachability(
305
+ startIds: string[],
306
+ maxDepth: number,
307
+ edgeTypes: EdgeType[] = [],
308
+ backward: boolean = false
309
+ ): Promise<string[]> {
310
+ const response = await this._send('reachability', {
311
+ startIds: startIds.map(String),
312
+ maxDepth,
313
+ edgeTypes,
314
+ backward
315
+ });
316
+ return (response as { ids?: string[] }).ids || [];
317
+ }
318
+
288
319
  /**
289
320
  * Get outgoing edges from a node
321
+ * Parses metadata JSON and spreads it onto the edge object for convenience
290
322
  */
291
- async getOutgoingEdges(id: string, edgeTypes: EdgeType[] | null = null): Promise<WireEdge[]> {
323
+ async getOutgoingEdges(id: string, edgeTypes: EdgeType[] | null = null): Promise<(WireEdge & Record<string, unknown>)[]> {
292
324
  const response = await this._send('getOutgoingEdges', {
293
325
  id: String(id),
294
326
  edgeTypes
295
327
  });
296
- return (response as { edges?: WireEdge[] }).edges || [];
328
+ const edges = (response as { edges?: WireEdge[] }).edges || [];
329
+
330
+ // Parse metadata and spread onto edge for convenience
331
+ return edges.map(e => {
332
+ let meta = {};
333
+ try {
334
+ meta = e.metadata ? JSON.parse(e.metadata) : {};
335
+ } catch {
336
+ // Keep empty metadata on parse error
337
+ }
338
+ return { ...e, type: e.edgeType, ...meta };
339
+ });
297
340
  }
298
341
 
299
342
  /**
300
343
  * Get incoming edges to a node
344
+ * Parses metadata JSON and spreads it onto the edge object for convenience
301
345
  */
302
- async getIncomingEdges(id: string, edgeTypes: EdgeType[] | null = null): Promise<WireEdge[]> {
346
+ async getIncomingEdges(id: string, edgeTypes: EdgeType[] | null = null): Promise<(WireEdge & Record<string, unknown>)[]> {
303
347
  const response = await this._send('getIncomingEdges', {
304
348
  id: String(id),
305
349
  edgeTypes
306
350
  });
307
- return (response as { edges?: WireEdge[] }).edges || [];
351
+ const edges = (response as { edges?: WireEdge[] }).edges || [];
352
+
353
+ // Parse metadata and spread onto edge for convenience
354
+ return edges.map(e => {
355
+ let meta = {};
356
+ try {
357
+ meta = e.metadata ? JSON.parse(e.metadata) : {};
358
+ } catch {
359
+ // Keep empty metadata on parse error
360
+ }
361
+ return { ...e, type: e.edgeType, ...meta };
362
+ });
308
363
  }
309
364
 
310
365
  // ===========================================================================
@@ -404,10 +459,22 @@ export class RFDBClient extends EventEmitter implements IRFDBClient {
404
459
 
405
460
  /**
406
461
  * Get all edges
462
+ * Parses metadata JSON and spreads it onto the edge object for convenience
407
463
  */
408
- async getAllEdges(): Promise<WireEdge[]> {
464
+ async getAllEdges(): Promise<(WireEdge & Record<string, unknown>)[]> {
409
465
  const response = await this._send('getAllEdges');
410
- return (response as { edges?: WireEdge[] }).edges || [];
466
+ const edges = (response as { edges?: WireEdge[] }).edges || [];
467
+
468
+ // Parse metadata and spread onto edge for convenience
469
+ return edges.map(e => {
470
+ let meta = {};
471
+ try {
472
+ meta = e.metadata ? JSON.parse(e.metadata) : {};
473
+ } catch {
474
+ // Keep empty metadata on parse error
475
+ }
476
+ return { ...e, type: e.edgeType, ...meta };
477
+ });
411
478
  }
412
479
 
413
480
  // ===========================================================================