@creact-labs/creact 0.1.8 → 0.2.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 (146) hide show
  1. package/README.md +85 -22
  2. package/dist/cli.d.ts +11 -0
  3. package/dist/cli.js +88 -0
  4. package/dist/index.d.ts +19 -44
  5. package/dist/index.js +20 -68
  6. package/dist/jsx/index.d.ts +2 -0
  7. package/dist/jsx/index.js +1 -0
  8. package/dist/jsx/jsx-dev-runtime.d.ts +4 -0
  9. package/dist/jsx/jsx-dev-runtime.js +4 -0
  10. package/dist/jsx/jsx-runtime.d.ts +38 -0
  11. package/dist/jsx/jsx-runtime.js +38 -0
  12. package/dist/jsx/types.d.ts +12 -0
  13. package/dist/jsx/types.js +4 -0
  14. package/dist/primitives/context.d.ts +34 -0
  15. package/dist/primitives/context.js +63 -0
  16. package/dist/primitives/index.d.ts +3 -0
  17. package/dist/primitives/index.js +3 -0
  18. package/dist/primitives/instance.d.ts +72 -0
  19. package/dist/primitives/instance.js +235 -0
  20. package/dist/primitives/store.d.ts +22 -0
  21. package/dist/primitives/store.js +97 -0
  22. package/dist/provider/backend.d.ts +110 -0
  23. package/dist/provider/backend.js +37 -0
  24. package/dist/provider/interface.d.ts +48 -0
  25. package/dist/provider/interface.js +39 -0
  26. package/dist/reactive/effect.d.ts +11 -0
  27. package/dist/reactive/effect.js +42 -0
  28. package/dist/reactive/index.d.ts +3 -0
  29. package/dist/reactive/index.js +3 -0
  30. package/dist/reactive/signal.d.ts +32 -0
  31. package/dist/reactive/signal.js +60 -0
  32. package/dist/reactive/tracking.d.ts +41 -0
  33. package/dist/reactive/tracking.js +161 -0
  34. package/dist/runtime/fiber.d.ts +21 -0
  35. package/dist/runtime/fiber.js +16 -0
  36. package/dist/runtime/index.d.ts +4 -0
  37. package/dist/runtime/index.js +4 -0
  38. package/dist/runtime/reconcile.d.ts +66 -0
  39. package/dist/runtime/reconcile.js +210 -0
  40. package/dist/runtime/render.d.ts +42 -0
  41. package/dist/runtime/render.js +231 -0
  42. package/dist/runtime/run.d.ts +119 -0
  43. package/dist/runtime/run.js +334 -0
  44. package/dist/runtime/state-machine.d.ts +95 -0
  45. package/dist/runtime/state-machine.js +209 -0
  46. package/dist/types.d.ts +13 -0
  47. package/dist/types.js +4 -0
  48. package/package.json +29 -24
  49. package/dist/cli/commands/BuildCommand.d.ts +0 -40
  50. package/dist/cli/commands/BuildCommand.js +0 -151
  51. package/dist/cli/commands/DeployCommand.d.ts +0 -38
  52. package/dist/cli/commands/DeployCommand.js +0 -194
  53. package/dist/cli/commands/DevCommand.d.ts +0 -52
  54. package/dist/cli/commands/DevCommand.js +0 -394
  55. package/dist/cli/commands/PlanCommand.d.ts +0 -39
  56. package/dist/cli/commands/PlanCommand.js +0 -164
  57. package/dist/cli/commands/index.d.ts +0 -36
  58. package/dist/cli/commands/index.js +0 -43
  59. package/dist/cli/core/ArgumentParser.d.ts +0 -46
  60. package/dist/cli/core/ArgumentParser.js +0 -127
  61. package/dist/cli/core/BaseCommand.d.ts +0 -75
  62. package/dist/cli/core/BaseCommand.js +0 -95
  63. package/dist/cli/core/CLIContext.d.ts +0 -68
  64. package/dist/cli/core/CLIContext.js +0 -183
  65. package/dist/cli/core/CommandRegistry.d.ts +0 -64
  66. package/dist/cli/core/CommandRegistry.js +0 -89
  67. package/dist/cli/core/index.d.ts +0 -36
  68. package/dist/cli/core/index.js +0 -43
  69. package/dist/cli/index.d.ts +0 -35
  70. package/dist/cli/index.js +0 -100
  71. package/dist/cli/output.d.ts +0 -204
  72. package/dist/cli/output.js +0 -437
  73. package/dist/cli/utils.d.ts +0 -59
  74. package/dist/cli/utils.js +0 -76
  75. package/dist/context/createContext.d.ts +0 -90
  76. package/dist/context/createContext.js +0 -113
  77. package/dist/context/index.d.ts +0 -30
  78. package/dist/context/index.js +0 -35
  79. package/dist/core/CReact.d.ts +0 -409
  80. package/dist/core/CReact.js +0 -1151
  81. package/dist/core/CloudDOMBuilder.d.ts +0 -447
  82. package/dist/core/CloudDOMBuilder.js +0 -1234
  83. package/dist/core/ContextDependencyTracker.d.ts +0 -165
  84. package/dist/core/ContextDependencyTracker.js +0 -448
  85. package/dist/core/ErrorRecoveryManager.d.ts +0 -145
  86. package/dist/core/ErrorRecoveryManager.js +0 -443
  87. package/dist/core/EventBus.d.ts +0 -91
  88. package/dist/core/EventBus.js +0 -185
  89. package/dist/core/ProviderOutputTracker.d.ts +0 -211
  90. package/dist/core/ProviderOutputTracker.js +0 -476
  91. package/dist/core/ReactiveUpdateQueue.d.ts +0 -76
  92. package/dist/core/ReactiveUpdateQueue.js +0 -121
  93. package/dist/core/Reconciler.d.ts +0 -415
  94. package/dist/core/Reconciler.js +0 -1044
  95. package/dist/core/RenderScheduler.d.ts +0 -153
  96. package/dist/core/RenderScheduler.js +0 -519
  97. package/dist/core/Renderer.d.ts +0 -336
  98. package/dist/core/Renderer.js +0 -944
  99. package/dist/core/Runtime.d.ts +0 -246
  100. package/dist/core/Runtime.js +0 -640
  101. package/dist/core/StateBindingManager.d.ts +0 -121
  102. package/dist/core/StateBindingManager.js +0 -309
  103. package/dist/core/StateMachine.d.ts +0 -441
  104. package/dist/core/StateMachine.js +0 -883
  105. package/dist/core/StructuralChangeDetector.d.ts +0 -140
  106. package/dist/core/StructuralChangeDetector.js +0 -363
  107. package/dist/core/Validator.d.ts +0 -127
  108. package/dist/core/Validator.js +0 -279
  109. package/dist/core/errors.d.ts +0 -153
  110. package/dist/core/errors.js +0 -202
  111. package/dist/core/index.d.ts +0 -38
  112. package/dist/core/index.js +0 -64
  113. package/dist/core/types.d.ts +0 -265
  114. package/dist/core/types.js +0 -48
  115. package/dist/hooks/context.d.ts +0 -147
  116. package/dist/hooks/context.js +0 -334
  117. package/dist/hooks/useContext.d.ts +0 -113
  118. package/dist/hooks/useContext.js +0 -169
  119. package/dist/hooks/useEffect.d.ts +0 -105
  120. package/dist/hooks/useEffect.js +0 -540
  121. package/dist/hooks/useInstance.d.ts +0 -139
  122. package/dist/hooks/useInstance.js +0 -455
  123. package/dist/hooks/useState.d.ts +0 -120
  124. package/dist/hooks/useState.js +0 -298
  125. package/dist/jsx.d.ts +0 -143
  126. package/dist/jsx.js +0 -76
  127. package/dist/providers/DummyBackendProvider.d.ts +0 -193
  128. package/dist/providers/DummyBackendProvider.js +0 -189
  129. package/dist/providers/DummyCloudProvider.d.ts +0 -128
  130. package/dist/providers/DummyCloudProvider.js +0 -157
  131. package/dist/providers/IBackendProvider.d.ts +0 -177
  132. package/dist/providers/IBackendProvider.js +0 -31
  133. package/dist/providers/ICloudProvider.d.ts +0 -230
  134. package/dist/providers/ICloudProvider.js +0 -31
  135. package/dist/providers/index.d.ts +0 -31
  136. package/dist/providers/index.js +0 -31
  137. package/dist/test-event-callbacks.d.ts +0 -0
  138. package/dist/test-event-callbacks.js +0 -1
  139. package/dist/utils/Logger.d.ts +0 -144
  140. package/dist/utils/Logger.js +0 -220
  141. package/dist/utils/Output.d.ts +0 -161
  142. package/dist/utils/Output.js +0 -401
  143. package/dist/utils/deepEqual.d.ts +0 -71
  144. package/dist/utils/deepEqual.js +0 -276
  145. package/dist/utils/naming.d.ts +0 -241
  146. package/dist/utils/naming.js +0 -376
