camstack 1.1.28 → 1.1.30

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-B3OHhFkL.mjs
14525
+ // ../types/dist/sleep-D8ZkNoYz.mjs
14526
14526
  var WELL_KNOWN_TABS = [
14527
14527
  {
14528
14528
  id: "overview",
@@ -15585,6 +15585,46 @@ var RecordingConfigSchema = external_exports.object({
15585
15585
  */
15586
15586
  scrubThumbnails: ScrubThumbnailPresetSchema.optional()
15587
15587
  });
15588
+ var OpsLogDomainSchema = external_exports.enum(["recording", "events"]);
15589
+ var OpsLogOpSchema = external_exports.enum([
15590
+ "prune",
15591
+ "manual-delete",
15592
+ "rescan",
15593
+ "retention-run"
15594
+ ]);
15595
+ var OpsLogReasonSchema = external_exports.enum([
15596
+ "retention",
15597
+ "quota",
15598
+ "manual",
15599
+ "operator"
15600
+ ]);
15601
+ var OpsLogEntrySchema = external_exports.object({
15602
+ /** Unique row id. */
15603
+ id: external_exports.string(),
15604
+ /** Epoch ms the operation completed. */
15605
+ at: external_exports.number(),
15606
+ domain: OpsLogDomainSchema,
15607
+ op: OpsLogOpSchema,
15608
+ reason: OpsLogReasonSchema,
15609
+ /** The camera the op targeted; null for a cluster/global op. */
15610
+ deviceId: external_exports.number().nullable(),
15611
+ /** Node that performed the op (the log carries nodeId — no cross-node aggregation). */
15612
+ nodeId: external_exports.string(),
15613
+ /** Buckets / rows deleted (op-specific unit). */
15614
+ itemsAffected: external_exports.number(),
15615
+ /** Bytes reclaimed by the op (0 when not measurable). */
15616
+ bytesReclaimed: external_exports.number(),
15617
+ /** Free-text detail (e.g. "floor moved to <ts>"); null when none. */
15618
+ detail: external_exports.string().nullable(),
15619
+ /** Who/what triggered the op. */
15620
+ actor: external_exports.string()
15621
+ });
15622
+ var OpsLogQueryInputSchema = external_exports.object({
15623
+ /** Restrict to a single camera; omit for every row. */
15624
+ deviceId: external_exports.number().optional(),
15625
+ /** Max rows returned, newest-first. */
15626
+ limit: external_exports.number().int().min(1).max(1e3).optional()
15627
+ });
15588
15628
  var StorageLocationTypeSchema = external_exports.string().regex(/^[a-z][a-zA-Z0-9-]*$/);
15589
15629
  var StorageLocationSchema = external_exports.object({
15590
15630
  id: external_exports.string().regex(/^[a-z][a-zA-Z0-9-]*:[a-zA-Z0-9-]+$/),
@@ -21806,7 +21846,11 @@ var ZoneRuleSchema = external_exports.object({
21806
21846
  enabled: external_exports.boolean().default(true)
21807
21847
  });
21808
21848
  var ZoneRulesArraySchema = external_exports.array(ZoneRuleSchema).readonly();
21809
- var ZoneRuleStageEnum = external_exports.enum(["motion", "detection"]);
21849
+ var ZoneRuleStageEnum = external_exports.enum([
21850
+ "motion",
21851
+ "detection",
21852
+ "package"
21853
+ ]);
21810
21854
  var zoneRulesCapability = {
21811
21855
  name: "zone-rules",
21812
21856
  scope: "device",
@@ -21833,16 +21877,25 @@ var zoneRulesCapability = {
21833
21877
  })
21834
21878
  },
21835
21879
  /**
21836
- * Runtime-state slice — both stages mirrored together so consumers
21880
+ * Runtime-state slice — every stage mirrored together so consumers
21837
21881
  * see one reactive handle (`device.state.zoneRules.value`) instead
21838
- * of two. Bulk-replace mutations on either stage write the full
21839
- * `{motion, detection}` shape, so subscribers always get the
21882
+ * of one per stage. Bulk-replace mutations on any stage write the full
21883
+ * `{motion, detection, package}` shape, so subscribers always get the
21840
21884
  * complete current set. Consumers that only care about one stage
21841
21885
  * just read the matching property.
21886
+ *
21887
+ * `package` backs the package-drop detector — a package zone is a
21888
+ * `ZoneRule` on the `'package'` stage referencing drawn polygons
21889
+ * (see docs/superpowers/specs/2026-07-17-package-zones-design.md §3.1).
21890
+ * The orchestrator provider writes this stage as a first-class slice
21891
+ * (Phase 4): every mutation mirrors the full `{motion, detection,
21892
+ * package}` shape, so consumers read the current package rules directly
21893
+ * off `device.state.zoneRules.value.package`.
21842
21894
  */
21843
21895
  runtimeState: external_exports.object({
21844
21896
  motion: external_exports.array(ZoneRuleSchema).readonly(),
21845
- detection: external_exports.array(ZoneRuleSchema).readonly()
21897
+ detection: external_exports.array(ZoneRuleSchema).readonly(),
21898
+ package: external_exports.array(ZoneRuleSchema).readonly()
21846
21899
  })
21847
21900
  };
21848
21901
  var UNIT_TABLE = {
@@ -25594,6 +25647,7 @@ var EventKindIconSchema = external_exports.enum([
25594
25647
  "smoke",
25595
25648
  "water",
25596
25649
  "button",
25650
+ "package",
25597
25651
  "generic"
25598
25652
  ]);
25599
25653
  var EventKindCategorySchema = external_exports.enum([
@@ -25601,7 +25655,8 @@ var EventKindCategorySchema = external_exports.enum([
25601
25655
  "audio",
25602
25656
  "detection",
25603
25657
  "sensor",
25604
- "custom"
25658
+ "custom",
25659
+ "package"
25605
25660
  ]);
25606
25661
  var EventKindDescriptorSchema = external_exports.object({
25607
25662
  /** Stable kind id (e.g. 'motion', 'person', 'contact'). */
@@ -25910,6 +25965,23 @@ var TrackCascadeCountsSchema = external_exports.object({
25910
25965
  /** Per-track CLIP search vectors removed (best-effort). */
25911
25966
  embeddings: external_exports.number().int()
25912
25967
  });
25968
+ var EventStoreDeviceFootprintSchema = external_exports.object({
25969
+ deviceId: external_exports.number(),
25970
+ /** Persisted event rows (motion + object + audio) for the camera. */
25971
+ rows: external_exports.number().int(),
25972
+ /** Event-owned media bytes on disk for the camera. */
25973
+ bytes: external_exports.number().int()
25974
+ });
25975
+ var EventStoreFootprintSchema = external_exports.object({
25976
+ totalRows: external_exports.number().int(),
25977
+ totalBytes: external_exports.number().int(),
25978
+ devices: external_exports.array(EventStoreDeviceFootprintSchema).readonly()
25979
+ });
25980
+ var EventPruneCountsSchema = external_exports.object({
25981
+ motion: external_exports.number().int(),
25982
+ object: external_exports.number().int(),
25983
+ audio: external_exports.number().int()
25984
+ });
25913
25985
  var pipelineAnalyticsCapability = {
25914
25986
  name: "pipeline-analytics",
25915
25987
  scope: "device",
@@ -26071,6 +26143,45 @@ var pipelineAnalyticsCapability = {
26071
26143
  kind: "mutation",
26072
26144
  auth: "admin"
26073
26145
  }),
26146
+ /**
26147
+ * Durable event-store footprint for the management UI: event rows
26148
+ * (motion + object + audio) counted per camera + total, plus the
26149
+ * event-owned media bytes on disk per camera + total. Stat/count-based,
26150
+ * computed on demand.
26151
+ */
26152
+ getEventStoreFootprint: method(external_exports.object({}), EventStoreFootprintSchema, {
26153
+ kind: "query",
26154
+ auth: "admin"
26155
+ }),
26156
+ /**
26157
+ * Cluster-wide prune of events older than `olderThanMs` (exclusive) across
26158
+ * every camera, deleting each event's media in lockstep. Logged to the
26159
+ * events ops-log with `reason` (default `'retention'`). Returns the summed
26160
+ * per-kind deleted counts.
26161
+ */
26162
+ pruneEvents: method(external_exports.object({
26163
+ olderThanMs: external_exports.number(),
26164
+ reason: OpsLogReasonSchema.optional()
26165
+ }), EventPruneCountsSchema, {
26166
+ kind: "mutation",
26167
+ auth: "admin"
26168
+ }),
26169
+ /**
26170
+ * Manually delete EVERY event (motion + object + audio) for one camera and
26171
+ * its event-owned media in lockstep. Logged to the events ops-log as
26172
+ * `op:'manual-delete', reason:'manual'`. Destructive — the admin UI guards
26173
+ * it behind a confirm.
26174
+ */
26175
+ deleteDeviceEvents: method(external_exports.object({ deviceId: external_exports.number() }), EventPruneCountsSchema, {
26176
+ kind: "mutation",
26177
+ auth: "admin"
26178
+ }),
26179
+ /** The events ops-log rows (newest-first), optionally scoped to one camera.
26180
+ * Backed by a declared pipeline-analytics SQLite collection. */
26181
+ listOpsLog: method(OpsLogQueryInputSchema, external_exports.array(OpsLogEntrySchema).readonly(), {
26182
+ kind: "query",
26183
+ auth: "admin"
26184
+ }),
26074
26185
  getEventMedia: method(external_exports.object({
26075
26186
  eventId: external_exports.string(),
26076
26187
  kind: MediaFileKindEnum.optional()
@@ -30003,14 +30114,138 @@ var recordingCapability = {
30003
30114
  auth: "admin"
30004
30115
  }),
30005
30116
  /** Apply this device's retention policy to footage now; returns the oldest
30006
- * surviving footage start (the retention floor) or null if no footage. */
30007
- pruneFootage: method(external_exports.object({ deviceId: external_exports.number() }), external_exports.object({
30117
+ * surviving footage start (the retention floor) or null if no footage. The
30118
+ * prune is logged to the recordings ops-log with `reason` (default
30119
+ * `'retention'` — the policy-driven prune; `'quota'` when disk-pressure
30120
+ * triggered). */
30121
+ pruneFootage: method(external_exports.object({
30122
+ deviceId: external_exports.number(),
30123
+ reason: OpsLogReasonSchema.optional()
30124
+ }), external_exports.object({
30008
30125
  floorMs: external_exports.number().nullable(),
30009
30126
  deletedBuckets: external_exports.number().int(),
30010
30127
  reclaimedBytes: external_exports.number().int()
30011
30128
  }), {
30012
30129
  kind: "mutation",
30013
30130
  auth: "admin"
30131
+ }),
30132
+ /**
30133
+ * Manually delete a camera's footage — the whole footprint, or a
30134
+ * `[fromMs, toMs)` window when either bound is given. Logged to the
30135
+ * recordings ops-log as `op:'manual-delete', reason:'manual'`. Destructive:
30136
+ * the admin UI guards it behind a confirm.
30137
+ */
30138
+ deleteFootprint: method(external_exports.object({
30139
+ deviceId: external_exports.number(),
30140
+ fromMs: external_exports.number().optional(),
30141
+ toMs: external_exports.number().optional()
30142
+ }), external_exports.object({
30143
+ deletedBuckets: external_exports.number().int(),
30144
+ reclaimedBytes: external_exports.number().int()
30145
+ }), {
30146
+ kind: "mutation",
30147
+ auth: "admin"
30148
+ }),
30149
+ /** The recordings ops-log rows (newest-first), optionally scoped to one
30150
+ * camera. Backed by the recorder's bounded DurableState ring. */
30151
+ listOpsLog: method(OpsLogQueryInputSchema, external_exports.array(OpsLogEntrySchema).readonly(), {
30152
+ kind: "query",
30153
+ auth: "admin"
30154
+ })
30155
+ }
30156
+ };
30157
+ var ExportSpeedSchema = external_exports.number().min(0.25).max(32);
30158
+ var ExportTimelapseSchema = external_exports.object({
30159
+ everyMs: external_exports.number().int().positive(),
30160
+ outputFps: external_exports.number().int().min(1).max(60).optional()
30161
+ });
30162
+ var ExportOptionsSchema = external_exports.object({
30163
+ speed: ExportSpeedSchema.optional(),
30164
+ timelapse: ExportTimelapseSchema.optional(),
30165
+ includeAudio: external_exports.boolean(),
30166
+ maxLifeMs: external_exports.number().int().positive(),
30167
+ deleteAfterDownload: external_exports.boolean(),
30168
+ title: external_exports.string().max(200).optional()
30169
+ }).superRefine((v, ctx) => {
30170
+ if (v.speed !== void 0 && v.timelapse !== void 0) ctx.addIssue({
30171
+ code: external_exports.ZodIssueCode.custom,
30172
+ message: "speed and timelapse are mutually exclusive",
30173
+ path: ["timelapse"]
30174
+ });
30175
+ });
30176
+ var ExportStateSchema = external_exports.enum([
30177
+ "queued",
30178
+ "rendering",
30179
+ "ready",
30180
+ "failed",
30181
+ "expired",
30182
+ "deleted"
30183
+ ]);
30184
+ var ExportRecordSchema = external_exports.object({
30185
+ id: external_exports.string(),
30186
+ deviceId: external_exports.number(),
30187
+ profile: external_exports.string(),
30188
+ fromMs: external_exports.number(),
30189
+ toMs: external_exports.number(),
30190
+ options: ExportOptionsSchema,
30191
+ state: ExportStateSchema,
30192
+ /** 0–100 while rendering; null otherwise. */
30193
+ progressPct: external_exports.number().nullable(),
30194
+ /** File size once ready; null before. */
30195
+ fileBytes: external_exports.number().nullable(),
30196
+ expiresAt: external_exports.number(),
30197
+ deleteAfterDownload: external_exports.boolean(),
30198
+ /** Epoch of the first complete download; null until then. */
30199
+ downloadedAt: external_exports.number().nullable(),
30200
+ createdAt: external_exports.number(),
30201
+ /** User id/name that requested the export. */
30202
+ createdBy: external_exports.string(),
30203
+ /** Failure reason when state is 'failed'; null otherwise. */
30204
+ error: external_exports.string().nullable()
30205
+ });
30206
+ var ExportDownloadSchema = external_exports.object({
30207
+ url: external_exports.string(),
30208
+ endpoints: external_exports.array(external_exports.string())
30209
+ });
30210
+ var recordingExportCapability = {
30211
+ name: "recordingExport",
30212
+ scope: "system",
30213
+ mode: "singleton",
30214
+ methods: {
30215
+ /** Queue a render of `[fromMs,toMs)` for `deviceId`/`profile`. Fails fast
30216
+ * when no footage covers the range. Returns the queued record. */
30217
+ createExport: method(external_exports.object({
30218
+ deviceId: external_exports.number(),
30219
+ profile: external_exports.string(),
30220
+ fromMs: external_exports.number(),
30221
+ toMs: external_exports.number(),
30222
+ options: ExportOptionsSchema
30223
+ }), ExportRecordSchema, {
30224
+ kind: "mutation",
30225
+ auth: "protected"
30226
+ }),
30227
+ /** All export rows (history included), optionally scoped to one device. */
30228
+ listExports: method(external_exports.object({ deviceId: external_exports.number().optional() }), external_exports.array(ExportRecordSchema), {
30229
+ kind: "query",
30230
+ auth: "protected"
30231
+ }),
30232
+ getExport: method(external_exports.object({ exportId: external_exports.string() }), ExportRecordSchema, {
30233
+ kind: "query",
30234
+ auth: "protected"
30235
+ }),
30236
+ /** Abort a queued/rendering export; the partial file is removed. */
30237
+ cancelExport: method(external_exports.object({ exportId: external_exports.string() }), ExportRecordSchema, {
30238
+ kind: "mutation",
30239
+ auth: "protected"
30240
+ }),
30241
+ /** Remove the file but keep the history row (state → 'deleted'). */
30242
+ deleteExport: method(external_exports.object({ exportId: external_exports.string() }), ExportRecordSchema, {
30243
+ kind: "mutation",
30244
+ auth: "protected"
30245
+ }),
30246
+ getDownloadUrl: method(external_exports.object({ exportId: external_exports.string() }), ExportDownloadSchema, {
30247
+ kind: "query",
30248
+ auth: "protected"
30014
30249
  })
30015
30250
  }
30016
30251
  };
@@ -33054,6 +33289,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
33054
33289
  addonId: null,
33055
33290
  access: "delete"
33056
33291
  },
33292
+ "pipelineAnalytics.deleteDeviceEvents": {
33293
+ capName: "pipeline-analytics",
33294
+ capScope: "device",
33295
+ addonId: null,
33296
+ access: "delete"
33297
+ },
33057
33298
  "pipelineAnalytics.deleteTracks": {
33058
33299
  capName: "pipeline-analytics",
33059
33300
  capScope: "device",
@@ -33084,6 +33325,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
33084
33325
  addonId: null,
33085
33326
  access: "view"
33086
33327
  },
33328
+ "pipelineAnalytics.getEventStoreFootprint": {
33329
+ capName: "pipeline-analytics",
33330
+ capScope: "device",
33331
+ addonId: null,
33332
+ access: "view"
33333
+ },
33087
33334
  "pipelineAnalytics.getKeyEvents": {
33088
33335
  capName: "pipeline-analytics",
33089
33336
  capScope: "device",
@@ -33126,6 +33373,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
33126
33373
  addonId: null,
33127
33374
  access: "view"
33128
33375
  },
33376
+ "pipelineAnalytics.listOpsLog": {
33377
+ capName: "pipeline-analytics",
33378
+ capScope: "device",
33379
+ addonId: null,
33380
+ access: "view"
33381
+ },
33129
33382
  "pipelineAnalytics.listRecentTracks": {
33130
33383
  capName: "pipeline-analytics",
33131
33384
  capScope: "device",
@@ -33138,6 +33391,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
33138
33391
  addonId: null,
33139
33392
  access: "view"
33140
33393
  },
33394
+ "pipelineAnalytics.pruneEvents": {
33395
+ capName: "pipeline-analytics",
33396
+ capScope: "device",
33397
+ addonId: null,
33398
+ access: "create"
33399
+ },
33141
33400
  "pipelineAnalytics.pruneEventsBefore": {
33142
33401
  capName: "pipeline-analytics",
33143
33402
  capScope: "device",
@@ -33900,6 +34159,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
33900
34159
  addonId: null,
33901
34160
  access: "create"
33902
34161
  },
34162
+ "recording.deleteFootprint": {
34163
+ capName: "recording",
34164
+ capScope: "system",
34165
+ addonId: null,
34166
+ access: "delete"
34167
+ },
33903
34168
  "recording.getAvailability": {
33904
34169
  capName: "recording",
33905
34170
  capScope: "system",
@@ -33930,6 +34195,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
33930
34195
  addonId: null,
33931
34196
  access: "view"
33932
34197
  },
34198
+ "recording.listOpsLog": {
34199
+ capName: "recording",
34200
+ capScope: "system",
34201
+ addonId: null,
34202
+ access: "view"
34203
+ },
33933
34204
  "recording.locateSegment": {
33934
34205
  capName: "recording",
33935
34206
  capScope: "system",
@@ -33960,6 +34231,42 @@ var METHOD_ACCESS_MAP = Object.freeze({
33960
34231
  addonId: null,
33961
34232
  access: "create"
33962
34233
  },
34234
+ "recordingExport.cancelExport": {
34235
+ capName: "recordingExport",
34236
+ capScope: "system",
34237
+ addonId: null,
34238
+ access: "create"
34239
+ },
34240
+ "recordingExport.createExport": {
34241
+ capName: "recordingExport",
34242
+ capScope: "system",
34243
+ addonId: null,
34244
+ access: "create"
34245
+ },
34246
+ "recordingExport.deleteExport": {
34247
+ capName: "recordingExport",
34248
+ capScope: "system",
34249
+ addonId: null,
34250
+ access: "delete"
34251
+ },
34252
+ "recordingExport.getDownloadUrl": {
34253
+ capName: "recordingExport",
34254
+ capScope: "system",
34255
+ addonId: null,
34256
+ access: "view"
34257
+ },
34258
+ "recordingExport.getExport": {
34259
+ capName: "recordingExport",
34260
+ capScope: "system",
34261
+ addonId: null,
34262
+ access: "view"
34263
+ },
34264
+ "recordingExport.listExports": {
34265
+ capName: "recordingExport",
34266
+ capScope: "system",
34267
+ addonId: null,
34268
+ access: "view"
34269
+ },
33963
34270
  "sceneMonitor.captureReference": {
33964
34271
  capName: "scene-monitor",
33965
34272
  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-REYL2W37.js";
4
+ } from "./chunk-WX6XSMWG.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-OTKOLUJJ.js");
1082
+ const { discoverNodes, resolveHubFromDiscovered, filterHubNodes, DEFAULT_HUB_HTTPS_PORT } = await import("./discover-Q6UMJNDP.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-REYL2W37.js";
8
+ } from "./chunk-WX6XSMWG.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.28",
3
+ "version": "1.1.30",
4
4
  "description": "CLI tool for managing and running CamStack server",
5
5
  "keywords": [
6
6
  "camstack",