@camstack/addon-provider-hikvision 1.2.32 → 1.2.34

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 +258 -17
  2. package/dist/addon.mjs +258 -17
  3. package/package.json +1 -1
package/dist/addon.js CHANGED
@@ -6,7 +6,7 @@ let node_crypto = require("node:crypto");
6
6
  let node_http = require("node:http");
7
7
  let node_https = require("node:https");
8
8
  let node_os = require("node:os");
9
- //#region ../types/dist/event-category-XfKNtfCc.mjs
9
+ //#region ../types/dist/event-category-CIa_iT6b.mjs
10
10
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
11
11
  EventCategory["SystemBoot"] = "system.boot";
12
12
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -22,6 +22,15 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
22
22
  */
23
23
  EventCategory["SystemRestartCompleted"] = "system.restart-completed";
24
24
  /**
25
+ * The hub reissued its own TLS certificate at boot (`ensureTlsCert`).
26
+ * Emitted only when the material on disk actually changed, so an
27
+ * operator who trusted the old certificate by hand is told rather than
28
+ * discovering it as a browser error. Payload `TlsCertChangedPayload`.
29
+ *
30
+ * Rule: docs/decisions/adr-0227-*.md
31
+ */
32
+ EventCategory["SystemTlsCertChanged"] = "system.tls-cert-changed";
33
+ /**
25
34
  * A newer addon or server-root package version was found by the
26
35
  * authoritative registry check. Emitted once when any observed
27
36
  * `latestVersion` changes (or a package/node first appears behind);
@@ -8181,6 +8190,15 @@ var LabelDefinitionSchema = object({
8181
8190
  description: string().optional(),
8182
8191
  icon: string().optional()
8183
8192
  });
8193
+ var ClassMapDefinitionSchema = object({
8194
+ mapping: record(string(), _enum([
8195
+ "person",
8196
+ "vehicle",
8197
+ "animal",
8198
+ "package"
8199
+ ])),
8200
+ preserveOriginal: boolean()
8201
+ });
8184
8202
  var MODEL_FORMATS = [
8185
8203
  "onnx",
8186
8204
  "coreml",
@@ -8359,7 +8377,13 @@ var ModelCatalogEntrySchema = object({
8359
8377
  * `id` stays the source of truth for resolution/download/persistence; grouping
8360
8378
  * is a presentation overlay resolved back to an `id`.
8361
8379
  */
8362
- group: ModelVariantGroupSchema.optional()
8380
+ group: ModelVariantGroupSchema.optional(),
8381
+ /**
8382
+ * Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
8383
+ * applies (Frigate / COCO public catalog). Set on a custom model whose raw
8384
+ * labels already ARE the CamStack macros (Scrypted identity map).
8385
+ */
8386
+ classMap: ClassMapDefinitionSchema.optional()
8363
8387
  });
