@memberjunction/react-runtime
Version:
Platform-agnostic React component runtime for MemberJunction. Provides core compilation, registry, and execution capabilities for React components in any JavaScript environment.
227 lines • 7.5 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ComponentRegistry = void 0;
const resource_manager_1 = require("../utilities/resource-manager");
const DEFAULT_REGISTRY_CONFIG = {
maxComponents: 1000,
cleanupInterval: 60000,
useLRU: true,
enableNamespaces: true
};
class ComponentRegistry {
constructor(config) {
this.config = { ...DEFAULT_REGISTRY_CONFIG, ...config };
this.registry = new Map();
this.registryId = `component-registry-${Date.now()}`;
if (this.config.cleanupInterval > 0) {
this.startCleanupTimer();
}
}
register(name, component, namespace = 'Global', version = 'v1', tags) {
const id = this.generateRegistryKey(name, namespace, version);
const metadata = {
id,
name,
version,
namespace,
registeredAt: new Date(),
tags
};
const entry = {
component,
metadata,
lastAccessed: new Date(),
refCount: 0
};
if (this.registry.size >= this.config.maxComponents && this.config.useLRU) {
this.evictLRU();
}
this.registry.set(id, entry);
return metadata;
}
get(name, namespace = 'Global', version) {
const id = version
? this.generateRegistryKey(name, namespace, version)
: this.findLatestVersion(name, namespace);
if (!id)
return undefined;
const entry = this.registry.get(id);
if (entry) {
entry.lastAccessed = new Date();
entry.refCount++;
return entry.component;
}
return undefined;
}
has(name, namespace = 'Global', version) {
const id = version
? this.generateRegistryKey(name, namespace, version)
: this.findLatestVersion(name, namespace);
return id ? this.registry.has(id) : false;
}
unregister(name, namespace = 'Global', version) {
const id = version
? this.generateRegistryKey(name, namespace, version)
: this.findLatestVersion(name, namespace);
if (!id)
return false;
return this.registry.delete(id);
}
getNamespace(namespace) {
const components = [];
for (const entry of this.registry.values()) {
if (entry.metadata.namespace === namespace) {
components.push(entry.metadata);
}
}
return components;
}
getAll(namespace = 'Global', version = 'v1') {
const components = {};
for (const entry of this.registry.values()) {
if (entry.metadata.namespace === namespace && entry.metadata.version === version) {
components[entry.metadata.name] = entry.component;
}
}
return components;
}
getNamespaces() {
const namespaces = new Set();
for (const entry of this.registry.values()) {
namespaces.add(entry.metadata.namespace);
}
return Array.from(namespaces);
}
getByTags(tags) {
const components = [];
for (const entry of this.registry.values()) {
if (entry.metadata.tags?.some(tag => tags.includes(tag))) {
components.push(entry.metadata);
}
}
return components;
}
release(name, namespace = 'Global', version) {
const id = version
? this.generateRegistryKey(name, namespace, version)
: this.findLatestVersion(name, namespace);
if (!id)
return;
const entry = this.registry.get(id);
if (entry && entry.refCount > 0) {
entry.refCount--;
}
}
clear() {
this.registry.clear();
}
clearNamespace(namespace = 'Global') {
const toRemove = [];
for (const [key, entry] of this.registry) {
if (entry.metadata.namespace === namespace) {
toRemove.push(key);
}
}
for (const key of toRemove) {
this.registry.delete(key);
}
return toRemove.length;
}
forceClear() {
this.stopCleanupTimer();
this.registry.clear();
console.log('🧹 Registry force cleared - all components removed');
}
size() {
return this.registry.size;
}
cleanup(force = false) {
const toRemove = [];
const now = Date.now();
for (const [id, entry] of this.registry) {
const timeSinceAccess = now - entry.lastAccessed.getTime();
const isUnused = entry.refCount === 0 && timeSinceAccess > this.config.cleanupInterval;
if (force || isUnused) {
toRemove.push(id);
}
}
for (const id of toRemove) {
this.registry.delete(id);
}
return toRemove.length;
}
getStats() {
let totalRefCount = 0;
let oldest;
let newest;
for (const entry of this.registry.values()) {
totalRefCount += entry.refCount;
if (!oldest || entry.metadata.registeredAt < oldest) {
oldest = entry.metadata.registeredAt;
}
if (!newest || entry.metadata.registeredAt > newest) {
newest = entry.metadata.registeredAt;
}
}
return {
totalComponents: this.registry.size,
namespaces: this.getNamespaces().length,
totalRefCount,
oldestComponent: oldest,
newestComponent: newest
};
}
destroy() {
this.stopCleanupTimer();
this.clear();
resource_manager_1.resourceManager.cleanupComponent(this.registryId);
}
generateRegistryKey(name, namespace, version) {
if (this.config.enableNamespaces) {
return `${namespace}::${name}@${version}`;
}
return `${name}@${version}`;
}
findLatestVersion(name, namespace) {
let latestKey;
let latestDate;
for (const [key, entry] of this.registry) {
if (entry.metadata.name === name &&
entry.metadata.namespace === namespace) {
if (!latestDate || entry.metadata.registeredAt > latestDate) {
latestDate = entry.metadata.registeredAt;
latestKey = key;
}
}
}
return latestKey;
}
evictLRU() {
let lruKey;
let lruTime;
for (const [key, entry] of this.registry) {
if (entry.refCount > 0)
continue;
if (!lruTime || entry.lastAccessed < lruTime) {
lruTime = entry.lastAccessed;
lruKey = key;
}
}
if (lruKey) {
this.registry.delete(lruKey);
}
}
startCleanupTimer() {
this.cleanupTimer = resource_manager_1.resourceManager.setInterval(this.registryId, () => {
this.cleanup();
}, this.config.cleanupInterval, { purpose: 'component-registry-cleanup' });
}
stopCleanupTimer() {
if (this.cleanupTimer) {
resource_manager_1.resourceManager.clearInterval(this.registryId, this.cleanupTimer);
this.cleanupTimer = undefined;
}
}
}
exports.ComponentRegistry = ComponentRegistry;
//# sourceMappingURL=component-registry.js.map