@camstack/addon-osd-manager 0.1.146 → 0.1.148

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 (18) hide show
  1. package/dist/{MotionZonesSettings-DAxqXklY.mjs → MotionZonesSettings-BE9WUdRt.mjs} +2 -2
  2. package/dist/{PrivacyMaskSettings-DxY1SExl.mjs → PrivacyMaskSettings-DS9QMvLQ.mjs} +4 -4
  3. package/dist/{SceneMonitorEditor-D2d47F_V.mjs → SceneMonitorEditor-Dp9VUno1.mjs} +3 -3
  4. package/dist/_stub.js +11 -11
  5. package/dist/{_virtual_mf-localSharedImportMap___mfe_internal__addon_osd_manager_page-CyeMVww2.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_osd_manager_page-BrVYU0wm.mjs} +3 -3
  6. package/dist/_virtual_mf___mfe_internal__addon_osd_manager_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-CCyGyV4m.mjs +26 -0
  7. package/dist/{hostInit-DEeDzJK5.mjs → hostInit-5x_5PqnW.mjs} +2 -2
  8. package/dist/index.js +292 -215
  9. package/dist/index.mjs +292 -215
  10. package/dist/{player-overlays-DeusjeOj.mjs → player-overlays-BF0CGxFK.mjs} +1 -1
  11. package/dist/remoteEntry.js +1 -1
  12. package/dist/{responsive-bl9DCRTN.mjs → responsive-COf1R73i.mjs} +1 -1
  13. package/dist/{scene-monitor-copy-BIDfr4E5.mjs → scene-monitor-copy-D_ksge64.mjs} +1 -1
  14. package/dist/{square-yZRmjMIg.mjs → square-D6ZZGuyC.mjs} +1 -1
  15. package/dist/{trash-2-IqfhyJQ1.mjs → trash-2-B-TzfoNr.mjs} +1 -1
  16. package/dist/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_osd_manager_page__remoteEntry_js-AnF0MZSp.mjs → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_osd_manager_page__remoteEntry_js-Cq_qaEBf.mjs} +1 -1
  17. package/package.json +1 -1
  18. package/dist/_virtual_mf___mfe_internal__addon_osd_manager_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-H1dXnudd.mjs +0 -26
