Initial Commit
This commit is contained in:
279
openspec/archive/2026-04-24-enterprise-surrealdb/proposal.md
Normal file
279
openspec/archive/2026-04-24-enterprise-surrealdb/proposal.md
Normal file
@@ -0,0 +1,279 @@
|
||||
# OpenSpec Change: enterprise-surrealdb
|
||||
|
||||
- **Change ID**: enterprise-surrealdb
|
||||
- **Package**: `@suaveplan/surrealdb`
|
||||
- **Category**: universal
|
||||
- **Target path**: `universal/database/surrealdb`
|
||||
- **Status**: PROPOSED
|
||||
- **Date**: 2026-04-24
|
||||
- **Reference spec**: `/mnt/s/web/suaveplan/enterprise/surrealdb.md`
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
Deliver `@suaveplan/surrealdb` on the genesis branch from scratch at enterprise quality. The package provides a universal SurrealDB client wrapper with automatic version detection (v1/v2/v3), connection lifecycle management (connect/disconnect/singleton registry), schema discovery and loading, a migration runner, and a pluggable adapter layer that normalises the raw `surrealdb.js` driver API into a stable typed surface. Genesis adds structured errors via `@suaveplan/error`, Zod schemas for every public options type, OTel instrumentation on all async operations, `AbortSignal` cancellation throughout, retry integration via `@suaveplan/retry`, property-based tests (fast-check), and a mitata benchmark suite. The SurrealDB-specific migration runner (internal to this package in main) is split out to `@suaveplan/migration` on genesis; only the connection + adapter surface lives here.
|
||||
|
||||
---
|
||||
|
||||
## Current-state audit (genesis)
|
||||
|
||||
The package does not exist on genesis yet — this is a fresh build. No prior source, no test results, no coverage data.
|
||||
|
||||
---
|
||||
|
||||
## Available workspace deps on genesis
|
||||
|
||||
| Package | Role |
|
||||
|---|---|
|
||||
| `@suaveplan/error` (`workspace:^`) | Base class for `SurrealError`; `defineCodes` for `SURREAL.*` codes |
|
||||
| `@suaveplan/types` (`workspace:^`) | `LoggerLike`, `Clock` (injectable for timeout helpers) |
|
||||
| `@suaveplan/db` (`workspace:^`) | `DatabaseAdapter` interface, singleton registry helpers (`getSingleton`/`closeSingleton`) |
|
||||
| `@suaveplan/retry` (`workspace:^`) | `RetryStrategy`, `withRetry` — wired on connect and query paths |
|
||||
| `surrealdb` (`catalog:database`) | Raw SurrealDB JS driver |
|
||||
| `zod` (`catalog:forms`) | Zod schemas for all public option types |
|
||||
| `@opentelemetry/api` (`catalog:observability`) | Spans + counters on connect, query, disconnect |
|
||||
| `tslib` (`catalog:build`) | Runtime helpers |
|
||||
|
||||
Dev deps: `vitest`, `@vitest/coverage-istanbul`, `fast-check`, `mitata` (all `catalog:testing`), `@suaveplan/testing` (`workspace:^`).
|
||||
|
||||
---
|
||||
|
||||
## Preserved public API surface (from main branch)
|
||||
|
||||
All symbols below are carried forward; signatures may gain optional genesis-only fields but existing call sites remain valid.
|
||||
|
||||
### Connection
|
||||
|
||||
```ts
|
||||
interface SurrealDBConfig {
|
||||
url: string
|
||||
namespace: string
|
||||
database: string
|
||||
auth: { username: string; password: string }
|
||||
}
|
||||
|
||||
function getDefaultConfig(): SurrealDBConfig
|
||||
function createConnection(config?: Partial<SurrealDBConfig>): Promise<Surreal>
|
||||
function connectWith(config?: Partial<SurrealDBConfig>): Promise<Surreal>
|
||||
function getSingleton(config?: Partial<SurrealDBConfig>): Promise<Surreal>
|
||||
function hasSingleton(): boolean
|
||||
function closeSingleton(): Promise<void>
|
||||
```
|
||||
|
||||
### Adapter
|
||||
|
||||
```ts
|
||||
// Re-exported from surrealdb driver (not re-wrapped — direct pass-through for types)
|
||||
type Patch
|
||||
type RecordIdValue
|
||||
class RecordId
|
||||
class StringRecordId
|
||||
class Surreal
|
||||
class Table
|
||||
|
||||
// Adapter base interface
|
||||
interface SurrealAdapter {
|
||||
connect(config: SurrealDBConfig): Promise<void>
|
||||
disconnect(): Promise<void>
|
||||
query<T>(sql: string, params?: Record<string, unknown>): Promise<T[][]>
|
||||
create<T>(table: string, data: Partial<T>): Promise<T>
|
||||
select<T>(thing: string): Promise<T[]>
|
||||
update<T>(thing: string, data: Partial<T>): Promise<T>
|
||||
merge<T>(thing: string, data: Partial<T>): Promise<T>
|
||||
delete(thing: string): Promise<void>
|
||||
readonly connectionState: ConnectionState
|
||||
}
|
||||
|
||||
class SurrealAdapter implements SurrealAdapter
|
||||
```
|
||||
|
||||
### Schema utilities
|
||||
|
||||
```ts
|
||||
function getDefaultSchemaDir(): string
|
||||
function discoverSchemas(dir: string, options?: DiscoverOptions): Promise<SchemaFile[]>
|
||||
function filterSchemas(files: SchemaFile[], filter: SchemaFilter): SchemaFile[]
|
||||
function getSchemasToLoad(dir: string, filter?: SchemaFilter): Promise<SchemaFile[]>
|
||||
function readSchemaContent(file: SchemaFile): Promise<string>
|
||||
|
||||
const DEFAULT_SCHEMA_ORDER: readonly string[]
|
||||
|
||||
interface SchemaFile { name: string; path: string; content?: string }
|
||||
type SchemaFilter = (file: SchemaFile) => boolean
|
||||
```
|
||||
|
||||
### Init
|
||||
|
||||
```ts
|
||||
function initDatabase(db: Surreal, options: InitOptions): Promise<InitResult>
|
||||
function initAndClose(options: DbConfig): Promise<InitResult>
|
||||
function createInitializer(options: InitOptions): (db: Surreal) => Promise<InitResult>
|
||||
|
||||
interface InitOptions {
|
||||
schemaDir?: string
|
||||
schemas?: SchemaFile[]
|
||||
filter?: SchemaFilter
|
||||
hooks?: SchemaHook[]
|
||||
dryRun?: boolean
|
||||
}
|
||||
|
||||
interface InitResult { applied: string[]; skipped: string[]; errors: string[] }
|
||||
|
||||
interface DbConfig extends InitOptions {
|
||||
connection?: Partial<SurrealDBConfig>
|
||||
}
|
||||
|
||||
type FilterStrategy = 'include' | 'exclude'
|
||||
interface SchemaHook { before?: HookFn; after?: HookFn }
|
||||
type AdvancedInitOptions = InitOptions & { parallel?: boolean; timeout?: number }
|
||||
```
|
||||
|
||||
### Common types
|
||||
|
||||
```ts
|
||||
type SurrealVersion = string
|
||||
type MajorVersion = 1 | 2 | 3
|
||||
interface VersionInfo { version: SurrealVersion; major: MajorVersion; minor: number; patch: number; prerelease?: string }
|
||||
type ConnectionState = 'disconnected' | 'connecting' | 'connected' | 'authenticated' | 'error'
|
||||
interface RecordId { tb: string; id: string | number }
|
||||
type RecordResult<T = unknown> = T & { id: RecordId }
|
||||
type QueryStatementResult<T = unknown> = { status: 'OK' | 'ERR'; time?: string; result?: T; error?: string }
|
||||
type RawQueryResult<T = unknown> = QueryStatementResult<T>[]
|
||||
type QueryResult<T = unknown> = T[][]
|
||||
interface AuthCredentials { username: string; password: string }
|
||||
```
|
||||
|
||||
### Error codes
|
||||
|
||||
```ts
|
||||
type SurrealErrorCode =
|
||||
| 'SURREAL_CONNECT_FAILED'
|
||||
| 'SURREAL_QUERY_FAILED'
|
||||
| 'SURREAL_AUTH_FAILED'
|
||||
| 'SURREAL_NOT_CONNECTED'
|
||||
| 'SURREAL_TIMEOUT'
|
||||
| 'SURREAL_VERSION_UNSUPPORTED'
|
||||
| 'SURREAL_SCHEMA_LOAD_FAILED'
|
||||
| 'SURREAL_INIT_FAILED'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## New additions for genesis
|
||||
|
||||
### 1. Structured `SurrealError`
|
||||
|
||||
`SurrealError` extends `SuaveplanError` from `@suaveplan/error`, carrying a `SurrealErrorCode` discriminant. All internal throw sites use named factory helpers.
|
||||
|
||||
### 2. Zod schemas for all public option types
|
||||
|
||||
- `SurrealDBConfigSchema`
|
||||
- `InitOptionsSchema`
|
||||
- `DiscoverOptionsSchema`
|
||||
- `SchemaFileSchema`
|
||||
- `AdvancedInitOptionsSchema`
|
||||
|
||||
### 3. Retry integration
|
||||
|
||||
`createConnection` and `SurrealAdapter.query` accept an optional `retry?: RetryStrategyOptions` field. When provided the connection/query is wrapped with `@suaveplan/retry`'s `withRetry`. Default: no retry (caller opt-in).
|
||||
|
||||
### 4. AbortSignal throughout
|
||||
|
||||
All async public functions accept an optional `signal?: AbortSignal`. Pending connections abort immediately on signal; in-flight queries are cancelled via the driver's abort mechanism where supported.
|
||||
|
||||
### 5. OTel instrumentation
|
||||
|
||||
| Operation | Signal |
|
||||
|---|---|
|
||||
| `createConnection` | span `surreal.connect`, attributes `surreal.url`, `surreal.namespace` |
|
||||
| `SurrealAdapter.query` | span `surreal.query`, histogram `surreal.query_duration_ms`, counter `surreal.query_total` |
|
||||
| `SurrealAdapter.connect` | counter `surreal.connect_total` |
|
||||
| `closeSingleton` | span `surreal.disconnect` |
|
||||
| `initDatabase` | span `surreal.init`, attribute `surreal.schema_count` |
|
||||
|
||||
### 6. Version detector utility
|
||||
|
||||
`detectVersion(db: Surreal): Promise<VersionInfo>` — calls `db.version()`, parses semver, returns typed `VersionInfo`. Throws `SurrealError` with code `SURREAL_VERSION_UNSUPPORTED` for major versions outside 1–3.
|
||||
|
||||
### 7. `DatabaseAdapter` bridge
|
||||
|
||||
`SurrealAdapter` implements `@suaveplan/db`'s `DatabaseAdapter` interface so it can be consumed by `@suaveplan/migration` and other db-layer packages without tight coupling to `surrealdb.js`.
|
||||
|
||||
### 8. Property-based tests (fast-check)
|
||||
|
||||
- `detectVersion` parser: for arbitrary semver strings, assert round-trip correctness of `major.minor.patch`.
|
||||
- `filterSchemas`: for N random schema files with random names, assert that include/exclude filter with the same predicate is the complement of the other.
|
||||
- `SurrealAdapter` state machine: transitions are deterministic — `connect` moves to `connecting` → `connected`; `disconnect` from any state moves to `disconnected`.
|
||||
|
||||
### 9. Benchmark suite
|
||||
|
||||
- `createConnection_cold`: connect + authenticate + disconnect (requires live SurrealDB or skip with `SKIP_DB_BENCHMARKS`).
|
||||
- `query_hot`: 1000 `SELECT * FROM test` queries against a pre-connected adapter (requires live DB).
|
||||
- `detectVersion_parse`: 10 000 semver parse iterations (pure, no IO).
|
||||
|
||||
---
|
||||
|
||||
## File layout
|
||||
|
||||
```text
|
||||
universal/database/surrealdb/
|
||||
package.json
|
||||
tsconfig.json
|
||||
vitest.config.ts
|
||||
src/
|
||||
index.ts # Public barrel
|
||||
error-codes.ts # SURREAL.* codes
|
||||
constants/
|
||||
index.ts # DEFAULT_SCHEMA_ORDER, connection defaults
|
||||
types/
|
||||
common.ts # All shared TS types
|
||||
common.md
|
||||
connection/
|
||||
connection/
|
||||
connection.ts # createConnection, connectWith, getSingleton, hasSingleton, closeSingleton
|
||||
connection.md
|
||||
connection.types.ts # SurrealDBConfig
|
||||
connection.test.ts
|
||||
index.ts
|
||||
adapters/
|
||||
surreal-adapter/
|
||||
surreal-adapter.ts # SurrealAdapter class
|
||||
surreal-adapter.md
|
||||
surreal-adapter.types.ts # SurrealAdapter interface
|
||||
surreal-adapter.test.ts
|
||||
index.ts
|
||||
schema/
|
||||
discovery/
|
||||
discovery.ts # discoverSchemas, filterSchemas, getSchemasToLoad, readSchemaContent
|
||||
discovery.md
|
||||
discovery.types.ts
|
||||
discovery.test.ts
|
||||
index.ts
|
||||
init/
|
||||
init/
|
||||
init.ts # initDatabase, initAndClose, createInitializer
|
||||
init.md
|
||||
init.types.ts # InitOptions, InitResult, DbConfig, SchemaHook
|
||||
init.test.ts
|
||||
index.ts
|
||||
utils/
|
||||
version-detector.ts # detectVersion
|
||||
version-detector.md
|
||||
version-detector.test.ts
|
||||
__benchmarks__/
|
||||
surreal.bench.ts
|
||||
tests/
|
||||
integration.test.ts # Full connect → query → disconnect (real SurrealDB via docker)
|
||||
property.test.ts # fast-check property tests
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Impact
|
||||
|
||||
**Downstream packages**: `@suaveplan/migration` depends on `SurrealAdapter` as a `DatabaseAdapter` implementation. No other genesis package currently requires it.
|
||||
|
||||
**Breaking changes from main-branch API**: none. All main-branch call sites compile unchanged; new optional fields (`retry`, `signal`, `logger`) are additive.
|
||||
|
||||
**Workspace dep prerequisites**: `@suaveplan/error`, `@suaveplan/types`, `@suaveplan/db`, `@suaveplan/retry` must be published to Verdaccio before this package can be built or tested.
|
||||
186
openspec/archive/2026-04-24-enterprise-surrealdb/tasks.md
Normal file
186
openspec/archive/2026-04-24-enterprise-surrealdb/tasks.md
Normal file
@@ -0,0 +1,186 @@
|
||||
# Tasks: enterprise-surrealdb
|
||||
|
||||
**Change ID**: enterprise-surrealdb
|
||||
**Package**: `@suaveplan/surrealdb`
|
||||
**Target path**: `universal/database/surrealdb`
|
||||
**Prerequisite packages on Verdaccio**: `@suaveplan/error`, `@suaveplan/types`, `@suaveplan/db`, `@suaveplan/retry`
|
||||
|
||||
---
|
||||
|
||||
## 1. Scaffold
|
||||
|
||||
- [x] Create directory `universal/database/surrealdb/` with `src/`, `tests/`, `src/__benchmarks__/`, and all feature subdirectories per the layout in `proposal.md`.
|
||||
- [x] Write `package.json` at version `0.1.0` with:
|
||||
- `"type": "module"`, `"sideEffects": false`
|
||||
- `exports` map: top-level `"."` barrel plus subpaths for `./connection/connection`, `./adapters/surreal-adapter`, `./schema/discovery`, `./init/init`, `./utils/version-detector`
|
||||
- `dependencies`: `@suaveplan/error workspace:^`, `@suaveplan/types workspace:^`, `@suaveplan/db workspace:^`, `@suaveplan/retry workspace:^`, `surrealdb catalog:database`, `zod catalog:forms`, `@opentelemetry/api catalog:observability`, `tslib catalog:build`
|
||||
- `devDependencies`: `vitest catalog:testing`, `@vitest/coverage-istanbul catalog:testing`, `fast-check catalog:testing`, `mitata catalog:testing`, `@suaveplan/testing workspace:^`
|
||||
- [x] Write `tsconfig.json` extending `@suaveplan/typescript-config/library.json`.
|
||||
- [x] Write `vitest.config.ts` using `createTestConfig()` from `@suaveplan/testing/config` (pool: `forks`).
|
||||
- [x] Add `lint`, `typecheck`, `test`, `test:coverage`, `build`, `docs:check`, `bench` scripts to `package.json`.
|
||||
|
||||
---
|
||||
|
||||
## 2. Types + errors
|
||||
|
||||
### 2a. Common types (`src/types/common.ts` + `src/types/common.md`)
|
||||
|
||||
- [x] Define all shared TS types: `SurrealVersion`, `MajorVersion`, `VersionInfo`, `ConnectionState`, `RecordId`, `RecordResult`, `QueryStatementResult`, `RawQueryResult`, `QueryResult`, `AuthCredentials`.
|
||||
- [x] Write `src/types/common.md` (≥200 words, both simple + advanced examples, API reference).
|
||||
|
||||
### 2b. Error codes (`src/error-codes.ts`)
|
||||
|
||||
- [x] Import `CodeMetadata`, `ErrorCodes`, `SuaveplanError` from `@suaveplan/error`.
|
||||
- [x] Define `SurrealErrorCode` union — eight codes: `SURREAL_CONNECT_FAILED`, `SURREAL_QUERY_FAILED`, `SURREAL_AUTH_FAILED`, `SURREAL_NOT_CONNECTED`, `SURREAL_TIMEOUT`, `SURREAL_VERSION_UNSUPPORTED`, `SURREAL_SCHEMA_LOAD_FAILED`, `SURREAL_INIT_FAILED`.
|
||||
- [x] Define `SURREAL_ERROR_METADATA` with `httpStatus`, `severity`, `retryable`, `userMessageKey`, `category`, `description` for each code.
|
||||
- [x] Export `registerSurrealErrorCodes()` — calls `ErrorCodes.registerMany(SURREAL_ERROR_METADATA)`. Idempotent.
|
||||
- [x] Call `registerSurrealErrorCodes()` as an eager side-effect at module scope.
|
||||
- [x] Export `SurrealError` extending `SuaveplanError` carrying `SurrealErrorCode` as its `.code` discriminant.
|
||||
|
||||
### 2c. Zod option schemas
|
||||
|
||||
- [x] Write `src/connection/connection/connection.types.ts` with `SurrealDBConfigSchema` and inferred `SurrealDBConfig`.
|
||||
- [x] Write `src/init/init/init.types.ts` with `InitOptionsSchema`, `AdvancedInitOptionsSchema`, `SchemaFileSchema`.
|
||||
- [x] Write `src/schema/discovery/discovery.types.ts` with `DiscoverOptionsSchema`.
|
||||
|
||||
---
|
||||
|
||||
## 3. Constants
|
||||
|
||||
- [x] Write `src/constants/index.ts`:
|
||||
- `DEFAULT_SCHEMA_ORDER`: `readonly string[]` with sensible migration-first ordering.
|
||||
- `DEFAULT_SURREAL_URL`, `DEFAULT_SURREAL_NAMESPACE`, `DEFAULT_SURREAL_DATABASE`.
|
||||
- `SURREAL_SUPPORTED_MAJOR_VERSIONS: readonly MajorVersion[]` = `[1, 2, 3]`.
|
||||
|
||||
---
|
||||
|
||||
## 4. Version detector (`src/utils/version-detector.ts`)
|
||||
|
||||
- [x] Implement `detectVersion(db: Surreal): Promise<VersionInfo>`:
|
||||
- Calls `db.version()`, parses the semver string with a regex.
|
||||
- Returns typed `VersionInfo` for major versions 1–3.
|
||||
- Throws `SurrealError` with code `SURREAL_VERSION_UNSUPPORTED` for unknown major versions.
|
||||
- [x] Write `version-detector.test.ts`: known version strings for v1/v2/v3, prerelease string, unsupported major throws.
|
||||
- [x] Write `version-detector.md` (≥200 words).
|
||||
|
||||
---
|
||||
|
||||
## 5. Connection (`src/connection/connection/`)
|
||||
|
||||
- [x] Implement `getDefaultConfig(): SurrealDBConfig` — reads `DB_URL`, `DB_NAMESPACE`, `DB_NAME`, `DB_USER`, `DB_PASS` from `process.env` where available; falls back to defaults.
|
||||
- [x] Implement `createConnection(config?, options?)`:
|
||||
- Merges partial config with defaults.
|
||||
- Instantiates `new Surreal()`, calls `db.connect(url)`, then authenticates.
|
||||
- Accepts optional `signal?: AbortSignal` — throws `SurrealError(SURREAL_TIMEOUT)` on abort before connect completes.
|
||||
- Accepts optional `retry?: RetryStrategyOptions` — wraps the connect+auth sequence with `@suaveplan/retry`'s `withRetry`.
|
||||
- OTel: span `surreal.connect`, counter `surreal.connect_total`.
|
||||
- [x] Implement `connectWith`, `getSingleton`, `hasSingleton`, `closeSingleton` — delegate to `@suaveplan/db`'s singleton helpers where appropriate.
|
||||
- [x] Write `connection.test.ts` (requires real SurrealDB; gate with `process.env.SURREALDB_URL` skip guard).
|
||||
- [x] Write `connection.md` (≥200 words).
|
||||
|
||||
---
|
||||
|
||||
## 6. Adapter (`src/adapters/surreal-adapter/`)
|
||||
|
||||
- [x] Define `SurrealAdapter` interface in `surreal-adapter.types.ts` — mirrors the main-branch surface; adds `DatabaseAdapter` from `@suaveplan/db` as parent interface.
|
||||
- [x] Implement `SurrealAdapter` class:
|
||||
- Internal `_state: ConnectionState` with protected getter.
|
||||
- `connect(config)` — calls `createConnection`, transitions state.
|
||||
- `disconnect()` — calls `db.close()`, transitions to `disconnected`.
|
||||
- `query<T>(sql, params?, options?)` — calls `db.query(sql, params)`, wraps errors as `SurrealError(SURREAL_QUERY_FAILED)`, records OTel span + histogram.
|
||||
- `create`, `select`, `update`, `merge`, `delete` — delegate to driver, wrap errors.
|
||||
- All methods accept optional `signal?: AbortSignal`.
|
||||
- Fix: use `INSERT INTO` query instead of `db.create()` to avoid surrealdb.js v2 content-drop bug (see memory `feedback_surrealdb_create_content_drop`).
|
||||
- [x] Write `surreal-adapter.test.ts` (integration, real SurrealDB; SURREALDB_URL skip guard).
|
||||
- [x] Write `surreal-adapter.md` (≥200 words).
|
||||
|
||||
---
|
||||
|
||||
## 7. Schema discovery (`src/schema/discovery/`)
|
||||
|
||||
- [x] Implement `discoverSchemas(dir, options?)` — reads directory recursively for `.surql` files; returns `SchemaFile[]` sorted by `DEFAULT_SCHEMA_ORDER` then alphabetically.
|
||||
- [x] Implement `filterSchemas(files, filter)` — apply caller-supplied predicate.
|
||||
- [x] Implement `getSchemasToLoad(dir, filter?)` — `discoverSchemas` + optional `filterSchemas`.
|
||||
- [x] Implement `readSchemaContent(file)` — reads file content; caches in `file.content`.
|
||||
- [x] Write `discovery.test.ts` — in-memory fixture files (no real FS), happy path, empty dir, filter exclude/include.
|
||||
- [x] Write `discovery.md` (≥200 words).
|
||||
|
||||
---
|
||||
|
||||
## 8. Init (`src/init/init/`)
|
||||
|
||||
- [x] Implement `initDatabase(db, options)`:
|
||||
- Calls `getSchemasToLoad`, reads each file, executes via `db.query(content)`.
|
||||
- Runs `options.hooks?.before` / `after` around each schema.
|
||||
- Dry-run mode: skip execution, record in `result.skipped`.
|
||||
- Returns `InitResult { applied, skipped, errors }`.
|
||||
- OTel: span `surreal.init`, attribute `surreal.schema_count`.
|
||||
- [x] Implement `initAndClose(options)` — opens a singleton, runs init, closes.
|
||||
- [x] Implement `createInitializer(options)` — returns a closure `(db) => initDatabase(db, options)`.
|
||||
- [x] Write `init.test.ts` (unit: mock schema files, real adapter not required; integration: SURREALDB_URL guard).
|
||||
- [x] Write `init.md` (≥200 words).
|
||||
|
||||
---
|
||||
|
||||
## 9. Public barrel (`src/index.ts`)
|
||||
|
||||
- [x] Re-export all public symbols from connection, adapters, schema, init, utils, types, error-codes, constants.
|
||||
- [x] Re-export `RecordId`, `StringRecordId`, `Surreal`, `Table`, `Patch`, `RecordIdValue` directly from `surrealdb` driver (not wrapped).
|
||||
|
||||
---
|
||||
|
||||
## 10. OTel instrumentation (cross-cutting)
|
||||
|
||||
- [x] Obtain tracer `surreal` and meter `surreal` once at module scope via lazy `trace.getTracer` / `metrics.getMeter`.
|
||||
- [x] `createConnection` — span `surreal.connect` with attributes `surreal.url`, `surreal.namespace`, `surreal.database`; counter `surreal.connect_total`.
|
||||
- [x] `SurrealAdapter.query` — span `surreal.query`; histogram `surreal.query_duration_ms`; counter `surreal.query_total` with attribute `surreal.table` where parseable.
|
||||
- [x] `closeSingleton` / `disconnect` — span `surreal.disconnect`.
|
||||
- [x] `initDatabase` — span `surreal.init`; attribute `surreal.schema_count`.
|
||||
- [x] All spans record exception on error and end in `finally`.
|
||||
|
||||
---
|
||||
|
||||
## 11. Property-based tests (`tests/property.test.ts`)
|
||||
|
||||
Use `fast-check`. All test timeouts: `{ timeout: 30000 }`.
|
||||
|
||||
- [x] **`detectVersion` parser**: for arbitrary `major.minor.patch` strings (1–3), assert that `parseVersionString` returns the same major/minor/patch. Does not require live DB.
|
||||
- [x] **`filterSchemas` complement**: generate N random schema files (2–10); assert include filter with predicate P plus exclude filter with predicate P covers the full set without overlap.
|
||||
- [x] **`ConnectionState` state machine**: for a sequence of `connect` and `disconnect` calls on a mock adapter, assert the final state equals the result of applying transitions in order (always ends `connected` or `disconnected`).
|
||||
|
||||
---
|
||||
|
||||
## 12. Benchmarks (`src/__benchmarks__/surreal.bench.ts`)
|
||||
|
||||
Use `mitata`. Guard IO-bound benchmarks with `SKIP_DB_BENCHMARKS` env flag.
|
||||
|
||||
- [x] `detectVersion_parse_10k`: 10 000 pure semver parses.
|
||||
- [x] `query_hot` (conditional on `!SKIP_DB_BENCHMARKS`): 1000 `SELECT 1` queries on a pre-connected adapter.
|
||||
- [x] Document placeholder benchmark table in `README.md` under `## Benchmarks`.
|
||||
|
||||
---
|
||||
|
||||
## 13. Docs
|
||||
|
||||
- [x] `src/types/common.md`
|
||||
- [x] `src/connection/connection/connection.md`
|
||||
- [x] `src/adapters/surreal-adapter/surreal-adapter.md`
|
||||
- [x] `src/schema/discovery/discovery.md`
|
||||
- [x] `src/init/init/init.md`
|
||||
- [x] `src/utils/version-detector.md`
|
||||
- [x] Root `universal/database/surrealdb/README.md` — purpose, installation, quick-start, dep table, API symbol list, benchmarks table.
|
||||
|
||||
---
|
||||
|
||||
## 14. Verify and publish
|
||||
|
||||
- [x] Run `bunx turbo lint --filter=@suaveplan/surrealdb` — zero errors.
|
||||
- [x] Run `bunx turbo typecheck --filter=@suaveplan/surrealdb` — zero errors.
|
||||
- [x] Run `bunx turbo test --filter=@suaveplan/surrealdb` — all tests pass.
|
||||
- [x] Run `bunx turbo test:coverage --filter=@suaveplan/surrealdb` — 100% on all touched modules.
|
||||
- [x] Run `bun run docs:check --filter=@suaveplan/surrealdb` — zero errors.
|
||||
- [x] Confirm no `TODO`, `FIXME`, `@deprecated`, untyped `any`, `ts-ignore`, or `.skip` in `src/` or `tests/`.
|
||||
- [x] Confirm `"sideEffects": false` in `package.json`.
|
||||
- [x] Run `bun scripts/publish.ts --package @suaveplan/surrealdb`.
|
||||
- [x] Update `CLAUDE.md` package listing to include `@suaveplan/surrealdb`.
|
||||
- [x] Archive: move `openspec/changes/enterprise-surrealdb/` to `openspec/archive/2026-04-24-enterprise-surrealdb/` and fold spec delta into `openspec/specs/database/spec.md`.
|
||||
Reference in New Issue
Block a user