@camstack/addon-provider-homeassistant 1.2.158 → 1.2.160

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/addon.js CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_dist = require("./dist-M6hP_tw3.js");
2
+ const require_dist = require("./dist-l71G4EIk.js");
3
3
  let node_crypto = require("node:crypto");
4
4
  let node_zlib = require("node:zlib");
5
5
  //#region src/ha-admin-link.ts
@@ -4839,25 +4839,6 @@ var HaWsClient = class {
4839
4839
  }
4840
4840
  }
4841
4841
  };
4842
- /**
4843
- * Resolve auth config from the addon environment + persisted config.
4844
- * Prefers Supervisor token when present (the addon is running inside
4845
- * the HA Supervisor); falls back to the user-provided long-lived token
4846
- * for external deployments.
4847
- */
4848
- function resolveAuthConfig(env, persistedConfig) {
4849
- const supervisorToken = env.SUPERVISOR_TOKEN;
4850
- if (supervisorToken && supervisorToken.length > 0) return {
4851
- kind: "supervisor",
4852
- supervisorToken
4853
- };
4854
- if (persistedConfig?.baseUrl && persistedConfig.accessToken) return {
4855
- kind: "long-lived",
4856
- baseUrl: persistedConfig.baseUrl,
4857
- accessToken: persistedConfig.accessToken
4858
- };
4859
- return { error: "No HA auth configured — set SUPERVISOR_TOKEN env (Supervisor deployment) or supply baseUrl + accessToken in addon config" };
4860
- }
4861
4842
  //#endregion
4862
4843
  //#region src/ha-events.ts
4863
4844
  function processEvent(current, updates) {
@@ -5142,7 +5123,7 @@ var HaIntegrationManager = class HaIntegrationManager {
5142
5123
  service: target.service
5143
5124
  };
5144
5125
  const targetEnvelope = {};
5145
- if (target.entityId !== void 0) targetEnvelope["entity_id"] = Array.isArray(target.entityId) ? [...target.entityId] : target.entityId;
5126
+ if (target.entityId !== void 0) targetEnvelope["entity_id"] = typeof target.entityId === "string" ? target.entityId : [...target.entityId];
5146
5127
  if (target.areaId) targetEnvelope["area_id"] = target.areaId;
5147
5128
  if (target.deviceId) targetEnvelope["device_id"] = target.deviceId;
5148
5129
  if (Object.keys(targetEnvelope).length > 0) message["target"] = targetEnvelope;
@@ -7163,6 +7144,14 @@ function createHaNotificationOutputProvider(deps) {
7163
7144
  addonId
7164
7145
  }));
7165
7146
  },
7147
+ getTarget: async ({ targetId }) => {
7148
+ const target = await store.getById(targetId);
7149
+ if (!target) throw new Error(`Unknown target '${targetId}'`);
7150
+ return {
7151
+ ...target,
7152
+ addonId
7153
+ };
7154
+ },
7166
7155
  discoverTargets: async ({ kind, config }) => {
7167
7156
  if (kind !== "homeassistant") return [];
7168
7157
  const explicit = config ? readBrokerId(config) : void 0;
@@ -9070,6 +9059,5 @@ exports.HaWsClient = HaWsClient;
9070
9059
  exports.authToSettings = authToSettings;
9071
9060
  exports.buildHaAuth = buildHaAuth;
9072
9061
  exports.processEvent = processEvent;
9073
- exports.resolveAuthConfig = resolveAuthConfig;
9074
9062
  exports.settingsToAuth = settingsToAuth;
9075
9063
  exports.subscribeEntities = subscribeEntities;
package/dist/addon.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { A as connectivityCapability, At as record, B as floodCapability, C as buildAddonRouteProvider, Ct as _enum, D as carbonMonoxideCapability, Dt as literal, E as calendarSourceCapability, Et as discriminatedUnion, F as deviceAdoptionCapability, Ft as EventCategory, G as lawnMowerControlCapability, H as humidifierCapability, J as motionCapability, K as lockControlCapability, L as enumSensorCapability, M as controlCapability, Mt as union, N as coverCapability, Nt as unknown, O as climateControlCapability, Ot as number, P as deviceAdminLinkCapability, Pt as url, Q as numericSensorCapability, R as eventEmitterCapability, S as brokerCapability, T as buttonCapability, Tt as boolean, U as humiditySensorCapability, V as gasCapability, W as imageCapability, X as notificationOutputCapability, Y as normalizeUnit, Z as notifierCapability, _ as automationControlCapability, _t as DeviceRole, at as scriptRunnerCapability, b as binaryCapability, ct as tamperCapability, d as TargetSchema, dt as vacuumControlCapability, et as parseAdminBase, f as accessoriesCapability, ft as valveCapability, g as ambientLightSensorCapability, gt as DeviceFeature, h as alarmPanelCapability, ht as weatherCapability, it as pressureSensorCapability, j as contactCapability, jt as string, k as colorCapability, kt as object, lt as temperatureSensorCapability, m as airQualitySensorCapability, mt as waterHeaterCapability, n as BaseDevice, nt as prepareNotification, ot as smokeCapability, p as addonRoutesCapability, pt as vibrationCapability, q as mediaPlayerCapability, r as BaseDeviceProvider, rt as presenceCapability, s as EnumSensorDateTimeFormatSchema, st as switchCapability, tt as powerMeterCapability, ut as updateCapability, v as batteryCapability, vt as DeviceType, w as buildDeviceAdminUrl, wt as array, x as brightnessCapability, xt as createEvent, y as bestLocationMatch, yt as errMsg, z as fanControlCapability } from "./dist-BgTykMb6.mjs";
1
+ import { A as connectivityCapability, At as record, B as floodCapability, C as buildAddonRouteProvider, Ct as _enum, D as carbonMonoxideCapability, Dt as literal, E as calendarSourceCapability, Et as discriminatedUnion, F as deviceAdoptionCapability, Ft as EventCategory, G as lawnMowerControlCapability, H as humidifierCapability, J as motionCapability, K as lockControlCapability, L as enumSensorCapability, M as controlCapability, Mt as union, N as coverCapability, Nt as unknown, O as climateControlCapability, Ot as number, P as deviceAdminLinkCapability, Pt as url, Q as numericSensorCapability, R as eventEmitterCapability, S as brokerCapability, T as buttonCapability, Tt as boolean, U as humiditySensorCapability, V as gasCapability, W as imageCapability, X as notificationOutputCapability, Y as normalizeUnit, Z as notifierCapability, _ as automationControlCapability, _t as DeviceRole, at as scriptRunnerCapability, b as binaryCapability, ct as tamperCapability, d as TargetSchema, dt as vacuumControlCapability, et as parseAdminBase, f as accessoriesCapability, ft as valveCapability, g as ambientLightSensorCapability, gt as DeviceFeature, h as alarmPanelCapability, ht as weatherCapability, it as pressureSensorCapability, j as contactCapability, jt as string, k as colorCapability, kt as object, lt as temperatureSensorCapability, m as airQualitySensorCapability, mt as waterHeaterCapability, n as BaseDevice, nt as prepareNotification, ot as smokeCapability, p as addonRoutesCapability, pt as vibrationCapability, q as mediaPlayerCapability, r as BaseDeviceProvider, rt as presenceCapability, s as EnumSensorDateTimeFormatSchema, st as switchCapability, tt as powerMeterCapability, ut as updateCapability, v as batteryCapability, vt as DeviceType, w as buildDeviceAdminUrl, wt as array, x as brightnessCapability, xt as createEvent, y as bestLocationMatch, yt as errMsg, z as fanControlCapability } from "./dist-H458ct4y.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import { brotliCompressSync, deflateSync, gzipSync } from "node:zlib";
4
4
  //#region src/ha-admin-link.ts
@@ -4838,25 +4838,6 @@ var HaWsClient = class {
4838
4838
  }
4839
4839
  }
4840
4840
  };
4841
- /**
4842
- * Resolve auth config from the addon environment + persisted config.
4843
- * Prefers Supervisor token when present (the addon is running inside
4844
- * the HA Supervisor); falls back to the user-provided long-lived token
4845
- * for external deployments.
4846
- */
4847
- function resolveAuthConfig(env, persistedConfig) {
4848
- const supervisorToken = env.SUPERVISOR_TOKEN;
4849
- if (supervisorToken && supervisorToken.length > 0) return {
4850
- kind: "supervisor",
4851
- supervisorToken
4852
- };
4853
- if (persistedConfig?.baseUrl && persistedConfig.accessToken) return {
4854
- kind: "long-lived",
4855
- baseUrl: persistedConfig.baseUrl,
4856
- accessToken: persistedConfig.accessToken
4857
- };
4858
- return { error: "No HA auth configured — set SUPERVISOR_TOKEN env (Supervisor deployment) or supply baseUrl + accessToken in addon config" };
4859
- }
4860
4841
  //#endregion
