@camstack/addon-provider-hikvision 1.2.136 → 1.2.137

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
@@ -15166,7 +15166,17 @@ var SiteZoneSchema = object({
15166
15166
  var ProviderStatusSchema = object({
15167
15167
  connected: boolean(),
15168
15168
  deviceCount: number(),
15169
- error: string().optional()
15169
+ error: string().optional(),
15170
+ /**
15171
+ * `'orchestrator'`: this provider writes NO camera's `motion` runtime slice
15172
+ * — the orchestrator is its only writer (D696). Set by `BaseDeviceProvider`,
15173
+ * which every provider bundles, so only a provider BUILT from D696-amended
15174
+ * code says it. ABSENT means an older provider that may still write it (raw
15175
+ * VMD writes, a boot seed), and the orchestrator's provider gate keeps that
15176
+ * provider's cameras unwritten (`camera-sensors/motion-slice-provider-gate.ts`)
15177
+ * — the provider twin of the runner's `getLocalLoad().motionSliceWriter`.
15178
+ */
15179
+ motionSliceWriter: literal("orchestrator").optional()
15170
15180
  });
15171
15181
  object({
15172
15182
  externalId: string(),
@@ -20647,6 +20657,29 @@ object({
20647
20657
  firstAt: number(),
20648
20658
  lastAt: number()
20649
20659
  });
20660
+ var NC_ALARM_TRIGGERED_MAX_SEC = 3600;
20661
+ var NcAlarmDelaySecSchema = number().int().min(0).max(600);
20662
+ var NcAlarmTriggeredSecSchema = number().int().min(0).max(NC_ALARM_TRIGGERED_MAX_SEC);
20663
+ var uniqueModes = (entries) => new Set(entries.map((e) => e.mode)).size === entries.length;
20664
+ var NcAlarmModeDelaysListSchema = array(object({
20665
+ mode: AlarmArmModeSchema,
20666
+ exitDelaySec: NcAlarmDelaySecSchema.optional(),
20667
+ entryDelaySec: NcAlarmDelaySecSchema.optional(),
20668
+ triggeredDurationSec: NcAlarmTriggeredSecSchema.optional()
20669
+ })).max(8).refine(uniqueModes, { message: "modeDelays: at most one entry per arm mode" });
20670
+ var NcAlarmModeDelaysEditListSchema = array(object({
20671
+ mode: AlarmArmModeSchema,
20672
+ exitDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
20673
+ entryDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
20674
+ triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional()
20675
+ })).max(8).refine(uniqueModes, { message: "modeDelays: at most one edit per arm mode" });
20676
+ /** One switch of the alarm table: put ONE device on, or take it off, ONE mode's list. */
20677
+ var NcAlarmNonBlockingEditSchema = object({
20678
+ mode: AlarmArmModeSchema,
20679
+ deviceId: number().int().positive(),
20680
+ /** true = on the list (may be open, does not block); false = off the list (blocks). */
20681
+ nonBlocking: boolean()
20682
+ });
20650
20683
  /**
20651
20684
  * The per-mode lists, at most one per mode. Two lists for one mode have no
20652
20685
  * meaning a reader could agree on (union? the last one?), so they are refused
@@ -20655,10 +20688,10 @@ object({
20655
20688
  var NcAlarmNonBlockingListSchema = array(object({
20656
20689
  mode: AlarmArmModeSchema,
20657
20690
  deviceIds: array(number().int()).max(200)
20658
- })).max(8).refine((lists) => new Set(lists.map((l) => l.mode)).size === lists.length, { message: "nonBlocking: at most one list per arm mode" });
20691
+ })).max(8).refine(uniqueModes, { message: "nonBlocking: at most one list per arm mode" });
20659
20692
  /**
20660
- * The three durations the panel's state machine runs on, who hears about its
20661
- * transitions, and which openings each mode tolerates.
20693
+ * The three durations — global, and per mode since D697 — the panel's state
20694
+ * machine runs on, who hears about its transitions, and which openings each mode tolerates.
20662
20695
  *
20663
20696
  * They live on the NOTIFICATION-RULES cap, not on `alarm-panel`, on purpose:
20664
20697
  * `alarm-panel` is `deviceNative` and its other provider mirrors somebody
@@ -20668,15 +20701,15 @@ var NcAlarmNonBlockingListSchema = array(object({
20668
20701
  */
20669
20702
  var NcAlarmSettingsSchema = object({
20670
20703
  /** Grace period between arming and the mode taking effect. 0 = immediate. */
20671
- exitDelaySec: number().int().min(0).max(600),
20704
+ exitDelaySec: NcAlarmDelaySecSchema,
20672
20705
  /** Grace period between a trigger and the alarm firing. 0 = immediate. */
20673
- entryDelaySec: number().int().min(0).max(600),
20706
+ entryDelaySec: NcAlarmDelaySecSchema,
20674
20707
  /**
20675
20708
  * How long `triggered` lasts before the panel re-arms itself.
20676
20709
  * **0 = until an operator disarms it** — the behaviour before this field
20677
20710
  * existed, and therefore what an untouched install keeps doing.
20678
20711
  */
20679
- triggeredDurationSec: number().int().min(0).max(3600),
20712
+ triggeredDurationSec: NcAlarmTriggeredSecSchema,
20680
20713
  /**
20681
20714
  * Deprecated by D630 — every transition is announced. Parsed, never read;
20682
20715
  * remove after one release. Optional so an older admin's patch (which still
@@ -20699,17 +20732,30 @@ var NcAlarmSettingsSchema = object({
20699
20732
  * per mode is meaningful. Defaulted to `[]` so a blob stored before D630
20700
20733
  * parses as "every opening blocks" — the behaviour it was written under.
20701
20734
  */
20702
- nonBlocking: NcAlarmNonBlockingListSchema.default([])
20735
+ nonBlocking: NcAlarmNonBlockingListSchema.default([]),
20736
+ /**
20737
+ * Per arm mode, the delays that mode OVERRIDES (D697). A mode with no entry, or an entry
20738
+ * without a field, uses the global value above — so `[]`, the default, is exactly the
20739
+ * behaviour of a blob stored before this field existed. Read through `resolveModeDelays`.
20740
+ */
20741
+ modeDelays: NcAlarmModeDelaysListSchema.default([])
20703
20742
  });
20704
20743
  /**
20705
20744
  * Every field optional — a tab edits one control at a time.
20706
20745
  *
20707
- * `nonBlocking` is re-declared WITHOUT its default: `.partial()` does not
20708
- * remove an inner `.default()`, so a patch that never named the field would
20709
- * parse to `nonBlocking: []` and wipe every mode's list on an unrelated edit
20710
- * (the same trap {@link NcRulePatchSchema} documents).
20746
+ * `nonBlocking` and `modeDelays` are re-declared WITHOUT their defaults:
20747
+ * `.partial()` does not remove an inner `.default()`, so a patch that never
20748
+ * named the field would parse to `[]` and wipe every mode's list on an
20749
+ * unrelated edit (the same trap {@link NcRulePatchSchema} documents). Here
20750
+ * `modeDelays` means EDITS, not the stored overrides.
20711
20751
  */
20712
- var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({ nonBlocking: NcAlarmNonBlockingListSchema }).partial();
20752
+ var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({
20753
+ nonBlocking: NcAlarmNonBlockingListSchema,
20754
+ /** Per-mode, per-field edits — NOT the whole list (see NcAlarmModeDelaysEditSchema). */
20755
+ modeDelays: NcAlarmModeDelaysEditListSchema,
20756
+ /** ONE membership change; the panel applies it to the list it holds at its turn. */
20757
+ nonBlockingEdit: NcAlarmNonBlockingEditSchema
20758
+ }).partial().refine((p) => p.nonBlocking === void 0 || p.nonBlockingEdit === void 0, { message: "nonBlocking and nonBlockingEdit are exclusive — send the whole lists or one edit" });
20713
20759
  /**
20714
20760
  * What one arm mode actually arms, DERIVED from the enabled rules gated on it.
20715
20761
  * Never authored, never stored — see `alarm-mode-coverage.ts` for why a stored
@@ -20809,6 +20855,28 @@ var NcAlarmConfigSchema = object({
20809
20855
  */
20810
20856
  live: NcAlarmLiveSchema.optional()
20811
20857
  });
20858
+ var NcAlarmSensorReadingSchema = _enum([
20859
+ "open",
20860
+ "closed",
20861
+ "unknown",
20862
+ "not-opening"
20863
+ ]);
20864
+ /** One device's state as the alarm reads it — the classifier the arm check uses. */
20865
+ var NcAlarmSensorStateSchema = object({
20866
+ deviceId: number().int().positive(),
20867
+ reading: NcAlarmSensorReadingSchema,
20868
+ /** The word as read (`open`, `closed`, `unlocked`, `stopped`, …); null when unknown / not an opening. */
20869
+ state: string().nullable(),
20870
+ /** Why `unknown`: the read failed, or the slice holds no word its cap defines (a placeholder included). */
20871
+ unknownWhy: _enum(["read-failed", "unknown-word"]).nullable(),
20872
+ /** The device manager's liveness as the centre mirrors it; null = not known. */
20873
+ online: boolean().nullable()
20874
+ });
20875
+ var NcAlarmSensorsInputSchema = object({ deviceIds: array(number().int().positive()).max(500) });
20876
+ var NcAlarmSensorsSchema = object({
20877
+ sensors: array(NcAlarmSensorStateSchema),
20878
+ readAt: number().int().nonnegative()
20879
+ });
20812
20880
  /**
20813
20881
  * ONE rule's demand on ONE camera's clip ring.
20814
20882
  *
@@ -20899,7 +20967,7 @@ method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), m
20899
20967
  }), method(object({}), NcAlarmConfigSchema, { auth: "admin" }), method(object({ patch: NcAlarmSettingsPatchSchema }), NcAlarmConfigSchema, {
20900
20968
  kind: "mutation",
20901
20969
  auth: "admin"
20902
- });
20970
+ }), method(NcAlarmSensorsInputSchema, NcAlarmSensorsSchema, { auth: "admin" });
20903
20971
  /**
20904
20972
  * Zod schemas for persisted record types.
20905
20973
  *
@@ -41222,13 +41290,14 @@ var BaseDeviceProvider = class extends BaseAddon {
41222
41290
  async getStatus() {
41223
41291
  const all = await this.ctx.kernel.devices?.getAll() ?? [];
41224
41292
  const summary = this.restoreFailureSummary();
41225
- if (summary === null) return {
41293
+ const base = {
41226
41294
  connected: true,
41227
- deviceCount: all.length
41295
+ deviceCount: all.length,
41296
+ motionSliceWriter: "orchestrator"
41228
41297
  };
41298
+ if (summary === null) return base;
41229
41299
  return {
41230
- connected: true,
41231
- deviceCount: all.length,
41300
+ ...base,
41232
41301
  error: summary
41233
41302
  };
41234
41303
  }
@@ -46882,6 +46951,12 @@ Object.freeze({
46882
46951
  addonId: null,
46883
46952
  access: "view"
46884
46953
  },
46954
+ "notificationRules.getAlarmSensors": {
46955
+ capName: "notification-rules",
46956
+ capScope: "system",
46957
+ addonId: null,
46958
+ access: "view"
46959
+ },
46885
46960
  "notificationRules.getClipRetentionAsks": {
46886
46961
  capName: "notification-rules",
46887
46962
  capScope: "system",
@@ -51365,6 +51440,11 @@ Object.freeze({
51365
51440
  form: "single",
51366
51441
  optional: false
51367
51442
  }],
51443
+ "notificationRules.getAlarmSensors": [{
51444
+ name: "deviceIds",
51445
+ form: "array",
51446
+ optional: false
51447
+ }],
51368
51448
  "notificationRules.setDeviceMuted": [{
51369
51449
  name: "deviceId",
51370
51450
  form: "single",
package/dist/addon.mjs CHANGED
@@ -15145,7 +15145,17 @@ var SiteZoneSchema = object({
15145
15145
  var ProviderStatusSchema = object({
15146
15146
  connected: boolean(),
15147
15147
  deviceCount: number(),
15148
- error: string().optional()
15148
+ error: string().optional(),
15149
+ /**
15150
+ * `'orchestrator'`: this provider writes NO camera's `motion` runtime slice
15151
+ * — the orchestrator is its only writer (D696). Set by `BaseDeviceProvider`,
15152
+ * which every provider bundles, so only a provider BUILT from D696-amended
15153
+ * code says it. ABSENT means an older provider that may still write it (raw
15154
+ * VMD writes, a boot seed), and the orchestrator's provider gate keeps that
15155
+ * provider's cameras unwritten (`camera-sensors/motion-slice-provider-gate.ts`)
15156
+ * — the provider twin of the runner's `getLocalLoad().motionSliceWriter`.
15157
+ */
15158
+ motionSliceWriter: literal("orchestrator").optional()
15149
15159
  });
