@camstack/addon-osd-manager 0.1.123 → 0.1.124

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 (19) hide show
  1. package/dist/{MotionZonesSettings-DN5iDMeX.mjs → MotionZonesSettings-DOFOB5MX.mjs} +2 -2
  2. package/dist/{PrivacyMaskSettings-DVZjIN6W.mjs → PrivacyMaskSettings-9rCXAZlR.mjs} +4 -4
  3. package/dist/{SceneMonitorEditor-vd5ui8yS.mjs → SceneMonitorEditor-D2ATIIZD.mjs} +3 -3
  4. package/dist/_stub.js +12 -12
  5. package/dist/{_virtual_mf-localSharedImportMap___mfe_internal__addon_osd_manager_page-BUn-8ukN.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_osd_manager_page-B2cBM7jE.mjs} +3 -3
  6. package/dist/_virtual_mf___mfe_internal__addon_osd_manager_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-BK-eslgm.mjs +26 -0
  7. package/dist/addon-osd-manager.css +1 -1
  8. package/dist/{hostInit-B0QYXY-C.mjs → hostInit-Du2Me1GR.mjs} +2 -2
  9. package/dist/index.js +383 -18
  10. package/dist/index.mjs +383 -18
  11. package/dist/{player-overlays-CnOtnn9E.mjs → player-overlays-CMeXfcep.mjs} +1 -1
  12. package/dist/remoteEntry.js +1 -1
  13. package/dist/{responsive-BJ6OUcwu.mjs → responsive-CC0j2h-d.mjs} +1 -1
  14. package/dist/{scene-monitor-copy-CbOCxWBI.mjs → scene-monitor-copy-CjiHJ4pT.mjs} +1 -1
  15. package/dist/{square-C85XpRsl.mjs → square-hvOcBhdH.mjs} +1 -1
  16. package/dist/{trash-2-RZb81dMj.mjs → trash-2-rb-x3jwf.mjs} +1 -1
  17. package/dist/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_osd_manager_page__remoteEntry_js-BYA-5ZRu.mjs → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_osd_manager_page__remoteEntry_js-D8j_yb3G.mjs} +1 -1
  18. package/package.json +1 -1
  19. package/dist/_virtual_mf___mfe_internal__addon_osd_manager_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-BzMsLBUL.mjs +0 -26
