@creact-labs/creact 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 (103) hide show
  1. package/LICENSE +212 -0
  2. package/README.md +379 -0
  3. package/dist/cli/commands/BuildCommand.d.ts +40 -0
  4. package/dist/cli/commands/BuildCommand.js +151 -0
  5. package/dist/cli/commands/DeployCommand.d.ts +38 -0
  6. package/dist/cli/commands/DeployCommand.js +194 -0
  7. package/dist/cli/commands/DevCommand.d.ts +52 -0
  8. package/dist/cli/commands/DevCommand.js +385 -0
  9. package/dist/cli/commands/PlanCommand.d.ts +39 -0
  10. package/dist/cli/commands/PlanCommand.js +164 -0
  11. package/dist/cli/commands/index.d.ts +36 -0
  12. package/dist/cli/commands/index.js +43 -0
  13. package/dist/cli/core/ArgumentParser.d.ts +46 -0
  14. package/dist/cli/core/ArgumentParser.js +127 -0
  15. package/dist/cli/core/BaseCommand.d.ts +75 -0
  16. package/dist/cli/core/BaseCommand.js +95 -0
  17. package/dist/cli/core/CLIContext.d.ts +68 -0
  18. package/dist/cli/core/CLIContext.js +183 -0
  19. package/dist/cli/core/CommandRegistry.d.ts +64 -0
  20. package/dist/cli/core/CommandRegistry.js +89 -0
  21. package/dist/cli/core/index.d.ts +36 -0
  22. package/dist/cli/core/index.js +43 -0
  23. package/dist/cli/index.d.ts +35 -0
  24. package/dist/cli/index.js +100 -0
  25. package/dist/cli/output.d.ts +204 -0
  26. package/dist/cli/output.js +437 -0
  27. package/dist/cli/utils.d.ts +59 -0
  28. package/dist/cli/utils.js +76 -0
  29. package/dist/context/createContext.d.ts +90 -0
  30. package/dist/context/createContext.js +113 -0
  31. package/dist/context/index.d.ts +30 -0
  32. package/dist/context/index.js +35 -0
  33. package/dist/core/CReact.d.ts +409 -0
  34. package/dist/core/CReact.js +1127 -0
  35. package/dist/core/CloudDOMBuilder.d.ts +429 -0
  36. package/dist/core/CloudDOMBuilder.js +1198 -0
  37. package/dist/core/ContextDependencyTracker.d.ts +165 -0
  38. package/dist/core/ContextDependencyTracker.js +448 -0
  39. package/dist/core/ErrorRecoveryManager.d.ts +145 -0
  40. package/dist/core/ErrorRecoveryManager.js +443 -0
  41. package/dist/core/EventBus.d.ts +91 -0
  42. package/dist/core/EventBus.js +185 -0
  43. package/dist/core/ProviderOutputTracker.d.ts +211 -0
  44. package/dist/core/ProviderOutputTracker.js +476 -0
  45. package/dist/core/ReactiveUpdateQueue.d.ts +76 -0
  46. package/dist/core/ReactiveUpdateQueue.js +121 -0
  47. package/dist/core/Reconciler.d.ts +415 -0
  48. package/dist/core/Reconciler.js +1037 -0
  49. package/dist/core/RenderScheduler.d.ts +153 -0
  50. package/dist/core/RenderScheduler.js +519 -0
  51. package/dist/core/Renderer.d.ts +276 -0
  52. package/dist/core/Renderer.js +791 -0
  53. package/dist/core/Runtime.d.ts +246 -0
  54. package/dist/core/Runtime.js +640 -0
  55. package/dist/core/StateBindingManager.d.ts +121 -0
  56. package/dist/core/StateBindingManager.js +309 -0
  57. package/dist/core/StateMachine.d.ts +424 -0
  58. package/dist/core/StateMachine.js +787 -0
  59. package/dist/core/StructuralChangeDetector.d.ts +140 -0
  60. package/dist/core/StructuralChangeDetector.js +363 -0
  61. package/dist/core/Validator.d.ts +127 -0
  62. package/dist/core/Validator.js +279 -0
  63. package/dist/core/errors.d.ts +153 -0
  64. package/dist/core/errors.js +202 -0
  65. package/dist/core/index.d.ts +38 -0
  66. package/dist/core/index.js +64 -0
  67. package/dist/core/types.d.ts +263 -0
  68. package/dist/core/types.js +48 -0
  69. package/dist/hooks/context.d.ts +147 -0
  70. package/dist/hooks/context.js +334 -0
  71. package/dist/hooks/useContext.d.ts +113 -0
  72. package/dist/hooks/useContext.js +169 -0
  73. package/dist/hooks/useEffect.d.ts +105 -0
  74. package/dist/hooks/useEffect.js +540 -0
  75. package/dist/hooks/useInstance.d.ts +139 -0
  76. package/dist/hooks/useInstance.js +441 -0
  77. package/dist/hooks/useState.d.ts +120 -0
  78. package/dist/hooks/useState.js +298 -0
  79. package/dist/index.d.ts +46 -0
  80. package/dist/index.js +70 -0
  81. package/dist/jsx.d.ts +64 -0
  82. package/dist/jsx.js +76 -0
  83. package/dist/providers/DummyBackendProvider.d.ts +193 -0
  84. package/dist/providers/DummyBackendProvider.js +189 -0
  85. package/dist/providers/DummyCloudProvider.d.ts +128 -0
  86. package/dist/providers/DummyCloudProvider.js +157 -0
  87. package/dist/providers/IBackendProvider.d.ts +177 -0
  88. package/dist/providers/IBackendProvider.js +31 -0
  89. package/dist/providers/ICloudProvider.d.ts +146 -0
  90. package/dist/providers/ICloudProvider.js +31 -0
  91. package/dist/providers/index.d.ts +31 -0
  92. package/dist/providers/index.js +31 -0
  93. package/dist/test-event-callbacks.d.ts +0 -0
  94. package/dist/test-event-callbacks.js +1 -0
  95. package/dist/utils/Logger.d.ts +144 -0
  96. package/dist/utils/Logger.js +220 -0
  97. package/dist/utils/Output.d.ts +161 -0
  98. package/dist/utils/Output.js +401 -0
  99. package/dist/utils/deepEqual.d.ts +71 -0
  100. package/dist/utils/deepEqual.js +276 -0
  101. package/dist/utils/naming.d.ts +241 -0
  102. package/dist/utils/naming.js +376 -0
  103. package/package.json +87 -0
