@linklabjs/core 0.1.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.
Files changed (72) hide show
  1. package/README.md +411 -0
  2. package/package.json +48 -0
  3. package/src/api/DomainNode.ts +1433 -0
  4. package/src/api/Graph.ts +271 -0
  5. package/src/api/PathBuilder.ts +247 -0
  6. package/src/api/index.ts +15 -0
  7. package/src/api/loadGraph.ts +207 -0
  8. package/src/api/test-api.ts +153 -0
  9. package/src/api/test-domain.ts +119 -0
  10. package/src/api/types.ts +88 -0
  11. package/src/config/synonyms.json +28 -0
  12. package/src/core/EventBus.ts +187 -0
  13. package/src/core/GraphEvents.ts +153 -0
  14. package/src/core/PathFinder.ts +283 -0
  15. package/src/formatters/BaseFormatter.ts +17 -0
  16. package/src/graph/GraphAssembler.ts +50 -0
  17. package/src/graph/GraphCompiler.ts +412 -0
  18. package/src/graph/GraphExtractor.ts +191 -0
  19. package/src/graph/GraphOptimizer.ts +404 -0
  20. package/src/graph/GraphTrainer.ts +247 -0
  21. package/src/http/LinkBuilder.ts +244 -0
  22. package/src/http/TrailRequest.ts +48 -0
  23. package/src/http/example-netflix.ts +59 -0
  24. package/src/http/hateoas/README.md +87 -0
  25. package/src/http/index.ts +33 -0
  26. package/src/http/plugin.ts +360 -0
  27. package/src/index.ts +121 -0
  28. package/src/instrumentation/TelemetryShim.ts +172 -0
  29. package/src/navigation/NavigationEngine.ts +441 -0
  30. package/src/navigation/Resolver.ts +134 -0
  31. package/src/navigation/Scheduler.ts +136 -0
  32. package/src/navigation/Trail.ts +252 -0
  33. package/src/navigation/TrailParser.ts +207 -0
  34. package/src/navigation/index.ts +11 -0
  35. package/src/providers/MockProvider.ts +68 -0
  36. package/src/providers/PostgresProvider.ts +187 -0
  37. package/src/runtime/CompiledGraphEngine.ts +274 -0
  38. package/src/runtime/DataLoader.ts +236 -0
  39. package/src/runtime/Engine.ts +163 -0
  40. package/src/runtime/QueryEngine.ts +222 -0
  41. package/src/scenarios/test-metro-paris/config.json +6 -0
  42. package/src/scenarios/test-metro-paris/graph.json +16325 -0
  43. package/src/scenarios/test-metro-paris/queries.ts +152 -0
  44. package/src/scenarios/test-metro-paris/stack.json +1 -0
  45. package/src/scenarios/test-musicians/config.json +10 -0
  46. package/src/scenarios/test-musicians/graph.json +20 -0
  47. package/src/scenarios/test-musicians/stack.json +1 -0
  48. package/src/scenarios/test-netflix/MIGRATION.md +23 -0
  49. package/src/scenarios/test-netflix/README.md +138 -0
  50. package/src/scenarios/test-netflix/actions.ts +92 -0
  51. package/src/scenarios/test-netflix/config.json +6 -0
  52. package/src/scenarios/test-netflix/data/categories.json +1 -0
  53. package/src/scenarios/test-netflix/data/companies.json +1 -0
  54. package/src/scenarios/test-netflix/data/credits.json +19797 -0
  55. package/src/scenarios/test-netflix/data/departments.json +18 -0
  56. package/src/scenarios/test-netflix/data/jobs.json +142 -0
  57. package/src/scenarios/test-netflix/data/movies.json +3497 -0
  58. package/src/scenarios/test-netflix/data/people.json +1 -0
  59. package/src/scenarios/test-netflix/data/synonyms.json +8 -0
  60. package/src/scenarios/test-netflix/data/users.json +70 -0
  61. package/src/scenarios/test-netflix/graph.json +1017 -0
  62. package/src/scenarios/test-netflix/queries.ts +159 -0
  63. package/src/scenarios/test-netflix/stack.json +14 -0
  64. package/src/schema/GraphBuilder.ts +106 -0
  65. package/src/schema/JsonSchemaExtractor.ts +107 -0
  66. package/src/schema/SchemaAnalyzer.ts +175 -0
  67. package/src/schema/SchemaExtractor.ts +102 -0
  68. package/src/schema/SynonymResolver.ts +143 -0
  69. package/src/scripts/dictionary.json +796 -0
  70. package/src/scripts/graph.json +664 -0
  71. package/src/scripts/regenerate.ts +248 -0
  72. package/src/types/index.ts +506 -0
