archive-codec 1.1.2 → 1.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.
package/README.md CHANGED
@@ -32,33 +32,33 @@ To run a single test file, pass its path to vitest directly, e.g. `pnpm exec vit
32
32
  Every module is importable by package-relative path as well as through the barrel — `tsdown` builds one dist file per src module (`root: 'src'`, the same layout ooxml.js ships), and `package.json`'s `./*` exports wildcard maps each subpath onto it:
33
33
 
34
34
  ```ts
35
- import { readCompoundFile } from 'archive-codec/cfb/read';
36
- import { walkArchive } from 'archive-codec/zip/walk';
35
+ import { readCompoundFile } from "archive-codec/cfb/read";
36
+ import { walkArchive } from "archive-codec/zip/walk";
37
37
  ```
38
38
 
39
39
  The smoke suite (`test/smoke.test.mjs`) is the guard on that advertisement: it loads each module below from the built `dist/` in both module systems, so a build config that stops serving an advertised subpath fails the suite — neither publint nor `attw` catches a wildcard whose targets are missing.
40
40
 
41
- | Module | Exports |
42
- |---|---|
43
- | `zip/container` | `zipPackage` (ordered-entries ZIP write with stored-uncompressed support), `unzipPackage`, `ZipEntry` |
44
- | `zip/detect` | `detectArchiveFormat` (`'zip' \| 'cfb' \| 'unknown'`), `isZipArchive`, `ArchiveFormat` |
45
- | `zip/walk` | `walkArchive` (recursive ZIP-in-ZIP walking), `ArchiveWalkEntry`, `ArchiveWalkLimitError`, `MAX_WALK_DEPTH`, `MAX_WALK_TOTAL_BYTES`, `WalkArchiveOptions` |
46
- | `cfb/detect` | `isCompoundFile` (the `D0 CF 11 E0 …` magic-byte check) |
47
- | `cfb/read` | `readCompoundFile` (bounded [MS-CFB] stream extraction), `CompoundFileStream`, `CompoundFileFormatError`, `MAX_CFB_TOTAL_STREAM_BYTES`, `ReadCompoundFileOptions` |
48
- | `cfb/ole-package` | `readOlePackage` (OLE Package stream unwrapping), `OlePackage`, `OlePackageFormatError` |
41
+ | Module | Exports |
42
+ | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
43
+ | `zip/container` | `zipPackage` (ordered-entries ZIP write with stored-uncompressed support), `unzipPackage`, `ZipEntry` |
44
+ | `zip/detect` | `detectArchiveFormat` (`'zip' \| 'cfb' \| 'unknown'`), `isZipArchive`, `ArchiveFormat` |
45
+ | `zip/walk` | `walkArchive` (recursive ZIP-in-ZIP walking), `ArchiveWalkEntry`, `ArchiveWalkLimitError`, `MAX_WALK_DEPTH`, `MAX_WALK_TOTAL_BYTES`, `WalkArchiveOptions` |
46
+ | `cfb/detect` | `isCompoundFile` (the `D0 CF 11 E0 …` magic-byte check) |
47
+ | `cfb/read` | `readCompoundFile` (bounded [MS-CFB] stream extraction), `CompoundFileStream`, `CompoundFileFormatError`, `MAX_CFB_TOTAL_STREAM_BYTES`, `ReadCompoundFileOptions` |
48
+ | `cfb/ole-package` | `readOlePackage` (OLE Package stream unwrapping), `OlePackage`, `OlePackageFormatError` |
49
49
 
50
50
  ### Recursive walking
51
51
 
52
52
  ```ts
53
- import { walkArchive } from 'archive-codec';
53
+ import { walkArchive } from "archive-codec";
54
54
 
55
55
  // Every entry of every nested ZIP, flattened. Throws ArchiveWalkLimitError if
56
56
  // the walk exceeds the depth cap or the cumulative decompressed-bytes budget.
57
57
  for (const entry of walkArchive(docxBytes)) {
58
- entry.path; // e.g. 'xl/workbook.xml', the path within its own archive
58
+ entry.path; // e.g. 'xl/workbook.xml', the path within its own archive
59
59
  entry.ancestors; // e.g. ['word/embeddings/oleObject1.xlsx'] -- the nested
60
- // ZIP entries descended through to reach this one
61
- entry.bytes; // decompressed content
60
+ // ZIP entries descended through to reach this one
61
+ entry.bytes; // decompressed content
62
62
  }
63
63
  ```
64
64
 
@@ -67,18 +67,20 @@ Both guards throw rather than truncate: an input outside the contract must fail
67
67
  ### Compound files
68
68
 
69
69
  ```ts
70
- import { readCompoundFile, readOlePackage } from 'archive-codec';
70
+ import { readCompoundFile, readOlePackage } from "archive-codec";
71
71
 
72
72
  // Every stream of a classic OLE compound file, with its storage path.
73
73
  // Throws CompoundFileFormatError on any structural nonconformance.
74
74
  for (const stream of readCompoundFile(oleBinBytes)) {
75
- stream.path; // e.g. 'Package' -- root-level, or 'ObjectStorage/Package'
75
+ stream.path; // e.g. 'Package' -- root-level, or 'ObjectStorage/Package'
76
76
  stream.bytes; // the stream's content
77
77
  }
78
78
 
79
79
  // The OLE packaging a Word/PowerPoint embed wraps the real file in before
80
80
  // storing it as the 'Package' stream: label, paths, and the file's bytes.
81
- const packageStream = readCompoundFile(oleBinBytes).find((s) => s.path === 'Package');
81
+ const packageStream = readCompoundFile(oleBinBytes).find(
82
+ (s) => s.path === "Package",
83
+ );
82
84
  if (packageStream !== undefined) {
83
85
  readOlePackage(packageStream.bytes).fileBytes; // often a ZIP for a modern embed
84
86
  }
@@ -88,7 +90,7 @@ Reading is bounded the same way walking is: chain cycles and out-of-range sector
88
90
 
89
91
  ### ZIP container
90
92
 
91
- `zipPackage` takes an *ordered* array of `[path, entry]` tuples, not a `Record`, so the caller controls the exact emission order deterministically (the property formats with a fixed-offset first entry — ODF's `mimetype` — depend on), and any entry can be written stored-uncompressed via `stored: true`. `unzipPackage` is the read side; the returned `Record` makes no ordering promise and collapses duplicate paths.
93
+ `zipPackage` takes an _ordered_ array of `[path, entry]` tuples, not a `Record`, so the caller controls the exact emission order deterministically (the property formats with a fixed-offset first entry — ODF's `mimetype` — depend on), and any entry can be written stored-uncompressed via `stored: true`. `unzipPackage` is the read side; the returned `Record` makes no ordering promise and collapses duplicate paths.
92
94
 
93
95
  ## Conventions
94
96
 
package/dist/cfb/read.cjs CHANGED
@@ -113,7 +113,7 @@ function readCompoundFile(bytes, options = {}) {
113
113
  });
114
114
  }
115
115
  const root = entries[0];
116
- if (root === void 0 || root.objectType !== OBJECT_TYPE_ROOT) throw new CompoundFileFormatError("the first directory entry is not the root storage entry (object type 5), as [MS-CFB] 2.6.1 requires");
116
+ if (root?.objectType !== OBJECT_TYPE_ROOT) throw new CompoundFileFormatError("the first directory entry is not the root storage entry (object type 5), as [MS-CFB] 2.6.1 requires");
117
117
  const miniStream = chainBytes(root.startSector).subarray(0, root.size);
118
118
  const miniSectorCount = Math.floor(miniStream.length / miniSectorSize);
119
119
  const miniFatBytes = chainBytes(firstMiniFatSector);
package/dist/cfb/read.js CHANGED
@@ -112,7 +112,7 @@ function readCompoundFile(bytes, options = {}) {
112
112
  });
113
113
  }
114
114
  const root = entries[0];
115
- if (root === void 0 || root.objectType !== OBJECT_TYPE_ROOT) throw new CompoundFileFormatError("the first directory entry is not the root storage entry (object type 5), as [MS-CFB] 2.6.1 requires");
115
+ if (root?.objectType !== OBJECT_TYPE_ROOT) throw new CompoundFileFormatError("the first directory entry is not the root storage entry (object type 5), as [MS-CFB] 2.6.1 requires");
116
116
  const miniStream = chainBytes(root.startSector).subarray(0, root.size);
117
117
  const miniSectorCount = Math.floor(miniStream.length / miniSectorSize);
118
118
  const miniFatBytes = chainBytes(firstMiniFatSector);
@@ -1,5 +1,5 @@
1
1
  //#region src/zip/detect.d.ts
2
- type ArchiveFormat = 'zip' | 'cfb' | 'unknown';
2
+ type ArchiveFormat = "zip" | "cfb" | "unknown";
3
3
  declare function isZipArchive(bytes: Uint8Array): boolean;
4
4
  declare function detectArchiveFormat(bytes: Uint8Array): ArchiveFormat;
5
5
  //#endregion
@@ -1,5 +1,5 @@
1
1
  //#region src/zip/detect.d.ts
2
- type ArchiveFormat = 'zip' | 'cfb' | 'unknown';
2
+ type ArchiveFormat = "zip" | "cfb" | "unknown";
3
3
  declare function isZipArchive(bytes: Uint8Array): boolean;
4
4
  declare function detectArchiveFormat(bytes: Uint8Array): ArchiveFormat;
5
5
  //#endregion
@@ -6,7 +6,7 @@ interface ArchiveWalkEntry {
6
6
  readonly ancestors: readonly string[];
7
7
  readonly bytes: Uint8Array<ArrayBuffer>;
8
8
  }
9
- type ArchiveWalkLimit = 'depth' | 'total-bytes';
9
+ type ArchiveWalkLimit = "depth" | "total-bytes";
10
10
  declare class ArchiveWalkLimitError extends Error {
11
11
  readonly limit: ArchiveWalkLimit;
12
12
  constructor(limit: ArchiveWalkLimit, message: string);
@@ -6,7 +6,7 @@ interface ArchiveWalkEntry {
6
6
  readonly ancestors: readonly string[];
7
7
  readonly bytes: Uint8Array<ArrayBuffer>;
8
8
  }
9
- type ArchiveWalkLimit = 'depth' | 'total-bytes';
9
+ type ArchiveWalkLimit = "depth" | "total-bytes";
10
10
  declare class ArchiveWalkLimitError extends Error {
11
11
  readonly limit: ArchiveWalkLimit;
12
12
  constructor(limit: ArchiveWalkLimit, message: string);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "archive-codec",
3
- "version": "1.1.2",
3
+ "version": "1.2.0",
4
4
  "description": "ZIP-in-ZIP recursive walking with depth and cumulative decompressed-size guards, plus bounded classic OLE compound-file ([MS-CFB]) reading - zero document-format knowledge, the archive and container utility package for the documents.js family.",
5
5
  "type": "module",
6
6
  "repository": {
@@ -72,22 +72,13 @@
72
72
  "devDependencies": {
73
73
  "@arethetypeswrong/cli": "^0.18.5",
74
74
  "@cloudflare/vitest-pool-workers": "^0.20.1",
75
- "@commitlint/cli": "^21.2.1",
76
- "@commitlint/config-conventional": "^21.2.0",
77
- "@eslint/js": "^10.0.1",
78
- "@semantic-release/changelog": "^7.0.0",
79
- "@semantic-release/git": "^11.0.1",
80
75
  "@types/node": "^26.1.2",
81
76
  "eslint": "^10.8.0",
82
- "globals": "^17.8.0",
83
77
  "husky": "^9.1.7",
84
- "lint-staged": "^17.2.0",
85
78
  "publint": "^0.3.21",
86
- "semantic-release": "^25.0.8",
87
79
  "tsdown": "^0.22.13",
88
80
  "turbo": "^2.10.8",
89
81
  "typescript": "^6.0.3",
90
- "typescript-eslint": "^8.65.0",
91
82
  "vitest": "^4.1.10"
92
83
  },
93
84
  "lint-staged": {