@memberjunction/react-runtime 5.33.0 → 5.34.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.
- package/.turbo/turbo-build.log +14 -14
- package/CHANGELOG.md +34 -0
- package/dist/324.runtime.umd.js +148 -103
- package/dist/component-manager/component-manager.d.ts +1 -0
- package/dist/component-manager/component-manager.d.ts.map +1 -1
- package/dist/component-manager/component-manager.js +28 -12
- package/dist/component-manager/component-manager.js.map +1 -1
- package/dist/registry/component-registry-service.d.ts.map +1 -1
- package/dist/registry/component-registry-service.js +5 -6
- package/dist/registry/component-registry-service.js.map +1 -1
- package/dist/registry/component-resolver.d.ts.map +1 -1
- package/dist/registry/component-resolver.js +3 -21
- package/dist/registry/component-resolver.js.map +1 -1
- package/dist/runtime.umd.js +4580 -2578
- package/package.json +6 -6
- package/src/component-manager/component-manager.ts +60 -47
- package/src/registry/component-registry-service.ts +14 -20
- package/src/registry/component-resolver.ts +11 -32
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memberjunction/react-runtime",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.34.1",
|
|
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
|
-
"@memberjunction/global": "5.
|
|
34
|
-
"@memberjunction/interactive-component-types": "5.
|
|
35
|
-
"@memberjunction/core-entities": "5.
|
|
36
|
-
"@memberjunction/graphql-dataprovider": "5.
|
|
32
|
+
"@memberjunction/core": "5.34.1",
|
|
33
|
+
"@memberjunction/global": "5.34.1",
|
|
34
|
+
"@memberjunction/interactive-component-types": "5.34.1",
|
|
35
|
+
"@memberjunction/core-entities": "5.34.1",
|
|
36
|
+
"@memberjunction/graphql-dataprovider": "5.34.1",
|
|
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
|
|
8
|
+
import { ComponentMetadataEngine, MJComponentLibraryEntity } from '@memberjunction/core-entities';
|
|
9
9
|
|
|
10
10
|
import { ComponentCompiler } from '../compiler';
|
|
11
11
|
import { ComponentRegistry } from '../registry';
|
|
@@ -424,12 +424,7 @@ export class ComponentManager {
|
|
|
424
424
|
}
|
|
425
425
|
}
|
|
426
426
|
|
|
427
|
-
|
|
428
|
-
// Prefer the input spec's dependencies over the cached result's dependencies.
|
|
429
|
-
// When a parent component is served from cache, result.spec contains stale
|
|
430
|
-
// dependency code. The input spec has the latest dependency code from the caller.
|
|
431
|
-
// Each dependency still gets its own individual cache check via loadComponent.
|
|
432
|
-
const dependencies = spec.dependencies || result.spec?.dependencies;
|
|
427
|
+
const dependencies = this.resolveDependencies(spec.dependencies, result.spec?.dependencies);
|
|
433
428
|
if (dependencies) {
|
|
434
429
|
for (const dep of dependencies) {
|
|
435
430
|
// Normalize dependency spec for local registry lookup
|
|
@@ -489,6 +484,29 @@ export class ComponentManager {
|
|
|
489
484
|
return results;
|
|
490
485
|
}
|
|
491
486
|
|
|
487
|
+
/**
|
|
488
|
+
* Determines which dependency list to use when loading a component's children.
|
|
489
|
+
*
|
|
490
|
+
* - Input deps with code take priority (caller has the latest version).
|
|
491
|
+
* - When input has no deps at all, fall back to fetched/cached deps
|
|
492
|
+
* (e.g., a registry reference spec with no dependency list).
|
|
493
|
+
* - When input has only stubs (no code), prefer fetched deps if they
|
|
494
|
+
* contain code (registry-populated hierarchies from Skip where the
|
|
495
|
+
* full tree is returned in one response).
|
|
496
|
+
*/
|
|
497
|
+
private resolveDependencies(
|
|
498
|
+
inputDeps: ComponentSpec[] | undefined,
|
|
499
|
+
fetchedDeps: ComponentSpec[] | undefined
|
|
500
|
+
): ComponentSpec[] | undefined {
|
|
501
|
+
const inputHasDeps = inputDeps && inputDeps.length > 0;
|
|
502
|
+
const inputHasCode = inputHasDeps && inputDeps.some(d => !!d.code);
|
|
503
|
+
|
|
504
|
+
if (inputHasCode) return inputDeps;
|
|
505
|
+
if (!inputHasDeps) return fetchedDeps || inputDeps;
|
|
506
|
+
if (fetchedDeps?.some(d => !!d.code)) return fetchedDeps;
|
|
507
|
+
return inputDeps;
|
|
508
|
+
}
|
|
509
|
+
|
|
492
510
|
/**
|
|
493
511
|
* Check if a component needs to be fetched from a registry
|
|
494
512
|
*/
|
|
@@ -515,87 +533,82 @@ export class ComponentManager {
|
|
|
515
533
|
// Check cache first
|
|
516
534
|
const cacheKey = this.getComponentKey(spec, {});
|
|
517
535
|
const cached = this.fetchCache.get(cacheKey);
|
|
518
|
-
|
|
536
|
+
|
|
519
537
|
if (cached && this.isCacheValid(cached)) {
|
|
520
538
|
this.log(`Using cached spec for: ${spec.name}`);
|
|
521
539
|
return cached.spec;
|
|
522
540
|
}
|
|
523
|
-
|
|
541
|
+
|
|
524
542
|
// Handle LOCAL registry components (registry is null/undefined)
|
|
525
543
|
if (!spec.registry) {
|
|
526
|
-
|
|
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();
|
|
544
|
+
const localComponent = await this.componentEngine.FindComponent(spec.name, spec.namespace);
|
|
536
545
|
|
|
537
|
-
if (nameMatch && !namespaceMatch) {
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
return nameMatch && namespaceMatch;
|
|
541
|
-
}
|
|
542
|
-
);
|
|
543
|
-
|
|
544
546
|
if (!localComponent) {
|
|
545
547
|
throw new Error(`Local component not found: ${spec.name}`);
|
|
546
548
|
}
|
|
547
|
-
|
|
548
|
-
// Parse specification from local component
|
|
549
|
+
|
|
549
550
|
if (!localComponent.Specification) {
|
|
550
551
|
throw new Error(`Local component ${spec.name} has no specification`);
|
|
551
552
|
}
|
|
552
|
-
|
|
553
|
+
|
|
553
554
|
const fullSpec = JSON.parse(localComponent.Specification);
|
|
554
|
-
|
|
555
|
-
// Cache it
|
|
555
|
+
|
|
556
556
|
this.fetchCache.set(cacheKey, {
|
|
557
557
|
spec: fullSpec,
|
|
558
558
|
fetchedAt: new Date(),
|
|
559
559
|
usageNotified: false
|
|
560
560
|
});
|
|
561
|
-
|
|
561
|
+
|
|
562
562
|
return fullSpec;
|
|
563
563
|
}
|
|
564
|
-
|
|
564
|
+
|
|
565
565
|
// Handle EXTERNAL registry components (registry has a name)
|
|
566
|
-
// Initialize GraphQL client if needed
|
|
567
566
|
if (!this.graphQLClient) {
|
|
568
567
|
await this.initializeGraphQLClient();
|
|
569
568
|
}
|
|
570
|
-
|
|
569
|
+
|
|
571
570
|
if (!this.graphQLClient) {
|
|
572
571
|
throw new Error('GraphQL client not available for registry fetching');
|
|
573
572
|
}
|
|
574
|
-
|
|
575
|
-
// Fetch from external registry
|
|
573
|
+
|
|
574
|
+
// Fetch from external registry, passing the cached hash (if any) so the
|
|
575
|
+
// server can return 304 Not Modified when the spec hasn't changed
|
|
576
576
|
this.log(`Fetching from external registry: ${spec.registry}/${spec.name}`);
|
|
577
|
-
|
|
578
|
-
|
|
577
|
+
const cachedHash = cached?.hash;
|
|
578
|
+
|
|
579
|
+
const response = await this.graphQLClient.GetRegistryComponentWithHash({
|
|
579
580
|
registryName: spec.registry,
|
|
580
581
|
namespace: spec.namespace || 'Global',
|
|
581
582
|
name: spec.name,
|
|
582
|
-
version: spec.version || 'latest'
|
|
583
|
+
version: spec.version || 'latest',
|
|
584
|
+
hash: cachedHash
|
|
583
585
|
});
|
|
584
|
-
|
|
585
|
-
|
|
586
|
+
|
|
587
|
+
// If not modified (304), reuse the cached spec and refresh the TTL
|
|
588
|
+
if (response.notModified && cached) {
|
|
589
|
+
this.log(`Registry returned 304 for ${spec.name}, reusing cached spec`);
|
|
590
|
+
this.fetchCache.set(cacheKey, {
|
|
591
|
+
...cached,
|
|
592
|
+
fetchedAt: new Date()
|
|
593
|
+
});
|
|
594
|
+
return cached.spec;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
if (!response.specification) {
|
|
586
598
|
throw new Error(`Component not found in registry: ${spec.registry}/${spec.name}`);
|
|
587
599
|
}
|
|
588
|
-
|
|
589
|
-
|
|
600
|
+
|
|
601
|
+
const fullSpec = response.specification as ComponentSpec;
|
|
590
602
|
const processedSpec = this.applyResolutionMode(fullSpec, spec, options?.resolutionMode);
|
|
591
|
-
|
|
592
|
-
// Cache it
|
|
603
|
+
|
|
604
|
+
// Cache it with the registry hash for future 304 checks
|
|
593
605
|
this.fetchCache.set(cacheKey, {
|
|
594
606
|
spec: processedSpec,
|
|
595
607
|
fetchedAt: new Date(),
|
|
608
|
+
hash: response.hash,
|
|
596
609
|
usageNotified: false
|
|
597
610
|
});
|
|
598
|
-
|
|
611
|
+
|
|
599
612
|
return processedSpec;
|
|
600
613
|
}
|
|
601
614
|
|
|
@@ -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.
|
|
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.
|
|
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.
|
|
701
|
-
|
|
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,
|
|
709
|
-
isRequired: true,
|
|
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.
|
|
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
|
-
|
|
749
|
-
|
|
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
|
|
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
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
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) {
|