@camstack/system 1.1.51 → 1.1.52

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 (58) hide show
  1. package/dist/addon-runner.js +2 -2
  2. package/dist/addon-runner.mjs +2 -2
  3. package/dist/addon-utils.js +1 -1
  4. package/dist/addon-utils.mjs +1 -1
  5. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
  6. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
  7. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
  8. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
  9. package/dist/builtins/alerts/alerts.addon.js +1 -1
  10. package/dist/builtins/alerts/alerts.addon.mjs +1 -1
  11. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
  12. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
  13. package/dist/builtins/console-logging/index.js +1 -1
  14. package/dist/builtins/console-logging/index.mjs +1 -1
  15. package/dist/builtins/device-manager/device-linked-devices.d.ts +47 -0
  16. package/dist/builtins/device-manager/device-manager.addon.js +1840 -1712
  17. package/dist/builtins/device-manager/device-manager.addon.mjs +1840 -1712
  18. package/dist/builtins/doorbell/index.d.ts +2 -0
  19. package/dist/builtins/doorbell/index.js +8 -0
  20. package/dist/builtins/doorbell/index.mjs +2 -0
  21. package/dist/builtins/doorbell/trigger-engine.d.ts +69 -0
  22. package/dist/builtins/doorbell/virtual-doorbell.addon.d.ts +87 -0
  23. package/dist/builtins/doorbell/virtual-doorbell.addon.js +489 -0
  24. package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +483 -0
  25. package/dist/builtins/hub-forwarder/index.js +1 -1
  26. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  27. package/dist/builtins/local-auth/local-auth.addon.js +2 -2
  28. package/dist/builtins/local-auth/local-auth.addon.mjs +2 -2
  29. package/dist/builtins/local-network/local-network.addon.js +1 -1
  30. package/dist/builtins/local-network/local-network.addon.mjs +1 -1
  31. package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
  32. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
  33. package/dist/builtins/platform-probe/index.js +1 -1
  34. package/dist/builtins/platform-probe/index.mjs +1 -1
  35. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  36. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  37. package/dist/builtins/snapshot/index.js +1 -1
  38. package/dist/builtins/snapshot/index.mjs +1 -1
  39. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
  40. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  41. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +1 -1
  42. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +1 -1
  43. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
  44. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
  45. package/dist/builtins/system-config/system-config.addon.js +4 -4
  46. package/dist/builtins/system-config/system-config.addon.mjs +4 -4
  47. package/dist/builtins/winston-logging/index.js +1 -1
  48. package/dist/builtins/winston-logging/index.mjs +1 -1
  49. package/dist/{dist-BWQX9yUj.mjs → dist-B_PSvr-m.mjs} +228 -12
  50. package/dist/{dist-C3uHEBtP.js → dist-BduBhv6N.js} +233 -11
  51. package/dist/http/file-data-plane.d.ts +8 -0
  52. package/dist/index.js +3 -3
  53. package/dist/index.mjs +3 -3
  54. package/dist/{manifest-python-deps-BA6KA9If.mjs → manifest-python-deps-CIyvuHAB.mjs} +1 -1
  55. package/dist/{manifest-python-deps-CVcJ9hDX.js → manifest-python-deps-CPAMH5gV.js} +1 -1
  56. package/dist/{model-download-service-C-IHWnXx.mjs → model-download-service-Cp9f4dk6.mjs} +1 -1
  57. package/dist/{model-download-service-D-Umz4-L.js → model-download-service-hf0ookyy.js} +1 -1
  58. package/package.json +13 -1
@@ -1,5 +1,5 @@
1
1
  let zod = require("zod");
2
- //#region ../types/dist/event-category-CFZs3jI4.mjs
2
+ //#region ../types/dist/event-category-H4AVePnn.mjs
3
3
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
4
4
  EventCategory["SystemBoot"] = "system.boot";
5
5
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -149,6 +149,9 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
149
149
  EventCategory["RecordingSegmentWritten"] = "recording.segment.written";
150
150
  EventCategory["RecordingPolicyFallback"] = "recording.policy.fallback";
151
151
  EventCategory["RecordingRetentionCompleted"] = "recording.retention.completed";
152
+ /** Runner-sampled scrub thumbnail (~1/5 s/camera). Telemetry (D8): a lost
153
+ * thumb is a scrub gap the recorder's keyframe backfill covers. */
154
+ EventCategory["RecordingThumbSampled"] = "recording.thumb-sampled";
152
155
  EventCategory["DetectionEvent"] = "detection.event";
153
156
  EventCategory["SessionTrackNew"] = "session.track.new";
154
157
  EventCategory["SessionTrackExpired"] = "session.track.expired";
@@ -6903,10 +6906,23 @@ var deviceDiscoveryCapability = {
6903
6906
  }
6904
6907
  };
