Configuration
More Examples
Usepackage.json auto-load for integration services that default-export a Hile service:
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
MessageLoadermaps*.msg.*files to routes using@hile/loader.- Message files use the same portable DSL as controllers:
[id].msg.tsdeclares one segment and[...paths].msg.tsdeclares one or more final segments. A catch-all handler reads the slash-joined value fromparams.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
prefixmay use rou3-native or bracket-style parameters, is compiled separately from file segments, and cannot duplicate a file parameter name; manualregister()calls continue to accept rou3-native paths. defineMessage(fn, options?)andMessageLoader.register(path, fn, options?)acceptMessageProtocolOptions;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/:xversus/: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 withMessageLoadInProgressError(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 callssuper.bindmust 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 aPromise._send()and_stream()acceptoptions.inputas anAsyncIterable,Uint8Array, orArrayBuffer. Passing one of those values directly asdataautomatically selects request streaming and leaves the handler’s structureddataundefined.MessageModem._send()and_push()use a30_000ms timeout when none is provided. An explicit timeout must be a safe integer from1through2_147_483_647; invalid values throwTypeErrorbefore a message is sent.MessageModem._stream()returns a NodeReadablein object mode.- Stream
timeoutandidleTimeoutvalues use the same1through2_147_483_647ms range. Idle timeout is refreshed by valid input or output stream activity. The response streamwindowmust be a safe integer from1through64and defaults to1; request input uses receiver-issued credit with a window of1. - 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_DATAframes and carry an explicitdirection: 'input' | 'output'; each direction has independent sequence and credit state.STREAM_CANCELstops one direction. A cancel carryingstatusfails the owning request immediately;ABORTcancels the whole invocation. - This frame model replaces the former response-only
stream,streamVersion, andstreamWindowfields. All peers on one transport connection must use compatible@hile/message-modemand transport package versions; do not mix old and new peers during a rolling deployment. @hile/message-wssendsUint8ArrayandArrayBufferrequest and response chunks as native binary frames rather than JSON/base64. PublicdecodeMessageFrame()payloads remain isolated from caller-owned input by default; the owned WebSocketRawDatapath uses a zero-copy binary view internally.@hile/message-ipctransparently Base64-wraps only binarySTREAM_DATApayloads 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 fourthMessageExecutionOptionsargument. ItsresponseStreamflag 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 asinput: Readable | undefined, separately from structureddataandinvocation.Application.call(namespace, url, data, options)requiresoptions.contextand returns a promise. It acceptsoptions.inputfor a streamed request with a normal response.Application.stream(namespace, url, data, options)requiresoptions.contextand returns a readable response stream; it can carry a request input stream at the same time.Application.call()andApplication.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 separateloadMicroContract()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()andApplication.stream()default retries to0when 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()andcallHttpOverMicro()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 requestmetadata.protocoland 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 withupdate()andunpublish().Application.subscribe(topic, callback)returns an unsubscribe function.Registrystores service addresses and retained config/topic state under~/.registry.