/** * PortsBuilder - Mutable builder for composing ports during app initialization * * This builder is a small composition helper for tests and custom bootstrapping * code that wants to assemble ports incrementally. */ /** * A mutable builder around a ports object. * Used during app composition and provider registration. */ export interface PortsBuilder { /** * The current ports object being built. * This is mutated internally when extend/replace are called. */ ports: Ports; /** * Extend ports with a new key. If the key already exists, it's overwritten. * * Returns the same builder instance with an extended type: * Ports & { [K in key]: Value } */ extend( key: K, value: V, ): PortsBuilder; /** * Replace an existing key. Does not change the type, but updates the runtime value. * Returns the same builder instance. */ replace(key: K, value: Ports[K]): PortsBuilder; } /** * Create a new PortsBuilder from an initial ports object. * * The builder wraps a mutable object internally and provides type-safe methods * to extend or replace ports. This is used during application composition * helpers that want to modify ports before passing them to a server. * * @example * ```ts * const initialPorts = definePorts({ db: dbAdapter }); * const builder = createPortsBuilder(initialPorts); * * // Provider extends with cache * builder.extend("cache", cacheAdapter); * * // Final ports includes both db and cache * const finalPorts = builder.ports; * ``` */ export function createPortsBuilder( initialPorts: Ports, ): PortsBuilder { // Keep a mutable object internally // biome-ignore lint/suspicious/noExplicitAny: internal mutable state needs any to accept arbitrary port extensions const state: { ports: any } = { ports: { ...initialPorts }, }; const builder: PortsBuilder = { get ports() { // Could freeze in dev, but keep simple return state.ports as Ports; }, extend( key: K, value: V, ): PortsBuilder { state.ports[key] = value; return builder as unknown as PortsBuilder; }, replace( key: K, value: Ports[K], ): PortsBuilder { state.ports[key] = value; return builder; }, }; return builder; } /** * Extract the Ports type from a PortsBuilder * * @example * ```ts * type MyPorts = PortsOf; * ``` */ export type PortsOf = PB extends PortsBuilder ? P : never;