/**
 * Get the global app instance (stub for backwards compatibility)
 * Returns null in Vite-native architecture
 */
export function getApp() {
    return null;
}
// Re-export event functions from _events
export { fireEvent } from './_events';
/**
 * Create and start an Agentuity application.
 *
 * This is the single entry point for the entire server lifecycle:
 * OTel, middleware, route mounting, services, and Bun.serve().
 *
 * @example
 * ```typescript
 * import { createApp } from '@agentuity/runtime';
 * import router from './src/api/router';
 * import agents from './src/agent';
 *
 * export default await createApp({
 *   router: { path: '/api', router },
 *   agents,
 * });
 * ```
 */
export async function createApp(config) {
    // --- Imports (lazy to avoid circular deps) ---
    const { bootstrapRuntimeEnv } = await import('@agentuity/server');
    const { register } = await import('./otel/config');
    const { setGlobalLogger, setGlobalTracer, setGlobalRouter, getSpanProcessors } = await import('./_server');
    const { createServices, getThreadProvider, getSessionProvider } = await import('./_services');
    const { createBaseMiddleware, createCorsMiddleware, createOtelMiddleware, createCompressionMiddleware, } = await import('./middleware');
    const { runAgentSetups, createAgentMiddleware } = await import('./agent');
    const { loadBuildMetadata } = await import('./_metadata');
    const { patchBunS3ForStorageDev } = await import('./bun-s3-patch');
    const { createWorkbenchRouter } = await import('./workbench');
    const { isDevelopment, resolveAnalyticsConfig, resolveWorkbenchConfig, registerHealthRoutes, registerAnalyticsRoutes, registerWebRoutes, registerWorkbenchUI, startServer, } = await import('./bootstrap');
    const { websocket } = await import('hono/bun');
    // --- Step 0: Environment ---
    if (isDevelopment()) {
        bootstrapRuntimeEnv();
    }
    if (isDevelopment() && process.env.AGENTUITY_NO_BUNDLE === 'true') {
        const { applyDevPatches } = await import('./dev-patches');
        await applyDevPatches();
    }
    loadBuildMetadata();
    patchBunS3ForStorageDev();
    // --- Step 1: Telemetry ---
    const otel = register({
        processors: getSpanProcessors(),
        logLevel: (process.env.AGENTUITY_LOG_LEVEL || 'info'),
    });
    setGlobalLogger(otel.logger);
    setGlobalTracer(otel.tracer);
    // --- Step 1b: Version consistency check ---
    const { checkVersionConsistency } = await import('./version-check');
    checkVersionConsistency(otel.logger);
    // --- Step 2: Router + middleware ---
    const { createRouter } = await import('./router');
    const app = createRouter();
    setGlobalRouter(app);
    app.use('*', createCompressionMiddleware(config?.compression));
    app.use('*', createBaseMiddleware({
        logger: otel.logger,
        tracer: otel.tracer,
        meter: otel.meter,
    }));
    app.use('/_agentuity/workbench/*', createOtelMiddleware());
    // --- Step 3: Services ---
    const port = process.env.PORT || '3500';
    const serverUrl = `http://127.0.0.1:${port}`;
    createServices(otel.logger, config, serverUrl);
    const threadProvider = getThreadProvider();
    const sessionProvider = getSessionProvider();
    await threadProvider.initialize({});
    await sessionProvider.initialize({});
    // --- Step 4: Routes ---
    const analyticsConfig = resolveAnalyticsConfig(config?.analytics);
    const workbenchConfig = resolveWorkbenchConfig(config?.workbench);
    registerHealthRoutes(app);
    if (analyticsConfig.enabled) {
        registerAnalyticsRoutes(app, analyticsConfig);
    }
    // Mount user routers
    if (config?.router) {
        const mounts = normalizeRouterConfig(config.router);
        for (const mount of mounts) {
            const prefix = mount.path.endsWith('/') ? mount.path + '*' : mount.path + '/*';
            app.use(prefix, createCorsMiddleware(config?.cors));
            app.use(prefix, createOtelMiddleware());
            app.use(prefix, createAgentMiddleware(''));
            app.route(mount.path, mount.router);
        }
    }
    // Workbench
    const workbenchRouter = createWorkbenchRouter();
    app.route('/', workbenchRouter);
    registerWorkbenchUI(app, workbenchConfig);
    // Web (production static serving)
    registerWebRoutes(app, analyticsConfig);
    // --- Step 5: Agent lifecycle + server ---
    await runAgentSetups({});
    // In dev mode with --hot, Bun manages the server via the default export's
    // `fetch` property. In production, we start Bun.serve() explicitly.
    if (!isDevelopment()) {
        startServer(app, { requestTimeout: config?.requestTimeout });
    }
    // Only log on first startup, not on --hot reloads
    const { serverStarted } = await import('./_globals');
    if (!serverStarted.get()) {
        serverStarted.set(true);
        otel.logger.debug('Server listening on %s', serverUrl);
    }
    const portNumber = parseInt(port, 10);
    // Wrap the fetch handler to set request timeout.
    // In dev mode, Bun --hot auto-serves from the default export's `fetch` property.
    // Without this wrapper, Bun uses its default request timeout (10s), which is too
    // short for long-running agent requests (LLM calls, etc.). In v1, the generated
    // entry file called server.timeout(req, 0) inside Bun.serve(). In v2, we must do
    // the same here so dev mode requests don't time out prematurely.
    const requestTimeout = config?.requestTimeout ?? 0;
    const wrappedFetch = (req, ...args) => {
        const server = args[0];
        if (server && typeof server === 'object' && 'timeout' in server) {
            server.timeout(req, requestTimeout);
        }
        return app.fetch(req, ...args);
    };
    const result = {
        config,
        router: app,
        server: { url: serverUrl },
        logger: otel.logger,
        // Bun --hot picks up `fetch` and `port` on the default export to
        // hot-swap the running server's request handler without restarting.
        fetch: wrappedFetch,
        port: portNumber,
        hostname: '127.0.0.1',
        websocket,
    };
    // In production, startServer() already called Bun.serve(). If we leave
    // `fetch` + `port` on the default export, Bun v1.2+ auto-serves from it
    // too — causing EADDRINUSE. Strip those properties so only the explicit
    // Bun.serve() is active.
    if (!isDevelopment()) {
        delete result.fetch;
        delete result.port;
        delete result.hostname;
        delete result.websocket;
    }
    return result;
}
/**
 * Normalize the router config into a consistent RouteMount[] form.
 * - Plain Hono → [{ path: '/api', router }]
 * - { path, router } → [{ path, router }]
 * - [{ path, router }, ...] → as-is
 * @internal
 */
