@camstack/addon-export-alexa 1.2.128 → 1.2.130

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.
@@ -10767,6 +10767,57 @@ var ClipSearchStrictnessSchema = _enum([
10767
10767
  "balanced",
10768
10768
  "strict"
10769
10769
  ]);
10770
+ new Set([
10771
+ {
10772
+ id: "person",
10773
+ name: "Person"
10774
+ },
10775
+ {
10776
+ id: "vehicle",
10777
+ name: "Vehicle"
10778
+ },
10779
+ {
10780
+ id: "animal",
10781
+ name: "Animal"
10782
+ },
10783
+ {
10784
+ id: "package",
10785
+ name: "Package"
10786
+ }
10787
+ ].map((l) => l.id));
10788
+ var COCO_TO_MACRO = {
10789
+ mapping: {
10790
+ person: "person",
10791
+ bicycle: "vehicle",
10792
+ car: "vehicle",
10793
+ motorcycle: "vehicle",
10794
+ airplane: "vehicle",
10795
+ bus: "vehicle",
10796
+ train: "vehicle",
10797
+ truck: "vehicle",
10798
+ boat: "vehicle",
10799
+ bird: "animal",
10800
+ cat: "animal",
10801
+ dog: "animal",
10802
+ horse: "animal",
10803
+ sheep: "animal",
10804
+ cow: "animal",
10805
+ elephant: "animal",
10806
+ bear: "animal",
10807
+ zebra: "animal",
10808
+ giraffe: "animal",
10809
+ suitcase: "package",
10810
+ backpack: "package",
10811
+ handbag: "package"
10812
+ },
10813
+ preserveOriginal: false
10814
+ };
10815
+ /** Steps a root detector may declare it fills. */
10816
+ var FILLABLE_STEP_IDS = [
10817
+ "animal-classifier",
10818
+ "vehicle-classifier",
10819
+ "package-detection"
10820
+ ];
10770
10821
  var MODEL_FORMATS = [
10771
10822
  "onnx",
10772
10823
  "coreml",
@@ -10836,11 +10887,11 @@ var ModelVariantGroupSchema = object({
10836
10887
  /** Quantization axis. Omit ⇒ the fp32 base build. */
10837
10888
  precision: _enum(["fp32", "int8"]).optional(),
10838
10889
  /**
10839
- * Speed-optimization axis. Omit ⇒ the standard build. `fast` marks a
10840
- * latency-optimized export (e.g. ReLU-activation variant) — the slot the
10841
- * future performance variants plug into.
10890
+ * Training / latency-variant axis. Omit ⇒ the standard build. `test` marks
10891
+ * an alternate training of the same family (Scrypted `relu_test`); chip
10892
+ * label is "Test".
10842
10893
  */
10843
- optimization: _enum(["standard", "fast"]).optional(),
10894
+ optimization: _enum(["standard", "test"]).optional(),
10844
10895
  /**
10845
10896
  * Input-resolution axis (square input side, px). Omit ⇒ the family's native
10846
10897
  * resolution (640 for yolo26). Reduced-input builds (320 / 256) are a big,
@@ -10863,9 +10914,10 @@ var ModelProviderIdSchema = _enum([
10863
10914
  * are per upstream. A persisted custom-model row written when this field was a
10864
10915
  * string still parses — the string is lifted into `{ weights }`.
10865
10916
  *
10866
- * Every licence surface (the admin "Models and licenses" page,
10867
- * `THIRD_PARTY_MODELS.md`, the Hugging Face model table) is GENERATED from
10868
- * these records by `scripts/gen-model-licenses.ts` (D661).
10917
+ * Every machine licence surface (`THIRD_PARTY_MODELS.md`, the Hugging Face
10918
+ * model table) is GENERATED from these records by
10919
+ * `scripts/gen-model-licenses.ts` (D661). Operator-facing docs live in
10920
+ * `camstack/docs` → `/docs/detection/models`.
10869
10921
  */
10870
10922
  var ModelLicenseSchema = preprocess((value) => typeof value === "string" ? { weights: value } : value, object({
10871
10923
  /** SPDX id of the WEIGHTS' terms, a `LicenseRef-*` for non-SPDX terms, or `UNKNOWN`. */
@@ -10898,6 +10950,12 @@ var ModelLicenseSchema = preprocess((value) => typeof value === "string" ? { wei
10898
10950
  /** True when the weights or their data forbid commercial use. */
10899
10951
  nonCommercial: boolean().optional()
10900
10952
  }));
10953
+ /** One `fillsClassifierEffects` entry — see `ModelCatalogEntry.fillsClassifierEffects`. */
10954
+ var FillsClassifierEffectSchema = object({
10955
+ stepId: _enum(FILLABLE_STEP_IDS),
10956
+ labelToEffect: record(string(), string()),
10957
+ uncovered: array(string()).readonly()
10958
+ });
10901
10959
  var ModelCatalogEntrySchema = object({
10902
10960
  id: string(),
10903
10961
  name: string(),
@@ -11024,6 +11082,16 @@ var ModelCatalogEntrySchema = object({
11024
11082
  */
11025
11083
  classMap: DetectionCatalogClassMapSchema.optional(),
11026
11084
  /**
11085
+ * The pipeline steps this ROOT detector already does the work of (D715):
11086
+ * its labels name the effect the step exists to produce (`deer` for
11087
+ * `animal-classifier`, `package` for `package-detection`). Derived from the
11088
+ * labelmap by `deriveClassifierFills`, never hand-written; a COCO model
11089
+ * declares none. Whether a declaration is honoured is the step's own
11090
+ * `labelLink` policy (`resolveLabelLink`). `labelToEffect` values are in
11091
+ * `FILLABLE_STEP_VOCABULARIES` (guard `check-label-link-vocabulary`).
11092
+ */
11093
+ fillsClassifierEffects: array(FillsClassifierEffectSchema).readonly().optional(),
11094
+ /**
11027
11095
  * The model's CLIP feature-space contract (text encoder, dimension, vector
11028
11096
  * index, token window, search floor) — see `clip-model.ts`. Present ONLY on a
11029
11097
  * CLIP image encoder; its absence is what "not a CLIP model" means to the
@@ -14420,7 +14488,7 @@ DeviceType.Camera;
14420
14488
  * This matters here more than anywhere else in the repo, because every provider
14421
14489
  * that knows a device's host knows its PASSWORD too: `{ host, port, username,
14422
14490
  * password }` sit in one object on Hikvision, Amcrest, Reolink and ONVIF alike,
14423
- * and `http://admin:hunter2@192.168.x.x/` is a URL a browser accepts. The
14491
+ * and `http://admin:hunter2@192.168.60.139/` is a URL a browser accepts. The
14424
14492
  * camera's own page will ask for its own login. That is correct, and pre-
14425
14493
  * filling it is the operator's business, not ours.
14426
14494
  *
@@ -17429,7 +17497,7 @@ method(object({
17429
17497
  timeoutMs: 6e5
17430
17498
  });
17431
17499
  method(object({
17432
- nodeId: string(),
17500
+ targetNodeId: string(),
17433
17501
  modelId: string(),
17434
17502
  format: _enum(MODEL_FORMATS),
17435
17503
  entry: ModelCatalogEntrySchema
@@ -17995,51 +18063,6 @@ method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSche
17995
18063
  kind: "mutation",
17996
18064
  auth: "admin"
17997
18065
  });
17998
- new Set([
17999
- {
18000
- id: "person",
18001
- name: "Person"
18002
- },
18003
- {
18004
- id: "vehicle",
18005
- name: "Vehicle"
18006
- },
18007
- {
18008
- id: "animal",
18009
- name: "Animal"
18010
- },
18011
- {
18012
- id: "package",
18013
- name: "Package"
18014
- }
18015
- ].map((l) => l.id));
18016
- var COCO_TO_MACRO = {
18017
- mapping: {
18018
- person: "person",
18019
- bicycle: "vehicle",
18020
- car: "vehicle",
18021
- motorcycle: "vehicle",
18022
- airplane: "vehicle",
18023
- bus: "vehicle",
18024
- train: "vehicle",
18025
- truck: "vehicle",
18026
- boat: "vehicle",
18027
- bird: "animal",
18028
- cat: "animal",
18029
- dog: "animal",
18030
- horse: "animal",
18031
- sheep: "animal",
18032
- cow: "animal",
18033
- elephant: "animal",
18034
- bear: "animal",
18035
- zebra: "animal",
18036
- giraffe: "animal",
18037
- suitcase: "package",
18038
- backpack: "package",
18039
- handbag: "package"
18040
- },
18041
- preserveOriginal: false
18042
- };
18043
18066
  var AUDIO_MACRO_LABELS = [
18044
18067
  {
18045
18068
  id: "speech",
@@ -19895,8 +19918,9 @@ var NcRuleSchema = NcRuleInputSchema.extend({
19895
19918
  disabledTargetIds: array(string()).default([])
19896
19919
  });
19897
19920
  /**
19898
- * The state-summary SECTIONS (D647 / D698): the D637 kind groups that report a
19899
- * still-true state. `backups-exports` and `alarm` are not sections — a completed
19921
+ * The state-summary SECTIONS (D647 / D698 / D708): the D637 kind groups that
19922
+ * report a still-true state. `addons` is the crash-looped addons only and
19923
+ * `addon-updates` the addons that are behind (D708 split them). `backups-exports` and `alarm` are not sections — a completed
19900
19924
  * job is not an open state, and the alarm stays instant.
19901
19925
  */
19902
19926
  var NcStateSummarySectionIdSchema = _enum([
@@ -19908,6 +19932,7 @@ var NcStateSummarySectionIdSchema = _enum([
19908
19932
  "detection-blind",
19909
19933
  "nodes",
19910
19934
  "addons",
19935
+ "addon-updates",
19911
19936
  "updates"
19912
19937
  ]);
19913
19938
  /** One section of a previewed state summary. `unavailable` = its state could not be read. */
@@ -20388,7 +20413,19 @@ var NcAlarmModeDelaysListSchema = array(object({
20388
20413
  * When this mode may be armed. Absent / null = always allowed (same as a
20389
20414
  * rule with no `schedule`). Evaluated with {@link isScheduleActive}.
20390
20415
  */
20391
- schedule: NcScheduleSchema.optional()
20416
+ schedule: NcScheduleSchema.optional(),
20417
+ /**
20418
+ * D706: while this mode's ENTRY DELAY runs, do the alarm rules' own pushes go out (as an
20419
+ * intrusion naming the locations)? Absent = false — the entry-delay notification is the
20420
+ * only one, and the matches ride the triggered notification's mosaic (D705).
20421
+ */
20422
+ notifyDuringEntryDelay: boolean().optional(),
20423
+ /**
20424
+ * D706: notify "watched again" when a sensor this arm bypassed closes and opens again.
20425
+ * Absent = false (logged, not sent). Even when true it is not sent when that same sensor
20426
+ * is the one that starts the entry delay — the entry-delay notification already names it.
20427
+ */
20428
+ notifySensorRewatched: boolean().optional()
20392
20429
  })).max(8).refine(uniqueModes, { message: "modeDelays: at most one entry per arm mode" });
20393
20430
  var NcAlarmModeDelaysEditListSchema = array(object({
20394
20431
  mode: AlarmArmModeSchema,
@@ -20397,7 +20434,11 @@ var NcAlarmModeDelaysEditListSchema = array(object({
20397
20434
  triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional(),
20398
20435
  postTriggeredAction: NcAlarmPostTriggeredActionSchema.nullable().optional(),
20399
20436
  /** Set a schedule, or `null` to clear (mode always allowed again). */
20400
- schedule: NcScheduleSchema.nullable().optional()
20437
+ schedule: NcScheduleSchema.nullable().optional(),
20438
+ /** D706: set the switch, or `null` to clear it (back to the default, false). */
20439
+ notifyDuringEntryDelay: boolean().nullable().optional(),
20440
+ /** D706: set the switch, or `null` to clear it (back to the default, false). */
20441
+ notifySensorRewatched: boolean().nullable().optional()
20401
20442
  })).max(8).refine(uniqueModes, { message: "modeDelays: at most one edit per arm mode" });
20402
20443
  /** One switch of the alarm table: put ONE device on, or take it off, ONE mode's list. */
20403
20444
  var NcAlarmNonBlockingEditSchema = object({
@@ -21374,39 +21415,19 @@ Object.freeze(Object.fromEntries([{
21374
21415
  label: "Face recognition model",
21375
21416
  defaultModelId: "auraface-r100",
21376
21417
  indexName: "the enrolled face gallery",
21377
- options: [
21378
- {
21379
- id: "auraface-r100",
21380
- label: "AuraFace R100"
21381
- },
21382
- {
21383
- id: "arcface-r100",
21384
- label: "ArcFace (ResNet34)"
21385
- },
21386
- {
21387
- id: "inception-resnet-v1",
21388
- label: "Inception ResNet V1"
21389
- }
21390
- ]
21418
+ options: [{
21419
+ id: "auraface-r100",
21420
+ label: "AuraFace R100"
21421
+ }]
21391
21422
  }, {
21392
21423
  stepId: "clip-embedding",
21393
21424
  label: "Semantic search model",
21394
- defaultModelId: "mobileclip-s1",
21425
+ defaultModelId: "siglip2-b16-224",
21395
21426
  indexName: "the object semantic-search index",
21396
- options: [
21397
- {
21398
- id: "mobileclip-s1",
21399
- label: "MobileCLIP S1"
21400
- },
21401
- {
21402
- id: "mobileclip-s2",
21403
- label: "MobileCLIP S2"
21404
- },
21405
- {
21406
- id: "siglip2-b16-224",
21407
- label: "SigLIP2 B/16 (Apache-2.0)"
21408
- }
21409
- ]
21427
+ options: [{
21428
+ id: "siglip2-b16-224",
21429
+ label: "SigLIP2 B/16 (Apache-2.0)"
21430
+ }]
21410
21431
  }].map((s) => [s.stepId, s.defaultModelId])));
21411
21432
  var CLUSTER_STEP_SETTING_FIELDS = [{
21412
21433
  stepId: "face-embedding",
@@ -23461,7 +23482,8 @@ var PipelineModelOptionSchema = object({
23461
23482
  group: ModelVariantGroupSchema.optional(),
23462
23483
  legacy: boolean().optional(),
23463
23484
  provider: ModelProviderIdSchema.optional(),
23464
- defaultConfidence: number().optional()
23485
+ defaultConfidence: number().optional(),
23486
+ fillsClassifierEffects: array(FillsClassifierEffectSchema).readonly().optional()
23465
23487
  });
23466
23488
  var ConfigFieldBridge = custom();
23467
23489
  var PipelineAddonSchemaSchema = object({
@@ -24254,6 +24276,22 @@ var MotionSourceEnum = _enum([
24254
24276
  "device-activity"
24255
24277
  ]);
24256
24278
  /**
24279
+ * What opened an on-motion detection SESSION: the motion source that passed the
24280
+ * camera's `motionSources` gate, and what raised it (the camera itself, or a
24281
+ * sensor the operator attached — D672). `sensorName` is the attached sensor's
24282
+ * device name as the orchestrator's camera-sensors resolution last read it;
24283
+ * absent when unknown or when the camera itself triggered.
24284
+ *
24285
+ * Carried on the session attach ONLY so the runner's `DetectionPhaseTransition`
24286
+ * can say what started the session (D672 rule 11, amended 2026-10-06). The
24287
+ * runner never decides anything on it.
24288
+ */
24289
+ var SessionTriggerSchema = object({
24290
+ source: MotionSourceEnum,
24291
+ triggeredBy: MotionTriggeredBySchema,
24292
+ sensorName: string().optional()
24293
+ });
24294
+ /**
24257
24295
  * List of motion sources active on a camera. Empty array is valid:
24258
24296
  * "no source" — happens for battery cams without firmware motion when
24259
24297
  * the operator hasn't opted into the SW analyzer (would hold the
@@ -24505,6 +24543,14 @@ var RunnerCameraConfigSchema = object({
24505
24543
  */
24506
24544
  motionSources: MotionSourcesSchema.default(["analyzer"]),
24507
24545
  /**
24546
+ * What opened this attach, on a SESSION attach only (see
24547
+ * {@link SessionTriggerSchema}). OPTIONAL with no default: absent on a
24548
+ * standing attach, an occupancy burst, a re-dispatch with no motion event
24549
+ * behind it, and every attach from an orchestrator older than the field — the
24550
+ * runner then names no source on the phase event.
24551
+ */
24552
+ sessionTrigger: SessionTriggerSchema.optional(),
24553
+ /**
24508
24554
  * WHICH root detector runs for this camera. The detection counterpart of
24509
24555
  * {@link motionSources}, same shape and same discipline: a per-camera list
24510
24556
  * of sources the system understands, vendor-agnostic, owned here.
@@ -30728,7 +30774,7 @@ var LocalInterfaceSchema = object({
30728
30774
  name: string(),
30729
30775
  family: _enum(["IPv4", "IPv6"]),
30730
30776
  address: string(),
30731
- /** CIDR shorthand (e.g. `192.168.x.x/24`). Empty when OS doesn't expose. */
30777
+ /** CIDR shorthand (e.g. `192.168.10.10/24`). Empty when OS doesn't expose. */
30732
30778
  cidr: string(),
30733
30779
  /** OS netmask. Stable across calls so the SDK can hash on it. */
30734
30780
  netmask: string(),
@@ -30782,7 +30828,8 @@ var ConnectionEndpointSchema = object({
30782
30828
  "lan-ipv4",
30783
30829
  "lan-ipv6",
30784
30830
  "public",
30785
- "loopback"
30831
+ "loopback",
30832
+ "app-link"
30786
30833
  ]),
30787
30834
  /**
30788
30835
  * Originating-interface kind — `lan`/`wifi`/`docker`/`vpn`/`other`/
@@ -30851,15 +30898,27 @@ var GetConnectionEndpointsResultSchema = object({
30851
30898
  localPort: AdvertisedLocalPortSchema
30852
30899
  });
30853
30900
  /**
30854
- * The chosen outbound endpoint for notification artifacts. `baseUrl: null` =
30855
- * AUTO (resolved from the candidate ranking at send time); `resolved` reports
30856
- * what AUTO currently picks, so the UI can show the effective value either way.
30901
+ * The address flagged for notification links. `baseUrl: null` = AUTO, which
30902
+ * since D709 is the CamStack app link; `resolved` reports the effective value,
30903
+ * so the UI can show it either way.
30857
30904
  */
30858
30905
  var NotificationEndpointSchema = object({
30859
30906
  /** The operator's explicit choice, or null for AUTO. */
30860
30907
  baseUrl: string().nullable(),
30861
- /** What the ranking currently resolves to (null when nothing is reachable). */
30862
- resolved: string().nullable()
30908
+ /**
30909
+ * The effective flagged address: the explicit choice, else (AUTO) the
30910
+ * CamStack app link `https://camstack.zentik.app` (D709). A pre-D709 hub
30911
+ * answered the public tunnel / mesh here, or null.
30912
+ */
30913
+ resolved: string().nullable(),
30914
+ /**
30915
+ * The hub origin an app link carries as `hub=` (D709): the hub's best
30916
+ * public HTTPS address — the tunnel, then the mesh (Tailscale MagicDNS) —
30917
+ * picked from this cap's own palette by `pickAppLinkHub`. `null` when the
30918
+ * hub advertises neither; the app link is then minted without `hub=`.
30919
+ * Absent on a pre-D709 hub.
30920
+ */
30921
+ appLinkHub: string().nullable()
30863
30922
  });
30864
30923
  /**
30865
30924
  * The URLs the SDK / viewer should race for API access. `baseUrls` empty =
@@ -30913,7 +30972,11 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
30913
30972
  * Pass `'https'` when the caller is itself loaded over HTTPS
30914
30973
  * to avoid mixed-content blocks in the browser. The public
30915
30974
  * tunnel always emits `https://` regardless. */
30916
- scheme: _enum(["http", "https"]).optional()
30975
+ scheme: _enum(["http", "https"]).optional(),
30976
+ /** Append the CamStack app link entry (`kind: 'app-link'`, D709) —
30977
+ * an address notification links can be flagged with, not a hub
30978
+ * route. Default `false`: racers and rankers never see it. */
30979
+ includeAppLink: boolean().optional()
30917
30980
  }), GetConnectionEndpointsResultSchema), method(_void(), NotificationEndpointSchema), method(object({ baseUrl: string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }), method(_void(), ViewerEndpointsSchema), method(object({ baseUrls: array(string()).readonly() }), ViewerEndpointsSchema, { kind: "mutation" }), method(_void(), AllowedAddressesSchema), method(AllowedAddressesSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), AllowedAddressesSchema, { kind: "mutation" }), method(_void(), TlsStatusSchema), method(object({ reason: string().optional() }), TlsStatusSchema, {
30918
30981
  kind: "mutation",
30919
30982
  auth: "admin"
@@ -31174,7 +31237,7 @@ var MeshPeerSchema = object({
31174
31237
  tags: array(string()).readonly(),
31175
31238
  /** True when the peer advertises itself as an exit-node candidate. */
31176
31239
  exitNodeOption: boolean(),
31177
- /** Subnet routes the peer advertises (e.g. `["192.168.x.x/24"]`). */
31240
+ /** Subnet routes the peer advertises (e.g. `["192.168.10.0/24"]`). */
31178
31241
  advertisedRoutes: array(string()).readonly(),
31179
31242
  /** Owner account login (e.g. `foo@example.com`). Null for tagged peers. */
31180
31243
  userLogin: string().nullable(),
@@ -32118,7 +32181,13 @@ var OsdStatusSchema = object({ overlays: array(object({
32118
32181
  */
32119
32182
  availablePositions: array(OsdPositionEnum).readonly(),
32120
32183
  /** Firmware does not allow editing the `text` field (e.g. timestamp). */
32121
- readOnly: boolean().optional()
32184
+ readOnly: boolean().optional(),
32185
+ /**
32186
+ * Firmware text ceiling for this overlay. Absent = no known limit.
32187
+ * The OSD manager truncates here on every write — never stores its own
32188
+ * copy on the binding.
32189
+ */
32190
+ maxCharacters: number().int().positive().optional()
32122
32191
  })).readonly() });
32123
32192
  var OsdOverlayPatchSchema = object({
32124
32193
  enabled: boolean().optional(),
@@ -32169,7 +32238,9 @@ var OsdTemplateBindingSchema = object({
32169
32238
  valuePath: string().min(1).max(64),
32170
32239
  /** Convert TO this unit at render (`tryConvertUnit`). Absent = source unit. */
32171
32240
  displayUnit: string().max(16).optional(),
32172
- maxDecimals: number().int().min(0).max(4).default(1)
32241
+ maxDecimals: number().int().min(0).max(4).default(1),
32242
+ /** Raw value → display text (same shape as slot binding). Empty string hides. */
32243
+ valueMap: record(string(), string()).optional()
32173
32244
  });
32174
32245
  /**
32175
32246
  * A named template: bindings (alias → leaf field) + a parser that
@@ -32219,18 +32290,11 @@ var OsdSlotBindingSchema = object({
32219
32290
  source: OsdSourceSchema,
32220
32291
  /** `${value}` and `${unit}` are substituted; every occurrence. */
32221
32292
  template: string().max(96).default("${value}"),
32222
- /** Truncate with an ellipsis past this length. Absent = no limit. */
32223
- maxCharacters: number().int().min(4).max(64).optional(),
32224
32293
  /**
32225
32294
  * Decimal places for a numeric value. `0` yields an integer — the
32226
32295
  * documented workaround for firmwares that reject `.` in overlay text.
32227
32296
  */
32228
32297
  maxDecimals: number().int().min(0).max(4).default(1),
32229
- /**
32230
- * Appended via `${unit}` when no unit conversion produces a label.
32231
- * Prefer `source.displayUnit` for converted device-state values.
32232
- */
32233
- unitLabel: string().max(8).optional(),
32234
32298
  /** Raw value → display text, e.g. `{"true":"MOTION","false":""}`. */
32235
32299
  valueMap: record(string(), string()).optional(),
32236
32300
  /** Time windows in which the slot is shown. Absent = always. */
@@ -32239,9 +32303,7 @@ var OsdSlotBindingSchema = object({
32239
32303
  * Display gate, in the notification centre's condition vocabulary.
32240
32304
  * Only the keys reported by `getConditionSupport` are accepted.
32241
32305
  */
32242
- conditions: NcConditionsSchema.optional(),
32243
- /** Rendered when the gate is closed or the value unreadable. Empty = hide. */
32244
- fallbackText: string().max(64).default("")
32306
+ conditions: NcConditionsSchema.optional()
32245
32307
  });
32246
32308
  /** One camera slot, as the operator sees it: firmware truth + our binding. */
32247
32309
  var OsdSlotViewSchema = object({
@@ -47918,12 +47980,14 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
47918
47980
  {
47919
47981
  id: "addons",
47920
47982
  family: "system",
47921
- label: "Addons",
47922
- kinds: [
47923
- "addon-crash-loop",
47924
- "addon-update-available",
47925
- "addon-updated"
47926
- ]
47983
+ label: "Addons stopped",
47984
+ kinds: ["addon-crash-loop"]
47985
+ },
47986
+ {
47987
+ id: "addon-updates",
47988
+ family: "system",
47989
+ label: "Addon updates",
47990
+ kinds: ["addon-update-available", "addon-updated"]
47927
47991
  },
47928
47992
  {
47929
47993
  id: "updates",
@@ -48083,13 +48147,15 @@ var STATE_SUMMARY_SECTION_VARS = [
48083
48147
  },
48084
48148
  {
48085
48149
  name: "summaryAddons",
48086
- label: "Summary: addons",
48087
- example: "@camstack/addon-recorder 1.2.3 → 1.2.4",
48088
- kinds: [
48089
- "addon-crash-loop",
48090
- "addon-update-available",
48091
- "addon-updated"
48092
- ]
48150
+ label: "Summary: addons stopped",
48151
+ example: "hub — recorder stopped after repeated crashes",
48152
+ kinds: ["addon-crash-loop"]
48153
+ },
48154
+ {
48155
+ name: "summaryAddonUpdates",
48156
+ label: "Summary: addon updates",
48157
+ example: "hub:\n• @camstack/addon-recorder 1.2.3 → 1.2.4",
48158
+ kinds: ["addon-update-available", "addon-updated"]
48093
48159
  },
48094
48160
  {
48095
48161
  name: "summaryUpdates",
@@ -48173,6 +48239,7 @@ var STATE_SUMMARY_VARS = [
48173
48239
  [...RULE_BODY_ONLY],
48174
48240
  [...RULE_TEXT],
48175
48241
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
48242
+ ([...RULE_TEXT], [...COMBINED_ALARM]),
48176
48243
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
48177
48244
  ([...RULE_TEXT], [...BATTERY, ...CONSUMABLE]),
48178
48245
  ([...RULE_TEXT], [...CONSUMABLE]),
@@ -48213,6 +48280,8 @@ var STATE_SUMMARY_VARS = [
48213
48280
  [...RULE_TEXT],
48214
48281
  [...RULE_TEXT],
48215
48282
  [...RULE_TEXT],
48283
+ [...RULE_TEXT],
48284
+ [...RULE_TEXT],
48216
48285
  ...STATE_SUMMARY_VARS
48217
48286
  ];
48218
48287
  new Set([
@@ -10740,6 +10740,57 @@ var ClipSearchStrictnessSchema = _enum([
10740
10740
  "balanced",
10741
10741
  "strict"
10742
10742
  ]);
10743
+ new Set([
10744
+ {
10745
+ id: "person",
10746
+ name: "Person"
10747
+ },
10748
+ {
10749
+ id: "vehicle",
10750
+ name: "Vehicle"
10751
+ },
10752
+ {
10753
+ id: "animal",
10754
+ name: "Animal"
10755
+ },
10756
+ {
10757
+ id: "package",
10758
+ name: "Package"
10759
+ }
10760
+ ].map((l) => l.id));
10761
+ var COCO_TO_MACRO = {
10762
+ mapping: {
10763
+ person: "person",
10764
+ bicycle: "vehicle",
10765
+ car: "vehicle",
10766
+ motorcycle: "vehicle",
10767
+ airplane: "vehicle",
10768
+ bus: "vehicle",
10769
+ train: "vehicle",
10770
+ truck: "vehicle",
10771
+ boat: "vehicle",
10772
+ bird: "animal",
10773
+ cat: "animal",
10774
+ dog: "animal",
10775
+ horse: "animal",
10776
+ sheep: "animal",
10777
+ cow: "animal",
10778
+ elephant: "animal",
10779
+ bear: "animal",
10780
+ zebra: "animal",
10781
+ giraffe: "animal",
10782
+ suitcase: "package",
10783
+ backpack: "package",
10784
+ handbag: "package"
10785
+ },
10786
+ preserveOriginal: false
10787
+ };
10788
+ /** Steps a root detector may declare it fills. */
10789
+ var FILLABLE_STEP_IDS = [
10790
+ "animal-classifier",
10791
+ "vehicle-classifier",
10792
+ "package-detection"
10793
+ ];
10743
10794
  var MODEL_FORMATS = [
10744
10795
  "onnx",
10745
10796
  "coreml",
@@ -10809,11 +10860,11 @@ var ModelVariantGroupSchema = object({
10809
10860
  /** Quantization axis. Omit ⇒ the fp32 base build. */
10810
10861
  precision: _enum(["fp32", "int8"]).optional(),
10811
10862
  /**
10812
- * Speed-optimization axis. Omit ⇒ the standard build. `fast` marks a
10813
- * latency-optimized export (e.g. ReLU-activation variant) — the slot the
10814
- * future performance variants plug into.
10863
+ * Training / latency-variant axis. Omit ⇒ the standard build. `test` marks
10864
+ * an alternate training of the same family (Scrypted `relu_test`); chip
10865
+ * label is "Test".
10815
10866
  */
10816
- optimization: _enum(["standard", "fast"]).optional(),
10867
+ optimization: _enum(["standard", "test"]).optional(),
10817
10868
  /**
10818
10869
  * Input-resolution axis (square input side, px). Omit ⇒ the family's native
10819
10870
  * resolution (640 for yolo26). Reduced-input builds (320 / 256) are a big,
@@ -10836,9 +10887,10 @@ var ModelProviderIdSchema = _enum([
10836
10887
  * are per upstream. A persisted custom-model row written when this field was a
10837
10888
  * string still parses — the string is lifted into `{ weights }`.
10838
10889
  *
10839
- * Every licence surface (the admin "Models and licenses" page,
10840
- * `THIRD_PARTY_MODELS.md`, the Hugging Face model table) is GENERATED from
10841
- * these records by `scripts/gen-model-licenses.ts` (D661).
10890
+ * Every machine licence surface (`THIRD_PARTY_MODELS.md`, the Hugging Face
10891
+ * model table) is GENERATED from these records by
10892
+ * `scripts/gen-model-licenses.ts` (D661). Operator-facing docs live in
10893
+ * `camstack/docs` → `/docs/detection/models`.
10842
10894
  */
10843
10895
  var ModelLicenseSchema = preprocess((value) => typeof value === "string" ? { weights: value } : value, object({
10844
10896
  /** SPDX id of the WEIGHTS' terms, a `LicenseRef-*` for non-SPDX terms, or `UNKNOWN`. */
@@ -10871,6 +10923,12 @@ var ModelLicenseSchema = preprocess((value) => typeof value === "string" ? { wei
10871
10923
  /** True when the weights or their data forbid commercial use. */
10872
10924
  nonCommercial: boolean().optional()
10873
10925
  }));
10926
+ /** One `fillsClassifierEffects` entry — see `ModelCatalogEntry.fillsClassifierEffects`. */
10927
+ var FillsClassifierEffectSchema = object({
10928
+ stepId: _enum(FILLABLE_STEP_IDS),
10929
+ labelToEffect: record(string(), string()),
10930
+ uncovered: array(string()).readonly()
10931
+ });
10874
10932
  var ModelCatalogEntrySchema = object({
10875
10933
  id: string(),
10876
10934
  name: string(),
@@ -10997,6 +11055,16 @@ var ModelCatalogEntrySchema = object({
10997
11055
  */
10998
11056
  classMap: DetectionCatalogClassMapSchema.optional(),
10999
11057
  /**
11058
+ * The pipeline steps this ROOT detector already does the work of (D715):
11059
+ * its labels name the effect the step exists to produce (`deer` for
11060
+ * `animal-classifier`, `package` for `package-detection`). Derived from the
11061
+ * labelmap by `deriveClassifierFills`, never hand-written; a COCO model
11062
+ * declares none. Whether a declaration is honoured is the step's own
11063
+ * `labelLink` policy (`resolveLabelLink`). `labelToEffect` values are in
11064
+ * `FILLABLE_STEP_VOCABULARIES` (guard `check-label-link-vocabulary`).
11065
+ */
11066
+ fillsClassifierEffects: array(FillsClassifierEffectSchema).readonly().optional(),
11067
+ /**
11000
11068
  * The model's CLIP feature-space contract (text encoder, dimension, vector
11001
11069
  * index, token window, search floor) — see `clip-model.ts`. Present ONLY on a
11002
11070
  * CLIP image encoder; its absence is what "not a CLIP model" means to the
@@ -14393,7 +14461,7 @@ DeviceType.Camera;
14393
14461
  * This matters here more than anywhere else in the repo, because every provider
14394
14462
  * that knows a device's host knows its PASSWORD too: `{ host, port, username,
14395
14463
  * password }` sit in one object on Hikvision, Amcrest, Reolink and ONVIF alike,
14396
- * and `http://admin:hunter2@192.168.x.x/` is a URL a browser accepts. The
14464
+ * and `http://admin:hunter2@192.168.60.139/` is a URL a browser accepts. The
14397
14465
  * camera's own page will ask for its own login. That is correct, and pre-
14398
14466
  * filling it is the operator's business, not ours.
14399
14467
  *
@@ -17402,7 +17470,7 @@ method(object({
17402
17470
  timeoutMs: 6e5
17403
17471
  });
17404
17472
  method(object({
17405
- nodeId: string(),
17473
+ targetNodeId: string(),
17406
17474
  modelId: string(),
17407
17475
  format: _enum(MODEL_FORMATS),
17408
17476
  entry: ModelCatalogEntrySchema
@@ -17968,51 +18036,6 @@ method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSche
17968
18036
  kind: "mutation",
17969
18037
  auth: "admin"
17970
18038
  });
17971
- new Set([
17972
- {
17973
- id: "person",
17974
- name: "Person"
17975
- },
17976
- {
17977
- id: "vehicle",
17978
- name: "Vehicle"
17979
- },
17980
- {
17981
- id: "animal",
17982
- name: "Animal"
17983
- },
17984
- {
17985
- id: "package",
17986
- name: "Package"
17987
- }
17988
- ].map((l) => l.id));
17989
- var COCO_TO_MACRO = {
17990
- mapping: {
17991
- person: "person",
17992
- bicycle: "vehicle",
17993
- car: "vehicle",
17994
- motorcycle: "vehicle",
17995
- airplane: "vehicle",
17996
- bus: "vehicle",
17997
- train: "vehicle",
17998
- truck: "vehicle",
17999
- boat: "vehicle",
18000
- bird: "animal",
18001
- cat: "animal",
18002
- dog: "animal",
18003
- horse: "animal",
18004
- sheep: "animal",
18005
- cow: "animal",
18006
- elephant: "animal",
18007
- bear: "animal",
18008
- zebra: "animal",
18009
- giraffe: "animal",
18010
- suitcase: "package",
18011
- backpack: "package",
18012
- handbag: "package"
18013
- },
18014
- preserveOriginal: false
18015
- };
18016
18039
  var AUDIO_MACRO_LABELS = [
18017
18040
  {
18018
18041
  id: "speech",
@@ -19868,8 +19891,9 @@ var NcRuleSchema = NcRuleInputSchema.extend({
19868
19891
  disabledTargetIds: array(string()).default([])
19869
19892
  });
19870
19893
  /**
19871
- * The state-summary SECTIONS (D647 / D698): the D637 kind groups that report a
19872
- * still-true state. `backups-exports` and `alarm` are not sections — a completed
19894
+ * The state-summary SECTIONS (D647 / D698 / D708): the D637 kind groups that
19895
+ * report a still-true state. `addons` is the crash-looped addons only and
19896
+ * `addon-updates` the addons that are behind (D708 split them). `backups-exports` and `alarm` are not sections — a completed
19873
19897
  * job is not an open state, and the alarm stays instant.
19874
19898
  */
19875
19899
  var NcStateSummarySectionIdSchema = _enum([
@@ -19881,6 +19905,7 @@ var NcStateSummarySectionIdSchema = _enum([
19881
19905
  "detection-blind",
19882
19906
  "nodes",
19883
19907
  "addons",
19908
+ "addon-updates",
19884
19909
  "updates"
19885
19910
  ]);
19886
19911
  /** One section of a previewed state summary. `unavailable` = its state could not be read. */
@@ -20361,7 +20386,19 @@ var NcAlarmModeDelaysListSchema = array(object({
20361
20386
  * When this mode may be armed. Absent / null = always allowed (same as a
20362
20387
  * rule with no `schedule`). Evaluated with {@link isScheduleActive}.
20363
20388
  */
20364
- schedule: NcScheduleSchema.optional()
20389
+ schedule: NcScheduleSchema.optional(),
20390
+ /**
20391
+ * D706: while this mode's ENTRY DELAY runs, do the alarm rules' own pushes go out (as an
20392
+ * intrusion naming the locations)? Absent = false — the entry-delay notification is the
20393
+ * only one, and the matches ride the triggered notification's mosaic (D705).
20394
+ */
20395
+ notifyDuringEntryDelay: boolean().optional(),
20396
+ /**
20397
+ * D706: notify "watched again" when a sensor this arm bypassed closes and opens again.
20398
+ * Absent = false (logged, not sent). Even when true it is not sent when that same sensor
20399
+ * is the one that starts the entry delay — the entry-delay notification already names it.
20400
+ */
20401
+ notifySensorRewatched: boolean().optional()
20365
20402
  })).max(8).refine(uniqueModes, { message: "modeDelays: at most one entry per arm mode" });
20366
20403
  var NcAlarmModeDelaysEditListSchema = array(object({
20367
20404
  mode: AlarmArmModeSchema,
@@ -20370,7 +20407,11 @@ var NcAlarmModeDelaysEditListSchema = array(object({
20370
20407
  triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional(),
20371
20408
  postTriggeredAction: NcAlarmPostTriggeredActionSchema.nullable().optional(),
20372
20409
  /** Set a schedule, or `null` to clear (mode always allowed again). */
20373
- schedule: NcScheduleSchema.nullable().optional()
20410
+ schedule: NcScheduleSchema.nullable().optional(),
20411
+ /** D706: set the switch, or `null` to clear it (back to the default, false). */
20412
+ notifyDuringEntryDelay: boolean().nullable().optional(),
20413
+ /** D706: set the switch, or `null` to clear it (back to the default, false). */
20414
+ notifySensorRewatched: boolean().nullable().optional()
20374
20415
  })).max(8).refine(uniqueModes, { message: "modeDelays: at most one edit per arm mode" });
20375
20416
  /** One switch of the alarm table: put ONE device on, or take it off, ONE mode's list. */
20376
20417
  var NcAlarmNonBlockingEditSchema = object({
@@ -21347,39 +21388,19 @@ Object.freeze(Object.fromEntries([{
21347
21388
  label: "Face recognition model",
21348
21389
  defaultModelId: "auraface-r100",
21349
21390
  indexName: "the enrolled face gallery",
21350
- options: [
21351
- {
21352
- id: "auraface-r100",
21353
- label: "AuraFace R100"
21354
- },
21355
- {
21356
- id: "arcface-r100",
21357
- label: "ArcFace (ResNet34)"
21358
- },
21359
- {
21360
- id: "inception-resnet-v1",
21361
- label: "Inception ResNet V1"
21362
- }
21363
- ]
21391
+ options: [{
21392
+ id: "auraface-r100",
21393
+ label: "AuraFace R100"
21394
+ }]
21364
21395
  }, {
21365
21396
  stepId: "clip-embedding",
21366
21397
  label: "Semantic search model",
21367
- defaultModelId: "mobileclip-s1",
21398
+ defaultModelId: "siglip2-b16-224",
21368
21399
  indexName: "the object semantic-search index",
21369
- options: [
21370
- {
21371
- id: "mobileclip-s1",
21372
- label: "MobileCLIP S1"
21373
- },
21374
- {
21375
- id: "mobileclip-s2",
21376
- label: "MobileCLIP S2"
21377
- },
21378
- {
21379
- id: "siglip2-b16-224",
21380
- label: "SigLIP2 B/16 (Apache-2.0)"
21381
- }
21382
- ]
21400
+ options: [{
21401
+ id: "siglip2-b16-224",
21402
+ label: "SigLIP2 B/16 (Apache-2.0)"
21403
+ }]
21383
21404
  }].map((s) => [s.stepId, s.defaultModelId])));
21384
21405
  var CLUSTER_STEP_SETTING_FIELDS = [{
21385
21406
  stepId: "face-embedding",
@@ -23434,7 +23455,8 @@ var PipelineModelOptionSchema = object({
23434
23455
  group: ModelVariantGroupSchema.optional(),
23435
23456
  legacy: boolean().optional(),
23436
23457
  provider: ModelProviderIdSchema.optional(),
23437
- defaultConfidence: number().optional()
23458
+ defaultConfidence: number().optional(),
23459
+ fillsClassifierEffects: array(FillsClassifierEffectSchema).readonly().optional()
23438
23460
  });
23439
23461
  var ConfigFieldBridge = custom();
23440
23462
  var PipelineAddonSchemaSchema = object({
@@ -24227,6 +24249,22 @@ var MotionSourceEnum = _enum([
24227
24249
  "device-activity"
24228
24250
  ]);
24229
24251
  /**
24252
+ * What opened an on-motion detection SESSION: the motion source that passed the
24253
+ * camera's `motionSources` gate, and what raised it (the camera itself, or a
24254
+ * sensor the operator attached — D672). `sensorName` is the attached sensor's
24255
+ * device name as the orchestrator's camera-sensors resolution last read it;
24256
+ * absent when unknown or when the camera itself triggered.
24257
+ *
24258
+ * Carried on the session attach ONLY so the runner's `DetectionPhaseTransition`
24259
+ * can say what started the session (D672 rule 11, amended 2026-10-06). The
24260
+ * runner never decides anything on it.
24261
+ */
24262
+ var SessionTriggerSchema = object({
24263
+ source: MotionSourceEnum,
24264
+ triggeredBy: MotionTriggeredBySchema,
24265
+ sensorName: string().optional()
24266
+ });
24267
+ /**
24230
24268
  * List of motion sources active on a camera. Empty array is valid:
24231
24269
  * "no source" — happens for battery cams without firmware motion when
24232
24270
  * the operator hasn't opted into the SW analyzer (would hold the
@@ -24478,6 +24516,14 @@ var RunnerCameraConfigSchema = object({
24478
24516
  */
24479
24517
  motionSources: MotionSourcesSchema.default(["analyzer"]),
24480
24518
  /**
24519
+ * What opened this attach, on a SESSION attach only (see
24520
+ * {@link SessionTriggerSchema}). OPTIONAL with no default: absent on a
24521
+ * standing attach, an occupancy burst, a re-dispatch with no motion event
24522
+ * behind it, and every attach from an orchestrator older than the field — the
24523
+ * runner then names no source on the phase event.
24524
+ */
24525
+ sessionTrigger: SessionTriggerSchema.optional(),
24526
+ /**
24481
24527
  * WHICH root detector runs for this camera. The detection counterpart of
24482
24528
  * {@link motionSources}, same shape and same discipline: a per-camera list
24483
24529
  * of sources the system understands, vendor-agnostic, owned here.
@@ -30701,7 +30747,7 @@ var LocalInterfaceSchema = object({
30701
30747
  name: string(),
30702
30748
  family: _enum(["IPv4", "IPv6"]),
30703
30749
  address: string(),
30704
- /** CIDR shorthand (e.g. `192.168.x.x/24`). Empty when OS doesn't expose. */
30750
+ /** CIDR shorthand (e.g. `192.168.10.10/24`). Empty when OS doesn't expose. */
30705
30751
  cidr: string(),
30706
30752
  /** OS netmask. Stable across calls so the SDK can hash on it. */
30707
30753
  netmask: string(),
@@ -30755,7 +30801,8 @@ var ConnectionEndpointSchema = object({
30755
30801
  "lan-ipv4",
30756
30802
  "lan-ipv6",
30757
30803
  "public",
30758
- "loopback"
30804
+ "loopback",
30805
+ "app-link"
30759
30806
  ]),
30760
30807
  /**
30761
30808
  * Originating-interface kind — `lan`/`wifi`/`docker`/`vpn`/`other`/
@@ -30824,15 +30871,27 @@ var GetConnectionEndpointsResultSchema = object({
30824
30871
  localPort: AdvertisedLocalPortSchema
30825
30872
  });
30826
30873
  /**
30827
- * The chosen outbound endpoint for notification artifacts. `baseUrl: null` =
30828
- * AUTO (resolved from the candidate ranking at send time); `resolved` reports
30829
- * what AUTO currently picks, so the UI can show the effective value either way.
30874
+ * The address flagged for notification links. `baseUrl: null` = AUTO, which
30875
+ * since D709 is the CamStack app link; `resolved` reports the effective value,
30876
+ * so the UI can show it either way.
30830
30877
  */
30831
30878
  var NotificationEndpointSchema = object({
30832
30879
  /** The operator's explicit choice, or null for AUTO. */
30833
30880
  baseUrl: string().nullable(),
30834
- /** What the ranking currently resolves to (null when nothing is reachable). */
30835
- resolved: string().nullable()
30881
+ /**
30882
+ * The effective flagged address: the explicit choice, else (AUTO) the
30883
+ * CamStack app link `https://camstack.zentik.app` (D709). A pre-D709 hub
30884
+ * answered the public tunnel / mesh here, or null.
30885
+ */
30886
+ resolved: string().nullable(),
30887
+ /**
30888
+ * The hub origin an app link carries as `hub=` (D709): the hub's best
30889
+ * public HTTPS address — the tunnel, then the mesh (Tailscale MagicDNS) —
30890
+ * picked from this cap's own palette by `pickAppLinkHub`. `null` when the
30891
+ * hub advertises neither; the app link is then minted without `hub=`.
30892
+ * Absent on a pre-D709 hub.
30893
+ */
30894
+ appLinkHub: string().nullable()
30836
30895
  });
30837
30896
  /**
30838
30897
  * The URLs the SDK / viewer should race for API access. `baseUrls` empty =
@@ -30886,7 +30945,11 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
30886
30945
  * Pass `'https'` when the caller is itself loaded over HTTPS
30887
30946
  * to avoid mixed-content blocks in the browser. The public
30888
30947
  * tunnel always emits `https://` regardless. */
30889
- scheme: _enum(["http", "https"]).optional()
30948
+ scheme: _enum(["http", "https"]).optional(),
30949
+ /** Append the CamStack app link entry (`kind: 'app-link'`, D709) —
30950
+ * an address notification links can be flagged with, not a hub
30951
+ * route. Default `false`: racers and rankers never see it. */
30952
+ includeAppLink: boolean().optional()
30890
30953
  }), GetConnectionEndpointsResultSchema), method(_void(), NotificationEndpointSchema), method(object({ baseUrl: string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }), method(_void(), ViewerEndpointsSchema), method(object({ baseUrls: array(string()).readonly() }), ViewerEndpointsSchema, { kind: "mutation" }), method(_void(), AllowedAddressesSchema), method(AllowedAddressesSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), AllowedAddressesSchema, { kind: "mutation" }), method(_void(), TlsStatusSchema), method(object({ reason: string().optional() }), TlsStatusSchema, {
30891
30954
  kind: "mutation",
30892
30955
  auth: "admin"
@@ -31147,7 +31210,7 @@ var MeshPeerSchema = object({
31147
31210
  tags: array(string()).readonly(),
31148
31211
  /** True when the peer advertises itself as an exit-node candidate. */
31149
31212
  exitNodeOption: boolean(),
31150
- /** Subnet routes the peer advertises (e.g. `["192.168.x.x/24"]`). */
31213
+ /** Subnet routes the peer advertises (e.g. `["192.168.10.0/24"]`). */
31151
31214
  advertisedRoutes: array(string()).readonly(),
31152
31215
  /** Owner account login (e.g. `foo@example.com`). Null for tagged peers. */
31153
31216
  userLogin: string().nullable(),
@@ -32091,7 +32154,13 @@ var OsdStatusSchema = object({ overlays: array(object({
32091
32154
  */
32092
32155
  availablePositions: array(OsdPositionEnum).readonly(),
32093
32156
  /** Firmware does not allow editing the `text` field (e.g. timestamp). */
32094
- readOnly: boolean().optional()
32157
+ readOnly: boolean().optional(),
32158
+ /**
32159
+ * Firmware text ceiling for this overlay. Absent = no known limit.
32160
+ * The OSD manager truncates here on every write — never stores its own
32161
+ * copy on the binding.
32162
+ */
32163
+ maxCharacters: number().int().positive().optional()
32095
32164
  })).readonly() });
32096
32165
  var OsdOverlayPatchSchema = object({
32097
32166
  enabled: boolean().optional(),
@@ -32142,7 +32211,9 @@ var OsdTemplateBindingSchema = object({
32142
32211
  valuePath: string().min(1).max(64),
32143
32212
  /** Convert TO this unit at render (`tryConvertUnit`). Absent = source unit. */
32144
32213
  displayUnit: string().max(16).optional(),
32145
- maxDecimals: number().int().min(0).max(4).default(1)
32214
+ maxDecimals: number().int().min(0).max(4).default(1),
32215
+ /** Raw value → display text (same shape as slot binding). Empty string hides. */
32216
+ valueMap: record(string(), string()).optional()
32146
32217
  });
32147
32218
  /**
32148
32219
  * A named template: bindings (alias → leaf field) + a parser that
@@ -32192,18 +32263,11 @@ var OsdSlotBindingSchema = object({
32192
32263
  source: OsdSourceSchema,
32193
32264
  /** `${value}` and `${unit}` are substituted; every occurrence. */
32194
32265
  template: string().max(96).default("${value}"),
32195
- /** Truncate with an ellipsis past this length. Absent = no limit. */
32196
- maxCharacters: number().int().min(4).max(64).optional(),
32197
32266
  /**
32198
32267
  * Decimal places for a numeric value. `0` yields an integer — the
32199
32268
  * documented workaround for firmwares that reject `.` in overlay text.
32200
32269
  */
32201
32270
  maxDecimals: number().int().min(0).max(4).default(1),
32202
- /**
32203
- * Appended via `${unit}` when no unit conversion produces a label.
32204
- * Prefer `source.displayUnit` for converted device-state values.
32205
- */
32206
- unitLabel: string().max(8).optional(),
32207
32271
  /** Raw value → display text, e.g. `{"true":"MOTION","false":""}`. */
32208
32272
  valueMap: record(string(), string()).optional(),
32209
32273
  /** Time windows in which the slot is shown. Absent = always. */
@@ -32212,9 +32276,7 @@ var OsdSlotBindingSchema = object({
32212
32276
  * Display gate, in the notification centre's condition vocabulary.
32213
32277
  * Only the keys reported by `getConditionSupport` are accepted.
32214
32278
  */
32215
- conditions: NcConditionsSchema.optional(),
32216
- /** Rendered when the gate is closed or the value unreadable. Empty = hide. */
32217
- fallbackText: string().max(64).default("")
32279
+ conditions: NcConditionsSchema.optional()
32218
32280
  });
32219
32281
  /** One camera slot, as the operator sees it: firmware truth + our binding. */
32220
32282
  var OsdSlotViewSchema = object({
@@ -47891,12 +47953,14 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
47891
47953
  {
47892
47954
  id: "addons",
47893
47955
  family: "system",
47894
- label: "Addons",
47895
- kinds: [
47896
- "addon-crash-loop",
47897
- "addon-update-available",
47898
- "addon-updated"
47899
- ]
47956
+ label: "Addons stopped",
47957
+ kinds: ["addon-crash-loop"]
47958
+ },
47959
+ {
47960
+ id: "addon-updates",
47961
+ family: "system",
47962
+ label: "Addon updates",
47963
+ kinds: ["addon-update-available", "addon-updated"]
47900
47964
  },
47901
47965
  {
47902
47966
  id: "updates",
@@ -48056,13 +48120,15 @@ var STATE_SUMMARY_SECTION_VARS = [
48056
48120
  },
48057
48121
  {
48058
48122
  name: "summaryAddons",
48059
- label: "Summary: addons",
48060
- example: "@camstack/addon-recorder 1.2.3 → 1.2.4",
48061
- kinds: [
48062
- "addon-crash-loop",
48063
- "addon-update-available",
48064
- "addon-updated"
48065
- ]
48123
+ label: "Summary: addons stopped",
48124
+ example: "hub — recorder stopped after repeated crashes",
48125
+ kinds: ["addon-crash-loop"]
48126
+ },
48127
+ {
48128
+ name: "summaryAddonUpdates",
48129
+ label: "Summary: addon updates",
48130
+ example: "hub:\n• @camstack/addon-recorder 1.2.3 → 1.2.4",
48131
+ kinds: ["addon-update-available", "addon-updated"]
48066
48132
  },
48067
48133
  {
48068
48134
  name: "summaryUpdates",
@@ -48146,6 +48212,7 @@ var STATE_SUMMARY_VARS = [
48146
48212
  [...RULE_BODY_ONLY],
48147
48213
  [...RULE_TEXT],
48148
48214
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
48215
+ ([...RULE_TEXT], [...COMBINED_ALARM]),
48149
48216
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
48150
48217
  ([...RULE_TEXT], [...BATTERY, ...CONSUMABLE]),
48151
48218
  ([...RULE_TEXT], [...CONSUMABLE]),
@@ -48186,6 +48253,8 @@ var STATE_SUMMARY_VARS = [
48186
48253
  [...RULE_TEXT],
48187
48254
  [...RULE_TEXT],
48188
48255
  [...RULE_TEXT],
48256
+ [...RULE_TEXT],
48257
+ [...RULE_TEXT],
48189
48258
  ...STATE_SUMMARY_VARS
48190
48259
  ];
48191
48260
  new Set([
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-export-alexa",
3
- "version": "1.2.128",
3
+ "version": "1.2.130",
4
4
  "description": "Alexa Smart Home Skill export — hub-side OAuth provider + directive handler. The companion AWS Lambda forwards Alexa directives to this addon's /addon/export-alexa/directive endpoint.",
5
5
  "keywords": [
6
6
  "camstack",