@memberjunction/react-runtime 5.33.0 → 5.34.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memberjunction/react-runtime",
3
- "version": "5.33.0",
3
+ "version": "5.34.0",
4
4
  "description": "Platform-agnostic React component runtime for MemberJunction. Provides core compilation, registry, and execution capabilities for React components in any JavaScript environment.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -29,11 +29,11 @@
29
29
  },
30
30
  "homepage": "https://github.com/MemberJunction/MJ#readme",
31
31
  "dependencies": {
32
- "@memberjunction/core": "5.33.0",
33
- "@memberjunction/global": "5.33.0",
34
- "@memberjunction/interactive-component-types": "5.33.0",
35
- "@memberjunction/core-entities": "5.33.0",
36
- "@memberjunction/graphql-dataprovider": "5.33.0",
32
+ "@memberjunction/core": "5.34.0",
33
+ "@memberjunction/global": "5.34.0",
34
+ "@memberjunction/interactive-component-types": "5.34.0",
35
+ "@memberjunction/core-entities": "5.34.0",
36
+ "@memberjunction/graphql-dataprovider": "5.34.0",
37
37
  "@babel/standalone": "^7.29.1",
38
38
  "rxjs": "^7.8.2"
39
39
  },
@@ -5,7 +5,7 @@
5
5
 
6
6
  import { ComponentSpec, ComponentLibraryDependency } from '@memberjunction/interactive-component-types';
7
7
  import { UserInfo, Metadata, LogError } from '@memberjunction/core';
8
- import { ComponentMetadataEngine, MJComponentLibraryEntity, MJComponentEntityExtended } from '@memberjunction/core-entities';
8
+ import { ComponentMetadataEngine, MJComponentLibraryEntity } from '@memberjunction/core-entities';
9
9
 
10
10
  import { ComponentCompiler } from '../compiler';
11
11
  import { ComponentRegistry } from '../registry';
