@camstack/addon-provider-amcrest 0.2.125 → 0.2.126

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
@@ -14874,7 +14874,17 @@ var SiteZoneSchema = object({
14874
14874
  var ProviderStatusSchema = object({
14875
14875
  connected: boolean(),
14876
14876
  deviceCount: number(),
14877
- error: string().optional()
14877
+ error: string().optional(),
14878
+ /**
14879
+ * `'orchestrator'`: this provider writes NO camera's `motion` runtime slice
14880
+ * — the orchestrator is its only writer (D696). Set by `BaseDeviceProvider`,
14881
+ * which every provider bundles, so only a provider BUILT from D696-amended
14882
+ * code says it. ABSENT means an older provider that may still write it (raw
14883
+ * VMD writes, a boot seed), and the orchestrator's provider gate keeps that
14884
+ * provider's cameras unwritten (`camera-sensors/motion-slice-provider-gate.ts`)
14885
+ * — the provider twin of the runner's `getLocalLoad().motionSliceWriter`.
14886
+ */
14887
+ motionSliceWriter: literal("orchestrator").optional()
14878
14888
  });
14879
14889
  object({
14880
14890
  externalId: string(),
@@ -20336,6 +20346,29 @@ object({
20336
20346
  firstAt: number(),
20337
20347
  lastAt: number()
20338
20348
  });
20349
+ var NC_ALARM_TRIGGERED_MAX_SEC = 3600;
20350
+ var NcAlarmDelaySecSchema = number().int().min(0).max(600);
20351
+ var NcAlarmTriggeredSecSchema = number().int().min(0).max(NC_ALARM_TRIGGERED_MAX_SEC);
20352
+ var uniqueModes = (entries) => new Set(entries.map((e) => e.mode)).size === entries.length;
20353
+ var NcAlarmModeDelaysListSchema = array(object({
20354
+ mode: AlarmArmModeSchema,
20355
+ exitDelaySec: NcAlarmDelaySecSchema.optional(),
20356
+ entryDelaySec: NcAlarmDelaySecSchema.optional(),
20357
+ triggeredDurationSec: NcAlarmTriggeredSecSchema.optional()
20358
+ })).max(8).refine(uniqueModes, { message: "modeDelays: at most one entry per arm mode" });
20359
+ var NcAlarmModeDelaysEditListSchema = array(object({
20360
+ mode: AlarmArmModeSchema,
20361
+ exitDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
20362
+ entryDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
20363
+ triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional()
20364
+ })).max(8).refine(uniqueModes, { message: "modeDelays: at most one edit per arm mode" });
20365
+ /** One switch of the alarm table: put ONE device on, or take it off, ONE mode's list. */
20366
+ var NcAlarmNonBlockingEditSchema = object({
20367
+ mode: AlarmArmModeSchema,
20368
+ deviceId: number().int().positive(),
20369
+ /** true = on the list (may be open, does not block); false = off the list (blocks). */
20370
+ nonBlocking: boolean()
20371
+ });
20339
20372
  /**
20340
20373
  * The per-mode lists, at most one per mode. Two lists for one mode have no
20341
20374
  * meaning a reader could agree on (union? the last one?), so they are refused
@@ -20344,10 +20377,10 @@ object({
20344
20377
  var NcAlarmNonBlockingListSchema = array(object({
20345
20378
  mode: AlarmArmModeSchema,
20346
20379
  deviceIds: array(number().int()).max(200)
20347
- })).max(8).refine((lists) => new Set(lists.map((l) => l.mode)).size === lists.length, { message: "nonBlocking: at most one list per arm mode" });
20380
+ })).max(8).refine(uniqueModes, { message: "nonBlocking: at most one list per arm mode" });
20348
20381
  /**
20349
- * The three durations the panel's state machine runs on, who hears about its
20350
- * transitions, and which openings each mode tolerates.
20382
+ * The three durations — global, and per mode since D697 — the panel's state
20383
+ * machine runs on, who hears about its transitions, and which openings each mode tolerates.
20351
20384
  *
20352
20385
  * They live on the NOTIFICATION-RULES cap, not on `alarm-panel`, on purpose:
20353
20386
  * `alarm-panel` is `deviceNative` and its other provider mirrors somebody
@@ -20357,15 +20390,15 @@ var NcAlarmNonBlockingListSchema = array(object({
20357
20390
  */
20358
20391
  var NcAlarmSettingsSchema = object({
20359
20392
  /** Grace period between arming and the mode taking effect. 0 = immediate. */
20360
- exitDelaySec: number().int().min(0).max(600),
20393
+ exitDelaySec: NcAlarmDelaySecSchema,
20361
20394
  /** Grace period between a trigger and the alarm firing. 0 = immediate. */
20362
- entryDelaySec: number().int().min(0).max(600),
20395
+ entryDelaySec: NcAlarmDelaySecSchema,
20363
20396
  /**
20364
20397
  * How long `triggered` lasts before the panel re-arms itself.
20365
20398
  * **0 = until an operator disarms it** — the behaviour before this field
20366
20399
  * existed, and therefore what an untouched install keeps doing.
20367
20400
  */
20368
- triggeredDurationSec: number().int().min(0).max(3600),
20401
+ triggeredDurationSec: NcAlarmTriggeredSecSchema,
20369
20402
  /**
20370
20403
  * Deprecated by D630 — every transition is announced. Parsed, never read;
20371
20404
  * remove after one release. Optional so an older admin's patch (which still
@@ -20388,17 +20421,30 @@ var NcAlarmSettingsSchema = object({
20388
20421
  * per mode is meaningful. Defaulted to `[]` so a blob stored before D630
20389
20422
  * parses as "every opening blocks" — the behaviour it was written under.
20390
20423
  */
20391
- nonBlocking: NcAlarmNonBlockingListSchema.default([])
20424
+ nonBlocking: NcAlarmNonBlockingListSchema.default([]),
20425
+ /**
20426
+ * Per arm mode, the delays that mode OVERRIDES (D697). A mode with no entry, or an entry
20427
+ * without a field, uses the global value above — so `[]`, the default, is exactly the
20428
+ * behaviour of a blob stored before this field existed. Read through `resolveModeDelays`.
20429
+ */
20430
+ modeDelays: NcAlarmModeDelaysListSchema.default([])
20392
20431
  });
20393
20432
  /**
20394
20433
  * Every field optional — a tab edits one control at a time.
20395
20434
  *
20396
- * `nonBlocking` is re-declared WITHOUT its default: `.partial()` does not
20397
- * remove an inner `.default()`, so a patch that never named the field would
20398
- * parse to `nonBlocking: []` and wipe every mode's list on an unrelated edit
20399
- * (the same trap {@link NcRulePatchSchema} documents).
20435
+ * `nonBlocking` and `modeDelays` are re-declared WITHOUT their defaults:
20436
+ * `.partial()` does not remove an inner `.default()`, so a patch that never
20437
+ * named the field would parse to `[]` and wipe every mode's list on an
20438
+ * unrelated edit (the same trap {@link NcRulePatchSchema} documents). Here
20439
+ * `modeDelays` means EDITS, not the stored overrides.
20400
20440
  */
20401
- var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({ nonBlocking: NcAlarmNonBlockingListSchema }).partial();
20441
+ var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({
20442
+ nonBlocking: NcAlarmNonBlockingListSchema,
20443
+ /** Per-mode, per-field edits — NOT the whole list (see NcAlarmModeDelaysEditSchema). */
20444
+ modeDelays: NcAlarmModeDelaysEditListSchema,
20445
+ /** ONE membership change; the panel applies it to the list it holds at its turn. */
20446
+ nonBlockingEdit: NcAlarmNonBlockingEditSchema
20447
+ }).partial().refine((p) => p.nonBlocking === void 0 || p.nonBlockingEdit === void 0, { message: "nonBlocking and nonBlockingEdit are exclusive — send the whole lists or one edit" });
20402
20448
  /**
20403
20449
  * What one arm mode actually arms, DERIVED from the enabled rules gated on it.
20404
20450
  * Never authored, never stored — see `alarm-mode-coverage.ts` for why a stored
@@ -20498,6 +20544,28 @@ var NcAlarmConfigSchema = object({
20498
20544
  */
20499
20545
  live: NcAlarmLiveSchema.optional()
20500
20546
  });
20547
+ var NcAlarmSensorReadingSchema = _enum([
20548
+ "open",
20549
+ "closed",
20550
+ "unknown",
20551
+ "not-opening"
20552
+ ]);
20553
+ /** One device's state as the alarm reads it — the classifier the arm check uses. */
20554
+ var NcAlarmSensorStateSchema = object({
20555
+ deviceId: number().int().positive(),
20556
+ reading: NcAlarmSensorReadingSchema,
20557
+ /** The word as read (`open`, `closed`, `unlocked`, `stopped`, …); null when unknown / not an opening. */
20558
+ state: string().nullable(),
20559
+ /** Why `unknown`: the read failed, or the slice holds no word its cap defines (a placeholder included). */
20560
+ unknownWhy: _enum(["read-failed", "unknown-word"]).nullable(),
20561
+ /** The device manager's liveness as the centre mirrors it; null = not known. */
20562
+ online: boolean().nullable()
20563
+ });
20564
+ var NcAlarmSensorsInputSchema = object({ deviceIds: array(number().int().positive()).max(500) });
20565
+ var NcAlarmSensorsSchema = object({
20566
+ sensors: array(NcAlarmSensorStateSchema),
20567
+ readAt: number().int().nonnegative()
20568
+ });
20501
20569
  /**
20502
20570
  * ONE rule's demand on ONE camera's clip ring.
20503
20571
  *
@@ -20588,7 +20656,7 @@ method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), m
20588
20656
  }), method(object({}), NcAlarmConfigSchema, { auth: "admin" }), method(object({ patch: NcAlarmSettingsPatchSchema }), NcAlarmConfigSchema, {
20589
20657
  kind: "mutation",
20590
20658
  auth: "admin"
20591
- });
20659
+ }), method(NcAlarmSensorsInputSchema, NcAlarmSensorsSchema, { auth: "admin" });
20592
20660
  /**
20593
20661
  * Zod schemas for persisted record types.
20594
20662
  *
@@ -40788,13 +40856,14 @@ var BaseDeviceProvider = class extends BaseAddon {
40788
40856
  async getStatus() {
40789
40857
  const all = await this.ctx.kernel.devices?.getAll() ?? [];
40790
40858
  const summary = this.restoreFailureSummary();
40791
- if (summary === null) return {
40859
+ const base = {
40792
40860
  connected: true,
40793
- deviceCount: all.length
40861
+ deviceCount: all.length,
40862
+ motionSliceWriter: "orchestrator"
40794
40863
  };
40864
+ if (summary === null) return base;
40795
40865
  return {
40796
- connected: true,
40797
- deviceCount: all.length,
40866
+ ...base,
40798
40867
  error: summary
40799
40868
  };
40800
40869
  }
@@ -46436,6 +46505,12 @@ Object.freeze({
46436
46505
  addonId: null,
46437
46506
  access: "view"
46438
46507
  },
46508
+ "notificationRules.getAlarmSensors": {
46509
+ capName: "notification-rules",
46510
+ capScope: "system",
46511
+ addonId: null,
46512
+ access: "view"
46513
+ },
46439
46514
  "notificationRules.getClipRetentionAsks": {
46440
46515
  capName: "notification-rules",
46441
46516
  capScope: "system",
@@ -50919,6 +50994,11 @@ Object.freeze({
50919
50994
  form: "single",
50920
50995
  optional: false
50921
50996
  }],
50997
+ "notificationRules.getAlarmSensors": [{
50998
+ name: "deviceIds",
50999
+ form: "array",
51000
+ optional: false
51001
+ }],
50922
51002
  "notificationRules.setDeviceMuted": [{
50923
51003
  name: "deviceId",
50924
51004
  form: "single",
package/dist/addon.mjs CHANGED
@@ -14853,7 +14853,17 @@ var SiteZoneSchema = object({
14853
14853
  var ProviderStatusSchema = object({
14854
14854
  connected: boolean(),
14855
14855
  deviceCount: number(),
14856
- error: string().optional()
14856
+ error: string().optional(),
14857
+ /**
14858
+ * `'orchestrator'`: this provider writes NO camera's `motion` runtime slice
14859
+ * — the orchestrator is its only writer (D696). Set by `BaseDeviceProvider`,
14860
+ * which every provider bundles, so only a provider BUILT from D696-amended
14861
+ * code says it. ABSENT means an older provider that may still write it (raw
14862
+ * VMD writes, a boot seed), and the orchestrator's provider gate keeps that
14863
+ * provider's cameras unwritten (`camera-sensors/motion-slice-provider-gate.ts`)
14864
+ * — the provider twin of the runner's `getLocalLoad().motionSliceWriter`.
14865
+ */
14866
+ motionSliceWriter: literal("orchestrator").optional()
14857
14867
  });
