@relazio/plugin-sdk 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,520 @@
1
+ # Builders Guide
2
+
3
+ This guide provides detailed documentation on using the SDK's builder utilities to create entities, edges, and transform results.
4
+
5
+ ## Overview
6
+
7
+ The SDK provides a scalable, type-agnostic approach to creating plugin responses:
8
+
9
+ - **createEntity()**: Universal entity creation function
10
+ - **createEdge()**: Edge creation with validation
11
+ - **ResultBuilder**: Fluent builder for complex results
12
+ - **EntityBuilder**: Advanced entity construction
13
+ - **EdgeBuilder**: Advanced edge construction
14
+
15
+ ## createEntity() - Universal Approach
16
+
17
+ The `createEntity()` function works with any entity type, present or future, eliminating the need for type-specific helpers.
18
+
19
+ ### Signature
20
+
21
+ ```typescript
22
+ createEntity(
23
+ type: EntityType,
24
+ value: string,
25
+ options?: {
26
+ id?: string;
27
+ label?: string;
28
+ metadata?: Record<string, any>;
29
+ }
30
+ ): OSINTEntity
31
+ ```
32
+
33
+ ### Examples
34
+
35
+ ```typescript
36
+ import { createEntity } from '@relazio/plugin-sdk';
37
+
38
+ // IP address
39
+ const ip = createEntity('ip', '8.8.8.8', {
40
+ label: 'Google DNS',
41
+ metadata: { country: 'US', isp: 'Google LLC' }
42
+ });
43
+
44
+ // Domain
45
+ const domain = createEntity('domain', 'google.com', {
46
+ metadata: { tld: 'com', registrar: 'MarkMonitor' }
47
+ });
48
+
49
+ // Email
50
+ const email = createEntity('email', 'user@example.com', {
51
+ metadata: { verified: true }
52
+ });
53
+
54
+ // Location
55
+ const location = createEntity('location', 'New York, NY', {
56
+ metadata: {
57
+ latitude: 40.7128,
58
+ longitude: -74.0060,
59
+ country: 'United States'
60
+ }
61
+ });
62
+
63
+ // Organization
64
+ const org = createEntity('organization', 'Google LLC', {
65
+ metadata: {
66
+ industry: 'Technology',
67
+ website: 'google.com'
68
+ }
69
+ });
70
+
71
+ // Note with Markdown
72
+ const note = createEntity('note', 'Analysis Results', {
73
+ label: '## Analysis\n\n**Result**: Success',
74
+ metadata: {
75
+ format: 'markdown',
76
+ tags: ['analysis', 'report']
77
+ }
78
+ });
79
+
80
+ // Custom entity type
81
+ const customEntity = createEntity('my-custom-type', 'value', {
82
+ metadata: { custom: 'data' }
83
+ });
84
+ ```
85
+
86
+ ### Advantages
87
+
88
+ - **Scalable**: No SDK updates needed for new entity types
89
+ - **Flexible**: Works with custom entity types
90
+ - **Consistent**: Same syntax for all types
91
+ - **Type-safe**: TypeScript validation for known types
92
+ - **Future-proof**: Compatible with future entity types
93
+
94
+ ## EntityBuilder - Advanced Construction
95
+
96
+ For complex entities requiring fine-grained control, use the EntityBuilder class.
97
+
98
+ ### Example
99
+
100
+ ```typescript
101
+ import { EntityBuilder } from '@relazio/plugin-sdk';
102
+
103
+ const entity = EntityBuilder
104
+ .create('ip', '8.8.8.8')
105
+ .withLabel('Google DNS')
106
+ .withMetadata({ country: 'US' })
107
+ .addMetadata('isp', 'Google LLC')
108
+ .addMetadata('asn', 'AS15169')
109
+ .build();
110
+ ```
111
+
112
+ ## createEdge() - Edge Creation
113
+
114
+ Creates edges between entities with automatic ID generation.
115
+
116
+ ### Signature
117
+
118
+ ```typescript
119
+ createEdge(
120
+ sourceId: string,
121
+ targetId: string,
122
+ label: string,
123
+ options?: {
124
+ id?: string;
125
+ relationship?: string;
126
+ metadata?: Record<string, any>;
127
+ }
128
+ ): OSINTEdge
129
+ ```
130
+
131
+ ### Examples
132
+
133
+ ```typescript
134
+ import { createEdge } from '@relazio/plugin-sdk';
135
+
136
+ // Simple edge
137
+ const edge = createEdge(
138
+ 'ip-abc123',
139
+ 'location-xyz',
140
+ 'located in'
141
+ );
142
+
143
+ // Edge with relationship and metadata
144
+ const edge = createEdge(
145
+ 'ip-abc123',
146
+ 'org-google',
147
+ 'assigned by',
148
+ {
149
+ relationship: 'isp_assignment',
150
+ metadata: { confidence: 0.98 }
151
+ }
152
+ );
153
+ ```
154
+
155
+ ## ResultBuilder - Automated Result Construction
156
+
157
+ ResultBuilder simplifies creating transform results by automatically generating edges from the input entity to created entities.
158
+
159
+ ### Basic Usage
160
+
161
+ ```typescript
162
+ import { ResultBuilder } from '@relazio/plugin-sdk';
163
+
164
+ handler: async (input) => {
165
+ const entity = createEntity('ip', '8.8.8.8');
166
+
167
+ return new ResultBuilder(input)
168
+ .addEntity(entity, 'resolves to')
169
+ .setMessage('Resolution successful')
170
+ .build();
171
+ }
172
+ ```
173
+
174
+ ### Adding Single Entities
175
+
176
+ ```typescript
177
+ const result = new ResultBuilder(input);
178
+
179
+ result.addEntity(entity, 'edge label', {
180
+ relationship: 'custom_relationship',
181
+ metadata: { confidence: 0.95 }
182
+ });
183
+
184
+ return result
185
+ .setMessage('Operation completed')
186
+ .build();
187
+ ```
188
+
189
+ ### Adding Multiple Entities
190
+
191
+ ```typescript
192
+ const result = new ResultBuilder(input);
193
+
194
+ const entities = ['1.1.1.1', '8.8.8.8'].map(ip =>
195
+ createEntity('ip', ip)
196
+ );
197
+
198
+ result.addEntities(entities, 'resolves to', {
199
+ relationship: 'dns_resolution'
200
+ });
201
+
202
+ return result.build();
203
+ ```
204
+
205
+ ### Adding Entities Without Edges
206
+
207
+ ```typescript
208
+ const result = new ResultBuilder(input);
209
+
210
+ // Add entity without creating an edge
211
+ result.addEntityOnly(entity);
212
+
213
+ return result.build();
214
+ ```
215
+
216
+ ### Adding Custom Edges
217
+
218
+ ```typescript
219
+ const result = new ResultBuilder(input);
220
+
221
+ result.addEntityOnly(entity1);
222
+ result.addEntityOnly(entity2);
223
+
224
+ // Create custom edge between entities
225
+ const edge = createEdge(entity1.id, entity2.id, 'related to');
226
+ result.addEdge(edge);
227
+
228
+ return result.build();
229
+ ```
230
+
231
+ ### Adding Metadata
232
+
233
+ ```typescript
234
+ return new ResultBuilder(input)
235
+ .addEntity(entity, 'label')
236
+ .setMessage('Success')
237
+ .addMetadata('executionTime', 123)
238
+ .addMetadata('source', 'api.example.com')
239
+ .build();
240
+ ```
241
+
242
+ ## Common Patterns
243
+
244
+ ### Pattern 1: IP Geolocation Lookup
245
+
246
+ ```typescript
247
+ handler: async (input) => {
248
+ const ip = input.entity.value;
249
+ const data = await lookupIP(ip);
250
+
251
+ const location = createEntity('location', data.city, {
252
+ metadata: {
253
+ latitude: data.lat,
254
+ longitude: data.lon,
255
+ country: data.country
256
+ }
257
+ });
258
+
259
+ const org = createEntity('organization', data.isp, {
260
+ metadata: { asn: data.asn }
261
+ });
262
+
263
+ return new ResultBuilder(input)
264
+ .addEntity(location, 'located in', {
265
+ relationship: 'geolocation'
266
+ })
267
+ .addEntity(org, 'assigned by', {
268
+ relationship: 'isp_assignment'
269
+ })
270
+ .setMessage(`Analyzed IP ${ip}`)
271
+ .build();
272
+ }
273
+ ```
274
+
275
+ ### Pattern 2: DNS Resolution
276
+
277
+ ```typescript
278
+ handler: async (input) => {
279
+ const domain = input.entity.value;
280
+ const ips = await resolveDomain(domain);
281
+
282
+ const ipEntities = ips.map(ip => createEntity('ip', ip, {
283
+ metadata: { recordType: 'A' }
284
+ }));
285
+
286
+ return new ResultBuilder(input)
287
+ .addEntities(ipEntities, 'resolves to', {
288
+ relationship: 'dns_resolution'
289
+ })
290
+ .setMessage(`Found ${ips.length} IP address(es)`)
291
+ .build();
292
+ }
293
+ ```
294
+
295
+ ### Pattern 3: Analysis with Markdown Notes
296
+
297
+ ```typescript
298
+ handler: async (input) => {
299
+ const data = await analyze(input.entity.value);
300
+
301
+ const markdown = `
302
+ ## Analysis Results
303
+
304
+ **Status**: ${data.status}
305
+ **Score**: ${data.score}/100
306
+
307
+ ### Details
308
+ - Finding 1: ${data.finding1}
309
+ - Finding 2: ${data.finding2}
310
+ `;
311
+
312
+ const note = createEntity('note', 'Analysis Report', {
313
+ label: markdown,
314
+ metadata: {
315
+ format: 'markdown',
316
+ tags: ['analysis', 'report'],
317
+ timestamp: new Date().toISOString()
318
+ }
319
+ });
320
+
321
+ return new ResultBuilder(input)
322
+ .addEntity(note, 'analysis')
323
+ .build();
324
+ }
325
+ ```
326
+
327
+ ### Pattern 4: Empty Results
328
+
329
+ ```typescript
330
+ import { emptyResult } from '@relazio/plugin-sdk';
331
+
332
+ handler: async (input) => {
333
+ const results = await search(input.entity.value);
334
+
335
+ if (results.length === 0) {
336
+ return emptyResult('No results found');
337
+ }
338
+
339
+ // Process results...
340
+ }
341
+ ```
342
+
343
+ ### Pattern 5: Error Handling
344
+
345
+ ```typescript
346
+ import { errorResult } from '@relazio/plugin-sdk';
347
+
348
+ handler: async (input) => {
349
+ try {
350
+ // Transform logic
351
+ } catch (error) {
352
+ throw error; // SDK handles automatically
353
+
354
+ // Or use errorResult for custom handling
355
+ return errorResult(error);
356
+ }
357
+ }
358
+ ```
359
+
360
+ ## Validation
361
+
362
+ The SDK automatically validates responses, but manual validation is available.
363
+
364
+ ```typescript
365
+ import { validateTransformResult } from '@relazio/plugin-sdk';
366
+
367
+ const result = {
368
+ entities: [/* ... */],
369
+ edges: [/* ... */]
370
+ };
371
+
372
+ const validation = validateTransformResult(result, input.entity.id);
373
+
374
+ if (!validation.valid) {
375
+ console.error('Validation errors:', validation.errors);
376
+ }
377
+ ```
378
+
379
+ ## ID Generation
380
+
381
+ IDs are generated automatically using deterministic hashing, but can be customized.
382
+
383
+ ```typescript
384
+ import { generateEntityId, generateEdgeId } from '@relazio/plugin-sdk';
385
+
386
+ // Deterministic entity ID
387
+ const id = generateEntityId('ip', '8.8.8.8');
388
+ // Returns: "ip-c909e98d"
389
+
390
+ // Deterministic edge ID
391
+ const edgeId = generateEdgeId('source-id', 'target-id', 'label');
392
+ // Returns: "edge-4f8a2d1c"
393
+
394
+ // Custom ID
395
+ const entity = createEntity('ip', '8.8.8.8', {
396
+ id: 'my-custom-id'
397
+ });
398
+ ```
399
+
400
+ ## Best Practices
401
+
402
+ ### Recommended Approach
403
+
404
+ ```typescript
405
+ // Use createEntity() for scalability
406
+ const ip = createEntity('ip', '8.8.8.8');
407
+
408
+ // Use ResultBuilder for complex results
409
+ return new ResultBuilder(input)
410
+ .addEntity(location, 'located in')
411
+ .build();
412
+
413
+ // Add meaningful metadata
414
+ createEntity('location', 'NYC', {
415
+ metadata: { latitude: 40.7, longitude: -74.0 }
416
+ });
417
+
418
+ // Use descriptive labels
419
+ createEntity('domain', 'mx1.google.com', {
420
+ label: 'mx1.google.com (priority: 10)'
421
+ });
422
+
423
+ // Works with custom types
424
+ createEntity('my-custom-type', 'value', {
425
+ metadata: { custom: 'data' }
426
+ });
427
+ ```
428
+
429
+ ### Common Mistakes
430
+
431
+ ```typescript
432
+ // Incorrect: Creating entities manually without IDs
433
+ const entity = { type: 'ip', value: '8.8.8.8' };
434
+
435
+ // Correct: Use createEntity()
436
+ const entity = createEntity('ip', '8.8.8.8');
437
+
438
+ // Incorrect: Empty edge label
439
+ createEdge('source-id', 'target-id', '');
440
+
441
+ // Correct: Descriptive label
442
+ createEdge('source-id', 'target-id', 'related to');
443
+ ```
444
+
445
+ ## Helper Functions
446
+
447
+ ### Result Helpers
448
+
449
+ ```typescript
450
+ // Empty result
451
+ emptyResult(message?: string): TransformResult
452
+
453
+ // Error result
454
+ errorResult(error: string | Error): TransformResult
455
+
456
+ // Single entity result
457
+ singleEntityResult(
458
+ inputEntityId: string,
459
+ entity: OSINTEntity,
460
+ edgeLabel: string,
461
+ options?: {
462
+ relationship?: string;
463
+ message?: string;
464
+ metadata?: Record<string, any>;
465
+ }
466
+ ): TransformResult
467
+
468
+ // Multi-entity result
469
+ multiEntityResult(
470
+ inputEntityId: string,
471
+ entities: OSINTEntity[],
472
+ edgeLabel: string,
473
+ options?: {
474
+ relationship?: string;
475
+ message?: string;
476
+ metadata?: Record<string, any>;
477
+ }
478
+ ): TransformResult
479
+ ```
480
+
481
+ ### Validation Helpers
482
+
483
+ ```typescript
484
+ validateEntities(entities: OSINTEntity[]): { valid: boolean; errors: string[] }
485
+
486
+ validateEdges(
487
+ edges: OSINTEdge[],
488
+ entities: OSINTEntity[],
489
+ inputEntityId?: string
490
+ ): { valid: boolean; errors: string[] }
491
+
492
+ validateTransformResult(
493
+ result: { entities: OSINTEntity[]; edges: OSINTEdge[] },
494
+ inputEntityId?: string
495
+ ): { valid: boolean; errors: string[] }
496
+ ```
497
+
498
+ ### ID Generation Helpers
499
+
500
+ ```typescript
501
+ generateEntityId(type: EntityType, value: string): string
502
+
503
+ generateEdgeId(sourceId: string, targetId: string, label?: string): string
504
+
505
+ generateRandomId(prefix: string): string
506
+
507
+ normalizeValue(value: string): string
508
+
509
+ isValidEntityId(id: string): boolean
510
+
511
+ isValidEdgeId(id: string): boolean
512
+ ```
513
+
514
+ ## Additional Resources
515
+
516
+ - [Quick Start Guide](./quick-start.md)
517
+ - [Response Format Specification](./response-format.md)
518
+ - [Examples Documentation](./examples.md)
519
+ - [Main README](../README.md)
520
+