UNPKG

everything-dev

Version:

A consolidated product package for building Module Federation apps with oRPC APIs.

204 lines (202 loc) • 7.69 kB
let node_fs = require("node:fs"); let node_path = require("node:path"); //#region src/db/core.ts const DEFAULT_MIGRATION_JOURNAL = { schema: "drizzle", table: "__drizzle_migrations" }; const PER_PLUGIN_ISOLATION = false; function normalizeSlug(name) { return (name.split("/").pop() ?? name).replace(/^@/, "").replace(/[^a-zA-Z0-9_-]/g, "_").replace(/-plugin$/i, "").replace(/-/g, "_").toLowerCase(); } function getMigrationSlug(dir) { if (!dir) return normalizeSlug(process.env.npm_package_name ?? "unknown"); let current = dir; for (let i = 0; i < 10; i++) { const pkgPath = (0, node_path.join)(current, "package.json"); if ((0, node_fs.existsSync)(pkgPath)) try { return normalizeSlug(JSON.parse((0, node_fs.readFileSync)(pkgPath, "utf-8")).name ?? current); } catch { return normalizeSlug(current); } const parent = (0, node_path.dirname)(current); if (parent === current) break; current = parent; } return normalizeSlug(dir); } function getMigrationStorage(slug, options) { const s = normalizeSlug(slug ?? getMigrationSlug()); if (options?.isolated ?? PER_PLUGIN_ISOLATION) return { schema: DEFAULT_MIGRATION_JOURNAL.schema, table: `__drizzle_migrations_${s}`, slug: s }; return { schema: DEFAULT_MIGRATION_JOURNAL.schema, table: DEFAULT_MIGRATION_JOURNAL.table, slug: s }; } /** * Format a JavaScript string array as a PostgreSQL text array literal for use * with Drizzle's `sql` tag. Example return: * `'{"h1","h2"}'::text[]` * * Usage: sql`WHERE col = ANY(${toSqlArray(values)})` * * Drizzle's default parameter binding does not handle array types correctly * with the pg driver (it emits `ANY(($1))` with a single string, which * Postgres rejects as a malformed array literal). */ function toSqlArray(arr) { if (arr.length === 0) return `'{}'::text[]`; return `'{${arr.map((v) => v.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")).map((v) => `"${v}"`).join(",")}}'::text[]`; } function pluginMigrationSlug(key) { return normalizeSlug(key); } function getDatabaseUrlSecretName(slug) { return `${slug.toUpperCase().replace(/-/g, "_")}_DATABASE_URL`; } const DUPLICATE_OBJECT_SQLSTATES = [ "42710", "42701", "42P07" ]; /** * Walk `error` and its `cause` chain (bounded), invoking `visit` on each link. * Postgres driver errors arrive wrapped by drizzle/Effect at varying depths, * so every error-shape predicate below shares this traversal. */ function visitCauses(error, depth, visit) { let current = error; for (let i = 0; i < depth && current; i++) { if (typeof current === "object" && current !== null && visit(current)) return true; current = current?.cause; } return false; } /** * pg_catalog unique indexes that can surface a concurrent-DDL race as SQLSTATE * 23505 instead of a duplicate-object class. When two connections run * `CREATE TABLE <name>` at the same time, the loser fails its insert into * `pg_type` ("duplicate key value violates unique constraint * `pg_type_typname_nsp_index`") rather than seeing 42P07, because the winner's * table is not yet committed. The same shape exists for schemas and other * relations. */ const CONCURRENT_DDL_CONSTRAINTS = /* @__PURE__ */ new Set([ "pg_type_typname_nsp_index", "pg_namespace_nspname_index", "pg_class_relname_nsp_index" ]); /** * Whether a SQLSTATE 23505 unique violation is the concurrent-DDL catalog * collision signature rather than a data-level constraint on a user table. * Data-level violations must keep failing loudly; only the pg_catalog indexes * above are treated as duplicate-DDL tolerance candidates. */ function isConcurrentDdlUniqueViolation(error) { return visitCauses(error, 6, (link) => { const { code, constraint, message } = link; if (code !== "23505") return false; if (typeof constraint === "string" && CONCURRENT_DDL_CONSTRAINTS.has(constraint)) return true; if (typeof message !== "string") return false; for (const name of CONCURRENT_DDL_CONSTRAINTS) if (message.includes(name)) return true; return false; }); } const RETRYABLE_SQLSTATES = /* @__PURE__ */ new Set([ "42P06", "42710", "42701", "42P07", "23505", "40001", "40P01", "55P03" ]); const RETRYABLE_DRIVER_CODES = /* @__PURE__ */ new Set([ "ECONNREFUSED", "ECONNRESET", "EPIPE", "ETIMEDOUT", "ENOTFOUND", "EAI_AGAIN" ]); function matchesRetryableStates(error, states) { return visitCauses(error, 6, (link) => { const code = link.code; if (typeof code !== "string") return false; return states.has(code) || code.startsWith("08") || RETRYABLE_DRIVER_CODES.has(code); }); } /** * Decide whether a failed migration-init statement (schema/journal creation) * is worth retrying. Covers the concurrent `CREATE SCHEMA IF NOT EXISTS` * race (unique violation on `pg_namespace`, duplicate-object errors), * serialization/deadlock errors, and transient connection failures. */ function isRetryableMigrationError(error) { return matchesRetryableStates(error, RETRYABLE_SQLSTATES); } const RETRYABLE_STATEMENT_SQLSTATES = /* @__PURE__ */ new Set([ "40001", "40P01", "55P03" ]); /** * Decide whether a failed migration *statement* (inside its transaction) is * worth retrying. Deliberately narrower than `isRetryableMigrationError`: * duplicate-object classes are tolerated at the SAVEPOINT level, and a 23505 * is either the concurrent-DDL catalog collision (also tolerated) or a * deterministic data-level violation (retrying is pointless) — so only * lock/serialization/transient-connection states justify re-running the * transaction. */ function isRetryableMigrationExecutionError(error) { return matchesRetryableStates(error, RETRYABLE_STATEMENT_SQLSTATES); } const PG_QUERY_QUEUE_DEPRECATION = "client.query() when the client is already executing a query"; let pgWarningFilterInstalled = false; /** * Silence pg's query-queue deprecation warning (fires once per process from * pg-pool's internal dispatch under concurrent boot load — node-postgres#3612, * #3617). Node's default warning handler prints even when user listeners are * attached, so it is removed first; every other warning is re-printed here. */ function suppressPgQueryQueueDeprecation() { if (pgWarningFilterInstalled) return; if (typeof process === "undefined" || typeof process.on !== "function") return; pgWarningFilterInstalled = true; process.removeAllListeners("warning"); process.on("warning", (warning) => { if (warning.name === "DeprecationWarning" && warning.message.includes(PG_QUERY_QUEUE_DEPRECATION)) return; console.error(warning.stack || `${warning.name}: ${warning.message}`); }); } function extractExpectedTables(migrations) { const tables = /* @__PURE__ */ new Set(); const re = /CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?(?:"([^"]+)"\.)?"([^"]+)"/gi; for (const migration of migrations) for (const stmt of migration.sql) for (const match of stmt.matchAll(re)) { const tableName = match[2]; if (tableName) tables.add(tableName); } return [...tables]; } //#endregion exports.DUPLICATE_OBJECT_SQLSTATES = DUPLICATE_OBJECT_SQLSTATES; exports.extractExpectedTables = extractExpectedTables; exports.getDatabaseUrlSecretName = getDatabaseUrlSecretName; exports.getMigrationSlug = getMigrationSlug; exports.getMigrationStorage = getMigrationStorage; exports.isConcurrentDdlUniqueViolation = isConcurrentDdlUniqueViolation; exports.isRetryableMigrationError = isRetryableMigrationError; exports.isRetryableMigrationExecutionError = isRetryableMigrationExecutionError; exports.normalizeSlug = normalizeSlug; exports.pluginMigrationSlug = pluginMigrationSlug; exports.suppressPgQueryQueueDeprecation = suppressPgQueryQueueDeprecation; exports.toSqlArray = toSqlArray; exports.visitCauses = visitCauses; //# sourceMappingURL=core.cjs.map