dicom-curate 0.26.1 → 0.27.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/dist/esm/applyMappingsWorker.js +56 -30
- package/dist/esm/collectMappings.js +3 -3
- package/dist/esm/config/dicom/tagConversion.js +1 -1
- package/dist/esm/config/sampleCompositeSpecification.js +1 -1
- package/dist/esm/curateDict.js +3 -3
- package/dist/esm/curateOne.js +56 -30
- package/dist/esm/deidentifyPS315E.js +3 -3
- package/dist/esm/fetchWithRetry.js +26 -0
- package/dist/esm/hash.js +1 -1
- package/dist/esm/index.js +93 -34
- package/dist/esm/mappingWorkerPool.js +30 -4
- package/dist/esm/s3Client.js +1 -1
- package/dist/esm/scanDirectoryWorker.js +37 -3
- package/dist/types/fetchWithRetry.d.ts +12 -0
- package/dist/types/mappingWorkerPool.d.ts +11 -1
- package/dist/types/scanDirectoryWorker.d.ts +2 -0
- package/dist/types/types.d.ts +1 -0
- package/dist/umd/dicom-curate.umd.js +265 -76
- package/dist/umd/dicom-curate.umd.js.map +1 -1
- package/dist/umd/dicom-curate.umd.min.js +7 -7
- package/dist/umd/dicom-curate.umd.min.js.map +1 -1
- package/package.json +1 -1
|
@@ -77997,7 +77997,7 @@ function isPrivateTag(tagId) {
|
|
|
77997
77997
|
return false;
|
|
77998
77998
|
}
|
|
77999
77999
|
function convertKeywordToTagId(keyword) {
|
|
78000
|
-
const tagId = isPrivateTag(keyword) ? keyword : dcmjs.data.DicomMetaDictionary.nameMap[keyword]?.tag
|
|
78000
|
+
const tagId = isPrivateTag(keyword) ? keyword : dcmjs.data.DicomMetaDictionary.nameMap[keyword]?.tag ?? keyword;
|
|
78001
78001
|
return tagId.replace(/[(),]/g, "").toLowerCase();
|
|
78002
78002
|
}
|
|
78003
78003
|
function convertKeywordPathToTagIdPath(keywordPath) {
|
|
@@ -78856,7 +78856,7 @@ function getCid7050Codes(options) {
|
|
|
78856
78856
|
var import_lodash = __toESM(require_lodash(), 1);
|
|
78857
78857
|
var nameMap = dcmjs2.data.DicomMetaDictionary.nameMap;
|
|
78858
78858
|
function getVr(keyword) {
|
|
78859
|
-
const element = nameMap[keyword]
|
|
78859
|
+
const element = nameMap[keyword] ?? nameMap[`RETIRED_${keyword}`];
|
|
78860
78860
|
return element?.vr;
|
|
78861
78861
|
}
|
|
78862
78862
|
function temporalVr(vr) {
|
|
@@ -78928,7 +78928,7 @@ function deidentifyPS315E({
|
|
|
78928
78928
|
}
|
|
78929
78929
|
}
|
|
78930
78930
|
}
|
|
78931
|
-
return current2[tagName]
|
|
78931
|
+
return current2[tagName] ?? null;
|
|
78932
78932
|
}
|
|
78933
78933
|
const {
|
|
78934
78934
|
cleanDescriptorsOption,
|
|
@@ -79661,6 +79661,30 @@ function curateDict(inputFilePath, dicomData, mappingOptions) {
|
|
|
79661
79661
|
return { dicomData: mappedDicomData, mapResults: (0, import_lodash4.cloneDeep)(mapResults) };
|
|
79662
79662
|
}
|
|
79663
79663
|
|
|
79664
|
+
// src/fetchWithRetry.ts
|
|
79665
|
+
var MAX_ATTEMPTS = 5;
|
|
79666
|
+
var BASE_DELAY_MS = 1e3;
|
|
79667
|
+
var BACKOFF_MULTIPLIER = 3;
|
|
79668
|
+
async function fetchWithRetry(...args) {
|
|
79669
|
+
for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
|
|
79670
|
+
try {
|
|
79671
|
+
return await fetch(...args);
|
|
79672
|
+
} catch (error2) {
|
|
79673
|
+
const isNetworkError = error2 instanceof TypeError;
|
|
79674
|
+
const isLastAttempt = attempt === MAX_ATTEMPTS;
|
|
79675
|
+
if (!isNetworkError || isLastAttempt) {
|
|
79676
|
+
throw error2;
|
|
79677
|
+
}
|
|
79678
|
+
const delayMs = BASE_DELAY_MS * BACKOFF_MULTIPLIER ** (attempt - 1);
|
|
79679
|
+
console.warn(
|
|
79680
|
+
`fetch attempt ${attempt}/${MAX_ATTEMPTS} failed: ${error2.message}. Retrying in ${delayMs}ms...`
|
|
79681
|
+
);
|
|
79682
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
79683
|
+
}
|
|
79684
|
+
}
|
|
79685
|
+
throw new Error("fetchWithRetry: unreachable");
|
|
79686
|
+
}
|
|
79687
|
+
|
|
79664
79688
|
// src/hash.ts
|
|
79665
79689
|
var import_md5 = __toESM(require_md5(), 1);
|
|
79666
79690
|
var import_js_crc = __toESM(require_crc(), 1);
|
|
@@ -79671,9 +79695,9 @@ async function hash(buffer, hashMethod) {
|
|
|
79671
79695
|
case "crc32":
|
|
79672
79696
|
return crc32Hex(buffer);
|
|
79673
79697
|
case "md5":
|
|
79698
|
+
default:
|
|
79674
79699
|
return md5Hex(buffer);
|
|
79675
79700
|
case "crc64":
|
|
79676
|
-
default:
|
|
79677
79701
|
return crc64Hex(buffer);
|
|
79678
79702
|
}
|
|
79679
79703
|
}
|
|
@@ -79748,7 +79772,7 @@ async function loadS3Client() {
|
|
|
79748
79772
|
const { createRequire } = await import("module");
|
|
79749
79773
|
const req = createRequire(import.meta.url);
|
|
79750
79774
|
const mod = req("@aws-sdk/client-s3");
|
|
79751
|
-
cachedS3Client = mod?.default
|
|
79775
|
+
cachedS3Client = mod?.default ?? mod;
|
|
79752
79776
|
} else {
|
|
79753
79777
|
cachedS3Client = await Promise.resolve().then(() => __toESM(require_dist_cjs71(), 1));
|
|
79754
79778
|
}
|
|
@@ -79787,7 +79811,7 @@ async function curateOne({
|
|
|
79787
79811
|
);
|
|
79788
79812
|
}
|
|
79789
79813
|
file = await resp.blob();
|
|
79790
|
-
const lastModifiedHeader = resp.headers.get("last-modified")
|
|
79814
|
+
const lastModifiedHeader = resp.headers.get("last-modified");
|
|
79791
79815
|
if (lastModifiedHeader) {
|
|
79792
79816
|
mtime = new Date(lastModifiedHeader).toISOString();
|
|
79793
79817
|
}
|
|
@@ -79853,14 +79877,14 @@ async function curateOne({
|
|
|
79853
79877
|
} catch (e4) {
|
|
79854
79878
|
}
|
|
79855
79879
|
}
|
|
79856
|
-
|
|
79880
|
+
let fileArrayBuffer = await file.arrayBuffer();
|
|
79857
79881
|
let preMappedHash;
|
|
79858
79882
|
let postMappedHash;
|
|
79859
79883
|
const postMappedHashHeader = "x-source-file-hash";
|
|
79860
79884
|
let canSkip = false;
|
|
79861
79885
|
if (previousSourceFileInfo?.preMappedHash !== void 0) {
|
|
79862
79886
|
try {
|
|
79863
|
-
preMappedHash = await hash(fileArrayBuffer, hashMethod
|
|
79887
|
+
preMappedHash = await hash(fileArrayBuffer, hashMethod ?? "md5");
|
|
79864
79888
|
} catch (e4) {
|
|
79865
79889
|
console.warn(`Failed to compute preMappedHash for ${fileInfo.name}`, e4);
|
|
79866
79890
|
}
|
|
@@ -79965,7 +79989,7 @@ async function curateOne({
|
|
|
79965
79989
|
}
|
|
79966
79990
|
if (!preMappedHash) {
|
|
79967
79991
|
try {
|
|
79968
|
-
preMappedHash = await hash(fileArrayBuffer, hashMethod
|
|
79992
|
+
preMappedHash = await hash(fileArrayBuffer, hashMethod ?? "md5");
|
|
79969
79993
|
} catch (e4) {
|
|
79970
79994
|
console.warn(`Failed to compute preMappedHash for ${fileInfo.name}`, e4);
|
|
79971
79995
|
}
|
|
@@ -79976,7 +80000,8 @@ async function curateOne({
|
|
|
79976
80000
|
const modifiedArrayBuffer = mappedDicomData.write({
|
|
79977
80001
|
allowInvalidVRLength: true
|
|
79978
80002
|
});
|
|
79979
|
-
postMappedHash = await hash(modifiedArrayBuffer, hashMethod
|
|
80003
|
+
postMappedHash = await hash(modifiedArrayBuffer, hashMethod ?? "md5");
|
|
80004
|
+
fileArrayBuffer = null;
|
|
79980
80005
|
const previousPostMappedHash = previousMappedFileInfo ? previousMappedFileInfo(clonedMapResults.outputFilePath)?.postMappedHash : void 0;
|
|
79981
80006
|
if (previousPostMappedHash !== void 0 && previousPostMappedHash === postMappedHash) {
|
|
79982
80007
|
return noMapResult(clonedMapResults.outputFilePath);
|
|
@@ -80008,54 +80033,53 @@ async function curateOne({
|
|
|
80008
80033
|
}
|
|
80009
80034
|
const fullFilePath = path.join(fullDirPath, fileName);
|
|
80010
80035
|
await fs.writeFile(fullFilePath, new DataView(modifiedArrayBuffer));
|
|
80011
|
-
} else {
|
|
80036
|
+
} else if (!outputTarget?.http && !outputTarget?.s3) {
|
|
80012
80037
|
clonedMapResults.mappedBlob = new Blob([modifiedArrayBuffer], {
|
|
80013
80038
|
type: "application/octet-stream"
|
|
80014
80039
|
});
|
|
80015
80040
|
}
|
|
80016
|
-
clonedMapResults.mappedBlob = new Blob([modifiedArrayBuffer], {
|
|
80017
|
-
type: "application/octet-stream"
|
|
80018
|
-
});
|
|
80019
80041
|
if (outputTarget?.http) {
|
|
80020
80042
|
try {
|
|
80021
80043
|
const key = clonedMapResults.outputFilePath.split("/").map(encodeURIComponent).join("/");
|
|
80022
80044
|
const uploadUrl = `${outputTarget.http.url}/${key}`;
|
|
80023
80045
|
const headers = {
|
|
80024
|
-
"Content-Type":
|
|
80046
|
+
"Content-Type": "application/octet-stream",
|
|
80025
80047
|
"X-File-Name": fileName,
|
|
80026
|
-
"X-File-Type":
|
|
80048
|
+
"X-File-Type": "application/octet-stream",
|
|
80027
80049
|
"X-File-Size": String(modifiedArrayBuffer.byteLength),
|
|
80028
|
-
"X-Source-File-Size": String(clonedMapResults.fileInfo?.size
|
|
80029
|
-
"X-Source-File-Modified-Time": mtime
|
|
80030
|
-
"X-Source-File-Hash": preMappedHash
|
|
80050
|
+
"X-Source-File-Size": String(clonedMapResults.fileInfo?.size ?? ""),
|
|
80051
|
+
"X-Source-File-Modified-Time": mtime ?? "",
|
|
80052
|
+
"X-Source-File-Hash": preMappedHash ?? ""
|
|
80031
80053
|
};
|
|
80032
80054
|
if (outputTarget.http.headers) {
|
|
80033
80055
|
Object.assign(headers, outputTarget.http.headers);
|
|
80034
80056
|
}
|
|
80035
80057
|
if (postMappedHashHeader && postMappedHash)
|
|
80036
80058
|
headers[postMappedHashHeader] = postMappedHash;
|
|
80037
|
-
const resp = await
|
|
80059
|
+
const resp = await fetchWithRetry(uploadUrl, {
|
|
80038
80060
|
method: "PUT",
|
|
80039
80061
|
headers,
|
|
80040
|
-
body:
|
|
80062
|
+
body: new Blob([modifiedArrayBuffer], {
|
|
80063
|
+
type: "application/octet-stream"
|
|
80064
|
+
})
|
|
80041
80065
|
});
|
|
80042
80066
|
if (!resp.ok) {
|
|
80043
80067
|
console.error(
|
|
80044
80068
|
`Upload failed for ${uploadUrl}: ${resp.status} ${resp.statusText}`
|
|
80045
80069
|
);
|
|
80046
|
-
clonedMapResults.errors = clonedMapResults.errors
|
|
80070
|
+
clonedMapResults.errors = clonedMapResults.errors ?? [];
|
|
80047
80071
|
clonedMapResults.errors.push(
|
|
80048
80072
|
`Upload failed: ${resp.status} ${resp.statusText}`
|
|
80049
80073
|
);
|
|
80050
80074
|
} else {
|
|
80051
|
-
clonedMapResults.outputUpload = clonedMapResults.outputUpload
|
|
80075
|
+
clonedMapResults.outputUpload = clonedMapResults.outputUpload ?? {
|
|
80052
80076
|
url: uploadUrl,
|
|
80053
80077
|
status: resp.status
|
|
80054
80078
|
};
|
|
80055
80079
|
}
|
|
80056
80080
|
} catch (e4) {
|
|
80057
80081
|
console.error("Upload error", e4);
|
|
80058
|
-
clonedMapResults.errors = clonedMapResults.errors
|
|
80082
|
+
clonedMapResults.errors = clonedMapResults.errors ?? [];
|
|
80059
80083
|
clonedMapResults.errors.push(
|
|
80060
80084
|
`Upload error: ${e4 instanceof Error ? e4.message : String(e4)}`
|
|
80061
80085
|
);
|
|
@@ -80075,12 +80099,14 @@ async function curateOne({
|
|
|
80075
80099
|
new s32.PutObjectCommand({
|
|
80076
80100
|
Bucket: outputTarget.s3.bucketName,
|
|
80077
80101
|
Key: key,
|
|
80078
|
-
|
|
80079
|
-
|
|
80102
|
+
// Use the ArrayBuffer directly — going through Blob.arrayBuffer()
|
|
80103
|
+
// would create yet another copy of the data in memory.
|
|
80104
|
+
Body: new Uint8Array(modifiedArrayBuffer),
|
|
80105
|
+
ContentType: "application/octet-stream",
|
|
80080
80106
|
Metadata: {
|
|
80081
|
-
"source-file-size": String(clonedMapResults.fileInfo?.size
|
|
80082
|
-
"source-file-modified-time": mtime
|
|
80083
|
-
"source-file-hash": preMappedHash
|
|
80107
|
+
"source-file-size": String(clonedMapResults.fileInfo?.size ?? ""),
|
|
80108
|
+
"source-file-modified-time": mtime ?? "",
|
|
80109
|
+
"source-file-hash": preMappedHash ?? "",
|
|
80084
80110
|
...postMappedHash ? { "source-file-post-mapped-hash": postMappedHash } : {}
|
|
80085
80111
|
}
|
|
80086
80112
|
})
|
|
@@ -80092,7 +80118,7 @@ async function curateOne({
|
|
|
80092
80118
|
};
|
|
80093
80119
|
} catch (e4) {
|
|
80094
80120
|
console.error("S3 Upload error", e4);
|
|
80095
|
-
clonedMapResults.errors = clonedMapResults.errors
|
|
80121
|
+
clonedMapResults.errors = clonedMapResults.errors ?? [];
|
|
80096
80122
|
clonedMapResults.errors.push(
|
|
80097
80123
|
`S3 Upload error: ${e4 instanceof Error ? e4.message : String(e4)}`
|
|
80098
80124
|
);
|
|
@@ -34005,7 +34005,7 @@ function isPrivateTag(tagId) {
|
|
|
34005
34005
|
return false;
|
|
34006
34006
|
}
|
|
34007
34007
|
function convertKeywordToTagId(keyword) {
|
|
34008
|
-
const tagId = isPrivateTag(keyword) ? keyword : dcmjs.data.DicomMetaDictionary.nameMap[keyword]?.tag
|
|
34008
|
+
const tagId = isPrivateTag(keyword) ? keyword : dcmjs.data.DicomMetaDictionary.nameMap[keyword]?.tag ?? keyword;
|
|
34009
34009
|
return tagId.replace(/[(),]/g, "").toLowerCase();
|
|
34010
34010
|
}
|
|
34011
34011
|
|
|
@@ -34850,7 +34850,7 @@ function getCid7050Codes(options) {
|
|
|
34850
34850
|
var import_lodash = __toESM(require_lodash(), 1);
|
|
34851
34851
|
var nameMap = dcmjs2.data.DicomMetaDictionary.nameMap;
|
|
34852
34852
|
function getVr(keyword) {
|
|
34853
|
-
const element = nameMap[keyword]
|
|
34853
|
+
const element = nameMap[keyword] ?? nameMap[`RETIRED_${keyword}`];
|
|
34854
34854
|
return element?.vr;
|
|
34855
34855
|
}
|
|
34856
34856
|
function temporalVr(vr) {
|
|
@@ -34922,7 +34922,7 @@ function deidentifyPS315E({
|
|
|
34922
34922
|
}
|
|
34923
34923
|
}
|
|
34924
34924
|
}
|
|
34925
|
-
return current[tagName]
|
|
34925
|
+
return current[tagName] ?? null;
|
|
34926
34926
|
}
|
|
34927
34927
|
const {
|
|
34928
34928
|
cleanDescriptorsOption,
|
|
@@ -17966,7 +17966,7 @@ function isPrivateTag(tagId) {
|
|
|
17966
17966
|
return false;
|
|
17967
17967
|
}
|
|
17968
17968
|
function convertKeywordToTagId(keyword) {
|
|
17969
|
-
const tagId = isPrivateTag(keyword) ? keyword : dcmjs.data.DicomMetaDictionary.nameMap[keyword]?.tag
|
|
17969
|
+
const tagId = isPrivateTag(keyword) ? keyword : dcmjs.data.DicomMetaDictionary.nameMap[keyword]?.tag ?? keyword;
|
|
17970
17970
|
return tagId.replace(/[(),]/g, "").toLowerCase();
|
|
17971
17971
|
}
|
|
17972
17972
|
function convertKeywordPathToTagIdPath(keywordPath) {
|
|
@@ -97,7 +97,7 @@ function composedSpec() {
|
|
|
97
97
|
ctxIn.hostProps.activityProviderName,
|
|
98
98
|
ctxIn.centerSubjectId(parser),
|
|
99
99
|
ctxIn.timepointName(parser),
|
|
100
|
-
ctxIn.scanName(parser) + "=" + parser.getDicom("SeriesNumber")
|
|
100
|
+
ctxIn.scanName(parser) + "=" + (parser.getDicom("SeriesNumber") ?? "UNKNOWN"),
|
|
101
101
|
parser.getFilePathComp(parser.FILEBASENAME) + ".dcm"
|
|
102
102
|
];
|
|
103
103
|
},
|
package/dist/esm/curateDict.js
CHANGED
|
@@ -34008,7 +34008,7 @@ function isPrivateTag(tagId) {
|
|
|
34008
34008
|
return false;
|
|
34009
34009
|
}
|
|
34010
34010
|
function convertKeywordToTagId(keyword) {
|
|
34011
|
-
const tagId = isPrivateTag(keyword) ? keyword : dcmjs.data.DicomMetaDictionary.nameMap[keyword]?.tag
|
|
34011
|
+
const tagId = isPrivateTag(keyword) ? keyword : dcmjs.data.DicomMetaDictionary.nameMap[keyword]?.tag ?? keyword;
|
|
34012
34012
|
return tagId.replace(/[(),]/g, "").toLowerCase();
|
|
34013
34013
|
}
|
|
34014
34014
|
function convertKeywordPathToTagIdPath(keywordPath) {
|
|
@@ -34867,7 +34867,7 @@ function getCid7050Codes(options) {
|
|
|
34867
34867
|
var import_lodash = __toESM(require_lodash(), 1);
|
|
34868
34868
|
var nameMap = dcmjs2.data.DicomMetaDictionary.nameMap;
|
|
34869
34869
|
function getVr(keyword) {
|
|
34870
|
-
const element = nameMap[keyword]
|
|
34870
|
+
const element = nameMap[keyword] ?? nameMap[`RETIRED_${keyword}`];
|
|
34871
34871
|
return element?.vr;
|
|
34872
34872
|
}
|
|
34873
34873
|
function temporalVr(vr) {
|
|
@@ -34939,7 +34939,7 @@ function deidentifyPS315E({
|
|
|
34939
34939
|
}
|
|
34940
34940
|
}
|
|
34941
34941
|
}
|
|
34942
|
-
return current[tagName]
|
|
34942
|
+
return current[tagName] ?? null;
|
|
34943
34943
|
}
|
|
34944
34944
|
const {
|
|
34945
34945
|
cleanDescriptorsOption,
|
package/dist/esm/curateOne.js
CHANGED
|
@@ -71706,7 +71706,7 @@ function isPrivateTag(tagId) {
|
|
|
71706
71706
|
return false;
|
|
71707
71707
|
}
|
|
71708
71708
|
function convertKeywordToTagId(keyword) {
|
|
71709
|
-
const tagId = isPrivateTag(keyword) ? keyword : dcmjs.data.DicomMetaDictionary.nameMap[keyword]?.tag
|
|
71709
|
+
const tagId = isPrivateTag(keyword) ? keyword : dcmjs.data.DicomMetaDictionary.nameMap[keyword]?.tag ?? keyword;
|
|
71710
71710
|
return tagId.replace(/[(),]/g, "").toLowerCase();
|
|
71711
71711
|
}
|
|
71712
71712
|
function convertKeywordPathToTagIdPath(keywordPath) {
|
|
@@ -72565,7 +72565,7 @@ function getCid7050Codes(options) {
|
|
|
72565
72565
|
var import_lodash = __toESM(require_lodash(), 1);
|
|
72566
72566
|
var nameMap = dcmjs2.data.DicomMetaDictionary.nameMap;
|
|
72567
72567
|
function getVr(keyword) {
|
|
72568
|
-
const element = nameMap[keyword]
|
|
72568
|
+
const element = nameMap[keyword] ?? nameMap[`RETIRED_${keyword}`];
|
|
72569
72569
|
return element?.vr;
|
|
72570
72570
|
}
|
|
72571
72571
|
function temporalVr(vr) {
|
|
@@ -72637,7 +72637,7 @@ function deidentifyPS315E({
|
|
|
72637
72637
|
}
|
|
72638
72638
|
}
|
|
72639
72639
|
}
|
|
72640
|
-
return current[tagName]
|
|
72640
|
+
return current[tagName] ?? null;
|
|
72641
72641
|
}
|
|
72642
72642
|
const {
|
|
72643
72643
|
cleanDescriptorsOption,
|
|
@@ -73370,6 +73370,30 @@ function curateDict(inputFilePath, dicomData, mappingOptions) {
|
|
|
73370
73370
|
return { dicomData: mappedDicomData, mapResults: (0, import_lodash4.cloneDeep)(mapResults) };
|
|
73371
73371
|
}
|
|
73372
73372
|
|
|
73373
|
+
// src/fetchWithRetry.ts
|
|
73374
|
+
var MAX_ATTEMPTS = 5;
|
|
73375
|
+
var BASE_DELAY_MS = 1e3;
|
|
73376
|
+
var BACKOFF_MULTIPLIER = 3;
|
|
73377
|
+
async function fetchWithRetry(...args) {
|
|
73378
|
+
for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
|
|
73379
|
+
try {
|
|
73380
|
+
return await fetch(...args);
|
|
73381
|
+
} catch (error2) {
|
|
73382
|
+
const isNetworkError = error2 instanceof TypeError;
|
|
73383
|
+
const isLastAttempt = attempt === MAX_ATTEMPTS;
|
|
73384
|
+
if (!isNetworkError || isLastAttempt) {
|
|
73385
|
+
throw error2;
|
|
73386
|
+
}
|
|
73387
|
+
const delayMs = BASE_DELAY_MS * BACKOFF_MULTIPLIER ** (attempt - 1);
|
|
73388
|
+
console.warn(
|
|
73389
|
+
`fetch attempt ${attempt}/${MAX_ATTEMPTS} failed: ${error2.message}. Retrying in ${delayMs}ms...`
|
|
73390
|
+
);
|
|
73391
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
73392
|
+
}
|
|
73393
|
+
}
|
|
73394
|
+
throw new Error("fetchWithRetry: unreachable");
|
|
73395
|
+
}
|
|
73396
|
+
|
|
73373
73397
|
// src/hash.ts
|
|
73374
73398
|
var import_md5 = __toESM(require_md5(), 1);
|
|
73375
73399
|
var import_js_crc = __toESM(require_crc(), 1);
|
|
@@ -73380,9 +73404,9 @@ async function hash(buffer, hashMethod) {
|
|
|
73380
73404
|
case "crc32":
|
|
73381
73405
|
return crc32Hex(buffer);
|
|
73382
73406
|
case "md5":
|
|
73407
|
+
default:
|
|
73383
73408
|
return md5Hex(buffer);
|
|
73384
73409
|
case "crc64":
|
|
73385
|
-
default:
|
|
73386
73410
|
return crc64Hex(buffer);
|
|
73387
73411
|
}
|
|
73388
73412
|
}
|
|
@@ -73457,7 +73481,7 @@ async function loadS3Client() {
|
|
|
73457
73481
|
const { createRequire } = await import("module");
|
|
73458
73482
|
const req = createRequire(import.meta.url);
|
|
73459
73483
|
const mod = req("@aws-sdk/client-s3");
|
|
73460
|
-
cachedS3Client = mod?.default
|
|
73484
|
+
cachedS3Client = mod?.default ?? mod;
|
|
73461
73485
|
} else {
|
|
73462
73486
|
cachedS3Client = await Promise.resolve().then(() => __toESM(require_dist_cjs71(), 1));
|
|
73463
73487
|
}
|
|
@@ -73496,7 +73520,7 @@ async function curateOne({
|
|
|
73496
73520
|
);
|
|
73497
73521
|
}
|
|
73498
73522
|
file = await resp.blob();
|
|
73499
|
-
const lastModifiedHeader = resp.headers.get("last-modified")
|
|
73523
|
+
const lastModifiedHeader = resp.headers.get("last-modified");
|
|
73500
73524
|
if (lastModifiedHeader) {
|
|
73501
73525
|
mtime = new Date(lastModifiedHeader).toISOString();
|
|
73502
73526
|
}
|
|
@@ -73562,14 +73586,14 @@ async function curateOne({
|
|
|
73562
73586
|
} catch (e4) {
|
|
73563
73587
|
}
|
|
73564
73588
|
}
|
|
73565
|
-
|
|
73589
|
+
let fileArrayBuffer = await file.arrayBuffer();
|
|
73566
73590
|
let preMappedHash;
|
|
73567
73591
|
let postMappedHash;
|
|
73568
73592
|
const postMappedHashHeader = "x-source-file-hash";
|
|
73569
73593
|
let canSkip = false;
|
|
73570
73594
|
if (previousSourceFileInfo?.preMappedHash !== void 0) {
|
|
73571
73595
|
try {
|
|
73572
|
-
preMappedHash = await hash(fileArrayBuffer, hashMethod
|
|
73596
|
+
preMappedHash = await hash(fileArrayBuffer, hashMethod ?? "md5");
|
|
73573
73597
|
} catch (e4) {
|
|
73574
73598
|
console.warn(`Failed to compute preMappedHash for ${fileInfo.name}`, e4);
|
|
73575
73599
|
}
|
|
@@ -73674,7 +73698,7 @@ async function curateOne({
|
|
|
73674
73698
|
}
|
|
73675
73699
|
if (!preMappedHash) {
|
|
73676
73700
|
try {
|
|
73677
|
-
preMappedHash = await hash(fileArrayBuffer, hashMethod
|
|
73701
|
+
preMappedHash = await hash(fileArrayBuffer, hashMethod ?? "md5");
|
|
73678
73702
|
} catch (e4) {
|
|
73679
73703
|
console.warn(`Failed to compute preMappedHash for ${fileInfo.name}`, e4);
|
|
73680
73704
|
}
|
|
@@ -73685,7 +73709,8 @@ async function curateOne({
|
|
|
73685
73709
|
const modifiedArrayBuffer = mappedDicomData.write({
|
|
73686
73710
|
allowInvalidVRLength: true
|
|
73687
73711
|
});
|
|
73688
|
-
postMappedHash = await hash(modifiedArrayBuffer, hashMethod
|
|
73712
|
+
postMappedHash = await hash(modifiedArrayBuffer, hashMethod ?? "md5");
|
|
73713
|
+
fileArrayBuffer = null;
|
|
73689
73714
|
const previousPostMappedHash = previousMappedFileInfo ? previousMappedFileInfo(clonedMapResults.outputFilePath)?.postMappedHash : void 0;
|
|
73690
73715
|
if (previousPostMappedHash !== void 0 && previousPostMappedHash === postMappedHash) {
|
|
73691
73716
|
return noMapResult(clonedMapResults.outputFilePath);
|
|
@@ -73717,54 +73742,53 @@ async function curateOne({
|
|
|
73717
73742
|
}
|
|
73718
73743
|
const fullFilePath = path.join(fullDirPath, fileName);
|
|
73719
73744
|
await fs.writeFile(fullFilePath, new DataView(modifiedArrayBuffer));
|
|
73720
|
-
} else {
|
|
73745
|
+
} else if (!outputTarget?.http && !outputTarget?.s3) {
|
|
73721
73746
|
clonedMapResults.mappedBlob = new Blob([modifiedArrayBuffer], {
|
|
73722
73747
|
type: "application/octet-stream"
|
|
73723
73748
|
});
|
|
73724
73749
|
}
|
|
73725
|
-
clonedMapResults.mappedBlob = new Blob([modifiedArrayBuffer], {
|
|
73726
|
-
type: "application/octet-stream"
|
|
73727
|
-
});
|
|
73728
73750
|
if (outputTarget?.http) {
|
|
73729
73751
|
try {
|
|
73730
73752
|
const key = clonedMapResults.outputFilePath.split("/").map(encodeURIComponent).join("/");
|
|
73731
73753
|
const uploadUrl = `${outputTarget.http.url}/${key}`;
|
|
73732
73754
|
const headers = {
|
|
73733
|
-
"Content-Type":
|
|
73755
|
+
"Content-Type": "application/octet-stream",
|
|
73734
73756
|
"X-File-Name": fileName,
|
|
73735
|
-
"X-File-Type":
|
|
73757
|
+
"X-File-Type": "application/octet-stream",
|
|
73736
73758
|
"X-File-Size": String(modifiedArrayBuffer.byteLength),
|
|
73737
|
-
"X-Source-File-Size": String(clonedMapResults.fileInfo?.size
|
|
73738
|
-
"X-Source-File-Modified-Time": mtime
|
|
73739
|
-
"X-Source-File-Hash": preMappedHash
|
|
73759
|
+
"X-Source-File-Size": String(clonedMapResults.fileInfo?.size ?? ""),
|
|
73760
|
+
"X-Source-File-Modified-Time": mtime ?? "",
|
|
73761
|
+
"X-Source-File-Hash": preMappedHash ?? ""
|
|
73740
73762
|
};
|
|
73741
73763
|
if (outputTarget.http.headers) {
|
|
73742
73764
|
Object.assign(headers, outputTarget.http.headers);
|
|
73743
73765
|
}
|
|
73744
73766
|
if (postMappedHashHeader && postMappedHash)
|
|
73745
73767
|
headers[postMappedHashHeader] = postMappedHash;
|
|
73746
|
-
const resp = await
|
|
73768
|
+
const resp = await fetchWithRetry(uploadUrl, {
|
|
73747
73769
|
method: "PUT",
|
|
73748
73770
|
headers,
|
|
73749
|
-
body:
|
|
73771
|
+
body: new Blob([modifiedArrayBuffer], {
|
|
73772
|
+
type: "application/octet-stream"
|
|
73773
|
+
})
|
|
73750
73774
|
});
|
|
73751
73775
|
if (!resp.ok) {
|
|
73752
73776
|
console.error(
|
|
73753
73777
|
`Upload failed for ${uploadUrl}: ${resp.status} ${resp.statusText}`
|
|
73754
73778
|
);
|
|
73755
|
-
clonedMapResults.errors = clonedMapResults.errors
|
|
73779
|
+
clonedMapResults.errors = clonedMapResults.errors ?? [];
|
|
73756
73780
|
clonedMapResults.errors.push(
|
|
73757
73781
|
`Upload failed: ${resp.status} ${resp.statusText}`
|
|
73758
73782
|
);
|
|
73759
73783
|
} else {
|
|
73760
|
-
clonedMapResults.outputUpload = clonedMapResults.outputUpload
|
|
73784
|
+
clonedMapResults.outputUpload = clonedMapResults.outputUpload ?? {
|
|
73761
73785
|
url: uploadUrl,
|
|
73762
73786
|
status: resp.status
|
|
73763
73787
|
};
|
|
73764
73788
|
}
|
|
73765
73789
|
} catch (e4) {
|
|
73766
73790
|
console.error("Upload error", e4);
|
|
73767
|
-
clonedMapResults.errors = clonedMapResults.errors
|
|
73791
|
+
clonedMapResults.errors = clonedMapResults.errors ?? [];
|
|
73768
73792
|
clonedMapResults.errors.push(
|
|
73769
73793
|
`Upload error: ${e4 instanceof Error ? e4.message : String(e4)}`
|
|
73770
73794
|
);
|
|
@@ -73784,12 +73808,14 @@ async function curateOne({
|
|
|
73784
73808
|
new s32.PutObjectCommand({
|
|
73785
73809
|
Bucket: outputTarget.s3.bucketName,
|
|
73786
73810
|
Key: key,
|
|
73787
|
-
|
|
73788
|
-
|
|
73811
|
+
// Use the ArrayBuffer directly — going through Blob.arrayBuffer()
|
|
73812
|
+
// would create yet another copy of the data in memory.
|
|
73813
|
+
Body: new Uint8Array(modifiedArrayBuffer),
|
|
73814
|
+
ContentType: "application/octet-stream",
|
|
73789
73815
|
Metadata: {
|
|
73790
|
-
"source-file-size": String(clonedMapResults.fileInfo?.size
|
|
73791
|
-
"source-file-modified-time": mtime
|
|
73792
|
-
"source-file-hash": preMappedHash
|
|
73816
|
+
"source-file-size": String(clonedMapResults.fileInfo?.size ?? ""),
|
|
73817
|
+
"source-file-modified-time": mtime ?? "",
|
|
73818
|
+
"source-file-hash": preMappedHash ?? "",
|
|
73793
73819
|
...postMappedHash ? { "source-file-post-mapped-hash": postMappedHash } : {}
|
|
73794
73820
|
}
|
|
73795
73821
|
})
|
|
@@ -73801,7 +73827,7 @@ async function curateOne({
|
|
|
73801
73827
|
};
|
|
73802
73828
|
} catch (e4) {
|
|
73803
73829
|
console.error("S3 Upload error", e4);
|
|
73804
|
-
clonedMapResults.errors = clonedMapResults.errors
|
|
73830
|
+
clonedMapResults.errors = clonedMapResults.errors ?? [];
|
|
73805
73831
|
clonedMapResults.errors.push(
|
|
73806
73832
|
`S3 Upload error: ${e4 instanceof Error ? e4.message : String(e4)}`
|
|
73807
73833
|
);
|
|
@@ -33999,7 +33999,7 @@ function isPrivateTag(tagId) {
|
|
|
33999
33999
|
return false;
|
|
34000
34000
|
}
|
|
34001
34001
|
function convertKeywordToTagId(keyword) {
|
|
34002
|
-
const tagId = isPrivateTag(keyword) ? keyword : dcmjs.data.DicomMetaDictionary.nameMap[keyword]?.tag
|
|
34002
|
+
const tagId = isPrivateTag(keyword) ? keyword : dcmjs.data.DicomMetaDictionary.nameMap[keyword]?.tag ?? keyword;
|
|
34003
34003
|
return tagId.replace(/[(),]/g, "").toLowerCase();
|
|
34004
34004
|
}
|
|
34005
34005
|
|
|
@@ -34844,7 +34844,7 @@ function getCid7050Codes(options) {
|
|
|
34844
34844
|
var import_lodash = __toESM(require_lodash(), 1);
|
|
34845
34845
|
var nameMap = dcmjs2.data.DicomMetaDictionary.nameMap;
|
|
34846
34846
|
function getVr(keyword) {
|
|
34847
|
-
const element = nameMap[keyword]
|
|
34847
|
+
const element = nameMap[keyword] ?? nameMap[`RETIRED_${keyword}`];
|
|
34848
34848
|
return element?.vr;
|
|
34849
34849
|
}
|
|
34850
34850
|
function temporalVr(vr) {
|
|
@@ -34916,7 +34916,7 @@ function deidentifyPS315E({
|
|
|
34916
34916
|
}
|
|
34917
34917
|
}
|
|
34918
34918
|
}
|
|
34919
|
-
return current[tagName]
|
|
34919
|
+
return current[tagName] ?? null;
|
|
34920
34920
|
}
|
|
34921
34921
|
const {
|
|
34922
34922
|
cleanDescriptorsOption,
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// src/fetchWithRetry.ts
|
|
2
|
+
var MAX_ATTEMPTS = 5;
|
|
3
|
+
var BASE_DELAY_MS = 1e3;
|
|
4
|
+
var BACKOFF_MULTIPLIER = 3;
|
|
5
|
+
async function fetchWithRetry(...args) {
|
|
6
|
+
for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
|
|
7
|
+
try {
|
|
8
|
+
return await fetch(...args);
|
|
9
|
+
} catch (error) {
|
|
10
|
+
const isNetworkError = error instanceof TypeError;
|
|
11
|
+
const isLastAttempt = attempt === MAX_ATTEMPTS;
|
|
12
|
+
if (!isNetworkError || isLastAttempt) {
|
|
13
|
+
throw error;
|
|
14
|
+
}
|
|
15
|
+
const delayMs = BASE_DELAY_MS * BACKOFF_MULTIPLIER ** (attempt - 1);
|
|
16
|
+
console.warn(
|
|
17
|
+
`fetch attempt ${attempt}/${MAX_ATTEMPTS} failed: ${error.message}. Retrying in ${delayMs}ms...`
|
|
18
|
+
);
|
|
19
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
throw new Error("fetchWithRetry: unreachable");
|
|
23
|
+
}
|
|
24
|
+
export {
|
|
25
|
+
fetchWithRetry
|
|
26
|
+
};
|
package/dist/esm/hash.js
CHANGED