14858
14868
  object({
14859
14869
  externalId: string(),
@@ -20315,6 +20325,29 @@ object({
20315
20325
  firstAt: number(),
20316
20326
  lastAt: number()
20317
20327
  });
20328
+ var NC_ALARM_TRIGGERED_MAX_SEC = 3600;
20329
+ var NcAlarmDelaySecSchema = number().int().min(0).max(600);
20330
+ var NcAlarmTriggeredSecSchema = number().int().min(0).max(NC_ALARM_TRIGGERED_MAX_SEC);
20331
+ var uniqueModes = (entries) => new Set(entries.map((e) => e.mode)).size === entries.length;
20332
+ var NcAlarmModeDelaysListSchema = array(object({
20333
+ mode: AlarmArmModeSchema,
20334
+ exitDelaySec: NcAlarmDelaySecSchema.optional(),
20335
+ entryDelaySec: NcAlarmDelaySecSchema.optional(),
20336
+ triggeredDurationSec: NcAlarmTriggeredSecSchema.optional()
20337
+ })).max(8).refine(uniqueModes, { message: "modeDelays: at most one entry per arm mode" });
20338
+ var NcAlarmModeDelaysEditListSchema = array(object({
20339
+ mode: AlarmArmModeSchema,
20340
+ exitDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
20341
+ entryDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
20342
+ triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional()
20343
+ })).max(8).refine(uniqueModes, { message: "modeDelays: at most one edit per arm mode" });
20344
+ /** One switch of the alarm table: put ONE device on, or take it off, ONE mode's list. */
20345
+ var NcAlarmNonBlockingEditSchema = object({
20346
+ mode: AlarmArmModeSchema,
20347
+ deviceId: number().int().positive(),
20348
+ /** true = on the list (may be open, does not block); false = off the list (blocks). */
20349
+ nonBlocking: boolean()
20350
+ });
20318
20351
  /**
20319
20352
  * The per-mode lists, at most one per mode. Two lists for one mode have no
20320
20353
  * meaning a reader could agree on (union? the last one?), so they are refused
@@ -20323,10 +20356,10 @@ object({
20323
20356
  var NcAlarmNonBlockingListSchema = array(object({
20324
20357
  mode: AlarmArmModeSchema,
20325
20358
  deviceIds: array(number().int()).max(200)
20326
- })).max(8).refine((lists) => new Set(lists.map((l) => l.mode)).size === lists.length, { message: "nonBlocking: at most one list per arm mode" });
20359
+ })).max(8).refine(uniqueModes, { message: "nonBlocking: at most one list per arm mode" });
20327
20360
  /**
20328
- * The three durations the panel's state machine runs on, who hears about its
20329
- * transitions, and which openings each mode tolerates.
20361
+ * The three durations — global, and per mode since D697 — the panel's state
20362
+ * machine runs on, who hears about its transitions, and which openings each mode tolerates.
20330
20363
  *
20331
20364
  * They live on the NOTIFICATION-RULES cap, not on `alarm-panel`, on purpose:
20332
20365
  * `alarm-panel` is `deviceNative` and its other provider mirrors somebody
@@ -20336,15 +20369,15 @@ var NcAlarmNonBlockingListSchema = array(object({
20336
20369
  */
20337
20370
  var NcAlarmSettingsSchema = object({
20338
20371
  /** Grace period between arming and the mode taking effect. 0 = immediate. */
20339
- exitDelaySec: number().int().min(0).max(600),
20372
+ exitDelaySec: NcAlarmDelaySecSchema,
20340
20373
  /** Grace period between a trigger and the alarm firing. 0 = immediate. */
20341
- entryDelaySec: number().int().min(0).max(600),
20374
+ entryDelaySec: NcAlarmDelaySecSchema,
20342
20375
  /**
20343
20376
  * How long `triggered` lasts before the panel re-arms itself.
20344
20377
  * **0 = until an operator disarms it** — the behaviour before this field
20345
20378
  * existed, and therefore what an untouched install keeps doing.
20346
20379
  */
20347
- triggeredDurationSec: number().int().min(0).max(3600),
20380
+ triggeredDurationSec: NcAlarmTriggeredSecSchema,
20348
20381
  /**
20349
20382
  * Deprecated by D630 — every transition is announced. Parsed, never read;
20350
20383
  * remove after one release. Optional so an older admin's patch (which still
@@ -20367,17 +20400,30 @@ var NcAlarmSettingsSchema = object({
20367
20400
  * per mode is meaningful. Defaulted to `[]` so a blob stored before D630
20368
20401
  * parses as "every opening blocks" — the behaviour it was written under.
20369
20402
  */
20370
- nonBlocking: NcAlarmNonBlockingListSchema.default([])
20403
+ nonBlocking: NcAlarmNonBlockingListSchema.default([]),
20404
+ /**
20405
+ * Per arm mode, the delays that mode OVERRIDES (D697). A mode with no entry, or an entry
20406
+ * without a field, uses the global value above — so `[]`, the default, is exactly the
20407
+ * behaviour of a blob stored before this field existed. Read through `resolveModeDelays`.
20408
+ */
20409
+ modeDelays: NcAlarmModeDelaysListSchema.default([])
20371
20410
  });
20372
20411
  /**
20373
20412
  * Every field optional — a tab edits one control at a time.
20374
20413
  *
20375
- * `nonBlocking` is re-declared WITHOUT its default: `.partial()` does not
20376
- * remove an inner `.default()`, so a patch that never named the field would
20377
- * parse to `nonBlocking: []` and wipe every mode's list on an unrelated edit
20378
- * (the same trap {@link NcRulePatchSchema} documents).
20414
+ * `nonBlocking` and `modeDelays` are re-declared WITHOUT their defaults:
20415
+ * `.partial()` does not remove an inner `.default()`, so a patch that never
20416
+ * named the field would parse to `[]` and wipe every mode's list on an
20417
+ * unrelated edit (the same trap {@link NcRulePatchSchema} documents). Here
20418
+ * `modeDelays` means EDITS, not the stored overrides.
20379
20419
  */
20380
- var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({ nonBlocking: NcAlarmNonBlockingListSchema }).partial();
20420
+ var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({
20421
+ nonBlocking: NcAlarmNonBlockingListSchema,
20422
+ /** Per-mode, per-field edits — NOT the whole list (see NcAlarmModeDelaysEditSchema). */
20423
+ modeDelays: NcAlarmModeDelaysEditListSchema,
20424
+ /** ONE membership change; the panel applies it to the list it holds at its turn. */
20425
+ nonBlockingEdit: NcAlarmNonBlockingEditSchema
20426
+ }).partial().refine((p) => p.nonBlocking === void 0 || p.nonBlockingEdit === void 0, { message: "nonBlocking and nonBlockingEdit are exclusive — send the whole lists or one edit" });
20381
20427
  /**
20382
20428
  * What one arm mode actually arms, DERIVED from the enabled rules gated on it.
20383
20429
  * Never authored, never stored — see `alarm-mode-coverage.ts` for why a stored
@@ -20477,6 +20523,28 @@ var NcAlarmConfigSchema = object({
20477
20523
  */
20478
20524
  live: NcAlarmLiveSchema.optional()
20479
20525
  });