6905
6908
  /**
6906
- * Doorbell button cap. Installed on a `DeviceType.Button` accessory
6907
- * with `role: DeviceRole.Doorbell`. Emits an `onPressed` event every
6908
- * time the firmware pushes a ring; status tracks the last press and
6909
- * a pressCount since start (diagnostic).
6909
+ * Doorbell button cap. Two kinds of providers coexist behind this cap
6910
+ * name (same pattern as `snapshot`):
6911
+ *
6912
+ * - **Native** providers: registered per-device by device-driver
6913
+ * addons via `ctx.registerNativeCap` — either on a
6914
+ * `DeviceType.Button` accessory with `role: DeviceRole.Doorbell`,
6915
+ * or directly on the camera (Reolink registers at camera level).
6916
+ * Emits an `onPressed` event every time the firmware pushes a
6917
+ * ring; status tracks the last press and a pressCount since start
6918
+ * (diagnostic).
6919
+ *
6920
+ * - **Wrapper** provider: the `virtual-doorbell` system builtin
6921
+ * (`@camstack/system/builtins/doorbell`). Turns ANY binary-ish
6922
+ * device (contact / switch / event-emitter …) into a doorbell for
6923
+ * a camera. `defaultActive: false` — the operator explicitly binds
6924
+ * it per camera in the device-bindings UI, then picks the source
6925
+ * device + trigger in the per-device settings.
6910
6926
  *
6911
6927
  * The DeviceEventPropagator re-emits `onPressed` on the camera parent
6912
6928
  * — subscribers listening at the camera level receive ring events
@@ -6927,7 +6943,10 @@ var doorbellCapability = {
6927
6943
  scope: "device",
6928
6944
  deviceNative: true,
6929
6945
  mode: "singleton",
6930
- deviceTypes: [DeviceType.Button],
6946
+ kind: "wrapper",
6947
+ defaultActive: false,
6948
+ deviceTypes: [DeviceType.Button, DeviceType.Camera],
6949
+ exposesDeviceSettings: true,
6931
6950
  methods: {},
6932
6951
  events: {
6933
6952
  /**
@@ -13565,6 +13584,14 @@ var ConfigEntrySchema = zod.z.object({
13565
13584
  value: zod.z.unknown(),
13566
13585
  description: zod.z.string().optional()
13567
13586
  });
13587
+ var DeviceLinkModeSchema = zod.z.enum(["auto", "manual"]);
13588
+ /** One resolved linked device — the compact projection consumers need. */
13589
+ var LinkedDeviceSchema = zod.z.object({
13590
+ deviceId: zod.z.number(),
13591
+ name: zod.z.string(),
13592
+ location: zod.z.string().nullable(),
13593
+ features: zod.z.array(zod.z.string())
13594
+ });
13568
13595
  var SavedDeviceRowSchema = zod.z.object({
13569
13596
  /** Numeric id reserved at allocateDeviceId time. */
13570
13597
  id: zod.z.number(),
@@ -13672,6 +13699,7 @@ var deviceManagerCapability = {
13672
13699
  name: "device-manager",
13673
13700
  scope: "system",
13674
13701
  mode: "singleton",
13702
+ exposesDeviceSettings: true,
13675
13703
  methods: {
13676
13704
  /** Reserve (or re-resolve) a progressive numeric id for `(addonId, stableId)`.
13677
13705
  * Idempotent: returns the existing id if one is already persisted for the
@@ -13922,6 +13950,19 @@ var deviceManagerCapability = {
13922
13950
  getDevice: method(zod.z.object({ deviceId: zod.z.number() }), DeviceInfoSchema.nullable()),
13923
13951
  /** List children of a parent device (by parent numeric id). */
13924
13952
  getChildren: method(zod.z.object({ parentDeviceId: zod.z.number() }), zod.z.array(DeviceInfoSchema)),
13953
+ /**
13954
+ * Resolve the devices LINKED to a camera — the single policy authority
13955
+ * both consumers call (viewer devices panel + pipeline-analytics event
13956
+ * kinds/ingest). Device-tree children are ALWAYS included; mode 'auto'
13957
+ * (default) adds every device sharing the camera's non-null `location`,
13958
+ * mode 'manual' adds the persisted manual list instead. Excludes the
13959
+ * camera itself; deduped. Configuration is standard per-device settings
13960
+ * (see the module docblock) — there are no bespoke link mutations.
13961
+ */
13962
+ getLinkedDevices: method(zod.z.object({ deviceId: zod.z.number() }), zod.z.object({
13963
+ mode: DeviceLinkModeSchema,
13964
+ devices: zod.z.array(LinkedDeviceSchema)
13965
+ })),
13925
13966
  /** Get stream sources for a camera device. */
13926
13967
  getStreamSources: method(zod.z.object({ deviceId: zod.z.number() }), zod.z.array(StreamSourceEntrySchema$1)),
13927
13968
  /** Get config entries (key + value + description) for a device. */
@@ -15640,6 +15681,61 @@ var EventKindSchema = zod.z.enum([
15640
15681
  "object",
15641
15682
  "audio"
15642
15683
  ]);
15684
+ /**
15685
+ * Spatial filter for `listTracks` — the rect + polygon variants of the shared
15686
+ * MaskShape vocabulary (see `mask-shape.ts`). Coordinates are NORMALIZED 0..1
15687
+ * of the camera frame (top-left origin), matching the drawing-plane editor.
15688
+ */
15689
+ var TrackZoneFilterSchema = zod.z.discriminatedUnion("kind", [MaskRectShapeSchema, MaskPolygonShapeSchema]);
15690
+ /** Closed icon vocabulary so clients render a known glyph per kind. */
15691
+ var EventKindIconSchema = zod.z.enum([
15692
+ "motion",
15693
+ "audio",
15694
+ "person",
15695
+ "vehicle",
15696
+ "animal",
15697
+ "door",
15698
+ "pir",
15699
+ "smoke",
15700
+ "water",
15701
+ "button",
15702
+ "generic"
15703
+ ]);
15704
+ var EventKindCategorySchema = zod.z.enum([
15705
+ "motion",
15706
+ "audio",
15707
+ "detection",
15708
+ "sensor",
15709
+ "custom"
15710
+ ]);
15711
+ var EventKindDescriptorSchema = zod.z.object({
15712
+ /** Stable kind id (e.g. 'motion', 'person', 'contact'). */
15713
+ kind: zod.z.string(),
15714
+ label: zod.z.string(),
15715
+ /** Hex color for timeline/legend rendering. */
15716
+ color: zod.z.string(),
15717
+ icon: EventKindIconSchema,
15718
+ category: EventKindCategorySchema,
15719
+ /** Which cap + device contributes this kind. For built-ins the camera
15720
+ * itself; for sensor kinds the LINKED source device. */
15721
+ source: zod.z.object({
15722
+ capName: zod.z.string(),
15723
+ deviceId: zod.z.number()
15724
+ })
15725
+ });
15726
+ var SensorEventSchema = zod.z.object({
15727
+ id: zod.z.string(),
15728
+ /** The CAMERA the event is attributed to (a sensor linked to N cameras
15729
+ * yields N rows, one per camera). */
15730
+ deviceId: zod.z.number(),
15731
+ /** The linked sensor device whose state changed. */
15732
+ sourceDeviceId: zod.z.number(),
15733
+ /** Event kind id — matches an `EventKindDescriptor.kind`. */
15734
+ kind: zod.z.string(),
15735
+ /** Snapshot of the sensor cap's runtime-state slice at the change. */
15736
+ value: zod.z.record(zod.z.string(), zod.z.unknown()).nullable(),
15737
+ timestamp: zod.z.number()
15738
+ });
15643
15739
  var TrackPositionSchema = zod.z.object({
15644
15740
  x: zod.z.number(),
15645
15741
  y: zod.z.number(),
@@ -15653,6 +15749,30 @@ var TrackSnapshotSchema = zod.z.object({
15653
15749
  mediaKey: zod.z.string()
15654
15750
  });
15655
15751
  /**
15752
+ * Normalized 0..1 trajectory envelope (min/max over every position bbox,
15753
+ * divided by the track's detection-frame dims), computed at persist time.
15754
+ * Absent when the frame dims were unknown when the track was persisted
15755
+ * (legacy rows / dims-less sources) and on active (in-RAM) tracks.
15756
+ */
15757
+ var TrackEnvelopeSchema = zod.z.object({
15758
+ minX: zod.z.number(),
15759
+ minY: zod.z.number(),
15760
+ maxX: zod.z.number(),
15761
+ maxY: zod.z.number()
15762
+ });
15763
+ /**
15764
+ * Row projection for track list queries. `full` (default) returns the
15765
+ * complete Track including the frame-rate `positions[]` history and the
15766
+ * `snapshots[]` references — megabytes across a page of tracks. `slim`
15767
+ * keeps every scalar the list surfaces actually render (ids, class(es),
15768
+ * label / audioLabels / importance enrichment, firstSeen/lastSeen, state,
15769
+ * zonesVisited, bestEventId, envelope) and returns `positions` /
15770
+ * `snapshots` as EMPTY arrays — detail views re-fetch the full row via
15771
+ * `getTrack`. Mirrors the event-store `projection` convention
15772
+ * (`getObjectEvents` et al.).
15773
+ */
15774
+ var TrackProjectionSchema = zod.z.enum(["full", "slim"]);
15775
+ /**
15656
15776
  * One audio-classification label heard on the track's camera while the
15657
15777
  * track was alive, aggregated per label. An "episode" is one persisted
15658
15778
  * audio event (the confident-classification path: score ≥ the device's
@@ -15703,7 +15823,11 @@ var TrackSchema = zod.z.object({
15703
15823
  /** Audio-classification labels heard on the camera during the track's
15704
15824
  * life (score ≥ device `classificationMinScore`), aggregated per label.
15705
15825
  * Absent on legacy rows / tracks with no confident audio. */
15706
- audioLabels: zod.z.array(TrackAudioLabelSchema).readonly().optional()
15826
+ audioLabels: zod.z.array(TrackAudioLabelSchema).readonly().optional(),
15827
+ /** Normalized 0..1 trajectory envelope (see {@link TrackEnvelopeSchema}).
15828
+ * Populated from the persisted envelope columns on historical reads;
15829
+ * absent on legacy rows, dims-less tracks and active (in-RAM) tracks. */
15830
+ envelope: TrackEnvelopeSchema.optional()
15707
15831
  });
15708
15832
  var BaseEventFields = {
15709
15833
  id: zod.z.string(),
@@ -15813,11 +15937,13 @@ var MediaFileSchema = zod.z.object({
15813
15937
  sizeBytes: zod.z.number(),
15814
15938
  timestamp: zod.z.number()
15815
15939
  });
15940
+ var DEFAULT_EVENT_QUERY_LIMIT = 1e3;
15941
+ var MAX_EVENT_QUERY_LIMIT = 5e3;
15816
15942
  var DeviceEventQueryInput = zod.z.object({
15817
15943
  deviceId: zod.z.number(),
15818
15944
  since: zod.z.number().optional(),
15819
15945
  until: zod.z.number().optional(),
15820
- limit: zod.z.number().int().min(1).max(5e3).default(1e3),
15946
+ limit: zod.z.number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT),
15821
15947
  /** `slim` drops heavy JSON fields (regions/bbox/zones) and carries an
15822
15948
  * optional `mediaUrl` (populated by B5). `full` (default) keeps today's
15823
15949
  * exact behaviour. Callers may omit this field — the store defaults to
@@ -15825,6 +15951,27 @@ var DeviceEventQueryInput = zod.z.object({
15825
15951
  projection: zod.z.enum(["full", "slim"]).optional()
15826
15952
  });
15827
15953
  var ObjectEventQueryInput = DeviceEventQueryInput.extend({ classFilter: zod.z.string().optional() });
15954
+ var RecentTracksQueryInput = zod.z.object({
15955
+ /** Devices to merge. An empty array yields `{ tracks: [], nextCursor: null }`. */
15956
+ deviceIds: zod.z.array(zod.z.number()),
15957
+ /** Window lower bound on `lastSeen` (inclusive). */
15958
+ since: zod.z.number().optional(),
15959
+ /** Window upper bound on `lastSeen` (inclusive). */
15960
+ until: zod.z.number().optional(),
15961
+ /** Page size. Default 200, max 1000. */
15962
+ limit: zod.z.number().int().min(1).max(1e3).default(200),
15963
+ /** Opaque continuation cursor from a previous page's `nextCursor`.
15964
+ * Encodes the (lastSeen, trackId) sort position — treat as opaque. */
15965
+ cursor: zod.z.string().optional(),
15966
+ /** See {@link TrackProjectionSchema}. Default `full`. */
15967
+ projection: TrackProjectionSchema.optional()
15968
+ });
15969
+ var RecentTracksPageSchema = zod.z.object({
15970
+ /** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
15971
+ tracks: zod.z.array(TrackSchema).readonly(),
15972
+ /** Cursor for the next page, or null when this page is the last. */
15973
+ nextCursor: zod.z.string().nullable()
15974
+ });
15828
15975
  var KeyEventQueryInput = zod.z.object({
15829
15976
  deviceId: zod.z.number(),
15830
15977
  /** Window lower bound (track firstSeen ≥ since). */
@@ -15921,8 +16068,27 @@ var pipelineAnalyticsCapability = {
15921
16068
  deviceId: zod.z.number(),
15922
16069
  since: zod.z.number().optional(),
15923
16070
  until: zod.z.number().optional(),
15924
- limit: zod.z.number().optional()
16071
+ limit: zod.z.number().optional(),
16072
+ /** Spatial filter — only tracks whose trajectory intersects the zone
16073
+ * (normalized 0..1 rect or polygon). SQL-prefiltered on the persisted
16074
+ * envelope columns, then precisely tested per position. Tracks with
16075
+ * an unknown envelope (no frame dims at persist time) always match. */
16076
+ zone: TrackZoneFilterSchema.optional(),
16077
+ /** See {@link TrackProjectionSchema}. Default `full` (backward
16078
+ * compatible — omitting the field keeps today's exact behaviour). */
16079
+ projection: TrackProjectionSchema.optional()
15925
16080
  }), zod.z.array(TrackSchema).readonly()),
16081
+ /**
16082
+ * Batched cluster-wide track listing — ONE call for the events page /
16083
+ * reel first paint instead of a per-camera `listTracks` fan-out. Merges
16084
+ * the persisted completed tracks of every requested device, sorted by
16085
+ * `lastSeen` DESC with a stable (lastSeen, trackId) cursor. Per-device
16086
+ * indexed pages (`idx_tracks_device_lastSeen`) are k-way merged
16087
+ * provider-side; `projection: 'slim'` drops the heavy `positions[]` /
16088
+ * `snapshots[]` JSON (returned as empty arrays). Active in-RAM tracks
16089
+ * are not included (same contract as `listTracks`).
16090
+ */
16091
+ listRecentTracks: method(RecentTracksQueryInput, RecentTracksPageSchema),
15926
16092
  clearTracks: method(zod.z.object({ deviceId: zod.z.number() }), zod.z.void(), {
15927
16093
  kind: "mutation",
15928
16094
  auth: "admin"
@@ -15931,6 +16097,26 @@ var pipelineAnalyticsCapability = {
15931
16097
  getObjectEvents: method(ObjectEventQueryInput, zod.z.array(ObjectEventSchema).readonly()),
15932
16098
  getAudioEvents: method(DeviceEventQueryInput, zod.z.array(AudioEventSchema).readonly()),
15933
16099
  /**
16100
+ * Every event kind the device can produce: built-ins (motion + audio),
16101
+ * detection classes actually observed for the device (from the track
16102
+ * history), and sensor kinds contributed by LINKED devices (resolved via
16103
+ * `device-manager.getLinkedDevices`, mapped through `EVENT_KIND_BY_CAP`).
16104
+ */
16105
+ listEventKinds: method(zod.z.object({ deviceId: zod.z.number() }), zod.z.array(EventKindDescriptorSchema).readonly()),
16106
+ /**
16107
+ * Sensor-event history for a camera: state changes of LINKED sensor
16108
+ * devices, attributed to the camera at ingest time (one row per linked
16109
+ * camera). Mirrors `getAudioEvents` query semantics; `kinds` narrows to
16110
+ * a kind subset.
16111
+ */
16112
+ getSensorEvents: method(zod.z.object({
16113
+ deviceId: zod.z.number(),
16114
+ since: zod.z.number().optional(),
16115
+ until: zod.z.number().optional(),
16116
+ kinds: zod.z.array(zod.z.string()).optional(),
16117
+ limit: zod.z.number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT)
16118
+ }), zod.z.array(SensorEventSchema).readonly()),
16119
+ /**
15934
16120
  * Importance-ranked highlights for a device+window. Queries completed
15935
16121
  * tracks by (deviceId, firstSeen ∈ [since,until]), scores each (or reuses
15936
16122
  * the persisted score), filters by minImportance/classFilter, orders by
@@ -20545,7 +20731,12 @@ var RecordingStorageUsageSchema = zod.z.object({
20545
20731
  /**
20546
20732
  * Result of locating footage at a wall-clock instant for one device/profile.
20547
20733
  * `segment` carries the covering segment's window; `gap` reports the forward
20548
- * nearest covered edge (`null` past the end of footage / when none exists).
20734
+ * nearest covered edge (`null` past the end of footage / when none exists)
20735
+ * and the backward covered edge `prevEndMs` (exclusive end of the nearest
20736
+ * footage behind the epoch; `null` when none — optional so older providers
20737
+ * that omit it stay valid). `prevEndMs` lets a backward frame-step hop the
20738
+ * small inter-segment cracks (durMs under-covers the span to the next
20739
+ * startMs by ~11-17 ms) instead of no-opping at a segment head.
20549
20740
  */
20550
20741
  var LocateSegmentResultSchema = zod.z.discriminatedUnion("kind", [zod.z.object({
20551
20742
  kind: zod.z.literal("segment"),
@@ -20554,7 +20745,8 @@ var LocateSegmentResultSchema = zod.z.discriminatedUnion("kind", [zod.z.object({
20554
20745
  bytes: zod.z.number()
20555
20746
  }), zod.z.object({
20556
20747
  kind: zod.z.literal("gap"),
20557
- nearestEdgeMs: zod.z.number().nullable()
20748
+ nearestEdgeMs: zod.z.number().nullable(),
20749
+ prevEndMs: zod.z.number().nullable().optional()
20558
20750
  })]);
20559
20751
  /** Raw bytes of one finalized footage segment (read off disk on the recording node). */
20560
20752
  var ReadSegmentBytesResultSchema = zod.z.object({ data: zod.z.instanceof(Uint8Array) });
@@ -22717,6 +22909,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
22717
22909
  addonId: null,
22718
22910
  access: "view"
22719
22911
  },
22912
+ "deviceManager.getLinkedDevices": {
22913
+ capName: "device-manager",
22914
+ capScope: "system",
22915
+ addonId: null,
22916
+ access: "view"
22917
+ },
22720
22918
  "deviceManager.getRoleDisplayDefaults": {
22721
22919
  capName: "device-manager",
22722
22920
  capScope: "system",
@@ -24271,6 +24469,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
24271
24469
  addonId: null,
24272
24470
  access: "view"
24273
24471
  },
24472
+ "pipelineAnalytics.getSensorEvents": {
24473
+ capName: "pipeline-analytics",
24474
+ capScope: "device",
24475
+ addonId: null,
24476
+ access: "view"
24477
+ },
24274
24478
  "pipelineAnalytics.getTrack": {
24275
24479
  capName: "pipeline-analytics",
24276
24480
  capScope: "device",
@@ -24283,6 +24487,18 @@ var METHOD_ACCESS_MAP = Object.freeze({
24283
24487
  addonId: null,
24284
24488
  access: "view"
24285
24489
  },
24490
+ "pipelineAnalytics.listEventKinds": {
24491
+ capName: "pipeline-analytics",
24492
+ capScope: "device",
24493
+ addonId: null,
24494
+ access: "view"
24495
+ },
24496
+ "pipelineAnalytics.listRecentTracks": {
24497
+ capName: "pipeline-analytics",
24498
+ capScope: "device",
24499
+ addonId: null,
24500
+ access: "view"
24501
+ },
24286
24502
  "pipelineAnalytics.listTracks": {
24287
24503
  capName: "pipeline-analytics",
24288
24504
  capScope: "device",
@@ -26548,6 +26764,12 @@ Object.defineProperty(exports, "deviceStatusCapability", {
26548
26764
  return deviceStatusCapability;
26549
26765
  }
26550
26766
  });
26767
+ Object.defineProperty(exports, "doorbellCapability", {
26768
+ enumerable: true,
26769
+ get: function() {
26770
+ return doorbellCapability;
26771
+ }
26772
+ });
26551
26773
  Object.defineProperty(exports, "emitDownForOwnedCaps", {
26552
26774
  enumerable: true,
26553
26775
  get: function() {
@@ -5,6 +5,14 @@ export interface FileDataPlaneOptions {
5
5
  readonly getRoots: () => readonly string[];
6
6
  /** Optional extension→content-type overrides merged over the media defaults. */
7
7
  readonly contentTypes?: Readonly<Record<string, string>>;
8
+ /**
9
+ * Optional per-path Cache-Control resolver. Return a header value to use for
10
+ * this rel path, or undefined for the default (`no-cache`). Lets a caller
11
+ * serve content-hashed bundle assets as `public, max-age=…, immutable`
12
+ * (re-downloading a 1MB SPA bundle on every open is a real cold-start cost)
13
+ * while entry HTML stays revalidated.
14
+ */
15
+ readonly cacheControl?: (rel: string) => string | undefined;
8
16
  }
9
17
  /** Build a `(req, res)` handler that serves `getRoots()` files with Range. */
10
18
  export declare function createFileDataPlaneHandler(opts: FileDataPlaneOptions): (req: IncomingMessage, res: ServerResponse) => Promise<void>;
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_chunk = require("./chunk-Cek0wNdY.js");
3
- const require_dist = require("./dist-C3uHEBtP.js");
4
- const require_model_download_service = require("./model-download-service-D-Umz4-L.js");
5
- const require_manifest_python_deps = require("./manifest-python-deps-CVcJ9hDX.js");
3
+ const require_dist = require("./dist-BduBhv6N.js");
4
+ const require_model_download_service = require("./model-download-service-hf0ookyy.js");
5
+ const require_manifest_python_deps = require("./manifest-python-deps-CPAMH5gV.js");
6
6
  const require_resource_monitor = require("./resource-monitor-DNNomR-i.js");
7
7
  const require_builtins_sqlite_storage_filesystem_storage_addon = require("./builtins/sqlite-storage/filesystem-storage.addon.js");
8
8
  const require_builtins_sqlite_storage_sqlite_settings_addon = require("./builtins/sqlite-storage/sqlite-settings.addon.js");
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
- import { A as isCollectionArrayMethod, Ct as parseJsonUnknown$1, E as extractNestedAddonId, Et as scopeKey, L as looseSchema, M as isVoidInput, N as kebabToCamel, Ot as EventCategory$1, P as lifecycleJobSchema, St as parseJsonObject, Tt as resolveCapMount, V as objectInputDeclaresAddonId, W as procedureAuthKey, _t as emitDownForOwnedCaps, at as DEVICE_SETTINGS_CONTRIBUTION_METHODS, dt as ReadinessTimeoutError, gt as createEvent, ht as asString$1, it as DATAPLANE_SECRET_HEADER$1, j as isObjectInput, k as isArrayOutputSchema, mt as asNumber, nt as errMsg$1, o as METHOD_ACCESS_MAP, ot as DEVICE_STATUS_METHOD, p as addonSettingsCapability, pt as asJsonObject$1, s as RUNTIME_DEFAULTS, t as ALL_CAPABILITY_DEFINITIONS, ut as ReadinessRegistry, wt as readinessKey, yt as expandCapMethods } from "./dist-BWQX9yUj.mjs";
2
- import { a as downloadModel, c as getModelFilePath, d as contentTypeFor, f as createAuthenticatedFileServer, h as resolveFilePath, i as downloadFile, l as isModelDownloaded, m as parseTokenizedUrl, n as collectModelFiles, o as ensureModel, p as parseRangeHeader, r as deleteModelFromDisk, s as fetchJson, t as ModelDownloadService, u as createFileDataPlaneHandler } from "./model-download-service-C-IHWnXx.mjs";
3
- import { $ as buildUdsNativeCapProxy, A as createParentUnownedCallHandler, B as AGENT_CAP_FWD_SERVICE, C as buildLinkChain, D as HUB_CAP_FWD_ACTION, E as localProviderLink, F as createUdsLoggerWithControl, G as createLocalTransport, H as CapRouteError, I as LocalChildClient, J as SocketChannel, K as UdsLocalTransportClient, L as LocalChildRegistry, M as createUdsEventBus, N as udsChildLogToWorkerEntry, O as HUB_CAP_FWD_SERVICE, P as createUdsLogger, Q as buildNativeCapProxy, R as UDS_NO_ROUTE_PREFIX, S as brokerTransportLink, T as ipcParentLink, U as classifyCapRoute, V as CapRouteResolver, W as callWithServiceDiscovery, X as FrameDecoder, Y as localEndpointPath, Z as encodeFrame, _ as resolveHwAccel, _t as CapabilityUnavailableError, a as getWorkerDeviceRegistry, at as createAddonService, b as getCapUsageRegistry, bt as resolveAddonClass, c as setHubConnected, ct as capActionName, d as getMoleculerEventStats, dt as capServiceName, et as createBrokerDeviceManagerApi, f as registerEventBusService, ft as parseCapAction, g as createKernelHwAccel, gt as CapabilityHandle, h as AddonDepsManager, ht as DeviceRegistry, i as createUdsAddonContext, j as createUdsEventBridge, k as createHubCapForwardService, l as EVENT_TOPIC_PREFIX, lt as capActionSuffix, m as subscribePassthrough, mt as serializeTypedArrays, n as adaptBrokerToCluster, o as getOrInitReadinessRegistry, ot as validateProviderRegistrations, p as setNodeEventInterest, pt as deserializeTypedArrays, q as UdsLocalTransportServer, r as createAddonContext, rt as mountNativeCapService, s as getOrInitReadinessRegistryForClient, st as NATIVE_PROVIDER_SERVICE_INFIX, t as installManifestPythonDeps, u as getBrokerEventBus, ut as capBareAction, v as CapUsageRegistry, vt as installManifestNativeDeps, w as ipcChildLink, x as brokerCallForCap, xt as createAddonDataPlaneFacility, y as __resetCapUsageRegistryForTests, yt as runNpm, z as AGENT_CAP_FWD_ACTION } from "./manifest-python-deps-BA6KA9If.mjs";
1
+ import { A as isArrayOutputSchema, Ct as parseJsonObject, D as extractNestedAddonId, Dt as scopeKey, Et as resolveCapMount, F as lifecycleJobSchema, G as procedureAuthKey, H as objectInputDeclaresAddonId, M as isObjectInput, N as isVoidInput, P as kebabToCamel, R as looseSchema, Tt as readinessKey, _t as createEvent, at as DATAPLANE_SECRET_HEADER$1, bt as expandCapMethods, dt as ReadinessRegistry, ft as ReadinessTimeoutError, gt as asString$1, ht as asNumber, j as isCollectionArrayMethod, kt as EventCategory$1, mt as asJsonObject$1, o as METHOD_ACCESS_MAP, ot as DEVICE_SETTINGS_CONTRIBUTION_METHODS, p as addonSettingsCapability, rt as errMsg$1, s as RUNTIME_DEFAULTS, st as DEVICE_STATUS_METHOD, t as ALL_CAPABILITY_DEFINITIONS, vt as emitDownForOwnedCaps, wt as parseJsonUnknown$1 } from "./dist-B_PSvr-m.mjs";
2
+ import { a as downloadModel, c as getModelFilePath, d as contentTypeFor, f as createAuthenticatedFileServer, h as resolveFilePath, i as downloadFile, l as isModelDownloaded, m as parseTokenizedUrl, n as collectModelFiles, o as ensureModel, p as parseRangeHeader, r as deleteModelFromDisk, s as fetchJson, t as ModelDownloadService, u as createFileDataPlaneHandler } from "./model-download-service-Cp9f4dk6.mjs";
3
+ import { $ as buildUdsNativeCapProxy, A as createParentUnownedCallHandler, B as AGENT_CAP_FWD_SERVICE, C as buildLinkChain, D as HUB_CAP_FWD_ACTION, E as localProviderLink, F as createUdsLoggerWithControl, G as createLocalTransport, H as CapRouteError, I as LocalChildClient, J as SocketChannel, K as UdsLocalTransportClient, L as LocalChildRegistry, M as createUdsEventBus, N as udsChildLogToWorkerEntry, O as HUB_CAP_FWD_SERVICE, P as createUdsLogger, Q as buildNativeCapProxy, R as UDS_NO_ROUTE_PREFIX, S as brokerTransportLink, T as ipcParentLink, U as classifyCapRoute, V as CapRouteResolver, W as callWithServiceDiscovery, X as FrameDecoder, Y as localEndpointPath, Z as encodeFrame, _ as resolveHwAccel, _t as CapabilityUnavailableError, a as getWorkerDeviceRegistry, at as createAddonService, b as getCapUsageRegistry, bt as resolveAddonClass, c as setHubConnected, ct as capActionName, d as getMoleculerEventStats, dt as capServiceName, et as createBrokerDeviceManagerApi, f as registerEventBusService, ft as parseCapAction, g as createKernelHwAccel, gt as CapabilityHandle, h as AddonDepsManager, ht as DeviceRegistry, i as createUdsAddonContext, j as createUdsEventBridge, k as createHubCapForwardService, l as EVENT_TOPIC_PREFIX, lt as capActionSuffix, m as subscribePassthrough, mt as serializeTypedArrays, n as adaptBrokerToCluster, o as getOrInitReadinessRegistry, ot as validateProviderRegistrations, p as setNodeEventInterest, pt as deserializeTypedArrays, q as UdsLocalTransportServer, r as createAddonContext, rt as mountNativeCapService, s as getOrInitReadinessRegistryForClient, st as NATIVE_PROVIDER_SERVICE_INFIX, t as installManifestPythonDeps, u as getBrokerEventBus, ut as capBareAction, v as CapUsageRegistry, vt as installManifestNativeDeps, w as ipcChildLink, x as brokerCallForCap, xt as createAddonDataPlaneFacility, y as __resetCapUsageRegistryForTests, yt as runNpm, z as AGENT_CAP_FWD_ACTION } from "./manifest-python-deps-CIyvuHAB.mjs";
4
4
  import { n as getSinglePidStats, t as getPidStats } from "./resource-monitor-Le3l0qS2.mjs";
5
5
  import { FilesystemStorageAddon, t as FilesystemStorageProvider } from "./builtins/sqlite-storage/filesystem-storage.addon.mjs";
6
6
  import { SqliteSettingsAddon, t as SqliteSettingsBackend } from "./builtins/sqlite-storage/sqlite-settings.addon.mjs";
@@ -1,4 +1,4 @@
1
- import { G as readNodePin } from "./dist-BWQX9yUj.mjs";
1
+ import { K as readNodePin } from "./dist-B_PSvr-m.mjs";
2
2
  import { ensureBinary, ensureFfmpeg, ensurePython, installPythonPackages, installPythonRequirements } from "@camstack/types/node";
3
3
  import { createServer } from "node:http";
4
4
  import * as fs from "node:fs";
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require("./chunk-Cek0wNdY.js");
2
- const require_dist = require("./dist-C3uHEBtP.js");
2
+ const require_dist = require("./dist-BduBhv6N.js");
3
3
  let _camstack_types_node = require("@camstack/types/node");
4
4
  let node_http = require("node:http");
5
5
  let node_fs = require("node:fs");
@@ -268,7 +268,7 @@ function createFileDataPlaneHandler(opts) {
268
268
  const baseHeaders = {
269
269
  "content-type": contentTypeFor(absPath, opts.contentTypes),
270
270
  "accept-ranges": "bytes",
271
- "cache-control": "no-cache"
271
+ "cache-control": opts.cacheControl?.(rel) ?? "no-cache"
272
272
  };
273
273
  const range = parseRangeHeader(req.headers.range, size);
274
274
  if (range) {
@@ -269,7 +269,7 @@ function createFileDataPlaneHandler(opts) {
269
269
  const baseHeaders = {
270
270
  "content-type": contentTypeFor(absPath, opts.contentTypes),
271
271
  "accept-ranges": "bytes",
272
- "cache-control": "no-cache"
272
+ "cache-control": opts.cacheControl?.(rel) ?? "no-cache"
273
273
  };
274
274
  const range = parseRangeHeader(req.headers.range, size);
275
275
  if (range) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/system",
3
- "version": "1.1.51",
3
+ "version": "1.1.52",
4
4
  "description": "Core addon for CamStack — builtins, pipeline, process management, auth, logging, events",
5
5
  "keywords": [
6
6
  "camstack",
@@ -152,6 +152,18 @@
152
152
  }
153
153
  ]
154
154
  },
155
+ {
156
+ "id": "virtual-doorbell",
157
+ "category": "system",
158
+ "name": "Virtual Doorbell",
159
+ "description": "Wrapper over the `doorbell` cap — turns any binary-ish device (contact sensor, switch, event emitter, flood/gas/CO sensor) into a per-camera doorbell. Operator binds it per camera and picks the source device + trigger in the camera's settings.",
160
+ "entry": "./dist/builtins/doorbell/index.js",
161
+ "capabilities": [
162
+ {
163
+ "name": "doorbell"
164
+ }
165
+ ]
166
+ },
155
167
  {
156
168
  "id": "alert-center",
157
169
  "category": "system",