@horizon-republic/nestjs-jetstream 2.9.1 → 2.10.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/dist/index.cjs CHANGED
@@ -29,6 +29,7 @@ var __decorateParam = (index, decorator) => (target, key) => decorator(target, k
29
29
  // src/index.ts
30
30
  var index_exports = {};
31
31
  __export(index_exports, {
32
+ ConsumeKind: () => ConsumeKind,
32
33
  DEFAULT_BROADCAST_CONSUMER_CONFIG: () => DEFAULT_BROADCAST_CONSUMER_CONFIG,
33
34
  DEFAULT_BROADCAST_STREAM_CONFIG: () => DEFAULT_BROADCAST_STREAM_CONFIG,
34
35
  DEFAULT_COMMAND_CONSUMER_CONFIG: () => DEFAULT_COMMAND_CONSUMER_CONFIG,
@@ -44,6 +45,7 @@ __export(index_exports, {
44
45
  DEFAULT_ORDERED_STREAM_CONFIG: () => DEFAULT_ORDERED_STREAM_CONFIG,
45
46
  DEFAULT_RPC_TIMEOUT: () => DEFAULT_RPC_TIMEOUT,
46
47
  DEFAULT_SHUTDOWN_TIMEOUT: () => DEFAULT_SHUTDOWN_TIMEOUT,
48
+ DEFAULT_TRACES: () => DEFAULT_TRACES,
47
49
  JETSTREAM_CODEC: () => JETSTREAM_CODEC,
48
50
  JETSTREAM_CONNECTION: () => JETSTREAM_CONNECTION,
49
51
  JETSTREAM_OPTIONS: () => JETSTREAM_OPTIONS,
@@ -55,15 +57,18 @@ __export(index_exports, {
55
57
  JetstreamRecord: () => JetstreamRecord,
56
58
  JetstreamRecordBuilder: () => JetstreamRecordBuilder,
57
59
  JetstreamStrategy: () => JetstreamStrategy,
60
+ JetstreamTrace: () => JetstreamTrace,
58
61
  JsonCodec: () => JsonCodec,
59
62
  MIN_METADATA_TTL: () => MIN_METADATA_TTL,
60
63
  MessageKind: () => MessageKind,
61
64
  MsgpackCodec: () => MsgpackCodec,
62
65
  NatsErrorCode: () => NatsErrorCode,
63
66
  PatternPrefix: () => PatternPrefix,
67
+ PublishKind: () => PublishKind,
64
68
  RESERVED_HEADERS: () => RESERVED_HEADERS,
65
69
  RpcContext: () => RpcContext,
66
70
  StreamKind: () => StreamKind,
71
+ TRACER_NAME: () => TRACER_NAME,
67
72
  TransportEvent: () => TransportEvent,
68
73
  buildBroadcastSubject: () => buildBroadcastSubject,
69
74
  buildSubject: () => buildSubject,
@@ -80,13 +85,14 @@ __export(index_exports, {
80
85
  module.exports = __toCommonJS(index_exports);
81
86
 
82
87
  // src/jetstream.module.ts
83
- var import_common14 = require("@nestjs/common");
88
+ var import_common18 = require("@nestjs/common");
84
89
 
85
90
  // src/client/jetstream.client.ts
86
- var import_common = require("@nestjs/common");
91
+ var import_common5 = require("@nestjs/common");
87
92
  var import_microservices = require("@nestjs/microservices");
88
- var import_transport_node = require("@nats-io/transport-node");
93
+ var import_api8 = require("@opentelemetry/api");
89
94
  var import_nuid = require("@nats-io/nuid");
95
+ var import_transport_node = require("@nats-io/transport-node");
90
96
 
91
97
  // src/interfaces/hooks.interface.ts
92
98
  var MessageKind = /* @__PURE__ */ ((MessageKind2) => {
@@ -276,6 +282,907 @@ var PatternPrefix = /* @__PURE__ */ ((PatternPrefix2) => {
276
282
  var isJetStreamRpcMode = (rpc) => rpc?.mode === "jetstream";
277
283
  var isCoreRpcMode = (rpc) => !rpc || rpc.mode === "core";
278
284
 
285
+ // src/otel/constants.ts
286
+ var TRACER_NAME = "@horizon-republic/nestjs-jetstream";
287
+
288
+ // src/otel/attribute-keys.ts
289
+ var ATTR_MESSAGING_SYSTEM = "messaging.system";
290
+ var ATTR_MESSAGING_DESTINATION_NAME = "messaging.destination.name";
291
+ var ATTR_MESSAGING_DESTINATION_TEMPLATE = "messaging.destination.template";
292
+ var ATTR_MESSAGING_CLIENT_ID = "messaging.client.id";
293
+ var ATTR_MESSAGING_OPERATION_NAME = "messaging.operation.name";
294
+ var ATTR_MESSAGING_OPERATION_TYPE = "messaging.operation.type";
295
+ var ATTR_MESSAGING_MESSAGE_BODY_SIZE = "messaging.message.body.size";
296
+ var ATTR_MESSAGING_MESSAGE_ID = "messaging.message.id";
297
+ var ATTR_MESSAGING_MESSAGE_CONVERSATION_ID = "messaging.message.conversation_id";
298
+ var ATTR_MESSAGING_CONSUMER_GROUP_NAME = "messaging.consumer.group.name";
299
+ var ATTR_MESSAGING_HEADER_PREFIX = "messaging.header.";
300
+ var ATTR_MESSAGING_NATS_STREAM_NAME = "messaging.nats.stream.name";
301
+ var ATTR_MESSAGING_NATS_STREAM_SEQUENCE = "messaging.nats.message.stream_sequence";
302
+ var ATTR_MESSAGING_NATS_CONSUMER_SEQUENCE = "messaging.nats.message.consumer_sequence";
303
+ var ATTR_MESSAGING_NATS_DELIVERY_COUNT = "messaging.nats.message.delivery_count";
304
+ var ATTR_MESSAGING_NATS_BODY = "messaging.nats.message.body";
305
+ var ATTR_MESSAGING_NATS_BODY_TRUNCATED = "messaging.nats.message.body.truncated";
306
+ var ATTR_SERVER_ADDRESS = "server.address";
307
+ var ATTR_SERVER_PORT = "server.port";
308
+ var ATTR_JETSTREAM_SERVICE_NAME = "jetstream.service.name";
309
+ var ATTR_JETSTREAM_KIND = "jetstream.kind";
310
+ var ATTR_JETSTREAM_RPC_REPLY_HAS_ERROR = "jetstream.rpc.reply.has_error";
311
+ var ATTR_JETSTREAM_RPC_REPLY_ERROR_CODE = "jetstream.rpc.reply.error.code";
312
+ var ATTR_JETSTREAM_PROVISIONING_ENTITY = "jetstream.provisioning.entity";
313
+ var ATTR_JETSTREAM_PROVISIONING_ACTION = "jetstream.provisioning.action";
314
+ var ATTR_JETSTREAM_PROVISIONING_NAME = "jetstream.provisioning.name";
315
+ var ATTR_JETSTREAM_SELF_HEALING_REASON = "jetstream.self_healing.reason";
316
+ var ATTR_JETSTREAM_MIGRATION_REASON = "jetstream.migration.reason";
317
+ var ATTR_JETSTREAM_DEAD_LETTER_REASON = "jetstream.dead_letter.reason";
318
+ var ATTR_JETSTREAM_SCHEDULE_TARGET = "jetstream.schedule.target";
319
+ var ATTR_NATS_CONNECTION_SERVER = "nats.connection.server";
320
+ var NATS_MSG_ID_HEADER = "Nats-Msg-Id";
321
+ var HOOK_PUBLISH = "publishHook";
322
+ var HOOK_CONSUME = "consumeHook";
323
+ var HOOK_RESPONSE = "responseHook";
324
+ var SPAN_NAME_PUBLISH = "publish";
325
+ var SPAN_NAME_PROCESS = "process";
326
+ var SPAN_NAME_SEND = "send";
327
+ var SPAN_NAME_DEAD_LETTER = "dead_letter";
328
+ var SPAN_NAME_NATS_CONNECTION = "nats.connection";
329
+ var SPAN_NAME_JETSTREAM_SHUTDOWN = "jetstream.shutdown";
330
+ var SPAN_NAME_JETSTREAM_SELF_HEALING = "jetstream.self_healing";
331
+ var SPAN_NAME_JETSTREAM_MIGRATION = "jetstream.migration";
332
+ var SPAN_NAME_JETSTREAM_PROVISIONING_PREFIX = "jetstream.provisioning.";
333
+ var EVENT_CONNECTION_DISCONNECTED = "connection.disconnected";
334
+ var EVENT_CONNECTION_RECONNECTED = "connection.reconnected";
335
+ var messagingHeaderAttr = (headerName) => `${ATTR_MESSAGING_HEADER_PREFIX}${headerName.toLowerCase()}`;
336
+
337
+ // src/otel/trace-kinds.ts
338
+ var JetstreamTrace = /* @__PURE__ */ ((JetstreamTrace2) => {
339
+ JetstreamTrace2["Publish"] = "publish";
340
+ JetstreamTrace2["Consume"] = "consume";
341
+ JetstreamTrace2["RpcClientSend"] = "rpc.client.send";
342
+ JetstreamTrace2["DeadLetter"] = "dead_letter";
343
+ JetstreamTrace2["ConnectionLifecycle"] = "connection.lifecycle";
344
+ JetstreamTrace2["SelfHealing"] = "self_healing";
345
+ JetstreamTrace2["Provisioning"] = "provisioning";
346
+ JetstreamTrace2["Migration"] = "migration";
347
+ JetstreamTrace2["Shutdown"] = "shutdown";
348
+ return JetstreamTrace2;
349
+ })(JetstreamTrace || {});
350
+ var DEFAULT_TRACES = [
351
+ "publish" /* Publish */,
352
+ "consume" /* Consume */,
353
+ "rpc.client.send" /* RpcClientSend */,
354
+ "dead_letter" /* DeadLetter */
355
+ ];
356
+
357
+ // src/otel/capture.ts
358
+ var NEGATION_PREFIX = "!";
359
+ var REGEX_SPECIAL_RE = /[.+?^${}()|[\]\\*]/gu;
360
+ var escapeForRegex = (input) => input.replace(REGEX_SPECIAL_RE, "\\$&");
361
+ var globToRegex = (glob) => {
362
+ const escaped = escapeForRegex(glob.toLowerCase()).replace(/\\\*/gu, ".*");
363
+ return new RegExp(`^${escaped}$`, "u");
364
+ };
365
+ var compileHeaderAllowlist = (allowlist) => {
366
+ if (allowlist === true) return () => true;
367
+ if (allowlist === false) return () => false;
368
+ if (allowlist.length === 0) return () => false;
369
+ const includes = [];
370
+ const excludes = [];
371
+ for (const pattern of allowlist) {
372
+ const isExclude = pattern.startsWith(NEGATION_PREFIX);
373
+ const body = isExclude ? pattern.slice(NEGATION_PREFIX.length) : pattern;
374
+ const regex = globToRegex(body);
375
+ if (isExclude) excludes.push(regex);
376
+ else includes.push(regex);
377
+ }
378
+ return (name) => {
379
+ const lower = name.toLowerCase();
380
+ if (!includes.some((re) => re.test(lower))) return false;
381
+ if (excludes.some((re) => re.test(lower))) return false;
382
+ return true;
383
+ };
384
+ };
385
+ var subjectMatcherCache = /* @__PURE__ */ new WeakMap();
386
+ var compileSubjectAllowlist = (allowlist) => {
387
+ if (!allowlist || allowlist.length === 0) return () => true;
388
+ const cached = subjectMatcherCache.get(allowlist);
389
+ if (cached) return cached;
390
+ const regexes = allowlist.map(globToRegex);
391
+ const matcher = (subject) => {
392
+ const lower = subject.toLowerCase();
393
+ return regexes.some((re) => re.test(lower));
394
+ };
395
+ subjectMatcherCache.set(allowlist, matcher);
396
+ return matcher;
397
+ };
398
+ var subjectMatchesAllowlist = (subject, allowlist) => compileSubjectAllowlist(allowlist)(subject);
399
+ var HEADER_DENYLIST = /* @__PURE__ */ new Set([
400
+ "traceparent",
401
+ "tracestate",
402
+ "baggage",
403
+ "sentry-trace",
404
+ "b3",
405
+ "x-b3-traceid",
406
+ "x-b3-spanid",
407
+ "x-b3-parentspanid",
408
+ "x-b3-sampled",
409
+ "x-b3-flags",
410
+ "uber-trace-id",
411
+ "x-correlation-id",
412
+ "x-reply-to",
413
+ "x-error",
414
+ "x-subject",
415
+ "x-caller-name"
416
+ ]);
417
+ var isNatsServerHeader = (lower) => lower.startsWith("nats-");
418
+ var captureMatchingHeaders = (headers2, matcher) => {
419
+ if (!headers2) return {};
420
+ const out = {};
421
+ for (const key of headers2.keys()) {
422
+ const lower = key.toLowerCase();
423
+ if (HEADER_DENYLIST.has(lower)) continue;
424
+ if (isNatsServerHeader(lower)) continue;
425
+ if (!matcher(key)) continue;
426
+ const value = headers2.get(key);
427
+ if (value === "") continue;
428
+ out[messagingHeaderAttr(lower)] = value;
429
+ }
430
+ return out;
431
+ };
432
+ var tryUtf8Decode = (bytes) => {
433
+ try {
434
+ return new TextDecoder("utf-8", { fatal: false }).decode(bytes);
435
+ } catch {
436
+ return Buffer.from(bytes).toString("base64");
437
+ }
438
+ };
439
+ var captureBodyAttribute = (subject, payload, capture) => {
440
+ if (capture === false) return {};
441
+ if (payload.byteLength === 0) return {};
442
+ if (!subjectMatchesAllowlist(subject, capture.subjectAllowlist)) return {};
443
+ const { maxBytes } = capture;
444
+ const truncated = payload.byteLength > maxBytes;
445
+ const slice = truncated ? payload.subarray(0, maxBytes) : payload;
446
+ const decoded = tryUtf8Decode(slice);
447
+ const out = { [ATTR_MESSAGING_NATS_BODY]: decoded };
448
+ if (truncated) out[ATTR_MESSAGING_NATS_BODY_TRUNCATED] = true;
449
+ return out;
450
+ };
451
+
452
+ // src/otel/config.ts
453
+ var PublishKind = /* @__PURE__ */ ((PublishKind2) => {
454
+ PublishKind2["Event"] = "event";
455
+ PublishKind2["RpcRequest"] = "rpc.request";
456
+ PublishKind2["Broadcast"] = "broadcast";
457
+ PublishKind2["Ordered"] = "ordered";
458
+ return PublishKind2;
459
+ })(PublishKind || {});
460
+ var ConsumeKind = /* @__PURE__ */ ((ConsumeKind2) => {
461
+ ConsumeKind2["Event"] = "event";
462
+ ConsumeKind2["Rpc"] = "rpc";
463
+ ConsumeKind2["Broadcast"] = "broadcast";
464
+ ConsumeKind2["Ordered"] = "ordered";
465
+ return ConsumeKind2;
466
+ })(ConsumeKind || {});
467
+ var DEFAULT_CAPTURE_HEADERS = ["x-request-id"];
468
+ var DEFAULT_CAPTURE_BODY_MAX_BYTES = 4096;
469
+ var NESTJS_BARE_ERROR_MESSAGE = "Internal server error";
470
+ var isNestjsBareErrorSentinel = (obj) => obj.status === "error" && obj.message === NESTJS_BARE_ERROR_MESSAGE;
471
+ var defaultErrorClassifier = (err) => {
472
+ if (err === null || typeof err !== "object") return "unexpected";
473
+ if (!(err instanceof Error)) {
474
+ if (isNestjsBareErrorSentinel(err)) return "unexpected";
475
+ return "expected";
476
+ }
477
+ let proto = err;
478
+ while (proto) {
479
+ const name = proto.constructor?.name;
480
+ if (name === "RpcException" || name === "HttpException") return "expected";
481
+ proto = Object.getPrototypeOf(proto);
482
+ }
483
+ return "unexpected";
484
+ };
485
+ var expandTracesOption = (option) => {
486
+ if (option === void 0 || option === "default") return new Set(DEFAULT_TRACES);
487
+ if (option === "all") return new Set(Object.values(JetstreamTrace));
488
+ if (option === "none") return /* @__PURE__ */ new Set();
489
+ return new Set(option);
490
+ };
491
+ var compileHeaderMatcher = (option) => compileHeaderAllowlist(option ?? DEFAULT_CAPTURE_HEADERS);
492
+ var resolveCaptureBody = (option) => {
493
+ if (option === void 0 || option === false) return false;
494
+ if (option === true) return { maxBytes: DEFAULT_CAPTURE_BODY_MAX_BYTES };
495
+ return {
496
+ maxBytes: option.maxBytes ?? DEFAULT_CAPTURE_BODY_MAX_BYTES,
497
+ subjectAllowlist: option.subjectAllowlist
498
+ };
499
+ };
500
+ var resolveOtelOptions = (options = {}) => {
501
+ return {
502
+ enabled: options.enabled ?? true,
503
+ traces: expandTracesOption(options.traces),
504
+ captureHeaders: compileHeaderMatcher(options.captureHeaders),
505
+ captureBody: resolveCaptureBody(options.captureBody),
506
+ publishHook: options.publishHook,
507
+ consumeHook: options.consumeHook,
508
+ responseHook: options.responseHook,
509
+ shouldTracePublish: options.shouldTracePublish,
510
+ shouldTraceConsume: options.shouldTraceConsume,
511
+ errorClassifier: options.errorClassifier ?? defaultErrorClassifier
512
+ };
513
+ };
514
+
515
+ // src/otel/internal-utils.ts
516
+ var import_common = require("@nestjs/common");
517
+ var logger = new import_common.Logger("Jetstream:Otel");
518
+ var safelyInvokeHook = (hookName, hook, ...args) => {
519
+ if (!hook) return;
520
+ const logHookFailure = (err) => {
521
+ const message = err instanceof Error ? err.message : String(err);
522
+ logger.debug(`OTel ${hookName} threw: ${message}`);
523
+ };
524
+ try {
525
+ const result = hook(...args);
526
+ if (result !== null && typeof result === "object" && "then" in result && typeof result.then === "function") {
527
+ result.then(void 0, logHookFailure);
528
+ }
529
+ } catch (err) {
530
+ logHookFailure(err);
531
+ }
532
+ };
533
+ var stripIpv6Brackets = (host) => host.startsWith("[") && host.endsWith("]") ? host.slice(1, -1) : host;
534
+ var parsePort = (portRaw) => {
535
+ if (!portRaw) return void 0;
536
+ const port = Number.parseInt(portRaw, 10);
537
+ return Number.isInteger(port) ? port : void 0;
538
+ };
539
+ var parseServerAddress = (servers) => {
540
+ const raw = servers[0];
541
+ if (!raw) return null;
542
+ if (raw.includes("://")) {
543
+ try {
544
+ const url = new URL(raw);
545
+ if (url.hostname.length === 0) return null;
546
+ const host2 = stripIpv6Brackets(url.hostname);
547
+ const port2 = parsePort(url.port || void 0);
548
+ return port2 === void 0 ? { host: host2 } : { host: host2, port: port2 };
549
+ } catch {
550
+ return null;
551
+ }
552
+ }
553
+ if (raw.startsWith("[")) {
554
+ const closeIdx = raw.indexOf("]");
555
+ if (closeIdx <= 0) return null;
556
+ const host2 = raw.slice(1, closeIdx);
557
+ const port2 = parsePort(raw.slice(closeIdx + 1).replace(/^:/u, ""));
558
+ return port2 === void 0 ? { host: host2 } : { host: host2, port: port2 };
559
+ }
560
+ const [host, portRaw] = raw.split(":");
561
+ if (!host) return null;
562
+ const port = parsePort(portRaw);
563
+ return port === void 0 ? { host } : { host, port };
564
+ };
565
+ var deriveOtelAttrs = (options) => ({
566
+ otel: resolveOtelOptions(options.otel),
567
+ serviceName: internalName(options.name),
568
+ serverEndpoint: parseServerAddress(options.servers)
569
+ });
570
+
571
+ // src/otel/propagator.ts
572
+ var import_api = require("@opentelemetry/api");
573
+ var injectContext = (ctx, carrier, setter) => {
574
+ import_api.propagation.inject(ctx, carrier, setter);
575
+ };
576
+ var extractContext = (ctx, carrier, getter) => import_api.propagation.extract(ctx, carrier, getter);
577
+
578
+ // src/otel/tracer.ts
579
+ var import_api2 = require("@opentelemetry/api");
580
+ var PACKAGE_VERSION = true ? "2.10.0" : "0.0.0";
581
+ var getTracer = () => import_api2.trace.getTracer(TRACER_NAME, PACKAGE_VERSION);
582
+
583
+ // src/otel/carrier.ts
584
+ var hdrsSetter = {
585
+ set: (headers2, key, value) => {
586
+ headers2.set(key, value);
587
+ }
588
+ };
589
+ var hdrsGetter = {
590
+ keys: (headers2) => headers2 ? headers2.keys() : [],
591
+ get: (headers2, key) => {
592
+ if (!headers2) return void 0;
593
+ const all = typeof headers2.values === "function" ? headers2.values(key) : void 0;
594
+ if (Array.isArray(all)) {
595
+ const nonEmpty = all.filter((value) => value !== "");
596
+ if (nonEmpty.length === 0) return void 0;
597
+ return nonEmpty.join(",");
598
+ }
599
+ const single = headers2.get(key);
600
+ return single === "" ? void 0 : single;
601
+ }
602
+ };
603
+
604
+ // src/otel/attributes.ts
605
+ var MESSAGING_SYSTEM = "nats";
606
+ var baseMessagingAttributes = (ctx) => {
607
+ const attrs = {
608
+ [ATTR_MESSAGING_SYSTEM]: MESSAGING_SYSTEM,
609
+ [ATTR_MESSAGING_DESTINATION_NAME]: ctx.subject,
610
+ [ATTR_MESSAGING_CLIENT_ID]: ctx.serviceName
611
+ };
612
+ if (ctx.serverAddress) attrs[ATTR_SERVER_ADDRESS] = ctx.serverAddress;
613
+ if (ctx.serverPort !== void 0) attrs[ATTR_SERVER_PORT] = ctx.serverPort;
614
+ if (ctx.pattern && ctx.pattern !== ctx.subject) {
615
+ attrs[ATTR_MESSAGING_DESTINATION_TEMPLATE] = ctx.pattern;
616
+ }
617
+ return attrs;
618
+ };
619
+ var jetstreamKindForPublish = (kind) => kind === "rpc.request" /* RpcRequest */ ? "rpc" /* Rpc */ : kind;
620
+ var buildPublishAttributes = (ctx) => {
621
+ const attrs = {
622
+ ...baseMessagingAttributes(ctx),
623
+ [ATTR_MESSAGING_OPERATION_NAME]: SPAN_NAME_PUBLISH,
624
+ [ATTR_MESSAGING_OPERATION_TYPE]: SPAN_NAME_SEND,
625
+ [ATTR_MESSAGING_MESSAGE_BODY_SIZE]: ctx.payloadBytes,
626
+ [ATTR_JETSTREAM_KIND]: jetstreamKindForPublish(ctx.kind)
627
+ };
628
+ if (ctx.messageId) attrs[ATTR_MESSAGING_MESSAGE_ID] = ctx.messageId;
629
+ if (ctx.correlationId) attrs[ATTR_MESSAGING_MESSAGE_CONVERSATION_ID] = ctx.correlationId;
630
+ return attrs;
631
+ };
632
+ var buildConsumeAttributes = (ctx) => {
633
+ const { msg, info, kind, payloadBytes } = ctx;
634
+ const attrs = {
635
+ ...baseMessagingAttributes(ctx),
636
+ [ATTR_MESSAGING_OPERATION_NAME]: SPAN_NAME_PROCESS,
637
+ [ATTR_MESSAGING_OPERATION_TYPE]: SPAN_NAME_PROCESS,
638
+ [ATTR_MESSAGING_MESSAGE_BODY_SIZE]: payloadBytes,
639
+ [ATTR_JETSTREAM_KIND]: kind
640
+ };
641
+ if (info) {
642
+ attrs[ATTR_MESSAGING_NATS_STREAM_NAME] = info.stream;
643
+ attrs[ATTR_MESSAGING_CONSUMER_GROUP_NAME] = info.consumer;
644
+ attrs[ATTR_MESSAGING_NATS_STREAM_SEQUENCE] = info.streamSequence;
645
+ attrs[ATTR_MESSAGING_NATS_CONSUMER_SEQUENCE] = info.deliverySequence;
646
+ attrs[ATTR_MESSAGING_NATS_DELIVERY_COUNT] = info.deliveryCount;
647
+ }
648
+ const messageId = msg.headers?.get(NATS_MSG_ID_HEADER);
649
+ if (messageId) attrs[ATTR_MESSAGING_MESSAGE_ID] = messageId;
650
+ return attrs;
651
+ };
652
+ var buildRpcClientAttributes = (ctx) => {
653
+ const attrs = {
654
+ ...baseMessagingAttributes(ctx),
655
+ [ATTR_MESSAGING_OPERATION_NAME]: SPAN_NAME_SEND,
656
+ [ATTR_MESSAGING_OPERATION_TYPE]: SPAN_NAME_SEND,
657
+ [ATTR_MESSAGING_MESSAGE_BODY_SIZE]: ctx.payloadBytes,
658
+ [ATTR_JETSTREAM_KIND]: "rpc" /* Rpc */
659
+ };
660
+ if (ctx.correlationId) attrs[ATTR_MESSAGING_MESSAGE_CONVERSATION_ID] = ctx.correlationId;
661
+ if (ctx.messageId) attrs[ATTR_MESSAGING_MESSAGE_ID] = ctx.messageId;
662
+ return attrs;
663
+ };
664
+ var buildDeadLetterAttributes = (ctx) => {
665
+ const attrs = {
666
+ ...baseMessagingAttributes(ctx),
667
+ [ATTR_MESSAGING_OPERATION_NAME]: SPAN_NAME_DEAD_LETTER,
668
+ [ATTR_MESSAGING_OPERATION_TYPE]: SPAN_NAME_PROCESS,
669
+ [ATTR_MESSAGING_NATS_DELIVERY_COUNT]: ctx.finalDeliveryCount
670
+ };
671
+ if (ctx.reason) attrs[ATTR_JETSTREAM_DEAD_LETTER_REASON] = ctx.reason;
672
+ return attrs;
673
+ };
674
+ var extractFromRpcException = (record) => {
675
+ const getError = record.getError;
676
+ if (typeof getError !== "function") return void 0;
677
+ return codeFromPayload(getError.call(record));
678
+ };
679
+ var extractFromHttpException = (record) => {
680
+ const getStatus = record.getStatus;
681
+ if (typeof getStatus !== "function") return void 0;
682
+ const status = getStatus.call(record);
683
+ return typeof status === "number" && Number.isFinite(status) ? `HTTP_${status}` : void 0;
684
+ };
685
+ var extractFromOwnCode = (record) => {
686
+ const code = record.code ?? record.errorCode;
687
+ return typeof code === "string" && isStableErrorCode(code) ? code : void 0;
688
+ };
689
+ var extractExpectedErrorCode = (err) => {
690
+ if (err === null || typeof err !== "object") return void 0;
691
+ const record = err;
692
+ if (hasAncestorNamed(err, "RpcException")) {
693
+ const fromPayload = extractFromRpcException(record);
694
+ if (fromPayload !== void 0) return fromPayload;
695
+ }
696
+ if (hasAncestorNamed(err, "HttpException")) {
697
+ const fromStatus = extractFromHttpException(record);
698
+ if (fromStatus !== void 0) return fromStatus;
699
+ }
700
+ return extractFromOwnCode(record);
701
+ };
702
+ var hasAncestorNamed = (err, name) => {
703
+ let proto = Object.getPrototypeOf(err);
704
+ while (proto) {
705
+ const ctorName = proto.constructor?.name;
706
+ if (ctorName === name) return true;
707
+ proto = Object.getPrototypeOf(proto);
708
+ }
709
+ return false;
710
+ };
711
+ var STABLE_ERROR_CODE_RE = /^[A-Z][A-Z0-9_]*$/u;
712
+ var isStableErrorCode = (value) => STABLE_ERROR_CODE_RE.test(value);
713
+ var codeFromPayload = (payload) => {
714
+ if (payload === null || payload === void 0) return void 0;
715
+ if (typeof payload === "string") return isStableErrorCode(payload) ? payload : void 0;
716
+ if (typeof payload === "object") {
717
+ const code = payload.code;
718
+ if (typeof code === "string" && isStableErrorCode(code)) return code;
719
+ }
720
+ return void 0;
721
+ };
722
+ var buildExpectedErrorAttributes = (err) => {
723
+ const attrs = {
724
+ [ATTR_JETSTREAM_RPC_REPLY_HAS_ERROR]: true
725
+ };
726
+ const code = extractExpectedErrorCode(err);
727
+ if (code !== void 0) attrs[ATTR_JETSTREAM_RPC_REPLY_ERROR_CODE] = code;
728
+ return attrs;
729
+ };
730
+ var applyExpectedErrorAttributes = (span, err) => {
731
+ span.setAttributes(buildExpectedErrorAttributes(err));
732
+ };
733
+
734
+ // src/otel/spans/publish.ts
735
+ var import_common2 = require("@nestjs/common");
736
+ var import_api3 = require("@opentelemetry/api");
737
+ var logger2 = new import_common2.Logger("Jetstream:Otel");
738
+ var shouldTracePublishSafe = (predicate, subject, record) => {
739
+ if (!predicate) return true;
740
+ try {
741
+ return predicate(subject, record);
742
+ } catch (err) {
743
+ const message = err instanceof Error ? err.message : String(err);
744
+ logger2.debug(`OTel shouldTracePublish threw: ${message}`);
745
+ return true;
746
+ }
747
+ };
748
+ var withPublishSpan = async (ctx, config, fn) => {
749
+ if (!config.enabled) return fn();
750
+ const shouldCreateSpan = config.traces.has("publish" /* Publish */) && shouldTracePublishSafe(config.shouldTracePublish, ctx.subject, ctx.record);
751
+ if (!shouldCreateSpan) {
752
+ injectContext(import_api3.context.active(), ctx.headers, hdrsSetter);
753
+ return fn();
754
+ }
755
+ const tracer = getTracer();
756
+ const span = tracer.startSpan(`${SPAN_NAME_PUBLISH} ${ctx.subject}`, {
757
+ kind: import_api3.SpanKind.PRODUCER,
758
+ attributes: {
759
+ ...buildPublishAttributes({
760
+ subject: ctx.subject,
761
+ pattern: ctx.pattern,
762
+ serviceName: ctx.serviceName,
763
+ serverAddress: ctx.endpoint?.host,
764
+ serverPort: ctx.endpoint?.port,
765
+ kind: ctx.kind,
766
+ payloadBytes: ctx.payloadBytes,
767
+ messageId: ctx.messageId,
768
+ correlationId: ctx.correlationId
769
+ }),
770
+ ...ctx.scheduleTarget ? { [ATTR_JETSTREAM_SCHEDULE_TARGET]: ctx.scheduleTarget } : {},
771
+ ...captureMatchingHeaders(ctx.headers, config.captureHeaders),
772
+ ...captureBodyAttribute(ctx.subject, ctx.payload, config.captureBody)
773
+ }
774
+ });
775
+ const ctxWithSpan = import_api3.trace.setSpan(import_api3.context.active(), span);
776
+ injectContext(ctxWithSpan, ctx.headers, hdrsSetter);
777
+ const start = Date.now();
778
+ const invokeResponseHook = (error) => {
779
+ import_api3.context.with(ctxWithSpan, () => {
780
+ safelyInvokeHook(HOOK_RESPONSE, config.responseHook, span, {
781
+ subject: ctx.subject,
782
+ durationMs: Date.now() - start,
783
+ error
784
+ });
785
+ });
786
+ };
787
+ try {
788
+ const result = await import_api3.context.with(ctxWithSpan, async () => {
789
+ safelyInvokeHook(HOOK_PUBLISH, config.publishHook, span, {
790
+ subject: ctx.subject,
791
+ record: ctx.record,
792
+ kind: ctx.kind
793
+ });
794
+ return fn();
795
+ });
796
+ span.setStatus({ code: import_api3.SpanStatusCode.OK });
797
+ invokeResponseHook();
798
+ return result;
799
+ } catch (err) {
800
+ const error = err instanceof Error ? err : new Error(String(err));
801
+ span.recordException(error);
802
+ span.setStatus({ code: import_api3.SpanStatusCode.ERROR, message: error.message });
803
+ invokeResponseHook(error);
804
+ throw err;
805
+ } finally {
806
+ span.end();
807
+ }
808
+ };
809
+
810
+ // src/otel/spans/consume.ts
811
+ var import_api4 = require("@opentelemetry/api");
812
+ var isPromiseLike = (value) => typeof value === "object" && value !== null && typeof value.then === "function";
813
+ var applyExpectedError = (span, err) => {
814
+ span.setStatus({ code: import_api4.SpanStatusCode.OK });
815
+ applyExpectedErrorAttributes(span, err);
816
+ };
817
+ var applyUnexpectedError = (span, err) => {
818
+ const error = err instanceof Error ? err : new Error(String(err));
819
+ span.recordException(error);
820
+ span.setStatus({ code: import_api4.SpanStatusCode.ERROR, message: error.message });
821
+ };
822
+ var withConsumeSpan = (ctx, config, fn, options = {}) => {
823
+ if (!config.enabled) return fn();
824
+ const parentCtx = extractContext(import_api4.ROOT_CONTEXT, ctx.msg.headers, hdrsGetter);
825
+ const shouldCreateSpan = config.traces.has("consume" /* Consume */) && (config.shouldTraceConsume?.(ctx.subject, ctx.msg) ?? true);
826
+ if (!shouldCreateSpan) {
827
+ return import_api4.context.with(parentCtx, fn);
828
+ }
829
+ const tracer = getTracer();
830
+ const span = tracer.startSpan(
831
+ `${SPAN_NAME_PROCESS} ${ctx.subject}`,
832
+ {
833
+ kind: import_api4.SpanKind.CONSUMER,
834
+ attributes: {
835
+ ...buildConsumeAttributes({
836
+ subject: ctx.subject,
837
+ pattern: ctx.pattern,
838
+ msg: ctx.msg,
839
+ info: ctx.info,
840
+ kind: ctx.kind,
841
+ payloadBytes: ctx.payloadBytes,
842
+ serviceName: ctx.serviceName,
843
+ serverAddress: ctx.endpoint?.host,
844
+ serverPort: ctx.endpoint?.port
845
+ }),
846
+ ...captureMatchingHeaders(ctx.msg.headers, config.captureHeaders),
847
+ ...captureBodyAttribute(ctx.subject, ctx.msg.data, config.captureBody)
848
+ }
849
+ },
850
+ parentCtx
851
+ );
852
+ const ctxWithSpan = import_api4.trace.setSpan(parentCtx, span);
853
+ const start = Date.now();
854
+ let finalized = false;
855
+ const { signal, timeoutLabel = "handler.timeout" } = options;
856
+ let detachAbort = null;
857
+ const invokeResponseHook = (durationMs, error) => {
858
+ import_api4.context.with(ctxWithSpan, () => {
859
+ safelyInvokeHook(HOOK_RESPONSE, config.responseHook, span, {
860
+ subject: ctx.subject,
861
+ durationMs,
862
+ error
863
+ });
864
+ });
865
+ };
866
+ const finishOk2 = () => {
867
+ if (finalized) return;
868
+ finalized = true;
869
+ detachAbort?.();
870
+ span.setStatus({ code: import_api4.SpanStatusCode.OK });
871
+ invokeResponseHook(Date.now() - start);
872
+ span.end();
873
+ };
874
+ const finishError2 = (err) => {
875
+ if (finalized) return;
876
+ finalized = true;
877
+ detachAbort?.();
878
+ let classification = "unexpected";
879
+ try {
880
+ classification = config.errorClassifier(err);
881
+ } catch {
882
+ }
883
+ if (classification === "expected") {
884
+ applyExpectedError(span, err);
885
+ } else {
886
+ applyUnexpectedError(span, err);
887
+ }
888
+ invokeResponseHook(Date.now() - start, err instanceof Error ? err : new Error(String(err)));
889
+ span.end();
890
+ };
891
+ const onAbort = () => {
892
+ if (finalized) return;
893
+ finalized = true;
894
+ const error = new Error(timeoutLabel);
895
+ span.addEvent(timeoutLabel);
896
+ span.recordException(error);
897
+ span.setStatus({ code: import_api4.SpanStatusCode.ERROR, message: timeoutLabel });
898
+ invokeResponseHook(Date.now() - start, error);
899
+ span.end();
900
+ };
901
+ if (signal) {
902
+ if (signal.aborted) {
903
+ onAbort();
904
+ } else {
905
+ signal.addEventListener("abort", onAbort, { once: true });
906
+ detachAbort = () => {
907
+ signal.removeEventListener("abort", onAbort);
908
+ };
909
+ }
910
+ }
911
+ let result;
912
+ try {
913
+ result = import_api4.context.with(ctxWithSpan, () => {
914
+ safelyInvokeHook(HOOK_CONSUME, config.consumeHook, span, {
915
+ subject: ctx.subject,
916
+ msg: ctx.msg,
917
+ handlerMetadata: ctx.handlerMetadata,
918
+ kind: ctx.kind
919
+ });
920
+ return fn();
921
+ });
922
+ } catch (err) {
923
+ finishError2(err);
924
+ throw err;
925
+ }
926
+ if (isPromiseLike(result)) {
927
+ return Promise.resolve(result).then(
928
+ (value) => {
929
+ finishOk2();
930
+ return value;
931
+ },
932
+ (err) => {
933
+ finishError2(err);
934
+ throw err;
935
+ }
936
+ );
937
+ }
938
+ finishOk2();
939
+ return result;
940
+ };
941
+
942
+ // src/otel/spans/rpc-client.ts
943
+ var import_common3 = require("@nestjs/common");
944
+ var import_api5 = require("@opentelemetry/api");
945
+ var logger3 = new import_common3.Logger("Jetstream:Otel");
946
+ var RPC_TIMEOUT_MESSAGE = "rpc.timeout";
947
+ var beginRpcClientSpan = (ctx, config) => {
948
+ if (!config.enabled) {
949
+ return {
950
+ activeContext: import_api5.context.active(),
951
+ finish: () => void 0
952
+ };
953
+ }
954
+ if (!config.traces.has("rpc.client.send" /* RpcClientSend */)) {
955
+ injectContext(import_api5.context.active(), ctx.headers, hdrsSetter);
956
+ return {
957
+ activeContext: import_api5.context.active(),
958
+ finish: () => void 0
959
+ };
960
+ }
961
+ const tracer = getTracer();
962
+ const span = tracer.startSpan(`${SPAN_NAME_SEND} ${ctx.subject}`, {
963
+ kind: import_api5.SpanKind.CLIENT,
964
+ attributes: {
965
+ ...buildRpcClientAttributes({
966
+ subject: ctx.subject,
967
+ pattern: ctx.pattern,
968
+ correlationId: ctx.correlationId,
969
+ payloadBytes: ctx.payloadBytes,
970
+ messageId: ctx.messageId,
971
+ serviceName: ctx.serviceName,
972
+ serverAddress: ctx.endpoint?.host,
973
+ serverPort: ctx.endpoint?.port
974
+ }),
975
+ ...captureMatchingHeaders(ctx.headers, config.captureHeaders),
976
+ ...captureBodyAttribute(ctx.subject, ctx.payload, config.captureBody)
977
+ }
978
+ });
979
+ const ctxWithSpan = import_api5.trace.setSpan(import_api5.context.active(), span);
980
+ injectContext(ctxWithSpan, ctx.headers, hdrsSetter);
981
+ const start = Date.now();
982
+ let finalized = false;
983
+ const finish = (outcome) => {
984
+ if (finalized) return;
985
+ finalized = true;
986
+ let reply;
987
+ let error;
988
+ switch (outcome.kind) {
989
+ case "ok" /* Ok */:
990
+ reply = outcome.reply;
991
+ span.setStatus({ code: import_api5.SpanStatusCode.OK });
992
+ break;
993
+ case "reply-error" /* ReplyError */:
994
+ reply = outcome.replyPayload;
995
+ applyExpectedErrorAttributes(span, outcome.replyPayload);
996
+ span.setStatus({ code: import_api5.SpanStatusCode.OK });
997
+ break;
998
+ case "timeout" /* Timeout */:
999
+ error = new Error(RPC_TIMEOUT_MESSAGE);
1000
+ span.addEvent(RPC_TIMEOUT_MESSAGE);
1001
+ span.setStatus({ code: import_api5.SpanStatusCode.ERROR, message: RPC_TIMEOUT_MESSAGE });
1002
+ break;
1003
+ case "error" /* Error */:
1004
+ error = outcome.error;
1005
+ span.recordException(outcome.error);
1006
+ span.setStatus({ code: import_api5.SpanStatusCode.ERROR, message: outcome.error.message });
1007
+ break;
1008
+ default: {
1009
+ const unknownOutcome = outcome;
1010
+ logger3.error(`Unhandled RPC outcome: ${String(unknownOutcome.kind)}`);
1011
+ span.setStatus({ code: import_api5.SpanStatusCode.ERROR, message: "unknown outcome" });
1012
+ }
1013
+ }
1014
+ import_api5.context.with(ctxWithSpan, () => {
1015
+ safelyInvokeHook(HOOK_RESPONSE, config.responseHook, span, {
1016
+ subject: ctx.subject,
1017
+ durationMs: Date.now() - start,
1018
+ reply,
1019
+ error
1020
+ });
1021
+ });
1022
+ span.end();
1023
+ };
1024
+ return { activeContext: ctxWithSpan, finish };
1025
+ };
1026
+
1027
+ // src/otel/spans/dead-letter.ts
1028
+ var import_api6 = require("@opentelemetry/api");
1029
+ var withDeadLetterSpan = async (ctx, config, fn) => {
1030
+ if (!config.enabled || !config.traces.has("dead_letter" /* DeadLetter */)) {
1031
+ return fn();
1032
+ }
1033
+ const parentCtx = extractContext(import_api6.ROOT_CONTEXT, ctx.msg.headers, hdrsGetter);
1034
+ const tracer = getTracer();
1035
+ const span = tracer.startSpan(
1036
+ `${SPAN_NAME_DEAD_LETTER} ${ctx.msg.subject}`,
1037
+ {
1038
+ kind: import_api6.SpanKind.INTERNAL,
1039
+ attributes: buildDeadLetterAttributes({
1040
+ subject: ctx.msg.subject,
1041
+ pattern: ctx.pattern,
1042
+ serviceName: ctx.serviceName,
1043
+ serverAddress: ctx.endpoint?.host,
1044
+ serverPort: ctx.endpoint?.port,
1045
+ finalDeliveryCount: ctx.finalDeliveryCount,
1046
+ reason: ctx.reason
1047
+ })
1048
+ },
1049
+ parentCtx
1050
+ );
1051
+ const ctxWithSpan = import_api6.trace.setSpan(parentCtx, span);
1052
+ const start = Date.now();
1053
+ const invokeResponseHook = (error) => {
1054
+ import_api6.context.with(ctxWithSpan, () => {
1055
+ safelyInvokeHook(HOOK_RESPONSE, config.responseHook, span, {
1056
+ subject: ctx.msg.subject,
1057
+ durationMs: Date.now() - start,
1058
+ error
1059
+ });
1060
+ });
1061
+ };
1062
+ try {
1063
+ const result = await import_api6.context.with(ctxWithSpan, fn);
1064
+ span.setStatus({ code: import_api6.SpanStatusCode.OK });
1065
+ invokeResponseHook();
1066
+ return result;
1067
+ } catch (err) {
1068
+ const error = err instanceof Error ? err : new Error(String(err));
1069
+ span.recordException(error);
1070
+ span.setStatus({ code: import_api6.SpanStatusCode.ERROR, message: error.message });
1071
+ invokeResponseHook(error);
1072
+ throw err;
1073
+ } finally {
1074
+ span.end();
1075
+ }
1076
+ };
1077
+
1078
+ // src/otel/spans/infrastructure.ts
1079
+ var import_common4 = require("@nestjs/common");
1080
+ var import_api7 = require("@opentelemetry/api");
1081
+ var logger4 = new import_common4.Logger("Jetstream:Otel");
1082
+ var startInfraSpan = (config, traceKind, name, ctx, extraAttributes = {}) => {
1083
+ if (!config.enabled || !config.traces.has(traceKind)) return null;
1084
+ const tracer = getTracer();
1085
+ const attributes = {
1086
+ [ATTR_JETSTREAM_SERVICE_NAME]: ctx.serviceName
1087
+ };
1088
+ if (ctx.endpoint?.host) attributes[ATTR_SERVER_ADDRESS] = ctx.endpoint.host;
1089
+ if (ctx.endpoint?.port !== void 0) attributes[ATTR_SERVER_PORT] = ctx.endpoint.port;
1090
+ for (const [key, value] of Object.entries(extraAttributes)) {
1091
+ if (value !== void 0) attributes[key] = value;
1092
+ }
1093
+ return tracer.startSpan(name, { kind: import_api7.SpanKind.INTERNAL, attributes });
1094
+ };
1095
+ var finishOk = (span) => {
1096
+ span.setStatus({ code: import_api7.SpanStatusCode.OK });
1097
+ span.end();
1098
+ };
1099
+ var finishError = (span, err) => {
1100
+ const error = err instanceof Error ? err : new Error(String(err));
1101
+ span.recordException(error);
1102
+ span.setStatus({ code: import_api7.SpanStatusCode.ERROR, message: error.message });
1103
+ span.end();
1104
+ };
1105
+ var wrapInfra = async (config, traceKind, name, ctx, attributes, op) => {
1106
+ const span = startInfraSpan(config, traceKind, name, ctx, attributes);
1107
+ if (!span) return op();
1108
+ const ctxWithSpan = import_api7.trace.setSpan(import_api7.context.active(), span);
1109
+ try {
1110
+ const result = await import_api7.context.with(ctxWithSpan, op);
1111
+ finishOk(span);
1112
+ return result;
1113
+ } catch (err) {
1114
+ finishError(span, err);
1115
+ throw err;
1116
+ }
1117
+ };
1118
+ var beginConnectionLifecycleSpan = (config, ctx) => {
1119
+ const span = startInfraSpan(
1120
+ config,
1121
+ "connection.lifecycle" /* ConnectionLifecycle */,
1122
+ SPAN_NAME_NATS_CONNECTION,
1123
+ ctx,
1124
+ { [ATTR_NATS_CONNECTION_SERVER]: ctx.server }
1125
+ );
1126
+ if (!span) {
1127
+ return {
1128
+ recordEvent: () => void 0,
1129
+ finish: () => void 0
1130
+ };
1131
+ }
1132
+ let finalized = false;
1133
+ return {
1134
+ recordEvent: (name, attributes) => {
1135
+ if (finalized) {
1136
+ logger4.debug(`recordEvent('${name}') called after connection span finished`);
1137
+ return;
1138
+ }
1139
+ span.addEvent(name, attributes);
1140
+ },
1141
+ finish: (err) => {
1142
+ if (finalized) return;
1143
+ finalized = true;
1144
+ if (err === void 0) finishOk(span);
1145
+ else finishError(span, err);
1146
+ }
1147
+ };
1148
+ };
1149
+ var withSelfHealingSpan = (config, ctx, op) => wrapInfra(
1150
+ config,
1151
+ "self_healing" /* SelfHealing */,
1152
+ SPAN_NAME_JETSTREAM_SELF_HEALING,
1153
+ ctx,
1154
+ {
1155
+ [ATTR_MESSAGING_NATS_STREAM_NAME]: ctx.stream,
1156
+ [ATTR_MESSAGING_CONSUMER_GROUP_NAME]: ctx.consumer,
1157
+ [ATTR_JETSTREAM_SELF_HEALING_REASON]: ctx.reason
1158
+ },
1159
+ op
1160
+ );
1161
+ var withProvisioningSpan = (config, ctx, op) => wrapInfra(
1162
+ config,
1163
+ "provisioning" /* Provisioning */,
1164
+ `${SPAN_NAME_JETSTREAM_PROVISIONING_PREFIX}${ctx.entity}`,
1165
+ ctx,
1166
+ {
1167
+ [ATTR_JETSTREAM_PROVISIONING_ENTITY]: ctx.entity,
1168
+ [ATTR_JETSTREAM_PROVISIONING_ACTION]: ctx.action,
1169
+ [ATTR_JETSTREAM_PROVISIONING_NAME]: ctx.name
1170
+ },
1171
+ op
1172
+ );
1173
+ var withMigrationSpan = (config, ctx, op) => wrapInfra(
1174
+ config,
1175
+ "migration" /* Migration */,
1176
+ SPAN_NAME_JETSTREAM_MIGRATION,
1177
+ ctx,
1178
+ {
1179
+ [ATTR_MESSAGING_NATS_STREAM_NAME]: ctx.stream,
1180
+ [ATTR_JETSTREAM_MIGRATION_REASON]: ctx.reason
1181
+ },
1182
+ op
1183
+ );
1184
+ var withShutdownSpan = (config, ctx, op) => wrapInfra(config, "shutdown" /* Shutdown */, SPAN_NAME_JETSTREAM_SHUTDOWN, ctx, {}, op);
1185
+
279
1186
  // src/client/jetstream.record.ts
280
1187
  var JetstreamRecord = class {
281
1188
  constructor(data, headers2, timeout, messageId, schedule, ttl) {
@@ -428,9 +1335,14 @@ var JetstreamRecordBuilder = class {
428
1335
  this.ttlDuration
429
1336
  );
430
1337
  }
431
- /** Validate that a header key is not reserved. */
1338
+ /**
1339
+ * Validate that a header key is not reserved. NATS treats header names
1340
+ * case-insensitively, so the check is against the lowercase form to keep
1341
+ * `'X-Correlation-ID'`, `'x-correlation-id'`, and any other casing in
1342
+ * lockstep. `RESERVED_HEADERS` is defined as an all-lowercase set.
1343
+ */
432
1344
  validateHeaderKey(key) {
433
- if (RESERVED_HEADERS.has(key)) {
1345
+ if (RESERVED_HEADERS.has(key.toLowerCase())) {
434
1346
  throw new Error(
435
1347
  `Header "${key}" is reserved by the JetStream transport and cannot be set manually. Reserved headers: ${[...RESERVED_HEADERS].join(", ")}`
436
1348
  );
@@ -451,6 +1363,11 @@ var nanosToGoDuration = (nanos) => {
451
1363
 
452
1364
  // src/client/jetstream.client.ts
453
1365
  var BROADCAST_SUBJECT_PREFIX = "broadcast.";
1366
+ var detectEventKind = (pattern) => {
1367
+ if (pattern.startsWith("broadcast:" /* Broadcast */)) return "broadcast" /* Broadcast */;
1368
+ if (pattern.startsWith("ordered:" /* Ordered */)) return "ordered" /* Ordered */;
1369
+ return "event" /* Event */;
1370
+ };
454
1371
  var JetstreamClient = class extends import_microservices.ClientProxy {
455
1372
  constructor(rootOptions, targetServiceName, connection, codec, eventBus) {
456
1373
  super();
@@ -466,8 +1383,11 @@ var JetstreamClient = class extends import_microservices.ClientProxy {
466
1383
  this.orderedSubjectPrefix = `${targetInternal}.${"ordered" /* Ordered */}.`;
467
1384
  this.isCoreMode = isCoreRpcMode(this.rootOptions.rpc);
468
1385
  this.defaultRpcTimeout = isJetStreamRpcMode(this.rootOptions.rpc) ? this.rootOptions.rpc?.timeout ?? DEFAULT_JETSTREAM_RPC_TIMEOUT : this.rootOptions.rpc?.timeout ?? DEFAULT_RPC_TIMEOUT;
1386
+ const derived = deriveOtelAttrs(this.rootOptions);
1387
+ this.otel = derived.otel;
1388
+ this.serverEndpoint = derived.serverEndpoint;
469
1389
  }
470
- logger = new import_common.Logger("Jetstream:Client");
1390
+ logger = new import_common5.Logger("Jetstream:Client");
471
1391
  /** Target service name this client sends messages to. */
472
1392
  targetName;
473
1393
  /** Pre-cached caller name derived from rootOptions.name, computed once in constructor. */
@@ -487,6 +1407,10 @@ var JetstreamClient = class extends import_microservices.ClientProxy {
487
1407
  */
488
1408
  isCoreMode;
489
1409
  defaultRpcTimeout;
1410
+ /** Resolved OpenTelemetry configuration, computed once in the constructor. */
1411
+ otel;
1412
+ /** Server endpoint parts used for `server.address` / `server.port` span attributes. */
1413
+ serverEndpoint;
490
1414
  /** Shared inbox for JetStream-mode RPC responses. */
491
1415
  inbox = null;
492
1416
  inboxSubscription = null;
@@ -554,33 +1478,55 @@ var JetstreamClient = class extends import_microservices.ClientProxy {
554
1478
  if (!this.readyForPublish) await this.connect();
555
1479
  const { data, hdrs, messageId, schedule, ttl } = this.extractRecordData(packet.data);
556
1480
  const eventSubject = this.buildEventSubject(packet.pattern);
1481
+ const publishSubject = schedule ? this.buildScheduleSubject(eventSubject) : eventSubject;
557
1482
  const msgHeaders = this.buildHeaders(hdrs, { subject: eventSubject });
558
- if (schedule) {
559
- const scheduleSubject = this.buildScheduleSubject(eventSubject);
560
- const ack = await this.connection.getJetStreamClient().publish(scheduleSubject, this.codec.encode(data), {
1483
+ const encoded = this.codec.encode(data);
1484
+ const effectiveMsgId = messageId ?? import_nuid.nuid.next();
1485
+ const record = packet.data instanceof JetstreamRecord ? packet.data : new JetstreamRecord(data, /* @__PURE__ */ new Map());
1486
+ await withPublishSpan(
1487
+ {
1488
+ subject: publishSubject,
1489
+ pattern: packet.pattern,
1490
+ record,
1491
+ kind: detectEventKind(packet.pattern),
1492
+ payloadBytes: encoded.length,
1493
+ payload: encoded,
1494
+ messageId: effectiveMsgId,
561
1495
  headers: msgHeaders,
562
- msgID: messageId ?? import_nuid.nuid.next(),
563
- ttl,
564
- schedule: {
565
- specification: schedule.at,
566
- target: eventSubject
1496
+ serviceName: this.callerName,
1497
+ endpoint: this.serverEndpoint,
1498
+ scheduleTarget: schedule ? eventSubject : void 0
1499
+ },
1500
+ this.otel,
1501
+ async () => {
1502
+ const warnIfDuplicate = (kindLabel, ack2) => {
1503
+ if (ack2.duplicate) {
1504
+ this.logger.warn(
1505
+ `Duplicate ${kindLabel} publish detected: ${publishSubject} (seq: ${ack2.seq})`
1506
+ );
1507
+ }
1508
+ };
1509
+ if (schedule) {
1510
+ const ack2 = await this.connection.getJetStreamClient().publish(publishSubject, encoded, {
1511
+ headers: msgHeaders,
1512
+ msgID: effectiveMsgId,
1513
+ ttl,
1514
+ schedule: {
1515
+ specification: schedule.at,
1516
+ target: eventSubject
1517
+ }
1518
+ });
1519
+ warnIfDuplicate("scheduled", ack2);
1520
+ return;
567
1521
  }
568
- });
569
- if (ack.duplicate) {
570
- this.logger.warn(
571
- `Duplicate scheduled publish detected: ${scheduleSubject} (seq: ${ack.seq})`
572
- );
573
- }
574
- } else {
575
- const ack = await this.connection.getJetStreamClient().publish(eventSubject, this.codec.encode(data), {
576
- headers: msgHeaders,
577
- msgID: messageId ?? import_nuid.nuid.next(),
578
- ttl
579
- });
580
- if (ack.duplicate) {
581
- this.logger.warn(`Duplicate event publish detected: ${eventSubject} (seq: ${ack.seq})`);
1522
+ const ack = await this.connection.getJetStreamClient().publish(publishSubject, encoded, {
1523
+ headers: msgHeaders,
1524
+ msgID: effectiveMsgId,
1525
+ ttl
1526
+ });
1527
+ warnIfDuplicate("event", ack);
582
1528
  }
583
- }
1529
+ );
584
1530
  return void 0;
585
1531
  }
586
1532
  /**
@@ -631,24 +1577,46 @@ var JetstreamClient = class extends import_microservices.ClientProxy {
631
1577
  }
632
1578
  /** Core mode: nc.request() with timeout. */
633
1579
  async publishCoreRpc(subject, data, customHeaders, timeout, callback) {
1580
+ const effectiveTimeout = timeout ?? this.defaultRpcTimeout;
1581
+ const hdrs = this.buildHeaders(customHeaders, { subject });
1582
+ const encoded = this.codec.encode(data);
1583
+ const spanHandle = beginRpcClientSpan(
1584
+ {
1585
+ subject,
1586
+ payloadBytes: encoded.length,
1587
+ payload: encoded,
1588
+ headers: hdrs,
1589
+ serviceName: this.callerName,
1590
+ endpoint: this.serverEndpoint
1591
+ },
1592
+ this.otel
1593
+ );
634
1594
  try {
635
1595
  const nc = this.readyForPublish ? this.connection.unwrap : await this.connect();
636
- const effectiveTimeout = timeout ?? this.defaultRpcTimeout;
637
- const hdrs = this.buildHeaders(customHeaders, { subject });
638
- const response = await nc.request(subject, this.codec.encode(data), {
639
- timeout: effectiveTimeout,
640
- headers: hdrs
641
- });
1596
+ const response = await import_api8.context.with(
1597
+ spanHandle.activeContext,
1598
+ () => nc.request(subject, encoded, {
1599
+ timeout: effectiveTimeout,
1600
+ headers: hdrs
1601
+ })
1602
+ );
642
1603
  const decoded = this.codec.decode(response.data);
643
1604
  if (response.headers?.get("x-error" /* Error */)) {
1605
+ spanHandle.finish({ kind: "reply-error" /* ReplyError */, replyPayload: decoded });
644
1606
  callback({ err: decoded, response: null, isDisposed: true });
645
1607
  } else {
1608
+ spanHandle.finish({ kind: "ok" /* Ok */, reply: decoded });
646
1609
  callback({ err: null, response: decoded, isDisposed: true });
647
1610
  }
648
1611
  } catch (err) {
649
1612
  const error = err instanceof Error ? err : new Error("Unknown error");
650
- this.logger.error(`Core RPC error (${subject}):`, err);
651
- this.eventBus.emit("error" /* Error */, error, "client-rpc");
1613
+ if (error instanceof import_transport_node.TimeoutError) {
1614
+ spanHandle.finish({ kind: "timeout" /* Timeout */ });
1615
+ this.eventBus.emit("rpcTimeout" /* RpcTimeout */, subject, "");
1616
+ } else {
1617
+ spanHandle.finish({ kind: "error" /* Error */, error });
1618
+ this.eventBus.emit("error" /* Error */, error, "client-rpc");
1619
+ }
652
1620
  callback({ err: error, response: null, isDisposed: true });
653
1621
  }
654
1622
  }
@@ -656,12 +1624,55 @@ var JetstreamClient = class extends import_microservices.ClientProxy {
656
1624
  async publishJetStreamRpc(subject, data, callback, options) {
657
1625
  const { headers: customHeaders, correlationId, messageId } = options;
658
1626
  const effectiveTimeout = options.timeout ?? this.defaultRpcTimeout;
659
- this.pendingMessages.set(correlationId, callback);
1627
+ const hdrs = this.buildHeaders(customHeaders, {
1628
+ subject,
1629
+ correlationId,
1630
+ replyTo: this.inbox ?? ""
1631
+ });
1632
+ const encoded = this.codec.encode(data);
1633
+ const spanHandle = beginRpcClientSpan(
1634
+ {
1635
+ subject,
1636
+ correlationId,
1637
+ payloadBytes: encoded.length,
1638
+ payload: encoded,
1639
+ messageId,
1640
+ headers: hdrs,
1641
+ serviceName: this.callerName,
1642
+ endpoint: this.serverEndpoint
1643
+ },
1644
+ this.otel
1645
+ );
1646
+ this.pendingMessages.set(correlationId, (packet) => {
1647
+ if (packet.err) {
1648
+ if (packet.err instanceof Error) {
1649
+ spanHandle.finish({ kind: "error" /* Error */, error: packet.err });
1650
+ } else {
1651
+ spanHandle.finish({ kind: "reply-error" /* ReplyError */, replyPayload: packet.err });
1652
+ }
1653
+ } else {
1654
+ spanHandle.finish({ kind: "ok" /* Ok */, reply: packet.response });
1655
+ }
1656
+ callback(packet);
1657
+ });
1658
+ const timeoutId = setTimeout(() => {
1659
+ if (!this.pendingMessages.has(correlationId)) return;
1660
+ this.pendingTimeouts.delete(correlationId);
1661
+ this.pendingMessages.delete(correlationId);
1662
+ spanHandle.finish({ kind: "timeout" /* Timeout */ });
1663
+ this.eventBus.emit("rpcTimeout" /* RpcTimeout */, subject, correlationId);
1664
+ callback({ err: new Error(RPC_TIMEOUT_MESSAGE), response: null, isDisposed: true });
1665
+ }, effectiveTimeout);
1666
+ this.pendingTimeouts.set(correlationId, timeoutId);
660
1667
  try {
661
1668
  if (!this.readyForPublish) await this.connect();
662
1669
  if (!this.pendingMessages.has(correlationId)) return;
663
1670
  if (!this.inbox) {
1671
+ clearTimeout(timeoutId);
1672
+ this.pendingTimeouts.delete(correlationId);
664
1673
  this.pendingMessages.delete(correlationId);
1674
+ const inboxError = new Error("Inbox not initialized");
1675
+ spanHandle.finish({ kind: "error" /* Error */, error: inboxError });
665
1676
  callback({
666
1677
  err: new Error("Inbox not initialized \u2014 JetStream RPC mode requires a connected inbox"),
667
1678
  response: null,
@@ -669,24 +1680,13 @@ var JetstreamClient = class extends import_microservices.ClientProxy {
669
1680
  });
670
1681
  return;
671
1682
  }
672
- const timeoutId = setTimeout(() => {
673
- if (!this.pendingMessages.has(correlationId)) return;
674
- this.pendingTimeouts.delete(correlationId);
675
- this.pendingMessages.delete(correlationId);
676
- this.logger.error(`JetStream RPC timeout (${effectiveTimeout}ms): ${subject}`);
677
- this.eventBus.emit("rpcTimeout" /* RpcTimeout */, subject, correlationId);
678
- callback({ err: new Error("RPC timeout"), response: null, isDisposed: true });
679
- }, effectiveTimeout);
680
- this.pendingTimeouts.set(correlationId, timeoutId);
681
- const hdrs = this.buildHeaders(customHeaders, {
682
- subject,
683
- correlationId,
684
- replyTo: this.inbox
685
- });
686
- await this.connection.getJetStreamClient().publish(subject, this.codec.encode(data), {
687
- headers: hdrs,
688
- msgID: messageId ?? import_nuid.nuid.next()
689
- });
1683
+ await import_api8.context.with(
1684
+ spanHandle.activeContext,
1685
+ () => this.connection.getJetStreamClient().publish(subject, encoded, {
1686
+ headers: hdrs,
1687
+ msgID: messageId ?? import_nuid.nuid.next()
1688
+ })
1689
+ );
690
1690
  } catch (err) {
691
1691
  const existingTimeout = this.pendingTimeouts.get(correlationId);
692
1692
  if (existingTimeout) {
@@ -696,7 +1696,8 @@ var JetstreamClient = class extends import_microservices.ClientProxy {
696
1696
  if (!this.pendingMessages.has(correlationId)) return;
697
1697
  this.pendingMessages.delete(correlationId);
698
1698
  const error = err instanceof Error ? err : new Error("Unknown error");
699
- this.logger.error(`JetStream RPC publish error (${subject}):`, err);
1699
+ spanHandle.finish({ kind: "error" /* Error */, error });
1700
+ this.eventBus.emit("error" /* Error */, error, `jetstream-rpc-publish:${subject}`);
700
1701
  callback({ err: error, response: null, isDisposed: true });
701
1702
  }
702
1703
  }
@@ -879,9 +1880,9 @@ var MsgpackCodec = class {
879
1880
  };
880
1881
 
881
1882
  // src/connection/connection.provider.ts
882
- var import_common2 = require("@nestjs/common");
1883
+ var import_common6 = require("@nestjs/common");
883
1884
  var import_transport_node2 = require("@nats-io/transport-node");
884
- var import_jetstream7 = require("@nats-io/jetstream");
1885
+ var import_jetstream8 = require("@nats-io/jetstream");
885
1886
  var import_rxjs = require("rxjs");
886
1887
  var DEFAULT_OPTIONS = {
887
1888
  maxReconnectAttempts: -1,
@@ -891,6 +1892,10 @@ var ConnectionProvider = class {
891
1892
  constructor(options, eventBus) {
892
1893
  this.options = options;
893
1894
  this.eventBus = eventBus;
1895
+ const derived = deriveOtelAttrs(options);
1896
+ this.otel = derived.otel;
1897
+ this.otelServiceName = derived.serviceName;
1898
+ this.otelEndpoint = derived.serverEndpoint;
894
1899
  this.nc$ = (0, import_rxjs.defer)(() => this.getConnection()).pipe(
895
1900
  (0, import_rxjs.shareReplay)({ bufferSize: 1, refCount: false })
896
1901
  );
@@ -903,12 +1908,16 @@ var ConnectionProvider = class {
903
1908
  nc$;
904
1909
  /** Live stream of connection status events (no replay). */
905
1910
  status$;
906
- logger = new import_common2.Logger("Jetstream:Connection");
1911
+ logger = new import_common6.Logger("Jetstream:Connection");
907
1912
  connection = null;
908
1913
  connectionPromise = null;
909
1914
  jsClient = null;
910
1915
  jsmInstance = null;
911
1916
  jsmPromise = null;
1917
+ otel;
1918
+ otelServiceName;
1919
+ otelEndpoint;
1920
+ lifecycleSpan = null;
912
1921
  /**
913
1922
  * Establish NATS connection. Idempotent — returns cached connection on subsequent calls.
914
1923
  *
@@ -951,7 +1960,7 @@ var ConnectionProvider = class {
951
1960
  if (!this.connection || this.connection.isClosed()) {
952
1961
  throw new Error("Not connected \u2014 call getConnection() before getJetStreamClient()");
953
1962
  }
954
- this.jsClient ??= (0, import_jetstream7.jetstream)(this.connection);
1963
+ this.jsClient ??= (0, import_jetstream8.jetstream)(this.connection);
955
1964
  return this.jsClient;
956
1965
  }
957
1966
  /** Direct access to the raw NATS connection, or `null` if not yet connected. */
@@ -972,14 +1981,24 @@ var ConnectionProvider = class {
972
1981
  }
973
1982
  if (!this.connection || this.connection.isClosed()) return;
974
1983
  try {
975
- await this.connection.drain();
976
- await this.connection.closed();
977
- } catch {
978
- try {
979
- await this.connection.close();
980
- } catch {
981
- }
1984
+ await withShutdownSpan(
1985
+ this.otel,
1986
+ { serviceName: this.otelServiceName, endpoint: this.otelEndpoint },
1987
+ async () => {
1988
+ try {
1989
+ await this.connection?.drain();
1990
+ await this.connection?.closed();
1991
+ } catch {
1992
+ try {
1993
+ await this.connection?.close();
1994
+ } catch {
1995
+ }
1996
+ }
1997
+ }
1998
+ );
982
1999
  } finally {
2000
+ this.lifecycleSpan?.finish();
2001
+ this.lifecycleSpan = null;
983
2002
  this.connection = null;
984
2003
  this.connectionPromise = null;
985
2004
  this.jsClient = null;
@@ -990,7 +2009,7 @@ var ConnectionProvider = class {
990
2009
  async initJetStreamManager() {
991
2010
  try {
992
2011
  const nc = await this.getConnection();
993
- this.jsmInstance = await (0, import_jetstream7.jetstreamManager)(nc);
2012
+ this.jsmInstance = await (0, import_jetstream8.jetstreamManager)(nc);
994
2013
  this.logger.log("JetStream manager initialized");
995
2014
  return this.jsmInstance;
996
2015
  } finally {
@@ -999,17 +2018,25 @@ var ConnectionProvider = class {
999
2018
  }
1000
2019
  /** Internal: establish the physical connection with reconnect monitoring. */
1001
2020
  async establish() {
1002
- const name = internalName(this.options.name);
1003
2021
  try {
1004
2022
  const nc = await (0, import_transport_node2.connect)({
1005
2023
  ...DEFAULT_OPTIONS,
2024
+ // Default the NATS connection name to the OTel-derived service name so
2025
+ // `nats server info` lines up with span attributes, but let user-supplied
2026
+ // `connectionOptions.name` win when set.
2027
+ name: this.otelServiceName,
1006
2028
  ...this.options.connectionOptions,
1007
- servers: this.options.servers,
1008
- name
2029
+ servers: this.options.servers
1009
2030
  });
1010
2031
  this.connection = nc;
1011
2032
  this.logger.log(`NATS connection established: ${nc.getServer()}`);
1012
2033
  this.eventBus.emit("connect" /* Connect */, nc.getServer());
2034
+ this.lifecycleSpan?.finish();
2035
+ this.lifecycleSpan = beginConnectionLifecycleSpan(this.otel, {
2036
+ serviceName: this.otelServiceName,
2037
+ endpoint: this.otelEndpoint,
2038
+ server: nc.getServer()
2039
+ });
1013
2040
  this.monitorStatus(nc);
1014
2041
  return nc;
1015
2042
  } catch (err) {
@@ -1019,37 +2046,55 @@ var ConnectionProvider = class {
1019
2046
  throw err;
1020
2047
  }
1021
2048
  }
2049
+ /** Handle a single `nc.status()` event, emitting hooks and span events. */
2050
+ handleStatusEvent(status, nc) {
2051
+ switch (status.type) {
2052
+ case "disconnect":
2053
+ this.eventBus.emit("disconnect" /* Disconnect */);
2054
+ this.lifecycleSpan?.recordEvent(EVENT_CONNECTION_DISCONNECTED);
2055
+ break;
2056
+ case "reconnect":
2057
+ this.jsClient = null;
2058
+ this.jsmInstance = null;
2059
+ this.jsmPromise = null;
2060
+ this.eventBus.emit("reconnect" /* Reconnect */, nc.getServer());
2061
+ this.lifecycleSpan?.recordEvent(EVENT_CONNECTION_RECONNECTED, {
2062
+ [ATTR_NATS_CONNECTION_SERVER]: nc.getServer()
2063
+ });
2064
+ break;
2065
+ case "error":
2066
+ this.eventBus.emit(
2067
+ "error" /* Error */,
2068
+ status.error,
2069
+ "connection"
2070
+ );
2071
+ break;
2072
+ case "update":
2073
+ case "ldm":
2074
+ case "reconnecting":
2075
+ case "ping":
2076
+ case "staleConnection":
2077
+ case "forceReconnect":
2078
+ case "slowConsumer":
2079
+ case "close":
2080
+ break;
2081
+ default: {
2082
+ const _exhaustive = status;
2083
+ const unknown = _exhaustive.type ?? "unknown";
2084
+ this.logger.warn(`Unhandled NATS status event: ${unknown}`);
2085
+ }
2086
+ }
2087
+ }
1022
2088
  /** Subscribe to connection status events and emit hooks. */
1023
2089
  monitorStatus(nc) {
1024
2090
  void (async () => {
1025
- for await (const status of nc.status()) {
1026
- switch (status.type) {
1027
- case "disconnect":
1028
- this.eventBus.emit("disconnect" /* Disconnect */);
1029
- break;
1030
- case "reconnect":
1031
- this.jsClient = null;
1032
- this.jsmInstance = null;
1033
- this.jsmPromise = null;
1034
- this.eventBus.emit("reconnect" /* Reconnect */, nc.getServer());
1035
- break;
1036
- case "error":
1037
- this.eventBus.emit(
1038
- "error" /* Error */,
1039
- status.error,
1040
- "connection"
1041
- );
1042
- break;
1043
- case "update":
1044
- case "ldm":
1045
- case "reconnecting":
1046
- case "ping":
1047
- case "staleConnection":
1048
- case "forceReconnect":
1049
- case "slowConsumer":
1050
- case "close":
1051
- break;
2091
+ try {
2092
+ for await (const status of nc.status()) {
2093
+ this.handleStatusEvent(status, nc);
1052
2094
  }
2095
+ } finally {
2096
+ this.lifecycleSpan?.finish();
2097
+ this.lifecycleSpan = null;
1053
2098
  }
1054
2099
  })().catch((err) => {
1055
2100
  this.logger.error("Status monitor error", err);
@@ -1061,8 +2106,8 @@ var ConnectionProvider = class {
1061
2106
  var EventBus = class {
1062
2107
  hooks;
1063
2108
  logger;
1064
- constructor(logger, hooks) {
1065
- this.logger = logger;
2109
+ constructor(logger5, hooks) {
2110
+ this.logger = logger5;
1066
2111
  this.hooks = hooks ?? {};
1067
2112
  }
1068
2113
  /**
@@ -1118,12 +2163,12 @@ var EventBus = class {
1118
2163
  };
1119
2164
 
1120
2165
  // src/health/jetstream.health-indicator.ts
1121
- var import_common3 = require("@nestjs/common");
2166
+ var import_common7 = require("@nestjs/common");
1122
2167
  var JetstreamHealthIndicator = class {
1123
2168
  constructor(connection) {
1124
2169
  this.connection = connection;
1125
2170
  }
1126
- logger = new import_common3.Logger("Jetstream:Health");
2171
+ logger = new import_common7.Logger("Jetstream:Health");
1127
2172
  /**
1128
2173
  * Plain health status check.
1129
2174
  *
@@ -1180,7 +2225,7 @@ var JetstreamHealthIndicator = class {
1180
2225
  }
1181
2226
  };
1182
2227
  JetstreamHealthIndicator = __decorateClass([
1183
- (0, import_common3.Injectable)()
2228
+ (0, import_common7.Injectable)()
1184
2229
  ], JetstreamHealthIndicator);
1185
2230
 
1186
2231
  // src/server/strategy.ts
@@ -1329,7 +2374,7 @@ var JetstreamStrategy = class extends import_microservices2.Server {
1329
2374
  };
1330
2375
 
1331
2376
  // src/server/core-rpc.server.ts
1332
- var import_common4 = require("@nestjs/common");
2377
+ var import_common8 = require("@nestjs/common");
1333
2378
  var import_transport_node3 = require("@nats-io/transport-node");
1334
2379
 
1335
2380
  // src/context/rpc.context.ts
@@ -1339,9 +2384,6 @@ var RpcContext = class extends import_microservices3.BaseRpcContext {
1339
2384
  _retryDelay;
1340
2385
  _shouldTerminate = false;
1341
2386
  _terminateReason;
1342
- // ---------------------------------------------------------------------------
1343
- // Message accessors
1344
- // ---------------------------------------------------------------------------
1345
2387
  /**
1346
2388
  * Get the underlying NATS message.
1347
2389
  *
@@ -1376,9 +2418,6 @@ var RpcContext = class extends import_microservices3.BaseRpcContext {
1376
2418
  isJetStream() {
1377
2419
  return "ack" in this.args[0];
1378
2420
  }
1379
- // ---------------------------------------------------------------------------
1380
- // JetStream metadata (return undefined for Core NATS messages)
1381
- // ---------------------------------------------------------------------------
1382
2421
  /** How many times this message has been delivered. */
1383
2422
  getDeliveryCount() {
1384
2423
  return this.asJetStream()?.info.deliveryCount;
@@ -1400,9 +2439,6 @@ var RpcContext = class extends import_microservices3.BaseRpcContext {
1400
2439
  getCallerName() {
1401
2440
  return this.getHeader("x-caller-name" /* CallerName */);
1402
2441
  }
1403
- // ---------------------------------------------------------------------------
1404
- // Handler-controlled settlement
1405
- // ---------------------------------------------------------------------------
1406
2442
  /**
1407
2443
  * Signal the transport to retry (nak) this message instead of acknowledging it.
1408
2444
  *
@@ -1447,9 +2483,6 @@ var RpcContext = class extends import_microservices3.BaseRpcContext {
1447
2483
  throw new Error(`${method}() is only available for JetStream messages`);
1448
2484
  }
1449
2485
  }
1450
- // ---------------------------------------------------------------------------
1451
- // Transport-facing state (read by EventRouter)
1452
- // ---------------------------------------------------------------------------
1453
2486
  /** @internal */
1454
2487
  get shouldRetry() {
1455
2488
  return this._shouldRetry;
@@ -1571,7 +2604,7 @@ var unwrapResult = (result) => {
1571
2604
  }
1572
2605
  return result;
1573
2606
  };
1574
- var isPromiseLike = (value) => value !== null && typeof value === "object" && typeof value.then === "function";
2607
+ var isPromiseLike2 = (value) => value !== null && typeof value === "object" && typeof value.then === "function";
1575
2608
  var subscribeToFirst = (obs) => new Promise((resolve, reject) => {
1576
2609
  let done = false;
1577
2610
  let subscription = null;
@@ -1601,20 +2634,25 @@ var subscribeToFirst = (obs) => new Promise((resolve, reject) => {
1601
2634
  // src/server/core-rpc.server.ts
1602
2635
  var CoreRpcServer = class {
1603
2636
  constructor(options, connection, patternRegistry, codec, eventBus) {
1604
- this.options = options;
1605
2637
  this.connection = connection;
1606
2638
  this.patternRegistry = patternRegistry;
1607
2639
  this.codec = codec;
1608
2640
  this.eventBus = eventBus;
2641
+ const derived = deriveOtelAttrs(options);
2642
+ this.otel = derived.otel;
2643
+ this.serviceName = derived.serviceName;
2644
+ this.serverEndpoint = derived.serverEndpoint;
1609
2645
  }
1610
- logger = new import_common4.Logger("Jetstream:CoreRpc");
2646
+ logger = new import_common8.Logger("Jetstream:CoreRpc");
1611
2647
  subscription = null;
2648
+ otel;
2649
+ serviceName;
2650
+ serverEndpoint;
1612
2651
  /** Start listening for RPC requests on the command subject. */
1613
2652
  async start() {
1614
2653
  const nc = await this.connection.getConnection();
1615
- const serviceName = internalName(this.options.name);
1616
- const subject = `${serviceName}.cmd.>`;
1617
- const queue = `${serviceName}_cmd_queue`;
2654
+ const subject = `${this.serviceName}.cmd.>`;
2655
+ const queue = `${this.serviceName}_cmd_queue`;
1618
2656
  this.subscription = nc.subscribe(subject, {
1619
2657
  queue,
1620
2658
  callback: (err, msg) => {
@@ -1659,11 +2697,29 @@ var CoreRpcServer = class {
1659
2697
  }
1660
2698
  const ctx = new RpcContext([msg]);
1661
2699
  try {
1662
- const raw = unwrapResult(handler(data, ctx));
1663
- const result = isPromiseLike(raw) ? await raw : raw;
1664
- msg.respond(this.codec.encode(result));
2700
+ const raw = await withConsumeSpan(
2701
+ {
2702
+ subject: msg.subject,
2703
+ msg,
2704
+ kind: "rpc" /* Rpc */,
2705
+ payloadBytes: msg.data.length,
2706
+ handlerMetadata: { pattern: msg.subject },
2707
+ serviceName: this.serviceName,
2708
+ endpoint: this.serverEndpoint
2709
+ },
2710
+ this.otel,
2711
+ () => {
2712
+ const out = unwrapResult(handler(data, ctx));
2713
+ return isPromiseLike2(out) ? out : out;
2714
+ }
2715
+ );
2716
+ msg.respond(this.codec.encode(raw));
1665
2717
  } catch (err) {
1666
- this.logger.error(`Handler error for Core RPC ${msg.subject}:`, err);
2718
+ this.eventBus.emit(
2719
+ "error" /* Error */,
2720
+ err instanceof Error ? err : new Error(String(err)),
2721
+ `core-rpc-handler:${msg.subject}`
2722
+ );
1667
2723
  this.respondWithError(msg, err);
1668
2724
  }
1669
2725
  }
@@ -1680,7 +2736,7 @@ var CoreRpcServer = class {
1680
2736
  };
1681
2737
 
1682
2738
  // src/server/infrastructure/stream.provider.ts
1683
- var import_common6 = require("@nestjs/common");
2739
+ var import_common10 = require("@nestjs/common");
1684
2740
  var import_jetstream14 = require("@nats-io/jetstream");
1685
2741
 
1686
2742
  // src/server/infrastructure/nats-error-codes.ts
@@ -1747,7 +2803,7 @@ var isEqual = (a, b) => {
1747
2803
  };
1748
2804
 
1749
2805
  // src/server/infrastructure/stream-migration.ts
1750
- var import_common5 = require("@nestjs/common");
2806
+ var import_common9 = require("@nestjs/common");
1751
2807
  var import_jetstream13 = require("@nats-io/jetstream");
1752
2808
  var MIGRATION_BACKUP_SUFFIX = "__migration_backup";
1753
2809
  var DEFAULT_SOURCING_TIMEOUT_MS = 3e4;
@@ -1756,7 +2812,7 @@ var StreamMigration = class {
1756
2812
  constructor(sourcingTimeoutMs = DEFAULT_SOURCING_TIMEOUT_MS) {
1757
2813
  this.sourcingTimeoutMs = sourcingTimeoutMs;
1758
2814
  }
1759
- logger = new import_common5.Logger("Jetstream:Stream");
2815
+ logger = new import_common9.Logger("Jetstream:Stream");
1760
2816
  async migrate(jsm, streamName2, newConfig) {
1761
2817
  const backupName = `${streamName2}${MIGRATION_BACKUP_SUFFIX}`;
1762
2818
  const startTime = Date.now();
@@ -1838,9 +2894,16 @@ var StreamProvider = class {
1838
2894
  constructor(options, connection) {
1839
2895
  this.options = options;
1840
2896
  this.connection = connection;
2897
+ const derived = deriveOtelAttrs(options);
2898
+ this.otel = derived.otel;
2899
+ this.otelServiceName = derived.serviceName;
2900
+ this.otelEndpoint = derived.serverEndpoint;
1841
2901
  }
1842
- logger = new import_common6.Logger("Jetstream:Stream");
2902
+ logger = new import_common10.Logger("Jetstream:Stream");
1843
2903
  migration = new StreamMigration();
2904
+ otel;
2905
+ otelServiceName;
2906
+ otelEndpoint;
1844
2907
  /**
1845
2908
  * Ensure all required streams exist with correct configuration.
1846
2909
  *
@@ -1886,32 +2949,56 @@ var StreamProvider = class {
1886
2949
  /** Ensure a single stream exists, creating or updating as needed. */
1887
2950
  async ensureStream(jsm, kind) {
1888
2951
  const config = this.buildConfig(kind);
1889
- this.logger.log(`Ensuring stream: ${config.name}`);
1890
- try {
1891
- const currentInfo = await jsm.streams.info(config.name);
1892
- return await this.handleExistingStream(jsm, currentInfo, config);
1893
- } catch (err) {
1894
- if (err instanceof import_jetstream14.JetStreamApiError && err.apiError().err_code === 10059 /* StreamNotFound */) {
1895
- this.logger.log(`Creating stream: ${config.name}`);
1896
- return await jsm.streams.add(config);
2952
+ return withProvisioningSpan(
2953
+ this.otel,
2954
+ {
2955
+ serviceName: this.otelServiceName,
2956
+ endpoint: this.otelEndpoint,
2957
+ entity: "stream",
2958
+ name: config.name,
2959
+ action: "ensure"
2960
+ },
2961
+ async () => {
2962
+ this.logger.log(`Ensuring stream: ${config.name}`);
2963
+ try {
2964
+ const currentInfo = await jsm.streams.info(config.name);
2965
+ return await this.handleExistingStream(jsm, currentInfo, config);
2966
+ } catch (err) {
2967
+ if (err instanceof import_jetstream14.JetStreamApiError && err.apiError().err_code === 10059 /* StreamNotFound */) {
2968
+ this.logger.log(`Creating stream: ${config.name}`);
2969
+ return await jsm.streams.add(config);
2970
+ }
2971
+ throw err;
2972
+ }
1897
2973
  }
1898
- throw err;
1899
- }
2974
+ );
1900
2975
  }
1901
2976
  /** Ensure a dead-letter queue stream exists, creating or updating as needed. */
1902
2977
  async ensureDlqStream(jsm) {
1903
2978
  const config = this.buildDlqConfig();
1904
- this.logger.log(`Ensuring DLQ stream: ${config.name}`);
1905
- try {
1906
- const currentInfo = await jsm.streams.info(config.name);
1907
- return await this.handleExistingStream(jsm, currentInfo, config);
1908
- } catch (err) {
1909
- if (err instanceof import_jetstream14.JetStreamApiError && err.apiError().err_code === 10059 /* StreamNotFound */) {
1910
- this.logger.log(`Creating DLQ stream: ${config.name}`);
1911
- return await jsm.streams.add(config);
2979
+ return withProvisioningSpan(
2980
+ this.otel,
2981
+ {
2982
+ serviceName: this.otelServiceName,
2983
+ endpoint: this.otelEndpoint,
2984
+ entity: "stream",
2985
+ name: config.name,
2986
+ action: "ensure"
2987
+ },
2988
+ async () => {
2989
+ this.logger.log(`Ensuring DLQ stream: ${config.name}`);
2990
+ try {
2991
+ const currentInfo = await jsm.streams.info(config.name);
2992
+ return await this.handleExistingStream(jsm, currentInfo, config);
2993
+ } catch (err) {
2994
+ if (err instanceof import_jetstream14.JetStreamApiError && err.apiError().err_code === 10059 /* StreamNotFound */) {
2995
+ this.logger.log(`Creating DLQ stream: ${config.name}`);
2996
+ return await jsm.streams.add(config);
2997
+ }
2998
+ throw err;
2999
+ }
1912
3000
  }
1913
- throw err;
1914
- }
3001
+ );
1915
3002
  }
1916
3003
  async handleExistingStream(jsm, currentInfo, config) {
1917
3004
  const diff = compareStreamConfig(currentInfo.config, config);
@@ -1940,7 +3027,18 @@ var StreamProvider = class {
1940
3027
  }
1941
3028
  return currentInfo;
1942
3029
  }
1943
- await this.migration.migrate(jsm, config.name, config);
3030
+ await withMigrationSpan(
3031
+ this.otel,
3032
+ {
3033
+ serviceName: this.otelServiceName,
3034
+ endpoint: this.otelEndpoint,
3035
+ stream: config.name,
3036
+ reason: diff.changes.filter((c) => c.mutability === "immutable").map((c) => c.property).join(", ")
3037
+ },
3038
+ async () => {
3039
+ await this.migration.migrate(jsm, config.name, config);
3040
+ }
3041
+ );
1944
3042
  return await jsm.streams.info(config.name);
1945
3043
  }
1946
3044
  buildMutableOnlyConfig(config, currentConfig, diff) {
@@ -2056,7 +3154,7 @@ var StreamProvider = class {
2056
3154
  };
2057
3155
 
2058
3156
  // src/server/infrastructure/consumer.provider.ts
2059
- var import_common7 = require("@nestjs/common");
3157
+ var import_common11 = require("@nestjs/common");
2060
3158
  var import_jetstream16 = require("@nats-io/jetstream");
2061
3159
  var ConsumerProvider = class {
2062
3160
  constructor(options, connection, streamProvider, patternRegistry) {
@@ -2064,8 +3162,15 @@ var ConsumerProvider = class {
2064
3162
  this.connection = connection;
2065
3163
  this.streamProvider = streamProvider;
2066
3164
  this.patternRegistry = patternRegistry;
2067
- }
2068
- logger = new import_common7.Logger("Jetstream:Consumer");
3165
+ const derived = deriveOtelAttrs(options);
3166
+ this.otel = derived.otel;
3167
+ this.otelServiceName = derived.serviceName;
3168
+ this.otelEndpoint = derived.serverEndpoint;
3169
+ }
3170
+ logger = new import_common11.Logger("Jetstream:Consumer");
3171
+ otel;
3172
+ otelServiceName;
3173
+ otelEndpoint;
2069
3174
  /**
2070
3175
  * Ensure consumers exist for the specified kinds.
2071
3176
  *
@@ -2095,17 +3200,29 @@ var ConsumerProvider = class {
2095
3200
  const stream = this.streamProvider.getStreamName(kind);
2096
3201
  const config = this.buildConfig(kind);
2097
3202
  const name = config.durable_name;
2098
- this.logger.log(`Ensuring consumer: ${name} on stream: ${stream}`);
2099
- try {
2100
- await jsm.consumers.info(stream, name);
2101
- this.logger.debug(`Consumer exists, updating: ${name}`);
2102
- return await jsm.consumers.update(stream, name, config);
2103
- } catch (err) {
2104
- if (!(err instanceof import_jetstream16.JetStreamApiError) || err.apiError().err_code !== 10014 /* ConsumerNotFound */) {
2105
- throw err;
3203
+ return withProvisioningSpan(
3204
+ this.otel,
3205
+ {
3206
+ serviceName: this.otelServiceName,
3207
+ endpoint: this.otelEndpoint,
3208
+ entity: "consumer",
3209
+ name,
3210
+ action: "ensure"
3211
+ },
3212
+ async () => {
3213
+ this.logger.log(`Ensuring consumer: ${name} on stream: ${stream}`);
3214
+ try {
3215
+ await jsm.consumers.info(stream, name);
3216
+ this.logger.debug(`Consumer exists, updating: ${name}`);
3217
+ return await jsm.consumers.update(stream, name, config);
3218
+ } catch (err) {
3219
+ if (!(err instanceof import_jetstream16.JetStreamApiError) || err.apiError().err_code !== 10014 /* ConsumerNotFound */) {
3220
+ throw err;
3221
+ }
3222
+ return await this.createConsumer(jsm, stream, name, config);
3223
+ }
2106
3224
  }
2107
- return await this.createConsumer(jsm, stream, name, config);
2108
- }
3225
+ );
2109
3226
  }
2110
3227
  /**
2111
3228
  * Recover a consumer that disappeared during runtime.
@@ -2124,16 +3241,28 @@ var ConsumerProvider = class {
2124
3241
  const stream = this.streamProvider.getStreamName(kind);
2125
3242
  const config = this.buildConfig(kind);
2126
3243
  const name = config.durable_name;
2127
- this.logger.log(`Recovering consumer: ${name} on stream: ${stream}`);
2128
- await this.assertNoMigrationInProgress(jsm, stream);
2129
- try {
2130
- return await jsm.consumers.info(stream, name);
2131
- } catch (err) {
2132
- if (!(err instanceof import_jetstream16.JetStreamApiError) || err.apiError().err_code !== 10014 /* ConsumerNotFound */) {
2133
- throw err;
3244
+ return withProvisioningSpan(
3245
+ this.otel,
3246
+ {
3247
+ serviceName: this.otelServiceName,
3248
+ endpoint: this.otelEndpoint,
3249
+ entity: "consumer",
3250
+ name,
3251
+ action: "recover"
3252
+ },
3253
+ async () => {
3254
+ this.logger.log(`Recovering consumer: ${name} on stream: ${stream}`);
3255
+ await this.assertNoMigrationInProgress(jsm, stream);
3256
+ try {
3257
+ return await jsm.consumers.info(stream, name);
3258
+ } catch (err) {
3259
+ if (!(err instanceof import_jetstream16.JetStreamApiError) || err.apiError().err_code !== 10014 /* ConsumerNotFound */) {
3260
+ throw err;
3261
+ }
3262
+ return await this.createConsumer(jsm, stream, name, config);
3263
+ }
2134
3264
  }
2135
- return await this.createConsumer(jsm, stream, name, config);
2136
- }
3265
+ );
2137
3266
  }
2138
3267
  /**
2139
3268
  * Throw if a migration backup stream exists for this stream.
@@ -2249,7 +3378,7 @@ var ConsumerProvider = class {
2249
3378
  };
2250
3379
 
2251
3380
  // src/server/infrastructure/message.provider.ts
2252
- var import_common8 = require("@nestjs/common");
3381
+ var import_common12 = require("@nestjs/common");
2253
3382
  var import_jetstream18 = require("@nats-io/jetstream");
2254
3383
  var import_rxjs3 = require("rxjs");
2255
3384
  var MessageProvider = class {
@@ -2259,7 +3388,7 @@ var MessageProvider = class {
2259
3388
  this.consumeOptionsMap = consumeOptionsMap;
2260
3389
  this.consumerRecoveryFn = consumerRecoveryFn;
2261
3390
  }
2262
- logger = new import_common8.Logger("Jetstream:Message");
3391
+ logger = new import_common12.Logger("Jetstream:Message");
2263
3392
  activeIterators = /* @__PURE__ */ new Set();
2264
3393
  orderedReadyResolve = null;
2265
3394
  orderedReadyReject = null;
@@ -2506,7 +3635,7 @@ var MessageProvider = class {
2506
3635
  };
2507
3636
 
2508
3637
  // src/server/infrastructure/metadata.provider.ts
2509
- var import_common9 = require("@nestjs/common");
3638
+ var import_common13 = require("@nestjs/common");
2510
3639
  var import_kv = require("@nats-io/kv");
2511
3640
  var MetadataProvider = class {
2512
3641
  constructor(options, connection) {
@@ -2515,7 +3644,7 @@ var MetadataProvider = class {
2515
3644
  this.replicas = options.metadata?.replicas ?? DEFAULT_METADATA_REPLICAS;
2516
3645
  this.ttl = Math.max(options.metadata?.ttl ?? DEFAULT_METADATA_TTL, MIN_METADATA_TTL);
2517
3646
  }
2518
- logger = new import_common9.Logger("Jetstream:Metadata");
3647
+ logger = new import_common13.Logger("Jetstream:Metadata");
2519
3648
  bucketName;
2520
3649
  replicas;
2521
3650
  ttl;
@@ -2608,7 +3737,7 @@ var MetadataProvider = class {
2608
3737
  };
2609
3738
 
2610
3739
  // src/server/routing/pattern-registry.ts
2611
- var import_common10 = require("@nestjs/common");
3740
+ var import_common14 = require("@nestjs/common");
2612
3741
  var HANDLER_LABELS = {
2613
3742
  ["broadcast" /* Broadcast */]: "broadcast" /* Broadcast */,
2614
3743
  ["ordered" /* Ordered */]: "ordered" /* Ordered */,
@@ -2619,7 +3748,7 @@ var PatternRegistry = class {
2619
3748
  constructor(options) {
2620
3749
  this.options = options;
2621
3750
  }
2622
- logger = new import_common10.Logger("Jetstream:PatternRegistry");
3751
+ logger = new import_common14.Logger("Jetstream:PatternRegistry");
2623
3752
  registry = /* @__PURE__ */ new Map();
2624
3753
  // Cached after registerHandlers() — the registry is immutable from that point
2625
3754
  cachedPatterns = null;
@@ -2776,8 +3905,13 @@ var PatternRegistry = class {
2776
3905
  };
2777
3906
 
2778
3907
  // src/server/routing/event.router.ts
2779
- var import_common11 = require("@nestjs/common");
3908
+ var import_common15 = require("@nestjs/common");
2780
3909
  var import_transport_node4 = require("@nats-io/transport-node");
3910
+ var eventConsumeKindFor = (kind) => {
3911
+ if (kind === "broadcast" /* Broadcast */) return "broadcast" /* Broadcast */;
3912
+ if (kind === "ordered" /* Ordered */) return "ordered" /* Ordered */;
3913
+ return "event" /* Event */;
3914
+ };
2781
3915
  var EventRouter = class {
2782
3916
  constructor(messageProvider, patternRegistry, codec, eventBus, deadLetterConfig, processingConfig, ackWaitMap, connection, options) {
2783
3917
  this.messageProvider = messageProvider;
@@ -2789,9 +3923,22 @@ var EventRouter = class {
2789
3923
  this.ackWaitMap = ackWaitMap;
2790
3924
  this.connection = connection;
2791
3925
  this.options = options;
3926
+ if (options) {
3927
+ const derived = deriveOtelAttrs(options);
3928
+ this.otel = derived.otel;
3929
+ this.serviceName = derived.serviceName;
3930
+ this.serverEndpoint = derived.serverEndpoint;
3931
+ } else {
3932
+ this.otel = resolveOtelOptions({ enabled: false });
3933
+ this.serviceName = "";
3934
+ this.serverEndpoint = null;
3935
+ }
2792
3936
  }
2793
- logger = new import_common11.Logger("Jetstream:EventRouter");
3937
+ logger = new import_common15.Logger("Jetstream:EventRouter");
2794
3938
  subscriptions = [];
3939
+ otel;
3940
+ serviceName;
3941
+ serverEndpoint;
2795
3942
  /**
2796
3943
  * Update the max_deliver thresholds from actual NATS consumer configs.
2797
3944
  * Called after consumers are ensured so the DLQ map reflects reality.
@@ -2821,8 +3968,12 @@ var EventRouter = class {
2821
3968
  const patternRegistry = this.patternRegistry;
2822
3969
  const codec = this.codec;
2823
3970
  const eventBus = this.eventBus;
2824
- const logger = this.logger;
3971
+ const logger5 = this.logger;
2825
3972
  const deadLetterConfig = this.deadLetterConfig;
3973
+ const otel = this.otel;
3974
+ const serviceName = this.serviceName;
3975
+ const serverEndpoint = this.serverEndpoint;
3976
+ const spanKind = eventConsumeKindFor(kind);
2826
3977
  const ackExtensionInterval = isOrdered ? null : resolveAckExtensionInterval(this.getAckExtensionConfig(kind), this.ackWaitMap?.get(kind));
2827
3978
  const hasAckExtension = ackExtensionInterval !== null && ackExtensionInterval > 0;
2828
3979
  const concurrency = this.getConcurrency(kind);
@@ -2853,7 +4004,7 @@ var EventRouter = class {
2853
4004
  const handler = patternRegistry.getHandler(subject);
2854
4005
  if (!handler) {
2855
4006
  msg.term(`No handler for event: ${subject}`);
2856
- logger.error(`No handler for subject: ${subject}`);
4007
+ logger5.error(`No handler for subject: ${subject}`);
2857
4008
  return null;
2858
4009
  }
2859
4010
  let data;
@@ -2861,17 +4012,17 @@ var EventRouter = class {
2861
4012
  data = codec.decode(msg.data);
2862
4013
  } catch (err) {
2863
4014
  msg.term("Decode error");
2864
- logger.error(`Decode error for ${subject}:`, err);
4015
+ logger5.error(`Decode error for ${subject}:`, err);
2865
4016
  return null;
2866
4017
  }
2867
4018
  if (emitRouted) eventBus.emitMessageRouted(subject, "event" /* Event */);
2868
4019
  return { handler, data };
2869
4020
  } catch (err) {
2870
- logger.error(`Unexpected error in ${kind} event router`, err);
4021
+ logger5.error(`Unexpected error in ${kind} event router`, err);
2871
4022
  try {
2872
4023
  msg.term("Unexpected router error");
2873
4024
  } catch (termErr) {
2874
- logger.error(`Failed to terminate message ${subject}:`, termErr);
4025
+ logger5.error(`Failed to terminate message ${subject}:`, termErr);
2875
4026
  }
2876
4027
  return null;
2877
4028
  }
@@ -2884,13 +4035,31 @@ var EventRouter = class {
2884
4035
  const stopAckExtension = hasAckExtension ? startAckExtensionTimer(msg, ackExtensionInterval) : null;
2885
4036
  let pending;
2886
4037
  try {
2887
- pending = unwrapResult(handler(data, ctx));
4038
+ pending = withConsumeSpan(
4039
+ {
4040
+ subject: msg.subject,
4041
+ msg,
4042
+ info: msg.info,
4043
+ kind: spanKind,
4044
+ payloadBytes: msg.data.length,
4045
+ handlerMetadata: { pattern: msg.subject },
4046
+ serviceName,
4047
+ endpoint: serverEndpoint
4048
+ },
4049
+ otel,
4050
+ () => unwrapResult(handler(data, ctx))
4051
+ );
2888
4052
  } catch (err) {
2889
- logger.error(`Event handler error (${msg.subject}) in ${kind} router:`, err);
2890
- if (stopAckExtension !== null) stopAckExtension();
2891
- return settleFailure(msg, data, err);
4053
+ eventBus.emit(
4054
+ "error" /* Error */,
4055
+ err instanceof Error ? err : new Error(String(err)),
4056
+ `${kind}-handler:${msg.subject}`
4057
+ );
4058
+ return settleFailure(msg, data, err).finally(() => {
4059
+ if (stopAckExtension !== null) stopAckExtension();
4060
+ });
2892
4061
  }
2893
- if (!isPromiseLike(pending)) {
4062
+ if (!isPromiseLike2(pending)) {
2894
4063
  settleSuccess(msg, ctx);
2895
4064
  if (stopAckExtension !== null) stopAckExtension();
2896
4065
  return void 0;
@@ -2901,7 +4070,11 @@ var EventRouter = class {
2901
4070
  if (stopAckExtension !== null) stopAckExtension();
2902
4071
  },
2903
4072
  async (err) => {
2904
- logger.error(`Event handler error (${msg.subject}) in ${kind} router:`, err);
4073
+ eventBus.emit(
4074
+ "error" /* Error */,
4075
+ err instanceof Error ? err : new Error(String(err)),
4076
+ `${kind}-handler:${msg.subject}`
4077
+ );
2905
4078
  try {
2906
4079
  await settleFailure(msg, data, err);
2907
4080
  } finally {
@@ -2917,41 +4090,54 @@ var EventRouter = class {
2917
4090
  try {
2918
4091
  handler = patternRegistry.getHandler(subject);
2919
4092
  if (!handler) {
2920
- logger.error(`No handler for subject: ${subject}`);
4093
+ logger5.error(`No handler for subject: ${subject}`);
2921
4094
  return void 0;
2922
4095
  }
2923
4096
  try {
2924
4097
  data = codec.decode(msg.data);
2925
4098
  } catch (err) {
2926
- logger.error(`Decode error for ${subject}:`, err);
4099
+ logger5.error(`Decode error for ${subject}:`, err);
2927
4100
  return void 0;
2928
4101
  }
2929
4102
  if (emitRouted) eventBus.emitMessageRouted(subject, "event" /* Event */);
2930
4103
  } catch (err) {
2931
- logger.error(`Ordered handler error (${subject}):`, err);
4104
+ logger5.error(`Ordered handler error (${subject}):`, err);
2932
4105
  return void 0;
2933
4106
  }
2934
4107
  const ctx = new RpcContext([msg]);
2935
4108
  const warnIfSettlementAttempted = () => {
2936
4109
  if (ctx.shouldRetry || ctx.shouldTerminate) {
2937
- logger.warn(
4110
+ logger5.warn(
2938
4111
  `retry()/terminate() ignored for ordered message ${subject} \u2014 ordered consumers auto-acknowledge`
2939
4112
  );
2940
4113
  }
2941
4114
  };
2942
4115
  let pending;
2943
4116
  try {
2944
- pending = unwrapResult(handler(data, ctx));
4117
+ pending = withConsumeSpan(
4118
+ {
4119
+ subject: msg.subject,
4120
+ msg,
4121
+ info: msg.info,
4122
+ kind: spanKind,
4123
+ payloadBytes: msg.data.length,
4124
+ handlerMetadata: { pattern: msg.subject },
4125
+ serviceName,
4126
+ endpoint: serverEndpoint
4127
+ },
4128
+ otel,
4129
+ () => unwrapResult(handler(data, ctx))
4130
+ );
2945
4131
  } catch (err) {
2946
- logger.error(`Ordered handler error (${subject}):`, err);
4132
+ logger5.error(`Ordered handler error (${subject}):`, err);
2947
4133
  return void 0;
2948
4134
  }
2949
- if (!isPromiseLike(pending)) {
4135
+ if (!isPromiseLike2(pending)) {
2950
4136
  warnIfSettlementAttempted();
2951
4137
  return void 0;
2952
4138
  }
2953
4139
  return pending.then(warnIfSettlementAttempted, (err) => {
2954
- logger.error(`Ordered handler error (${subject}):`, err);
4140
+ logger5.error(`Ordered handler error (${subject}):`, err);
2955
4141
  });
2956
4142
  };
2957
4143
  const route = isOrdered ? handleOrderedSafe : handleSafe;
@@ -2984,7 +4170,7 @@ var EventRouter = class {
2984
4170
  backlog.push(msg);
2985
4171
  if (!backlogWarned && backlog.length >= backlogWarnThreshold) {
2986
4172
  backlogWarned = true;
2987
- logger.warn(
4173
+ logger5.warn(
2988
4174
  `${kind} backlog reached ${backlog.length} messages \u2014 consumer may be falling behind`
2989
4175
  );
2990
4176
  }
@@ -3000,7 +4186,7 @@ var EventRouter = class {
3000
4186
  }
3001
4187
  },
3002
4188
  error: (err) => {
3003
- logger.error(`Stream error in ${kind} router`, err);
4189
+ logger5.error(`Stream error in ${kind} router`, err);
3004
4190
  }
3005
4191
  });
3006
4192
  this.subscriptions.push(subscription);
@@ -3015,14 +4201,11 @@ var EventRouter = class {
3015
4201
  if (kind === "broadcast" /* Broadcast */) return this.processingConfig?.broadcast?.ackExtension;
3016
4202
  return void 0;
3017
4203
  }
3018
- /** Handle a dead letter: invoke callback, then term or nak based on result. */
3019
4204
  /**
3020
- * Fallback execution for a dead letter when DLQ is disabled, or when
3021
- * publishing to the DLQ stream fails (due to network or NATS errors).
3022
- *
3023
- * Triggers the user-provided `onDeadLetter` hook for logging/alerting.
3024
- * On success, terminates the message. On error, leaves it unacknowledged (nak)
3025
- * so NATS can retry the delivery on the next cycle.
4205
+ * Last-resort path for a dead letter: invoke `onDeadLetter`, then `term` on
4206
+ * success or `nak` on hook failure so NATS retries on the next delivery
4207
+ * cycle. Used when DLQ stream isn't configured, or when publishing to it
4208
+ * failed and we still have to surface the message somewhere observable.
3026
4209
  */
3027
4210
  async fallbackToOnDeadLetterCallback(info, msg) {
3028
4211
  if (!this.deadLetterConfig) {
@@ -3114,20 +4297,37 @@ var EventRouter = class {
3114
4297
  streamSequence: msg.info.streamSequence,
3115
4298
  timestamp: new Date(msg.info.timestampNanos / 1e6).toISOString()
3116
4299
  };
3117
- this.eventBus.emit("deadLetter" /* DeadLetter */, info);
3118
- if (!this.options?.dlq) {
3119
- await this.fallbackToOnDeadLetterCallback(info, msg);
3120
- } else {
3121
- await this.publishToDlq(msg, info, error);
3122
- }
4300
+ await withDeadLetterSpan(
4301
+ {
4302
+ msg,
4303
+ // Pattern resolution mirrors event-routing: when a registered
4304
+ // pattern matches, surface it on the DLQ span so APM can filter
4305
+ // dead letters by handler without parsing the subject. Falls back
4306
+ // to the subject itself when no glob handler is in play.
4307
+ pattern: this.patternRegistry.getHandler(msg.subject) ? msg.subject : void 0,
4308
+ finalDeliveryCount: msg.info.deliveryCount,
4309
+ reason: error instanceof Error ? error.message : String(error),
4310
+ serviceName: this.serviceName,
4311
+ endpoint: this.serverEndpoint
4312
+ },
4313
+ this.otel,
4314
+ async () => {
4315
+ this.eventBus.emit("deadLetter" /* DeadLetter */, info);
4316
+ if (!this.options?.dlq) {
4317
+ await this.fallbackToOnDeadLetterCallback(info, msg);
4318
+ } else {
4319
+ await this.publishToDlq(msg, info, error);
4320
+ }
4321
+ }
4322
+ );
3123
4323
  }
3124
4324
  };
3125
4325
 
3126
4326
  // src/server/routing/rpc.router.ts
3127
- var import_common12 = require("@nestjs/common");
4327
+ var import_common16 = require("@nestjs/common");
3128
4328
  var import_transport_node5 = require("@nats-io/transport-node");
3129
4329
  var RpcRouter = class {
3130
- constructor(messageProvider, patternRegistry, connection, codec, eventBus, rpcOptions, ackWaitMap) {
4330
+ constructor(messageProvider, patternRegistry, connection, codec, eventBus, rpcOptions, ackWaitMap, options) {
3131
4331
  this.messageProvider = messageProvider;
3132
4332
  this.patternRegistry = patternRegistry;
3133
4333
  this.connection = connection;
@@ -3137,13 +4337,26 @@ var RpcRouter = class {
3137
4337
  this.ackWaitMap = ackWaitMap;
3138
4338
  this.timeout = rpcOptions?.timeout ?? DEFAULT_JETSTREAM_RPC_TIMEOUT;
3139
4339
  this.concurrency = rpcOptions?.concurrency;
4340
+ if (options) {
4341
+ const derived = deriveOtelAttrs(options);
4342
+ this.otel = derived.otel;
4343
+ this.serviceName = derived.serviceName;
4344
+ this.serverEndpoint = derived.serverEndpoint;
4345
+ } else {
4346
+ this.otel = resolveOtelOptions({ enabled: false });
4347
+ this.serviceName = "";
4348
+ this.serverEndpoint = null;
4349
+ }
3140
4350
  }
3141
- logger = new import_common12.Logger("Jetstream:RpcRouter");
4351
+ logger = new import_common16.Logger("Jetstream:RpcRouter");
3142
4352
  timeout;
3143
4353
  concurrency;
3144
4354
  resolvedAckExtensionInterval;
3145
4355
  subscription = null;
3146
4356
  cachedNc = null;
4357
+ otel;
4358
+ serviceName;
4359
+ serverEndpoint;
3147
4360
  /** Lazily resolve the ack extension interval (needs ackWaitMap populated at runtime). */
3148
4361
  get ackExtensionInterval() {
3149
4362
  if (this.resolvedAckExtensionInterval !== void 0) return this.resolvedAckExtensionInterval;
@@ -3160,11 +4373,14 @@ var RpcRouter = class {
3160
4373
  const patternRegistry = this.patternRegistry;
3161
4374
  const codec = this.codec;
3162
4375
  const eventBus = this.eventBus;
3163
- const logger = this.logger;
4376
+ const logger5 = this.logger;
3164
4377
  const timeout = this.timeout;
3165
4378
  const ackExtensionInterval = this.ackExtensionInterval;
3166
4379
  const hasAckExtension = ackExtensionInterval !== null && ackExtensionInterval > 0;
3167
4380
  const maxActive = this.concurrency ?? Number.POSITIVE_INFINITY;
4381
+ const otel = this.otel;
4382
+ const serviceName = this.serviceName;
4383
+ const serverEndpoint = this.serverEndpoint;
3168
4384
  const emitRpcTimeout = (subject, correlationId) => {
3169
4385
  eventBus.emit("rpcTimeout" /* RpcTimeout */, subject, correlationId);
3170
4386
  };
@@ -3174,7 +4390,7 @@ var RpcRouter = class {
3174
4390
  hdrs.set("x-correlation-id" /* CorrelationId */, correlationId);
3175
4391
  nc.publish(replyTo, codec.encode(payload), { headers: hdrs });
3176
4392
  } catch (publishErr) {
3177
- logger.error(`Failed to publish RPC response`, publishErr);
4393
+ logger5.error(`Failed to publish RPC response`, publishErr);
3178
4394
  }
3179
4395
  };
3180
4396
  const publishErrorReply = (replyTo, correlationId, subject, err) => {
@@ -3184,7 +4400,7 @@ var RpcRouter = class {
3184
4400
  hdrs.set("x-error" /* Error */, "true");
3185
4401
  nc.publish(replyTo, codec.encode(serializeError(err)), { headers: hdrs });
3186
4402
  } catch (encodeErr) {
3187
- logger.error(`Failed to encode RPC error for ${subject}`, encodeErr);
4403
+ logger5.error(`Failed to encode RPC error for ${subject}`, encodeErr);
3188
4404
  }
3189
4405
  };
3190
4406
  const resolveCommand = (msg) => {
@@ -3193,7 +4409,7 @@ var RpcRouter = class {
3193
4409
  const handler = patternRegistry.getHandler(subject);
3194
4410
  if (!handler) {
3195
4411
  msg.term(`No handler for RPC: ${subject}`);
3196
- logger.error(`No handler for RPC subject: ${subject}`);
4412
+ logger5.error(`No handler for RPC subject: ${subject}`);
3197
4413
  return null;
3198
4414
  }
3199
4415
  const msgHeaders = msg.headers;
@@ -3201,7 +4417,7 @@ var RpcRouter = class {
3201
4417
  const correlationId = msgHeaders?.get("x-correlation-id" /* CorrelationId */);
3202
4418
  if (!replyTo || !correlationId) {
3203
4419
  msg.term("Missing required headers (reply-to or correlation-id)");
3204
- logger.error(`Missing headers for RPC: ${subject}`);
4420
+ logger5.error(`Missing headers for RPC: ${subject}`);
3205
4421
  return null;
3206
4422
  }
3207
4423
  let data;
@@ -3209,17 +4425,17 @@ var RpcRouter = class {
3209
4425
  data = codec.decode(msg.data);
3210
4426
  } catch (err) {
3211
4427
  msg.term("Decode error");
3212
- logger.error(`Decode error for RPC ${subject}:`, err);
4428
+ logger5.error(`Decode error for RPC ${subject}:`, err);
3213
4429
  return null;
3214
4430
  }
3215
4431
  eventBus.emitMessageRouted(subject, "rpc" /* Rpc */);
3216
4432
  return { handler, data, replyTo, correlationId };
3217
4433
  } catch (err) {
3218
- logger.error("Unexpected error in RPC router", err);
4434
+ logger5.error("Unexpected error in RPC router", err);
3219
4435
  try {
3220
4436
  msg.term("Unexpected router error");
3221
4437
  } catch (termErr) {
3222
- logger.error(`Failed to terminate RPC message ${subject}:`, termErr);
4438
+ logger5.error(`Failed to terminate RPC message ${subject}:`, termErr);
3223
4439
  }
3224
4440
  return null;
3225
4441
  }
@@ -3231,17 +4447,39 @@ var RpcRouter = class {
3231
4447
  const subject = msg.subject;
3232
4448
  const ctx = new RpcContext([msg]);
3233
4449
  const stopAckExtension = hasAckExtension ? startAckExtensionTimer(msg, ackExtensionInterval) : null;
4450
+ const reportHandlerError = (err) => {
4451
+ eventBus.emit(
4452
+ "error" /* Error */,
4453
+ err instanceof Error ? err : new Error(String(err)),
4454
+ `rpc-handler:${subject}`
4455
+ );
4456
+ publishErrorReply(replyTo, correlationId, subject, err);
4457
+ msg.term(`Handler error: ${subject}`);
4458
+ };
4459
+ const abortController = new AbortController();
3234
4460
  let pending;
3235
4461
  try {
3236
- pending = unwrapResult(handler(data, ctx));
4462
+ pending = withConsumeSpan(
4463
+ {
4464
+ subject,
4465
+ msg,
4466
+ info: msg.info,
4467
+ kind: "rpc" /* Rpc */,
4468
+ payloadBytes: msg.data.length,
4469
+ handlerMetadata: { pattern: subject },
4470
+ serviceName,
4471
+ endpoint: serverEndpoint
4472
+ },
4473
+ otel,
4474
+ () => unwrapResult(handler(data, ctx)),
4475
+ { signal: abortController.signal, timeoutLabel: "rpc.handler.timeout" }
4476
+ );
3237
4477
  } catch (err) {
3238
4478
  if (stopAckExtension !== null) stopAckExtension();
3239
- logger.error(`RPC handler error (${subject}):`, err);
3240
- publishErrorReply(replyTo, correlationId, subject, err);
3241
- msg.term(`Handler error: ${subject}`);
4479
+ reportHandlerError(err);
3242
4480
  return void 0;
3243
4481
  }
3244
- if (!isPromiseLike(pending)) {
4482
+ if (!isPromiseLike2(pending)) {
3245
4483
  if (stopAckExtension !== null) stopAckExtension();
3246
4484
  msg.ack();
3247
4485
  publishReply(replyTo, correlationId, pending);
@@ -3252,7 +4490,7 @@ var RpcRouter = class {
3252
4490
  if (settled) return;
3253
4491
  settled = true;
3254
4492
  if (stopAckExtension !== null) stopAckExtension();
3255
- logger.error(`RPC timeout (${timeout}ms): ${subject}`);
4493
+ abortController.abort();
3256
4494
  emitRpcTimeout(subject, correlationId);
3257
4495
  msg.term("Handler timeout");
3258
4496
  }, timeout);
@@ -3270,9 +4508,7 @@ var RpcRouter = class {
3270
4508
  settled = true;
3271
4509
  clearTimeout(timeoutId);
3272
4510
  if (stopAckExtension !== null) stopAckExtension();
3273
- logger.error(`RPC handler error (${subject}):`, err);
3274
- publishErrorReply(replyTo, correlationId, subject, err);
3275
- msg.term(`Handler error: ${subject}`);
4511
+ reportHandlerError(err);
3276
4512
  }
3277
4513
  );
3278
4514
  };
@@ -3304,7 +4540,7 @@ var RpcRouter = class {
3304
4540
  backlog.push(msg);
3305
4541
  if (!backlogWarned && backlog.length >= backlogWarnThreshold) {
3306
4542
  backlogWarned = true;
3307
- logger.warn(
4543
+ logger5.warn(
3308
4544
  `RPC backlog reached ${backlog.length} messages \u2014 consumer may be falling behind`
3309
4545
  );
3310
4546
  }
@@ -3320,7 +4556,7 @@ var RpcRouter = class {
3320
4556
  }
3321
4557
  },
3322
4558
  error: (err) => {
3323
- logger.error("Stream error in RPC router", err);
4559
+ logger5.error("Stream error in RPC router", err);
3324
4560
  }
3325
4561
  });
3326
4562
  }
@@ -3332,14 +4568,14 @@ var RpcRouter = class {
3332
4568
  };
3333
4569
 
3334
4570
  // src/shutdown/shutdown.manager.ts
3335
- var import_common13 = require("@nestjs/common");
4571
+ var import_common17 = require("@nestjs/common");
3336
4572
  var ShutdownManager = class {
3337
4573
  constructor(connection, eventBus, timeout) {
3338
4574
  this.connection = connection;
3339
4575
  this.eventBus = eventBus;
3340
4576
  this.timeout = timeout;
3341
4577
  }
3342
- logger = new import_common13.Logger("Jetstream:Shutdown");
4578
+ logger = new import_common17.Logger("Jetstream:Shutdown");
3343
4579
  shutdownPromise;
3344
4580
  /**
3345
4581
  * Execute the full shutdown sequence.
@@ -3379,9 +4615,6 @@ var JetstreamModule = class {
3379
4615
  this.shutdownManager = shutdownManager;
3380
4616
  this.strategy = strategy;
3381
4617
  }
3382
- // -------------------------------------------------------------------
3383
- // forRoot — global module registration
3384
- // -------------------------------------------------------------------
3385
4618
  /**
3386
4619
  * Register the JetStream transport globally.
3387
4620
  *
@@ -3408,9 +4641,6 @@ var JetstreamModule = class {
3408
4641
  ]
3409
4642
  };
3410
4643
  }
3411
- // -------------------------------------------------------------------
3412
- // forRootAsync — async global module registration
3413
- // -------------------------------------------------------------------
3414
4644
  /**
3415
4645
  * Register the JetStream transport globally with async configuration.
3416
4646
  *
@@ -3439,9 +4669,6 @@ var JetstreamModule = class {
3439
4669
  ]
3440
4670
  };
3441
4671
  }
3442
- // -------------------------------------------------------------------
3443
- // forFeature — per-module client registration
3444
- // -------------------------------------------------------------------
3445
4672
  /**
3446
4673
  * Register a lightweight client proxy for a target service.
3447
4674
  *
@@ -3467,9 +4694,6 @@ var JetstreamModule = class {
3467
4694
  exports: [clientToken]
3468
4695
  };
3469
4696
  }
3470
- // -------------------------------------------------------------------
3471
- // Provider factories
3472
- // -------------------------------------------------------------------
3473
4697
  static createCoreProviders(options) {
3474
4698
  return [
3475
4699
  {
@@ -3487,8 +4711,8 @@ var JetstreamModule = class {
3487
4711
  provide: JETSTREAM_EVENT_BUS,
3488
4712
  inject: [JETSTREAM_OPTIONS],
3489
4713
  useFactory: (options) => {
3490
- const logger = new import_common14.Logger("Jetstream:Module");
3491
- return new EventBus(logger, options.hooks);
4714
+ const logger5 = new import_common18.Logger("Jetstream:Module");
4715
+ return new EventBus(logger5, options.hooks);
3492
4716
  }
3493
4717
  },
3494
4718
  // Codec — global encode/decode
@@ -3527,10 +4751,8 @@ var JetstreamModule = class {
3527
4751
  );
3528
4752
  }
3529
4753
  },
3530
- // ---------------------------------------------------------------
3531
4754
  // Consumer infrastructure — only created when consumer !== false.
3532
4755
  // Providers return null when consumer is disabled (publisher-only mode).
3533
- // ---------------------------------------------------------------
3534
4756
  // PatternRegistry — subject-to-handler mapping
3535
4757
  {
3536
4758
  provide: PatternRegistry,
@@ -3566,8 +4788,14 @@ var JetstreamModule = class {
3566
4788
  // MessageProvider — pull-based message consumption
3567
4789
  {
3568
4790
  provide: MessageProvider,
3569
- inject: [JETSTREAM_OPTIONS, JETSTREAM_CONNECTION, JETSTREAM_EVENT_BUS, ConsumerProvider],
3570
- useFactory: (options, connection, eventBus, consumerProvider) => {
4791
+ inject: [
4792
+ JETSTREAM_OPTIONS,
4793
+ JETSTREAM_CONNECTION,
4794
+ JETSTREAM_EVENT_BUS,
4795
+ ConsumerProvider,
4796
+ StreamProvider
4797
+ ],
4798
+ useFactory: (options, connection, eventBus, consumerProvider, streamProvider) => {
3571
4799
  if (options.consumer === false) return null;
3572
4800
  const consumeOptionsMap = /* @__PURE__ */ new Map();
3573
4801
  if (options.events?.consume)
@@ -3577,10 +4805,22 @@ var JetstreamModule = class {
3577
4805
  if (options.rpc?.mode === "jetstream" && options.rpc.consume) {
3578
4806
  consumeOptionsMap.set("cmd" /* Command */, options.rpc.consume);
3579
4807
  }
3580
- const consumerRecoveryFn = consumerProvider ? async (kind) => {
3581
- const jsm = await connection.getJetStreamManager();
3582
- return consumerProvider.recoverConsumer(jsm, kind);
3583
- } : void 0;
4808
+ const derived = deriveOtelAttrs(options);
4809
+ const { otel, serverEndpoint: otelEndpoint, serviceName: otelServiceName } = derived;
4810
+ const consumerRecoveryFn = consumerProvider && streamProvider ? async (kind) => withSelfHealingSpan(
4811
+ otel,
4812
+ {
4813
+ serviceName: otelServiceName,
4814
+ endpoint: otelEndpoint,
4815
+ consumer: consumerProvider.getConsumerName(kind),
4816
+ stream: streamProvider.getStreamName(kind),
4817
+ reason: "consumer not found"
4818
+ },
4819
+ async () => {
4820
+ const jsm = await connection.getJetStreamManager();
4821
+ return consumerProvider.recoverConsumer(jsm, kind);
4822
+ }
4823
+ ) : void 0;
3584
4824
  return new MessageProvider(connection, eventBus, consumeOptionsMap, consumerRecoveryFn);
3585
4825
  }
3586
4826
  },
@@ -3651,7 +4891,8 @@ var JetstreamModule = class {
3651
4891
  codec,
3652
4892
  eventBus,
3653
4893
  rpcOptions,
3654
- ackWaitMap
4894
+ ackWaitMap,
4895
+ options
3655
4896
  );
3656
4897
  }
3657
4898
  },
@@ -3754,9 +4995,6 @@ var JetstreamModule = class {
3754
4995
  }
3755
4996
  ];
3756
4997
  }
3757
- // -------------------------------------------------------------------
3758
- // Lifecycle hooks
3759
- // -------------------------------------------------------------------
3760
4998
  /**
3761
4999
  * Gracefully shut down the transport on application termination.
3762
5000
  */
@@ -3767,15 +5005,16 @@ var JetstreamModule = class {
3767
5005
  }
3768
5006
  };
3769
5007
  JetstreamModule = __decorateClass([
3770
- (0, import_common14.Global)(),
3771
- (0, import_common14.Module)({}),
3772
- __decorateParam(0, (0, import_common14.Optional)()),
3773
- __decorateParam(0, (0, import_common14.Inject)(ShutdownManager)),
3774
- __decorateParam(1, (0, import_common14.Optional)()),
3775
- __decorateParam(1, (0, import_common14.Inject)(JetstreamStrategy))
5008
+ (0, import_common18.Global)(),
5009
+ (0, import_common18.Module)({}),
5010
+ __decorateParam(0, (0, import_common18.Optional)()),
5011
+ __decorateParam(0, (0, import_common18.Inject)(ShutdownManager)),
5012
+ __decorateParam(1, (0, import_common18.Optional)()),
5013
+ __decorateParam(1, (0, import_common18.Inject)(JetstreamStrategy))
3776
5014
  ], JetstreamModule);
3777
5015
  // Annotate the CommonJS export names for ESM import in node:
3778
5016
  0 && (module.exports = {
5017
+ ConsumeKind,
3779
5018
  DEFAULT_BROADCAST_CONSUMER_CONFIG,
3780
5019
  DEFAULT_BROADCAST_STREAM_CONFIG,
3781
5020
  DEFAULT_COMMAND_CONSUMER_CONFIG,
@@ -3791,6 +5030,7 @@ JetstreamModule = __decorateClass([
3791
5030
  DEFAULT_ORDERED_STREAM_CONFIG,
3792
5031
  DEFAULT_RPC_TIMEOUT,
3793
5032
  DEFAULT_SHUTDOWN_TIMEOUT,
5033
+ DEFAULT_TRACES,
3794
5034
  JETSTREAM_CODEC,
3795
5035
  JETSTREAM_CONNECTION,
3796
5036
  JETSTREAM_OPTIONS,
@@ -3802,15 +5042,18 @@ JetstreamModule = __decorateClass([
3802
5042
  JetstreamRecord,
3803
5043
  JetstreamRecordBuilder,
3804
5044
  JetstreamStrategy,
5045
+ JetstreamTrace,
3805
5046
  JsonCodec,
3806
5047
  MIN_METADATA_TTL,
3807
5048
  MessageKind,
3808
5049
  MsgpackCodec,
3809
5050
  NatsErrorCode,
3810
5051
  PatternPrefix,
5052
+ PublishKind,
3811
5053
  RESERVED_HEADERS,
3812
5054
  RpcContext,
3813
5055
  StreamKind,
5056
+ TRACER_NAME,
3814
5057
  TransportEvent,
3815
5058
  buildBroadcastSubject,
3816
5059
  buildSubject,