@ubercode/dcmtk 0.1.4 → 0.2.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.
Files changed (40) hide show
  1. package/README.md +18 -15
  2. package/dist/DicomInstance-By9zd7GM.d.cts +625 -0
  3. package/dist/DicomInstance-CQEIuF_x.d.ts +625 -0
  4. package/dist/{dcmodify-CTXBWKU9.d.cts → dcmodify-B-_uUIKB.d.ts} +4 -2
  5. package/dist/{dcmodify-Daeafqrm.d.ts → dcmodify-Gds9u5Vj.d.cts} +4 -2
  6. package/dist/dicom.cjs +329 -51
  7. package/dist/dicom.cjs.map +1 -1
  8. package/dist/dicom.d.cts +368 -3
  9. package/dist/dicom.d.ts +368 -3
  10. package/dist/dicom.js +329 -51
  11. package/dist/dicom.js.map +1 -1
  12. package/dist/index.cjs +1460 -419
  13. package/dist/index.cjs.map +1 -1
  14. package/dist/index.d.cts +8 -7
  15. package/dist/index.d.ts +8 -7
  16. package/dist/index.js +1432 -413
  17. package/dist/index.js.map +1 -1
  18. package/dist/servers.cjs +2379 -196
  19. package/dist/servers.cjs.map +1 -1
  20. package/dist/servers.d.cts +1654 -3
  21. package/dist/servers.d.ts +1654 -3
  22. package/dist/servers.js +2305 -145
  23. package/dist/servers.js.map +1 -1
  24. package/dist/tools.cjs +97 -50
  25. package/dist/tools.cjs.map +1 -1
  26. package/dist/tools.d.cts +21 -4
  27. package/dist/tools.d.ts +21 -4
  28. package/dist/tools.js +97 -51
  29. package/dist/tools.js.map +1 -1
  30. package/dist/{types-zHhxS7d2.d.cts → types-Cgumy1N4.d.cts} +1 -24
  31. package/dist/{types-zHhxS7d2.d.ts → types-Cgumy1N4.d.ts} +1 -24
  32. package/dist/utils.cjs.map +1 -1
  33. package/dist/utils.d.cts +1 -1
  34. package/dist/utils.d.ts +1 -1
  35. package/dist/utils.js.map +1 -1
  36. package/package.json +8 -8
  37. package/dist/index-BZxi4104.d.ts +0 -826
  38. package/dist/index-CapkWqxy.d.ts +0 -1295
  39. package/dist/index-DX4C3zbo.d.cts +0 -826
  40. package/dist/index-r7AvpkCE.d.cts +0 -1295
package/dist/dicom.cjs CHANGED
@@ -2,12 +2,12 @@
2
2
 
3
3
  var path = require('path');
4
4
  var stderrLib = require('stderr-lib');
5
- var promises = require('fs/promises');
6
- var zod = require('zod');
7
5
  var child_process = require('child_process');
8
6
  var kill = require('tree-kill');
9
7
  var fs = require('fs');
8
+ var zod = require('zod');
10
9
  var fastXmlParser = require('fast-xml-parser');
10
+ var promises = require('fs/promises');
11
11
 
12
12
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
13
13
 
@@ -30129,6 +30129,18 @@ function buildMergedModifications(base, other, erasures) {
30129
30129
  }
30130
30130
  return merged;
30131
30131
  }
