UNPKG

@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
"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