Components
Audio Architecture
System Architecture
adapter 3 components
Wraps Audio.Sound and Audio.Recording. Creates, loads, and releases native resources. Forwards status updates to the store via callback injection. Handles iOS audio session category configuration and Android focus management.
-
file-storage— Reads and writes audio files from local storage.
patch-translator
↗ Patch Persistence Converts MobX Keystone patches to SQL operations. Maps patch paths to Drizzle table references and builds type-safe insert/update/delete statements. Filters out ephemeral and computed fields.
-
drizzle-schema— Resolves table references and column names from Drizzle schema.
Bridges Drizzle's type-safe query builder to op-sqlite's . Uses Drizzle's to extract SQL + params, subscribes via op-sqlite's native change hook, and validates results through Zod before applying to Keystone models.
-
drizzle-schema— Builds queries using Drizzle's . -
zod-schemas— Validates reactive query results before applying to models. -
keystone-models— Applies validated results to Keystone stores via surgical reconciliation.
store 6 components
Root state model: currentRecordingId, status (idle | recording | playing | paused), positionMs, durationMs, metering levels. Exposes actions for play, pause, seek, startRecording, stopRecording. Derives formatted timestamps and progress ratio as views.
-
audio-bridge— Delegates to the native bridge for all expo-av interactions.
Uses keyed by entity ID for O(1) lookups during reconciliation. Surgical per-instance updates replace naive on arrays, avoiding the performance cliff at 1000+ items on low-end devices.
-
keystone-models— Holds model instances in an ObjectMap.
Domain models that participate in draft-based editing expose a single model action as their write surface. This action is the only mutation point called by domain functions, ensuring all field changes within one save produce a single patch group.
A generic model with type/id key encoding, arbitrary data payload, and timestamps. Carries metadata about whether it represents a new entity or an edit of an existing one. Provides computed helpers for validation and change detection.
Manages the lifecycle of all active drafts. Provides upsert, get, and discard operations. Persists the entire draft collection as a JSON blob in a SQLite key-value table with debounced writes. Supports hydration on app restart for crash recovery.
-
draft-model— Holds a collection of Draft model instances.
Domain models generated from Zod schemas via , extended with computed values and model actions. Observed by UI components for reactive rendering. In Option A these are view-caches; in Option B they are the source of truth.
-
zod-schemas— Model shape derived from Zod select schemas.
infrastructure 6 components
Provides the SQLite database connection. In production, wraps with extensions (FTS5, sqlite-vec, rtree). Configured via .
On-device tests covering op-sqlite-specific features that cannot be tested with : reactive queries firing on data changes, FTS5 full-text search results, sqlite-vec vector queries, and extension-specific behaviour.
Manages the on-device audio file directory. Provides paths for new recordings and resolves paths for playback. Handles cleanup of orphaned files.
Generates migration SQL files at dev time via . Bundles migrations into the JS bundle via Babel inline-import plugin. Runs migrations on device at app startup via hook before any UI renders. Tracks applied migrations in table.
-
drizzle-schema— Generates migrations from schema diffs. -
database-provider— Applies migrations to the on-device database.
Wraps to intercept top-level actions. Records patches during action execution, groups them on completion, and flushes as a single SQL transaction. Skips persistence when actions throw (Keystone already reverts the model tree).
-
patch-translator— Delegates patch-to-SQL conversion. -
database-provider— Executes SQL transactions against the database.
Creates isolated in-memory SQLite databases for tests. Each call returns a fresh Drizzle instance with the current schema applied via . No migration files, no Docker, no shared state.
contract 2 components
Defines all SQLite tables via . Serves as the single schema source from which Zod schemas, TS types, and Keystone models are derived. Also produces type-safe query builders.
Select, insert, and update schemas derived from Drizzle via , , . Used for runtime validation of query results and service inputs.
-
drizzle-schema— Schemas are generated from Drizzle table definitions.
surface 1 component
Editor components bind to the draft model (not the persisted domain model). The draft is created from the domain entity on mount, mutated freely via two-way bindings, and committed via the domain function on save. Draft lifetime is managed via component state, a volatile on a screen model, or the global DraftStore for crash recovery.
-
draft-store— Retrieves or creates drafts by key. -
draft-aware-model— Commits drafts via domain functions targeting the domain model.
ui 1 component
Renders playback controls (play/pause, seek bar, timestamp), recording indicator with live metering, and waveform visualization. Observes the audio-player-store via mobx-react-lite . Shows recording indicator and live duration counter. Transitions UI to playback-ready state.
-
audio-player-store— Reads state and dispatches actions.
service 2 components
Domain logic, validation, and business rules. All database writes flow through services. Services accept (Drizzle type) via constructor injection, making them testable with any compatible SQLite driver.
-
drizzle-schema— Executes type-safe Drizzle queries for reads and writes. -
zod-schemas— Validates inputs using insert/update Zod schemas.
Manages undo/redo history using Keystone's inverse patches. Each history entry corresponds to one top-level action (one draft commit). Applying inverse patches to the model tree automatically triggers the persistence middleware to generate compensating SQL.
-
persistence-middleware— Undo/redo mutations flow through the same persistence pipeline.