8364
8388
  var ConvertTargetSchema = discriminatedUnion("format", [object({
8365
8389
  format: literal("openvino"),
@@ -8388,7 +8412,8 @@ var ModelConvertMetadataSchema = object({
8388
8412
  "ocr",
8389
8413
  "segmentation"
8390
8414
  ]),
8391
- faceAlignment: boolean().optional()
8415
+ faceAlignment: boolean().optional(),
8416
+ classMap: ClassMapDefinitionSchema.optional()
8392
8417
  });
8393
8418
  var ConvertResultSchema = object({
8394
8419
  entry: ModelCatalogEntrySchema,
@@ -17693,6 +17718,33 @@ var NativeCropRefSchema = object({
17693
17718
  h: number()
17694
17719
  })
17695
17720
  });
17721
+ object({
17722
+ crop: object({
17723
+ left: number(),
17724
+ top: number(),
17725
+ width: number().positive(),
17726
+ height: number().positive()
17727
+ }).optional(),
17728
+ content: object({
17729
+ width: number().int().positive(),
17730
+ height: number().int().positive()
17731
+ }),
17732
+ fit: _enum(["stretch", "contain"]),
17733
+ format: _enum([
17734
+ "rgb",
17735
+ "gray",
17736
+ "jpeg"
17737
+ ])
17738
+ });
17739
+ var FrameRefSchema = object({
17740
+ registryId: string().min(1),
17741
+ id: string().min(1),
17742
+ width: number().int().positive(),
17743
+ height: number().int().positive(),
17744
+ format: _enum(["rgb", "gray"]),
17745
+ timestamp: number(),
17746
+ capturedAt: number().optional()
17747
+ });
17696
17748
  var ModelFormatSchema$1 = _enum([
17697
17749
  "onnx",
17698
17750
  "coreml",
@@ -17937,6 +17989,12 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
17937
17989
  steps: array(PipelineStepInputSchema).min(1),
17938
17990
  frame: FrameInputSchema.optional(),
17939
17991
  /**
17992
+ * Process-local lazy frame. Valid only when caller and provider resolve
17993
+ * in the same execution-group process; split/cross-node callers use
17994
+ * `frame`/`image` inline compatibility instead.
17995
+ */
17996
+ frameRef: FrameRefSchema.optional(),
17997
+ /**
17940
17998
  * CB5 shm passthrough — a `FrameHandle` naming the same ring slot
17941
17999
  * the decoded pixels live in. One more member of the one-of
17942
18000
  * frame/frameHandle/image/imageBase64/referenceImage group.
@@ -18232,7 +18290,10 @@ var NativeCropResultSchema = object({
18232
18290
  * Which source served this crop, so a quality-sensitive consumer (the native
18233
18291
  * `keyFrame`) can reject a degraded fallback:
18234
18292
  * - `native` — cut from the decode worker's retained NATIVE surface (the
18235
- * quality path).
18293
+ * quality path). A subject-tile serve is also native-resolution and stays
18294
+ * `native` here: the public enum cannot name `tile` without a breaking cap
18295
+ * change. Runner telemetry distinguishes lease vs tile via `source` on the
18296
+ * internal crop result (`nativeHits` vs `tileHits`).
18236
18297
  * - `ram-fullframe` — the native surface MISSED but the request was full-frame,
18237
18298
  * so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
18238
18299
  * the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
@@ -18723,12 +18784,41 @@ var RunnerLocalLoadSchema = object({
18723
18784
  * legacy `OrchestratorMetricsSchema` shape so existing dashboards keep
18724
18785
  * working unchanged when they switch to reading from the runner cap.
18725
18786
  */
18787
+ var FrameLazyCountersSchema = object({
18788
+ framesDecoded: number(),
18789
+ framesAdmitted: number(),
18790
+ framesDroppedPixelFree: number(),
18791
+ viewsMaterialized: number(),
18792
+ viewsSkipped: number(),
18793
+ workerToRunnerBytes: number(),
18794
+ runnerToPoolRawBytes: number(),
18795
+ runnerToPoolJpegBytes: number(),
18796
+ onDemandFullFrameRequests: number(),
18797
+ onDemandCropRequests: number(),
18798
+ nativeHits: number(),
18799
+ nativeMisses: number(),
18800
+ tileHits: number(),
18801
+ tileMisses: number(),
18802
+ fallbackHits: number(),
18803
+ fallbackMisses: number(),
18804
+ retainedWritesAvoided: number(),
18805
+ residentRefs: number(),
18806
+ residentBytes: number(),
18807
+ releases: number(),
18808
+ evictions: number(),
18809
+ staleMisses: number()
18810
+ });
18811
+ var FrameLazyMetricsSchema = object({
18812
+ node: FrameLazyCountersSchema,
18813
+ cameras: array(FrameLazyCountersSchema.extend({ deviceId: number() }))
18814
+ });
18726
18815
  var RunnerLocalMetricsSchema = object({
18727
18816
  nodeId: string(),
18728
18817
  activeCameras: number(),
18729
18818
  throttledCameras: number(),
18730
18819
  avgInferenceTimeMs: number(),
18731
- queueDepth: number()
18820
+ queueDepth: number(),
18821
+ frameLazy: FrameLazyMetricsSchema.optional()
18732
18822
  });
18733
18823
  method(RunnerCameraConfigSchema, object({ success: literal(true) }), { kind: "mutation" }), method(object({ deviceId: number() }), object({ success: literal(true) }), { kind: "mutation" }), method(ReportMotionInputSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), RunnerLocalLoadSchema), method(_void(), RunnerLocalMetricsSchema), method(object({ deviceId: number() }), CameraMetricsSchema.nullable()), method(_void(), array(CameraMetricsWithDeviceIdSchema).readonly()), method(_void(), array(number()).readonly()), method(object({
18734
18824
  handle: FrameHandleSchema,
@@ -20132,6 +20222,9 @@ method(_void(), ProviderInfoSchema), method(object({ config: record(string(), un
20132
20222
  location: StorageLocationSchema,
20133
20223
  relativePath: string()
20134
20224
  }), _void(), { kind: "mutation" }), method(object({ location: StorageLocationSchema }), number().nullable()), method(BeginUploadInputSchema, BeginUploadResultSchema, { kind: "mutation" }), method(WriteChunkInputSchema, _void(), { kind: "mutation" }), method(FinalizeUploadInputSchema, _void(), { kind: "mutation" }), method(AbortUploadInputSchema, _void(), { kind: "mutation" }), method(BeginDownloadInputSchema, BeginDownloadResultSchema, { kind: "mutation" }), method(ReadChunkInputSchema, _instanceof(Uint8Array)), method(EndDownloadInputSchema, _void(), { kind: "mutation" });
20225
+ /** Profile-exported FormBuilder schema. Shape is ConfigUISchema at the UI. */
20226
+ var ProfileSettingsSchemaBridge = unknown().nullable();
20227
+ var ProfileSettingsBagSchema = record(string(), unknown());
20135
20228
  /**
20136
20229
  * A live terminal session hosted by the provider addon. Output and input do
20137
20230
  * NOT flow through the capability — they use the addon data plane
@@ -20161,7 +20254,14 @@ var TerminalSessionInfoSchema = object({
20161
20254
  var TerminalProfileInfoSchema = object({
20162
20255
  profileId: string(),
20163
20256
  label: string(),
20164
- description: string().optional()
20257
+ description: string().optional(),
20258
+ /** Spawn defaults the instance form copies on create. */
20259
+ executable: string().optional(),
20260
+ args: array(string()).readonly().optional(),
20261
+ cwd: string().optional(),
20262
+ environment: array(string()).readonly().optional(),
20263
+ /** ConfigUISchema for instance knobs, or null when the profile has none. */
20264
+ settingsSchema: ProfileSettingsSchemaBridge.optional()
20165
20265
  });
20166
20266
  /**
20167
20267
  * A durable operator-created Terminal instance. Profiles are templates; only
@@ -20174,7 +20274,12 @@ var TerminalInstanceInfoSchema = object({
20174
20274
  profileId: string(),
20175
20275
  profileLabel: string(),
20176
20276
  name: string(),
20177
- enabled: boolean()
20277
+ enabled: boolean(),
20278
+ executable: string(),
20279
+ args: array(string()).readonly(),
20280
+ cwd: string(),
20281
+ environment: array(string()).readonly(),
20282
+ profileSettings: ProfileSettingsBagSchema
20178
20283
  });
20179
20284
  var TerminalLegacyCameraSchema = object({
20180
20285
  stableId: string(),
@@ -20204,7 +20309,23 @@ var TerminalOutputBatchSchema = object({
20204
20309
  method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }), method(_void(), array(TerminalInstanceInfoSchema).readonly(), { auth: "admin" }), method(object({
20205
20310
  targetNodeId: string().min(1),
20206
20311
  profileId: string().min(1),
20207
- name: string().trim().min(1).max(160).optional()
20312
+ name: string().trim().min(1).max(160).optional(),
20313
+ executable: string().max(1024).optional(),
20314
+ args: array(string().max(2048)).max(64).optional(),
20315
+ cwd: string().max(1024).optional(),
20316
+ environment: array(string().max(4096)).max(64).optional(),
20317
+ profileSettings: ProfileSettingsBagSchema.optional()
20318
+ }), TerminalInstanceInfoSchema, {
20319
+ kind: "mutation",
20320
+ auth: "admin"
20321
+ }), method(object({
20322
+ instanceId: string().min(1),
20323
+ name: string().trim().min(1).max(160).optional(),
20324
+ executable: string().max(1024).optional(),
20325
+ args: array(string().max(2048)).max(64).optional(),
20326
+ cwd: string().max(1024).optional(),
20327
+ environment: array(string().max(4096)).max(64).optional(),
20328
+ profileSettings: ProfileSettingsBagSchema.optional()
20208
20329
  }), TerminalInstanceInfoSchema, {
20209
20330
  kind: "mutation",
20210
20331
  auth: "admin"
@@ -20226,7 +20347,11 @@ method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }),
20226
20347
  }), method(_void(), array(TerminalSessionInfoSchema).readonly(), { auth: "admin" }), method(object({
20227
20348
  profileId: string(),
20228
20349
  cols: number().int().positive(),
20229
- rows: number().int().positive()
20350
+ rows: number().int().positive(),
20351
+ executable: string().max(1024).optional(),
20352
+ args: array(string().max(2048)).max(64).optional(),
20353
+ cwd: string().max(1024).optional(),
20354
+ environment: array(string().max(4096)).max(64).optional()
20230
20355
  }), TerminalSessionInfoSchema, {
20231
20356
  kind: "mutation",
20232
20357
  auth: "admin"
@@ -24101,10 +24226,10 @@ var lawnMowerControlCapability = {
24101
24226
  *
24102
24227
  * • The SDK (mobile / web client) consumes `getConnectionEndpoints()`
24103
24228
  * to receive an ordered list of candidate base URLs it should race
24104
- * on connect — LAN IPv4 first (lowest latency when on same network),
24105
- * then public hostname (if a tunnel is up), then IPv6. The SDK can
24106
- * race them with short timeouts and stick with the winner for the
24107
- * session.
24229
+ * on connect — LAN IPv4 and stable LAN IPv6 first (lowest latency
24230
+ * when on the same network), then public hostname (if a tunnel is
24231
+ * up). The SDK can race them with short timeouts and stick with the
24232
+ * winner for the session.
24108
24233
  *
24109
24234
  * Why hub-only: agents are not directly addressable by the operator's
24110
24235
  * clients — they reverse-connect to the hub. Exposing their interfaces
@@ -24259,6 +24384,17 @@ var NotificationEndpointSchema = object({
24259
24384
  /** What the ranking currently resolves to (null when nothing is reachable). */
24260
24385
  resolved: string().nullable()
24261
24386
  });
24387
+ /**
24388
+ * The URLs the SDK / viewer should race for API access. `baseUrls` empty =
24389
+ * AUTO (every LAN IPv4 + the public tunnel). `resolved` is what that choice
24390
+ * currently expands to, so the UI can show the effective set either way.
24391
+ */
24392
+ var ViewerEndpointsSchema = object({
24393
+ /** The operator's explicit race set, or empty for AUTO. */
24394
+ baseUrls: array(string()).readonly(),
24395
+ /** What the ranking currently resolves to (may be empty if nothing is up). */
24396
+ resolved: array(string()).readonly()
24397
+ });
24262
24398
  var AllowedAddressesSchema = object({
24263
24399
  /**
24264
24400
  * Allowlist of interface addresses operators have explicitly opted
@@ -24267,6 +24403,20 @@ var AllowedAddressesSchema = object({
24267
24403
  * Network Addresses admin page and persisted by the addon.
24268
24404
  */
24269
24405
  addresses: array(string()).readonly() });
24406
+ var TlsStatusSchema = object({
24407
+ mode: _enum([
24408
+ "generated",
24409
+ "uploaded",
24410
+ "disabled"
24411
+ ]),
24412
+ leafFingerprintSha256: string().nullable(),
24413
+ caFingerprintSha256: string().nullable(),
24414
+ validTo: string().nullable(),
24415
+ sans: array(string()),
24416
+ caCertPem: string().nullable(),
24417
+ reissueError: string().nullable(),
24418
+ restartRequired: boolean()
24419
+ });
24270
24420
  method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(object({
24271
24421
  /**
24272
24422
  * LEGACY HINT — do not send from new code. Kept optional so clients
@@ -24276,17 +24426,31 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
24276
24426
  */
24277
24427
  port: number().int().min(1).max(65535).optional(),
24278
24428
  /** Include `http(s)://127.0.0.1:<port>` as the lowest-priority
24279
- * candidate. Default `true`. */
24429
+ * candidate. Default `false` — loopback is not a client route. */
24280
24430
  includeLoopback: boolean().optional(),
24281
- /** Skip IPv6 entries. Some legacy clients can't parse them.
24282
- * Default `false`. */
24431
+ /** Skip IPv6 entries. Default `false` the palette includes stable
24432
+ * LAN IPv6 (ICE/WebRTC uses dual-stack regardless). Pass `true` to
24433
+ * hide them. The viewer HTTP/WS race is `getViewerEndpoints`. */
24283
24434
  ipv4Only: boolean().optional(),
24284
24435
  /** Scheme to emit for LAN/loopback URLs. Default `'http'`.
24285
24436
  * Pass `'https'` when the caller is itself loaded over HTTPS
24286
24437
  * to avoid mixed-content blocks in the browser. The public
24287
24438
  * tunnel always emits `https://` regardless. */
24288
24439
  scheme: _enum(["http", "https"]).optional()
24289
- }), GetConnectionEndpointsResultSchema), method(_void(), NotificationEndpointSchema), method(object({ baseUrl: string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }), method(_void(), AllowedAddressesSchema), method(AllowedAddressesSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), AllowedAddressesSchema, { kind: "mutation" });
24440
+ }), 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, {
24441
+ kind: "mutation",
24442
+ auth: "admin"
24443
+ }), method(object({
24444
+ certPem: string().min(1),
24445
+ keyPem: string().min(1),
24446
+ caPem: string().optional()
24447
+ }), TlsStatusSchema, {
24448
+ kind: "mutation",
24449
+ auth: "admin"
24450
+ }), method(_void(), object({ pem: string() })), method(_void(), TlsStatusSchema, {
24451
+ kind: "mutation",
24452
+ auth: "admin"
24453
+ });
24290
24454
  var LockControlStatusSchema = object({
24291
24455
  /** Lifecycle state of the lock. `jammed` means the motor reported
24292
24456
  * failure to reach the target — operator intervention required. */
@@ -32877,6 +33041,12 @@ Object.freeze({
32877
33041
  addonId: null,
32878
33042
  access: "create"
32879
33043
  },
33044
+ "localNetwork.downloadCa": {
33045
+ capName: "local-network",
33046
+ capScope: "system",
33047
+ addonId: null,
33048
+ access: "view"
33049
+ },
32880
33050
  "localNetwork.getAllowedAddresses": {
32881
33051
  capName: "local-network",
32882
33052
  capScope: "system",
@@ -32901,18 +33071,42 @@ Object.freeze({
32901
33071
  addonId: null,
32902
33072
  access: "view"
32903
33073
  },
33074
+ "localNetwork.getTlsStatus": {
33075
+ capName: "local-network",
33076
+ capScope: "system",
33077
+ addonId: null,
33078
+ access: "view"
33079
+ },
33080
+ "localNetwork.getViewerEndpoints": {
33081
+ capName: "local-network",
33082
+ capScope: "system",
33083
+ addonId: null,
33084
+ access: "view"
33085
+ },
32904
33086
  "localNetwork.list": {
32905
33087
  capName: "local-network",
32906
33088
  capScope: "system",
32907
33089
  addonId: null,
32908
33090
  access: "view"
32909
33091
  },
33092
+ "localNetwork.regenerateCertificate": {
33093
+ capName: "local-network",
33094
+ capScope: "system",
33095
+ addonId: null,
33096
+ access: "create"
33097
+ },
32910
33098
  "localNetwork.resetAllowlistToBestMatch": {
32911
33099
  capName: "local-network",
32912
33100
  capScope: "system",
32913
33101
  addonId: null,
32914
33102
  access: "delete"
32915
33103
  },
33104
+ "localNetwork.revertToGeneratedCertificate": {
33105
+ capName: "local-network",
33106
+ capScope: "system",
33107
+ addonId: null,
33108
+ access: "create"
33109
+ },
32916
33110
  "localNetwork.setAllowedAddresses": {
32917
33111
  capName: "local-network",
32918
33112
  capScope: "system",
@@ -32925,6 +33119,18 @@ Object.freeze({
32925
33119
  addonId: null,
32926
33120
  access: "create"
32927
33121
  },
33122
+ "localNetwork.setViewerEndpoints": {
33123
+ capName: "local-network",
33124
+ capScope: "system",
33125
+ addonId: null,
33126
+ access: "create"
33127
+ },
33128
+ "localNetwork.uploadCertificate": {
33129
+ capName: "local-network",
33130
+ capScope: "system",
33131
+ addonId: null,
33132
+ access: "create"
33133
+ },
32928
33134
  "lockControl.lock": {
32929
33135
  capName: "lock-control",
32930
33136
  capScope: "device",
@@ -35805,6 +36011,12 @@ Object.freeze({
35805
36011
  addonId: null,
35806
36012
  access: "create"
35807
36013
  },
36014
+ "terminalSession.updateInstance": {
36015
+ capName: "terminal-session",
36016
+ capScope: "system",
36017
+ addonId: null,
36018
+ access: "create"
36019
+ },
35808
36020
  "terminalSession.writeInput": {
35809
36021
  capName: "terminal-session",
35810
36022
  capScope: "system",
@@ -38292,6 +38504,35 @@ Object.freeze(Object.fromEntries([{
38292
38504
  }]
38293
38505
  }].map((s) => [s.stepId, s.defaultModelId])));
38294
38506
  string().min(1);
38507
+ var CLUSTER_STEP_SETTING_FIELDS = [{
38508
+ stepId: "face-embedding",
38509
+ key: "minLandmarkFaceSize",
38510
+ label: "Min face size for recognition (detection px)",
38511
+ description: "Refuse to embed a face smaller than this IN THE DETECTION FRAME. Applies to every node — the enrolled gallery is one index, and two admission floors would fill it from two policies. 0 disables the gate.",
38512
+ type: "slider",
38513
+ min: 0,
38514
+ max: 64,
38515
+ step: 2,
38516
+ default: 24
38517
+ }];
38518
+ function clusterStepSettingKey(stepId, fieldKey) {
38519
+ return `clusterStepSetting:${stepId}:${fieldKey}`;
38520
+ }
38521
+ var ClusterSettingNumberSchema = number().finite();
38522
+ function readClusterStepSettings(config) {
38523
+ const out = {};
38524
+ for (const field of CLUSTER_STEP_SETTING_FIELDS) {
38525
+ const parsed = ClusterSettingNumberSchema.safeParse(config[clusterStepSettingKey(field.stepId, field.key)]);
38526
+ const value = parsed.success ? parsed.data : field.default;
38527
+ const existing = out[field.stepId] ?? {};
38528
+ out[field.stepId] = {
38529
+ ...existing,
38530
+ [field.key]: value
38531
+ };
38532
+ }
38533
+ return out;
38534
+ }
38535
+ readClusterStepSettings({});
38295
38536
  object({
38296
38537
  /**
38297
38538
  * Fraction of the box's own size added on EACH side before cutting.
package/dist/addon.mjs CHANGED
@@ -7,7 +7,7 @@ import { networkInterfaces } from "node:os";
7
7
  var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
8
8
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
9
9
  //#endregion
10
- //#region ../types/dist/event-category-XfKNtfCc.mjs
10
+ //#region ../types/dist/event-category-CIa_iT6b.mjs
11
11
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
12
12
  EventCategory["SystemBoot"] = "system.boot";
13
13
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -23,6 +23,15 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
23
23
  */
24
24
  EventCategory["SystemRestartCompleted"] = "system.restart-completed";
25
25
  /**
26
+ * The hub reissued its own TLS certificate at boot (`ensureTlsCert`).
27
+ * Emitted only when the material on disk actually changed, so an
28
+ * operator who trusted the old certificate by hand is told rather than
29
+ * discovering it as a browser error. Payload `TlsCertChangedPayload`.
30
+ *
31
+ * Rule: docs/decisions/adr-0227-*.md
32
+ */
33
+ EventCategory["SystemTlsCertChanged"] = "system.tls-cert-changed";
34
+ /**
26
35
  * A newer addon or server-root package version was found by the
27
36
  * authoritative registry check. Emitted once when any observed
28
37
  * `latestVersion` changes (or a package/node first appears behind);
@@ -8182,6 +8191,15 @@ var LabelDefinitionSchema = object({
8182
8191
  description: string().optional(),
8183
8192
  icon: string().optional()
8184
8193
  });
8194
+ var ClassMapDefinitionSchema = object({
8195
+ mapping: record(string(), _enum([
8196
+ "person",
8197
+ "vehicle",
8198
+ "animal",
8199
+ "package"
8200
+ ])),
8201
+ preserveOriginal: boolean()
8202
+ });
8185
8203
  var MODEL_FORMATS = [
8186
8204
  "onnx",
8187
8205
  "coreml",
@@ -8360,7 +8378,13 @@ var ModelCatalogEntrySchema = object({
8360
8378
  * `id` stays the source of truth for resolution/download/persistence; grouping
8361
8379
  * is a presentation overlay resolved back to an `id`.
8362
8380
  */
8363
- group: ModelVariantGroupSchema.optional()
8381
+ group: ModelVariantGroupSchema.optional(),
8382
+ /**
8383
+ * Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
8384
+ * applies (Frigate / COCO public catalog). Set on a custom model whose raw
8385
+ * labels already ARE the CamStack macros (Scrypted identity map).
8386
+ */
8387
+ classMap: ClassMapDefinitionSchema.optional()
8364
8388
  });
8365
8389
  var ConvertTargetSchema = discriminatedUnion("format", [object({
8366
8390
  format: literal("openvino"),
@@ -8389,7 +8413,8 @@ var ModelConvertMetadataSchema = object({
8389
8413
  "ocr",
8390
8414
  "segmentation"
8391
8415
  ]),
8392
- faceAlignment: boolean().optional()
8416
+ faceAlignment: boolean().optional(),
8417
+ classMap: ClassMapDefinitionSchema.optional()
8393
8418
  });
8394
8419
  var ConvertResultSchema = object({
8395
8420
  entry: ModelCatalogEntrySchema,
@@ -17694,6 +17719,33 @@ var NativeCropRefSchema = object({
17694
17719
  h: number()
17695
17720
  })
17696
17721
  });
17722
+ object({
17723
+ crop: object({
17724
+ left: number(),
17725
+ top: number(),
17726
+ width: number().positive(),
17727
+ height: number().positive()
17728
+ }).optional(),
17729
+ content: object({
17730
+ width: number().int().positive(),
17731
+ height: number().int().positive()
17732
+ }),
17733
+ fit: _enum(["stretch", "contain"]),
17734
+ format: _enum([
17735
+ "rgb",
17736
+ "gray",
17737
+ "jpeg"
17738
+ ])
17739
+ });
17740
+ var FrameRefSchema = object({
17741
+ registryId: string().min(1),
17742
+ id: string().min(1),
17743
+ width: number().int().positive(),
17744
+ height: number().int().positive(),
17745
+ format: _enum(["rgb", "gray"]),
17746
+ timestamp: number(),
17747
+ capturedAt: number().optional()
17748
+ });
17697
17749
  var ModelFormatSchema$1 = _enum([
17698
17750
  "onnx",
17699
17751
  "coreml",
@@ -17938,6 +17990,12 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
17938
17990
  steps: array(PipelineStepInputSchema).min(1),
17939
17991
  frame: FrameInputSchema.optional(),
17940
17992
  /**
17993
+ * Process-local lazy frame. Valid only when caller and provider resolve
17994
+ * in the same execution-group process; split/cross-node callers use
17995
+ * `frame`/`image` inline compatibility instead.
17996
+ */
17997
+ frameRef: FrameRefSchema.optional(),
17998
+ /**
17941
17999
  * CB5 shm passthrough — a `FrameHandle` naming the same ring slot
17942
18000
  * the decoded pixels live in. One more member of the one-of
17943
18001
  * frame/frameHandle/image/imageBase64/referenceImage group.
@@ -18233,7 +18291,10 @@ var NativeCropResultSchema = object({
18233
18291
  * Which source served this crop, so a quality-sensitive consumer (the native
18234
18292
  * `keyFrame`) can reject a degraded fallback:
18235
18293
  * - `native` — cut from the decode worker's retained NATIVE surface (the
18236
- * quality path).
18294
+ * quality path). A subject-tile serve is also native-resolution and stays
18295
+ * `native` here: the public enum cannot name `tile` without a breaking cap
18296
+ * change. Runner telemetry distinguishes lease vs tile via `source` on the
18297
+ * internal crop result (`nativeHits` vs `tileHits`).
18237
18298
  * - `ram-fullframe` — the native surface MISSED but the request was full-frame,
18238
18299
  * so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
18239
18300
  * the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
@@ -18724,12 +18785,41 @@ var RunnerLocalLoadSchema = object({
18724
18785
  * legacy `OrchestratorMetricsSchema` shape so existing dashboards keep
18725
18786
  * working unchanged when they switch to reading from the runner cap.
18726
18787
  */
18788
+ var FrameLazyCountersSchema = object({
18789
+ framesDecoded: number(),
18790
+ framesAdmitted: number(),
18791
+ framesDroppedPixelFree: number(),
18792
+ viewsMaterialized: number(),
18793
+ viewsSkipped: number(),
18794
+ workerToRunnerBytes: number(),
18795
+ runnerToPoolRawBytes: number(),
18796
+ runnerToPoolJpegBytes: number(),
18797
+ onDemandFullFrameRequests: number(),
18798
+ onDemandCropRequests: number(),
18799
+ nativeHits: number(),
18800
+ nativeMisses: number(),
18801
+ tileHits: number(),
18802
+ tileMisses: number(),
18803
+ fallbackHits: number(),
18804
+ fallbackMisses: number(),
18805
+ retainedWritesAvoided: number(),
18806
+ residentRefs: number(),
18807
+ residentBytes: number(),
18808
+ releases: number(),
18809
+ evictions: number(),
18810
+ staleMisses: number()
18811
+ });
18812
+ var FrameLazyMetricsSchema = object({
18813
+ node: FrameLazyCountersSchema,
18814
+ cameras: array(FrameLazyCountersSchema.extend({ deviceId: number() }))
18815
+ });
18727
18816
  var RunnerLocalMetricsSchema = object({
18728
18817
  nodeId: string(),
18729
18818
  activeCameras: number(),
18730
18819
  throttledCameras: number(),
18731
18820
  avgInferenceTimeMs: number(),
18732
- queueDepth: number()
18821
+ queueDepth: number(),
18822
+ frameLazy: FrameLazyMetricsSchema.optional()
18733
18823
  });
18734
18824
  method(RunnerCameraConfigSchema, object({ success: literal(true) }), { kind: "mutation" }), method(object({ deviceId: number() }), object({ success: literal(true) }), { kind: "mutation" }), method(ReportMotionInputSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), RunnerLocalLoadSchema), method(_void(), RunnerLocalMetricsSchema), method(object({ deviceId: number() }), CameraMetricsSchema.nullable()), method(_void(), array(CameraMetricsWithDeviceIdSchema).readonly()), method(_void(), array(number()).readonly()), method(object({
18735
18825
  handle: FrameHandleSchema,
@@ -20133,6 +20223,9 @@ method(_void(), ProviderInfoSchema), method(object({ config: record(string(), un
20133
20223
  location: StorageLocationSchema,
20134
20224
  relativePath: string()
20135
20225
  }), _void(), { kind: "mutation" }), method(object({ location: StorageLocationSchema }), number().nullable()), method(BeginUploadInputSchema, BeginUploadResultSchema, { kind: "mutation" }), method(WriteChunkInputSchema, _void(), { kind: "mutation" }), method(FinalizeUploadInputSchema, _void(), { kind: "mutation" }), method(AbortUploadInputSchema, _void(), { kind: "mutation" }), method(BeginDownloadInputSchema, BeginDownloadResultSchema, { kind: "mutation" }), method(ReadChunkInputSchema, _instanceof(Uint8Array)), method(EndDownloadInputSchema, _void(), { kind: "mutation" });
20226
+ /** Profile-exported FormBuilder schema. Shape is ConfigUISchema at the UI. */
20227
+ var ProfileSettingsSchemaBridge = unknown().nullable();
20228
+ var ProfileSettingsBagSchema = record(string(), unknown());
20136
20229
  /**
20137
20230
  * A live terminal session hosted by the provider addon. Output and input do
20138
20231
  * NOT flow through the capability — they use the addon data plane
@@ -20162,7 +20255,14 @@ var TerminalSessionInfoSchema = object({
20162
20255
  var TerminalProfileInfoSchema = object({
20163
20256
  profileId: string(),
20164
20257
  label: string(),
20165
- description: string().optional()
20258
+ description: string().optional(),
20259
+ /** Spawn defaults the instance form copies on create. */
20260
+ executable: string().optional(),
20261
+ args: array(string()).readonly().optional(),
20262
+ cwd: string().optional(),
20263
+ environment: array(string()).readonly().optional(),
20264
+ /** ConfigUISchema for instance knobs, or null when the profile has none. */
20265
+ settingsSchema: ProfileSettingsSchemaBridge.optional()
20166
20266
  });
20167
20267
  /**
20168
20268
  * A durable operator-created Terminal instance. Profiles are templates; only
@@ -20175,7 +20275,12 @@ var TerminalInstanceInfoSchema = object({
20175
20275
  profileId: string(),
20176
20276
  profileLabel: string(),
20177
20277
  name: string(),
20178
- enabled: boolean()
20278
+ enabled: boolean(),
20279
+ executable: string(),
20280
+ args: array(string()).readonly(),
20281
+ cwd: string(),
20282
+ environment: array(string()).readonly(),
20283
+ profileSettings: ProfileSettingsBagSchema
20179
20284
  });
20180
20285
  var TerminalLegacyCameraSchema = object({
20181
20286
  stableId: string(),
@@ -20205,7 +20310,23 @@ var TerminalOutputBatchSchema = object({
20205
20310
  method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }), method(_void(), array(TerminalInstanceInfoSchema).readonly(), { auth: "admin" }), method(object({
20206
20311
  targetNodeId: string().min(1),
20207
20312
  profileId: string().min(1),
20208
- name: string().trim().min(1).max(160).optional()
20313
+ name: string().trim().min(1).max(160).optional(),
20314
+ executable: string().max(1024).optional(),
20315
+ args: array(string().max(2048)).max(64).optional(),
20316
+ cwd: string().max(1024).optional(),
20317
+ environment: array(string().max(4096)).max(64).optional(),
20318
+ profileSettings: ProfileSettingsBagSchema.optional()
20319
+ }), TerminalInstanceInfoSchema, {
20320
+ kind: "mutation",
20321
+ auth: "admin"
20322
+ }), method(object({
20323
+ instanceId: string().min(1),
20324
+ name: string().trim().min(1).max(160).optional(),
20325
+ executable: string().max(1024).optional(),
20326
+ args: array(string().max(2048)).max(64).optional(),
20327
+ cwd: string().max(1024).optional(),
20328
+ environment: array(string().max(4096)).max(64).optional(),
20329
+ profileSettings: ProfileSettingsBagSchema.optional()
20209
20330
  }), TerminalInstanceInfoSchema, {
20210
20331
  kind: "mutation",
20211
20332
  auth: "admin"
@@ -20227,7 +20348,11 @@ method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }),
20227
20348
  }), method(_void(), array(TerminalSessionInfoSchema).readonly(), { auth: "admin" }), method(object({
20228
20349
  profileId: string(),
20229
20350
  cols: number().int().positive(),
20230
- rows: number().int().positive()
20351
+ rows: number().int().positive(),
20352
+ executable: string().max(1024).optional(),
20353
+ args: array(string().max(2048)).max(64).optional(),
20354
+ cwd: string().max(1024).optional(),
20355
+ environment: array(string().max(4096)).max(64).optional()
20231
20356
  }), TerminalSessionInfoSchema, {
20232
20357
  kind: "mutation",
20233
20358
  auth: "admin"
@@ -24102,10 +24227,10 @@ var lawnMowerControlCapability = {
24102
24227
  *
24103
24228
  * • The SDK (mobile / web client) consumes `getConnectionEndpoints()`
24104
24229
  * to receive an ordered list of candidate base URLs it should race
24105
- * on connect — LAN IPv4 first (lowest latency when on same network),
24106
- * then public hostname (if a tunnel is up), then IPv6. The SDK can
24107
- * race them with short timeouts and stick with the winner for the
24108
- * session.
24230
+ * on connect — LAN IPv4 and stable LAN IPv6 first (lowest latency
24231
+ * when on the same network), then public hostname (if a tunnel is
24232
+ * up). The SDK can race them with short timeouts and stick with the
24233
+ * winner for the session.
24109
24234
  *
24110
24235
  * Why hub-only: agents are not directly addressable by the operator's
24111
24236
  * clients — they reverse-connect to the hub. Exposing their interfaces
@@ -24260,6 +24385,17 @@ var NotificationEndpointSchema = object({
24260
24385
  /** What the ranking currently resolves to (null when nothing is reachable). */
24261
24386
  resolved: string().nullable()
24262
24387
  });
24388
+ /**
24389
+ * The URLs the SDK / viewer should race for API access. `baseUrls` empty =
24390
+ * AUTO (every LAN IPv4 + the public tunnel). `resolved` is what that choice
24391
+ * currently expands to, so the UI can show the effective set either way.
24392
+ */
24393
+ var ViewerEndpointsSchema = object({
24394
+ /** The operator's explicit race set, or empty for AUTO. */
24395
+ baseUrls: array(string()).readonly(),
24396
+ /** What the ranking currently resolves to (may be empty if nothing is up). */
24397
+ resolved: array(string()).readonly()
24398
+ });
24263
24399
  var AllowedAddressesSchema = object({
24264
24400
  /**
24265
24401
  * Allowlist of interface addresses operators have explicitly opted
@@ -24268,6 +24404,20 @@ var AllowedAddressesSchema = object({
24268
24404
  * Network Addresses admin page and persisted by the addon.
24269
24405
  */
24270
24406
  addresses: array(string()).readonly() });
24407
+ var TlsStatusSchema = object({
24408
+ mode: _enum([
24409
+ "generated",
24410
+ "uploaded",
24411
+ "disabled"
24412
+ ]),
24413
+ leafFingerprintSha256: string().nullable(),
24414
+ caFingerprintSha256: string().nullable(),
24415
+ validTo: string().nullable(),
24416
+ sans: array(string()),
24417
+ caCertPem: string().nullable(),
24418
+ reissueError: string().nullable(),
24419
+ restartRequired: boolean()
24420
+ });
24271
24421
  method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(object({
24272
24422
  /**
24273
24423
  * LEGACY HINT — do not send from new code. Kept optional so clients
@@ -24277,17 +24427,31 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
24277
24427
  */
24278
24428
  port: number().int().min(1).max(65535).optional(),
24279
24429
  /** Include `http(s)://127.0.0.1:<port>` as the lowest-priority
24280
- * candidate. Default `true`. */
24430
+ * candidate. Default `false` — loopback is not a client route. */
24281
24431
  includeLoopback: boolean().optional(),
24282
- /** Skip IPv6 entries. Some legacy clients can't parse them.
24283
- * Default `false`. */
24432
+ /** Skip IPv6 entries. Default `false` the palette includes stable
24433
+ * LAN IPv6 (ICE/WebRTC uses dual-stack regardless). Pass `true` to
24434
+ * hide them. The viewer HTTP/WS race is `getViewerEndpoints`. */
24284
24435
  ipv4Only: boolean().optional(),
24285
24436
  /** Scheme to emit for LAN/loopback URLs. Default `'http'`.
24286
24437
  * Pass `'https'` when the caller is itself loaded over HTTPS
24287
24438
  * to avoid mixed-content blocks in the browser. The public
24288
24439
  * tunnel always emits `https://` regardless. */
24289
24440
  scheme: _enum(["http", "https"]).optional()
24290
- }), GetConnectionEndpointsResultSchema), method(_void(), NotificationEndpointSchema), method(object({ baseUrl: string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }), method(_void(), AllowedAddressesSchema), method(AllowedAddressesSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), AllowedAddressesSchema, { kind: "mutation" });
24441
+ }), 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, {
24442
+ kind: "mutation",
24443
+ auth: "admin"
24444
+ }), method(object({
24445
+ certPem: string().min(1),
24446
+ keyPem: string().min(1),
24447
+ caPem: string().optional()
24448
+ }), TlsStatusSchema, {
24449
+ kind: "mutation",
24450
+ auth: "admin"
24451
+ }), method(_void(), object({ pem: string() })), method(_void(), TlsStatusSchema, {
24452
+ kind: "mutation",
24453
+ auth: "admin"
24454
+ });
24291
24455
  var LockControlStatusSchema = object({
24292
24456
  /** Lifecycle state of the lock. `jammed` means the motor reported
24293
24457
  * failure to reach the target — operator intervention required. */
@@ -32878,6 +33042,12 @@ Object.freeze({
32878
33042
  addonId: null,
32879
33043
  access: "create"
32880
33044
  },
33045
+ "localNetwork.downloadCa": {
33046
+ capName: "local-network",
33047
+ capScope: "system",
33048
+ addonId: null,
33049
+ access: "view"
33050
+ },
32881
33051
  "localNetwork.getAllowedAddresses": {
32882
33052
  capName: "local-network",
32883
33053
  capScope: "system",
@@ -32902,18 +33072,42 @@ Object.freeze({
32902
33072
  addonId: null,
32903
33073
  access: "view"
32904
33074
  },
33075
+ "localNetwork.getTlsStatus": {
33076
+ capName: "local-network",
33077
+ capScope: "system",
33078
+ addonId: null,
33079
+ access: "view"
33080
+ },
33081
+ "localNetwork.getViewerEndpoints": {
33082
+ capName: "local-network",
33083
+ capScope: "system",
33084
+ addonId: null,
33085
+ access: "view"
33086
+ },
32905
33087
  "localNetwork.list": {
32906
33088
  capName: "local-network",
32907
33089
  capScope: "system",
32908
33090
  addonId: null,
32909
33091
  access: "view"
32910
33092
  },
33093
+ "localNetwork.regenerateCertificate": {
33094
+ capName: "local-network",
33095
+ capScope: "system",
33096
+ addonId: null,
33097
+ access: "create"
33098
+ },
32911
33099
  "localNetwork.resetAllowlistToBestMatch": {
32912
33100
  capName: "local-network",
32913
33101
  capScope: "system",
32914
33102
  addonId: null,
32915
33103
  access: "delete"
32916
33104
  },
33105
+ "localNetwork.revertToGeneratedCertificate": {
33106
+ capName: "local-network",
33107
+ capScope: "system",
33108
+ addonId: null,
33109
+ access: "create"
33110
+ },
32917
33111
  "localNetwork.setAllowedAddresses": {
32918
33112
  capName: "local-network",
32919
33113
  capScope: "system",
@@ -32926,6 +33120,18 @@ Object.freeze({
32926
33120
  addonId: null,
32927
33121
  access: "create"
32928
33122
  },
33123
+ "localNetwork.setViewerEndpoints": {
33124
+ capName: "local-network",
33125
+ capScope: "system",
33126
+ addonId: null,
33127
+ access: "create"
33128
+ },
33129
+ "localNetwork.uploadCertificate": {
33130
+ capName: "local-network",
33131
+ capScope: "system",
33132
+ addonId: null,
33133
+ access: "create"
33134
+ },
32929
33135
  "lockControl.lock": {
32930
33136
  capName: "lock-control",
32931
33137
  capScope: "device",
@@ -35806,6 +36012,12 @@ Object.freeze({
35806
36012
  addonId: null,
35807
36013
  access: "create"
35808
36014
  },
36015
+ "terminalSession.updateInstance": {
36016
+ capName: "terminal-session",
36017
+ capScope: "system",
36018
+ addonId: null,
36019
+ access: "create"
36020
+ },
35809
36021
  "terminalSession.writeInput": {
35810
36022
  capName: "terminal-session",
35811
36023
  capScope: "system",
@@ -38293,6 +38505,35 @@ Object.freeze(Object.fromEntries([{
38293
38505
  }]
38294
38506
  }].map((s) => [s.stepId, s.defaultModelId])));
38295
38507
  string().min(1);
38508
+ var CLUSTER_STEP_SETTING_FIELDS = [{
38509
+ stepId: "face-embedding",
38510
+ key: "minLandmarkFaceSize",
38511
+ label: "Min face size for recognition (detection px)",
38512
+ description: "Refuse to embed a face smaller than this IN THE DETECTION FRAME. Applies to every node — the enrolled gallery is one index, and two admission floors would fill it from two policies. 0 disables the gate.",
38513
+ type: "slider",
38514
+ min: 0,
38515
+ max: 64,
38516
+ step: 2,
38517
+ default: 24
38518
+ }];
38519
+ function clusterStepSettingKey(stepId, fieldKey) {
38520
+ return `clusterStepSetting:${stepId}:${fieldKey}`;
38521
+ }
38522
+ var ClusterSettingNumberSchema = number().finite();
38523
+ function readClusterStepSettings(config) {
38524
+ const out = {};
38525
+ for (const field of CLUSTER_STEP_SETTING_FIELDS) {
38526
+ const parsed = ClusterSettingNumberSchema.safeParse(config[clusterStepSettingKey(field.stepId, field.key)]);
38527
+ const value = parsed.success ? parsed.data : field.default;
38528
+ const existing = out[field.stepId] ?? {};
38529
+ out[field.stepId] = {
38530
+ ...existing,
38531
+ [field.key]: value
38532
+ };
38533
+ }
38534
+ return out;
38535
+ }
38536
+ readClusterStepSettings({});
38296
38537
  object({
38297
38538
  /**
38298
38539
  * Fraction of the box's own size added on EACH side before cutting.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-hikvision",
3
- "version": "1.2.32",
3
+ "version": "1.2.34",
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",