@camstack/addon-provider-hikvision 1.1.21 → 1.1.22

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
@@ -4635,7 +4635,7 @@ function _instanceof(cls, params = {}) {
4635
4635
  return inst;
4636
4636
  }
4637
4637
  //#endregion
4638
- //#region ../types/dist/sleep-DJaTV2D7.mjs
4638
+ //#region ../types/dist/sleep-BC9Yqte7.mjs
4639
4639
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
4640
4640
  EventCategory["SystemBoot"] = "system.boot";
4641
4641
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -6739,6 +6739,18 @@ function method(input, output, options) {
6739
6739
  timeoutMs: options?.timeoutMs
6740
6740
  };
6741
6741
  }
6742
+ /**
6743
+ * A wrapper/system-only method: served exclusively by the cap's system-level
6744
+ * provider (`InferProvider`), and OPTIONAL on `InferNativeProvider` so per-device
6745
+ * driver natives don't stub out a wrapper concern (e.g. a cross-device cache
6746
+ * overview). The `systemOnly: true` literal is what `InferNativeProvider` keys on.
6747
+ */
6748
+ function systemMethod(input, output, options) {
6749
+ return {
6750
+ ...method(input, output, options),
6751
+ systemOnly: true
6752
+ };
6753
+ }
6742
6754
  /** Shorthand to define an event schema */
