digitaltwin-core 0.14.3 → 1.0.1

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 (159) hide show
  1. package/README.md +218 -1
  2. package/dist/auth/apisix_parser.d.ts +56 -56
  3. package/dist/auth/apisix_parser.d.ts.map +1 -1
  4. package/dist/auth/apisix_parser.js +72 -86
  5. package/dist/auth/apisix_parser.js.map +1 -1
  6. package/dist/auth/auth_provider.d.ts +118 -0
  7. package/dist/auth/auth_provider.d.ts.map +1 -0
  8. package/dist/auth/auth_provider.js +8 -0
  9. package/dist/auth/auth_provider.js.map +1 -0
  10. package/dist/auth/auth_provider_factory.d.ts +91 -0
  11. package/dist/auth/auth_provider_factory.d.ts.map +1 -0
  12. package/dist/auth/auth_provider_factory.js +146 -0
  13. package/dist/auth/auth_provider_factory.js.map +1 -0
  14. package/dist/auth/index.d.ts +4 -1
  15. package/dist/auth/index.d.ts.map +1 -1
  16. package/dist/auth/index.js +3 -0
  17. package/dist/auth/index.js.map +1 -1
  18. package/dist/auth/providers/gateway_auth_provider.d.ts +78 -0
  19. package/dist/auth/providers/gateway_auth_provider.d.ts.map +1 -0
  20. package/dist/auth/providers/gateway_auth_provider.js +109 -0
  21. package/dist/auth/providers/gateway_auth_provider.js.map +1 -0
  22. package/dist/auth/providers/index.d.ts +4 -0
  23. package/dist/auth/providers/index.d.ts.map +1 -0
  24. package/dist/auth/providers/index.js +4 -0
  25. package/dist/auth/providers/index.js.map +1 -0
  26. package/dist/auth/providers/jwt_auth_provider.d.ts +91 -0
  27. package/dist/auth/providers/jwt_auth_provider.d.ts.map +1 -0
  28. package/dist/auth/providers/jwt_auth_provider.js +204 -0
  29. package/dist/auth/providers/jwt_auth_provider.js.map +1 -0
  30. package/dist/auth/providers/no_auth_provider.d.ts +61 -0
  31. package/dist/auth/providers/no_auth_provider.d.ts.map +1 -0
  32. package/dist/auth/providers/no_auth_provider.js +76 -0
  33. package/dist/auth/providers/no_auth_provider.js.map +1 -0
  34. package/dist/auth/types.d.ts +5 -3
  35. package/dist/auth/types.d.ts.map +1 -1
  36. package/dist/components/assets_manager.d.ts +1 -1
  37. package/dist/components/assets_manager.d.ts.map +1 -1
  38. package/dist/components/assets_manager.js +54 -48
  39. package/dist/components/assets_manager.js.map +1 -1
  40. package/dist/components/collector.d.ts.map +1 -1
  41. package/dist/components/collector.js +30 -18
  42. package/dist/components/collector.js.map +1 -1
  43. package/dist/components/custom_table_manager.d.ts.map +1 -1
  44. package/dist/components/custom_table_manager.js +36 -65
  45. package/dist/components/custom_table_manager.js.map +1 -1
  46. package/dist/components/global_assets_handler.d.ts +4 -2
  47. package/dist/components/global_assets_handler.d.ts.map +1 -1
  48. package/dist/components/global_assets_handler.js.map +1 -1
  49. package/dist/components/harvester.d.ts.map +1 -1
  50. package/dist/components/harvester.js +46 -33
  51. package/dist/components/harvester.js.map +1 -1
  52. package/dist/components/interfaces.d.ts +3 -2
  53. package/dist/components/interfaces.d.ts.map +1 -1
  54. package/dist/components/map_manager.d.ts.map +1 -1
  55. package/dist/components/map_manager.js.map +1 -1
  56. package/dist/components/tileset_manager.d.ts +2 -1
  57. package/dist/components/tileset_manager.d.ts.map +1 -1
  58. package/dist/components/tileset_manager.js +20 -15
  59. package/dist/components/tileset_manager.js.map +1 -1
  60. package/dist/database/adapters/knex_database_adapter.d.ts +6 -1
  61. package/dist/database/adapters/knex_database_adapter.d.ts.map +1 -1
  62. package/dist/database/adapters/knex_database_adapter.js +118 -36
  63. package/dist/database/adapters/knex_database_adapter.js.map +1 -1
  64. package/dist/database/database_adapter.d.ts +13 -1
  65. package/dist/database/database_adapter.d.ts.map +1 -1
  66. package/dist/database/database_adapter.js.map +1 -1
  67. package/dist/engine/component_types.d.ts +95 -0
  68. package/dist/engine/component_types.d.ts.map +1 -0
  69. package/dist/engine/component_types.js +93 -0
  70. package/dist/engine/component_types.js.map +1 -0
  71. package/dist/engine/digital_twin_engine.d.ts +121 -6
  72. package/dist/engine/digital_twin_engine.d.ts.map +1 -1
  73. package/dist/engine/digital_twin_engine.js +402 -74
  74. package/dist/engine/digital_twin_engine.js.map +1 -1
  75. package/dist/engine/endpoints.d.ts.map +1 -1
  76. package/dist/engine/endpoints.js +35 -3
  77. package/dist/engine/endpoints.js.map +1 -1
  78. package/dist/engine/error_handler.d.ts +20 -0
  79. package/dist/engine/error_handler.d.ts.map +1 -0
  80. package/dist/engine/error_handler.js +69 -0
  81. package/dist/engine/error_handler.js.map +1 -0
  82. package/dist/engine/events.d.ts +1 -1
  83. package/dist/engine/events.d.ts.map +1 -1
  84. package/dist/engine/events.js.map +1 -1
  85. package/dist/engine/health.d.ts +112 -0
  86. package/dist/engine/health.d.ts.map +1 -0
  87. package/dist/engine/health.js +190 -0
  88. package/dist/engine/health.js.map +1 -0
  89. package/dist/engine/initializer.d.ts.map +1 -1
  90. package/dist/engine/initializer.js +6 -4
  91. package/dist/engine/initializer.js.map +1 -1
  92. package/dist/engine/scheduler.d.ts.map +1 -1
  93. package/dist/engine/scheduler.js +17 -9
  94. package/dist/engine/scheduler.js.map +1 -1
  95. package/dist/engine/upload_processor.d.ts.map +1 -1
  96. package/dist/engine/upload_processor.js +24 -12
  97. package/dist/engine/upload_processor.js.map +1 -1
  98. package/dist/errors/index.d.ts +94 -0
  99. package/dist/errors/index.d.ts.map +1 -0
  100. package/dist/errors/index.js +149 -0
  101. package/dist/errors/index.js.map +1 -0
  102. package/dist/index.d.ts +9 -0
  103. package/dist/index.d.ts.map +1 -1
  104. package/dist/index.js +13 -0
  105. package/dist/index.js.map +1 -1
  106. package/dist/loader/component_loader.d.ts +128 -0
  107. package/dist/loader/component_loader.d.ts.map +1 -0
  108. package/dist/loader/component_loader.js +330 -0
  109. package/dist/loader/component_loader.js.map +1 -0
  110. package/dist/loader/index.d.ts +19 -0
  111. package/dist/loader/index.d.ts.map +1 -0
  112. package/dist/loader/index.js +19 -0
  113. package/dist/loader/index.js.map +1 -0
  114. package/dist/storage/adapters/local_storage_service.d.ts +6 -0
  115. package/dist/storage/adapters/local_storage_service.d.ts.map +1 -1
  116. package/dist/storage/adapters/local_storage_service.js +26 -4
  117. package/dist/storage/adapters/local_storage_service.js.map +1 -1
  118. package/dist/storage/adapters/ovh_storage_service.d.ts.map +1 -1
  119. package/dist/storage/adapters/ovh_storage_service.js +5 -6
  120. package/dist/storage/adapters/ovh_storage_service.js.map +1 -1
  121. package/dist/storage/storage_factory.d.ts.map +1 -1
  122. package/dist/storage/storage_factory.js +4 -1
  123. package/dist/storage/storage_factory.js.map +1 -1
  124. package/dist/storage/storage_service.d.ts.map +1 -1
  125. package/dist/storage/storage_service.js +6 -2
  126. package/dist/storage/storage_service.js.map +1 -1
  127. package/dist/types/http.d.ts +156 -0
  128. package/dist/types/http.d.ts.map +1 -0
  129. package/dist/types/http.js +8 -0
  130. package/dist/types/http.js.map +1 -0
  131. package/dist/utils/graceful_shutdown.d.ts +44 -0
  132. package/dist/utils/graceful_shutdown.d.ts.map +1 -0
  133. package/dist/utils/graceful_shutdown.js +79 -0
  134. package/dist/utils/graceful_shutdown.js.map +1 -0
  135. package/dist/utils/http_responses.d.ts +20 -0
  136. package/dist/utils/http_responses.d.ts.map +1 -1
  137. package/dist/utils/http_responses.js +28 -2
  138. package/dist/utils/http_responses.js.map +1 -1
  139. package/dist/utils/logger.d.ts +8 -8
  140. package/dist/utils/logger.d.ts.map +1 -1
  141. package/dist/utils/logger.js +8 -8
  142. package/dist/utils/logger.js.map +1 -1
  143. package/dist/utils/safe_async.d.ts +50 -0
  144. package/dist/utils/safe_async.d.ts.map +1 -0
  145. package/dist/utils/safe_async.js +90 -0
  146. package/dist/utils/safe_async.js.map +1 -0
  147. package/dist/validation/index.d.ts +3 -0
  148. package/dist/validation/index.d.ts.map +1 -0
  149. package/dist/validation/index.js +7 -0
  150. package/dist/validation/index.js.map +1 -0
  151. package/dist/validation/schemas.d.ts +273 -0
  152. package/dist/validation/schemas.d.ts.map +1 -0
  153. package/dist/validation/schemas.js +82 -0
  154. package/dist/validation/schemas.js.map +1 -0
  155. package/dist/validation/validate.d.ts +49 -0
  156. package/dist/validation/validate.d.ts.map +1 -0
  157. package/dist/validation/validate.js +110 -0
  158. package/dist/validation/validate.js.map +1 -0
  159. package/package.json +14 -8
