@memberjunction/react-runtime 2.89.0 → 2.91.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 (84) hide show
  1. package/.turbo/turbo-build.log +29 -1
  2. package/CHANGELOG.md +30 -0
  3. package/dist/compiler/babel-config.js +1 -0
  4. package/dist/compiler/babel-config.js.map +1 -0
  5. package/dist/compiler/component-compiler.d.ts +3 -0
  6. package/dist/compiler/component-compiler.d.ts.map +1 -1
  7. package/dist/compiler/component-compiler.js +159 -8
  8. package/dist/compiler/component-compiler.js.map +1 -0
  9. package/dist/compiler/index.js +1 -0
  10. package/dist/compiler/index.js.map +1 -0
  11. package/dist/index.d.ts +1 -1
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +4 -4
  14. package/dist/index.js.map +1 -0
  15. package/dist/registry/component-registry.d.ts +1 -0
  16. package/dist/registry/component-registry.d.ts.map +1 -1
  17. package/dist/registry/component-registry.js +10 -0
  18. package/dist/registry/component-registry.js.map +1 -0
  19. package/dist/registry/component-resolver.js +1 -0
  20. package/dist/registry/component-resolver.js.map +1 -0
  21. package/dist/registry/index.js +1 -0
  22. package/dist/registry/index.js.map +1 -0
  23. package/dist/runtime/component-hierarchy.d.ts +7 -4
  24. package/dist/runtime/component-hierarchy.d.ts.map +1 -1
  25. package/dist/runtime/component-hierarchy.js +20 -6
  26. package/dist/runtime/component-hierarchy.js.map +1 -0
  27. package/dist/runtime/error-boundary.js +1 -0
  28. package/dist/runtime/error-boundary.js.map +1 -0
  29. package/dist/runtime/index.js +1 -0
  30. package/dist/runtime/index.js.map +1 -0
  31. package/dist/runtime/prop-builder.d.ts +2 -1
  32. package/dist/runtime/prop-builder.d.ts.map +1 -1
  33. package/dist/runtime/prop-builder.js +1 -0
  34. package/dist/runtime/prop-builder.js.map +1 -0
  35. package/dist/runtime/react-root-manager.js +1 -0
  36. package/dist/runtime/react-root-manager.js.map +1 -0
  37. package/dist/runtime.umd.js +2 -0
  38. package/dist/runtime.umd.js.LICENSE.txt +10 -0
  39. package/dist/types/index.d.ts +4 -5
  40. package/dist/types/index.d.ts.map +1 -1
  41. package/dist/types/index.js +1 -0
  42. package/dist/types/index.js.map +1 -0
  43. package/dist/types/library-config.js +1 -0
  44. package/dist/types/library-config.js.map +1 -0
  45. package/dist/utilities/cache-manager.js +1 -0
  46. package/dist/utilities/cache-manager.js.map +1 -0
  47. package/dist/utilities/component-error-analyzer.js +1 -0
  48. package/dist/utilities/component-error-analyzer.js.map +1 -0
  49. package/dist/utilities/component-styles.js +1 -0
  50. package/dist/utilities/component-styles.js.map +1 -0
  51. package/dist/utilities/core-libraries.js +1 -0
  52. package/dist/utilities/core-libraries.js.map +1 -0
  53. package/dist/utilities/index.d.ts +1 -1
  54. package/dist/utilities/index.d.ts.map +1 -1
  55. package/dist/utilities/index.js +2 -1
  56. package/dist/utilities/index.js.map +1 -0
  57. package/dist/utilities/library-loader.d.ts.map +1 -1
  58. package/dist/utilities/library-loader.js +15 -0
  59. package/dist/utilities/library-loader.js.map +1 -0
  60. package/dist/utilities/library-registry.d.ts +24 -0
  61. package/dist/utilities/library-registry.d.ts.map +1 -0
  62. package/dist/utilities/library-registry.js +74 -0
  63. package/dist/utilities/library-registry.js.map +1 -0
  64. package/dist/utilities/resource-manager.js +1 -0
  65. package/dist/utilities/resource-manager.js.map +1 -0
  66. package/dist/utilities/standard-libraries.js +1 -0
  67. package/dist/utilities/standard-libraries.js.map +1 -0
  68. package/package.json +16 -6
  69. package/src/compiler/component-compiler.ts +238 -9
  70. package/src/index.ts +5 -4
  71. package/src/registry/component-registry.ts +18 -0
  72. package/src/runtime/component-hierarchy.ts +29 -8
  73. package/src/runtime/prop-builder.ts +3 -2
  74. package/src/types/index.ts +12 -11
  75. package/src/utilities/index.ts +1 -1
  76. package/src/utilities/library-loader.ts +18 -0
  77. package/src/utilities/library-registry.ts +149 -0
  78. package/tsconfig.json +1 -0
  79. package/tsconfig.tsbuildinfo +1 -1
  80. package/webpack.umd.config.js +76 -0
  81. package/dist/utilities/runtime-utilities.d.ts +0 -10
  82. package/dist/utilities/runtime-utilities.d.ts.map +0 -1
  83. package/dist/utilities/runtime-utilities.js +0 -92
  84. package/src/utilities/runtime-utilities.ts +0 -122
