/** * Internal helpers extracted from `serve()` to reduce its cyclomatic complexity. * These are implementation details — do not import from outside `src/server/`. * * @internal */ import { MetricsCollector } from '../observability/metrics.ts'; import { buildTLSOptions } from './authentication.ts'; import type { ServeOptions } from './index.ts'; import type { WebSocketData } from './json-rpc-websocket-runtime.ts'; import { createServerWebSocketHandlers } from './runtime/authentication-bridge.ts'; import type { ServerContext } from './runtime/context.ts'; import { type EventBroadcastingHandle } from './runtime/event-broadcasting.ts'; /** * Hard ceiling on the raw WebSocket frame size for every connection (worker * stream, `/watch`, token `/stream`, and JSON-RPC). Bun's default is 16 MiB; * this caps the frame at the transport layer before any JSON parse, so a * malicious peer cannot force a 16 MiB parse per message. A bounded 4 MiB parse * is not a CPU-burn, so this constant ceiling fully closes the DoS on its own. * * This is deliberately NOT derived from `payloadSize.maxBytes`. That option is * an application-level admission policy measured on the codec-encoded (msgpack) * byte length of the bare value, whereas `maxPayloadLength` bounds the raw * UTF-8 JSON frame (envelope plus JSON-serialized value) — different units. * Tightening the frame limit down to a smaller `payloadSize.maxBytes` would * reject legitimate frames whose value is within the admission cap (JSON and * envelope overhead inflate the frame past the msgpack value size) with an * opaque transport close instead of a clean `PayloadSizeExceededError`, across * every shared WebSocket endpoint — for no additional DoS protection. Value * size stays enforced by the post-parse admission check. * * @internal Exported only for test assertions. */ export declare const WEBSOCKET_MAX_PAYLOAD_BYTES: number; /** * @internal * * Warning emitted when a server starts with no authentication and no explicit * `unauthenticatedAccess` policy. Exported only for internal tests (see * `tests/auth-warning-filter.test.ts`) and not part of the public API surface. */ export declare const NO_AUTHENTICATION_WARNING = "[weft] WARNING: server started with NO authentication; all non-public operations are publicly accessible. Configure serve({ auth }) to lock down, or set unauthenticatedAccess: \"reject\" in production to fail closed."; export declare const MCP_ORIGIN_CONFIGURATION_WARNING = "[weft] WARNING: MCP HTTP transport is enabled without publicOrigin or trustedHosts. Cross-origin /mcp requests are rejected, and discovery routes that emit absolute URLs return 503. Configure serve({ publicOrigin: \"https://api.example.com\" }) or serve({ trustedHosts: [\"api.example.com\"] }) before exposing the server through a browser or reverse proxy."; /** * Clamp a user-supplied `workerReconnectGracePeriodMs` into `[0, 5_000]`. * Returns the 2000ms default when undefined or non-finite. */ export declare function clampWorkerReconnectGracePeriod(value: number | undefined): number; export declare function assertAuthenticationPosture(options: ServeOptions, environmentRequirement?: string | undefined): void; export declare function warnIfMcpOriginConfigurationMissing(options: ServeOptions): void; /** * A mutable holder for the Bun server instance. The `fetch` handler needs to * call back into the server (for WebSocket upgrades) but the server isn't * created until `Bun.serve()` is called. The holder is populated immediately * after `Bun.serve()` returns, before any requests can be handled. */ export type ServerHolder = { current: ReturnType | null; }; /** `ServeOptions` with `prometheusExporter` guaranteed present. */ export type ResolvedServeOptions = ServeOptions & { prometheusExporter: NonNullable; }; /** * Resolved network parameters plus the TLS config derived from auth options. * Extracted so `serve()` does not need ternaries for defaults or TLS. */ export type ResolvedNetworkConfig = { port: number; hostname: string; development: boolean; tlsOptions: ReturnType; serverOptions: ResolvedServeOptions; serverMetricsCollector: MetricsCollector; }; /** * Resolves all network configuration defaults and validates the auth config * synchronously so misconfigurations fail fast before `Bun.serve()` binds. */ export declare function resolveNetworkConfig(options: ServeOptions): ResolvedNetworkConfig; /** * Builds the initial `ServerContext` from resolved options. All mutable state * maps and the metrics collector are allocated here so `serve()` stays linear. * * Also starts startup task-ledger recovery (WFT-23) against the fully * constructed context before returning it. Recovery runs asynchronously — * this function itself stays synchronous, same as `serve()` — but its * outcome is captured into `context.taskLedgerRecovery.ready` immediately, * before any request can reach a gated entry point, rather than in a * separate call `serve()` makes later (as the retired `restoreInflightTasks` * required): starting it here minimizes the window between context * construction and recovery beginning. */ export declare function buildServerContext(options: ResolvedServeOptions, serverMetricsCollector: MetricsCollector): ServerContext; /** * Returns the `fetch` handler for `Bun.serve()`. The handler reads the server * instance from `serverHolder.current`, which is populated right after * `Bun.serve()` returns. This avoids a circular dependency between the server * reference and its own fetch callback. */ export declare function buildFetchHandler(serverHolder: ServerHolder, context: ServerContext, options: ResolvedServeOptions): (request: Request) => Promise; /** * Removes an operationId from the workflow→operations reverse index. * Module-scope so it does not contribute to `serve()`'s cyclomatic complexity. */ export declare function cleanupWorkflowIndex(context: ServerContext, operationId: string): void; /** * Assembles the `Bun.serve()` options object. Separating this avoids a * conditional spread (`...(tlsOptions ? { tls } : {})`) inside `serve()`. * * Sets a constant `maxPayloadLength` of `WEBSOCKET_MAX_PAYLOAD_BYTES` (4 MiB) * so Bun rejects oversized frames at the transport layer before any JSON parse * occurs. The cap is intentionally a fixed transport-safety ceiling, not * derived from `payloadSize.maxBytes` (see that constant's docs for why mixing * the raw-frame limit with the application value-size policy would cause false * rejections in the wrong unit). */ export declare function buildBunServeConfig(port: number, hostname: string, development: boolean, routes: Bun.Serve.Routes, tlsOptions: ReturnType, fetchHandler: (request: Request) => Promise, websocketCallbacks: ReturnType): Parameters>[0]; /** * Registers all `AsyncDisposableStack` entries and periodic intervals for a * running server. The stack disposes entries in reverse registration order so * the most-recently-registered item is torn down first. */ export declare function registerStackDisposers(stack: AsyncDisposableStack, context: ServerContext, options: ServeOptions, broadcastingHandle: EventBroadcastingHandle, onOperationCleanup: (operationId: string) => void): void;