@camstack/system 1.2.74 → 1.2.75

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.
@@ -788,6 +788,13 @@ function parseVerifiedSnapshotLink(input) {
788
788
  * answers inside it, short enough that a dead camera cannot stall the batch.
789
789
  */
790
790
  var LINK_MINT_DEADLINE_MS = 2500;
791
+ /**
792
+ * A links RPC is one Viewer-wide batch. Never let one slow camera hold every
793
+ * fast camera behind its individual capture deadline: wait briefly for the
794
+ * common fast path, then mint from the cache as it stands. Slow captures keep
795
+ * running and their new generation is returned by the next 5 s poll.
796
+ */
797
+ var LINK_BATCH_WAIT_MS = 750;
791
798
  /** Frames older than this are never represented as current by the Viewer. */
792
799
  var LINK_CURRENT_MAX_AGE_MS = 15e3;
793
800
  /** Default cache window for non-battery cams (seconds). 10s feels live. */
@@ -1053,12 +1060,18 @@ var SnapshotAddon = class SnapshotAddon extends require_dist.BaseAddon {
1053
1060
  const expMs = snapshotLinkExpiry(now, SNAPSHOT_LINK_TTL_MS);
1054
1061
  const served = this.linkDataPlane !== null && secret !== null;
1055
1062
  const prefix = this.linkRoutePrefix();
1056
- const rows = await Promise.all(input.targets.map(async (target) => {
1063
+ const sleepingByDevice = /* @__PURE__ */ new Map();
1064
+ const refreshes = input.targets.map(async (target) => {
1065
+ const width = target.width === void 0 ? void 0 : snapSnapshotWidth(target.width);
1066
+ this.subscriptions.note(target.deviceId, void 0, width, now);
1067
+ const sleeping = await this.isSleepingBatteryDevice(target.deviceId);
1068
+ sleepingByDevice.set(target.deviceId, sleeping);
1069
+ if (!sleeping) await this.awaitFreshEnough(target.deviceId);
1070
+ });
1071
+ await raceForResult(Promise.allSettled(refreshes), LINK_BATCH_WAIT_MS);
1072
+ const rows = input.targets.map((target) => {
1057
1073
  const { deviceId } = target;
1058
1074
  const width = target.width === void 0 ? void 0 : snapSnapshotWidth(target.width);
1059
- this.subscriptions.note(deviceId, void 0, width, now);
1060
- const sleeping = await this.isSleepingBatteryDevice(deviceId);
1061
- if (!sleeping) await this.awaitFreshEnough(deviceId);
1062
1075
  const capturedAt = this.cache.latest(deviceId)?.ts ?? null;
1063
1076
  const answeredAt = Date.now();
1064
1077
  return {
@@ -1076,9 +1089,9 @@ var SnapshotAddon = class SnapshotAddon extends require_dist.BaseAddon {
1076
1089
  expiresAt: served ? expMs : null,
1077
1090
  width: width ?? null,
1078
1091
  neverCaptured: capturedAt === null,
1079
- sleeping
1092
+ sleeping: sleepingByDevice.get(deviceId) ?? false
1080
1093
  };
1081
- }));
1094
+ });
1082
1095
  this.ctx.logger.debug("snapshot: minted links", { meta: {
1083
1096
  targets: input.targets.length,
1084
1097
  served,
@@ -783,6 +783,13 @@ function parseVerifiedSnapshotLink(input) {
783
783
  * answers inside it, short enough that a dead camera cannot stall the batch.
784
784
  */
785
785
  var LINK_MINT_DEADLINE_MS = 2500;
786
+ /**
787
+ * A links RPC is one Viewer-wide batch. Never let one slow camera hold every
788
+ * fast camera behind its individual capture deadline: wait briefly for the
789
+ * common fast path, then mint from the cache as it stands. Slow captures keep
790
+ * running and their new generation is returned by the next 5 s poll.
791
+ */
792
+ var LINK_BATCH_WAIT_MS = 750;
786
793
  /** Frames older than this are never represented as current by the Viewer. */
787
794
  var LINK_CURRENT_MAX_AGE_MS = 15e3;
788
795
  /** Default cache window for non-battery cams (seconds). 10s feels live. */
@@ -1048,12 +1055,18 @@ var SnapshotAddon = class SnapshotAddon extends BaseAddon {
1048
1055
  const expMs = snapshotLinkExpiry(now, SNAPSHOT_LINK_TTL_MS);
1049
1056
  const served = this.linkDataPlane !== null && secret !== null;
1050
1057
  const prefix = this.linkRoutePrefix();
1051
- const rows = await Promise.all(input.targets.map(async (target) => {
1058
+ const sleepingByDevice = /* @__PURE__ */ new Map();
1059
+ const refreshes = input.targets.map(async (target) => {
1060
+ const width = target.width === void 0 ? void 0 : snapSnapshotWidth(target.width);
1061
+ this.subscriptions.note(target.deviceId, void 0, width, now);
1062
+ const sleeping = await this.isSleepingBatteryDevice(target.deviceId);
1063
+ sleepingByDevice.set(target.deviceId, sleeping);
1064
+ if (!sleeping) await this.awaitFreshEnough(target.deviceId);
1065
+ });
1066
+ await raceForResult(Promise.allSettled(refreshes), LINK_BATCH_WAIT_MS);
1067
+ const rows = input.targets.map((target) => {
1052
1068
  const { deviceId } = target;
1053
1069
  const width = target.width === void 0 ? void 0 : snapSnapshotWidth(target.width);
1054
- this.subscriptions.note(deviceId, void 0, width, now);
1055
- const sleeping = await this.isSleepingBatteryDevice(deviceId);
1056
- if (!sleeping) await this.awaitFreshEnough(deviceId);
1057
1070
  const capturedAt = this.cache.latest(deviceId)?.ts ?? null;
1058
1071
  const answeredAt = Date.now();
1059
1072
  return {
@@ -1071,9 +1084,9 @@ var SnapshotAddon = class SnapshotAddon extends BaseAddon {
1071
1084
  expiresAt: served ? expMs : null,
1072
1085
  width: width ?? null,
1073
1086
  neverCaptured: capturedAt === null,
1074
- sleeping
1087
+ sleeping: sleepingByDevice.get(deviceId) ?? false
1075
1088
  };
1076
- }));
1089
+ });
1077
1090
  this.ctx.logger.debug("snapshot: minted links", { meta: {
1078
1091
  targets: input.targets.length,
1079
1092
  served,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/system",
3
- "version": "1.2.74",
3
+ "version": "1.2.75",
4
4
  "description": "Core addon for CamStack — builtins, pipeline, process management, auth, logging, events",
5
5
  "keywords": [
6
6
  "camstack",