@@ -4,6 +4,7 @@
4
4
  * @module @memberjunction/react-runtime/compiler
5
5
  */
6
6
 
7
+ import { UserInfo } from '@memberjunction/core';
7
8
  import {
8
9
  CompileOptions,
9
10
  CompiledComponent,
@@ -12,6 +13,8 @@ import {
12
13
  ComponentError,
13
14
  RuntimeContext
14
15
  } from '../types';
16
+ import { LibraryRegistry } from '../utilities/library-registry';
17
+ import { ComponentLibraryEntity } from '@memberjunction/core-entities';
15
18
 
16
19
  /**
17
20
  * Default compiler configuration
@@ -78,6 +81,9 @@ export class ComponentCompiler {
78
81
  // Validate inputs
79
82
  this.validateCompileOptions(options);
80
83
 
84
+ // Load required libraries if specified
85
+ const loadedLibraries = await this.loadRequiredLibraries(options.libraries!, options.allLibraries);
86
+
81
87
  // Transpile the component code
82
88
  const transpiledCode = this.transpileComponent(
83
89
  options.componentCode,
@@ -85,10 +91,11 @@ export class ComponentCompiler {
85
91
  options
86
92
  );
87
93
 
88
- // Create the component factory
94
+ // Create the component factory with loaded libraries
89
95
  const componentFactory = this.createComponentFactory(
90
96
  transpiledCode,
91
- options.componentName
97
+ options.componentName,
98
+ loadedLibraries
92
99
  );
93
100
 
94
101
  // Build the compiled component
@@ -137,7 +144,7 @@ export class ComponentCompiler {
137
144
  throw new Error('Babel instance not set. Call setBabelInstance() first.');
138
145
  }
139
146
 
140
- const wrappedCode = this.wrapComponentCode(code, componentName);
147
+ const wrappedCode = this.wrapComponentCode(code, componentName, options.libraries);
141
148
 
142
149
  try {
143
150
  const result = this.babelInstance.transform(wrappedCode, {
@@ -158,16 +165,25 @@ export class ComponentCompiler {
158
165
  * Wraps component code in a factory function for execution
159
166
  * @param componentCode - Raw component code
160
167
  * @param componentName - Name of the component
168
+ * @param libraries - Optional library dependencies
161
169
  * @returns Wrapped component code
162
170
  */
163
- private wrapComponentCode(componentCode: string, componentName: string): string {
171
+ private wrapComponentCode(componentCode: string, componentName: string, libraries?: any[]): string {
172
+ // Generate library declarations if libraries are provided
173
+ const libraryDeclarations = libraries && libraries.length > 0
174
+ ? libraries
175
+ .filter(lib => lib.globalVariable) // Only include libraries with globalVariable
176
+ .map(lib => `const ${lib.globalVariable} = libraries['${lib.globalVariable}'];`)
177
+ .join('\n ')
178
+ : '';
179
+
164
180
  return `
165
181
  function createComponent(
166
182
  React, ReactDOM,
167
183
  useState, useEffect, useCallback, useMemo, useRef, useContext, useReducer, useLayoutEffect,
168
184
  libraries, styles, console
169
185
  ) {
170
- ${componentCode}
186
+ ${libraryDeclarations ? libraryDeclarations + '\n ' : ''}${componentCode}
171
187
 
172
188
  // Ensure the component exists
173
189
  if (typeof ${componentName} === 'undefined') {
@@ -190,13 +206,219 @@ export class ComponentCompiler {
190
206
  `;
191
207
  }
192
208
 
209
+ /**
210
+ * Load required libraries from the registry
211
+ * @param libraries - Array of library dependencies
212
+ * @param contextUser - Context user for accessing library registry
213
+ * @returns Map of loaded libraries
214
+ */
215
+ private async loadRequiredLibraries(libraries: any[], componentLibraries: ComponentLibraryEntity[]): Promise<Map<string, any>> {
216
+ const loadedLibraries = new Map<string, any>();
217
+
218
+ console.log('🔍 loadRequiredLibraries called with:', {
219
+ librariesCount: libraries?.length || 0,
220
+ libraries: libraries?.map(l => ({ name: l.name, version: l.version, globalVariable: l.globalVariable }))
221
+ });
222
+
223
+ if (!libraries || libraries.length === 0) {
224
+ console.log('📚 No libraries to load, returning empty map');
225
+ return loadedLibraries;
226
+ }
227
+
228
+ // Only works in browser environment
229
+ if (typeof window === 'undefined') {
230
+ console.warn('Library loading is only supported in browser environments');
231
+ return loadedLibraries;
232
+ }
233
+
234
+ // Initialize LibraryRegistry with componentLibraries if provided
235
+ if (componentLibraries) {
236
+ await LibraryRegistry.Config(false, componentLibraries);
237
+ } else {
238
+ console.warn('⚠️ No componentLibraries provided for LibraryRegistry initialization');
239
+ }
240
+
241
+ const loadPromises = libraries.map(async (lib) => {
242
+ console.log(`📦 Processing library: ${lib.name}`);
243
+
244
+ // Check if library is approved
245
+ const isApproved = LibraryRegistry.isApproved(lib.name);
246
+ console.log(` ✓ Approved check for ${lib.name}: ${isApproved}`);
247
+
248
+ if (!isApproved) {
249
+ console.error(` ❌ Library '${lib.name}' is not approved`);
250
+ throw new Error(`Library '${lib.name}' is not approved. Only approved libraries can be used.`);
251
+ }
252
+
253
+ // Get library definition for complete info
254
+ const libraryDef = LibraryRegistry.getLibrary(lib.name);
255
+ console.log(` ✓ Library definition found for ${lib.name}: ${!!libraryDef}`);
256
+
257
+ if (!libraryDef) {
258
+ console.error(` ❌ Library '${lib.name}' not found in registry`);
259
+ throw new Error(`Library '${lib.name}' not found in registry`);
260
+ }
261
+
262
+ // Get CDN URL for the library
263
+ const resolvedVersion = LibraryRegistry.resolveVersion(lib.name, lib.version);
264
+ console.log(` ✓ Resolved version for ${lib.name}: ${resolvedVersion}`);
265
+
266
+ const cdnUrl = LibraryRegistry.getCdnUrl(lib.name, resolvedVersion);
267
+ console.log(` ✓ CDN URL for ${lib.name}: ${cdnUrl}`);
268
+
269
+ if (!cdnUrl) {
270
+ console.error(` ❌ No CDN URL found for library '${lib.name}' version '${lib.version || 'default'}'`);
271
+ throw new Error(`No CDN URL found for library '${lib.name}' version '${lib.version || 'default'}'`);
272
+ }
273
+
274
+ // Check if already loaded
275
+ if ((window as any)[lib.globalVariable]) {
276
+ console.log(` ℹ️ Library ${lib.name} already loaded globally as ${lib.globalVariable}`);
277
+ loadedLibraries.set(lib.globalVariable, (window as any)[lib.globalVariable]);
278
+ return;
279
+ }
280
+
281
+ // Load CSS files if the library requires them
282
+ const versionInfo = libraryDef.versions[resolvedVersion || libraryDef.defaultVersion];
283
+ if (versionInfo?.cssUrls) {
284
+ await this.loadStyles(versionInfo.cssUrls);
285
+ }
286
+
287
+ // Load the library dynamically (cdnUrl is guaranteed to be non-null here due to check above)
288
+ console.log(` 📥 Loading script from CDN for ${lib.name}...`);
289
+ await this.loadScript(cdnUrl!, lib.globalVariable);
290
+
291
+ // Capture the library value from global scope
292
+ // Note: Libraries loaded from CDN typically attach to window automatically
293
+ // We capture them here to pass through the component's closure
294
+ const libraryValue = (window as any)[lib.globalVariable];
295
+ console.log(` ✓ Library ${lib.name} loaded successfully, global variable ${lib.globalVariable} is:`, typeof libraryValue);
296
+
297
+ if (libraryValue) {
298
+ loadedLibraries.set(lib.globalVariable, libraryValue);
299
+ console.log(` ✅ Added ${lib.name} to loaded libraries map`);
300
+ } else {
301
+ console.error(` ❌ Library '${lib.name}' failed to expose global variable '${lib.globalVariable}'`);
302
+ throw new Error(`Library '${lib.name}' failed to load or did not expose '${lib.globalVariable}'`);
303
+ }
304
+ });
305
+
306
+ await Promise.all(loadPromises);
307
+
308
+ console.log(`✅ All libraries loaded successfully. Total: ${loadedLibraries.size}`);
309
+ console.log('📚 Loaded libraries map:', Array.from(loadedLibraries.keys()));
310
+
311
+ return loadedLibraries;
312
+ }
313
+
314
+ /**
315
+ * Load CSS stylesheets dynamically
316
+ * @param urls - Array of CSS URLs to load
317
+ * @returns Promise that resolves when all stylesheets are loaded
318
+ */
319
+ private async loadStyles(urls: string[]): Promise<void> {
320
+ const loadPromises = urls.map(url => {
321
+ return new Promise<void>((resolve) => {
322
+ // Check if stylesheet already exists
323
+ const existingLink = document.querySelector(`link[href="${url}"]`);
324
+ if (existingLink) {
325
+ resolve();
326
+ return;
327
+ }
328
+
329
+ // Create new link element
330
+ const link = document.createElement('link');
331
+ link.rel = 'stylesheet';
332
+ link.href = url;
333
+
334
+ // CSS load events are not reliable cross-browser, so resolve immediately
335
+ // The CSS will load asynchronously but won't block component rendering
336
+ document.head.appendChild(link);
337
+ resolve();
338
+ });
339
+ });
340
+
341
+ await Promise.all(loadPromises);
342
+ }
343
+
344
+ /**
345
+ * Load a script dynamically
346
+ * @param url - Script URL
347
+ * @param globalName - Expected global variable name
348
+ * @returns Promise that resolves when script is loaded
349
+ */
350
+ private loadScript(url: string, globalName: string): Promise<void> {
351
+ return new Promise((resolve, reject) => {
352
+ // Check if script already exists
353
+ const existingScript = document.querySelector(`script[src="${url}"]`);
354
+ if (existingScript) {
355
+ // Wait for it to finish loading with exponential backoff
356
+ let attempts = 0;
357
+ const maxAttempts = 50; // 5 seconds total with 100ms intervals
358
+ const checkLoaded = () => {
359
+ if ((window as any)[globalName]) {
360
+ resolve();
361
+ } else if (attempts >= maxAttempts) {
362
+ reject(new Error(`${globalName} not found after ${maxAttempts * 100}ms waiting for existing script`));
363
+ } else {
364
+ attempts++;
365
+ setTimeout(checkLoaded, 100);
366
+ }
367
+ };
368
+ checkLoaded();
369
+ return;
370
+ }
371
+
372
+ // Create new script element
373
+ const script = document.createElement('script');
374
+ script.src = url;
375
+ script.async = true;
376
+
377
+ script.onload = () => {
378
+ // More robust checking with multiple attempts
379
+ let attempts = 0;
380
+ const maxAttempts = 20; // 2 seconds total
381
+ const checkInterval = 100; // Check every 100ms
382
+
383
+ const checkGlobal = () => {
384
+ if ((window as any)[globalName]) {
385
+ console.log(` ✓ Global variable ${globalName} found after ${attempts * checkInterval}ms`);
386
+ resolve();
387
+ } else if (attempts >= maxAttempts) {
388
+ // Final check - some libraries might use a different global name pattern
389
+ console.error(` ❌ ${globalName} not found after ${attempts * checkInterval}ms`);
390
+ console.log(` ℹ️ Window properties:`, Object.keys(window).filter(k => k.toLowerCase().includes(globalName.toLowerCase())));
391
+ reject(new Error(`${globalName} not found after loading script from ${url}`));
392
+ } else {
393
+ attempts++;
394
+ setTimeout(checkGlobal, checkInterval);
395
+ }
396
+ };
397
+
398
+ // Start checking immediately (don't wait 100ms first)
399
+ checkGlobal();
400
+ };
401
+
402
+ script.onerror = () => {
403
+ reject(new Error(`Failed to load script: ${url}`));
404
+ };
405
+
406
+ document.head.appendChild(script);
407
+ });
408
+ }
409
+
193
410
  /**
194
411
  * Creates a component factory function from transpiled code
195
412
  * @param transpiledCode - Transpiled JavaScript code
196
413
  * @param componentName - Name of the component
414
+ * @param loadedLibraries - Map of loaded libraries
197
415
  * @returns Component factory function
198
416
  */
199
- private createComponentFactory(transpiledCode: string, componentName: string): Function {
417
+ private createComponentFactory(
418
+ transpiledCode: string,
419
+ componentName: string,
420
+ loadedLibraries: Map<string, any>
421
+ ): Function {
200
422
  try {
201
423
  // Create the factory function with all React hooks
202
424
  const factoryCreator = new Function(
@@ -209,6 +431,12 @@ export class ComponentCompiler {
209
431
  // Return a function that executes the factory with runtime context
210
432
  return (context: RuntimeContext, styles: any = {}) => {
211
433
  const { React, ReactDOM, libraries = {} } = context;
434
+
435
+ // Merge loaded libraries with context libraries
436
+ const mergedLibraries = { ...libraries };
437
+ loadedLibraries.forEach((value, key) => {
438
+ mergedLibraries[key] = value;
439
+ });
212
440
 
213
441
  // Execute the factory creator to get the createComponent function
214
442
  const createComponentFn = factoryCreator(
@@ -222,7 +450,7 @@ export class ComponentCompiler {
222
450
  React.useContext,
223
451
  React.useReducer,
224
452
  React.useLayoutEffect,
225
- libraries,
453
+ mergedLibraries,
226
454
  styles,
227
455
  console
228
456
  );
@@ -239,7 +467,7 @@ export class ComponentCompiler {
239
467
  React.useContext,
240
468
  React.useReducer,
241
469
  React.useLayoutEffect,
242
- libraries,
470
+ mergedLibraries,
243
471
  styles,
244
472
  console
245
473
  );
@@ -366,7 +594,8 @@ export class ComponentCompiler {
366
594
  if (this.compilationCache.size >= this.config.maxCacheSize) {
367
595
  // Remove oldest entry (first in map)
368
596
  const firstKey = this.compilationCache.keys().next().value;
369
- this.compilationCache.delete(firstKey);
597
+ if (firstKey)
598
+ this.compilationCache.delete(firstKey);
370
599
  }
371
600
 
372
601
  const cacheKey = this.createCacheKey(component.name, code);
package/src/index.ts CHANGED
@@ -71,10 +71,6 @@ export {
71
71
  } from './runtime';
72
72
 
73
73
  // Export utilities
74
- export {
75
- RuntimeUtilities,
76
- createRuntimeUtilities
77
- } from './utilities/runtime-utilities';
78
74
 
79
75
  export {
80
76
  SetupStyles,
@@ -93,6 +89,11 @@ export {
93
89
  LibraryLoadResult
94
90
  } from './utilities/library-loader';
95
91
 
92
+ export {
93
+ LibraryRegistry,
94
+ LibraryDefinition
95
+ } from './utilities/library-registry';
96
+
96
97
  export {
97
98
  ComponentErrorAnalyzer,
98
99
  FailedComponentInfo
@@ -167,6 +167,24 @@ export class ComponentRegistry {
167
167
  return components;
168
168
  }
169
169
 
170
+ /**
171
+ * Gets all components in a namespace and version as a map
172
+ * @param namespace - Namespace to query (default: 'Global')
173
+ * @param version - Version to query (default: 'v1')
174
+ * @returns Object mapping component names to components
175
+ */
176
+ getAll(namespace: string = 'Global', version: string = 'v1'): Record<string, any> {
177
+ const components: Record<string, any> = {};
178
+
179
+ for (const entry of this.registry.values()) {
180
+ if (entry.metadata.namespace === namespace && entry.metadata.version === version) {
181
+ components[entry.metadata.name] = entry.component;
182
+ }
183
+ }
184
+
185
+ return components;
186
+ }
187
+
170
188
  /**
171
189
  * Gets all registered namespaces
172
190
  * @returns Array of unique namespace names
@@ -7,13 +7,14 @@
7
7
  import {
8
8
  CompilationResult,
9
9
  CompileOptions,
10
- ComponentStyles,
11
10
  RuntimeContext
12
11
  } from '../types';
13
12
  import { ComponentCompiler } from '../compiler';
14
13
  import { ComponentRegistry } from '../registry';
15
14
 
16
- import { ComponentSpec } from '@memberjunction/interactive-component-types';
15
+ import { ComponentSpec, ComponentStyles } from '@memberjunction/interactive-component-types';
16
+ import { UserInfo } from '@memberjunction/core';
17
+ import { ComponentLibraryEntity } from '@memberjunction/core-entities';
17
18
 
18
19
  /**
19
20
  * Result of a hierarchy registration operation
@@ -48,6 +49,10 @@ export interface HierarchyRegistrationOptions {
48
49
  continueOnError?: boolean;
49
50
  /** Whether to override existing components */
50
51
  allowOverride?: boolean;
52
+ /**
53
+ * Required, metadata for all possible libraries allowed by the system
54
+ */
55
+ allLibraries: ComponentLibraryEntity[];
51
56
  }
52
57
 
53
58
  /**
@@ -68,7 +73,7 @@ export class ComponentHierarchyRegistrar {
68
73
  */
69
74
  async registerHierarchy(
70
75
  rootSpec: ComponentSpec,
71
- options: HierarchyRegistrationOptions = {}
76
+ options: HierarchyRegistrationOptions
72
77
  ): Promise<HierarchyRegistrationResult> {
73
78
  const {
74
79
  styles,
@@ -78,6 +83,13 @@ export class ComponentHierarchyRegistrar {
78
83
  allowOverride = true
79
84
  } = options;
80
85
 
86
+ console.log('🌳 ComponentHierarchyRegistrar.registerHierarchy:', {
87
+ rootComponent: rootSpec.name,
88
+ hasLibraries: !!(rootSpec.libraries && rootSpec.libraries.length > 0),
89
+ libraryCount: rootSpec.libraries?.length || 0,
90
+ libraries: rootSpec.libraries?.map(l => l.name)
91
+ });
92
+
81
93
  const registeredComponents: string[] = [];
82
94
  const errors: ComponentRegistrationError[] = [];
83
95
  const warnings: string[] = [];
@@ -85,7 +97,7 @@ export class ComponentHierarchyRegistrar {
85
97
  // Register the root component
86
98
  const rootResult = await this.registerSingleComponent(
87
99
  rootSpec,
88
- { styles, namespace, version, allowOverride }
100
+ { styles, namespace, version, allowOverride, allLibraries: options.allLibraries }
89
101
  );
90
102
 
91
103
  if (rootResult.success) {
@@ -102,7 +114,7 @@ export class ComponentHierarchyRegistrar {
102
114
  if (childComponents.length > 0) {
103
115
  const childResult = await this.registerChildComponents(
104
116
  childComponents,
105
- { styles, namespace, version, continueOnError, allowOverride },
117
+ { styles, namespace, version, continueOnError, allowOverride, allLibraries: options.allLibraries },
106
118
  registeredComponents,
107
119
  errors,
108
120
  warnings
@@ -130,6 +142,7 @@ export class ComponentHierarchyRegistrar {
130
142
  namespace?: string;
131
143
  version?: string;
132
144
  allowOverride?: boolean;
145
+ allLibraries: ComponentLibraryEntity[];
133
146
  }
134
147
  ): Promise<{ success: boolean; error?: ComponentRegistrationError }> {
135
148
  const { styles, namespace = 'Global', version = 'v1', allowOverride = true } = options;
@@ -160,9 +173,16 @@ export class ComponentHierarchyRegistrar {
160
173
  const compileOptions: CompileOptions = {
161
174
  componentName: spec.name,
162
175
  componentCode: spec.code,
163
- styles
176
+ styles,
177
+ libraries: spec.libraries, // Pass along library dependencies from the spec
178
+ allLibraries: options.allLibraries
164
179
  };
165
180
 
181
+ console.log(`🔧 Compiling component ${spec.name} with libraries:`, {
182
+ libraryCount: spec.libraries?.length || 0,
183
+ libraries: spec.libraries?.map(l => ({ name: l.name, globalVariable: l.globalVariable }))
184
+ });
185
+
166
186
  const compilationResult = await this.compiler.compile(compileOptions);
167
187
 
168
188
  if (!compilationResult.success) {
@@ -222,7 +242,8 @@ export class ComponentHierarchyRegistrar {
222
242
  styles: options.styles,
223
243
  namespace: options.namespace,
224
244
  version: options.version,
225
- allowOverride: options.allowOverride
245
+ allowOverride: options.allowOverride,
246
+ allLibraries: options.allLibraries
226
247
  });
227
248
 
228
249
  if (childResult.success) {
@@ -265,7 +286,7 @@ export async function registerComponentHierarchy(
265
286
  compiler: ComponentCompiler,
266
287
  registry: ComponentRegistry,
267
288
  runtimeContext: RuntimeContext,
268
- options: HierarchyRegistrationOptions = {}
289
+ options: HierarchyRegistrationOptions
269
290
  ): Promise<HierarchyRegistrationResult> {
270
291
  const registrar = new ComponentHierarchyRegistrar(compiler, registry, runtimeContext);
271
292
  return registrar.registerHierarchy(rootSpec, options);
@@ -4,7 +4,8 @@
4
4
  * @module @memberjunction/react-runtime/runtime
5
5
  */
6
6
 
7
- import { ComponentProps, ComponentCallbacks, ComponentStyles } from '../types';
7
+ import { ComponentStyles } from '@memberjunction/interactive-component-types';
8
+ import { ComponentProps, ComponentCallbacks } from '../types';
8
9
  import { Subject, debounceTime, Subscription } from 'rxjs';
9
10
 
10
11
  /**
@@ -187,7 +188,7 @@ export function mergeProps(...propsList: Partial<ComponentProps>[]): ComponentPr
187
188
  utilities: {},
188
189
  callbacks: {},
189
190
  components: {},
190
- styles: {}
191
+ styles: {} as ComponentStyles
191
192
  };
192
193
 
193
194
  for (const props of propsList) {
@@ -4,6 +4,10 @@
4
4
  * @module @memberjunction/react-runtime/types
5
5
  */
6
6
 
7
+ import { UserInfo } from '@memberjunction/core';
8
+ import { ComponentLibraryEntity } from '@memberjunction/core-entities';
9
+ import { ComponentLibraryDependency, ComponentStyles } from '@memberjunction/interactive-component-types';
10
+
7
11
  /**
8
12
  * Represents a compiled React component with its metadata
9
13
  */
@@ -36,20 +40,17 @@ export interface CompileOptions {
36
40
  babelPlugins?: string[];
37
41
  /** Custom Babel presets to use */
38
42
  babelPresets?: string[];
39
- }
40
43
 
41
- /**
42
- * Component styles that can be applied
43
- */
44
- export interface ComponentStyles {
45
- /** CSS classes to apply */
46
- className?: string;
47
- /** Inline styles */
48
- style?: Record<string, any>;
49
- /** Global CSS to inject */
50
- globalCss?: string;
44
+ /** Library dependencies that the component requires */
45
+ libraries?: ComponentLibraryDependency[];
46
+
47
+ /**
48
+ * Required, metadata for all possible libraries allowed by the system
49
+ */
50
+ allLibraries: ComponentLibraryEntity[];
51
51
  }
52
52
 
53
+
53
54
  /**
54
55
  * Registry entry for a compiled component
55
56
  */
@@ -3,10 +3,10 @@
3
3
  * @module @memberjunction/react-runtime/utilities
4
4
  */
5
5
 
6
- export * from './runtime-utilities';
7
6
  export * from './component-styles';
8
7
  export * from './standard-libraries';
9
8
  export * from './library-loader';
9
+ export * from './library-registry';
10
10
  export * from './component-error-analyzer';
11
11
  export * from './resource-manager';
12
12
  export * from './cache-manager';
@@ -99,6 +99,24 @@ export class LibraryLoader {
99
99
  const ReactDOM = coreResults.find((_, i) => coreLibraries[i].globalVariable === 'ReactDOM');
100
100
  const Babel = coreResults.find((_, i) => coreLibraries[i].globalVariable === 'Babel');
101
101
 
102
+ // Expose React and ReactDOM as globals for UMD libraries that expect them
103
+ // Many React component libraries (Recharts, Victory, etc.) expect these as globals
104
+ if (typeof window !== 'undefined') {
105
+ if (React && !(window as any).React) {
106
+ (window as any).React = React;
107
+ console.log('✓ Exposed React as window.React for UMD compatibility');
108
+ }
109
+ if (ReactDOM && !(window as any).ReactDOM) {
110
+ (window as any).ReactDOM = ReactDOM;
111
+ console.log('✓ Exposed ReactDOM as window.ReactDOM for UMD compatibility');
112
+ }
113
+ // Also expose PropTypes as empty object if not present (for older libraries)
114
+ if (!(window as any).PropTypes) {
115
+ (window as any).PropTypes = {};
116
+ console.log('✓ Exposed empty PropTypes as window.PropTypes for UMD compatibility');
117
+ }
118
+ }
119
+
102
120
  // Now load plugin libraries from configuration
103
121
  const config = StandardLibraryManager.getConfiguration();
104
122
  const enabledLibraries = StandardLibraryManager.getEnabledLibraries();