@nmakarov/cli-toolkit 0.79.0 → 0.81.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/db.js CHANGED
@@ -144,7 +144,7 @@ var CONNECTION_ERROR_CODES = /* @__PURE__ */ new Set([
144
144
  "57P02",
145
145
  "57P03"
146
146
  ]);
147
- var CONNECTION_ERROR_MESSAGE_RE = /connection (terminated|ended|closed|destroyed|reset|refused|not open)|Connection terminated unexpectedly|Client has encountered a connection error|server closed the connection|Cannot use a pool after calling end|This socket has been ended|connect ECONNRESET/i;
147
+ var CONNECTION_ERROR_MESSAGE_RE = /connection (terminated|ended|closed|destroyed|reset|refused|not open)|Connection (terminated|ended) unexpectedly|Client has encountered a connection error|server closed the connection|Cannot use a pool after calling end|This socket has been ended|connect ECONNRESET/i;
148
148
  var Db = class _Db {
149
149
  static async init(context, options = {}) {
150
150
  const buildConfig = async () => {
@@ -412,6 +412,10 @@ var Db = class _Db {
412
412
  this.isConnected = false;
413
413
  this.queriesLog = [];
414
414
  this._reconnectPromise = null;
415
+ this._closed = false;
416
+ this._liveKnex = /* @__PURE__ */ new Set();
417
+ this._reconnectCooldownUntil = 0;
418
+ this._reconnectAcquireTimeoutMs = null;
415
419
  this.config = {
416
420
  testConnection: true,
417
421
  profile: false,
@@ -496,6 +500,9 @@ var Db = class _Db {
496
500
  return null;
497
501
  }
498
502
  async connect() {
503
+ if (this._closed) {
504
+ throw new ParamError("Db: Connection closed");
505
+ }
499
506
  if (this.isConnected && this.knexInstance) {
500
507
  this.logger.warn?.("[Db] Already connected");
501
508
  return;
@@ -511,22 +518,46 @@ var Db = class _Db {
511
518
  connectionString: this.config.connectionString,
512
519
  family: 4
513
520
  };
521
+ const acquireTimeout = this._reconnectAcquireTimeoutMs ?? this.config.acquireConnectionTimeout;
514
522
  this.knexInstance = knex({
515
523
  client,
516
524
  connection: connectionConfig,
517
525
  pool: this.config.pool,
518
- acquireConnectionTimeout: this.config.acquireConnectionTimeout,
526
+ acquireConnectionTimeout: acquireTimeout,
519
527
  ...this.config.ssl && { ssl: this.config.ssl }
520
528
  });
529
+ this._liveKnex.add(this.knexInstance);
530
+ this.knexInstance.on?.("error", (err) => {
531
+ if (this._closed) return;
532
+ this.logger.warn?.(
533
+ `[Db] Connection error (${this.getErrorMessage(err)})`
534
+ );
535
+ });
536
+ if (this._closed) {
537
+ await this._destroyKnex(this.knexInstance, "connect aborted (closed)");
538
+ this.knexInstance = null;
539
+ throw new ParamError("Db: Connection closed");
540
+ }
521
541
  if (this.config.profile) {
522
542
  this.attachProfiler();
523
543
  }
524
544
  if (this.config.testConnection) {
525
545
  await this.testConnection();
526
546
  }
547
+ if (this._closed) {
548
+ await this._destroyKnex(this.knexInstance, "connect aborted (closed)");
549
+ this.knexInstance = null;
550
+ throw new ParamError("Db: Connection closed");
551
+ }
527
552
  this.isConnected = true;
528
553
  this.logger.debug?.(formatDbConnectMessage(this.config.name, this.config.connectionString));
529
554
  } catch (error) {
555
+ const failed = this.knexInstance;
556
+ this.knexInstance = null;
557
+ this.isConnected = false;
558
+ if (failed) {
559
+ await this._destroyKnex(failed, "connect failed");
560
+ }
530
561
  if (error instanceof ParamError) {
531
562
  throw error;
532
563
  }
@@ -534,20 +565,42 @@ var Db = class _Db {
534
565
  throw new ParamError(`Db: Connection failed - ${errorMsg}`);
535
566
  }
536
567
  }
537
- async disconnect() {
538
- if (!this.knexInstance) {
539
- return;
540
- }
568
+ /**
569
+ * Destroy a knex pool without hanging exit on stuck TCP sockets (ETIMEDOUT).
570
+ * @param {import("knex").Knex | null | undefined} knexInst
571
+ * @param {string} [reason]
572
+ * @param {number} [timeoutMs]
573
+ */
574
+ async _destroyKnex(knexInst, reason = "destroy", timeoutMs = 3e3) {
575
+ if (!knexInst || typeof knexInst.destroy !== "function") return;
576
+ this._liveKnex.delete(knexInst);
541
577
  try {
542
- await this.knexInstance.destroy();
543
- this.knexInstance = null;
544
- this.isConnected = false;
545
- this.queriesLog = [];
546
- this.logger.debug?.(formatDbDisconnectMessage(this.config.name, this.config.connectionString));
578
+ await Promise.race([
579
+ knexInst.destroy(),
580
+ new Promise((_, reject) => {
581
+ const t = setTimeout(
582
+ () => reject(new Error(`Db: ${reason} timed out after ${timeoutMs}ms`)),
583
+ timeoutMs
584
+ );
585
+ t.unref?.();
586
+ })
587
+ ]);
547
588
  } catch (error) {
548
- const errorMsg = this.getErrorMessage(error);
549
- this.logger.error?.(`[Db] Error disconnecting: ${errorMsg}`);
550
- throw error;
589
+ this.logger.debug?.(
590
+ `[Db] ${reason}: ${this.getErrorMessage(error)}`
591
+ );
592
+ }
593
+ }
594
+ async disconnect() {
595
+ this._closed = true;
596
+ this.isConnected = false;
597
+ this.knexInstance = null;
598
+ this.queriesLog = [];
599
+ const all = [...this._liveKnex];
600
+ this._liveKnex.clear();
601
+ await Promise.all(all.map((inst) => this._destroyKnex(inst, "disconnect")));
602
+ if (all.length > 0) {
603
+ this.logger.debug?.(formatDbDisconnectMessage(this.config.name, this.config.connectionString));
551
604
  }
552
605
  }
553
606
  /**
@@ -570,27 +623,39 @@ var Db = class _Db {
570
623
  }
571
624
  /**
572
625
  * Destroy the current knex pool and open a new one. Concurrent callers share one attempt.
626
+ * No-ops once disconnect() has closed the handle.
573
627
  */
574
628
  async reconnect() {
629
+ if (this._closed) {
630
+ return;
631
+ }
632
+ if (this._reconnectCooldownUntil && Date.now() < this._reconnectCooldownUntil) {
633
+ return;
634
+ }
575
635
  if (this._reconnectPromise) {
576
636
  await this._reconnectPromise;
577
637
  return;
578
638
  }
579
639
  this._reconnectPromise = (async () => {
640
+ if (this._closed) return;
580
641
  const old = this.knexInstance;
581
642
  this.isConnected = false;
582
643
  this.knexInstance = null;
583
644
  this.queriesLog = [];
584
645
  if (old) {
585
- try {
586
- await old.destroy();
587
- } catch (error) {
588
- this.logger.debug?.(
589
- `[Db] destroy during reconnect: ${this.getErrorMessage(error)}`
590
- );
591
- }
646
+ await this._destroyKnex(old, "destroy during reconnect");
647
+ }
648
+ if (this._closed) return;
649
+ this._reconnectAcquireTimeoutMs = 3e3;
650
+ try {
651
+ await this.connect();
652
+ this._reconnectCooldownUntil = 0;
653
+ } catch (error) {
654
+ this._reconnectCooldownUntil = Date.now() + 5e3;
655
+ throw error;
656
+ } finally {
657
+ this._reconnectAcquireTimeoutMs = null;
592
658
  }
593
- await this.connect();
594
659
  })();
595
660
  try {
596
661
  await this._reconnectPromise;
@@ -599,10 +664,19 @@ var Db = class _Db {
599
664
  }
600
665
  }
601
666
  async reconnectAfterConnectionError(error) {
667
+ if (this._closed) {
668
+ return;
669
+ }
670
+ if (this._reconnectCooldownUntil && Date.now() < this._reconnectCooldownUntil) {
671
+ return;
672
+ }
602
673
  this.logger.warn?.(
603
674
  `[Db] Connection lost (${this.getErrorMessage(error)}) \u2014 reconnecting\u2026`
604
675
  );
605
- await this.reconnect();
676
+ try {
677
+ await this.reconnect();
678
+ } catch {
679
+ }
606
680
  }
607
681
  /**
608
682
  * Run `fn`; on a connection error, reconnect once (by default) and retry `fn`.
@@ -615,10 +689,13 @@ var Db = class _Db {
615
689
  return await fn();
616
690
  } catch (error) {
617
691
  lastError = error;
618
- if (!this.isConnectionError(error) || attempt >= retries) {
692
+ if (this._closed || !this.isConnectionError(error) || attempt >= retries) {
619
693
  throw error;
620
694
  }
621
695
  await this.reconnectAfterConnectionError(error);
696
+ if (this._closed) {
697
+ throw error;
698
+ }
622
699
  }
623
700
  }
624
701
  throw lastError;
@@ -642,10 +719,13 @@ var Db = class _Db {
642
719
  try {
643
720
  return await protoThen.call(builder);
644
721
  } catch (error) {
645
- if (!inst.isConnectionError(error)) {
722
+ if (inst._closed || !inst.isConnectionError(error)) {
646
723
  throw error;
647
724
  }
648
725
  await inst.reconnectAfterConnectionError(error);
726
+ if (inst._closed || !inst.knexInstance) {
727
+ throw error;
728
+ }
649
729
  if (typeof builder.clone === "function") {
650
730
  const retry = builder.clone();
651
731
  retry.client = inst.knexInstance.client;
package/dist/db.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/db/index.js","../src/errors.js","../src/db/ensure.js"],"sourcesContent":["import knex from \"knex\";\nimport { ParamError } from \"../errors.js\";\n\nexport {\n ensureExtension,\n ensureTable,\n ensureIndex,\n ensureSchema,\n ensureSchemaEverywhere,\n} from \"./ensure.js\";\n\nconst KNEX_DEFAULTS = {\n testConnection: true,\n // min: 0 avoids holding idle sockets that go stale during long-running CLIs\n pool: { min: 0, max: 10, idleTimeoutMillis: 30_000 },\n acquireConnectionTimeout: 10000,\n ssl: { rejectUnauthorized: false },\n};\n\n/** Node / pg / knex signals that the socket or pool is dead and a reconnect may help. */\nconst CONNECTION_ERROR_CODES = new Set([\n \"ECONNRESET\",\n \"ECONNREFUSED\",\n \"EPIPE\",\n \"ETIMEDOUT\",\n \"ENOTFOUND\",\n \"EHOSTUNREACH\",\n \"ENETUNREACH\",\n \"ECONNABORTED\",\n \"CONNECTION_ENDED\",\n \"CONNECTION_CLOSED\",\n // PostgreSQL SQLSTATE class 08xxx (connection exception) + admin shutdowns\n \"08000\",\n \"08001\",\n \"08003\",\n \"08004\",\n \"08006\",\n \"08007\",\n \"08P01\",\n \"57P01\",\n \"57P02\",\n \"57P03\",\n]);\n\n// Note: \"Timeout acquiring a connection\" is pool contention (all slots busy),\n// not a dead socket — reconnecting destroys healthy clients and makes it worse.\nconst CONNECTION_ERROR_MESSAGE_RE =\n /connection (terminated|ended|closed|destroyed|reset|refused|not open)|Connection terminated unexpectedly|Client has encountered a connection error|server closed the connection|Cannot use a pool after calling end|This socket has been ended|connect ECONNRESET/i;\n\nexport class Db {\n static async init(context, options = {}) {\n const buildConfig = async () => {\n const defs = {\n dbName: \"string\",\n dbProfile: \"boolean default false\",\n /** Cap knex pool size (default 10). Size ≈ expected concurrency + headroom. */\n dbPoolMax: \"number\",\n };\n const discovered = context?.params?.getAllForModule?.(\"db\", defs) ?? {};\n const merged = { ...discovered, ...options };\n\n let { dbName, dbProfile } = merged;\n let dbConnectionString = options.dbConnectionString ?? options.connectionString;\n let connectionParam = dbConnectionString ? \"options\" : null;\n\n if (!dbConnectionString) {\n const src = context?.args?.getSource?.(\"dbConnectionString\");\n if (src === \"cli\" || src === \"overrides\" || src === \"config\") {\n dbConnectionString = await context.params.get(\"dbConnectionString\", \"string\");\n connectionParam = \"dbConnectionString\";\n }\n }\n\n if (!dbConnectionString && dbName && /^(postgresql|mysql):\\/\\//.test(dbName)) {\n dbConnectionString = dbName;\n dbName = undefined;\n }\n\n if (!dbConnectionString && dbName) {\n const paramName = `dbConnectionString${capitalizeFirstLetter(dbName)}`;\n dbConnectionString = await context.params.get(paramName, \"string\");\n connectionParam = paramName;\n if (!dbConnectionString) {\n throw new ParamError(\n `Db: cannot find dbConnectionString for dbName=\"${dbName}\" (looked for param \"${paramName}\")`\n );\n }\n }\n\n if (!dbConnectionString) {\n dbConnectionString = await context.params.get(\"dbConnectionString\", \"string\");\n if (dbConnectionString) {\n connectionParam = \"dbConnectionString\";\n }\n }\n\n if (!dbConnectionString) {\n if (!dbName) {\n const env = context?.args?.env;\n // Never silently fall back to \"local\" on production/stage — that\n // masked missing DB_NAME_* / --dbName as a localhost:6032 connect.\n if (env && String(env).toLowerCase() !== \"local\") {\n throw new ParamError(\n `Db: dbName not set for env=\"${env}\" (set --dbName or DB_NAME_${String(env).toUpperCase()})`\n );\n }\n dbName = \"local\";\n }\n const paramName = `dbConnectionString${capitalizeFirstLetter(dbName)}`;\n dbConnectionString = await context.params.get(paramName, \"string\");\n connectionParam = paramName;\n if (!dbConnectionString) {\n throw new ParamError(\n `Db: cannot find dbConnectionString for dbName=\"${dbName}\" (looked for param \"${paramName}\")`\n );\n }\n }\n\n const displayName = resolveDbDisplayName(\n dbName,\n connectionParam,\n context?.args?.env,\n merged.name\n );\n\n const poolMaxRaw = merged.dbPoolMax ?? merged.pool?.max;\n const poolMax = Number(poolMaxRaw);\n const pool = {\n ...KNEX_DEFAULTS.pool,\n ...(merged.pool && typeof merged.pool === \"object\" ? merged.pool : {}),\n };\n if (Number.isFinite(poolMax) && poolMax >= 1) {\n pool.max = Math.floor(poolMax);\n }\n\n return {\n ...KNEX_DEFAULTS,\n connectionString: dbConnectionString,\n name: displayName,\n profile: !!dbProfile,\n logger: context.logger,\n pool,\n ...(merged.acquireConnectionTimeout != null\n ? { acquireConnectionTimeout: merged.acquireConnectionTimeout }\n : {}),\n };\n };\n\n const config = context?.params?.runWithModuleAsync\n ? await context.params.runWithModuleAsync(\"db\", buildConfig)\n : await buildConfig();\n\n return dbConnect(context, config);\n }\n\n /**\n * Initialize a SIBLING database handler: a database that lives on the same\n * server with the same credentials/options as an existing (\"base\") one, and\n * differs only by its database name. Typical use: a per-tenant / per-subject\n * database alongside a main database that keeps the shared tables.\n *\n * context.db = await Db.init(context); // main\n * const sub = await Db.initSibling(context, \"src_bright\"); // sibling\n *\n * LOCATION-AGNOSTIC BY DESIGN — the call gracefully falls back to the main\n * database, so callers can use it for all subject data without knowing what\n * has been migrated where:\n * - empty `siblingName` → the main handler (same as Db.init)\n * - sibling DB does not exist yet → the main handler (data not migrated;\n * it still lives in the main database)\n * Callers that must not fall back can check `handler === context.db`.\n *\n * Connection string resolution for an actual sibling, in order:\n * 1. Explicit override — param `dbConnectionStringSib<SiblingName>` (env\n * `DB_CONNECTION_STRING_SIB_<SIBLING_NAME>`, e.g. `src_bright` →\n * `DB_CONNECTION_STRING_SIB_SRC_BRIGHT`). Nobody needs this on day\n * one; it is the escape hatch for when a sibling later moves to its\n * own server — one env var, no code changes (the `SIB_` namespace\n * both overrides the connection and declares that the sibling\n * exists, so it never falls back to main).\n * 2. Derived — take the base connection string and swap the database\n * name (after confirming the database exists on that server). The\n * base is `options.baseDb` (a Db handler), then\n * `options.baseConnectionString`, then `context.db`.\n *\n * Handlers are cached per name on the context (`context.siblingDbs`), so\n * any number of components asking for the same sibling share one pool —\n * including the \"falls back to main\" answer, which is remembered for the\n * lifetime of the process (a mid-run migration is picked up on restart).\n * Disconnect is registered via `context.registerCleanup`, same as the\n * main handler.\n *\n * @param {object} context - context with params/logger (and usually .db)\n * @param {string} [siblingName] - the sibling's database name (e.g. \"src_bright\")\n * @param {object} [options] - { baseDb, baseConnectionString, dbProfile }\n * @returns {Promise<Db>} connected handler (same proxy shape as Db.init)\n */\n static async initSibling(context, siblingName, options = {}) {\n // Empty name → the main database, so call sites stay location-agnostic.\n if (!siblingName) {\n return resolveMainHandler(context, options);\n }\n if (!/^[a-zA-Z0-9_]+$/.test(siblingName)) {\n throw new ParamError(\n `Db.initSibling: invalid sibling database name \"${siblingName}\" (letters, digits and _ only)`\n );\n }\n\n if (!context.siblingDbs) {\n context.siblingDbs = new Map();\n }\n const cached = context.siblingDbs.get(siblingName);\n if (cached) {\n return cached;\n }\n\n // 1. explicit override: dbConnectionStringSib<SiblingName> param / env var.\n // Its presence also DECLARES the sibling (it may live on another server),\n // so the existence check below is skipped.\n const overrideParam = `dbConnectionStringSib${camelizeDbName(siblingName)}`;\n let connectionString = await context?.params?.get?.(overrideParam, \"string\");\n if (connectionString) {\n context.logger?.debug?.(\n `[Db] sibling \"${siblingName}\": using override param \"${overrideParam}\"`\n );\n } else {\n // 2. derive from the base connection string\n const baseHandle = options.baseDb ?? context.db;\n const base =\n baseHandle?.config?.connectionString ?? options.baseConnectionString;\n if (!base) {\n throw new ParamError(\n `Db.initSibling: no base connection to derive \"${siblingName}\" from — ` +\n `init the main Db first (context.db = await Db.init(context)), ` +\n `or pass options.baseDb / options.baseConnectionString, ` +\n `or set the ${overrideParam} param (env ${toEnvKey(overrideParam)})`\n );\n }\n\n // Not migrated yet? Fall back to the main database so the caller's\n // code works the same before and after the split.\n const exists = await databaseExistsOnServer(baseHandle, base, siblingName);\n if (!exists) {\n context.logger?.debug?.(\n `[Db] sibling \"${siblingName}\" does not exist — falling back to the main database`\n );\n const main = await resolveMainHandler(context, options);\n context.siblingDbs.set(siblingName, main);\n return main;\n }\n\n connectionString = replaceDatabaseName(base, siblingName);\n context.logger?.debug?.(\n `[Db] sibling \"${siblingName}\": derived from base (${formatConnectionEndpoint(base) ?? \"?\"})`\n );\n }\n\n const config = {\n ...KNEX_DEFAULTS,\n connectionString,\n name: siblingName,\n profile: !!options.dbProfile,\n logger: context.logger,\n };\n\n const handler = await dbConnect(context, config);\n context.siblingDbs.set(siblingName, handler);\n return handler;\n }\n\n /**\n * Discover the sibling databases that are \"currently in use\", by name.\n * Two sources, merged (env wins on duplicates):\n *\n * 1. ENV-DECLARED — every `DB_CONNECTION_STRING_SIB_<NAME>` env var\n * (the dedicated `SIB_` namespace) whose decoded name matches. This\n * covers siblings that moved to their own server: the same var that\n * overrides the connection also *registers* the database, so `.env`\n * stays the single convenient list.\n * 2. SAME-SERVER SCAN — `SELECT datname FROM pg_database` on the base\n * server (PostgreSQL only), filtered the same way.\n *\n * The caller says what \"matches\": `{ prefix: \"src_\" }` or\n * `{ match: /^src_/ }` — the toolkit does not guess a naming convention.\n *\n * @param {object} context - needs context.db (or options.baseDb) for the server scan\n * @param {{ prefix?: string, match?: RegExp, baseDb?: object, env?: object }} options\n * @returns {Promise<Array<{ name: string, origin: \"env\"|\"server\" }>>} sorted by name\n */\n static async discoverSiblings(context, options = {}) {\n const { prefix, match, env = process.env } = options;\n if (!prefix && !match) {\n throw new ParamError(`Db.discoverSiblings: pass { prefix: \"...\" } or { match: /.../ }`);\n }\n const matches = match instanceof RegExp ? (n) => match.test(n) : (n) => n.startsWith(prefix);\n\n const found = new Map();\n\n // 1. env-declared siblings (possibly on other servers) — SIB_ namespace\n for (const key of Object.keys(env)) {\n const m = /^DB_CONNECTION_STRING_SIB_(.+)$/.exec(key);\n if (!m || !env[key]) continue;\n const name = m[1].toLowerCase();\n if (matches(name)) {\n found.set(name, \"env\");\n }\n }\n\n // 2. same-server scan (PostgreSQL)\n const base = options.baseDb ?? context?.db;\n if (base) {\n const connectionString = String(base.config?.connectionString ?? \"\");\n if (connectionString.startsWith(\"postgresql\")) {\n const { rows } = await base.raw(\n \"SELECT datname FROM pg_database WHERE datistemplate = false\",\n );\n for (const { datname } of rows) {\n if (matches(datname) && !found.has(datname)) {\n found.set(datname, \"server\");\n }\n }\n } else {\n context?.logger?.warn?.(\n \"[Db] discoverSiblings: server scan supported for PostgreSQL only; using env-declared siblings\",\n );\n }\n }\n\n return [...found]\n .map(([name, origin]) => ({ name, origin }))\n .sort((a, b) => a.name.localeCompare(b.name));\n }\n\n /**\n * Discover + connect: one handler per active sibling (cached, pooled —\n * see initSibling). Pass `includeMain: true` to get `[context.db, ...]`,\n * which is the usual shape for \"apply this DDL everywhere\" loops:\n *\n * const dbs = await Db.initAllSiblings(context, { prefix: \"src_\", includeMain: true });\n * await ensureSchemaEverywhere(dbs, spec, { logger: context.logger });\n *\n * @param {object} context\n * @param {{ prefix?: string, match?: RegExp, includeMain?: boolean, baseDb?: object, env?: object }} options\n * @returns {Promise<Function[]>} connected handlers\n */\n static async initAllSiblings(context, options = {}) {\n const discovered = await Db.discoverSiblings(context, options);\n const handlers = [];\n for (const { name } of discovered) {\n handlers.push(await Db.initSibling(context, name, options));\n }\n return options.includeMain && context.db ? [context.db, ...handlers] : handlers;\n }\n\n constructor(config) {\n if (!config || !config.connectionString) {\n throw new ParamError(\"Db: connectionString is required\");\n }\n\n this.knexInstance = null;\n this.isConnected = false;\n this.queriesLog = [];\n this._reconnectPromise = null;\n\n this.config = {\n testConnection: true,\n profile: false,\n pool: { min: 0, max: 10, idleTimeoutMillis: 30_000 },\n acquireConnectionTimeout: 10000,\n ssl: { rejectUnauthorized: false },\n logger: console,\n ...config,\n };\n\n this.logger = this.config.logger;\n\n const instance = this;\n const callableWrapper = function () {\n throw new Error(\"This should never be called directly\");\n };\n callableWrapper._instance = instance;\n\n return new Proxy(callableWrapper, {\n apply: (target, _thisArg, argumentsList) => {\n const inst = target._instance;\n if (!inst.knexInstance) {\n throw new Error(\"Db: Not connected. Call connect() first.\");\n }\n return inst.wrapQueryBuilder(inst.knexInstance(...argumentsList));\n },\n get: (target, prop) => {\n if (prop === \"_instance\") {\n return target._instance;\n }\n\n const inst = target._instance;\n\n const ownMethods = [\n \"connect\",\n \"disconnect\",\n \"reconnect\",\n \"testConnection\",\n \"tableExists\",\n \"raw\",\n \"withConnectionRetry\",\n \"isConnectionError\",\n \"getQueryLog\",\n \"getKnex\",\n \"isConnectedToDb\",\n \"getErrorMessage\",\n \"detectClient\",\n \"attachProfiler\",\n ];\n\n if (prop in inst) {\n const value = inst[prop];\n if (typeof value === \"function\" && ownMethods.includes(prop)) {\n return value.bind(inst);\n }\n if (typeof value !== \"function\") {\n return value;\n }\n }\n\n if (inst.knexInstance) {\n const knexProp = inst.knexInstance[prop];\n if (typeof knexProp === \"function\") {\n if (prop === \"raw\") {\n return (...args) => inst.raw(...args);\n }\n return knexProp.bind(inst.knexInstance);\n }\n return knexProp;\n }\n\n if (prop in inst) {\n const method = inst[prop];\n if (typeof method === \"function\") {\n return method.bind(inst);\n }\n return method;\n }\n\n return undefined;\n },\n });\n }\n\n detectClient(connectionString) {\n if (connectionString.match(/^postgresql/)) {\n return \"pg\";\n }\n if (connectionString.match(/^mysql/)) {\n return \"mysql2\";\n }\n return null;\n }\n\n async connect() {\n if (this.isConnected && this.knexInstance) {\n this.logger.warn?.(\"[Db] Already connected\");\n return;\n }\n\n const client = this.detectClient(this.config.connectionString);\n if (!client) {\n throw new ParamError(\n \"Db: Cannot determine client type from connection string. Expected postgresql:// or mysql://\"\n );\n }\n\n try {\n const connectionConfig = {\n connectionString: this.config.connectionString,\n family: 4,\n };\n\n this.knexInstance = knex({\n client,\n connection: connectionConfig,\n pool: this.config.pool,\n acquireConnectionTimeout: this.config.acquireConnectionTimeout,\n ...(this.config.ssl && { ssl: this.config.ssl }),\n });\n\n if (this.config.profile) {\n this.attachProfiler();\n }\n\n if (this.config.testConnection) {\n await this.testConnection();\n }\n\n this.isConnected = true;\n this.logger.debug?.(formatDbConnectMessage(this.config.name, this.config.connectionString));\n } catch (error) {\n if (error instanceof ParamError) {\n throw error;\n }\n const errorMsg = this.getErrorMessage(error);\n throw new ParamError(`Db: Connection failed - ${errorMsg}`);\n }\n }\n\n async disconnect() {\n if (!this.knexInstance) {\n return;\n }\n\n try {\n await this.knexInstance.destroy();\n this.knexInstance = null;\n this.isConnected = false;\n this.queriesLog = [];\n this.logger.debug?.(formatDbDisconnectMessage(this.config.name, this.config.connectionString));\n } catch (error) {\n const errorMsg = this.getErrorMessage(error);\n this.logger.error?.(`[Db] Error disconnecting: ${errorMsg}`);\n throw error;\n }\n }\n\n /**\n * True when the error indicates a dead socket / pool that a fresh connect may fix.\n * Safe to call as `Db.prototype.isConnectionError(err)` or via a connected handle.\n */\n isConnectionError(error) {\n if (!error) {\n return false;\n }\n\n if (error instanceof AggregateError && Array.isArray(error.errors)) {\n return error.errors.some((e) => this.isConnectionError(e));\n }\n\n const code = error.code ?? error.errno;\n if (code != null && CONNECTION_ERROR_CODES.has(String(code))) {\n return true;\n }\n\n const msg = error instanceof Error ? error.message : String(error);\n return CONNECTION_ERROR_MESSAGE_RE.test(msg);\n }\n\n /**\n * Destroy the current knex pool and open a new one. Concurrent callers share one attempt.\n */\n async reconnect() {\n if (this._reconnectPromise) {\n await this._reconnectPromise;\n return;\n }\n\n this._reconnectPromise = (async () => {\n const old = this.knexInstance;\n this.isConnected = false;\n this.knexInstance = null;\n this.queriesLog = [];\n\n if (old) {\n try {\n await old.destroy();\n } catch (error) {\n this.logger.debug?.(\n `[Db] destroy during reconnect: ${this.getErrorMessage(error)}`\n );\n }\n }\n\n await this.connect();\n })();\n\n try {\n await this._reconnectPromise;\n } finally {\n this._reconnectPromise = null;\n }\n }\n\n async reconnectAfterConnectionError(error) {\n this.logger.warn?.(\n `[Db] Connection lost (${this.getErrorMessage(error)}) — reconnecting…`\n );\n await this.reconnect();\n }\n\n /**\n * Run `fn`; on a connection error, reconnect once (by default) and retry `fn`.\n * `fn` should look up `this.knexInstance` each call so the retry uses the new client.\n */\n async withConnectionRetry(fn, { retries = 1 } = {}) {\n let lastError;\n for (let attempt = 0; attempt <= retries; attempt++) {\n try {\n return await fn();\n } catch (error) {\n lastError = error;\n if (!this.isConnectionError(error) || attempt >= retries) {\n throw error;\n }\n await this.reconnectAfterConnectionError(error);\n }\n }\n throw lastError;\n }\n\n /**\n * Wrap a knex QueryBuilder / Raw so that awaiting it retries once after reconnect\n * when the first attempt dies with a connection error.\n */\n wrapQueryBuilder(builder) {\n if (!builder || typeof builder.then !== \"function\" || builder.__dbReconnectWrapped) {\n return builder;\n }\n\n builder.__dbReconnectWrapped = true;\n const inst = this;\n const protoThen = Object.getPrototypeOf(builder)?.then;\n if (typeof protoThen !== \"function\") {\n return builder;\n }\n\n builder.then = function (onFulfilled, onRejected) {\n const run = async () => {\n try {\n return await protoThen.call(builder);\n } catch (error) {\n if (!inst.isConnectionError(error)) {\n throw error;\n }\n await inst.reconnectAfterConnectionError(error);\n\n if (typeof builder.clone === \"function\") {\n const retry = builder.clone();\n retry.client = inst.knexInstance.client;\n return await protoThen.call(retry);\n }\n\n if (typeof builder.toSQL === \"function\" && inst.knexInstance) {\n const sql = builder.toSQL();\n const statements = Array.isArray(sql) ? sql : [sql];\n let last;\n for (const stmt of statements) {\n last = await inst.knexInstance.raw(stmt.sql, stmt.bindings);\n }\n return last;\n }\n\n throw error;\n }\n };\n return run().then(onFulfilled, onRejected);\n };\n\n return builder;\n }\n\n /** knex.raw with auto-reconnect on dead connections. */\n raw(...args) {\n if (!this.knexInstance) {\n throw new Error(\"Db: Not connected. Call connect() first.\");\n }\n return this.wrapQueryBuilder(this.knexInstance.raw(...args));\n }\n\n getErrorMessage(error) {\n if (error instanceof AggregateError) {\n const errors = error.errors || [];\n\n if (errors.length > 0) {\n const firstError = errors[0];\n const firstErrorMsg =\n firstError instanceof Error ? firstError.message : String(firstError);\n\n const allSimilar = errors.every((e) => {\n const msg = e instanceof Error ? e.message : String(e);\n const codeMatch = msg.match(/^(\\w+)\\s/);\n const firstCodeMatch = firstErrorMsg.match(/^(\\w+)\\s/);\n return codeMatch && firstCodeMatch && codeMatch[1] === firstCodeMatch[1];\n });\n\n if (allSimilar && errors.length > 1) {\n const addresses = errors\n .map((e) => {\n const msg = e instanceof Error ? e.message : String(e);\n const addrMatch = msg.match(/([:\\d.]+:\\d+)/);\n return addrMatch ? addrMatch[1] : null;\n })\n .filter(Boolean);\n\n if (addresses.length > 0) {\n const codeMatch = firstErrorMsg.match(/^(\\w+)\\s/);\n const code = codeMatch ? codeMatch[1] : \"Connection error\";\n return `${code} (tried: ${addresses.join(\", \")})`;\n }\n }\n\n const uniqueMessages = [\n ...new Set(\n errors.map((e) => (e instanceof Error ? e.message : String(e)))\n ),\n ];\n\n if (uniqueMessages.length === 1) {\n return uniqueMessages[0];\n }\n\n return uniqueMessages.join(\"; \");\n }\n\n return error.message || \"Multiple errors occurred\";\n }\n\n if (error instanceof Error) {\n const code = error.code;\n if (code) {\n return `${code}: ${error.message || String(error)}`;\n }\n return error.message || String(error);\n }\n\n if (typeof error === \"string\") {\n return error;\n }\n\n if (error && typeof error === \"object\" && \"message\" in error) {\n const msg = String(error.message);\n const code = error.code;\n if (code) {\n return `${code}: ${msg}`;\n }\n return msg;\n }\n\n return String(error) || \"Unknown error\";\n }\n\n async testConnection() {\n if (!this.knexInstance) {\n throw new Error(\"Db: Not connected. Call connect() first.\");\n }\n\n try {\n const result = await this.knexInstance.raw(\"SELECT 2+3 AS result\");\n const isOk = result.rows?.[0]?.result === 5 || result[0]?.[0]?.result === 5;\n this.logger.debug?.(`[Db] Connection test: ${isOk ? \"OK\" : \"FAILED\"}`);\n return isOk;\n } catch (error) {\n const errorMsg = this.getErrorMessage(error);\n this.logger.error?.(`[Db] Connection test failed: ${errorMsg}`);\n throw new ParamError(`Db: Connection test failed - ${errorMsg}`);\n }\n }\n\n attachProfiler() {\n if (!this.knexInstance) {\n return;\n }\n\n this.queriesLog = [];\n this.knexInstance.queriesLog = this.queriesLog;\n\n // Knex emits fresh Object.assign(...) copies on \"query\" and \"query-response\",\n // so __startTime on the query object does not survive — track per-connection FIFO.\n const startsByConnection = new Map();\n\n const pushStart = (query) => {\n const uid = query?.__knexUid ?? \"\";\n if (!startsByConnection.has(uid)) {\n startsByConnection.set(uid, []);\n }\n startsByConnection.get(uid).push(process.hrtime());\n };\n\n const popStart = (query) => {\n const uid = query?.__knexUid ?? \"\";\n const stack = startsByConnection.get(uid);\n if (!stack?.length) {\n return null;\n }\n return stack.pop();\n };\n\n const isTimeoutError = (error) =>\n error?.name === \"KnexTimeoutError\" ||\n /query timeout|timeout exceeded/i.test(String(error?.message ?? \"\"));\n\n const logQueryEntry = (query, start, { error } = {}) => {\n let executionTimeMs;\n if (start) {\n const [seconds, nanoseconds] = process.hrtime(start);\n executionTimeMs = (seconds * 1000 + nanoseconds / 1e6).toFixed(2);\n } else if (error?.timeout != null) {\n executionTimeMs = Number(error.timeout).toFixed(2);\n } else {\n executionTimeMs = \"?\";\n }\n\n let status = \"ok\";\n if (error) {\n status = isTimeoutError(error) ? \"timeout\" : \"error\";\n }\n\n const logEntry = {\n sql: query?.sql,\n bindings: query?.bindings || [],\n executionTimeMs,\n status,\n };\n if (error) {\n logEntry.error = error.message ?? String(error);\n }\n\n this.queriesLog.push(logEntry);\n const suffix = error ? ` | ${status}: ${logEntry.error}` : \"\";\n this.logger.debug?.(\n `[Db] Query: ${query?.sql} | Duration: ${executionTimeMs}ms${suffix}`,\n );\n };\n\n const handleQueryError = (error, query) => {\n const start = popStart(query);\n logQueryEntry(query, start, { error });\n this.logger.error?.(`[Db] Query failed: ${query?.sql}`, error);\n };\n\n this.knexInstance.on(\"query\", (query) => {\n pushStart(query);\n });\n\n this.knexInstance.on(\"query-response\", (_response, query) => {\n const start = popStart(query);\n if (!start) {\n return;\n }\n logQueryEntry(query, start);\n });\n\n this.knexInstance.on(\"query-error\", (error, query) => {\n handleQueryError(error, query);\n });\n\n // Builder queries emit \"query\" / \"query-error\" on the builder, not always on client.\n const hookBuilder = (builder) => {\n if (!builder || builder.__dbProfilerHooked) {\n return;\n }\n builder.__dbProfilerHooked = true;\n builder.on(\"query\", pushStart);\n builder.on(\"query-error\", handleQueryError);\n };\n\n const client = this.knexInstance.client;\n if (client && !client.__dbProfilerPatched) {\n client.__dbProfilerPatched = true;\n if (typeof client.queryBuilder === \"function\") {\n const origQueryBuilder = client.queryBuilder.bind(client);\n client.queryBuilder = (...args) => {\n const builder = origQueryBuilder(...args);\n hookBuilder(builder);\n return builder;\n };\n }\n }\n }\n\n getQueryLog() {\n return [...this.queriesLog];\n }\n\n async tableExists(tableName) {\n if (!this.knexInstance) {\n throw new Error(\"Db: Not connected. Call connect() first.\");\n }\n\n try {\n return await this.withConnectionRetry(() =>\n this.knexInstance.schema.hasTable(tableName)\n );\n } catch (error) {\n this.logger.error?.(`[Db] Error checking table existence: ${error.message}`);\n throw error;\n }\n }\n\n getKnex() {\n if (!this.knexInstance) {\n throw new Error(\"Db: Not connected. Call connect() first.\");\n }\n return this.knexInstance;\n }\n\n isConnectedToDb() {\n return this.isConnected && this.knexInstance !== null;\n }\n}\n\nfunction capitalizeFirstLetter(str) {\n return str.charAt(0).toUpperCase() + str.slice(1);\n}\n\n/**\n * The main database handler, for initSibling's fallbacks: the base handle when\n * one was passed, otherwise `context.db` (initialized on demand, so an\n * initSibling-only script still works).\n */\nasync function resolveMainHandler(context, options = {}) {\n if (options.baseDb) {\n return options.baseDb;\n }\n if (!context.db) {\n context.db = await Db.init(context);\n }\n return context.db;\n}\n\n/**\n * Does `databaseName` exist on the base server? Checked via an existing handle\n * when available (no extra connection), else a short-lived one. Non-PostgreSQL\n * bases skip the check (returns true — connection will tell).\n */\nasync function databaseExistsOnServer(baseHandle, baseConnectionString, databaseName) {\n if (!String(baseConnectionString).startsWith(\"postgresql\")) {\n return true;\n }\n const query = \"SELECT 1 FROM pg_database WHERE datname = ?\";\n if (baseHandle) {\n const { rows } = await baseHandle.raw(query, [databaseName]);\n return rows.length > 0;\n }\n const shortLived = knex({\n client: \"pg\",\n connection: { connectionString: baseConnectionString },\n pool: { min: 0, max: 1 },\n });\n try {\n const { rows } = await shortLived.raw(query, [databaseName]);\n return rows.length > 0;\n } finally {\n await shortLived.destroy();\n }\n}\n\n/**\n * Database name → camelCase param suffix: \"src_bright\" → \"SrcBright\",\n * so the override param becomes dbConnectionStringSibSrcBright\n * (env DB_CONNECTION_STRING_SIB_SRC_BRIGHT).\n */\nfunction camelizeDbName(name) {\n return name\n .split(/[_-]+/)\n .filter(Boolean)\n .map(capitalizeFirstLetter)\n .join(\"\");\n}\n\n/** camelCase param name → its SNAKE_CASE env var (for error messages only). */\nfunction toEnvKey(key) {\n return key.replace(/([A-Z])/g, \"_$1\").toUpperCase();\n}\n\n/**\n * Replace the database name in a connection string, keeping everything else\n * (credentials, host, port, query options like sslmode) intact.\n * Exported for reuse (e.g. database-splitting tools) and tests.\n */\nexport function replaceDatabaseName(connectionString, databaseName) {\n let url;\n try {\n url = new URL(connectionString);\n } catch {\n throw new ParamError(\n `Db: cannot parse connection string to derive a sibling database from it`\n );\n }\n url.pathname = `/${databaseName}`;\n return url.toString();\n}\n\nfunction resolveDbDisplayName(dbName, connectionParam, argsEnv, mergedName) {\n if (dbName) {\n return dbName;\n }\n if (mergedName) {\n return mergedName;\n }\n if (\n connectionParam?.startsWith(\"dbConnectionString\") &&\n connectionParam.length > \"dbConnectionString\".length\n ) {\n return connectionParam.slice(\"dbConnectionString\".length).toLowerCase();\n }\n if (connectionParam === \"dbConnectionString\" && argsEnv) {\n return argsEnv;\n }\n return undefined;\n}\n\nfunction formatDbConnectMessage(name, connectionString) {\n const endpointSuffix = formatConnectionEndpointSuffix(connectionString);\n if (name) {\n return `[Db] Connected to database \"${name}\"${endpointSuffix}`;\n }\n return `[Db] Connected${endpointSuffix}`;\n}\n\nfunction formatDbDisconnectMessage(name, connectionString) {\n const endpointSuffix = formatConnectionEndpointSuffix(connectionString);\n if (name) {\n return `[Db] Disconnected from database \"${name}\"${endpointSuffix}`;\n }\n return `[Db] Disconnected${endpointSuffix}`;\n}\n\nfunction formatDbInstanceMessage(action, name) {\n if (name) {\n return `[Db] instance \"${name}\" ${action}`;\n }\n return `[Db] instance ${action}`;\n}\n\nfunction formatConnectionEndpointSuffix(connectionString) {\n const endpoint = formatConnectionEndpoint(connectionString);\n return endpoint ? ` (${endpoint})` : \"\";\n}\n\nfunction formatConnectionEndpoint(connectionString) {\n try {\n const url = new URL(connectionString);\n const host = url.hostname;\n if (!host) {\n return null;\n }\n\n let port = url.port;\n if (!port) {\n if (url.protocol === \"postgresql:\") {\n port = \"5432\";\n } else if (url.protocol === \"mysql:\") {\n port = \"3306\";\n }\n }\n\n return port ? `${host}:${port}` : host;\n } catch {\n return null;\n }\n}\n\nasync function dbConnect(context, config) {\n try {\n const db = new Db(config);\n\n context.registerCleanup(async () => {\n await db.disconnect();\n context.logger.debug?.(formatDbInstanceMessage(\"disconnected\", config.name));\n });\n\n await db.connect();\n\n context.logger.debug?.(formatDbInstanceMessage(\"initialized\", config.name));\n\n return db;\n } catch (error) {\n if (error instanceof ParamError) {\n throw error;\n }\n const errorMsg = error instanceof Error ? error.message : String(error);\n throw new ParamError(`[Db] connect error: ${errorMsg}`);\n }\n}\n","/**\n * Error classes for the CLI toolkit\n */\n\nexport class FrameworkError extends Error {\n constructor(message) {\n super(message);\n this.name = \"FrameworkError\";\n }\n}\n\nexport class ParamError extends FrameworkError {\n constructor(message) {\n super(message);\n this.name = \"ParamError\";\n }\n}\n\nexport class InitError extends FrameworkError {\n constructor(message) {\n super(message);\n this.name = \"InitError\";\n }\n}\n\nexport class CriticalRequestError extends FrameworkError {\n constructor(message) {\n super(message);\n this.name = \"CriticalRequestError\";\n }\n}\n\nexport class ControlFlowError extends Error {\n constructor(message) {\n super(message);\n this.name = \"ControlFlowError\";\n }\n}\n\nexport class HttpClientError extends FrameworkError {\n constructor(message, cause) {\n super(message);this.cause = cause;;\n this.name = \"HttpClientError\";\n }\n}\n\nexport class FileDatabaseError extends FrameworkError {\n constructor(message) {\n super(message);\n this.name = \"FileDatabaseError\";\n }\n}\n\n","/**\n * Declarative, idempotent DDL — \"make sure this schema exists\" helpers.\n *\n * Components describe the schema they need (tables, columns, indexes,\n * extensions) once, as data; `ensureSchema` diffs that spec against a live\n * database and applies only what's missing:\n *\n * - table missing → CREATE TABLE with all columns + indexes\n * - table there, column not → ALTER TABLE ADD COLUMN (never drops/changes)\n * - index/unique missing → CREATE [UNIQUE] INDEX IF NOT EXISTS\n * - extension missing → CREATE EXTENSION IF NOT EXISTS\n *\n * Because the input is a spec (not imperative code), the same call can be\n * repeated over any number of databases — the main one and every sibling —\n * and each gets exactly the DDL it lacks. See Db.initSibling /\n * Db.discoverSiblings for getting those handles.\n *\n * Spec shape:\n *\n * {\n * extensions: [\"uuid-ossp\"],\n * tables: {\n * my_table: {\n * columns: {\n * id: (t, db) => t.uuid(\"id\").primary().defaultTo(db.raw(\"uuid_generate_v4()\")),\n * name: (t) => t.text(\"name\").notNullable(),\n * },\n * indexes: [\n * { columns: [\"name\"], name: \"my_table_name_idx\" },\n * { columns: [\"a\", \"b\"], name: \"my_table_ab_uniq\", unique: true },\n * ],\n * },\n * },\n * }\n *\n * Every function accepts `{ dryRun: true }` and then only *reports* what it\n * would do (returned in the report, logged when a logger is given) without\n * touching the database.\n */\n\n/** @typedef {{ columns: Record<string, Function>, indexes?: Array<{ columns: string[], name: string, unique?: boolean }> }} TableSpec */\n/** @typedef {{ extensions?: string[], tables?: Record<string, TableSpec> }} SchemaSpec */\n\nconst dbLabel = (db) => db?.config?.name ?? \"db\";\n\n/**\n * CREATE EXTENSION IF NOT EXISTS (PostgreSQL). No-op report entry on dryRun.\n *\n * @param {Function} db - a connected Db/knex handle\n * @param {string} name - extension name, e.g. \"uuid-ossp\"\n * @param {{ dryRun?: boolean, logger?: object }} [options]\n * @returns {Promise<{ action: string }>}\n */\nexport async function ensureExtension(db, name, options = {}) {\n const action = `CREATE EXTENSION IF NOT EXISTS \"${name}\"`;\n if (!options.dryRun) {\n await db.raw(action);\n }\n options.logger?.silly?.(`[ensure] ${dbLabel(db)}: ${action}${options.dryRun ? \" (dryRun)\" : \"\"}`);\n return { action };\n}\n\n/**\n * Create a table when missing; when it exists, add any missing columns and\n * indexes from the spec. Never drops or alters existing columns.\n *\n * @param {Function} db\n * @param {string} tableName\n * @param {TableSpec} spec\n * @param {{ dryRun?: boolean, logger?: object }} [options]\n * @returns {Promise<string[]>} human-readable list of applied (or planned) DDL\n */\nexport async function ensureTable(db, tableName, spec, options = {}) {\n const { dryRun = false, logger } = options;\n const actions = [];\n const exists = await db.tableExists(tableName);\n\n if (!exists) {\n actions.push(`CREATE TABLE ${tableName} (${Object.keys(spec.columns).length} columns)`);\n if (!dryRun) {\n await db.schema.createTable(tableName, (t) => {\n for (const define of Object.values(spec.columns)) {\n define(t, db);\n }\n });\n }\n } else {\n // Column-level ensure: add whatever the spec has that the table lacks.\n const missing = [];\n for (const column of Object.keys(spec.columns)) {\n if (!(await db.schema.hasColumn(tableName, column))) {\n missing.push(column);\n }\n }\n if (missing.length > 0) {\n actions.push(`ALTER TABLE ${tableName} ADD COLUMN ${missing.join(\", \")}`);\n if (!dryRun) {\n await db.schema.alterTable(tableName, (t) => {\n for (const column of missing) {\n spec.columns[column](t, db);\n }\n });\n }\n }\n }\n\n for (const index of spec.indexes ?? []) {\n const indexActions = await ensureIndex(db, tableName, index, options);\n actions.push(...indexActions);\n }\n\n for (const action of actions) {\n logger?.silly?.(`[ensure] ${dbLabel(db)}: ${action}${dryRun ? \" (dryRun)\" : \"\"}`);\n }\n return actions;\n}\n\n/**\n * Ensure a (unique) index exists. On PostgreSQL this is a real existence check\n * (`CREATE [UNIQUE] INDEX IF NOT EXISTS`); other dialects fall back to\n * attempt-and-tolerate-\"already exists\".\n *\n * @param {Function} db\n * @param {string} tableName\n * @param {{ columns: string[], name: string, unique?: boolean }} index\n * @param {{ dryRun?: boolean, logger?: object }} [options]\n * @returns {Promise<string[]>}\n */\nexport async function ensureIndex(db, tableName, index, options = {}) {\n const { dryRun = false } = options;\n const kind = index.unique ? \"UNIQUE INDEX\" : \"INDEX\";\n const cols = index.columns.map((c) => `\"${c}\"`).join(\", \");\n const isPg = String(db?.config?.connectionString ?? \"\").startsWith(\"postgresql\");\n\n if (isPg) {\n const sql = `CREATE ${kind} IF NOT EXISTS \"${index.name}\" ON \"${tableName}\" (${cols})`;\n const { rows } = await db.raw(`SELECT 1 FROM pg_indexes WHERE indexname = ?`, [index.name]);\n if (rows.length > 0) return [];\n if (!dryRun) await db.raw(sql);\n return [sql];\n }\n\n // Non-pg fallback: try, and treat \"already exists\" as success.\n const sql = `CREATE ${kind} ${index.name} ON ${tableName} (${cols})`;\n if (!dryRun) {\n try {\n await db.raw(sql);\n } catch (error) {\n if (!/already exists|duplicate/i.test(error?.message ?? \"\")) throw error;\n return [];\n }\n }\n return [sql];\n}\n\n/**\n * Apply a full schema spec to ONE database. Returns the list of applied\n * (or, with dryRun, planned) DDL statements — empty when everything is\n * already in place.\n *\n * @param {Function} db\n * @param {SchemaSpec} spec\n * @param {{ dryRun?: boolean, logger?: object }} [options]\n * @returns {Promise<{ database: string, actions: string[] }>}\n */\nexport async function ensureSchema(db, spec, options = {}) {\n const actions = [];\n for (const extension of spec.extensions ?? []) {\n // Extensions are cheap no-ops when present; report only in dryRun.\n const { action } = await ensureExtension(db, extension, options);\n if (options.dryRun) actions.push(action);\n }\n for (const [tableName, tableSpec] of Object.entries(spec.tables ?? {})) {\n actions.push(...(await ensureTable(db, tableName, tableSpec, options)));\n }\n return { database: dbLabel(db), actions };\n}\n\n/**\n * Apply a schema spec to MANY databases (e.g. the main DB plus every sibling).\n * Convenience loop over {@link ensureSchema} with a combined report and\n * per-database info logging.\n *\n * @param {Function[]} dbs - connected handles (see Db.initAllSiblings)\n * @param {SchemaSpec} spec\n * @param {{ dryRun?: boolean, logger?: object }} [options]\n * @returns {Promise<Array<{ database: string, actions: string[] }>>}\n */\nexport async function ensureSchemaEverywhere(dbs, spec, options = {}) {\n const reports = [];\n for (const db of dbs) {\n const report = await ensureSchema(db, spec, options);\n if (report.actions.length > 0) {\n options.logger?.info?.(\n `[ensure] ${report.database}: ${options.dryRun ? \"would apply\" : \"applied\"} ${report.actions.length} DDL statement(s)`,\n );\n }\n reports.push(report);\n }\n return reports;\n}\n"],"mappings":"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","names":["sql"]}
1
+ {"version":3,"sources":["../src/db/index.js","../src/errors.js","../src/db/ensure.js"],"sourcesContent":["import knex from \"knex\";\nimport { ParamError } from \"../errors.js\";\n\nexport {\n ensureExtension,\n ensureTable,\n ensureIndex,\n ensureSchema,\n ensureSchemaEverywhere,\n} from \"./ensure.js\";\n\nconst KNEX_DEFAULTS = {\n testConnection: true,\n // min: 0 avoids holding idle sockets that go stale during long-running CLIs\n pool: { min: 0, max: 10, idleTimeoutMillis: 30_000 },\n acquireConnectionTimeout: 10000,\n ssl: { rejectUnauthorized: false },\n};\n\n/** Node / pg / knex signals that the socket or pool is dead and a reconnect may help. */\nconst CONNECTION_ERROR_CODES = new Set([\n \"ECONNRESET\",\n \"ECONNREFUSED\",\n \"EPIPE\",\n \"ETIMEDOUT\",\n \"ENOTFOUND\",\n \"EHOSTUNREACH\",\n \"ENETUNREACH\",\n \"ECONNABORTED\",\n \"CONNECTION_ENDED\",\n \"CONNECTION_CLOSED\",\n // PostgreSQL SQLSTATE class 08xxx (connection exception) + admin shutdowns\n \"08000\",\n \"08001\",\n \"08003\",\n \"08004\",\n \"08006\",\n \"08007\",\n \"08P01\",\n \"57P01\",\n \"57P02\",\n \"57P03\",\n]);\n\n// Note: \"Timeout acquiring a connection\" is pool contention (all slots busy),\n// not a dead socket — reconnecting destroys healthy clients and makes it worse.\nconst CONNECTION_ERROR_MESSAGE_RE =\n /connection (terminated|ended|closed|destroyed|reset|refused|not open)|Connection (terminated|ended) unexpectedly|Client has encountered a connection error|server closed the connection|Cannot use a pool after calling end|This socket has been ended|connect ECONNRESET/i;\n\nexport class Db {\n static async init(context, options = {}) {\n const buildConfig = async () => {\n const defs = {\n dbName: \"string\",\n dbProfile: \"boolean default false\",\n /** Cap knex pool size (default 10). Size ≈ expected concurrency + headroom. */\n dbPoolMax: \"number\",\n };\n const discovered = context?.params?.getAllForModule?.(\"db\", defs) ?? {};\n const merged = { ...discovered, ...options };\n\n let { dbName, dbProfile } = merged;\n let dbConnectionString = options.dbConnectionString ?? options.connectionString;\n let connectionParam = dbConnectionString ? \"options\" : null;\n\n if (!dbConnectionString) {\n const src = context?.args?.getSource?.(\"dbConnectionString\");\n if (src === \"cli\" || src === \"overrides\" || src === \"config\") {\n dbConnectionString = await context.params.get(\"dbConnectionString\", \"string\");\n connectionParam = \"dbConnectionString\";\n }\n }\n\n if (!dbConnectionString && dbName && /^(postgresql|mysql):\\/\\//.test(dbName)) {\n dbConnectionString = dbName;\n dbName = undefined;\n }\n\n if (!dbConnectionString && dbName) {\n const paramName = `dbConnectionString${capitalizeFirstLetter(dbName)}`;\n dbConnectionString = await context.params.get(paramName, \"string\");\n connectionParam = paramName;\n if (!dbConnectionString) {\n throw new ParamError(\n `Db: cannot find dbConnectionString for dbName=\"${dbName}\" (looked for param \"${paramName}\")`\n );\n }\n }\n\n if (!dbConnectionString) {\n dbConnectionString = await context.params.get(\"dbConnectionString\", \"string\");\n if (dbConnectionString) {\n connectionParam = \"dbConnectionString\";\n }\n }\n\n if (!dbConnectionString) {\n if (!dbName) {\n const env = context?.args?.env;\n // Never silently fall back to \"local\" on production/stage — that\n // masked missing DB_NAME_* / --dbName as a localhost:6032 connect.\n if (env && String(env).toLowerCase() !== \"local\") {\n throw new ParamError(\n `Db: dbName not set for env=\"${env}\" (set --dbName or DB_NAME_${String(env).toUpperCase()})`\n );\n }\n dbName = \"local\";\n }\n const paramName = `dbConnectionString${capitalizeFirstLetter(dbName)}`;\n dbConnectionString = await context.params.get(paramName, \"string\");\n connectionParam = paramName;\n if (!dbConnectionString) {\n throw new ParamError(\n `Db: cannot find dbConnectionString for dbName=\"${dbName}\" (looked for param \"${paramName}\")`\n );\n }\n }\n\n const displayName = resolveDbDisplayName(\n dbName,\n connectionParam,\n context?.args?.env,\n merged.name\n );\n\n const poolMaxRaw = merged.dbPoolMax ?? merged.pool?.max;\n const poolMax = Number(poolMaxRaw);\n const pool = {\n ...KNEX_DEFAULTS.pool,\n ...(merged.pool && typeof merged.pool === \"object\" ? merged.pool : {}),\n };\n if (Number.isFinite(poolMax) && poolMax >= 1) {\n pool.max = Math.floor(poolMax);\n }\n\n return {\n ...KNEX_DEFAULTS,\n connectionString: dbConnectionString,\n name: displayName,\n profile: !!dbProfile,\n logger: context.logger,\n pool,\n ...(merged.acquireConnectionTimeout != null\n ? { acquireConnectionTimeout: merged.acquireConnectionTimeout }\n : {}),\n };\n };\n\n const config = context?.params?.runWithModuleAsync\n ? await context.params.runWithModuleAsync(\"db\", buildConfig)\n : await buildConfig();\n\n return dbConnect(context, config);\n }\n\n /**\n * Initialize a SIBLING database handler: a database that lives on the same\n * server with the same credentials/options as an existing (\"base\") one, and\n * differs only by its database name. Typical use: a per-tenant / per-subject\n * database alongside a main database that keeps the shared tables.\n *\n * context.db = await Db.init(context); // main\n * const sub = await Db.initSibling(context, \"src_bright\"); // sibling\n *\n * LOCATION-AGNOSTIC BY DESIGN — the call gracefully falls back to the main\n * database, so callers can use it for all subject data without knowing what\n * has been migrated where:\n * - empty `siblingName` → the main handler (same as Db.init)\n * - sibling DB does not exist yet → the main handler (data not migrated;\n * it still lives in the main database)\n * Callers that must not fall back can check `handler === context.db`.\n *\n * Connection string resolution for an actual sibling, in order:\n * 1. Explicit override — param `dbConnectionStringSib<SiblingName>` (env\n * `DB_CONNECTION_STRING_SIB_<SIBLING_NAME>`, e.g. `src_bright` →\n * `DB_CONNECTION_STRING_SIB_SRC_BRIGHT`). Nobody needs this on day\n * one; it is the escape hatch for when a sibling later moves to its\n * own server — one env var, no code changes (the `SIB_` namespace\n * both overrides the connection and declares that the sibling\n * exists, so it never falls back to main).\n * 2. Derived — take the base connection string and swap the database\n * name (after confirming the database exists on that server). The\n * base is `options.baseDb` (a Db handler), then\n * `options.baseConnectionString`, then `context.db`.\n *\n * Handlers are cached per name on the context (`context.siblingDbs`), so\n * any number of components asking for the same sibling share one pool —\n * including the \"falls back to main\" answer, which is remembered for the\n * lifetime of the process (a mid-run migration is picked up on restart).\n * Disconnect is registered via `context.registerCleanup`, same as the\n * main handler.\n *\n * @param {object} context - context with params/logger (and usually .db)\n * @param {string} [siblingName] - the sibling's database name (e.g. \"src_bright\")\n * @param {object} [options] - { baseDb, baseConnectionString, dbProfile }\n * @returns {Promise<Db>} connected handler (same proxy shape as Db.init)\n */\n static async initSibling(context, siblingName, options = {}) {\n // Empty name → the main database, so call sites stay location-agnostic.\n if (!siblingName) {\n return resolveMainHandler(context, options);\n }\n if (!/^[a-zA-Z0-9_]+$/.test(siblingName)) {\n throw new ParamError(\n `Db.initSibling: invalid sibling database name \"${siblingName}\" (letters, digits and _ only)`\n );\n }\n\n if (!context.siblingDbs) {\n context.siblingDbs = new Map();\n }\n const cached = context.siblingDbs.get(siblingName);\n if (cached) {\n return cached;\n }\n\n // 1. explicit override: dbConnectionStringSib<SiblingName> param / env var.\n // Its presence also DECLARES the sibling (it may live on another server),\n // so the existence check below is skipped.\n const overrideParam = `dbConnectionStringSib${camelizeDbName(siblingName)}`;\n let connectionString = await context?.params?.get?.(overrideParam, \"string\");\n if (connectionString) {\n context.logger?.debug?.(\n `[Db] sibling \"${siblingName}\": using override param \"${overrideParam}\"`\n );\n } else {\n // 2. derive from the base connection string\n const baseHandle = options.baseDb ?? context.db;\n const base =\n baseHandle?.config?.connectionString ?? options.baseConnectionString;\n if (!base) {\n throw new ParamError(\n `Db.initSibling: no base connection to derive \"${siblingName}\" from — ` +\n `init the main Db first (context.db = await Db.init(context)), ` +\n `or pass options.baseDb / options.baseConnectionString, ` +\n `or set the ${overrideParam} param (env ${toEnvKey(overrideParam)})`\n );\n }\n\n // Not migrated yet? Fall back to the main database so the caller's\n // code works the same before and after the split.\n const exists = await databaseExistsOnServer(baseHandle, base, siblingName);\n if (!exists) {\n context.logger?.debug?.(\n `[Db] sibling \"${siblingName}\" does not exist — falling back to the main database`\n );\n const main = await resolveMainHandler(context, options);\n context.siblingDbs.set(siblingName, main);\n return main;\n }\n\n connectionString = replaceDatabaseName(base, siblingName);\n context.logger?.debug?.(\n `[Db] sibling \"${siblingName}\": derived from base (${formatConnectionEndpoint(base) ?? \"?\"})`\n );\n }\n\n const config = {\n ...KNEX_DEFAULTS,\n connectionString,\n name: siblingName,\n profile: !!options.dbProfile,\n logger: context.logger,\n };\n\n const handler = await dbConnect(context, config);\n context.siblingDbs.set(siblingName, handler);\n return handler;\n }\n\n /**\n * Discover the sibling databases that are \"currently in use\", by name.\n * Two sources, merged (env wins on duplicates):\n *\n * 1. ENV-DECLARED — every `DB_CONNECTION_STRING_SIB_<NAME>` env var\n * (the dedicated `SIB_` namespace) whose decoded name matches. This\n * covers siblings that moved to their own server: the same var that\n * overrides the connection also *registers* the database, so `.env`\n * stays the single convenient list.\n * 2. SAME-SERVER SCAN — `SELECT datname FROM pg_database` on the base\n * server (PostgreSQL only), filtered the same way.\n *\n * The caller says what \"matches\": `{ prefix: \"src_\" }` or\n * `{ match: /^src_/ }` — the toolkit does not guess a naming convention.\n *\n * @param {object} context - needs context.db (or options.baseDb) for the server scan\n * @param {{ prefix?: string, match?: RegExp, baseDb?: object, env?: object }} options\n * @returns {Promise<Array<{ name: string, origin: \"env\"|\"server\" }>>} sorted by name\n */\n static async discoverSiblings(context, options = {}) {\n const { prefix, match, env = process.env } = options;\n if (!prefix && !match) {\n throw new ParamError(`Db.discoverSiblings: pass { prefix: \"...\" } or { match: /.../ }`);\n }\n const matches = match instanceof RegExp ? (n) => match.test(n) : (n) => n.startsWith(prefix);\n\n const found = new Map();\n\n // 1. env-declared siblings (possibly on other servers) — SIB_ namespace\n for (const key of Object.keys(env)) {\n const m = /^DB_CONNECTION_STRING_SIB_(.+)$/.exec(key);\n if (!m || !env[key]) continue;\n const name = m[1].toLowerCase();\n if (matches(name)) {\n found.set(name, \"env\");\n }\n }\n\n // 2. same-server scan (PostgreSQL)\n const base = options.baseDb ?? context?.db;\n if (base) {\n const connectionString = String(base.config?.connectionString ?? \"\");\n if (connectionString.startsWith(\"postgresql\")) {\n const { rows } = await base.raw(\n \"SELECT datname FROM pg_database WHERE datistemplate = false\",\n );\n for (const { datname } of rows) {\n if (matches(datname) && !found.has(datname)) {\n found.set(datname, \"server\");\n }\n }\n } else {\n context?.logger?.warn?.(\n \"[Db] discoverSiblings: server scan supported for PostgreSQL only; using env-declared siblings\",\n );\n }\n }\n\n return [...found]\n .map(([name, origin]) => ({ name, origin }))\n .sort((a, b) => a.name.localeCompare(b.name));\n }\n\n /**\n * Discover + connect: one handler per active sibling (cached, pooled —\n * see initSibling). Pass `includeMain: true` to get `[context.db, ...]`,\n * which is the usual shape for \"apply this DDL everywhere\" loops:\n *\n * const dbs = await Db.initAllSiblings(context, { prefix: \"src_\", includeMain: true });\n * await ensureSchemaEverywhere(dbs, spec, { logger: context.logger });\n *\n * @param {object} context\n * @param {{ prefix?: string, match?: RegExp, includeMain?: boolean, baseDb?: object, env?: object }} options\n * @returns {Promise<Function[]>} connected handlers\n */\n static async initAllSiblings(context, options = {}) {\n const discovered = await Db.discoverSiblings(context, options);\n const handlers = [];\n for (const { name } of discovered) {\n handlers.push(await Db.initSibling(context, name, options));\n }\n return options.includeMain && context.db ? [context.db, ...handlers] : handlers;\n }\n\n constructor(config) {\n if (!config || !config.connectionString) {\n throw new ParamError(\"Db: connectionString is required\");\n }\n\n this.knexInstance = null;\n this.isConnected = false;\n this.queriesLog = [];\n this._reconnectPromise = null;\n /** Set by disconnect(); blocks reconnect and connect so exit does not hang. */\n this._closed = false;\n /** Every knex client we created — reconnect can leave extras that disconnect must kill. */\n this._liveKnex = new Set();\n /** After a failed reconnect, skip further attempts until this timestamp. */\n this._reconnectCooldownUntil = 0;\n /** Shorter acquire timeout used only while reconnecting. */\n this._reconnectAcquireTimeoutMs = null;\n\n this.config = {\n testConnection: true,\n profile: false,\n pool: { min: 0, max: 10, idleTimeoutMillis: 30_000 },\n acquireConnectionTimeout: 10000,\n ssl: { rejectUnauthorized: false },\n logger: console,\n ...config,\n };\n\n this.logger = this.config.logger;\n\n const instance = this;\n const callableWrapper = function () {\n throw new Error(\"This should never be called directly\");\n };\n callableWrapper._instance = instance;\n\n return new Proxy(callableWrapper, {\n apply: (target, _thisArg, argumentsList) => {\n const inst = target._instance;\n if (!inst.knexInstance) {\n throw new Error(\"Db: Not connected. Call connect() first.\");\n }\n return inst.wrapQueryBuilder(inst.knexInstance(...argumentsList));\n },\n get: (target, prop) => {\n if (prop === \"_instance\") {\n return target._instance;\n }\n\n const inst = target._instance;\n\n const ownMethods = [\n \"connect\",\n \"disconnect\",\n \"reconnect\",\n \"testConnection\",\n \"tableExists\",\n \"raw\",\n \"withConnectionRetry\",\n \"isConnectionError\",\n \"getQueryLog\",\n \"getKnex\",\n \"isConnectedToDb\",\n \"getErrorMessage\",\n \"detectClient\",\n \"attachProfiler\",\n ];\n\n if (prop in inst) {\n const value = inst[prop];\n if (typeof value === \"function\" && ownMethods.includes(prop)) {\n return value.bind(inst);\n }\n if (typeof value !== \"function\") {\n return value;\n }\n }\n\n if (inst.knexInstance) {\n const knexProp = inst.knexInstance[prop];\n if (typeof knexProp === \"function\") {\n if (prop === \"raw\") {\n return (...args) => inst.raw(...args);\n }\n return knexProp.bind(inst.knexInstance);\n }\n return knexProp;\n }\n\n if (prop in inst) {\n const method = inst[prop];\n if (typeof method === \"function\") {\n return method.bind(inst);\n }\n return method;\n }\n\n return undefined;\n },\n });\n }\n\n detectClient(connectionString) {\n if (connectionString.match(/^postgresql/)) {\n return \"pg\";\n }\n if (connectionString.match(/^mysql/)) {\n return \"mysql2\";\n }\n return null;\n }\n\n async connect() {\n if (this._closed) {\n throw new ParamError(\"Db: Connection closed\");\n }\n if (this.isConnected && this.knexInstance) {\n this.logger.warn?.(\"[Db] Already connected\");\n return;\n }\n\n const client = this.detectClient(this.config.connectionString);\n if (!client) {\n throw new ParamError(\n \"Db: Cannot determine client type from connection string. Expected postgresql:// or mysql://\"\n );\n }\n\n try {\n const connectionConfig = {\n connectionString: this.config.connectionString,\n family: 4,\n };\n\n const acquireTimeout = this._reconnectAcquireTimeoutMs\n ?? this.config.acquireConnectionTimeout;\n this.knexInstance = knex({\n client,\n connection: connectionConfig,\n pool: this.config.pool,\n acquireConnectionTimeout: acquireTimeout,\n ...(this.config.ssl && { ssl: this.config.ssl }),\n });\n this._liveKnex.add(this.knexInstance);\n this.knexInstance.on?.(\"error\", (err) => {\n if (this._closed) return;\n this.logger.warn?.(\n `[Db] Connection error (${this.getErrorMessage(err)})`\n );\n });\n\n if (this._closed) {\n await this._destroyKnex(this.knexInstance, \"connect aborted (closed)\");\n this.knexInstance = null;\n throw new ParamError(\"Db: Connection closed\");\n }\n\n if (this.config.profile) {\n this.attachProfiler();\n }\n\n if (this.config.testConnection) {\n await this.testConnection();\n }\n\n if (this._closed) {\n await this._destroyKnex(this.knexInstance, \"connect aborted (closed)\");\n this.knexInstance = null;\n throw new ParamError(\"Db: Connection closed\");\n }\n\n this.isConnected = true;\n this.logger.debug?.(formatDbConnectMessage(this.config.name, this.config.connectionString));\n } catch (error) {\n // Always tear down a half-open pool (e.g. testConnection ENOTFOUND),\n // otherwise the next reconnect/disconnect waits on a dead knex forever.\n const failed = this.knexInstance;\n this.knexInstance = null;\n this.isConnected = false;\n if (failed) {\n await this._destroyKnex(failed, \"connect failed\");\n }\n if (error instanceof ParamError) {\n throw error;\n }\n const errorMsg = this.getErrorMessage(error);\n throw new ParamError(`Db: Connection failed - ${errorMsg}`);\n }\n }\n\n /**\n * Destroy a knex pool without hanging exit on stuck TCP sockets (ETIMEDOUT).\n * @param {import(\"knex\").Knex | null | undefined} knexInst\n * @param {string} [reason]\n * @param {number} [timeoutMs]\n */\n async _destroyKnex(knexInst, reason = \"destroy\", timeoutMs = 3_000) {\n if (!knexInst || typeof knexInst.destroy !== \"function\") return;\n this._liveKnex.delete(knexInst);\n try {\n await Promise.race([\n knexInst.destroy(),\n new Promise((_, reject) => {\n const t = setTimeout(\n () => reject(new Error(`Db: ${reason} timed out after ${timeoutMs}ms`)),\n timeoutMs,\n );\n t.unref?.();\n }),\n ]);\n } catch (error) {\n this.logger.debug?.(\n `[Db] ${reason}: ${this.getErrorMessage(error)}`\n );\n }\n }\n\n async disconnect() {\n this._closed = true;\n this.isConnected = false;\n this.knexInstance = null;\n this.queriesLog = [];\n\n // Do not await an in-flight reconnect — connect() may be stuck in\n // testConnection / DNS for acquireConnectionTimeout (often 60s).\n // Tear down every knex we created, including ones spawned mid-reconnect.\n const all = [...this._liveKnex];\n this._liveKnex.clear();\n await Promise.all(all.map((inst) => this._destroyKnex(inst, \"disconnect\")));\n if (all.length > 0) {\n this.logger.debug?.(formatDbDisconnectMessage(this.config.name, this.config.connectionString));\n }\n }\n\n /**\n * True when the error indicates a dead socket / pool that a fresh connect may fix.\n * Safe to call as `Db.prototype.isConnectionError(err)` or via a connected handle.\n */\n isConnectionError(error) {\n if (!error) {\n return false;\n }\n\n if (error instanceof AggregateError && Array.isArray(error.errors)) {\n return error.errors.some((e) => this.isConnectionError(e));\n }\n\n const code = error.code ?? error.errno;\n if (code != null && CONNECTION_ERROR_CODES.has(String(code))) {\n return true;\n }\n\n const msg = error instanceof Error ? error.message : String(error);\n return CONNECTION_ERROR_MESSAGE_RE.test(msg);\n }\n\n /**\n * Destroy the current knex pool and open a new one. Concurrent callers share one attempt.\n * No-ops once disconnect() has closed the handle.\n */\n async reconnect() {\n if (this._closed) {\n return;\n }\n if (this._reconnectCooldownUntil && Date.now() < this._reconnectCooldownUntil) {\n return;\n }\n if (this._reconnectPromise) {\n await this._reconnectPromise;\n return;\n }\n\n this._reconnectPromise = (async () => {\n if (this._closed) return;\n\n const old = this.knexInstance;\n this.isConnected = false;\n this.knexInstance = null;\n this.queriesLog = [];\n\n if (old) {\n await this._destroyKnex(old, \"destroy during reconnect\");\n }\n\n if (this._closed) return;\n // Don't inherit the caller's 60s acquire timeout while the host is down.\n this._reconnectAcquireTimeoutMs = 3_000;\n try {\n await this.connect();\n this._reconnectCooldownUntil = 0;\n } catch (error) {\n this._reconnectCooldownUntil = Date.now() + 5_000;\n throw error;\n } finally {\n this._reconnectAcquireTimeoutMs = null;\n }\n })();\n\n try {\n await this._reconnectPromise;\n } finally {\n this._reconnectPromise = null;\n }\n }\n\n async reconnectAfterConnectionError(error) {\n if (this._closed) {\n return;\n }\n if (this._reconnectCooldownUntil && Date.now() < this._reconnectCooldownUntil) {\n return;\n }\n this.logger.warn?.(\n `[Db] Connection lost (${this.getErrorMessage(error)}) — reconnecting…`\n );\n try {\n await this.reconnect();\n } catch {\n // connect() already logged the test failure; caller retries or throws.\n }\n }\n\n /**\n * Run `fn`; on a connection error, reconnect once (by default) and retry `fn`.\n * `fn` should look up `this.knexInstance` each call so the retry uses the new client.\n */\n async withConnectionRetry(fn, { retries = 1 } = {}) {\n let lastError;\n for (let attempt = 0; attempt <= retries; attempt++) {\n try {\n return await fn();\n } catch (error) {\n lastError = error;\n if (this._closed || !this.isConnectionError(error) || attempt >= retries) {\n throw error;\n }\n await this.reconnectAfterConnectionError(error);\n if (this._closed) {\n throw error;\n }\n }\n }\n throw lastError;\n }\n\n /**\n * Wrap a knex QueryBuilder / Raw so that awaiting it retries once after reconnect\n * when the first attempt dies with a connection error.\n */\n wrapQueryBuilder(builder) {\n if (!builder || typeof builder.then !== \"function\" || builder.__dbReconnectWrapped) {\n return builder;\n }\n\n builder.__dbReconnectWrapped = true;\n const inst = this;\n const protoThen = Object.getPrototypeOf(builder)?.then;\n if (typeof protoThen !== \"function\") {\n return builder;\n }\n\n builder.then = function (onFulfilled, onRejected) {\n const run = async () => {\n try {\n return await protoThen.call(builder);\n } catch (error) {\n if (inst._closed || !inst.isConnectionError(error)) {\n throw error;\n }\n await inst.reconnectAfterConnectionError(error);\n if (inst._closed || !inst.knexInstance) {\n throw error;\n }\n\n if (typeof builder.clone === \"function\") {\n const retry = builder.clone();\n retry.client = inst.knexInstance.client;\n return await protoThen.call(retry);\n }\n\n if (typeof builder.toSQL === \"function\" && inst.knexInstance) {\n const sql = builder.toSQL();\n const statements = Array.isArray(sql) ? sql : [sql];\n let last;\n for (const stmt of statements) {\n last = await inst.knexInstance.raw(stmt.sql, stmt.bindings);\n }\n return last;\n }\n\n throw error;\n }\n };\n return run().then(onFulfilled, onRejected);\n };\n\n return builder;\n }\n\n /** knex.raw with auto-reconnect on dead connections. */\n raw(...args) {\n if (!this.knexInstance) {\n throw new Error(\"Db: Not connected. Call connect() first.\");\n }\n return this.wrapQueryBuilder(this.knexInstance.raw(...args));\n }\n\n getErrorMessage(error) {\n if (error instanceof AggregateError) {\n const errors = error.errors || [];\n\n if (errors.length > 0) {\n const firstError = errors[0];\n const firstErrorMsg =\n firstError instanceof Error ? firstError.message : String(firstError);\n\n const allSimilar = errors.every((e) => {\n const msg = e instanceof Error ? e.message : String(e);\n const codeMatch = msg.match(/^(\\w+)\\s/);\n const firstCodeMatch = firstErrorMsg.match(/^(\\w+)\\s/);\n return codeMatch && firstCodeMatch && codeMatch[1] === firstCodeMatch[1];\n });\n\n if (allSimilar && errors.length > 1) {\n const addresses = errors\n .map((e) => {\n const msg = e instanceof Error ? e.message : String(e);\n const addrMatch = msg.match(/([:\\d.]+:\\d+)/);\n return addrMatch ? addrMatch[1] : null;\n })\n .filter(Boolean);\n\n if (addresses.length > 0) {\n const codeMatch = firstErrorMsg.match(/^(\\w+)\\s/);\n const code = codeMatch ? codeMatch[1] : \"Connection error\";\n return `${code} (tried: ${addresses.join(\", \")})`;\n }\n }\n\n const uniqueMessages = [\n ...new Set(\n errors.map((e) => (e instanceof Error ? e.message : String(e)))\n ),\n ];\n\n if (uniqueMessages.length === 1) {\n return uniqueMessages[0];\n }\n\n return uniqueMessages.join(\"; \");\n }\n\n return error.message || \"Multiple errors occurred\";\n }\n\n if (error instanceof Error) {\n const code = error.code;\n if (code) {\n return `${code}: ${error.message || String(error)}`;\n }\n return error.message || String(error);\n }\n\n if (typeof error === \"string\") {\n return error;\n }\n\n if (error && typeof error === \"object\" && \"message\" in error) {\n const msg = String(error.message);\n const code = error.code;\n if (code) {\n return `${code}: ${msg}`;\n }\n return msg;\n }\n\n return String(error) || \"Unknown error\";\n }\n\n async testConnection() {\n if (!this.knexInstance) {\n throw new Error(\"Db: Not connected. Call connect() first.\");\n }\n\n try {\n const result = await this.knexInstance.raw(\"SELECT 2+3 AS result\");\n const isOk = result.rows?.[0]?.result === 5 || result[0]?.[0]?.result === 5;\n this.logger.debug?.(`[Db] Connection test: ${isOk ? \"OK\" : \"FAILED\"}`);\n return isOk;\n } catch (error) {\n const errorMsg = this.getErrorMessage(error);\n this.logger.error?.(`[Db] Connection test failed: ${errorMsg}`);\n throw new ParamError(`Db: Connection test failed - ${errorMsg}`);\n }\n }\n\n attachProfiler() {\n if (!this.knexInstance) {\n return;\n }\n\n this.queriesLog = [];\n this.knexInstance.queriesLog = this.queriesLog;\n\n // Knex emits fresh Object.assign(...) copies on \"query\" and \"query-response\",\n // so __startTime on the query object does not survive — track per-connection FIFO.\n const startsByConnection = new Map();\n\n const pushStart = (query) => {\n const uid = query?.__knexUid ?? \"\";\n if (!startsByConnection.has(uid)) {\n startsByConnection.set(uid, []);\n }\n startsByConnection.get(uid).push(process.hrtime());\n };\n\n const popStart = (query) => {\n const uid = query?.__knexUid ?? \"\";\n const stack = startsByConnection.get(uid);\n if (!stack?.length) {\n return null;\n }\n return stack.pop();\n };\n\n const isTimeoutError = (error) =>\n error?.name === \"KnexTimeoutError\" ||\n /query timeout|timeout exceeded/i.test(String(error?.message ?? \"\"));\n\n const logQueryEntry = (query, start, { error } = {}) => {\n let executionTimeMs;\n if (start) {\n const [seconds, nanoseconds] = process.hrtime(start);\n executionTimeMs = (seconds * 1000 + nanoseconds / 1e6).toFixed(2);\n } else if (error?.timeout != null) {\n executionTimeMs = Number(error.timeout).toFixed(2);\n } else {\n executionTimeMs = \"?\";\n }\n\n let status = \"ok\";\n if (error) {\n status = isTimeoutError(error) ? \"timeout\" : \"error\";\n }\n\n const logEntry = {\n sql: query?.sql,\n bindings: query?.bindings || [],\n executionTimeMs,\n status,\n };\n if (error) {\n logEntry.error = error.message ?? String(error);\n }\n\n this.queriesLog.push(logEntry);\n const suffix = error ? ` | ${status}: ${logEntry.error}` : \"\";\n this.logger.debug?.(\n `[Db] Query: ${query?.sql} | Duration: ${executionTimeMs}ms${suffix}`,\n );\n };\n\n const handleQueryError = (error, query) => {\n const start = popStart(query);\n logQueryEntry(query, start, { error });\n this.logger.error?.(`[Db] Query failed: ${query?.sql}`, error);\n };\n\n this.knexInstance.on(\"query\", (query) => {\n pushStart(query);\n });\n\n this.knexInstance.on(\"query-response\", (_response, query) => {\n const start = popStart(query);\n if (!start) {\n return;\n }\n logQueryEntry(query, start);\n });\n\n this.knexInstance.on(\"query-error\", (error, query) => {\n handleQueryError(error, query);\n });\n\n // Builder queries emit \"query\" / \"query-error\" on the builder, not always on client.\n const hookBuilder = (builder) => {\n if (!builder || builder.__dbProfilerHooked) {\n return;\n }\n builder.__dbProfilerHooked = true;\n builder.on(\"query\", pushStart);\n builder.on(\"query-error\", handleQueryError);\n };\n\n const client = this.knexInstance.client;\n if (client && !client.__dbProfilerPatched) {\n client.__dbProfilerPatched = true;\n if (typeof client.queryBuilder === \"function\") {\n const origQueryBuilder = client.queryBuilder.bind(client);\n client.queryBuilder = (...args) => {\n const builder = origQueryBuilder(...args);\n hookBuilder(builder);\n return builder;\n };\n }\n }\n }\n\n getQueryLog() {\n return [...this.queriesLog];\n }\n\n async tableExists(tableName) {\n if (!this.knexInstance) {\n throw new Error(\"Db: Not connected. Call connect() first.\");\n }\n\n try {\n return await this.withConnectionRetry(() =>\n this.knexInstance.schema.hasTable(tableName)\n );\n } catch (error) {\n this.logger.error?.(`[Db] Error checking table existence: ${error.message}`);\n throw error;\n }\n }\n\n getKnex() {\n if (!this.knexInstance) {\n throw new Error(\"Db: Not connected. Call connect() first.\");\n }\n return this.knexInstance;\n }\n\n isConnectedToDb() {\n return this.isConnected && this.knexInstance !== null;\n }\n}\n\nfunction capitalizeFirstLetter(str) {\n return str.charAt(0).toUpperCase() + str.slice(1);\n}\n\n/**\n * The main database handler, for initSibling's fallbacks: the base handle when\n * one was passed, otherwise `context.db` (initialized on demand, so an\n * initSibling-only script still works).\n */\nasync function resolveMainHandler(context, options = {}) {\n if (options.baseDb) {\n return options.baseDb;\n }\n if (!context.db) {\n context.db = await Db.init(context);\n }\n return context.db;\n}\n\n/**\n * Does `databaseName` exist on the base server? Checked via an existing handle\n * when available (no extra connection), else a short-lived one. Non-PostgreSQL\n * bases skip the check (returns true — connection will tell).\n */\nasync function databaseExistsOnServer(baseHandle, baseConnectionString, databaseName) {\n if (!String(baseConnectionString).startsWith(\"postgresql\")) {\n return true;\n }\n const query = \"SELECT 1 FROM pg_database WHERE datname = ?\";\n if (baseHandle) {\n const { rows } = await baseHandle.raw(query, [databaseName]);\n return rows.length > 0;\n }\n const shortLived = knex({\n client: \"pg\",\n connection: { connectionString: baseConnectionString },\n pool: { min: 0, max: 1 },\n });\n try {\n const { rows } = await shortLived.raw(query, [databaseName]);\n return rows.length > 0;\n } finally {\n await shortLived.destroy();\n }\n}\n\n/**\n * Database name → camelCase param suffix: \"src_bright\" → \"SrcBright\",\n * so the override param becomes dbConnectionStringSibSrcBright\n * (env DB_CONNECTION_STRING_SIB_SRC_BRIGHT).\n */\nfunction camelizeDbName(name) {\n return name\n .split(/[_-]+/)\n .filter(Boolean)\n .map(capitalizeFirstLetter)\n .join(\"\");\n}\n\n/** camelCase param name → its SNAKE_CASE env var (for error messages only). */\nfunction toEnvKey(key) {\n return key.replace(/([A-Z])/g, \"_$1\").toUpperCase();\n}\n\n/**\n * Replace the database name in a connection string, keeping everything else\n * (credentials, host, port, query options like sslmode) intact.\n * Exported for reuse (e.g. database-splitting tools) and tests.\n */\nexport function replaceDatabaseName(connectionString, databaseName) {\n let url;\n try {\n url = new URL(connectionString);\n } catch {\n throw new ParamError(\n `Db: cannot parse connection string to derive a sibling database from it`\n );\n }\n url.pathname = `/${databaseName}`;\n return url.toString();\n}\n\nfunction resolveDbDisplayName(dbName, connectionParam, argsEnv, mergedName) {\n if (dbName) {\n return dbName;\n }\n if (mergedName) {\n return mergedName;\n }\n if (\n connectionParam?.startsWith(\"dbConnectionString\") &&\n connectionParam.length > \"dbConnectionString\".length\n ) {\n return connectionParam.slice(\"dbConnectionString\".length).toLowerCase();\n }\n if (connectionParam === \"dbConnectionString\" && argsEnv) {\n return argsEnv;\n }\n return undefined;\n}\n\nfunction formatDbConnectMessage(name, connectionString) {\n const endpointSuffix = formatConnectionEndpointSuffix(connectionString);\n if (name) {\n return `[Db] Connected to database \"${name}\"${endpointSuffix}`;\n }\n return `[Db] Connected${endpointSuffix}`;\n}\n\nfunction formatDbDisconnectMessage(name, connectionString) {\n const endpointSuffix = formatConnectionEndpointSuffix(connectionString);\n if (name) {\n return `[Db] Disconnected from database \"${name}\"${endpointSuffix}`;\n }\n return `[Db] Disconnected${endpointSuffix}`;\n}\n\nfunction formatDbInstanceMessage(action, name) {\n if (name) {\n return `[Db] instance \"${name}\" ${action}`;\n }\n return `[Db] instance ${action}`;\n}\n\nfunction formatConnectionEndpointSuffix(connectionString) {\n const endpoint = formatConnectionEndpoint(connectionString);\n return endpoint ? ` (${endpoint})` : \"\";\n}\n\nfunction formatConnectionEndpoint(connectionString) {\n try {\n const url = new URL(connectionString);\n const host = url.hostname;\n if (!host) {\n return null;\n }\n\n let port = url.port;\n if (!port) {\n if (url.protocol === \"postgresql:\") {\n port = \"5432\";\n } else if (url.protocol === \"mysql:\") {\n port = \"3306\";\n }\n }\n\n return port ? `${host}:${port}` : host;\n } catch {\n return null;\n }\n}\n\nasync function dbConnect(context, config) {\n try {\n const db = new Db(config);\n\n context.registerCleanup(async () => {\n await db.disconnect();\n context.logger.debug?.(formatDbInstanceMessage(\"disconnected\", config.name));\n });\n\n await db.connect();\n\n context.logger.debug?.(formatDbInstanceMessage(\"initialized\", config.name));\n\n return db;\n } catch (error) {\n if (error instanceof ParamError) {\n throw error;\n }\n const errorMsg = error instanceof Error ? error.message : String(error);\n throw new ParamError(`[Db] connect error: ${errorMsg}`);\n }\n}\n","/**\n * Error classes for the CLI toolkit\n */\n\nexport class FrameworkError extends Error {\n constructor(message) {\n super(message);\n this.name = \"FrameworkError\";\n }\n}\n\nexport class ParamError extends FrameworkError {\n constructor(message) {\n super(message);\n this.name = \"ParamError\";\n }\n}\n\nexport class InitError extends FrameworkError {\n constructor(message) {\n super(message);\n this.name = \"InitError\";\n }\n}\n\nexport class CriticalRequestError extends FrameworkError {\n constructor(message) {\n super(message);\n this.name = \"CriticalRequestError\";\n }\n}\n\nexport class ControlFlowError extends Error {\n constructor(message) {\n super(message);\n this.name = \"ControlFlowError\";\n }\n}\n\nexport class HttpClientError extends FrameworkError {\n constructor(message, cause) {\n super(message);this.cause = cause;;\n this.name = \"HttpClientError\";\n }\n}\n\nexport class FileDatabaseError extends FrameworkError {\n constructor(message) {\n super(message);\n this.name = \"FileDatabaseError\";\n }\n}\n\n","/**\n * Declarative, idempotent DDL — \"make sure this schema exists\" helpers.\n *\n * Components describe the schema they need (tables, columns, indexes,\n * extensions) once, as data; `ensureSchema` diffs that spec against a live\n * database and applies only what's missing:\n *\n * - table missing → CREATE TABLE with all columns + indexes\n * - table there, column not → ALTER TABLE ADD COLUMN (never drops/changes)\n * - index/unique missing → CREATE [UNIQUE] INDEX IF NOT EXISTS\n * - extension missing → CREATE EXTENSION IF NOT EXISTS\n *\n * Because the input is a spec (not imperative code), the same call can be\n * repeated over any number of databases — the main one and every sibling —\n * and each gets exactly the DDL it lacks. See Db.initSibling /\n * Db.discoverSiblings for getting those handles.\n *\n * Spec shape:\n *\n * {\n * extensions: [\"uuid-ossp\"],\n * tables: {\n * my_table: {\n * columns: {\n * id: (t, db) => t.uuid(\"id\").primary().defaultTo(db.raw(\"uuid_generate_v4()\")),\n * name: (t) => t.text(\"name\").notNullable(),\n * },\n * indexes: [\n * { columns: [\"name\"], name: \"my_table_name_idx\" },\n * { columns: [\"a\", \"b\"], name: \"my_table_ab_uniq\", unique: true },\n * ],\n * },\n * },\n * }\n *\n * Every function accepts `{ dryRun: true }` and then only *reports* what it\n * would do (returned in the report, logged when a logger is given) without\n * touching the database.\n */\n\n/** @typedef {{ columns: Record<string, Function>, indexes?: Array<{ columns: string[], name: string, unique?: boolean }> }} TableSpec */\n/** @typedef {{ extensions?: string[], tables?: Record<string, TableSpec> }} SchemaSpec */\n\nconst dbLabel = (db) => db?.config?.name ?? \"db\";\n\n/**\n * CREATE EXTENSION IF NOT EXISTS (PostgreSQL). No-op report entry on dryRun.\n *\n * @param {Function} db - a connected Db/knex handle\n * @param {string} name - extension name, e.g. \"uuid-ossp\"\n * @param {{ dryRun?: boolean, logger?: object }} [options]\n * @returns {Promise<{ action: string }>}\n */\nexport async function ensureExtension(db, name, options = {}) {\n const action = `CREATE EXTENSION IF NOT EXISTS \"${name}\"`;\n if (!options.dryRun) {\n await db.raw(action);\n }\n options.logger?.silly?.(`[ensure] ${dbLabel(db)}: ${action}${options.dryRun ? \" (dryRun)\" : \"\"}`);\n return { action };\n}\n\n/**\n * Create a table when missing; when it exists, add any missing columns and\n * indexes from the spec. Never drops or alters existing columns.\n *\n * @param {Function} db\n * @param {string} tableName\n * @param {TableSpec} spec\n * @param {{ dryRun?: boolean, logger?: object }} [options]\n * @returns {Promise<string[]>} human-readable list of applied (or planned) DDL\n */\nexport async function ensureTable(db, tableName, spec, options = {}) {\n const { dryRun = false, logger } = options;\n const actions = [];\n const exists = await db.tableExists(tableName);\n\n if (!exists) {\n actions.push(`CREATE TABLE ${tableName} (${Object.keys(spec.columns).length} columns)`);\n if (!dryRun) {\n await db.schema.createTable(tableName, (t) => {\n for (const define of Object.values(spec.columns)) {\n define(t, db);\n }\n });\n }\n } else {\n // Column-level ensure: add whatever the spec has that the table lacks.\n const missing = [];\n for (const column of Object.keys(spec.columns)) {\n if (!(await db.schema.hasColumn(tableName, column))) {\n missing.push(column);\n }\n }\n if (missing.length > 0) {\n actions.push(`ALTER TABLE ${tableName} ADD COLUMN ${missing.join(\", \")}`);\n if (!dryRun) {\n await db.schema.alterTable(tableName, (t) => {\n for (const column of missing) {\n spec.columns[column](t, db);\n }\n });\n }\n }\n }\n\n for (const index of spec.indexes ?? []) {\n const indexActions = await ensureIndex(db, tableName, index, options);\n actions.push(...indexActions);\n }\n\n for (const action of actions) {\n logger?.silly?.(`[ensure] ${dbLabel(db)}: ${action}${dryRun ? \" (dryRun)\" : \"\"}`);\n }\n return actions;\n}\n\n/**\n * Ensure a (unique) index exists. On PostgreSQL this is a real existence check\n * (`CREATE [UNIQUE] INDEX IF NOT EXISTS`); other dialects fall back to\n * attempt-and-tolerate-\"already exists\".\n *\n * @param {Function} db\n * @param {string} tableName\n * @param {{ columns: string[], name: string, unique?: boolean }} index\n * @param {{ dryRun?: boolean, logger?: object }} [options]\n * @returns {Promise<string[]>}\n */\nexport async function ensureIndex(db, tableName, index, options = {}) {\n const { dryRun = false } = options;\n const kind = index.unique ? \"UNIQUE INDEX\" : \"INDEX\";\n const cols = index.columns.map((c) => `\"${c}\"`).join(\", \");\n const isPg = String(db?.config?.connectionString ?? \"\").startsWith(\"postgresql\");\n\n if (isPg) {\n const sql = `CREATE ${kind} IF NOT EXISTS \"${index.name}\" ON \"${tableName}\" (${cols})`;\n const { rows } = await db.raw(`SELECT 1 FROM pg_indexes WHERE indexname = ?`, [index.name]);\n if (rows.length > 0) return [];\n if (!dryRun) await db.raw(sql);\n return [sql];\n }\n\n // Non-pg fallback: try, and treat \"already exists\" as success.\n const sql = `CREATE ${kind} ${index.name} ON ${tableName} (${cols})`;\n if (!dryRun) {\n try {\n await db.raw(sql);\n } catch (error) {\n if (!/already exists|duplicate/i.test(error?.message ?? \"\")) throw error;\n return [];\n }\n }\n return [sql];\n}\n\n/**\n * Apply a full schema spec to ONE database. Returns the list of applied\n * (or, with dryRun, planned) DDL statements — empty when everything is\n * already in place.\n *\n * @param {Function} db\n * @param {SchemaSpec} spec\n * @param {{ dryRun?: boolean, logger?: object }} [options]\n * @returns {Promise<{ database: string, actions: string[] }>}\n */\nexport async function ensureSchema(db, spec, options = {}) {\n const actions = [];\n for (const extension of spec.extensions ?? []) {\n // Extensions are cheap no-ops when present; report only in dryRun.\n const { action } = await ensureExtension(db, extension, options);\n if (options.dryRun) actions.push(action);\n }\n for (const [tableName, tableSpec] of Object.entries(spec.tables ?? {})) {\n actions.push(...(await ensureTable(db, tableName, tableSpec, options)));\n }\n return { database: dbLabel(db), actions };\n}\n\n/**\n * Apply a schema spec to MANY databases (e.g. the main DB plus every sibling).\n * Convenience loop over {@link ensureSchema} with a combined report and\n * per-database info logging.\n *\n * @param {Function[]} dbs - connected handles (see Db.initAllSiblings)\n * @param {SchemaSpec} spec\n * @param {{ dryRun?: boolean, logger?: object }} [options]\n * @returns {Promise<Array<{ database: string, actions: string[] }>>}\n */\nexport async function ensureSchemaEverywhere(dbs, spec, options = {}) {\n const reports = [];\n for (const db of dbs) {\n const report = await ensureSchema(db, spec, options);\n if (report.actions.length > 0) {\n options.logger?.info?.(\n `[ensure] ${report.database}: ${options.dryRun ? \"would apply\" : \"applied\"} ${report.actions.length} DDL statement(s)`,\n );\n }\n reports.push(report);\n }\n return reports;\n}\n"],"mappings":"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","names":["sql"]}