@camstack/addon-pipeline 1.1.42 → 1.1.43

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.
@@ -3935,12 +3935,15 @@ var PipelineExecutor = class {
3935
3935
  try {
3936
3936
  await this.executeChildren(rootStep.children, mutable, fullFrameJpegProvider, imageWidth, imageHeight, traceBuilder, stepTimings, ctx, poolAgg);
3937
3937
  } catch (err) {
3938
- this.opts.logger?.warn("Pipeline child execution failed — keeping parent detection", { meta: {
3939
- rootStepId: rootStep.stepId,
3940
- parentClass: mutable.macroClass,
3941
- parentScore: mutable.score,
3942
- error: require_dist.errMsg(err)
3943
- } });
3938
+ this.opts.logger?.warn("Pipeline child execution failed — keeping parent detection", {
3939
+ tags: { deviceId },
3940
+ meta: {
3941
+ rootStepId: rootStep.stepId,
3942
+ parentClass: mutable.macroClass,
3943
+ parentScore: mutable.score,
3944
+ error: require_dist.errMsg(err)
3945
+ }
3946
+ });
3944
3947
  }
3945
3948
  firstLevel.push(mutable);
3946
3949
  }
@@ -3928,12 +3928,15 @@ var PipelineExecutor = class {
3928
3928
  try {
3929
3929
  await this.executeChildren(rootStep.children, mutable, fullFrameJpegProvider, imageWidth, imageHeight, traceBuilder, stepTimings, ctx, poolAgg);
3930
3930
  } catch (err) {
3931
- this.opts.logger?.warn("Pipeline child execution failed — keeping parent detection", { meta: {
3932
- rootStepId: rootStep.stepId,
3933
- parentClass: mutable.macroClass,
3934
- parentScore: mutable.score,
3935
- error: errMsg(err)
3936
- } });
3931
+ this.opts.logger?.warn("Pipeline child execution failed — keeping parent detection", {
3932
+ tags: { deviceId },
3933
+ meta: {
3934
+ rootStepId: rootStep.stepId,
3935
+ parentClass: mutable.macroClass,
3936
+ parentScore: mutable.score,
3937
+ error: errMsg(err)
3938
+ }
3939
+ });
3937
3940
  }
3938
3941
  firstLevel.push(mutable);
3939
3942
  }
@@ -448,13 +448,16 @@ async function runRedundancyJanitor(deps) {
448
448
  files += vrows.length;
449
449
  bytes += reclaimed;
450
450
  } catch (err) {
451
- deps.logger.warn("janitor: evict failed (skipping)", { meta: {
452
- deviceId,
453
- profile,
454
- location,
455
- count: vrows.length,
456
- error: err instanceof Error ? err.message : String(err)
457
- } });
451
+ deps.logger.warn("janitor: evict failed (skipping)", {
452
+ tags: { deviceId },
453
+ meta: {
454
+ deviceId,
455
+ profile,
456
+ location,
457
+ count: vrows.length,
458
+ error: err instanceof Error ? err.message : String(err)
459
+ }
460
+ });
458
461
  }
459
462
  }
460
463
  }
@@ -1091,9 +1094,12 @@ function buildRecordingProvider(deps) {
1091
1094
  return require_dist.hydrateSchema(buildRecordingDeviceSchema(), {});
1092
1095
  },
1093
1096
  getDeviceLiveContribution: async () => null,
1094
- applyDeviceSettingsPatch: async ({ patch }) => {
1097
+ applyDeviceSettingsPatch: async ({ deviceId, patch }) => {
1095
1098
  const keys = Object.keys(patch ?? {});
1096
- if (keys.length > 0) deps.logger.debug("recorder: ignoring legacy settings patch (widget owns settings)", { meta: { keys } });
1099
+ if (keys.length > 0) deps.logger.debug("recorder: ignoring legacy settings patch (widget owns settings)", {
1100
+ tags: { deviceId },
1101
+ meta: { keys }
1102
+ });
1097
1103
  return { success: true };
1098
1104
  }
1099
1105
  };
@@ -1880,13 +1886,14 @@ var RecordingController = class {
1880
1886
  }));
1881
1887
  const outDir = node_path.default.join(placement.root, STAGING_DIR_NAME, String(deviceId), profile);
1882
1888
  await node_fs.promises.mkdir(outDir, { recursive: true });
1889
+ const deviceLog = this.deps.logger.withTags({ deviceId });
1883
1890
  const writer = new SegmentWriter({
1884
1891
  rtspUrl: source.url,
1885
1892
  outDir,
1886
1893
  segmentSeconds
1887
1894
  }, {
1888
1895
  spawn: this.deps.spawn,
1889
- logger: this.deps.logger,
1896
+ logger: deviceLog,
1890
1897
  onGaveUp: () => {
1891
1898
  this.recoverWriterGaveUp(deviceId);
1892
1899
  }
@@ -1901,7 +1908,7 @@ var RecordingController = class {
1901
1908
  onFinalized: (startMs, durMs, flatAbsPath) => {
1902
1909
  this.handleFinalizedSegment(deviceId, profile, placement, startMs, durMs, flatAbsPath);
1903
1910
  },
1904
- logger: this.deps.logger
1911
+ logger: deviceLog
1905
1912
  }),
1906
1913
  pipelineKey: source.pipelineKey,
1907
1914
  outDir
@@ -447,13 +447,16 @@ async function runRedundancyJanitor(deps) {
447
447
  files += vrows.length;
448
448
  bytes += reclaimed;
449
449
  } catch (err) {
450
- deps.logger.warn("janitor: evict failed (skipping)", { meta: {
451
- deviceId,
452
- profile,
453
- location,
454
- count: vrows.length,
455
- error: err instanceof Error ? err.message : String(err)
456
- } });
450
+ deps.logger.warn("janitor: evict failed (skipping)", {
451
+ tags: { deviceId },
452
+ meta: {
453
+ deviceId,
454
+ profile,
455
+ location,
456
+ count: vrows.length,
457
+ error: err instanceof Error ? err.message : String(err)
458
+ }
459
+ });
457
460
  }
458
461
  }
