Skip to main content

Configuration

More Examples

Use package.json auto-load for integration services that default-export a Hile service:
Inside another service, load dependencies:

Complete Example

Failure And Cleanup Behavior

  • save() validates fields before mutating memory.
  • Redis is written before memory and event emission update.
  • initialize() publishes every config field as a topic.
  • Cleanup unpublishes topics and removes listeners.

Runtime And Lifecycle Notes

  • MessageLoader maps *.msg.* files to routes using @hile/loader.
  • Message files use the same portable DSL as controllers: [id].msg.ts declares one segment and [...paths].msg.ts declares one or more final segments. A catch-all handler reads the slash-joined value from params.paths; Hile compiles it to rou3’s named catch-all syntax.
  • Optional catch-all, mixed or non-terminal dynamic segments, multiple catch-alls, duplicate dynamic names, unsafe or object-meta names, and router-native syntax in message file names fail during loading. The configured prefix may use rou3-native or bracket-style parameters, is compiled separately from file segments, and cannot duplicate a file parameter name; manual register() calls continue to accept rou3-native paths.
  • defineMessage(fn, options?) and MessageLoader.register(path, fn, options?) accept MessageProtocolOptions; MessageLoader.dispatch(path, data, extras?, options?) checks that protocol before invoking the matched handler.
  • Raw registrations and file-loaded messages share route ownership. Duplicate normalized paths and equal-specificity overlaps fail with MessageRouteConflictError (HILE_MESSAGE_ROUTE_CONFLICT). This includes /a/:x versus /:x/b; regex parameters are conservatively treated as unrestricted, so disjoint regexes with the same route shape also conflict. Distinct static branches and different-specificity static/parameter/catch-all precedence remain supported by rou3.
  • A MessageLoader.load() batch is invisible until it commits. Import, bind, or final commit failure rolls back only that batch. Unload is idempotent and owner-specific; an old release cannot remove a replacement. Concurrent loads or raw registration during a load fail with MessageLoadInProgressError (HILE_MESSAGE_LOAD_IN_PROGRESS); releasing existing owners remains allowed and cannot resurrect them at commit.
  • protected bind(file, metadata) remains the extension point. An override that calls super.bind must return/compose its cleanup and unwind its own side effects on failure. The generic loader does not parse business payloads or inspect Context.
  • MessageModem._send() returns a Promise.
  • _send() and _stream() accept options.input as an AsyncIterable, Uint8Array, or ArrayBuffer. Passing one of those values directly as data automatically selects request streaming and leaves the handler’s structured data undefined.
  • MessageModem._send() and _push() use a 30_000 ms timeout when none is provided. An explicit timeout must be a safe integer from 1 through 2_147_483_647; invalid values throw TypeError before a message is sent.
  • MessageModem._stream() returns a Node Readable in object mode.
  • Stream timeout and idleTimeout values use the same 1 through 2_147_483_647 ms range. Idle timeout is refreshed by valid input or output stream activity. The response stream window must be a safe integer from 1 through 64 and defaults to 1; request input uses receiver-issued credit with a window of 1.
  • Each modem schedules request, total-stream, and idle-stream deadlines through one internal deadline scheduler. This reduces active Node.js timers without changing timeout, cancellation, ordering, or error semantics.
  • Request and response chunks share STREAM_DATA frames and carry an explicit direction: 'input' | 'output'; each direction has independent sequence and credit state. STREAM_CANCEL stops one direction. A cancel carrying status fails the owning request immediately; ABORT cancels the whole invocation.
  • This frame model replaces the former response-only stream, streamVersion, and streamWindow fields. All peers on one transport connection must use compatible @hile/message-modem and transport package versions; do not mix old and new peers during a rolling deployment.
  • @hile/message-ws sends Uint8Array and ArrayBuffer request and response chunks as native binary frames rather than JSON/base64. Public decodeMessageFrame() payloads remain isolated from caller-owned input by default; the owned WebSocket RawData path uses a zero-copy binary view internally.
  • @hile/message-ipc transparently Base64-wraps only binary STREAM_DATA payloads so request and response streams survive Node child-process IPC’s default JSON serialization. Other IPC frames keep their ordinary object representation.
  • A stream request requires exec() to return an async iterable.
  • MessageModem.exec(data, signal?, input?, execution?) has an optional fourth MessageExecutionOptions argument. Its responseStream flag comes from the decoded request frame, not payload metadata or the presence of an input stream. Existing three-argument transport subclasses remain compatible; custom subclasses that forward execution to another dispatcher must preserve this argument when the receiver needs to enforce unary-only operations.
  • An execution whose response cannot be delivered (including a unary request returning an async iterable, or a stream failing during iteration) aborts its request scope before sending the original error. Cleanup is cooperative and does not delay the failure frame; provider shutdown still owns its bounded drain deadline.
  • defineMicroMessage() handlers receive request streams as input: Readable | undefined, separately from structured data and invocation.
  • Application.call(namespace, url, data, options) requires options.context and returns a promise. It accepts options.input for a streamed request with a normal response.
  • Application.stream(namespace, url, data, options) requires options.context and returns a readable response stream; it can carry a request input stream at the same time.
  • Application.call() and Application.stream() may target the application’s own namespace. These self RPCs use normal Registry-discovered WebSocket/modem transport, not an automatic local branch; replica selection and network behavior remain unchanged. The separate loadMicroContract() binding provides explicit local execution only for its typed fixed-path unary operations, through the same provider executor. See Typed Micro contracts for its distinct failure and lifecycle semantics.
  • A peer address (host:port) is the routing and reuse identity, not an individual WebSocket identity. If both peers dial each other concurrently, including an application dialing itself, the server preserves both physical connections while they are active instead of replacing a connection that may carry an in-flight request. Later calls still reuse the cached peer connection.
  • This connection bookkeeping does not add or change wire frames; request, response, stream, credit, cancel, and abort protocol fields remain unchanged.
  • Application.call() and Application.stream() default retries to 0 when request input is streamed. Explicit nonzero retries fail before service discovery because streamed input is non-replayable.
  • Native nonstream Application.call()/stream() retain the existing default of one transport retry. createMicroClient() and callHttpOverMicro() explicitly default to zero for both reads and writes. Opt-in retries remain subject to the underlying eligible-error policy and the caller’s end-to-end attempt/idempotency budget; provider contract/protocol rejection, HILE_MICRO_EXECUTION_FAILED, and unavailable admission do not trigger automatic retries. Safe typed execution errors must not replay a whole orchestration after a downstream validation failure; native unknown-error handling is unchanged.
  • Micro adapters can pass options.protocol; it travels in existing request metadata.protocol and is checked by the generic message loader. There is no new modem frame or operation dispatcher. All selectable receivers must support this check before relying on protocol isolation: older receivers may ignore the marker.
  • A caller-owned request input source failure is surfaced as MessageInputError, aborts the peer invocation, and is not counted against that peer’s circuit-breaker health.
  • Application.publish(topic, payload) returns an object with update() and unpublish().
  • Application.subscribe(topic, callback) returns an unsubscribe function.
  • Registry stores service addresses and retained config/topic state under ~/.registry.