import type { Server } from 'bun';
import './request-augmentation';
import { Router } from '@stacksjs/bun-router';
import type { ActionHandler, EnhancedRequest, Route, ServerOptions } from '@stacksjs/bun-router';
import type { ActionValidations, ValidationResult } from '@stacksjs/actions';
/**
 * Warn (once per process) when more than one @stacksjs/router module has loaded
 * (stacksjs/stacks#1975 / #1982). Routing still works — the route table and
 * request context are process-global singletons — but a duplicated install is
 * worth surfacing. Called at serve() boot. Returns whether a split was detected
 * so callers/tests can assert on it without capturing logs.
 */
export declare function warnOnMultipleRouterInstances(): boolean;
/**
 * Generate a full URL for a named route, like Laravel's route() helper.
 *
 * Validates path parameters at call time so a typo'd argument
 * (`url('user.post', { userId: 1 })` against `/users/{id}`) throws
 * immediately with a list of expected names instead of silently
 * producing a URL with `{id}` left literal in the path.
 *
 * @example
 * ```typescript
 * // Define a named route
 * route.get('/api/email/unsubscribe', 'Actions/UnsubscribeAction').name('email.unsubscribe')
 *
 * // Generate URL
 * url('email.unsubscribe', { token: 'abc-123' })
 * // → https://stacksjs.com/api/email/unsubscribe?token=abc-123
 *
 * // With path parameters
 * route.get('/users/{id}/posts/{postId}', handler).name('user.post')
 * url('user.post', { id: 42, postId: 7 })
 * // → https://stacksjs.com/users/42/posts/7
 * ```
 */
export declare function url(routeName: string, params?: Record<string, string | number>): string;
/**
 * List the placeholder names a named route expects — handy for
 * codegen/test cases and for detecting typos before runtime.
 */
export declare function routeParams(routeName: string): string[];
/**
 * Snapshot of the registered routes — `{ method, path, name? }` per
 * route. Used by `buddy route:list` and the dev-server startup banner.
 */
export declare function listRegisteredRoutes(): Array<{ method: string, path: string, name?: string }>;
/**
 * Clear the middleware cache (useful for hot-reload in development).
 *
 * `installMiddlewareHotReload()` will wire this up automatically when
 * called from the dev server — production should never invoke it.
 */
export declare function clearMiddlewareCache(): void;
/**
 * Watch `app/Middleware/` and `app/Middleware.ts` and invalidate the
 * cached middleware modules whenever a file changes. Intended for the
 * dev server only — calling this in production is a no-op (the
 * watcher handle is created but never fires anything user code cares
 * about). Returns a `disposer()` to stop watching.
 *
 * Without this hook, editing a middleware file in dev requires a
 * full server restart to see the change — the import map caches the
 * old version forever.
 */
export declare function installMiddlewareHotReload(): () => void;
/**
 * Resolve every middleware alias referenced by a registered route and
 * report the ones that don't load. `csrf` is always checked too — it's
 * auto-injected on unsafe methods even when no route lists it.
 *
 * Resolution is inherently lazy (`.middleware(name)` is a sync chainable
 * that just records a string; the alias map and middleware modules load
 * via async dynamic import), so a throw at literal registration time is
 * impossible. Calling this after all routes are registered — the end of
 * `importRoutes()` and the compiled-binary boot in core/server — IS
 * effectively registration-time validation. See stacksjs/stacks#1957.
 */
export declare function findUnresolvableRouteMiddleware(): Promise<Array<{ alias: string, routes: string[] }>>;
/**
 * Throw when any registered route references a middleware alias that
 * cannot be resolved. Fail-closed boot validation: a typo'd `auth` alias
 * must abort startup loudly, not serve the route unprotected (the
 * request-time guard in createMiddlewareHandler 500s as a backstop).
 */
export declare function assertRouteMiddlewareResolvable(): Promise<void>;
/**
 * Run an action's declarative `validations:` against the request.
 *
 * @internal Exported for regression coverage of path-param coercion
 * (stacksjs/stacks#1865). Production callers should rely on the
 * router's action-resolution path, which invokes this for you.
 */
export declare function validateActionInput(req: EnhancedRequest, validations: ActionValidations): Promise<ValidationResult>;
export declare function stream(source: ReadableStream | AsyncIterable<string | Uint8Array>, options?: StreamOptions): Response;
// Decorate the incoming request with the helpers the framework's middleware
// and actions assume are always available. Names follow Laravel's convention
// because that's the API surface Stacks userland expects.
export declare function enhanceRequest(req: EnhancedRequest): EnhancedRequest;
/**
 * Create a Stacks-enhanced router
 */
export declare function createStacksRouter(config?: StacksRouterConfig): StacksRouterInstance;
/**
 * Handle a server request through the router
 * This is the main entry point for the Stacks server
 */
