@camstack/addon-provider-wyze 0.2.126 → 0.2.128

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/addon.js +244 -135
  2. package/dist/addon.mjs +244 -135
  3. package/package.json +1 -1
package/dist/addon.js CHANGED
@@ -10517,6 +10517,57 @@ var ClipSearchStrictnessSchema = _enum([
10517
10517
  "balanced",
10518
10518
  "strict"
10519
10519
  ]);
10520
+ new Set([
10521
+ {
10522
+ id: "person",
10523
+ name: "Person"
10524
+ },
10525
+ {
10526
+ id: "vehicle",
10527
+ name: "Vehicle"
10528
+ },
10529
+ {
10530
+ id: "animal",
10531
+ name: "Animal"
10532
+ },
10533
+ {
10534
+ id: "package",
10535
+ name: "Package"
10536
+ }
10537
+ ].map((l) => l.id));
10538
+ var COCO_TO_MACRO = {
10539
+ mapping: {
10540
+ person: "person",
10541
+ bicycle: "vehicle",
10542
+ car: "vehicle",
10543
+ motorcycle: "vehicle",
10544
+ airplane: "vehicle",
10545
+ bus: "vehicle",
10546
+ train: "vehicle",
10547
+ truck: "vehicle",
10548
+ boat: "vehicle",
10549
+ bird: "animal",
10550
+ cat: "animal",
10551
+ dog: "animal",
10552
+ horse: "animal",
10553
+ sheep: "animal",
10554
+ cow: "animal",
10555
+ elephant: "animal",
10556
+ bear: "animal",
10557
+ zebra: "animal",
10558
+ giraffe: "animal",
10559
+ suitcase: "package",
10560
+ backpack: "package",
10561
+ handbag: "package"
10562
+ },
10563
+ preserveOriginal: false
10564
+ };
10565
+ /** Steps a root detector may declare it fills. */
10566
+ var FILLABLE_STEP_IDS = [
10567
+ "animal-classifier",
10568
+ "vehicle-classifier",
10569
+ "package-detection"
10570
+ ];
10520
10571
  var MODEL_FORMATS = [
10521
10572
  "onnx",
10522
10573
  "coreml",
@@ -10586,11 +10637,11 @@ var ModelVariantGroupSchema = object({
10586
10637
  /** Quantization axis. Omit ⇒ the fp32 base build. */
10587
10638
  precision: _enum(["fp32", "int8"]).optional(),
10588
10639
  /**
10589
- * Speed-optimization axis. Omit ⇒ the standard build. `fast` marks a
10590
- * latency-optimized export (e.g. ReLU-activation variant) — the slot the
10591
- * future performance variants plug into.
10640
+ * Training / latency-variant axis. Omit ⇒ the standard build. `test` marks
10641
+ * an alternate training of the same family (Scrypted `relu_test`); chip
10642
+ * label is "Test".
10592
10643
  */
10593
- optimization: _enum(["standard", "fast"]).optional(),
10644
+ optimization: _enum(["standard", "test"]).optional(),
10594
10645
  /**
10595
10646
  * Input-resolution axis (square input side, px). Omit ⇒ the family's native
10596
10647
  * resolution (640 for yolo26). Reduced-input builds (320 / 256) are a big,
@@ -10613,9 +10664,10 @@ var ModelProviderIdSchema = _enum([
10613
10664
  * are per upstream. A persisted custom-model row written when this field was a
10614
10665
  * string still parses — the string is lifted into `{ weights }`.
10615
10666
  *
10616
- * Every licence surface (the admin "Models and licenses" page,
10617
- * `THIRD_PARTY_MODELS.md`, the Hugging Face model table) is GENERATED from
10618
- * these records by `scripts/gen-model-licenses.ts` (D661).
10667
+ * Every machine licence surface (`THIRD_PARTY_MODELS.md`, the Hugging Face
10668
+ * model table) is GENERATED from these records by
10669
+ * `scripts/gen-model-licenses.ts` (D661). Operator-facing docs live in
10670
+ * `camstack/docs` → `/docs/detection/models`.
10619
10671
  */
10620
10672
  var ModelLicenseSchema = preprocess((value) => typeof value === "string" ? { weights: value } : value, object({
10621
10673
  /** SPDX id of the WEIGHTS' terms, a `LicenseRef-*` for non-SPDX terms, or `UNKNOWN`. */
@@ -10648,6 +10700,12 @@ var ModelLicenseSchema = preprocess((value) => typeof value === "string" ? { wei
10648
10700
  /** True when the weights or their data forbid commercial use. */
10649
10701
  nonCommercial: boolean().optional()
10650
10702
  }));
10703
+ /** One `fillsClassifierEffects` entry — see `ModelCatalogEntry.fillsClassifierEffects`. */
10704
+ var FillsClassifierEffectSchema = object({
10705
+ stepId: _enum(FILLABLE_STEP_IDS),
10706
+ labelToEffect: record(string(), string()),
10707
+ uncovered: array(string()).readonly()
10708
+ });
10651
10709
  var ModelCatalogEntrySchema = object({
10652
10710
  id: string(),
10653
10711
  name: string(),
@@ -10774,6 +10832,16 @@ var ModelCatalogEntrySchema = object({
10774
10832
  */
10775
10833
  classMap: DetectionCatalogClassMapSchema.optional(),
10776
10834
  /**
10835
+ * The pipeline steps this ROOT detector already does the work of (D715):
10836
+ * its labels name the effect the step exists to produce (`deer` for
10837
+ * `animal-classifier`, `package` for `package-detection`). Derived from the
10838
+ * labelmap by `deriveClassifierFills`, never hand-written; a COCO model
10839
+ * declares none. Whether a declaration is honoured is the step's own
10840
+ * `labelLink` policy (`resolveLabelLink`). `labelToEffect` values are in
10841
+ * `FILLABLE_STEP_VOCABULARIES` (guard `check-label-link-vocabulary`).
10842
+ */
10843
+ fillsClassifierEffects: array(FillsClassifierEffectSchema).readonly().optional(),
10844
+ /**
10777
10845
  * The model's CLIP feature-space contract (text encoder, dimension, vector
10778
10846
  * index, token window, search floor) — see `clip-model.ts`. Present ONLY on a
10779
10847
  * CLIP image encoder; its absence is what "not a CLIP model" means to the
@@ -14246,7 +14314,7 @@ DeviceType.Camera;
14246
14314
  * This matters here more than anywhere else in the repo, because every provider
14247
14315
  * that knows a device's host knows its PASSWORD too: `{ host, port, username,
14248
14316
  * password }` sit in one object on Hikvision, Amcrest, Reolink and ONVIF alike,
14249
- * and `http://admin:hunter2@192.168.x.x/` is a URL a browser accepts. The
14317
+ * and `http://admin:hunter2@192.168.60.139/` is a URL a browser accepts. The
14250
14318
  * camera's own page will ask for its own login. That is correct, and pre-
14251
14319
  * filling it is the operator's business, not ours.
14252
14320
  *
@@ -17435,7 +17503,7 @@ method(object({
17435
17503
  timeoutMs: 6e5
17436
17504
  });
17437
17505
  method(object({
17438
- nodeId: string(),
17506
+ targetNodeId: string(),
17439
17507
  modelId: string(),
17440
17508
  format: _enum(MODEL_FORMATS),
17441
17509
  entry: ModelCatalogEntrySchema
@@ -18001,51 +18069,6 @@ method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSche
18001
18069
  kind: "mutation",
18002
18070
  auth: "admin"
18003
18071
  });
18004
- new Set([
18005
- {
18006
- id: "person",
18007
- name: "Person"
18008
- },
18009
- {
18010
- id: "vehicle",
18011
- name: "Vehicle"
18012
- },
18013
- {
18014
- id: "animal",
18015
- name: "Animal"
18016
- },
18017
- {
18018
- id: "package",
18019
- name: "Package"
18020
- }
18021
- ].map((l) => l.id));
18022
- var COCO_TO_MACRO = {
18023
- mapping: {
18024
- person: "person",
18025
- bicycle: "vehicle",
18026
- car: "vehicle",
18027
- motorcycle: "vehicle",
18028
- airplane: "vehicle",
18029
- bus: "vehicle",
18030
- train: "vehicle",
18031
- truck: "vehicle",
18032
- boat: "vehicle",
18033
- bird: "animal",
18034
- cat: "animal",
18035
- dog: "animal",
18036
- horse: "animal",
18037
- sheep: "animal",
18038
- cow: "animal",
18039
- elephant: "animal",
18040
- bear: "animal",
18041
- zebra: "animal",
18042
- giraffe: "animal",
18043
- suitcase: "package",
18044
- backpack: "package",
18045
- handbag: "package"
18046
- },
18047
- preserveOriginal: false
18048
- };
18049
18072
  var AUDIO_MACRO_LABELS = [
18050
18073
  {
18051
18074
  id: "speech",
@@ -18841,6 +18864,8 @@ var NcSystemEventKindSchema = _enum([
18841
18864
  "stream-offline",
18842
18865
  "node-online",
18843
18866
  "node-offline",
18867
+ "node-restarting",
18868
+ "node-updating",
18844
18869
  "node-inference-unavailable",
18845
18870
  "detection-blind",
18846
18871
  "addon-crash-loop",
@@ -19939,8 +19964,9 @@ var NcRuleSchema = NcRuleInputSchema.extend({
19939
19964
  disabledTargetIds: array(string()).default([])
19940
19965
  });
19941
19966
  /**
19942
- * The state-summary SECTIONS (D647 / D698): the D637 kind groups that report a
19943
- * still-true state. `backups-exports` and `alarm` are not sections — a completed
19967
+ * The state-summary SECTIONS (D647 / D698 / D708): the D637 kind groups that
19968
+ * report a still-true state. `addons` is the crash-looped addons only and
19969
+ * `addon-updates` the addons that are behind (D708 split them). `backups-exports` and `alarm` are not sections — a completed
19944
19970
  * job is not an open state, and the alarm stays instant.
19945
19971
  */
19946
19972
  var NcStateSummarySectionIdSchema = _enum([
@@ -19952,6 +19978,7 @@ var NcStateSummarySectionIdSchema = _enum([
19952
19978
  "detection-blind",
19953
19979
  "nodes",
19954
19980
  "addons",
19981
+ "addon-updates",
19955
19982
  "updates"
19956
19983
  ]);
19957
19984
  /** One section of a previewed state summary. `unavailable` = its state could not be read. */
@@ -20432,7 +20459,19 @@ var NcAlarmModeDelaysListSchema = array(object({
20432
20459
  * When this mode may be armed. Absent / null = always allowed (same as a
20433
20460
  * rule with no `schedule`). Evaluated with {@link isScheduleActive}.
20434
20461
  */
20435
- schedule: NcScheduleSchema.optional()
20462
+ schedule: NcScheduleSchema.optional(),
20463
+ /**
20464
+ * D706: while this mode's ENTRY DELAY runs, do the alarm rules' own pushes go out (as an
20465
+ * intrusion naming the locations)? Absent = false — the entry-delay notification is the
20466
+ * only one, and the matches ride the triggered notification's mosaic (D705).
20467
+ */
20468
+ notifyDuringEntryDelay: boolean().optional(),
20469
+ /**
20470
+ * D706: notify "watched again" when a sensor this arm bypassed closes and opens again.
20471
+ * Absent = false (logged, not sent). Even when true it is not sent when that same sensor
20472
+ * is the one that starts the entry delay — the entry-delay notification already names it.
20473
+ */
20474
+ notifySensorRewatched: boolean().optional()
20436
20475
  })).max(8).refine(uniqueModes, { message: "modeDelays: at most one entry per arm mode" });
20437
20476
  var NcAlarmModeDelaysEditListSchema = array(object({
20438
20477
  mode: AlarmArmModeSchema,
@@ -20441,7 +20480,11 @@ var NcAlarmModeDelaysEditListSchema = array(object({
20441
20480
  triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional(),
20442
20481
  postTriggeredAction: NcAlarmPostTriggeredActionSchema.nullable().optional(),
20443
20482
  /** Set a schedule, or `null` to clear (mode always allowed again). */
20444
- schedule: NcScheduleSchema.nullable().optional()
20483
+ schedule: NcScheduleSchema.nullable().optional(),
20484
+ /** D706: set the switch, or `null` to clear it (back to the default, false). */
20485
+ notifyDuringEntryDelay: boolean().nullable().optional(),
20486
+ /** D706: set the switch, or `null` to clear it (back to the default, false). */
20487
+ notifySensorRewatched: boolean().nullable().optional()
20445
20488
  })).max(8).refine(uniqueModes, { message: "modeDelays: at most one edit per arm mode" });
20446
20489
  /** One switch of the alarm table: put ONE device on, or take it off, ONE mode's list. */
20447
20490
  var NcAlarmNonBlockingEditSchema = object({
@@ -21402,39 +21445,19 @@ Object.freeze(Object.fromEntries([{
21402
21445
  label: "Face recognition model",
21403
21446
  defaultModelId: "auraface-r100",
21404
21447
  indexName: "the enrolled face gallery",
21405
- options: [
21406
- {
21407
- id: "auraface-r100",
21408
- label: "AuraFace R100"
21409
- },
21410
- {
21411
- id: "arcface-r100",
21412
- label: "ArcFace (ResNet34)"
21413
- },
21414
- {
21415
- id: "inception-resnet-v1",
21416
- label: "Inception ResNet V1"
21417
- }
21418
- ]
21448
+ options: [{
21449
+ id: "auraface-r100",
21450
+ label: "AuraFace R100"
21451
+ }]
21419
21452
  }, {
21420
21453
  stepId: "clip-embedding",
21421
21454
  label: "Semantic search model",
21422
- defaultModelId: "mobileclip-s1",
21455
+ defaultModelId: "siglip2-b16-224",
21423
21456
  indexName: "the object semantic-search index",
21424
- options: [
21425
- {
21426
- id: "mobileclip-s1",
21427
- label: "MobileCLIP S1"
21428
- },
21429
- {
21430
- id: "mobileclip-s2",
21431
- label: "MobileCLIP S2"
21432
- },
21433
- {
21434
- id: "siglip2-b16-224",
21435
- label: "SigLIP2 B/16 (Apache-2.0)"
21436
- }
21437
- ]
21457
+ options: [{
21458
+ id: "siglip2-b16-224",
21459
+ label: "SigLIP2 B/16 (Apache-2.0)"
21460
+ }]
21438
21461
  }].map((s) => [s.stepId, s.defaultModelId])));
21439
21462
  var CLUSTER_STEP_SETTING_FIELDS = [{
21440
21463
  stepId: "face-embedding",
@@ -23489,7 +23512,8 @@ var PipelineModelOptionSchema = object({
23489
23512
  group: ModelVariantGroupSchema.optional(),
23490
23513
  legacy: boolean().optional(),
23491
23514
  provider: ModelProviderIdSchema.optional(),
23492
- defaultConfidence: number().optional()
23515
+ defaultConfidence: number().optional(),
23516
+ fillsClassifierEffects: array(FillsClassifierEffectSchema).readonly().optional()
23493
23517
  });
23494
23518
  var ConfigFieldBridge = custom();
23495
23519
  var PipelineAddonSchemaSchema = object({
@@ -24322,6 +24346,22 @@ var MotionSourceEnum = _enum([
24322
24346
  "device-activity"
24323
24347
  ]);
24324
24348
  /**
24349
+ * What opened an on-motion detection SESSION: the motion source that passed the
24350
+ * camera's `motionSources` gate, and what raised it (the camera itself, or a
24351
+ * sensor the operator attached — D672). `sensorName` is the attached sensor's
24352
+ * device name as the orchestrator's camera-sensors resolution last read it;
24353
+ * absent when unknown or when the camera itself triggered.
24354
+ *
24355
+ * Carried on the session attach ONLY so the runner's `DetectionPhaseTransition`
24356
+ * can say what started the session (D672 rule 11, amended 2026-10-06). The
24357
+ * runner never decides anything on it.
24358
+ */
24359
+ var SessionTriggerSchema = object({
24360
+ source: MotionSourceEnum,
24361
+ triggeredBy: MotionTriggeredBySchema,
24362
+ sensorName: string().optional()
24363
+ });
24364
+ /**
24325
24365
  * List of motion sources active on a camera. Empty array is valid:
24326
24366
  * "no source" — happens for battery cams without firmware motion when
24327
24367
  * the operator hasn't opted into the SW analyzer (would hold the
@@ -24573,6 +24613,14 @@ var RunnerCameraConfigSchema = object({
24573
24613
  */
24574
24614
  motionSources: MotionSourcesSchema.default(["analyzer"]),
24575
24615
  /**
24616
+ * What opened this attach, on a SESSION attach only (see
24617
+ * {@link SessionTriggerSchema}). OPTIONAL with no default: absent on a
24618
+ * standing attach, an occupancy burst, a re-dispatch with no motion event
24619
+ * behind it, and every attach from an orchestrator older than the field — the
24620
+ * runner then names no source on the phase event.
24621
+ */
24622
+ sessionTrigger: SessionTriggerSchema.optional(),
24623
+ /**
24576
24624
  * WHICH root detector runs for this camera. The detection counterpart of
24577
24625
  * {@link motionSources}, same shape and same discipline: a per-camera list
24578
24626
  * of sources the system understands, vendor-agnostic, owned here.
@@ -32073,7 +32121,7 @@ var LocalInterfaceSchema = object({
32073
32121
  name: string(),
32074
32122
  family: _enum(["IPv4", "IPv6"]),
32075
32123
  address: string(),
32076
- /** CIDR shorthand (e.g. `192.168.x.x/24`). Empty when OS doesn't expose. */
32124
+ /** CIDR shorthand (e.g. `192.168.10.10/24`). Empty when OS doesn't expose. */
32077
32125
  cidr: string(),
32078
32126
  /** OS netmask. Stable across calls so the SDK can hash on it. */
32079
32127
  netmask: string(),
@@ -32127,7 +32175,8 @@ var ConnectionEndpointSchema = object({
32127
32175
  "lan-ipv4",
32128
32176
  "lan-ipv6",
32129
32177
  "public",
32130
- "loopback"
32178
+ "loopback",
32179
+ "app-link"
32131
32180
  ]),
32132
32181
  /**
32133
32182
  * Originating-interface kind — `lan`/`wifi`/`docker`/`vpn`/`other`/
@@ -32196,15 +32245,27 @@ var GetConnectionEndpointsResultSchema = object({
32196
32245
  localPort: AdvertisedLocalPortSchema
32197
32246
  });
32198
32247
  /**
32199
- * The chosen outbound endpoint for notification artifacts. `baseUrl: null` =
32200
- * AUTO (resolved from the candidate ranking at send time); `resolved` reports
32201
- * what AUTO currently picks, so the UI can show the effective value either way.
32248
+ * The address flagged for notification links. `baseUrl: null` = AUTO, which
32249
+ * since D709 is the CamStack app link; `resolved` reports the effective value,
32250
+ * so the UI can show it either way.
32202
32251
  */
32203
32252
  var NotificationEndpointSchema = object({
32204
32253
  /** The operator's explicit choice, or null for AUTO. */
32205
32254
  baseUrl: string().nullable(),
32206
- /** What the ranking currently resolves to (null when nothing is reachable). */
32207
- resolved: string().nullable()
32255
+ /**
32256
+ * The effective flagged address: the explicit choice, else (AUTO) the
32257
+ * CamStack app link `https://camstack.zentik.app` (D709). A pre-D709 hub
32258
+ * answered the public tunnel / mesh here, or null.
32259
+ */
32260
+ resolved: string().nullable(),
32261
+ /**
32262
+ * The hub origin an app link carries as `hub=` (D709): the hub's best
32263
+ * public HTTPS address — the tunnel, then the mesh (Tailscale MagicDNS) —
32264
+ * picked from this cap's own palette by `pickAppLinkHub`. `null` when the
32265
+ * hub advertises neither; the app link is then minted without `hub=`.
32266
+ * Absent on a pre-D709 hub.
32267
+ */
32268
+ appLinkHub: string().nullable()
32208
32269
  });
32209
32270
  /**
32210
32271
  * The URLs the SDK / viewer should race for API access. `baseUrls` empty =
@@ -32258,7 +32319,11 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
32258
32319
  * Pass `'https'` when the caller is itself loaded over HTTPS
32259
32320
  * to avoid mixed-content blocks in the browser. The public
32260
32321
  * tunnel always emits `https://` regardless. */
32261
- scheme: _enum(["http", "https"]).optional()
32322
+ scheme: _enum(["http", "https"]).optional(),
32323
+ /** Append the CamStack app link entry (`kind: 'app-link'`, D709) —
32324
+ * an address notification links can be flagged with, not a hub
32325
+ * route. Default `false`: racers and rankers never see it. */
32326
+ includeAppLink: boolean().optional()
32262
32327
  }), 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, {
32263
32328
  kind: "mutation",
32264
32329
  auth: "admin"
@@ -32587,7 +32652,7 @@ var MeshPeerSchema = object({
32587
32652
  tags: array(string()).readonly(),
32588
32653
  /** True when the peer advertises itself as an exit-node candidate. */
32589
32654
  exitNodeOption: boolean(),
32590
- /** Subnet routes the peer advertises (e.g. `["192.168.x.x/24"]`). */
32655
+ /** Subnet routes the peer advertises (e.g. `["192.168.10.0/24"]`). */
32591
32656
  advertisedRoutes: array(string()).readonly(),
32592
32657
  /** Owner account login (e.g. `foo@example.com`). Null for tagged peers. */
32593
32658
  userLogin: string().nullable(),
@@ -32717,7 +32782,8 @@ var MotionStatusSchema = object({
32717
32782
  * writes this slice (not even a boot seed), and neither does the runner's
32718
32783
  * phase machine: its phase is "a session is attached" for every on-motion
32719
32784
  * session, not motion, and it now has its own `DetectionPhaseTransition`.
32720
- * A provider's `isDetected` answers from the hub's slice.
32785
+ * A provider's `isDetected` and `getStatus` answer from the hub's slice
32786
+ * (`hubMotionNativeProvider`).
32721
32787
  * - **Sensors** (Home Assistant binary sensors, Homematic, Matter, Alexa
32722
32788
  * imports) — the provider pushes both edges itself, from the upstream
32723
32789
  * system's own state change. That is the sensor's own fact.
@@ -33915,7 +33981,13 @@ var OsdStatusSchema = object({ overlays: array(object({
33915
33981
  */
33916
33982
  availablePositions: array(OsdPositionEnum).readonly(),
33917
33983
  /** Firmware does not allow editing the `text` field (e.g. timestamp). */
33918
- readOnly: boolean().optional()
33984
+ readOnly: boolean().optional(),
33985
+ /**
33986
+ * Firmware text ceiling for this overlay. Absent = no known limit.
33987
+ * The OSD manager truncates here on every write — never stores its own
33988
+ * copy on the binding.
33989
+ */
33990
+ maxCharacters: number().int().positive().optional()
33919
33991
  })).readonly() });
33920
33992
  var OsdOverlayPatchSchema = object({
33921
33993
  enabled: boolean().optional(),
@@ -33966,7 +34038,9 @@ var OsdTemplateBindingSchema = object({
33966
34038
  valuePath: string().min(1).max(64),
33967
34039
  /** Convert TO this unit at render (`tryConvertUnit`). Absent = source unit. */
33968
34040
  displayUnit: string().max(16).optional(),
33969
- maxDecimals: number().int().min(0).max(4).default(1)
34041
+ maxDecimals: number().int().min(0).max(4).default(1),
34042
+ /** Raw value → display text (same shape as slot binding). Empty string hides. */
34043
+ valueMap: record(string(), string()).optional()
33970
34044
  });
33971
34045
  /**
33972
34046
  * A named template: bindings (alias → leaf field) + a parser that
@@ -34016,18 +34090,11 @@ var OsdSlotBindingSchema = object({
34016
34090
  source: OsdSourceSchema,
34017
34091
  /** `${value}` and `${unit}` are substituted; every occurrence. */
34018
34092
  template: string().max(96).default("${value}"),
34019
- /** Truncate with an ellipsis past this length. Absent = no limit. */
34020
- maxCharacters: number().int().min(4).max(64).optional(),
34021
34093
  /**
34022
34094
  * Decimal places for a numeric value. `0` yields an integer — the
34023
34095
  * documented workaround for firmwares that reject `.` in overlay text.
34024
34096
  */
34025
34097
  maxDecimals: number().int().min(0).max(4).default(1),
34026
- /**
34027
- * Appended via `${unit}` when no unit conversion produces a label.
34028
- * Prefer `source.displayUnit` for converted device-state values.
34029
- */
34030
- unitLabel: string().max(8).optional(),
34031
34098
  /** Raw value → display text, e.g. `{"true":"MOTION","false":""}`. */
34032
34099
  valueMap: record(string(), string()).optional(),
34033
34100
  /** Time windows in which the slot is shown. Absent = always. */
@@ -34036,9 +34103,7 @@ var OsdSlotBindingSchema = object({
34036
34103
  * Display gate, in the notification centre's condition vocabulary.
34037
34104
  * Only the keys reported by `getConditionSupport` are accepted.
34038
34105
  */
34039
- conditions: NcConditionsSchema.optional(),
34040
- /** Rendered when the gate is closed or the value unreadable. Empty = hide. */
34041
- fallbackText: string().max(64).default("")
34106
+ conditions: NcConditionsSchema.optional()
34042
34107
  });
34043
34108
  /** One camera slot, as the operator sees it: firmware truth + our binding. */
34044
34109
  var OsdSlotViewSchema = object({
@@ -52188,6 +52253,8 @@ new Map(Object.entries({
52188
52253
  "detection-blind": "device-events",
52189
52254
  "node-online": "system",
52190
52255
  "node-offline": "system",
52256
+ "node-restarting": "system",
52257
+ "node-updating": "system",
52191
52258
  "node-inference-unavailable": "system",
52192
52259
  "addon-crash-loop": "system",
52193
52260
  "addon-update-available": "system",
@@ -52265,18 +52332,21 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
52265
52332
  kinds: [
52266
52333
  "node-offline",
52267
52334
  "node-online",
52335
+ "node-restarting",
52268
52336
  "node-inference-unavailable"
52269
52337
  ]
52270
52338
  },
52271
52339
  {
52272
52340
  id: "addons",
52273
52341
  family: "system",
52274
- label: "Addons",
52275
- kinds: [
52276
- "addon-crash-loop",
52277
- "addon-update-available",
52278
- "addon-updated"
52279
- ]
52342
+ label: "Addons stopped",
52343
+ kinds: ["addon-crash-loop"]
52344
+ },
52345
+ {
52346
+ id: "addon-updates",
52347
+ family: "system",
52348
+ label: "Addon updates",
52349
+ kinds: ["addon-update-available", "addon-updated"]
52280
52350
  },
52281
52351
  {
52282
52352
  id: "updates",
@@ -52284,6 +52354,7 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
52284
52354
  label: "Server & container updates",
52285
52355
  kinds: [
52286
52356
  "server-update-available",
52357
+ "node-updating",
52287
52358
  "server-updated",
52288
52359
  "wrapper-update-available"
52289
52360
  ]
@@ -52431,18 +52502,21 @@ var STATE_SUMMARY_SECTION_VARS = [
52431
52502
  kinds: [
52432
52503
  "node-offline",
52433
52504
  "node-online",
52505
+ "node-restarting",
52434
52506
  "node-inference-unavailable"
52435
52507
  ]
52436
52508
  },
52437
52509
  {
52438
52510
  name: "summaryAddons",
52439
- label: "Summary: addons",
52440
- example: "@camstack/addon-recorder 1.2.3 → 1.2.4",
52441
- kinds: [
52442
- "addon-crash-loop",
52443
- "addon-update-available",
52444
- "addon-updated"
52445
- ]
52511
+ label: "Summary: addons stopped",
52512
+ example: "hub — recorder stopped after repeated crashes",
52513
+ kinds: ["addon-crash-loop"]
52514
+ },
52515
+ {
52516
+ name: "summaryAddonUpdates",
52517
+ label: "Summary: addon updates",
52518
+ example: "hub:\n• @camstack/addon-recorder 1.2.3 → 1.2.4",
52519
+ kinds: ["addon-update-available", "addon-updated"]
52446
52520
  },
52447
52521
  {
52448
52522
  name: "summaryUpdates",
@@ -52450,6 +52524,7 @@ var STATE_SUMMARY_SECTION_VARS = [
52450
52524
  example: "server 1.2.377 → 1.2.378",
52451
52525
  kinds: [
52452
52526
  "server-update-available",
52527
+ "node-updating",
52453
52528
  "server-updated",
52454
52529
  "wrapper-update-available"
52455
52530
  ]
@@ -52526,6 +52601,7 @@ var STATE_SUMMARY_VARS = [
52526
52601
  [...RULE_BODY_ONLY],
52527
52602
  [...RULE_TEXT],
52528
52603
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
52604
+ ([...RULE_TEXT], [...COMBINED_ALARM]),
52529
52605
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
52530
52606
  ([...RULE_TEXT], [...BATTERY, ...CONSUMABLE]),
52531
52607
  ([...RULE_TEXT], [...CONSUMABLE]),
@@ -52566,6 +52642,8 @@ var STATE_SUMMARY_VARS = [
52566
52642
  [...RULE_TEXT],
52567
52643
  [...RULE_TEXT],
52568
52644
  [...RULE_TEXT],
52645
+ [...RULE_TEXT],
52646
+ [...RULE_TEXT],
52569
52647
  ...STATE_SUMMARY_VARS
52570
52648
  ];
52571
52649
  new Set([
@@ -52902,10 +52980,9 @@ TimelapseRuleInputSchema.extend({
52902
52980
  createdAt: number(),
52903
52981
  updatedAt: number()
52904
52982
  });
52905
- async function readHubMotionDetected(deviceState, deviceId) {
52906
- let slice;
52983
+ async function readSlice(deviceState, deviceId) {
52907
52984
  try {
52908
- slice = await deviceState.getCapSlice.query({
52985
+ return await deviceState.getCapSlice.query({
52909
52986
  deviceId,
52910
52987
  capName: "motion"
52911
52988
  });
@@ -52913,10 +52990,44 @@ async function readHubMotionDetected(deviceState, deviceId) {
52913
52990
  const reason = err instanceof Error ? err.message : String(err);
52914
52991
  throw new Error(`motion state of device ${deviceId} is unreadable: ${reason}`, { cause: err });
52915
52992
  }
52916
- const detected = slice?.["detected"];
52993
+ }
52994
+ /**
52995
+ * The hub's `motion` slice as a `MotionStatus`, or `null` when nobody has
52996
+ * published it since the hub started. Throws when the hub does not answer or
52997
+ * the slice is malformed — never a made-up "no motion".
52998
+ */
52999
+ async function readHubMotionStatus(deviceState, deviceId) {
53000
+ const slice = await readSlice(deviceState, deviceId);
53001
+ if (slice === null) return null;
53002
+ const parsed = MotionStatusSchema.safeParse(slice);
53003
+ if (!parsed.success) throw new Error(`motion state of device ${deviceId} is malformed on the hub: ${parsed.error.message}`);
53004
+ return parsed.data;
53005
+ }
53006
+ async function readHubMotionDetected(deviceState, deviceId) {
53007
+ const detected = (await readSlice(deviceState, deviceId))?.["detected"];
52917
53008
  if (typeof detected !== "boolean") throw new Error(`motion state of device ${deviceId} is not published yet (unknown)`);
52918
53009
  return detected;
52919
53010
  }
53011
+ /**
53012
+ * The native `motion` provider of a camera whose slice the orchestrator writes
53013
+ * (D696): `isDetected` AND `getStatus`, both from the hub. `owner` names the
53014
+ * provider class in the deviceId-mismatch error.
53015
+ */
53016
+ function hubMotionNativeProvider(deviceState, deviceId, owner) {
53017
+ const ownDevice = (asked) => {
53018
+ if (asked !== deviceId) throw new Error(`${owner}: motion deviceId mismatch, expected ${deviceId}, got ${asked}`);
53019
+ };
53020
+ return {
53021
+ isDetected: async ({ deviceId: asked }) => {
53022
+ ownDevice(asked);
53023
+ return readHubMotionDetected(deviceState, deviceId);
53024
+ },
53025
+ getStatus: async ({ deviceId: asked }) => {
53026
+ ownDevice(asked);
53027
+ return readHubMotionStatus(deviceState, deviceId);
53028
+ }
53029
+ };
53030
+ }
52920
53031
  MotionOnMotionChangedDataSchema.omit({ triggeredBy: true });
52921
53032
  function providerMotionEvent(source, data) {
52922
53033
  return createEvent(EventCategory.ProviderMotion, source, data);
@@ -56517,7 +56628,7 @@ function buildCreationFormSchema() {
56517
56628
  key: "ip",
56518
56629
  label: "Local IP",
56519
56630
  required: true,
56520
- placeholder: "192.168.x.x"
56631
+ placeholder: "192.168.10.41"
56521
56632
  },
56522
56633
  {
56523
56634
  type: "text",
@@ -57392,15 +57503,13 @@ var WyzeCamera = class extends BaseDevice {
57392
57503
  /**
57393
57504
  * The native `motion` cap. This provider writes NO `motion` slice (D696): the
57394
57505
  * orchestrator is its only writer, with the EFFECTIVE motion, on the hub.
57395
- * `isDetected` answers from the HUB's slice; an unreadable hub, or a slice
57396
- * nobody has published yet, fails the call — never `false` for unknown
57397
- * (D49, D393).
57506
+ * `isDetected` and `getStatus` answer from the HUB's slice
57507
+ * (`hubMotionNativeProvider`); an unreadable hub fails both — never `false`
57508
+ * for unknown (D49, D393).
57398
57509
  */
57399
57510
  registerMotionProvider() {
57400
- this.ctx.registerNativeCap(motionCapability, { isDetected: async ({ deviceId }) => {
57401
- if (deviceId !== this.id) throw new Error(`WyzeCamera: deviceId mismatch, expected ${this.id}, got ${deviceId}`);
57402
- return readHubMotionDetected(this.ctx.api.deviceState, this.id);
57403
- } });
57511
+ const provider = hubMotionNativeProvider(this.ctx.api.deviceState, this.id, "WyzeCamera");
57512
+ this.ctx.registerNativeCap(motionCapability, provider);
57404
57513
  }
57405
57514
  /**
57406
57515
  * Start the configured motion source. `cloud` polls the Wyze events API
package/dist/addon.mjs CHANGED
@@ -10496,6 +10496,57 @@ var ClipSearchStrictnessSchema = _enum([
10496
10496
  "balanced",
10497
10497
  "strict"
10498
10498
  ]);
10499
+ new Set([
10500
+ {
10501
+ id: "person",
10502
+ name: "Person"
10503
+ },
10504
+ {
10505
+ id: "vehicle",
10506
+ name: "Vehicle"
10507
+ },
10508
+ {
10509
+ id: "animal",
10510
+ name: "Animal"
10511
+ },
10512
+ {
10513
+ id: "package",
10514
+ name: "Package"
10515
+ }
10516
+ ].map((l) => l.id));
10517
+ var COCO_TO_MACRO = {
10518
+ mapping: {
10519
+ person: "person",
10520
+ bicycle: "vehicle",
10521
+ car: "vehicle",
10522
+ motorcycle: "vehicle",
10523
+ airplane: "vehicle",
10524
+ bus: "vehicle",
10525
+ train: "vehicle",
10526
+ truck: "vehicle",
10527
+ boat: "vehicle",
10528
+ bird: "animal",
10529
+ cat: "animal",
10530
+ dog: "animal",
10531
+ horse: "animal",
10532
+ sheep: "animal",
10533
+ cow: "animal",
10534
+ elephant: "animal",
10535
+ bear: "animal",
10536
+ zebra: "animal",
10537
+ giraffe: "animal",
10538
+ suitcase: "package",
10539
+ backpack: "package",
10540
+ handbag: "package"
10541
+ },
10542
+ preserveOriginal: false
10543
+ };
10544
+ /** Steps a root detector may declare it fills. */
10545
+ var FILLABLE_STEP_IDS = [
10546
+ "animal-classifier",
10547
+ "vehicle-classifier",
10548
+ "package-detection"
10549
+ ];
10499
10550
  var MODEL_FORMATS = [
10500
10551
  "onnx",
10501
10552
  "coreml",
@@ -10565,11 +10616,11 @@ var ModelVariantGroupSchema = object({
10565
10616
  /** Quantization axis. Omit ⇒ the fp32 base build. */
10566
10617
  precision: _enum(["fp32", "int8"]).optional(),
10567
10618
  /**
10568
- * Speed-optimization axis. Omit ⇒ the standard build. `fast` marks a
10569
- * latency-optimized export (e.g. ReLU-activation variant) — the slot the
10570
- * future performance variants plug into.
10619
+ * Training / latency-variant axis. Omit ⇒ the standard build. `test` marks
10620
+ * an alternate training of the same family (Scrypted `relu_test`); chip
10621
+ * label is "Test".
10571
10622
  */
10572
- optimization: _enum(["standard", "fast"]).optional(),
10623
+ optimization: _enum(["standard", "test"]).optional(),
10573
10624
  /**
10574
10625
  * Input-resolution axis (square input side, px). Omit ⇒ the family's native
10575
10626
  * resolution (640 for yolo26). Reduced-input builds (320 / 256) are a big,
@@ -10592,9 +10643,10 @@ var ModelProviderIdSchema = _enum([
10592
10643
  * are per upstream. A persisted custom-model row written when this field was a
10593
10644
  * string still parses — the string is lifted into `{ weights }`.
10594
10645
  *
10595
- * Every licence surface (the admin "Models and licenses" page,
10596
- * `THIRD_PARTY_MODELS.md`, the Hugging Face model table) is GENERATED from
10597
- * these records by `scripts/gen-model-licenses.ts` (D661).
10646
+ * Every machine licence surface (`THIRD_PARTY_MODELS.md`, the Hugging Face
10647
+ * model table) is GENERATED from these records by
10648
+ * `scripts/gen-model-licenses.ts` (D661). Operator-facing docs live in
10649
+ * `camstack/docs` → `/docs/detection/models`.
10598
10650
  */
10599
10651
  var ModelLicenseSchema = preprocess((value) => typeof value === "string" ? { weights: value } : value, object({
10600
10652
  /** SPDX id of the WEIGHTS' terms, a `LicenseRef-*` for non-SPDX terms, or `UNKNOWN`. */
@@ -10627,6 +10679,12 @@ var ModelLicenseSchema = preprocess((value) => typeof value === "string" ? { wei
10627
10679
  /** True when the weights or their data forbid commercial use. */
10628
10680
  nonCommercial: boolean().optional()
10629
10681
  }));
10682
+ /** One `fillsClassifierEffects` entry — see `ModelCatalogEntry.fillsClassifierEffects`. */
10683
+ var FillsClassifierEffectSchema = object({
10684
+ stepId: _enum(FILLABLE_STEP_IDS),
10685
+ labelToEffect: record(string(), string()),
10686
+ uncovered: array(string()).readonly()
10687
+ });
10630
10688
  var ModelCatalogEntrySchema = object({
10631
10689
  id: string(),
10632
10690
  name: string(),
@@ -10753,6 +10811,16 @@ var ModelCatalogEntrySchema = object({
10753
10811
  */
10754
10812
  classMap: DetectionCatalogClassMapSchema.optional(),
10755
10813
  /**
10814
+ * The pipeline steps this ROOT detector already does the work of (D715):
10815
+ * its labels name the effect the step exists to produce (`deer` for
10816
+ * `animal-classifier`, `package` for `package-detection`). Derived from the
10817
+ * labelmap by `deriveClassifierFills`, never hand-written; a COCO model
10818
+ * declares none. Whether a declaration is honoured is the step's own
10819
+ * `labelLink` policy (`resolveLabelLink`). `labelToEffect` values are in
10820
+ * `FILLABLE_STEP_VOCABULARIES` (guard `check-label-link-vocabulary`).
10821
+ */
10822
+ fillsClassifierEffects: array(FillsClassifierEffectSchema).readonly().optional(),
10823
+ /**
10756
10824
  * The model's CLIP feature-space contract (text encoder, dimension, vector
10757
10825
  * index, token window, search floor) — see `clip-model.ts`. Present ONLY on a
10758
10826
  * CLIP image encoder; its absence is what "not a CLIP model" means to the
@@ -14225,7 +14293,7 @@ DeviceType.Camera;
14225
14293
  * This matters here more than anywhere else in the repo, because every provider
14226
14294
  * that knows a device's host knows its PASSWORD too: `{ host, port, username,
14227
14295
  * password }` sit in one object on Hikvision, Amcrest, Reolink and ONVIF alike,
14228
- * and `http://admin:hunter2@192.168.x.x/` is a URL a browser accepts. The
14296
+ * and `http://admin:hunter2@192.168.60.139/` is a URL a browser accepts. The
14229
14297
  * camera's own page will ask for its own login. That is correct, and pre-
14230
14298
  * filling it is the operator's business, not ours.
14231
14299
  *
@@ -17414,7 +17482,7 @@ method(object({
17414
17482
  timeoutMs: 6e5
17415
17483
  });
17416
17484
  method(object({
17417
- nodeId: string(),
17485
+ targetNodeId: string(),
17418
17486
  modelId: string(),
17419
17487
  format: _enum(MODEL_FORMATS),
17420
17488
  entry: ModelCatalogEntrySchema
@@ -17980,51 +18048,6 @@ method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSche
17980
18048
  kind: "mutation",
17981
18049
  auth: "admin"
17982
18050
  });
17983
- new Set([
17984
- {
17985
- id: "person",
17986
- name: "Person"
17987
- },
17988
- {
17989
- id: "vehicle",
17990
- name: "Vehicle"
17991
- },
17992
- {
17993
- id: "animal",
17994
- name: "Animal"
17995
- },
17996
- {
17997
- id: "package",
17998
- name: "Package"
17999
- }
18000
- ].map((l) => l.id));
18001
- var COCO_TO_MACRO = {
18002
- mapping: {
18003
- person: "person",
18004
- bicycle: "vehicle",
18005
- car: "vehicle",
18006
- motorcycle: "vehicle",
18007
- airplane: "vehicle",
18008
- bus: "vehicle",
18009
- train: "vehicle",
18010
- truck: "vehicle",
18011
- boat: "vehicle",
18012
- bird: "animal",
18013
- cat: "animal",
18014
- dog: "animal",
18015
- horse: "animal",
18016
- sheep: "animal",
18017
- cow: "animal",
18018
- elephant: "animal",
18019
- bear: "animal",
18020
- zebra: "animal",
18021
- giraffe: "animal",
18022
- suitcase: "package",
18023
- backpack: "package",
18024
- handbag: "package"
18025
- },
18026
- preserveOriginal: false
18027
- };
18028
18051
  var AUDIO_MACRO_LABELS = [
18029
18052
  {
18030
18053
  id: "speech",
@@ -18820,6 +18843,8 @@ var NcSystemEventKindSchema = _enum([
18820
18843
  "stream-offline",
18821
18844
  "node-online",
18822
18845
  "node-offline",
18846
+ "node-restarting",
18847
+ "node-updating",
18823
18848
  "node-inference-unavailable",
18824
18849
  "detection-blind",
18825
18850
  "addon-crash-loop",
@@ -19918,8 +19943,9 @@ var NcRuleSchema = NcRuleInputSchema.extend({
19918
19943
  disabledTargetIds: array(string()).default([])
19919
19944
  });
19920
19945
  /**
19921
- * The state-summary SECTIONS (D647 / D698): the D637 kind groups that report a
19922
- * still-true state. `backups-exports` and `alarm` are not sections — a completed
19946
+ * The state-summary SECTIONS (D647 / D698 / D708): the D637 kind groups that
19947
+ * report a still-true state. `addons` is the crash-looped addons only and
19948
+ * `addon-updates` the addons that are behind (D708 split them). `backups-exports` and `alarm` are not sections — a completed
19923
19949
  * job is not an open state, and the alarm stays instant.
19924
19950
  */
19925
19951
  var NcStateSummarySectionIdSchema = _enum([
@@ -19931,6 +19957,7 @@ var NcStateSummarySectionIdSchema = _enum([
19931
19957
  "detection-blind",
19932
19958
  "nodes",
19933
19959
  "addons",
19960
+ "addon-updates",
19934
19961
  "updates"
19935
19962
  ]);
19936
19963
  /** One section of a previewed state summary. `unavailable` = its state could not be read. */
@@ -20411,7 +20438,19 @@ var NcAlarmModeDelaysListSchema = array(object({
20411
20438
  * When this mode may be armed. Absent / null = always allowed (same as a
20412
20439
  * rule with no `schedule`). Evaluated with {@link isScheduleActive}.
20413
20440
  */
20414
- schedule: NcScheduleSchema.optional()
20441
+ schedule: NcScheduleSchema.optional(),
20442
+ /**
20443
+ * D706: while this mode's ENTRY DELAY runs, do the alarm rules' own pushes go out (as an
20444
+ * intrusion naming the locations)? Absent = false — the entry-delay notification is the
20445
+ * only one, and the matches ride the triggered notification's mosaic (D705).
20446
+ */
20447
+ notifyDuringEntryDelay: boolean().optional(),
20448
+ /**
20449
+ * D706: notify "watched again" when a sensor this arm bypassed closes and opens again.
20450
+ * Absent = false (logged, not sent). Even when true it is not sent when that same sensor
20451
+ * is the one that starts the entry delay — the entry-delay notification already names it.
20452
+ */
20453
+ notifySensorRewatched: boolean().optional()
20415
20454
  })).max(8).refine(uniqueModes, { message: "modeDelays: at most one entry per arm mode" });
20416
20455
  var NcAlarmModeDelaysEditListSchema = array(object({
20417
20456
  mode: AlarmArmModeSchema,
@@ -20420,7 +20459,11 @@ var NcAlarmModeDelaysEditListSchema = array(object({
20420
20459
  triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional(),
20421
20460
  postTriggeredAction: NcAlarmPostTriggeredActionSchema.nullable().optional(),
20422
20461
  /** Set a schedule, or `null` to clear (mode always allowed again). */
20423
- schedule: NcScheduleSchema.nullable().optional()
20462
+ schedule: NcScheduleSchema.nullable().optional(),
20463
+ /** D706: set the switch, or `null` to clear it (back to the default, false). */
20464
+ notifyDuringEntryDelay: boolean().nullable().optional(),
20465
+ /** D706: set the switch, or `null` to clear it (back to the default, false). */
20466
+ notifySensorRewatched: boolean().nullable().optional()
20424
20467
  })).max(8).refine(uniqueModes, { message: "modeDelays: at most one edit per arm mode" });
20425
20468
  /** One switch of the alarm table: put ONE device on, or take it off, ONE mode's list. */
20426
20469
  var NcAlarmNonBlockingEditSchema = object({
@@ -21381,39 +21424,19 @@ Object.freeze(Object.fromEntries([{
21381
21424
  label: "Face recognition model",
21382
21425
  defaultModelId: "auraface-r100",
21383
21426
  indexName: "the enrolled face gallery",
21384
- options: [
21385
- {
21386
- id: "auraface-r100",
21387
- label: "AuraFace R100"
21388
- },
21389
- {
21390
- id: "arcface-r100",
21391
- label: "ArcFace (ResNet34)"
21392
- },
21393
- {
21394
- id: "inception-resnet-v1",
21395
- label: "Inception ResNet V1"
21396
- }
21397
- ]
21427
+ options: [{
21428
+ id: "auraface-r100",
21429
+ label: "AuraFace R100"
21430
+ }]
21398
21431
  }, {
21399
21432
  stepId: "clip-embedding",
21400
21433
  label: "Semantic search model",
21401
- defaultModelId: "mobileclip-s1",
21434
+ defaultModelId: "siglip2-b16-224",
21402
21435
  indexName: "the object semantic-search index",
21403
- options: [
21404
- {
21405
- id: "mobileclip-s1",
21406
- label: "MobileCLIP S1"
21407
- },
21408
- {
21409
- id: "mobileclip-s2",
21410
- label: "MobileCLIP S2"
21411
- },
21412
- {
21413
- id: "siglip2-b16-224",
21414
- label: "SigLIP2 B/16 (Apache-2.0)"
21415
- }
21416
- ]
21436
+ options: [{
21437
+ id: "siglip2-b16-224",
21438
+ label: "SigLIP2 B/16 (Apache-2.0)"
21439
+ }]
21417
21440
  }].map((s) => [s.stepId, s.defaultModelId])));
21418
21441
  var CLUSTER_STEP_SETTING_FIELDS = [{
21419
21442
  stepId: "face-embedding",
@@ -23468,7 +23491,8 @@ var PipelineModelOptionSchema = object({
23468
23491
  group: ModelVariantGroupSchema.optional(),
23469
23492
  legacy: boolean().optional(),
23470
23493
  provider: ModelProviderIdSchema.optional(),
23471
- defaultConfidence: number().optional()
23494
+ defaultConfidence: number().optional(),
23495
+ fillsClassifierEffects: array(FillsClassifierEffectSchema).readonly().optional()
23472
23496
  });
23473
23497
  var ConfigFieldBridge = custom();
23474
23498
  var PipelineAddonSchemaSchema = object({
@@ -24301,6 +24325,22 @@ var MotionSourceEnum = _enum([
24301
24325
  "device-activity"
24302
24326
  ]);
24303
24327
  /**
24328
+ * What opened an on-motion detection SESSION: the motion source that passed the
24329
+ * camera's `motionSources` gate, and what raised it (the camera itself, or a
24330
+ * sensor the operator attached — D672). `sensorName` is the attached sensor's
24331
+ * device name as the orchestrator's camera-sensors resolution last read it;
24332
+ * absent when unknown or when the camera itself triggered.
24333
+ *
24334
+ * Carried on the session attach ONLY so the runner's `DetectionPhaseTransition`
24335
+ * can say what started the session (D672 rule 11, amended 2026-10-06). The
24336
+ * runner never decides anything on it.
24337
+ */
24338
+ var SessionTriggerSchema = object({
24339
+ source: MotionSourceEnum,
24340
+ triggeredBy: MotionTriggeredBySchema,
24341
+ sensorName: string().optional()
24342
+ });
24343
+ /**
24304
24344
  * List of motion sources active on a camera. Empty array is valid:
24305
24345
  * "no source" — happens for battery cams without firmware motion when
24306
24346
  * the operator hasn't opted into the SW analyzer (would hold the
@@ -24552,6 +24592,14 @@ var RunnerCameraConfigSchema = object({
24552
24592
  */
24553
24593
  motionSources: MotionSourcesSchema.default(["analyzer"]),
24554
24594
  /**
24595
+ * What opened this attach, on a SESSION attach only (see
24596
+ * {@link SessionTriggerSchema}). OPTIONAL with no default: absent on a
24597
+ * standing attach, an occupancy burst, a re-dispatch with no motion event
24598
+ * behind it, and every attach from an orchestrator older than the field — the
24599
+ * runner then names no source on the phase event.
24600
+ */
24601
+ sessionTrigger: SessionTriggerSchema.optional(),
24602
+ /**
24555
24603
  * WHICH root detector runs for this camera. The detection counterpart of
24556
24604
  * {@link motionSources}, same shape and same discipline: a per-camera list
24557
24605
  * of sources the system understands, vendor-agnostic, owned here.
@@ -32052,7 +32100,7 @@ var LocalInterfaceSchema = object({
32052
32100
  name: string(),
32053
32101
  family: _enum(["IPv4", "IPv6"]),
32054
32102
  address: string(),
32055
- /** CIDR shorthand (e.g. `192.168.x.x/24`). Empty when OS doesn't expose. */
32103
+ /** CIDR shorthand (e.g. `192.168.10.10/24`). Empty when OS doesn't expose. */
32056
32104
  cidr: string(),
32057
32105
  /** OS netmask. Stable across calls so the SDK can hash on it. */
32058
32106
  netmask: string(),
@@ -32106,7 +32154,8 @@ var ConnectionEndpointSchema = object({
32106
32154
  "lan-ipv4",
32107
32155
  "lan-ipv6",
32108
32156
  "public",
32109
- "loopback"
32157
+ "loopback",
32158
+ "app-link"
32110
32159
  ]),
32111
32160
  /**
32112
32161
  * Originating-interface kind — `lan`/`wifi`/`docker`/`vpn`/`other`/
@@ -32175,15 +32224,27 @@ var GetConnectionEndpointsResultSchema = object({
32175
32224
  localPort: AdvertisedLocalPortSchema
32176
32225
  });
32177
32226
  /**
32178
- * The chosen outbound endpoint for notification artifacts. `baseUrl: null` =
32179
- * AUTO (resolved from the candidate ranking at send time); `resolved` reports
32180
- * what AUTO currently picks, so the UI can show the effective value either way.
32227
+ * The address flagged for notification links. `baseUrl: null` = AUTO, which
32228
+ * since D709 is the CamStack app link; `resolved` reports the effective value,
32229
+ * so the UI can show it either way.
32181
32230
  */
32182
32231
  var NotificationEndpointSchema = object({
32183
32232
  /** The operator's explicit choice, or null for AUTO. */
32184
32233
  baseUrl: string().nullable(),
32185
- /** What the ranking currently resolves to (null when nothing is reachable). */
32186
- resolved: string().nullable()
32234
+ /**
32235
+ * The effective flagged address: the explicit choice, else (AUTO) the
32236
+ * CamStack app link `https://camstack.zentik.app` (D709). A pre-D709 hub
32237
+ * answered the public tunnel / mesh here, or null.
32238
+ */
32239
+ resolved: string().nullable(),
32240
+ /**
32241
+ * The hub origin an app link carries as `hub=` (D709): the hub's best
32242
+ * public HTTPS address — the tunnel, then the mesh (Tailscale MagicDNS) —
32243
+ * picked from this cap's own palette by `pickAppLinkHub`. `null` when the
32244
+ * hub advertises neither; the app link is then minted without `hub=`.
32245
+ * Absent on a pre-D709 hub.
32246
+ */
32247
+ appLinkHub: string().nullable()
32187
32248
  });
32188
32249
  /**
32189
32250
  * The URLs the SDK / viewer should race for API access. `baseUrls` empty =
@@ -32237,7 +32298,11 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
32237
32298
  * Pass `'https'` when the caller is itself loaded over HTTPS
32238
32299
  * to avoid mixed-content blocks in the browser. The public
32239
32300
  * tunnel always emits `https://` regardless. */
32240
- scheme: _enum(["http", "https"]).optional()
32301
+ scheme: _enum(["http", "https"]).optional(),
32302
+ /** Append the CamStack app link entry (`kind: 'app-link'`, D709) —
32303
+ * an address notification links can be flagged with, not a hub
32304
+ * route. Default `false`: racers and rankers never see it. */
32305
+ includeAppLink: boolean().optional()
32241
32306
  }), 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, {
32242
32307
  kind: "mutation",
32243
32308
  auth: "admin"
@@ -32566,7 +32631,7 @@ var MeshPeerSchema = object({
32566
32631
  tags: array(string()).readonly(),
32567
32632
  /** True when the peer advertises itself as an exit-node candidate. */
32568
32633
  exitNodeOption: boolean(),
32569
- /** Subnet routes the peer advertises (e.g. `["192.168.x.x/24"]`). */
32634
+ /** Subnet routes the peer advertises (e.g. `["192.168.10.0/24"]`). */
32570
32635
  advertisedRoutes: array(string()).readonly(),
32571
32636
  /** Owner account login (e.g. `foo@example.com`). Null for tagged peers. */
32572
32637
  userLogin: string().nullable(),
@@ -32696,7 +32761,8 @@ var MotionStatusSchema = object({
32696
32761
  * writes this slice (not even a boot seed), and neither does the runner's
32697
32762
  * phase machine: its phase is "a session is attached" for every on-motion
32698
32763
  * session, not motion, and it now has its own `DetectionPhaseTransition`.
32699
- * A provider's `isDetected` answers from the hub's slice.
32764
+ * A provider's `isDetected` and `getStatus` answer from the hub's slice
32765
+ * (`hubMotionNativeProvider`).
32700
32766
  * - **Sensors** (Home Assistant binary sensors, Homematic, Matter, Alexa
32701
32767
  * imports) — the provider pushes both edges itself, from the upstream
32702
32768
  * system's own state change. That is the sensor's own fact.
@@ -33894,7 +33960,13 @@ var OsdStatusSchema = object({ overlays: array(object({
33894
33960
  */
33895
33961
  availablePositions: array(OsdPositionEnum).readonly(),
33896
33962
  /** Firmware does not allow editing the `text` field (e.g. timestamp). */
33897
- readOnly: boolean().optional()
33963
+ readOnly: boolean().optional(),
33964
+ /**
33965
+ * Firmware text ceiling for this overlay. Absent = no known limit.
33966
+ * The OSD manager truncates here on every write — never stores its own
33967
+ * copy on the binding.
33968
+ */
33969
+ maxCharacters: number().int().positive().optional()
33898
33970
  })).readonly() });
33899
33971
  var OsdOverlayPatchSchema = object({
33900
33972
  enabled: boolean().optional(),
@@ -33945,7 +34017,9 @@ var OsdTemplateBindingSchema = object({
33945
34017
  valuePath: string().min(1).max(64),
33946
34018
  /** Convert TO this unit at render (`tryConvertUnit`). Absent = source unit. */
33947
34019
  displayUnit: string().max(16).optional(),
33948
- maxDecimals: number().int().min(0).max(4).default(1)
34020
+ maxDecimals: number().int().min(0).max(4).default(1),
34021
+ /** Raw value → display text (same shape as slot binding). Empty string hides. */
34022
+ valueMap: record(string(), string()).optional()
33949
34023
  });
33950
34024
  /**
33951
34025
  * A named template: bindings (alias → leaf field) + a parser that
@@ -33995,18 +34069,11 @@ var OsdSlotBindingSchema = object({
33995
34069
  source: OsdSourceSchema,
33996
34070
  /** `${value}` and `${unit}` are substituted; every occurrence. */
33997
34071
  template: string().max(96).default("${value}"),
33998
- /** Truncate with an ellipsis past this length. Absent = no limit. */
33999
- maxCharacters: number().int().min(4).max(64).optional(),
34000
34072
  /**
34001
34073
  * Decimal places for a numeric value. `0` yields an integer — the
34002
34074
  * documented workaround for firmwares that reject `.` in overlay text.
34003
34075
  */
34004
34076
  maxDecimals: number().int().min(0).max(4).default(1),
34005
- /**
34006
- * Appended via `${unit}` when no unit conversion produces a label.
34007
- * Prefer `source.displayUnit` for converted device-state values.
34008
- */
34009
- unitLabel: string().max(8).optional(),
34010
34077
  /** Raw value → display text, e.g. `{"true":"MOTION","false":""}`. */
34011
34078
  valueMap: record(string(), string()).optional(),
34012
34079
  /** Time windows in which the slot is shown. Absent = always. */
@@ -34015,9 +34082,7 @@ var OsdSlotBindingSchema = object({
34015
34082
  * Display gate, in the notification centre's condition vocabulary.
34016
34083
  * Only the keys reported by `getConditionSupport` are accepted.
34017
34084
  */
34018
- conditions: NcConditionsSchema.optional(),
34019
- /** Rendered when the gate is closed or the value unreadable. Empty = hide. */
34020
- fallbackText: string().max(64).default("")
34085
+ conditions: NcConditionsSchema.optional()
34021
34086
  });
34022
34087
  /** One camera slot, as the operator sees it: firmware truth + our binding. */
34023
34088
  var OsdSlotViewSchema = object({
@@ -52167,6 +52232,8 @@ new Map(Object.entries({
52167
52232
  "detection-blind": "device-events",
52168
52233
  "node-online": "system",
52169
52234
  "node-offline": "system",
52235
+ "node-restarting": "system",
52236
+ "node-updating": "system",
52170
52237
  "node-inference-unavailable": "system",
52171
52238
  "addon-crash-loop": "system",
52172
52239
  "addon-update-available": "system",
@@ -52244,18 +52311,21 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
52244
52311
  kinds: [
52245
52312
  "node-offline",
52246
52313
  "node-online",
52314
+ "node-restarting",
52247
52315
  "node-inference-unavailable"
52248
52316
  ]
52249
52317
  },
52250
52318
  {
52251
52319
  id: "addons",
52252
52320
  family: "system",
52253
- label: "Addons",
52254
- kinds: [
52255
- "addon-crash-loop",
52256
- "addon-update-available",
52257
- "addon-updated"
52258
- ]
52321
+ label: "Addons stopped",
52322
+ kinds: ["addon-crash-loop"]
52323
+ },
52324
+ {
52325
+ id: "addon-updates",
52326
+ family: "system",
52327
+ label: "Addon updates",
52328
+ kinds: ["addon-update-available", "addon-updated"]
52259
52329
  },
52260
52330
  {
52261
52331
  id: "updates",
@@ -52263,6 +52333,7 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
52263
52333
  label: "Server & container updates",
52264
52334
  kinds: [
52265
52335
  "server-update-available",
52336
+ "node-updating",
52266
52337
  "server-updated",
52267
52338
  "wrapper-update-available"
52268
52339
  ]
@@ -52410,18 +52481,21 @@ var STATE_SUMMARY_SECTION_VARS = [
52410
52481
  kinds: [
52411
52482
  "node-offline",
52412
52483
  "node-online",
52484
+ "node-restarting",
52413
52485
  "node-inference-unavailable"
52414
52486
  ]
52415
52487
  },
52416
52488
  {
52417
52489
  name: "summaryAddons",
52418
- label: "Summary: addons",
52419
- example: "@camstack/addon-recorder 1.2.3 → 1.2.4",
52420
- kinds: [
52421
- "addon-crash-loop",
52422
- "addon-update-available",
52423
- "addon-updated"
52424
- ]
52490
+ label: "Summary: addons stopped",
52491
+ example: "hub — recorder stopped after repeated crashes",
52492
+ kinds: ["addon-crash-loop"]
52493
+ },
52494
+ {
52495
+ name: "summaryAddonUpdates",
52496
+ label: "Summary: addon updates",
52497
+ example: "hub:\n• @camstack/addon-recorder 1.2.3 → 1.2.4",
52498
+ kinds: ["addon-update-available", "addon-updated"]
52425
52499
  },
52426
52500
  {
52427
52501
  name: "summaryUpdates",
@@ -52429,6 +52503,7 @@ var STATE_SUMMARY_SECTION_VARS = [
52429
52503
  example: "server 1.2.377 → 1.2.378",
52430
52504
  kinds: [
52431
52505
  "server-update-available",
52506
+ "node-updating",
52432
52507
  "server-updated",
52433
52508
  "wrapper-update-available"
52434
52509
  ]
@@ -52505,6 +52580,7 @@ var STATE_SUMMARY_VARS = [
52505
52580
  [...RULE_BODY_ONLY],
52506
52581
  [...RULE_TEXT],
52507
52582
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
52583
+ ([...RULE_TEXT], [...COMBINED_ALARM]),
52508
52584
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
52509
52585
  ([...RULE_TEXT], [...BATTERY, ...CONSUMABLE]),
52510
52586
  ([...RULE_TEXT], [...CONSUMABLE]),
@@ -52545,6 +52621,8 @@ var STATE_SUMMARY_VARS = [
52545
52621
  [...RULE_TEXT],
52546
52622
  [...RULE_TEXT],
52547
52623
  [...RULE_TEXT],
52624
+ [...RULE_TEXT],
52625
+ [...RULE_TEXT],
52548
52626
  ...STATE_SUMMARY_VARS
52549
52627
  ];
52550
52628
  new Set([
@@ -52881,10 +52959,9 @@ TimelapseRuleInputSchema.extend({
52881
52959
  createdAt: number(),
52882
52960
  updatedAt: number()
52883
52961
  });
52884
- async function readHubMotionDetected(deviceState, deviceId) {
52885
- let slice;
52962
+ async function readSlice(deviceState, deviceId) {
52886
52963
  try {
52887
- slice = await deviceState.getCapSlice.query({
52964
+ return await deviceState.getCapSlice.query({
52888
52965
  deviceId,
52889
52966
  capName: "motion"
52890
52967
  });
@@ -52892,10 +52969,44 @@ async function readHubMotionDetected(deviceState, deviceId) {
52892
52969
  const reason = err instanceof Error ? err.message : String(err);
52893
52970
  throw new Error(`motion state of device ${deviceId} is unreadable: ${reason}`, { cause: err });
52894
52971
  }
52895
- const detected = slice?.["detected"];
52972
+ }
52973
+ /**
52974
+ * The hub's `motion` slice as a `MotionStatus`, or `null` when nobody has
52975
+ * published it since the hub started. Throws when the hub does not answer or
52976
+ * the slice is malformed — never a made-up "no motion".
52977
+ */
52978
+ async function readHubMotionStatus(deviceState, deviceId) {
52979
+ const slice = await readSlice(deviceState, deviceId);
52980
+ if (slice === null) return null;
52981
+ const parsed = MotionStatusSchema.safeParse(slice);
52982
+ if (!parsed.success) throw new Error(`motion state of device ${deviceId} is malformed on the hub: ${parsed.error.message}`);
52983
+ return parsed.data;
52984
+ }
52985
+ async function readHubMotionDetected(deviceState, deviceId) {
52986
+ const detected = (await readSlice(deviceState, deviceId))?.["detected"];
52896
52987
  if (typeof detected !== "boolean") throw new Error(`motion state of device ${deviceId} is not published yet (unknown)`);
52897
52988
  return detected;
52898
52989
  }
52990
+ /**
52991
+ * The native `motion` provider of a camera whose slice the orchestrator writes
52992
+ * (D696): `isDetected` AND `getStatus`, both from the hub. `owner` names the
52993
+ * provider class in the deviceId-mismatch error.
52994
+ */
52995
+ function hubMotionNativeProvider(deviceState, deviceId, owner) {
52996
+ const ownDevice = (asked) => {
52997
+ if (asked !== deviceId) throw new Error(`${owner}: motion deviceId mismatch, expected ${deviceId}, got ${asked}`);
52998
+ };
52999
+ return {
53000
+ isDetected: async ({ deviceId: asked }) => {
53001
+ ownDevice(asked);
53002
+ return readHubMotionDetected(deviceState, deviceId);
53003
+ },
53004
+ getStatus: async ({ deviceId: asked }) => {
53005
+ ownDevice(asked);
53006
+ return readHubMotionStatus(deviceState, deviceId);
53007
+ }
53008
+ };
53009
+ }
52899
53010
  MotionOnMotionChangedDataSchema.omit({ triggeredBy: true });
52900
53011
  function providerMotionEvent(source, data) {
52901
53012
  return createEvent(EventCategory.ProviderMotion, source, data);
@@ -56496,7 +56607,7 @@ function buildCreationFormSchema() {
56496
56607
  key: "ip",
56497
56608
  label: "Local IP",
56498
56609
  required: true,
56499
- placeholder: "192.168.x.x"
56610
+ placeholder: "192.168.10.41"
56500
56611
  },
56501
56612
  {
56502
56613
  type: "text",
@@ -57371,15 +57482,13 @@ var WyzeCamera = class extends BaseDevice {
57371
57482
  /**
57372
57483
  * The native `motion` cap. This provider writes NO `motion` slice (D696): the
57373
57484
  * orchestrator is its only writer, with the EFFECTIVE motion, on the hub.
57374
- * `isDetected` answers from the HUB's slice; an unreadable hub, or a slice
57375
- * nobody has published yet, fails the call — never `false` for unknown
57376
- * (D49, D393).
57485
+ * `isDetected` and `getStatus` answer from the HUB's slice
57486
+ * (`hubMotionNativeProvider`); an unreadable hub fails both — never `false`
57487
+ * for unknown (D49, D393).
57377
57488
  */
57378
57489
  registerMotionProvider() {
57379
- this.ctx.registerNativeCap(motionCapability, { isDetected: async ({ deviceId }) => {
57380
- if (deviceId !== this.id) throw new Error(`WyzeCamera: deviceId mismatch, expected ${this.id}, got ${deviceId}`);
57381
- return readHubMotionDetected(this.ctx.api.deviceState, this.id);
57382
- } });
57490
+ const provider = hubMotionNativeProvider(this.ctx.api.deviceState, this.id, "WyzeCamera");
57491
+ this.ctx.registerNativeCap(motionCapability, provider);
57383
57492
  }
57384
57493
  /**
57385
57494
  * Start the configured motion source. `cloud` polls the Wyze events API
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-wyze",
3
- "version": "0.2.126",
3
+ "version": "0.2.128",
4
4
  "description": "Wyze camera device-provider addon for CamStack — wraps the @apocaliss92/wyze-bridge-js P2P/DTLS client, feeding the stream-broker via the pull-rfc4571 lazy-publish path (a structural twin of addon-provider-reolink)",
5
5
  "keywords": [
6
6
  "camstack",