dir-archiver 3.0.1 → 3.0.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.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,12 @@
4
4
 
5
5
  * No entries yet.
6
6
 
7
+ ### 3.0.2 (June 19, 2026)
8
+
9
+ * Fix JSR documentation checks for current and pinned Deno doc output.
10
+ * Update `argv-flags` to 1.0.5.
11
+ * Bump GitHub Actions dependencies in CI and release workflows.
12
+
7
13
  ### 3.0.1 (March 3, 2026)
8
14
 
9
15
  * Rework README/docs information architecture for fast first-use onboarding.
package/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # dir-archiver
2
2
 
3
- Archive orchestration for detect/list/audit/extract/normalize/write flows across Node, Deno, and Bun.
3
+ Deterministic directory archiving and extraction over zip, tar, and layered compression.
4
+
5
+ Supports Node.js, Deno, and Bun.
4
6
 
5
7
  ## What it is
6
8
 
@@ -29,12 +31,6 @@ await extract("./project.zip", "./out", { profile: "strict" });
29
31
  console.log(detected.format);
30
32
  ```
31
33
 
32
- ## Options reference
33
-
34
- - [Options reference](https://github.com/Ismail-elkorchi/dir-archiver/blob/main/docs/reference/options.md)
35
- - [CLI reference](https://github.com/Ismail-elkorchi/dir-archiver/blob/main/docs/reference/cli.md)
36
- - [10-minute tutorial: bundle a plugin directory](https://github.com/Ismail-elkorchi/dir-archiver/blob/main/docs/tutorial/bundle-a-plugin.md)
37
-
38
34
  ## When not to use
39
35
 
40
36
  - You only need a low-level parser for a single format.
@@ -51,19 +47,13 @@ console.log(detected.format);
51
47
 
52
48
  - Module system: ESM-only.
53
49
  - Runtimes: Node `>=24`, current Deno, current Bun.
54
- - CLI and API contracts are documented in `CONTRACT.md`.
50
+ - CLI and API contracts are documented in [Contract](https://github.com/Ismail-elkorchi/dir-archiver/blob/main/CONTRACT.md).
55
51
 
56
- ## Links
52
+ ## Documentation
57
53
 
58
54
  - [Docs index](https://github.com/Ismail-elkorchi/dir-archiver/blob/main/docs/index.md)
59
- - Reference:
60
- - [Reference index](https://github.com/Ismail-elkorchi/dir-archiver/blob/main/docs/reference/index.md)
61
- - [Contract](https://github.com/Ismail-elkorchi/dir-archiver/blob/main/CONTRACT.md)
62
- - [Security policy](https://github.com/Ismail-elkorchi/dir-archiver/blob/main/SECURITY.md)
63
- - How-to:
64
- - [How-to index](https://github.com/Ismail-elkorchi/dir-archiver/blob/main/docs/how-to/index.md)
65
- - [Contributing](https://github.com/Ismail-elkorchi/dir-archiver/blob/main/CONTRIBUTING.md)
66
- - Explanation: [explanation index](https://github.com/Ismail-elkorchi/dir-archiver/blob/main/docs/explanation/index.md)
55
+ - [Tutorial: bundle a plugin directory](https://github.com/Ismail-elkorchi/dir-archiver/blob/main/docs/tutorial/bundle-a-plugin.md)
56
+ - [Reference: CLI](https://github.com/Ismail-elkorchi/dir-archiver/blob/main/docs/reference/cli.md)
67
57
 
68
58
  ## Verification
69
59
 
package/dist/core.d.ts CHANGED
@@ -1,31 +1,100 @@
1
1
  import type { ArchiveAuditReport, ArchiveReader } from '@ismail-elkorchi/bytefold';
2
2
  import type { DetectResult, DirArchiverInput, ExtractOptions, ExtractResult, ListResult, NormalizeOptions, NormalizeResult, OpenOptions, WriteOptions, WriteResult } from './types.js';
3
3
  /**
4
- * Opens an archive input with bytefold runtime bindings.
4
+ * Opens an archive and returns the live bytefold reader.
5
+ *
6
+ * Use this when you need direct access to low-level reader capabilities such
7
+ * as `entries()`, `audit()`, or normalization support checks. The returned
8
+ * reader is not auto-disposed, so callers should close or dispose it when the
9
+ * active runtime exposes a cleanup hook.
10
+ *
11
+ * @param input Archive bytes, path, URL, stream, or blob to open.
12
+ * @param options Format hints, safety profile, limits, and cancellation
13
+ * signal forwarded to bytefold.
14
+ * @returns A live `ArchiveReader` for advanced inspection flows.
5
15
  */
6
16
  export declare const open: (input: DirArchiverInput, options?: OpenOptions) => Promise<ArchiveReader>;
7
17
  /**
8
- * Detects archive format and exposes bytefold detection metadata.
18
+ * Detects an archive format without extracting or listing its contents.
19
+ *
20
+ * This is the lightest-weight way to confirm the container and compression
21
+ * layers before choosing a follow-up operation.
22
+ *
23
+ * @param input Archive bytes, path, URL, stream, or blob to inspect.
24
+ * @param options Format hints and parse controls applied during detection.
25
+ * @returns The resolved archive format and any bytefold detection metadata.
9
26
  */
10
27
  export declare const detect: (input: DirArchiverInput, options?: OpenOptions) => Promise<DetectResult>;
11
28
  /**
12
- * Lists archive entries without extracting to disk.
29
+ * Lists archive entries without extracting anything to disk.
30
+ *
31
+ * Each entry is projected into a JSON-safe summary so CLI and API callers can
32
+ * inspect paths, sizes, and link metadata before deciding to extract.
33
+ *
34
+ * @param input Archive bytes, path, URL, stream, or blob to inspect.
35
+ * @param options Format hints and parse controls applied while reading the
36
+ * archive directory.
37
+ * @returns Archive metadata plus the entry summaries visible to callers.
13
38
  */
14
39
  export declare const list: (input: DirArchiverInput, options?: OpenOptions) => Promise<ListResult>;
15
40
  /**
16
- * Runs bytefold audit checks for the selected safety profile.
41
+ * Audits an archive against the selected bytefold safety profile.
42
+ *
43
+ * Use this before extraction when you need a report of unsafe paths, link
44
+ * entries, or format-specific concerns without writing files to disk.
45
+ *
46
+ * @param input Archive bytes, path, URL, stream, or blob to audit.
47
+ * @param options Safety profile, limits, and format hints used during the
48
+ * audit pass.
49
+ * @returns The bytefold audit report for the requested profile.
17
50
  */
18
51
  export declare const audit: (input: DirArchiverInput, options?: OpenOptions) => Promise<ArchiveAuditReport>;
19
52
  /**
20
- * Writes a normalized deterministic archive when supported by the format.
53
+ * Rewrites an archive into its normalized deterministic representation.
54
+ *
55
+ * Normalization is available only when the opened archive reader exposes
56
+ * bytefold normalization support. Unsupported formats throw
57
+ * `DIRARCHIVER_NORMALIZE_UNSUPPORTED`.
58
+ *
59
+ * @param input Archive bytes, path, URL, stream, or blob to normalize.
60
+ * @param destination Output archive path that will receive the normalized
61
+ * bytes.
62
+ * @param options Format hints and normalization controls applied during the
63
+ * read and write pass.
64
+ * @returns The source format and bytefold normalization report.
65
+ * @throws {DirArchiverError} When the selected archive format cannot be
66
+ * normalized by the active runtime.
21
67
  */
22
68
  export declare const normalize: (input: DirArchiverInput, destination: string, options?: NormalizeOptions) => Promise<NormalizeResult>;
23
69
  /**
24
- * Extracts entries to a destination directory with safety enforcement.
70
+ * Extracts an archive into a destination directory with safety enforcement.
71
+ *
72
+ * `extract()` defaults to `profile: 'strict'`. Under `strict` or `agent`, the
73
+ * archive is audited before bytes are written to disk and unsafe entries raise
74
+ * a `DirArchiverError` instead of being silently materialized.
75
+ *
76
+ * @param input Archive bytes, path, URL, stream, or blob to extract.
77
+ * @param destination Directory that will receive extracted files.
78
+ * @param options Extraction policy, safety profile, and resource limits.
79
+ * @returns A summary of what was extracted, skipped, and flagged.
80
+ * @throws {DirArchiverError} When audit checks fail, resource limits are
81
+ * exceeded, or unsupported entry types are encountered.
25
82
  */
26
83
  export declare const extract: (input: DirArchiverInput, destination: string, options?: ExtractOptions) => Promise<ExtractResult>;
27
84
  /**
28
- * Writes an archive from a file or directory source.
85
+ * Writes an archive from a file or directory source path.
86
+ *
87
+ * Directory sources are traversed deterministically. When callers request a
88
+ * single-file compression codec such as `gz` for a directory source,
89
+ * `dir-archiver` wraps the directory in the corresponding tar-based container
90
+ * (`tar.gz`, `tar.zst`, and so on).
91
+ *
92
+ * @param source File or directory path to archive.
93
+ * @param destination Output archive path.
94
+ * @param options Format selection, traversal rules, and exclusion controls.
95
+ * @returns A summary of the emitted archive format and entry count.
96
+ * @throws {DirArchiverError} When the requested output format is unsupported by
97
+ * the active bytefold writer.
29
98
  */
30
99
  export declare const write: (source: string, destination: string, options?: WriteOptions) => Promise<WriteResult>;
31
100
  export declare const copyStreamToFile: (source: string, destination: string) => Promise<void>;
package/dist/core.js CHANGED
@@ -12,14 +12,31 @@ const DIRECTORY_TO_SINGLE_FILE_CODEC = {
12
12
  };
13
13
  const writeUnsupportedFormats = new Set(['tar.bz2', 'bz2', 'tar.xz', 'xz']);
14
14
  /**
15
- * Opens an archive input with bytefold runtime bindings.
15
+ * Opens an archive and returns the live bytefold reader.
16
+ *
17
+ * Use this when you need direct access to low-level reader capabilities such
18
+ * as `entries()`, `audit()`, or normalization support checks. The returned
19
+ * reader is not auto-disposed, so callers should close or dispose it when the
20
+ * active runtime exposes a cleanup hook.
21
+ *
22
+ * @param input Archive bytes, path, URL, stream, or blob to open.
23
+ * @param options Format hints, safety profile, limits, and cancellation
24
+ * signal forwarded to bytefold.
25
+ * @returns A live `ArchiveReader` for advanced inspection flows.
16
26
  */
17
27
  export const open = async (input, options = {}) => {
18
28
  const runtime = await loadRuntimeBindings();
19
29
  return runtime.openArchive(input, toArchiveOpenOptions(options));
20
30
  };
21
31
  /**
22
- * Detects archive format and exposes bytefold detection metadata.
32
+ * Detects an archive format without extracting or listing its contents.
33
+ *
34
+ * This is the lightest-weight way to confirm the container and compression
35
+ * layers before choosing a follow-up operation.
36
+ *
37
+ * @param input Archive bytes, path, URL, stream, or blob to inspect.
38
+ * @param options Format hints and parse controls applied during detection.
39
+ * @returns The resolved archive format and any bytefold detection metadata.
23
40
  */
24
41
  export const detect = async (input, options = {}) => {
25
42
  const reader = await open(input, options);
@@ -34,7 +51,15 @@ export const detect = async (input, options = {}) => {
34
51
  }
35
52
  };
36
53
  /**
37
- * Lists archive entries without extracting to disk.
54
+ * Lists archive entries without extracting anything to disk.
55
+ *
56
+ * Each entry is projected into a JSON-safe summary so CLI and API callers can
57
+ * inspect paths, sizes, and link metadata before deciding to extract.
58
+ *
59
+ * @param input Archive bytes, path, URL, stream, or blob to inspect.
60
+ * @param options Format hints and parse controls applied while reading the
61
+ * archive directory.
62
+ * @returns Archive metadata plus the entry summaries visible to callers.
38
63
  */
39
64
  export const list = async (input, options = {}) => {
40
65
  const reader = await open(input, options);
@@ -61,7 +86,15 @@ export const list = async (input, options = {}) => {
61
86
  }
62
87
  };
63
88
  /**
64
- * Runs bytefold audit checks for the selected safety profile.
89
+ * Audits an archive against the selected bytefold safety profile.
90
+ *
91
+ * Use this before extraction when you need a report of unsafe paths, link
92
+ * entries, or format-specific concerns without writing files to disk.
93
+ *
94
+ * @param input Archive bytes, path, URL, stream, or blob to audit.
95
+ * @param options Safety profile, limits, and format hints used during the
96
+ * audit pass.
97
+ * @returns The bytefold audit report for the requested profile.
65
98
  */
66
99
  export const audit = async (input, options = {}) => {
67
100
  const reader = await open(input, options);
@@ -73,7 +106,20 @@ export const audit = async (input, options = {}) => {
73
106
  }
74
107
  };
75
108
  /**
76
- * Writes a normalized deterministic archive when supported by the format.
109
+ * Rewrites an archive into its normalized deterministic representation.
110
+ *
111
+ * Normalization is available only when the opened archive reader exposes
112
+ * bytefold normalization support. Unsupported formats throw
113
+ * `DIRARCHIVER_NORMALIZE_UNSUPPORTED`.
114
+ *
115
+ * @param input Archive bytes, path, URL, stream, or blob to normalize.
116
+ * @param destination Output archive path that will receive the normalized
117
+ * bytes.
118
+ * @param options Format hints and normalization controls applied during the
119
+ * read and write pass.
120
+ * @returns The source format and bytefold normalization report.
121
+ * @throws {DirArchiverError} When the selected archive format cannot be
122
+ * normalized by the active runtime.
77
123
  */
78
124
  export const normalize = async (input, destination, options = {}) => {
79
125
  const reader = await open(input, options);
@@ -95,7 +141,18 @@ export const normalize = async (input, destination, options = {}) => {
95
141
  }
96
142
  };
97
143
  /**
98
- * Extracts entries to a destination directory with safety enforcement.
144
+ * Extracts an archive into a destination directory with safety enforcement.
145
+ *
146
+ * `extract()` defaults to `profile: 'strict'`. Under `strict` or `agent`, the
147
+ * archive is audited before bytes are written to disk and unsafe entries raise
148
+ * a `DirArchiverError` instead of being silently materialized.
149
+ *
150
+ * @param input Archive bytes, path, URL, stream, or blob to extract.
151
+ * @param destination Directory that will receive extracted files.
152
+ * @param options Extraction policy, safety profile, and resource limits.
153
+ * @returns A summary of what was extracted, skipped, and flagged.
154
+ * @throws {DirArchiverError} When audit checks fail, resource limits are
155
+ * exceeded, or unsupported entry types are encountered.
99
156
  */
100
157
  export const extract = async (input, destination, options = {}) => {
101
158
  var _a;
@@ -180,7 +237,19 @@ export const extract = async (input, destination, options = {}) => {
180
237
  }
181
238
  };
182
239
  /**
183
- * Writes an archive from a file or directory source.
240
+ * Writes an archive from a file or directory source path.
241
+ *
242
+ * Directory sources are traversed deterministically. When callers request a
243
+ * single-file compression codec such as `gz` for a directory source,
244
+ * `dir-archiver` wraps the directory in the corresponding tar-based container
245
+ * (`tar.gz`, `tar.zst`, and so on).
246
+ *
247
+ * @param source File or directory path to archive.
248
+ * @param destination Output archive path.
249
+ * @param options Format selection, traversal rules, and exclusion controls.
250
+ * @returns A summary of the emitted archive format and entry count.
251
+ * @throws {DirArchiverError} When the requested output format is unsupported by
252
+ * the active bytefold writer.
184
253
  */
185
254
  export const write = async (source, destination, options = {}) => {
186
255
  var _a, _b;
package/dist/errors.d.ts CHANGED
@@ -1,25 +1,69 @@
1
1
  /**
2
- * Stable dir-archiver error codes.
2
+ * Stable machine-readable error codes emitted by `dir-archiver`.
3
+ *
4
+ * - `DIRARCHIVER_INVALID_SOURCE`: input bytes or paths could not be read.
5
+ * - `DIRARCHIVER_INVALID_DESTINATION`: destination path or parent directory is
6
+ * invalid for the requested operation.
7
+ * - `DIRARCHIVER_PATH_TRAVERSAL`: strict extraction rejected a traversal or
8
+ * absolute-path entry.
9
+ * - `DIRARCHIVER_UNSUPPORTED_ENTRY`: the archive contains an entry type or
10
+ * feature that `dir-archiver` does not support safely.
11
+ * - `DIRARCHIVER_RESOURCE_LIMIT`: extraction exceeded configured byte limits.
12
+ * - `DIRARCHIVER_RUNTIME_UNSUPPORTED`: the current runtime cannot satisfy a
13
+ * required bytefold capability.
14
+ * - `DIRARCHIVER_NORMALIZE_UNSUPPORTED`: normalization is unavailable for the
15
+ * selected format/runtime pair.
16
+ * - `DIRARCHIVER_USAGE`: CLI invocation is missing required flags or uses
17
+ * unsupported values.
3
18
  */
4
19
  export type DirArchiverErrorCode = 'DIRARCHIVER_INVALID_SOURCE' | 'DIRARCHIVER_INVALID_DESTINATION' | 'DIRARCHIVER_PATH_TRAVERSAL' | 'DIRARCHIVER_UNSUPPORTED_ENTRY' | 'DIRARCHIVER_RESOURCE_LIMIT' | 'DIRARCHIVER_RUNTIME_UNSUPPORTED' | 'DIRARCHIVER_NORMALIZE_UNSUPPORTED' | 'DIRARCHIVER_USAGE';
20
+ /**
21
+ * Stable JSON payload emitted by `DirArchiverError.toJSON()`.
22
+ *
23
+ * This is the machine-readable error shape used by the CLI `--json` surface and
24
+ * by API consumers that persist `DirArchiverError` objects to logs or reports.
25
+ */
26
+ export interface DirArchiverErrorJson {
27
+ /** Schema version for the serialized error payload. */
28
+ schemaVersion: '1';
29
+ /** Stable error class name used in serialized output. */
30
+ name: 'DirArchiverError';
31
+ /** Stable machine-readable error code. */
32
+ code: DirArchiverErrorCode;
33
+ /** Human-readable summary of the failure. */
34
+ message: string;
35
+ /** Optional remediation hint when the error carries one. */
36
+ hint?: string;
37
+ /** Optional structured context for logs and diagnostics. */
38
+ context?: Record<string, unknown>;
39
+ }
5
40
  /**
6
41
  * Structured error contract for dir-archiver v3.
7
42
  */
8
43
  export declare class DirArchiverError extends Error {
44
+ /** Stable machine-readable error code. */
9
45
  readonly code: DirArchiverErrorCode;
46
+ /** Optional operator-facing hint for remediation. */
10
47
  readonly hint: string | undefined;
48
+ /** Optional structured context for logs, JSON output, or diagnostics. */
11
49
  readonly context: Record<string, unknown> | undefined;
50
+ /**
51
+ * Creates a structured error value safe for CLI and API consumers.
52
+ *
53
+ * @param code Stable machine-readable error code.
54
+ * @param message Human-readable summary of the failure.
55
+ * @param options Optional hint, structured context, and nested cause.
56
+ */
12
57
  constructor(code: DirArchiverErrorCode, message: string, options?: {
13
58
  hint?: string | undefined;
14
59
  context?: Record<string, unknown> | undefined;
15
60
  cause?: unknown;
16
61
  });
17
- toJSON(): {
18
- schemaVersion: '1';
19
- name: 'DirArchiverError';
20
- code: DirArchiverErrorCode;
21
- message: string;
22
- hint?: string;
23
- context?: Record<string, unknown>;
24
- };
62
+ /**
63
+ * Serializes the error into the stable JSON shape used by the CLI.
64
+ *
65
+ * The returned object always includes `schemaVersion`, `name`, `code`, and
66
+ * `message`. Optional `hint` and `context` keys are omitted when unset.
67
+ */
68
+ toJSON(): DirArchiverErrorJson;
25
69
  }
package/dist/errors.js CHANGED
@@ -2,6 +2,13 @@
2
2
  * Structured error contract for dir-archiver v3.
3
3
  */
4
4
  export class DirArchiverError extends Error {
5
+ /**
6
+ * Creates a structured error value safe for CLI and API consumers.
7
+ *
8
+ * @param code Stable machine-readable error code.
9
+ * @param message Human-readable summary of the failure.
10
+ * @param options Optional hint, structured context, and nested cause.
11
+ */
5
12
  constructor(code, message, options = {}) {
6
13
  super(message);
7
14
  this.name = 'DirArchiverError';
@@ -12,6 +19,12 @@ export class DirArchiverError extends Error {
12
19
  this.cause = options.cause;
13
20
  }
14
21
  }
22
+ /**
23
+ * Serializes the error into the stable JSON shape used by the CLI.
24
+ *
25
+ * The returned object always includes `schemaVersion`, `name`, `code`, and
26
+ * `message`. Optional `hint` and `context` keys are omitted when unset.
27
+ */
15
28
  toJSON() {
16
29
  return {
17
30
  schemaVersion: '1',
package/dist/index.d.ts CHANGED
@@ -1,19 +1,40 @@
1
1
  /**
2
- * dir-archiver v3 API surface.
2
+ * Deterministic directory archiving and extraction over zip, tar, and layered compression.
3
3
  *
4
- * v3 is a bytefold-backed orchestration layer that supports Node.js, Deno, and Bun.
4
+ * Supports Node.js, Deno, and Bun through one API surface backed by bytefold.
5
5
  */
6
6
  import { audit, detect, extract, list, normalize, open, write } from './core.js';
7
7
  export { audit, detect, extract, list, normalize, open, write };
8
8
  export { DirArchiverError } from './errors.js';
9
- export type { ArchiveFormat, ArchiveLimits, ArchiveProfile, CliUsageError, DetectResult, DirArchiverInput, ExtractOptions, ExtractResult, ListEntry, ListResult, NormalizeOptions, NormalizeResult, OpenOptions, SupportedCommandMap, WriteOptions, WriteResult } from './types.js';
10
- declare const api: {
11
- open: (input: import("./types.js").DirArchiverInput, options?: import("./types.js").OpenOptions) => Promise<import("@ismail-elkorchi/bytefold").ArchiveReader>;
12
- detect: (input: import("./types.js").DirArchiverInput, options?: import("./types.js").OpenOptions) => Promise<import("./types.js").DetectResult>;
13
- list: (input: import("./types.js").DirArchiverInput, options?: import("./types.js").OpenOptions) => Promise<import("./types.js").ListResult>;
14
- audit: (input: import("./types.js").DirArchiverInput, options?: import("./types.js").OpenOptions) => Promise<import("@ismail-elkorchi/bytefold").ArchiveAuditReport>;
15
- normalize: (input: import("./types.js").DirArchiverInput, destination: string, options?: import("./types.js").NormalizeOptions) => Promise<import("./types.js").NormalizeResult>;
16
- extract: (input: import("./types.js").DirArchiverInput, destination: string, options?: import("./types.js").ExtractOptions) => Promise<import("./types.js").ExtractResult>;
17
- write: (source: string, destination: string, options?: import("./types.js").WriteOptions) => Promise<import("./types.js").WriteResult>;
18
- };
9
+ export type { DirArchiverErrorCode, DirArchiverErrorJson } from './errors.js';
10
+ export type { ArchiveFormat, ArchiveLimits, ArchiveDetectionReport, ArchiveIssue, ArchiveNormalizeReport, ArchiveProfile, CliUsageError, DetectResult, DirArchiverInput, ExtractOptions, ExtractResult, ListEntry, ListResult, NormalizeOptions, NormalizeResult, OpenOptions, SupportedCommandMap, WriteOptions, WriteResult } from './types.js';
11
+ /**
12
+ * Namespace-style API contract mirrored by the default export.
13
+ *
14
+ * Consumers who prefer `import dirArchiver from "dir-archiver"` get the same
15
+ * operations and semantics as the named exports on this interface.
16
+ */
17
+ export interface DirArchiverNamespace {
18
+ /** Open an archive reader after resolving format, limits, and runtime support. */
19
+ readonly open: typeof open;
20
+ /** Detect an archive format without extracting entries. */
21
+ readonly detect: typeof detect;
22
+ /** Project archive entries into a stable listing payload. */
23
+ readonly list: typeof list;
24
+ /** Audit an archive against the requested safety profile and limits. */
25
+ readonly audit: typeof audit;
26
+ /** Rewrite an archive into its normalized deterministic representation. */
27
+ readonly normalize: typeof normalize;
28
+ /** Extract an archive to disk with explicit safety and size controls. */
29
+ readonly extract: typeof extract;
30
+ /** Write a directory or file tree into an archive. */
31
+ readonly write: typeof write;
32
+ }
33
+ /**
34
+ * Namespace-style default export for consumers who prefer
35
+ * `import dirArchiver from "dir-archiver"`.
36
+ *
37
+ * It mirrors the named exports exactly and does not add extra behavior.
38
+ */
39
+ declare const api: DirArchiverNamespace;
19
40
  export default api;
package/dist/index.js CHANGED
@@ -1,11 +1,17 @@
1
1
  /**
2
- * dir-archiver v3 API surface.
2
+ * Deterministic directory archiving and extraction over zip, tar, and layered compression.
3
3
  *
4
- * v3 is a bytefold-backed orchestration layer that supports Node.js, Deno, and Bun.
4
+ * Supports Node.js, Deno, and Bun through one API surface backed by bytefold.
5
5
  */
6
6
  import { audit, detect, extract, list, normalize, open, write } from './core.js';
7
7
  export { audit, detect, extract, list, normalize, open, write };
8
8
  export { DirArchiverError } from './errors.js';
9
+ /**
10
+ * Namespace-style default export for consumers who prefer
11
+ * `import dirArchiver from "dir-archiver"`.
12
+ *
13
+ * It mirrors the named exports exactly and does not add extra behavior.
14
+ */
9
15
  const api = {
10
16
  open,
11
17
  detect,
package/dist/types.d.ts CHANGED
@@ -1,7 +1,18 @@
1
- import type { ArchiveDetectionReport, ArchiveFormat, ArchiveIssue, ArchiveLimits, ArchiveNormalizeReport, ArchiveOpenOptions, ArchiveProfile } from '@ismail-elkorchi/bytefold';
2
- export type { ArchiveFormat, ArchiveLimits, ArchiveProfile };
1
+ import type { ArchiveFormat, ArchiveProfile } from '@ismail-elkorchi/bytefold';
2
+ export type { ArchiveFormat, ArchiveProfile, } from '@ismail-elkorchi/bytefold';
3
+ /** Resource limit configuration accepted by `open`, `audit`, and extraction flows. */
4
+ export type ArchiveLimits = Record<string, unknown>;
5
+ /** Issue shape emitted for archive read/normalize/extract failures. */
6
+ export type ArchiveIssue = Record<string, unknown>;
7
+ /** Public detection report shape aligned with runtime diagnostics payloads. */
8
+ export type ArchiveDetectionReport = Record<string, unknown>;
9
+ /** Public normalize report shape for deterministic archive rewrites. */
10
+ export type ArchiveNormalizeReport = Record<string, unknown>;
3
11
  /**
4
12
  * Accepted input shapes for archive read operations.
13
+ *
14
+ * String paths and `URL` objects are the most common inputs, but callers can
15
+ * also supply raw bytes or web streams when the archive is already in memory.
5
16
  */
6
17
  export type DirArchiverInput = string | URL | Uint8Array | ArrayBuffer | ReadableStream<Uint8Array> | Blob;
7
18
  /**
@@ -13,56 +24,67 @@ export interface OpenOptions {
13
24
  /**
14
25
  * Explicit format override when callers already know archive type.
15
26
  */
16
- format?: ArchiveOpenOptions['format'] | undefined;
27
+ format?: ArchiveFormat | 'auto' | undefined;
17
28
  /**
18
29
  * Safety profile (`compat`, `strict`, `agent`) applied during reads/audits.
19
30
  */
20
- profile?: ArchiveOpenOptions['profile'] | undefined;
31
+ profile?: ArchiveProfile | undefined;
21
32
  /**
22
33
  * Extra strictness toggle forwarded to bytefold parsing.
23
34
  */
24
- isStrict?: ArchiveOpenOptions['isStrict'] | undefined;
35
+ isStrict?: boolean | undefined;
25
36
  /**
26
37
  * Parser/resource limits enforced while opening or auditing archives.
27
38
  */
28
- limits?: ArchiveOpenOptions['limits'] | undefined;
39
+ limits?: ArchiveLimits | undefined;
29
40
  /**
30
41
  * Abort signal for cancelling in-flight async operations.
31
42
  */
32
- signal?: ArchiveOpenOptions['signal'] | undefined;
43
+ signal?: AbortSignal | undefined;
33
44
  /**
34
45
  * Password used for encrypted archives when supported by the runtime.
35
46
  */
36
- password?: ArchiveOpenOptions['password'] | undefined;
47
+ password?: string | undefined;
37
48
  /**
38
49
  * Filename hint used for extension-based inference with non-path inputs.
39
50
  */
40
- filename?: ArchiveOpenOptions['filename'] | undefined;
51
+ filename?: string | undefined;
41
52
  }
42
53
  /**
43
54
  * Format detection result.
44
55
  */
45
56
  export interface DetectResult {
57
+ /** Resolved archive format after detection. */
46
58
  format: ArchiveFormat;
59
+ /** Bytefold detection metadata, if the runtime produced it. */
47
60
  detection: ArchiveDetectionReport | undefined;
48
61
  }
49
62
  /**
50
63
  * Single archive entry projection used by list responses.
51
64
  */
52
65
  export interface ListEntry {
66
+ /** Entry format as exposed by the underlying reader. */
53
67
  format: ArchiveFormat;
68
+ /** Entry path inside the archive, normalized to forward slashes. */
54
69
  name: string;
70
+ /** Entry size encoded as a string for JSON-safe transport. */
55
71
  size: string;
72
+ /** Whether the entry materializes as a directory. */
56
73
  isDirectory: boolean;
74
+ /** Whether the entry is a symbolic link. */
57
75
  isSymlink: boolean;
76
+ /** Link target when the entry is a symbolic link. */
58
77
  linkName?: string | undefined;
59
78
  }
60
79
  /**
61
80
  * Archive listing response payload.
62
81
  */
63
82
  export interface ListResult {
83
+ /** Resolved archive format after detection/open completed. */
64
84
  format: ArchiveFormat;
85
+ /** Bytefold detection metadata used to choose `format`, when available. */
65
86
  detection: ArchiveDetectionReport | undefined;
87
+ /** Projected archive entries in archive iteration order. */
66
88
  entries: ListEntry[];
67
89
  }
68
90
  /**
@@ -76,13 +98,16 @@ export type AuditOptions = OpenOptions;
76
98
  * Normalize operation options.
77
99
  */
78
100
  export interface NormalizeOptions extends OpenOptions {
101
+ /** Request deterministic normalization when the runtime supports the knob. */
79
102
  deterministic?: boolean | undefined;
80
103
  }
81
104
  /**
82
105
  * Normalize operation result payload.
83
106
  */
84
107
  export interface NormalizeResult {
108
+ /** Source archive format that was normalized. */
85
109
  format: ArchiveFormat;
110
+ /** Detailed normalization report from bytefold. */
86
111
  report: ArchiveNormalizeReport;
87
112
  }
88
113
  /**
@@ -114,11 +139,17 @@ export interface ExtractOptions extends OpenOptions {
114
139
  * Extraction summary result.
115
140
  */
116
141
  export interface ExtractResult {
142
+ /** Source archive format that was extracted to disk. */
117
143
  format: ArchiveFormat;
144
+ /** Absolute destination directory path used for extraction. */
118
145
  destination: string;
146
+ /** Number of file entries written to disk. */
119
147
  extractedFiles: number;
148
+ /** Number of directory entries created on disk. */
120
149
  extractedDirectories: number;
150
+ /** Number of entries skipped due to policy, such as disallowed symlinks. */
121
151
  skippedEntries: number;
152
+ /** Audit issues collected before or during extraction. */
122
153
  issues: ArchiveIssue[];
123
154
  }
124
155
  /**
@@ -156,17 +187,24 @@ export interface WriteOptions {
156
187
  * Archive writer result payload.
157
188
  */
158
189
  export interface WriteResult {
190
+ /** Archive format emitted to the destination path. */
159
191
  format: ArchiveFormat;
192
+ /** Absolute source path that was archived. */
160
193
  source: string;
194
+ /** Absolute destination archive path that was written. */
161
195
  destination: string;
196
+ /** Number of archive entries written to the output archive. */
162
197
  entryCount: number;
198
+ /** Whether a directory source was wrapped in a tar-based single-file codec. */
163
199
  wrappedDirectoryCodec: boolean;
164
200
  }
165
201
  /**
166
202
  * Usage-error shape emitted by CLI parsing.
167
203
  */
168
204
  export interface CliUsageError {
205
+ /** Human-readable summary of the CLI validation failure. */
169
206
  message: string;
207
+ /** Individual issues returned by the command-line parser. */
170
208
  issues: readonly {
171
209
  code: string;
172
210
  message: string;
@@ -176,11 +214,18 @@ export interface CliUsageError {
176
214
  * Canonical command identifiers supported by the CLI contract.
177
215
  */
178
216
  export interface SupportedCommandMap {
217
+ /** Literal identifier for the `open` command. */
179
218
  open: 'open';
219
+ /** Literal identifier for the `detect` command. */
180
220
  detect: 'detect';
221
+ /** Literal identifier for the `list` command. */
181
222
  list: 'list';
223
+ /** Literal identifier for the `audit` command. */
182
224
  audit: 'audit';
225
+ /** Literal identifier for the `extract` command. */
183
226
  extract: 'extract';
227
+ /** Literal identifier for the `normalize` command. */
184
228
  normalize: 'normalize';
229
+ /** Literal identifier for the `write` command. */
185
230
  write: 'write';
186
231
  }
@@ -0,0 +1,78 @@
1
+ # How-to: use CLI JSON output and exit codes
2
+
3
+ ## Goal
4
+ Drive `dir-archiver` from automation without scraping human-readable command
5
+ output.
6
+
7
+ ## Prereqs
8
+ - Node `>=24`
9
+ - `npm install`
10
+ - `npm run build`
11
+
12
+ ## Copy/paste
13
+ ```sh
14
+ tmpdir="$(mktemp -d)"
15
+ mkdir -p "$tmpdir/src"
16
+ printf 'hello from dir-archiver\n' > "$tmpdir/src/hello.txt"
17
+
18
+ node dist/cli.js write --source "$tmpdir/src" --output "$tmpdir/archive.zip" --json
19
+ node dist/cli.js detect --input "$tmpdir/archive.zip" --json
20
+
21
+ set +e
22
+ node dist/cli.js extract --json
23
+ usage_exit=$?
24
+ set -e
25
+
26
+ printf 'usage_exit=%s\n' "$usage_exit"
27
+ rm -rf "$tmpdir"
28
+ ```
29
+
30
+ ## What you should see
31
+ - `write` emits JSON on stdout with fields shaped like:
32
+
33
+ ```json
34
+ {
35
+ "format": "zip",
36
+ "source": "/tmp/.../src",
37
+ "destination": "/tmp/.../archive.zip",
38
+ "entryCount": 1,
39
+ "wrappedDirectoryCodec": false
40
+ }
41
+ ```
42
+
43
+ - `detect` emits JSON on stdout with `format` plus a `detection` object.
44
+ - The invalid `extract --json` invocation emits a usage payload on stdout shaped
45
+ like:
46
+
47
+ ```json
48
+ {
49
+ "schemaVersion": "1",
50
+ "code": "DIRARCHIVER_USAGE",
51
+ "message": "Invalid CLI arguments.",
52
+ "issues": [
53
+ { "code": "REQUIRED", "message": "extract requires --input." },
54
+ { "code": "REQUIRED", "message": "extract requires --output." }
55
+ ]
56
+ }
57
+ ```
58
+
59
+ - `usage_exit=2` confirms the usage-error exit code.
60
+
61
+ ## Exit codes
62
+
63
+ | Exit code | Meaning | Where to read details |
64
+ | --- | --- | --- |
65
+ | `0` | Command completed successfully. | stdout (`--json`) or normal console output |
66
+ | `1` | Runtime failure or archive-policy failure. | stderr |
67
+ | `2` | CLI usage or validation failure. | stdout with `--json`, stderr otherwise |
68
+
69
+ ## Common failure modes
70
+ - Scripts scrape prose output instead of passing `--json`.
71
+ - Exit codes `1` and `2` are collapsed into one generic failure bucket.
72
+ - stdout and stderr are merged, which corrupts JSON parsing.
73
+ - Commands are run before `npm run build`, so `dist/cli.js` is missing.
74
+
75
+ ## Related reference
76
+ - [CLI reference](../reference/cli.md)
77
+ - [Options reference](../reference/options.md)
78
+ - [Contract](../../CONTRACT.md)
@@ -10,7 +10,13 @@ into a filesystem or resource-exhaustion risk.
10
10
  - `npm run build`
11
11
 
12
12
  ## Copy/paste
13
- Recommended pattern (audit first, then extract with limits):
13
+ Runnable example file:
14
+
15
+ ```sh
16
+ node examples/extract-untrusted.mjs
17
+ ```
18
+
19
+ Equivalent API pattern (audit first, then extract with limits):
14
20
 
15
21
  ```ts
