@camstack/addon-model-studio 1.1.46 → 1.1.48

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-DatYL4fO.mjs → MotionZonesSettings-nSvd3wgP.mjs} +2 -2
  2. package/dist/{PrivacyMaskSettings-B-voWing.mjs → PrivacyMaskSettings-DpUECTGc.mjs} +4 -4
  3. package/dist/{SceneMonitorEditor-B9pWKzVY.mjs → SceneMonitorEditor-BYUThwmI.mjs} +3 -3
  4. package/dist/_stub.js +147 -147
  5. package/dist/{_virtual_mf-localSharedImportMap___mfe_internal__addon_model_studio_page-DuCWAiYv.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_model_studio_page-CxnjpyLl.mjs} +4 -4
  6. package/dist/_virtual_mf___mfe_internal__addon_model_studio_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-D5YltPmo.mjs +26 -0
  7. package/dist/{hostInit-NwYsxI8A.mjs → hostInit-Dx9Oh7tu.mjs} +3 -3
  8. package/dist/model-studio.addon.js +409 -30
  9. package/dist/model-studio.addon.mjs +409 -30
  10. package/dist/{player-overlays-BpSi3fah.mjs → player-overlays-DxPiRDNZ.mjs} +1 -1
  11. package/dist/remoteEntry.js +1 -1
  12. package/dist/{responsive-CpGiOR9P.mjs → responsive-ChIDJ7ve.mjs} +1 -1
  13. package/dist/{square-BuNcSEVL.mjs → square-CpAXUT52.mjs} +1 -1
  14. package/dist/{trash-2-DgoF37KH.mjs → trash-2-siK2nOpd.mjs} +1 -1
  15. package/dist/{use-device-snapshot-pFUT6-FP.mjs → use-device-snapshot-CLLnyzyW.mjs} +1 -1
  16. package/dist/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_model_studio_page__remoteEntry_js-Ddkj3KLy.mjs → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_model_studio_page__remoteEntry_js-DZ9FPtvZ.mjs} +1 -1
  17. package/package.json +1 -1
  18. package/dist/_virtual_mf___mfe_internal__addon_model_studio_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-hvsEgbZS.mjs +0 -26
@@ -8107,6 +8107,111 @@ var CameraSwitchGroupSchema = object({
8107
8107
  fetchedAt: number()
8108
8108
  });
