@memberjunction/react-runtime 2.93.0 → 2.94.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 (62) hide show
  1. package/.turbo/turbo-build.log +6 -6
  2. package/CHANGELOG.md +16 -0
  3. package/README.md +180 -2
  4. package/dist/compiler/component-compiler.d.ts.map +1 -1
  5. package/dist/compiler/component-compiler.js +206 -57
  6. package/dist/compiler/component-compiler.js.map +1 -1
  7. package/dist/index.d.ts +2 -1
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +13 -4
  10. package/dist/index.js.map +1 -1
  11. package/dist/registry/component-registry-service.d.ts +4 -3
  12. package/dist/registry/component-registry-service.d.ts.map +1 -1
  13. package/dist/registry/component-registry-service.js +27 -11
  14. package/dist/registry/component-registry-service.js.map +1 -1
  15. package/dist/registry/component-registry.d.ts +4 -3
  16. package/dist/registry/component-registry.d.ts.map +1 -1
  17. package/dist/registry/component-registry.js.map +1 -1
  18. package/dist/registry/component-resolver.d.ts +2 -1
  19. package/dist/registry/component-resolver.d.ts.map +1 -1
  20. package/dist/registry/component-resolver.js +42 -10
  21. package/dist/registry/component-resolver.js.map +1 -1
  22. package/dist/runtime/component-hierarchy.d.ts.map +1 -1
  23. package/dist/runtime/component-hierarchy.js +8 -2
  24. package/dist/runtime/component-hierarchy.js.map +1 -1
  25. package/dist/runtime/prop-builder.d.ts +2 -2
  26. package/dist/runtime/prop-builder.d.ts.map +1 -1
  27. package/dist/runtime/prop-builder.js +32 -14
  28. package/dist/runtime/prop-builder.js.map +1 -1
  29. package/dist/runtime.umd.js +1 -1
  30. package/dist/types/dependency-types.d.ts +62 -0
  31. package/dist/types/dependency-types.d.ts.map +1 -0
  32. package/dist/types/dependency-types.js +3 -0
  33. package/dist/types/dependency-types.js.map +1 -0
  34. package/dist/types/index.d.ts +8 -10
  35. package/dist/types/index.d.ts.map +1 -1
  36. package/dist/types/index.js +1 -0
  37. package/dist/types/index.js.map +1 -1
  38. package/dist/utilities/index.d.ts +1 -0
  39. package/dist/utilities/index.d.ts.map +1 -1
  40. package/dist/utilities/index.js +1 -0
  41. package/dist/utilities/index.js.map +1 -1
  42. package/dist/utilities/library-dependency-resolver.d.ts +19 -0
  43. package/dist/utilities/library-dependency-resolver.d.ts.map +1 -0
  44. package/dist/utilities/library-dependency-resolver.js +410 -0
  45. package/dist/utilities/library-dependency-resolver.js.map +1 -0
  46. package/dist/utilities/library-loader.d.ts +9 -0
  47. package/dist/utilities/library-loader.d.ts.map +1 -1
  48. package/dist/utilities/library-loader.js +143 -0
  49. package/dist/utilities/library-loader.js.map +1 -1
  50. package/package.json +5 -5
  51. package/src/compiler/component-compiler.ts +227 -77
  52. package/src/index.ts +18 -4
  53. package/src/registry/component-registry-service.ts +32 -14
  54. package/src/registry/component-registry.ts +8 -7
  55. package/src/registry/component-resolver.ts +51 -10
  56. package/src/runtime/component-hierarchy.ts +12 -4
  57. package/src/runtime/prop-builder.ts +38 -18
  58. package/src/types/dependency-types.ts +110 -0
  59. package/src/types/index.ts +17 -21
  60. package/src/utilities/index.ts +1 -0
  61. package/src/utilities/library-dependency-resolver.ts +603 -0
  62. package/src/utilities/library-loader.ts +252 -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,254 @@ 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
