@camstack/addon-provider-hikvision 1.2.140 → 1.2.142

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 +130 -83
  2. package/dist/addon.mjs +130 -83
  3. package/package.json +1 -1
package/dist/addon.js CHANGED
@@ -10871,11 +10871,11 @@ var ModelVariantGroupSchema = object({
10871
10871
  /** Quantization axis. Omit ⇒ the fp32 base build. */
10872
10872
  precision: _enum(["fp32", "int8"]).optional(),
10873
10873
  /**
10874
- * Speed-optimization axis. Omit ⇒ the standard build. `fast` marks a
10875
- * latency-optimized export (e.g. ReLU-activation variant) — the slot the
10876
- * future performance variants plug into.
10874
+ * Training / latency-variant axis. Omit ⇒ the standard build. `test` marks
10875
+ * an alternate training of the same family (Scrypted `relu_test`); chip
10876
+ * label is "Test".
10877
10877
  */
10878
- optimization: _enum(["standard", "fast"]).optional(),
10878
+ optimization: _enum(["standard", "test"]).optional(),
10879
10879
  /**
10880
10880
  * Input-resolution axis (square input side, px). Omit ⇒ the family's native
10881
10881
  * resolution (640 for yolo26). Reduced-input builds (320 / 256) are a big,
@@ -10898,9 +10898,10 @@ var ModelProviderIdSchema = _enum([
10898
10898
  * are per upstream. A persisted custom-model row written when this field was a
10899
10899
  * string still parses — the string is lifted into `{ weights }`.
10900
10900
  *
10901
- * Every licence surface (the admin "Models and licenses" page,
10902
- * `THIRD_PARTY_MODELS.md`, the Hugging Face model table) is GENERATED from
10903
- * these records by `scripts/gen-model-licenses.ts` (D661).
10901
+ * Every machine licence surface (`THIRD_PARTY_MODELS.md`, the Hugging Face
10902
+ * model table) is GENERATED from these records by
10903
+ * `scripts/gen-model-licenses.ts` (D661). Operator-facing docs live in
10904
+ * `camstack/docs` → `/docs/detection/models`.
10904
10905
  */
10905
10906
  var ModelLicenseSchema = preprocess((value) => typeof value === "string" ? { weights: value } : value, object({
10906
10907
  /** SPDX id of the WEIGHTS' terms, a `LicenseRef-*` for non-SPDX terms, or `UNKNOWN`. */
@@ -14531,7 +14532,7 @@ DeviceType.Camera;
14531
14532
  * This matters here more than anywhere else in the repo, because every provider
14532
14533
  * that knows a device's host knows its PASSWORD too: `{ host, port, username,
14533
14534
  * password }` sit in one object on Hikvision, Amcrest, Reolink and ONVIF alike,
14534
- * 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
14535
14536
  * camera's own page will ask for its own login. That is correct, and pre-
14536
14537
  * filling it is the operator's business, not ours.
14537
14538
  *
@@ -17835,7 +17836,7 @@ method(object({
17835
17836
  timeoutMs: 6e5
17836
17837
  });
17837
17838
  method(object({
17838
- nodeId: string(),
17839
+ targetNodeId: string(),
17839
17840
  modelId: string(),
17840
17841
  format: _enum(MODEL_FORMATS),
17841
17842
  entry: ModelCatalogEntrySchema
@@ -20339,8 +20340,9 @@ var NcRuleSchema = NcRuleInputSchema.extend({
20339
20340
  disabledTargetIds: array(string()).default([])
20340
20341
  });
20341
20342
  /**
20342
- * The state-summary SECTIONS (D647 / D698): the D637 kind groups that report a
20343
- * still-true state. `backups-exports` and `alarm` are not sections — a completed
20343
+ * The state-summary SECTIONS (D647 / D698 / D708): the D637 kind groups that
20344
+ * report a still-true state. `addons` is the crash-looped addons only and
20345
+ * `addon-updates` the addons that are behind (D708 split them). `backups-exports` and `alarm` are not sections — a completed
20344
20346
  * job is not an open state, and the alarm stays instant.
20345
20347
  */
20346
20348
  var NcStateSummarySectionIdSchema = _enum([
@@ -20352,6 +20354,7 @@ var NcStateSummarySectionIdSchema = _enum([
20352
20354
  "detection-blind",
20353
20355
  "nodes",
20354
20356
  "addons",
20357
+ "addon-updates",
20355
20358
  "updates"
20356
20359
  ]);
20357
20360
  /** One section of a previewed state summary. `unavailable` = its state could not be read. */
@@ -20832,7 +20835,19 @@ var NcAlarmModeDelaysListSchema = array(object({
20832
20835
  * When this mode may be armed. Absent / null = always allowed (same as a
20833
20836
  * rule with no `schedule`). Evaluated with {@link isScheduleActive}.
20834
20837
  */
20835
- schedule: NcScheduleSchema.optional()
20838
+ schedule: NcScheduleSchema.optional(),
20839
+ /**
20840
+ * D706: while this mode's ENTRY DELAY runs, do the alarm rules' own pushes go out (as an
20841
+ * intrusion naming the locations)? Absent = false — the entry-delay notification is the
20842
+ * only one, and the matches ride the triggered notification's mosaic (D705).
20843
+ */
20844
+ notifyDuringEntryDelay: boolean().optional(),
20845
+ /**
20846
+ * D706: notify "watched again" when a sensor this arm bypassed closes and opens again.
20847
+ * Absent = false (logged, not sent). Even when true it is not sent when that same sensor
20848
+ * is the one that starts the entry delay — the entry-delay notification already names it.
20849
+ */
20850
+ notifySensorRewatched: boolean().optional()
20836
20851
  })).max(8).refine(uniqueModes, { message: "modeDelays: at most one entry per arm mode" });
20837
20852
  var NcAlarmModeDelaysEditListSchema = array(object({
20838
20853
  mode: AlarmArmModeSchema,
@@ -20841,7 +20856,11 @@ var NcAlarmModeDelaysEditListSchema = array(object({
20841
20856
  triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional(),
20842
20857
  postTriggeredAction: NcAlarmPostTriggeredActionSchema.nullable().optional(),
20843
20858
  /** Set a schedule, or `null` to clear (mode always allowed again). */
20844
- schedule: NcScheduleSchema.nullable().optional()
20859
+ schedule: NcScheduleSchema.nullable().optional(),
20860
+ /** D706: set the switch, or `null` to clear it (back to the default, false). */
20861
+ notifyDuringEntryDelay: boolean().nullable().optional(),
20862
+ /** D706: set the switch, or `null` to clear it (back to the default, false). */
20863
+ notifySensorRewatched: boolean().nullable().optional()
20845
20864
  })).max(8).refine(uniqueModes, { message: "modeDelays: at most one edit per arm mode" });
20846
20865
  /** One switch of the alarm table: put ONE device on, or take it off, ONE mode's list. */
20847
20866
  var NcAlarmNonBlockingEditSchema = object({
@@ -21802,39 +21821,19 @@ Object.freeze(Object.fromEntries([{
21802
21821
  label: "Face recognition model",
21803
21822
  defaultModelId: "auraface-r100",
21804
21823
  indexName: "the enrolled face gallery",
21805
- options: [
21806
- {
21807
- id: "auraface-r100",
21808
- label: "AuraFace R100"
21809
- },
21810
- {
21811
- id: "arcface-r100",
21812
- label: "ArcFace (ResNet34)"
21813
- },
21814
- {
21815
- id: "inception-resnet-v1",
21816
- label: "Inception ResNet V1"
21817
- }
21818
- ]
21824
+ options: [{
21825
+ id: "auraface-r100",
21826
+ label: "AuraFace R100"
21827
+ }]
21819
21828
  }, {
21820
21829
  stepId: "clip-embedding",
21821
21830
  label: "Semantic search model",
21822
- defaultModelId: "mobileclip-s1",
21831
+ defaultModelId: "siglip2-b16-224",
21823
21832
  indexName: "the object semantic-search index",
21824
- options: [
21825
- {
21826
- id: "mobileclip-s1",
21827
- label: "MobileCLIP S1"
21828
- },
21829
- {
21830
- id: "mobileclip-s2",
21831
- label: "MobileCLIP S2"
21832
- },
21833
- {
21834
- id: "siglip2-b16-224",
21835
- label: "SigLIP2 B/16 (Apache-2.0)"
21836
- }
21837
- ]
21833
+ options: [{
21834
+ id: "siglip2-b16-224",
21835
+ label: "SigLIP2 B/16 (Apache-2.0)"
21836
+ }]
21838
21837
  }].map((s) => [s.stepId, s.defaultModelId])));
21839
21838
  var CLUSTER_STEP_SETTING_FIELDS = [{
21840
21839
  stepId: "face-embedding",
@@ -24722,6 +24721,22 @@ var MotionSourceEnum = _enum([
24722
24721
  "device-activity"
24723
24722
  ]);
24724
24723
  /**
24724
+ * What opened an on-motion detection SESSION: the motion source that passed the
24725
+ * camera's `motionSources` gate, and what raised it (the camera itself, or a
24726
+ * sensor the operator attached — D672). `sensorName` is the attached sensor's
24727
+ * device name as the orchestrator's camera-sensors resolution last read it;
24728
+ * absent when unknown or when the camera itself triggered.
24729
+ *
24730
+ * Carried on the session attach ONLY so the runner's `DetectionPhaseTransition`
24731
+ * can say what started the session (D672 rule 11, amended 2026-10-06). The
24732
+ * runner never decides anything on it.
24733
+ */
24734
+ var SessionTriggerSchema = object({
24735
+ source: MotionSourceEnum,
24736
+ triggeredBy: MotionTriggeredBySchema,
24737
+ sensorName: string().optional()
24738
+ });
24739
+ /**
24725
24740
  * List of motion sources active on a camera. Empty array is valid:
24726
24741
  * "no source" — happens for battery cams without firmware motion when
24727
24742
  * the operator hasn't opted into the SW analyzer (would hold the
@@ -24973,6 +24988,14 @@ var RunnerCameraConfigSchema = object({
24973
24988
  */
24974
24989
  motionSources: MotionSourcesSchema.default(["analyzer"]),
24975
24990
  /**
24991
+ * What opened this attach, on a SESSION attach only (see
24992
+ * {@link SessionTriggerSchema}). OPTIONAL with no default: absent on a
24993
+ * standing attach, an occupancy burst, a re-dispatch with no motion event
24994
+ * behind it, and every attach from an orchestrator older than the field — the
24995
+ * runner then names no source on the phase event.
24996
+ */
24997
+ sessionTrigger: SessionTriggerSchema.optional(),
24998
+ /**
24976
24999
  * WHICH root detector runs for this camera. The detection counterpart of
24977
25000
  * {@link motionSources}, same shape and same discipline: a per-camera list
24978
25001
  * of sources the system understands, vendor-agnostic, owned here.
@@ -32883,7 +32906,7 @@ var LocalInterfaceSchema = object({
32883
32906
  name: string(),
32884
32907
  family: _enum(["IPv4", "IPv6"]),
32885
32908
  address: string(),
32886
- /** CIDR shorthand (e.g. `192.168.x.x/24`). Empty when OS doesn't expose. */
32909
+ /** CIDR shorthand (e.g. `192.168.10.10/24`). Empty when OS doesn't expose. */
32887
32910
  cidr: string(),
32888
32911
  /** OS netmask. Stable across calls so the SDK can hash on it. */
32889
32912
  netmask: string(),
@@ -32937,7 +32960,8 @@ var ConnectionEndpointSchema = object({
32937
32960
  "lan-ipv4",
32938
32961
  "lan-ipv6",
32939
32962
  "public",
32940
- "loopback"
32963
+ "loopback",
32964
+ "app-link"
32941
32965
  ]),
32942
32966
  /**
32943
32967
  * Originating-interface kind — `lan`/`wifi`/`docker`/`vpn`/`other`/
@@ -33006,15 +33030,27 @@ var GetConnectionEndpointsResultSchema = object({
33006
33030
  localPort: AdvertisedLocalPortSchema
33007
33031
  });
33008
33032
  /**
33009
- * The chosen outbound endpoint for notification artifacts. `baseUrl: null` =
33010
- * AUTO (resolved from the candidate ranking at send time); `resolved` reports
33011
- * what AUTO currently picks, so the UI can show the effective value either way.
33033
+ * The address flagged for notification links. `baseUrl: null` = AUTO, which
33034
+ * since D709 is the CamStack app link; `resolved` reports the effective value,
33035
+ * so the UI can show it either way.
33012
33036
  */
33013
33037
  var NotificationEndpointSchema = object({
33014
33038
  /** The operator's explicit choice, or null for AUTO. */
33015
33039
  baseUrl: string().nullable(),
33016
- /** What the ranking currently resolves to (null when nothing is reachable). */
33017
- resolved: string().nullable()
33040
+ /**
33041
+ * The effective flagged address: the explicit choice, else (AUTO) the
33042
+ * CamStack app link `https://camstack.zentik.app` (D709). A pre-D709 hub
33043
+ * answered the public tunnel / mesh here, or null.
33044
+ */
33045
+ resolved: string().nullable(),
33046
+ /**
33047
+ * The hub origin an app link carries as `hub=` (D709): the hub's best
33048
+ * public HTTPS address — the tunnel, then the mesh (Tailscale MagicDNS) —
33049
+ * picked from this cap's own palette by `pickAppLinkHub`. `null` when the
33050
+ * hub advertises neither; the app link is then minted without `hub=`.
33051
+ * Absent on a pre-D709 hub.
33052
+ */
33053
+ appLinkHub: string().nullable()
33018
33054
  });
33019
33055
  /**
33020
33056
  * The URLs the SDK / viewer should race for API access. `baseUrls` empty =
@@ -33068,7 +33104,11 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
33068
33104
  * Pass `'https'` when the caller is itself loaded over HTTPS
33069
33105
  * to avoid mixed-content blocks in the browser. The public
33070
33106
  * tunnel always emits `https://` regardless. */
33071
- scheme: _enum(["http", "https"]).optional()
33107
+ scheme: _enum(["http", "https"]).optional(),
33108
+ /** Append the CamStack app link entry (`kind: 'app-link'`, D709) —
33109
+ * an address notification links can be flagged with, not a hub
33110
+ * route. Default `false`: racers and rankers never see it. */
33111
+ includeAppLink: boolean().optional()
33072
33112
  }), 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, {
33073
33113
  kind: "mutation",
33074
33114
  auth: "admin"
@@ -33397,7 +33437,7 @@ var MeshPeerSchema = object({
33397
33437
  tags: array(string()).readonly(),
33398
33438
  /** True when the peer advertises itself as an exit-node candidate. */
33399
33439
  exitNodeOption: boolean(),
33400
- /** Subnet routes the peer advertises (e.g. `["192.168.x.x/24"]`). */
33440
+ /** Subnet routes the peer advertises (e.g. `["192.168.10.0/24"]`). */
33401
33441
  advertisedRoutes: array(string()).readonly(),
33402
33442
  /** Owner account login (e.g. `foo@example.com`). Null for tagged peers. */
33403
33443
  userLogin: string().nullable(),
@@ -34725,7 +34765,13 @@ var OsdStatusSchema = object({ overlays: array(object({
34725
34765
  */
34726
34766
  availablePositions: array(OsdPositionEnum).readonly(),
34727
34767
  /** Firmware does not allow editing the `text` field (e.g. timestamp). */
34728
- readOnly: boolean().optional()
34768
+ readOnly: boolean().optional(),
34769
+ /**
34770
+ * Firmware text ceiling for this overlay. Absent = no known limit.
34771
+ * The OSD manager truncates here on every write — never stores its own
34772
+ * copy on the binding.
34773
+ */
34774
+ maxCharacters: number().int().positive().optional()
34729
34775
  })).readonly() });
34730
34776
  var OsdOverlayPatchSchema = object({
34731
34777
  enabled: boolean().optional(),
@@ -34822,7 +34868,9 @@ var OsdTemplateBindingSchema = object({
34822
34868
  valuePath: string().min(1).max(64),
34823
34869
  /** Convert TO this unit at render (`tryConvertUnit`). Absent = source unit. */
34824
34870
  displayUnit: string().max(16).optional(),
34825
- maxDecimals: number().int().min(0).max(4).default(1)
34871
+ maxDecimals: number().int().min(0).max(4).default(1),
34872
+ /** Raw value → display text (same shape as slot binding). Empty string hides. */
34873
+ valueMap: record(string(), string()).optional()
34826
34874
  });
34827
34875
  /**
34828
34876
  * A named template: bindings (alias → leaf field) + a parser that
@@ -34872,18 +34920,11 @@ var OsdSlotBindingSchema = object({
34872
34920
  source: OsdSourceSchema,
34873
34921
  /** `${value}` and `${unit}` are substituted; every occurrence. */
34874
34922
  template: string().max(96).default("${value}"),
34875
- /** Truncate with an ellipsis past this length. Absent = no limit. */
34876
- maxCharacters: number().int().min(4).max(64).optional(),
34877
34923
  /**
34878
34924
  * Decimal places for a numeric value. `0` yields an integer — the
34879
34925
  * documented workaround for firmwares that reject `.` in overlay text.
34880
34926
  */
34881
34927
  maxDecimals: number().int().min(0).max(4).default(1),
34882
- /**
34883
- * Appended via `${unit}` when no unit conversion produces a label.
34884
- * Prefer `source.displayUnit` for converted device-state values.
34885
- */
34886
- unitLabel: string().max(8).optional(),
34887
34928
  /** Raw value → display text, e.g. `{"true":"MOTION","false":""}`. */
34888
34929
  valueMap: record(string(), string()).optional(),
34889
34930
  /** Time windows in which the slot is shown. Absent = always. */
@@ -34892,9 +34933,7 @@ var OsdSlotBindingSchema = object({
34892
34933
  * Display gate, in the notification centre's condition vocabulary.
34893
34934
  * Only the keys reported by `getConditionSupport` are accepted.
34894
34935
  */
34895
- conditions: NcConditionsSchema.optional(),
34896
- /** Rendered when the gate is closed or the value unreadable. Empty = hide. */
34897
- fallbackText: string().max(64).default("")
34936
+ conditions: NcConditionsSchema.optional()
34898
34937
  });
34899
34938
  /** One camera slot, as the operator sees it: firmware truth + our binding. */
34900
34939
  var OsdSlotViewSchema = object({
@@ -53875,12 +53914,14 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
53875
53914
  {
53876
53915
  id: "addons",
53877
53916
  family: "system",
53878
- label: "Addons",
53879
- kinds: [
53880
- "addon-crash-loop",
53881
- "addon-update-available",
53882
- "addon-updated"
53883
- ]
53917
+ label: "Addons stopped",
53918
+ kinds: ["addon-crash-loop"]
53919
+ },
53920
+ {
53921
+ id: "addon-updates",
53922
+ family: "system",
53923
+ label: "Addon updates",
53924
+ kinds: ["addon-update-available", "addon-updated"]
53884
53925
  },
53885
53926
  {
53886
53927
  id: "updates",
@@ -54040,13 +54081,15 @@ var STATE_SUMMARY_SECTION_VARS = [
54040
54081
  },
54041
54082
  {
54042
54083
  name: "summaryAddons",
54043
- label: "Summary: addons",
54044
- example: "@camstack/addon-recorder 1.2.3 → 1.2.4",
54045
- kinds: [
54046
- "addon-crash-loop",
54047
- "addon-update-available",
54048
- "addon-updated"
54049
- ]
54084
+ label: "Summary: addons stopped",
54085
+ example: "hub — recorder stopped after repeated crashes",
54086
+ kinds: ["addon-crash-loop"]
54087
+ },
54088
+ {
54089
+ name: "summaryAddonUpdates",
54090
+ label: "Summary: addon updates",
54091
+ example: "hub:\n• @camstack/addon-recorder 1.2.3 → 1.2.4",
54092
+ kinds: ["addon-update-available", "addon-updated"]
54050
54093
  },
54051
54094
  {
54052
54095
  name: "summaryUpdates",
@@ -54130,6 +54173,7 @@ var STATE_SUMMARY_VARS = [
54130
54173
  [...RULE_BODY_ONLY],
54131
54174
  [...RULE_TEXT],
54132
54175
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
54176
+ ([...RULE_TEXT], [...COMBINED_ALARM]),
54133
54177
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
54134
54178
  ([...RULE_TEXT], [...BATTERY, ...CONSUMABLE]),
54135
54179
  ([...RULE_TEXT], [...CONSUMABLE]),
@@ -54170,6 +54214,8 @@ var STATE_SUMMARY_VARS = [
54170
54214
  [...RULE_TEXT],
54171
54215
  [...RULE_TEXT],
54172
54216
  [...RULE_TEXT],
54217
+ [...RULE_TEXT],
54218
+ [...RULE_TEXT],
54173
54219
  ...STATE_SUMMARY_VARS
54174
54220
  ];
54175
54221
  new Set([
@@ -64780,7 +64826,8 @@ var HikvisionCamera = class HikvisionCamera extends BaseDevice {
64780
64826
  kind: "text",
64781
64827
  enabled: t.enabled,
64782
64828
  text: t.text ?? "",
64783
- availablePositions: []
64829
+ availablePositions: [],
64830
+ maxCharacters: 44
64784
64831
  });
64785
64832
  return { overlays };
64786
64833
  },
@@ -66874,7 +66921,7 @@ var HikvisionCamera = class HikvisionCamera extends BaseDevice {
66874
66921
  key: "host",
66875
66922
  label: "Camera IP",
66876
66923
  required: true,
66877
- placeholder: "192.168.x.x"
66924
+ placeholder: "192.168.10.100"
66878
66925
  },
66879
66926
  {
66880
66927
  type: "number",
@@ -76923,13 +76970,13 @@ function enumerateHosts(cidr) {
76923
76970
  for (let d = 1; d <= 254; d += 1) out.push(`${a}.${b}.${c}.${d}`);
76924
76971
  return out;
76925
76972
  }
76926
- /** Best-effort local /24 from the first non-internal IPv4 interface (e.g. `192.168.x.x/24`). */
76973
+ /** Best-effort local /24 from the first non-internal IPv4 interface (e.g. `192.168.10.0/24`). */
76927
76974
  function detectLocalCidr() {
76928
76975
  for (const addrs of Object.values((0, node_os.networkInterfaces)())) for (const addr of addrs ?? []) if (addr.family === "IPv4" && !addr.internal) {
76929
76976
  const [a, b, c] = addr.address.split(".");
76930
76977
  return `${a}.${b}.${c}.0/24`;
76931
76978
  }
76932
- return "192.168.x.x/24";
76979
+ return "192.168.10.0/24";
76933
76980
  }
76934
76981
  /** Flatten a host into a flat row-key slug — must match `generateStableId`'s host fallback so a
76935
76982
  * re-scan of a host-added camera is detected as already onboarded. */
@@ -76999,7 +77046,7 @@ function buildCreationFormSchema() {
76999
77046
  key: "host",
77000
77047
  label: "Camera IP",
77001
77048
  required: true,
77002
- placeholder: "192.168.x.x",
77049
+ placeholder: "192.168.10.100",
77003
77050
  inputType: "text"
77004
77051
  },
77005
77052
  {
@@ -77049,14 +77096,14 @@ function buildDiscoveryParamsFormSchema() {
77049
77096
  }, {
77050
77097
  id: "scan",
77051
77098
  title: "Scan options",
77052
- description: "The credentialed ISAPI subnet scan is the reliable path (multicast WS-Discovery is not received on a macvlan/br0 hub). IMPORTANT: leaving the network blank scans only the HUB’s own subnet — if your cameras are on a DIFFERENT subnet than the hub, you MUST enter their CIDR here (e.g. 192.168.x.x/24), otherwise the scan returns nothing.",
77099
+ description: "The credentialed ISAPI subnet scan is the reliable path (multicast WS-Discovery is not received on a macvlan/br0 hub). IMPORTANT: leaving the network blank scans only the HUB’s own subnet — if your cameras are on a DIFFERENT subnet than the hub, you MUST enter their CIDR here (e.g. 192.168.60.0/24), otherwise the scan returns nothing.",
77053
77100
  columns: 1,
77054
77101
  fields: [{
77055
77102
  type: "text",
77056
77103
  key: "networkCidr",
77057
77104
  label: "Network (CIDR) — required if cameras are on a different subnet than the hub",
77058
77105
  required: false,
77059
- placeholder: "192.168.x.x/24"
77106
+ placeholder: "192.168.60.0/24"
77060
77107
  }, {
77061
77108
  type: "number",
77062
77109
  key: "timeoutMs",
package/dist/addon.mjs CHANGED
@@ -10850,11 +10850,11 @@ var ModelVariantGroupSchema = object({
10850
10850
  /** Quantization axis. Omit ⇒ the fp32 base build. */
10851
10851
  precision: _enum(["fp32", "int8"]).optional(),
10852
10852
  /**
10853
- * Speed-optimization axis. Omit ⇒ the standard build. `fast` marks a
10854
- * latency-optimized export (e.g. ReLU-activation variant) — the slot the
10855
- * future performance variants plug into.
10853
+ * Training / latency-variant axis. Omit ⇒ the standard build. `test` marks
10854
+ * an alternate training of the same family (Scrypted `relu_test`); chip
10855
+ * label is "Test".
10856
10856
  */
10857
- optimization: _enum(["standard", "fast"]).optional(),
10857
+ optimization: _enum(["standard", "test"]).optional(),
10858
10858
  /**
10859
10859
  * Input-resolution axis (square input side, px). Omit ⇒ the family's native
10860
10860
  * resolution (640 for yolo26). Reduced-input builds (320 / 256) are a big,
@@ -10877,9 +10877,10 @@ var ModelProviderIdSchema = _enum([
10877
10877
  * are per upstream. A persisted custom-model row written when this field was a
10878
10878
  * string still parses — the string is lifted into `{ weights }`.
10879
10879
  *
10880
- * Every licence surface (the admin "Models and licenses" page,
10881
- * `THIRD_PARTY_MODELS.md`, the Hugging Face model table) is GENERATED from
10882
- * these records by `scripts/gen-model-licenses.ts` (D661).
10880
+ * Every machine licence surface (`THIRD_PARTY_MODELS.md`, the Hugging Face
10881
+ * model table) is GENERATED from these records by
10882
+ * `scripts/gen-model-licenses.ts` (D661). Operator-facing docs live in
10883
+ * `camstack/docs` → `/docs/detection/models`.
10883
10884
  */
10884
10885
  var ModelLicenseSchema = preprocess((value) => typeof value === "string" ? { weights: value } : value, object({
10885
10886
  /** SPDX id of the WEIGHTS' terms, a `LicenseRef-*` for non-SPDX terms, or `UNKNOWN`. */
@@ -14510,7 +14511,7 @@ DeviceType.Camera;
14510
14511
  * This matters here more than anywhere else in the repo, because every provider
14511
14512
  * that knows a device's host knows its PASSWORD too: `{ host, port, username,
14512
14513
  * password }` sit in one object on Hikvision, Amcrest, Reolink and ONVIF alike,
14513
- * and `http://admin:hunter2@192.168.x.x/` is a URL a browser accepts. The
14514
+ * and `http://admin:hunter2@192.168.60.139/` is a URL a browser accepts. The
14514
14515
  * camera's own page will ask for its own login. That is correct, and pre-
14515
14516
  * filling it is the operator's business, not ours.
14516
14517
  *
@@ -17814,7 +17815,7 @@ method(object({
17814
17815
  timeoutMs: 6e5
17815
17816
  });
17816
17817
  method(object({
17817
- nodeId: string(),
17818
+ targetNodeId: string(),
17818
17819
  modelId: string(),
17819
17820
  format: _enum(MODEL_FORMATS),
17820
17821
  entry: ModelCatalogEntrySchema
@@ -20318,8 +20319,9 @@ var NcRuleSchema = NcRuleInputSchema.extend({
20318
20319
  disabledTargetIds: array(string()).default([])
20319
20320
  });
20320
20321
  /**
20321
- * The state-summary SECTIONS (D647 / D698): the D637 kind groups that report a
20322
- * still-true state. `backups-exports` and `alarm` are not sections — a completed
20322
+ * The state-summary SECTIONS (D647 / D698 / D708): the D637 kind groups that
20323
+ * report a still-true state. `addons` is the crash-looped addons only and
20324
+ * `addon-updates` the addons that are behind (D708 split them). `backups-exports` and `alarm` are not sections — a completed
20323
20325
  * job is not an open state, and the alarm stays instant.
20324
20326
  */
20325
20327
  var NcStateSummarySectionIdSchema = _enum([
@@ -20331,6 +20333,7 @@ var NcStateSummarySectionIdSchema = _enum([
20331
20333
  "detection-blind",
20332
20334
  "nodes",
20333
20335
  "addons",
20336
+ "addon-updates",
20334
20337
  "updates"
20335
20338
  ]);
20336
20339
  /** One section of a previewed state summary. `unavailable` = its state could not be read. */
@@ -20811,7 +20814,19 @@ var NcAlarmModeDelaysListSchema = array(object({
20811
20814
  * When this mode may be armed. Absent / null = always allowed (same as a
20812
20815
  * rule with no `schedule`). Evaluated with {@link isScheduleActive}.
20813
20816
  */
20814
- schedule: NcScheduleSchema.optional()
20817
+ schedule: NcScheduleSchema.optional(),
20818
+ /**
20819
+ * D706: while this mode's ENTRY DELAY runs, do the alarm rules' own pushes go out (as an
20820
+ * intrusion naming the locations)? Absent = false — the entry-delay notification is the
20821
+ * only one, and the matches ride the triggered notification's mosaic (D705).
20822
+ */
20823
+ notifyDuringEntryDelay: boolean().optional(),
20824
+ /**
20825
+ * D706: notify "watched again" when a sensor this arm bypassed closes and opens again.
20826
+ * Absent = false (logged, not sent). Even when true it is not sent when that same sensor
20827
+ * is the one that starts the entry delay — the entry-delay notification already names it.
20828
+ */
20829
+ notifySensorRewatched: boolean().optional()
20815
20830
  })).max(8).refine(uniqueModes, { message: "modeDelays: at most one entry per arm mode" });
20816
20831
  var NcAlarmModeDelaysEditListSchema = array(object({
20817
20832
  mode: AlarmArmModeSchema,
@@ -20820,7 +20835,11 @@ var NcAlarmModeDelaysEditListSchema = array(object({
20820
20835
  triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional(),
20821
20836
  postTriggeredAction: NcAlarmPostTriggeredActionSchema.nullable().optional(),
20822
20837
  /** Set a schedule, or `null` to clear (mode always allowed again). */
20823
- schedule: NcScheduleSchema.nullable().optional()
20838
+ schedule: NcScheduleSchema.nullable().optional(),
20839
+ /** D706: set the switch, or `null` to clear it (back to the default, false). */
20840
+ notifyDuringEntryDelay: boolean().nullable().optional(),
20841
+ /** D706: set the switch, or `null` to clear it (back to the default, false). */
20842
+ notifySensorRewatched: boolean().nullable().optional()
20824
20843
  })).max(8).refine(uniqueModes, { message: "modeDelays: at most one edit per arm mode" });
20825
20844
  /** One switch of the alarm table: put ONE device on, or take it off, ONE mode's list. */
20826
20845
  var NcAlarmNonBlockingEditSchema = object({
@@ -21781,39 +21800,19 @@ Object.freeze(Object.fromEntries([{
21781
21800
  label: "Face recognition model",
21782
21801
  defaultModelId: "auraface-r100",
21783
21802
  indexName: "the enrolled face gallery",
21784
- options: [
21785
- {
21786
- id: "auraface-r100",
21787
- label: "AuraFace R100"
21788
- },
21789
- {
21790
- id: "arcface-r100",
21791
- label: "ArcFace (ResNet34)"
21792
- },
21793
- {
21794
- id: "inception-resnet-v1",
21795
- label: "Inception ResNet V1"
21796
- }
21797
- ]
21803
+ options: [{
21804
+ id: "auraface-r100",
21805
+ label: "AuraFace R100"
21806
+ }]
21798
21807
  }, {
21799
21808
  stepId: "clip-embedding",
21800
21809
  label: "Semantic search model",
21801
- defaultModelId: "mobileclip-s1",
21810
+ defaultModelId: "siglip2-b16-224",
21802
21811
  indexName: "the object semantic-search index",
21803
- options: [
21804
- {
21805
- id: "mobileclip-s1",
21806
- label: "MobileCLIP S1"
21807
- },
21808
- {
21809
- id: "mobileclip-s2",
21810
- label: "MobileCLIP S2"
21811
- },
21812
- {
21813
- id: "siglip2-b16-224",
21814
- label: "SigLIP2 B/16 (Apache-2.0)"
21815
- }
21816
- ]
21812
+ options: [{
21813
+ id: "siglip2-b16-224",
21814
+ label: "SigLIP2 B/16 (Apache-2.0)"
21815
+ }]
21817
21816
  }].map((s) => [s.stepId, s.defaultModelId])));
21818
21817
  var CLUSTER_STEP_SETTING_FIELDS = [{
21819
21818
  stepId: "face-embedding",
@@ -24701,6 +24700,22 @@ var MotionSourceEnum = _enum([
24701
24700
  "device-activity"
24702
24701
  ]);
24703
24702
  /**
24703
+ * What opened an on-motion detection SESSION: the motion source that passed the
24704
+ * camera's `motionSources` gate, and what raised it (the camera itself, or a
24705
+ * sensor the operator attached — D672). `sensorName` is the attached sensor's
24706
+ * device name as the orchestrator's camera-sensors resolution last read it;
24707
+ * absent when unknown or when the camera itself triggered.
24708
+ *
24709
+ * Carried on the session attach ONLY so the runner's `DetectionPhaseTransition`
24710
+ * can say what started the session (D672 rule 11, amended 2026-10-06). The
24711
+ * runner never decides anything on it.
24712
+ */
24713
+ var SessionTriggerSchema = object({
24714
+ source: MotionSourceEnum,
24715
+ triggeredBy: MotionTriggeredBySchema,
24716
+ sensorName: string().optional()
24717
+ });
24718
+ /**
24704
24719
  * List of motion sources active on a camera. Empty array is valid:
24705
24720
  * "no source" — happens for battery cams without firmware motion when
24706
24721
  * the operator hasn't opted into the SW analyzer (would hold the
@@ -24952,6 +24967,14 @@ var RunnerCameraConfigSchema = object({
24952
24967
  */
24953
24968
  motionSources: MotionSourcesSchema.default(["analyzer"]),
24954
24969
  /**
24970
+ * What opened this attach, on a SESSION attach only (see
24971
+ * {@link SessionTriggerSchema}). OPTIONAL with no default: absent on a
24972
+ * standing attach, an occupancy burst, a re-dispatch with no motion event
24973
+ * behind it, and every attach from an orchestrator older than the field — the
24974
+ * runner then names no source on the phase event.
24975
+ */
24976
+ sessionTrigger: SessionTriggerSchema.optional(),
24977
+ /**
24955
24978
  * WHICH root detector runs for this camera. The detection counterpart of
24956
24979
  * {@link motionSources}, same shape and same discipline: a per-camera list
24957
24980
  * of sources the system understands, vendor-agnostic, owned here.
@@ -32862,7 +32885,7 @@ var LocalInterfaceSchema = object({
32862
32885
  name: string(),
32863
32886
  family: _enum(["IPv4", "IPv6"]),
32864
32887
  address: string(),
32865
- /** CIDR shorthand (e.g. `192.168.x.x/24`). Empty when OS doesn't expose. */
32888
+ /** CIDR shorthand (e.g. `192.168.10.10/24`). Empty when OS doesn't expose. */
32866
32889
  cidr: string(),
32867
32890
  /** OS netmask. Stable across calls so the SDK can hash on it. */
32868
32891
  netmask: string(),
@@ -32916,7 +32939,8 @@ var ConnectionEndpointSchema = object({
32916
32939
  "lan-ipv4",
32917
32940
  "lan-ipv6",
32918
32941
  "public",
32919
- "loopback"
32942
+ "loopback",
32943
+ "app-link"
32920
32944
  ]),
32921
32945
  /**
32922
32946
  * Originating-interface kind — `lan`/`wifi`/`docker`/`vpn`/`other`/
@@ -32985,15 +33009,27 @@ var GetConnectionEndpointsResultSchema = object({
32985
33009
  localPort: AdvertisedLocalPortSchema
32986
33010
  });
32987
33011
  /**
32988
- * The chosen outbound endpoint for notification artifacts. `baseUrl: null` =
32989
- * AUTO (resolved from the candidate ranking at send time); `resolved` reports
32990
- * what AUTO currently picks, so the UI can show the effective value either way.
33012
+ * The address flagged for notification links. `baseUrl: null` = AUTO, which
33013
+ * since D709 is the CamStack app link; `resolved` reports the effective value,
33014
+ * so the UI can show it either way.
32991
33015
  */
32992
33016
  var NotificationEndpointSchema = object({
32993
33017
  /** The operator's explicit choice, or null for AUTO. */
32994
33018
  baseUrl: string().nullable(),
32995
- /** What the ranking currently resolves to (null when nothing is reachable). */
32996
- resolved: string().nullable()
33019
+ /**
33020
+ * The effective flagged address: the explicit choice, else (AUTO) the
33021
+ * CamStack app link `https://camstack.zentik.app` (D709). A pre-D709 hub
33022
+ * answered the public tunnel / mesh here, or null.
33023
+ */
33024
+ resolved: string().nullable(),
33025
+ /**
33026
+ * The hub origin an app link carries as `hub=` (D709): the hub's best
33027
+ * public HTTPS address — the tunnel, then the mesh (Tailscale MagicDNS) —
33028
+ * picked from this cap's own palette by `pickAppLinkHub`. `null` when the
33029
+ * hub advertises neither; the app link is then minted without `hub=`.
33030
+ * Absent on a pre-D709 hub.
33031
+ */
33032
+ appLinkHub: string().nullable()
32997
33033
  });
32998
33034
  /**
32999
33035
  * The URLs the SDK / viewer should race for API access. `baseUrls` empty =
@@ -33047,7 +33083,11 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
33047
33083
  * Pass `'https'` when the caller is itself loaded over HTTPS
33048
33084
  * to avoid mixed-content blocks in the browser. The public
33049
33085
  * tunnel always emits `https://` regardless. */
33050
- scheme: _enum(["http", "https"]).optional()
33086
+ scheme: _enum(["http", "https"]).optional(),
33087
+ /** Append the CamStack app link entry (`kind: 'app-link'`, D709) —
33088
+ * an address notification links can be flagged with, not a hub
33089
+ * route. Default `false`: racers and rankers never see it. */
33090
+ includeAppLink: boolean().optional()
33051
33091
  }), 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, {
33052
33092
  kind: "mutation",
33053
33093
  auth: "admin"
@@ -33376,7 +33416,7 @@ var MeshPeerSchema = object({
33376
33416
  tags: array(string()).readonly(),
33377
33417
  /** True when the peer advertises itself as an exit-node candidate. */
33378
33418
  exitNodeOption: boolean(),
33379
- /** Subnet routes the peer advertises (e.g. `["192.168.x.x/24"]`). */
33419
+ /** Subnet routes the peer advertises (e.g. `["192.168.10.0/24"]`). */
33380
33420
  advertisedRoutes: array(string()).readonly(),
33381
33421
  /** Owner account login (e.g. `foo@example.com`). Null for tagged peers. */
33382
33422
  userLogin: string().nullable(),
@@ -34704,7 +34744,13 @@ var OsdStatusSchema = object({ overlays: array(object({
34704
34744
  */
34705
34745
  availablePositions: array(OsdPositionEnum).readonly(),
34706
34746
  /** Firmware does not allow editing the `text` field (e.g. timestamp). */
34707
- readOnly: boolean().optional()
34747
+ readOnly: boolean().optional(),
34748
+ /**
34749
+ * Firmware text ceiling for this overlay. Absent = no known limit.
34750
+ * The OSD manager truncates here on every write — never stores its own
34751
+ * copy on the binding.
34752
+ */
34753
+ maxCharacters: number().int().positive().optional()
34708
34754
  })).readonly() });
34709
34755
  var OsdOverlayPatchSchema = object({
34710
34756
  enabled: boolean().optional(),
@@ -34801,7 +34847,9 @@ var OsdTemplateBindingSchema = object({
34801
34847
  valuePath: string().min(1).max(64),
34802
34848
  /** Convert TO this unit at render (`tryConvertUnit`). Absent = source unit. */
34803
34849
  displayUnit: string().max(16).optional(),
34804
- maxDecimals: number().int().min(0).max(4).default(1)
34850
+ maxDecimals: number().int().min(0).max(4).default(1),
34851
+ /** Raw value → display text (same shape as slot binding). Empty string hides. */
34852
+ valueMap: record(string(), string()).optional()
34805
34853
  });
34806
34854
  /**
34807
34855
  * A named template: bindings (alias → leaf field) + a parser that
@@ -34851,18 +34899,11 @@ var OsdSlotBindingSchema = object({
34851
34899
  source: OsdSourceSchema,
34852
34900
  /** `${value}` and `${unit}` are substituted; every occurrence. */
34853
34901
  template: string().max(96).default("${value}"),
34854
- /** Truncate with an ellipsis past this length. Absent = no limit. */
34855
- maxCharacters: number().int().min(4).max(64).optional(),
34856
34902
  /**
34857
34903
  * Decimal places for a numeric value. `0` yields an integer — the
34858
34904
  * documented workaround for firmwares that reject `.` in overlay text.
34859
34905
  */
34860
34906
  maxDecimals: number().int().min(0).max(4).default(1),
34861
- /**
34862
- * Appended via `${unit}` when no unit conversion produces a label.
34863
- * Prefer `source.displayUnit` for converted device-state values.
34864
- */
34865
- unitLabel: string().max(8).optional(),
34866
34907
  /** Raw value → display text, e.g. `{"true":"MOTION","false":""}`. */
34867
34908
  valueMap: record(string(), string()).optional(),
34868
34909
  /** Time windows in which the slot is shown. Absent = always. */
@@ -34871,9 +34912,7 @@ var OsdSlotBindingSchema = object({
34871
34912
  * Display gate, in the notification centre's condition vocabulary.
34872
34913
  * Only the keys reported by `getConditionSupport` are accepted.
34873
34914
  */
34874
- conditions: NcConditionsSchema.optional(),
34875
- /** Rendered when the gate is closed or the value unreadable. Empty = hide. */
34876
- fallbackText: string().max(64).default("")
34915
+ conditions: NcConditionsSchema.optional()
34877
34916
  });
34878
34917
  /** One camera slot, as the operator sees it: firmware truth + our binding. */
34879
34918
  var OsdSlotViewSchema = object({
@@ -53854,12 +53893,14 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
53854
53893
  {
53855
53894
  id: "addons",
53856
53895
  family: "system",
53857
- label: "Addons",
53858
- kinds: [
53859
- "addon-crash-loop",
53860
- "addon-update-available",
53861
- "addon-updated"
53862
- ]
53896
+ label: "Addons stopped",
53897
+ kinds: ["addon-crash-loop"]
53898
+ },
53899
+ {
53900
+ id: "addon-updates",
53901
+ family: "system",
53902
+ label: "Addon updates",
53903
+ kinds: ["addon-update-available", "addon-updated"]
53863
53904
  },
53864
53905
  {
53865
53906
  id: "updates",
@@ -54019,13 +54060,15 @@ var STATE_SUMMARY_SECTION_VARS = [
54019
54060
  },
54020
54061
  {
54021
54062
  name: "summaryAddons",
54022
- label: "Summary: addons",
54023
- example: "@camstack/addon-recorder 1.2.3 → 1.2.4",
54024
- kinds: [
54025
- "addon-crash-loop",
54026
- "addon-update-available",
54027
- "addon-updated"
54028
- ]
54063
+ label: "Summary: addons stopped",
54064
+ example: "hub — recorder stopped after repeated crashes",
54065
+ kinds: ["addon-crash-loop"]
54066
+ },
54067
+ {
54068
+ name: "summaryAddonUpdates",
54069
+ label: "Summary: addon updates",
54070
+ example: "hub:\n• @camstack/addon-recorder 1.2.3 → 1.2.4",
54071
+ kinds: ["addon-update-available", "addon-updated"]
54029
54072
  },
54030
54073
  {
54031
54074
  name: "summaryUpdates",
@@ -54109,6 +54152,7 @@ var STATE_SUMMARY_VARS = [
54109
54152
  [...RULE_BODY_ONLY],
54110
54153
  [...RULE_TEXT],
54111
54154
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
54155
+ ([...RULE_TEXT], [...COMBINED_ALARM]),
54112
54156
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
54113
54157
  ([...RULE_TEXT], [...BATTERY, ...CONSUMABLE]),
54114
54158
  ([...RULE_TEXT], [...CONSUMABLE]),
@@ -54149,6 +54193,8 @@ var STATE_SUMMARY_VARS = [
54149
54193
  [...RULE_TEXT],
54150
54194
  [...RULE_TEXT],
54151
54195
  [...RULE_TEXT],
54196
+ [...RULE_TEXT],
54197
+ [...RULE_TEXT],
54152
54198
  ...STATE_SUMMARY_VARS
54153
54199
  ];
54154
54200
  new Set([
@@ -64759,7 +64805,8 @@ var HikvisionCamera = class HikvisionCamera extends BaseDevice {
64759
64805
  kind: "text",
64760
64806
  enabled: t.enabled,
64761
64807
  text: t.text ?? "",
64762
- availablePositions: []
64808
+ availablePositions: [],
64809
+ maxCharacters: 44
64763
64810
  });
64764
64811
  return { overlays };
64765
64812
  },
@@ -66853,7 +66900,7 @@ var HikvisionCamera = class HikvisionCamera extends BaseDevice {
66853
66900
  key: "host",
66854
66901
  label: "Camera IP",
66855
66902
  required: true,
66856
- placeholder: "192.168.x.x"
66903
+ placeholder: "192.168.10.100"
66857
66904
  },
66858
66905
  {
66859
66906
  type: "number",
@@ -76902,13 +76949,13 @@ function enumerateHosts(cidr) {
76902
76949
  for (let d = 1; d <= 254; d += 1) out.push(`${a}.${b}.${c}.${d}`);
76903
76950
  return out;
76904
76951
  }
76905
- /** Best-effort local /24 from the first non-internal IPv4 interface (e.g. `192.168.x.x/24`). */
76952
+ /** Best-effort local /24 from the first non-internal IPv4 interface (e.g. `192.168.10.0/24`). */
76906
76953
  function detectLocalCidr() {
76907
76954
  for (const addrs of Object.values(networkInterfaces())) for (const addr of addrs ?? []) if (addr.family === "IPv4" && !addr.internal) {
76908
76955
  const [a, b, c] = addr.address.split(".");
76909
76956
  return `${a}.${b}.${c}.0/24`;
76910
76957
  }
76911
- return "192.168.x.x/24";
76958
+ return "192.168.10.0/24";
76912
76959
  }
76913
76960
  /** Flatten a host into a flat row-key slug — must match `generateStableId`'s host fallback so a
76914
76961
  * re-scan of a host-added camera is detected as already onboarded. */
@@ -76978,7 +77025,7 @@ function buildCreationFormSchema() {
76978
77025
  key: "host",
76979
77026
  label: "Camera IP",
76980
77027
  required: true,
76981
- placeholder: "192.168.x.x",
77028
+ placeholder: "192.168.10.100",
76982
77029
  inputType: "text"
76983
77030
  },
76984
77031
  {
@@ -77028,14 +77075,14 @@ function buildDiscoveryParamsFormSchema() {
77028
77075
  }, {
77029
77076
  id: "scan",
77030
77077
  title: "Scan options",
77031
- description: "The credentialed ISAPI subnet scan is the reliable path (multicast WS-Discovery is not received on a macvlan/br0 hub). IMPORTANT: leaving the network blank scans only the HUB’s own subnet — if your cameras are on a DIFFERENT subnet than the hub, you MUST enter their CIDR here (e.g. 192.168.x.x/24), otherwise the scan returns nothing.",
77078
+ description: "The credentialed ISAPI subnet scan is the reliable path (multicast WS-Discovery is not received on a macvlan/br0 hub). IMPORTANT: leaving the network blank scans only the HUB’s own subnet — if your cameras are on a DIFFERENT subnet than the hub, you MUST enter their CIDR here (e.g. 192.168.60.0/24), otherwise the scan returns nothing.",
77032
77079
  columns: 1,
77033
77080
  fields: [{
77034
77081
  type: "text",
77035
77082
  key: "networkCidr",
77036
77083
  label: "Network (CIDR) — required if cameras are on a different subnet than the hub",
77037
77084
  required: false,
77038
- placeholder: "192.168.x.x/24"
77085
+ placeholder: "192.168.60.0/24"
77039
77086
  }, {
77040
77087
  type: "number",
77041
77088
  key: "timeoutMs",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-hikvision",
3
- "version": "1.2.140",
3
+ "version": "1.2.142",
4
4
  "description": "Hikvision camera device provider addon for CamStack — ISAPI over HTTP(S) with digest auth (snapshot, alarm stream, RTSP discovery)",
5
5
  "keywords": [
6
6
  "camstack",