dir-archiver 3.0.0 → 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 +100 -0
- package/CONTRACT.md +94 -0
- package/CONTRIBUTING.md +33 -0
- package/README.md +35 -59
- package/SECURITY.md +23 -0
- package/SUPPORT.md +16 -0
- package/dist/cli.js +1 -0
- package/dist/core.d.ts +76 -7
- package/dist/core.js +76 -7
- package/dist/errors.d.ts +53 -9
- package/dist/errors.js +13 -0
- package/dist/index.d.ts +33 -12
- package/dist/index.js +8 -2
- package/dist/types.d.ts +120 -10
- package/docs/explanation/index.md +5 -0
- package/docs/explanation/profiles.md +21 -0
- package/docs/how-to/cli-json-and-exit-codes.md +78 -0
- package/docs/how-to/extract-untrusted.md +54 -0
- package/docs/how-to/index.md +7 -0
- package/docs/how-to/troubleshoot-common-failures.md +78 -0
- package/docs/index.md +23 -0
- package/docs/maintainers/ci-release-artifact.md +39 -0
- package/docs/maintainers/ci-usage.md +41 -0
- package/docs/reference/cli.md +277 -0
- package/docs/reference/contract.md +13 -0
- package/docs/reference/index.md +7 -0
- package/docs/reference/options.md +57 -0
- package/docs/tutorial/bundle-a-plugin.md +55 -0
- package/docs/tutorial/first-archive-flow.md +52 -0
- package/jsr.json +10 -5
- package/package.json +30 -14
package/docs/index.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Documentation
|
|
2
|
+
|
|
3
|
+
Use this map to pick the right doc quickly.
|
|
4
|
+
|
|
5
|
+
## Tutorial
|
|
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
|
|
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
|
+
- [Extract untrusted archives safely](how-to/extract-untrusted.md)
|
|
13
|
+
- [How-to index](how-to/index.md)
|
|
14
|
+
|
|
15
|
+
## Reference
|
|
16
|
+
- [CLI reference](reference/cli.md)
|
|
17
|
+
- [Options reference](reference/options.md)
|
|
18
|
+
- [Contract](reference/contract.md)
|
|
19
|
+
- [Reference index](reference/index.md)
|
|
20
|
+
|
|
21
|
+
## Explanation
|
|
22
|
+
- [Explanation index](explanation/index.md)
|
|
23
|
+
- [Profile behavior and tradeoffs](explanation/profiles.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,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,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)
|
|
@@ -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,55 @@
|
|
|
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
|
+
```sh
|
|
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 \
|
|
25
|
+
--exclude node_modules \
|
|
26
|
+
--exclude package-lock.json \
|
|
27
|
+
--json
|
|
28
|
+
|
|
29
|
+
node dist/cli.js list --input "$tmpdir/bundle.zip" --json
|
|
30
|
+
rm -rf "$tmpdir"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Runnable example file:
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
node examples/bundle-a-plugin.mjs
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## What you should see
|
|
40
|
+
- A ZIP file is created.
|
|
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)
|
|
@@ -0,0 +1,52 @@
|
|
|
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
|
+
```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"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## What you should see
|
|
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,21 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ismail-elkorchi/dir-archiver",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.2",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./src/index.ts"
|
|
7
7
|
},
|
|
8
8
|
"imports": {
|
|
9
|
-
"@ismail-elkorchi/bytefold": "jsr:@ismail-elkorchi/bytefold@^0.
|
|
10
|
-
"@ismail-elkorchi/bytefold/node": "jsr:@ismail-elkorchi/bytefold/node@^0.
|
|
11
|
-
"@ismail-elkorchi/bytefold/deno": "jsr:@ismail-elkorchi/bytefold/deno@^0.
|
|
12
|
-
"@ismail-elkorchi/bytefold/bun": "jsr:@ismail-elkorchi/bytefold/bun@^0.
|
|
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
13
|
},
|
|
14
14
|
"publish": {
|
|
15
15
|
"include": [
|
|
16
16
|
"LICENSE",
|
|
17
17
|
"README.md",
|
|
18
18
|
"CHANGELOG.md",
|
|
19
|
+
"CONTRACT.md",
|
|
20
|
+
"SECURITY.md",
|
|
21
|
+
"CONTRIBUTING.md",
|
|
22
|
+
"SUPPORT.md",
|
|
23
|
+
"docs/**",
|
|
19
24
|
"src/**",
|
|
20
25
|
"jsr.json",
|
|
21
26
|
"package.json"
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dir-archiver",
|
|
3
|
-
"version": "3.0.
|
|
4
|
-
"description": "
|
|
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",
|
|
@@ -17,6 +17,13 @@
|
|
|
17
17
|
},
|
|
18
18
|
"files": [
|
|
19
19
|
"LICENSE",
|
|
20
|
+
"README.md",
|
|
21
|
+
"CHANGELOG.md",
|
|
22
|
+
"CONTRACT.md",
|
|
23
|
+
"SECURITY.md",
|
|
24
|
+
"CONTRIBUTING.md",
|
|
25
|
+
"SUPPORT.md",
|
|
26
|
+
"docs",
|
|
20
27
|
"dist",
|
|
21
28
|
"jsr.json"
|
|
22
29
|
],
|
|
@@ -46,16 +53,25 @@
|
|
|
46
53
|
"homepage": "https://github.com/Ismail-elkorchi/dir-archiver",
|
|
47
54
|
"scripts": {
|
|
48
55
|
"build": "tsc -p tsconfig.json",
|
|
56
|
+
"examples:run": "node ./examples/run-all.mjs",
|
|
49
57
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
50
58
|
"lint": "npm run typecheck && eslint . --max-warnings=0",
|
|
51
|
-
"
|
|
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",
|
|
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",
|
|
65
|
+
"check:fast": "npm run lint && npm run docs:quality:jsr && npm run test && npm run examples:run",
|
|
52
66
|
"test:security": "npm run build && node --test test/security.test.mjs",
|
|
53
|
-
"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 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",
|
|
68
|
+
"deps:fresh": "node ./scripts/direct-runtime-deps-freshness.mjs",
|
|
54
69
|
"test:deno": "npm run build && deno run --allow-read --allow-write --allow-env --allow-sys test/deno-smoke.mjs",
|
|
55
70
|
"test:bun": "npm run build && bun test/bun-smoke.mjs",
|
|
56
71
|
"test:runtimes": "npm run test:deno && npm run test:bun && npm run test:runtimes:fingerprints",
|
|
57
72
|
"test:runtimes:fingerprints": "npm run build && node ./scripts/compare-runtime-fingerprints.mjs",
|
|
58
73
|
"jsr:score": "node ./scripts/jsr-score-gate.mjs",
|
|
74
|
+
"release:audit": "node ./scripts/release-audit.mjs",
|
|
59
75
|
"test:downstream:released": "npm run test",
|
|
60
76
|
"test:downstream:main": "npm install --no-save github:Ismail-elkorchi/bytefold#main github:Ismail-elkorchi/argv-flags#main && npm run test",
|
|
61
77
|
"jsr:dry": "deno publish --dry-run --allow-dirty --sloppy-imports",
|
|
@@ -65,17 +81,17 @@
|
|
|
65
81
|
"node": ">=24"
|
|
66
82
|
},
|
|
67
83
|
"dependencies": {
|
|
68
|
-
"@ismail-elkorchi/bytefold": "^0.
|
|
69
|
-
"argv-flags": "^1.0.
|
|
84
|
+
"@ismail-elkorchi/bytefold": "^0.8.1",
|
|
85
|
+
"argv-flags": "^1.0.5"
|
|
70
86
|
},
|
|
71
87
|
"devDependencies": {
|
|
72
|
-
"@eslint/js": "^
|
|
73
|
-
"@types/node": "^
|
|
74
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
75
|
-
"@typescript-eslint/parser": "^8.
|
|
76
|
-
"eslint": "^
|
|
77
|
-
"globals": "^17.
|
|
78
|
-
"typescript": "^
|
|
79
|
-
"yauzl": "^3.
|
|
88
|
+
"@eslint/js": "^10.0.1",
|
|
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"
|
|
80
96
|
}
|
|
81
97
|
}
|