@camstack/addon-admin-ui 1.2.33 → 1.2.35
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.
- package/dist/assets/{AddLocationWizard-BNLzjRkS.js → AddLocationWizard-BpkZ7g8M.js} +1 -1
- package/dist/assets/{AddonCollectionPage-CvyviITl.js → AddonCollectionPage-CqEMePgW.js} +1 -1
- package/dist/assets/Addons-cCLSqWfM.js +1 -0
- package/dist/assets/{AdminTabs-V94RuaJP.js → AdminTabs-BzqgdZo8.js} +1 -1
- package/dist/assets/{AiProfiles-CNda-xrz.js → AiProfiles-Du2Gut1p.js} +1 -1
- package/dist/assets/{Automation-DYV0gbiV.js → Automation-CryfmheY.js} +2 -2
- package/dist/assets/{BrokerForm-DX_RUCNg.js → BrokerForm-en5xEKn5.js} +1 -1
- package/dist/assets/{Capabilities-Cud2I1p1.js → Capabilities-DOVICQ71.js} +1 -1
- package/dist/assets/{CapabilityBadges-CaKz6Row.js → CapabilityBadges-2-jFnJcJ.js} +1 -1
- package/dist/assets/Cluster-DSXKolnm.js +1 -0
- package/dist/assets/{ClusterRecordingTab-BShu9AFE.js → ClusterRecordingTab-BdEH4zMe.js} +1 -1
- package/dist/assets/{Dashboard-CN0qzHHd.js → Dashboard-Bi7LNLdP.js} +1 -1
- package/dist/assets/{Data-Cddnp6Uz.js → Data-CTCmNwJC.js} +1 -1
- package/dist/assets/DetectionIntelligence-3cLwl4I3.js +1 -0
- package/dist/assets/{DeviceAggregateSection-H5AVeNJ0.js → DeviceAggregateSection-D8oQ4avR.js} +1 -1
- package/dist/assets/DeviceDetail-BcRXDqYg.js +2 -0
- package/dist/assets/{Devices-Bp2S4_jq.js → Devices-BmmGXj4K.js} +1 -1
- package/dist/assets/{EmbedPlayerPage-DVIbQ9_P.js → EmbedPlayerPage-CRkfP_Ng.js} +1 -1
- package/dist/assets/Events-CRvWzt-T.js +1 -0
- package/dist/assets/{FormBuilder-B3G6L5El.js → FormBuilder-D36jBkTY.js} +1 -1
- package/dist/assets/{Identity-D5YIw7nG.js → Identity-D6X1Vx5c.js} +1 -1
- package/dist/assets/IntegrationDetail-Kd39JHzv.js +1 -0
- package/dist/assets/Integrations-BUaA-BHV.js +1 -0
- package/dist/assets/{Integrations-fadRG4Km.js → Integrations-CsuR-wnp.js} +1 -1
- package/dist/assets/{Logs-zJNzZ183.js → Logs-D-v1pY1C.js} +1 -1
- package/dist/assets/{MotionZonesSettings-4IW50CRy.js → MotionZonesSettings-DSAuUczY.js} +1 -1
- package/dist/assets/{MyAccess-CBfHhwSU.js → MyAccess-CSduDxGh.js} +1 -1
- package/dist/assets/Network-D2GsfRiT.js +1 -0
- package/dist/assets/{NodeAddonsSettingsPanel-C2NjwPws.js → NodeAddonsSettingsPanel-0BTA46bg.js} +1 -1
- package/dist/assets/{NodeInferenceDevices-uPCEdvuj.js → NodeInferenceDevices-FEzIpBGg.js} +1 -1
- package/dist/assets/Notifications-C2xW5T2d.js +1 -0
- package/dist/assets/Pipeline-BAy-OSuJ.js +1 -0
- package/dist/assets/Plates-B-enbHRO.js +1 -0
- package/dist/assets/{PrivacyMaskSettings-DOgtt7Eb.js → PrivacyMaskSettings-CfGREDOs.js} +1 -1
- package/dist/assets/{ProviderIcon-DpSmN8_h.js → ProviderIcon-mSy1d917.js} +1 -1
- package/dist/assets/{Recordings-5kVeLC44.js → Recordings-CVuEjle9.js} +1 -1
- package/dist/assets/Retrain-B38fDPkv.js +1 -0
- package/dist/assets/{ScanNetworkModal-CVNem53G.js → ScanNetworkModal-DsEiGH4q.js} +1 -1
- package/dist/assets/{Settings-Dot1aUpP.js → Settings-_QzMAEQz.js} +1 -1
- package/dist/assets/{Showroom-CE0pD_JA.js → Showroom-BrqmuRQr.js} +1 -1
- package/dist/assets/{Terminal-Jn61QHqq.js → Terminal-D6ADzUw6.js} +2 -2
- package/dist/assets/{_virtual_mf-localSharedImportMap___mfe_internal__admin_ui_host-DfmS2X5b.js → _virtual_mf-localSharedImportMap___mfe_internal__admin_ui_host-D6JCOoeB.js} +1 -1
- package/dist/assets/{build-cluster-graph-oxCzI_GT.js → build-cluster-graph-DK8tHUpQ.js} +2 -2
- package/dist/assets/circle-check-big-CmRUug-s.js +1 -0
- package/dist/assets/clock-CbQ_m2UA.js +1 -0
- package/dist/assets/{copy-BrMo-O0l.js → copy-CiHOHvWK.js} +1 -1
- package/dist/assets/debounced-invalidate-CS1Zql4g.js +1 -0
- package/dist/assets/{dist-w7XvHdqJ.js → dist-CD_UFqu_.js} +1 -1
- package/dist/assets/dist-DyDQKWiO.js +7 -0
- package/dist/assets/{download-Bd71YsuA.js → download-BbJFh_GP.js} +1 -1
- package/dist/assets/{face-bbox-ByAacIlM.js → face-bbox-DFwfVPg5.js} +1 -1
- package/dist/assets/{hostInit-DhSUBWsx.js → hostInit-Gt7MZSrm.js} +1 -1
- package/dist/assets/image-off-CePvOw2Z.js +1 -0
- package/dist/assets/index-D4VDD87s.css +2 -0
- package/dist/assets/index-DzefosH4.js +4 -0
- package/dist/assets/{key-round-DZL9RdNY.js → key-round-wDYpv-03.js} +1 -1
- package/dist/assets/{mf-entry-bootstrap-0-28bb7ad2.js → mf-entry-bootstrap-0-eafb02b4.js} +2 -2
- package/dist/assets/{pencil-TjwM9NpS.js → pencil-CGcp1H_S.js} +1 -1
- package/dist/assets/{player-overlays-CkAkhPbQ.js → player-overlays-DnLMvF2y.js} +1 -1
- package/dist/assets/plus-CWclgqCc.js +1 -0
- package/dist/assets/{radio-DOrncLmg.js → radio-DejuKcx3.js} +1 -1
- package/dist/assets/{refresh-cw-BYCB135v.js → refresh-cw-CW_Ljqdp.js} +1 -1
- package/dist/assets/remoteEntry-DNdwEnrY.js +1 -0
- package/dist/assets/{rotate-ccw-Db_qQ-Qx.js → rotate-ccw-RsWJHCWz.js} +1 -1
- package/dist/assets/rotate-cw-Bj3NywrT.js +1 -0
- package/dist/assets/search-kZ6MJ1BT.js +1 -0
- package/dist/assets/{send-CosR7D5R.js → send-CJWIa1yB.js} +1 -1
- package/dist/assets/{server-CUNj6w6P.js → server-DLCgy7fU.js} +1 -1
- package/dist/assets/square-I9BIO4a-.js +1 -0
- package/dist/assets/{square-check-big-yxLWkS9v.js → square-check-big-C1eD-s2U.js} +1 -1
- package/dist/assets/{src-DOXkuCPk.js → src-C2KiI31z.js} +10 -10
- package/dist/assets/src-DREH726E.js +7 -0
- package/dist/assets/undo-2-B2bADvVZ.js +1 -0
- package/dist/assets/{upload-D0orNbud.js → upload-DeJAhsSx.js} +1 -1
- package/dist/assets/{useEventInvalidation-DJ5h5Wvp.js → useEventInvalidation-BuTU98fj.js} +1 -1
- package/dist/assets/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__admin_ui_host__remoteEntry-_hash_-Cg_QybrP.js → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__admin_ui_host__remoteEntry-_hash_-CwEvP83T.js} +2 -2
- package/dist/assets/{wifi-D0ItCC1K.js → wifi-BuwizIJA.js} +1 -1
- package/dist/assets/{zap-CIK4k9g5.js → zap-CWuo4dzD.js} +1 -1
- package/dist/index.html +6 -6
- package/dist/server/addon.js +740 -15
- package/package.json +1 -1
- package/dist/assets/Addons-B0nG62pB.js +0 -1
- package/dist/assets/Cluster-Cx5dtvDp.js +0 -1
- package/dist/assets/DetectionIntelligence-C4g5DaCG.js +0 -1
- package/dist/assets/DeviceDetail-CLQTZBsf.js +0 -2
- package/dist/assets/Events-C_TE39Tm.js +0 -1
- package/dist/assets/IntegrationDetail-Dj2OdD1K.js +0 -1
- package/dist/assets/Integrations-DZKddVhD.js +0 -1
- package/dist/assets/Network-Dx9MFUR0.js +0 -1
- package/dist/assets/Notifications-C3Ng_pEz.js +0 -1
- package/dist/assets/Pipeline-Daj8GJqM.js +0 -1
- package/dist/assets/Plates-CdBLHSjv.js +0 -1
- package/dist/assets/circle-check-big-bqZqQn_F.js +0 -1
- package/dist/assets/clock-BxBK96nq.js +0 -1
- package/dist/assets/debounced-invalidate-DCfaNC1r.js +0 -1
- package/dist/assets/dist-DPJBx5gf.js +0 -7
- package/dist/assets/index-BIqRUg3I.css +0 -2
- package/dist/assets/index-BZA0u2Kc.js +0 -4
- package/dist/assets/plus-BgUAuoLj.js +0 -1
- package/dist/assets/remoteEntry-2xQrocPD.js +0 -1
- package/dist/assets/rotate-cw-vsmRF4Nv.js +0 -1
- package/dist/assets/search-BopXcdUz.js +0 -1
- package/dist/assets/square-C0Uc1Hub.js +0 -1
- package/dist/assets/src-Bh5CQXm7.js +0 -7
package/dist/server/addon.js
CHANGED
|
@@ -6462,7 +6462,20 @@ var BrokerStatsSchema = object({
|
|
|
6462
6462
|
sampleRate: number(),
|
|
6463
6463
|
channels: number(),
|
|
6464
6464
|
supported: boolean()
|
|
6465
|
-
}).nullable().optional()
|
|
6465
|
+
}).nullable().optional(),
|
|
6466
|
+
/**
|
|
6467
|
+
* BROKER-SIDE AUDIO MUTE (D83). `true` = this broker is deliberately
|
|
6468
|
+
* distributing none of the device's audio, on live or recording.
|
|
6469
|
+
*
|
|
6470
|
+
* Present so a silent camera can be told apart from a broken one on the
|
|
6471
|
+
* stream panel itself, without cross-referencing the switch group: a
|
|
6472
|
+
* broker holding an `audio` track descriptor while `audioMuted` is true is
|
|
6473
|
+
* working exactly as asked. `audioMutedDropped` counts the audio units
|
|
6474
|
+
* thrown away since the current dial — it is how you confirm from stats
|
|
6475
|
+
* alone that the mute is on the packet path and not merely persisted.
|
|
6476
|
+
*/
|
|
6477
|
+
audioMuted: boolean().optional(),
|
|
6478
|
+
audioMutedDropped: number().optional()
|
|
6466
6479
|
});
|
|
6467
6480
|
/**
|
|
6468
6481
|
* Exporter-facing "profile restream" entry. Returned by
|
|
@@ -7100,6 +7113,19 @@ object({
|
|
|
7100
7113
|
* | `notifications` | `notificationRules.setDeviceMuted` | `NotificationCenter.evaluateAndEnqueue` returns before any rule is evaluated |
|
|
7101
7114
|
* | `privacy-mask` | `privacyMask.setMask({ enabled })` → the CAMERA | the camera blanks the masked regions itself; every stream and recording carries the black boxes |
|
|
7102
7115
|
* | `device-audio` | `privacyMask.setAudioEnabled` → the CAMERA | the camera stops encoding an audio track at all; every consumer sees silent video |
|
|
7116
|
+
* | `broker-audio` | `streamBroker.setDeviceAudioMute` → `DeviceOverride.audioMuted` | `StreamBroker.setAudioMuted` drops the audio plane at the source: no `type:'audio'` packet leaves `fanOutEncoded`, no RTP reaches the restreamer, and the restreamer serves the video-only SDP |
|
|
7117
|
+
*
|
|
7118
|
+
* ## `device-audio` and `broker-audio` are two functions, not two knobs
|
|
7119
|
+
*
|
|
7120
|
+
* They look adjacent and they are not the same control ([D83](../../../../docs/decisions/adr-0083.md)):
|
|
7121
|
+
* `device-audio` writes the CAMERA, so it is hardware privacy — the microphone
|
|
7122
|
+
* genuinely stops, it survives CamStack entirely, and it costs a multi-second
|
|
7123
|
+
* encoder restart on every flip. `broker-audio` writes THIS server, so it is
|
|
7124
|
+
* instant, vendor-independent and reversible without touching the camera, and
|
|
7125
|
+
* a camera that ignores or lacks the ISAPI/Reolink control is still silenced.
|
|
7126
|
+
* D62 forbids a second switch that *disagrees* with the first; these two
|
|
7127
|
+
* cannot disagree, because neither reads the other's store — the camera holds
|
|
7128
|
+
* one, the broker holds the other, and each reports its own fact.
|
|
7103
7129
|
*
|
|
7104
7130
|
* ## The two switches whose authority is not on this server
|
|
7105
7131
|
*
|
|
@@ -7161,6 +7187,7 @@ var CameraSwitchIdSchema = _enum([
|
|
|
7161
7187
|
"object-detection",
|
|
7162
7188
|
"privacy-mask",
|
|
7163
7189
|
"device-audio",
|
|
7190
|
+
"broker-audio",
|
|
7164
7191
|
"audio-analysis",
|
|
7165
7192
|
"recording",
|
|
7166
7193
|
"notifications"
|
|
@@ -7186,7 +7213,8 @@ var CameraSwitchAuthoritySchema = discriminatedUnion("kind", [
|
|
|
7186
7213
|
object({
|
|
7187
7214
|
kind: literal("camera-mask"),
|
|
7188
7215
|
capName: string()
|
|
7189
|
-
})
|
|
7216
|
+
}),
|
|
7217
|
+
object({ kind: literal("broker-audio-mute") })
|
|
7190
7218
|
]);
|
|
7191
7219
|
/**
|
|
7192
7220
|
* Why a switch is not offered for this camera. Rendered instead of the
|
|
@@ -9383,7 +9411,25 @@ method(object({
|
|
|
9383
9411
|
}), _void(), {
|
|
9384
9412
|
kind: "mutation",
|
|
9385
9413
|
auth: "admin"
|
|
9386
|
-
}), method(object({ brokerId: string() }), boolean()), object({
|
|
9414
|
+
}), method(object({ brokerId: string() }), boolean()), method(object({ deviceId: number().int() }), object({
|
|
9415
|
+
muted: boolean(),
|
|
9416
|
+
/**
|
|
9417
|
+
* How many live non-derived brokers currently hold the mute. Purely
|
|
9418
|
+
* diagnostic: `muted` is the policy and is authoritative on its own
|
|
9419
|
+
* (it applies to brokers that do not exist yet), while this says
|
|
9420
|
+
* whether anything is presently being silenced.
|
|
9421
|
+
*/
|
|
9422
|
+
appliedBrokers: number().int().nonnegative()
|
|
9423
|
+
})), method(object({
|
|
9424
|
+
deviceId: number().int(),
|
|
9425
|
+
muted: boolean()
|
|
9426
|
+
}), object({
|
|
9427
|
+
muted: boolean(),
|
|
9428
|
+
appliedBrokers: number().int().nonnegative()
|
|
9429
|
+
}), {
|
|
9430
|
+
kind: "mutation",
|
|
9431
|
+
auth: "admin"
|
|
9432
|
+
}), object({
|
|
9387
9433
|
deviceId: number().int().nonnegative(),
|
|
9388
9434
|
camStreamId: string(),
|
|
9389
9435
|
profile: CamProfileSchema
|
|
@@ -14625,6 +14671,30 @@ var TrackSourceSchema = _enum([
|
|
|
14625
14671
|
"audio"
|
|
14626
14672
|
]);
|
|
14627
14673
|
/**
|
|
14674
|
+
* Where a track sits in the RETRAIN lifecycle (D81).
|
|
14675
|
+
*
|
|
14676
|
+
* - `none` — never marked, or un-marked. Evictable.
|
|
14677
|
+
* - `staging` — the operator wants this track as training material and has not
|
|
14678
|
+
* finished with it. **This is the only state retention holds**: the track and
|
|
14679
|
+
* everything it owns (object events, crops, keyframes, CLIP vector) survive
|
|
14680
|
+
* the device's age window.
|
|
14681
|
+
* - `trained` — the retrain page has taken what it needed. The frames it chose
|
|
14682
|
+
* were COPIED into the retrain dataset at selection time, so the dataset no
|
|
14683
|
+
* longer depends on the track's media and the track becomes EVICTABLE again.
|
|
14684
|
+
* Terminal for the plain `markForTrain` toggle: returning it to `staging` is
|
|
14685
|
+
* a deliberate action of the retrain page, not a side effect of a checkbox.
|
|
14686
|
+
*
|
|
14687
|
+
* There is no `null`. The state is stored `TEXT NOT NULL DEFAULT 'none'` because
|
|
14688
|
+
* the store's filter language has only positive equality and `whereIn` — no
|
|
14689
|
+
* negation, no IS NULL — so a NULL would be unselectable by ANY predicate and
|
|
14690
|
+
* would make the entire pre-column history immortal in one deploy.
|
|
14691
|
+
*/
|
|
14692
|
+
var RetrainStatusSchema = _enum([
|
|
14693
|
+
"none",
|
|
14694
|
+
"staging",
|
|
14695
|
+
"trained"
|
|
14696
|
+
]);
|
|
14697
|
+
/**
|
|
14628
14698
|
* Per-track OPERATOR flags — set by hand from the admin UI or the viewer, never
|
|
14629
14699
|
* by the pipeline. Spread into `TrackSchema` and `KeyEventSchema` from one place
|
|
14630
14700
|
* so the two surfaces cannot drift.
|
|
@@ -14634,18 +14704,31 @@ var TrackSourceSchema = _enum([
|
|
|
14634
14704
|
* columns existed read as absent, and a consumer that needs a boolean should say
|
|
14635
14705
|
* `flag === true`, not `flag !== false`.
|
|
14636
14706
|
*
|
|
14637
|
-
*
|
|
14638
|
-
*
|
|
14639
|
-
*
|
|
14640
|
-
* `
|
|
14707
|
+
* `markForTrain` is the WIRE FACE of {@link RetrainStatusSchema}, not a column:
|
|
14708
|
+
* it is exactly `retrainStatus === 'staging'`, in both directions. Writing
|
|
14709
|
+
* `true` moves `none → staging`, writing `false` moves `staging → none`, and a
|
|
14710
|
+
* `trained` track reports `false` while refusing both writes. The boolean is
|
|
14711
|
+
* kept because three surfaces drive a toggle off it; anything that needs to tell
|
|
14712
|
+
* "never marked" from "already trained" must read `retrainStatus`.
|
|
14713
|
+
*
|
|
14714
|
+
* `debug` does NOT pin; it is attention, not durability.
|
|
14641
14715
|
*/
|
|
14642
14716
|
var TrackFlagFields = {
|
|
14643
|
-
/** Operator marked this track as training material.
|
|
14717
|
+
/** Operator marked this track as training material — i.e. `retrainStatus` is
|
|
14718
|
+
* `'staging'`. */
|
|
14644
14719
|
markForTrain: boolean().optional(),
|
|
14645
14720
|
/** Operator marked this track for diagnostic attention. */
|
|
14646
14721
|
debug: boolean().optional()
|
|
14647
14722
|
};
|
|
14648
14723
|
/**
|
|
14724
|
+
* The lifecycle field itself, on the READ surfaces only (`Track`, `KeyEvent`).
|
|
14725
|
+
* Deliberately NOT part of {@link TrackFlagFields}: that group also builds the
|
|
14726
|
+
* write patch, and the status is not something the toggle sets — it is what the
|
|
14727
|
+
* toggle's boolean is derived from. Absent on an in-RAM track never touched;
|
|
14728
|
+
* always present on a persisted row (the column default materialises `'none'`).
|
|
14729
|
+
*/
|
|
14730
|
+
var TrackRetrainFields = { retrainStatus: RetrainStatusSchema.optional() };
|
|
14731
|
+
/**
|
|
14649
14732
|
* The write half: a PARTIAL patch. An omitted key is left untouched, so setting
|
|
14650
14733
|
* one flag can never clear the other — the toggles are independent and are
|
|
14651
14734
|
* driven from three surfaces that do not know about each other.
|
|
@@ -14659,13 +14742,92 @@ var TrackFlagsPatchSchema = object(TrackFlagFields);
|
|
|
14659
14742
|
var TrackFlagsSchema = object({
|
|
14660
14743
|
trackId: string(),
|
|
14661
14744
|
markForTrain: boolean(),
|
|
14662
|
-
debug: boolean()
|
|
14745
|
+
debug: boolean(),
|
|
14746
|
+
/** The lifecycle state the boolean was derived from. Required here (unlike on
|
|
14747
|
+
* a track row) because this shape is only ever produced by the write body,
|
|
14748
|
+
* which always knows it — and a surface that has just written needs to render
|
|
14749
|
+
* `trained` without a re-fetch. */
|
|
14750
|
+
retrainStatus: RetrainStatusSchema
|
|
14751
|
+
});
|
|
14752
|
+
union([literal(1), literal(2)]);
|
|
14753
|
+
/**
|
|
14754
|
+
* WHO decided a label, and when. Carried per tier so a value can be traced to
|
|
14755
|
+
* the step and model that produced it — which is what makes the write rule
|
|
14756
|
+
* arguable after the fact ("why is 592's label `dog` and not `Canis lupus`?")
|
|
14757
|
+
* and what lets a migrated, UNATTRIBUTED value be told apart from a real one.
|
|
14758
|
+
*
|
|
14759
|
+
* `stepId` is the pipeline step id (`animal-classifier`, `bird-classifier`,
|
|
14760
|
+
* `plate-ocr`, `face-embedding`, `object-detection`), or the sentinel
|
|
14761
|
+
* `migration:4g` for a value the 4g migration moved from the single-slot era —
|
|
14762
|
+
* that value has no provenance, and the write rule lets ANY properly-attributed
|
|
14763
|
+
* write of the same tier replace it regardless of score.
|
|
14764
|
+
*/
|
|
14765
|
+
var LabelAttributionSchema = object({
|
|
14766
|
+
stepId: string(),
|
|
14767
|
+
modelId: string().optional(),
|
|
14768
|
+
decidedAt: number()
|
|
14769
|
+
});
|
|
14770
|
+
/**
|
|
14771
|
+
* The TIERED label model (roadmap 4g), spread into `TrackSchema` and
|
|
14772
|
+
* `ObjectEventSchema` from ONE place so the two surfaces cannot drift — a
|
|
14773
|
+
* track and its events always answer the same question the same way.
|
|
14774
|
+
*
|
|
14775
|
+
* Two scalar columns, not an array: every consumer wants "the coarse one" or
|
|
14776
|
+
* "the fine one", and an array made both a scan. `label` is tier 1, `subLabel`
|
|
14777
|
+
* is tier 2, and each carries its own score + attribution.
|
|
14778
|
+
*
|
|
14779
|
+
* **Reading it.** What a human should be shown is `subLabel ?? label` — the
|
|
14780
|
+
* finest thing known. Before 4g the single `label` column held the finest
|
|
14781
|
+
* value, so a consumer that has not been updated reads the tier-1 slot and
|
|
14782
|
+
* shows nothing on a species-only row; that is why the migration puts every
|
|
14783
|
+
* pre-4g value in tier 2 (it cannot regress a display that reads the fallback)
|
|
14784
|
+
* and why the read surfaces were changed in the same train.
|
|
14785
|
+
*
|
|
14786
|
+
* **Writing it.** The slots are independent, which is the whole point: a
|
|
14787
|
+
* tier-1 write (`bird`) can never overwrite a tier-2 value (`Turdus
|
|
14788
|
+
* migratorius`), so fineness cannot regress by construction. Within a tier the
|
|
14789
|
+
* higher score wins. One rule, one implementation — see
|
|
14790
|
+
* `pipeline/label-tier.ts` in addon-post-analysis.
|
|
14791
|
+
*/
|
|
14792
|
+
var TieredLabelFields = {
|
|
14793
|
+
/** Tier 1 — the sub-class. See {@link LabelTierSchema}. */
|
|
14794
|
+
label: string().optional(),
|
|
14795
|
+
/** Confidence of the tier-1 value, as reported by the deciding step. */
|
|
14796
|
+
labelScore: number().optional(),
|
|
14797
|
+
/** Provenance of the tier-1 value. See {@link LabelAttributionSchema}. */
|
|
14798
|
+
labelMeta: LabelAttributionSchema.optional(),
|
|
14799
|
+
/** Tier 2 — the instance. See {@link LabelTierSchema}. */
|
|
14800
|
+
subLabel: string().optional(),
|
|
14801
|
+
/** Confidence of the tier-2 value, as reported by the deciding step. */
|
|
14802
|
+
subLabelScore: number().optional(),
|
|
14803
|
+
/** Provenance of the tier-2 value. See {@link LabelAttributionSchema}. */
|
|
14804
|
+
subLabelMeta: LabelAttributionSchema.optional()
|
|
14805
|
+
};
|
|
14806
|
+
/** Per-camera slice of a training-export estimate. */
|
|
14807
|
+
var TrainingExportDeviceTotalsSchema = object({
|
|
14808
|
+
deviceId: number(),
|
|
14809
|
+
tracks: number().int(),
|
|
14810
|
+
files: number().int(),
|
|
14811
|
+
bytes: number().int()
|
|
14812
|
+
});
|
|
14813
|
+
/**
|
|
14814
|
+
* What a training export WOULD contain. Computed from media index rows only —
|
|
14815
|
+
* no blob is read to produce this.
|
|
14816
|
+
*/
|
|
14817
|
+
var TrainingExportSummarySchema = object({
|
|
14818
|
+
generatedAt: number(),
|
|
14819
|
+
trackCount: number().int(),
|
|
14820
|
+
fileCount: number().int(),
|
|
14821
|
+
byteCount: number().int(),
|
|
14822
|
+
/** More marked tracks exist than a single pass carries. */
|
|
14823
|
+
truncated: boolean(),
|
|
14824
|
+
devices: array(TrainingExportDeviceTotalsSchema).readonly()
|
|
14663
14825
|
});
|
|
14664
14826
|
var TrackSchema = object({
|
|
14665
14827
|
trackId: string(),
|
|
14666
14828
|
deviceId: number(),
|
|
14667
14829
|
className: string(),
|
|
14668
|
-
|
|
14830
|
+
...TieredLabelFields,
|
|
14669
14831
|
producingDeviceName: string().optional(),
|
|
14670
14832
|
/** Track provenance. Absent ⇒ `pipeline` (legacy rows). */
|
|
14671
14833
|
source: TrackSourceSchema.optional(),
|
|
@@ -14704,7 +14866,8 @@ var TrackSchema = object({
|
|
|
14704
14866
|
* Populated from the persisted envelope columns on historical reads;
|
|
14705
14867
|
* absent on legacy rows, dims-less tracks and active (in-RAM) tracks. */
|
|
14706
14868
|
envelope: TrackEnvelopeSchema.optional(),
|
|
14707
|
-
...TrackFlagFields
|
|
14869
|
+
...TrackFlagFields,
|
|
14870
|
+
...TrackRetrainFields
|
|
14708
14871
|
});
|
|
14709
14872
|
var BaseEventFields = {
|
|
14710
14873
|
id: string(),
|
|
@@ -14777,7 +14940,7 @@ var ObjectEventSchema = object({
|
|
|
14777
14940
|
/** Omitted in slim projection. */
|
|
14778
14941
|
trackId: string().optional(),
|
|
14779
14942
|
className: string(),
|
|
14780
|
-
|
|
14943
|
+
...TieredLabelFields,
|
|
14781
14944
|
/** Omitted in slim projection. */
|
|
14782
14945
|
confidence: number().optional(),
|
|
14783
14946
|
/** Heavy JSON — omitted in slim projection. */
|
|
@@ -14858,6 +15021,173 @@ var MediaFileSchema = object({
|
|
|
14858
15021
|
* stored blob and a `?variant=thumb` rendering without fetching either.
|
|
14859
15022
|
*/
|
|
14860
15023
|
var MediaFileInfoSchema = MediaFileSchema.omit({ base64: true });
|
|
15024
|
+
/**
|
|
15025
|
+
* The MACRO tier of an annotation — a CLOSED set.
|
|
15026
|
+
*
|
|
15027
|
+
* This is what the exported detector predicts, so a typo here is a new class
|
|
15028
|
+
* with one example in it. `label` and `subLabel` are open strings by contrast:
|
|
15029
|
+
* the whole point of the page is teaching the model things it does not know
|
|
15030
|
+
* yet, and constraining that vocabulary would make it useless.
|
|
15031
|
+
*
|
|
15032
|
+
* A macro class is NEVER a label. The provider refuses a write whose `label` or
|
|
15033
|
+
* `subLabel` is one of these values, in any casing, because once `person`
|
|
15034
|
+
* exists in both tiers "every person box" stops being answerable without
|
|
15035
|
+
* knowing every string anyone ever typed — and the damage is retroactive.
|
|
15036
|
+
*/
|
|
15037
|
+
var RetrainMacroClassSchema = _enum([
|
|
15038
|
+
"person",
|
|
15039
|
+
"vehicle",
|
|
15040
|
+
"animal",
|
|
15041
|
+
"package",
|
|
15042
|
+
"face",
|
|
15043
|
+
"plate"
|
|
15044
|
+
]);
|
|
15045
|
+
/** A subject to learn, or a phantom to unlearn (taught by OMISSION). */
|
|
15046
|
+
var RetrainAnnotationKindSchema = _enum(["subject", "model_error"]);
|
|
15047
|
+
/** Did a human draw this box, or did the assist propose it? */
|
|
15048
|
+
var RetrainAnnotationSourceSchema = _enum(["operator", "assist"]);
|
|
15049
|
+
/** Normalised `[0,1]` rectangle against the FULL frame — the canonical form. */
|
|
15050
|
+
var RetrainBboxSchema = object({
|
|
15051
|
+
x: number(),
|
|
15052
|
+
y: number(),
|
|
15053
|
+
w: number(),
|
|
15054
|
+
h: number()
|
|
15055
|
+
});
|
|
15056
|
+
/**
|
|
15057
|
+
* One annotated subject.
|
|
15058
|
+
*
|
|
15059
|
+
* `bbox` is normalised against the full frame, ALWAYS. The per-model shapes
|
|
15060
|
+
* (letterboxed root / zone-cropped package / subject-cropped classifier) are
|
|
15061
|
+
* derived from it at export and never stored — storing them is how one feature
|
|
15062
|
+
* space ends up holding two crops of the same subject (D52).
|
|
15063
|
+
*/
|
|
15064
|
+
var RetrainAnnotationSchema = object({
|
|
15065
|
+
id: string(),
|
|
15066
|
+
trackId: string(),
|
|
15067
|
+
deviceId: number(),
|
|
15068
|
+
/** The COPY in retrain storage — never the source track's media key. */
|
|
15069
|
+
mediaKey: string(),
|
|
15070
|
+
bbox: RetrainBboxSchema,
|
|
15071
|
+
macroClass: RetrainMacroClassSchema,
|
|
15072
|
+
label: string().optional(),
|
|
15073
|
+
subLabel: string().optional(),
|
|
15074
|
+
kind: RetrainAnnotationKindSchema,
|
|
15075
|
+
source: RetrainAnnotationSourceSchema,
|
|
15076
|
+
/** Which model proposed this box — or, on a `model_error`, drew the phantom. */
|
|
15077
|
+
assistModelId: string().optional(),
|
|
15078
|
+
assistScore: number().optional(),
|
|
15079
|
+
exportedInBatch: string().optional(),
|
|
15080
|
+
createdAt: number()
|
|
15081
|
+
});
|
|
15082
|
+
/** The write form — the server owns `id`, `createdAt` and the frame binding. */
|
|
15083
|
+
var RetrainAnnotationDraftSchema = RetrainAnnotationSchema.omit({
|
|
15084
|
+
id: true,
|
|
15085
|
+
trackId: true,
|
|
15086
|
+
deviceId: true,
|
|
15087
|
+
mediaKey: true,
|
|
15088
|
+
createdAt: true,
|
|
15089
|
+
exportedInBatch: true
|
|
15090
|
+
});
|
|
15091
|
+
/** A track sitting in `staging`, with everything the worklist needs to rank it. */
|
|
15092
|
+
var RetrainTrackSchema = object({
|
|
15093
|
+
trackId: string(),
|
|
15094
|
+
deviceId: number(),
|
|
15095
|
+
className: string(),
|
|
15096
|
+
label: string().optional(),
|
|
15097
|
+
firstSeen: number(),
|
|
15098
|
+
lastSeen: number(),
|
|
15099
|
+
/** How many frames the dataset already holds from this track. */
|
|
15100
|
+
frameCount: number().int(),
|
|
15101
|
+
/** How many subjects have been annotated on those frames. `0` with
|
|
15102
|
+
* `frameCount: 0` is exactly "staging, still to work". */
|
|
15103
|
+
annotationCount: number().int()
|
|
15104
|
+
});
|
|
15105
|
+
/** A frame the picker may offer — an index row, no blob was read to produce it. */
|
|
15106
|
+
var RetrainFrameCandidateSchema = object({
|
|
15107
|
+
mediaKey: string(),
|
|
15108
|
+
kind: MediaFileKindEnum,
|
|
15109
|
+
timestamp: number(),
|
|
15110
|
+
sizeBytes: number().int(),
|
|
15111
|
+
/** A copy of this original already exists — selecting it is free and cannot
|
|
15112
|
+
* fail, whatever became of the original. */
|
|
15113
|
+
copied: boolean()
|
|
15114
|
+
});
|
|
15115
|
+
/** A frame the dataset OWNS: bytes copied at selection time. */
|
|
15116
|
+
var RetrainFrameSchema = object({
|
|
15117
|
+
frameId: string(),
|
|
15118
|
+
deviceId: number(),
|
|
15119
|
+
trackId: string(),
|
|
15120
|
+
/** Provenance only. It may already point at nothing — that is expected. */
|
|
15121
|
+
sourceMediaKey: string(),
|
|
15122
|
+
sourceKind: MediaFileKindEnum,
|
|
15123
|
+
sizeBytes: number().int(),
|
|
15124
|
+
width: number().int(),
|
|
15125
|
+
height: number().int(),
|
|
15126
|
+
copiedAt: number()
|
|
15127
|
+
});
|
|
15128
|
+
/** Why a copy-on-select could not be honoured — named, never a silent skip. */
|
|
15129
|
+
var RetrainCopyRefusalSchema = _enum([
|
|
15130
|
+
"source-missing",
|
|
15131
|
+
"unreadable-image",
|
|
15132
|
+
"write-failed"
|
|
15133
|
+
]);
|
|
15134
|
+
var RetrainFrameSelectionSchema = object({
|
|
15135
|
+
copied: array(RetrainFrameSchema).readonly(),
|
|
15136
|
+
refused: array(object({
|
|
15137
|
+
sourceMediaKey: string(),
|
|
15138
|
+
reason: RetrainCopyRefusalSchema
|
|
15139
|
+
})).readonly()
|
|
15140
|
+
});
|
|
15141
|
+
var RetrainFrameListSchema = object({
|
|
15142
|
+
candidates: array(RetrainFrameCandidateSchema).readonly(),
|
|
15143
|
+
copies: array(RetrainFrameSchema).readonly(),
|
|
15144
|
+
/** What the page pre-selects — the native key frame when one survives. */
|
|
15145
|
+
autoPickMediaKey: string().optional()
|
|
15146
|
+
});
|
|
15147
|
+
/** What the operator asked the assist to look for. */
|
|
15148
|
+
var RetrainAssistSubjectSchema = discriminatedUnion("kind", [object({
|
|
15149
|
+
kind: literal("package"),
|
|
15150
|
+
zone: RetrainBboxSchema.optional()
|
|
15151
|
+
}), object({
|
|
15152
|
+
kind: literal("objects"),
|
|
15153
|
+
modelId: string(),
|
|
15154
|
+
minScore: number().optional()
|
|
15155
|
+
})]);
|
|
15156
|
+
/**
|
|
15157
|
+
* The assist's answer — a discriminated union, because "the model saw nothing"
|
|
15158
|
+
* and "this node cannot run that model" lead to different next moves and a
|
|
15159
|
+
* nullable result cannot tell them apart.
|
|
15160
|
+
*/
|
|
15161
|
+
var RetrainAssistResultSchema = discriminatedUnion("kind", [object({
|
|
15162
|
+
kind: literal("proposed"),
|
|
15163
|
+
modelId: string(),
|
|
15164
|
+
stepId: string(),
|
|
15165
|
+
minScore: number(),
|
|
15166
|
+
/** Drafts, ready to edit. `source: 'assist'` until the operator touches one. */
|
|
15167
|
+
proposals: array(RetrainAnnotationDraftSchema).readonly(),
|
|
15168
|
+
/** Returned by the runner but removed by the threshold. */
|
|
15169
|
+
belowThreshold: number().int()
|
|
15170
|
+
}), object({
|
|
15171
|
+
kind: literal("refused"),
|
|
15172
|
+
/** `no-zone` is ours; the rest are the runner's own refusal vocabulary. */
|
|
15173
|
+
reason: string(),
|
|
15174
|
+
detail: string().optional()
|
|
15175
|
+
})]);
|
|
15176
|
+
/** The outcome of a lifecycle move owned by the retrain page. */
|
|
15177
|
+
var RetrainTransitionResultSchema = object({
|
|
15178
|
+
trackId: string(),
|
|
15179
|
+
/** Where the track ended up, whatever happened. */
|
|
15180
|
+
retrainStatus: RetrainStatusSchema,
|
|
15181
|
+
/** `false` ⇒ the move was refused or was a no-op; `reason` says which. */
|
|
15182
|
+
changed: boolean(),
|
|
15183
|
+
reason: _enum([
|
|
15184
|
+
"unknown-track",
|
|
15185
|
+
"no-frames-copied",
|
|
15186
|
+
"not-staging",
|
|
15187
|
+
"not-trained",
|
|
15188
|
+
"unchanged"
|
|
15189
|
+
]).optional()
|
|
15190
|
+
});
|
|
14861
15191
|
var DEFAULT_EVENT_QUERY_LIMIT = 1e3;
|
|
14862
15192
|
var MAX_EVENT_QUERY_LIMIT = 5e3;
|
|
14863
15193
|
var DeviceEventQueryInput = object({
|
|
@@ -14912,13 +15242,14 @@ var KeyEventSchema = object({
|
|
|
14912
15242
|
/** Track start time (firstSeen). */
|
|
14913
15243
|
timestamp: number(),
|
|
14914
15244
|
className: string(),
|
|
14915
|
-
|
|
15245
|
+
...TieredLabelFields,
|
|
14916
15246
|
importance: number(),
|
|
14917
15247
|
/** Highest-confidence ObjectEvent id for the track (empty when none). */
|
|
14918
15248
|
bestEventId: string(),
|
|
14919
15249
|
/** Track lifetime in ms (lastSeen - firstSeen). */
|
|
14920
15250
|
windowMs: number().optional(),
|
|
14921
|
-
...TrackFlagFields
|
|
15251
|
+
...TrackFlagFields,
|
|
15252
|
+
...TrackRetrainFields
|
|
14922
15253
|
});
|
|
14923
15254
|
object({
|
|
14924
15255
|
trackId: string(),
|
|
@@ -15179,6 +15510,85 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
15179
15510
|
}), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
|
|
15180
15511
|
kind: "query",
|
|
15181
15512
|
auth: "admin"
|
|
15513
|
+
}), method(object({ deviceIds: array(number()).optional() }), TrainingExportSummarySchema, {
|
|
15514
|
+
kind: "query",
|
|
15515
|
+
auth: "admin"
|
|
15516
|
+
}), method(object({ deviceIds: array(number()).optional() }), object({ url: string() }), {
|
|
15517
|
+
kind: "query",
|
|
15518
|
+
auth: "admin"
|
|
15519
|
+
}), method(object({
|
|
15520
|
+
/** Empty ⇒ every camera that has staging tracks. A LIST, not a single
|
|
15521
|
+
* `deviceId`, deliberately: `deviceId` would make this device-bound and
|
|
15522
|
+
* route it at one camera's owner, and "every camera" would stop being
|
|
15523
|
+
* expressible at all. */
|
|
15524
|
+
deviceIds: array(number()).optional(),
|
|
15525
|
+
limit: number().int().min(1).max(500).optional()
|
|
15526
|
+
}), array(RetrainTrackSchema).readonly(), {
|
|
15527
|
+
kind: "query",
|
|
15528
|
+
auth: "admin"
|
|
15529
|
+
}), method(object({ trackId: string() }), RetrainFrameListSchema, {
|
|
15530
|
+
kind: "query",
|
|
15531
|
+
auth: "admin"
|
|
15532
|
+
}), method(object({
|
|
15533
|
+
deviceId: number(),
|
|
15534
|
+
trackId: string(),
|
|
15535
|
+
mediaKeys: array(string()).min(1)
|
|
15536
|
+
}), RetrainFrameSelectionSchema, {
|
|
15537
|
+
kind: "mutation",
|
|
15538
|
+
auth: "admin"
|
|
15539
|
+
}), method(object({
|
|
15540
|
+
deviceId: number(),
|
|
15541
|
+
trackId: string(),
|
|
15542
|
+
frameId: string()
|
|
15543
|
+
}), object({
|
|
15544
|
+
removed: boolean(),
|
|
15545
|
+
removedAnnotations: number().int()
|
|
15546
|
+
}), {
|
|
15547
|
+
kind: "mutation",
|
|
15548
|
+
auth: "admin"
|
|
15549
|
+
}), method(object({ frameId: string() }), object({
|
|
15550
|
+
base64: string(),
|
|
15551
|
+
width: number().int(),
|
|
15552
|
+
height: number().int()
|
|
15553
|
+
}), {
|
|
15554
|
+
kind: "query",
|
|
15555
|
+
auth: "admin"
|
|
15556
|
+
}), method(object({
|
|
15557
|
+
deviceId: number(),
|
|
15558
|
+
trackId: string(),
|
|
15559
|
+
frameId: string(),
|
|
15560
|
+
subject: RetrainAssistSubjectSchema,
|
|
15561
|
+
/** Which node runs it. Absent ⇒ wherever an unowned call lands. */
|
|
15562
|
+
nodeId: string().optional()
|
|
15563
|
+
}), RetrainAssistResultSchema, {
|
|
15564
|
+
kind: "mutation",
|
|
15565
|
+
auth: "admin"
|
|
15566
|
+
}), method(object({ trackId: string() }), array(RetrainAnnotationSchema).readonly(), {
|
|
15567
|
+
kind: "query",
|
|
15568
|
+
auth: "admin"
|
|
15569
|
+
}), method(object({
|
|
15570
|
+
deviceId: number(),
|
|
15571
|
+
trackId: string(),
|
|
15572
|
+
frameId: string(),
|
|
15573
|
+
annotations: array(RetrainAnnotationDraftSchema)
|
|
15574
|
+
}), array(RetrainAnnotationSchema).readonly(), {
|
|
15575
|
+
kind: "mutation",
|
|
15576
|
+
auth: "admin"
|
|
15577
|
+
}), method(object({
|
|
15578
|
+
deviceId: number(),
|
|
15579
|
+
trackId: string()
|
|
15580
|
+
}), RetrainTransitionResultSchema, {
|
|
15581
|
+
kind: "mutation",
|
|
15582
|
+
auth: "admin"
|
|
15583
|
+
}), method(object({
|
|
15584
|
+
deviceId: number(),
|
|
15585
|
+
trackId: string()
|
|
15586
|
+
}), RetrainTransitionResultSchema, {
|
|
15587
|
+
kind: "mutation",
|
|
15588
|
+
auth: "admin"
|
|
15589
|
+
}), method(object({ deviceIds: array(number()).optional() }), object({ url: string() }), {
|
|
15590
|
+
kind: "query",
|
|
15591
|
+
auth: "admin"
|
|
15182
15592
|
}), method(object({
|
|
15183
15593
|
eventId: string(),
|
|
15184
15594
|
kind: MediaFileKindEnum.optional()
|
|
@@ -15758,6 +16168,22 @@ var DetailResultSchema = object({
|
|
|
15758
16168
|
bbox: NativeCropBboxSchema.optional(),
|
|
15759
16169
|
embedding: string().optional(),
|
|
15760
16170
|
label: string().optional(),
|
|
16171
|
+
/**
|
|
16172
|
+
* The tier `label` occupies, copied VERBATIM from the producing step's
|
|
16173
|
+
* `StepDefinition.labelTier` (roadmap 4g). Present only when `label` is.
|
|
16174
|
+
*
|
|
16175
|
+
* It rides the wire rather than being resolved by the consumer because the
|
|
16176
|
+
* declaration lives with the step definition, which only the executing node
|
|
16177
|
+
* has: post-analysis holds no step registry, and re-deriving the tier from
|
|
16178
|
+
* `className` there would be exactly the inference this model exists to
|
|
16179
|
+
* forbid. A `label` that arrives WITHOUT this field is refused by the write
|
|
16180
|
+
* rule and logged (`label tier undeclared`) — an older runner therefore
|
|
16181
|
+
* stops enriching rather than guessing, which is why addon-pipeline is
|
|
16182
|
+
* deployed BEFORE addon-post-analysis.
|
|
16183
|
+
*/
|
|
16184
|
+
labelTier: union([literal(1), literal(2)]).optional(),
|
|
16185
|
+
/** Model that produced `label` — carried into the tier's attribution. */
|
|
16186
|
+
labelModelId: string().optional(),
|
|
15761
16187
|
alignedCropJpeg: string().optional(),
|
|
15762
16188
|
/** Face short side (px) measured on the NATIVE crop surface. The `bbox`
|
|
15763
16189
|
* above is detection-frame px (≈6× smaller on a 4K camera) — min-face-size
|
|
@@ -20839,6 +21265,173 @@ DeviceType.Camera, method(object({
|
|
|
20839
21265
|
status: OsdStatusSchema
|
|
20840
21266
|
});
|
|
20841
21267
|
/**
|
|
21268
|
+
* `osd-manager` — the ORCHESTRATOR over the device-scope `osd` cap.
|
|
21269
|
+
*
|
|
21270
|
+
* The `osd` cap is the firmware contract: it probes a camera's overlay
|
|
21271
|
+
* SLOTS and writes literal text into one. It has no idea WHERE that text
|
|
21272
|
+
* comes from, and it must not — a driver that grew a "show the temperature
|
|
21273
|
+
* here" feature would grow it once per vendor.
|
|
21274
|
+
*
|
|
21275
|
+
* This cap owns the other half: a per-(camera, slot) BINDING that says
|
|
21276
|
+
* which value feeds the slot, how it is formatted, and under which
|
|
21277
|
+
* conditions it is shown at all. One addon renders every binding on every
|
|
21278
|
+
* camera, so a new source costs zero driver code.
|
|
21279
|
+
*
|
|
21280
|
+
* Three deliberate choices, each with a rejected alternative:
|
|
21281
|
+
*
|
|
21282
|
+
* 1. A source is `(capName, valuePath)` over the kernel's device
|
|
21283
|
+
* runtime-state mirror — NOT a closed enum of source kinds. Every
|
|
21284
|
+
* cap-keyed slice a device publishes is bindable the day the cap
|
|
21285
|
+
* ships. The rejected alternative (one enum member per source, with
|
|
21286
|
+
* a resolver branch each) is what makes "add the humidity too" a
|
|
21287
|
+
* code change.
|
|
21288
|
+
* 2. The display gate reuses `NcConditionsSchema` verbatim — the
|
|
21289
|
+
* notification centre's condition vocabulary — rather than a parallel
|
|
21290
|
+
* model. An operator who has learned one condition editor has learned
|
|
21291
|
+
* both.
|
|
21292
|
+
* 3. Because the renderer's facts are device STATE and not a detection
|
|
21293
|
+
* record, only a SUBSET of that vocabulary can be answered here.
|
|
21294
|
+
* `setSlotBinding` REJECTS the rest at write time (see
|
|
21295
|
+
* `getConditionSupport`). It does not accept-then-fail-closed: a
|
|
21296
|
+
* condition that can never be true renders a permanently blank
|
|
21297
|
+
* overlay, and a blank overlay looks exactly like a broken camera.
|
|
21298
|
+
*/
|
|
21299
|
+
/** Where a slot's value comes from. */
|
|
21300
|
+
var OsdSourceSchema = discriminatedUnion("kind", [
|
|
21301
|
+
object({
|
|
21302
|
+
kind: literal("static"),
|
|
21303
|
+
text: string().max(64)
|
|
21304
|
+
}),
|
|
21305
|
+
object({
|
|
21306
|
+
kind: literal("clock"),
|
|
21307
|
+
/** Token pattern: `YYYY MM DD HH mm ss`. Everything else is literal. */
|
|
21308
|
+
pattern: string().min(1).max(32).default("HH:mm"),
|
|
21309
|
+
/** IANA zone. Omitted = the server's zone. */
|
|
21310
|
+
timezone: string().min(1).max(64).optional()
|
|
21311
|
+
}),
|
|
21312
|
+
object({
|
|
21313
|
+
kind: literal("device-state"),
|
|
21314
|
+
deviceId: number().int().optional(),
|
|
21315
|
+
capName: string().min(1).max(64),
|
|
21316
|
+
/** Dot path inside the slice, e.g. `detected`, `value`, `mode`. */
|
|
21317
|
+
valuePath: string().min(1).max(64)
|
|
21318
|
+
})
|
|
21319
|
+
]);
|
|
21320
|
+
var OsdSlotBindingSchema = object({
|
|
21321
|
+
/** Off = the manager stops driving this slot. It does NOT clear it. */
|
|
21322
|
+
enabled: boolean().default(true),
|
|
21323
|
+
source: OsdSourceSchema,
|
|
21324
|
+
/** `${value}` and `${unit}` are substituted; every occurrence. */
|
|
21325
|
+
template: string().max(96).default("${value}"),
|
|
21326
|
+
/** Truncate with an ellipsis past this length. Absent = no limit. */
|
|
21327
|
+
maxCharacters: number().int().min(4).max(64).optional(),
|
|
21328
|
+
/**
|
|
21329
|
+
* Decimal places for a numeric value. `0` yields an integer — the
|
|
21330
|
+
* documented workaround for firmwares that reject `.` in overlay text.
|
|
21331
|
+
*/
|
|
21332
|
+
maxDecimals: number().int().min(0).max(4).default(1),
|
|
21333
|
+
/** Appended via `${unit}`. The state mirror does not carry units. */
|
|
21334
|
+
unitLabel: string().max(8).optional(),
|
|
21335
|
+
/** Raw value → display text, e.g. `{"true":"MOTION","false":""}`. */
|
|
21336
|
+
valueMap: record(string(), string()).optional(),
|
|
21337
|
+
/** Time windows in which the slot is shown. Absent = always. */
|
|
21338
|
+
schedule: NcScheduleSchema.optional(),
|
|
21339
|
+
/**
|
|
21340
|
+
* Display gate, in the notification centre's condition vocabulary.
|
|
21341
|
+
* Only the keys reported by `getConditionSupport` are accepted.
|
|
21342
|
+
*/
|
|
21343
|
+
conditions: NcConditionsSchema.optional(),
|
|
21344
|
+
/** Rendered when the gate is closed or the value unreadable. Empty = hide. */
|
|
21345
|
+
fallbackText: string().max(64).default("")
|
|
21346
|
+
});
|
|
21347
|
+
/** One camera slot, as the operator sees it: firmware truth + our binding. */
|
|
21348
|
+
var OsdSlotViewSchema = object({
|
|
21349
|
+
slotId: string(),
|
|
21350
|
+
kind: OsdOverlayKindEnum,
|
|
21351
|
+
/** Firmware refuses text edits (a timestamp, the channel name). */
|
|
21352
|
+
readOnly: boolean(),
|
|
21353
|
+
cameraEnabled: boolean(),
|
|
21354
|
+
cameraText: string().optional(),
|
|
21355
|
+
binding: OsdSlotBindingSchema.nullable()
|
|
21356
|
+
});
|
|
21357
|
+
/**
|
|
21358
|
+
* What happened to one slot on one render pass. `unchanged` exists so the
|
|
21359
|
+
* operator can tell "we are driving this and the value is steady" from
|
|
21360
|
+
* "we never got there" — and so the loop can prove it is not rewriting
|
|
21361
|
+
* identical text to the camera every tick.
|
|
21362
|
+
*/
|
|
21363
|
+
var OsdRenderOutcomeEnum = _enum([
|
|
21364
|
+
"written",
|
|
21365
|
+
"unchanged",
|
|
21366
|
+
"gated",
|
|
21367
|
+
"unreadable",
|
|
21368
|
+
"disabled",
|
|
21369
|
+
"unbound",
|
|
21370
|
+
"failed"
|
|
21371
|
+
]);
|
|
21372
|
+
var OsdRenderResultSchema = object({
|
|
21373
|
+
slotId: string(),
|
|
21374
|
+
outcome: OsdRenderOutcomeEnum,
|
|
21375
|
+
/** The text the slot should carry. Empty = the slot is switched off. */
|
|
21376
|
+
text: string(),
|
|
21377
|
+
/** Why, whenever the outcome is not a plain write. Never silent. */
|
|
21378
|
+
reason: string().optional()
|
|
21379
|
+
});
|
|
21380
|
+
var OsdSourceValueTypeEnum = _enum([
|
|
21381
|
+
"number",
|
|
21382
|
+
"boolean",
|
|
21383
|
+
"string",
|
|
21384
|
+
"enum"
|
|
21385
|
+
]);
|
|
21386
|
+
/**
|
|
21387
|
+
* One bindable value, derived from a cap's `runtimeState` schema — never
|
|
21388
|
+
* hand-listed. The editor renders from this, so a cap that ships a new
|
|
21389
|
+
* state field becomes bindable with no UI change.
|
|
21390
|
+
*/
|
|
21391
|
+
var OsdSourceOptionSchema = object({
|
|
21392
|
+
deviceId: number().int(),
|
|
21393
|
+
deviceName: string(),
|
|
21394
|
+
capName: string(),
|
|
21395
|
+
valuePath: string(),
|
|
21396
|
+
label: string(),
|
|
21397
|
+
valueType: OsdSourceValueTypeEnum,
|
|
21398
|
+
/** Present for `enum`; the editor offers these as `valueMap` keys. */
|
|
21399
|
+
enumValues: array(string()).readonly().optional()
|
|
21400
|
+
});
|
|
21401
|
+
method(object({ deviceId: number().int() }), object({
|
|
21402
|
+
supported: boolean(),
|
|
21403
|
+
slots: array(OsdSlotViewSchema)
|
|
21404
|
+
}), { auth: "admin" }), method(object({ deviceId: number().int() }), object({ sources: array(OsdSourceOptionSchema) }), { auth: "admin" }), method(object({}), object({
|
|
21405
|
+
supported: array(string()),
|
|
21406
|
+
catalog: array(NcConditionDescriptorSchema)
|
|
21407
|
+
}), { auth: "admin" }), method(object({
|
|
21408
|
+
deviceId: number().int(),
|
|
21409
|
+
slotId: string().min(1),
|
|
21410
|
+
binding: OsdSlotBindingSchema
|
|
21411
|
+
}), object({
|
|
21412
|
+
slot: OsdSlotViewSchema,
|
|
21413
|
+
render: OsdRenderResultSchema
|
|
21414
|
+
}), {
|
|
21415
|
+
kind: "mutation",
|
|
21416
|
+
auth: "admin"
|
|
21417
|
+
}), method(object({
|
|
21418
|
+
deviceId: number().int(),
|
|
21419
|
+
slotId: string().min(1)
|
|
21420
|
+
}), object({ success: literal(true) }), {
|
|
21421
|
+
kind: "mutation",
|
|
21422
|
+
auth: "admin"
|
|
21423
|
+
}), method(object({
|
|
21424
|
+
deviceId: number().int(),
|
|
21425
|
+
slotId: string().min(1),
|
|
21426
|
+
binding: OsdSlotBindingSchema.optional()
|
|
21427
|
+
}), OsdRenderResultSchema, {
|
|
21428
|
+
kind: "mutation",
|
|
21429
|
+
auth: "admin"
|
|
21430
|
+
}), method(object({ deviceId: number().int() }), object({ results: array(OsdRenderResultSchema) }), {
|
|
21431
|
+
kind: "mutation",
|
|
21432
|
+
auth: "admin"
|
|
21433
|
+
});
|
|
21434
|
+
/**
|
|
20842
21435
|
* Feeder connectivity / power status — mirrors the HA petkit device-status
|
|
20843
21436
|
* enum: `normal` (online, mains), `offline` (not reaching PetKit cloud),
|
|
20844
21437
|
* `on_batteries` (running on battery backup). `null` until first reported.
|
|
@@ -25794,6 +26387,48 @@ Object.freeze({
|
|
|
25794
26387
|
addonId: null,
|
|
25795
26388
|
access: "create"
|
|
25796
26389
|
},
|
|
26390
|
+
"osdManager.clearSlotBinding": {
|
|
26391
|
+
capName: "osd-manager",
|
|
26392
|
+
capScope: "system",
|
|
26393
|
+
addonId: null,
|
|
26394
|
+
access: "delete"
|
|
26395
|
+
},
|
|
26396
|
+
"osdManager.getConditionSupport": {
|
|
26397
|
+
capName: "osd-manager",
|
|
26398
|
+
capScope: "system",
|
|
26399
|
+
addonId: null,
|
|
26400
|
+
access: "view"
|
|
26401
|
+
},
|
|
26402
|
+
"osdManager.getDeviceOsd": {
|
|
26403
|
+
capName: "osd-manager",
|
|
26404
|
+
capScope: "system",
|
|
26405
|
+
addonId: null,
|
|
26406
|
+
access: "view"
|
|
26407
|
+
},
|
|
26408
|
+
"osdManager.getSourceCatalog": {
|
|
26409
|
+
capName: "osd-manager",
|
|
26410
|
+
capScope: "system",
|
|
26411
|
+
addonId: null,
|
|
26412
|
+
access: "view"
|
|
26413
|
+
},
|
|
26414
|
+
"osdManager.previewSlot": {
|
|
26415
|
+
capName: "osd-manager",
|
|
26416
|
+
capScope: "system",
|
|
26417
|
+
addonId: null,
|
|
26418
|
+
access: "create"
|
|
26419
|
+
},
|
|
26420
|
+
"osdManager.renderDevice": {
|
|
26421
|
+
capName: "osd-manager",
|
|
26422
|
+
capScope: "system",
|
|
26423
|
+
addonId: null,
|
|
26424
|
+
access: "create"
|
|
26425
|
+
},
|
|
26426
|
+
"osdManager.setSlotBinding": {
|
|
26427
|
+
capName: "osd-manager",
|
|
26428
|
+
capScope: "system",
|
|
26429
|
+
addonId: null,
|
|
26430
|
+
access: "create"
|
|
26431
|
+
},
|
|
25797
26432
|
"petFeeder.callPet": {
|
|
25798
26433
|
capName: "pet-feeder",
|
|
25799
26434
|
capScope: "device",
|
|
@@ -25866,6 +26501,12 @@ Object.freeze({
|
|
|
25866
26501
|
addonId: null,
|
|
25867
26502
|
access: "delete"
|
|
25868
26503
|
},
|
|
26504
|
+
"pipelineAnalytics.completeRetrainTrack": {
|
|
26505
|
+
capName: "pipeline-analytics",
|
|
26506
|
+
capScope: "device",
|
|
26507
|
+
addonId: null,
|
|
26508
|
+
access: "create"
|
|
26509
|
+
},
|
|
25869
26510
|
"pipelineAnalytics.deleteDeviceEvents": {
|
|
25870
26511
|
capName: "pipeline-analytics",
|
|
25871
26512
|
capScope: "device",
|
|
@@ -25878,6 +26519,12 @@ Object.freeze({
|
|
|
25878
26519
|
addonId: null,
|
|
25879
26520
|
access: "delete"
|
|
25880
26521
|
},
|
|
26522
|
+
"pipelineAnalytics.deselectRetrainFrame": {
|
|
26523
|
+
capName: "pipeline-analytics",
|
|
26524
|
+
capScope: "device",
|
|
26525
|
+
addonId: null,
|
|
26526
|
+
access: "create"
|
|
26527
|
+
},
|
|
25881
26528
|
"pipelineAnalytics.getActiveTracks": {
|
|
25882
26529
|
capName: "pipeline-analytics",
|
|
25883
26530
|
capScope: "device",
|
|
@@ -25938,6 +26585,18 @@ Object.freeze({
|
|
|
25938
26585
|
addonId: null,
|
|
25939
26586
|
access: "view"
|
|
25940
26587
|
},
|
|
26588
|
+
"pipelineAnalytics.getRetrainExportUrl": {
|
|
26589
|
+
capName: "pipeline-analytics",
|
|
26590
|
+
capScope: "device",
|
|
26591
|
+
addonId: null,
|
|
26592
|
+
access: "view"
|
|
26593
|
+
},
|
|
26594
|
+
"pipelineAnalytics.getRetrainFrameImage": {
|
|
26595
|
+
capName: "pipeline-analytics",
|
|
26596
|
+
capScope: "device",
|
|
26597
|
+
addonId: null,
|
|
26598
|
+
access: "view"
|
|
26599
|
+
},
|
|
25941
26600
|
"pipelineAnalytics.getSensorEvents": {
|
|
25942
26601
|
capName: "pipeline-analytics",
|
|
25943
26602
|
capScope: "device",
|
|
@@ -25956,6 +26615,18 @@ Object.freeze({
|
|
|
25956
26615
|
addonId: null,
|
|
25957
26616
|
access: "view"
|
|
25958
26617
|
},
|
|
26618
|
+
"pipelineAnalytics.getTrainingExportSummary": {
|
|
26619
|
+
capName: "pipeline-analytics",
|
|
26620
|
+
capScope: "device",
|
|
26621
|
+
addonId: null,
|
|
26622
|
+
access: "view"
|
|
26623
|
+
},
|
|
26624
|
+
"pipelineAnalytics.getTrainingExportUrl": {
|
|
26625
|
+
capName: "pipeline-analytics",
|
|
26626
|
+
capScope: "device",
|
|
26627
|
+
addonId: null,
|
|
26628
|
+
access: "view"
|
|
26629
|
+
},
|
|
25959
26630
|
"pipelineAnalytics.listEventKinds": {
|
|
25960
26631
|
capName: "pipeline-analytics",
|
|
25961
26632
|
capScope: "device",
|
|
@@ -25980,6 +26651,24 @@ Object.freeze({
|
|
|
25980
26651
|
addonId: null,
|
|
25981
26652
|
access: "view"
|
|
25982
26653
|
},
|
|
26654
|
+
"pipelineAnalytics.listRetrainAnnotations": {
|
|
26655
|
+
capName: "pipeline-analytics",
|
|
26656
|
+
capScope: "device",
|
|
26657
|
+
addonId: null,
|
|
26658
|
+
access: "view"
|
|
26659
|
+
},
|
|
26660
|
+
"pipelineAnalytics.listRetrainFrames": {
|
|
26661
|
+
capName: "pipeline-analytics",
|
|
26662
|
+
capScope: "device",
|
|
26663
|
+
addonId: null,
|
|
26664
|
+
access: "view"
|
|
26665
|
+
},
|
|
26666
|
+
"pipelineAnalytics.listRetrainStaging": {
|
|
26667
|
+
capName: "pipeline-analytics",
|
|
26668
|
+
capScope: "device",
|
|
26669
|
+
addonId: null,
|
|
26670
|
+
access: "view"
|
|
26671
|
+
},
|
|
25983
26672
|
"pipelineAnalytics.listTrackMedia": {
|
|
25984
26673
|
capName: "pipeline-analytics",
|
|
25985
26674
|
capScope: "device",
|
|
@@ -25992,6 +26681,12 @@ Object.freeze({
|
|
|
25992
26681
|
addonId: null,
|
|
25993
26682
|
access: "view"
|
|
25994
26683
|
},
|
|
26684
|
+
"pipelineAnalytics.proposeRetrainAnnotations": {
|
|
26685
|
+
capName: "pipeline-analytics",
|
|
26686
|
+
capScope: "device",
|
|
26687
|
+
addonId: null,
|
|
26688
|
+
access: "create"
|
|
26689
|
+
},
|
|
25995
26690
|
"pipelineAnalytics.pruneEvents": {
|
|
25996
26691
|
capName: "pipeline-analytics",
|
|
25997
26692
|
capScope: "device",
|
|
@@ -26022,12 +26717,30 @@ Object.freeze({
|
|
|
26022
26717
|
addonId: null,
|
|
26023
26718
|
access: "create"
|
|
26024
26719
|
},
|
|
26720
|
+
"pipelineAnalytics.restageRetrainTrack": {
|
|
26721
|
+
capName: "pipeline-analytics",
|
|
26722
|
+
capScope: "device",
|
|
26723
|
+
addonId: null,
|
|
26724
|
+
access: "create"
|
|
26725
|
+
},
|
|
26726
|
+
"pipelineAnalytics.saveRetrainAnnotations": {
|
|
26727
|
+
capName: "pipeline-analytics",
|
|
26728
|
+
capScope: "device",
|
|
26729
|
+
addonId: null,
|
|
26730
|
+
access: "create"
|
|
26731
|
+
},
|
|
26025
26732
|
"pipelineAnalytics.searchObjectEvents": {
|
|
26026
26733
|
capName: "pipeline-analytics",
|
|
26027
26734
|
capScope: "device",
|
|
26028
26735
|
addonId: null,
|
|
26029
26736
|
access: "view"
|
|
26030
26737
|
},
|
|
26738
|
+
"pipelineAnalytics.selectRetrainFrames": {
|
|
26739
|
+
capName: "pipeline-analytics",
|
|
26740
|
+
capScope: "device",
|
|
26741
|
+
addonId: null,
|
|
26742
|
+
access: "create"
|
|
26743
|
+
},
|
|
26031
26744
|
"pipelineAnalytics.setTrackFlags": {
|
|
26032
26745
|
capName: "pipeline-analytics",
|
|
26033
26746
|
capScope: "device",
|
|
@@ -27432,6 +28145,12 @@ Object.freeze({
|
|
|
27432
28145
|
addonId: null,
|
|
27433
28146
|
access: "view"
|
|
27434
28147
|
},
|
|
28148
|
+
"streamBroker.getDeviceAudioMute": {
|
|
28149
|
+
capName: "stream-broker",
|
|
28150
|
+
capScope: "system",
|
|
28151
|
+
addonId: null,
|
|
28152
|
+
access: "view"
|
|
28153
|
+
},
|
|
27435
28154
|
"streamBroker.getPreBufferInfo": {
|
|
27436
28155
|
capName: "stream-broker",
|
|
27437
28156
|
capScope: "system",
|
|
@@ -27552,6 +28271,12 @@ Object.freeze({
|
|
|
27552
28271
|
addonId: null,
|
|
27553
28272
|
access: "create"
|
|
27554
28273
|
},
|
|
28274
|
+
"streamBroker.setDeviceAudioMute": {
|
|
28275
|
+
capName: "stream-broker",
|
|
28276
|
+
capScope: "system",
|
|
28277
|
+
addonId: null,
|
|
28278
|
+
access: "create"
|
|
28279
|
+
},
|
|
27555
28280
|
"streamBroker.setPreBufferDuration": {
|
|
27556
28281
|
capName: "stream-broker",
|
|
27557
28282
|
capScope: "system",
|
|
@@ -28413,7 +29138,7 @@ var AdminUIAddon = class extends BaseAddon {
|
|
|
28413
29138
|
capability: adminUiCapability,
|
|
28414
29139
|
provider: {
|
|
28415
29140
|
getStaticDir: async () => ({ staticDir: resolveAdminUiDistDir() }),
|
|
28416
|
-
getVersion: async () => ({ version: "1.2.
|
|
29141
|
+
getVersion: async () => ({ version: "1.2.35" })
|
|
28417
29142
|
}
|
|
28418
29143
|
}];
|
|
28419
29144
|
}
|