dir-archiver 2.2.0 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +94 -0
- package/CONTRACT.md +94 -0
- package/CONTRIBUTING.md +33 -0
- package/README.md +48 -99
- package/SECURITY.md +23 -0
- package/SUPPORT.md +16 -0
- package/dist/cli-args.d.ts +24 -0
- package/dist/cli-args.js +204 -0
- package/dist/cli.js +132 -46
- package/dist/core.d.ts +33 -0
- package/dist/core.js +549 -0
- package/dist/errors.d.ts +25 -0
- package/dist/errors.js +25 -0
- package/dist/index.d.ts +19 -28
- package/dist/index.js +17 -319
- package/dist/runtime/bun.d.ts +2 -0
- package/dist/runtime/bun.js +17 -0
- package/dist/runtime/deno.d.ts +2 -0
- package/dist/runtime/deno.js +17 -0
- package/dist/runtime/index.d.ts +2 -0
- package/dist/runtime/index.js +33 -0
- package/dist/runtime/node.d.ts +2 -0
- package/dist/runtime/node.js +17 -0
- package/dist/runtime/types.d.ts +11 -0
- package/dist/runtime/types.js +1 -0
- package/dist/types.d.ts +186 -0
- package/dist/types.js +1 -0
- package/docs/explanation/index.md +5 -0
- package/docs/explanation/profiles.md +21 -0
- package/docs/how-to/ci-release-artifact.md +32 -0
- package/docs/how-to/ci-usage.md +34 -0
- package/docs/how-to/extract-untrusted.md +57 -0
- package/docs/how-to/index.md +7 -0
- package/docs/index.md +24 -0
- package/docs/reference/cli.md +277 -0
- package/docs/reference/index.md +7 -0
- package/docs/reference/options.md +57 -0
- package/docs/tutorial/bundle-a-plugin.md +42 -0
- package/docs/tutorial/first-archive-flow.md +33 -0
- package/jsr.json +35 -0
- package/package.json +52 -20
|
@@ -0,0 +1,32 @@
|
|
|
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.
|
|
@@ -0,0 +1,34 @@
|
|
|
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.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# How-to: extract untrusted archives safely
|
|
2
|
+
|
|
3
|
+
## Goal
|
|
4
|
+
Prevent path traversal and decompression amplification from turning extraction
|
|
5
|
+
into a filesystem or resource-exhaustion risk.
|
|
6
|
+
|
|
7
|
+
## Prereqs
|
|
8
|
+
- Node `>=24`
|
|
9
|
+
- `npm install`
|
|
10
|
+
- `npm run build`
|
|
11
|
+
|
|
12
|
+
## Copy/paste
|
|
13
|
+
Recommended pattern (audit first, then extract with limits):
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { audit, extract } from "dir-archiver";
|
|
17
|
+
|
|
18
|
+
const input = "./incoming.zip";
|
|
19
|
+
const report = await audit(input, { profile: "agent" });
|
|
20
|
+
if (!report.ok) {
|
|
21
|
+
console.error(JSON.stringify({ ok: false, issues: report.issues }, null, 2));
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
await extract(input, "./out", {
|
|
26
|
+
profile: "strict",
|
|
27
|
+
maxEntryBytes: 64 * 1024 * 1024,
|
|
28
|
+
maxTotalExtractedBytes: 512 * 1024 * 1024,
|
|
29
|
+
});
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Runnable example file:
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
node examples/extract-untrusted.mjs
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## What you should see
|
|
39
|
+
- The audit step succeeds before extraction starts.
|
|
40
|
+
- The example intentionally sets a low extraction limit and reports
|
|
41
|
+
`DIRARCHIVER_RESOURCE_LIMIT`.
|
|
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`.
|
package/docs/index.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Documentation
|
|
2
|
+
|
|
3
|
+
Use this map to pick the right doc quickly.
|
|
4
|
+
|
|
5
|
+
## Start here
|
|
6
|
+
- [Tutorial: bundle a plugin directory](tutorial/bundle-a-plugin.md)
|
|
7
|
+
- [Tutorial: first archive flow](tutorial/first-archive-flow.md)
|
|
8
|
+
|
|
9
|
+
## How-to guides
|
|
10
|
+
- [How-to index](how-to/index.md)
|
|
11
|
+
- [Create CI release artifacts](how-to/ci-release-artifact.md)
|
|
12
|
+
- [Extract untrusted archives safely](how-to/extract-untrusted.md)
|
|
13
|
+
- [Use in CI pipelines](how-to/ci-usage.md)
|
|
14
|
+
|
|
15
|
+
## Reference
|
|
16
|
+
- [Contract](../CONTRACT.md)
|
|
17
|
+
- [CLI reference](reference/cli.md)
|
|
18
|
+
- [Options reference](reference/options.md)
|
|
19
|
+
- [Reference index](reference/index.md)
|
|
20
|
+
- [Security policy](../SECURITY.md)
|
|
21
|
+
|
|
22
|
+
## Explanation
|
|
23
|
+
- [Explanation index](explanation/index.md)
|
|
24
|
+
- [Profile behavior and tradeoffs](explanation/profiles.md)
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
# CLI reference
|
|
2
|
+
|
|
3
|
+
## Goal
|
|
4
|
+
Provide one canonical reference for `dir-archiver` CLI commands, flags, JSON
|
|
5
|
+
outputs, and exit-code behavior.
|
|
6
|
+
|
|
7
|
+
## Prereqs
|
|
8
|
+
- Build CLI once: `npm run build`
|
|
9
|
+
- Binary path in this repo: `dist/cli.js`
|
|
10
|
+
|
|
11
|
+
## Copy/paste
|
|
12
|
+
Show usage:
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
node dist/cli.js
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Run examples:
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
node examples/run-all.mjs
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## What you should see
|
|
25
|
+
- Exit code `2` with usage diagnostics for invalid invocations.
|
|
26
|
+
- Exit code `0` for successful commands.
|
|
27
|
+
- JSON payloads on stdout when `--json` is set.
|
|
28
|
+
|
|
29
|
+
## Safety notes
|
|
30
|
+
> [!NOTE]
|
|
31
|
+
> For automation, always pass `--json` and consume stable codes/fields instead
|
|
32
|
+
> of parsing human-readable output.
|
|
33
|
+
|
|
34
|
+
## Common flags
|
|
35
|
+
|
|
36
|
+
| Flag | Alias | Default | Notes |
|
|
37
|
+
| --- | --- | --- | --- |
|
|
38
|
+
| `--source` | `--src` | command-specific | Input directory/file for `write`. |
|
|
39
|
+
| `--input` | `-i` | command-specific | Archive path for `open`, `detect`, `list`, `audit`, `extract`, `normalize`. |
|
|
40
|
+
| `--output` | `--dest`, `-o` | command-specific | Destination path for `write`, `extract`, `normalize`. |
|
|
41
|
+
| `--format` | - | inferred/auto | Values: `zip`, `tar`, `tgz`, `tar.gz`, `gz`, `bz2`, `tar.bz2`, `zst`, `tar.zst`, `br`, `tar.br`, `xz`, `tar.xz`. |
|
|
42
|
+
| `--profile` | - | `strict` | Values: `compat`, `strict`, `agent`. |
|
|
43
|
+
| `--json` | - | `false` | Emit machine-readable JSON on stdout. |
|
|
44
|
+
| `--include-base-directory` | `--includebasedir` | `false` | Wrap archive content under the source directory name in `write`. |
|
|
45
|
+
| `--follow-symlinks` | `--followsymlinks` | `false` | Follow symlink targets when archiving source input. |
|
|
46
|
+
| `--exclude` | - | `[]` | Exclude path globs in `write`. Repeatable. |
|
|
47
|
+
| `--allow-symlinks` | - | `false` | Permit symlink extraction targets. |
|
|
48
|
+
| `--allow-hardlinks` | - | `false` | Permit hardlink extraction targets. |
|
|
49
|
+
| `--max-entry-bytes` | - | unset | Maximum bytes per extracted entry. |
|
|
50
|
+
| `--max-total-extracted-bytes` | - | unset | Maximum aggregate extracted bytes per run. |
|
|
51
|
+
|
|
52
|
+
## Commands
|
|
53
|
+
|
|
54
|
+
### `write`
|
|
55
|
+
|
|
56
|
+
Synopsis:
|
|
57
|
+
|
|
58
|
+
```sh
|
|
59
|
+
dir-archiver write --source <path> --src <path> --output <archive> --dest <archive> [--format <format>] [--include-base-directory|--includebasedir] [--follow-symlinks|--followsymlinks] [--exclude <path>...]
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Example:
|
|
63
|
+
|
|
64
|
+
```sh
|
|
65
|
+
dir-archiver write --source ./plugin --output ./bundle.zip --include-base-directory --exclude .git --json
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
JSON output shape:
|
|
69
|
+
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"format": "zip",
|
|
73
|
+
"source": "./plugin",
|
|
74
|
+
"destination": "./bundle.zip",
|
|
75
|
+
"entryCount": 3,
|
|
76
|
+
"wrappedDirectoryCodec": false
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### `open`
|
|
81
|
+
|
|
82
|
+
Synopsis:
|
|
83
|
+
|
|
84
|
+
```sh
|
|
85
|
+
dir-archiver open --input <archive> [--format <format>] [--profile <profile>] [--json]
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Example:
|
|
89
|
+
|
|
90
|
+
```sh
|
|
91
|
+
dir-archiver open --input ./bundle.zip --json
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
JSON output shape:
|
|
95
|
+
|
|
96
|
+
```json
|
|
97
|
+
{
|
|
98
|
+
"format": "zip",
|
|
99
|
+
"detection": {
|
|
100
|
+
"schemaVersion": "1",
|
|
101
|
+
"inputKind": "file",
|
|
102
|
+
"detected": {
|
|
103
|
+
"container": "zip",
|
|
104
|
+
"compression": "none",
|
|
105
|
+
"layers": ["zip"]
|
|
106
|
+
},
|
|
107
|
+
"confidence": "high",
|
|
108
|
+
"notes": ["Format inferred from magic bytes"]
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### `detect`
|
|
114
|
+
|
|
115
|
+
Synopsis:
|
|
116
|
+
|
|
117
|
+
```sh
|
|
118
|
+
dir-archiver detect --input <archive> [--json]
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Example:
|
|
122
|
+
|
|
123
|
+
```sh
|
|
124
|
+
dir-archiver detect --input ./bundle.zip --json
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
JSON output shape:
|
|
128
|
+
|
|
129
|
+
```json
|
|
130
|
+
{
|
|
131
|
+
"format": "zip",
|
|
132
|
+
"detection": {
|
|
133
|
+
"schemaVersion": "1",
|
|
134
|
+
"inputKind": "file",
|
|
135
|
+
"detected": {
|
|
136
|
+
"container": "zip",
|
|
137
|
+
"compression": "none",
|
|
138
|
+
"layers": ["zip"]
|
|
139
|
+
},
|
|
140
|
+
"confidence": "high",
|
|
141
|
+
"notes": ["Format inferred from magic bytes"]
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### `list`
|
|
147
|
+
|
|
148
|
+
Synopsis:
|
|
149
|
+
|
|
150
|
+
```sh
|
|
151
|
+
dir-archiver list --input <archive> [--json]
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Example:
|
|
155
|
+
|
|
156
|
+
```sh
|
|
157
|
+
dir-archiver list --input ./bundle.zip --json
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
JSON output shape:
|
|
161
|
+
|
|
162
|
+
```json
|
|
163
|
+
{
|
|
164
|
+
"format": "zip",
|
|
165
|
+
"detection": { "...": "same shape as detect/open" },
|
|
166
|
+
"entries": [
|
|
167
|
+
{
|
|
168
|
+
"format": "zip",
|
|
169
|
+
"name": "plugin/index.js",
|
|
170
|
+
"size": "42",
|
|
171
|
+
"isDirectory": false,
|
|
172
|
+
"isSymlink": false
|
|
173
|
+
}
|
|
174
|
+
]
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### `audit`
|
|
179
|
+
|
|
180
|
+
Synopsis:
|
|
181
|
+
|
|
182
|
+
```sh
|
|
183
|
+
dir-archiver audit --input <archive> [--profile <profile>] [--json]
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Example:
|
|
187
|
+
|
|
188
|
+
```sh
|
|
189
|
+
dir-archiver audit --input ./bundle.zip --profile agent --json
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
JSON output shape:
|
|
193
|
+
|
|
194
|
+
```json
|
|
195
|
+
{
|
|
196
|
+
"schemaVersion": "1",
|
|
197
|
+
"ok": true,
|
|
198
|
+
"summary": {
|
|
199
|
+
"entries": 3,
|
|
200
|
+
"warnings": 0,
|
|
201
|
+
"errors": 0
|
|
202
|
+
},
|
|
203
|
+
"issues": []
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### `extract`
|
|
208
|
+
|
|
209
|
+
Synopsis:
|
|
210
|
+
|
|
211
|
+
```sh
|
|
212
|
+
dir-archiver extract --input <archive> --output <directory> [--profile <profile>] [--allow-symlinks] [--allow-hardlinks] [--max-entry-bytes <n>] [--max-total-extracted-bytes <n>] [--json]
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Example:
|
|
216
|
+
|
|
217
|
+
```sh
|
|
218
|
+
dir-archiver extract --input ./bundle.zip --output ./out --profile strict --max-total-extracted-bytes 536870912 --json
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
JSON output shape:
|
|
222
|
+
|
|
223
|
+
```json
|
|
224
|
+
{
|
|
225
|
+
"format": "zip",
|
|
226
|
+
"destination": "./out",
|
|
227
|
+
"extractedFiles": 2,
|
|
228
|
+
"extractedDirectories": 1,
|
|
229
|
+
"skippedEntries": 0,
|
|
230
|
+
"issues": []
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### `normalize`
|
|
235
|
+
|
|
236
|
+
Synopsis:
|
|
237
|
+
|
|
238
|
+
```sh
|
|
239
|
+
dir-archiver normalize --input <archive> --output <archive> [--profile <profile>] [--json]
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Example:
|
|
243
|
+
|
|
244
|
+
```sh
|
|
245
|
+
dir-archiver normalize --input ./incoming.zip --output ./normalized.zip --profile strict --json
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
JSON output shape:
|
|
249
|
+
|
|
250
|
+
```json
|
|
251
|
+
{
|
|
252
|
+
"format": "zip",
|
|
253
|
+
"report": {
|
|
254
|
+
"schemaVersion": "1",
|
|
255
|
+
"ok": true,
|
|
256
|
+
"summary": {
|
|
257
|
+
"entries": 10,
|
|
258
|
+
"outputEntries": 10,
|
|
259
|
+
"droppedEntries": 0,
|
|
260
|
+
"renamedEntries": 0,
|
|
261
|
+
"warnings": 0,
|
|
262
|
+
"errors": 0
|
|
263
|
+
},
|
|
264
|
+
"issues": []
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
## Exit codes and stderr/stdout contract
|
|
270
|
+
|
|
271
|
+
- Exit `0`: success.
|
|
272
|
+
- Exit `1`: operational failure (typed `DirArchiverError` JSON on stderr).
|
|
273
|
+
- Exit `2`: usage/validation failure (`DIRARCHIVER_USAGE` with `issues`).
|
|
274
|
+
|
|
275
|
+
For machine consumers:
|
|
276
|
+
- stdout is reserved for success payloads (especially with `--json`).
|
|
277
|
+
- stderr is reserved for diagnostics/failures.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Options reference
|
|
2
|
+
|
|
3
|
+
This page is the single reference for public option fields in `dir-archiver`.
|
|
4
|
+
For CLI commands and flags, see [CLI reference](cli.md).
|
|
5
|
+
|
|
6
|
+
## `OpenOptions`
|
|
7
|
+
|
|
8
|
+
Used by `open`, `detect`, `list`, and `audit`.
|
|
9
|
+
|
|
10
|
+
| Field | Type | Default | Notes |
|
|
11
|
+
| --- | --- | --- | --- |
|
|
12
|
+
| `format` | `ArchiveFormat` | auto-detect | Force a format when detection by bytes/filename is ambiguous. |
|
|
13
|
+
| `profile` | `compat \| strict \| agent` | bytefold default | Safety profile passed to archive readers/audit. |
|
|
14
|
+
| `isStrict` | `boolean` | profile-driven | Explicit strict-mode override. |
|
|
15
|
+
| `limits` | `ArchiveLimits` | none | Resource ceilings for parse/audit operations. |
|
|
16
|
+
| `signal` | `AbortSignal` | none | Cancels long-running operations. |
|
|
17
|
+
| `password` | `string` | none | Password for encrypted archives where supported. |
|
|
18
|
+
| `filename` | `string` | none | Filename hint for extension-based detection. |
|
|
19
|
+
|
|
20
|
+
## `ExtractOptions`
|
|
21
|
+
|
|
22
|
+
`ExtractOptions` extends `OpenOptions`.
|
|
23
|
+
|
|
24
|
+
| Field | Type | Default | Notes |
|
|
25
|
+
| --- | --- | --- | --- |
|
|
26
|
+
| `profile` | `compat \| strict \| agent` | `strict` | `extract` defaults to strict safety posture. |
|
|
27
|
+
| `allowSymlinks` | `boolean` | `false` | When `false`, symlink entries are skipped. |
|
|
28
|
+
| `allowHardlinks` | `boolean` | `false` | Hard-link entries are currently rejected with `DIRARCHIVER_UNSUPPORTED_ENTRY`. |
|
|
29
|
+
| `maxEntryBytes` | `number` | none | Maximum bytes for one extracted file entry. |
|
|
30
|
+
| `maxTotalExtractedBytes` | `number` | none | Maximum cumulative bytes written during extraction. |
|
|
31
|
+
|
|
32
|
+
## `WriteOptions`
|
|
33
|
+
|
|
34
|
+
| Field | Type | Default | Notes |
|
|
35
|
+
| --- | --- | --- | --- |
|
|
36
|
+
| `format` | `ArchiveFormat` | inferred from destination extension, fallback `zip` | Also wraps directory + single-file codec requests (`gz` -> `tar.gz`, etc.). |
|
|
37
|
+
| `includeBaseDirectory` | `boolean` | `false` | Include source directory name as archive root path prefix. |
|
|
38
|
+
| `followSymlinks` | `boolean` | `false` | Follow symlinks while traversing source directories. |
|
|
39
|
+
| `exclude` | `string[]` | `[]` | Exact basename or relative-path matches to skip while traversing the source root (not glob patterns). |
|
|
40
|
+
| `profile` | `ArchiveProfile` | none | Present in API type; currently reserved and not forwarded by `write()`. |
|
|
41
|
+
| `limits` | `ArchiveLimits` | none | Present in API type; currently reserved and not forwarded by `write()`. |
|
|
42
|
+
|
|
43
|
+
## Examples
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
import { extract, write } from "dir-archiver";
|
|
47
|
+
|
|
48
|
+
await extract("./archive.zip", "./out", {
|
|
49
|
+
profile: "strict",
|
|
50
|
+
maxTotalExtractedBytes: 512 * 1024 * 1024,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
await write("./project", "./project.zip", {
|
|
54
|
+
includeBaseDirectory: true,
|
|
55
|
+
exclude: ["tmp", "nested/skip.txt"],
|
|
56
|
+
});
|
|
57
|
+
```
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Tutorial: bundle a plugin directory
|
|
2
|
+
|
|
3
|
+
## Goal
|
|
4
|
+
Create a distributable ZIP that keeps a stable root folder and excludes local
|
|
5
|
+
development files.
|
|
6
|
+
|
|
7
|
+
## Prereqs
|
|
8
|
+
- Node `>=24`
|
|
9
|
+
- `npm install`
|
|
10
|
+
- `npm run build`
|
|
11
|
+
|
|
12
|
+
## Copy/paste
|
|
13
|
+
CLI-style command:
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
dir-archiver write \
|
|
17
|
+
--includebasedir \
|
|
18
|
+
--src . \
|
|
19
|
+
--dest ../bundle.zip \
|
|
20
|
+
--exclude .git \
|
|
21
|
+
--exclude node_modules \
|
|
22
|
+
--exclude package-lock.json \
|
|
23
|
+
--exclude package.json \
|
|
24
|
+
--json
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Runnable example file:
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
node examples/bundle-a-plugin.mjs
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## What you should see
|
|
34
|
+
- 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.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Tutorial: first archive flow
|
|
2
|
+
|
|
3
|
+
## Goal
|
|
4
|
+
Write an archive, detect its format, and extract it with strict safety defaults.
|
|
5
|
+
|
|
6
|
+
## Prereqs
|
|
7
|
+
- Node `>=24`
|
|
8
|
+
- `npm install`
|
|
9
|
+
- `npm run build`
|
|
10
|
+
|
|
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);
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## 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.
|
package/jsr.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ismail-elkorchi/dir-archiver",
|
|
3
|
+
"version": "3.0.1",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"exports": {
|
|
6
|
+
".": "./src/index.ts"
|
|
7
|
+
},
|
|
8
|
+
"imports": {
|
|
9
|
+
"@ismail-elkorchi/bytefold": "jsr:@ismail-elkorchi/bytefold@^0.8.1",
|
|
10
|
+
"@ismail-elkorchi/bytefold/node": "jsr:@ismail-elkorchi/bytefold/node@^0.8.1",
|
|
11
|
+
"@ismail-elkorchi/bytefold/deno": "jsr:@ismail-elkorchi/bytefold/deno@^0.8.1",
|
|
12
|
+
"@ismail-elkorchi/bytefold/bun": "jsr:@ismail-elkorchi/bytefold/bun@^0.8.1"
|
|
13
|
+
},
|
|
14
|
+
"publish": {
|
|
15
|
+
"include": [
|
|
16
|
+
"LICENSE",
|
|
17
|
+
"README.md",
|
|
18
|
+
"CHANGELOG.md",
|
|
19
|
+
"CONTRACT.md",
|
|
20
|
+
"SECURITY.md",
|
|
21
|
+
"CONTRIBUTING.md",
|
|
22
|
+
"SUPPORT.md",
|
|
23
|
+
"docs/**",
|
|
24
|
+
"src/**",
|
|
25
|
+
"jsr.json",
|
|
26
|
+
"package.json"
|
|
27
|
+
],
|
|
28
|
+
"exclude": [
|
|
29
|
+
"dist/**",
|
|
30
|
+
"test/**",
|
|
31
|
+
"node_modules/**",
|
|
32
|
+
".github/**"
|
|
33
|
+
]
|
|
34
|
+
}
|
|
35
|
+
}
|