4861
4842
  //#region src/ha-events.ts
4862
4843
  function processEvent(current, updates) {
@@ -5141,7 +5122,7 @@ var HaIntegrationManager = class HaIntegrationManager {
5141
5122
  service: target.service
5142
5123
  };
5143
5124
  const targetEnvelope = {};
5144
- if (target.entityId !== void 0) targetEnvelope["entity_id"] = Array.isArray(target.entityId) ? [...target.entityId] : target.entityId;
5125
+ if (target.entityId !== void 0) targetEnvelope["entity_id"] = typeof target.entityId === "string" ? target.entityId : [...target.entityId];
5145
5126
  if (target.areaId) targetEnvelope["area_id"] = target.areaId;
5146
5127
  if (target.deviceId) targetEnvelope["device_id"] = target.deviceId;
5147
5128
  if (Object.keys(targetEnvelope).length > 0) message["target"] = targetEnvelope;
@@ -7162,6 +7143,14 @@ function createHaNotificationOutputProvider(deps) {
7162
7143
  addonId
7163
7144
  }));
7164
7145
  },
7146
+ getTarget: async ({ targetId }) => {
7147
+ const target = await store.getById(targetId);
7148
+ if (!target) throw new Error(`Unknown target '${targetId}'`);
7149
+ return {
7150
+ ...target,
7151
+ addonId
7152
+ };
7153
+ },
7165
7154
  discoverTargets: async ({ kind, config }) => {
7166
7155
  if (kind !== "homeassistant") return [];
7167
7156
  const explicit = config ? readBrokerId(config) : void 0;
@@ -9058,4 +9047,4 @@ function coerceHaFilter(filter) {
9058
9047
  return out;
9059
9048
  }
9060
9049
  //#endregion
9061
- export { HaProviderAddon, HaIntegrationManager as a, HaWsClient as c, HaAuthConfigSchema as d, HaDomain as f, settingsToAuth as i, buildHaAuth as l, HaBrokerRegistry as n, processEvent as o, HaEntityStateSchema as p, authToSettings as r, subscribeEntities as s, HaBrokerEntrySchema as t, resolveAuthConfig as u };
9050
+ export { HaProviderAddon, HaIntegrationManager as a, HaWsClient as c, HaDomain as d, HaEntityStateSchema as f, settingsToAuth as i, buildHaAuth as l, HaBrokerRegistry as n, processEvent as o, authToSettings as r, subscribeEntities as s, HaBrokerEntrySchema as t, HaAuthConfigSchema as u };
@@ -10667,6 +10667,57 @@ var ClipSearchStrictnessSchema = _enum([
10667
10667
  "balanced",
10668
10668
  "strict"
10669
10669
  ]);
10670
+ new Set([
10671
+ {
10672
+ id: "person",
10673
+ name: "Person"
10674
+ },
10675
+ {
10676
+ id: "vehicle",
10677
+ name: "Vehicle"
10678
+ },
10679
+ {
10680
+ id: "animal",
10681
+ name: "Animal"
10682
+ },
10683
+ {
10684
+ id: "package",
10685
+ name: "Package"
10686
+ }
10687
+ ].map((l) => l.id));
10688
+ var COCO_TO_MACRO = {
10689
+ mapping: {
10690
+ person: "person",
10691
+ bicycle: "vehicle",
10692
+ car: "vehicle",
10693
+ motorcycle: "vehicle",
10694
+ airplane: "vehicle",
10695
+ bus: "vehicle",
10696
+ train: "vehicle",
10697
+ truck: "vehicle",
10698
+ boat: "vehicle",
10699
+ bird: "animal",
10700
+ cat: "animal",
10701
+ dog: "animal",
10702
+ horse: "animal",
10703
+ sheep: "animal",
10704
+ cow: "animal",
10705
+ elephant: "animal",
10706
+ bear: "animal",
10707
+ zebra: "animal",
10708
+ giraffe: "animal",
10709
+ suitcase: "package",
10710
+ backpack: "package",
10711
+ handbag: "package"
10712
+ },
10713
+ preserveOriginal: false
10714
+ };
10715
+ /** Steps a root detector may declare it fills. */
10716
+ var FILLABLE_STEP_IDS = [
10717
+ "animal-classifier",
10718
+ "vehicle-classifier",
10719
+ "package-detection"
10720
+ ];
10670
10721
  var MODEL_FORMATS = [
10671
10722
  "onnx",
10672
10723
  "coreml",
@@ -10736,11 +10787,11 @@ var ModelVariantGroupSchema = object({
10736
10787
  /** Quantization axis. Omit ⇒ the fp32 base build. */
10737
10788
  precision: _enum(["fp32", "int8"]).optional(),
10738
10789
  /**
10739
- * Speed-optimization axis. Omit ⇒ the standard build. `fast` marks a
10740
- * latency-optimized export (e.g. ReLU-activation variant) — the slot the
10741
- * future performance variants plug into.
10790
+ * Training / latency-variant axis. Omit ⇒ the standard build. `test` marks
10791
+ * an alternate training of the same family (Scrypted `relu_test`); chip
10792
+ * label is "Test".
10742
10793
  */
10743
- optimization: _enum(["standard", "fast"]).optional(),
10794
+ optimization: _enum(["standard", "test"]).optional(),
10744
10795
  /**
10745
10796
  * Input-resolution axis (square input side, px). Omit ⇒ the family's native
10746
10797
  * resolution (640 for yolo26). Reduced-input builds (320 / 256) are a big,
@@ -10763,9 +10814,10 @@ var ModelProviderIdSchema = _enum([
10763
10814
  * are per upstream. A persisted custom-model row written when this field was a
10764
10815
  * string still parses — the string is lifted into `{ weights }`.
10765
10816
  *
10766
- * Every licence surface (the admin "Models and licenses" page,
10767
- * `THIRD_PARTY_MODELS.md`, the Hugging Face model table) is GENERATED from
10768
- * these records by `scripts/gen-model-licenses.ts` (D661).
10817
+ * Every machine licence surface (`THIRD_PARTY_MODELS.md`, the Hugging Face
10818
+ * model table) is GENERATED from these records by
10819
+ * `scripts/gen-model-licenses.ts` (D661). Operator-facing docs live in
10820
+ * `camstack/docs` → `/docs/detection/models`.
10769
10821
  */
10770
10822
  var ModelLicenseSchema = preprocess((value) => typeof value === "string" ? { weights: value } : value, object({
10771
10823
  /** SPDX id of the WEIGHTS' terms, a `LicenseRef-*` for non-SPDX terms, or `UNKNOWN`. */
@@ -10798,6 +10850,12 @@ var ModelLicenseSchema = preprocess((value) => typeof value === "string" ? { wei
10798
10850
  /** True when the weights or their data forbid commercial use. */
10799
10851
  nonCommercial: boolean().optional()
10800
10852
  }));
10853
+ /** One `fillsClassifierEffects` entry — see `ModelCatalogEntry.fillsClassifierEffects`. */
10854
+ var FillsClassifierEffectSchema = object({
10855
+ stepId: _enum(FILLABLE_STEP_IDS),
10856
+ labelToEffect: record(string(), string()),
10857
+ uncovered: array(string()).readonly()
10858
+ });
10801
10859
  var ModelCatalogEntrySchema = object({
10802
10860
  id: string(),
10803
10861
  name: string(),
@@ -10924,6 +10982,16 @@ var ModelCatalogEntrySchema = object({
10924
10982
  */
10925
10983
  classMap: DetectionCatalogClassMapSchema.optional(),
10926
10984
  /**
10985
+ * The pipeline steps this ROOT detector already does the work of (D715):
10986
+ * its labels name the effect the step exists to produce (`deer` for
10987
+ * `animal-classifier`, `package` for `package-detection`). Derived from the
10988
+ * labelmap by `deriveClassifierFills`, never hand-written; a COCO model
10989
+ * declares none. Whether a declaration is honoured is the step's own
10990
+ * `labelLink` policy (`resolveLabelLink`). `labelToEffect` values are in
10991
+ * `FILLABLE_STEP_VOCABULARIES` (guard `check-label-link-vocabulary`).
10992
+ */
10993
+ fillsClassifierEffects: array(FillsClassifierEffectSchema).readonly().optional(),
10994
+ /**
10927
10995
  * The model's CLIP feature-space contract (text encoder, dimension, vector
10928
10996
  * index, token window, search floor) — see `clip-model.ts`. Present ONLY on a
10929
10997
  * CLIP image encoder; its absence is what "not a CLIP model" means to the
@@ -14464,7 +14532,7 @@ DeviceType.Camera;
14464
14532
  * This matters here more than anywhere else in the repo, because every provider
14465
14533
  * that knows a device's host knows its PASSWORD too: `{ host, port, username,
14466
14534
  * password }` sit in one object on Hikvision, Amcrest, Reolink and ONVIF alike,
14467
- * and `http://admin:hunter2@192.168.x.x/` is a URL a browser accepts. The
14535
+ * and `http://admin:hunter2@192.168.60.139/` is a URL a browser accepts. The
14468
14536
  * camera's own page will ask for its own login. That is correct, and pre-
14469
14537
  * filling it is the operator's business, not ours.
14470
14538
  *
@@ -17870,7 +17938,7 @@ method(object({
17870
17938
  timeoutMs: 6e5
17871
17939
  });
17872
17940
  method(object({
17873
- nodeId: string(),
17941
+ targetNodeId: string(),
17874
17942
  modelId: string(),
17875
17943
  format: _enum(MODEL_FORMATS),
17876
17944
  entry: ModelCatalogEntrySchema
@@ -18458,51 +18526,6 @@ var notificationOutputCapability = {
18458
18526
  })
18459
18527
  }
18460
18528
  };
18461
- new Set([
18462
- {
18463
- id: "person",
18464
- name: "Person"
18465
- },
18466
- {
18467
- id: "vehicle",
18468
- name: "Vehicle"
18469
- },
18470
- {
18471
- id: "animal",
18472
- name: "Animal"
18473
- },
18474
- {
18475
- id: "package",
18476
- name: "Package"
18477
- }
18478
- ].map((l) => l.id));
18479
- var COCO_TO_MACRO = {
18480
- mapping: {
18481
- person: "person",
18482
- bicycle: "vehicle",
18483
- car: "vehicle",
18484
- motorcycle: "vehicle",
18485
- airplane: "vehicle",
18486
- bus: "vehicle",
18487
- train: "vehicle",
18488
- truck: "vehicle",
18489
- boat: "vehicle",
18490
- bird: "animal",
18491
- cat: "animal",
18492
- dog: "animal",
18493
- horse: "animal",
18494
- sheep: "animal",
18495
- cow: "animal",
18496
- elephant: "animal",
18497
- bear: "animal",
18498
- zebra: "animal",
18499
- giraffe: "animal",
18500
- suitcase: "package",
18501
- backpack: "package",
18502
- handbag: "package"
18503
- },
18504
- preserveOriginal: false
18505
- };
18506
18529
  var AUDIO_MACRO_LABELS = [
18507
18530
  {
18508
18531
  id: "speech",
@@ -20396,8 +20419,9 @@ var NcRuleSchema = NcRuleInputSchema.extend({
20396
20419
  disabledTargetIds: array(string()).default([])
20397
20420
  });
20398
20421
  /**
20399
- * The state-summary SECTIONS (D647 / D698): the D637 kind groups that report a
20400
- * still-true state. `backups-exports` and `alarm` are not sections — a completed
20422
+ * The state-summary SECTIONS (D647 / D698 / D708): the D637 kind groups that
20423
+ * report a still-true state. `addons` is the crash-looped addons only and
20424
+ * `addon-updates` the addons that are behind (D708 split them). `backups-exports` and `alarm` are not sections — a completed
20401
20425
  * job is not an open state, and the alarm stays instant.
20402
20426
  */
20403
20427
  var NcStateSummarySectionIdSchema = _enum([
@@ -20409,6 +20433,7 @@ var NcStateSummarySectionIdSchema = _enum([
20409
20433
  "detection-blind",
20410
20434
  "nodes",
20411
20435
  "addons",
20436
+ "addon-updates",
20412
20437
  "updates"
20413
20438
  ]);
20414
20439
  /** One section of a previewed state summary. `unavailable` = its state could not be read. */
@@ -20889,7 +20914,19 @@ var NcAlarmModeDelaysListSchema = array(object({
20889
20914
  * When this mode may be armed. Absent / null = always allowed (same as a
20890
20915
  * rule with no `schedule`). Evaluated with {@link isScheduleActive}.
20891
20916
  */
20892
- schedule: NcScheduleSchema.optional()
20917
+ schedule: NcScheduleSchema.optional(),
20918
+ /**
20919
+ * D706: while this mode's ENTRY DELAY runs, do the alarm rules' own pushes go out (as an
20920
+ * intrusion naming the locations)? Absent = false — the entry-delay notification is the
20921
+ * only one, and the matches ride the triggered notification's mosaic (D705).
20922
+ */
20923
+ notifyDuringEntryDelay: boolean().optional(),
20924
+ /**
20925
+ * D706: notify "watched again" when a sensor this arm bypassed closes and opens again.
20926
+ * Absent = false (logged, not sent). Even when true it is not sent when that same sensor
20927
+ * is the one that starts the entry delay — the entry-delay notification already names it.
20928
+ */
20929
+ notifySensorRewatched: boolean().optional()
20893
20930
  })).max(8).refine(uniqueModes, { message: "modeDelays: at most one entry per arm mode" });
20894
20931
  var NcAlarmModeDelaysEditListSchema = array(object({
20895
20932
  mode: AlarmArmModeSchema,
@@ -20898,7 +20935,11 @@ var NcAlarmModeDelaysEditListSchema = array(object({
20898
20935
  triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional(),
20899
20936
  postTriggeredAction: NcAlarmPostTriggeredActionSchema.nullable().optional(),
20900
20937
  /** Set a schedule, or `null` to clear (mode always allowed again). */
20901
- schedule: NcScheduleSchema.nullable().optional()
20938
+ schedule: NcScheduleSchema.nullable().optional(),
20939
+ /** D706: set the switch, or `null` to clear it (back to the default, false). */
20940
+ notifyDuringEntryDelay: boolean().nullable().optional(),
20941
+ /** D706: set the switch, or `null` to clear it (back to the default, false). */
20942
+ notifySensorRewatched: boolean().nullable().optional()
20902
20943
  })).max(8).refine(uniqueModes, { message: "modeDelays: at most one edit per arm mode" });
20903
20944
  /** One switch of the alarm table: put ONE device on, or take it off, ONE mode's list. */
20904
20945
  var NcAlarmNonBlockingEditSchema = object({
@@ -21875,39 +21916,19 @@ Object.freeze(Object.fromEntries([{
21875
21916
  label: "Face recognition model",
21876
21917
  defaultModelId: "auraface-r100",
21877
21918
  indexName: "the enrolled face gallery",
21878
- options: [
21879
- {
21880
- id: "auraface-r100",
21881
- label: "AuraFace R100"
21882
- },
21883
- {
21884
- id: "arcface-r100",
21885
- label: "ArcFace (ResNet34)"
21886
- },
21887
- {
21888
- id: "inception-resnet-v1",
21889
- label: "Inception ResNet V1"
21890
- }
21891
- ]
21919
+ options: [{
21920
+ id: "auraface-r100",
21921
+ label: "AuraFace R100"
21922
+ }]
21892
21923
  }, {
21893
21924
  stepId: "clip-embedding",
21894
21925
  label: "Semantic search model",
21895
- defaultModelId: "mobileclip-s1",
21926
+ defaultModelId: "siglip2-b16-224",
21896
21927
  indexName: "the object semantic-search index",
21897
- options: [
21898
- {
21899
- id: "mobileclip-s1",
21900
- label: "MobileCLIP S1"
21901
- },
21902
- {
21903
- id: "mobileclip-s2",
21904
- label: "MobileCLIP S2"
21905
- },
21906
- {
21907
- id: "siglip2-b16-224",
21908
- label: "SigLIP2 B/16 (Apache-2.0)"
21909
- }
21910
- ]
21928
+ options: [{
21929
+ id: "siglip2-b16-224",
21930
+ label: "SigLIP2 B/16 (Apache-2.0)"
21931
+ }]
21911
21932
  }].map((s) => [s.stepId, s.defaultModelId])));
21912
21933
  var CLUSTER_STEP_SETTING_FIELDS = [{
21913
21934
  stepId: "face-embedding",
@@ -23962,7 +23983,8 @@ var PipelineModelOptionSchema = object({
23962
23983
  group: ModelVariantGroupSchema.optional(),
23963
23984
  legacy: boolean().optional(),
23964
23985
  provider: ModelProviderIdSchema.optional(),
23965
- defaultConfidence: number().optional()
23986
+ defaultConfidence: number().optional(),
23987
+ fillsClassifierEffects: array(FillsClassifierEffectSchema).readonly().optional()
23966
23988
  });
23967
23989
  var ConfigFieldBridge = custom();
23968
23990
  var PipelineAddonSchemaSchema = object({
@@ -24795,6 +24817,22 @@ var MotionSourceEnum = _enum([
24795
24817
  "device-activity"
24796
24818
  ]);
24797
24819
  /**
24820
+ * What opened an on-motion detection SESSION: the motion source that passed the
24821
+ * camera's `motionSources` gate, and what raised it (the camera itself, or a
24822
+ * sensor the operator attached — D672). `sensorName` is the attached sensor's
24823
+ * device name as the orchestrator's camera-sensors resolution last read it;
24824
+ * absent when unknown or when the camera itself triggered.
24825
+ *
24826
+ * Carried on the session attach ONLY so the runner's `DetectionPhaseTransition`
24827
+ * can say what started the session (D672 rule 11, amended 2026-10-06). The
24828
+ * runner never decides anything on it.
24829
+ */
24830
+ var SessionTriggerSchema = object({
24831
+ source: MotionSourceEnum,
24832
+ triggeredBy: MotionTriggeredBySchema,
24833
+ sensorName: string().optional()
24834
+ });
24835
+ /**
24798
24836
  * List of motion sources active on a camera. Empty array is valid:
24799
24837
  * "no source" — happens for battery cams without firmware motion when
24800
24838
  * the operator hasn't opted into the SW analyzer (would hold the
@@ -25046,6 +25084,14 @@ var RunnerCameraConfigSchema = object({
25046
25084
  */
25047
25085
  motionSources: MotionSourcesSchema.default(["analyzer"]),
25048
25086
  /**
25087
+ * What opened this attach, on a SESSION attach only (see
25088
+ * {@link SessionTriggerSchema}). OPTIONAL with no default: absent on a
25089
+ * standing attach, an occupancy burst, a re-dispatch with no motion event
25090
+ * behind it, and every attach from an orchestrator older than the field — the
25091
+ * runner then names no source on the phase event.
25092
+ */
25093
+ sessionTrigger: SessionTriggerSchema.optional(),
25094
+ /**
25049
25095
  * WHICH root detector runs for this camera. The detection counterpart of
25050
25096
  * {@link motionSources}, same shape and same discipline: a per-camera list
25051
25097
  * of sources the system understands, vendor-agnostic, owned here.
@@ -32532,7 +32578,7 @@ var LocalInterfaceSchema = object({
32532
32578
  name: string(),
32533
32579
  family: _enum(["IPv4", "IPv6"]),
32534
32580
  address: string(),
32535
- /** CIDR shorthand (e.g. `192.168.x.x/24`). Empty when OS doesn't expose. */
32581
+ /** CIDR shorthand (e.g. `192.168.10.10/24`). Empty when OS doesn't expose. */
32536
32582
  cidr: string(),
32537
32583
  /** OS netmask. Stable across calls so the SDK can hash on it. */
32538
32584
  netmask: string(),
@@ -32586,7 +32632,8 @@ var ConnectionEndpointSchema = object({
32586
32632
  "lan-ipv4",
32587
32633
  "lan-ipv6",
32588
32634
  "public",
32589
- "loopback"
32635
+ "loopback",
32636
+ "app-link"
32590
32637
  ]),
32591
32638
  /**
32592
32639
  * Originating-interface kind — `lan`/`wifi`/`docker`/`vpn`/`other`/
@@ -32655,15 +32702,27 @@ var GetConnectionEndpointsResultSchema = object({
32655
32702
  localPort: AdvertisedLocalPortSchema
32656
32703
  });
32657
32704
  /**
32658
- * The chosen outbound endpoint for notification artifacts. `baseUrl: null` =
32659
- * AUTO (resolved from the candidate ranking at send time); `resolved` reports
32660
- * what AUTO currently picks, so the UI can show the effective value either way.
32705
+ * The address flagged for notification links. `baseUrl: null` = AUTO, which
32706
+ * since D709 is the CamStack app link; `resolved` reports the effective value,
32707
+ * so the UI can show it either way.
32661
32708
  */
32662
32709
  var NotificationEndpointSchema = object({
32663
32710
  /** The operator's explicit choice, or null for AUTO. */
32664
32711
  baseUrl: string().nullable(),
32665
- /** What the ranking currently resolves to (null when nothing is reachable). */
32666
- resolved: string().nullable()
32712
+ /**
32713
+ * The effective flagged address: the explicit choice, else (AUTO) the
32714
+ * CamStack app link `https://camstack.zentik.app` (D709). A pre-D709 hub
32715
+ * answered the public tunnel / mesh here, or null.
32716
+ */
32717
+ resolved: string().nullable(),
32718
+ /**
32719
+ * The hub origin an app link carries as `hub=` (D709): the hub's best
32720
+ * public HTTPS address — the tunnel, then the mesh (Tailscale MagicDNS) —
32721
+ * picked from this cap's own palette by `pickAppLinkHub`. `null` when the
32722
+ * hub advertises neither; the app link is then minted without `hub=`.
32723
+ * Absent on a pre-D709 hub.
32724
+ */
32725
+ appLinkHub: string().nullable()
32667
32726
  });
32668
32727
  /**
32669
32728
  * The URLs the SDK / viewer should race for API access. `baseUrls` empty =
@@ -32717,7 +32776,11 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
32717
32776
  * Pass `'https'` when the caller is itself loaded over HTTPS
32718
32777
  * to avoid mixed-content blocks in the browser. The public
32719
32778
  * tunnel always emits `https://` regardless. */
32720
- scheme: _enum(["http", "https"]).optional()
32779
+ scheme: _enum(["http", "https"]).optional(),
32780
+ /** Append the CamStack app link entry (`kind: 'app-link'`, D709) —
32781
+ * an address notification links can be flagged with, not a hub
32782
+ * route. Default `false`: racers and rankers never see it. */
32783
+ includeAppLink: boolean().optional()
32721
32784
  }), 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, {
32722
32785
  kind: "mutation",
32723
32786
  auth: "admin"
@@ -33046,7 +33109,7 @@ var MeshPeerSchema = object({
33046
33109
  tags: array(string()).readonly(),
33047
33110
  /** True when the peer advertises itself as an exit-node candidate. */
33048
33111
  exitNodeOption: boolean(),
33049
- /** Subnet routes the peer advertises (e.g. `["192.168.x.x/24"]`). */
33112
+ /** Subnet routes the peer advertises (e.g. `["192.168.10.0/24"]`). */
33050
33113
  advertisedRoutes: array(string()).readonly(),
33051
33114
  /** Owner account login (e.g. `foo@example.com`). Null for tagged peers. */
33052
33115
  userLogin: string().nullable(),
@@ -34374,7 +34437,13 @@ var OsdStatusSchema = object({ overlays: array(object({
34374
34437
  */
34375
34438
  availablePositions: array(OsdPositionEnum).readonly(),
34376
34439
  /** Firmware does not allow editing the `text` field (e.g. timestamp). */
34377
- readOnly: boolean().optional()
34440
+ readOnly: boolean().optional(),
34441
+ /**
34442
+ * Firmware text ceiling for this overlay. Absent = no known limit.
34443
+ * The OSD manager truncates here on every write — never stores its own
34444
+ * copy on the binding.
34445
+ */
34446
+ maxCharacters: number().int().positive().optional()
34378
34447
  })).readonly() });
34379
34448
  var OsdOverlayPatchSchema = object({
34380
34449
  enabled: boolean().optional(),
@@ -34425,7 +34494,9 @@ var OsdTemplateBindingSchema = object({
34425
34494
  valuePath: string().min(1).max(64),
34426
34495
  /** Convert TO this unit at render (`tryConvertUnit`). Absent = source unit. */
34427
34496
  displayUnit: string().max(16).optional(),
34428
- maxDecimals: number().int().min(0).max(4).default(1)
34497
+ maxDecimals: number().int().min(0).max(4).default(1),
34498
+ /** Raw value → display text (same shape as slot binding). Empty string hides. */
34499
+ valueMap: record(string(), string()).optional()
34429
34500
  });
34430
34501
  /**
34431
34502
  * A named template: bindings (alias → leaf field) + a parser that
@@ -34475,18 +34546,11 @@ var OsdSlotBindingSchema = object({
34475
34546
  source: OsdSourceSchema,
34476
34547
  /** `${value}` and `${unit}` are substituted; every occurrence. */
34477
34548
  template: string().max(96).default("${value}"),
34478
- /** Truncate with an ellipsis past this length. Absent = no limit. */
34479
- maxCharacters: number().int().min(4).max(64).optional(),
34480
34549
  /**
34481
34550
  * Decimal places for a numeric value. `0` yields an integer — the
34482
34551
  * documented workaround for firmwares that reject `.` in overlay text.
34483
34552
  */
34484
34553
  maxDecimals: number().int().min(0).max(4).default(1),
34485
- /**
34486
- * Appended via `${unit}` when no unit conversion produces a label.
34487
- * Prefer `source.displayUnit` for converted device-state values.
34488
- */
34489
- unitLabel: string().max(8).optional(),
34490
34554
  /** Raw value → display text, e.g. `{"true":"MOTION","false":""}`. */
34491
34555
  valueMap: record(string(), string()).optional(),
34492
34556
  /** Time windows in which the slot is shown. Absent = always. */
@@ -34495,9 +34559,7 @@ var OsdSlotBindingSchema = object({
34495
34559
  * Display gate, in the notification centre's condition vocabulary.
34496
34560
  * Only the keys reported by `getConditionSupport` are accepted.
34497
34561
  */
34498
- conditions: NcConditionsSchema.optional(),
34499
- /** Rendered when the gate is closed or the value unreadable. Empty = hide. */
34500
- fallbackText: string().max(64).default("")
34562
+ conditions: NcConditionsSchema.optional()
34501
34563
  });
34502
34564
  /** One camera slot, as the operator sees it: firmware truth + our binding. */
34503
34565
  var OsdSlotViewSchema = object({
@@ -52937,12 +52999,14 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
52937
52999
  {
52938
53000
  id: "addons",
52939
53001
  family: "system",
52940
- label: "Addons",
52941
- kinds: [
52942
- "addon-crash-loop",
52943
- "addon-update-available",
52944
- "addon-updated"
52945
- ]
53002
+ label: "Addons stopped",
53003
+ kinds: ["addon-crash-loop"]
53004
+ },
53005
+ {
53006
+ id: "addon-updates",
53007
+ family: "system",
53008
+ label: "Addon updates",
53009
+ kinds: ["addon-update-available", "addon-updated"]
52946
53010
  },
52947
53011
  {
52948
53012
  id: "updates",
@@ -53102,13 +53166,15 @@ var STATE_SUMMARY_SECTION_VARS = [
53102
53166
  },
53103
53167
  {
53104
53168
  name: "summaryAddons",
53105
- label: "Summary: addons",
53106
- example: "@camstack/addon-recorder 1.2.3 → 1.2.4",
53107
- kinds: [
53108
- "addon-crash-loop",
53109
- "addon-update-available",
53110
- "addon-updated"
53111
- ]
53169
+ label: "Summary: addons stopped",
53170
+ example: "hub — recorder stopped after repeated crashes",
53171
+ kinds: ["addon-crash-loop"]
53172
+ },
53173
+ {
53174
+ name: "summaryAddonUpdates",
53175
+ label: "Summary: addon updates",
53176
+ example: "hub:\n• @camstack/addon-recorder 1.2.3 → 1.2.4",
53177
+ kinds: ["addon-update-available", "addon-updated"]
53112
53178
  },
53113
53179
  {
53114
53180
  name: "summaryUpdates",
@@ -53192,6 +53258,7 @@ var STATE_SUMMARY_VARS = [
53192
53258
  [...RULE_BODY_ONLY],
53193
53259
  [...RULE_TEXT],
53194
53260
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
53261
+ ([...RULE_TEXT], [...COMBINED_ALARM]),
53195
53262
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
53196
53263
  ([...RULE_TEXT], [...BATTERY, ...CONSUMABLE]),
53197
53264
  ([...RULE_TEXT], [...CONSUMABLE]),
@@ -53232,6 +53299,8 @@ var STATE_SUMMARY_VARS = [
53232
53299
  [...RULE_TEXT],
53233
53300
  [...RULE_TEXT],
53234
53301
  [...RULE_TEXT],
53302
+ [...RULE_TEXT],
53303
+ [...RULE_TEXT],
53235
53304
  ...STATE_SUMMARY_VARS
53236
53305
  ];
53237
53306
  new Set([
@@ -10668,6 +10668,57 @@ var ClipSearchStrictnessSchema = _enum([
10668
10668
  "balanced",
10669
10669
  "strict"
10670
10670
  ]);
10671
+ new Set([
10672
+ {
10673
+ id: "person",
10674
+ name: "Person"
10675
+ },
10676
+ {
10677
+ id: "vehicle",
10678
+ name: "Vehicle"
10679
+ },
10680
+ {
10681
+ id: "animal",
10682
+ name: "Animal"
10683
+ },
10684
+ {
10685
+ id: "package",
10686
+ name: "Package"
10687
+ }
10688
+ ].map((l) => l.id));
10689
+ var COCO_TO_MACRO = {
10690
+ mapping: {
10691
+ person: "person",
10692
+ bicycle: "vehicle",
10693
+ car: "vehicle",
10694
+ motorcycle: "vehicle",
10695
+ airplane: "vehicle",
10696
+ bus: "vehicle",
10697
+ train: "vehicle",
10698
+ truck: "vehicle",
10699
+ boat: "vehicle",
10700
+ bird: "animal",
10701
+ cat: "animal",
10702
+ dog: "animal",
10703
+ horse: "animal",
10704
+ sheep: "animal",
10705
+ cow: "animal",
10706
+ elephant: "animal",
10707
+ bear: "animal",
10708
+ zebra: "animal",
10709
+ giraffe: "animal",
10710
+ suitcase: "package",
10711
+ backpack: "package",
10712
+ handbag: "package"
10713
+ },
10714
+ preserveOriginal: false
10715
+ };
10716
+ /** Steps a root detector may declare it fills. */
10717
+ var FILLABLE_STEP_IDS = [
10718
+ "animal-classifier",
10719
+ "vehicle-classifier",
10720
+ "package-detection"
10721
+ ];
10671
10722
  var MODEL_FORMATS = [
10672
10723
  "onnx",
10673
10724
  "coreml",
@@ -10737,11 +10788,11 @@ var ModelVariantGroupSchema = object({
10737
10788
  /** Quantization axis. Omit ⇒ the fp32 base build. */
10738
10789
  precision: _enum(["fp32", "int8"]).optional(),
10739
10790
  /**
10740
- * Speed-optimization axis. Omit ⇒ the standard build. `fast` marks a
10741
- * latency-optimized export (e.g. ReLU-activation variant) — the slot the
10742
- * future performance variants plug into.
10791
+ * Training / latency-variant axis. Omit ⇒ the standard build. `test` marks
10792
+ * an alternate training of the same family (Scrypted `relu_test`); chip
10793
+ * label is "Test".
10743
10794
  */
10744
- optimization: _enum(["standard", "fast"]).optional(),
10795
+ optimization: _enum(["standard", "test"]).optional(),
10745
10796
  /**
10746
10797
  * Input-resolution axis (square input side, px). Omit ⇒ the family's native
10747
10798
  * resolution (640 for yolo26). Reduced-input builds (320 / 256) are a big,
@@ -10764,9 +10815,10 @@ var ModelProviderIdSchema = _enum([
10764
10815
  * are per upstream. A persisted custom-model row written when this field was a
10765
10816
  * string still parses — the string is lifted into `{ weights }`.
10766
10817
  *
10767
- * Every licence surface (the admin "Models and licenses" page,
10768
- * `THIRD_PARTY_MODELS.md`, the Hugging Face model table) is GENERATED from
10769
- * these records by `scripts/gen-model-licenses.ts` (D661).
10818
+ * Every machine licence surface (`THIRD_PARTY_MODELS.md`, the Hugging Face
10819
+ * model table) is GENERATED from these records by
10820
+ * `scripts/gen-model-licenses.ts` (D661). Operator-facing docs live in
10821
+ * `camstack/docs` → `/docs/detection/models`.
10770
10822
  */
10771
10823
  var ModelLicenseSchema = preprocess((value) => typeof value === "string" ? { weights: value } : value, object({
10772
10824
  /** SPDX id of the WEIGHTS' terms, a `LicenseRef-*` for non-SPDX terms, or `UNKNOWN`. */
@@ -10799,6 +10851,12 @@ var ModelLicenseSchema = preprocess((value) => typeof value === "string" ? { wei
10799
10851
  /** True when the weights or their data forbid commercial use. */
10800
10852
  nonCommercial: boolean().optional()
10801
10853
  }));
10854
+ /** One `fillsClassifierEffects` entry — see `ModelCatalogEntry.fillsClassifierEffects`. */
10855
+ var FillsClassifierEffectSchema = object({
10856
+ stepId: _enum(FILLABLE_STEP_IDS),
10857
+ labelToEffect: record(string(), string()),
10858
+ uncovered: array(string()).readonly()
10859
+ });
10802
10860
  var ModelCatalogEntrySchema = object({
10803
10861
  id: string(),
10804
10862
  name: string(),
@@ -10925,6 +10983,16 @@ var ModelCatalogEntrySchema = object({
10925
10983
  */
10926
10984
  classMap: DetectionCatalogClassMapSchema.optional(),
10927
10985
  /**
10986
+ * The pipeline steps this ROOT detector already does the work of (D715):
10987
+ * its labels name the effect the step exists to produce (`deer` for
10988
+ * `animal-classifier`, `package` for `package-detection`). Derived from the
10989
+ * labelmap by `deriveClassifierFills`, never hand-written; a COCO model
10990
+ * declares none. Whether a declaration is honoured is the step's own
10991
+ * `labelLink` policy (`resolveLabelLink`). `labelToEffect` values are in
10992
+ * `FILLABLE_STEP_VOCABULARIES` (guard `check-label-link-vocabulary`).
10993
+ */
10994
+ fillsClassifierEffects: array(FillsClassifierEffectSchema).readonly().optional(),
10995
+ /**
10928
10996
  * The model's CLIP feature-space contract (text encoder, dimension, vector
10929
10997
  * index, token window, search floor) — see `clip-model.ts`. Present ONLY on a
10930
10998
  * CLIP image encoder; its absence is what "not a CLIP model" means to the
@@ -14465,7 +14533,7 @@ DeviceType.Camera;
14465
14533
  * This matters here more than anywhere else in the repo, because every provider
14466
14534
  * that knows a device's host knows its PASSWORD too: `{ host, port, username,
14467
14535
  * password }` sit in one object on Hikvision, Amcrest, Reolink and ONVIF alike,
14468
- * and `http://admin:hunter2@192.168.x.x/` is a URL a browser accepts. The
14536
+ * and `http://admin:hunter2@192.168.60.139/` is a URL a browser accepts. The
14469
14537
  * camera's own page will ask for its own login. That is correct, and pre-
14470
14538
  * filling it is the operator's business, not ours.
14471
14539
  *
@@ -17871,7 +17939,7 @@ method(object({
17871
17939
  timeoutMs: 6e5
17872
17940
  });
17873
17941
  method(object({
17874
- nodeId: string(),
17942
+ targetNodeId: string(),
17875
17943
  modelId: string(),
17876
17944
  format: _enum(MODEL_FORMATS),
17877
17945
  entry: ModelCatalogEntrySchema
@@ -18459,51 +18527,6 @@ var notificationOutputCapability = {
18459
18527
  })
18460
18528
  }
18461
18529
  };
18462
- new Set([
18463
- {
18464
- id: "person",
18465
- name: "Person"
18466
- },
18467
- {
18468
- id: "vehicle",
18469
- name: "Vehicle"
18470
- },
18471
- {
18472
- id: "animal",
18473
- name: "Animal"
18474
- },
18475
- {
18476
- id: "package",
18477
- name: "Package"
18478
- }
18479
- ].map((l) => l.id));
18480
- var COCO_TO_MACRO = {
18481
- mapping: {
18482
- person: "person",
18483
- bicycle: "vehicle",
18484
- car: "vehicle",
18485
- motorcycle: "vehicle",
18486
- airplane: "vehicle",
18487
- bus: "vehicle",
18488
- train: "vehicle",
18489
- truck: "vehicle",
18490
- boat: "vehicle",
18491
- bird: "animal",
18492
- cat: "animal",
18493
- dog: "animal",
18494
- horse: "animal",
18495
- sheep: "animal",
18496
- cow: "animal",
18497
- elephant: "animal",
18498
- bear: "animal",
18499
- zebra: "animal",
18500
- giraffe: "animal",
18501
- suitcase: "package",
18502
- backpack: "package",
18503
- handbag: "package"
18504
- },
18505
- preserveOriginal: false
18506
- };
18507
18530
  var AUDIO_MACRO_LABELS = [
18508
18531
  {
18509
18532
  id: "speech",
@@ -20397,8 +20420,9 @@ var NcRuleSchema = NcRuleInputSchema.extend({
20397
20420
  disabledTargetIds: array(string()).default([])
20398
20421
  });
20399
20422
  /**
20400
- * The state-summary SECTIONS (D647 / D698): the D637 kind groups that report a
20401
- * still-true state. `backups-exports` and `alarm` are not sections — a completed
20423
+ * The state-summary SECTIONS (D647 / D698 / D708): the D637 kind groups that
20424
+ * report a still-true state. `addons` is the crash-looped addons only and
20425
+ * `addon-updates` the addons that are behind (D708 split them). `backups-exports` and `alarm` are not sections — a completed
20402
20426
  * job is not an open state, and the alarm stays instant.
20403
20427
  */
20404
20428
  var NcStateSummarySectionIdSchema = _enum([
@@ -20410,6 +20434,7 @@ var NcStateSummarySectionIdSchema = _enum([
20410
20434
  "detection-blind",
20411
20435
  "nodes",
20412
20436
  "addons",
20437
+ "addon-updates",
20413
20438
  "updates"
20414
20439
  ]);
20415
20440
  /** One section of a previewed state summary. `unavailable` = its state could not be read. */
@@ -20890,7 +20915,19 @@ var NcAlarmModeDelaysListSchema = array(object({
20890
20915
  * When this mode may be armed. Absent / null = always allowed (same as a
20891
20916
  * rule with no `schedule`). Evaluated with {@link isScheduleActive}.
20892
20917
  */
20893
- schedule: NcScheduleSchema.optional()
20918
+ schedule: NcScheduleSchema.optional(),
20919
+ /**
20920
+ * D706: while this mode's ENTRY DELAY runs, do the alarm rules' own pushes go out (as an
20921
+ * intrusion naming the locations)? Absent = false — the entry-delay notification is the
20922
+ * only one, and the matches ride the triggered notification's mosaic (D705).
20923
+ */
20924
+ notifyDuringEntryDelay: boolean().optional(),
20925
+ /**
20926
+ * D706: notify "watched again" when a sensor this arm bypassed closes and opens again.
20927
+ * Absent = false (logged, not sent). Even when true it is not sent when that same sensor
20928
+ * is the one that starts the entry delay — the entry-delay notification already names it.
20929
+ */
20930
+ notifySensorRewatched: boolean().optional()
20894
20931
  })).max(8).refine(uniqueModes, { message: "modeDelays: at most one entry per arm mode" });
20895
20932
  var NcAlarmModeDelaysEditListSchema = array(object({
20896
20933
  mode: AlarmArmModeSchema,
@@ -20899,7 +20936,11 @@ var NcAlarmModeDelaysEditListSchema = array(object({
20899
20936
  triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional(),
20900
20937
  postTriggeredAction: NcAlarmPostTriggeredActionSchema.nullable().optional(),
20901
20938
  /** Set a schedule, or `null` to clear (mode always allowed again). */
20902
- schedule: NcScheduleSchema.nullable().optional()
20939
+ schedule: NcScheduleSchema.nullable().optional(),
20940
+ /** D706: set the switch, or `null` to clear it (back to the default, false). */
20941
+ notifyDuringEntryDelay: boolean().nullable().optional(),
20942
+ /** D706: set the switch, or `null` to clear it (back to the default, false). */
20943
+ notifySensorRewatched: boolean().nullable().optional()
20903
20944
  })).max(8).refine(uniqueModes, { message: "modeDelays: at most one edit per arm mode" });
20904
20945
  /** One switch of the alarm table: put ONE device on, or take it off, ONE mode's list. */
20905
20946
  var NcAlarmNonBlockingEditSchema = object({
@@ -21876,39 +21917,19 @@ Object.freeze(Object.fromEntries([{
21876
21917
  label: "Face recognition model",
21877
21918
  defaultModelId: "auraface-r100",
21878
21919
  indexName: "the enrolled face gallery",
21879
- options: [
21880
- {
21881
- id: "auraface-r100",
21882
- label: "AuraFace R100"
21883
- },
21884
- {
21885
- id: "arcface-r100",
21886
- label: "ArcFace (ResNet34)"
21887
- },
21888
- {
21889
- id: "inception-resnet-v1",
21890
- label: "Inception ResNet V1"
21891
- }
21892
- ]
21920
+ options: [{
21921
+ id: "auraface-r100",
21922
+ label: "AuraFace R100"
21923
+ }]
21893
21924
  }, {
21894
21925
  stepId: "clip-embedding",
21895
21926
  label: "Semantic search model",
21896
- defaultModelId: "mobileclip-s1",
21927
+ defaultModelId: "siglip2-b16-224",
21897
21928
  indexName: "the object semantic-search index",
21898
- options: [
21899
- {
21900
- id: "mobileclip-s1",
21901
- label: "MobileCLIP S1"
21902
- },
21903
- {
21904
- id: "mobileclip-s2",
21905
- label: "MobileCLIP S2"
21906
- },
21907
- {
21908
- id: "siglip2-b16-224",
21909
- label: "SigLIP2 B/16 (Apache-2.0)"
21910
- }
21911
- ]
21929
+ options: [{
21930
+ id: "siglip2-b16-224",
21931
+ label: "SigLIP2 B/16 (Apache-2.0)"
21932
+ }]
21912
21933
  }].map((s) => [s.stepId, s.defaultModelId])));
21913
21934
  var CLUSTER_STEP_SETTING_FIELDS = [{
21914
21935
  stepId: "face-embedding",
@@ -23963,7 +23984,8 @@ var PipelineModelOptionSchema = object({
23963
23984
  group: ModelVariantGroupSchema.optional(),
23964
23985
  legacy: boolean().optional(),
23965
23986
  provider: ModelProviderIdSchema.optional(),
23966
- defaultConfidence: number().optional()
23987
+ defaultConfidence: number().optional(),
23988
+ fillsClassifierEffects: array(FillsClassifierEffectSchema).readonly().optional()
23967
23989
  });
23968
23990
  var ConfigFieldBridge = custom();
23969
23991
  var PipelineAddonSchemaSchema = object({
@@ -24796,6 +24818,22 @@ var MotionSourceEnum = _enum([
24796
24818
  "device-activity"
24797
24819
  ]);
24798
24820
  /**
24821
+ * What opened an on-motion detection SESSION: the motion source that passed the
24822
+ * camera's `motionSources` gate, and what raised it (the camera itself, or a
24823
+ * sensor the operator attached — D672). `sensorName` is the attached sensor's
24824
+ * device name as the orchestrator's camera-sensors resolution last read it;
24825
+ * absent when unknown or when the camera itself triggered.
24826
+ *
24827
+ * Carried on the session attach ONLY so the runner's `DetectionPhaseTransition`
24828
+ * can say what started the session (D672 rule 11, amended 2026-10-06). The
24829
+ * runner never decides anything on it.
24830
+ */
24831
+ var SessionTriggerSchema = object({
24832
+ source: MotionSourceEnum,
24833
+ triggeredBy: MotionTriggeredBySchema,
24834
+ sensorName: string().optional()
24835
+ });
24836
+ /**
24799
24837
  * List of motion sources active on a camera. Empty array is valid:
24800
24838
  * "no source" — happens for battery cams without firmware motion when
24801
24839
  * the operator hasn't opted into the SW analyzer (would hold the
@@ -25047,6 +25085,14 @@ var RunnerCameraConfigSchema = object({
25047
25085
  */
25048
25086
  motionSources: MotionSourcesSchema.default(["analyzer"]),
25049
25087
  /**
25088
+ * What opened this attach, on a SESSION attach only (see
25089
+ * {@link SessionTriggerSchema}). OPTIONAL with no default: absent on a
25090
+ * standing attach, an occupancy burst, a re-dispatch with no motion event
25091
+ * behind it, and every attach from an orchestrator older than the field — the
25092
+ * runner then names no source on the phase event.
25093
+ */
25094
+ sessionTrigger: SessionTriggerSchema.optional(),
25095
+ /**
25050
25096
  * WHICH root detector runs for this camera. The detection counterpart of
25051
25097
  * {@link motionSources}, same shape and same discipline: a per-camera list
25052
25098
  * of sources the system understands, vendor-agnostic, owned here.
@@ -32533,7 +32579,7 @@ var LocalInterfaceSchema = object({
32533
32579
  name: string(),
32534
32580
  family: _enum(["IPv4", "IPv6"]),
32535
32581
  address: string(),
32536
- /** CIDR shorthand (e.g. `192.168.x.x/24`). Empty when OS doesn't expose. */
32582
+ /** CIDR shorthand (e.g. `192.168.10.10/24`). Empty when OS doesn't expose. */
32537
32583
  cidr: string(),
32538
32584
  /** OS netmask. Stable across calls so the SDK can hash on it. */
32539
32585
  netmask: string(),
@@ -32587,7 +32633,8 @@ var ConnectionEndpointSchema = object({
32587
32633
  "lan-ipv4",
32588
32634
  "lan-ipv6",
32589
32635
  "public",
32590
- "loopback"
32636
+ "loopback",
32637
+ "app-link"
32591
32638
  ]),
32592
32639
  /**
32593
32640
  * Originating-interface kind — `lan`/`wifi`/`docker`/`vpn`/`other`/
@@ -32656,15 +32703,27 @@ var GetConnectionEndpointsResultSchema = object({
32656
32703
  localPort: AdvertisedLocalPortSchema
32657
32704
  });
32658
32705
  /**
32659
- * The chosen outbound endpoint for notification artifacts. `baseUrl: null` =
32660
- * AUTO (resolved from the candidate ranking at send time); `resolved` reports
32661
- * what AUTO currently picks, so the UI can show the effective value either way.
32706
+ * The address flagged for notification links. `baseUrl: null` = AUTO, which
32707
+ * since D709 is the CamStack app link; `resolved` reports the effective value,
32708
+ * so the UI can show it either way.
32662
32709
  */
32663
32710
  var NotificationEndpointSchema = object({
32664
32711
  /** The operator's explicit choice, or null for AUTO. */
32665
32712
  baseUrl: string().nullable(),
32666
- /** What the ranking currently resolves to (null when nothing is reachable). */
32667
- resolved: string().nullable()
32713
+ /**
32714
+ * The effective flagged address: the explicit choice, else (AUTO) the
32715
+ * CamStack app link `https://camstack.zentik.app` (D709). A pre-D709 hub
32716
+ * answered the public tunnel / mesh here, or null.
32717
+ */
32718
+ resolved: string().nullable(),
32719
+ /**
32720
+ * The hub origin an app link carries as `hub=` (D709): the hub's best
32721
+ * public HTTPS address — the tunnel, then the mesh (Tailscale MagicDNS) —
32722
+ * picked from this cap's own palette by `pickAppLinkHub`. `null` when the
32723
+ * hub advertises neither; the app link is then minted without `hub=`.
32724
+ * Absent on a pre-D709 hub.
32725
+ */
32726
+ appLinkHub: string().nullable()
32668
32727
  });
32669
32728
  /**
32670
32729
  * The URLs the SDK / viewer should race for API access. `baseUrls` empty =
@@ -32718,7 +32777,11 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
32718
32777
  * Pass `'https'` when the caller is itself loaded over HTTPS
32719
32778
  * to avoid mixed-content blocks in the browser. The public
32720
32779
  * tunnel always emits `https://` regardless. */
32721
- scheme: _enum(["http", "https"]).optional()
32780
+ scheme: _enum(["http", "https"]).optional(),
32781
+ /** Append the CamStack app link entry (`kind: 'app-link'`, D709) —
32782
+ * an address notification links can be flagged with, not a hub
32783
+ * route. Default `false`: racers and rankers never see it. */
32784
+ includeAppLink: boolean().optional()
32722
32785
  }), 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, {
32723
32786
  kind: "mutation",
32724
32787
  auth: "admin"
@@ -33047,7 +33110,7 @@ var MeshPeerSchema = object({
33047
33110
  tags: array(string()).readonly(),
33048
33111
  /** True when the peer advertises itself as an exit-node candidate. */
33049
33112
  exitNodeOption: boolean(),
33050
- /** Subnet routes the peer advertises (e.g. `["192.168.x.x/24"]`). */
33113
+ /** Subnet routes the peer advertises (e.g. `["192.168.10.0/24"]`). */
33051
33114
  advertisedRoutes: array(string()).readonly(),
33052
33115
  /** Owner account login (e.g. `foo@example.com`). Null for tagged peers. */
33053
33116
  userLogin: string().nullable(),
@@ -34375,7 +34438,13 @@ var OsdStatusSchema = object({ overlays: array(object({
34375
34438
  */
34376
34439
  availablePositions: array(OsdPositionEnum).readonly(),
34377
34440
  /** Firmware does not allow editing the `text` field (e.g. timestamp). */
34378
- readOnly: boolean().optional()
34441
+ readOnly: boolean().optional(),
34442
+ /**
34443
+ * Firmware text ceiling for this overlay. Absent = no known limit.
34444
+ * The OSD manager truncates here on every write — never stores its own
34445
+ * copy on the binding.
34446
+ */
34447
+ maxCharacters: number().int().positive().optional()
34379
34448
  })).readonly() });
34380
34449
  var OsdOverlayPatchSchema = object({
34381
34450
  enabled: boolean().optional(),
@@ -34426,7 +34495,9 @@ var OsdTemplateBindingSchema = object({
34426
34495
  valuePath: string().min(1).max(64),
34427
34496
  /** Convert TO this unit at render (`tryConvertUnit`). Absent = source unit. */
34428
34497
  displayUnit: string().max(16).optional(),
34429
- maxDecimals: number().int().min(0).max(4).default(1)
34498
+ maxDecimals: number().int().min(0).max(4).default(1),
34499
+ /** Raw value → display text (same shape as slot binding). Empty string hides. */
34500
+ valueMap: record(string(), string()).optional()
34430
34501
  });
34431
34502
  /**
34432
34503
  * A named template: bindings (alias → leaf field) + a parser that
@@ -34476,18 +34547,11 @@ var OsdSlotBindingSchema = object({
34476
34547
  source: OsdSourceSchema,
34477
34548
  /** `${value}` and `${unit}` are substituted; every occurrence. */
34478
34549
  template: string().max(96).default("${value}"),
34479
- /** Truncate with an ellipsis past this length. Absent = no limit. */
34480
- maxCharacters: number().int().min(4).max(64).optional(),
34481
34550
  /**
34482
34551
  * Decimal places for a numeric value. `0` yields an integer — the
34483
34552
  * documented workaround for firmwares that reject `.` in overlay text.
34484
34553
  */
34485
34554
  maxDecimals: number().int().min(0).max(4).default(1),
34486
- /**
34487
- * Appended via `${unit}` when no unit conversion produces a label.
34488
- * Prefer `source.displayUnit` for converted device-state values.
34489
- */
34490
- unitLabel: string().max(8).optional(),
34491
34555
  /** Raw value → display text, e.g. `{"true":"MOTION","false":""}`. */
34492
34556
  valueMap: record(string(), string()).optional(),
34493
34557
  /** Time windows in which the slot is shown. Absent = always. */
@@ -34496,9 +34560,7 @@ var OsdSlotBindingSchema = object({
34496
34560
  * Display gate, in the notification centre's condition vocabulary.
34497
34561
  * Only the keys reported by `getConditionSupport` are accepted.
34498
34562
  */
34499
- conditions: NcConditionsSchema.optional(),
34500
- /** Rendered when the gate is closed or the value unreadable. Empty = hide. */
34501
- fallbackText: string().max(64).default("")
34563
+ conditions: NcConditionsSchema.optional()
34502
34564
  });
34503
34565
  /** One camera slot, as the operator sees it: firmware truth + our binding. */
34504
34566
  var OsdSlotViewSchema = object({
@@ -52938,12 +53000,14 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
52938
53000
  {
52939
53001
  id: "addons",
52940
53002
  family: "system",
52941
- label: "Addons",
52942
- kinds: [
52943
- "addon-crash-loop",
52944
- "addon-update-available",
52945
- "addon-updated"
52946
- ]
53003
+ label: "Addons stopped",
53004
+ kinds: ["addon-crash-loop"]
53005
+ },
53006
+ {
53007
+ id: "addon-updates",
53008
+ family: "system",
53009
+ label: "Addon updates",
53010
+ kinds: ["addon-update-available", "addon-updated"]
52947
53011
  },
52948
53012
  {
52949
53013
  id: "updates",
@@ -53103,13 +53167,15 @@ var STATE_SUMMARY_SECTION_VARS = [
53103
53167
  },
53104
53168
  {
53105
53169
  name: "summaryAddons",
53106
- label: "Summary: addons",
53107
- example: "@camstack/addon-recorder 1.2.3 → 1.2.4",
53108
- kinds: [
53109
- "addon-crash-loop",
53110
- "addon-update-available",
53111
- "addon-updated"
53112
- ]
53170
+ label: "Summary: addons stopped",
53171
+ example: "hub — recorder stopped after repeated crashes",
53172
+ kinds: ["addon-crash-loop"]
53173
+ },
53174
+ {
53175
+ name: "summaryAddonUpdates",
53176
+ label: "Summary: addon updates",
53177
+ example: "hub:\n• @camstack/addon-recorder 1.2.3 → 1.2.4",
53178
+ kinds: ["addon-update-available", "addon-updated"]
53113
53179
  },
53114
53180
  {
53115
53181
  name: "summaryUpdates",
@@ -53193,6 +53259,7 @@ var STATE_SUMMARY_VARS = [
53193
53259
  [...RULE_BODY_ONLY],
53194
53260
  [...RULE_TEXT],
53195
53261
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
53262
+ ([...RULE_TEXT], [...COMBINED_ALARM]),
53196
53263
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
53197
53264
  ([...RULE_TEXT], [...BATTERY, ...CONSUMABLE]),
53198
53265
  ([...RULE_TEXT], [...CONSUMABLE]),
@@ -53233,6 +53300,8 @@ var STATE_SUMMARY_VARS = [
53233
53300
  [...RULE_TEXT],
53234
53301
  [...RULE_TEXT],
53235
53302
  [...RULE_TEXT],
53303
+ [...RULE_TEXT],
53304
+ [...RULE_TEXT],
53236
53305
  ...STATE_SUMMARY_VARS
53237
53306
  ];
53238
53307
  new Set([
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  //#endregion
6
- const require_dist = require("../dist-M6hP_tw3.js");
6
+ const require_dist = require("../dist-l71G4EIk.js");
7
7
  let node_crypto = require("node:crypto");
8
8
  //#region src/ha-export/topics.ts
9
9
  /**
@@ -1,4 +1,4 @@
1
- import { $ as oauthIntegrationCapability, C as buildAddonRouteProvider, Ft as EventCategory, I as deviceExportCapability, St as nodePin, a as COCO_TO_MACRO, bt as BaseAddon, c as FanDirectionSchema, i as CAMERA_SWITCH_ORDER, jt as string, l as HvacModeSchema, o as CameraSwitchIdSchema, p as addonRoutesCapability, t as AlarmArmModeSchema, u as MediaPlayerRepeatSchema } from "../dist-BgTykMb6.mjs";
1
+ import { $ as oauthIntegrationCapability, C as buildAddonRouteProvider, Ft as EventCategory, I as deviceExportCapability, St as nodePin, a as COCO_TO_MACRO, bt as BaseAddon, c as FanDirectionSchema, i as CAMERA_SWITCH_ORDER, jt as string, l as HvacModeSchema, o as CameraSwitchIdSchema, p as addonRoutesCapability, t as AlarmArmModeSchema, u as MediaPlayerRepeatSchema } from "../dist-H458ct4y.mjs";
2
2
  import { createHmac, timingSafeEqual } from "node:crypto";
3
3
  //#region src/ha-export/topics.ts
4
4
  /**
package/dist/index.js CHANGED
@@ -13,6 +13,5 @@ exports.HaWsClient = require_addon.HaWsClient;
13
13
  exports.authToSettings = require_addon.authToSettings;
14
14
  exports.buildHaAuth = require_addon.buildHaAuth;
15
15
  exports.processEvent = require_addon.processEvent;
16
- exports.resolveAuthConfig = require_addon.resolveAuthConfig;
17
16
  exports.settingsToAuth = require_addon.settingsToAuth;
18
17
  exports.subscribeEntities = require_addon.subscribeEntities;
package/dist/index.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { HaProviderAddon, a as HaIntegrationManager, c as HaWsClient, d as HaAuthConfigSchema, f as HaDomain, i as settingsToAuth, l as buildHaAuth, n as HaBrokerRegistry, o as processEvent, p as HaEntityStateSchema, r as authToSettings, s as subscribeEntities, t as HaBrokerEntrySchema, u as resolveAuthConfig } from "./addon.mjs";
1
+ import { HaProviderAddon, a as HaIntegrationManager, c as HaWsClient, d as HaDomain, f as HaEntityStateSchema, i as settingsToAuth, l as buildHaAuth, n as HaBrokerRegistry, o as processEvent, r as authToSettings, s as subscribeEntities, t as HaBrokerEntrySchema, u as HaAuthConfigSchema } from "./addon.mjs";
2
2
  import { HaExportAddon } from "./ha-export/ha-export.addon.mjs";
3
- export { HaAuthConfigSchema, HaBrokerEntrySchema, HaBrokerRegistry, HaDomain, HaEntityStateSchema, HaExportAddon, HaIntegrationManager, HaProviderAddon, HaWsClient, authToSettings, buildHaAuth, processEvent, resolveAuthConfig, settingsToAuth, subscribeEntities };
3
+ export { HaAuthConfigSchema, HaBrokerEntrySchema, HaBrokerRegistry, HaDomain, HaEntityStateSchema, HaExportAddon, HaIntegrationManager, HaProviderAddon, HaWsClient, authToSettings, buildHaAuth, processEvent, settingsToAuth, subscribeEntities };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-homeassistant",
3
- "version": "1.2.158",
3
+ "version": "1.2.160",
4
4
  "description": "Home Assistant device provider addon for CamStack",
5
5
  "keywords": [
6
6
  "camstack",