@camstack/addon-pipeline 1.2.263 → 1.2.265

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.
@@ -18,7 +18,7 @@ var e = {
18
18
  },
19
19
  "@camstack/types": {
20
20
  name: "@camstack/types",
21
- version: "1.2.216",
21
+ version: "1.2.217",
22
22
  scope: ["default"],
23
23
  loaded: !1,
24
24
  from: "addon_stream_broker_widgets",
@@ -36,7 +36,7 @@ async function r() {
36
36
  }
37
37
  },
38
38
  "@camstack/types": {
39
- version: "1.2.216",
39
+ version: "1.2.217",
40
40
  scope: "default",
41
41
  shareConfig: {
42
42
  singleton: !0,
@@ -30525,6 +30525,18 @@ function reduceProfileForTranscodeDown(base) {
30525
30525
  }
30526
30526
  };
30527
30527
  }
30528
+ /**
30529
+ * How long a session setup waits for a broker that is on its way back.
30530
+ *
30531
+ * An addon respawn rebuilds every broker and re-registers it; the gap measured
30532
+ * on this hub is seconds, not tens of seconds. Five is enough to cover it and
30533
+ * short enough that a stream which really is gone still fails while the viewer
30534
+ * is looking at the player, with a message that says it waited.
30535
+ *
30536
+ * The alternative shipped for months: fail instantly and let the operator press
30537
+ * pause/play, which works only because the second attempt happens later.
30538
+ */
30539
+ var BROKER_REAPPEAR_WAIT_MS = 5e3;
30528
30540
  var BrokerWebrtcServer = class {
30529
30541
  logger;
30530
30542
  getIceServersFn;
@@ -30580,6 +30592,8 @@ var BrokerWebrtcServer = class {
30580
30592
  * devices (the manager's own gate), so an unset hook or a local-owner call
30581
30593
  * leaves adaptive resolution byte-identical to before this hook existed.
30582
30594
  */
30595
+ /** Callers parked on a broker that is being rebuilt, keyed by brokerId. */
30596
+ brokerWaiters = /* @__PURE__ */ new Map();
30583
30597
  ensureAdaptiveTierBroker = null;
30584
30598
  /** sessionId → session entry. */
30585
30599
  sessions = /* @__PURE__ */ new Map();
@@ -30606,6 +30620,11 @@ var BrokerWebrtcServer = class {
30606
30620
  }
30607
30621
  registerBroker(brokerId, broker) {
30608
30622
  this.brokers.set(brokerId, broker);
30623
+ const waiters = this.brokerWaiters.get(brokerId);
30624
+ if (waiters !== void 0) {
30625
+ this.brokerWaiters.delete(brokerId);
30626
+ for (const wake of waiters) wake();
30627
+ }
30609
30628
  const did = deviceIdFromBrokerId(brokerId);
30610
30629
  this.logger.info("WebRTC broker registered", {
30611
30630
  ...did !== -1 ? { tags: { deviceId: did } } : {},
@@ -30613,6 +30632,44 @@ var BrokerWebrtcServer = class {
30613
30632
  });
30614
30633
  }
30615
30634
  /**
30635
+ * Wait, briefly, for a broker that is on its way back.
30636
+ *
30637
+ * An addon respawn — every deploy — tears the brokers down and rebuilds
30638
+ * them, re-registering each with {@link registerBroker}. A viewer
30639
+ * reconnecting inside that window used to get `No broker for stream`,
30640
+ * terminal and immediate, and the only cure was the operator pressing
30641
+ * pause/play: the second attempt is the SAME call, later, by which point the
30642
+ * broker exists. The difference was never the call, it was the time.
30643
+ *
30644
+ * Resolves `null` on the deadline rather than throwing, so the caller keeps
30645
+ * owning the error message — a stream that really is gone must still fail,
30646
+ * and say that it waited.
30647
+ */
30648
+ waitForBroker(brokerId, timeoutMs) {
30649
+ const existing = this.brokers.get(brokerId);
30650
+ if (existing !== void 0) return Promise.resolve(existing);
30651
+ return new Promise((resolve) => {
30652
+ let settled = false;
30653
+ const finish = (value) => {
30654
+ if (settled) return;
30655
+ settled = true;
30656
+ resolve(value);
30657
+ };
30658
+ const wake = () => {
30659
+ finish(this.brokers.get(brokerId) ?? null);
30660
+ };
30661
+ const list = this.brokerWaiters.get(brokerId);
30662
+ if (list === void 0) this.brokerWaiters.set(brokerId, [wake]);
30663
+ else list.push(wake);
30664
+ setTimeout(() => {
30665
+ const remaining = (this.brokerWaiters.get(brokerId) ?? []).filter((w) => w !== wake);
30666
+ if (remaining.length === 0) this.brokerWaiters.delete(brokerId);
30667
+ else this.brokerWaiters.set(brokerId, remaining);
30668
+ finish(null);
30669
+ }, timeoutMs).unref?.();
30670
+ });
30671
+ }
30672
+ /**
30616
30673
  * Provide a resolver that maps brokerId → current profile tier. The
30617
30674
  * manager injects one wired to its `assignments` map. Without it the
30618
30675
  * server still serves brokers but can't honour client `prefersTier`
@@ -30833,14 +30890,14 @@ var BrokerWebrtcServer = class {
30833
30890
  try {
30834
30891
  await this.ensureAdaptiveTierBroker?.(adaptiveDeviceId, desiredTier);
30835
30892
  } catch (err) {
30836
- throw new Error(`Failed to ensure remote adaptive-tier broker for stream "${streamId}" (tier: ${desiredTier}): ${require_dist.errMsg(err)}`);
30893
+ throw new Error(`Could not prepare the owner node's broker for stream "${streamId}" (requested tier ${desiredTier}, ${String(Date.now() - ensureTierStart)}ms): ${require_dist.errMsg(err)}`);
30837
30894
  } finally {
30838
30895
  ensureTierMs = Date.now() - ensureTierStart;
30839
30896
  }
30840
30897
  }
30841
30898
  const brokerId = this.resolveBrokerId(streamId, resolveHints);
30842
- const broker = this.brokers.get(brokerId);
30843
- if (!broker) throw new Error(`No broker for stream "${streamId}" (resolved: "${brokerId}")`);
30899
+ const broker = this.brokers.get(brokerId) ?? await this.waitForBroker(brokerId, BROKER_REAPPEAR_WAIT_MS);
30900
+ if (!broker) throw new Error(`No broker for stream "${streamId}" (resolved: "${brokerId}") after waiting ${String(BROKER_REAPPEAR_WAIT_MS)}ms for one to register`);
30844
30901
  const baseTranscodeProfile = opts.transcodeProfile ?? WEBRTC_FALLBACK_PROFILE;
30845
30902
  const effectiveTranscodeProfile = intent?.forceTranscodeDown === true ? reduceProfileForTranscodeDown(baseTranscodeProfile) : opts.transcodeProfile;
30846
30903
  if (intent !== void 0 && opts.sessionId !== void 0) this.adaptiveIntent.delete(opts.sessionId);
@@ -30521,6 +30521,18 @@ function reduceProfileForTranscodeDown(base) {
30521
30521
  }
30522
30522
  };
30523
30523
  }
30524
+ /**
30525
+ * How long a session setup waits for a broker that is on its way back.
30526
+ *
30527
+ * An addon respawn rebuilds every broker and re-registers it; the gap measured
30528
+ * on this hub is seconds, not tens of seconds. Five is enough to cover it and
30529
+ * short enough that a stream which really is gone still fails while the viewer
30530
+ * is looking at the player, with a message that says it waited.
30531
+ *
30532
+ * The alternative shipped for months: fail instantly and let the operator press
30533
+ * pause/play, which works only because the second attempt happens later.
30534
+ */
30535
+ var BROKER_REAPPEAR_WAIT_MS = 5e3;
30524
30536
  var BrokerWebrtcServer = class {
30525
30537
  logger;
30526
30538
  getIceServersFn;
@@ -30576,6 +30588,8 @@ var BrokerWebrtcServer = class {
30576
30588
  * devices (the manager's own gate), so an unset hook or a local-owner call
30577
30589
  * leaves adaptive resolution byte-identical to before this hook existed.
30578
30590
  */
30591
+ /** Callers parked on a broker that is being rebuilt, keyed by brokerId. */
30592
+ brokerWaiters = /* @__PURE__ */ new Map();
30579
30593
  ensureAdaptiveTierBroker = null;
30580
30594
  /** sessionId → session entry. */
30581
30595
  sessions = /* @__PURE__ */ new Map();
@@ -30602,6 +30616,11 @@ var BrokerWebrtcServer = class {
30602
30616
  }
30603
30617
  registerBroker(brokerId, broker) {
30604
30618
  this.brokers.set(brokerId, broker);
30619
+ const waiters = this.brokerWaiters.get(brokerId);
30620
+ if (waiters !== void 0) {
30621
+ this.brokerWaiters.delete(brokerId);
30622
+ for (const wake of waiters) wake();
30623
+ }
30605
30624
  const did = deviceIdFromBrokerId(brokerId);
30606
30625
  this.logger.info("WebRTC broker registered", {
30607
30626
  ...did !== -1 ? { tags: { deviceId: did } } : {},
@@ -30609,6 +30628,44 @@ var BrokerWebrtcServer = class {
30609
30628
  });
30610
30629
  }
30611
30630
  /**
30631
+ * Wait, briefly, for a broker that is on its way back.
30632
+ *
30633
+ * An addon respawn — every deploy — tears the brokers down and rebuilds
30634
+ * them, re-registering each with {@link registerBroker}. A viewer
30635
+ * reconnecting inside that window used to get `No broker for stream`,
30636
+ * terminal and immediate, and the only cure was the operator pressing
30637
+ * pause/play: the second attempt is the SAME call, later, by which point the
30638
+ * broker exists. The difference was never the call, it was the time.
30639
+ *
30640
+ * Resolves `null` on the deadline rather than throwing, so the caller keeps
30641
+ * owning the error message — a stream that really is gone must still fail,
30642
+ * and say that it waited.
30643
+ */
30644
+ waitForBroker(brokerId, timeoutMs) {
30645
+ const existing = this.brokers.get(brokerId);
30646
+ if (existing !== void 0) return Promise.resolve(existing);
30647
+ return new Promise((resolve) => {
30648
+ let settled = false;
30649
+ const finish = (value) => {
30650
+ if (settled) return;
30651
+ settled = true;
30652
+ resolve(value);
30653
+ };
30654
+ const wake = () => {
30655
+ finish(this.brokers.get(brokerId) ?? null);
30656
+ };
30657
+ const list = this.brokerWaiters.get(brokerId);
30658
+ if (list === void 0) this.brokerWaiters.set(brokerId, [wake]);
30659
+ else list.push(wake);
30660
+ setTimeout(() => {
30661
+ const remaining = (this.brokerWaiters.get(brokerId) ?? []).filter((w) => w !== wake);
30662
+ if (remaining.length === 0) this.brokerWaiters.delete(brokerId);
30663
+ else this.brokerWaiters.set(brokerId, remaining);
30664
+ finish(null);
30665
+ }, timeoutMs).unref?.();
30666
+ });
30667
+ }
30668
+ /**
30612
30669
  * Provide a resolver that maps brokerId → current profile tier. The
30613
30670
  * manager injects one wired to its `assignments` map. Without it the
30614
30671
  * server still serves brokers but can't honour client `prefersTier`
@@ -30829,14 +30886,14 @@ var BrokerWebrtcServer = class {
30829
30886
  try {
30830
30887
  await this.ensureAdaptiveTierBroker?.(adaptiveDeviceId, desiredTier);
30831
30888
  } catch (err) {
30832
- throw new Error(`Failed to ensure remote adaptive-tier broker for stream "${streamId}" (tier: ${desiredTier}): ${errMsg(err)}`);
30889
+ throw new Error(`Could not prepare the owner node's broker for stream "${streamId}" (requested tier ${desiredTier}, ${String(Date.now() - ensureTierStart)}ms): ${errMsg(err)}`);
30833
30890
  } finally {
30834
30891
  ensureTierMs = Date.now() - ensureTierStart;
30835
30892
  }
30836
30893
  }
30837
30894
  const brokerId = this.resolveBrokerId(streamId, resolveHints);
30838
- const broker = this.brokers.get(brokerId);
30839
- if (!broker) throw new Error(`No broker for stream "${streamId}" (resolved: "${brokerId}")`);
30895
+ const broker = this.brokers.get(brokerId) ?? await this.waitForBroker(brokerId, BROKER_REAPPEAR_WAIT_MS);
30896
+ if (!broker) throw new Error(`No broker for stream "${streamId}" (resolved: "${brokerId}") after waiting ${String(BROKER_REAPPEAR_WAIT_MS)}ms for one to register`);
30840
30897
  const baseTranscodeProfile = opts.transcodeProfile ?? WEBRTC_FALLBACK_PROFILE;
30841
30898
  const effectiveTranscodeProfile = intent?.forceTranscodeDown === true ? reduceProfileForTranscodeDown(baseTranscodeProfile) : opts.transcodeProfile;
30842
30899
  if (intent !== void 0 && opts.sessionId !== void 0) this.adaptiveIntent.delete(opts.sessionId);
@@ -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-r_tNVu_V.mjs")).catch((e) => {
33
+ return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-YMFzjaS5.mjs")).catch((e) => {
34
34
  throw l = void 0, e;
35
35
  }), l;
36
36
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-pipeline",
3
- "version": "1.2.263",
3
+ "version": "1.2.265",
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",