@zintrust/workers 0.1.27

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 (178) hide show
  1. package/README.md +861 -0
  2. package/dist/AnomalyDetection.d.ts +102 -0
  3. package/dist/AnomalyDetection.js +321 -0
  4. package/dist/AutoScaler.d.ts +127 -0
  5. package/dist/AutoScaler.js +425 -0
  6. package/dist/BroadcastWorker.d.ts +21 -0
  7. package/dist/BroadcastWorker.js +24 -0
  8. package/dist/CanaryController.d.ts +103 -0
  9. package/dist/CanaryController.js +380 -0
  10. package/dist/ChaosEngineering.d.ts +79 -0
  11. package/dist/ChaosEngineering.js +216 -0
  12. package/dist/CircuitBreaker.d.ts +106 -0
  13. package/dist/CircuitBreaker.js +374 -0
  14. package/dist/ClusterLock.d.ts +90 -0
  15. package/dist/ClusterLock.js +385 -0
  16. package/dist/ComplianceManager.d.ts +177 -0
  17. package/dist/ComplianceManager.js +556 -0
  18. package/dist/DatacenterOrchestrator.d.ts +133 -0
  19. package/dist/DatacenterOrchestrator.js +404 -0
  20. package/dist/DeadLetterQueue.d.ts +122 -0
  21. package/dist/DeadLetterQueue.js +539 -0
  22. package/dist/HealthMonitor.d.ts +42 -0
  23. package/dist/HealthMonitor.js +301 -0
  24. package/dist/MultiQueueWorker.d.ts +89 -0
  25. package/dist/MultiQueueWorker.js +277 -0
  26. package/dist/NotificationWorker.d.ts +21 -0
  27. package/dist/NotificationWorker.js +23 -0
  28. package/dist/Observability.d.ts +153 -0
  29. package/dist/Observability.js +530 -0
  30. package/dist/PluginManager.d.ts +123 -0
  31. package/dist/PluginManager.js +392 -0
  32. package/dist/PriorityQueue.d.ts +117 -0
  33. package/dist/PriorityQueue.js +244 -0
  34. package/dist/ResourceMonitor.d.ts +164 -0
  35. package/dist/ResourceMonitor.js +605 -0
  36. package/dist/SLAMonitor.d.ts +110 -0
  37. package/dist/SLAMonitor.js +274 -0
  38. package/dist/WorkerFactory.d.ts +193 -0
  39. package/dist/WorkerFactory.js +1507 -0
  40. package/dist/WorkerInit.d.ts +85 -0
  41. package/dist/WorkerInit.js +223 -0
  42. package/dist/WorkerMetrics.d.ts +114 -0
  43. package/dist/WorkerMetrics.js +509 -0
  44. package/dist/WorkerRegistry.d.ts +145 -0
  45. package/dist/WorkerRegistry.js +319 -0
  46. package/dist/WorkerShutdown.d.ts +61 -0
  47. package/dist/WorkerShutdown.js +159 -0
  48. package/dist/WorkerVersioning.d.ts +107 -0
  49. package/dist/WorkerVersioning.js +300 -0
  50. package/dist/build-manifest.json +462 -0
  51. package/dist/config/workerConfig.d.ts +3 -0
  52. package/dist/config/workerConfig.js +19 -0
  53. package/dist/createQueueWorker.d.ts +23 -0
  54. package/dist/createQueueWorker.js +113 -0
  55. package/dist/dashboard/index.d.ts +1 -0
  56. package/dist/dashboard/index.js +1 -0
  57. package/dist/dashboard/types.d.ts +117 -0
  58. package/dist/dashboard/types.js +1 -0
  59. package/dist/dashboard/workers-api.d.ts +4 -0
  60. package/dist/dashboard/workers-api.js +638 -0
  61. package/dist/dashboard/workers-dashboard-ui.d.ts +3 -0
  62. package/dist/dashboard/workers-dashboard-ui.js +1026 -0
  63. package/dist/dashboard/workers-dashboard.d.ts +4 -0
  64. package/dist/dashboard/workers-dashboard.js +904 -0
  65. package/dist/helper/index.d.ts +5 -0
  66. package/dist/helper/index.js +10 -0
  67. package/dist/http/WorkerApiController.d.ts +38 -0
  68. package/dist/http/WorkerApiController.js +312 -0
  69. package/dist/http/WorkerController.d.ts +374 -0
  70. package/dist/http/WorkerController.js +1351 -0
  71. package/dist/http/middleware/CustomValidation.d.ts +92 -0
  72. package/dist/http/middleware/CustomValidation.js +270 -0
  73. package/dist/http/middleware/DatacenterValidator.d.ts +3 -0
  74. package/dist/http/middleware/DatacenterValidator.js +94 -0
  75. package/dist/http/middleware/EditWorkerValidation.d.ts +7 -0
  76. package/dist/http/middleware/EditWorkerValidation.js +55 -0
  77. package/dist/http/middleware/FeaturesValidator.d.ts +3 -0
  78. package/dist/http/middleware/FeaturesValidator.js +60 -0
  79. package/dist/http/middleware/InfrastructureValidator.d.ts +31 -0
  80. package/dist/http/middleware/InfrastructureValidator.js +226 -0
  81. package/dist/http/middleware/OptionsValidator.d.ts +3 -0
  82. package/dist/http/middleware/OptionsValidator.js +112 -0
  83. package/dist/http/middleware/PayloadSanitizer.d.ts +7 -0
  84. package/dist/http/middleware/PayloadSanitizer.js +42 -0
  85. package/dist/http/middleware/ProcessorPathSanitizer.d.ts +3 -0
  86. package/dist/http/middleware/ProcessorPathSanitizer.js +74 -0
  87. package/dist/http/middleware/QueueNameSanitizer.d.ts +3 -0
  88. package/dist/http/middleware/QueueNameSanitizer.js +45 -0
  89. package/dist/http/middleware/ValidateDriver.d.ts +7 -0
  90. package/dist/http/middleware/ValidateDriver.js +20 -0
  91. package/dist/http/middleware/VersionSanitizer.d.ts +3 -0
  92. package/dist/http/middleware/VersionSanitizer.js +25 -0
  93. package/dist/http/middleware/WorkerNameSanitizer.d.ts +3 -0
  94. package/dist/http/middleware/WorkerNameSanitizer.js +46 -0
  95. package/dist/http/middleware/WorkerValidationChain.d.ts +27 -0
  96. package/dist/http/middleware/WorkerValidationChain.js +185 -0
  97. package/dist/index.d.ts +46 -0
  98. package/dist/index.js +48 -0
  99. package/dist/routes/workers.d.ts +12 -0
  100. package/dist/routes/workers.js +81 -0
  101. package/dist/storage/WorkerStore.d.ts +45 -0
  102. package/dist/storage/WorkerStore.js +195 -0
  103. package/dist/type.d.ts +76 -0
  104. package/dist/type.js +1 -0
  105. package/dist/ui/router/ui.d.ts +3 -0
  106. package/dist/ui/router/ui.js +83 -0
  107. package/dist/ui/types/worker-ui.d.ts +229 -0
  108. package/dist/ui/types/worker-ui.js +5 -0
  109. package/package.json +53 -0
  110. package/src/AnomalyDetection.ts +434 -0
  111. package/src/AutoScaler.ts +654 -0
  112. package/src/BroadcastWorker.ts +34 -0
  113. package/src/CanaryController.ts +531 -0
  114. package/src/ChaosEngineering.ts +301 -0
  115. package/src/CircuitBreaker.ts +495 -0
  116. package/src/ClusterLock.ts +499 -0
  117. package/src/ComplianceManager.ts +815 -0
  118. package/src/DatacenterOrchestrator.ts +561 -0
  119. package/src/DeadLetterQueue.ts +733 -0
  120. package/src/HealthMonitor.ts +390 -0
  121. package/src/MultiQueueWorker.ts +431 -0
  122. package/src/NotificationWorker.ts +33 -0
  123. package/src/Observability.ts +696 -0
  124. package/src/PluginManager.ts +551 -0
  125. package/src/PriorityQueue.ts +351 -0
  126. package/src/ResourceMonitor.ts +769 -0
  127. package/src/SLAMonitor.ts +408 -0
  128. package/src/WorkerFactory.ts +2108 -0
  129. package/src/WorkerInit.ts +313 -0
  130. package/src/WorkerMetrics.ts +709 -0
  131. package/src/WorkerRegistry.ts +443 -0
  132. package/src/WorkerShutdown.ts +210 -0
  133. package/src/WorkerVersioning.ts +422 -0
  134. package/src/config/workerConfig.ts +25 -0
  135. package/src/createQueueWorker.ts +174 -0
  136. package/src/dashboard/index.ts +6 -0
  137. package/src/dashboard/types.ts +141 -0
  138. package/src/dashboard/workers-api.ts +785 -0
  139. package/src/dashboard/zintrust.svg +30 -0
  140. package/src/helper/index.ts +11 -0
  141. package/src/http/WorkerApiController.ts +369 -0
  142. package/src/http/WorkerController.ts +1512 -0
  143. package/src/http/middleware/CustomValidation.ts +360 -0
  144. package/src/http/middleware/DatacenterValidator.ts +124 -0
  145. package/src/http/middleware/EditWorkerValidation.ts +74 -0
  146. package/src/http/middleware/FeaturesValidator.ts +82 -0
  147. package/src/http/middleware/InfrastructureValidator.ts +295 -0
  148. package/src/http/middleware/OptionsValidator.ts +144 -0
  149. package/src/http/middleware/PayloadSanitizer.ts +52 -0
  150. package/src/http/middleware/ProcessorPathSanitizer.ts +86 -0
  151. package/src/http/middleware/QueueNameSanitizer.ts +55 -0
  152. package/src/http/middleware/ValidateDriver.ts +29 -0
  153. package/src/http/middleware/VersionSanitizer.ts +30 -0
  154. package/src/http/middleware/WorkerNameSanitizer.ts +56 -0
  155. package/src/http/middleware/WorkerValidationChain.ts +230 -0
  156. package/src/index.ts +98 -0
  157. package/src/routes/workers.ts +154 -0
  158. package/src/storage/WorkerStore.ts +240 -0
  159. package/src/type.ts +89 -0
  160. package/src/types/queue-monitor.d.ts +38 -0
  161. package/src/types/queue-redis.d.ts +38 -0
  162. package/src/ui/README.md +13 -0
  163. package/src/ui/components/JsonEditor.js +670 -0
  164. package/src/ui/components/JsonViewer.js +387 -0
  165. package/src/ui/components/WorkerCard.js +178 -0
  166. package/src/ui/components/WorkerExpandPanel.js +257 -0
  167. package/src/ui/components/fetcher.js +42 -0
  168. package/src/ui/components/sla-scorecard.js +32 -0
  169. package/src/ui/components/styles.css +30 -0
  170. package/src/ui/components/table-expander.js +34 -0
  171. package/src/ui/integration/worker-ui-integration.js +565 -0
  172. package/src/ui/router/ui.ts +99 -0
  173. package/src/ui/services/workerApi.js +240 -0
  174. package/src/ui/types/worker-ui.ts +283 -0
  175. package/src/ui/utils/jsonValidator.js +444 -0
  176. package/src/ui/workers/index.html +202 -0
  177. package/src/ui/workers/main.js +1781 -0
  178. package/src/ui/workers/styles.css +1350 -0
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Plugin Manager
3
+ * Extensible plugin system with lifecycle hooks
4
+ * Sealed namespace for immutability
5
+ */
6
+ export type PluginHook = 'beforeStart' | 'afterStart' | 'beforeProcess' | 'afterProcess' | 'beforeStop' | 'afterStop' | 'onError' | 'onComplete' | 'onRetry' | 'onCircuitOpen' | 'onCircuitClose' | 'onScaleUp' | 'onScaleDown';
7
+ export type HookContext = {
8
+ workerName: string;
9
+ jobId?: string;
10
+ version?: string;
11
+ jobData?: unknown;
12
+ error?: Error;
13
+ metadata?: Record<string, unknown>;
14
+ timestamp: Date;
15
+ };
16
+ export type HookResult = {
17
+ modified?: boolean;
18
+ jobData?: unknown;
19
+ stop?: boolean;
20
+ error?: Error;
21
+ };
22
+ export type PluginMetadata = {
23
+ name: string;
24
+ version: string;
25
+ author?: string;
26
+ description?: string;
27
+ dependencies?: string[];
28
+ };
29
+ export type Plugin = {
30
+ metadata: PluginMetadata;
31
+ hooks: Partial<Record<PluginHook, PluginHookHandler>>;
32
+ onEnable?: () => void | Promise<void>;
33
+ onDisable?: () => void | Promise<void>;
34
+ };
35
+ export type PluginHookHandler = (context: HookContext) => HookResult | Promise<HookResult> | undefined | Promise<HookResult | undefined>;
36
+ export type RegisteredPlugin = {
37
+ plugin: Plugin;
38
+ enabled: boolean;
39
+ registeredAt: Date;
40
+ priority: number;
41
+ };
42
+ export type HookExecutionResult = {
43
+ data: unknown;
44
+ hook: PluginHook;
45
+ executionTime: number;
46
+ pluginsExecuted: number;
47
+ errors: Array<{
48
+ pluginName: string;
49
+ error: Error;
50
+ }>;
51
+ context: HookContext;
52
+ modified: boolean;
53
+ stopped: boolean;
54
+ };
55
+ /**
56
+ * Plugin Manager - Sealed namespace
57
+ */
58
+ export declare const PluginManager: Readonly<{
59
+ /**
60
+ * Register a plugin
61
+ */
62
+ register(plugin: Plugin, priority?: number): Promise<void>;
63
+ /**
64
+ * Unregister a plugin
65
+ */
66
+ unregister(pluginName: string): Promise<void>;
67
+ /**
68
+ * Enable a plugin
69
+ */
70
+ enable(pluginName: string): Promise<void>;
71
+ /**
72
+ * Disable a plugin
73
+ */
74
+ disable(pluginName: string): Promise<void>;
75
+ /**
76
+ * Execute hooks for a lifecycle event
77
+ */
78
+ executeHook(hook: PluginHook, context: HookContext): Promise<HookExecutionResult>;
79
+ /**
80
+ * Get registered plugins
81
+ */
82
+ getPlugins(): ReadonlyArray<RegisteredPlugin & {
83
+ name: string;
84
+ }>;
85
+ /**
86
+ * Get plugin by name
87
+ */
88
+ getPlugin(pluginName: string): (RegisteredPlugin & {
89
+ name: string;
90
+ }) | null;
91
+ /**
92
+ * Check if plugin is registered
93
+ */
94
+ isRegistered(pluginName: string): boolean;
95
+ /**
96
+ * Check if plugin is enabled
97
+ */
98
+ isEnabled(pluginName: string): boolean;
99
+ /**
100
+ * Get hook execution history
101
+ */
102
+ getExecutionHistory(hook?: PluginHook, limit?: number): ReadonlyArray<HookExecutionResult>;
103
+ /**
104
+ * Get plugin statistics
105
+ */
106
+ getStatistics(): {
107
+ totalPlugins: number;
108
+ enabledPlugins: number;
109
+ disabledPlugins: number;
110
+ totalHookExecutions: number;
111
+ hookExecutionsByType: Record<PluginHook, number>;
112
+ averageExecutionTime: number;
113
+ totalErrors: number;
114
+ };
115
+ /**
116
+ * Clear execution history
117
+ */
118
+ clearHistory(): void;
119
+ /**
120
+ * Shutdown and disable all plugins
121
+ */
122
+ shutdown(): Promise<void>;
123
+ }>;
@@ -0,0 +1,392 @@
1
+ /**
2
+ * Plugin Manager
3
+ * Extensible plugin system with lifecycle hooks
4
+ * Sealed namespace for immutability
5
+ */
6
+ import { ErrorFactory, Logger } from '@zintrust/core';
7
+ // Internal state
8
+ const plugins = new Map();
9
+ const hookExecutionHistory = [];
10
+ const MAX_HISTORY = 1000;
11
+ /**
12
+ * Helper: Validate plugin metadata
13
+ */
14
+ const validatePlugin = (plugin) => {
15
+ if (!plugin.metadata.name) {
16
+ throw ErrorFactory.createWorkerError('Plugin name is required');
17
+ }
18
+ if (!plugin.metadata.version) {
19
+ throw ErrorFactory.createWorkerError('Plugin version is required');
20
+ }
21
+ if (Object.keys(plugin.hooks).length === 0) {
22
+ throw ErrorFactory.createWorkerError('Plugin must implement at least one hook');
23
+ }
24
+ };
25
+ /**
26
+ * Helper: Check plugin dependencies
27
+ */
28
+ const checkDependencies = (plugin) => {
29
+ if (!plugin.metadata.dependencies || plugin.metadata.dependencies.length === 0) {
30
+ return { satisfied: true, missing: [] };
31
+ }
32
+ const missing = [];
33
+ for (const depName of plugin.metadata.dependencies) {
34
+ const dep = plugins.get(depName);
35
+ if (dep?.enabled !== true) {
36
+ missing.push(depName);
37
+ }
38
+ }
39
+ return {
40
+ satisfied: missing.length === 0,
41
+ missing,
42
+ };
43
+ };
44
+ /**
45
+ * Helper: Get enabled plugins for a hook, sorted by priority
46
+ */
47
+ const getEnabledPluginsForHook = (hook) => {
48
+ const enabledPlugins = [];
49
+ for (const registered of plugins.values()) {
50
+ if (registered.enabled && registered.plugin.hooks[hook]) {
51
+ enabledPlugins.push(registered);
52
+ }
53
+ }
54
+ // Sort by priority (lower number = higher priority)
55
+ return enabledPlugins.sort((a, b) => a.priority - b.priority);
56
+ };
57
+ /**
58
+ * Helper: Store execution result
59
+ */
60
+ const storeExecutionResult = (result) => {
61
+ hookExecutionHistory.push(result);
62
+ // Keep only last MAX_HISTORY results
63
+ if (hookExecutionHistory.length > MAX_HISTORY) {
64
+ hookExecutionHistory.shift();
65
+ }
66
+ };
67
+ /**
68
+ * Plugin Manager - Sealed namespace
69
+ */
70
+ export const PluginManager = Object.freeze({
71
+ /**
72
+ * Register a plugin
73
+ */
74
+ async register(plugin, priority = 100) {
75
+ validatePlugin(plugin);
76
+ const { name } = plugin.metadata;
77
+ if (plugins.has(name)) {
78
+ throw ErrorFactory.createWorkerError(`Plugin "${name}" is already registered`);
79
+ }
80
+ // Check dependencies
81
+ const depCheck = checkDependencies(plugin);
82
+ if (!depCheck.satisfied) {
83
+ throw ErrorFactory.createWorkerError(`Plugin "${name}" has unsatisfied dependencies: ${depCheck.missing.join(', ')}`);
84
+ }
85
+ const registered = {
86
+ plugin,
87
+ enabled: true,
88
+ registeredAt: new Date(),
89
+ priority,
90
+ };
91
+ plugins.set(name, registered);
92
+ // Call onEnable if provided
93
+ if (plugin.onEnable) {
94
+ try {
95
+ await plugin.onEnable();
96
+ }
97
+ catch (error) {
98
+ Logger.error(`Plugin "${name}" onEnable failed`, error);
99
+ plugins.delete(name);
100
+ throw error;
101
+ }
102
+ }
103
+ Logger.info(`Plugin registered: ${name}@${plugin.metadata.version}`, {
104
+ hooks: Object.keys(plugin.hooks),
105
+ priority,
106
+ });
107
+ },
108
+ /**
109
+ * Unregister a plugin
110
+ */
111
+ async unregister(pluginName) {
112
+ const registered = plugins.get(pluginName);
113
+ if (!registered) {
114
+ throw ErrorFactory.createNotFoundError(`Plugin "${pluginName}" not found`);
115
+ }
116
+ // Check if other plugins depend on this one
117
+ const dependents = [];
118
+ for (const [name, reg] of plugins.entries()) {
119
+ if (name !== pluginName && reg.enabled) {
120
+ const deps = reg.plugin.metadata.dependencies ?? [];
121
+ if (deps.includes(pluginName)) {
122
+ dependents.push(name);
123
+ }
124
+ }
125
+ }
126
+ if (dependents.length > 0) {
127
+ throw ErrorFactory.createWorkerError(`Cannot unregister plugin "${pluginName}": required by ${dependents.join(', ')}`);
128
+ }
129
+ // Call onDisable if provided
130
+ if (registered.plugin.onDisable) {
131
+ try {
132
+ await registered.plugin.onDisable();
133
+ }
134
+ catch (error) {
135
+ Logger.error(`Plugin "${pluginName}" onDisable failed`, error);
136
+ }
137
+ }
138
+ plugins.delete(pluginName);
139
+ Logger.info(`Plugin unregistered: ${pluginName}`);
140
+ },
141
+ /**
142
+ * Enable a plugin
143
+ */
144
+ async enable(pluginName) {
145
+ const registered = plugins.get(pluginName);
146
+ if (!registered) {
147
+ throw ErrorFactory.createNotFoundError(`Plugin "${pluginName}" not found`);
148
+ }
149
+ if (registered.enabled) {
150
+ Logger.warn(`Plugin "${pluginName}" is already enabled`);
151
+ return;
152
+ }
153
+ // Check dependencies
154
+ const depCheck = checkDependencies(registered.plugin);
155
+ if (!depCheck.satisfied) {
156
+ throw ErrorFactory.createWorkerError(`Cannot enable plugin "${pluginName}": unsatisfied dependencies: ${depCheck.missing.join(', ')}`);
157
+ }
158
+ registered.enabled = true;
159
+ // Call onEnable if provided
160
+ if (registered.plugin.onEnable) {
161
+ try {
162
+ await registered.plugin.onEnable();
163
+ }
164
+ catch (error) {
165
+ Logger.error(`Plugin "${pluginName}" onEnable failed`, error);
166
+ registered.enabled = false;
167
+ throw error;
168
+ }
169
+ }
170
+ Logger.info(`Plugin enabled: ${pluginName}`);
171
+ },
172
+ /**
173
+ * Disable a plugin
174
+ */
175
+ async disable(pluginName) {
176
+ const registered = plugins.get(pluginName);
177
+ if (!registered) {
178
+ throw ErrorFactory.createNotFoundError(`Plugin "${pluginName}" not found`);
179
+ }
180
+ if (!registered.enabled) {
181
+ Logger.warn(`Plugin "${pluginName}" is already disabled`);
182
+ return;
183
+ }
184
+ // Check if other enabled plugins depend on this one
185
+ const dependents = [];
186
+ for (const [name, reg] of plugins.entries()) {
187
+ if (name !== pluginName && reg.enabled) {
188
+ const deps = reg.plugin.metadata.dependencies ?? [];
189
+ if (deps.includes(pluginName)) {
190
+ dependents.push(name);
191
+ }
192
+ }
193
+ }
194
+ if (dependents.length > 0) {
195
+ throw ErrorFactory.createWorkerError(`Cannot disable plugin "${pluginName}": required by enabled plugins: ${dependents.join(', ')}`);
196
+ }
197
+ registered.enabled = false;
198
+ // Call onDisable if provided
199
+ if (registered.plugin.onDisable) {
200
+ try {
201
+ await registered.plugin.onDisable();
202
+ }
203
+ catch (error) {
204
+ Logger.error(`Plugin "${pluginName}" onDisable failed`, error);
205
+ }
206
+ }
207
+ Logger.info(`Plugin disabled: ${pluginName}`);
208
+ },
209
+ /**
210
+ * Execute hooks for a lifecycle event
211
+ */
212
+ async executeHook(hook, context) {
213
+ const startTime = Date.now();
214
+ const enabledPlugins = getEnabledPluginsForHook(hook);
215
+ const result = {
216
+ data: context.jobData,
217
+ hook,
218
+ executionTime: 0,
219
+ pluginsExecuted: 0,
220
+ errors: [],
221
+ context,
222
+ modified: false,
223
+ stopped: false,
224
+ };
225
+ const currentContext = { ...context };
226
+ let stopped = false;
227
+ const executeHandler = async (registered) => {
228
+ if (stopped)
229
+ return;
230
+ const { plugin } = registered;
231
+ const handler = plugin.hooks[hook];
232
+ if (!handler)
233
+ return;
234
+ try {
235
+ const hookResult = await handler(currentContext);
236
+ result.pluginsExecuted++;
237
+ if (hookResult !== undefined) {
238
+ if (hookResult.modified === true) {
239
+ result.modified = true;
240
+ }
241
+ if (hookResult.jobData !== undefined) {
242
+ currentContext.jobData = hookResult.jobData;
243
+ result.data = hookResult.jobData;
244
+ }
245
+ if (hookResult.stop === true) {
246
+ result.stopped = true;
247
+ stopped = true;
248
+ Logger.warn(`Hook execution stopped by plugin: ${plugin.metadata.name}`, { hook });
249
+ }
250
+ if (hookResult.error instanceof Error) {
251
+ result.errors.push({
252
+ pluginName: plugin.metadata.name,
253
+ error: hookResult.error,
254
+ });
255
+ }
256
+ }
257
+ }
258
+ catch (error) {
259
+ Logger.error(`Plugin "${plugin.metadata.name}" hook "${hook}" failed`, error);
260
+ result.errors.push({
261
+ pluginName: plugin.metadata.name,
262
+ error: error,
263
+ });
264
+ if (hook === 'beforeStart' || hook === 'beforeStop') {
265
+ result.stopped = true;
266
+ stopped = true;
267
+ }
268
+ }
269
+ };
270
+ let chain = Promise.resolve();
271
+ for (const registered of enabledPlugins) {
272
+ chain = chain.then(async () => executeHandler(registered));
273
+ }
274
+ await chain;
275
+ result.executionTime = Date.now() - startTime;
276
+ storeExecutionResult(result);
277
+ Logger.debug(`Hook executed: ${hook}`, {
278
+ pluginsExecuted: result.pluginsExecuted,
279
+ executionTime: result.executionTime,
280
+ errors: result.errors.length,
281
+ });
282
+ return result;
283
+ },
284
+ /**
285
+ * Get registered plugins
286
+ */
287
+ getPlugins() {
288
+ return Array.from(plugins.entries()).map(([name, registered]) => ({
289
+ name,
290
+ ...registered,
291
+ }));
292
+ },
293
+ /**
294
+ * Get plugin by name
295
+ */
296
+ getPlugin(pluginName) {
297
+ const registered = plugins.get(pluginName);
298
+ if (!registered)
299
+ return null;
300
+ return {
301
+ name: pluginName,
302
+ ...registered,
303
+ };
304
+ },
305
+ /**
306
+ * Check if plugin is registered
307
+ */
308
+ isRegistered(pluginName) {
309
+ return plugins.has(pluginName);
310
+ },
311
+ /**
312
+ * Check if plugin is enabled
313
+ */
314
+ isEnabled(pluginName) {
315
+ const registered = plugins.get(pluginName);
316
+ return registered ? registered.enabled : false;
317
+ },
318
+ /**
319
+ * Get hook execution history
320
+ */
321
+ getExecutionHistory(hook, limit = 100) {
322
+ let history = hookExecutionHistory;
323
+ if (hook) {
324
+ history = history.filter((result) => result.hook === hook);
325
+ }
326
+ return history.slice(-limit).map((result) => ({ ...result }));
327
+ },
328
+ /**
329
+ * Get plugin statistics
330
+ */
331
+ getStatistics() {
332
+ const stats = {
333
+ totalPlugins: plugins.size,
334
+ enabledPlugins: 0,
335
+ disabledPlugins: 0,
336
+ totalHookExecutions: hookExecutionHistory.length,
337
+ hookExecutionsByType: {},
338
+ averageExecutionTime: 0,
339
+ totalErrors: 0,
340
+ };
341
+ for (const registered of plugins.values()) {
342
+ if (registered.enabled) {
343
+ stats.enabledPlugins++;
344
+ }
345
+ else {
346
+ stats.disabledPlugins++;
347
+ }
348
+ }
349
+ let totalExecutionTime = 0;
350
+ for (const result of hookExecutionHistory) {
351
+ const hookType = result.hook;
352
+ stats.hookExecutionsByType[hookType] = (stats.hookExecutionsByType[hookType] || 0) + 1;
353
+ totalExecutionTime += result.executionTime;
354
+ stats.totalErrors += result.errors.length;
355
+ }
356
+ if (hookExecutionHistory.length > 0) {
357
+ stats.averageExecutionTime = totalExecutionTime / hookExecutionHistory.length;
358
+ }
359
+ return stats;
360
+ },
361
+ /**
362
+ * Clear execution history
363
+ */
364
+ clearHistory() {
365
+ hookExecutionHistory.length = 0;
366
+ Logger.info('Plugin execution history cleared');
367
+ },
368
+ /**
369
+ * Shutdown and disable all plugins
370
+ */
371
+ async shutdown() {
372
+ Logger.info('PluginManager shutting down...');
373
+ // Disable all plugins in reverse order of priority
374
+ const sortedPlugins = Array.from(plugins.entries()).sort(([, a], [, b]) => b.priority - a.priority);
375
+ const disableTasks = sortedPlugins.map(async ([name, registered]) => {
376
+ if (!registered.enabled || !registered.plugin.onDisable)
377
+ return;
378
+ try {
379
+ await registered.plugin.onDisable();
380
+ Logger.debug(`Plugin disabled: ${name}`);
381
+ }
382
+ catch (error) {
383
+ Logger.error(`Plugin "${name}" onDisable failed during shutdown`, error);
384
+ }
385
+ });
386
+ await Promise.allSettled(disableTasks);
387
+ plugins.clear();
388
+ hookExecutionHistory.length = 0;
389
+ Logger.info('PluginManager shutdown complete');
390
+ },
391
+ });
392
+ // Graceful shutdown handled by WorkerShutdown
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Priority Queue Manager
3
+ * BullMQ priority levels with datacenter affinity
4
+ * Sealed namespace for immutability
5
+ */
6
+ import { type RedisConfig } from '@zintrust/core';
7
+ import type { Queue } from 'bullmq';
8
+ export type PriorityLevel = 'critical' | 'high' | 'normal' | 'low';
9
+ export type JobPriority = {
10
+ level: PriorityLevel;
11
+ value: number;
12
+ };
13
+ export type DatacenterAffinity = {
14
+ preferred: string[];
15
+ fallback: string[];
16
+ };
17
+ export type PriorityJobOptions = {
18
+ priority: PriorityLevel;
19
+ datacenter?: DatacenterAffinity;
20
+ delay?: number;
21
+ attempts?: number;
22
+ backoff?: {
23
+ type: 'exponential' | 'fixed';
24
+ delay: number;
25
+ };
26
+ removeOnComplete?: boolean | number;
27
+ removeOnFail?: boolean | number;
28
+ };
29
+ export type QueueInfo = {
30
+ name: string;
31
+ isPaused: boolean;
32
+ jobCounts: {
33
+ active: number;
34
+ waiting: number;
35
+ completed: number;
36
+ failed: number;
37
+ delayed: number;
38
+ paused: number;
39
+ };
40
+ };
41
+ /**
42
+ * Priority Queue Manager - Sealed namespace
43
+ */
44
+ export declare const PriorityQueue: Readonly<{
45
+ /**
46
+ * Initialize with Redis configuration
47
+ */
48
+ initialize(_config: RedisConfig): void;
49
+ /**
50
+ * Add a job to the queue with priority
51
+ */
52
+ addJob<T = unknown>(queueName: string, jobName: string, data: T, options: PriorityJobOptions): Promise<string>;
53
+ /**
54
+ * Add multiple jobs in bulk
55
+ */
56
+ addBulk<T = unknown>(queueName: string, jobs: Array<{
57
+ name: string;
58
+ data: T;
59
+ options: PriorityJobOptions;
60
+ }>): Promise<string[]>;
61
+ /**
62
+ * Get job by ID
63
+ */
64
+ getJob(queueName: string, jobId: string): Promise<import("bullmq").Job<any, any, string>>;
65
+ /**
66
+ * Remove a job
67
+ */
68
+ removeJob(queueName: string, jobId: string): Promise<void>;
69
+ /**
70
+ * Pause a queue
71
+ */
72
+ pause(queueName: string): Promise<void>;
73
+ /**
74
+ * Resume a queue
75
+ */
76
+ resume(queueName: string): Promise<void>;
77
+ /**
78
+ * Get queue information
79
+ */
80
+ getQueueInfo(queueName: string): Promise<QueueInfo>;
81
+ /**
82
+ * Get all queue names
83
+ */
84
+ getQueueNames(): string[];
85
+ /**
86
+ * Drain queue (remove all jobs)
87
+ */
88
+ drain(queueName: string, delayed?: boolean): Promise<void>;
89
+ /**
90
+ * Clean old jobs from queue
91
+ */
92
+ clean(queueName: string, grace: number, limit: number, type?: "completed" | "failed" | "delayed" | "wait" | "active" | "paused"): Promise<string[]>;
93
+ /**
94
+ * Obliterate queue (remove all data including queue itself)
95
+ */
96
+ obliterate(queueName: string, force?: boolean): Promise<void>;
97
+ /**
98
+ * Get priority value for level
99
+ */
100
+ getPriorityValue(level: PriorityLevel): number;
101
+ /**
102
+ * Check if job matches datacenter affinity
103
+ */
104
+ matchesDatacenter(jobDatacenter: DatacenterAffinity | undefined, workerRegion: string): boolean;
105
+ /**
106
+ * Get queue instance (internal use)
107
+ */
108
+ getQueueInstance(queueName: string): Queue;
109
+ /**
110
+ * Close a queue
111
+ */
112
+ closeQueue(queueName: string): Promise<void>;
113
+ /**
114
+ * Shutdown and close all queues
115
+ */
116
+ shutdown(): Promise<void>;
117
+ }>;