export declare function serverResponse(request: Request, _body?: string): Promise<Response>;
// Export serve function that uses the default router
export declare function serve(options?: ServerOptions): Promise<Server<unknown>>;
export declare const route: StacksRouterInstance;
declare interface StacksRouterConfig {
  verbose?: boolean
  apiPrefix?: string
}
declare interface GroupOptions {
  prefix?: string
  middleware?: string | string[]
  apiResponse?: boolean
}
declare interface ResourceRouteOptions {
  only?: ResourceAction[]
  except?: ResourceAction[]
  middleware?: string | string[]
}
/**
 * Chainable route interface for middleware and naming support
 */
declare interface ChainableRoute {
  middleware: (name: string) => ChainableRoute
  name: (routeName: string) => ChainableRoute
  skipCsrf: () => ChainableRoute
  requireCsrf: () => ChainableRoute
  rateLimit: (max: number, window: 'second' | 'minute' | 'hour' | 'day' | number) => ChainableRoute
}
/**
 * Helper for streaming responses — wraps a `ReadableStream` or async
 * generator with the right headers for the chosen content type.
 *
 * Common shapes:
 *
 *   ```ts
 *   // Server-Sent Events
 *   return stream(async function* () {
 *     for await (const evt of source) yield `data: ${JSON.stringify(evt)}\n\n`
 *   }, { type: 'sse' })
 *
 *   // Chunked JSON (NDJSON) — one JSON object per line
 *   return stream(async function* () {
 *     for await (const row of rows) yield `${JSON.stringify(row)}\n`
 *   }, { type: 'ndjson' })
 *
 *   // Raw bytes — caller supplies a ReadableStream of Uint8Array chunks
 *   return stream(myReadable, { contentType: 'application/octet-stream' })
 *   ```
 *
 * The wrapper sets `Cache-Control: no-cache` and `Connection: keep-alive`
 * for SSE — the two headers a sane proxy / browser pair won't ignore — and
 * leaves backpressure / cancellation to the underlying stream.
 *
 * See stacksjs/stacks#1870 R-4.
 */
export declare interface StreamOptions {
  type?: 'sse' | 'ndjson'
  contentType?: string
  headers?: HeadersInit
  status?: number
}
export declare interface StacksRouterInstance {
  bunRouter: Router
  routes: Route[]
  get: (path: string, handler: StacksHandler) => ChainableRoute
  post: (path: string, handler: StacksHandler) => ChainableRoute
  put: (path: string, handler: StacksHandler) => ChainableRoute
  patch: (path: string, handler: StacksHandler) => ChainableRoute
  delete: (path: string, handler: StacksHandler) => ChainableRoute
  options: (path: string, handler: StacksHandler) => ChainableRoute
  group: (options: GroupOptions, callback: () => void | Promise<void>) => StacksRouterInstance | Promise<StacksRouterInstance>
  resource: (name: string, handler: string, options?: ResourceRouteOptions) => StacksRouterInstance
  match: (methods: string[], path: string, handler: StacksHandler) => ChainableRoute
  health: () => StacksRouterInstance
  use: (middleware: ActionHandler | ((req: EnhancedRequest, next: () => Promise<Response>) => Response | Promise<Response>)) => StacksRouterInstance
  register: (routePath: string, options?: { prefix?: string, middleware?: string | string[] }) => Promise<StacksRouterInstance>
  serve: (options?: ServerOptions) => Promise<Server<unknown>>
  handleRequest: (req: Request) => Promise<Response>
  getAllowedMethods: (pathname: string, domain?: string) => string[]
  importRoutes: () => Promise<void>
  loadDiscoveredRoutes: () => Promise<void>
}
declare type RouteHandlerFn = (_req: EnhancedRequest) => Response | Promise<Response>;
declare type StacksHandler = string | RouteHandlerFn;
declare type ResourceAction = 'index' | 'store' | 'show' | 'update' | 'destroy';
/**
 * FIFO-bounded Map. Wraps `Map` with a hard size cap; on overflow,
 * the oldest entry (Map insertion order) is evicted. Used for the
 * router's small framework-internal caches whose size is normally
 * bounded by action count, but which had no upper limit before —
 * tests that instantiate many short-lived routers would leak entries
 * across `createStacksRouter()` calls (stacksjs/stacks#1863 T-8).
 *
 * Insertion-order LRU is appropriate here because the access pattern
 * is "set once at action-load time, then many reads" — refreshing on
 * get would buy nothing since reads dominate.
 */
declare class BoundedMap<K, V> {
  constructor(max: number);
  get(key: K): V | undefined;
  has(key: K): boolean;
  set(key: K, value: V): this;
  delete(key: K): boolean;
  clear(): void;
  get size(): number;
}
