Development¶
Setup¶
git clone https://github.com/mbe24/zaungast && cd zaungast
npm install
Requires Node.js ≥ 22.5.
Scripts¶
| Script | Description |
|---|---|
npm run build |
Compile TypeScript to dist/ and copy schema mappings. |
npm run typecheck |
tsc --noEmit over src/. |
npm run typecheck:test |
Type-check test/ (via test/tsconfig.json; run in CI). |
npm run format |
Format src/ + test/ with Prettier. |
npm run format:check |
Verify formatting (run in CI). |
npm test |
Data-free unit tests (test/unit.ts) — run in CI. |
npm run test:fixture |
Generate a synthetic leveldb cache and drive the full read → ingest → tools pipeline against it — no real data; run in CI. |
npm run test:integration:ci |
Run the mutation/equivalence harnesses against a synthetic .ldb+.log fixture — no real data; run in CI. |
npm run test:integration |
Same harnesses against a real local Teams cache (see below). |
npm run dev |
Run the server from source via tsx (no build step). |
npm run assets |
Re-render the SVG brand assets in assets/ and .github/ to PNG. |
Code style¶
Formatting is enforced by Prettier (.prettierrc: semicolons, single quotes, 100 columns);
npm run format:check runs in CI. Run npm run format before committing.
There is no ESLint yet: typescript-eslint does not support TypeScript 7 (its parser targets
typescript < 6.1), so it can't run on this codebase. It'll be added once upstream supports
TS 7; the intended ruleset is typescript-eslint recommended + no-unused-vars (ignoring _)
+ no-console scoped to src/ (stdout is the MCP transport).
Tests¶
- Unit (
npm test) exercise the pure layers — Snappy, structured-clone decode, CRC32C, key coding, HTML→text, handles, topic extraction — with synthetic inputs and no Teams data. These run in CI. - Synthetic fixture (
test/fixture/) — a group of CS students chatting, entirely fake and PII-free. It's the reader's inverse:test/fixture/encode.ts+sstable-encode.tswrite the same byte formatssrc/format/chromium/*reads (.logWAL,.ldbSSTable, IndexedDB key coding, V8 structured-clone), deterministically. Two CI tests run against it, needing no real cache: npm run test:fixturegenerates a WAL-only cache and drives the full read → ingest → tools pipeline, asserting the decoded content matches what was generated.npm run test:integration:cigenerates a mixed.ldb+.logcache and runs the mutation/equivalence harnesses (_inctest,_reusetest,_fbtest) against it — including.ldbtruncation and forced compaction.- Real-cache integration (
npm run test:integration) runs the same_inctest/_reusetest/_fbtestharnesses against a real on-disk Teams cache — a belt-and-braces check that catches real-world format quirks the synthetic fixture doesn't model. It runs locally (shipping a real cache would leak PII): point it at a copy of your leveldb dir viaZAUNGAST_TEST_DIR(or pass the dir asargv[2]to a harness directly).
The integration suite's backbone is an equivalence invariant: an incrementally-refreshed
store must be byte-identical to a full rebuild of the same on-disk state — which keeps the
fast copy-reuse path provably correct.
Architecture¶
src/format/— the stable, dependency-free reader.src/format/index.tsis the public barrel every caller imports; it's the single seam. Underneath:src/format/chromium/— the Windows Chromium-IndexedDB-on-LevelDB byte format (SSTable, write-ahead log, Snappy, IndexedDB key coding, V8 structured clone). Engine-specific — a second platform (e.g. macOS WebKit-on-SQLite) would be a sibling directory yielding the same record contract, not a rewrite.src/format/fingerprint.ts,resolver.ts,discover.ts— the engine-agnostic schema layer (version fingerprint, field mapping) and the on-disk locator. Unchanged across Teams updates.src/format/types.ts— the shared record/result contracts.src/schema/versions/— per-fingerprint field mappings (the volatile part).src/ingest/—store.ts(SQLite schema + derived recompute) andingest.ts(decode → rows, full + incremental).src/session.ts— snapshot + refresh lifecycle (copy-reuse / reparse).src/tools.ts,src/schemas.ts,src/server.ts— the MCP tools and their argument schemas.src/index.tsis the bootstrap;src/main.tsis the actual server entry.
See How it works for the read path in detail, and the Chromium IndexedDB format reference for the byte-level spec each layer implements.
Releasing¶
CI (.github/workflows/ci.yml) runs typecheck + build + unit tests on every push/PR to
master. To publish: bump version in package.json, tag vX.Y.Z, and push the tag — the
release workflow verifies the tag matches the version and that CI is green for the commit,
then publishes to npm with provenance.