@@ -0,0 +1,145 @@
1
+ /**
2
+
3
+ * Licensed under the Apache License, Version 2.0 (the "License");
4
+
5
+ * you may not use this file except in compliance with the License.
6
+
7
+ * You may obtain a copy of the License at
8
+
9
+ *
10
+
11
+ * http://www.apache.org/licenses/LICENSE-2.0
12
+
13
+ *
14
+
15
+ * Unless required by applicable law or agreed to in writing, software
16
+
17
+ * distributed under the License is distributed on an "AS IS" BASIS,
18
+
19
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
+
21
+ * See the License for the specific language governing permissions and
22
+
23
+ * limitations under the License.
24
+
25
+ *
26
+
27
+ * Copyright 2025 Daniel Coutinho Ribeiro
28
+
29
+ */
30
+ import { FiberNode, ReRenderReason, CReactEvents } from './types';
31
+ import { CircularDependencyError } from './errors';
32
+ /**
33
+ * Recovery strategy for different types of errors
34
+ */
35
+ export type RecoveryStrategy = 'rollback' | 'isolate' | 'retry' | 'skip' | 'abort';
36
+ /**
37
+ * Recovery action result
38
+ */
39
+ export interface RecoveryResult {
40
+ success: boolean;
41
+ strategy: RecoveryStrategy;
42
+ message: string;
43
+ recoveredFibers?: FiberNode[];
44
+ failedFibers?: FiberNode[];
45
+ }
46
+ /**
47
+ * ErrorRecoveryManager - Handles error recovery and rollback semantics
48
+ *
49
+ * Provides:
50
+ * - Rollback semantics for failed re-renders
51
+ * - Error isolation for component failures
52
+ * - Graceful degradation for partial failures
53
+ * - Recovery strategies based on error type
54
+ */
55
+ export declare class ErrorRecoveryManager {
56
+ private componentSnapshots;
57
+ private contextSnapshots;
58
+ private eventHooks?;
59
+ private maxRetries;
60
+ private retryDelay;
61
+ constructor(eventHooks?: CReactEvents);
62
+ /**
63
+ * Create a snapshot of component state before risky operations
64
+ */
65
+ createComponentSnapshot(fiber: FiberNode): void;
66
+ /**
67
+ * Create snapshots for multiple components
68
+ */
69
+ createComponentSnapshots(fibers: FiberNode[]): void;
70
+ /**
71
+ * Create a snapshot of context value before changes
72
+ */
73
+ createContextSnapshot(contextId: symbol, value: any): void;
74
+ /**
75
+ * Rollback a component to its previous snapshot
76
+ */
77
+ rollbackComponent(fiber: FiberNode): boolean;
78
+ /**
79
+ * Rollback multiple components to their snapshots
80
+ */
81
+ rollbackComponents(fibers: FiberNode[]): RecoveryResult;
82
+ /**
83
+ * Rollback context value to its previous snapshot
84
+ */
85
+ rollbackContextValue(contextId: symbol): boolean;
86
+ /**
87
+ * Handle re-render errors with appropriate recovery strategy
88
+ */
89
+ handleReRenderError(error: Error, affectedFibers: FiberNode[], reason: ReRenderReason): Promise<RecoveryResult>;
90
+ /**
91
+ * Handle state update errors with isolation
92
+ */
93
+ handleStateUpdateError(error: Error, fiber: FiberNode, hookIndex: number): RecoveryResult;
94
+ /**
95
+ * Handle context propagation errors
96
+ */
97
+ handleContextPropagationError(error: Error, contextId: symbol, affectedFibers: FiberNode[]): Promise<RecoveryResult>;
98
+ /**
99
+ * Handle circular dependency errors
100
+ */
101
+ handleCircularDependencyError(error: CircularDependencyError, affectedFibers: FiberNode[]): RecoveryResult;
102
+ /**
103
+ * Determine the appropriate recovery strategy based on error type and context
104
+ */
105
+ private determineRecoveryStrategy;
106
+ /**
107
+ * Isolate failed components and continue with successful ones
108
+ */
109
+ private isolateFailedComponents;
110
+ /**
111
+ * Retry operation with exponential backoff
112
+ */
113
+ private retryOperation;
114
+ /**
115
+ * Skip failed components and continue with others
116
+ */
117
+ private skipFailedComponents;
118
+ /**
119
+ * Find the fiber that's causing a circular dependency
120
+ */
121
+ private findCycleCausingFiber;
122
+ /**
123
+ * Deep clone an object for snapshots
124
+ */
125
+ private deepClone;
126
+ /**
127
+ * Clean up old snapshots to prevent memory leaks
128
+ */
129
+ cleanupOldSnapshots(maxAge?: number): void;
130
+ /**
131
+ * Get recovery statistics
132
+ */
133
+ getRecoveryStats(): {
134
+ activeSnapshots: number;
135
+ contextSnapshots: number;
136
+ };
137
+ /**
138
+ * Clear all snapshots (for testing/cleanup)
139
+ */
140
+ clearAllSnapshots(): void;
141
+ /**
142
+ * Set retry configuration
143
+ */
144
+ setRetryConfig(maxRetries: number, retryDelay: number): void;
145
+ }
@@ -0,0 +1,443 @@
1
+ "use strict";
2
+ /**
3
+
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+
6
+ * you may not use this file except in compliance with the License.
7
+
8
+ * You may obtain a copy of the License at
9
+
10
+ *
11
+
12
+ * http://www.apache.org/licenses/LICENSE-2.0
13
+
14
+ *
15
+
16
+ * Unless required by applicable law or agreed to in writing, software
17
+
18
+ * distributed under the License is distributed on an "AS IS" BASIS,
19
+
20
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21
+
22
+ * See the License for the specific language governing permissions and
23
+
24
+ * limitations under the License.
25
+
26
+ *
27
+
28
+ * Copyright 2025 Daniel Coutinho Ribeiro
29
+
30
+ */
31
+ Object.defineProperty(exports, "__esModule", { value: true });
32
+ exports.ErrorRecoveryManager = void 0;
33
+ const errors_1 = require("./errors");
34
+ const Logger_1 = require("../utils/Logger");
35
+ const logger = Logger_1.LoggerFactory.getLogger('runtime');
36
+ /**
37
+ * ErrorRecoveryManager - Handles error recovery and rollback semantics
38
+ *
39
+ * Provides:
40
+ * - Rollback semantics for failed re-renders
41
+ * - Error isolation for component failures
42
+ * - Graceful degradation for partial failures
43
+ * - Recovery strategies based on error type
44
+ */
45
+ class ErrorRecoveryManager {
46
+ constructor(eventHooks) {
47
+ this.componentSnapshots = new WeakMap();
48
+ this.contextSnapshots = new Map();
49
+ this.maxRetries = 3;
50
+ this.retryDelay = 100; // ms
51
+ this.eventHooks = eventHooks;
52
+ }
53
+ /**
54
+ * Create a snapshot of component state before risky operations
55
+ */
56
+ createComponentSnapshot(fiber) {
57
+ const snapshot = {
58
+ fiber,
59
+ hooks: fiber.hooks ? [...fiber.hooks] : [],
60
+ reactiveState: fiber.reactiveState ? { ...fiber.reactiveState } : undefined,
61
+ timestamp: Date.now(),
62
+ };
63
+ this.componentSnapshots.set(fiber, snapshot);
64
+ }
65
+ /**
66
+ * Create snapshots for multiple components
67
+ */
68
+ createComponentSnapshots(fibers) {
69
+ fibers.forEach((fiber) => this.createComponentSnapshot(fiber));
70
+ }
71
+ /**
72
+ * Create a snapshot of context value before changes
73
+ */
74
+ createContextSnapshot(contextId, value) {
75
+ this.contextSnapshots.set(contextId, {
76
+ value: this.deepClone(value),
77
+ timestamp: Date.now(),
78
+ });
79
+ }
80
+ /**
81
+ * Rollback a component to its previous snapshot
82
+ */
83
+ rollbackComponent(fiber) {
84
+ const snapshot = this.componentSnapshots.get(fiber);
85
+ if (!snapshot) {
86
+ return false;
87
+ }
88
+ try {
89
+ // Restore hooks
90
+ if (fiber.hooks && snapshot.hooks) {
91
+ fiber.hooks.splice(0, fiber.hooks.length, ...snapshot.hooks);
92
+ }
93
+ // Restore reactive state
94
+ if (fiber.reactiveState && snapshot.reactiveState) {
95
+ Object.assign(fiber.reactiveState, snapshot.reactiveState);
96
+ }
97
+ return true;
98
+ }
99
+ catch (error) {
100
+ logger.warn(`Failed to rollback component ${fiber.path.join('.')}:`, error);
101
+ return false;
102
+ }
103
+ }
104
+ /**
105
+ * Rollback multiple components to their snapshots
106
+ */
107
+ rollbackComponents(fibers) {
108
+ const recoveredFibers = [];
109
+ const failedFibers = [];
110
+ for (const fiber of fibers) {
111
+ if (this.rollbackComponent(fiber)) {
112
+ recoveredFibers.push(fiber);
113
+ }
114
+ else {
115
+ failedFibers.push(fiber);
116
+ }
117
+ }
118
+ return {
119
+ success: failedFibers.length === 0,
120
+ strategy: 'rollback',
121
+ message: `Rolled back ${recoveredFibers.length}/${fibers.length} components`,
122
+ recoveredFibers,
123
+ failedFibers,
124
+ };
125
+ }
126
+ /**
127
+ * Rollback context value to its previous snapshot
128
+ */
129
+ rollbackContextValue(contextId) {
130
+ const snapshot = this.contextSnapshots.get(contextId);
131
+ if (!snapshot) {
132
+ return false;
133
+ }
134
+ try {
135
+ // The actual context value rollback would be handled by ContextDependencyTracker
136
+ // This method just validates that we have a snapshot to rollback to
137
+ return true;
138
+ }
139
+ catch (error) {
140
+ logger.warn(`Failed to rollback context ${String(contextId)}:`, error);
141
+ return false;
142
+ }
143
+ }
144
+ /**
145
+ * Handle re-render errors with appropriate recovery strategy
146
+ */
147
+ async handleReRenderError(error, affectedFibers, reason) {
148
+ // Determine recovery strategy based on error type and reason
149
+ const strategy = this.determineRecoveryStrategy(error, reason);
150
+ switch (strategy) {
151
+ case 'rollback':
152
+ return this.rollbackComponents(affectedFibers);
153
+ case 'isolate':
154
+ return this.isolateFailedComponents(error, affectedFibers);
155
+ case 'retry':
156
+ return await this.retryOperation(error, affectedFibers, reason);
157
+ case 'skip':
158
+ return this.skipFailedComponents(affectedFibers);
159
+ case 'abort':
160
+ default:
161
+ return {
162
+ success: false,
163
+ strategy: 'abort',
164
+ message: `Aborting due to unrecoverable error: ${error.message}`,
165
+ failedFibers: affectedFibers,
166
+ };
167
+ }
168
+ }
169
+ /**
170
+ * Handle state update errors with isolation
171
+ */
172
+ handleStateUpdateError(error, fiber, hookIndex) {
173
+ try {
174
+ // Try to rollback the specific hook
175
+ const snapshot = this.componentSnapshots.get(fiber);
176
+ if (snapshot && snapshot.hooks[hookIndex] !== undefined) {
177
+ if (fiber.hooks) {
178
+ fiber.hooks[hookIndex] = snapshot.hooks[hookIndex];
179
+ }
180
+ return {
181
+ success: true,
182
+ strategy: 'rollback',
183
+ message: `Rolled back state hook ${hookIndex} for component ${fiber.path.join('.')}`,
184
+ recoveredFibers: [fiber],
185
+ };
186
+ }
187
+ // If no snapshot, isolate the component
188
+ return this.isolateFailedComponents(error, [fiber]);
189
+ }
190
+ catch (recoveryError) {
191
+ return {
192
+ success: false,
193
+ strategy: 'abort',
194
+ message: `Failed to recover from state update error: ${recoveryError}`,
195
+ failedFibers: [fiber],
196
+ };
197
+ }
198
+ }
199
+ /**
200
+ * Handle context propagation errors
201
+ */
202
+ async handleContextPropagationError(error, contextId, affectedFibers) {
203
+ try {
204
+ // Try to rollback context value
205
+ const contextRollback = this.rollbackContextValue(contextId);
206
+ if (contextRollback) {
207
+ // Rollback affected components
208
+ const componentRollback = this.rollbackComponents(affectedFibers);
209
+ return {
210
+ success: componentRollback.success,
211
+ strategy: 'rollback',
212
+ message: `Rolled back context and ${componentRollback.recoveredFibers?.length || 0} components`,
213
+ recoveredFibers: componentRollback.recoveredFibers,
214
+ failedFibers: componentRollback.failedFibers,
215
+ };
216
+ }
217
+ // If context rollback fails, isolate affected components
218
+ return this.isolateFailedComponents(error, affectedFibers);
219
+ }
220
+ catch (recoveryError) {
221
+ return {
222
+ success: false,
223
+ strategy: 'abort',
224
+ message: `Failed to recover from context propagation error: ${recoveryError}`,
225
+ failedFibers: affectedFibers,
226
+ };
227
+ }
228
+ }
229
+ /**
230
+ * Handle circular dependency errors
231
+ */
232
+ handleCircularDependencyError(error, affectedFibers) {
233
+ try {
234
+ // For circular dependencies, we need to break the cycle
235
+ // Find the fiber that's causing the cycle and isolate it
236
+ const cycleFiber = this.findCycleCausingFiber(error.cyclePath, affectedFibers);
237
+ if (cycleFiber) {
238
+ // Isolate the cycle-causing fiber
239
+ const isolationResult = this.isolateFailedComponents(error, [cycleFiber]);
240
+ // Continue with remaining fibers
241
+ const remainingFibers = affectedFibers.filter((f) => f !== cycleFiber);
242
+ return {
243
+ success: true,
244
+ strategy: 'isolate',
245
+ message: `Isolated cycle-causing component ${cycleFiber.path.join('.')}`,
246
+ recoveredFibers: remainingFibers,
247
+ failedFibers: [cycleFiber],
248
+ };
249
+ }
250
+ // If we can't identify the cycle cause, rollback all
251
+ return this.rollbackComponents(affectedFibers);
252
+ }
253
+ catch (recoveryError) {
254
+ return {
255
+ success: false,
256
+ strategy: 'abort',
257
+ message: `Failed to recover from circular dependency: ${recoveryError}`,
258
+ failedFibers: affectedFibers,
259
+ };
260
+ }
261
+ }
262
+ /**
263
+ * Determine the appropriate recovery strategy based on error type and context
264
+ */
265
+ determineRecoveryStrategy(error, reason) {
266
+ // Circular dependency errors should be isolated
267
+ if (error instanceof errors_1.CircularDependencyError) {
268
+ return 'isolate';
269
+ }
270
+ // State update errors can usually be rolled back
271
+ if (error instanceof errors_1.StateUpdateError) {
272
+ return 'rollback';
273
+ }
274
+ // Context propagation errors should be rolled back
275
+ if (error instanceof errors_1.ContextPropagationError) {
276
+ return 'rollback';
277
+ }
278
+ // For manual re-renders, we can retry
279
+ if (reason === 'manual') {
280
+ return 'retry';
281
+ }
282
+ // For output updates, we can skip and continue
283
+ if (reason === 'output-update') {
284
+ return 'skip';
285
+ }
286
+ // For hot reload, we can retry
287
+ if (reason === 'hot-reload') {
288
+ return 'retry';
289
+ }
290
+ // Default to rollback for other cases
291
+ return 'rollback';
292
+ }
293
+ /**
294
+ * Isolate failed components and continue with successful ones
295
+ */
296
+ isolateFailedComponents(error, failedFibers) {
297
+ // Mark failed components as isolated
298
+ failedFibers.forEach((fiber) => {
299
+ if (fiber.reactiveState) {
300
+ fiber.reactiveState.isDirty = false;
301
+ fiber.reactiveState.updatePending = false;
302
+ // Add isolation marker
303
+ fiber.reactiveState.isolated = true;
304
+ fiber.reactiveState.isolationReason = error.message;
305
+ fiber.reactiveState.isolationTime = Date.now();
306
+ }
307
+ });
308
+ this.eventHooks?.onError(error, failedFibers[0]);
309
+ return {
310
+ success: true,
311
+ strategy: 'isolate',
312
+ message: `Isolated ${failedFibers.length} failed components`,
313
+ failedFibers,
314
+ };
315
+ }
316
+ /**
317
+ * Retry operation with exponential backoff
318
+ */
319
+ async retryOperation(error, fibers, reason, attempt = 1) {
320
+ if (attempt > this.maxRetries) {
321
+ return {
322
+ success: false,
323
+ strategy: 'retry',
324
+ message: `Max retries (${this.maxRetries}) exceeded`,
325
+ failedFibers: fibers,
326
+ };
327
+ }
328
+ // Wait with exponential backoff
329
+ const delay = this.retryDelay * Math.pow(2, attempt - 1);
330
+ await new Promise((resolve) => setTimeout(resolve, delay));
331
+ try {
332
+ // The actual retry would be handled by the calling code
333
+ // This method just provides the retry logic framework
334
+ return {
335
+ success: true,
336
+ strategy: 'retry',
337
+ message: `Retry attempt ${attempt} scheduled`,
338
+ recoveredFibers: fibers,
339
+ };
340
+ }
341
+ catch (retryError) {
342
+ // Recursive retry
343
+ return this.retryOperation(error, fibers, reason, attempt + 1);
344
+ }
345
+ }
346
+ /**
347
+ * Skip failed components and continue with others
348
+ */
349
+ skipFailedComponents(fibers) {
350
+ // Mark components as skipped
351
+ fibers.forEach((fiber) => {
352
+ if (fiber.reactiveState) {
353
+ fiber.reactiveState.isDirty = false;
354
+ fiber.reactiveState.updatePending = false;
355
+ // Add skip marker
356
+ fiber.reactiveState.skipped = true;
357
+ fiber.reactiveState.skipTime = Date.now();
358
+ }
359
+ });
360
+ return {
361
+ success: true,
362
+ strategy: 'skip',
363
+ message: `Skipped ${fibers.length} components`,
364
+ recoveredFibers: [],
365
+ };
366
+ }
367
+ /**
368
+ * Find the fiber that's causing a circular dependency
369
+ */
370
+ findCycleCausingFiber(cyclePath, fibers) {
371
+ // Look for a fiber whose path matches part of the cycle path
372
+ for (const fiber of fibers) {
373
+ const fiberPathStr = fiber.path.join('.');
374
+ if (cyclePath.includes(fiberPathStr)) {
375
+ return fiber;
376
+ }
377
+ }
378
+ return null;
379
+ }
380
+ /**
381
+ * Deep clone an object for snapshots
382
+ */
383
+ deepClone(obj) {
384
+ if (obj === null || typeof obj !== 'object') {
385
+ return obj;
386
+ }
387
+ if (obj instanceof Date) {
388
+ return new Date(obj.getTime());
389
+ }
390
+ if (obj instanceof Array) {
391
+ return obj.map((item) => this.deepClone(item));
392
+ }
393
+ if (typeof obj === 'object') {
394
+ const cloned = {};
395
+ for (const key in obj) {
396
+ if (obj.hasOwnProperty(key)) {
397
+ cloned[key] = this.deepClone(obj[key]);
398
+ }
399
+ }
400
+ return cloned;
401
+ }
402
+ return obj;
403
+ }
404
+ /**
405
+ * Clean up old snapshots to prevent memory leaks
406
+ */
407
+ cleanupOldSnapshots(maxAge = 300000) {
408
+ // 5 minutes default
409
+ const now = Date.now();
410
+ // Clean up context snapshots
411
+ Array.from(this.contextSnapshots.entries()).forEach(([contextId, snapshot]) => {
412
+ if (now - snapshot.timestamp > maxAge) {
413
+ this.contextSnapshots.delete(contextId);
414
+ }
415
+ });
416
+ // Note: Component snapshots use WeakMap, so they'll be garbage collected
417
+ // automatically when the fiber is no longer referenced
418
+ }
419
+ /**
420
+ * Get recovery statistics
421
+ */
422
+ getRecoveryStats() {
423
+ return {
424
+ activeSnapshots: 0, // WeakMap doesn't have size
425
+ contextSnapshots: this.contextSnapshots.size,
426
+ };
427
+ }
428
+ /**
429
+ * Clear all snapshots (for testing/cleanup)
430
+ */
431
+ clearAllSnapshots() {
432
+ this.contextSnapshots.clear();
433
+ // WeakMap will be cleared automatically when fibers are GC'd
434
+ }
435
+ /**
436
+ * Set retry configuration
437
+ */
438
+ setRetryConfig(maxRetries, retryDelay) {
439
+ this.maxRetries = maxRetries;
440
+ this.retryDelay = retryDelay;
441
+ }
442
+ }
443
+ exports.ErrorRecoveryManager = ErrorRecoveryManager;
@@ -0,0 +1,91 @@
1
+ /**
2
+
3
+ * Licensed under the Apache License, Version 2.0 (the "License");
4
+
5
+ * you may not use this file except in compliance with the License.
6
+
7
+ * You may obtain a copy of the License at
8
+
9
+ *
10
+
11
+ * http://www.apache.org/licenses/LICENSE-2.0
12
+
13
+ *
14
+
15
+ * Unless required by applicable law or agreed to in writing, software
16
+
17
+ * distributed under the License is distributed on an "AS IS" BASIS,
18
+
19
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
+
21
+ * See the License for the specific language governing permissions and
22
+
23
+ * limitations under the License.
24
+
25
+ *
26
+
27
+ * Copyright 2025 Daniel Coutinho Ribeiro
28
+
29
+ */
30
+ import { CloudDOMNode } from './types';
31
+ /**
32
+ * CloudDOM Event Bus - Centralized event system for deployment lifecycle
33
+ *
34
+ * Provides a clean way to trigger CloudDOM event callbacks without
35
+ * coupling to specific classes like CloudDOMBuilder or StateMachine.
36
+ *
37
+ * REQ-2.3: CloudDOM event callbacks for deployment lifecycle
38
+ * REQ-3.2: Error handling with component context
39
+ */
40
+ export declare class CloudDOMEventBus {
41
+ /**
42
+ * Trigger CloudDOM event callbacks for a resource
43
+ *
44
+ * Called during deployment lifecycle to notify parent components
45
+ * about their child resources' deployment events.
46
+ *
47
+ * @param node - CloudDOM node with event callbacks
48
+ * @param phase - Deployment phase ('deploy', 'error', 'destroy')
49
+ * @param error - Error object (only for 'error' phase)
50
+ */
51
+ static triggerEventCallbacks(node: CloudDOMNode, phase: 'deploy' | 'error' | 'destroy', error?: Error): Promise<void>;
52
+ /**
53
+ * Trigger event callbacks for all nodes in a CloudDOM tree
54
+ *
55
+ * Recursively walks the tree and triggers callbacks for each node.
56
+ *
57
+ * @param nodes - CloudDOM nodes to trigger events for
58
+ * @param phase - Deployment phase
59
+ * @param error - Error object (only for 'error' phase)
60
+ */
61
+ static triggerEventCallbacksRecursive(nodes: CloudDOMNode[], phase: 'deploy' | 'error' | 'destroy', error?: Error): Promise<void>;
62
+ /**
63
+ * Trigger event callbacks for a specific list of nodes by ID
64
+ *
65
+ * Useful for triggering events for specific resources during deployment.
66
+ *
67
+ * @param allNodes - All CloudDOM nodes to search in
68
+ * @param nodeIds - IDs of nodes to trigger events for
69
+ * @param phase - Deployment phase
70
+ * @param error - Error object (only for 'error' phase)
71
+ */
72
+ static triggerEventCallbacksForNodes(allNodes: CloudDOMNode[], nodeIds: string[], phase: 'deploy' | 'error' | 'destroy', error?: Error): Promise<void>;
73
+ /**
74
+ * Check if any nodes in a tree have event callbacks
75
+ *
76
+ * Useful for optimization - skip event processing if no callbacks exist.
77
+ *
78
+ * @param nodes - CloudDOM nodes to check
79
+ * @returns True if any node has event callbacks
80
+ */
81
+ static hasEventCallbacks(nodes: CloudDOMNode[]): boolean;
82
+ /**
83
+ * Get all nodes with event callbacks from a tree
84
+ *
85
+ * Useful for debugging and introspection.
86
+ *
87
+ * @param nodes - CloudDOM nodes to search
88
+ * @returns Array of nodes that have event callbacks
89
+ */
90
+ static getNodesWithEventCallbacks(nodes: CloudDOMNode[]): CloudDOMNode[];
91
+ }