@camstack/addon-post-analysis 0.1.19 → 0.1.20

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 (67) hide show
  1. package/dist/embedding-encoder/index.js +1 -1
  2. package/dist/embedding-encoder/index.mjs +1 -1
  3. package/dist/enrichment-engine/index.js +1 -1
  4. package/dist/enrichment-engine/index.mjs +1 -1
  5. package/dist/{index-BFbwYH1P.js → index-B0RhVv1c.js} +3514 -750
  6. package/dist/index-B0RhVv1c.js.map +1 -0
  7. package/dist/{index-BrTlzsrE.mjs → index-ot5PeFg_.mjs} +3517 -753
  8. package/dist/index-ot5PeFg_.mjs.map +1 -0
  9. package/dist/pipeline-analytics/@mf-types.zip +0 -0
  10. package/dist/pipeline-analytics/{__mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_sdk__loadShare__.mjs-h5aXOPSA.mjs → __mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_sdk__loadShare__.mjs-lantnv8e.mjs} +1 -1
  11. package/dist/pipeline-analytics/__mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.mjs-BD3oMNGB.mjs +29 -0
  12. package/dist/pipeline-analytics/__mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.mjs-BgOHCakr.mjs +18 -0
  13. package/dist/pipeline-analytics/{__mfe_internal__addon_pipeline_analytics_widgets__loadShare__react__loadShare__.mjs-BZTB2scQ.mjs → __mfe_internal__addon_pipeline_analytics_widgets__loadShare__react__loadShare__.mjs-D1qPKjvR.mjs} +2 -1
  14. package/dist/pipeline-analytics/{__mfe_internal__addon_pipeline_analytics_widgets__loadShare__react__loadShare__.mjs_commonjs-proxy-CJO5YKGV.mjs → __mfe_internal__addon_pipeline_analytics_widgets__loadShare__react__loadShare__.mjs_commonjs-proxy-B5X50Xa4.mjs} +1 -1
  15. package/dist/pipeline-analytics/{__mfe_internal__addon_pipeline_analytics_widgets__loadShare__react_mf_2_dom__loadShare__.mjs_commonjs-proxy-B0h0AGOH.mjs → __mfe_internal__addon_pipeline_analytics_widgets__loadShare__react_mf_2_dom__loadShare__.mjs_commonjs-proxy-B10b5k5J.mjs} +1 -1
  16. package/dist/pipeline-analytics/_stub.js +2 -3
  17. package/dist/pipeline-analytics/{_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-kZBmgzMg.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-DWB3apaJ.mjs} +6 -6
  18. package/dist/pipeline-analytics/{client-BlxIUpgf.mjs → client-C6xdgLZU.mjs} +2 -2
  19. package/dist/pipeline-analytics/{hostInit-qBB1Thhi.mjs → hostInit-3cyL9eyG.mjs} +12 -12
  20. package/dist/pipeline-analytics/{index-Dw6Q30NI.mjs → index-BCTHeI2m.mjs} +253 -267
  21. package/dist/pipeline-analytics/{index-DlhiA9R0.mjs → index-BuWLz0GG.mjs} +1 -1
  22. package/dist/pipeline-analytics/{index-DtdgkNgf.mjs → index-CIwq-tQL.mjs} +1 -1
  23. package/dist/pipeline-analytics/{index-BoL0rgZt.mjs → index-CWBMDbou.mjs} +1 -1
  24. package/dist/pipeline-analytics/index-CZhagnlH.mjs +67784 -0
  25. package/dist/pipeline-analytics/{index-CR1aiZDH.mjs → index-D883Q5B8.mjs} +1 -1
  26. package/dist/pipeline-analytics/{index-Dy2V7VOm.mjs → index-DtOI1aTU.mjs} +10112 -5987
  27. package/dist/pipeline-analytics/index.js +605 -42
  28. package/dist/pipeline-analytics/index.js.map +1 -1
  29. package/dist/pipeline-analytics/index.mjs +604 -42
  30. package/dist/pipeline-analytics/index.mjs.map +1 -1
  31. package/dist/pipeline-analytics/{jsx-runtime-Dlbl3gpr.mjs → jsx-runtime-DdLhuHmJ.mjs} +1 -1
  32. package/dist/pipeline-analytics/remoteEntry.js +1 -1
  33. package/dist/pipeline-analytics/{schemas-ClCuS4qa.mjs → schemas-B7L0qZtq.mjs} +411 -406
  34. package/package.json +12 -27
  35. package/dist/ffmpeg-config-DRONlBsj.mjs +0 -56
  36. package/dist/ffmpeg-config-DRONlBsj.mjs.map +0 -1
  37. package/dist/ffmpeg-config-uANz3sV5.js +0 -73
  38. package/dist/ffmpeg-config-uANz3sV5.js.map +0 -1
  39. package/dist/index-BFbwYH1P.js.map +0 -1
  40. package/dist/index-BrTlzsrE.mjs.map +0 -1
  41. package/dist/pipeline-analytics/__mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.mjs-NjF4kxzW.mjs +0 -19
  42. package/dist/pipeline-analytics/__mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.mjs-7HAAnpQu.mjs +0 -18
  43. package/dist/pipeline-analytics/index-i47purqY.mjs +0 -37880
  44. package/dist/playlist-generator-EhPaB7Hn.js +0 -48
  45. package/dist/playlist-generator-EhPaB7Hn.js.map +0 -1
  46. package/dist/playlist-generator-VTkgn53O.mjs +0 -48
  47. package/dist/playlist-generator-VTkgn53O.mjs.map +0 -1
  48. package/dist/recording/index.js +0 -257
  49. package/dist/recording/index.js.map +0 -1
  50. package/dist/recording/index.mjs +0 -235
  51. package/dist/recording/index.mjs.map +0 -1
  52. package/dist/recording-coordinator-BoGr5moz.js +0 -1052
  53. package/dist/recording-coordinator-BoGr5moz.js.map +0 -1
  54. package/dist/recording-coordinator-CsYH9LqF.mjs +0 -1012
  55. package/dist/recording-coordinator-CsYH9LqF.mjs.map +0 -1
  56. package/dist/recording-db-gOgaoQh0.js +0 -348
  57. package/dist/recording-db-gOgaoQh0.js.map +0 -1
  58. package/dist/recording-db-lIkSMTLq.mjs +0 -348
  59. package/dist/recording-db-lIkSMTLq.mjs.map +0 -1
  60. package/dist/recording-service-facade-B9lG6OFn.mjs +0 -123
  61. package/dist/recording-service-facade-B9lG6OFn.mjs.map +0 -1
  62. package/dist/recording-service-facade-Do1PKlAL.js +0 -123
  63. package/dist/recording-service-facade-Do1PKlAL.js.map +0 -1
  64. package/dist/storage-estimator-CRpoQc9j.js +0 -72
  65. package/dist/storage-estimator-CRpoQc9j.js.map +0 -1
  66. package/dist/storage-estimator-DzD8gWJH.mjs +0 -72
  67. package/dist/storage-estimator-DzD8gWJH.mjs.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"recording-service-facade-Do1PKlAL.js","sources":["../src/recording/recording-service-facade.ts"],"sourcesContent":["/**\n * RecordingServiceFacade — implements the recording-engine capability\n * contract by delegating to the internal service classes.\n *\n * Introduced in session 6 Sprint D.2 to replace the broken hand-written\n * recording.router.ts which invoked non-existent methods via a generic\n * `call()` dispatcher. Each facade method delegates to the correct\n * internal service: RecordingCoordinator, RecordingDb, PlaylistGenerator,\n * or StorageEstimator.\n *\n * The facade is the capability provider registered via\n * `context.registerProvider('recording-engine', facade)` — the auto-\n * generated cap router dispatches typed tRPC procedures directly to\n * these methods with full Zod input/output validation.\n */\n\nimport type { RecordingCoordinator } from './recording/recording-coordinator.js'\nimport type { RecordingDb } from './recording/recording-db.js'\nimport type { PlaylistGenerator } from './recording/playlist-generator.js'\nimport type { StorageEstimator } from './recording/storage-estimator.js'\nimport type {\n RecordingPolicy,\n RecordingSegment,\n RecordingThumbnail,\n RecordingStorageConfig,\n StorageEstimate,\n DataCategory,\n} from './recording/types.js'\n\ninterface FacadeDeps {\n readonly coordinator: RecordingCoordinator\n readonly db: RecordingDb\n readonly playlistGenerator: PlaylistGenerator\n readonly storageEstimator: StorageEstimator\n}\n\nexport class RecordingServiceFacade {\n constructor(private readonly deps: FacadeDeps) {}\n\n // ── Status ────────────────────────────────────────────────────────\n\n getStatus(): { activeRecordings: number; totalSegments: number; totalSizeMB: number } {\n const { db, coordinator } = this.deps\n const activeRecordings = coordinator.getActiveCount()\n const { segmentCount: totalSegments, totalBytes } = db.getGlobalStorageUsage()\n return {\n activeRecordings,\n totalSegments,\n totalSizeMB: Math.round(totalBytes / (1024 * 1024)),\n }\n }\n\n // ── Lifecycle ─────────────────────────────────────────────────────\n\n async enable(input: {\n deviceId: number\n policy: Omit<RecordingPolicy, 'deviceId'>\n storageOverrides?: readonly Omit<RecordingStorageConfig, 'deviceId'>[]\n ffmpegOverrides?: Record<string, unknown>\n }): Promise<void> {\n await this.deps.coordinator.enableRecording(input.deviceId, {\n policy: input.policy,\n storageOverrides: input.storageOverrides,\n ffmpegOverrides: input.ffmpegOverrides,\n })\n }\n\n async disable(input: { deviceId: number }): Promise<void> {\n await this.deps.coordinator.disableRecording(input.deviceId)\n }\n\n // ── Config ────────────────────────────────────────────────────────\n\n getConfig(input: { deviceId: number }): RecordingPolicy | null {\n return this.deps.db.getPolicy(input.deviceId)\n }\n\n async updateConfig(input: {\n deviceId: number\n policy: Omit<RecordingPolicy, 'deviceId'>\n ffmpegOverrides?: Record<string, unknown>\n }): Promise<void> {\n this.deps.db.upsertPolicy({ ...input.policy, deviceId: input.deviceId })\n // If the device is actively recording, restart with the new config\n if (this.deps.coordinator.isRecording(input.deviceId)) {\n await this.deps.coordinator.disableRecording(input.deviceId)\n await this.deps.coordinator.enableRecording(input.deviceId, {\n policy: input.policy,\n ffmpegOverrides: input.ffmpegOverrides,\n })\n }\n }\n\n // ── Playback ──────────────────────────────────────────────────────\n\n getPlaylist(input: {\n deviceId: number\n streamId: string\n startTime: number\n endTime: number\n live?: boolean\n }): string {\n return this.deps.playlistGenerator.generate(\n input.deviceId,\n input.streamId,\n input.startTime,\n input.endTime,\n { live: input.live },\n )\n }\n\n getThumbnail(input: {\n deviceId: number\n timestamp: number\n category?: string\n }): RecordingThumbnail | null {\n return this.deps.db.findNearestThumbnail(\n input.deviceId,\n input.timestamp,\n input.category ?? 'scrub',\n )\n }\n\n getSegments(input: {\n deviceId: number\n streamId: string\n startTime: number\n endTime: number\n }): readonly RecordingSegment[] {\n return this.deps.db.querySegments(\n input.deviceId,\n input.streamId,\n input.startTime,\n input.endTime,\n )\n }\n\n getAvailability(input: {\n deviceId: number\n startTime: number\n endTime: number\n }): readonly { startTime: number; endTime: number; streams: readonly string[] }[] {\n return this.deps.db.getAvailability(\n input.deviceId,\n input.startTime,\n input.endTime,\n )\n }\n\n // ── Storage ───────────────────────────────────────────────────────\n\n estimateStorage(input: {\n deviceId: number\n motionInput?: { avgEventsPerDay: number; avgDurationSec: number }\n }): StorageEstimate {\n return this.deps.storageEstimator.estimateForDevice(\n input.deviceId,\n input.motionInput,\n )\n }\n\n estimateGlobalStorage(): StorageEstimate {\n return this.deps.storageEstimator.estimateGlobal()\n }\n\n getStorageUsage(input: { deviceId: number; streamId: string }): {\n totalBytes: number\n segmentCount: number\n } {\n return this.deps.db.getStorageUsage(input.deviceId, input.streamId)\n }\n\n // ── Policy ────────────────────────────────────────────────────────\n\n setPolicy(input: {\n deviceId: number\n policy: Omit<RecordingPolicy, 'deviceId'>\n }): void {\n this.deps.db.upsertPolicy({ ...input.policy, deviceId: input.deviceId })\n }\n\n getPolicy(input: { deviceId: number }): RecordingPolicy | null {\n return this.deps.db.getPolicy(input.deviceId)\n }\n\n getPolicyStatus(input: { deviceId: number }): {\n deviceId: number\n enabled: boolean\n mode: RecordingPolicy['mode']\n activeStreams: number\n } | null {\n const policy = this.deps.db.getPolicy(input.deviceId)\n if (!policy) return null\n const activeStreams = this.deps.coordinator.isRecording(input.deviceId)\n ? policy.streams.length\n : 0\n return {\n deviceId: input.deviceId,\n enabled: policy.enabled,\n mode: policy.mode,\n activeStreams,\n }\n }\n\n // ── Retention ─────────────────────────────────────────────────────\n\n getRetentionConfig(input: {\n deviceId: number\n dataCategory: DataCategory\n }): RecordingStorageConfig | null {\n return this.deps.db.resolveStorageConfig(input.deviceId, input.dataCategory)\n }\n\n updateRetentionConfig(input: RecordingStorageConfig): void {\n this.deps.db.upsertStorageConfig(input)\n }\n\n // ── Motion ────────────────────────────────────────────────────────\n\n getMotionStats(input: {\n deviceId: number\n startTime: number\n endTime: number\n }): {\n totalEvents: number\n avgDurationSec: number\n avgEventsPerDay: number\n dutyCyclePercent: number\n } {\n return this.deps.db.getMotionStats(\n input.deviceId,\n input.startTime,\n input.endTime,\n )\n }\n}\n"],"names":[],"mappings":"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"}
