taglib-wasm 2.2.3 → 2.3.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 (60) hide show
  1. package/README.md +192 -13
  2. package/dist/index.browser.d.ts +24 -4
  3. package/dist/index.browser.d.ts.map +1 -1
  4. package/dist/index.browser.js +1123 -208
  5. package/dist/index.d.ts +2 -1
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +2 -0
  8. package/dist/simple.browser.js +527 -202
  9. package/dist/src/errors/base.d.ts +17 -2
  10. package/dist/src/errors/base.d.ts.map +1 -1
  11. package/dist/src/errors/base.js +18 -0
  12. package/dist/src/runtime/wasi-adapter/adapter.d.ts +13 -1
  13. package/dist/src/runtime/wasi-adapter/adapter.d.ts.map +1 -1
  14. package/dist/src/runtime/wasi-adapter/adapter.js +17 -0
  15. package/dist/src/runtime/wasi-adapter/audio-properties.d.ts +4 -1
  16. package/dist/src/runtime/wasi-adapter/audio-properties.d.ts.map +1 -1
  17. package/dist/src/runtime/wasi-adapter/audio-properties.js +23 -6
  18. package/dist/src/runtime/wasi-adapter/path-open.d.ts +68 -0
  19. package/dist/src/runtime/wasi-adapter/path-open.d.ts.map +1 -0
  20. package/dist/src/runtime/wasi-adapter/path-open.js +76 -0
  21. package/dist/src/runtime/wasi-adapter/wasm-io.d.ts.map +1 -1
  22. package/dist/src/runtime/wasi-adapter/wasm-io.js +36 -28
  23. package/dist/src/runtime/wasi-host-loader.js +8 -3
  24. package/dist/src/runtime/wasmer-sdk-loader/types.d.ts +13 -0
  25. package/dist/src/runtime/wasmer-sdk-loader/types.d.ts.map +1 -1
  26. package/dist/src/simple/checksum-operations.d.ts +25 -0
  27. package/dist/src/simple/checksum-operations.d.ts.map +1 -0
  28. package/dist/src/simple/checksum-operations.js +7 -0
  29. package/dist/src/simple/index.d.ts +2 -0
  30. package/dist/src/simple/index.d.ts.map +1 -1
  31. package/dist/src/simple/index.js +2 -0
  32. package/dist/src/taglib/audio-file-checksum.d.ts +47 -0
  33. package/dist/src/taglib/audio-file-checksum.d.ts.map +1 -0
  34. package/dist/src/taglib/audio-file-checksum.js +77 -0
  35. package/dist/src/taglib/audio-file-impl.d.ts +4 -0
  36. package/dist/src/taglib/audio-file-impl.d.ts.map +1 -1
  37. package/dist/src/taglib/audio-file-impl.js +32 -0
  38. package/dist/src/taglib/audio-file-interface.d.ts +17 -0
  39. package/dist/src/taglib/audio-file-interface.d.ts.map +1 -1
  40. package/dist/src/taglib/media-ranges.d.ts +85 -0
  41. package/dist/src/taglib/media-ranges.d.ts.map +1 -0
  42. package/dist/src/taglib/media-ranges.js +192 -0
  43. package/dist/src/taglib/metadata-extent.d.ts +55 -0
  44. package/dist/src/taglib/metadata-extent.d.ts.map +1 -1
  45. package/dist/src/taglib/metadata-extent.js +24 -6
  46. package/dist/src/taglib/taglib-class.d.ts.map +1 -1
  47. package/dist/src/taglib/taglib-class.js +13 -24
  48. package/dist/src/utils/path.d.ts +12 -0
  49. package/dist/src/utils/path.d.ts.map +1 -1
  50. package/dist/src/utils/path.js +19 -0
  51. package/dist/src/version.d.ts +1 -1
  52. package/dist/src/version.js +1 -1
  53. package/dist/src/wasm.d.ts +9 -0
  54. package/dist/src/wasm.d.ts.map +1 -1
  55. package/dist/taglib-wasi.wasm +0 -0
  56. package/dist/taglib-web.wasm +0 -0
  57. package/dist/web.browser.d.ts +13 -0
  58. package/dist/web.browser.d.ts.map +1 -0
  59. package/dist/web.browser.js +3630 -0
  60. package/package.json +12 -4
@@ -1,7 +1,22 @@
1
1
  /**
2
- * List of audio formats supported by TagLib-Wasm
2
+ * List of audio formats supported by TagLib-Wasm.
3
+ *
4
+ * The prose source of truth is the README's "Supported Formats" section; this
5
+ * list carries every `FileType` member except `"unknown"` (src/types/audio-
6
+ * formats.ts), plus the extension aliases files actually carry ("M4A", "MKA")
7
+ * — ASF is the container of the WMA flavour the README names.
8
+ *
9
+ * Public contract: the default `supportedFormats` on `UnsupportedFormatError`
10
+ * (src/errors/classes.ts), and part of that error's message.
11
+ *
12
+ * This is the formats the library can read, not a promise that both backends
13
+ * describe all of them identically. Measured 2026-09-18 (taglib-uat8):
14
+ * `getFormat()` answers every member on both backends, but on Emscripten
15
+ * `audioProperties().containerFormat` / `.codec` still report `"unknown"` for
16
+ * the formats the embind sniffer cannot place (APE, DSF, DSDIFF, MPC, SHN,
17
+ * MOD, S3M, IT, XM); their tags and the rest of their properties load.
3
18
  */
