@ubercode/dcmtk 0.13.2 → 0.15.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.
@@ -1777,6 +1777,8 @@ declare class DicomReceiver extends EventEmitter<DicomReceiverEventMap> {
1777
1777
  private startTcpProxy;
1778
1778
  /** Closes the TCP proxy server. */
1779
1779
  private closeTcpProxy;
1780
+ /** Drains in-flight file and instance work on all non-idle workers, with a 5s safety timeout. */
1781
+ private drainAllWorkers;
1780
1782
  /** Routes an incoming connection to an idle worker. */
1781
1783
  private handleConnection;
1782
1784
  /** Finds an idle worker, retrying up to connectionTimeoutMs. */
@@ -1777,6 +1777,8 @@ declare class DicomReceiver extends EventEmitter<DicomReceiverEventMap> {
1777
1777
  private startTcpProxy;
1778
1778
  /** Closes the TCP proxy server. */
1779
1779
  private closeTcpProxy;
1780
+ /** Drains in-flight file and instance work on all non-idle workers, with a 5s safety timeout. */
1781
+ private drainAllWorkers;
1780
1782
  /** Routes an incoming connection to an idle worker. */
1781
1783
  private handleConnection;
1782
1784
  /** Finds an idle worker, retrying up to connectionTimeoutMs. */
package/dist/index.cjs CHANGED
@@ -713,6 +713,51 @@ var LineParser = class extends events.EventEmitter {
713
713
  }
714
714
  };
715
715
 
716
+ // src/tools/_toolError.ts
717
+ var MAX_ARGS_LENGTH = 200;
718
+ var MAX_STDERR_LENGTH = 500;
719
+ function truncate(value, maxLength) {
720
+ if (value.length <= maxLength) {
721
+ return value;
722
+ }
723
+ return `${value.substring(0, maxLength)}...`;
724
+ }
725
+ var ToolExecutionError = class extends Error {
726
+ constructor(message, details) {
727
+ super(message);
728
+ __publicField(this, "stdout");
729
+ __publicField(this, "stderr");
730
+ __publicField(this, "exitCode");
731
+ this.name = "ToolExecutionError";
732
+ this.stdout = details.stdout;
733
+ this.stderr = details.stderr;
734
+ this.exitCode = details.exitCode;
735
+ }
736
+ };
737
+ function createToolError(toolName, args, exitCode, stderr8, stdout = "") {
738
+ const argsStr = truncate(args.join(" "), MAX_ARGS_LENGTH);
739
+ const stderrStr = truncate(stderr8.trim(), MAX_STDERR_LENGTH);
740
+ const parts = [`${toolName} failed (exit code ${String(exitCode)})`];
741
+ if (argsStr.length > 0) {
742
+ parts.push(`args: ${argsStr}`);
743
+ }
744
+ if (stderrStr.length > 0) {
745
+ parts.push(`stderr: ${stderrStr}`);
746
+ }
747
+ return new ToolExecutionError(parts.join(" | "), { stdout, stderr: stderr8, exitCode });
748
+ }
749
+ function createValidationError(toolName, zodError) {
750
+ const parts = [];
751
+ for (let i = 0; i < zodError.issues.length; i++) {
752
+ const issue = zodError.issues[i];
753
+ if (issue === void 0) continue;
754
+ const path2 = issue.path.length > 0 ? issue.path.map(String).join(".") : "(root)";
755
+ parts.push(`${path2}: ${issue.message}`);
756
+ }
757
+ const detail = parts.length > 0 ? parts.join("; ") : "unknown validation error";
758
+ return new Error(`${toolName}: invalid options \u2014 ${detail}`);
759
+ }
760
+
716
761
  // src/dicom/vr.ts
717
762
  var VR = {
718
763
  /** Application Entity — 16 bytes max, leading/trailing spaces significant */
@@ -31136,39 +31181,6 @@ function resolveBinary(toolName) {
31136
31181
  return ok(path.join(pathResult.value, binaryName2));
31137
31182
  }
31138
31183
 
31139
- // src/tools/_toolError.ts
31140
- var MAX_ARGS_LENGTH = 200;
31141
- var MAX_STDERR_LENGTH = 500;
31142
- function truncate(value, maxLength) {
31143
- if (value.length <= maxLength) {
31144
- return value;
31145
- }
31146
- return `${value.substring(0, maxLength)}...`;
31147
- }
31148
- function createToolError(toolName, args, exitCode, stderr8) {
31149
- const argsStr = truncate(args.join(" "), MAX_ARGS_LENGTH);
31150
- const stderrStr = truncate(stderr8.trim(), MAX_STDERR_LENGTH);
31151
- const parts = [`${toolName} failed (exit code ${String(exitCode)})`];
31152
- if (argsStr.length > 0) {
31153
- parts.push(`args: ${argsStr}`);
31154
- }
31155
- if (stderrStr.length > 0) {
31156
- parts.push(`stderr: ${stderrStr}`);
31157
- }
31158
- return new Error(parts.join(" | "));
31159
- }
31160
- function createValidationError(toolName, zodError) {
31161
- const parts = [];
31162
- for (let i = 0; i < zodError.issues.length; i++) {
31163
- const issue = zodError.issues[i];
31164
- if (issue === void 0) continue;
31165
- const path2 = issue.path.length > 0 ? issue.path.map(String).join(".") : "(root)";
31166
- parts.push(`${path2}: ${issue.message}`);
31167
- }
31168
- const detail = parts.length > 0 ? parts.join("; ") : "unknown validation error";
31169
- return new Error(`${toolName}: invalid options \u2014 ${detail}`);
31170
- }
31171
-
31172
31184
  // src/tools/dcm2xml.ts
31173
31185
  var Dcm2xmlCharset = {
31174
31186
  /** Use UTF-8 encoding (default). */
@@ -31552,15 +31564,17 @@ async function dcm2json(inputPath, options) {
31552
31564
  }
31553
31565
  const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
31554
31566
  const signal = options?.signal;
31567
+ const startTime = Date.now();
31568
+ const remaining = () => Math.max(1e3, timeoutMs - (Date.now() - startTime));
31555
31569
  const verbosity = options?.verbosity;
31556
31570
  if (options?.directOnly === true) {
31557
- return tryDirectPath(inputPath, timeoutMs, signal, verbosity);
31571
+ return tryDirectPath(inputPath, remaining(), signal, verbosity);
31558
31572
  }
31559
- const xmlResult = await tryXmlPath(inputPath, timeoutMs, signal, buildXmlOpts(options));
31573
+ const xmlResult = await tryXmlPath(inputPath, remaining(), signal, buildXmlOpts(options));
31560
31574
  if (xmlResult.ok) {
31561
31575
  return xmlResult;
31562
31576
  }
31563
- return tryDirectPath(inputPath, timeoutMs, signal, verbosity);
31577
+ return tryDirectPath(inputPath, remaining(), signal, verbosity);
31564
31578
  }
31565
31579
  var DcmdumpFormat = {
31566
31580
  /** Print standard DCMTK format. */
@@ -33288,7 +33302,7 @@ async function dcmsend(options) {
33288
33302
  return err(result.error);
33289
33303
  }
33290
33304
  if (result.value.exitCode !== 0) {
33291
- return err(createToolError("dcmsend", args, result.value.exitCode, result.value.stderr));
33305
+ return err(createToolError("dcmsend", args, result.value.exitCode, result.value.stderr, result.value.stdout));
33292
33306
  }
33293
33307
  return ok({ success: true, stdout: result.value.stdout, stderr: result.value.stderr });
33294
33308
  }
@@ -33443,10 +33457,10 @@ async function storescu(options) {
33443
33457
  return err(result.error);
33444
33458
  }
33445
33459
  if (result.value.exitCode !== 0) {
33446
- return err(createToolError("storescu", args, result.value.exitCode, result.value.stderr));
33460
+ return err(createToolError("storescu", args, result.value.exitCode, result.value.stderr, result.value.stdout));
33447
33461
  }
33448
33462
  if (DIMSE_ERROR_PATTERN.test(result.value.stderr)) {
33449
- return err(createToolError("storescu", args, 0, result.value.stderr));
33463
+ return err(createToolError("storescu", args, 0, result.value.stderr, result.value.stdout));
33450
33464
  }
33451
33465
  return ok({ success: true, stdout: result.value.stdout, stderr: result.value.stderr });
33452
33466
  }
@@ -36517,7 +36531,7 @@ var Worker = class {
36517
36531
  this.port = port;
36518
36532
  this.tempDir = tempDir;
36519
36533
  }
36520
- /** Current worker state. */
36534
+ /** Current worker state: idle (ready), busy (handling association), finalizing (draining). */
36521
36535
  get state() {
36522
36536
  return this._state;
36523
36537
  }
@@ -36549,6 +36563,10 @@ var Worker = class {
36549
36563
  this._instancesReceived = 0;
36550
36564
  this._instanceErrors = 0;
36551
36565
  }
36566
+ /** Marks the worker as finalizing — still has valid context but cannot accept new connections. */
36567
+ markFinalizing() {
36568
+ this._state = "finalizing";
36569
+ }
36552
36570
  /**
36553
36571
  * Returns the worker to idle. Context is intentionally preserved so that
36554
36572
  * late FILE_RECEIVED events (arriving in a subsequent pipe chunk after
@@ -36731,6 +36749,7 @@ var DicomReceiver = class _DicomReceiver extends events.EventEmitter {
36731
36749
  this.options.signal.removeEventListener("abort", this.abortHandler);
36732
36750
  }
36733
36751
  await this.closeTcpProxy();
36752
+ await this.drainAllWorkers();
36734
36753
  const stopPromises = [];
36735
36754
  for (const worker of this.workers.values()) {
36736
36755
  stopPromises.push(this.stopWorker(worker));
@@ -36899,6 +36918,18 @@ var DicomReceiver = class _DicomReceiver extends events.EventEmitter {
36899
36918
  this.tcpServer.close(() => resolve());
36900
36919
  });
36901
36920
  }
36921
+ /** Drains in-flight file and instance work on all non-idle workers, with a 5s safety timeout. */
36922
+ async drainAllWorkers() {
36923
+ const drainPromises = [];
36924
+ for (const worker of this.workers.values()) {
36925
+ if (worker.state !== "idle") {
36926
+ drainPromises.push(worker.drainPendingFiles());
36927
+ drainPromises.push(worker.drainInstancePending());
36928
+ }
36929
+ }
36930
+ if (drainPromises.length === 0) return;
36931
+ await Promise.race([Promise.all(drainPromises), promises.setTimeout(5e3)]);
36932
+ }
36902
36933
  // -----------------------------------------------------------------------
36903
36934
  // Connection routing
36904
36935
  // -----------------------------------------------------------------------
@@ -36927,7 +36958,9 @@ var DicomReceiver = class _DicomReceiver extends events.EventEmitter {
36927
36958
  };
36928
36959
  worker.beginAssociation(ctx);
36929
36960
  this.pipeConnection(worker, remoteSocket);
36930
- void this.replenishPool();
36961
+ void this.replenishPool().catch((e) => {
36962
+ this.emit("error", { error: e instanceof Error ? e : new Error(String(e)) });
36963
+ });
36931
36964
  }
