archive-codec 1.0.2 → 1.1.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.
@@ -0,0 +1,41 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_zip_container = require("./container.cjs");
3
+ const require_zip_detect = require("./detect.cjs");
4
+ //#region src/zip/walk.ts
5
+ const MAX_WALK_DEPTH = 8;
6
+ const MAX_WALK_TOTAL_BYTES = 536870912;
7
+ var ArchiveWalkLimitError = class extends Error {
8
+ limit;
9
+ constructor(limit, message) {
10
+ super(message);
11
+ this.name = "ArchiveWalkLimitError";
12
+ this.limit = limit;
13
+ }
14
+ };
15
+ function walkArchive(bytes, options = {}) {
16
+ const maxDepth = options.maxDepth ?? 8;
17
+ const maxTotalBytes = options.maxTotalBytes ?? 536870912;
18
+ if (!require_zip_detect.isZipArchive(bytes)) throw new Error("walkArchive input is not a ZIP archive (leading magic bytes are not PK\\x03\\x04 or PK\\x05\\x06)");
19
+ const entries = [];
20
+ let totalBytes = 0;
21
+ visit(bytes, []);
22
+ return entries;
23
+ function visit(archive, ancestors) {
24
+ if (ancestors.length + 1 > maxDepth) throw new ArchiveWalkLimitError("depth", `archive nesting exceeds the maximum walk depth of ${maxDepth} at ${ancestors.join(" > ")}`);
25
+ for (const [path, entryBytes] of Object.entries(require_zip_container.unzipPackage(archive))) {
26
+ totalBytes += entryBytes.length;
27
+ if (totalBytes > maxTotalBytes) throw new ArchiveWalkLimitError("total-bytes", `cumulative decompressed size of the walk exceeded the ${maxTotalBytes}-byte budget at ${path}`);
28
+ entries.push({
29
+ path,
30
+ ancestors,
31
+ bytes: entryBytes
32
+ });
33
+ if (require_zip_detect.isZipArchive(entryBytes)) visit(entryBytes, [...ancestors, path]);
34
+ }
35
+ }
36
+ }
37
+ //#endregion
38
+ exports.ArchiveWalkLimitError = ArchiveWalkLimitError;
39
+ exports.MAX_WALK_DEPTH = MAX_WALK_DEPTH;
40
+ exports.MAX_WALK_TOTAL_BYTES = MAX_WALK_TOTAL_BYTES;
41
+ exports.walkArchive = walkArchive;
@@ -0,0 +1,20 @@
1
+ //#region src/zip/walk.d.ts
2
+ declare const MAX_WALK_DEPTH = 8;
3
+ declare const MAX_WALK_TOTAL_BYTES: number;
4
+ interface ArchiveWalkEntry {
5
+ readonly path: string;
6
+ readonly ancestors: readonly string[];
7
+ readonly bytes: Uint8Array<ArrayBuffer>;
8
+ }
9
+ type ArchiveWalkLimit = 'depth' | 'total-bytes';
10
+ declare class ArchiveWalkLimitError extends Error {
11
+ readonly limit: ArchiveWalkLimit;
12
+ constructor(limit: ArchiveWalkLimit, message: string);
13
+ }
14
+ interface WalkArchiveOptions {
15
+ readonly maxDepth?: number;
16
+ readonly maxTotalBytes?: number;
17
+ }
18
+ declare function walkArchive(bytes: Uint8Array<ArrayBuffer>, options?: WalkArchiveOptions): ArchiveWalkEntry[];
19
+ //#endregion
20
+ export { ArchiveWalkEntry, ArchiveWalkLimit, ArchiveWalkLimitError, MAX_WALK_DEPTH, MAX_WALK_TOTAL_BYTES, WalkArchiveOptions, walkArchive };
@@ -0,0 +1,20 @@
1
+ //#region src/zip/walk.d.ts
2
+ declare const MAX_WALK_DEPTH = 8;
3
+ declare const MAX_WALK_TOTAL_BYTES: number;
4
+ interface ArchiveWalkEntry {
5
+ readonly path: string;
6
+ readonly ancestors: readonly string[];
7
+ readonly bytes: Uint8Array<ArrayBuffer>;
8
+ }
9
+ type ArchiveWalkLimit = 'depth' | 'total-bytes';
10
+ declare class ArchiveWalkLimitError extends Error {
11
+ readonly limit: ArchiveWalkLimit;
12
+ constructor(limit: ArchiveWalkLimit, message: string);
13
+ }
14
+ interface WalkArchiveOptions {
15
+ readonly maxDepth?: number;
16
+ readonly maxTotalBytes?: number;
17
+ }
18
+ declare function walkArchive(bytes: Uint8Array<ArrayBuffer>, options?: WalkArchiveOptions): ArchiveWalkEntry[];
19
+ //#endregion
20
+ export { ArchiveWalkEntry, ArchiveWalkLimit, ArchiveWalkLimitError, MAX_WALK_DEPTH, MAX_WALK_TOTAL_BYTES, WalkArchiveOptions, walkArchive };
@@ -0,0 +1,37 @@
1
+ import { unzipPackage } from "./container.js";
2
+ import { isZipArchive } from "./detect.js";
3
+ //#region src/zip/walk.ts
4
+ const MAX_WALK_DEPTH = 8;
5
+ const MAX_WALK_TOTAL_BYTES = 536870912;
6
+ var ArchiveWalkLimitError = class extends Error {
7
+ limit;
8
+ constructor(limit, message) {
9
+ super(message);
10
+ this.name = "ArchiveWalkLimitError";
11
+ this.limit = limit;
12
+ }
13
+ };
14
+ function walkArchive(bytes, options = {}) {
15
+ const maxDepth = options.maxDepth ?? 8;
16
+ const maxTotalBytes = options.maxTotalBytes ?? 536870912;
17
+ if (!isZipArchive(bytes)) throw new Error("walkArchive input is not a ZIP archive (leading magic bytes are not PK\\x03\\x04 or PK\\x05\\x06)");
18
+ const entries = [];
19
+ let totalBytes = 0;
20
+ visit(bytes, []);
21
+ return entries;
22
+ function visit(archive, ancestors) {
23
+ if (ancestors.length + 1 > maxDepth) throw new ArchiveWalkLimitError("depth", `archive nesting exceeds the maximum walk depth of ${maxDepth} at ${ancestors.join(" > ")}`);
24
+ for (const [path, entryBytes] of Object.entries(unzipPackage(archive))) {
25
+ totalBytes += entryBytes.length;
26
+ if (totalBytes > maxTotalBytes) throw new ArchiveWalkLimitError("total-bytes", `cumulative decompressed size of the walk exceeded the ${maxTotalBytes}-byte budget at ${path}`);
27
+ entries.push({
28
+ path,
29
+ ancestors,
30
+ bytes: entryBytes
31
+ });
32
+ if (isZipArchive(entryBytes)) visit(entryBytes, [...ancestors, path]);
33
+ }
34
+ }
35
+ }
36
+ //#endregion
37
+ export { ArchiveWalkLimitError, MAX_WALK_DEPTH, MAX_WALK_TOTAL_BYTES, walkArchive };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "archive-codec",
3
- "version": "1.0.2",
4
- "description": "Recursive archive (ZIP-in-ZIP) detection and walking with depth and cumulative decompressed-size guards - zero document-format knowledge, the archive utility package for the documents.js family.",
3
+ "version": "1.1.1",
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": {
7
7
  "type": "git",
@@ -57,10 +57,12 @@
57
57
  "_typecheck": "tsc -p tsconfig.json && tsc -p tsconfig.node.json",
58
58
  "_typecheck:attw": "attw --pack",
59
59
  "test": "turbo run _test",
60
- "_test": "vitest run",
61
- "test:watch": "vitest",
60
+ "_test": "vitest run --project unit",
61
+ "test:watch": "vitest --project unit",
62
62
  "test:workers": "turbo run _test:workers",
63
63
  "_test:workers": "vitest run --config vitest.workers.config.ts",
64
+ "test:smoke": "turbo run _test:smoke",
65
+ "_test:smoke": "vitest run --project smoke",
64
66
  "prepare": "husky"
65
67
  },
66
68
  "packageManager": "pnpm@11.6.0",