typekro 0.2.2 → 0.3.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 (213) hide show
  1. package/README.md +4 -3
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/core/composition/imperative.d.ts.map +1 -1
  4. package/dist/core/composition/imperative.js +15 -2
  5. package/dist/core/composition/imperative.js.map +1 -1
  6. package/dist/core/composition/typekro-runtime/typekro-runtime.d.ts.map +1 -1
  7. package/dist/core/composition/typekro-runtime/typekro-runtime.js +24 -25
  8. package/dist/core/composition/typekro-runtime/typekro-runtime.js.map +1 -1
  9. package/dist/core/dependencies/type-guards.d.ts.map +1 -1
  10. package/dist/core/dependencies/type-guards.js +7 -2
  11. package/dist/core/dependencies/type-guards.js.map +1 -1
  12. package/dist/core/deployment/engine.d.ts +13 -1
  13. package/dist/core/deployment/engine.d.ts.map +1 -1
  14. package/dist/core/deployment/engine.js +48 -3
  15. package/dist/core/deployment/engine.js.map +1 -1
  16. package/dist/core/errors.d.ts +85 -0
  17. package/dist/core/errors.d.ts.map +1 -1
  18. package/dist/core/errors.js +135 -0
  19. package/dist/core/errors.js.map +1 -1
  20. package/dist/core/evaluation/cel-optimizer.d.ts.map +1 -1
  21. package/dist/core/evaluation/cel-optimizer.js +7 -13
  22. package/dist/core/evaluation/cel-optimizer.js.map +1 -1
  23. package/dist/core/expressions/analyzer.d.ts +584 -0
  24. package/dist/core/expressions/analyzer.d.ts.map +1 -0
  25. package/dist/core/expressions/analyzer.js +2956 -0
  26. package/dist/core/expressions/analyzer.js.map +1 -0
  27. package/dist/core/expressions/cache.d.ts +136 -0
  28. package/dist/core/expressions/cache.d.ts.map +1 -0
  29. package/dist/core/expressions/cache.js +347 -0
  30. package/dist/core/expressions/cache.js.map +1 -0
  31. package/dist/core/expressions/cel-conversion-engine.d.ts +126 -0
  32. package/dist/core/expressions/cel-conversion-engine.d.ts.map +1 -0
  33. package/dist/core/expressions/cel-conversion-engine.js +293 -0
  34. package/dist/core/expressions/cel-conversion-engine.js.map +1 -0
  35. package/dist/core/expressions/compile-time-validation.d.ts +270 -0
  36. package/dist/core/expressions/compile-time-validation.d.ts.map +1 -0
  37. package/dist/core/expressions/compile-time-validation.js +506 -0
  38. package/dist/core/expressions/compile-time-validation.js.map +1 -0
  39. package/dist/core/expressions/composition-integration.d.ts +315 -0
  40. package/dist/core/expressions/composition-integration.d.ts.map +1 -0
  41. package/dist/core/expressions/composition-integration.js +936 -0
  42. package/dist/core/expressions/composition-integration.js.map +1 -0
  43. package/dist/core/expressions/conditional-expression-processor.d.ts +154 -0
  44. package/dist/core/expressions/conditional-expression-processor.d.ts.map +1 -0
  45. package/dist/core/expressions/conditional-expression-processor.js +479 -0
  46. package/dist/core/expressions/conditional-expression-processor.js.map +1 -0
  47. package/dist/core/expressions/conditional-integration.d.ts +133 -0
  48. package/dist/core/expressions/conditional-integration.d.ts.map +1 -0
  49. package/dist/core/expressions/conditional-integration.js +293 -0
  50. package/dist/core/expressions/conditional-integration.js.map +1 -0
  51. package/dist/core/expressions/conditional-validation.d.ts +181 -0
  52. package/dist/core/expressions/conditional-validation.d.ts.map +1 -0
  53. package/dist/core/expressions/conditional-validation.js +460 -0
  54. package/dist/core/expressions/conditional-validation.js.map +1 -0
  55. package/dist/core/expressions/context-aware-generator.d.ts +127 -0
  56. package/dist/core/expressions/context-aware-generator.d.ts.map +1 -0
  57. package/dist/core/expressions/context-aware-generator.js +500 -0
  58. package/dist/core/expressions/context-aware-generator.js.map +1 -0
  59. package/dist/core/expressions/context-detector.d.ts +148 -0
  60. package/dist/core/expressions/context-detector.d.ts.map +1 -0
  61. package/dist/core/expressions/context-detector.js +546 -0
  62. package/dist/core/expressions/context-detector.js.map +1 -0
  63. package/dist/core/expressions/context-switcher.d.ts +185 -0
  64. package/dist/core/expressions/context-switcher.d.ts.map +1 -0
  65. package/dist/core/expressions/context-switcher.js +515 -0
  66. package/dist/core/expressions/context-switcher.js.map +1 -0
  67. package/dist/core/expressions/context-validator.d.ts +176 -0
  68. package/dist/core/expressions/context-validator.d.ts.map +1 -0
  69. package/dist/core/expressions/context-validator.js +452 -0
  70. package/dist/core/expressions/context-validator.js.map +1 -0
  71. package/dist/core/expressions/custom-context-manager.d.ts +194 -0
  72. package/dist/core/expressions/custom-context-manager.d.ts.map +1 -0
  73. package/dist/core/expressions/custom-context-manager.js +390 -0
  74. package/dist/core/expressions/custom-context-manager.js.map +1 -0
  75. package/dist/core/expressions/expression-proxy.d.ts +80 -0
  76. package/dist/core/expressions/expression-proxy.d.ts.map +1 -0
  77. package/dist/core/expressions/expression-proxy.js +227 -0
  78. package/dist/core/expressions/expression-proxy.js.map +1 -0
  79. package/dist/core/expressions/factory-integration.d.ts +132 -0
  80. package/dist/core/expressions/factory-integration.d.ts.map +1 -0
  81. package/dist/core/expressions/factory-integration.js +327 -0
  82. package/dist/core/expressions/factory-integration.js.map +1 -0
  83. package/dist/core/expressions/factory-pattern-handler.d.ts +88 -0
  84. package/dist/core/expressions/factory-pattern-handler.d.ts.map +1 -0
  85. package/dist/core/expressions/factory-pattern-handler.js +336 -0
  86. package/dist/core/expressions/factory-pattern-handler.js.map +1 -0
  87. package/dist/core/expressions/field-hydration-processor.d.ts +188 -0
  88. package/dist/core/expressions/field-hydration-processor.d.ts.map +1 -0
  89. package/dist/core/expressions/field-hydration-processor.js +562 -0
  90. package/dist/core/expressions/field-hydration-processor.js.map +1 -0
  91. package/dist/core/expressions/imperative-analyzer.d.ts +21 -0
  92. package/dist/core/expressions/imperative-analyzer.d.ts.map +1 -0
  93. package/dist/core/expressions/imperative-analyzer.js +457 -0
  94. package/dist/core/expressions/imperative-analyzer.js.map +1 -0
  95. package/dist/core/expressions/index.d.ts +54 -0
  96. package/dist/core/expressions/index.d.ts.map +1 -0
  97. package/dist/core/expressions/index.js +50 -0
  98. package/dist/core/expressions/index.js.map +1 -0
  99. package/dist/core/expressions/lazy-analysis.d.ts +1128 -0
  100. package/dist/core/expressions/lazy-analysis.d.ts.map +1 -0
  101. package/dist/core/expressions/lazy-analysis.js +2443 -0
  102. package/dist/core/expressions/lazy-analysis.js.map +1 -0
  103. package/dist/core/expressions/magic-assignable-analyzer.d.ts +123 -0
  104. package/dist/core/expressions/magic-assignable-analyzer.d.ts.map +1 -0
  105. package/dist/core/expressions/magic-assignable-analyzer.js +352 -0
  106. package/dist/core/expressions/magic-assignable-analyzer.js.map +1 -0
  107. package/dist/core/expressions/magic-proxy-analyzer.d.ts +206 -0
  108. package/dist/core/expressions/magic-proxy-analyzer.d.ts.map +1 -0
  109. package/dist/core/expressions/magic-proxy-analyzer.js +639 -0
  110. package/dist/core/expressions/magic-proxy-analyzer.js.map +1 -0
  111. package/dist/core/expressions/magic-proxy-detector.d.ts +154 -0
  112. package/dist/core/expressions/magic-proxy-detector.d.ts.map +1 -0
  113. package/dist/core/expressions/magic-proxy-detector.js +242 -0
  114. package/dist/core/expressions/magic-proxy-detector.js.map +1 -0
  115. package/dist/core/expressions/migration-helpers.d.ts +133 -0
  116. package/dist/core/expressions/migration-helpers.d.ts.map +1 -0
  117. package/dist/core/expressions/migration-helpers.js +443 -0
  118. package/dist/core/expressions/migration-helpers.js.map +1 -0
  119. package/dist/core/expressions/optionality-handler.d.ts +503 -0
  120. package/dist/core/expressions/optionality-handler.d.ts.map +1 -0
  121. package/dist/core/expressions/optionality-handler.js +1306 -0
  122. package/dist/core/expressions/optionality-handler.js.map +1 -0
  123. package/dist/core/expressions/readiness-integration.d.ts +119 -0
  124. package/dist/core/expressions/readiness-integration.d.ts.map +1 -0
  125. package/dist/core/expressions/readiness-integration.js +386 -0
  126. package/dist/core/expressions/readiness-integration.js.map +1 -0
  127. package/dist/core/expressions/resource-analyzer.d.ts +486 -0
  128. package/dist/core/expressions/resource-analyzer.d.ts.map +1 -0
  129. package/dist/core/expressions/resource-analyzer.js +1086 -0
  130. package/dist/core/expressions/resource-analyzer.js.map +1 -0
  131. package/dist/core/expressions/resource-validation.d.ts +187 -0
  132. package/dist/core/expressions/resource-validation.d.ts.map +1 -0
  133. package/dist/core/expressions/resource-validation.js +552 -0
  134. package/dist/core/expressions/resource-validation.js.map +1 -0
  135. package/dist/core/expressions/runtime-error-mapper.d.ts +138 -0
  136. package/dist/core/expressions/runtime-error-mapper.d.ts.map +1 -0
  137. package/dist/core/expressions/runtime-error-mapper.js +412 -0
  138. package/dist/core/expressions/runtime-error-mapper.js.map +1 -0
  139. package/dist/core/expressions/source-map.d.ts +168 -0
  140. package/dist/core/expressions/source-map.d.ts.map +1 -0
  141. package/dist/core/expressions/source-map.js +350 -0
  142. package/dist/core/expressions/source-map.js.map +1 -0
  143. package/dist/core/expressions/status-builder-analyzer.d.ts +353 -0
  144. package/dist/core/expressions/status-builder-analyzer.d.ts.map +1 -0
  145. package/dist/core/expressions/status-builder-analyzer.js +1311 -0
  146. package/dist/core/expressions/status-builder-analyzer.js.map +1 -0
  147. package/dist/core/expressions/type-inference.d.ts +184 -0
  148. package/dist/core/expressions/type-inference.d.ts.map +1 -0
  149. package/dist/core/expressions/type-inference.js +838 -0
  150. package/dist/core/expressions/type-inference.js.map +1 -0
  151. package/dist/core/expressions/type-safety.d.ts +203 -0
  152. package/dist/core/expressions/type-safety.d.ts.map +1 -0
  153. package/dist/core/expressions/type-safety.js +442 -0
  154. package/dist/core/expressions/type-safety.js.map +1 -0
  155. package/dist/core/expressions/types.d.ts +282 -0
  156. package/dist/core/expressions/types.d.ts.map +1 -0
  157. package/dist/core/expressions/types.js +8 -0
  158. package/dist/core/expressions/types.js.map +1 -0
  159. package/dist/core/kubernetes/client-provider.js +2 -2
  160. package/dist/core/kubernetes/client-provider.js.map +1 -1
  161. package/dist/core/references/cel.d.ts +13 -1
  162. package/dist/core/references/cel.d.ts.map +1 -1
  163. package/dist/core/references/cel.js +50 -0
  164. package/dist/core/references/cel.js.map +1 -1
  165. package/dist/core/references/schema-proxy.d.ts.map +1 -1
  166. package/dist/core/references/schema-proxy.js +13 -8
  167. package/dist/core/references/schema-proxy.js.map +1 -1
  168. package/dist/core/serialization/core.d.ts.map +1 -1
  169. package/dist/core/serialization/core.js +573 -9
  170. package/dist/core/serialization/core.js.map +1 -1
  171. package/dist/core/types/deployment.d.ts +7 -0
  172. package/dist/core/types/deployment.d.ts.map +1 -1
  173. package/dist/core/types/deployment.js +7 -0
  174. package/dist/core/types/deployment.js.map +1 -1
  175. package/dist/core/types/index.d.ts +1 -0
  176. package/dist/core/types/index.d.ts.map +1 -1
  177. package/dist/core/types/index.js.map +1 -1
  178. package/dist/core/validation/cel-validator.d.ts.map +1 -1
  179. package/dist/core/validation/cel-validator.js +4 -8
  180. package/dist/core/validation/cel-validator.js.map +1 -1
  181. package/dist/core.d.ts +1 -1
  182. package/dist/core.d.ts.map +1 -1
  183. package/dist/core.js +1 -1
  184. package/dist/core.js.map +1 -1
  185. package/dist/factories/helm/helm-release.d.ts.map +1 -1
  186. package/dist/factories/helm/helm-release.js +0 -5
  187. package/dist/factories/helm/helm-release.js.map +1 -1
  188. package/dist/factories/helm/types.d.ts +1 -1
  189. package/dist/factories/helm/types.d.ts.map +1 -1
  190. package/dist/factories/index.js +1 -0
  191. package/dist/factories/index.js.map +1 -1
  192. package/dist/factories/shared.d.ts.map +1 -1
  193. package/dist/factories/shared.js +21 -1
  194. package/dist/factories/shared.js.map +1 -1
  195. package/dist/factories/simple/index.d.ts +2 -2
  196. package/dist/factories/simple/index.d.ts.map +1 -1
  197. package/dist/factories/simple/workloads/deployment.d.ts +3 -3
  198. package/dist/factories/simple/workloads/deployment.d.ts.map +1 -1
  199. package/dist/factories/simple/workloads/deployment.js +37 -11
  200. package/dist/factories/simple/workloads/deployment.js.map +1 -1
  201. package/dist/index.d.ts +1 -1
  202. package/dist/index.d.ts.map +1 -1
  203. package/dist/index.js +1 -1
  204. package/dist/index.js.map +1 -1
  205. package/dist/utils/index.d.ts +1 -1
  206. package/dist/utils/index.d.ts.map +1 -1
  207. package/dist/utils/index.js +1 -1
  208. package/dist/utils/index.js.map +1 -1
  209. package/dist/utils/type-guards.d.ts +6 -0
  210. package/dist/utils/type-guards.d.ts.map +1 -1
  211. package/dist/utils/type-guards.js +25 -2
  212. package/dist/utils/type-guards.js.map +1 -1
  213. package/package.json +6 -1
