@camstack/addon-post-analysis 0.1.18 → 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.
- package/dist/embedding-encoder/index.js +1 -1
- package/dist/embedding-encoder/index.mjs +1 -1
- package/dist/enrichment-engine/index.js +1 -1
- package/dist/enrichment-engine/index.mjs +1 -1
- package/dist/{index-DafwGlkQ.js → index-B0RhVv1c.js} +3940 -807
- package/dist/index-B0RhVv1c.js.map +1 -0
- package/dist/{index-CIJfmsWX.mjs → index-ot5PeFg_.mjs} +3943 -810
- package/dist/index-ot5PeFg_.mjs.map +1 -0
- package/dist/pipeline-analytics/@mf-types.zip +0 -0
- 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
- package/dist/pipeline-analytics/__mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.mjs-BD3oMNGB.mjs +29 -0
- 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
- package/dist/pipeline-analytics/{__mfe_internal__addon_pipeline_analytics_widgets__loadShare__react__loadShare__.mjs-D-USVuHq.mjs → __mfe_internal__addon_pipeline_analytics_widgets__loadShare__react__loadShare__.mjs-D1qPKjvR.mjs} +3 -1
- package/dist/pipeline-analytics/{__mfe_internal__addon_pipeline_analytics_widgets__loadShare__react__loadShare__.mjs_commonjs-proxy-qQCPW8pT.mjs → __mfe_internal__addon_pipeline_analytics_widgets__loadShare__react__loadShare__.mjs_commonjs-proxy-B5X50Xa4.mjs} +1 -1
- package/dist/pipeline-analytics/{__mfe_internal__addon_pipeline_analytics_widgets__loadShare__react_mf_2_dom__loadShare__.mjs_commonjs-proxy-Bv9bYz9E.mjs → __mfe_internal__addon_pipeline_analytics_widgets__loadShare__react_mf_2_dom__loadShare__.mjs_commonjs-proxy-B10b5k5J.mjs} +1 -1
- package/dist/pipeline-analytics/_stub.js +2 -3
- package/dist/pipeline-analytics/{_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-B3kCe2qM.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-DWB3apaJ.mjs} +6 -6
- package/dist/pipeline-analytics/{client-DHmQcIWy.mjs → client-C6xdgLZU.mjs} +2 -2
- package/dist/pipeline-analytics/{hostInit-CuWzic_f.mjs → hostInit-3cyL9eyG.mjs} +12 -12
- package/dist/pipeline-analytics/{index-BA65ZJOW.mjs → index-BCTHeI2m.mjs} +254 -268
- package/dist/pipeline-analytics/{index-Crs1D0Uu.mjs → index-BuWLz0GG.mjs} +1 -1
- package/dist/pipeline-analytics/{index-gpelkpEE.mjs → index-CIwq-tQL.mjs} +1 -1
- package/dist/pipeline-analytics/{index-CHnXxMRA.mjs → index-CWBMDbou.mjs} +1 -1
- package/dist/pipeline-analytics/index-CZhagnlH.mjs +67784 -0
- package/dist/pipeline-analytics/{index-DicaGC31.mjs → index-D883Q5B8.mjs} +1 -1
- package/dist/pipeline-analytics/index-DtOI1aTU.mjs +18504 -0
- package/dist/pipeline-analytics/index.js +605 -42
- package/dist/pipeline-analytics/index.js.map +1 -1
- package/dist/pipeline-analytics/index.mjs +604 -42
- package/dist/pipeline-analytics/index.mjs.map +1 -1
- package/dist/pipeline-analytics/{jsx-runtime-Wcfyyyt4.mjs → jsx-runtime-DdLhuHmJ.mjs} +1 -1
- package/dist/pipeline-analytics/remoteEntry.js +1 -1
- package/dist/pipeline-analytics/{schemas-ChN4Ih0h.mjs → schemas-B7L0qZtq.mjs} +530 -515
- package/package.json +12 -27
- package/dist/ffmpeg-config-DRONlBsj.mjs +0 -56
- package/dist/ffmpeg-config-DRONlBsj.mjs.map +0 -1
- package/dist/ffmpeg-config-uANz3sV5.js +0 -73
- package/dist/ffmpeg-config-uANz3sV5.js.map +0 -1
- package/dist/index-CIJfmsWX.mjs.map +0 -1
- package/dist/index-DafwGlkQ.js.map +0 -1
- package/dist/pipeline-analytics/__mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.mjs-d8PmLbO2.mjs +0 -19
- package/dist/pipeline-analytics/__mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.mjs-BcWYbuKp.mjs +0 -18
- package/dist/pipeline-analytics/index-CUXiTSWS.mjs +0 -13883
- package/dist/pipeline-analytics/index-gbflFMEY.mjs +0 -36403
- package/dist/playlist-generator-EhPaB7Hn.js +0 -48
- package/dist/playlist-generator-EhPaB7Hn.js.map +0 -1
- package/dist/playlist-generator-VTkgn53O.mjs +0 -48
- package/dist/playlist-generator-VTkgn53O.mjs.map +0 -1
- package/dist/recording/index.js +0 -257
- package/dist/recording/index.js.map +0 -1
- package/dist/recording/index.mjs +0 -235
- package/dist/recording/index.mjs.map +0 -1
- package/dist/recording-coordinator-BKsM_JGg.js +0 -1052
- package/dist/recording-coordinator-BKsM_JGg.js.map +0 -1
- package/dist/recording-coordinator-Bw3N1gYu.mjs +0 -1012
- package/dist/recording-coordinator-Bw3N1gYu.mjs.map +0 -1
- package/dist/recording-db-gOgaoQh0.js +0 -348
- package/dist/recording-db-gOgaoQh0.js.map +0 -1
- package/dist/recording-db-lIkSMTLq.mjs +0 -348
- package/dist/recording-db-lIkSMTLq.mjs.map +0 -1
- package/dist/recording-service-facade-B9lG6OFn.mjs +0 -123
- package/dist/recording-service-facade-B9lG6OFn.mjs.map +0 -1
- package/dist/recording-service-facade-Do1PKlAL.js +0 -123
- package/dist/recording-service-facade-Do1PKlAL.js.map +0 -1
- package/dist/storage-estimator-CRpoQc9j.js +0 -72
- package/dist/storage-estimator-CRpoQc9j.js.map +0 -1
- package/dist/storage-estimator-DzD8gWJH.mjs +0 -72
- 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;"}
|