@camstack/types 1.2.82 → 1.2.84

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.
@@ -29,6 +29,11 @@ export declare const ClipSchema: z.ZodObject<{
29
29
  endMs: z.ZodNumber;
30
30
  }, z.core.$strip>;
31
31
  thumbnail: z.ZodOptional<z.ZodString>;
32
+ eventIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
33
+ holes: z.ZodOptional<z.ZodArray<z.ZodObject<{
34
+ startMs: z.ZodNumber;
35
+ endMs: z.ZodNumber;
36
+ }, z.core.$strip>>>;
32
37
  }, z.core.$strip>;
33
38
  export type Clip = z.infer<typeof ClipSchema>;
34
39
  export declare const ClipPlaybackSchema: z.ZodObject<{
@@ -67,6 +72,11 @@ export declare const videoclipsCapability: {
67
72
  endMs: z.ZodNumber;
68
73
  }, z.core.$strip>;
69
74
  thumbnail: z.ZodOptional<z.ZodString>;
75
+ eventIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
76
+ holes: z.ZodOptional<z.ZodArray<z.ZodObject<{
77
+ startMs: z.ZodNumber;
78
+ endMs: z.ZodNumber;
79
+ }, z.core.$strip>>>;
70
80
  }, z.core.$strip>>>, "query">;
71
81
  readonly getClipPlayback: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
72
82
  deviceId: z.ZodNumber;
@@ -146,15 +146,6 @@ export declare abstract class BaseDeviceProvider<TConfig extends object = Record
146
146
  value: unknown;
147
147
  formValues?: Record<string, unknown>;
148
148
  }): Promise<FieldProbeResult>;
149
- /**
150
- * Top-level devices restored at once in {@link onRestoreDevices}.
151
- *
152
- * Four covers the fleets this ships to without turning a boot into a burst a
153
- * camera NVR answers with a refusal. A provider whose upstream is a single
154
- * session with a serial command channel (a Baichuan hub, an NVR that
155
- * serialises ISAPI) should lower it; nothing needs to raise it.
156
- */
157
- protected readonly restoreConcurrency: number;
158
149
  restoreDevices(savedDevices: readonly SavedDevice[]): Promise<void>;
159
150
  /**
160
151
  * Concrete device classes this provider can spawn, keyed by
@@ -14,9 +14,10 @@ export declare enum EventCategory {
14
14
  SystemRestartCompleted = "system.restart-completed",
15
15
  /**
16
16
  * A newer addon or server-root package version was found by the
17
- * authoritative registry check. Emitted once per
18
- * `(target, packageName, currentVersion, latestVersion)` transition; repeated
19
- * polling of the same result is deduplicated by the checker.
17
+ * authoritative registry check. Emitted once when any observed
18
+ * `latestVersion` changes (or a package/node first appears behind);
19
+ * the payload carries the full currently-available list. Repeated
20
+ * polling of the same latests is silent.
20
21
  */
21
22
  UpdateAvailable = "update.available",
