@btravstack/amqp-worker 0.13.0 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -188,15 +188,15 @@ module lists (`imports`, `provides`, `exports`, `needs`). The `amqp()`
188
188
  primitive does not take `handlers` as an option — it **needs** the handlers
189
189
  provider on its own port, which is how the composition root supplies it:
190
190
 
191
- | Option | What it is |
192
- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------- |
193
- | `contract` | the `amqp-contract` contract; the queues consumed are read off it |
194
- | `handlers` | the handlers provider — what `AmqpHandlers(contract)(...)` returns for this contract |
195
- | `url` | pins `AMQP_URL` (default `amqp://127.0.0.1:5672`) — a test's container |
196
- | `connectionOptions` | `AmqpConnectionOptions`, the library's own connection tuning: heartbeat, reconnect interval, `findServers`, TLS |
197
- | `defaultConsumerOptions` | the library's `ConsumerOptions`, applied to every handler: `prefetch` (the throughput knob), `priority`, … |
198
- | `connectTimeoutMs` | pins `AMQP_CONNECT_TIMEOUT_MS` — how long startup waits before an unreachable broker is a `RuntimeStartFailed` (default `5000`) |
199
- | `unit` | `{ message }` — the module the worker forks per delivery, seeded with the message on `AmqpMessage(contract)` |
191
+ | Option | What it is |
192
+ | ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- |
193
+ | `contract` | the `amqp-contract` contract; the queues consumed are read off it |
194
+ | `handlers` | the handlers provider — what `AmqpHandlers(contract)(...)` returns for this contract |
195
+ | `url` | pins `AMQP_URL` (default `amqp://127.0.0.1:5672`) — a test's container |
196
+ | `connectionOptions` | `AmqpConnectionOptions`, the library's own connection tuning: heartbeat, reconnect interval, `findServers`, TLS |
197
+ | `defaultConsumerOptions` | the library's `ConsumerOptions`, applied to every handler: `prefetch` (the throughput knob — unset is `10`, `"unbounded"` is no cap), `priority`, … |
198
+ | `connectTimeoutMs` | pins `AMQP_CONNECT_TIMEOUT_MS` — how long startup waits before an unreachable broker is a `RuntimeStartFailed` (default `5000`) |
199
+ | `unit` | `{ message }` — the module the worker forks per delivery, seeded with the message on `AmqpMessage(contract)` |
200
200
 
201
201
  The full table — required/optional, defaults, and the reasoning — lives on
