UNPKG

@aurora-mp/core

Version:

Core package of the aurora-mp TypeScript framework, providing dependency injection, event handling, and module registration.

1,132 lines (1,101 loc) 38.8 kB
var __defProp = Object.defineProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); // src/index.ts import "reflect-metadata"; // src/constants/injection-tokens.ts var CONFIG_LOADER = Symbol.for("aurora:config:loader"); var CONFIG_SERVICE = Symbol.for("aurora:config:service"); var EVENT_SERVICE = Symbol.for("aurora:event:service"); var RPC_SERVICE = Symbol.for("aurora:rpc:service"); var LOGGER_SERVICE = Symbol.for("aurora:logger:service"); var PLATFORM_DRIVER = Symbol.for("aurora:platform:driver"); var WEBVIEW_SERVICE = Symbol.for("aurora:webview:service"); // src/constants/metadata-key.ts var MODULE_METADATA_KEY = Symbol.for("aurora:module"); var GLOBAL_MODULE_KEY = Symbol.for("aurora:global:module"); var CONTROLLER_METADATA_KEY = Symbol.for("aurora:controller"); var CONTROLLER_EVENTS_KEY = Symbol.for("aurora:controller:events"); var CONTROLLER_PARAMS_KEY = Symbol.for("aurora:controller:params"); var CONTROLLER_RPCS_KEY = Symbol.for("aurora:controller:rpcs"); var GUARDS_METADATA_KEY = Symbol.for("aurora:guards"); var INJECT_TOKEN_KEY = Symbol.for("aurora:inject"); var INJECT_PROPERTY_KEY = Symbol.for("aurora:inject:property"); var INJECTABLE_METADATA_KEY = Symbol.for("aurora:injectable"); var INJECTABLE_SCOPE_OPTIONS = Symbol.for("aurora:injectable:scope:options"); var EVENT_HANDLER_KEY = Symbol.for("aurora:event:handler"); // src/di/container.ts var Container = class { static { __name(this, "Container"); } providers = /* @__PURE__ */ new Map(); /** * Registers a provider instance under the given token. * If a provider already exists for this token, it will be overridden. * * @param token The injection token (class constructor, string, or symbol). * @param value The instance or value to associate with the token. */ register(token, value) { if (this.providers.has(token)) { console.warn(`A provider with the token "${String(token)}" is already registered. It will be overridden.`); } this.providers.set(token, value); } /** * Retrieves the provider instance associated with the given token. * * @param token The injection token to resolve. * @returns The instance or value stored under the token. * @throws {Error} If no provider is found for the token. */ resolve(token) { const instance = this.providers.get(token); if (instance === void 0) { throw new Error(`No provider found for token "${String(token)}". Make sure it is provided in a module and exported if necessary.`); } return instance; } /** * Checks whether a provider is registered for the given token. * * @param token The injection token to check. * @returns `true` if a provider exists, `false` otherwise. */ has(token) { return this.providers.has(token); } /** * Returns an iterator over all registered provider instances. * Can be used for debugging or lifecycle management. * * @returns Iterable iterator of all stored provider values. */ getInstances() { return this.providers.values(); } }; // src/di/module-wrapper.ts var ModuleWrapper = class { static { __name(this, "ModuleWrapper"); } type; metadata; /** * Modules imported by this module. */ _imports = /* @__PURE__ */ new Set(); /** * Controller classes declared in this module. */ _controllers = /* @__PURE__ */ new Set(); /** * Tokens exported by this module for other modules to consume. */ _exports = /* @__PURE__ */ new Set(); /** * The DI container instance scoped to this module. * Initially holds provider definitions, later replaced with their instantiated values. */ container = new Container(); /** * Creates a new ModuleWrapper. * * @param type The module’s class constructor. * @param metadata The metadata extracted from the @Module decorator, including * imports, controllers, providers, and exports. */ constructor(type, metadata) { this.type = type; this.metadata = metadata; metadata.controllers?.forEach((c) => this._controllers.add(c)); metadata.exports?.forEach((e) => this._exports.add(e)); metadata.providers?.forEach((p) => { const token = this.getTokenFromProvider(p); this.container.register(token, p); }); } /** * Gets the set of modules imported by this module. */ get imports() { return this._imports; } /** * Gets the set of controller classes declared in this module. */ get controllers() { return this._controllers; } /** * Gets the set of tokens this module exports. */ get exports() { return this._exports; } /** * Adds an imported module to this module’s import graph. * * @param importedModule The ModuleWrapper instance to import. */ addImport(importedModule) { this._imports.add(importedModule); } /** * Determines the DI token for a provider definition. * If the provider is a class constructor, the constructor itself is the token; * otherwise uses the `provide` property of the Provider object. * * @param provider The provider definition (class or object). * @returns The token under which this provider is registered. */ getTokenFromProvider(provider) { return typeof provider === "function" ? provider : provider.provide; } }; // src/enums/event-type.enum.ts var EventType = /* @__PURE__ */ function(EventType2) { EventType2["ON"] = "on"; EventType2["ON_CLIENT"] = "onClient"; EventType2["ON_SERVER"] = "onServer"; return EventType2; }({}); // src/enums/method-param-type.enum.ts var MethodParamType = /* @__PURE__ */ function(MethodParamType2) { MethodParamType2["PAYLOAD"] = "payload"; MethodParamType2["PARAM"] = "param"; MethodParamType2["PLAYER"] = "player"; return MethodParamType2; }({}); // src/enums/rpc-type.enum.ts var RpcType = /* @__PURE__ */ function(RpcType2) { RpcType2["ON_CLIENT"] = "onClientRpc"; RpcType2["ON_SERVER"] = "onServerRpc"; return RpcType2; }({}); // src/enums/scope.enum.ts var Scope = /* @__PURE__ */ function(Scope2) { Scope2[Scope2["SINGLETON"] = 0] = "SINGLETON"; Scope2[Scope2["TRANSIENT"] = 1] = "TRANSIENT"; return Scope2; }({}); // src/enums/webview-events.enum.ts var WebViewEvents = /* @__PURE__ */ function(WebViewEvents2) { WebViewEvents2["DISPATCH"] = "aurora:webview:dispatch"; WebViewEvents2["EMIT_SERVER"] = "aurora:webview:emitServer"; WebViewEvents2["INVOKE_SERVER_RPC"] = "aurora:webview:invokeServerRpc"; return WebViewEvents2; }({}); // src/utils/provider-utils.ts function normalizeProvider(provider) { if (typeof provider === "function") { return { provide: provider, useClass: provider }; } if ("useFactory" in provider && provider.useFactory) { const fp = { provide: provider.provide, useFactory: provider.useFactory, inject: provider.inject ?? [] }; if (provider.scope !== void 0) { fp.scope = provider.scope; } return fp; } if ("useValue" in provider && provider.useValue !== void 0) { const vp = { provide: provider.provide, useValue: provider.useValue }; if (provider.scope !== void 0) { vp.scope = provider.scope; } return vp; } if ("useClass" in provider && provider.useClass) { const cp = { provide: provider.provide, useClass: provider.useClass }; if (provider.scope !== void 0) { cp.scope = provider.scope; } return cp; } throw new Error(`[Aurora] Invalid provider configuration for token "${String(provider.provide)}"`); } __name(normalizeProvider, "normalizeProvider"); function getProviderScope(provider) { const norm = normalizeProvider(provider); if ("useFactory" in norm) { return norm.scope ?? Scope.SINGLETON; } let ctor; if ("useClass" in norm) { ctor = norm.useClass; } else if ("useValue" in norm) { ctor = norm.useValue.constructor; } if (ctor) { const meta = Reflect.getMetadata(INJECTABLE_SCOPE_OPTIONS, ctor); return meta ?? Scope.SINGLETON; } return Scope.SINGLETON; } __name(getProviderScope, "getProviderScope"); // src/utils/token-utils.ts function getTokenName(token) { return typeof token === "function" ? token.name : String(token); } __name(getTokenName, "getTokenName"); function tokenToString(token) { if (typeof token === "function") { return token.name; } if (typeof token === "symbol") { return token.toString(); } if (token && typeof token === "object") { if ("provide" in token) { return tokenToString(token.provide); } if ("useClass" in token) { return `[useClass: ${tokenToString(token.useClass)}]`; } if ("useValue" in token) { return `[useValue: ${typeof token.useValue}]`; } if ("useFactory" in token) { const name = token.useFactory.name || "<anonymous>"; return `[useFactory: ${name}]`; } } return String(token); } __name(tokenToString, "tokenToString"); // src/bootstrap/controller-flow.handler.ts var ControllerFlowHandler = class { static { __name(this, "ControllerFlowHandler"); } container; logger = console; constructor(container) { this.container = container; } setLogger(logger) { this.logger = logger; } /** * Maps the ExecutionContext to an array of arguments for the controller method. * @param context The current execution context containing raw arguments. * @param event Metadata for the event handler including parameter definitions. * @returns An array of arguments to apply to the controller method. */ createArgs(context, handler) { if (!handler.params?.length) { return context.args; } const sorted = [ ...handler.params ].sort((a, b) => a.index - b.index); const rawArgs = context.args; const args = []; for (const param of sorted) { let value; switch (param.type) { case MethodParamType.PLAYER: value = param.data ? rawArgs[0]?.[param.data] : rawArgs[0]; break; case MethodParamType.PAYLOAD: let rawPayload = rawArgs[1]; if (typeof rawPayload === "string") { try { rawPayload = JSON.parse(rawPayload); } catch { } } if (rawPayload != null && typeof rawPayload === "object") { value = param.data ? rawPayload[param.data] : rawPayload; } else { value = rawArgs.slice(1); } break; case MethodParamType.PARAM: const obj = rawArgs[1]; if (obj != null && typeof obj === "object") { value = obj?.[param.data]; } else { value = rawArgs[param.index]; } break; default: throw new Error(`Unknown parameter type ${param.type}`); } args[param.index] = value; } return args; } async canActivate(context) { const targetClass = context.getClass(); const handler = context.getHandler(); const classGuards = Reflect.getMetadata(GUARDS_METADATA_KEY, targetClass) || []; const methodGuards = Reflect.getMetadata(GUARDS_METADATA_KEY, targetClass.prototype, handler.name) || []; const allGuards = [ ...classGuards, ...methodGuards ]; for (const guard of allGuards) { const instance = this.container.resolve(guard); const allowed = await instance.canActivate(context); if (!allowed) { this.logger.debug(`[Aurora] Access denied by ${guard.name} on ${targetClass.name}.${handler.name}`); return false; } this.logger.debug(`[Aurora] Guard ${guard.name} granted access.`); } return true; } wrapWithGuardsProxy(instance, targetClass) { const methodNames = Object.getOwnPropertyNames(targetClass.prototype).filter((name) => name !== "constructor" && typeof instance[name] === "function"); return new Proxy(instance, { get: /* @__PURE__ */ __name((obj, prop, receiver) => { if (typeof prop !== "string" || !methodNames.includes(prop)) { return Reflect.get(obj, prop, receiver); } const original = Reflect.get(obj, prop, receiver); return async (...args) => { const ctx = { name: `${targetClass.name}.${prop}`, args, payload: args[1] ?? args[0], player: args[0], getClass: /* @__PURE__ */ __name(() => targetClass, "getClass"), getHandler: /* @__PURE__ */ __name(() => targetClass.prototype[prop], "getHandler"), getPlayer: /* @__PURE__ */ __name(() => args[0], "getPlayer") }; if (!await this.canActivate(ctx)) { this.logger.warn(`[Aurora] Access denied to ${ctx.name}`); return; } return original.apply(obj, args); }; }, "get") }); } hasGuards(targetClass) { const proto = targetClass.prototype; const classGuards = Reflect.getMetadata(GUARDS_METADATA_KEY, targetClass) || []; if (classGuards.length) return true; return Object.getOwnPropertyNames(proto).some((m) => m !== "constructor" && (Reflect.getMetadata(GUARDS_METADATA_KEY, proto, m) || []).length > 0); } }; // src/bootstrap/event-binder.ts var EventBinder = class { static { __name(this, "EventBinder"); } platformDriver; flowHandler; constructor(platformDriver, flowHandler) { this.platformDriver = platformDriver; this.flowHandler = flowHandler; } /** * Binds all controller event handlers for a given set of modules/controllers. * @param controllersWithInstances Array of [ControllerClass, controllerInstance] */ bindControllerEvents(controllersWithInstances) { for (const [controllerType, controllerInstance] of controllersWithInstances) { const eventHandlers = Reflect.getMetadata(CONTROLLER_EVENTS_KEY, controllerType) || []; for (const handler of eventHandlers) { const params = Reflect.getOwnMetadata(CONTROLLER_PARAMS_KEY, controllerType.prototype, handler.methodName) ?? []; handler.params = params; const guards = Reflect.getOwnMetadata(GUARDS_METADATA_KEY, controllerType.prototype, handler.methodName) ?? []; handler.guards = guards; const dispatcher = this.createDispatcher(controllerInstance, handler); switch (handler.type) { case EventType.ON: this.platformDriver.on(handler.name, dispatcher); break; case EventType.ON_CLIENT: if (this.platformDriver.onClient) this.platformDriver.onClient(handler.name, dispatcher); break; case EventType.ON_SERVER: if (this.platformDriver.onServer) this.platformDriver.onServer(handler.name, dispatcher); break; } } } } /** * Creates a dispatcher for the event handler method (param injection). */ createDispatcher(instance, handler) { return async (...args) => { try { const context = { name: handler.name, args, payload: args, player: handler.type === EventType.ON_CLIENT ? args[0] : void 0, getClass: /* @__PURE__ */ __name(() => instance.constructor, "getClass"), getHandler: /* @__PURE__ */ __name(() => instance[handler.methodName], "getHandler"), getPlayer: /* @__PURE__ */ __name(() => args[0], "getPlayer") }; const allowed = await this.flowHandler.canActivate(context); if (!allowed) { console.warn(`[Aurora] Access denied for event "${handler.name}"`); return; } const methodArgs = this.flowHandler.createArgs(context, handler); await instance[handler.methodName](...methodArgs); } catch (error) { console.error(`[Aurora] Error handling event "${handler.name}" on "${instance.constructor.name}"`, error); } }; } }; // src/bootstrap/rpc-binder.ts var RpcBinder = class { static { __name(this, "RpcBinder"); } platformDriver; flowHandler; constructor(platformDriver, flowHandler) { this.platformDriver = platformDriver; this.flowHandler = flowHandler; } bindControllerRpcs(controllers) { for (const [controllerType, controllerInstance] of controllers) { const rpcs = Reflect.getMetadata(CONTROLLER_RPCS_KEY, controllerType) || []; for (const rpc of rpcs) { const params = Reflect.getOwnMetadata(CONTROLLER_PARAMS_KEY, controllerType.prototype, rpc.methodName) || []; rpc.params = params; const guards = Reflect.getOwnMetadata(GUARDS_METADATA_KEY, controllerType.prototype, rpc.methodName) ?? []; rpc.guards = guards; const dispatcher = this.createDispatcher(controllerInstance, rpc); switch (rpc.type) { case RpcType.ON_CLIENT: if (this.platformDriver.onRpcServer) this.platformDriver.onRpcServer(rpc.name, dispatcher); break; case RpcType.ON_SERVER: if (this.platformDriver.onRpcClient) this.platformDriver.onRpcClient(rpc.name, dispatcher); break; } } } } createDispatcher(instance, rpc) { return async (...args) => { try { const context = { name: rpc.name, args, payload: args, // TODO: player: handler.type === EventType.ON_CLIENT ? args[0] : undefined, getClass: /* @__PURE__ */ __name(() => instance.constructor, "getClass"), getHandler: /* @__PURE__ */ __name(() => instance[rpc.methodName], "getHandler"), getPlayer: /* @__PURE__ */ __name(() => args[0], "getPlayer") }; const allowed = await this.flowHandler.canActivate(context); if (!allowed) { console.warn(`[Aurora] Access denied for RPC "${rpc.name}"`); return; } const methodArgs = this.flowHandler.createArgs(context, rpc); return await instance[rpc.methodName](...methodArgs); } catch (error) { console.error(`[AuroraDI] Error handling RPC "${rpc.name}" on "${instance.constructor.name}"`, error); } }; } }; // src/bootstrap/application.factory.ts var ApplicationFactory = class _ApplicationFactory { static { __name(this, "ApplicationFactory"); } platformDriver; applicationRef; moduleWrappers = /* @__PURE__ */ new Map(); globalModules = /* @__PURE__ */ new Set(); instanceContainer = new Container(); flowHandler; eventBinder; rpcBinder; plugins = []; logger = console; config; started = false; closed = false; debug = false; /** * @param platformDriver The platform driver for event binding/runtime APIs. * @internal */ constructor(platformDriver) { this.platformDriver = platformDriver; this.instanceContainer.register(PLATFORM_DRIVER, this.platformDriver); this.flowHandler = new ControllerFlowHandler(this.instanceContainer); this.eventBinder = new EventBinder(platformDriver, this.flowHandler); this.rpcBinder = new RpcBinder(platformDriver, this.flowHandler); this.applicationRef = { start: this.start.bind(this), get: this.get.bind(this), close: this.close.bind(this), usePlugins: this.usePlugins.bind(this) }; } /** * Bootstraps an Aurora application and returns its public interface. * @param rootModule The application's root module (entry point) * @param platformDriver The platform driver for this runtime * @returns A Promise resolving to the IApplication instance */ static async create(rootModule, platformDriver, plugins = []) { const factory = new _ApplicationFactory(platformDriver); factory.usePlugins(...plugins); await factory.initialize(rootModule); return factory.applicationRef; } usePlugins(...plugins) { this.plugins.push(...plugins); return this; } /** * Starts the application and binds all controller event handlers. */ async start() { if (this.started) { this.logger.warn("[Aurora] Application already started."); return; } this.started = true; this.logger.info("[Aurora] Starting application, binding events and rpcs."); this.bindControllerEvents(); this.bindControllerRpcs(); for (const plugin of this.plugins) { if (plugin.onBootstrap) { await plugin.onBootstrap(this.applicationRef); } } await this.callLifecycle("onAppStarted"); this.registerShutdownListeners(); this.logger.info("[Aurora] Application started, listening for events and rpcs."); } /** * Shuts down the application and calls shutdown hooks. */ async close(signal) { if (this.closed) { this.logger.warn("[Aurora] Application already closed."); return; } this.closed = true; this.logger.info(`[Aurora] Closing application (signal: ${signal})`); await this.callLifecycle("onAppShutdown", signal); this.logger.info("[Aurora] Application closed"); } /** * Resolves an instance from the DI container. * @param token The provider token or class */ async get(token) { if (!this.instanceContainer.has(token)) { throw new Error(`[Aurora] Provider for token "${getTokenName(token)}" could not be found in the application context.`); } return this.instanceContainer.resolve(token); } /** * Binds all controller events (decorated handlers) to the platform driver via EventBinder. */ bindControllerEvents() { const controllersWithInstances = []; for (const module of this.moduleWrappers.values()) { for (const controllerType of module.controllers) { controllersWithInstances.push([ controllerType, this.instanceContainer.resolve(controllerType) ]); } } this.eventBinder.bindControllerEvents(controllersWithInstances); } bindControllerRpcs() { const controllersWithInstances = []; for (const module of this.moduleWrappers.values()) { for (const controllerType of module.controllers) { controllersWithInstances.push([ controllerType, this.instanceContainer.resolve(controllerType) ]); } } this.rpcBinder.bindControllerRpcs(controllersWithInstances); } /** * Internal bootstrap: scans modules, builds the graph, and triggers instantiation. * @param rootModuleType The root module class */ async initialize(rootModuleType) { await this.scanModules(rootModuleType); const rootModule = this.moduleWrappers.get(rootModuleType); await this.initializeCoreServices(rootModule); console.dir(this.plugins); for (const plugin of this.plugins) { if (plugin.onInit) { await plugin.onInit(this.applicationRef); } } if (this.debug) { this.logModulesTree(); } await this.instantiateModules(); await this.callLifecycle("onAppInit"); this.logger.info("[Aurora] Application initialized successfully."); } // TODO registerShutdownListeners() { } /** * Recursively scans all modules, handles imports/exports and registers global modules. */ async scanModules(moduleType, seen = /* @__PURE__ */ new Set()) { if (seen.has(moduleType)) { throw new Error(`[Aurora] Circular dependency detected in module imports: ${moduleType.name} is part of a cycle.`); } seen.add(moduleType); if (this.moduleWrappers.has(moduleType)) { return this.moduleWrappers.get(moduleType); } const metadata = Reflect.getMetadata(MODULE_METADATA_KEY, moduleType); if (!metadata) throw new Error(`[Aurora] Class ${moduleType.name} is not a valid module. Did you forget @Module()?`); const moduleWrapper = new ModuleWrapper(moduleType, metadata); this.moduleWrappers.set(moduleType, moduleWrapper); if (Reflect.getMetadata(GLOBAL_MODULE_KEY, moduleType)) { this.globalModules.add(moduleWrapper); } for (const importedType of metadata.imports ?? []) { const importedModuleWrapper = await this.scanModules(importedType, new Set(seen)); moduleWrapper.addImport(importedModuleWrapper); } return moduleWrapper; } /** * Eagerly instantiates and assigns core services like Logger and Config. */ async initializeCoreServices(rootModule) { if (this.findModuleByProvider(CONFIG_SERVICE, rootModule)) { try { this.config = await this.resolveDependency(CONFIG_SERVICE, rootModule); this.debug = this.config.get("DEBUG", false); } catch { this.logger.warn(`[Aurora] CONFIG_SERVICE not found or failed to load. Debug logging will be disabled.`); } } try { this.logger = await this.resolveDependency(LOGGER_SERVICE, rootModule); } catch { this.logger.warn(`[Aurora] LOGGER_SERVICE not found. Falling back to console logging.`); } this.flowHandler.setLogger(this.logger); } /** * Prints the module graph in a tree format (debug/dev only). */ logModulesTree() { this.logger.debug("[Aurora] Modules tree"); for (const [type, wrapper] of this.moduleWrappers.entries()) { const meta = wrapper.metadata; this.logger.debug(`- ${type.name}${this.globalModules.has(wrapper) ? " [GLOBAL]" : ""}`); if (meta.imports?.length) this.logger.debug(` imports: ${meta.imports.map((x) => x.name).join(", ")}`); if (meta.exports?.length) this.logger.debug(` exports: ${meta.exports.map((x) => tokenToString(x)).join(", ")}`); if (meta.providers?.length) this.logger.debug(` providers: ${meta.providers.map((x) => tokenToString(x)).join(", ")}`); if (meta.controllers?.length) this.logger.debug(` controllers: ${meta.controllers.map((x) => x.name).join(", ")}`); } this.logger.debug("[Aurora] End tree\n"); } async callLifecycle(hook, ...args) { for (const wrapper of this.moduleWrappers.values()) { for (const ctrlType of wrapper.controllers) { const instance = this.instanceContainer.resolve(ctrlType); const fn = instance[hook]; if (typeof fn === "function") { this.logger.debug(`[Aurora] Calling ${hook} on ${ctrlType.name}.`); await fn.apply(instance, args); } } } } /** * Instantiate all providers first, then all controllers. */ async instantiateModules() { for (const moduleWrapper of this.moduleWrappers.values()) { for (const providerDef of moduleWrapper.metadata.providers ?? []) { const { provide } = normalizeProvider(providerDef); await this.resolveDependency(provide, moduleWrapper); } for (const controller of moduleWrapper.controllers) { await this.resolveDependency(controller, moduleWrapper); } } } /** * Create an instance of the given class, resolving and injecting both * constructor-parameter tokens and decorated property tokens. * * @param targetClass The class to instantiate. * @param contextModule The module wrapper providing the DI context. * @returns A Promise resolving to a new instance with all dependencies injected. */ async instantiateClass(targetClass, contextModule) { const paramTypes = Reflect.getMetadata("design:paramtypes", targetClass) || []; const customTokens = Reflect.getOwnMetadata(INJECT_TOKEN_KEY, targetClass) || []; const dependencies = await Promise.all(paramTypes.map(async (paramType, index) => { const token = customTokens[index] || paramType; if (!token) { throw new Error(`[Aurora] Could not resolve dependency for ${targetClass.name} at constructor index ${index}.`); } return this.resolveDependency(token, contextModule); })); const instance = new targetClass(...dependencies); const propsToInject = []; let ctor = targetClass; while (ctor && ctor !== Function.prototype) { const ownProps = Reflect.getOwnMetadata(INJECT_PROPERTY_KEY, ctor); if (ownProps) { propsToInject.push(...ownProps); } ctor = Object.getPrototypeOf(ctor); } for (const { key, token } of propsToInject) { instance[key] = await this.resolveDependency(token, contextModule); } if (this.flowHandler.hasGuards(targetClass)) { return this.flowHandler.wrapWithGuardsProxy(instance, targetClass); } return instance; } /** * Resolves a provider (controller/service) in the DI graph, including global modules. * @param token The token/class to resolve * @param contextModule The module to start searching from * @param seen (Cycle detection) */ async resolveDependency(token, contextModule, seen = /* @__PURE__ */ new Set()) { if (this.instanceContainer.has(token)) { return this.instanceContainer.resolve(token); } if (seen.has(token)) { throw new Error(`[Aurora] Circular dependency detected for token "${getTokenName(token)}".`); } seen.add(token); const destinationModule = this.findModuleByProvider(token, contextModule); if (!destinationModule) { throw new Error(`[AuroraDI] Cannot resolve dependency for token "${getTokenName(token)}"`); } const providerDef = this.findProviderDefinition(token, destinationModule); if (!providerDef) { throw new Error(`[AuroraDI] Cannot resolve dependency for token "${getTokenName(token)}"`); } const normalized = normalizeProvider(providerDef); const scope = getProviderScope(providerDef); if ("useValue" in normalized && normalized.useValue !== void 0) { this.instanceContainer.register(token, normalized.useValue); return normalized.useValue; } if ("useFactory" in normalized && normalized.useFactory) { const args = await Promise.all((normalized.inject ?? []).map(async ({ token: inj, optional }) => { try { return await this.resolveDependency(inj, destinationModule, seen); } catch (err) { if (optional) { return void 0; } throw err; } })); const result = await normalized.useFactory(...args); if (scope === Scope.SINGLETON) { this.instanceContainer.register(token, result); } return result; } if ("useClass" in normalized && normalized.useClass) { const instance = await this.instantiateClass(normalized.useClass, destinationModule); if (scope === Scope.SINGLETON) { this.instanceContainer.register(token, instance); } return instance; } throw new Error(`[AuroraDI] Cannot resolve dependency for token "${getTokenName(token)}"`); } /** * Finds the module able to provide the given token. * 1. Current module (providers/controllers) * 2. Imported modules (recursive, if they export the token) * 3. All global modules (@Global) */ findModuleByProvider(token, contextModule) { if (this.findProviderDefinition(token, contextModule)) { return contextModule; } for (const imported of contextModule.imports) { if (imported.exports.has(token)) { const found = this.findModuleByProvider(token, imported); if (found) { return found; } } } for (const globalMod of this.globalModules) { if (globalMod.exports.has(token) && this.findProviderDefinition(token, globalMod)) { return globalMod; } } return void 0; } /** * Finds a provider definition for a token in a given module, including controllers. */ findProviderDefinition(token, moduleWrapper) { if (moduleWrapper.controllers.has(token)) { return token; } return moduleWrapper.metadata.providers?.find((provider) => { const normalized = normalizeProvider(provider); return normalized.provide === token; }); } }; // src/decorators/events/create-event-decorator.ts function createEventDecorator(type, name, webViewId) { return (target, methodKey) => { const eventName = name ?? methodKey; const existingEvents = Reflect.getOwnMetadata(CONTROLLER_EVENTS_KEY, target.constructor) ?? []; if (existingEvents.some((e) => e.methodName === methodKey)) { throw new Error(`Cannot apply multiple event decorators to the same method "${String(methodKey)}".`); } const updatedEvents = [ ...existingEvents, { type, name: eventName, methodName: methodKey, params: [], ...webViewId !== void 0 ? { webViewId } : {} } ]; Reflect.defineMetadata(CONTROLLER_EVENTS_KEY, updatedEvents, target.constructor); }; } __name(createEventDecorator, "createEventDecorator"); // src/decorators/events/on.decorator.ts function On(eventName) { return createEventDecorator(EventType.ON, eventName); } __name(On, "On"); // src/decorators/params/create-param-decorator.ts function createParamDecorator(type) { return (data) => { return (target, propertyKey, parameterIndex) => { if (!propertyKey) { return; } const paramTypes = Reflect.getOwnMetadata("design:paramtypes", target, propertyKey) || []; const existingParams = Reflect.getOwnMetadata(CONTROLLER_PARAMS_KEY, target, propertyKey) ?? []; existingParams.push({ index: parameterIndex, type, data, metatype: paramTypes[parameterIndex], method: propertyKey.toString() }); Reflect.defineMetadata(CONTROLLER_PARAMS_KEY, existingParams, target, propertyKey); }; }; } __name(createParamDecorator, "createParamDecorator"); // src/decorators/params/param.decorator.ts var Param = createParamDecorator(MethodParamType.PARAM); // src/decorators/params/payload.decorator.ts var Payload = createParamDecorator(MethodParamType.PAYLOAD); // src/decorators/params/player.decorator.ts var Player = createParamDecorator(MethodParamType.PLAYER); // src/decorators/rpc/create-rpc-decorator.ts function createRpcDecorator(type, name, webViewId) { return (target, methodKey) => { const rpcName = name ?? methodKey; const existingRpcs = Reflect.getOwnMetadata(CONTROLLER_RPCS_KEY, target.constructor) ?? []; const updatedRpcs = [ ...existingRpcs, { type, name: rpcName, methodName: methodKey, params: [], ...webViewId !== void 0 ? { webViewId } : {} } ]; Reflect.defineMetadata(CONTROLLER_RPCS_KEY, updatedRpcs, target.constructor); }; } __name(createRpcDecorator, "createRpcDecorator"); // src/decorators/controller.decorator.ts function Controller() { return (target) => { if (Reflect.hasOwnMetadata(CONTROLLER_METADATA_KEY, target)) { throw new Error(`Cannot apply @Controller decorator multiple times on the same target (${target.name}).`); } Reflect.defineMetadata(CONTROLLER_METADATA_KEY, true, target); }; } __name(Controller, "Controller"); // src/decorators/global.decorator.ts function Global() { return (target) => { if (Reflect.hasOwnMetadata(GLOBAL_MODULE_KEY, target)) { throw new Error(`Cannot apply @Global decorator multiple times on the same target (${target.name}).`); } Reflect.defineMetadata(GLOBAL_MODULE_KEY, true, target); }; } __name(Global, "Global"); // src/decorators/inject.decorator.ts function Inject(token) { const decoratorFn = /* @__PURE__ */ __name((target, propertyKey, parameterIndex) => { if (typeof parameterIndex === "number") { const existingParams = Reflect.getOwnMetadata(INJECT_TOKEN_KEY, target) || []; existingParams[parameterIndex] = token; Reflect.defineMetadata(INJECT_TOKEN_KEY, existingParams, target); } else { const ctor = target.constructor; const existingProps = Reflect.getOwnMetadata(INJECT_PROPERTY_KEY, ctor) || []; existingProps.push({ key: propertyKey, token }); Reflect.defineMetadata(INJECT_PROPERTY_KEY, existingProps, ctor); } }, "decoratorFn"); return decoratorFn; } __name(Inject, "Inject"); // src/decorators/injectable.decorator.ts function Injectable(options) { return (target) => { if (Reflect.hasOwnMetadata(INJECTABLE_METADATA_KEY, target)) { throw new Error(`Cannot apply @Injectable decorator multiple times on the same target (${target.name}).`); } Reflect.defineMetadata(INJECTABLE_METADATA_KEY, true, target); Reflect.defineMetadata(INJECTABLE_SCOPE_OPTIONS, options?.scope ?? Scope.SINGLETON, target); }; } __name(Injectable, "Injectable"); // src/decorators/module.decorator.ts var VALID_MODULE_KEYS = [ "imports", "controllers", "providers", "exports" ]; function Module(metadata) { return (target) => { if (Reflect.hasOwnMetadata(MODULE_METADATA_KEY, target)) { throw new Error(`Cannot apply @Module decorator multiple times on the same target (${target.name}).`); } for (const key in metadata) { if (!VALID_MODULE_KEYS.includes(key)) { throw new Error(`Invalid property '${key}' passed into the @Module metadata in ${target.name}.`); } } Reflect.defineMetadata(MODULE_METADATA_KEY, metadata, target); }; } __name(Module, "Module"); // src/decorators/set-metatadata.decorator.ts function SetMetadata(key, value) { return (target, propertyKey, _descriptor) => { Reflect.defineMetadata(key, value, target, propertyKey); }; } __name(SetMetadata, "SetMetadata"); // src/decorators/use-guards.decorator.ts function UseGuards(...guards) { return (target, propertyKey, descriptor) => { if (propertyKey && descriptor) { const existing = Reflect.getMetadata(GUARDS_METADATA_KEY, target, propertyKey) || []; Reflect.defineMetadata(GUARDS_METADATA_KEY, [ ...existing, ...guards ], target, propertyKey); } else { const existing = Reflect.getMetadata(GUARDS_METADATA_KEY, target) || []; Reflect.defineMetadata(GUARDS_METADATA_KEY, [ ...existing, ...guards ], target); } }; } __name(UseGuards, "UseGuards"); export { ApplicationFactory, CONFIG_LOADER, CONFIG_SERVICE, CONTROLLER_EVENTS_KEY, CONTROLLER_METADATA_KEY, CONTROLLER_PARAMS_KEY, CONTROLLER_RPCS_KEY, Container, Controller, ControllerFlowHandler, EVENT_HANDLER_KEY, EVENT_SERVICE, EventBinder, EventType, GLOBAL_MODULE_KEY, GUARDS_METADATA_KEY, Global, INJECTABLE_METADATA_KEY, INJECTABLE_SCOPE_OPTIONS, INJECT_PROPERTY_KEY, INJECT_TOKEN_KEY, Inject, Injectable, LOGGER_SERVICE, MODULE_METADATA_KEY, MethodParamType, Module, ModuleWrapper, On, PLATFORM_DRIVER, Param, Payload, Player, RPC_SERVICE, RpcType, Scope, SetMetadata, UseGuards, WEBVIEW_SERVICE, WebViewEvents, createEventDecorator, createParamDecorator, createRpcDecorator, getProviderScope, getTokenName, normalizeProvider, tokenToString };