@memberjunction/react-runtime 2.93.0 → 2.95.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 (64) hide show
  1. package/.turbo/turbo-build.log +6 -6
  2. package/CHANGELOG.md +28 -0
  3. package/README.md +180 -2
  4. package/dist/compiler/component-compiler.d.ts +1 -0
  5. package/dist/compiler/component-compiler.d.ts.map +1 -1
  6. package/dist/compiler/component-compiler.js +253 -61
  7. package/dist/compiler/component-compiler.js.map +1 -1
  8. package/dist/index.d.ts +3 -2
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +15 -5
  11. package/dist/index.js.map +1 -1
  12. package/dist/registry/component-registry-service.d.ts +6 -3
  13. package/dist/registry/component-registry-service.d.ts.map +1 -1
  14. package/dist/registry/component-registry-service.js +38 -11
  15. package/dist/registry/component-registry-service.js.map +1 -1
  16. package/dist/registry/component-registry.d.ts +6 -3
  17. package/dist/registry/component-registry.d.ts.map +1 -1
  18. package/dist/registry/component-registry.js +17 -0
  19. package/dist/registry/component-registry.js.map +1 -1
  20. package/dist/registry/component-resolver.d.ts +2 -1
  21. package/dist/registry/component-resolver.d.ts.map +1 -1
  22. package/dist/registry/component-resolver.js +101 -14
  23. package/dist/registry/component-resolver.js.map +1 -1
  24. package/dist/runtime/component-hierarchy.d.ts.map +1 -1
  25. package/dist/runtime/component-hierarchy.js +75 -13
  26. package/dist/runtime/component-hierarchy.js.map +1 -1
  27. package/dist/runtime/prop-builder.d.ts +2 -2
  28. package/dist/runtime/prop-builder.d.ts.map +1 -1
  29. package/dist/runtime/prop-builder.js +32 -14
  30. package/dist/runtime/prop-builder.js.map +1 -1
  31. package/dist/runtime.umd.js +1 -1
  32. package/dist/types/dependency-types.d.ts +62 -0
  33. package/dist/types/dependency-types.d.ts.map +1 -0
  34. package/dist/types/dependency-types.js +3 -0
  35. package/dist/types/dependency-types.js.map +1 -0
  36. package/dist/types/index.d.ts +8 -10
  37. package/dist/types/index.d.ts.map +1 -1
  38. package/dist/types/index.js +1 -0
  39. package/dist/types/index.js.map +1 -1
  40. package/dist/utilities/index.d.ts +1 -0
  41. package/dist/utilities/index.d.ts.map +1 -1
  42. package/dist/utilities/index.js +1 -0
  43. package/dist/utilities/index.js.map +1 -1
  44. package/dist/utilities/library-dependency-resolver.d.ts +19 -0
  45. package/dist/utilities/library-dependency-resolver.d.ts.map +1 -0
  46. package/dist/utilities/library-dependency-resolver.js +419 -0
  47. package/dist/utilities/library-dependency-resolver.js.map +1 -0
  48. package/dist/utilities/library-loader.d.ts +9 -0
  49. package/dist/utilities/library-loader.d.ts.map +1 -1
  50. package/dist/utilities/library-loader.js +164 -0
  51. package/dist/utilities/library-loader.js.map +1 -1
  52. package/package.json +5 -5
  53. package/src/compiler/component-compiler.ts +280 -82
  54. package/src/index.ts +20 -5
  55. package/src/registry/component-registry-service.ts +53 -14
  56. package/src/registry/component-registry.ts +36 -7
  57. package/src/registry/component-resolver.ts +130 -16
  58. package/src/runtime/component-hierarchy.ts +101 -27
  59. package/src/runtime/prop-builder.ts +38 -18
  60. package/src/types/dependency-types.ts +110 -0
  61. package/src/types/index.ts +17 -21
  62. package/src/utilities/index.ts +1 -0
  63. package/src/utilities/library-dependency-resolver.ts +613 -0
  64. package/src/utilities/library-loader.ts +274 -0
