FileWorker Entry (
Repository DO (
Caching Layer (
Blob: docs/architecture.md
Architecture Overview
This project implements a Git Smart HTTP v2 server on Cloudflare Workers using a hybrid of Durable Objects (DO) and R2.
Module Structure
The codebase is organized into focused modules with index.ts export files:
/git- Core Git functionalityoperations/- Git operations (upload-pack, receive-pack)core/- Protocol handling, pkt-line, readerspack/- Pack assembly, indexing
/do- Durable Objectsrepo/repoDO.ts- Repository Durable Object (per-repo authority)
/auth- Authentication module- Tessera OIDC, sealed browser sessions, and Git PAT verification
/cache- Two-tier caching system- UI layer caching (JSON responses)
- Git object caching (immutable objects)
/web- Web UI utilitiesformat.ts- Content formatting helpersrender.ts- Page renderingtemplates.ts- React view compatibility shim
/ui- React SSR UI layerserver/- Document shell, manifest resolution, render registrypages/- Route-level React page componentscomponents/- Shared server-rendered UI building blocksislands/- Small client-side interactive modulesclient/entry.tsx- Browser entry for CSS and islands
/common- Shared utilitiescompression.ts,hex.ts,logger.ts,response.ts,stub.ts,progress.ts
/routes- HTTP route handlersgit.ts- Git protocol endpoints (upload-pack, receive-pack)ui.ts- Web UI routes for browsing reposauth.ts- Authentication UI and API endpointsadmin.ts- Repository admin routes
Core Components
Worker Entry (src/index.ts)
- Routes for Git endpoints, admin JSON, and the web UI
- Integrates all route handlers via AutoRouter
Repository DO (src/do/repo/repoDO.ts)
- Metadata authority for a single repo. The data plane lives in R2 packs.
- Typed RPC methods (selected):
listRefs(),setRefs(),getHead(),setHead(),getHeadAndRefs()beginReceive(),finalizeReceive(),abortReceive()— receive lease lifecyclebeginCompaction(),commitCompaction()— queue-driven pack compactiongetActivePackCatalog()— pack catalog snapshot for worker-local reads
- Push: the Worker writes
.packand.idxto R2, then commits refs and pack-catalog metadata atomically through typed DO RPCs. One active receive lease at a time; concurrent pushes receive503 Retry-After: 10. - Pack metadata lives in
pack_catalog(SQLite). Exact pack membership lives in.idxfiles in R2.
Ownership And Auth
- D1 stores users, namespaces, memberships, repositories, PATs, and grants.
- Tessera OIDC signs users into sealed local browser sessions.
- Git push uses HTTP Basic where the username matches the namespace slug and the password is a PAT with push access.
Caching Layer (src/cache/)
- UI Cache: 60s for HEAD/refs, 5min for README, 1hr for tag commits
- Object Cache: Immutable Git objects cached for 1 year
- Pack discovery and memoization:
src/git/object-store/catalog.ts#loadActivePackCatalog()loads the active pack catalog through the Repo DO once per request and memoizes the snapshot inRequestMemo. - Per-request limiter and soft budget: All DO/R2 calls in read and upload paths use a concurrency limiter and a soft subrequest budget to avoid hitting platform limits.
Durable Objects SQLite (drizzle-orm)
- The Repository DO maintains a small SQLite database using
drizzle-orm/durable-sqlitefor metadata that benefits from indexed lookups and batch queries. - Migrations run during DO initialization via
migrate(db, migrations)and Wranglernew_sqlite_classes(seewrangler.jsoncanddrizzle.config.ts). - Tables:
pack_catalog(pack_key, ...)— authoritative pack metadata: key, state, tier, sequence range, object count, byte sizes, creation/supersession timestamps. Drives both read-path discovery and compaction planning.
- Access policy: all SQLite operations must go through the DAL (
src/do/repo/db/dal.ts). Avoid raw drizzle queries outside the DAL. - Repository listing and authorization come from D1.
ROUTESKV is only a non-sensitive route candidate cache.
Static assets and UI rendering (env.ASSETS + React SSR)
- React page components are rendered on the Worker through
renderToReadableStream()insrc/client/server/render.tsx. - Route handlers call
renderUiView()and the view registry insrc/client/server/registry.tsxso SSR pages and fragments share one rendering path. - Client assets are split across
src/client/entries/*.ts, withsrc/client/entries/styles.tsloading shared UI CSS and route-specific entrypoints mounting only the islands each page needs. - Production assets are built by Vite and served through the
ASSETSbinding using the generated manifest (dist/client/manifest.json). - Development runs through the Cloudflare Vite plugin so Worker code, TSX, and CSS all participate in the same hot-reload pipeline.
- Assets config uses
html_handling: "none"so the Worker controls routes like/authwithout the assets layer intercepting them.
Background processing and alarms
- The repo DO
alarm()handles:- Lightweight lease cleanup (expired receive/compaction leases)
- Compaction queue re-arm when
compactionWantedAtis set - Idle cleanup (purge empty repos after idle timeout)
- Helpers:
rearmCompactionQueueFromAlarm()- Triggers compaction when requestedhandleIdleAndMaintenance()- Manages idle cleanup and alarm schedulingshouldCleanupIdle()- Determines if cleanup is neededperformIdleCleanup()- Executes cleanuppurgeR2Mirror()- Handles R2 cleanup
Logging
- Structured JSON logs are emitted with a minimal logger. Set
LOG_LEVELtodebug|info|warn|errorto control verbosity.
See also:
- Storage model
- Data flows
- Top-level
README.mdfor development and testing commands.