15150
15160
  object({
15151
15161
  externalId: string(),
@@ -20626,6 +20636,29 @@ object({
20626
20636
  firstAt: number(),
20627
20637
  lastAt: number()
20628
20638
  });
20639
+ var NC_ALARM_TRIGGERED_MAX_SEC = 3600;
20640
+ var NcAlarmDelaySecSchema = number().int().min(0).max(600);
20641
+ var NcAlarmTriggeredSecSchema = number().int().min(0).max(NC_ALARM_TRIGGERED_MAX_SEC);
20642
+ var uniqueModes = (entries) => new Set(entries.map((e) => e.mode)).size === entries.length;
20643
+ var NcAlarmModeDelaysListSchema = array(object({
20644
+ mode: AlarmArmModeSchema,
20645
+ exitDelaySec: NcAlarmDelaySecSchema.optional(),
20646
+ entryDelaySec: NcAlarmDelaySecSchema.optional(),
20647
+ triggeredDurationSec: NcAlarmTriggeredSecSchema.optional()
20648
+ })).max(8).refine(uniqueModes, { message: "modeDelays: at most one entry per arm mode" });
20649
+ var NcAlarmModeDelaysEditListSchema = array(object({
20650
+ mode: AlarmArmModeSchema,
20651
+ exitDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
20652
+ entryDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
20653
+ triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional()
20654
+ })).max(8).refine(uniqueModes, { message: "modeDelays: at most one edit per arm mode" });
20655
+ /** One switch of the alarm table: put ONE device on, or take it off, ONE mode's list. */
20656
+ var NcAlarmNonBlockingEditSchema = object({
20657
+ mode: AlarmArmModeSchema,
20658
+ deviceId: number().int().positive(),
20659
+ /** true = on the list (may be open, does not block); false = off the list (blocks). */
20660
+ nonBlocking: boolean()
20661
+ });
20629
20662
  /**
20630
20663
  * The per-mode lists, at most one per mode. Two lists for one mode have no
20631
20664
  * meaning a reader could agree on (union? the last one?), so they are refused
@@ -20634,10 +20667,10 @@ object({
20634
20667
  var NcAlarmNonBlockingListSchema = array(object({
20635
20668
  mode: AlarmArmModeSchema,
20636
20669
  deviceIds: array(number().int()).max(200)
20637
- })).max(8).refine((lists) => new Set(lists.map((l) => l.mode)).size === lists.length, { message: "nonBlocking: at most one list per arm mode" });
20670
+ })).max(8).refine(uniqueModes, { message: "nonBlocking: at most one list per arm mode" });
20638
20671
  /**
20639
- * The three durations the panel's state machine runs on, who hears about its
20640
- * transitions, and which openings each mode tolerates.
20672
+ * The three durations — global, and per mode since D697 — the panel's state
20673
+ * machine runs on, who hears about its transitions, and which openings each mode tolerates.
20641
20674
  *
20642
20675
  * They live on the NOTIFICATION-RULES cap, not on `alarm-panel`, on purpose:
20643
20676
  * `alarm-panel` is `deviceNative` and its other provider mirrors somebody
@@ -20647,15 +20680,15 @@ var NcAlarmNonBlockingListSchema = array(object({
20647
20680
  */
20648
20681
  var NcAlarmSettingsSchema = object({
20649
20682
  /** Grace period between arming and the mode taking effect. 0 = immediate. */
20650
- exitDelaySec: number().int().min(0).max(600),
20683
+ exitDelaySec: NcAlarmDelaySecSchema,
20651
20684
  /** Grace period between a trigger and the alarm firing. 0 = immediate. */
20652
- entryDelaySec: number().int().min(0).max(600),
20685
+ entryDelaySec: NcAlarmDelaySecSchema,
20653
20686
  /**
20654
20687
  * How long `triggered` lasts before the panel re-arms itself.
20655
20688
  * **0 = until an operator disarms it** — the behaviour before this field
20656
20689
  * existed, and therefore what an untouched install keeps doing.
20657
20690
  */
20658
- triggeredDurationSec: number().int().min(0).max(3600),
20691
+ triggeredDurationSec: NcAlarmTriggeredSecSchema,
20659
20692
  /**
20660
20693
  * Deprecated by D630 — every transition is announced. Parsed, never read;
20661
20694
  * remove after one release. Optional so an older admin's patch (which still
@@ -20678,17 +20711,30 @@ var NcAlarmSettingsSchema = object({
20678
20711
  * per mode is meaningful. Defaulted to `[]` so a blob stored before D630
20679
20712
  * parses as "every opening blocks" — the behaviour it was written under.
20680
20713
  */
20681
- nonBlocking: NcAlarmNonBlockingListSchema.default([])
20714
+ nonBlocking: NcAlarmNonBlockingListSchema.default([]),
20715
+ /**
20716
+ * Per arm mode, the delays that mode OVERRIDES (D697). A mode with no entry, or an entry
20717
+ * without a field, uses the global value above — so `[]`, the default, is exactly the
20718
+ * behaviour of a blob stored before this field existed. Read through `resolveModeDelays`.
20719
+ */
20720
+ modeDelays: NcAlarmModeDelaysListSchema.default([])
20682
20721
  });
20683
20722
  /**
20684
20723
  * Every field optional — a tab edits one control at a time.
20685
20724
  *
20686
- * `nonBlocking` is re-declared WITHOUT its default: `.partial()` does not
20687
- * remove an inner `.default()`, so a patch that never named the field would
20688
- * parse to `nonBlocking: []` and wipe every mode's list on an unrelated edit
20689
- * (the same trap {@link NcRulePatchSchema} documents).
20725
+ * `nonBlocking` and `modeDelays` are re-declared WITHOUT their defaults:
20726
+ * `.partial()` does not remove an inner `.default()`, so a patch that never
20727
+ * named the field would parse to `[]` and wipe every mode's list on an
20728
+ * unrelated edit (the same trap {@link NcRulePatchSchema} documents). Here
20729
+ * `modeDelays` means EDITS, not the stored overrides.
20690
20730
  */
20691
- var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({ nonBlocking: NcAlarmNonBlockingListSchema }).partial();
20731
+ var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({
20732
+ nonBlocking: NcAlarmNonBlockingListSchema,
20733
+ /** Per-mode, per-field edits — NOT the whole list (see NcAlarmModeDelaysEditSchema). */
20734
+ modeDelays: NcAlarmModeDelaysEditListSchema,
20735
+ /** ONE membership change; the panel applies it to the list it holds at its turn. */
20736
+ nonBlockingEdit: NcAlarmNonBlockingEditSchema
20737
+ }).partial().refine((p) => p.nonBlocking === void 0 || p.nonBlockingEdit === void 0, { message: "nonBlocking and nonBlockingEdit are exclusive — send the whole lists or one edit" });
20692
20738
  /**
20693
20739
  * What one arm mode actually arms, DERIVED from the enabled rules gated on it.
20694
20740
  * Never authored, never stored — see `alarm-mode-coverage.ts` for why a stored
@@ -20788,6 +20834,28 @@ var NcAlarmConfigSchema = object({
20788
20834
  */
20789
20835
  live: NcAlarmLiveSchema.optional()
20790
20836
  });
