everything-dev
Version:
A consolidated product package for building Module Federation apps with oRPC APIs.
80 lines (78 loc) • 4.59 kB
JavaScript
const require_core = require('./core.cjs');
const require_driver = require('./driver.cjs');
const require_errors = require('./errors.cjs');
const require_run_migrations = require('./run-migrations.cjs');
let effect = require("effect");
//#region src/db/layer.ts
/**
* The plugin author's whole database surface (ADR 0033): one call that
* acquires the driver against the plugin's lifecycle scope, applies
* migrations on boot (journal-scoped advisory lock, ADR 0019), detects
* drift, and provides the typed drizzle database on the **plugin-owned tag**
* — the swap seam. A different engine, a different drizzle setup, or a
* totally different storage situation is the same interface: provide any
* `Layer` for your own tag and nothing else in the plugin changes.
*
* `namespace: true` (the default) scopes the workspace into the
* `plugin_<slug>` schema on the shared database; `namespace: false` keeps
* the public topology (the api shell, or a dedicated database like auth's).
* `migrations` is the workspace-bound loader Effect (`loadMigrations` from
* this package, instantiated with the workspace's `import.meta.dirname` and
* its bundle's `virtual:drizzle-migrations.sql` module); omit it to skip
* boot migration entirely.
*/
function databaseLayer(tag, url, options) {
return effect.Layer.effect(tag, effect.Effect.gen(function* () {
const { pluginId, schema, migrations, namespace = true } = options;
const slug = require_core.pluginMigrationSlug(pluginId);
const schemaName = namespace ? require_driver.pluginSchemaName(pluginId) : void 0;
const driver = yield* effect.Effect.acquireRelease(effect.Effect.tryPromise({
try: () => require_driver.createDatabaseDriver(url, schema, schemaName),
catch: (cause) => new require_errors.DatabaseError({
stage: "driver",
cause
})
}), (driver) => effect.Effect.tryPromise({
try: () => driver.close(),
catch: (cause) => new require_errors.DatabaseError({
stage: "close",
cause
})
}).pipe(effect.Effect.ignore));
if (!migrations) return driver.db;
const storage = require_core.getMigrationStorage(slug);
const { migrations: loaded, source } = yield* migrations;
if (loaded.length === 0) yield* effect.Effect.logWarning(`[Database] No migrations found (source: ${source}) — schema may be missing`);
else {
const applied = (yield* require_run_migrations.runMigrations(driver.db, loaded, {
journal: storage,
schemaName
})).applied;
if (applied === 0) yield* effect.Effect.logInfo(`[Database] Schema up to date (0 migrations needed, source: ${source})`);
else yield* effect.Effect.logInfo(`[Database] Applied ${applied}/${loaded.length} migration(s) (source: ${source}, journal: ${storage.schema}.${storage.table}, schema: ${schemaName ?? "public"})`);
const drift = yield* require_run_migrations.detectDrift(driver.db, loaded, storage, schemaName);
if (drift.status === "healthy" || drift.status === "untracked-existing-schema") yield* effect.Effect.logInfo(`[Database] Ready`);
else if (drift.status === "drift-safe-repair") {
yield* effect.Effect.logWarning(`[Database] ⚠️ Migration drift detected: ${drift.missingTables.length} expected table(s) missing: ${drift.missingTables.join(", ")}`);
yield* effect.Effect.logWarning(`[Database] Run \`bos db doctor ${storage.slug}\` to diagnose and \`bos db repair ${storage.slug}\` to fix.`);
return yield* new require_errors.DatabaseError({
stage: "migration",
migrationTag: "drift-safe-repair",
cause: /* @__PURE__ */ new Error(`Migration journal has ${drift.appliedHashes} applied hashes but all ${drift.expectedTables.length} expected table(s) are missing. Run \`bos db repair ${storage.slug}\` to reset the migration history and reapply migrations. Missing tables: ${drift.missingTables.join(", ")}`)
});
}
if (drift.status === "drift-manual") {
yield* effect.Effect.logWarning(`[Database] ⚠️ Partial migration drift detected: ${drift.missingTables.length}/${drift.expectedTables.length} expected table(s) missing.`);
return yield* new require_errors.DatabaseError({
stage: "migration",
migrationTag: "drift-manual",
cause: /* @__PURE__ */ new Error(`Partial schema drift — ${drift.missingTables.length}/${drift.expectedTables.length} expected table(s) are missing. Run \`bos db doctor ${storage.slug}\` for details. Manual intervention required. Missing tables: ${drift.missingTables.join(", ")}`)
});
}
}
return driver.db;
}));
}
//#endregion
exports.databaseLayer = databaseLayer;
//# sourceMappingURL=layer.cjs.map