@@ -515,87 +515,82 @@ export class ComponentManager {
515
515
  // Check cache first
516
516
  const cacheKey = this.getComponentKey(spec, {});
517
517
  const cached = this.fetchCache.get(cacheKey);
518
-
518
+
519
519
  if (cached && this.isCacheValid(cached)) {
520
520
  this.log(`Using cached spec for: ${spec.name}`);
521
521
  return cached.spec;
522
522
  }
523
-
523
+
524
524
  // Handle LOCAL registry components (registry is null/undefined)
525
525
  if (!spec.registry) {
526
- this.log(`Fetching from local registry: ${spec.name}`);
527
-
528
- // Find component in local ComponentMetadataEngine
529
- const localComponent = this.componentEngine.Components?.find(
530
- (c: MJComponentEntityExtended) => {
531
- // Match by name (case-insensitive for better compatibility)
532
- const nameMatch = c.Name?.toLowerCase() === spec.name?.toLowerCase();
533
-
534
- // Match by namespace if provided (handle different formats)
535
- const namespaceMatch = !spec.namespace || c.Namespace?.toLowerCase() === spec.namespace?.toLowerCase();
526
+ const localComponent = await this.componentEngine.FindComponent(spec.name, spec.namespace);
536
527
 
537
- if (nameMatch && !namespaceMatch) {
538
- }
539
-
540
- return nameMatch && namespaceMatch;
541
- }
542
- );
543
-
544
528
  if (!localComponent) {
545
529
  throw new Error(`Local component not found: ${spec.name}`);
546
530
  }
547
-
548
- // Parse specification from local component
531
+
549
532
  if (!localComponent.Specification) {
550
533
  throw new Error(`Local component ${spec.name} has no specification`);
551
534
  }
552
-
535
+
553
536
  const fullSpec = JSON.parse(localComponent.Specification);
554
-
555
- // Cache it
537
+
556
538
  this.fetchCache.set(cacheKey, {
557
539
  spec: fullSpec,
558
540
  fetchedAt: new Date(),
559
541
  usageNotified: false
560
542
  });
561
-
543
+
562
544
  return fullSpec;
563
545
  }
564
-
546
+
565
547
  // Handle EXTERNAL registry components (registry has a name)
566
- // Initialize GraphQL client if needed
567
548
  if (!this.graphQLClient) {
568
549
  await this.initializeGraphQLClient();
569
550
  }
570
-
551
+
571
552
  if (!this.graphQLClient) {
572
553
  throw new Error('GraphQL client not available for registry fetching');
573
554
  }
574
-
575
- // Fetch from external registry
555
+
556
+ // Fetch from external registry, passing the cached hash (if any) so the
557
+ // server can return 304 Not Modified when the spec hasn't changed
576
558
  this.log(`Fetching from external registry: ${spec.registry}/${spec.name}`);
577
-
578
- const fullSpec = await this.graphQLClient.GetRegistryComponent({
559
+ const cachedHash = cached?.hash;
560
+
561
+ const response = await this.graphQLClient.GetRegistryComponentWithHash({
579
562
  registryName: spec.registry,
580
563
  namespace: spec.namespace || 'Global',
581
564
  name: spec.name,
582
- version: spec.version || 'latest'
565
+ version: spec.version || 'latest',
566
+ hash: cachedHash
583
567
  });
584
-
585
- if (!fullSpec) {
568
+
569
+ // If not modified (304), reuse the cached spec and refresh the TTL
570
+ if (response.notModified && cached) {
571
+ this.log(`Registry returned 304 for ${spec.name}, reusing cached spec`);
572
+ this.fetchCache.set(cacheKey, {
573
+ ...cached,
574
+ fetchedAt: new Date()
575
+ });
576
+ return cached.spec;
577
+ }
578
+
579
+ if (!response.specification) {
586
580
  throw new Error(`Component not found in registry: ${spec.registry}/${spec.name}`);
587
581
  }
588
-
589
- // Apply resolution mode if specified
582
+
583
+ const fullSpec = response.specification as ComponentSpec;
590
584
  const processedSpec = this.applyResolutionMode(fullSpec, spec, options?.resolutionMode);
591
-
592
- // Cache it
585
+
586
+ // Cache it with the registry hash for future 304 checks
593
587
  this.fetchCache.set(cacheKey, {
594
588
  spec: processedSpec,
595
589
  fetchedAt: new Date(),
590
+ hash: response.hash,
596
591
  usageNotified: false
597
592
  });
598
-
593
+
599
594
  return processedSpec;
600
595
  }
601
596
 
@@ -232,8 +232,8 @@ export class ComponentRegistryService {
232
232
  ): Promise<ComponentObject> {
233
233
  await this.initialize(contextUser);
234
234
 
235
- // Find component in metadata
236
- const component = this.componentEngine.Components.find((c: MJComponentEntity) => UUIDsEqual(c.ID, componentId));
235
+ // Find component in metadata via targeted query
236
+ const component = await this.componentEngine.FindComponentByID(componentId, contextUser);
237
237
  if (!component) {
238
238
  throw new Error(`Component not found: ${componentId}`);
239
239
  }
@@ -487,7 +487,7 @@ export class ComponentRegistryService {
487
487
  ): Promise<ComponentSpec> {
488
488
  await this.initialize(contextUser);
489
489
 
490
- const component = this.componentEngine.Components.find((c: MJComponentEntity) => UUIDsEqual(c.ID, componentId));
490
+ const component = await this.componentEngine.FindComponentByID(componentId, contextUser);
491
491
  if (!component) {
492
492
  throw new Error(`Component not found: ${componentId}`);
493
493
  }
@@ -697,16 +697,14 @@ export class ComponentRegistryService {
697
697
 
698
698
  for (const dep of dependencies) {
699
699
  // Find the dependency component
700
- const depComponent = this.componentEngine.Components.find(
701
- (c: MJComponentEntity) => UUIDsEqual(c.ID, dep.DependencyComponentID)
702
- );
703
-
700
+ const depComponent = await this.componentEngine.FindComponentByID(dep.DependencyComponentID, contextUser);
701
+
704
702
  if (depComponent) {
705
703
  result.push({
706
704
  name: depComponent.Name,
707
705
  namespace: depComponent.Namespace || '',
708
- version: depComponent.Version, // Version comes from the linked Component record
709
- isRequired: true, // All dependencies are required in MemberJunction
706
+ version: depComponent.Version,
707
+ isRequired: true,
710
708
  location: depComponent.SourceRegistryID ? 'registry' : 'embedded',
711
709
  sourceRegistryID: depComponent.SourceRegistryID
712
710
  });
@@ -734,27 +732,23 @@ export class ComponentRegistryService {
734
732
 
735
733
  await this.initialize(contextUser);
736
734
 
737
- const component = this.componentEngine.Components.find((c: MJComponentEntity) => UUIDsEqual(c.ID, componentId));
735
+ const component = await this.componentEngine.FindComponentByID(componentId, contextUser);
738
736
  if (!component) {
739
737
  return { componentId, dependencies: [] };
740
738
  }
741
-
739
+
742
740
  // Get direct dependencies
743
741
  const directDeps = await this.loadDependencies(componentId, contextUser);
744
-
742
+
745
743
  // Recursively resolve each dependency
746
744
  const dependencies: DependencyTree[] = [];
747
745
  for (const dep of directDeps) {
748
- // Find the dependency component
749
- const depComponent = this.componentEngine.Components.find(
750
- c => c.Name.trim().toLowerCase() === dep.name.trim().toLowerCase() &&
751
- c.Namespace?.trim().toLowerCase() === dep.namespace?.trim().toLowerCase()
752
- );
753
-
746
+ const depComponent = await this.componentEngine.FindComponent(dep.name, dep.namespace, undefined, contextUser);
747
+
754
748
  if (depComponent) {
755
749
  const subTree = await this.resolveDependencyTree(
756
- depComponent.ID,
757
- contextUser,
750
+ depComponent.ID,
751
+ contextUser,
758
752
  visited
759
753
  );
760
754
  dependencies.push(subTree);
@@ -95,7 +95,7 @@ export class ComponentResolver {
95
95
  }
96
96
  await this.componentEngine.Config(false, contextUser);
97
97
  if (this.debug) {
98
- console.log(`✅ [ComponentResolver] Component engine initialized with ${this.componentEngine.Components?.length || 0} components`);
98
+ console.log(`✅ [ComponentResolver] Component engine initialized`);
99
99
  }
100
100
  }
101
101
 
@@ -243,36 +243,18 @@ export class ComponentResolver {
243
243
  console.error(`❌ [ComponentResolver] Failed to fetch from external registry: ${spec.name} from ${spec.registry}`);
244
244
  }
245
245
  } else {
246
- // LOCAL REGISTRY: Get from local database
246
+ // LOCAL REGISTRY: Get from local database via targeted RunView
247
247
  if (this.debug) {
248
- console.log(`💾 [ComponentResolver] Looking for locally registered component`);
248
+ console.log(`💾 [ComponentResolver] Looking for locally registered component: ${spec.name}`);
249
249
  }
250
-
251
- // First, try to find the component in the metadata engine
252
- const allComponents = this.componentEngine.Components || [];
253
- if (this.debug) {
254
- console.log(`📊 [ComponentResolver] Total components in engine: ${allComponents.length}`);
255
- }
256
-
257
- // Log all matching names to see duplicates
258
- const matchingNames = allComponents.filter((c: any) => c.Name === spec.name);
259
- if (matchingNames.length > 0 && this.debug) {
260
- console.log(`🔎 [ComponentResolver] Found ${matchingNames.length} components with name "${spec.name}":`,
261
- matchingNames.map((c: any) => ({
262
- ID: c.ID,
263
- Name: c.Name,
264
- Namespace: c.Namespace,
265
- Version: c.Version,
266
- Status: c.Status
267
- }))
268
- );
269
- }
270
-
271
- const component = this.componentEngine.Components?.find(
272
- (c: any) => c.Name === spec.name &&
273
- c.Namespace === (spec.namespace || namespace)
250
+
251
+ const component = await this.componentEngine.FindComponent(
252
+ spec.name,
253
+ spec.namespace || namespace,
254
+ undefined,
255
+ contextUser
274
256
  );
275
-
257
+
276
258
  if (component) {
277
259
  if (this.debug) {
278
260
  console.log(`✅ [ComponentResolver] Found component in local DB:`, {
@@ -282,7 +264,7 @@ export class ComponentResolver {
282
264
  Version: component.Version
283
265
  });
284
266
  }
285
-
267
+
286
268
  // Get compiled component from registry service (local compilation)
287
269
  const compiledComponent = await this.registryService.getCompiledComponent(
288
270
  component.ID,
@@ -295,9 +277,6 @@ export class ComponentResolver {
295
277
  }
296
278
  } else {
297
279
  console.error(`❌ [ComponentResolver] Local registry component NOT found in database: ${spec.name} with namespace: ${spec.namespace || namespace}`);
298
- if (this.debug) {
299
- console.warn(`Local registry component not found in database: ${spec.name}`);
300
- }
301
280
  }
302
281
  }
303
282
  } catch (error) {