dicom-curate 0.28.0 → 0.29.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.
@@ -79926,7 +79926,7 @@ async function curateOne({
79926
79926
  canSkip = previousSourceFileInfo.size === fileInfo.size && previousSourceFileInfo.mtime === mtime;
79927
79927
  }
79928
79928
  }
79929
- const noMapResult = (outputFilePath) => {
79929
+ const noMapResult = (outputFilePath, knownPostMappedHash) => {
79930
79930
  const retval = {
79931
79931
  sourceInstanceUID: `unchanged_${fileInfo.name.replace(/[^a-zA-Z0-9]/g, "_")}`,
79932
79932
  mappings: {},
@@ -79939,7 +79939,10 @@ async function curateOne({
79939
79939
  size: fileInfo.size,
79940
79940
  path: fileInfo.path,
79941
79941
  mtime: previousSourceFileInfo?.mtime,
79942
- preMappedHash
79942
+ preMappedHash,
79943
+ ...knownPostMappedHash !== void 0 && {
79944
+ postMappedHash: knownPostMappedHash
79945
+ }
79943
79946
  },
79944
79947
  // include curationTime even when skipped to measure hashing/check time
79945
79948
  curationTime: performance.now() - startTime,
@@ -80039,9 +80042,9 @@ async function curateOne({
80039
80042
  hashPartSize
80040
80043
  );
80041
80044
  fileArrayBuffer = null;
80042
- const previousPostMappedHash = previousMappedFileInfo ? previousMappedFileInfo(clonedMapResults.outputFilePath)?.postMappedHash : void 0;
80045
+ const previousPostMappedHash = previousMappedFileInfo ? (await previousMappedFileInfo(clonedMapResults.outputFilePath))?.postMappedHash : void 0;
80043
80046
  if (previousPostMappedHash !== void 0 && previousPostMappedHash === postMappedHash) {
80044
- return noMapResult(clonedMapResults.outputFilePath);
80047
+ return noMapResult(clonedMapResults.outputFilePath, postMappedHash);
80045
80048
  }
80046
80049
  if (typeof outputTarget?.directory === "object" && "getFileHandle" in outputTarget.directory) {
80047
80050
  const subDirectoryHandle = await createNestedDirectories(
@@ -80109,9 +80112,11 @@ async function curateOne({
80109
80112
  `Upload failed: ${resp.status} ${resp.statusText}`
80110
80113
  );
80111
80114
  } else {
80115
+ const etag = resp.headers.get("etag") ?? void 0;
80112
80116
  clonedMapResults.outputUpload = clonedMapResults.outputUpload ?? {
80113
80117
  url: uploadUrl,
80114
- status: resp.status
80118
+ status: resp.status,
80119
+ etag
80115
80120
  };
80116
80121
  }
80117
80122
  } catch (e4) {
@@ -80132,7 +80137,7 @@ async function curateOne({
80132
80137
  try {
80133
80138
  const prefix = outputTarget.s3.prefix ? outputTarget.s3.prefix.endsWith("/") ? outputTarget.s3.prefix : outputTarget.s3.prefix + "/" : "";
80134
80139
  const key = prefix + clonedMapResults.outputFilePath;
80135
- await client.send(
80140
+ const putResponse = await client.send(
80136
80141
  new s32.PutObjectCommand({
80137
80142
  Bucket: outputTarget.s3.bucketName,
80138
80143
  Key: key,
@@ -80151,7 +80156,8 @@ async function curateOne({
80151
80156
  const uploadUrl = `s3://${outputTarget.s3.bucketName}/${key}`;
80152
80157
  clonedMapResults.outputUpload = {
80153
80158
  url: uploadUrl,
80154
- status: 200
80159
+ status: 200,
80160
+ etag: putResponse.ETag ?? void 0
80155
80161
  };
80156
80162
  } catch (e4) {
80157
80163
  console.error("S3 Upload error", e4);
@@ -85792,9 +85798,6 @@ function deserializeMappingOptions(serializedMappingOptions) {
85792
85798
  return { ...rest, curationSpec };
85793
85799
  }
85794
85800
 
85795
- // src/types.ts
85796
- var OUTPUT_FILE_PREFIX = "output#";
85797
-
85798
85801
  // src/worker.ts
85799
85802
  var wt = null;
85800
85803
  async function initializeNodeWorker() {
@@ -85848,51 +85851,60 @@ function postErrorResponse(error2, fileInfo) {
85848
85851
  });
85849
85852
  }
85850
85853
  }
85851
- var postMappedFileInfo;
85854
+ var pendingLookupResolve = null;
85855
+ function lookupMappedFileInfo(outputPath) {
85856
+ return new Promise((resolve) => {
85857
+ pendingLookupResolve = resolve;
85858
+ globalThis.postMessage({
85859
+ response: "lookup",
85860
+ outputPath
85861
+ });
85862
+ });
85863
+ }
85852
85864
  fixupNodeWorkerEnvironment().then(() => {
85853
85865
  globalThis.addEventListener(
85854
85866
  "message",
85855
85867
  (event) => {
85856
- switch (event.data.request) {
85857
- case "fileInfoIndex": {
85858
- postMappedFileInfo = event.data.fileInfoIndex;
85859
- break;
85860
- }
85861
- case "apply": {
85862
- const { serializedMappingOptions } = event.data;
85863
- const mappingOptions = deserializeMappingOptions(
85864
- serializedMappingOptions
85865
- );
85866
- const fileInfo = event.data.fileInfo;
85867
- try {
85868
- curateOne({
85869
- fileInfo,
85870
- outputTarget: event.data.outputTarget ?? {},
85871
- hashMethod: event.data.hashMethod,
85872
- hashPartSize: event.data.hashPartSize,
85873
- mappingOptions,
85874
- previousSourceFileInfo: event.data.previousFileInfo,
85875
- previousMappedFileInfo: (targetName) => {
85876
- const hash2 = postMappedFileInfo?.[OUTPUT_FILE_PREFIX + targetName];
85877
- return hash2;
85878
- }
85879
- }).then((mapResults) => {
85880
- globalThis.postMessage({
85881
- response: "finished",
85882
- mapResults
85883
- });
85884
- }).catch((error2) => {
85885
- postErrorResponse(error2, fileInfo);
85886
- });
85887
- } catch (error2) {
85888
- postErrorResponse(error2, fileInfo);
85889
- }
85890
- break;
85868
+ if ("response" in event.data && event.data.response === "lookupResult") {
85869
+ const resolve = pendingLookupResolve;
85870
+ pendingLookupResolve = null;
85871
+ if (resolve) {
85872
+ const hash2 = event.data.postMappedHash;
85873
+ resolve(hash2 ? { postMappedHash: hash2 } : void 0);
85891
85874
  }
85892
- default:
85893
- console.error(
85894
- `Unknown request ${event.data.request}`
85895
- );
85875
+ return;
85876
+ }
85877
+ const data10 = event.data;
85878
+ if (data10.request !== "apply") {
85879
+ console.error(
85880
+ `Unknown request ${data10.request}`
85881
+ );
85882
+ return;
85883
+ }
85884
+ const { serializedMappingOptions } = data10;
85885
+ const mappingOptions = deserializeMappingOptions(
85886
+ serializedMappingOptions
85887
+ );
85888
+ const fileInfo = data10.fileInfo;
85889
+ try {
85890
+ curateOne({
85891
+ fileInfo,
85892
+ outputTarget: data10.outputTarget ?? {},
85893
+ hashMethod: data10.hashMethod,
85894
+ hashPartSize: data10.hashPartSize,
85895
+ mappingOptions,
85896
+ previousSourceFileInfo: data10.previousFileInfo,
85897
+ previousMappedFileInfo: lookupMappedFileInfo
85898
+ }).then((mapResults) => {
85899
+ globalThis.postMessage({
85900
+ response: "finished",
85901
+ mapResults
85902
+ });
85903
+ }).catch((error2) => {
85904
+ postErrorResponse(error2, fileInfo);
85905
+ });
85906
+ } catch (error2) {
85907
+ postErrorResponse(error2, fileInfo);
85896
85908
  }
85897
85909
  }
85898
85910
  );
@@ -73635,7 +73635,7 @@ async function curateOne({
73635
73635
  canSkip = previousSourceFileInfo.size === fileInfo.size && previousSourceFileInfo.mtime === mtime;
73636
73636
  }
73637
73637
  }
73638
- const noMapResult = (outputFilePath) => {
73638
+ const noMapResult = (outputFilePath, knownPostMappedHash) => {
73639
73639
  const retval = {
73640
73640
  sourceInstanceUID: `unchanged_${fileInfo.name.replace(/[^a-zA-Z0-9]/g, "_")}`,
73641
73641
  mappings: {},
@@ -73648,7 +73648,10 @@ async function curateOne({
73648
73648
  size: fileInfo.size,
73649
73649
  path: fileInfo.path,
73650
73650
  mtime: previousSourceFileInfo?.mtime,
73651
- preMappedHash
73651
+ preMappedHash,
73652
+ ...knownPostMappedHash !== void 0 && {
73653
+ postMappedHash: knownPostMappedHash
73654
+ }
73652
73655
  },
73653
73656
  // include curationTime even when skipped to measure hashing/check time
73654
73657
  curationTime: performance.now() - startTime,
@@ -73748,9 +73751,9 @@ async function curateOne({
73748
73751
  hashPartSize
73749
73752
  );
73750
73753
  fileArrayBuffer = null;
73751
- const previousPostMappedHash = previousMappedFileInfo ? previousMappedFileInfo(clonedMapResults.outputFilePath)?.postMappedHash : void 0;
73754
+ const previousPostMappedHash = previousMappedFileInfo ? (await previousMappedFileInfo(clonedMapResults.outputFilePath))?.postMappedHash : void 0;
73752
73755
  if (previousPostMappedHash !== void 0 && previousPostMappedHash === postMappedHash) {
73753
- return noMapResult(clonedMapResults.outputFilePath);
73756
+ return noMapResult(clonedMapResults.outputFilePath, postMappedHash);
73754
73757
  }
73755
73758
  if (typeof outputTarget?.directory === "object" && "getFileHandle" in outputTarget.directory) {
73756
73759
  const subDirectoryHandle = await createNestedDirectories(
@@ -73818,9 +73821,11 @@ async function curateOne({
73818
73821
  `Upload failed: ${resp.status} ${resp.statusText}`
73819
73822
  );
73820
73823
  } else {
73824
+ const etag = resp.headers.get("etag") ?? void 0;
73821
73825
  clonedMapResults.outputUpload = clonedMapResults.outputUpload ?? {
73822
73826
  url: uploadUrl,
73823
- status: resp.status
73827
+ status: resp.status,
73828
+ etag
73824
73829
  };
73825
73830
  }
73826
73831
  } catch (e4) {
@@ -73841,7 +73846,7 @@ async function curateOne({
73841
73846
  try {
73842
73847
  const prefix = outputTarget.s3.prefix ? outputTarget.s3.prefix.endsWith("/") ? outputTarget.s3.prefix : outputTarget.s3.prefix + "/" : "";
73843
73848
  const key = prefix + clonedMapResults.outputFilePath;
73844
- await client.send(
73849
+ const putResponse = await client.send(
73845
73850
  new s32.PutObjectCommand({
73846
73851
  Bucket: outputTarget.s3.bucketName,
73847
73852
  Key: key,
@@ -73860,7 +73865,8 @@ async function curateOne({
73860
73865
  const uploadUrl = `s3://${outputTarget.s3.bucketName}/${key}`;
73861
73866
  clonedMapResults.outputUpload = {
73862
73867
  url: uploadUrl,
73863
- status: 200
73868
+ status: 200,
73869
+ etag: putResponse.ETag ?? void 0
73864
73870
  };
73865
73871
  } catch (e4) {
73866
73872
  console.error("S3 Upload error", e4);
package/dist/esm/index.js CHANGED
@@ -81486,7 +81486,7 @@ async function curateOne({
81486
81486
  canSkip = previousSourceFileInfo.size === fileInfo.size && previousSourceFileInfo.mtime === mtime;
81487
81487
  }
81488
81488
  }
81489
- const noMapResult = (outputFilePath) => {
81489
+ const noMapResult = (outputFilePath, knownPostMappedHash) => {
81490
81490
  const retval = {
81491
81491
  sourceInstanceUID: `unchanged_${fileInfo.name.replace(/[^a-zA-Z0-9]/g, "_")}`,
81492
81492
  mappings: {},
@@ -81499,7 +81499,10 @@ async function curateOne({
81499
81499
  size: fileInfo.size,
81500
81500
  path: fileInfo.path,
81501
81501
  mtime: previousSourceFileInfo?.mtime,
81502
- preMappedHash
81502
+ preMappedHash,
81503
+ ...knownPostMappedHash !== void 0 && {
81504
+ postMappedHash: knownPostMappedHash
81505
+ }
81503
81506
  },
81504
81507
  // include curationTime even when skipped to measure hashing/check time
81505
81508
  curationTime: performance.now() - startTime,
@@ -81599,9 +81602,9 @@ async function curateOne({
81599
81602
  hashPartSize
81600
81603
  );
81601
81604
  fileArrayBuffer = null;
81602
- const previousPostMappedHash = previousMappedFileInfo ? previousMappedFileInfo(clonedMapResults.outputFilePath)?.postMappedHash : void 0;
81605
+ const previousPostMappedHash = previousMappedFileInfo ? (await previousMappedFileInfo(clonedMapResults.outputFilePath))?.postMappedHash : void 0;
81603
81606
  if (previousPostMappedHash !== void 0 && previousPostMappedHash === postMappedHash) {
81604
- return noMapResult(clonedMapResults.outputFilePath);
81607
+ return noMapResult(clonedMapResults.outputFilePath, postMappedHash);
81605
81608
  }
81606
81609
  if (typeof outputTarget?.directory === "object" && "getFileHandle" in outputTarget.directory) {
81607
81610
  const subDirectoryHandle = await createNestedDirectories(
@@ -81669,9 +81672,11 @@ async function curateOne({
81669
81672
  `Upload failed: ${resp.status} ${resp.statusText}`
81670
81673
  );
81671
81674
  } else {
81675
+ const etag = resp.headers.get("etag") ?? void 0;
81672
81676
  clonedMapResults.outputUpload = clonedMapResults.outputUpload ?? {
81673
81677
  url: uploadUrl,
81674
- status: resp.status
81678
+ status: resp.status,
81679
+ etag
81675
81680
  };
81676
81681
  }
81677
81682
  } catch (e4) {
@@ -81692,7 +81697,7 @@ async function curateOne({
81692
81697
  try {
81693
81698
  const prefix = outputTarget.s3.prefix ? outputTarget.s3.prefix.endsWith("/") ? outputTarget.s3.prefix : outputTarget.s3.prefix + "/" : "";
81694
81699
  const key = prefix + clonedMapResults.outputFilePath;
81695
- await client.send(
81700
+ const putResponse = await client.send(
81696
81701
  new s32.PutObjectCommand({
81697
81702
  Bucket: outputTarget.s3.bucketName,
81698
81703
  Key: key,
@@ -81711,7 +81716,8 @@ async function curateOne({
81711
81716
  const uploadUrl = `s3://${outputTarget.s3.bucketName}/${key}`;
81712
81717
  clonedMapResults.outputUpload = {
81713
81718
  url: uploadUrl,
81714
- status: 200
81719
+ status: 200,
81720
+ etag: putResponse.ETag ?? void 0
81715
81721
  };
81716
81722
  } catch (e4) {
81717
81723
  console.error("S3 Upload error", e4);
@@ -87465,6 +87471,9 @@ async function getHttpOutputHeaders(outputTarget) {
87465
87471
  return outputTarget;
87466
87472
  }
87467
87473
 
87474
+ // src/types.ts
87475
+ var OUTPUT_FILE_PREFIX = "output#";
87476
+
87468
87477
  // src/mappingWorkerPool.ts
87469
87478
  var mappingWorkerOptions = {};
87470
87479
  var availableMappingWorkers = [];
@@ -87512,10 +87521,7 @@ async function initializeMappingWorkers(skipCollectingMappings, fileInfoIndex, p
87512
87521
  progressCallback = progressCb;
87513
87522
  const effectiveWorkerCount = workerCount ?? Math.min(await getHardwareConcurrency(), 8);
87514
87523
  const workers = await Promise.all(
87515
- Array.from(
87516
- { length: effectiveWorkerCount },
87517
- () => createMappingWorker(fileInfoIndex)
87518
- )
87524
+ Array.from({ length: effectiveWorkerCount }, () => createMappingWorker())
87519
87525
  );
87520
87526
  availableMappingWorkers.push(...workers);
87521
87527
  }
@@ -87615,7 +87621,7 @@ function recoverCrashedWorker(mappingWorker, errorMessage) {
87615
87621
  });
87616
87622
  dispatchMappingJobs();
87617
87623
  pendingReplacements += 1;
87618
- void createMappingWorker(currentFileInfoIndex).then((worker) => {
87624
+ void createMappingWorker().then((worker) => {
87619
87625
  pendingReplacements -= 1;
87620
87626
  availableMappingWorkers.push(worker);
87621
87627
  dispatchMappingJobs();
@@ -87625,7 +87631,7 @@ function recoverCrashedWorker(mappingWorker, errorMessage) {
87625
87631
  dispatchMappingJobs();
87626
87632
  });
87627
87633
  }
87628
- async function createMappingWorker(fileInfoIndex) {
87634
+ async function createMappingWorker() {
87629
87635
  const mappingWorker = await createWorker(
87630
87636
  new URL("./applyMappingsWorker.js", import.meta.url),
87631
87637
  { type: "module" }
@@ -87645,18 +87651,16 @@ async function createMappingWorker(fileInfoIndex) {
87645
87651
  }
87646
87652
  });
87647
87653
  }
87648
- if (fileInfoIndex !== void 0) {
87649
- const postMappedOnly = Object.fromEntries(
87650
- Object.entries(fileInfoIndex).filter(
87651
- ([_key, value]) => !!value.postMappedHash
87652
- )
87653
- );
87654
- mappingWorker.postMessage({
87655
- request: "fileInfoIndex",
87656
- fileInfoIndex: postMappedOnly
87657
- });
87658
- }
87659
87654
  mappingWorker.addEventListener("message", (event) => {
87655
+ if (event.data.response === "lookup") {
87656
+ const outputPath = event.data.outputPath;
87657
+ const entry = currentFileInfoIndex?.[OUTPUT_FILE_PREFIX + outputPath];
87658
+ mappingWorker.postMessage({
87659
+ response: "lookupResult",
87660
+ postMappedHash: entry?.postMappedHash
87661
+ });
87662
+ return;
87663
+ }
87660
87664
  lastWorkerProgressTime = Date.now();
87661
87665
  workerCurrentFile.delete(mappingWorker);
87662
87666
  switch (event.data.response) {
@@ -87715,9 +87719,6 @@ function getLastWorkerProgressTime() {
87715
87719
  return lastWorkerProgressTime;
87716
87720
  }
87717
87721
 
87718
- // src/types.ts
87719
- var OUTPUT_FILE_PREFIX = "output#";
87720
-
87721
87722
  // src/index.ts
87722
87723
  function requiresDateOffset(deIdOpts) {
87723
87724
  return deIdOpts !== "Off" && deIdOpts.retainLongitudinalTemporalInformationOptions === "Offset";
@@ -12043,6 +12043,9 @@ function dataURLToBlobURL(dataURL) {
12043
12043
  return URL.createObjectURL(blob);
12044
12044
  }
12045
12045
 
12046
+ // src/types.ts
12047
+ var OUTPUT_FILE_PREFIX = "output#";
12048
+
12046
12049
  // src/mappingWorkerPool.ts
12047
12050
  var mappingWorkerOptions = {};
12048
12051
  var availableMappingWorkers = [];
@@ -12090,10 +12093,7 @@ async function initializeMappingWorkers(skipCollectingMappings, fileInfoIndex, p
12090
12093
  progressCallback = progressCb;
12091
12094
  const effectiveWorkerCount = workerCount ?? Math.min(await getHardwareConcurrency(), 8);
12092
12095
  const workers = await Promise.all(
12093
- Array.from(
12094
- { length: effectiveWorkerCount },
12095
- () => createMappingWorker(fileInfoIndex)
12096
- )
12096
+ Array.from({ length: effectiveWorkerCount }, () => createMappingWorker())
12097
12097
  );
12098
12098
  availableMappingWorkers.push(...workers);
12099
12099
  }
@@ -12193,7 +12193,7 @@ function recoverCrashedWorker(mappingWorker, errorMessage) {
12193
12193
  });
12194
12194
  dispatchMappingJobs();
12195
12195
  pendingReplacements += 1;
12196
- void createMappingWorker(currentFileInfoIndex).then((worker) => {
12196
+ void createMappingWorker().then((worker) => {
12197
12197
  pendingReplacements -= 1;
12198
12198
  availableMappingWorkers.push(worker);
12199
12199
  dispatchMappingJobs();
@@ -12203,7 +12203,7 @@ function recoverCrashedWorker(mappingWorker, errorMessage) {
12203
12203
  dispatchMappingJobs();
12204
12204
  });
12205
12205
  }
12206
- async function createMappingWorker(fileInfoIndex) {
12206
+ async function createMappingWorker() {
12207
12207
  const mappingWorker = await createWorker(
12208
12208
  new URL("./applyMappingsWorker.js", import.meta.url),
12209
12209
  { type: "module" }
@@ -12223,18 +12223,16 @@ async function createMappingWorker(fileInfoIndex) {
12223
12223
  }
12224
12224
  });
12225
12225
  }
12226
- if (fileInfoIndex !== void 0) {
12227
- const postMappedOnly = Object.fromEntries(
12228
- Object.entries(fileInfoIndex).filter(
12229
- ([_key, value]) => !!value.postMappedHash
12230
- )
12231
- );
12232
- mappingWorker.postMessage({
12233
- request: "fileInfoIndex",
12234
- fileInfoIndex: postMappedOnly
12235
- });
12236
- }
12237
12226
  mappingWorker.addEventListener("message", (event) => {
12227
+ if (event.data.response === "lookup") {
12228
+ const outputPath = event.data.outputPath;
12229
+ const entry = currentFileInfoIndex?.[OUTPUT_FILE_PREFIX + outputPath];
12230
+ mappingWorker.postMessage({
12231
+ response: "lookupResult",
12232
+ postMappedHash: entry?.postMappedHash
12233
+ });
12234
+ return;
12235
+ }
12238
12236
  lastWorkerProgressTime = Date.now();
12239
12237
  workerCurrentFile.delete(mappingWorker);
12240
12238
  switch (event.data.response) {
@@ -1,4 +1,4 @@
1
- import { type TFileInfo, type TFileInfoIndex, type THashMethod, type TOutputTarget, type TSerializedMappingOptions } from './types';
1
+ import { type TFileInfo, type THashMethod, type TOutputTarget, type TSerializedMappingOptions } from './types';
2
2
  export type MappingRequest = {
3
3
  request: 'apply';
4
4
  fileInfo: TFileInfo;
@@ -11,7 +11,9 @@ export type MappingRequest = {
11
11
  hashMethod?: THashMethod;
12
12
  hashPartSize?: number;
13
13
  serializedMappingOptions: TSerializedMappingOptions;
14
- } | {
15
- request: 'fileInfoIndex';
16
- fileInfoIndex?: TFileInfoIndex;
14
+ };
15
+ /** Response sent back from the main thread for a fileInfoIndex lookup. */
16
+ export type LookupResponse = {
17
+ response: 'lookupResult';
18
+ postMappedHash?: string;
17
19
  };
@@ -10,9 +10,9 @@ export type TCurateOneArgs = {
10
10
  mtime?: string;
11
11
  preMappedHash?: string;
12
12
  };
13
- previousMappedFileInfo?: (mappedFileName: string) => {
13
+ previousMappedFileInfo?: (mappedFileName: string) => Promise<{
14
14
  postMappedHash?: string;
15
- } | undefined;
15
+ } | undefined>;
16
16
  };
17
17
  export declare function curateOne({ fileInfo, outputTarget, mappingOptions, hashMethod, hashPartSize, previousSourceFileInfo, previousMappedFileInfo, }: TCurateOneArgs): Promise<Omit<Partial<TMapResults>, 'anomalies'> & {
18
18
  anomalies: TMapResults['anomalies'];
@@ -141,6 +141,7 @@ export type TMapResults = {
141
141
  outputUpload?: {
142
142
  url: string;
143
143
  status: number;
144
+ etag?: string;
144
145
  };
145
146
  mappingRequired?: boolean;
146
147
  curationTime?: number;