459
462
  }
@@ -1090,9 +1093,12 @@ function buildRecordingProvider(deps) {
1090
1093
  return hydrateSchema(buildRecordingDeviceSchema(), {});
1091
1094
  },
1092
1095
  getDeviceLiveContribution: async () => null,
1093
- applyDeviceSettingsPatch: async ({ patch }) => {
1096
+ applyDeviceSettingsPatch: async ({ deviceId, patch }) => {
1094
1097
  const keys = Object.keys(patch ?? {});
1095
- if (keys.length > 0) deps.logger.debug("recorder: ignoring legacy settings patch (widget owns settings)", { meta: { keys } });
1098
+ if (keys.length > 0) deps.logger.debug("recorder: ignoring legacy settings patch (widget owns settings)", {
1099
+ tags: { deviceId },
1100
+ meta: { keys }
1101
+ });
1096
1102
  return { success: true };
1097
1103
  }
1098
1104
  };
@@ -1879,13 +1885,14 @@ var RecordingController = class {
1879
1885
  }));
1880
1886
  const outDir = path.join(placement.root, STAGING_DIR_NAME, String(deviceId), profile);
1881
1887
  await promises.mkdir(outDir, { recursive: true });
1888
+ const deviceLog = this.deps.logger.withTags({ deviceId });
1882
1889
  const writer = new SegmentWriter({
1883
1890
  rtspUrl: source.url,
1884
1891
  outDir,
1885
1892
  segmentSeconds
1886
1893
  }, {
1887
1894
  spawn: this.deps.spawn,
1888
- logger: this.deps.logger,
1895
+ logger: deviceLog,
1889
1896
  onGaveUp: () => {
1890
1897
  this.recoverWriterGaveUp(deviceId);
1891
1898
  }
@@ -1900,7 +1907,7 @@ var RecordingController = class {
1900
1907
  onFinalized: (startMs, durMs, flatAbsPath) => {
1901
1908
  this.handleFinalizedSegment(deviceId, profile, placement, startMs, durMs, flatAbsPath);
1902
1909
  },
1903
- logger: this.deps.logger
1910
+ logger: deviceLog
1904
1911
  }),
1905
1912
  pipelineKey: source.pipelineKey,
1906
1913
  outDir
@@ -318,6 +318,16 @@ var DecodeWorkerChild = class {
318
318
  abortController = null;
319
319
  started = false;
320
320
  stopped = false;
321
+ /**
322
+ * The numeric device id this worker decodes for — learned from the `start`
323
+ * message's {@link VideoFrameSource}. The child's stderr is INHERITED by the
324
+ * pipeline-runner (silent:false fork), so these lines land in the runner's
325
+ * raw stderr WITHOUT passing through a scoped logger; prefixing every line
326
+ * with `[dev:<id>]` (see {@link emitStderr}) is what lets the per-device log
327
+ * UI attribute the forked worker's output to its camera. `null` only for the
328
+ * brief pre-`start` window (e.g. a malformed first message).
329
+ */
330
+ deviceId = null;
321
331
  sessionFormat = "rgb";
322
332
  minIntervalMs = 0;
323
333
  /**
@@ -390,16 +400,17 @@ var DecodeWorkerChild = class {
390
400
  const deliveredDelta = this.framesDelivered - this.lastDeliveredSnapshot;
391
401
  const deliveredFps = Math.round(deliveredDelta / windowMs * 1e3 * 10) / 10;
392
402
  const skipped = this.framesSkipped + this.frames.droppedCount;
393
- process.stderr.write(`session-decode metrics {framesDecoded:${this.framesDecoded}, framesSkipped:${skipped}, deliveredFps:${deliveredFps}}${final ? " (final)" : ""}\n`);
403
+ this.emitStderr(`session-decode metrics {framesDecoded:${this.framesDecoded}, framesSkipped:${skipped}, deliveredFps:${deliveredFps}}${final ? " (final)" : ""}\n`);
394
404
  this.lastMetricsAt = now;
395
405
  this.lastDeliveredSnapshot = this.framesDelivered;
396
406
  }
397
407
  handleStart(source, opts) {
398
408
  if (this.started) {
399
- process.stderr.write("decode-worker-child: duplicate start ignored\n");
409
+ this.emitStderr("decode-worker-child: duplicate start ignored\n");
400
410
  return;
401
411
  }
402
412
  this.started = true;
413
+ this.deviceId = source.deviceId;
403
414
  this.sessionFormat = opts.format ?? "rgb";
404
415
  this.minIntervalMs = opts.fps && opts.fps > 0 ? 1e3 / opts.fps : 0;
405
416
  this.lastMetricsAt = Date.now();
@@ -456,7 +467,7 @@ var DecodeWorkerChild = class {
456
467
  await this.dialAndDecode(nav, C, url);
457
468
  } catch (err) {
458
469
  if (this.stopped) break;
459
- process.stderr.write(`decode-worker-child: dial ended — re-dial scheduled: ${errMessage(err)}\n`);
470
+ this.emitStderr(`decode-worker-child: dial ended — re-dial scheduled: ${errMessage(err)}\n`);
460
471
  } finally {
461
472
  this.closeInput();
462
473
  }
@@ -549,7 +560,7 @@ var DecodeWorkerChild = class {
549
560
  return;
550
561
  }
551
562
  this.hwFilterDecision = "hardware";
552
- process.stderr.write(`decode-worker-child: GPU crop+scale path active (${this.gpuScaleFilter})\n`);
563
+ this.emitStderr(`decode-worker-child: GPU crop+scale path active (${this.gpuScaleFilter})\n`);
553
564
  }
554
565
  this.publishFrame(frame);
555
566
  }
@@ -587,7 +598,7 @@ var DecodeWorkerChild = class {
587
598
  for (const out of outputs) out.free();
588
599
  return ok;
589
600
  } catch (err) {
590
- process.stderr.write(`decode-worker-child: GPU filter probe failed — using software decode: ${errMessage(err)}\n`);
601
+ this.emitStderr(`decode-worker-child: GPU filter probe failed — using software decode: ${errMessage(err)}\n`);
591
602
  return false;
592
603
  } finally {
593
604
  filter?.close();
@@ -764,7 +775,7 @@ var DecodeWorkerChild = class {
764
775
  if (deviceType === null) continue;
765
776
  const hw = nav.HardwareContext.create(deviceType);
766
777
  if (!hw) {
767
- process.stderr.write(`decode-worker-child: hwaccel candidate '${backend}' failed — trying next\n`);
778
+ this.emitStderr(`decode-worker-child: hwaccel candidate '${backend}' failed — trying next\n`);
768
779
  continue;
769
780
  }
770
781
  this.hwContext = hw;
@@ -772,7 +783,7 @@ var DecodeWorkerChild = class {
772
783
  this.hwFilterDecision = this.gpuScaleFilter !== null ? "undecided" : "software";
773
784
  return;
774
785
  }
775
- process.stderr.write("decode-worker-child: no hwaccel backend available — using software decode\n");
786
+ this.emitStderr("decode-worker-child: no hwaccel backend available — using software decode\n");
776
787
  }
777
788
  /** Interruptible re-dial backoff — `teardown` clears the pending timer. */
778
789
  sleep(ms) {
@@ -803,8 +814,19 @@ var DecodeWorkerChild = class {
803
814
  send(reply) {
804
815
  process.send?.(reply);
805
816
  }
817
+ /**
818
+ * Write one diagnostic line to the (inherited) stderr, prefixed with the
819
+ * device tag so the per-device log UI can attribute the forked worker's
820
+ * output. Public so the module-level process handlers — which only hold the
821
+ * `worker` instance — emit device-tagged lines too. Callers pass the line
822
+ * INCLUDING its trailing newline (unchanged from the prior direct writes).
823
+ */
824
+ emitStderr(line) {
825
+ const tag = this.deviceId === null ? "[dev:?]" : `[dev:${this.deviceId}]`;
826
+ process.stderr.write(`${tag} ${line}`);
827
+ }
806
828
  sendError(message, frameId) {
807
- process.stderr.write(`${message}\n`);
829
+ this.emitStderr(`${message}\n`);
808
830
  this.send(frameId === void 0 ? {
809
831
  kind: "error",
810
832
  message
@@ -824,12 +846,12 @@ process.on("disconnect", () => {
824
846
  process.exit(0);
825
847
  });
826
848
  process.on("uncaughtException", (err) => {
827
- process.stderr.write(`decode-worker-child: uncaught exception — ${errMessage(err)}\n`);
849
+ worker.emitStderr(`decode-worker-child: uncaught exception — ${errMessage(err)}\n`);
828
850
  worker.teardown();
829
851
  process.exit(1);
830
852
  });
831
853
  process.on("unhandledRejection", (reason) => {
832
- process.stderr.write(`decode-worker-child: unhandled rejection — ${errMessage(reason)}\n`);
854
+ worker.emitStderr(`decode-worker-child: unhandled rejection — ${errMessage(reason)}\n`);
833
855
  });
834
856
  //#endregion
835
857
  exports.DecodeWorkerChild = DecodeWorkerChild;
@@ -317,6 +317,16 @@ var DecodeWorkerChild = class {
317
317
  abortController = null;
318
318
  started = false;
319
319
  stopped = false;
320
+ /**
321
+ * The numeric device id this worker decodes for — learned from the `start`
322
+ * message's {@link VideoFrameSource}. The child's stderr is INHERITED by the
323
+ * pipeline-runner (silent:false fork), so these lines land in the runner's
324
+ * raw stderr WITHOUT passing through a scoped logger; prefixing every line
325
+ * with `[dev:<id>]` (see {@link emitStderr}) is what lets the per-device log
326
+ * UI attribute the forked worker's output to its camera. `null` only for the
327
+ * brief pre-`start` window (e.g. a malformed first message).
328
+ */
329
+ deviceId = null;
320
330
  sessionFormat = "rgb";
321
331
  minIntervalMs = 0;
322
332
  /**
@@ -389,16 +399,17 @@ var DecodeWorkerChild = class {
389
399
  const deliveredDelta = this.framesDelivered - this.lastDeliveredSnapshot;
390
400
  const deliveredFps = Math.round(deliveredDelta / windowMs * 1e3 * 10) / 10;
391
401
  const skipped = this.framesSkipped + this.frames.droppedCount;
392
- process.stderr.write(`session-decode metrics {framesDecoded:${this.framesDecoded}, framesSkipped:${skipped}, deliveredFps:${deliveredFps}}${final ? " (final)" : ""}\n`);
402
+ this.emitStderr(`session-decode metrics {framesDecoded:${this.framesDecoded}, framesSkipped:${skipped}, deliveredFps:${deliveredFps}}${final ? " (final)" : ""}\n`);
393
403
  this.lastMetricsAt = now;
394
404
  this.lastDeliveredSnapshot = this.framesDelivered;
395
405
  }
396
406
  handleStart(source, opts) {
397
407
  if (this.started) {
398
- process.stderr.write("decode-worker-child: duplicate start ignored\n");
408
+ this.emitStderr("decode-worker-child: duplicate start ignored\n");
399
409
  return;
400
410
  }
401
411
  this.started = true;
412
+ this.deviceId = source.deviceId;
402
413
  this.sessionFormat = opts.format ?? "rgb";
403
414
  this.minIntervalMs = opts.fps && opts.fps > 0 ? 1e3 / opts.fps : 0;
404
415
  this.lastMetricsAt = Date.now();
@@ -455,7 +466,7 @@ var DecodeWorkerChild = class {
455
466
  await this.dialAndDecode(nav, C, url);
456
467
  } catch (err) {
457
468
  if (this.stopped) break;
458
- process.stderr.write(`decode-worker-child: dial ended — re-dial scheduled: ${errMessage(err)}\n`);
469
+ this.emitStderr(`decode-worker-child: dial ended — re-dial scheduled: ${errMessage(err)}\n`);
459
470
  } finally {
460
471
  this.closeInput();
461
472
  }
@@ -548,7 +559,7 @@ var DecodeWorkerChild = class {
548
559
  return;
549
560
  }
550
561
  this.hwFilterDecision = "hardware";
551
- process.stderr.write(`decode-worker-child: GPU crop+scale path active (${this.gpuScaleFilter})\n`);
562
+ this.emitStderr(`decode-worker-child: GPU crop+scale path active (${this.gpuScaleFilter})\n`);
552
563
  }
553
564
  this.publishFrame(frame);
554
565
  }
@@ -586,7 +597,7 @@ var DecodeWorkerChild = class {
586
597
  for (const out of outputs) out.free();
587
598
  return ok;
588
599
  } catch (err) {
589
- process.stderr.write(`decode-worker-child: GPU filter probe failed — using software decode: ${errMessage(err)}\n`);
600
+ this.emitStderr(`decode-worker-child: GPU filter probe failed — using software decode: ${errMessage(err)}\n`);
590
601
  return false;
591
602
  } finally {
592
603
  filter?.close();
@@ -763,7 +774,7 @@ var DecodeWorkerChild = class {
763
774
  if (deviceType === null) continue;
764
775
  const hw = nav.HardwareContext.create(deviceType);
765
776
  if (!hw) {
766
- process.stderr.write(`decode-worker-child: hwaccel candidate '${backend}' failed — trying next\n`);
777
+ this.emitStderr(`decode-worker-child: hwaccel candidate '${backend}' failed — trying next\n`);
767
778
  continue;
768
779
  }
769
780
  this.hwContext = hw;
@@ -771,7 +782,7 @@ var DecodeWorkerChild = class {
771
782
  this.hwFilterDecision = this.gpuScaleFilter !== null ? "undecided" : "software";
772
783
  return;
773
784
  }
774
- process.stderr.write("decode-worker-child: no hwaccel backend available — using software decode\n");
785
+ this.emitStderr("decode-worker-child: no hwaccel backend available — using software decode\n");
775
786
  }
776
787
  /** Interruptible re-dial backoff — `teardown` clears the pending timer. */
777
788
  sleep(ms) {
@@ -802,8 +813,19 @@ var DecodeWorkerChild = class {
802
813
  send(reply) {
803
814
  process.send?.(reply);
804
815
  }
816
+ /**
817
+ * Write one diagnostic line to the (inherited) stderr, prefixed with the
818
+ * device tag so the per-device log UI can attribute the forked worker's
819
+ * output. Public so the module-level process handlers — which only hold the
820
+ * `worker` instance — emit device-tagged lines too. Callers pass the line
821
+ * INCLUDING its trailing newline (unchanged from the prior direct writes).
822
+ */
823
+ emitStderr(line) {
824
+ const tag = this.deviceId === null ? "[dev:?]" : `[dev:${this.deviceId}]`;
825
+ process.stderr.write(`${tag} ${line}`);
826
+ }
805
827
  sendError(message, frameId) {
806
- process.stderr.write(`${message}\n`);
828
+ this.emitStderr(`${message}\n`);
807
829
  this.send(frameId === void 0 ? {
808
830
  kind: "error",
809
831
  message
@@ -823,12 +845,12 @@ process.on("disconnect", () => {
823
845
  process.exit(0);
824
846
  });
825
847
  process.on("uncaughtException", (err) => {
826
- process.stderr.write(`decode-worker-child: uncaught exception — ${errMessage(err)}\n`);
848
+ worker.emitStderr(`decode-worker-child: uncaught exception — ${errMessage(err)}\n`);
827
849
  worker.teardown();
828
850
  process.exit(1);
829
851
  });
830
852
  process.on("unhandledRejection", (reason) => {
831
- process.stderr.write(`decode-worker-child: unhandled rejection — ${errMessage(reason)}\n`);
853
+ worker.emitStderr(`decode-worker-child: unhandled rejection — ${errMessage(reason)}\n`);
832
854
  });
833
855
  //#endregion
834
856
  export { DecodeWorkerChild };
@@ -11875,10 +11875,13 @@ var TranscodePipelineManager = class {
11875
11875
  const sourceRes = sourceStream.resolution;
11876
11876
  const resMatchesTarget = input.targetResolution === void 0 || sourceRes !== void 0 && sourceRes.width === input.targetResolution.width && sourceRes.height === input.targetResolution.height;
11877
11877
  if (input.video === "copy" || sourceCodec !== null && videoTargetToCodec(input.video) === sourceCodec && wantedAudio === "copy" && outputArgs.length === 0 && resMatchesTarget) {
11878
- if (sourceCodec === null) this.logger.warn("copy-passthrough requested but source codec is unknown — reporting H264", { meta: {
11879
- deviceId: input.deviceId,
11880
- camStreamId: sourceStream.camStreamId
11881
- } });
11878
+ if (sourceCodec === null) this.logger.warn("copy-passthrough requested but source codec is unknown — reporting H264", {
11879
+ tags: { deviceId: input.deviceId },
11880
+ meta: {
11881
+ deviceId: input.deviceId,
11882
+ camStreamId: sourceStream.camStreamId
11883
+ }
11884
+ });
11882
11885
  const passVideoCodec = sourceCodec ?? "H264";
11883
11886
  const url = this.resolveSourceUrl(input.deviceId, sourceStream.camStreamId);
11884
11887
  const key = pipelineKeyFor(input.deviceId, sourceStream.camStreamId, "copy", wantedAudio, outResolution, outputArgs, false);
@@ -11967,13 +11970,16 @@ var TranscodePipelineManager = class {
11967
11970
  releaseTimer: null
11968
11971
  };
11969
11972
  this.entries.set(opts.key, entry);
11970
- this.logger.info("Transcode pipeline started", { meta: {
11971
- key: opts.key,
11972
- encoder,
11973
- decodeHwAccel,
11974
- sourceUrl,
11975
- url
11976
- } });
11973
+ this.logger.info("Transcode pipeline started", {
11974
+ tags: { deviceId: opts.deviceId },
11975
+ meta: {
11976
+ key: opts.key,
11977
+ encoder,
11978
+ decodeHwAccel,
11979
+ sourceUrl,
11980
+ url
11981
+ }
11982
+ });
11977
11983
  return source;
11978
11984
  }
11979
11985
  firstPublished(deviceId) {
@@ -14506,10 +14512,13 @@ var StreamBrokerManager = class {
14506
14512
  const key = `${cam.deviceId}:${cam.camStreamId}`;
14507
14513
  if (!this.sourceParserFellBackWarned.has(key)) {
14508
14514
  this.sourceParserFellBackWarned.add(key);
14509
- this.logger.warn("source parser native-udp requested but not yet implemented — falling back to native-tcp", { meta: {
14510
- deviceId: cam.deviceId,
14511
- camStreamId: cam.camStreamId
14512
- } });
14515
+ this.logger.warn("source parser native-udp requested but not yet implemented — falling back to native-tcp", {
14516
+ tags: { deviceId: cam.deviceId },
14517
+ meta: {
14518
+ deviceId: cam.deviceId,
14519
+ camStreamId: cam.camStreamId
14520
+ }
14521
+ });
14513
14522
  }
14514
14523
  }
14515
14524
  if (resolved.engine !== "ffmpeg") return {};
@@ -14725,7 +14734,7 @@ var StreamBrokerManager = class {
14725
14734
  if (!broker) return;
14726
14735
  if (this.derivedFeeders.has(brokerId)) return;
14727
14736
  const controller = new DerivedFeederController({
14728
- logger: this.logger.child(`derived-feeder:${camStreamId}`),
14737
+ logger: this.logger.child(`derived-feeder:${camStreamId}`).withTags({ deviceId }),
14729
14738
  spawn: (onTeardown) => this.spawnDerivedFeeder(deviceId, camStreamId, source, encodeProfile, broker, onTeardown)
14730
14739
  });
14731
14740
  const unsubscribe = broker.onDemandChange((active) => controller.onDemand(active));
@@ -14776,21 +14785,27 @@ var StreamBrokerManager = class {
14776
14785
  const feeder = new DerivedStreamFeeder({
14777
14786
  ffmpegPath: this.ffmpegConfig.binaryPath,
14778
14787
  args,
14779
- logger: this.logger.child(`derived-ffmpeg:${camStreamId}`)
14788
+ logger: this.logger.child(`derived-ffmpeg:${camStreamId}`).withTags({ deviceId })
14780
14789
  }, {
14781
14790
  onEncodedPacket: (packet) => broker.pushEncodedPacket(packet),
14782
14791
  onAudioInfo: (info) => broker.pushAudioInfo(info),
14783
14792
  onPlaying: () => {
14784
- this.logger.info("derived feeder streaming", { meta: {
14785
- camStreamId,
14786
- loopbackUrl
14787
- } });
14793
+ this.logger.info("derived feeder streaming", {
14794
+ tags: { deviceId },
14795
+ meta: {
14796
+ camStreamId,
14797
+ loopbackUrl
14798
+ }
14799
+ });
14788
14800
  },
14789
14801
  onError: (error) => {
14790
- this.logger.warn("derived feeder error", { meta: {
14791
- camStreamId,
14792
- error: error.message
14793
- } });
14802
+ this.logger.warn("derived feeder error", {
14803
+ tags: { deviceId },
14804
+ meta: {
14805
+ camStreamId,
14806
+ error: error.message
14807
+ }
14808
+ });
14794
14809
  },
14795
14810
  onTeardown
14796
14811
  });
@@ -16937,10 +16952,13 @@ var BrokerWebrtcServer = class {
16937
16952
  const entry = this.sessions.get(sessionId);
16938
16953
  if (!entry) return;
16939
16954
  await entry.session.addIceCandidate(candidate).catch((err) => {
16940
- this.logger.warn("addIceCandidate threw", { meta: {
16941
- sessionId,
16942
- error: require_dist.errMsg(err)
16943
- } });
16955
+ this.logger.warn("addIceCandidate threw", {
16956
+ tags: { deviceId: deviceIdFromBrokerId(entry.brokerId) },
16957
+ meta: {
16958
+ sessionId,
16959
+ error: require_dist.errMsg(err)
16960
+ }
16961
+ });
16944
16962
  });
16945
16963
  }
16946
16964
  /** Trickle ICE — the server's gathered candidates for a session (poll). */
@@ -16957,10 +16975,13 @@ var BrokerWebrtcServer = class {
16957
16975
  if (!entry) return;
16958
16976
  this.cleanupSession(sessionId);
16959
16977
  await entry.session.close().catch(() => {});
16960
- this.logger.info("WebRTC session closed", { meta: {
16961
- sessionId,
16962
- deviceId: deviceIdFromBrokerId(entry.brokerId)
16963
- } });
16978
+ this.logger.info("WebRTC session closed", {
16979
+ tags: { deviceId: deviceIdFromBrokerId(entry.brokerId) },
16980
+ meta: {
16981
+ sessionId,
16982
+ deviceId: deviceIdFromBrokerId(entry.brokerId)
16983
+ }
16984
+ });
16964
16985
  }
16965
16986
  async stop() {
16966
16987
  if (this.stopped) return;
@@ -17061,13 +17082,16 @@ var BrokerWebrtcServer = class {
17061
17082
  target: { kind: "adaptive" },
17062
17083
  epoch
17063
17084
  };
17064
- this.logger.info("adaptive: scheduling renegotiation", { meta: {
17065
- sessionId,
17066
- deviceId,
17067
- tier,
17068
- forceTranscodeDown,
17069
- epoch
17070
- } });
17085
+ this.logger.info("adaptive: scheduling renegotiation", {
17086
+ tags: { deviceId },
17087
+ meta: {
17088
+ sessionId,
17089
+ deviceId,
17090
+ tier,
17091
+ forceTranscodeDown,
17092
+ epoch
17093
+ }
17094
+ });
17071
17095
  }
17072
17096
  cleanupSession(sessionId) {
17073
17097
  const entry = this.sessions.get(sessionId);
@@ -17301,10 +17325,13 @@ var CameraStreamsProvider = class {
17301
17325
  async pickStream(input) {
17302
17326
  const streams = await this.manager.getCameraStreamsForDevice(input.deviceId);
17303
17327
  if (streams.length === 0) {
17304
- this.manager.getLogger?.()?.info("camera-streams: pickStream — no streams for device", { meta: {
17305
- deviceId: input.deviceId,
17306
- requirements: input.requirements
17307
- } });
17328
+ this.manager.getLogger?.()?.info("camera-streams: pickStream — no streams for device", {
17329
+ tags: { deviceId: input.deviceId },
17330
+ meta: {
17331
+ deviceId: input.deviceId,
17332
+ requirements: input.requirements
17333
+ }
17334
+ });
17308
17335
  return null;
17309
17336
  }
17310
17337
  const requirements = input.requirements;
@@ -17321,15 +17348,18 @@ var CameraStreamsProvider = class {
17321
17348
  return true;
17322
17349
  });
17323
17350
  if (candidates.length === 0) {
17324
- this.manager.getLogger?.()?.info("camera-streams: pickStream — no matching candidates", { meta: {
17325
- deviceId: input.deviceId,
17326
- requirements: input.requirements,
17327
- streams: streams.map((s) => ({
17328
- camStreamId: s.camStreamId,
17329
- codec: s.codec,
17330
- resolution: s.resolution
17331
- }))
17332
- } });
17351
+ this.manager.getLogger?.()?.info("camera-streams: pickStream — no matching candidates", {
17352
+ tags: { deviceId: input.deviceId },
17353
+ meta: {
17354
+ deviceId: input.deviceId,
17355
+ requirements: input.requirements,
17356
+ streams: streams.map((s) => ({
17357
+ camStreamId: s.camStreamId,
17358
+ codec: s.codec,
17359
+ resolution: s.resolution
17360
+ }))
17361
+ }
17362
+ });
17333
17363
  return null;
17334
17364
  }
17335
17365
  const requireSibling = requirements.requireSiblingCodec ?? [];
@@ -17338,14 +17368,17 @@ var CameraStreamsProvider = class {
17338
17368
  if (s.camStreamId.startsWith("derived:")) return false;
17339
17369
  return codecMatches(s.codec, requireSibling);
17340
17370
  })) {
17341
- this.manager.getLogger?.()?.info("camera-streams: pickStream — no sibling codec, skipping bypass", { meta: {
17342
- deviceId: input.deviceId,
17343
- requireSibling,
17344
- streams: streams.map((s) => ({
17345
- camStreamId: s.camStreamId,
17346
- codec: s.codec
17347
- }))
17348
- } });
17371
+ this.manager.getLogger?.()?.info("camera-streams: pickStream — no sibling codec, skipping bypass", {
17372
+ tags: { deviceId: input.deviceId },
17373
+ meta: {
17374
+ deviceId: input.deviceId,
17375
+ requireSibling,
17376
+ streams: streams.map((s) => ({
17377
+ camStreamId: s.camStreamId,
17378
+ codec: s.codec
17379
+ }))
17380
+ }
17381
+ });
17349
17382
  return null;
17350
17383
  }
17351
17384
  }
@@ -11871,10 +11871,13 @@ var TranscodePipelineManager = class {
11871
11871
  const sourceRes = sourceStream.resolution;
11872
11872
  const resMatchesTarget = input.targetResolution === void 0 || sourceRes !== void 0 && sourceRes.width === input.targetResolution.width && sourceRes.height === input.targetResolution.height;
11873
11873
  if (input.video === "copy" || sourceCodec !== null && videoTargetToCodec(input.video) === sourceCodec && wantedAudio === "copy" && outputArgs.length === 0 && resMatchesTarget) {
11874
- if (sourceCodec === null) this.logger.warn("copy-passthrough requested but source codec is unknown — reporting H264", { meta: {
11875
- deviceId: input.deviceId,
11876
- camStreamId: sourceStream.camStreamId
11877
- } });
11874
+ if (sourceCodec === null) this.logger.warn("copy-passthrough requested but source codec is unknown — reporting H264", {
11875
+ tags: { deviceId: input.deviceId },
11876
+ meta: {
11877
+ deviceId: input.deviceId,
11878
+ camStreamId: sourceStream.camStreamId
11879
+ }
11880
+ });
11878
11881
  const passVideoCodec = sourceCodec ?? "H264";
11879
11882
  const url = this.resolveSourceUrl(input.deviceId, sourceStream.camStreamId);
11880
11883
  const key = pipelineKeyFor(input.deviceId, sourceStream.camStreamId, "copy", wantedAudio, outResolution, outputArgs, false);
@@ -11963,13 +11966,16 @@ var TranscodePipelineManager = class {
11963
11966
  releaseTimer: null
11964
11967
  };
11965
11968
  this.entries.set(opts.key, entry);
11966
- this.logger.info("Transcode pipeline started", { meta: {
11967
- key: opts.key,
11968
- encoder,
11969
- decodeHwAccel,
11970
- sourceUrl,
11971
- url
11972
- } });
11969
+ this.logger.info("Transcode pipeline started", {
11970
+ tags: { deviceId: opts.deviceId },
11971
+ meta: {
11972
+ key: opts.key,
11973
+ encoder,
11974
+ decodeHwAccel,
11975
+ sourceUrl,
11976
+ url
11977
+ }
11978
+ });
11973
11979
  return source;
11974
11980
  }
11975
11981
  firstPublished(deviceId) {
@@ -14502,10 +14508,13 @@ var StreamBrokerManager = class {
14502
14508
  const key = `${cam.deviceId}:${cam.camStreamId}`;
14503
14509
  if (!this.sourceParserFellBackWarned.has(key)) {
14504
14510
  this.sourceParserFellBackWarned.add(key);
14505
- this.logger.warn("source parser native-udp requested but not yet implemented — falling back to native-tcp", { meta: {
14506
- deviceId: cam.deviceId,
14507
- camStreamId: cam.camStreamId
14508
- } });
14511
+ this.logger.warn("source parser native-udp requested but not yet implemented — falling back to native-tcp", {
14512
+ tags: { deviceId: cam.deviceId },
14513
+ meta: {
14514
+ deviceId: cam.deviceId,
14515
+ camStreamId: cam.camStreamId
14516
+ }
14517
+ });
14509
14518
  }
14510
14519
  }
14511
14520
  if (resolved.engine !== "ffmpeg") return {};
@@ -14721,7 +14730,7 @@ var StreamBrokerManager = class {
14721
14730
  if (!broker) return;
14722
14731
  if (this.derivedFeeders.has(brokerId)) return;
14723
14732
  const controller = new DerivedFeederController({
14724
- logger: this.logger.child(`derived-feeder:${camStreamId}`),
14733
+ logger: this.logger.child(`derived-feeder:${camStreamId}`).withTags({ deviceId }),
14725
14734
  spawn: (onTeardown) => this.spawnDerivedFeeder(deviceId, camStreamId, source, encodeProfile, broker, onTeardown)
14726
14735
  });
14727
14736
  const unsubscribe = broker.onDemandChange((active) => controller.onDemand(active));
@@ -14772,21 +14781,27 @@ var StreamBrokerManager = class {
14772
14781
  const feeder = new DerivedStreamFeeder({
14773
14782
  ffmpegPath: this.ffmpegConfig.binaryPath,
14774
14783
  args,
14775
- logger: this.logger.child(`derived-ffmpeg:${camStreamId}`)
14784
+ logger: this.logger.child(`derived-ffmpeg:${camStreamId}`).withTags({ deviceId })
14776
14785
  }, {
14777
14786
  onEncodedPacket: (packet) => broker.pushEncodedPacket(packet),
14778
14787
  onAudioInfo: (info) => broker.pushAudioInfo(info),
14779
14788
  onPlaying: () => {
14780
- this.logger.info("derived feeder streaming", { meta: {
14781
- camStreamId,
14782
- loopbackUrl
14783
- } });
14789
+ this.logger.info("derived feeder streaming", {
14790
+ tags: { deviceId },
14791
+ meta: {
14792
+ camStreamId,
14793
+ loopbackUrl
14794
+ }
14795
+ });
14784
14796
  },
14785
14797
  onError: (error) => {
14786
- this.logger.warn("derived feeder error", { meta: {
14787
- camStreamId,
14788
- error: error.message
14789
- } });
14798
+ this.logger.warn("derived feeder error", {
14799
+ tags: { deviceId },
14800
+ meta: {
14801
+ camStreamId,
14802
+ error: error.message
14803
+ }
14804
+ });
14790
14805
  },
14791
14806
  onTeardown
14792
14807
  });
@@ -16933,10 +16948,13 @@ var BrokerWebrtcServer = class {
16933
16948
  const entry = this.sessions.get(sessionId);
16934
16949
  if (!entry) return;
16935
16950
  await entry.session.addIceCandidate(candidate).catch((err) => {
16936
- this.logger.warn("addIceCandidate threw", { meta: {
16937
- sessionId,
16938
- error: errMsg(err)
16939
- } });
16951
+ this.logger.warn("addIceCandidate threw", {
16952
+ tags: { deviceId: deviceIdFromBrokerId(entry.brokerId) },
16953
+ meta: {
16954
+ sessionId,
16955
+ error: errMsg(err)
16956
+ }
16957
+ });
16940
16958
  });
16941
16959
  }
16942
16960
  /** Trickle ICE — the server's gathered candidates for a session (poll). */
@@ -16953,10 +16971,13 @@ var BrokerWebrtcServer = class {
16953
16971
  if (!entry) return;
16954
16972
  this.cleanupSession(sessionId);
16955
16973
  await entry.session.close().catch(() => {});
16956
- this.logger.info("WebRTC session closed", { meta: {
16957
- sessionId,
16958
- deviceId: deviceIdFromBrokerId(entry.brokerId)
16959
- } });
16974
+ this.logger.info("WebRTC session closed", {
16975
+ tags: { deviceId: deviceIdFromBrokerId(entry.brokerId) },
16976
+ meta: {
16977
+ sessionId,
16978
+ deviceId: deviceIdFromBrokerId(entry.brokerId)
16979
+ }
16980
+ });
16960
16981
  }
16961
16982
  async stop() {
16962
16983
  if (this.stopped) return;
@@ -17057,13 +17078,16 @@ var BrokerWebrtcServer = class {
17057
17078
  target: { kind: "adaptive" },
17058
17079
  epoch
17059
17080
  };
17060
- this.logger.info("adaptive: scheduling renegotiation", { meta: {
17061
- sessionId,
17062
- deviceId,
17063
- tier,
17064
- forceTranscodeDown,
17065
- epoch
17066
- } });
17081
+ this.logger.info("adaptive: scheduling renegotiation", {
17082
+ tags: { deviceId },
17083
+ meta: {
17084
+ sessionId,
17085
+ deviceId,
17086
+ tier,
17087
+ forceTranscodeDown,
17088
+ epoch
17089
+ }
17090
+ });
17067
17091
  }
17068
17092
  cleanupSession(sessionId) {
17069
17093
  const entry = this.sessions.get(sessionId);
@@ -17297,10 +17321,13 @@ var CameraStreamsProvider = class {
17297
17321
  async pickStream(input) {
17298
17322
  const streams = await this.manager.getCameraStreamsForDevice(input.deviceId);
17299
17323
  if (streams.length === 0) {
17300
- this.manager.getLogger?.()?.info("camera-streams: pickStream — no streams for device", { meta: {
17301
- deviceId: input.deviceId,
17302
- requirements: input.requirements
17303
- } });
17324
+ this.manager.getLogger?.()?.info("camera-streams: pickStream — no streams for device", {
17325
+ tags: { deviceId: input.deviceId },
17326
+ meta: {
17327
+ deviceId: input.deviceId,
17328
+ requirements: input.requirements
17329
+ }
17330
+ });
17304
17331
  return null;
17305
17332
  }
17306
17333
  const requirements = input.requirements;
@@ -17317,15 +17344,18 @@ var CameraStreamsProvider = class {
17317
17344
  return true;
17318
17345
  });
17319
17346
  if (candidates.length === 0) {
17320
- this.manager.getLogger?.()?.info("camera-streams: pickStream — no matching candidates", { meta: {
17321
- deviceId: input.deviceId,
17322
- requirements: input.requirements,
17323
- streams: streams.map((s) => ({
17324
- camStreamId: s.camStreamId,
17325
- codec: s.codec,
17326
- resolution: s.resolution
17327
- }))
17328
- } });
17347
+ this.manager.getLogger?.()?.info("camera-streams: pickStream — no matching candidates", {
17348
+ tags: { deviceId: input.deviceId },
17349
+ meta: {
17350
+ deviceId: input.deviceId,
17351
+ requirements: input.requirements,
17352
+ streams: streams.map((s) => ({
17353
+ camStreamId: s.camStreamId,
17354
+ codec: s.codec,
17355
+ resolution: s.resolution
17356
+ }))
17357
+ }
17358
+ });
17329
17359
  return null;
17330
17360
  }
17331
17361
  const requireSibling = requirements.requireSiblingCodec ?? [];
@@ -17334,14 +17364,17 @@ var CameraStreamsProvider = class {
17334
17364
  if (s.camStreamId.startsWith("derived:")) return false;
17335
17365
  return codecMatches(s.codec, requireSibling);
17336
17366
  })) {
17337
- this.manager.getLogger?.()?.info("camera-streams: pickStream — no sibling codec, skipping bypass", { meta: {
17338
- deviceId: input.deviceId,
17339
- requireSibling,
17340
- streams: streams.map((s) => ({
17341
- camStreamId: s.camStreamId,
17342
- codec: s.codec
17343
- }))
17344
- } });
17367
+ this.manager.getLogger?.()?.info("camera-streams: pickStream — no sibling codec, skipping bypass", {
17368
+ tags: { deviceId: input.deviceId },
17369
+ meta: {
17370
+ deviceId: input.deviceId,
17371
+ requireSibling,
17372
+ streams: streams.map((s) => ({
17373
+ camStreamId: s.camStreamId,
17374
+ codec: s.codec
17375
+ }))
17376
+ }
17377
+ });
17345
17378
  return null;
17346
17379
  }
17347
17380
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-pipeline",
3
- "version": "1.1.42",
3
+ "version": "1.1.43",
4
4
  "description": "CamStack Pipeline bundle — runner, detection, motion, audio + stream broker. Multi-entry npm package shipping pipeline addons under a single bundle.",
5
5
  "keywords": [
6
6
  "camstack",