Envelope
Overview
Section titled “Overview”Envelope is the on-the-wire shape of every message. It has exactly two fields: a free-form headers map and a body byte array. The serializer produces the body bytes; the bus and pipeline stamp the headers. Filters in the outgoing and inbound pipelines see and can mutate the envelope before it goes to the transport or after it comes off.
Import
Section titled “Import”import type { Envelope } from '@serviceconnect/core';Signature
Section titled “Signature”export interface Envelope { headers: Record<string, unknown>; body: Uint8Array;}Parameters
Section titled “Parameters”headers—Record<string, unknown>. The in-process headers map — the internal camelCaseMessageHeadersbag that the pipeline filters see. Carries keys such asmessageId,messageType,sourceAddress,destinationAddress, andtimeSent, plus any custom headers the caller passed viaSendOptions.headers/PublishOptions.headers. At the transport boundary the bus rewrites these to the PascalCase wire names (see below). Values are typedunknownbecause they survive a round-trip through the transport — assumestringfor anything you set yourself.body—Uint8Array. The serialised payload bytes. With the default serializer this is UTF-8 JSON; with a custom serializer it can be anything.
C# wire-format compatibility
Section titled “C# wire-format compatibility”@serviceconnect/core is wire-compatible with the .NET ServiceConnect (master) stack, so Node.js and .NET services interoperate on the same RabbitMQ bus. The bus translates between its internal camelCase headers and .NET’s PascalCase wire headers at the transport boundary:
- Outgoing (
encodeWireHeaders) — internal keys are stamped as PascalCase wire headers:messageTypebecomesTypeName(the .NET type identity),messageId→MessageId,sourceAddress→SourceAddress, and so on. A separateMessageTypeheader carries the operation (PublishorSend), and every message is taggedConsumerType: 'RabbitMQ'andLanguage: 'Node'.correlationIdis not sent as a header — it is a property of the serialised message body, matching .NET. - Incoming (
decodeWireHeaders) — PascalCase wire headers map back to camelCase. The message type is resolved fromFullTypeName(an assembly-qualified name, reduced to its FullName) when present, otherwise fromTypeName.FullTypeNameis optional, and Node never sets it on outgoing messages.
A message arriving from a .NET service with only PascalCase headers is therefore resolved correctly. This interop is exercised by the repository’s interop/ harness against a real C# master fixture.
Example
Section titled “Example”import type { Envelope } from '@serviceconnect/core';import { asFilter, FilterAction } from '@serviceconnect/core';
const stampTenant = asFilter(async (envelope: Envelope) => { envelope.headers.tenantId = process.env.TENANT_ID ?? 'default'; return FilterAction.Continue;});
bus.use('outgoing', stampTenant);