export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS'; export type Primitive = string | number | boolean | null; export type JsonValue = Primitive | JsonObject | JsonValue[]; export interface JsonObject { [key: string]: JsonValue; } /** Header values may be multi-valued (e.g. Set-Cookie). */ export type Headers = Record; export type Query = Record; export interface SimulatorRequest { method: HttpMethod; /** Pathname used for matching. Optional when `url` or `baseUrl` is provided. */ path?: string; /** * Absolute or relative URL. Absolute `http(s)://` URLs contribute pathname, * query, and Host. Relative values without `baseUrl` are treated as a path. */ url?: string; /** Resolve `path` (or relative `url`) against this origin, same as `new URL(path, baseUrl)`. */ baseUrl?: string; headers?: Headers; query?: Query; body?: TBody; } export interface MatchedSimulatorRequest extends SimulatorRequest { path: string; headers: Headers; query: Query; params: Record; } export interface SimulatorResponse { status?: number; headers?: Headers; body?: TBody; } export interface FixedBehavior { type: 'fixed'; response: SimulatorResponse; } export interface RelativeBehavior { type: 'relative'; response: SimulatorResponse; /** Throw when a token cannot be resolved. Defaults to true. */ strict?: boolean; } /** * Mutable bag shared across endpoints of one `ApiDefinition`. * Single-process only — no locks, not durable across restarts. */ export interface SimulationState { get(key: string): T | undefined; set(key: string, value: unknown): void; delete(key: string): boolean; snapshot(): Record; reset(): void; } export interface SimulationContext = Record> { apiId: string; endpointId: string; request: MatchedSimulatorRequest; data: Readonly; state: SimulationState; } export type SimulationFunction = Record, TBody = unknown> = (context: SimulationContext) => SimulatorResponse | Promise>; export interface SimulationBehavior = Record, TBody = unknown> { type: 'simulation'; handler: SimulationFunction; } /** * A discriminated union guarantees that every endpoint has exactly one behavior. */ export type EndpointBehavior = Record> = FixedBehavior | RelativeBehavior | SimulationBehavior; export type EndpointValidateResult = void | SimulatorResponse | Promise; export interface EndpointDefinition = Record> { id: string; method: HttpMethod; /** Express-style path, for example /parents/:parentId/children. Supports `:id(\\d+)` and `:id?`. */ path: string; behavior: EndpointBehavior; enabled?: boolean; /** Optional artificial latency for this endpoint. */ delayMs?: number; /** * Optional request/response gate. Runs after route match, before behavior. * Returning a SimulatorResponse short-circuits the behavior handler. */ validate?: (context: SimulationContext) => EndpointValidateResult; } export interface CorsOptions { origins: string[] | '*'; methods?: HttpMethod[]; headers?: string[]; maxAge?: number; } export interface ApiDefinition = Record> { id: string; /** Optional prefix, for example /crm/v1. */ basePath?: string; /** * Optional host matcher for multi-tenant routing. * Compared against the request `Host` header (hostname only, port stripped). */ host?: string | RegExp; data?: TData; endpoints: EndpointDefinition[]; /** When set, expands OPTIONS preflight routes and adds CORS headers on matches. */ cors?: CorsOptions; } export interface SimulatorDefinition { apis: ApiDefinition[]; } export interface SimulatorOptions { recordHistory?: boolean | { limit?: number; }; /** At construction, validate `{{data.*}}` tokens in relative templates. */ validateTemplates?: boolean; } export interface DispatchMatch { apiId: string; endpointId: string; request: MatchedSimulatorRequest; response: SimulatorResponse; } export interface ApiSimulator { dispatch(request: SimulatorRequest): Promise; tryDispatch(request: SimulatorRequest): Promise; listEndpoints(): Array<{ apiId: string; endpointId: string; method: HttpMethod; path: string; behaviorType: EndpointBehavior['type']; }>; getHistory(): readonly DispatchMatch[]; clearHistory(): void; /** Mutable state for one API. Throws if `apiId` is unknown. */ getState(apiId: string): SimulationState; /** Reset one API's state, or every API when `apiId` is omitted. */ resetState(apiId?: string): void; } //# sourceMappingURL=types.d.ts.map