22
23
  /**
package/dist/enums.js CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_event_category = require("./event-category-D3gG7oil.js");
2
+ const require_event_category = require("./event-category-DBHdQVIy.js");
3
3
  //#region src/enums/event-source-type.ts
4
4
  var EventSourceType = /* @__PURE__ */ function(EventSourceType) {
5
5
  EventSourceType["Addon"] = "addon";
package/dist/enums.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { t as EventCategory } from "./event-category-Bxo5yJjt.mjs";
1
+ import { t as EventCategory } from "./event-category-C0lyLd5U.mjs";
2
2
  //#region src/enums/event-source-type.ts
3
3
  var EventSourceType = /* @__PURE__ */ function(EventSourceType) {
4
4
  EventSourceType["Addon"] = "addon";
@@ -15,9 +15,10 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
15
15
  EventCategory["SystemRestartCompleted"] = "system.restart-completed";
16
16
  /**
17
17
  * A newer addon or server-root package version was found by the
18
- * authoritative registry check. Emitted once per
19
- * `(target, packageName, currentVersion, latestVersion)` transition; repeated
20
- * polling of the same result is deduplicated by the checker.
18
+ * authoritative registry check. Emitted once when any observed
19
+ * `latestVersion` changes (or a package/node first appears behind);
20
+ * the payload carries the full currently-available list. Repeated
21
+ * polling of the same latests is silent.
21
22
  */
22
23
  EventCategory["UpdateAvailable"] = "update.available";
23
24
  /**
@@ -15,9 +15,10 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
15
15
  EventCategory["SystemRestartCompleted"] = "system.restart-completed";
16
16
  /**
17
17
  * A newer addon or server-root package version was found by the
18
- * authoritative registry check. Emitted once per
19
- * `(target, packageName, currentVersion, latestVersion)` transition; repeated
20
- * polling of the same result is deduplicated by the checker.
18
+ * authoritative registry check. Emitted once when any observed
19
+ * `latestVersion` changes (or a package/node first appears behind);
20
+ * the payload carries the full currently-available list. Repeated
21
+ * polling of the same latests is silent.
21
22
  */
22
23
  EventCategory["UpdateAvailable"] = "update.available";
23
24
  /**
@@ -4865,6 +4865,13 @@ export type AppRouter = TrpcCoreRouter<{
4865
4865
  output: z.infer<typeof pipelineAnalyticsCapability.methods.wipeAllAnalytics.output>;
4866
4866
  meta: object;
4867
4867
  }>;
4868
+ reconcileFromDisk: TRPCMutationProcedure<{
4869
+ input: {
4870
+ [x: string]: unknown;
4871
+ } & z.input<typeof pipelineAnalyticsCapability.methods.reconcileFromDisk.input>;
4872
+ output: z.infer<typeof pipelineAnalyticsCapability.methods.reconcileFromDisk.output>;
4873
+ meta: object;
4874
+ }>;
4868
4875
  deleteTracks: TRPCMutationProcedure<{
4869
4876
  input: {
4870
4877
  [x: string]: unknown;
@@ -5656,6 +5663,20 @@ export type AppRouter = TrpcCoreRouter<{
5656
5663
  output: z.infer<typeof pipelineOrchestratorCapability.methods.getCameraStatuses.output>;
5657
5664
  meta: object;
5658
5665
  }>;
5666
+ reconcileFromDisk: TRPCMutationProcedure<{
5667
+ input: {
5668
+ nodeId?: string | undefined;
5669
+ } | undefined;
5670
+ output: z.infer<typeof pipelineOrchestratorCapability.methods.reconcileFromDisk.output>;
5671
+ meta: object;
5672
+ }>;
5673
+ getReconcileFromDiskStatus: TRPCQueryProcedure<{
5674
+ input: {
5675
+ nodeId?: string | undefined;
5676
+ } | undefined;
5677
+ output: z.infer<typeof pipelineOrchestratorCapability.methods.getReconcileFromDiskStatus.output>;
5678
+ meta: object;
5679
+ }>;
5659
5680
  listTemplates: TRPCQueryProcedure<{
5660
5681
  input: {
5661
5682
  nodeId?: string | undefined;
@@ -281,7 +281,7 @@ export interface DeviceProxy {
281
281
  readonly pipelineRunner: Pick<InferDeviceProxyCap<typeof pipelineRunnerCapability>, 'detachCamera' | 'getCameraMetrics' | 'runDetailSubtree'>;
282
282
  readonly plateGallery: Pick<InferDeviceProxyCap<typeof plateGalleryCapability>, 'listPlates' | 'getPlateByTrack'>;
283
283
  readonly recording: Pick<InferDeviceProxyCap<typeof recordingCapability>, 'getAvailability' | 'getDaysWithRecordings' | 'getPlaybackManifest' | 'getDeviceConfig' | 'locateSegment' | 'readSegmentBytes' | 'readGopBytes' | 'setDeviceConfig' | 'rescanStorage' | 'pruneFootage' | 'deleteFootprint' | 'renderGif' | 'renderClip' | 'getStatus' | 'getDeviceSettingsContribution' | 'getDeviceLiveContribution' | 'applyDeviceSettingsPatch'>;
284
- readonly recordingExport: Pick<InferDeviceProxyCap<typeof recordingExportCapability>, 'createExport' | 'listExports'>;
284
+ readonly recordingExport: Pick<InferDeviceProxyCap<typeof recordingExportCapability>, 'listExports'>;
285
285
  readonly streamBroker: Pick<InferDeviceProxyCap<typeof streamBrokerCapability>, 'publishCameraStream' | 'retractCameraStream' | 'assignProfile' | 'unassignProfile' | 'renderPreBufferClip' | 'produceEventMedia' | 'restartProfile' | 'getDeviceAudioMute' | 'setDeviceAudioMute' | 'getDeviceSettingsContribution' | 'getDeviceLiveContribution' | 'applyDeviceSettingsPatch'>;
286
286
  }
287
287
  /**
@@ -6,7 +6,7 @@
6
6
  * scope+access check inside `protectedProcedure` (see
7
7
  * `server/backend/src/api/trpc/trpc.middleware.ts`).
8
8
  *
9
- * Coverage: 940 method paths across 123 capabilities.
9
+ * Coverage: 943 method paths across 123 capabilities.
10
10
  */
11
11
  import type { CapabilityMethodAccess } from '../capabilities/capability-definition.js';
12
12
  export interface MethodAccessRecord {
@@ -6,7 +6,7 @@
6
6
  * system-scope cap that takes a deviceId was previously never device-filtered
7
7
  * — see the generator header).
8
8
  *
9
- * Coverage: 336 methods carry a device reference, of which
9
+ * Coverage: 337 methods carry a device reference, of which
10
10
  * 124 are on SYSTEM-scope caps.
11
11
  *
12
12
  * Top-level fields, number arrays, and one-level arrays of objects carrying
@@ -84,11 +84,11 @@ export interface SystemProxy {
84
84
  readonly notificationOutput: Pick<InferProvider<typeof notificationOutputCapability>, 'listTargetKinds' | 'listTargets' | 'discoverTargets' | 'send' | 'testTarget' | 'upsertTarget' | 'deleteTarget' | 'setTargetEnabled'>;
85
85
  readonly osdManager: Pick<InferProvider<typeof osdManagerCapability>, 'getConditionSupport' | 'copyDeviceConfiguration'>;
86
86
  readonly pipelineExecutor: Pick<InferProvider<typeof pipelineExecutorCapability>, 'getAvailableEngines' | 'getSelectedEngine' | 'getDefaultSteps' | 'getEngineProvisioning' | 'getVideoPipelineSteps' | 'setVideoPipelineSteps' | 'clearDeviceOverrides' | 'getSchema' | 'getGlobalSteps' | 'getGlobalPipelineConfig' | 'getOrchestratorConfigSchema' | 'validatePipeline' | 'listTemplates' | 'saveTemplate' | 'updateTemplate' | 'deleteTemplate' | 'getCapabilities' | 'getAddonModels' | 'downloadModel' | 'deleteModel' | 'cacheFrameInPool' | 'inferCached' | 'uncacheFrame' | 'getEffectiveTuning' | 'listLoadedEngines' | 'spinEngine' | 'killEngine' | 'listReferenceImages' | 'getReferenceImage' | 'getReferenceAudioFiles' | 'getReferenceAudio' | 'getAudioCapabilities' | 'runAudioTest' | 'getDetectionConfigSchema'>;
87
- readonly pipelineOrchestrator: Pick<InferProvider<typeof pipelineOrchestratorCapability>, 'pauseForStorageMigration' | 'resumeForStorageMigration' | 'rebalance' | 'getPipelineAssignments' | 'getAgentLoad' | 'getGlobalMetrics' | 'getCapabilityBindings' | 'setCapabilityBinding' | 'getIngestOwner' | 'getAudioNodeLoad' | 'getAgentSettings' | 'listAgentSettings' | 'removeAgentSettings' | 'setAgentMaxCameras' | 'setAgentDetectWeight' | 'setAgentCapabilities' | 'setAgentReachableHost' | 'setAgentInferenceDevices' | 'getNodeInferenceDevices' | 'resetNodePipelineDefaults' | 'getCameraStatuses' | 'listTemplates' | 'saveTemplate' | 'updateTemplate' | 'deleteTemplate'>;
87
+ readonly pipelineOrchestrator: Pick<InferProvider<typeof pipelineOrchestratorCapability>, 'pauseForStorageMigration' | 'resumeForStorageMigration' | 'rebalance' | 'getPipelineAssignments' | 'getAgentLoad' | 'getGlobalMetrics' | 'getCapabilityBindings' | 'setCapabilityBinding' | 'getIngestOwner' | 'getAudioNodeLoad' | 'getAgentSettings' | 'listAgentSettings' | 'removeAgentSettings' | 'setAgentMaxCameras' | 'setAgentDetectWeight' | 'setAgentCapabilities' | 'setAgentReachableHost' | 'setAgentInferenceDevices' | 'getNodeInferenceDevices' | 'resetNodePipelineDefaults' | 'getCameraStatuses' | 'reconcileFromDisk' | 'getReconcileFromDiskStatus' | 'listTemplates' | 'saveTemplate' | 'updateTemplate' | 'deleteTemplate'>;
88
88
  readonly pipelineRunner: Pick<InferProvider<typeof pipelineRunnerCapability>, 'attachCamera' | 'reportMotion' | 'getLocalLoad' | 'getLocalMetrics' | 'getAllCameraMetrics' | 'getLocalCameras' | 'getNativeCrop' | 'runStatelessStep'>;
89
89
  readonly plateGallery: Pick<InferProvider<typeof plateGalleryCapability>, 'getPlateMedia' | 'searchPlates' | 'suggestPlateClusters' | 'correctPlateText' | 'deletePlate' | 'listVehicles' | 'createVehicle' | 'renameVehicle' | 'deleteVehicle' | 'listVehicleSamples' | 'removeVehicleSample' | 'assignPlate' | 'unassignPlate' | 'assignPlates' | 'unassignPlates'>;
90
90
  readonly recording: Pick<InferProvider<typeof recordingCapability>, 'getStorageUsage' | 'listOpsLog' | 'pauseForStorageMigration' | 'resumeForStorageMigration' | 'refreshStorageLocationsForMigration' | 'startStorageMigrationMove' | 'getStorageMigrationMoveStatus' | 'cancelStorageMigrationMove' | 'relocateFootage' | 'listRelocateJobs' | 'cancelRelocateJob' | 'planStorageRebalance' | 'startStorageRebalance'>;
91
- readonly recordingExport: Pick<InferProvider<typeof recordingExportCapability>, 'getExport' | 'cancelExport' | 'deleteExport' | 'getDownloadUrl' | 'readExportBytes'>;
91
+ readonly recordingExport: Pick<InferProvider<typeof recordingExportCapability>, 'createExport' | 'getExport' | 'cancelExport' | 'deleteExport' | 'getDownloadUrl' | 'readExportBytes'>;
92
92
  readonly serverManagement: Pick<InferProvider<typeof serverManagementCapability>, 'getServerPackageStatus' | 'checkServerUpdate' | 'applyServerUpdate' | 'rollbackServerUpdate' | 'restartServer'>;
93
93
  readonly settingsStore: Pick<InferProvider<typeof settingsStoreCapability>, 'get' | 'set' | 'query' | 'insert' | 'update' | 'delete' | 'deleteWhere' | 'updateWhere' | 'count' | 'histogram' | 'isEmpty' | 'declareCollection'>;
94
94
  readonly storage: Pick<InferProvider<typeof storageCapability>, 'resolve' | 'write' | 'read' | 'exists' | 'list' | 'delete' | 'getAvailableSpace' | 'beginUpload' | 'writeChunk' | 'finalizeUpload' | 'abortUpload' | 'beginDownload' | 'readChunk' | 'endDownload' | 'listLocations' | 'getDefaultLocation' | 'listLocationDeclarations' | 'upsertLocation' | 'deleteLocation' | 'testLocation' | 'listProviders' | 'testConfig'>;
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_event_category = require("./event-category-D3gG7oil.js");
3
- const require_sleep = require("./sleep-EYtyUX0L.js");
2
+ const require_event_category = require("./event-category-DBHdQVIy.js");
3
+ const require_sleep = require("./sleep-DZAjGv1f.js");
4
4
  const require_canonical_hash = require("./canonical-hash-DNV8S5ET.js");
5
5
  const require_enums = require("./enums.js");
6
6
  const require_err_msg = require("./err-msg-COpsHMw2.js");
@@ -1539,6 +1539,20 @@ var DEFAULT_EVENTS_BAND_BUFFER_SEC = {
1539
1539
  postBufferSec: 30
1540
1540
  };
1541
1541
  /**
1542
+ * Adjacent recorded ranges closer than this belong to the SAME videoclip visit.
1543
+ *
1544
+ * This is NOT the recorder calendar merge (`RANGE_MERGE_GAP_MS = 5s`). That
1545
+ * threshold is for the timeline bar, which must show exact holes — including
1546
+ * the ~8s GOP/keyframe rolls measured on events-mode cameras (dispensa 1438,
1547
+ * 2026-08-16). A videoclip is the events-mode keep-window (writer session),
1548
+ * whose idle bound is `postBufferSec`. Using that default (30s) glues those
1549
+ * intra-visit holes without joining visits hours apart.
1550
+ *
1551
+ * Segments stay the source of truth on disk (`startMs-durMs-bytes.m4s`); a
1552
+ * visit is derived, not a second copy of the files.
1553
+ */
1554
+ var VISIT_MERGE_GAP_MS = DEFAULT_EVENTS_BAND_BUFFER_SEC.postBufferSec * 1e3;
1555
+ /**
1542
1556
  * Per-device retention overrides. Every field is optional; an unset or `0`
1543
1557
  * value inherits the node-wide recorder default. Only footage-lifetime limits
1544
1558
  * live per-camera: `maxAgeDays` and `maxSizeGb`. The disk-occupancy threshold
@@ -1644,6 +1658,12 @@ var RecordingConfigSchema = zod.z.object({
1644
1658
  /** DERIVED summary of `bands`, stamped by the recorder on every save.
1645
1659
  * Authoring it has no effect — see {@link RecordingStorageModeSchema}. */
1646
1660
  mode: RecordingStorageModeSchema.optional(),
1661
+ /**
1662
+ * Which assigned broker slots to record. Absent / empty = {@link
1663
+ * DEFAULT_RECORDING_PROFILES} (`high`+`low`) intersected with the
1664
+ * camera's currently assigned slots — never `mid` unless the operator
1665
+ * picks it, and never a slot the broker has not assigned.
1666
+ */
1647
1667
  profiles: zod.z.array(require_sleep.CamProfileSchema).optional(),
1648
1668
  segmentSeconds: zod.z.number().int().positive().optional(),
1649
1669
  /**
@@ -1668,7 +1688,7 @@ var RecordingConfigSchema = zod.z.object({
1668
1688
  *
1669
1689
  * THE one definition: the recorder stamps `config.mode` with it on save and
1670
1690
  * reports it as the cap's `activeMode`, and the settings UI reads it back to
1671
- * decide which authoring tab a config opens in. Two copies would drift, and the
1691
+ * highlight the Off/Events/Continuous shortcut. Two copies would drift, and the
1672
1692
  * symptom (a status dot disagreeing with what is being recorded) is exactly the
1673
1693
  * bug this field was added to fix.
1674
1694
  */
@@ -1677,6 +1697,30 @@ function deriveRecordingMode(config) {
1677
1697
  if (config.bands.some((band) => band.mode === "continuous")) return "continuous";
1678
1698
  return "events";
1679
1699
  }
1700
+ /**
1701
+ * Default recorded slots when a config omits `profiles`: high + low.
1702
+ * `mid` is opt-in — it is usually a second native encode the operator
1703
+ * did not ask to store twice.
1704
+ */
1705
+ var DEFAULT_RECORDING_PROFILES = ["high", "low"];
1706
+ /**
1707
+ * Pick which assigned broker slots to record. `assigned` is already the
1708
+ * broker's assigned∩deduped set (see `selectAssignedProfileSlots`).
1709
+ *
1710
+ * An operator `override` DISABLES unselected assigned slots (assigned ∩
1711
+ * selection). A selection matching none of the assigned sources, or an
1712
+ * absent/empty override, falls through: prefer {@link DEFAULT_RECORDING_PROFILES}
1713
+ * among assigned, else every assigned slot (a camera with only `mid`
1714
+ * still records something). Empty assigned → empty result.
1715
+ */
1716
+ function resolveRecordingProfiles(assigned, override) {
1717
+ if (override !== void 0 && override.length > 0) {
1718
+ const selected = assigned.filter((profile) => override.includes(profile));
1719
+ return selected.length > 0 ? selected : [...assigned];
1720
+ }
1721
+ const preferred = assigned.filter((profile) => DEFAULT_RECORDING_PROFILES.includes(profile));
1722
+ return preferred.length > 0 ? preferred : [...assigned];
1723
+ }
1680
1724
  //#endregion
1681
1725
  //#region src/interfaces/relocate.ts
1682
1726
  /**
@@ -1742,7 +1786,11 @@ var RelocateFootageInputSchema = zod.z.object({
1742
1786
  profiles: zod.z.array(zod.z.string()).optional(),
1743
1787
  /** Copy throttle in MB/s (default 40) — the drain is a background chore,
1744
1788
  * never allowed to starve live writers. */
1745
- throttleMbps: zod.z.number().min(1).max(1e3).optional()
1789
+ throttleMbps: zod.z.number().min(1).max(1e3).optional(),
1790
+ /** Move only segments whose startMs is >= this. Absent = the whole source
1791
+ * pile. Used when a full drain is too expensive and the operator only
1792
+ * wants the recent window on the new disk. */
1793
+ sinceMs: zod.z.number().int().optional()
1746
1794
  });
1747
1795
  /** Internal, lease-scoped participant operation. It is intentionally separate
1748
1796
  * from persistent recording settings: a migration never changes
@@ -12211,6 +12259,9 @@ var NcSystemEventKindSchema = zod.z.enum([
12211
12259
  "alarm-disarmed",
12212
12260
  "alarm-arming",
12213
12261
  "alarm-arm-refused",
12262
+ "addon-updated",
12263
+ "server-updated",
12264
+ "export-completed",
12214
12265
  "camera-online",
12215
12266
  "camera-offline",
12216
12267
  "camera-disabled",
@@ -13360,6 +13411,18 @@ var NC_CONDITION_CATALOG = [
13360
13411
  value: "server-update-available",
13361
13412
  label: "Server update available"
13362
13413
  },
13414
+ {
13415
+ value: "addon-updated",
13416
+ label: "Addons updated"
13417
+ },
13418
+ {
13419
+ value: "server-updated",
13420
+ label: "Server updated"
13421
+ },
13422
+ {
13423
+ value: "export-completed",
13424
+ label: "Export completed"
13425
+ },
13363
13426
  {
13364
13427
  value: "alarm-arming",
13365
13428
  label: "Alarm arming (exit delay)"
@@ -14711,13 +14774,19 @@ var RetrainStatusSchema = zod.z.enum([
14711
14774
  * "never marked" from "already trained" must read `retrainStatus`.
14712
14775
  *
14713
14776
  * `debug` does NOT pin; it is attention, not durability.
14777
+ *
14778
+ * `favourited` IS a BOOLEAN pin (durability bit), not a retrain lifecycle.
14779
+ * A favourited track is skipped by retention the same way `staging` is, but
14780
+ * it does not enter `none|staging|trained` and has no staging budget.
14714
14781
  */
14715
14782
  var TrackFlagFields = {
14716
14783
  /** Operator marked this track as training material — i.e. `retrainStatus` is
14717
14784
  * `'staging'`. */
14718
14785
  markForTrain: zod.z.boolean().optional(),
14719
14786
  /** Operator marked this track for diagnostic attention. */
14720
- debug: zod.z.boolean().optional()
14787
+ debug: zod.z.boolean().optional(),
14788
+ /** Operator favourited this track. Pins it against pruning. */
14789
+ favourited: zod.z.boolean().optional()
14721
14790
  };
14722
14791
  /**
14723
14792
  * The lifecycle field itself, on the READ surfaces only (`Track`, `KeyEvent`).
@@ -14742,6 +14811,7 @@ var TrackFlagsSchema = zod.z.object({
14742
14811
  trackId: zod.z.string(),
14743
14812
  markForTrain: zod.z.boolean(),
14744
14813
  debug: zod.z.boolean(),
14814
+ favourited: zod.z.boolean(),
14745
14815
  /** The lifecycle state the boolean was derived from. Required here (unlike on
14746
14816
  * a track row) because this shape is only ever produced by the write body,
14747
14817
  * which always knows it — and a surface that has just written needs to render
@@ -15398,6 +15468,12 @@ var TrackCascadeCountsSchema = zod.z.object({
15398
15468
  /** Per-track CLIP search vectors removed (best-effort). */
15399
15469
  embeddings: zod.z.number().int()
15400
15470
  });
