export interface DeviceGroup { readonly id: string; readonly name: string; readonly description: string; readonly deviceCount: number; readonly createdAt: string; readonly updatedAt: string; } export interface DeviceGroupInput { readonly name: string; readonly description?: string; } export interface DeviceGroupPatch { readonly name?: string; readonly description?: string; } export interface DeviceTag { readonly tag: string; readonly color: string; readonly deviceCount: number; readonly createdAt: string; readonly updatedAt: string; } export interface DeviceTagInput { readonly tag: string; readonly color?: string; } export interface DeviceTagPatch { readonly color?: string; } export const TAG_COLORS = [ '', 'coral', 'turquoise', 'lime', 'yellow', 'pink', 'purple', 'blue', ] as const; export type TagColor = (typeof TAG_COLORS)[number]; function text(value: unknown, field: string, maximum: number): string { if (typeof value !== 'string') throw new TypeError(`${field} must be a string`); const result = value.trim(); if (result.length > maximum) throw new TypeError(`${field} must be at most ${maximum} characters`); return result; } export function parseDeviceGroupInput(value: unknown): DeviceGroupInput { const record = value as Record; const name = text(record?.name, 'name', 100); if (!name) throw new TypeError('name must not be empty'); const description = record?.description === undefined ? '' : text(record.description, 'description', 500); return { name, description }; } export function parseDeviceGroupPatch(value: unknown): DeviceGroupPatch { const record = value as Record; const patch: { name?: string; description?: string } = {}; if (record?.name !== undefined) { const name = text(record.name, 'name', 100); if (!name) throw new TypeError('name must not be empty'); patch.name = name; } if (record?.description !== undefined) patch.description = text(record.description, 'description', 500); if (Object.keys(patch).length === 0) throw new TypeError('no group fields to update'); return patch; } export function parseDeviceTagInput(value: unknown): DeviceTagInput { const record = value as Record; const tag = text(record?.tag, 'tag', 100); if (!tag) throw new TypeError('tag must not be empty'); const color = record?.color === undefined ? '' : text(record.color, 'color', 32); return { tag, color }; } export function parseDeviceTagPatch(value: unknown): DeviceTagPatch { const record = value as Record; if (record?.color === undefined) throw new TypeError('no tag fields to update'); return { color: text(record.color, 'color', 32) }; }