@@ -0,0 +1,936 @@
1
+ /**
2
+ * Composition Integration for JavaScript to CEL Expression Conversion
3
+ *
4
+ * This module provides integration between the kubernetesComposition API and the
5
+ * JavaScript to CEL expression conversion system. It handles KubernetesRef detection
6
+ * and conversion within imperative composition patterns.
7
+ */
8
+ import { getCurrentCompositionContext } from '../../factories/shared.js';
9
+ import { isKubernetesRef } from '../../utils/type-guards.js';
10
+ import { MagicAssignableAnalyzer } from './magic-assignable-analyzer.js';
11
+ import { CelConversionEngine } from './cel-conversion-engine.js';
12
+ /**
13
+ * Composition-aware expression analyzer that integrates with kubernetesComposition
14
+ */
15
+ export class CompositionExpressionAnalyzer {
16
+ magicAssignableAnalyzer;
17
+ celEngine;
18
+ patternConfigs;
19
+ contextTracker;
20
+ scopeManager;
21
+ constructor() {
22
+ this.magicAssignableAnalyzer = new MagicAssignableAnalyzer();
23
+ this.celEngine = new CelConversionEngine();
24
+ this.contextTracker = new CompositionContextTracker();
25
+ this.scopeManager = new MagicProxyScopeManager();
26
+ // Initialize pattern-specific configurations
27
+ this.patternConfigs = new Map([
28
+ ['imperative', {
29
+ pattern: 'imperative',
30
+ allowSideEffects: true,
31
+ trackResourceCreation: true,
32
+ validateScope: true,
33
+ convertTocel: true,
34
+ }],
35
+ ['declarative', {
36
+ pattern: 'declarative',
37
+ allowSideEffects: false,
38
+ trackResourceCreation: false,
39
+ validateScope: false,
40
+ convertTocel: true,
41
+ }],
42
+ ]);
43
+ }
44
+ /**
45
+ * Detect the composition pattern being used
46
+ */
47
+ detectCompositionPattern(compositionFn, context) {
48
+ // If there's an active composition context, it's imperative
49
+ if (context || getCurrentCompositionContext()) {
50
+ return 'imperative';
51
+ }
52
+ // Analyze function signature and behavior
53
+ const fnString = compositionFn.toString();
54
+ // Look for imperative patterns
55
+ const imperativeIndicators = [
56
+ /\.add\w+\(/, // .addResource, .addService, etc.
57
+ /register\w+\(/, // registerResource, etc.
58
+ /create\w+\(/, // createResource, etc.
59
+ /simple\w+\(/, // simpleDeployment, simpleService, etc.
60
+ ];
61
+ const hasImperativeIndicators = imperativeIndicators.some(pattern => pattern.test(fnString));
62
+ return hasImperativeIndicators ? 'imperative' : 'declarative';
63
+ }
64
+ /**
65
+ * Analyze composition function with pattern awareness
66
+ */
67
+ analyzeCompositionFunctionWithPattern(compositionFn, schemaProxy, pattern, context) {
68
+ // Detect pattern if not provided
69
+ const detectedPattern = pattern || this.detectCompositionPattern(compositionFn, context);
70
+ const config = this.patternConfigs.get(detectedPattern);
71
+ // Track side effects if this is an imperative pattern
72
+ let sideEffectsDetected = false;
73
+ let resourceCreationTracked = false;
74
+ let scopeValidationPerformed = false;
75
+ if (config.trackResourceCreation && context) {
76
+ const resourcesBefore = new Set(Object.keys(context.resources));
77
+ // Execute the base analysis
78
+ const baseResult = this.analyzeCompositionFunction(compositionFn, schemaProxy, context);
79
+ // Check for side effects
80
+ const resourcesAfter = Object.keys(context.resources);
81
+ sideEffectsDetected = resourcesAfter.some(id => !resourcesBefore.has(id));
82
+ resourceCreationTracked = true;
83
+ // Perform scope validation if enabled
84
+ if (config.validateScope) {
85
+ // This would be handled by the scope manager
86
+ scopeValidationPerformed = true;
87
+ }
88
+ return {
89
+ ...baseResult,
90
+ pattern: detectedPattern,
91
+ patternSpecificMetadata: {
92
+ sideEffectsDetected,
93
+ resourceCreationTracked,
94
+ scopeValidationPerformed,
95
+ },
96
+ };
97
+ }
98
+ else {
99
+ // Execute the base analysis without side effect tracking
100
+ const baseResult = this.analyzeCompositionFunction(compositionFn, schemaProxy, context);
101
+ return {
102
+ ...baseResult,
103
+ pattern: detectedPattern,
104
+ patternSpecificMetadata: {
105
+ sideEffectsDetected,
106
+ resourceCreationTracked,
107
+ scopeValidationPerformed,
108
+ },
109
+ };
110
+ }
111
+ }
112
+ /**
113
+ * Process composition based on detected pattern
114
+ */
115
+ processCompositionByPattern(statusShape, pattern, factoryType = 'kro') {
116
+ const config = this.patternConfigs.get(pattern);
117
+ if (!config.convertTocel) {
118
+ // Pattern doesn't require CEL conversion
119
+ return statusShape;
120
+ }
121
+ // Use the standard processing logic
122
+ return this.processCompositionStatus(statusShape, factoryType);
123
+ }
124
+ /**
125
+ * Validate composition pattern compatibility
126
+ */
127
+ validatePatternCompatibility(pattern, factoryType, context) {
128
+ const warnings = [];
129
+ const recommendations = [];
130
+ let isCompatible = true;
131
+ const config = this.patternConfigs.get(pattern);
132
+ // Check imperative pattern with direct factory
133
+ if (pattern === 'imperative' && factoryType === 'direct') {
134
+ if (!context) {
135
+ warnings.push('Imperative pattern without composition context may not work correctly with direct factory');
136
+ recommendations.push('Ensure kubernetesComposition is used with proper context management');
137
+ }
138
+ }
139
+ // Check declarative pattern with side effects
140
+ if (pattern === 'declarative' && config.allowSideEffects && context) {
141
+ const resourceCount = Object.keys(context.resources).length;
142
+ if (resourceCount > 0) {
143
+ warnings.push('Declarative pattern detected but resources found in composition context');
144
+ recommendations.push('Consider using imperative pattern (kubernetesComposition) for side-effect based resource creation');
145
+ }
146
+ }
147
+ // Check CEL conversion compatibility
148
+ if (factoryType === 'kro' && !config.convertTocel) {
149
+ isCompatible = false;
150
+ warnings.push(`Pattern '${pattern}' is not compatible with Kro factory (CEL conversion required)`);
151
+ recommendations.push('Use direct factory or enable CEL conversion for this pattern');
152
+ }
153
+ return {
154
+ isCompatible,
155
+ warnings,
156
+ recommendations,
157
+ };
158
+ }
159
+ /**
160
+ * Get pattern-specific analysis recommendations
161
+ */
162
+ getPatternRecommendations(pattern, analysisResult) {
163
+ const recommendations = [];
164
+ if (pattern === 'imperative') {
165
+ if (analysisResult.kubernetesRefs.length === 0) {
166
+ recommendations.push('Consider using declarative pattern (toResourceGraph) for static compositions without KubernetesRef objects');
167
+ }
168
+ if (analysisResult.referencedResources.length > 10) {
169
+ recommendations.push('Large number of resource references detected - consider breaking into smaller compositions');
170
+ }
171
+ }
172
+ if (pattern === 'declarative') {
173
+ if (analysisResult.kubernetesRefs.length > 0) {
174
+ recommendations.push('KubernetesRef objects detected - imperative pattern (kubernetesComposition) might be more suitable');
175
+ }
176
+ }
177
+ return recommendations;
178
+ }
179
+ /**
180
+ * Analyze a composition function for KubernetesRef usage and expression conversion needs
181
+ */
182
+ analyzeCompositionFunction(compositionFn, schemaProxy, context) {
183
+ const _startTime = Date.now();
184
+ try {
185
+ // Execute the composition function to capture the returned status shape
186
+ const statusShape = compositionFn(schemaProxy.spec);
187
+ // Create analysis context
188
+ const analysisContext = {
189
+ type: 'status',
190
+ availableReferences: context?.resources || {},
191
+ schemaProxy,
192
+ factoryType: 'kro',
193
+ };
194
+ // Analyze the status shape for KubernetesRef objects
195
+ const analysisResult = this.magicAssignableAnalyzer.analyzeMagicAssignableShape(statusShape, analysisContext);
196
+ // Extract referenced resources from the composition context if available
197
+ const referencedResources = this.extractReferencedResources(context);
198
+ // Determine if CEL conversion is needed
199
+ const requiresCelConversion = analysisResult.dependencies.length > 0;
200
+ const conversionMetadata = {
201
+ expressionsAnalyzed: Object.keys(analysisResult.fieldResults).length,
202
+ kubernetesRefsDetected: analysisResult.dependencies.length,
203
+ celExpressionsGenerated: requiresCelConversion ? Object.keys(analysisResult.fieldResults).length : 0,
204
+ };
205
+ return {
206
+ statusShape,
207
+ kubernetesRefs: analysisResult.dependencies,
208
+ referencedResources,
209
+ requiresCelConversion,
210
+ conversionMetadata,
211
+ };
212
+ }
213
+ catch (error) {
214
+ throw new Error(`Failed to analyze composition function: ${error instanceof Error ? error.message : String(error)}`);
215
+ }
216
+ }
217
+ /**
218
+ * Analyze a composition function's resource creation patterns
219
+ */
220
+ analyzeResourceCreation(compositionFn, schemaProxy, context) {
221
+ const currentContext = context || getCurrentCompositionContext();
222
+ if (!currentContext) {
223
+ return {
224
+ resourcesCreated: [],
225
+ kubernetesRefsInResources: [],
226
+ requiresCelConversion: false,
227
+ };
228
+ }
229
+ // Track resources before execution
230
+ const resourcesBefore = new Set(Object.keys(currentContext.resources));
231
+ try {
232
+ // Execute the composition function to trigger resource creation
233
+ compositionFn(schemaProxy.spec);
234
+ // Find newly created resources
235
+ const resourcesAfter = Object.keys(currentContext.resources);
236
+ const resourcesCreated = resourcesAfter.filter(id => !resourcesBefore.has(id));
237
+ // Analyze newly created resources for KubernetesRef objects
238
+ const kubernetesRefsInResources = [];
239
+ for (const resourceId of resourcesCreated) {
240
+ const resource = currentContext.resources[resourceId];
241
+ if (resource) {
242
+ const refs = this.extractKubernetesRefsFromResource(resource);
243
+ kubernetesRefsInResources.push(...refs);
244
+ }
245
+ }
246
+ return {
247
+ resourcesCreated,
248
+ kubernetesRefsInResources,
249
+ requiresCelConversion: kubernetesRefsInResources.length > 0,
250
+ };
251
+ }
252
+ catch (error) {
253
+ throw new Error(`Failed to analyze resource creation: ${error instanceof Error ? error.message : String(error)}`);
254
+ }
255
+ }
256
+ /**
257
+ * Process a composition's status shape for CEL conversion
258
+ */
259
+ processCompositionStatus(statusShape, factoryType = 'kro') {
260
+ if (factoryType === 'direct') {
261
+ // For direct factory, leave expressions as-is for runtime evaluation
262
+ return statusShape;
263
+ }
264
+ // Create analysis context
265
+ const analysisContext = {
266
+ type: 'status',
267
+ availableReferences: {},
268
+ factoryType,
269
+ };
270
+ // For Kro factory, convert KubernetesRef-containing expressions to CEL
271
+ return this.magicAssignableAnalyzer.analyzeMagicAssignableShape(statusShape, analysisContext).processedShape;
272
+ }
273
+ /**
274
+ * Enhanced status building with comprehensive KubernetesRef handling
275
+ */
276
+ buildCompositionStatus(statusShape, context, factoryType = 'kro') {
277
+ // Create analysis context
278
+ const analysisContext = {
279
+ type: 'status',
280
+ availableReferences: context.resources,
281
+ factoryType,
282
+ };
283
+ // Analyze the status shape for KubernetesRef objects
284
+ const analysisResult = this.magicAssignableAnalyzer.analyzeMagicAssignableShape(statusShape, analysisContext);
285
+ // Track context for dependency analysis
286
+ const contextTracking = this.contextTracker.trackCompositionContext(context);
287
+ // Extract dependencies from KubernetesRef objects
288
+ const dependencies = new Set();
289
+ let crossResourceReferences = 0;
290
+ for (const ref of analysisResult.dependencies) {
291
+ if (ref.resourceId !== '__schema__') {
292
+ dependencies.add(ref.resourceId);
293
+ // Check if this is a cross-resource reference
294
+ if (contextTracking.resourcesWithKubernetesRefs.includes(ref.resourceId)) {
295
+ crossResourceReferences++;
296
+ }
297
+ }
298
+ }
299
+ // Process the status shape based on factory type
300
+ let processedStatus;
301
+ let celExpressionsGenerated = 0;
302
+ if (factoryType === 'direct') {
303
+ // For direct factory, leave expressions as-is for runtime evaluation
304
+ processedStatus = statusShape;
305
+ }
306
+ else {
307
+ // For Kro factory, convert KubernetesRef-containing expressions to CEL
308
+ processedStatus = analysisResult.processedShape;
309
+ celExpressionsGenerated = Object.keys(analysisResult.fieldResults).length;
310
+ }
311
+ return {
312
+ processedStatus,
313
+ kubernetesRefs: analysisResult.dependencies,
314
+ dependencies: Array.from(dependencies),
315
+ requiresCelConversion: analysisResult.dependencies.length > 0,
316
+ conversionMetadata: {
317
+ fieldsProcessed: Object.keys(analysisResult.fieldResults).length,
318
+ kubernetesRefsFound: analysisResult.dependencies.length,
319
+ celExpressionsGenerated,
320
+ crossResourceReferences,
321
+ },
322
+ };
323
+ }
324
+ /**
325
+ * Validate status shape for composition compatibility
326
+ */
327
+ validateStatusShape(statusShape, context) {
328
+ const errors = [];
329
+ const warnings = [];
330
+ try {
331
+ // Create analysis context
332
+ const analysisContext = {
333
+ type: 'status',
334
+ availableReferences: context?.resources || {},
335
+ factoryType: 'kro',
336
+ };
337
+ // Analyze the status shape
338
+ const analysisResult = this.magicAssignableAnalyzer.analyzeMagicAssignableShape(statusShape, analysisContext);
339
+ // Validate each KubernetesRef
340
+ for (const ref of analysisResult.dependencies) {
341
+ const scopeValidation = this.scopeManager.validateKubernetesRefScope(ref);
342
+ if (!scopeValidation.isValid) {
343
+ errors.push(`Invalid KubernetesRef scope: ${scopeValidation.error}`);
344
+ }
345
+ // Check if the referenced resource exists in the context
346
+ if (context && ref.resourceId !== '__schema__' && !context.resources[ref.resourceId]) {
347
+ warnings.push(`Referenced resource '${ref.resourceId}' not found in composition context`);
348
+ }
349
+ }
350
+ // Check for circular dependencies
351
+ if (context) {
352
+ const contextTracking = this.contextTracker.trackCompositionContext(context);
353
+ // Simple circular dependency detection
354
+ const resourceGraph = new Map();
355
+ for (const crossRef of contextTracking.crossResourceReferences) {
356
+ if (!resourceGraph.has(crossRef.sourceResource)) {
357
+ resourceGraph.set(crossRef.sourceResource, new Set());
358
+ }
359
+ resourceGraph.get(crossRef.sourceResource)?.add(crossRef.targetResource);
360
+ }
361
+ // Check for cycles using DFS
362
+ const visited = new Set();
363
+ const recursionStack = new Set();
364
+ const hasCycle = (node) => {
365
+ if (recursionStack.has(node)) {
366
+ return true;
367
+ }
368
+ if (visited.has(node)) {
369
+ return false;
370
+ }
371
+ visited.add(node);
372
+ recursionStack.add(node);
373
+ const neighbors = resourceGraph.get(node) || new Set();
374
+ for (const neighbor of neighbors) {
375
+ if (hasCycle(neighbor)) {
376
+ return true;
377
+ }
378
+ }
379
+ recursionStack.delete(node);
380
+ return false;
381
+ };
382
+ for (const resource of resourceGraph.keys()) {
383
+ if (hasCycle(resource)) {
384
+ errors.push(`Circular dependency detected involving resource '${resource}'`);
385
+ break;
386
+ }
387
+ }
388
+ }
389
+ }
390
+ catch (error) {
391
+ errors.push(`Status shape validation failed: ${error instanceof Error ? error.message : String(error)}`);
392
+ }
393
+ return {
394
+ isValid: errors.length === 0,
395
+ errors,
396
+ warnings,
397
+ };
398
+ }
399
+ /**
400
+ * Extract referenced resources from composition context
401
+ */
402
+ extractReferencedResources(context) {
403
+ if (!context) {
404
+ const currentContext = getCurrentCompositionContext();
405
+ if (!currentContext) {
406
+ return [];
407
+ }
408
+ context = currentContext;
409
+ }
410
+ return Object.keys(context.resources);
411
+ }
412
+ /**
413
+ * Extract KubernetesRef objects from a resource
414
+ */
415
+ extractKubernetesRefsFromResource(resource) {
416
+ const refs = [];
417
+ const traverse = (obj) => {
418
+ if (isKubernetesRef(obj)) {
419
+ refs.push(obj);
420
+ return;
421
+ }
422
+ if (Array.isArray(obj)) {
423
+ obj.forEach(traverse);
424
+ }
425
+ else if (obj && typeof obj === 'object') {
426
+ Object.values(obj).forEach(traverse);
427
+ }
428
+ };
429
+ traverse(resource);
430
+ return refs;
431
+ }
432
+ }
433
+ /**
434
+ * Context-aware resource tracking for composition integration
435
+ */
436
+ export class CompositionContextTracker {
437
+ contextAnalysisCache = new Map();
438
+ resourceKubernetesRefCache = new Map();
439
+ /**
440
+ * Track KubernetesRef usage in a composition context
441
+ */
442
+ trackCompositionContext(context) {
443
+ const allKubernetesRefs = [];
444
+ const resourcesWithKubernetesRefs = [];
445
+ const crossResourceReferences = [];
446
+ // Analyze all resources in the context
447
+ for (const [resourceId, resource] of Object.entries(context.resources)) {
448
+ const refs = this.extractKubernetesRefsFromResource(resource);
449
+ if (refs.length > 0) {
450
+ resourcesWithKubernetesRefs.push(resourceId);
451
+ allKubernetesRefs.push(...refs);
452
+ // Cache the refs for this resource
453
+ this.resourceKubernetesRefCache.set(resourceId, refs);
454
+ // Identify cross-resource references
455
+ for (const ref of refs) {
456
+ if (ref.resourceId !== resourceId && ref.resourceId !== '__schema__') {
457
+ crossResourceReferences.push({
458
+ sourceResource: resourceId,
459
+ targetResource: ref.resourceId,
460
+ fieldPath: ref.fieldPath,
461
+ });
462
+ }
463
+ }
464
+ }
465
+ }
466
+ return {
467
+ totalKubernetesRefs: allKubernetesRefs.length,
468
+ resourcesWithKubernetesRefs,
469
+ crossResourceReferences,
470
+ };
471
+ }
472
+ /**
473
+ * Get cached KubernetesRef objects for a resource
474
+ */
475
+ getCachedResourceKubernetesRefs(resourceId) {
476
+ return this.resourceKubernetesRefCache.get(resourceId) || [];
477
+ }
478
+ /**
479
+ * Clear caches for a specific context
480
+ */
481
+ clearContextCache(contextId) {
482
+ this.contextAnalysisCache.delete(contextId);
483
+ }
484
+ /**
485
+ * Extract KubernetesRef objects from a resource
486
+ */
487
+ extractKubernetesRefsFromResource(resource) {
488
+ const refs = [];
489
+ const traverse = (obj, path = '') => {
490
+ if (isKubernetesRef(obj)) {
491
+ refs.push(obj);
492
+ return;
493
+ }
494
+ if (Array.isArray(obj)) {
495
+ obj.forEach((item, index) => traverse(item, `${path}[${index}]`));
496
+ }
497
+ else if (obj && typeof obj === 'object') {
498
+ Object.entries(obj).forEach(([key, value]) => {
499
+ const newPath = path ? `${path}.${key}` : key;
500
+ traverse(value, newPath);
501
+ });
502
+ }
503
+ };
504
+ traverse(resource);
505
+ return refs;
506
+ }
507
+ }
508
+ /**
509
+ * Magic proxy scoping manager for composition contexts with nested composition support
510
+ */
511
+ export class MagicProxyScopeManager {
512
+ scopeStack = [];
513
+ scopeRegistry = new Map();
514
+ /**
515
+ * Enter a new composition scope
516
+ */
517
+ enterScope(contextId, schemaProxy) {
518
+ const parentScope = this.getCurrentScope();
519
+ const depth = parentScope ? parentScope.depth + 1 : 0;
520
+ const newScope = {
521
+ contextId,
522
+ resourceIds: new Set(),
523
+ schemaProxy,
524
+ parentScope,
525
+ childScopes: [],
526
+ depth,
527
+ };
528
+ // Link to parent scope
529
+ if (parentScope) {
530
+ parentScope.childScopes.push(newScope);
531
+ }
532
+ this.scopeStack.push(newScope);
533
+ this.scopeRegistry.set(contextId, newScope);
534
+ }
535
+ /**
536
+ * Exit the current composition scope
537
+ */
538
+ exitScope() {
539
+ const exitingScope = this.scopeStack.pop();
540
+ if (exitingScope) {
541
+ this.scopeRegistry.delete(exitingScope.contextId);
542
+ }
543
+ }
544
+ /**
545
+ * Register a resource in the current scope
546
+ */
547
+ registerResource(resourceId) {
548
+ const currentScope = this.getCurrentScope();
549
+ if (currentScope) {
550
+ currentScope.resourceIds.add(resourceId);
551
+ }
552
+ }
553
+ /**
554
+ * Register merged resources from a nested composition
555
+ */
556
+ registerMergedResources(contextId, mergedResourceIds) {
557
+ const scope = this.scopeRegistry.get(contextId);
558
+ if (scope) {
559
+ scope.mergedResourceIds = mergedResourceIds;
560
+ // Also register these resources in the current scope for accessibility
561
+ const currentScope = this.getCurrentScope();
562
+ if (currentScope && currentScope !== scope) {
563
+ mergedResourceIds.forEach(id => currentScope.resourceIds.add(id));
564
+ }
565
+ }
566
+ }
567
+ /**
568
+ * Get the current scope
569
+ */
570
+ getCurrentScope() {
571
+ return this.scopeStack[this.scopeStack.length - 1];
572
+ }
573
+ /**
574
+ * Get a scope by context ID
575
+ */
576
+ getScope(contextId) {
577
+ return this.scopeRegistry.get(contextId);
578
+ }
579
+ /**
580
+ * Check if a resource is accessible in the current scope (including parent scopes)
581
+ */
582
+ isResourceAccessible(resourceId) {
583
+ const currentScope = this.getCurrentScope();
584
+ if (!currentScope) {
585
+ return false;
586
+ }
587
+ // Check current scope and all parent scopes
588
+ let scope = currentScope;
589
+ while (scope) {
590
+ if (scope.resourceIds.has(resourceId)) {
591
+ return true;
592
+ }
593
+ // Check merged resources from nested compositions
594
+ if (scope.mergedResourceIds?.includes(resourceId)) {
595
+ return true;
596
+ }
597
+ scope = scope.parentScope;
598
+ }
599
+ return false;
600
+ }
601
+ /**
602
+ * Check if a resource is in the current scope only
603
+ */
604
+ isResourceInCurrentScope(resourceId) {
605
+ const currentScope = this.getCurrentScope();
606
+ return currentScope ? currentScope.resourceIds.has(resourceId) : false;
607
+ }
608
+ /**
609
+ * Get all accessible resources (current scope + parent scopes)
610
+ */
611
+ getAccessibleResources() {
612
+ const currentScope = this.getCurrentScope();
613
+ if (!currentScope) {
614
+ return [];
615
+ }
616
+ const accessibleResources = new Set();
617
+ // Collect resources from current scope and all parent scopes
618
+ let scope = currentScope;
619
+ while (scope) {
620
+ scope.resourceIds.forEach(id => accessibleResources.add(id));
621
+ // Add merged resources from nested compositions
622
+ if (scope.mergedResourceIds) {
623
+ scope.mergedResourceIds.forEach(id => accessibleResources.add(id));
624
+ }
625
+ scope = scope.parentScope;
626
+ }
627
+ return Array.from(accessibleResources);
628
+ }
629
+ /**
630
+ * Get resources in the current scope only
631
+ */
632
+ getCurrentScopeResources() {
633
+ const currentScope = this.getCurrentScope();
634
+ return currentScope ? Array.from(currentScope.resourceIds) : [];
635
+ }
636
+ /**
637
+ * Get the scope hierarchy as a string for debugging
638
+ */
639
+ getScopeHierarchy() {
640
+ const currentScope = this.getCurrentScope();
641
+ if (!currentScope) {
642
+ return 'No active scope';
643
+ }
644
+ const hierarchy = [];
645
+ let scope = currentScope;
646
+ while (scope) {
647
+ hierarchy.unshift(`${scope.contextId} (depth: ${scope.depth}, resources: ${scope.resourceIds.size})`);
648
+ scope = scope.parentScope;
649
+ }
650
+ return hierarchy.join(' -> ');
651
+ }
652
+ /**
653
+ * Validate KubernetesRef scope with nested composition support
654
+ */
655
+ validateKubernetesRefScope(kubernetesRef) {
656
+ const currentScope = this.getCurrentScope();
657
+ if (!currentScope) {
658
+ return { isValid: false, error: 'No active composition scope' };
659
+ }
660
+ // Schema references are always valid
661
+ if (kubernetesRef.resourceId === '__schema__') {
662
+ return { isValid: true };
663
+ }
664
+ // Check accessibility in nested scope hierarchy
665
+ let scope = currentScope;
666
+ while (scope) {
667
+ if (scope.resourceIds.has(kubernetesRef.resourceId)) {
668
+ return {
669
+ isValid: true,
670
+ scopeInfo: {
671
+ foundInScope: scope.contextId,
672
+ scopeDepth: scope.depth,
673
+ },
674
+ };
675
+ }
676
+ // Check merged resources from nested compositions
677
+ if (scope.mergedResourceIds?.includes(kubernetesRef.resourceId)) {
678
+ return {
679
+ isValid: true,
680
+ scopeInfo: {
681
+ foundInScope: scope.contextId,
682
+ scopeDepth: scope.depth,
683
+ },
684
+ };
685
+ }
686
+ scope = scope.parentScope;
687
+ }
688
+ return {
689
+ isValid: false,
690
+ error: `Resource '${kubernetesRef.resourceId}' is not accessible in the current composition scope hierarchy`,
691
+ };
692
+ }
693
+ /**
694
+ * Get nested composition statistics
695
+ */
696
+ getNestedCompositionStats() {
697
+ const currentScope = this.getCurrentScope();
698
+ const stats = {
699
+ totalScopes: this.scopeRegistry.size,
700
+ maxDepth: 0,
701
+ currentDepth: currentScope?.depth || 0,
702
+ totalResources: 0,
703
+ resourcesByScope: {},
704
+ };
705
+ for (const [contextId, scope] of this.scopeRegistry) {
706
+ stats.maxDepth = Math.max(stats.maxDepth, scope.depth);
707
+ stats.totalResources += scope.resourceIds.size;
708
+ stats.resourcesByScope[contextId] = scope.resourceIds.size;
709
+ if (scope.mergedResourceIds) {
710
+ stats.totalResources += scope.mergedResourceIds.length;
711
+ }
712
+ }
713
+ return stats;
714
+ }
715
+ }
716
+ /**
717
+ * Integration hooks for kubernetesComposition API
718
+ */
719
+ export class CompositionIntegrationHooks {
720
+ analyzer;
721
+ contextTracker;
722
+ scopeManager;
723
+ constructor() {
724
+ this.analyzer = new CompositionExpressionAnalyzer();
725
+ this.contextTracker = new CompositionContextTracker();
726
+ this.scopeManager = new MagicProxyScopeManager();
727
+ }
728
+ /**
729
+ * Hook called before composition execution to set up expression analysis
730
+ */
731
+ beforeCompositionExecution(compositionFn, schemaProxy, contextId) {
732
+ // Enter the composition scope
733
+ this.scopeManager.enterScope(contextId, schemaProxy);
734
+ // Pre-analyze the composition for optimization opportunities
735
+ try {
736
+ const analysisResult = this.analyzer.analyzeCompositionFunction(compositionFn, schemaProxy);
737
+ // Store analysis result for later use during serialization
738
+ if (analysisResult.requiresCelConversion) {
739
+ console.debug(`Composition ${contextId} requires CEL conversion: ${analysisResult.conversionMetadata.kubernetesRefsDetected} KubernetesRef objects detected`);
740
+ }
741
+ }
742
+ catch (error) {
743
+ // Non-fatal error - composition can continue without pre-analysis
744
+ console.warn(`Composition pre-analysis failed: ${error instanceof Error ? error.message : String(error)}`);
745
+ }
746
+ }
747
+ /**
748
+ * Hook called after composition execution to process results
749
+ */
750
+ afterCompositionExecution(statusShape, factoryType = 'kro', context) {
751
+ try {
752
+ // Track the composition context if provided
753
+ if (context) {
754
+ const trackingResult = this.contextTracker.trackCompositionContext(context);
755
+ if (trackingResult.crossResourceReferences.length > 0) {
756
+ console.debug(`Composition has ${trackingResult.crossResourceReferences.length} cross-resource references that may require CEL conversion`);
757
+ }
758
+ }
759
+ // Process the status shape
760
+ const processedStatus = this.analyzer.processCompositionStatus(statusShape, factoryType);
761
+ return processedStatus;
762
+ }
763
+ finally {
764
+ // Exit the composition scope
765
+ this.scopeManager.exitScope();
766
+ }
767
+ }
768
+ /**
769
+ * Hook called during resource creation to analyze KubernetesRef usage
770
+ */
771
+ onResourceCreation(resourceId, resource, _context) {
772
+ // Register the resource in the current scope
773
+ this.scopeManager.registerResource(resourceId);
774
+ // Analyze KubernetesRef usage
775
+ const refs = this.contextTracker.getCachedResourceKubernetesRefs(resourceId) ||
776
+ this.contextTracker.extractKubernetesRefsFromResource(resource);
777
+ if (refs.length > 0) {
778
+ console.debug(`Resource ${resourceId} contains ${refs.length} KubernetesRef objects that may require CEL conversion`);
779
+ // Validate scope for each KubernetesRef
780
+ for (const ref of refs) {
781
+ const validation = this.scopeManager.validateKubernetesRefScope(ref);
782
+ if (!validation.isValid) {
783
+ console.warn(`KubernetesRef validation failed for resource ${resourceId}: ${validation.error}`);
784
+ }
785
+ }
786
+ }
787
+ }
788
+ /**
789
+ * Get the current magic proxy scope manager
790
+ */
791
+ getScopeManager() {
792
+ return this.scopeManager;
793
+ }
794
+ /**
795
+ * Get the context tracker
796
+ */
797
+ getContextTracker() {
798
+ return this.contextTracker;
799
+ }
800
+ /**
801
+ * Handle auto-registration of resources with KubernetesRef tracking
802
+ */
803
+ handleAutoRegistration(resourceId, resource, context) {
804
+ // Register the resource in the current scope
805
+ this.scopeManager.registerResource(resourceId);
806
+ // Track KubernetesRef objects in the auto-registered resource
807
+ const refs = this.contextTracker.extractKubernetesRefsFromResource(resource);
808
+ if (refs.length > 0) {
809
+ // Validate that all referenced resources are accessible
810
+ for (const ref of refs) {
811
+ const validation = this.scopeManager.validateKubernetesRefScope(ref);
812
+ if (!validation.isValid) {
813
+ console.warn(`Auto-registered resource '${resourceId}' contains invalid KubernetesRef: ${validation.error}`);
814
+ }
815
+ }
816
+ // Cache the KubernetesRef objects for later use
817
+ this.contextTracker.resourceKubernetesRefCache.set(resourceId, refs);
818
+ }
819
+ // Update the composition context
820
+ context.addResource(resourceId, resource);
821
+ }
822
+ /**
823
+ * Handle side-effect based resource creation with magic proxy integration
824
+ */
825
+ handleSideEffectCreation(resourceFactory, resourceId, context) {
826
+ const activeContext = context || getCurrentCompositionContext();
827
+ if (!activeContext) {
828
+ // No active composition context - create resource normally
829
+ return resourceFactory();
830
+ }
831
+ // Track resources before creation
832
+ const resourcesBefore = new Set(Object.keys(activeContext.resources));
833
+ // Create the resource
834
+ const resource = resourceFactory();
835
+ // Determine the actual resource ID
836
+ const actualResourceId = resourceId || this.generateResourceIdFromResource(resource);
837
+ // Check if new resources were created as side effects
838
+ const resourcesAfter = Object.keys(activeContext.resources);
839
+ const newResources = resourcesAfter.filter(id => !resourcesBefore.has(id));
840
+ // Handle each new resource
841
+ for (const newResourceId of newResources) {
842
+ const newResource = activeContext.resources[newResourceId];
843
+ if (newResource) {
844
+ this.handleAutoRegistration(newResourceId, newResource, activeContext);
845
+ }
846
+ }
847
+ // Handle the main resource if it wasn't already registered
848
+ if (!activeContext.resources[actualResourceId]) {
849
+ this.handleAutoRegistration(actualResourceId, resource, activeContext);
850
+ }
851
+ return resource;
852
+ }
853
+ /**
854
+ * Track magic proxy usage during composition execution
855
+ */
856
+ trackMagicProxyUsage(proxyAccess) {
857
+ const currentScope = this.scopeManager.getCurrentScope();
858
+ if (!currentScope) {
859
+ return;
860
+ }
861
+ // Validate that the accessed resource is in scope
862
+ if (proxyAccess.resourceId !== '__schema__' &&
863
+ !this.scopeManager.isResourceAccessible(proxyAccess.resourceId)) {
864
+ console.warn(`Magic proxy access to out-of-scope resource: ${proxyAccess.resourceId}.${proxyAccess.fieldPath}`);
865
+ }
866
+ // Track KubernetesRef creation from magic proxy access
867
+ if (proxyAccess.accessType === 'read' && isKubernetesRef(proxyAccess.value)) {
868
+ const validation = this.scopeManager.validateKubernetesRefScope(proxyAccess.value);
869
+ if (!validation.isValid) {
870
+ console.warn(`Magic proxy created invalid KubernetesRef: ${validation.error}`);
871
+ }
872
+ }
873
+ }
874
+ /**
875
+ * Ensure compatibility with existing factory functions
876
+ */
877
+ ensureFactoryCompatibility(factoryFn, factoryName) {
878
+ const currentScope = this.scopeManager.getCurrentScope();
879
+ if (!currentScope) {
880
+ // No active composition - use factory normally
881
+ return factoryFn();
882
+ }
883
+ try {
884
+ // Execute factory with side-effect tracking
885
+ return this.handleSideEffectCreation(factoryFn, undefined, getCurrentCompositionContext());
886
+ }
887
+ catch (error) {
888
+ console.error(`Factory function '${factoryName}' failed in composition context: ${error instanceof Error ? error.message : String(error)}`);
889
+ throw error;
890
+ }
891
+ }
892
+ /**
893
+ * Generate a resource ID from a resource object
894
+ */
895
+ generateResourceIdFromResource(resource) {
896
+ // Try to extract ID from common resource properties
897
+ const resourceObj = resource;
898
+ if (resourceObj.__resourceId) {
899
+ return resourceObj.__resourceId;
900
+ }
901
+ if (resourceObj.metadata?.name) {
902
+ const kind = resourceObj.kind || 'resource';
903
+ return `${kind.toLowerCase()}-${resourceObj.metadata.name}`;
904
+ }
905
+ if (resourceObj.kind) {
906
+ return `${resourceObj.kind.toLowerCase()}-${Date.now()}`;
907
+ }
908
+ return `resource-${Date.now()}`;
909
+ }
910
+ }
911
+ /**
912
+ * Global composition integration instance
913
+ */
914
+ export const compositionIntegration = new CompositionIntegrationHooks();
915
+ /**
916
+ * Utility function to check if a composition function uses KubernetesRef objects
917
+ */
918
+ export function compositionUsesKubernetesRefs(compositionFn, schemaProxy) {
919
+ const analyzer = new CompositionExpressionAnalyzer();
920
+ try {
921
+ const result = analyzer.analyzeCompositionFunction(compositionFn, schemaProxy);
922
+ return result.requiresCelConversion;
923
+ }
924
+ catch {
925
+ // If analysis fails, assume it might use KubernetesRef objects to be safe
926
+ return true;
927
+ }
928
+ }
929
+ /**
930
+ * Utility function to get composition analysis metadata
931
+ */
932
+ export function getCompositionAnalysis(compositionFn, schemaProxy) {
933
+ const analyzer = new CompositionExpressionAnalyzer();
934
+ return analyzer.analyzeCompositionFunction(compositionFn, schemaProxy);
935
+ }
936
+ //# sourceMappingURL=composition-integration.js.map