16
22
  import { audit, extract } from "dir-archiver";
@@ -29,29 +35,20 @@ await extract(input, "./out", {
29
35
  });
30
36
  ```
31
37
 
32
- Runnable example file:
33
-
34
- ```sh
35
- node examples/extract-untrusted.mjs
36
- ```
37
-
38
38
  ## What you should see
39
39
  - The audit step succeeds before extraction starts.
40
40
  - The example intentionally sets a low extraction limit and reports
41
41
  `DIRARCHIVER_RESOURCE_LIMIT`.
42
42
 
43
- ## Safety notes
44
- > [!CAUTION]
45
- > Never extract untrusted archives without limits. Attackers can use deeply
46
- > nested or highly compressed entries to trigger large disk writes
47
- > (`CWE-409`-style decompression amplification).
48
- >
49
- > [!CAUTION]
50
- > Keep `profile: "strict"` or `"agent"` for untrusted input. These profiles
51
- > reject traversal-style paths and unsafe entry classes during extraction.
52
- >
53
- > [!WARNING]
54
- > Symlink and hardlink handling changes the risk envelope:
55
- > - `allowSymlinks` defaults to `false`.
56
- > - `allowHardlinks` currently remains unsupported and triggers
57
- > `DIRARCHIVER_UNSUPPORTED_ENTRY`.
43
+ ## Common failure modes
44
+ - `profile: "compat"` is used for hostile input, which weakens pre-extract
45
+ safety checks.
46
+ - Limits are left unset, so decompression amplification can consume far more
47
+ disk than expected.
48
+ - Callers treat file creation as success instead of checking the returned issues
49
+ and skipped-entry counts.
50
+
51
+ ## Related reference
52
+ - [CLI reference](../reference/cli.md)
53
+ - [Options reference](../reference/options.md)
54
+ - [Contract](../../CONTRACT.md)
@@ -1,7 +1,7 @@
1
1
  # How-to index
2
2
 
3
- Task guides:
3
+ Pick the guide that matches the job:
4
4
 
5
- - [Create CI release artifacts](ci-release-artifact.md)
5
+ - [Use CLI JSON output and exit codes](cli-json-and-exit-codes.md)
6
+ - [Troubleshoot common failures](troubleshoot-common-failures.md)
6
7
  - [Extract untrusted archives safely](extract-untrusted.md)
7
- - [Use in CI pipelines](ci-usage.md)
@@ -0,0 +1,78 @@
1
+ # How-to: troubleshoot common failures
2
+
3
+ ## Goal
4
+ Map common `dir-archiver` failures to the likely option or input problem
5
+ without guessing from raw shell output.
6
+
7
+ ## Prereqs
8
+ - Node `>=24`
9
+ - `npm install`
10
+ - `npm run build`
11
+
12
+ ## Copy/paste
13
+ ```sh
14
+ tmpdir="$(mktemp -d)"
15
+ mkdir -p "$tmpdir/src"
16
+ printf 'hello world\n' > "$tmpdir/src/hello.txt"
17
+ node dist/cli.js write --source "$tmpdir/src" --output "$tmpdir/archive.zip" --json >/dev/null
18
+
19
+ set +e
20
+ node dist/cli.js extract \
21
+ --input "$tmpdir/archive.zip" \
22
+ --output "$tmpdir/out" \
23
+ --max-entry-bytes 4 \
24
+ --json
25
+ runtime_exit=$?
26
+
27
+ node dist/cli.js extract --json
28
+ usage_exit=$?
29
+ set -e
30
+
31
+ printf 'runtime_exit=%s\n' "$runtime_exit"
32
+ printf 'usage_exit=%s\n' "$usage_exit"
33
+
34
+ node dist/cli.js detect --input "$tmpdir/archive.zip" --json
35
+ node dist/cli.js list --input "$tmpdir/archive.zip" --json
36
+ rm -rf "$tmpdir"
37
+ ```
38
+
39
+ ## What you should see
40
+ - The first `extract` fails with a `DirArchiverError` JSON payload on stderr
41
+ shaped like:
42
+
43
+ ```json
44
+ {
45
+ "schemaVersion": "1",
46
+ "name": "DirArchiverError",
47
+ "code": "DIRARCHIVER_RESOURCE_LIMIT",
48
+ "message": "..."
49
+ }
50
+ ```
51
+
52
+ - `runtime_exit=1` confirms a runtime/archive-policy failure.
53
+ - The second `extract --json` emits a `DIRARCHIVER_USAGE` payload on stdout and
54
+ `usage_exit=2`.
55
+ - `detect` and `list` still succeed. Use them to inspect the archive before
56
+ trying a different `extract` policy or limit.
57
+
58
+ ## Quick diagnosis table
59
+
60
+ | Symptom | Likely cause | First fix |
61
+ | --- | --- | --- |
62
+ | Exit `2` with `DIRARCHIVER_USAGE` | Missing or invalid command flags | Compare the command to the [CLI reference](../reference/cli.md). |
63
+ | Exit `1` with `DIRARCHIVER_RESOURCE_LIMIT` | `maxEntryBytes` or `maxTotalExtractedBytes` is lower than the archive requires | Raise the limit or audit first to size the archive. |
64
+ | Exit `1` with `DIRARCHIVER_PATH_TRAVERSAL` or `DIRARCHIVER_UNSUPPORTED_ENTRY` | Strict/agent safety checks rejected an entry path or link | Run `audit` or `list` first and keep `compat` only for trusted input. |
65
+ | Raw `ENOENT` or a missing-path stack trace | The input or output path is wrong for the current working directory | Re-run with absolute paths or verify the file exists. |
66
+
67
+ ## Common failure modes
68
+ - Missing input files or missing output directories.
69
+ - Unsupported archive formats or encrypted inputs without the required
70
+ password/support.
71
+ - Strict extraction rejecting traversal-style or link-based entries.
72
+ - Treating an exit code alone as the diagnosis instead of reading the JSON
73
+ error `code`.
74
+
75
+ ## Related reference
76
+ - [CLI reference](../reference/cli.md)
77
+ - [Options reference](../reference/options.md)
78
+ - [Contract](../../CONTRACT.md)
package/docs/index.md CHANGED
@@ -2,22 +2,21 @@
2
2
 
3
3
  Use this map to pick the right doc quickly.
4
4
 
5
- ## Start here
5
+ ## Tutorial
6
6
  - [Tutorial: bundle a plugin directory](tutorial/bundle-a-plugin.md)
7
7
  - [Tutorial: first archive flow](tutorial/first-archive-flow.md)
8
8
 
9
- ## How-to guides
10
- - [How-to index](how-to/index.md)
11
- - [Create CI release artifacts](how-to/ci-release-artifact.md)
9
+ ## How-to
10
+ - [Use CLI JSON output and exit codes](how-to/cli-json-and-exit-codes.md)
11
+ - [Troubleshoot common failures](how-to/troubleshoot-common-failures.md)
12
12
  - [Extract untrusted archives safely](how-to/extract-untrusted.md)
13
- - [Use in CI pipelines](how-to/ci-usage.md)
13
+ - [How-to index](how-to/index.md)
14
14
 
15
15
  ## Reference
16
- - [Contract](../CONTRACT.md)
17
16
  - [CLI reference](reference/cli.md)
18
17
  - [Options reference](reference/options.md)
18
+ - [Contract](reference/contract.md)
19
19
  - [Reference index](reference/index.md)
20
- - [Security policy](../SECURITY.md)
21
20
 
22
21
  ## Explanation
23
22
  - [Explanation index](explanation/index.md)
@@ -0,0 +1,39 @@
1
+ # Maintainer how-to: create a CI release artifact
2
+
3
+ ## Goal
4
+ Produce a release ZIP in CI and emit a machine-readable JSON summary.
5
+
6
+ ## Prereqs
7
+ - Node `>=24`
8
+ - `npm install`
9
+ - `npm run build`
10
+
11
+ ## Copy/paste
12
+ Minimal CI shell snippet:
13
+
14
+ ```sh
15
+ node examples/ci-release-artifact.mjs
16
+ ```
17
+
18
+ Equivalent CLI flow:
19
+
20
+ ```sh
21
+ node dist/cli.js write --source ./dist --output ./release.zip --include-base-directory --json
22
+ node dist/cli.js detect --input ./release.zip --json
23
+ ```
24
+
25
+ ## What you should see
26
+ - JSON output containing `artifact`, `format`, and `entryCount`.
27
+ - `format` is `zip` when the destination extension is `.zip`.
28
+
29
+ ## Common failure modes
30
+ - `--json` is omitted, so CI jobs have to scrape human-readable output.
31
+ - The destination extension does not match the intended format, so inference
32
+ chooses the wrong archive type.
33
+ - `--include-base-directory` is skipped and extracted files do not land under a
34
+ stable root folder.
35
+
36
+ ## Related reference
37
+ - [CLI reference](../reference/cli.md)
38
+ - [Options reference](../reference/options.md)
39
+ - [Contract](../reference/contract.md)
@@ -0,0 +1,41 @@
1
+ # Maintainer how-to: use dir-archiver in CI pipelines
2
+
3
+ ## Goal
4
+ Normalize incoming archives and gate releases with deterministic audit results.
5
+
6
+ ## Prereqs
7
+ - `dir-archiver` available in CI
8
+ - Input archive path from build pipeline
9
+
10
+ ## Copy/paste
11
+ Normalize:
12
+
13
+ ```sh
14
+ node dist/cli.js normalize \
15
+ --input ./incoming.zip \
16
+ --output ./normalized.zip \
17
+ --profile strict \
18
+ --json
19
+ ```
20
+
21
+ Audit gate:
22
+
23
+ ```sh
24
+ node dist/cli.js audit --input ./incoming.zip --profile agent --json
25
+ ```
26
+
27
+ ## What you should see
28
+ - Normalize emits JSON report with deterministic summary fields.
29
+ - Audit exits with code `0` when safe and `1` when operational risk is detected.
30
+
31
+ ## Common failure modes
32
+ - Exit code `2` is treated like an archive-safety failure instead of a CLI
33
+ usage mistake.
34
+ - Pipelines skip `audit` and extract or normalize untrusted input blindly.
35
+ - Jobs do not persist the JSON output, so later stages cannot inspect the exact
36
+ audit or normalize report.
37
+
38
+ ## Related reference
39
+ - [CLI reference](../reference/cli.md)
40
+ - [Options reference](../reference/options.md)
41
+ - [Contract](../reference/contract.md)
@@ -0,0 +1,13 @@
1
+ # Contract
2
+
3
+ Goal: point API and CLI users to the stable behavior contract that backs the public surface.
4
+
5
+ The full contract lives at the repo root so it can ship with npm and JSR artifacts alongside the package entrypoints.
6
+
7
+ Use the root contract for:
8
+ - CLI JSON output shape expectations
9
+ - exit-code meanings
10
+ - stability expectations for named commands and result payloads
11
+
12
+ Primary contract:
13
+ - [CONTRACT.md](../../CONTRACT.md)
@@ -4,4 +4,4 @@ Use this page as the canonical reference entrypoint.
4
4
 
5
5
  - [CLI reference](cli.md)
6
6
  - [Options reference](options.md)
7
- - [Contract](../../CONTRACT.md)
7
+ - [Contract](contract.md)
@@ -10,18 +10,24 @@ development files.
10
10
  - `npm run build`
11
11
 
12
12
  ## Copy/paste
13
- CLI-style command:
14
-
15
13
  ```sh