package/dist/index.mjs CHANGED
@@ -5369,7 +5369,7 @@ var ZodIssueCode = {
5369
5369
  var ZodFirstPartyTypeKind;
5370
5370
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5371
5371
  //#endregion
5372
- //#region ../types/dist/sleep-jkRQgtSc.mjs
5372
+ //#region ../types/dist/sleep-C-v96WpE.mjs
5373
5373
  /**
5374
5374
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5375
5375
  * window to float samples (D455).
@@ -6925,6 +6925,10 @@ var ProfileRtspEntrySchema = object({
6925
6925
  codec: string().optional(),
6926
6926
  resolution: CamStreamResolutionSchema.optional()
6927
6927
  });
6928
+ object({
6929
+ field: string().min(1),
6930
+ on: literal("advance")
6931
+ });
6928
6932
  /**
6929
6933
  * Output schema shared by the contribution + live methods.
6930
6934
  *
@@ -7506,7 +7510,45 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
7506
7510
  return DeviceRole;
7507
7511
  }({});
7508
7512
  //#endregion
7509
- //#region ../types/dist/composition-CPFIlFfw.mjs
7513
+ //#region ../types/dist/composition-BK-GTFYb.mjs
7514
+ /**
7515
+ * LA tabella "quale booleano di questo tipo di device conta come ALTO", e il
7516
+ * valutatore puro del suo FRONTE.
7517
+ *
7518
+ * Viveva dentro il builtin virtual-doorbell
7519
+ * (`@camstack/system` — `builtins/doorbell/trigger-engine.ts`) e i suoi
7520
+ * predicati erano privati al modulo. Il recorder ne ha bisogno per il trigger
7521
+ * `RecordingTriggers.sensorDeviceIds`: copiarla avrebbe creato la SECONDA
7522
+ * tabella, che diverge alla prima cap aggiunta e il cui sintomo — "il sensore
7523
+ * fa suonare il campanello ma non registra" — è esattamente D62. Quindi si
7524
+ * SPOSTA qui e il doorbell la ri-esporta.
7525
+ *
7526
+ * ⚠ NON è `DEVICE_STATE_READERS` (`catalogs/device-state-vocabulary.ts`), e le
7527
+ * due non vanno unificate: quella risponde a "qual è la PAROLA di stato per una
7528
+ * regola" (e include `presence`, `cover`, `alarm-panel`), questa a "qual è il
7529
+ * booleano il cui FRONTE conta". Vocabolari deliberatamente diversi.
7530
+ */
7531
+ /**
7532
+ * Known binary / switch source caps → the boolean slice field whose
7533
+ * false→true rise counts as ACTIVE. Every entry is "fire on active".
7534
+ * Sensors whose "active" reading is not a plain boolean (presence's string
7535
+ * state, connectivity's connected flag) are deliberately excluded — a
7536
+ * reconnect is not a doorbell press, and it is not a recording either.
7537
+ */
7538
+ var SOURCE_CAP_ACTIVE_FIELD = {
7539
+ contact: "entryOpen",
7540
+ binary: "on",
7541
+ switch: "on",
7542
+ motion: "detected",
7543
+ flood: "flooded",
7544
+ gas: "detected",
7545
+ smoke: "detected",
7546
+ "carbon-monoxide": "detected",
7547
+ vibration: "detected",
7548
+ tamper: "tampered"
7549
+ };
7550
+ /** Cap names whose presence in a device's bindings qualify it as a source. */
7551
+ var SOURCE_CAPS = Object.keys(SOURCE_CAP_ACTIVE_FIELD);
7510
7552
  /**
7511
7553
  * Error types for the safe expression engine. Two distinct classes so callers
7512
7554
  * can tell a compile-time (grammar) failure from a runtime (evaluation)
@@ -7704,6 +7746,20 @@ var table = {
7704
7746
  const present = args.flatMap((a, i) => a === null ? [] : [asFiniteNumber(a, "latest", i)]);
7705
7747
  return present.length === 0 ? null : finiteResult(Math.max(...present), "latest");
7706
7748
  }
7749
+ },
7750
+ rose: {
7751
+ minArgs: 2,
7752
+ maxArgs: 3,
7753
+ apply: () => {
7754
+ throw new ExpressionEvalError("rose: stateful evaluation context is required");
7755
+ }
7756
+ },
7757
+ count: {
7758
+ minArgs: 1,
7759
+ maxArgs: 1,
7760
+ apply: () => {
7761
+ throw new ExpressionEvalError("count: stateful evaluation context is required");
7762
+ }
7707
7763
  }
7708
7764
  };
7709
7765
  Object.freeze(Object.assign(Object.create(null), table));
@@ -8218,6 +8274,7 @@ var CompositionItemEntrySchema = object({
8218
8274
  var CompositionFeatureSchema = discriminatedUnion("kind", [object({
8219
8275
  kind: literal("fields"),
8220
8276
  cap: string().min(1),
8277
+ enabled: boolean().optional(),
8221
8278
  fields: record(string().min(1), CompositionFieldSourceSchema).refine((fields) => Object.keys(fields).length <= 32, { message: `at most 32 fields per capability` }),
8222
8279
  /**
8223
8280
  * Items of the cap's item array, keyed by item key (D663). Naming `items`
@@ -8229,6 +8286,7 @@ var CompositionFeatureSchema = discriminatedUnion("kind", [object({
8229
8286
  }), object({
8230
8287
  kind: literal("passthrough"),
8231
8288
  cap: string().min(1),
8289
+ enabled: boolean().optional(),
8232
8290
  source: CompositionSourceRefSchema
8233
8291
  })]);
8234
8292
  var CompositionSchema = object({
@@ -8258,7 +8316,6 @@ var CompositionSchema = object({
8258
8316
  });
8259
8317
  new Set([
8260
8318
  "track",
8261
- "summary",
8262
8319
  "face",
8263
8320
  "identity",
8264
8321
  "plate",
@@ -13638,6 +13695,15 @@ var cameraStreamsCapability = {
13638
13695
  */
13639
13696
  durability: "session"
13640
13697
  };
13698
+ EventCategory.DoorbellOnPressed;
13699
+ var CompositionEventPlanSchema = object({
13700
+ featureIndex: number().int().nonnegative(),
13701
+ cap: string(),
13702
+ eventName: string(),
13703
+ category: _enum(EventCategory),
13704
+ stateField: string(),
13705
+ fieldKey: string()
13706
+ });
13641
13707
  /** One refusal, named (D391). `path` points into the composition, e.g. `features[0].fields.celsius`. */
