camstack 1.1.26 → 1.1.28

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.
@@ -14522,7 +14522,7 @@ function date4(params) {
14522
14522
  // ../../node_modules/zod/v4/classic/external.js
14523
14523
  config(en_default());
14524
14524
 
14525
- // ../types/dist/sleep-Br7r_3fq.mjs
14525
+ // ../types/dist/sleep-B3OHhFkL.mjs
14526
14526
  var WELL_KNOWN_TABS = [
14527
14527
  {
14528
14528
  id: "overview",
@@ -15540,6 +15540,13 @@ var RecordingRetentionSchema = external_exports.object({
15540
15540
  maxAgeDays: external_exports.number().min(0).optional(),
15541
15541
  maxSizeGb: external_exports.number().min(0).optional()
15542
15542
  });
15543
+ var ScrubThumbnailPresetSchema = external_exports.enum([
15544
+ "minimal",
15545
+ "low",
15546
+ "standard",
15547
+ "high",
15548
+ "max"
15549
+ ]);
15543
15550
  var RecordingConfigSchema = external_exports.object({
15544
15551
  enabled: external_exports.boolean(),
15545
15552
  /** Authoritative storage mode. Absent on legacy targets → derived once via
@@ -15569,7 +15576,14 @@ var RecordingConfigSchema = external_exports.object({
15569
15576
  * derived into bands once via `migrateConfigToBands`.
15570
15577
  */
15571
15578
  bands: external_exports.array(RecordingBandSchema).optional(),
15572
- retention: RecordingRetentionSchema.optional()
15579
+ retention: RecordingRetentionSchema.optional(),
15580
+ /**
15581
+ * Per-camera scrub-thumbnail fidelity preset (resolution + JPEG quality for
15582
+ * timeline-scrub sprite previews). Absent = `standard`. Applies to NEW
15583
+ * windows only — existing sheets are immutable, and each window's index
15584
+ * carries its own tile dims so mixed-preset history renders correctly.
15585
+ */
15586
+ scrubThumbnails: ScrubThumbnailPresetSchema.optional()
15573
15587
  });
15574
15588
  var StorageLocationTypeSchema = external_exports.string().regex(/^[a-z][a-zA-Z0-9-]*$/);
15575
15589
  var StorageLocationSchema = external_exports.object({
@@ -18401,7 +18415,10 @@ var doorbellCapability = {
18401
18415
  scope: "device",
18402
18416
  deviceNative: true,
18403
18417
  mode: "singleton",
18404
- deviceTypes: [DeviceType.Button],
18418
+ kind: "wrapper",
18419
+ defaultActive: false,
18420
+ deviceTypes: [DeviceType.Button, DeviceType.Camera],
18421
+ exposesDeviceSettings: true,
18405
18422
  methods: {},
18406
18423
  events: {
18407
18424
  /**
@@ -23740,6 +23757,13 @@ var ConfigEntrySchema2 = external_exports.object({
23740
23757
  value: external_exports.unknown(),
23741
23758
  description: external_exports.string().optional()
23742
23759
  });
23760
+ var DeviceLinkModeSchema = external_exports.enum(["auto", "manual"]);
23761
+ var LinkedDeviceSchema = external_exports.object({
23762
+ deviceId: external_exports.number(),
23763
+ name: external_exports.string(),
23764
+ location: external_exports.string().nullable(),
23765
+ features: external_exports.array(external_exports.string())
23766
+ });
23743
23767
  var SavedDeviceRowSchema = external_exports.object({
23744
23768
  /** Numeric id reserved at allocateDeviceId time. */
23745
23769
  id: external_exports.number(),
@@ -23842,6 +23866,7 @@ var deviceManagerCapability = {
23842
23866
  name: "device-manager",
23843
23867
  scope: "system",
23844
23868
  mode: "singleton",
23869
+ exposesDeviceSettings: true,
23845
23870
  methods: {
23846
23871
  /** Reserve (or re-resolve) a progressive numeric id for `(addonId, stableId)`.
23847
23872
  * Idempotent: returns the existing id if one is already persisted for the
@@ -24092,6 +24117,19 @@ var deviceManagerCapability = {
24092
24117
  getDevice: method(external_exports.object({ deviceId: external_exports.number() }), DeviceInfoSchema.nullable()),
24093
24118
  /** List children of a parent device (by parent numeric id). */
24094
24119
  getChildren: method(external_exports.object({ parentDeviceId: external_exports.number() }), external_exports.array(DeviceInfoSchema)),
24120
+ /**
24121
+ * Resolve the devices LINKED to a camera — the single policy authority
24122
+ * both consumers call (viewer devices panel + pipeline-analytics event
24123
+ * kinds/ingest). Device-tree children are ALWAYS included; mode 'auto'
24124
+ * (default) adds every device sharing the camera's non-null `location`,
24125
+ * mode 'manual' adds the persisted manual list instead. Excludes the
24126
+ * camera itself; deduped. Configuration is standard per-device settings
24127
+ * (see the module docblock) — there are no bespoke link mutations.
24128
+ */
24129
+ getLinkedDevices: method(external_exports.object({ deviceId: external_exports.number() }), external_exports.object({
24130
+ mode: DeviceLinkModeSchema,
24131
+ devices: external_exports.array(LinkedDeviceSchema)
24132
+ })),
24095
24133
  /** Get stream sources for a camera device. */
24096
24134
  getStreamSources: method(external_exports.object({ deviceId: external_exports.number() }), external_exports.array(StreamSourceEntrySchema$1)),
24097
24135
  /** Get config entries (key + value + description) for a device. */
@@ -25544,6 +25582,55 @@ var EventKindSchema = external_exports.enum([
25544
25582
  "object",
25545
25583
  "audio"
25546
25584
  ]);
25585
+ var TrackZoneFilterSchema = external_exports.discriminatedUnion("kind", [MaskRectShapeSchema, MaskPolygonShapeSchema]);
25586
+ var EventKindIconSchema = external_exports.enum([
25587
+ "motion",
25588
+ "audio",
25589
+ "person",
25590
+ "vehicle",
25591
+ "animal",
25592
+ "door",
25593
+ "pir",
25594
+ "smoke",
25595
+ "water",
25596
+ "button",
25597
+ "generic"
25598
+ ]);
25599
+ var EventKindCategorySchema = external_exports.enum([
25600
+ "motion",
25601
+ "audio",
25602
+ "detection",
25603
+ "sensor",
25604
+ "custom"
25605
+ ]);
25606
+ var EventKindDescriptorSchema = external_exports.object({
25607
+ /** Stable kind id (e.g. 'motion', 'person', 'contact'). */
25608
+ kind: external_exports.string(),
25609
+ label: external_exports.string(),
25610
+ /** Hex color for timeline/legend rendering. */
25611
+ color: external_exports.string(),
25612
+ icon: EventKindIconSchema,
25613
+ category: EventKindCategorySchema,
25614
+ /** Which cap + device contributes this kind. For built-ins the camera
25615
+ * itself; for sensor kinds the LINKED source device. */
25616
+ source: external_exports.object({
25617
+ capName: external_exports.string(),
25618
+ deviceId: external_exports.number()
25619
+ })
25620
+ });
25621
+ var SensorEventSchema = external_exports.object({
25622
+ id: external_exports.string(),
25623
+ /** The CAMERA the event is attributed to (a sensor linked to N cameras
25624
+ * yields N rows, one per camera). */
25625
+ deviceId: external_exports.number(),
25626
+ /** The linked sensor device whose state changed. */
25627
+ sourceDeviceId: external_exports.number(),
25628
+ /** Event kind id — matches an `EventKindDescriptor.kind`. */
25629
+ kind: external_exports.string(),
25630
+ /** Snapshot of the sensor cap's runtime-state slice at the change. */
25631
+ value: external_exports.record(external_exports.string(), external_exports.unknown()).nullable(),
25632
+ timestamp: external_exports.number()
25633
+ });
25547
25634
  var TrackPositionSchema = external_exports.object({
25548
25635
  x: external_exports.number(),
25549
25636
  y: external_exports.number(),
@@ -25556,6 +25643,13 @@ var TrackSnapshotSchema = external_exports.object({
25556
25643
  /** MediaStore key; resolve via `getTrackMedia({ trackId })`. */
25557
25644
  mediaKey: external_exports.string()
25558
25645
  });
25646
+ var TrackEnvelopeSchema = external_exports.object({
25647
+ minX: external_exports.number(),
25648
+ minY: external_exports.number(),
25649
+ maxX: external_exports.number(),
25650
+ maxY: external_exports.number()
25651
+ });
25652
+ var TrackProjectionSchema = external_exports.enum(["full", "slim"]);
25559
25653
  var TrackAudioLabelSchema = external_exports.object({
25560
25654
  label: external_exports.string(),
25561
25655
  /** Highest classification score observed across the label's episodes. */
@@ -25600,7 +25694,11 @@ var TrackSchema = external_exports.object({
25600
25694
  /** Audio-classification labels heard on the camera during the track's
25601
25695
  * life (score ≥ device `classificationMinScore`), aggregated per label.
25602
25696
  * Absent on legacy rows / tracks with no confident audio. */
25603
- audioLabels: external_exports.array(TrackAudioLabelSchema).readonly().optional()
25697
+ audioLabels: external_exports.array(TrackAudioLabelSchema).readonly().optional(),
25698
+ /** Normalized 0..1 trajectory envelope (see {@link TrackEnvelopeSchema}).
25699
+ * Populated from the persisted envelope columns on historical reads;
25700
+ * absent on legacy rows, dims-less tracks and active (in-RAM) tracks. */
25701
+ envelope: TrackEnvelopeSchema.optional()
25604
25702
  });
25605
25703
  var BaseEventFields = {
25606
25704
  id: external_exports.string(),
@@ -25702,11 +25800,13 @@ var MediaFileSchema = external_exports.object({
25702
25800
  sizeBytes: external_exports.number(),
25703
25801
  timestamp: external_exports.number()
25704
25802
  });
25803
+ var DEFAULT_EVENT_QUERY_LIMIT = 1e3;
25804
+ var MAX_EVENT_QUERY_LIMIT = 5e3;
25705
25805
  var DeviceEventQueryInput = external_exports.object({
25706
25806
  deviceId: external_exports.number(),
25707
25807
  since: external_exports.number().optional(),
25708
25808
  until: external_exports.number().optional(),
25709
- limit: external_exports.number().int().min(1).max(5e3).default(1e3),
25809
+ limit: external_exports.number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT),
25710
25810
  /** `slim` drops heavy JSON fields (regions/bbox/zones) and carries an
25711
25811
  * optional `mediaUrl` (populated by B5). `full` (default) keeps today's
25712
25812
  * exact behaviour. Callers may omit this field — the store defaults to
@@ -25714,6 +25814,27 @@ var DeviceEventQueryInput = external_exports.object({
25714
25814
  projection: external_exports.enum(["full", "slim"]).optional()
25715
25815
  });
25716
25816
  var ObjectEventQueryInput = DeviceEventQueryInput.extend({ classFilter: external_exports.string().optional() });
25817
+ var RecentTracksQueryInput = external_exports.object({
25818
+ /** Devices to merge. An empty array yields `{ tracks: [], nextCursor: null }`. */
25819
+ deviceIds: external_exports.array(external_exports.number()),
25820
+ /** Window lower bound on `lastSeen` (inclusive). */
25821
+ since: external_exports.number().optional(),
25822
+ /** Window upper bound on `lastSeen` (inclusive). */
25823
+ until: external_exports.number().optional(),
25824
+ /** Page size. Default 200, max 1000. */
25825
+ limit: external_exports.number().int().min(1).max(1e3).default(200),
25826
+ /** Opaque continuation cursor from a previous page's `nextCursor`.
25827
+ * Encodes the (lastSeen, trackId) sort position — treat as opaque. */
25828
+ cursor: external_exports.string().optional(),
25829
+ /** See {@link TrackProjectionSchema}. Default `full`. */
25830
+ projection: TrackProjectionSchema.optional()
25831
+ });
25832
+ var RecentTracksPageSchema = external_exports.object({
25833
+ /** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
25834
+ tracks: external_exports.array(TrackSchema).readonly(),
25835
+ /** Cursor for the next page, or null when this page is the last. */
25836
+ nextCursor: external_exports.string().nullable()
25837
+ });
25717
25838
  var KeyEventQueryInput = external_exports.object({
25718
25839
  deviceId: external_exports.number(),
25719
25840
  /** Window lower bound (track firstSeen ≥ since). */
@@ -25810,8 +25931,27 @@ var pipelineAnalyticsCapability = {
25810
25931
  deviceId: external_exports.number(),
25811
25932
  since: external_exports.number().optional(),
25812
25933
  until: external_exports.number().optional(),
25813
- limit: external_exports.number().optional()
25934
+ limit: external_exports.number().optional(),
25935
+ /** Spatial filter — only tracks whose trajectory intersects the zone
25936
+ * (normalized 0..1 rect or polygon). SQL-prefiltered on the persisted
25937
+ * envelope columns, then precisely tested per position. Tracks with
25938
+ * an unknown envelope (no frame dims at persist time) always match. */
25939
+ zone: TrackZoneFilterSchema.optional(),
25940
+ /** See {@link TrackProjectionSchema}. Default `full` (backward
25941
+ * compatible — omitting the field keeps today's exact behaviour). */
25942
+ projection: TrackProjectionSchema.optional()
25814
25943
  }), external_exports.array(TrackSchema).readonly()),
25944
+ /**
25945
+ * Batched cluster-wide track listing — ONE call for the events page /
25946
+ * reel first paint instead of a per-camera `listTracks` fan-out. Merges
25947
+ * the persisted completed tracks of every requested device, sorted by
25948
+ * `lastSeen` DESC with a stable (lastSeen, trackId) cursor. Per-device
25949
+ * indexed pages (`idx_tracks_device_lastSeen`) are k-way merged
25950
+ * provider-side; `projection: 'slim'` drops the heavy `positions[]` /
25951
+ * `snapshots[]` JSON (returned as empty arrays). Active in-RAM tracks
25952
+ * are not included (same contract as `listTracks`).
25953
+ */
25954
+ listRecentTracks: method(RecentTracksQueryInput, RecentTracksPageSchema),
25815
25955
  clearTracks: method(external_exports.object({ deviceId: external_exports.number() }), external_exports.void(), {
25816
25956
  kind: "mutation",
25817
25957
  auth: "admin"
@@ -25820,6 +25960,26 @@ var pipelineAnalyticsCapability = {
25820
25960
  getObjectEvents: method(ObjectEventQueryInput, external_exports.array(ObjectEventSchema).readonly()),
25821
25961
  getAudioEvents: method(DeviceEventQueryInput, external_exports.array(AudioEventSchema).readonly()),
25822
25962
  /**
25963
+ * Every event kind the device can produce: built-ins (motion + audio),
25964
+ * detection classes actually observed for the device (from the track
25965
+ * history), and sensor kinds contributed by LINKED devices (resolved via
25966
+ * `device-manager.getLinkedDevices`, mapped through `EVENT_KIND_BY_CAP`).
25967
+ */
25968
+ listEventKinds: method(external_exports.object({ deviceId: external_exports.number() }), external_exports.array(EventKindDescriptorSchema).readonly()),
25969
+ /**
25970
+ * Sensor-event history for a camera: state changes of LINKED sensor
25971
+ * devices, attributed to the camera at ingest time (one row per linked
25972
+ * camera). Mirrors `getAudioEvents` query semantics; `kinds` narrows to
25973
+ * a kind subset.
25974
+ */
25975
+ getSensorEvents: method(external_exports.object({
25976
+ deviceId: external_exports.number(),
25977
+ since: external_exports.number().optional(),
25978
+ until: external_exports.number().optional(),
25979
+ kinds: external_exports.array(external_exports.string()).optional(),
25980
+ limit: external_exports.number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT)
25981
+ }), external_exports.array(SensorEventSchema).readonly()),
25982
+ /**
25823
25983
  * Importance-ranked highlights for a device+window. Queries completed
25824
25984
  * tracks by (deviceId, firstSeen ∈ [since,until]), scores each (or reuses
25825
25985
  * the persisted score), filters by minImportance/classFilter, orders by
@@ -29758,7 +29918,8 @@ var LocateSegmentResultSchema = external_exports.discriminatedUnion("kind", [ext
29758
29918
  bytes: external_exports.number()
29759
29919
  }), external_exports.object({
29760
29920
  kind: external_exports.literal("gap"),
29761
- nearestEdgeMs: external_exports.number().nullable()
29921
+ nearestEdgeMs: external_exports.number().nullable(),
29922
+ prevEndMs: external_exports.number().nullable().optional()
29762
29923
  })]);
29763
29924
  var ReadSegmentBytesResultSchema = external_exports.object({ data: external_exports.instanceof(Uint8Array) });
29764
29925
  var recordingCapability = {
@@ -31381,6 +31542,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
31381
31542
  addonId: null,
31382
31543
  access: "view"
31383
31544
  },
31545
+ "deviceManager.getLinkedDevices": {
31546
+ capName: "device-manager",
31547
+ capScope: "system",
31548
+ addonId: null,
31549
+ access: "view"
31550
+ },
31384
31551
  "deviceManager.getRoleDisplayDefaults": {
31385
31552
  capName: "device-manager",
31386
31553
  capScope: "system",
@@ -32935,6 +33102,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
32935
33102
  addonId: null,
32936
33103
  access: "view"
32937
33104
  },
33105
+ "pipelineAnalytics.getSensorEvents": {
33106
+ capName: "pipeline-analytics",
33107
+ capScope: "device",
33108
+ addonId: null,
33109
+ access: "view"
33110
+ },
32938
33111
  "pipelineAnalytics.getTrack": {
32939
33112
  capName: "pipeline-analytics",
32940
33113
  capScope: "device",
@@ -32947,6 +33120,18 @@ var METHOD_ACCESS_MAP = Object.freeze({
32947
33120
  addonId: null,
32948
33121
  access: "view"
32949
33122
  },
33123
+ "pipelineAnalytics.listEventKinds": {
33124
+ capName: "pipeline-analytics",
33125
+ capScope: "device",
33126
+ addonId: null,
33127
+ access: "view"
33128
+ },
33129
+ "pipelineAnalytics.listRecentTracks": {
33130
+ capName: "pipeline-analytics",
33131
+ capScope: "device",
33132
+ addonId: null,
33133
+ access: "view"
33134
+ },
32950
33135
  "pipelineAnalytics.listTracks": {
32951
33136
  capName: "pipeline-analytics",
32952
33137
  capScope: "device",
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runDiscover
4
- } from "./chunk-VLAF6UXF.js";
4
+ } from "./chunk-REYL2W37.js";
5
5
  import "./chunk-K3NQKI34.js";
6
6
 
7
7
  // src/cli.ts
@@ -1079,7 +1079,7 @@ function isUnknown(_value) {
1079
1079
  return true;
1080
1080
  }
1081
1081
  async function resolveServerInteractive(presetNamespace) {
1082
- const { discoverNodes, resolveHubFromDiscovered, filterHubNodes, DEFAULT_HUB_HTTPS_PORT } = await import("./discover-BJ6SMXC2.js");
1082
+ const { discoverNodes, resolveHubFromDiscovered, filterHubNodes, DEFAULT_HUB_HTTPS_PORT } = await import("./discover-OTKOLUJJ.js");
1083
1083
  if (presetNamespace) {
1084
1084
  const spinner4 = clack.spinner();
1085
1085
  spinner4.start(`Discovering hub on LAN (namespace "${presetNamespace}")`);
@@ -5,7 +5,7 @@ import {
5
5
  filterHubNodes,
6
6
  resolveHubFromDiscovered,
7
7
  runDiscover
8
- } from "./chunk-VLAF6UXF.js";
8
+ } from "./chunk-REYL2W37.js";
9
9
  import "./chunk-K3NQKI34.js";
10
10
  export {
11
11
  DEFAULT_HUB_HTTPS_PORT,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "camstack",
3
- "version": "1.1.26",
3
+ "version": "1.1.28",
4
4
  "description": "CLI tool for managing and running CamStack server",
5
5
  "keywords": [
6
6
  "camstack",