dicom-curate 0.37.0 → 0.38.1

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 CHANGED
@@ -113,6 +113,49 @@ It is also possible to use S3-compatible buckets as input or output locations.
113
113
  Consult `OrganizeOptions` for further details. Please note that this feature is only
114
114
  available if you have the `@aws-sdk/client-s3` package installed.
115
115
 
116
+ ### Custom uploader
117
+
118
+ For use cases that require resumable, chunked, or otherwise non-standard uploads, you can supply your own uploader via `outputUploader`. This is mutually exclusive with `outputEndpoint`.
119
+
120
+ The uploader runs on the **main thread**. When using `curateMany()`, the mapped file's `ReadableStream` is transferred directly from the worker to the main thread (zero-copy) and handed as-is to the uploader.
121
+
122
+ ```ts
123
+ import { curateMany, OrganizeOptions, TCustomUploader } from 'dicom-curate'
124
+
125
+ const myUploader: TCustomUploader = {
126
+ async upload({ key, stream, size, contentType, headers, signal }) {
127
+ // key – output path relative to the root (URL-encoded path segments)
128
+ // stream – ReadableStream<Uint8Array> of the mapped DICOM bytes; consume once
129
+ // size – total byte length of the file
130
+ // headers – derived metadata headers (X-File-*, x-source-file-hash, …)
131
+ // signal – AbortSignal forwarded from OrganizeOptions.signal
132
+
133
+ const response = await fetch(`https://my-server.example.com/upload/${key}`, {
134
+ method: 'PUT',
135
+ body: stream,
136
+ headers: { 'Content-Length': String(size), ...headers },
137
+ signal,
138
+ // @ts-expect-error – duplex required by some runtimes for streaming bodies
139
+ duplex: 'half',
140
+ })
141
+
142
+ const etag = response.headers.get('ETag') ?? undefined
143
+ return { etag }
144
+ },
145
+ }
146
+
147
+ const options: OrganizeOptions = {
148
+ inputType: 'path',
149
+ inputDirectory: '/home/user/files',
150
+ outputUploader: myUploader,
151
+ curationSpec,
152
+ }
153
+
154
+ await curateMany(files, options)
155
+ ```
156
+
157
+ The value returned by `upload()` is passed back through the `CurateResult` for each file, so you can store server-assigned identifiers (e.g. ETags, upload IDs) alongside the normal curation results.
158
+
116
159
  ### Matching S3 ETags across uploaders
117
160
 
118
161
  When uploading to S3, you can set `uploadPartSize` on the output S3
@@ -194,6 +237,29 @@ curateOne({
194
237
  })
195
238
  ```
196
239
 
240
+ To use a custom uploader with `curateOne`, set `outputTarget.custom: true` and provide an `uploader` function directly on the call arguments:
241
+
242
+ ```ts
243
+ import { curateOne } from 'dicom-curate'
244
+
245
+ const result = await curateOne({
246
+ fileInfo,
247
+ mappingOptions: { curationSpec },
248
+ outputTarget: { custom: true },
249
+ uploader: async ({ key, stream, size, headers, signal }) => {
250
+ const response = await fetch(`https://my-server.example.com/upload/${key}`, {
251
+ method: 'PUT',
252
+ body: stream,
253
+ headers: { 'Content-Length': String(size), ...headers },
254
+ signal,
255
+ // @ts-expect-error – duplex required by some runtimes for streaming bodies
256
+ duplex: 'half',
257
+ })
258
+ return { etag: response.headers.get('ETag') ?? undefined }
259
+ },
260
+ })
261
+ ```
262
+
197
263
  An example DICOM curation function:
198
264
 
199
265
  <!-- Snippet auto-generated from src/config/sampleBatchCurationSpecification.ts -->