40 lines
1.6 KiB
TypeScript
40 lines
1.6 KiB
TypeScript
export const STORAGE_BUDGET_SCHEMA_VERSION = 1 as const;
|
|
|
|
export interface StorageBudgetBreakdown {
|
|
schemaVersion: typeof STORAGE_BUDGET_SCHEMA_VERSION;
|
|
projectId: string;
|
|
projectBytes: number;
|
|
snapshotBytes: number;
|
|
lodBytes: number;
|
|
mediaBytes: number;
|
|
vdbBytes: number;
|
|
totalBytes: number;
|
|
}
|
|
|
|
export function createStorageBudget(projectId: string, values: Partial<Omit<StorageBudgetBreakdown, "schemaVersion" | "projectId" | "totalBytes">> = {}): StorageBudgetBreakdown {
|
|
const fields = ["projectBytes", "snapshotBytes", "lodBytes", "mediaBytes", "vdbBytes"] as const;
|
|
const normalized = Object.fromEntries(fields.map((field) => {
|
|
const value = values[field] ?? 0;
|
|
if (!Number.isSafeInteger(value) || value < 0) throw new Error(`STORAGE_BUDGET_INVALID: ${field}`);
|
|
return [field, value];
|
|
})) as Pick<StorageBudgetBreakdown, typeof fields[number]>;
|
|
const totalBytes = fields.reduce((total, field) => {
|
|
const next = total + normalized[field];
|
|
if (!Number.isSafeInteger(next)) throw new Error("STORAGE_BUDGET_INVALID: totalBytes");
|
|
return next;
|
|
}, 0);
|
|
return { schemaVersion: STORAGE_BUDGET_SCHEMA_VERSION, projectId, ...normalized, totalBytes };
|
|
}
|
|
|
|
export function formatStorageBytes(bytes: number): string {
|
|
if (!Number.isSafeInteger(bytes) || bytes < 0) throw new Error("STORAGE_BUDGET_INVALID: bytes");
|
|
if (bytes < 1024) return `${bytes} B`;
|
|
const units = ["KiB", "MiB", "GiB", "TiB"];
|
|
let value = bytes;
|
|
for (const unit of units) {
|
|
value /= 1024;
|
|
if (value < 1024 || unit === units[units.length - 1]) return `${value.toFixed(value >= 10 ? 0 : 1)} ${unit}`;
|
|
}
|
|
return `${bytes} B`;
|
|
}
|