camstack 1.2.153 → 1.2.155

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.
@@ -23633,9 +23633,9 @@ var require_zod = __commonJS({
23633
23633
  }
23634
23634
  });
23635
23635
 
23636
- // ../system/dist/dist-DaSCLJVH.js
23637
- var require_dist_DaSCLJVH = __commonJS({
23638
- "../system/dist/dist-DaSCLJVH.js"(exports) {
23636
+ // ../system/dist/dist-Dze0l7UM.js
23637
+ var require_dist_Dze0l7UM = __commonJS({
23638
+ "../system/dist/dist-Dze0l7UM.js"(exports) {
23639
23639
  "use strict";
23640
23640
  var zod = require_zod();
23641
23641
  var EventCategory = /* @__PURE__ */ (function(EventCategory2) {
@@ -29471,6 +29471,21 @@ var require_dist_DaSCLJVH = __commonJS({
29471
29471
  mode: "singleton",
29472
29472
  deviceTypes: Object.values(DeviceType),
29473
29473
  runtimeState: StreamSignalsStatusSchema,
29474
+ /**
29475
+ * Runtime-state durability: **session** — mirrored in RAM, never written.
29476
+ *
29477
+ * The slice holds what the DEVICE says it can emit. That is a probed fact,
29478
+ * not an operator choice: the provider re-declares it on every registration,
29479
+ * so losing it loses nothing and persisting it would freeze an answer the
29480
+ * camera is entitled to change. Measured the same day on the sibling case —
29481
+ * `native-object-detection.supportedClasses` was persisted, and a firmware
29482
+ * class the camera really detected stayed missing for the life of the row
29483
+ * because the fix could not reach it.
29484
+ *
29485
+ * See `RuntimeStateDurability`. Enforced by
29486
+ * `scripts/check-runtime-state-durability.ts`.
29487
+ */
29488
+ durability: "session",
29474
29489
  methods: {
29475
29490
  /**
29476
29491
  * What this device can emit. Empty is a valid and common answer — most
@@ -30735,16 +30750,6 @@ var require_dist_DaSCLJVH = __commonJS({
30735
30750
  })) }), { auth: "admin" })
30736
30751
  }
30737
30752
  };
30738
- function describeCustomActions(catalog) {
30739
- const out = {};
30740
- for (const [name, spec] of Object.entries(catalog)) out[name] = {
30741
- kind: spec.kind,
30742
- auth: spec.auth,
30743
- scope: spec.scope,
30744
- ...spec.caller === "required" ? { caller: "required" } : {}
30745
- };
30746
- return out;
30747
- }
30748
30753
  var CustomModelDescriptorSchema = zod.z.object({
30749
30754
  stepId: zod.z.string(),
30750
30755
  entry: ModelCatalogEntrySchema
@@ -36354,6 +36359,29 @@ var require_dist_DaSCLJVH = __commonJS({
36354
36359
  settings: NcAlarmSettingsSchema,
36355
36360
  coverage: zod.z.array(NcAlarmModeCoverageSchema)
36356
36361
  });
36362
+ var NcClipRetentionAskSchema = zod.z.object({
36363
+ /**
36364
+ * The camera this ask is about. **Absent = every camera**, which is what a
36365
+ * rule with no `conditions.devices` means: it can fire anywhere, so it is
36366
+ * asking everywhere.
36367
+ */
36368
+ deviceId: zod.z.number().int().nonnegative().optional(),
36369
+ /** Seconds of history the rule needs held for it. Never zero — a rule that
36370
+ * needs nothing produces no ask at all. */
36371
+ seconds: zod.z.number().min(0).max(60),
36372
+ /** The profile the rule cuts from, when it named one. Absent = the cheapest
36373
+ * assigned, which is what the cut defaults to. */
36374
+ profile: CamProfileSchema.optional(),
36375
+ /** Who is asking — so a retention the operator did not expect names a rule. */
36376
+ ruleId: zod.z.string(),
36377
+ ruleName: zod.z.string(),
36378
+ /** Why this many seconds: the rule's own window, or the occupancy ceiling. */
36379
+ reason: zod.z.enum(["window", "occupancy"])
36380
+ });
36381
+ var NcClipRetentionPlanSchema = zod.z.object({
36382
+ rulesLoaded: zod.z.boolean(),
36383
+ asks: zod.z.array(NcClipRetentionAskSchema).readonly()
36384
+ });
36357
36385
  var notificationRulesCapability = {
36358
36386
  name: "notification-rules",
36359
36387
  scope: "system",
@@ -36386,6 +36414,23 @@ var require_dist_DaSCLJVH = __commonJS({
36386
36414
  auth: "admin"
36387
36415
  }),
36388
36416
  /**
36417
+ * WHAT THE RULES ACTUALLY ASK the stream broker to retain, per camera.
36418
+ *
36419
+ * The notification centre owns the rules, so it is the only thing that can
36420
+ * say how much history a camera's notifications will ever reach back for.
36421
+ * Before this the broker guessed — a flat minute on every camera — and
36422
+ * learned the PROFILE reactively, after the first clip had already been cut
36423
+ * from the wrong one. This is the same ask stated once, in front.
36424
+ *
36425
+ * A QUERY, pulled by each node's broker, not a push: brokers are per node
36426
+ * (a camera's ring lives wherever its stream is ingested) while this cap is
36427
+ * a singleton, so a push would have to enumerate the cluster. The pull also
36428
+ * makes the failure mode right — a broker that cannot reach the centre
36429
+ * keeps the plan it has, and a plan that has never arrived is UNKNOWN
36430
+ * rather than empty (D49: a read that fails changes nothing).
36431
+ */
36432
+ getClipRetentionAsks: method(zod.z.object({}), NcClipRetentionPlanSchema, { auth: "admin" }),
36433
+ /**
36389
36434
  * PERMANENT per-camera mute — the notifications half of the per-camera
36390
36435
  * function switch group ([D61](../../../../docs/decisions/adr-0067.md)).
36391
36436
  *
@@ -38594,6 +38639,20 @@ var require_dist_DaSCLJVH = __commonJS({
38594
38639
  framesMatched: zod.z.number().int()
38595
38640
  });
38596
38641
  var RunReplayFrameProcessorResultSchema = zod.z.object({ tracks: zod.z.array(ReplayTrackSchema).readonly() });
38642
+ var AnalyticsLtsSeriesSchema = zod.z.enum([
38643
+ "motion",
38644
+ "audio-dbfs",
38645
+ "battery",
38646
+ "occupancy"
38647
+ ]);
38648
+ var LtsBucketSchema = zod.z.object({
38649
+ scope: zod.z.string(),
38650
+ bucketStart: zod.z.number().int(),
38651
+ samples: zod.z.number().int().nonnegative(),
38652
+ sum: zod.z.number(),
38653
+ min: zod.z.number(),
38654
+ max: zod.z.number()
38655
+ });
38597
38656
  var pipelineAnalyticsCapability = {
38598
38657
  name: "pipeline-analytics",
38599
38658
  scope: "device",
@@ -38737,6 +38796,30 @@ var require_dist_DaSCLJVH = __commonJS({
38737
38796
  getKeyEventsBatch: method(KeyEventBatchQueryInput, zod.z.array(KeyEventsForDeviceSchema).readonly()),
38738
38797
  /** Server-side bucketed event counts for the 24-hour timeline.
38739
38798
  * Returns one entry per non-empty bucket; empty buckets are omitted. */
38799
+ /**
38800
+ * Read one camera's long-term series — 5-minute buckets, kept for a year.
38801
+ *
38802
+ * This is the history surface for every chart that used to be served from a
38803
+ * RAM ring: the ring dies with the process, cannot answer about last night,
38804
+ * and had a 60-minute horizon, while these rows are ~60 bytes and already
38805
+ * written. `scope` is the series' own dimension — for `occupancy`, spell it
38806
+ * with {@link occupancyScope} rather than by hand, and omit it to get every
38807
+ * scope back at once (the caller then groups with
38808
+ * {@link parseOccupancyScope}).
38809
+ *
38810
+ * Bounds are inclusive on the BUCKET START, so a range that ends mid-bucket
38811
+ * still returns the bucket it lands in — the alternative is a chart whose
38812
+ * last column silently disappears for five minutes out of every five.
38813
+ */
38814
+ readLongTermSeries: method(zod.z.object({
38815
+ deviceId: zod.z.number(),
38816
+ series: AnalyticsLtsSeriesSchema,
38817
+ /** Omit for EVERY scope of this series in the range. */
38818
+ scope: zod.z.string().optional(),
38819
+ from: zod.z.number(),
38820
+ to: zod.z.number(),
38821
+ limit: zod.z.number().int().positive().optional()
38822
+ }), zod.z.array(LtsBucketSchema).readonly()),
38740
38823
  getEventDensity: method(zod.z.object({
38741
38824
  deviceId: zod.z.number(),
38742
38825
  since: zod.z.number(),
@@ -40053,6 +40136,12 @@ var require_dist_DaSCLJVH = __commonJS({
40053
40136
  queueDepth: zod.z.number(),
40054
40137
  frameLazy: FrameLazyMetricsSchema.optional()
40055
40138
  });
40139
+ var OccupancyBurstRefusalSchema = zod.z.enum([
40140
+ "not-attached",
40141
+ "battery-asleep",
40142
+ "not-watching",
40143
+ "already-bursting"
40144
+ ]);
40056
40145
  var pipelineRunnerCapability = {
40057
40146
  name: "pipeline-runner",
40058
40147
  scope: "system",
@@ -40089,6 +40178,50 @@ var require_dist_DaSCLJVH = __commonJS({
40089
40178
  /** List the deviceIds currently attached to this runner. */
40090
40179
  getLocalCameras: method(zod.z.void(), zod.z.array(zod.z.number()).readonly()),
40091
40180
  /**
40181
+ * Look at a camera NOW, out of band, because something just happened that
40182
+ * only a fresh look can settle.
40183
+ *
40184
+ * The periodic recheck (`occupancyRecheckSec`, 300 s) exists to watch a
40185
+ * still scene. It is the wrong instrument for a QUESTION that has just been
40186
+ * asked: on device 617 a parked car's departure was observed, a departure
40187
+ * strike was armed — and then the motion session ended, the strike decayed
40188
+ * after its 30 s TTL, and the next periodic look arrived up to five minutes
40189
+ * later with nothing left to confirm. Every one of those departures was
40190
+ * settled by the entry ageing out 6 to 10 minutes of observed time later,
40191
+ * and the notification's clip showed an empty space with nothing leaving
40192
+ * it.
40193
+ *
40194
+ * Two numbers make the ask specific, and a caller that ignores them wastes
40195
+ * the burst: a confirmation must land at least
40196
+ * `DEPARTURE_CONFIRM_MIN_GAP_MS` (3 s) after the read that armed the
40197
+ * strike — before that it is the same optical event and is refused — and
40198
+ * `DEPARTURE_ABSENCE_MIN_READS` (5) consecutive unassociated frames are
40199
+ * needed, while `occupancyRecheckFrames` defaults to FOUR. A burst of four
40200
+ * can never confirm an absence; that is why two periodic looks were always
40201
+ * required.
40202
+ *
40203
+ * The runner answers whether it actually started one. A refusal is NAMED,
40204
+ * never a silent `false`: a camera that is asleep on battery (D173 — this
40205
+ * must not become a self-initiated wake), detached, mid-session or already
40206
+ * bursting are four different facts, and a caller told only "no" cannot
40207
+ * tell a protection from a bug.
40208
+ */
40209
+ requestOccupancyBurst: method(zod.z.object({
40210
+ deviceId: zod.z.number(),
40211
+ /** How many frames to collect. The caller sizes this against what its
40212
+ * own confirmation needs; the runner clamps it to the field's range. */
40213
+ frames: zod.z.number().int().positive().optional(),
40214
+ /** Why, for the log. A burst nobody can attribute is a cost nobody can
40215
+ * defend — the periodic one at least has a timer to point at. */
40216
+ reason: zod.z.string()
40217
+ }), zod.z.object({
40218
+ started: zod.z.boolean(),
40219
+ refusedBecause: OccupancyBurstRefusalSchema.optional()
40220
+ }), {
40221
+ auth: "admin",
40222
+ kind: "mutation"
40223
+ }),
40224
+ /**
40092
40225
  * Best-effort NATIVE-resolution crop of a retention-ring frame. Given the
40093
40226
  * `FrameHandle` that rode an inference-result event and a normalized `bbox`,
40094
40227
  * the runner asks the decode worker still holding that frame's NATIVE
@@ -51841,7 +51974,28 @@ var require_dist_DaSCLJVH = __commonJS({
51841
51974
  /** Total tracked objects in this scope (frame / zone / unzoned). */
51842
51975
  totalObjects: zod.z.number().int().nonnegative(),
51843
51976
  /** Per-class count. Keys are macro class names (e.g. `person`, `car`). */
51844
- byClass: zod.z.record(zod.z.string(), zod.z.number().int().nonnegative())
51977
+ byClass: zod.z.record(zod.z.string(), zod.z.number().int().nonnegative()),
51978
+ /**
51979
+ * Of `totalObjects`, how many are STANDING — objects the census holds,
51980
+ * present but not going anywhere (a parked car, a bin, a statue).
51981
+ *
51982
+ * The operator's question about a scene has two halves and they answer
51983
+ * different things: "what is parked here" is stable for hours and must not
51984
+ * flap, while "who is walking through" is the thing an alert is about. One
51985
+ * number could only serve one of them, and `totalObjects` served the first
51986
+ * badly — a passer-by moved it and every occupancy rule saw a change.
51987
+ *
51988
+ * `standing + transient === totalObjects`, always. The total keeps its old
51989
+ * meaning exactly, so no rule written against it changes behaviour.
51990
+ *
51991
+ * ABSENT means UNKNOWN, never zero (D393): a snapshot from a node older than
51992
+ * this field cannot say, and a reader that folds absence in as 0 reports "no
51993
+ * parked objects here" about a camera whose lot is full.
51994
+ */
51995
+ standingObjects: zod.z.number().int().nonnegative().optional(),
51996
+ /** Of `totalObjects`, how many are passing through. See `standingObjects` —
51997
+ * same absence rule. */
51998
+ transientObjects: zod.z.number().int().nonnegative().optional()
51845
51999
  });
51846
52000
  var ZoneScopeBreakdownSchema = PerScopeBreakdownSchema.extend({
51847
52001
  zoneId: zod.z.string(),
@@ -55763,6 +55917,12 @@ var require_dist_DaSCLJVH = __commonJS({
55763
55917
  addonId: null,
55764
55918
  access: "view"
55765
55919
  },
55920
+ "notificationRules.getClipRetentionAsks": {
55921
+ capName: "notification-rules",
55922
+ capScope: "system",
55923
+ addonId: null,
55924
+ access: "view"
55925
+ },
55766
55926
  "notificationRules.getConditionCatalog": {
55767
55927
  capName: "notification-rules",
55768
55928
  capScope: "system",
@@ -56273,6 +56433,12 @@ var require_dist_DaSCLJVH = __commonJS({
56273
56433
  addonId: null,
56274
56434
  access: "create"
56275
56435
  },
56436
+ "pipelineAnalytics.readLongTermSeries": {
56437
+ capName: "pipeline-analytics",
56438
+ capScope: "device",
56439
+ addonId: null,
56440
+ access: "view"
56441
+ },
56276
56442
  "pipelineAnalytics.rebuildObjectEmbeddings": {
56277
56443
  capName: "pipeline-analytics",
56278
56444
  capScope: "device",
@@ -56945,6 +57111,12 @@ var require_dist_DaSCLJVH = __commonJS({
56945
57111
  addonId: null,
56946
57112
  access: "create"
56947
57113
  },
57114
+ "pipelineRunner.requestOccupancyBurst": {
57115
+ capName: "pipeline-runner",
57116
+ capScope: "system",
57117
+ addonId: null,
57118
+ access: "create"
57119
+ },
56948
57120
  "pipelineRunner.runDetailSubtree": {
56949
57121
  capName: "pipeline-runner",
56950
57122
  capScope: "system",
@@ -60089,6 +60261,11 @@ var require_dist_DaSCLJVH = __commonJS({
60089
60261
  form: "single",
60090
60262
  optional: false
60091
60263
  }],
60264
+ "pipelineAnalytics.readLongTermSeries": [{
60265
+ name: "deviceId",
60266
+ form: "single",
60267
+ optional: false
60268
+ }],
60092
60269
  "pipelineAnalytics.rebuildObjectEmbeddings": [{
60093
60270
  name: "deviceId",
60094
60271
  form: "single",
@@ -60279,6 +60456,11 @@ var require_dist_DaSCLJVH = __commonJS({
60279
60456
  form: "single",
60280
60457
  optional: false
60281
60458
  }],
60459
+ "pipelineRunner.requestOccupancyBurst": [{
60460
+ name: "deviceId",
60461
+ form: "single",
60462
+ optional: false
60463
+ }],
60282
60464
  "pipelineRunner.runDetailSubtree": [{
60283
60465
  name: "deviceId",
60284
60466
  form: "single",
@@ -61947,12 +62129,6 @@ var require_dist_DaSCLJVH = __commonJS({
61947
62129
  return deriveBatteryPresence;
61948
62130
  }
61949
62131
  });
61950
- Object.defineProperty(exports, "describeCustomActions", {
61951
- enumerable: true,
61952
- get: function() {
61953
- return describeCustomActions;
61954
- }
61955
- });
61956
62132
  Object.defineProperty(exports, "deviceManagerCapability", {
61957
62133
  enumerable: true,
61958
62134
  get: function() {
@@ -62379,7 +62555,7 @@ var require_alerts_addon = __commonJS({
62379
62555
  [Symbol.toStringTag]: { value: "Module" }
62380
62556
  });
62381
62557
  require_chunk_Cek0wNdY();
62382
- var require_dist10 = require_dist_DaSCLJVH();
62558
+ var require_dist10 = require_dist_Dze0l7UM();
62383
62559
  function selectExpired(alerts, cutoffMs) {
62384
62560
  return alerts.filter((a) => a.createdAt < cutoffMs).sort((a, b) => a.createdAt - b.createdAt).map((a) => a.id);
62385
62561
  }
@@ -63198,7 +63374,7 @@ var require_console_logging = __commonJS({
63198
63374
  [Symbol.toStringTag]: { value: "Module" }
63199
63375
  });
63200
63376
  require_chunk_Cek0wNdY();
63201
- var require_dist10 = require_dist_DaSCLJVH();
63377
+ var require_dist10 = require_dist_Dze0l7UM();
63202
63378
  var require_formatter = require_formatter_DqAKDlvN();
63203
63379
  var LEVEL_RANK = {
63204
63380
  debug: 0,
@@ -63292,7 +63468,7 @@ var require_core_blocks_addon = __commonJS({
63292
63468
  "use strict";
63293
63469
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
63294
63470
  var require_chunk = require_chunk_Cek0wNdY();
63295
- var require_dist10 = require_dist_DaSCLJVH();
63471
+ var require_dist10 = require_dist_Dze0l7UM();
63296
63472
  var node_crypto = __require("crypto");
63297
63473
  var node_fs_promises = __require("fs/promises");
63298
63474
  node_fs_promises = require_chunk.__toESM(node_fs_promises);
@@ -64189,11 +64365,11 @@ var require_core_blocks = __commonJS({
64189
64365
  }
64190
64366
  });
64191
64367
 
64192
- // ../system/dist/retired-settings-keys-CZISf623.js
64193
- var require_retired_settings_keys_CZISf623 = __commonJS({
64194
- "../system/dist/retired-settings-keys-CZISf623.js"(exports) {
64368
+ // ../system/dist/retired-settings-keys-1GWw9mup.js
64369
+ var require_retired_settings_keys_1GWw9mup = __commonJS({
64370
+ "../system/dist/retired-settings-keys-1GWw9mup.js"(exports) {
64195
64371
  "use strict";
64196
- var require_dist10 = require_dist_DaSCLJVH();
64372
+ var require_dist10 = require_dist_Dze0l7UM();
64197
64373
  function settingsStoreIsAuthoritativeHere(env) {
64198
64374
  const raw = (env["CAMSTACK_ROLE"] ?? "").trim().toLowerCase();
64199
64375
  return raw === "" || raw === "hub";
@@ -66430,8 +66606,8 @@ var require_device_manager_addon = __commonJS({
66430
66606
  [Symbol.toStringTag]: { value: "Module" }
66431
66607
  });
66432
66608
  require_chunk_Cek0wNdY();
66433
- var require_dist10 = require_dist_DaSCLJVH();
66434
- var require_retired_settings_keys = require_retired_settings_keys_CZISf623();
66609
+ var require_dist10 = require_dist_Dze0l7UM();
66610
+ var require_retired_settings_keys = require_retired_settings_keys_1GWw9mup();
66435
66611
  var node_crypto = __require("crypto");
66436
66612
  var _camstack_types_node = require_node();
66437
66613
  var JOB_HISTORY = 20;
@@ -66719,6 +66895,75 @@ var require_device_manager_addon = __commonJS({
66719
66895
  }
66720
66896
  }
66721
66897
  };
66898
+ var CONTRIBUTION_BUDGET_MS = 1500;
66899
+ var ContributionCache = class {
66900
+ maxEntries;
66901
+ entries = /* @__PURE__ */ new Map();
66902
+ constructor(maxEntries = 512) {
66903
+ this.maxEntries = maxEntries;
66904
+ }
66905
+ /**
66906
+ * Resolve one provider's contribution within `budgetMs`.
66907
+ *
66908
+ * The call is never cancelled: it keeps running and its answer refreshes the
66909
+ * cache, so the provider that overran this page pays for the next one.
66910
+ */
66911
+ async resolve(key, call, budgetMs = CONTRIBUTION_BUDGET_MS) {
66912
+ const existing = this.entries.get(key);
66913
+ if (existing?.inFlight) return existing.value !== null ? {
66914
+ kind: "stale",
66915
+ value: existing.value
66916
+ } : {
66917
+ kind: "absent",
66918
+ reason: "slow"
66919
+ };
66920
+ const entry = existing ?? {
66921
+ value: null,
66922
+ inFlight: null
66923
+ };
66924
+ if (!existing) this.remember(key, entry);
66925
+ let settled = false;
66926
+ let answer = null;
66927
+ let failed = false;
66928
+ const refresh = call().then((value) => {
66929
+ answer = value;
66930
+ settled = true;
66931
+ entry.value = value;
66932
+ entry.inFlight = null;
66933
+ }, () => {
66934
+ failed = true;
66935
+ settled = true;
66936
+ entry.inFlight = null;
66937
+ });
66938
+ entry.inFlight = refresh;
66939
+ await Promise.race([refresh, sleep(budgetMs)]);
66940
+ if (settled && !failed) return {
66941
+ kind: "fresh",
66942
+ value: answer
66943
+ };
66944
+ if (entry.value !== null) return {
66945
+ kind: "stale",
66946
+ value: entry.value
66947
+ };
66948
+ return {
66949
+ kind: "absent",
66950
+ reason: failed ? "failed" : "slow"
66951
+ };
66952
+ }
66953
+ remember(key, entry) {
66954
+ this.entries.set(key, entry);
66955
+ while (this.entries.size > this.maxEntries) {
66956
+ const oldest = this.entries.keys().next();
66957
+ if (oldest.done === true) break;
66958
+ this.entries.delete(oldest.value);
66959
+ }
66960
+ }
66961
+ };
66962
+ function sleep(ms) {
66963
+ return new Promise((resolve) => {
66964
+ setTimeout(resolve, ms).unref?.();
66965
+ });
66966
+ }
66722
66967
  function tagContribution(contribution, capName, addonId, kind) {
66723
66968
  const source = kind === "settings" ? "settings" : "live";
66724
66969
  return {
@@ -68310,6 +68555,39 @@ var require_device_manager_addon = __commonJS({
68310
68555
  driverPatch
68311
68556
  };
68312
68557
  }
68558
+ var contributionCache = new ContributionCache();
68559
+ async function resolveContribution(deps, input) {
68560
+ const { deviceId, kind, capName, addonId } = input;
68561
+ const outcome = await contributionCache.resolve(`${String(deviceId)}:${kind}:${capName}:${addonId}`, input.call);
68562
+ if (outcome.kind === "fresh") return outcome.value === null ? null : tagContribution(outcome.value, capName, addonId, kind);
68563
+ if (outcome.kind === "stale") {
68564
+ deps.ctx.logger.info("device contribution served from the last answer \u2014 the provider is slow", {
68565
+ tags: {
68566
+ deviceId,
68567
+ addonId
68568
+ },
68569
+ meta: {
68570
+ capName,
68571
+ method: kind,
68572
+ budgetMs: CONTRIBUTION_BUDGET_MS
68573
+ }
68574
+ });
68575
+ return tagContribution(outcome.value, capName, addonId, kind);
68576
+ }
68577
+ deps.ctx.logger.warn("device contribution unavailable \u2014 the panel is missing this section", {
68578
+ tags: {
68579
+ deviceId,
68580
+ addonId
68581
+ },
68582
+ meta: {
68583
+ capName,
68584
+ method: kind,
68585
+ reason: outcome.reason,
68586
+ budgetMs: CONTRIBUTION_BUDGET_MS
68587
+ }
68588
+ });
68589
+ return null;
68590
+ }
68313
68591
  async function getDeviceAggregate(deps, deviceId, kind) {
68314
68592
  const registry = deps.capabilityRegistry;
68315
68593
  if (!registry) {
@@ -68325,25 +68603,16 @@ var require_device_manager_addon = __commonJS({
68325
68603
  if (!def?.exposesDeviceSettings) return null;
68326
68604
  const provider = registry.getProviderByAddon(entry.capName, entry.providerAddonId);
68327
68605
  if (!provider) return null;
68328
- try {
68329
- const contribution = await provider[method]({ deviceId });
68330
- if (!contribution) return null;
68331
- return tagContribution(toWireShape(contribution), entry.capName, entry.providerAddonId, kind);
68332
- } catch (err) {
68333
- const msg = err instanceof Error ? err.message : String(err);
68334
- deps.ctx.logger.warn("contribution method failed", {
68335
- tags: {
68336
- deviceId,
68337
- addonId: entry.providerAddonId
68338
- },
68339
- meta: {
68340
- capName: entry.capName,
68341
- method,
68342
- error: msg
68343
- }
68344
- });
68345
- return null;
68346
- }
68606
+ return await resolveContribution(deps, {
68607
+ deviceId,
68608
+ kind,
68609
+ capName: entry.capName,
68610
+ addonId: entry.providerAddonId,
68611
+ call: async () => {
68612
+ const contribution = await provider[method]({ deviceId });
68613
+ return contribution ? toWireShape(contribution) : null;
68614
+ }
68615
+ });
68347
68616
  }));
68348
68617
  const base = kind === "settings" ? await buildBaseDeviceSection(deps, deviceId) : null;
68349
68618
  const systemResults = await collectSystemDeviceContributions(deps, deviceId, kind, seenCaps);
@@ -68368,24 +68637,16 @@ var require_device_manager_addon = __commonJS({
68368
68637
  for (const addonId of addonIds) tasks.push((async () => {
68369
68638
  const provider = registry.getProviderByAddon(info.name, addonId);
68370
68639
  if (!provider) return null;
68371
- try {
68372
- const contribution = await provider[method]({ deviceId });
68373
- if (!contribution) return null;
68374
- return tagContribution(toWireShape(contribution), info.name, addonId, kind);
68375
- } catch (err) {
68376
- deps.ctx.logger.warn("system device-settings contribution skipped", {
68377
- tags: {
68378
- deviceId,
68379
- addonId
68380
- },
68381
- meta: {
68382
- capName: info.name,
68383
- method,
68384
- error: err instanceof Error ? err.message : String(err)
68385
- }
68386
- });
68387
- return null;
68388
- }
68640
+ return await resolveContribution(deps, {
68641
+ deviceId,
68642
+ kind,
68643
+ capName: info.name,
68644
+ addonId,
68645
+ call: async () => {
68646
+ const contribution = await provider[method]({ deviceId });
68647
+ return contribution ? toWireShape(contribution) : null;
68648
+ }
68649
+ });
68389
68650
  })());
68390
68651
  }
68391
68652
  return (await Promise.all(tasks)).filter((r) => r !== null);
@@ -72056,7 +72317,7 @@ var require_hub_forwarder = __commonJS({
72056
72317
  [Symbol.toStringTag]: { value: "Module" }
72057
72318
  });
72058
72319
  require_chunk_Cek0wNdY();
72059
- var require_dist10 = require_dist_DaSCLJVH();
72320
+ var require_dist10 = require_dist_Dze0l7UM();
72060
72321
  var require_formatter = require_formatter_DqAKDlvN();
72061
72322
  var DEFAULT_OUTBOUND_BUFFER_SIZE = 500;
72062
72323
  var HubForwarderDestination = class {
@@ -72193,7 +72454,7 @@ var require_liveness_monitor_addon = __commonJS({
72193
72454
  "use strict";
72194
72455
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
72195
72456
  require_chunk_Cek0wNdY();
72196
- var require_dist10 = require_dist_DaSCLJVH();
72457
+ var require_dist10 = require_dist_Dze0l7UM();
72197
72458
  var NO_DEVICES = "liveness:no-devices";
72198
72459
  var ALL_OFFLINE = "liveness:all-devices-offline";
72199
72460
  var NO_FOOTAGE_PREFIX = "liveness:no-footage:";
@@ -72389,7 +72650,7 @@ var require_local_auth_addon = __commonJS({
72389
72650
  [Symbol.toStringTag]: { value: "Module" }
72390
72651
  });
72391
72652
  var require_chunk = require_chunk_Cek0wNdY();
72392
- var require_dist10 = require_dist_DaSCLJVH();
72653
+ var require_dist10 = require_dist_Dze0l7UM();
72393
72654
  var node_crypto = __require("crypto");
72394
72655
  node_crypto = require_chunk.__toESM(node_crypto);
72395
72656
  var crypto$1 = __require("crypto");
@@ -80202,7 +80463,7 @@ var require_loki_logging = __commonJS({
80202
80463
  [Symbol.toStringTag]: { value: "Module" }
80203
80464
  });
80204
80465
  require_chunk_Cek0wNdY();
80205
- var require_dist10 = require_dist_DaSCLJVH();
80466
+ var require_dist10 = require_dist_Dze0l7UM();
80206
80467
  function sanitizeLabelName(raw) {
80207
80468
  const replaced = raw.replaceAll(/[^a-zA-Z0-9_]/g, "_");
80208
80469
  return /^[a-zA-Z_]/.test(replaced) ? replaced : `_${replaced}`;
@@ -80789,7 +81050,7 @@ var require_native_metrics_addon = __commonJS({
80789
81050
  [Symbol.toStringTag]: { value: "Module" }
80790
81051
  });
80791
81052
  var require_chunk = require_chunk_Cek0wNdY();
80792
- var require_dist10 = require_dist_DaSCLJVH();
81053
+ var require_dist10 = require_dist_Dze0l7UM();
80793
81054
  var node_fs_promises = __require("fs/promises");
80794
81055
  var node_fs = __require("fs");
80795
81056
  node_fs = require_chunk.__toESM(node_fs);
@@ -83542,7 +83803,7 @@ var require_filesystem_storage_addon = __commonJS({
83542
83803
  [Symbol.toStringTag]: { value: "Module" }
83543
83804
  });
83544
83805
  var require_chunk = require_chunk_Cek0wNdY();
83545
- var require_dist10 = require_dist_DaSCLJVH();
83806
+ var require_dist10 = require_dist_Dze0l7UM();
83546
83807
  var node_crypto = __require("crypto");
83547
83808
  var node_fs_promises = __require("fs/promises");
83548
83809
  var node_path = __require("path");
@@ -84769,8 +85030,8 @@ var require_sqlite_settings_addon = __commonJS({
84769
85030
  [Symbol.toStringTag]: { value: "Module" }
84770
85031
  });
84771
85032
  var require_chunk = require_chunk_Cek0wNdY();
84772
- var require_dist10 = require_dist_DaSCLJVH();
84773
- var require_retired_settings_keys = require_retired_settings_keys_CZISf623();
85033
+ var require_dist10 = require_dist_Dze0l7UM();
85034
+ var require_retired_settings_keys = require_retired_settings_keys_1GWw9mup();
84774
85035
  var require_wal_checkpoint_policy = require_wal_checkpoint_policy_CCJZngds();
84775
85036
  var node_crypto = __require("crypto");
84776
85037
  var node_path = __require("path");
@@ -87557,7 +87818,7 @@ var require_storage_orchestrator_addon = __commonJS({
87557
87818
  [Symbol.toStringTag]: { value: "Module" }
87558
87819
  });
87559
87820
  var require_chunk = require_chunk_Cek0wNdY();
87560
- var require_dist10 = require_dist_DaSCLJVH();
87821
+ var require_dist10 = require_dist_Dze0l7UM();
87561
87822
  var require_hub_cap_forward = require_hub_cap_forward_DmHNjbB0();
87562
87823
  var zod = require_zod();
87563
87824
  var node_crypto = __require("crypto");
@@ -91284,7 +91545,7 @@ var require_system_config_addon = __commonJS({
91284
91545
  [Symbol.toStringTag]: { value: "Module" }
91285
91546
  });
91286
91547
  require_chunk_Cek0wNdY();
91287
- var require_dist10 = require_dist_DaSCLJVH();
91548
+ var require_dist10 = require_dist_Dze0l7UM();
91288
91549
  var SECTION_TITLES = {
91289
91550
  server: "Server",
91290
91551
  auth: "Authentication"
@@ -109345,7 +109606,7 @@ var require_winston_logging = __commonJS({
109345
109606
  [Symbol.toStringTag]: { value: "Module" }
109346
109607
  });
109347
109608
  var require_chunk = require_chunk_Cek0wNdY();
109348
- var require_dist10 = require_dist_DaSCLJVH();
109609
+ var require_dist10 = require_dist_Dze0l7UM();
109349
109610
  var require_formatter = require_formatter_DqAKDlvN();
109350
109611
  var node_path = __require("path");
109351
109612
  node_path = require_chunk.__toESM(node_path);
@@ -111383,9 +111644,9 @@ var require_event_category_BVfsrBYA = __commonJS({
111383
111644
  }
111384
111645
  });
111385
111646
 
111386
- // ../types/dist/sleep-B8nfmQ8a.js
111387
- var require_sleep_B8nfmQ8a = __commonJS({
111388
- "../types/dist/sleep-B8nfmQ8a.js"(exports) {
111647
+ // ../types/dist/sleep-DqtlfkSS.js
111648
+ var require_sleep_DqtlfkSS = __commonJS({
111649
+ "../types/dist/sleep-DqtlfkSS.js"(exports) {
111389
111650
  "use strict";
111390
111651
  var require_event_category = require_event_category_BVfsrBYA();
111391
111652
  var zod = require_zod();
@@ -113463,6 +113724,41 @@ var require_sleep_B8nfmQ8a = __commonJS({
113463
113724
  DeviceRole2["GenericNotifier"] = "generic-notifier";
113464
113725
  return DeviceRole2;
113465
113726
  })({});
113727
+ function defineCustomActions(spec) {
113728
+ return spec;
113729
+ }
113730
+ function customAction(input, output, options) {
113731
+ return {
113732
+ input,
113733
+ output,
113734
+ kind: options?.kind ?? "query",
113735
+ auth: options?.auth ?? "protected",
113736
+ scope: options?.scope ?? { kind: "system" },
113737
+ ...options?.caller ? { caller: "required" } : {}
113738
+ };
113739
+ }
113740
+ function deviceCustomAction(input, output, options) {
113741
+ return {
113742
+ input,
113743
+ output,
113744
+ kind: options?.kind ?? "query",
113745
+ auth: options?.auth ?? "protected",
113746
+ scope: {
113747
+ kind: "device",
113748
+ ...options?.deviceTypes ? { deviceTypes: options.deviceTypes } : {}
113749
+ }
113750
+ };
113751
+ }
113752
+ function describeCustomActions(catalog) {
113753
+ const out = {};
113754
+ for (const [name, spec] of Object.entries(catalog)) out[name] = {
113755
+ kind: spec.kind,
113756
+ auth: spec.auth,
113757
+ scope: spec.scope,
113758
+ ...spec.caller === "required" ? { caller: "required" } : {}
113759
+ };
113760
+ return out;
113761
+ }
113466
113762
  var DEVICE_CHILDREN_BATCH_MAX = 256;
113467
113763
  var StaticDirOutputSchema = zod.z.object({ staticDir: zod.z.string() });
113468
113764
  var VersionOutputSchema = zod.z.object({ version: zod.z.string() });
@@ -114126,6 +114422,7 @@ var require_sleep_B8nfmQ8a = __commonJS({
114126
114422
  updateRule: (input) => dispatch("notification-rules", "notificationRules", "updateRule", "mutation", input),
114127
114423
  deleteRule: (input) => dispatch("notification-rules", "notificationRules", "deleteRule", "mutation", input),
114128
114424
  setRuleEnabled: (input) => dispatch("notification-rules", "notificationRules", "setRuleEnabled", "mutation", input),
114425
+ getClipRetentionAsks: (input) => dispatch("notification-rules", "notificationRules", "getClipRetentionAsks", "query", input),
114129
114426
  listDeviceMutes: (input) => dispatch("notification-rules", "notificationRules", "listDeviceMutes", "query", input),
114130
114427
  setDeviceMuted: (input) => dispatch("notification-rules", "notificationRules", "setDeviceMuted", "mutation", input),
114131
114428
  testRule: (input) => dispatch("notification-rules", "notificationRules", "testRule", "mutation", input),
@@ -114178,6 +114475,7 @@ var require_sleep_B8nfmQ8a = __commonJS({
114178
114475
  getSensorEvents: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getSensorEvents", "query", input),
114179
114476
  getKeyEvents: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getKeyEvents", "query", input),
114180
114477
  getKeyEventsBatch: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getKeyEventsBatch", "query", input),
114478
+ readLongTermSeries: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "readLongTermSeries", "query", input),
114181
114479
  getEventDensity: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getEventDensity", "query", input),
114182
114480
  getEventDensityBatch: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getEventDensityBatch", "query", input),
114183
114481
  pruneEventsBefore: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "pruneEventsBefore", "mutation", input),
@@ -114478,6 +114776,7 @@ var require_sleep_B8nfmQ8a = __commonJS({
114478
114776
  pipelineRunner: {
114479
114777
  detachCamera: (input) => dispatchSystem("pipelineRunner", "detachCamera", "mutation", input),
114480
114778
  getCameraMetrics: (input) => dispatchSystem("pipelineRunner", "getCameraMetrics", "query", input),
114779
+ requestOccupancyBurst: (input) => dispatchSystem("pipelineRunner", "requestOccupancyBurst", "mutation", input),
114481
114780
  runDetailSubtree: (input) => dispatchSystem("pipelineRunner", "runDetailSubtree", "mutation", input),
114482
114781
  parkTrackFrame: (input) => dispatchSystem("pipelineRunner", "parkTrackFrame", "mutation", input),
114483
114782
  getParkedTrackFrame: (input) => dispatchSystem("pipelineRunner", "getParkedTrackFrame", "query", input),
@@ -115030,6 +115329,30 @@ var require_sleep_B8nfmQ8a = __commonJS({
115030
115329
  return createSliceHandle;
115031
115330
  }
115032
115331
  });
115332
+ Object.defineProperty(exports, "customAction", {
115333
+ enumerable: true,
115334
+ get: function() {
115335
+ return customAction;
115336
+ }
115337
+ });
115338
+ Object.defineProperty(exports, "defineCustomActions", {
115339
+ enumerable: true,
115340
+ get: function() {
115341
+ return defineCustomActions;
115342
+ }
115343
+ });
115344
+ Object.defineProperty(exports, "describeCustomActions", {
115345
+ enumerable: true,
115346
+ get: function() {
115347
+ return describeCustomActions;
115348
+ }
115349
+ });
115350
+ Object.defineProperty(exports, "deviceCustomAction", {
115351
+ enumerable: true,
115352
+ get: function() {
115353
+ return deviceCustomAction;
115354
+ }
115355
+ });
115033
115356
  Object.defineProperty(exports, "deviceOpsCapability", {
115034
115357
  enumerable: true,
115035
115358
  get: function() {
@@ -115224,7 +115547,7 @@ var require_addon = __commonJS({
115224
115547
  "../types/dist/addon.js"(exports) {
115225
115548
  "use strict";
115226
115549
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
115227
- var require_sleep = require_sleep_B8nfmQ8a();
115550
+ var require_sleep = require_sleep_DqtlfkSS();
115228
115551
  var require_event_category = require_event_category_BVfsrBYA();
115229
115552
  var require_err_msg = require_err_msg_COpsHMw2();
115230
115553
  var CAP_INPUT_DEFAULTS = Object.freeze({
@@ -115537,6 +115860,7 @@ var require_addon = __commonJS({
115537
115860
  exports.asString = require_sleep.asString;
115538
115861
  exports.createDeviceProxy = require_sleep.createDeviceProxy;
115539
115862
  exports.createEventBusSliceSource = require_sleep.createEventBusSliceSource;
115863
+ exports.describeCustomActions = require_sleep.describeCustomActions;
115540
115864
  exports.deviceOpsCapability = require_sleep.deviceOpsCapability;
115541
115865
  exports.emitReadiness = require_sleep.emitReadiness;
115542
115866
  exports.errMsg = require_err_msg.errMsg;
@@ -122091,9 +122415,9 @@ var require_dist2 = __commonJS({
122091
122415
  }
122092
122416
  });
122093
122417
 
122094
- // ../system/dist/manifest-system-deps-CrSP0Kkp.js
122095
- var require_manifest_system_deps_CrSP0Kkp = __commonJS({
122096
- "../system/dist/manifest-system-deps-CrSP0Kkp.js"(exports) {
122418
+ // ../system/dist/manifest-system-deps-CzyjTMcO.js
122419
+ var require_manifest_system_deps_CzyjTMcO = __commonJS({
122420
+ "../system/dist/manifest-system-deps-CzyjTMcO.js"(exports) {
122097
122421
  "use strict";
122098
122422
  var require_chunk = require_chunk_Cek0wNdY();
122099
122423
  require_hub_cap_forward_DmHNjbB0();
@@ -127198,10 +127522,104 @@ var require_manifest_system_deps_CrSP0Kkp = __commonJS({
127198
127522
  function __resetCapUsageRegistryForTests() {
127199
127523
  singleton = null;
127200
127524
  }
127525
+ var MIRROR_REASON_BY_CATEGORY = new Map([
127526
+ {
127527
+ category: "device.state-changed",
127528
+ reason: "Device runtime-state mirror, 69.1 % of fleet traffic. Each event is a snapshot of the slice AFTER the change; the superseded snapshot describes a state the device is no longer in, and every consumer (SystemMirror, DeviceStateHandle) reads the latest one only."
127529
+ },
127530
+ {
127531
+ category: "camera-streams.onCamStreamsChanged",
127532
+ reason: "Full stream-list snapshot per camera, 20.1 % of fleet traffic. The payload is the complete current list, not a delta, so an older list is strictly less true than the newer one."
127533
+ },
127534
+ {
127535
+ category: "system.ready-state",
127536
+ reason: "Readiness is a LEVEL, not an edge: the event reports whether a capability is ready right now. Declared for the case where it carries a deviceId; when it does not it stays in the global ring like any other unattributed event."
127537
+ }
127538
+ ].map((m) => [m.category, m.reason]));
127539
+ function isMirrorCategory(category) {
127540
+ return MIRROR_REASON_BY_CATEGORY.has(category);
127541
+ }
127542
+ var MAX_DEVICE_RING_EVENTS = 2e3;
127543
+ function serializePayload(data) {
127544
+ try {
127545
+ const json = JSON.stringify(data);
127546
+ if (typeof json !== "string") return null;
127547
+ return {
127548
+ json,
127549
+ bytes: Buffer.byteLength(json, "utf8")
127550
+ };
127551
+ } catch {
127552
+ return null;
127553
+ }
127554
+ }
127555
+ function capEventData(event) {
127556
+ const serialized = serializePayload(event.data);
127557
+ if (serialized !== null && serialized.bytes <= 256) return event;
127558
+ const truncated = {
127559
+ __truncated: true,
127560
+ __originalBytes: serialized?.bytes ?? null,
127561
+ __preview: serialized === null ? "" : serialized.json.slice(0, 160)
127562
+ };
127563
+ return {
127564
+ ...event,
127565
+ data: truncated
127566
+ };
127567
+ }
127568
+ function eventDeviceId(event) {
127569
+ const explicit = event.source.deviceId;
127570
+ if (explicit !== void 0) return Number.isFinite(explicit) ? explicit : void 0;
127571
+ if (event.source.type !== "device") return void 0;
127572
+ const asNumber = Number(event.source.id);
127573
+ return Number.isFinite(asNumber) ? asNumber : void 0;
127574
+ }
127575
+ function createDeviceEventRings() {
127576
+ return { byDevice: /* @__PURE__ */ new Map() };
127577
+ }
127578
+ function ringFor(rings, deviceId) {
127579
+ const existing = rings.byDevice.get(deviceId);
127580
+ if (existing !== void 0) {
127581
+ rings.byDevice.delete(deviceId);
127582
+ rings.byDevice.set(deviceId, existing);
127583
+ return existing;
127584
+ }
127585
+ const created = {
127586
+ history: [],
127587
+ mirrors: /* @__PURE__ */ new Map()
127588
+ };
127589
+ rings.byDevice.set(deviceId, created);
127590
+ while (rings.byDevice.size > 512) {
127591
+ const oldest = rings.byDevice.keys().next();
127592
+ if (oldest.done === true) break;
127593
+ rings.byDevice.delete(oldest.value);
127594
+ }
127595
+ return created;
127596
+ }
127597
+ function recordDeviceEvent(rings, event) {
127598
+ const deviceId = eventDeviceId(event);
127599
+ if (deviceId === void 0) return void 0;
127600
+ const ring = ringFor(rings, deviceId);
127601
+ const retained = capEventData(event);
127602
+ if (isMirrorCategory(event.category)) {
127603
+ ring.mirrors.set(event.category, retained);
127604
+ return deviceId;
127605
+ }
127606
+ ring.history.push(retained);
127607
+ if (ring.history.length > 2e3) ring.history.splice(0, ring.history.length - MAX_DEVICE_RING_EVENTS);
127608
+ return deviceId;
127609
+ }
127610
+ function getDeviceRecent(rings, deviceId) {
127611
+ const ring = rings.byDevice.get(deviceId);
127612
+ if (ring === void 0) return [];
127613
+ if (ring.mirrors.size === 0) return ring.history;
127614
+ const merged = [...ring.history, ...ring.mirrors.values()];
127615
+ merged.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
127616
+ return merged;
127617
+ }
127201
127618
  function createSharedBusState(retainRecent = false) {
127202
127619
  return {
127203
127620
  handlers: /* @__PURE__ */ new Map(),
127204
127621
  recent: [],
127622
+ deviceRings: createDeviceEventRings(),
127205
127623
  retainRecent
127206
127624
  };
127207
127625
  }
@@ -127309,6 +127727,7 @@ var require_manifest_system_deps_CrSP0Kkp = __commonJS({
127309
127727
  if (state.retainRecent && !isHighFrequencyCategory(event.category)) {
127310
127728
  state.recent.push(event);
127311
127729
  if (state.recent.length > 1e3) state.recent.splice(0, state.recent.length - MAX_RECENT_EVENTS);
127730
+ recordDeviceEvent(state.deviceRings, event);
127312
127731
  }
127313
127732
  const delivered = /* @__PURE__ */ new Set();
127314
127733
  for (const [pattern, set] of state.handlers) {
@@ -129703,14 +130122,15 @@ var require_manifest_system_deps_CrSP0Kkp = __commonJS({
129703
130122
  });
129704
130123
  },
129705
130124
  getRecent(filter, limit) {
129706
- const filtered = filter ? state.recent.filter((e) => {
130125
+ const source = filter?.deviceId !== void 0 ? getDeviceRecent(state.deviceRings, filter.deviceId) : state.recent;
130126
+ const filtered = filter ? source.filter((e) => {
129707
130127
  const cat = filter.category;
129708
130128
  if (cat) {
129709
130129
  const categories = typeof cat === "string" ? [cat] : Array.isArray(cat) ? cat : [];
129710
130130
  if (categories.length > 0 && !categories.some((c) => matchesPattern(String(c), e.category))) return false;
129711
130131
  }
129712
130132
  return matchesEventFilter(e, filter);
129713
- }) : state.recent;
130133
+ }) : source;
129714
130134
  return limit !== void 0 ? filtered.slice(-limit) : filtered;
129715
130135
  }
129716
130136
  };
@@ -131635,11 +132055,11 @@ var require_manifest_system_deps_CrSP0Kkp = __commonJS({
131635
132055
  }
131636
132056
  });
131637
132057
 
131638
- // ../system/dist/custom-action-registry-DG-QIWxd.js
131639
- var require_custom_action_registry_DG_QIWxd = __commonJS({
131640
- "../system/dist/custom-action-registry-DG-QIWxd.js"(exports) {
132058
+ // ../system/dist/custom-action-registry-acBY3mHA.js
132059
+ var require_custom_action_registry_acBY3mHA = __commonJS({
132060
+ "../system/dist/custom-action-registry-acBY3mHA.js"(exports) {
131641
132061
  "use strict";
131642
- var require_dist10 = require_dist_DaSCLJVH();
132062
+ var _camstack_types_addon = require_addon();
131643
132063
  var CustomActionRegistry = class {
131644
132064
  byAddon = /* @__PURE__ */ new Map();
131645
132065
  registerAddon(addonId, catalog, handler) {
@@ -131680,7 +132100,7 @@ var require_custom_action_registry_DG_QIWxd = __commonJS({
131680
132100
  for (const [addonId, actions] of this.byAddon) {
131681
132101
  const catalog = {};
131682
132102
  for (const [name, entry] of actions) catalog[name] = entry.spec;
131683
- out[addonId] = require_dist10.describeCustomActions(catalog);
132103
+ out[addonId] = (0, _camstack_types_addon.describeCustomActions)(catalog);
131684
132104
  }
131685
132105
  return out;
131686
132106
  }
@@ -135453,7 +135873,7 @@ var require_dist3 = __commonJS({
135453
135873
  "use strict";
135454
135874
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
135455
135875
  var require_chunk = require_chunk_Cek0wNdY();
135456
- var require_dist10 = require_dist_DaSCLJVH();
135876
+ var require_dist10 = require_dist_Dze0l7UM();
135457
135877
  var require_builtins_alerts_alerts_addon = require_alerts_addon();
135458
135878
  require_alerts();
135459
135879
  var require_formatter = require_formatter_DqAKDlvN();
@@ -135480,9 +135900,9 @@ var require_dist3 = __commonJS({
135480
135900
  var require_builtins_winston_logging_index = require_winston_logging();
135481
135901
  var require_event_loop_stall_monitor = require_event_loop_stall_monitor_CAsHdMwP();
135482
135902
  var require_tls$1 = require_tls_BFs4PzoW();
135483
- var require_manifest_system_deps = require_manifest_system_deps_CrSP0Kkp();
135903
+ var require_manifest_system_deps = require_manifest_system_deps_CzyjTMcO();
135484
135904
  var require_resource_monitor = require_resource_monitor_LVE1BoLs();
135485
- var require_custom_action_registry = require_custom_action_registry_DG_QIWxd();
135905
+ var require_custom_action_registry = require_custom_action_registry_acBY3mHA();
135486
135906
  var zod = require_zod();
135487
135907
  var node_crypto = __require("crypto");
135488
135908
  var _camstack_types_node = require_node();
@@ -216591,7 +217011,7 @@ var require_dist4 = __commonJS({
216591
217011
  "../types/dist/index.js"(exports) {
216592
217012
  "use strict";
216593
217013
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
216594
- var require_sleep = require_sleep_B8nfmQ8a();
217014
+ var require_sleep = require_sleep_DqtlfkSS();
216595
217015
  var require_event_category = require_event_category_BVfsrBYA();
216596
217016
  var require_canonical_hash = require_canonical_hash_9lydiEzx();
216597
217017
  var require_enums2 = require_enums();
@@ -219401,6 +219821,49 @@ var require_dist4 = __commonJS({
219401
219821
  pixels: entry.resolution.width * entry.resolution.height
219402
219822
  }])].sort((a, b) => compareToTarget(a.pixels, b.pixels, targetPixels))[0]?.entry;
219403
219823
  }
219824
+ var OVERLAY_LAYERS = [
219825
+ "motion",
219826
+ "objects",
219827
+ "discarded",
219828
+ "stationary"
219829
+ ];
219830
+ var DEFAULT_OVERLAY_LAYERS = [
219831
+ "motion",
219832
+ "objects",
219833
+ "stationary"
219834
+ ];
219835
+ var STATIONARY_OVERLAY_STYLE = {
219836
+ /** Border width in px, at the surface's own scale. */
219837
+ borderWidth: 2,
219838
+ /** Dashed, not solid — the census is not a live detection. */
219839
+ dashed: true,
219840
+ /** Dash on/off lengths in px, for a renderer that needs them explicitly
219841
+ * (React Native cannot express `border-dashed` without them). */
219842
+ dashPattern: [6, 4],
219843
+ /**
219844
+ * FULL opacity, deliberately.
219845
+ *
219846
+ * This was 0.7, to make a parked car quieter than a live subject. It made it
219847
+ * quieter by lying about its colour: a class hue at 70% over a dark frame
219848
+ * reads as a different hue, and the operator saw the census boxes as the
219849
+ * wrong colour — which they effectively were.
219850
+ *
219851
+ * The dash already says "censused", and it says it without touching the
219852
+ * hue. Two signals for one fact was one too many, and the one that had to go
219853
+ * is the one that corrupts a value the rest of the system agrees on: the
219854
+ * class colour comes from `EVENT_TAXONOMY` and must reach the screen intact
219855
+ * on every surface, or the palette is shared in name only.
219856
+ */
219857
+ opacity: 1,
219858
+ /** Corner radius in px. */
219859
+ borderRadius: 2
219860
+ };
219861
+ function formatParkedFor(ms) {
219862
+ if (!Number.isFinite(ms) || ms <= 0) return "0 s";
219863
+ if (ms < 6e4) return `${String(Math.round(ms / 1e3))} s`;
219864
+ if (ms < 36e5) return `${String(Math.round(ms / 6e4))} min`;
219865
+ return `${String(Math.round(ms / 36e5))} h`;
219866
+ }
219404
219867
  var FORMAT_KEYS = [
219405
219868
  "onnx",
219406
219869
  "coreml",
@@ -222285,6 +222748,21 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
222285
222748
  mode: "singleton",
222286
222749
  deviceTypes: Object.values(require_sleep.DeviceType),
222287
222750
  runtimeState: StreamSignalsStatusSchema,
222751
+ /**
222752
+ * Runtime-state durability: **session** — mirrored in RAM, never written.
222753
+ *
222754
+ * The slice holds what the DEVICE says it can emit. That is a probed fact,
222755
+ * not an operator choice: the provider re-declares it on every registration,
222756
+ * so losing it loses nothing and persisting it would freeze an answer the
222757
+ * camera is entitled to change. Measured the same day on the sibling case —
222758
+ * `native-object-detection.supportedClasses` was persisted, and a firmware
222759
+ * class the camera really detected stayed missing for the life of the row
222760
+ * because the fix could not reach it.
222761
+ *
222762
+ * See `RuntimeStateDurability`. Enforced by
222763
+ * `scripts/check-runtime-state-durability.ts`.
222764
+ */
222765
+ durability: "session",
222288
222766
  methods: {
222289
222767
  /**
222290
222768
  * What this device can emit. Empty is a valid and common answer — most
@@ -223549,41 +224027,6 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
223549
224027
  })) }), { auth: "admin" })
223550
224028
  }
223551
224029
  };
223552
- function defineCustomActions(spec) {
223553
- return spec;
223554
- }
223555
- function customAction(input, output, options) {
223556
- return {
223557
- input,
223558
- output,
223559
- kind: options?.kind ?? "query",
223560
- auth: options?.auth ?? "protected",
223561
- scope: options?.scope ?? { kind: "system" },
223562
- ...options?.caller ? { caller: "required" } : {}
223563
- };
223564
- }
223565
- function deviceCustomAction(input, output, options) {
223566
- return {
223567
- input,
223568
- output,
223569
- kind: options?.kind ?? "query",
223570
- auth: options?.auth ?? "protected",
223571
- scope: {
223572
- kind: "device",
223573
- ...options?.deviceTypes ? { deviceTypes: options.deviceTypes } : {}
223574
- }
223575
- };
223576
- }
223577
- function describeCustomActions(catalog) {
223578
- const out = {};
223579
- for (const [name, spec] of Object.entries(catalog)) out[name] = {
223580
- kind: spec.kind,
223581
- auth: spec.auth,
223582
- scope: spec.scope,
223583
- ...spec.caller === "required" ? { caller: "required" } : {}
223584
- };
223585
- return out;
223586
- }
223587
224030
  var CustomModelDescriptorSchema = zod.z.object({
223588
224031
  stepId: zod.z.string(),
223589
224032
  entry: ModelCatalogEntrySchema
@@ -230105,6 +230548,30 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
230105
230548
  settings: NcAlarmSettingsSchema,
230106
230549
  coverage: zod.z.array(NcAlarmModeCoverageSchema)
230107
230550
  });
230551
+ var NC_CLIP_RETENTION_MAX_SEC = 60;
230552
+ var NcClipRetentionAskSchema = zod.z.object({
230553
+ /**
230554
+ * The camera this ask is about. **Absent = every camera**, which is what a
230555
+ * rule with no `conditions.devices` means: it can fire anywhere, so it is
230556
+ * asking everywhere.
230557
+ */
230558
+ deviceId: zod.z.number().int().nonnegative().optional(),
230559
+ /** Seconds of history the rule needs held for it. Never zero — a rule that
230560
+ * needs nothing produces no ask at all. */
230561
+ seconds: zod.z.number().min(0).max(60),
230562
+ /** The profile the rule cuts from, when it named one. Absent = the cheapest
230563
+ * assigned, which is what the cut defaults to. */
230564
+ profile: require_sleep.CamProfileSchema.optional(),
230565
+ /** Who is asking — so a retention the operator did not expect names a rule. */
230566
+ ruleId: zod.z.string(),
230567
+ ruleName: zod.z.string(),
230568
+ /** Why this many seconds: the rule's own window, or the occupancy ceiling. */
230569
+ reason: zod.z.enum(["window", "occupancy"])
230570
+ });
230571
+ var NcClipRetentionPlanSchema = zod.z.object({
230572
+ rulesLoaded: zod.z.boolean(),
230573
+ asks: zod.z.array(NcClipRetentionAskSchema).readonly()
230574
+ });
230108
230575
  var notificationRulesCapability = {
230109
230576
  name: "notification-rules",
230110
230577
  scope: "system",
@@ -230137,6 +230604,23 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
230137
230604
  auth: "admin"
230138
230605
  }),
230139
230606
  /**
230607
+ * WHAT THE RULES ACTUALLY ASK the stream broker to retain, per camera.
230608
+ *
230609
+ * The notification centre owns the rules, so it is the only thing that can
230610
+ * say how much history a camera's notifications will ever reach back for.
230611
+ * Before this the broker guessed — a flat minute on every camera — and
230612
+ * learned the PROFILE reactively, after the first clip had already been cut
230613
+ * from the wrong one. This is the same ask stated once, in front.
230614
+ *
230615
+ * A QUERY, pulled by each node's broker, not a push: brokers are per node
230616
+ * (a camera's ring lives wherever its stream is ingested) while this cap is
230617
+ * a singleton, so a push would have to enumerate the cluster. The pull also
230618
+ * makes the failure mode right — a broker that cannot reach the centre
230619
+ * keeps the plan it has, and a plan that has never arrived is UNKNOWN
230620
+ * rather than empty (D49: a read that fails changes nothing).
230621
+ */
230622
+ getClipRetentionAsks: require_sleep.method(zod.z.object({}), NcClipRetentionPlanSchema, { auth: "admin" }),
230623
+ /**
230140
230624
  * PERMANENT per-camera mute — the notifications half of the per-camera
230141
230625
  * function switch group ([D61](../../../../docs/decisions/adr-0067.md)).
230142
230626
  *
@@ -232350,6 +232834,33 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
232350
232834
  framesMatched: zod.z.number().int()
232351
232835
  });
232352
232836
  var RunReplayFrameProcessorResultSchema = zod.z.object({ tracks: zod.z.array(ReplayTrackSchema).readonly() });
232837
+ var AnalyticsLtsSeriesSchema = zod.z.enum([
232838
+ "motion",
232839
+ "audio-dbfs",
232840
+ "battery",
232841
+ "occupancy"
232842
+ ]);
232843
+ var LTS_SCOPE_CLASS_SEPARATOR = "|";
232844
+ function occupancyScope(zoneId, className) {
232845
+ const place = zoneId ?? "";
232846
+ return className === void 0 ? place : `${place}|${className}`;
232847
+ }
232848
+ function parseOccupancyScope(scope) {
232849
+ const at = scope.indexOf("|");
232850
+ if (at < 0) return { zoneId: scope };
232851
+ return {
232852
+ zoneId: scope.slice(0, at),
232853
+ className: scope.slice(at + 1)
232854
+ };
232855
+ }
232856
+ var LtsBucketSchema = zod.z.object({
232857
+ scope: zod.z.string(),
232858
+ bucketStart: zod.z.number().int(),
232859
+ samples: zod.z.number().int().nonnegative(),
232860
+ sum: zod.z.number(),
232861
+ min: zod.z.number(),
232862
+ max: zod.z.number()
232863
+ });
232353
232864
  var pipelineAnalyticsCapability = {
232354
232865
  name: "pipeline-analytics",
232355
232866
  scope: "device",
@@ -232493,6 +233004,30 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
232493
233004
  getKeyEventsBatch: require_sleep.method(KeyEventBatchQueryInput, zod.z.array(KeyEventsForDeviceSchema).readonly()),
232494
233005
  /** Server-side bucketed event counts for the 24-hour timeline.
232495
233006
  * Returns one entry per non-empty bucket; empty buckets are omitted. */
233007
+ /**
233008
+ * Read one camera's long-term series — 5-minute buckets, kept for a year.
233009
+ *
233010
+ * This is the history surface for every chart that used to be served from a
233011
+ * RAM ring: the ring dies with the process, cannot answer about last night,
233012
+ * and had a 60-minute horizon, while these rows are ~60 bytes and already
233013
+ * written. `scope` is the series' own dimension — for `occupancy`, spell it
233014
+ * with {@link occupancyScope} rather than by hand, and omit it to get every
233015
+ * scope back at once (the caller then groups with
233016
+ * {@link parseOccupancyScope}).
233017
+ *
233018
+ * Bounds are inclusive on the BUCKET START, so a range that ends mid-bucket
233019
+ * still returns the bucket it lands in — the alternative is a chart whose
233020
+ * last column silently disappears for five minutes out of every five.
233021
+ */
233022
+ readLongTermSeries: require_sleep.method(zod.z.object({
233023
+ deviceId: zod.z.number(),
233024
+ series: AnalyticsLtsSeriesSchema,
233025
+ /** Omit for EVERY scope of this series in the range. */
233026
+ scope: zod.z.string().optional(),
233027
+ from: zod.z.number(),
233028
+ to: zod.z.number(),
233029
+ limit: zod.z.number().int().positive().optional()
233030
+ }), zod.z.array(LtsBucketSchema).readonly()),
232496
233031
  getEventDensity: require_sleep.method(zod.z.object({
232497
233032
  deviceId: zod.z.number(),
232498
233033
  since: zod.z.number(),
@@ -233995,6 +234530,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
233995
234530
  queueDepth: zod.z.number(),
233996
234531
  frameLazy: FrameLazyMetricsSchema.optional()
233997
234532
  });
234533
+ var OccupancyBurstRefusalSchema = zod.z.enum([
234534
+ "not-attached",
234535
+ "battery-asleep",
234536
+ "not-watching",
234537
+ "already-bursting"
234538
+ ]);
233998
234539
  var pipelineRunnerCapability = {
233999
234540
  name: "pipeline-runner",
234000
234541
  scope: "system",
@@ -234031,6 +234572,50 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
234031
234572
  /** List the deviceIds currently attached to this runner. */
234032
234573
  getLocalCameras: require_sleep.method(zod.z.void(), zod.z.array(zod.z.number()).readonly()),
234033
234574
  /**
234575
+ * Look at a camera NOW, out of band, because something just happened that
234576
+ * only a fresh look can settle.
234577
+ *
234578
+ * The periodic recheck (`occupancyRecheckSec`, 300 s) exists to watch a
234579
+ * still scene. It is the wrong instrument for a QUESTION that has just been
234580
+ * asked: on device 617 a parked car's departure was observed, a departure
234581
+ * strike was armed — and then the motion session ended, the strike decayed
234582
+ * after its 30 s TTL, and the next periodic look arrived up to five minutes
234583
+ * later with nothing left to confirm. Every one of those departures was
234584
+ * settled by the entry ageing out 6 to 10 minutes of observed time later,
234585
+ * and the notification's clip showed an empty space with nothing leaving
234586
+ * it.
234587
+ *
234588
+ * Two numbers make the ask specific, and a caller that ignores them wastes
234589
+ * the burst: a confirmation must land at least
234590
+ * `DEPARTURE_CONFIRM_MIN_GAP_MS` (3 s) after the read that armed the
234591
+ * strike — before that it is the same optical event and is refused — and
234592
+ * `DEPARTURE_ABSENCE_MIN_READS` (5) consecutive unassociated frames are
234593
+ * needed, while `occupancyRecheckFrames` defaults to FOUR. A burst of four
234594
+ * can never confirm an absence; that is why two periodic looks were always
234595
+ * required.
234596
+ *
234597
+ * The runner answers whether it actually started one. A refusal is NAMED,
234598
+ * never a silent `false`: a camera that is asleep on battery (D173 — this
234599
+ * must not become a self-initiated wake), detached, mid-session or already
234600
+ * bursting are four different facts, and a caller told only "no" cannot
234601
+ * tell a protection from a bug.
234602
+ */
234603
+ requestOccupancyBurst: require_sleep.method(zod.z.object({
234604
+ deviceId: zod.z.number(),
234605
+ /** How many frames to collect. The caller sizes this against what its
234606
+ * own confirmation needs; the runner clamps it to the field's range. */
234607
+ frames: zod.z.number().int().positive().optional(),
234608
+ /** Why, for the log. A burst nobody can attribute is a cost nobody can
234609
+ * defend — the periodic one at least has a timer to point at. */
234610
+ reason: zod.z.string()
234611
+ }), zod.z.object({
234612
+ started: zod.z.boolean(),
234613
+ refusedBecause: OccupancyBurstRefusalSchema.optional()
234614
+ }), {
234615
+ auth: "admin",
234616
+ kind: "mutation"
234617
+ }),
234618
+ /**
234034
234619
  * Best-effort NATIVE-resolution crop of a retention-ring frame. Given the
234035
234620
  * `FrameHandle` that rode an inference-result event and a normalized `bbox`,
234036
234621
  * the runner asks the decode worker still holding that frame's NATIVE
@@ -245972,7 +246557,28 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
245972
246557
  /** Total tracked objects in this scope (frame / zone / unzoned). */
245973
246558
  totalObjects: zod.z.number().int().nonnegative(),
245974
246559
  /** Per-class count. Keys are macro class names (e.g. `person`, `car`). */
245975
- byClass: zod.z.record(zod.z.string(), zod.z.number().int().nonnegative())
246560
+ byClass: zod.z.record(zod.z.string(), zod.z.number().int().nonnegative()),
246561
+ /**
246562
+ * Of `totalObjects`, how many are STANDING — objects the census holds,
246563
+ * present but not going anywhere (a parked car, a bin, a statue).
246564
+ *
246565
+ * The operator's question about a scene has two halves and they answer
246566
+ * different things: "what is parked here" is stable for hours and must not
246567
+ * flap, while "who is walking through" is the thing an alert is about. One
246568
+ * number could only serve one of them, and `totalObjects` served the first
246569
+ * badly — a passer-by moved it and every occupancy rule saw a change.
246570
+ *
246571
+ * `standing + transient === totalObjects`, always. The total keeps its old
246572
+ * meaning exactly, so no rule written against it changes behaviour.
246573
+ *
246574
+ * ABSENT means UNKNOWN, never zero (D393): a snapshot from a node older than
246575
+ * this field cannot say, and a reader that folds absence in as 0 reports "no
246576
+ * parked objects here" about a camera whose lot is full.
246577
+ */
246578
+ standingObjects: zod.z.number().int().nonnegative().optional(),
246579
+ /** Of `totalObjects`, how many are passing through. See `standingObjects` —
246580
+ * same absence rule. */
246581
+ transientObjects: zod.z.number().int().nonnegative().optional()
245976
246582
  });
245977
246583
  var ZoneScopeBreakdownSchema = PerScopeBreakdownSchema.extend({
245978
246584
  zoneId: zod.z.string(),
@@ -253249,6 +253855,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
253249
253855
  addonId: null,
253250
253856
  access: "view"
253251
253857
  },
253858
+ "notificationRules.getClipRetentionAsks": {
253859
+ capName: "notification-rules",
253860
+ capScope: "system",
253861
+ addonId: null,
253862
+ access: "view"
253863
+ },
253252
253864
  "notificationRules.getConditionCatalog": {
253253
253865
  capName: "notification-rules",
253254
253866
  capScope: "system",
@@ -253759,6 +254371,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
253759
254371
  addonId: null,
253760
254372
  access: "create"
253761
254373
  },
254374
+ "pipelineAnalytics.readLongTermSeries": {
254375
+ capName: "pipeline-analytics",
254376
+ capScope: "device",
254377
+ addonId: null,
254378
+ access: "view"
254379
+ },
253762
254380
  "pipelineAnalytics.rebuildObjectEmbeddings": {
253763
254381
  capName: "pipeline-analytics",
253764
254382
  capScope: "device",
@@ -254431,6 +255049,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
254431
255049
  addonId: null,
254432
255050
  access: "create"
254433
255051
  },
255052
+ "pipelineRunner.requestOccupancyBurst": {
255053
+ capName: "pipeline-runner",
255054
+ capScope: "system",
255055
+ addonId: null,
255056
+ access: "create"
255057
+ },
254434
255058
  "pipelineRunner.runDetailSubtree": {
254435
255059
  capName: "pipeline-runner",
254436
255060
  capScope: "system",
@@ -257841,6 +258465,11 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
257841
258465
  form: "single",
257842
258466
  optional: false
257843
258467
  }],
258468
+ "pipelineAnalytics.readLongTermSeries": [{
258469
+ name: "deviceId",
258470
+ form: "single",
258471
+ optional: false
258472
+ }],
257844
258473
  "pipelineAnalytics.rebuildObjectEmbeddings": [{
257845
258474
  name: "deviceId",
257846
258475
  form: "single",
@@ -258031,6 +258660,11 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
258031
258660
  form: "single",
258032
258661
  optional: false
258033
258662
  }],
258663
+ "pipelineRunner.requestOccupancyBurst": [{
258664
+ name: "deviceId",
258665
+ form: "single",
258666
+ optional: false
258667
+ }],
258034
258668
  "pipelineRunner.runDetailSubtree": [{
258035
258669
  name: "deviceId",
258036
258670
  form: "single",
@@ -258714,6 +259348,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
258714
259348
  "pipelineRunner.parkTrackFrame",
258715
259349
  "pipelineRunner.releaseParkedTrackFrames",
258716
259350
  "pipelineRunner.reportMotion",
259351
+ "pipelineRunner.requestOccupancyBurst",
258717
259352
  "pipelineRunner.runDetailSubtree",
258718
259353
  "pipelineRunner.runStatelessStep",
258719
259354
  "plateGallery.getPlateByTrack",
@@ -262522,6 +263157,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
262522
263157
  exports.AlertSourceSchema = AlertSourceSchema;
262523
263158
  exports.AlertStatusSchema = AlertStatusSchema;
262524
263159
  exports.AmbientLightSensorStatusSchema = AmbientLightSensorStatusSchema;
263160
+ exports.AnalyticsLtsSeriesSchema = AnalyticsLtsSeriesSchema;
262525
263161
  exports.ApiKeyRecordSchema = ApiKeyRecordSchema;
262526
263162
  exports.ApiKeySummarySchema = ApiKeySummarySchema;
262527
263163
  exports.ArchiveEntrySchema = ArchiveEntrySchema;
@@ -262716,6 +263352,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
262716
263352
  exports.DEFAULT_FIRST_SIGHTING_FRESHNESS_MS = DEFAULT_FIRST_SIGHTING_FRESHNESS_MS;
262717
263353
  exports.DEFAULT_MIN_LANDMARK_FACE_SIZE_PX = DEFAULT_MIN_LANDMARK_FACE_SIZE_PX;
262718
263354
  exports.DEFAULT_NATIVE_LEASE_SETTINGS = DEFAULT_NATIVE_LEASE_SETTINGS;
263355
+ exports.DEFAULT_OVERLAY_LAYERS = DEFAULT_OVERLAY_LAYERS;
262719
263356
  exports.DEFAULT_POOL_MEMORY_POLICY = DEFAULT_POOL_MEMORY_POLICY;
262720
263357
  exports.DEFAULT_RECORDING_PROFILES = DEFAULT_RECORDING_PROFILES;
262721
263358
  exports.DEFAULT_RETENTION = DEFAULT_RETENTION;
@@ -262899,6 +263536,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
262899
263536
  exports.LOAD_CONTRIBUTION_ROLES = LOAD_CONTRIBUTION_ROLES;
262900
263537
  exports.LOG_CHANNEL_TICK_MS = LOG_CHANNEL_TICK_MS;
262901
263538
  exports.LOG_LEVEL_RANK = LOG_LEVEL_RANK;
263539
+ exports.LTS_SCOPE_CLASS_SEPARATOR = LTS_SCOPE_CLASS_SEPARATOR;
262902
263540
  exports.LabelAttributionSchema = LabelAttributionSchema;
262903
263541
  exports.LabelDefinitionSchema = LabelDefinitionSchema;
262904
263542
  exports.LabelTierSchema = LabelTierSchema;
@@ -262959,6 +263597,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
262959
263597
  exports.LoggingSettingsStateSchema = LoggingSettingsStateSchema;
262960
263598
  exports.LoginMethodContributionSchema = LoginMethodContributionSchema;
262961
263599
  exports.LoginStageEnum = LoginStageEnum;
263600
+ exports.LtsBucketSchema = LtsBucketSchema;
262962
263601
  exports.MACRO_LABELS = MACRO_LABELS;
262963
263602
  exports.MAX_ARCHIVED_DEBUG_NOTES = MAX_ARCHIVED_DEBUG_NOTES;
262964
263603
  exports.MAX_BIRTH_DECISION_RECORDS = MAX_BIRTH_DECISION_RECORDS;
@@ -263072,6 +263711,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
263072
263711
  exports.NC_AUDIO_SEED = NC_AUDIO_SEED;
263073
263712
  exports.NC_AUTHORABLE_SYSTEM_EVENT_KINDS = NC_AUTHORABLE_SYSTEM_EVENT_KINDS;
263074
263713
  exports.NC_BASE_CONDITION_KEYS = NC_BASE_CONDITION_KEYS;
263714
+ exports.NC_CLIP_RETENTION_MAX_SEC = NC_CLIP_RETENTION_MAX_SEC;
263075
263715
  exports.NC_CONDITION_CATALOG = NC_CONDITION_CATALOG;
263076
263716
  exports.NC_CONFIRM_DEFAULT_MAX_IMAGE_PX = NC_CONFIRM_DEFAULT_MAX_IMAGE_PX;
263077
263717
  exports.NC_CONFIRM_DEFAULT_TIMEOUT_MS = NC_CONFIRM_DEFAULT_TIMEOUT_MS;
@@ -263120,6 +263760,8 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
263120
263760
  exports.NcAlarmSkipReasonSchema = NcAlarmSkipReasonSchema;
263121
263761
  exports.NcAlarmSkippedDeviceSchema = NcAlarmSkippedDeviceSchema;
263122
263762
  exports.NcAudioConditionSchema = NcAudioConditionSchema;
263763
+ exports.NcClipRetentionAskSchema = NcClipRetentionAskSchema;
263764
+ exports.NcClipRetentionPlanSchema = NcClipRetentionPlanSchema;
263123
263765
  exports.NcConditionDescriptorSchema = NcConditionDescriptorSchema;
263124
263766
  exports.NcConditionsSchema = NcConditionsSchema;
263125
263767
  exports.NcConfirmExpectSchema = NcConfirmExpectSchema;
@@ -263173,8 +263815,10 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
263173
263815
  exports.OPS_LOG_DEFAULT_LIMIT = OPS_LOG_DEFAULT_LIMIT;
263174
263816
  exports.OPS_LOG_RING_DEFAULT_MAX = OPS_LOG_RING_DEFAULT_MAX;
263175
263817
  exports.OVERFLOW_REASON = OVERFLOW_REASON;
263818
+ exports.OVERLAY_LAYERS = OVERLAY_LAYERS;
263176
263819
  exports.OauthIntegrationDescriptorSchema = OauthIntegrationDescriptorSchema;
263177
263820
  exports.ObjectEventSchema = ObjectEventSchema;
263821
+ exports.OccupancyBurstRefusalSchema = OccupancyBurstRefusalSchema;
263178
263822
  exports.OpsLogDomainSchema = OpsLogDomainSchema;
263179
263823
  exports.OpsLogEntrySchema = OpsLogEntrySchema;
263180
263824
  exports.OpsLogOpSchema = OpsLogOpSchema;
@@ -263358,6 +264002,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
263358
264002
  exports.SOURCE_CAP_CHANGED_AT_FIELD = SOURCE_CAP_CHANGED_AT_FIELD;
263359
264003
  exports.SOURCE_DEVICE_TYPES = SOURCE_DEVICE_TYPES;
263360
264004
  exports.SOURCE_INFO_METADATA_KEY = SOURCE_INFO_METADATA_KEY;
264005
+ exports.STATIONARY_OVERLAY_STYLE = STATIONARY_OVERLAY_STYLE;
263361
264006
  exports.STORAGE_ACCESS_FALLBACK = STORAGE_ACCESS_FALLBACK;
263362
264007
  exports.STORAGE_BYTES_PER_GB = STORAGE_BYTES_PER_GB;
263363
264008
  exports.STORAGE_LOCATION_MODES = STORAGE_LOCATION_MODES;
@@ -263690,7 +264335,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
263690
264335
  exports.createRuntimeStateBridge = createRuntimeStateBridge;
263691
264336
  exports.createSliceHandle = require_sleep.createSliceHandle;
263692
264337
  exports.createSystemProxy = createSystemProxy;
263693
- exports.customAction = customAction;
264338
+ exports.customAction = require_sleep.customAction;
263694
264339
  exports.customModelRegistryCapability = customModelRegistryCapability;
263695
264340
  exports.dataStoreProviderCapability = dataStoreProviderCapability;
263696
264341
  exports.dayNightCapability = dayNightCapability;
@@ -263700,18 +264345,18 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
263700
264345
  exports.decoderCapability = decoderCapability;
263701
264346
  exports.defaultDeliveryForSection = defaultDeliveryForSection;
263702
264347
  exports.defaultDeviceFor = defaultDeviceFor;
263703
- exports.defineCustomActions = defineCustomActions;
264348
+ exports.defineCustomActions = require_sleep.defineCustomActions;
263704
264349
  exports.deriveBatteryPresence = deriveBatteryPresence;
263705
264350
  exports.deriveCameraSwitches = deriveCameraSwitches;
263706
264351
  exports.deriveDetailCropRect = deriveDetailCropRect;
263707
264352
  exports.deriveRecordingMode = deriveRecordingMode;
263708
- exports.describeCustomActions = describeCustomActions;
264353
+ exports.describeCustomActions = require_sleep.describeCustomActions;
263709
264354
  exports.describeModelVariant = describeModelVariant;
263710
264355
  exports.detectAccessRole = detectAccessRole;
263711
264356
  exports.detectionPipelineCapability = detectionPipelineCapability;
263712
264357
  exports.deviceAdoptionCapability = deviceAdoptionCapability;
263713
264358
  exports.deviceBackendToFormat = deviceBackendToFormat;
263714
- exports.deviceCustomAction = deviceCustomAction;
264359
+ exports.deviceCustomAction = require_sleep.deviceCustomAction;
263715
264360
  exports.deviceDiscoveryCapability = deviceDiscoveryCapability;
263716
264361
  exports.deviceExportCapability = deviceExportCapability;
263717
264362
  exports.deviceManagerCapability = deviceManagerCapability;
@@ -263761,6 +264406,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
263761
264406
  exports.formatForBackend = formatForBackend;
263762
264407
  exports.formatForRuntime = formatForRuntime;
263763
264408
  exports.formatMediaOwnerKey = formatMediaOwnerKey;
264409
+ exports.formatParkedFor = formatParkedFor;
263764
264410
  exports.gasCapability = gasCapability;
263765
264411
  exports.gbToBytes = gbToBytes;
263766
264412
  exports.generateAutomationBlock = generateAutomationBlock;
@@ -263877,6 +264523,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
263877
264523
  exports.numericSensorCapability = numericSensorCapability;
263878
264524
  exports.oauthIntegrationCapability = oauthIntegrationCapability;
263879
264525
  exports.objectInputDeclaresAddonId = objectInputDeclaresAddonId;
264526
+ exports.occupancyScope = occupancyScope;
263880
264527
  exports.osdCapability = osdCapability;
263881
264528
  exports.osdManagerCapability = osdManagerCapability;
263882
264529
  exports.overlayClusterStepSettings = overlayClusterStepSettings;
@@ -263886,6 +264533,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
263886
264533
  exports.parseJsonObject = require_sleep.parseJsonObject;
263887
264534
  exports.parseJsonUnknown = require_sleep.parseJsonUnknown;
263888
264535
  exports.parseMediaOwnerKey = parseMediaOwnerKey;
264536
+ exports.parseOccupancyScope = parseOccupancyScope;
263889
264537
  exports.parseProcStatus = parseProcStatus;
263890
264538
  exports.parseProfileBrokerId = require_sleep.parseProfileBrokerId;
263891
264539
  exports.parseRuleSection = parseRuleSection;