Canonical guide for AI coding agents working in this repository (AGENTS.md open standard — complements the human-facing README.md).
| File | Audience | Role |
|---|---|---|
| README.md | Humans / npm consumers | Install, quick start, API reference |
| AGENTS.md (this file) | Agents (+ contributor ops) | Hard rules, architecture, test/debug commands |
| CLAUDE.md | Claude Code | Thin pointer to this file — do not fork rules there |
Shared facts (version matrix, peer floors, iOS 15.5, Zip Slip / ERR_UNSAFE_PATH, public API names) must agree between README.md and this file. Prefer one canonical sentence + a cross-link over two diverging copies.
When you change doc-impacting code (index.js, index.d.ts, specs/, android/src/, ios/RNZipArchive.*, package.json, app.plugin.js):
- Update both
README.mdandAGENTS.mdin the same change when user-facing or agent-facing guidance shifts. - Run
npm run test:docs-sync(same check as CI and optional pre-commit). - Rare internal-only change with no doc impact: commit message may include
[docs-sync skip].
Enforcement is portable (not editor-specific): scripts/check-docs-sync.sh → GitHub Actions docs-sync.yml + optional .pre-commit-config.yaml.
react-native-zip-archive — a React Native TurboModule that zips and unzips files on iOS and Android. Public npm package; JS API is stable across v7 → v9 (native rebuild required when upgrading).
| Layer | Role |
|---|---|
index.js / index.d.ts |
Public JS API + TypeScript types |
specs/NativeZipArchive.ts |
Codegen TurboModule spec (source of truth for native method names) |
android/src/... |
Android implementation (zip4j) |
ios/RNZipArchive.mm |
iOS implementation (SSZipArchive / minizip) |
app.plugin.js |
Expo config plugin (passthrough; enables plugins entry) |
playground-expo/ / playground-rn/ |
Demo apps (file:.. link to this package) |
__tests__/ |
Jest tests (native module mocked) |
scripts/ |
Interop validators, E2E helpers |
.maestro/ |
Maestro E2E flows |
| React Native | Package |
|---|---|
| < 0.70 | Stay on v7 (^7.0.0) |
| 0.70–0.81 | v9 — New Arch recommended; old arch works after native rebuild |
| 0.82+ | v9 — New Arch only (RN ignores opt-out flags) |
- Current package version: see
package.json. - User-facing docs:
README.md. Upgrade notes:MIGRATION.md. Security:SECURITY.md. - Review checklist:
REVIEW.md.
- Spec parity. Any change to
specs/NativeZipArchive.tsmust be reflected in Android, iOS,index.js, andindex.d.ts. Do not ship one-sided API changes. - Zip Slip. Unzip must reject entry paths that escape the destination (
ERR_UNSAFE_PATH). Touching path normalization or extract on either platform requires security scrutiny. Symlink entries must be skipped, not materialized. - Stable error codes. Reject with the
ERR_*codes inErrorCodes(index.js). Keep codes aligned on both platforms. - No new heavy deps. Peer range is React ≥ 18 and RN ≥ 0.70. Do not add native or JS dependencies lightly.
ZipErroris a factory, not an ESclass(Metro /@babel/runtime). Never introduceinstanceof ZipErrorchecks in docs or examples.- Do not edit generated / lock noise unless the task requires it:
node_modules/, build outputs, playground lock churn without a real dep change.
TurboModuleRegistry.get('RNZipArchive') → NativeModules.RNZipArchive
If neither is present, throw ERR_UNSUPPORTED with a clear install/link message.
Options objects ({ signal }, { entries }, { compressionLevel }) are JS-side conveniences; natives use the codegen positional methods. Keep overloads in index.d.ts in sync with index.js.
- Threading: Android zip/unzip on a single-thread executor (FIFO). iOS on a background serial queue. Never block the UI/main thread with archive I/O.
cancel()must not wait behind the operation it should abort. - Encryption default:
'STANDARD'= ZipCrypto (interop with Node/Java/unzip). AES = WinZip-AES; many server tools cannot open AES zips — default to STANDARD for off-device consumers. - Charset: Android may honor non-UTF-8; iOS must reject non-UTF-8 with
ERR_UNSUPPORTED(except where docs say charset is ignored, e.g.getUncompressedSizeon iOS). - Progress: Emit monotonic 0→1 with explicit start/end. Shape:
{ progress, filePath }. Treat cross-platform divergence as a bug.
Run from repo root:
npm test # Jest — preferred fast check for JS/API changes
npm run test:interop # Node unzipper + Java ZipInputStream on fixtures/
npm run test:docs-sync # README ↔ AGENTS.md (same as CI / pre-commit)
npm run lint # ESLint on index.jsWhen changing the public API:
- Update
__mocks__/react-native.jsif the native surface changes. - Extend
__tests__/api.test.js(and related) for new overloads / error paths. - Prefer
npm testbefore claiming done; add interop checks if zip format/encryption defaults change.
E2E (device/simulator, heavy):
npm run test:e2e:expo # Maestro vs playground-expo
npm run test:e2e:rn # Maestro vs playground-rnSee e2e/README.md. Skip E2E unless the change is native behavior that Jest cannot cover.
Old-architecture compile proof (CI): .github/workflows/old-arch.yml on RN 0.81.6. Not device Maestro.
| Directory | Purpose |
|---|---|
playground-expo/ |
Expo SDK 55 / New Arch — config plugin + expo-file-system usage |
playground-rn/ |
Bare RN 0.83.9 / New Arch |
Both depend on "react-native-zip-archive": "file:..". After changing native code, rebuild the playground (Metro reload alone is not enough).
Treat playground edits as optional unless the task is demo/E2E related. Prefer keeping playgrounds compiling when you change the public API.
| File | Audience |
|---|---|
README.md |
Humans — install, quick start, API |
AGENTS.md |
Agents — this file (canonical) |
CLAUDE.md |
Claude Code — pointer to AGENTS.md |
MIGRATION.md |
Version upgrades (v7→v9, minor notes) |
SECURITY.md |
Supported versions, vuln reporting, Zip Slip scope |
REVIEW.md |
PR review focus (parity, security, threading) |
CHANGELOG.md |
Release history |
Keep README examples accurate to index.d.ts. Prefer linking here or to MIGRATION.md for deep architecture detail instead of duplicating long matrices in the README. See Keep in sync.
| Workflow | What it covers |
|---|---|
docs-sync.yml |
README ↔ AGENTS.md fact + change pairing (always) |
js-tests.yml |
Jest + lint when js paths change |
android-build.yml / ios-build.yml |
Native builds — only when native paths change |
e2e.yml |
Maestro E2E — only when native paths change |
old-arch.yml |
RN 0.81.6 paper/old-arch compile — native paths |
zip-interop.yml |
Fixture unzip interop — interop paths |
publish.yml |
npm publish (tags) |
minor-discussion.yml |
Announcement Discussion for minors |
Path filters live in .github/path-filters.yml (see .github/workflows/path-filters.md). Docs-only PRs must not burn macOS/Android build minutes: heavy jobs are gated behind a cheap changes job so concurrency: cancel-in-progress can still stop outdated runs. Force a full build with Actions → Run workflow.
- Spec (
specs/NativeZipArchive.ts) if native signature changes. - Android + iOS implementations.
index.jswrappers (options / AbortSignal / validation).index.d.tsoverloads.- Jest mocks + tests.
- README API section (short example) and this file if hard rules/commands change.
npm run test:docs-syncMIGRATION.mdif behavior/default changes for existing callers.
- Prefer STANDARD for defaults that leave the device.
- Update
fixtures/interop/andnpm run test:interopexpectations. - Document in
MIGRATION.mdif defaults flip.
- Mirror Android and iOS validation.
- Reject traversal with
ERR_UNSAFE_PATH. - Skip symlinks on extract.
- Note supported-version impact in
SECURITY.mdif shipping a fix.
- Stay on or recommend v7 for RN ≥ 0.70 (except RN < 0.70).
- Claim Expo Go support.
- Force-push
masteror rewrite published release tags. - Add purple “AI slop” marketing to docs; keep README factual and scannable.
- Estimate calendar time in planning — describe technical scope instead.
- Read
package.jsonversion and peer deps. - Skim
specs/NativeZipArchive.ts+index.d.tsfor the real API. - For native bugs: find the path in
ios/RNZipArchive.mmandandroid/src/main/java/com/rnziparchive/. - Run
npm testafter JS changes;npm run test:interopafter format/crypto changes. - Update docs for the surfaces you changed; keep README + AGENTS.md paired (
npm run test:docs-sync).