@@ -11,6 +11,10 @@ import {
11
11
  import { LibraryConfiguration, ExternalLibraryConfig, LibraryLoadOptions as ConfigLoadOptions } from '../types/library-config';
12
12
  import { getCoreRuntimeLibraries, isCoreRuntimeLibrary } from './core-libraries';
13
13
  import { resourceManager } from './resource-manager';
14
+ import { ComponentLibraryEntity } from '@memberjunction/core-entities';
15
+ import { LibraryDependencyResolver } from './library-dependency-resolver';
16
+ import { LoadedLibraryState, DependencyResolutionOptions } from '../types/dependency-types';
17
+ import { LibraryRegistry } from './library-registry';
14
18
 
15
19
  // Unique component ID for resource tracking
16
20
  const LIBRARY_LOADER_COMPONENT_ID = 'mj-react-runtime-library-loader-singleton';
@@ -53,6 +57,8 @@ export interface LibraryLoadResult {
53
57
  */
54
58
  export class LibraryLoader {
55
59
  private static loadedResources = new Map<string, LoadedResource>();
60
+ private static loadedLibraryStates = new Map<string, LoadedLibraryState>();
61
+ private static dependencyResolver = new LibraryDependencyResolver({ debug: false });
56
62
 
57
63
  /**
58
64
  * Load all standard libraries (core + UI + CSS)
@@ -383,8 +389,276 @@ export class LibraryLoader {
383
389
  });
384
390
 
385
391
  this.loadedResources.clear();
392
+ this.loadedLibraryStates.clear();
386
393
 
387
394
  // Clean up any resources managed by resource manager
388
395
  resourceManager.cleanupComponent(LIBRARY_LOADER_COMPONENT_ID);
389
396
  }
397
+
398
+ /**
399
+ * Load a library with its dependencies
400
+ * @param libraryName - Name of the library to load
401
+ * @param allLibraries - All available libraries for dependency resolution
402
+ * @param requestedBy - Name of the component/library requesting this load
403
+ * @param options - Dependency resolution options
404
+ * @returns Promise resolving to the loaded library global object
405
+ */
406
+ static async loadLibraryWithDependencies(
407
+ libraryName: string,
408
+ allLibraries: ComponentLibraryEntity[],
409
+ requestedBy: string = 'user',
410
+ options?: DependencyResolutionOptions
411
+ ): Promise<any> {
412
+ const debug = options?.debug || false;
413
+
414
+ if (debug) {
415
+ console.log(`📚 Loading library '${libraryName}' with dependencies`);
416
+ }
417
+
418
+ // Check if already loaded
419
+ const existingState = this.loadedLibraryStates.get(libraryName);
420
+ if (existingState) {
421
+ if (debug) {
422
+ console.log(`✅ Library '${libraryName}' already loaded (version: ${existingState.version})`);
423
+ }
424
+ // Track who requested it
425
+ if (!existingState.requestedBy.includes(requestedBy)) {
426
+ existingState.requestedBy.push(requestedBy);
427
+ }
428
+ return (window as any)[existingState.globalVariable];
429
+ }
430
+
431
+ // Get load order including dependencies
432
+ const loadOrderResult = this.dependencyResolver.getLoadOrder(
433
+ [libraryName],
434
+ allLibraries,
435
+ options
436
+ );
437
+
438
+ if (!loadOrderResult.success) {
439
+ const errors = loadOrderResult.errors?.join(', ') || 'Unknown error';
440
+ throw new Error(`Failed to resolve dependencies for '${libraryName}': ${errors}`);
441
+ }
442
+
443
+ if (loadOrderResult.warnings && debug) {
444
+ console.warn(`⚠️ Warnings for '${libraryName}':`, loadOrderResult.warnings);
445
+ }
446
+
447
+ const loadOrder = loadOrderResult.order || [];
448
+ if (debug) {
449
+ console.log(`📋 Load order for '${libraryName}':`, loadOrder.map(lib => `${lib.Name}@${lib.Version}`));
450
+ }
451
+
452
+ // Load libraries in order
453
+ for (const library of loadOrder) {
454
+ // Skip if already loaded
455
+ if (this.loadedLibraryStates.has(library.Name)) {
456
+ if (debug) {
457
+ console.log(`⏭️ Skipping '${library.Name}' (already loaded)`);
458
+ }
459
+ continue;
460
+ }
461
+
462
+ if (debug) {
463
+ console.log(`📥 Loading '${library.Name}@${library.Version}'`);
464
+ }
465
+
466
+ // Load the library
467
+ if (!library.CDNUrl || !library.GlobalVariable) {
468
+ throw new Error(`Library '${library.Name}' missing CDN URL or global variable`);
469
+ }
470
+
471
+ // Load CSS if available
472
+ if (library.CDNCssUrl) {
473
+ const cssUrls = library.CDNCssUrl.split(',').map(url => url.trim());
474
+ for (const cssUrl of cssUrls) {
475
+ if (cssUrl) {
476
+ this.loadCSS(cssUrl);
477
+ }
478
+ }
479
+ }
480
+
481
+ // Load the script
482
+ const loadedGlobal = await this.loadScript(library.CDNUrl, library.GlobalVariable);
483
+
484
+ // Track the loaded state
485
+ const dependencies = Array.from(
486
+ this.dependencyResolver.getDirectDependencies(library).keys()
487
+ );
488
+
489
+ this.loadedLibraryStates.set(library.Name, {
490
+ name: library.Name,
491
+ version: library.Version || 'unknown',
492
+ globalVariable: library.GlobalVariable,
493
+ loadedAt: new Date(),
494
+ requestedBy: library.Name === libraryName ? [requestedBy] : [],
495
+ dependencies
496
+ });
497
+
498
+ if (debug) {
499
+ console.log(`✅ Loaded '${library.Name}@${library.Version}'`);
500
+ }
501
+ }
502
+
503
+ // Return the originally requested library's global
504
+ const targetLibrary = loadOrder.find(lib => lib.Name === libraryName);
505
+ if (!targetLibrary || !targetLibrary.GlobalVariable) {
506
+ throw new Error(`Failed to load library '${libraryName}'`);
507
+ }
508
+
509
+ return (window as any)[targetLibrary.GlobalVariable];
510
+ }
511
+
512
+ /**
513
+ * Load multiple libraries with dependency resolution
514
+ * @param libraryNames - Names of libraries to load
515
+ * @param allLibraries - All available libraries for dependency resolution
516
+ * @param requestedBy - Name of the component requesting these libraries
517
+ * @param options - Dependency resolution options
518
+ * @returns Map of library names to their loaded global objects
519
+ */
520
+ static async loadLibrariesWithDependencies(
521
+ libraryNames: string[],
522
+ allLibraries: ComponentLibraryEntity[],
523
+ requestedBy: string = 'user',
524
+ options?: DependencyResolutionOptions
525
+ ): Promise<Map<string, any>> {
526
+ const debug = options?.debug || false;
527
+ const result = new Map<string, any>();
528
+
529
+ if (debug) {
530
+ console.log(`📚 Loading libraries with dependencies:`, libraryNames);
531
+ console.log(` 📦 Total available libraries: ${allLibraries.length}`);
532
+ console.log(` 📋 Available library list:`, allLibraries.map(l => `${l.Name}@${l.Version}`));
533
+ }
534
+
535
+ // Get combined load order for all requested libraries
536
+ const loadOrderResult = this.dependencyResolver.getLoadOrder(
537
+ libraryNames,
538
+ allLibraries,
539
+ options
540
+ );
541
+
542
+ if (!loadOrderResult.success) {
543
+ const errors = loadOrderResult.errors?.join(', ') || 'Unknown error';
544
+ throw new Error(`Failed to resolve dependencies: ${errors}`);
545
+ }
546
+
547
+ if (debug) {
548
+ console.log(` 📊 Dependency resolution result:`, {
549
+ success: loadOrderResult.success,
550
+ errors: loadOrderResult.errors || [],
551
+ warnings: loadOrderResult.warnings || []
552
+ });
553
+
554
+ if (loadOrderResult.order) {
555
+ console.log(` 🔄 Resolved dependencies for each library:`);
556
+ loadOrderResult.order.forEach(lib => {
557
+ const deps = this.dependencyResolver.parseDependencies(lib.Dependencies);
558
+ if (deps.size > 0) {
559
+ console.log(` • ${lib.Name}@${lib.Version} requires:`, Array.from(deps.entries()));
560
+ } else {
561
+ console.log(` • ${lib.Name}@${lib.Version} (no dependencies)`);
562
+ }
563
+ });
564
+ }
565
+ }
566
+
567
+ if (loadOrderResult.warnings && debug) {
568
+ console.warn(` ⚠️ Warnings:`, loadOrderResult.warnings);
569
+ }
570
+
571
+ const loadOrder = loadOrderResult.order || [];
572
+ if (debug) {
573
+ console.log(` 📋 Final load order:`, loadOrder.map(lib => `${lib.Name}@${lib.Version}`));
574
+ }
575
+
576
+ // Load all libraries in order
577
+ for (const library of loadOrder) {
578
+ // Skip if already loaded
579
+ if (this.loadedLibraryStates.has(library.Name)) {
580
+ if (debug) {
581
+ console.log(`⏭️ Skipping '${library.Name}' (already loaded)`);
582
+ }
583
+ const state = this.loadedLibraryStates.get(library.Name)!;
584
+ if (libraryNames.includes(library.Name)) {
585
+ result.set(library.Name, (window as any)[state.globalVariable]);
586
+ }
587
+ continue;
588
+ }
589
+
590
+ if (debug) {
591
+ console.log(`📥 Loading '${library.Name}@${library.Version}'`);
592
+ }
593
+
594
+ // Load the library
595
+ if (!library.CDNUrl || !library.GlobalVariable) {
596
+ throw new Error(`Library '${library.Name}' missing CDN URL or global variable`);
597
+ }
598
+
599
+ // Load CSS if available
600
+ if (library.CDNCssUrl) {
601
+ const cssUrls = library.CDNCssUrl.split(',').map(url => url.trim());
602
+ for (const cssUrl of cssUrls) {
603
+ if (cssUrl) {
604
+ this.loadCSS(cssUrl);
605
+ }
606
+ }
607
+ }
608
+
609
+ // Load the script
610
+ const loadedGlobal = await this.loadScript(library.CDNUrl, library.GlobalVariable);
611
+
612
+ // Track the loaded state
613
+ const dependencies = Array.from(
614
+ this.dependencyResolver.getDirectDependencies(library).keys()
615
+ );
616
+
617
+ this.loadedLibraryStates.set(library.Name, {
618
+ name: library.Name,
619
+ version: library.Version || 'unknown',
620
+ globalVariable: library.GlobalVariable,
621
+ loadedAt: new Date(),
622
+ requestedBy: libraryNames.includes(library.Name) ? [requestedBy] : [],
623
+ dependencies
624
+ });
625
+
626
+ // Add to result if it was directly requested
627
+ if (libraryNames.includes(library.Name)) {
628
+ result.set(library.Name, loadedGlobal);
629
+ }
630
+
631
+ if (debug) {
632
+ console.log(`✅ Loaded '${library.Name}@${library.Version}'`);
633
+ }
634
+ }
635
+
636
+ return result;
637
+ }
638
+
639
+ /**
640
+ * Get information about loaded libraries
641
+ * @returns Map of loaded library states
642
+ */
643
+ static getLoadedLibraryStates(): Map<string, LoadedLibraryState> {
644
+ return new Map(this.loadedLibraryStates);
645
+ }
646
+
647
+ /**
648
+ * Check if a library is loaded
649
+ * @param libraryName - Name of the library
650
+ * @returns True if the library is loaded
651
+ */
652
+ static isLibraryLoaded(libraryName: string): boolean {
653
+ return this.loadedLibraryStates.has(libraryName);
654
+ }
655
+
656
+ /**
657
+ * Get the version of a loaded library
658
+ * @param libraryName - Name of the library
659
+ * @returns Version string or undefined if not loaded
660
+ */
661
+ static getLoadedLibraryVersion(libraryName: string): string | undefined {
662
+ return this.loadedLibraryStates.get(libraryName)?.version;
663
+ }
390
664
  }