Skip to content

@btravstack/http


@btravstack/http

Classes

HttpConfig

Defined in: http/src/http-runtime.ts:30

What the socket is bound with, as a service: http() binds it from the environment — PORT (default 3000; 0 lets the OS pick, read it back from RunningApp.runtimeInfo()) and HOST (default 0.0.0.0: the deployment target is a pod, not a laptop) — and anything else in the graph may read it.

Extends

  • PortInstance<"HttpConfig", { hostname: string; port: number; }>

Constructors

Constructor
ts
new HttpConfig(): HttpConfig;

Defined in: di/dist/index.d.mts:15

Returns

HttpConfig

Inherited from
ts
Port("HttpConfig")<{
  readonly port: number;
  readonly hostname: string;
}>.constructor

Properties

PropertyModifierTypeInherited fromDefined in
[ID]readonly"HttpConfig"Port("HttpConfig").[ID]di/dist/index.d.mts:11
[SERVICE]readonlyobjectPort("HttpConfig").[SERVICE]di/dist/index.d.mts:12
[SERVICE].hostnamereadonlystring-http/src/http-runtime.ts:32
[SERVICE].portreadonlynumber-http/src/http-runtime.ts:31
portIdreadonly"HttpConfig"Port("HttpConfig").portIddi/dist/index.d.mts:16

HttpRuntime

Defined in: http/src/http-runtime.ts:50

The runtime's port: what http() provides, and what the module start boots must export.

Extends

Constructors

Constructor
ts
new HttpRuntime(): HttpRuntime;

Defined in: di/dist/index.d.mts:15

Returns

HttpRuntime

Inherited from
ts
RuntimePort<Runtime<never, HttpInfo>>.constructor

Properties

PropertyModifierTypeInherited fromDefined in
[ID]readonly"Runtime"RuntimePort.[ID]di/dist/index.d.mts:11
[SERVICE]readonlyRuntimeRuntimePort.[SERVICE]di/dist/index.d.mts:12
portIdreadonly"Runtime"RuntimePort.portIddi/dist/index.d.mts:16

Type Aliases

HttpInfo

ts
type HttpInfo = object;

Defined in: http/src/http-runtime.ts:21

What the runtime publishes once it is listening, read back through RunningApp.runtimeInfo().

Properties

PropertyModifierTypeDefined in
portreadonlynumberhttp/src/http-runtime.ts:21

HttpModuleOptions

ts
type HttpModuleOptions<RouterError, RouterNeeds, I, P, X> = object;

Defined in: http/src/http-module.ts:25

Type Parameters

Type Parameter
RouterError
RouterNeeds
I extends readonly AnyModule[]
P extends readonly AnyProvider[]
X extends readonly Exportable<Imports<I>, Provides<P, RouterError, RouterNeeds>>[]

Properties

PropertyModifierTypeDescriptionDefined in
exports?readonlyXThe application's own exports; HttpRuntime is added, since start resolves it.http/src/http-module.ts:42
hostname?readonlystring-http/src/http-module.ts:38
imports?readonlyI-http/src/http-module.ts:39
port?readonlynumberPins for a test — otherwise PORT/HOST from the environment.http/src/http-module.ts:37
prefix?readonly`/${string}`Where the RPC endpoint is mounted. Default /rpc.http/src/http-module.ts:35
provides?readonlyP-http/src/http-module.ts:40
routerreadonlyProvider<HttpRouterPort, RouterError, RouterNeeds>The application's oRPC router — HttpRouter(contract)(deps, arm), the provider that builds it from the services its procedures call.http/src/http-module.ts:33

HttpOptions

ts
type HttpOptions = object;

Defined in: http/src/http-runtime.ts:42

http()'s options: where the router is mounted, and what a caller pins instead of reading from the environment — a test's { port: 0 }. The router itself is not an option: it is the provider the composition root supplies on the starter's own router port (HttpRouter(contract)(deps, arm)), which this module needs.

Properties

PropertyModifierTypeDescriptionDefined in
hostname?readonlystring-http/src/http-runtime.ts:46
port?readonlynumber-http/src/http-runtime.ts:45
prefix?readonly`/${string}`Where the RPC endpoint is mounted. Default /rpc.http/src/http-runtime.ts:44

Functions

http()

ts
function http(options?): Module<HttpRuntime | HttpConfig, ConfigInvalid, Env | HttpRouterPort>;

Defined in: http/src/http-runtime.ts:114

The HTTP starter, and the one way HTTP is answered here: oRPC. A module providing the runtime (HttpRuntime), its configuration (HttpConfig, bound from PORT/HOST unless pinned) and the HTTP surface built from the application's router — a provider on the starter's own router port, built by HttpRouter(contract)(deps, arm) from the use cases its procedures call, which this module NEEDS: a composition root that imports the starter without providing a router owes the port, and di's gate says so. http() mounts it under prefix and puts the listener on the socket. Import it next to the application, provide the router, export HttpRuntime, and that is the whole of the transport wiring: no handler, no needs, no context handed to a procedure.

Pin port/hostname and the module reads nothing from the environment (the declared Env need and ConfigInvalid stay — the kernel discharges the one, a pinned config never produces the other); pin only some and the rest still comes from the environment.

Parameters

ParameterType
optionsHttpOptions

Returns

Module<HttpRuntime | HttpConfig, ConfigInvalid, Env | HttpRouterPort>


HttpController()

ts
function HttpController<Name, C>(name, contract): <D>(deps, options) => Provider<PortInstance<Name, Implementation<C>>, never, InstanceType<D[number]>> & object;

Defined in: http/src/controller.ts:30

