@oh-my-pi/pi-utils 17.4.0 → 17.4.2

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 (82) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/LICENSE +22 -0
  3. package/THIRD-PARTY-NOTICES.txt +22909 -0
  4. package/dist/types/ar/arj.d.ts +5 -0
  5. package/dist/types/ar/asar.d.ts +7 -0
  6. package/dist/types/ar/bytes.d.ts +20 -0
  7. package/dist/types/ar/cab.d.ts +5 -0
  8. package/dist/types/ar/checksums.d.ts +10 -0
  9. package/dist/types/ar/codecs/bzip2.d.ts +4 -0
  10. package/dist/types/ar/codecs/gzip.d.ts +6 -0
  11. package/dist/types/ar/codecs/lzma.d.ts +6 -0
  12. package/dist/types/ar/codecs/lzw.d.ts +4 -0
  13. package/dist/types/ar/codecs/lzx.d.ts +7 -0
  14. package/dist/types/ar/codecs/xz.d.ts +4 -0
  15. package/dist/types/ar/codecs/zstd.d.ts +6 -0
  16. package/dist/types/ar/cpio.d.ts +7 -0
  17. package/dist/types/ar/deb.d.ts +5 -0
  18. package/dist/types/ar/entries.d.ts +22 -0
  19. package/dist/types/ar/error.d.ts +8 -0
  20. package/dist/types/ar/index.d.ts +11 -0
  21. package/dist/types/ar/iso.d.ts +5 -0
  22. package/dist/types/ar/limits.d.ts +33 -0
  23. package/dist/types/ar/lzh.d.ts +7 -0
  24. package/dist/types/ar/open.d.ts +45 -0
  25. package/dist/types/ar/paths.d.ts +18 -0
  26. package/dist/types/ar/rar/rar4-decoder.d.ts +6 -0
  27. package/dist/types/ar/rar/rar5-decoder.d.ts +6 -0
  28. package/dist/types/ar/rar.d.ts +5 -0
  29. package/dist/types/ar/reader.d.ts +28 -0
  30. package/dist/types/ar/registry.d.ts +17 -0
  31. package/dist/types/ar/rpm.d.ts +5 -0
  32. package/dist/types/ar/sevenzip/decode.d.ts +33 -0
  33. package/dist/types/ar/sevenzip.d.ts +5 -0
  34. package/dist/types/ar/source.d.ts +54 -0
  35. package/dist/types/ar/tar.d.ts +9 -0
  36. package/dist/types/ar/types.d.ts +99 -0
  37. package/dist/types/ar/unix-ar.d.ts +7 -0
  38. package/dist/types/ar/write.d.ts +10 -0
  39. package/dist/types/ar/zip.d.ts +10 -0
  40. package/dist/types/postmortem.d.ts +33 -0
  41. package/package.json +9 -3
  42. package/src/ar/arj.ts +314 -0
  43. package/src/ar/asar.ts +480 -0
  44. package/src/ar/bytes.ts +78 -0
  45. package/src/ar/cab.ts +377 -0
  46. package/src/ar/checksums.ts +62 -0
  47. package/src/ar/codecs/bzip2.ts +489 -0
  48. package/src/ar/codecs/gzip.ts +25 -0
  49. package/src/ar/codecs/lzma.ts +437 -0
  50. package/src/ar/codecs/lzw.ts +191 -0
  51. package/src/ar/codecs/lzx.ts +366 -0
  52. package/src/ar/codecs/xz.ts +522 -0
  53. package/src/ar/codecs/zstd.ts +25 -0
  54. package/src/ar/cpio.ts +389 -0
  55. package/src/ar/deb.ts +160 -0
  56. package/src/ar/entries.ts +97 -0
  57. package/src/ar/error.ts +11 -0
  58. package/src/ar/index.ts +16 -0
  59. package/src/ar/iso.ts +712 -0
  60. package/src/ar/limits.ts +80 -0
  61. package/src/ar/lzh.ts +659 -0
  62. package/src/ar/open.ts +225 -0
  63. package/src/ar/paths.ts +70 -0
  64. package/src/ar/rar/rar4-decoder.ts +459 -0
  65. package/src/ar/rar/rar5-decoder.ts +400 -0
  66. package/src/ar/rar.ts +735 -0
  67. package/src/ar/reader.ts +162 -0
  68. package/src/ar/registry.ts +208 -0
  69. package/src/ar/rpm.ts +320 -0
  70. package/src/ar/sevenzip/decode.ts +239 -0
  71. package/src/ar/sevenzip.ts +634 -0
  72. package/src/ar/source.ts +190 -0
  73. package/src/ar/tar.ts +771 -0
  74. package/src/ar/types.ts +131 -0
  75. package/src/ar/unix-ar.ts +312 -0
  76. package/src/ar/write.ts +55 -0
  77. package/src/ar/zip.ts +719 -0
  78. package/src/browsers.ts +2 -149
  79. package/src/docx/converter.ts +9 -9
  80. package/src/postmortem.ts +74 -0
  81. package/dist/types/docx/zip.d.ts +0 -6
  82. package/src/docx/zip.ts +0 -87