+ }
532
+
533
+ // Get combined load order for all requested libraries
534
+ const loadOrderResult = this.dependencyResolver.getLoadOrder(
535
+ libraryNames,
536
+ allLibraries,
537
+ options
538
+ );
539
+
540
+ if (!loadOrderResult.success) {
541
+ const errors = loadOrderResult.errors?.join(', ') || 'Unknown error';
542
+ throw new Error(`Failed to resolve dependencies: ${errors}`);
543
+ }
544
+
545
+ if (loadOrderResult.warnings && debug) {
546
+ console.warn(`⚠️ Warnings:`, loadOrderResult.warnings);
547
+ }
548
+
549
+ const loadOrder = loadOrderResult.order || [];
550
+ if (debug) {
551
+ console.log(`📋 Combined load order:`, loadOrder.map(lib => `${lib.Name}@${lib.Version}`));
552
+ }
553
+
554
+ // Load all libraries in order
555
+ for (const library of loadOrder) {
556
+ // Skip if already loaded
557
+ if (this.loadedLibraryStates.has(library.Name)) {
558
+ if (debug) {
559
+ console.log(`⏭️ Skipping '${library.Name}' (already loaded)`);
560
+ }
561
+ const state = this.loadedLibraryStates.get(library.Name)!;
562
+ if (libraryNames.includes(library.Name)) {
563
+ result.set(library.Name, (window as any)[state.globalVariable]);
564
+ }
565
+ continue;
566
+ }
567
+
568
+ if (debug) {
569
+ console.log(`📥 Loading '${library.Name}@${library.Version}'`);
570
+ }
571
+
572
+ // Load the library
573
+ if (!library.CDNUrl || !library.GlobalVariable) {
574
+ throw new Error(`Library '${library.Name}' missing CDN URL or global variable`);
575
+ }
576
+
577
+ // Load CSS if available
578
+ if (library.CDNCssUrl) {
579
+ const cssUrls = library.CDNCssUrl.split(',').map(url => url.trim());
580
+ for (const cssUrl of cssUrls) {
581
+ if (cssUrl) {
582
+ this.loadCSS(cssUrl);
583
+ }
584
+ }
585
+ }
586
+
587
+ // Load the script
588
+ const loadedGlobal = await this.loadScript(library.CDNUrl, library.GlobalVariable);
589
+
590
+ // Track the loaded state
591
+ const dependencies = Array.from(
592
+ this.dependencyResolver.getDirectDependencies(library).keys()
593
+ );
594
+
595
+ this.loadedLibraryStates.set(library.Name, {
596
+ name: library.Name,
597
+ version: library.Version || 'unknown',
598
+ globalVariable: library.GlobalVariable,
599
+ loadedAt: new Date(),
600
+ requestedBy: libraryNames.includes(library.Name) ? [requestedBy] : [],
601
+ dependencies
602
+ });
603
+
604
+ // Add to result if it was directly requested
605
+ if (libraryNames.includes(library.Name)) {
606
+ result.set(library.Name, loadedGlobal);
607
+ }
608
+
609
+ if (debug) {
610
+ console.log(`✅ Loaded '${library.Name}@${library.Version}'`);
611
+ }
612
+ }
613
+
614
+ return result;
615
+ }
616
+
617
+ /**
618
+ * Get information about loaded libraries
619
+ * @returns Map of loaded library states
620
+ */
621
+ static getLoadedLibraryStates(): Map<string, LoadedLibraryState> {
622
+ return new Map(this.loadedLibraryStates);
623
+ }
624
+
625
+ /**
626
+ * Check if a library is loaded
627
+ * @param libraryName - Name of the library
628
+ * @returns True if the library is loaded
629
+ */
630
+ static isLibraryLoaded(libraryName: string): boolean {
631
+ return this.loadedLibraryStates.has(libraryName);
632
+ }
633
+
634
+ /**
635
+ * Get the version of a loaded library
636
+ * @param libraryName - Name of the library
637
+ * @returns Version string or undefined if not loaded
638
+ */
639
+ static getLoadedLibraryVersion(libraryName: string): string | undefined {
640
+ return this.loadedLibraryStates.get(libraryName)?.version;
641
+ }
390
642
  }