How to selective zipper in developer workflows
- Step 1Pick the subset you want to ship — Decide the glob: one component (
components/Button/**), one language (src/**/*.ts), one asset type (*.svg), or a build-output subset (dist/**/*.js). One positive pattern per run. - Step 2Drop the working-tree folder — Open /archive-tools/selective-zipper and drop the relevant folder (or the repo root). The directory picker reads every file with its relative path — no
git checkout, no clone, no upload. - Step 3Enter the glob and process — Type the pattern into
globPatternand click Process. ReadMatchedvsTotal consideredto confirm you caught the right files. Remember*stays within a path segment; use**to cross directories. - Step 4Split multi-extension needs into passes — Because there is no brace expansion, ship
.tsand.tsxas two runs (src/**/*.ts, thensrc/**/*.tsx) and combine the ZIPs with archive-merger. - Step 5Make it reproducible — For a build artifact, chain timestamp-normalizer (fixed mtime) then checksum-generator (SHA-256). Same input order → same bytes → same hash, which CI can verify.
- Step 6Diff before/after for review — When a change alters which files ship, build the old and new subsets and run archive-diff over them to get an entry-level diff — equivalent to
diff -ron extracted trees, without extracting.
Developer glob recipes
Patterns for common dev hand-offs and what they capture. The pattern is tested against each file's full relative path; ** crosses directories.
| Goal | globPattern | Notes |
|---|---|---|
| Ship one component | components/Button/** | Whole component dir: code, styles, tests, stories |
| Ship only TypeScript | src/**/*.ts | Excludes .tsx, .css, JS — run a second pass for .tsx |
| Ship all SVG assets | *.svg | Basename fallback catches SVGs at any depth |
| Ship a build-output subset | dist/**/*.js | Only .js under dist/ (no maps unless you add a pass) |
Ship .ts and .tsx | two runs + merge | No brace expansion; merge with archive-merger |
| Ship everything except tests | not supported | No excludes; curate folder or use inverse workflow |
Option contract & execution facts
The real, code-backed contract for the Selective Zipper. Verified against the tool schema, processor, and tier-limits source.
| Fact | Value |
|---|---|
| Options | globPattern (string, default *) — the only control |
| Engine | fflate zipSync, DEFLATE level 6 (fixed) |
| Input | Multiple files / a folder (directory picker, relative paths preserved) |
| Output | filtered.zip (ZIP only — no tar.gz/gz/7z) |
| Generative | Yes — builds a new ZIP from local files (does not read an archive) |
| Glob support | *, **, ? — no braces, no excludes, no [a-z] classes |
| Result metrics | Pattern, Matched, Total considered |
| Execution | Browser-only (fflate); API schema at GET /api/v1/tools/selective-zipper, apiAvailable: false, runner-backed local execution |
| Tier (Free / Pro / Pro-media / Dev) | 50 MB·500 / 500 MB·50k / 2 GB·500k / 2 GB·500k |
Cookbook
Copy-pasteable dev recipes: each shows the glob, the resulting ZIP contents, and where to chain a sibling tool for diffing or reproducibility.
Hand off a single component
Send a reviewer just one component directory — code, styles, tests, stories — without the rest of the repo.
globPattern: components/Button/** filtered.zip: components/Button/Button.tsx components/Button/Button.test.tsx components/Button/Button.module.css components/Button/index.ts Matched=4
Extract one language for a code sample
Pull only the TypeScript out of src/ for a teaching repo or a focused review, leaving CSS and assets behind.
globPattern: src/**/*.ts filtered.zip: src/index.ts src/lib/util.ts src/app/main.ts (src/app/styles.css and src/logo.svg excluded)
Reproducible release subset
Build a deterministic ZIP of the JS bundle for a release, then normalise timestamps and hash it so CI can attest the artifact.
selective-zipper (dist/**/*.js) -> filtered.zip
timestamp-normalizer (mtime = 0) -> stable bytes
checksum-generator -> filtered.zip
SHA-256: a17f...9c
CI compares hash on every build.Diff which files a change ships
A refactor changes which files match src/**/*.ts. Build both subsets and diff them to confirm the intended files moved in/out.
Before branch: selective-zipper src/**/*.ts -> before.zip After branch: selective-zipper src/**/*.ts -> after.zip archive-diff(before.zip, after.zip): + src/app/newModule.ts - src/app/legacy.ts ~ src/index.ts (content changed)
Two-extension bundle via merge
No brace expansion means .ts + .tsx is two runs plus a merge — a small price for a deterministic single positive matcher.
Run 1: globPattern src/**/*.ts -> ts.zip Run 2: globPattern src/**/*.tsx -> tsx.zip archive-merger: ts.zip + tsx.zip -> components.zip
Edge cases and what actually happens
`*.{ts,tsx}` matches nothing
By designBrace expansion is not implemented; {, }, , are literal. The pattern looks for a file literally ending {ts,tsx}. Run src/**/*.ts and src/**/*.tsx separately and merge with archive-merger.
Exclude pattern `!*.test.ts` ignored
By designThere is no negation. To ship code without tests, either drop the tests from the staged folder first, or use the inverse: folder-to-zip then selective-extractor with a keep-pattern.
`src/*.ts` misses nested files
ExpectedA single * compiles to [^/]* and does not cross /. src/*.ts matches only files directly in src/. Use src/**/*.ts to include nested directories.
Pattern fails because of the repo-root folder name
Verify scopeDropping the repo folder makes every path start with the repo name (e.g. myrepo/src/...). src/**/*.ts then matches nothing. Use **/*.ts to ignore the prefix or include the repo name in the pattern.
Timestamps are not the source mtimes
Expectedfflate writes default entry timestamps via this build path. For reproducible artifacts or to preserve a known mtime, chain timestamp-normalizer after the zip.
Output cannot be tar.gz for a Linux pipeline
Not in this toolSelective Zipper writes ZIP only. Convert with zip-to-tar-gz or archive-format-converter if your deploy expects .tar.gz.
Repo near the tier cap
Tier capThe documented free cap is 50 MB / 500 entries — a real repo (especially with node_modules) blows past both, and the work runs in-tab via fflate so browser memory is the practical ceiling. Drop a narrower folder (e.g. just src/) rather than the whole repo, since every dropped file is read into memory even if the glob only matches some, or upgrade to Pro (500 MB / 50,000 entries).
Scripting the tool in CI
Runner-backedGET /api/v1/tools/selective-zipper returns the globPattern schema, but direct server execution is unavailable (apiAvailable: false). Archive tools run browser-only; CI automation pairs the @jadapps/runner, which drives the tool in a local headless browser. For pure shell CI, a native zip/tar step may be simpler.
Frequently asked questions
Can I bundle just one component without zipping the repo?
Yes — that is the core use case. Drop the repo (or component parent) folder and set globPattern to components/Button/**. Only that directory's files go into filtered.zip, with relative paths preserved.
How do I ship .ts and .tsx together?
Two runs: src/**/*.ts, then src/**/*.tsx, then merge with archive-merger. Brace expansion (*.{ts,tsx}) is not supported and matches nothing.
Can I exclude test files?
Not directly — only one positive glob is applied. Curate the folder before zipping, or use the inverse workflow (folder-to-zip then selective-extractor with a keep-pattern).
Is the output reproducible for CI verification?
fflate output is deterministic for a given input order. To make it fully reproducible across machines, chain timestamp-normalizer (fixed mtime) and checksum-generator (SHA-256), then have CI compare the hash.
Why didn't `src/**/*.ts` match anything?
Most likely the dropped folder's name is part of every path (e.g. myrepo/src/...), so the src/ prefix never matches. Use **/*.ts to ignore the prefix, or write myrepo/src/**/*.ts.
Can I set the compression level for a smaller artifact?
Not in this tool — it uses fflate DEFLATE level 6. To compare levels use compression-level-optimizer; for automatic per-file tuning use smart-archive-compressor.
Does it output tar.gz for Linux deploys?
No — ZIP only (filtered.zip). Convert with zip-to-tar-gz or archive-format-converter if your pipeline needs .tar.gz.
How do I see which files a change adds or removes from the bundle?
Build the before and after subsets with the same glob on each branch's folder, then run archive-diff over the two ZIPs. It reports added, removed, and content-changed entries without extracting.
What's the exact option contract?
One option: globPattern (string, default *). No compression-level, password, format, or exclude options exist. Input is multiple files / a folder; output is filtered.zip via fflate at level 6.
Can I call it from a script or CI job?
GET /api/v1/tools/selective-zipper returns the schema for discovery. Direct server execution is not available (apiAvailable: false); archive tools run browser-only, so execution goes through the paired @jadapps/runner driving a local headless browser. Files never leave your machine.
Does it handle a full repo with node_modules?
It is bounded by the tier caps (Free 50 MB / 500 entries) and, in practice, by browser memory — a repo with node_modules will overwhelm both. Drop a narrower folder (e.g. just src/) rather than the whole repo: every dropped file is read into memory even though the glob only puts matches into the ZIP. The glob decides what is added to the output, not what gets read off disk.
Are paths inside the ZIP relative to my dropped folder?
Yes — the directory picker captures each file's relative path, which becomes its ZIP path. Drop the repo root and entries start at the repo-name root, so extracting reproduces your layout exactly.
Privacy first
Every JAD Archive tool runs entirely in your browser using fflate, @zip.js/zip.js, and the libarchive WASM bridge. Your archives never leave your device — verified by zero outbound network requests during processing.