13642
13708
  var CompositionProblemSchema = object({
13643
13709
  code: _enum([
@@ -13687,12 +13753,14 @@ var CompositionUnavailableModeSchema = _enum([
13687
13753
  ]);
13688
13754
  /**
13689
13755
  * `derived` reads a source · `clock` reads only `now`, recomputed when a sibling
13690
- * field of its cap changes value · `constant` reads nothing, computed once.
13756
+ * field of its cap changes value · `constant` reads nothing, computed once ·
13757
+ * `accumulator` advances from the target's seed/current output.
13691
13758
  */
13692
13759
  var CompositionFieldRoleSchema = _enum([
13693
13760
  "derived",
13694
13761
  "clock",
13695
- "constant"
13762
+ "constant",
13763
+ "accumulator"
13696
13764
  ]);
13697
13765
  /** The item a planned field belongs to; its `path` is then the dotted path INSIDE the item. */
13698
13766
  var CompositionFieldItemSchema = object({
@@ -13728,6 +13796,7 @@ var CompositionFeatureModeSchema = _enum([
13728
13796
  "replace"
13729
13797
  ]);
13730
13798
  var CompositionFeaturePlanSchema = object({
13799
+ /** Index in the stored feature array; disabled features are omitted rather than re-indexed. */
13731
13800
  featureIndex: number().int().nonnegative(),
13732
13801
  cap: string(),
13733
13802
  mode: CompositionFeatureModeSchema
@@ -13736,7 +13805,8 @@ var CompositionValidationSchema = object({
13736
13805
  ok: boolean(),
13737
13806
  problems: array(CompositionProblemSchema),
13738
13807
  fields: array(CompositionFieldPlanSchema),
13739
- features: array(CompositionFeaturePlanSchema)
13808
+ features: array(CompositionFeaturePlanSchema),
13809
+ events: array(CompositionEventPlanSchema)
13740
13810
  });
13741
13811
  /**
13742
13812
  * Mirrors `CoreBlockStatus`, pinned by `core-blocks-source.spec.ts`. `degraded`:
@@ -15992,6 +16062,34 @@ var DeviceBindingsForDeviceSchema = object({
15992
16062
  nativeAddonId: string()
15993
16063
  }))
15994
16064
  });
16065
+ /**
16066
+ * The STORED wrapper activation for one `(device, capability)` pair — the row
16067
+ * `setWrapperActive` writes, read back three-way (D675):
16068
+ *
16069
+ * - `value` — the store answered and holds an activation: the bound wrapper's
16070
+ * addon id, or `null`, the operator's explicit "off" marker (D62);
16071
+ * - `missing` — the store answered, its activation map exists, and it holds
16072
+ * nothing for this pair: the operator never activated or deactivated a
16073
+ * wrapper here;
16074
+ * - `failed` — the store could not be read, holds no activation map at all
16075
+ * (an empty or unready snapshot, D44), or holds something that is not an
16076
+ * activation. It carries NO information: a consumer must never read it as
16077
+ * `missing` (D315, D393).
16078
+ *
16079
+ * This is the persisted INPUT, not the derived `getBindings` view — no registry
16080
+ * resolution, no `defaultActive` auto-binding, no cluster native-cap folding.
16081
+ */
16082
+ var WrapperActivationReadSchema = discriminatedUnion("kind", [
16083
+ object({
16084
+ kind: literal("value"),
16085
+ wrapperAddonId: string().nullable()
16086
+ }),
16087
+ object({ kind: literal("missing") }),
16088
+ object({
16089
+ kind: literal("failed"),
16090
+ error: string()
16091
+ })
16092
+ ]);
15995
16093
  var SavedDeviceRowSchema = object({
15996
16094
  /** Numeric id reserved at allocateDeviceId time. */
15997
16095
  id: number(),
@@ -16790,6 +16888,21 @@ var deviceManagerCapability = {
16790
16888
  auth: "admin"
16791
16889
  }),
16792
16890
  /**
16891
+ * The STORED wrapper activation for one `(device, capName)` pair, three-way
16892
+ * (`value` / `missing` / `failed`, see {@link WrapperActivationReadSchema}).
16893
+ *
16894
+ * The narrow read of the durable authority behind `getBindings`: a
16895
+ * consumer that must know what the operator PERSISTED (virtual-doorbell,
16896
+ * before it drops a press) asks this instead of pulling device-manager's
16897
+ * whole addon store through `addonSettingsRaw.getGlobal` — which answered
16898
+ * `{}` on every isolated-engine hub and so never worked (D675). It reads
16899
+ * ONE row (the activation map, ~1.6 KB), never the ~625 KB store.
16900
+ */
16901
+ getWrapperActivation: method(object({
16902
+ deviceId: number(),
16903
+ capName: string().min(1)
16904
+ }), WrapperActivationReadSchema),
16905
+ /**
16793
16906
  * Return the addon ids that declared a wrapper provider for `capName`.
16794
16907
  * Backs the device-bindings UI's wrapper-picker dropdown. Entries are
16795
16908
  * sourced from `CapabilityRegistry.wrapperProviders`, populated when
@@ -23286,6 +23399,102 @@ var oauthIntegrationCapability = {
23286
23399
  getDescriptor: method(_void(), OauthIntegrationDescriptorSchema, { auth: "admin" }) }
23287
23400
  };
23288
23401
  /**
23402
+ * What started a camera's onboard motion (D672). `camera` is the camera's own
23403
+ * firmware; `sensor` is a device the operator ATTACHED to it. Absent on the
23404
+ * wire means the camera: only the camera-sensors bridge ever says `sensor`.
23405
+ */
23406
+ var MotionTriggeredBySchema = discriminatedUnion("kind", [object({ kind: literal("camera") }), object({
23407
+ kind: literal("sensor"),
23408
+ deviceId: number().int().positive()
23409
+ })]);
23410
+ Object.freeze({ kind: "camera" });
23411
+ var CameraSensorRefSchema = object({
23412
+ addonId: string().min(1),
23413
+ stableId: string().min(1)
23414
+ });
23415
+ function cameraSensorRefKey(ref) {
23416
+ return `${ref.addonId}/${ref.stableId}`;
23417
+ }
23418
+ /** CS-1 accepts exactly one mode; CS-2 (D673) widens it to confirm / replace. */
23419
+ var CameraSensorsModeSchema = _enum(["in-addition"]);
23420
+ object({
23421
+ mode: CameraSensorsModeSchema,
23422
+ sensors: array(CameraSensorRefSchema).min(1).max(8)
23423
+ }).superRefine((value, ctx) => {
23424
+ const seen = /* @__PURE__ */ new Set();
23425
+ value.sensors.forEach((ref, index) => {
23426
+ const key = cameraSensorRefKey(ref);
23427
+ if (seen.has(key)) ctx.addIssue({
23428
+ code: "custom",
23429
+ path: ["sensors", index],
23430
+ message: `duplicate camera sensor ${key}`
23431
+ });
23432
+ seen.add(key);
23433
+ });
23434
+ });
23435
+ var RefFields = {
23436
+ addonId: string(),
23437
+ stableId: string()
23438
+ };
23439
+ var CameraSensorAttachmentSchema = discriminatedUnion("state", [
23440
+ object({
23441
+ ...RefFields,
23442
+ state: literal("ready"),
23443
+ deviceId: number(),
23444
+ name: string(),
23445
+ caps: array(string()).readonly()
23446
+ }),
23447
+ object({
23448
+ ...RefFields,
23449
+ state: literal("offline"),
23450
+ deviceId: number(),
23451
+ name: string(),
23452
+ reason: _enum(["offline", "disabled"])
23453
+ }),
23454
+ object({
23455
+ ...RefFields,
23456
+ state: literal("missing"),
23457
+ reason: string()
23458
+ }),
23459
+ object({
23460
+ ...RefFields,
23461
+ state: literal("unsupported"),
23462
+ deviceId: number(),
23463
+ name: string(),
23464
+ reason: string()
23465
+ }),
23466
+ object({
23467
+ ...RefFields,
23468
+ state: literal("unreadable"),
23469
+ reason: string()
23470
+ })
23471
+ ]);
23472
+ /**
23473
+ * Why a configured camera forwards NOTHING from its sensors, however ready they
23474
+ * are (D672): it does not list `onboard` in `motionSources` (attaching a sensor
23475
+ * does not add it), or it has no active detection config at all (the bridge
23476
+ * reads the active config). Absent = forwarded, or an older node that does not
23477
+ * say.
23478
+ */
23479
+ var CameraSensorsNotForwardedSchema = _enum(["onboard-not-listed", "no-active-detection"]);
23480
+ var CameraSensorsStatusSchema = discriminatedUnion("state", [
23481
+ object({ state: literal("not-configured") }),
23482
+ object({
23483
+ state: literal("unreadable"),
23484
+ reason: string()
23485
+ }),
23486
+ object({
23487
+ state: literal("configured"),
23488
+ mode: CameraSensorsModeSchema,
23489
+ sensors: array(CameraSensorAttachmentSchema).readonly(),
23490
+ notForwarded: CameraSensorsNotForwardedSchema.optional()
23491
+ })
23492
+ ]);
23493
+ Object.freeze({
23494
+ state: "unreadable",
23495
+ reason: "camera sensor mappings not loaded"
23496
+ });
23497
+ /**
23289
23498
  * A model choice has a SCOPE, and a scope change has a workflow.
23290
23499
  *
23291
23500
  * ## The two scopes
@@ -24034,6 +24243,12 @@ var MotionEventSchema = object({
24034
24243
  /** Populated by B5 (recording playback URL for this event). */
24035
24244
  mediaUrl: string().optional(),
24036
24245
  /**
24246
+ * The FIRST trigger of an `onboard` episode, written once at open (D672).
24247
+ * Absent = not recorded (a row written before D672, or an analyzer /
24248
+ * device-activity episode) — never read as "the camera" (D393).
24249
+ */
24250
+ triggeredBy: MotionTriggeredBySchema.optional(),
24251
+ /**
24037
24252
  * One row per motion EPISODE, not one per push (D475). `null` while the
24038
24253
  * episode is still open — a further rising edge extends it in place rather
24039
24254
  * than inserting a new row. Set once, at close, to `lastOnAt - startedAt`
@@ -24527,131 +24742,6 @@ var RecentTracksQueryInput = object({
24527
24742
  /** See {@link ExcludeSourcesDoc}. */
24528
24743
  excludeSources: array(TrackSourceSchema).optional()
24529
24744
  });
24530
- /**
24531
- * A Summary (D359): the per-camera session envelope that references tracks.
24532
- * `groupShotMediaId` is the media ROW id of its group shot (`ownerKind:
24533
- * 'summary'`, served by the event-media plane at `/m/<id>`), null until the
24534
- * first frame with a member visible has been materialised (D482 — it was the
24535
- * row's composite key, which embedded the owner and could name another table's
24536
- * row once event ids became per-table rowids).
24537
- */
24538
- var SummarySchema = object({
24539
- id: string(),
24540
- deviceId: number(),
24541
- openedAt: number(),
24542
- lastActiveAt: number(),
24543
- sealedAt: number().nullable(),
24544
- memberCount: number().int().nonnegative(),
24545
- groupShotMediaId: number().int().nullable()
24546
- });
24547
- var SummariesQueryInput = object({
24548
- deviceIds: array(number()).min(1),
24549
- since: number().optional(),
24550
- until: number().optional(),
24551
- limit: number().int().min(1).max(200).default(50),
24552
- /** The same member-wise filter {@link listRecentSummaries} takes — one
24553
- * meaning of "dog" on every summary surface. */
24554
- classes: array(string().min(1).max(60)).max(40).optional()
24555
- });
24556
- var SummaryDetailSchema = object({
24557
- summary: SummarySchema,
24558
- /** Members in absorption order, oldest join first. */
24559
- members: array(object({
24560
- trackId: string(),
24561
- /**
24562
- * The track's class at the time it JOINED, or `null` when it was unresolved
24563
- * and the track no longer exists to fill it.
24564
- *
24565
- * The join, not the latest opinion: class voting can re-decide a track's
24566
- * class afterwards, and a group's composition is the history of who came
24567
- * together. A consumer counts these to badge a thumbnail — "two people and a
24568
- * dog" — rather than being handed a second, denormalised tally that would
24569
- * drift from the members it claims to describe.
24570
- */
24571
- className: string().nullable(),
24572
- /** `primary` is the one member that carries the group's identity. */
24573
- role: _enum([
24574
- "primary",
24575
- "sibling",
24576
- "child"
24577
- ]).nullable(),
24578
- joinedAt: number(),
24579
- /** Tier 1 — the sub-class (`dog`, `van`), resolved from the member's track
24580
- * at read time. Absent when nothing resolved, never an empty string. */
24581
- label: string().optional(),
24582
- /** Tier 2 — the instance: a person's name, a plate. Absent when the pipeline
24583
- * recognised nobody, and absent for a member whose track has been pruned —
24584
- * a thumbnail that names the wrong person is worse than one naming nobody. */
24585
- subLabel: string().optional()
24586
- })).readonly()
24587
- });
24588
- /**
24589
- * What a LIST of groups carries: the envelope plus what it is MADE OF.
24590
- *
24591
- * Coarse on purpose — the operator's rule is "only the rough data on the list,
24592
- * we extend when we notice we need more". Enough to draw the card ("two people
24593
- * and a dog") and no more. The MEMBERS, their names and the per-member links
24594
- * are on {@link getSummary}: shipping every member of every group so a client
24595
- * can count them turns a page of two hundred groups into a thousand records to
24596
- * draw two hundred badges.
24597
- */
24598
- var SummaryListItemSchema = object({
24599
- summary: SummarySchema,
24600
- /** Class counts, most numerous first; `className: null` is a member whose
24601
- * class never resolved, counted so the counts add up to `memberCount`. */
24602
- classes: array(object({
24603
- className: string().nullable(),
24604
- count: number().int().positive()
24605
- })).readonly()
24606
- });
24607
- var SummariesPageSchema = object({ summaries: array(SummaryListItemSchema).readonly() });
24608
- /**
24609
- * The paged feed, deliberately the SAME shape as {@link RecentTracksQueryInput}.
24610
- *
24611
- * The reel on the cameras page and the Events gallery both ride a cursor, so a
24612
- * summaries feed that could only answer "the last N for these cameras"
24613
- * (`listSummaries`) would make groups available in the timeline and nowhere
24614
- * else. Two feeds with different ordering contracts would be two ideas of what
24615
- * "newest" means, on one screen.
24616
- */
24617
- var RecentSummariesQueryInput = object({
24618
- /** Devices to merge. An empty array yields an empty page. */
24619
- deviceIds: array(number()),
24620
- /** Window lower bound on `lastActiveAt` (inclusive). */
24621
- since: number().optional(),
24622
- /** Window upper bound on `lastActiveAt` (inclusive). */
24623
- until: number().optional(),
24624
- limit: number().int().min(1).max(500).default(100),
24625
- /** Opaque continuation cursor from a previous page's `nextCursor`. */
24626
- cursor: string().optional(),
24627
- /**
24628
- * Restrict to these classes — THE SAME FIELD `listRecentTracks` takes, and
24629
- * deliberately the same name: the events filter tree emits one list of ticked
24630
- * taxonomy nodes, and a summaries feed that called it something else would
24631
- * make the operator's one filter component produce two shapes.
24632
- *
24633
- * A question about the MEMBERS: a group matches when ANY of them does. "Show
24634
- * me the arrivals with a dog" has to return the group of four people who had
24635
- * one with them; a filter on the group's own fields could only ever answer
24636
- * about its primary.
24637
- *
24638
- * Matched against all THREE tiers of a member — the class (`animal`), the
24639
- * sub-class (`dog`) and the instance (a name, a plate) — because which tier a
24640
- * ticked node lives on is the taxonomy's business, not the caller's. `dog` is
24641
- * an event kind in the tree and a tier-1 label on an `animal` track; a filter
24642
- * that read only the class would answer "animal" and never "dog".
24643
- *
24644
- * ABSENT or EMPTY means no filter — absent is not a selection of none.
24645
- */
24646
- classes: array(string().min(1).max(60)).max(40).optional()
24647
- });
24648
- var RecentSummariesPageSchema = object({
24649
- /** Ordered by (`lastActiveAt` DESC, id DESC). Same light item as
24650
- * {@link listSummaries} — one list shape, so a card renders the same
24651
- * whichever feed drew it. */
24652
- summaries: array(SummaryListItemSchema).readonly(),
24653
- nextCursor: string().nullable()
24654
- });
24655
24745
  var RecentTracksPageSchema = object({
24656
24746
  /** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
24657
24747
  tracks: array(TrackSchema).readonly(),
@@ -25189,15 +25279,6 @@ var pipelineAnalyticsCapability = {
25189
25279
  * are not included (same contract as `listTracks`).
25190
25280
  */
25191
25281
  listRecentTracks: method(RecentTracksQueryInput, RecentTracksPageSchema),
25192
- /** Newest first by `openedAt`, for a camera set, inside an optional window. */
25193
- listSummaries: method(SummariesQueryInput, SummariesPageSchema),
25194
- /**
25195
- * The PAGED feed — the reel and the Events gallery. Same cursor contract as
25196
- * {@link listRecentTracks}, so one screen cannot hold two ideas of newest.
25197
- */
25198
- listRecentSummaries: method(RecentSummariesQueryInput, RecentSummariesPageSchema),
25199
- /** One summary with its member track ids; `null` for an id nobody wrote. */
25200
- getSummary: method(object({ id: string() }), SummaryDetailSchema.nullable()),
25201
25282
  clearTracks: method(object({ deviceId: number() }), _void(), {
25202
25283
  kind: "mutation",
25203
25284
  auth: "admin"
@@ -27224,6 +27305,23 @@ var MotionSourceEnum = _enum([
27224
27305
  */
27225
27306
  var MotionSourcesSchema = array(MotionSourceEnum);
27226
27307
  /**
27308
+ * The operator-facing name of each MOTION source (D672: `onboard` = the
27309
+ * camera's sensors — its own motion plus any sensor attached to it). The wire
27310
+ * value stays `onboard`; only the label changed. `detectionSources: 'onboard'`
27311
+ * ("Camera onboard AI") and the notification source filter keep their labels.
27312
+ */
27313
+ var MOTION_SOURCE_LABELS = {
27314
+ analyzer: "Frame-diff Analyzer (motion addon)",
27315
+ onboard: "Camera sensors",
27316
+ "device-activity": "Device activity (the device says it is working)"
27317
+ };
27318
+ /** The order the motion-source picker offers them in (not the enum's order). */
27319
+ var MOTION_SOURCE_PICKER_ORDER = [
27320
+ "analyzer",
27321
+ "onboard",
27322
+ "device-activity"
27323
+ ];
27324
+ /**
27227
27325
  * Which root detector a camera runs — EXACTLY ONE.
27228
27326
  *
27229
27327
  * Deliberately the SAME vocabulary post-analysis already tags every detection
@@ -27570,7 +27668,14 @@ var RunnerCameraConfigSchema = object({
27570
27668
  */
27571
27669
  inferenceDevices: array(RunnerInferenceDeviceSchema).readonly().optional()
27572
27670
  });
27573
- 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;
27671
+ MOTION_SOURCE_PICKER_ORDER.map((value) => value === "onboard" ? {
27672
+ value,
27673
+ label: MOTION_SOURCE_LABELS[value],
27674
+ description: "The camera's own motion, plus any sensor attached to it"
27675
+ } : {
27676
+ value,
27677
+ label: MOTION_SOURCE_LABELS[value]
27678
+ }), 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;
27574
27679
  /**
27575
27680
  * Runtime load summary returned by `getLocalLoad`. Used by the orchestrator's
27576
27681
  * load-balancing levels (L2 capacity-based, L3 hardware-aware) to decide
@@ -28336,6 +28441,11 @@ var CameraStatusSchema = object({
28336
28441
  */
28337
28442
  switchedOff: array(CameraSwitchIdSchema).readonly(),
28338
28443
  /**
28444
+ * The camera's attached sensors (D672). Optional only for a status composed
28445
+ * by an orchestrator older than D672; this orchestrator always sets it.
28446
+ */
28447
+ cameraSensors: CameraSensorsStatusSchema.optional(),
28448
+ /**
28339
28449
  * Stages of the bounded fan-out that were CUT SHORT — a timeout or a
28340
28450
  * rejection — and whose block is therefore `null` because we could not
28341
28451
  * READ it, not because there is nothing there.
@@ -31807,44 +31917,6 @@ var videoclipsCapability = {
31807
31917
  }
31808
31918
  };
31809
31919
  /**
31810
- * LA tabella "quale booleano di questo tipo di device conta come ALTO", e il
31811
- * valutatore puro del suo FRONTE.
31812
- *
31813
- * Viveva dentro il builtin virtual-doorbell
31814
- * (`@camstack/system` — `builtins/doorbell/trigger-engine.ts`) e i suoi
31815
- * predicati erano privati al modulo. Il recorder ne ha bisogno per il trigger
31816
- * `RecordingTriggers.sensorDeviceIds`: copiarla avrebbe creato la SECONDA
31817
- * tabella, che diverge alla prima cap aggiunta e il cui sintomo — "il sensore
31818
- * fa suonare il campanello ma non registra" — è esattamente D62. Quindi si
31819
- * SPOSTA qui e il doorbell la ri-esporta.
31820
- *
31821
- * ⚠ NON è `DEVICE_STATE_READERS` (`catalogs/device-state-vocabulary.ts`), e le
31822
- * due non vanno unificate: quella risponde a "qual è la PAROLA di stato per una
31823
- * regola" (e include `presence`, `cover`, `alarm-panel`), questa a "qual è il
31824
- * booleano il cui FRONTE conta". Vocabolari deliberatamente diversi.
31825
- */
31826
- /**
31827
- * Known binary / switch source caps → the boolean slice field whose
31828
- * false→true rise counts as ACTIVE. Every entry is "fire on active".
31829
- * Sensors whose "active" reading is not a plain boolean (presence's string
31830
- * state, connectivity's connected flag) are deliberately excluded — a
31831
- * reconnect is not a doorbell press, and it is not a recording either.
31832
- */
31833
- var SOURCE_CAP_ACTIVE_FIELD = {
31834
- contact: "entryOpen",
31835
- binary: "on",
31836
- switch: "on",
31837
- motion: "detected",
31838
- flood: "flooded",
31839
- gas: "detected",
31840
- smoke: "detected",
31841
- "carbon-monoxide": "detected",
31842
- vibration: "detected",
31843
- tamper: "tampered"
31844
- };
31845
- /** Cap names whose presence in a device's bindings qualify it as a source. */
31846
- var SOURCE_CAPS = Object.keys(SOURCE_CAP_ACTIVE_FIELD);
31847
- /**
31848
31920
  * Doorbell button cap. Two kinds of providers coexist behind this cap
31849
31921
  * name (same pattern as `snapshot`):
31850
31922
  *
@@ -31917,7 +31989,13 @@ var doorbellCapability = {
31917
31989
  * push (`ReolinkSimpleEvent.type === 'doorbell'`). There is no
31918
31990
  * release/duration — it's a pulse.
31919
31991
  */
31920
- onPressed: { data: DoorbellPressEventSchema } },
31992
+ onPressed: {
31993
+ data: DoorbellPressEventSchema,
31994
+ fromState: {
31995
+ field: "lastPressedAt",
31996
+ on: "advance"
31997
+ }
31998
+ } },
31921
31999
  status: {
31922
32000
  schema: DoorbellStatusSchema,
31923
32001
  kind: "push"
@@ -37410,7 +37488,9 @@ var MotionOnMotionChangedDataSchema = object({
37410
37488
  detected: boolean(),
37411
37489
  timestamp: number(),
37412
37490
  source: MotionSourceEnum,
37413
- regions: array(MotionRegionSchema).readonly().optional()
37491
+ regions: array(MotionRegionSchema).readonly().optional(),
37492
+ /** Who started it (D672). Absent = the camera itself. Only `onboard` carries `sensor`. */
37493
+ triggeredBy: MotionTriggeredBySchema.optional()
37414
37494
  });
37415
37495
  var motionCapability = {
37416
37496
  name: "motion",
@@ -40772,12 +40852,21 @@ var RecordingStorageUsageSchema = object({
40772
40852
  */
40773
40853
  devicesRead: _enum(["archive", "unavailable"]).optional(),
40774
40854
  /**
40855
+ * Is the `archive` answer WHOLE (D674): the hour ledger loaded without
40856
+ * hitting its row cap, and at least one location resolved? Only then may a
40857
+ * camera ABSENT from `devices[]` be read as "no footage" — and only then is a
40858
+ * row's `oldestMs` the archive's oldest rather than the oldest of a fraction.
40859
+ * OPTIONAL: a recorder predating D674 omits it, and a consumer must read the
40860
+ * absence as `false`. A retention floor is a delete; it never guesses.
40861
+ */
40862
+ complete: boolean().optional(),
40863
+ /**
40775
40864
  * Per-physical-volume capacity. OPTIONAL, and consumers must render the rest
40776
- * of the payload without it: the hub serves this method through a BAKED
40777
- * router, so a hub whose framework train predates a change to this array
40778
- * strips it out of an answer a newer recorder happily produced. A UI that
40779
- * dereferences it unconditionally crashes the whole Storage page over a
40780
- * missing disk bar.
40865
+ * of the payload without it: a recorder that could not build it omits it. A
40866
+ * UI that dereferences it unconditionally crashes the whole Storage page over
40867
+ * a missing disk bar. (The hub's cap routers pass output through unvalidated
40868
+ * since 2026-07-11 — `cap-router-builder.ts` — so a newer recorder's fields
40869
+ * are not stripped by an older hub.)
40781
40870
  */
40782
40871
  locations: array(RecordingLocationUsageSchema).optional()
40783
40872
  });
@@ -44701,7 +44790,12 @@ Object.freeze({
44701
44790
  number: {
44702
44791
  kind: "fixed",
44703
44792
  result: ["number", "null"]
44704
- }
44793
+ },
44794
+ rose: {
44795
+ kind: "fixed",
44796
+ result: ["number", "null"]
44797
+ },
44798
+ count: NUMBER
44705
44799
  });
44706
44800
  `${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
44707
44801
  /**
@@ -48042,6 +48136,12 @@ Object.freeze({
48042
48136
  addonId: null,
48043
48137
  access: "view"
48044
48138
  },
48139
+ "deviceManager.getWrapperActivation": {
48140
+ capName: "device-manager",
48141
+ capScope: "system",
48142
+ addonId: null,
48143
+ access: "view"
48144
+ },
48045
48145
  "deviceManager.listAll": {
48046
48146
  capName: "device-manager",
48047
48147
  capScope: "system",
@@ -50316,12 +50416,6 @@ Object.freeze({
50316
50416
  addonId: null,
50317
50417
  access: "view"
50318
50418
  },
50319
- "pipelineAnalytics.getSummary": {
50320
- capName: "pipeline-analytics",
50321
- capScope: "device",
50322
- addonId: null,
50323
- access: "view"
50324
- },
50325
50419
  "pipelineAnalytics.getTrack": {
50326
50420
  capName: "pipeline-analytics",
50327
50421
  capScope: "device",
@@ -50382,12 +50476,6 @@ Object.freeze({
50382
50476
  addonId: null,
50383
50477
  access: "view"
50384
50478
  },
50385
- "pipelineAnalytics.listRecentSummaries": {
50386
- capName: "pipeline-analytics",
50387
- capScope: "device",
50388
- addonId: null,
50389
- access: "view"
50390
- },
50391
50479
  "pipelineAnalytics.listRecentTracks": {
50392
50480
  capName: "pipeline-analytics",
50393
50481
  capScope: "device",
@@ -50418,12 +50506,6 @@ Object.freeze({
50418
50506
  addonId: null,
50419
50507
  access: "view"
50420
50508
  },
50421
- "pipelineAnalytics.listSummaries": {
50422
- capName: "pipeline-analytics",
50423
- capScope: "device",
50424
- addonId: null,
50425
- access: "view"
50426
- },
50427
50509
  "pipelineAnalytics.listTrackMedia": {
50428
50510
  capName: "pipeline-analytics",
50429
50511
  capScope: "device",
@@ -53851,6 +53933,11 @@ Object.freeze({
53851
53933
  form: "single",
53852
53934
  optional: false
53853
53935
  }],
53936
+ "deviceManager.getWrapperActivation": [{
53937
+ name: "deviceId",
53938
+ form: "single",
53939
+ optional: false
53940
+ }],
53854
53941
  "deviceManager.listAll": [{
53855
53942
  name: "deviceIds",
53856
53943
  form: "array",
@@ -54588,11 +54675,6 @@ Object.freeze({
54588
54675
  form: "single",
54589
54676
  optional: true
54590
54677
  }],
54591
- "pipelineAnalytics.listRecentSummaries": [{
54592
- name: "deviceIds",
54593
- form: "array",
54594
- optional: false
54595
- }],
54596
54678
  "pipelineAnalytics.listRecentTracks": [{
54597
54679
  name: "deviceIds",
54598
54680
  form: "array",
@@ -54603,11 +54685,6 @@ Object.freeze({
54603
54685
  form: "array",
54604
54686
  optional: true
54605
54687
  }],
54606
- "pipelineAnalytics.listSummaries": [{
54607
- name: "deviceIds",
54608
- form: "array",
54609
- optional: false
54610
- }],
54611
54688
  "pipelineAnalytics.listTrackMedia": [{
54612
54689
  name: "deviceId",
54613
54690
  form: "single",