15471
+ /** Disk-wins reconcile: media rows whose blobs are gone, then empty tracks. */
15472
+ var DiskReconcileCountsSchema = zod.z.object({
15473
+ mediaDropped: zod.z.number().int(),
15474
+ tracks: zod.z.number().int(),
15475
+ events: zod.z.number().int()
15476
+ });
15401
15477
  /** Event-store footprint for one camera. */
15402
15478
  var EventStoreDeviceFootprintSchema = zod.z.object({
15403
15479
  deviceId: zod.z.number(),
@@ -15683,6 +15759,17 @@ var pipelineAnalyticsCapability = {
15683
15759
  auth: "admin"
15684
15760
  }),
15685
15761
  /**
15762
+ * Disk-wins reconcile for one camera. Drops media index rows whose blobs
15763
+ * are gone, then cascades tracks (including favourited and staging) that
15764
+ * have no remaining files. Enrolled identity/vehicle/scene media is never
15765
+ * probed. Trackless motion/audio events with no remaining file are dropped,
15766
+ * including snapshot-less rows.
15767
+ */
15768
+ reconcileFromDisk: require_sleep.method(zod.z.object({ deviceId: zod.z.number() }), DiskReconcileCountsSchema, {
15769
+ kind: "mutation",
15770
+ auth: "admin"
15771
+ }),
15772
+ /**
15686
15773
  * Delete whole tracks (object events) by id for the given device,
15687
15774
  * cascading their media in lockstep. Returns the number of tracks
15688
15775
  * actually deleted plus the ids that could not be removed.
@@ -15701,7 +15788,7 @@ var pipelineAnalyticsCapability = {
15701
15788
  auth: "admin"
15702
15789
  }),
15703
15790
  /**
15704
- * Set the per-track operator flags (`markForTrain`, `debug`) on ONE track.
15791
+ * Set the per-track operator flags (`markForTrain`, `debug`, `favourited`) on ONE track.
15705
15792
  * The patch is PARTIAL — an omitted key is left untouched — because the
15706
15793
  * three surfaces that write it (admin Events grid, viewer track detail,
15707
15794
  * viewer cluster detail) each own one toggle and must not clobber the other.
@@ -18009,6 +18096,24 @@ var CameraStatusDegradationSchema = zod.z.object({
18009
18096
  *
18010
18097
  * See spec: `docs/superpowers/specs/2026-06-24-camera-status-aggregator-cap.md`
18011
18098
  */
18099
+ var DiskReconcileJobSchema = zod.z.object({
18100
+ state: zod.z.enum([
18101
+ "idle",
18102
+ "running",
18103
+ "done",
18104
+ "error"
18105
+ ]),
18106
+ total: zod.z.number().int().nonnegative(),
18107
+ completed: zod.z.number().int().nonnegative(),
18108
+ currentDeviceId: zod.z.number().int().nullable(),
18109
+ failed: zod.z.array(zod.z.number().int()).readonly(),
18110
+ mediaDropped: zod.z.number().int().nonnegative(),
18111
+ tracks: zod.z.number().int().nonnegative(),
18112
+ events: zod.z.number().int().nonnegative(),
18113
+ startedAtMs: zod.z.number().int().nullable(),
18114
+ finishedAtMs: zod.z.number().int().nullable(),
18115
+ error: zod.z.string().nullable()
18116
+ });
18012
18117
  var CameraStatusSchema = zod.z.object({
18013
18118
  deviceId: zod.z.number(),
18014
18119
  assignment: CameraAssignmentStatusSchema,
@@ -18545,6 +18650,18 @@ var pipelineOrchestratorCapability = {
18545
18650
  * rail without issuing N parallel browser round-trips.
18546
18651
  */
18547
18652
  getCameraStatuses: require_sleep.method(zod.z.object({ deviceIds: zod.z.array(zod.z.number()).optional() }), zod.z.array(CameraStatusSchema).readonly()),
18653
+ /**
18654
+ * Disk-wins fleet reconcile after a recordings wipe. Starts the walk in
18655
+ * the addon process and returns immediately with the job snapshot — the
18656
+ * work outlives the tRPC/UDS 60s timeout. Poll `getReconcileFromDiskStatus`.
18657
+ * Admin-only. Idempotent while a job is already running.
18658
+ */
18659
+ reconcileFromDisk: require_sleep.method(zod.z.void(), DiskReconcileJobSchema, {
18660
+ kind: "mutation",
18661
+ auth: "admin"
18662
+ }),
18663
+ /** Snapshot of the in-flight or last disk-wins fleet reconcile. */
18664
+ getReconcileFromDiskStatus: require_sleep.method(zod.z.void(), DiskReconcileJobSchema, { auth: "admin" }),
18548
18665
  /** List every template the operator has saved. */
18549
18666
  listTemplates: require_sleep.method(zod.z.void(), zod.z.array(PipelineTemplateSchema).readonly()),
18550
18667
  /** Create a new named preset from a given CameraPipelineConfig. */
@@ -20107,8 +20224,28 @@ var ClipSchema = zod.z.object({
20107
20224
  startMs: zod.z.number(),
20108
20225
  endMs: zod.z.number()
20109
20226
  }),
20110
- /** Thumbnail URL (lazy; e.g. analytics `getEventMedia`). Never inlined. */
20111
- thumbnail: zod.z.string().optional()
20227
+ /**
20228
+ * Lazy thumbnail URL, never inlined.
20229
+ *
20230
+ * Recording-derived clips (events-mode keep-window, and the prepared
20231
+ * continuous event+fragment visit) MUST use the snapshot of the **main
20232
+ * event of the interval** — `getEventMedia({ eventId, kind: 'snapshot' })`
20233
+ * of the event that owns `kind` (object > motion > audio). Do not extract
20234
+ * a keyframe from the recorded segments. Other providers (onboard, HKSV)
20235
+ * mint their own stills.
20236
+ */
20237
+ thumbnail: zod.z.string().optional(),
20238
+ /** Analytics event ids that overlap this visit. Empty on footage-only clips.
20239
+ * The default provider's visit grain puts many motion heartbeats on one clip
20240
+ * instead of minting one clip per marker. */
20241
+ eventIds: zod.z.array(zod.z.string()).optional(),
20242
+ /** Intra-visit footage holes (GOP rolls, discarded segments) still shorter
20243
+ * than `VISIT_MERGE_GAP_MS`. Playback concatenates around them; the timeline
20244
+ * bar keeps showing them via `recording.getAvailability`. */
20245
+ holes: zod.z.array(zod.z.object({
20246
+ startMs: zod.z.number(),
20247
+ endMs: zod.z.number()
20248
+ })).optional()
20112
20249
  });
20113
20250
  var ClipPlaybackSchema = zod.z.object({
20114
20251
  /** HLS master URL through the hub data-plane (Range + token in path). */
@@ -27680,7 +27817,9 @@ var ExportOptionsSchema = zod.z.object({
27680
27817
  includeAudio: zod.z.boolean(),
27681
27818
  maxLifeMs: zod.z.number().int().positive(),
27682
27819
  deleteAfterDownload: zod.z.boolean(),
27683
- title: zod.z.string().max(200).optional()
27820
+ title: zod.z.string().max(200).optional(),
27821
+ /** Notification-output target ids to ping when this export becomes ready. */
27822
+ notifyTargetIds: zod.z.array(zod.z.string().min(1)).max(20).optional()
27684
27823
  }).superRefine((v, ctx) => {
27685
27824
  if (v.speed !== void 0 && v.timelapse !== void 0) ctx.addIssue({
27686
27825
  code: zod.z.ZodIssueCode.custom,
@@ -27756,20 +27895,36 @@ var ExportBytesSchema = zod.z.object({
27756
27895
  name: zod.z.string(),
27757
27896
  bytes: zod.z.number().int().nonnegative()
27758
27897
  });
27898
+ /**
27899
+ * `createExport` input. `profiles` is the canonical field (min 1). A legacy
27900
+ * singular `profile` is still accepted so existing callers do not break.
27901
+ *
27902
+ * Must remain a ZodObject (`.loose()` for out-of-band `nodeId`).
27903
+ */
27904
+ var CreateExportInputSchema = zod.z.object({
27905
+ deviceId: zod.z.number(),
27906
+ /** @deprecated Prefer `profiles`. Kept so timelapse/notifiers keep working. */
27907
+ profile: zod.z.string().optional(),
27908
+ profiles: zod.z.array(zod.z.string()).min(1).optional(),
27909
+ fromMs: zod.z.number(),
27910
+ toMs: zod.z.number(),
27911
+ options: ExportOptionsSchema
27912
+ }).superRefine((v, ctx) => {
27913
+ if ((v.profiles !== void 0 && v.profiles.length > 0 ? v.profiles : v.profile !== void 0 ? [v.profile] : []).length < 1) ctx.addIssue({
27914
+ code: zod.z.ZodIssueCode.custom,
27915
+ message: "pass profiles[] (min 1) or legacy profile",
27916
+ path: ["profiles"]
27917
+ });
27918
+ });
27759
27919
  var recordingExportCapability = {
27760
27920
  name: "recording-export",
27761
27921
  scope: "system",
27762
27922
  mode: "singleton",
27763
27923
  methods: {
27764
- /** Queue a render of `[fromMs,toMs)` for `deviceId`/`profile`. Fails fast
27765
- * when no footage covers the range. Returns the queued record. */
27766
- createExport: require_sleep.method(zod.z.object({
27767
- deviceId: zod.z.number(),
27768
- profile: zod.z.string(),
27769
- fromMs: zod.z.number(),
27770
- toMs: zod.z.number(),
27771
- options: ExportOptionsSchema
27772
- }), ExportRecordSchema, {
27924
+ /** Queue a render of `[fromMs,toMs)` for `deviceId`/`profiles` (legacy
27925
+ * singular `profile` still accepted). Fails fast when no footage covers
27926
+ * the range. One job per profile; returns the first queued record. */
27927
+ createExport: require_sleep.method(CreateExportInputSchema, ExportRecordSchema, {
27773
27928
  kind: "mutation",
27774
27929
  auth: "protected"
27775
27930
  }),
@@ -31363,15 +31518,6 @@ var BaseDeviceProvider = class extends require_sleep.BaseAddon {
31363
31518
  labels: ["probe not implemented"]
31364
31519
  };
31365
31520
  }
31366
- /**
31367
- * Top-level devices restored at once in {@link onRestoreDevices}.
31368
- *
31369
- * Four covers the fleets this ships to without turning a boot into a burst a
31370
- * camera NVR answers with a refusal. A provider whose upstream is a single
31371
- * session with a serial command channel (a Baichuan hub, an NVR that
31372
- * serialises ISAPI) should lower it; nothing needs to raise it.
31373
- */
31374
- restoreConcurrency = 4;
31375
31521
  async restoreDevices(savedDevices) {
31376
31522
  await this.onRestoreDevices(savedDevices);
31377
31523
  if (savedDevices.length > 0) this.ctx.logger.info(`Restored ${savedDevices.length} ${this.providerName} device(s)`);
@@ -31426,14 +31572,7 @@ var BaseDeviceProvider = class extends require_sleep.BaseAddon {
31426
31572
  });
31427
31573
  }
31428
31574
  };
31429
- let nextTopLevel = 0;
31430
- await Promise.all(Array.from({ length: Math.min(Math.max(1, this.restoreConcurrency), topLevel.length) }, async () => {
31431
- for (;;) {
31432
- const saved = topLevel[nextTopLevel++];
31433
- if (saved === void 0) return;
31434
- await restoreOne(saved);
31435
- }
31436
- }));
31575
+ await Promise.all(topLevel.map((saved) => restoreOne(saved)));
31437
31576
  const childRows = savedDevices.filter((s) => s.parentDeviceId !== null);
31438
31577
  for (const saved of childRows) {
31439
31578
  const Class = this.deviceClasses[saved.type];
@@ -37246,6 +37385,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
37246
37385
  addonId: null,
37247
37386
  access: "create"
37248
37387
  },
37388
+ "pipelineAnalytics.reconcileFromDisk": {
37389
+ capName: "pipeline-analytics",
37390
+ capScope: "device",
37391
+ addonId: null,
37392
+ access: "create"
37393
+ },
37249
37394
  "pipelineAnalytics.refreshStorageLocationsForMigration": {
37250
37395
  capName: "pipeline-analytics",
37251
37396
  capScope: "device",
@@ -37648,6 +37793,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
37648
37793
  addonId: null,
37649
37794
  access: "view"
37650
37795
  },
37796
+ "pipelineOrchestrator.getReconcileFromDiskStatus": {
37797
+ capName: "pipeline-orchestrator",
37798
+ capScope: "system",
37799
+ addonId: null,
37800
+ access: "view"
37801
+ },
37651
37802
  "pipelineOrchestrator.listAgentSettings": {
37652
37803
  capName: "pipeline-orchestrator",
37653
37804
  capScope: "system",
@@ -37672,6 +37823,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
37672
37823
  addonId: null,
37673
37824
  access: "create"
37674
37825
  },
37826
+ "pipelineOrchestrator.reconcileFromDisk": {
37827
+ capName: "pipeline-orchestrator",
37828
+ capScope: "system",
37829
+ addonId: null,
37830
+ access: "create"
37831
+ },
37675
37832
  "pipelineOrchestrator.removeAgentSettings": {
37676
37833
  capName: "pipeline-orchestrator",
37677
37834
  capScope: "system",
@@ -40920,6 +41077,11 @@ var METHOD_DEVICE_SELECTORS = Object.freeze({
40920
41077
  form: "single",
40921
41078
  optional: true
40922
41079
  }],
41080
+ "pipelineAnalytics.reconcileFromDisk": [{
41081
+ name: "deviceId",
41082
+ form: "single",
41083
+ optional: false
41084
+ }],
40923
41085
  "pipelineAnalytics.restageRetrainTrack": [{
40924
41086
  name: "deviceId",
40925
41087
  form: "single",
@@ -42585,6 +42747,8 @@ function createSystemProxy(api) {
42585
42747
  getNodeInferenceDevices: (input) => dispatch("pipelineOrchestrator", "getNodeInferenceDevices", "query", input),
42586
42748
  resetNodePipelineDefaults: (input) => dispatch("pipelineOrchestrator", "resetNodePipelineDefaults", "mutation", input),
42587
42749
  getCameraStatuses: (input) => dispatch("pipelineOrchestrator", "getCameraStatuses", "query", input),
42750
+ reconcileFromDisk: (input) => dispatch("pipelineOrchestrator", "reconcileFromDisk", "mutation", input),
42751
+ getReconcileFromDiskStatus: (input) => dispatch("pipelineOrchestrator", "getReconcileFromDiskStatus", "query", input),
42588
42752
  listTemplates: (input) => dispatch("pipelineOrchestrator", "listTemplates", "query", input),
42589
42753
  saveTemplate: (input) => dispatch("pipelineOrchestrator", "saveTemplate", "mutation", input),
42590
42754
  updateTemplate: (input) => dispatch("pipelineOrchestrator", "updateTemplate", "mutation", input),
@@ -42633,6 +42797,7 @@ function createSystemProxy(api) {
42633
42797
  startStorageRebalance: (input) => dispatch("recording", "startStorageRebalance", "mutation", input)
42634
42798
  },
42635
42799
  recordingExport: {
42800
+ createExport: (input) => dispatch("recordingExport", "createExport", "mutation", input),
42636
42801
  getExport: (input) => dispatch("recordingExport", "getExport", "query", input),
42637
42802
  cancelExport: (input) => dispatch("recordingExport", "cancelExport", "mutation", input),
42638
42803
  deleteExport: (input) => dispatch("recordingExport", "deleteExport", "mutation", input),
@@ -45941,6 +46106,7 @@ exports.DEFAULT_EVENTS_BAND_BUFFER_SEC = DEFAULT_EVENTS_BAND_BUFFER_SEC;
45941
46106
  exports.DEFAULT_EVENT_COLOR = DEFAULT_EVENT_COLOR;
45942
46107
  exports.DEFAULT_FEATURES = DEFAULT_FEATURES;
45943
46108
  exports.DEFAULT_NATIVE_LEASE_SETTINGS = DEFAULT_NATIVE_LEASE_SETTINGS;
46109
+ exports.DEFAULT_RECORDING_PROFILES = DEFAULT_RECORDING_PROFILES;
45944
46110
  exports.DEFAULT_RETENTION = DEFAULT_RETENTION;
45945
46111
  exports.DEFAULT_RUNTIME_STATE_DURABILITY = require_sleep.DEFAULT_RUNTIME_STATE_DURABILITY;
45946
46112
  exports.DEFAULT_SCRUB_THUMBNAIL_PRESET = DEFAULT_SCRUB_THUMBNAIL_PRESET;
@@ -45991,6 +46157,7 @@ exports.DiscoveredChildDeviceSchema = DiscoveredChildDeviceSchema;
45991
46157
  exports.DiscoveredChildStatusSchema = DiscoveredChildStatusSchema;
45992
46158
  exports.DiscoveredDeviceSchema = DiscoveredDeviceSchema;
45993
46159
  exports.DiscoveredTargetSchema = DiscoveredTargetSchema;
46160
+ exports.DiskReconcileJobSchema = DiskReconcileJobSchema;
45994
46161
  exports.DisposerChain = require_sleep.DisposerChain;
45995
46162
  exports.DoorbellPressEventSchema = DoorbellPressEventSchema;
45996
46163
  exports.DoorbellStatusSchema = DoorbellStatusSchema;
@@ -46588,6 +46755,7 @@ exports.UpdateStatusSchema = UpdateStatusSchema;
46588
46755
  exports.UpdateUserInputSchema = UpdateUserInputSchema;
46589
46756
  exports.UserRecordSchema = UserRecordSchema;
46590
46757
  exports.UserSummarySchema = UserSummarySchema;
46758
+ exports.VISIT_MERGE_GAP_MS = VISIT_MERGE_GAP_MS;
46591
46759
  exports.VacuumControlStatusSchema = VacuumControlStatusSchema;
46592
46760
  exports.VacuumStateSchema = VacuumStateSchema;
46593
46761
  exports.ValveStateSchema = ValveStateSchema;
@@ -46930,6 +47098,7 @@ exports.resolveFormat = resolveFormat;
46930
47098
  exports.resolveHydratedFieldValue = require_sleep.resolveHydratedFieldValue;
46931
47099
  exports.resolveModelFormat = resolveModelFormat;
46932
47100
  exports.resolveMutate = resolveMutate;
47101
+ exports.resolveRecordingProfiles = resolveRecordingProfiles;
46933
47102
  exports.resolveRunnerId = resolveRunnerId;
46934
47103
  exports.resolveScrubThumbnailGeometry = resolveScrubThumbnailGeometry;
46935
47104
  exports.resolveVariantModelId = resolveVariantModelId;