@@ -0,0 +1,5 @@
1
+ import type { FormatReader } from "./types.js";
2
+ /** Probe whether bytes begin with a CRC-framed ARJ main header. */
3
+ export declare function sniffArj(bytes: Uint8Array): boolean;
4
+ /** Index an ARJ archive and lazily decode stored, static-Huffman, and fast-LZSS members. */
5
+ export declare const readArj: FormatReader;
@@ -0,0 +1,7 @@
1
+ import type { FormatReader } from "./types.js";
2
+ /** Read an Electron ASAR index while keeping packed and unpacked member payloads lazy. */
3
+ export declare const readAsar: FormatReader;
4
+ /** Whether bytes begin with a structurally plausible Electron ASAR Pickle header. */
5
+ export declare function sniffAsar(bytes: Uint8Array): boolean;
6
+ /** Encode file members in Electron's Pickle-framed ASAR layout. */
7
+ export declare function encodeAsar(members: Iterable<readonly [string, Uint8Array]>): Promise<Uint8Array>;
@@ -0,0 +1,20 @@
1
+ /** Shared UTF-8 decoder for archive member names and text payloads. */
2
+ export declare const UTF8_DECODER: TextDecoder;
3
+ export declare function readUInt16LE(bytes: Uint8Array, offset: number): number;
4
+ export declare function readUInt32LE(bytes: Uint8Array, offset: number): number;
5
+ /** Read a u64 as a JS number, rejecting values beyond `Number.MAX_SAFE_INTEGER`. */
6
+ export declare function readUInt64LE(bytes: Uint8Array, offset: number): number;
7
+ export declare function readUInt16BE(bytes: Uint8Array, offset: number): number;
8
+ export declare function readUInt32BE(bytes: Uint8Array, offset: number): number;
9
+ /** Read a big-endian u64 as a JS number, rejecting unsafe values. */
10
+ export declare function readUInt64BE(bytes: Uint8Array, offset: number): number;
11
+ export declare function writeUInt16LE(buf: Uint8Array, offset: number, value: number): void;
12
+ export declare function writeUInt32LE(buf: Uint8Array, offset: number, value: number): void;
13
+ /** Write a safe-integer u64 (values beyond 2^53-1 must be rejected upstream). */
14
+ export declare function writeUInt64LE(buf: Uint8Array, offset: number, value: number): void;
15
+ /** Whether `bytes` contains the ASCII string `value` at `offset`. */
16
+ export declare function bytesMatchAscii(bytes: Uint8Array, offset: number, value: string): boolean;
17
+ /** Whether `bytes` is exactly the ASCII string `value`. */
18
+ export declare function bytesEqualAscii(bytes: Uint8Array, value: string): boolean;
19
+ /** First index at or after `start` where the ASCII string `value` occurs, or -1. */
20
+ export declare function indexOfAscii(bytes: Uint8Array, value: string, start: number): number;
@@ -0,0 +1,5 @@
1
+ import type { FormatReader } from "./types.js";
2
+ /** Probe a byte prefix for the Microsoft Cabinet `MSCF` signature. */
3
+ export declare function sniffCab(bytes: Uint8Array): boolean;
4
+ /** Index a Microsoft Cabinet archive and defer folder decompression until a member is read. */
5
+ export declare const readCab: FormatReader;
@@ -0,0 +1,10 @@
1
+ /** CRC-32 (IEEE 802.3, reflected). Chainable: pass the previous value as `seed`. */
2
+ export declare function crc32(bytes: Uint8Array, seed?: number): number;
3
+ /**
4
+ * CRC-64/XZ (ECMA-182, reflected) as used by `.xz` block checks. Chainable
5
+ * via `seed`. State is split into 32-bit halves so the hot loop stays on
6
+ * fast integer paths instead of per-byte BigInt arithmetic.
7
+ */
8
+ export declare function crc64(bytes: Uint8Array, seed?: bigint): bigint;
9
+ /** CRC-16/ARC (reflected, poly 0xA001, init 0) as used by LZH member data and ARJ. */
10
+ export declare function crc16Arc(bytes: Uint8Array, seed?: number): number;
@@ -0,0 +1,4 @@
1
+ /** Return whether bytes begin with a valid bzip2 stream signature. */
2
+ export declare function isBzip2(bytes: Uint8Array): boolean;
3
+ /** Decompress concatenated bzip2 streams while enforcing a hard output bound. */
4
+ export declare function bzip2Decompress(bytes: Uint8Array, maxOutput: number): Promise<Uint8Array>;
@@ -0,0 +1,6 @@
1
+ /** gzip magic: 0x1f 0x8b. */
2
+ export declare function isGzip(bytes: Uint8Array): boolean;
3
+ /** Decompress one gzip stream, bounded so a gzip bomb cannot inflate without limit. */
4
+ export declare function gzipDecompress(bytes: Uint8Array, maxOutput: number): Promise<Uint8Array>;
5
+ /** Compress bytes as one gzip stream (tar.gz writing). */
6
+ export declare function gzipCompress(bytes: Uint8Array): Promise<Uint8Array>;
@@ -0,0 +1,6 @@
1
+ /** Decompress a raw LZMA1 stream using the standard five-byte properties. */
2
+ export declare function lzmaDecompress(props: Uint8Array, bytes: Uint8Array, outSize: number): Promise<Uint8Array>;
3
+ /** Decompress an LZMA-alone container, including unknown-size end-marked streams. */
4
+ export declare function lzmaAloneDecompress(bytes: Uint8Array, maxOutput: number): Promise<Uint8Array>;
5
+ /** Decompress an LZMA2 stream, enforcing its dictionary and output limits. */
6
+ export declare function lzma2Decompress(dictSizeProp: number, bytes: Uint8Array, maxOutput: number): Promise<Uint8Array>;
@@ -0,0 +1,4 @@
1
+ /** Return whether bytes begin with the ncompress `.Z` magic number. */
2
+ export declare function isCompressZ(bytes: Uint8Array): boolean;
3
+ /** Decompress an ncompress `.Z` stream while enforcing a hard output bound. */
4
+ export declare function lzwDecompress(bytes: Uint8Array, maxOutput: number): Promise<Uint8Array>;
@@ -0,0 +1,7 @@
1
+ /** Stateful Microsoft LZX decoder used by CAB folders, retaining trees and window history between 32 KiB frames. */
2
+ export declare class LzxDecoder {
3
+ #private;
4
+ constructor(windowBits: number);
5
+ /** Decode one CAB CFDATA LZX frame while preserving the folder's dictionary and Huffman state. */
6
+ decompressFrame(bytes: Uint8Array, outputSize: number): Uint8Array;
7
+ }
@@ -0,0 +1,4 @@
1
+ /** Whether bytes begin with the XZ stream-header magic. */
2
+ export declare function isXz(bytes: Uint8Array): boolean;
3
+ /** Decompress all concatenated streams in an XZ container within `maxOutput`. */
4
+ export declare function xzDecompress(bytes: Uint8Array, maxOutput: number): Promise<Uint8Array>;
@@ -0,0 +1,6 @@
1
+ /** zstd frame magic: 28 b5 2f fd. */
2
+ export declare function isZstd(bytes: Uint8Array): boolean;
3
+ /** Decompress one zstd frame, bounded to `maxOutput` bytes. */
4
+ export declare function zstdDecompress(bytes: Uint8Array, maxOutput: number): Promise<Uint8Array>;
5
+ /** Compress bytes as one zstd frame (tar.zst writing). */
6
+ export declare function zstdCompress(bytes: Uint8Array): Promise<Uint8Array>;
@@ -0,0 +1,7 @@
1
+ import type { ArchiveIndexEntry, FormatReader, FormatReadOptions } from "./types.js";
2
+ /** Parse an already-materialized CPIO stream for direct and RPM-composed readers. */
3
+ export declare function readCpioEntriesFromBuffer(bytes: Uint8Array, options: FormatReadOptions): ArchiveIndexEntry[];
4
+ /** Read and index a CPIO archive, materializing its inherently sequential stream once. */
5
+ export declare const readCpio: FormatReader;
6
+ /** Detect newc, CRC, odc, or either-endian old binary CPIO headers. */
7
+ export declare function sniffCpio(bytes: Uint8Array): boolean;
@@ -0,0 +1,5 @@
1
+ import type { FormatReader } from "./types.js";
2
+ /** Read a Debian binary package and expose its control and data tar members. */
3
+ export declare const readDeb: FormatReader;
4
+ /** Detect a Debian package by its ar header and first debian-binary member. */
5
+ export declare function sniffDeb(bytes: Uint8Array): boolean;
@@ -0,0 +1,22 @@
1
+ import { type ArchiveLimits } from "./limits.js";
2
+ import type { ArchiveIndexEntry } from "./types.js";
3
+ /**
4
+ * Insert `entry` into the index map with archive append/update semantics:
5
+ * files replace directories of the same path, directories never shadow files,
6
+ * and same-kind duplicates keep the later record while earlier metadata fills
7
+ * gaps (matching system tar extraction). Returns the retained entry, or
8
+ * `undefined` when the incoming entry was dropped.
9
+ */
10
+ export declare function upsertArchiveEntry(map: Map<string, ArchiveIndexEntry>, entry: ArchiveIndexEntry): ArchiveIndexEntry | undefined;
11
+ /**
12
+ * Synthesize directory entries for every ancestor of every indexed path, so
13
+ * containers that omit directory records (ZIP, cpio, most tars) still list
14
+ * correctly. Enforces `limits.maxEntries` as the map grows.
15
+ */
16
+ export declare function ensureParentDirectories(map: Map<string, ArchiveIndexEntry>, limits: ArchiveLimits): void;
17
+ /**
18
+ * Rewrite `archivePath` through symlink aliases until it no longer crosses
19
+ * one. Bounded: an exact revisit and an alias chain that keeps growing the
20
+ * path (e.g. `a -> a/b`) both throw a catchable cyclic-symlink error.
21
+ */
22
+ export declare function resolveArchiveLinkPath(entries: ReadonlyMap<string, ArchiveIndexEntry>, archivePath: string, maxLinkDepth: number): string;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Error raised for invalid, unsupported, or unsafe archive input. The message
3
+ * is safe to surface directly to users/models; callers that need a different
4
+ * error taxonomy (e.g. the coding agent's `ToolError`) match on this class.
5
+ */
6
+ export declare class ArchiveError extends Error {
7
+ constructor(message: string);
8
+ }
@@ -0,0 +1,11 @@
1
+ export * from "./bytes.js";
2
+ export * from "./entries.js";
3
+ export * from "./error.js";
4
+ export * from "./limits.js";
5
+ export * from "./open.js";
6
+ export * from "./paths.js";
7
+ export * from "./reader.js";
8
+ export * from "./registry.js";
9
+ export * from "./source.js";
10
+ export * from "./types.js";
11
+ export * from "./write.js";
@@ -0,0 +1,5 @@
1
+ import type { FormatReader } from "./types.js";
2
+ /** Probe an ISO 9660 primary-volume signature at sector 16. */
3
+ export declare function sniffIso(bytes: Uint8Array): boolean;
4
+ /** Index an ISO 9660 image lazily, preferring a valid Joliet supplementary tree. */
5
+ export declare const readIso: FormatReader;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Resource ceilings enforced before archive metadata can drive expensive
3
+ * work. All sizes are attacker-controlled inputs until proven otherwise, so
4
+ * every allocation-driving field is checked against these before use.
5
+ * Mirrors `Limits` in the Rust `omp-ar` crate.
6
+ */
7
+ export interface ArchiveLimits {
8
+ /** Max indexed entries per archive. */
9
+ maxEntries: number;
10
+ /** Max bytes for any archive fully materialized in memory (tar buffers, solid/decompressed streams). */
11
+ maxInMemorySize: number;
12
+ /** Max bytes for archive metadata (ZIP central directory, ASAR JSON header, RAR/7z header areas). */
13
+ maxIndexSize: number;
14
+ /** Max declared bytes for a single extracted member. */
15
+ maxMemberSize: number;
16
+ /** Max byte length of a member path or link target. */
17
+ maxPathBytes: number;
18
+ /** Max symlink rewrites while resolving one path. */
19
+ maxLinkDepth: number;
20
+ }
21
+ export declare const DEFAULT_ARCHIVE_LIMITS: ArchiveLimits;
22
+ /** Reject an archive that would be fully materialized beyond `maxInMemorySize`. */
23
+ export declare function assertInMemorySize(size: number, limits: ArchiveLimits): void;
24
+ /** Reject archive metadata (index/header) beyond `maxIndexSize`. */
25
+ export declare function assertIndexSize(size: number, limits: ArchiveLimits, what: string): void;
26
+ /**
27
+ * Reject a member whose declared (uncompressed) size exceeds `maxMemberSize`.
28
+ * The declared size is metadata — a crafted entry can claim multi-GB sizes
29
+ * that would be allocated up front before any data decompresses.
30
+ */
31
+ export declare function assertArchiveMemberSize(size: number, memberPath: string, limits: ArchiveLimits): void;
32
+ /** Reject an index that grew beyond `maxEntries` while parsing. */
33
+ export declare function assertEntryCount(count: number, limits: ArchiveLimits): void;
@@ -0,0 +1,7 @@
1
+ import type { FormatReader } from "./types.js";
2
+ /** @internal Decode the static-Huffman LZSS stream shared by LZH and ARJ methods 1-3. */
3
+ export declare function decompressLhStatic(packed: Uint8Array, outSize: number, dictionarySize: number, positionBits: number, positionSymbols: number, label: string): Uint8Array;
4
+ /** Probe whether bytes begin with an LZH/LHA member header. */
5
+ export declare function sniffLzh(bytes: Uint8Array): boolean;
6
+ /** Index an LZH/LHA archive and lazily decode its members from the bounded archive buffer. */
7
+ export declare const readLzh: FormatReader;
@@ -0,0 +1,45 @@
1
+ import { type ArchiveLimits } from "./limits.js";
2
+ import { ArchiveReader } from "./reader.js";
3
+ import type { ArchiveDirectoryEntry, ArchiveFormat, ArchiveMemberContent, ArchivePathCandidate, ArchiveSource } from "./types.js";
4
+ /** Options accepted by every archive-opening entry point. */
5
+ export interface OpenArchiveOptions {
6
+ /** Override individual resource ceilings; unset fields keep defaults. */
7
+ limits?: Partial<ArchiveLimits>;
8
+ }
9
+ /**
10
+ * Open an archive for browsing and member reads. File- and source-backed
11
+ * containers with random-access layouts (ZIP, ASAR, RAR, 7z, ISO, CAB) index
12
+ * lazily; stream containers (tar family, cpio, ar) buffer once under limits.
13
+ */
14
+ export declare function openArchive(input: ArchiveSource, options?: OpenArchiveOptions): Promise<ArchiveReader>;
15
+ /**
16
+ * Split an `archive.ext:inner/path` reference into every plausible
17
+ * `{ archivePath, subPath }` pair, longest archive prefix first. A path may
18
+ * contain more than one archive extension, so each candidate is a guess at
19
+ * where the archive ends and the member portion begins.
20
+ */
21
+ export declare function parseArchivePathCandidates(filePath: string): ArchivePathCandidate[];
22
+ /** Render directory entries one per line: `name/` for dirs, `name (size)` for files. */
23
+ export declare function formatArchiveEntryLines(entries: readonly ArchiveDirectoryEntry[]): string[];
24
+ /** Render the top-level entries of an in-memory archive as one line each. */
25
+ export declare function listArchiveRoot(bytes: Uint8Array, format: ArchiveFormat, opts?: {
26
+ limit?: number;
27
+ }): Promise<string>;
28
+ /**
29
+ * Fully materialize every file member into a `path → bytes` map. Use this
30
+ * for whole-archive rewrite; browsing and single-member reads should use
31
+ * {@link openArchive} so payloads remain lazy. Total extracted bytes are
32
+ * bounded by `limits.maxInMemorySize`.
33
+ */
34
+ export declare function readArchiveEntries(input: ArchiveSource, options?: OpenArchiveOptions): Promise<Map<string, Uint8Array>>;
35
+ /** Convert member content for packing: strings become UTF-8 bytes. */
36
+ export declare function memberContentToBytes(content: ArchiveMemberContent): Promise<Uint8Array>;
37
+ /** Read one materialized member as UTF-8 text, or `undefined` when absent. */
38
+ export declare function archiveEntryText(entries: ReadonlyMap<string, Uint8Array>, entryPath: string): string | undefined;
39
+ /**
40
+ * Extract every member to `destDir`: files (with mode bits when recorded),
41
+ * directories, and symlinks (targets validated to stay inside `destDir`).
42
+ * Entries that would escape via `..` or absolute paths are rejected.
43
+ * Returns the number of filesystem entries written.
44
+ */
45
+ export declare function extractArchive(input: ArchiveSource, destDir: string, options?: OpenArchiveOptions): Promise<number>;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Normalize a user-supplied lookup path inside an archive. Returns `""` for
3
+ * the archive root, `undefined` when the path escapes the root via `..`.
4
+ */
5
+ export declare function normalizeArchiveLookupPath(rawPath?: string): string | undefined;
6
+ /**
7
+ * Normalize an archive member path from container metadata. Returns
8
+ * `undefined` for empty paths and paths that escape the root via `..`.
9
+ */
10
+ export declare function normalizeArchiveEntryPath(rawPath: string): string | undefined;
11
+ /** Whether raw container metadata spells a directory via a trailing separator. */
12
+ export declare function isArchiveDirectoryName(rawPath: string): boolean;
13
+ /** Clamp an attacker-controlled path to a short preview for error messages. */
14
+ export declare function formatArchivePathForError(value: string): string;
15
+ /** Reject a member path/link target longer than `maxPathBytes`. */
16
+ export declare function assertArchivePathBytes(size: number, field: string, maxPathBytes: number): void;
17
+ /** {@link assertArchivePathBytes} for an already-decoded string. */
18
+ export declare function assertArchivePathString(value: string, field: string, maxPathBytes: number): void;
@@ -0,0 +1,6 @@
1
+ /** Stateful decoder for the RAR 2.9 LZ/Huffman algorithm used by RAR3/4 archives. */
2
+ export declare class Rar4Decoder {
3
+ #private;
4
+ reset(): void;
5
+ decode(packed: Uint8Array, unpackedSize: number, dictionarySize: number, solid: boolean, version: number): Uint8Array;
6
+ }
@@ -0,0 +1,6 @@
1
+ /** Stateful RAR5 LZSS decoder; reuse one instance for members in a solid chain. */
2
+ export declare class Rar5Decoder {
3
+ #private;
4
+ reset(): void;
5
+ decode(packed: Uint8Array, unpackedSize: number, dictionarySize: number, solid: boolean, version: number): Uint8Array;
6
+ }
@@ -0,0 +1,5 @@
1
+ import type { FormatReader } from "./types.js";
2
+ /** Probe the RAR 1.5-4.x or RAR5 signature. */
3
+ export declare function sniffRar(bytes: Uint8Array): boolean;
4
+ /** Index a RAR4 or RAR5 archive and defer member decompression until extraction. */
5
+ export declare const readRar: FormatReader;
@@ -0,0 +1,28 @@
1
+ import { type ArchiveLimits } from "./limits.js";
2
+ import type { ArchiveDirectoryEntry, ArchiveFormat, ArchiveIndexEntry, ArchiveNode, ExtractedArchiveFile } from "./types.js";
3
+ /** Raise the canonical error for a symlink whose target cannot be materialized. */
4
+ export declare function throwUnreadableArchiveLink(targetPath: string, memberPath: string): never;
5
+ /**
6
+ * An indexed, read-only view over a single archive. Member payloads stay
7
+ * lazy behind their format's `MemberSource`; symlink aliases are traversed
8
+ * lazily so N files behind M directory aliases never inflate the index to
9
+ * N×M entries during listing.
10
+ */
11
+ export declare class ArchiveReader {
12
+ #private;
13
+ readonly format: ArchiveFormat;
14
+ readonly limits: ArchiveLimits;
15
+ constructor(format: ArchiveFormat, entries: ArchiveIndexEntry[], limits?: ArchiveLimits);
16
+ /**
17
+ * Raw index entries, including link records and synthesized directories.
18
+ * For extraction/merge flows that need storage kinds; path lookups should
19
+ * use {@link getNode}/{@link readFile}, which resolve symlink aliases.
20
+ */
21
+ indexEntries(): IterableIterator<ArchiveIndexEntry>;
22
+ /** Resolve a path to its node, or `undefined` when absent or escaping the root. */
23
+ getNode(subPath?: string): ArchiveNode | undefined;
24
+ /** List one directory's children, sorted case-insensitively by name. */
25
+ listDirectory(subPath?: string): ArchiveDirectoryEntry[];
26
+ /** Extract one file member's bytes, following symlink aliases. */
27
+ readFile(subPath: string): Promise<ExtractedArchiveFile>;
28
+ }
@@ -0,0 +1,17 @@
1
+ import type { ArchiveFormat, FormatReader } from "./types.js";
2
+ /**
3
+ * Regex alternation of every recognized archive extension, longest first so
4
+ * `.tar.gz` wins over `.gz`. Shared with `parseArchivePathCandidates` as its
5
+ * split pattern so extension recognition and path splitting never drift.
6
+ */
7
+ export declare const ARCHIVE_EXTENSION_ALTERNATION: string;
8
+ /** Infer an archive format from a filesystem path's extension. */
9
+ export declare function archiveFormatFromPath(filePath: string): ArchiveFormat | undefined;
10
+ /** The format reader responsible for `format`. */
11
+ export declare function formatReaderFor(format: ArchiveFormat): FormatReader;
12
+ /**
13
+ * Sniff an archive format from its bytes. Pass the full buffer when
14
+ * available: most probes read the head, but tar needs offset 257, ISO offset
15
+ * 32769, and the trailing ZIP central-directory scan needs the tail.
16
+ */
17
+ export declare function sniffArchiveFormat(bytes: Uint8Array): ArchiveFormat | undefined;
@@ -0,0 +1,5 @@
1
+ import type { FormatReader } from "./types.js";
2
+ /** Read an RPM lead, headers, compressed payload, and its contained CPIO entries. */
3
+ export declare const readRpm: FormatReader;
4
+ /** Detect the four-byte RPM package lead magic. */
5
+ export declare function sniffRpm(bytes: Uint8Array): boolean;
@@ -0,0 +1,33 @@
1
+ import type { ArchiveLimits } from "../limits.js";
2
+ import type { ByteSource } from "../source.js";
3
+ /** One 7z coder and its global folder-stream coordinates. */
4
+ export interface SevenZipCoder {
5
+ id: bigint;
6
+ properties: Uint8Array;
7
+ inputStart: number;
8
+ outputStart: number;
9
+ numInputs: number;
10
+ numOutputs: number;
11
+ }
12
+ /** One binding from a coder output stream to another coder input stream. */
13
+ export interface SevenZipBindPair {
14
+ input: number;
15
+ output: number;
16
+ }
17
+ /** Parsed folder graph and its lazy packed-data coordinates. */
18
+ export interface SevenZipFolderRecord {
19
+ coders: SevenZipCoder[];
20
+ bindPairs: SevenZipBindPair[];
21
+ packedIndices: number[];
22
+ unpackSizes: number[];
23
+ packOffsets: number[];
24
+ packSizes: number[];
25
+ packCrcs: Array<number | undefined>;
26
+ crc?: number;
27
+ }
28
+ /** Shared lazy decoder/cache for a single 7z folder (solid block). */
29
+ export declare class SevenZipFolderSource {
30
+ #private;
31
+ constructor(source: ByteSource, folder: SevenZipFolderRecord, limits: ArchiveLimits);
32
+ read(): Promise<Uint8Array>;
33
+ }
@@ -0,0 +1,5 @@
1
+ import type { FormatReader } from "./types.js";
2
+ /** Whether bytes begin with the canonical 7z signature. */
3
+ export declare function sniffSevenZip(bytes: Uint8Array): boolean;
4
+ /** Index a 7z archive and lazily decode member folders on extraction. */
5
+ export declare const readSevenZip: FormatReader;
@@ -0,0 +1,54 @@
1
+ /**
2
+ * A byte window into an archive — file-backed (lazy, ranged reads) or
3
+ * in-memory. Format readers index through this so ZIP/ASAR/RAR payloads are
4
+ * only read when a member is actually extracted.
5
+ */
6
+ export interface ByteSource {
7
+ readonly size: number;
8
+ read(start: number, end: number): Promise<Uint8Array>;
9
+ }
10
+ /** Reject a nonsensical `[start, end)` range before any read. */
11
+ export declare function assertValidRange(start: number, end: number): void;
12
+ /** Read an exact in-memory range, throwing (not clamping) when it runs past the buffer. */
13
+ export declare function readMemoryRange(buffer: Uint8Array, start: number, end: number): Uint8Array;
14
+ /** Wrap borrowed bytes as a {@link ByteSource}. */
15
+ export declare function memoryByteSource(buffer: Uint8Array): ByteSource;
16
+ /** Lazily read ranges of a file on disk as a {@link ByteSource}. */
17
+ export declare function fileByteSource(filePath: string): ByteSource;
18
+ /** Materialize an entire {@link ByteSource}; use only under a limits check. */
19
+ export declare function readAllBytes(source: ByteSource): Promise<Uint8Array>;
20
+ /** Options for {@link httpByteSource}. */
21
+ export interface HttpByteSourceOptions {
22
+ /** Extra request headers (e.g. authorization). */
23
+ headers?: Record<string, string>;
24
+ /** Fetch implementation seam for tests; defaults to global `fetch`. */
25
+ fetch?: typeof fetch;
26
+ /**
27
+ * When the server ignores `Range` (responds 200), the body is buffered in
28
+ * memory instead, capped to this many bytes. Default 256 MiB.
29
+ */
30
+ maxFallbackBytes?: number;
31
+ }
32
+ /**
33
+ * A {@link ByteSource} over HTTP(S) range requests, so remote archives can be
34
+ * indexed and read member-by-member without downloading the whole file.
35
+ * Probes with `Range: bytes=0-0`; servers without range support fall back to
36
+ * one bounded full download. Wrap with {@link cachingByteSource} to coalesce
37
+ * the many small header reads format parsers issue.
38
+ */
39
+ export declare function httpByteSource(url: string | URL, options?: HttpByteSourceOptions): Promise<ByteSource>;
40
+ /** Options for {@link cachingByteSource}. */
41
+ export interface CachingByteSourceOptions {
42
+ /** Cache block size in bytes. Default 256 KiB. */
43
+ blockSize?: number;
44
+ /** Max cached blocks. Default 64 (16 MiB at the default block size). */
45
+ maxBlocks?: number;
46
+ }
47
+ /**
48
+ * Wrap a high-latency {@link ByteSource} (HTTP, network filesystems) with an
49
+ * aligned-block LRU cache. Small header reads coalesce into shared block
50
+ * fetches (concurrent readers of one block share a single in-flight request);
51
+ * reads spanning more than two blocks bypass the cache to avoid copying large
52
+ * member payloads through it.
53
+ */
54
+ export declare function cachingByteSource(source: ByteSource, options?: CachingByteSourceOptions): ByteSource;
@@ -0,0 +1,9 @@
1
+ import type { ArchiveIndexEntry, FormatReader, FormatReadOptions } from "./types.js";
2
+ /** Index an already-decompressed tar buffer with bounded GNU, ustar, and PAX handling. */
3
+ export declare function readTarEntriesFromBuffer(buffer: Uint8Array, options: FormatReadOptions): ArchiveIndexEntry[];
4
+ /** Read and index a tar source after one bounded whole-stream read. */
5
+ export declare const readTar: FormatReader;
6
+ /** Detect a tar header, including legacy pre-ustar archives, by its checksum. */
7
+ export declare function sniffTar(bytes: Uint8Array): boolean;
8
+ /** Encode files as a deterministic ustar archive, using PAX records for overflow paths. */
9
+ export declare function encodeTar(members: Iterable<readonly [string, Uint8Array]>): Promise<Uint8Array>;
@@ -0,0 +1,99 @@
1
+ import type { ArchiveLimits } from "./limits.js";
2
+ import type { ByteSource } from "./source.js";
3
+ /** Archive container formats readable by the unified archive API. */
4
+ export type ArchiveFormat = "zip" | "tar" | "tar.gz" | "tar.bz2" | "tar.xz" | "tar.zst" | "tar.Z" | "asar" | "rar" | "7z" | "iso" | "cab" | "cpio" | "rpm" | "ar" | "deb" | "lzh" | "arj" | "gz" | "bz2" | "xz" | "zst" | "Z" | "lzma";
5
+ /** Archive formats the unified API can serialize. Everything else is read-only. */
6
+ export type WritableArchiveFormat = "zip" | "tar" | "tar.gz" | "tar.zst" | "asar";
7
+ /**
8
+ * Where to read an archive from: an extension-inferred filesystem path, a
9
+ * format-tagged filesystem path, in-memory bytes, or any caller-provided
10
+ * {@link ByteSource} (e.g. `httpByteSource` for ranged remote reads).
11
+ * File- and source-backed ZIP/ASAR/RAR/7z/ISO are read lazily.
12
+ */
13
+ export type ArchiveSource = string | {
14
+ bytes: Uint8Array;
15
+ format: ArchiveFormat;
16
+ } | {
17
+ path: string;
18
+ format: ArchiveFormat;
19
+ } | {
20
+ source: ByteSource;
21
+ format: ArchiveFormat;
22
+ path?: string;
23
+ };
24
+ /** Content for a member when packing or extracting an archive. */
25
+ export type ArchiveMemberContent = string | Uint8Array | Blob;
26
+ /** One `archive.ext:inner/path` split candidate (see `parseArchivePathCandidates`). */
27
+ export interface ArchivePathCandidate {
28
+ archivePath: string;
29
+ subPath: string;
30
+ }
31
+ /** A file or directory node visible through an `ArchiveReader`. */
32
+ export interface ArchiveNode {
33
+ path: string;
34
+ isDirectory: boolean;
35
+ size: number;
36
+ mtimeMs?: number;
37
+ /** Unix permission/type bits when the container records them. */
38
+ mode?: number;
39
+ }
40
+ /** An {@link ArchiveNode} with its name relative to the listed directory. */
41
+ export interface ArchiveDirectoryEntry extends ArchiveNode {
42
+ name: string;
43
+ }
44
+ /** An {@link ArchiveNode} with its extracted payload. */
45
+ export interface ExtractedArchiveFile extends ArchiveNode {
46
+ bytes: Uint8Array;
47
+ }
48
+ /**
49
+ * Format-owned handle that extracts one member's bytes on demand. Instances
50
+ * may share per-archive state (solid-block decoders, 7z folder caches).
51
+ * Prefer classes with prototype methods over closures: archives can index
52
+ * hundreds of thousands of members.
53
+ */
54
+ export interface MemberSource {
55
+ /**
56
+ * Read this member's bytes. `size` is the entry's declared uncompressed
57
+ * size (already bounds-checked); `memberPath` is for error messages.
58
+ * Implementations must verify the produced byte count (and checksums when
59
+ * the container records them) and throw {@link ArchiveError} on mismatch.
60
+ */
61
+ read(size: number, memberPath: string): Promise<Uint8Array>;
62
+ }
63
+ /**
64
+ * How an indexed entry's bytes are stored. `link` entries alias another
65
+ * archive path and are resolved lazily by the reader core; `member` entries
66
+ * defer to their format module.
67
+ */
68
+ export type EntryStorage = {
69
+ type: "link";
70
+ targetPath: string;
71
+ /** Follow before target kind is known (ASAR link records do not encode it). */
72
+ resolveTarget: boolean;
73
+ } | {
74
+ type: "member";
75
+ source: MemberSource;
76
+ };
77
+ /** One indexed entry as produced by a format reader, before core resolution. */
78
+ export interface ArchiveIndexEntry extends ArchiveNode {
79
+ storage?: EntryStorage;
80
+ }
81
+ /** Context passed to every format reader. */
82
+ export interface FormatReadOptions {
83
+ limits: ArchiveLimits;
84
+ /**
85
+ * Filesystem path of the archive when file-backed. Formats that reference
86
+ * sibling files use it (ASAR `.unpacked` payloads, multi-volume RAR).
87
+ */
88
+ archivePath?: string;
89
+ }
90
+ /**
91
+ * Contract implemented by every format module: index `source` into normalized
92
+ * entries without materializing member payloads unless the container forces
93
+ * it (tar streams, solid archives). Implementations must:
94
+ * - normalize paths via `normalizeArchiveEntryPath` and drop unrepresentable ones,
95
+ * - enforce `options.limits` before metadata-driven allocations,
96
+ * - throw {@link ArchiveError} for malformed, truncated, encrypted, or
97
+ * unsupported input — never a bare `Error`, and never process-fatal paths.
98
+ */
99
+ export type FormatReader = (source: ByteSource, options: FormatReadOptions) => Promise<ArchiveIndexEntry[]>;
@@ -0,0 +1,7 @@
1
+ import type { ArchiveIndexEntry, FormatReader, FormatReadOptions } from "./types.js";
2
+ /** Parse a fully materialized Unix ar archive for composition by formats such as deb. */
3
+ export declare function readUnixArEntriesFromBuffer(bytes: Uint8Array, options: FormatReadOptions): ArchiveIndexEntry[];
4
+ /** Read a Unix ar, static-library, or COFF import-library container. */
5
+ export declare const readUnixAr: FormatReader;
6
+ /** Detect the Unix ar global header. */
7
+ export declare function sniffUnixAr(bytes: Uint8Array): boolean;
@@ -0,0 +1,10 @@
1
+ import type { ArchiveFormat, ArchiveMemberContent, WritableArchiveFormat } from "./types.js";
2
+ /** Whether `format` can be serialized by {@link writeArchive} (rest are read-only). */
3
+ export declare function isWritableArchiveFormat(format: ArchiveFormat): format is WritableArchiveFormat;
4
+ /**
5
+ * Serialize `entries` into an archive of `format` in memory. String members
6
+ * are encoded as UTF-8; member names are normalized to forward slashes.
7
+ */
8
+ export declare function encodeArchive(format: WritableArchiveFormat, entries: Iterable<readonly [string, ArchiveMemberContent]>): Promise<Uint8Array>;
9
+ /** {@link encodeArchive}, written to `destPath` (parent directories auto-created). */
10
+ export declare function writeArchive(destPath: string, format: WritableArchiveFormat, entries: Iterable<readonly [string, ArchiveMemberContent]>): Promise<void>;
@@ -0,0 +1,10 @@
1
+ import { type ArchiveLimits } from "./limits.js";
2
+ import type { FormatReader } from "./types.js";
3
+ /** Index a ZIP/ZIP64 archive lazily from its central directory. */
4
+ export declare const readZip: FormatReader;
5
+ /** Detect a ZIP local header, empty-archive end record, or leading data descriptor. */
6
+ export declare function sniffZip(bytes: Uint8Array): boolean;
7
+ /** Materialize every regular ZIP member into a path-to-bytes map for document converters. */
8
+ export declare function readZipEager(bytes: Uint8Array, limits?: ArchiveLimits): Promise<Map<string, Uint8Array>>;
9
+ /** Encode deterministic stored/deflated ZIP bytes, emitting ZIP64 end records when the entry count requires them. */
10
+ export declare function encodeZip(members: Iterable<readonly [string, Uint8Array]>): Promise<Uint8Array>;