202
202
  [the reference page](https://btravstack.github.io/btravstack/reference/amqp-worker),
package/dist/index.cjs CHANGED
@@ -5,6 +5,60 @@ let _btravstack_config = require("@btravstack/config");
5
5
  let _btravstack_core = require("@btravstack/core");
6
6
  let unthrown = require("unthrown");
7
7
  let node_crypto = require("node:crypto");
8
+ //#region src/broker-log.ts
9
+ /**
10
+ * The library's own diagnostics, as operations on `Observers`.
11
+ *
12
+ * **`@amqp-contract/worker` takes a `logger` and was given none**, so every
13
+ * line it writes was discarded: "Consumer cancelled by server", "poison message
14
+ * will be lost on nack", "Max retries exceeded, sending to DLQ", "Publish for
15
+ * retry failed; leaving original un-ack'd", "Failed to parse/validate message;
16
+ * sending to DLQ", and the channel's own `error`. Each of those is a fact an
17
+ * operator has no other way to learn: the first three are permanent outages
18
+ * this package's own `Serving` cannot see, and the last is where a poison
19
+ * stream goes — nacked before the handler middleware runs, so the `outcome`
20
+ * dimension a healthy-looking rate is read off never sees it.
21
+ *
22
+ * **Observers rather than the kernel's `Logger` port.** Forwarding `Logger`
23
+ * would put it in `amqp()`'s `Needs`, which is exactly the compile error the
24
+ * `instrumented` flag was deleted for: a root that wants a worker and no
25
+ * OpenTelemetry SDK should not be handed a port list. This costs a root
26
+ * nothing — the starter already injects `Observers` and contributes the no-op
27
+ * member — and a root composing `observability()` gets the lines for free.
28
+ *
29
+ * **`debug` and `info` are dropped, and that is the shape of the seam rather
30
+ * than a judgement about them.** An observer writes no line for a successful
31
+ * operation — the repository's own rule, and what keeps a per-request metric
32
+ * from also being a per-request line — so an `info` mapped to `outcome: "ok"`
33
+ * would be silently discarded anyway. Every diagnostic the issue named is a
34
+ * `warn` or an `error`, which is the half that survives.
35
+ *
36
+ * `traced: false`: these have no duration, and a zero-length span per broker
37
+ * line is noise in a trace rather than information.
38
+ */
39
+ const brokerLog = (observers) => {
40
+ const report = (level) => (message, context) => {
41
+ (0, _btravstack_core.observe)(observers, {
42
+ component: "amqp",
43
+ name: "broker",
44
+ attributes: { level },
45
+ details: { message },
46
+ traced: false
47
+ })({
48
+ outcome: "error",
49
+ attributes: {},
50
+ ...context?.error === void 0 ? {} : { cause: context.error }
51
+ });
52
+ };
53
+ const ignore = () => {};
54
+ return {
55
+ debug: ignore,
56
+ info: ignore,
57
+ warn: report("warn"),
58
+ error: report("error")
59
+ };
60
+ };
61
+ //#endregion
8
62
  //#region src/unit.ts
9
63
  /**
10
64
  * Where `messageUnits` leaves the forked context for the piece wrappers to read.
@@ -268,6 +322,7 @@ const createWorker = (host, config, options, handlers, observers) => _amqp_contr
268
322
  contract: options.contract,
269
323
  handlers,
270
324
  middleware: messageUnits(host, observers, options.unit?.message),
325
+ logger: brokerLog(observers),
271
326
  urls: [config.url],
272
327
  ...options.connectionOptions === void 0 ? {} : { connectionOptions: options.connectionOptions },
273
328
  ...options.defaultConsumerOptions === void 0 ? {} : { defaultConsumerOptions: options.defaultConsumerOptions },
package/dist/index.d.cts CHANGED
@@ -53,7 +53,7 @@ type AmqpMessageInstance = PortInstance<"AmqpMessage", unknown>;
53
53
  * at the type level, the move `AmqpHandlersPort` makes, so a module built for
54
54
  * one contract cannot read another's message.
55
55
  */
56
- declare const AmqpMessage: <C extends AnyAmqpContract>(contract: C) => AmqpMessagePortOf<C>;
56
+ export declare const AmqpMessage: <C extends AnyAmqpContract>(contract: C) => AmqpMessagePortOf<C>;
57
57
  /**
58
58
  * The port one piece targets. Its id carries the contract key, which is what
59
59
  * makes two slices claiming one consumer di's duplicate-provider defect rather
@@ -84,7 +84,7 @@ type MintedHandler<C extends AnyAmqpContract, K extends HandlerKeyOf<C>, N, U ex
84
84
  * of the fork the delivery opened; the root's `unit.message` module must export
85
85
  * every one of them.
86
86
  */
87
- declare const AmqpHandler: <C extends AnyAmqpContract, const K extends HandlerKeyOf<C>>(contract: C, key: K) => <const D extends Readonly<Record<string, AnyPort>>, const U extends Readonly<Record<string, AnyPort>> = Record<never, never>>(options: {
87
+ export declare const AmqpHandler: <C extends AnyAmqpContract, const K extends HandlerKeyOf<C>>(contract: C, key: K) => <const D extends Readonly<Record<string, AnyPort>>, const U extends Readonly<Record<string, AnyPort>> = Record<never, never>>(options: {
88
88
  readonly inject: D;
89
89
  /** The unit-scoped ports this handler reads off `context.unit`. */
90
90
  readonly unit?: U;
@@ -107,13 +107,13 @@ declare const AmqpConfig_base: import("@btravstack/di").PortClass<"AmqpConfig">;
107
107
  * unless pinned, and anything else in the graph may read it — a publisher
108
108
  * sharing the consumer's broker, say.
109
109
  */
110
- declare class AmqpConfig extends AmqpConfig_base<{
110
+ export declare class AmqpConfig extends AmqpConfig_base<{
111
111
  readonly url: string;
112
112
  /** How long `create` waits for the connection before failing. */
113
113
  readonly connectTimeoutMs: number;
114
114
  }> {}
115
115
  /** The runtime's port: what `amqp()` provides, and what the module `start` boots must export. */
116
- declare class AmqpRuntime extends RuntimePort<Runtime<never, AmqpInfo>> {}
116
+ export declare class AmqpRuntime extends RuntimePort<Runtime<never, AmqpInfo>> {}
117
117
  /**
118
118
  * A module `unit.message` may bind, as the upper bound `amqp()` constrains its
119
119
  * own `Unit` type parameter to. `Module`'s `_exports` channel is contravariant,
@@ -192,7 +192,7 @@ type AmqpTuning<Unit extends AnyUnitModule | undefined = undefined> = {
192
192
  *
193
193
  * With `url` pinned the module reads nothing from the environment.
194
194
  */
195
- declare const amqp: <TContract extends AnyAmqpContract, Unit extends AnyUnitModule | undefined = undefined>(options: AmqpOptions<TContract, Unit>) => Module<AmqpRuntime | AmqpConfig, ConfigInvalid, Env | HandlersInstanceOf<TContract> | UnitNeedsOf<Unit>>;
195
+ export declare const amqp: <TContract extends AnyAmqpContract, Unit extends AnyUnitModule | undefined = undefined>(options: AmqpOptions<TContract, Unit>) => Module<AmqpRuntime | AmqpConfig, ConfigInvalid, Env | HandlersInstanceOf<TContract> | UnitNeedsOf<Unit>>;
196
196
  /** One piece of the handlers record — what `AmqpHandler(contract, key)(…)` returns, as the composing form consumes it. */
197
197
  type PieceOf<C extends AnyAmqpContract> = { readonly [K in HandlerKeyOf<C>]: {
198
198
  readonly port: HandlerPortOf<C, K>;
@@ -276,7 +276,7 @@ type Compose<C extends AnyAmqpContract> = <const T extends readonly PieceOf<C>[]
276
276
  * record IS the handlers record. Every declared key must be covered, and two
277
277
  * slices claiming one key are di's duplicate-provider defect at build.
278
278
  */
279
- declare const AmqpHandlers: <C extends AnyAmqpContract>(contract: C) => Whole<C> & Compose<C>;
279
+ export declare const AmqpHandlers: <C extends AnyAmqpContract>(contract: C) => Whole<C> & Compose<C>;
280
280
  //#endregion
281
281
  //#region src/amqp-module.d.ts
282
282
  /** The starter's own module, as the sugar adds it to the application's imports. */
@@ -322,6 +322,6 @@ type AmqpModuleOptions<TContract extends AnyAmqpContract, HandlersError, Handler
322
322
  * await runMain(OrderAmqpWorker);
323
323
  * ```
324
324
  */
325
- declare const AmqpModule: <const Name extends string>(name: Name) => <TContract extends AnyAmqpContract, HandlersError, HandlersNeeds, Declared = never, Unit extends AnyUnitModule | undefined = undefined, const I extends readonly AnyModule[] = [], const P extends readonly AnyProvider[] = [], const X extends readonly Exportable<Imports<I, TContract, Unit>, Provides<P, TContract, HandlersError, HandlersNeeds>>[] = [], const N extends readonly AnyPort[] = []>(options: AmqpModuleOptions<TContract, HandlersError, HandlersNeeds, Declared, Unit, I, P, X, N>) => Module<(Extract<(readonly [typeof AmqpRuntime, ...X])[number], AnyModule> extends (infer T) ? T extends Extract<(readonly [typeof AmqpRuntime, ...X])[number], AnyModule> ? T extends Module<infer X_1, infer E, infer N_1> ? readonly [X_1, E, N_1] : never : never : never)[0] | ((readonly [typeof AmqpRuntime, ...X])[number] extends (infer E_1) ? E_1 extends AnyPort ? InstanceType<E_1> : E_1 extends AnyProvider ? InstanceType<E_1["port"]> : never : never), ((readonly [Provider<HandlersInstanceOf<TContract>, HandlersError, HandlersNeeds>, ...P])[number] extends (infer T_1) ? T_1 extends (readonly [Provider<HandlersInstanceOf<TContract>, HandlersError, HandlersNeeds>, ...P])[number] ? T_1 extends Provider<infer P_1, infer E_2, infer N_2> ? readonly [P_1, E_2, N_2] : never : never : never)[1] | ((readonly [...I, AmqpStarter<TContract, Unit>])[number] extends (infer T_2) ? T_2 extends (readonly [...I, AmqpStarter<TContract, Unit>])[number] ? T_2 extends Module<infer X_1, infer E, infer N_1> ? readonly [X_1, E, N_1] : never : never : never)[1], Exclude<((readonly [Provider<HandlersInstanceOf<TContract>, HandlersError, HandlersNeeds>, ...P])[number] extends (infer T_3) ? T_3 extends (readonly [Provider<HandlersInstanceOf<TContract>, HandlersError, HandlersNeeds>, ...P])[number] ? T_3 extends Provider<infer P_1, infer E_2, infer N_2> ? readonly [P_1, E_2, N_2] : never : never : never)[2], ((readonly [...I, AmqpStarter<TContract, Unit>])[number] extends (infer T_4) ? T_4 extends (readonly [...I, AmqpStarter<TContract, Unit>])[number] ? T_4 extends Module<infer X_1, infer E, infer N_1> ? readonly [X_1, E, N_1] : never : never : never)[0] | ((readonly [Provider<HandlersInstanceOf<TContract>, HandlersError, HandlersNeeds>, ...P])[number] extends (infer T_3) ? T_3 extends (readonly [Provider<HandlersInstanceOf<TContract>, HandlersError, HandlersNeeds>, ...P])[number] ? T_3 extends Provider<infer P_1, infer E_2, infer N_2> ? readonly [P_1, E_2, N_2] : never : never : never)[0]> | Exclude<((readonly [...I, AmqpStarter<TContract, Unit>])[number] extends (infer T_4) ? T_4 extends (readonly [...I, AmqpStarter<TContract, Unit>])[number] ? T_4 extends Module<infer X_1, infer E, infer N_1> ? readonly [X_1, E, N_1] : never : never : never)[2], ((readonly [...I, AmqpStarter<TContract, Unit>])[number] extends (infer T_4) ? T_4 extends (readonly [...I, AmqpStarter<TContract, Unit>])[number] ? T_4 extends Module<infer X_1, infer E, infer N_1> ? readonly [X_1, E, N_1] : never : never : never)[0] | ((readonly [Provider<HandlersInstanceOf<TContract>, HandlersError, HandlersNeeds>, ...P])[number] extends (infer T_3) ? T_3 extends (readonly [Provider<HandlersInstanceOf<TContract>, HandlersError, HandlersNeeds>, ...P])[number] ? T_3 extends Provider<infer P_1, infer E_2, infer N_2> ? readonly [P_1, E_2, N_2] : never : never : never)[0]>>;
325
+ export declare const AmqpModule: <const Name extends string>(name: Name) => <TContract extends AnyAmqpContract, HandlersError, HandlersNeeds, Declared = never, Unit extends AnyUnitModule | undefined = undefined, const I extends readonly AnyModule[] = [], const P extends readonly AnyProvider[] = [], const X extends readonly Exportable<Imports<I, TContract, Unit>, Provides<P, TContract, HandlersError, HandlersNeeds>>[] = [], const N extends readonly AnyPort[] = []>(options: AmqpModuleOptions<TContract, HandlersError, HandlersNeeds, Declared, Unit, I, P, X, N>) => Module<(Extract<(readonly [typeof AmqpRuntime, ...X])[number], AnyModule> extends (infer T) ? T extends Extract<(readonly [typeof AmqpRuntime, ...X])[number], AnyModule> ? T extends Module<infer X_1, infer E, infer N_1> ? readonly [X_1, E, N_1] : never : never : never)[0] | ((readonly [typeof AmqpRuntime, ...X])[number] extends (infer E_1) ? E_1 extends AnyPort ? InstanceType<E_1> : E_1 extends AnyProvider ? InstanceType<E_1["port"]> : never : never), ((readonly [Provider<HandlersInstanceOf<TContract>, HandlersError, HandlersNeeds>, ...P])[number] extends (infer T_1) ? T_1 extends (readonly [Provider<HandlersInstanceOf<TContract>, HandlersError, HandlersNeeds>, ...P])[number] ? T_1 extends Provider<infer P_1, infer E_2, infer N_2> ? readonly [P_1, E_2, N_2] : never : never : never)[1] | ((readonly [...I, AmqpStarter<TContract, Unit>])[number] extends (infer T_2) ? T_2 extends (readonly [...I, AmqpStarter<TContract, Unit>])[number] ? T_2 extends Module<infer X_1, infer E, infer N_1> ? readonly [X_1, E, N_1] : never : never : never)[1], Exclude<((readonly [Provider<HandlersInstanceOf<TContract>, HandlersError, HandlersNeeds>, ...P])[number] extends (infer T_3) ? T_3 extends (readonly [Provider<HandlersInstanceOf<TContract>, HandlersError, HandlersNeeds>, ...P])[number] ? T_3 extends Provider<infer P_1, infer E_2, infer N_2> ? readonly [P_1, E_2, N_2] : never : never : never)[2], ((readonly [...I, AmqpStarter<TContract, Unit>])[number] extends (infer T_4) ? T_4 extends (readonly [...I, AmqpStarter<TContract, Unit>])[number] ? T_4 extends Module<infer X_1, infer E, infer N_1> ? readonly [X_1, E, N_1] : never : never : never)[0] | ((readonly [Provider<HandlersInstanceOf<TContract>, HandlersError, HandlersNeeds>, ...P])[number] extends (infer T_3) ? T_3 extends (readonly [Provider<HandlersInstanceOf<TContract>, HandlersError, HandlersNeeds>, ...P])[number] ? T_3 extends Provider<infer P_1, infer E_2, infer N_2> ? readonly [P_1, E_2, N_2] : never : never : never)[0]> | Exclude<((readonly [...I, AmqpStarter<TContract, Unit>])[number] extends (infer T_4) ? T_4 extends (readonly [...I, AmqpStarter<TContract, Unit>])[number] ? T_4 extends Module<infer X_1, infer E, infer N_1> ? readonly [X_1, E, N_1] : never : never : never)[2], ((readonly [...I, AmqpStarter<TContract, Unit>])[number] extends (infer T_4) ? T_4 extends (readonly [...I, AmqpStarter<TContract, Unit>])[number] ? T_4 extends Module<infer X_1, infer E, infer N_1> ? readonly [X_1, E, N_1] : never : never : never)[0] | ((readonly [Provider<HandlersInstanceOf<TContract>, HandlersError, HandlersNeeds>, ...P])[number] extends (infer T_3) ? T_3 extends (readonly [Provider<HandlersInstanceOf<TContract>, HandlersError, HandlersNeeds>, ...P])[number] ? T_3 extends Provider<infer P_1, infer E_2, infer N_2> ? readonly [P_1, E_2, N_2] : never : never : never)[0]>>;
326
326
  //#endregion
327
- export { AmqpConfig, type AmqpConnectionOptions, AmqpHandler, AmqpHandlers, type AmqpInfo, AmqpMessage, type AmqpMessageOf, type AmqpMessagePortOf, AmqpModule, type AmqpModuleOptions, type AmqpOptions, AmqpRuntime, type HandlerPortOf, type HandlersInstanceOf, type HandlersPortOf, amqp };
327
+ export type { AmqpConnectionOptions, AmqpInfo, AmqpMessageOf, AmqpMessagePortOf, AmqpModuleOptions, AmqpOptions, HandlerPortOf, HandlersInstanceOf, HandlersPortOf };
package/dist/index.d.mts CHANGED
@@ -53,7 +53,7 @@ type AmqpMessageInstance = PortInstance<"AmqpMessage", unknown>;
53
53
  * at the type level, the move `AmqpHandlersPort` makes, so a module built for
54
54
  * one contract cannot read another's message.
55
55
  */
56
- declare const AmqpMessage: <C extends AnyAmqpContract>(contract: C) => AmqpMessagePortOf<C>;
56
+ export declare const AmqpMessage: <C extends AnyAmqpContract>(contract: C) => AmqpMessagePortOf<C>;
57
57
  /**
58
58
  * The port one piece targets. Its id carries the contract key, which is what
59
59
  * makes two slices claiming one consumer di's duplicate-provider defect rather
@@ -84,7 +84,7 @@ type MintedHandler<C extends AnyAmqpContract, K extends HandlerKeyOf<C>, N, U ex
84
84
  * of the fork the delivery opened; the root's `unit.message` module must export
85
85
  * every one of them.
86
86
  */
87
- declare const AmqpHandler: <C extends AnyAmqpContract, const K extends HandlerKeyOf<C>>(contract: C, key: K) => <const D extends Readonly<Record<string, AnyPort>>, const U extends Readonly<Record<string, AnyPort>> = Record<never, never>>(options: {
87
+ export declare const AmqpHandler: <C extends AnyAmqpContract, const K extends HandlerKeyOf<C>>(contract: C, key: K) => <const D extends Readonly<Record<string, AnyPort>>, const U extends Readonly<Record<string, AnyPort>> = Record<never, never>>(options: {
88
88
  readonly inject: D;
89
89
  /** The unit-scoped ports this handler reads off `context.unit`. */
90
90
  readonly unit?: U;
@@ -107,13 +107,13 @@ declare const AmqpConfig_base: import("@btravstack/di").PortClass<"AmqpConfig">;
107
107
  * unless pinned, and anything else in the graph may read it — a publisher
108
108
  * sharing the consumer's broker, say.
109
109
  */
110
- declare class AmqpConfig extends AmqpConfig_base<{
110
+ export declare class AmqpConfig extends AmqpConfig_base<{
111
111
  readonly url: string;
112
112
  /** How long `create` waits for the connection before failing. */
113
113
  readonly connectTimeoutMs: number;
114
114
  }> {}
115
115
  /** The runtime's port: what `amqp()` provides, and what the module `start` boots must export. */
116
- declare class AmqpRuntime extends RuntimePort<Runtime<never, AmqpInfo>> {}
116
+ export declare class AmqpRuntime extends RuntimePort<Runtime<never, AmqpInfo>> {}
117
117
  /**
118
118
  * A module `unit.message` may bind, as the upper bound `amqp()` constrains its
119
119
  * own `Unit` type parameter to. `Module`'s `_exports` channel is contravariant,
@@ -192,7 +192,7 @@ type AmqpTuning<Unit extends AnyUnitModule | undefined = undefined> = {
192
192
  *
193
193
  * With `url` pinned the module reads nothing from the environment.
194
194
  */
195
- declare const amqp: <TContract extends AnyAmqpContract, Unit extends AnyUnitModule | undefined = undefined>(options: AmqpOptions<TContract, Unit>) => Module<AmqpRuntime | AmqpConfig, ConfigInvalid, Env | HandlersInstanceOf<TContract> | UnitNeedsOf<Unit>>;
195
+ export declare const amqp: <TContract extends AnyAmqpContract, Unit extends AnyUnitModule | undefined = undefined>(options: AmqpOptions<TContract, Unit>) => Module<AmqpRuntime | AmqpConfig, ConfigInvalid, Env | HandlersInstanceOf<TContract> | UnitNeedsOf<Unit>>;
196
196
  /** One piece of the handlers record — what `AmqpHandler(contract, key)(…)` returns, as the composing form consumes it. */
197
197
  type PieceOf<C extends AnyAmqpContract> = { readonly [K in HandlerKeyOf<C>]: {
198
198
  readonly port: HandlerPortOf<C, K>;
@@ -276,7 +276,7 @@ type Compose<C extends AnyAmqpContract> = <const T extends readonly PieceOf<C>[]
276
276
  * record IS the handlers record. Every declared key must be covered, and two
277
277
  * slices claiming one key are di's duplicate-provider defect at build.
278
278
  */
279
- declare const AmqpHandlers: <C extends AnyAmqpContract>(contract: C) => Whole<C> & Compose<C>;
279
+ export declare const AmqpHandlers: <C extends AnyAmqpContract>(contract: C) => Whole<C> & Compose<C>;
280
280
  //#endregion
281
281
  //#region src/amqp-module.d.ts
282
282
  /** The starter's own module, as the sugar adds it to the application's imports. */
@@ -322,6 +322,6 @@ type AmqpModuleOptions<TContract extends AnyAmqpContract, HandlersError, Handler
322
322
  * await runMain(OrderAmqpWorker);
323
323
  * ```
324
324
  */
325
- declare const AmqpModule: <const Name extends string>(name: Name) => <TContract extends AnyAmqpContract, HandlersError, HandlersNeeds, Declared = never, Unit extends AnyUnitModule | undefined = undefined, const I extends readonly AnyModule[] = [], const P extends readonly AnyProvider[] = [], const X extends readonly Exportable<Imports<I, TContract, Unit>, Provides<P, TContract, HandlersError, HandlersNeeds>>[] = [], const N extends readonly AnyPort[] = []>(options: AmqpModuleOptions<TContract, HandlersError, HandlersNeeds, Declared, Unit, I, P, X, N>) => Module<(Extract<(readonly [typeof AmqpRuntime, ...X])[number], AnyModule> extends (infer T) ? T extends Extract<(readonly [typeof AmqpRuntime, ...X])[number], AnyModule> ? T extends Module<infer X_1, infer E, infer N_1> ? readonly [X_1, E, N_1] : never : never : never)[0] | ((readonly [typeof AmqpRuntime, ...X])[number] extends (infer E_1) ? E_1 extends AnyPort ? InstanceType<E_1> : E_1 extends AnyProvider ? InstanceType<E_1["port"]> : never : never), ((readonly [Provider<HandlersInstanceOf<TContract>, HandlersError, HandlersNeeds>, ...P])[number] extends (infer T_1) ? T_1 extends (readonly [Provider<HandlersInstanceOf<TContract>, HandlersError, HandlersNeeds>, ...P])[number] ? T_1 extends Provider<infer P_1, infer E_2, infer N_2> ? readonly [P_1, E_2, N_2] : never : never : never)[1] | ((readonly [...I, AmqpStarter<TContract, Unit>])[number] extends (infer T_2) ? T_2 extends (readonly [...I, AmqpStarter<TContract, Unit>])[number] ? T_2 extends Module<infer X_1, infer E, infer N_1> ? readonly [X_1, E, N_1] : never : never : never)[1], Exclude<((readonly [Provider<HandlersInstanceOf<TContract>, HandlersError, HandlersNeeds>, ...P])[number] extends (infer T_3) ? T_3 extends (readonly [Provider<HandlersInstanceOf<TContract>, HandlersError, HandlersNeeds>, ...P])[number] ? T_3 extends Provider<infer P_1, infer E_2, infer N_2> ? readonly [P_1, E_2, N_2] : never : never : never)[2], ((readonly [...I, AmqpStarter<TContract, Unit>])[number] extends (infer T_4) ? T_4 extends (readonly [...I, AmqpStarter<TContract, Unit>])[number] ? T_4 extends Module<infer X_1, infer E, infer N_1> ? readonly [X_1, E, N_1] : never : never : never)[0] | ((readonly [Provider<HandlersInstanceOf<TContract>, HandlersError, HandlersNeeds>, ...P])[number] extends (infer T_3) ? T_3 extends (readonly [Provider<HandlersInstanceOf<TContract>, HandlersError, HandlersNeeds>, ...P])[number] ? T_3 extends Provider<infer P_1, infer E_2, infer N_2> ? readonly [P_1, E_2, N_2] : never : never : never)[0]> | Exclude<((readonly [...I, AmqpStarter<TContract, Unit>])[number] extends (infer T_4) ? T_4 extends (readonly [...I, AmqpStarter<TContract, Unit>])[number] ? T_4 extends Module<infer X_1, infer E, infer N_1> ? readonly [X_1, E, N_1] : never : never : never)[2], ((readonly [...I, AmqpStarter<TContract, Unit>])[number] extends (infer T_4) ? T_4 extends (readonly [...I, AmqpStarter<TContract, Unit>])[number] ? T_4 extends Module<infer X_1, infer E, infer N_1> ? readonly [X_1, E, N_1] : never : never : never)[0] | ((readonly [Provider<HandlersInstanceOf<TContract>, HandlersError, HandlersNeeds>, ...P])[number] extends (infer T_3) ? T_3 extends (readonly [Provider<HandlersInstanceOf<TContract>, HandlersError, HandlersNeeds>, ...P])[number] ? T_3 extends Provider<infer P_1, infer E_2, infer N_2> ? readonly [P_1, E_2, N_2] : never : never : never)[0]>>;
325
+ export declare const AmqpModule: <const Name extends string>(name: Name) => <TContract extends AnyAmqpContract, HandlersError, HandlersNeeds, Declared = never, Unit extends AnyUnitModule | undefined = undefined, const I extends readonly AnyModule[] = [], const P extends readonly AnyProvider[] = [], const X extends readonly Exportable<Imports<I, TContract, Unit>, Provides<P, TContract, HandlersError, HandlersNeeds>>[] = [], const N extends readonly AnyPort[] = []>(options: AmqpModuleOptions<TContract, HandlersError, HandlersNeeds, Declared, Unit, I, P, X, N>) => Module<(Extract<(readonly [typeof AmqpRuntime, ...X])[number], AnyModule> extends (infer T) ? T extends Extract<(readonly [typeof AmqpRuntime, ...X])[number], AnyModule> ? T extends Module<infer X_1, infer E, infer N_1> ? readonly [X_1, E, N_1] : never : never : never)[0] | ((readonly [typeof AmqpRuntime, ...X])[number] extends (infer E_1) ? E_1 extends AnyPort ? InstanceType<E_1> : E_1 extends AnyProvider ? InstanceType<E_1["port"]> : never : never), ((readonly [Provider<HandlersInstanceOf<TContract>, HandlersError, HandlersNeeds>, ...P])[number] extends (infer T_1) ? T_1 extends (readonly [Provider<HandlersInstanceOf<TContract>, HandlersError, HandlersNeeds>, ...P])[number] ? T_1 extends Provider<infer P_1, infer E_2, infer N_2> ? readonly [P_1, E_2, N_2] : never : never : never)[1] | ((readonly [...I, AmqpStarter<TContract, Unit>])[number] extends (infer T_2) ? T_2 extends (readonly [...I, AmqpStarter<TContract, Unit>])[number] ? T_2 extends Module<infer X_1, infer E, infer N_1> ? readonly [X_1, E, N_1] : never : never : never)[1], Exclude<((readonly [Provider<HandlersInstanceOf<TContract>, HandlersError, HandlersNeeds>, ...P])[number] extends (infer T_3) ? T_3 extends (readonly [Provider<HandlersInstanceOf<TContract>, HandlersError, HandlersNeeds>, ...P])[number] ? T_3 extends Provider<infer P_1, infer E_2, infer N_2> ? readonly [P_1, E_2, N_2] : never : never : never)[2], ((readonly [...I, AmqpStarter<TContract, Unit>])[number] extends (infer T_4) ? T_4 extends (readonly [...I, AmqpStarter<TContract, Unit>])[number] ? T_4 extends Module<infer X_1, infer E, infer N_1> ? readonly [X_1, E, N_1] : never : never : never)[0] | ((readonly [Provider<HandlersInstanceOf<TContract>, HandlersError, HandlersNeeds>, ...P])[number] extends (infer T_3) ? T_3 extends (readonly [Provider<HandlersInstanceOf<TContract>, HandlersError, HandlersNeeds>, ...P])[number] ? T_3 extends Provider<infer P_1, infer E_2, infer N_2> ? readonly [P_1, E_2, N_2] : never : never : never)[0]> | Exclude<((readonly [...I, AmqpStarter<TContract, Unit>])[number] extends (infer T_4) ? T_4 extends (readonly [...I, AmqpStarter<TContract, Unit>])[number] ? T_4 extends Module<infer X_1, infer E, infer N_1> ? readonly [X_1, E, N_1] : never : never : never)[2], ((readonly [...I, AmqpStarter<TContract, Unit>])[number] extends (infer T_4) ? T_4 extends (readonly [...I, AmqpStarter<TContract, Unit>])[number] ? T_4 extends Module<infer X_1, infer E, infer N_1> ? readonly [X_1, E, N_1] : never : never : never)[0] | ((readonly [Provider<HandlersInstanceOf<TContract>, HandlersError, HandlersNeeds>, ...P])[number] extends (infer T_3) ? T_3 extends (readonly [Provider<HandlersInstanceOf<TContract>, HandlersError, HandlersNeeds>, ...P])[number] ? T_3 extends Provider<infer P_1, infer E_2, infer N_2> ? readonly [P_1, E_2, N_2] : never : never : never)[0]>>;
326
326
  //#endregion
327
- export { AmqpConfig, type AmqpConnectionOptions, AmqpHandler, AmqpHandlers, type AmqpInfo, AmqpMessage, type AmqpMessageOf, type AmqpMessagePortOf, AmqpModule, type AmqpModuleOptions, type AmqpOptions, AmqpRuntime, type HandlerPortOf, type HandlersInstanceOf, type HandlersPortOf, amqp };
327
+ export type { AmqpConnectionOptions, AmqpInfo, AmqpMessageOf, AmqpMessagePortOf, AmqpModuleOptions, AmqpOptions, HandlerPortOf, HandlersInstanceOf, HandlersPortOf };
package/dist/index.mjs CHANGED
@@ -4,6 +4,60 @@ import { Config, Env } from "@btravstack/config";
4
4
  import { Observers, RuntimePort, RuntimeStartFailed, noObserver, observe, releasedBy, traceIdOfTraceparent } from "@btravstack/core";
5
5
  import { P } from "unthrown";
6
6
  import { randomUUID } from "node:crypto";
7
+ //#region src/broker-log.ts
8
+ /**
9
+ * The library's own diagnostics, as operations on `Observers`.
10
+ *
11
+ * **`@amqp-contract/worker` takes a `logger` and was given none**, so every
12
+ * line it writes was discarded: "Consumer cancelled by server", "poison message
13
+ * will be lost on nack", "Max retries exceeded, sending to DLQ", "Publish for
14
+ * retry failed; leaving original un-ack'd", "Failed to parse/validate message;
15
+ * sending to DLQ", and the channel's own `error`. Each of those is a fact an
16
+ * operator has no other way to learn: the first three are permanent outages
17
+ * this package's own `Serving` cannot see, and the last is where a poison
18
+ * stream goes — nacked before the handler middleware runs, so the `outcome`
19
+ * dimension a healthy-looking rate is read off never sees it.
20
+ *
21
+ * **Observers rather than the kernel's `Logger` port.** Forwarding `Logger`
22
+ * would put it in `amqp()`'s `Needs`, which is exactly the compile error the
23
+ * `instrumented` flag was deleted for: a root that wants a worker and no
24
+ * OpenTelemetry SDK should not be handed a port list. This costs a root
25
+ * nothing — the starter already injects `Observers` and contributes the no-op
26
+ * member — and a root composing `observability()` gets the lines for free.
27
+ *
28
+ * **`debug` and `info` are dropped, and that is the shape of the seam rather
29
+ * than a judgement about them.** An observer writes no line for a successful
30
+ * operation — the repository's own rule, and what keeps a per-request metric
31
+ * from also being a per-request line — so an `info` mapped to `outcome: "ok"`
32
+ * would be silently discarded anyway. Every diagnostic the issue named is a
33
+ * `warn` or an `error`, which is the half that survives.
34
+ *
35
+ * `traced: false`: these have no duration, and a zero-length span per broker
36
+ * line is noise in a trace rather than information.
37
+ */
38
+ const brokerLog = (observers) => {
39
+ const report = (level) => (message, context) => {
40
+ observe(observers, {
41
+ component: "amqp",
42
+ name: "broker",
43
+ attributes: { level },
44
+ details: { message },
45
+ traced: false
46
+ })({
47
+ outcome: "error",
48
+ attributes: {},
49
+ ...context?.error === void 0 ? {} : { cause: context.error }
50
+ });
51
+ };
52
+ const ignore = () => {};
53
+ return {
54
+ debug: ignore,
55
+ info: ignore,
56
+ warn: report("warn"),
57
+ error: report("error")
58
+ };
59
+ };
60
+ //#endregion
7
61
  //#region src/unit.ts
8
62
  /**
9
63
  * Where `messageUnits` leaves the forked context for the piece wrappers to read.
@@ -267,6 +321,7 @@ const createWorker = (host, config, options, handlers, observers) => TypedAmqpWo
267
321
  contract: options.contract,
268
322
  handlers,
269
323
  middleware: messageUnits(host, observers, options.unit?.message),
324
+ logger: brokerLog(observers),
270
325
  urls: [config.url],
271
326
  ...options.connectionOptions === void 0 ? {} : { connectionOptions: options.connectionOptions },
272
327
  ...options.defaultConsumerOptions === void 0 ? {} : { defaultConsumerOptions: options.defaultConsumerOptions },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@btravstack/amqp-worker",
3
- "version": "0.13.0",
3
+ "version": "0.15.0",
4
4
  "description": "The AMQP starter for @btravstack/core: the handlers as a port, one unit per delivery, and a drain the kernel's deadline releases",
5
5
  "keywords": [
6
6
  "amqp",
@@ -47,29 +47,29 @@
47
47
  "@amqp-contract/contract": "3.0.0-beta.7",
48
48
  "@amqp-contract/testing": "3.0.0-beta.7",
49
49
  "@amqp-contract/worker": "3.0.0-beta.7",
50
+ "@btravstack/config": "0.15.0",
51
+ "@btravstack/core": "0.15.0",
52
+ "@btravstack/di": "0.15.0",
53
+ "@btravstack/internal-test-infra": "0.0.0",
54
+ "@btravstack/testing": "0.15.0",
50
55
  "@btravstack/tsconfig": "0.4.0",
51
56
  "@opentelemetry/api": "1.9.1",
52
- "@types/node": "26.4.0",
53
- "@unthrown/vitest": "5.7.0",
57
+ "@types/node": "26.4.1",
58
+ "@unthrown/vitest": "5.8.0",
54
59
  "@vitest/coverage-v8": "4.1.11",
55
- "tsdown": "0.22.14",
60
+ "tsdown": "0.23.0",
56
61
  "typescript": "7.0.2",
57
- "unthrown": "5.7.0",
62
+ "unthrown": "5.8.0",
58
63
  "vitest": "4.1.11",
59
- "zod": "4.5.3",
60
- "@btravstack/config": "0.13.0",
61
- "@btravstack/core": "0.13.0",
62
- "@btravstack/di": "0.13.0",
63
- "@btravstack/internal-test-infra": "0.0.0",
64
- "@btravstack/testing": "0.13.0"
64
+ "zod": "4.5.4"
65
65
  },
66
66
  "peerDependencies": {
67
67
  "@amqp-contract/worker": "^3.0.0-beta.7",
68
+ "@btravstack/config": "^0.15.0",
69
+ "@btravstack/core": "^0.15.0",
70
+ "@btravstack/di": "^0.15.0",
68
71
  "@opentelemetry/api": "^1",
69
- "unthrown": "^5.0.0",
70
- "@btravstack/config": "^0.13.0",
71
- "@btravstack/core": "^0.13.0",
72
- "@btravstack/di": "^0.13.0"
72
+ "unthrown": "^5.0.0"
73
73
  },
74
74
  "engines": {
75
75
  "node": ">=22"
@@ -78,7 +78,6 @@
78
78
  "build": "tsdown src/index.ts --format cjs,esm --dts --clean",
79
79
  "dev": "tsdown src/index.ts --format cjs,esm --dts --watch",
80
80
  "test": "vitest run --coverage",
81
- "test:types": "tsc --noEmit -p tsconfig.test-d.json",
82
81
  "typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.test-d.json"
83
82
  }
84
83
  }