import { C as CatalogCall, a as CatalogStream, S as ServiceCatalog, R as RemoteResolver, b as Server, c as CreateServerOptions, T as TLSOptions } from './types-BHxcLelB.js'; export { B as BidiStreamHandle, d as CallOptions, e as ClientStreamHandle, f as ConnectumCallMap, g as ConnectumMethodImpl, h as ConnectumServiceImpl, i as ConnectumStreamMap, j as Context, D as DnsResolverOptions, E as EventBusLike, H as HttpHandler, L as LifecycleEvent, N as NodeRequest, k as NodeResponse, P as PerServiceEnvResolverOptions, l as ProtocolContext, m as ProtocolRegistration, n as ResolverContext, o as ServerClientOptions, p as ServerState, q as ServiceDefinition, r as ServiceOptions, s as ShutdownHook, t as ShutdownOptions, u as StreamReturn, v as TransportServer, w as defineCatalog, x as defineLazyService, y as defineService, z as dnsResolver, A as mapResolver, F as mergeCatalogs, G as perServiceEnvResolver, I as singleTransportResolver } from './types-BHxcLelB.js'; import { Interceptor, Transport } from '@connectrpc/connect'; import { DescFile } from '@bufbuild/protobuf'; export { BooleanFromStringSchema, ConnectumEnv, ConnectumEnvSchema, LogFormatSchema, LogLevelSchema, LoggerBackendSchema, NodeEnvSchema, parseEnvConfig, safeParseEnvConfig } from './config/index.js'; import 'node:events'; import 'node:http'; import 'node:http2'; import 'node:net'; import 'zod'; /** * Catalog client — the catalog-typed `call`/`stream` surface usable OUTSIDE a * `Server`. * * In-handler `ctx.call`/`ctx.stream` give catalog-typed, resolver-routed * cross-service calls — but only where a {@link Context} exists, i.e. inside a * Connectum service handler. An out-of-process caller (a Temporal worker, a * scheduler, a CLI) has no `Server` and no `HandlerContext`, so it would * otherwise hand-build `createClient(Service, transport)` per service and lose * the service-catalog typing and the {@link RemoteResolver} wiring. * * {@link createCatalogClient} closes that gap: it produces the SAME typed `call` * (unary) and `stream` (server/client/bidi) surface as the handler `ctx`, keyed * off the generated {@link ConnectumCallMap}/{@link ConnectumStreamMap}, but * resolves every target purely through the supplied {@link RemoteResolver}. * There is no in-process/local path here (no `Server`, no mounted services), so * a service the resolver cannot resolve is a clear `ConnectError`. * * Cascade differences vs. `ctx.call` (there is no inbound request to cascade * from): `signal`/`timeoutMs`/`headers` are taken verbatim from * {@link CallOptions}; `timeoutMs` is NOT clamped (nothing to clamp against), * no inbound headers are propagated, and no `ContextValues` are forwarded. * * @module catalogClient */ /** * Options for {@link createCatalogClient}. */ interface CreateCatalogClientOptions { /** * The service catalog (a `Record`) that backs typed * dispatch — the same object passed to `createServer({ catalog })`. */ catalog: ServiceCatalog; /** * Maps a target service `typeName` to a ConnectRPC `Transport`. Required: * unlike a `Server`, a catalog client has no in-process/local path, so every * call is routed through the resolver. A resolver that returns `null` for a * target makes that call fail with `Code.Unavailable`. */ resolver: RemoteResolver; } /** * A standalone, catalog-typed client. Exposes the SAME `call` (unary) and * `stream` (server/client/bidi) surface as the handler {@link Context}, keyed * off {@link ConnectumCallMap}/{@link ConnectumStreamMap}, without constructing * a `Server`. */ interface CatalogClient { /** * Invoke a unary service in the catalog over the resolver-supplied * transport. With no augmentation of {@link ConnectumCallMap} this is * statically uncallable — exactly as on the handler `ctx`. * * Errors mirror `ctx.call`: no catalog / unknown service / unknown method / * wrong kind → `Code.FailedPrecondition`/`Code.Unimplemented`; resolver * returns `null` → `Code.Unavailable`; resolver throws → `Code.Internal` * (cause preserved). */ call: CatalogCall; /** * Open a streaming call to a service in the catalog over the * resolver-supplied transport. Returns the same kind-specific factory as * `ctx.stream` (server-streaming → `AsyncIterable`; client-/bidi-streaming → * push handles). */ stream: CatalogStream; } /** * Build a standalone {@link CatalogClient} from a {@link ServiceCatalog} and a * {@link RemoteResolver}. * * @example * ```ts * import { createCatalogClient, mapResolver } from "@connectum/core"; * import { serviceCatalog } from "./gen/catalog.ts"; // @connectum/protoc-gen-catalog * * const client = createCatalogClient({ * catalog: serviceCatalog, * resolver: mapResolver({ * "fleet.v1.FleetService": createGrpcTransport({ baseUrl: process.env.FLEET_ADDR }), * }), * }); * * // Fully typed off the generated catalog — same surface as ctx.call: * const trip = await client.call("trip.v1.TripService/StartTrip", { vehicleId }); * ``` */ declare function createCatalogClient(options: CreateCatalogClientOptions): CatalogClient; /** * CatalogConfigError — a configuration mistake in the service-catalog setup. * * This is a **programmer error**: it should fail loud with a stack trace rather * than be mapped to an RPC status code. It is thrown eagerly for misconfiguration * such as `server.client(Desc)` on a non-local service with no resolver, * `enabledServices` that is not a subset of the catalog, or a duplicate `typeName` * during `mergeCatalogs`. * * Operational failures (a resolver returning `null`, a network error, an unknown * `typeName` at `ctx.call` dispatch) stay `ConnectError` with the appropriate * Connect status code. This split (Q15) keeps developer mistakes distinct from * runtime failures. * * @module catalogErrors */ declare class CatalogConfigError extends Error { readonly name = "CatalogConfigError"; constructor(message: string); } /** * `enabledServices` helpers — env-driven local activation of catalog services. * * `enabledServices` is a list of full proto `typeName`s that a process mounts * locally; everything else in the catalog is remote. Short service names are * NOT used — they collide (`catalog.v1.UsersService` and `auth.v1.UsersService` * both shorten to `users`; medium-compose finding F-E). * * @module enabledServices */ /** * Parse a comma-separated env value into a list of proto `typeName`s, trimming * whitespace and dropping empty entries. Returns `[]` for an empty/undefined value. * * @example `enabledServices: parseServicesEnv(process.env.CONNECTUM_SERVICES)` */ declare function parseServicesEnv(value: string | undefined | null): string[]; /** * Return the subset of `names` matching a glob `pattern`, where `*` matches any * run of characters (including dots). E.g. `"acme.*"` matches * `"acme.v1.UsersService"`. Matched without a constructed `RegExp` (segment scan). */ declare function matchServicesPattern(pattern: string, names: readonly string[]): string[]; /** Merge several `enabledServices` lists, de-duplicating while preserving first-seen order. */ declare function mergeEnabledServices(...lists: readonly (readonly string[])[]): string[]; /** * In-process ConnectRPC transport. * * Wraps `createRouterTransport` from `@connectrpc/connect` over the already * registered routes of a Connectum `Server`, dispatching calls directly to * handler functions without opening an HTTP/2 socket. * * @module localTransport */ /** * Options for {@link createLocalTransport}. */ interface CreateLocalTransportOptions { /** * Client-side interceptors applied to outbound calls before they reach * the registered handlers. Server-side interceptors configured on the * `Server` instance still run inside the handler chain — these are * additive and run on the client side of the in-memory pipe. */ interceptors?: Interceptor[]; } /** * Create an in-process ConnectRPC `Transport` over the services already * registered on the given Connectum `Server`. * * The transport is safe to use before `server.start()` — it never opens a * TCP/UDP port or HTTP/2 session. Server-side interceptors configured via * `createServer({ interceptors })` are applied inside the handler chain; * `options.interceptors` are applied on the client side of the call. * * Headers are propagated via `Headers` objects through the in-memory pipe; * the wrapped `createRouterTransport` already clones headers at the call * boundary, providing mutation isolation between client and server. * * The synthetic origin observed by interceptors reading `req.url` is * `https://in-memory//` (set by the underlying ConnectRPC * router transport — see `@connectrpc/connect`'s `router-transport.ts`). * * @param server - A server created via `createServer({...})`. * @param options - Optional client-side interceptors. * @returns A ConnectRPC `Transport` suitable for `createClient(service, transport)`. */ declare function createLocalTransport(server: Server, options?: CreateLocalTransportOptions): Transport; /** * Header propagation for `ctx.call` / `ctx.stream`. * * By default Connectum propagates NO inbound headers to outgoing catalog calls * (no hidden behaviour). Opt in by listing header names in * `createServer({ propagateHeaders })`; explicit `CallOptions.headers` always * take precedence over propagated values. * * {@link defaultPropagateHeaders} is a ready-made set you can spread and tweak, * mirroring the opt-in `createDefaultInterceptors` ergonomics: * * ```ts * createServer({ propagateHeaders: [...defaultPropagateHeaders, "x-tenant-id"] }); * ``` * * @module propagateHeaders */ /** * Recommended default allow-list: W3C trace-context headers only. * * Trace headers let a downstream call continue the inbound trace even without * an OpenTelemetry SDK. When the `@connectum/otel` client interceptor is also * mounted in `outgoingInterceptors`, it overwrites `traceparent` with the * active span's context (so the OTel value wins — no conflicting double value). * * `authorization` is intentionally excluded: forwarding credentials is a * deliberate, security-sensitive choice the caller must opt into explicitly. */ declare const defaultPropagateHeaders: readonly string[]; /** * Server implementation with explicit lifecycle * * Provides the new Server API (PRD v1.1) with explicit start/stop control. * * @module Server */ /** * Create a new server instance * * Returns an unstarted server. Call server.start() to begin accepting connections. * * @param options - Server configuration options * @returns Unstarted server instance * * @example * ```typescript * import { createServer } from '@connectum/core'; * import { Healthcheck, healthcheckManager, ServingStatus } from '@connectum/healthcheck'; * import { Reflection } from '@connectum/reflection'; * * const server = createServer({ * services: [myRoutes], * protocols: [Healthcheck({ httpEnabled: true }), Reflection()], * shutdown: { autoShutdown: true }, * }); * * server.on('ready', () => { * healthcheckManager.update(ServingStatus.SERVING); * }); * * await server.start(); * ``` */ declare function createServer(options: CreateServerOptions): Server; /** * Sanitizable error protocol * * Interface for errors that carry server-side details while providing * a safe client-facing message. ErrorHandler interceptor recognizes * this interface and sanitizes automatically. * * @module errors */ /** * Sanitizable error interface. * * Errors implementing this protocol carry rich server-side details * but expose only a safe message to clients. */ interface SanitizableError { readonly clientMessage: string; readonly serverDetails: Readonly>; } /** * Type guard for SanitizableError. * * Checks if the value is an object with clientMessage (string) and * serverDetails (non-null object) properties, plus a numeric code. */ declare function isSanitizableError(err: unknown): err is Error & SanitizableError & { code: number; }; /** * TLS configuration utilities * * @module TLSConfig */ /** * Get TLS directory path * * Resolves TLS directory from environment variable or default location. * * @returns TLS directory path */ declare function getTLSPath(): string; /** * Read TLS certificates from configuration * * @param options - TLS options * @returns TLS key and cert buffers */ declare function readTLSCertificates(options?: TLSOptions): { key: Buffer; cert: Buffer; }; /** * Exported for backward compatibility */ declare const tlsPath: string; /** * Transport / streaming-kind validation * * The Connect protocol requires HTTP/2 for bidi-streaming RPCs ("Bidirectional * streaming requires HTTP/2, but the other RPC types also support HTTP/1.1" — * connectrpc.com/docs/protocol). HTTP/1.1 is half-duplex at the wire level, so * a bidi method registers cleanly and then fails silently at runtime: the * first client send hangs forever (or yields HTTP 505). This module turns that * misconfiguration into a startup-time diagnostic. * * Two transport situations are diagnosed: * - **plaintext HTTP/1.1** (no TLS, `allowHTTP1: true` — the default): bidi can * only ever fail → `error` by default (configurable). * - **TLS with `allowHTTP1: true`**: the server negotiates HTTP/2 via ALPN, so * bidi works for HTTP/2 clients — but a client (or proxy) that negotiates * HTTP/1.1 over TLS hits the same hang. This is a residual risk, not a * certain failure, so it is always a one-time `warn` (never a hard error): * a mixed port serving HTTP/1.1 unary clients alongside HTTP/2 bidi clients * is a legitimate, if discouraged, configuration. Setting `allowHTTP1: false` * makes the server refuse HTTP/1.1 at ALPN and removes the risk entirely. * * Unary, server-streaming, and client-streaming are excluded: the Connect * protocol supports them over HTTP/1.1. * * @module TransportValidation */ /** * Stable error code for the streaming-vs-transport startup diagnostic. * Searchable in logs and docs. */ declare const TRANSPORT_VALIDATION_ERROR_CODE = "CONNECTUM_UNSUPPORTED_STREAMING_TRANSPORT"; /** Validation severity. */ declare const TransportValidationMode: { readonly ERROR: "error"; readonly WARN: "warn"; readonly OFF: "off"; }; type TransportValidationMode = (typeof TransportValidationMode)[keyof typeof TransportValidationMode]; /** * Effective transport resolved from `tls` + `allowHTTP1`. * * - `plaintext-h1` — no TLS, `allowHTTP1: true` (default): HTTP/1.1 only. * - `h2c` — no TLS, `allowHTTP1: false`: plaintext HTTP/2. * - `tls-h1-negotiable` — TLS, `allowHTTP1: true`: ALPN offers both; a client * may negotiate HTTP/1.1 (residual bidi risk). * - `tls-h2-only` — TLS, `allowHTTP1: false`: ALPN refuses HTTP/1.1. */ declare const EffectiveTransport: { readonly PLAINTEXT_H1: "plaintext-h1"; readonly H2C: "h2c"; readonly TLS_H1_NEGOTIABLE: "tls-h1-negotiable"; readonly TLS_H2_ONLY: "tls-h2-only"; }; type EffectiveTransport = (typeof EffectiveTransport)[keyof typeof EffectiveTransport]; /** * Resolve the effective transport from the server's TLS and `allowHTTP1` * configuration. `allowHTTP1` defaults to `true` (matching TransportManager). */ declare function resolveEffectiveTransport(options: { hasTls: boolean; allowHTTP1?: boolean | undefined; }): EffectiveTransport; /** A streaming method that requires HTTP/2. */ interface StreamingMethodInfo { /** Fully qualified service typeName (e.g. `acme.v1.ScannerService`). */ readonly service: string; /** Method name (e.g. `StreamCodes`). */ readonly method: string; /** Streaming kind: `bidi_streaming`. */ readonly kind: string; } /** * Startup validation error: bidi-streaming methods registered on a * transport that cannot carry them. Carries the stable * {@link TRANSPORT_VALIDATION_ERROR_CODE} code and the affected methods. */ declare class TransportValidationError extends Error { readonly code = "CONNECTUM_UNSUPPORTED_STREAMING_TRANSPORT"; readonly methods: readonly StreamingMethodInfo[]; constructor(message: string, methods: readonly StreamingMethodInfo[]); } /** * Collect bidi-streaming methods from a DescFile registry (built during * route registration). Client-streaming is NOT collected — the Connect * protocol supports it over HTTP/1.1. */ declare function collectStreamingMethods(registry: readonly DescFile[]): StreamingMethodInfo[]; export { CatalogCall, type CatalogClient, CatalogConfigError, CatalogStream, type CreateCatalogClientOptions, type CreateLocalTransportOptions, CreateServerOptions, EffectiveTransport, RemoteResolver, type SanitizableError, Server, ServiceCatalog, type StreamingMethodInfo, TLSOptions, TRANSPORT_VALIDATION_ERROR_CODE, TransportValidationError, TransportValidationMode, collectStreamingMethods, createCatalogClient, createLocalTransport, createServer, defaultPropagateHeaders, getTLSPath, isSanitizableError, matchServicesPattern, mergeEnabledServices, parseServicesEnv, readTLSCertificates, resolveEffectiveTransport, tlsPath };