dir-archiver 2.2.0 → 3.0.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
@@ -1,125 +1,88 @@
1
- [![npm][npm-image]][npm-url] [![license][license-image]][license-url]
2
- [![changelog][changelog-image]][changelog-url]
1
+ ---
2
+ role: overview
3
+ audience: users
4
+ source_of_truth: README.md
5
+ update_triggers:
6
+ - public API changes
7
+ - CLI contract changes
8
+ - runtime support changes
9
+ ---
3
10
 
4
- # Dir Archiver
5
- Compress a whole directory (including subdirectories) into a zip file, with options to exclude specific files or directories.
11
+ # dir-archiver
6
12
 
7
- # Installation
13
+ `dir-archiver` v3 is a bytefold-backed archive orchestration layer for Node.js, Deno, and Bun.
14
+ ESM-only. Safety profiles: `compat | strict | agent`.
8
15
 
9
- ```sh
10
- $ npm install dir-archiver
11
- ```
12
-
13
- Requires Node.js >=18.
14
-
15
- # Usage
16
-
17
- ## API
16
+ ## Install
18
17
 
19
- Quick start (async/await):
18
+ ### npm
20
19
 
21
- ```javascript
22
- const DirArchiver = require('dir-archiver');
20
+ ```sh
21
+ npm install dir-archiver
22
+ ```
23
23
 
24
- const archive = new DirArchiver(
25
- './my-project',
26
- './my-project.zip',
27
- true,
28
- ['node_modules', 'dist', 'nested/secret.txt'],
29
- false
30
- );
24
+ ### JSR
31
25
 
32
- await archive.createZip();
26
+ ```sh
27
+ deno add jsr:@ismail-elkorchi/dir-archiver
33
28
  ```
34
29
 
35
- Signature:
30
+ ## Quickstart (API)
36
31
 
37
32
  ```ts
38
- new DirArchiver(
39
- directoryPath: string,
40
- zipPath: string,
41
- includeBaseDirectory?: boolean,
42
- excludes?: string[],
43
- followSymlinks?: boolean
44
- )
45
- ```
46
-
47
- Parameters:
48
- - `directoryPath`: Root folder to archive (must exist).
49
- - `zipPath`: Destination zip file path (parent directory must exist).
50
- - `includeBaseDirectory`: When true, the archive contains the source folder as the top-level directory.
51
- - `excludes`: Names or relative paths to skip. Names without path separators match anywhere; use a relative path
52
- (for example, `nested/file.txt`) to target a specific entry. Trailing slashes can target directories (for example, `cache/`).
53
- Windows-style backslashes are accepted and normalized. Absolute paths inside the source tree are accepted and converted
54
- to relative excludes. Matching is case-insensitive on Windows.
55
- - `followSymlinks`: Follow symlinks when traversing directories. Default: `false`.
33
+ import { write, detect, list, extract } from 'dir-archiver';
56
34
 
57
- `createZip()` returns a Promise that resolves with the zip path when the archive is finalized and rejects on failure.
58
- Zip entries always use forward slashes, regardless of OS, and are added in deterministic order.
35
+ await write('./project', './project.zip', {
36
+ format: 'zip',
37
+ includeBaseDirectory: true,
38
+ profile: 'strict'
39
+ });
59
40
 
60
- ## Command Line Interface
41
+ const detected = await detect('./project.zip');
42
+ const listed = await list('./project.zip');
43
+ await extract('./project.zip', './out', { profile: 'strict' });
61
44
 
62
- ```sh
63
- Usage: dir-archiver --src <path-to-directory> --dest <path-to-file>.zip --includebasedir true|false --exclude folder-name file-name.extension
64
-
65
- Options:
66
- --src The path of the folder to archive. [string][required]
67
- --dest The path of the zip file to create. [string][required]
68
- --includebasedir Includes a base directory at the root of the archive.
69
- For example, if the root folder of your project is named
70
- "your-project", setting this option to true will create
71
- an archive that includes this base directory.
72
- If this option is set to false the archive created will
73
- unzip its content to the current directory. [bool]
74
- --followsymlinks Follow symlinks when traversing directories. [bool]
75
- --exclude A list with the names of the files and folders to exclude. Names without
76
- path separators match anywhere; use a relative path to target a specific
77
- entry. Windows-style backslashes are accepted and normalized. [array]
45
+ console.log(detected.format, listed.entries.length);
78
46
  ```
79
47
 
80
- Inline values are supported for flags (for example, `--includebasedir=true` or `--exclude=cache`).
81
-
82
- # CLI examples
48
+ ## Public operations
83
49
 
84
- ```sh
85
- # Basic
86
- dir-archiver --src ./my-project --dest ./my-project.zip
50
+ - `open(input, options)`
51
+ - `detect(input, options)`
52
+ - `list(input, options)`
53
+ - `audit(input, options)`
54
+ - `extract(input, destination, options)`
55
+ - `normalize(input, destination, options)`
56
+ - `write(source, destination, options)`
87
57
 