@@ -0,0 +1,128 @@
1
+ /**
2
+ * @fileoverview Component auto-discovery and loading utilities
3
+ *
4
+ * Provides functions to automatically discover and load Digital Twin components
5
+ * from a directory based on file naming conventions.
6
+ */
7
+ import type { LoadedComponents } from '../engine/component_types.js';
8
+ /**
9
+ * Options for component auto-discovery
10
+ */
11
+ export interface LoadComponentsOptions {
12
+ /**
13
+ * File patterns to match by suffix.
14
+ * Keys are component types, values are file suffixes (without extension).
15
+ * @default Standard naming conventions
16
+ */
17
+ patterns?: {
18
+ collectors?: string;
19
+ harvesters?: string;
20
+ handlers?: string;
21
+ assetsManagers?: string;
22
+ customTableManagers?: string;
23
+ };
24
+ /**
25
+ * File extensions to scan for.
26
+ * @default ['.js', '.mjs']
27
+ */
28
+ extensions?: string[];
29
+ /**
30
+ * Whether to scan subdirectories recursively.
31
+ * @default true
32
+ */
33
+ recursive?: boolean;
34
+ /**
35
+ * Patterns to exclude (glob-like patterns applied to file names).
36
+ * @default ['*.spec.*', '*.test.*', 'index.*']
37
+ */
38
+ exclude?: string[];
39
+ /**
40
+ * Enable verbose logging during discovery.
41
+ * @default false
42
+ */
43
+ verbose?: boolean;
44
+ }
45
+ /**
46
+ * Result of component loading operation
47
+ */
48
+ export interface LoadComponentsResult extends LoadedComponents {
49
+ /** Files that were scanned */
50
+ scannedFiles: string[];
51
+ /** Errors encountered during loading */
52
+ errors: Array<{
53
+ file: string;
54
+ error: string;
55
+ }>;
56
+ /** Summary statistics */
57
+ summary: {
58
+ total: number;
59
+ collectors: number;
60
+ harvesters: number;
61
+ handlers: number;
62
+ assetsManagers: number;
63
+ customTableManagers: number;
64
+ errors: number;
65
+ };
66
+ }
67
+ /**
68
+ * Auto-discovers and loads Digital Twin components from a directory.
69
+ *
70
+ * This function scans the specified directory for component files following
71
+ * the naming conventions (*_collector.js, *_harvester.js, etc.), dynamically
72
+ * imports them, and instantiates any component classes found.
73
+ *
74
+ * ## Naming Conventions
75
+ *
76
+ * Component files should follow these naming patterns:
77
+ * - Collectors: `*_collector.js` (e.g., `weather_collector.js`)
78
+ * - Harvesters: `*_harvester.js` (e.g., `traffic_harvester.js`)
79
+ * - Handlers: `*_handler.js` (e.g., `api_handler.js`)
80
+ * - Assets Managers: `*_assets_manager.js` (e.g., `gltf_assets_manager.js`)
81
+ * - Custom Table Managers: `*_custom_table.js` (e.g., `wms_custom_table.js`)
82
+ *
83
+ * ## Component Export Requirements
84
+ *
85
+ * Components should be exported as default export or named export matching the class name:
86
+ * ```typescript
87
+ * // Default export (preferred)
88
+ * export default class WeatherCollector extends Collector { ... }
89
+ *
90
+ * // Named export matching file name
91
+ * export class WeatherCollector extends Collector { ... }
92
+ * ```
93
+ *
94
+ * @param directory - Directory path to scan for components (absolute or relative to cwd)
95
+ * @param options - Configuration options for discovery
96
+ * @returns Promise resolving to loaded components and metadata
97
+ *
98
+ * @example
99
+ * ```typescript
100
+ * import { loadComponents, DigitalTwinEngine } from 'digitaltwin-core'
101
+ *
102
+ * // Basic usage - scan compiled components
103
+ * const result = await loadComponents('./dist/components')
104
+ *
105
+ * console.log(`Loaded ${result.summary.total} components`)
106
+ *
107
+ * const engine = new DigitalTwinEngine({ storage, database })
108
+ * engine.registerComponents(result)
109
+ * await engine.start()
110
+ * ```
111
+ *
112
+ * @example
113
+ * ```typescript
114
+ * // Advanced usage with options
115
+ * const result = await loadComponents('./dist/components', {
116
+ * recursive: true,
117
+ * verbose: true,
118
+ * extensions: ['.js'],
119
+ * exclude: ['*.test.*', 'deprecated_*']
120
+ * })
121
+ *
122
+ * if (result.errors.length > 0) {
123
+ * console.warn('Some components failed to load:', result.errors)
124
+ * }
125
+ * ```
126
+ */
127
+ export declare function loadComponents(directory: string, options?: LoadComponentsOptions): Promise<LoadComponentsResult>;
128
+ //# sourceMappingURL=component_loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"component_loader.d.ts","sourceRoot":"","sources":["../../src/loader/component_loader.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EAAE,gBAAgB,EAAgB,MAAM,8BAA8B,CAAA;AASlF;;GAEG;AACH,MAAM,WAAW,qBAAqB;IAClC;;;;OAIG;IACH,QAAQ,CAAC,EAAE;QACP,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,cAAc,CAAC,EAAE,MAAM,CAAA;QACvB,mBAAmB,CAAC,EAAE,MAAM,CAAA;KAC/B,CAAA;IAED;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;IAErB;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IAEnB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAElB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAqB,SAAQ,gBAAgB;IAC1D,8BAA8B;IAC9B,YAAY,EAAE,MAAM,EAAE,CAAA;IAEtB,wCAAwC;IACxC,MAAM,EAAE,KAAK,CAAC;QACV,IAAI,EAAE,MAAM,CAAA;QACZ,KAAK,EAAE,MAAM,CAAA;KAChB,CAAC,CAAA;IAEF,yBAAyB;IACzB,OAAO,EAAE;QACL,KAAK,EAAE,MAAM,CAAA;QACb,UAAU,EAAE,MAAM,CAAA;QAClB,UAAU,EAAE,MAAM,CAAA;QAClB,QAAQ,EAAE,MAAM,CAAA;QAChB,cAAc,EAAE,MAAM,CAAA;QACtB,mBAAmB,EAAE,MAAM,CAAA;QAC3B,MAAM,EAAE,MAAM,CAAA;KACjB,CAAA;CACJ;AA6JD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AACH,wBAAsB,cAAc,CAChC,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,qBAA0B,GACpC,OAAO,CAAC,oBAAoB,CAAC,CAoJ/B"}
@@ -0,0 +1,330 @@
1
+ /**
2
+ * @fileoverview Component auto-discovery and loading utilities
3
+ *
4
+ * Provides functions to automatically discover and load Digital Twin components
5
+ * from a directory based on file naming conventions.
6
+ */
7
+ import { pathToFileURL } from 'node:url';
8
+ import fs from 'node:fs/promises';
9
+ import path from 'node:path';
10
+ import { isCollector, isHarvester, isHandler, isAssetsManager, isCustomTableManager } from '../engine/component_types.js';
11
+ /**
12
+ * Default file patterns for component detection based on naming conventions
13
+ */
14
+ const DEFAULT_PATTERNS = {
15
+ collectors: '_collector',
16
+ harvesters: '_harvester',
17
+ handlers: '_handler',
18
+ assetsManagers: '_assets_manager',
19
+ customTableManagers: '_custom_table'
20
+ };
21
+ const DEFAULT_EXTENSIONS = ['.js', '.mjs'];
22
+ const DEFAULT_EXCLUDE = ['*.spec.*', '*.test.*', 'index.*', '*.d.ts'];
23
+ /**
24
+ * Check if a filename matches an exclusion pattern.
25
+ */
26
+ function matchesExcludePattern(filename, patterns) {
27
+ for (const pattern of patterns) {
28
+ // Convert glob pattern to regex
29
+ const regexPattern = pattern.replace(/\./g, '\\.').replace(/\*/g, '.*');
30
+ const regex = new RegExp(`^${regexPattern}$`, 'i');
31
+ if (regex.test(filename)) {
32
+ return true;
33
+ }
34
+ }
35
+ return false;
36
+ }
37
+ /**
38
+ * Determine component type from filename based on patterns.
39
+ */
40
+ function getComponentTypeFromFilename(filename, patterns) {
41
+ const baseName = path.basename(filename);
42
+ // Remove extension for matching
43
+ const nameWithoutExt = baseName.replace(/\.[^.]+$/, '');
44
+ if (nameWithoutExt.endsWith(patterns.collectors))
45
+ return 'collectors';
46
+ if (nameWithoutExt.endsWith(patterns.harvesters))
47
+ return 'harvesters';
48
+ if (nameWithoutExt.endsWith(patterns.handlers))
49
+ return 'handlers';
50
+ if (nameWithoutExt.endsWith(patterns.assetsManagers))
51
+ return 'assetsManagers';
52
+ if (nameWithoutExt.endsWith(patterns.customTableManagers))
53
+ return 'customTableManagers';
54
+ // Also check for *_manager pattern for tileset/map managers
55
+ if (nameWithoutExt.endsWith('_manager') ||
56
+ nameWithoutExt.endsWith('_tileset_manager') ||
57
+ nameWithoutExt.endsWith('_map_manager')) {
58
+ return 'assetsManagers';
59
+ }
60
+ return null;
61
+ }
62
+ /**
63
+ * Check if a value is a class constructor.
64
+ */
65
+ function isClassConstructor(value) {
66
+ return typeof value === 'function' && value.prototype && value.prototype.constructor === value;
67
+ }
68
+ /**
69
+ * Check if an instance is a valid Digital Twin component.
70
+ */
71
+ function isValidComponent(instance) {
72
+ if (!instance || typeof instance !== 'object')
73
+ return false;
74
+ if (typeof instance.getConfiguration !== 'function')
75
+ return false;
76
+ return (isCollector(instance) ||
77
+ isHarvester(instance) ||
78
+ isHandler(instance) ||
79
+ isAssetsManager(instance) ||
80
+ isCustomTableManager(instance));
81
+ }
82
+ /**
83
+ * Recursively scan a directory for component files.
84
+ */
85
+ async function scanDirectory(dir, options) {
86
+ const results = [];
87
+ try {
88
+ const entries = await fs.readdir(dir, { withFileTypes: true });
89
+ for (const entry of entries) {
90
+ const fullPath = path.join(dir, entry.name);
91
+ // Skip hidden files/directories
92
+ if (entry.name.startsWith('.') || entry.name.startsWith('_')) {
93
+ continue;
94
+ }
95
+ if (entry.isDirectory() && options.recursive) {
96
+ const subResults = await scanDirectory(fullPath, options);
97
+ results.push(...subResults);
98
+ }
99
+ else if (entry.isFile()) {
100
+ // Check extension
101
+ const ext = path.extname(entry.name);
102
+ if (!options.extensions.includes(ext)) {
103
+ continue;
104
+ }
105
+ // Check exclusions
106
+ if (matchesExcludePattern(entry.name, options.exclude)) {
107
+ continue;
108
+ }
109
+ // Determine component type
110
+ const componentType = getComponentTypeFromFilename(entry.name, options.patterns);
111
+ if (componentType) {
112
+ results.push({ path: fullPath, type: componentType });
113
+ }
114
+ }
115
+ }
116
+ }
117
+ catch {
118
+ // Directory doesn't exist or can't be read - return empty array
119
+ }
120
+ return results;
121
+ }
122
+ /**
123
+ * Convert a snake_case or kebab-case string to PascalCase.
124
+ */
125
+ function toPascalCase(str) {
126
+ return str
127
+ .split(/[-_]/)
128
+ .map(part => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase())
129
+ .join('');
130
+ }
131
+ /**
132
+ * Auto-discovers and loads Digital Twin components from a directory.
133
+ *
134
+ * This function scans the specified directory for component files following
135
+ * the naming conventions (*_collector.js, *_harvester.js, etc.), dynamically
136
+ * imports them, and instantiates any component classes found.
137
+ *
138
+ * ## Naming Conventions
139
+ *
140
+ * Component files should follow these naming patterns:
141
+ * - Collectors: `*_collector.js` (e.g., `weather_collector.js`)
142
+ * - Harvesters: `*_harvester.js` (e.g., `traffic_harvester.js`)
143
+ * - Handlers: `*_handler.js` (e.g., `api_handler.js`)
144
+ * - Assets Managers: `*_assets_manager.js` (e.g., `gltf_assets_manager.js`)
145
+ * - Custom Table Managers: `*_custom_table.js` (e.g., `wms_custom_table.js`)
146
+ *
147
+ * ## Component Export Requirements
148
+ *
149
+ * Components should be exported as default export or named export matching the class name:
150
+ * ```typescript
151
+ * // Default export (preferred)
152
+ * export default class WeatherCollector extends Collector { ... }
153
+ *
154
+ * // Named export matching file name
155
+ * export class WeatherCollector extends Collector { ... }
156
+ * ```
157
+ *
158
+ * @param directory - Directory path to scan for components (absolute or relative to cwd)
159
+ * @param options - Configuration options for discovery
160
+ * @returns Promise resolving to loaded components and metadata
161
+ *
162
+ * @example
163
+ * ```typescript
164
+ * import { loadComponents, DigitalTwinEngine } from 'digitaltwin-core'
165
+ *
166
+ * // Basic usage - scan compiled components
167
+ * const result = await loadComponents('./dist/components')
168
+ *
169
+ * console.log(`Loaded ${result.summary.total} components`)
170
+ *
171
+ * const engine = new DigitalTwinEngine({ storage, database })
172
+ * engine.registerComponents(result)
173
+ * await engine.start()
174
+ * ```
175
+ *
176
+ * @example
177
+ * ```typescript
178
+ * // Advanced usage with options
179
+ * const result = await loadComponents('./dist/components', {
180
+ * recursive: true,
181
+ * verbose: true,
182
+ * extensions: ['.js'],
183
+ * exclude: ['*.test.*', 'deprecated_*']
184
+ * })
185
+ *
186
+ * if (result.errors.length > 0) {
187
+ * console.warn('Some components failed to load:', result.errors)
188
+ * }
189
+ * ```
190
+ */
191
+ export async function loadComponents(directory, options = {}) {
192
+ const patterns = { ...DEFAULT_PATTERNS, ...options.patterns };
193
+ const extensions = options.extensions ?? DEFAULT_EXTENSIONS;
194
+ const exclude = options.exclude ?? DEFAULT_EXCLUDE;
195
+ const recursive = options.recursive ?? true;
196
+ const verbose = options.verbose ?? false;
197
+ const result = {
198
+ collectors: [],
199
+ harvesters: [],
200
+ handlers: [],
201
+ assetsManagers: [],
202
+ customTableManagers: [],
203
+ scannedFiles: [],
204
+ errors: [],
205
+ summary: {
206
+ total: 0,
207
+ collectors: 0,
208
+ harvesters: 0,
209
+ handlers: 0,
210
+ assetsManagers: 0,
211
+ customTableManagers: 0,
212
+ errors: 0
213
+ }
214
+ };
215
+ // Resolve directory path
216
+ const absoluteDir = path.isAbsolute(directory) ? directory : path.resolve(process.cwd(), directory);
217
+ // Check if directory exists
218
+ try {
219
+ await fs.access(absoluteDir);
220
+ }
221
+ catch {
222
+ if (verbose) {
223
+ console.warn(`[loadComponents] Directory not found: ${absoluteDir}`);
224
+ }
225
+ return result;
226
+ }
227
+ // Scan for component files
228
+ const files = await scanDirectory(absoluteDir, { extensions, exclude, recursive, patterns });
229
+ result.scannedFiles = files.map(f => f.path);
230
+ if (verbose) {
231
+ console.log(`[loadComponents] Found ${files.length} potential component files`);
232
+ }
233
+ // Load each component file
234
+ for (const { path: filePath, type: expectedType } of files) {
235
+ try {
236
+ // Convert to file URL for ESM import
237
+ const fileUrl = pathToFileURL(filePath).href;
238
+ const module = await import(fileUrl);
239
+ // Find component class in module exports
240
+ let ComponentClass = null;
241
+ // Try default export first
242
+ if (module.default && isClassConstructor(module.default)) {
243
+ ComponentClass = module.default;
244
+ }
245
+ else {
246
+ // Try named exports
247
+ const fileName = path.basename(filePath, path.extname(filePath));
248
+ const expectedClassName = toPascalCase(fileName);
249
+ if (module[expectedClassName] && isClassConstructor(module[expectedClassName])) {
250
+ ComponentClass = module[expectedClassName];
251
+ }
252
+ else {
253
+ // Try to find any class export that's a valid component
254
+ for (const [, value] of Object.entries(module)) {
255
+ if (isClassConstructor(value)) {
256
+ try {
257
+ const testInstance = new value();
258
+ if (isValidComponent(testInstance)) {
259
+ ComponentClass = value;
260
+ break;
261
+ }
262
+ }
263
+ catch {
264
+ // Skip if instantiation fails
265
+ }
266
+ }
267
+ }
268
+ }
269
+ }
270
+ if (!ComponentClass) {
271
+ result.errors.push({
272
+ file: filePath,
273
+ error: 'No valid component class found in module exports'
274
+ });
275
+ continue;
276
+ }
277
+ // Instantiate the component
278
+ const instance = new ComponentClass();
279
+ if (!isValidComponent(instance)) {
280
+ result.errors.push({
281
+ file: filePath,
282
+ error: 'Instantiated class is not a valid Digital Twin component'
283
+ });
284
+ continue;
285
+ }
286
+ // Add to appropriate array based on actual type (not expected type)
287
+ if (isCollector(instance)) {
288
+ result.collectors.push(instance);
289
+ result.summary.collectors++;
290
+ }
291
+ else if (isHarvester(instance)) {
292
+ result.harvesters.push(instance);
293
+ result.summary.harvesters++;
294
+ }
295
+ else if (isHandler(instance)) {
296
+ result.handlers.push(instance);
297
+ result.summary.handlers++;
298
+ }
299
+ else if (isCustomTableManager(instance)) {
300
+ result.customTableManagers.push(instance);
301
+ result.summary.customTableManagers++;
302
+ }
303
+ else if (isAssetsManager(instance)) {
304
+ result.assetsManagers.push(instance);
305
+ result.summary.assetsManagers++;
306
+ }
307
+ result.summary.total++;
308
+ if (verbose) {
309
+ const config = instance.getConfiguration();
310
+ console.log(`[loadComponents] Loaded: ${config.name} (${expectedType})`);
311
+ }
312
+ }
313
+ catch (error) {
314
+ const errorMessage = error instanceof Error ? error.message : String(error);
315
+ result.errors.push({
316
+ file: filePath,
317
+ error: `Failed to import: ${errorMessage}`
318
+ });
319
+ result.summary.errors++;
320
+ if (verbose) {
321
+ console.error(`[loadComponents] Error loading ${filePath}:`, errorMessage);
322
+ }
323
+ }
324
+ }
325
+ if (verbose) {
326
+ console.log(`[loadComponents] Summary:`, result.summary);
327
+ }
328
+ return result;
329
+ }
330
+ //# sourceMappingURL=component_loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"component_loader.js","sourceRoot":"","sources":["../../src/loader/component_loader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @fileoverview Component auto-discovery and loading utilities
3
+ *
4
+ * This module provides utilities for automatically discovering and loading
5
+ * Digital Twin components from a directory based on file naming conventions.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { loadComponents } from 'digitaltwin-core'
10
+ *
11
+ * const result = await loadComponents('./dist/components')
12
+ *
13
+ * const engine = new DigitalTwinEngine({ storage, database })
14
+ * engine.registerComponents(result)
15
+ * await engine.start()
16
+ * ```
17
+ */
18
+ export { loadComponents, type LoadComponentsOptions, type LoadComponentsResult } from './component_loader.js';
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/loader/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,cAAc,EAAE,KAAK,qBAAqB,EAAE,KAAK,oBAAoB,EAAE,MAAM,uBAAuB,CAAA"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @fileoverview Component auto-discovery and loading utilities
3
+ *
4
+ * This module provides utilities for automatically discovering and loading
5
+ * Digital Twin components from a directory based on file naming conventions.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { loadComponents } from 'digitaltwin-core'
10
+ *
11
+ * const result = await loadComponents('./dist/components')
12
+ *
13
+ * const engine = new DigitalTwinEngine({ storage, database })
14
+ * engine.registerComponents(result)
15
+ * await engine.start()
16
+ * ```
17
+ */
18
+ export { loadComponents } from './component_loader.js';
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/loader/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,cAAc,EAAyD,MAAM,uBAAuB,CAAA"}
@@ -4,6 +4,7 @@ import { StorageService } from '../storage_service.js';
4
4
  * Saves files in a configured folder using a timestamp as filename.
