2.9 KiB
databaseSchema
Purpose
Database-wiring block. Pins whether the plugin needs a database connection, which engines it supports, its current schema version, and how tenant isolation should be expressed. The host's migration runner reads schemaVersion + migrationsDir at install to apply forward-only migrations before plugin code runs.
Features
required: falselets a plugin opt out of database wiring entirelypreferredEngine+compatibleEnginesdescribe the engine compatibility matrixschemaVersionis a non-negative integer (0 = pre-migration)- Three tenant-isolation modes:
row-level,schema,database
Basic Example
import { databaseSchema } from "@suaveplan/api-manifest/schema";
databaseSchema.parse({ required: true, schemaVersion: 0 });
Advanced Example
import { databaseSchema } from "@suaveplan/api-manifest/schema";
const db = databaseSchema.parse({
required: true,
preferredEngine: "postgres",
compatibleEngines: ["postgres", "sqlite", "surrealdb"],
schemaVersion: 7,
migrationsDir: "migrations",
tenantIsolation: "row-level",
tablePrefix: "billing_",
});
API Reference
databaseSchema: z.ZodObject<{ required, preferredEngine?, compatibleEngines?, schemaVersion, migrationsDir?, tenantIsolation?, tablePrefix? }>DatabaseBlock = z.infer<typeof databaseSchema>
Implementation Notes
Engine names are free-form strings rather than an enum so a plugin can declare compatibility with an engine the host doesn't know about yet — the capability resolver decides at boot whether any declared engine is available. schemaVersion is a single integer instead of a range; the host's migration runner walks every step from the journal's last-applied version up to this number. tablePrefix is a hint for engines that support it (Postgres/SQLite); SurrealDB uses table namespaces instead.
Cross-package Notes
This module is part of the @suaveplan/api-manifest Stage-1 contract package. It sits beneath every Stage-2 consumer (api-host, api-loader, the admin CLI, the IDE plugin) and above the foundation packages (@suaveplan/error, @suaveplan/types). The strict-mode top-level rejection of unknown keys means upgrading from manifest v1 to v2 is an OpenSpec-driven event: a new key landing in a consumer manifest is a parse failure rather than a silent drift, which is exactly the contract this stage exists to guarantee.
When the host reloads a plugin without a full restart, every manifest field this module validates is compared against the install-time manifestHash. A mismatch triggers a hard rollback via the RollbackJournal because the host's invariants (route mounts, registered capabilities, declared scopes) are derived from these exact bytes. Treat the schemas and validators here as the contract surface, not just an input filter — downstream code reads manifest.foo.bar and relies on those keys being present, well-typed, and non-undefined in the documented optionality regions.