@@ -1,139 +0,0 @@
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 '../core/types';
31
- import { ProviderOutputTracker } from '../core/ProviderOutputTracker';
32
- /**
33
- * Set the ProviderOutputTracker instance (for testing/injection)
34
- * @internal
35
- */
36
- export declare function setProviderOutputTracker(tracker: ProviderOutputTracker): void;
37
- /**
38
- * Get the ProviderOutputTracker instance (for external access)
39
- * @internal
40
- */
41
- export declare function getProviderOutputTrackerInstance(): ProviderOutputTracker;
42
- /**
43
- * Set the current rendering context
44
- * Called by Renderer before executing a component
45
- *
46
- * @internal
47
- */
48
- export declare function setInstanceRenderContext(fiber: any, path: string[]): void;
49
- /**
50
- * Clear the current rendering context
51
- * Called by Renderer after component execution
52
- *
53
- * @internal
54
- */
55
- export declare function clearInstanceRenderContext(): void;
56
- /**
57
- * Set previous outputs map for restoration during render
58
- * Called by CReact before rendering
59
- *
60
- * @internal
61
- */
62
- export declare function setPreviousOutputs(outputsMap: Map<string, Record<string, any>> | null): void;
63
- /**
64
- * useInstance hook - Register an infrastructure resource (React-like API)
65
- *
66
- * This hook creates a CloudDOM node and attaches it to the current Fiber.
67
- * It must be called during component rendering (inside a component function).
68
- *
69
- * Automatically extracts event callbacks (onDeploy, onError, onDestroy) from
70
- * component props and attaches them to the CloudDOM node for lifecycle events.
71
- *
72
- * REQ-01: JSX → CloudDOM rendering
73
- * REQ-04: Resource creation via hooks (React-like API)
74
- * REQ-2.3: CloudDOM event callbacks for deployment lifecycle
75
- *
76
- * @param construct - Constructor/class for the infrastructure resource
77
- * @param props - Properties/configuration for the resource (may include `key` and event callbacks)
78
- * @returns Reference to the created CloudDOM node
79
- *
80
- * @example
81
- * ```tsx
82
- * // With event callbacks (extracted from component props)
83
- * function MyDatabase({ onDeploy, onError }) {
84
- * const db = useInstance(Database, {
85
- * name: 'my-db',
86
- * size: '100GB'
87
- * });
88
- * // onDeploy and onError are automatically extracted from component props
89
- * return <></>;
90
- * }
91
- *
92
- * // Usage with event callbacks
93
- * <MyDatabase
94
- * onDeploy={(ctx) => logger.info('Database deployed:', ctx.resourceId)}
95
- * onError={(ctx, err) => logger.error('Database failed:', err)}
96
- * />
97
- *
98
- * // Without event callbacks (normal usage)
99
- * function MyBucket() {
100
- * const bucket = useInstance(S3Bucket, {
101
- * bucketName: 'my-assets'
102
- * });
103
- * return <></>;
104
- * }
105
- * ```
106
- */
107
- export declare function useInstance<T = any>(construct: new (...args: any[]) => T, props: Record<string, any>): CloudDOMNode;
108
- /**
109
- * Reset construct call counts for a fiber
110
- * Called by Renderer before executing a component
111
- *
112
- * @internal
113
- */
114
- export declare function resetConstructCounts(fiber: any): void;
115
- /**
116
- * Get the current rendering path
117
- * Useful for debugging and testing
118
- *
119
- * @internal
120
- */
121
- export declare function getCurrentPath(): string[];
122
- /**
123
- * Check if currently rendering
124
- * Useful for validation and testing
125
- *
126
- * @internal
127
- */
128
- export declare function isRendering(): boolean;
129
- /**
130
- * Update outputs for a CloudDOM node and notify bound components
131
- * This is called after deployment when provider outputs are available
132
- * @internal
133
- */
134
- export declare function updateNodeOutputs(nodeId: string, newOutputs: Record<string, any>): void;
135
- /**
136
- * Get current outputs for a CloudDOM node
137
- * @internal
138
- */
139
- export declare function getNodeOutputs(nodeId: string): Record<string, any>;
@@ -1,455 +0,0 @@
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.setProviderOutputTracker = setProviderOutputTracker;
33
- exports.getProviderOutputTrackerInstance = getProviderOutputTrackerInstance;
34
- exports.setInstanceRenderContext = setInstanceRenderContext;
35
- exports.clearInstanceRenderContext = clearInstanceRenderContext;
36
- exports.setPreviousOutputs = setPreviousOutputs;
37
- exports.useInstance = useInstance;
38
- exports.resetConstructCounts = resetConstructCounts;
39
- exports.getCurrentPath = getCurrentPath;
40
- exports.isRendering = isRendering;
41
- exports.updateNodeOutputs = updateNodeOutputs;
42
- exports.getNodeOutputs = getNodeOutputs;
43
- const naming_1 = require("../utils/naming");
44
- const ProviderOutputTracker_1 = require("../core/ProviderOutputTracker");
45
- const context_1 = require("./context");
46
- const Logger_1 = require("../utils/Logger");
47
- const logger = Logger_1.LoggerFactory.getLogger('hooks');
48
- // Global ProviderOutputTracker instance
49
- let providerOutputTracker = null;
50
- /**
51
- * Get or create the global ProviderOutputTracker instance
52
- * @internal
53
- */
54
- function getProviderOutputTracker() {
55
- if (!providerOutputTracker) {
56
- providerOutputTracker = new ProviderOutputTracker_1.ProviderOutputTracker();
57
- }
58
- return providerOutputTracker;
59
- }
60
- /**
61
- * Set the ProviderOutputTracker instance (for testing/injection)
62
- * @internal
63
- */
64
- function setProviderOutputTracker(tracker) {
65
- providerOutputTracker = tracker;
66
- }
67
- /**
68
- * Get the ProviderOutputTracker instance (for external access)
69
- * @internal
70
- */
71
- function getProviderOutputTrackerInstance() {
72
- return getProviderOutputTracker();
73
- }
74
- /**
75
- * Create a placeholder node when dependencies are undefined
76
- * This node won't be included in CloudDOM but allows the component to continue rendering
77
- * All output accesses return undefined
78
- *
79
- * Uses the same ID generation logic as real nodes for proper reconciliation tracking
80
- *
81
- * @internal
82
- */
83
- function createPlaceholderNode(construct, currentPath, key, currentFiber, props) {
84
- // Generate ID using same logic as real nodes (use existing naming utilities)
85
- const id = (0, naming_1.getNodeName)(construct, props, key);
86
- const fullPath = [...currentPath, id];
87
- const resourceId = (0, naming_1.generateResourceId)(fullPath);
88
- const placeholderNode = {
89
- id: resourceId,
90
- path: fullPath,
91
- construct,
92
- constructType: construct.name || 'UnknownConstruct',
93
- props: props,
94
- children: [],
95
- outputs: {},
96
- };
97
- // Return a proxy that always returns undefined for outputs
98
- return new Proxy(placeholderNode, {
99
- get(target, prop) {
100
- if (prop === 'outputs') {
101
- return new Proxy({}, {
102
- get() {
103
- return undefined;
104
- },
105
- });
106
- }
107
- return Reflect.get(target, prop);
108
- },
109
- });
110
- }
111
- /**
112
- * Create an enhanced CloudDOM node with output reference capabilities
113
- * This allows automatic binding when outputs are used in useState
114
- * The proxy dynamically reads from the node's current outputs for reactivity
115
- *
116
- * REQ-2.1, 2.4, 2.5: Enhanced proxy that always reads live values and tracks access
117
- *
118
- * @internal
119
- */
120
- function createEnhancedNode(node, fiber) {
121
- // Create a proxy that intercepts property access to provide reactive output access
122
- return new Proxy(node, {
123
- get(target, prop, receiver) {
124
- // Special handling for 'outputs' property to ensure reactivity
125
- if (prop === 'outputs') {
126
- // Return a proxy for the outputs object that tracks reads
127
- return new Proxy(target.outputs || {}, {
128
- get(outputsTarget, outputKey) {
129
- if (typeof outputKey === 'string') {
130
- // REQ-2.1: Always read from current target.outputs (live values)
131
- const currentValue = target.outputs?.[outputKey];
132
- // REQ-2.4, 2.5: Track this output read for binding creation
133
- if (currentValue !== undefined) {
134
- const tracker = getProviderOutputTracker();
135
- tracker.trackOutputRead(target.id, outputKey, fiber);
136
- logger.debug(`Tracked output read: ${target.id}.${outputKey} = ${currentValue}`);
137
- }
138
- // REQ-2.2: Return undefined gracefully if not populated
139
- return currentValue;
140
- }
141
- return Reflect.get(outputsTarget, outputKey);
142
- },
143
- has(outputsTarget, outputKey) {
144
- // Check if output exists in current target.outputs
145
- return (typeof outputKey === 'string' &&
146
- target.outputs !== undefined &&
147
- outputKey in target.outputs);
148
- },
149
- ownKeys(outputsTarget) {
150
- // Return keys from current target.outputs
151
- return target.outputs ? Object.keys(target.outputs) : [];
152
- },
153
- });
154
- }
155
- // For all other properties, return the original value
156
- return Reflect.get(target, prop, receiver);
157
- },
158
- has(target, prop) {
159
- // Standard property checks
160
- return Reflect.has(target, prop);
161
- },
162
- ownKeys(target) {
163
- // Return original keys
164
- return Reflect.ownKeys(target);
165
- },
166
- });
167
- }
168
- /**
169
- * Set the current rendering context
170
- * Called by Renderer before executing a component
171
- *
172
- * @internal
173
- */
174
- function setInstanceRenderContext(fiber, path) {
175
- (0, context_1.setRenderContext)(fiber, path);
176
- }
177
- /**
178
- * Clear the current rendering context
179
- * Called by Renderer after component execution
180
- *
181
- * @internal
182
- */
183
- function clearInstanceRenderContext() {
184
- (0, context_1.clearRenderContext)();
185
- }
186
- /**
187
- * Set previous outputs map for restoration during render
188
- * Called by CReact before rendering
189
- *
190
- * @internal
191
- */
192
- function setPreviousOutputs(outputsMap) {
193
- (0, context_1.setPreviousOutputs)(outputsMap);
194
- }
195
- /**
196
- * Track construct call counts per component for auto-ID generation
197
- * Maps component fiber to construct type to call count
198
- */
199
- const constructCallCounts = new WeakMap();
200
- /**
201
- * useInstance hook - Register an infrastructure resource (React-like API)
202
- *
203
- * This hook creates a CloudDOM node and attaches it to the current Fiber.
204
- * It must be called during component rendering (inside a component function).
205
- *
206
- * Automatically extracts event callbacks (onDeploy, onError, onDestroy) from
207
- * component props and attaches them to the CloudDOM node for lifecycle events.
208
- *
209
- * REQ-01: JSX → CloudDOM rendering
210
- * REQ-04: Resource creation via hooks (React-like API)
211
- * REQ-2.3: CloudDOM event callbacks for deployment lifecycle
212
- *
213
- * @param construct - Constructor/class for the infrastructure resource
214
- * @param props - Properties/configuration for the resource (may include `key` and event callbacks)
215
- * @returns Reference to the created CloudDOM node
216
- *
217
- * @example
218
- * ```tsx
219
- * // With event callbacks (extracted from component props)
220
- * function MyDatabase({ onDeploy, onError }) {
221
- * const db = useInstance(Database, {
222
- * name: 'my-db',
223
- * size: '100GB'
224
- * });
225
- * // onDeploy and onError are automatically extracted from component props
226
- * return <></>;
227
- * }
228
- *
229
- * // Usage with event callbacks
230
- * <MyDatabase
231
- * onDeploy={(ctx) => logger.info('Database deployed:', ctx.resourceId)}
232
- * onError={(ctx, err) => logger.error('Database failed:', err)}
233
- * />
234
- *
235
- * // Without event callbacks (normal usage)
236
- * function MyBucket() {
237
- * const bucket = useInstance(S3Bucket, {
238
- * bucketName: 'my-assets'
239
- * });
240
- * return <></>;
241
- * }
242
- * ```
243
- */
244
- function useInstance(construct, props) {
245
- // Use consolidated hook context
246
- const context = (0, context_1.requireHookContext)();
247
- const currentFiber = context.currentFiber; // Non-null assertion safe due to requireHookContext validation
248
- const { currentPath, previousOutputsMap } = context;
249
- // Get hook index for this useInstance call (instance-specific)
250
- const hookIndex = (0, context_1.incrementHookIndex)('instance');
251
- // CONSTRAINT: Only one useInstance per component
252
- // This simplifies dependency tracking and drift recovery
253
- if (hookIndex > 0) {
254
- const componentName = currentFiber.type?.name || 'Anonymous';
255
- throw new Error(`[CReact Constraint] Only one useInstance call is allowed per component.\n\n` +
256
- `Component: ${componentName}\n` +
257
- `Path: ${currentPath.join('.')}\n\n` +
258
- `This constraint ensures:\n` +
259
- ` 1. Clear resource dependencies (parent-child nesting)\n` +
260
- ` 2. Simpler drift recovery (clear drifted node + children)\n` +
261
- ` 3. Better component composition\n\n` +
262
- `Solution: Split your component into multiple components, one per resource.\n\n` +
263
- `Example:\n` +
264
- ` ❌ function Stack() {\n` +
265
- ` const db = useInstance(Database, {...});\n` +
266
- ` const api = useInstance(API, {...}); // Error!\n` +
267
- ` }\n\n` +
268
- ` ✅ function Stack() {\n` +
269
- ` return (\n` +
270
- ` <>\n` +
271
- ` <PrimaryDatabase />\n` +
272
- ` <ApiServer />\n` +
273
- ` </>\n` +
274
- ` );\n` +
275
- ` }\n` +
276
- ` function PrimaryDatabase() {\n` +
277
- ` const db = useInstance(Database, {...});\n` +
278
- ` return <></>;\n` +
279
- ` }\n` +
280
- ` function ApiServer() {\n` +
281
- ` const api = useInstance(API, {...});\n` +
282
- ` return <></>;\n` +
283
- ` }\n`);
284
- }
285
- // Extract key from props (React-like)
286
- const { key, ...restProps } = props;
287
- // Check for undefined dependencies - enforce deployment order
288
- // If any prop value is undefined, don't create the node yet
289
- // This ensures resources are only created when their dependencies are available
290
- const hasUndefinedDeps = Object.values(restProps).some((v) => v === undefined);
291
- if (hasUndefinedDeps) {
292
- logger.info(`[Deployment Order] Skipping resource creation - undefined dependencies detected`);
293
- logger.info(` Construct: ${construct.name}`);
294
- logger.info(` Props with undefined values:`, Object.entries(restProps)
295
- .filter(([_, v]) => v === undefined)
296
- .map(([k]) => k));
297
- // Don't attach anything to fiber - this resource will be skipped entirely
298
- // Return a placeholder node that won't be included in CloudDOM
299
- // The proxy will return undefined for all output accesses
300
- // Use the same ID generation logic as real nodes for proper reconciliation tracking
301
- return createPlaceholderNode(construct, currentPath, key, currentFiber, restProps);
302
- }
303
- // Remove undefined values from props to match JSON serialization behavior
304
- // When CloudDOM is saved to backend, JSON.stringify strips undefined values
305
- // This ensures consistent comparison after deserialization
306
- const cleanProps = {};
307
- for (const [k, v] of Object.entries(restProps)) {
308
- if (v !== undefined) {
309
- cleanProps[k] = v;
310
- }
311
- }
312
- // Extract event callbacks from current component's props (not useInstance props)
313
- const componentProps = currentFiber.props || {};
314
- const eventCallbacks = {};
315
- // Extract onDeploy callback
316
- if (typeof componentProps.onDeploy === 'function') {
317
- eventCallbacks.onDeploy = componentProps.onDeploy;
318
- }
319
- // Extract onError callback
320
- if (typeof componentProps.onError === 'function') {
321
- eventCallbacks.onError = componentProps.onError;
322
- }
323
- // Extract onDestroy callback
324
- if (typeof componentProps.onDestroy === 'function') {
325
- eventCallbacks.onDestroy = componentProps.onDestroy;
326
- }
327
- // Generate ID using getNodeName for consistency with placeholder nodes
328
- // This ensures placeholder and real nodes have matching IDs for proper reconciliation
329
- const id = (0, naming_1.getNodeName)(construct, restProps, key);
330
- // Generate full resource ID from current path
331
- // Example: ['registry', 'service'] + 'bucket' → 'registry.service.bucket'
332
- const fullPath = [...currentPath, id];
333
- const resourceId = (0, naming_1.generateResourceId)(fullPath);
334
- // Generate stable constructType identifier
335
- // This is a serializable string that uniquely identifies the construct type
336
- const constructType = construct.name || 'UnknownConstruct';
337
- // Create CloudDOM node
338
- const node = {
339
- id: resourceId,
340
- path: fullPath,
341
- construct,
342
- constructType, // Serializable construct type identifier
343
- props: cleanProps, // Use cleaned props (no undefined values, no key)
344
- children: [],
345
- outputs: {}, // Will be populated during materialization
346
- eventCallbacks: Object.keys(eventCallbacks).length > 0 ? eventCallbacks : undefined,
347
- };
348
- // Restore outputs from previous state if available
349
- logger.debug(`Checking for outputs: ${resourceId}, map has ${previousOutputsMap?.size || 0} entries`);
350
- if (previousOutputsMap && previousOutputsMap.has(resourceId)) {
351
- node.outputs = { ...previousOutputsMap.get(resourceId) };
352
- logger.debug(`✓ Restored outputs for: ${resourceId}`, node.outputs);
353
- }
354
- else {
355
- logger.debug(`✗ No outputs found for: ${resourceId}`);
356
- if (previousOutputsMap) {
357
- logger.debug(` Available keys:`, Array.from(previousOutputsMap.keys()));
358
- }
359
- }
360
- // Attach node to current Fiber
361
- // The Fiber stores all CloudDOM nodes created during its execution
362
- if (!currentFiber.cloudDOMNodes) {
363
- currentFiber.cloudDOMNodes = [];
364
- }
365
- // Check if a node with this ID already exists (from previous render)
366
- // If so, update it instead of creating a duplicate
367
- const existingNodeIndex = currentFiber.cloudDOMNodes.findIndex((n) => n.id === resourceId);
368
- if (existingNodeIndex >= 0) {
369
- logger.debug(`Updating existing node: ${resourceId}`);
370
- currentFiber.cloudDOMNodes[existingNodeIndex] = node;
371
- }
372
- else {
373
- logger.debug(`Creating new node: ${resourceId}`);
374
- currentFiber.cloudDOMNodes.push(node);
375
- }
376
- // Track this instance with ProviderOutputTracker for output change detection
377
- const outputTracker = getProviderOutputTracker();
378
- outputTracker.trackInstance(node, currentFiber);
379
- // REQ-2.3, 6.1: Enhance the node with proxy that reads live values and tracks access
380
- // No longer creating stale outputReferences - proxy reads directly from target.outputs
381
- const enhancedNode = createEnhancedNode(node, currentFiber);
382
- // Debug logging
383
- logger.debug(`Created and tracked instance: ${resourceId}`);
384
- logger.debug(`Node outputs at creation: ${JSON.stringify(node.outputs || {})}`);
385
- // Return reference to the enhanced node
386
- // This allows components to reference the resource and its outputs
387
- // REQ-2.5: Multiple accesses within same render cycle are consistent
388
- return enhancedNode;
389
- }
390
- /**
391
- * Reset construct call counts for a fiber
392
- * Called by Renderer before executing a component
393
- *
394
- * @internal
395
- */
396
- function resetConstructCounts(fiber) {
397
- constructCallCounts.delete(fiber);
398
- }
399
- /**
400
- * Get the current rendering path
401
- * Useful for debugging and testing
402
- *
403
- * @internal
404
- */
405
- function getCurrentPath() {
406
- try {
407
- const context = (0, context_1.requireHookContext)();
408
- return [...context.currentPath];
409
- }
410
- catch {
411
- return [];
412
- }
413
- }
414
- /**
415
- * Check if currently rendering
416
- * Useful for validation and testing
417
- *
418
- * @internal
419
- */
420
- function isRendering() {
421
- try {
422
- const context = (0, context_1.requireHookContext)();
423
- return context.currentFiber !== null;
424
- }
425
- catch {
426
- return false;
427
- }
428
- }
429
- /**
430
- * Update outputs for a CloudDOM node and notify bound components
431
- * This is called after deployment when provider outputs are available
432
- * @internal
433
- */
434
- function updateNodeOutputs(nodeId, newOutputs) {
435
- const outputTracker = getProviderOutputTracker();
436
- const changes = outputTracker.updateNodeOutputs(nodeId, newOutputs);
437
- if (changes.length > 0) {
438
- // Process the changes and get affected fibers
439
- const affectedFibers = outputTracker.processOutputChanges(changes);
440
- logger.debug(`Output changes detected for ${nodeId}:`, {
441
- changes: changes.length,
442
- affectedFibers: affectedFibers.size,
443
- });
444
- // Note: The actual re-rendering will be handled by the RenderScheduler
445
- // when it's integrated with the CReact main orchestrator
446
- }
447
- }
448
- /**
449
- * Get current outputs for a CloudDOM node
450
- * @internal
451
- */
452
- function getNodeOutputs(nodeId) {
453
- const outputTracker = getProviderOutputTracker();
454
- return outputTracker.getNodeOutputs(nodeId);
455
- }