@camstack/addon-pipeline 1.2.192 → 1.2.193

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.
Files changed (35) hide show
  1. package/dist/audio-analyzer/index.js +2 -2
  2. package/dist/audio-analyzer/index.mjs +2 -2
  3. package/dist/detection-pipeline/index.js +7 -7
  4. package/dist/detection-pipeline/index.mjs +5 -5
  5. package/dist/{dist-CXO_Fmx6.js → dist-HG5geL9t.js} +129 -1
  6. package/dist/{dist-B8J7wrtY.mjs → dist-mYDK58Jp.mjs} +118 -2
  7. package/dist/{lazy-sharp-o-aNNXuz.js → lazy-sharp-DmAwZ0s9.js} +1 -1
  8. package/dist/{local-frame-registry-BDeDpYQk.mjs → local-frame-registry-av9ObDG0.mjs} +1 -1
  9. package/dist/{local-frame-registry-P7tSfvaY.js → local-frame-registry-x3m6SNqf.js} +1 -1
  10. package/dist/motion-wasm/index.js +2 -2
  11. package/dist/motion-wasm/index.mjs +1 -1
  12. package/dist/{node-DF98pVP7.js → node--my8JTOW.js} +1 -1
  13. package/dist/{node-BSbB0or0.mjs → node-xRsaPwBa.mjs} +1 -1
  14. package/dist/pipeline-runner/index.js +255 -221
  15. package/dist/pipeline-runner/index.mjs +253 -219
  16. package/dist/{process-memory-BZTgJyE8.mjs → process-memory-BDHR3lxe.mjs} +1 -1
  17. package/dist/{process-memory-BVMk3gfY.js → process-memory-CoCSce63.js} +1 -1
  18. package/dist/recorder/index.js +319 -8
  19. package/dist/recorder/index.mjs +319 -8
  20. package/dist/{segment-demux-js-CLaSHw0n.js → segment-demux-js-CBynn9Gh.js} +1 -1
  21. package/dist/{segment-demux-js-0L1EF4Fg.mjs → segment-demux-js-CXvgKfsn.mjs} +1 -1
  22. package/dist/session-decode/decode-worker-child.js +2 -2
  23. package/dist/session-decode/decode-worker-child.mjs +1 -1
  24. package/dist/stream-broker/_stub.js +1 -1
  25. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-BmNfrv_U.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-CUjbLOm9.mjs} +3 -3
  26. package/dist/stream-broker/{_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-D8AK-_F6.mjs → _virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-B_NVJXAy.mjs} +1 -1
  27. package/dist/stream-broker/demux-worker-child.js +1 -1
  28. package/dist/stream-broker/demux-worker-child.mjs +1 -1
  29. package/dist/stream-broker/{hostInit-DQLtjntf.mjs → hostInit-DnBCyuSA.mjs} +3 -3
  30. package/dist/stream-broker/index.js +93 -43
  31. package/dist/stream-broker/index.mjs +93 -43
  32. package/dist/stream-broker/remoteEntry.js +1 -1
  33. package/dist/{worker-protocol-WiXU2VuW.mjs → worker-protocol-C0R1DDC0.mjs} +1 -1
  34. package/dist/{worker-protocol-BJzhw3t0.js → worker-protocol-DCsi4YS1.js} +1 -1
  35. package/package.json +1 -1
@@ -1,11 +1,13 @@
1
1
  import { r as __toESM } from "../chunk-DnnnRqeS.mjs";