16
- dir-archiver write \
17
- --includebasedir \
18
- --src . \
19
- --dest ../bundle.zip \
20
- --exclude .git \
14
+ tmpdir="$(mktemp -d)"
15
+ mkdir -p "$tmpdir/plugin/src" "$tmpdir/plugin/node_modules/demo"
16
+ printf 'export const pluginName = \"demo\";\n' > "$tmpdir/plugin/src/index.js"
17
+ printf '{\"name\":\"demo\"}\n' > "$tmpdir/plugin/package.json"
18
+ printf 'ignore me\n' > "$tmpdir/plugin/package-lock.json"
19
+ printf 'ignore me\n' > "$tmpdir/plugin/node_modules/demo/index.js"
20
+
21
+ node dist/cli.js write \
22
+ --source "$tmpdir/plugin" \
23
+ --output "$tmpdir/bundle.zip" \
24
+ --include-base-directory \
21
25
  --exclude node_modules \
22
26
  --exclude package-lock.json \
23
- --exclude package.json \
24
27
  --json
28
+
29
+ node dist/cli.js list --input "$tmpdir/bundle.zip" --json
30
+ rm -rf "$tmpdir"
25
31
  ```
26
32
 
27
33
  Runnable example file:
@@ -32,11 +38,18 @@ node examples/bundle-a-plugin.mjs
32
38
 
33
39
  ## What you should see
34
40
  - A ZIP file is created.
35
- - JSON output reports `format: "zip"`.
36
- - Excluded paths (`.git`, `node_modules`, lock/package manifests) are omitted.
37
-
38
- ## Safety notes
39
- > [!NOTE]
40
- > `--includebasedir` preserves one top-level folder in the archive. This keeps
41
- > extraction deterministic and prevents files from scattering into whichever
42
- > directory the user extracts into.
41
+ - `write` reports `format: "zip"` and a stable `entryCount`.
42
+ - `list` shows entries rooted under the plugin directory and does not include
43
+ `node_modules` or `package-lock.json`.
44
+
45
+ ## Common failure modes
46
+ - The output extension is missing, so format inference falls back to the wrong
47
+ archive type.
48
+ - `includeBaseDirectory` is omitted and extracted files scatter directly into
49
+ the destination root.
50
+ - Exclude patterns miss local build artifacts, which leaks development files
51
+ into the distributable archive.
52
+
53
+ ## Related reference
54
+ - [CLI reference](../reference/cli.md)
55
+ - [Options reference](../reference/options.md)
@@ -9,25 +9,44 @@ Write an archive, detect its format, and extract it with strict safety defaults.
9
9
  - `npm run build`
10
10
 
11
11
  ## Copy/paste
12
- ```ts
13
- import { write, detect, extract } from "dir-archiver";
14
-
15
- await write("./project", "./project.zip", {
16
- format: "zip",
17
- includeBaseDirectory: true,
18
- });
19
-
20
- const detected = await detect("./project.zip");
21
- await extract("./project.zip", "./out", { profile: "strict" });
22
-
23
- console.log(detected.format);
12
+ ```sh
13
+ tmpdir="$(mktemp -d)"
14
+ mkdir -p "$tmpdir/project"
15
+ printf 'hello from tutorial\n' > "$tmpdir/project/hello.txt"
16
+
17
+ node dist/cli.js write \
18
+ --source "$tmpdir/project" \
19
+ --output "$tmpdir/project.zip" \
20
+ --include-base-directory \
21
+ --json
22
+
23
+ node dist/cli.js detect --input "$tmpdir/project.zip" --json
24
+
25
+ node dist/cli.js extract \
26
+ --input "$tmpdir/project.zip" \
27
+ --output "$tmpdir/out" \
28
+ --profile strict \
29
+ --json
30
+
31
+ find "$tmpdir/out" -maxdepth 3 -type f | sort
32
+ rm -rf "$tmpdir"
24
33
  ```