20837
+ var NcAlarmSensorReadingSchema = _enum([
20838
+ "open",
20839
+ "closed",
20840
+ "unknown",
20841
+ "not-opening"
20842
+ ]);
20843
+ /** One device's state as the alarm reads it — the classifier the arm check uses. */
20844
+ var NcAlarmSensorStateSchema = object({
20845
+ deviceId: number().int().positive(),
20846
+ reading: NcAlarmSensorReadingSchema,
20847
+ /** The word as read (`open`, `closed`, `unlocked`, `stopped`, …); null when unknown / not an opening. */
20848
+ state: string().nullable(),
20849
+ /** Why `unknown`: the read failed, or the slice holds no word its cap defines (a placeholder included). */
20850
+ unknownWhy: _enum(["read-failed", "unknown-word"]).nullable(),
20851
+ /** The device manager's liveness as the centre mirrors it; null = not known. */
20852
+ online: boolean().nullable()
20853
+ });
20854
+ var NcAlarmSensorsInputSchema = object({ deviceIds: array(number().int().positive()).max(500) });
20855
+ var NcAlarmSensorsSchema = object({
20856
+ sensors: array(NcAlarmSensorStateSchema),
20857
+ readAt: number().int().nonnegative()
20858
+ });
20791
20859
  /**
20792
20860
  * ONE rule's demand on ONE camera's clip ring.
20793
20861
  *
@@ -20878,7 +20946,7 @@ method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), m
20878
20946
  }), method(object({}), NcAlarmConfigSchema, { auth: "admin" }), method(object({ patch: NcAlarmSettingsPatchSchema }), NcAlarmConfigSchema, {
20879
20947
  kind: "mutation",
20880
20948
  auth: "admin"
20881
- });
20949
+ }), method(NcAlarmSensorsInputSchema, NcAlarmSensorsSchema, { auth: "admin" });
20882
20950
  /**
20883
20951
  * Zod schemas for persisted record types.
20884
20952
  *
@@ -41201,13 +41269,14 @@ var BaseDeviceProvider = class extends BaseAddon {
41201
41269
  async getStatus() {
41202
41270
  const all = await this.ctx.kernel.devices?.getAll() ?? [];
41203
41271
  const summary = this.restoreFailureSummary();
41204
- if (summary === null) return {
41272
+ const base = {
41205
41273
  connected: true,
41206
- deviceCount: all.length
41274
+ deviceCount: all.length,
41275
+ motionSliceWriter: "orchestrator"
41207
41276
  };
41277
+ if (summary === null) return base;
41208
41278
  return {
41209
- connected: true,
41210
- deviceCount: all.length,
41279
+ ...base,
41211
41280
  error: summary
41212
41281
  };
41213
41282
  }
@@ -46861,6 +46930,12 @@ Object.freeze({
46861
46930
  addonId: null,
46862
46931
  access: "view"
46863
46932
  },
46933
+ "notificationRules.getAlarmSensors": {
46934
+ capName: "notification-rules",
46935
+ capScope: "system",
46936
+ addonId: null,
46937
+ access: "view"
46938
+ },
46864
46939
  "notificationRules.getClipRetentionAsks": {
46865
46940
  capName: "notification-rules",
46866
46941
  capScope: "system",
@@ -51344,6 +51419,11 @@ Object.freeze({
51344
51419
  form: "single",
51345
51420
  optional: false
51346
51421
  }],
51422
+ "notificationRules.getAlarmSensors": [{
51423
+ name: "deviceIds",
51424
+ form: "array",
51425
+ optional: false
51426
+ }],
51347
51427
  "notificationRules.setDeviceMuted": [{
51348
51428
  name: "deviceId",
51349
51429
  form: "single",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-hikvision",
3
- "version": "1.2.136",
3
+ "version": "1.2.137",
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",