@ubercode/dcmtk 0.7.1 → 0.7.3

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/dist/index.d.cts CHANGED
@@ -263,8 +263,10 @@ interface DicomSenderOptions {
263
263
  readonly mode?: SenderModeValue | undefined;
264
264
  /** Maximum concurrent storescu associations. Defaults to 4 (forced to 1 in single mode). */
265
265
  readonly maxAssociations?: number | undefined;
266
- /** Proposed transfer syntax for associations. */
267
- readonly proposedTransferSyntax?: ProposedTransferSyntaxValue | undefined;
266
+ /** Proposed transfer syntax(es) for associations. Pass an array to propose multiple. */
267
+ readonly proposedTransferSyntax?: ProposedTransferSyntaxValue | readonly ProposedTransferSyntaxValue[] | undefined;
268
+ /** Combine proposed transfer syntaxes into fewer presentation contexts. Maps to `+C`/`--combine`. */
269
+ readonly combineProposedTransferSyntaxes?: boolean | undefined;
268
270
  /** Maximum queued send requests before rejecting. Defaults to 1000. */
269
271
  readonly maxQueueLength?: number | undefined;
270
272
  /** Per-storescu timeout in milliseconds. Defaults to 30000. */
@@ -291,6 +293,8 @@ interface DicomSenderOptions {
291
293
  readonly noHostnameLookup?: boolean | undefined;
292
294
  /** Verbosity level for diagnostic output. `'verbose'` maps to `-v`, `'debug'` maps to `-d`. */
293
295
  readonly verbosity?: 'verbose' | 'debug' | undefined;
296
+ /** Propose only each file's native transfer syntax (passed through to storescu `-R`). */
297
+ readonly required?: boolean | undefined;
294
298
  /** AbortSignal for external cancellation. */
295
299
  readonly signal?: AbortSignal | undefined;
296
300
  }
@@ -304,6 +308,12 @@ interface SendOptions {
304
308
  readonly calledAETitle?: string | undefined;
305
309
  /** Override calling AE Title for this send. */
306
310
  readonly callingAETitle?: string | undefined;
311
+ /** Override required flag for this send. */
312
+ readonly required?: boolean | undefined;
313
+ /** Override proposed transfer syntax(es) for this send. */
314
+ readonly proposedTransferSyntax?: ProposedTransferSyntaxValue | readonly ProposedTransferSyntaxValue[] | undefined;
315
+ /** Override combine proposed transfer syntaxes for this send. */
316
+ readonly combineProposedTransferSyntaxes?: boolean | undefined;
307
317
  }
308
318
  /** Result of a successful send operation. */
309
319
  interface SendResult {
@@ -476,6 +486,8 @@ declare class DicomSender extends EventEmitter<DicomSenderEventMap> {
476
486
  * @returns A Result containing the send result or an error
477
487
  */
478
488
  send(files: readonly string[], options?: SendOptions): Promise<Result<SendResult>>;
489
+ /** Builds SendParams from per-send options, applying instance defaults. */
490
+ private buildSendParams;
479
491
  /** Dispatches a send to the appropriate mode handler. */
480
492
  private dispatchSend;
481
493
  /**
@@ -534,6 +546,8 @@ declare class DicomSender extends EventEmitter<DicomSenderEventMap> {
534
546
  private enqueueBucket;
535
547
  /** Counts total files in the current bucket. */
536
548
  private countBucketFiles;
549
+ /** Merges bucket entries into a single QueueEntry. */
550
+ private mergeBucketEntries;
537
551
  /** Flushes the current bucket: combines all files, dispatches as one send. */
538
552
  private flushBucketInternal;
539
553
  /** Resets the bucket flush timer. */
package/dist/index.d.ts CHANGED
@@ -263,8 +263,10 @@ interface DicomSenderOptions {
263
263
  readonly mode?: SenderModeValue | undefined;
264
264
  /** Maximum concurrent storescu associations. Defaults to 4 (forced to 1 in single mode). */
265
265
  readonly maxAssociations?: number | undefined;
266
- /** Proposed transfer syntax for associations. */
267
- readonly proposedTransferSyntax?: ProposedTransferSyntaxValue | undefined;
266
+ /** Proposed transfer syntax(es) for associations. Pass an array to propose multiple. */
267
+ readonly proposedTransferSyntax?: ProposedTransferSyntaxValue | readonly ProposedTransferSyntaxValue[] | undefined;
268
+ /** Combine proposed transfer syntaxes into fewer presentation contexts. Maps to `+C`/`--combine`. */
269
+ readonly combineProposedTransferSyntaxes?: boolean | undefined;
268
270
  /** Maximum queued send requests before rejecting. Defaults to 1000. */
269
271
  readonly maxQueueLength?: number | undefined;
270
272
  /** Per-storescu timeout in milliseconds. Defaults to 30000. */
@@ -291,6 +293,8 @@ interface DicomSenderOptions {
291
293
  readonly noHostnameLookup?: boolean | undefined;
292
294
  /** Verbosity level for diagnostic output. `'verbose'` maps to `-v`, `'debug'` maps to `-d`. */
293
295
  readonly verbosity?: 'verbose' | 'debug' | undefined;
296
+ /** Propose only each file's native transfer syntax (passed through to storescu `-R`). */
297
+ readonly required?: boolean | undefined;
294
298
  /** AbortSignal for external cancellation. */
295
299
  readonly signal?: AbortSignal | undefined;
296
300
  }
@@ -304,6 +308,12 @@ interface SendOptions {
304
308
  readonly calledAETitle?: string | undefined;
305
309
  /** Override calling AE Title for this send. */
306
310
  readonly callingAETitle?: string | undefined;
311
+ /** Override required flag for this send. */
312
+ readonly required?: boolean | undefined;
313
+ /** Override proposed transfer syntax(es) for this send. */
314
+ readonly proposedTransferSyntax?: ProposedTransferSyntaxValue | readonly ProposedTransferSyntaxValue[] | undefined;
315
+ /** Override combine proposed transfer syntaxes for this send. */
316
+ readonly combineProposedTransferSyntaxes?: boolean | undefined;
307
317
  }
308
318
  /** Result of a successful send operation. */
309
319
  interface SendResult {
@@ -476,6 +486,8 @@ declare class DicomSender extends EventEmitter<DicomSenderEventMap> {
476
486
  * @returns A Result containing the send result or an error
477
487
  */
478
488
  send(files: readonly string[], options?: SendOptions): Promise<Result<SendResult>>;
489
+ /** Builds SendParams from per-send options, applying instance defaults. */
490
+ private buildSendParams;
479
491
  /** Dispatches a send to the appropriate mode handler. */
480
492
  private dispatchSend;
481
493
  /**
@@ -534,6 +546,8 @@ declare class DicomSender extends EventEmitter<DicomSenderEventMap> {
534
546
  private enqueueBucket;
535
547
  /** Counts total files in the current bucket. */
536
548
  private countBucketFiles;
549
+ /** Merges bucket entries into a single QueueEntry. */
550
+ private mergeBucketEntries;
537
551
  /** Flushes the current bucket: combines all files, dispatches as one send. */
538
552
  private flushBucketInternal;
539
553
  /** Resets the bucket flush timer. */
package/dist/index.js CHANGED
@@ -33200,7 +33200,18 @@ var ProposedTransferSyntax = {
33200
33200
  J2K_LOSSLESS: "j2kLossless",
33201
33201
  J2K_LOSSY: "j2kLossy",
33202
33202
  JLS_LOSSLESS: "jlsLossless",
33203
- JLS_LOSSY: "jlsLossy"
33203
+ JLS_LOSSY: "jlsLossy",
33204
+ MPEG2: "mpeg2",
33205
+ MPEG2_HIGH: "mpeg2High",
33206
+ MPEG4: "mpeg4",
33207
+ MPEG4_BD: "mpeg4Bd",
33208
+ MPEG4_2_2D: "mpeg4_2_2d",
33209
+ MPEG4_2_3D: "mpeg4_2_3d",
33210
+ MPEG4_2_ST: "mpeg4_2_st",
33211
+ HEVC: "hevc",
33212
+ HEVC10: "hevc10",
33213
+ RLE: "rle",
33214
+ DEFLATED: "deflated"
33204
33215
  };
33205
33216
  var PROPOSED_TS_FLAG_MAP = {
33206
33217
  [ProposedTransferSyntax.UNCOMPRESSED]: "-x=",
@@ -33213,8 +33224,20 @@ var PROPOSED_TS_FLAG_MAP = {
33213
33224
  [ProposedTransferSyntax.J2K_LOSSLESS]: "-xv",
33214
33225
  [ProposedTransferSyntax.J2K_LOSSY]: "-xw",
33215
33226
  [ProposedTransferSyntax.JLS_LOSSLESS]: "-xt",
33216
- [ProposedTransferSyntax.JLS_LOSSY]: "-xu"
33227
+ [ProposedTransferSyntax.JLS_LOSSY]: "-xu",
33228
+ [ProposedTransferSyntax.MPEG2]: "-xm",
33229
+ [ProposedTransferSyntax.MPEG2_HIGH]: "-xh",
33230
+ [ProposedTransferSyntax.MPEG4]: "-xn",
33231
+ [ProposedTransferSyntax.MPEG4_BD]: "-xl",
33232
+ [ProposedTransferSyntax.MPEG4_2_2D]: "-x2",
33233
+ [ProposedTransferSyntax.MPEG4_2_3D]: "-x3",
33234
+ [ProposedTransferSyntax.MPEG4_2_ST]: "-xo",
33235
+ [ProposedTransferSyntax.HEVC]: "-x4",
33236
+ [ProposedTransferSyntax.HEVC10]: "-x5",
33237
+ [ProposedTransferSyntax.RLE]: "-xr",
33238
+ [ProposedTransferSyntax.DEFLATED]: "-xd"
33217
33239
  };
33240
+ var PROPOSED_TS_VALUES = Object.values(ProposedTransferSyntax);
33218
33241
  var StorescuOptionsSchema = z.object({
33219
33242
  timeoutMs: z.number().int().positive().optional(),
33220
33243
  signal: z.instanceof(AbortSignal).optional(),
@@ -33232,21 +33255,21 @@ var StorescuOptionsSchema = z.object({
33232
33255
  acseTimeout: z.number().int().positive().optional(),
33233
33256
  dimseTimeout: z.number().int().positive().optional(),
33234
33257
  noHostnameLookup: z.boolean().optional(),
33235
- proposedTransferSyntax: z.enum([
33236
- "uncompressed",
33237
- "littleEndian",
33238
- "bigEndian",
33239
- "implicitVR",
33240
- "jpegLossless",
33241
- "jpeg8Bit",
33242
- "jpeg12Bit",
33243
- "j2kLossless",
33244
- "j2kLossy",
33245
- "jlsLossless",
33246
- "jlsLossy"
33247
- ]).optional()
33258
+ required: z.boolean().optional(),
33259
+ proposedTransferSyntax: z.union([z.enum(PROPOSED_TS_VALUES), z.array(z.enum(PROPOSED_TS_VALUES)).min(1)]).optional(),
33260
+ combineProposedTransferSyntaxes: z.boolean().optional()
33248
33261
  }).strict();
33262
+ function pushProposedTsArgs(args, ts) {
33263
+ if (typeof ts === "string") {
33264
+ args.push(PROPOSED_TS_FLAG_MAP[ts]);
33265
+ } else {
33266
+ for (let i = 0; i < ts.length; i++) {
33267
+ args.push(PROPOSED_TS_FLAG_MAP[ts[i]]);
33268
+ }
33269
+ }
33270
+ }
33249
33271
  var VERBOSITY_FLAGS20 = { verbose: "-v", debug: "-d" };
33272
+ var DIMSE_ERROR_PATTERN = /^E:.*(?:DIMSE Failed|Store Failed)/m;
33250
33273
  function pushNetworkArgs3(args, options) {
33251
33274
  if (options.verbosity !== void 0) {
33252
33275
  args.push(VERBOSITY_FLAGS20[options.verbosity]);
@@ -33286,7 +33309,13 @@ function buildArgs34(options) {
33286
33309
  args.push("+r");
33287
33310
  }
33288
33311
  if (options.proposedTransferSyntax !== void 0) {
33289
- args.push(PROPOSED_TS_FLAG_MAP[options.proposedTransferSyntax]);
33312
+ pushProposedTsArgs(args, options.proposedTransferSyntax);
33313
+ }
33314
+ if (options.combineProposedTransferSyntaxes === true) {
33315
+ args.push("+C");
33316
+ }
33317
+ if (options.required === true) {
33318
+ args.push("-R");
33290
33319
  }
33291
33320
  args.push(options.host, String(options.port));
33292
33321
  args.push(...options.files);
@@ -33313,6 +33342,9 @@ async function storescu(options) {
33313
33342
  if (result.value.exitCode !== 0) {
33314
33343
  return err(createToolError("storescu", args, result.value.exitCode, result.value.stderr));
33315
33344
  }
33345
+ if (DIMSE_ERROR_PATTERN.test(result.value.stderr)) {
33346
+ return err(createToolError("storescu", args, 0, result.value.stderr));
33347
+ }
33316
33348
  return ok({ success: true, stdout: result.value.stdout, stderr: result.value.stderr });
33317
33349
  }
33318
33350
  var QueryModel = {
@@ -36838,19 +36870,8 @@ var DicomSenderOptionsSchema = z.object({
36838
36870
  callingAETitle: z.string().min(1).max(16).refine(isValidAETitle, { message: "AE Title contains invalid characters" }).optional(),
36839
36871
  mode: z.enum(["single", "multiple", "bucket"]).optional(),
36840
36872
  maxAssociations: z.number().int().min(1).max(MAX_ASSOCIATIONS_LIMIT).optional(),
36841
- proposedTransferSyntax: z.enum([
36842
- "uncompressed",
36843
- "littleEndian",
36844
- "bigEndian",
36845
- "implicitVR",
36846
- "jpegLossless",
36847
- "jpeg8Bit",
36848
- "jpeg12Bit",
36849
- "j2kLossless",
36850
- "j2kLossy",
36851
- "jlsLossless",
36852
- "jlsLossy"
36853
- ]).optional(),
36873
+ proposedTransferSyntax: z.union([z.enum(PROPOSED_TS_VALUES), z.array(z.enum(PROPOSED_TS_VALUES)).min(1)]).optional(),
36874
+ combineProposedTransferSyntaxes: z.boolean().optional(),
36854
36875
  maxQueueLength: z.number().int().min(1).optional(),
36855
36876
  timeoutMs: z.number().int().positive().optional(),
36856
36877
  maxRetries: z.number().int().min(0).optional(),
@@ -36864,6 +36885,7 @@ var DicomSenderOptionsSchema = z.object({
36864
36885
  dimseTimeout: z.number().int().positive().optional(),
36865
36886
  noHostnameLookup: z.boolean().optional(),
36866
36887
  verbosity: z.enum(["verbose", "debug"]).optional(),
36888
+ required: z.boolean().optional(),
36867
36889
  signal: z.instanceof(AbortSignal).optional()
36868
36890
  }).strict();
36869
36891
  function resolveConfig(options) {
@@ -36962,13 +36984,19 @@ var DicomSender = class _DicomSender extends EventEmitter {
36962
36984
  if (files.length === 0) {
36963
36985
  return Promise.resolve(err(new Error("DicomSender: no files provided")));
36964
36986
  }
36965
- const params = {
36987
+ return this.dispatchSend(files, this.buildSendParams(options));
36988
+ }
36989
+ /** Builds SendParams from per-send options, applying instance defaults. */
36990
+ buildSendParams(options) {
36991
+ return {
36966
36992
  timeoutMs: options?.timeoutMs ?? this.defaultTimeoutMs,
36967
36993
  maxRetries: options?.maxRetries ?? this.defaultMaxRetries,
36968
36994
  calledAETitle: options?.calledAETitle,
36969
- callingAETitle: options?.callingAETitle
36995
+ callingAETitle: options?.callingAETitle,
36996
+ required: options?.required,
36997
+ proposedTransferSyntax: options?.proposedTransferSyntax,
36998
+ combineProposedTransferSyntaxes: options?.combineProposedTransferSyntaxes
36970
36999
  };
36971
- return this.dispatchSend(files, params);
36972
37000
  }
36973
37001
  /** Dispatches a send to the appropriate mode handler. */
36974
37002
  dispatchSend(files, params) {
@@ -37085,6 +37113,9 @@ var DicomSender = class _DicomSender extends EventEmitter {
37085
37113
  maxRetries: params.maxRetries,
37086
37114
  calledAETitle: params.calledAETitle,
37087
37115
  callingAETitle: params.callingAETitle,
37116
+ required: params.required,
37117
+ proposedTransferSyntax: params.proposedTransferSyntax,
37118
+ combineProposedTransferSyntaxes: params.combineProposedTransferSyntaxes,
37088
37119
  resolve
37089
37120
  };
37090
37121
  if (this.activeAssociations < this.effectiveMaxAssociations) {
@@ -37113,8 +37144,18 @@ var DicomSender = class _DicomSender extends EventEmitter {
37113
37144
  resolve(err(new Error("DicomSender: queue full")));
37114
37145
  return;
37115
37146
  }
37116
- const { timeoutMs, maxRetries, calledAETitle, callingAETitle } = params;
37117
- this.currentBucket.push({ files, resolve, timeoutMs, maxRetries, calledAETitle, callingAETitle });
37147
+ const { timeoutMs, maxRetries, calledAETitle, callingAETitle, required, proposedTransferSyntax, combineProposedTransferSyntaxes } = params;
37148
+ this.currentBucket.push({
37149
+ files,
37150
+ resolve,
37151
+ timeoutMs,
37152
+ maxRetries,
37153
+ calledAETitle,
37154
+ callingAETitle,
37155
+ required,
37156
+ proposedTransferSyntax,
37157
+ combineProposedTransferSyntaxes
37158
+ });
37118
37159
  const totalFiles = this.countBucketFiles();
37119
37160
  if (totalFiles >= this.maxBucketSize) {
37120
37161
  this.clearBucketTimer();
@@ -37132,36 +37173,41 @@ var DicomSender = class _DicomSender extends EventEmitter {
37132
37173
  }
37133
37174
  return count;
37134
37175
  }
37135
- /** Flushes the current bucket: combines all files, dispatches as one send. */
37136
- flushBucketInternal(reason) {
37137
- if (this.currentBucket.length === 0) return;
37138
- const entries = [...this.currentBucket];
37139
- this.currentBucket = [];
37176
+ /** Merges bucket entries into a single QueueEntry. */
37177
+ mergeBucketEntries(entries) {
37140
37178
  const allFiles = [];
37179
+ let timeoutMs = 0;
37180
+ let maxRetries = 0;
37141
37181
  for (let i = 0; i < entries.length; i++) {
37142
37182
  for (let j = 0; j < entries[i].files.length; j++) {
37143
37183
  allFiles.push(entries[i].files[j]);
37144
37184
  }
37145
- }
37146
- let timeoutMs = 0;
37147
- let maxRetries = 0;
37148
- for (let i = 0; i < entries.length; i++) {
37149
37185
  if (entries[i].timeoutMs > timeoutMs) timeoutMs = entries[i].timeoutMs;
37150
37186
  if (entries[i].maxRetries > maxRetries) maxRetries = entries[i].maxRetries;
37151
37187
  }
37152
- this.emit("BUCKET_FLUSHED", { fileCount: allFiles.length, reason });
37153
- const bucketEntry = {
37188
+ return {
37154
37189
  files: allFiles,
37155
37190
  timeoutMs,
37156
37191
  maxRetries,
37157
37192
  calledAETitle: entries[0]?.calledAETitle,
37158
37193
  callingAETitle: entries[0]?.callingAETitle,
37194
+ required: entries[0]?.required,
37195
+ proposedTransferSyntax: entries[0]?.proposedTransferSyntax,
37196
+ combineProposedTransferSyntaxes: entries[0]?.combineProposedTransferSyntaxes,
37159
37197
  resolve: (result) => {
37160
37198
  for (let i = 0; i < entries.length; i++) {
37161
37199
  entries[i].resolve(result);
37162
37200
  }
37163
37201
  }
37164
37202
  };
37203
+ }
37204
+ /** Flushes the current bucket: combines all files, dispatches as one send. */
37205
+ flushBucketInternal(reason) {
37206
+ if (this.currentBucket.length === 0) return;
37207
+ const entries = [...this.currentBucket];
37208
+ this.currentBucket = [];
37209
+ const bucketEntry = this.mergeBucketEntries(entries);
37210
+ this.emit("BUCKET_FLUSHED", { fileCount: bucketEntry.files.length, reason });
37165
37211
  if (this.activeAssociations < this.effectiveMaxAssociations) {
37166
37212
  void this.executeEntry(bucketEntry);
37167
37213
  } else {
@@ -37235,7 +37281,8 @@ var DicomSender = class _DicomSender extends EventEmitter {
37235
37281
  files: [...entry.files],
37236
37282
  calledAETitle: entry.calledAETitle ?? this.options.calledAETitle,
37237
37283
  callingAETitle: entry.callingAETitle ?? this.options.callingAETitle,
37238
- proposedTransferSyntax: this.options.proposedTransferSyntax,
37284
+ proposedTransferSyntax: entry.proposedTransferSyntax ?? this.options.proposedTransferSyntax,
37285
+ combineProposedTransferSyntaxes: entry.combineProposedTransferSyntaxes ?? this.options.combineProposedTransferSyntaxes,
37239
37286
  maxPduReceive: this.options.maxPduReceive,
37240
37287
  maxPduSend: this.options.maxPduSend,
37241
37288
  associationTimeout: this.options.associationTimeout,
@@ -37243,6 +37290,7 @@ var DicomSender = class _DicomSender extends EventEmitter {
37243
37290
  dimseTimeout: this.options.dimseTimeout,
37244
37291
  noHostnameLookup: this.options.noHostnameLookup,
37245
37292
  verbosity: this.options.verbosity,
37293
+ required: entry.required ?? this.options.required,
37246
37294
  timeoutMs: entry.timeoutMs,
37247
37295
  signal: this.options.signal
37248
37296
  });