25
34
 
26
35
  ## What you should see
27
- - `detected.format` prints `zip`.
28
- - `./out` contains the extracted files.
29
-
30
- ## Safety notes
31
- > [!NOTE]
32
- > Use `profile: "strict"` for extraction unless you have a documented reason to
33
- > weaken constraints.
36
+ - `write` reports `format: "zip"` and `wrappedDirectoryCodec: false`.
37
+ - `detect` reports `format: "zip"` plus a `detection` object.
38
+ - `extract` reports at least one extracted file and one extracted directory.
39
+ - `find` prints a path ending in `/project/hello.txt`.
40
+
41
+ ## Common failure modes
42
+ - `--include-base-directory` is omitted and the extracted files land directly
43
+ in the destination root.
44
+ - The output archive extension is missing or mismatched, so format inference is
45
+ not what you expected.
46
+ - Extraction is run with `compat` on untrusted input, which weakens path and
47
+ entry checks.
48
+
49
+ ## Related reference
50
+ - [CLI reference](../reference/cli.md)
51
+ - [Options reference](../reference/options.md)
52
+ - [Contract](../../CONTRACT.md)
package/jsr.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ismail-elkorchi/dir-archiver",
3
- "version": "3.0.1",
3
+ "version": "3.0.2",
4
4
  "license": "MIT",
