import { TekirServer } from './server/server'; import { App } from './app'; import { type ConfigStore } from '@tekir/config'; import { type Logger } from '@tekir/logger'; /** * The runtime environment the application is running in. * - `'web'`: HTTP server mode (default) * - `'console'`: CLI/artisan command mode * - `'test'`: test runner mode (NODE_ENV=test) */ export type Environment = 'web' | 'console' | 'test'; /** * Shape of `config/app.ts` for projects scaffolded with create-tekir-app. * All fields are optional, so apps can extend the object with their own keys * (for example `defaultLocale`, `timezone`, etc.) without losing autocomplete * on the framework-known fields. */ export interface AppConfig { /** Human-readable application name. */ name?: string; /** Application encryption key, used by sessions, signed cookies, JWTs. */ key?: string; /** HTTP port the server listens on. */ port?: number; /** * Network interface the server binds to. Defaults to `'0.0.0.0'` (all * interfaces). Set `'127.0.0.1'` to accept only local connections, or a * specific LAN/host address. Typically wired from an env var in * `config/app.ts`, e.g. `host: process.env.HOST ?? '0.0.0.0'`. */ host?: string; /** Alias for {@link host}, matching Bun.serve's option name. `host` wins if both are set. */ hostname?: string; /** Runtime environment label (`'production'`, `'development'`, etc.). */ env?: string; /** Override `tekir()`'s auto-detected runtime environment. */ environment?: Environment; /** Allow apps to add their own keys without losing type safety on the rest. */ [key: string]: unknown; } /** * Options passed to `app.start()` to configure server startup. * @example * app.start({ mode: 'production', callback: () => console.log('Ready!') }) * // or simply: * app.start(() => console.log('Server running')) */ export interface StartOptions { /** Force `'production'` or `'development'` mode regardless of env config. */ mode?: 'production' | 'development'; /** Callback executed after the server starts listening. */ callback?: () => void | Promise; /** * Bind the listener even when the process was launched via `tekir test` * (i.e. when `process.env.TEKIR_RUNNER === 'test'`). Off by default so * a user entry's top-level `app.start()` does not fight the test * runner; integration tests that need a real socket pass `true`. */ force?: boolean; } /** * Configuration options for creating a Tekir application via `tekir()`. * @example * const app = await tekir({ * appRoot: import.meta.dir, * config: { app: { port: 4000 } }, * middleware: [cors(), bodyParser()], * }) */ export interface TekirOptions { /** * Root directory of the application. When omitted, `tekir()` walks * the call stack to find the file that called it and uses its * `dirname`, falling back to `process.cwd()` only if no user frame * is recoverable. The auto-detection means most users do not need * to set this. `tekir()` from `admin/index.ts` resolves to the * `admin/` directory regardless of how the process was launched * (turbo from the repo root, pm2 from `/`, plain `bun run dev` from * any cwd). */ appRoot?: string; /** Override auto-detected environment (`'web'`, `'console'`, or `'test'`). */ environment?: Environment; /** Inline config object. Use instead of loading from `config/` directory. */ config?: Record; /** Service providers to register (class constructors or instances). */ providers?: (any | (new () => any))[]; /** Server-level middleware applied to every incoming request. */ middleware?: any[]; /** Router-level middleware applied only to matched routes. */ routerMiddleware?: any[]; /** * Inline route registration. Runs after providers boot, so services are * available. Methods on the passed router are pre-bound so destructuring * works. * @example * routes: ({ get, post }) => { * get('/health', () => ({ ok: true })) * post('/users', async ({ body }) => createUser(body)) * } */ routes?: (router: ReturnType) => void | Promise; /** * Path to an env-setup file (relative to `appRoot`, or absolute). Loaded * once at boot for its side effects. Skipped silently when the file does * not exist; never set, never scanned. */ envFile?: string; /** * Directory of config files (relative to `appRoot`, or absolute). Each * `*.{ts,js,mjs}` file is loaded into the config store. Skipped silently * when the directory does not exist; never set, never scanned. */ configDir?: string; /** * Directory containing `kernel.{ts,js,...}`, `routes.{ts,...}`, * `boot.{ts,...}`, `commands.{ts,...}` (relative to `appRoot`, or * absolute). Each file's default export is awaited with the booted * `TekirApp`. Skipped silently when the directory does not exist; never * set, never scanned. */ startDir?: string; /** Frontend framework integration (Vite, Next.js, or raw Bun). */ frontend?: { type: 'vite' | 'next' | 'bun'; [key: string]: any; }; } /** * The main application instance returned by `tekir()`. * Provides access to the HTTP server, router, logger, config, and lifecycle hooks. * * @example * const app = await tekir() * app.router.get('/hello', () => ({ message: 'Hello!' })) * app.start(() => console.log('Running')) */ export interface TekirApp { /** The IoC container holding all registered services. */ app: App; /** The underlying HTTP server instance. */ server: TekirServer; /** The application router for defining routes, groups, and resources. */ router: ReturnType; /** The application logger (pino-compatible). */ logger: Logger; /** Read a config value: `config('app.port', 3000)`. */ config: ConfigStore['get']; /** The detected runtime environment (`'web'`, `'console'`, or `'test'`). */ environment: Environment; /** Retrieve a registered service by name with type inference. */ service: (name: string) => T; /** Register a callback to run after `app.start()`. Returns `this` for chaining. */ onStart: (fn: () => void | Promise) => TekirApp; /** Register a callback to run on `app.shutdown()`. Returns `this` for chaining. */ onShutdown: (fn: () => void | Promise) => TekirApp; /** * Start the HTTP server. Accepts either a callback or a `StartOptions` object. * @example * app.start(() => console.log('Listening on port 3000')) * app.start({ mode: 'production' }) */ start: (options?: StartOptions | (() => void | Promise)) => void; shutdown: () => Promise; } /** * Create and boot a new Tekir application. Loads env, config, providers, * middleware, routes, and returns a ready-to-start `TekirApp` instance. * * @param options - Application configuration (root dir, inline config, providers, middleware, frontend). * @returns A fully configured `TekirApp`. Call `app.start()` to begin listening. * * @example * ```ts * import { tekir } from '@tekir/core' * * const app = await tekir({ appRoot: import.meta.dir }) * * app.router.get('/hello', () => ({ message: 'Hello World!' })) * * app.start(() => { * console.log(`Server running at http://localhost:${process.env.PORT || 3000}`) * }) * ``` */ export declare function tekir(options?: TekirOptions): Promise; export { getApp, getServer, getLogger, getRouter } from './container';