One slice of a contract, as a provider on a port of its own.

A large API is several controllers, each owning a fragment of the contract and declaring the use cases its procedures call; HttpRouter(contract)(...) composes them. contract is read for its type only — it is what shapes sync, so a procedure the fragment does not declare, or a handler whose input or output has drifted, is a compile error here rather than at the root.

The port is minted for you and carried back on provider.port, the same shape Config.provider("RelayConfig")(schema) returns: there is nothing to name twice. It is spelled through di's PortInstance / PortClassOf rather than the class expression's own type because a class expression is anonymous and a consumer that exports the provider cannot emit its declaration (TS4023, measured on examples/order-api).

Type Parameters

Type Parameter
Name extends string
C extends RouterContract

Parameters

ParameterType
nameName
contractC

Returns

<D>(deps, options) => Provider<PortInstance<Name, Implementation<C>>, never, InstanceType<D[number]>> & object


HttpModule()

ts
function HttpModule<Name>(name): <RouterError, RouterNeeds, I, P, X>(options) => Module<ResolvedExports<readonly [typeof HttpRuntime, X]>, 
  | ErrOf<readonly [Provider<HttpRouterPort, RouterError, RouterNeeds>, P][number]>
  | ErrOfModule<readonly [I, HttpStarter][number]>, 
  | Exclude<NeedOf<readonly [Provider<HttpRouterPort, RouterError, RouterNeeds>, P][number]>, Available<readonly [I, HttpStarter], readonly [Provider<HttpRouterPort, RouterError, RouterNeeds>, P]>>
  | Exclude<NeedsOfModule<readonly [I, HttpStarter][number]>, Available<readonly [I, HttpStarter], readonly [Provider<HttpRouterPort, RouterError, RouterNeeds>, P]>>>;

Defined in: http/src/http-module.ts:66

Module(name)({...}) for an HTTP deployment: everything a di module takes, plus the router provider, and nothing else to know. The sugar imports the starter (http()), provides the router, and exports HttpRuntime — so a root that would otherwise write those two lines and remember that start needs the runtime exported writes neither. It hands back exactly the module Module(...) would have declared over the augmented imports/provides/exports (spelled from di's own pieces), so the kernel, start's gate and di's see nothing new: syntax over the same primitives, one source of truth.

ts
export const OrderApi = HttpModule("OrderApi")({
  router: orderRouter,
  imports: [OrderApplicationModule, OrderPersistenceModule],
  exports: [Logger],
});
await runMain(OrderApi);

Type Parameters

Type Parameter
Name extends string

Parameters

ParameterType
nameName

Returns

<RouterError, RouterNeeds, I, P, X>(options) => Module<ResolvedExports<readonly [typeof HttpRuntime, X]>, | ErrOf<readonly [Provider<HttpRouterPort, RouterError, RouterNeeds>, P][number]> | ErrOfModule<readonly [I, HttpStarter][number]>, | Exclude<NeedOf<readonly [Provider<HttpRouterPort, RouterError, RouterNeeds>, P][number]>, Available<readonly [I, HttpStarter], readonly [Provider<HttpRouterPort, RouterError, RouterNeeds>, P]>> | Exclude<NeedsOfModule<readonly [I, HttpStarter][number]>, Available<readonly [I, HttpStarter], readonly [Provider<HttpRouterPort, RouterError, RouterNeeds>, P]>>>


HttpRouter()

ts
function HttpRouter<C>(contract): {
<D>  (deps, options): Provider<PortInstance<"HttpRouter", Router<Record<never, never>>>, never, InstanceType<D[number]>> & object;
<M>  (controllers): Provider<PortInstance<"HttpRouter", Router<Record<never, never>>>, never, InstanceType<M[keyof M]["port"]>> & object;
};

Defined in: http/src/orpc.ts:102

The router as a provider, from the contract:

ts
const orderRouter = HttpRouter(orderContract)([PlaceOrder, FindOrder], {
  sync: (place, find) => ({
    orders: {
      place: ({ errors }, input) => place.execute(input.id, input.quantity).map(view).mapErrCases(…),
      find: ({ errors }, input) => find.execute(input.id).map(view).mapErrCases(…),
    },
  }),
});

The contract already says which procedures exist, what each takes and returns and which errors it declares — so an implementation is a record shaped like the contract whose leaves are plain Result-returning functions ((helpers, input) => AsyncResult<Output, ORPCError>, the .result() handler @unthrown/orpc gives an implementer), typed by the contract at the call: a typo'd key, a missing procedure, a wrong output are compile errors here. implement(contract), os.…, .result(...) and os.router(...) are what this call does for you.

The first call fixes the contract; the second is di's Provider(port)([deps], { sync }) on the starter's own router port, with one difference: sync returns the implementation record and the router is built from it. There is no name to give — a process serves one router, so the port is the starter's (HttpRouterPort), and the provider carries it typed (orderRouter.port) for whoever else needs the class.

The second call also takes a keyed record of controllers instead of (deps, { sync }): HttpRouter(contract)({ orders: ordersController, users: usersController }), one HttpController per top-level contract key. Each fragment is composed as-is rather than re-implemented, and every key of the contract must be covered — a missing or extra key is a compile error.

Type Parameters

Type Parameter
C extends Record<string, RouterContract>

Parameters

ParameterType
contractC

Returns

{ <D> (deps, options): Provider<PortInstance<"HttpRouter", Router<Record<never, never>>>, never, InstanceType<D[number]>> & object; <M> (controllers): Provider<PortInstance<"HttpRouter", Router<Record<never, never>>>, never, InstanceType<M[keyof M]["port"]>> & object; }

Released under the MIT License.