20526
+ var NcAlarmSensorReadingSchema = _enum([
20527
+ "open",
20528
+ "closed",
20529
+ "unknown",
20530
+ "not-opening"
20531
+ ]);
20532
+ /** One device's state as the alarm reads it — the classifier the arm check uses. */
20533
+ var NcAlarmSensorStateSchema = object({
20534
+ deviceId: number().int().positive(),
20535
+ reading: NcAlarmSensorReadingSchema,
20536
+ /** The word as read (`open`, `closed`, `unlocked`, `stopped`, …); null when unknown / not an opening. */
20537
+ state: string().nullable(),
20538
+ /** Why `unknown`: the read failed, or the slice holds no word its cap defines (a placeholder included). */
20539
+ unknownWhy: _enum(["read-failed", "unknown-word"]).nullable(),
20540
+ /** The device manager's liveness as the centre mirrors it; null = not known. */
20541
+ online: boolean().nullable()
20542
+ });
20543
+ var NcAlarmSensorsInputSchema = object({ deviceIds: array(number().int().positive()).max(500) });
20544
+ var NcAlarmSensorsSchema = object({
20545
+ sensors: array(NcAlarmSensorStateSchema),
20546
+ readAt: number().int().nonnegative()
20547
+ });
20480
20548
  /**
20481
20549
  * ONE rule's demand on ONE camera's clip ring.
20482
20550
  *
@@ -20567,7 +20635,7 @@ method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), m
20567
20635
  }), method(object({}), NcAlarmConfigSchema, { auth: "admin" }), method(object({ patch: NcAlarmSettingsPatchSchema }), NcAlarmConfigSchema, {
20568
20636
  kind: "mutation",
20569
20637
  auth: "admin"
20570
- });
20638
+ }), method(NcAlarmSensorsInputSchema, NcAlarmSensorsSchema, { auth: "admin" });
20571
20639
  /**
20572
20640
  * Zod schemas for persisted record types.
20573
20641
  *
@@ -40767,13 +40835,14 @@ var BaseDeviceProvider = class extends BaseAddon {
40767
40835
  async getStatus() {
40768
40836
  const all = await this.ctx.kernel.devices?.getAll() ?? [];
40769
40837
  const summary = this.restoreFailureSummary();
40770
- if (summary === null) return {
40838
+ const base = {
40771
40839
  connected: true,
40772
- deviceCount: all.length
40840
+ deviceCount: all.length,
40841
+ motionSliceWriter: "orchestrator"
40773
40842
  };
40843
+ if (summary === null) return base;
40774
40844
  return {
40775
- connected: true,
40776
- deviceCount: all.length,
40845
+ ...base,
40777
40846
  error: summary
40778
40847
  };
40779
40848
  }
@@ -46415,6 +46484,12 @@ Object.freeze({
46415
46484
  addonId: null,
46416
46485
  access: "view"
46417
46486
  },
46487
+ "notificationRules.getAlarmSensors": {
46488
+ capName: "notification-rules",
46489
+ capScope: "system",
46490
+ addonId: null,
46491
+ access: "view"
46492
+ },
46418
46493
  "notificationRules.getClipRetentionAsks": {
46419
46494
  capName: "notification-rules",
46420
46495
  capScope: "system",
@@ -50898,6 +50973,11 @@ Object.freeze({
50898
50973
  form: "single",
50899
50974
  optional: false
50900
50975
  }],
50976
+ "notificationRules.getAlarmSensors": [{
50977
+ name: "deviceIds",
50978
+ form: "array",
50979
+ optional: false
50980
+ }],
50901
50981
  "notificationRules.setDeviceMuted": [{
50902
50982
  name: "deviceId",
50903
50983
  form: "single",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-amcrest",
3
- "version": "0.2.125",
3
+ "version": "0.2.126",
4
4
  "description": "Amcrest/Dahua camera device provider addon for CamStack — Dahua CGI over HTTP(S) with digest auth (snapshot, RTSP catalog, PTZ, image/day-night config)",
5
5
  "keywords": [
6
6
  "camstack",