8109
8109
  /**
8110
+ * Per-component log CHANNELS — the gate a hot path consults, and the registry
8111
+ * an addon declares its channels in.
8112
+ *
8113
+ * ## Two axes, deliberately separated
8114
+ *
8115
+ * - **DECLARATION** — which channels exist. Only the addon knows:
8116
+ * `stream-broker` knows webrtc/ICE/RTP, `provider-reolink` knows
8117
+ * baichuan/handshake. A hand-wired central list rots at the first addition,
8118
+ * and rots silently. So a channel is declared where it is consulted, and the
8119
+ * `log-channels` capability enumerates the declarations.
8120
+ * - **VALUE** — at which level, for which scope, until when. That stays ONE
8121
+ * thing: the logging settings document on the `system` cap. Two authorities
8122
+ * over the values is the exact defect
8123
+ * `docs/design/plans/2026-08-26-logging-per-componente.md` was written to
8124
+ * remove; re-introducing it from the cure side would be grotesque.
8125
+ *
8126
+ * Nothing in this file reads a clock, an env var or a store. The registry is
8127
+ * a MIRROR: it is moved only by {@link LogChannelRegistry.apply}, called off
8128
+ * the hot path with a value somebody actually read, and by
8129
+ * {@link LogChannelRegistry.tick}, called on a timer. A store read that fails
8130
+ * never reaches here, so it can neither disarm an armed channel nor arm a
8131
+ * disarmed one (D49).
8132
+ *
8133
+ * ## The canonical call shape
8134
+ *
8135
+ * ```ts
8136
+ * if (CH_RTP.on && CH_RTP.wants(deviceId)) {
8137
+ * CH_RTP.log(logger, 'rtp subscriber added', { tags: { deviceId }, meta: { ssrc } })
8138
+ * }
8139
+ * ```
8140
+ *
8141
+ * `on` is a plain boolean FIELD — never a getter — and it is the FIRST thing
8142
+ * read. Disarmed, a call site costs one load and one branch, and the `extras`
8143
+ * object literal is never constructed because it lives inside the branch. It
8144
+ * is the same shape already proven in production at `stream-broker.ts:1650`,
8145
+ * and the same discipline `LoggingGate.allowsDestination` uses for the
8146
+ * destination floor (measured at 1.93 ns/call when off).
8147
+ *
8148
+ * ## Why a channel emits at `info`
8149
+ *
8150
+ * `loki-logging.addon.ts` pins the destination default at `info` and
8151
+ * `loki-destination.ts` drops everything below it, so a line emitted at
8152
+ * `debug` never reaches Loki and the hub's in-memory ring only holds ~35
8153
+ * minutes. A diagnostic that cannot be read an hour later is worse than no
8154
+ * diagnostic, because it looks done. {@link LogChannelGate.log} therefore
8155
+ * emits at the channel's declared level, whose schema floor is `info`.
8156
+ */
8157
+ /**
8158
+ * The level a channel writes at once armed.
8159
+ *
8160
+ * `debug` is absent ON PURPOSE and not by omission: below `info` the line does
8161
+ * not leave the process for Loki, and the whole point of arming a channel is
8162
+ * to read it later.
8163
+ */
8164
+ var LogChannelLevelSchema = _enum([
8165
+ "info",
8166
+ "warn",
8167
+ "error"
8168
+ ]);
8169
+ /**
8170
+ * What an addon declares about one channel. No value, no state — a
8171
+ * declaration is inert.
8172
+ */
8173
+ var LogChannelDescriptorSchema = object({
8174
+ /**
8175
+ * Dotted `area.thing`, unique across the workspace. `area` is conventionally
8176
+ * the addon's short name so an operator reading a channel list can tell who
8177
+ * owns it without a second lookup.
8178
+ */
8179
+ name: string().min(3).regex(/^[a-z0-9-]+(\.[a-z0-9-]+)+$/, "a channel name is dotted lower-kebab, e.g. area.thing"),
8180
+ /** One sentence: what the operator will SEE after arming it. */
8181
+ description: string().min(1),
8182
+ /** The level its lines are emitted at. Never below `info`. */
8183
+ defaultLevel: LogChannelLevelSchema,
8184
+ /**
8185
+ * Whether this channel can be narrowed to a camera.
8186
+ *
8187
+ * `true` is a PROMISE with two halves, and both must hold: the gate is
8188
+ * consulted with the numeric device id, AND every line the channel admits
8189
+ * carries `tags: { deviceId }` with that same numeric id. The second half is
8190
+ * what makes `| json | deviceId="617"` work in Loki — `loki-payload.ts`
8191
+ * keeps `deviceId` out of the stream labels for cardinality, so the tag in
8192
+ * the body is the only way to filter.
8193
+ *
8194
+ * A channel whose lines carry the device only in `meta` (or not at all) is
8195
+ * declared `false`. Declaring it `true` anyway would be a lie the UI repeats:
8196
+ * the operator narrows to one camera, sees nothing, and concludes the code
8197
+ * path was never taken.
8198
+ */
8199
+ perDevice: boolean()
8200
+ });
8201
+ /**
8202
+ * An armed window over one channel, as the document hands it to a mirror.
8203
+ *
8204
+ * A window is a DEADLINE, never a flag (ADR-0244): a channel somebody forgot
8205
+ * expires by itself, which is the one failure a boolean cannot avoid.
8206
+ */
8207
+ var LogChannelWindowSchema = object({
8208
+ channel: string().min(1),
8209
+ /** Epoch ms the window closes at. */
8210
+ armedUntilMs: number(),
8211
+ /** `null` = every camera. A non-empty list narrows to those numeric ids. */
8212
+ deviceIds: array(number().int()).readonly().nullable()
8213
+ });
8214
+ /**
8110
8215
  * Ops-log — the durable, append-only operations audit shared by the
8111
8216
  * recordings and events management surfaces.
8112
8217
  *
@@ -11681,6 +11786,35 @@ var MutationFilterSchema = object({
11681
11786
  whereBetween: record(string(), tuple([unknown(), unknown()])).optional(),
11682
11787
  whereNot: record(string(), unknown()).optional()
11683
11788
  });
11789
+ /**
11790
+ * One scalar an {@link settingsStoreCapability.methods.aggregate} call asks for.
11791
+ *
11792
+ * `as` names the slot in the result, so the SAME column may be asked twice with
11793
+ * two operations (`MIN(startMs)` and `MAX(startMs)` in one round trip) — which
11794
+ * a `Record<column, op>` shape could not express.
11795
+ */
11796
+ var AggregateFieldSchema = object({
11797
+ /** Result key. */
11798
+ as: string().min(1),
11799
+ /** Column to aggregate. Must be a real column of a declared collection. */
11800
+ field: string().min(1),
11801
+ op: _enum([
11802
+ "sum",
11803
+ "min",
11804
+ "max"
11805
+ ])
11806
+ });
11807
+ /**
11808
+ * `COUNT(*)` plus one number per requested field.
11809
+ *
11810
+ * `null` means NO ROW MATCHED, never zero: a `SUM` over an empty set and a sum
11811
+ * that really is 0 are different facts, and an accounting caller that renders
11812
+ * "0 bytes, oldest = 0" for "nothing here" reports a lie about a disk.
11813
+ */
11814
+ var AggregateResultSchema = object({
11815
+ count: number().int(),
11816
+ values: record(string(), number().nullable())
11817
+ });
11684
11818
  /** A single stored record: `{ id, data }`. */
