How to prefix remover in developer workflows
- Step 1Flatten a release ZIP during review — When a PR or issue ships a release archive, drop it into the Path Prefix Remover to strip the
repo-x.y.z/wrapper without cloning the branch — quicker than rebuilding locally. - Step 2Leave prefix empty for the common case — GitHub source ZIPs have one top folder, so auto-detect (empty prefix box) handles them with zero configuration. Click Process and download.
- Step 3Type a prefix for monorepo bundles — If an artifact wraps several packages, type the exact path you want at root — for example
packages/foo/— so only that subtree is flattened and the rest is preserved. - Step 4Compare before/after with Archive Diff — For PRs that change archive contents, run the archive diff over the two archives to see exactly which entries changed — like
diff -ron extracted trees. - Step 5Normalize timestamps for reproducibility — Because the re-zip uses rebuild times, follow with the timestamp normalizer set to a fixed date (1980-01-01 is the ZIP-epoch convention) for byte-stable output.
- Step 6Emit a checksum manifest — Run the checksum generator on the flattened, normalized ZIP to produce a SHA-256 manifest your CI can verify against future builds.
Tool behaviour vs the fflate equivalent
The tool wraps a small fflate script. This is the equivalent Node logic for each behaviour.
| Behaviour | In the tool | fflate / Node equivalent |
|---|---|---|
| Read the archive | Drop file; format detected by magic bytes | const files = unzipSync(buf) (or libarchive for 7z/rar) |
| Auto-detect prefix | Empty Prefix box; single top folder | Collect name.split('/')[0]; if exactly one, use it + / |
| Strip the prefix | Process | name.startsWith(p) ? name.slice(p.length) : name |
| Drop empty wrapper entry | Automatic | Skip keys that become empty after the slice |
| Write output | Download ZIP | zipSync(stripped, { level: 6 }) |
| Output format | Always ZIP | Always ZIP (not the input format) |
Batch and tier reality for dev use
This tool is single-file. These are the relevant tier limits and the sibling tools for multi-archive work.
| Need | This tool | Where to go instead |
|---|---|---|
| One release ZIP | Free, 50 MB / 500 entries | n/a — use it directly |
| A 400 MB build artifact | Pro, 500 MB / 50,000 entries | Pro tier |
| Many archives at once | Not supported (1 file/job) | batch extraction manager |
| Compare two artifacts | Not this tool | archive diff |
| Deterministic timestamps | Re-zip uses rebuild time | timestamp normalizer |
Cookbook
Developer-shaped recipes with the path transformations and the Node equivalent so you can reproduce or script the behaviour.
Flatten a GitHub source ZIP
The canonical case. GitHub always wraps source downloads in repo-tag/. Auto-detect strips it.
Input: acme-cli-1.2.3.zip (Prefix to strip = empty) Before After acme-cli-1.2.3/Cargo.toml -> Cargo.toml acme-cli-1.2.3/src/main.rs -> src/main.rs Result panel: Prefix stripped: acme-cli-1.2.3/ Entries renamed: 2
The equivalent Node script
What the tool does, in fflate. Useful when you eventually need it in a local script.
import { unzipSync, zipSync } from 'fflate';
const files = unzipSync(buf);
const tops = new Set(Object.keys(files).map(n => n.split('/')[0]).filter(Boolean));
const prefix = tops.size === 1 ? [...tops][0] + '/' : null;
if (!prefix) throw new Error('No common top-level prefix detected');
const out = {};
for (const [n, d] of Object.entries(files)) {
const next = n.startsWith(prefix) ? n.slice(prefix.length) : n;
if (next) out[next] = d;
}
const zip = zipSync(out, { level: 6 });Monorepo bundle — flatten one package
An artifact wraps several packages. Type the exact prefix to bring only one to root.
Input: bundle.zip (Prefix to strip = packages/foo/) Before After packages/foo/dist/index.js -> dist/index.js packages/foo/package.json -> package.json packages/bar/dist/index.js -> packages/bar/dist/index.js (kept)
Reproducible artifact pipeline
Flatten, then normalize timestamps, then hash — three single-purpose tools producing a byte-stable, attestable ZIP.
1) path-prefix-remover (auto) -> repo-1.2.3-flattened.zip 2) timestamp-normalizer (1980-01-01) -> deterministic.zip 3) checksum-generator (SHA-256) -> deterministic.zip.sha256 # same input + same steps -> identical bytes across machines
TAR.GZ artifact becomes a ZIP
Heads-up for build scripts: the output format is ZIP, not the input format. Convert back if a later step needs TAR.GZ.
Input: dist-2.0.tar.gz (auto) Download: dist-2.0-flattened.zip (ZIP, not tar.gz) If you need tar.gz again: archive-format-converter: ZIP -> TAR.GZ
Edge cases and what actually happens
Output is ZIP even for a TAR.GZ input
By designThe tool always re-packs with fflate's ZIP writer. A build step expecting the original format must convert with the archive format converter after flattening.
Re-zip uses rebuild timestamps
Not reproducible aloneTwo runs produce ZIPs with different embedded timestamps. For byte-stable output, chain the timestamp normalizer with a fixed date.
Multiple top folders, empty prefix
Stopped — no prefix detectedAuto-detect only works with a single top segment. A monorepo bundle with several top folders needs an explicit prefix, or it throws "No common top-level prefix detected".
Need to flatten many archives in CI
Not supported (single file)There is no API yet and the tool is one-file-per-job. Script the fflate equivalent in your build, or use the batch extraction manager for multi-archive extraction.
Artifact over the tier cap
Rejected (tier limit)Free is 50 MB; Pro 500 MB; Pro-Media and Developer 2 GB. A large build artifact needs a higher tier or a local fflate script.
Compression level is fixed at 6
By designThe re-zip uses fflate level 6; there is no level control on this tool. For a specific ratio, use the compression level optimizer on the output.
Prefix matches no entries
Preserved (zero renamed)If your typed prefix does not match any path, the output is the same tree re-zipped with "Entries renamed: 0". Check the trailing slash and exact casing.
Encrypted ZIP artifact
Supported (output unencrypted)Encrypted entries are read via zip.js and the output is unencrypted. Re-encrypt downstream with the encrypted ZIP creator if the artifact must stay protected.
7z artifact from a non-JS build
Supported (read-only)libarchive reads 7z so you can flatten it in-browser, but the tool cannot write 7z — the result is a ZIP.
Entry-dense node_modules bundle
Rejected (entry limit)A bundled node_modules can blow past the entry cap (500 Free, 50,000 Pro). Use a higher tier or exclude paths first with the selective extractor.
Frequently asked questions
Is there a CLI or API?
Not yet — every tool is a browser page. The closest equivalent is a tiny fflate script: unzip, slice the leading path segment off each key, re-zip at level 6. The tool wraps exactly that logic.
How do I make the output reproducible?
The re-zip uses rebuild timestamps, so flatten first, then run the timestamp normalizer with a fixed date (1980-01-01 is the ZIP-epoch convention). Verify with a SHA-256 manifest from the checksum generator.
What output format do I get?
Always ZIP, named <name>-flattened.zip. A TAR.GZ or 7z input is read and re-packed as ZIP — convert back with the archive format converter if needed.
Can I script bulk flatten runs?
Not through this tool — it is one file per job. Script the fflate equivalent in Node, or for multi-archive extraction use the batch extraction manager.
Can I control the compression level?
No — the re-zip is fixed at fflate level 6. If a specific ratio matters, run the compression level optimizer on the flattened output.
How does auto-detect handle a monorepo bundle?
It declines when there is more than one top folder. Type the exact prefix (e.g. packages/foo/) to bring that one subtree to root and keep the rest.
Does it preserve the inner directory tree?
Yes. Only the matching prefix is removed; subdirectories below it are kept. It does not flatten everything into one folder the way unzip -j does.
Is the prefix override a paid feature?
No. The Prefix to strip input works on every tier including Free. Only size and entry limits change between tiers.
What are the size and entry limits?
Free 50 MB / 500 entries, Pro 500 MB / 50,000, Pro-Media and Developer 2 GB / 500,000. The entry cap is separate from byte size and can bite on dependency bundles.
Can I diff the flattened result against my source?
Yes — run the archive diff over the flattened ZIP and a reference archive to see exactly which entries differ, like diff -r on extracted trees.
Does it add any JAD-specific metadata?
No. The output is a plain ZIP with no proprietary headers — structurally identical to one produced by any standard ZIP writer.
What if the artifact is a nested archive?
This tool reads one archive level. For archives inside archives, run the nested archive extractor first, then flatten the result.
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.