2
- import { $t as record, At as BOOT_RECOVERY_BACKOFF_MS, Bt as nodePin, C as RATE_CONTROL_RELAXED, Ct as webrtcSessionCapability, D as RingBuffer, Dt as buildFfmpegArgs$1, F as createHwAccelCache, Ft as createEvent, G as egressTranscodeSharingKey, Gt as _enum, Ht as parseProfileBrokerId, I as createLogChannelsProvider, Jt as discriminatedUnion, K as egressTransportFromRequest, Kt as array, Lt as isEvent, Mt as CAM_PROFILE_ORDER, N as batteryCapability, Nt as DeviceFeature, Ot as invocationFromEncodeProfile, P as cameraStreamsCapability, Pt as DeviceType, Qt as object, R as declareLogChannel, Rt as makeProfileBrokerId, Tt as AUDIO_PRESETS, V as deriveBatteryPresence, Xt as literal, Zt as number, en as string, et as loadContributionCapability, gt as resolveEgressDecodeHwAccel, h as EncodeProfileSchema, i as BatteryStatusSchema, jt as BaseAddon, k as addonWidgetsSourceCapability, kt as isSoftwareDecode, nn as EventCategory, qt as boolean, rt as maskUrlCredentials, tn as union, tt as logChannelsCapability, w as RATE_CONTROL_TIGHT, wt as errMsg, xt as streamBrokerCapability, zt as makeSourceBrokerId } from "../dist-B8J7wrtY.mjs";
3
- import { i as NO_COST_CLAIM, n as Fmp4FragmentChild, r as Fmp4FragmentPlane, t as ChildCostRegistry } from "../node-BSbB0or0.mjs";
2
+ import { $t as number, A as addonWidgetsSourceCapability, At as invocationFromEncodeProfile, Bt as makeProfileBrokerId, C as RATE_CONTROL_RELAXED, Ct as streamBrokerCapability, Dt as AUDIO_PRESETS, Et as errMsg, F as cameraStreamsCapability, Ft as DeviceFeature, H as deriveBatteryPresence, Ht as nodePin, I as createHwAccelCache, It as DeviceType, Jt as array, K as egressTranscodeSharingKey, L as createLogChannelsProvider, Lt as createEvent, Mt as BOOT_RECOVERY_BACKOFF_MS, Nt as BaseAddon, O as RingBuffer, P as batteryCapability, Pt as CAM_PROFILE_ORDER, Qt as literal, Tt as webrtcSessionCapability, Vt as makeSourceBrokerId, Wt as parseProfileBrokerId, Xt as discriminatedUnion, Yt as boolean, en as object, h as EncodeProfileSchema, i as BatteryStatusSchema, in as EventCategory, it as maskUrlCredentials, jt as isSoftwareDecode, kt as buildFfmpegArgs$1, nn as string, nt as logChannelsCapability, q as egressTransportFromRequest, qt as _enum, rn as union, tn as record, tt as loadContributionCapability, vt as resolveEgressDecodeHwAccel, w as RATE_CONTROL_TIGHT, z as declareLogChannel, zt as isEvent } from "../dist-mYDK58Jp.mjs";
3
+ import { i as NO_COST_CLAIM, n as Fmp4FragmentChild, r as Fmp4FragmentPlane, t as ChildCostRegistry } from "../node-xRsaPwBa.mjs";
4
4
  import { t as parseRestreamPath } from "../restream-intent-B4BXZra7.mjs";
5
5
  import { n as profileForStreamId } from "../remote-restream-BeHi78PZ.mjs";
6
6
  import { n as RowMapStore, t as retireRootKeys } from "../retire-root-keys-DMolfhsP.mjs";
7
- import { i as require_mp4box_all, n as demuxSegmentPreferJs, r as runFfmpegOnce, t as demuxSegmentFullJs } from "../segment-demux-js-0L1EF4Fg.mjs";
7
+ import { i as require_mp4box_all, n as demuxSegmentPreferJs, r as runFfmpegOnce, t as demuxSegmentFullJs } from "../segment-demux-js-CXvgKfsn.mjs";
8
8
  import { createRequire } from "node:module";
9
+ import * as os from "node:os";
10
+ import { networkInterfaces, tmpdir } from "node:os";
9
11
  import * as crypto$1 from "node:crypto";
10
12
  import crypto, { createHash, randomBytes, randomUUID } from "node:crypto";
11
13
  import * as fs from "node:fs";
@@ -15,13 +17,11 @@ import { join } from "node:path";
15
17
  import { spawn } from "node:child_process";
16
18
  import { readFile } from "node:fs/promises";
17
19
  import { fileURLToPath, pathToFileURL } from "node:url";