88
- # Include base directory and exclude node_modules anywhere
89
- dir-archiver --src ./my-project --dest ./my-project.zip --includebasedir=true --exclude node_modules
58
+ Format surface matches bytefold `ArchiveFormat` support.
59
+ Directory + single-file codec requests are normalized to `tar.<codec>` (`gz`, `bz2`, `xz`, `zst`, `br`).
90
60
 
91
- # Exclude a specific path
92
- dir-archiver --src ./my-project --dest ./my-project.zip --exclude nested/secret.txt
93
-
94
- # Windows-style excludes (backslashes are normalized)
95
- dir-archiver --src . --dest archive.zip --exclude .\\nested\\skip.txt
96
-
97
- # Follow symlinks
98
- dir-archiver --src ./my-project --dest ./my-project.zip --followsymlinks=true
99
- ```
100
-
101
- # Testing
61
+ ## CLI
102
62
 
103
63
  ```sh
104
- $ npm test
64
+ dir-archiver write --source ./project --output ./project.zip --format zip --json
65
+ dir-archiver detect --input ./project.zip --json
66
+ dir-archiver list --input ./project.zip --json
67
+ dir-archiver audit --input ./project.zip --profile agent --json
68
+ dir-archiver extract --input ./project.zip --output ./out --profile strict --json
69
+ dir-archiver normalize --input ./project.zip --output ./normalized.zip --json
105
70
  ```
106
71
 
107
- # Development
72
+ Exit codes:
108
73
 
109
- ```sh
110
- $ npm install
111
- $ npm run typecheck
112
- $ npm run build
113
- $ npm run lint
114
- ```
74
+ - `0` success
75
+ - `1` operational failure
76
+ - `2` usage/validation failure
115
77
 
116
- Linting runs TypeScript typechecking and ESLint. CI runs lint and tests on Node 18/20/22 across Linux, macOS, and Windows.
78
+ ## Security model
117
79
 
80
+ - Archive extraction treats input as untrusted by default.
81
+ - Traversal/absolute paths are blocked in strict/agent profiles.
82
+ - See `SECURITY.md` and `docs/security-triage.md`.
118
83
 
84
+ ## Docs
119
85
 
120
- [changelog-image]: https://img.shields.io/badge/changelog-md-blue.svg?style=flat-square
121
- [changelog-url]: CHANGELOG.md
122
- [license-image]: https://img.shields.io/npm/l/dir-archiver.svg?style=flat-square
123
- [license-url]: LICENSE
124
- [npm-image]: https://img.shields.io/npm/v/dir-archiver.svg?style=flat-square
125
- [npm-url]: https://www.npmjs.com/package/dir-archiver
86
+ - `docs/V3_CONTRACT.md`
87
+ - `CHANGELOG.md`
88
+ - `SECURITY.md`
@@ -0,0 +1,24 @@
1
+ import type { ArchiveFormat, ArchiveProfile } from './types.js';
2
+ export type CliCommand = 'open' | 'detect' | 'list' | 'audit' | 'extract' | 'normalize' | 'write';
3
+ export interface ParsedCliArgs {
4
+ ok: boolean;
5
+ issues: {
6
+ code: string;
7
+ message: string;
8
+ }[];
9
+ command: CliCommand | undefined;
10
+ input: string | undefined;
11
+ source: string | undefined;
12
+ output: string | undefined;
13
+ format: ArchiveFormat | undefined;
14
+ profile: ArchiveProfile;
15
+ json: boolean;
16
+ includeBaseDirectory: boolean;
17
+ followSymlinks: boolean;
18
+ exclude: string[];
19
+ allowSymlinks: boolean;
20
+ allowHardlinks: boolean;
21
+ maxEntryBytes: number | undefined;
22
+ maxTotalExtractedBytes: number | undefined;
23
+ }
24
+ export declare const parseCliArgs: (argv: readonly string[]) => Promise<ParsedCliArgs>;
@@ -0,0 +1,204 @@
1
+ const SUPPORTED_COMMANDS = new Set(['open', 'detect', 'list', 'audit', 'extract', 'normalize', 'write']);
2
+ const SUPPORTED_FORMATS = new Set([
3
+ 'zip',
4
+ 'tar',
5
+ 'tgz',
6
+ 'tar.gz',
7
+ 'gz',
8
+ 'bz2',
9
+ 'tar.bz2',
10
+ 'zst',
11
+ 'tar.zst',
12
+ 'br',
13
+ 'tar.br',
14
+ 'xz',
15
+ 'tar.xz'
16
+ ]);
17
+ const SUPPORTED_PROFILES = new Set(['compat', 'strict', 'agent']);
18
+ const CLI_SCHEMA = {
19
+ source: {
20
+ type: 'string',
21
+ flags: ['--source', '--src']
22
+ },
23
+ input: {
24
+ type: 'string',
25
+ flags: ['--input', '-i']
26
+ },
27
+ output: {
28
+ type: 'string',
29
+ flags: ['--output', '--dest', '-o']
30
+ },
31
+ format: {
32
+ type: 'string',
33
+ flags: ['--format']
34
+ },
35
+ profile: {
36
+ type: 'string',
37
+ flags: ['--profile'],
38
+ default: 'strict'
39
+ },
40
+ json: {
41
+ type: 'boolean',
42
+ flags: ['--json'],
43
+ default: false
44
+ },
45
+ includeBaseDirectory: {
46
+ type: 'boolean',
47
+ flags: ['--include-base-directory', '--includebasedir'],
48
+ default: false
49
+ },
50
+ followSymlinks: {
51
+ type: 'boolean',
52
+ flags: ['--follow-symlinks', '--followsymlinks'],
53
+ default: false
54
+ },
55
+ exclude: {
56
+ type: 'array',
57
+ flags: ['--exclude'],
58
+ default: []
59
+ },
60
+ allowSymlinks: {
61
+ type: 'boolean',
62
+ flags: ['--allow-symlinks'],
63
+ default: false
64
+ },
65
+ allowHardlinks: {
66
+ type: 'boolean',
67
+ flags: ['--allow-hardlinks'],
68
+ default: false
69
+ },
70
+ maxEntryBytes: {
71
+ type: 'number',
72
+ flags: ['--max-entry-bytes']
73
+ },
74
+ maxTotalExtractedBytes: {
75
+ type: 'number',
76
+ flags: ['--max-total-extracted-bytes']
77
+ }
78
+ };
79
+ let parseArgsPromise;
80
+ const loadParseArgs = () => {
81
+ parseArgsPromise !== null && parseArgsPromise !== void 0 ? parseArgsPromise : (parseArgsPromise = import('argv-flags').then((moduleExports) => moduleExports.default));
82
+ return parseArgsPromise;
83
+ };
84
+ export const parseCliArgs = async (argv) => {
85
+ const parseArgs = await loadParseArgs();
86
+ const parsed = parseArgs(CLI_SCHEMA, {
87
+ argv: [...argv]
88
+ });
89
+ const issues = parsed.issues.map((issue) => ({
90
+ code: issue.code,
91
+ message: issue.message
92
+ }));
93
+ const values = parsed.values;
94
+ const commandToken = parsed.rest[0];
95
+ const command = resolveCommand(commandToken, values, issues);
96
+ const profile = resolveProfile(values['profile'], issues);
97
+ const format = resolveFormat(values['format'], issues);
98
+ const source = toOptionalString(values['source']);
99
+ const input = toOptionalString(values['input']);
100
+ const output = toOptionalString(values['output']);
101
+ validateCommandRequirements(command, { source, input, output }, issues);
102
+ return {
103
+ ok: issues.length === 0,
104
+ issues,
105
+ command,
106
+ source,
107
+ input,
108
+ output,
109
+ format,
110
+ profile,
111
+ json: values['json'] === true,
112
+ includeBaseDirectory: values['includeBaseDirectory'] === true,
113
+ followSymlinks: values['followSymlinks'] === true,
114
+ exclude: toStringArray(values['exclude']),
115
+ allowSymlinks: values['allowSymlinks'] === true,
116
+ allowHardlinks: values['allowHardlinks'] === true,
117
+ maxEntryBytes: toOptionalNumber(values['maxEntryBytes']),
118
+ maxTotalExtractedBytes: toOptionalNumber(values['maxTotalExtractedBytes'])
119
+ };
120
+ };
121
+ const resolveCommand = (commandToken, values, issues) => {
122
+ if (typeof commandToken === 'string' && SUPPORTED_COMMANDS.has(commandToken)) {
123
+ return commandToken;
124
+ }
125
+ if (typeof commandToken === 'string' && commandToken.length > 0) {
126
+ issues.push({
127
+ code: 'USAGE',
128
+ message: `Unknown command "${commandToken}".`
129
+ });
130
+ return undefined;
131
+ }
132
+ const hasSource = typeof values['source'] === 'string';
133
+ const hasOutput = typeof values['output'] === 'string';
134
+ if (hasSource && hasOutput) {
135
+ return 'write';
136
+ }
137
+ issues.push({
138
+ code: 'USAGE',
139
+ message: 'Missing command.'
140
+ });
141
+ return undefined;
142
+ };
143
+ const resolveProfile = (value, issues) => {
144
+ const normalized = typeof value === 'string' ? value : 'strict';
145
+ if (!SUPPORTED_PROFILES.has(normalized)) {
146
+ issues.push({
147
+ code: 'INVALID_VALUE',
148
+ message: `Unsupported profile "${String(value)}".`
149
+ });
150
+ return 'strict';
151
+ }
152
+ return normalized;
153
+ };
154
+ const resolveFormat = (value, issues) => {
155
+ if (typeof value !== 'string') {
156
+ return undefined;
157
+ }
158
+ if (!SUPPORTED_FORMATS.has(value)) {
159
+ issues.push({
160
+ code: 'INVALID_VALUE',
161
+ message: `Unsupported format "${value}".`
162
+ });
163
+ return undefined;
164
+ }
165
+ return value;
166
+ };
167
+ const validateCommandRequirements = (command, values, issues) => {
168
+ if (!command) {
169
+ return;
170
+ }
171
+ if (command === 'write') {
172
+ if (!values.source) {
173
+ issues.push({ code: 'REQUIRED', message: 'write requires --source/--src.' });
174
+ }
175
+ if (!values.output) {
176
+ issues.push({ code: 'REQUIRED', message: 'write requires --output/--dest.' });
177
+ }
178
+ return;
179
+ }
180
+ if (command === 'extract' || command === 'normalize') {
181
+ if (!values.input) {
182
+ issues.push({ code: 'REQUIRED', message: `${command} requires --input.` });
183
+ }
184
+ if (!values.output) {
185
+ issues.push({ code: 'REQUIRED', message: `${command} requires --output.` });
186
+ }
187
+ return;
188
+ }
189
+ if (!values.input) {
190
+ issues.push({ code: 'REQUIRED', message: `${command} requires --input.` });
191
+ }
192
+ };
193
+ const toOptionalString = (value) => {
194
+ return typeof value === 'string' ? value : undefined;
195
+ };
196
+ const toStringArray = (value) => {
197
+ if (!Array.isArray(value)) {
198
+ return [];
199
+ }
200
+ return value.filter((item) => typeof item === 'string');
201
+ };
202
+ const toOptionalNumber = (value) => {
203
+ return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
204
+ };
package/dist/cli.js CHANGED
@@ -1,51 +1,136 @@
1
1
  #!/usr/bin/env node
2
- "use strict";
3
- var __importDefault = (this && this.__importDefault) || function (mod) {
4
- return (mod && mod.__esModule) ? mod : { "default": mod };
5
- };
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- const index_1 = __importDefault(require("./index"));
8
- const argv_flags_1 = __importDefault(require("argv-flags"));
9
- const parseBooleanFlag = (flag) => {
10
- const rawValue = (0, argv_flags_1.default)(flag, 'string');
11
- if (typeof rawValue === 'string' && rawValue.length > 0 && !rawValue.startsWith('-')) {
12
- const normalized = rawValue.toLowerCase();
13
- if (normalized === 'true') {
14
- return true;
15
- }
16
- if (normalized === 'false') {
17
- return false;
2
+ import { audit, detect, extract, list, normalize, open, write } from './index.js';
3
+ import { DirArchiverError } from './errors.js';
4
+ import { parseCliArgs } from './cli-args.js';
5
+ const usage = `Usage:
6
+ dir-archiver write --source <path> --output <archive> [--format <format>] [--include-base-directory] [--exclude <path>...]
7
+ dir-archiver detect --input <archive>
8
+ dir-archiver list --input <archive>
9
+ dir-archiver audit --input <archive> [--profile compat|strict|agent]
10
+ dir-archiver extract --input <archive> --output <directory> [--profile compat|strict|agent] [--max-entry-bytes <n>] [--max-total-extracted-bytes <n>]
11
+ dir-archiver normalize --input <archive> --output <archive> [--profile compat|strict|agent]
12
+
13
+ Common options:
14
+ --format <format> zip|tar|tgz|tar.gz|gz|bz2|tar.bz2|zst|tar.zst|br|tar.br|xz|tar.xz
15
+ --profile <profile> compat|strict|agent
16
+ --json emit machine-readable JSON
17
+ --allow-symlinks enable symlink extraction
18
+ --allow-hardlinks enable hardlink extraction (currently unsupported)
19
+ `;
20
+ const run = async () => {
21
+ const parsed = await parseCliArgs(process.argv.slice(2));
22
+ const command = parsed.command;
23
+ if (!parsed.ok || !command) {
24
+ const payload = {
25
+ schemaVersion: '1',
26
+ code: 'DIRARCHIVER_USAGE',
27
+ message: 'Invalid CLI arguments.',
28
+ issues: parsed.issues
29
+ };
30
+ if (parsed.json) {
31
+ console.log(JSON.stringify(payload));
32
+ }
33
+ else {
34
+ console.error(usage);
35
+ for (const issue of parsed.issues) {
36
+ console.error(`- [${issue.code}] ${issue.message}`);
37
+ }
38
+ }
39
+ return 2;
40
+ }
41
+ const commonOptions = {
42
+ profile: parsed.profile,
43
+ ...(parsed.format ? { format: parsed.format } : {})
44
+ };
45
+ switch (command) {
46
+ case 'write': {
47
+ const result = await write(requireString(parsed.source, 'write requires --source/--src'), requireString(parsed.output, 'write requires --output/--dest'), {
48
+ ...commonOptions,
49
+ includeBaseDirectory: parsed.includeBaseDirectory,
50
+ followSymlinks: parsed.followSymlinks,
51
+ exclude: parsed.exclude
52
+ });
53
+ outputResult(parsed.json, result);
54
+ return 0;
55
+ }
56
+ case 'open': {
57
+ const reader = await open(requireString(parsed.input, 'open requires --input'), commonOptions);
58
+ outputResult(parsed.json, {
59
+ format: reader.format,
60
+ detection: reader.detection
61
+ });
62
+ return 0;
63
+ }
64
+ case 'detect': {
65
+ const result = await detect(requireString(parsed.input, 'detect requires --input'), commonOptions);
66
+ outputResult(parsed.json, result);
67
+ return 0;
68
+ }
69
+ case 'list': {
70
+ const result = await list(requireString(parsed.input, 'list requires --input'), commonOptions);
71
+ outputResult(parsed.json, result);
72
+ return 0;
73
+ }
74
+ case 'audit': {
75
+ const result = await audit(requireString(parsed.input, 'audit requires --input'), commonOptions);
76
+ outputResult(parsed.json, result);
77
+ return 0;
78
+ }
79
+ case 'extract': {
80
+ const result = await extract(requireString(parsed.input, 'extract requires --input'), requireString(parsed.output, 'extract requires --output'), {
81
+ ...commonOptions,
82
+ allowSymlinks: parsed.allowSymlinks,
83
+ allowHardlinks: parsed.allowHardlinks,
84
+ ...(typeof parsed.maxEntryBytes === 'number' ? { maxEntryBytes: parsed.maxEntryBytes } : {}),
85
+ ...(typeof parsed.maxTotalExtractedBytes === 'number'
86
+ ? { maxTotalExtractedBytes: parsed.maxTotalExtractedBytes }
87
+ : {})
88
+ });
89
+ outputResult(parsed.json, result);
90
+ return 0;
91
+ }
92
+ case 'normalize': {
93
+ const result = await normalize(requireString(parsed.input, 'normalize requires --input'), requireString(parsed.output, 'normalize requires --output'), {
94
+ ...commonOptions
95
+ });
96
+ outputResult(parsed.json, result);
97
+ return 0;
18
98
  }
99
+ default:
100
+ break;
19
101
  }
20
- return (0, argv_flags_1.default)(flag, 'boolean') === true;
102
+ const unreachable = command;
103
+ throw new Error(`Unhandled command: ${String(unreachable)}`);
21
104
  };
22
- const directoryPath = (0, argv_flags_1.default)('--src', 'string');
23
- const zipPath = (0, argv_flags_1.default)('--dest', 'string');
24
- const includeBaseDirectory = parseBooleanFlag('--includebasedir');
25
- const followSymlinks = parseBooleanFlag('--followsymlinks');
26
- const excludeValues = (0, argv_flags_1.default)('--exclude', 'array');
27
- const excludes = Array.isArray(excludeValues) ? excludeValues : [];
28
- if (typeof directoryPath !== 'string' || typeof zipPath !== 'string') {
29
- console.log(` Dir Archiver could not be executed. Some arguments are missing.
30
-
31
- Options:
32
- --src The path of the folder to archive. [string][required]
33
- --dest The path of the zip file to create. [string][required]
34
- --includebasedir Includes a base directory at the root of the archive.
35
- For example, if the root folder of your project is named
36
- "your-project", setting this option to true will create
37
- an archive that includes this base directory.
38
- If this option is set to false the archive created will
39
- unzip its content to the current directory. [bool]
40
- --followsymlinks Follow symlinks when traversing directories. [bool]
41
- --exclude A list with the names of the files and folders to exclude. [array]`);
42
- process.exitCode = 1;
43
- }
44
- else {
45
- const archive = new index_1.default(directoryPath, zipPath, includeBaseDirectory, excludes, followSymlinks);
46
- archive.createZip().catch((err) => {
47
- const normalizedError = err instanceof Error ? err : new Error(String(err));
48
- console.error(normalizedError);
105
+ const outputResult = (asJson, payload) => {
106
+ if (asJson) {
107
+ console.log(JSON.stringify(payload));
108
+ return;
109
+ }
110
+ console.log(payload);
111
+ };
112
+ const requireString = (value, message) => {
113
+ if (typeof value !== 'string' || value.length === 0) {
114
+ throw new DirArchiverError('DIRARCHIVER_USAGE', message);
115
+ }
116
+ return value;
117
+ };
118
+ void run()
119
+ .then((exitCode) => {
120
+ process.exitCode = exitCode;
121
+ })
122
+ .catch((error) => {
123
+ var _a;
124
+ if (error instanceof DirArchiverError) {
125
+ console.error(JSON.stringify(error.toJSON()));
49
126
  process.exitCode = 1;
50
- });
51
- }
127
+ return;
128
+ }
129
+ if (error instanceof Error) {
130
+ console.error((_a = error.stack) !== null && _a !== void 0 ? _a : error.message);
131
+ }
132
+ else {
133
+ console.error(String(error));
134
+ }
135
+ process.exitCode = 1;
136
+ });
package/dist/core.d.ts ADDED
@@ -0,0 +1,33 @@
1
+ import type { ArchiveAuditReport, ArchiveReader } from '@ismail-elkorchi/bytefold';
2
+ import type { DetectResult, DirArchiverInput, ExtractOptions, ExtractResult, ListResult, NormalizeOptions, NormalizeResult, OpenOptions, WriteOptions, WriteResult } from './types.js';
3
+ /**
4
+ * Opens an archive input with bytefold runtime bindings.
5
+ */
6
+ export declare const open: (input: DirArchiverInput, options?: OpenOptions) => Promise<ArchiveReader>;
7
+ /**
8
+ * Detects archive format and exposes bytefold detection metadata.
9
+ */
10
+ export declare const detect: (input: DirArchiverInput, options?: OpenOptions) => Promise<DetectResult>;
11
+ /**
12
+ * Lists archive entries without extracting to disk.
13
+ */
14
+ export declare const list: (input: DirArchiverInput, options?: OpenOptions) => Promise<ListResult>;
15
+ /**
16
+ * Runs bytefold audit checks for the selected safety profile.
17
+ */
18
+ export declare const audit: (input: DirArchiverInput, options?: OpenOptions) => Promise<ArchiveAuditReport>;
19
+ /**
20
+ * Writes a normalized deterministic archive when supported by the format.
21
+ */
22
+ export declare const normalize: (input: DirArchiverInput, destination: string, options?: NormalizeOptions) => Promise<NormalizeResult>;
23
+ /**
24
+ * Extracts entries to a destination directory with safety enforcement.
25
+ */
26
+ export declare const extract: (input: DirArchiverInput, destination: string, options?: ExtractOptions) => Promise<ExtractResult>;
27
+ /**
28
+ * Writes an archive from a file or directory source.
29
+ */
30
+ export declare const write: (source: string, destination: string, options?: WriteOptions) => Promise<WriteResult>;
31
+ export declare const copyStreamToFile: (source: string, destination: string) => Promise<void>;
32
+ export declare const pathExists: (value: string) => boolean;
33
+ export declare const fileSize: (value: string) => number;