5
5
  */
6
6
  export declare class LocalStorageService extends StorageService {
7
+ #private;
7
8
  private baseDir;
8
9
  constructor(baseDir?: string);
9
10
  /**
@@ -18,11 +19,13 @@ export declare class LocalStorageService extends StorageService {
18
19
  * Retrieves a file as buffer using its relative path.
19
20
  * @param relativePath - Filename previously returned by `save`
20
21
  * @returns File content as Buffer
22
+ * @throws Error if path traversal is detected
21
23
  */
22
24
  retrieve(relativePath: string): Promise<Buffer>;
23
25
  /**
24
26
  * Deletes a stored file.
25
27
  * @param relativePath - Filename previously returned by `save`
28
+ * @throws Error if path traversal is detected
26
29
  */
27
30
  delete(relativePath: string): Promise<void>;
28
31
  /**
@@ -31,6 +34,7 @@ export declare class LocalStorageService extends StorageService {
31
34
  * @param buffer - Content to save
32
35
  * @param relativePath - Full relative path including filename (e.g., 'tilesets/123/tileset.json')
33
36
  * @returns The same relative path that was provided
37
+ * @throws Error if path traversal is detected
34
38
  */
35
39
  saveWithPath(buffer: Buffer, relativePath: string): Promise<string>;
36
40
  /**
@@ -39,12 +43,14 @@ export declare class LocalStorageService extends StorageService {
39
43
  * In production, use a cloud storage service (OVH, S3) for public URLs.
40
44
  * @param relativePath - The storage path of the file
41
45
  * @returns The file path (relative to baseDir)
46
+ * @throws Error if path traversal is detected
42
47
  */
43
48
  getPublicUrl(relativePath: string): string;
44
49
  /**
45
50
  * Deletes all files under a given prefix (folder).
46
51
  * @param prefix - The folder/prefix to delete (e.g., 'tilesets/123')
47
52
  * @returns Number of files deleted
53
+ * @throws Error if path traversal is detected
48
54
  */
49
55
  deleteByPrefix(prefix: string): Promise<number>;
50
56
  }