5
5
  "exports": {
6
6
  ".": "./src/index.ts"
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dir-archiver",
3
- "version": "3.0.1",
4
- "description": "Bytefold-backed archive orchestration for directories/files across Node.js, Deno, and Bun.",
3
+ "version": "3.0.2",
4
+ "description": "Deterministic directory archiving and extraction over zip, tar, and layered compression.",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "main": "dist/index.js",
@@ -56,10 +56,15 @@
56
56
  "examples:run": "node ./examples/run-all.mjs",
57
57
  "typecheck": "tsc -p tsconfig.json --noEmit",
58
58
  "lint": "npm run typecheck && eslint . --max-warnings=0",
59
+ "docs:lint:jsr": "deno doc --lint --sloppy-imports src/index.ts",
60
+ "docs:test:jsr": "node ./scripts/jsr-docs-quality.mjs",
61
+ "docs:quality:jsr": "npm run docs:lint:jsr && npm run docs:test:jsr",
62
+ "release:notes:dry-run": "node ./scripts/release-notes.mjs --dry-run",
63
+ "changelog:update:dry-run": "node ./scripts/changelog-update.mjs --dry-run",
59
64
  "test": "npm run build && node --test test/api-snapshot.test.mjs test/operations.test.mjs test/cli.test.mjs test/cli-docs-drift.test.mjs test/matrix-node.test.mjs",
60
- "check:fast": "npm run lint && npm run test && npm run examples:run",
65
+ "check:fast": "npm run lint && npm run docs:quality:jsr && npm run test && npm run examples:run",
61
66
  "test:security": "npm run build && node --test test/security.test.mjs",
62
- "check": "node ./scripts/verify-runtime-versions.mjs && node ./scripts/workflow-policy-check.mjs && node ./scripts/esm-only-guard.mjs && node ./scripts/docs-policy-check.mjs && npm run lint && npm run test && npm run examples:run && npm run test:security && npm run test:runtimes",
67
+ "check": "node ./scripts/verify-runtime-versions.mjs && node ./scripts/workflow-policy-check.mjs && node ./scripts/esm-only-guard.mjs && node ./scripts/docs-policy-check.mjs && npm run lint && npm run docs:quality:jsr && npm run test && npm run examples:run && npm run test:security && npm run test:runtimes",
63
68
  "deps:fresh": "node ./scripts/direct-runtime-deps-freshness.mjs",
64
69
  "test:deno": "npm run build && deno run --allow-read --allow-write --allow-env --allow-sys test/deno-smoke.mjs",
65
70
  "test:bun": "npm run build && bun test/bun-smoke.mjs",
@@ -77,16 +82,16 @@
77
82
  },