18
- import * as os from "node:os";
19
- import { networkInterfaces, tmpdir } from "node:os";
20
20
  import * as net$1 from "node:net";
21
21
  import net from "node:net";
22
22
  import { createSocket } from "node:dgram";
23
- import { Socket } from "net";
24
23
  import { once } from "events";
24
+ import { Socket } from "net";
25
25
  import { lookup } from "node:dns/promises";
26
26
  import { Worker } from "node:worker_threads";
27
27
  import { EventEmitter } from "node:events";
@@ -1723,6 +1723,65 @@ function fillEmptyProfileSlots(current, autoRanked) {
1723
1723
  }
1724
1724
  return next;
1725
1725
  }
1726
+ //#endregion
1727
+ //#region src/stream-broker/initial-assignment.ts
1728
+ function pixels(stream) {
1729
+ return stream.resolution ? stream.resolution.width * stream.resolution.height : -1;
1730
+ }
1731
+ /** Pixels descending, then publish order — the heuristic as it always was. */
1732
+ function rankByPixels(streams) {
1733
+ return [...streams].toSorted((a, b) => {
1734
+ const aPx = pixels(a);
1735
+ const bPx = pixels(b);
1736
+ if (aPx !== bPx) return bPx - aPx;
1737
+ return a.order - b.order;
1738
+ });
1739
+ }
1740
+ /**
1741
+ * The slots the un-hinted ranking fills, by how many streams are left: one
1742
+ * stream is a `mid`, two are `high`+`low`, three fill everything. Filtered to
1743
+ * the slots the hints did not take, in this priority order, so a camera with
1744
+ * one hinted `low` and one other stream gets `high` for the other — the pair
1745
+ * every two-stream camera already had.
1746
+ */
1747
+ var RANK_ORDER_BY_COUNT = {
1748
+ 1: ["mid"],
1749
+ 2: ["high", "low"],
1750
+ 3: [
1751
+ "high",
1752
+ "mid",
1753
+ "low"
1754
+ ]
1755
+ };
1756
+ /**
1757
+ * Streams marked `autoEligible: false` are skipped — they remain published
1758
+ * (visible + manually assignable via `assignProfile`) but never become the
1759
+ * default. If every stream is non-eligible the map stays empty: ranking
1760
+ * ineligible streams (a derived that beat the catalog to boot) parked a
1761
+ * transcode on `high` and left the natives around it (618, 2026-08-17).
1762
+ */
1763
+ function rankInitialAssignment(streams) {
1764
+ const eligible = streams.filter((s) => s.autoEligible);
1765
+ if (eligible.length === 0) return {};
1766
+ const hinted = {};
1767
+ const rest = [];
1768
+ for (const stream of [...eligible].toSorted((a, b) => a.order - b.order)) {
1769
+ const hint = stream.profileHint;
1770
+ if (hint !== void 0 && hinted[hint] === void 0) hinted[hint] = stream.camStreamId;
1771
+ else rest.push(stream);
1772
+ }
1773
+ const ranked = rankByPixels(rest).slice(0, 3);
1774
+ const freeSlots = (RANK_ORDER_BY_COUNT[Math.min(3, eligible.length)] ?? []).filter((slot) => hinted[slot] === void 0);
1775
+ const byRank = {};
1776
+ ranked.forEach((stream, index) => {
1777
+ const slot = freeSlots[index];
1778
+ if (slot !== void 0) byRank[slot] = stream.camStreamId;
1779
+ });
1780
+ return {
1781
+ ...hinted,
1782
+ ...byRank
1783
+ };
1784
+ }
1726
1785
  /**
1727
1786
  * Ceiling for a configured pre-roll.
1728
1787
  *
@@ -7444,16 +7503,28 @@ function aacSamplingIndexToHz(index) {
7444
7503
  return AAC_SAMPLE_RATES[index] ?? null;
7445
7504
  }
7446
7505
  //#endregion
7506
+ //#region src/stream-broker/rtmp/rtmp-url.ts
7507
+ var DEFAULT_RTMP_PORT = 1935;
7508
+ var RTMP_URL = /^rtmp:\/\/([^/:]+)(?::(\d+))?\/(.*)$/;
7509
+ function parseRtmpUrl(url) {
7510
+ const m = RTMP_URL.exec(url);
7511
+ if (!m) throw new Error(`not an rtmp:// url: ${url}`);
7512
+ const host = m[1] ?? "";
7513
+ const port = m[2] !== void 0 ? Number(m[2]) : DEFAULT_RTMP_PORT;
7514
+ const path = m[3] ?? "";
7515
+ const slash = path.lastIndexOf("/");
7516
+ if (slash < 0) throw new Error(`rtmp url has no playpath: ${url}`);
7517
+ const app = path.slice(0, slash);
7518
+ return {
7519
+ host,
7520
+ port,
7521
+ app,
7522
+ playPath: path.slice(slash + 1),
7523
+ tcUrl: `rtmp://${host}:${String(port)}/${app}`
7524
+ };
7525
+ }
7526
+ //#endregion
7447
7527
  //#region src/stream-broker/rtmp/rtmp-client.ts
7448
- /**
7449
- * RTMP client (TCP, handshake, AMF0 connect/createStream/play, chunk parser).
7450
- *
7451
- * RTMP client with the following adaptations from the original implementation:
7452
- * - `console` replaced with project `IScopedLogger`.
7453
- * - Inlined `readLength` helper (no external dependency).
7454
- * - Strict TS — AMF0 encoder accepts a tagged union instead of `any`.
7455
- * - Async-friendly `destroy()` for the broker's reconnect cycle.
7456
- */
7457
7528
  var StreamEndError = class extends Error {
7458
7529
  constructor(where) {
7459
7530
  super(`stream ended: ${where}`);
@@ -7492,7 +7563,6 @@ async function readLength(readable, length) {
7492
7563
  }
7493
7564
  var HANDSHAKE_SIZE = 1536;
7494
7565
  var RTMP_VERSION = 3;
7495
- var DEFAULT_RTMP_PORT = 1935;
7496
7566
  function encodeAmf0(value) {
7497
7567
  if (typeof value === "number") {
7498
7568
  const buf = Buffer.alloc(9);
@@ -7591,9 +7661,7 @@ var RtmpClient = class {
7591
7661
  const { messageTypeId } = (await this.readMessage()).chunkStream;
7592
7662
  if (messageTypeId !== 20) throw new Error(`Unexpected message type for createStream result: ${messageTypeId}`);
7593
7663
  this.logger?.debug("rtmp createStream _result received");
7594
- const parsedUrl = new URL(this.url);
7595
- const parts = parsedUrl.pathname.split("/");
7596
- const playPath = (parts.length > 2 ? parts.slice(2).join("/") : "") + parsedUrl.search;
7664
+ const { playPath } = parseRtmpUrl(this.url);
7597
7665
  const getStreamLengthData = encodeAmf0Command("getStreamLength", this.transactionId++, null, playPath);
7598
7666
  this.sendMessage(5, 0, 20, 0, getStreamLengthData);
7599
7667
  this.sendPlay(this.streamId, playPath);
@@ -7626,9 +7694,7 @@ var RtmpClient = class {
7626
7694
  } catch {}
7627
7695
  }
7628
7696
  async connect() {
7629
- const parsedUrl = new URL(this.url);
7630
- const host = parsedUrl.hostname;
7631
- const port = parseInt(parsedUrl.port || `${DEFAULT_RTMP_PORT}`, 10) || DEFAULT_RTMP_PORT;
7697
+ const { host, port } = parseRtmpUrl(this.url);
7632
7698
  this.logger?.debug("rtmp tcp connecting", { meta: {
7633
7699
  host,
7634
7700
  port
@@ -7791,10 +7857,9 @@ var RtmpClient = class {
7791
7857
  for (const chunk of chunks) this.socket.write(chunk);
7792
7858
  }
7793
7859
  async sendConnect() {
7794
- const parsedUrl = new URL(this.url);
7795
- const tcUrl = `${parsedUrl.protocol}//${parsedUrl.host}/${parsedUrl.pathname.split("/")[1]}`;
7860
+ const { app, tcUrl } = parseRtmpUrl(this.url);
7796
7861
  const connectObject = {
7797
- app: parsedUrl.pathname.split("/")[1],
7862
+ app,
7798
7863
  flashVer: "LNX 9,0,124,2",
7799
7864
  tcUrl,
7800
7865
  fpad: false,
@@ -16230,6 +16295,7 @@ var StreamBrokerManager = class StreamBrokerManager {
16230
16295
  const order = existing?.order ?? this.nextOrder(deviceId);
16231
16296
  const deviceFeatures = input.deviceFeatures ? [...input.deviceFeatures] : existing?.deviceFeatures ? [...existing.deviceFeatures] : [];
16232
16297
  const autoEligible = input.autoEligible ?? existing?.autoEligible ?? true;
16298
+ const profileHint = input.profileHint ?? existing?.profileHint;
16233
16299
  const brokerOwned = input.brokerOwned ?? existing?.brokerOwned ?? false;
16234
16300
  const cam = {
16235
16301
  camStreamId,
@@ -16244,6 +16310,7 @@ var StreamBrokerManager = class StreamBrokerManager {
16244
16310
  order,
16245
16311
  deviceFeatures,
16246
16312
  autoEligible,
16313
+ ...profileHint !== void 0 ? { profileHint } : {},
16247
16314
  brokerOwned
16248
16315
  };
16249
16316
  streamMap.set(camStreamId, cam);
@@ -18577,24 +18644,7 @@ var StreamBrokerManager = class StreamBrokerManager {
18577
18644
  * around it (618, 2026-08-17).
18578
18645
  */
18579
18646
  computeInitialAssignment(streams) {
18580
- const eligible = streams.filter((s) => s.autoEligible);
18581
- if (eligible.length === 0) return {};
18582
- const ranked = [...eligible].toSorted((a, b) => {
18583
- const aPx = a.resolution ? a.resolution.width * a.resolution.height : -1;
18584
- const bPx = b.resolution ? b.resolution.width * b.resolution.height : -1;
18585
- if (aPx !== bPx) return bPx - aPx;
18586
- return a.order - b.order;
18587
- });
18588
- if (ranked.length === 1) return { mid: ranked[0].camStreamId };
18589
- if (ranked.length === 2) return {
18590
- high: ranked[0].camStreamId,
18591
- low: ranked[1].camStreamId
18592
- };
18593
- return {
18594
- high: ranked[0].camStreamId,
18595
- mid: ranked[1].camStreamId,
18596
- low: ranked[2].camStreamId
18597
- };
18647
+ return rankInitialAssignment(streams);
18598
18648
  }
18599
18649
  /**
18600
18650
  * Recompute the auto profile assignment for a device over its CURRENT
@@ -30,7 +30,7 @@ async function d(e) {
30
30
  }
31
31
  }
32
32
  async function f() {
33
- return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-BmNfrv_U.mjs")).catch((e) => {
33
+ return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-CUjbLOm9.mjs")).catch((e) => {
34
34
  throw l = void 0, e;
35
35
  }), l;
36
36
  }
@@ -1,4 +1,4 @@
1
- import { b as NativeLeaseSettingsSchema, p as DEFAULT_NATIVE_LEASE_SETTINGS, y as NativeLeaseAdmissionSchema } from "./dist-B8J7wrtY.mjs";
1
+ import { b as NativeLeaseSettingsSchema, p as DEFAULT_NATIVE_LEASE_SETTINGS, y as NativeLeaseAdmissionSchema } from "./dist-mYDK58Jp.mjs";
2
2
  //#region src/session-decode/native-lease-config.ts
3
3
  /**
4
4
  * Resolution of the native-frame hold / tile knobs for one decode worker.
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-CXO_Fmx6.js");
1
+ const require_dist = require("./dist-HG5geL9t.js");
2
2
  //#region src/session-decode/native-lease-config.ts
3
3
  /**
4
4
  * Resolution of the native-frame hold / tile knobs for one decode worker.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-pipeline",
3
- "version": "1.2.192",
3
+ "version": "1.2.193",
4
4
  "description": "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",