UNPKG

@dbs-portal/core-module-registry

Version:

Core module registry system for automatic module discovery and registration

1,213 lines (1,212 loc) 33.7 kB
var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); import { z } from "zod"; import { E, F, w, e, u, d, f, k, s, a, b, g, j, c, t, v, i, q, m, r, n, o, l, h, p, x } from "./platform-utils-Cix3Fefx.js"; var ModuleCategory = /* @__PURE__ */ ((ModuleCategory2) => { ModuleCategory2["IDENTITY"] = "identity"; ModuleCategory2["CONTENT"] = "content"; ModuleCategory2["COMMUNICATION"] = "communication"; ModuleCategory2["SYSTEM"] = "system"; ModuleCategory2["BUSINESS"] = "business"; ModuleCategory2["ANALYTICS"] = "analytics"; ModuleCategory2["INTEGRATION"] = "integration"; return ModuleCategory2; })(ModuleCategory || {}); var ModuleStatus = /* @__PURE__ */ ((ModuleStatus2) => { ModuleStatus2["ACTIVE"] = "active"; ModuleStatus2["INACTIVE"] = "inactive"; ModuleStatus2["DEVELOPMENT"] = "development"; ModuleStatus2["DEPRECATED"] = "deprecated"; ModuleStatus2["MAINTENANCE"] = "maintenance"; return ModuleStatus2; })(ModuleStatus || {}); var RouteGuardType = /* @__PURE__ */ ((RouteGuardType2) => { RouteGuardType2["PERMISSION"] = "permission"; RouteGuardType2["ROLE"] = "role"; RouteGuardType2["CUSTOM"] = "custom"; return RouteGuardType2; })(RouteGuardType || {}); var NavigationBadgeType = /* @__PURE__ */ ((NavigationBadgeType2) => { NavigationBadgeType2["COUNT"] = "count"; NavigationBadgeType2["STATUS"] = "status"; NavigationBadgeType2["NEW"] = "new"; return NavigationBadgeType2; })(NavigationBadgeType || {}); const RouteGuardSchema = z.object({ name: z.string(), type: z.nativeEnum(RouteGuardType), condition: z.string(), redirect: z.string().optional(), message: z.string().optional() }); const ModuleRouteSchema = z.lazy(() => z.object({ path: z.string(), component: z.string(), exact: z.boolean().optional(), permissions: z.array(z.string()).optional(), roles: z.array(z.string()).optional(), title: z.string().optional(), description: z.string().optional(), meta: z.record(z.any()).optional(), children: z.array(ModuleRouteSchema).optional(), redirect: z.string().optional(), guards: z.array(RouteGuardSchema).optional() })); const NavigationBadgeSchema = z.object({ text: z.string(), color: z.string(), type: z.nativeEnum(NavigationBadgeType) }); const NavigationItemSchema = z.lazy(() => z.object({ key: z.string(), label: z.string(), icon: z.string(), path: z.string(), category: z.string(), order: z.number(), permissions: z.array(z.string()).optional(), roles: z.array(z.string()).optional(), children: z.array(NavigationItemSchema).optional(), badge: NavigationBadgeSchema.optional(), tooltip: z.string().optional(), external: z.boolean().optional(), target: z.string().optional(), hidden: z.boolean().optional() })); const ModuleMetadataSchema = z.object({ // Core Identification id: z.string().regex(/^[a-z0-9-]+$/, "Module ID must be lowercase alphanumeric with hyphens"), name: z.string().min(1, "Module name is required"), version: z.string().regex(/^\d+\.\d+\.\d+/, "Version must follow semantic versioning"), description: z.string().optional(), // Categorization category: z.nativeEnum(ModuleCategory), subcategory: z.string().optional(), tags: z.array(z.string()).default([]), // Visual Configuration icon: z.string().min(1, "Icon is required"), color: z.string().optional(), banner: z.string().optional(), // Security and Access permissions: z.array(z.string()).default([]), roles: z.array(z.string()).optional(), public: z.boolean().optional(), // Routing Configuration routes: z.array(ModuleRouteSchema).default([]), basePath: z.string().optional(), // Navigation Configuration navigation: z.array(NavigationItemSchema).default([]), hideFromNavigation: z.boolean().optional(), // Dependencies dependencies: z.array(z.string()).default([]), peerDependencies: z.array(z.string()).optional(), optionalDependencies: z.array(z.string()).optional(), // Module Status status: z.nativeEnum(ModuleStatus).default( "active" /* ACTIVE */ ), priority: z.number().default(100), experimental: z.boolean().optional(), // Metadata author: z.string().optional(), license: z.string().optional(), repository: z.string().optional(), homepage: z.string().optional(), documentation: z.string().optional(), // Feature Configuration features: z.record(z.boolean()).optional(), config: z.record(z.any()).optional(), // Lifecycle Hooks onLoad: z.string().optional(), onUnload: z.string().optional(), onActivate: z.string().optional(), onDeactivate: z.string().optional(), // Performance lazy: z.boolean().optional(), preload: z.boolean().optional(), chunkName: z.string().optional() }); const validateModuleMetadata = (metadata) => { try { ModuleMetadataSchema.parse(metadata); return { valid: true, errors: [] }; } catch (error) { if (error instanceof z.ZodError) { return { valid: false, errors: error.errors.map((err) => ({ field: err.path.join("."), message: err.message, value: "received" in err ? err.received : void 0 })) }; } return { valid: false, errors: [{ field: "unknown", message: "Unknown validation error" }] }; } }; class ModuleCache { constructor(defaultTTL = 5 * 60 * 1e3, options = {}) { __publicField(this, "cache", /* @__PURE__ */ new Map()); __publicField(this, "options"); __publicField(this, "stats"); __publicField(this, "cleanupTimer", null); this.options = { defaultTTL, maxSize: 1e3, cleanupInterval: 60 * 1e3, // 1 minute enableStats: true, ...options }; this.stats = { hits: 0, misses: 0, sets: 0, deletes: 0, evictions: 0, size: 0, hitRate: 0 }; this.startCleanupTimer(); } /** * Get value from cache */ get(key) { const entry = this.cache.get(key); if (!entry) { this.updateStats("miss"); return null; } if (Date.now() > entry.expiry) { this.cache.delete(key); this.updateStats("miss"); return null; } this.updateStats("hit"); return entry.value; } /** * Set value in cache */ set(key, value, ttl) { const actualTTL = ttl ?? this.options.defaultTTL; const expiry = Date.now() + actualTTL; if (this.cache.size >= this.options.maxSize && !this.cache.has(key)) { this.evictOldest(); } const entry = { value, expiry, timestamp: Date.now() }; this.cache.set(key, entry); this.updateStats("set"); } /** * Check if key exists in cache (without updating access time) */ has(key) { const entry = this.cache.get(key); if (!entry) { return false; } if (Date.now() > entry.expiry) { this.cache.delete(key); return false; } return true; } /** * Delete value from cache */ delete(key) { const deleted = this.cache.delete(key); if (deleted) { this.updateStats("delete"); } return deleted; } /** * Clear all cache entries */ clear() { this.cache.clear(); this.resetStats(); } /** * Get cache size */ size() { return this.cache.size; } /** * Get all cache keys */ keys() { return Array.from(this.cache.keys()); } /** * Get cache statistics */ getStats() { this.updateHitRate(); return { ...this.stats, size: this.cache.size }; } /** * Reset cache statistics */ resetStats() { this.stats = { hits: 0, misses: 0, sets: 0, deletes: 0, evictions: 0, size: this.cache.size, hitRate: 0 }; } /** * Get cache entries that match a pattern */ getByPattern(pattern) { const results = []; const now = Date.now(); for (const [key, entry] of this.cache.entries()) { if (now > entry.expiry) { this.cache.delete(key); continue; } if (pattern.test(key)) { results.push({ key, value: entry.value }); } } return results; } /** * Set multiple values at once */ setMany(entries) { entries.forEach(({ key, value, ttl }) => { this.set(key, value, ttl); }); } /** * Get multiple values at once */ getMany(keys) { return keys.map((key) => ({ key, value: this.get(key) })); } /** * Delete multiple keys at once */ deleteMany(keys) { let deletedCount = 0; keys.forEach((key) => { if (this.delete(key)) { deletedCount++; } }); return deletedCount; } /** * Get cache memory usage estimate (in bytes) */ getMemoryUsage() { let totalSize = 0; for (const [key, entry] of this.cache.entries()) { totalSize += key.length * 2; totalSize += JSON.stringify(entry.value).length * 2; totalSize += 64; } return totalSize; } /** * Cleanup expired entries */ cleanup() { const now = Date.now(); let cleanedCount = 0; for (const [key, entry] of this.cache.entries()) { if (now > entry.expiry) { this.cache.delete(key); cleanedCount++; } } return cleanedCount; } /** * Destroy cache and cleanup resources */ destroy() { if (this.cleanupTimer) { clearInterval(this.cleanupTimer); this.cleanupTimer = null; } this.clear(); } /** * Start automatic cleanup timer */ startCleanupTimer() { if (this.options.cleanupInterval > 0) { this.cleanupTimer = setInterval(() => { this.cleanup(); }, this.options.cleanupInterval); } } /** * Evict oldest entry when cache is full */ evictOldest() { let oldestKey = null; let oldestTimestamp = Date.now(); for (const [key, entry] of this.cache.entries()) { if (entry.timestamp < oldestTimestamp) { oldestTimestamp = entry.timestamp; oldestKey = key; } } if (oldestKey) { this.cache.delete(oldestKey); this.updateStats("eviction"); } } /** * Update cache statistics */ updateStats(operation) { if (!this.options.enableStats) { return; } switch (operation) { case "hit": this.stats.hits++; break; case "miss": this.stats.misses++; break; case "set": this.stats.sets++; break; case "delete": this.stats.deletes++; break; case "eviction": this.stats.evictions++; break; } } /** * Update hit rate calculation */ updateHitRate() { const total = this.stats.hits + this.stats.misses; this.stats.hitRate = total > 0 ? this.stats.hits / total * 100 : 0; } } class BrowserEventEmitter { constructor() { __publicField(this, "events", /* @__PURE__ */ new Map()); __publicField(this, "onceEvents", /* @__PURE__ */ new Map()); __publicField(this, "maxListeners", 10); } /** * Add a listener for the specified event */ on(event, listener) { if (!this.events.has(event)) { this.events.set(event, /* @__PURE__ */ new Set()); } const listeners = this.events.get(event); listeners.add(listener); if (listeners.size > this.maxListeners) { console.warn(`MaxListenersExceededWarning: Possible EventEmitter memory leak detected. ${listeners.size} ${event} listeners added.`); } return this; } /** * Add a one-time listener for the specified event */ once(event, listener) { if (!this.onceEvents.has(event)) { this.onceEvents.set(event, /* @__PURE__ */ new Set()); } this.onceEvents.get(event).add(listener); return this; } /** * Remove a listener for the specified event */ off(event, listener) { const listeners = this.events.get(event); if (listeners) { listeners.delete(listener); if (listeners.size === 0) { this.events.delete(event); } } const onceListeners = this.onceEvents.get(event); if (onceListeners) { onceListeners.delete(listener); if (onceListeners.size === 0) { this.onceEvents.delete(event); } } return this; } /** * Emit an event to all listeners */ emit(event, ...args) { let hasListeners = false; const listeners = this.events.get(event); if (listeners && listeners.size > 0) { hasListeners = true; const listenersArray = Array.from(listeners); for (const listener of listenersArray) { try { listener.apply(this, args); } catch (error) { this.emitError(error); } } } const onceListeners = this.onceEvents.get(event); if (onceListeners && onceListeners.size > 0) { hasListeners = true; const onceListenersArray = Array.from(onceListeners); this.onceEvents.delete(event); for (const listener of onceListenersArray) { try { listener.apply(this, args); } catch (error) { this.emitError(error); } } } return hasListeners; } /** * Remove all listeners for a specific event or all events */ removeAllListeners(event) { if (event) { this.events.delete(event); this.onceEvents.delete(event); } else { this.events.clear(); this.onceEvents.clear(); } return this; } /** * Get the number of listeners for an event */ listenerCount(event) { const regularCount = this.events.get(event)?.size || 0; const onceCount = this.onceEvents.get(event)?.size || 0; return regularCount + onceCount; } /** * Get all listeners for an event */ listeners(event) { const regularListeners = Array.from(this.events.get(event) || []); const onceListeners = Array.from(this.onceEvents.get(event) || []); return [...regularListeners, ...onceListeners]; } /** * Set the maximum number of listeners before warning */ setMaxListeners(n2) { this.maxListeners = n2; return this; } /** * Get the maximum number of listeners */ getMaxListeners() { return this.maxListeners; } /** * Get all event names that have listeners */ eventNames() { const regularEvents = Array.from(this.events.keys()); const onceEvents = Array.from(this.onceEvents.keys()); return [.../* @__PURE__ */ new Set([...regularEvents, ...onceEvents])]; } /** * Add listener (alias for on) */ addListener(event, listener) { return this.on(event, listener); } /** * Remove listener (alias for off) */ removeListener(event, listener) { return this.off(event, listener); } /** * Prepend listener to the beginning of the listeners array */ prependListener(event, listener) { const listeners = this.events.get(event); if (listeners) { const existingListeners = Array.from(listeners); listeners.clear(); listeners.add(listener); existingListeners.forEach((l2) => listeners.add(l2)); } else { this.on(event, listener); } return this; } /** * Prepend one-time listener */ prependOnceListener(event, listener) { const onceListeners = this.onceEvents.get(event); if (onceListeners) { const existingListeners = Array.from(onceListeners); onceListeners.clear(); onceListeners.add(listener); existingListeners.forEach((l2) => onceListeners.add(l2)); } else { this.once(event, listener); } return this; } /** * Emit error event safely */ emitError(error) { if (this.listenerCount("error") > 0) { try { this.emit("error", error); } catch (e2) { console.error("EventEmitter error in error handler:", e2); } } else { console.error("Unhandled EventEmitter error:", error); } } } const defaultEventEmitter = new BrowserEventEmitter(); const _ModuleRegistry = class _ModuleRegistry { constructor(options = {}) { __publicField(this, "modules", /* @__PURE__ */ new Map()); __publicField(this, "registryListeners", /* @__PURE__ */ new Set()); __publicField(this, "cache"); __publicField(this, "options"); __publicField(this, "initialized", false); __publicField(this, "initializing", false); __publicField(this, "eventEmitter"); this.eventEmitter = new BrowserEventEmitter(); this.options = { enableCaching: true, cacheTimeout: 5 * 60 * 1e3, // 5 minutes validateOnRegister: true, allowDuplicates: false, autoInitialize: true, ...options }; this.cache = new ModuleCache(this.options.cacheTimeout); this.eventEmitter.on("error", (error) => { console.error("ModuleRegistry Error:", error); this.notifyListeners("onRegistryError", error); }); } /** * Event emitter methods - delegate to internal event emitter */ on(event, listener) { this.eventEmitter.on(event, listener); return this; } once(event, listener) { this.eventEmitter.once(event, listener); return this; } off(event, listener) { this.eventEmitter.off(event, listener); return this; } emit(event, ...args) { return this.eventEmitter.emit(event, ...args); } removeAllListeners(event) { this.eventEmitter.removeAllListeners(event); return this; } listenerCount(event) { return this.eventEmitter.listenerCount(event); } listeners(event) { return this.eventEmitter.listeners(event); } /** * Get singleton instance of ModuleRegistry */ static getInstance(options) { if (!_ModuleRegistry.instance) { _ModuleRegistry.instance = new _ModuleRegistry(options); } return _ModuleRegistry.instance; } /** * Reset singleton instance (mainly for testing) */ static resetInstance() { if (_ModuleRegistry.instance) { _ModuleRegistry.instance.removeAllListeners(); _ModuleRegistry.instance.modules.clear(); _ModuleRegistry.instance.registryListeners.clear(); _ModuleRegistry.instance.cache.clear(); } _ModuleRegistry.instance = null; } /** * Initialize the registry with module discovery */ async initialize() { if (this.initialized) { return; } if (this.initializing) { return new Promise((resolve) => { this.once("initialized", resolve); }); } this.initializing = true; try { const { ModuleDiscoveryService } = await import("./ModuleDiscoveryService-Dtr212Ba.js"); const discoveryService = new ModuleDiscoveryService(); const modules = await discoveryService.discoverModules(); for (const module of modules) { try { await this.registerModule(module, "discovery"); } catch (error) { console.warn(`Failed to register module ${module.id}:`, error); this.emit("error", error, module.id); } } this.initialized = true; this.initializing = false; this.emit("initialized", this.getAllModules()); this.notifyListeners("onRegistryInitialized", this.getAllModules()); } catch (error) { this.initializing = false; this.emit("error", error); throw error; } } /** * Register a module in the registry (with duplicate check) */ async registerModule(metadata, source = "runtime") { try { if (this.options.validateOnRegister) { const validation = this.validateModule(metadata); if (!validation.valid) { throw new Error(`Module validation failed: ${validation.errors.map((e2) => e2.message).join(", ")}`); } } if (!this.options.allowDuplicates && this.modules.has(metadata.id)) { const existingModule = this.modules.get(metadata.id); console.warn(`⚠️ Module ${metadata.id} is already registered`, { existing: { source: existingModule?.source, timestamp: existingModule?.timestamp, name: existingModule?.metadata.name }, new: { source, name: metadata.name } }); throw new Error(`Module ${metadata.id} is already registered`); } const registration = { metadata, timestamp: Date.now(), source }; this.modules.set(metadata.id, registration); if (this.options.enableCaching) { this.cache.set(`module:${metadata.id}`, registration); } const event = { type: "register", moduleId: metadata.id, module: metadata, timestamp: Date.now() }; this.emit("moduleRegistered", event); this.notifyListeners("onModuleRegistered", metadata); } catch (error) { this.emit("error", error, metadata.id); throw error; } } /** * Register a module safely (won't throw if already registered) */ async registerModuleSafe(metadata, source = "runtime") { try { if (this.modules.has(metadata.id)) { console.log(`ℹ️ Module ${metadata.id} is already registered, skipping`); return false; } await this.registerModule(metadata, source); return true; } catch (error) { console.warn(`Failed to register module ${metadata.id}:`, error); return false; } } /** * Unregister a module from the registry */ unregisterModule(moduleId) { try { const registration = this.modules.get(moduleId); if (!registration) { return false; } this.modules.delete(moduleId); if (this.options.enableCaching) { this.cache.delete(`module:${moduleId}`); } const event = { type: "unregister", moduleId, module: registration.metadata, timestamp: Date.now() }; this.emit("moduleUnregistered", event); this.notifyListeners("onModuleUnregistered", registration.metadata); return true; } catch (error) { this.emit("error", error, moduleId); return false; } } /** * Update a module's metadata */ updateModule(moduleId, updates) { try { const registration = this.modules.get(moduleId); if (!registration) { return false; } const updatedMetadata = { ...registration.metadata, ...updates }; if (this.options.validateOnRegister) { const validation = this.validateModule(updatedMetadata); if (!validation.valid) { throw new Error(`Module validation failed: ${validation.errors.map((e2) => e2.message).join(", ")}`); } } const updatedRegistration = { ...registration, metadata: updatedMetadata, timestamp: Date.now() }; this.modules.set(moduleId, updatedRegistration); if (this.options.enableCaching) { this.cache.set(`module:${moduleId}`, updatedRegistration); } const event = { type: "update", moduleId, module: updatedMetadata, timestamp: Date.now() }; this.emit("moduleUpdated", event); this.notifyListeners("onModuleUpdated", updatedMetadata); return true; } catch (error) { this.emit("error", error, moduleId); return false; } } /** * Get a specific module by ID */ getModule(moduleId) { if (this.options.enableCaching) { const cached = this.cache.get(`module:${moduleId}`); if (cached) { return cached.metadata; } } const registration = this.modules.get(moduleId); return registration?.metadata; } /** * Get all registered modules */ getAllModules() { return Array.from(this.modules.values()).map((reg) => reg.metadata); } /** * Get modules by category */ getModulesByCategory(category) { return this.getAllModules().filter((module) => module.category === category); } /** * Get modules by status */ getModulesByStatus(status) { return this.getAllModules().filter((module) => module.status === status); } /** * Get active modules only */ getActiveModules() { return this.getModulesByStatus(ModuleStatus.ACTIVE); } /** * Get modules with specific permissions */ getModulesWithPermissions(permissions) { return this.getAllModules().filter( (module) => permissions.some((permission) => module.permissions.includes(permission)) ); } /** * Search modules by name, description, or tags */ searchModules(query) { const lowerQuery = query.toLowerCase(); return this.getAllModules().filter( (module) => module.name.toLowerCase().includes(lowerQuery) || module.description.toLowerCase().includes(lowerQuery) || module.tags.some((tag) => tag.toLowerCase().includes(lowerQuery)) ); } /** * Check if a module is registered */ hasModule(moduleId) { return this.modules.has(moduleId); } /** * Get module count */ getModuleCount() { return this.modules.size; } /** * Validate module metadata */ validateModule(metadata) { return validateModuleMetadata(metadata); } /** * Add registry listener */ addListener(listener) { this.registryListeners.add(listener); } /** * Remove registry listener */ removeListener(listener) { this.registryListeners.delete(listener); } /** * Clear all modules (mainly for testing) */ clear() { this.modules.clear(); this.cache.clear(); this.registryListeners.clear(); this.initialized = false; this.initializing = false; } /** * Get registry statistics */ getStats() { const modules = this.getAllModules(); const categories = /* @__PURE__ */ new Map(); const statuses = /* @__PURE__ */ new Map(); modules.forEach((module) => { categories.set(module.category, (categories.get(module.category) || 0) + 1); statuses.set(module.status, (statuses.get(module.status) || 0) + 1); }); return { totalModules: modules.length, categories: Object.fromEntries(categories), statuses: Object.fromEntries(statuses), initialized: this.initialized, cacheEnabled: this.options.enableCaching }; } /** * Notify all listeners of an event */ notifyListeners(method, ...args) { this.registryListeners.forEach((listener) => { try { const fn = listener[method]; if (typeof fn === "function") { fn.apply(listener, args); } } catch (error) { console.error(`Error in registry listener ${method}:`, error); } }); } }; __publicField(_ModuleRegistry, "instance", null); let ModuleRegistry = _ModuleRegistry; const loadModuleAsync = async (modulePath) => { try { const module = await import(modulePath); return module.default || module; } catch (error) { console.error(`Failed to load module from ${modulePath}:`, error); throw error; } }; const normalizeModuleId = (id) => { return id.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, ""); }; const isValidModuleId = (id) => { return /^[a-z0-9-]+$/.test(id) && id.length > 0 && !id.startsWith("-") && !id.endsWith("-"); }; const resolveModulePath = (baseDir, moduleId) => { return `${baseDir}/${moduleId}`; }; const getModulePackageName = (moduleId) => { return `@dbs-portal/module-${moduleId}`; }; const hasPermission = (userPermissions, requiredPermissions) => { if (requiredPermissions.length === 0) return true; return requiredPermissions.some((permission) => userPermissions.includes(permission)); }; const hasRole = (userRoles, requiredRoles) => { if (!requiredRoles || requiredRoles.length === 0) return true; return requiredRoles.some((role) => userRoles.includes(role)); }; const filterModulesByPermissions = (modules, userPermissions) => { return modules.filter((module) => hasPermission(userPermissions, module.permissions)); }; const filterModulesByRoles = (modules, userRoles) => { return modules.filter((module) => hasRole(userRoles, module.roles || [])); }; const sortModulesByPriority = (modules) => { return [...modules].sort((a2, b2) => b2.priority - a2.priority); }; const sortModulesByName = (modules) => { return [...modules].sort((a2, b2) => a2.name.localeCompare(b2.name)); }; const groupModulesByCategory = (modules) => { return modules.reduce((groups, module) => { const category = module.category; if (!groups[category]) { groups[category] = []; } groups[category].push(module); return groups; }, {}); }; const validateModuleId = (id) => { if (!id) { return { valid: false, error: "Module ID is required" }; } if (!isValidModuleId(id)) { return { valid: false, error: "Module ID must be lowercase alphanumeric with hyphens" }; } if (id.length > 50) { return { valid: false, error: "Module ID must be 50 characters or less" }; } return { valid: true }; }; const resolveDependencies = (modules) => { const moduleMap = new Map(modules.map((m2) => [m2.id, m2])); const resolved = []; const resolving = /* @__PURE__ */ new Set(); const resolved_ids = /* @__PURE__ */ new Set(); const resolve = (moduleId) => { if (resolved_ids.has(moduleId)) return; if (resolving.has(moduleId)) { throw new Error(`Circular dependency detected: ${moduleId}`); } const module = moduleMap.get(moduleId); if (!module) { throw new Error(`Module not found: ${moduleId}`); } resolving.add(moduleId); for (const depId of module.dependencies) { resolve(depId); } resolving.delete(moduleId); resolved_ids.add(moduleId); resolved.push(module); }; for (const module of modules) { resolve(module.id); } return resolved; }; class ModuleRegistryError extends Error { constructor(message, moduleId, cause) { super(message); this.moduleId = moduleId; this.cause = cause; this.name = "ModuleRegistryError"; } } class ModuleValidationError extends ModuleRegistryError { constructor(message, moduleId, validationErrors) { super(message, moduleId); this.validationErrors = validationErrors; this.name = "ModuleValidationError"; } } class ModuleDiscoveryError extends ModuleRegistryError { constructor(message, source, cause) { super(message, void 0, cause); this.source = source; this.name = "ModuleDiscoveryError"; } } const measurePerformance = async (operation, label) => { const start = performance.now(); const result = await operation(); const duration = performance.now() - start; console.debug(`${label} took ${duration.toFixed(2)}ms`); return { result, duration }; }; const debounce = (func, wait) => { let timeout = null; return (...args) => { if (timeout) { clearTimeout(timeout); } timeout = setTimeout(() => { func(...args); }, wait); }; }; const throttle = (func, limit) => { let inThrottle = false; return (...args) => { if (!inThrottle) { func(...args); inThrottle = true; setTimeout(() => { inThrottle = false; }, limit); } }; }; async function createModuleDiscoveryService(options) { const { ModuleDiscoveryService } = await import( /* webpackChunkName: "discovery-service" */ "./ModuleDiscoveryService-Dtr212Ba.js" ); return new ModuleDiscoveryService(options); } const VERSION = "1.0.0"; const DEFAULT_REGISTRY_OPTIONS = { enableCaching: true, cacheTimeout: 5 * 60 * 1e3, // 5 minutes validateOnRegister: true, allowDuplicates: false, autoInitialize: true }; const DEFAULT_DISCOVERY_OPTIONS = { packageScanPaths: ["packages/modules/*", "packages/core/*"], configScanPaths: ["packages/modules/*", "src/pages/modules/*"], packageNamePattern: "@dbs-portal/module-*", configFilePattern: "module.config.{ts,js}", enablePackageScanning: true, enableConfigDetection: true, enableRuntimeRegistration: true, validateModules: true, ignorePatterns: ["node_modules/**", "dist/**", "**/*.test.*", "**/*.spec.*"] }; export { BrowserEventEmitter, DEFAULT_DISCOVERY_OPTIONS, DEFAULT_REGISTRY_OPTIONS, E as ENV, F as FEATURES, ModuleCache, ModuleCategory, ModuleDiscoveryError, ModuleMetadataSchema, ModuleRegistry, ModuleRegistryError, ModuleRouteSchema, ModuleStatus, ModuleValidationError, NavigationBadgeSchema, NavigationBadgeType, NavigationItemSchema, RouteGuardSchema, RouteGuardType, VERSION, w as assertFeature, e as clearModuleCache, u as createLogger, createModuleDiscoveryService, d as createPlatformError, debounce, defaultEventEmitter, f as detectEnvironment, filterModulesByPermissions, filterModulesByRoles, k as getCurrentDirectory, s as getEnvironmentName, a as getFs, b as getGlob, getModulePackageName, g as getPath, j as getPathSeparator, c as getPlatformInfo, t as getPlatformName, groupModulesByCategory, v as hasFeature, hasPermission, hasRole, i as initializePlatformModules, q as isBrowser, m as isDevelopment, r as isNode, n as isProduction, o as isTest, isValidModuleId, l as loadConditionalModule, h as loadConditionalModuleSync, loadModuleAsync, measurePerformance, normalizeModuleId, p as preloadBrowserModules, resolveDependencies, resolveModulePath, sortModulesByName, sortModulesByPriority, throttle, validateModuleId, validateModuleMetadata, x as warnMissingFeature }; //# sourceMappingURL=index.js.map