6743
6755
  function event(data) {
6744
6756
  return { data };
@@ -12022,6 +12034,7 @@ var PipelineAddonSchemaSchema = object({
12022
12034
  defaultModelId: string(),
12023
12035
  defaultModelIdByFormat: record(string(), string()).optional(),
12024
12036
  enabledByDefault: boolean().optional(),
12037
+ backfillIntoExistingOverrides: boolean().optional(),
12025
12038
  defaultConfidence: number(),
12026
12039
  group: string().optional(),
12027
12040
  configSchema: array(ConfigFieldBridge).readonly().optional()
@@ -12361,6 +12374,25 @@ var zonesCapability = {
12361
12374
  runtimeState: object({ zones: array(ZoneSchema).readonly() })
12362
12375
  };
12363
12376
  /**
12377
+ * A bounding box in NORMALIZED [0,1] frame coordinates for `getNativeCrop`. The
12378
+ * decode worker resolves it against the RETAINED native frame's real pixel dims,
12379
+ * so the caller supplies only the detection-res bbox divided by the detection
12380
+ * dims — no native resolution to plumb.
12381
+ */
12382
+ var NativeCropBboxSchema = object({
12383
+ x: number(),
12384
+ y: number(),
12385
+ w: number(),
12386
+ h: number()
12387
+ });
12388
+ /** Result of a best-effort native-resolution crop (`getNativeCrop`). */
12389
+ var NativeCropResultSchema = object({
12390
+ /** Packed rgb (24-bit) pixels of the crop. */
12391
+ bytes: _instanceof(Uint8Array),
12392
+ width: number().int().positive(),
12393
+ height: number().int().positive()
12394
+ });
12395
+ /**
12364
12396
  * Per-camera tunable ranges + defaults. Single source of truth used
12365
12397
  * by both the Zod data schema (validation + default fallback) and
12366
12398
  * the device settings UI (slider min/max/step). Touch one place and
@@ -12616,7 +12648,11 @@ var RunnerLocalMetricsSchema = object({
12616
12648
  avgInferenceTimeMs: number(),
12617
12649
  queueDepth: number()
12618
12650
  });
12619
- 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());
12651
+ 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({
12652
+ handle: FrameHandleSchema,
12653
+ bbox: NativeCropBboxSchema,
12654
+ maxWidth: number().int().positive().optional()
12655
+ }), NativeCropResultSchema.nullable());
12620
12656
  /**
12621
12657
  * Hardware / firmware motion sensor cap — binary detected state plus
12622
12658
  * a timestamp of the last observation. Distinct from
@@ -18303,7 +18339,17 @@ var TrackSchema = object({
18303
18339
  /** Cumulative normalized distance travelled (0..1 units = full frame width). */
18304
18340
  totalDistance: number(),
18305
18341
  state: TrackStateSchema,
18306
- active: boolean()
18342
+ active: boolean(),
18343
+ /** Deterministic key-event importance score in [0,1] (server-computed at
18344
+ * track expiry, recomputed on late label). Absent on legacy rows written
18345
+ * before scoring shipped — consumers degrade to absence / compute-on-read. */
18346
+ importance: number().optional(),
18347
+ /** Id of the track's highest-confidence ObjectEvent (its representative
18348
+ * "best" frame). Absent when the track produced no object events. */
18349
+ bestEventId: string().optional(),
18350
+ /** Tag of the importance sub-signal that dominated the score
18351
+ * (identity|dwell|proximity|class|confidence|travel|zone). */
18352
+ importanceReason: string().optional()
18307
18353
  });
18308
18354
  var BaseEventFields = {
18309
18355
  id: string(),
@@ -18368,8 +18414,18 @@ var ObjectEventSchema = object({
18368
18414
  frameHeight: number().optional(),
18369
18415
  /** MediaStore key for the crop attached to this event (if any). */
18370
18416
  mediaKey: string().optional(),
18417
+ /** Design B: MediaStore key of the track's native-resolution key frame (the
18418
+ * best-detection full frame). Resolve via the event-media data-plane
18419
+ * (`/addon/<addonId>/event-media/<keyFrameMediaKey>`) for a detail view that
18420
+ * draws `bbox` over the native frame. Absent on legacy rows / non-decoded
18421
+ * sources — consumers fall back to `mediaKey` (the tight crop). */
18422
+ keyFrameMediaKey: string().optional(),
18371
18423
  /** Populated by B5 (recording playback URL for this event). */
18372
- mediaUrl: string().optional()
18424
+ mediaUrl: string().optional(),
18425
+ /** The parent track's key-event importance [0,1], propagated to every object
18426
+ * event of the track (so an event row can be sorted by importance without a
18427
+ * track join). Absent on legacy rows / before the track was scored. */
18428
+ importance: number().optional()
18373
18429
  });
18374
18430
  var AudioEventSchema = object({
18375
18431
  ...BaseEventFields,
@@ -18393,7 +18449,8 @@ var MediaFileKindEnum = _enum([
18393
18449
  "fullFrame",
18394
18450
  "fullFrameBoxed",
18395
18451
  "faceCrop",
18396
- "plateCrop"
18452
+ "plateCrop",
18453
+ "keyFrame"
18397
18454
  ]);
18398
18455
  var MediaFileSchema = object({
18399
18456
  key: string(),
@@ -18414,6 +18471,32 @@ var DeviceEventQueryInput = object({
18414
18471
  projection: _enum(["full", "slim"]).optional()
18415
18472
  });
18416
18473
  var ObjectEventQueryInput = DeviceEventQueryInput.extend({ classFilter: string().optional() });
18474
+ var KeyEventQueryInput = object({
18475
+ deviceId: number(),
18476
+ /** Window lower bound (track firstSeen ≥ since). */
18477
+ since: number(),
18478
+ /** Window upper bound (track firstSeen ≤ until). */
18479
+ until: number(),
18480
+ limit: number().int().min(1).max(200).default(50),
18481
+ /** Drop tracks scoring below this importance. */
18482
+ minImportance: number().min(0).max(1).optional(),
18483
+ /** Restrict to a single class (e.g. 'person'). */
18484
+ classFilter: string().optional()
18485
+ });
18486
+ var KeyEventSchema = object({
18487
+ /** The representative event id (the track's best ObjectEvent, else its trackId). */
18488
+ id: string(),
18489
+ trackId: string(),
18490
+ /** Track start time (firstSeen). */
18491
+ timestamp: number(),
18492
+ className: string(),
18493
+ label: string().optional(),
18494
+ importance: number(),
18495
+ /** Highest-confidence ObjectEvent id for the track (empty when none). */
18496
+ bestEventId: string(),
18497
+ /** Track lifetime in ms (lastSeen - firstSeen). */
18498
+ windowMs: number().optional()
18499
+ });
18417
18500
  var TrackedDetectionSchema = object({
18418
18501
  trackId: string(),
18419
18502
  className: string(),
@@ -18443,7 +18526,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
18443
18526
  }), array(TrackSchema).readonly()), method(object({ deviceId: number() }), _void(), {
18444
18527
  kind: "mutation",
18445
18528
  auth: "admin"
18446
- }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(object({
18529
+ }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
18447
18530
  deviceId: number(),
18448
18531
  since: number(),
18449
18532
  until: number(),
@@ -19247,7 +19330,20 @@ var snapshotCapability = {
19247
19330
  invalidateCache: method(object({ deviceId: number() }), _void(), {
19248
19331
  kind: "mutation",
19249
19332
  auth: "admin"
19250
- })
19333
+ }),
19334
+ /**
19335
+ * Cache-only batch overview — answers from the wrapper's in-memory cache in
19336
+ * O(n) and NEVER triggers a capture. Lets a grid skip requesting images for
19337
+ * devices that never produced a frame, and gives it an ETag per device for
19338
+ * conditional (304-able) image fetches. `lastCapturedAt`/`cacheAgeMs`/`etag`
19339
+ * are null for a device with no cached frame.
19340
+ */
19341
+ getSnapshotOverview: systemMethod(object({ deviceIds: array(number()).min(1).max(200) }), array(object({
19342
+ deviceId: number(),
19343
+ lastCapturedAt: number().nullable(),
19344
+ cacheAgeMs: number().nullable(),
19345
+ etag: string().nullable()
19346
+ })))
19251
19347
  },
19252
19348
  status: {
19253
19349
  schema: SnapshotStatusSchema,
@@ -19504,10 +19600,32 @@ method(_void(), array(TurnServerSchema).readonly());
19504
19600
  * b. `finishAuthentication({userId, response})` → server verifies
19505
19601
  * the assertion, bumps the credential counter, returns ok.
19506
19602
  *
19603
+ * 2b. Usernameless (discoverable-credential) authentication — the
19604
+ * passkey IS the primary factor, no password leg:
19605
+ * a. `beginDiscoverableAuthentication({})` → assertion options with
19606
+ * EMPTY `allowCredentials` (the browser offers every resident
19607
+ * passkey it holds for this RP) + `userVerification: 'required'`
19608
+ * (the passkey replaces both factors, so UV is mandatory).
19609
+ * The challenge is stored server-side, NOT bound to any user.
19610
+ * b. `finishDiscoverableAuthentication({response})` → the provider
19611
+ * resolves the credential by the response's credential id,
19612
+ * verifies the assertion against the stored challenge + that
19613
+ * credential's public key/counter, and returns the OWNING
19614
+ * `userId` — the caller (core auth router) mints the session.
19615
+ *
19507
19616
  * 3. Management:
19508
19617
  * - `listPasskeys({userId})` — enumerate user's enrolled credentials.
19509
19618
  * - `removePasskey({userId, credentialId})` — revoke one credential.
19510
19619
  *
19620
+ * 4. Second-factor preference (opt-in, default OFF):
19621
+ * Enrolling a passkey only enables passkey-FIRST sign-in. It is
19622
+ * demanded as a second factor after a password login ONLY when the
19623
+ * user explicitly opts in via `setSecondFactorPreference`.
19624
+ * - `getSecondFactorPreference({userId})` → `{ enabled }` (missing
19625
+ * row ⇒ `enabled: false`).
19626
+ * - `setSecondFactorPreference({userId, enabled})` — persisted by
19627
+ * the providing addon beside its credentials.
19628
+ *
19511
19629
  * Challenges are short-lived (5 min, in-memory). The cap is internal —
19512
19630
  * the admin-ui composes the begin/finish round-trip and never exposes
19513
19631
  * the cap to non-admins.
@@ -19550,6 +19668,17 @@ method(object({
19550
19668
  }), object({ verified: boolean() }), {
19551
19669
  kind: "mutation",
19552
19670
  access: "view"
19671
+ }), method(object({}), object({ optionsJSON: record(string(), unknown()) }), {
19672
+ kind: "mutation",
19673
+ access: "view"
19674
+ }), method(object({
19675
+ /** AuthenticationResponseJSON from the browser. */
19676
+ response: record(string(), unknown()) }), object({
19677
+ verified: boolean(),
19678
+ userId: string().nullable()
19679
+ }), {
19680
+ kind: "mutation",
19681
+ access: "view"
19553
19682
  }), method(object({ userId: string() }), array(PasskeySummarySchema), { auth: "admin" }), method(object({
19554
19683
  userId: string(),
19555
19684
  credentialId: string()
@@ -19557,6 +19686,13 @@ method(object({
19557
19686
  kind: "mutation",
19558
19687
  auth: "admin",
19559
19688
  access: "delete"
19689
+ }), method(object({ userId: string() }), object({ enabled: boolean() }), { auth: "admin" }), method(object({
19690
+ userId: string(),
19691
+ enabled: boolean()
19692
+ }), object({ success: literal(true) }), {
19693
+ kind: "mutation",
19694
+ auth: "admin",
19695
+ access: "create"
19560
19696
  });
19561
19697
  /**
19562
19698
  * `videoclips` — the unified, navigable-clip surface for a camera.
@@ -20358,7 +20494,17 @@ var FaceInfoSchema = object({
20358
20494
  recognizedIdentityId: string().optional(),
20359
20495
  identityName: string().optional(),
20360
20496
  assigned: boolean(),
20361
- base64: string().optional()
20497
+ base64: string().optional(),
20498
+ /** Design B: the face bbox (pixel space) on the key frame — lets a detail
20499
+ * view draw the box over the native `keyFrameMediaKey` frame. Absent on
20500
+ * legacy rows written before design B. */
20501
+ faceBbox: BoundingBoxSchema.optional(),
20502
+ /** Design B: MediaStore key of the track's native-resolution key frame.
20503
+ * Fetch the native JPEG via the event-media data-plane
20504
+ * (`/addon/<addonId>/event-media/<keyFrameMediaKey>`). Absent when the
20505
+ * track produced no key frame (e.g. native/onboard source) — the UI falls
20506
+ * back to the inline `base64` face crop. */
20507
+ keyFrameMediaKey: string().optional()
20362
20508
  });
20363
20509
  var FaceFilterEnum = _enum([
20364
20510
  "unassigned",
@@ -24852,6 +24998,12 @@ Object.freeze({
24852
24998
  addonId: null,
24853
24999
  access: "view"
24854
25000
  },
25001
+ "pipelineAnalytics.getKeyEvents": {
25002
+ capName: "pipeline-analytics",
25003
+ capScope: "device",
25004
+ addonId: null,
25005
+ access: "view"
25006
+ },
24855
25007
  "pipelineAnalytics.getMotionEvents": {
24856
25008
  capName: "pipeline-analytics",
24857
25009
  capScope: "device",
@@ -25380,6 +25532,12 @@ Object.freeze({
25380
25532
  addonId: null,
25381
25533
  access: "view"
25382
25534
  },
25535
+ "pipelineRunner.getNativeCrop": {
25536
+ capName: "pipeline-runner",
25537
+ capScope: "system",
25538
+ addonId: null,
25539
+ access: "view"
25540
+ },
25383
25541
  "pipelineRunner.reportMotion": {
25384
25542
  capName: "pipeline-runner",
25385
25543
  capScope: "system",
@@ -25746,6 +25904,12 @@ Object.freeze({
25746
25904
  addonId: null,
25747
25905
  access: "view"
25748
25906
  },
25907
+ "snapshot.getSnapshotOverview": {
25908
+ capName: "snapshot",
25909
+ capScope: "device",
25910
+ addonId: null,
25911
+ access: "view"
25912
+ },
25749
25913
  "snapshot.invalidateCache": {
25750
25914
  capName: "snapshot",
25751
25915
  capScope: "device",
@@ -26424,6 +26588,12 @@ Object.freeze({
26424
26588
  addonId: null,
26425
26589
  access: "view"
26426
26590
  },
26591
+ "userPasskeys.beginDiscoverableAuthentication": {
26592
+ capName: "user-passkeys",
26593
+ capScope: "system",
26594
+ addonId: null,
26595
+ access: "view"
26596
+ },
26427
26597
  "userPasskeys.beginRegistration": {
26428
26598
  capName: "user-passkeys",
26429
26599
  capScope: "system",
@@ -26436,12 +26606,24 @@ Object.freeze({
26436
26606
  addonId: null,
26437
26607
  access: "view"
26438
26608
  },
26609
+ "userPasskeys.finishDiscoverableAuthentication": {
26610
+ capName: "user-passkeys",
26611
+ capScope: "system",
26612
+ addonId: null,
26613
+ access: "view"
26614
+ },
26439
26615
  "userPasskeys.finishRegistration": {
26440
26616
  capName: "user-passkeys",
26441
26617
  capScope: "system",
26442
26618
  addonId: null,
26443
26619
  access: "create"
26444
26620
  },
26621
+ "userPasskeys.getSecondFactorPreference": {
26622
+ capName: "user-passkeys",
26623
+ capScope: "system",
26624
+ addonId: null,
26625
+ access: "view"
26626
+ },
26445
26627
  "userPasskeys.listPasskeys": {
26446
26628
  capName: "user-passkeys",
26447
26629
  capScope: "system",
@@ -26454,6 +26636,12 @@ Object.freeze({
26454
26636
  addonId: null,
26455
26637
  access: "delete"
26456
26638
  },
26639
+ "userPasskeys.setSecondFactorPreference": {
26640
+ capName: "user-passkeys",
26641
+ capScope: "system",
26642
+ addonId: null,
26643
+ access: "create"
26644
+ },
26457
26645
  "vacuumControl.locate": {
26458
26646
  capName: "vacuum-control",
26459
26647
  capScope: "device",
package/dist/addon.mjs CHANGED
@@ -4636,7 +4636,7 @@ function _instanceof(cls, params = {}) {
4636
4636
  return inst;
4637
4637
  }
4638
4638
  //#endregion
4639
- //#region ../types/dist/sleep-DJaTV2D7.mjs
4639
+ //#region ../types/dist/sleep-BC9Yqte7.mjs
4640
4640
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
4641
4641
  EventCategory["SystemBoot"] = "system.boot";
4642
4642
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -6740,6 +6740,18 @@ function method(input, output, options) {
6740
6740
  timeoutMs: options?.timeoutMs
6741
6741
  };
6742
6742
  }
6743
+ /**
6744
+ * A wrapper/system-only method: served exclusively by the cap's system-level
6745
+ * provider (`InferProvider`), and OPTIONAL on `InferNativeProvider` so per-device
6746
+ * driver natives don't stub out a wrapper concern (e.g. a cross-device cache
6747
+ * overview). The `systemOnly: true` literal is what `InferNativeProvider` keys on.
6748
+ */
6749
+ function systemMethod(input, output, options) {
6750
+ return {
6751
+ ...method(input, output, options),
6752
+ systemOnly: true
6753
+ };
6754
+ }
6743
6755
  /** Shorthand to define an event schema */
6744
6756
  function event(data) {
6745
6757
  return { data };
@@ -12023,6 +12035,7 @@ var PipelineAddonSchemaSchema = object({
12023
12035
  defaultModelId: string(),
12024
12036
  defaultModelIdByFormat: record(string(), string()).optional(),
12025
12037
  enabledByDefault: boolean().optional(),
12038
+ backfillIntoExistingOverrides: boolean().optional(),
12026
12039
  defaultConfidence: number(),
12027
12040
  group: string().optional(),
12028
12041
  configSchema: array(ConfigFieldBridge).readonly().optional()
@@ -12362,6 +12375,25 @@ var zonesCapability = {
12362
12375
  runtimeState: object({ zones: array(ZoneSchema).readonly() })
12363
12376
  };
12364
12377
  /**
12378
+ * A bounding box in NORMALIZED [0,1] frame coordinates for `getNativeCrop`. The
12379
+ * decode worker resolves it against the RETAINED native frame's real pixel dims,
12380
+ * so the caller supplies only the detection-res bbox divided by the detection
12381
+ * dims — no native resolution to plumb.
12382
+ */
12383
+ var NativeCropBboxSchema = object({
12384
+ x: number(),
12385
+ y: number(),
12386
+ w: number(),
12387
+ h: number()
12388
+ });
12389
+ /** Result of a best-effort native-resolution crop (`getNativeCrop`). */
12390
+ var NativeCropResultSchema = object({
12391
+ /** Packed rgb (24-bit) pixels of the crop. */
12392
+ bytes: _instanceof(Uint8Array),
12393
+ width: number().int().positive(),
12394
+ height: number().int().positive()
12395
+ });
12396
+ /**
12365
12397
  * Per-camera tunable ranges + defaults. Single source of truth used
12366
12398
  * by both the Zod data schema (validation + default fallback) and
12367
12399
  * the device settings UI (slider min/max/step). Touch one place and
@@ -12617,7 +12649,11 @@ var RunnerLocalMetricsSchema = object({
12617
12649
  avgInferenceTimeMs: number(),
12618
12650
  queueDepth: number()
12619
12651
  });
12620
- 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());
12652
+ 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({
12653
+ handle: FrameHandleSchema,
12654
+ bbox: NativeCropBboxSchema,
12655
+ maxWidth: number().int().positive().optional()
12656
+ }), NativeCropResultSchema.nullable());
12621
12657
  /**
12622
12658
  * Hardware / firmware motion sensor cap — binary detected state plus
12623
12659
  * a timestamp of the last observation. Distinct from
@@ -18304,7 +18340,17 @@ var TrackSchema = object({
18304
18340
  /** Cumulative normalized distance travelled (0..1 units = full frame width). */
18305
18341
  totalDistance: number(),
18306
18342
  state: TrackStateSchema,
18307
- active: boolean()
18343
+ active: boolean(),
18344
+ /** Deterministic key-event importance score in [0,1] (server-computed at
18345
+ * track expiry, recomputed on late label). Absent on legacy rows written
18346
+ * before scoring shipped — consumers degrade to absence / compute-on-read. */
18347
+ importance: number().optional(),
18348
+ /** Id of the track's highest-confidence ObjectEvent (its representative
18349
+ * "best" frame). Absent when the track produced no object events. */
18350
+ bestEventId: string().optional(),
18351
+ /** Tag of the importance sub-signal that dominated the score
18352
+ * (identity|dwell|proximity|class|confidence|travel|zone). */
18353
+ importanceReason: string().optional()
18308
18354
  });
18309
18355
  var BaseEventFields = {
18310
18356
  id: string(),
@@ -18369,8 +18415,18 @@ var ObjectEventSchema = object({
18369
18415
  frameHeight: number().optional(),
18370
18416
  /** MediaStore key for the crop attached to this event (if any). */
18371
18417
  mediaKey: string().optional(),
18418
+ /** Design B: MediaStore key of the track's native-resolution key frame (the
18419
+ * best-detection full frame). Resolve via the event-media data-plane
18420
+ * (`/addon/<addonId>/event-media/<keyFrameMediaKey>`) for a detail view that
18421
+ * draws `bbox` over the native frame. Absent on legacy rows / non-decoded
18422
+ * sources — consumers fall back to `mediaKey` (the tight crop). */
18423
+ keyFrameMediaKey: string().optional(),
18372
18424
  /** Populated by B5 (recording playback URL for this event). */
18373
- mediaUrl: string().optional()
18425
+ mediaUrl: string().optional(),
18426
+ /** The parent track's key-event importance [0,1], propagated to every object
18427
+ * event of the track (so an event row can be sorted by importance without a
18428
+ * track join). Absent on legacy rows / before the track was scored. */
18429
+ importance: number().optional()
18374
18430
  });
18375
18431
  var AudioEventSchema = object({
18376
18432
  ...BaseEventFields,
@@ -18394,7 +18450,8 @@ var MediaFileKindEnum = _enum([
18394
18450
  "fullFrame",
18395
18451
  "fullFrameBoxed",
18396
18452
  "faceCrop",
18397
- "plateCrop"
18453
+ "plateCrop",
18454
+ "keyFrame"
18398
18455
  ]);
18399
18456
  var MediaFileSchema = object({
18400
18457
  key: string(),
@@ -18415,6 +18472,32 @@ var DeviceEventQueryInput = object({
18415
18472
  projection: _enum(["full", "slim"]).optional()
18416
18473
  });
18417
18474
  var ObjectEventQueryInput = DeviceEventQueryInput.extend({ classFilter: string().optional() });
18475
+ var KeyEventQueryInput = object({
18476
+ deviceId: number(),
18477
+ /** Window lower bound (track firstSeen ≥ since). */
18478
+ since: number(),
18479
+ /** Window upper bound (track firstSeen ≤ until). */
18480
+ until: number(),
18481
+ limit: number().int().min(1).max(200).default(50),
18482
+ /** Drop tracks scoring below this importance. */
18483
+ minImportance: number().min(0).max(1).optional(),
18484
+ /** Restrict to a single class (e.g. 'person'). */
18485
+ classFilter: string().optional()
18486
+ });
18487
+ var KeyEventSchema = object({
18488
+ /** The representative event id (the track's best ObjectEvent, else its trackId). */
18489
+ id: string(),
18490
+ trackId: string(),
18491
+ /** Track start time (firstSeen). */
18492
+ timestamp: number(),
18493
+ className: string(),
18494
+ label: string().optional(),
18495
+ importance: number(),
18496
+ /** Highest-confidence ObjectEvent id for the track (empty when none). */
18497
+ bestEventId: string(),
18498
+ /** Track lifetime in ms (lastSeen - firstSeen). */
18499
+ windowMs: number().optional()
18500
+ });
18418
18501
  var TrackedDetectionSchema = object({
18419
18502
  trackId: string(),
18420
18503
  className: string(),
@@ -18444,7 +18527,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
18444
18527
  }), array(TrackSchema).readonly()), method(object({ deviceId: number() }), _void(), {
18445
18528
  kind: "mutation",
18446
18529
  auth: "admin"
18447
- }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(object({
18530
+ }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
18448
18531
  deviceId: number(),
18449
18532
  since: number(),
18450
18533
  until: number(),
@@ -19248,7 +19331,20 @@ var snapshotCapability = {
19248
19331
  invalidateCache: method(object({ deviceId: number() }), _void(), {
19249
19332
  kind: "mutation",
19250
19333
  auth: "admin"
19251
- })
19334
+ }),
19335
+ /**
19336
+ * Cache-only batch overview — answers from the wrapper's in-memory cache in
19337
+ * O(n) and NEVER triggers a capture. Lets a grid skip requesting images for
19338
+ * devices that never produced a frame, and gives it an ETag per device for
19339
+ * conditional (304-able) image fetches. `lastCapturedAt`/`cacheAgeMs`/`etag`
19340
+ * are null for a device with no cached frame.
19341
+ */
19342
+ getSnapshotOverview: systemMethod(object({ deviceIds: array(number()).min(1).max(200) }), array(object({
19343
+ deviceId: number(),
19344
+ lastCapturedAt: number().nullable(),
19345
+ cacheAgeMs: number().nullable(),
19346
+ etag: string().nullable()
19347
+ })))
19252
19348
  },
19253
19349
  status: {
19254
19350
  schema: SnapshotStatusSchema,
@@ -19505,10 +19601,32 @@ method(_void(), array(TurnServerSchema).readonly());
19505
19601
  * b. `finishAuthentication({userId, response})` → server verifies
19506
19602
  * the assertion, bumps the credential counter, returns ok.
19507
19603
  *
19604
+ * 2b. Usernameless (discoverable-credential) authentication — the
19605
+ * passkey IS the primary factor, no password leg:
19606
+ * a. `beginDiscoverableAuthentication({})` → assertion options with
19607
+ * EMPTY `allowCredentials` (the browser offers every resident
19608
+ * passkey it holds for this RP) + `userVerification: 'required'`
19609
+ * (the passkey replaces both factors, so UV is mandatory).
19610
+ * The challenge is stored server-side, NOT bound to any user.
19611
+ * b. `finishDiscoverableAuthentication({response})` → the provider
19612
+ * resolves the credential by the response's credential id,
19613
+ * verifies the assertion against the stored challenge + that
19614
+ * credential's public key/counter, and returns the OWNING
19615
+ * `userId` — the caller (core auth router) mints the session.
19616
+ *
19508
19617
  * 3. Management:
19509
19618
  * - `listPasskeys({userId})` — enumerate user's enrolled credentials.
19510
19619
  * - `removePasskey({userId, credentialId})` — revoke one credential.
19511
19620
  *
19621
+ * 4. Second-factor preference (opt-in, default OFF):
19622
+ * Enrolling a passkey only enables passkey-FIRST sign-in. It is
19623
+ * demanded as a second factor after a password login ONLY when the
19624
+ * user explicitly opts in via `setSecondFactorPreference`.
19625
+ * - `getSecondFactorPreference({userId})` → `{ enabled }` (missing
19626
+ * row ⇒ `enabled: false`).
19627
+ * - `setSecondFactorPreference({userId, enabled})` — persisted by
19628
+ * the providing addon beside its credentials.
19629
+ *
19512
19630
  * Challenges are short-lived (5 min, in-memory). The cap is internal —
19513
19631
  * the admin-ui composes the begin/finish round-trip and never exposes
19514
19632
  * the cap to non-admins.
@@ -19551,6 +19669,17 @@ method(object({
19551
19669
  }), object({ verified: boolean() }), {
19552
19670
  kind: "mutation",
19553
19671
  access: "view"
19672
+ }), method(object({}), object({ optionsJSON: record(string(), unknown()) }), {
19673
+ kind: "mutation",
19674
+ access: "view"
19675
+ }), method(object({
19676
+ /** AuthenticationResponseJSON from the browser. */
19677
+ response: record(string(), unknown()) }), object({
19678
+ verified: boolean(),
19679
+ userId: string().nullable()
19680
+ }), {
19681
+ kind: "mutation",
19682
+ access: "view"
19554
19683
  }), method(object({ userId: string() }), array(PasskeySummarySchema), { auth: "admin" }), method(object({
19555
19684
  userId: string(),
19556
19685
  credentialId: string()
@@ -19558,6 +19687,13 @@ method(object({
19558
19687
  kind: "mutation",
19559
19688
  auth: "admin",
19560
19689
  access: "delete"
19690
+ }), method(object({ userId: string() }), object({ enabled: boolean() }), { auth: "admin" }), method(object({
19691
+ userId: string(),
19692
+ enabled: boolean()
19693
+ }), object({ success: literal(true) }), {
19694
+ kind: "mutation",
19695
+ auth: "admin",
19696
+ access: "create"
19561
19697
  });
19562
19698
  /**
19563
19699
  * `videoclips` — the unified, navigable-clip surface for a camera.
@@ -20359,7 +20495,17 @@ var FaceInfoSchema = object({
20359
20495
  recognizedIdentityId: string().optional(),
20360
20496
  identityName: string().optional(),
20361
20497
  assigned: boolean(),
20362
- base64: string().optional()
20498
+ base64: string().optional(),
20499
+ /** Design B: the face bbox (pixel space) on the key frame — lets a detail
20500
+ * view draw the box over the native `keyFrameMediaKey` frame. Absent on
20501
+ * legacy rows written before design B. */
20502
+ faceBbox: BoundingBoxSchema.optional(),
20503
+ /** Design B: MediaStore key of the track's native-resolution key frame.
20504
+ * Fetch the native JPEG via the event-media data-plane
20505
+ * (`/addon/<addonId>/event-media/<keyFrameMediaKey>`). Absent when the
20506
+ * track produced no key frame (e.g. native/onboard source) — the UI falls
20507
+ * back to the inline `base64` face crop. */
20508
+ keyFrameMediaKey: string().optional()
20363
20509
  });
20364
20510
  var FaceFilterEnum = _enum([
20365
20511
  "unassigned",
@@ -24853,6 +24999,12 @@ Object.freeze({
24853
24999
  addonId: null,
24854
25000
  access: "view"
24855
25001
  },
25002
+ "pipelineAnalytics.getKeyEvents": {
25003
+ capName: "pipeline-analytics",
25004
+ capScope: "device",
25005
+ addonId: null,
25006
+ access: "view"
25007
+ },
24856
25008
  "pipelineAnalytics.getMotionEvents": {
24857
25009
  capName: "pipeline-analytics",
24858
25010
  capScope: "device",
@@ -25381,6 +25533,12 @@ Object.freeze({
25381
25533
  addonId: null,
25382
25534
  access: "view"
25383
25535
  },
25536
+ "pipelineRunner.getNativeCrop": {
25537
+ capName: "pipeline-runner",
25538
+ capScope: "system",
25539
+ addonId: null,
25540
+ access: "view"
25541
+ },
25384
25542
  "pipelineRunner.reportMotion": {
25385
25543
  capName: "pipeline-runner",
25386
25544
  capScope: "system",
@@ -25747,6 +25905,12 @@ Object.freeze({
25747
25905
  addonId: null,
25748
25906
  access: "view"
25749
25907
  },
25908
+ "snapshot.getSnapshotOverview": {
25909
+ capName: "snapshot",
25910
+ capScope: "device",
25911
+ addonId: null,
25912
+ access: "view"
25913
+ },
25750
25914
  "snapshot.invalidateCache": {
25751
25915
  capName: "snapshot",
25752
25916
  capScope: "device",
@@ -26425,6 +26589,12 @@ Object.freeze({
26425
26589
  addonId: null,
26426
26590
  access: "view"
26427
26591
  },
26592
+ "userPasskeys.beginDiscoverableAuthentication": {
26593
+ capName: "user-passkeys",
26594
+ capScope: "system",
26595
+ addonId: null,
26596
+ access: "view"
26597
+ },
26428
26598
  "userPasskeys.beginRegistration": {
26429
26599
  capName: "user-passkeys",
26430
26600
  capScope: "system",
@@ -26437,12 +26607,24 @@ Object.freeze({
26437
26607
  addonId: null,
26438
26608
  access: "view"
26439
26609
  },
26610
+ "userPasskeys.finishDiscoverableAuthentication": {
26611
+ capName: "user-passkeys",
26612
+ capScope: "system",
26613
+ addonId: null,
26614
+ access: "view"
26615
+ },
26440
26616
  "userPasskeys.finishRegistration": {
26441
26617
  capName: "user-passkeys",
26442
26618
  capScope: "system",
26443
26619
  addonId: null,
26444
26620
  access: "create"
26445
26621
  },
26622
+ "userPasskeys.getSecondFactorPreference": {
26623
+ capName: "user-passkeys",
26624
+ capScope: "system",
26625
+ addonId: null,
26626
+ access: "view"
26627
+ },
26446
26628
  "userPasskeys.listPasskeys": {
26447
26629
  capName: "user-passkeys",
26448
26630
  capScope: "system",
@@ -26455,6 +26637,12 @@ Object.freeze({
26455
26637
  addonId: null,
26456
26638
  access: "delete"
26457
26639
  },
26640
+ "userPasskeys.setSecondFactorPreference": {
26641
+ capName: "user-passkeys",
26642
+ capScope: "system",
26643
+ addonId: null,
26644
+ access: "create"
26645
+ },
26458
26646
  "vacuumControl.locate": {
26459
26647
  capName: "vacuum-control",
26460
26648
  capScope: "device",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-hikvision",
3
- "version": "1.1.21",
3
+ "version": "1.1.22",
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",