first commit
This commit is contained in:
71
docs/api-stack/api/api-plugin-database/src/plugin/plugin.md
Normal file
71
docs/api-stack/api/api-plugin-database/src/plugin/plugin.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# `plugin`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Exports `createDatabasePlugin`, the top-level factory that produces the `PluginDescriptor` consumed by `@suaveplan/api-plugin`'s `PluginRegistry`. The factory composes every other module in the package — `DatabasePluginOptionsSchema` validates options at the boundary, `ConnectionPool` owns lifecycle and concurrency control, `runMigrations` handles ledger-backed `.surql` application under an advisory lock, the `db` service slot is augmented onto `ServiceRegistry`, and the OTel instrument bundle is shared with the pool. This file is the single integration point — every consumer of the package builds its descriptor through this one function.
|
||||
|
||||
The descriptor binds three lifecycle hooks. `onInit` constructs the pool, eagerly acquires the primary adapter, and registers it under `ServiceRegistry["db"]`. `onReady` runs migrations under advisory lock when `migrations.autoRun` is `true`. `onClose` drains the pool. Construction-time Zod validation surfaces invalid options as `DatabaseError(DATABASE.INVALID_CONFIG)` so misconfigurations fail at registry intake rather than during the first request.
|
||||
|
||||
## Features
|
||||
|
||||
- Zod-validated options at construction time; invalid input surfaces `DATABASE.INVALID_CONFIG`.
|
||||
- Three lifecycle hooks wired against a single `PluginRuntime` cell — no cross-hook globals.
|
||||
- Injectable `adapterFactory` so tests run against a fake adapter without touching surrealdb.
|
||||
- Auto-registers the canonical `db` service slot via module augmentation.
|
||||
- Pool-acquired primary adapter exposed as `db` — every other plugin sees a fully connected `DatabaseAdapter`.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { createDatabasePlugin } from "@suaveplan/api-plugin-database/plugin/plugin";
|
||||
import { createPluginRegistry } from "@suaveplan/api-plugin";
|
||||
|
||||
const registry = createPluginRegistry();
|
||||
registry.register(
|
||||
createDatabasePlugin({ url: "ws://localhost:8000/rpc" })
|
||||
);
|
||||
await registry.initialize();
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import { createDatabasePlugin } from "@suaveplan/api-plugin-database";
|
||||
import { PooledSurrealAdapter } from "@suaveplan/api-plugin-database";
|
||||
|
||||
const plugin = createDatabasePlugin({
|
||||
url: process.env.SURREAL_URL,
|
||||
namespace: "prod",
|
||||
database: "main",
|
||||
username: process.env.SURREAL_USER,
|
||||
password: process.env.SURREAL_PASS,
|
||||
pool: { min: 2, max: 50, idleMs: 60_000, acquireTimeoutMs: 5_000 },
|
||||
retry: { maxAttempts: 5, baseBackoffMs: 100, maxBackoffMs: 10_000, jitter: true },
|
||||
tenancy: { strategy: "namespace-per-tenant" },
|
||||
migrations: {
|
||||
autoRun: true,
|
||||
directory: "./surql",
|
||||
ledgerTable: "_migrations",
|
||||
lockTable: "_migration_lock",
|
||||
leaseMs: 60_000,
|
||||
},
|
||||
adapterFactory: (cfg) => new PooledSurrealAdapter({ ...cfg }),
|
||||
});
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `createDatabasePlugin(options?): PluginDescriptor<DatabasePluginConfigParsed>`
|
||||
|
||||
Returns the plugin descriptor consumed by `PluginRegistry.register`. Throws `DatabaseError(DATABASE.INVALID_CONFIG)` synchronously if `options` fail Zod validation.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- The factory keeps the pool, the primary adapter, and the runtime cell inside a closure so multiple `createDatabasePlugin` calls produce isolated runtimes. There is no module-level global state.
|
||||
- `onReady` calls `getRawClient()` on the primary adapter to obtain the raw `SurrealClientLike` the migration runner needs. Because the primary adapter is acquired in `onInit` and held until `onClose`, the raw client is always live by the time `onReady` runs.
|
||||
- `onClose` releases the primary adapter back to the pool before calling `close()` so the pool's drain phase isn't fighting an `inUse` member. The release is best-effort — `pool.release(adapter)` silently ignores unknown adapters, so multiple shutdown attempts are safe.
|
||||
- The descriptor declares zero `dependencies` — consumers that need the database service register this plugin first.
|
||||
Reference in New Issue
Block a user