@camstack/addon-agent-ui 1.2.154 → 1.2.156

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/addon.js +274 -206
  2. package/package.json +1 -1
package/dist/addon.js CHANGED
@@ -5371,7 +5371,7 @@ var ZodIssueCode = {
5371
5371
  var ZodFirstPartyTypeKind;
5372
5372
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5373
5373
  //#endregion
5374
- //#region ../types/dist/sleep-jkRQgtSc.mjs
5374
+ //#region ../types/dist/sleep-C-v96WpE.mjs
5375
5375
  /**
5376
5376
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5377
5377
  * window to float samples (D455).
@@ -6927,6 +6927,10 @@ var ProfileRtspEntrySchema = object({
6927
6927
  codec: string().optional(),
6928
6928
  resolution: CamStreamResolutionSchema.optional()
6929
6929
  });
6930
+ object({
6931
+ field: string().min(1),
6932
+ on: literal("advance")
6933
+ });
6930
6934
  /**
6931
6935
  * Output schema shared by the contribution + live methods.
6932
6936
  *
@@ -7414,7 +7418,43 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
7414
7418
  return DeviceRole;
7415
7419
  }({});
7416
7420
  //#endregion
7417
- //#region ../types/dist/composition-CPFIlFfw.mjs
7421
+ //#region ../types/dist/composition-BK-GTFYb.mjs
7422
+ /**
7423
+ * LA tabella "quale booleano di questo tipo di device conta come ALTO", e il
7424
+ * valutatore puro del suo FRONTE.
7425
+ *
7426
+ * Viveva dentro il builtin virtual-doorbell
7427
+ * (`@camstack/system` — `builtins/doorbell/trigger-engine.ts`) e i suoi
7428
+ * predicati erano privati al modulo. Il recorder ne ha bisogno per il trigger
7429
+ * `RecordingTriggers.sensorDeviceIds`: copiarla avrebbe creato la SECONDA
7430
+ * tabella, che diverge alla prima cap aggiunta e il cui sintomo — "il sensore
7431
+ * fa suonare il campanello ma non registra" — è esattamente D62. Quindi si
7432
+ * SPOSTA qui e il doorbell la ri-esporta.
7433
+ *
7434
+ * ⚠ NON è `DEVICE_STATE_READERS` (`catalogs/device-state-vocabulary.ts`), e le
7435
+ * due non vanno unificate: quella risponde a "qual è la PAROLA di stato per una
7436
+ * regola" (e include `presence`, `cover`, `alarm-panel`), questa a "qual è il
7437
+ * booleano il cui FRONTE conta". Vocabolari deliberatamente diversi.
7438
+ */
7439
+ /**
7440
+ * Known binary / switch source caps → the boolean slice field whose
7441
+ * false→true rise counts as ACTIVE. Every entry is "fire on active".
7442
+ * Sensors whose "active" reading is not a plain boolean (presence's string
7443
+ * state, connectivity's connected flag) are deliberately excluded — a
7444
+ * reconnect is not a doorbell press, and it is not a recording either.
7445
+ */
7446
+ var SOURCE_CAP_ACTIVE_FIELD = {
7447
+ contact: "entryOpen",
7448
+ binary: "on",
7449
+ switch: "on",
7450
+ motion: "detected",
7451
+ flood: "flooded",
7452
+ gas: "detected",
7453
+ smoke: "detected",
7454
+ "carbon-monoxide": "detected",
7455
+ vibration: "detected",
7456
+ tamper: "tampered"
7457
+ };
7418
7458
  /**
7419
7459
  * Error types for the safe expression engine. Two distinct classes so callers
7420
7460
  * can tell a compile-time (grammar) failure from a runtime (evaluation)
@@ -7612,6 +7652,20 @@ var table = {
7612
7652
  const present = args.flatMap((a, i) => a === null ? [] : [asFiniteNumber(a, "latest", i)]);
7613
7653
  return present.length === 0 ? null : finiteResult(Math.max(...present), "latest");
7614
7654
  }
7655
+ },
7656
+ rose: {
7657
+ minArgs: 2,
7658
+ maxArgs: 3,
7659
+ apply: () => {
7660
+ throw new ExpressionEvalError("rose: stateful evaluation context is required");
7661
+ }
7662
+ },
7663
+ count: {
7664
+ minArgs: 1,
7665
+ maxArgs: 1,
7666
+ apply: () => {
7667
+ throw new ExpressionEvalError("count: stateful evaluation context is required");
7668
+ }
7615
7669
  }
7616
7670
  };
7617
7671
  Object.freeze(Object.assign(Object.create(null), table));
@@ -8126,6 +8180,7 @@ var CompositionItemEntrySchema = object({
8126
8180
  var CompositionFeatureSchema = discriminatedUnion("kind", [object({
8127
8181
  kind: literal("fields"),
8128
8182
  cap: string().min(1),
8183
+ enabled: boolean().optional(),
8129
8184
  fields: record(string().min(1), CompositionFieldSourceSchema).refine((fields) => Object.keys(fields).length <= 32, { message: `at most 32 fields per capability` }),
8130
8185
  /**
8131
8186
  * Items of the cap's item array, keyed by item key (D663). Naming `items`
@@ -8137,6 +8192,7 @@ var CompositionFeatureSchema = discriminatedUnion("kind", [object({
8137
8192
  }), object({
8138
8193
  kind: literal("passthrough"),
8139
8194
  cap: string().min(1),
8195
+ enabled: boolean().optional(),
8140
8196
  source: CompositionSourceRefSchema
8141
8197
  })]);
8142
8198
  var CompositionSchema = object({
@@ -8166,7 +8222,6 @@ var CompositionSchema = object({
8166
8222
  });
8167
8223
  new Set([
8168
8224
  "track",
8169
- "summary",
8170
8225
  "face",
8171
8226
  "identity",
8172
8227
  "plate",
@@ -12770,6 +12825,15 @@ DeviceType.Camera, method(object({ deviceId: number().int().nonnegative() }), ar
12770
12825
  }),
12771
12826
  lastChangedAt: number()
12772
12827
  });
12828
+ EventCategory.DoorbellOnPressed;
12829
+ var CompositionEventPlanSchema = object({
12830
+ featureIndex: number().int().nonnegative(),
12831
+ cap: string(),
12832
+ eventName: string(),
12833
+ category: _enum(EventCategory),
12834
+ stateField: string(),
12835
+ fieldKey: string()
12836
+ });
12773
12837
  /** One refusal, named (D391). `path` points into the composition, e.g. `features[0].fields.celsius`. */
12774
12838
  var CompositionProblemSchema = object({
12775
12839
  code: _enum([
@@ -12819,12 +12883,14 @@ var CompositionUnavailableModeSchema = _enum([
12819
12883
  ]);
12820
12884
  /**
12821
12885
  * `derived` reads a source · `clock` reads only `now`, recomputed when a sibling
12822
- * field of its cap changes value · `constant` reads nothing, computed once.
12886
+ * field of its cap changes value · `constant` reads nothing, computed once ·
12887
+ * `accumulator` advances from the target's seed/current output.
12823
12888
  */
12824
12889
  var CompositionFieldRoleSchema = _enum([
12825
12890
  "derived",
12826
12891
  "clock",
12827
- "constant"
12892
+ "constant",
12893
+ "accumulator"
12828
12894
  ]);
12829
12895
  /** The item a planned field belongs to; its `path` is then the dotted path INSIDE the item. */
12830
12896
  var CompositionFieldItemSchema = object({
@@ -12860,6 +12926,7 @@ var CompositionFeatureModeSchema = _enum([
12860
12926
  "replace"
12861
12927
  ]);
12862
12928
  var CompositionFeaturePlanSchema = object({
12929
+ /** Index in the stored feature array; disabled features are omitted rather than re-indexed. */
12863
12930
  featureIndex: number().int().nonnegative(),
12864
12931
  cap: string(),
12865
12932
  mode: CompositionFeatureModeSchema
@@ -12868,7 +12935,8 @@ var CompositionValidationSchema = object({
12868
12935
  ok: boolean(),
12869
12936
  problems: array(CompositionProblemSchema),
12870
12937
  fields: array(CompositionFieldPlanSchema),
12871
- features: array(CompositionFeaturePlanSchema)
12938
+ features: array(CompositionFeaturePlanSchema),
12939
+ events: array(CompositionEventPlanSchema)
12872
12940
  });
12873
12941
  /**
12874
12942
  * Mirrors `CoreBlockStatus`, pinned by `core-blocks-source.spec.ts`. `degraded`:
@@ -14463,6 +14531,34 @@ var DeviceBindingsForDeviceSchema = object({
14463
14531
  nativeAddonId: string()
14464
14532
  }))
14465
14533
  });
14534
+ /**
14535
+ * The STORED wrapper activation for one `(device, capability)` pair — the row
14536
+ * `setWrapperActive` writes, read back three-way (D675):
14537
+ *
14538
+ * - `value` — the store answered and holds an activation: the bound wrapper's
14539
+ * addon id, or `null`, the operator's explicit "off" marker (D62);
14540
+ * - `missing` — the store answered, its activation map exists, and it holds
14541
+ * nothing for this pair: the operator never activated or deactivated a
14542
+ * wrapper here;
14543
+ * - `failed` — the store could not be read, holds no activation map at all
14544
+ * (an empty or unready snapshot, D44), or holds something that is not an
14545
+ * activation. It carries NO information: a consumer must never read it as
14546
+ * `missing` (D315, D393).
14547
+ *
14548
+ * This is the persisted INPUT, not the derived `getBindings` view — no registry
14549
+ * resolution, no `defaultActive` auto-binding, no cluster native-cap folding.
14550
+ */
14551
+ var WrapperActivationReadSchema = discriminatedUnion("kind", [
14552
+ object({
14553
+ kind: literal("value"),
14554
+ wrapperAddonId: string().nullable()
14555
+ }),
14556
+ object({ kind: literal("missing") }),
14557
+ object({
14558
+ kind: literal("failed"),
14559
+ error: string()
14560
+ })
14561
+ ]);
14466
14562
  var SavedDeviceRowSchema = object({
14467
14563
  /** Numeric id reserved at allocateDeviceId time. */
14468
14564
  id: number(),
@@ -14813,7 +14909,10 @@ method(object({
14813
14909
  }), _void(), {
14814
14910
  kind: "mutation",
14815
14911
  auth: "admin"
14816
- }), method(object({ capName: string() }), array(string())), method(object({ deviceType: string() }), array(object({
14912
+ }), method(object({
14913
+ deviceId: number(),
14914
+ capName: string().min(1)
14915
+ }), WrapperActivationReadSchema), method(object({ capName: string() }), array(string())), method(object({ deviceType: string() }), array(object({
14817
14916
  capName: string(),
14818
14917
  wrappers: array(string())
14819
14918
  }))), method(object({ deviceId: number() }), SettingsSchemaWithValuesSchema.nullable()), method(object({ deviceId: number() }), SettingsSchemaWithValuesSchema.nullable()), method(object({ deviceId: number() }), object({
@@ -19924,6 +20023,102 @@ var OauthIntegrationDescriptorSchema = object({
19924
20023
  });
19925
20024
  method(_void(), OauthIntegrationDescriptorSchema, { auth: "admin" });
19926
20025
  /**
20026
+ * What started a camera's onboard motion (D672). `camera` is the camera's own
20027
+ * firmware; `sensor` is a device the operator ATTACHED to it. Absent on the
20028
+ * wire means the camera: only the camera-sensors bridge ever says `sensor`.
20029
+ */
20030
+ var MotionTriggeredBySchema = discriminatedUnion("kind", [object({ kind: literal("camera") }), object({
20031
+ kind: literal("sensor"),
20032
+ deviceId: number().int().positive()
20033
+ })]);
20034
+ Object.freeze({ kind: "camera" });
20035
+ var CameraSensorRefSchema = object({
20036
+ addonId: string().min(1),
20037
+ stableId: string().min(1)
20038
+ });
20039
+ function cameraSensorRefKey(ref) {
20040
+ return `${ref.addonId}/${ref.stableId}`;
20041
+ }
20042
+ /** CS-1 accepts exactly one mode; CS-2 (D673) widens it to confirm / replace. */
20043
+ var CameraSensorsModeSchema = _enum(["in-addition"]);
20044
+ object({
20045
+ mode: CameraSensorsModeSchema,
20046
+ sensors: array(CameraSensorRefSchema).min(1).max(8)
20047
+ }).superRefine((value, ctx) => {
20048
+ const seen = /* @__PURE__ */ new Set();
20049
+ value.sensors.forEach((ref, index) => {
20050
+ const key = cameraSensorRefKey(ref);
20051
+ if (seen.has(key)) ctx.addIssue({
20052
+ code: "custom",
20053
+ path: ["sensors", index],
20054
+ message: `duplicate camera sensor ${key}`
20055
+ });
20056
+ seen.add(key);
20057
+ });
20058
+ });
20059
+ var RefFields = {
20060
+ addonId: string(),
20061
+ stableId: string()
20062
+ };
20063
+ var CameraSensorAttachmentSchema = discriminatedUnion("state", [
20064
+ object({
20065
+ ...RefFields,
20066
+ state: literal("ready"),
20067
+ deviceId: number(),
20068
+ name: string(),
20069
+ caps: array(string()).readonly()
20070
+ }),
20071
+ object({
20072
+ ...RefFields,
20073
+ state: literal("offline"),
20074
+ deviceId: number(),
20075
+ name: string(),
20076
+ reason: _enum(["offline", "disabled"])
20077
+ }),
20078
+ object({
20079
+ ...RefFields,
20080
+ state: literal("missing"),
20081
+ reason: string()
20082
+ }),
20083
+ object({
20084
+ ...RefFields,
20085
+ state: literal("unsupported"),
20086
+ deviceId: number(),
20087
+ name: string(),
20088
+ reason: string()
20089
+ }),
20090
+ object({
20091
+ ...RefFields,
20092
+ state: literal("unreadable"),
20093
+ reason: string()
20094
+ })
20095
+ ]);
20096
+ /**
20097
+ * Why a configured camera forwards NOTHING from its sensors, however ready they
20098
+ * are (D672): it does not list `onboard` in `motionSources` (attaching a sensor
20099
+ * does not add it), or it has no active detection config at all (the bridge
20100
+ * reads the active config). Absent = forwarded, or an older node that does not
20101
+ * say.
20102
+ */
20103
+ var CameraSensorsNotForwardedSchema = _enum(["onboard-not-listed", "no-active-detection"]);
20104
+ var CameraSensorsStatusSchema = discriminatedUnion("state", [
20105
+ object({ state: literal("not-configured") }),
20106
+ object({
20107
+ state: literal("unreadable"),
20108
+ reason: string()
20109
+ }),
20110
+ object({
20111
+ state: literal("configured"),
20112
+ mode: CameraSensorsModeSchema,
20113
+ sensors: array(CameraSensorAttachmentSchema).readonly(),
20114
+ notForwarded: CameraSensorsNotForwardedSchema.optional()
20115
+ })
20116
+ ]);
20117
+ Object.freeze({
20118
+ state: "unreadable",
20119
+ reason: "camera sensor mappings not loaded"
20120
+ });
20121
+ /**
19927
20122
  * A model choice has a SCOPE, and a scope change has a workflow.
19928
20123
  *
19929
20124
  * ## The two scopes
@@ -20672,6 +20867,12 @@ var MotionEventSchema = object({
20672
20867
  /** Populated by B5 (recording playback URL for this event). */
20673
20868
  mediaUrl: string().optional(),
20674
20869
  /**
20870
+ * The FIRST trigger of an `onboard` episode, written once at open (D672).
20871
+ * Absent = not recorded (a row written before D672, or an analyzer /
20872
+ * device-activity episode) — never read as "the camera" (D393).
20873
+ */
20874
+ triggeredBy: MotionTriggeredBySchema.optional(),
20875
+ /**
20675
20876
  * One row per motion EPISODE, not one per push (D475). `null` while the
20676
20877
  * episode is still open — a further rising edge extends it in place rather
20677
20878
  * than inserting a new row. Set once, at close, to `lastOnAt - startedAt`
@@ -21165,131 +21366,6 @@ var RecentTracksQueryInput = object({
21165
21366
  /** See {@link ExcludeSourcesDoc}. */
21166
21367
  excludeSources: array(TrackSourceSchema).optional()
21167
21368
  });
21168
- /**
21169
- * A Summary (D359): the per-camera session envelope that references tracks.
21170
- * `groupShotMediaId` is the media ROW id of its group shot (`ownerKind:
21171
- * 'summary'`, served by the event-media plane at `/m/<id>`), null until the
21172
- * first frame with a member visible has been materialised (D482 — it was the
21173
- * row's composite key, which embedded the owner and could name another table's
21174
- * row once event ids became per-table rowids).
21175
- */
21176
- var SummarySchema = object({
21177
- id: string(),
21178
- deviceId: number(),
21179
- openedAt: number(),
21180
- lastActiveAt: number(),
21181
- sealedAt: number().nullable(),
21182
- memberCount: number().int().nonnegative(),
21183
- groupShotMediaId: number().int().nullable()
21184
- });
21185
- var SummariesQueryInput = object({
21186
- deviceIds: array(number()).min(1),
21187
- since: number().optional(),
21188
- until: number().optional(),
21189
- limit: number().int().min(1).max(200).default(50),
21190
- /** The same member-wise filter {@link listRecentSummaries} takes — one
21191
- * meaning of "dog" on every summary surface. */
21192
- classes: array(string().min(1).max(60)).max(40).optional()
21193
- });
21194
- var SummaryDetailSchema = object({
21195
- summary: SummarySchema,
21196
- /** Members in absorption order, oldest join first. */
21197
- members: array(object({
21198
- trackId: string(),
21199
- /**
21200
- * The track's class at the time it JOINED, or `null` when it was unresolved
21201
- * and the track no longer exists to fill it.
21202
- *
21203
- * The join, not the latest opinion: class voting can re-decide a track's
21204
- * class afterwards, and a group's composition is the history of who came
21205
- * together. A consumer counts these to badge a thumbnail — "two people and a
21206
- * dog" — rather than being handed a second, denormalised tally that would
21207
- * drift from the members it claims to describe.
21208
- */
21209
- className: string().nullable(),
21210
- /** `primary` is the one member that carries the group's identity. */
21211
- role: _enum([
21212
- "primary",
21213
- "sibling",
21214
- "child"
21215
- ]).nullable(),
21216
- joinedAt: number(),
21217
- /** Tier 1 — the sub-class (`dog`, `van`), resolved from the member's track
21218
- * at read time. Absent when nothing resolved, never an empty string. */
21219
- label: string().optional(),
21220
- /** Tier 2 — the instance: a person's name, a plate. Absent when the pipeline
21221
- * recognised nobody, and absent for a member whose track has been pruned —
21222
- * a thumbnail that names the wrong person is worse than one naming nobody. */
21223
- subLabel: string().optional()
21224
- })).readonly()
21225
- });
21226
- /**
21227
- * What a LIST of groups carries: the envelope plus what it is MADE OF.
21228
- *
21229
- * Coarse on purpose — the operator's rule is "only the rough data on the list,
21230
- * we extend when we notice we need more". Enough to draw the card ("two people
21231
- * and a dog") and no more. The MEMBERS, their names and the per-member links
21232
- * are on {@link getSummary}: shipping every member of every group so a client
21233
- * can count them turns a page of two hundred groups into a thousand records to
21234
- * draw two hundred badges.
21235
- */
21236
- var SummaryListItemSchema = object({
21237
- summary: SummarySchema,
21238
- /** Class counts, most numerous first; `className: null` is a member whose
21239
- * class never resolved, counted so the counts add up to `memberCount`. */
21240
- classes: array(object({
21241
- className: string().nullable(),
21242
- count: number().int().positive()
21243
- })).readonly()
21244
- });
21245
- var SummariesPageSchema = object({ summaries: array(SummaryListItemSchema).readonly() });
21246
- /**
21247
- * The paged feed, deliberately the SAME shape as {@link RecentTracksQueryInput}.
21248
- *
21249
- * The reel on the cameras page and the Events gallery both ride a cursor, so a
21250
- * summaries feed that could only answer "the last N for these cameras"
21251
- * (`listSummaries`) would make groups available in the timeline and nowhere
21252
- * else. Two feeds with different ordering contracts would be two ideas of what
21253
- * "newest" means, on one screen.
21254
- */
21255
- var RecentSummariesQueryInput = object({
21256
- /** Devices to merge. An empty array yields an empty page. */
21257
- deviceIds: array(number()),
21258
- /** Window lower bound on `lastActiveAt` (inclusive). */
21259
- since: number().optional(),
21260
- /** Window upper bound on `lastActiveAt` (inclusive). */
21261
- until: number().optional(),
21262
- limit: number().int().min(1).max(500).default(100),
21263
- /** Opaque continuation cursor from a previous page's `nextCursor`. */
21264
- cursor: string().optional(),
21265
- /**
21266
- * Restrict to these classes — THE SAME FIELD `listRecentTracks` takes, and
21267
- * deliberately the same name: the events filter tree emits one list of ticked
21268
- * taxonomy nodes, and a summaries feed that called it something else would
21269
- * make the operator's one filter component produce two shapes.
21270
- *
21271
- * A question about the MEMBERS: a group matches when ANY of them does. "Show
21272
- * me the arrivals with a dog" has to return the group of four people who had
21273
- * one with them; a filter on the group's own fields could only ever answer
21274
- * about its primary.
21275
- *
21276
- * Matched against all THREE tiers of a member — the class (`animal`), the
21277
- * sub-class (`dog`) and the instance (a name, a plate) — because which tier a
21278
- * ticked node lives on is the taxonomy's business, not the caller's. `dog` is
21279
- * an event kind in the tree and a tier-1 label on an `animal` track; a filter
21280
- * that read only the class would answer "animal" and never "dog".
21281
- *
21282
- * ABSENT or EMPTY means no filter — absent is not a selection of none.
21283
- */
21284
- classes: array(string().min(1).max(60)).max(40).optional()
21285
- });
21286
- var RecentSummariesPageSchema = object({
21287
- /** Ordered by (`lastActiveAt` DESC, id DESC). Same light item as
21288
- * {@link listSummaries} — one list shape, so a card renders the same
21289
- * whichever feed drew it. */
21290
- summaries: array(SummaryListItemSchema).readonly(),
21291
- nextCursor: string().nullable()
21292
- });
21293
21369
  var RecentTracksPageSchema = object({
21294
21370
  /** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
21295
21371
  tracks: array(TrackSchema).readonly(),
@@ -21801,7 +21877,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
21801
21877
  classes: array(string()).optional(),
21802
21878
  /** See {@link ExcludeSourcesDoc}. */
21803
21879
  excludeSources: array(TrackSourceSchema).optional()
21804
- }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(SummariesQueryInput, SummariesPageSchema), method(RecentSummariesQueryInput, RecentSummariesPageSchema), method(object({ id: string() }), SummaryDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
21880
+ }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(object({ deviceId: number() }), _void(), {
21805
21881
  kind: "mutation",
21806
21882
  auth: "admin"
21807
21883
  }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(object({ deviceId: number() }), array(EventKindDescriptorSchema).readonly()), method(object({ deviceIds: array(number()).min(1).max(200) }), array(EventKindsForDeviceSchema).readonly()), method(object({
@@ -22981,6 +23057,23 @@ var MotionSourceEnum = _enum([
22981
23057
  */
22982
23058
  var MotionSourcesSchema = array(MotionSourceEnum);
22983
23059
  /**
23060
+ * The operator-facing name of each MOTION source (D672: `onboard` = the
23061
+ * camera's sensors — its own motion plus any sensor attached to it). The wire
23062
+ * value stays `onboard`; only the label changed. `detectionSources: 'onboard'`
23063
+ * ("Camera onboard AI") and the notification source filter keep their labels.
23064
+ */
23065
+ var MOTION_SOURCE_LABELS = {
23066
+ analyzer: "Frame-diff Analyzer (motion addon)",
23067
+ onboard: "Camera sensors",
23068
+ "device-activity": "Device activity (the device says it is working)"
23069
+ };
23070
+ /** The order the motion-source picker offers them in (not the enum's order). */
23071
+ var MOTION_SOURCE_PICKER_ORDER = [
23072
+ "analyzer",
23073
+ "onboard",
23074
+ "device-activity"
23075
+ ];
23076
+ /**
22984
23077
  * Which root detector a camera runs — EXACTLY ONE.
22985
23078
  *
22986
23079
  * Deliberately the SAME vocabulary post-analysis already tags every detection
@@ -23327,7 +23420,14 @@ var RunnerCameraConfigSchema = object({
23327
23420
  */
23328
23421
  inferenceDevices: array(RunnerInferenceDeviceSchema).readonly().optional()
23329
23422
  });
23330
- motionFpsField.min, motionFpsField.max, motionFpsField.step, motionFpsField.default, detectionFpsField.min, detectionFpsField.max, detectionFpsField.step, detectionFpsField.default, motionCooldownMsField.min, motionCooldownMsField.max, motionCooldownMsField.step, motionCooldownMsField.default, maxSessionHoldMsField.min, maxSessionHoldMsField.max, maxSessionHoldMsField.step, maxSessionHoldMsField.default, audioMotionWindowMsField.min, audioMotionWindowMsField.max, audioMotionWindowMsField.step, audioMotionWindowMsField.default, preRollInferenceFramesField.min, preRollInferenceFramesField.max, preRollInferenceFramesField.step, preRollInferenceFramesField.default, occupancyRecheckSecField.min, occupancyRecheckSecField.max, occupancyRecheckSecField.step, occupancyRecheckSecField.default, occupancyRecheckFramesField.min, occupancyRecheckFramesField.max, occupancyRecheckFramesField.step, occupancyRecheckFramesField.default;
23423
+ MOTION_SOURCE_PICKER_ORDER.map((value) => value === "onboard" ? {
23424
+ value,
23425
+ label: MOTION_SOURCE_LABELS[value],
23426
+ description: "The camera's own motion, plus any sensor attached to it"
23427
+ } : {
23428
+ value,
23429
+ label: MOTION_SOURCE_LABELS[value]
23430
+ }), motionFpsField.min, motionFpsField.max, motionFpsField.step, motionFpsField.default, detectionFpsField.min, detectionFpsField.max, detectionFpsField.step, detectionFpsField.default, motionCooldownMsField.min, motionCooldownMsField.max, motionCooldownMsField.step, motionCooldownMsField.default, maxSessionHoldMsField.min, maxSessionHoldMsField.max, maxSessionHoldMsField.step, maxSessionHoldMsField.default, audioMotionWindowMsField.min, audioMotionWindowMsField.max, audioMotionWindowMsField.step, audioMotionWindowMsField.default, preRollInferenceFramesField.min, preRollInferenceFramesField.max, preRollInferenceFramesField.step, preRollInferenceFramesField.default, occupancyRecheckSecField.min, occupancyRecheckSecField.max, occupancyRecheckSecField.step, occupancyRecheckSecField.default, occupancyRecheckFramesField.min, occupancyRecheckFramesField.max, occupancyRecheckFramesField.step, occupancyRecheckFramesField.default;
23331
23431
  /**
23332
23432
  * Runtime load summary returned by `getLocalLoad`. Used by the orchestrator's
23333
23433
  * load-balancing levels (L2 capacity-based, L3 hardware-aware) to decide
@@ -23901,6 +24001,11 @@ var CameraStatusSchema = object({
23901
24001
  */
23902
24002
  switchedOff: array(CameraSwitchIdSchema).readonly(),
23903
24003
  /**
24004
+ * The camera's attached sensors (D672). Optional only for a status composed
24005
+ * by an orchestrator older than D672; this orchestrator always sets it.
24006
+ */
24007
+ cameraSensors: CameraSensorsStatusSchema.optional(),
24008
+ /**
23904
24009
  * Stages of the bounded fan-out that were CUT SHORT — a timeout or a
23905
24010
  * rejection — and whose block is therefore `null` because we could not
23906
24011
  * READ it, not because there is nothing there.
@@ -26323,42 +26428,6 @@ DeviceType.Camera, method(object({
26323
26428
  kind: "query",
26324
26429
  auth: "protected"
26325
26430
  });
26326
- /**
26327
- * LA tabella "quale booleano di questo tipo di device conta come ALTO", e il
26328
- * valutatore puro del suo FRONTE.
26329
- *
26330
- * Viveva dentro il builtin virtual-doorbell
26331
- * (`@camstack/system` — `builtins/doorbell/trigger-engine.ts`) e i suoi
26332
- * predicati erano privati al modulo. Il recorder ne ha bisogno per il trigger
26333
- * `RecordingTriggers.sensorDeviceIds`: copiarla avrebbe creato la SECONDA
26334
- * tabella, che diverge alla prima cap aggiunta e il cui sintomo — "il sensore
26335
- * fa suonare il campanello ma non registra" — è esattamente D62. Quindi si
26336
- * SPOSTA qui e il doorbell la ri-esporta.
26337
- *
26338
- * ⚠ NON è `DEVICE_STATE_READERS` (`catalogs/device-state-vocabulary.ts`), e le
26339
- * due non vanno unificate: quella risponde a "qual è la PAROLA di stato per una
26340
- * regola" (e include `presence`, `cover`, `alarm-panel`), questa a "qual è il
26341
- * booleano il cui FRONTE conta". Vocabolari deliberatamente diversi.
26342
- */
26343
- /**
26344
- * Known binary / switch source caps → the boolean slice field whose
26345
- * false→true rise counts as ACTIVE. Every entry is "fire on active".
26346
- * Sensors whose "active" reading is not a plain boolean (presence's string
26347
- * state, connectivity's connected flag) are deliberately excluded — a
26348
- * reconnect is not a doorbell press, and it is not a recording either.
26349
- */
26350
- var SOURCE_CAP_ACTIVE_FIELD = {
26351
- contact: "entryOpen",
26352
- binary: "on",
26353
- switch: "on",
26354
- motion: "detected",
26355
- flood: "flooded",
26356
- gas: "detected",
26357
- smoke: "detected",
26358
- "carbon-monoxide": "detected",
26359
- vibration: "detected",
26360
- tamper: "tampered"
26361
- };
26362
26431
  object({
26363
26432
  /** Ms epoch of the last press. null = never observed since this provider started. */
26364
26433
  lastPressedAt: number().nullable(),
@@ -30008,7 +30077,9 @@ object({
30008
30077
  detected: boolean(),
30009
30078
  timestamp: number(),
30010
30079
  source: MotionSourceEnum,
30011
- regions: array(MotionRegionSchema).readonly().optional()
30080
+ regions: array(MotionRegionSchema).readonly().optional(),
30081
+ /** Who started it (D672). Absent = the camera itself. Only `onboard` carries `sensor`. */
30082
+ triggeredBy: MotionTriggeredBySchema.optional()
30012
30083
  });
30013
30084
  DeviceType.Camera, DeviceType.Sensor, method(object({ deviceId: number() }), boolean());
30014
30085
  object({
@@ -32330,12 +32401,21 @@ var RecordingStorageUsageSchema = object({
32330
32401
  */
32331
32402
  devicesRead: _enum(["archive", "unavailable"]).optional(),
32332
32403
  /**
32404
+ * Is the `archive` answer WHOLE (D674): the hour ledger loaded without
32405
+ * hitting its row cap, and at least one location resolved? Only then may a
32406
+ * camera ABSENT from `devices[]` be read as "no footage" — and only then is a
32407
+ * row's `oldestMs` the archive's oldest rather than the oldest of a fraction.
32408
+ * OPTIONAL: a recorder predating D674 omits it, and a consumer must read the
32409
+ * absence as `false`. A retention floor is a delete; it never guesses.
32410
+ */
32411
+ complete: boolean().optional(),
32412
+ /**
32333
32413
  * Per-physical-volume capacity. OPTIONAL, and consumers must render the rest
32334
- * of the payload without it: the hub serves this method through a BAKED
32335
- * router, so a hub whose framework train predates a change to this array
32336
- * strips it out of an answer a newer recorder happily produced. A UI that
32337
- * dereferences it unconditionally crashes the whole Storage page over a
32338
- * missing disk bar.
32414
+ * of the payload without it: a recorder that could not build it omits it. A
32415
+ * UI that dereferences it unconditionally crashes the whole Storage page over
32416
+ * a missing disk bar. (The hub's cap routers pass output through unvalidated
32417
+ * since 2026-07-11 — `cap-router-builder.ts` — so a newer recorder's fields
32418
+ * are not stripped by an older hub.)
32339
32419
  */
32340
32420
  locations: array(RecordingLocationUsageSchema).optional()
32341
32421
  });
@@ -35106,7 +35186,12 @@ Object.freeze({
35106
35186
  number: {
35107
35187
  kind: "fixed",
35108
35188
  result: ["number", "null"]
35109
- }
35189
+ },
35190
+ rose: {
35191
+ kind: "fixed",
35192
+ result: ["number", "null"]
35193
+ },
35194
+ count: NUMBER
35110
35195
  });
35111
35196
  `${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
35112
35197
  /**
@@ -38221,6 +38306,12 @@ Object.freeze({
38221
38306
  addonId: null,
38222
38307
  access: "view"
38223
38308
  },
38309
+ "deviceManager.getWrapperActivation": {
38310
+ capName: "device-manager",
38311
+ capScope: "system",
38312
+ addonId: null,
38313
+ access: "view"
38314
+ },
38224
38315
  "deviceManager.listAll": {
38225
38316
  capName: "device-manager",
38226
38317
  capScope: "system",
@@ -40495,12 +40586,6 @@ Object.freeze({
40495
40586
  addonId: null,
40496
40587
  access: "view"
40497
40588
  },
40498
- "pipelineAnalytics.getSummary": {
40499
- capName: "pipeline-analytics",
40500
- capScope: "device",
40501
- addonId: null,
40502
- access: "view"
40503
- },
40504
40589
  "pipelineAnalytics.getTrack": {
40505
40590
  capName: "pipeline-analytics",
40506
40591
  capScope: "device",
@@ -40561,12 +40646,6 @@ Object.freeze({
40561
40646
  addonId: null,
40562
40647
  access: "view"
40563
40648
  },
40564
- "pipelineAnalytics.listRecentSummaries": {
40565
- capName: "pipeline-analytics",
40566
- capScope: "device",
40567
- addonId: null,
40568
- access: "view"
40569
- },
40570
40649
  "pipelineAnalytics.listRecentTracks": {
40571
40650
  capName: "pipeline-analytics",
40572
40651
  capScope: "device",
@@ -40597,12 +40676,6 @@ Object.freeze({
40597
40676
  addonId: null,
40598
40677
  access: "view"
40599
40678
  },
40600
- "pipelineAnalytics.listSummaries": {
40601
- capName: "pipeline-analytics",
40602
- capScope: "device",
40603
- addonId: null,
40604
- access: "view"
40605
- },
40606
40679
  "pipelineAnalytics.listTrackMedia": {
40607
40680
  capName: "pipeline-analytics",
40608
40681
  capScope: "device",
@@ -44030,6 +44103,11 @@ Object.freeze({
44030
44103
  form: "single",
44031
44104
  optional: false
44032
44105
  }],
44106
+ "deviceManager.getWrapperActivation": [{
44107
+ name: "deviceId",
44108
+ form: "single",
44109
+ optional: false
44110
+ }],
44033
44111
  "deviceManager.listAll": [{
44034
44112
  name: "deviceIds",
44035
44113
  form: "array",
@@ -44767,11 +44845,6 @@ Object.freeze({
44767
44845
  form: "single",
44768
44846
  optional: true
44769
44847
  }],
44770
- "pipelineAnalytics.listRecentSummaries": [{
44771
- name: "deviceIds",
44772
- form: "array",
44773
- optional: false
44774
- }],
44775
44848
  "pipelineAnalytics.listRecentTracks": [{
44776
44849
  name: "deviceIds",
44777
44850
  form: "array",
@@ -44782,11 +44855,6 @@ Object.freeze({
44782
44855
  form: "array",
44783
44856
  optional: true
44784
44857
  }],
44785
- "pipelineAnalytics.listSummaries": [{
44786
- name: "deviceIds",
44787
- form: "array",
44788
- optional: false
44789
- }],
44790
44858
  "pipelineAnalytics.listTrackMedia": [{
44791
44859
  name: "deviceId",
44792
44860
  form: "single",
@@ -46598,7 +46666,7 @@ var AgentUIAddon = class extends BaseAddon {
46598
46666
  capability: adminUiCapability,
46599
46667
  provider: {
46600
46668
  getStaticDir: async () => ({ staticDir: path.resolve(__dirname) }),
46601
- getVersion: async () => ({ version: "1.2.154" })
46669
+ getVersion: async () => ({ version: "1.2.156" })
46602
46670
  }
46603
46671
  }];
46604
46672
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-agent-ui",
3
- "version": "1.2.154",
3
+ "version": "1.2.156",
4
4
  "description": "Agent UI — lightweight status dashboard served by every agent node",
5
5
  "keywords": [
6
6
  "camstack",