@@ -1 +1 @@
1
- {"version":3,"file":"local_storage_service.d.ts","sourceRoot":"","sources":["../../../src/storage/adapters/local_storage_service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAItD;;;GAGG;AACH,qBAAa,mBAAoB,SAAQ,cAAc;IACvC,OAAO,CAAC,OAAO;gBAAP,OAAO,GAAE,MAAe;IAI5C;;;;;;OAMG;IACG,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAetF;;;;OAIG;IACG,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAKrD;;;OAGG;IACG,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKjD;;;;;;OAMG;IACG,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAUzE;;;;;;OAMG;IACH,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;IAM1C;;;;OAIG;IACG,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAgCxD"}
1
+ {"version":3,"file":"local_storage_service.d.ts","sourceRoot":"","sources":["../../../src/storage/adapters/local_storage_service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAItD;;;GAGG;AACH,qBAAa,mBAAoB,SAAQ,cAAc;;IAGvC,OAAO,CAAC,OAAO;gBAAP,OAAO,GAAE,MAAe;IAqB5C;;;;;;OAMG;IACG,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAetF;;;;;OAKG;IACG,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAKrD;;;;OAIG;IACG,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKjD;;;;;;;OAOG;IACG,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAUzE;;;;;;;OAOG;IACH,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;IAQ1C;;;;;OAKG;IACG,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAgCxD"}
@@ -6,9 +6,24 @@ import path from 'path';
6
6
  * Saves files in a configured folder using a timestamp as filename.
7
7
  */
8
8
  export class LocalStorageService extends StorageService {
9
+ #normalizedBase;
9
10
  constructor(baseDir = 'data') {
10
11
  super();
11
12
  this.baseDir = baseDir;
13
+ this.#normalizedBase = path.resolve(this.baseDir);
14
+ }
15
+ /**
16
+ * Validates that a path does not escape the base directory (path traversal protection).
17
+ * @param relativePath - The relative path to validate
18
+ * @returns The resolved absolute path if valid
19
+ * @throws Error if path traversal is detected
20
+ */
21
+ #validatePath(relativePath) {
22
+ const resolved = path.resolve(this.#normalizedBase, relativePath);
23
+ if (!resolved.startsWith(this.#normalizedBase + path.sep) && resolved !== this.#normalizedBase) {
24
+ throw new Error(`Invalid path: path traversal detected for "${relativePath}"`);
25
+ }
26
+ return resolved;
12
27
  }
13
28
  /**
14
29
  * Saves the given buffer to disk under a unique filename.
@@ -33,17 +48,19 @@ export class LocalStorageService extends StorageService {
33
48
  * Retrieves a file as buffer using its relative path.
34
49
  * @param relativePath - Filename previously returned by `save`
35
50
  * @returns File content as Buffer
51
+ * @throws Error if path traversal is detected
36
52
  */
37
53
  async retrieve(relativePath) {
38
- const filePath = path.join(this.baseDir, relativePath);
54
+ const filePath = this.#validatePath(relativePath);
39
55
  return fs.readFile(filePath);
40
56
  }
41
57
  /**
42
58
  * Deletes a stored file.
43
59
  * @param relativePath - Filename previously returned by `save`
60
+ * @throws Error if path traversal is detected
44
61
  */
45
62
  async delete(relativePath) {
46
- const filePath = path.join(this.baseDir, relativePath);
63
+ const filePath = this.#validatePath(relativePath);
47
64
  await fs.rm(filePath, { force: true });
48
65
  }
49
66
  /**
@@ -52,9 +69,10 @@ export class LocalStorageService extends StorageService {
52
69
  * @param buffer - Content to save
53
70
  * @param relativePath - Full relative path including filename (e.g., 'tilesets/123/tileset.json')
54
71
  * @returns The same relative path that was provided
72
+ * @throws Error if path traversal is detected
55
73
  */
56
74
  async saveWithPath(buffer, relativePath) {
57
- const filePath = path.join(this.baseDir, relativePath);
75
+ const filePath = this.#validatePath(relativePath);
58
76
  const dirPath = path.dirname(filePath);
59
77
  await fs.mkdir(dirPath, { recursive: true });
60
78
  await fs.writeFile(filePath, buffer);
@@ -66,8 +84,11 @@ export class LocalStorageService extends StorageService {
66
84
  * In production, use a cloud storage service (OVH, S3) for public URLs.
67
85
  * @param relativePath - The storage path of the file
68
86
  * @returns The file path (relative to baseDir)
87
+ * @throws Error if path traversal is detected
69
88
  */
70
89
  getPublicUrl(relativePath) {
90
+ // Validate path to prevent traversal (even though this just returns a string)
91
+ this.#validatePath(relativePath);
71
92
  // For local storage, return the file path
72
93
  // In a real deployment, you'd need Express static serving or similar
73
94
  return path.join(this.baseDir, relativePath);
@@ -76,9 +97,10 @@ export class LocalStorageService extends StorageService {
76
97
  * Deletes all files under a given prefix (folder).
77
98
  * @param prefix - The folder/prefix to delete (e.g., 'tilesets/123')
78
99
  * @returns Number of files deleted
100
+ * @throws Error if path traversal is detected
79
101
  */
80
102
  async deleteByPrefix(prefix) {
81
- const folderPath = path.join(this.baseDir, prefix);
103
+ const folderPath = this.#validatePath(prefix);
82
104
  try {
83
105
  // Check if folder exists
84
106
  await fs.access(folderPath);