Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,146 @@
# OpenSpec Change: enterprise-db-sqlite
- **Change ID**: enterprise-db-sqlite
- **Package**: `@suaveplan/db-sqlite`
- **Category**: universal
- **Target path**: `universal/database/db-sqlite`
- **Status**: IN PROGRESS
- **Date**: 2026-04-23
- **Reference spec**: `/mnt/s/web/suaveplan/enterprise/db-sqlite.md`
## Summary
Greenfield implementation of `@suaveplan/db-sqlite` for the genesis branch. Universal SQLite adapter — `bun:sqlite` on the Bun server, `@sqlite.org/sqlite-wasm` with OPFS persistence in the browser, unified behind a single Drizzle-ORM surface. One schema definition, one query builder API, two runtimes selected transparently via `package.json` conditional exports.
The main-branch version (v1.0.0) provides the baseline public-API surface to preserve. Genesis adds enterprise-grade structured errors, an LRU prepared-statement cache, a forward-only migration runner with a ledger table and dry-run mode, OTel instrumentation, property-based tests, benchmarks, and a full co-located documentation suite.
## Current-state audit (genesis)
The package does not exist on genesis yet — this is a fresh build. The `universal/database/` domain directory does not exist either and must be created alongside the required predecessor package `@suaveplan/db`.
## Available workspace deps on genesis
| Package | Status | Notes |
|---------|--------|-------|
| `@suaveplan/error` | ✅ built | Extend for `SqliteError` with `SQLITE.*` codes |
| `@suaveplan/types` | ✅ built | `Clock`, `IdGenerator`, `LoggerLike` interfaces |
| `@suaveplan/db` | ❌ not yet built | Must land before `db-sqlite` — provides `DatabaseAdapter`, `DatabaseConfig`, `MigrationConfig`, `MigrationResult`, singleton helpers |
| `@suaveplan/logger` | ✅ built | Structured logging inside adapter |
| `@suaveplan/opentelemetry` | ❌ not yet built | Use `@opentelemetry/api` directly |
| `@suaveplan/schema-registry` | ✅ built | Wire Zod schemas for config/row types |
| `@suaveplan/retry` | ✅ built | Retry on `SQLITE_BUSY` write paths |
| `@suaveplan/feature-flags` | ✅ built | Gate risky migration or pragma changes |
External deps — require a new `catalog:database` block in the root `package.json` (none of these exist in any current catalog):
| Package | Catalog entry to add |
|---------|---------------------|
| `drizzle-orm` | `catalog:database` |
| `@sqlite.org/sqlite-wasm` | `catalog:database` |
`bun:sqlite` is a built-in Bun module — no npm dep needed; import is conditional.
Dev deps (all already in `catalog:testing`):
- `vitest`, `@vitest/coverage-istanbul`, `fast-check`, `mitata`
Build deps (already in `catalog:build`):
- `vite`, `vite-plugin-dts`, `tslib`
## Preserved public API surface (from main branch)
All of the following must be exported from the genesis build at `"."` and at the
corresponding feature subpaths.
### Types
- `SqliteAdapterOptions` — alias for `BunDriverOptions` (filename, readonly)
- `BunDriverOptions` — `{ filename?: string; readonly?: boolean }`
- `BunDriverResult` — `{ sqlite: Database; close: () => Promise<void> }`
- `WasmDriverOptions` — `{ filename?: string }`
- `WasmDriverResult<TSchema>` — `{ db: SqliteRemoteDatabase<TSchema>; close: () => Promise<void> }`
### Classes
- `SqliteAdapter<TSchema>` — implements `DatabaseAdapter` from `@suaveplan/db`
- `constructor(options?: SqliteAdapterOptions, schema?: TSchema)`
- `connect(config?: Partial<DatabaseConfig>): Promise<void>`
- `disconnect(): Promise<void>`
- `query<T>(sql: string, params?: unknown[]): Promise<T[]>`
- `execute(sql: string, params?: unknown[]): Promise<void>`
- `transaction<T>(fn: () => Promise<T>): Promise<T>`
- `migrate(config?: MigrationConfig): Promise<MigrationResult>`
- `get isConnected: boolean`
- `get drizzle: BunSQLiteDatabase<TSchema>` — available after `connect()`
### Functions
- `createBunDriver(options?: BunDriverOptions): Promise<BunDriverResult>`
- `isBunEnvironment(): boolean`
- `createWasmDriver<TSchema>(options?: WasmDriverOptions, schema?: TSchema): Promise<WasmDriverResult<TSchema>>`
- `getDefaultSqlite(options?, config?, name?): Promise<SqliteAdapter>`
- `closeSqlite(name: string): Promise<void>`
- `closeAllSqlite(): Promise<void>`
- `hasSqlite(name: string): boolean`
### Unsafe subpath (`@suaveplan/db-sqlite/unsafe`)
- `rawQuery(db, sql, params?)` — direct SQL execution, bypasses query builder
## New additions for genesis
### Modules
- **`src/errors/`** — `SqliteError` extending `SuaveplanError`; stable code registry `SQLITE_CODES`:
`SQLITE.NOT_CONNECTED`, `SQLITE.QUERY_FAILED`, `SQLITE.EXECUTE_FAILED`,
`SQLITE.TRANSACTION_FAILED`, `SQLITE.MIGRATION_FAILED`, `SQLITE.ENVIRONMENT_ERROR`,
`SQLITE.BUSY`, `SQLITE.CONSTRAINT`, `SQLITE.CORRUPT`, `SQLITE.DRIVER_INIT_FAILED`
- **`src/cache/`** — `PreparedStatementCache` — LRU-bounded (configurable max size, default 128),
keyed by SQL text, invalidated on migration, OTel hit/miss counters
- **`src/migration/`** — `MigrationRunner` — forward-only, idempotent, ledger table
(`__sqlite_migrations`), dry-run mode, `MigrationRunnerOptions` Zod schema,
integrates with Drizzle migrator; emits OTel span per migration file applied
- **`src/schemas/`** — Zod schemas for `SqliteAdapterOptions`, `BunDriverOptions`,
`WasmDriverOptions`, `MigrationRunnerOptions`; exported as re-usable validators
- **`src/otel/`** — `withQuerySpan(name, sql, fn)` wrapper — sanitises SQL (strips
literal values), records `db.system=sqlite`, `db.statement`, latency histogram,
error event on failure; no-op when no OTel provider registered
- **`src/conformance/`** — shared test suite (`conformance-suite.ts`) exercising both
Bun and WASM drivers: CRUD, transactions, rollback semantics, prepared-statement
cache hits, migration ledger idempotency, `AbortSignal` cancellation
- **`src/__benchmarks__/`** — mitata benchmarks: single-row insert, bulk insert (1 k
rows), point-lookup, full-table scan, prepared vs. ad-hoc statement comparison
### Cross-cutting enterprise requirements
- `SqliteAdapter` constructor throws `SqliteError(SQLITE.ENVIRONMENT_ERROR)` when
`isBunEnvironment()` is false — keeps runtime guarantee at the type level
- `PreparedStatementCache` evicts on `migrate()` to prevent stale plan reuse
- All public-facing async methods accept optional `AbortSignal` where the underlying
driver supports cancellation (query abort path on `bun:sqlite` via `statement.finalize()`)
- `transaction()` uses `BEGIN IMMEDIATE` to avoid deadlock on concurrent writes
- `sideEffects: false` confirmed and guarded by a tree-shake size test
- Property-based tests (fast-check) for: SQL-injection resistance via Drizzle
parameterisation, transaction isolation invariants, cache eviction correctness
- Zero `any`, zero `ts-ignore`, zero mock usage in tests — real in-memory SQLite only
- Injectable `clock` for migration ledger timestamps (defaults to `Date.now`)
- Conditional `package.json` exports route `./adapter` to `adapter.bun.js` (Bun runtime)
and `adapter.wasm.js` (browser), keeping hot-path free of runtime detection
## Impact
- Introduces a new domain directory: `universal/database/`
- Adds `catalog:database` block to root `package.json` (new entries: `drizzle-orm`,
`@sqlite.org/sqlite-wasm`)
- Blocks on `@suaveplan/db` landing first (dependency-order constraint)
- No existing genesis packages depend on `@suaveplan/db-sqlite` yet — zero breaking-change
risk within the current tree
- WASM test suite requires `fileParallelism: false` in the browser-environment
vitest config (WSL2 concurrent OPFS forks limitation)