UNPKG

@beignet/core

Version:

Core framework primitives for Beignet

148 lines 5.92 kB
import type { HttpContractConfig } from "../contracts/index.js"; import type { AnyPorts, BoundGate, GatePort, PolicyDefinition } from "../ports/index.js"; import type { TraceContext } from "../tracing/index.js"; import type { HttpRequestLike, MaybePromise } from "./http.js"; import type { TrustedRequestInfo } from "./trusted-proxy.js"; /** * Arguments passed to the `context.request` factory after a route is matched. */ export type RequestContextArgs<Ports extends AnyPorts = AnyPorts> = { /** * Framework-neutral request. */ req: HttpRequestLike; /** * Request metadata resolved from the server's explicit trusted-proxy policy. * Forwarding headers never affect this value unless * `createServer({ trustedProxy })` opts into them. */ requestInfo: TrustedRequestInfo; /** * Final app ports, including ports contributed by providers. */ ports: Ports; /** * Matched contract, when the request resolved to a registered route. */ contract?: HttpContractConfig; /** * Request correlation ID resolved by the server from the configured request * ID header, or generated when the request did not send one. */ requestId: string; /** * W3C trace context resolved by the server from the incoming `traceparent` * header, or generated when the request did not send one. Spread this into * the context (`...trace`) to correlate downstream activity. */ trace: TraceContext; }; /** * Arguments passed to the `context.service` factory. */ export type ServiceContextArgs<Ports extends AnyPorts = AnyPorts, ServiceInput = void> = { /** * Final app ports, including ports contributed by providers. */ ports: Ports; /** * Caller-provided input such as the service actor or tenant. */ input: ServiceInput; /** * Fresh correlation ID generated for this service context. */ requestId: string; /** * Fresh W3C trace context generated for this service context. Spread this * into the context (`...trace`) to correlate downstream activity. */ trace: TraceContext; }; /** * App context without its `gate` property. * * Context factories return seeds; the server attaches the gate declared by * the blueprint's `gate` selector, so hand-binding `gate` in a factory is a * type error. */ export type ContextSeed<Ctx> = Omit<Ctx, "gate"> & { gate?: never; }; type ContextGateOption<Ctx, Ports extends AnyPorts> = [Ctx] extends [ { gate: BoundGate<infer TPolicies extends readonly PolicyDefinition[]>; } ] ? { /** * Select the gate port the server attaches to every context it builds. */ gate: (ports: Ports) => GatePort<ContextSeed<Ctx>, TPolicies>; } : { /** * Gate selection is only available when the context type declares a * `gate` property. */ gate?: never; }; /** * Context blueprint accepted by `createServer(...)`. * * The server owns context assembly: `request` and `service` return context * seeds, and the server attaches the gate declared by `gate` so identity * changes can never authorize against a stale context. */ export type ServerContextOptions<Ctx, Ports extends AnyPorts = AnyPorts, ServiceInput = void> = { /** * Build the per-request context seed. */ request: (args: RequestContextArgs<Ports>) => MaybePromise<ContextSeed<Ctx>>; /** * Build a service context seed for schedules, outbox drains, tasks, and * background work. Required before `server.createServiceContext(...)` can * be called. */ service?: (args: ServiceContextArgs<Ports, ServiceInput>) => MaybePromise<ContextSeed<Ctx>>; } & ContextGateOption<Ctx, Ports>; /** * Context configuration accepted by `createServer(...)`. * * Contexts without a `gate` property may use the plain request-factory * shorthand. Contexts with a `gate` must use the blueprint form so the server * owns gate attachment. */ export type ServerContextConfig<Ctx, Ports extends AnyPorts = AnyPorts, ServiceInput = void> = [Ctx] extends [{ gate: unknown; }] ? ServerContextOptions<Ctx, Ports, ServiceInput> : ((args: RequestContextArgs<Ports>) => MaybePromise<Ctx>) | ServerContextOptions<Ctx, Ports, ServiceInput>; /** * Argument tuple for `createServiceContext(...)`. * * Servers without a declared service input are callable with no arguments; * optional inputs stay optional at the call site. */ export type ServiceContextInputArgs<ServiceInput> = [ServiceInput] extends [ void ] ? [] : undefined extends ServiceInput ? [input?: ServiceInput] : [input: ServiceInput]; type AnyGateSelector<Ports extends AnyPorts> = (ports: Ports) => Pick<GatePort<unknown>, "attach">; /** * Normalized runtime view of a server context configuration. */ export type ResolvedServerContext<Ctx, Ports extends AnyPorts, ServiceInput> = { request: (args: RequestContextArgs<Ports>) => MaybePromise<ContextSeed<Ctx> | Ctx>; service?: (args: ServiceContextArgs<Ports, ServiceInput>) => MaybePromise<ContextSeed<Ctx>>; gate?: AnyGateSelector<Ports>; }; /** * Normalize a server context configuration into its runtime parts. */ export declare function resolveServerContext<Ctx, Ports extends AnyPorts, ServiceInput>(config: ServerContextConfig<Ctx, Ports, ServiceInput>): ResolvedServerContext<Ctx, Ports, ServiceInput>; /** * Create the context finalizer for a resolved server context. * * When the blueprint declares a gate, the finalizer strips hand-assigned * `gate` values from seeds and attaches the live gate. Without a gate * declaration the seed is the context. */ export declare function createContextFinalizer<Ctx, Ports extends AnyPorts, ServiceInput>(resolved: ResolvedServerContext<Ctx, Ports, ServiceInput>, getPorts: () => Ports): (seed: ContextSeed<Ctx> | Ctx) => Ctx; export {}; //# sourceMappingURL=context.d.ts.map