WASM Engine
The core binary operations (SHA-1, zlib via libdeflate, packfiles, deltas) run in Zig-compiled WASM modules with SIMD128 acceleration. Two modules serve different use cases:
| Module | npm Entry | Size | Use case |
|---|---|---|---|
Server (gitmode.wasm) | import { WasmEngine } from "gitmode/server" | 865KB | Full git server — all operations including libgit2 |
Client (gitmode-core.wasm) | import { WasmEngineCore } from "gitmode/client" | 83KB | Lightweight client — SHA-1, zlib, delta only (no packfile/libgit2) |
The server module is used internally by createHandler() / RepoStore — you don’t import it directly unless building custom server logic. The client module is standalone and runs anywhere WASM runs (browsers, Node.js, Workers, Deno).
Build Pipeline
Section titled “Build Pipeline”Zig 0.15 (ReleaseSmall) → wasm-metadce (remove unused exports) → wasm-opt -Oz (size optimization) → 865KB server / 83KB coreBuild commands:
pnpm run build:wasm # Server module onlypnpm run build:wasm-core # Core module onlypnpm run build:wasm-all # Both modulesExports
Section titled “Exports”The WASM module exports 29 functions organized by category:
Memory Management
Section titled “Memory Management”| Export | Description |
|---|---|
memory | Linear memory |
alloc | Allocate bytes in WASM heap |
resetHeap | Reset heap (arena allocator) |
getHeapUsed | Get current heap usage |
heapSave | Save heap offset (returns checkpoint) |
heapRestore | Restore heap to checkpoint (frees allocations after it) |
| Export | Description |
|---|---|
sha1_hash | Hash raw bytes |
sha1_hash_object | Hash with git object header (e.g., blob 5\0hello) |
| Export | Description |
|---|---|
zlib_inflate | Decompress zlib data |
zlib_inflate_tracked | Decompress with size tracking |
zlib_deflate | Compress data |
Object Parsing
Section titled “Object Parsing”| Export | Description |
|---|---|
parse_object_header | Parse type size\0 header |
serialize_object | Create object with header |
parse_tree | Parse tree entries |
Packfile Operations
Section titled “Packfile Operations”| Export | Description |
|---|---|
pack_parse_header | Parse PACK header (magic, version, count) |
pack_parse_entry_header | Parse entry type and size |
pack_build | Build a packfile from objects |
Delta Encoding
Section titled “Delta Encoding”| Export | Description |
|---|---|
delta_apply | Apply delta instructions to base object |
delta_create | Create delta between two objects |
Pkt-Line
Section titled “Pkt-Line”| Export | Description |
|---|---|
pktline_encode | Encode data with 4-byte hex length prefix |
pktline_decode | Decode pkt-line framed data |
SIMD Utilities
Section titled “SIMD Utilities”| Export | Description |
|---|---|
simd_memeql | SIMD-accelerated memory comparison |
simd_memchr | SIMD-accelerated byte search |
Checkout
Section titled “Checkout”| Export | Description |
|---|---|
checkout_commit | Materialize a commit’s tree into R2 worktree for browseable file access |
libgit2 Integration
Section titled “libgit2 Integration”| Export | Description |
|---|---|
libgit2_init | Initialize libgit2 |
libgit2_shutdown | Shut down libgit2 |
libgit2_diff | Compute diff between trees |
libgit2_revwalk | Walk commit history |
libgit2_blame | Line-level blame |
Size Optimization
Section titled “Size Optimization”The server WASM binary is 865KB after optimization:
-
wasm-metadce — Dead code elimination based on an export graph. Only 28 exports are kept; all unreachable functions are removed. This reduced function count from ~3000+ to 1272.
-
wasm-opt -Oz — Binaryen’s aggressive size optimizer. Applies code folding, constant propagation, dead argument elimination, and instruction combining.
Both tools require feature flags for the WASM features used:
--enable-simd --enable-bulk-memory --enable-nontrapping-float-to-intZig Source
Section titled “Zig Source”The WASM source lives in wasm/ with two build targets:
zig build wasm— server module (main.zig, includes libgit2)zig build core— core module (main_core.zig, SHA-1/zlib/delta only)
Key build settings:
entry = .disabled— no_startentry point (library mode)rdynamic = true— export all public functions (required in Zig 0.15)stack_size = 4MB— sufficient for deep tree recursion and large packfiles
Zlib via libdeflate
Section titled “Zlib via libdeflate”Zlib operations use vendored libdeflate 1.25 (wasm/vendor/libdeflate/), imported via Zig’s @cImport. This replaced Zig’s std.compress.flate which crashed on certain inputs. libdeflate is purpose-built for in-memory inflate/deflate and consistently faster than general-purpose zlib implementations.
Zero-Copy WASM Memory
Section titled “Zero-Copy WASM Memory”The JS↔WASM boundary avoids unnecessary copies using two techniques:
View bytes (subarray, not slice)
Section titled “View bytes (subarray, not slice)”viewBytes() returns a Uint8Array subarray directly into WebAssembly.Memory — zero copy. The view is valid until the next WASM alloc, reset, or memory grow. Used in packfile building and compute workers where the deflate result is immediately consumed:
// Zero-copy: deflate result stays in WASM memoryconst compressedView = wasm.zlibDeflateView(content);entry.set(compressedView, headerLen); // copies once into final bufferFused pipelines (hashAndDeflate)
Section titled “Fused pipelines (hashAndDeflate)”hashAndDeflate() performs SHA-1 hashing and zlib deflation in a single heap session. Content is written to WASM memory once; the SHA-1 is computed, then the header + content are assembled in WASM memory (using an intra-WASM copy, not a JS roundtrip) and deflated. One resetHeap() instead of two, one content write instead of two.
Heap save/restore
Section titled “Heap save/restore”heapSave() and heapRestore() allow multiple results to coexist in WASM memory without a full resetHeap(). This enables pipeline patterns where intermediate results stay in WASM memory and are consumed by the next operation without copying out to JS.