@@ -0,0 +1,506 @@
1
+ /**
2
+ * LinkLab Core Types
3
+ * * Base type definitions for the entire system
4
+ */
5
+
6
+ // ============================================================
7
+ // Graph Types
8
+ // ============================================================
9
+
10
+ export type NodeType = 'table' | 'view' | 'entity' | 'action'
11
+
12
+ export interface Column {
13
+ name: string
14
+ type: string
15
+ nullable?: boolean
16
+ primaryKey?: boolean
17
+ foreignKey?: boolean
18
+ defaultValue?: any
19
+ description?: string
20
+ }
21
+
22
+ export interface GraphNode {
23
+ id: string
24
+ type: string
25
+ name?: string
26
+ exposed?: boolean
27
+ [key: string]: any
28
+ }
29
+
30
+ export interface GraphEdge {
31
+ from: string
32
+ to: string
33
+ weight: number
34
+ name?: string // Ajouté pour rel.label
35
+ via?: string // Ajouté pour stocker la colonne de jointure
36
+ fromCol?: string // Utilisé par le compilateur
37
+ toCol?: string // Utilisé par le compilateur
38
+ metadata?: {
39
+ condition?: string | Record<string, any>
40
+ semanticType?: string
41
+ [key: string]: any
42
+ }
43
+ }
44
+
45
+ export interface Graph {
46
+ nodes: GraphNode[]
47
+ edges: GraphEdge[]
48
+ }
49
+
50
+ // Pour le CompiledGraph (ce que le QueryEngine lira)
51
+ export interface RouteStep {
52
+ fromCol: string
53
+ toCol: string
54
+ }
55
+
56
+ export interface RouteInfo {
57
+ from: string
58
+ to: string
59
+ primary: {
60
+ path: string[]
61
+ edges: RouteStep[] // 🌟 Ajouté ici
62
+ weight: number
63
+ joins: number
64
+ avgTime: number
65
+ }
66
+ fallbacks: Array<{
67
+ path: string[]
68
+ edges: RouteStep[] // 🌟 Ajouté ici
69
+ weight: number
70
+ joins: number
71
+ avgTime: number
72
+ }>
73
+ alternativesDiscarded: number
74
+ }
75
+
76
+ export interface GraphMetadata {
77
+ version?: string
78
+ generatedAt?: string
79
+ database?: DatabaseInfo
80
+ [key: string]: any
81
+ }
82
+
83
+ export interface DatabaseInfo {
84
+ name: string
85
+ type: 'postgresql' | 'mysql' | 'sqlite' | 'mongodb'
86
+ version?: string
87
+ }
88
+
89
+ // ============================================================
90
+ // Action & Registry Types
91
+ // ============================================================
92
+
93
+ export interface ActionDefinition {
94
+ id: string
95
+ description?: string
96
+ requiredParams: Column[] // Ce que l'action attend de la pile
97
+ provides?: string[] // Ce que l'action injecte après coup
98
+ handler: (context: any) => Promise<any>
99
+ }
100
+
101
+ export interface ActionRegistry {
102
+ register(action: ActionDefinition): void
103
+ get(id: string): ActionDefinition | undefined
104
+ getAll(): ActionDefinition[]
105
+ }
106
+
107
+ // ============================================================
108
+ // Context & Engine Types
109
+ // ============================================================
110
+
111
+ export interface ContextLayer {
112
+ nodeId: string
113
+ timestamp: number
114
+ data: Record<string, any>
115
+ type: 'navigation' | 'action' | 'system'
116
+ }
117
+
118
+ export interface EngineConfig {
119
+ cache?: CacheConfig
120
+ debug?: boolean
121
+ // Hooks pour l'intervention du développeur
122
+ onResolveContext?: (currentContext: any) => Awaitable<any>
123
+ onValidatePath?: (node: GraphNode, context: any) => Awaitable<boolean>
124
+ }
125
+
126
+ // ============================================================
127
+ // Path Types
128
+ // ============================================================
129
+
130
+ export type Path = string[]
131
+
132
+ export interface PathDetails {
133
+ path: Path
134
+ length: number
135
+ joins: number
136
+ weight: number
137
+ edges: GraphEdge[]
138
+ indirect?: boolean
139
+ }
140
+
141
+ export interface PathMetrics {
142
+ path: Path
143
+ weight: number
144
+ joins: number
145
+ avgTime?: number
146
+ executions?: number
147
+ minTime?: number
148
+ maxTime?: number
149
+ }
150
+
151
+ export type MetricsMap = Map<string, TrainingMetrics>
152
+
153
+ // ============================================================
154
+ // Provider Types
155
+ // ============================================================
156
+
157
+ export interface ProviderConfig {
158
+ host?: string
159
+ port?: number
160
+ database: string
161
+ user?: string
162
+ password?: string
163
+ connectionString?: string
164
+ mock?: boolean
165
+ [key: string]: any
166
+ }
167
+
168
+ export interface Provider {
169
+ query<T = any>(sql: string, params?: any[]): Promise<T[]>
170
+ close(): Promise<void>
171
+ }
172
+
173
+ // ============================================================
174
+ // Compiled Graph Types
175
+ // ============================================================
176
+
177
+ export interface CompiledGraph {
178
+ version: string
179
+ compiledAt: string
180
+ config: CompilerConfig
181
+ nodes: GraphNode[]
182
+ routes: RouteInfo[]
183
+ stats: CompilationStats
184
+ }
185
+
186
+ export interface CompilerConfig {
187
+ weightThreshold: number
188
+ minUsage?: number
189
+ keepFallbacks: boolean
190
+ maxFallbacks: number
191
+ expose?: ExposeConfig
192
+ }
193
+
194
+ export interface CompilationStats {
195
+ totalPairs: number
196
+ routesCompiled: number
197
+ routesFiltered: number
198
+ compressionRatio: string
199
+ }
200
+
201
+ // ============================================================
202
+ // Training & Cache Types
203
+ // ============================================================
204
+
205
+ export interface UseCase {
206
+ description: string
207
+ from: string
208
+ to: string
209
+ sampleData?: Record<string, any>
210
+ expectedPath?: Path // Pour tes tests sémantiques
211
+ }
212
+
213
+ export interface TrainingMetrics {
214
+ path: Path
215
+ executions: number
216
+ successes?: number
217
+ failures?: number
218
+ totalTime: number
219
+ avgTime: number
220
+ minTime: number
221
+ maxTime: number
222
+ used: boolean
223
+ failed?: boolean
224
+ error?: string
225
+ }
226
+
227
+ export interface CacheConfig {
228
+ maxSize?: number
229
+ ttl?: number
230
+ }
231
+
232
+ // ============================================================
233
+ // Utility & Error Types
234
+ // ============================================================
235
+
236
+ export type Awaitable<T> = T | Promise<T>
237
+
238
+ export type ExposeConfig =
239
+ | 'all'
240
+ | 'none'
241
+ | { include: string[] }
242
+ | { exclude: string[] }
243
+
244
+ export class LinkLabError extends Error {
245
+ constructor(
246
+ message: string,
247
+ public code: string,
248
+ public details?: any
249
+ ) {
250
+ super(message)
251
+ this.name = 'LinkLabError'
252
+ }
253
+ }
254
+
255
+ export class ProviderError extends LinkLabError {
256
+ constructor(message: string, details?: any) {
257
+ super(message, 'PROVIDER_ERROR', details)
258
+ this.name = 'ProviderError'
259
+ }
260
+ }
261
+
262
+ // --- Types pour la couche technique ---
263
+
264
+ export interface TechProperty {
265
+ name: string
266
+ type: string
267
+ isPK: boolean
268
+ isFK: boolean
269
+ references?: {
270
+ table: string
271
+ column: string
272
+ }
273
+ isIndexed: boolean
274
+ }
275
+
276
+ export interface TechEntity {
277
+ name: string
278
+ properties: TechProperty[]
279
+ rowCount: number
280
+ }
281
+
282
+ export interface TechnicalSchema {
283
+ source: {
284
+ type: string
285
+ name: string
286
+ generatedAt: string
287
+ }
288
+ entities: TechEntity[]
289
+ }
290
+
291
+ // --- Types pour la couche d'Analyse ---
292
+
293
+ export interface AnalysisAdvice {
294
+ type: 'PERFORMANCE' | 'STRUCTURE' | 'VIRTUAL_RELATION'
295
+ level: 'INFO' | 'WARNING' | 'CRITICAL'
296
+ message: string
297
+ target: string // Le nom de la table ou table.colonne
298
+ action?: string // Commande suggérée ou flag pour le Builder
299
+ }
300
+
301
+ export interface ImplicitRelation {
302
+ fromTable: string // Table source
303
+ column: string // Colonne *_id sans FK déclarée
304
+ guessedTable: string // Table cible résolue par SynonymResolver
305
+ }
306
+
307
+ export interface AnalyzedSchema extends TechnicalSchema {
308
+ advices: AnalysisAdvice[]
309
+ weights: Record<string, number> // "table.colonne" -> poids numérique
310
+ implicitRelations: ImplicitRelation[] // FK implicites détectées par SchemaAnalyzer
311
+ }
312
+
313
+ // --- Structure du Dictionnaire Final ---
314
+
315
+ export interface Dictionary {
316
+ tables: Table[]
317
+ relations: Relation[]
318
+ }
319
+
320
+ export interface Table {
321
+ name: string
322
+ columns: string[]
323
+ rowCount: number
324
+ }
325
+
326
+ export interface Relation {
327
+ from: string // Table source
328
+ to: string // Table destination
329
+ via: string // La clé technique (nom de la colonne ou table pivot)
330
+ type: 'physical' | 'physical_reverse' | 'semantic_view' | 'virtual'
331
+ weight: number // Calculé par l'Analyzer
332
+ label: string // Nom lisible (ex: "acting", "directing")
333
+
334
+ // Pour les vues sémantiques (le filtrage dynamique)
335
+ condition?: {
336
+ [column: string]: any // ex: { jobId: 2 }
337
+ }
338
+
339
+ // Pour le transport de données additionnelles (ex: nom du rôle dans 'options')
340
+ metadataField?: string
341
+ }
342
+
343
+ /**
344
+ * Schema definitions for physical data discovery
345
+ */
346
+ export interface ColumnSchema {
347
+ name: string
348
+ type: 'string' | 'number' | 'boolean' | 'date' | 'object' | 'array'
349
+ isNullable?: boolean
350
+ isPrimaryKey?: boolean
351
+ isForeignKey?: boolean
352
+ references?: {
353
+ table: string
354
+ column: string
355
+ }
356
+ }
357
+
358
+ export interface TableSchema {
359
+ name: string
360
+ columns: ColumnSchema[]
361
+ rowCount?: number
362
+ fileSize?: number
363
+ filePath?: string // Chemin vers le JSON ou la table SQL
364
+ }
365
+
366
+ export interface DatabaseSchema {
367
+ tables: TableSchema[]
368
+ relationships: SchemaRelationship[]
369
+ }
370
+
371
+ export interface SchemaRelationship {
372
+ fromTable: string
373
+ fromColumn: string
374
+ toTable: string
375
+ toColumn: string
376
+ type: 'one-to-one' | 'one-to-many' | 'many-to-many'
377
+ }
378
+
379
+ // ============================================================
380
+ // Navigation Engine Types (PATHFIND / NAVIGATE / SCHEDULE)
381
+ // ============================================================
382
+
383
+ export type EngineMode = 'PATHFIND' | 'NAVIGATE' | 'SCHEDULE'
384
+
385
+ /**
386
+ * Frame : unité de navigation sur la stack.
387
+ * Représente un pointeur sémantique vers une entité,
388
+ * avec son état de résolution.
389
+ */
390
+ export interface Frame {
391
+ entity: string
392
+ id?: any
393
+ state?: 'RESOLVED' | 'UNRESOLVED' | 'DEFERRED'
394
+ purpose?: string
395
+ intent?: Record<string, any>
396
+ data?: any
397
+ resolvedBy?: {
398
+ relation: string
399
+ via: string
400
+ filters?: FrameFilter[]
401
+ }
402
+ }
403
+
404
+ export interface FrameFilter {
405
+ field: string
406
+ operator: 'equals' | 'contains' | 'gt' | 'lt' | 'exists'
407
+ value: any
408
+ }
409
+
410
+ /**
411
+ * PathQuery : paramètres pour le mode PATHFIND
412
+ */
413
+ export interface PathQuery {
414
+ from: string
415
+ to: string
416
+ maxPaths?: number
417
+ minHops?: number // Nombre minimum d'étapes (ignore les chemins trop directs)
418
+ maxHops?: number
419
+ transferPenalty?: number // Pénalité en minutes par correspondance (0 = temps pur, 5 = confort)
420
+ via?: string[] // Types de relations autorisés ex: ['CREATED', 'SAMPLES', 'CREDITED']
421
+ preferences?: {
422
+ minimizeTransfers?: boolean
423
+ avoidEdges?: string[]
424
+ [key: string]: any
425
+ }
426
+ }
427
+
428
+ /**
429
+ * ScheduleAction : action pour le mode SCHEDULE.
430
+ * Différenciée de ActionDefinition (infrastructure) pour éviter
431
+ * tout conflit avec le registre d'actions techniques de V3.
432
+ */
433
+ export interface ScheduleAction {
434
+ name: string
435
+ weight: number
436
+ when?: (stack: Frame[]) => boolean
437
+ execute: (stack: Frame[], graph: Graph) => Promise<Frame[]>
438
+ cooldown?: number
439
+ maxExecutions?: number
440
+ terminal?: boolean
441
+ onUse?: (stack: Frame[], result: NavigationResult) => void
442
+ }
443
+
444
+ export interface ActionState {
445
+ cooldownUntil: number
446
+ executionCount: number
447
+ executed?: boolean
448
+ lastResult?: NavigationResult
449
+ }
450
+
451
+ /**
452
+ * Config du NavigationEngine
453
+ */
454
+ export interface NavigationEngineConfig {
455
+ mode: EngineMode
456
+ graph: Graph
457
+ trail?: import('../navigation/Trail.js').Trail // Trail existant à réutiliser
458
+ initialStack?: Frame[] // Ignoré si trail fourni
459
+ actions?: ScheduleAction[]
460
+ pathQuery?: PathQuery
461
+ }
462
+
463
+ /**
464
+ * Résultat d'un step d'exécution
465
+ */
466
+ export interface EngineStepResult {
467
+ time: number
468
+ mode: EngineMode
469
+ phase?: 'RESOLVE' | 'EXECUTE' | 'COMPLETE'
470
+ selectedAction?: string
471
+ resolvedCount?: number
472
+ unresolvedCount?: number
473
+ path?: NavigationPath
474
+ result?: NavigationResult
475
+ }
476
+
477
+ /**
478
+ * Chemin trouvé par PATHFIND — riche en métadonnées
479
+ * pour les formatters (ligne, direction, correspondance)
480
+ */
481
+ export interface NavigationPath {
482
+ nodes: string[]
483
+ edges: GraphEdge[]
484
+ totalWeight: number
485
+ }
486
+
487
+ export interface NavigationResult {
488
+ type: 'SUCCESS' | 'FAIL' | 'DEFER'
489
+ reason?: string
490
+ data?: any
491
+ }
492
+
493
+ // ============================================================
494
+ // Cache Stats (used by Engine LRU)
495
+ // ============================================================
496
+
497
+ export interface CacheStats {
498
+ entries: number
499
+ size: number
500
+ sizeFormatted: string
501
+ maxSize: number
502
+ usage: string
503
+ hits: number
504
+ misses: number
505
+ hitRate: string
506
+ }