/** * Branded type for process IDs to ensure type safety */ export type ProcessId = number & { readonly __brand: 'ProcessId' }; /** * Input type that accepts various ID formats for backward compatibility */ export type ProcessIdInput = ProcessId | number | string; /** * Normalizes various ID input formats to a ProcessId * @param input - The ID in various formats (string, number, or ProcessId) * @returns A normalized ProcessId * @throws Error if the input is not a valid process ID */ export function toProcessId(input: ProcessIdInput): ProcessId { let num: number; if (typeof input === 'string') { const trimmed = input.trim(); if (!/^\d+$/.test(trimmed)) { throw new Error(`Invalid process ID: "${input}" is not a numeric string`); } num = parseInt(trimmed, 10); } else if (typeof input === 'number') { num = input; } else { // Already a ProcessId return input; } if (!Number.isInteger(num) || num < 1) { throw new Error(`Invalid process ID: ${input} must be a positive integer`); } return num as ProcessId; } /** * Type guard to check if a value is a ProcessId */ export function isProcessId(value: unknown): value is ProcessId { return typeof value === 'number' && Number.isInteger(value) && value >= 1; } /** * Gets the next sequential ID given existing IDs */ export function getNextProcessId(existingIds: Iterable): ProcessId { let maxId = 0; for (const id of existingIds) { maxId = Math.max(maxId, id); } return (maxId + 1) as ProcessId; }