30132
+ function applyBatchEntries(initial, entries) {
30133
+ const keys = Object.keys(entries);
30134
+ let cs = initial;
30135
+ for (let i = 0; i < keys.length; i++) {
30136
+ const key = keys[i];
30137
+ if (key === void 0) continue;
30138
+ const value = entries[key];
30139
+ if (value === void 0) continue;
30140
+ cs = cs.setTag(key, value);
30141
+ }
30142
+ return cs;
30143
+ }
30132
30144
  var ChangeSet = class _ChangeSet {
30133
30145
  constructor(mods, erasures) {
30134
30146
  __publicField(this, "mods");
@@ -30146,7 +30158,7 @@ var ChangeSet = class _ChangeSet {
30146
30158
  * Control characters (except LF/CR) are stripped from the value.
30147
30159
  * If the tag was previously erased, it is removed from the erasure set.
30148
30160
  *
30149
- * @param path - The DICOM tag path to set
30161
+ * @param path - The DICOM tag path to set (e.g. `'(0010,0010)'`)
30150
30162
  * @param value - The new value for the tag
30151
30163
  * @returns A new ChangeSet with the modification applied
30152
30164
  * @throws Error if operation count would exceed MAX_CHANGESET_OPERATIONS
@@ -30169,7 +30181,7 @@ var ChangeSet = class _ChangeSet {
30169
30181
  *
30170
30182
  * If the tag was previously set, the modification is removed.
30171
30183
  *
30172
- * @param path - The DICOM tag path to erase
30184
+ * @param path - The DICOM tag path to erase (e.g. `'(0010,0010)'`)
30173
30185
  * @returns A new ChangeSet with the erasure applied
30174
30186
  * @throws Error if operation count would exceed MAX_CHANGESET_OPERATIONS
30175
30187
  */
@@ -30200,6 +30212,50 @@ var ChangeSet = class _ChangeSet {
30200
30212
  newErasures.add(ERASE_PRIVATE_SENTINEL);
30201
30213
  return new _ChangeSet(new Map(this.mods), newErasures);
30202
30214
  }
30215
+ // -----------------------------------------------------------------------
30216
+ // Convenience setters for common DICOM tags
30217
+ // -----------------------------------------------------------------------
30218
+ /** Sets Patient's Name (0010,0010). */
30219
+ setPatientName(value) {
30220
+ return this.setTag("(0010,0010)", value);
30221
+ }
30222
+ /** Sets Patient ID (0010,0020). */
30223
+ setPatientID(value) {
30224
+ return this.setTag("(0010,0020)", value);
30225
+ }
30226
+ /** Sets Study Date (0008,0020). */
30227
+ setStudyDate(value) {
30228
+ return this.setTag("(0008,0020)", value);
30229
+ }
30230
+ /** Sets Modality (0008,0060). */
30231
+ setModality(value) {
30232
+ return this.setTag("(0008,0060)", value);
30233
+ }
30234
+ /** Sets Accession Number (0008,0050). */
30235
+ setAccessionNumber(value) {
30236
+ return this.setTag("(0008,0050)", value);
30237
+ }
30238
+ /** Sets Study Description (0008,1030). */
30239
+ setStudyDescription(value) {
30240
+ return this.setTag("(0008,1030)", value);
30241
+ }
30242
+ /** Sets Series Description (0008,103E). */
30243
+ setSeriesDescription(value) {
30244
+ return this.setTag("(0008,103E)", value);
30245
+ }
30246
+ /** Sets Institution Name (0008,0080). */
30247
+ setInstitutionName(value) {
30248
+ return this.setTag("(0008,0080)", value);
30249
+ }
30250
+ /**
30251
+ * Sets multiple tags at once, returning a new ChangeSet.
30252
+ *
30253
+ * @param entries - A record of tag path → value pairs
30254
+ * @returns A new ChangeSet with all modifications applied
30255
+ */
30256
+ setBatch(entries) {
30257
+ return applyBatchEntries(this, entries);
30258
+ }
30203
30259
  /** All pending tag modifications as a readonly map of path → value. */
30204
30260
  get modifications() {
30205
30261
  return this.mods;
@@ -30730,7 +30786,8 @@ var DcmodifyOptionsSchema = zod.z.object({
30730
30786
  erasures: zod.z.array(zod.z.string()).optional(),
30731
30787
  erasePrivateTags: zod.z.boolean().optional(),
30732
30788
  noBackup: zod.z.boolean().optional(),
30733
- insertIfMissing: zod.z.boolean().optional()
30789
+ insertIfMissing: zod.z.boolean().optional(),
30790
+ ignoreMissingTags: zod.z.boolean().optional()
30734
30791
  }).strict().refine((data) => data.modifications.length > 0 || data.erasures !== void 0 && data.erasures.length > 0 || data.erasePrivateTags === true, {
30735
30792
  message: "At least one of modifications, erasures, or erasePrivateTags is required"
30736
30793
  });
@@ -30739,6 +30796,9 @@ function buildArgs(inputPath, options) {
30739
30796
  if (options.noBackup !== false) {
30740
30797
  args.push("-nb");
30741
30798
  }
30799
+ if (options.ignoreMissingTags === true) {
30800
+ args.push("-imt");
30801
+ }
30742
30802
  const flag = options.insertIfMissing === true ? "-i" : "-m";
30743
30803
  const modifications = options.modifications ?? [];
30744
30804
  for (const mod of modifications) {
@@ -30758,7 +30818,7 @@ function buildArgs(inputPath, options) {
30758
30818
  async function dcmodify(inputPath, options) {
30759
30819
  const validation = DcmodifyOptionsSchema.safeParse(options);
30760
30820
  if (!validation.success) {
30761
- return err(new Error(`dcmodify: invalid options: ${validation.error.message}`));
30821
+ return err(createValidationError("dcmodify", validation.error));
30762
30822
  }
30763
30823
  const binaryResult = resolveBinary("dcmodify");
30764
30824
  if (!binaryResult.ok) {
@@ -30778,16 +30838,16 @@ async function dcmodify(inputPath, options) {
30778
30838
  }
30779
30839
  return ok({ filePath: inputPath });
30780
30840
  }
30781
-
30782
- // src/dicom/DicomFile.ts
30783
30841
  async function applyModifications(filePath, changeset, options) {
30784
30842
  const modifications = changeset.toModifications();
30785
30843
  const erasures = changeset.toErasureArgs();
30844
+ const hasErasures = erasures.length > 0 || changeset.erasePrivate;
30786
30845
  const result = await dcmodify(filePath, {
30787
30846
  modifications: modifications.length > 0 ? modifications : void 0,
30788
30847
  erasures: erasures.length > 0 ? erasures : void 0,
30789
30848
  erasePrivateTags: changeset.erasePrivate || void 0,
30790
30849
  insertIfMissing: true,
30850
+ ignoreMissingTags: hasErasures || void 0,
30791
30851
  timeoutMs: options.timeoutMs ?? DEFAULT_TIMEOUT_MS,
30792
30852
  signal: options.signal
30793
30853
  });
@@ -30812,24 +30872,28 @@ async function unlinkFile(path) {
30812
30872
  (e) => new Error(`Failed to delete file: ${e.message}`)
30813
30873
  );
30814
30874
  }
30815
- var DicomFile = class _DicomFile {
30816
- constructor(dataset, filePath, changes) {
30817
- /** The immutable DICOM dataset read from the file. */
30818
- __publicField(this, "dataset");
30819
- /** The branded file path. */
30820
- __publicField(this, "filePath");
30821
- /** The accumulated pending changes. */
30822
- __publicField(this, "changes");
30823
- this.dataset = dataset;
30824
- this.filePath = filePath;
30825
- this.changes = changes;
30875
+
30876
+ // src/dicom/DicomInstance.ts
30877
+ var DicomInstance = class _DicomInstance {
30878
+ constructor(dataset, changes, filePath, metadata) {
30879
+ __publicField(this, "dicomDataset");
30880
+ __publicField(this, "changeSet");
30881
+ __publicField(this, "filepath");
30882
+ __publicField(this, "meta");
30883
+ this.dicomDataset = dataset;
30884
+ this.changeSet = changes;
30885
+ this.filepath = filePath;
30886
+ this.meta = metadata;
30826
30887
  }
30888
+ // -----------------------------------------------------------------------
30889
+ // Factories
30890
+ // -----------------------------------------------------------------------
30827
30891
  /**
30828
- * Opens a DICOM file and reads its dataset.
30892
+ * Opens a DICOM file and creates a DicomInstance.
30829
30893
  *
30830
30894
  * @param path - Filesystem path to the DICOM file
30831
30895
  * @param options - Timeout and abort options
30832
- * @returns A Result containing the DicomFile or an error
30896
+ * @returns A Result containing the DicomInstance or an error
30833
30897
  */
30834
30898
  static async open(path, options) {
30835
30899
  const filePathResult = createDicomFilePath(path);
@@ -30841,64 +30905,250 @@ var DicomFile = class _DicomFile {
30841
30905
  if (!jsonResult.ok) return err(jsonResult.error);
30842
30906
  const datasetResult = DicomDataset.fromJson(jsonResult.value.data);
30843
30907
  if (!datasetResult.ok) return err(datasetResult.error);
30844
- return ok(new _DicomFile(datasetResult.value, filePathResult.value, ChangeSet.empty()));
30908
+ return ok(new _DicomInstance(datasetResult.value, ChangeSet.empty(), filePathResult.value, /* @__PURE__ */ new Map()));
30845
30909
  }
30846
30910
  /**
30847
- * Returns a new DicomFile with the given changes merged into the pending changes.
30911
+ * Creates a DicomInstance from an existing DicomDataset.
30912
+ *
30913
+ * @param dataset - The DicomDataset to wrap
30914
+ * @param filePath - Optional file path (e.g. if the dataset came from a file)
30915
+ * @returns A Result containing the DicomInstance
30916
+ */
30917
+ static fromDataset(dataset, filePath) {
30918
+ let fp;
30919
+ if (filePath !== void 0) {
30920
+ const fpResult = createDicomFilePath(filePath);
30921
+ if (!fpResult.ok) return err(fpResult.error);
30922
+ fp = fpResult.value;
30923
+ }
30924
+ return ok(new _DicomInstance(dataset, ChangeSet.empty(), fp, /* @__PURE__ */ new Map()));
30925
+ }
30926
+ // -----------------------------------------------------------------------
30927
+ // Read accessors (delegate to DicomDataset)
30928
+ // -----------------------------------------------------------------------
30929
+ /** The underlying immutable DICOM dataset. */
30930
+ get dataset() {
30931
+ return this.dicomDataset;
30932
+ }
30933
+ /** The pending change set. */
30934
+ get changes() {
30935
+ return this.changeSet;
30936
+ }
30937
+ /** Whether there are unsaved changes. */
30938
+ get hasUnsavedChanges() {
30939
+ return !this.changeSet.isEmpty;
30940
+ }
30941
+ /** The file path, or undefined if this instance has no associated file. */
30942
+ get filePath() {
30943
+ return this.filepath;
30944
+ }
30945
+ /** Patient's Name (0010,0010). */
30946
+ get patientName() {
30947
+ return this.dicomDataset.patientName;
30948
+ }
30949
+ /** Patient ID (0010,0020). */
30950
+ get patientID() {
30951
+ return this.dicomDataset.patientID;
30952
+ }
30953
+ /** Study Date (0008,0020). */
30954
+ get studyDate() {
30955
+ return this.dicomDataset.studyDate;
30956
+ }
30957
+ /** Modality (0008,0060). */
30958
+ get modality() {
30959
+ return this.dicomDataset.modality;
30960
+ }
30961
+ /** Accession Number (0008,0050). */
30962
+ get accession() {
30963
+ return this.dicomDataset.accession;
30964
+ }
30965
+ /** SOP Class UID (0008,0016). */
30966
+ get sopClassUID() {
30967
+ return this.dicomDataset.sopClassUID;
30968
+ }
30969
+ /** Study Instance UID (0020,000D). */
30970
+ get studyInstanceUID() {
30971
+ return this.dicomDataset.studyInstanceUID;
30972
+ }
30973
+ /** Series Instance UID (0020,000E). */
30974
+ get seriesInstanceUID() {
30975
+ return this.dicomDataset.seriesInstanceUID;
30976
+ }
30977
+ /** SOP Instance UID (0008,0018). */
30978
+ get sopInstanceUID() {
30979
+ return this.dicomDataset.sopInstanceUID;
30980
+ }
30981
+ /** Transfer Syntax UID (0002,0010). */
30982
+ get transferSyntaxUID() {
30983
+ return this.dicomDataset.transferSyntaxUID;
30984
+ }
30985
+ /**
30986
+ * Gets a tag value as a string with optional fallback.
30987
+ *
30988
+ * @param tag - A DICOM tag, e.g. `'(0010,0010)'` or `'00100010'`
30989
+ * @param fallback - Value to return if tag is missing (default: `''`)
30990
+ */
30991
+ getString(tag, fallback = "") {
30992
+ return this.dicomDataset.getString(tag, fallback);
30993
+ }
30994
+ /**
30995
+ * Gets a tag value as a number.
30996
+ *
30997
+ * @param tag - A DICOM tag, e.g. `'(0020,0013)'`
30998
+ */
30999
+ getNumber(tag) {
31000
+ return this.dicomDataset.getNumber(tag);
31001
+ }
31002
+ /** Checks whether a tag exists in the dataset. */
31003
+ hasTag(tag) {
31004
+ return this.dicomDataset.hasTag(tag);
31005
+ }
31006
+ /**
31007
+ * Finds all values matching a wildcard path.
31008
+ *
31009
+ * @param path - A DicomTagPath with optional wildcard indices
31010
+ */
31011
+ findValues(path) {
31012
+ return this.dicomDataset.findValues(path);
31013
+ }
31014
+ // -----------------------------------------------------------------------
31015
+ // Write methods (return new instance)
31016
+ // -----------------------------------------------------------------------
31017
+ /**
31018
+ * Sets a tag value, returning a new DicomInstance.
31019
+ *
31020
+ * @param path - The DICOM tag path (e.g. `'(0010,0010)'`)
31021
+ * @param value - The new value
31022
+ */
31023
+ setTag(path, value) {
31024
+ return new _DicomInstance(this.dicomDataset, this.changeSet.setTag(path, value), this.filepath, this.meta);
31025
+ }
31026
+ /**
31027
+ * Erases a tag, returning a new DicomInstance.
31028
+ *
31029
+ * @param path - The DICOM tag path to erase
31030
+ */
31031
+ eraseTag(path) {
31032
+ return new _DicomInstance(this.dicomDataset, this.changeSet.eraseTag(path), this.filepath, this.meta);
31033
+ }
31034
+ /** Erases all private tags, returning a new DicomInstance. */
31035
+ erasePrivateTags() {
31036
+ return new _DicomInstance(this.dicomDataset, this.changeSet.erasePrivateTags(), this.filepath, this.meta);
31037
+ }
31038
+ /** Sets Patient's Name (0010,0010). */
31039
+ setPatientName(value) {
31040
+ return this.setTag("(0010,0010)", value);
31041
+ }
31042
+ /** Sets Patient ID (0010,0020). */
31043
+ setPatientID(value) {
31044
+ return this.setTag("(0010,0020)", value);
31045
+ }
31046
+ /** Sets Study Date (0008,0020). */
31047
+ setStudyDate(value) {
31048
+ return this.setTag("(0008,0020)", value);
31049
+ }
31050
+ /** Sets Modality (0008,0060). */
31051
+ setModality(value) {
31052
+ return this.setTag("(0008,0060)", value);
31053
+ }
31054
+ /** Sets Accession Number (0008,0050). */
31055
+ setAccessionNumber(value) {
31056
+ return this.setTag("(0008,0050)", value);
31057
+ }
31058
+ /** Sets Study Description (0008,1030). */
31059
+ setStudyDescription(value) {
31060
+ return this.setTag("(0008,1030)", value);
31061
+ }
31062
+ /** Sets Series Description (0008,103E). */
31063
+ setSeriesDescription(value) {
31064
+ return this.setTag("(0008,103E)", value);
31065
+ }
31066
+ /** Sets Institution Name (0008,0080). */
31067
+ setInstitutionName(value) {
31068
+ return this.setTag("(0008,0080)", value);
31069
+ }
31070
+ /**
31071
+ * Transforms a tag value using a function.
31072
+ *
31073
+ * The function receives the current string value (or undefined if tag is missing)
31074
+ * and returns the new value. Returns a new DicomInstance with the modification.
31075
+ *
31076
+ * @param path - The DICOM tag path
31077
+ * @param fn - Transform function receiving the current value
31078
+ */
31079
+ transformTag(path, fn) {
31080
+ const current = this.dicomDataset.getString(path);
31081
+ const newValue = fn(current.length > 0 ? current : void 0);
31082
+ return this.setTag(path, newValue);
31083
+ }
31084
+ /**
31085
+ * Sets multiple tags at once, returning a new DicomInstance.
31086
+ *
31087
+ * @param entries - A record of tag path → value pairs
31088
+ */
31089
+ setBatch(entries) {
31090
+ return new _DicomInstance(this.dicomDataset, this.changeSet.setBatch(entries), this.filepath, this.meta);
31091
+ }
31092
+ /**
31093
+ * Returns a new DicomInstance with the given changes merged into pending changes.
30848
31094
  *
30849
31095
  * @param changes - A ChangeSet to merge with existing pending changes
30850
- * @returns A new DicomFile with accumulated changes
31096
+ * @returns A new DicomInstance with accumulated changes
30851
31097
  */
30852
31098
  withChanges(changes) {
30853
- return new _DicomFile(this.dataset, this.filePath, this.changes.merge(changes));
31099
+ return new _DicomInstance(this.dicomDataset, this.changeSet.merge(changes), this.filepath, this.meta);
30854
31100
  }
30855
31101
  /**
30856
- * Returns a new DicomFile with a different file path.
31102
+ * Returns a new DicomInstance pointing to a different file path.
30857
31103
  *
30858
- * Preserves the dataset and pending changes.
31104
+ * Preserves the dataset, pending changes, and metadata.
30859
31105
  *
30860
- * @param newPath - The new branded file path
30861
- * @returns A new DicomFile pointing to the new path
31106
+ * @param newPath - The new filesystem path (validated via createDicomFilePath)
31107
+ * @returns A new DicomInstance with the updated path
31108
+ * @throws If the path is invalid
30862
31109
  */
30863
31110
  withFilePath(newPath) {
30864
- return new _DicomFile(this.dataset, newPath, this.changes);
31111
+ const result = createDicomFilePath(newPath);
31112
+ if (!result.ok) throw result.error;
31113
+ return new _DicomInstance(this.dicomDataset, this.changeSet, result.value, this.meta);
30865
31114
  }
31115
+ // -----------------------------------------------------------------------
31116
+ // File I/O
31117
+ // -----------------------------------------------------------------------
30866
31118
  /**
30867
- * Applies pending changes to the file in-place using dcmodify.
31119
+ * Applies pending changes to the file in-place.
30868
31120
  *
30869
- * If there are no pending changes, this is a no-op that returns success.
30870
- * After applying, the dataset is NOT refreshed — call {@link DicomFile.open}
30871
- * again if you need fresh data.
31121
+ * Requires that the instance has an associated file path.
30872
31122
  *
30873
31123
  * @param options - Timeout and abort options
30874
- * @returns A Result indicating success or failure
30875
31124
  */
30876
31125
  async applyChanges(options) {
30877
- if (this.changes.isEmpty) return ok(void 0);
30878
- return applyModifications(this.filePath, this.changes, options ?? {});
31126
+ if (this.filepath === void 0) return err(new Error("No file path associated with this instance"));
31127
+ if (this.changeSet.isEmpty) return ok(void 0);
31128
+ return applyModifications(this.filepath, this.changeSet, options ?? {});
30879
31129
  }
30880
31130
  /**
30881
31131
  * Copies the file to a new path and applies pending changes to the copy.
30882
31132
  *
30883
- * If there are no pending changes, only the copy is performed.
30884
- * On dcmodify failure, the copy is cleaned up.
31133
+ * Returns a new DicomInstance pointing to the output path.
30885
31134
  *
30886
31135
  * @param outputPath - Destination filesystem path
30887
31136
  * @param options - Timeout and abort options
30888
- * @returns A Result containing the branded output path or an error
30889
31137
  */
30890
31138
  async writeAs(outputPath, options) {
31139
+ if (this.filepath === void 0) return err(new Error("No file path associated with this instance"));
30891
31140
  const outPathResult = createDicomFilePath(outputPath);
30892
31141
  if (!outPathResult.ok) return err(outPathResult.error);
30893
- const copyResult = await copyFileSafe(this.filePath, outputPath);
31142
+ const copyResult = await copyFileSafe(this.filepath, outputPath);
30894
31143
  if (!copyResult.ok) return err(copyResult.error);
30895
- if (this.changes.isEmpty) return ok(outPathResult.value);
30896
- const applyResult = await applyModifications(outPathResult.value, this.changes, options ?? {});
30897
- if (!applyResult.ok) {
30898
- await unlinkFile(outputPath);
30899
- return err(applyResult.error);
31144
+ if (!this.changeSet.isEmpty) {
31145
+ const applyResult = await applyModifications(outPathResult.value, this.changeSet, options ?? {});
31146
+ if (!applyResult.ok) {
31147
+ await unlinkFile(outputPath);
31148
+ return err(applyResult.error);
31149
+ }
30900
31150
  }
30901
- return ok(outPathResult.value);
31151
+ return ok(new _DicomInstance(this.dicomDataset, ChangeSet.empty(), outPathResult.value, this.meta));
30902
31152
  }
30903
31153
  /**
30904
31154
  * Gets the file size in bytes.
@@ -30906,15 +31156,43 @@ var DicomFile = class _DicomFile {
30906
31156
  * @returns A Result containing the size or an error
30907
31157
  */
30908
31158
  async fileSize() {
30909
- return statFileSize(this.filePath);
31159
+ if (this.filepath === void 0) return err(new Error("No file path associated with this instance"));
31160
+ return statFileSize(this.filepath);
30910
31161
  }
30911
31162
  /**
30912
- * Deletes the file from the filesystem.
31163
+ * Deletes the associated file from the filesystem.
30913
31164
  *
30914
31165
  * @returns A Result indicating success or failure
30915
31166
  */
30916
31167
  async unlink() {
30917
- return unlinkFile(this.filePath);
31168
+ if (this.filepath === void 0) return err(new Error("No file path associated with this instance"));
31169
+ return unlinkFile(this.filepath);
31170
+ }
31171
+ // -----------------------------------------------------------------------
31172
+ // Metadata (non-DICOM app context)
31173
+ // -----------------------------------------------------------------------
31174
+ /**
31175
+ * Returns a new DicomInstance with application metadata attached.
31176
+ *
31177
+ * Metadata is not stored in the DICOM file — it's for application context
31178
+ * (e.g. tracking source association, processing status, etc.).
31179
+ *
31180
+ * @param key - Metadata key
31181
+ * @param value - Metadata value
31182
+ */
31183
+ withMetadata(key, value) {
31184
+ const newMeta = new Map(this.meta);
31185
+ newMeta.set(key, value);
31186
+ return new _DicomInstance(this.dicomDataset, this.changeSet, this.filepath, newMeta);
31187
+ }
31188
+ /**
31189
+ * Gets application metadata by key.
31190
+ *
31191
+ * @param key - Metadata key
31192
+ * @returns The metadata value or undefined
31193
+ */
31194
+ getMetadata(key) {
31195
+ return this.meta.get(key);
30918
31196
  }
30919
31197
  };
30920
31198
 
@@ -31034,7 +31312,7 @@ function sopClassNameFromUID(uid) {
31034
31312
 
31035
31313
  exports.ChangeSet = ChangeSet;
31036
31314
  exports.DicomDataset = DicomDataset;
31037
- exports.DicomFile = DicomFile;
31315
+ exports.DicomInstance = DicomInstance;
31038
31316
  exports.SOP_CLASSES = SOP_CLASSES;
31039
31317
  exports.VR = VR;
31040
31318
  exports.VR_CATEGORY = VR_CATEGORY;