Capabilities
What z0 SDK does: Event-sourced ledger system for building immutable, traceable systems on Cloudflare Workers.
Core Capabilities
Section titled “Core Capabilities”1. Event Sourcing with Facts
Section titled “1. Event Sourcing with Facts”What: Immutable event records (Facts) are the source of truth. All state is derived from Facts.
When to use:
- Need complete audit trail of all changes
- Building financial systems requiring immutability
- Implementing GDPR-compliant data tracking
- Supporting point-in-time reconstruction
When NOT to use:
- Simple CRUD apps where audit history isn’t needed
- Real-time gaming (latency-sensitive, not business-critical)
- Static file hosting
2. Entity-Based State Management
Section titled “2. Entity-Based State Management”What: Entities are identity containers. One Durable Object per Entity for perfect isolation.
When to use:
- Multi-tenant SaaS (tenant isolation built-in)
- Systems requiring per-entity transaction guarantees
- Applications with complex entity relationships
When NOT to use:
- Need cross-entity queries (use D1 replication for analytics)
- Entities have no unique identity (use KV or R2)
3. Versioned Configuration (Config)
Section titled “3. Versioned Configuration (Config)”What: Configuration changes create new versions instead of overwriting. Time-based activation with effective_at.
When to use:
- Pricing rules that change over time
- Feature flags with scheduled rollout
- Routing policies with audit trail
When NOT to use:
- Static environment variables
- Per-request context (use middleware)
4. Real-Time Subscriptions (0.8.0+)
Section titled “4. Real-Time Subscriptions (0.8.0+)”What: WebSocket and SSE support for streaming entity changes to clients.
When to use:
- Real-time dashboards
- Live notifications
- Collaborative editing
When NOT to use:
- Static reports (use snapshot endpoints)
- One-time queries
5. Cached State Derivation
Section titled “5. Cached State Derivation”What: Denormalized views (CachedState) derived from Facts. Can be rebuilt anytime.
When to use:
- Expensive aggregations (balance, usage totals)
- Frequently-read derived data
- Performance-critical queries
When NOT to use:
- Storing source data (use Facts)
- Cross-entity aggregations (use D1)
6. Hierarchical Entity Trees
Section titled “6. Hierarchical Entity Trees”What: Parent-child entity relationships with depth limits and cached parent data.
When to use:
- Organization → Team → User hierarchies
- Account → Sub-account structures
- Nested resource ownership
When NOT to use:
- Graph relationships (many-to-many)
- Flat data structures
7. Schema-Based Development
Section titled “7. Schema-Based Development”What: TypeScript-first schema builders OR YAML manifests for entity definitions.
When to use:
- Type-safe domain modeling
- Validation at fact append time
- Generating docs/tests from schemas
When NOT to use:
- Schemaless/freeform data (use raw JSON)
8. API Gateway Layer (0.9.0+)
Section titled “8. API Gateway Layer (0.9.0+)”What: Declarative HTTP routing with type-safe contracts, authentication, and rate limiting.
When to use:
- Building REST APIs on Cloudflare Workers
- Contract-first development with OpenAPI generation
- Need built-in auth, rate limiting, validation
- Want consistent API response formats
When NOT to use:
- GraphQL APIs (no GraphQL support)
- WebSocket-only APIs (use real-time subscriptions directly)
- Static file serving
Key features:
- Routes in YAML - Define HTTP routes alongside entities
- GatewayWorker base class - Extend for automatic routing and middleware
- oRPC contracts - Type-safe action interfaces with Zod validation
- Auth middleware - API key authentication built-in
- Rate limiting - Per-route rate limits (tenant/global scope)
- Response shaping - Standard envelopes (
{ data, meta }) and RFC 7807 errors - Code generation - Generate complete Workers from manifests
- OpenAPI generation - Auto-generate OpenAPI 3.0 specs from contracts
Actions available:
emit- Append a fact to an entityget- Retrieve an entity by IDcreate- Create a new entitylist- List entities with cursor paginationquery- Execute projection queries
9. Built-In Utilities
Section titled “9. Built-In Utilities”Included:
- ID generation with prefixes
- RFC 7807 error handling
- Webhook signing and delivery
- Tiered pricing calculation
- Threshold monitoring
- Batch operations with resumability
- Circuit breakers for DO-to-DO calls
- Rate limiting with backpressure
- Temporal resource binding (phone numbers, email addresses)
10. Testing Utilities
Section titled “10. Testing Utilities”What: Mock Durable Object context, stubs, and queues for unit testing.
When to use:
- Testing EntityLedger subclasses
- Mocking DO dependencies
- Isolated ledger tests
11. Engines
Section titled “11. Engines”ProjectionEngine: Fact aggregations from YAML config (sum, avg, count, max, min) MeterEngine: Usage tracking and budget enforcement
Architecture Patterns
Section titled “Architecture Patterns”DO-Level Isolation
Section titled “DO-Level Isolation”- One Entity = One Durable Object
- Perfect tenant isolation
- No cross-entity queries (by design)
Fact Replication
Section titled “Fact Replication”- Facts auto-replicate to D1 (analytics)
- Facts optionally replicate to R2 (archival)
- DOs remain the source of truth
Lifecycle Management
Section titled “Lifecycle Management”- States: active → retiring → retired → anonymized → deleted
- GDPR compliance with anonymization
- Dead-lettering rejected facts
Migration Support
Section titled “Migration Support”- Schema versioning for facts
- Data tier transitions (hot → warm → cold)
- Backward-compatible migrations
Limits & Constraints
Section titled “Limits & Constraints”SDK Limits
Section titled “SDK Limits”| Limit | Value | Why |
|---|---|---|
| Max hierarchy depth | 10 | Prevent infinite recursion |
| Default query limit | 1000 facts | Memory/performance |
| WebSocket subscribers | Per DO limit | Memory in DO |
| Config versions | Unlimited | Stored in SQLite |
| Fact immutability | Forever | Append corrections, never mutate |
Cloudflare Infrastructure Limits (CRITICAL)
Section titled “Cloudflare Infrastructure Limits (CRITICAL)”These are platform constraints that affect architectural decisions:
| Service | Limit | Impact |
|---|---|---|
| Analytics Engine | 90 days retention | Historical data beyond 90 days is lost. For long-term analytics, replicate to R2/external storage. |
| D1 Database | 10GB per database | Large datasets need sharding or external DB |
| D1 Rows | 100M rows per database | Plan for horizontal scaling |
| Durable Object Storage | 10GB per DO | Partition large entities |
| DO Request Duration | 30s (default), 15min (paid) | Long-running operations need queues |
| DO Memory | 128MB | Watch CachedState size, paginate large queries |
| KV Value Size | 25MB | Split large objects |
| R2 Object Size | 5TB | Effectively unlimited for archival |
| Queue Message Size | 128KB | Serialize large payloads to R2 |
| Queue Batch Size | 100 messages | Plan batch processing |
| Worker CPU Time | 10-50ms (free), 30s (paid) | Offload heavy computation |
| Worker Memory | 128MB | Stream large responses |
| Subrequest Limit | 50 (free), 1000 (paid) | Batch DO calls |
Time-Based Constraints
Section titled “Time-Based Constraints”| Constraint | Duration | Mitigation |
|---|---|---|
| Analytics Engine data | 90 days | Export to R2 before expiration |
| DO hibernation | After 10s idle | Use alarms for scheduled work |
| WebSocket idle timeout | 60s | Send heartbeats |
| Queue retry window | 4 days | Dead-letter unprocessable messages |
Design Implications
Section titled “Design Implications”Analytics Engine 90-day limit:
// ❌ DON'T: Rely on Analytics Engine for historical reportsconst yearlyReport = await analytics.query('SELECT ... WHERE timestamp > DATE_SUB(NOW(), 365)');// Data older than 90 days is GONE
// ✅ DO: Archive to R2 for long-term analyticsawait env.ARCHIVE_BUCKET.put( `analytics/${year}/${month}/data.json`, JSON.stringify(monthlySnapshot));D1 row limits:
// ❌ DON'T: Assume unlimited D1 growth// With 100M row limit, high-volume fact replication can hit limits
// ✅ DO: Implement retention policiesawait env.DB.exec(` DELETE FROM facts WHERE timestamp < datetime('now', '-6 months') AND archived_to_r2 = true`);DO memory constraints:
// ❌ DON'T: Load all facts into memoryconst allFacts = this.getFacts(); // Could OOM with large history
// ✅ DO: Paginate and streamfor await (const batch of this.getFactsPaginated({ limit: 100 })) { // Process batch}Status: Stable (v0.10.0)
Section titled “Status: Stable (v0.10.0)”Published: npm @z0-app/sdk
License: MIT
Platform: Cloudflare Workers + Durable Objects
Language: TypeScript
NOT Included
Section titled “NOT Included”- UI framework (bring your own)
- Authentication provider (use Clerk, Auth0, etc.)
- Database ORM (uses raw SQLite)
- HTTP framework (compatible with Hono, Itty Router, etc.)
- Cross-entity joins (use D1 replication)