11685
11819
  var SettingsRecordSchema = object({
11686
11820
  id: string(),
@@ -11765,6 +11899,11 @@ method(object({
11765
11899
  collection: string(),
11766
11900
  filter: QueryFilterSchema.optional()
11767
11901
  }), number()), method(object({
11902
+ namespace: string().optional(),
11903
+ collection: string(),
11904
+ fields: array(AggregateFieldSchema).readonly(),
11905
+ filter: QueryFilterSchema.optional()
11906
+ }), AggregateResultSchema), method(object({
11768
11907
  namespace: string().optional(),
11769
11908
  collection: string(),
11770
11909
  field: string(),
@@ -11881,6 +12020,11 @@ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
11881
12020
  collection: string(),
11882
12021
  filter: QueryFilterSchema.optional()
11883
12022
  }), number(), { auth: "admin" }), method(object({
12023
+ namespace: string().optional(),
12024
+ collection: string(),
12025
+ fields: array(AggregateFieldSchema).readonly(),
12026
+ filter: QueryFilterSchema.optional()
12027
+ }), AggregateResultSchema, { auth: "admin" }), method(object({
11884
12028
  namespace: string().optional(),
11885
12029
  collection: string(),
11886
12030
  field: string(),
@@ -12442,24 +12586,6 @@ method(_void(), _void(), { kind: "mutation" }), method(_void(), _void(), { kind:
12442
12586
  kind: "mutation",
12443
12587
  auth: "admin"
12444
12588
  });
12445
- /**
12446
- * Device Manager capability — hub-side singleton that unifies device persistence,
12447
- * live registry access, and all management operations into a single tRPC surface.
12448
- *
12449
- * Replaces:
12450
- * - `device-persistence` capability (persistence methods absorbed here)
12451
- * - `device-management.router.ts` (deleted in Phase 2)
12452
- * - `device-ops.router.ts` (compat layer — deleted; device-provider ops absorbed here)
12453
- *
12454
- * All device provider addons (rtsp, onvif, frigate, …) are hub-local: they may
12455
- * fork into separate processes but never run on remote cluster agents. Therefore:
12456
- * - No nodeId routing needed — this is a pure hub singleton.
12457
- * - The hub's DeviceRegistry is the single source of truth for all live devices.
12458
- * - No shadow registry or cross-node aggregation required.
12459
- *
12460
- * Forked workers register devices back to the hub via `ctx.devices`
12461
- * (DeviceManagerApi → ctx.api.deviceManager.registerDevice), same as today.
12462
- */
12463
12589
  /** One child-placement directive on a container's `childLayout`. Structurally
12464
12590
  * identical to `ChildLayoutEntry` in `device-management.ts` — the cap wire
12465
12591
  * shape for the same field. The child is identified by its re-sync-stable
@@ -12828,7 +12954,7 @@ method(object({
12828
12954
  * it answers today and the caller filters as it already does.
12829
12955
  */
12830
12956
  deviceIds: array(number()).optional()
12831
- }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), DeviceInfoSchema.nullable()), method(object({ parentDeviceId: number() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), object({
12957
+ }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), DeviceInfoSchema.nullable()), method(object({ parentDeviceId: number() }), array(DeviceInfoSchema)), method(object({ parentDeviceIds: array(number()).max(256) }), record(string(), array(DeviceInfoSchema))), method(object({ deviceId: number() }), object({
12832
12958
  mode: LinkedDevicesModeSchema,
12833
12959
  devices: array(LinkedDeviceSchema)
12834
12960
  })), method(object({ deviceIds: array(number()) }), array(LinkedDevicesForDeviceSchema)), method(object({ deviceId: number() }), array(StreamSourceEntrySchema$1)), method(object({ deviceId: number() }), array(ConfigEntrySchema)), method(object({ deviceId: number() }), ConfigUISchemaOutput), method(object({
@@ -13552,6 +13678,59 @@ method(LlmGenerateBaseInputSchema, LlmGenerateResultSchema, { kind: "mutation" }
13552
13678
  kind: "mutation",
13553
13679
  auth: "admin"
13554
13680
  });
13681
+ /**
13682
+ * `log-channels` — the capability an addon DECLARES its diagnostic channels
13683
+ * through. It stores nothing.
13684
+ *
13685
+ * ## Why a capability at all, and why this shape
13686
+ *
13687
+ * Which channels exist is knowledge only the addon has: `stream-broker` knows
13688
+ * webrtc/ICE/RTP, `provider-reolink` knows baichuan/handshake. A central list
13689
+ * maintained by hand rots at the first addition and rots INVISIBLY — nothing
13690
+ * fails, an operator just never sees the channel somebody added. So the list
13691
+ * is assembled from declarations at runtime.
13692
+ *
13693
+ * The shape is copied from `log-destination.cap.ts`, which already does
13694
+ * exactly this job: `mode: 'collection'`, `internal: true`,
13695
+ * `mount: { kind: 'skip' }` — no tRPC route, no generated hooks — while
13696
+ * `addons.listCapabilityProviders` still enumerates it, and the hub's
13697
+ * `CapabilityRegistry` still holds an RPC proxy per provider so a forked
13698
+ * runner's declarations reach hub-main over the transport that already exists.
13699
+ * No new UDS message, no second registry.
13700
+ *
13701
+ * ## What it deliberately does NOT own
13702
+ *
13703
+ * The VALUES — which channel is armed, for which cameras, until when — live in
13704
+ * ONE place: the logging settings document on the `system` cap
13705
+ * (`getLoggingSettings` / `setLoggingSettings`). Two authorities over the same
13706
+ * value is the defect the plan behind this work exists to remove, and
13707
+ * `setRequestCensus` was retired (D245) rather than allowed to be a second
13708
+ * one. {@link logChannelsCapability} therefore has no getter for a level, no
13709
+ * setter for a window and no persistence of any kind.
13710
+ *
13711
+ * ## Why `apply` is here even so
13712
+ *
13713
+ * The gate lives in the addon's PROCESS; the document lives in hub-main. Some
13714
+ * seam has to carry the value from the authority to the mirror, and a channel
13715
+ * that cannot be reached is precisely the dead knob this whole slice exists to
13716
+ * make impossible (D62 — `audioThresholdDbfs`, the HA entities with no source).
13717
+ * `apply` is that seam and nothing more: it writes an in-memory mirror, it
13718
+ * persists nothing, it is never the source of a value, and it is called only
13719
+ * with a set the hub actually read (D49 — a read that fails does not call it
13720
+ * at all, so no channel is silently disarmed by a bad read).
13721
+ */
13722
+ /** What `apply` reports back — enough to log, not enough to be a second state. */
13723
+ var LogChannelApplyResultSchema = object({
13724
+ /** How many declared channels are armed in this process after the call. */
13725
+ armed: number().int().min(0),
13726
+ /**
13727
+ * Names the document armed that this process does not declare. Reported
13728
+ * rather than swallowed: a name here is either a typo or an addon that has
13729
+ * not booted, and both deserve a line instead of silence.
13730
+ */
13731
+ unknown: array(string()).readonly()
13732
+ });
13733
+ method(_void(), array(LogChannelDescriptorSchema).readonly()), method(object({ windows: array(LogChannelWindowSchema).readonly() }), LogChannelApplyResultSchema, { kind: "mutation" });
13555
13734
  var LogLevelSchema = _enum([
13556
13735
  "debug",
13557
13736
  "info",
@@ -26813,17 +26992,60 @@ var SetSiteLocationInputSchema = object({
26813
26992
  longitude: number().min(-180).max(180)
26814
26993
  }).nullable();
26815
26994
  /**
26816
- * One `(procedure, user-agent, ip, principal)` tuple of the HTTP request
26995
+ * The TRANSPORT a call arrived on.
26996
+ *
26997
+ * Every counted call carries exactly one of these, and `unknown` is a PLANE
26998
+ * rather than a gap: a plane that cannot attribute a call declares it here, so
26999
+ * the call lands in a named bucket instead of vanishing. `planes` summing to
27000
+ * `procedureCalls` is what makes "the sum of the planes explains the total"
27001
+ * checkable rather than asserted.
27002
+ *
27003
+ * - `http` — the Fastify tRPC plugin (`/trpc/*`), one context per request.
27004
+ * - `ws` — `applyWSSHandler`, counted per OPERATION rather than per
27005
+ * connection; the viewer talks to the hub over `wsLink`
27006
+ * exclusively, so this is the plane the HTTP census could not see.
27007
+ * - `mesh` — the in-process `$core-caps` bridge (`createCaller`), which
27008
+ * never touches a socket and therefore never touched a census.
27009
+ * - `unknown` — counted, plane undecidable. No hook produces it today, and
27010
+ * that is exactly what its `0` asserts: every plane the hub has can name
27011
+ * itself. It is an output bucket, never a knob — a call that arrives on a
27012
+ * plane nobody instrumented lands here instead of vanishing from the total.
27013
+ */
27014
+ var TransportPlaneSchema = _enum([
27015
+ "http",
27016
+ "ws",
27017
+ "mesh",
27018
+ "unknown"
27019
+ ]);
27020
+ /**
27021
+ * Calls per plane. Every key is always present, `0` included — an absent plane
27022
+ * reads as "not instrumented", which is the one thing this census must never
27023
+ * make an operator wonder about.
27024
+ */
27025
+ var TransportPlaneCountsSchema = object({
27026
+ http: number(),
27027
+ ws: number(),
27028
+ mesh: number(),
27029
+ unknown: number()
27030
+ });
27031
+ /**
27032
+ * One `(plane, procedure, user-agent, ip, principal)` tuple of the transport
26817
27033
  * census. `principal` is the DERIVED identity (`apocaliss92 (admin)`,
26818
27034
  * `scoped:1a2b3c4d (scoped-token)`, `anonymous`) that the tRPC error log
26819
27035
  * already prints - never a token, never an `Authorization` header.
27036
+ *
27037
+ * `subscriptions` is counted APART from `calls`: a subscription is opened once
27038
+ * and lives for hours, so folding it into a call count makes one long-lived
27039
+ * stream look like a storm.
26820
27040
  */
26821
27041
  var RequestCensusGroupSchema = object({
27042
+ plane: TransportPlaneSchema,
26822
27043
  procedure: string(),
26823
27044
  userAgent: string(),
26824
27045
  ip: string(),
26825
27046
  principal: string(),
26826
27047
  calls: number(),
27048
+ subscriptions: number(),
26827
27049
  perMin: number()
26828
27050
  });
26829
27051
  /**
@@ -26836,6 +27058,14 @@ var RequestCensusGroupSchema = object({
26836
27058
  var RequestCensusProcedureSchema = object({
26837
27059
  procedure: string(),
26838
27060
  calls: number(),
27061
+ /**
27062
+ * The same total, split by transport. THIS is the row that answers the
27063
+ * question the census exists for: one look at `deviceManager.listAll` says
27064
+ * which plane carried the 4 960, without joining two log lines by eye.
27065
+ */
27066
+ planes: TransportPlaneCountsSchema,
27067
+ /** Subscription STARTS on this procedure. Never folded into `calls`. */
27068
+ subscriptions: number(),
26839
27069
  perMin: number()
26840
27070
  });
26841
27071
  /**
@@ -26863,14 +27093,45 @@ var RequestCensusStatusSchema = object({
26863
27093
  */
26864
27094
  procedureCalls: number(),
26865
27095
  /**
27096
+ * `procedureCalls` split by transport. The four keys sum to
27097
+ * `procedureCalls` by construction - {@link RequestCensusSnapshotSchema}'s
27098
+ * `planesExplainTotal` is that identity, checked rather than assumed.
27099
+ */
27100
+ planes: TransportPlaneCountsSchema,
27101
+ /**
27102
+ * True iff `planes` sums to `procedureCalls`. False means a call was counted
27103
+ * on no plane at all - which is a RESULT (a plane is missing from the
27104
+ * instrument), not a failure, and it has to be visible to be read as one.
27105
+ */
27106
+ planesExplainTotal: boolean(),
27107
+ /**
26866
27108
  * tRPC WebSocket connections opened during the window. NOT calls - the WS
26867
- * transport resolves one context per connection - but the number that says
26868
- * whether a plane this census cannot see was busy while HTTP was quiet.
27109
+ * adapter resolves one context per connection - kept because a plane's call
27110
+ * count of zero against 37 open connections says something different from a
27111
+ * plane with no connections at all.
26869
27112
  */
26870
27113
  wsConnections: number(),
27114
+ /**
27115
+ * Client frames the WS plane looked at. `wsMessages` far above
27116
+ * `planes.ws + subscriptions` means most traffic is not operations
27117
+ * (keepalives, connection params) - which is itself an answer.
27118
+ */
27119
+ wsMessages: number(),
27120
+ /**
27121
+ * Subscription STARTS across every plane, excluded from `procedureCalls` on
27122
+ * purpose: one live-events stream opened at boot and held for six hours is
27123
+ * one subscription, and counting it as a call would let a quiet plane
27124
+ * masquerade as the storm.
27125
+ */
27126
+ subscriptions: number(),
27127
+ /** `subscription.stop` frames. Starts minus stops is what is still open. */
27128
+ subscriptionStops: number(),
26871
27129
  distinctGroups: number(),
26872
- /** Calls counted in the totals whose group attribution was shed at the
26873
- * cardinality bound. */
27130
+ /**
27131
+ * Operations counted in the totals whose CALLER attribution was shed at the
27132
+ * cardinality bound. Unrelated to the `unknown` PLANE: these calls know
27133
+ * which transport they arrived on, they just lost their group row.
27134
+ */
26874
27135
  unattributedCalls: number(),
26875
27136
  procedures: array(RequestCensusProcedureSchema).readonly(),
26876
27137
  groups: array(RequestCensusGroupSchema).readonly()
@@ -26893,10 +27154,11 @@ var DiagnosticIdSchema = _enum(["request-census"]);
26893
27154
  * The layers of the level hierarchy, general → specific. The most specific
26894
27155
  * layer that carries an explicit value wins.
26895
27156
  *
26896
- * `component` is DECLARED and not yet resolvable: the per-component channels
26897
- * are a later slice of the same plan, and a `levelSource` enum that has to
26898
- * grow later would force every consumer of this document to change with it.
26899
- * Nothing returns `component` today.
27157
+ * `component` became RESOLVABLE on 2026-08-27: a component is a declared log
27158
+ * CHANNEL (`stream-broker.webrtc`, `provider-reolink.baichuan`), named by
27159
+ * `scopeComponent`. It was declared-but-dark in the first slice precisely so
27160
+ * that turning it on would not force every consumer of this document to widen
27161
+ * a `levelSource` enum — which is what has now not happened.
26900
27162
  */
26901
27163
  var LoggingScopeKindSchema = _enum([
26902
27164
  "cluster",
@@ -26923,6 +27185,14 @@ var LoggingLevelLayerSchema = object({
26923
27185
  scope: LoggingScopeKindSchema,
26924
27186
  /** The node this layer speaks for; `null` on the cluster layer. */
26925
27187
  nodeId: string().nullable(),
27188
+ /**
27189
+ * The declared channel this layer speaks for; `null` on every layer but
27190
+ * `component`. Never folded into `nodeId`: a component level is CLUSTER-WIDE
27191
+ * by design — the convention this repo settled on is one orchestrator-wide
27192
+ * setting, never per node (D52) — so a component layer that carried a node
27193
+ * would invite a per-node copy of a value that has no per-node meaning.
27194
+ */
27195
+ component: string().nullable(),
26926
27196
  /** Explicitly set here, or `null` when this layer inherits. */
26927
27197
  level: LogLevelSchema$1.nullable()
26928
27198
  });
@@ -26964,6 +27234,49 @@ var DiagnosticWindowPatchSchema = object({
26964
27234
  reportEveryMs: number().int().positive().optional()
26965
27235
  });
26966
27236
  /**
27237
+ * A channel ARMED, as the document reports it.
27238
+ *
27239
+ * `armMs` is not echoed back: what an operator needs to see is the deadline
27240
+ * and the time left, because a diagnostic left running is itself an incident
27241
+ * and "armed for 10 minutes" said an hour ago is not an answer.
27242
+ */
27243
+ var LogChannelWindowStateSchema = object({
27244
+ channel: string(),
27245
+ armed: boolean(),
27246
+ /** Epoch ms the window closes at. 0 when disarmed. */
27247
+ armedUntilMs: number(),
27248
+ /** Ms left before it expires on its own. 0 when disarmed. */
27249
+ remainingMs: number(),
27250
+ /**
27251
+ * The cameras it is narrowed to, or `null` for every camera.
27252
+ *
27253
+ * A channel declared `perDevice: false` can only ever report `null` here:
27254
+ * its lines do not carry `tags: { deviceId }`, so narrowing them would
27255
+ * produce a filter that silently matches nothing. The server REFUSES such a
27256
+ * patch rather than quietly widening it — ignoring the request would teach
27257
+ * the operator that per-camera filtering works on that channel when it does
27258
+ * not.
27259
+ */
27260
+ deviceIds: array(number().int()).readonly().nullable()
27261
+ });
27262
+ /**
27263
+ * `armMs: 0` DISARMS. Same grammar as {@link DiagnosticWindowPatchSchema}, and
27264
+ * for the same reason: a channel is a window with a deadline, never a switch.
27265
+ */
27266
+ var LogChannelWindowPatchSchema = object({
27267
+ channel: string().min(1),
27268
+ armMs: number().int().min(0),
27269
+ /**
27270
+ * Narrow to these numeric device ids. Absent or `null` = every camera.
27271
+ *
27272
+ * Numeric because the repo's own rule makes it possible: every log line
27273
+ * about a device carries `tags: { deviceId }` with the numeric id. That rule
27274
+ * was paid for with a 22% thumbnail gap and a 3-hour media blackout both
27275
+ * diagnosed by hand, and this is the first thing that collects on it.
27276
+ */
27277
+ deviceIds: array(number().int()).readonly().nullable().optional()
27278
+ });
27279
+ /**
26967
27280
  * A PATCH, and patches MERGE.
26968
27281
  *
26969
27282
  * A field absent from the patch is left exactly as it was — arming a
@@ -26982,7 +27295,14 @@ var LoggingSettingsPatchSchema = object({
26982
27295
  * Only the diagnostics NAMED here change. An armed window that is not listed
26983
27296
  * keeps running — a patch is never a full replacement.
26984
27297
  */
26985
- diagnostics: array(DiagnosticWindowPatchSchema).readonly().optional()
27298
+ diagnostics: array(DiagnosticWindowPatchSchema).readonly().optional(),
27299
+ /**
27300
+ * Only the channels NAMED here change. An armed channel that is not listed
27301
+ * keeps running — same rule as `diagnostics`, because a patch that silently
27302
+ * disarmed the channels it did not mention would make the Levels page and
27303
+ * the Diagnostics page fight over the same value.
27304
+ */
27305
+ channels: array(LogChannelWindowPatchSchema).readonly().optional()
26986
27306
  });
26987
27307
  /**
26988
27308
  * Which LAYER of the hierarchy is addressed. Absent = the cluster layer.
@@ -26995,9 +27315,22 @@ var LoggingSettingsPatchSchema = object({
26995
27315
  * authority over the whole hierarchy and answers for every layer, so the
26996
27316
  * layer selector needs a name the transport does not already own.
26997
27317
  */
26998
- var GetLoggingSettingsInputSchema = object({ scopeNodeId: string().optional() });
27318
+ var GetLoggingSettingsInputSchema = object({
27319
+ scopeNodeId: string().optional(),
27320
+ /**
27321
+ * The declared CHANNEL this document is addressed at, when the caller wants
27322
+ * the `component` layer. Absent = the node/cluster hierarchy only.
27323
+ *
27324
+ * Naming it separately rather than overloading `scopeNodeId` keeps the two
27325
+ * axes from collapsing: a component level is cluster-wide, a node level is
27326
+ * not, and one selector for both would make "which of these two did I just
27327
+ * set" unanswerable — the exact ambiguity `explicit` exists to remove.
27328
+ */
27329
+ scopeComponent: string().optional()
27330
+ });
26999
27331
  var SetLoggingSettingsInputSchema = object({
27000
27332
  scopeNodeId: string().optional(),
27333
+ scopeComponent: string().optional(),
27001
27334
  patch: LoggingSettingsPatchSchema
27002
27335
  });
27003
27336
  /**
@@ -27012,9 +27345,20 @@ var SetLoggingSettingsInputSchema = object({
27012
27345
  var LoggingSettingsStateSchema = object({
27013
27346
  /** The layer this document was read at. `null` = the cluster layer. */
27014
27347
  scopeNodeId: string().nullable(),
27348
+ /** The channel this document was read at. `null` = no component layer. */
27349
+ scopeComponent: string().nullable(),
27015
27350
  effective: LoggingEffectiveSchema,
27016
27351
  explicit: LoggingExplicitSchema,
27017
27352
  activeWindows: array(DiagnosticWindowSchema).readonly(),
27353
+ /**
27354
+ * Every channel the cluster's addons DECLARE, gathered from the
27355
+ * `log-channels` providers. Not stored anywhere: assembled per read, so a
27356
+ * channel added by a redeployed addon appears without anybody editing a
27357
+ * list, and a channel whose addon is gone stops being offered.
27358
+ */
27359
+ channels: array(LogChannelDescriptorSchema).readonly(),
27360
+ /** The channels ARMED right now, each with its deadline. */
27361
+ activeChannels: array(LogChannelWindowStateSchema).readonly(),
27018
27362
  persisted: boolean()
27019
27363
  });
27020
27364
  method(_void(), FeatureManifestSchema), method(_void(), HealthStatusSchema), method(_void(), FeatureManifestSchema), method(_void(), array(NetworkAddressSchema).readonly()), method(_void(), unknown().nullable(), { auth: "admin" }), method(record(string(), unknown()), _null(), {
@@ -28591,6 +28935,12 @@ Object.freeze({
28591
28935
  addonId: null,
28592
28936
  access: "view"
28593
28937
  },
28938
+ "dataStoreProvider.aggregate": {
28939
+ capName: "data-store-provider",
28940
+ capScope: "system",
28941
+ addonId: null,
28942
+ access: "view"
28943
+ },
28594
28944
  "dataStoreProvider.count": {
28595
28945
  capName: "data-store-provider",
28596
28946
  capScope: "system",
@@ -29005,6 +29355,12 @@ Object.freeze({
29005
29355
  addonId: null,
29006
29356
  access: "view"
29007
29357
  },
29358
+ "deviceManager.getChildrenBatch": {
29359
+ capName: "device-manager",
29360
+ capScope: "system",
29361
+ addonId: null,
29362
+ access: "view"
29363
+ },
29008
29364
  "deviceManager.getConfigSchema": {
29009
29365
  capName: "device-manager",
29010
29366
  capScope: "system",
@@ -30055,6 +30411,18 @@ Object.freeze({
30055
30411
  addonId: null,
30056
30412
  access: "create"
30057
30413
  },
30414
+ "logChannels.apply": {
30415
+ capName: "log-channels",
30416
+ capScope: "system",
30417
+ addonId: null,
30418
+ access: "create"
30419
+ },
30420
+ "logChannels.list": {
30421
+ capName: "log-channels",
30422
+ capScope: "system",
30423
+ addonId: null,
30424
+ access: "view"
30425
+ },
30058
30426
  "logDestination.query": {
30059
30427
  capName: "log-destination",
30060
30428
  capScope: "system",
@@ -32209,6 +32577,12 @@ Object.freeze({
32209
32577
  addonId: null,
32210
32578
  access: "create"
32211
32579
  },
32580
+ "settingsStore.aggregate": {
32581
+ capName: "settings-store",
32582
+ capScope: "system",
32583
+ addonId: null,
32584
+ access: "view"
32585
+ },
32212
32586
  "settingsStore.count": {
32213
32587
  capName: "settings-store",
32214
32588
  capScope: "system",
@@ -33788,6 +34162,11 @@ Object.freeze({
33788
34162
  form: "single",
33789
34163
  optional: false
33790
34164
  }],
34165
+ "deviceManager.getChildrenBatch": [{
34166
+ name: "parentDeviceIds",
34167
+ form: "array",
34168
+ optional: false
34169
+ }],
33791
34170
  "deviceManager.getConfigSchema": [{
33792
34171
  name: "deviceId",
33793
34172
  form: "single",
@@ -1,5 +1,5 @@
1
1
  import { h as e, l as t, u as n, y as r } from "./_virtual_mf___mfe_internal__addon_model_studio_page__loadShare__react__loadShare__.js-DJDHChgO.mjs";
2
- import { o as i, s as a } from "./responsive-CpGiOR9P.mjs";
2
+ import { o as i, s as a } from "./responsive-ChIDJ7ve.mjs";
3
3
  import { n as o, r as s, t as c } from "./_virtual_mf___mfe_internal__addon_model_studio_page__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.js-ds_Ehzaa.mjs";
4
4
  var l = a("chevron-down", [["path", {
5
5
  d: "m6 9 6 6 6-6",
@@ -1,2 +1,2 @@
1
- import { n as e, t } from "./virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_model_studio_page__remoteEntry_js-Ddkj3KLy.mjs";
1
+ import { n as e, t } from "./virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_model_studio_page__remoteEntry_js-DZ9FPtvZ.mjs";
2
2
  export { t as get, e as init };
@@ -1,6 +1,6 @@
1
1
  import { c as e, g as t, h as n, l as r, n as i, p as a, r as o, t as s, u as c, y as l } from "./_virtual_mf___mfe_internal__addon_model_studio_page__loadShare__react__loadShare__.js-DJDHChgO.mjs";
2
2
  import "./_virtual_mf___mfe_internal__addon_model_studio_page__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.js-ds_Ehzaa.mjs";
3
- import { n as u } from "./_virtual_mf___mfe_internal__addon_model_studio_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-hvsEgbZS.mjs";
3
+ import { n as u } from "./_virtual_mf___mfe_internal__addon_model_studio_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-D5YltPmo.mjs";
4
4
  //#region ../ui-library/node_modules/lucide-react/dist/esm/shared/src/utils/mergeClasses.js
5
5
  l();
6
6
  var d = (...e) => e.filter((e, t, n) => !!e && e.trim() !== "" && n.indexOf(e) === t).join(" ").trim(), f = (e) => e.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase(), p = (e) => e.replace(/^([A-Z])|[\s-_]+(\w)/g, (e, t, n) => n ? n.toUpperCase() : t.toLowerCase()), m = (e) => {
@@ -1,4 +1,4 @@
1
- import { s as e } from "./responsive-CpGiOR9P.mjs";
1
+ import { s as e } from "./responsive-ChIDJ7ve.mjs";
2
2
  var t = e("eye-off", [
3
3
  ["path", {
4
4
  d: "M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49",
@@ -1,4 +1,4 @@
1
- import { s as e } from "./responsive-CpGiOR9P.mjs";
1
+ import { s as e } from "./responsive-ChIDJ7ve.mjs";
2
2
  var t = e("trash-2", [
3
3
  ["path", {
4
4
  d: "M10 11v6",
@@ -1,5 +1,5 @@
1
1
  import { c as e, h as t, p as n, y as r } from "./_virtual_mf___mfe_internal__addon_model_studio_page__loadShare__react__loadShare__.js-DJDHChgO.mjs";
2
- import { s as i } from "./responsive-CpGiOR9P.mjs";
2
+ import { s as i } from "./responsive-ChIDJ7ve.mjs";
3
3
  var a = i("camera", [["path", {
4
4
  d: "M13.997 4a2 2 0 0 1 1.76 1.05l.486.9A2 2 0 0 0 18.003 7H20a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V9a2 2 0 0 1 2-2h1.997a2 2 0 0 0 1.759-1.048l.489-.904A2 2 0 0 1 10.004 4z",
5
5
  key: "18u6gg"
@@ -2753,7 +2753,7 @@ async function rr(e) {
2753
2753
  }
2754
2754
  }
2755
2755
  async function ir() {
2756
- return tr ||= rr(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_model_studio_page-DuCWAiYv.mjs")).catch((e) => {
2756
+ return tr ||= rr(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_model_studio_page-CxnjpyLl.mjs")).catch((e) => {
2757
2757
  throw tr = void 0, e;
2758
2758
  }), tr;
2759
2759
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-model-studio",
3
- "version": "1.1.46",
3
+ "version": "1.1.48",
4
4
  "description": "Custom detection model registry, conversion & distribution for CamStack",
5
5
  "keywords": [
6
6
  "camstack",