78
83
  "dependencies": {
79
84
  "@ismail-elkorchi/bytefold": "^0.8.1",
80
- "argv-flags": "^1.0.4"
85
+ "argv-flags": "^1.0.5"
81
86
  },
82
87
  "devDependencies": {
83
88
  "@eslint/js": "^10.0.1",
84
- "@types/node": "^25.3.2",
85
- "@typescript-eslint/eslint-plugin": "^8.56.1",
86
- "@typescript-eslint/parser": "^8.54.0",
87
- "eslint": "^10.0.2",
88
- "globals": "^17.3.0",
89
- "typescript": "^5.3.3",
90
- "yauzl": "^3.2.0"
89
+ "@types/node": "^25.9.3",
90
+ "@typescript-eslint/eslint-plugin": "^8.61.1",
91
+ "@typescript-eslint/parser": "^8.61.1",
92
+ "eslint": "^10.5.0",
93
+ "globals": "^17.6.0",
94
+ "typescript": "^6.0.3",
95
+ "yauzl": "^3.4.0"
91
96
  }
92
97
  }
@@ -1,32 +0,0 @@
1
- # How-to: create a CI release artifact
2
-
3
- ## Goal
4
- Produce a release ZIP in CI and emit a machine-readable JSON summary.
5
-
6
- ## Prereqs
7
- - Node `>=24`
8
- - `npm install`
9
- - `npm run build`
10
-
11
- ## Copy/paste
12
- Minimal CI shell snippet:
13
-
14
- ```sh
15
- node examples/ci-release-artifact.mjs
16
- ```
17
-
18
- Equivalent CLI flow:
19
-
20
- ```sh
21
- dir-archiver write --source ./dist --output ./release.zip --include-base-directory --json
22
- dir-archiver detect --input ./release.zip --json
23
- ```
24
-
25
- ## What you should see
26
- - JSON output containing `artifact`, `format`, and `entryCount`.
27
- - `format` is `zip` when the destination extension is `.zip`.
28
-
29
- ## Safety notes
30
- > [!NOTE]
31
- > Keep `--json` enabled in CI so build steps can parse deterministic fields
32
- > instead of scraping human-readable text.
@@ -1,34 +0,0 @@
1
- # How-to: use dir-archiver in CI pipelines
2
-
3
- ## Goal
4
- Normalize incoming archives and gate releases with deterministic audit results.
5
-
6
- ## Prereqs
7
- - `dir-archiver` available in CI
8
- - Input archive path from build pipeline
9
-
10
- ## Copy/paste
11
- Normalize:
12
-
13
- ```sh
14
- dir-archiver normalize \
15
- --input ./incoming.zip \
16
- --output ./normalized.zip \
17
- --profile strict \
18
- --json
19
- ```
20
-
21
- Audit gate:
22
-
23
- ```sh
24
- dir-archiver audit --input ./incoming.zip --profile agent --json
25
- ```
26
-
27
- ## What you should see
28
- - Normalize emits JSON report with deterministic summary fields.
29
- - Audit exits with code `0` when safe and `1` when operational risk is detected.
30
-
31
- ## Safety notes
32
- > [!NOTE]
33
- > Exit code `2` indicates CLI usage mistakes (missing/invalid flags), not
34
- > archive safety problems.