4
- export declare const SUPPORTED_FORMATS: readonly ["MP3", "MP4", "M4A", "FLAC", "OGG", "WAV", "MKA"];
19
+ export declare const SUPPORTED_FORMATS: readonly ["MP3", "AAC", "MP4", "M4A", "FLAC", "OGG", "OPUS", "OggFLAC", "SPEEX", "WAV", "AIFF", "ASF", "APE", "DSF", "DSDIFF", "WV", "MPC", "TTA", "SHN", "MOD", "S3M", "IT", "XM", "MATROSKA", "MKA"];
5
20
  /**
6
21
  * Error codes for programmatic error handling
7
22
  */
@@ -1 +1 @@
1
- {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../src/errors/base.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,iBAAiB,6DAQpB,CAAC;AAEX;;GAEG;AACH,MAAM,MAAM,eAAe,GACvB,gBAAgB,GAChB,gBAAgB,GAChB,oBAAoB,GACpB,gBAAgB,GAChB,UAAU,GACV,QAAQ,GACR,aAAa,GACb,aAAa,GACb,aAAa,GACb,WAAW,CAAC;AAEhB;;GAEG;AACH,qBAAa,WAAY,SAAQ,KAAK;aAQlB,IAAI,EAAE,eAAe;aAErB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IATnD;;;;;OAKG;gBAEe,IAAI,EAAE,eAAe,EACrC,OAAO,EAAE,MAAM,EACC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,YAAA;CAMpD"}
1
+ {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../src/errors/base.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,iBAAiB,wMA0BpB,CAAC;AAEX;;GAEG;AACH,MAAM,MAAM,eAAe,GACvB,gBAAgB,GAChB,gBAAgB,GAChB,oBAAoB,GACpB,gBAAgB,GAChB,UAAU,GACV,QAAQ,GACR,aAAa,GACb,aAAa,GACb,aAAa,GACb,WAAW,CAAC;AAEhB;;GAEG;AACH,qBAAa,WAAY,SAAQ,KAAK;aAQlB,IAAI,EAAE,eAAe;aAErB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IATnD;;;;;OAKG;gBAEe,IAAI,EAAE,eAAe,EACrC,OAAO,EAAE,MAAM,EACC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,YAAA;CAMpD"}
@@ -3,11 +3,29 @@ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { en
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
4
  const SUPPORTED_FORMATS = [
5
5
  "MP3",
6
+ "AAC",
6
7
  "MP4",
7
8
  "M4A",
8
9
  "FLAC",
9
10
  "OGG",
11
+ "OPUS",
12
+ "OggFLAC",
13
+ "SPEEX",
10
14
  "WAV",
15
+ "AIFF",
16
+ "ASF",
17
+ "APE",
18
+ "DSF",
19
+ "DSDIFF",
20
+ "WV",
21
+ "MPC",
22
+ "TTA",
23
+ "SHN",
24
+ "MOD",
25
+ "S3M",
26
+ "IT",
27
+ "XM",
28
+ "MATROSKA",
11
29
  "MKA"
12
30
  ];
13
31
  class TagLibError extends Error {
@@ -4,7 +4,7 @@
4
4
  * Adapts a WASI module interface to the TagLibModule interface,
5
5
  * providing Emscripten-compatible memory access and string operations.
6
6
  */
7
- import type { FileHandle, TagLibModule } from "../../wasm.js";
7
+ import type { FileHandle, TagLibModule, WasmFileHandle } from "../../wasm.js";
8
8
  import type { WasiModule } from "../wasmer-sdk-loader/types.js";
9
9
  export declare class WasiToTagLibAdapter implements TagLibModule {
10
10
  private readonly wasi;
@@ -27,6 +27,18 @@ export declare class WasiToTagLibAdapter implements TagLibModule {
27
27
  stringToUTF8(str: string, ptr: number, maxBytes: number): number;
28
28
  lengthBytesUTF8(str: string): number;
29
29
  createFileHandle(): FileHandle;
30
+ /**
31
+ * The WASI host module this adapter wraps. Path mode's content gate
32
+ * (taglib-j9ld) needs the host's own detector and its WASI→host path
33
+ * resolution, neither of which belongs on the shared `TagLibModule` surface
34
+ * every backend implements.
35
+ */
36
+ get hostModule(): WasiModule;
37
+ /**
38
+ * The gated path open: `WasiFileHandle.loadFromPath` plus the content check a
39
+ * path needs where a buffer would be refused outright (see `path-open.ts`).
40
+ */
41
+ loadAudioPath(wasiPath: string, displayPath: string): Promise<WasmFileHandle>;
30
42
  version(): string;
31
43
  addFunction(_func: any): number;
32
44
  removeFunction(_ptr: number): void;
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../../src/runtime/wasi-adapter/adapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAKhE,qBAAa,mBAAoB,YAAW,YAAY;IACtD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;IAClC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;gBAEtB,UAAU,EAAE,UAAU;IAKlC,UAAU,EAMM,UAAU,UAAU,CAAC;IAErC,IAAI,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAEzB;IAED,IAAI,KAAK,IAAI,SAAS,CAErB;IAED,IAAI,MAAM,IAAI,UAAU,CAEvB;IAED,IAAI,MAAM,IAAI,UAAU,CAEvB;IAED,IAAI,MAAM,IAAI,UAAU,CAEvB;IAED,IAAI,OAAO,IAAI,WAAW,CAEzB;IAED,IAAI,OAAO,IAAI,WAAW,CAEzB;IAED,IAAI,OAAO,IAAI,YAAY,CAE1B;IAED,IAAI,OAAO,IAAI,YAAY,CAE1B;IAED,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAI7B,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIxB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM;IAe9C,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAOjC,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;IAQhE,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAIpC,gBAAgB,IAAI,UAAU;IAI9B,OAAO,IAAI,MAAM;IAIjB,WAAW,CAAC,KAAK,EAAE,GAAG,GAAG,MAAM;IAM/B,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAMlC,KAAK,CACH,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,SAAS,EAAE,MAAM,EAAE,GAClB,GAAG;IAMN,KAAK,CACH,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,SAAS,EAAE,MAAM,EAAE,EACnB,KAAK,EAAE,GAAG,EAAE,GACX,GAAG;CAKP"}
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../../src/runtime/wasi-adapter/adapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC9E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAMhE,qBAAa,mBAAoB,YAAW,YAAY;IACtD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;IAClC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;gBAEtB,UAAU,EAAE,UAAU;IAKlC,UAAU,EAMM,UAAU,UAAU,CAAC;IAErC,IAAI,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAEzB;IAED,IAAI,KAAK,IAAI,SAAS,CAErB;IAED,IAAI,MAAM,IAAI,UAAU,CAEvB;IAED,IAAI,MAAM,IAAI,UAAU,CAEvB;IAED,IAAI,MAAM,IAAI,UAAU,CAEvB;IAED,IAAI,OAAO,IAAI,WAAW,CAEzB;IAED,IAAI,OAAO,IAAI,WAAW,CAEzB;IAED,IAAI,OAAO,IAAI,YAAY,CAE1B;IAED,IAAI,OAAO,IAAI,YAAY,CAE1B;IAED,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAI7B,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIxB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM;IAe9C,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAOjC,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;IAQhE,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAIpC,gBAAgB,IAAI,UAAU;IAI9B;;;;;OAKG;IACH,IAAI,UAAU,IAAI,UAAU,CAE3B;IAED;;;OAGG;IACH,aAAa,CACX,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,cAAc,CAAC;IAI1B,OAAO,IAAI,MAAM;IAIjB,WAAW,CAAC,KAAK,EAAE,GAAG,GAAG,MAAM;IAM/B,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAMlC,KAAK,CACH,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,SAAS,EAAE,MAAM,EAAE,GAClB,GAAG;IAMN,KAAK,CACH,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,SAAS,EAAE,MAAM,EAAE,EACnB,KAAK,EAAE,GAAG,EAAE,GACX,GAAG;CAKP"}
@@ -4,6 +4,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
4
4
  import { WasmerExecutionError } from "../wasmer-sdk-loader/types.js";
5
5
  import { MemoryError } from "../../errors/classes.js";
6
6
  import { WasiFileHandle } from "./file-handle.js";
7
+ import { openAudioPath } from "./path-open.js";
7
8
  class WasiToTagLibAdapter {
8
9
  constructor(wasiModule) {
9
10
  __publicField(this, "wasi");
@@ -84,6 +85,22 @@ class WasiToTagLibAdapter {
84
85
  createFileHandle() {
85
86
  return new WasiFileHandle(this.wasi);
86
87
  }
88
+ /**
89
+ * The WASI host module this adapter wraps. Path mode's content gate
90
+ * (taglib-j9ld) needs the host's own detector and its WASI→host path
91
+ * resolution, neither of which belongs on the shared `TagLibModule` surface
92
+ * every backend implements.
93
+ */
94
+ get hostModule() {
95
+ return this.wasi;
96
+ }
97
+ /**
98
+ * The gated path open: `WasiFileHandle.loadFromPath` plus the content check a
99
+ * path needs where a buffer would be refused outright (see `path-open.ts`).
100
+ */
101
+ loadAudioPath(wasiPath, displayPath) {
102
+ return openAudioPath(this, wasiPath, displayPath);
103
+ }
87
104
  version() {
88
105
  return this.wasi.tl_version();
89
106
  }
@@ -8,7 +8,10 @@
8
8
  import type { AudioProperties } from "../../types.js";
9
9
  /** The audio-properties block of the C++ snapshot, null when absent. */
10
10
  export declare function getAudioProperties(tagData: Record<string, unknown> | null): AudioProperties | null;
11
- /** OGG codec sniffing: "OpusHead" in the first page payload, else OGG. */
11
+ /**
12
+ * OGG codec sniffing from the first page payload: "OpusHead" (Opus),
13
+ * 0x7F"FLAC" (FLAC-in-Ogg), "Speex " (Speex), else Ogg Vorbis ("OGG").
14
+ */
12
15
  export declare function detectOggCodec(fileData: Uint8Array): string;
13
16
  /**
14
17
  * Format detection: container-based first (works for path and buffer modes),
@@ -1 +1 @@
1
- {"version":3,"file":"audio-properties.d.ts","sourceRoot":"","sources":["../../../../src/runtime/wasi-adapter/audio-properties.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAEV,eAAe,EAEhB,MAAM,gBAAgB,CAAC;AAgBxB,wEAAwE;AACxE,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GACtC,eAAe,GAAG,IAAI,CA4BxB;AAED,0EAA0E;AAC1E,wBAAgB,cAAc,CAAC,QAAQ,EAAE,UAAU,GAAG,MAAM,CAe3D;AAED;;;GAGG;AACH,wBAAgB,SAAS,CACvB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,EACvC,QAAQ,EAAE,UAAU,GAAG,IAAI,GAC1B,MAAM,CAuDR;AAED,4EAA4E;AAC5E,wBAAgB,KAAK,CACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,EACvC,QAAQ,EAAE,UAAU,GAAG,IAAI,GAC1B,OAAO,CAYT"}
1
+ {"version":3,"file":"audio-properties.d.ts","sourceRoot":"","sources":["../../../../src/runtime/wasi-adapter/audio-properties.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAEV,eAAe,EAEhB,MAAM,gBAAgB,CAAC;AA6CxB,wEAAwE;AACxE,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GACtC,eAAe,GAAG,IAAI,CA4BxB;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,UAAU,GAAG,MAAM,CAsB3D;AAED;;;GAGG;AACH,wBAAgB,SAAS,CACvB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,EACvC,QAAQ,EAAE,UAAU,GAAG,IAAI,GAC1B,MAAM,CAyDR;AAED,4EAA4E;AAC5E,wBAAgB,KAAK,CACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,EACvC,QAAQ,EAAE,UAAU,GAAG,IAAI,GAC1B,OAAO,CAYT"}
@@ -6,11 +6,25 @@ const CONTAINER_TO_FORMAT = {
6
6
  OGG: "OGG",
7
7
  WAV: "WAV",
8
8
  AIFF: "AIFF",
9
+ ASF: "ASF",
10
+ APE: "APE",
11
+ DSF: "DSF",
12
+ DSDIFF: "DSDIFF",
9
13
  WavPack: "WV",
14
+ MPC: "MPC",
10
15
  TTA: "TTA",
11
- ASF: "ASF",
16
+ Shorten: "SHN",
17
+ MOD: "MOD",
18
+ S3M: "S3M",
19
+ IT: "IT",
20
+ XM: "XM",
12
21
  Matroska: "MATROSKA"
13
22
  };
23
+ const OGG_CODEC_TO_FORMAT = {
24
+ Opus: "OPUS",
25
+ FLAC: "OggFLAC",
26
+ Speex: "SPEEX"
27
+ };
14
28
  function getAudioProperties(tagData) {
15
29
  if (!tagData || !("sampleRate" in tagData)) return null;
16
30
  const d = tagData;
@@ -39,17 +53,20 @@ function detectOggCodec(fileData) {
39
53
  if (segCount === void 0) return "OGG";
40
54
  const payloadStart = 27 + segCount;
41
55
  if (fileData.length < payloadStart + 8) return "OGG";
42
- const sig = String.fromCharCode(
43
- ...fileData.slice(payloadStart, payloadStart + 8)
44
- );
45
- if (sig === "OpusHead") return "OPUS";
56
+ const sig = fileData.slice(payloadStart, payloadStart + 8);
57
+ const text = String.fromCharCode(...sig);
58
+ if (text === "OpusHead") return "OPUS";
59
+ if (sig[0] === 127 && sig[1] === 70 && sig[2] === 76 && sig[3] === 65 && sig[4] === 67) return "OggFLAC";
60
+ if (text === "Speex ") return "SPEEX";
46
61
  return "OGG";
47
62
  }
48
63
  function getFormat(tagData, fileData) {
49
64
  const container = tagData?.containerFormat;
50
65
  if (container) {
51
66
  const codec = tagData?.codec;
52
- if (container === "OGG" && codec === "Opus") return "OPUS";
67
+ if (container === "OGG" && codec && OGG_CODEC_TO_FORMAT[codec]) {
68
+ return OGG_CODEC_TO_FORMAT[codec];
69
+ }
53
70
  if (CONTAINER_TO_FORMAT[container]) return CONTAINER_TO_FORMAT[container];
54
71
  }
55
72
  if (!fileData || fileData.length < 8) return "unknown";
@@ -0,0 +1,68 @@
1
+ /**
2
+ * The gated path open for the WASI backend: `WasiFileHandle.loadFromPath` plus
3
+ * the content check a path needs and a buffer does not.
4
+ *
5
+ * `read_from_path` resolves the file class by *extension* first, and upstream's
6
+ * `MPEG::File` reports itself valid for any bytes at all (its `read()` never
7
+ * clears validity, `lib/taglib/taglib/mpeg/mpegfile.cpp`), so `junk.mp3` opens
8
+ * where the same bytes in a buffer are refused. Two independent signals say
9
+ * whether anything was really there, in cost order:
10
+ *
11
+ * 1. {@link statesAudioProperties} — whether the parse read an audio property
12
+ * out of the file. No extra I/O: the snapshot is what the open already
13
+ * produced. A file that states a sample rate is audio TagLib read, whatever
14
+ * its head looks like — which is how an MP3 behind a 4 KiB or 70 KiB APEv2
15
+ * tag (this repo's own corpus shapes, tests/media-checksum-corpus.test.ts)
16
+ * stays readable even though neither detector can see the frames behind the
17
+ * tag.
18
+ * 2. {@link hasRecognizableHead} — whether the head is content the boundary's
19
+ * detector knows, or opens as a buffer. This is what saves a file whose
20
+ * properties are legitimately absent (`lib/taglib/tests/data/segfault.wav`
21
+ * is 30 bytes of `RIFF`/`WAVE`; `tests/test-files/mp4/synth-multi-mdat.mp4`
22
+ * has `ftyp` and no `moov`) and every tag-only file, whose head *is* its tag:
23
+ * content is recognizable even when there is nothing to measure.
24
+ *
25
+ * A path is refused only when *both* say nothing — a zero-length file, junk
26
+ * bytes behind an audio extension. That is the shape of every refusal in this
27
+ * repo's and upstream's corpora (163 fixtures, swept by
28
+ * `tests/checksum-input-contract.test.ts`), and neither signal can refuse a file
29
+ * the buffer form accepts: every detector rule is head-based (MOD's signature at
30
+ * offset 1080 is the deepest, and the window clears it), the ID3v2 rule answers
31
+ * "MP3" rather than giving up when the tag runs past the window
32
+ * (`src/capi/taglib_boundary.c`, `tl_detect_format`), and a head that opens as a
33
+ * buffer *is* the buffer form's own verdict.
34
+ *
35
+ * The one asymmetry that survives is upstream's deliberately corrupt fixtures
36
+ * whose bytes still yield a property (`garbage.mp3`, `sv4_header.mpc`,
37
+ * `sv5_header.mpc`, `stripped.xm`): TagLib reads a header out of them, so the
38
+ * path form keeps accepting them exactly as it did before this change, while the
39
+ * buffer form's narrower magic rules refuse them. Nothing in the C detector can
40
+ * place SV4/SV5 MPC or junk-with-a-frame-header — see taglib-uat8 for that
41
+ * reachability gap — and refusing them here would mean refusing files the parse
42
+ * did read.
43
+ */
44
+ import type { FileHandle, WasmFileHandle } from "../../wasm.js";
45
+ import type { WasiModule } from "../wasmer-sdk-loader/types.js";
46
+ /** The WASI backend this open runs on: its host module (where the detector and
47
+ * the WASI→host path resolution live, `WasiToTagLibAdapter.hostModule`) and its
48
+ * handle factory. */
49
+ export interface PathOpenHost {
50
+ readonly hostModule: WasiModule;
51
+ createFileHandle(): FileHandle;
52
+ }
53
+ /**
54
+ * Load an audio file by path, verifying that its content is audio.
55
+ *
56
+ * Every failure the caller can act on is distinct: `FileOperationError` for a
57
+ * path the host does not have (what the buffer form's own stat answers, so a
58
+ * typo reads the same on both backends), `InvalidFormatError` for a zero-byte
59
+ * file (see below) and for content the boundary could not resolve as audio, and
60
+ * the wasm-level errors unchanged. Either content signal above suffices; both
61
+ * saying nothing is a refusal.
62
+ *
63
+ * The returned handle is the library-owned one (the WASI brand asserted here,
64
+ * the WASI equivalent of `wrapEmbindHandle`), destroyed on any failure — the
65
+ * caller's `AudioFile` takes it over on success.
66
+ */
67
+ export declare function openAudioPath(backend: PathOpenHost, wasiPath: string, displayPath: string): Promise<WasmFileHandle>;
68
+ //# sourceMappingURL=path-open.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path-open.d.ts","sourceRoot":"","sources":["../../../../src/runtime/wasi-adapter/path-open.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAChE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAqBhE;;qBAEqB;AACrB,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,gBAAgB,IAAI,UAAU,CAAC;CAChC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,YAAY,EACrB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,cAAc,CAAC,CA0CzB"}
@@ -0,0 +1,76 @@
1
+ import {
2
+ FileOperationError,
3
+ InvalidFormatError
4
+ } from "../../errors/classes.js";
5
+ import { getFileSize, readPartialFileData } from "../../utils/file.js";
6
+ import { readTagsFromWasm } from "./wasm-io.js";
7
+ const TL_FORMAT_AUTO = 0;
8
+ const HEADER_WINDOW = 4096;
9
+ async function openAudioPath(backend, wasiPath, displayPath) {
10
+ const hostPath = backend.hostModule.hostPathFor(wasiPath);
11
+ if (hostPath === void 0) {
12
+ throw new FileOperationError(
13
+ "read",
14
+ "The path is outside the WASI preopens this host was created with",
15
+ displayPath
16
+ );
17
+ }
18
+ if (await getFileSize(hostPath) === 0) {
19
+ throw new InvalidFormatError(
20
+ `The file is empty. Path: ${displayPath}`
21
+ );
22
+ }
23
+ const handle = backend.createFileHandle();
24
+ try {
25
+ const loaded = handle.loadFromPath(wasiPath);
26
+ if (!loaded) {
27
+ throw new InvalidFormatError(
28
+ `Failed to load audio file. Path: ${displayPath}`
29
+ );
30
+ }
31
+ if (!await holdsAudio(backend, wasiPath, handle)) {
32
+ throw new InvalidFormatError(
33
+ `Failed to load audio file. File may be corrupted or in an unsupported format. Path: ${displayPath}`
34
+ );
35
+ }
36
+ return handle;
37
+ } catch (error) {
38
+ handle.destroy();
39
+ throw error;
40
+ }
41
+ }
42
+ async function holdsAudio(backend, wasiPath, handle) {
43
+ return statesAudioProperties(handle) || await hasRecognizableHead(backend, wasiPath);
44
+ }
45
+ function statesAudioProperties(handle) {
46
+ const audio = handle.getAudioProperties();
47
+ return audio !== null && (audio.sampleRate > 0 || audio.channels > 0 || audio.bitrate > 0 || audio.duration > 0 || audio.bitsPerSample > 0);
48
+ }
49
+ async function hasRecognizableHead(backend, wasiPath) {
50
+ const wasi = backend.hostModule;
51
+ const hostPath = wasi.hostPathFor(wasiPath);
52
+ if (hostPath === void 0) return false;
53
+ const head = await readPartialFileData(hostPath, HEADER_WINDOW, 0);
54
+ return detectsFormat(wasi, head) || opensAsBuffer(wasi, head);
55
+ }
56
+ function detectsFormat(wasi, head) {
57
+ const ptr = wasi.malloc(Math.max(head.length, 1));
58
+ try {
59
+ new Uint8Array(wasi.memory.buffer).set(head, ptr);
60
+ return wasi.tl_detect_format(ptr, head.length) !== TL_FORMAT_AUTO;
61
+ } finally {
62
+ wasi.free(ptr);
63
+ }
64
+ }
65
+ function opensAsBuffer(wasi, head) {
66
+ try {
67
+ readTagsFromWasm(wasi, head);
68
+ return true;
69
+ } catch (error) {
70
+ if (error instanceof InvalidFormatError) return false;
71
+ throw error;
72
+ }
73
+ }
74
+ export {
75
+ openAudioPath
76
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"wasm-io.d.ts","sourceRoot":"","sources":["../../../../src/runtime/wasi-adapter/wasm-io.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAYhE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAKnD,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,UAAU,GACjB,UAAU,CAoCZ;AAED,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,MAAM,GACX,UAAU,CA8BZ;AAED,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,UAAU,GAAG,MAAM,EAC3B,EAAE,CAAC,EAAE,MAAM,GACV,aAAa,EAAE,CA8CjB;AAED,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,WAAW,GACnB,OAAO,CA2BT;AAED,wBAAgB,eAAe,CAC7B,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,UAAU,EACpB,OAAO,EAAE,WAAW,GACnB,UAAU,GAAG,IAAI,CA8BnB"}
1
+ {"version":3,"file":"wasm-io.d.ts","sourceRoot":"","sources":["../../../../src/runtime/wasi-adapter/wasm-io.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAahE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAyDnD,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,UAAU,GACjB,UAAU,CA2BZ;AAED,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,MAAM,GACX,UAAU,CAqBZ;AAED,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,UAAU,GAAG,MAAM,EAC3B,EAAE,CAAC,EAAE,MAAM,GACV,aAAa,EAAE,CA0CjB;AAED,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,WAAW,GACnB,OAAO,CA0BT;AAED,wBAAgB,eAAe,CAC7B,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,UAAU,EACpB,OAAO,EAAE,WAAW,GACnB,UAAU,GAAG,IAAI,CA8BnB"}
@@ -48,13 +48,38 @@ import {
48
48
  WasmMemoryError
49
49
  } from "../wasi-memory.js";
50
50
  import {
51
+ FileOperationError,
51
52
  InvalidFormatError,
52
53
  UnsupportedFormatError
53
54
  } from "../../errors/classes.js";
54
55
  import { encodeTagData } from "../../msgpack/encoder.js";
55
56
  import { decodeMessagePack } from "../../msgpack/decoder.js";
57
+ const TL_ERROR_INVALID_INPUT = -1;
56
58
  const TL_ERROR_UNSUPPORTED_FORMAT = -2;
59
+ const TL_ERROR_MEMORY_ALLOCATION = -3;
60
+ const TL_ERROR_IO_READ = -4;
61
+ const TL_ERROR_IO_WRITE = -5;
57
62
  const TL_ERROR_PARSE_FAILED = -6;
63
+ function throwForErrorCode(errorCode, operation, where, bufferSize) {
64
+ switch (errorCode) {
65
+ case TL_ERROR_INVALID_INPUT:
66
+ case TL_ERROR_UNSUPPORTED_FORMAT:
67
+ case TL_ERROR_IO_READ:
68
+ case TL_ERROR_PARSE_FAILED:
69
+ throw new InvalidFormatError(
70
+ `File may be corrupted or in an unsupported format${where}`,
71
+ bufferSize
72
+ );
73
+ case TL_ERROR_IO_WRITE:
74
+ throw new FileOperationError("write", `Failed to write tags${where}`);
75
+ default:
76
+ throw new WasmMemoryError(
77
+ `error code ${errorCode}${where}`,
78
+ operation,
79
+ errorCode
80
+ );
81
+ }
82
+ }
58
83
  function readTagsFromWasm(wasi, buffer) {
59
84
  var _stack = [];
60
85
  try {
@@ -68,17 +93,11 @@ function readTagsFromWasm(wasi, buffer) {
68
93
  outSizePtr.ptr
69
94
  );
70
95
  if (resultPtr === 0) {
71
- const errorCode = wasi.tl_get_last_error_code();
72
- if (errorCode === TL_ERROR_UNSUPPORTED_FORMAT || errorCode === TL_ERROR_PARSE_FAILED) {
73
- throw new InvalidFormatError(
74
- "File may be corrupted or in an unsupported format",
75
- buffer.length
76
- );
77
- }
78
- throw new WasmMemoryError(
79
- `error code ${errorCode}. Buffer size: ${buffer.length} bytes`,
96
+ throwForErrorCode(
97
+ wasi.tl_get_last_error_code(),
80
98
  "read tags",
81
- errorCode
99
+ `. Buffer size: ${buffer.length} bytes`,
100
+ buffer.length
82
101
  );
83
102
  }
84
103
  const outSize = outSizePtr.readUint32();
@@ -100,16 +119,10 @@ function readTagsFromWasmPath(wasi, path) {
100
119
  const outSizePtr = arena.allocUint32();
101
120
  const resultPtr = wasi.tl_read_tags(pathAlloc.ptr, 0, 0, outSizePtr.ptr);
102
121
  if (resultPtr === 0) {
103
- const errorCode = wasi.tl_get_last_error_code();
104
- if (errorCode === TL_ERROR_UNSUPPORTED_FORMAT || errorCode === TL_ERROR_PARSE_FAILED) {
105
- throw new InvalidFormatError(
106
- `File may be corrupted or in an unsupported format. Path: ${path}`
107
- );
108
- }
109
- throw new WasmMemoryError(
110
- `error code ${errorCode}. Path: ${path}`,
122
+ throwForErrorCode(
123
+ wasi.tl_get_last_error_code(),
111
124
  "read tags from path",
112
- errorCode
125
+ `. Path: ${path}`
113
126
  );
114
127
  }
115
128
  const outSize = outSizePtr.readUint32();
@@ -156,11 +169,7 @@ function readId3v2FramesFromWasm(wasi, source, id) {
156
169
  operation: "readId3v2Frames"
157
170
  });
158
171
  }
159
- throw new WasmMemoryError(
160
- `error code ${errorCode}`,
161
- "read ID3v2 frames",
162
- errorCode
163
- );
172
+ throwForErrorCode(errorCode, "read ID3v2 frames", "");
164
173
  }
165
174
  const outSize = outSizePtr.readUint32();
166
175
  const u8 = new Uint8Array(wasi.memory.buffer);
@@ -191,11 +200,10 @@ function writeTagsToWasmPath(wasi, path, tagData) {
191
200
  outSizePtr.ptr
192
201
  );
193
202
  if (result !== 0) {
194
- const errorCode = wasi.tl_get_last_error_code();
195
- throw new WasmMemoryError(
196
- `error code ${errorCode}. Path: ${path}`,
203
+ throwForErrorCode(
204
+ wasi.tl_get_last_error_code(),
197
205
  "write tags to path",
198
- errorCode
206
+ `. Path: ${path}`
199
207
  );
200
208
  }
201
209
  return true;
@@ -2,7 +2,7 @@ import {
2
2
  createWasiImports
3
3
  } from "./wasi-host.js";
4
4
  import { TagLibError } from "../errors/base.js";
5
- import { fileUrlToPath } from "../utils/path.js";
5
+ import { fileUrlToPath, hostPathForPreopens } from "../utils/path.js";
6
6
  import { isDeno } from "./detector.js";
7
7
  class WasiHostLoadError extends TagLibError {
8
8
  constructor(message, cause) {
@@ -55,7 +55,7 @@ async function loadWasiHost(config) {
55
55
  if (instance.exports._initialize) {
56
56
  instance.exports._initialize();
57
57
  }
58
- return createWasiModuleFromInstance(instance, memory, wasiImports);
58
+ return createWasiModuleFromInstance(instance, memory, wasiImports, preopens);
59
59
  }
60
60
  async function loadWasmBinary(path, fs) {
61
61
  if (path.startsWith("http://") || path.startsWith("https://")) {
@@ -76,7 +76,7 @@ async function loadWasmBinary(path, fs) {
76
76
  );
77
77
  }
78
78
  }
79
- function createWasiModuleFromInstance(instance, memory, wasiImports) {
79
+ function createWasiModuleFromInstance(instance, memory, wasiImports, preopens) {
80
80
  const exports = instance.exports;
81
81
  function readCString(ptr) {
82
82
  if (!ptr) return "";
@@ -96,6 +96,11 @@ function createWasiModuleFromInstance(instance, memory, wasiImports) {
96
96
  tl_read_tags: (pathPtr, bufPtr, len, outSizePtr) => exports.tl_read_tags(pathPtr, bufPtr, len, outSizePtr),
97
97
  tl_read_id3v2_frames: (pathPtr, bufPtr, len, idPtr, outSizePtr) => exports.tl_read_id3v2_frames(pathPtr, bufPtr, len, idPtr, outSizePtr),
98
98
  tl_write_tags: (pathPtr, bufPtr, len, tagsPtr, tagsSz, outPtr, outSzPtr) => exports.tl_write_tags(pathPtr, bufPtr, len, tagsPtr, tagsSz, outPtr, outSzPtr),
99
+ tl_detect_format: (bufPtr, len) => exports.tl_detect_format(
100
+ bufPtr,
101
+ len
102
+ ),
103
+ hostPathFor: (wasiPath) => hostPathForPreopens(wasiPath, preopens),
99
104
  tl_get_last_error: () => exports.tl_get_last_error(),
100
105
  tl_get_last_error_code: () => exports.tl_get_last_error_code(),
101
106
  tl_clear_error: () => exports.tl_clear_error(),
@@ -16,6 +16,19 @@ export interface WasiModule {
16
16
  tl_read_tags(pathPtr: number, bufPtr: number, len: number, outSizePtr: number): number;
17
17
  tl_read_id3v2_frames(pathPtr: number, bufPtr: number, len: number, idPtr: number, outSizePtr: number): number;
18
18
  tl_write_tags(pathPtr: number, bufPtr: number, len: number, tagsPtr: number, tagsSize: number, outBufPtr: number, outSizePtr: number): number;
19
+ /**
20
+ * The boundary's content detector (`src/capi/taglib_boundary.c`), the one the
21
+ * buffer open runs before it picks a file class: a `tl_format` value, or
22
+ * `TL_FORMAT_AUTO` (0) when the bytes are not a container it knows.
23
+ */
24
+ tl_detect_format(bufPtr: number, len: number): number;
25
+ /**
26
+ * The host path behind a WASI path, resolved through the preopens this host
27
+ * was created with, or undefined when no preopen covers it. Host-side code
28
+ * cannot otherwise read a file the guest reads (`utils/path.ts` carries the
29
+ * rule); the path content gate is the only caller.
30
+ */
31
+ hostPathFor(wasiPath: string): string | undefined;
19
32
  tl_get_last_error(): number;
20
33
  tl_get_last_error_code(): number;
21
34
  tl_clear_error(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/runtime/wasmer-sdk-loader/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,qBAAa,oBAAqB,SAAQ,WAAW;gBACvC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;CAM7C;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IAEzB,UAAU,IAAI,MAAM,CAAC;IACrB,cAAc,IAAI,MAAM,CAAC;IAGzB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAGxB,YAAY,CACV,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,GACjB,MAAM,CAAC;IACV,oBAAoB,CAClB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,GACjB,MAAM,CAAC;IACV,aAAa,CACX,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,MAAM,CAAC;IAGV,iBAAiB,IAAI,MAAM,CAAC;IAC5B,sBAAsB,IAAI,MAAM,CAAC;IACjC,cAAc,IAAI,IAAI,CAAC;IAGvB,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC;CAC5B"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/runtime/wasmer-sdk-loader/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,qBAAa,oBAAqB,SAAQ,WAAW;gBACvC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;CAM7C;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IAEzB,UAAU,IAAI,MAAM,CAAC;IACrB,cAAc,IAAI,MAAM,CAAC;IAGzB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAGxB,YAAY,CACV,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,GACjB,MAAM,CAAC;IACV,oBAAoB,CAClB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,GACjB,MAAM,CAAC;IACV,aAAa,CACX,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,MAAM,CAAC;IAEV;;;;OAIG;IACH,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IAEtD;;;;;OAKG;IACH,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IAGlD,iBAAiB,IAAI,MAAM,CAAC;IAC5B,sBAAsB,IAAI,MAAM,CAAC;IACjC,cAAc,IAAI,IAAI,CAAC;IAGvB,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC;CAC5B"}
@@ -0,0 +1,25 @@
1
+ import type { AudioFileInput } from "../types.js";
2
+ import type { MediaChecksum, MediaChecksumOptions } from "../taglib/audio-file-checksum.js";
3
+ /**
4
+ * Reads a checksum of an audio file's media content.
5
+ *
6
+ * The digest is of the *encoded media payload* — the bytes that are the audio,
7
+ * not the tags around them — so it survives a tag edit, with one boundary: an
8
+ * ID3v2 tag appended after a FLAC's audio is inside that payload, so editing it
9
+ * does move the hash. Formats whose payload cannot be delimited answer the
10
+ * whole file instead and say so (`source: "file"`), where a tag edit does move
11
+ * the hash.
12
+ *
13
+ * @param file - File path, Uint8Array, ArrayBuffer, or File object
14
+ * @param options - `basis: "pcm"` asks for FLAC's STREAMINFO MD5, the digest of
15
+ * the *uncompressed* stream, instead of the encoded payload's SHA-256
16
+ * @returns The hex digest, the algorithm, what it covers (`source`), and how
17
+ * many bytes were hashed
18
+ * @throws {TagLibInitializationError} If the Wasm module fails to initialize
19
+ * @throws {InvalidFormatError} If the file is corrupted or in an unsupported format
20
+ * @throws {UnsupportedFormatError} If `basis: "pcm"` is asked of a non-FLAC file
21
+ * @throws {MetadataError} If the payload cannot be walked, or the handle holds
22
+ * no bytes and no readable source
23
+ */
24
+ export declare function readMediaChecksum(file: AudioFileInput, options?: MediaChecksumOptions): Promise<MediaChecksum>;
25
+ //# sourceMappingURL=checksum-operations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checksum-operations.d.ts","sourceRoot":"","sources":["../../../src/simple/checksum-operations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EACV,aAAa,EACb,oBAAoB,EACrB,MAAM,kCAAkC,CAAC;AAG1C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,cAAc,EACpB,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,aAAa,CAAC,CAExB"}
@@ -0,0 +1,7 @@
1
+ import { withAudioFile } from "./with-audio-file.js";
2
+ async function readMediaChecksum(file, options) {
3
+ return withAudioFile(file, (audioFile) => audioFile.mediaChecksum(options));
4
+ }
5
+ export {
6
+ readMediaChecksum
7
+ };
@@ -3,6 +3,8 @@ export { applyTags, applyTagsToFile, clearTags, isValidAudioFile, readFormat, re
3
3
  export { addPicture, applyCoverArt, applyPictures, clearPictures, findPictureByType, readCoverArt, readPictureMetadata, readPictures, replacePictureByType, } from "./picture-operations.js";
4
4
  export { editTagsBatch, readMetadata, readMetadataBatch, readPropertiesBatch, readTagsBatch, writeTagsBatch, } from "./batch-operations.js";
5
5
  export type { BatchItem, BatchOptions, BatchResult, FileMetadata, WriteTagUpdate, } from "./batch-operations.js";
6
+ export { readMediaChecksum } from "./checksum-operations.js";
7
+ export type { ChecksumAlgorithm, ChecksumSource, MediaChecksum, MediaChecksumOptions, } from "../taglib/audio-file-checksum.js";
6
8
  export type { AudioProperties, ExtendedTag, Picture, PictureType, Tag, TagInput, } from "../types.js";
7
9
  export { PICTURE_TYPE_NAMES, PICTURE_TYPE_VALUES } from "../types.js";
8
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/simple/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEvD,OAAO,EACL,SAAS,EACT,eAAe,EACf,SAAS,EACT,gBAAgB,EAChB,UAAU,EACV,cAAc,EACd,QAAQ,GACT,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,UAAU,EACV,aAAa,EACb,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,YAAY,EACZ,mBAAmB,EACnB,YAAY,EACZ,oBAAoB,GACrB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EACnB,aAAa,EACb,cAAc,GACf,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACV,SAAS,EACT,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,cAAc,GACf,MAAM,uBAAuB,CAAC;AAE/B,YAAY,EACV,eAAe,EACf,WAAW,EACX,OAAO,EACP,WAAW,EACX,GAAG,EACH,QAAQ,GACT,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/simple/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEvD,OAAO,EACL,SAAS,EACT,eAAe,EACf,SAAS,EACT,gBAAgB,EAChB,UAAU,EACV,cAAc,EACd,QAAQ,GACT,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,UAAU,EACV,aAAa,EACb,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,YAAY,EACZ,mBAAmB,EACnB,YAAY,EACZ,oBAAoB,GACrB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EACnB,aAAa,EACb,cAAc,GACf,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACV,SAAS,EACT,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,cAAc,GACf,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,YAAY,EACV,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,oBAAoB,GACrB,MAAM,kCAAkC,CAAC;AAE1C,YAAY,EACV,eAAe,EACf,WAAW,EACX,OAAO,EACP,WAAW,EACX,GAAG,EACH,QAAQ,GACT,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC"}
@@ -27,6 +27,7 @@ import {
27
27
  readTagsBatch,
28
28
  writeTagsBatch
29
29
  } from "./batch-operations.js";
30
+ import { readMediaChecksum } from "./checksum-operations.js";
30
31
  import { PICTURE_TYPE_NAMES, PICTURE_TYPE_VALUES } from "../types.js";
31
32
  export {
32
33
  PICTURE_TYPE_NAMES,
@@ -44,6 +45,7 @@ export {
44
45
  isValidAudioFile,
45
46
  readCoverArt,
46
47
  readFormat,
48
+ readMediaChecksum,
47
49
  readMetadata,
48
50
  readMetadataBatch,
49
51
  readPictureMetadata,