package/dist/index.mjs CHANGED
@@ -5359,7 +5359,7 @@ var ZodIssueCode = {
5359
5359
  var ZodFirstPartyTypeKind;
5360
5360
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5361
5361
  //#endregion
5362
- //#region ../types/dist/sleep-CiR4z7r9.mjs
5362
+ //#region ../types/dist/sleep-CopaBJss.mjs
5363
5363
  /**
5364
5364
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5365
5365
  * window to float samples (D455).
@@ -5559,6 +5559,12 @@ Object.fromEntries([
5559
5559
  icon: "circle-dot",
5560
5560
  order: 40
5561
5561
  },
5562
+ {
5563
+ id: "clips",
5564
+ label: "Clips",
5565
+ icon: "clapperboard",
5566
+ order: 41
5567
+ },
5562
5568
  {
5563
5569
  id: "engine",
5564
5570
  label: "Inference Engine",
@@ -15936,14 +15942,30 @@ var deviceManagerCapability = {
15936
15942
  */
15937
15943
  getAllBindings: method(object({}), array(DeviceBindingsForDeviceSchema)),
15938
15944
  /**
15939
- * Activate (or deactivate) a wrapper addon for a (device, cap) pair.
15940
- * Persists the binding via ctx.settings. active=false clears the wrapper
15941
- * (falls back to native if registered).
15945
+ * Activate (or deactivate) a wrapper addon — or ONE of its sources — for a
15946
+ * (device, cap) pair.
15947
+ *
15948
+ * Persists the binding via ctx.settings; `active: false` on a SINGLETON cap
15949
+ * clears the wrapper (falling back to native if one is registered). On a
15950
+ * COLLECTION cap it adds to the per-device DENY set instead, and the
15951
+ * wrapper binding is left exactly as it was — a cap with several sources
15952
+ * has no "which one" for `getBindings` to answer (D556).
15953
+ *
15954
+ * `sourceId` is what makes the switch match its label. One addon can serve
15955
+ * several of a device's sources (`addon-provider-reolink` answers a hub
15956
+ * child with `native:reolink:onboard` AND `native:reolink:hub`), so a
15957
+ * toggle keyed by addon would turn off both while saying it turned off one
15958
+ * — the D62 defect with the polarity reversed (D557). Naming the source
15959
+ * denies exactly that source. OMITTING it keeps the cap-wide meaning
15960
+ * D556 shipped: every source this addon serves for this device, which is
15961
+ * also how a deny entry persisted before the re-key is still read.
15942
15962
  */
15943
15963
  setWrapperActive: method(object({
15944
15964
  deviceId: number(),
15945
15965
  capName: string(),
15946
15966
  wrapperAddonId: string(),
15967
+ /** The `ClipSource.source` id to toggle. Absent = all of the addon's. */
15968
+ sourceId: string().optional(),
15947
15969
  active: boolean()
15948
15970
  }), _void(), {
15949
15971
  kind: "mutation",
@@ -27105,10 +27127,9 @@ var ServerBootModeSchema = _enum([
27105
27127
  * - `idle` / `checking` / `staging` — steady / in-flight registry work.
27106
27128
  * - `pending-restart` — a version is staged and the node has NOT yet
27107
27129
  * restarted onto it (still running the OLD version).
27108
- * - `awaiting-confirmation` — the node HAS restarted onto the staged version
27109
- * (it is the active probation boot) and is waiting to confirm boot-health.
27110
- * Apply/rollback are refused in this state and the node must NOT be
27111
- * manually restarted, or the probation boot auto-rolls-back.
27130
+ * - `awaiting-confirmation` — RETIRED with the probation boot (single-copy
27131
+ * collapse, 2026-07-18). Kept in the enum so an older client still parses;
27132
+ * no provider emits it.
27112
27133
  */
27113
27134
  var ServerUpdateStateSchema = _enum([
27114
27135
  "idle",
@@ -27197,12 +27218,35 @@ var ServerRollbackInfoSchema = object({
27197
27218
  var ServerPackageStatusSchema = object({
27198
27219
  /** Root package name (`@camstack/server` on the hub). */
27199
27220
  packageName: string(),
27200
- /** Version of the code the running process ACTUALLY loaded. */
27221
+ /**
27222
+ * Version of the code THIS PROCESS loaded — captured once, at boot, from the
27223
+ * package.json of the copy the code was loaded from, and never re-read. A
27224
+ * copy replaced on disk under a live process must not move this number;
27225
+ * that divergence is what `installedVersion` is for. Before 2026-09-20 this
27226
+ * was a lazy disk read that would have followed such a swap silently.
27227
+ */
27201
27228
  runningVersion: string().nullable(),
27202
27229
  /** Node.js runtime version the node's process runs on (`process.versions.node`). */
27203
27230
  nodeRuntimeVersion: string().nullable(),
27204
27231
  /** Active data-dir root version; null when booted from seed/workspace. */
27205
27232
  activeVersion: string().nullable(),
27233
+ /**
27234
+ * Version of the root package in the data-root `current/` copy RIGHT NOW —
27235
+ * what the next boot would load if nothing is staged. Normally equal to
27236
+ * `runningVersion`; differs only when the copy on disk changed under the
27237
+ * live process. `null` when there is no data-root copy (baked seed or
27238
+ * workspace boot). Optional for version skew: an older provider omits it.
27239
+ */
27240
+ installedVersion: string().nullable().optional(),
27241
+ /**
27242
+ * True when the code that would run after a restart is NOT the code running
27243
+ * now: a version is staged (`pendingVersion`), or `installedVersion` differs
27244
+ * from `runningVersion`. Derived on every read, never stored. This is the
27245
+ * one field that lets an operator or a script say "1.2.353 is installed and
27246
+ * will run after a restart" instead of reading it off a number that means
27247
+ * "installed". Optional for version skew.
27248
+ */
27249
+ restartRequired: boolean().optional(),
27206
27250
  /** N-1 version kept for rollback; null when no previous version exists. */
27207
27251
  previousVersion: string().nullable(),
27208
27252
  /** Version of the immutable baked seed closure (image fallback). */
@@ -27237,19 +27281,71 @@ var ServerPackageStatusSchema = object({
27237
27281
  });
27238
27282
  var ServerUpdateCheckResultSchema = object({
27239
27283
  packageName: string(),
27284
+ /** Same meaning as on the status payload: what THIS process loaded. */
27240
27285
  runningVersion: string().nullable(),
27241
27286
  latestVersion: string().nullable(),
27287
+ /**
27288
+ * `latestVersion` is newer than `runningVersion` AND is not the version
27289
+ * already staged on this node. A staged-and-waiting version is not "an
27290
+ * update available" — applying it again is refused (`already-staged`), and
27291
+ * a button that announced "updating…" on this boolean then got refused
27292
+ * would be lying. It is reported through `pendingVersion` instead.
27293
+ */
27242
27294
  updateAvailable: boolean(),
27243
27295
  checkedAtMs: number(),
27244
27296
  /** Non-null when the registry lookup failed (offline, bad registry, …). */
27245
- error: string().nullable()
27297
+ error: string().nullable(),
27298
+ /**
27299
+ * Version staged on this node and awaiting its restart, when one is. Before
27300
+ * 2026-09-20 a check answered `{runningVersion, updateAvailable:false}` for a
27301
+ * node whose staged closure had never booted, and the caller had no way to
27302
+ * see the difference. Optional for version skew.
27303
+ */
27304
+ pendingVersion: string().nullable().optional(),
27305
+ /** See the status payload: staged, or installed-on-disk ≠ running. Optional for skew. */
27306
+ restartRequired: boolean().optional()
27246
27307
  });
27308
+ /**
27309
+ * What an action DID — the discriminant `accepted` cannot carry. Before
27310
+ * 2026-09-20 `applyServerUpdate` answered `accepted:false` both for a refusal
27311
+ * where nothing was wrong (already current, already staged) and for a staging
27312
+ * install that died on `npm error code ECONNRESET`; the only difference was
27313
+ * prose in `message`, and an operator restarted a container on the strength of
27314
+ * it, booting the previous version.
27315
+ *
27316
+ * - `staged` — the closure is installed and validated; the node
27317
+ * restarts to apply it (`restarting:true`). NOTHING
27318
+ * runs the new code until that restart completes.
27319
+ * - `restart-scheduled` — a plain, version-preserving restart was accepted.
27320
+ * - `already-current` — the target IS the running version; nothing done.
27321
+ * - `refused` — dropped by a gate; `reason` names which.
27322
+ * - `failed` — attempted and did not land; `error` says why.
27323
+ */
27324
+ var ServerUpdateOutcomeSchema = _enum([
27325
+ "staged",
27326
+ "restart-scheduled",
27327
+ "already-current",
27328
+ "refused",
27329
+ "failed"
27330
+ ]);
27247
27331
  var ServerUpdateActionResultSchema = object({
27248
27332
  accepted: boolean(),
27249
27333
  targetVersion: string().nullable(),
27250
27334
  /** True when a graceful restart was scheduled to apply the change. */
27251
27335
  restarting: boolean(),
27252
- message: string()
27336
+ message: string(),
27337
+ /** See {@link ServerUpdateOutcomeSchema}. Optional for version skew. */
27338
+ outcome: ServerUpdateOutcomeSchema.optional(),
27339
+ /**
27340
+ * Stable, greppable cause for `refused` / `failed` (the engine's
27341
+ * `UpdateRefusalReason`, `staging-failed`, …). `null` on success.
27342
+ */
27343
+ reason: string().nullable().optional(),
27344
+ /**
27345
+ * The failure itself, verbatim enough to act on (the npm output for a
27346
+ * staging install). Non-null only for `failed`.
27347
+ */
27348
+ error: string().nullable().optional()
27253
27349
  });
27254
27350
  var serverManagementCapability = {
27255
27351
  name: "server-management",
@@ -28940,41 +29036,299 @@ var ClipSchema = object({
28940
29036
  holes: array(object({
28941
29037
  startMs: number(),
28942
29038
  endMs: number()
28943
- })).optional()
29039
+ })).optional(),
29040
+ /**
29041
+ * A URL that MAY produce this clip's still, asked only for rows actually on
29042
+ * screen. The opposite of {@link ClipSchema.thumbnail}: that one is VOUCHED
29043
+ * (a JPEG is already on disk), this one is an offer. The route answers 200
29044
+ * with the image, or 204 with `x-camstack-reason` when it could not mint one
29045
+ * — a surface latches that refusal to the instant rather than retrying.
29046
+ *
29047
+ * Never both: a clip with a vouched `thumbnail` needs no mint.
29048
+ */
29049
+ thumbnailMint: string().optional(),
29050
+ /**
29051
+ * Why no still will be produced for this clip RIGHT NOW — set when the
29052
+ * provider already knows, so the surface draws the glyph and the reason
29053
+ * instead of firing a mint that cannot succeed.
29054
+ *
29055
+ * `sleeping` — a standalone battery camera; a read would be a wake (D549 4).
29056
+ * `camera-refused` — the camera answered the CoverPreview with a refusal.
29057
+ * `no-keyframe` — the window holds no decodable I-frame (an event that sits
29058
+ * inside no file is the measured case).
29059
+ * `unsupported` — this source cannot mint stills at all.
29060
+ */
29061
+ thumbnailUnavailable: object({ reason: _enum([
29062
+ "sleeping",
29063
+ "camera-refused",
29064
+ "no-keyframe",
29065
+ "unsupported"
29066
+ ]) }).optional(),
29067
+ /**
29068
+ * When the catalog this row came from was last CONFIRMED against the device.
29069
+ * Absent means "this row was read live". A persisted catalog served while a
29070
+ * camera sleeps carries the age it really has — a cached list is never drawn
29071
+ * as current (D549 13).
29072
+ */
29073
+ catalogAsOf: number().optional(),
29074
+ /**
29075
+ * The camera's OWN type strings for this clip, all of them, unmapped
29076
+ * (`md`, `people`, `dog_cat`, `sched`, …). Kept beside {@link labels}
29077
+ * because a firmware inventing a type must not vanish: the mapping into our
29078
+ * filter vocabulary is lossy on purpose and this is the lossless copy
29079
+ * (D549 20).
29080
+ */
29081
+ nativeTypes: array(string()).optional(),
29082
+ /**
29083
+ * What the subject DID — `crossline`, `intrude`, `loitering`. A behaviour
29084
+ * travels BESIDE a class, never instead of one, and the class filter ignores
29085
+ * it: "a person crossed a line" is still a person (D549 20).
29086
+ */
29087
+ behaviours: array(string()).optional(),
29088
+ /**
29089
+ * The same recording as two files — the sub twin (what the row and its
29090
+ * thumbnail are) and its main twin, matched at listing time so a quality
29091
+ * change never re-searches the camera (D549 15). `getClipPlayback`'s
29092
+ * `profile` picks between them: `low | mid` → sub, `high` → main.
29093
+ */
29094
+ streams: object({
29095
+ sub: object({
29096
+ id: string(),
29097
+ bytes: number().optional()
29098
+ }).optional(),
29099
+ main: object({
29100
+ id: string(),
29101
+ bytes: number().optional()
29102
+ }).optional()
29103
+ }).optional(),
29104
+ /** The camera says it holds a sub-stream copy of this recording. */
29105
+ supportSub: boolean().optional(),
29106
+ /**
29107
+ * Whether this row has bytes behind it. ABSENT means yes — every clip that
29108
+ * IS a file is playable, and only a source that lists EVENTS can produce a
29109
+ * row with nothing to play (the measured case: 1 of 29 hub events on 3628
29110
+ * fell inside no file). Such a row is shown, never dropped and never offered
29111
+ * as playable-then-failing (D549 19).
29112
+ */
29113
+ playable: boolean().optional(),
29114
+ /** Why {@link playable} is false, verbatim (`no-file-for-window`). */
29115
+ unplayableReason: string().optional()
28944
29116
  });
28945
29117
  var ClipPlaybackSchema = object({
28946
- /** HLS master URL through the hub data-plane (Range + token in path). */
29118
+ /**
29119
+ * A media URL through the hub data-plane. {@link ClipPlaybackSchema.format}
29120
+ * says what kind — an HLS master playlist for a recording-derived clip, a
29121
+ * progressive MP4 for a native file the vendor addon muxed and serves with
29122
+ * `Range`. The URL is NOT a credential: both planes are registered
29123
+ * `access: 'authenticated'` and the hub's `/addon/<id>/<prefix>` proxy takes
29124
+ * the session cookie, so nothing is appended to it (D549 22).
29125
+ */
28947
29126
  playbackUrl: string(),
29127
+ /**
29128
+ * How to play {@link playbackUrl}. Absent means `hls` — the shape every
29129
+ * existing consumer already assumes. A player that branches on this is the
29130
+ * one change a native clip needs; a player that ignores it will hand an MP4
29131
+ * to hls.js and fail parsing it as a manifest.
29132
+ */
29133
+ format: _enum(["hls", "mp4"]).optional(),
29134
+ /**
29135
+ * Which twin was actually served. A clip that holds only one stream answers
29136
+ * with the one it has, and the surface SAYS so — a missing main twin is
29137
+ * never served silently as if it were the asked-for quality (D549 15).
29138
+ */
29139
+ served: CamProfileSchema.optional(),
28948
29140
  /** Optional LAN/remote alternates for the same clip. */
28949
29141
  playbackEndpoints: array(string()).optional(),
28950
29142
  token: string().optional()
28951
29143
  });
29144
+ /**
29145
+ * Why a source cannot answer right now — per SOURCE, never fleet-wide.
29146
+ *
29147
+ * `ok` is the only state whose clip list may be read as complete. The other
29148
+ * three exist because an empty list from a sleeping camera reads as "this
29149
+ * camera has no recordings", which is the defect this whole line of work is
29150
+ * about: a battery camera nobody woke (`sleeping`), a camera that could not be
29151
+ * reached at all (`unreachable`, also what a provider that THREW reports), a
29152
+ * camera whose SD card is not mounted (`no-storage`, measured on 640 —
29153
+ * `HddInfo mount 0`, honestly nothing to list rather than "no clips"), and a
29154
+ * camera whose OWN index disagrees with its OWN calendar (`index-empty`,
29155
+ * measured on 618: the calendar marks 3–20 September, days 6–20 list zero
29156
+ * files on both streams and both filters, with 177 GB free). That last one is
29157
+ * a defect ON THE CAMERA, and the only honest thing a provider can do is say
29158
+ * which days it asked for and got nothing — "no clips" would be a lie about a
29159
+ * card that is full of them.
29160
+ */
29161
+ var ClipSourceAvailabilitySchema = object({
29162
+ state: _enum([
29163
+ "ok",
29164
+ "sleeping",
29165
+ "unreachable",
29166
+ "no-storage",
29167
+ "index-empty"
29168
+ ]),
29169
+ /** Free text, shown verbatim. Names the camera's own refusal when there is one. */
29170
+ reason: string().optional(),
29171
+ /** When this source's catalog was last CONFIRMED. A cached list is never
29172
+ * drawn as current: the surface shows the age whenever it is older than the
29173
+ * refresh interval. */
29174
+ catalogAsOf: number().optional()
29175
+ });
29176
+ /**
29177
+ * One SOURCE of clips for a camera — a row of the picker, and the namespace
29178
+ * every clip id from it is prefixed with (`analytics`,
29179
+ * `native:reolink:onboard`, `hksv`, …).
29180
+ *
29181
+ * A provider lists the sources IT serves for that device, and answers for each
29182
+ * of them whether it can answer at all. A provider with nothing to offer on a
29183
+ * camera returns `[]` — it is not that camera's business.
29184
+ */
29185
+ var ClipSourceSchema = object({
29186
+ /** The value this source stamps on {@link ClipSchema.source}, and the prefix
29187
+ * of every clip id it mints. `getClipPlayback` routes on it. */
29188
+ source: string(),
29189
+ /** Operator-facing name of the source ("CamStack recordings", "SD card"). */
29190
+ label: string(),
29191
+ /**
29192
+ * The addon that SERVES this row.
29193
+ *
29194
+ * A surface cannot otherwise resolve a source to who answers it, and the
29195
+ * alternative — a `native:reolink:* → provider-reolink` table inside the
29196
+ * widget — is a second authority on provider identity living in the one
29197
+ * package with no business knowing it, wrong the day a third source appears
29198
+ * (D557). One addon may serve SEVERAL sources: `addon-provider-reolink`
29199
+ * answers a hub child with both `native:reolink:onboard` and
29200
+ * `native:reolink:hub`, which is why the per-device switch is keyed by
29201
+ * SOURCE and not by this (D555).
29202
+ *
29203
+ * Optional for version skew only. The collection dispatcher stamps it from
29204
+ * the registry, so a row that travelled through the fan-out carries the
29205
+ * authoritative id whatever the provider filled in.
29206
+ */
29207
+ addonId: string().optional(),
29208
+ /**
29209
+ * Which API this source resolved to FOR THIS CAMERA, when it has a choice.
29210
+ *
29211
+ * A source may cover one store through more than one surface — the Reolink
29212
+ * provider reads a hub child through the parent's event log and a standalone
29213
+ * through its own file list, because that is what each camera answers. The
29214
+ * CHOICE is the provider's, made from what the camera is, and is never a row
29215
+ * the operator has to understand; but it is REPORTED, because a source that
29216
+ * silently reads a different API on two cameras and then behaves differently
29217
+ * is the thing nobody can debug later. Absent when the source has only one
29218
+ * way to read its store.
29219
+ */
29220
+ via: string().optional(),
29221
+ availability: ClipSourceAvailabilitySchema,
29222
+ /**
29223
+ * The operator switched this source OFF for this camera.
29224
+ *
29225
+ * Deliberately NOT a member of {@link ClipSourceAvailabilitySchema}'s
29226
+ * vocabulary. That enum models what the source CAN do — a sleeping camera, an
29227
+ * unmounted card, an index that disagrees with its own calendar — and a
29228
+ * switched-off source could answer perfectly well; the operator decided it
29229
+ * should not. Folding the choice in is how `disabled` and `broken` stop being
29230
+ * distinguishable, which is the D62 rule this repo has already paid for twice:
29231
+ * an off switch is REPORTED off (`CameraStatus.switchedOff`, the same word),
29232
+ * and disabled must never look like broken. It is also what lets every
29233
+ * exhaustive consumer of the availability enum keep compiling.
29234
+ *
29235
+ * A switched-off source contributes NO clips (`listClips` never calls it) and
29236
+ * its row carries no `catalogAsOf`: nothing confirms a catalog it is not
29237
+ * allowed to serve, and a frozen age that can only grow draws a stalling
29238
+ * source rather than an off switch.
29239
+ *
29240
+ * The row survives BECAUSE it is the control the operator switches the source
29241
+ * back on from — D554 decision 4's rule ("a source that cannot answer
29242
+ * produces a ROW, not an absence") applied to the one case D556 carved out of
29243
+ * it, and D557's own kept property ("a source is never hidden, only its
29244
+ * rows"). Absent means on.
29245
+ *
29246
+ * A provider never sets this — like {@link ClipSourceSchema.addonId} it is
29247
+ * stamped by the collection dispatcher, which holds the registry's projection
29248
+ * of the persisted authority (D556) and is the only place that knows it.
29249
+ */
29250
+ switchedOff: boolean().optional()
29251
+ });
28952
29252
  var videoclipsCapability = {
28953
29253
  name: "videoclips",
28954
29254
  scope: "device",
28955
- mode: "singleton",
29255
+ mode: "collection",
28956
29256
  kind: "wrapper",
28957
29257
  defaultActive: true,
28958
29258
  /** A clip is a window over a camera's footage — the cap is meaningless on a
28959
29259
  * sensor, a button or an event emitter, and the `defaultActive` auto-bind
28960
29260
  * reads this to decide which devices it may claim. */
28961
29261
  deviceTypes: [DeviceType.Camera],
29262
+ /**
29263
+ * The Clips section of a camera's device details is FRAMEWORK-DERIVED (D14):
29264
+ * the aggregator turns this declaration into the `type:'widget'` section and
29265
+ * `DeviceDetail.tsx` is never edited. `videoclips` is the first WRAPPER cap
29266
+ * to declare one — every previous `host/` widget cap is `deviceNative` — so
29267
+ * `device-config-widget-wrapped-binding.spec.ts` pins that a `kind:'wrapped'`
29268
+ * binding entry derives the same section a native one does.
29269
+ *
29270
+ * `topTab` because the browser owns the whole pane (a day's clips, a source
29271
+ * list and a player), exactly as `ptz` does; the widget itself is
29272
+ * `host/clips-browser` in ui-library's `HOST_WIDGETS`.
29273
+ */
29274
+ deviceConfig: { ui: {
29275
+ kind: "widget",
29276
+ widgetId: "host/clips-browser",
29277
+ tab: "clips",
29278
+ topTab: true,
29279
+ label: "Clips",
29280
+ order: 0
29281
+ } },
28962
29282
  methods: {
28963
29283
  listClips: method(object({
28964
29284
  deviceId: number(),
28965
29285
  since: number(),
28966
29286
  until: number(),
28967
- limit: number().int().positive().optional()
29287
+ limit: number().int().positive().optional(),
29288
+ /**
29289
+ * View filter over {@link ClipSourceSchema.source} values — the
29290
+ * picker's selection, forwarded so a provider need not list what
29291
+ * nobody is looking at. ABSENT means every source this camera has,
29292
+ * which is the honest default for a surface whose whole point is that
29293
+ * nothing is hidden (D554 3). A provider with one source ignores it.
29294
+ */
29295
+ sources: array(string()).optional()
28968
29296
  }), array(ClipSchema).readonly(), {
28969
29297
  kind: "query",
28970
- auth: "admin"
29298
+ auth: "protected"
29299
+ }),
29300
+ /**
29301
+ * The sources this camera has, WITH the reason any of them cannot answer.
29302
+ *
29303
+ * Asked separately from `listClips` because an empty clip list is
29304
+ * ambiguous and this is the only place the ambiguity is resolved: every
29305
+ * bound provider contributes its own rows, and a provider that could not
29306
+ * be reached at all still produces one row saying so. A surface that draws
29307
+ * "no clips" without reading this is drawing a guess.
29308
+ */
29309
+ listSources: method(object({ deviceId: number() }), array(ClipSourceSchema).readonly(), {
29310
+ kind: "query",
29311
+ auth: "protected"
28971
29312
  }),
28972
29313
  getClipPlayback: method(object({
28973
29314
  deviceId: number(),
28974
- clipId: string()
29315
+ clipId: string(),
29316
+ /**
29317
+ * Which twin to serve, on the ONE quality scale the system already has
29318
+ * (`CamProfileSchema`). `low | mid` → the sub file, `high` → the main
29319
+ * twin; both ids are already on the row so this never re-searches the
29320
+ * camera. Absent means the provider's own default (the sub file, which
29321
+ * every source is measured to hold).
29322
+ *
29323
+ * `auto` is deliberately NOT accepted here: a stored file has no
29324
+ * broker session, so the adaptive tier cannot be resolved for it. The
29325
+ * viewer resolves `auto` to a profile the same way live does, before
29326
+ * it calls (D549 15).
29327
+ */
29328
+ profile: CamProfileSchema.optional()
28975
29329
  }), ClipPlaybackSchema, {
28976
29330
  kind: "query",
28977
- auth: "admin"
29331
+ auth: "protected"
28978
29332
  })
28979
29333
  }
28980
29334
  };
@@ -47068,6 +47422,12 @@ Object.freeze({
47068
47422
  addonId: null,
47069
47423
  access: "view"
47070
47424
  },
47425
+ "videoclips.listSources": {
47426
+ capName: "videoclips",
47427
+ capScope: "device",
47428
+ addonId: null,
47429
+ access: "view"
47430
+ },
47071
47431
  "viewerUi.getStaticDir": {
47072
47432
  capName: "viewer-ui",
47073
47433
  capScope: "system",
@@ -49076,6 +49436,11 @@ Object.freeze({
49076
49436
  form: "single",
49077
49437
  optional: false
49078
49438
  }],
49439
+ "videoclips.listSources": [{
49440
+ name: "deviceId",
49441
+ form: "single",
49442
+ optional: false
49443
+ }],
49079
49444
  "waterHeater.setAway": [{
49080
49445
  name: "deviceId",
49081
49446
  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_osd_manager_page__loadShare__react__loadShare__.js-Bs1t18EM.mjs";
2
- import { o as i, s as a } from "./responsive-BJ6OUcwu.mjs";
2
+ import { o as i, s as a } from "./responsive-CC0j2h-d.mjs";
3
3
  import { n as o, r as s, t as c } from "./_virtual_mf___mfe_internal__addon_osd_manager_page__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.js-DalfdIDw.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_osd_manager_page__remoteEntry_js-BYA-5ZRu.mjs";
1
+ import { n as e, t } from "./virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_osd_manager_page__remoteEntry_js-D8j_yb3G.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_osd_manager_page__loadShare__react__loadShare__.js-Bs1t18EM.mjs";
2
2
  import "./_virtual_mf___mfe_internal__addon_osd_manager_page__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.js-DalfdIDw.mjs";
3
- import { n as u } from "./_virtual_mf___mfe_internal__addon_osd_manager_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-BzMsLBUL.mjs";
3
+ import { n as u } from "./_virtual_mf___mfe_internal__addon_osd_manager_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-BK-eslgm.mjs";
4
4
  //#region ../../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,5 +1,5 @@
1
1
  import { c as e, h as t, p as n, y as r } from "./_virtual_mf___mfe_internal__addon_osd_manager_page__loadShare__react__loadShare__.js-Bs1t18EM.mjs";
2
- import { s as i } from "./responsive-BJ6OUcwu.mjs";
2
+ import { s as i } from "./responsive-CC0j2h-d.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"
@@ -1,4 +1,4 @@
1
- import { s as e } from "./responsive-BJ6OUcwu.mjs";
1
+ import { s as e } from "./responsive-CC0j2h-d.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-BJ6OUcwu.mjs";
1
+ import { s as e } from "./responsive-CC0j2h-d.mjs";
2
2
  var t = e("trash-2", [
3
3
  ["path", {
4
4
  d: "M10 11v6",
@@ -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_osd_manager_page-BUn-8ukN.mjs")).catch((e) => {
2756
+ return tr ||= rr(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_osd_manager_page-B2cBM7jE.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-osd-manager",
3
- "version": "0.1.123",
3
+ "version": "0.1.124",
4
4
  "description": "Binds camera on-screen-display slots to live state and recognitions",
5
5
  "keywords": [
6
6
  "camstack",