@ubercode/dcmtk 0.2.0 → 0.4.0
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/README.md +17 -12
- package/dist/{DicomInstance-CQEIuF_x.d.ts → DicomInstance-CGBr3a-C.d.ts} +2 -2
- package/dist/{DicomInstance-By9zd7GM.d.cts → DicomInstance-DWOjhccQ.d.cts} +2 -2
- package/dist/{dcmodify-Gds9u5Vj.d.cts → dcmodify-B9js5K1f.d.cts} +2 -0
- package/dist/{dcmodify-B-_uUIKB.d.ts → dcmodify-BvaIeyJg.d.ts} +2 -0
- package/dist/dicom.cjs +27 -11
- package/dist/dicom.cjs.map +1 -1
- package/dist/dicom.d.cts +3 -3
- package/dist/dicom.d.ts +3 -3
- package/dist/dicom.js +27 -11
- package/dist/dicom.js.map +1 -1
- package/dist/index.cjs +1299 -172
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +320 -7
- package/dist/index.d.ts +320 -7
- package/dist/index.js +1297 -173
- package/dist/index.js.map +1 -1
- package/dist/servers.cjs +28 -12
- package/dist/servers.cjs.map +1 -1
- package/dist/servers.d.cts +2 -2
- package/dist/servers.d.ts +2 -2
- package/dist/servers.js +28 -12
- package/dist/servers.js.map +1 -1
- package/dist/tools.cjs +755 -157
- package/dist/tools.cjs.map +1 -1
- package/dist/tools.d.cts +226 -10
- package/dist/tools.d.ts +226 -10
- package/dist/tools.js +755 -157
- package/dist/tools.js.map +1 -1
- package/package.json +17 -1
package/dist/servers.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts","../src/constants.ts","../src/DcmtkProcess.ts","../src/parsers/LineParser.ts","../src/patterns.ts","../src/findDcmtkPath.ts","../src/tools/_resolveBinary.ts","../src/tools/_toolError.ts","../src/events/dcmrecv.ts","../src/servers/AssociationTracker.ts","../src/servers/Dcmrecv.ts","../src/events/storescp.ts","../src/servers/StoreSCP.ts","../src/brands.ts","../src/dicom/tagPath.ts","../src/dicom/ChangeSet.ts","../src/dicom/DicomDataset.ts","../src/exec.ts","../src/tools/_xmlToJson.ts","../src/tools/_repairJson.ts","../src/tools/dcm2json.ts","../src/tools/dcmodify.ts","../src/dicom/_fileHelpers.ts","../src/dicom/DicomInstance.ts","../src/servers/DicomReceiver.ts","../src/events/dcmprscp.ts","../src/servers/DcmprsCP.ts","../src/events/dcmpsrcv.ts","../src/servers/Dcmpsrcv.ts","../src/events/dcmqrscp.ts","../src/servers/DcmQRSCP.ts","../src/events/wlmscpfs.ts","../src/servers/Wlmscpfs.ts"],"names":["EventEmitter","stderr","isWindows","binaryName","join","path","parser","z","buildArgs","kill","spawn","stat","buildNetworkArgs"],"mappings":"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","file":"servers.js","sourcesContent":["/**\n * Represents the outcome of an operation that can succeed or fail.\n *\n * @typeParam T - The type of the success value\n * @typeParam E - The type of the error (defaults to Error)\n *\n * @example\n * ```ts\n * function divide(a: number, b: number): Result<number> {\n * if (b === 0) {\n * return err(new Error('Division by zero'));\n * }\n * return ok(a / b);\n * }\n *\n * const result = divide(10, 2);\n * if (result.ok) {\n * console.log(result.value); // 5\n * } else {\n * console.error(result.error.message);\n * }\n * ```\n */\ntype Result<T, E = Error> = { readonly ok: true; readonly value: T } | { readonly ok: false; readonly error: E };\n\n/**\n * Creates a successful Result containing the given value.\n *\n * @param value - The success value to wrap\n * @returns A Result representing success\n *\n * @example\n * ```ts\n * const result = ok(42);\n * // result.ok === true, result.value === 42\n * ```\n */\nfunction ok<T>(value: T): Result<T, never> {\n return { ok: true, value };\n}\n\n/**\n * Creates a failed Result containing the given error.\n *\n * @param error - The error to wrap\n * @returns A Result representing failure\n *\n * @example\n * ```ts\n * const result = err(new Error('not found'));\n * // result.ok === false, result.error.message === 'not found'\n * ```\n */\nfunction err<E>(error: E): Result<never, E> {\n return { ok: false, error };\n}\n\n/**\n * Exhaustive check helper for discriminated unions and switch statements.\n * Calling this in a default case ensures all variants are handled at compile time.\n *\n * @param x - A value that should be of type `never` if all cases are handled\n * @returns Never returns; always throws\n * @throws Always throws an Error indicating an unhandled case\n *\n * @example\n * ```ts\n * type Shape = { kind: 'circle' } | { kind: 'square' };\n *\n * function area(shape: Shape): number {\n * switch (shape.kind) {\n * case 'circle': return Math.PI;\n * case 'square': return 1;\n * default: assertUnreachable(shape);\n * }\n * }\n * ```\n */\nfunction assertUnreachable(x: never): never {\n throw new Error(`Exhaustive check failed: ${JSON.stringify(x)}`);\n}\n\n// ---------------------------------------------------------------------------\n// Process result types (Rule 7.1: immutable)\n// ---------------------------------------------------------------------------\n\n/**\n * The result of executing a short-lived DCMTK binary.\n * All properties are readonly to enforce immutability.\n */\ninterface DcmtkProcessResult {\n /** The captured stdout output from the process. */\n readonly stdout: string;\n /** The captured stderr output from the process. */\n readonly stderr: string;\n /** The exit code of the process (0 typically means success). */\n readonly exitCode: number;\n}\n\n// ---------------------------------------------------------------------------\n// Common option types (Rule 8.4: options objects for > 4 params)\n// ---------------------------------------------------------------------------\n\n/**\n * Options for short-lived DCMTK process execution.\n * Provides configurable timeout and abort support per Rule 4.2.\n */\ninterface ExecOptions {\n /** Working directory for the child process. */\n readonly cwd?: string | undefined;\n /** Timeout in milliseconds. Defaults to DEFAULT_TIMEOUT_MS. */\n readonly timeoutMs?: number | undefined;\n /** AbortSignal for external cancellation. */\n readonly signal?: AbortSignal | undefined;\n}\n\n/**\n * Options for spawning a DCMTK process with user-supplied arguments.\n * Uses spawn() instead of exec() to avoid shell injection (Rule 7.4).\n */\ninterface SpawnOptions extends ExecOptions {\n /** Additional environment variables merged with process.env. */\n readonly env?: Readonly<Record<string, string>> | undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Event types (Rule 8.3: discriminated unions)\n// ---------------------------------------------------------------------------\n\n/**\n * Line source discriminant for output parsing.\n */\ntype LineSource = 'stdout' | 'stderr';\n\n/**\n * A single line of output from a DCMTK process.\n */\ninterface ProcessLine {\n readonly source: LineSource;\n readonly text: string;\n}\n\n// ---------------------------------------------------------------------------\n// Result utility functions\n// ---------------------------------------------------------------------------\n\n/**\n * Transforms the success value of a Result, passing through errors unchanged.\n *\n * @param result - The Result to transform\n * @param fn - The transformation function\n * @returns A new Result with the transformed value, or the original error\n *\n * @example\n * ```ts\n * const result = ok(42);\n * const doubled = mapResult(result, x => x * 2);\n * // doubled.ok === true, doubled.value === 84\n * ```\n */\nfunction mapResult<T, U>(result: Result<T>, fn: (value: T) => U): Result<U> {\n if (result.ok) {\n return ok(fn(result.value));\n }\n return result;\n}\n\n/**\n * Extracts the success type from a Result.\n * Useful for extracting branded types from factory function returns.\n *\n * @example\n * ```ts\n * type Tag = ResultValue<ReturnType<typeof createDicomTag>>; // DicomTag\n * ```\n */\ntype ResultValue<R> = R extends Result<infer T> ? T : never;\n\nexport { ok, err, assertUnreachable, mapResult };\nexport type { Result, ResultValue, DcmtkProcessResult, ExecOptions, SpawnOptions, LineSource, ProcessLine };\n","/**\n * Application-wide constants.\n *\n * All values use `as const` assertions per Rule 3.5 (no traditional enums).\n * All bounds are documented per Rule 8.1 (bounded loops/buffers).\n *\n * @module constants\n */\n\n// ---------------------------------------------------------------------------\n// Timeouts (Rule 4.2: mandatory timeouts on all async operations)\n// ---------------------------------------------------------------------------\n\n/** Default timeout for short-lived process execution (30 seconds). */\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\n/** Default timeout for long-lived process startup (10 seconds). */\nconst DEFAULT_START_TIMEOUT_MS = 10_000;\n\n/** Default timeout for graceful shutdown drain (5 seconds). */\nconst DEFAULT_DRAIN_TIMEOUT_MS = 5_000;\n\n/** Default timeout for multi-line block accumulation in line parser (1 second). */\nconst DEFAULT_BLOCK_TIMEOUT_MS = 1_000;\n\n// ---------------------------------------------------------------------------\n// DICOM network constants\n// ---------------------------------------------------------------------------\n\n/** DICOM protocol default PDU sizes. */\nconst PDU_SIZE = {\n /** Default maximum PDU receive size (16 KB). */\n DEFAULT: 16_384,\n /** Minimum allowed PDU size (4 KB). */\n MIN: 4_096,\n /** Maximum allowed PDU size (128 KB). */\n MAX: 131_072,\n} as const;\n\n/** Default DICOM port used by DCMTK tools. */\nconst DEFAULT_DICOM_PORT = 104;\n\n// ---------------------------------------------------------------------------\n// Platform-specific known DCMTK install paths\n// ---------------------------------------------------------------------------\n\n/** Known DCMTK binary locations on Windows. */\nconst WINDOWS_SEARCH_PATHS = ['C:\\\\Program Files\\\\DCMTK\\\\bin', 'C:\\\\Program Files (x86)\\\\DCMTK\\\\bin', 'C:\\\\ProgramData\\\\chocolatey\\\\bin'] as const;\n\n/** Known DCMTK binary locations on Unix/macOS. */\nconst UNIX_SEARCH_PATHS = ['/usr/local/bin', '/usr/bin', '/opt/local/bin', '/opt/homebrew/bin'] as const;\n\n// ---------------------------------------------------------------------------\n// Required DCMTK binaries (minimum set for core functionality)\n// ---------------------------------------------------------------------------\n\n/** Binaries that must be present for the library to function. */\nconst REQUIRED_BINARIES = ['dcm2json', 'dcm2xml', 'dcmodify', 'dcmdump', 'dcmrecv', 'dcmsend', 'echoscu'] as const;\n\n// ---------------------------------------------------------------------------\n// Bounded limits (Rule 8.1: all loops and buffers must have upper bounds)\n// ---------------------------------------------------------------------------\n\n/** Maximum lines accumulated in multi-line block parser. */\nconst MAX_BLOCK_LINES = 1_000;\n\n/** Maximum number of event patterns a line parser can hold. */\nconst MAX_EVENT_PATTERNS = 200;\n\n/** Maximum loop iterations for iterative traversal (e.g., nested sequences). */\nconst MAX_TRAVERSAL_DEPTH = 50;\n\n/** Maximum number of operations (modifications + erasures) in a single ChangeSet. */\nconst MAX_CHANGESET_OPERATIONS = 10_000;\n\n/** Maximum bytes allowed for stdout + stderr buffering (100 MB). */\nconst MAX_OUTPUT_BYTES = 100 * 1024 * 1024;\n\nexport {\n DEFAULT_TIMEOUT_MS,\n DEFAULT_START_TIMEOUT_MS,\n DEFAULT_DRAIN_TIMEOUT_MS,\n DEFAULT_BLOCK_TIMEOUT_MS,\n PDU_SIZE,\n DEFAULT_DICOM_PORT,\n WINDOWS_SEARCH_PATHS,\n UNIX_SEARCH_PATHS,\n REQUIRED_BINARIES,\n MAX_BLOCK_LINES,\n MAX_EVENT_PATTERNS,\n MAX_TRAVERSAL_DEPTH,\n MAX_CHANGESET_OPERATIONS,\n MAX_OUTPUT_BYTES,\n};\n","/**\n * Base class for long-lived DCMTK processes (servers).\n *\n * Manages spawning, line-by-line output buffering, typed event emission,\n * lifecycle (start/stop), mandatory timeouts, and graceful shutdown.\n *\n * Implements `Disposable` for deterministic cleanup (Rule 5.1).\n *\n * @module DcmtkProcess\n */\n\nimport { EventEmitter } from 'node:events';\nimport { spawn } from 'node:child_process';\nimport type { ChildProcess } from 'node:child_process';\nimport { stderr } from 'stderr-lib';\nimport kill from 'tree-kill';\nimport type { Result, LineSource } from './types';\nimport { ok, err } from './types';\nimport { DEFAULT_START_TIMEOUT_MS, DEFAULT_DRAIN_TIMEOUT_MS, MAX_OUTPUT_BYTES } from './constants';\n\n// ---------------------------------------------------------------------------\n// Event types\n// ---------------------------------------------------------------------------\n\n/** Events emitted by a DcmtkProcess. */\ninterface DcmtkProcessEventMap {\n started: [];\n stopped: [{ readonly reason: string }];\n error: [{ readonly error: Error; readonly fatal: boolean }];\n line: [{ readonly source: LineSource; readonly text: string }];\n}\n\n/** Configuration for a DcmtkProcess instance. */\ninterface DcmtkProcessConfig {\n /** Full path to the DCMTK binary. */\n readonly binary: string;\n /** Command-line arguments. */\n readonly args: readonly string[];\n /** Working directory. */\n readonly cwd?: string | undefined;\n /** Timeout for start() to resolve, in milliseconds. */\n readonly startTimeoutMs?: number | undefined;\n /** Timeout for graceful drain during stop(), in milliseconds. */\n readonly drainTimeoutMs?: number | undefined;\n /**\n * A function that inspects each output line and returns `true` when\n * the process is considered \"started\" (e.g., \"listening on port X\").\n * If not provided, start() resolves immediately after spawn.\n */\n readonly isStartedPredicate?: ((line: string) => boolean) | undefined;\n}\n\n// ---------------------------------------------------------------------------\n// State enum (as const, not traditional enum — Rule 3.5)\n// ---------------------------------------------------------------------------\n\nconst ProcessState = {\n IDLE: 'IDLE',\n STARTING: 'STARTING',\n RUNNING: 'RUNNING',\n STOPPING: 'STOPPING',\n STOPPED: 'STOPPED',\n} as const;\n\ntype ProcessStateValue = (typeof ProcessState)[keyof typeof ProcessState];\n\n// ---------------------------------------------------------------------------\n// DcmtkProcess class\n// ---------------------------------------------------------------------------\n\n/**\n * Base class for persistent DCMTK processes (e.g., dcmrecv, storescp).\n *\n * @example\n * ```ts\n * const proc = new DcmtkProcess({\n * binary: '/usr/local/bin/dcmrecv',\n * args: ['--config', 'storescp.cfg', '11112'],\n * isStartedPredicate: line => line.includes('listening'),\n * });\n *\n * const result = await proc.start();\n * if (result.ok) {\n * // Process is running\n * proc.on('line', ({ source, text }) => console.log(`[${source}] ${text}`));\n * }\n *\n * await proc.stop();\n * ```\n */\nclass DcmtkProcess extends EventEmitter<DcmtkProcessEventMap> {\n private state: ProcessStateValue = ProcessState.IDLE;\n private child: ChildProcess | null = null;\n private stdoutBuffer = '';\n private stderrBuffer = '';\n private readonly config: DcmtkProcessConfig;\n\n constructor(config: DcmtkProcessConfig) {\n super();\n // Servers can have up to ~15 event types plus internal listeners;\n // raise above the default 10 to avoid MaxListenersExceeded warnings.\n this.setMaxListeners(20);\n this.config = config;\n // Prevent unhandled 'error' events from crashing the process (Node.js\n // throws if 'error' is emitted with no listener). Consumers should\n // register their own 'error' listener before calling start() to receive\n // errors. Startup errors are also returned via Result from start().\n this.on('error', () => {});\n }\n\n /** Whether the process is currently running. */\n get isRunning(): boolean {\n return this.state === ProcessState.RUNNING;\n }\n\n /** Current process state. */\n get currentState(): ProcessStateValue {\n return this.state;\n }\n\n /**\n * Starts the DCMTK process.\n *\n * Single-use enforcement: returns an error if called more than once.\n * Waits for the `isStartedPredicate` to match an output line, or resolves\n * immediately after spawn if no predicate is configured.\n *\n * @returns A Result indicating success or failure\n */\n async start(): Promise<Result<void>> {\n if (this.state !== ProcessState.IDLE) {\n return err(new Error(`Cannot start: process is in state \"${this.state}\"`));\n }\n this.state = ProcessState.STARTING;\n const timeoutMs = this.config.startTimeoutMs ?? DEFAULT_START_TIMEOUT_MS;\n\n return new Promise<Result<void>>(resolve => {\n let settled = false;\n const timer = setTimeout(() => {\n if (settled) return;\n settled = true;\n this.state = ProcessState.STOPPED;\n this.killChild();\n resolve(err(new Error(`Process failed to start within ${timeoutMs}ms`)));\n }, timeoutMs);\n\n // Safe from races: Node.js is single-threaded, so the `settled`\n // flag check + set is atomic within each event handler invocation.\n const settle = (result: Result<void>): void => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n resolve(result);\n };\n\n try {\n this.child = spawn(this.config.binary, [...this.config.args], {\n cwd: this.config.cwd,\n windowsHide: true,\n });\n /* v8 ignore start -- spawn() rarely throws synchronously */\n } catch (e: unknown) {\n settle(err(new Error(`Failed to spawn process: ${stderr(e).message}`)));\n return;\n }\n /* v8 ignore stop */\n this.wireChildEvents(settle);\n });\n }\n\n /**\n * Stops the process gracefully.\n *\n * Waits up to `drainTimeoutMs` for the process to exit, then force-kills.\n */\n async stop(): Promise<void> {\n if (this.state === ProcessState.STOPPED || this.state === ProcessState.IDLE) {\n return;\n }\n\n this.state = ProcessState.STOPPING;\n const drainMs = this.config.drainTimeoutMs ?? DEFAULT_DRAIN_TIMEOUT_MS;\n\n return new Promise<void>(resolve => {\n /* v8 ignore next 4 -- drain timeout is a safety net for unresponsive processes */\n const timer = setTimeout(() => {\n this.killChild();\n this.state = ProcessState.STOPPED;\n resolve();\n }, drainMs);\n\n // Safe: Node.js is single-threaded, so `this.child` cannot become null\n // between the check and the `.once('close', ...)` registration. The\n // drain timeout handles the edge case where the child exits before\n // the close listener is registered.\n if (this.child) {\n this.child.once('close', () => {\n clearTimeout(timer);\n this.state = ProcessState.STOPPED;\n resolve();\n });\n this.killChild();\n /* v8 ignore start -- edge case: state is RUNNING but child is already null */\n } else {\n clearTimeout(timer);\n this.state = ProcessState.STOPPED;\n resolve();\n }\n /* v8 ignore stop */\n });\n }\n\n /**\n * Implements Disposable for deterministic cleanup (Rule 5.1).\n */\n [Symbol.dispose](): void {\n if (this.child) {\n this.killChild();\n this.child = null;\n }\n this.state = ProcessState.STOPPED;\n this.removeAllListeners();\n }\n\n // -----------------------------------------------------------------------\n // Private helpers\n // -----------------------------------------------------------------------\n\n private killChild(): void {\n if (this.child?.pid !== undefined && this.child.pid !== null) {\n try {\n kill(this.child.pid);\n /* v8 ignore next */\n } catch {\n // Process may already be dead\n }\n }\n }\n\n /**\n * Wires all child process event handlers for startup.\n */\n private wireChildEvents(settle: (result: Result<void>) => void): void {\n const child = this.child;\n if (!child) return;\n\n child.on('error', (error: Error) => {\n this.emit('error', { error, fatal: true });\n if (this.state === ProcessState.STARTING) {\n this.state = ProcessState.STOPPED;\n settle(err(new Error(`Process error during start: ${error.message}`)));\n }\n });\n\n child.on('close', (code: number | null) => {\n const prevState = this.state;\n this.state = ProcessState.STOPPED;\n this.child = null;\n const reason = `Process exited with code ${String(code ?? 'null')}`;\n this.emit('stopped', { reason });\n if (prevState === ProcessState.STARTING) settle(err(new Error(reason)));\n });\n\n child.stdout?.on('data', (chunk: Buffer | string) => {\n this.handleData('stdout', chunk);\n });\n child.stderr?.on('data', (chunk: Buffer | string) => {\n this.handleData('stderr', chunk);\n });\n\n child.on('spawn', () => {\n if (!this.config.isStartedPredicate) {\n this.state = ProcessState.RUNNING;\n this.emit('started');\n settle(ok(undefined));\n }\n });\n\n if (this.config.isStartedPredicate) {\n this.wireStartedPredicate(settle);\n }\n }\n\n /**\n * Wires a line listener that resolves start() when the predicate matches.\n */\n private wireStartedPredicate(settle: (result: Result<void>) => void): void {\n const onLine = ({ text }: { readonly source: LineSource; readonly text: string }): void => {\n if (this.config.isStartedPredicate?.(text)) {\n this.removeListener('line', onLine);\n this.state = ProcessState.RUNNING;\n this.emit('started');\n settle(ok(undefined));\n }\n };\n this.on('line', onLine);\n }\n\n private handleData(source: LineSource, chunk: Buffer | string): void {\n if (source === 'stdout') {\n this.stdoutBuffer += String(chunk);\n } else {\n this.stderrBuffer += String(chunk);\n }\n\n if (this.stdoutBuffer.length + this.stderrBuffer.length > MAX_OUTPUT_BYTES) {\n this.emit('error', { error: new Error(`Process output exceeded ${MAX_OUTPUT_BYTES} bytes`), fatal: true });\n this.killChild();\n return;\n }\n\n this.processLines(source, source === 'stdout' ? 'stdoutBuffer' : 'stderrBuffer');\n }\n\n private processLines(source: LineSource, bufferKey: 'stdoutBuffer' | 'stderrBuffer'): void {\n // Handle bare \\r (CR-only) line endings by converting to \\n\n this[bufferKey] = this[bufferKey].replace(/\\r(?!\\n)/g, '\\n');\n\n let newlineIdx = this[bufferKey].indexOf('\\n');\n\n // Iterative line extraction — no recursion (Rule 8.2)\n while (newlineIdx !== -1) {\n const current = this[bufferKey];\n const line = current.substring(0, newlineIdx).replace(/\\r$/, '');\n this[bufferKey] = current.substring(newlineIdx + 1);\n this.emit('line', { source, text: line });\n newlineIdx = this[bufferKey].indexOf('\\n');\n }\n }\n}\n\nexport { DcmtkProcess, ProcessState };\nexport type { DcmtkProcessEventMap, DcmtkProcessConfig, ProcessStateValue };\n","/**\n * Line-by-line parser for DCMTK process output.\n *\n * Matches output lines against registered EventPattern objects and emits\n * structured events. Supports both single-line and multi-line block matching.\n *\n * All algorithms are iterative (Rule 8.2: no recursion).\n * All buffers are bounded (Rule 8.1).\n *\n * @module parsers/LineParser\n */\n\nimport { EventEmitter } from 'node:events';\nimport { stderr } from 'stderr-lib';\nimport type { EventPattern } from './EventPattern';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { MAX_BLOCK_LINES, MAX_EVENT_PATTERNS, DEFAULT_BLOCK_TIMEOUT_MS } from '../constants';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Events emitted by the LineParser. */\ninterface LineParserEventMap {\n /** Emitted when a pattern matches. Carries the event name and extracted data. */\n match: [{ readonly event: string; readonly data: unknown }];\n /** Emitted when a multi-line block times out before the footer is matched. Consumers should listen for this event to detect and handle incomplete blocks. */\n blockTimeout: [{ readonly event: string; readonly lines: readonly string[] }];\n /** Emitted when a pattern processor throws. */\n error: [Error];\n}\n\n/** Tracks the state of an in-progress multi-line block. */\ninterface BlockState {\n readonly pattern: EventPattern;\n readonly lines: string[];\n readonly timer: ReturnType<typeof setTimeout>;\n}\n\n// ---------------------------------------------------------------------------\n// LineParser class\n// ---------------------------------------------------------------------------\n\n/**\n * Parses DCMTK output lines against registered event patterns.\n *\n * @example\n * ```ts\n * const parser = new LineParser();\n * parser.addPattern({\n * event: 'LISTENING',\n * pattern: /listening on port (\\d+)/i,\n * processor: match => ({ port: Number(match[1]) }),\n * });\n *\n * parser.on('match', ({ event, data }) => {\n * console.log(`${event}:`, data);\n * });\n *\n * parser.feed('I: listening on port 11112');\n * // Emits: match { event: 'LISTENING', data: { port: 11112 } }\n * ```\n */\nclass LineParser extends EventEmitter<LineParserEventMap> {\n private readonly patterns: EventPattern[] = [];\n private activeBlock: BlockState | null = null;\n\n constructor() {\n super();\n // LineParser is used internally and the number of patterns can be\n // large — disable the listener limit (0 = unlimited) to avoid\n // MaxListenersExceeded warnings.\n this.setMaxListeners(0);\n // Prevent unhandled 'error' events from crashing the process.\n // Consumers should register their own 'error' listener.\n this.on('error', () => {});\n }\n\n /**\n * Registers an event pattern.\n *\n * @param pattern - The pattern to register\n * @returns Result indicating success or failure if pattern limit exceeded\n */\n addPattern(pattern: EventPattern): Result<void> {\n if (this.patterns.length >= MAX_EVENT_PATTERNS) {\n return err(new Error(`Maximum event patterns (${MAX_EVENT_PATTERNS}) exceeded`));\n }\n this.patterns.push(pattern);\n return ok(undefined);\n }\n\n /**\n * Feeds a single line of output to the parser.\n *\n * The line is matched against all registered patterns (iteratively, Rule 8.2).\n * If a multi-line block is active, the line is accumulated until the footer matches.\n *\n * @param line - A single line of DCMTK output (without trailing newline)\n */\n feed(line: string): void {\n // If a multi-line block is active, accumulate lines\n if (this.activeBlock !== null) {\n this.feedToBlock(line);\n return;\n }\n\n // Check for multi-line block headers first\n for (let i = 0; i < this.patterns.length; i++) {\n const pattern = this.patterns[i];\n /* v8 ignore next -- safety guard for noUncheckedIndexedAccess */\n if (pattern === undefined) continue;\n\n if (pattern.multiLine) {\n const headerMatch = pattern.multiLine.header.exec(line);\n if (headerMatch) {\n this.startBlock(pattern, line);\n return;\n }\n }\n }\n\n // Check single-line patterns\n this.matchSingleLine(line);\n }\n\n /**\n * Feeds multiple lines of output (e.g., from a chunk split by newlines).\n *\n * @param lines - Array of lines to process\n */\n feedLines(lines: readonly string[]): void {\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n if (line !== undefined) {\n this.feed(line);\n }\n }\n }\n\n /**\n * Resets the parser state, clearing any active multi-line block.\n */\n reset(): void {\n if (this.activeBlock !== null) {\n clearTimeout(this.activeBlock.timer);\n this.activeBlock = null;\n }\n }\n\n /**\n * Implements Disposable for cleanup (Rule 5.1).\n */\n [Symbol.dispose](): void {\n this.reset();\n this.removeAllListeners();\n }\n\n // -----------------------------------------------------------------------\n // Private helpers\n // -----------------------------------------------------------------------\n\n private matchSingleLine(line: string): void {\n for (let i = 0; i < this.patterns.length; i++) {\n const pattern = this.patterns[i];\n /* v8 ignore next -- safety guard for noUncheckedIndexedAccess */\n if (pattern === undefined) continue;\n\n // Skip multi-line-only patterns for single-line matching\n if (pattern.multiLine) continue;\n\n const match = pattern.pattern.exec(line);\n if (match) {\n try {\n const data = pattern.processor(match);\n this.emit('match', { event: pattern.event, data });\n } catch (thrown: unknown) {\n this.emit('error', stderr(thrown));\n }\n return; // First match wins\n }\n }\n }\n\n private startBlock(pattern: EventPattern, headerLine: string): void {\n /* v8 ignore next -- multiLine is always defined when startBlock is called */\n const timeoutMs = pattern.multiLine?.timeoutMs ?? DEFAULT_BLOCK_TIMEOUT_MS;\n\n const timer = setTimeout(() => {\n if (this.activeBlock !== null) {\n const lines = [...this.activeBlock.lines];\n const evt = this.activeBlock.pattern.event;\n this.activeBlock = null;\n this.emit('blockTimeout', { event: evt, lines });\n }\n }, timeoutMs);\n\n this.activeBlock = {\n pattern,\n lines: [headerLine],\n timer,\n };\n }\n\n private feedToBlock(line: string): void {\n /* v8 ignore next -- safety guard: activeBlock is always set when feedToBlock is called */\n if (this.activeBlock === null) return;\n\n const { pattern, lines, timer } = this.activeBlock;\n /* v8 ignore next -- multiLine is always defined for block patterns */\n const maxLines = pattern.multiLine?.maxLines ?? MAX_BLOCK_LINES;\n\n lines.push(line);\n\n // Check footer\n if (pattern.multiLine?.footer.test(line)) {\n clearTimeout(timer);\n const blockText = lines.join('\\n');\n const match = pattern.pattern.exec(blockText);\n this.activeBlock = null;\n\n if (match) {\n try {\n const data = pattern.processor(match);\n this.emit('match', { event: pattern.event, data });\n } catch (thrown: unknown) {\n this.emit('error', stderr(thrown));\n }\n }\n return;\n }\n\n // Enforce bounded accumulation (Rule 8.1)\n if (lines.length >= maxLines) {\n clearTimeout(timer);\n const evt = pattern.event;\n const accumulated = [...lines];\n this.activeBlock = null;\n this.emit('blockTimeout', { event: evt, lines: accumulated });\n }\n }\n}\n\nexport { LineParser };\nexport type { LineParserEventMap };\n","/**\n * Shared validation regex patterns and constants.\n *\n * Centralises all DICOM-related validation patterns so that brands,\n * validation schemas, and server modules reference a single source\n * of truth rather than maintaining duplicated copies.\n *\n * @module patterns\n */\n\n// ---------------------------------------------------------------------------\n// DICOM tag and UID patterns\n// ---------------------------------------------------------------------------\n\n/** Matches a DICOM tag in `(XXXX,XXXX)` format where X is a hex digit. */\nconst DICOM_TAG_PATTERN = /^\\([0-9A-Fa-f]{4},[0-9A-Fa-f]{4}\\)$/;\n\n/** Matches a DICOM AE Title: letters, digits, spaces, and hyphens. */\nconst AE_TITLE_PATTERN = /^[A-Za-z0-9 -]+$/;\n\n/**\n * Matches a dotted numeric OID (e.g. `1.2.840.10008`).\n *\n * Note: This intentionally accepts any syntactically valid dotted-numeric form.\n * DICOM PS3.5 §9.1 requires UIDs start with a non-zero root (e.g., `0.0.0` is\n * technically invalid), but real-world DICOM datasets contain such UIDs, so we\n * validate syntax only and leave semantic UID validation to the application layer.\n */\nconst UID_PATTERN = /^[0-9]+(\\.[0-9]+)*$/;\n\n/** Matches a single DICOM tag path segment with optional array index. */\nconst TAG_PATH_SEGMENT = /\\([0-9A-Fa-f]{4},[0-9A-Fa-f]{4}\\)(\\[\\d+\\])?/;\n\n/** Matches a full dot-separated DICOM tag path (e.g. `(0040,A730)[0].(0010,0010)`). */\nconst DICOM_TAG_PATH_PATTERN = new RegExp(`^${TAG_PATH_SEGMENT.source}(\\\\.${TAG_PATH_SEGMENT.source})*$`);\n\n// ---------------------------------------------------------------------------\n// Validation constants\n// ---------------------------------------------------------------------------\n\n/** Minimum length for an AE Title. */\nconst AE_TITLE_MIN_LENGTH = 1;\n\n/** Maximum length for an AE Title. */\nconst AE_TITLE_MAX_LENGTH = 16;\n\n/** Maximum length for a DICOM UID. */\nconst UID_MAX_LENGTH = 64;\n\n/** Minimum valid network port number. */\nconst PORT_MIN = 1;\n\n/** Maximum valid network port number. */\nconst PORT_MAX = 65535;\n\n// ---------------------------------------------------------------------------\n// DICOM query key patterns\n// ---------------------------------------------------------------------------\n\n/**\n * Matches a valid DICOM query key for `-k` arguments.\n *\n * Accepted formats:\n * - `XXXX,XXXX` — bare tag\n * - `XXXX,XXXX=value` — tag with value\n * - `XXXX,XXXX[0].XXXX,XXXX=value` — nested path with value\n * - `XXXX,XXXX.XXXX,XXXX=value` — dotted path with value\n *\n * The tag portion must start with a valid hex tag pair. Value after `=` is unconstrained.\n */\n// eslint-disable-next-line no-useless-escape\nconst DICOM_QUERY_KEY_PATTERN = /^[0-9A-Fa-f]{4},[0-9A-Fa-f]{4}(?:[\\[.\\]0-9A-Fa-f,]*)?(?:=.*)?$/;\n\n/**\n * Returns true if the string is a valid DICOM query key for `-k` arguments.\n */\nfunction isValidDicomKey(key: string): boolean {\n return DICOM_QUERY_KEY_PATTERN.test(key);\n}\n\n// ---------------------------------------------------------------------------\n// Path safety\n// ---------------------------------------------------------------------------\n\n/** Pattern matching `..` as a path segment (between separators, or at start/end). */\nconst PATH_TRAVERSAL_PATTERN = /(?:^|[\\\\/])\\.\\.(?:[\\\\/]|$)/;\n\n/**\n * Returns true if the string contains only valid DICOM AE Title characters.\n */\nfunction isValidAETitle(value: string): boolean {\n return AE_TITLE_PATTERN.test(value);\n}\n\n/**\n * Returns true if the path does not contain traversal sequences.\n *\n * @param p - The filesystem path to check\n * @returns `true` when the path is safe (no `..` segments)\n */\nfunction isSafePath(p: string): boolean {\n return !PATH_TRAVERSAL_PATTERN.test(p);\n}\n\nexport {\n DICOM_TAG_PATTERN,\n AE_TITLE_PATTERN,\n UID_PATTERN,\n TAG_PATH_SEGMENT,\n DICOM_TAG_PATH_PATTERN,\n AE_TITLE_MIN_LENGTH,\n AE_TITLE_MAX_LENGTH,\n UID_MAX_LENGTH,\n PORT_MIN,\n PORT_MAX,\n DICOM_QUERY_KEY_PATTERN,\n isValidDicomKey,\n isValidAETitle,\n PATH_TRAVERSAL_PATTERN,\n isSafePath,\n};\n","/**\n * Locates DCMTK binaries on the host system.\n *\n * Search order:\n * 1. `DCMTK_PATH` environment variable\n * 2. Platform-specific known install locations\n * 3. System PATH (via `which`/`where` lookup)\n *\n * @module findDcmtkPath\n */\n\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { execSync } from 'node:child_process';\nimport type { Result } from './types';\nimport { ok, err } from './types';\nimport { WINDOWS_SEARCH_PATHS, UNIX_SEARCH_PATHS, REQUIRED_BINARIES } from './constants';\nimport { isSafePath } from './patterns';\n\n/** Cached path result. Cleared only by passing `noCache: true`. */\nlet cachedPath: string | undefined;\n\nconst isWindows = process.platform === 'win32';\n\n/**\n * Returns the binary filename with platform-appropriate extension.\n *\n * @param name - The base binary name (e.g., `\"dcm2json\"`)\n * @returns The binary name with `.exe` appended on Windows\n */\nfunction binaryName(name: string): string {\n /* v8 ignore next -- platform-specific branch */\n return isWindows ? `${name}.exe` : name;\n}\n\n/**\n * Checks whether a directory contains all required DCMTK binaries.\n *\n * @param dir - The directory to check\n * @returns `true` if all required binaries exist in the directory\n */\nfunction hasRequiredBinaries(dir: string): boolean {\n for (const bin of REQUIRED_BINARIES) {\n if (!existsSync(join(dir, binaryName(bin)))) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Attempts to locate a binary via the system PATH using `which` (Unix) or `where` (Windows).\n *\n * @param name - The binary name to search for\n * @returns The directory containing the binary, or `undefined` if not found\n */\nfunction findViaSystemPath(name: string): string | undefined {\n try {\n /* v8 ignore next -- platform-specific branch */\n const cmd = isWindows ? `where ${binaryName(name)}` : `which ${name}`;\n const result = execSync(cmd, { encoding: 'utf-8', timeout: 5_000, windowsHide: true }).trim();\n const firstLine = result.split('\\n')[0]?.trim();\n if (firstLine) {\n /* v8 ignore next -- platform-specific branch */\n const lastSep = firstLine.lastIndexOf(isWindows ? '\\\\' : '/');\n if (lastSep >= 0) {\n return firstLine.substring(0, lastSep);\n }\n }\n } catch {\n // Binary not in PATH — this is expected, not exceptional\n }\n return undefined;\n}\n\n/**\n * Checks the DCMTK_PATH environment variable for a valid DCMTK installation.\n *\n * @returns A Result if the env var is set (success or error), or `undefined` if unset\n */\nfunction searchEnvPath(): Result<string> | undefined {\n const envPath = process.env['DCMTK_PATH'];\n if (envPath === undefined || envPath.length === 0) {\n return undefined;\n }\n if (!isSafePath(envPath)) {\n return err(new Error(`DCMTK_PATH=\"${envPath}\" contains path traversal sequences`));\n }\n if (hasRequiredBinaries(envPath)) {\n return ok(envPath);\n }\n return err(new Error(`DCMTK_PATH=\"${envPath}\" is set but required binaries are missing`));\n}\n\n/**\n * Searches platform-specific known install locations for DCMTK binaries.\n *\n * @returns The directory path if found, or `undefined`\n */\nfunction searchKnownPaths(): string | undefined {\n /* v8 ignore next -- platform-specific branch */\n const searchPaths = isWindows ? WINDOWS_SEARCH_PATHS : UNIX_SEARCH_PATHS;\n for (const candidate of searchPaths) {\n if (hasRequiredBinaries(candidate)) {\n return candidate;\n }\n }\n return undefined;\n}\n\n/**\n * Searches the system PATH for DCMTK binaries.\n *\n * @returns The directory path if found, or `undefined`\n */\nfunction searchSystemPath(): string | undefined {\n /* v8 ignore next -- fallback never used since REQUIRED_BINARIES is non-empty */\n const systemDir = findViaSystemPath(REQUIRED_BINARIES[0] ?? 'dcm2json');\n if (systemDir !== undefined && hasRequiredBinaries(systemDir)) {\n return systemDir;\n }\n return undefined;\n}\n\n/**\n * Options for {@link findDcmtkPath}.\n */\ninterface FindDcmtkPathOptions {\n /** Bypass the cached result and perform a fresh search. */\n readonly noCache?: boolean | undefined;\n}\n\n/**\n * Locates the directory containing DCMTK command-line binaries.\n *\n * Searches in the following order:\n * 1. `DCMTK_PATH` environment variable (if set)\n * 2. Platform-specific known install locations\n * 3. System PATH lookup via `which`/`where`\n *\n * The result is cached after the first successful call. Pass `{ noCache: true }`\n * to force a fresh search.\n *\n * @param options - Optional configuration\n * @returns A Result containing the DCMTK binary directory path, or an error if not found\n * @throws Never throws for expected failures (Rule 6.1)\n *\n * @example\n * ```ts\n * const result = findDcmtkPath();\n * if (result.ok) {\n * console.log(`DCMTK found at: ${result.value}`);\n * } else {\n * console.error(result.error.message);\n * }\n * ```\n */\nfunction findDcmtkPath(options?: FindDcmtkPathOptions): Result<string> {\n if (cachedPath !== undefined && !options?.noCache) {\n return ok(cachedPath);\n }\n\n const envResult = searchEnvPath();\n if (envResult !== undefined) {\n if (envResult.ok) {\n cachedPath = envResult.value;\n }\n return envResult;\n }\n\n const knownPath = searchKnownPaths();\n if (knownPath !== undefined) {\n cachedPath = knownPath;\n return ok(knownPath);\n }\n\n const systemPath = searchSystemPath();\n if (systemPath !== undefined) {\n cachedPath = systemPath;\n return ok(systemPath);\n }\n\n return err(\n new Error(\n 'DCMTK binaries not found. Install DCMTK and either:\\n' +\n ' - Set the DCMTK_PATH environment variable, or\\n' +\n ' - Install DCMTK to a standard location, or\\n' +\n ' - Ensure DCMTK binaries are on the system PATH'\n )\n );\n}\n\n/**\n * Clears the cached DCMTK path. Primarily for testing.\n */\nfunction clearDcmtkPathCache(): void {\n cachedPath = undefined;\n}\n\nexport { findDcmtkPath, clearDcmtkPathCache };\nexport type { FindDcmtkPathOptions };\n","/**\n * Resolves the full path to a DCMTK binary.\n *\n * Wraps {@link findDcmtkPath} + `path.join` and appends `.exe` on Windows.\n *\n * @module _resolveBinary\n * @internal\n */\n\nimport { join } from 'node:path';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { findDcmtkPath } from '../findDcmtkPath';\n\nconst isWindows = process.platform === 'win32';\n\n/**\n * Resolves the full filesystem path to a named DCMTK binary.\n *\n * @param toolName - The DCMTK binary name (e.g., \"dcm2xml\")\n * @returns A Result containing the full binary path or an error if DCMTK is not found\n */\nfunction resolveBinary(toolName: string): Result<string> {\n const pathResult = findDcmtkPath();\n if (!pathResult.ok) {\n return err(pathResult.error);\n }\n /* v8 ignore next -- platform-specific branch */\n const binaryName = isWindows ? `${toolName}.exe` : toolName;\n return ok(join(pathResult.value, binaryName));\n}\n\nexport { resolveBinary };\n","/**\n * Standardized error factory for tool wrappers.\n *\n * Produces consistent error messages that include the tool name, sanitized\n * arguments (truncated), exit code, and a stderr excerpt.\n *\n * @module _toolError\n * @internal\n */\n\n/** Maximum length for the arguments portion of the error message. */\nconst MAX_ARGS_LENGTH = 200;\n\n/** Maximum length for the stderr excerpt in the error message. */\nconst MAX_STDERR_LENGTH = 500;\n\n/**\n * Truncates a string to a maximum length, appending \"...\" if truncated.\n *\n * @param value - The string to truncate\n * @param maxLength - The maximum allowed length\n * @returns The original string or a truncated version\n */\nfunction truncate(value: string, maxLength: number): string {\n if (value.length <= maxLength) {\n return value;\n }\n return `${value.substring(0, maxLength)}...`;\n}\n\n/**\n * Creates a standardized Error for a tool wrapper failure.\n *\n * **Privacy note:** Arguments are included in the error message for debugging.\n * These may contain file paths. Callers exposing errors to end users or external\n * logs should sanitize sensitive paths before display.\n *\n * @param toolName - The DCMTK binary name (e.g., \"dcm2xml\")\n * @param args - The command-line arguments passed to the tool\n * @param exitCode - The process exit code\n * @param stderr - The captured stderr output\n * @returns An Error with a descriptive message\n */\nfunction createToolError(toolName: string, args: readonly string[], exitCode: number, stderr: string): Error {\n const argsStr = truncate(args.join(' '), MAX_ARGS_LENGTH);\n const stderrStr = truncate(stderr.trim(), MAX_STDERR_LENGTH);\n const parts = [`${toolName} failed (exit code ${String(exitCode)})`];\n if (argsStr.length > 0) {\n parts.push(`args: ${argsStr}`);\n }\n if (stderrStr.length > 0) {\n parts.push(`stderr: ${stderrStr}`);\n }\n return new Error(parts.join(' | '));\n}\n\n/**\n * Formats a Zod validation error into a concise, human-readable string.\n *\n * Flattens nested Zod issues into `field: message` pairs, producing\n * cleaner output than the raw Zod `.message` JSON string.\n *\n * @param toolName - The DCMTK tool name for context\n * @param zodError - The Zod error object (must have `.issues` array)\n * @returns A formatted Error\n */\nfunction createValidationError(\n toolName: string,\n zodError: { readonly issues: ReadonlyArray<{ readonly path: ReadonlyArray<PropertyKey>; readonly message: string }> }\n): Error {\n const parts: string[] = [];\n for (let i = 0; i < zodError.issues.length; i++) {\n const issue = zodError.issues[i];\n /* v8 ignore next */\n if (issue === undefined) continue;\n const path = issue.path.length > 0 ? issue.path.map(String).join('.') : '(root)';\n parts.push(`${path}: ${issue.message}`);\n }\n const detail = parts.length > 0 ? parts.join('; ') : 'unknown validation error';\n return new Error(`${toolName}: invalid options — ${detail}`);\n}\n\nexport { createToolError, createValidationError, truncate, MAX_ARGS_LENGTH, MAX_STDERR_LENGTH };\n","/**\n * Event patterns and types for dcmrecv output parsing.\n *\n * Defines regex patterns that match DCMTK dcmrecv verbose output,\n * along with typed event data interfaces for each event.\n *\n * @module events/dcmrecv\n */\n\nimport type { EventPattern } from '../parsers/EventPattern';\n\n// ---------------------------------------------------------------------------\n// Event constants (as const, not enum — Rule 3.5)\n// ---------------------------------------------------------------------------\n\n/** Events emitted by dcmrecv process output. */\nconst DcmrecvEvent = {\n LISTENING: 'LISTENING',\n ASSOCIATION_RECEIVED: 'ASSOCIATION_RECEIVED',\n ASSOCIATION_ACKNOWLEDGED: 'ASSOCIATION_ACKNOWLEDGED',\n C_STORE_REQUEST: 'C_STORE_REQUEST',\n STORED_FILE: 'STORED_FILE',\n ASSOCIATION_RELEASE: 'ASSOCIATION_RELEASE',\n ASSOCIATION_ABORTED: 'ASSOCIATION_ABORTED',\n ECHO_REQUEST: 'ECHO_REQUEST',\n CANNOT_START_LISTENER: 'CANNOT_START_LISTENER',\n REFUSING_ASSOCIATION: 'REFUSING_ASSOCIATION',\n /** Synthetic: STORED_FILE enriched with association context. */\n FILE_RECEIVED: 'FILE_RECEIVED',\n /** Synthetic: emitted on association release/abort with summary. */\n ASSOCIATION_COMPLETE: 'ASSOCIATION_COMPLETE',\n} as const;\n\ntype DcmrecvEventValue = (typeof DcmrecvEvent)[keyof typeof DcmrecvEvent];\n\n// ---------------------------------------------------------------------------\n// Event data interfaces (all readonly)\n// ---------------------------------------------------------------------------\n\n/** Data for ASSOCIATION_RECEIVED event. */\ninterface AssociationReceivedData {\n readonly source: string;\n readonly callingAE: string;\n readonly calledAE: string;\n}\n\n/** Data for ASSOCIATION_ACKNOWLEDGED event. */\ninterface AssociationAcknowledgedData {\n readonly maxSendPDV: number;\n}\n\n/** Data for C_STORE_REQUEST event. */\ninterface CStoreRequestData {\n readonly raw: string;\n}\n\n/** Data for STORED_FILE event. */\ninterface StoredFileData {\n readonly filePath: string;\n}\n\n/** Data for REFUSING_ASSOCIATION event. */\ninterface RefusingAssociationData {\n readonly reason: string;\n}\n\n/** Data for CANNOT_START_LISTENER event. */\ninterface CannotStartListenerData {\n readonly message: string;\n}\n\n/** Data for FILE_RECEIVED synthetic event. */\ninterface FileReceivedData {\n readonly filePath: string;\n readonly associationId: string;\n readonly callingAE: string;\n readonly calledAE: string;\n readonly source: string;\n}\n\n/** Data for ASSOCIATION_COMPLETE synthetic event. */\ninterface AssociationCompleteData {\n readonly associationId: string;\n readonly callingAE: string;\n readonly calledAE: string;\n readonly source: string;\n readonly files: readonly string[];\n readonly durationMs: number;\n readonly endReason: 'release' | 'abort';\n}\n\n// ---------------------------------------------------------------------------\n// Regex patterns for dcmrecv verbose output\n// ---------------------------------------------------------------------------\n\n/** Event patterns for parsing dcmrecv verbose output. */\nconst DCMRECV_PATTERNS: readonly EventPattern[] = [\n {\n event: DcmrecvEvent.LISTENING,\n pattern: /listening/i,\n processor: () => undefined,\n },\n {\n event: DcmrecvEvent.ASSOCIATION_RECEIVED,\n pattern: /Association Received\\s{1,100}(\\S+):\\s+(\\S+)\\s+->\\s+(\\S+)/,\n processor: (match): AssociationReceivedData => ({\n source: match[1] ?? '',\n callingAE: match[2] ?? '',\n calledAE: match[3] ?? '',\n }),\n },\n {\n event: DcmrecvEvent.ASSOCIATION_ACKNOWLEDGED,\n pattern: /Association Acknowledged \\(Max Send PDV:\\s*(\\d+)\\)/,\n processor: (match): AssociationAcknowledgedData => ({\n maxSendPDV: Number(match[1]),\n }),\n },\n {\n event: DcmrecvEvent.C_STORE_REQUEST,\n pattern: /Received Store Request/i,\n processor: (match): CStoreRequestData => ({\n raw: match[0] ?? '',\n }),\n },\n {\n event: DcmrecvEvent.STORED_FILE,\n pattern: /Stored received object to file:\\s{0,20}(.{1,1024})/,\n processor: (match): StoredFileData => ({\n filePath: (match[1] ?? '').trim(),\n }),\n },\n {\n event: DcmrecvEvent.ASSOCIATION_RELEASE,\n pattern: /Association Release/i,\n processor: () => undefined,\n },\n {\n event: DcmrecvEvent.ASSOCIATION_ABORTED,\n pattern: /Received Association Abort/i,\n processor: () => undefined,\n },\n {\n event: DcmrecvEvent.ECHO_REQUEST,\n pattern: /Received C-ECHO Request/,\n processor: () => undefined,\n },\n {\n event: DcmrecvEvent.CANNOT_START_LISTENER,\n pattern: /cannot (?:start SCP and )?listen on port/i,\n processor: (match): CannotStartListenerData => ({\n message: match[0] ?? '',\n }),\n },\n {\n event: DcmrecvEvent.REFUSING_ASSOCIATION,\n pattern: /Refusing Association\\s{0,20}\\((.{1,500})\\)/,\n processor: (match): RefusingAssociationData => ({\n reason: match[1] ?? '',\n }),\n },\n];\n\n/** Events that indicate fatal errors (process should be stopped). */\nconst DCMRECV_FATAL_EVENTS: ReadonlySet<string> = new Set([DcmrecvEvent.CANNOT_START_LISTENER]);\n\nexport { DcmrecvEvent, DCMRECV_PATTERNS, DCMRECV_FATAL_EVENTS };\nexport type {\n DcmrecvEventValue,\n AssociationReceivedData,\n AssociationAcknowledgedData,\n CStoreRequestData,\n StoredFileData,\n RefusingAssociationData,\n CannotStartListenerData,\n FileReceivedData,\n AssociationCompleteData,\n};\n","/**\n * Pure state machine tracking DICOM association lifecycle.\n *\n * No I/O, no async, no EventEmitter — just state transitions.\n * Used by Dcmrecv and StoreSCP to correlate files to associations.\n *\n * State machine:\n * ```\n * IDLE -> [beginAssociation] -> ACTIVE -> [trackFile]* -> [endAssociation] -> IDLE\n * ```\n *\n * This single-slot design is safe because all DCMTK server binaries\n * (dcmrecv, storescp, etc.) are single-threaded and handle one\n * association at a time. Concurrent connections queue at the TCP level,\n * so associations never interleave in the output stream.\n *\n * @module servers/AssociationTracker\n */\n\n// ---------------------------------------------------------------------------\n// Interfaces\n// ---------------------------------------------------------------------------\n\n/** Context for the currently active association. */\ninterface AssociationContext {\n readonly associationId: string;\n readonly callingAE: string;\n readonly calledAE: string;\n readonly source: string;\n readonly startTime: number;\n readonly files: string[];\n}\n\n/** A file enriched with association context. */\ninterface TrackedFile {\n readonly filePath: string;\n readonly associationId: string;\n readonly callingAE: string;\n readonly calledAE: string;\n readonly source: string;\n}\n\n/** Summary emitted when an association completes. */\ninterface AssociationSummary {\n readonly associationId: string;\n readonly callingAE: string;\n readonly calledAE: string;\n readonly source: string;\n readonly files: readonly string[];\n readonly durationMs: number;\n readonly endReason: 'release' | 'abort';\n}\n\n// ---------------------------------------------------------------------------\n// AssociationTracker class\n// ---------------------------------------------------------------------------\n\n/**\n * Tracks DICOM association lifecycle for file-to-source correlation.\n *\n * Maintains a simple IDLE/ACTIVE state machine. While active, all tracked\n * files are enriched with the current association context. Only one\n * association can be active at a time — this is safe because DCMTK\n * servers are single-threaded and process associations sequentially.\n *\n * @example\n * ```ts\n * const tracker = new AssociationTracker();\n * const id = tracker.beginAssociation({ callingAE: 'SCU', calledAE: 'SCP', source: 'db' });\n * const file = tracker.trackFile('/path/to/received.dcm');\n * const summary = tracker.endAssociation('release');\n * ```\n */\nclass AssociationTracker {\n private association: AssociationContext | undefined;\n private counter = 0;\n\n /**\n * Begins a new association, transitioning from IDLE to ACTIVE.\n *\n * If an association is already active, it is silently ended (abort)\n * and the new one begins.\n *\n * @param data - Association metadata\n * @returns The unique association ID\n */\n beginAssociation(data: { readonly callingAE: string; readonly calledAE: string; readonly source: string }): string {\n this.counter++;\n const associationId = `assoc-${String(this.counter)}`;\n this.association = {\n associationId,\n callingAE: data.callingAE,\n calledAE: data.calledAE,\n source: data.source,\n startTime: Date.now(),\n files: [],\n };\n return associationId;\n }\n\n /**\n * Tracks a file received during the current association.\n *\n * If no association is active, returns a TrackedFile with empty context.\n *\n * @param filePath - Path to the received file\n * @returns A TrackedFile enriched with association context\n */\n trackFile(filePath: string): TrackedFile {\n if (this.association === undefined) {\n return {\n filePath,\n associationId: '',\n callingAE: '',\n calledAE: '',\n source: '',\n };\n }\n this.association.files.push(filePath);\n return {\n filePath,\n associationId: this.association.associationId,\n callingAE: this.association.callingAE,\n calledAE: this.association.calledAE,\n source: this.association.source,\n };\n }\n\n /**\n * Ends the current association, transitioning from ACTIVE to IDLE.\n *\n * @param reason - Why the association ended\n * @returns An AssociationSummary, or undefined if no association was active\n */\n endAssociation(reason: 'release' | 'abort'): AssociationSummary | undefined {\n if (this.association === undefined) return undefined;\n\n const summary: AssociationSummary = {\n associationId: this.association.associationId,\n callingAE: this.association.callingAE,\n calledAE: this.association.calledAE,\n source: this.association.source,\n files: [...this.association.files],\n durationMs: Date.now() - this.association.startTime,\n endReason: reason,\n };\n\n this.association = undefined;\n return summary;\n }\n\n /** The currently active association context, or undefined. */\n get current(): AssociationContext | undefined {\n return this.association;\n }\n\n /** Whether an association is currently active. */\n get isActive(): boolean {\n return this.association !== undefined;\n }\n\n /** Resets the tracker to IDLE, discarding any active association. */\n reset(): void {\n this.association = undefined;\n }\n}\n\nexport { AssociationTracker };\nexport type { AssociationContext, TrackedFile, AssociationSummary };\n","/**\n * DICOM receiver server wrapping the dcmrecv binary.\n *\n * Provides a type-safe, event-driven API for receiving DICOM objects\n * via C-STORE. Uses a static factory pattern because binary resolution\n * must happen before the constructor call.\n *\n * @module servers/Dcmrecv\n */\n\nimport { z } from 'zod';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { DcmtkProcess } from '../DcmtkProcess';\nimport type { DcmtkProcessConfig } from '../DcmtkProcess';\nimport { LineParser } from '../parsers/LineParser';\nimport { resolveBinary } from '../tools/_resolveBinary';\nimport { createValidationError } from '../tools/_toolError';\nimport { isSafePath, isValidAETitle } from '../patterns';\nimport { DcmrecvEvent, DCMRECV_PATTERNS, DCMRECV_FATAL_EVENTS } from '../events/dcmrecv';\nimport type {\n AssociationReceivedData,\n AssociationAcknowledgedData,\n CStoreRequestData,\n StoredFileData,\n RefusingAssociationData,\n CannotStartListenerData,\n FileReceivedData,\n AssociationCompleteData,\n} from '../events/dcmrecv';\nimport { AssociationTracker } from './AssociationTracker';\n\n// ---------------------------------------------------------------------------\n// Event map type (for documentation — consumers see typed overloads on class)\n// ---------------------------------------------------------------------------\n\n/** Typed event map for the Dcmrecv server. */\ninterface DcmrecvEventMap {\n LISTENING: [];\n ASSOCIATION_RECEIVED: [AssociationReceivedData];\n ASSOCIATION_ACKNOWLEDGED: [AssociationAcknowledgedData];\n C_STORE_REQUEST: [CStoreRequestData];\n STORED_FILE: [StoredFileData];\n ASSOCIATION_RELEASE: [];\n ASSOCIATION_ABORTED: [];\n ECHO_REQUEST: [];\n CANNOT_START_LISTENER: [CannotStartListenerData];\n REFUSING_ASSOCIATION: [RefusingAssociationData];\n FILE_RECEIVED: [FileReceivedData];\n ASSOCIATION_COMPLETE: [AssociationCompleteData];\n}\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\n/** Subdirectory generation mode for received files. */\nconst SubdirectoryMode = {\n NONE: 'none',\n SERIES_DATE: 'series-date',\n} as const;\n\ntype SubdirectoryModeValue = (typeof SubdirectoryMode)[keyof typeof SubdirectoryMode];\n\n/** Filename generation mode for received files. */\nconst FilenameMode = {\n DEFAULT: 'default',\n UNIQUE: 'unique',\n SHORT_UNIQUE: 'short-unique',\n SYSTEM_TIME: 'system-time',\n} as const;\n\ntype FilenameModeValue = (typeof FilenameMode)[keyof typeof FilenameMode];\n\n/** Storage mode for received DICOM objects. */\nconst StorageMode = {\n NORMAL: 'normal',\n BIT_PRESERVING: 'bit-preserving',\n IGNORE: 'ignore',\n} as const;\n\ntype StorageModeValue = (typeof StorageMode)[keyof typeof StorageMode];\n\n/** Options for creating a Dcmrecv server instance. */\ninterface DcmrecvOptions {\n /** Port to listen on (required). */\n readonly port: number;\n /** Application Entity Title. */\n readonly aeTitle?: string | undefined;\n /** Output directory for received files. */\n readonly outputDirectory?: string | undefined;\n /** Path to an association negotiation configuration file. */\n readonly configFile?: string | undefined;\n /** Profile name within the configuration file. */\n readonly configProfile?: string | undefined;\n /** Subdirectory generation mode. */\n readonly subdirectory?: SubdirectoryModeValue | undefined;\n /** Filename generation mode. */\n readonly filenameMode?: FilenameModeValue | undefined;\n /** File extension for received files. */\n readonly filenameExtension?: string | undefined;\n /** Storage mode for received DICOM objects. */\n readonly storageMode?: StorageModeValue | undefined;\n /** ACSE timeout in seconds (passed to DCMTK as-is). */\n readonly acseTimeout?: number | undefined;\n /** DIMSE timeout in seconds (passed to DCMTK as-is). */\n readonly dimseTimeout?: number | undefined;\n /** Maximum PDU receive size. */\n readonly maxPdu?: number | undefined;\n /** Timeout for start() to resolve (milliseconds). */\n readonly startTimeoutMs?: number | undefined;\n /** Timeout for graceful drain during stop() (milliseconds). */\n readonly drainTimeoutMs?: number | undefined;\n /** AbortSignal for external cancellation. */\n readonly signal?: AbortSignal | undefined;\n}\n\nconst DcmrecvOptionsSchema = z\n .object({\n port: z.number().int().min(1).max(65535),\n aeTitle: z.string().min(1).max(16).refine(isValidAETitle, { message: 'AE Title contains invalid characters' }).optional(),\n outputDirectory: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in outputDirectory' }).optional(),\n configFile: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in configFile' }).optional(),\n configProfile: z.string().min(1).optional(),\n subdirectory: z.enum(['none', 'series-date']).optional(),\n filenameMode: z.enum(['default', 'unique', 'short-unique', 'system-time']).optional(),\n filenameExtension: z.string().min(1).optional(),\n storageMode: z.enum(['normal', 'bit-preserving', 'ignore']).optional(),\n acseTimeout: z.number().int().positive().optional(),\n dimseTimeout: z.number().int().positive().optional(),\n maxPdu: z.number().int().min(4096).max(131072).optional(),\n startTimeoutMs: z.number().int().positive().optional(),\n drainTimeoutMs: z.number().int().positive().optional(),\n signal: z.instanceof(AbortSignal).optional(),\n })\n .strict();\n\n// ---------------------------------------------------------------------------\n// Argument builders (each <= 40 lines)\n// ---------------------------------------------------------------------------\n\n/** Builds the CLI arguments array from validated options. */\nfunction buildArgs(options: DcmrecvOptions): string[] {\n const args: string[] = ['--verbose'];\n\n if (options.aeTitle !== undefined) {\n args.push('--aetitle', options.aeTitle);\n }\n if (options.outputDirectory !== undefined) {\n args.push('--output-directory', options.outputDirectory);\n }\n if (options.configFile !== undefined && options.configProfile !== undefined) {\n args.push('--config-file', options.configFile, options.configProfile);\n }\n\n addFilenameArgs(args, options);\n addStorageArgs(args, options);\n addNetworkArgs(args, options);\n\n args.push(String(options.port));\n return args;\n}\n\n/** Appends filename-related CLI flags. */\nfunction addFilenameArgs(args: string[], options: DcmrecvOptions): void {\n if (options.subdirectory === 'series-date') {\n args.push('--sort-on-patientsname');\n }\n if (options.filenameMode === 'unique') {\n args.push('--unique-filenames');\n } else if (options.filenameMode === 'short-unique') {\n args.push('--short-unique-filenames');\n } else if (options.filenameMode === 'system-time') {\n args.push('--system-time-filenames');\n }\n if (options.filenameExtension !== undefined) {\n args.push('--filename-extension', options.filenameExtension);\n }\n}\n\n/** Appends storage-related CLI flags. */\nfunction addStorageArgs(args: string[], options: DcmrecvOptions): void {\n if (options.storageMode === 'bit-preserving') {\n args.push('--bit-preserving');\n } else if (options.storageMode === 'ignore') {\n args.push('--ignore');\n }\n}\n\n/** Appends network-related CLI flags. */\nfunction addNetworkArgs(args: string[], options: DcmrecvOptions): void {\n if (options.acseTimeout !== undefined) {\n args.push('--acse-timeout', String(options.acseTimeout));\n }\n if (options.dimseTimeout !== undefined) {\n args.push('--dimse-timeout', String(options.dimseTimeout));\n }\n if (options.maxPdu !== undefined) {\n args.push('--max-pdu', String(options.maxPdu));\n }\n}\n\n// ---------------------------------------------------------------------------\n// Dcmrecv class\n// ---------------------------------------------------------------------------\n\n/**\n * DICOM receiver server wrapping the dcmrecv binary.\n *\n * Uses a static `create()` factory because binary resolution is fallible\n * and must complete before the constructor runs.\n *\n * Server-specific events (LISTENING, STORED_FILE, etc.) are emitted dynamically\n * via the LineParser. Use `onEvent()` for typed listeners on server events.\n *\n * @example\n * ```ts\n * const result = Dcmrecv.create({ port: 11112, outputDirectory: '/tmp/received' });\n * if (result.ok) {\n * const server = result.value;\n * server.onEvent('STORED_FILE', (data) => console.log('Stored:', data.filePath));\n * const startResult = await server.start();\n * }\n * ```\n */\nclass Dcmrecv extends DcmtkProcess {\n private readonly parser: LineParser;\n private readonly tracker: AssociationTracker;\n private abortSignal: AbortSignal | undefined;\n private abortHandler: (() => void) | undefined;\n\n private constructor(config: DcmtkProcessConfig, parser: LineParser, signal?: AbortSignal) {\n super(config);\n this.parser = parser;\n this.tracker = new AssociationTracker();\n this.wireParser();\n this.wireTracker();\n if (signal !== undefined) {\n this.wireAbortSignal(signal);\n }\n }\n\n /**\n * Registers a typed listener for a dcmrecv-specific event.\n *\n * @param event - The event name from DcmrecvEventMap\n * @param listener - Callback receiving typed event data\n * @returns this for chaining\n */\n /** Disposes the server and its parser, preventing listener leaks. */\n [Symbol.dispose](): void {\n if (this.abortSignal !== undefined && this.abortHandler !== undefined) {\n this.abortSignal.removeEventListener('abort', this.abortHandler);\n }\n this.parser[Symbol.dispose]();\n super[Symbol.dispose]();\n }\n\n onEvent<K extends keyof DcmrecvEventMap>(event: K, listener: (...args: DcmrecvEventMap[K]) => void): this {\n return this.on(event as string, listener as never);\n }\n\n /**\n * Registers a listener for incoming associations.\n *\n * @param listener - Callback receiving association data\n * @returns this for chaining\n */\n onAssociationReceived(listener: (...args: DcmrecvEventMap['ASSOCIATION_RECEIVED']) => void): this {\n return this.onEvent('ASSOCIATION_RECEIVED', listener);\n }\n\n /**\n * Registers a listener for stored files.\n *\n * @param listener - Callback receiving stored file data\n * @returns this for chaining\n */\n onStoredFile(listener: (...args: DcmrecvEventMap['STORED_FILE']) => void): this {\n return this.onEvent('STORED_FILE', listener);\n }\n\n /**\n * Registers a listener for received files enriched with association context.\n *\n * @param listener - Callback receiving tracked file data\n * @returns this for chaining\n */\n onFileReceived(listener: (...args: DcmrecvEventMap['FILE_RECEIVED']) => void): this {\n return this.onEvent('FILE_RECEIVED', listener);\n }\n\n /**\n * Registers a listener for completed associations.\n *\n * @param listener - Callback receiving association summary\n * @returns this for chaining\n */\n onAssociationComplete(listener: (...args: DcmrecvEventMap['ASSOCIATION_COMPLETE']) => void): this {\n return this.onEvent('ASSOCIATION_COMPLETE', listener);\n }\n\n /**\n * Creates a new Dcmrecv server instance.\n *\n * @param options - Configuration options for the dcmrecv server\n * @returns A Result containing the server instance or a validation/resolution error\n */\n static create(options: DcmrecvOptions): Result<Dcmrecv> {\n const validation = DcmrecvOptionsSchema.safeParse(options);\n if (!validation.success) {\n return err(createValidationError('dcmrecv', validation.error));\n }\n\n const binaryResult = resolveBinary('dcmrecv');\n if (!binaryResult.ok) {\n return err(binaryResult.error);\n }\n\n const args = buildArgs(options);\n const parser = new LineParser();\n for (const pattern of DCMRECV_PATTERNS) {\n const addResult = parser.addPattern(pattern);\n if (!addResult.ok) {\n return err(addResult.error);\n }\n }\n\n const config: DcmtkProcessConfig = {\n binary: binaryResult.value,\n args,\n startTimeoutMs: options.startTimeoutMs,\n drainTimeoutMs: options.drainTimeoutMs,\n isStartedPredicate: line => /listening/i.test(line),\n };\n\n return ok(new Dcmrecv(config, parser, options.signal));\n }\n\n /** Wires the line parser to the process output. */\n private wireParser(): void {\n this.on('line', ({ text }) => {\n this.parser.feed(text);\n });\n\n this.parser.on('match', ({ event, data }) => {\n if (DCMRECV_FATAL_EVENTS.has(event)) {\n this.emit('error', { error: new Error(`Fatal: ${event}`), fatal: true });\n void this.stop();\n }\n this.emit(event, data);\n });\n }\n\n /** Wires the AssociationTracker to server events. */\n private wireTracker(): void {\n this.onEvent('ASSOCIATION_RECEIVED', data => {\n this.tracker.beginAssociation(data);\n });\n\n this.onEvent('STORED_FILE', data => {\n const tracked = this.tracker.trackFile(data.filePath);\n this.emit(DcmrecvEvent.FILE_RECEIVED as string, tracked);\n });\n\n this.onEvent('ASSOCIATION_RELEASE', () => {\n const summary = this.tracker.endAssociation('release');\n if (summary !== undefined) {\n this.emit(DcmrecvEvent.ASSOCIATION_COMPLETE as string, summary);\n }\n });\n\n this.onEvent('ASSOCIATION_ABORTED', () => {\n const summary = this.tracker.endAssociation('abort');\n if (summary !== undefined) {\n this.emit(DcmrecvEvent.ASSOCIATION_COMPLETE as string, summary);\n }\n });\n }\n\n /** Wires an AbortSignal to stop the server. */\n private wireAbortSignal(signal: AbortSignal): void {\n if (signal.aborted) {\n void this.stop();\n return;\n }\n this.abortSignal = signal;\n this.abortHandler = (): void => {\n void this.stop();\n };\n signal.addEventListener('abort', this.abortHandler, { once: true });\n }\n}\n\nexport { Dcmrecv, SubdirectoryMode, FilenameMode, StorageMode };\nexport type { DcmrecvOptions, DcmrecvEventMap, SubdirectoryModeValue, FilenameModeValue, StorageModeValue };\n","/**\n * Event patterns and types for storescp output parsing.\n *\n * Extends dcmrecv patterns with storescp-specific events like\n * file storage progress and subdirectory creation.\n *\n * @module events/storescp\n */\n\nimport type { EventPattern } from '../parsers/EventPattern';\nimport { DcmrecvEvent, DCMRECV_PATTERNS, DCMRECV_FATAL_EVENTS } from './dcmrecv';\nimport type { AssociationReceivedData } from './dcmrecv';\n\n// ---------------------------------------------------------------------------\n// Event constants (superset of dcmrecv — Rule 3.5)\n// ---------------------------------------------------------------------------\n\n/** Events emitted by storescp process output. */\nconst StorescpEvent = {\n ...DcmrecvEvent,\n STORING_FILE: 'STORING_FILE',\n SUBDIRECTORY_CREATED: 'SUBDIRECTORY_CREATED',\n} as const;\n\ntype StorescpEventValue = (typeof StorescpEvent)[keyof typeof StorescpEvent];\n\n// ---------------------------------------------------------------------------\n// Additional event data interfaces\n// ---------------------------------------------------------------------------\n\n/** Data for STORING_FILE event. */\ninterface StoringFileData {\n readonly filePath: string;\n}\n\n/** Data for SUBDIRECTORY_CREATED event. */\ninterface SubdirectoryCreatedData {\n readonly directory: string;\n}\n\n// ---------------------------------------------------------------------------\n// storescp-specific patterns\n// ---------------------------------------------------------------------------\n\n/**\n * storescp-specific ASSOCIATION_RECEIVED pattern.\n * storescp --verbose outputs only \"Association Received\" (no AE details),\n * so this pattern returns empty fields for source/callingAE/calledAE.\n */\nconst STORESCP_ASSOCIATION_RECEIVED: EventPattern = {\n event: StorescpEvent.ASSOCIATION_RECEIVED,\n pattern: /Association Received/i,\n processor: (): AssociationReceivedData => ({ source: '', callingAE: '', calledAE: '' }),\n};\n\nconst STORESCP_ADDITIONAL_PATTERNS: readonly EventPattern[] = [\n {\n event: StorescpEvent.STORING_FILE,\n pattern: /storing DICOM file:\\s{0,20}(.{1,1024})/i,\n processor: (match): StoringFileData => ({\n filePath: (match[1] ?? '').trim(),\n }),\n },\n {\n event: StorescpEvent.SUBDIRECTORY_CREATED,\n pattern: /created new subdirectory[:\\s]{0,20}(.{1,1024})/i,\n processor: (match): SubdirectoryCreatedData => ({\n directory: (match[1] ?? '').trim(),\n }),\n },\n];\n\n/** Combined event patterns for parsing storescp verbose output. */\nconst STORESCP_PATTERNS: readonly EventPattern[] = [\n ...DCMRECV_PATTERNS.filter(p => p.event !== DcmrecvEvent.ASSOCIATION_RECEIVED),\n STORESCP_ASSOCIATION_RECEIVED,\n ...STORESCP_ADDITIONAL_PATTERNS,\n];\n\n/** Events that indicate fatal errors (process should be stopped). */\nconst STORESCP_FATAL_EVENTS: ReadonlySet<string> = new Set([...DCMRECV_FATAL_EVENTS]);\n\nexport { StorescpEvent, STORESCP_PATTERNS, STORESCP_FATAL_EVENTS };\nexport type { StorescpEventValue, StoringFileData, SubdirectoryCreatedData };\n","/**\n * DICOM Storage SCP server wrapping the storescp binary.\n *\n * Provides a type-safe, event-driven API for receiving DICOM objects\n * via the storescp command-line tool. Supports sorting, exec hooks,\n * custom transfer syntaxes, and all standard storescp options.\n *\n * @module servers/StoreSCP\n */\n\nimport { z } from 'zod';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { DcmtkProcess } from '../DcmtkProcess';\nimport type { DcmtkProcessConfig } from '../DcmtkProcess';\nimport { LineParser } from '../parsers/LineParser';\nimport { resolveBinary } from '../tools/_resolveBinary';\nimport { createValidationError } from '../tools/_toolError';\nimport { isSafePath, isValidAETitle } from '../patterns';\nimport { STORESCP_PATTERNS, STORESCP_FATAL_EVENTS } from '../events/storescp';\nimport { DcmrecvEvent } from '../events/dcmrecv';\nimport type {\n AssociationReceivedData,\n AssociationAcknowledgedData,\n CStoreRequestData,\n StoredFileData,\n RefusingAssociationData,\n CannotStartListenerData,\n FileReceivedData,\n AssociationCompleteData,\n} from '../events/dcmrecv';\nimport type { StoringFileData, SubdirectoryCreatedData } from '../events/storescp';\nimport { AssociationTracker } from './AssociationTracker';\n\n// ---------------------------------------------------------------------------\n// Event map type (for documentation — consumers see typed overloads on class)\n// ---------------------------------------------------------------------------\n\n/** Typed event map for the StoreSCP server. */\ninterface StoreSCPEventMap {\n LISTENING: [];\n ASSOCIATION_RECEIVED: [AssociationReceivedData];\n ASSOCIATION_ACKNOWLEDGED: [AssociationAcknowledgedData];\n C_STORE_REQUEST: [CStoreRequestData];\n STORED_FILE: [StoredFileData];\n ASSOCIATION_RELEASE: [];\n ASSOCIATION_ABORTED: [];\n ECHO_REQUEST: [];\n CANNOT_START_LISTENER: [CannotStartListenerData];\n REFUSING_ASSOCIATION: [RefusingAssociationData];\n STORING_FILE: [StoringFileData];\n SUBDIRECTORY_CREATED: [SubdirectoryCreatedData];\n FILE_RECEIVED: [FileReceivedData];\n ASSOCIATION_COMPLETE: [AssociationCompleteData];\n}\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\n/** Preferred transfer syntax for incoming associations. */\nconst PreferredTransferSyntax = {\n LITTLE_ENDIAN: 'little-endian',\n BIG_ENDIAN: 'big-endian',\n IMPLICIT: 'implicit',\n ACCEPT_ALL: 'accept-all',\n} as const;\n\ntype PreferredTransferSyntaxValue = (typeof PreferredTransferSyntax)[keyof typeof PreferredTransferSyntax];\n\n/** Options for creating a StoreSCP server instance. */\ninterface StoreSCPOptions {\n /** Port to listen on (required). */\n readonly port: number;\n /** Application Entity Title. */\n readonly aeTitle?: string | undefined;\n /** Output directory for received files. */\n readonly outputDirectory?: string | undefined;\n /** Path to an association negotiation configuration file. */\n readonly configFile?: string | undefined;\n /** Profile name within the configuration file. */\n readonly configProfile?: string | undefined;\n /** Preferred transfer syntax (not valid with configFile). */\n readonly preferredTransferSyntax?: PreferredTransferSyntaxValue | undefined;\n /** Sort studies into subdirectories. */\n readonly sortByStudy?: boolean | undefined;\n /** Sort by Study Instance UID. */\n readonly sortByStudyUID?: boolean | undefined;\n /** Sort by patient name. */\n readonly sortByPatientName?: boolean | undefined;\n /** Generate unique filenames. */\n readonly uniqueFilenames?: boolean | undefined;\n /** Use bit-preserving mode. */\n readonly bitPreserving?: boolean | undefined;\n /** Execute command on each received file. */\n readonly execOnReception?: string | undefined;\n /** Execute command at end of study. */\n readonly execOnEndOfStudy?: string | undefined;\n /** Timeout for end-of-study detection in seconds (passed to DCMTK as-is). */\n readonly endOfStudyTimeout?: number | undefined;\n /** Rename files at end of study. */\n readonly renameOnEndOfStudy?: boolean | undefined;\n /** Socket timeout in seconds (passed to DCMTK as-is). */\n readonly socketTimeout?: number | undefined;\n /** ACSE timeout in seconds (passed to DCMTK as-is). */\n readonly acseTimeout?: number | undefined;\n /** DIMSE timeout in seconds (passed to DCMTK as-is). */\n readonly dimseTimeout?: number | undefined;\n /** Maximum PDU receive size. */\n readonly maxPdu?: number | undefined;\n /** Filename extension for received files. */\n readonly filenameExtension?: string | undefined;\n /** Timeout for start() to resolve (milliseconds). */\n readonly startTimeoutMs?: number | undefined;\n /** Timeout for graceful drain during stop() (milliseconds). */\n readonly drainTimeoutMs?: number | undefined;\n /** AbortSignal for external cancellation. */\n readonly signal?: AbortSignal | undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Configuration presets\n// ---------------------------------------------------------------------------\n\n/**\n * Pre-configured option sets for common StoreSCP deployment patterns.\n * Spread a preset into your options to avoid specifying boilerplate.\n *\n * @example\n * ```ts\n * StoreSCP.create({ ...StoreSCPPreset.PRODUCTION, port: 11112, outputDirectory: '/data' });\n * ```\n */\nconst StoreSCPPreset = {\n /** Basic storage: unique filenames to avoid collisions. */\n BASIC_STORAGE: {\n uniqueFilenames: true,\n },\n /** Testing: unique filenames, preserving raw transfer syntax. */\n TESTING: {\n uniqueFilenames: true,\n bitPreserving: true,\n },\n /** Production: unique filenames with reasonable timeouts. */\n PRODUCTION: {\n uniqueFilenames: true,\n acseTimeout: 30,\n dimseTimeout: 60,\n },\n} as const satisfies Record<string, Partial<StoreSCPOptions>>;\n\n/** Names of the available StoreSCP configuration presets. */\ntype StoreSCPPresetName = keyof typeof StoreSCPPreset;\n\nconst StoreSCPOptionsSchema = z\n .object({\n port: z.number().int().min(1).max(65535),\n aeTitle: z.string().min(1).max(16).refine(isValidAETitle, { message: 'AE Title contains invalid characters' }).optional(),\n outputDirectory: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in outputDirectory' }).optional(),\n configFile: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in configFile' }).optional(),\n configProfile: z.string().min(1).optional(),\n preferredTransferSyntax: z.enum(['little-endian', 'big-endian', 'implicit', 'accept-all']).optional(),\n sortByStudy: z.boolean().optional(),\n sortByStudyUID: z.boolean().optional(),\n sortByPatientName: z.boolean().optional(),\n uniqueFilenames: z.boolean().optional(),\n bitPreserving: z.boolean().optional(),\n execOnReception: z.string().min(1).optional(),\n execOnEndOfStudy: z.string().min(1).optional(),\n endOfStudyTimeout: z.number().int().positive().optional(),\n renameOnEndOfStudy: z.boolean().optional(),\n socketTimeout: z.number().int().positive().optional(),\n acseTimeout: z.number().int().positive().optional(),\n dimseTimeout: z.number().int().positive().optional(),\n maxPdu: z.number().int().min(4096).max(131072).optional(),\n filenameExtension: z.string().min(1).optional(),\n startTimeoutMs: z.number().int().positive().optional(),\n drainTimeoutMs: z.number().int().positive().optional(),\n signal: z.instanceof(AbortSignal).optional(),\n })\n .strict();\n\n// ---------------------------------------------------------------------------\n// Argument builders (each <= 40 lines)\n// ---------------------------------------------------------------------------\n\n/** Builds the full CLI arguments array. */\nfunction buildArgs(options: StoreSCPOptions): string[] {\n const args: string[] = ['--verbose'];\n\n if (options.aeTitle !== undefined) {\n args.push('--aetitle', options.aeTitle);\n }\n if (options.configFile !== undefined && options.configProfile !== undefined) {\n args.push('--config-file', options.configFile, options.configProfile);\n }\n\n buildTransferSyntaxArgs(args, options);\n buildSortArgs(args, options);\n buildOutputArgs(args, options);\n buildNetworkArgs(args, options);\n buildExecArgs(args, options);\n\n args.push(String(options.port));\n return args;\n}\n\n/** Appends transfer syntax CLI flags. */\nfunction buildTransferSyntaxArgs(args: string[], options: StoreSCPOptions): void {\n if (options.preferredTransferSyntax === 'little-endian') {\n args.push('+xe');\n } else if (options.preferredTransferSyntax === 'big-endian') {\n args.push('+xb');\n } else if (options.preferredTransferSyntax === 'implicit') {\n args.push('+xi');\n } else if (options.preferredTransferSyntax === 'accept-all') {\n args.push('+xa');\n }\n}\n\n/** Appends sorting-related CLI flags. */\nfunction buildSortArgs(args: string[], options: StoreSCPOptions): void {\n if (options.sortByStudy === true) {\n args.push('--sort-conc-studies');\n }\n if (options.sortByStudyUID === true) {\n args.push('--sort-on-study-uid');\n }\n if (options.sortByPatientName === true) {\n args.push('--sort-on-patientsname');\n }\n}\n\n/** Appends output-related CLI flags. */\nfunction buildOutputArgs(args: string[], options: StoreSCPOptions): void {\n if (options.outputDirectory !== undefined) {\n args.push('--output-directory', options.outputDirectory);\n }\n if (options.uniqueFilenames === true) {\n args.push('--unique-filenames');\n }\n if (options.bitPreserving === true) {\n args.push('--bit-preserving');\n }\n if (options.filenameExtension !== undefined) {\n args.push('--filename-extension', options.filenameExtension);\n }\n}\n\n/** Appends network-related CLI flags. */\nfunction buildNetworkArgs(args: string[], options: StoreSCPOptions): void {\n if (options.socketTimeout !== undefined) {\n args.push('--socket-timeout', String(options.socketTimeout));\n }\n if (options.acseTimeout !== undefined) {\n args.push('--acse-timeout', String(options.acseTimeout));\n }\n if (options.dimseTimeout !== undefined) {\n args.push('--dimse-timeout', String(options.dimseTimeout));\n }\n if (options.maxPdu !== undefined) {\n args.push('--max-pdu', String(options.maxPdu));\n }\n}\n\n/** Appends exec-related CLI flags. */\nfunction buildExecArgs(args: string[], options: StoreSCPOptions): void {\n if (options.execOnReception !== undefined) {\n args.push('--exec-on-reception', options.execOnReception);\n }\n if (options.execOnEndOfStudy !== undefined) {\n args.push('--exec-on-eostudy', options.execOnEndOfStudy);\n }\n if (options.endOfStudyTimeout !== undefined) {\n args.push('--eostudy-timeout', String(options.endOfStudyTimeout));\n }\n if (options.renameOnEndOfStudy === true) {\n args.push('--rename-on-eostudy');\n }\n}\n\n// ---------------------------------------------------------------------------\n// StoreSCP class\n// ---------------------------------------------------------------------------\n\n/**\n * DICOM Storage SCP server wrapping the storescp binary.\n *\n * Uses a static `create()` factory because binary resolution is fallible\n * and must complete before the constructor runs.\n *\n * Note: storescp does not print a \"listening\" message, so `start()` resolves\n * on spawn. If the port is busy, storescp exits immediately and `start()`\n * returns an error via the close handler.\n *\n * Server-specific events are emitted dynamically via the LineParser.\n * Use `onEvent()` for typed listeners on server events.\n *\n * @example\n * ```ts\n * const result = StoreSCP.create({ port: 11112, outputDirectory: '/tmp/received' });\n * if (result.ok) {\n * const server = result.value;\n * server.onEvent('STORED_FILE', (data) => console.log('Stored:', data.filePath));\n * const startResult = await server.start();\n * }\n * ```\n */\nclass StoreSCP extends DcmtkProcess {\n private readonly parser: LineParser;\n private readonly tracker: AssociationTracker;\n private abortSignal: AbortSignal | undefined;\n private abortHandler: (() => void) | undefined;\n\n private constructor(config: DcmtkProcessConfig, parser: LineParser, signal?: AbortSignal) {\n super(config);\n this.parser = parser;\n this.tracker = new AssociationTracker();\n this.wireParser();\n this.wireTracker();\n if (signal !== undefined) {\n this.wireAbortSignal(signal);\n }\n }\n\n /** Disposes the server and its parser, preventing listener leaks. */\n [Symbol.dispose](): void {\n if (this.abortSignal !== undefined && this.abortHandler !== undefined) {\n this.abortSignal.removeEventListener('abort', this.abortHandler);\n }\n this.parser[Symbol.dispose]();\n super[Symbol.dispose]();\n }\n\n /**\n * Registers a typed listener for a storescp-specific event.\n *\n * @param event - The event name from StoreSCPEventMap\n * @param listener - Callback receiving typed event data\n * @returns this for chaining\n */\n onEvent<K extends keyof StoreSCPEventMap>(event: K, listener: (...args: StoreSCPEventMap[K]) => void): this {\n return this.on(event as string, listener as never);\n }\n\n /**\n * Registers a listener for incoming associations.\n *\n * @param listener - Callback receiving association data\n * @returns this for chaining\n */\n onAssociationReceived(listener: (...args: StoreSCPEventMap['ASSOCIATION_RECEIVED']) => void): this {\n return this.onEvent('ASSOCIATION_RECEIVED', listener);\n }\n\n /**\n * Registers a listener for files being stored to disk.\n *\n * @param listener - Callback receiving storing file data\n * @returns this for chaining\n */\n onStoringFile(listener: (...args: StoreSCPEventMap['STORING_FILE']) => void): this {\n return this.onEvent('STORING_FILE', listener);\n }\n\n /**\n * Registers a listener for received files enriched with association context.\n *\n * @param listener - Callback receiving tracked file data\n * @returns this for chaining\n */\n onFileReceived(listener: (...args: StoreSCPEventMap['FILE_RECEIVED']) => void): this {\n return this.onEvent('FILE_RECEIVED', listener);\n }\n\n /**\n * Registers a listener for completed associations.\n *\n * @param listener - Callback receiving association summary\n * @returns this for chaining\n */\n onAssociationComplete(listener: (...args: StoreSCPEventMap['ASSOCIATION_COMPLETE']) => void): this {\n return this.onEvent('ASSOCIATION_COMPLETE', listener);\n }\n\n /**\n * Creates a new StoreSCP server instance.\n *\n * @param options - Configuration options for the storescp server\n * @returns A Result containing the server instance or a validation/resolution error\n */\n static create(options: StoreSCPOptions): Result<StoreSCP> {\n const validation = StoreSCPOptionsSchema.safeParse(options);\n if (!validation.success) {\n return err(createValidationError('storescp', validation.error));\n }\n\n const binaryResult = resolveBinary('storescp');\n if (!binaryResult.ok) {\n return err(binaryResult.error);\n }\n\n const args = buildArgs(options);\n const parser = new LineParser();\n for (const pattern of STORESCP_PATTERNS) {\n const addResult = parser.addPattern(pattern);\n if (!addResult.ok) {\n return err(addResult.error);\n }\n }\n\n const config: DcmtkProcessConfig = {\n binary: binaryResult.value,\n args,\n startTimeoutMs: options.startTimeoutMs,\n drainTimeoutMs: options.drainTimeoutMs,\n // storescp doesn't print \"listening\" — resolve on spawn\n };\n\n return ok(new StoreSCP(config, parser, options.signal));\n }\n\n /** Wires the line parser to the process output. */\n private wireParser(): void {\n this.on('line', ({ text }) => {\n this.parser.feed(text);\n });\n\n this.parser.on('match', ({ event, data }) => {\n if (STORESCP_FATAL_EVENTS.has(event)) {\n this.emit('error', { error: new Error(`Fatal: ${event}`), fatal: true });\n void this.stop();\n }\n this.emit(event, data);\n });\n }\n\n /** Wires the AssociationTracker to server events. */\n private wireTracker(): void {\n this.onEvent('ASSOCIATION_RECEIVED', data => {\n this.tracker.beginAssociation(data);\n });\n\n // storescp outputs \"storing DICOM file:\" (STORING_FILE), not\n // \"Stored received object to file:\" (STORED_FILE) like dcmrecv.\n // Listen to both so the tracker works regardless of which fires.\n this.onEvent('STORING_FILE', data => {\n const tracked = this.tracker.trackFile(data.filePath);\n this.emit(DcmrecvEvent.FILE_RECEIVED as string, tracked);\n });\n\n this.onEvent('STORED_FILE', data => {\n const tracked = this.tracker.trackFile(data.filePath);\n this.emit(DcmrecvEvent.FILE_RECEIVED as string, tracked);\n });\n\n this.onEvent('ASSOCIATION_RELEASE', () => {\n const summary = this.tracker.endAssociation('release');\n if (summary !== undefined) {\n this.emit(DcmrecvEvent.ASSOCIATION_COMPLETE as string, summary);\n }\n });\n\n this.onEvent('ASSOCIATION_ABORTED', () => {\n const summary = this.tracker.endAssociation('abort');\n if (summary !== undefined) {\n this.emit(DcmrecvEvent.ASSOCIATION_COMPLETE as string, summary);\n }\n });\n }\n\n /** Wires an AbortSignal to stop the server. */\n private wireAbortSignal(signal: AbortSignal): void {\n if (signal.aborted) {\n void this.stop();\n return;\n }\n this.abortSignal = signal;\n this.abortHandler = (): void => {\n void this.stop();\n };\n signal.addEventListener('abort', this.abortHandler, { once: true });\n }\n}\n\nexport { StoreSCP, PreferredTransferSyntax, StoreSCPPreset };\nexport type { StoreSCPOptions, StoreSCPEventMap, PreferredTransferSyntaxValue, StoreSCPPresetName };\n","/**\n * Branded types for domain primitives.\n *\n * Branded types use TypeScript's structural type system to prevent accidental\n * mixing of semantically different values that share the same underlying type.\n * A `DicomTag` cannot be used where an `AETitle` is expected, even though both\n * are strings at runtime.\n *\n * @module brands\n */\n\nimport { normalize } from 'node:path';\nimport type { Result } from './types';\nimport { ok, err } from './types';\nimport {\n DICOM_TAG_PATTERN,\n AE_TITLE_PATTERN,\n UID_PATTERN,\n DICOM_TAG_PATH_PATTERN,\n AE_TITLE_MIN_LENGTH,\n AE_TITLE_MAX_LENGTH,\n UID_MAX_LENGTH,\n PORT_MIN,\n PORT_MAX,\n PATH_TRAVERSAL_PATTERN,\n} from './patterns';\n\ndeclare const __brand: unique symbol;\n\n/** Intersects a base type with a phantom brand property for nominal typing. */\ntype Brand<T, TBrand extends string> = T & { readonly [__brand]: TBrand };\n\n// ---------------------------------------------------------------------------\n// Branded types\n// ---------------------------------------------------------------------------\n\n/**\n * A validated DICOM tag string, e.g. `\"(0010,0010)\"`.\n *\n * @remarks\n * Branded types enforce type safety when passing values between functions.\n * They are not required for direct API calls (which validate internally via Zod).\n * Use {@link createDicomTag} to obtain a branded value from a raw string.\n */\ntype DicomTag = Brand<string, 'DicomTag'>;\n\n/**\n * A validated AE Title (1-16 chars: uppercase letters, digits, spaces, hyphens).\n *\n * @remarks\n * Branded types enforce type safety when passing values between functions.\n * They are not required for direct API calls (which validate internally via Zod).\n * Use {@link createAETitle} to obtain a branded value from a raw string.\n */\ntype AETitle = Brand<string, 'AETitle'>;\n\n/**\n * A validated DICOM tag path, e.g. `\"(0040,A730)[0].(0010,0010)\"`.\n *\n * @remarks\n * Branded types enforce type safety when passing values between functions.\n * They are not required for direct API calls (which validate internally via Zod).\n * Use {@link createDicomTagPath} to obtain a branded value from a raw string.\n */\ntype DicomTagPath = Brand<string, 'DicomTagPath'>;\n\n/**\n * A validated SOP Class UID (dotted numeric OID, 1-64 chars).\n *\n * @remarks\n * Branded types enforce type safety when passing values between functions.\n * They are not required for direct API calls (which validate internally via Zod).\n * Use {@link createSOPClassUID} to obtain a branded value from a raw string.\n */\ntype SOPClassUID = Brand<string, 'SOPClassUID'>;\n\n/**\n * A validated Transfer Syntax UID (dotted numeric OID, 1-64 chars).\n *\n * @remarks\n * Branded types enforce type safety when passing values between functions.\n * They are not required for direct API calls (which validate internally via Zod).\n * Use {@link createTransferSyntaxUID} to obtain a branded value from a raw string.\n */\ntype TransferSyntaxUID = Brand<string, 'TransferSyntaxUID'>;\n\n/**\n * A validated filesystem path to a DICOM file.\n *\n * @remarks\n * Branded types enforce type safety when passing values between functions.\n * They are not required for direct API calls (which validate internally via Zod).\n * Use {@link createDicomFilePath} to obtain a branded value from a raw string.\n */\ntype DicomFilePath = Brand<string, 'DicomFilePath'>;\n\n/**\n * A validated network port number (1-65535).\n *\n * @remarks\n * Branded types enforce type safety when passing values between functions.\n * They are not required for direct API calls (which validate internally via Zod).\n * Use {@link createPort} to obtain a branded value from a raw number.\n */\ntype Port = Brand<number, 'Port'>;\n\n// Validation patterns and constants imported from ./patterns\n\n// ---------------------------------------------------------------------------\n// Factory functions\n// ---------------------------------------------------------------------------\n\n/**\n * Creates a validated DicomTag from a raw string.\n *\n * @param input - A string expected to be in format `(XXXX,XXXX)` where X is a hex digit\n * @returns A Result containing the branded DicomTag or an error\n */\nfunction createDicomTag(input: string): Result<DicomTag> {\n if (!DICOM_TAG_PATTERN.test(input)) {\n return err(new Error(`Invalid DICOM tag: \"${input}\". Expected format (XXXX,XXXX) where X is a hex digit`));\n }\n return ok(input as DicomTag);\n}\n\n/**\n * Creates a validated AETitle from a raw string.\n *\n * @param input - A string expected to be 1-16 chars of letters, digits, spaces, or hyphens\n * @returns A Result containing the branded AETitle or an error\n */\nfunction createAETitle(input: string): Result<AETitle> {\n if (input.length < AE_TITLE_MIN_LENGTH || input.length > AE_TITLE_MAX_LENGTH) {\n return err(new Error(`Invalid AE Title: \"${input}\". Must be ${AE_TITLE_MIN_LENGTH}-${AE_TITLE_MAX_LENGTH} characters`));\n }\n if (!AE_TITLE_PATTERN.test(input)) {\n return err(new Error(`Invalid AE Title: \"${input}\". Only letters, digits, spaces, and hyphens are allowed`));\n }\n return ok(input as AETitle);\n}\n\n/**\n * Creates a validated DicomTagPath from a raw string.\n *\n * @param input - A dot-separated path of DICOM tags with optional array indices\n * @returns A Result containing the branded DicomTagPath or an error\n */\nfunction createDicomTagPath(input: string): Result<DicomTagPath> {\n // Empty check is duplicated in the Zod DicomTagPathSchema (.min(1)), but\n // kept here for a clearer error message from the brands factory.\n if (input.length === 0) {\n return err(new Error('Invalid DICOM tag path: empty string'));\n }\n if (!DICOM_TAG_PATH_PATTERN.test(input)) {\n return err(new Error(`Invalid DICOM tag path: \"${input}\". Expected format like (XXXX,XXXX) or (XXXX,XXXX)[0].(XXXX,XXXX)`));\n }\n return ok(input as DicomTagPath);\n}\n\n/**\n * Creates a validated SOPClassUID from a raw string.\n *\n * @param input - A dotted numeric OID string, 1-64 characters\n * @returns A Result containing the branded SOPClassUID or an error\n */\nfunction createSOPClassUID(input: string): Result<SOPClassUID> {\n if (input.length === 0 || input.length > UID_MAX_LENGTH) {\n return err(new Error(`Invalid SOP Class UID: \"${input}\". Must be 1-${UID_MAX_LENGTH} characters`));\n }\n if (!UID_PATTERN.test(input)) {\n return err(new Error(`Invalid SOP Class UID: \"${input}\". Must be a dotted numeric OID`));\n }\n return ok(input as SOPClassUID);\n}\n\n/**\n * Creates a validated TransferSyntaxUID from a raw string.\n *\n * @param input - A dotted numeric OID string, 1-64 characters\n * @returns A Result containing the branded TransferSyntaxUID or an error\n */\nfunction createTransferSyntaxUID(input: string): Result<TransferSyntaxUID> {\n if (input.length === 0 || input.length > UID_MAX_LENGTH) {\n return err(new Error(`Invalid Transfer Syntax UID: \"${input}\". Must be 1-${UID_MAX_LENGTH} characters`));\n }\n if (!UID_PATTERN.test(input)) {\n return err(new Error(`Invalid Transfer Syntax UID: \"${input}\". Must be a dotted numeric OID`));\n }\n return ok(input as TransferSyntaxUID);\n}\n\n/**\n * Creates a branded DicomFilePath from a raw string.\n * Validates that the path is non-empty and does not contain path traversal sequences.\n *\n * @param input - A filesystem path string\n * @returns A Result containing the branded DicomFilePath or an error\n */\nfunction createDicomFilePath(input: string): Result<DicomFilePath> {\n if (input.length === 0) {\n return err(new Error('Invalid DICOM file path: empty string'));\n }\n if (PATH_TRAVERSAL_PATTERN.test(input)) {\n return err(new Error(`Invalid DICOM file path: path traversal detected in \"${input}\"`));\n }\n // normalize() resolves `.` segments and trailing separators, ensuring\n // consistent path comparison regardless of input style (e.g., `a//b` → `a/b`).\n const normalized = normalize(input);\n return ok(normalized as DicomFilePath);\n}\n\n/**\n * Creates a validated Port from a raw number.\n *\n * @param input - A number expected to be an integer between 1 and 65535\n * @returns A Result containing the branded Port or an error\n */\nfunction createPort(input: number): Result<Port> {\n if (!Number.isInteger(input) || input < PORT_MIN || input > PORT_MAX) {\n return err(new Error(`Invalid port: ${String(input)}. Must be an integer between ${PORT_MIN} and ${PORT_MAX}`));\n }\n return ok(input as Port);\n}\n\n/**\n * Shorthand for creating a DicomTagPath, throwing on invalid input.\n *\n * Use this when you know the tag path is valid (e.g. hardcoded constants).\n * For user-supplied input, use {@link createDicomTagPath} which returns a Result.\n *\n * @param input - A DICOM tag path string, e.g. `'(0010,0010)'`\n * @returns The branded DicomTagPath\n * @throws Error if the input is not a valid DICOM tag path\n */\nfunction tag(input: string): DicomTagPath {\n const result = createDicomTagPath(input);\n if (!result.ok) throw result.error;\n return result.value;\n}\n\nexport { createDicomTag, createAETitle, createDicomTagPath, createSOPClassUID, createTransferSyntaxUID, createDicomFilePath, createPort, tag };\nexport type { Brand, DicomTag, AETitle, DicomTagPath, SOPClassUID, TransferSyntaxUID, DicomFilePath, Port };\n","/**\n * DICOM tag path parser and serializer.\n *\n * Provides iterative (no recursion) parsing of DICOM tag paths like\n * `(0040,A730)[0].(0040,A160)` into structured segments, and conversion\n * back to dcmodify-compatible strings.\n *\n * Supports wildcard indices `[*]` for use with DicomDataset.findValues.\n *\n * @module dicom/tagPath\n */\n\nimport type { DicomTag, DicomTagPath } from '../brands';\nimport { createDicomTag } from '../brands';\nimport { MAX_TRAVERSAL_DEPTH } from '../constants';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** A single segment of a parsed DICOM tag path. */\ninterface TagSegment {\n /** The DICOM tag for this segment. */\n readonly tag: DicomTag;\n /** The array index for sequence items, or undefined for non-sequence tags. */\n readonly index?: number | undefined;\n /** Whether this segment uses a wildcard index `[*]`. */\n readonly isWildcard?: boolean | undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Patterns\n// ---------------------------------------------------------------------------\n\n// Matches a tag segment: (XXXX,XXXX) optionally followed by [N] or [*]\nconst SEGMENT_PATTERN = /^\\(([0-9A-Fa-f]{4}),([0-9A-Fa-f]{4})\\)(?:\\[(\\d+|\\*)\\])?/;\n\n// ---------------------------------------------------------------------------\n// Internal helpers (extracted for complexity/line limits)\n// ---------------------------------------------------------------------------\n\n/** Parses a single regex match into a TagSegment. */\nfunction matchToSegment(match: RegExpExecArray): TagSegment {\n const group = match[1];\n const element = match[2];\n const indexStr = match[3];\n\n /* v8 ignore next 3 */\n if (group === undefined || element === undefined) {\n throw new Error('Failed to parse tag group/element');\n }\n\n const tagResult = createDicomTag(`(${group},${element})`);\n /* v8 ignore next 2 */\n if (!tagResult.ok) throw new Error(`Invalid tag in path: (${group},${element})`);\n\n if (indexStr === '*') return { tag: tagResult.value, isWildcard: true };\n if (indexStr !== undefined) return { tag: tagResult.value, index: Number(indexStr) };\n return { tag: tagResult.value };\n}\n\n/** Advances past the current match and any dot separator. Returns the updated remaining string. */\nfunction advancePastMatch(remaining: string, matchLength: number): string {\n const after = remaining.slice(matchLength);\n if (!after.startsWith('.')) return after;\n if (after.length === 1) throw new Error('Tag path cannot end with a dot separator');\n return after.slice(1);\n}\n\n// ---------------------------------------------------------------------------\n// Parser\n// ---------------------------------------------------------------------------\n\n/**\n * Parses a DICOM tag path into an array of segments.\n *\n * Uses iterative parsing with bounded loop (Rule 8.2: no recursion).\n *\n * @param path - A branded DicomTagPath string\n * @returns An array of TagSegment objects\n * @throws Error if the path is malformed or exceeds MAX_TRAVERSAL_DEPTH\n *\n * @example\n * ```ts\n * tagPathToSegments('(0040,A730)[0].(0040,A160)' as DicomTagPath)\n * // => [\n * // { tag: '(0040,A730)' as DicomTag, index: 0 },\n * // { tag: '(0040,A160)' as DicomTag }\n * // ]\n * ```\n */\nfunction tagPathToSegments(path: DicomTagPath): ReadonlyArray<TagSegment> {\n const segments: TagSegment[] = [];\n let remaining: string = path;\n\n for (let i = 0; i < MAX_TRAVERSAL_DEPTH && remaining.length > 0; i++) {\n const match = SEGMENT_PATTERN.exec(remaining);\n if (match === null) {\n throw new Error(`Invalid tag path segment at position ${path.length - remaining.length}: \"${remaining}\"`);\n }\n segments.push(matchToSegment(match));\n remaining = advancePastMatch(remaining, match[0].length);\n }\n\n if (remaining.length > 0) throw new Error(`Tag path exceeds maximum depth of ${MAX_TRAVERSAL_DEPTH}`);\n if (segments.length === 0) throw new Error('Tag path is empty');\n return segments;\n}\n\n// ---------------------------------------------------------------------------\n// Serializers\n// ---------------------------------------------------------------------------\n\n/**\n * Converts tag segments back to a dcmodify-compatible path string.\n *\n * Format: `(0040,A730)[0].(0040,A160)`\n *\n * @param segments - An array of TagSegment objects\n * @returns A dcmodify-compatible path string\n */\nfunction segmentsToModifyPath(segments: ReadonlyArray<TagSegment>): string {\n const parts: string[] = [];\n for (const seg of segments) {\n let part: string = seg.tag;\n if (seg.isWildcard === true) {\n part += '[*]';\n } else if (seg.index !== undefined) {\n part += `[${seg.index}]`;\n }\n parts.push(part);\n }\n return parts.join('.');\n}\n\n/**\n * Converts tag segments to a canonical display string.\n *\n * Same format as dcmodify path: `(0040,A730)[0].(0040,A160)`\n *\n * @param segments - An array of TagSegment objects\n * @returns A human-readable path string\n */\nfunction segmentsToString(segments: ReadonlyArray<TagSegment>): string {\n return segmentsToModifyPath(segments);\n}\n\nexport { tagPathToSegments, segmentsToModifyPath, segmentsToString };\nexport type { TagSegment };\n","/**\n * Immutable mutation tracking for DICOM datasets.\n *\n * Every mutation method returns a new ChangeSet instance, preserving immutability.\n * Bridge methods produce dcmodify-compatible arguments for applying changes to files.\n *\n * @module dicom/ChangeSet\n */\n\nimport type { TagModification } from '../tools/dcmodify';\nimport { MAX_CHANGESET_OPERATIONS } from '../constants';\nimport type { DicomTagPath } from '../brands';\nimport { tagPathToSegments } from './tagPath';\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/** Sentinel value in the erasures set to indicate erasing all private tags. */\nconst ERASE_PRIVATE_SENTINEL = '__ERASE_PRIVATE__';\n\n// ---------------------------------------------------------------------------\n// Helpers (extracted for complexity/line limits)\n// ---------------------------------------------------------------------------\n\n/**\n * Returns true if a char code is a control character to strip.\n * Strips 0x00-0x09, 0x0B, 0x0C, 0x0E-0x1F, 0x7F.\n * Preserves LF (0x0A), CR (0x0D), and backslash.\n */\nfunction isControlChar(code: number): boolean {\n if (code <= 0x09) return true;\n if (code === 0x0b || code === 0x0c) return true;\n if (code >= 0x0e && code <= 0x1f) return true;\n return code === 0x7f;\n}\n\n/** Strips control characters from a value while preserving LF, CR, and backslash. */\nfunction sanitizeValue(value: string): string {\n let result = '';\n for (let i = 0; i < value.length; i++) {\n const code = value.charCodeAt(i);\n if (!isControlChar(code)) {\n result += value[i];\n }\n }\n return result;\n}\n\n/** Merges two modification maps, with `other` winning conflicts. Removes keys present in erasures. */\nfunction buildMergedModifications(\n base: ReadonlyMap<string, string>,\n other: ReadonlyMap<string, string>,\n erasures: ReadonlySet<string>\n): ReadonlyMap<string, string> {\n const merged = new Map<string, string>(base);\n for (const [key, value] of other) {\n merged.set(key, value);\n }\n for (const key of erasures) {\n merged.delete(key);\n }\n return merged;\n}\n\n/** Iteratively applies all entries to a ChangeSet, returning the final result. */\nfunction applyBatchEntries(initial: ChangeSet, entries: Readonly<Record<string, string>>): ChangeSet {\n const keys = Object.keys(entries);\n let cs = initial;\n for (let i = 0; i < keys.length; i++) {\n const key = keys[i];\n /* v8 ignore next */\n if (key === undefined) continue;\n const value = entries[key];\n /* v8 ignore next */\n if (value === undefined) continue;\n cs = cs.setTag(key, value);\n }\n return cs;\n}\n\n// ---------------------------------------------------------------------------\n// ChangeSet class\n// ---------------------------------------------------------------------------\n\n/**\n * Immutable mutation tracker for DICOM datasets.\n *\n * Every mutation method returns a **new** ChangeSet — the original is never modified.\n * Use {@link ChangeSet.toModifications} and {@link ChangeSet.toErasureArgs} to bridge\n * to the dcmodify tool wrapper.\n *\n * @example\n * ```ts\n * const cs = ChangeSet.empty()\n * .setTag('(0010,0010)' as DicomTagPath, 'Anonymous')\n * .eraseTag('(0010,0020)' as DicomTagPath)\n * .erasePrivateTags();\n * ```\n */\nclass ChangeSet {\n private readonly mods: ReadonlyMap<string, string>;\n private readonly erased: ReadonlySet<string>;\n\n private constructor(mods: ReadonlyMap<string, string>, erasures: ReadonlySet<string>) {\n this.mods = mods;\n this.erased = erasures;\n }\n\n /** Creates an empty ChangeSet with no modifications or erasures. */\n static empty(): ChangeSet {\n return new ChangeSet(new Map(), new Set());\n }\n\n /**\n * Sets a tag value, returning a new ChangeSet.\n *\n * Control characters (except LF/CR) are stripped from the value.\n * If the tag was previously erased, it is removed from the erasure set.\n *\n * @param path - The DICOM tag path to set (e.g. `'(0010,0010)'`)\n * @param value - The new value for the tag\n * @returns A new ChangeSet with the modification applied\n * @throws Error if operation count would exceed MAX_CHANGESET_OPERATIONS\n */\n setTag(path: string, value: string): ChangeSet {\n const totalOps = this.mods.size + this.erased.size;\n if (totalOps >= MAX_CHANGESET_OPERATIONS) {\n throw new Error(`ChangeSet operation limit (${MAX_CHANGESET_OPERATIONS}) exceeded`);\n }\n tagPathToSegments(path as DicomTagPath);\n const sanitized = sanitizeValue(value);\n const newMods = new Map(this.mods);\n newMods.set(path, sanitized);\n const newErasures = new Set(this.erased);\n newErasures.delete(path);\n return new ChangeSet(newMods, newErasures);\n }\n\n /**\n * Marks a tag for erasure, returning a new ChangeSet.\n *\n * If the tag was previously set, the modification is removed.\n *\n * @param path - The DICOM tag path to erase (e.g. `'(0010,0010)'`)\n * @returns A new ChangeSet with the erasure applied\n * @throws Error if operation count would exceed MAX_CHANGESET_OPERATIONS\n */\n eraseTag(path: string): ChangeSet {\n const totalOps = this.mods.size + this.erased.size;\n if (totalOps >= MAX_CHANGESET_OPERATIONS) {\n throw new Error(`ChangeSet operation limit (${MAX_CHANGESET_OPERATIONS}) exceeded`);\n }\n tagPathToSegments(path as DicomTagPath);\n const newMods = new Map(this.mods);\n newMods.delete(path);\n const newErasures = new Set(this.erased);\n newErasures.add(path);\n return new ChangeSet(newMods, newErasures);\n }\n\n /**\n * Marks all private tags for erasure, returning a new ChangeSet.\n *\n * @returns A new ChangeSet with the erase-private flag set\n * @throws Error if operation count would exceed MAX_CHANGESET_OPERATIONS\n */\n erasePrivateTags(): ChangeSet {\n const totalOps = this.mods.size + this.erased.size;\n if (totalOps >= MAX_CHANGESET_OPERATIONS) {\n throw new Error(`ChangeSet operation limit (${MAX_CHANGESET_OPERATIONS}) exceeded`);\n }\n const newErasures = new Set(this.erased);\n newErasures.add(ERASE_PRIVATE_SENTINEL);\n return new ChangeSet(new Map(this.mods), newErasures);\n }\n\n // -----------------------------------------------------------------------\n // Convenience setters for common DICOM tags\n // -----------------------------------------------------------------------\n\n /** Sets Patient's Name (0010,0010). */\n setPatientName(value: string): ChangeSet {\n return this.setTag('(0010,0010)', value);\n }\n\n /** Sets Patient ID (0010,0020). */\n setPatientID(value: string): ChangeSet {\n return this.setTag('(0010,0020)', value);\n }\n\n /** Sets Study Date (0008,0020). */\n setStudyDate(value: string): ChangeSet {\n return this.setTag('(0008,0020)', value);\n }\n\n /** Sets Modality (0008,0060). */\n setModality(value: string): ChangeSet {\n return this.setTag('(0008,0060)', value);\n }\n\n /** Sets Accession Number (0008,0050). */\n setAccessionNumber(value: string): ChangeSet {\n return this.setTag('(0008,0050)', value);\n }\n\n /** Sets Study Description (0008,1030). */\n setStudyDescription(value: string): ChangeSet {\n return this.setTag('(0008,1030)', value);\n }\n\n /** Sets Series Description (0008,103E). */\n setSeriesDescription(value: string): ChangeSet {\n return this.setTag('(0008,103E)', value);\n }\n\n /** Sets Institution Name (0008,0080). */\n setInstitutionName(value: string): ChangeSet {\n return this.setTag('(0008,0080)', value);\n }\n\n /**\n * Sets multiple tags at once, returning a new ChangeSet.\n *\n * @param entries - A record of tag path → value pairs\n * @returns A new ChangeSet with all modifications applied\n */\n setBatch(entries: Readonly<Record<string, string>>): ChangeSet {\n return applyBatchEntries(this, entries);\n }\n\n /** All pending tag modifications as a readonly map of path → value. */\n get modifications(): ReadonlyMap<string, string> {\n return this.mods;\n }\n\n /** All pending tag erasures as a readonly set of paths. */\n get erasures(): ReadonlySet<string> {\n return this.erased;\n }\n\n /** Total number of operations (modifications + erasures) in this ChangeSet. */\n get operationCount(): number {\n return this.mods.size + this.erased.size;\n }\n\n /** Whether the ChangeSet has no modifications and no erasures. */\n get isEmpty(): boolean {\n return this.mods.size === 0 && this.erased.size === 0;\n }\n\n /** Whether the erase-all-private-tags flag is set. */\n get erasePrivate(): boolean {\n return this.erased.has(ERASE_PRIVATE_SENTINEL);\n }\n\n /**\n * Merges another ChangeSet into this one, returning a new ChangeSet.\n *\n * The `other` ChangeSet wins on conflicts: if the same tag is modified in both,\n * `other`'s value is used. Erasures from both sets are unioned. An erasure in\n * `other` removes a modification from `base`.\n *\n * @param other - The ChangeSet to merge in\n * @returns A new ChangeSet with merged modifications and erasures\n */\n merge(other: ChangeSet): ChangeSet {\n const mergedErasures = new Set([...this.erased, ...other.erased]);\n const mergedMods = buildMergedModifications(this.mods, other.mods, mergedErasures);\n return new ChangeSet(mergedMods, mergedErasures);\n }\n\n /**\n * Converts modifications to dcmodify-compatible TagModification array.\n *\n * @returns A readonly array of TagModification objects\n */\n toModifications(): ReadonlyArray<TagModification> {\n const result: TagModification[] = [];\n for (const [tag, value] of this.mods) {\n result.push({ tag, value });\n }\n return result;\n }\n\n /**\n * Converts erasures to dcmodify-compatible argument strings.\n *\n * The erase-private sentinel is excluded — use {@link erasePrivate} to check\n * whether `-ep` should be passed.\n *\n * @returns A readonly array of tag path strings for `-e` arguments\n */\n toErasureArgs(): ReadonlyArray<string> {\n const result: string[] = [];\n for (const path of this.erased) {\n if (path !== ERASE_PRIVATE_SENTINEL) {\n result.push(path);\n }\n }\n return result;\n }\n}\n\nexport { ChangeSet };\n","/**\n * Immutable DICOM dataset wrapper with type-safe accessors.\n *\n * Wraps DICOM JSON Model data (PS3.18 F.2) from dcm2json/dcm2xml with\n * convenient read-only accessors. No setters — mutations go through ChangeSet.\n *\n * @module dicom/DicomDataset\n */\n\nimport { stderr } from 'stderr-lib';\nimport type { DicomTag, DicomTagPath, SOPClassUID } from '../brands';\nimport { createSOPClassUID } from '../brands';\nimport { MAX_TRAVERSAL_DEPTH } from '../constants';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport type { TagSegment } from './tagPath';\nimport { tagPathToSegments } from './tagPath';\nimport type { DicomJsonElement, DicomJsonModel } from '../tools/_xmlToJson';\n\n// ---------------------------------------------------------------------------\n// Structural validation\n// ---------------------------------------------------------------------------\n\nconst HEX_TAG_KEY = /^[0-9A-Fa-f]{8}$/;\n\n/**\n * Returns true if the value looks like a DicomJsonElement (has a string `vr` property).\n * This is a lightweight structural check, not a full VR validation.\n */\nfunction isDicomJsonElement(value: unknown): value is DicomJsonElement {\n return typeof value === 'object' && value !== null && 'vr' in value && typeof (value as Record<string, unknown>)['vr'] === 'string';\n}\n\n/**\n * Returns true if the object looks like a DicomJsonModel.\n * Every key must be an 8-char hex string and every value must have { vr: string }.\n */\nfunction isValidDicomJsonModel(obj: Record<string, unknown>): boolean {\n const keys = Object.keys(obj);\n for (let i = 0; i < keys.length; i++) {\n const key = keys[i];\n /* v8 ignore next */\n if (key === undefined) continue;\n if (!HEX_TAG_KEY.test(key)) return false;\n if (!isDicomJsonElement(obj[key])) return false;\n }\n return true;\n}\n\n// ---------------------------------------------------------------------------\n// Tag normalization\n// ---------------------------------------------------------------------------\n\nconst TAG_WITH_PARENS = /^\\(([0-9A-Fa-f]{4}),([0-9A-Fa-f]{4})\\)$/;\nconst TAG_HEX_ONLY = /^[0-9A-Fa-f]{8}$/;\n\n/**\n * Normalizes a DICOM tag to 8-char uppercase hex.\n * Accepts `(0010,0010)` or `00100010` formats.\n */\nfunction normalizeTag(tag: DicomTag | string): Result<string> {\n const parenMatch = TAG_WITH_PARENS.exec(tag);\n if (parenMatch !== null) {\n const group = parenMatch[1];\n const element = parenMatch[2];\n /* v8 ignore next */\n if (group === undefined || element === undefined) return err(new Error(`Invalid tag: \"${tag}\"`));\n return ok(`${group}${element}`.toUpperCase());\n }\n if (TAG_HEX_ONLY.test(tag)) {\n return ok(tag.toUpperCase());\n }\n return err(new Error(`Invalid tag format: \"${tag}\". Expected (XXXX,XXXX) or XXXXXXXX`));\n}\n\n// ---------------------------------------------------------------------------\n// Element extraction helpers\n// ---------------------------------------------------------------------------\n\n/** Resolves an element from the data by normalized tag key. */\nfunction resolveElement(data: DicomJsonModel, tagKey: string): DicomJsonElement | undefined {\n return data[tagKey];\n}\n\n/**\n * Extracts the Alphabetic component from a PN (PersonName) value.\n * Returns empty string if the Alphabetic component is missing or the\n * value is not a valid PN object — consistent with DICOM PS3.5 which\n * treats missing components as empty strings.\n */\nfunction extractPNAlphabetic(first: unknown): string {\n if (typeof first !== 'object' || first === null) return '';\n const pn = first as Record<string, unknown>;\n const alphabetic = pn['Alphabetic'];\n return typeof alphabetic === 'string' ? alphabetic : '';\n}\n\n/** Converts a primitive value to string. */\nfunction primitiveToString(value: unknown): string {\n if (typeof value === 'string') return value;\n if (typeof value === 'number' || typeof value === 'boolean') return String(value);\n return '';\n}\n\n/** Extracts a string from a DicomJsonElement, handling PN values. */\nfunction extractString(element: DicomJsonElement): string {\n const values = element.Value;\n if (values === undefined || values.length === 0) return '';\n\n const first = values[0];\n if (first === undefined || first === null) return '';\n\n if (element.vr === 'PN') return extractPNAlphabetic(first);\n return primitiveToString(first);\n}\n\n/** Extracts a number from a DicomJsonElement with validation. */\nfunction extractNumber(element: DicomJsonElement): Result<number> {\n const values = element.Value;\n if (values === undefined || values.length === 0) {\n return err(new Error('Element has no Value array'));\n }\n const first = values[0];\n if (typeof first === 'number') return ok(first);\n if (typeof first === 'string') {\n const parsed = Number(first);\n if (Number.isNaN(parsed)) {\n return err(new Error(`Cannot convert \"${first}\" to number`));\n }\n return ok(parsed);\n }\n return err(new Error(`Value is not numeric: ${typeof first}`));\n}\n\n/** Extracts all values as strings from a DicomJsonElement. */\nfunction extractStrings(element: DicomJsonElement): ReadonlyArray<string> {\n const values = element.Value;\n if (values === undefined) return [];\n const result: string[] = [];\n for (const v of values) {\n if (typeof v === 'string') {\n result.push(v);\n } else if (typeof v === 'number' || typeof v === 'boolean') {\n result.push(String(v));\n } else {\n result.push('');\n }\n }\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Path traversal helpers (iterative, no recursion — Rule 8.2)\n// ---------------------------------------------------------------------------\n\n/** Gets the sequence items array from a DicomJsonElement. */\nfunction getSequenceItems(element: DicomJsonElement): ReadonlyArray<unknown> | undefined {\n if (element.vr !== 'SQ' || element.Value === undefined) return undefined;\n return element.Value;\n}\n\n/** Returns true if the value is a plausible DicomJsonModel (non-null object with no array). */\nfunction isPlausibleModel(value: unknown): value is DicomJsonModel {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/** Descends into a sequence item, returning the nested dataset or an error. */\nfunction descendIntoSequence(element: DicomJsonElement, seg: TagSegment): Result<DicomJsonModel> {\n const items = getSequenceItems(element);\n if (items === undefined) {\n return err(new Error(`Tag ${seg.tag} is not a sequence`));\n }\n const idx = seg.index ?? 0;\n const item = items[idx];\n if (!isPlausibleModel(item)) {\n return err(new Error(`Sequence ${seg.tag} has no valid item at index ${idx}`));\n }\n return ok(item);\n}\n\n/** Traverses a non-wildcard path iteratively through nested sequences. */\nfunction traversePath(data: DicomJsonModel, segments: ReadonlyArray<TagSegment>): Result<DicomJsonElement> {\n let current: DicomJsonModel = data;\n\n for (let i = 0; i < segments.length; i++) {\n const seg = segments[i];\n /* v8 ignore next */\n if (seg === undefined) return err(new Error('Unexpected undefined segment'));\n\n const tagResult = normalizeTag(seg.tag);\n if (!tagResult.ok) return err(tagResult.error);\n\n const element = resolveElement(current, tagResult.value);\n if (element === undefined) return err(new Error(`Tag ${seg.tag} not found`));\n\n if (i === segments.length - 1) return ok(element);\n\n const descent = descendIntoSequence(element, seg);\n if (!descent.ok) return err(descent.error);\n current = descent.value;\n }\n\n /* v8 ignore next */\n return err(new Error('Empty path segments'));\n}\n\n// ---------------------------------------------------------------------------\n// Wildcard collection (iterative queue — Rule 8.2)\n// ---------------------------------------------------------------------------\n\ninterface QueueEntry {\n readonly data: DicomJsonModel;\n readonly segmentIndex: number;\n}\n\ninterface WildcardResult {\n readonly values: ReadonlyArray<unknown>;\n readonly truncated: boolean;\n}\n\n/** Collects all values matching a wildcard path using an iterative BFS queue. */\nfunction collectWildcard(data: DicomJsonModel, segments: ReadonlyArray<TagSegment>): WildcardResult {\n const results: unknown[] = [];\n const queue: QueueEntry[] = [{ data, segmentIndex: 0 }];\n const maxIterations = MAX_TRAVERSAL_DEPTH * 100;\n\n let iteration = 0;\n for (; iteration < maxIterations && queue.length > 0; iteration++) {\n const entry = queue.shift();\n /* v8 ignore next */\n if (entry === undefined) break;\n processQueueEntry(entry, segments, results, queue);\n }\n\n return { values: results, truncated: iteration >= maxIterations && queue.length > 0 };\n}\n\n/** Processes a single queue entry for wildcard collection. */\nfunction processQueueEntry(entry: QueueEntry, segments: ReadonlyArray<TagSegment>, results: unknown[], queue: QueueEntry[]): void {\n const seg = segments[entry.segmentIndex];\n /* v8 ignore next */\n if (seg === undefined) return;\n\n const tagResult = normalizeTag(seg.tag);\n if (!tagResult.ok) return;\n\n const element = resolveElement(entry.data, tagResult.value);\n if (element === undefined) return;\n\n const isLast = entry.segmentIndex === segments.length - 1;\n\n if (isLast) {\n collectLeafValues(element, results);\n return;\n }\n\n enqueueSequenceItems(element, seg, entry.segmentIndex, queue);\n}\n\n/** Collects values from a leaf element into the results array. */\nfunction collectLeafValues(element: DicomJsonElement, results: unknown[]): void {\n if (element.Value !== undefined) {\n for (const v of element.Value) {\n results.push(v);\n }\n }\n}\n\n/** Enqueues child sequence items for further wildcard processing. */\nfunction enqueueSequenceItems(element: DicomJsonElement, seg: TagSegment, segmentIndex: number, queue: QueueEntry[]): void {\n const items = getSequenceItems(element);\n if (items === undefined) return;\n\n if (seg.isWildcard === true) {\n for (const item of items) {\n if (isPlausibleModel(item)) {\n queue.push({ data: item, segmentIndex: segmentIndex + 1 });\n }\n }\n } else {\n const idx = seg.index ?? 0;\n const item = items[idx];\n if (isPlausibleModel(item)) {\n queue.push({ data: item, segmentIndex: segmentIndex + 1 });\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Well-known DICOM tag keys (8-char hex, uppercase)\n// ---------------------------------------------------------------------------\n\nconst TAGS = {\n AccessionNumber: '00080050',\n PatientName: '00100010',\n PatientID: '00100020',\n StudyDate: '00080020',\n Modality: '00080060',\n SOPClassUID: '00080016',\n StudyInstanceUID: '0020000D',\n SeriesInstanceUID: '0020000E',\n SOPInstanceUID: '00080018',\n TransferSyntaxUID: '00020010',\n} as const;\n\n// ---------------------------------------------------------------------------\n// DicomDataset class\n// ---------------------------------------------------------------------------\n\n/**\n * Immutable wrapper around DICOM JSON Model data.\n *\n * Provides type-safe read-only accessors for DICOM tag values.\n * Construct via the static {@link DicomDataset.fromJson} factory.\n *\n * @example\n * ```ts\n * const result = DicomDataset.fromJson(jsonData);\n * if (result.ok) {\n * const ds = result.value;\n * console.log(ds.patientName);\n * console.log(ds.modality);\n * }\n * ```\n */\nclass DicomDataset {\n private readonly data: DicomJsonModel;\n\n private constructor(data: DicomJsonModel) {\n this.data = data;\n }\n\n /**\n * Creates a DicomDataset from a DICOM JSON Model object.\n *\n * Performs structural validation only — verifies the input is a non-null object.\n *\n * @param json - A DICOM JSON Model object (typically from dcm2json)\n * @returns A Result containing the DicomDataset or an error\n */\n static fromJson(json: unknown): Result<DicomDataset> {\n if (json === null || json === undefined || typeof json !== 'object' || Array.isArray(json)) {\n return err(new Error('Invalid DICOM JSON: expected a non-null, non-array object'));\n }\n const obj = json as Record<string, unknown>;\n if (!isValidDicomJsonModel(obj)) {\n return err(new Error('Invalid DICOM JSON: every key must be an 8-char hex tag and every value must have a \"vr\" string property'));\n }\n return ok(new DicomDataset(json as DicomJsonModel));\n }\n\n /**\n * Gets the full DICOM JSON element for a tag.\n *\n * @param tag - A DicomTag `(0010,0010)` or hex string `00100010`\n * @returns Result containing the element or an error if not found\n */\n getElement(tag: DicomTag | string): Result<DicomJsonElement> {\n const norm = normalizeTag(tag);\n if (!norm.ok) return err(norm.error);\n const element = resolveElement(this.data, norm.value);\n if (element === undefined) return err(new Error(`Tag ${tag} not found`));\n return ok(element);\n }\n\n /**\n * Gets the Value array for a tag.\n *\n * @param tag - A DicomTag `(0010,0010)` or hex string `00100010`\n * @returns Result containing the readonly Value array or an error\n */\n getValue(tag: DicomTag | string): Result<ReadonlyArray<unknown>> {\n const elemResult = this.getElement(tag);\n if (!elemResult.ok) return err(elemResult.error);\n const values = elemResult.value.Value;\n if (values === undefined) return err(new Error(`Tag ${tag} has no Value`));\n return ok(values);\n }\n\n /**\n * Gets the first element of the Value array for a tag.\n *\n * @param tag - A DicomTag `(0010,0010)` or hex string `00100010`\n * @returns Result containing the first value or an error\n */\n getFirstValue(tag: DicomTag | string): Result<unknown> {\n const valResult = this.getValue(tag);\n if (!valResult.ok) return err(valResult.error);\n const first = valResult.value[0];\n if (first === undefined) return err(new Error(`Tag ${tag} Value array is empty`));\n return ok(first);\n }\n\n /**\n * Gets a tag value as a string with optional fallback.\n *\n * Returns the fallback (default empty string) if the tag is missing or has no value.\n * Handles PN (PersonName) values by extracting the Alphabetic component.\n *\n * @param tag - A DicomTag `(0010,0010)` or hex string `00100010`\n * @param fallback - Value to return if tag is missing (default: `''`)\n * @returns The string value or the fallback\n */\n getString(tag: DicomTag | string, fallback = ''): string {\n const elemResult = this.getElement(tag);\n if (!elemResult.ok) return fallback;\n const str = extractString(elemResult.value);\n return str.length > 0 ? str : fallback;\n }\n\n /**\n * Gets a tag value as a validated number.\n *\n * @param tag - A DicomTag `(0010,0010)` or hex string `00100010`\n * @returns Result containing the number or an error\n */\n getNumber(tag: DicomTag | string): Result<number> {\n const elemResult = this.getElement(tag);\n if (!elemResult.ok) return err(elemResult.error);\n return extractNumber(elemResult.value);\n }\n\n /**\n * Gets all values of a tag as strings.\n *\n * Useful for multi-valued tags like CS (Code String).\n *\n * @param tag - A DicomTag `(0010,0010)` or hex string `00100010`\n * @returns Result containing the readonly string array or an error\n */\n getStrings(tag: DicomTag | string): Result<ReadonlyArray<string>> {\n const elemResult = this.getElement(tag);\n if (!elemResult.ok) return err(elemResult.error);\n return ok(extractStrings(elemResult.value));\n }\n\n /**\n * Checks whether a tag exists in the dataset.\n *\n * @param tag - A DicomTag `(0010,0010)` or hex string `00100010`\n * @returns `true` if the tag is present\n */\n hasTag(tag: DicomTag | string): boolean {\n const norm = normalizeTag(tag);\n if (!norm.ok) return false;\n return resolveElement(this.data, norm.value) !== undefined;\n }\n\n /**\n * Gets an element by traversing a dotted tag path through sequences.\n *\n * @param path - A branded DicomTagPath, e.g. `(0040,A730)[0].(0040,A160)`\n * @returns Result containing the element at the path or an error\n */\n getElementAtPath(path: DicomTagPath): Result<DicomJsonElement> {\n let segments: ReadonlyArray<TagSegment>;\n try {\n segments = tagPathToSegments(path);\n } catch (e: unknown) {\n return err(stderr(e));\n }\n return traversePath(this.data, segments);\n }\n\n /**\n * Finds all values matching a path with wildcard `[*]` indices.\n *\n * Traverses all items in wildcard sequence positions using an iterative BFS queue.\n * The traversal is bounded to {@link MAX_TRAVERSAL_DEPTH} * 100 iterations (5 000).\n * For extremely large datasets this may truncate results silently; callers\n * needing completeness guarantees should verify dataset size independently.\n *\n * @param path - A branded DicomTagPath, e.g. `(0040,A730)[*].(0040,A160)`\n * @returns A readonly array of all matching values (may be empty)\n */\n findValues(path: DicomTagPath): ReadonlyArray<unknown> {\n let segments: ReadonlyArray<TagSegment>;\n try {\n segments = tagPathToSegments(path);\n } catch {\n return [];\n }\n const result = collectWildcard(this.data, segments);\n return result.values;\n }\n\n // -----------------------------------------------------------------------\n // Convenience readonly getters\n // -----------------------------------------------------------------------\n\n /** Accession Number (0008,0050). */\n get accession(): string {\n return this.getString(TAGS.AccessionNumber);\n }\n\n /** Patient's Name (0010,0010). */\n get patientName(): string {\n return this.getString(TAGS.PatientName);\n }\n\n /** Patient ID (0010,0020). */\n get patientID(): string {\n return this.getString(TAGS.PatientID);\n }\n\n /** Study Date (0008,0020). */\n get studyDate(): string {\n return this.getString(TAGS.StudyDate);\n }\n\n /** Modality (0008,0060). */\n get modality(): string {\n return this.getString(TAGS.Modality);\n }\n\n /** SOP Class UID (0008,0016) as a branded SOPClassUID, or undefined if missing/invalid. */\n get sopClassUID(): SOPClassUID | undefined {\n const uid = this.getString(TAGS.SOPClassUID);\n if (uid.length === 0) return undefined;\n const result = createSOPClassUID(uid);\n return result.ok ? result.value : undefined;\n }\n\n /** Study Instance UID (0020,000D). */\n get studyInstanceUID(): string {\n return this.getString(TAGS.StudyInstanceUID);\n }\n\n /** Series Instance UID (0020,000E). */\n get seriesInstanceUID(): string {\n return this.getString(TAGS.SeriesInstanceUID);\n }\n\n /** SOP Instance UID (0008,0018). */\n get sopInstanceUID(): string {\n return this.getString(TAGS.SOPInstanceUID);\n }\n\n /** Transfer Syntax UID (0002,0010). */\n get transferSyntaxUID(): string {\n return this.getString(TAGS.TransferSyntaxUID);\n }\n}\n\nexport { DicomDataset };\n","/**\n * Short-lived DCMTK process execution.\n *\n * Two execution modes:\n * - `execCommand()` — convenience wrapper; uses `spawn()` internally for safety\n * - `spawnCommand()` — uses `child_process.spawn()`, safer for user-supplied values (Rule 7.4)\n *\n * Both enforce mandatory timeouts (Rule 4.2) and return `Result<DcmtkProcessResult>`.\n *\n * @module exec\n */\n\nimport { spawn } from 'node:child_process';\nimport type { ChildProcess } from 'node:child_process';\nimport kill from 'tree-kill';\nimport type { Result, DcmtkProcessResult, ExecOptions, SpawnOptions } from './types';\nimport { ok, err } from './types';\nimport { DEFAULT_TIMEOUT_MS, MAX_OUTPUT_BYTES } from './constants';\n\n/**\n * Kills a process tree by PID. Wraps tree-kill in a promise.\n *\n * @param pid - The process ID to kill\n */\nfunction killTree(pid: number): void {\n try {\n kill(pid);\n /* v8 ignore next */\n } catch {\n // Process may already be dead — not exceptional\n }\n}\n\n/**\n * Executes a DCMTK binary as a short-lived process.\n *\n * **Security:** This function uses `child_process.spawn()` internally, passing\n * arguments as an array to avoid shell interpretation. This eliminates shell\n * injection risks regardless of argument content (Rule 7.4).\n *\n * @param binary - Full path to the DCMTK binary\n * @param args - Command-line arguments (passed directly, no shell interpolation)\n * @param options - Execution options (timeout, cwd, signal)\n * @returns A Result containing the process output or an error\n * @throws Never throws for expected failures (Rule 6.1)\n *\n * @example\n * ```ts\n * const result = await execCommand('/usr/local/bin/dcm2json', ['+ll', 'input.dcm']);\n * if (result.ok) {\n * console.log(result.value.stdout);\n * }\n * ```\n */\nasync function execCommand(binary: string, args: readonly string[], options?: ExecOptions): Promise<Result<DcmtkProcessResult>> {\n const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\n return new Promise(resolve => {\n const child = spawn(binary, [...args], {\n cwd: options?.cwd,\n windowsHide: true,\n signal: options?.signal,\n });\n wireSpawnListeners(child, timeoutMs, resolve);\n });\n}\n\n/**\n * Wires event listeners on a spawned child process with timeout, bounded buffering, and settle logic.\n */\nfunction wireSpawnListeners(child: ChildProcess, timeoutMs: number, resolve: (result: Result<DcmtkProcessResult>) => void): void {\n let stdout = '';\n let stderr = '';\n let settled = false;\n\n const settle = (result: Result<DcmtkProcessResult>): void => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n resolve(result);\n };\n\n const timer = setTimeout(() => {\n if (child.pid !== undefined && child.pid !== null) killTree(child.pid);\n settle(err(new Error(`Process timed out after ${timeoutMs}ms`)));\n }, timeoutMs);\n\n child.stdout?.on('data', (chunk: Buffer | string) => {\n stdout += String(chunk);\n if (stdout.length + stderr.length > MAX_OUTPUT_BYTES) {\n if (child.pid !== undefined && child.pid !== null) killTree(child.pid);\n settle(err(new Error(`Process output exceeded ${MAX_OUTPUT_BYTES} bytes`)));\n }\n });\n\n child.stderr?.on('data', (chunk: Buffer | string) => {\n stderr += String(chunk);\n if (stdout.length + stderr.length > MAX_OUTPUT_BYTES) {\n if (child.pid !== undefined && child.pid !== null) killTree(child.pid);\n settle(err(new Error(`Process output exceeded ${MAX_OUTPUT_BYTES} bytes`)));\n }\n });\n\n child.on('error', (error: Error) => {\n if (child.pid !== undefined && child.pid !== null) killTree(child.pid);\n settle(err(new Error(`Process error: ${error.message}`)));\n });\n\n child.on('close', (code: number | null) => {\n settle(ok({ stdout, stderr, exitCode: code ?? 1 }));\n });\n}\n\n/**\n * Executes a DCMTK binary using `child_process.spawn()`.\n *\n * Like {@link execCommand}, arguments are passed as an array to avoid shell\n * injection (Rule 7.4). This variant additionally supports custom environment\n * variables via the `env` option.\n *\n * @param binary - Full path to the DCMTK binary\n * @param args - Command-line arguments (passed directly, no shell interpolation)\n * @param options - Execution options (timeout, cwd, signal, env)\n * @returns A Result containing the process output or an error\n * @throws Never throws for expected failures (Rule 6.1)\n *\n * @example\n * ```ts\n * const result = await spawnCommand('/usr/local/bin/dcmodify', ['-m', '(0010,0010)=Smith^John', 'input.dcm']);\n * ```\n */\nasync function spawnCommand(binary: string, args: readonly string[], options?: SpawnOptions): Promise<Result<DcmtkProcessResult>> {\n const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\n return new Promise(resolve => {\n const child = spawn(binary, [...args], {\n cwd: options?.cwd,\n env: options?.env ? { ...process.env, ...options.env } : undefined,\n windowsHide: true,\n signal: options?.signal,\n });\n wireSpawnListeners(child, timeoutMs, resolve);\n });\n}\n\nexport { execCommand, spawnCommand };\n","/**\n * Converts dcm2xml \"Native DICOM Model\" XML into the DICOM JSON Model (PS3.18 F.2).\n *\n * dcm2xml outputs XML in the DCMTK native format:\n * ```xml\n * <NativeDicomModel>\n * <DicomAttribute tag=\"00100010\" vr=\"PN\" keyword=\"PatientName\">\n * <PersonName number=\"1\">\n * <Alphabetic><FamilyName>Smith</FamilyName></Alphabetic>\n * </PersonName>\n * </DicomAttribute>\n * <DicomAttribute tag=\"00100020\" vr=\"LO\" keyword=\"PatientID\">\n * <Value number=\"1\">12345</Value>\n * </DicomAttribute>\n * </NativeDicomModel>\n * ```\n *\n * The DICOM JSON Model output:\n * ```json\n * {\n * \"00100010\": { \"vr\": \"PN\", \"Value\": [{\"Alphabetic\": \"Smith\"}] },\n * \"00100020\": { \"vr\": \"LO\", \"Value\": [\"12345\"] }\n * }\n * ```\n *\n * @module _xmlToJson\n * @internal\n */\n\nimport { XMLParser } from 'fast-xml-parser';\nimport { stderr } from 'stderr-lib';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\n\n/** DICOM JSON Model element. */\ninterface DicomJsonElement {\n readonly vr: string;\n readonly Value?: ReadonlyArray<unknown>;\n readonly InlineBinary?: string;\n readonly BulkDataURI?: string;\n}\n\n/** Mutable builder for DicomJsonElement during conversion. */\ninterface ElementBuilder {\n vr: string;\n Value?: unknown[];\n InlineBinary?: string;\n BulkDataURI?: string;\n}\n\n/** DICOM JSON Model top-level object. */\ntype DicomJsonModel = Record<string, DicomJsonElement>;\n\n/** Parsed XML attribute node from fast-xml-parser. */\ninterface XmlDicomAttribute {\n readonly '@_tag': string;\n readonly '@_vr': string;\n readonly '@_keyword'?: string;\n readonly Value?: unknown;\n readonly PersonName?: unknown;\n readonly InlineBinary?: unknown;\n readonly BulkDataURI?: unknown;\n readonly Item?: unknown;\n}\n\n/** Person name components from XML. */\ninterface XmlPersonNameComponent {\n readonly FamilyName?: string;\n readonly GivenName?: string;\n readonly MiddleName?: string;\n readonly NamePrefix?: string;\n readonly NameSuffix?: string;\n}\n\n/** PN representation types. */\ntype PnRepType = 'Alphabetic' | 'Ideographic' | 'Phonetic';\nconst PN_REPS: readonly PnRepType[] = ['Alphabetic', 'Ideographic', 'Phonetic'];\n\nconst ARRAY_TAG_NAMES = new Set(['DicomAttribute', 'Value', 'PersonName', 'Item']);\n\n/**\n * The 34 standard DICOM VR codes (PS3.5 Table 6.2-1).\n * Used to validate VR values from DCMTK XML output. Unrecognized VRs\n * (e.g. retired/internal codes like \"xs\", \"ox\") fall back to 'UN'.\n */\nconst KNOWN_VR_CODES = new Set([\n 'AE',\n 'AS',\n 'AT',\n 'CS',\n 'DA',\n 'DS',\n 'DT',\n 'FD',\n 'FL',\n 'IS',\n 'LO',\n 'LT',\n 'OB',\n 'OD',\n 'OF',\n 'OL',\n 'OV',\n 'OW',\n 'PN',\n 'SH',\n 'SL',\n 'SQ',\n 'SS',\n 'ST',\n 'SV',\n 'TM',\n 'UC',\n 'UI',\n 'UL',\n 'UN',\n 'UR',\n 'US',\n 'UT',\n 'UV',\n]);\n\n/**\n * Builds a PN string from name components.\n */\nfunction buildPnString(comp: XmlPersonNameComponent): string {\n const parts = [comp.FamilyName ?? '', comp.GivenName ?? '', comp.MiddleName ?? '', comp.NamePrefix ?? '', comp.NameSuffix ?? ''];\n let last = parts.length - 1;\n for (; last >= 0; last--) {\n if (parts[last] !== '') break;\n }\n return parts.slice(0, last + 1).join('^');\n}\n\n/** Ensures a value is an array. */\nfunction toArray(val: unknown): readonly unknown[] {\n if (Array.isArray(val)) return val;\n if (val === undefined || val === null) return [];\n return [val];\n}\n\n/**\n * Converts a PersonName XML element to DICOM JSON PN format.\n */\nfunction convertPersonName(pnNode: unknown): Record<string, string> {\n const result: Record<string, string> = {};\n /* v8 ignore next -- defensive guard for malformed XML */\n if (typeof pnNode !== 'object' || pnNode === null) return result;\n const pn = pnNode as Record<string, unknown>;\n\n for (const rep of PN_REPS) {\n const repNode = pn[rep];\n if (repNode !== undefined && typeof repNode === 'object' && repNode !== null) {\n const str = buildPnString(repNode as XmlPersonNameComponent);\n if (str.length > 0) {\n result[rep] = str;\n }\n }\n }\n return result;\n}\n\n/** Safely converts an unknown value to a string without risking [object Object]. */\nfunction safeString(val: unknown): string {\n if (typeof val === 'string') return val;\n if (typeof val === 'number' || typeof val === 'boolean') return String(val);\n /* v8 ignore next */\n return '';\n}\n\n/** Handles InlineBinary elements. */\nfunction convertInlineBinary(attr: XmlDicomAttribute, element: ElementBuilder): void {\n element.InlineBinary = safeString(attr.InlineBinary);\n}\n\n/** Handles BulkDataURI elements. */\nfunction convertBulkDataURI(attr: XmlDicomAttribute, element: ElementBuilder): void {\n const bulkArray = toArray(attr.BulkDataURI);\n const firstBulk = bulkArray[0];\n if (typeof firstBulk === 'object' && firstBulk !== null && '@_uri' in firstBulk) {\n element.BulkDataURI = safeString((firstBulk as Record<string, unknown>)['@_uri']);\n } else {\n element.BulkDataURI = safeString(firstBulk);\n }\n}\n\n/** Handles PersonName (PN VR) elements. */\nfunction convertPNValue(attr: XmlDicomAttribute, element: ElementBuilder): void {\n const pnArray = toArray(attr.PersonName);\n const values: Record<string, string>[] = [];\n for (const pn of pnArray) {\n values.push(convertPersonName(pn));\n }\n if (values.length > 0) element.Value = values;\n}\n\n/** Handles Sequence (SQ) elements. */\nfunction convertSequence(attr: XmlDicomAttribute, element: ElementBuilder): void {\n const items = toArray(attr.Item);\n const values: DicomJsonModel[] = [];\n for (const item of items) {\n /* v8 ignore next -- defensive guard for malformed XML */\n if (typeof item !== 'object' || item === null) continue;\n values.push(convertAttributes(item as Record<string, unknown>));\n }\n if (values.length > 0) element.Value = values;\n}\n\n/** Handles regular Value elements. */\nfunction convertRegularValue(attr: XmlDicomAttribute, element: ElementBuilder): void {\n const valArray = toArray(attr.Value);\n const values: unknown[] = [];\n for (const v of valArray) {\n if (typeof v === 'object' && v !== null && '#text' in v) {\n values.push((v as Record<string, unknown>)['#text']);\n } else {\n values.push(v);\n }\n }\n if (values.length > 0) element.Value = values;\n}\n\n/**\n * Converts a single DicomAttribute XML element to its DICOM JSON element.\n */\nfunction convertElement(attr: XmlDicomAttribute): DicomJsonElement {\n const rawVr = attr['@_vr'];\n const vr = KNOWN_VR_CODES.has(rawVr) ? rawVr : 'UN';\n const element: ElementBuilder = { vr };\n\n if (attr.InlineBinary !== undefined) {\n convertInlineBinary(attr, element);\n } else if (attr.BulkDataURI !== undefined) {\n convertBulkDataURI(attr, element);\n } else if (element.vr === 'PN' && attr.PersonName !== undefined) {\n convertPNValue(attr, element);\n } else if (element.vr === 'SQ' && attr.Item !== undefined) {\n convertSequence(attr, element);\n } else if (attr.Value !== undefined) {\n convertRegularValue(attr, element);\n }\n\n return Object.freeze(element) as DicomJsonElement;\n}\n\n/**\n * Converts an object containing DicomAttribute children into a DICOM JSON Model object.\n */\nfunction convertAttributes(obj: Record<string, unknown>): DicomJsonModel {\n const result: Record<string, DicomJsonElement> = {};\n const attrs = toArray(obj['DicomAttribute']);\n\n for (const attr of attrs) {\n if (typeof attr !== 'object' || attr === null) continue;\n const xmlAttr = attr as XmlDicomAttribute;\n const tag = xmlAttr['@_tag'];\n if (tag === undefined) continue;\n result[tag] = convertElement(xmlAttr);\n }\n\n return result;\n}\n\n/** XML parser configured for the DCMTK Native DICOM Model. */\nconst parser = new XMLParser({\n ignoreAttributes: false,\n attributeNamePrefix: '@_',\n parseTagValue: false,\n isArray: (name: string): boolean => ARRAY_TAG_NAMES.has(name),\n});\n\n/**\n * Converts dcm2xml XML output to DICOM JSON Model.\n *\n * @param xml - The XML string from dcm2xml\n * @returns A Result containing the DICOM JSON Model or an error\n */\nfunction xmlToJson(xml: string): Result<DicomJsonModel> {\n try {\n const parsed = parser.parse(xml) as Record<string, unknown>;\n const root = parsed['NativeDicomModel'];\n if (root === undefined) {\n return err(new Error('Invalid dcm2xml output: missing NativeDicomModel root element'));\n }\n // Empty NativeDicomModel produces an empty string from the parser\n if (typeof root !== 'object' || root === null) {\n return ok({});\n }\n return ok(convertAttributes(root as Record<string, unknown>));\n } catch (error: unknown) {\n return err(new Error(`Failed to parse dcm2xml XML: ${stderr(error).message}`));\n }\n}\n\nexport { xmlToJson };\nexport type { DicomJsonModel, DicomJsonElement };\n","/**\n * Repairs malformed JSON output from the dcm2json binary.\n *\n * DCMTK's dcm2json sometimes emits invalid JSON for numeric-string VRs\n * (DS, IS) by producing unquoted numbers in arrays:\n * ```json\n * \"Value\": [1.5, 2.0] // invalid — DS values must be strings\n * \"Value\": [\"1.5\", \"2.0\"] // valid\n * ```\n *\n * This module detects and repairs these patterns before JSON.parse.\n *\n * @module _repairJson\n * @internal\n */\n\n/**\n * Pattern matching \"Value\" arrays in DICOM JSON.\n * Captures: (prefix including `[`)(inner content)(closing `]`).\n */\nconst VALUE_ARRAY_PATTERN = /(\"Value\"\\s*:\\s*\\[)([\\s\\S]*?)(\\])/g;\n\n/**\n * Matches a bare (unquoted) numeric literal.\n * Handles integers, decimals, scientific notation, and negative values.\n */\nconst BARE_NUMBER = /^-?(?:\\d+\\.?\\d*|\\.\\d+)(?:[eE][+-]?\\d+)?$/;\n\n/**\n * Quotes a bare number token, leaving already-quoted strings unchanged.\n *\n * @param token - A trimmed token from inside a Value array\n * @returns The token, quoted if it was a bare number\n */\nfunction quoteIfBareNumber(token: string): string {\n const trimmed = token.trim();\n if (BARE_NUMBER.test(trimmed)) {\n return `\"${trimmed}\"`;\n }\n return trimmed;\n}\n\n/**\n * Repairs the inner content of a \"Value\" array by quoting bare numbers.\n *\n * @param inner - The content between `[` and `]`\n * @returns Repaired content with bare numbers quoted\n */\nfunction repairInner(inner: string): string {\n const trimmed = inner.trim();\n if (trimmed.length === 0) return inner;\n\n // Split on commas that are not inside quotes\n const tokens: string[] = [];\n let current = '';\n let inString = false;\n\n for (let i = 0; i < trimmed.length; i++) {\n const ch = trimmed[i]!;\n if (ch === '\"' && (i === 0 || trimmed[i - 1] !== '\\\\')) {\n inString = !inString;\n current += ch;\n } else if (ch === ',' && !inString) {\n tokens.push(current);\n current = '';\n } else {\n current += ch;\n }\n }\n tokens.push(current);\n\n return tokens.map(quoteIfBareNumber).join(', ');\n}\n\n/**\n * Repairs malformed dcm2json output by quoting unquoted numeric values in \"Value\" arrays.\n *\n * @param raw - The raw JSON string from dcm2json\n * @returns The repaired JSON string safe for JSON.parse\n */\nfunction repairJson(raw: string): string {\n return raw.replace(VALUE_ARRAY_PATTERN, (_match, prefix: string, inner: string, suffix: string) => {\n return `${prefix}${repairInner(inner)}${suffix}`;\n });\n}\n\nexport { repairJson };\n","/**\n * DICOM to JSON conversion using a two-phase strategy.\n *\n * Primary: dcm2xml → xmlToJson (more reliable output)\n * Fallback: dcm2json binary → repairJson → JSON.parse\n *\n * The result includes a `source` discriminant indicating which strategy succeeded.\n *\n * @module dcm2json\n */\n\nimport { stderr } from 'stderr-lib';\nimport { z } from 'zod';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { execCommand } from '../exec';\nimport { DEFAULT_TIMEOUT_MS } from '../constants';\nimport { resolveBinary } from './_resolveBinary';\nimport { createToolError, createValidationError } from './_toolError';\nimport { xmlToJson } from './_xmlToJson';\nimport { repairJson } from './_repairJson';\nimport type { DicomJsonModel } from './_xmlToJson';\nimport type { ToolBaseOptions } from './_toolTypes';\n\n/** Indicates which conversion strategy produced the result. */\ntype Dcm2jsonSource = 'xml' | 'direct';\n\n/** Options for {@link dcm2json}. */\ninterface Dcm2jsonOptions extends ToolBaseOptions {\n /** Skip the XML primary path and use direct dcm2json only. Defaults to false. */\n readonly directOnly?: boolean | undefined;\n}\n\n/** Result of a successful dcm2json conversion. */\ninterface Dcm2jsonResult {\n /** The DICOM JSON Model object. */\n readonly data: DicomJsonModel;\n /** Which conversion strategy produced this result. */\n readonly source: Dcm2jsonSource;\n}\n\nconst Dcm2jsonOptionsSchema = z\n .object({\n timeoutMs: z.number().int().positive().optional(),\n signal: z.instanceof(AbortSignal).optional(),\n directOnly: z.boolean().optional(),\n })\n .strict()\n .optional();\n\n/**\n * Attempts XML-primary conversion: dcm2xml → xmlToJson.\n */\nasync function tryXmlPath(inputPath: string, timeoutMs: number, signal?: AbortSignal): Promise<Result<Dcm2jsonResult>> {\n const xmlBinary = resolveBinary('dcm2xml');\n if (!xmlBinary.ok) {\n return err(xmlBinary.error);\n }\n\n const xmlResult = await execCommand(xmlBinary.value, ['-nat', inputPath], { timeoutMs, signal });\n if (!xmlResult.ok) {\n return err(xmlResult.error);\n }\n\n if (xmlResult.value.exitCode !== 0) {\n return err(createToolError('dcm2xml', ['-nat', inputPath], xmlResult.value.exitCode, xmlResult.value.stderr));\n }\n\n const jsonResult = xmlToJson(xmlResult.value.stdout);\n if (!jsonResult.ok) {\n return err(jsonResult.error);\n }\n\n return ok({ data: jsonResult.value, source: 'xml' as const });\n}\n\n/**\n * Attempts direct conversion: dcm2json binary → repairJson → JSON.parse.\n */\nasync function tryDirectPath(inputPath: string, timeoutMs: number, signal?: AbortSignal): Promise<Result<Dcm2jsonResult>> {\n const jsonBinary = resolveBinary('dcm2json');\n if (!jsonBinary.ok) {\n return err(jsonBinary.error);\n }\n\n const result = await execCommand(jsonBinary.value, [inputPath], { timeoutMs, signal });\n if (!result.ok) {\n return err(result.error);\n }\n\n if (result.value.exitCode !== 0) {\n return err(createToolError('dcm2json', [inputPath], result.value.exitCode, result.value.stderr));\n }\n\n try {\n const repaired = repairJson(result.value.stdout);\n // Cast is safe: repairJson ensures valid DICOM JSON Model structure,\n // and JSON.parse returns `unknown` in strict TS (we narrow via caller checks).\n const data = JSON.parse(repaired) as DicomJsonModel;\n return ok({ data, source: 'direct' as const });\n } catch (parseError: unknown) {\n return err(createToolError('dcm2json', [inputPath], 1, `Parse error: ${stderr(parseError).message}`));\n }\n}\n\n/**\n * Converts a DICOM file to the DICOM JSON Model.\n *\n * Uses a two-phase strategy:\n * 1. Primary: dcm2xml → XML-to-JSON conversion (more reliable)\n * 2. Fallback: direct dcm2json binary with JSON repair\n *\n * @param inputPath - Path to the DICOM input file\n * @param options - Conversion options\n * @returns A Result containing the DICOM JSON Model with source discriminant\n *\n * @example\n * ```ts\n * const result = await dcm2json('/path/to/study.dcm');\n * if (result.ok) {\n * console.log(result.value.source); // 'xml' or 'direct'\n * console.log(result.value.data['00100010']); // Patient Name\n * }\n * ```\n */\nasync function dcm2json(inputPath: string, options?: Dcm2jsonOptions): Promise<Result<Dcm2jsonResult>> {\n const validation = Dcm2jsonOptionsSchema.safeParse(options);\n if (!validation.success) {\n return err(createValidationError('dcm2json', validation.error));\n }\n\n const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const signal = options?.signal;\n\n // Direct-only mode: skip XML path\n if (options?.directOnly === true) {\n return tryDirectPath(inputPath, timeoutMs, signal);\n }\n\n // Try XML path first\n const xmlResult = await tryXmlPath(inputPath, timeoutMs, signal);\n if (xmlResult.ok) {\n return xmlResult;\n }\n\n // Fall back to direct path\n return tryDirectPath(inputPath, timeoutMs, signal);\n}\n\nexport { dcm2json };\nexport type { Dcm2jsonOptions, Dcm2jsonResult, Dcm2jsonSource, DicomJsonModel };\n","/**\n * Modify DICOM tags using the dcmodify binary.\n *\n * Uses spawnCommand instead of execCommand because user-supplied DICOM values\n * could contain shell metacharacters. Spawn passes args as an array with no\n * shell interpolation (Rule 7.4).\n *\n * @module dcmodify\n */\n\nimport { z } from 'zod';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { spawnCommand } from '../exec';\nimport { DEFAULT_TIMEOUT_MS } from '../constants';\nimport { resolveBinary } from './_resolveBinary';\nimport { createToolError, createValidationError } from './_toolError';\nimport type { ToolBaseOptions } from './_toolTypes';\n\n/** A single tag modification. */\ninterface TagModification {\n /** DICOM tag to modify, e.g. \"(0010,0010)\". */\n readonly tag: string;\n /** New value for the tag. */\n readonly value: string;\n}\n\n/** Options for {@link dcmodify}. */\ninterface DcmodifyOptions extends ToolBaseOptions {\n /** Tag modifications to apply. */\n readonly modifications?: readonly TagModification[] | undefined;\n /** Tag paths to erase (passed as `-e path`). */\n readonly erasures?: readonly string[] | undefined;\n /** Erase all private tags (uses `-ep` flag). */\n readonly erasePrivateTags?: boolean | undefined;\n /** Do not create backup (.bak) file. Defaults to true. */\n readonly noBackup?: boolean | undefined;\n /** Insert tag if it doesn't exist (uses -i flag). Defaults to false. */\n readonly insertIfMissing?: boolean | undefined;\n /** Treat 'tag not found' as success when erasing (uses -imt flag). Defaults to false. */\n readonly ignoreMissingTags?: boolean | undefined;\n}\n\n/** Result of a successful dcmodify operation. */\ninterface DcmodifyResult {\n /** Path to the modified DICOM file. */\n readonly filePath: string;\n}\n\n/** Matches a single tag or a dotted tag path: (XXXX,XXXX) or (XXXX,XXXX)[N].(XXXX,XXXX) */\nconst TAG_OR_PATH_PATTERN = /^\\([0-9A-Fa-f]{4},[0-9A-Fa-f]{4}\\)(\\[\\d+\\](\\.\\([0-9A-Fa-f]{4},[0-9A-Fa-f]{4}\\)(\\[\\d+\\])?)*)?$/;\n\nconst TagModificationSchema = z.object({\n tag: z.string().regex(TAG_OR_PATH_PATTERN),\n value: z.string(),\n});\n\nconst DcmodifyOptionsSchema = z\n .object({\n timeoutMs: z.number().int().positive().optional(),\n signal: z.instanceof(AbortSignal).optional(),\n modifications: z.array(TagModificationSchema).optional().default([]),\n erasures: z.array(z.string()).optional(),\n erasePrivateTags: z.boolean().optional(),\n noBackup: z.boolean().optional(),\n insertIfMissing: z.boolean().optional(),\n ignoreMissingTags: z.boolean().optional(),\n })\n .strict()\n .refine(data => data.modifications.length > 0 || (data.erasures !== undefined && data.erasures.length > 0) || data.erasePrivateTags === true, {\n message: 'At least one of modifications, erasures, or erasePrivateTags is required',\n });\n\n/**\n * Builds dcmodify command-line arguments from validated options.\n */\nfunction buildArgs(inputPath: string, options: DcmodifyOptions): string[] {\n const args: string[] = [];\n\n if (options.noBackup !== false) {\n args.push('-nb');\n }\n\n if (options.ignoreMissingTags === true) {\n args.push('-imt');\n }\n\n const flag = options.insertIfMissing === true ? '-i' : '-m';\n const modifications = options.modifications ?? [];\n\n for (const mod of modifications) {\n args.push(flag, `${mod.tag}=${mod.value}`);\n }\n\n if (options.erasures !== undefined) {\n for (const erasure of options.erasures) {\n args.push('-e', erasure);\n }\n }\n\n if (options.erasePrivateTags === true) {\n args.push('-ep');\n }\n\n args.push(inputPath);\n\n return args;\n}\n\n/**\n * Modifies DICOM tags in a file using the dcmodify binary.\n *\n * Uses spawn (not exec) for safety with user-supplied values.\n *\n * @param inputPath - Path to the DICOM file to modify (modified in-place)\n * @param options - Modification options\n * @returns A Result containing the file path or an error\n *\n * @example\n * ```ts\n * const result = await dcmodify('/path/to/study.dcm', {\n * modifications: [\n * { tag: '(0010,0010)', value: 'Anonymous' },\n * { tag: '(0010,0020)', value: 'ANON001' },\n * ],\n * });\n * ```\n */\nasync function dcmodify(inputPath: string, options: DcmodifyOptions): Promise<Result<DcmodifyResult>> {\n const validation = DcmodifyOptionsSchema.safeParse(options);\n if (!validation.success) {\n return err(createValidationError('dcmodify', validation.error));\n }\n\n const binaryResult = resolveBinary('dcmodify');\n if (!binaryResult.ok) {\n return err(binaryResult.error);\n }\n\n const args = buildArgs(inputPath, options);\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\n const result = await spawnCommand(binaryResult.value, args, {\n timeoutMs,\n signal: options.signal,\n });\n\n if (!result.ok) {\n return err(result.error);\n }\n\n if (result.value.exitCode !== 0) {\n return err(createToolError('dcmodify', args, result.value.exitCode, result.value.stderr));\n }\n\n return ok({ filePath: inputPath });\n}\n\nexport { dcmodify };\nexport type { DcmodifyOptions, DcmodifyResult, TagModification };\n","/**\n * File operation helpers for DicomInstance.\n *\n * Extracted to keep DicomInstance methods under line-count limits.\n *\n * @module dicom/_fileHelpers\n */\n\nimport { copyFile, stat, unlink } from 'node:fs/promises';\nimport { tryCatch } from 'stderr-lib';\nimport type { DicomFilePath } from '../brands';\nimport { DEFAULT_TIMEOUT_MS } from '../constants';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport type { ChangeSet } from './ChangeSet';\nimport { dcmodify } from '../tools/dcmodify';\n\n/** Options for file I/O operations. */\ninterface FileIOOptions {\n /** Timeout in milliseconds. Defaults to DEFAULT_TIMEOUT_MS. */\n readonly timeoutMs?: number | undefined;\n /** AbortSignal for external cancellation. */\n readonly signal?: AbortSignal | undefined;\n}\n\n/** Bridges a ChangeSet to a dcmodify call on the given file. */\nasync function applyModifications(filePath: DicomFilePath, changeset: ChangeSet, options: FileIOOptions): Promise<Result<void>> {\n const modifications = changeset.toModifications();\n const erasures = changeset.toErasureArgs();\n\n const hasErasures = erasures.length > 0 || changeset.erasePrivate;\n\n const result = await dcmodify(filePath, {\n modifications: modifications.length > 0 ? modifications : undefined,\n erasures: erasures.length > 0 ? erasures : undefined,\n erasePrivateTags: changeset.erasePrivate || undefined,\n insertIfMissing: true,\n ignoreMissingTags: hasErasures || undefined,\n timeoutMs: options.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n signal: options.signal,\n });\n\n if (!result.ok) return err(result.error);\n return ok(undefined);\n}\n\n/** Wraps fs.copyFile in a Result. */\nasync function copyFileSafe(source: string, dest: string): Promise<Result<void>> {\n return tryCatch(\n () => copyFile(source, dest),\n e => new Error(`Failed to copy file: ${e.message}`)\n );\n}\n\n/** Wraps fs.stat in a Result, returning file size. */\nasync function statFileSize(path: string): Promise<Result<number>> {\n return tryCatch(\n async () => (await stat(path)).size,\n e => new Error(`Failed to stat file: ${e.message}`)\n );\n}\n\n/** Wraps fs.unlink in a Result. */\nasync function unlinkFile(path: string): Promise<Result<void>> {\n return tryCatch(\n () => unlink(path),\n e => new Error(`Failed to delete file: ${e.message}`)\n );\n}\n\nexport { applyModifications, copyFileSafe, statFileSize, unlinkFile };\nexport type { FileIOOptions };\n","/**\n * Unified DICOM object composing DicomDataset + ChangeSet + file I/O.\n *\n * Every setter returns a new DicomInstance — the original is never modified.\n * Designed for ergonomic DICOM workflows that combine reading, modifying,\n * and writing DICOM data in a single fluent API.\n *\n * @module dicom/DicomInstance\n */\n\nimport type { DicomFilePath, DicomTag, DicomTagPath, SOPClassUID } from '../brands';\nimport { createDicomFilePath } from '../brands';\nimport { DEFAULT_TIMEOUT_MS } from '../constants';\nimport type { Result } from '../types';\nimport { err, ok } from '../types';\nimport { ChangeSet } from './ChangeSet';\nimport { DicomDataset } from './DicomDataset';\nimport { dcm2json } from '../tools';\nimport type { FileIOOptions } from './_fileHelpers';\nimport { applyModifications, copyFileSafe, statFileSize, unlinkFile } from './_fileHelpers';\n\n// ---------------------------------------------------------------------------\n// DicomInstance class\n// ---------------------------------------------------------------------------\n\n/**\n * Unified DICOM object composing dataset, change tracking, file path, and metadata.\n *\n * Every setter returns a new immutable instance — the original is never modified.\n * Use the static factories {@link DicomInstance.open} or {@link DicomInstance.fromDataset}\n * to create instances.\n *\n * @example\n * ```ts\n * const result = await DicomInstance.open('/path/to/file.dcm');\n * if (!result.ok) { console.error(result.error.message); return; }\n * const modified = result.value\n * .setPatientName('DOE^JOHN')\n * .setPatientID('PAT001')\n * .erasePrivateTags();\n * await modified.writeAs('/path/to/output.dcm');\n * ```\n */\nclass DicomInstance {\n private readonly dicomDataset: DicomDataset;\n private readonly changeSet: ChangeSet;\n private readonly filepath: DicomFilePath | undefined;\n private readonly meta: ReadonlyMap<string, unknown>;\n\n private constructor(dataset: DicomDataset, changes: ChangeSet, filePath: DicomFilePath | undefined, metadata: ReadonlyMap<string, unknown>) {\n this.dicomDataset = dataset;\n this.changeSet = changes;\n this.filepath = filePath;\n this.meta = metadata;\n }\n\n // -----------------------------------------------------------------------\n // Factories\n // -----------------------------------------------------------------------\n\n /**\n * Opens a DICOM file and creates a DicomInstance.\n *\n * @param path - Filesystem path to the DICOM file\n * @param options - Timeout and abort options\n * @returns A Result containing the DicomInstance or an error\n */\n static async open(path: string, options?: FileIOOptions): Promise<Result<DicomInstance>> {\n const filePathResult = createDicomFilePath(path);\n if (!filePathResult.ok) return err(filePathResult.error);\n\n const jsonResult = await dcm2json(path, {\n timeoutMs: options?.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n signal: options?.signal,\n });\n if (!jsonResult.ok) return err(jsonResult.error);\n\n const datasetResult = DicomDataset.fromJson(jsonResult.value.data);\n if (!datasetResult.ok) return err(datasetResult.error);\n\n return ok(new DicomInstance(datasetResult.value, ChangeSet.empty(), filePathResult.value, new Map()));\n }\n\n /**\n * Creates a DicomInstance from an existing DicomDataset.\n *\n * @param dataset - The DicomDataset to wrap\n * @param filePath - Optional file path (e.g. if the dataset came from a file)\n * @returns A Result containing the DicomInstance\n */\n static fromDataset(dataset: DicomDataset, filePath?: string): Result<DicomInstance> {\n let fp: DicomFilePath | undefined;\n if (filePath !== undefined) {\n const fpResult = createDicomFilePath(filePath);\n if (!fpResult.ok) return err(fpResult.error);\n fp = fpResult.value;\n }\n return ok(new DicomInstance(dataset, ChangeSet.empty(), fp, new Map()));\n }\n\n // -----------------------------------------------------------------------\n // Read accessors (delegate to DicomDataset)\n // -----------------------------------------------------------------------\n\n /** The underlying immutable DICOM dataset. */\n get dataset(): DicomDataset {\n return this.dicomDataset;\n }\n\n /** The pending change set. */\n get changes(): ChangeSet {\n return this.changeSet;\n }\n\n /** Whether there are unsaved changes. */\n get hasUnsavedChanges(): boolean {\n return !this.changeSet.isEmpty;\n }\n\n /** The file path, or undefined if this instance has no associated file. */\n get filePath(): string | undefined {\n return this.filepath;\n }\n\n /** Patient's Name (0010,0010). */\n get patientName(): string {\n return this.dicomDataset.patientName;\n }\n\n /** Patient ID (0010,0020). */\n get patientID(): string {\n return this.dicomDataset.patientID;\n }\n\n /** Study Date (0008,0020). */\n get studyDate(): string {\n return this.dicomDataset.studyDate;\n }\n\n /** Modality (0008,0060). */\n get modality(): string {\n return this.dicomDataset.modality;\n }\n\n /** Accession Number (0008,0050). */\n get accession(): string {\n return this.dicomDataset.accession;\n }\n\n /** SOP Class UID (0008,0016). */\n get sopClassUID(): SOPClassUID | undefined {\n return this.dicomDataset.sopClassUID;\n }\n\n /** Study Instance UID (0020,000D). */\n get studyInstanceUID(): string {\n return this.dicomDataset.studyInstanceUID;\n }\n\n /** Series Instance UID (0020,000E). */\n get seriesInstanceUID(): string {\n return this.dicomDataset.seriesInstanceUID;\n }\n\n /** SOP Instance UID (0008,0018). */\n get sopInstanceUID(): string {\n return this.dicomDataset.sopInstanceUID;\n }\n\n /** Transfer Syntax UID (0002,0010). */\n get transferSyntaxUID(): string {\n return this.dicomDataset.transferSyntaxUID;\n }\n\n /**\n * Gets a tag value as a string with optional fallback.\n *\n * @param tag - A DICOM tag, e.g. `'(0010,0010)'` or `'00100010'`\n * @param fallback - Value to return if tag is missing (default: `''`)\n */\n getString(tag: DicomTag | string, fallback = ''): string {\n return this.dicomDataset.getString(tag, fallback);\n }\n\n /**\n * Gets a tag value as a number.\n *\n * @param tag - A DICOM tag, e.g. `'(0020,0013)'`\n */\n getNumber(tag: DicomTag | string): Result<number> {\n return this.dicomDataset.getNumber(tag);\n }\n\n /** Checks whether a tag exists in the dataset. */\n hasTag(tag: DicomTag | string): boolean {\n return this.dicomDataset.hasTag(tag);\n }\n\n /**\n * Finds all values matching a wildcard path.\n *\n * @param path - A DicomTagPath with optional wildcard indices\n */\n findValues(path: DicomTagPath): ReadonlyArray<unknown> {\n return this.dicomDataset.findValues(path);\n }\n\n // -----------------------------------------------------------------------\n // Write methods (return new instance)\n // -----------------------------------------------------------------------\n\n /**\n * Sets a tag value, returning a new DicomInstance.\n *\n * @param path - The DICOM tag path (e.g. `'(0010,0010)'`)\n * @param value - The new value\n */\n setTag(path: string, value: string): DicomInstance {\n return new DicomInstance(this.dicomDataset, this.changeSet.setTag(path, value), this.filepath, this.meta);\n }\n\n /**\n * Erases a tag, returning a new DicomInstance.\n *\n * @param path - The DICOM tag path to erase\n */\n eraseTag(path: string): DicomInstance {\n return new DicomInstance(this.dicomDataset, this.changeSet.eraseTag(path), this.filepath, this.meta);\n }\n\n /** Erases all private tags, returning a new DicomInstance. */\n erasePrivateTags(): DicomInstance {\n return new DicomInstance(this.dicomDataset, this.changeSet.erasePrivateTags(), this.filepath, this.meta);\n }\n\n /** Sets Patient's Name (0010,0010). */\n setPatientName(value: string): DicomInstance {\n return this.setTag('(0010,0010)', value);\n }\n\n /** Sets Patient ID (0010,0020). */\n setPatientID(value: string): DicomInstance {\n return this.setTag('(0010,0020)', value);\n }\n\n /** Sets Study Date (0008,0020). */\n setStudyDate(value: string): DicomInstance {\n return this.setTag('(0008,0020)', value);\n }\n\n /** Sets Modality (0008,0060). */\n setModality(value: string): DicomInstance {\n return this.setTag('(0008,0060)', value);\n }\n\n /** Sets Accession Number (0008,0050). */\n setAccessionNumber(value: string): DicomInstance {\n return this.setTag('(0008,0050)', value);\n }\n\n /** Sets Study Description (0008,1030). */\n setStudyDescription(value: string): DicomInstance {\n return this.setTag('(0008,1030)', value);\n }\n\n /** Sets Series Description (0008,103E). */\n setSeriesDescription(value: string): DicomInstance {\n return this.setTag('(0008,103E)', value);\n }\n\n /** Sets Institution Name (0008,0080). */\n setInstitutionName(value: string): DicomInstance {\n return this.setTag('(0008,0080)', value);\n }\n\n /**\n * Transforms a tag value using a function.\n *\n * The function receives the current string value (or undefined if tag is missing)\n * and returns the new value. Returns a new DicomInstance with the modification.\n *\n * @param path - The DICOM tag path\n * @param fn - Transform function receiving the current value\n */\n transformTag(path: string, fn: (current: string | undefined) => string): DicomInstance {\n const current = this.dicomDataset.getString(path);\n const newValue = fn(current.length > 0 ? current : undefined);\n return this.setTag(path, newValue);\n }\n\n /**\n * Sets multiple tags at once, returning a new DicomInstance.\n *\n * @param entries - A record of tag path → value pairs\n */\n setBatch(entries: Readonly<Record<string, string>>): DicomInstance {\n return new DicomInstance(this.dicomDataset, this.changeSet.setBatch(entries), this.filepath, this.meta);\n }\n\n /**\n * Returns a new DicomInstance with the given changes merged into pending changes.\n *\n * @param changes - A ChangeSet to merge with existing pending changes\n * @returns A new DicomInstance with accumulated changes\n */\n withChanges(changes: ChangeSet): DicomInstance {\n return new DicomInstance(this.dicomDataset, this.changeSet.merge(changes), this.filepath, this.meta);\n }\n\n /**\n * Returns a new DicomInstance pointing to a different file path.\n *\n * Preserves the dataset, pending changes, and metadata.\n *\n * @param newPath - The new filesystem path (validated via createDicomFilePath)\n * @returns A new DicomInstance with the updated path\n * @throws If the path is invalid\n */\n withFilePath(newPath: string): DicomInstance {\n const result = createDicomFilePath(newPath);\n if (!result.ok) throw result.error;\n return new DicomInstance(this.dicomDataset, this.changeSet, result.value, this.meta);\n }\n\n // -----------------------------------------------------------------------\n // File I/O\n // -----------------------------------------------------------------------\n\n /**\n * Applies pending changes to the file in-place.\n *\n * Requires that the instance has an associated file path.\n *\n * @param options - Timeout and abort options\n */\n async applyChanges(options?: FileIOOptions): Promise<Result<void>> {\n if (this.filepath === undefined) return err(new Error('No file path associated with this instance'));\n if (this.changeSet.isEmpty) return ok(undefined);\n return applyModifications(this.filepath, this.changeSet, options ?? {});\n }\n\n /**\n * Copies the file to a new path and applies pending changes to the copy.\n *\n * Returns a new DicomInstance pointing to the output path.\n *\n * @param outputPath - Destination filesystem path\n * @param options - Timeout and abort options\n */\n async writeAs(outputPath: string, options?: FileIOOptions): Promise<Result<DicomInstance>> {\n if (this.filepath === undefined) return err(new Error('No file path associated with this instance'));\n\n const outPathResult = createDicomFilePath(outputPath);\n if (!outPathResult.ok) return err(outPathResult.error);\n\n const copyResult = await copyFileSafe(this.filepath, outputPath);\n if (!copyResult.ok) return err(copyResult.error);\n\n if (!this.changeSet.isEmpty) {\n const applyResult = await applyModifications(outPathResult.value, this.changeSet, options ?? {});\n if (!applyResult.ok) {\n await unlinkFile(outputPath);\n return err(applyResult.error);\n }\n }\n\n return ok(new DicomInstance(this.dicomDataset, ChangeSet.empty(), outPathResult.value, this.meta));\n }\n\n /**\n * Gets the file size in bytes.\n *\n * @returns A Result containing the size or an error\n */\n async fileSize(): Promise<Result<number>> {\n if (this.filepath === undefined) return err(new Error('No file path associated with this instance'));\n return statFileSize(this.filepath);\n }\n\n /**\n * Deletes the associated file from the filesystem.\n *\n * @returns A Result indicating success or failure\n */\n async unlink(): Promise<Result<void>> {\n if (this.filepath === undefined) return err(new Error('No file path associated with this instance'));\n return unlinkFile(this.filepath);\n }\n\n // -----------------------------------------------------------------------\n // Metadata (non-DICOM app context)\n // -----------------------------------------------------------------------\n\n /**\n * Returns a new DicomInstance with application metadata attached.\n *\n * Metadata is not stored in the DICOM file — it's for application context\n * (e.g. tracking source association, processing status, etc.).\n *\n * @param key - Metadata key\n * @param value - Metadata value\n */\n withMetadata(key: string, value: unknown): DicomInstance {\n const newMeta = new Map(this.meta);\n newMeta.set(key, value);\n return new DicomInstance(this.dicomDataset, this.changeSet, this.filepath, newMeta);\n }\n\n /**\n * Gets application metadata by key.\n *\n * @param key - Metadata key\n * @returns The metadata value or undefined\n */\n getMetadata(key: string): unknown {\n return this.meta.get(key);\n }\n}\n\nexport { DicomInstance };\n","/**\n * Pooled DICOM receiver with auto-scaling.\n *\n * Manages a pool of long-lived `Dcmrecv` workers behind a TCP proxy,\n * routing incoming connections to idle workers. Workers are reused\n * across associations — they are only stopped during scale-down or\n * shutdown.\n *\n * @module servers/DicomReceiver\n */\n\nimport * as net from 'node:net';\nimport * as path from 'node:path';\nimport * as fs from 'node:fs/promises';\nimport * as os from 'node:os';\nimport { EventEmitter } from 'node:events';\nimport { z } from 'zod';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { isSafePath, isValidAETitle } from '../patterns';\nimport { createValidationError } from '../tools/_toolError';\nimport { Dcmrecv } from './Dcmrecv';\nimport type { AssociationCompleteData } from '../events/dcmrecv';\nimport { DicomInstance } from '../dicom/DicomInstance';\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_MIN_POOL_SIZE = 2;\nconst DEFAULT_MAX_POOL_SIZE = 10;\nconst DEFAULT_CONNECTION_TIMEOUT_MS = 10_000;\nconst CONNECTION_RETRY_INTERVAL_MS = 500;\nconst MAX_CONNECTION_RETRIES = 200;\n\n// ---------------------------------------------------------------------------\n// Public interfaces\n// ---------------------------------------------------------------------------\n\n/** Snapshot of the worker pool state. */\ninterface PoolStatus {\n /** Number of idle workers ready for connections. */\n readonly idle: number;\n /** Number of workers currently handling associations. */\n readonly busy: number;\n /** Total number of workers (idle + busy). */\n readonly total: number;\n}\n\n/** Data emitted with FILE_RECEIVED events. */\ninterface ReceiverFileData {\n readonly filePath: string;\n readonly associationId: string;\n readonly associationDir: string;\n readonly callingAE: string;\n readonly calledAE: string;\n readonly source: string;\n readonly instance: DicomInstance;\n}\n\n/** Data emitted with ASSOCIATION_COMPLETE events. */\ninterface ReceiverAssociationData {\n readonly associationId: string;\n readonly associationDir: string;\n readonly callingAE: string;\n readonly calledAE: string;\n readonly source: string;\n readonly files: readonly string[];\n readonly durationMs: number;\n readonly endReason: 'release' | 'abort';\n readonly totalBytes: number;\n readonly bytesPerSecond: number;\n readonly startAt: number;\n readonly endAt: number;\n}\n\n/** Data emitted with error events. */\ninterface ReceiverErrorData {\n readonly error: Error;\n readonly filePath?: string;\n readonly associationId?: string;\n readonly associationDir?: string;\n readonly callingAE?: string;\n readonly calledAE?: string;\n readonly source?: string;\n}\n\n/** Typed event map for DicomReceiver. */\ninterface DicomReceiverEventMap {\n FILE_RECEIVED: [ReceiverFileData];\n ASSOCIATION_COMPLETE: [ReceiverAssociationData];\n error: [ReceiverErrorData];\n}\n\n/** Options for creating a DicomReceiver instance. */\ninterface DicomReceiverOptions {\n /** External port to listen on (required). */\n readonly port: number;\n /** Root directory for association subdirectories (required). */\n readonly storageDir: string;\n /** Application Entity Title for workers. */\n readonly aeTitle?: string | undefined;\n /** Minimum number of idle workers to maintain. */\n readonly minPoolSize?: number | undefined;\n /** Maximum total workers allowed. */\n readonly maxPoolSize?: number | undefined;\n /** Timeout for waiting for an idle worker (milliseconds). */\n readonly connectionTimeoutMs?: number | undefined;\n /** Path to a dcmrecv association negotiation configuration file. */\n readonly configFile?: string | undefined;\n /** Profile name within the configuration file. */\n readonly configProfile?: string | undefined;\n /** AbortSignal for external cancellation. */\n readonly signal?: AbortSignal | undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Zod validation schema\n// ---------------------------------------------------------------------------\n\nconst DicomReceiverOptionsSchema = z\n .object({\n port: z.number().int().min(1).max(65535),\n storageDir: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in storageDir' }),\n aeTitle: z.string().min(1).max(16).refine(isValidAETitle, { message: 'AE Title contains invalid characters' }).optional(),\n minPoolSize: z.number().int().min(1).max(100).optional(),\n maxPoolSize: z.number().int().min(1).max(100).optional(),\n connectionTimeoutMs: z.number().int().positive().optional(),\n configFile: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in configFile' }).optional(),\n configProfile: z.string().min(1).optional(),\n signal: z.instanceof(AbortSignal).optional(),\n })\n .strict()\n .refine(data => (data.minPoolSize ?? DEFAULT_MIN_POOL_SIZE) <= (data.maxPoolSize ?? DEFAULT_MAX_POOL_SIZE), {\n message: 'minPoolSize must be <= maxPoolSize',\n });\n\n// ---------------------------------------------------------------------------\n// Internal worker type\n// ---------------------------------------------------------------------------\n\ninterface WorkerInfo {\n readonly dcmrecv: Dcmrecv;\n readonly port: number;\n readonly tempDir: string;\n state: 'idle' | 'busy';\n associationId: string | undefined;\n associationDir: string | undefined;\n /** Files moved to the association dir during the current association. */\n files: string[];\n /** Byte sizes parallel to files[], for transfer stats. */\n fileSizes: number[];\n /** Timestamp when the TCP connection was routed to this worker. */\n startAt: number | undefined;\n remoteSocket: net.Socket | undefined;\n workerSocket: net.Socket | undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Port allocation helper\n// ---------------------------------------------------------------------------\n\n/** Allocates a free ephemeral port by binding to port 0. */\nfunction allocatePort(): Promise<Result<number>> {\n return new Promise(resolve => {\n const server = net.createServer();\n server.listen(0, '127.0.0.1', () => {\n const addr = server.address();\n if (addr === null || typeof addr === 'string') {\n server.close(() => resolve(err(new Error('Failed to allocate port'))));\n return;\n }\n const port = addr.port;\n server.close(() => resolve(ok(port)));\n });\n server.on('error', e => {\n resolve(err(new Error(`Port allocation failed: ${e.message}`)));\n });\n });\n}\n\n// ---------------------------------------------------------------------------\n// DicomReceiver class\n// ---------------------------------------------------------------------------\n\n/**\n * Pooled DICOM receiver with auto-scaling.\n *\n * Manages a pool of long-lived `Dcmrecv` workers behind a TCP proxy.\n * Incoming connections are routed to idle workers. Workers are reused\n * across associations and only stopped during scale-down or shutdown.\n *\n * @example\n * ```ts\n * const result = DicomReceiver.create({\n * port: 4242,\n * storageDir: '/data/received',\n * minPoolSize: 2,\n * maxPoolSize: 8,\n * });\n * if (!result.ok) { console.error(result.error.message); return; }\n * const receiver = result.value;\n *\n * receiver.onFileReceived(data => console.log('File:', data.filePath));\n * receiver.onAssociationComplete(data => console.log('Done:', data.associationDir));\n *\n * await receiver.start();\n * ```\n */\nclass DicomReceiver extends EventEmitter<DicomReceiverEventMap> {\n private readonly options: DicomReceiverOptions;\n private readonly minPoolSize: number;\n private readonly maxPoolSize: number;\n private readonly connectionTimeoutMs: number;\n private readonly workers: Map<number, WorkerInfo> = new Map();\n private tcpServer: net.Server | undefined;\n private associationCounter = 0;\n private started = false;\n private stopping = false;\n private abortHandler: (() => void) | undefined;\n\n private constructor(options: DicomReceiverOptions) {\n super();\n this.setMaxListeners(20);\n this.on('error', () => {\n /* prevent Node.js uncaught exception on unhandled 'error' */\n });\n this.options = options;\n this.minPoolSize = options.minPoolSize ?? DEFAULT_MIN_POOL_SIZE;\n this.maxPoolSize = options.maxPoolSize ?? DEFAULT_MAX_POOL_SIZE;\n this.connectionTimeoutMs = options.connectionTimeoutMs ?? DEFAULT_CONNECTION_TIMEOUT_MS;\n }\n\n // -----------------------------------------------------------------------\n // Public API\n // -----------------------------------------------------------------------\n\n /**\n * Creates a new DicomReceiver instance.\n *\n * @param options - Configuration options\n * @returns A Result containing the instance or a validation error\n */\n static create(options: DicomReceiverOptions): Result<DicomReceiver> {\n const validation = DicomReceiverOptionsSchema.safeParse(options);\n if (!validation.success) {\n return err(createValidationError('DicomReceiver', validation.error));\n }\n return ok(new DicomReceiver(options));\n }\n\n /**\n * Starts the TCP proxy and spawns the initial worker pool.\n *\n * @returns A Result indicating success or failure\n */\n async start(): Promise<Result<void>> {\n if (this.started) {\n return err(new Error('DicomReceiver: already started'));\n }\n this.started = true;\n\n const storageDirResult = await ensureDirectory(this.options.storageDir);\n if (!storageDirResult.ok) return storageDirResult;\n\n const spawnResults = await this.spawnWorkers(this.minPoolSize);\n if (!spawnResults.ok) return spawnResults;\n\n const listenResult = await this.startTcpProxy();\n if (!listenResult.ok) return listenResult;\n\n if (this.options.signal !== undefined) {\n this.wireAbortSignal(this.options.signal);\n }\n\n return ok(undefined);\n }\n\n /**\n * Stops the TCP proxy and all workers.\n */\n async stop(): Promise<void> {\n if (!this.started || this.stopping) {\n return;\n }\n this.stopping = true;\n\n if (this.options.signal !== undefined && this.abortHandler !== undefined) {\n this.options.signal.removeEventListener('abort', this.abortHandler);\n }\n\n await this.closeTcpProxy();\n\n const stopPromises: Promise<void>[] = [];\n for (const worker of this.workers.values()) {\n stopPromises.push(this.stopWorker(worker));\n }\n await Promise.all(stopPromises);\n this.workers.clear();\n\n this.started = false;\n this.stopping = false;\n }\n\n /**\n * Registers a typed listener for a DicomReceiver-specific event.\n *\n * @param event - The event name from DicomReceiverEventMap\n * @param listener - Callback receiving typed event data\n * @returns this for chaining\n */\n onEvent<K extends keyof DicomReceiverEventMap>(event: K, listener: (...args: DicomReceiverEventMap[K]) => void): this {\n return this.on(event, listener as never);\n }\n\n /**\n * Registers a listener for received files.\n *\n * @param listener - Callback receiving file data\n * @returns this for chaining\n */\n onFileReceived(listener: (data: ReceiverFileData) => void): this {\n return this.on('FILE_RECEIVED', listener);\n }\n\n /**\n * Registers a listener for completed associations.\n *\n * @param listener - Callback receiving association data\n * @returns this for chaining\n */\n onAssociationComplete(listener: (data: ReceiverAssociationData) => void): this {\n return this.on('ASSOCIATION_COMPLETE', listener);\n }\n\n /** Current pool status. */\n get poolStatus(): PoolStatus {\n let idle = 0;\n let busy = 0;\n for (const w of this.workers.values()) {\n if (w.state === 'idle') idle++;\n else busy++;\n }\n return { idle, busy, total: this.workers.size };\n }\n\n // -----------------------------------------------------------------------\n // TCP proxy\n // -----------------------------------------------------------------------\n\n /** Starts the TCP proxy on the configured port. */\n private startTcpProxy(): Promise<Result<void>> {\n return new Promise(resolve => {\n this.tcpServer = net.createServer(socket => {\n void this.handleConnection(socket);\n });\n this.tcpServer.on('error', e => {\n if (!this.started) {\n resolve(err(new Error(`DicomReceiver: TCP proxy failed: ${e.message}`)));\n } else {\n this.emit('error', { error: e instanceof Error ? e : new Error(String(e)) });\n }\n });\n this.tcpServer.listen(this.options.port, () => {\n resolve(ok(undefined));\n });\n });\n }\n\n /** Closes the TCP proxy server. */\n private closeTcpProxy(): Promise<void> {\n return new Promise(resolve => {\n if (this.tcpServer === undefined) {\n resolve();\n return;\n }\n this.tcpServer.close(() => resolve());\n });\n }\n\n // -----------------------------------------------------------------------\n // Connection routing\n // -----------------------------------------------------------------------\n\n /** Routes an incoming connection to an idle worker. */\n private async handleConnection(remoteSocket: net.Socket): Promise<void> {\n remoteSocket.pause();\n\n const worker = await this.findIdleWorker();\n if (worker === undefined) {\n remoteSocket.destroy(new Error('DicomReceiver: no idle worker available'));\n this.emit('error', { error: new Error('DicomReceiver: connection rejected — pool exhausted') });\n return;\n }\n\n this.associationCounter++;\n const associationId = `assoc-${String(this.associationCounter)}`;\n const associationDir = path.join(this.options.storageDir, associationId);\n\n const mkdirResult = await ensureDirectory(associationDir);\n if (!mkdirResult.ok) {\n remoteSocket.destroy();\n this.emit('error', { error: mkdirResult.error });\n return;\n }\n\n worker.state = 'busy';\n worker.associationId = associationId;\n worker.associationDir = associationDir;\n worker.files = [];\n worker.fileSizes = [];\n worker.startAt = Date.now();\n\n this.pipeConnection(worker, remoteSocket);\n void this.replenishPool();\n }\n\n /** Finds an idle worker, retrying up to connectionTimeoutMs. */\n private async findIdleWorker(): Promise<WorkerInfo | undefined> {\n const idle = this.getIdleWorker();\n if (idle !== undefined) return idle;\n\n const maxRetries = Math.min(Math.ceil(this.connectionTimeoutMs / CONNECTION_RETRY_INTERVAL_MS), MAX_CONNECTION_RETRIES);\n\n for (let i = 0; i < maxRetries; i++) {\n await delay(CONNECTION_RETRY_INTERVAL_MS);\n const found = this.getIdleWorker();\n if (found !== undefined) return found;\n if (this.stopping) return undefined;\n }\n return undefined;\n }\n\n /** Returns the first idle worker, or undefined. */\n private getIdleWorker(): WorkerInfo | undefined {\n for (const w of this.workers.values()) {\n if (w.state === 'idle') return w;\n }\n return undefined;\n }\n\n /** Pipes remote socket bidirectionally to the worker's port. */\n private pipeConnection(worker: WorkerInfo, remoteSocket: net.Socket): void {\n const workerSocket = net.createConnection({ port: worker.port, host: '127.0.0.1' });\n\n worker.remoteSocket = remoteSocket;\n worker.workerSocket = workerSocket;\n\n remoteSocket.pipe(workerSocket);\n workerSocket.pipe(remoteSocket);\n\n remoteSocket.resume();\n\n const cleanup = (): void => {\n remoteSocket.unpipe(workerSocket);\n workerSocket.unpipe(remoteSocket);\n if (!remoteSocket.destroyed) remoteSocket.destroy();\n if (!workerSocket.destroyed) workerSocket.destroy();\n };\n\n remoteSocket.on('error', cleanup);\n workerSocket.on('error', cleanup);\n remoteSocket.on('close', cleanup);\n workerSocket.on('close', cleanup);\n }\n\n // -----------------------------------------------------------------------\n // Worker pool management\n // -----------------------------------------------------------------------\n\n /** Spawns `count` new workers and adds them to the pool. */\n private async spawnWorkers(count: number): Promise<Result<void>> {\n const promises: Promise<Result<WorkerInfo>>[] = [];\n for (let i = 0; i < count; i++) {\n promises.push(this.spawnWorker());\n }\n const results = await Promise.all(promises);\n for (const result of results) {\n if (!result.ok) return err(result.error);\n }\n return ok(undefined);\n }\n\n /** Spawns a single Dcmrecv worker with an ephemeral port. */\n private async spawnWorker(): Promise<Result<WorkerInfo>> {\n const portResult = await allocatePort();\n if (!portResult.ok) return portResult;\n const port = portResult.value;\n\n const tempDir = path.join(os.tmpdir(), `dcmrecv-pool-${String(port)}-${String(Date.now())}`);\n const mkdirResult = await ensureDirectory(tempDir);\n if (!mkdirResult.ok) return mkdirResult;\n\n const createResult = Dcmrecv.create({\n port,\n aeTitle: this.options.aeTitle ?? 'DCMRECV',\n outputDirectory: tempDir,\n configFile: this.options.configFile,\n configProfile: this.options.configProfile,\n });\n if (!createResult.ok) return createResult;\n\n const dcmrecv = createResult.value;\n const worker: WorkerInfo = {\n dcmrecv,\n port,\n tempDir,\n state: 'idle',\n associationId: undefined,\n associationDir: undefined,\n files: [],\n fileSizes: [],\n startAt: undefined,\n remoteSocket: undefined,\n workerSocket: undefined,\n };\n\n this.wireWorkerEvents(worker);\n const startResult = await dcmrecv.start();\n if (!startResult.ok) {\n return err(new Error(`DicomReceiver: worker start failed on port ${String(port)}: ${startResult.error.message}`));\n }\n\n this.workers.set(port, worker);\n return ok(worker);\n }\n\n /** Stops a single worker: stop process, clean temp dir, remove from pool. */\n private async stopWorker(worker: WorkerInfo): Promise<void> {\n if (worker.remoteSocket !== undefined && !worker.remoteSocket.destroyed) {\n worker.remoteSocket.destroy();\n }\n if (worker.workerSocket !== undefined && !worker.workerSocket.destroyed) {\n worker.workerSocket.destroy();\n }\n await worker.dcmrecv.stop();\n worker.dcmrecv[Symbol.dispose]();\n await removeDirSafe(worker.tempDir);\n this.workers.delete(worker.port);\n }\n\n /** Pre-emptively spawns workers to keep idle count >= minPoolSize. */\n private async replenishPool(): Promise<void> {\n const status = this.poolStatus;\n const needed = this.minPoolSize - status.idle;\n const capacity = this.maxPoolSize - status.total;\n const toSpawn = Math.min(needed, capacity);\n\n if (toSpawn <= 0) return;\n\n const promises: Promise<Result<WorkerInfo>>[] = [];\n for (let i = 0; i < toSpawn; i++) {\n promises.push(this.spawnWorker());\n }\n const results = await Promise.all(promises);\n for (const result of results) {\n if (!result.ok) {\n this.emit('error', { error: result.error });\n }\n }\n }\n\n /** Stops excess idle workers when idle count > minPoolSize + 2. */\n private async scaleDown(): Promise<void> {\n const idleWorkers: WorkerInfo[] = [];\n for (const w of this.workers.values()) {\n if (w.state === 'idle') idleWorkers.push(w);\n }\n const excess = idleWorkers.length - (this.minPoolSize + 2);\n if (excess <= 0) return;\n\n const toStop = idleWorkers.slice(0, excess);\n const promises: Promise<void>[] = [];\n for (const w of toStop) {\n promises.push(this.stopWorker(w));\n }\n await Promise.all(promises);\n }\n\n // -----------------------------------------------------------------------\n // Worker event wiring\n // -----------------------------------------------------------------------\n\n /** Wires FILE_RECEIVED and ASSOCIATION_COMPLETE events on a worker. */\n private wireWorkerEvents(worker: WorkerInfo): void {\n this.wireFileReceived(worker);\n this.wireAssociationComplete(worker);\n }\n\n /** Wires FILE_RECEIVED from dcmrecv worker to handleFileReceived. */\n private wireFileReceived(worker: WorkerInfo): void {\n worker.dcmrecv.onFileReceived(data => {\n void this.handleFileReceived(worker, data);\n });\n }\n\n /** Moves a received file, opens it as DicomInstance, and emits FILE_RECEIVED. */\n private async handleFileReceived(worker: WorkerInfo, data: { filePath: string; callingAE: string; calledAE: string; source: string }): Promise<void> {\n if (worker.associationDir === undefined || worker.associationId === undefined) return;\n const srcPath = data.filePath;\n const destPath = path.join(worker.associationDir, path.basename(srcPath));\n const assocId = worker.associationId;\n const assocDir = worker.associationDir;\n\n const moveResult = await moveFile(srcPath, destPath);\n const finalPath = moveResult.ok ? destPath : srcPath;\n worker.files.push(finalPath);\n worker.fileSizes.push(await statFileSafe(finalPath));\n\n const openResult = await DicomInstance.open(finalPath);\n if (!openResult.ok) {\n this.emit('error', {\n error: openResult.error,\n filePath: finalPath,\n associationId: assocId,\n associationDir: assocDir,\n callingAE: data.callingAE,\n calledAE: data.calledAE,\n source: data.source,\n });\n return;\n }\n\n this.emit('FILE_RECEIVED', {\n filePath: finalPath,\n associationId: assocId,\n associationDir: assocDir,\n callingAE: data.callingAE,\n calledAE: data.calledAE,\n source: data.source,\n instance: openResult.value,\n });\n }\n\n /** Returns worker to idle pool on association complete, emits summary. */\n private wireAssociationComplete(worker: WorkerInfo): void {\n worker.dcmrecv.onAssociationComplete((data: AssociationCompleteData) => {\n const assocId = worker.associationId ?? data.associationId;\n const assocDir = worker.associationDir ?? '';\n const files = [...worker.files];\n\n const endAt = Date.now();\n const startAt = worker.startAt ?? endAt;\n const totalBytes = sumArray(worker.fileSizes);\n const elapsedMs = endAt - startAt;\n const bytesPerSecond = elapsedMs > 0 ? Math.round((totalBytes / elapsedMs) * 1000) : 0;\n\n this.emit('ASSOCIATION_COMPLETE', {\n associationId: assocId,\n associationDir: assocDir,\n callingAE: data.callingAE,\n calledAE: data.calledAE,\n source: data.source,\n files,\n durationMs: data.durationMs,\n endReason: data.endReason,\n totalBytes,\n bytesPerSecond,\n startAt,\n endAt,\n });\n\n worker.state = 'idle';\n worker.associationId = undefined;\n worker.associationDir = undefined;\n worker.files = [];\n worker.fileSizes = [];\n worker.startAt = undefined;\n worker.remoteSocket = undefined;\n worker.workerSocket = undefined;\n\n void this.scaleDown();\n });\n }\n\n // -----------------------------------------------------------------------\n // Abort signal\n // -----------------------------------------------------------------------\n\n /** Wires an AbortSignal to stop the receiver. */\n private wireAbortSignal(signal: AbortSignal): void {\n /* v8 ignore next 4 */\n if (signal.aborted) {\n void this.stop();\n return;\n }\n this.abortHandler = (): void => {\n void this.stop();\n };\n signal.addEventListener('abort', this.abortHandler, { once: true });\n }\n}\n\n// ---------------------------------------------------------------------------\n// File system helpers\n// ---------------------------------------------------------------------------\n\n/** Ensures a directory exists, creating it recursively if needed. */\nasync function ensureDirectory(dirPath: string): Promise<Result<void>> {\n try {\n await fs.mkdir(dirPath, { recursive: true });\n return ok(undefined);\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n return err(new Error(`Failed to create directory ${dirPath}: ${msg}`));\n }\n}\n\n/** Moves a file from src to dest, falling back to copy+delete on cross-device. */\nasync function moveFile(src: string, dest: string): Promise<Result<void>> {\n try {\n await fs.rename(src, dest);\n return ok(undefined);\n } catch {\n try {\n await fs.copyFile(src, dest);\n await fs.unlink(src);\n return ok(undefined);\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n return err(new Error(`Failed to move file ${src} → ${dest}: ${msg}`));\n }\n }\n}\n\n/** Returns the file size in bytes, or 0 on error. */\nasync function statFileSafe(filePath: string): Promise<number> {\n try {\n const stat = await fs.stat(filePath);\n return stat.size;\n } catch {\n /* v8 ignore next */\n return 0;\n }\n}\n\n/** Sums an array of numbers iteratively. */\nfunction sumArray(arr: readonly number[]): number {\n let total = 0;\n for (let i = 0; i < arr.length; i++) {\n total += arr[i] ?? 0;\n }\n return total;\n}\n\n/** Removes a directory recursively, ignoring errors. */\nasync function removeDirSafe(dirPath: string): Promise<void> {\n try {\n await fs.rm(dirPath, { recursive: true, force: true });\n } catch {\n /* best-effort cleanup */\n }\n}\n\n/** Promise-based delay. */\nfunction delay(ms: number): Promise<void> {\n return new Promise(resolve => {\n setTimeout(resolve, ms);\n });\n}\n\nexport { DicomReceiver };\nexport type { DicomReceiverOptions, DicomReceiverEventMap, ReceiverFileData, ReceiverAssociationData, ReceiverErrorData, PoolStatus };\n","/**\n * Event patterns and types for dcmprscp output parsing.\n *\n * Defines regex patterns that match DCMTK dcmprscp (print management SCP)\n * verbose output, along with typed event data interfaces for each event.\n *\n * @module events/dcmprscp\n */\n\nimport type { EventPattern } from '../parsers/EventPattern';\n\n// ---------------------------------------------------------------------------\n// Event constants (as const, not enum — Rule 3.5)\n// ---------------------------------------------------------------------------\n\n/** Events emitted by dcmprscp process output. */\nconst DcmprscpEvent = {\n DATABASE_READY: 'DATABASE_READY',\n ASSOCIATION_RECEIVED: 'ASSOCIATION_RECEIVED',\n ASSOCIATION_ACKNOWLEDGED: 'ASSOCIATION_ACKNOWLEDGED',\n ASSOCIATION_RELEASE: 'ASSOCIATION_RELEASE',\n ASSOCIATION_ABORTED: 'ASSOCIATION_ABORTED',\n CANNOT_START_LISTENER: 'CANNOT_START_LISTENER',\n CONFIG_ERROR: 'CONFIG_ERROR',\n} as const;\n\ntype DcmprscpEventValue = (typeof DcmprscpEvent)[keyof typeof DcmprscpEvent];\n\n// ---------------------------------------------------------------------------\n// Event data interfaces (all readonly)\n// ---------------------------------------------------------------------------\n\n/** Data for DATABASE_READY event. */\ninterface DatabaseReadyData {\n readonly directory: string;\n}\n\n/** Data for ASSOCIATION_RECEIVED event. */\ninterface PrintAssociationReceivedData {\n readonly peerInfo: string;\n}\n\n/** Data for ASSOCIATION_ACKNOWLEDGED event. */\ninterface PrintAssociationAcknowledgedData {\n readonly maxSendPDV: number;\n}\n\n/** Data for CANNOT_START_LISTENER event. */\ninterface PrintCannotStartListenerData {\n readonly message: string;\n}\n\n/** Data for CONFIG_ERROR event. */\ninterface ConfigErrorData {\n readonly message: string;\n}\n\n// ---------------------------------------------------------------------------\n// Regex patterns for dcmprscp verbose output\n// ---------------------------------------------------------------------------\n\n/** Event patterns for parsing dcmprscp verbose output. */\nconst DCMPRSCP_PATTERNS: readonly EventPattern[] = [\n {\n event: DcmprscpEvent.DATABASE_READY,\n pattern: /Using database in directory\\s+'([^']+)'/,\n processor: (match): DatabaseReadyData => ({\n directory: match[1] ?? '',\n }),\n },\n {\n event: DcmprscpEvent.ASSOCIATION_RECEIVED,\n pattern: /Association Received\\s{0,20}\\(([^)]+)\\)/,\n processor: (match): PrintAssociationReceivedData => ({\n peerInfo: (match[1] ?? '').trim(),\n }),\n },\n {\n event: DcmprscpEvent.ASSOCIATION_ACKNOWLEDGED,\n pattern: /Association Acknowledged \\(Max Send PDV:\\s*(\\d+)\\)/,\n processor: (match): PrintAssociationAcknowledgedData => ({\n maxSendPDV: Number(match[1]),\n }),\n },\n {\n event: DcmprscpEvent.ASSOCIATION_RELEASE,\n pattern: /Association Release/i,\n processor: () => undefined,\n },\n {\n event: DcmprscpEvent.ASSOCIATION_ABORTED,\n pattern: /Association Abort/i,\n processor: () => undefined,\n },\n {\n event: DcmprscpEvent.CANNOT_START_LISTENER,\n pattern: /cannot initialise network|cannot listen/i,\n processor: (match): PrintCannotStartListenerData => ({\n message: match[0] ?? '',\n }),\n },\n {\n event: DcmprscpEvent.CONFIG_ERROR,\n pattern: /can't open configuration file|no (?:default )?print scp/i,\n processor: (match): ConfigErrorData => ({\n message: match[0] ?? '',\n }),\n },\n];\n\n/** Events that indicate fatal errors (process should be stopped). */\nconst DCMPRSCP_FATAL_EVENTS: ReadonlySet<string> = new Set([DcmprscpEvent.CANNOT_START_LISTENER, DcmprscpEvent.CONFIG_ERROR]);\n\nexport { DcmprscpEvent, DCMPRSCP_PATTERNS, DCMPRSCP_FATAL_EVENTS };\nexport type {\n DcmprscpEventValue,\n DatabaseReadyData,\n PrintAssociationReceivedData,\n PrintAssociationAcknowledgedData,\n PrintCannotStartListenerData,\n ConfigErrorData,\n};\n","/**\n * DICOM Print Management SCP server wrapping the dcmprscp binary.\n *\n * Provides a type-safe, event-driven API for the Basic Grayscale Print\n * Management SCP. Uses a static factory pattern because binary resolution\n * and validation must happen before the constructor call.\n *\n * @module servers/DcmprsCP\n */\n\nimport { z } from 'zod';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { DcmtkProcess } from '../DcmtkProcess';\nimport type { DcmtkProcessConfig } from '../DcmtkProcess';\nimport { LineParser } from '../parsers/LineParser';\nimport { resolveBinary } from '../tools/_resolveBinary';\nimport { createValidationError } from '../tools/_toolError';\nimport { isSafePath } from '../patterns';\nimport { DCMPRSCP_PATTERNS, DCMPRSCP_FATAL_EVENTS } from '../events/dcmprscp';\nimport type {\n DatabaseReadyData,\n PrintAssociationReceivedData,\n PrintAssociationAcknowledgedData,\n PrintCannotStartListenerData,\n ConfigErrorData,\n} from '../events/dcmprscp';\n\n// ---------------------------------------------------------------------------\n// Event map type\n// ---------------------------------------------------------------------------\n\n/** Typed event map for the DcmprsCP server. */\ninterface DcmprsCPEventMap {\n DATABASE_READY: [DatabaseReadyData];\n ASSOCIATION_RECEIVED: [PrintAssociationReceivedData];\n ASSOCIATION_ACKNOWLEDGED: [PrintAssociationAcknowledgedData];\n ASSOCIATION_RELEASE: [];\n ASSOCIATION_ABORTED: [];\n CANNOT_START_LISTENER: [PrintCannotStartListenerData];\n CONFIG_ERROR: [ConfigErrorData];\n}\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\n/** Options for creating a DcmprsCP server instance. */\ninterface DcmprsCPOptions {\n /** Path to the dcmpstat configuration file (required). */\n readonly configFile: string;\n /** Printer identifier from the config file (optional, defaults to first printer). */\n readonly printer?: string | undefined;\n /** Enable DIMSE message dumping. */\n readonly dump?: boolean | undefined;\n /** Log level override. */\n readonly logLevel?: 'fatal' | 'error' | 'warn' | 'info' | 'debug' | 'trace' | undefined;\n /** Path to a log configuration file. */\n readonly logConfig?: string | undefined;\n /** Timeout for start() to resolve (milliseconds). */\n readonly startTimeoutMs?: number | undefined;\n /** Timeout for graceful drain during stop() (milliseconds). */\n readonly drainTimeoutMs?: number | undefined;\n /** AbortSignal for external cancellation. */\n readonly signal?: AbortSignal | undefined;\n}\n\nconst DcmprsCPOptionsSchema = z\n .object({\n configFile: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in configFile' }),\n printer: z.string().min(1).optional(),\n dump: z.boolean().optional(),\n logLevel: z.enum(['fatal', 'error', 'warn', 'info', 'debug', 'trace']).optional(),\n logConfig: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in logConfig' }).optional(),\n startTimeoutMs: z.number().int().positive().optional(),\n drainTimeoutMs: z.number().int().positive().optional(),\n signal: z.instanceof(AbortSignal).optional(),\n })\n .strict();\n\n// ---------------------------------------------------------------------------\n// Argument builder\n// ---------------------------------------------------------------------------\n\n/** Builds the CLI arguments array from validated options. */\nfunction buildArgs(options: DcmprsCPOptions): string[] {\n const args: string[] = ['--verbose', '--config', options.configFile];\n\n if (options.printer !== undefined) {\n args.push('--printer', options.printer);\n }\n if (options.dump === true) {\n args.push('--dump');\n }\n if (options.logLevel !== undefined) {\n args.push('--log-level', options.logLevel);\n }\n if (options.logConfig !== undefined) {\n args.push('--log-config', options.logConfig);\n }\n\n return args;\n}\n\n// ---------------------------------------------------------------------------\n// DcmprsCP class\n// ---------------------------------------------------------------------------\n\n/**\n * DICOM Print Management SCP server wrapping the dcmprscp binary.\n *\n * Uses a static `create()` factory because binary resolution is fallible\n * and must complete before the constructor runs.\n *\n * Note: dcmprscp does not print a \"listening\" message. The `start()` method\n * resolves either when the DATABASE_READY event is detected or on spawn.\n *\n * @example\n * ```ts\n * const result = DcmprsCP.create({ configFile: '/etc/dcmpstat.cfg' });\n * if (result.ok) {\n * const server = result.value;\n * server.onEvent('DATABASE_READY', (data) => console.log('DB:', data.directory));\n * const startResult = await server.start();\n * }\n * ```\n */\nclass DcmprsCP extends DcmtkProcess {\n private readonly parser: LineParser;\n private abortSignal: AbortSignal | undefined;\n private abortHandler: (() => void) | undefined;\n\n private constructor(config: DcmtkProcessConfig, parser: LineParser, signal?: AbortSignal) {\n super(config);\n this.parser = parser;\n this.wireParser();\n if (signal !== undefined) {\n this.wireAbortSignal(signal);\n }\n }\n\n /**\n * Registers a typed listener for a dcmprscp-specific event.\n *\n * @param event - The event name from DcmprsCPEventMap\n * @param listener - Callback receiving typed event data\n * @returns this for chaining\n */\n /** Disposes the server and its parser, preventing listener leaks. */\n [Symbol.dispose](): void {\n if (this.abortSignal !== undefined && this.abortHandler !== undefined) {\n this.abortSignal.removeEventListener('abort', this.abortHandler);\n }\n this.parser[Symbol.dispose]();\n super[Symbol.dispose]();\n }\n\n onEvent<K extends keyof DcmprsCPEventMap>(event: K, listener: (...args: DcmprsCPEventMap[K]) => void): this {\n return this.on(event as string, listener as never);\n }\n\n /**\n * Registers a listener for when the database is ready.\n *\n * @param listener - Callback receiving database ready data\n * @returns this for chaining\n */\n onDatabaseReady(listener: (...args: DcmprsCPEventMap['DATABASE_READY']) => void): this {\n return this.onEvent('DATABASE_READY', listener);\n }\n\n /**\n * Registers a listener for incoming associations.\n *\n * @param listener - Callback receiving association data\n * @returns this for chaining\n */\n onAssociationReceived(listener: (...args: DcmprsCPEventMap['ASSOCIATION_RECEIVED']) => void): this {\n return this.onEvent('ASSOCIATION_RECEIVED', listener);\n }\n\n /**\n * Creates a new DcmprsCP server instance.\n *\n * @param options - Configuration options for the dcmprscp server\n * @returns A Result containing the server instance or a validation/resolution error\n */\n static create(options: DcmprsCPOptions): Result<DcmprsCP> {\n const validation = DcmprsCPOptionsSchema.safeParse(options);\n if (!validation.success) {\n return err(createValidationError('dcmprscp', validation.error));\n }\n\n const binaryResult = resolveBinary('dcmprscp');\n if (!binaryResult.ok) {\n return err(binaryResult.error);\n }\n\n const args = buildArgs(options);\n const parser = new LineParser();\n for (const pattern of DCMPRSCP_PATTERNS) {\n const addResult = parser.addPattern(pattern);\n if (!addResult.ok) {\n return err(addResult.error);\n }\n }\n\n const config: DcmtkProcessConfig = {\n binary: binaryResult.value,\n args,\n startTimeoutMs: options.startTimeoutMs,\n drainTimeoutMs: options.drainTimeoutMs,\n isStartedPredicate: line => /Using database in directory/i.test(line),\n };\n\n return ok(new DcmprsCP(config, parser, options.signal));\n }\n\n /** Wires the line parser to the process output. */\n private wireParser(): void {\n this.on('line', ({ text }) => {\n this.parser.feed(text);\n });\n\n this.parser.on('match', ({ event, data }) => {\n if (DCMPRSCP_FATAL_EVENTS.has(event)) {\n this.emit('error', { error: new Error(`Fatal: ${event}`), fatal: true });\n void this.stop();\n }\n this.emit(event, data);\n });\n }\n\n /** Wires an AbortSignal to stop the server. */\n private wireAbortSignal(signal: AbortSignal): void {\n if (signal.aborted) {\n void this.stop();\n return;\n }\n this.abortSignal = signal;\n this.abortHandler = (): void => {\n void this.stop();\n };\n signal.addEventListener('abort', this.abortHandler, { once: true });\n }\n}\n\nexport { DcmprsCP };\nexport type { DcmprsCPOptions, DcmprsCPEventMap };\n","/**\n * Event patterns and types for dcmpsrcv output parsing.\n *\n * Defines regex patterns that match DCMTK dcmpsrcv (viewer network receiver)\n * verbose output. Shares several patterns with dcmrecv/storescp since\n * dcmpsrcv handles incoming DICOM associations and C-STORE operations.\n *\n * @module events/dcmpsrcv\n */\n\nimport type { EventPattern } from '../parsers/EventPattern';\n\n// ---------------------------------------------------------------------------\n// Event constants (as const, not enum — Rule 3.5)\n// ---------------------------------------------------------------------------\n\n/** Events emitted by dcmpsrcv process output. */\nconst DcmpsrcvEvent = {\n LISTENING: 'LISTENING',\n DATABASE_READY: 'DATABASE_READY',\n ASSOCIATION_RECEIVED: 'ASSOCIATION_RECEIVED',\n ASSOCIATION_ACKNOWLEDGED: 'ASSOCIATION_ACKNOWLEDGED',\n ECHO_REQUEST: 'ECHO_REQUEST',\n C_STORE_REQUEST: 'C_STORE_REQUEST',\n FILE_DELETED: 'FILE_DELETED',\n ASSOCIATION_RELEASE: 'ASSOCIATION_RELEASE',\n ASSOCIATION_ABORTED: 'ASSOCIATION_ABORTED',\n CANNOT_START_LISTENER: 'CANNOT_START_LISTENER',\n CONFIG_ERROR: 'CONFIG_ERROR',\n TERMINATING: 'TERMINATING',\n} as const;\n\ntype DcmpsrcvEventValue = (typeof DcmpsrcvEvent)[keyof typeof DcmpsrcvEvent];\n\n// ---------------------------------------------------------------------------\n// Event data interfaces (all readonly)\n// ---------------------------------------------------------------------------\n\n/** Data for LISTENING event. */\ninterface ReceiverListeningData {\n readonly receiverId: string;\n readonly port: number;\n}\n\n/** Data for DATABASE_READY event. */\ninterface ReceiverDatabaseReadyData {\n readonly directory: string;\n}\n\n/** Data for ASSOCIATION_RECEIVED event. */\ninterface ReceiverAssociationReceivedData {\n readonly peerInfo: string;\n}\n\n/** Data for ASSOCIATION_ACKNOWLEDGED event. */\ninterface ReceiverAssociationAcknowledgedData {\n readonly maxSendPDV: number;\n}\n\n/** Data for ECHO_REQUEST event. */\ninterface ReceiverEchoRequestData {\n readonly messageId: number;\n}\n\n/** Data for C_STORE_REQUEST event. */\ninterface ReceiverCStoreRequestData {\n readonly raw: string;\n}\n\n/** Data for FILE_DELETED event. */\ninterface FileDeletedData {\n readonly filePath: string;\n}\n\n/** Data for CANNOT_START_LISTENER event. */\ninterface ReceiverCannotStartListenerData {\n readonly message: string;\n}\n\n/** Data for CONFIG_ERROR event. */\ninterface ReceiverConfigErrorData {\n readonly message: string;\n}\n\n// ---------------------------------------------------------------------------\n// Regex patterns for dcmpsrcv verbose output\n// ---------------------------------------------------------------------------\n\n/** Event patterns for parsing dcmpsrcv verbose output. */\nconst DCMPSRCV_PATTERNS: readonly EventPattern[] = [\n {\n event: DcmpsrcvEvent.LISTENING,\n pattern: /Receiver\\s{1,20}(\\S+)\\s{1,20}on port\\s{1,20}(\\d+)/,\n processor: (match): ReceiverListeningData => ({\n receiverId: match[1] ?? '',\n port: Number(match[2]),\n }),\n },\n {\n event: DcmpsrcvEvent.DATABASE_READY,\n pattern: /Using database in directory\\s+'([^']+)'/,\n processor: (match): ReceiverDatabaseReadyData => ({\n directory: match[1] ?? '',\n }),\n },\n {\n event: DcmpsrcvEvent.ASSOCIATION_RECEIVED,\n pattern: /Association Received\\s*\\(([^)]+)\\)/,\n processor: (match): ReceiverAssociationReceivedData => ({\n peerInfo: (match[1] ?? '').trim(),\n }),\n },\n {\n event: DcmpsrcvEvent.ASSOCIATION_ACKNOWLEDGED,\n pattern: /Association Acknowledged \\(Max Send PDV:\\s*(\\d+)\\)/,\n processor: (match): ReceiverAssociationAcknowledgedData => ({\n maxSendPDV: Number(match[1]),\n }),\n },\n {\n event: DcmpsrcvEvent.ECHO_REQUEST,\n pattern: /Received Echo SCP RQ:\\s*MsgID\\s+(\\d+)/,\n processor: (match): ReceiverEchoRequestData => ({\n messageId: Number(match[1]),\n }),\n },\n {\n event: DcmpsrcvEvent.C_STORE_REQUEST,\n pattern: /Received Store SCP/i,\n processor: (match): ReceiverCStoreRequestData => ({\n raw: match[0] ?? '',\n }),\n },\n {\n event: DcmpsrcvEvent.FILE_DELETED,\n pattern: /Deleting Image File:\\s{0,20}(.{1,1024})/,\n processor: (match): FileDeletedData => ({\n filePath: (match[1] ?? '').trim(),\n }),\n },\n {\n event: DcmpsrcvEvent.ASSOCIATION_RELEASE,\n pattern: /Association Release/i,\n processor: () => undefined,\n },\n {\n event: DcmpsrcvEvent.ASSOCIATION_ABORTED,\n pattern: /Association Abort/i,\n processor: () => undefined,\n },\n {\n event: DcmpsrcvEvent.CANNOT_START_LISTENER,\n pattern: /cannot listen on port/i,\n processor: (match): ReceiverCannotStartListenerData => ({\n message: match[0] ?? '',\n }),\n },\n {\n event: DcmpsrcvEvent.CONFIG_ERROR,\n pattern: /can't open configuration file|missing configuration file|no application entity title|no or invalid port number/i,\n processor: (match): ReceiverConfigErrorData => ({\n message: match[0] ?? '',\n }),\n },\n {\n event: DcmpsrcvEvent.TERMINATING,\n pattern: /Terminating all receivers/i,\n processor: () => undefined,\n },\n];\n\n/** Events that indicate fatal errors (process should be stopped). */\nconst DCMPSRCV_FATAL_EVENTS: ReadonlySet<string> = new Set([DcmpsrcvEvent.CANNOT_START_LISTENER, DcmpsrcvEvent.CONFIG_ERROR]);\n\nexport { DcmpsrcvEvent, DCMPSRCV_PATTERNS, DCMPSRCV_FATAL_EVENTS };\nexport type {\n DcmpsrcvEventValue,\n ReceiverListeningData,\n ReceiverDatabaseReadyData,\n ReceiverAssociationReceivedData,\n ReceiverAssociationAcknowledgedData,\n ReceiverEchoRequestData,\n ReceiverCStoreRequestData,\n FileDeletedData,\n ReceiverCannotStartListenerData,\n ReceiverConfigErrorData,\n};\n","/**\n * DICOM Viewer Network Receiver wrapping the dcmpsrcv binary.\n *\n * Provides a type-safe, event-driven API for the DICOMscope network\n * receiver component. Accepts incoming DICOM associations for storage\n * and C-ECHO verification.\n *\n * @module servers/Dcmpsrcv\n */\n\nimport { z } from 'zod';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { DcmtkProcess } from '../DcmtkProcess';\nimport type { DcmtkProcessConfig } from '../DcmtkProcess';\nimport { LineParser } from '../parsers/LineParser';\nimport { resolveBinary } from '../tools/_resolveBinary';\nimport { createValidationError } from '../tools/_toolError';\nimport { isSafePath } from '../patterns';\nimport { DCMPSRCV_PATTERNS, DCMPSRCV_FATAL_EVENTS } from '../events/dcmpsrcv';\nimport type {\n ReceiverListeningData,\n ReceiverDatabaseReadyData,\n ReceiverAssociationReceivedData,\n ReceiverAssociationAcknowledgedData,\n ReceiverEchoRequestData,\n ReceiverCStoreRequestData,\n FileDeletedData,\n ReceiverCannotStartListenerData,\n ReceiverConfigErrorData,\n} from '../events/dcmpsrcv';\n\n// ---------------------------------------------------------------------------\n// Event map type\n// ---------------------------------------------------------------------------\n\n/** Typed event map for the Dcmpsrcv server. */\ninterface DcmpsrcvEventMap {\n LISTENING: [ReceiverListeningData];\n DATABASE_READY: [ReceiverDatabaseReadyData];\n ASSOCIATION_RECEIVED: [ReceiverAssociationReceivedData];\n ASSOCIATION_ACKNOWLEDGED: [ReceiverAssociationAcknowledgedData];\n ECHO_REQUEST: [ReceiverEchoRequestData];\n C_STORE_REQUEST: [ReceiverCStoreRequestData];\n FILE_DELETED: [FileDeletedData];\n ASSOCIATION_RELEASE: [];\n ASSOCIATION_ABORTED: [];\n CANNOT_START_LISTENER: [ReceiverCannotStartListenerData];\n CONFIG_ERROR: [ReceiverConfigErrorData];\n TERMINATING: [];\n}\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\n/** Options for creating a Dcmpsrcv server instance. */\ninterface DcmpsrcvOptions {\n /** Path to the dcmpstat configuration file (required). */\n readonly configFile: string;\n /** Receiver identifier from the config file (optional, defaults to first receiver). */\n readonly receiverId?: string | undefined;\n /** Log level override. */\n readonly logLevel?: 'fatal' | 'error' | 'warn' | 'info' | 'debug' | 'trace' | undefined;\n /** Path to a log configuration file. */\n readonly logConfig?: string | undefined;\n /** Timeout for start() to resolve (milliseconds). */\n readonly startTimeoutMs?: number | undefined;\n /** Timeout for graceful drain during stop() (milliseconds). */\n readonly drainTimeoutMs?: number | undefined;\n /** AbortSignal for external cancellation. */\n readonly signal?: AbortSignal | undefined;\n}\n\nconst DcmpsrcvOptionsSchema = z\n .object({\n configFile: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in configFile' }),\n receiverId: z.string().min(1).optional(),\n logLevel: z.enum(['fatal', 'error', 'warn', 'info', 'debug', 'trace']).optional(),\n logConfig: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in logConfig' }).optional(),\n startTimeoutMs: z.number().int().positive().optional(),\n drainTimeoutMs: z.number().int().positive().optional(),\n signal: z.instanceof(AbortSignal).optional(),\n })\n .strict();\n\n// ---------------------------------------------------------------------------\n// Argument builder\n// ---------------------------------------------------------------------------\n\n/** Builds the CLI arguments array from validated options. */\nfunction buildArgs(options: DcmpsrcvOptions): string[] {\n const args: string[] = ['--verbose'];\n\n if (options.logLevel !== undefined) {\n args.push('--log-level', options.logLevel);\n }\n if (options.logConfig !== undefined) {\n args.push('--log-config', options.logConfig);\n }\n\n args.push(options.configFile);\n\n if (options.receiverId !== undefined) {\n args.push(options.receiverId);\n }\n\n return args;\n}\n\n// ---------------------------------------------------------------------------\n// Dcmpsrcv class\n// ---------------------------------------------------------------------------\n\n/**\n * DICOM Viewer Network Receiver wrapping the dcmpsrcv binary.\n *\n * Uses a static `create()` factory because binary resolution is fallible\n * and must complete before the constructor runs.\n *\n * The `start()` method resolves when the LISTENING event is detected\n * (i.e., \"Receiver <id> on port <port>\").\n *\n * @example\n * ```ts\n * const result = Dcmpsrcv.create({ configFile: '/etc/dcmpstat.cfg', receiverId: 'RECEIVE_1' });\n * if (result.ok) {\n * const server = result.value;\n * server.onEvent('LISTENING', (data) => console.log(`Listening on port ${data.port}`));\n * const startResult = await server.start();\n * }\n * ```\n */\nclass Dcmpsrcv extends DcmtkProcess {\n private readonly parser: LineParser;\n private abortSignal: AbortSignal | undefined;\n private abortHandler: (() => void) | undefined;\n\n private constructor(config: DcmtkProcessConfig, parser: LineParser, signal?: AbortSignal) {\n super(config);\n this.parser = parser;\n this.wireParser();\n if (signal !== undefined) {\n this.wireAbortSignal(signal);\n }\n }\n\n /**\n * Registers a typed listener for a dcmpsrcv-specific event.\n *\n * @param event - The event name from DcmpsrcvEventMap\n * @param listener - Callback receiving typed event data\n * @returns this for chaining\n */\n /** Disposes the server and its parser, preventing listener leaks. */\n [Symbol.dispose](): void {\n if (this.abortSignal !== undefined && this.abortHandler !== undefined) {\n this.abortSignal.removeEventListener('abort', this.abortHandler);\n }\n this.parser[Symbol.dispose]();\n super[Symbol.dispose]();\n }\n\n onEvent<K extends keyof DcmpsrcvEventMap>(event: K, listener: (...args: DcmpsrcvEventMap[K]) => void): this {\n return this.on(event as string, listener as never);\n }\n\n /**\n * Registers a listener for when the receiver starts listening.\n *\n * @param listener - Callback receiving listening data (receiver ID and port)\n * @returns this for chaining\n */\n onListening(listener: (...args: DcmpsrcvEventMap['LISTENING']) => void): this {\n return this.onEvent('LISTENING', listener);\n }\n\n /**\n * Registers a listener for incoming C-STORE requests.\n *\n * @param listener - Callback receiving C-STORE request data\n * @returns this for chaining\n */\n onCStoreRequest(listener: (...args: DcmpsrcvEventMap['C_STORE_REQUEST']) => void): this {\n return this.onEvent('C_STORE_REQUEST', listener);\n }\n\n /**\n * Creates a new Dcmpsrcv server instance.\n *\n * @param options - Configuration options for the dcmpsrcv server\n * @returns A Result containing the server instance or a validation/resolution error\n */\n static create(options: DcmpsrcvOptions): Result<Dcmpsrcv> {\n const validation = DcmpsrcvOptionsSchema.safeParse(options);\n if (!validation.success) {\n return err(createValidationError('dcmpsrcv', validation.error));\n }\n\n const binaryResult = resolveBinary('dcmpsrcv');\n if (!binaryResult.ok) {\n return err(binaryResult.error);\n }\n\n const args = buildArgs(options);\n const parser = new LineParser();\n for (const pattern of DCMPSRCV_PATTERNS) {\n const addResult = parser.addPattern(pattern);\n if (!addResult.ok) {\n return err(addResult.error);\n }\n }\n\n const config: DcmtkProcessConfig = {\n binary: binaryResult.value,\n args,\n startTimeoutMs: options.startTimeoutMs,\n drainTimeoutMs: options.drainTimeoutMs,\n isStartedPredicate: line => /Receiver\\s+\\S+\\s+on port/i.test(line),\n };\n\n return ok(new Dcmpsrcv(config, parser, options.signal));\n }\n\n /** Wires the line parser to the process output. */\n private wireParser(): void {\n this.on('line', ({ text }) => {\n this.parser.feed(text);\n });\n\n this.parser.on('match', ({ event, data }) => {\n if (DCMPSRCV_FATAL_EVENTS.has(event)) {\n this.emit('error', { error: new Error(`Fatal: ${event}`), fatal: true });\n void this.stop();\n }\n this.emit(event, data);\n });\n }\n\n /** Wires an AbortSignal to stop the server. */\n private wireAbortSignal(signal: AbortSignal): void {\n if (signal.aborted) {\n void this.stop();\n return;\n }\n this.abortSignal = signal;\n this.abortHandler = (): void => {\n void this.stop();\n };\n signal.addEventListener('abort', this.abortHandler, { once: true });\n }\n}\n\nexport { Dcmpsrcv };\nexport type { DcmpsrcvOptions, DcmpsrcvEventMap };\n","/**\n * Event patterns and types for dcmqrscp output parsing.\n *\n * Defines regex patterns that match DCMTK dcmqrscp (Query/Retrieve SCP)\n * verbose output, along with typed event data interfaces for each event.\n *\n * @module events/dcmqrscp\n */\n\nimport type { EventPattern } from '../parsers/EventPattern';\n\n// ---------------------------------------------------------------------------\n// Event constants (as const, not enum — Rule 3.5)\n// ---------------------------------------------------------------------------\n\n/** Events emitted by dcmqrscp process output. */\nconst DcmqrscpEvent = {\n LISTENING: 'LISTENING',\n ASSOCIATION_RECEIVED: 'ASSOCIATION_RECEIVED',\n ASSOCIATION_ACKNOWLEDGED: 'ASSOCIATION_ACKNOWLEDGED',\n C_FIND_REQUEST: 'C_FIND_REQUEST',\n C_MOVE_REQUEST: 'C_MOVE_REQUEST',\n C_GET_REQUEST: 'C_GET_REQUEST',\n C_STORE_REQUEST: 'C_STORE_REQUEST',\n ASSOCIATION_RELEASE: 'ASSOCIATION_RELEASE',\n ASSOCIATION_ABORTED: 'ASSOCIATION_ABORTED',\n CANNOT_START_LISTENER: 'CANNOT_START_LISTENER',\n} as const;\n\ntype DcmqrscpEventValue = (typeof DcmqrscpEvent)[keyof typeof DcmqrscpEvent];\n\n// ---------------------------------------------------------------------------\n// Event data interfaces (all readonly)\n// ---------------------------------------------------------------------------\n\n/** Data for LISTENING event. */\ninterface QRListeningData {\n readonly port: number;\n}\n\n/** Data for ASSOCIATION_RECEIVED event. */\ninterface QRAssociationReceivedData {\n readonly peerInfo: string;\n}\n\n/** Data for ASSOCIATION_ACKNOWLEDGED event. */\ninterface QRAssociationAcknowledgedData {\n readonly maxSendPDV: number;\n}\n\n/** Data for C_FIND_REQUEST event. */\ninterface QRCFindRequestData {\n readonly raw: string;\n}\n\n/** Data for C_MOVE_REQUEST event. */\ninterface QRCMoveRequestData {\n readonly raw: string;\n}\n\n/** Data for C_GET_REQUEST event. */\ninterface QRCGetRequestData {\n readonly raw: string;\n}\n\n/** Data for C_STORE_REQUEST event. */\ninterface QRCStoreRequestData {\n readonly raw: string;\n}\n\n/** Data for CANNOT_START_LISTENER event. */\ninterface QRCannotStartListenerData {\n readonly message: string;\n}\n\n// ---------------------------------------------------------------------------\n// Regex patterns for dcmqrscp verbose output\n// ---------------------------------------------------------------------------\n\n/** Event patterns for parsing dcmqrscp verbose output. */\nconst DCMQRSCP_PATTERNS: readonly EventPattern[] = [\n {\n event: DcmqrscpEvent.LISTENING,\n pattern: /listening on port\\s{1,20}(\\d+)/i,\n processor: (match): QRListeningData => ({\n port: Number(match[1]),\n }),\n },\n {\n event: DcmqrscpEvent.ASSOCIATION_RECEIVED,\n pattern: /Association Received\\s{0,20}([^\\r\\n]+)/,\n processor: (match): QRAssociationReceivedData => ({\n peerInfo: (match[1] ?? '').trim(),\n }),\n },\n {\n event: DcmqrscpEvent.ASSOCIATION_ACKNOWLEDGED,\n pattern: /Association Acknowledged \\(Max Send PDV:\\s*(\\d+)\\)/,\n processor: (match): QRAssociationAcknowledgedData => ({\n maxSendPDV: Number(match[1]),\n }),\n },\n {\n event: DcmqrscpEvent.C_FIND_REQUEST,\n pattern: /Received Find (?:SCP )?Request/i,\n processor: (match): QRCFindRequestData => ({\n raw: match[0] ?? '',\n }),\n },\n {\n event: DcmqrscpEvent.C_MOVE_REQUEST,\n pattern: /Received Move (?:SCP )?Request/i,\n processor: (match): QRCMoveRequestData => ({\n raw: match[0] ?? '',\n }),\n },\n {\n event: DcmqrscpEvent.C_GET_REQUEST,\n pattern: /Received Get (?:SCP )?Request/i,\n processor: (match): QRCGetRequestData => ({\n raw: match[0] ?? '',\n }),\n },\n {\n event: DcmqrscpEvent.C_STORE_REQUEST,\n pattern: /Received Store (?:SCP )?Request/i,\n processor: (match): QRCStoreRequestData => ({\n raw: match[0] ?? '',\n }),\n },\n {\n event: DcmqrscpEvent.ASSOCIATION_RELEASE,\n pattern: /Association Release/i,\n processor: () => undefined,\n },\n {\n event: DcmqrscpEvent.ASSOCIATION_ABORTED,\n pattern: /Association Abort/i,\n processor: () => undefined,\n },\n {\n event: DcmqrscpEvent.CANNOT_START_LISTENER,\n pattern: /cannot listen|cannot initialise network/i,\n processor: (match): QRCannotStartListenerData => ({\n message: match[0] ?? '',\n }),\n },\n];\n\n/** Events that indicate fatal errors (process should be stopped). */\nconst DCMQRSCP_FATAL_EVENTS: ReadonlySet<string> = new Set([DcmqrscpEvent.CANNOT_START_LISTENER]);\n\nexport { DcmqrscpEvent, DCMQRSCP_PATTERNS, DCMQRSCP_FATAL_EVENTS };\nexport type {\n DcmqrscpEventValue,\n QRListeningData,\n QRAssociationReceivedData,\n QRAssociationAcknowledgedData,\n QRCFindRequestData,\n QRCMoveRequestData,\n QRCGetRequestData,\n QRCStoreRequestData,\n QRCannotStartListenerData,\n};\n","/**\n * DICOM Query/Retrieve SCP server wrapping the dcmqrscp binary.\n *\n * Provides a type-safe, event-driven API for the Q/R SCP that supports\n * C-FIND, C-MOVE, C-GET, and C-STORE operations. Uses a static factory\n * pattern because binary resolution and validation must happen before\n * the constructor call.\n *\n * @module servers/DcmQRSCP\n */\n\nimport { z } from 'zod';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { DcmtkProcess } from '../DcmtkProcess';\nimport type { DcmtkProcessConfig } from '../DcmtkProcess';\nimport { LineParser } from '../parsers/LineParser';\nimport { resolveBinary } from '../tools/_resolveBinary';\nimport { createValidationError } from '../tools/_toolError';\nimport { isSafePath } from '../patterns';\nimport { DCMQRSCP_PATTERNS, DCMQRSCP_FATAL_EVENTS } from '../events/dcmqrscp';\nimport type {\n QRListeningData,\n QRAssociationReceivedData,\n QRAssociationAcknowledgedData,\n QRCFindRequestData,\n QRCMoveRequestData,\n QRCGetRequestData,\n QRCStoreRequestData,\n QRCannotStartListenerData,\n} from '../events/dcmqrscp';\n\n// ---------------------------------------------------------------------------\n// Event map type\n// ---------------------------------------------------------------------------\n\n/** Typed event map for the DcmQRSCP server. */\ninterface DcmQRSCPEventMap {\n LISTENING: [QRListeningData];\n ASSOCIATION_RECEIVED: [QRAssociationReceivedData];\n ASSOCIATION_ACKNOWLEDGED: [QRAssociationAcknowledgedData];\n C_FIND_REQUEST: [QRCFindRequestData];\n C_MOVE_REQUEST: [QRCMoveRequestData];\n C_GET_REQUEST: [QRCGetRequestData];\n C_STORE_REQUEST: [QRCStoreRequestData];\n ASSOCIATION_RELEASE: [];\n ASSOCIATION_ABORTED: [];\n CANNOT_START_LISTENER: [QRCannotStartListenerData];\n}\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\n/** Options for creating a DcmQRSCP server instance. */\ninterface DcmQRSCPOptions {\n /** Path to the dcmqrscp configuration file (required). */\n readonly configFile: string;\n /** Override port from config (positional arg). */\n readonly port?: number | undefined;\n /** Single-process mode (-s flag, recommended on Windows). */\n readonly singleProcess?: boolean | undefined;\n /** Check Find responses (-XF). */\n readonly checkFind?: boolean | undefined;\n /** Check Move responses (-XM). */\n readonly checkMove?: boolean | undefined;\n /** Disable C-GET support (--disable-get). */\n readonly disableGet?: boolean | undefined;\n /** Maximum PDU receive size. */\n readonly maxPdu?: number | undefined;\n /** ACSE timeout in seconds (passed to DCMTK as-is). */\n readonly acseTimeout?: number | undefined;\n /** DIMSE timeout in seconds (passed to DCMTK as-is). */\n readonly dimseTimeout?: number | undefined;\n /** Enable verbose mode (default true for event detection). */\n readonly verbose?: boolean | undefined;\n /** Timeout for start() to resolve (milliseconds). */\n readonly startTimeoutMs?: number | undefined;\n /** Timeout for graceful drain during stop() (milliseconds). */\n readonly drainTimeoutMs?: number | undefined;\n /** AbortSignal for external cancellation. */\n readonly signal?: AbortSignal | undefined;\n}\n\nconst DcmQRSCPOptionsSchema = z\n .object({\n configFile: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in configFile' }),\n port: z.number().int().min(1).max(65535).optional(),\n singleProcess: z.boolean().optional(),\n checkFind: z.boolean().optional(),\n checkMove: z.boolean().optional(),\n disableGet: z.boolean().optional(),\n maxPdu: z.number().int().min(4096).max(131072).optional(),\n acseTimeout: z.number().int().positive().optional(),\n dimseTimeout: z.number().int().positive().optional(),\n verbose: z.boolean().optional(),\n startTimeoutMs: z.number().int().positive().optional(),\n drainTimeoutMs: z.number().int().positive().optional(),\n signal: z.instanceof(AbortSignal).optional(),\n })\n .strict();\n\n// ---------------------------------------------------------------------------\n// Argument builder\n// ---------------------------------------------------------------------------\n\n/** Builds the CLI arguments array from validated options. */\nfunction buildArgs(options: DcmQRSCPOptions): string[] {\n const args: string[] = [];\n\n if (options.verbose !== false) {\n args.push('--verbose');\n }\n\n args.push('--config', options.configFile);\n\n if (options.singleProcess === true) {\n args.push('-s');\n }\n if (options.checkFind === true) {\n args.push('-XF');\n }\n if (options.checkMove === true) {\n args.push('-XM');\n }\n if (options.disableGet === true) {\n args.push('--disable-get');\n }\n\n buildNetworkArgs(args, options);\n\n if (options.port !== undefined) {\n args.push(String(options.port));\n }\n\n return args;\n}\n\n/** Appends network-related CLI flags. */\nfunction buildNetworkArgs(args: string[], options: DcmQRSCPOptions): void {\n if (options.maxPdu !== undefined) {\n args.push('--max-pdu', String(options.maxPdu));\n }\n if (options.acseTimeout !== undefined) {\n args.push('--acse-timeout', String(options.acseTimeout));\n }\n if (options.dimseTimeout !== undefined) {\n args.push('--dimse-timeout', String(options.dimseTimeout));\n }\n}\n\n// ---------------------------------------------------------------------------\n// DcmQRSCP class\n// ---------------------------------------------------------------------------\n\n/**\n * DICOM Query/Retrieve SCP server wrapping the dcmqrscp binary.\n *\n * Uses a static `create()` factory because binary resolution is fallible\n * and must complete before the constructor runs.\n *\n * @example\n * ```ts\n * const result = DcmQRSCP.create({ configFile: '/etc/dcmqrscp.cfg', port: 11112 });\n * if (result.ok) {\n * const server = result.value;\n * server.onEvent('C_FIND_REQUEST', (data) => console.log('Find:', data.raw));\n * const startResult = await server.start();\n * }\n * ```\n */\nclass DcmQRSCP extends DcmtkProcess {\n private readonly parser: LineParser;\n private abortSignal: AbortSignal | undefined;\n private abortHandler: (() => void) | undefined;\n\n private constructor(config: DcmtkProcessConfig, parser: LineParser, signal?: AbortSignal) {\n super(config);\n this.parser = parser;\n this.wireParser();\n if (signal !== undefined) {\n this.wireAbortSignal(signal);\n }\n }\n\n /** Disposes the server and its parser, preventing listener leaks. */\n [Symbol.dispose](): void {\n if (this.abortSignal !== undefined && this.abortHandler !== undefined) {\n this.abortSignal.removeEventListener('abort', this.abortHandler);\n }\n this.parser[Symbol.dispose]();\n super[Symbol.dispose]();\n }\n\n /**\n * Registers a typed listener for a dcmqrscp-specific event.\n *\n * @param event - The event name from DcmQRSCPEventMap\n * @param listener - Callback receiving typed event data\n * @returns this for chaining\n */\n onEvent<K extends keyof DcmQRSCPEventMap>(event: K, listener: (...args: DcmQRSCPEventMap[K]) => void): this {\n return this.on(event as string, listener as never);\n }\n\n /**\n * Registers a listener for incoming C-FIND requests.\n *\n * @param listener - Callback receiving C-FIND request data\n * @returns this for chaining\n */\n onCFindRequest(listener: (...args: DcmQRSCPEventMap['C_FIND_REQUEST']) => void): this {\n return this.onEvent('C_FIND_REQUEST', listener);\n }\n\n /**\n * Registers a listener for incoming C-MOVE requests.\n *\n * @param listener - Callback receiving C-MOVE request data\n * @returns this for chaining\n */\n onCMoveRequest(listener: (...args: DcmQRSCPEventMap['C_MOVE_REQUEST']) => void): this {\n return this.onEvent('C_MOVE_REQUEST', listener);\n }\n\n /**\n * Creates a new DcmQRSCP server instance.\n *\n * @param options - Configuration options for the dcmqrscp server\n * @returns A Result containing the server instance or a validation/resolution error\n */\n static create(options: DcmQRSCPOptions): Result<DcmQRSCP> {\n const validation = DcmQRSCPOptionsSchema.safeParse(options);\n if (!validation.success) {\n return err(createValidationError('dcmqrscp', validation.error));\n }\n\n const binaryResult = resolveBinary('dcmqrscp');\n if (!binaryResult.ok) {\n return err(binaryResult.error);\n }\n\n const args = buildArgs(options);\n const parser = new LineParser();\n for (const pattern of DCMQRSCP_PATTERNS) {\n const addResult = parser.addPattern(pattern);\n if (!addResult.ok) {\n return err(addResult.error);\n }\n }\n\n // dcmqrscp v3.7.0+ does not print a \"listening on port\" message even\n // in verbose/debug mode, so we resolve on spawn (like StoreSCP) and\n // rely on a short warmup delay in callers that need the socket ready.\n const config: DcmtkProcessConfig = {\n binary: binaryResult.value,\n args,\n startTimeoutMs: options.startTimeoutMs,\n drainTimeoutMs: options.drainTimeoutMs,\n };\n\n return ok(new DcmQRSCP(config, parser, options.signal));\n }\n\n /** Wires the line parser to the process output. */\n private wireParser(): void {\n this.on('line', ({ text }) => {\n this.parser.feed(text);\n });\n\n this.parser.on('match', ({ event, data }) => {\n if (DCMQRSCP_FATAL_EVENTS.has(event)) {\n this.emit('error', { error: new Error(`Fatal: ${event}`), fatal: true });\n void this.stop();\n }\n this.emit(event, data);\n });\n }\n\n /** Wires an AbortSignal to stop the server. */\n private wireAbortSignal(signal: AbortSignal): void {\n if (signal.aborted) {\n void this.stop();\n return;\n }\n this.abortSignal = signal;\n this.abortHandler = (): void => {\n void this.stop();\n };\n signal.addEventListener('abort', this.abortHandler, { once: true });\n }\n}\n\nexport { DcmQRSCP };\nexport type { DcmQRSCPOptions, DcmQRSCPEventMap };\n","/**\n * Event patterns and types for wlmscpfs output parsing.\n *\n * Defines regex patterns that match DCMTK wlmscpfs (Worklist Management SCP)\n * verbose output, along with typed event data interfaces for each event.\n *\n * @module events/wlmscpfs\n */\n\nimport type { EventPattern } from '../parsers/EventPattern';\n\n// ---------------------------------------------------------------------------\n// Event constants (as const, not enum — Rule 3.5)\n// ---------------------------------------------------------------------------\n\n/** Events emitted by wlmscpfs process output. */\nconst WlmscpfsEvent = {\n LISTENING: 'LISTENING',\n ASSOCIATION_RECEIVED: 'ASSOCIATION_RECEIVED',\n ASSOCIATION_ACKNOWLEDGED: 'ASSOCIATION_ACKNOWLEDGED',\n C_FIND_REQUEST: 'C_FIND_REQUEST',\n ASSOCIATION_RELEASE: 'ASSOCIATION_RELEASE',\n ASSOCIATION_ABORTED: 'ASSOCIATION_ABORTED',\n ECHO_REQUEST: 'ECHO_REQUEST',\n CANNOT_START_LISTENER: 'CANNOT_START_LISTENER',\n} as const;\n\ntype WlmscpfsEventValue = (typeof WlmscpfsEvent)[keyof typeof WlmscpfsEvent];\n\n// ---------------------------------------------------------------------------\n// Event data interfaces (all readonly)\n// ---------------------------------------------------------------------------\n\n/** Data for LISTENING event. */\ninterface WlmListeningData {\n readonly port: number;\n}\n\n/** Data for ASSOCIATION_RECEIVED event. */\ninterface WlmAssociationReceivedData {\n readonly peerInfo: string;\n}\n\n/** Data for ASSOCIATION_ACKNOWLEDGED event. */\ninterface WlmAssociationAcknowledgedData {\n readonly maxSendPDV: number;\n}\n\n/** Data for C_FIND_REQUEST event. */\ninterface WlmCFindRequestData {\n readonly raw: string;\n}\n\n/** Data for CANNOT_START_LISTENER event. */\ninterface WlmCannotStartListenerData {\n readonly message: string;\n}\n\n// ---------------------------------------------------------------------------\n// Regex patterns for wlmscpfs verbose output\n// ---------------------------------------------------------------------------\n\n/** Event patterns for parsing wlmscpfs verbose output. */\nconst WLMSCPFS_PATTERNS: readonly EventPattern[] = [\n {\n event: WlmscpfsEvent.LISTENING,\n pattern: /listening on port\\s{1,20}(\\d+)/i,\n processor: (match): WlmListeningData => ({\n port: Number(match[1]),\n }),\n },\n {\n event: WlmscpfsEvent.ASSOCIATION_RECEIVED,\n pattern: /Association Received\\s{0,20}([^\\r\\n]+)/,\n processor: (match): WlmAssociationReceivedData => ({\n peerInfo: (match[1] ?? '').trim(),\n }),\n },\n {\n event: WlmscpfsEvent.ASSOCIATION_ACKNOWLEDGED,\n pattern: /Association Acknowledged \\(Max Send PDV:\\s*(\\d+)\\)/,\n processor: (match): WlmAssociationAcknowledgedData => ({\n maxSendPDV: Number(match[1]),\n }),\n },\n {\n event: WlmscpfsEvent.C_FIND_REQUEST,\n pattern: /Received (?:C-FIND|Find) Request/i,\n processor: (match): WlmCFindRequestData => ({\n raw: match[0] ?? '',\n }),\n },\n {\n event: WlmscpfsEvent.ASSOCIATION_RELEASE,\n pattern: /Association Release/i,\n processor: () => undefined,\n },\n {\n event: WlmscpfsEvent.ASSOCIATION_ABORTED,\n pattern: /Association Abort/i,\n processor: () => undefined,\n },\n {\n event: WlmscpfsEvent.ECHO_REQUEST,\n pattern: /Received (?:C-ECHO|Echo) Request/i,\n processor: () => undefined,\n },\n {\n event: WlmscpfsEvent.CANNOT_START_LISTENER,\n pattern: /cannot listen|cannot initialise network/i,\n processor: (match): WlmCannotStartListenerData => ({\n message: match[0] ?? '',\n }),\n },\n];\n\n/** Events that indicate fatal errors (process should be stopped). */\nconst WLMSCPFS_FATAL_EVENTS: ReadonlySet<string> = new Set([WlmscpfsEvent.CANNOT_START_LISTENER]);\n\nexport { WlmscpfsEvent, WLMSCPFS_PATTERNS, WLMSCPFS_FATAL_EVENTS };\nexport type {\n WlmscpfsEventValue,\n WlmListeningData,\n WlmAssociationReceivedData,\n WlmAssociationAcknowledgedData,\n WlmCFindRequestData,\n WlmCannotStartListenerData,\n};\n","/**\n * DICOM Worklist Management SCP server wrapping the wlmscpfs binary.\n *\n * Provides a type-safe, event-driven API for serving worklist data\n * from a file-system based database. Uses a static factory pattern\n * because binary resolution and validation must happen before the\n * constructor call.\n *\n * @module servers/Wlmscpfs\n */\n\nimport { z } from 'zod';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { DcmtkProcess } from '../DcmtkProcess';\nimport type { DcmtkProcessConfig } from '../DcmtkProcess';\nimport { LineParser } from '../parsers/LineParser';\nimport { resolveBinary } from '../tools/_resolveBinary';\nimport { createValidationError } from '../tools/_toolError';\nimport { isSafePath } from '../patterns';\nimport { WLMSCPFS_PATTERNS, WLMSCPFS_FATAL_EVENTS } from '../events/wlmscpfs';\nimport type {\n WlmListeningData,\n WlmAssociationReceivedData,\n WlmAssociationAcknowledgedData,\n WlmCFindRequestData,\n WlmCannotStartListenerData,\n} from '../events/wlmscpfs';\n\n// ---------------------------------------------------------------------------\n// Event map type\n// ---------------------------------------------------------------------------\n\n/** Typed event map for the Wlmscpfs server. */\ninterface WlmscpfsEventMap {\n LISTENING: [WlmListeningData];\n ASSOCIATION_RECEIVED: [WlmAssociationReceivedData];\n ASSOCIATION_ACKNOWLEDGED: [WlmAssociationAcknowledgedData];\n C_FIND_REQUEST: [WlmCFindRequestData];\n ASSOCIATION_RELEASE: [];\n ASSOCIATION_ABORTED: [];\n ECHO_REQUEST: [];\n CANNOT_START_LISTENER: [WlmCannotStartListenerData];\n}\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\n/** Options for creating a Wlmscpfs server instance. */\ninterface WlmscpfsOptions {\n /** Port to listen on (required, positional arg). */\n readonly port: number;\n /** Worklist data directory (required, -dfp flag). */\n readonly worklistDirectory: string;\n /** Enable file rejection (default true). Maps to -efr / -dfr. */\n readonly enableFileRejection?: boolean | undefined;\n /** Maximum PDU receive size. */\n readonly maxPdu?: number | undefined;\n /** ACSE timeout in seconds (passed to DCMTK as-is). */\n readonly acseTimeout?: number | undefined;\n /** DIMSE timeout in seconds (passed to DCMTK as-is). */\n readonly dimseTimeout?: number | undefined;\n /** Maximum simultaneous associations. */\n readonly maxAssociations?: number | undefined;\n /** Enable verbose mode (default true for event detection). */\n readonly verbose?: boolean | undefined;\n /** Timeout for start() to resolve (milliseconds). */\n readonly startTimeoutMs?: number | undefined;\n /** Timeout for graceful drain during stop() (milliseconds). */\n readonly drainTimeoutMs?: number | undefined;\n /** AbortSignal for external cancellation. */\n readonly signal?: AbortSignal | undefined;\n}\n\nconst WlmscpfsOptionsSchema = z\n .object({\n port: z.number().int().min(1).max(65535),\n worklistDirectory: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in worklistDirectory' }),\n enableFileRejection: z.boolean().optional(),\n maxPdu: z.number().int().min(4096).max(131072).optional(),\n acseTimeout: z.number().int().positive().optional(),\n dimseTimeout: z.number().int().positive().optional(),\n maxAssociations: z.number().int().positive().optional(),\n verbose: z.boolean().optional(),\n startTimeoutMs: z.number().int().positive().optional(),\n drainTimeoutMs: z.number().int().positive().optional(),\n signal: z.instanceof(AbortSignal).optional(),\n })\n .strict();\n\n// ---------------------------------------------------------------------------\n// Argument builder\n// ---------------------------------------------------------------------------\n\n/** Builds the CLI arguments array from validated options. */\nfunction buildArgs(options: WlmscpfsOptions): string[] {\n const args: string[] = [];\n\n if (options.verbose !== false) {\n args.push('--verbose');\n }\n\n args.push('-dfp', options.worklistDirectory);\n\n if (options.enableFileRejection === false) {\n args.push('-dfr');\n } else {\n args.push('-efr');\n }\n\n buildNetworkArgs(args, options);\n\n args.push(String(options.port));\n\n return args;\n}\n\n/** Appends network-related CLI flags. */\nfunction buildNetworkArgs(args: string[], options: WlmscpfsOptions): void {\n if (options.maxPdu !== undefined) {\n args.push('--max-pdu', String(options.maxPdu));\n }\n if (options.acseTimeout !== undefined) {\n args.push('--acse-timeout', String(options.acseTimeout));\n }\n if (options.dimseTimeout !== undefined) {\n args.push('--dimse-timeout', String(options.dimseTimeout));\n }\n if (options.maxAssociations !== undefined) {\n args.push('--max-associations', String(options.maxAssociations));\n }\n}\n\n// ---------------------------------------------------------------------------\n// Wlmscpfs class\n// ---------------------------------------------------------------------------\n\n/**\n * DICOM Worklist Management SCP server wrapping the wlmscpfs binary.\n *\n * Uses a static `create()` factory because binary resolution is fallible\n * and must complete before the constructor runs.\n *\n * Note: wlmscpfs does not print a reliable \"listening\" message in all\n * DCMTK versions, so `start()` resolves on spawn (like StoreSCP).\n *\n * @example\n * ```ts\n * const result = Wlmscpfs.create({ port: 2005, worklistDirectory: '/var/worklists' });\n * if (result.ok) {\n * const server = result.value;\n * server.onEvent('C_FIND_REQUEST', (data) => console.log('Find:', data.raw));\n * const startResult = await server.start();\n * }\n * ```\n */\nclass Wlmscpfs extends DcmtkProcess {\n private readonly parser: LineParser;\n private abortSignal: AbortSignal | undefined;\n private abortHandler: (() => void) | undefined;\n\n private constructor(config: DcmtkProcessConfig, parser: LineParser, signal?: AbortSignal) {\n super(config);\n this.parser = parser;\n this.wireParser();\n if (signal !== undefined) {\n this.wireAbortSignal(signal);\n }\n }\n\n /** Disposes the server and its parser, preventing listener leaks. */\n [Symbol.dispose](): void {\n if (this.abortSignal !== undefined && this.abortHandler !== undefined) {\n this.abortSignal.removeEventListener('abort', this.abortHandler);\n }\n this.parser[Symbol.dispose]();\n super[Symbol.dispose]();\n }\n\n /**\n * Registers a typed listener for a wlmscpfs-specific event.\n *\n * @param event - The event name from WlmscpfsEventMap\n * @param listener - Callback receiving typed event data\n * @returns this for chaining\n */\n onEvent<K extends keyof WlmscpfsEventMap>(event: K, listener: (...args: WlmscpfsEventMap[K]) => void): this {\n return this.on(event as string, listener as never);\n }\n\n /**\n * Registers a listener for incoming C-FIND requests.\n *\n * @param listener - Callback receiving C-FIND request data\n * @returns this for chaining\n */\n onCFindRequest(listener: (...args: WlmscpfsEventMap['C_FIND_REQUEST']) => void): this {\n return this.onEvent('C_FIND_REQUEST', listener);\n }\n\n /**\n * Registers a listener for when the server starts listening.\n *\n * @param listener - Callback receiving listening data (port)\n * @returns this for chaining\n */\n onListening(listener: (...args: WlmscpfsEventMap['LISTENING']) => void): this {\n return this.onEvent('LISTENING', listener);\n }\n\n /**\n * Creates a new Wlmscpfs server instance.\n *\n * @param options - Configuration options for the wlmscpfs server\n * @returns A Result containing the server instance or a validation/resolution error\n */\n static create(options: WlmscpfsOptions): Result<Wlmscpfs> {\n const validation = WlmscpfsOptionsSchema.safeParse(options);\n if (!validation.success) {\n return err(createValidationError('wlmscpfs', validation.error));\n }\n\n const binaryResult = resolveBinary('wlmscpfs');\n if (!binaryResult.ok) {\n return err(binaryResult.error);\n }\n\n const args = buildArgs(options);\n const parser = new LineParser();\n for (const pattern of WLMSCPFS_PATTERNS) {\n const addResult = parser.addPattern(pattern);\n if (!addResult.ok) {\n return err(addResult.error);\n }\n }\n\n const config: DcmtkProcessConfig = {\n binary: binaryResult.value,\n args,\n startTimeoutMs: options.startTimeoutMs,\n drainTimeoutMs: options.drainTimeoutMs,\n // wlmscpfs doesn't reliably print \"listening\" — resolve on spawn\n };\n\n return ok(new Wlmscpfs(config, parser, options.signal));\n }\n\n /** Wires the line parser to the process output. */\n private wireParser(): void {\n this.on('line', ({ text }) => {\n this.parser.feed(text);\n });\n\n this.parser.on('match', ({ event, data }) => {\n if (WLMSCPFS_FATAL_EVENTS.has(event)) {\n this.emit('error', { error: new Error(`Fatal: ${event}`), fatal: true });\n void this.stop();\n }\n this.emit(event, data);\n });\n }\n\n /** Wires an AbortSignal to stop the server. */\n private wireAbortSignal(signal: AbortSignal): void {\n if (signal.aborted) {\n void this.stop();\n return;\n }\n this.abortSignal = signal;\n this.abortHandler = (): void => {\n void this.stop();\n };\n signal.addEventListener('abort', this.abortHandler, { once: true });\n }\n}\n\nexport { Wlmscpfs };\nexport type { WlmscpfsOptions, WlmscpfsEventMap };\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/constants.ts","../src/DcmtkProcess.ts","../src/parsers/LineParser.ts","../src/patterns.ts","../src/findDcmtkPath.ts","../src/tools/_resolveBinary.ts","../src/tools/_toolError.ts","../src/events/dcmrecv.ts","../src/servers/AssociationTracker.ts","../src/servers/Dcmrecv.ts","../src/events/storescp.ts","../src/servers/StoreSCP.ts","../src/brands.ts","../src/dicom/tagPath.ts","../src/dicom/ChangeSet.ts","../src/dicom/DicomDataset.ts","../src/exec.ts","../src/tools/_xmlToJson.ts","../src/tools/_repairJson.ts","../src/tools/dcm2json.ts","../src/tools/dcmodify.ts","../src/dicom/_fileHelpers.ts","../src/dicom/DicomInstance.ts","../src/servers/DicomReceiver.ts","../src/events/dcmprscp.ts","../src/servers/DcmprsCP.ts","../src/events/dcmpsrcv.ts","../src/servers/Dcmpsrcv.ts","../src/events/dcmqrscp.ts","../src/servers/DcmQRSCP.ts","../src/events/wlmscpfs.ts","../src/servers/Wlmscpfs.ts"],"names":["EventEmitter","stderr","isWindows","binaryName","join","path","parser","z","buildArgs","kill","spawn","VERBOSITY_FLAGS","stat","buildNetworkArgs"],"mappings":"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","file":"servers.js","sourcesContent":["/**\n * Represents the outcome of an operation that can succeed or fail.\n *\n * @typeParam T - The type of the success value\n * @typeParam E - The type of the error (defaults to Error)\n *\n * @example\n * ```ts\n * function divide(a: number, b: number): Result<number> {\n * if (b === 0) {\n * return err(new Error('Division by zero'));\n * }\n * return ok(a / b);\n * }\n *\n * const result = divide(10, 2);\n * if (result.ok) {\n * console.log(result.value); // 5\n * } else {\n * console.error(result.error.message);\n * }\n * ```\n */\ntype Result<T, E = Error> = { readonly ok: true; readonly value: T } | { readonly ok: false; readonly error: E };\n\n/**\n * Creates a successful Result containing the given value.\n *\n * @param value - The success value to wrap\n * @returns A Result representing success\n *\n * @example\n * ```ts\n * const result = ok(42);\n * // result.ok === true, result.value === 42\n * ```\n */\nfunction ok<T>(value: T): Result<T, never> {\n return { ok: true, value };\n}\n\n/**\n * Creates a failed Result containing the given error.\n *\n * @param error - The error to wrap\n * @returns A Result representing failure\n *\n * @example\n * ```ts\n * const result = err(new Error('not found'));\n * // result.ok === false, result.error.message === 'not found'\n * ```\n */\nfunction err<E>(error: E): Result<never, E> {\n return { ok: false, error };\n}\n\n/**\n * Exhaustive check helper for discriminated unions and switch statements.\n * Calling this in a default case ensures all variants are handled at compile time.\n *\n * @param x - A value that should be of type `never` if all cases are handled\n * @returns Never returns; always throws\n * @throws Always throws an Error indicating an unhandled case\n *\n * @example\n * ```ts\n * type Shape = { kind: 'circle' } | { kind: 'square' };\n *\n * function area(shape: Shape): number {\n * switch (shape.kind) {\n * case 'circle': return Math.PI;\n * case 'square': return 1;\n * default: assertUnreachable(shape);\n * }\n * }\n * ```\n */\nfunction assertUnreachable(x: never): never {\n throw new Error(`Exhaustive check failed: ${JSON.stringify(x)}`);\n}\n\n// ---------------------------------------------------------------------------\n// Process result types (Rule 7.1: immutable)\n// ---------------------------------------------------------------------------\n\n/**\n * The result of executing a short-lived DCMTK binary.\n * All properties are readonly to enforce immutability.\n */\ninterface DcmtkProcessResult {\n /** The captured stdout output from the process. */\n readonly stdout: string;\n /** The captured stderr output from the process. */\n readonly stderr: string;\n /** The exit code of the process (0 typically means success). */\n readonly exitCode: number;\n}\n\n// ---------------------------------------------------------------------------\n// Common option types (Rule 8.4: options objects for > 4 params)\n// ---------------------------------------------------------------------------\n\n/**\n * Options for short-lived DCMTK process execution.\n * Provides configurable timeout and abort support per Rule 4.2.\n */\ninterface ExecOptions {\n /** Working directory for the child process. */\n readonly cwd?: string | undefined;\n /** Timeout in milliseconds. Defaults to DEFAULT_TIMEOUT_MS. */\n readonly timeoutMs?: number | undefined;\n /** AbortSignal for external cancellation. */\n readonly signal?: AbortSignal | undefined;\n}\n\n/**\n * Options for spawning a DCMTK process with user-supplied arguments.\n * Uses spawn() instead of exec() to avoid shell injection (Rule 7.4).\n */\ninterface SpawnOptions extends ExecOptions {\n /** Additional environment variables merged with process.env. */\n readonly env?: Readonly<Record<string, string>> | undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Event types (Rule 8.3: discriminated unions)\n// ---------------------------------------------------------------------------\n\n/**\n * Line source discriminant for output parsing.\n */\ntype LineSource = 'stdout' | 'stderr';\n\n/**\n * A single line of output from a DCMTK process.\n */\ninterface ProcessLine {\n readonly source: LineSource;\n readonly text: string;\n}\n\n// ---------------------------------------------------------------------------\n// Result utility functions\n// ---------------------------------------------------------------------------\n\n/**\n * Transforms the success value of a Result, passing through errors unchanged.\n *\n * @param result - The Result to transform\n * @param fn - The transformation function\n * @returns A new Result with the transformed value, or the original error\n *\n * @example\n * ```ts\n * const result = ok(42);\n * const doubled = mapResult(result, x => x * 2);\n * // doubled.ok === true, doubled.value === 84\n * ```\n */\nfunction mapResult<T, U>(result: Result<T>, fn: (value: T) => U): Result<U> {\n if (result.ok) {\n return ok(fn(result.value));\n }\n return result;\n}\n\n/**\n * Extracts the success type from a Result.\n * Useful for extracting branded types from factory function returns.\n *\n * @example\n * ```ts\n * type Tag = ResultValue<ReturnType<typeof createDicomTag>>; // DicomTag\n * ```\n */\ntype ResultValue<R> = R extends Result<infer T> ? T : never;\n\nexport { ok, err, assertUnreachable, mapResult };\nexport type { Result, ResultValue, DcmtkProcessResult, ExecOptions, SpawnOptions, LineSource, ProcessLine };\n","/**\n * Application-wide constants.\n *\n * All values use `as const` assertions per Rule 3.5 (no traditional enums).\n * All bounds are documented per Rule 8.1 (bounded loops/buffers).\n *\n * @module constants\n */\n\n// ---------------------------------------------------------------------------\n// Timeouts (Rule 4.2: mandatory timeouts on all async operations)\n// ---------------------------------------------------------------------------\n\n/** Default timeout for short-lived process execution (30 seconds). */\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\n/** Default timeout for long-lived process startup (10 seconds). */\nconst DEFAULT_START_TIMEOUT_MS = 10_000;\n\n/** Default timeout for graceful shutdown drain (5 seconds). */\nconst DEFAULT_DRAIN_TIMEOUT_MS = 5_000;\n\n/** Default timeout for multi-line block accumulation in line parser (1 second). */\nconst DEFAULT_BLOCK_TIMEOUT_MS = 1_000;\n\n// ---------------------------------------------------------------------------\n// DICOM network constants\n// ---------------------------------------------------------------------------\n\n/** DICOM protocol default PDU sizes. */\nconst PDU_SIZE = {\n /** Default maximum PDU receive size (16 KB). */\n DEFAULT: 16_384,\n /** Minimum allowed PDU size (4 KB). */\n MIN: 4_096,\n /** Maximum allowed PDU size (128 KB). */\n MAX: 131_072,\n} as const;\n\n/** Default DICOM port used by DCMTK tools. */\nconst DEFAULT_DICOM_PORT = 104;\n\n// ---------------------------------------------------------------------------\n// Platform-specific known DCMTK install paths\n// ---------------------------------------------------------------------------\n\n/** Known DCMTK binary locations on Windows. */\nconst WINDOWS_SEARCH_PATHS = ['C:\\\\Program Files\\\\DCMTK\\\\bin', 'C:\\\\Program Files (x86)\\\\DCMTK\\\\bin', 'C:\\\\ProgramData\\\\chocolatey\\\\bin'] as const;\n\n/** Known DCMTK binary locations on Unix/macOS. */\nconst UNIX_SEARCH_PATHS = ['/usr/local/bin', '/usr/bin', '/opt/local/bin', '/opt/homebrew/bin'] as const;\n\n// ---------------------------------------------------------------------------\n// Required DCMTK binaries (minimum set for core functionality)\n// ---------------------------------------------------------------------------\n\n/** Binaries that must be present for the library to function. */\nconst REQUIRED_BINARIES = ['dcm2json', 'dcm2xml', 'dcmodify', 'dcmdump', 'dcmrecv', 'dcmsend', 'echoscu'] as const;\n\n// ---------------------------------------------------------------------------\n// Bounded limits (Rule 8.1: all loops and buffers must have upper bounds)\n// ---------------------------------------------------------------------------\n\n/** Maximum lines accumulated in multi-line block parser. */\nconst MAX_BLOCK_LINES = 1_000;\n\n/** Maximum number of event patterns a line parser can hold. */\nconst MAX_EVENT_PATTERNS = 200;\n\n/** Maximum loop iterations for iterative traversal (e.g., nested sequences). */\nconst MAX_TRAVERSAL_DEPTH = 50;\n\n/** Maximum number of operations (modifications + erasures) in a single ChangeSet. */\nconst MAX_CHANGESET_OPERATIONS = 10_000;\n\n/** Maximum bytes allowed for stdout + stderr buffering (100 MB). */\nconst MAX_OUTPUT_BYTES = 100 * 1024 * 1024;\n\nexport {\n DEFAULT_TIMEOUT_MS,\n DEFAULT_START_TIMEOUT_MS,\n DEFAULT_DRAIN_TIMEOUT_MS,\n DEFAULT_BLOCK_TIMEOUT_MS,\n PDU_SIZE,\n DEFAULT_DICOM_PORT,\n WINDOWS_SEARCH_PATHS,\n UNIX_SEARCH_PATHS,\n REQUIRED_BINARIES,\n MAX_BLOCK_LINES,\n MAX_EVENT_PATTERNS,\n MAX_TRAVERSAL_DEPTH,\n MAX_CHANGESET_OPERATIONS,\n MAX_OUTPUT_BYTES,\n};\n","/**\n * Base class for long-lived DCMTK processes (servers).\n *\n * Manages spawning, line-by-line output buffering, typed event emission,\n * lifecycle (start/stop), mandatory timeouts, and graceful shutdown.\n *\n * Implements `Disposable` for deterministic cleanup (Rule 5.1).\n *\n * @module DcmtkProcess\n */\n\nimport { EventEmitter } from 'node:events';\nimport { spawn } from 'node:child_process';\nimport type { ChildProcess } from 'node:child_process';\nimport { stderr } from 'stderr-lib';\nimport kill from 'tree-kill';\nimport type { Result, LineSource } from './types';\nimport { ok, err } from './types';\nimport { DEFAULT_START_TIMEOUT_MS, DEFAULT_DRAIN_TIMEOUT_MS, MAX_OUTPUT_BYTES } from './constants';\n\n// ---------------------------------------------------------------------------\n// Event types\n// ---------------------------------------------------------------------------\n\n/** Events emitted by a DcmtkProcess. */\ninterface DcmtkProcessEventMap {\n started: [];\n stopped: [{ readonly reason: string }];\n error: [{ readonly error: Error; readonly fatal: boolean }];\n line: [{ readonly source: LineSource; readonly text: string }];\n}\n\n/** Configuration for a DcmtkProcess instance. */\ninterface DcmtkProcessConfig {\n /** Full path to the DCMTK binary. */\n readonly binary: string;\n /** Command-line arguments. */\n readonly args: readonly string[];\n /** Working directory. */\n readonly cwd?: string | undefined;\n /** Timeout for start() to resolve, in milliseconds. */\n readonly startTimeoutMs?: number | undefined;\n /** Timeout for graceful drain during stop(), in milliseconds. */\n readonly drainTimeoutMs?: number | undefined;\n /**\n * A function that inspects each output line and returns `true` when\n * the process is considered \"started\" (e.g., \"listening on port X\").\n * If not provided, start() resolves immediately after spawn.\n */\n readonly isStartedPredicate?: ((line: string) => boolean) | undefined;\n}\n\n// ---------------------------------------------------------------------------\n// State enum (as const, not traditional enum — Rule 3.5)\n// ---------------------------------------------------------------------------\n\nconst ProcessState = {\n IDLE: 'IDLE',\n STARTING: 'STARTING',\n RUNNING: 'RUNNING',\n STOPPING: 'STOPPING',\n STOPPED: 'STOPPED',\n} as const;\n\ntype ProcessStateValue = (typeof ProcessState)[keyof typeof ProcessState];\n\n// ---------------------------------------------------------------------------\n// DcmtkProcess class\n// ---------------------------------------------------------------------------\n\n/**\n * Base class for persistent DCMTK processes (e.g., dcmrecv, storescp).\n *\n * @example\n * ```ts\n * const proc = new DcmtkProcess({\n * binary: '/usr/local/bin/dcmrecv',\n * args: ['--config', 'storescp.cfg', '11112'],\n * isStartedPredicate: line => line.includes('listening'),\n * });\n *\n * const result = await proc.start();\n * if (result.ok) {\n * // Process is running\n * proc.on('line', ({ source, text }) => console.log(`[${source}] ${text}`));\n * }\n *\n * await proc.stop();\n * ```\n */\nclass DcmtkProcess extends EventEmitter<DcmtkProcessEventMap> {\n private state: ProcessStateValue = ProcessState.IDLE;\n private child: ChildProcess | null = null;\n private stdoutBuffer = '';\n private stderrBuffer = '';\n private readonly config: DcmtkProcessConfig;\n\n constructor(config: DcmtkProcessConfig) {\n super();\n // Servers can have up to ~15 event types plus internal listeners;\n // raise above the default 10 to avoid MaxListenersExceeded warnings.\n this.setMaxListeners(20);\n this.config = config;\n // Prevent unhandled 'error' events from crashing the process (Node.js\n // throws if 'error' is emitted with no listener). Consumers should\n // register their own 'error' listener before calling start() to receive\n // errors. Startup errors are also returned via Result from start().\n this.on('error', () => {});\n }\n\n /** Whether the process is currently running. */\n get isRunning(): boolean {\n return this.state === ProcessState.RUNNING;\n }\n\n /** Current process state. */\n get currentState(): ProcessStateValue {\n return this.state;\n }\n\n /**\n * Starts the DCMTK process.\n *\n * Single-use enforcement: returns an error if called more than once.\n * Waits for the `isStartedPredicate` to match an output line, or resolves\n * immediately after spawn if no predicate is configured.\n *\n * @returns A Result indicating success or failure\n */\n async start(): Promise<Result<void>> {\n if (this.state !== ProcessState.IDLE) {\n return err(new Error(`Cannot start: process is in state \"${this.state}\"`));\n }\n this.state = ProcessState.STARTING;\n const timeoutMs = this.config.startTimeoutMs ?? DEFAULT_START_TIMEOUT_MS;\n\n return new Promise<Result<void>>(resolve => {\n let settled = false;\n const timer = setTimeout(() => {\n if (settled) return;\n settled = true;\n this.state = ProcessState.STOPPED;\n this.killChild();\n resolve(err(new Error(`Process failed to start within ${timeoutMs}ms`)));\n }, timeoutMs);\n\n // Safe from races: Node.js is single-threaded, so the `settled`\n // flag check + set is atomic within each event handler invocation.\n const settle = (result: Result<void>): void => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n resolve(result);\n };\n\n try {\n this.child = spawn(this.config.binary, [...this.config.args], {\n cwd: this.config.cwd,\n windowsHide: true,\n });\n /* v8 ignore start -- spawn() rarely throws synchronously */\n } catch (e: unknown) {\n settle(err(new Error(`Failed to spawn process: ${stderr(e).message}`)));\n return;\n }\n /* v8 ignore stop */\n this.wireChildEvents(settle);\n });\n }\n\n /**\n * Stops the process gracefully.\n *\n * Waits up to `drainTimeoutMs` for the process to exit, then force-kills.\n */\n async stop(): Promise<void> {\n if (this.state === ProcessState.STOPPED || this.state === ProcessState.IDLE) {\n return;\n }\n\n this.state = ProcessState.STOPPING;\n const drainMs = this.config.drainTimeoutMs ?? DEFAULT_DRAIN_TIMEOUT_MS;\n\n return new Promise<void>(resolve => {\n /* v8 ignore next 4 -- drain timeout is a safety net for unresponsive processes */\n const timer = setTimeout(() => {\n this.killChild();\n this.state = ProcessState.STOPPED;\n resolve();\n }, drainMs);\n\n // Safe: Node.js is single-threaded, so `this.child` cannot become null\n // between the check and the `.once('close', ...)` registration. The\n // drain timeout handles the edge case where the child exits before\n // the close listener is registered.\n if (this.child) {\n this.child.once('close', () => {\n clearTimeout(timer);\n this.state = ProcessState.STOPPED;\n resolve();\n });\n this.killChild();\n /* v8 ignore start -- edge case: state is RUNNING but child is already null */\n } else {\n clearTimeout(timer);\n this.state = ProcessState.STOPPED;\n resolve();\n }\n /* v8 ignore stop */\n });\n }\n\n /**\n * Implements Disposable for deterministic cleanup (Rule 5.1).\n */\n [Symbol.dispose](): void {\n if (this.child) {\n this.killChild();\n this.child = null;\n }\n this.state = ProcessState.STOPPED;\n this.removeAllListeners();\n }\n\n // -----------------------------------------------------------------------\n // Private helpers\n // -----------------------------------------------------------------------\n\n private killChild(): void {\n if (this.child?.pid !== undefined && this.child.pid !== null) {\n try {\n kill(this.child.pid);\n /* v8 ignore next */\n } catch {\n // Process may already be dead\n }\n }\n }\n\n /**\n * Wires all child process event handlers for startup.\n */\n private wireChildEvents(settle: (result: Result<void>) => void): void {\n const child = this.child;\n if (!child) return;\n\n child.on('error', (error: Error) => {\n this.emit('error', { error, fatal: true });\n if (this.state === ProcessState.STARTING) {\n this.state = ProcessState.STOPPED;\n settle(err(new Error(`Process error during start: ${error.message}`)));\n }\n });\n\n child.on('close', (code: number | null) => {\n const prevState = this.state;\n this.state = ProcessState.STOPPED;\n this.child = null;\n const reason = `Process exited with code ${String(code ?? 'null')}`;\n this.emit('stopped', { reason });\n if (prevState === ProcessState.STARTING) settle(err(new Error(reason)));\n });\n\n child.stdout?.on('data', (chunk: Buffer | string) => {\n this.handleData('stdout', chunk);\n });\n child.stderr?.on('data', (chunk: Buffer | string) => {\n this.handleData('stderr', chunk);\n });\n\n child.on('spawn', () => {\n if (!this.config.isStartedPredicate) {\n this.state = ProcessState.RUNNING;\n this.emit('started');\n settle(ok(undefined));\n }\n });\n\n if (this.config.isStartedPredicate) {\n this.wireStartedPredicate(settle);\n }\n }\n\n /**\n * Wires a line listener that resolves start() when the predicate matches.\n */\n private wireStartedPredicate(settle: (result: Result<void>) => void): void {\n const onLine = ({ text }: { readonly source: LineSource; readonly text: string }): void => {\n if (this.config.isStartedPredicate?.(text)) {\n this.removeListener('line', onLine);\n this.state = ProcessState.RUNNING;\n this.emit('started');\n settle(ok(undefined));\n }\n };\n this.on('line', onLine);\n }\n\n private handleData(source: LineSource, chunk: Buffer | string): void {\n if (source === 'stdout') {\n this.stdoutBuffer += String(chunk);\n } else {\n this.stderrBuffer += String(chunk);\n }\n\n if (this.stdoutBuffer.length + this.stderrBuffer.length > MAX_OUTPUT_BYTES) {\n this.emit('error', { error: new Error(`Process output exceeded ${MAX_OUTPUT_BYTES} bytes`), fatal: true });\n this.killChild();\n return;\n }\n\n this.processLines(source, source === 'stdout' ? 'stdoutBuffer' : 'stderrBuffer');\n }\n\n private processLines(source: LineSource, bufferKey: 'stdoutBuffer' | 'stderrBuffer'): void {\n // Handle bare \\r (CR-only) line endings by converting to \\n\n this[bufferKey] = this[bufferKey].replace(/\\r(?!\\n)/g, '\\n');\n\n let newlineIdx = this[bufferKey].indexOf('\\n');\n\n // Iterative line extraction — no recursion (Rule 8.2)\n while (newlineIdx !== -1) {\n const current = this[bufferKey];\n const line = current.substring(0, newlineIdx).replace(/\\r$/, '');\n this[bufferKey] = current.substring(newlineIdx + 1);\n this.emit('line', { source, text: line });\n newlineIdx = this[bufferKey].indexOf('\\n');\n }\n }\n}\n\nexport { DcmtkProcess, ProcessState };\nexport type { DcmtkProcessEventMap, DcmtkProcessConfig, ProcessStateValue };\n","/**\n * Line-by-line parser for DCMTK process output.\n *\n * Matches output lines against registered EventPattern objects and emits\n * structured events. Supports both single-line and multi-line block matching.\n *\n * All algorithms are iterative (Rule 8.2: no recursion).\n * All buffers are bounded (Rule 8.1).\n *\n * @module parsers/LineParser\n */\n\nimport { EventEmitter } from 'node:events';\nimport { stderr } from 'stderr-lib';\nimport type { EventPattern } from './EventPattern';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { MAX_BLOCK_LINES, MAX_EVENT_PATTERNS, DEFAULT_BLOCK_TIMEOUT_MS } from '../constants';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Events emitted by the LineParser. */\ninterface LineParserEventMap {\n /** Emitted when a pattern matches. Carries the event name and extracted data. */\n match: [{ readonly event: string; readonly data: unknown }];\n /** Emitted when a multi-line block times out before the footer is matched. Consumers should listen for this event to detect and handle incomplete blocks. */\n blockTimeout: [{ readonly event: string; readonly lines: readonly string[] }];\n /** Emitted when a pattern processor throws. */\n error: [Error];\n}\n\n/** Tracks the state of an in-progress multi-line block. */\ninterface BlockState {\n readonly pattern: EventPattern;\n readonly lines: string[];\n readonly timer: ReturnType<typeof setTimeout>;\n}\n\n// ---------------------------------------------------------------------------\n// LineParser class\n// ---------------------------------------------------------------------------\n\n/**\n * Parses DCMTK output lines against registered event patterns.\n *\n * @example\n * ```ts\n * const parser = new LineParser();\n * parser.addPattern({\n * event: 'LISTENING',\n * pattern: /listening on port (\\d+)/i,\n * processor: match => ({ port: Number(match[1]) }),\n * });\n *\n * parser.on('match', ({ event, data }) => {\n * console.log(`${event}:`, data);\n * });\n *\n * parser.feed('I: listening on port 11112');\n * // Emits: match { event: 'LISTENING', data: { port: 11112 } }\n * ```\n */\nclass LineParser extends EventEmitter<LineParserEventMap> {\n private readonly patterns: EventPattern[] = [];\n private activeBlock: BlockState | null = null;\n\n constructor() {\n super();\n // LineParser is used internally and the number of patterns can be\n // large — disable the listener limit (0 = unlimited) to avoid\n // MaxListenersExceeded warnings.\n this.setMaxListeners(0);\n // Prevent unhandled 'error' events from crashing the process.\n // Consumers should register their own 'error' listener.\n this.on('error', () => {});\n }\n\n /**\n * Registers an event pattern.\n *\n * @param pattern - The pattern to register\n * @returns Result indicating success or failure if pattern limit exceeded\n */\n addPattern(pattern: EventPattern): Result<void> {\n if (this.patterns.length >= MAX_EVENT_PATTERNS) {\n return err(new Error(`Maximum event patterns (${MAX_EVENT_PATTERNS}) exceeded`));\n }\n this.patterns.push(pattern);\n return ok(undefined);\n }\n\n /**\n * Feeds a single line of output to the parser.\n *\n * The line is matched against all registered patterns (iteratively, Rule 8.2).\n * If a multi-line block is active, the line is accumulated until the footer matches.\n *\n * @param line - A single line of DCMTK output (without trailing newline)\n */\n feed(line: string): void {\n // If a multi-line block is active, accumulate lines\n if (this.activeBlock !== null) {\n this.feedToBlock(line);\n return;\n }\n\n // Check for multi-line block headers first\n for (let i = 0; i < this.patterns.length; i++) {\n const pattern = this.patterns[i];\n /* v8 ignore next -- safety guard for noUncheckedIndexedAccess */\n if (pattern === undefined) continue;\n\n if (pattern.multiLine) {\n const headerMatch = pattern.multiLine.header.exec(line);\n if (headerMatch) {\n this.startBlock(pattern, line);\n return;\n }\n }\n }\n\n // Check single-line patterns\n this.matchSingleLine(line);\n }\n\n /**\n * Feeds multiple lines of output (e.g., from a chunk split by newlines).\n *\n * @param lines - Array of lines to process\n */\n feedLines(lines: readonly string[]): void {\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n if (line !== undefined) {\n this.feed(line);\n }\n }\n }\n\n /**\n * Resets the parser state, clearing any active multi-line block.\n */\n reset(): void {\n if (this.activeBlock !== null) {\n clearTimeout(this.activeBlock.timer);\n this.activeBlock = null;\n }\n }\n\n /**\n * Implements Disposable for cleanup (Rule 5.1).\n */\n [Symbol.dispose](): void {\n this.reset();\n this.removeAllListeners();\n }\n\n // -----------------------------------------------------------------------\n // Private helpers\n // -----------------------------------------------------------------------\n\n private matchSingleLine(line: string): void {\n for (let i = 0; i < this.patterns.length; i++) {\n const pattern = this.patterns[i];\n /* v8 ignore next -- safety guard for noUncheckedIndexedAccess */\n if (pattern === undefined) continue;\n\n // Skip multi-line-only patterns for single-line matching\n if (pattern.multiLine) continue;\n\n const match = pattern.pattern.exec(line);\n if (match) {\n try {\n const data = pattern.processor(match);\n this.emit('match', { event: pattern.event, data });\n } catch (thrown: unknown) {\n this.emit('error', stderr(thrown));\n }\n return; // First match wins\n }\n }\n }\n\n private startBlock(pattern: EventPattern, headerLine: string): void {\n /* v8 ignore next -- multiLine is always defined when startBlock is called */\n const timeoutMs = pattern.multiLine?.timeoutMs ?? DEFAULT_BLOCK_TIMEOUT_MS;\n\n const timer = setTimeout(() => {\n if (this.activeBlock !== null) {\n const lines = [...this.activeBlock.lines];\n const evt = this.activeBlock.pattern.event;\n this.activeBlock = null;\n this.emit('blockTimeout', { event: evt, lines });\n }\n }, timeoutMs);\n\n this.activeBlock = {\n pattern,\n lines: [headerLine],\n timer,\n };\n }\n\n private feedToBlock(line: string): void {\n /* v8 ignore next -- safety guard: activeBlock is always set when feedToBlock is called */\n if (this.activeBlock === null) return;\n\n const { pattern, lines, timer } = this.activeBlock;\n /* v8 ignore next -- multiLine is always defined for block patterns */\n const maxLines = pattern.multiLine?.maxLines ?? MAX_BLOCK_LINES;\n\n lines.push(line);\n\n // Check footer\n if (pattern.multiLine?.footer.test(line)) {\n clearTimeout(timer);\n const blockText = lines.join('\\n');\n const match = pattern.pattern.exec(blockText);\n this.activeBlock = null;\n\n if (match) {\n try {\n const data = pattern.processor(match);\n this.emit('match', { event: pattern.event, data });\n } catch (thrown: unknown) {\n this.emit('error', stderr(thrown));\n }\n }\n return;\n }\n\n // Enforce bounded accumulation (Rule 8.1)\n if (lines.length >= maxLines) {\n clearTimeout(timer);\n const evt = pattern.event;\n const accumulated = [...lines];\n this.activeBlock = null;\n this.emit('blockTimeout', { event: evt, lines: accumulated });\n }\n }\n}\n\nexport { LineParser };\nexport type { LineParserEventMap };\n","/**\n * Shared validation regex patterns and constants.\n *\n * Centralises all DICOM-related validation patterns so that brands,\n * validation schemas, and server modules reference a single source\n * of truth rather than maintaining duplicated copies.\n *\n * @module patterns\n */\n\n// ---------------------------------------------------------------------------\n// DICOM tag and UID patterns\n// ---------------------------------------------------------------------------\n\n/** Matches a DICOM tag in `(XXXX,XXXX)` format where X is a hex digit. */\nconst DICOM_TAG_PATTERN = /^\\([0-9A-Fa-f]{4},[0-9A-Fa-f]{4}\\)$/;\n\n/** Matches a DICOM AE Title: printable ASCII excluding backslash (DICOM PS3.5 default repertoire). */\nconst AE_TITLE_PATTERN = /^[\\x20-\\x5b\\x5d-\\x7e]+$/;\n\n/**\n * Matches a dotted numeric OID (e.g. `1.2.840.10008`).\n *\n * Note: This intentionally accepts any syntactically valid dotted-numeric form.\n * DICOM PS3.5 §9.1 requires UIDs start with a non-zero root (e.g., `0.0.0` is\n * technically invalid), but real-world DICOM datasets contain such UIDs, so we\n * validate syntax only and leave semantic UID validation to the application layer.\n */\nconst UID_PATTERN = /^[0-9]+(\\.[0-9]+)*$/;\n\n/** Matches a single DICOM tag path segment with optional array index. */\nconst TAG_PATH_SEGMENT = /\\([0-9A-Fa-f]{4},[0-9A-Fa-f]{4}\\)(\\[\\d+\\])?/;\n\n/** Matches a full dot-separated DICOM tag path (e.g. `(0040,A730)[0].(0010,0010)`). */\nconst DICOM_TAG_PATH_PATTERN = new RegExp(`^${TAG_PATH_SEGMENT.source}(\\\\.${TAG_PATH_SEGMENT.source})*$`);\n\n// ---------------------------------------------------------------------------\n// Validation constants\n// ---------------------------------------------------------------------------\n\n/** Minimum length for an AE Title. */\nconst AE_TITLE_MIN_LENGTH = 1;\n\n/** Maximum length for an AE Title. */\nconst AE_TITLE_MAX_LENGTH = 16;\n\n/** Maximum length for a DICOM UID. */\nconst UID_MAX_LENGTH = 64;\n\n/** Minimum valid network port number. */\nconst PORT_MIN = 1;\n\n/** Maximum valid network port number. */\nconst PORT_MAX = 65535;\n\n// ---------------------------------------------------------------------------\n// DICOM query key patterns\n// ---------------------------------------------------------------------------\n\n/**\n * Matches a valid DICOM query key for `-k` arguments.\n *\n * Accepted formats:\n * - `XXXX,XXXX` — bare tag\n * - `XXXX,XXXX=value` — tag with value\n * - `XXXX,XXXX[0].XXXX,XXXX=value` — nested path with value\n * - `XXXX,XXXX.XXXX,XXXX=value` — dotted path with value\n *\n * The tag portion must start with a valid hex tag pair. Value after `=` is unconstrained.\n */\n// eslint-disable-next-line no-useless-escape\nconst DICOM_QUERY_KEY_PATTERN = /^[0-9A-Fa-f]{4},[0-9A-Fa-f]{4}(?:[\\[.\\]0-9A-Fa-f,]*)?(?:=.*)?$/;\n\n/**\n * Returns true if the string is a valid DICOM query key for `-k` arguments.\n */\nfunction isValidDicomKey(key: string): boolean {\n return DICOM_QUERY_KEY_PATTERN.test(key);\n}\n\n// ---------------------------------------------------------------------------\n// Path safety\n// ---------------------------------------------------------------------------\n\n/** Pattern matching `..` as a path segment (between separators, or at start/end). */\nconst PATH_TRAVERSAL_PATTERN = /(?:^|[\\\\/])\\.\\.(?:[\\\\/]|$)/;\n\n/**\n * Returns true if the string contains only valid DICOM AE Title characters.\n */\nfunction isValidAETitle(value: string): boolean {\n return AE_TITLE_PATTERN.test(value);\n}\n\n/**\n * Returns true if the path does not contain traversal sequences.\n *\n * @param p - The filesystem path to check\n * @returns `true` when the path is safe (no `..` segments)\n */\nfunction isSafePath(p: string): boolean {\n return !PATH_TRAVERSAL_PATTERN.test(p);\n}\n\nexport {\n DICOM_TAG_PATTERN,\n AE_TITLE_PATTERN,\n UID_PATTERN,\n TAG_PATH_SEGMENT,\n DICOM_TAG_PATH_PATTERN,\n AE_TITLE_MIN_LENGTH,\n AE_TITLE_MAX_LENGTH,\n UID_MAX_LENGTH,\n PORT_MIN,\n PORT_MAX,\n DICOM_QUERY_KEY_PATTERN,\n isValidDicomKey,\n isValidAETitle,\n PATH_TRAVERSAL_PATTERN,\n isSafePath,\n};\n","/**\n * Locates DCMTK binaries on the host system.\n *\n * Search order:\n * 1. `DCMTK_PATH` environment variable\n * 2. Platform-specific known install locations\n * 3. System PATH (via `which`/`where` lookup)\n *\n * @module findDcmtkPath\n */\n\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { execSync } from 'node:child_process';\nimport type { Result } from './types';\nimport { ok, err } from './types';\nimport { WINDOWS_SEARCH_PATHS, UNIX_SEARCH_PATHS, REQUIRED_BINARIES } from './constants';\nimport { isSafePath } from './patterns';\n\n/** Cached path result. Cleared only by passing `noCache: true`. */\nlet cachedPath: string | undefined;\n\nconst isWindows = process.platform === 'win32';\n\n/**\n * Returns the binary filename with platform-appropriate extension.\n *\n * @param name - The base binary name (e.g., `\"dcm2json\"`)\n * @returns The binary name with `.exe` appended on Windows\n */\nfunction binaryName(name: string): string {\n /* v8 ignore next -- platform-specific branch */\n return isWindows ? `${name}.exe` : name;\n}\n\n/**\n * Checks whether a directory contains all required DCMTK binaries.\n *\n * @param dir - The directory to check\n * @returns `true` if all required binaries exist in the directory\n */\nfunction hasRequiredBinaries(dir: string): boolean {\n for (const bin of REQUIRED_BINARIES) {\n if (!existsSync(join(dir, binaryName(bin)))) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Attempts to locate a binary via the system PATH using `which` (Unix) or `where` (Windows).\n *\n * @param name - The binary name to search for\n * @returns The directory containing the binary, or `undefined` if not found\n */\nfunction findViaSystemPath(name: string): string | undefined {\n try {\n /* v8 ignore next -- platform-specific branch */\n const cmd = isWindows ? `where ${binaryName(name)}` : `which ${name}`;\n const result = execSync(cmd, { encoding: 'utf-8', timeout: 5_000, windowsHide: true }).trim();\n const firstLine = result.split('\\n')[0]?.trim();\n if (firstLine) {\n /* v8 ignore next -- platform-specific branch */\n const lastSep = firstLine.lastIndexOf(isWindows ? '\\\\' : '/');\n if (lastSep >= 0) {\n return firstLine.substring(0, lastSep);\n }\n }\n } catch {\n // Binary not in PATH — this is expected, not exceptional\n }\n return undefined;\n}\n\n/**\n * Checks the DCMTK_PATH environment variable for a valid DCMTK installation.\n *\n * @returns A Result if the env var is set (success or error), or `undefined` if unset\n */\nfunction searchEnvPath(): Result<string> | undefined {\n const envPath = process.env['DCMTK_PATH'];\n if (envPath === undefined || envPath.length === 0) {\n return undefined;\n }\n if (!isSafePath(envPath)) {\n return err(new Error(`DCMTK_PATH=\"${envPath}\" contains path traversal sequences`));\n }\n if (hasRequiredBinaries(envPath)) {\n return ok(envPath);\n }\n return err(new Error(`DCMTK_PATH=\"${envPath}\" is set but required binaries are missing`));\n}\n\n/**\n * Searches platform-specific known install locations for DCMTK binaries.\n *\n * @returns The directory path if found, or `undefined`\n */\nfunction searchKnownPaths(): string | undefined {\n /* v8 ignore next -- platform-specific branch */\n const searchPaths = isWindows ? WINDOWS_SEARCH_PATHS : UNIX_SEARCH_PATHS;\n for (const candidate of searchPaths) {\n if (hasRequiredBinaries(candidate)) {\n return candidate;\n }\n }\n return undefined;\n}\n\n/**\n * Searches the system PATH for DCMTK binaries.\n *\n * @returns The directory path if found, or `undefined`\n */\nfunction searchSystemPath(): string | undefined {\n /* v8 ignore next -- fallback never used since REQUIRED_BINARIES is non-empty */\n const systemDir = findViaSystemPath(REQUIRED_BINARIES[0] ?? 'dcm2json');\n if (systemDir !== undefined && hasRequiredBinaries(systemDir)) {\n return systemDir;\n }\n return undefined;\n}\n\n/**\n * Options for {@link findDcmtkPath}.\n */\ninterface FindDcmtkPathOptions {\n /** Bypass the cached result and perform a fresh search. */\n readonly noCache?: boolean | undefined;\n}\n\n/**\n * Locates the directory containing DCMTK command-line binaries.\n *\n * Searches in the following order:\n * 1. `DCMTK_PATH` environment variable (if set)\n * 2. Platform-specific known install locations\n * 3. System PATH lookup via `which`/`where`\n *\n * The result is cached after the first successful call. Pass `{ noCache: true }`\n * to force a fresh search.\n *\n * @param options - Optional configuration\n * @returns A Result containing the DCMTK binary directory path, or an error if not found\n * @throws Never throws for expected failures (Rule 6.1)\n *\n * @example\n * ```ts\n * const result = findDcmtkPath();\n * if (result.ok) {\n * console.log(`DCMTK found at: ${result.value}`);\n * } else {\n * console.error(result.error.message);\n * }\n * ```\n */\nfunction findDcmtkPath(options?: FindDcmtkPathOptions): Result<string> {\n if (cachedPath !== undefined && !options?.noCache) {\n return ok(cachedPath);\n }\n\n const envResult = searchEnvPath();\n if (envResult !== undefined) {\n if (envResult.ok) {\n cachedPath = envResult.value;\n }\n return envResult;\n }\n\n const knownPath = searchKnownPaths();\n if (knownPath !== undefined) {\n cachedPath = knownPath;\n return ok(knownPath);\n }\n\n const systemPath = searchSystemPath();\n if (systemPath !== undefined) {\n cachedPath = systemPath;\n return ok(systemPath);\n }\n\n return err(\n new Error(\n 'DCMTK binaries not found. Install DCMTK and either:\\n' +\n ' - Set the DCMTK_PATH environment variable, or\\n' +\n ' - Install DCMTK to a standard location, or\\n' +\n ' - Ensure DCMTK binaries are on the system PATH'\n )\n );\n}\n\n/**\n * Clears the cached DCMTK path. Primarily for testing.\n */\nfunction clearDcmtkPathCache(): void {\n cachedPath = undefined;\n}\n\nexport { findDcmtkPath, clearDcmtkPathCache };\nexport type { FindDcmtkPathOptions };\n","/**\n * Resolves the full path to a DCMTK binary.\n *\n * Wraps {@link findDcmtkPath} + `path.join` and appends `.exe` on Windows.\n *\n * @module _resolveBinary\n * @internal\n */\n\nimport { join } from 'node:path';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { findDcmtkPath } from '../findDcmtkPath';\n\nconst isWindows = process.platform === 'win32';\n\n/**\n * Resolves the full filesystem path to a named DCMTK binary.\n *\n * @param toolName - The DCMTK binary name (e.g., \"dcm2xml\")\n * @returns A Result containing the full binary path or an error if DCMTK is not found\n */\nfunction resolveBinary(toolName: string): Result<string> {\n const pathResult = findDcmtkPath();\n if (!pathResult.ok) {\n return err(pathResult.error);\n }\n /* v8 ignore next -- platform-specific branch */\n const binaryName = isWindows ? `${toolName}.exe` : toolName;\n return ok(join(pathResult.value, binaryName));\n}\n\nexport { resolveBinary };\n","/**\n * Standardized error factory for tool wrappers.\n *\n * Produces consistent error messages that include the tool name, sanitized\n * arguments (truncated), exit code, and a stderr excerpt.\n *\n * @module _toolError\n * @internal\n */\n\n/** Maximum length for the arguments portion of the error message. */\nconst MAX_ARGS_LENGTH = 200;\n\n/** Maximum length for the stderr excerpt in the error message. */\nconst MAX_STDERR_LENGTH = 500;\n\n/**\n * Truncates a string to a maximum length, appending \"...\" if truncated.\n *\n * @param value - The string to truncate\n * @param maxLength - The maximum allowed length\n * @returns The original string or a truncated version\n */\nfunction truncate(value: string, maxLength: number): string {\n if (value.length <= maxLength) {\n return value;\n }\n return `${value.substring(0, maxLength)}...`;\n}\n\n/**\n * Creates a standardized Error for a tool wrapper failure.\n *\n * **Privacy note:** Arguments are included in the error message for debugging.\n * These may contain file paths. Callers exposing errors to end users or external\n * logs should sanitize sensitive paths before display.\n *\n * @param toolName - The DCMTK binary name (e.g., \"dcm2xml\")\n * @param args - The command-line arguments passed to the tool\n * @param exitCode - The process exit code\n * @param stderr - The captured stderr output\n * @returns An Error with a descriptive message\n */\nfunction createToolError(toolName: string, args: readonly string[], exitCode: number, stderr: string): Error {\n const argsStr = truncate(args.join(' '), MAX_ARGS_LENGTH);\n const stderrStr = truncate(stderr.trim(), MAX_STDERR_LENGTH);\n const parts = [`${toolName} failed (exit code ${String(exitCode)})`];\n if (argsStr.length > 0) {\n parts.push(`args: ${argsStr}`);\n }\n if (stderrStr.length > 0) {\n parts.push(`stderr: ${stderrStr}`);\n }\n return new Error(parts.join(' | '));\n}\n\n/**\n * Formats a Zod validation error into a concise, human-readable string.\n *\n * Flattens nested Zod issues into `field: message` pairs, producing\n * cleaner output than the raw Zod `.message` JSON string.\n *\n * @param toolName - The DCMTK tool name for context\n * @param zodError - The Zod error object (must have `.issues` array)\n * @returns A formatted Error\n */\nfunction createValidationError(\n toolName: string,\n zodError: { readonly issues: ReadonlyArray<{ readonly path: ReadonlyArray<PropertyKey>; readonly message: string }> }\n): Error {\n const parts: string[] = [];\n for (let i = 0; i < zodError.issues.length; i++) {\n const issue = zodError.issues[i];\n /* v8 ignore next */\n if (issue === undefined) continue;\n const path = issue.path.length > 0 ? issue.path.map(String).join('.') : '(root)';\n parts.push(`${path}: ${issue.message}`);\n }\n const detail = parts.length > 0 ? parts.join('; ') : 'unknown validation error';\n return new Error(`${toolName}: invalid options — ${detail}`);\n}\n\nexport { createToolError, createValidationError, truncate, MAX_ARGS_LENGTH, MAX_STDERR_LENGTH };\n","/**\n * Event patterns and types for dcmrecv output parsing.\n *\n * Defines regex patterns that match DCMTK dcmrecv verbose output,\n * along with typed event data interfaces for each event.\n *\n * @module events/dcmrecv\n */\n\nimport type { EventPattern } from '../parsers/EventPattern';\n\n// ---------------------------------------------------------------------------\n// Event constants (as const, not enum — Rule 3.5)\n// ---------------------------------------------------------------------------\n\n/** Events emitted by dcmrecv process output. */\nconst DcmrecvEvent = {\n LISTENING: 'LISTENING',\n ASSOCIATION_RECEIVED: 'ASSOCIATION_RECEIVED',\n ASSOCIATION_ACKNOWLEDGED: 'ASSOCIATION_ACKNOWLEDGED',\n C_STORE_REQUEST: 'C_STORE_REQUEST',\n STORED_FILE: 'STORED_FILE',\n ASSOCIATION_RELEASE: 'ASSOCIATION_RELEASE',\n ASSOCIATION_ABORTED: 'ASSOCIATION_ABORTED',\n ECHO_REQUEST: 'ECHO_REQUEST',\n CANNOT_START_LISTENER: 'CANNOT_START_LISTENER',\n REFUSING_ASSOCIATION: 'REFUSING_ASSOCIATION',\n /** Synthetic: STORED_FILE enriched with association context. */\n FILE_RECEIVED: 'FILE_RECEIVED',\n /** Synthetic: emitted on association release/abort with summary. */\n ASSOCIATION_COMPLETE: 'ASSOCIATION_COMPLETE',\n} as const;\n\ntype DcmrecvEventValue = (typeof DcmrecvEvent)[keyof typeof DcmrecvEvent];\n\n// ---------------------------------------------------------------------------\n// Event data interfaces (all readonly)\n// ---------------------------------------------------------------------------\n\n/** Data for ASSOCIATION_RECEIVED event. */\ninterface AssociationReceivedData {\n readonly source: string;\n readonly callingAE: string;\n readonly calledAE: string;\n}\n\n/** Data for ASSOCIATION_ACKNOWLEDGED event. */\ninterface AssociationAcknowledgedData {\n readonly maxSendPDV: number;\n}\n\n/** Data for C_STORE_REQUEST event. */\ninterface CStoreRequestData {\n readonly raw: string;\n}\n\n/** Data for STORED_FILE event. */\ninterface StoredFileData {\n readonly filePath: string;\n}\n\n/** Data for REFUSING_ASSOCIATION event. */\ninterface RefusingAssociationData {\n readonly reason: string;\n}\n\n/** Data for CANNOT_START_LISTENER event. */\ninterface CannotStartListenerData {\n readonly message: string;\n}\n\n/** Data for FILE_RECEIVED synthetic event. */\ninterface FileReceivedData {\n readonly filePath: string;\n readonly associationId: string;\n readonly callingAE: string;\n readonly calledAE: string;\n readonly source: string;\n}\n\n/** Data for ASSOCIATION_COMPLETE synthetic event. */\ninterface AssociationCompleteData {\n readonly associationId: string;\n readonly callingAE: string;\n readonly calledAE: string;\n readonly source: string;\n readonly files: readonly string[];\n readonly durationMs: number;\n readonly endReason: 'release' | 'abort';\n}\n\n// ---------------------------------------------------------------------------\n// Regex patterns for dcmrecv verbose output\n// ---------------------------------------------------------------------------\n\n/** Event patterns for parsing dcmrecv verbose output. */\nconst DCMRECV_PATTERNS: readonly EventPattern[] = [\n {\n event: DcmrecvEvent.LISTENING,\n pattern: /listening/i,\n processor: () => undefined,\n },\n {\n event: DcmrecvEvent.ASSOCIATION_RECEIVED,\n pattern: /Association Received\\s{1,100}(\\S+):\\s+(\\S+)\\s+->\\s+(\\S+)/,\n processor: (match): AssociationReceivedData => ({\n source: match[1] ?? '',\n callingAE: match[2] ?? '',\n calledAE: match[3] ?? '',\n }),\n },\n {\n event: DcmrecvEvent.ASSOCIATION_ACKNOWLEDGED,\n pattern: /Association Acknowledged \\(Max Send PDV:\\s*(\\d+)\\)/,\n processor: (match): AssociationAcknowledgedData => ({\n maxSendPDV: Number(match[1]),\n }),\n },\n {\n event: DcmrecvEvent.C_STORE_REQUEST,\n pattern: /Received Store Request/i,\n processor: (match): CStoreRequestData => ({\n raw: match[0] ?? '',\n }),\n },\n {\n event: DcmrecvEvent.STORED_FILE,\n pattern: /Stored received object to file:\\s{0,20}(.{1,1024})/,\n processor: (match): StoredFileData => ({\n filePath: (match[1] ?? '').trim(),\n }),\n },\n {\n event: DcmrecvEvent.ASSOCIATION_RELEASE,\n pattern: /Association Release/i,\n processor: () => undefined,\n },\n {\n event: DcmrecvEvent.ASSOCIATION_ABORTED,\n pattern: /Received Association Abort/i,\n processor: () => undefined,\n },\n {\n event: DcmrecvEvent.ECHO_REQUEST,\n pattern: /Received C-ECHO Request/,\n processor: () => undefined,\n },\n {\n event: DcmrecvEvent.CANNOT_START_LISTENER,\n pattern: /cannot (?:start SCP and )?listen on port/i,\n processor: (match): CannotStartListenerData => ({\n message: match[0] ?? '',\n }),\n },\n {\n event: DcmrecvEvent.REFUSING_ASSOCIATION,\n pattern: /Refusing Association\\s{0,20}\\((.{1,500})\\)/,\n processor: (match): RefusingAssociationData => ({\n reason: match[1] ?? '',\n }),\n },\n];\n\n/** Events that indicate fatal errors (process should be stopped). */\nconst DCMRECV_FATAL_EVENTS: ReadonlySet<string> = new Set([DcmrecvEvent.CANNOT_START_LISTENER]);\n\nexport { DcmrecvEvent, DCMRECV_PATTERNS, DCMRECV_FATAL_EVENTS };\nexport type {\n DcmrecvEventValue,\n AssociationReceivedData,\n AssociationAcknowledgedData,\n CStoreRequestData,\n StoredFileData,\n RefusingAssociationData,\n CannotStartListenerData,\n FileReceivedData,\n AssociationCompleteData,\n};\n","/**\n * Pure state machine tracking DICOM association lifecycle.\n *\n * No I/O, no async, no EventEmitter — just state transitions.\n * Used by Dcmrecv and StoreSCP to correlate files to associations.\n *\n * State machine:\n * ```\n * IDLE -> [beginAssociation] -> ACTIVE -> [trackFile]* -> [endAssociation] -> IDLE\n * ```\n *\n * This single-slot design is safe because all DCMTK server binaries\n * (dcmrecv, storescp, etc.) are single-threaded and handle one\n * association at a time. Concurrent connections queue at the TCP level,\n * so associations never interleave in the output stream.\n *\n * @module servers/AssociationTracker\n */\n\n// ---------------------------------------------------------------------------\n// Interfaces\n// ---------------------------------------------------------------------------\n\n/** Context for the currently active association. */\ninterface AssociationContext {\n readonly associationId: string;\n readonly callingAE: string;\n readonly calledAE: string;\n readonly source: string;\n readonly startTime: number;\n readonly files: string[];\n}\n\n/** A file enriched with association context. */\ninterface TrackedFile {\n readonly filePath: string;\n readonly associationId: string;\n readonly callingAE: string;\n readonly calledAE: string;\n readonly source: string;\n}\n\n/** Summary emitted when an association completes. */\ninterface AssociationSummary {\n readonly associationId: string;\n readonly callingAE: string;\n readonly calledAE: string;\n readonly source: string;\n readonly files: readonly string[];\n readonly durationMs: number;\n readonly endReason: 'release' | 'abort';\n}\n\n// ---------------------------------------------------------------------------\n// AssociationTracker class\n// ---------------------------------------------------------------------------\n\n/**\n * Tracks DICOM association lifecycle for file-to-source correlation.\n *\n * Maintains a simple IDLE/ACTIVE state machine. While active, all tracked\n * files are enriched with the current association context. Only one\n * association can be active at a time — this is safe because DCMTK\n * servers are single-threaded and process associations sequentially.\n *\n * @example\n * ```ts\n * const tracker = new AssociationTracker();\n * const id = tracker.beginAssociation({ callingAE: 'SCU', calledAE: 'SCP', source: 'db' });\n * const file = tracker.trackFile('/path/to/received.dcm');\n * const summary = tracker.endAssociation('release');\n * ```\n */\nclass AssociationTracker {\n private association: AssociationContext | undefined;\n private counter = 0;\n\n /**\n * Begins a new association, transitioning from IDLE to ACTIVE.\n *\n * If an association is already active, it is silently ended (abort)\n * and the new one begins.\n *\n * @param data - Association metadata\n * @returns The unique association ID\n */\n beginAssociation(data: { readonly callingAE: string; readonly calledAE: string; readonly source: string }): string {\n this.counter++;\n const associationId = `assoc-${String(this.counter)}`;\n this.association = {\n associationId,\n callingAE: data.callingAE,\n calledAE: data.calledAE,\n source: data.source,\n startTime: Date.now(),\n files: [],\n };\n return associationId;\n }\n\n /**\n * Tracks a file received during the current association.\n *\n * If no association is active, returns a TrackedFile with empty context.\n *\n * @param filePath - Path to the received file\n * @returns A TrackedFile enriched with association context\n */\n trackFile(filePath: string): TrackedFile {\n if (this.association === undefined) {\n return {\n filePath,\n associationId: '',\n callingAE: '',\n calledAE: '',\n source: '',\n };\n }\n this.association.files.push(filePath);\n return {\n filePath,\n associationId: this.association.associationId,\n callingAE: this.association.callingAE,\n calledAE: this.association.calledAE,\n source: this.association.source,\n };\n }\n\n /**\n * Ends the current association, transitioning from ACTIVE to IDLE.\n *\n * @param reason - Why the association ended\n * @returns An AssociationSummary, or undefined if no association was active\n */\n endAssociation(reason: 'release' | 'abort'): AssociationSummary | undefined {\n if (this.association === undefined) return undefined;\n\n const summary: AssociationSummary = {\n associationId: this.association.associationId,\n callingAE: this.association.callingAE,\n calledAE: this.association.calledAE,\n source: this.association.source,\n files: [...this.association.files],\n durationMs: Date.now() - this.association.startTime,\n endReason: reason,\n };\n\n this.association = undefined;\n return summary;\n }\n\n /** The currently active association context, or undefined. */\n get current(): AssociationContext | undefined {\n return this.association;\n }\n\n /** Whether an association is currently active. */\n get isActive(): boolean {\n return this.association !== undefined;\n }\n\n /** Resets the tracker to IDLE, discarding any active association. */\n reset(): void {\n this.association = undefined;\n }\n}\n\nexport { AssociationTracker };\nexport type { AssociationContext, TrackedFile, AssociationSummary };\n","/**\n * DICOM receiver server wrapping the dcmrecv binary.\n *\n * Provides a type-safe, event-driven API for receiving DICOM objects\n * via C-STORE. Uses a static factory pattern because binary resolution\n * must happen before the constructor call.\n *\n * @module servers/Dcmrecv\n */\n\nimport { z } from 'zod';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { DcmtkProcess } from '../DcmtkProcess';\nimport type { DcmtkProcessConfig } from '../DcmtkProcess';\nimport { LineParser } from '../parsers/LineParser';\nimport { resolveBinary } from '../tools/_resolveBinary';\nimport { createValidationError } from '../tools/_toolError';\nimport { isSafePath, isValidAETitle } from '../patterns';\nimport { DcmrecvEvent, DCMRECV_PATTERNS, DCMRECV_FATAL_EVENTS } from '../events/dcmrecv';\nimport type {\n AssociationReceivedData,\n AssociationAcknowledgedData,\n CStoreRequestData,\n StoredFileData,\n RefusingAssociationData,\n CannotStartListenerData,\n FileReceivedData,\n AssociationCompleteData,\n} from '../events/dcmrecv';\nimport { AssociationTracker } from './AssociationTracker';\n\n// ---------------------------------------------------------------------------\n// Event map type (for documentation — consumers see typed overloads on class)\n// ---------------------------------------------------------------------------\n\n/** Typed event map for the Dcmrecv server. */\ninterface DcmrecvEventMap {\n LISTENING: [];\n ASSOCIATION_RECEIVED: [AssociationReceivedData];\n ASSOCIATION_ACKNOWLEDGED: [AssociationAcknowledgedData];\n C_STORE_REQUEST: [CStoreRequestData];\n STORED_FILE: [StoredFileData];\n ASSOCIATION_RELEASE: [];\n ASSOCIATION_ABORTED: [];\n ECHO_REQUEST: [];\n CANNOT_START_LISTENER: [CannotStartListenerData];\n REFUSING_ASSOCIATION: [RefusingAssociationData];\n FILE_RECEIVED: [FileReceivedData];\n ASSOCIATION_COMPLETE: [AssociationCompleteData];\n}\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\n/** Subdirectory generation mode for received files. */\nconst SubdirectoryMode = {\n NONE: 'none',\n SERIES_DATE: 'series-date',\n} as const;\n\ntype SubdirectoryModeValue = (typeof SubdirectoryMode)[keyof typeof SubdirectoryMode];\n\n/** Filename generation mode for received files. */\nconst FilenameMode = {\n DEFAULT: 'default',\n UNIQUE: 'unique',\n SHORT_UNIQUE: 'short-unique',\n SYSTEM_TIME: 'system-time',\n} as const;\n\ntype FilenameModeValue = (typeof FilenameMode)[keyof typeof FilenameMode];\n\n/** Storage mode for received DICOM objects. */\nconst StorageMode = {\n NORMAL: 'normal',\n BIT_PRESERVING: 'bit-preserving',\n IGNORE: 'ignore',\n} as const;\n\ntype StorageModeValue = (typeof StorageMode)[keyof typeof StorageMode];\n\n/** Options for creating a Dcmrecv server instance. */\ninterface DcmrecvOptions {\n /** Port to listen on (required). */\n readonly port: number;\n /** Application Entity Title. */\n readonly aeTitle?: string | undefined;\n /** Output directory for received files. */\n readonly outputDirectory?: string | undefined;\n /** Path to an association negotiation configuration file. */\n readonly configFile?: string | undefined;\n /** Profile name within the configuration file. */\n readonly configProfile?: string | undefined;\n /** Subdirectory generation mode. */\n readonly subdirectory?: SubdirectoryModeValue | undefined;\n /** Filename generation mode. */\n readonly filenameMode?: FilenameModeValue | undefined;\n /** File extension for received files. */\n readonly filenameExtension?: string | undefined;\n /** Storage mode for received DICOM objects. */\n readonly storageMode?: StorageModeValue | undefined;\n /** ACSE timeout in seconds (passed to DCMTK as-is). */\n readonly acseTimeout?: number | undefined;\n /** DIMSE timeout in seconds (passed to DCMTK as-is). */\n readonly dimseTimeout?: number | undefined;\n /** Maximum PDU receive size. */\n readonly maxPdu?: number | undefined;\n /** Timeout for start() to resolve (milliseconds). */\n readonly startTimeoutMs?: number | undefined;\n /** Timeout for graceful drain during stop() (milliseconds). */\n readonly drainTimeoutMs?: number | undefined;\n /** AbortSignal for external cancellation. */\n readonly signal?: AbortSignal | undefined;\n}\n\nconst DcmrecvOptionsSchema = z\n .object({\n port: z.number().int().min(1).max(65535),\n aeTitle: z.string().min(1).max(16).refine(isValidAETitle, { message: 'AE Title contains invalid characters' }).optional(),\n outputDirectory: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in outputDirectory' }).optional(),\n configFile: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in configFile' }).optional(),\n configProfile: z.string().min(1).optional(),\n subdirectory: z.enum(['none', 'series-date']).optional(),\n filenameMode: z.enum(['default', 'unique', 'short-unique', 'system-time']).optional(),\n filenameExtension: z.string().min(1).optional(),\n storageMode: z.enum(['normal', 'bit-preserving', 'ignore']).optional(),\n acseTimeout: z.number().int().positive().optional(),\n dimseTimeout: z.number().int().positive().optional(),\n maxPdu: z.number().int().min(4096).max(131072).optional(),\n startTimeoutMs: z.number().int().positive().optional(),\n drainTimeoutMs: z.number().int().positive().optional(),\n signal: z.instanceof(AbortSignal).optional(),\n })\n .strict();\n\n// ---------------------------------------------------------------------------\n// Argument builders (each <= 40 lines)\n// ---------------------------------------------------------------------------\n\n/** Builds the CLI arguments array from validated options. */\nfunction buildArgs(options: DcmrecvOptions): string[] {\n const args: string[] = ['--verbose'];\n\n if (options.aeTitle !== undefined) {\n args.push('--aetitle', options.aeTitle);\n }\n if (options.outputDirectory !== undefined) {\n args.push('--output-directory', options.outputDirectory);\n }\n if (options.configFile !== undefined && options.configProfile !== undefined) {\n args.push('--config-file', options.configFile, options.configProfile);\n }\n\n addFilenameArgs(args, options);\n addStorageArgs(args, options);\n addNetworkArgs(args, options);\n\n args.push(String(options.port));\n return args;\n}\n\n/** Appends filename-related CLI flags. */\nfunction addFilenameArgs(args: string[], options: DcmrecvOptions): void {\n if (options.subdirectory === 'series-date') {\n args.push('--sort-on-patientsname');\n }\n if (options.filenameMode === 'unique') {\n args.push('--unique-filenames');\n } else if (options.filenameMode === 'short-unique') {\n args.push('--short-unique-filenames');\n } else if (options.filenameMode === 'system-time') {\n args.push('--system-time-filenames');\n }\n if (options.filenameExtension !== undefined) {\n args.push('--filename-extension', options.filenameExtension);\n }\n}\n\n/** Appends storage-related CLI flags. */\nfunction addStorageArgs(args: string[], options: DcmrecvOptions): void {\n if (options.storageMode === 'bit-preserving') {\n args.push('--bit-preserving');\n } else if (options.storageMode === 'ignore') {\n args.push('--ignore');\n }\n}\n\n/** Appends network-related CLI flags. */\nfunction addNetworkArgs(args: string[], options: DcmrecvOptions): void {\n if (options.acseTimeout !== undefined) {\n args.push('--acse-timeout', String(options.acseTimeout));\n }\n if (options.dimseTimeout !== undefined) {\n args.push('--dimse-timeout', String(options.dimseTimeout));\n }\n if (options.maxPdu !== undefined) {\n args.push('--max-pdu', String(options.maxPdu));\n }\n}\n\n// ---------------------------------------------------------------------------\n// Dcmrecv class\n// ---------------------------------------------------------------------------\n\n/**\n * DICOM receiver server wrapping the dcmrecv binary.\n *\n * Uses a static `create()` factory because binary resolution is fallible\n * and must complete before the constructor runs.\n *\n * Server-specific events (LISTENING, STORED_FILE, etc.) are emitted dynamically\n * via the LineParser. Use `onEvent()` for typed listeners on server events.\n *\n * @example\n * ```ts\n * const result = Dcmrecv.create({ port: 11112, outputDirectory: '/tmp/received' });\n * if (result.ok) {\n * const server = result.value;\n * server.onEvent('STORED_FILE', (data) => console.log('Stored:', data.filePath));\n * const startResult = await server.start();\n * }\n * ```\n */\nclass Dcmrecv extends DcmtkProcess {\n private readonly parser: LineParser;\n private readonly tracker: AssociationTracker;\n private abortSignal: AbortSignal | undefined;\n private abortHandler: (() => void) | undefined;\n\n private constructor(config: DcmtkProcessConfig, parser: LineParser, signal?: AbortSignal) {\n super(config);\n this.parser = parser;\n this.tracker = new AssociationTracker();\n this.wireParser();\n this.wireTracker();\n if (signal !== undefined) {\n this.wireAbortSignal(signal);\n }\n }\n\n /**\n * Registers a typed listener for a dcmrecv-specific event.\n *\n * @param event - The event name from DcmrecvEventMap\n * @param listener - Callback receiving typed event data\n * @returns this for chaining\n */\n /** Disposes the server and its parser, preventing listener leaks. */\n [Symbol.dispose](): void {\n if (this.abortSignal !== undefined && this.abortHandler !== undefined) {\n this.abortSignal.removeEventListener('abort', this.abortHandler);\n }\n this.parser[Symbol.dispose]();\n super[Symbol.dispose]();\n }\n\n onEvent<K extends keyof DcmrecvEventMap>(event: K, listener: (...args: DcmrecvEventMap[K]) => void): this {\n return this.on(event as string, listener as never);\n }\n\n /**\n * Registers a listener for incoming associations.\n *\n * @param listener - Callback receiving association data\n * @returns this for chaining\n */\n onAssociationReceived(listener: (...args: DcmrecvEventMap['ASSOCIATION_RECEIVED']) => void): this {\n return this.onEvent('ASSOCIATION_RECEIVED', listener);\n }\n\n /**\n * Registers a listener for stored files.\n *\n * @param listener - Callback receiving stored file data\n * @returns this for chaining\n */\n onStoredFile(listener: (...args: DcmrecvEventMap['STORED_FILE']) => void): this {\n return this.onEvent('STORED_FILE', listener);\n }\n\n /**\n * Registers a listener for received files enriched with association context.\n *\n * @param listener - Callback receiving tracked file data\n * @returns this for chaining\n */\n onFileReceived(listener: (...args: DcmrecvEventMap['FILE_RECEIVED']) => void): this {\n return this.onEvent('FILE_RECEIVED', listener);\n }\n\n /**\n * Registers a listener for completed associations.\n *\n * @param listener - Callback receiving association summary\n * @returns this for chaining\n */\n onAssociationComplete(listener: (...args: DcmrecvEventMap['ASSOCIATION_COMPLETE']) => void): this {\n return this.onEvent('ASSOCIATION_COMPLETE', listener);\n }\n\n /**\n * Creates a new Dcmrecv server instance.\n *\n * @param options - Configuration options for the dcmrecv server\n * @returns A Result containing the server instance or a validation/resolution error\n */\n static create(options: DcmrecvOptions): Result<Dcmrecv> {\n const validation = DcmrecvOptionsSchema.safeParse(options);\n if (!validation.success) {\n return err(createValidationError('dcmrecv', validation.error));\n }\n\n const binaryResult = resolveBinary('dcmrecv');\n if (!binaryResult.ok) {\n return err(binaryResult.error);\n }\n\n const args = buildArgs(options);\n const parser = new LineParser();\n for (const pattern of DCMRECV_PATTERNS) {\n const addResult = parser.addPattern(pattern);\n if (!addResult.ok) {\n return err(addResult.error);\n }\n }\n\n const config: DcmtkProcessConfig = {\n binary: binaryResult.value,\n args,\n startTimeoutMs: options.startTimeoutMs,\n drainTimeoutMs: options.drainTimeoutMs,\n isStartedPredicate: line => /listening/i.test(line),\n };\n\n return ok(new Dcmrecv(config, parser, options.signal));\n }\n\n /** Wires the line parser to the process output. */\n private wireParser(): void {\n this.on('line', ({ text }) => {\n this.parser.feed(text);\n });\n\n this.parser.on('match', ({ event, data }) => {\n if (DCMRECV_FATAL_EVENTS.has(event)) {\n this.emit('error', { error: new Error(`Fatal: ${event}`), fatal: true });\n void this.stop();\n }\n this.emit(event, data);\n });\n }\n\n /** Wires the AssociationTracker to server events. */\n private wireTracker(): void {\n this.onEvent('ASSOCIATION_RECEIVED', data => {\n this.tracker.beginAssociation(data);\n });\n\n this.onEvent('STORED_FILE', data => {\n const tracked = this.tracker.trackFile(data.filePath);\n this.emit(DcmrecvEvent.FILE_RECEIVED as string, tracked);\n });\n\n this.onEvent('ASSOCIATION_RELEASE', () => {\n const summary = this.tracker.endAssociation('release');\n if (summary !== undefined) {\n this.emit(DcmrecvEvent.ASSOCIATION_COMPLETE as string, summary);\n }\n });\n\n this.onEvent('ASSOCIATION_ABORTED', () => {\n const summary = this.tracker.endAssociation('abort');\n if (summary !== undefined) {\n this.emit(DcmrecvEvent.ASSOCIATION_COMPLETE as string, summary);\n }\n });\n }\n\n /** Wires an AbortSignal to stop the server. */\n private wireAbortSignal(signal: AbortSignal): void {\n if (signal.aborted) {\n void this.stop();\n return;\n }\n this.abortSignal = signal;\n this.abortHandler = (): void => {\n void this.stop();\n };\n signal.addEventListener('abort', this.abortHandler, { once: true });\n }\n}\n\nexport { Dcmrecv, SubdirectoryMode, FilenameMode, StorageMode };\nexport type { DcmrecvOptions, DcmrecvEventMap, SubdirectoryModeValue, FilenameModeValue, StorageModeValue };\n","/**\n * Event patterns and types for storescp output parsing.\n *\n * Extends dcmrecv patterns with storescp-specific events like\n * file storage progress and subdirectory creation.\n *\n * @module events/storescp\n */\n\nimport type { EventPattern } from '../parsers/EventPattern';\nimport { DcmrecvEvent, DCMRECV_PATTERNS, DCMRECV_FATAL_EVENTS } from './dcmrecv';\nimport type { AssociationReceivedData } from './dcmrecv';\n\n// ---------------------------------------------------------------------------\n// Event constants (superset of dcmrecv — Rule 3.5)\n// ---------------------------------------------------------------------------\n\n/** Events emitted by storescp process output. */\nconst StorescpEvent = {\n ...DcmrecvEvent,\n STORING_FILE: 'STORING_FILE',\n SUBDIRECTORY_CREATED: 'SUBDIRECTORY_CREATED',\n} as const;\n\ntype StorescpEventValue = (typeof StorescpEvent)[keyof typeof StorescpEvent];\n\n// ---------------------------------------------------------------------------\n// Additional event data interfaces\n// ---------------------------------------------------------------------------\n\n/** Data for STORING_FILE event. */\ninterface StoringFileData {\n readonly filePath: string;\n}\n\n/** Data for SUBDIRECTORY_CREATED event. */\ninterface SubdirectoryCreatedData {\n readonly directory: string;\n}\n\n// ---------------------------------------------------------------------------\n// storescp-specific patterns\n// ---------------------------------------------------------------------------\n\n/**\n * storescp-specific ASSOCIATION_RECEIVED pattern.\n * storescp --verbose outputs only \"Association Received\" (no AE details),\n * so this pattern returns empty fields for source/callingAE/calledAE.\n */\nconst STORESCP_ASSOCIATION_RECEIVED: EventPattern = {\n event: StorescpEvent.ASSOCIATION_RECEIVED,\n pattern: /Association Received/i,\n processor: (): AssociationReceivedData => ({ source: '', callingAE: '', calledAE: '' }),\n};\n\nconst STORESCP_ADDITIONAL_PATTERNS: readonly EventPattern[] = [\n {\n event: StorescpEvent.STORING_FILE,\n pattern: /storing DICOM file:\\s{0,20}(.{1,1024})/i,\n processor: (match): StoringFileData => ({\n filePath: (match[1] ?? '').trim(),\n }),\n },\n {\n event: StorescpEvent.SUBDIRECTORY_CREATED,\n pattern: /created new subdirectory[:\\s]{0,20}(.{1,1024})/i,\n processor: (match): SubdirectoryCreatedData => ({\n directory: (match[1] ?? '').trim(),\n }),\n },\n];\n\n/** Combined event patterns for parsing storescp verbose output. */\nconst STORESCP_PATTERNS: readonly EventPattern[] = [\n ...DCMRECV_PATTERNS.filter(p => p.event !== DcmrecvEvent.ASSOCIATION_RECEIVED),\n STORESCP_ASSOCIATION_RECEIVED,\n ...STORESCP_ADDITIONAL_PATTERNS,\n];\n\n/** Events that indicate fatal errors (process should be stopped). */\nconst STORESCP_FATAL_EVENTS: ReadonlySet<string> = new Set([...DCMRECV_FATAL_EVENTS]);\n\nexport { StorescpEvent, STORESCP_PATTERNS, STORESCP_FATAL_EVENTS };\nexport type { StorescpEventValue, StoringFileData, SubdirectoryCreatedData };\n","/**\n * DICOM Storage SCP server wrapping the storescp binary.\n *\n * Provides a type-safe, event-driven API for receiving DICOM objects\n * via the storescp command-line tool. Supports sorting, exec hooks,\n * custom transfer syntaxes, and all standard storescp options.\n *\n * @module servers/StoreSCP\n */\n\nimport { z } from 'zod';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { DcmtkProcess } from '../DcmtkProcess';\nimport type { DcmtkProcessConfig } from '../DcmtkProcess';\nimport { LineParser } from '../parsers/LineParser';\nimport { resolveBinary } from '../tools/_resolveBinary';\nimport { createValidationError } from '../tools/_toolError';\nimport { isSafePath, isValidAETitle } from '../patterns';\nimport { STORESCP_PATTERNS, STORESCP_FATAL_EVENTS } from '../events/storescp';\nimport { DcmrecvEvent } from '../events/dcmrecv';\nimport type {\n AssociationReceivedData,\n AssociationAcknowledgedData,\n CStoreRequestData,\n StoredFileData,\n RefusingAssociationData,\n CannotStartListenerData,\n FileReceivedData,\n AssociationCompleteData,\n} from '../events/dcmrecv';\nimport type { StoringFileData, SubdirectoryCreatedData } from '../events/storescp';\nimport { AssociationTracker } from './AssociationTracker';\n\n// ---------------------------------------------------------------------------\n// Event map type (for documentation — consumers see typed overloads on class)\n// ---------------------------------------------------------------------------\n\n/** Typed event map for the StoreSCP server. */\ninterface StoreSCPEventMap {\n LISTENING: [];\n ASSOCIATION_RECEIVED: [AssociationReceivedData];\n ASSOCIATION_ACKNOWLEDGED: [AssociationAcknowledgedData];\n C_STORE_REQUEST: [CStoreRequestData];\n STORED_FILE: [StoredFileData];\n ASSOCIATION_RELEASE: [];\n ASSOCIATION_ABORTED: [];\n ECHO_REQUEST: [];\n CANNOT_START_LISTENER: [CannotStartListenerData];\n REFUSING_ASSOCIATION: [RefusingAssociationData];\n STORING_FILE: [StoringFileData];\n SUBDIRECTORY_CREATED: [SubdirectoryCreatedData];\n FILE_RECEIVED: [FileReceivedData];\n ASSOCIATION_COMPLETE: [AssociationCompleteData];\n}\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\n/** Preferred transfer syntax for incoming associations. */\nconst PreferredTransferSyntax = {\n LITTLE_ENDIAN: 'little-endian',\n BIG_ENDIAN: 'big-endian',\n IMPLICIT: 'implicit',\n ACCEPT_ALL: 'accept-all',\n} as const;\n\ntype PreferredTransferSyntaxValue = (typeof PreferredTransferSyntax)[keyof typeof PreferredTransferSyntax];\n\n/** Options for creating a StoreSCP server instance. */\ninterface StoreSCPOptions {\n /** Port to listen on (required). */\n readonly port: number;\n /** Application Entity Title. */\n readonly aeTitle?: string | undefined;\n /** Output directory for received files. */\n readonly outputDirectory?: string | undefined;\n /** Path to an association negotiation configuration file. */\n readonly configFile?: string | undefined;\n /** Profile name within the configuration file. */\n readonly configProfile?: string | undefined;\n /** Preferred transfer syntax (not valid with configFile). */\n readonly preferredTransferSyntax?: PreferredTransferSyntaxValue | undefined;\n /** Sort studies into subdirectories. */\n readonly sortByStudy?: boolean | undefined;\n /** Sort by Study Instance UID. */\n readonly sortByStudyUID?: boolean | undefined;\n /** Sort by patient name. */\n readonly sortByPatientName?: boolean | undefined;\n /** Generate unique filenames. */\n readonly uniqueFilenames?: boolean | undefined;\n /** Use bit-preserving mode. */\n readonly bitPreserving?: boolean | undefined;\n /** Execute command on each received file. */\n readonly execOnReception?: string | undefined;\n /** Execute command at end of study. */\n readonly execOnEndOfStudy?: string | undefined;\n /** Timeout for end-of-study detection in seconds (passed to DCMTK as-is). */\n readonly endOfStudyTimeout?: number | undefined;\n /** Rename files at end of study. */\n readonly renameOnEndOfStudy?: boolean | undefined;\n /** Socket timeout in seconds (passed to DCMTK as-is). */\n readonly socketTimeout?: number | undefined;\n /** ACSE timeout in seconds (passed to DCMTK as-is). */\n readonly acseTimeout?: number | undefined;\n /** DIMSE timeout in seconds (passed to DCMTK as-is). */\n readonly dimseTimeout?: number | undefined;\n /** Maximum PDU receive size. */\n readonly maxPdu?: number | undefined;\n /** Filename extension for received files. */\n readonly filenameExtension?: string | undefined;\n /** Timeout for start() to resolve (milliseconds). */\n readonly startTimeoutMs?: number | undefined;\n /** Timeout for graceful drain during stop() (milliseconds). */\n readonly drainTimeoutMs?: number | undefined;\n /** AbortSignal for external cancellation. */\n readonly signal?: AbortSignal | undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Configuration presets\n// ---------------------------------------------------------------------------\n\n/**\n * Pre-configured option sets for common StoreSCP deployment patterns.\n * Spread a preset into your options to avoid specifying boilerplate.\n *\n * @example\n * ```ts\n * StoreSCP.create({ ...StoreSCPPreset.PRODUCTION, port: 11112, outputDirectory: '/data' });\n * ```\n */\nconst StoreSCPPreset = {\n /** Basic storage: unique filenames to avoid collisions. */\n BASIC_STORAGE: {\n uniqueFilenames: true,\n },\n /** Testing: unique filenames, preserving raw transfer syntax. */\n TESTING: {\n uniqueFilenames: true,\n bitPreserving: true,\n },\n /** Production: unique filenames with reasonable timeouts. */\n PRODUCTION: {\n uniqueFilenames: true,\n acseTimeout: 30,\n dimseTimeout: 60,\n },\n} as const satisfies Record<string, Partial<StoreSCPOptions>>;\n\n/** Names of the available StoreSCP configuration presets. */\ntype StoreSCPPresetName = keyof typeof StoreSCPPreset;\n\nconst StoreSCPOptionsSchema = z\n .object({\n port: z.number().int().min(1).max(65535),\n aeTitle: z.string().min(1).max(16).refine(isValidAETitle, { message: 'AE Title contains invalid characters' }).optional(),\n outputDirectory: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in outputDirectory' }).optional(),\n configFile: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in configFile' }).optional(),\n configProfile: z.string().min(1).optional(),\n preferredTransferSyntax: z.enum(['little-endian', 'big-endian', 'implicit', 'accept-all']).optional(),\n sortByStudy: z.boolean().optional(),\n sortByStudyUID: z.boolean().optional(),\n sortByPatientName: z.boolean().optional(),\n uniqueFilenames: z.boolean().optional(),\n bitPreserving: z.boolean().optional(),\n execOnReception: z.string().min(1).optional(),\n execOnEndOfStudy: z.string().min(1).optional(),\n endOfStudyTimeout: z.number().int().positive().optional(),\n renameOnEndOfStudy: z.boolean().optional(),\n socketTimeout: z.number().int().positive().optional(),\n acseTimeout: z.number().int().positive().optional(),\n dimseTimeout: z.number().int().positive().optional(),\n maxPdu: z.number().int().min(4096).max(131072).optional(),\n filenameExtension: z.string().min(1).optional(),\n startTimeoutMs: z.number().int().positive().optional(),\n drainTimeoutMs: z.number().int().positive().optional(),\n signal: z.instanceof(AbortSignal).optional(),\n })\n .strict();\n\n// ---------------------------------------------------------------------------\n// Argument builders (each <= 40 lines)\n// ---------------------------------------------------------------------------\n\n/** Builds the full CLI arguments array. */\nfunction buildArgs(options: StoreSCPOptions): string[] {\n const args: string[] = ['--verbose'];\n\n if (options.aeTitle !== undefined) {\n args.push('--aetitle', options.aeTitle);\n }\n if (options.configFile !== undefined && options.configProfile !== undefined) {\n args.push('--config-file', options.configFile, options.configProfile);\n }\n\n buildTransferSyntaxArgs(args, options);\n buildSortArgs(args, options);\n buildOutputArgs(args, options);\n buildNetworkArgs(args, options);\n buildExecArgs(args, options);\n\n args.push(String(options.port));\n return args;\n}\n\n/** Appends transfer syntax CLI flags. */\nfunction buildTransferSyntaxArgs(args: string[], options: StoreSCPOptions): void {\n if (options.preferredTransferSyntax === 'little-endian') {\n args.push('+xe');\n } else if (options.preferredTransferSyntax === 'big-endian') {\n args.push('+xb');\n } else if (options.preferredTransferSyntax === 'implicit') {\n args.push('+xi');\n } else if (options.preferredTransferSyntax === 'accept-all') {\n args.push('+xa');\n }\n}\n\n/** Appends sorting-related CLI flags. */\nfunction buildSortArgs(args: string[], options: StoreSCPOptions): void {\n if (options.sortByStudy === true) {\n args.push('--sort-conc-studies');\n }\n if (options.sortByStudyUID === true) {\n args.push('--sort-on-study-uid');\n }\n if (options.sortByPatientName === true) {\n args.push('--sort-on-patientsname');\n }\n}\n\n/** Appends output-related CLI flags. */\nfunction buildOutputArgs(args: string[], options: StoreSCPOptions): void {\n if (options.outputDirectory !== undefined) {\n args.push('--output-directory', options.outputDirectory);\n }\n if (options.uniqueFilenames === true) {\n args.push('--unique-filenames');\n }\n if (options.bitPreserving === true) {\n args.push('--bit-preserving');\n }\n if (options.filenameExtension !== undefined) {\n args.push('--filename-extension', options.filenameExtension);\n }\n}\n\n/** Appends network-related CLI flags. */\nfunction buildNetworkArgs(args: string[], options: StoreSCPOptions): void {\n if (options.socketTimeout !== undefined) {\n args.push('--socket-timeout', String(options.socketTimeout));\n }\n if (options.acseTimeout !== undefined) {\n args.push('--acse-timeout', String(options.acseTimeout));\n }\n if (options.dimseTimeout !== undefined) {\n args.push('--dimse-timeout', String(options.dimseTimeout));\n }\n if (options.maxPdu !== undefined) {\n args.push('--max-pdu', String(options.maxPdu));\n }\n}\n\n/** Appends exec-related CLI flags. */\nfunction buildExecArgs(args: string[], options: StoreSCPOptions): void {\n if (options.execOnReception !== undefined) {\n args.push('--exec-on-reception', options.execOnReception);\n }\n if (options.execOnEndOfStudy !== undefined) {\n args.push('--exec-on-eostudy', options.execOnEndOfStudy);\n }\n if (options.endOfStudyTimeout !== undefined) {\n args.push('--eostudy-timeout', String(options.endOfStudyTimeout));\n }\n if (options.renameOnEndOfStudy === true) {\n args.push('--rename-on-eostudy');\n }\n}\n\n// ---------------------------------------------------------------------------\n// StoreSCP class\n// ---------------------------------------------------------------------------\n\n/**\n * DICOM Storage SCP server wrapping the storescp binary.\n *\n * Uses a static `create()` factory because binary resolution is fallible\n * and must complete before the constructor runs.\n *\n * Note: storescp does not print a \"listening\" message, so `start()` resolves\n * on spawn. If the port is busy, storescp exits immediately and `start()`\n * returns an error via the close handler.\n *\n * Server-specific events are emitted dynamically via the LineParser.\n * Use `onEvent()` for typed listeners on server events.\n *\n * @example\n * ```ts\n * const result = StoreSCP.create({ port: 11112, outputDirectory: '/tmp/received' });\n * if (result.ok) {\n * const server = result.value;\n * server.onEvent('STORED_FILE', (data) => console.log('Stored:', data.filePath));\n * const startResult = await server.start();\n * }\n * ```\n */\nclass StoreSCP extends DcmtkProcess {\n private readonly parser: LineParser;\n private readonly tracker: AssociationTracker;\n private abortSignal: AbortSignal | undefined;\n private abortHandler: (() => void) | undefined;\n\n private constructor(config: DcmtkProcessConfig, parser: LineParser, signal?: AbortSignal) {\n super(config);\n this.parser = parser;\n this.tracker = new AssociationTracker();\n this.wireParser();\n this.wireTracker();\n if (signal !== undefined) {\n this.wireAbortSignal(signal);\n }\n }\n\n /** Disposes the server and its parser, preventing listener leaks. */\n [Symbol.dispose](): void {\n if (this.abortSignal !== undefined && this.abortHandler !== undefined) {\n this.abortSignal.removeEventListener('abort', this.abortHandler);\n }\n this.parser[Symbol.dispose]();\n super[Symbol.dispose]();\n }\n\n /**\n * Registers a typed listener for a storescp-specific event.\n *\n * @param event - The event name from StoreSCPEventMap\n * @param listener - Callback receiving typed event data\n * @returns this for chaining\n */\n onEvent<K extends keyof StoreSCPEventMap>(event: K, listener: (...args: StoreSCPEventMap[K]) => void): this {\n return this.on(event as string, listener as never);\n }\n\n /**\n * Registers a listener for incoming associations.\n *\n * @param listener - Callback receiving association data\n * @returns this for chaining\n */\n onAssociationReceived(listener: (...args: StoreSCPEventMap['ASSOCIATION_RECEIVED']) => void): this {\n return this.onEvent('ASSOCIATION_RECEIVED', listener);\n }\n\n /**\n * Registers a listener for files being stored to disk.\n *\n * @param listener - Callback receiving storing file data\n * @returns this for chaining\n */\n onStoringFile(listener: (...args: StoreSCPEventMap['STORING_FILE']) => void): this {\n return this.onEvent('STORING_FILE', listener);\n }\n\n /**\n * Registers a listener for received files enriched with association context.\n *\n * @param listener - Callback receiving tracked file data\n * @returns this for chaining\n */\n onFileReceived(listener: (...args: StoreSCPEventMap['FILE_RECEIVED']) => void): this {\n return this.onEvent('FILE_RECEIVED', listener);\n }\n\n /**\n * Registers a listener for completed associations.\n *\n * @param listener - Callback receiving association summary\n * @returns this for chaining\n */\n onAssociationComplete(listener: (...args: StoreSCPEventMap['ASSOCIATION_COMPLETE']) => void): this {\n return this.onEvent('ASSOCIATION_COMPLETE', listener);\n }\n\n /**\n * Creates a new StoreSCP server instance.\n *\n * @param options - Configuration options for the storescp server\n * @returns A Result containing the server instance or a validation/resolution error\n */\n static create(options: StoreSCPOptions): Result<StoreSCP> {\n const validation = StoreSCPOptionsSchema.safeParse(options);\n if (!validation.success) {\n return err(createValidationError('storescp', validation.error));\n }\n\n const binaryResult = resolveBinary('storescp');\n if (!binaryResult.ok) {\n return err(binaryResult.error);\n }\n\n const args = buildArgs(options);\n const parser = new LineParser();\n for (const pattern of STORESCP_PATTERNS) {\n const addResult = parser.addPattern(pattern);\n if (!addResult.ok) {\n return err(addResult.error);\n }\n }\n\n const config: DcmtkProcessConfig = {\n binary: binaryResult.value,\n args,\n startTimeoutMs: options.startTimeoutMs,\n drainTimeoutMs: options.drainTimeoutMs,\n // storescp doesn't print \"listening\" — resolve on spawn\n };\n\n return ok(new StoreSCP(config, parser, options.signal));\n }\n\n /** Wires the line parser to the process output. */\n private wireParser(): void {\n this.on('line', ({ text }) => {\n this.parser.feed(text);\n });\n\n this.parser.on('match', ({ event, data }) => {\n if (STORESCP_FATAL_EVENTS.has(event)) {\n this.emit('error', { error: new Error(`Fatal: ${event}`), fatal: true });\n void this.stop();\n }\n this.emit(event, data);\n });\n }\n\n /** Wires the AssociationTracker to server events. */\n private wireTracker(): void {\n this.onEvent('ASSOCIATION_RECEIVED', data => {\n this.tracker.beginAssociation(data);\n });\n\n // storescp outputs \"storing DICOM file:\" (STORING_FILE), not\n // \"Stored received object to file:\" (STORED_FILE) like dcmrecv.\n // Listen to both so the tracker works regardless of which fires.\n this.onEvent('STORING_FILE', data => {\n const tracked = this.tracker.trackFile(data.filePath);\n this.emit(DcmrecvEvent.FILE_RECEIVED as string, tracked);\n });\n\n this.onEvent('STORED_FILE', data => {\n const tracked = this.tracker.trackFile(data.filePath);\n this.emit(DcmrecvEvent.FILE_RECEIVED as string, tracked);\n });\n\n this.onEvent('ASSOCIATION_RELEASE', () => {\n const summary = this.tracker.endAssociation('release');\n if (summary !== undefined) {\n this.emit(DcmrecvEvent.ASSOCIATION_COMPLETE as string, summary);\n }\n });\n\n this.onEvent('ASSOCIATION_ABORTED', () => {\n const summary = this.tracker.endAssociation('abort');\n if (summary !== undefined) {\n this.emit(DcmrecvEvent.ASSOCIATION_COMPLETE as string, summary);\n }\n });\n }\n\n /** Wires an AbortSignal to stop the server. */\n private wireAbortSignal(signal: AbortSignal): void {\n if (signal.aborted) {\n void this.stop();\n return;\n }\n this.abortSignal = signal;\n this.abortHandler = (): void => {\n void this.stop();\n };\n signal.addEventListener('abort', this.abortHandler, { once: true });\n }\n}\n\nexport { StoreSCP, PreferredTransferSyntax, StoreSCPPreset };\nexport type { StoreSCPOptions, StoreSCPEventMap, PreferredTransferSyntaxValue, StoreSCPPresetName };\n","/**\n * Branded types for domain primitives.\n *\n * Branded types use TypeScript's structural type system to prevent accidental\n * mixing of semantically different values that share the same underlying type.\n * A `DicomTag` cannot be used where an `AETitle` is expected, even though both\n * are strings at runtime.\n *\n * @module brands\n */\n\nimport { normalize } from 'node:path';\nimport type { Result } from './types';\nimport { ok, err } from './types';\nimport {\n DICOM_TAG_PATTERN,\n AE_TITLE_PATTERN,\n UID_PATTERN,\n DICOM_TAG_PATH_PATTERN,\n AE_TITLE_MIN_LENGTH,\n AE_TITLE_MAX_LENGTH,\n UID_MAX_LENGTH,\n PORT_MIN,\n PORT_MAX,\n PATH_TRAVERSAL_PATTERN,\n} from './patterns';\n\ndeclare const __brand: unique symbol;\n\n/** Intersects a base type with a phantom brand property for nominal typing. */\ntype Brand<T, TBrand extends string> = T & { readonly [__brand]: TBrand };\n\n// ---------------------------------------------------------------------------\n// Branded types\n// ---------------------------------------------------------------------------\n\n/**\n * A validated DICOM tag string, e.g. `\"(0010,0010)\"`.\n *\n * @remarks\n * Branded types enforce type safety when passing values between functions.\n * They are not required for direct API calls (which validate internally via Zod).\n * Use {@link createDicomTag} to obtain a branded value from a raw string.\n */\ntype DicomTag = Brand<string, 'DicomTag'>;\n\n/**\n * A validated AE Title (1-16 chars: uppercase letters, digits, spaces, hyphens).\n *\n * @remarks\n * Branded types enforce type safety when passing values between functions.\n * They are not required for direct API calls (which validate internally via Zod).\n * Use {@link createAETitle} to obtain a branded value from a raw string.\n */\ntype AETitle = Brand<string, 'AETitle'>;\n\n/**\n * A validated DICOM tag path, e.g. `\"(0040,A730)[0].(0010,0010)\"`.\n *\n * @remarks\n * Branded types enforce type safety when passing values between functions.\n * They are not required for direct API calls (which validate internally via Zod).\n * Use {@link createDicomTagPath} to obtain a branded value from a raw string.\n */\ntype DicomTagPath = Brand<string, 'DicomTagPath'>;\n\n/**\n * A validated SOP Class UID (dotted numeric OID, 1-64 chars).\n *\n * @remarks\n * Branded types enforce type safety when passing values between functions.\n * They are not required for direct API calls (which validate internally via Zod).\n * Use {@link createSOPClassUID} to obtain a branded value from a raw string.\n */\ntype SOPClassUID = Brand<string, 'SOPClassUID'>;\n\n/**\n * A validated Transfer Syntax UID (dotted numeric OID, 1-64 chars).\n *\n * @remarks\n * Branded types enforce type safety when passing values between functions.\n * They are not required for direct API calls (which validate internally via Zod).\n * Use {@link createTransferSyntaxUID} to obtain a branded value from a raw string.\n */\ntype TransferSyntaxUID = Brand<string, 'TransferSyntaxUID'>;\n\n/**\n * A validated filesystem path to a DICOM file.\n *\n * @remarks\n * Branded types enforce type safety when passing values between functions.\n * They are not required for direct API calls (which validate internally via Zod).\n * Use {@link createDicomFilePath} to obtain a branded value from a raw string.\n */\ntype DicomFilePath = Brand<string, 'DicomFilePath'>;\n\n/**\n * A validated network port number (1-65535).\n *\n * @remarks\n * Branded types enforce type safety when passing values between functions.\n * They are not required for direct API calls (which validate internally via Zod).\n * Use {@link createPort} to obtain a branded value from a raw number.\n */\ntype Port = Brand<number, 'Port'>;\n\n// Validation patterns and constants imported from ./patterns\n\n// ---------------------------------------------------------------------------\n// Factory functions\n// ---------------------------------------------------------------------------\n\n/**\n * Creates a validated DicomTag from a raw string.\n *\n * @param input - A string expected to be in format `(XXXX,XXXX)` where X is a hex digit\n * @returns A Result containing the branded DicomTag or an error\n */\nfunction createDicomTag(input: string): Result<DicomTag> {\n if (!DICOM_TAG_PATTERN.test(input)) {\n return err(new Error(`Invalid DICOM tag: \"${input}\". Expected format (XXXX,XXXX) where X is a hex digit`));\n }\n return ok(input as DicomTag);\n}\n\n/**\n * Creates a validated AETitle from a raw string.\n *\n * @param input - A string expected to be 1-16 printable ASCII chars (no backslash)\n * @returns A Result containing the branded AETitle or an error\n */\nfunction createAETitle(input: string): Result<AETitle> {\n if (input.length < AE_TITLE_MIN_LENGTH || input.length > AE_TITLE_MAX_LENGTH) {\n return err(new Error(`Invalid AE Title: \"${input}\". Must be ${AE_TITLE_MIN_LENGTH}-${AE_TITLE_MAX_LENGTH} characters`));\n }\n if (!AE_TITLE_PATTERN.test(input)) {\n return err(new Error(`Invalid AE Title: \"${input}\". Only printable ASCII characters (no backslash) are allowed`));\n }\n return ok(input as AETitle);\n}\n\n/**\n * Creates a validated DicomTagPath from a raw string.\n *\n * @param input - A dot-separated path of DICOM tags with optional array indices\n * @returns A Result containing the branded DicomTagPath or an error\n */\nfunction createDicomTagPath(input: string): Result<DicomTagPath> {\n // Empty check is duplicated in the Zod DicomTagPathSchema (.min(1)), but\n // kept here for a clearer error message from the brands factory.\n if (input.length === 0) {\n return err(new Error('Invalid DICOM tag path: empty string'));\n }\n if (!DICOM_TAG_PATH_PATTERN.test(input)) {\n return err(new Error(`Invalid DICOM tag path: \"${input}\". Expected format like (XXXX,XXXX) or (XXXX,XXXX)[0].(XXXX,XXXX)`));\n }\n return ok(input as DicomTagPath);\n}\n\n/**\n * Creates a validated SOPClassUID from a raw string.\n *\n * @param input - A dotted numeric OID string, 1-64 characters\n * @returns A Result containing the branded SOPClassUID or an error\n */\nfunction createSOPClassUID(input: string): Result<SOPClassUID> {\n if (input.length === 0 || input.length > UID_MAX_LENGTH) {\n return err(new Error(`Invalid SOP Class UID: \"${input}\". Must be 1-${UID_MAX_LENGTH} characters`));\n }\n if (!UID_PATTERN.test(input)) {\n return err(new Error(`Invalid SOP Class UID: \"${input}\". Must be a dotted numeric OID`));\n }\n return ok(input as SOPClassUID);\n}\n\n/**\n * Creates a validated TransferSyntaxUID from a raw string.\n *\n * @param input - A dotted numeric OID string, 1-64 characters\n * @returns A Result containing the branded TransferSyntaxUID or an error\n */\nfunction createTransferSyntaxUID(input: string): Result<TransferSyntaxUID> {\n if (input.length === 0 || input.length > UID_MAX_LENGTH) {\n return err(new Error(`Invalid Transfer Syntax UID: \"${input}\". Must be 1-${UID_MAX_LENGTH} characters`));\n }\n if (!UID_PATTERN.test(input)) {\n return err(new Error(`Invalid Transfer Syntax UID: \"${input}\". Must be a dotted numeric OID`));\n }\n return ok(input as TransferSyntaxUID);\n}\n\n/**\n * Creates a branded DicomFilePath from a raw string.\n * Validates that the path is non-empty and does not contain path traversal sequences.\n *\n * @param input - A filesystem path string\n * @returns A Result containing the branded DicomFilePath or an error\n */\nfunction createDicomFilePath(input: string): Result<DicomFilePath> {\n if (input.length === 0) {\n return err(new Error('Invalid DICOM file path: empty string'));\n }\n if (PATH_TRAVERSAL_PATTERN.test(input)) {\n return err(new Error(`Invalid DICOM file path: path traversal detected in \"${input}\"`));\n }\n // normalize() resolves `.` segments and trailing separators, ensuring\n // consistent path comparison regardless of input style (e.g., `a//b` → `a/b`).\n const normalized = normalize(input);\n return ok(normalized as DicomFilePath);\n}\n\n/**\n * Creates a validated Port from a raw number.\n *\n * @param input - A number expected to be an integer between 1 and 65535\n * @returns A Result containing the branded Port or an error\n */\nfunction createPort(input: number): Result<Port> {\n if (!Number.isInteger(input) || input < PORT_MIN || input > PORT_MAX) {\n return err(new Error(`Invalid port: ${String(input)}. Must be an integer between ${PORT_MIN} and ${PORT_MAX}`));\n }\n return ok(input as Port);\n}\n\n/**\n * Shorthand for creating a DicomTagPath, throwing on invalid input.\n *\n * Use this when you know the tag path is valid (e.g. hardcoded constants).\n * For user-supplied input, use {@link createDicomTagPath} which returns a Result.\n *\n * @param input - A DICOM tag path string, e.g. `'(0010,0010)'`\n * @returns The branded DicomTagPath\n * @throws Error if the input is not a valid DICOM tag path\n */\nfunction tag(input: string): DicomTagPath {\n const result = createDicomTagPath(input);\n if (!result.ok) throw result.error;\n return result.value;\n}\n\nexport { createDicomTag, createAETitle, createDicomTagPath, createSOPClassUID, createTransferSyntaxUID, createDicomFilePath, createPort, tag };\nexport type { Brand, DicomTag, AETitle, DicomTagPath, SOPClassUID, TransferSyntaxUID, DicomFilePath, Port };\n","/**\n * DICOM tag path parser and serializer.\n *\n * Provides iterative (no recursion) parsing of DICOM tag paths like\n * `(0040,A730)[0].(0040,A160)` into structured segments, and conversion\n * back to dcmodify-compatible strings.\n *\n * Supports wildcard indices `[*]` for use with DicomDataset.findValues.\n *\n * @module dicom/tagPath\n */\n\nimport type { DicomTag, DicomTagPath } from '../brands';\nimport { createDicomTag } from '../brands';\nimport { MAX_TRAVERSAL_DEPTH } from '../constants';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** A single segment of a parsed DICOM tag path. */\ninterface TagSegment {\n /** The DICOM tag for this segment. */\n readonly tag: DicomTag;\n /** The array index for sequence items, or undefined for non-sequence tags. */\n readonly index?: number | undefined;\n /** Whether this segment uses a wildcard index `[*]`. */\n readonly isWildcard?: boolean | undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Patterns\n// ---------------------------------------------------------------------------\n\n// Matches a tag segment: (XXXX,XXXX) optionally followed by [N] or [*]\nconst SEGMENT_PATTERN = /^\\(([0-9A-Fa-f]{4}),([0-9A-Fa-f]{4})\\)(?:\\[(\\d+|\\*)\\])?/;\n\n// ---------------------------------------------------------------------------\n// Internal helpers (extracted for complexity/line limits)\n// ---------------------------------------------------------------------------\n\n/** Parses a single regex match into a TagSegment. */\nfunction matchToSegment(match: RegExpExecArray): TagSegment {\n const group = match[1];\n const element = match[2];\n const indexStr = match[3];\n\n /* v8 ignore next 3 */\n if (group === undefined || element === undefined) {\n throw new Error('Failed to parse tag group/element');\n }\n\n const tagResult = createDicomTag(`(${group},${element})`);\n /* v8 ignore next 2 */\n if (!tagResult.ok) throw new Error(`Invalid tag in path: (${group},${element})`);\n\n if (indexStr === '*') return { tag: tagResult.value, isWildcard: true };\n if (indexStr !== undefined) return { tag: tagResult.value, index: Number(indexStr) };\n return { tag: tagResult.value };\n}\n\n/** Advances past the current match and any dot separator. Returns the updated remaining string. */\nfunction advancePastMatch(remaining: string, matchLength: number): string {\n const after = remaining.slice(matchLength);\n if (!after.startsWith('.')) return after;\n if (after.length === 1) throw new Error('Tag path cannot end with a dot separator');\n return after.slice(1);\n}\n\n// ---------------------------------------------------------------------------\n// Parser\n// ---------------------------------------------------------------------------\n\n/**\n * Parses a DICOM tag path into an array of segments.\n *\n * Uses iterative parsing with bounded loop (Rule 8.2: no recursion).\n *\n * @param path - A branded DicomTagPath string\n * @returns An array of TagSegment objects\n * @throws Error if the path is malformed or exceeds MAX_TRAVERSAL_DEPTH\n *\n * @example\n * ```ts\n * tagPathToSegments('(0040,A730)[0].(0040,A160)' as DicomTagPath)\n * // => [\n * // { tag: '(0040,A730)' as DicomTag, index: 0 },\n * // { tag: '(0040,A160)' as DicomTag }\n * // ]\n * ```\n */\nfunction tagPathToSegments(path: DicomTagPath): ReadonlyArray<TagSegment> {\n const segments: TagSegment[] = [];\n let remaining: string = path;\n\n for (let i = 0; i < MAX_TRAVERSAL_DEPTH && remaining.length > 0; i++) {\n const match = SEGMENT_PATTERN.exec(remaining);\n if (match === null) {\n throw new Error(`Invalid tag path segment at position ${path.length - remaining.length}: \"${remaining}\"`);\n }\n segments.push(matchToSegment(match));\n remaining = advancePastMatch(remaining, match[0].length);\n }\n\n if (remaining.length > 0) throw new Error(`Tag path exceeds maximum depth of ${MAX_TRAVERSAL_DEPTH}`);\n if (segments.length === 0) throw new Error('Tag path is empty');\n return segments;\n}\n\n// ---------------------------------------------------------------------------\n// Serializers\n// ---------------------------------------------------------------------------\n\n/**\n * Converts tag segments back to a dcmodify-compatible path string.\n *\n * Format: `(0040,A730)[0].(0040,A160)`\n *\n * @param segments - An array of TagSegment objects\n * @returns A dcmodify-compatible path string\n */\nfunction segmentsToModifyPath(segments: ReadonlyArray<TagSegment>): string {\n const parts: string[] = [];\n for (const seg of segments) {\n let part: string = seg.tag;\n if (seg.isWildcard === true) {\n part += '[*]';\n } else if (seg.index !== undefined) {\n part += `[${seg.index}]`;\n }\n parts.push(part);\n }\n return parts.join('.');\n}\n\n/**\n * Converts tag segments to a canonical display string.\n *\n * Same format as dcmodify path: `(0040,A730)[0].(0040,A160)`\n *\n * @param segments - An array of TagSegment objects\n * @returns A human-readable path string\n */\nfunction segmentsToString(segments: ReadonlyArray<TagSegment>): string {\n return segmentsToModifyPath(segments);\n}\n\nexport { tagPathToSegments, segmentsToModifyPath, segmentsToString };\nexport type { TagSegment };\n","/**\n * Immutable mutation tracking for DICOM datasets.\n *\n * Every mutation method returns a new ChangeSet instance, preserving immutability.\n * Bridge methods produce dcmodify-compatible arguments for applying changes to files.\n *\n * @module dicom/ChangeSet\n */\n\nimport type { TagModification } from '../tools/dcmodify';\nimport { MAX_CHANGESET_OPERATIONS } from '../constants';\nimport type { DicomTagPath } from '../brands';\nimport { tagPathToSegments } from './tagPath';\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/** Sentinel value in the erasures set to indicate erasing all private tags. */\nconst ERASE_PRIVATE_SENTINEL = '__ERASE_PRIVATE__';\n\n// ---------------------------------------------------------------------------\n// Helpers (extracted for complexity/line limits)\n// ---------------------------------------------------------------------------\n\n/**\n * Returns true if a char code is a control character to strip.\n * Strips 0x00-0x09, 0x0B, 0x0C, 0x0E-0x1F, 0x7F.\n * Preserves LF (0x0A), CR (0x0D), and backslash.\n */\nfunction isControlChar(code: number): boolean {\n if (code <= 0x09) return true;\n if (code === 0x0b || code === 0x0c) return true;\n if (code >= 0x0e && code <= 0x1f) return true;\n return code === 0x7f;\n}\n\n/** Strips control characters from a value while preserving LF, CR, and backslash. */\nfunction sanitizeValue(value: string): string {\n let result = '';\n for (let i = 0; i < value.length; i++) {\n const code = value.charCodeAt(i);\n if (!isControlChar(code)) {\n result += value[i];\n }\n }\n return result;\n}\n\n/** Merges two modification maps, with `other` winning conflicts. Removes keys present in erasures. */\nfunction buildMergedModifications(\n base: ReadonlyMap<string, string>,\n other: ReadonlyMap<string, string>,\n erasures: ReadonlySet<string>\n): ReadonlyMap<string, string> {\n const merged = new Map<string, string>(base);\n for (const [key, value] of other) {\n merged.set(key, value);\n }\n for (const key of erasures) {\n merged.delete(key);\n }\n return merged;\n}\n\n/** Iteratively applies all entries to a ChangeSet, returning the final result. */\nfunction applyBatchEntries(initial: ChangeSet, entries: Readonly<Record<string, string>>): ChangeSet {\n const keys = Object.keys(entries);\n let cs = initial;\n for (let i = 0; i < keys.length; i++) {\n const key = keys[i];\n /* v8 ignore next */\n if (key === undefined) continue;\n const value = entries[key];\n /* v8 ignore next */\n if (value === undefined) continue;\n cs = cs.setTag(key, value);\n }\n return cs;\n}\n\n// ---------------------------------------------------------------------------\n// ChangeSet class\n// ---------------------------------------------------------------------------\n\n/**\n * Immutable mutation tracker for DICOM datasets.\n *\n * Every mutation method returns a **new** ChangeSet — the original is never modified.\n * Use {@link ChangeSet.toModifications} and {@link ChangeSet.toErasureArgs} to bridge\n * to the dcmodify tool wrapper.\n *\n * @example\n * ```ts\n * const cs = ChangeSet.empty()\n * .setTag('(0010,0010)' as DicomTagPath, 'Anonymous')\n * .eraseTag('(0010,0020)' as DicomTagPath)\n * .erasePrivateTags();\n * ```\n */\nclass ChangeSet {\n private readonly mods: ReadonlyMap<string, string>;\n private readonly erased: ReadonlySet<string>;\n\n private constructor(mods: ReadonlyMap<string, string>, erasures: ReadonlySet<string>) {\n this.mods = mods;\n this.erased = erasures;\n }\n\n /** Creates an empty ChangeSet with no modifications or erasures. */\n static empty(): ChangeSet {\n return new ChangeSet(new Map(), new Set());\n }\n\n /**\n * Sets a tag value, returning a new ChangeSet.\n *\n * Control characters (except LF/CR) are stripped from the value.\n * If the tag was previously erased, it is removed from the erasure set.\n *\n * @param path - The DICOM tag path to set (e.g. `'(0010,0010)'`)\n * @param value - The new value for the tag\n * @returns A new ChangeSet with the modification applied\n * @throws Error if operation count would exceed MAX_CHANGESET_OPERATIONS\n */\n setTag(path: string, value: string): ChangeSet {\n const totalOps = this.mods.size + this.erased.size;\n if (totalOps >= MAX_CHANGESET_OPERATIONS) {\n throw new Error(`ChangeSet operation limit (${MAX_CHANGESET_OPERATIONS}) exceeded`);\n }\n tagPathToSegments(path as DicomTagPath);\n const sanitized = sanitizeValue(value);\n const newMods = new Map(this.mods);\n newMods.set(path, sanitized);\n const newErasures = new Set(this.erased);\n newErasures.delete(path);\n return new ChangeSet(newMods, newErasures);\n }\n\n /**\n * Marks a tag for erasure, returning a new ChangeSet.\n *\n * If the tag was previously set, the modification is removed.\n *\n * @param path - The DICOM tag path to erase (e.g. `'(0010,0010)'`)\n * @returns A new ChangeSet with the erasure applied\n * @throws Error if operation count would exceed MAX_CHANGESET_OPERATIONS\n */\n eraseTag(path: string): ChangeSet {\n const totalOps = this.mods.size + this.erased.size;\n if (totalOps >= MAX_CHANGESET_OPERATIONS) {\n throw new Error(`ChangeSet operation limit (${MAX_CHANGESET_OPERATIONS}) exceeded`);\n }\n tagPathToSegments(path as DicomTagPath);\n const newMods = new Map(this.mods);\n newMods.delete(path);\n const newErasures = new Set(this.erased);\n newErasures.add(path);\n return new ChangeSet(newMods, newErasures);\n }\n\n /**\n * Marks all private tags for erasure, returning a new ChangeSet.\n *\n * @returns A new ChangeSet with the erase-private flag set\n * @throws Error if operation count would exceed MAX_CHANGESET_OPERATIONS\n */\n erasePrivateTags(): ChangeSet {\n const totalOps = this.mods.size + this.erased.size;\n if (totalOps >= MAX_CHANGESET_OPERATIONS) {\n throw new Error(`ChangeSet operation limit (${MAX_CHANGESET_OPERATIONS}) exceeded`);\n }\n const newErasures = new Set(this.erased);\n newErasures.add(ERASE_PRIVATE_SENTINEL);\n return new ChangeSet(new Map(this.mods), newErasures);\n }\n\n // -----------------------------------------------------------------------\n // Convenience setters for common DICOM tags\n // -----------------------------------------------------------------------\n\n /** Sets Patient's Name (0010,0010). */\n setPatientName(value: string): ChangeSet {\n return this.setTag('(0010,0010)', value);\n }\n\n /** Sets Patient ID (0010,0020). */\n setPatientID(value: string): ChangeSet {\n return this.setTag('(0010,0020)', value);\n }\n\n /** Sets Study Date (0008,0020). */\n setStudyDate(value: string): ChangeSet {\n return this.setTag('(0008,0020)', value);\n }\n\n /** Sets Modality (0008,0060). */\n setModality(value: string): ChangeSet {\n return this.setTag('(0008,0060)', value);\n }\n\n /** Sets Accession Number (0008,0050). */\n setAccessionNumber(value: string): ChangeSet {\n return this.setTag('(0008,0050)', value);\n }\n\n /** Sets Study Description (0008,1030). */\n setStudyDescription(value: string): ChangeSet {\n return this.setTag('(0008,1030)', value);\n }\n\n /** Sets Series Description (0008,103E). */\n setSeriesDescription(value: string): ChangeSet {\n return this.setTag('(0008,103E)', value);\n }\n\n /** Sets Institution Name (0008,0080). */\n setInstitutionName(value: string): ChangeSet {\n return this.setTag('(0008,0080)', value);\n }\n\n /**\n * Sets multiple tags at once, returning a new ChangeSet.\n *\n * @param entries - A record of tag path → value pairs\n * @returns A new ChangeSet with all modifications applied\n */\n setBatch(entries: Readonly<Record<string, string>>): ChangeSet {\n return applyBatchEntries(this, entries);\n }\n\n /** All pending tag modifications as a readonly map of path → value. */\n get modifications(): ReadonlyMap<string, string> {\n return this.mods;\n }\n\n /** All pending tag erasures as a readonly set of paths. */\n get erasures(): ReadonlySet<string> {\n return this.erased;\n }\n\n /** Total number of operations (modifications + erasures) in this ChangeSet. */\n get operationCount(): number {\n return this.mods.size + this.erased.size;\n }\n\n /** Whether the ChangeSet has no modifications and no erasures. */\n get isEmpty(): boolean {\n return this.mods.size === 0 && this.erased.size === 0;\n }\n\n /** Whether the erase-all-private-tags flag is set. */\n get erasePrivate(): boolean {\n return this.erased.has(ERASE_PRIVATE_SENTINEL);\n }\n\n /**\n * Merges another ChangeSet into this one, returning a new ChangeSet.\n *\n * The `other` ChangeSet wins on conflicts: if the same tag is modified in both,\n * `other`'s value is used. Erasures from both sets are unioned. An erasure in\n * `other` removes a modification from `base`.\n *\n * @param other - The ChangeSet to merge in\n * @returns A new ChangeSet with merged modifications and erasures\n */\n merge(other: ChangeSet): ChangeSet {\n const mergedErasures = new Set([...this.erased, ...other.erased]);\n const mergedMods = buildMergedModifications(this.mods, other.mods, mergedErasures);\n return new ChangeSet(mergedMods, mergedErasures);\n }\n\n /**\n * Converts modifications to dcmodify-compatible TagModification array.\n *\n * @returns A readonly array of TagModification objects\n */\n toModifications(): ReadonlyArray<TagModification> {\n const result: TagModification[] = [];\n for (const [tag, value] of this.mods) {\n result.push({ tag, value });\n }\n return result;\n }\n\n /**\n * Converts erasures to dcmodify-compatible argument strings.\n *\n * The erase-private sentinel is excluded — use {@link erasePrivate} to check\n * whether `-ep` should be passed.\n *\n * @returns A readonly array of tag path strings for `-e` arguments\n */\n toErasureArgs(): ReadonlyArray<string> {\n const result: string[] = [];\n for (const path of this.erased) {\n if (path !== ERASE_PRIVATE_SENTINEL) {\n result.push(path);\n }\n }\n return result;\n }\n}\n\nexport { ChangeSet };\n","/**\n * Immutable DICOM dataset wrapper with type-safe accessors.\n *\n * Wraps DICOM JSON Model data (PS3.18 F.2) from dcm2json/dcm2xml with\n * convenient read-only accessors. No setters — mutations go through ChangeSet.\n *\n * @module dicom/DicomDataset\n */\n\nimport { stderr } from 'stderr-lib';\nimport type { DicomTag, DicomTagPath, SOPClassUID } from '../brands';\nimport { createSOPClassUID } from '../brands';\nimport { MAX_TRAVERSAL_DEPTH } from '../constants';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport type { TagSegment } from './tagPath';\nimport { tagPathToSegments } from './tagPath';\nimport type { DicomJsonElement, DicomJsonModel } from '../tools/_xmlToJson';\n\n// ---------------------------------------------------------------------------\n// Structural validation\n// ---------------------------------------------------------------------------\n\nconst HEX_TAG_KEY = /^[0-9A-Fa-f]{8}$/;\n\n/**\n * Returns true if the value looks like a DicomJsonElement (has a string `vr` property).\n * This is a lightweight structural check, not a full VR validation.\n */\nfunction isDicomJsonElement(value: unknown): value is DicomJsonElement {\n return typeof value === 'object' && value !== null && 'vr' in value && typeof (value as Record<string, unknown>)['vr'] === 'string';\n}\n\n/**\n * Returns true if the object looks like a DicomJsonModel.\n * Every key must be an 8-char hex string and every value must have { vr: string }.\n */\nfunction isValidDicomJsonModel(obj: Record<string, unknown>): boolean {\n const keys = Object.keys(obj);\n for (let i = 0; i < keys.length; i++) {\n const key = keys[i];\n /* v8 ignore next */\n if (key === undefined) continue;\n if (!HEX_TAG_KEY.test(key)) return false;\n if (!isDicomJsonElement(obj[key])) return false;\n }\n return true;\n}\n\n// ---------------------------------------------------------------------------\n// Tag normalization\n// ---------------------------------------------------------------------------\n\nconst TAG_WITH_PARENS = /^\\(([0-9A-Fa-f]{4}),([0-9A-Fa-f]{4})\\)$/;\nconst TAG_HEX_ONLY = /^[0-9A-Fa-f]{8}$/;\n\n/**\n * Normalizes a DICOM tag to 8-char uppercase hex.\n * Accepts `(0010,0010)` or `00100010` formats.\n */\nfunction normalizeTag(tag: DicomTag | string): Result<string> {\n const parenMatch = TAG_WITH_PARENS.exec(tag);\n if (parenMatch !== null) {\n const group = parenMatch[1];\n const element = parenMatch[2];\n /* v8 ignore next */\n if (group === undefined || element === undefined) return err(new Error(`Invalid tag: \"${tag}\"`));\n return ok(`${group}${element}`.toUpperCase());\n }\n if (TAG_HEX_ONLY.test(tag)) {\n return ok(tag.toUpperCase());\n }\n return err(new Error(`Invalid tag format: \"${tag}\". Expected (XXXX,XXXX) or XXXXXXXX`));\n}\n\n// ---------------------------------------------------------------------------\n// Element extraction helpers\n// ---------------------------------------------------------------------------\n\n/** Resolves an element from the data by normalized tag key. */\nfunction resolveElement(data: DicomJsonModel, tagKey: string): DicomJsonElement | undefined {\n return data[tagKey];\n}\n\n/**\n * Extracts the Alphabetic component from a PN (PersonName) value.\n * Returns empty string if the Alphabetic component is missing or the\n * value is not a valid PN object — consistent with DICOM PS3.5 which\n * treats missing components as empty strings.\n */\nfunction extractPNAlphabetic(first: unknown): string {\n if (typeof first !== 'object' || first === null) return '';\n const pn = first as Record<string, unknown>;\n const alphabetic = pn['Alphabetic'];\n return typeof alphabetic === 'string' ? alphabetic : '';\n}\n\n/** Converts a primitive value to string. */\nfunction primitiveToString(value: unknown): string {\n if (typeof value === 'string') return value;\n if (typeof value === 'number' || typeof value === 'boolean') return String(value);\n return '';\n}\n\n/** Extracts a string from a DicomJsonElement, handling PN values. */\nfunction extractString(element: DicomJsonElement): string {\n const values = element.Value;\n if (values === undefined || values.length === 0) return '';\n\n const first = values[0];\n if (first === undefined || first === null) return '';\n\n if (element.vr === 'PN') return extractPNAlphabetic(first);\n return primitiveToString(first);\n}\n\n/** Extracts a number from a DicomJsonElement with validation. */\nfunction extractNumber(element: DicomJsonElement): Result<number> {\n const values = element.Value;\n if (values === undefined || values.length === 0) {\n return err(new Error('Element has no Value array'));\n }\n const first = values[0];\n if (typeof first === 'number') return ok(first);\n if (typeof first === 'string') {\n const parsed = Number(first);\n if (Number.isNaN(parsed)) {\n return err(new Error(`Cannot convert \"${first}\" to number`));\n }\n return ok(parsed);\n }\n return err(new Error(`Value is not numeric: ${typeof first}`));\n}\n\n/** Extracts all values as strings from a DicomJsonElement. */\nfunction extractStrings(element: DicomJsonElement): ReadonlyArray<string> {\n const values = element.Value;\n if (values === undefined) return [];\n const result: string[] = [];\n for (const v of values) {\n if (typeof v === 'string') {\n result.push(v);\n } else if (typeof v === 'number' || typeof v === 'boolean') {\n result.push(String(v));\n } else {\n result.push('');\n }\n }\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Path traversal helpers (iterative, no recursion — Rule 8.2)\n// ---------------------------------------------------------------------------\n\n/** Gets the sequence items array from a DicomJsonElement. */\nfunction getSequenceItems(element: DicomJsonElement): ReadonlyArray<unknown> | undefined {\n if (element.vr !== 'SQ' || element.Value === undefined) return undefined;\n return element.Value;\n}\n\n/** Returns true if the value is a plausible DicomJsonModel (non-null object with no array). */\nfunction isPlausibleModel(value: unknown): value is DicomJsonModel {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/** Descends into a sequence item, returning the nested dataset or an error. */\nfunction descendIntoSequence(element: DicomJsonElement, seg: TagSegment): Result<DicomJsonModel> {\n const items = getSequenceItems(element);\n if (items === undefined) {\n return err(new Error(`Tag ${seg.tag} is not a sequence`));\n }\n const idx = seg.index ?? 0;\n const item = items[idx];\n if (!isPlausibleModel(item)) {\n return err(new Error(`Sequence ${seg.tag} has no valid item at index ${idx}`));\n }\n return ok(item);\n}\n\n/** Traverses a non-wildcard path iteratively through nested sequences. */\nfunction traversePath(data: DicomJsonModel, segments: ReadonlyArray<TagSegment>): Result<DicomJsonElement> {\n let current: DicomJsonModel = data;\n\n for (let i = 0; i < segments.length; i++) {\n const seg = segments[i];\n /* v8 ignore next */\n if (seg === undefined) return err(new Error('Unexpected undefined segment'));\n\n const tagResult = normalizeTag(seg.tag);\n if (!tagResult.ok) return err(tagResult.error);\n\n const element = resolveElement(current, tagResult.value);\n if (element === undefined) return err(new Error(`Tag ${seg.tag} not found`));\n\n if (i === segments.length - 1) return ok(element);\n\n const descent = descendIntoSequence(element, seg);\n if (!descent.ok) return err(descent.error);\n current = descent.value;\n }\n\n /* v8 ignore next */\n return err(new Error('Empty path segments'));\n}\n\n// ---------------------------------------------------------------------------\n// Wildcard collection (iterative queue — Rule 8.2)\n// ---------------------------------------------------------------------------\n\ninterface QueueEntry {\n readonly data: DicomJsonModel;\n readonly segmentIndex: number;\n}\n\ninterface WildcardResult {\n readonly values: ReadonlyArray<unknown>;\n readonly truncated: boolean;\n}\n\n/** Collects all values matching a wildcard path using an iterative BFS queue. */\nfunction collectWildcard(data: DicomJsonModel, segments: ReadonlyArray<TagSegment>): WildcardResult {\n const results: unknown[] = [];\n const queue: QueueEntry[] = [{ data, segmentIndex: 0 }];\n const maxIterations = MAX_TRAVERSAL_DEPTH * 100;\n\n let iteration = 0;\n for (; iteration < maxIterations && queue.length > 0; iteration++) {\n const entry = queue.shift();\n /* v8 ignore next */\n if (entry === undefined) break;\n processQueueEntry(entry, segments, results, queue);\n }\n\n return { values: results, truncated: iteration >= maxIterations && queue.length > 0 };\n}\n\n/** Processes a single queue entry for wildcard collection. */\nfunction processQueueEntry(entry: QueueEntry, segments: ReadonlyArray<TagSegment>, results: unknown[], queue: QueueEntry[]): void {\n const seg = segments[entry.segmentIndex];\n /* v8 ignore next */\n if (seg === undefined) return;\n\n const tagResult = normalizeTag(seg.tag);\n if (!tagResult.ok) return;\n\n const element = resolveElement(entry.data, tagResult.value);\n if (element === undefined) return;\n\n const isLast = entry.segmentIndex === segments.length - 1;\n\n if (isLast) {\n collectLeafValues(element, results);\n return;\n }\n\n enqueueSequenceItems(element, seg, entry.segmentIndex, queue);\n}\n\n/** Collects values from a leaf element into the results array. */\nfunction collectLeafValues(element: DicomJsonElement, results: unknown[]): void {\n if (element.Value !== undefined) {\n for (const v of element.Value) {\n results.push(v);\n }\n }\n}\n\n/** Enqueues child sequence items for further wildcard processing. */\nfunction enqueueSequenceItems(element: DicomJsonElement, seg: TagSegment, segmentIndex: number, queue: QueueEntry[]): void {\n const items = getSequenceItems(element);\n if (items === undefined) return;\n\n if (seg.isWildcard === true) {\n for (const item of items) {\n if (isPlausibleModel(item)) {\n queue.push({ data: item, segmentIndex: segmentIndex + 1 });\n }\n }\n } else {\n const idx = seg.index ?? 0;\n const item = items[idx];\n if (isPlausibleModel(item)) {\n queue.push({ data: item, segmentIndex: segmentIndex + 1 });\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Well-known DICOM tag keys (8-char hex, uppercase)\n// ---------------------------------------------------------------------------\n\nconst TAGS = {\n AccessionNumber: '00080050',\n PatientName: '00100010',\n PatientID: '00100020',\n StudyDate: '00080020',\n Modality: '00080060',\n SOPClassUID: '00080016',\n StudyInstanceUID: '0020000D',\n SeriesInstanceUID: '0020000E',\n SOPInstanceUID: '00080018',\n TransferSyntaxUID: '00020010',\n} as const;\n\n// ---------------------------------------------------------------------------\n// DicomDataset class\n// ---------------------------------------------------------------------------\n\n/**\n * Immutable wrapper around DICOM JSON Model data.\n *\n * Provides type-safe read-only accessors for DICOM tag values.\n * Construct via the static {@link DicomDataset.fromJson} factory.\n *\n * @example\n * ```ts\n * const result = DicomDataset.fromJson(jsonData);\n * if (result.ok) {\n * const ds = result.value;\n * console.log(ds.patientName);\n * console.log(ds.modality);\n * }\n * ```\n */\nclass DicomDataset {\n private readonly data: DicomJsonModel;\n\n private constructor(data: DicomJsonModel) {\n this.data = data;\n }\n\n /**\n * Creates a DicomDataset from a DICOM JSON Model object.\n *\n * Performs structural validation only — verifies the input is a non-null object.\n *\n * @param json - A DICOM JSON Model object (typically from dcm2json)\n * @returns A Result containing the DicomDataset or an error\n */\n static fromJson(json: unknown): Result<DicomDataset> {\n if (json === null || json === undefined || typeof json !== 'object' || Array.isArray(json)) {\n return err(new Error('Invalid DICOM JSON: expected a non-null, non-array object'));\n }\n const obj = json as Record<string, unknown>;\n if (!isValidDicomJsonModel(obj)) {\n return err(new Error('Invalid DICOM JSON: every key must be an 8-char hex tag and every value must have a \"vr\" string property'));\n }\n return ok(new DicomDataset(json as DicomJsonModel));\n }\n\n /**\n * Gets the full DICOM JSON element for a tag.\n *\n * @param tag - A DicomTag `(0010,0010)` or hex string `00100010`\n * @returns Result containing the element or an error if not found\n */\n getElement(tag: DicomTag | string): Result<DicomJsonElement> {\n const norm = normalizeTag(tag);\n if (!norm.ok) return err(norm.error);\n const element = resolveElement(this.data, norm.value);\n if (element === undefined) return err(new Error(`Tag ${tag} not found`));\n return ok(element);\n }\n\n /**\n * Gets the Value array for a tag.\n *\n * @param tag - A DicomTag `(0010,0010)` or hex string `00100010`\n * @returns Result containing the readonly Value array or an error\n */\n getValue(tag: DicomTag | string): Result<ReadonlyArray<unknown>> {\n const elemResult = this.getElement(tag);\n if (!elemResult.ok) return err(elemResult.error);\n const values = elemResult.value.Value;\n if (values === undefined) return err(new Error(`Tag ${tag} has no Value`));\n return ok(values);\n }\n\n /**\n * Gets the first element of the Value array for a tag.\n *\n * @param tag - A DicomTag `(0010,0010)` or hex string `00100010`\n * @returns Result containing the first value or an error\n */\n getFirstValue(tag: DicomTag | string): Result<unknown> {\n const valResult = this.getValue(tag);\n if (!valResult.ok) return err(valResult.error);\n const first = valResult.value[0];\n if (first === undefined) return err(new Error(`Tag ${tag} Value array is empty`));\n return ok(first);\n }\n\n /**\n * Gets a tag value as a string with optional fallback.\n *\n * Returns the fallback (default empty string) if the tag is missing or has no value.\n * Handles PN (PersonName) values by extracting the Alphabetic component.\n *\n * @param tag - A DicomTag `(0010,0010)` or hex string `00100010`\n * @param fallback - Value to return if tag is missing (default: `''`)\n * @returns The string value or the fallback\n */\n getString(tag: DicomTag | string, fallback = ''): string {\n const elemResult = this.getElement(tag);\n if (!elemResult.ok) return fallback;\n const str = extractString(elemResult.value);\n return str.length > 0 ? str : fallback;\n }\n\n /**\n * Gets a tag value as a validated number.\n *\n * @param tag - A DicomTag `(0010,0010)` or hex string `00100010`\n * @returns Result containing the number or an error\n */\n getNumber(tag: DicomTag | string): Result<number> {\n const elemResult = this.getElement(tag);\n if (!elemResult.ok) return err(elemResult.error);\n return extractNumber(elemResult.value);\n }\n\n /**\n * Gets all values of a tag as strings.\n *\n * Useful for multi-valued tags like CS (Code String).\n *\n * @param tag - A DicomTag `(0010,0010)` or hex string `00100010`\n * @returns Result containing the readonly string array or an error\n */\n getStrings(tag: DicomTag | string): Result<ReadonlyArray<string>> {\n const elemResult = this.getElement(tag);\n if (!elemResult.ok) return err(elemResult.error);\n return ok(extractStrings(elemResult.value));\n }\n\n /**\n * Checks whether a tag exists in the dataset.\n *\n * @param tag - A DicomTag `(0010,0010)` or hex string `00100010`\n * @returns `true` if the tag is present\n */\n hasTag(tag: DicomTag | string): boolean {\n const norm = normalizeTag(tag);\n if (!norm.ok) return false;\n return resolveElement(this.data, norm.value) !== undefined;\n }\n\n /**\n * Gets an element by traversing a dotted tag path through sequences.\n *\n * @param path - A branded DicomTagPath, e.g. `(0040,A730)[0].(0040,A160)`\n * @returns Result containing the element at the path or an error\n */\n getElementAtPath(path: DicomTagPath): Result<DicomJsonElement> {\n let segments: ReadonlyArray<TagSegment>;\n try {\n segments = tagPathToSegments(path);\n } catch (e: unknown) {\n return err(stderr(e));\n }\n return traversePath(this.data, segments);\n }\n\n /**\n * Finds all values matching a path with wildcard `[*]` indices.\n *\n * Traverses all items in wildcard sequence positions using an iterative BFS queue.\n * The traversal is bounded to {@link MAX_TRAVERSAL_DEPTH} * 100 iterations (5 000).\n * For extremely large datasets this may truncate results silently; callers\n * needing completeness guarantees should verify dataset size independently.\n *\n * @param path - A branded DicomTagPath, e.g. `(0040,A730)[*].(0040,A160)`\n * @returns A readonly array of all matching values (may be empty)\n */\n findValues(path: DicomTagPath): ReadonlyArray<unknown> {\n let segments: ReadonlyArray<TagSegment>;\n try {\n segments = tagPathToSegments(path);\n } catch {\n return [];\n }\n const result = collectWildcard(this.data, segments);\n return result.values;\n }\n\n // -----------------------------------------------------------------------\n // Convenience readonly getters\n // -----------------------------------------------------------------------\n\n /** Accession Number (0008,0050). */\n get accession(): string {\n return this.getString(TAGS.AccessionNumber);\n }\n\n /** Patient's Name (0010,0010). */\n get patientName(): string {\n return this.getString(TAGS.PatientName);\n }\n\n /** Patient ID (0010,0020). */\n get patientID(): string {\n return this.getString(TAGS.PatientID);\n }\n\n /** Study Date (0008,0020). */\n get studyDate(): string {\n return this.getString(TAGS.StudyDate);\n }\n\n /** Modality (0008,0060). */\n get modality(): string {\n return this.getString(TAGS.Modality);\n }\n\n /** SOP Class UID (0008,0016) as a branded SOPClassUID, or undefined if missing/invalid. */\n get sopClassUID(): SOPClassUID | undefined {\n const uid = this.getString(TAGS.SOPClassUID);\n if (uid.length === 0) return undefined;\n const result = createSOPClassUID(uid);\n return result.ok ? result.value : undefined;\n }\n\n /** Study Instance UID (0020,000D). */\n get studyInstanceUID(): string {\n return this.getString(TAGS.StudyInstanceUID);\n }\n\n /** Series Instance UID (0020,000E). */\n get seriesInstanceUID(): string {\n return this.getString(TAGS.SeriesInstanceUID);\n }\n\n /** SOP Instance UID (0008,0018). */\n get sopInstanceUID(): string {\n return this.getString(TAGS.SOPInstanceUID);\n }\n\n /** Transfer Syntax UID (0002,0010). */\n get transferSyntaxUID(): string {\n return this.getString(TAGS.TransferSyntaxUID);\n }\n}\n\nexport { DicomDataset };\n","/**\n * Short-lived DCMTK process execution.\n *\n * Two execution modes:\n * - `execCommand()` — convenience wrapper; uses `spawn()` internally for safety\n * - `spawnCommand()` — uses `child_process.spawn()`, safer for user-supplied values (Rule 7.4)\n *\n * Both enforce mandatory timeouts (Rule 4.2) and return `Result<DcmtkProcessResult>`.\n *\n * @module exec\n */\n\nimport { spawn } from 'node:child_process';\nimport type { ChildProcess } from 'node:child_process';\nimport kill from 'tree-kill';\nimport type { Result, DcmtkProcessResult, ExecOptions, SpawnOptions } from './types';\nimport { ok, err } from './types';\nimport { DEFAULT_TIMEOUT_MS, MAX_OUTPUT_BYTES } from './constants';\n\n/**\n * Kills a process tree by PID. Wraps tree-kill in a promise.\n *\n * @param pid - The process ID to kill\n */\nfunction killTree(pid: number): void {\n try {\n kill(pid);\n /* v8 ignore next */\n } catch {\n // Process may already be dead — not exceptional\n }\n}\n\n/**\n * Executes a DCMTK binary as a short-lived process.\n *\n * **Security:** This function uses `child_process.spawn()` internally, passing\n * arguments as an array to avoid shell interpretation. This eliminates shell\n * injection risks regardless of argument content (Rule 7.4).\n *\n * @param binary - Full path to the DCMTK binary\n * @param args - Command-line arguments (passed directly, no shell interpolation)\n * @param options - Execution options (timeout, cwd, signal)\n * @returns A Result containing the process output or an error\n * @throws Never throws for expected failures (Rule 6.1)\n *\n * @example\n * ```ts\n * const result = await execCommand('/usr/local/bin/dcm2json', ['+ll', 'input.dcm']);\n * if (result.ok) {\n * console.log(result.value.stdout);\n * }\n * ```\n */\nasync function execCommand(binary: string, args: readonly string[], options?: ExecOptions): Promise<Result<DcmtkProcessResult>> {\n const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\n return new Promise(resolve => {\n const child = spawn(binary, [...args], {\n cwd: options?.cwd,\n windowsHide: true,\n signal: options?.signal,\n });\n wireSpawnListeners(child, timeoutMs, resolve);\n });\n}\n\n/**\n * Wires event listeners on a spawned child process with timeout, bounded buffering, and settle logic.\n */\nfunction wireSpawnListeners(child: ChildProcess, timeoutMs: number, resolve: (result: Result<DcmtkProcessResult>) => void): void {\n let stdout = '';\n let stderr = '';\n let settled = false;\n\n const settle = (result: Result<DcmtkProcessResult>): void => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n resolve(result);\n };\n\n const timer = setTimeout(() => {\n if (child.pid !== undefined && child.pid !== null) killTree(child.pid);\n settle(err(new Error(`Process timed out after ${timeoutMs}ms`)));\n }, timeoutMs);\n\n child.stdout?.on('data', (chunk: Buffer | string) => {\n stdout += String(chunk);\n if (stdout.length + stderr.length > MAX_OUTPUT_BYTES) {\n if (child.pid !== undefined && child.pid !== null) killTree(child.pid);\n settle(err(new Error(`Process output exceeded ${MAX_OUTPUT_BYTES} bytes`)));\n }\n });\n\n child.stderr?.on('data', (chunk: Buffer | string) => {\n stderr += String(chunk);\n if (stdout.length + stderr.length > MAX_OUTPUT_BYTES) {\n if (child.pid !== undefined && child.pid !== null) killTree(child.pid);\n settle(err(new Error(`Process output exceeded ${MAX_OUTPUT_BYTES} bytes`)));\n }\n });\n\n child.on('error', (error: Error) => {\n if (child.pid !== undefined && child.pid !== null) killTree(child.pid);\n settle(err(new Error(`Process error: ${error.message}`)));\n });\n\n child.on('close', (code: number | null) => {\n settle(ok({ stdout, stderr, exitCode: code ?? 1 }));\n });\n}\n\n/**\n * Executes a DCMTK binary using `child_process.spawn()`.\n *\n * Like {@link execCommand}, arguments are passed as an array to avoid shell\n * injection (Rule 7.4). This variant additionally supports custom environment\n * variables via the `env` option.\n *\n * @param binary - Full path to the DCMTK binary\n * @param args - Command-line arguments (passed directly, no shell interpolation)\n * @param options - Execution options (timeout, cwd, signal, env)\n * @returns A Result containing the process output or an error\n * @throws Never throws for expected failures (Rule 6.1)\n *\n * @example\n * ```ts\n * const result = await spawnCommand('/usr/local/bin/dcmodify', ['-m', '(0010,0010)=Smith^John', 'input.dcm']);\n * ```\n */\nasync function spawnCommand(binary: string, args: readonly string[], options?: SpawnOptions): Promise<Result<DcmtkProcessResult>> {\n const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\n return new Promise(resolve => {\n const child = spawn(binary, [...args], {\n cwd: options?.cwd,\n env: options?.env ? { ...process.env, ...options.env } : undefined,\n windowsHide: true,\n signal: options?.signal,\n });\n wireSpawnListeners(child, timeoutMs, resolve);\n });\n}\n\nexport { execCommand, spawnCommand };\n","/**\n * Converts dcm2xml \"Native DICOM Model\" XML into the DICOM JSON Model (PS3.18 F.2).\n *\n * dcm2xml outputs XML in the DCMTK native format:\n * ```xml\n * <NativeDicomModel>\n * <DicomAttribute tag=\"00100010\" vr=\"PN\" keyword=\"PatientName\">\n * <PersonName number=\"1\">\n * <Alphabetic><FamilyName>Smith</FamilyName></Alphabetic>\n * </PersonName>\n * </DicomAttribute>\n * <DicomAttribute tag=\"00100020\" vr=\"LO\" keyword=\"PatientID\">\n * <Value number=\"1\">12345</Value>\n * </DicomAttribute>\n * </NativeDicomModel>\n * ```\n *\n * The DICOM JSON Model output:\n * ```json\n * {\n * \"00100010\": { \"vr\": \"PN\", \"Value\": [{\"Alphabetic\": \"Smith\"}] },\n * \"00100020\": { \"vr\": \"LO\", \"Value\": [\"12345\"] }\n * }\n * ```\n *\n * @module _xmlToJson\n * @internal\n */\n\nimport { XMLParser } from 'fast-xml-parser';\nimport { stderr } from 'stderr-lib';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\n\n/** DICOM JSON Model element. */\ninterface DicomJsonElement {\n readonly vr: string;\n readonly Value?: ReadonlyArray<unknown>;\n readonly InlineBinary?: string;\n readonly BulkDataURI?: string;\n}\n\n/** Mutable builder for DicomJsonElement during conversion. */\ninterface ElementBuilder {\n vr: string;\n Value?: unknown[];\n InlineBinary?: string;\n BulkDataURI?: string;\n}\n\n/** DICOM JSON Model top-level object. */\ntype DicomJsonModel = Record<string, DicomJsonElement>;\n\n/** Parsed XML attribute node from fast-xml-parser. */\ninterface XmlDicomAttribute {\n readonly '@_tag': string;\n readonly '@_vr': string;\n readonly '@_keyword'?: string;\n readonly Value?: unknown;\n readonly PersonName?: unknown;\n readonly InlineBinary?: unknown;\n readonly BulkDataURI?: unknown;\n readonly Item?: unknown;\n}\n\n/** Person name components from XML. */\ninterface XmlPersonNameComponent {\n readonly FamilyName?: string;\n readonly GivenName?: string;\n readonly MiddleName?: string;\n readonly NamePrefix?: string;\n readonly NameSuffix?: string;\n}\n\n/** PN representation types. */\ntype PnRepType = 'Alphabetic' | 'Ideographic' | 'Phonetic';\nconst PN_REPS: readonly PnRepType[] = ['Alphabetic', 'Ideographic', 'Phonetic'];\n\nconst ARRAY_TAG_NAMES = new Set(['DicomAttribute', 'Value', 'PersonName', 'Item']);\n\n/**\n * The 34 standard DICOM VR codes (PS3.5 Table 6.2-1).\n * Used to validate VR values from DCMTK XML output. Unrecognized VRs\n * (e.g. retired/internal codes like \"xs\", \"ox\") fall back to 'UN'.\n */\nconst KNOWN_VR_CODES = new Set([\n 'AE',\n 'AS',\n 'AT',\n 'CS',\n 'DA',\n 'DS',\n 'DT',\n 'FD',\n 'FL',\n 'IS',\n 'LO',\n 'LT',\n 'OB',\n 'OD',\n 'OF',\n 'OL',\n 'OV',\n 'OW',\n 'PN',\n 'SH',\n 'SL',\n 'SQ',\n 'SS',\n 'ST',\n 'SV',\n 'TM',\n 'UC',\n 'UI',\n 'UL',\n 'UN',\n 'UR',\n 'US',\n 'UT',\n 'UV',\n]);\n\n/**\n * Builds a PN string from name components.\n */\nfunction buildPnString(comp: XmlPersonNameComponent): string {\n const parts = [comp.FamilyName ?? '', comp.GivenName ?? '', comp.MiddleName ?? '', comp.NamePrefix ?? '', comp.NameSuffix ?? ''];\n let last = parts.length - 1;\n for (; last >= 0; last--) {\n if (parts[last] !== '') break;\n }\n return parts.slice(0, last + 1).join('^');\n}\n\n/** Ensures a value is an array. */\nfunction toArray(val: unknown): readonly unknown[] {\n if (Array.isArray(val)) return val;\n if (val === undefined || val === null) return [];\n return [val];\n}\n\n/**\n * Converts a PersonName XML element to DICOM JSON PN format.\n */\nfunction convertPersonName(pnNode: unknown): Record<string, string> {\n const result: Record<string, string> = {};\n /* v8 ignore next -- defensive guard for malformed XML */\n if (typeof pnNode !== 'object' || pnNode === null) return result;\n const pn = pnNode as Record<string, unknown>;\n\n for (const rep of PN_REPS) {\n const repNode = pn[rep];\n if (repNode !== undefined && typeof repNode === 'object' && repNode !== null) {\n const str = buildPnString(repNode as XmlPersonNameComponent);\n if (str.length > 0) {\n result[rep] = str;\n }\n }\n }\n return result;\n}\n\n/** Safely converts an unknown value to a string without risking [object Object]. */\nfunction safeString(val: unknown): string {\n if (typeof val === 'string') return val;\n if (typeof val === 'number' || typeof val === 'boolean') return String(val);\n /* v8 ignore next */\n return '';\n}\n\n/** Handles InlineBinary elements. */\nfunction convertInlineBinary(attr: XmlDicomAttribute, element: ElementBuilder): void {\n element.InlineBinary = safeString(attr.InlineBinary);\n}\n\n/** Handles BulkDataURI elements. */\nfunction convertBulkDataURI(attr: XmlDicomAttribute, element: ElementBuilder): void {\n const bulkArray = toArray(attr.BulkDataURI);\n const firstBulk = bulkArray[0];\n if (typeof firstBulk === 'object' && firstBulk !== null && '@_uri' in firstBulk) {\n element.BulkDataURI = safeString((firstBulk as Record<string, unknown>)['@_uri']);\n } else {\n element.BulkDataURI = safeString(firstBulk);\n }\n}\n\n/** Handles PersonName (PN VR) elements. */\nfunction convertPNValue(attr: XmlDicomAttribute, element: ElementBuilder): void {\n const pnArray = toArray(attr.PersonName);\n const values: Record<string, string>[] = [];\n for (const pn of pnArray) {\n values.push(convertPersonName(pn));\n }\n if (values.length > 0) element.Value = values;\n}\n\n/** Handles Sequence (SQ) elements. */\nfunction convertSequence(attr: XmlDicomAttribute, element: ElementBuilder): void {\n const items = toArray(attr.Item);\n const values: DicomJsonModel[] = [];\n for (const item of items) {\n /* v8 ignore next -- defensive guard for malformed XML */\n if (typeof item !== 'object' || item === null) continue;\n values.push(convertAttributes(item as Record<string, unknown>));\n }\n if (values.length > 0) element.Value = values;\n}\n\n/** Handles regular Value elements. */\nfunction convertRegularValue(attr: XmlDicomAttribute, element: ElementBuilder): void {\n const valArray = toArray(attr.Value);\n const values: unknown[] = [];\n for (const v of valArray) {\n if (typeof v === 'object' && v !== null && '#text' in v) {\n values.push((v as Record<string, unknown>)['#text']);\n } else {\n values.push(v);\n }\n }\n if (values.length > 0) element.Value = values;\n}\n\n/**\n * Converts a single DicomAttribute XML element to its DICOM JSON element.\n */\nfunction convertElement(attr: XmlDicomAttribute): DicomJsonElement {\n const rawVr = attr['@_vr'];\n const vr = KNOWN_VR_CODES.has(rawVr) ? rawVr : 'UN';\n const element: ElementBuilder = { vr };\n\n if (attr.InlineBinary !== undefined) {\n convertInlineBinary(attr, element);\n } else if (attr.BulkDataURI !== undefined) {\n convertBulkDataURI(attr, element);\n } else if (element.vr === 'PN' && attr.PersonName !== undefined) {\n convertPNValue(attr, element);\n } else if (element.vr === 'SQ' && attr.Item !== undefined) {\n convertSequence(attr, element);\n } else if (attr.Value !== undefined) {\n convertRegularValue(attr, element);\n }\n\n return Object.freeze(element) as DicomJsonElement;\n}\n\n/**\n * Converts an object containing DicomAttribute children into a DICOM JSON Model object.\n */\nfunction convertAttributes(obj: Record<string, unknown>): DicomJsonModel {\n const result: Record<string, DicomJsonElement> = {};\n const attrs = toArray(obj['DicomAttribute']);\n\n for (const attr of attrs) {\n if (typeof attr !== 'object' || attr === null) continue;\n const xmlAttr = attr as XmlDicomAttribute;\n const tag = xmlAttr['@_tag'];\n if (tag === undefined) continue;\n result[tag] = convertElement(xmlAttr);\n }\n\n return result;\n}\n\n/** XML parser configured for the DCMTK Native DICOM Model. */\nconst parser = new XMLParser({\n ignoreAttributes: false,\n attributeNamePrefix: '@_',\n parseTagValue: false,\n isArray: (name: string): boolean => ARRAY_TAG_NAMES.has(name),\n});\n\n/**\n * Converts dcm2xml XML output to DICOM JSON Model.\n *\n * @param xml - The XML string from dcm2xml\n * @returns A Result containing the DICOM JSON Model or an error\n */\nfunction xmlToJson(xml: string): Result<DicomJsonModel> {\n try {\n const parsed = parser.parse(xml) as Record<string, unknown>;\n const root = parsed['NativeDicomModel'];\n if (root === undefined) {\n return err(new Error('Invalid dcm2xml output: missing NativeDicomModel root element'));\n }\n // Empty NativeDicomModel produces an empty string from the parser\n if (typeof root !== 'object' || root === null) {\n return ok({});\n }\n return ok(convertAttributes(root as Record<string, unknown>));\n } catch (error: unknown) {\n return err(new Error(`Failed to parse dcm2xml XML: ${stderr(error).message}`));\n }\n}\n\nexport { xmlToJson };\nexport type { DicomJsonModel, DicomJsonElement };\n","/**\n * Repairs malformed JSON output from the dcm2json binary.\n *\n * DCMTK's dcm2json sometimes emits invalid JSON for numeric-string VRs\n * (DS, IS) by producing unquoted numbers in arrays:\n * ```json\n * \"Value\": [1.5, 2.0] // invalid — DS values must be strings\n * \"Value\": [\"1.5\", \"2.0\"] // valid\n * ```\n *\n * This module detects and repairs these patterns before JSON.parse.\n *\n * @module _repairJson\n * @internal\n */\n\n/**\n * Pattern matching \"Value\" arrays in DICOM JSON.\n * Captures: (prefix including `[`)(inner content)(closing `]`).\n */\nconst VALUE_ARRAY_PATTERN = /(\"Value\"\\s*:\\s*\\[)([\\s\\S]*?)(\\])/g;\n\n/**\n * Matches a bare (unquoted) numeric literal.\n * Handles integers, decimals, scientific notation, and negative values.\n */\nconst BARE_NUMBER = /^-?(?:\\d+\\.?\\d*|\\.\\d+)(?:[eE][+-]?\\d+)?$/;\n\n/**\n * Quotes a bare number token, leaving already-quoted strings unchanged.\n *\n * @param token - A trimmed token from inside a Value array\n * @returns The token, quoted if it was a bare number\n */\nfunction quoteIfBareNumber(token: string): string {\n const trimmed = token.trim();\n if (BARE_NUMBER.test(trimmed)) {\n return `\"${trimmed}\"`;\n }\n return trimmed;\n}\n\n/**\n * Repairs the inner content of a \"Value\" array by quoting bare numbers.\n *\n * @param inner - The content between `[` and `]`\n * @returns Repaired content with bare numbers quoted\n */\nfunction repairInner(inner: string): string {\n const trimmed = inner.trim();\n if (trimmed.length === 0) return inner;\n\n // Split on commas that are not inside quotes\n const tokens: string[] = [];\n let current = '';\n let inString = false;\n\n for (let i = 0; i < trimmed.length; i++) {\n const ch = trimmed[i]!;\n if (ch === '\"' && (i === 0 || trimmed[i - 1] !== '\\\\')) {\n inString = !inString;\n current += ch;\n } else if (ch === ',' && !inString) {\n tokens.push(current);\n current = '';\n } else {\n current += ch;\n }\n }\n tokens.push(current);\n\n return tokens.map(quoteIfBareNumber).join(', ');\n}\n\n/**\n * Repairs malformed dcm2json output by quoting unquoted numeric values in \"Value\" arrays.\n *\n * @param raw - The raw JSON string from dcm2json\n * @returns The repaired JSON string safe for JSON.parse\n */\nfunction repairJson(raw: string): string {\n return raw.replace(VALUE_ARRAY_PATTERN, (_match, prefix: string, inner: string, suffix: string) => {\n return `${prefix}${repairInner(inner)}${suffix}`;\n });\n}\n\nexport { repairJson };\n","/**\n * DICOM to JSON conversion using a two-phase strategy.\n *\n * Primary: dcm2xml → xmlToJson (more reliable output)\n * Fallback: dcm2json binary → repairJson → JSON.parse\n *\n * The result includes a `source` discriminant indicating which strategy succeeded.\n *\n * @module dcm2json\n */\n\nimport { stderr } from 'stderr-lib';\nimport { z } from 'zod';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { execCommand } from '../exec';\nimport { DEFAULT_TIMEOUT_MS } from '../constants';\nimport { resolveBinary } from './_resolveBinary';\nimport { createToolError, createValidationError } from './_toolError';\nimport { xmlToJson } from './_xmlToJson';\nimport { repairJson } from './_repairJson';\nimport type { DicomJsonModel } from './_xmlToJson';\nimport type { ToolBaseOptions } from './_toolTypes';\n\n/** Indicates which conversion strategy produced the result. */\ntype Dcm2jsonSource = 'xml' | 'direct';\n\n/** Options for {@link dcm2json}. */\ninterface Dcm2jsonOptions extends ToolBaseOptions {\n /** Skip the XML primary path and use direct dcm2json only. Defaults to false. */\n readonly directOnly?: boolean | undefined;\n /** Verbosity level for diagnostic output. `'verbose'` maps to `-v`, `'debug'` maps to `-d`. */\n readonly verbosity?: 'verbose' | 'debug' | undefined;\n}\n\n/** Result of a successful dcm2json conversion. */\ninterface Dcm2jsonResult {\n /** The DICOM JSON Model object. */\n readonly data: DicomJsonModel;\n /** Which conversion strategy produced this result. */\n readonly source: Dcm2jsonSource;\n}\n\nconst Dcm2jsonOptionsSchema = z\n .object({\n timeoutMs: z.number().int().positive().optional(),\n signal: z.instanceof(AbortSignal).optional(),\n directOnly: z.boolean().optional(),\n verbosity: z.enum(['verbose', 'debug']).optional(),\n })\n .strict()\n .optional();\n\n/** Maps verbosity level to command-line flag. */\nconst VERBOSITY_FLAGS: Record<'verbose' | 'debug', string> = { verbose: '-v', debug: '-d' };\n\n/**\n * Builds verbosity args for internal calls.\n */\nfunction buildVerbosityArgs(verbosity?: 'verbose' | 'debug'): string[] {\n if (verbosity !== undefined) {\n return [VERBOSITY_FLAGS[verbosity]];\n }\n return [];\n}\n\n/**\n * Attempts XML-primary conversion: dcm2xml → xmlToJson.\n */\nasync function tryXmlPath(inputPath: string, timeoutMs: number, signal?: AbortSignal, verbosity?: 'verbose' | 'debug'): Promise<Result<Dcm2jsonResult>> {\n const xmlBinary = resolveBinary('dcm2xml');\n if (!xmlBinary.ok) {\n return err(xmlBinary.error);\n }\n\n const xmlArgs = [...buildVerbosityArgs(verbosity), '-nat', inputPath];\n const xmlResult = await execCommand(xmlBinary.value, xmlArgs, { timeoutMs, signal });\n if (!xmlResult.ok) {\n return err(xmlResult.error);\n }\n\n if (xmlResult.value.exitCode !== 0) {\n return err(createToolError('dcm2xml', xmlArgs, xmlResult.value.exitCode, xmlResult.value.stderr));\n }\n\n const jsonResult = xmlToJson(xmlResult.value.stdout);\n if (!jsonResult.ok) {\n return err(jsonResult.error);\n }\n\n return ok({ data: jsonResult.value, source: 'xml' as const });\n}\n\n/**\n * Attempts direct conversion: dcm2json binary → repairJson → JSON.parse.\n */\nasync function tryDirectPath(inputPath: string, timeoutMs: number, signal?: AbortSignal, verbosity?: 'verbose' | 'debug'): Promise<Result<Dcm2jsonResult>> {\n const jsonBinary = resolveBinary('dcm2json');\n if (!jsonBinary.ok) {\n return err(jsonBinary.error);\n }\n\n const directArgs = [...buildVerbosityArgs(verbosity), inputPath];\n const result = await execCommand(jsonBinary.value, directArgs, { timeoutMs, signal });\n if (!result.ok) {\n return err(result.error);\n }\n\n if (result.value.exitCode !== 0) {\n return err(createToolError('dcm2json', directArgs, result.value.exitCode, result.value.stderr));\n }\n\n try {\n const repaired = repairJson(result.value.stdout);\n // Cast is safe: repairJson ensures valid DICOM JSON Model structure,\n // and JSON.parse returns `unknown` in strict TS (we narrow via caller checks).\n const data = JSON.parse(repaired) as DicomJsonModel;\n return ok({ data, source: 'direct' as const });\n } catch (parseError: unknown) {\n return err(createToolError('dcm2json', [inputPath], 1, `Parse error: ${stderr(parseError).message}`));\n }\n}\n\n/**\n * Converts a DICOM file to the DICOM JSON Model.\n *\n * Uses a two-phase strategy:\n * 1. Primary: dcm2xml → XML-to-JSON conversion (more reliable)\n * 2. Fallback: direct dcm2json binary with JSON repair\n *\n * @param inputPath - Path to the DICOM input file\n * @param options - Conversion options\n * @returns A Result containing the DICOM JSON Model with source discriminant\n *\n * @example\n * ```ts\n * const result = await dcm2json('/path/to/study.dcm');\n * if (result.ok) {\n * console.log(result.value.source); // 'xml' or 'direct'\n * console.log(result.value.data['00100010']); // Patient Name\n * }\n * ```\n */\nasync function dcm2json(inputPath: string, options?: Dcm2jsonOptions): Promise<Result<Dcm2jsonResult>> {\n const validation = Dcm2jsonOptionsSchema.safeParse(options);\n if (!validation.success) {\n return err(createValidationError('dcm2json', validation.error));\n }\n\n const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const signal = options?.signal;\n\n const verbosity = options?.verbosity;\n\n // Direct-only mode: skip XML path\n if (options?.directOnly === true) {\n return tryDirectPath(inputPath, timeoutMs, signal, verbosity);\n }\n\n // Try XML path first\n const xmlResult = await tryXmlPath(inputPath, timeoutMs, signal, verbosity);\n if (xmlResult.ok) {\n return xmlResult;\n }\n\n // Fall back to direct path\n return tryDirectPath(inputPath, timeoutMs, signal, verbosity);\n}\n\nexport { dcm2json };\nexport type { Dcm2jsonOptions, Dcm2jsonResult, Dcm2jsonSource, DicomJsonModel };\n","/**\n * Modify DICOM tags using the dcmodify binary.\n *\n * Uses spawnCommand instead of execCommand because user-supplied DICOM values\n * could contain shell metacharacters. Spawn passes args as an array with no\n * shell interpolation (Rule 7.4).\n *\n * @module dcmodify\n */\n\nimport { z } from 'zod';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { spawnCommand } from '../exec';\nimport { DEFAULT_TIMEOUT_MS } from '../constants';\nimport { resolveBinary } from './_resolveBinary';\nimport { createToolError, createValidationError } from './_toolError';\nimport type { ToolBaseOptions } from './_toolTypes';\n\n/** A single tag modification. */\ninterface TagModification {\n /** DICOM tag to modify, e.g. \"(0010,0010)\". */\n readonly tag: string;\n /** New value for the tag. */\n readonly value: string;\n}\n\n/** Options for {@link dcmodify}. */\ninterface DcmodifyOptions extends ToolBaseOptions {\n /** Tag modifications to apply. */\n readonly modifications?: readonly TagModification[] | undefined;\n /** Tag paths to erase (passed as `-e path`). */\n readonly erasures?: readonly string[] | undefined;\n /** Erase all private tags (uses `-ep` flag). */\n readonly erasePrivateTags?: boolean | undefined;\n /** Do not create backup (.bak) file. Defaults to true. */\n readonly noBackup?: boolean | undefined;\n /** Insert tag if it doesn't exist (uses -i flag). Defaults to false. */\n readonly insertIfMissing?: boolean | undefined;\n /** Treat 'tag not found' as success when erasing (uses -imt flag). Defaults to false. */\n readonly ignoreMissingTags?: boolean | undefined;\n /** Verbosity level for diagnostic output. `'verbose'` maps to `-v`, `'debug'` maps to `-d`. */\n readonly verbosity?: 'verbose' | 'debug' | undefined;\n}\n\n/** Result of a successful dcmodify operation. */\ninterface DcmodifyResult {\n /** Path to the modified DICOM file. */\n readonly filePath: string;\n}\n\n/** Matches a single tag or a dotted tag path: (XXXX,XXXX) or (XXXX,XXXX)[N].(XXXX,XXXX) */\nconst TAG_OR_PATH_PATTERN = /^\\([0-9A-Fa-f]{4},[0-9A-Fa-f]{4}\\)(\\[\\d+\\](\\.\\([0-9A-Fa-f]{4},[0-9A-Fa-f]{4}\\)(\\[\\d+\\])?)*)?$/;\n\nconst TagModificationSchema = z.object({\n tag: z.string().regex(TAG_OR_PATH_PATTERN),\n value: z.string(),\n});\n\n/** Maps verbosity level to command-line flag. */\nconst VERBOSITY_FLAGS: Record<'verbose' | 'debug', string> = { verbose: '-v', debug: '-d' };\n\nconst DcmodifyOptionsSchema = z\n .object({\n timeoutMs: z.number().int().positive().optional(),\n signal: z.instanceof(AbortSignal).optional(),\n modifications: z.array(TagModificationSchema).optional().default([]),\n erasures: z.array(z.string()).optional(),\n erasePrivateTags: z.boolean().optional(),\n noBackup: z.boolean().optional(),\n insertIfMissing: z.boolean().optional(),\n ignoreMissingTags: z.boolean().optional(),\n verbosity: z.enum(['verbose', 'debug']).optional(),\n })\n .strict()\n .refine(data => data.modifications.length > 0 || (data.erasures !== undefined && data.erasures.length > 0) || data.erasePrivateTags === true, {\n message: 'At least one of modifications, erasures, or erasePrivateTags is required',\n });\n\n/**\n * Builds dcmodify command-line arguments from validated options.\n */\nfunction buildArgs(inputPath: string, options: DcmodifyOptions): string[] {\n const args: string[] = [];\n\n if (options.verbosity !== undefined) {\n args.push(VERBOSITY_FLAGS[options.verbosity]);\n }\n\n if (options.noBackup !== false) {\n args.push('-nb');\n }\n\n if (options.ignoreMissingTags === true) {\n args.push('-imt');\n }\n\n const flag = options.insertIfMissing === true ? '-i' : '-m';\n const modifications = options.modifications ?? [];\n\n for (const mod of modifications) {\n args.push(flag, `${mod.tag}=${mod.value}`);\n }\n\n if (options.erasures !== undefined) {\n for (const erasure of options.erasures) {\n args.push('-e', erasure);\n }\n }\n\n if (options.erasePrivateTags === true) {\n args.push('-ep');\n }\n\n args.push(inputPath);\n\n return args;\n}\n\n/**\n * Modifies DICOM tags in a file using the dcmodify binary.\n *\n * Uses spawn (not exec) for safety with user-supplied values.\n *\n * @param inputPath - Path to the DICOM file to modify (modified in-place)\n * @param options - Modification options\n * @returns A Result containing the file path or an error\n *\n * @example\n * ```ts\n * const result = await dcmodify('/path/to/study.dcm', {\n * modifications: [\n * { tag: '(0010,0010)', value: 'Anonymous' },\n * { tag: '(0010,0020)', value: 'ANON001' },\n * ],\n * });\n * ```\n */\nasync function dcmodify(inputPath: string, options: DcmodifyOptions): Promise<Result<DcmodifyResult>> {\n const validation = DcmodifyOptionsSchema.safeParse(options);\n if (!validation.success) {\n return err(createValidationError('dcmodify', validation.error));\n }\n\n const binaryResult = resolveBinary('dcmodify');\n if (!binaryResult.ok) {\n return err(binaryResult.error);\n }\n\n const args = buildArgs(inputPath, options);\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\n const result = await spawnCommand(binaryResult.value, args, {\n timeoutMs,\n signal: options.signal,\n });\n\n if (!result.ok) {\n return err(result.error);\n }\n\n if (result.value.exitCode !== 0) {\n return err(createToolError('dcmodify', args, result.value.exitCode, result.value.stderr));\n }\n\n return ok({ filePath: inputPath });\n}\n\nexport { dcmodify };\nexport type { DcmodifyOptions, DcmodifyResult, TagModification };\n","/**\n * File operation helpers for DicomInstance.\n *\n * Extracted to keep DicomInstance methods under line-count limits.\n *\n * @module dicom/_fileHelpers\n */\n\nimport { copyFile, stat, unlink } from 'node:fs/promises';\nimport { tryCatch } from 'stderr-lib';\nimport type { DicomFilePath } from '../brands';\nimport { DEFAULT_TIMEOUT_MS } from '../constants';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport type { ChangeSet } from './ChangeSet';\nimport { dcmodify } from '../tools/dcmodify';\n\n/** Options for file I/O operations. */\ninterface FileIOOptions {\n /** Timeout in milliseconds. Defaults to DEFAULT_TIMEOUT_MS. */\n readonly timeoutMs?: number | undefined;\n /** AbortSignal for external cancellation. */\n readonly signal?: AbortSignal | undefined;\n}\n\n/** Bridges a ChangeSet to a dcmodify call on the given file. */\nasync function applyModifications(filePath: DicomFilePath, changeset: ChangeSet, options: FileIOOptions): Promise<Result<void>> {\n const modifications = changeset.toModifications();\n const erasures = changeset.toErasureArgs();\n\n const hasErasures = erasures.length > 0 || changeset.erasePrivate;\n\n const result = await dcmodify(filePath, {\n modifications: modifications.length > 0 ? modifications : undefined,\n erasures: erasures.length > 0 ? erasures : undefined,\n erasePrivateTags: changeset.erasePrivate || undefined,\n insertIfMissing: true,\n ignoreMissingTags: hasErasures || undefined,\n timeoutMs: options.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n signal: options.signal,\n });\n\n if (!result.ok) return err(result.error);\n return ok(undefined);\n}\n\n/** Wraps fs.copyFile in a Result. */\nasync function copyFileSafe(source: string, dest: string): Promise<Result<void>> {\n return tryCatch(\n () => copyFile(source, dest),\n e => new Error(`Failed to copy file: ${e.message}`)\n );\n}\n\n/** Wraps fs.stat in a Result, returning file size. */\nasync function statFileSize(path: string): Promise<Result<number>> {\n return tryCatch(\n async () => (await stat(path)).size,\n e => new Error(`Failed to stat file: ${e.message}`)\n );\n}\n\n/** Wraps fs.unlink in a Result. */\nasync function unlinkFile(path: string): Promise<Result<void>> {\n return tryCatch(\n () => unlink(path),\n e => new Error(`Failed to delete file: ${e.message}`)\n );\n}\n\nexport { applyModifications, copyFileSafe, statFileSize, unlinkFile };\nexport type { FileIOOptions };\n","/**\n * Unified DICOM object composing DicomDataset + ChangeSet + file I/O.\n *\n * Every setter returns a new DicomInstance — the original is never modified.\n * Designed for ergonomic DICOM workflows that combine reading, modifying,\n * and writing DICOM data in a single fluent API.\n *\n * @module dicom/DicomInstance\n */\n\nimport type { DicomFilePath, DicomTag, DicomTagPath, SOPClassUID } from '../brands';\nimport { createDicomFilePath } from '../brands';\nimport { DEFAULT_TIMEOUT_MS } from '../constants';\nimport type { Result } from '../types';\nimport { err, ok } from '../types';\nimport { ChangeSet } from './ChangeSet';\nimport { DicomDataset } from './DicomDataset';\nimport { dcm2json } from '../tools';\nimport type { FileIOOptions } from './_fileHelpers';\nimport { applyModifications, copyFileSafe, statFileSize, unlinkFile } from './_fileHelpers';\n\n// ---------------------------------------------------------------------------\n// DicomInstance class\n// ---------------------------------------------------------------------------\n\n/**\n * Unified DICOM object composing dataset, change tracking, file path, and metadata.\n *\n * Every setter returns a new immutable instance — the original is never modified.\n * Use the static factories {@link DicomInstance.open} or {@link DicomInstance.fromDataset}\n * to create instances.\n *\n * @example\n * ```ts\n * const result = await DicomInstance.open('/path/to/file.dcm');\n * if (!result.ok) { console.error(result.error.message); return; }\n * const modified = result.value\n * .setPatientName('DOE^JOHN')\n * .setPatientID('PAT001')\n * .erasePrivateTags();\n * await modified.writeAs('/path/to/output.dcm');\n * ```\n */\nclass DicomInstance {\n private readonly dicomDataset: DicomDataset;\n private readonly changeSet: ChangeSet;\n private readonly filepath: DicomFilePath | undefined;\n private readonly meta: ReadonlyMap<string, unknown>;\n\n private constructor(dataset: DicomDataset, changes: ChangeSet, filePath: DicomFilePath | undefined, metadata: ReadonlyMap<string, unknown>) {\n this.dicomDataset = dataset;\n this.changeSet = changes;\n this.filepath = filePath;\n this.meta = metadata;\n }\n\n // -----------------------------------------------------------------------\n // Factories\n // -----------------------------------------------------------------------\n\n /**\n * Opens a DICOM file and creates a DicomInstance.\n *\n * @param path - Filesystem path to the DICOM file\n * @param options - Timeout and abort options\n * @returns A Result containing the DicomInstance or an error\n */\n static async open(path: string, options?: FileIOOptions): Promise<Result<DicomInstance>> {\n const filePathResult = createDicomFilePath(path);\n if (!filePathResult.ok) return err(filePathResult.error);\n\n const jsonResult = await dcm2json(path, {\n timeoutMs: options?.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n signal: options?.signal,\n });\n if (!jsonResult.ok) return err(jsonResult.error);\n\n const datasetResult = DicomDataset.fromJson(jsonResult.value.data);\n if (!datasetResult.ok) return err(datasetResult.error);\n\n return ok(new DicomInstance(datasetResult.value, ChangeSet.empty(), filePathResult.value, new Map()));\n }\n\n /**\n * Creates a DicomInstance from an existing DicomDataset.\n *\n * @param dataset - The DicomDataset to wrap\n * @param filePath - Optional file path (e.g. if the dataset came from a file)\n * @returns A Result containing the DicomInstance\n */\n static fromDataset(dataset: DicomDataset, filePath?: string): Result<DicomInstance> {\n let fp: DicomFilePath | undefined;\n if (filePath !== undefined) {\n const fpResult = createDicomFilePath(filePath);\n if (!fpResult.ok) return err(fpResult.error);\n fp = fpResult.value;\n }\n return ok(new DicomInstance(dataset, ChangeSet.empty(), fp, new Map()));\n }\n\n // -----------------------------------------------------------------------\n // Read accessors (delegate to DicomDataset)\n // -----------------------------------------------------------------------\n\n /** The underlying immutable DICOM dataset. */\n get dataset(): DicomDataset {\n return this.dicomDataset;\n }\n\n /** The pending change set. */\n get changes(): ChangeSet {\n return this.changeSet;\n }\n\n /** Whether there are unsaved changes. */\n get hasUnsavedChanges(): boolean {\n return !this.changeSet.isEmpty;\n }\n\n /** The file path, or undefined if this instance has no associated file. */\n get filePath(): string | undefined {\n return this.filepath;\n }\n\n /** Patient's Name (0010,0010). */\n get patientName(): string {\n return this.dicomDataset.patientName;\n }\n\n /** Patient ID (0010,0020). */\n get patientID(): string {\n return this.dicomDataset.patientID;\n }\n\n /** Study Date (0008,0020). */\n get studyDate(): string {\n return this.dicomDataset.studyDate;\n }\n\n /** Modality (0008,0060). */\n get modality(): string {\n return this.dicomDataset.modality;\n }\n\n /** Accession Number (0008,0050). */\n get accession(): string {\n return this.dicomDataset.accession;\n }\n\n /** SOP Class UID (0008,0016). */\n get sopClassUID(): SOPClassUID | undefined {\n return this.dicomDataset.sopClassUID;\n }\n\n /** Study Instance UID (0020,000D). */\n get studyInstanceUID(): string {\n return this.dicomDataset.studyInstanceUID;\n }\n\n /** Series Instance UID (0020,000E). */\n get seriesInstanceUID(): string {\n return this.dicomDataset.seriesInstanceUID;\n }\n\n /** SOP Instance UID (0008,0018). */\n get sopInstanceUID(): string {\n return this.dicomDataset.sopInstanceUID;\n }\n\n /** Transfer Syntax UID (0002,0010). */\n get transferSyntaxUID(): string {\n return this.dicomDataset.transferSyntaxUID;\n }\n\n /**\n * Gets a tag value as a string with optional fallback.\n *\n * @param tag - A DICOM tag, e.g. `'(0010,0010)'` or `'00100010'`\n * @param fallback - Value to return if tag is missing (default: `''`)\n */\n getString(tag: DicomTag | string, fallback = ''): string {\n return this.dicomDataset.getString(tag, fallback);\n }\n\n /**\n * Gets a tag value as a number.\n *\n * @param tag - A DICOM tag, e.g. `'(0020,0013)'`\n */\n getNumber(tag: DicomTag | string): Result<number> {\n return this.dicomDataset.getNumber(tag);\n }\n\n /** Checks whether a tag exists in the dataset. */\n hasTag(tag: DicomTag | string): boolean {\n return this.dicomDataset.hasTag(tag);\n }\n\n /**\n * Finds all values matching a wildcard path.\n *\n * @param path - A DicomTagPath with optional wildcard indices\n */\n findValues(path: DicomTagPath): ReadonlyArray<unknown> {\n return this.dicomDataset.findValues(path);\n }\n\n // -----------------------------------------------------------------------\n // Write methods (return new instance)\n // -----------------------------------------------------------------------\n\n /**\n * Sets a tag value, returning a new DicomInstance.\n *\n * @param path - The DICOM tag path (e.g. `'(0010,0010)'`)\n * @param value - The new value\n */\n setTag(path: string, value: string): DicomInstance {\n return new DicomInstance(this.dicomDataset, this.changeSet.setTag(path, value), this.filepath, this.meta);\n }\n\n /**\n * Erases a tag, returning a new DicomInstance.\n *\n * @param path - The DICOM tag path to erase\n */\n eraseTag(path: string): DicomInstance {\n return new DicomInstance(this.dicomDataset, this.changeSet.eraseTag(path), this.filepath, this.meta);\n }\n\n /** Erases all private tags, returning a new DicomInstance. */\n erasePrivateTags(): DicomInstance {\n return new DicomInstance(this.dicomDataset, this.changeSet.erasePrivateTags(), this.filepath, this.meta);\n }\n\n /** Sets Patient's Name (0010,0010). */\n setPatientName(value: string): DicomInstance {\n return this.setTag('(0010,0010)', value);\n }\n\n /** Sets Patient ID (0010,0020). */\n setPatientID(value: string): DicomInstance {\n return this.setTag('(0010,0020)', value);\n }\n\n /** Sets Study Date (0008,0020). */\n setStudyDate(value: string): DicomInstance {\n return this.setTag('(0008,0020)', value);\n }\n\n /** Sets Modality (0008,0060). */\n setModality(value: string): DicomInstance {\n return this.setTag('(0008,0060)', value);\n }\n\n /** Sets Accession Number (0008,0050). */\n setAccessionNumber(value: string): DicomInstance {\n return this.setTag('(0008,0050)', value);\n }\n\n /** Sets Study Description (0008,1030). */\n setStudyDescription(value: string): DicomInstance {\n return this.setTag('(0008,1030)', value);\n }\n\n /** Sets Series Description (0008,103E). */\n setSeriesDescription(value: string): DicomInstance {\n return this.setTag('(0008,103E)', value);\n }\n\n /** Sets Institution Name (0008,0080). */\n setInstitutionName(value: string): DicomInstance {\n return this.setTag('(0008,0080)', value);\n }\n\n /**\n * Transforms a tag value using a function.\n *\n * The function receives the current string value (or undefined if tag is missing)\n * and returns the new value. Returns a new DicomInstance with the modification.\n *\n * @param path - The DICOM tag path\n * @param fn - Transform function receiving the current value\n */\n transformTag(path: string, fn: (current: string | undefined) => string): DicomInstance {\n const current = this.dicomDataset.getString(path);\n const newValue = fn(current.length > 0 ? current : undefined);\n return this.setTag(path, newValue);\n }\n\n /**\n * Sets multiple tags at once, returning a new DicomInstance.\n *\n * @param entries - A record of tag path → value pairs\n */\n setBatch(entries: Readonly<Record<string, string>>): DicomInstance {\n return new DicomInstance(this.dicomDataset, this.changeSet.setBatch(entries), this.filepath, this.meta);\n }\n\n /**\n * Returns a new DicomInstance with the given changes merged into pending changes.\n *\n * @param changes - A ChangeSet to merge with existing pending changes\n * @returns A new DicomInstance with accumulated changes\n */\n withChanges(changes: ChangeSet): DicomInstance {\n return new DicomInstance(this.dicomDataset, this.changeSet.merge(changes), this.filepath, this.meta);\n }\n\n /**\n * Returns a new DicomInstance pointing to a different file path.\n *\n * Preserves the dataset, pending changes, and metadata.\n *\n * @param newPath - The new filesystem path (validated via createDicomFilePath)\n * @returns A new DicomInstance with the updated path\n * @throws If the path is invalid\n */\n withFilePath(newPath: string): DicomInstance {\n const result = createDicomFilePath(newPath);\n if (!result.ok) throw result.error;\n return new DicomInstance(this.dicomDataset, this.changeSet, result.value, this.meta);\n }\n\n // -----------------------------------------------------------------------\n // File I/O\n // -----------------------------------------------------------------------\n\n /**\n * Applies pending changes to the file in-place.\n *\n * Requires that the instance has an associated file path.\n *\n * @param options - Timeout and abort options\n */\n async applyChanges(options?: FileIOOptions): Promise<Result<void>> {\n if (this.filepath === undefined) return err(new Error('No file path associated with this instance'));\n if (this.changeSet.isEmpty) return ok(undefined);\n return applyModifications(this.filepath, this.changeSet, options ?? {});\n }\n\n /**\n * Copies the file to a new path and applies pending changes to the copy.\n *\n * Returns a new DicomInstance pointing to the output path.\n *\n * @param outputPath - Destination filesystem path\n * @param options - Timeout and abort options\n */\n async writeAs(outputPath: string, options?: FileIOOptions): Promise<Result<DicomInstance>> {\n if (this.filepath === undefined) return err(new Error('No file path associated with this instance'));\n\n const outPathResult = createDicomFilePath(outputPath);\n if (!outPathResult.ok) return err(outPathResult.error);\n\n const copyResult = await copyFileSafe(this.filepath, outputPath);\n if (!copyResult.ok) return err(copyResult.error);\n\n if (!this.changeSet.isEmpty) {\n const applyResult = await applyModifications(outPathResult.value, this.changeSet, options ?? {});\n if (!applyResult.ok) {\n await unlinkFile(outputPath);\n return err(applyResult.error);\n }\n }\n\n return ok(new DicomInstance(this.dicomDataset, ChangeSet.empty(), outPathResult.value, this.meta));\n }\n\n /**\n * Gets the file size in bytes.\n *\n * @returns A Result containing the size or an error\n */\n async fileSize(): Promise<Result<number>> {\n if (this.filepath === undefined) return err(new Error('No file path associated with this instance'));\n return statFileSize(this.filepath);\n }\n\n /**\n * Deletes the associated file from the filesystem.\n *\n * @returns A Result indicating success or failure\n */\n async unlink(): Promise<Result<void>> {\n if (this.filepath === undefined) return err(new Error('No file path associated with this instance'));\n return unlinkFile(this.filepath);\n }\n\n // -----------------------------------------------------------------------\n // Metadata (non-DICOM app context)\n // -----------------------------------------------------------------------\n\n /**\n * Returns a new DicomInstance with application metadata attached.\n *\n * Metadata is not stored in the DICOM file — it's for application context\n * (e.g. tracking source association, processing status, etc.).\n *\n * @param key - Metadata key\n * @param value - Metadata value\n */\n withMetadata(key: string, value: unknown): DicomInstance {\n const newMeta = new Map(this.meta);\n newMeta.set(key, value);\n return new DicomInstance(this.dicomDataset, this.changeSet, this.filepath, newMeta);\n }\n\n /**\n * Gets application metadata by key.\n *\n * @param key - Metadata key\n * @returns The metadata value or undefined\n */\n getMetadata(key: string): unknown {\n return this.meta.get(key);\n }\n}\n\nexport { DicomInstance };\n","/**\n * Pooled DICOM receiver with auto-scaling.\n *\n * Manages a pool of long-lived `Dcmrecv` workers behind a TCP proxy,\n * routing incoming connections to idle workers. Workers are reused\n * across associations — they are only stopped during scale-down or\n * shutdown.\n *\n * @module servers/DicomReceiver\n */\n\nimport * as net from 'node:net';\nimport * as path from 'node:path';\nimport * as fs from 'node:fs/promises';\nimport * as os from 'node:os';\nimport { EventEmitter } from 'node:events';\nimport { z } from 'zod';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { isSafePath, isValidAETitle } from '../patterns';\nimport { createValidationError } from '../tools/_toolError';\nimport { Dcmrecv } from './Dcmrecv';\nimport type { AssociationCompleteData } from '../events/dcmrecv';\nimport { DicomInstance } from '../dicom/DicomInstance';\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_MIN_POOL_SIZE = 2;\nconst DEFAULT_MAX_POOL_SIZE = 10;\nconst DEFAULT_CONNECTION_TIMEOUT_MS = 10_000;\nconst CONNECTION_RETRY_INTERVAL_MS = 500;\nconst MAX_CONNECTION_RETRIES = 200;\n\n// ---------------------------------------------------------------------------\n// Public interfaces\n// ---------------------------------------------------------------------------\n\n/** Snapshot of the worker pool state. */\ninterface PoolStatus {\n /** Number of idle workers ready for connections. */\n readonly idle: number;\n /** Number of workers currently handling associations. */\n readonly busy: number;\n /** Total number of workers (idle + busy). */\n readonly total: number;\n}\n\n/** Data emitted with FILE_RECEIVED events. */\ninterface ReceiverFileData {\n readonly filePath: string;\n readonly associationId: string;\n readonly associationDir: string;\n readonly callingAE: string;\n readonly calledAE: string;\n readonly source: string;\n readonly instance: DicomInstance;\n}\n\n/** Data emitted with ASSOCIATION_COMPLETE events. */\ninterface ReceiverAssociationData {\n readonly associationId: string;\n readonly associationDir: string;\n readonly callingAE: string;\n readonly calledAE: string;\n readonly source: string;\n readonly files: readonly string[];\n readonly durationMs: number;\n readonly endReason: 'release' | 'abort';\n readonly totalBytes: number;\n readonly bytesPerSecond: number;\n readonly startAt: number;\n readonly endAt: number;\n}\n\n/** Data emitted with error events. */\ninterface ReceiverErrorData {\n readonly error: Error;\n readonly filePath?: string;\n readonly associationId?: string;\n readonly associationDir?: string;\n readonly callingAE?: string;\n readonly calledAE?: string;\n readonly source?: string;\n}\n\n/** Typed event map for DicomReceiver. */\ninterface DicomReceiverEventMap {\n FILE_RECEIVED: [ReceiverFileData];\n ASSOCIATION_COMPLETE: [ReceiverAssociationData];\n error: [ReceiverErrorData];\n}\n\n/** Options for creating a DicomReceiver instance. */\ninterface DicomReceiverOptions {\n /** External port to listen on (required). */\n readonly port: number;\n /** Root directory for association subdirectories (required). */\n readonly storageDir: string;\n /** Application Entity Title for workers. */\n readonly aeTitle?: string | undefined;\n /** Minimum number of idle workers to maintain. */\n readonly minPoolSize?: number | undefined;\n /** Maximum total workers allowed. */\n readonly maxPoolSize?: number | undefined;\n /** Timeout for waiting for an idle worker (milliseconds). */\n readonly connectionTimeoutMs?: number | undefined;\n /** Path to a dcmrecv association negotiation configuration file. */\n readonly configFile?: string | undefined;\n /** Profile name within the configuration file. */\n readonly configProfile?: string | undefined;\n /** AbortSignal for external cancellation. */\n readonly signal?: AbortSignal | undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Zod validation schema\n// ---------------------------------------------------------------------------\n\nconst DicomReceiverOptionsSchema = z\n .object({\n port: z.number().int().min(1).max(65535),\n storageDir: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in storageDir' }),\n aeTitle: z.string().min(1).max(16).refine(isValidAETitle, { message: 'AE Title contains invalid characters' }).optional(),\n minPoolSize: z.number().int().min(1).max(100).optional(),\n maxPoolSize: z.number().int().min(1).max(100).optional(),\n connectionTimeoutMs: z.number().int().positive().optional(),\n configFile: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in configFile' }).optional(),\n configProfile: z.string().min(1).optional(),\n signal: z.instanceof(AbortSignal).optional(),\n })\n .strict()\n .refine(data => (data.minPoolSize ?? DEFAULT_MIN_POOL_SIZE) <= (data.maxPoolSize ?? DEFAULT_MAX_POOL_SIZE), {\n message: 'minPoolSize must be <= maxPoolSize',\n });\n\n// ---------------------------------------------------------------------------\n// Internal worker type\n// ---------------------------------------------------------------------------\n\ninterface WorkerInfo {\n readonly dcmrecv: Dcmrecv;\n readonly port: number;\n readonly tempDir: string;\n state: 'idle' | 'busy';\n associationId: string | undefined;\n associationDir: string | undefined;\n /** Files moved to the association dir during the current association. */\n files: string[];\n /** Byte sizes parallel to files[], for transfer stats. */\n fileSizes: number[];\n /** Timestamp when the TCP connection was routed to this worker. */\n startAt: number | undefined;\n remoteSocket: net.Socket | undefined;\n workerSocket: net.Socket | undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Port allocation helper\n// ---------------------------------------------------------------------------\n\n/** Allocates a free ephemeral port by binding to port 0. */\nfunction allocatePort(): Promise<Result<number>> {\n return new Promise(resolve => {\n const server = net.createServer();\n server.listen(0, '127.0.0.1', () => {\n const addr = server.address();\n if (addr === null || typeof addr === 'string') {\n server.close(() => resolve(err(new Error('Failed to allocate port'))));\n return;\n }\n const port = addr.port;\n server.close(() => resolve(ok(port)));\n });\n server.on('error', e => {\n resolve(err(new Error(`Port allocation failed: ${e.message}`)));\n });\n });\n}\n\n// ---------------------------------------------------------------------------\n// DicomReceiver class\n// ---------------------------------------------------------------------------\n\n/**\n * Pooled DICOM receiver with auto-scaling.\n *\n * Manages a pool of long-lived `Dcmrecv` workers behind a TCP proxy.\n * Incoming connections are routed to idle workers. Workers are reused\n * across associations and only stopped during scale-down or shutdown.\n *\n * @example\n * ```ts\n * const result = DicomReceiver.create({\n * port: 4242,\n * storageDir: '/data/received',\n * minPoolSize: 2,\n * maxPoolSize: 8,\n * });\n * if (!result.ok) { console.error(result.error.message); return; }\n * const receiver = result.value;\n *\n * receiver.onFileReceived(data => console.log('File:', data.filePath));\n * receiver.onAssociationComplete(data => console.log('Done:', data.associationDir));\n *\n * await receiver.start();\n * ```\n */\nclass DicomReceiver extends EventEmitter<DicomReceiverEventMap> {\n private readonly options: DicomReceiverOptions;\n private readonly minPoolSize: number;\n private readonly maxPoolSize: number;\n private readonly connectionTimeoutMs: number;\n private readonly workers: Map<number, WorkerInfo> = new Map();\n private tcpServer: net.Server | undefined;\n private associationCounter = 0;\n private started = false;\n private stopping = false;\n private abortHandler: (() => void) | undefined;\n\n private constructor(options: DicomReceiverOptions) {\n super();\n this.setMaxListeners(20);\n this.on('error', () => {\n /* prevent Node.js uncaught exception on unhandled 'error' */\n });\n this.options = options;\n this.minPoolSize = options.minPoolSize ?? DEFAULT_MIN_POOL_SIZE;\n this.maxPoolSize = options.maxPoolSize ?? DEFAULT_MAX_POOL_SIZE;\n this.connectionTimeoutMs = options.connectionTimeoutMs ?? DEFAULT_CONNECTION_TIMEOUT_MS;\n }\n\n // -----------------------------------------------------------------------\n // Public API\n // -----------------------------------------------------------------------\n\n /**\n * Creates a new DicomReceiver instance.\n *\n * @param options - Configuration options\n * @returns A Result containing the instance or a validation error\n */\n static create(options: DicomReceiverOptions): Result<DicomReceiver> {\n const validation = DicomReceiverOptionsSchema.safeParse(options);\n if (!validation.success) {\n return err(createValidationError('DicomReceiver', validation.error));\n }\n return ok(new DicomReceiver(options));\n }\n\n /**\n * Starts the TCP proxy and spawns the initial worker pool.\n *\n * @returns A Result indicating success or failure\n */\n async start(): Promise<Result<void>> {\n if (this.started) {\n return err(new Error('DicomReceiver: already started'));\n }\n this.started = true;\n\n const storageDirResult = await ensureDirectory(this.options.storageDir);\n if (!storageDirResult.ok) return storageDirResult;\n\n const spawnResults = await this.spawnWorkers(this.minPoolSize);\n if (!spawnResults.ok) return spawnResults;\n\n const listenResult = await this.startTcpProxy();\n if (!listenResult.ok) return listenResult;\n\n if (this.options.signal !== undefined) {\n this.wireAbortSignal(this.options.signal);\n }\n\n return ok(undefined);\n }\n\n /**\n * Stops the TCP proxy and all workers.\n */\n async stop(): Promise<void> {\n if (!this.started || this.stopping) {\n return;\n }\n this.stopping = true;\n\n if (this.options.signal !== undefined && this.abortHandler !== undefined) {\n this.options.signal.removeEventListener('abort', this.abortHandler);\n }\n\n await this.closeTcpProxy();\n\n const stopPromises: Promise<void>[] = [];\n for (const worker of this.workers.values()) {\n stopPromises.push(this.stopWorker(worker));\n }\n await Promise.all(stopPromises);\n this.workers.clear();\n\n this.started = false;\n this.stopping = false;\n }\n\n /**\n * Registers a typed listener for a DicomReceiver-specific event.\n *\n * @param event - The event name from DicomReceiverEventMap\n * @param listener - Callback receiving typed event data\n * @returns this for chaining\n */\n onEvent<K extends keyof DicomReceiverEventMap>(event: K, listener: (...args: DicomReceiverEventMap[K]) => void): this {\n return this.on(event, listener as never);\n }\n\n /**\n * Registers a listener for received files.\n *\n * @param listener - Callback receiving file data\n * @returns this for chaining\n */\n onFileReceived(listener: (data: ReceiverFileData) => void): this {\n return this.on('FILE_RECEIVED', listener);\n }\n\n /**\n * Registers a listener for completed associations.\n *\n * @param listener - Callback receiving association data\n * @returns this for chaining\n */\n onAssociationComplete(listener: (data: ReceiverAssociationData) => void): this {\n return this.on('ASSOCIATION_COMPLETE', listener);\n }\n\n /** Current pool status. */\n get poolStatus(): PoolStatus {\n let idle = 0;\n let busy = 0;\n for (const w of this.workers.values()) {\n if (w.state === 'idle') idle++;\n else busy++;\n }\n return { idle, busy, total: this.workers.size };\n }\n\n // -----------------------------------------------------------------------\n // TCP proxy\n // -----------------------------------------------------------------------\n\n /** Starts the TCP proxy on the configured port. */\n private startTcpProxy(): Promise<Result<void>> {\n return new Promise(resolve => {\n this.tcpServer = net.createServer(socket => {\n void this.handleConnection(socket);\n });\n this.tcpServer.on('error', e => {\n if (!this.started) {\n resolve(err(new Error(`DicomReceiver: TCP proxy failed: ${e.message}`)));\n } else {\n this.emit('error', { error: e instanceof Error ? e : new Error(String(e)) });\n }\n });\n this.tcpServer.listen(this.options.port, () => {\n resolve(ok(undefined));\n });\n });\n }\n\n /** Closes the TCP proxy server. */\n private closeTcpProxy(): Promise<void> {\n return new Promise(resolve => {\n if (this.tcpServer === undefined) {\n resolve();\n return;\n }\n this.tcpServer.close(() => resolve());\n });\n }\n\n // -----------------------------------------------------------------------\n // Connection routing\n // -----------------------------------------------------------------------\n\n /** Routes an incoming connection to an idle worker. */\n private async handleConnection(remoteSocket: net.Socket): Promise<void> {\n remoteSocket.pause();\n\n const worker = await this.findIdleWorker();\n if (worker === undefined) {\n remoteSocket.destroy(new Error('DicomReceiver: no idle worker available'));\n this.emit('error', { error: new Error('DicomReceiver: connection rejected — pool exhausted') });\n return;\n }\n\n this.associationCounter++;\n const associationId = `assoc-${String(this.associationCounter)}`;\n const associationDir = path.join(this.options.storageDir, associationId);\n\n const mkdirResult = await ensureDirectory(associationDir);\n if (!mkdirResult.ok) {\n remoteSocket.destroy();\n this.emit('error', { error: mkdirResult.error });\n return;\n }\n\n worker.state = 'busy';\n worker.associationId = associationId;\n worker.associationDir = associationDir;\n worker.files = [];\n worker.fileSizes = [];\n worker.startAt = Date.now();\n\n this.pipeConnection(worker, remoteSocket);\n void this.replenishPool();\n }\n\n /** Finds an idle worker, retrying up to connectionTimeoutMs. */\n private async findIdleWorker(): Promise<WorkerInfo | undefined> {\n const idle = this.getIdleWorker();\n if (idle !== undefined) return idle;\n\n const maxRetries = Math.min(Math.ceil(this.connectionTimeoutMs / CONNECTION_RETRY_INTERVAL_MS), MAX_CONNECTION_RETRIES);\n\n for (let i = 0; i < maxRetries; i++) {\n await delay(CONNECTION_RETRY_INTERVAL_MS);\n const found = this.getIdleWorker();\n if (found !== undefined) return found;\n if (this.stopping) return undefined;\n }\n return undefined;\n }\n\n /** Returns the first idle worker, or undefined. */\n private getIdleWorker(): WorkerInfo | undefined {\n for (const w of this.workers.values()) {\n if (w.state === 'idle') return w;\n }\n return undefined;\n }\n\n /** Pipes remote socket bidirectionally to the worker's port. */\n private pipeConnection(worker: WorkerInfo, remoteSocket: net.Socket): void {\n const workerSocket = net.createConnection({ port: worker.port, host: '127.0.0.1' });\n\n worker.remoteSocket = remoteSocket;\n worker.workerSocket = workerSocket;\n\n remoteSocket.pipe(workerSocket);\n workerSocket.pipe(remoteSocket);\n\n remoteSocket.resume();\n\n const cleanup = (): void => {\n remoteSocket.unpipe(workerSocket);\n workerSocket.unpipe(remoteSocket);\n if (!remoteSocket.destroyed) remoteSocket.destroy();\n if (!workerSocket.destroyed) workerSocket.destroy();\n };\n\n remoteSocket.on('error', cleanup);\n workerSocket.on('error', cleanup);\n remoteSocket.on('close', cleanup);\n workerSocket.on('close', cleanup);\n }\n\n // -----------------------------------------------------------------------\n // Worker pool management\n // -----------------------------------------------------------------------\n\n /** Spawns `count` new workers and adds them to the pool. */\n private async spawnWorkers(count: number): Promise<Result<void>> {\n const promises: Promise<Result<WorkerInfo>>[] = [];\n for (let i = 0; i < count; i++) {\n promises.push(this.spawnWorker());\n }\n const results = await Promise.all(promises);\n for (const result of results) {\n if (!result.ok) return err(result.error);\n }\n return ok(undefined);\n }\n\n /** Spawns a single Dcmrecv worker with an ephemeral port. */\n private async spawnWorker(): Promise<Result<WorkerInfo>> {\n const portResult = await allocatePort();\n if (!portResult.ok) return portResult;\n const port = portResult.value;\n\n const tempDir = path.join(os.tmpdir(), `dcmrecv-pool-${String(port)}-${String(Date.now())}`);\n const mkdirResult = await ensureDirectory(tempDir);\n if (!mkdirResult.ok) return mkdirResult;\n\n const createResult = Dcmrecv.create({\n port,\n aeTitle: this.options.aeTitle ?? 'DCMRECV',\n outputDirectory: tempDir,\n configFile: this.options.configFile,\n configProfile: this.options.configProfile,\n });\n if (!createResult.ok) return createResult;\n\n const dcmrecv = createResult.value;\n const worker: WorkerInfo = {\n dcmrecv,\n port,\n tempDir,\n state: 'idle',\n associationId: undefined,\n associationDir: undefined,\n files: [],\n fileSizes: [],\n startAt: undefined,\n remoteSocket: undefined,\n workerSocket: undefined,\n };\n\n this.wireWorkerEvents(worker);\n const startResult = await dcmrecv.start();\n if (!startResult.ok) {\n return err(new Error(`DicomReceiver: worker start failed on port ${String(port)}: ${startResult.error.message}`));\n }\n\n this.workers.set(port, worker);\n return ok(worker);\n }\n\n /** Stops a single worker: stop process, clean temp dir, remove from pool. */\n private async stopWorker(worker: WorkerInfo): Promise<void> {\n if (worker.remoteSocket !== undefined && !worker.remoteSocket.destroyed) {\n worker.remoteSocket.destroy();\n }\n if (worker.workerSocket !== undefined && !worker.workerSocket.destroyed) {\n worker.workerSocket.destroy();\n }\n await worker.dcmrecv.stop();\n worker.dcmrecv[Symbol.dispose]();\n await removeDirSafe(worker.tempDir);\n this.workers.delete(worker.port);\n }\n\n /** Pre-emptively spawns workers to keep idle count >= minPoolSize. */\n private async replenishPool(): Promise<void> {\n const status = this.poolStatus;\n const needed = this.minPoolSize - status.idle;\n const capacity = this.maxPoolSize - status.total;\n const toSpawn = Math.min(needed, capacity);\n\n if (toSpawn <= 0) return;\n\n const promises: Promise<Result<WorkerInfo>>[] = [];\n for (let i = 0; i < toSpawn; i++) {\n promises.push(this.spawnWorker());\n }\n const results = await Promise.all(promises);\n for (const result of results) {\n if (!result.ok) {\n this.emit('error', { error: result.error });\n }\n }\n }\n\n /** Stops excess idle workers when idle count > minPoolSize + 2. */\n private async scaleDown(): Promise<void> {\n const idleWorkers: WorkerInfo[] = [];\n for (const w of this.workers.values()) {\n if (w.state === 'idle') idleWorkers.push(w);\n }\n const excess = idleWorkers.length - (this.minPoolSize + 2);\n if (excess <= 0) return;\n\n const toStop = idleWorkers.slice(0, excess);\n const promises: Promise<void>[] = [];\n for (const w of toStop) {\n promises.push(this.stopWorker(w));\n }\n await Promise.all(promises);\n }\n\n // -----------------------------------------------------------------------\n // Worker event wiring\n // -----------------------------------------------------------------------\n\n /** Wires FILE_RECEIVED and ASSOCIATION_COMPLETE events on a worker. */\n private wireWorkerEvents(worker: WorkerInfo): void {\n this.wireFileReceived(worker);\n this.wireAssociationComplete(worker);\n }\n\n /** Wires FILE_RECEIVED from dcmrecv worker to handleFileReceived. */\n private wireFileReceived(worker: WorkerInfo): void {\n worker.dcmrecv.onFileReceived(data => {\n void this.handleFileReceived(worker, data);\n });\n }\n\n /** Moves a received file, opens it as DicomInstance, and emits FILE_RECEIVED. */\n private async handleFileReceived(worker: WorkerInfo, data: { filePath: string; callingAE: string; calledAE: string; source: string }): Promise<void> {\n if (worker.associationDir === undefined || worker.associationId === undefined) return;\n const srcPath = data.filePath;\n const destPath = path.join(worker.associationDir, path.basename(srcPath));\n const assocId = worker.associationId;\n const assocDir = worker.associationDir;\n\n const moveResult = await moveFile(srcPath, destPath);\n const finalPath = moveResult.ok ? destPath : srcPath;\n worker.files.push(finalPath);\n worker.fileSizes.push(await statFileSafe(finalPath));\n\n const openResult = await DicomInstance.open(finalPath);\n if (!openResult.ok) {\n this.emit('error', {\n error: openResult.error,\n filePath: finalPath,\n associationId: assocId,\n associationDir: assocDir,\n callingAE: data.callingAE,\n calledAE: data.calledAE,\n source: data.source,\n });\n return;\n }\n\n this.emit('FILE_RECEIVED', {\n filePath: finalPath,\n associationId: assocId,\n associationDir: assocDir,\n callingAE: data.callingAE,\n calledAE: data.calledAE,\n source: data.source,\n instance: openResult.value,\n });\n }\n\n /** Returns worker to idle pool on association complete, emits summary. */\n private wireAssociationComplete(worker: WorkerInfo): void {\n worker.dcmrecv.onAssociationComplete((data: AssociationCompleteData) => {\n const assocId = worker.associationId ?? data.associationId;\n const assocDir = worker.associationDir ?? '';\n const files = [...worker.files];\n\n const endAt = Date.now();\n const startAt = worker.startAt ?? endAt;\n const totalBytes = sumArray(worker.fileSizes);\n const elapsedMs = endAt - startAt;\n const bytesPerSecond = elapsedMs > 0 ? Math.round((totalBytes / elapsedMs) * 1000) : 0;\n\n this.emit('ASSOCIATION_COMPLETE', {\n associationId: assocId,\n associationDir: assocDir,\n callingAE: data.callingAE,\n calledAE: data.calledAE,\n source: data.source,\n files,\n durationMs: data.durationMs,\n endReason: data.endReason,\n totalBytes,\n bytesPerSecond,\n startAt,\n endAt,\n });\n\n worker.state = 'idle';\n worker.associationId = undefined;\n worker.associationDir = undefined;\n worker.files = [];\n worker.fileSizes = [];\n worker.startAt = undefined;\n worker.remoteSocket = undefined;\n worker.workerSocket = undefined;\n\n void this.scaleDown();\n });\n }\n\n // -----------------------------------------------------------------------\n // Abort signal\n // -----------------------------------------------------------------------\n\n /** Wires an AbortSignal to stop the receiver. */\n private wireAbortSignal(signal: AbortSignal): void {\n /* v8 ignore next 4 */\n if (signal.aborted) {\n void this.stop();\n return;\n }\n this.abortHandler = (): void => {\n void this.stop();\n };\n signal.addEventListener('abort', this.abortHandler, { once: true });\n }\n}\n\n// ---------------------------------------------------------------------------\n// File system helpers\n// ---------------------------------------------------------------------------\n\n/** Ensures a directory exists, creating it recursively if needed. */\nasync function ensureDirectory(dirPath: string): Promise<Result<void>> {\n try {\n await fs.mkdir(dirPath, { recursive: true });\n return ok(undefined);\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n return err(new Error(`Failed to create directory ${dirPath}: ${msg}`));\n }\n}\n\n/** Moves a file from src to dest, falling back to copy+delete on cross-device. */\nasync function moveFile(src: string, dest: string): Promise<Result<void>> {\n try {\n await fs.rename(src, dest);\n return ok(undefined);\n } catch {\n try {\n await fs.copyFile(src, dest);\n await fs.unlink(src);\n return ok(undefined);\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n return err(new Error(`Failed to move file ${src} → ${dest}: ${msg}`));\n }\n }\n}\n\n/** Returns the file size in bytes, or 0 on error. */\nasync function statFileSafe(filePath: string): Promise<number> {\n try {\n const stat = await fs.stat(filePath);\n return stat.size;\n } catch {\n /* v8 ignore next */\n return 0;\n }\n}\n\n/** Sums an array of numbers iteratively. */\nfunction sumArray(arr: readonly number[]): number {\n let total = 0;\n for (let i = 0; i < arr.length; i++) {\n total += arr[i] ?? 0;\n }\n return total;\n}\n\n/** Removes a directory recursively, ignoring errors. */\nasync function removeDirSafe(dirPath: string): Promise<void> {\n try {\n await fs.rm(dirPath, { recursive: true, force: true });\n } catch {\n /* best-effort cleanup */\n }\n}\n\n/** Promise-based delay. */\nfunction delay(ms: number): Promise<void> {\n return new Promise(resolve => {\n setTimeout(resolve, ms);\n });\n}\n\nexport { DicomReceiver };\nexport type { DicomReceiverOptions, DicomReceiverEventMap, ReceiverFileData, ReceiverAssociationData, ReceiverErrorData, PoolStatus };\n","/**\n * Event patterns and types for dcmprscp output parsing.\n *\n * Defines regex patterns that match DCMTK dcmprscp (print management SCP)\n * verbose output, along with typed event data interfaces for each event.\n *\n * @module events/dcmprscp\n */\n\nimport type { EventPattern } from '../parsers/EventPattern';\n\n// ---------------------------------------------------------------------------\n// Event constants (as const, not enum — Rule 3.5)\n// ---------------------------------------------------------------------------\n\n/** Events emitted by dcmprscp process output. */\nconst DcmprscpEvent = {\n DATABASE_READY: 'DATABASE_READY',\n ASSOCIATION_RECEIVED: 'ASSOCIATION_RECEIVED',\n ASSOCIATION_ACKNOWLEDGED: 'ASSOCIATION_ACKNOWLEDGED',\n ASSOCIATION_RELEASE: 'ASSOCIATION_RELEASE',\n ASSOCIATION_ABORTED: 'ASSOCIATION_ABORTED',\n CANNOT_START_LISTENER: 'CANNOT_START_LISTENER',\n CONFIG_ERROR: 'CONFIG_ERROR',\n} as const;\n\ntype DcmprscpEventValue = (typeof DcmprscpEvent)[keyof typeof DcmprscpEvent];\n\n// ---------------------------------------------------------------------------\n// Event data interfaces (all readonly)\n// ---------------------------------------------------------------------------\n\n/** Data for DATABASE_READY event. */\ninterface DatabaseReadyData {\n readonly directory: string;\n}\n\n/** Data for ASSOCIATION_RECEIVED event. */\ninterface PrintAssociationReceivedData {\n readonly peerInfo: string;\n}\n\n/** Data for ASSOCIATION_ACKNOWLEDGED event. */\ninterface PrintAssociationAcknowledgedData {\n readonly maxSendPDV: number;\n}\n\n/** Data for CANNOT_START_LISTENER event. */\ninterface PrintCannotStartListenerData {\n readonly message: string;\n}\n\n/** Data for CONFIG_ERROR event. */\ninterface ConfigErrorData {\n readonly message: string;\n}\n\n// ---------------------------------------------------------------------------\n// Regex patterns for dcmprscp verbose output\n// ---------------------------------------------------------------------------\n\n/** Event patterns for parsing dcmprscp verbose output. */\nconst DCMPRSCP_PATTERNS: readonly EventPattern[] = [\n {\n event: DcmprscpEvent.DATABASE_READY,\n pattern: /Using database in directory\\s+'([^']+)'/,\n processor: (match): DatabaseReadyData => ({\n directory: match[1] ?? '',\n }),\n },\n {\n event: DcmprscpEvent.ASSOCIATION_RECEIVED,\n pattern: /Association Received\\s{0,20}\\(([^)]+)\\)/,\n processor: (match): PrintAssociationReceivedData => ({\n peerInfo: (match[1] ?? '').trim(),\n }),\n },\n {\n event: DcmprscpEvent.ASSOCIATION_ACKNOWLEDGED,\n pattern: /Association Acknowledged \\(Max Send PDV:\\s*(\\d+)\\)/,\n processor: (match): PrintAssociationAcknowledgedData => ({\n maxSendPDV: Number(match[1]),\n }),\n },\n {\n event: DcmprscpEvent.ASSOCIATION_RELEASE,\n pattern: /Association Release/i,\n processor: () => undefined,\n },\n {\n event: DcmprscpEvent.ASSOCIATION_ABORTED,\n pattern: /Association Abort/i,\n processor: () => undefined,\n },\n {\n event: DcmprscpEvent.CANNOT_START_LISTENER,\n pattern: /cannot initialise network|cannot listen/i,\n processor: (match): PrintCannotStartListenerData => ({\n message: match[0] ?? '',\n }),\n },\n {\n event: DcmprscpEvent.CONFIG_ERROR,\n pattern: /can't open configuration file|no (?:default )?print scp/i,\n processor: (match): ConfigErrorData => ({\n message: match[0] ?? '',\n }),\n },\n];\n\n/** Events that indicate fatal errors (process should be stopped). */\nconst DCMPRSCP_FATAL_EVENTS: ReadonlySet<string> = new Set([DcmprscpEvent.CANNOT_START_LISTENER, DcmprscpEvent.CONFIG_ERROR]);\n\nexport { DcmprscpEvent, DCMPRSCP_PATTERNS, DCMPRSCP_FATAL_EVENTS };\nexport type {\n DcmprscpEventValue,\n DatabaseReadyData,\n PrintAssociationReceivedData,\n PrintAssociationAcknowledgedData,\n PrintCannotStartListenerData,\n ConfigErrorData,\n};\n","/**\n * DICOM Print Management SCP server wrapping the dcmprscp binary.\n *\n * Provides a type-safe, event-driven API for the Basic Grayscale Print\n * Management SCP. Uses a static factory pattern because binary resolution\n * and validation must happen before the constructor call.\n *\n * @module servers/DcmprsCP\n */\n\nimport { z } from 'zod';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { DcmtkProcess } from '../DcmtkProcess';\nimport type { DcmtkProcessConfig } from '../DcmtkProcess';\nimport { LineParser } from '../parsers/LineParser';\nimport { resolveBinary } from '../tools/_resolveBinary';\nimport { createValidationError } from '../tools/_toolError';\nimport { isSafePath } from '../patterns';\nimport { DCMPRSCP_PATTERNS, DCMPRSCP_FATAL_EVENTS } from '../events/dcmprscp';\nimport type {\n DatabaseReadyData,\n PrintAssociationReceivedData,\n PrintAssociationAcknowledgedData,\n PrintCannotStartListenerData,\n ConfigErrorData,\n} from '../events/dcmprscp';\n\n// ---------------------------------------------------------------------------\n// Event map type\n// ---------------------------------------------------------------------------\n\n/** Typed event map for the DcmprsCP server. */\ninterface DcmprsCPEventMap {\n DATABASE_READY: [DatabaseReadyData];\n ASSOCIATION_RECEIVED: [PrintAssociationReceivedData];\n ASSOCIATION_ACKNOWLEDGED: [PrintAssociationAcknowledgedData];\n ASSOCIATION_RELEASE: [];\n ASSOCIATION_ABORTED: [];\n CANNOT_START_LISTENER: [PrintCannotStartListenerData];\n CONFIG_ERROR: [ConfigErrorData];\n}\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\n/** Options for creating a DcmprsCP server instance. */\ninterface DcmprsCPOptions {\n /** Path to the dcmpstat configuration file (required). */\n readonly configFile: string;\n /** Printer identifier from the config file (optional, defaults to first printer). */\n readonly printer?: string | undefined;\n /** Enable DIMSE message dumping. */\n readonly dump?: boolean | undefined;\n /** Log level override. */\n readonly logLevel?: 'fatal' | 'error' | 'warn' | 'info' | 'debug' | 'trace' | undefined;\n /** Path to a log configuration file. */\n readonly logConfig?: string | undefined;\n /** Timeout for start() to resolve (milliseconds). */\n readonly startTimeoutMs?: number | undefined;\n /** Timeout for graceful drain during stop() (milliseconds). */\n readonly drainTimeoutMs?: number | undefined;\n /** AbortSignal for external cancellation. */\n readonly signal?: AbortSignal | undefined;\n}\n\nconst DcmprsCPOptionsSchema = z\n .object({\n configFile: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in configFile' }),\n printer: z.string().min(1).optional(),\n dump: z.boolean().optional(),\n logLevel: z.enum(['fatal', 'error', 'warn', 'info', 'debug', 'trace']).optional(),\n logConfig: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in logConfig' }).optional(),\n startTimeoutMs: z.number().int().positive().optional(),\n drainTimeoutMs: z.number().int().positive().optional(),\n signal: z.instanceof(AbortSignal).optional(),\n })\n .strict();\n\n// ---------------------------------------------------------------------------\n// Argument builder\n// ---------------------------------------------------------------------------\n\n/** Builds the CLI arguments array from validated options. */\nfunction buildArgs(options: DcmprsCPOptions): string[] {\n const args: string[] = ['--verbose', '--config', options.configFile];\n\n if (options.printer !== undefined) {\n args.push('--printer', options.printer);\n }\n if (options.dump === true) {\n args.push('--dump');\n }\n if (options.logLevel !== undefined) {\n args.push('--log-level', options.logLevel);\n }\n if (options.logConfig !== undefined) {\n args.push('--log-config', options.logConfig);\n }\n\n return args;\n}\n\n// ---------------------------------------------------------------------------\n// DcmprsCP class\n// ---------------------------------------------------------------------------\n\n/**\n * DICOM Print Management SCP server wrapping the dcmprscp binary.\n *\n * Uses a static `create()` factory because binary resolution is fallible\n * and must complete before the constructor runs.\n *\n * Note: dcmprscp does not print a \"listening\" message. The `start()` method\n * resolves either when the DATABASE_READY event is detected or on spawn.\n *\n * @example\n * ```ts\n * const result = DcmprsCP.create({ configFile: '/etc/dcmpstat.cfg' });\n * if (result.ok) {\n * const server = result.value;\n * server.onEvent('DATABASE_READY', (data) => console.log('DB:', data.directory));\n * const startResult = await server.start();\n * }\n * ```\n */\nclass DcmprsCP extends DcmtkProcess {\n private readonly parser: LineParser;\n private abortSignal: AbortSignal | undefined;\n private abortHandler: (() => void) | undefined;\n\n private constructor(config: DcmtkProcessConfig, parser: LineParser, signal?: AbortSignal) {\n super(config);\n this.parser = parser;\n this.wireParser();\n if (signal !== undefined) {\n this.wireAbortSignal(signal);\n }\n }\n\n /**\n * Registers a typed listener for a dcmprscp-specific event.\n *\n * @param event - The event name from DcmprsCPEventMap\n * @param listener - Callback receiving typed event data\n * @returns this for chaining\n */\n /** Disposes the server and its parser, preventing listener leaks. */\n [Symbol.dispose](): void {\n if (this.abortSignal !== undefined && this.abortHandler !== undefined) {\n this.abortSignal.removeEventListener('abort', this.abortHandler);\n }\n this.parser[Symbol.dispose]();\n super[Symbol.dispose]();\n }\n\n onEvent<K extends keyof DcmprsCPEventMap>(event: K, listener: (...args: DcmprsCPEventMap[K]) => void): this {\n return this.on(event as string, listener as never);\n }\n\n /**\n * Registers a listener for when the database is ready.\n *\n * @param listener - Callback receiving database ready data\n * @returns this for chaining\n */\n onDatabaseReady(listener: (...args: DcmprsCPEventMap['DATABASE_READY']) => void): this {\n return this.onEvent('DATABASE_READY', listener);\n }\n\n /**\n * Registers a listener for incoming associations.\n *\n * @param listener - Callback receiving association data\n * @returns this for chaining\n */\n onAssociationReceived(listener: (...args: DcmprsCPEventMap['ASSOCIATION_RECEIVED']) => void): this {\n return this.onEvent('ASSOCIATION_RECEIVED', listener);\n }\n\n /**\n * Creates a new DcmprsCP server instance.\n *\n * @param options - Configuration options for the dcmprscp server\n * @returns A Result containing the server instance or a validation/resolution error\n */\n static create(options: DcmprsCPOptions): Result<DcmprsCP> {\n const validation = DcmprsCPOptionsSchema.safeParse(options);\n if (!validation.success) {\n return err(createValidationError('dcmprscp', validation.error));\n }\n\n const binaryResult = resolveBinary('dcmprscp');\n if (!binaryResult.ok) {\n return err(binaryResult.error);\n }\n\n const args = buildArgs(options);\n const parser = new LineParser();\n for (const pattern of DCMPRSCP_PATTERNS) {\n const addResult = parser.addPattern(pattern);\n if (!addResult.ok) {\n return err(addResult.error);\n }\n }\n\n const config: DcmtkProcessConfig = {\n binary: binaryResult.value,\n args,\n startTimeoutMs: options.startTimeoutMs,\n drainTimeoutMs: options.drainTimeoutMs,\n isStartedPredicate: line => /Using database in directory/i.test(line),\n };\n\n return ok(new DcmprsCP(config, parser, options.signal));\n }\n\n /** Wires the line parser to the process output. */\n private wireParser(): void {\n this.on('line', ({ text }) => {\n this.parser.feed(text);\n });\n\n this.parser.on('match', ({ event, data }) => {\n if (DCMPRSCP_FATAL_EVENTS.has(event)) {\n this.emit('error', { error: new Error(`Fatal: ${event}`), fatal: true });\n void this.stop();\n }\n this.emit(event, data);\n });\n }\n\n /** Wires an AbortSignal to stop the server. */\n private wireAbortSignal(signal: AbortSignal): void {\n if (signal.aborted) {\n void this.stop();\n return;\n }\n this.abortSignal = signal;\n this.abortHandler = (): void => {\n void this.stop();\n };\n signal.addEventListener('abort', this.abortHandler, { once: true });\n }\n}\n\nexport { DcmprsCP };\nexport type { DcmprsCPOptions, DcmprsCPEventMap };\n","/**\n * Event patterns and types for dcmpsrcv output parsing.\n *\n * Defines regex patterns that match DCMTK dcmpsrcv (viewer network receiver)\n * verbose output. Shares several patterns with dcmrecv/storescp since\n * dcmpsrcv handles incoming DICOM associations and C-STORE operations.\n *\n * @module events/dcmpsrcv\n */\n\nimport type { EventPattern } from '../parsers/EventPattern';\n\n// ---------------------------------------------------------------------------\n// Event constants (as const, not enum — Rule 3.5)\n// ---------------------------------------------------------------------------\n\n/** Events emitted by dcmpsrcv process output. */\nconst DcmpsrcvEvent = {\n LISTENING: 'LISTENING',\n DATABASE_READY: 'DATABASE_READY',\n ASSOCIATION_RECEIVED: 'ASSOCIATION_RECEIVED',\n ASSOCIATION_ACKNOWLEDGED: 'ASSOCIATION_ACKNOWLEDGED',\n ECHO_REQUEST: 'ECHO_REQUEST',\n C_STORE_REQUEST: 'C_STORE_REQUEST',\n FILE_DELETED: 'FILE_DELETED',\n ASSOCIATION_RELEASE: 'ASSOCIATION_RELEASE',\n ASSOCIATION_ABORTED: 'ASSOCIATION_ABORTED',\n CANNOT_START_LISTENER: 'CANNOT_START_LISTENER',\n CONFIG_ERROR: 'CONFIG_ERROR',\n TERMINATING: 'TERMINATING',\n} as const;\n\ntype DcmpsrcvEventValue = (typeof DcmpsrcvEvent)[keyof typeof DcmpsrcvEvent];\n\n// ---------------------------------------------------------------------------\n// Event data interfaces (all readonly)\n// ---------------------------------------------------------------------------\n\n/** Data for LISTENING event. */\ninterface ReceiverListeningData {\n readonly receiverId: string;\n readonly port: number;\n}\n\n/** Data for DATABASE_READY event. */\ninterface ReceiverDatabaseReadyData {\n readonly directory: string;\n}\n\n/** Data for ASSOCIATION_RECEIVED event. */\ninterface ReceiverAssociationReceivedData {\n readonly peerInfo: string;\n}\n\n/** Data for ASSOCIATION_ACKNOWLEDGED event. */\ninterface ReceiverAssociationAcknowledgedData {\n readonly maxSendPDV: number;\n}\n\n/** Data for ECHO_REQUEST event. */\ninterface ReceiverEchoRequestData {\n readonly messageId: number;\n}\n\n/** Data for C_STORE_REQUEST event. */\ninterface ReceiverCStoreRequestData {\n readonly raw: string;\n}\n\n/** Data for FILE_DELETED event. */\ninterface FileDeletedData {\n readonly filePath: string;\n}\n\n/** Data for CANNOT_START_LISTENER event. */\ninterface ReceiverCannotStartListenerData {\n readonly message: string;\n}\n\n/** Data for CONFIG_ERROR event. */\ninterface ReceiverConfigErrorData {\n readonly message: string;\n}\n\n// ---------------------------------------------------------------------------\n// Regex patterns for dcmpsrcv verbose output\n// ---------------------------------------------------------------------------\n\n/** Event patterns for parsing dcmpsrcv verbose output. */\nconst DCMPSRCV_PATTERNS: readonly EventPattern[] = [\n {\n event: DcmpsrcvEvent.LISTENING,\n pattern: /Receiver\\s{1,20}(\\S+)\\s{1,20}on port\\s{1,20}(\\d+)/,\n processor: (match): ReceiverListeningData => ({\n receiverId: match[1] ?? '',\n port: Number(match[2]),\n }),\n },\n {\n event: DcmpsrcvEvent.DATABASE_READY,\n pattern: /Using database in directory\\s+'([^']+)'/,\n processor: (match): ReceiverDatabaseReadyData => ({\n directory: match[1] ?? '',\n }),\n },\n {\n event: DcmpsrcvEvent.ASSOCIATION_RECEIVED,\n pattern: /Association Received\\s*\\(([^)]+)\\)/,\n processor: (match): ReceiverAssociationReceivedData => ({\n peerInfo: (match[1] ?? '').trim(),\n }),\n },\n {\n event: DcmpsrcvEvent.ASSOCIATION_ACKNOWLEDGED,\n pattern: /Association Acknowledged \\(Max Send PDV:\\s*(\\d+)\\)/,\n processor: (match): ReceiverAssociationAcknowledgedData => ({\n maxSendPDV: Number(match[1]),\n }),\n },\n {\n event: DcmpsrcvEvent.ECHO_REQUEST,\n pattern: /Received Echo SCP RQ:\\s*MsgID\\s+(\\d+)/,\n processor: (match): ReceiverEchoRequestData => ({\n messageId: Number(match[1]),\n }),\n },\n {\n event: DcmpsrcvEvent.C_STORE_REQUEST,\n pattern: /Received Store SCP/i,\n processor: (match): ReceiverCStoreRequestData => ({\n raw: match[0] ?? '',\n }),\n },\n {\n event: DcmpsrcvEvent.FILE_DELETED,\n pattern: /Deleting Image File:\\s{0,20}(.{1,1024})/,\n processor: (match): FileDeletedData => ({\n filePath: (match[1] ?? '').trim(),\n }),\n },\n {\n event: DcmpsrcvEvent.ASSOCIATION_RELEASE,\n pattern: /Association Release/i,\n processor: () => undefined,\n },\n {\n event: DcmpsrcvEvent.ASSOCIATION_ABORTED,\n pattern: /Association Abort/i,\n processor: () => undefined,\n },\n {\n event: DcmpsrcvEvent.CANNOT_START_LISTENER,\n pattern: /cannot listen on port/i,\n processor: (match): ReceiverCannotStartListenerData => ({\n message: match[0] ?? '',\n }),\n },\n {\n event: DcmpsrcvEvent.CONFIG_ERROR,\n pattern: /can't open configuration file|missing configuration file|no application entity title|no or invalid port number/i,\n processor: (match): ReceiverConfigErrorData => ({\n message: match[0] ?? '',\n }),\n },\n {\n event: DcmpsrcvEvent.TERMINATING,\n pattern: /Terminating all receivers/i,\n processor: () => undefined,\n },\n];\n\n/** Events that indicate fatal errors (process should be stopped). */\nconst DCMPSRCV_FATAL_EVENTS: ReadonlySet<string> = new Set([DcmpsrcvEvent.CANNOT_START_LISTENER, DcmpsrcvEvent.CONFIG_ERROR]);\n\nexport { DcmpsrcvEvent, DCMPSRCV_PATTERNS, DCMPSRCV_FATAL_EVENTS };\nexport type {\n DcmpsrcvEventValue,\n ReceiverListeningData,\n ReceiverDatabaseReadyData,\n ReceiverAssociationReceivedData,\n ReceiverAssociationAcknowledgedData,\n ReceiverEchoRequestData,\n ReceiverCStoreRequestData,\n FileDeletedData,\n ReceiverCannotStartListenerData,\n ReceiverConfigErrorData,\n};\n","/**\n * DICOM Viewer Network Receiver wrapping the dcmpsrcv binary.\n *\n * Provides a type-safe, event-driven API for the DICOMscope network\n * receiver component. Accepts incoming DICOM associations for storage\n * and C-ECHO verification.\n *\n * @module servers/Dcmpsrcv\n */\n\nimport { z } from 'zod';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { DcmtkProcess } from '../DcmtkProcess';\nimport type { DcmtkProcessConfig } from '../DcmtkProcess';\nimport { LineParser } from '../parsers/LineParser';\nimport { resolveBinary } from '../tools/_resolveBinary';\nimport { createValidationError } from '../tools/_toolError';\nimport { isSafePath } from '../patterns';\nimport { DCMPSRCV_PATTERNS, DCMPSRCV_FATAL_EVENTS } from '../events/dcmpsrcv';\nimport type {\n ReceiverListeningData,\n ReceiverDatabaseReadyData,\n ReceiverAssociationReceivedData,\n ReceiverAssociationAcknowledgedData,\n ReceiverEchoRequestData,\n ReceiverCStoreRequestData,\n FileDeletedData,\n ReceiverCannotStartListenerData,\n ReceiverConfigErrorData,\n} from '../events/dcmpsrcv';\n\n// ---------------------------------------------------------------------------\n// Event map type\n// ---------------------------------------------------------------------------\n\n/** Typed event map for the Dcmpsrcv server. */\ninterface DcmpsrcvEventMap {\n LISTENING: [ReceiverListeningData];\n DATABASE_READY: [ReceiverDatabaseReadyData];\n ASSOCIATION_RECEIVED: [ReceiverAssociationReceivedData];\n ASSOCIATION_ACKNOWLEDGED: [ReceiverAssociationAcknowledgedData];\n ECHO_REQUEST: [ReceiverEchoRequestData];\n C_STORE_REQUEST: [ReceiverCStoreRequestData];\n FILE_DELETED: [FileDeletedData];\n ASSOCIATION_RELEASE: [];\n ASSOCIATION_ABORTED: [];\n CANNOT_START_LISTENER: [ReceiverCannotStartListenerData];\n CONFIG_ERROR: [ReceiverConfigErrorData];\n TERMINATING: [];\n}\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\n/** Options for creating a Dcmpsrcv server instance. */\ninterface DcmpsrcvOptions {\n /** Path to the dcmpstat configuration file (required). */\n readonly configFile: string;\n /** Receiver identifier from the config file (optional, defaults to first receiver). */\n readonly receiverId?: string | undefined;\n /** Log level override. */\n readonly logLevel?: 'fatal' | 'error' | 'warn' | 'info' | 'debug' | 'trace' | undefined;\n /** Path to a log configuration file. */\n readonly logConfig?: string | undefined;\n /** Timeout for start() to resolve (milliseconds). */\n readonly startTimeoutMs?: number | undefined;\n /** Timeout for graceful drain during stop() (milliseconds). */\n readonly drainTimeoutMs?: number | undefined;\n /** AbortSignal for external cancellation. */\n readonly signal?: AbortSignal | undefined;\n}\n\nconst DcmpsrcvOptionsSchema = z\n .object({\n configFile: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in configFile' }),\n receiverId: z.string().min(1).optional(),\n logLevel: z.enum(['fatal', 'error', 'warn', 'info', 'debug', 'trace']).optional(),\n logConfig: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in logConfig' }).optional(),\n startTimeoutMs: z.number().int().positive().optional(),\n drainTimeoutMs: z.number().int().positive().optional(),\n signal: z.instanceof(AbortSignal).optional(),\n })\n .strict();\n\n// ---------------------------------------------------------------------------\n// Argument builder\n// ---------------------------------------------------------------------------\n\n/** Builds the CLI arguments array from validated options. */\nfunction buildArgs(options: DcmpsrcvOptions): string[] {\n const args: string[] = ['--verbose'];\n\n if (options.logLevel !== undefined) {\n args.push('--log-level', options.logLevel);\n }\n if (options.logConfig !== undefined) {\n args.push('--log-config', options.logConfig);\n }\n\n args.push(options.configFile);\n\n if (options.receiverId !== undefined) {\n args.push(options.receiverId);\n }\n\n return args;\n}\n\n// ---------------------------------------------------------------------------\n// Dcmpsrcv class\n// ---------------------------------------------------------------------------\n\n/**\n * DICOM Viewer Network Receiver wrapping the dcmpsrcv binary.\n *\n * Uses a static `create()` factory because binary resolution is fallible\n * and must complete before the constructor runs.\n *\n * The `start()` method resolves when the LISTENING event is detected\n * (i.e., \"Receiver <id> on port <port>\").\n *\n * @example\n * ```ts\n * const result = Dcmpsrcv.create({ configFile: '/etc/dcmpstat.cfg', receiverId: 'RECEIVE_1' });\n * if (result.ok) {\n * const server = result.value;\n * server.onEvent('LISTENING', (data) => console.log(`Listening on port ${data.port}`));\n * const startResult = await server.start();\n * }\n * ```\n */\nclass Dcmpsrcv extends DcmtkProcess {\n private readonly parser: LineParser;\n private abortSignal: AbortSignal | undefined;\n private abortHandler: (() => void) | undefined;\n\n private constructor(config: DcmtkProcessConfig, parser: LineParser, signal?: AbortSignal) {\n super(config);\n this.parser = parser;\n this.wireParser();\n if (signal !== undefined) {\n this.wireAbortSignal(signal);\n }\n }\n\n /**\n * Registers a typed listener for a dcmpsrcv-specific event.\n *\n * @param event - The event name from DcmpsrcvEventMap\n * @param listener - Callback receiving typed event data\n * @returns this for chaining\n */\n /** Disposes the server and its parser, preventing listener leaks. */\n [Symbol.dispose](): void {\n if (this.abortSignal !== undefined && this.abortHandler !== undefined) {\n this.abortSignal.removeEventListener('abort', this.abortHandler);\n }\n this.parser[Symbol.dispose]();\n super[Symbol.dispose]();\n }\n\n onEvent<K extends keyof DcmpsrcvEventMap>(event: K, listener: (...args: DcmpsrcvEventMap[K]) => void): this {\n return this.on(event as string, listener as never);\n }\n\n /**\n * Registers a listener for when the receiver starts listening.\n *\n * @param listener - Callback receiving listening data (receiver ID and port)\n * @returns this for chaining\n */\n onListening(listener: (...args: DcmpsrcvEventMap['LISTENING']) => void): this {\n return this.onEvent('LISTENING', listener);\n }\n\n /**\n * Registers a listener for incoming C-STORE requests.\n *\n * @param listener - Callback receiving C-STORE request data\n * @returns this for chaining\n */\n onCStoreRequest(listener: (...args: DcmpsrcvEventMap['C_STORE_REQUEST']) => void): this {\n return this.onEvent('C_STORE_REQUEST', listener);\n }\n\n /**\n * Creates a new Dcmpsrcv server instance.\n *\n * @param options - Configuration options for the dcmpsrcv server\n * @returns A Result containing the server instance or a validation/resolution error\n */\n static create(options: DcmpsrcvOptions): Result<Dcmpsrcv> {\n const validation = DcmpsrcvOptionsSchema.safeParse(options);\n if (!validation.success) {\n return err(createValidationError('dcmpsrcv', validation.error));\n }\n\n const binaryResult = resolveBinary('dcmpsrcv');\n if (!binaryResult.ok) {\n return err(binaryResult.error);\n }\n\n const args = buildArgs(options);\n const parser = new LineParser();\n for (const pattern of DCMPSRCV_PATTERNS) {\n const addResult = parser.addPattern(pattern);\n if (!addResult.ok) {\n return err(addResult.error);\n }\n }\n\n const config: DcmtkProcessConfig = {\n binary: binaryResult.value,\n args,\n startTimeoutMs: options.startTimeoutMs,\n drainTimeoutMs: options.drainTimeoutMs,\n isStartedPredicate: line => /Receiver\\s+\\S+\\s+on port/i.test(line),\n };\n\n return ok(new Dcmpsrcv(config, parser, options.signal));\n }\n\n /** Wires the line parser to the process output. */\n private wireParser(): void {\n this.on('line', ({ text }) => {\n this.parser.feed(text);\n });\n\n this.parser.on('match', ({ event, data }) => {\n if (DCMPSRCV_FATAL_EVENTS.has(event)) {\n this.emit('error', { error: new Error(`Fatal: ${event}`), fatal: true });\n void this.stop();\n }\n this.emit(event, data);\n });\n }\n\n /** Wires an AbortSignal to stop the server. */\n private wireAbortSignal(signal: AbortSignal): void {\n if (signal.aborted) {\n void this.stop();\n return;\n }\n this.abortSignal = signal;\n this.abortHandler = (): void => {\n void this.stop();\n };\n signal.addEventListener('abort', this.abortHandler, { once: true });\n }\n}\n\nexport { Dcmpsrcv };\nexport type { DcmpsrcvOptions, DcmpsrcvEventMap };\n","/**\n * Event patterns and types for dcmqrscp output parsing.\n *\n * Defines regex patterns that match DCMTK dcmqrscp (Query/Retrieve SCP)\n * verbose output, along with typed event data interfaces for each event.\n *\n * @module events/dcmqrscp\n */\n\nimport type { EventPattern } from '../parsers/EventPattern';\n\n// ---------------------------------------------------------------------------\n// Event constants (as const, not enum — Rule 3.5)\n// ---------------------------------------------------------------------------\n\n/** Events emitted by dcmqrscp process output. */\nconst DcmqrscpEvent = {\n LISTENING: 'LISTENING',\n ASSOCIATION_RECEIVED: 'ASSOCIATION_RECEIVED',\n ASSOCIATION_ACKNOWLEDGED: 'ASSOCIATION_ACKNOWLEDGED',\n C_FIND_REQUEST: 'C_FIND_REQUEST',\n C_MOVE_REQUEST: 'C_MOVE_REQUEST',\n C_GET_REQUEST: 'C_GET_REQUEST',\n C_STORE_REQUEST: 'C_STORE_REQUEST',\n ASSOCIATION_RELEASE: 'ASSOCIATION_RELEASE',\n ASSOCIATION_ABORTED: 'ASSOCIATION_ABORTED',\n CANNOT_START_LISTENER: 'CANNOT_START_LISTENER',\n} as const;\n\ntype DcmqrscpEventValue = (typeof DcmqrscpEvent)[keyof typeof DcmqrscpEvent];\n\n// ---------------------------------------------------------------------------\n// Event data interfaces (all readonly)\n// ---------------------------------------------------------------------------\n\n/** Data for LISTENING event. */\ninterface QRListeningData {\n readonly port: number;\n}\n\n/** Data for ASSOCIATION_RECEIVED event. */\ninterface QRAssociationReceivedData {\n readonly peerInfo: string;\n}\n\n/** Data for ASSOCIATION_ACKNOWLEDGED event. */\ninterface QRAssociationAcknowledgedData {\n readonly maxSendPDV: number;\n}\n\n/** Data for C_FIND_REQUEST event. */\ninterface QRCFindRequestData {\n readonly raw: string;\n}\n\n/** Data for C_MOVE_REQUEST event. */\ninterface QRCMoveRequestData {\n readonly raw: string;\n}\n\n/** Data for C_GET_REQUEST event. */\ninterface QRCGetRequestData {\n readonly raw: string;\n}\n\n/** Data for C_STORE_REQUEST event. */\ninterface QRCStoreRequestData {\n readonly raw: string;\n}\n\n/** Data for CANNOT_START_LISTENER event. */\ninterface QRCannotStartListenerData {\n readonly message: string;\n}\n\n// ---------------------------------------------------------------------------\n// Regex patterns for dcmqrscp verbose output\n// ---------------------------------------------------------------------------\n\n/** Event patterns for parsing dcmqrscp verbose output. */\nconst DCMQRSCP_PATTERNS: readonly EventPattern[] = [\n {\n event: DcmqrscpEvent.LISTENING,\n pattern: /listening on port\\s{1,20}(\\d+)/i,\n processor: (match): QRListeningData => ({\n port: Number(match[1]),\n }),\n },\n {\n event: DcmqrscpEvent.ASSOCIATION_RECEIVED,\n pattern: /Association Received\\s{0,20}([^\\r\\n]+)/,\n processor: (match): QRAssociationReceivedData => ({\n peerInfo: (match[1] ?? '').trim(),\n }),\n },\n {\n event: DcmqrscpEvent.ASSOCIATION_ACKNOWLEDGED,\n pattern: /Association Acknowledged \\(Max Send PDV:\\s*(\\d+)\\)/,\n processor: (match): QRAssociationAcknowledgedData => ({\n maxSendPDV: Number(match[1]),\n }),\n },\n {\n event: DcmqrscpEvent.C_FIND_REQUEST,\n pattern: /Received Find (?:SCP )?Request/i,\n processor: (match): QRCFindRequestData => ({\n raw: match[0] ?? '',\n }),\n },\n {\n event: DcmqrscpEvent.C_MOVE_REQUEST,\n pattern: /Received Move (?:SCP )?Request/i,\n processor: (match): QRCMoveRequestData => ({\n raw: match[0] ?? '',\n }),\n },\n {\n event: DcmqrscpEvent.C_GET_REQUEST,\n pattern: /Received Get (?:SCP )?Request/i,\n processor: (match): QRCGetRequestData => ({\n raw: match[0] ?? '',\n }),\n },\n {\n event: DcmqrscpEvent.C_STORE_REQUEST,\n pattern: /Received Store (?:SCP )?Request/i,\n processor: (match): QRCStoreRequestData => ({\n raw: match[0] ?? '',\n }),\n },\n {\n event: DcmqrscpEvent.ASSOCIATION_RELEASE,\n pattern: /Association Release/i,\n processor: () => undefined,\n },\n {\n event: DcmqrscpEvent.ASSOCIATION_ABORTED,\n pattern: /Association Abort/i,\n processor: () => undefined,\n },\n {\n event: DcmqrscpEvent.CANNOT_START_LISTENER,\n pattern: /cannot listen|cannot initialise network/i,\n processor: (match): QRCannotStartListenerData => ({\n message: match[0] ?? '',\n }),\n },\n];\n\n/** Events that indicate fatal errors (process should be stopped). */\nconst DCMQRSCP_FATAL_EVENTS: ReadonlySet<string> = new Set([DcmqrscpEvent.CANNOT_START_LISTENER]);\n\nexport { DcmqrscpEvent, DCMQRSCP_PATTERNS, DCMQRSCP_FATAL_EVENTS };\nexport type {\n DcmqrscpEventValue,\n QRListeningData,\n QRAssociationReceivedData,\n QRAssociationAcknowledgedData,\n QRCFindRequestData,\n QRCMoveRequestData,\n QRCGetRequestData,\n QRCStoreRequestData,\n QRCannotStartListenerData,\n};\n","/**\n * DICOM Query/Retrieve SCP server wrapping the dcmqrscp binary.\n *\n * Provides a type-safe, event-driven API for the Q/R SCP that supports\n * C-FIND, C-MOVE, C-GET, and C-STORE operations. Uses a static factory\n * pattern because binary resolution and validation must happen before\n * the constructor call.\n *\n * @module servers/DcmQRSCP\n */\n\nimport { z } from 'zod';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { DcmtkProcess } from '../DcmtkProcess';\nimport type { DcmtkProcessConfig } from '../DcmtkProcess';\nimport { LineParser } from '../parsers/LineParser';\nimport { resolveBinary } from '../tools/_resolveBinary';\nimport { createValidationError } from '../tools/_toolError';\nimport { isSafePath } from '../patterns';\nimport { DCMQRSCP_PATTERNS, DCMQRSCP_FATAL_EVENTS } from '../events/dcmqrscp';\nimport type {\n QRListeningData,\n QRAssociationReceivedData,\n QRAssociationAcknowledgedData,\n QRCFindRequestData,\n QRCMoveRequestData,\n QRCGetRequestData,\n QRCStoreRequestData,\n QRCannotStartListenerData,\n} from '../events/dcmqrscp';\n\n// ---------------------------------------------------------------------------\n// Event map type\n// ---------------------------------------------------------------------------\n\n/** Typed event map for the DcmQRSCP server. */\ninterface DcmQRSCPEventMap {\n LISTENING: [QRListeningData];\n ASSOCIATION_RECEIVED: [QRAssociationReceivedData];\n ASSOCIATION_ACKNOWLEDGED: [QRAssociationAcknowledgedData];\n C_FIND_REQUEST: [QRCFindRequestData];\n C_MOVE_REQUEST: [QRCMoveRequestData];\n C_GET_REQUEST: [QRCGetRequestData];\n C_STORE_REQUEST: [QRCStoreRequestData];\n ASSOCIATION_RELEASE: [];\n ASSOCIATION_ABORTED: [];\n CANNOT_START_LISTENER: [QRCannotStartListenerData];\n}\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\n/** Options for creating a DcmQRSCP server instance. */\ninterface DcmQRSCPOptions {\n /** Path to the dcmqrscp configuration file (required). */\n readonly configFile: string;\n /** Override port from config (positional arg). */\n readonly port?: number | undefined;\n /** Single-process mode (-s flag, recommended on Windows). */\n readonly singleProcess?: boolean | undefined;\n /** Check Find responses (-XF). */\n readonly checkFind?: boolean | undefined;\n /** Check Move responses (-XM). */\n readonly checkMove?: boolean | undefined;\n /** Disable C-GET support (--disable-get). */\n readonly disableGet?: boolean | undefined;\n /** Maximum PDU receive size. */\n readonly maxPdu?: number | undefined;\n /** ACSE timeout in seconds (passed to DCMTK as-is). */\n readonly acseTimeout?: number | undefined;\n /** DIMSE timeout in seconds (passed to DCMTK as-is). */\n readonly dimseTimeout?: number | undefined;\n /** Enable verbose mode (default true for event detection). */\n readonly verbose?: boolean | undefined;\n /** Timeout for start() to resolve (milliseconds). */\n readonly startTimeoutMs?: number | undefined;\n /** Timeout for graceful drain during stop() (milliseconds). */\n readonly drainTimeoutMs?: number | undefined;\n /** AbortSignal for external cancellation. */\n readonly signal?: AbortSignal | undefined;\n}\n\nconst DcmQRSCPOptionsSchema = z\n .object({\n configFile: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in configFile' }),\n port: z.number().int().min(1).max(65535).optional(),\n singleProcess: z.boolean().optional(),\n checkFind: z.boolean().optional(),\n checkMove: z.boolean().optional(),\n disableGet: z.boolean().optional(),\n maxPdu: z.number().int().min(4096).max(131072).optional(),\n acseTimeout: z.number().int().positive().optional(),\n dimseTimeout: z.number().int().positive().optional(),\n verbose: z.boolean().optional(),\n startTimeoutMs: z.number().int().positive().optional(),\n drainTimeoutMs: z.number().int().positive().optional(),\n signal: z.instanceof(AbortSignal).optional(),\n })\n .strict();\n\n// ---------------------------------------------------------------------------\n// Argument builder\n// ---------------------------------------------------------------------------\n\n/** Builds the CLI arguments array from validated options. */\nfunction buildArgs(options: DcmQRSCPOptions): string[] {\n const args: string[] = [];\n\n if (options.verbose !== false) {\n args.push('--verbose');\n }\n\n args.push('--config', options.configFile);\n\n if (options.singleProcess === true) {\n args.push('-s');\n }\n if (options.checkFind === true) {\n args.push('-XF');\n }\n if (options.checkMove === true) {\n args.push('-XM');\n }\n if (options.disableGet === true) {\n args.push('--disable-get');\n }\n\n buildNetworkArgs(args, options);\n\n if (options.port !== undefined) {\n args.push(String(options.port));\n }\n\n return args;\n}\n\n/** Appends network-related CLI flags. */\nfunction buildNetworkArgs(args: string[], options: DcmQRSCPOptions): void {\n if (options.maxPdu !== undefined) {\n args.push('--max-pdu', String(options.maxPdu));\n }\n if (options.acseTimeout !== undefined) {\n args.push('--acse-timeout', String(options.acseTimeout));\n }\n if (options.dimseTimeout !== undefined) {\n args.push('--dimse-timeout', String(options.dimseTimeout));\n }\n}\n\n// ---------------------------------------------------------------------------\n// DcmQRSCP class\n// ---------------------------------------------------------------------------\n\n/**\n * DICOM Query/Retrieve SCP server wrapping the dcmqrscp binary.\n *\n * Uses a static `create()` factory because binary resolution is fallible\n * and must complete before the constructor runs.\n *\n * @example\n * ```ts\n * const result = DcmQRSCP.create({ configFile: '/etc/dcmqrscp.cfg', port: 11112 });\n * if (result.ok) {\n * const server = result.value;\n * server.onEvent('C_FIND_REQUEST', (data) => console.log('Find:', data.raw));\n * const startResult = await server.start();\n * }\n * ```\n */\nclass DcmQRSCP extends DcmtkProcess {\n private readonly parser: LineParser;\n private abortSignal: AbortSignal | undefined;\n private abortHandler: (() => void) | undefined;\n\n private constructor(config: DcmtkProcessConfig, parser: LineParser, signal?: AbortSignal) {\n super(config);\n this.parser = parser;\n this.wireParser();\n if (signal !== undefined) {\n this.wireAbortSignal(signal);\n }\n }\n\n /** Disposes the server and its parser, preventing listener leaks. */\n [Symbol.dispose](): void {\n if (this.abortSignal !== undefined && this.abortHandler !== undefined) {\n this.abortSignal.removeEventListener('abort', this.abortHandler);\n }\n this.parser[Symbol.dispose]();\n super[Symbol.dispose]();\n }\n\n /**\n * Registers a typed listener for a dcmqrscp-specific event.\n *\n * @param event - The event name from DcmQRSCPEventMap\n * @param listener - Callback receiving typed event data\n * @returns this for chaining\n */\n onEvent<K extends keyof DcmQRSCPEventMap>(event: K, listener: (...args: DcmQRSCPEventMap[K]) => void): this {\n return this.on(event as string, listener as never);\n }\n\n /**\n * Registers a listener for incoming C-FIND requests.\n *\n * @param listener - Callback receiving C-FIND request data\n * @returns this for chaining\n */\n onCFindRequest(listener: (...args: DcmQRSCPEventMap['C_FIND_REQUEST']) => void): this {\n return this.onEvent('C_FIND_REQUEST', listener);\n }\n\n /**\n * Registers a listener for incoming C-MOVE requests.\n *\n * @param listener - Callback receiving C-MOVE request data\n * @returns this for chaining\n */\n onCMoveRequest(listener: (...args: DcmQRSCPEventMap['C_MOVE_REQUEST']) => void): this {\n return this.onEvent('C_MOVE_REQUEST', listener);\n }\n\n /**\n * Creates a new DcmQRSCP server instance.\n *\n * @param options - Configuration options for the dcmqrscp server\n * @returns A Result containing the server instance or a validation/resolution error\n */\n static create(options: DcmQRSCPOptions): Result<DcmQRSCP> {\n const validation = DcmQRSCPOptionsSchema.safeParse(options);\n if (!validation.success) {\n return err(createValidationError('dcmqrscp', validation.error));\n }\n\n const binaryResult = resolveBinary('dcmqrscp');\n if (!binaryResult.ok) {\n return err(binaryResult.error);\n }\n\n const args = buildArgs(options);\n const parser = new LineParser();\n for (const pattern of DCMQRSCP_PATTERNS) {\n const addResult = parser.addPattern(pattern);\n if (!addResult.ok) {\n return err(addResult.error);\n }\n }\n\n // dcmqrscp v3.7.0+ does not print a \"listening on port\" message even\n // in verbose/debug mode, so we resolve on spawn (like StoreSCP) and\n // rely on a short warmup delay in callers that need the socket ready.\n const config: DcmtkProcessConfig = {\n binary: binaryResult.value,\n args,\n startTimeoutMs: options.startTimeoutMs,\n drainTimeoutMs: options.drainTimeoutMs,\n };\n\n return ok(new DcmQRSCP(config, parser, options.signal));\n }\n\n /** Wires the line parser to the process output. */\n private wireParser(): void {\n this.on('line', ({ text }) => {\n this.parser.feed(text);\n });\n\n this.parser.on('match', ({ event, data }) => {\n if (DCMQRSCP_FATAL_EVENTS.has(event)) {\n this.emit('error', { error: new Error(`Fatal: ${event}`), fatal: true });\n void this.stop();\n }\n this.emit(event, data);\n });\n }\n\n /** Wires an AbortSignal to stop the server. */\n private wireAbortSignal(signal: AbortSignal): void {\n if (signal.aborted) {\n void this.stop();\n return;\n }\n this.abortSignal = signal;\n this.abortHandler = (): void => {\n void this.stop();\n };\n signal.addEventListener('abort', this.abortHandler, { once: true });\n }\n}\n\nexport { DcmQRSCP };\nexport type { DcmQRSCPOptions, DcmQRSCPEventMap };\n","/**\n * Event patterns and types for wlmscpfs output parsing.\n *\n * Defines regex patterns that match DCMTK wlmscpfs (Worklist Management SCP)\n * verbose output, along with typed event data interfaces for each event.\n *\n * @module events/wlmscpfs\n */\n\nimport type { EventPattern } from '../parsers/EventPattern';\n\n// ---------------------------------------------------------------------------\n// Event constants (as const, not enum — Rule 3.5)\n// ---------------------------------------------------------------------------\n\n/** Events emitted by wlmscpfs process output. */\nconst WlmscpfsEvent = {\n LISTENING: 'LISTENING',\n ASSOCIATION_RECEIVED: 'ASSOCIATION_RECEIVED',\n ASSOCIATION_ACKNOWLEDGED: 'ASSOCIATION_ACKNOWLEDGED',\n C_FIND_REQUEST: 'C_FIND_REQUEST',\n ASSOCIATION_RELEASE: 'ASSOCIATION_RELEASE',\n ASSOCIATION_ABORTED: 'ASSOCIATION_ABORTED',\n ECHO_REQUEST: 'ECHO_REQUEST',\n CANNOT_START_LISTENER: 'CANNOT_START_LISTENER',\n} as const;\n\ntype WlmscpfsEventValue = (typeof WlmscpfsEvent)[keyof typeof WlmscpfsEvent];\n\n// ---------------------------------------------------------------------------\n// Event data interfaces (all readonly)\n// ---------------------------------------------------------------------------\n\n/** Data for LISTENING event. */\ninterface WlmListeningData {\n readonly port: number;\n}\n\n/** Data for ASSOCIATION_RECEIVED event. */\ninterface WlmAssociationReceivedData {\n readonly peerInfo: string;\n}\n\n/** Data for ASSOCIATION_ACKNOWLEDGED event. */\ninterface WlmAssociationAcknowledgedData {\n readonly maxSendPDV: number;\n}\n\n/** Data for C_FIND_REQUEST event. */\ninterface WlmCFindRequestData {\n readonly raw: string;\n}\n\n/** Data for CANNOT_START_LISTENER event. */\ninterface WlmCannotStartListenerData {\n readonly message: string;\n}\n\n// ---------------------------------------------------------------------------\n// Regex patterns for wlmscpfs verbose output\n// ---------------------------------------------------------------------------\n\n/** Event patterns for parsing wlmscpfs verbose output. */\nconst WLMSCPFS_PATTERNS: readonly EventPattern[] = [\n {\n event: WlmscpfsEvent.LISTENING,\n pattern: /listening on port\\s{1,20}(\\d+)/i,\n processor: (match): WlmListeningData => ({\n port: Number(match[1]),\n }),\n },\n {\n event: WlmscpfsEvent.ASSOCIATION_RECEIVED,\n pattern: /Association Received\\s{0,20}([^\\r\\n]+)/,\n processor: (match): WlmAssociationReceivedData => ({\n peerInfo: (match[1] ?? '').trim(),\n }),\n },\n {\n event: WlmscpfsEvent.ASSOCIATION_ACKNOWLEDGED,\n pattern: /Association Acknowledged \\(Max Send PDV:\\s*(\\d+)\\)/,\n processor: (match): WlmAssociationAcknowledgedData => ({\n maxSendPDV: Number(match[1]),\n }),\n },\n {\n event: WlmscpfsEvent.C_FIND_REQUEST,\n pattern: /Received (?:C-FIND|Find) Request/i,\n processor: (match): WlmCFindRequestData => ({\n raw: match[0] ?? '',\n }),\n },\n {\n event: WlmscpfsEvent.ASSOCIATION_RELEASE,\n pattern: /Association Release/i,\n processor: () => undefined,\n },\n {\n event: WlmscpfsEvent.ASSOCIATION_ABORTED,\n pattern: /Association Abort/i,\n processor: () => undefined,\n },\n {\n event: WlmscpfsEvent.ECHO_REQUEST,\n pattern: /Received (?:C-ECHO|Echo) Request/i,\n processor: () => undefined,\n },\n {\n event: WlmscpfsEvent.CANNOT_START_LISTENER,\n pattern: /cannot listen|cannot initialise network/i,\n processor: (match): WlmCannotStartListenerData => ({\n message: match[0] ?? '',\n }),\n },\n];\n\n/** Events that indicate fatal errors (process should be stopped). */\nconst WLMSCPFS_FATAL_EVENTS: ReadonlySet<string> = new Set([WlmscpfsEvent.CANNOT_START_LISTENER]);\n\nexport { WlmscpfsEvent, WLMSCPFS_PATTERNS, WLMSCPFS_FATAL_EVENTS };\nexport type {\n WlmscpfsEventValue,\n WlmListeningData,\n WlmAssociationReceivedData,\n WlmAssociationAcknowledgedData,\n WlmCFindRequestData,\n WlmCannotStartListenerData,\n};\n","/**\n * DICOM Worklist Management SCP server wrapping the wlmscpfs binary.\n *\n * Provides a type-safe, event-driven API for serving worklist data\n * from a file-system based database. Uses a static factory pattern\n * because binary resolution and validation must happen before the\n * constructor call.\n *\n * @module servers/Wlmscpfs\n */\n\nimport { z } from 'zod';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { DcmtkProcess } from '../DcmtkProcess';\nimport type { DcmtkProcessConfig } from '../DcmtkProcess';\nimport { LineParser } from '../parsers/LineParser';\nimport { resolveBinary } from '../tools/_resolveBinary';\nimport { createValidationError } from '../tools/_toolError';\nimport { isSafePath } from '../patterns';\nimport { WLMSCPFS_PATTERNS, WLMSCPFS_FATAL_EVENTS } from '../events/wlmscpfs';\nimport type {\n WlmListeningData,\n WlmAssociationReceivedData,\n WlmAssociationAcknowledgedData,\n WlmCFindRequestData,\n WlmCannotStartListenerData,\n} from '../events/wlmscpfs';\n\n// ---------------------------------------------------------------------------\n// Event map type\n// ---------------------------------------------------------------------------\n\n/** Typed event map for the Wlmscpfs server. */\ninterface WlmscpfsEventMap {\n LISTENING: [WlmListeningData];\n ASSOCIATION_RECEIVED: [WlmAssociationReceivedData];\n ASSOCIATION_ACKNOWLEDGED: [WlmAssociationAcknowledgedData];\n C_FIND_REQUEST: [WlmCFindRequestData];\n ASSOCIATION_RELEASE: [];\n ASSOCIATION_ABORTED: [];\n ECHO_REQUEST: [];\n CANNOT_START_LISTENER: [WlmCannotStartListenerData];\n}\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\n/** Options for creating a Wlmscpfs server instance. */\ninterface WlmscpfsOptions {\n /** Port to listen on (required, positional arg). */\n readonly port: number;\n /** Worklist data directory (required, -dfp flag). */\n readonly worklistDirectory: string;\n /** Enable file rejection (default true). Maps to -efr / -dfr. */\n readonly enableFileRejection?: boolean | undefined;\n /** Maximum PDU receive size. */\n readonly maxPdu?: number | undefined;\n /** ACSE timeout in seconds (passed to DCMTK as-is). */\n readonly acseTimeout?: number | undefined;\n /** DIMSE timeout in seconds (passed to DCMTK as-is). */\n readonly dimseTimeout?: number | undefined;\n /** Maximum simultaneous associations. */\n readonly maxAssociations?: number | undefined;\n /** Enable verbose mode (default true for event detection). */\n readonly verbose?: boolean | undefined;\n /** Timeout for start() to resolve (milliseconds). */\n readonly startTimeoutMs?: number | undefined;\n /** Timeout for graceful drain during stop() (milliseconds). */\n readonly drainTimeoutMs?: number | undefined;\n /** AbortSignal for external cancellation. */\n readonly signal?: AbortSignal | undefined;\n}\n\nconst WlmscpfsOptionsSchema = z\n .object({\n port: z.number().int().min(1).max(65535),\n worklistDirectory: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in worklistDirectory' }),\n enableFileRejection: z.boolean().optional(),\n maxPdu: z.number().int().min(4096).max(131072).optional(),\n acseTimeout: z.number().int().positive().optional(),\n dimseTimeout: z.number().int().positive().optional(),\n maxAssociations: z.number().int().positive().optional(),\n verbose: z.boolean().optional(),\n startTimeoutMs: z.number().int().positive().optional(),\n drainTimeoutMs: z.number().int().positive().optional(),\n signal: z.instanceof(AbortSignal).optional(),\n })\n .strict();\n\n// ---------------------------------------------------------------------------\n// Argument builder\n// ---------------------------------------------------------------------------\n\n/** Builds the CLI arguments array from validated options. */\nfunction buildArgs(options: WlmscpfsOptions): string[] {\n const args: string[] = [];\n\n if (options.verbose !== false) {\n args.push('--verbose');\n }\n\n args.push('-dfp', options.worklistDirectory);\n\n if (options.enableFileRejection === false) {\n args.push('-dfr');\n } else {\n args.push('-efr');\n }\n\n buildNetworkArgs(args, options);\n\n args.push(String(options.port));\n\n return args;\n}\n\n/** Appends network-related CLI flags. */\nfunction buildNetworkArgs(args: string[], options: WlmscpfsOptions): void {\n if (options.maxPdu !== undefined) {\n args.push('--max-pdu', String(options.maxPdu));\n }\n if (options.acseTimeout !== undefined) {\n args.push('--acse-timeout', String(options.acseTimeout));\n }\n if (options.dimseTimeout !== undefined) {\n args.push('--dimse-timeout', String(options.dimseTimeout));\n }\n if (options.maxAssociations !== undefined) {\n args.push('--max-associations', String(options.maxAssociations));\n }\n}\n\n// ---------------------------------------------------------------------------\n// Wlmscpfs class\n// ---------------------------------------------------------------------------\n\n/**\n * DICOM Worklist Management SCP server wrapping the wlmscpfs binary.\n *\n * Uses a static `create()` factory because binary resolution is fallible\n * and must complete before the constructor runs.\n *\n * Note: wlmscpfs does not print a reliable \"listening\" message in all\n * DCMTK versions, so `start()` resolves on spawn (like StoreSCP).\n *\n * @example\n * ```ts\n * const result = Wlmscpfs.create({ port: 2005, worklistDirectory: '/var/worklists' });\n * if (result.ok) {\n * const server = result.value;\n * server.onEvent('C_FIND_REQUEST', (data) => console.log('Find:', data.raw));\n * const startResult = await server.start();\n * }\n * ```\n */\nclass Wlmscpfs extends DcmtkProcess {\n private readonly parser: LineParser;\n private abortSignal: AbortSignal | undefined;\n private abortHandler: (() => void) | undefined;\n\n private constructor(config: DcmtkProcessConfig, parser: LineParser, signal?: AbortSignal) {\n super(config);\n this.parser = parser;\n this.wireParser();\n if (signal !== undefined) {\n this.wireAbortSignal(signal);\n }\n }\n\n /** Disposes the server and its parser, preventing listener leaks. */\n [Symbol.dispose](): void {\n if (this.abortSignal !== undefined && this.abortHandler !== undefined) {\n this.abortSignal.removeEventListener('abort', this.abortHandler);\n }\n this.parser[Symbol.dispose]();\n super[Symbol.dispose]();\n }\n\n /**\n * Registers a typed listener for a wlmscpfs-specific event.\n *\n * @param event - The event name from WlmscpfsEventMap\n * @param listener - Callback receiving typed event data\n * @returns this for chaining\n */\n onEvent<K extends keyof WlmscpfsEventMap>(event: K, listener: (...args: WlmscpfsEventMap[K]) => void): this {\n return this.on(event as string, listener as never);\n }\n\n /**\n * Registers a listener for incoming C-FIND requests.\n *\n * @param listener - Callback receiving C-FIND request data\n * @returns this for chaining\n */\n onCFindRequest(listener: (...args: WlmscpfsEventMap['C_FIND_REQUEST']) => void): this {\n return this.onEvent('C_FIND_REQUEST', listener);\n }\n\n /**\n * Registers a listener for when the server starts listening.\n *\n * @param listener - Callback receiving listening data (port)\n * @returns this for chaining\n */\n onListening(listener: (...args: WlmscpfsEventMap['LISTENING']) => void): this {\n return this.onEvent('LISTENING', listener);\n }\n\n /**\n * Creates a new Wlmscpfs server instance.\n *\n * @param options - Configuration options for the wlmscpfs server\n * @returns A Result containing the server instance or a validation/resolution error\n */\n static create(options: WlmscpfsOptions): Result<Wlmscpfs> {\n const validation = WlmscpfsOptionsSchema.safeParse(options);\n if (!validation.success) {\n return err(createValidationError('wlmscpfs', validation.error));\n }\n\n const binaryResult = resolveBinary('wlmscpfs');\n if (!binaryResult.ok) {\n return err(binaryResult.error);\n }\n\n const args = buildArgs(options);\n const parser = new LineParser();\n for (const pattern of WLMSCPFS_PATTERNS) {\n const addResult = parser.addPattern(pattern);\n if (!addResult.ok) {\n return err(addResult.error);\n }\n }\n\n const config: DcmtkProcessConfig = {\n binary: binaryResult.value,\n args,\n startTimeoutMs: options.startTimeoutMs,\n drainTimeoutMs: options.drainTimeoutMs,\n // wlmscpfs doesn't reliably print \"listening\" — resolve on spawn\n };\n\n return ok(new Wlmscpfs(config, parser, options.signal));\n }\n\n /** Wires the line parser to the process output. */\n private wireParser(): void {\n this.on('line', ({ text }) => {\n this.parser.feed(text);\n });\n\n this.parser.on('match', ({ event, data }) => {\n if (WLMSCPFS_FATAL_EVENTS.has(event)) {\n this.emit('error', { error: new Error(`Fatal: ${event}`), fatal: true });\n void this.stop();\n }\n this.emit(event, data);\n });\n }\n\n /** Wires an AbortSignal to stop the server. */\n private wireAbortSignal(signal: AbortSignal): void {\n if (signal.aborted) {\n void this.stop();\n return;\n }\n this.abortSignal = signal;\n this.abortHandler = (): void => {\n void this.stop();\n };\n signal.addEventListener('abort', this.abortHandler, { once: true });\n }\n}\n\nexport { Wlmscpfs };\nexport type { WlmscpfsOptions, WlmscpfsEventMap };\n"]}
|