@@ -1,72 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- class StorageEstimator {
4
- constructor(db, networkTracker) {
5
- this.db = db;
6
- this.networkTracker = networkTracker;
7
- }
8
- estimateForDevice(deviceId, motionInput) {
9
- const policy = this.db.getPolicy(deviceId);
10
- if (!policy) return { perStream: {}, thumbnails: { estimatedGb: 0 }, totalEstimatedGb: 0 };
11
- const stats = this.networkTracker.getDeviceStats(deviceId);
12
- const perStream = {};
13
- let totalGb = 0;
14
- const motionEstimate = motionInput ? {
15
- avgEventsPerDay: motionInput.avgEventsPerDay,
16
- avgDurationSec: motionInput.avgDurationSec,
17
- dutyCyclePercent: motionInput.avgEventsPerDay * motionInput.avgDurationSec / 86400 * 100
18
- } : void 0;
19
- for (const sp of policy.streams) {
20
- const category = `recording:${sp.streamId}`;
21
- const config = this.db.resolveStorageConfig(deviceId, category);
22
- const retentionDays = config?.retentionDays ?? null;
23
- const retentionGb = config?.retentionGb ?? null;
24
- const streamStats = stats?.streams[sp.streamId];
25
- const observedBitrate = streamStats?.observedBitrateKbps ?? 0;
26
- const bitrateKbps = observedBitrate > 0 ? observedBitrate : streamStats?.nominalBitrateKbps ?? 4e3;
27
- let estimatedGb = 0;
28
- if (retentionDays !== null) {
29
- const retentionSeconds = retentionDays * 86400;
30
- estimatedGb = bitrateKbps * retentionSeconds / 8 / 1024 / 1024 / 1024;
31
- }
32
- if (policy.mode === "motion" && motionEstimate) {
33
- estimatedGb = estimatedGb * motionEstimate.dutyCyclePercent / 100;
34
- }
35
- let estimatedDaysAtCapacity = null;
36
- if (retentionGb !== null && estimatedGb > retentionGb) {
37
- estimatedDaysAtCapacity = retentionDays !== null ? retentionDays * (retentionGb / estimatedGb) : null;
38
- estimatedGb = retentionGb;
39
- }
40
- perStream[sp.streamId] = { bitrateKbps, retentionDays, retentionGb, estimatedGb, estimatedDaysAtCapacity };
41
- totalGb += estimatedGb;
42
- }
43
- const thumbRetentionDays = policy.streams[0] ? this.db.resolveStorageConfig(deviceId, "thumbnail:scrub")?.retentionDays ?? 7 : 7;
44
- const thumbGb = 2 * 24 * thumbRetentionDays / 1024;
45
- totalGb += thumbGb;
46
- return { perStream, thumbnails: { estimatedGb: thumbGb }, totalEstimatedGb: totalGb, motionEstimate };
47
- }
48
- /**
49
- * Estimate global storage across all devices with active policies.
50
- * Sums per-device estimates. No motion weighting — uses continuous mode
51
- * for the global view.
52
- */
53
- estimateGlobal() {
54
- const allPolicies = this.db.getEnabledPolicies();
55
- let totalGb = 0;
56
- const perStream = {};
57
- let totalThumbGb = 0;
58
- for (const policy of allPolicies) {
59
- if (!policy.enabled) continue;
60
- const deviceEstimate = this.estimateForDevice(policy.deviceId);
61
- totalGb += deviceEstimate.totalEstimatedGb;
62
- totalThumbGb += deviceEstimate.thumbnails.estimatedGb;
63
- for (const [key, val] of Object.entries(deviceEstimate.perStream)) {
64
- const globalKey = `${policy.deviceId}/${key}`;
65
- perStream[globalKey] = val;
66
- }
67
- }
68
- return { perStream, thumbnails: { estimatedGb: totalThumbGb }, totalEstimatedGb: totalGb };
69
- }
70
- }
71
- exports.StorageEstimator = StorageEstimator;
72
- //# sourceMappingURL=storage-estimator-CRpoQc9j.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"storage-estimator-CRpoQc9j.js","sources":["../src/recording/recording/storage-estimator.ts"],"sourcesContent":["import type { INetworkQualityTracker } from '@camstack/types'\nimport type { RecordingDb } from './recording-db.js'\nimport type { DataCategory, StorageEstimate, StreamEstimate } from './types.js'\n\ninterface MotionEstimateInput {\n readonly avgEventsPerDay: number\n readonly avgDurationSec: number\n}\n\nexport class StorageEstimator {\n constructor(\n private readonly db: RecordingDb,\n private readonly networkTracker: INetworkQualityTracker,\n ) {}\n\n estimateForDevice(deviceId: number, motionInput?: MotionEstimateInput): StorageEstimate {\n const policy = this.db.getPolicy(deviceId)\n if (!policy) return { perStream: {}, thumbnails: { estimatedGb: 0 }, totalEstimatedGb: 0 }\n\n const stats = this.networkTracker.getDeviceStats(deviceId)\n const perStream: Record<string, StreamEstimate> = {}\n let totalGb = 0\n\n const motionEstimate = motionInput ? {\n avgEventsPerDay: motionInput.avgEventsPerDay,\n avgDurationSec: motionInput.avgDurationSec,\n dutyCyclePercent: (motionInput.avgEventsPerDay * motionInput.avgDurationSec / 86400) * 100,\n } : undefined\n\n for (const sp of policy.streams) {\n const category = `recording:${sp.streamId}` as DataCategory\n const config = this.db.resolveStorageConfig(deviceId, category)\n const retentionDays = config?.retentionDays ?? null\n const retentionGb = config?.retentionGb ?? null\n\n const streamStats = stats?.streams[sp.streamId]\n const observedBitrate = streamStats?.observedBitrateKbps ?? 0\n const bitrateKbps = observedBitrate > 0\n ? observedBitrate\n : (streamStats?.nominalBitrateKbps ?? 4000)\n\n let estimatedGb = 0\n if (retentionDays !== null) {\n const retentionSeconds = retentionDays * 86400\n estimatedGb = (bitrateKbps * retentionSeconds) / 8 / 1024 / 1024 / 1024\n }\n\n if (policy.mode === 'motion' && motionEstimate) {\n estimatedGb = estimatedGb * motionEstimate.dutyCyclePercent / 100\n }\n\n let estimatedDaysAtCapacity: number | null = null\n if (retentionGb !== null && estimatedGb > retentionGb) {\n estimatedDaysAtCapacity = retentionDays !== null ? retentionDays * (retentionGb / estimatedGb) : null\n estimatedGb = retentionGb\n }\n\n perStream[sp.streamId] = { bitrateKbps, retentionDays, retentionGb, estimatedGb, estimatedDaysAtCapacity }\n totalGb += estimatedGb\n }\n\n const thumbRetentionDays = policy.streams[0]\n ? (this.db.resolveStorageConfig(deviceId, 'thumbnail:scrub')?.retentionDays ?? 7)\n : 7\n const thumbGb = (2 * 24 * thumbRetentionDays) / 1024\n totalGb += thumbGb\n\n return { perStream, thumbnails: { estimatedGb: thumbGb }, totalEstimatedGb: totalGb, motionEstimate }\n }\n\n /**\n * Estimate global storage across all devices with active policies.\n * Sums per-device estimates. No motion weighting — uses continuous mode\n * for the global view.\n */\n estimateGlobal(): StorageEstimate {\n const allPolicies = this.db.getEnabledPolicies()\n let totalGb = 0\n const perStream: Record<string, StreamEstimate> = {}\n let totalThumbGb = 0\n\n for (const policy of allPolicies) {\n if (!policy.enabled) continue\n const deviceEstimate = this.estimateForDevice(policy.deviceId)\n totalGb += deviceEstimate.totalEstimatedGb\n totalThumbGb += deviceEstimate.thumbnails.estimatedGb\n for (const [key, val] of Object.entries(deviceEstimate.perStream)) {\n const globalKey = `${policy.deviceId}/${key}`\n perStream[globalKey] = val\n }\n }\n\n return { perStream, thumbnails: { estimatedGb: totalThumbGb }, totalEstimatedGb: totalGb }\n }\n}\n"],"names":[],"mappings":";;AASO,MAAM,iBAAiB;AAAA,EAC5B,YACmB,IACA,gBACjB;AAFiB,SAAA,KAAA;AACA,SAAA,iBAAA;AAAA,EAChB;AAAA,EAEH,kBAAkB,UAAkB,aAAoD;AACtF,UAAM,SAAS,KAAK,GAAG,UAAU,QAAQ;AACzC,QAAI,CAAC,OAAQ,QAAO,EAAE,WAAW,CAAA,GAAI,YAAY,EAAE,aAAa,KAAK,kBAAkB,EAAA;AAEvF,UAAM,QAAQ,KAAK,eAAe,eAAe,QAAQ;AACzD,UAAM,YAA4C,CAAA;AAClD,QAAI,UAAU;AAEd,UAAM,iBAAiB,cAAc;AAAA,MACnC,iBAAiB,YAAY;AAAA,MAC7B,gBAAgB,YAAY;AAAA,MAC5B,kBAAmB,YAAY,kBAAkB,YAAY,iBAAiB,QAAS;AAAA,IAAA,IACrF;AAEJ,eAAW,MAAM,OAAO,SAAS;AAC/B,YAAM,WAAW,aAAa,GAAG,QAAQ;AACzC,YAAM,SAAS,KAAK,GAAG,qBAAqB,UAAU,QAAQ;AAC9D,YAAM,gBAAgB,QAAQ,iBAAiB;AAC/C,YAAM,cAAc,QAAQ,eAAe;AAE3C,YAAM,cAAc,OAAO,QAAQ,GAAG,QAAQ;AAC9C,YAAM,kBAAkB,aAAa,uBAAuB;AAC5D,YAAM,cAAc,kBAAkB,IAClC,kBACC,aAAa,sBAAsB;AAExC,UAAI,cAAc;AAClB,UAAI,kBAAkB,MAAM;AAC1B,cAAM,mBAAmB,gBAAgB;AACzC,sBAAe,cAAc,mBAAoB,IAAI,OAAO,OAAO;AAAA,MACrE;AAEA,UAAI,OAAO,SAAS,YAAY,gBAAgB;AAC9C,sBAAc,cAAc,eAAe,mBAAmB;AAAA,MAChE;AAEA,UAAI,0BAAyC;AAC7C,UAAI,gBAAgB,QAAQ,cAAc,aAAa;AACrD,kCAA0B,kBAAkB,OAAO,iBAAiB,cAAc,eAAe;AACjG,sBAAc;AAAA,MAChB;AAEA,gBAAU,GAAG,QAAQ,IAAI,EAAE,aAAa,eAAe,aAAa,aAAa,wBAAA;AACjF,iBAAW;AAAA,IACb;AAEA,UAAM,qBAAqB,OAAO,QAAQ,CAAC,IACtC,KAAK,GAAG,qBAAqB,UAAU,iBAAiB,GAAG,iBAAiB,IAC7E;AACJ,UAAM,UAAW,IAAI,KAAK,qBAAsB;AAChD,eAAW;AAEX,WAAO,EAAE,WAAW,YAAY,EAAE,aAAa,WAAW,kBAAkB,SAAS,eAAA;AAAA,EACvF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,iBAAkC;AAChC,UAAM,cAAc,KAAK,GAAG,mBAAA;AAC5B,QAAI,UAAU;AACd,UAAM,YAA4C,CAAA;AAClD,QAAI,eAAe;AAEnB,eAAW,UAAU,aAAa;AAChC,UAAI,CAAC,OAAO,QAAS;AACrB,YAAM,iBAAiB,KAAK,kBAAkB,OAAO,QAAQ;AAC7D,iBAAW,eAAe;AAC1B,sBAAgB,eAAe,WAAW;AAC1C,iBAAW,CAAC,KAAK,GAAG,KAAK,OAAO,QAAQ,eAAe,SAAS,GAAG;AACjE,cAAM,YAAY,GAAG,OAAO,QAAQ,IAAI,GAAG;AAC3C,kBAAU,SAAS,IAAI;AAAA,MACzB;AAAA,IACF;AAEA,WAAO,EAAE,WAAW,YAAY,EAAE,aAAa,aAAA,GAAgB,kBAAkB,QAAA;AAAA,EACnF;AACF;;"}
@@ -1,72 +0,0 @@
1
- class StorageEstimator {
2
- constructor(db, networkTracker) {
3
- this.db = db;
4
- this.networkTracker = networkTracker;
5
- }
6
- estimateForDevice(deviceId, motionInput) {
7
- const policy = this.db.getPolicy(deviceId);
8
- if (!policy) return { perStream: {}, thumbnails: { estimatedGb: 0 }, totalEstimatedGb: 0 };
9
- const stats = this.networkTracker.getDeviceStats(deviceId);
10
- const perStream = {};
11
- let totalGb = 0;
12
- const motionEstimate = motionInput ? {
13
- avgEventsPerDay: motionInput.avgEventsPerDay,
14
- avgDurationSec: motionInput.avgDurationSec,
15
- dutyCyclePercent: motionInput.avgEventsPerDay * motionInput.avgDurationSec / 86400 * 100
16
- } : void 0;
17
- for (const sp of policy.streams) {
18
- const category = `recording:${sp.streamId}`;
19
- const config = this.db.resolveStorageConfig(deviceId, category);
20
- const retentionDays = config?.retentionDays ?? null;
21
- const retentionGb = config?.retentionGb ?? null;
22
- const streamStats = stats?.streams[sp.streamId];
23
- const observedBitrate = streamStats?.observedBitrateKbps ?? 0;
24
- const bitrateKbps = observedBitrate > 0 ? observedBitrate : streamStats?.nominalBitrateKbps ?? 4e3;
25
- let estimatedGb = 0;
26
- if (retentionDays !== null) {
27
- const retentionSeconds = retentionDays * 86400;
28
- estimatedGb = bitrateKbps * retentionSeconds / 8 / 1024 / 1024 / 1024;
29
- }
30
- if (policy.mode === "motion" && motionEstimate) {
31
- estimatedGb = estimatedGb * motionEstimate.dutyCyclePercent / 100;
32
- }
33
- let estimatedDaysAtCapacity = null;
34
- if (retentionGb !== null && estimatedGb > retentionGb) {
35
- estimatedDaysAtCapacity = retentionDays !== null ? retentionDays * (retentionGb / estimatedGb) : null;
36
- estimatedGb = retentionGb;
37
- }
38
- perStream[sp.streamId] = { bitrateKbps, retentionDays, retentionGb, estimatedGb, estimatedDaysAtCapacity };
39
- totalGb += estimatedGb;
40
- }
41
- const thumbRetentionDays = policy.streams[0] ? this.db.resolveStorageConfig(deviceId, "thumbnail:scrub")?.retentionDays ?? 7 : 7;
42
- const thumbGb = 2 * 24 * thumbRetentionDays / 1024;
43
- totalGb += thumbGb;
44
- return { perStream, thumbnails: { estimatedGb: thumbGb }, totalEstimatedGb: totalGb, motionEstimate };
45
- }
46
- /**
47
- * Estimate global storage across all devices with active policies.
48
- * Sums per-device estimates. No motion weighting — uses continuous mode
49
- * for the global view.
50
- */
51
- estimateGlobal() {
52
- const allPolicies = this.db.getEnabledPolicies();
53
- let totalGb = 0;
54
- const perStream = {};
55
- let totalThumbGb = 0;
56
- for (const policy of allPolicies) {
57
- if (!policy.enabled) continue;
58
- const deviceEstimate = this.estimateForDevice(policy.deviceId);
59
- totalGb += deviceEstimate.totalEstimatedGb;
60
- totalThumbGb += deviceEstimate.thumbnails.estimatedGb;
61
- for (const [key, val] of Object.entries(deviceEstimate.perStream)) {
62
- const globalKey = `${policy.deviceId}/${key}`;
63
- perStream[globalKey] = val;
64
- }
65
- }
66
- return { perStream, thumbnails: { estimatedGb: totalThumbGb }, totalEstimatedGb: totalGb };
67
- }
68
- }
69
- export {
70
- StorageEstimator
71
- };
72
- //# sourceMappingURL=storage-estimator-DzD8gWJH.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"storage-estimator-DzD8gWJH.mjs","sources":["../src/recording/recording/storage-estimator.ts"],"sourcesContent":["import type { INetworkQualityTracker } from '@camstack/types'\nimport type { RecordingDb } from './recording-db.js'\nimport type { DataCategory, StorageEstimate, StreamEstimate } from './types.js'\n\ninterface MotionEstimateInput {\n readonly avgEventsPerDay: number\n readonly avgDurationSec: number\n}\n\nexport class StorageEstimator {\n constructor(\n private readonly db: RecordingDb,\n private readonly networkTracker: INetworkQualityTracker,\n ) {}\n\n estimateForDevice(deviceId: number, motionInput?: MotionEstimateInput): StorageEstimate {\n const policy = this.db.getPolicy(deviceId)\n if (!policy) return { perStream: {}, thumbnails: { estimatedGb: 0 }, totalEstimatedGb: 0 }\n\n const stats = this.networkTracker.getDeviceStats(deviceId)\n const perStream: Record<string, StreamEstimate> = {}\n let totalGb = 0\n\n const motionEstimate = motionInput ? {\n avgEventsPerDay: motionInput.avgEventsPerDay,\n avgDurationSec: motionInput.avgDurationSec,\n dutyCyclePercent: (motionInput.avgEventsPerDay * motionInput.avgDurationSec / 86400) * 100,\n } : undefined\n\n for (const sp of policy.streams) {\n const category = `recording:${sp.streamId}` as DataCategory\n const config = this.db.resolveStorageConfig(deviceId, category)\n const retentionDays = config?.retentionDays ?? null\n const retentionGb = config?.retentionGb ?? null\n\n const streamStats = stats?.streams[sp.streamId]\n const observedBitrate = streamStats?.observedBitrateKbps ?? 0\n const bitrateKbps = observedBitrate > 0\n ? observedBitrate\n : (streamStats?.nominalBitrateKbps ?? 4000)\n\n let estimatedGb = 0\n if (retentionDays !== null) {\n const retentionSeconds = retentionDays * 86400\n estimatedGb = (bitrateKbps * retentionSeconds) / 8 / 1024 / 1024 / 1024\n }\n\n if (policy.mode === 'motion' && motionEstimate) {\n estimatedGb = estimatedGb * motionEstimate.dutyCyclePercent / 100\n }\n\n let estimatedDaysAtCapacity: number | null = null\n if (retentionGb !== null && estimatedGb > retentionGb) {\n estimatedDaysAtCapacity = retentionDays !== null ? retentionDays * (retentionGb / estimatedGb) : null\n estimatedGb = retentionGb\n }\n\n perStream[sp.streamId] = { bitrateKbps, retentionDays, retentionGb, estimatedGb, estimatedDaysAtCapacity }\n totalGb += estimatedGb\n }\n\n const thumbRetentionDays = policy.streams[0]\n ? (this.db.resolveStorageConfig(deviceId, 'thumbnail:scrub')?.retentionDays ?? 7)\n : 7\n const thumbGb = (2 * 24 * thumbRetentionDays) / 1024\n totalGb += thumbGb\n\n return { perStream, thumbnails: { estimatedGb: thumbGb }, totalEstimatedGb: totalGb, motionEstimate }\n }\n\n /**\n * Estimate global storage across all devices with active policies.\n * Sums per-device estimates. No motion weighting — uses continuous mode\n * for the global view.\n */\n estimateGlobal(): StorageEstimate {\n const allPolicies = this.db.getEnabledPolicies()\n let totalGb = 0\n const perStream: Record<string, StreamEstimate> = {}\n let totalThumbGb = 0\n\n for (const policy of allPolicies) {\n if (!policy.enabled) continue\n const deviceEstimate = this.estimateForDevice(policy.deviceId)\n totalGb += deviceEstimate.totalEstimatedGb\n totalThumbGb += deviceEstimate.thumbnails.estimatedGb\n for (const [key, val] of Object.entries(deviceEstimate.perStream)) {\n const globalKey = `${policy.deviceId}/${key}`\n perStream[globalKey] = val\n }\n }\n\n return { perStream, thumbnails: { estimatedGb: totalThumbGb }, totalEstimatedGb: totalGb }\n }\n}\n"],"names":[],"mappings":"AASO,MAAM,iBAAiB;AAAA,EAC5B,YACmB,IACA,gBACjB;AAFiB,SAAA,KAAA;AACA,SAAA,iBAAA;AAAA,EAChB;AAAA,EAEH,kBAAkB,UAAkB,aAAoD;AACtF,UAAM,SAAS,KAAK,GAAG,UAAU,QAAQ;AACzC,QAAI,CAAC,OAAQ,QAAO,EAAE,WAAW,CAAA,GAAI,YAAY,EAAE,aAAa,KAAK,kBAAkB,EAAA;AAEvF,UAAM,QAAQ,KAAK,eAAe,eAAe,QAAQ;AACzD,UAAM,YAA4C,CAAA;AAClD,QAAI,UAAU;AAEd,UAAM,iBAAiB,cAAc;AAAA,MACnC,iBAAiB,YAAY;AAAA,MAC7B,gBAAgB,YAAY;AAAA,MAC5B,kBAAmB,YAAY,kBAAkB,YAAY,iBAAiB,QAAS;AAAA,IAAA,IACrF;AAEJ,eAAW,MAAM,OAAO,SAAS;AAC/B,YAAM,WAAW,aAAa,GAAG,QAAQ;AACzC,YAAM,SAAS,KAAK,GAAG,qBAAqB,UAAU,QAAQ;AAC9D,YAAM,gBAAgB,QAAQ,iBAAiB;AAC/C,YAAM,cAAc,QAAQ,eAAe;AAE3C,YAAM,cAAc,OAAO,QAAQ,GAAG,QAAQ;AAC9C,YAAM,kBAAkB,aAAa,uBAAuB;AAC5D,YAAM,cAAc,kBAAkB,IAClC,kBACC,aAAa,sBAAsB;AAExC,UAAI,cAAc;AAClB,UAAI,kBAAkB,MAAM;AAC1B,cAAM,mBAAmB,gBAAgB;AACzC,sBAAe,cAAc,mBAAoB,IAAI,OAAO,OAAO;AAAA,MACrE;AAEA,UAAI,OAAO,SAAS,YAAY,gBAAgB;AAC9C,sBAAc,cAAc,eAAe,mBAAmB;AAAA,MAChE;AAEA,UAAI,0BAAyC;AAC7C,UAAI,gBAAgB,QAAQ,cAAc,aAAa;AACrD,kCAA0B,kBAAkB,OAAO,iBAAiB,cAAc,eAAe;AACjG,sBAAc;AAAA,MAChB;AAEA,gBAAU,GAAG,QAAQ,IAAI,EAAE,aAAa,eAAe,aAAa,aAAa,wBAAA;AACjF,iBAAW;AAAA,IACb;AAEA,UAAM,qBAAqB,OAAO,QAAQ,CAAC,IACtC,KAAK,GAAG,qBAAqB,UAAU,iBAAiB,GAAG,iBAAiB,IAC7E;AACJ,UAAM,UAAW,IAAI,KAAK,qBAAsB;AAChD,eAAW;AAEX,WAAO,EAAE,WAAW,YAAY,EAAE,aAAa,WAAW,kBAAkB,SAAS,eAAA;AAAA,EACvF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,iBAAkC;AAChC,UAAM,cAAc,KAAK,GAAG,mBAAA;AAC5B,QAAI,UAAU;AACd,UAAM,YAA4C,CAAA;AAClD,QAAI,eAAe;AAEnB,eAAW,UAAU,aAAa;AAChC,UAAI,CAAC,OAAO,QAAS;AACrB,YAAM,iBAAiB,KAAK,kBAAkB,OAAO,QAAQ;AAC7D,iBAAW,eAAe;AAC1B,sBAAgB,eAAe,WAAW;AAC1C,iBAAW,CAAC,KAAK,GAAG,KAAK,OAAO,QAAQ,eAAe,SAAS,GAAG;AACjE,cAAM,YAAY,GAAG,OAAO,QAAQ,IAAI,GAAG;AAC3C,kBAAU,SAAS,IAAI;AAAA,MACzB;AAAA,IACF;AAEA,WAAO,EAAE,WAAW,YAAY,EAAE,aAAa,aAAA,GAAgB,kBAAkB,QAAA;AAAA,EACnF;AACF;"}