36932
36965
  /** Finds an idle worker, retrying up to connectionTimeoutMs. */
36933
36966
  async findIdleWorker() {
@@ -37166,6 +37199,7 @@ var DicomReceiver = class _DicomReceiver extends events.EventEmitter {
37166
37199
  /** Returns worker to idle pool on association complete, emits summary. */
37167
37200
  wireAssociationComplete(worker) {
37168
37201
  worker.dcmrecv.onAssociationComplete((data) => {
37202
+ worker.markFinalizing();
37169
37203
  setImmediate(() => {
37170
37204
  void this.finalizeAssociation(worker, data);
37171
37205
  });
@@ -37319,8 +37353,14 @@ var SenderEngine = class {
37319
37353
  // Bucket state (bucket mode only)
37320
37354
  __publicField(this, "currentBucket", []);
37321
37355
  __publicField(this, "bucketTimer");
37356
+ // Abort wiring: stopController fires on stop(); combinedSignal also fires
37357
+ // when the externally provided config.signal aborts. Passed into the
37358
+ // executor and into delayInterruptible so stop() unblocks promptly.
37359
+ __publicField(this, "stopController", new AbortController());
37360
+ __publicField(this, "combinedSignal");
37322
37361
  this.config = config;
37323
37362
  this.effectiveMaxAssociations = config.configuredMaxAssociations;
37363
+ this.combinedSignal = combineSignals(this.stopController.signal, config.signal);
37324
37364
  }
37325
37365
  // -----------------------------------------------------------------------
37326
37366
  // Public API
@@ -37346,6 +37386,7 @@ var SenderEngine = class {
37346
37386
  async stop() {
37347
37387
  if (this.isStopped) return;
37348
37388
  this.isStopped = true;
37389
+ this.stopController.abort();
37349
37390
  this.clearBucketTimer();
37350
37391
  this.rejectBucket(`${this.config.senderName}: sender stopped`);
37351
37392
  this.rejectQueue(`${this.config.senderName}: sender stopped`);
@@ -37462,18 +37503,48 @@ var SenderEngine = class {
37462
37503
  }
37463
37504
  };
37464
37505
  }
37465
- /** Flushes the current bucket: combines all files, dispatches as one send. */
37506
+ /**
37507
+ * Flushes the current bucket. Entries with the same bucketParamsKey merge
37508
+ * into one underlying call; differing keys split into separate calls,
37509
+ * preserving first-occurrence order. Each group emits its own
37510
+ * BUCKET_FLUSHED. If the number of groups exceeds available capacity,
37511
+ * the surplus is queued and drains as capacity frees.
37512
+ */
37466
37513
  flushBucketInternal(reason) {
37467
37514
  if (this.currentBucket.length === 0) return;
37468
37515
  const entries = [...this.currentBucket];
37469
37516
  this.currentBucket = [];
37470
- const bucketEntry = this.mergeBucketEntries(entries);
37471
- this.config.emitters.emitBucketFlushed({ fileCount: bucketEntry.files.length, reason });
37472
- if (this.activeAssociations < this.effectiveMaxAssociations) {
37473
- void this.executeEntry(bucketEntry);
37474
- } else {
37475
- this.queue.push(bucketEntry);
37517
+ const groups = this.groupBucketByParams(entries);
37518
+ for (const group of groups) {
37519
+ const bucketEntry = this.mergeBucketEntries(group);
37520
+ this.config.emitters.emitBucketFlushed({ fileCount: bucketEntry.files.length, reason });
37521
+ if (this.activeAssociations < this.effectiveMaxAssociations) {
37522
+ void this.executeEntry(bucketEntry);
37523
+ } else {
37524
+ this.queue.push(bucketEntry);
37525
+ }
37526
+ }
37527
+ }
37528
+ /**
37529
+ * Groups bucket entries by bucketParamsKey while preserving first-occurrence
37530
+ * order. Without a key function, returns a single group containing every
37531
+ * entry (current behavior for callers that don't vary binaryParams).
37532
+ */
37533
+ groupBucketByParams(entries) {
37534
+ const keyFn = this.config.bucketParamsKey;
37535
+ if (keyFn === void 0) return [entries.slice()];
37536
+ const groups = /* @__PURE__ */ new Map();
37537
+ for (let i = 0; i < entries.length; i++) {
37538
+ const entry = entries[i];
37539
+ const key = keyFn(entry.binaryParams);
37540
+ let group = groups.get(key);
37541
+ if (group === void 0) {
37542
+ group = [];
37543
+ groups.set(key, group);
37544
+ }
37545
+ group.push(entry);
37476
37546
  }
37547
+ return Array.from(groups.values());
37477
37548
  }
37478
37549
  /** Resets the bucket flush timer. */
37479
37550
  resetBucketTimer() {
@@ -37515,25 +37586,33 @@ var SenderEngine = class {
37515
37586
  /** Attempts the binary call up to maxAttempts times. Returns undefined on success. */
37516
37587
  async attemptSend(entry, maxAttempts, startMs) {
37517
37588
  let lastError;
37518
- const lastOutput = { stdout: "", stderr: "" };
37589
+ let lastOutput = { stdout: "", stderr: "" };
37519
37590
  for (let attempt = 0; attempt < maxAttempts; attempt++) {
37520
37591
  if (this.isStopped) {
37521
- this.activeAssociations--;
37522
- entry.resolve(err(new Error(`${this.config.senderName}: sender stopped`)));
37523
- return void 0;
37592
+ return this.resolveStopped(entry);
37524
37593
  }
37525
- const result = await this.config.executor(entry.files, entry.timeoutMs, entry.binaryParams, this.config.signal);
37526
- if (result.ok) {
37527
- this.handleSendSuccess(entry, startMs, result.value);
37594
+ const outcome = await this.config.executor(entry.files, entry.timeoutMs, entry.binaryParams, this.combinedSignal);
37595
+ lastOutput = { stdout: outcome.stdout, stderr: outcome.stderr };
37596
+ if (outcome.error === void 0) {
37597
+ this.handleSendSuccess(entry, startMs, lastOutput);
37528
37598
  return void 0;
37529
37599
  }
37530
- lastError = result.error;
37600
+ if (this.isStopped) {
37601
+ return this.resolveStopped(entry);
37602
+ }
37603
+ lastError = outcome.error;
37531
37604
  if (attempt < maxAttempts - 1) {
37532
- await delay2(this.config.retryDelayMs * (attempt + 1));
37605
+ await delayInterruptible(this.config.retryDelayMs * (attempt + 1), this.combinedSignal);
37533
37606
  }
37534
37607
  }
37535
37608
  return { error: lastError ?? new Error(`${this.config.senderName}: send failed`), output: lastOutput };
37536
37609
  }
37610
+ /** Resolves the entry as stopped and decrements activeAssociations. Used from attemptSend. */
37611
+ resolveStopped(entry) {
37612
+ this.activeAssociations--;
37613
+ entry.resolve(err(new Error(`${this.config.senderName}: sender stopped`)));
37614
+ return void 0;
37615
+ }
37537
37616
  /** Handles a successful send: updates state, emits event, resolves promise. */
37538
37617
  handleSendSuccess(entry, startMs, output) {
37539
37618
  this.activeAssociations--;
@@ -37639,11 +37718,41 @@ var SenderEngine = class {
37639
37718
  });
37640
37719
  }
37641
37720
  };
37642
- function delay2(ms) {
37721
+ function delayInterruptible(ms, signal) {
37722
+ if (signal.aborted) return Promise.resolve();
37643
37723
  return new Promise((resolve) => {
37644
- setTimeout(resolve, ms);
37724
+ const onAbort = () => {
37725
+ clearTimeout(timer);
37726
+ resolve();
37727
+ };
37728
+ const timer = setTimeout(() => {
37729
+ signal.removeEventListener("abort", onAbort);
37730
+ resolve();
37731
+ }, ms);
37732
+ signal.addEventListener("abort", onAbort, { once: true });
37645
37733
  });
37646
37734
  }
37735
+ function combineSignals(primary, external) {
37736
+ if (external === void 0) return primary;
37737
+ if (primary.aborted) return primary;
37738
+ if (external.aborted) {
37739
+ const c = new AbortController();
37740
+ c.abort(external.reason);
37741
+ return c.signal;
37742
+ }
37743
+ const merged = new AbortController();
37744
+ const onPrimary = () => {
37745
+ merged.abort(primary.reason);
37746
+ external.removeEventListener("abort", onExternal);
37747
+ };
37748
+ const onExternal = () => {
37749
+ merged.abort(external.reason);
37750
+ primary.removeEventListener("abort", onPrimary);
37751
+ };
37752
+ primary.addEventListener("abort", onPrimary, { once: true });
37753
+ external.addEventListener("abort", onExternal, { once: true });
37754
+ return merged.signal;
37755
+ }
37647
37756
 
37648
37757
  // src/senders/DicomSender.ts
37649
37758
  var DEFAULT_MAX_ASSOCIATIONS = 4;
@@ -37678,6 +37787,9 @@ var DicomSenderOptionsSchema = zod.z.object({
37678
37787
  required: zod.z.boolean().optional(),
37679
37788
  signal: zod.z.instanceof(AbortSignal).optional()
37680
37789
  }).strict();
37790
+ function storescuBucketKey(p) {
37791
+ return JSON.stringify(p);
37792
+ }
37681
37793
  function createStorescuExecutor(options) {
37682
37794
  return async (files, timeoutMs, params, signal) => {
37683
37795
  const result = await storescu({
@@ -37699,8 +37811,13 @@ function createStorescuExecutor(options) {
37699
37811
  timeoutMs,
37700
37812
  signal
37701
37813
  });
37702
- if (!result.ok) return err(result.error);
37703
- return ok({ stdout: result.value.stdout, stderr: result.value.stderr });
37814
+ if (!result.ok) {
37815
+ const e = result.error;
37816
+ const stdout = e instanceof ToolExecutionError ? e.stdout : "";
37817
+ const stderr8 = e instanceof ToolExecutionError ? e.stderr : "";
37818
+ return { stdout, stderr: stderr8, error: e };
37819
+ }
37820
+ return { stdout: result.value.stdout, stderr: result.value.stderr };
37704
37821
  };
37705
37822
  }
37706
37823
  function resolveConfig2(options) {
@@ -37757,6 +37874,7 @@ var DicomSender = class _DicomSender extends events.EventEmitter {
37757
37874
  executor: createStorescuExecutor(options),
37758
37875
  signal: options.signal,
37759
37876
  senderName: "DicomSender",
37877
+ bucketParamsKey: storescuBucketKey,
37760
37878
  emitters: {
37761
37879
  emitSendComplete: (data) => {
37762
37880
  senderRef.current.emit("SEND_COMPLETE", data);
@@ -37925,6 +38043,9 @@ var DicomSendOptionsSchema = zod.z.object({
37925
38043
  noUidChecks: zod.z.boolean().optional(),
37926
38044
  signal: zod.z.instanceof(AbortSignal).optional()
37927
38045
  }).strict();
38046
+ function dcmsendBucketKey(p) {
38047
+ return JSON.stringify(p);
38048
+ }
37928
38049
  function createDcmsendExecutor(options) {
37929
38050
  return async (files, timeoutMs, params, signal) => {
37930
38051
  const result = await dcmsend({
@@ -37948,8 +38069,13 @@ function createDcmsendExecutor(options) {
37948
38069
  timeoutMs,
37949
38070
  signal
37950
38071
  });
37951
- if (!result.ok) return err(result.error);
37952
- return ok({ stdout: result.value.stdout, stderr: result.value.stderr });
38072
+ if (!result.ok) {
38073
+ const e = result.error;
38074
+ const stdout = e instanceof ToolExecutionError ? e.stdout : "";
38075
+ const stderr8 = e instanceof ToolExecutionError ? e.stderr : "";
38076
+ return { stdout, stderr: stderr8, error: e };
38077
+ }
38078
+ return { stdout: result.value.stdout, stderr: result.value.stderr };
37953
38079
  };
37954
38080
  }
37955
38081
  function resolveConfig3(options) {
@@ -38006,6 +38132,7 @@ var DicomSend = class _DicomSend extends events.EventEmitter {
38006
38132
  executor: createDcmsendExecutor(options),
38007
38133
  signal: options.signal,
38008
38134
  senderName: "DicomSend",
38135
+ bucketParamsKey: dcmsendBucketKey,
38009
38136
  emitters: {
38010
38137
  emitSendComplete: (data) => {
38011
38138
  senderRef.current.emit("SEND_COMPLETE", data);
@@ -38693,7 +38820,7 @@ function computeThroughput(succeeded, totalBytes, durationMs) {
38693
38820
  bytesPerSec: durationSec > 0 ? totalBytes / durationSec : 0
38694
38821
  };
38695
38822
  }
38696
- function delay3(ms) {
38823
+ function delay2(ms) {
38697
38824
  return new Promise((resolve) => {
38698
38825
  setTimeout(resolve, ms);
38699
38826
  });
@@ -38840,7 +38967,7 @@ var DicomHammer = class _DicomHammer extends events.EventEmitter {
38840
38967
  /** Sends a single file, with optional delay. */
38841
38968
  async sendOneFile(file) {
38842
38969
  if (this.opts.delayMs > 0) {
38843
- await delay3(this.opts.delayMs);
38970
+ await delay2(this.opts.delayMs);
38844
38971
  }
38845
38972
  const result = await dcmsend({
38846
38973
  host: this.opts.host,
@@ -39007,6 +39134,7 @@ exports.StoreSCP = StoreSCP;
39007
39134
  exports.StoreSCPPreset = StoreSCPPreset;
39008
39135
  exports.StorescpEvent = StorescpEvent;
39009
39136
  exports.SubdirectoryMode = SubdirectoryMode;
39137
+ exports.ToolExecutionError = ToolExecutionError;
39010
39138
  exports.TransferSyntax = TransferSyntax;
39011
39139
  exports.UIDSchema = UIDSchema;
39012
39140
  exports.UNIX_SEARCH_PATHS = UNIX_SEARCH_PATHS;