export function normalizeRouterConfig(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
router) {
    if (Array.isArray(router)) {
        return router;
    }
    if ('router' in router && 'path' in router) {
        return [router];
    }
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    return [{ path: '/api', router: router }];
}
/**
 * Gets the global shutdown hooks registry.
 */
function getShutdownHooks() {
    const key = Symbol.for('@agentuity/runtime:shutdown-hooks');
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const g = globalThis;
    if (!g[key]) {
        g[key] = [];
    }
    return g[key];
}
/**
 * Registers a shutdown hook to be called during graceful shutdown.
 *
 * Hooks are called in reverse order of registration (LIFO) after the
 * app's shutdown callback and agent shutdowns have completed.
 *
 * This is useful for packages like @agentuity/postgres to register
 * their own cleanup logic without requiring explicit wiring in each app.
 *
 * @param hook - The function to call during shutdown
 * @returns A function to unregister the hook
 *
 * @example
 * ```typescript
 * import { registerShutdownHook } from '@agentuity/runtime';
 *
 * // Register a cleanup function
 * const unregister = registerShutdownHook(async () => {
 *   await myResource.close();
 * });
 *
 * // Later, if needed, unregister it
 * unregister();
 * ```
 */
export function registerShutdownHook(hook) {
    const hooks = getShutdownHooks();
    hooks.push(hook);
    return () => {
        const index = hooks.indexOf(hook);
        if (index !== -1) {
            hooks.splice(index, 1);
        }
    };
}
/**
 * Run all registered shutdown hooks.
 * Called during graceful shutdown (SIGTERM/SIGINT).
 *
 * Hooks are called in reverse order of registration (LIFO).
 */
export async function runShutdown() {
    const hooks = getShutdownHooks();
    for (let i = hooks.length - 1; i >= 0; i--) {
        const hook = hooks[i];
        if (!hook)
            continue;
        try {
            await hook();
        }
        catch {
            // Ignore errors during shutdown hooks
        }
    }
}
//# sourceMappingURL=app.js.map