{"version":3,"sources":["../src/version-check.ts"],"names":[],"mappings":"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","file":"version-check.cjs","sourcesContent":["// What: shared connect-time DB version check.\n// Why: each dialect has version-dependent capabilities (RENAME COLUMN on\n// SQLite 3.25+, transactional DDL on MySQL 8+, etc). This helper hard-fails\n// at connect on real dialects below minimum, lets recognized cloud variants\n// (MariaDB, TiDB, Aurora, PlanetScale, Vitess) proceed with a warning, and\n// hard-fails on completely unparseable strings. F17 in the schema\n// architecture plan.\n\n// Why local imports only: adapter-drizzle is upstream of nextly\n// in the dep graph. Importing from nextly here would create a\n// circular dependency. SupportedDialect and DatabaseError already exist\n// in adapter-drizzle's own type system.\nimport type { SupportedDialect } from \"./types\";\nimport type { DatabaseError } from \"./types/error\";\n\n// Why these minimums: PG 15 ships native MERGE + nbtree dedup needed for\n// our schema rename pipeline. MySQL 8.0 ships native RENAME COLUMN.\n// SQLite 3.38 ships strict tables + native unixepoch(). Older versions\n// would force fallback paths that v1 explicitly does not implement.\nexport const NEXTLY_MIN_DB_VERSIONS = {\n  postgresql: { major: 15, minor: 0 },\n  mysql: { major: 8, minor: 0 },\n  sqlite: { major: 3, minor: 38 },\n} as const;\n\n// What: typed error thrown when a real DB version is below minimum or a\n// version string cannot be parsed.\n// Why: implements adapter-drizzle's DatabaseError interface so existing\n// isDatabaseError() type guards work. Stores dialect + detected/required\n// versions on the instance so callers can build upgrade-guidance UI from\n// the error fields without parsing the message.\nexport class UnsupportedDialectVersionError\n  extends Error\n  implements DatabaseError\n{\n  public readonly kind = \"unsupported_version\" as const;\n  public readonly dialect: SupportedDialect;\n  public readonly detectedVersion: string;\n  public readonly requiredVersion: string;\n  public override readonly cause?: Error;\n\n  constructor(args: {\n    dialect: SupportedDialect;\n    detectedVersion: string;\n    requiredVersion: string;\n    message: string;\n    cause?: Error;\n  }) {\n    super(args.message);\n    this.name = \"UnsupportedDialectVersionError\";\n    this.dialect = args.dialect;\n    this.detectedVersion = args.detectedVersion;\n    this.requiredVersion = args.requiredVersion;\n    this.cause = args.cause;\n  }\n}\n\n// What: minimal duck-typed query interface so this helper does not pull in\n// pg / mysql2 / better-sqlite3 types directly.\n// Why: keeps adapter-drizzle dependency-free of the per-dialect drivers.\n// query() returns unknown because Promise<unknown> is already a subtype of\n// unknown; the helper awaits at the call site, which works for both sync\n// and async return shapes.\nexport interface VersionQueryClient {\n  query?: (sql: string) => unknown;\n  prepare?: (sql: string) => { get: () => unknown };\n}\n\n// What: optional callback so adapters can route the variant warning through\n// their own logger.\n// Why: the helper itself does not depend on a logger module; the adapter\n// owns logger config and is the right place to surface the warning.\nexport interface CheckDialectVersionOptions {\n  onWarning?: (message: string) => void;\n}\n\n// What: doc URL embedded in error messages.\n// Why: gives users a single landing page with upgrade instructions per\n// dialect + cloud provider. Filled in PR-2.\nconst DOCS_URL = \"https://nextlyhq.com/docs/database/support\";\n\n// What: recognized MySQL-protocol-compatible variants. Detection of any of\n// these tokens in the version string causes a warning instead of a hard-\n// fail.\n// Why: these databases speak the MySQL wire protocol but use their own\n// version schemes (MariaDB 10.x, TiDB 6.x advertising MySQL 5.7, Aurora's\n// custom suffix). Hard-failing them would lock out a large fraction of\n// real cloud users on first install. We warn so the user knows we have not\n// regression-tested against their variant; we proceed because the wire\n// protocol is compatible enough that most operations work.\nconst VARIANT_TOKENS = [\n  \"mariadb\",\n  \"tidb\",\n  \"aurora\",\n  \"planetscale\",\n  \"vitess\",\n] as const;\n\nconst POSTGRES_REGEX = /^PostgreSQL (\\d+)\\.(\\d+)/;\nconst MYSQL_REGEX = /^(\\d+)\\.(\\d+)\\.(\\d+)/;\nconst SQLITE_REGEX = /^(\\d+)\\.(\\d+)\\.(\\d+)/;\n\ninterface ParsedVersion {\n  major: number;\n  minor: number;\n}\n\nfunction parsePostgres(raw: string): ParsedVersion | null {\n  const match = POSTGRES_REGEX.exec(raw);\n  if (!match) return null;\n  return { major: Number(match[1]), minor: Number(match[2]) };\n}\n\nfunction parseMySQL(raw: string): ParsedVersion | null {\n  const match = MYSQL_REGEX.exec(raw);\n  if (!match) return null;\n  return { major: Number(match[1]), minor: Number(match[2]) };\n}\n\nfunction parseSQLite(raw: string): ParsedVersion | null {\n  const match = SQLITE_REGEX.exec(raw);\n  if (!match) return null;\n  return { major: Number(match[1]), minor: Number(match[2]) };\n}\n\nfunction detectVariant(raw: string): string | null {\n  const lower = raw.toLowerCase();\n  for (const token of VARIANT_TOKENS) {\n    if (lower.includes(token)) return token;\n  }\n  return null;\n}\n\n// What: compares detected version to required minimum.\n// Why: simple major-minor comparison is sufficient; we do not gate on patch.\nfunction meetsMinimum(\n  detected: ParsedVersion,\n  required: { major: number; minor: number }\n): boolean {\n  if (detected.major > required.major) return true;\n  if (detected.major < required.major) return false;\n  return detected.minor >= required.minor;\n}\n\n// What: queries the DB for its version string and validates it under the\n// hybrid policy.\n// Why: called as the first DB-content step inside each adapter's connect()\n// method.\n//\n// Decision tree:\n//   1. Variant token present (MariaDB/TiDB/Aurora/PlanetScale/Vitess)?\n//      -> emit warning via options.onWarning, return successfully.\n//   2. Strict regex matches and version >= minimum?\n//      -> return successfully.\n//   3. Strict regex matches but version < minimum?\n//      -> throw UnsupportedDialectVersionError (real-DB-too-old path).\n//   4. Strict regex does not match AND no variant token detected?\n//      -> throw UnsupportedDialectVersionError (truly unparseable path).\nexport async function checkDialectVersion(\n  client: VersionQueryClient,\n  dialect: SupportedDialect,\n  options?: CheckDialectVersionOptions\n): Promise<void> {\n  const required = NEXTLY_MIN_DB_VERSIONS[dialect];\n  const requiredStr = `${required.major}.${required.minor}+`;\n\n  let raw: string;\n  if (dialect === \"sqlite\") {\n    raw = await querySqliteVersion(client);\n  } else if (dialect === \"postgresql\") {\n    raw = await queryPostgresVersion(client);\n  } else {\n    raw = await queryMysqlVersion(client);\n  }\n\n  // Step 1: variant check. Only meaningful for MySQL — Postgres-flavored\n  // services (Neon, Supabase, RDS PG, Aurora PG) all return canonical\n  // \"PostgreSQL X.Y...\" strings and pass the strict regex naturally.\n  const variant = dialect === \"mysql\" ? detectVariant(raw) : null;\n  if (variant) {\n    const warning =\n      `Detected ${variant} ('${raw}'). Nextly is regression-tested ` +\n      `against real MySQL 8.0+ only; this MySQL-compatible variant is not ` +\n      `officially supported in v1 but most operations should work. ` +\n      `See ${DOCS_URL}.`;\n    if (options?.onWarning) options.onWarning(warning);\n    return;\n  }\n\n  // Step 2/3: strict regex parse for real dialects.\n  let parsed: ParsedVersion | null;\n  if (dialect === \"postgresql\") parsed = parsePostgres(raw);\n  else if (dialect === \"mysql\") parsed = parseMySQL(raw);\n  else parsed = parseSQLite(raw);\n\n  if (!parsed) {\n    // Step 4: truly unparseable. Hard-fail so we surface the issue at boot\n    // rather than silently letting the user proceed and hit cryptic errors\n    // later.\n    throw new UnsupportedDialectVersionError({\n      dialect,\n      detectedVersion: raw,\n      requiredVersion: requiredStr,\n      message:\n        `Could not parse ${dialect} version from '${raw}'. ` +\n        `Nextly requires ${dialect} ${requiredStr}. ` +\n        `If you are on a known MySQL-compatible variant we did not detect, ` +\n        `please file an issue. See ${DOCS_URL}.`,\n    });\n  }\n\n  if (!meetsMinimum(parsed, required)) {\n    const labels: Record<SupportedDialect, string> = {\n      postgresql: \"PostgreSQL\",\n      mysql: \"MySQL\",\n      sqlite: \"SQLite\",\n    };\n    throw new UnsupportedDialectVersionError({\n      dialect,\n      detectedVersion: `${parsed.major}.${parsed.minor}`,\n      requiredVersion: requiredStr,\n      message:\n        `${labels[dialect]} ${requiredStr} required; detected ` +\n        `${parsed.major}.${parsed.minor}. See ${DOCS_URL}.`,\n    });\n  }\n}\n\n// What: PG version query.\n// Why: pg's Client/PoolClient.query() returns { rows: [{ version: \"...\" }] }.\nasync function queryPostgresVersion(\n  client: VersionQueryClient\n): Promise<string> {\n  if (!client.query) {\n    throw new Error(\"PostgreSQL client missing query() method\");\n  }\n  const result = (await client.query(\"SELECT version()\")) as {\n    rows?: Array<{ version?: unknown }>;\n  };\n  const row = result.rows?.[0];\n  const version = row?.version;\n  if (typeof version !== \"string\") {\n    throw new Error(\n      `Unexpected response shape from SELECT version(): ${JSON.stringify(result)}`\n    );\n  }\n  return version;\n}\n\n// What: MySQL version query.\n// Why: mysql2's Connection.query() returns [rows, fields] where rows[0]\n// has the column aliased as 'version'.\nasync function queryMysqlVersion(client: VersionQueryClient): Promise<string> {\n  if (!client.query) {\n    throw new Error(\"MySQL client missing query() method\");\n  }\n  const result = (await client.query(\"SELECT VERSION() AS version\")) as Array<\n    Array<{ version?: unknown }>\n  >;\n  const row = result?.[0]?.[0];\n  const version = row?.version;\n  if (typeof version !== \"string\") {\n    throw new Error(\n      `Unexpected response shape from SELECT VERSION(): ${JSON.stringify(result)}`\n    );\n  }\n  return version;\n}\n\n// What: SQLite version query via better-sqlite3's prepare/get.\n// Why: better-sqlite3 is synchronous, so this is a plain function returning\n// a resolved Promise. The helper awaits it uniformly with PG/MySQL paths.\nfunction querySqliteVersion(client: VersionQueryClient): Promise<string> {\n  if (!client.prepare) {\n    return Promise.reject(new Error(\"SQLite client missing prepare() method\"));\n  }\n  const stmt = client.prepare(\"SELECT sqlite_version() AS version\");\n  const row = stmt.get() as { version?: unknown } | undefined;\n  const version = row?.version;\n  if (typeof version !== \"string\") {\n    return Promise.reject(\n      new Error(\n        `Unexpected response shape from SELECT sqlite_version(): ${JSON.stringify(row)}`\n      )\n    );\n  }\n  return Promise.resolve(version);\n}\n"]}