{"version":3,"file":"src-_M69mn2G.mjs","names":["emitChange","emitCreateTable","emitAddIndex","emitAddFk","emitColumnDecl","FK_ACTIONS","DEFAULT_EXCLUDED","readColumns","readIndexes","readForeignKeys","normalizeType","mapFkAction","DEFAULT_EXCLUDED","readColumns","readIndexes","readForeignKeys","normalizeType","mapFkAction","emitChange","emitCreateTable","emitColumnDecl","emitAddIndex","FK_ACTIONS","jsonArrayFrom","jsonObjectFrom","jsonArrayFrom","jsonObjectFrom","#transformer","_exhaustive"],"sources":["../src/errors.ts","../src/query/errors.ts","../src/query/extract-relations.ts","../src/snapshot/extract.ts","../src/snapshot/render.ts","../src/diff/engine.ts","../src/diff/invert.ts","../src/diff/composite-detect.ts","../src/migrate/errors.ts","../src/emit/identifiers.ts","../src/emit/alter-type.ts","../src/emit/pg.ts","../src/migrate/enum-drop-gate.ts","../src/migrate/journal.ts","../src/migrate/schema.ts","../src/migrate/memory-adapter.ts","../src/migrate/introspect-pg.ts","../src/migrate/introspect-sqlite.ts","../src/migrate/introspect-mysql.ts","../src/emit/sqlite.ts","../src/emit/mysql.ts","../src/migrate/drift.ts","../src/migrate/runner.ts","../src/adapter.ts","../src/tokens.ts","../src/client/events.ts","../src/dsl/columns/types.ts","../src/custom-type.ts","../src/client/codec-plugin.ts","../src/extend/result-plugin.ts","../src/extend/apply.ts","../src/query/builder.ts","../src/client/wrap.ts","../src/dialect-marker.ts","../src/query/compile-shared.ts","../src/query/compile-pg.ts","../src/query/compile-sqlite.ts","../src/query/compile-mysql.ts","../src/query/compilers.ts","../src/client/create.ts","../src/client/plugins.ts","../src/migrate/review.ts","../src/cli/config.ts","../src/cli/generate.ts","../src/dsl/columns/builders.ts","../src/dsl/table.ts","../src/dsl/constraints.ts","../src/dsl/relations.ts","../src/query/like.ts"],"sourcesContent":["export class KickDbError extends Error {\n  readonly code: string\n\n  constructor(code: string, message: string) {\n    super(message)\n    this.name = this.constructor.name\n    this.code = code\n  }\n}\n\n/**\n * Thrown by `kick db generate` when the diff would emit a\n * `removeEnumValue` change against a column whose default is one of\n * the values being removed. The rename-recreate dance preserves\n * column DEFAULTs through the type swap (M5.A.1), but it can't\n * preserve a default that's no longer in the enum's value list — the\n * `SET DEFAULT 'X'::\"foo\"` step would fail at apply time.\n *\n * The operator's options: change the column's default in the schema\n * to a value that survives the removal, or drop the default entirely.\n *\n * Spec: docs/db/spec-default-preservation.md.\n */\nexport class RemovedValueAsDefaultError extends KickDbError {\n  readonly enum: string\n  readonly table: string\n  readonly column: string\n  readonly value: string\n\n  constructor(enumName: string, table: string, column: string, value: string) {\n    super(\n      'removed_value_as_default',\n      `Cannot remove value '${value}' from enum '${enumName}': the column ` +\n        `${table}.${column} declares it as the default. Update the column's ` +\n        `default to a surviving enum value (or drop the default) before ` +\n        `re-running \\`kick db generate\\`.`,\n    )\n    this.enum = enumName\n    this.table = table\n    this.column = column\n    this.value = value\n  }\n}\n","/**\n * Errors thrown by the relational-query compiler. All extend\n * `KickDbError` so adopters can catch the family with a single\n * `instanceof` check.\n *\n * Spec: docs/db/spec-relational-query.md §6 (edge cases) + §7 (R-3,\n * R-5).\n */\n\nimport { KickDbError } from '../errors'\n\n/**\n * Thrown at compile time when a `with` key references a relation\n * that the source table doesn't declare.\n */\nexport class RelationalQueryUnknownRelationError extends KickDbError {\n  readonly sourceTable: string\n  readonly relationKey: string\n  constructor(sourceTable: string, relationKey: string) {\n    super(\n      'KICK_DB_RELATIONAL_UNKNOWN_RELATION',\n      `Unknown relation \\`${sourceTable}.${relationKey}\\` — declare it via \\`relations()\\` ` +\n        `before referencing it inside \\`db.query.${sourceTable}.findMany({ with })\\`.`,\n    )\n    this.sourceTable = sourceTable\n    this.relationKey = relationKey\n  }\n}\n\n/**\n * Thrown at compile time when a `with` clause nests deeper than\n * `maxDepth` (spec §7 R-3, default 5). Catches infinite specs on\n * self-referencing tables before any SQL is built.\n */\nexport class RelationalQueryDepthError extends KickDbError {\n  readonly maxDepth: number\n  readonly trace: readonly string[]\n  constructor(maxDepth: number, trace: readonly string[]) {\n    super(\n      'KICK_DB_RELATIONAL_DEPTH_EXCEEDED',\n      `Relational query exceeds maxDepth=${maxDepth}. Path: ${trace.join(' → ')}. ` +\n        `Override with \\`{ maxDepth: N }\\` on the call site if intentional.`,\n    )\n    this.maxDepth = maxDepth\n    this.trace = trace\n  }\n}\n\n/**\n * Thrown at compile time when a relation name collides with a\n * literal column on the same table (spec §7 R-5). Forces the schema\n * author to rename one of them so the LATERAL alias stays\n * unambiguous.\n */\nexport class RelationalQueryAliasCollisionError extends KickDbError {\n  readonly sourceTable: string\n  readonly conflictingName: string\n  constructor(sourceTable: string, conflictingName: string) {\n    super(\n      'KICK_DB_RELATIONAL_ALIAS_COLLISION',\n      `Relation \\`${sourceTable}.${conflictingName}\\` collides with a column of the same name. ` +\n        `Rename the relation or the column to disambiguate.`,\n    )\n    this.sourceTable = sourceTable\n    this.conflictingName = conflictingName\n  }\n}\n\n/**\n * Thrown by `db.query.X.find{Many,First,Unique}` when an\n * `AbortSignal` passed via options fires (or is already aborted at\n * call time). Wraps the underlying cause — typically a DOMException\n * with `name === 'AbortError'`, or whatever the caller passed to\n * `AbortController.abort(reason)` — on the `cause` field for adopter\n * inspection (e.g. distinguishing HTTP timeout from explicit\n * cancellation from user-disconnect).\n *\n * Spec: docs/db/spec-abortsignal-threading.md.\n */\nexport class RelationalQueryCancelledError extends KickDbError {\n  readonly cause?: unknown\n\n  constructor(cause?: unknown) {\n    const reasonText = formatCancelCause(cause)\n    super(\n      'relational_query_cancelled',\n      `Relational query cancelled by AbortSignal${reasonText ? ` — ${reasonText}` : '.'}`,\n    )\n    this.cause = cause\n  }\n}\n\nfunction formatCancelCause(cause: unknown): string {\n  if (cause == null) return ''\n  if (cause instanceof Error) return cause.message\n  if (typeof cause === 'string') return cause\n  try {\n    return JSON.stringify(cause)\n  } catch {\n    return String(cause)\n  }\n}\n\n/**\n * Thrown by SQLite + MySQL compiler stubs in v1. The interface ships\n * with PG only; the other dialects fill in during M4 without an API\n * change at the call site.\n */\nexport class RelationalQueryNotSupportedError extends KickDbError {\n  readonly dialect: string\n  constructor(dialect: string) {\n    super(\n      'KICK_DB_RELATIONAL_NOT_SUPPORTED',\n      `Relational query compiler for dialect \\`${dialect}\\` lands in M4. ` +\n        `Use layer 1 / 2 (\\`db.selectFrom(...)\\`) with manual joins for now.`,\n    )\n    this.dialect = dialect\n  }\n}\n\n/**\n * Thrown at extract time when more than one inverse `one` declared\n * on the **target** table shares the same `relationName` AND points\n * back at the same source — the actual ambiguity case for resolver\n * step 1. Scope is per `(sourceTable, targetTable, relationName)`:\n * the same tag can be reused across unrelated table pairs. Spec:\n * docs/db/spec-relation-name.md §7 R-2.\n */\nexport class RelationalQueryAmbiguousRelationNameError extends KickDbError {\n  readonly sourceTable: string\n  readonly targetTable: string\n  readonly relationName: string\n  /** Relation keys on the target table whose inverse `one` shares the tag. */\n  readonly conflicting: readonly string[]\n  constructor(\n    sourceTable: string,\n    targetTable: string,\n    relationName: string,\n    conflicting: readonly string[],\n  ) {\n    super(\n      'KICK_DB_RELATIONAL_AMBIGUOUS_RELATION_NAME',\n      `Cannot pair \\`${sourceTable}\\`'s \\`many\\` with relationName='${relationName}' — ` +\n        `multiple \\`one\\` relations on \\`${targetTable}\\` share that tag and point back at ` +\n        `\\`${sourceTable}\\` (${conflicting.map((c) => `\\`${targetTable}.${c}\\``).join(', ')}). ` +\n        `The pairing tag must be unique per (source, target, name) triple — rename one of the ` +\n        `\\`one\\` relations on \\`${targetTable}\\` or split the schema.`,\n    )\n    this.sourceTable = sourceTable\n    this.targetTable = targetTable\n    this.relationName = relationName\n    this.conflicting = conflicting\n  }\n}\n\n/**\n * Thrown at extract time when a `many` relation has no inverse\n * `one` declared on the target table. The compiler needs the FK\n * column pair to build the join predicate; without an inverse we\n * have no way to discover it. Adopters fix by declaring the inverse\n * `one` on the target side (drizzle-style symmetric declarations).\n */\nexport class RelationalQueryMissingInverseError extends KickDbError {\n  readonly sourceTable: string\n  readonly relationName: string\n  readonly targetTable: string\n  constructor(sourceTable: string, relationName: string, targetTable: string) {\n    super(\n      'KICK_DB_RELATIONAL_MISSING_INVERSE',\n      `Cannot resolve \\`many\\` relation \\`${sourceTable}.${relationName}\\` — ` +\n        `no inverse \\`one\\` relation declared on \\`${targetTable}\\` pointing back to \\`${sourceTable}\\`, ` +\n        `and ${targetTable}'s foreign keys to ${sourceTable} are either zero or ambiguous. ` +\n        `If the target has multiple FKs to the source, tag both sides with the same ` +\n        `\\`relationName: 'foo'\\` to pair them — see docs/db/spec-relation-name.md. ` +\n        `Otherwise add e.g. \\`relations(${targetTable}, h => ({ ${sourceTable}: h.one(${sourceTable}, { fields: [${targetTable}.${sourceTable}Id], references: [${sourceTable}.id] }) }))\\` ` +\n        `so the compiler knows which columns join the two tables.`,\n    )\n    this.sourceTable = sourceTable\n    this.relationName = relationName\n    this.targetTable = targetTable\n  }\n}\n","/**\n * Resolve `relations()` declarations into the JSON-serializable\n * sidecar shape consumed by the relational-query compiler.\n *\n *  - `one` relations resolve straight from `RelationOne.{fields,\n *    references}`.\n *  - `many` relations resolve via the inverse `one` on the target\n *    table — drizzle-style symmetric declarations. If no inverse\n *    exists, throw `RelationalQueryMissingInverseError` at extract\n *    time so adopters get a clear error before the schema ships.\n *  - Alias collisions (a relation name that shadows a column on the\n *    same table) throw `RelationalQueryAliasCollisionError` per spec\n *    §7 R-5.\n *\n * Spec: docs/db/spec-relational-query.md §5.3.\n */\n\nimport type { Relation, RelationOne, RelationsDecl } from '../dsl/relations'\nimport type { TableSnapshot } from '../snapshot/types'\nimport type { ResolvedRelations } from './relations'\nimport {\n  RelationalQueryAliasCollisionError,\n  RelationalQueryAmbiguousRelationNameError,\n  RelationalQueryMissingInverseError,\n} from './errors'\n\ninterface MaybeRelations {\n  __isRelations?: boolean\n  __sourceTable?: string\n  __relations?: Record<string, Relation>\n}\n\nfunction isRelations(v: unknown): v is RelationsDecl {\n  return Boolean(v && typeof v === 'object' && (v as MaybeRelations).__isRelations === true)\n}\n\n/**\n * Walk the schema record for `RelationsDecl` entries and return the\n * resolved sidecar. Returns `undefined` when no relations are\n * declared so callers can leave the snapshot's `relations` field\n * absent.\n */\nexport function extractRelations(\n  schema: Record<string, unknown>,\n  tables: Record<string, TableSnapshot>,\n): ResolvedRelations | undefined {\n  const declsBySource: Record<string, Record<string, Relation>> = {}\n\n  for (const value of Object.values(schema)) {\n    if (isRelations(value)) {\n      // A second `relations()` call against the same source merges —\n      // adopters can split one large declaration across files. Last\n      // writer wins on duplicate keys.\n      declsBySource[value.__sourceTable] = {\n        ...declsBySource[value.__sourceTable],\n        ...value.__relations,\n      }\n    }\n  }\n\n  if (Object.keys(declsBySource).length === 0) return undefined\n\n  const out: ResolvedRelations = {}\n\n  for (const [sourceTable, relations] of Object.entries(declsBySource)) {\n    const tableSnapshot = tables[sourceTable]\n    // Ignore relations declared against an unknown table — `extract`\n    // already skips non-table entries; mismatched relations() calls\n    // get the same treatment rather than throwing on a typo.\n    if (!tableSnapshot) continue\n\n    out[sourceTable] = {}\n\n    for (const [relationName, rel] of Object.entries(relations)) {\n      if (relationName in tableSnapshot.columns) {\n        throw new RelationalQueryAliasCollisionError(sourceTable, relationName)\n      }\n\n      if (rel.kind === 'one') {\n        out[sourceTable][relationName] = {\n          kind: 'one',\n          target: rel.target.__name,\n          sourceColumns: rel.fields.map((f) => f.__name),\n          targetColumns: rel.references.map((r) => r.__name),\n          ...(rel.relationName !== undefined ? { relationName: rel.relationName } : {}),\n        }\n        continue\n      }\n\n      // `many` resolution precedence (spec-relation-name.md §4):\n      //   1. `relationName` match — both sides declared.\n      //   2. Single untagged inverse `one` — exactly one + neither\n      //      side has a relationName.\n      //   3. FK introspection — exactly one FK back to source.\n      //   4. Throw MissingInverseError with hint.\n      const target = rel.target.__name\n      const targetRelations = declsBySource[target] ?? {}\n\n      // Preserve the source-side `relationName` on the resolved\n      // sidecar regardless of which step ends up resolving the join.\n      // The tag is part of the public surface (RelationSnapshot /\n      // RelationMapEntry) and shouldn't drop just because step 1 fell\n      // through to step 2/3.\n      const relNameSpread = rel.relationName !== undefined ? { relationName: rel.relationName } : {}\n\n      // Step 1 — paired by relationName.\n      if (rel.relationName !== undefined) {\n        const matchingInverses = findInversesByRelationName(\n          targetRelations,\n          sourceTable,\n          rel.relationName,\n        )\n        if (matchingInverses.length > 1) {\n          throw new RelationalQueryAmbiguousRelationNameError(\n            sourceTable,\n            target,\n            rel.relationName,\n            matchingInverses.map((m) => m.relationKey),\n          )\n        }\n        if (matchingInverses.length === 1) {\n          const inverse = matchingInverses[0]!.relation\n          out[sourceTable][relationName] = {\n            kind: 'many',\n            target,\n            sourceColumns: inverse.references.map((r) => r.__name),\n            targetColumns: inverse.fields.map((f) => f.__name),\n            ...relNameSpread,\n          }\n          continue\n        }\n        // Tagged on this side but no matching inverse — fall through\n        // to FK fallback so the eventual error message lists what\n        // the resolver looked at.\n      }\n\n      // Step 2 — single untagged inverse `one`.\n      const untaggedInverse = findUniqueUntaggedInverse(targetRelations, sourceTable)\n      if (untaggedInverse) {\n        out[sourceTable][relationName] = {\n          kind: 'many',\n          target,\n          sourceColumns: untaggedInverse.references.map((r) => r.__name),\n          targetColumns: untaggedInverse.fields.map((f) => f.__name),\n          ...relNameSpread,\n        }\n        continue\n      }\n\n      // Step 3 — FK introspection fallback.\n      const fkFallback = resolveByForeignKey(tables[target], sourceTable)\n      if (fkFallback) {\n        out[sourceTable][relationName] = {\n          kind: 'many',\n          target,\n          sourceColumns: fkFallback.refColumns,\n          targetColumns: fkFallback.columns,\n          ...relNameSpread,\n        }\n        continue\n      }\n\n      // Step 4 — give up.\n      throw new RelationalQueryMissingInverseError(sourceTable, relationName, target)\n    }\n  }\n\n  return out\n}\n\n/**\n * Step-1 helper — find inverse `one` declarations on the target\n * table whose `relationName` matches the requested tag AND whose\n * own target is the source. Returns the relation key alongside the\n * relation itself so the ambiguous-error message can list the\n * conflicting names.\n */\nfunction findInversesByRelationName(\n  targetRelations: Record<string, Relation>,\n  sourceTable: string,\n  relationName: string,\n): Array<{ relationKey: string; relation: RelationOne }> {\n  const matches: Array<{ relationKey: string; relation: RelationOne }> = []\n  for (const [key, rel] of Object.entries(targetRelations)) {\n    if (\n      rel.kind === 'one' &&\n      rel.target.__name === sourceTable &&\n      rel.relationName === relationName\n    ) {\n      matches.push({ relationKey: key, relation: rel })\n    }\n  }\n  return matches\n}\n\n/**\n * Step-2 helper — find a single inverse `one` on the target table\n * pointing at the source AND with **no** `relationName` set. The\n * uniqueness check is the M4.B tightening of M3's first-match\n * heuristic; multi-FK schemas now surface as `MissingInverseError`\n * (which routes adopters at adding `relationName`) instead of\n * silently picking the first inverse.\n */\nfunction findUniqueUntaggedInverse(\n  targetRelations: Record<string, Relation>,\n  sourceTable: string,\n): RelationOne | null {\n  let unique: RelationOne | null = null\n  for (const rel of Object.values(targetRelations)) {\n    if (rel.kind === 'one' && rel.target.__name === sourceTable && rel.relationName === undefined) {\n      if (unique) return null // ambiguous — caller falls through\n      unique = rel\n    }\n  }\n  return unique\n}\n\n/**\n * Fallback resolution path for `many` relations without an inverse\n * `one`. Walks the target table's FK list for a single edge back to\n * the source. Returns `null` when there is no FK or when more than\n * one FK qualifies — adopters with ambiguous schemas need the\n * explicit inverse to disambiguate.\n */\nfunction resolveByForeignKey(\n  targetTable: TableSnapshot | undefined,\n  sourceTable: string,\n): { columns: readonly string[]; refColumns: readonly string[] } | null {\n  if (!targetTable) return null\n  const matches = targetTable.foreignKeys.filter((fk) => fk.refTable === sourceTable)\n  if (matches.length !== 1) return null\n  const fk = matches[0]!\n  return { columns: fk.columns, refColumns: fk.refColumns }\n}\n","import type { ColumnBuilder } from '../dsl/columns/types'\nimport type { TableDecl } from '../dsl/table'\nimport { extractRelations } from '../query/extract-relations'\nimport type {\n  Dialect,\n  EnumSnapshot,\n  ForeignKeySnapshot,\n  IndexSnapshot,\n  SchemaSnapshot,\n  TableSnapshot,\n} from './types'\n\ninterface MaybeTable {\n  __isTable?: boolean\n  __name?: string\n  __columns?: Record<string, ColumnBuilder>\n  __indexes?: IndexSnapshot[]\n}\n\nfunction isTable(v: unknown): v is TableDecl<string, Record<string, ColumnBuilder>> {\n  return Boolean(v && typeof v === 'object' && (v as MaybeTable).__isTable === true)\n}\n\n/**\n * pgEnum() returns a function with `enumName` + `values` attached.\n * Detect via duck-typing rather than `instanceof` so the snapshot\n * code stays decoupled from the PG-specific module — the snapshot\n * pipeline runs for every dialect.\n */\ninterface MaybePgEnum {\n  enumName?: unknown\n  values?: unknown\n}\n\nfunction isPgEnum(v: unknown): v is { enumName: string; values: readonly string[] } {\n  if (typeof v !== 'function') return false\n  const f = v as MaybePgEnum\n  return typeof f.enumName === 'string' && Array.isArray(f.values)\n}\n\nexport function extractSnapshot(schema: Record<string, unknown>, dialect: Dialect): SchemaSnapshot {\n  const tables: Record<string, TableSnapshot> = {}\n  const enums: Record<string, EnumSnapshot> = {}\n\n  for (const value of Object.values(schema)) {\n    if (isTable(value)) {\n      tables[value.__name] = extractTable(value)\n    } else if (isPgEnum(value)) {\n      enums[value.enumName] = { name: value.enumName, values: [...value.values] }\n    }\n  }\n\n  const relations = extractRelations(schema, tables)\n\n  // Only carry `enums` on PG snapshots — other dialects don't define\n  // them and an empty record would just bloat the diff output.\n  // `relations` is dialect-agnostic (query-time sugar) but we still\n  // omit it when absent to keep snapshots minimal for adopters who\n  // don't use the relational query layer.\n  const snapshot: SchemaSnapshot = { version: 1, dialect, tables }\n  if (dialect === 'postgres' && Object.keys(enums).length > 0) {\n    snapshot.enums = enums\n  }\n  if (relations) {\n    snapshot.relations = relations\n  }\n  return snapshot\n}\n\nfunction extractTable(t: TableDecl<string, Record<string, ColumnBuilder>>): TableSnapshot {\n  const columns: TableSnapshot['columns'] = {}\n  const indexes: IndexSnapshot[] = [...t.__indexes]\n  const foreignKeys: ForeignKeySnapshot[] = []\n\n  for (const [colKey, builder] of Object.entries(t.__columns)) {\n    columns[colKey] = builder.toJSON(colKey)\n    const state = builder.__state()\n    if (state.unique) {\n      indexes.push({\n        name: `${t.__name}_${colKey}_unique`,\n        columns: [colKey],\n        unique: true,\n      })\n    }\n    if (state.references) {\n      // Resolve the FK thunk lazily — by extract time the table const has\n      // been bound, so self-references (`() => self.id`) work.\n      const ref = state.references.thunk()\n      foreignKeys.push({\n        name: `${t.__name}_${colKey}_fk`,\n        columns: [colKey],\n        refTable: ref.__tableName,\n        refColumns: [ref.__name],\n        onDelete: state.references.onDelete,\n        onUpdate: state.references.onUpdate,\n      })\n    }\n  }\n\n  return { name: t.__name, columns, indexes, foreignKeys, checks: [] }\n}\n","import type {\n  ColumnSnapshot,\n  ForeignKeySnapshot,\n  IndexSnapshot,\n  SchemaSnapshot,\n  TableSnapshot,\n} from './types'\n\n/**\n * Render a SchemaSnapshot to TypeScript source matching the kickjs-db DSL.\n * Inverse of extractSnapshot().\n *\n * Naming: tables become exported `const`s with the same name. Constants\n * starting with digits get an underscore prefix to stay JS-valid.\n *\n * Limits (M1 — refined in M2/M3):\n *   - No relations() emission. Adopter adds them manually post-introspect.\n *   - No checks (M1 doesn't model CHECK constraints in the snapshot).\n *   - Default values pass through as-is. The DSL accepts string defaults,\n *     so 'true' / 'CURRENT_TIMESTAMP' / \"'foo'\" all round-trip.\n *   - Auto-derived constraint names (`<table>_<col>_unique`, `<table>_<col>_fk`)\n *     are detected and rendered as the chained .unique() / .references() form.\n *     Custom-named constraints fall back to the third-arg callback / FK helper.\n */\nexport function renderSchemaSource(snapshot: SchemaSnapshot): string {\n  const usedColumnHelpers = new Set<string>()\n  const tableSources: string[] = []\n\n  // First pass: render every table, accumulating which column helpers we used.\n  for (const table of Object.values(snapshot.tables)) {\n    tableSources.push(renderTable(table, usedColumnHelpers))\n  }\n\n  const helpers = ['table', ...Array.from(usedColumnHelpers).toSorted()]\n  // Common constraint helpers used by tables with secondary objects.\n  const needsIndex = Object.values(snapshot.tables).some((t) =>\n    t.indexes.some((i) => !isAutoUniqueName(t.name, i)),\n  )\n  if (needsIndex) helpers.push('index')\n  const needsUnique = Object.values(snapshot.tables).some((t) =>\n    t.indexes.some((i) => i.unique && !isAutoUniqueName(t.name, i)),\n  )\n  if (needsUnique && !helpers.includes('unique')) helpers.push('unique')\n\n  const importLine = `import { ${helpers.join(', ')} } from '@forinda/kickjs-db'`\n  return [importLine, '', ...tableSources].join('\\n').trimEnd() + '\\n'\n}\n\nfunction renderTable(table: TableSnapshot, helpers: Set<string>): string {\n  const ident = jsIdent(table.name)\n  const columns: string[] = []\n  for (const col of Object.values(table.columns)) {\n    const fk = table.foreignKeys.find(\n      (f) =>\n        f.columns.length === 1 &&\n        f.columns[0] === col.name &&\n        f.name === `${table.name}_${col.name}_fk`,\n    )\n    const inlineUnique =\n      table.indexes.find(\n        (i) =>\n          i.unique &&\n          i.columns.length === 1 &&\n          i.columns[0] === col.name &&\n          isAutoUniqueName(table.name, i),\n      ) !== undefined\n    columns.push(`  ${jsKey(col.name)}: ${renderColumn(col, helpers, fk, inlineUnique)},`)\n  }\n\n  // Constraints that don't fit on a column chain.\n  const explicitIndexes = table.indexes.filter((i) => !isAutoUniqueName(table.name, i))\n  const explicitFks = table.foreignKeys.filter(\n    (f) => f.name !== `${table.name}_${f.columns[0]}_fk` || f.columns.length !== 1,\n  )\n\n  const hasThirdArg = explicitIndexes.length > 0\n  const tableArgs: string[] = [`'${table.name}'`, `{\\n${columns.join('\\n')}\\n}`]\n\n  if (hasThirdArg) {\n    const callbacks = explicitIndexes\n      .map((i) => `    ${jsKey(i.name)}: ${renderIndexCall(i)}`)\n      .join(',\\n')\n    tableArgs.push(`(t) => ({\\n${callbacks},\\n  })`)\n  }\n\n  let src = `export const ${ident} = table(${tableArgs.join(', ')})`\n\n  // Explicit FKs that don't fit the auto-derived <table>_<col>_fk pattern get\n  // logged as TODO comments — adopter handles them manually. M3 may upgrade\n  // this to emit a separate ALTER snippet.\n  if (explicitFks.length > 0) {\n    src +=\n      '\\n// TODO: kick db introspect — composite or custom-named foreign keys not auto-rendered:\\n'\n    for (const f of explicitFks) {\n      src += `// ${f.name}: (${f.columns.join(', ')}) → ${f.refTable}(${f.refColumns.join(', ')})\\n`\n    }\n  }\n\n  return src\n}\n\nfunction renderColumn(\n  col: ColumnSnapshot,\n  helpers: Set<string>,\n  fk: ForeignKeySnapshot | undefined,\n  inlineUnique: boolean,\n): string {\n  const { helperName, args } = pickColumnHelper(col)\n  helpers.add(helperName)\n\n  let chain = `${helperName}(${args})`\n  if (col.primaryKey) chain += '.primaryKey()'\n  if (!col.primaryKey && !col.nullable) chain += '.notNull()'\n  if (col.default !== null) chain += `.default(${JSON.stringify(col.default)})`\n  if (inlineUnique) chain += '.unique()'\n  if (fk) {\n    const ref = `${jsIdent(fk.refTable)}.${jsIdent(fk.refColumns[0])}`\n    const onDelete = fk.onDelete === 'no_action' ? '' : `, { onDelete: '${fk.onDelete}' }`\n    chain += `.references(() => ${ref}${onDelete})`\n  }\n  return chain\n}\n\nfunction pickColumnHelper(col: ColumnSnapshot): { helperName: string; args: string } {\n  // Strip array suffix; render as base type + .array() chain in renderColumn\n  // (M2 — for now arrays land as a literal `<T>[]` type which the DSL doesn't\n  // round-trip). For M1, just pick the closest helper.\n  const t = col.type\n\n  if (t === 'serial') return { helperName: 'serial', args: '' }\n  if (t === 'bigserial') return { helperName: 'bigSerial', args: '' }\n  if (t === 'smallserial') return { helperName: 'serial', args: '' }\n  if (t === 'integer') return { helperName: 'integer', args: '' }\n  if (t === 'bigint') return { helperName: 'bigint', args: '' }\n  if (t === 'smallint') return { helperName: 'smallint', args: '' }\n  if (t === 'real') return { helperName: 'real', args: '' }\n  if (t === 'double precision') return { helperName: 'doublePrecision', args: '' }\n  if (/^numeric(\\(.+\\))?$/.test(t)) return { helperName: 'numeric', args: extractParens(t) }\n  if (/^varchar(\\(\\d+\\))?$/.test(t)) return { helperName: 'varchar', args: extractParens(t) }\n  if (/^char(\\(\\d+\\))?$/.test(t)) return { helperName: 'char', args: extractParens(t) }\n  if (t === 'text') return { helperName: 'text', args: '' }\n  if (t === 'boolean') return { helperName: 'boolean', args: '' }\n  if (t === 'timestamp') return { helperName: 'timestamp', args: '' }\n  if (t === 'timestamptz') return { helperName: 'timestamptz', args: '' }\n  if (t === 'date') return { helperName: 'date', args: '' }\n  if (t === 'time') return { helperName: 'time', args: '' }\n  if (t === 'interval') return { helperName: 'interval', args: '' }\n  if (t === 'uuid') return { helperName: 'uuid', args: '' }\n  if (t === 'jsonb') return { helperName: 'jsonb', args: '' }\n  if (t === 'json') return { helperName: 'json', args: '' }\n  if (t === 'bytea') return { helperName: 'bytea', args: '' }\n\n  // Fallback: emit as a comment + placeholder text() so the file still\n  // parses. Adopter edits to the right helper.\n  return { helperName: 'text', args: `/* TODO: ${t} */` }\n}\n\nfunction extractParens(t: string): string {\n  const m = t.match(/\\(([^)]+)\\)/)\n  return m ? m[1] : ''\n}\n\nfunction renderIndexCall(idx: IndexSnapshot): string {\n  const helper = idx.unique ? 'unique' : 'index'\n  const cols = idx.columns.map((c) => `t.${jsIdent(c)}`).join(', ')\n  return `${helper}('${idx.name}').on(${cols})`\n}\n\nfunction isAutoUniqueName(tableName: string, idx: IndexSnapshot): boolean {\n  return (\n    idx.unique && idx.columns.length === 1 && idx.name === `${tableName}_${idx.columns[0]}_unique`\n  )\n}\n\n/** Make a JS-safe identifier from a snake_case column/table name. */\nfunction jsIdent(raw: string): string {\n  if (/^[A-Za-z_$][\\w$]*$/.test(raw)) return raw\n  // Prefix digits-leading names with underscore.\n  return `_${raw.replace(/[^\\w$]/g, '_')}`\n}\n\n/** Render a record key — quoted if not a valid identifier. */\nfunction jsKey(raw: string): string {\n  return /^[A-Za-z_$][\\w$]*$/.test(raw) ? raw : JSON.stringify(raw)\n}\n","import { RemovedValueAsDefaultError } from '../errors'\nimport type { SchemaSnapshot, TableSnapshot } from '../snapshot/types'\nimport type { Change, ChangeSet } from './types'\n\nexport function diff(prev: SchemaSnapshot, next: SchemaSnapshot): ChangeSet {\n  const changes: Change[] = []\n\n  const prevTables = new Set(Object.keys(prev.tables))\n  const nextTables = new Set(Object.keys(next.tables))\n\n  // Enum diffs run BEFORE table operations on the create side (so a new\n  // table referencing a new enum sees the type already exist) and AFTER\n  // table operations on the drop side (so a dropped enum can't have\n  // dangling column references). Order: createEnum → addEnumValue →\n  // table changes → dropEnum (appended at the end).\n  diffEnumsCreatePhase(prev, next, changes)\n\n  // Drops first (so FKs that depend on dropped tables are handled before drops below)\n  for (const name of prevTables) {\n    if (!nextTables.has(name)) {\n      changes.push({ kind: 'dropTable', table: prev.tables[name] })\n    }\n  }\n\n  // Creates — three passes so secondary objects only land after every new\n  // table exists. Pass 1: every CREATE TABLE. Pass 2: every CREATE INDEX.\n  // Pass 3: every ADD FOREIGN KEY. This keeps the order safe regardless of\n  // ESM namespace iteration (which is alphabetical, not declaration order)\n  // and lets each change kind map 1:1 to a SQL statement.\n  const newTableNames = [...nextTables].filter((n) => !prevTables.has(n))\n  for (const name of newTableNames) {\n    changes.push({ kind: 'createTable', table: next.tables[name] })\n  }\n  for (const name of newTableNames) {\n    for (const i of next.tables[name].indexes) {\n      changes.push({ kind: 'addIndex', table: name, index: i })\n    }\n  }\n  for (const name of newTableNames) {\n    for (const f of next.tables[name].foreignKeys) {\n      changes.push({ kind: 'addForeignKey', table: name, fk: f })\n    }\n  }\n\n  // Common tables — column/index/fk diff comes in Tasks 10-12\n  for (const name of nextTables) {\n    if (!prevTables.has(name)) continue\n    diffTable(prev.tables[name], next.tables[name], changes)\n  }\n\n  // Drop enums after every dependent table change has been emitted.\n  diffEnumsDropPhase(prev, next, changes)\n\n  return changes\n}\n\nfunction diffEnumsCreatePhase(prev: SchemaSnapshot, next: SchemaSnapshot, changes: Change[]) {\n  const prevEnums = prev.enums ?? {}\n  const nextEnums = next.enums ?? {}\n\n  // New enums first.\n  for (const [name, e] of Object.entries(nextEnums)) {\n    if (prevEnums[name]) continue\n    changes.push({ kind: 'createEnum', enum: e })\n  }\n\n  // ALTER TYPE ADD VALUE for non-destructive value additions on\n  // existing enums. Removed values are NOT round-trippable without\n  // dropping every column that references the type — those surface\n  // as a `removeEnumValue` advisory the emitter turns into a SQL\n  // comment with explicit operator guidance.\n  for (const [name, e] of Object.entries(nextEnums)) {\n    const prior = prevEnums[name]\n    if (!prior) continue\n    const priorValues = new Set(prior.values)\n    const nextValues = new Set(e.values)\n    const nextValueList = e.values\n\n    let lastInsertedAt = -1\n    for (let i = 0; i < nextValueList.length; i++) {\n      const value = nextValueList[i]\n      if (priorValues.has(value)) {\n        lastInsertedAt = i\n        continue\n      }\n      // New value — emit ADD VALUE. PG honours the BEFORE clause so\n      // we preserve the declaration order on existing values.\n      const before = nextValueList[i + 1]\n      const beforeIsExisting = before != null && priorValues.has(before)\n      changes.push({\n        kind: 'addEnumValue',\n        enum: name,\n        value,\n        ...(beforeIsExisting ? { before } : {}),\n      })\n      void lastInsertedAt\n    }\n\n    // Removed values — collect in declaration order from the prior\n    // snapshot so the emitter list matches the order the operator\n    // originally wrote.\n    const removed = prior.values.filter((v) => !nextValues.has(v))\n    if (removed.length > 0) {\n      const affectedColumns = collectColumnsByEnumType(next, name)\n      // M5.A.1 — pull each affected column's default off the PRIOR\n      // snapshot. The default is what the column had before the\n      // migration; we restore it (cast through the new type) after\n      // the type swap. Reading from `prev` keeps the dance idempotent\n      // with respect to schema-author intent.\n      // In-place assign — collectColumnsByEnumType builds fresh objects,\n      // so mutating them here is safe and skips a per-entry spread copy.\n      const affectedColumnsWithDefaults = affectedColumns.map((c) =>\n        Object.assign(c, { default: readPriorDefault(prev, c.table, c.column) }),\n      )\n      // Refuse at diff time when the column's default is being dropped\n      // from the enum. The operator must update the column default\n      // in the schema first.\n      for (const c of affectedColumnsWithDefaults) {\n        if (c.default == null) continue\n        const literal = stripDefaultCast(c.default)\n        if (literal != null && removed.includes(literal)) {\n          throw new RemovedValueAsDefaultError(name, c.table, c.column, literal)\n        }\n      }\n      changes.push({\n        kind: 'removeEnumValue',\n        enum: name,\n        removed,\n        values: nextValueList,\n        affectedColumns: affectedColumnsWithDefaults,\n      })\n    }\n  }\n}\n\n/**\n * Walk the next snapshot for columns whose declared type matches the\n * enum being modified. The emitter rewrites each via\n * `ALTER TABLE … ALTER COLUMN … TYPE foo USING column::text::foo`\n * inside the rename-recreate block.\n */\nfunction collectColumnsByEnumType(\n  snapshot: SchemaSnapshot,\n  enumName: string,\n): { table: string; column: string }[] {\n  const out: { table: string; column: string }[] = []\n  for (const [tableName, table] of Object.entries(snapshot.tables)) {\n    for (const [columnName, column] of Object.entries(table.columns)) {\n      if (column.type === enumName) {\n        out.push({ table: tableName, column: columnName })\n      }\n    }\n  }\n  return out\n}\n\n/**\n * Pull the literal default expression off the prior-snapshot column.\n * Returns `null` when the table/column doesn't exist in `prev` (i.e.\n * a column added in the same diff that introduces the enum change).\n */\nfunction readPriorDefault(\n  prev: SchemaSnapshot,\n  tableName: string,\n  columnName: string,\n): string | null {\n  const table = prev.tables[tableName]\n  if (!table) return null\n  const column = table.columns[columnName]\n  if (!column) return null\n  return column.default\n}\n\n/**\n * Strip the optional PG `::\"enum\"` cast from a default expression to\n * recover the bare literal. Returns the literal sans outer single\n * quotes when it's a simple text default, or `null` for function\n * calls, complex expressions, or anything else that wouldn't be a\n * value in the enum.\n *\n * Used only for the M5.A.1 \"default points at a removed value\" check.\n */\nfunction stripDefaultCast(expr: string): string | null {\n  const noCast = expr.replace(/::\\s*\"?[a-zA-Z_][a-zA-Z0-9_]*\"?\\s*$/, '').trim()\n  const match = /^'((?:[^']|'')*)'$/.exec(noCast)\n  if (!match) return null\n  return match[1]!.replace(/''/g, \"'\")\n}\n\nfunction diffEnumsDropPhase(prev: SchemaSnapshot, next: SchemaSnapshot, changes: Change[]) {\n  const prevEnums = prev.enums ?? {}\n  const nextEnums = next.enums ?? {}\n  for (const [name, e] of Object.entries(prevEnums)) {\n    if (nextEnums[name]) continue\n    changes.push({ kind: 'dropEnum', enum: e })\n  }\n}\n\nfunction diffTable(prev: TableSnapshot, next: TableSnapshot, changes: Change[]) {\n  const prevCols = new Map(Object.entries(prev.columns))\n  const nextCols = new Map(Object.entries(next.columns))\n\n  const drops: string[] = []\n  const adds: string[] = []\n  for (const c of prevCols.keys()) if (!nextCols.has(c)) drops.push(c)\n  for (const c of nextCols.keys()) if (!prevCols.has(c)) adds.push(c)\n\n  // Rename heuristic — pair only if exactly one drop + one add with identical attrs.\n  if (drops.length === 1 && adds.length === 1) {\n    const before = prevCols.get(drops[0])!\n    const after = nextCols.get(adds[0])!\n    if (columnAttrsEqual(before, after)) {\n      changes.push({ kind: 'renameColumn', table: next.name, from: drops[0], to: adds[0] })\n      drops.length = 0\n      adds.length = 0\n    }\n  }\n\n  for (const c of drops) {\n    changes.push({ kind: 'dropColumn', table: next.name, column: prevCols.get(c)! })\n  }\n  for (const c of adds) {\n    changes.push({ kind: 'addColumn', table: next.name, column: nextCols.get(c)! })\n  }\n\n  // Common columns — alter detection\n  for (const c of nextCols.keys()) {\n    if (!prevCols.has(c)) continue\n    const before = prevCols.get(c)!\n    const after = nextCols.get(c)!\n    if (!columnsEqual(before, after)) {\n      changes.push({ kind: 'alterColumn', table: next.name, column: c, before, after })\n    }\n  }\n\n  diffByName(\n    prev.indexes,\n    next.indexes,\n    (i) => changes.push({ kind: 'dropIndex', table: next.name, index: i }),\n    (i) => changes.push({ kind: 'addIndex', table: next.name, index: i }),\n  )\n\n  diffByName(\n    prev.foreignKeys,\n    next.foreignKeys,\n    (f) => changes.push({ kind: 'dropForeignKey', table: next.name, fk: f }),\n    (f) => changes.push({ kind: 'addForeignKey', table: next.name, fk: f }),\n  )\n}\n\nfunction diffByName<T extends { name: string }>(\n  prev: T[],\n  next: T[],\n  onDrop: (item: T) => void,\n  onAdd: (item: T) => void,\n) {\n  const prevByName = new Map(prev.map((p) => [p.name, p]))\n  const nextByName = new Map(next.map((n) => [n.name, n]))\n  for (const [n, p] of prevByName) if (!nextByName.has(n)) onDrop(p)\n  for (const [n, x] of nextByName) if (!prevByName.has(n)) onAdd(x)\n}\n\nfunction columnsEqual(\n  a: import('../snapshot/types').ColumnSnapshot,\n  b: import('../snapshot/types').ColumnSnapshot,\n): boolean {\n  return (\n    a.type === b.type &&\n    a.nullable === b.nullable &&\n    a.default === b.default &&\n    a.primaryKey === b.primaryKey\n  )\n}\n\nfunction columnAttrsEqual(\n  a: import('../snapshot/types').ColumnSnapshot,\n  b: import('../snapshot/types').ColumnSnapshot,\n): boolean {\n  // Like columnsEqual but ignores name (since rename is *about* name change).\n  return (\n    a.type === b.type &&\n    a.nullable === b.nullable &&\n    a.default === b.default &&\n    a.primaryKey === b.primaryKey\n  )\n}\n","import type { Change, ChangeSet } from './types'\n\n/**\n * Reverse a forward ChangeSet so emitting it produces the SQL that undoes\n * the forward migration.\n *\n * The reverse of an *unambiguous* change is exact (rename → rename swapped,\n * add → drop, drop → add). The reverse of an *ambiguous* change (drop column,\n * drop table, type widen, NOT NULL gain without default) is a defensible\n * best-effort derived from the snapshot the forward change carried — the\n * runner refuses to apply a non-reviewed migration in non-dev so the operator\n * always sees the draft before it touches a DB.\n *\n * The order is reversed too: drop FK before drop index before drop table is\n * the safe sequence for tearing down what create-FK / create-index / create-\n * table built up.\n */\nexport function invertChanges(forward: ChangeSet): ChangeSet {\n  const reversed: Change[] = []\n  for (const change of forward) {\n    reversed.push(invert(change))\n  }\n  const ordered = reversed.toReversed()\n\n  // Prune redundant teardown: when the inverted set drops a table\n  // outright, its dropForeignKey / dropIndex entries are no-ops — the\n  // DROP TABLE removes both. On SQLite they're actively fatal: FK/index\n  // drops compile to a table rebuild against the post-state snapshot,\n  // which no longer contains the table when the inversion of a\n  // createTable is in the same set (every first migration of an\n  // FK-bearing schema hit `SqliteRebuildRequiredError`).\n  const droppedTables = new Set(\n    ordered.filter((c) => c.kind === 'dropTable').map((c) => c.table.name),\n  )\n  return ordered.filter((c) => {\n    if (c.kind === 'dropForeignKey' || c.kind === 'dropIndex') {\n      return !droppedTables.has(c.table)\n    }\n    return true\n  })\n}\n\nfunction invert(change: Change): Change {\n  switch (change.kind) {\n    case 'createTable':\n      return { kind: 'dropTable', table: change.table }\n    case 'dropTable':\n      return { kind: 'createTable', table: change.table }\n    case 'renameTable':\n      return { kind: 'renameTable', from: change.to, to: change.from }\n    case 'addColumn':\n      return { kind: 'dropColumn', table: change.table, column: change.column }\n    case 'dropColumn':\n      return { kind: 'addColumn', table: change.table, column: change.column }\n    case 'renameColumn':\n      return {\n        kind: 'renameColumn',\n        table: change.table,\n        from: change.to,\n        to: change.from,\n      }\n    case 'alterColumn':\n      return {\n        kind: 'alterColumn',\n        table: change.table,\n        column: change.column,\n        before: change.after,\n        after: change.before,\n      }\n    case 'addIndex':\n      return { kind: 'dropIndex', table: change.table, index: change.index }\n    case 'dropIndex':\n      return { kind: 'addIndex', table: change.table, index: change.index }\n    case 'addForeignKey':\n      return { kind: 'dropForeignKey', table: change.table, fk: change.fk }\n    case 'dropForeignKey':\n      return { kind: 'addForeignKey', table: change.table, fk: change.fk }\n    case 'createEnum':\n      return { kind: 'dropEnum', enum: change.enum }\n    case 'dropEnum':\n      return { kind: 'createEnum', enum: change.enum }\n    case 'addEnumValue':\n      // PG can't ALTER TYPE … DROP VALUE without recreating the type +\n      // touching every column that uses it. Down-migrations carry the\n      // forward change verbatim; the operator gets a draft + a clear\n      // signal that the down won't auto-revert.\n      return change\n    case 'removeEnumValue':\n      // The forward direction of a value removal is itself an\n      // advisory + manual operation; the reverse is symmetric. Carry\n      // the change verbatim so the down draft surfaces the same\n      // SQL-comment guidance, with `removed` listing the values that\n      // would need to be re-added.\n      return change\n  }\n}\n\n/**\n * Returns the change kinds that produce ambiguous reverses — drop column,\n * drop table, type widen — so the generator can flag the down.sql as a draft\n * even if every individual statement is technically valid SQL.\n */\nconst AMBIGUOUS_REVERSE_KINDS = new Set<Change['kind']>([\n  'dropTable',\n  'dropColumn',\n  'alterColumn',\n  // PG enum value additions can't auto-reverse — drop-value isn't\n  // supported without recreating the type. The down draft surfaces\n  // the forward statement so the operator manually rewrites it.\n  'addEnumValue',\n  // Removed values can't auto-reverse for the symmetric reason: the\n  // value(s) that disappeared from the schema may have been held by\n  // existing rows whose state is already gone. Down draft preserves\n  // the advisory comment.\n  'removeEnumValue',\n])\n\nexport function hasAmbiguousReverse(forward: ChangeSet): boolean {\n  return forward.some((c) => AMBIGUOUS_REVERSE_KINDS.has(c.kind))\n}\n","/**\n * PG composite-type detection for `removeEnumValue` migrations (M4.C).\n *\n * The M3.B rename-recreate dance assumes the enum is referenced only by\n * table columns — each affected column gets a single `ALTER TABLE …\n * ALTER COLUMN … TYPE foo USING column::text::foo` clause. PG composite\n * types / arrays-of-composite / domains containing the enum break that\n * approach: the USING clause can't reach into composite fields, so the\n * migration fails opaquely at apply time with `type X is being used by\n * table Y`.\n *\n * `detectCompositeReferences` queries `pg_type` + `pg_attribute` to\n * surface those references at generate time. The CLI `kick db generate`\n * command then refuses to emit a migration when any are found, telling\n * the operator to drop or restructure the composite first.\n *\n * Driver-agnostic: takes a structural query runner (any pg-protocol-\n * compatible client). The CLI wires this against the same pool used for\n * `kick db migrate` so adopters don't configure a second connection.\n *\n * Spec: docs/db/m4-plan.md §M4.C.\n */\n\nimport { KickDbError } from '../errors'\n\n/**\n * One composite-type field that holds the target enum. The composite\n * may itself be referenced by table columns; that second level is not\n * surfaced — the goal here is to refuse the rename-recreate, not to\n * map the full dependency graph.\n */\nexport interface CompositeRef {\n  /** Schema-qualified composite type name, e.g. `\"public.address_t\"`. */\n  composite: string\n  /** Attribute (field) within the composite that holds the enum. */\n  attribute: string\n  /** Schema-qualified enum type name. */\n  enum: string\n}\n\n/**\n * Slim contract for a pg-protocol-compatible query function. Both\n * `pg.Pool` and `@neondatabase/serverless`'s Pool match this shape, as\n * does the `query` method on a pooled client.\n */\nexport interface CompositeQueryRunner {\n  query<R = unknown>(sql: string, params?: readonly unknown[]): Promise<{ rows: R[] }>\n}\n\ninterface CompositeRow {\n  composite_schema: string\n  composite_name: string\n  attribute_name: string\n  enum_schema: string\n  enum_name: string\n}\n\n/**\n * Find every PG composite type whose attribute(s) hold the given enum\n * type. `enumName` may be unqualified (treated as `public.<name>`) or\n * schema-qualified (`schema.name`).\n *\n * Returns an empty array when:\n *  - the enum doesn't exist in the live DB (the diff engine raised it\n *    against a snapshot, but the DB hasn't applied the prior migration\n *    yet — generate-time refusal would be a false alarm), or\n *  - no composite references the enum (the M3.B path is safe).\n */\nexport async function detectCompositeReferences(\n  runner: CompositeQueryRunner,\n  enumName: string,\n): Promise<CompositeRef[]> {\n  const { schema, name } = splitQualifiedName(enumName)\n\n  const sql = `\n    SELECT\n      ns_comp.nspname AS composite_schema,\n      t_comp.typname AS composite_name,\n      a.attname AS attribute_name,\n      ns_enum.nspname AS enum_schema,\n      t_enum.typname AS enum_name\n    FROM pg_type t_comp\n    JOIN pg_namespace ns_comp ON ns_comp.oid = t_comp.typnamespace\n    JOIN pg_class c ON c.oid = t_comp.typrelid\n    JOIN pg_attribute a ON a.attrelid = c.oid AND a.attnum > 0 AND NOT a.attisdropped\n    JOIN pg_type t_enum_or_arr ON t_enum_or_arr.oid = a.atttypid\n    JOIN pg_type t_enum ON t_enum.oid = COALESCE(NULLIF(t_enum_or_arr.typelem, 0), t_enum_or_arr.oid)\n    JOIN pg_namespace ns_enum ON ns_enum.oid = t_enum.typnamespace\n    WHERE t_comp.typtype = 'c'\n      AND c.relkind = 'c'\n      AND t_enum.typtype = 'e'\n      AND t_enum.typname = $1\n      AND ($2::text IS NULL OR ns_enum.nspname = $2)\n  `\n\n  const result = await runner.query<CompositeRow>(sql, [name, schema])\n  return result.rows.map((r) => ({\n    composite: `${r.composite_schema}.${r.composite_name}`,\n    attribute: r.attribute_name,\n    enum: `${r.enum_schema}.${r.enum_name}`,\n  }))\n}\n\nfunction splitQualifiedName(qualified: string): { schema: string | null; name: string } {\n  const dot = qualified.indexOf('.')\n  if (dot === -1) return { schema: null, name: qualified }\n  return { schema: qualified.slice(0, dot), name: qualified.slice(dot + 1) }\n}\n\n/**\n * Thrown by `kick db generate` when the diff would emit one or more\n * `removeEnumValue` changes against an enum that is referenced by a\n * PG composite type. The rename-recreate dance can't reach into\n * composite fields, so the generator refuses to write the migration\n * rather than letting it fail at apply time.\n *\n * The operator's options: drop the composite, restructure it not to\n * use the enum, or keep the value and ship the change later.\n */\nexport class CompositeEnumReferenceError extends KickDbError {\n  readonly refs: readonly CompositeRef[]\n\n  constructor(refs: readonly CompositeRef[]) {\n    const summary = refs.map((r) => `${r.composite}.${r.attribute} → ${r.enum}`).join(', ')\n    super(\n      'composite_enum_reference',\n      `Cannot generate migration: the enum value(s) being removed are reachable through ` +\n        `composite type field(s) [${summary}]. PostgreSQL's USING-cast in the rename-recreate ` +\n        `path can't reach into composite fields, so the migration would fail at apply time. ` +\n        `Drop or restructure the composite type(s) first, then re-run \\`kick db generate\\`.`,\n    )\n    this.refs = refs\n  }\n}\n","import { KickDbError } from '../errors'\n\nexport class MigrationError extends KickDbError {}\n\nexport class MigrationLockError extends MigrationError {\n  constructor(message: string) {\n    super('migration_lock_held', message)\n  }\n}\n\nexport interface SchemaDiffSummary {\n  added: string[]\n  removed: string[]\n  changed: string[]\n}\n\nexport class MigrationDriftError extends MigrationError {\n  readonly diff: SchemaDiffSummary\n\n  constructor(message: string, diff: SchemaDiffSummary) {\n    super('migration_drift', message)\n    this.diff = diff\n  }\n}\n\nexport class MigrationHashError extends MigrationError {\n  readonly id: string\n  readonly expected: string\n  readonly actual: string\n\n  constructor(id: string, expected: string, actual: string) {\n    super('migration_hash_mismatch', `Hash mismatch for migration ${id}`)\n    this.id = id\n    this.expected = expected\n    this.actual = actual\n  }\n}\n\nexport class UnreviewedMigrationError extends MigrationError {\n  readonly id: string\n\n  constructor(id: string) {\n    super(\n      'migration_unreviewed',\n      `Migration ${id} is unreviewed (meta.json reviewed: false) — run \\`kick db migrate review ${id}\\` before applying outside dev`,\n    )\n    this.id = id\n  }\n}\n\n/**\n * Thrown by the runner when a migration carries the `-- KICK ENUM\n * REMOVE` header and the operator hasn't passed `confirmEnumDrop:\n * true` (CLI: `--confirm-enum-drop`). Spec:\n * docs/db/spec-enum-value-removal.md §4.\n */\nexport class MigrationEnumDropError extends MigrationError {\n  readonly id: string\n  readonly enums: readonly string[]\n  readonly removed: readonly string[]\n  readonly columns: readonly string[]\n\n  constructor(\n    id: string,\n    enums: readonly string[],\n    removed: readonly string[],\n    columns: readonly string[],\n  ) {\n    const enumList = enums.join(', ')\n    const valueList = removed.join(', ')\n    super(\n      'migration_enum_drop_unconfirmed',\n      `Migration ${id} drops value(s) ${valueList} from PostgreSQL enum(s) ${enumList}. ` +\n        `Re-run with \\`--confirm-enum-drop\\` (CLI) or \\`confirmEnumDrop: true\\` ` +\n        `(RunnerOptions) after reviewing the column-USING clauses in up.sql.`,\n    )\n    this.id = id\n    this.enums = enums\n    this.removed = removed\n    this.columns = columns\n  }\n}\n","export function quoteIdent(name: string): string {\n  return name\n    .split('.')\n    .map((part) => '\"' + part.replace(/\"/g, '\"\"') + '\"')\n    .join('.')\n}\n\nexport function quoteLiteral(value: string): string {\n  return \"'\" + value.replace(/'/g, \"''\") + \"'\"\n}\n","import { quoteIdent, quoteLiteral } from './identifiers'\n\n// M5.B.1 — Typed IR for the four PG `ALTER TYPE` shapes that the\n// migration emitter produces. Modelled on Kysely 0.29's\n// `AlterTypeNode` (operation-node/alter-type-node.d.ts) so the\n// shapes stay in sync with the upstream typed surface, but rendered\n// by the local emitter — Kysely's `PostgresQueryCompiler` emits\n// lowercase keywords (`alter type \"foo\" rename to ...`) while the\n// kickjs-db emitter has always emitted uppercase. The existing\n// snapshot tests + every adopter's `_journal.json` migration hash\n// lock the uppercase form, so byte-identical output is the\n// constraint; Kysely's compiler can't honor it.\n//\n// Refactor goal: consolidate the four `ALTER TYPE` string-builds\n// scattered through `emit/pg.ts` into one typed IR + one renderer,\n// so future enum-related work (rename, value-rename, schema-move)\n// touches one source of truth instead of N call sites.\n\n/** Pure data describing one PG `ALTER TYPE` statement. */\nexport type AlterTypeIr = AlterTypeRenameTo | AlterTypeAddValue | AlterTypeRenameValue\n\nexport interface AlterTypeRenameTo {\n  readonly kind: 'renameTo'\n  readonly name: string\n  readonly newName: string\n}\n\nexport interface AlterTypeAddValue {\n  readonly kind: 'addValue'\n  readonly name: string\n  readonly value: string\n  /**\n   * Optional positional clause. Mutually exclusive with `after`;\n   * the renderer rejects both being set.\n   */\n  readonly before?: string\n  readonly after?: string\n}\n\nexport interface AlterTypeRenameValue {\n  readonly kind: 'renameValue'\n  readonly name: string\n  readonly oldValue: string\n  readonly newValue: string\n}\n\n/** Build a `RENAME TO` IR node. */\nexport function alterTypeRenameTo(name: string, newName: string): AlterTypeRenameTo {\n  return { kind: 'renameTo', name, newName }\n}\n\n/** Build an `ADD VALUE` IR node. Pass at most one of `before` / `after`. */\nexport function alterTypeAddValue(\n  name: string,\n  value: string,\n  position?: { before?: string; after?: string },\n): AlterTypeAddValue {\n  return {\n    kind: 'addValue',\n    name,\n    value,\n    before: position?.before,\n    after: position?.after,\n  }\n}\n\n/** Build a `RENAME VALUE` IR node. */\nexport function alterTypeRenameValue(\n  name: string,\n  oldValue: string,\n  newValue: string,\n): AlterTypeRenameValue {\n  return { kind: 'renameValue', name, oldValue, newValue }\n}\n\n/**\n * Render an `AlterTypeIr` to a single trailing-`;` SQL statement\n * matching the historic emitter output byte-for-byte. Identifiers\n * pass through `quoteIdent`; values through `quoteLiteral`.\n */\nexport function renderAlterType(ir: AlterTypeIr): string {\n  switch (ir.kind) {\n    case 'renameTo':\n      return `ALTER TYPE ${quoteIdent(ir.name)} RENAME TO ${quoteIdent(ir.newName)};`\n    case 'addValue': {\n      if (ir.before != null && ir.after != null) {\n        throw new Error(\n          'alterTypeAddValue: `before` and `after` are mutually exclusive — pass at most one',\n        )\n      }\n      const position =\n        ir.before != null\n          ? ` BEFORE ${quoteLiteral(ir.before)}`\n          : ir.after != null\n            ? ` AFTER ${quoteLiteral(ir.after)}`\n            : ''\n      return `ALTER TYPE ${quoteIdent(ir.name)} ADD VALUE ${quoteLiteral(ir.value)}${position};`\n    }\n    case 'renameValue':\n      return (\n        `ALTER TYPE ${quoteIdent(ir.name)} ` +\n        `RENAME VALUE ${quoteLiteral(ir.oldValue)} TO ${quoteLiteral(ir.newValue)};`\n      )\n  }\n}\n","import type { Change, ChangeSet } from '../diff/types'\nimport type { ColumnSnapshot, TableSnapshot } from '../snapshot/types'\nimport { quoteIdent, quoteLiteral } from './identifiers'\nimport { alterTypeAddValue, alterTypeRenameTo, renderAlterType } from './alter-type'\n\nexport function emitPg(changes: ChangeSet): string {\n  return changes.map(emitChange).join('\\n')\n}\n\nfunction emitChange(change: Change): string {\n  switch (change.kind) {\n    case 'createTable':\n      return emitCreateTable(change.table)\n    case 'dropTable':\n      return `DROP TABLE ${quoteIdent(change.table.name)};`\n    case 'renameTable':\n      return `ALTER TABLE ${quoteIdent(change.from)} RENAME TO ${quoteIdent(change.to)};`\n    case 'addColumn':\n      return emitAddColumn(change.table, change.column)\n    case 'dropColumn':\n      return `ALTER TABLE ${quoteIdent(change.table)} DROP COLUMN ${quoteIdent(change.column.name)};`\n    case 'renameColumn':\n      return `ALTER TABLE ${quoteIdent(change.table)} RENAME COLUMN ${quoteIdent(change.from)} TO ${quoteIdent(change.to)};`\n    case 'alterColumn':\n      return emitAlterColumn(change.table, change.before, change.after)\n    case 'addIndex':\n      return emitAddIndex(change.table, change.index)\n    case 'dropIndex':\n      return `DROP INDEX ${quoteIdent(change.index.name)};`\n    case 'addForeignKey':\n      return emitAddFk(change.table, change.fk)\n    case 'dropForeignKey':\n      return `ALTER TABLE ${quoteIdent(change.table)} DROP CONSTRAINT ${quoteIdent(change.fk.name)};`\n    case 'createEnum': {\n      const values = change.enum.values.map((v) => quoteLiteral(v)).join(', ')\n      return `CREATE TYPE ${quoteIdent(change.enum.name)} AS ENUM (${values});`\n    }\n    case 'dropEnum':\n      return `DROP TYPE ${quoteIdent(change.enum.name)};`\n    case 'addEnumValue':\n      return renderAlterType(\n        alterTypeAddValue(change.enum, change.value, { before: change.before }),\n      )\n    case 'removeEnumValue':\n      return emitRemoveEnumValueRecreate(change)\n  }\n}\n\n/**\n * Magic header line that the migration runner detects to gate the\n * apply step behind `confirmEnumDrop`. Kept short + on its own line\n * so a `String.includes` is enough to find it. Any change to this\n * literal must also update the runner's check function.\n */\nexport const ENUM_DROP_HEADER = '-- KICK ENUM REMOVE'\n\n/**\n * Render the rename-recreate dance for a `pgEnum` value removal.\n *\n *   ALTER TYPE foo RENAME TO foo__old\n *   CREATE TYPE foo AS ENUM (…new value list…)\n *   for each affected column:\n *     ALTER TABLE T ALTER COLUMN C TYPE foo USING C::text::foo\n *   DROP TYPE foo__old\n *\n * No explicit `BEGIN; … COMMIT;` — the runner wraps every up.sql\n * in `applySqlInTx` by default, and PG DDL is transactional, so\n * the four statements either all commit or all roll back. Wrapping\n * here would nest a transaction inside the runner's outer one,\n * which PG accepts (NOTICE-level warning) but commits early on the\n * inner COMMIT, defeating the runner's atomic-apply guarantee.\n *\n * The leading `-- KICK ENUM REMOVE` header is the runner's gate\n * signal — without `confirmEnumDrop`, the runner refuses to apply\n * before any DB write happens.\n *\n * Spec: docs/db/spec-enum-value-removal.md.\n */\nfunction emitRemoveEnumValueRecreate(change: {\n  enum: string\n  removed: readonly string[]\n  values: readonly string[]\n  affectedColumns: readonly { table: string; column: string; default: string | null }[]\n}): string {\n  const safeName = sanitizeForLineComment(quoteIdent(change.enum))\n  const removedList = change.removed.map((v) => sanitizeForLineComment(quoteLiteral(v))).join(', ')\n  const columnsList = change.affectedColumns\n    .map((c) => sanitizeForLineComment(`${c.table}.${c.column}`))\n    .join(', ')\n\n  const oldTypeName = quoteIdent(`${change.enum}__old`)\n  const typeName = quoteIdent(change.enum)\n  const oldTypeRawName = `${change.enum}__old`\n  const valuesList = change.values.map((v) => quoteLiteral(v)).join(', ')\n\n  const header = [\n    ENUM_DROP_HEADER,\n    `-- enum: ${safeName}`,\n    `-- removed: ${removedList}`,\n    `-- columns: ${columnsList || '(none)'}`,\n    `--`,\n    `-- This migration drops values from a PostgreSQL ENUM type. The`,\n    `-- runner refuses to apply it without the --confirm-enum-drop flag`,\n    `-- (or \\`confirmEnumDrop: true\\` in RunnerOptions). Inspect the`,\n    `-- column USING clauses below to confirm rows holding a removed`,\n    `-- value will fail loudly rather than silently coerce.`,\n  ]\n\n  const body: string[] = [\n    renderAlterType(alterTypeRenameTo(change.enum, oldTypeRawName)),\n    `CREATE TYPE ${typeName} AS ENUM (${valuesList});`,\n  ]\n  for (const col of change.affectedColumns) {\n    // M5.A.1 — when the column carries a default, drop it before the\n    // type swap and restore it cast through the new type after.\n    // Columns without a default emit the bare swap (byte-identical\n    // to pre-M5.A.1 output, so existing migration hashes stay valid).\n    const tableIdent = quoteIdent(col.table)\n    const columnIdent = quoteIdent(col.column)\n    if (col.default != null) {\n      body.push(`ALTER TABLE ${tableIdent} ALTER COLUMN ${columnIdent} DROP DEFAULT;`)\n    }\n    body.push(\n      `ALTER TABLE ${tableIdent}`,\n      `  ALTER COLUMN ${columnIdent} TYPE ${typeName}`,\n      `  USING ${columnIdent}::text::${typeName};`,\n    )\n    if (col.default != null) {\n      // Strip any existing `::\"<old-enum>\"` cast so we don't double-\n      // cast through the renamed shadow type. Re-attach the cast\n      // through the freshly-created type name.\n      const literal = stripDefaultTypeCast(col.default)\n      body.push(\n        `ALTER TABLE ${tableIdent} ALTER COLUMN ${columnIdent} SET DEFAULT ${literal}::${typeName};`,\n      )\n    }\n  }\n  body.push(`DROP TYPE ${oldTypeName};`)\n\n  return [...header, ...body].join('\\n')\n}\n\n/**\n * Make a value safe to interpolate into a single-line `--` SQL\n * comment. Identifiers and quoted literals normally don't carry\n * line breaks, but the user-supplied portion (enum name + values)\n * can contain anything an adopter passes to `pgEnum()`. A literal\n * `\\n` would terminate the comment early and turn the rest of the\n * line into executable SQL.\n *\n * Scope of the sanitiser:\n * - Line-break code points (`\\r`, `\\n`, `U+2028`, `U+2029`) collapse\n *   runs to a single space so the comment stays on one line.\n * - C0 control bytes excluding tab (0x00-0x08, 0x0B, 0x0C, 0x0E-0x1F)\n *   plus DEL (0x7F) escape to `\\x<hh>`.\n * - Tab (0x09) passes through — visually fine inside a `--` comment.\n *\n * Out of scope on purpose: C1 controls (U+0080-U+009F) and other\n * non-ASCII characters pass through unchanged. Adopters do legitimately\n * pass UTF-8 enum names + values (`'café'`, `'naïve'`); aggressively\n * escaping them would degrade the migration file's readability without\n * adding security — only line terminators can break out of a `--`\n * comment, and those are handled above.\n */\n/**\n * Strip a trailing `::\"<typename>\"` (or `::<typename>`) cast off a\n * default expression. The rename-recreate dance recreates the enum\n * type, so any existing cast in the snapshot defaults points at the\n * about-to-be-renamed shadow type. Re-attach the cast through the\n * freshly-created type at the SET DEFAULT call site.\n *\n * Returns the bare expression (literal, function call, etc.) when no\n * cast was present.\n */\nfunction stripDefaultTypeCast(expr: string): string {\n  return expr.replace(/::\\s*\"?[a-zA-Z_][a-zA-Z0-9_]*\"?\\s*$/, '').trim()\n}\n\nfunction sanitizeForLineComment(value: string): string {\n  // Walk code units rather than regex character classes \\u2014 control-char\n  // regex literals trip `no-control-regex` lints and confuse some\n  // editor analysers with \"unreachable\" warnings on the second\n  // replace. Code-unit iteration is unambiguous: for every char we\n  // either pass it through, collapse a line-break to a space, or\n  // escape a control byte into `\\x<hh>`.\n  let out = ''\n  let prevWasLineBreak = false\n  for (let i = 0; i < value.length; i++) {\n    const code = value.charCodeAt(i)\n    // Line-break code points \\u2192 collapse runs to a single space.\n    // Includes \\r (0x0D), \\n (0x0A), U+2028 (LINE SEPARATOR),\n    // U+2029 (PARAGRAPH SEPARATOR).\n    const isLineBreak = code === 0x0a || code === 0x0d || code === 0x2028 || code === 0x2029\n    if (isLineBreak) {\n      if (!prevWasLineBreak) out += ' '\n      prevWasLineBreak = true\n      continue\n    }\n    prevWasLineBreak = false\n    // Tab (0x09) passes through \\u2014 visually fine inside a `--` comment.\n    // Other C0 control bytes (0x00-0x08, 0x0B, 0x0C, 0x0E-0x1F) and\n    // DEL (0x7F) escape to `\\x<hh>` so the migration file stays\n    // printable ASCII clean.\n    const isControl =\n      (code >= 0x00 && code <= 0x08) ||\n      code === 0x0b ||\n      code === 0x0c ||\n      (code >= 0x0e && code <= 0x1f) ||\n      code === 0x7f\n    if (isControl) {\n      out += `\\\\x${code.toString(16).padStart(2, '0')}`\n      continue\n    }\n    out += value[i]\n  }\n  return out\n}\n\nfunction emitAddColumn(table: string, c: ColumnSnapshot): string {\n  return `ALTER TABLE ${quoteIdent(table)} ADD COLUMN ${emitColumnDecl(c)};`\n}\n\nfunction emitAlterColumn(table: string, before: ColumnSnapshot, after: ColumnSnapshot): string {\n  const stmts: string[] = []\n  const t = quoteIdent(table)\n  const c = quoteIdent(after.name)\n\n  const typeChanged = before.type !== after.type\n  const nullChanged = before.nullable !== after.nullable\n  const defaultChanged = before.default !== after.default\n  const losingNotNull = !before.nullable && after.nullable\n\n  if (typeChanged) {\n    stmts.push(`ALTER TABLE ${t} ALTER COLUMN ${c} TYPE ${after.type} USING ${c}::${after.type};`)\n  }\n\n  // Default precedes nullable when loosening (DROP DEFAULT before DROP NOT NULL keeps\n  // each interim state valid). Otherwise nullable precedes default (SET NOT NULL before\n  // SET DEFAULT lets the default apply on the now-required column).\n  const emitDefault = () => {\n    if (!defaultChanged) return\n    stmts.push(\n      after.default === null\n        ? `ALTER TABLE ${t} ALTER COLUMN ${c} DROP DEFAULT;`\n        : `ALTER TABLE ${t} ALTER COLUMN ${c} SET DEFAULT ${formatDefault(after.default)};`,\n    )\n  }\n  const emitNullable = () => {\n    if (!nullChanged) return\n    stmts.push(\n      `ALTER TABLE ${t} ALTER COLUMN ${c} ${after.nullable ? 'DROP NOT NULL' : 'SET NOT NULL'};`,\n    )\n  }\n\n  if (losingNotNull) {\n    emitDefault()\n    emitNullable()\n  } else {\n    emitNullable()\n    emitDefault()\n  }\n\n  return stmts.join('\\n')\n}\n\nfunction emitAddIndex(table: string, i: import('../snapshot/types').IndexSnapshot): string {\n  const cols = i.columns.map(quoteIdent).join(', ')\n  return `CREATE${i.unique ? ' UNIQUE' : ''} INDEX ${quoteIdent(i.name)} ON ${quoteIdent(table)} (${cols});`\n}\n\nconst FK_ACTIONS: Record<string, string> = {\n  cascade: 'CASCADE',\n  restrict: 'RESTRICT',\n  set_null: 'SET NULL',\n  set_default: 'SET DEFAULT',\n  no_action: 'NO ACTION',\n}\n\nfunction emitAddFk(table: string, fk: import('../snapshot/types').ForeignKeySnapshot): string {\n  const cols = fk.columns.map(quoteIdent).join(', ')\n  const refCols = fk.refColumns.map(quoteIdent).join(', ')\n  return (\n    `ALTER TABLE ${quoteIdent(table)} ADD CONSTRAINT ${quoteIdent(fk.name)} ` +\n    `FOREIGN KEY (${cols}) REFERENCES ${quoteIdent(fk.refTable)} (${refCols}) ` +\n    `ON DELETE ${FK_ACTIONS[fk.onDelete]} ON UPDATE ${FK_ACTIONS[fk.onUpdate]};`\n  )\n}\n\nfunction emitCreateTable(t: TableSnapshot): string {\n  const cols = Object.values(t.columns).map(emitColumnDecl)\n  const pk = Object.values(t.columns)\n    .filter((c) => c.primaryKey)\n    .map((c) => quoteIdent(c.name))\n  const lines = [...cols]\n  if (pk.length > 0) lines.push(`PRIMARY KEY (${pk.join(', ')})`)\n  return `CREATE TABLE ${quoteIdent(t.name)} (\\n  ${lines.join(',\\n  ')}\\n);`\n}\n\nfunction emitColumnDecl(c: ColumnSnapshot): string {\n  let s = `${quoteIdent(c.name)} ${c.type}`\n  if (!c.nullable) s += ' NOT NULL'\n  if (c.default !== null) s += ` DEFAULT ${formatDefault(c.default)}`\n  return s\n}\n\nfunction formatDefault(value: unknown): string {\n  // Defensive: a snapshot authored before defaults were normalised to\n  // strings (or hand-edited) may carry a raw boolean/number. Coerce so\n  // `quoteLiteral` (String.prototype.replace) never sees a non-string.\n  if (typeof value === 'boolean') return value ? 'true' : 'false'\n  if (typeof value === 'number' || typeof value === 'bigint') return String(value)\n  const str = String(value)\n  // SQL keywords pass through bare.\n  if (/^[A-Z_]+$/.test(str)) return str // CURRENT_TIMESTAMP, CURRENT_DATE, NULL, etc.\n  // SQL function calls pass through bare: NOW(), gen_random_uuid(), etc.\n  if (/^[a-z_][a-z0-9_]*\\s*\\([^)]*\\)$/i.test(str)) return str\n  if (/^-?\\d+(\\.\\d+)?$/.test(str)) return str // numeric\n  if (str === 'true' || str === 'false') return str // boolean literal\n  return quoteLiteral(str)\n}\n","/**\n * Runner gate for the `-- KICK ENUM REMOVE` header.\n *\n * Pure parser + decision function — no I/O, no adapter, no DB. The\n * runner reads up.sql, hands it to `parseEnumDropHeader`, and\n * passes the result to `enforceEnumDropGate` which throws\n * `MigrationEnumDropError` when the header is present and\n * `confirmEnumDrop` is falsy.\n *\n * Spec: docs/db/spec-enum-value-removal.md §4.\n */\n\nimport { ENUM_DROP_HEADER } from '../emit/pg'\nimport { MigrationEnumDropError } from './errors'\n\n/**\n * Parsed payload from the header block. Empty arrays for keys not\n * present (resilient to operators editing the migration by hand).\n */\nexport interface EnumDropHeader {\n  enums: string[]\n  removed: string[]\n  columns: string[]\n}\n\n/**\n * Scan the first 64 lines of an up.sql for one or more enum-drop\n * header blocks. Returns null when no header is present.\n */\nexport function parseEnumDropHeader(sql: string): EnumDropHeader | null {\n  if (!sql.includes(ENUM_DROP_HEADER)) return null\n\n  const lines = sql.split(/\\r?\\n/, 64)\n  const enums: string[] = []\n  const removed: string[] = []\n  const columns: string[] = []\n\n  for (let i = 0; i < lines.length; i++) {\n    const line = lines[i]?.trim() ?? ''\n    if (line !== ENUM_DROP_HEADER) continue\n    for (let j = i + 1; j < lines.length; j++) {\n      const next = lines[j]?.trim() ?? ''\n      if (!next.startsWith('--')) break\n      const m = /^--\\s*([a-z]+):\\s*(.+)$/i.exec(next)\n      if (!m) continue\n      const key = m[1]!.toLowerCase()\n      const raw = m[2]!.trim()\n      if (key === 'enum') enums.push(raw)\n      else if (key === 'removed') removed.push(...splitListing(raw))\n      else if (key === 'columns') columns.push(...splitListing(raw))\n    }\n  }\n\n  if (enums.length === 0 && removed.length === 0 && columns.length === 0) {\n    return { enums: [], removed: [], columns: [] }\n  }\n  return { enums, removed, columns }\n}\n\n/**\n * Throws `MigrationEnumDropError` when the migration has an\n * enum-drop header and `confirmEnumDrop` is not set. Returns\n * silently otherwise.\n */\nexport function enforceEnumDropGate(\n  id: string,\n  sql: string,\n  confirmEnumDrop: boolean,\n): EnumDropHeader | null {\n  const header = parseEnumDropHeader(sql)\n  if (!header) return null\n  if (!confirmEnumDrop) {\n    throw new MigrationEnumDropError(id, header.enums, header.removed, header.columns)\n  }\n  return header\n}\n\nfunction splitListing(raw: string): string[] {\n  if (raw === '(none)' || raw === '') return []\n  return raw\n    .split(',')\n    .map((s) => s.trim().replace(/^['\"`]|['\"`]$/g, ''))\n    .filter((s) => s.length > 0)\n}\n","import { createHash } from 'node:crypto'\nimport { readFile, writeFile } from 'node:fs/promises'\nimport { existsSync } from 'node:fs'\nimport path from 'node:path'\n\nimport type { Dialect } from '../snapshot/types'\n\nexport interface JournalEntry {\n  id: string\n  tag: string\n  hash: string\n  createdAt: string\n}\n\nexport interface Journal {\n  version: 1\n  dialect: Dialect\n  entries: JournalEntry[]\n}\n\nconst FILE = '_journal.json'\n\nexport async function readJournal(migrationsDir: string, dialect: Dialect): Promise<Journal> {\n  const file = path.join(migrationsDir, FILE)\n  if (!existsSync(file)) {\n    return { version: 1, dialect, entries: [] }\n  }\n  const raw = JSON.parse(await readFile(file, 'utf8'))\n  if (raw.version !== 1) {\n    throw new Error(`_journal.json version ${raw.version} unsupported (expected 1)`)\n  }\n  return raw\n}\n\nexport async function appendJournalEntry(\n  migrationsDir: string,\n  dialect: Dialect,\n  entry: JournalEntry,\n): Promise<void> {\n  const j = await readJournal(migrationsDir, dialect)\n  j.entries.push(entry)\n  const file = path.join(migrationsDir, FILE)\n  await writeFile(file, JSON.stringify(j, null, 2) + '\\n', 'utf8')\n}\n\nexport async function computeMigrationHash(migrationDir: string): Promise<string> {\n  const up = await readFile(path.join(migrationDir, 'up.sql'), 'utf8')\n  const down = await readFile(path.join(migrationDir, 'down.sql'), 'utf8')\n  const snap = await readFile(path.join(migrationDir, 'snapshot.json'), 'utf8')\n  const h = createHash('sha256')\n    .update(up)\n    .update('|')\n    .update(down)\n    .update('|')\n    .update(snap)\n    .digest('hex')\n  return `sha256:${h}`\n}\n\nexport async function verifyMigrationHash(\n  migrationDir: string,\n  expected: string,\n): Promise<boolean> {\n  const actual = await computeMigrationHash(migrationDir)\n  return actual === expected\n}\n","import type { Dialect } from '../snapshot/types'\n\nexport const KICK_MIGRATIONS_TABLE = 'kick_migrations'\nexport const KICK_LOCK_TABLE = 'kick_migrations_lock'\n\nexport function migrationsTableDdl(dialect: Dialect): string {\n  switch (dialect) {\n    case 'postgres':\n      return `CREATE TABLE IF NOT EXISTS \"${KICK_MIGRATIONS_TABLE}\" (\n        \"id\" varchar(128) PRIMARY KEY,\n        \"name\" text NOT NULL,\n        \"hash\" text NOT NULL,\n        \"batch\" integer NOT NULL,\n        \"applied_at\" timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP,\n        \"direction\" varchar(8) NOT NULL DEFAULT 'up'\n      );\n      CREATE INDEX IF NOT EXISTS \"${KICK_MIGRATIONS_TABLE}_batch_idx\" ON \"${KICK_MIGRATIONS_TABLE}\" (\"batch\");`\n    case 'sqlite':\n      return `CREATE TABLE IF NOT EXISTS \"${KICK_MIGRATIONS_TABLE}\" (\n        \"id\" text PRIMARY KEY,\n        \"name\" text NOT NULL,\n        \"hash\" text NOT NULL,\n        \"batch\" integer NOT NULL,\n        \"applied_at\" text NOT NULL DEFAULT (datetime('now')),\n        \"direction\" text NOT NULL DEFAULT 'up'\n      );\n      CREATE INDEX IF NOT EXISTS \"${KICK_MIGRATIONS_TABLE}_batch_idx\" ON \"${KICK_MIGRATIONS_TABLE}\" (\"batch\");`\n    case 'mysql':\n      return `CREATE TABLE IF NOT EXISTS \\`${KICK_MIGRATIONS_TABLE}\\` (\n        \\`id\\` varchar(128) PRIMARY KEY,\n        \\`name\\` text NOT NULL,\n        \\`hash\\` text NOT NULL,\n        \\`batch\\` int NOT NULL,\n        \\`applied_at\\` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\n        \\`direction\\` varchar(8) NOT NULL DEFAULT 'up',\n        INDEX \\`${KICK_MIGRATIONS_TABLE}_batch_idx\\` (\\`batch\\`)\n      );`\n  }\n}\n\nexport function lockTableDdl(dialect: Dialect): string {\n  switch (dialect) {\n    case 'postgres':\n      return `CREATE TABLE IF NOT EXISTS \"${KICK_LOCK_TABLE}\" (\n        \"id\" smallint PRIMARY KEY,\n        \"locked_at\" timestamptz,\n        \"locked_by\" text\n      );\n      INSERT INTO \"${KICK_LOCK_TABLE}\" (\"id\") VALUES (1) ON CONFLICT DO NOTHING;`\n    case 'sqlite':\n      return `CREATE TABLE IF NOT EXISTS \"${KICK_LOCK_TABLE}\" (\n        \"id\" integer PRIMARY KEY,\n        \"locked_at\" text,\n        \"locked_by\" text\n      );\n      INSERT OR IGNORE INTO \"${KICK_LOCK_TABLE}\" (\"id\") VALUES (1);`\n    case 'mysql':\n      return `CREATE TABLE IF NOT EXISTS \\`${KICK_LOCK_TABLE}\\` (\n        \\`id\\` smallint PRIMARY KEY,\n        \\`locked_at\\` timestamp NULL,\n        \\`locked_by\\` text\n      );\n      INSERT IGNORE INTO \\`${KICK_LOCK_TABLE}\\` (\\`id\\`) VALUES (1);`\n  }\n}\n","import type { Dialect, SchemaSnapshot } from '../snapshot/types'\nimport type { MigrationAdapter, MigrationRow } from './adapter'\n\n/**\n * In-memory MigrationAdapter for unit tests. Lock semantics are exact (single-\n * holder atomic), but applySqlInTx / applySqlNoTx / introspect are shaped as\n * test-only stubs — the real DB-bound semantics are validated in db-pg's\n * integration tests, not here.\n */\nexport class MemoryMigrationAdapter implements MigrationAdapter {\n  readonly dialect: Dialect = 'postgres'\n\n  private rows: MigrationRow[] = []\n  private locked: { by: string; at: string } | null = null\n  private appliedSql: string[] = []\n  private currentSchema: SchemaSnapshot = { version: 1, dialect: 'postgres', tables: {} }\n\n  async ensureMigrationTables(): Promise<void> {\n    /* no-op */\n  }\n\n  async listApplied(): Promise<MigrationRow[]> {\n    return [...this.rows]\n  }\n\n  async recordApplied(row: Omit<MigrationRow, 'appliedAt'>): Promise<void> {\n    this.rows.push({ ...row, appliedAt: new Date().toISOString() })\n  }\n\n  async removeApplied(id: string): Promise<void> {\n    this.rows = this.rows.filter((r) => r.id !== id)\n  }\n\n  async acquireLock(owner: string): Promise<boolean> {\n    if (this.locked) return false\n    this.locked = { by: owner, at: new Date().toISOString() }\n    return true\n  }\n\n  async releaseLock(): Promise<void> {\n    this.locked = null\n  }\n\n  async applySqlInTx(sql: string): Promise<void> {\n    this.appliedSql.push(sql)\n  }\n\n  async applySqlNoTx(sql: string): Promise<void> {\n    this.appliedSql.push(sql)\n  }\n\n  async introspect(): Promise<SchemaSnapshot> {\n    return this.currentSchema\n  }\n\n  async close(): Promise<void> {\n    /* no-op */\n  }\n\n  /** Test-only setter — let drift tests stage a \"live\" schema state. */\n  __setIntrospectedSchema(snap: SchemaSnapshot): void {\n    this.currentSchema = snap\n  }\n\n  /** Test-only inspector — what SQL we received. */\n  __appliedSql(): readonly string[] {\n    return this.appliedSql\n  }\n}\n","import type {\n  ForeignKeySnapshot,\n  FkAction,\n  IndexSnapshot,\n  SchemaSnapshot,\n  TableSnapshot,\n} from '../snapshot/types'\nimport type { IntrospectPgOptions, PgQueryRunner } from './introspect-types'\n\nconst DEFAULT_EXCLUDED = ['kick_migrations', 'kick_migrations_lock']\n\ninterface ColumnRow {\n  column_name: string\n  data_type: string\n  udt_name: string\n  is_nullable: 'YES' | 'NO'\n  column_default: string | null\n  character_maximum_length: number | null\n  numeric_precision: number | null\n  numeric_scale: number | null\n}\n\ninterface IndexRow {\n  index_name: string\n  column_name: string\n  is_unique: boolean\n  is_primary: boolean\n}\n\ninterface FkRow {\n  constraint_name: string\n  column_name: string\n  ref_table: string\n  ref_column: string\n  delete_rule: string\n  update_rule: string\n}\n\nexport async function introspectPg(\n  client: PgQueryRunner,\n  opts: IntrospectPgOptions = {},\n): Promise<SchemaSnapshot> {\n  const schema = opts.schema ?? 'public'\n  const excluded = opts.excludeTables ?? DEFAULT_EXCLUDED\n\n  const tableRows = await client.query<{ table_name: string }>(\n    `SELECT table_name\n     FROM information_schema.tables\n     WHERE table_schema = $1 AND table_type = 'BASE TABLE'\n     ORDER BY table_name`,\n    [schema],\n  )\n\n  const tables: Record<string, TableSnapshot> = {}\n  for (const t of tableRows.rows) {\n    if (excluded.includes(t.table_name)) continue\n    tables[t.table_name] = {\n      name: t.table_name,\n      columns: await readColumns(client, schema, t.table_name),\n      indexes: await readIndexes(client, schema, t.table_name),\n      foreignKeys: await readForeignKeys(client, schema, t.table_name),\n      checks: [],\n    }\n  }\n  return { version: 1, dialect: 'postgres', tables }\n}\n\nasync function readColumns(\n  client: PgQueryRunner,\n  schema: string,\n  table: string,\n): Promise<TableSnapshot['columns']> {\n  const cols = await client.query<ColumnRow>(\n    `SELECT column_name, data_type, udt_name, is_nullable, column_default,\n            character_maximum_length, numeric_precision, numeric_scale\n     FROM information_schema.columns\n     WHERE table_schema = $1 AND table_name = $2\n     ORDER BY ordinal_position`,\n    [schema, table],\n  )\n\n  const pkCols = await client.query<{ column_name: string }>(\n    `SELECT k.column_name\n     FROM information_schema.table_constraints c\n     JOIN information_schema.key_column_usage k\n       ON k.constraint_name = c.constraint_name\n      AND k.table_schema = c.table_schema\n     WHERE c.table_schema = $1 AND c.table_name = $2 AND c.constraint_type = 'PRIMARY KEY'\n     ORDER BY k.ordinal_position`,\n    [schema, table],\n  )\n  const pkSet = new Set(pkCols.rows.map((r) => r.column_name))\n\n  const out: TableSnapshot['columns'] = {}\n  for (const r of cols.rows) {\n    const isSerial = isSerialColumn(r)\n    out[r.column_name] = {\n      name: r.column_name,\n      type: isSerial ? serialTypeFor(r) : normalizeType(r),\n      nullable: r.is_nullable === 'YES',\n      // serial columns own their nextval default; collapse it to keep round-\n      // trips (DSL → emit → introspect) idempotent.\n      default: isSerial ? null : normalizeDefault(r.column_default),\n      primaryKey: pkSet.has(r.column_name),\n    }\n  }\n  return out\n}\n\nfunction isSerialColumn(r: ColumnRow): boolean {\n  if (!r.column_default) return false\n  if (!r.column_default.startsWith('nextval(')) return false\n  return r.udt_name === 'int2' || r.udt_name === 'int4' || r.udt_name === 'int8'\n}\n\nfunction serialTypeFor(r: ColumnRow): string {\n  if (r.udt_name === 'int8') return 'bigserial'\n  if (r.udt_name === 'int2') return 'smallserial'\n  return 'serial'\n}\n\nfunction normalizeType(r: ColumnRow): string {\n  // Map PG's information_schema data_type back to the DSL surface.\n  if (r.data_type === 'character varying') {\n    return r.character_maximum_length ? `varchar(${r.character_maximum_length})` : 'varchar'\n  }\n  if (r.data_type === 'character') {\n    return r.character_maximum_length ? `char(${r.character_maximum_length})` : 'char(1)'\n  }\n  if (r.data_type === 'numeric') {\n    if (r.numeric_precision !== null && r.numeric_scale !== null) {\n      return `numeric(${r.numeric_precision}, ${r.numeric_scale})`\n    }\n    if (r.numeric_precision !== null) return `numeric(${r.numeric_precision})`\n    return 'numeric'\n  }\n  if (r.data_type === 'timestamp with time zone') return 'timestamptz'\n  if (r.data_type === 'timestamp without time zone') return 'timestamp'\n  if (r.data_type === 'time without time zone') return 'time'\n  if (r.data_type === 'double precision') return 'double precision'\n  if (r.data_type === 'USER-DEFINED') return r.udt_name\n  if (r.data_type === 'ARRAY') {\n    // udt_name for arrays is _<element>; strip and append [].\n    const elem = r.udt_name.replace(/^_/, '')\n    return `${elem}[]`\n  }\n  // bigint, integer, smallint, text, boolean, date, json, jsonb, bytea, uuid,\n  // interval, etc — pass through as data_type when it matches the DSL.\n  return r.data_type\n}\n\nfunction normalizeDefault(raw: string | null): string | null {\n  if (!raw) return null\n  // Strip PG's :: cast suffixes: 'true'::boolean → true, 'foo'::text → 'foo'\n  const stripped = raw.replace(/::[\\w\" ]+(\\([^)]*\\))?$/, '')\n  // Normalize CURRENT_TIMESTAMP / now() to the DSL canonical token.\n  const upper = stripped.toUpperCase()\n  if (upper === 'NOW()' || upper === 'CURRENT_TIMESTAMP') return 'CURRENT_TIMESTAMP'\n  if (upper === 'GEN_RANDOM_UUID()') return 'gen_random_uuid()'\n  // 'foo' literal → foo. true / false / numeric pass through.\n  return stripped.replace(/^'(.*)'$/, '$1')\n}\n\nasync function readIndexes(\n  client: PgQueryRunner,\n  schema: string,\n  table: string,\n): Promise<IndexSnapshot[]> {\n  const rows = await client.query<IndexRow>(\n    `SELECT i.relname AS index_name,\n            a.attname AS column_name,\n            ix.indisunique AS is_unique,\n            ix.indisprimary AS is_primary\n     FROM pg_class t\n     JOIN pg_namespace n ON n.oid = t.relnamespace\n     JOIN pg_index ix ON ix.indrelid = t.oid\n     JOIN pg_class i ON i.oid = ix.indexrelid\n     JOIN unnest(ix.indkey) WITH ORDINALITY AS k(attnum, ord) ON true\n     JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = k.attnum\n     WHERE n.nspname = $1 AND t.relname = $2 AND t.relkind = 'r'\n     ORDER BY i.relname, k.ord`,\n    [schema, table],\n  )\n\n  // Group rows by index_name, preserve column order.\n  type Tagged = IndexSnapshot & { _isPrimary: boolean }\n  const byIndex = new Map<string, Tagged>()\n  for (const r of rows.rows) {\n    let entry = byIndex.get(r.index_name)\n    if (!entry) {\n      entry = {\n        name: r.index_name,\n        columns: [],\n        unique: r.is_unique,\n        _isPrimary: r.is_primary,\n      }\n      byIndex.set(r.index_name, entry)\n    }\n    entry.columns.push(r.column_name)\n  }\n\n  // Drop PK-backing indexes — primaryKey is recorded on the column itself.\n  return [...byIndex.values()]\n    .filter((i) => !i._isPrimary)\n    .map(({ _isPrimary, ...rest }) => rest)\n    .toSorted((a, b) => a.name.localeCompare(b.name))\n}\n\nasync function readForeignKeys(\n  client: PgQueryRunner,\n  schema: string,\n  table: string,\n): Promise<ForeignKeySnapshot[]> {\n  const rows = await client.query<FkRow>(\n    `SELECT tc.constraint_name,\n            kcu.column_name,\n            ccu.table_name AS ref_table,\n            ccu.column_name AS ref_column,\n            rc.delete_rule,\n            rc.update_rule\n     FROM information_schema.table_constraints tc\n     JOIN information_schema.key_column_usage kcu\n       ON kcu.constraint_name = tc.constraint_name\n      AND kcu.table_schema = tc.table_schema\n     JOIN information_schema.referential_constraints rc\n       ON rc.constraint_name = tc.constraint_name\n      AND rc.constraint_schema = tc.table_schema\n     JOIN information_schema.constraint_column_usage ccu\n       ON ccu.constraint_name = rc.unique_constraint_name\n      AND ccu.constraint_schema = rc.unique_constraint_schema\n     WHERE tc.table_schema = $1\n       AND tc.table_name = $2\n       AND tc.constraint_type = 'FOREIGN KEY'\n     ORDER BY tc.constraint_name, kcu.ordinal_position`,\n    [schema, table],\n  )\n\n  const byName = new Map<string, ForeignKeySnapshot>()\n  for (const r of rows.rows) {\n    let fk = byName.get(r.constraint_name)\n    if (!fk) {\n      fk = {\n        name: r.constraint_name,\n        columns: [],\n        refTable: r.ref_table,\n        refColumns: [],\n        onDelete: mapFkAction(r.delete_rule),\n        onUpdate: mapFkAction(r.update_rule),\n      }\n      byName.set(r.constraint_name, fk)\n    }\n    fk.columns.push(r.column_name)\n    fk.refColumns.push(r.ref_column)\n  }\n  return [...byName.values()].toSorted((a, b) => a.name.localeCompare(b.name))\n}\n\nfunction mapFkAction(raw: string): FkAction {\n  switch (raw.toUpperCase()) {\n    case 'CASCADE':\n      return 'cascade'\n    case 'RESTRICT':\n      return 'restrict'\n    case 'SET NULL':\n      return 'set_null'\n    case 'SET DEFAULT':\n      return 'set_default'\n    case 'NO ACTION':\n    default:\n      return 'no_action'\n  }\n}\n","import type {\n  ColumnSnapshot,\n  ForeignKeySnapshot,\n  FkAction,\n  IndexSnapshot,\n  SchemaSnapshot,\n  TableSnapshot,\n} from '../snapshot/types'\n\nconst DEFAULT_EXCLUDED = ['kick_migrations', 'kick_migrations_lock']\n\n/**\n * Minimal better-sqlite3 surface introspection needs (sync `.all()`).\n *\n * `all` is deliberately NOT method-generic: better-sqlite3 v12's own\n * `Statement.all(...params): Result[]` is non-generic, so a generic\n * method here would make a real `Database` instance structurally\n * incompatible (callers had to cast). Row typing happens inside this\n * module via per-call assertions instead.\n */\nexport interface SqliteIntrospectDb {\n  prepare(sql: string): { all(...params: unknown[]): unknown[] }\n}\n\nexport interface IntrospectSqliteOptions {\n  excludeTables?: string[]\n}\n\ninterface TableInfoRow {\n  cid: number\n  name: string\n  type: string\n  notnull: 0 | 1\n  dflt_value: string | null\n  pk: number\n}\n\ninterface IndexListRow {\n  seq: number\n  name: string\n  unique: 0 | 1\n  origin: string // 'c' = CREATE INDEX, 'u' = UNIQUE constraint, 'pk' = primary key\n  partial: 0 | 1\n}\n\ninterface IndexInfoRow {\n  seqno: number\n  cid: number\n  name: string | null\n}\n\ninterface FkListRow {\n  id: number\n  seq: number\n  table: string\n  from: string\n  to: string\n  on_update: string\n  on_delete: string\n  match: string\n}\n\n/**\n * Read a live SQLite database into a {@link SchemaSnapshot} via\n * `sqlite_master` + `PRAGMA` walks. Type strings come back as the\n * column's *declared* affinity (`TEXT`, `INTEGER`, …) lowercased — SQLite\n * doesn't preserve the original DSL type (a `uuid()` column reads back as\n * `text`), so this is primarily for `kick db introspect` (reverse-engineer\n * a schema), not byte-exact drift against a code-first snapshot.\n */\nexport function introspectSqlite(\n  db: SqliteIntrospectDb,\n  opts: IntrospectSqliteOptions = {},\n): SchemaSnapshot {\n  const excluded = opts.excludeTables ?? DEFAULT_EXCLUDED\n\n  const tableRows = db\n    .prepare(\n      `SELECT name FROM sqlite_master\n       WHERE type = 'table' AND name NOT LIKE 'sqlite_%'\n       ORDER BY name`,\n    )\n    .all() as { name: string }[]\n\n  const tables: Record<string, TableSnapshot> = {}\n  for (const { name } of tableRows) {\n    if (excluded.includes(name)) continue\n    tables[name] = {\n      name,\n      columns: readColumns(db, name),\n      indexes: readIndexes(db, name),\n      foreignKeys: readForeignKeys(db, name),\n      checks: [],\n    }\n  }\n  return { version: 1, dialect: 'sqlite', tables }\n}\n\nfunction readColumns(db: SqliteIntrospectDb, table: string): Record<string, ColumnSnapshot> {\n  const rows = db.prepare(`PRAGMA table_info(${quote(table)})`).all() as TableInfoRow[]\n  const out: Record<string, ColumnSnapshot> = {}\n  for (const r of rows) {\n    out[r.name] = {\n      name: r.name,\n      type: normalizeType(r.type),\n      nullable: r.notnull === 0,\n      default: r.dflt_value,\n      primaryKey: r.pk > 0,\n    }\n  }\n  return out\n}\n\nfunction readIndexes(db: SqliteIntrospectDb, table: string): IndexSnapshot[] {\n  const list = db.prepare(`PRAGMA index_list(${quote(table)})`).all() as IndexListRow[]\n  const out: IndexSnapshot[] = []\n  for (const idx of list) {\n    // Skip auto-indexes SQLite creates for UNIQUE / PK constraints — those\n    // belong to the column/constraint definitions, not standalone indexes.\n    if (idx.origin !== 'c') continue\n    const cols = (db.prepare(`PRAGMA index_info(${quote(idx.name)})`).all() as IndexInfoRow[])\n      .filter((c) => c.name !== null)\n      .map((c) => c.name as string)\n    out.push({ name: idx.name, columns: cols, unique: idx.unique === 1 })\n  }\n  return out\n}\n\nfunction readForeignKeys(db: SqliteIntrospectDb, table: string): ForeignKeySnapshot[] {\n  const rows = db.prepare(`PRAGMA foreign_key_list(${quote(table)})`).all() as FkListRow[]\n  // Group multi-column FKs by their `id`.\n  const byId = new Map<number, FkListRow[]>()\n  for (const r of rows) {\n    const g = byId.get(r.id) ?? []\n    g.push(r)\n    byId.set(r.id, g)\n  }\n  const out: ForeignKeySnapshot[] = []\n  for (const [id, group] of byId) {\n    group.sort((a, b) => a.seq - b.seq)\n    const first = group[0]\n    out.push({\n      // SQLite doesn't name FKs — synthesize a stable name.\n      name: `${table}_${group.map((g) => g.from).join('_')}_fk_${id}`,\n      columns: group.map((g) => g.from),\n      refTable: first.table,\n      refColumns: group.map((g) => g.to),\n      onDelete: mapFkAction(first.on_delete),\n      onUpdate: mapFkAction(first.on_update),\n    })\n  }\n  return out\n}\n\nfunction mapFkAction(action: string): FkAction {\n  switch (action.toUpperCase()) {\n    case 'CASCADE':\n      return 'cascade'\n    case 'RESTRICT':\n      return 'restrict'\n    case 'SET NULL':\n      return 'set_null'\n    case 'SET DEFAULT':\n      return 'set_default'\n    default:\n      return 'no_action'\n  }\n}\n\n/** Lowercase the declared type, preserving any `(length)` qualifier. */\nfunction normalizeType(declared: string): string {\n  return declared.trim().toLowerCase() || 'text'\n}\n\n/** Quote a SQLite identifier for interpolation into a PRAGMA (no binding). */\nfunction quote(name: string): string {\n  return '\"' + name.replace(/\"/g, '\"\"') + '\"'\n}\n","import type {\n  ColumnSnapshot,\n  ForeignKeySnapshot,\n  FkAction,\n  IndexSnapshot,\n  SchemaSnapshot,\n  TableSnapshot,\n} from '../snapshot/types'\n\nconst DEFAULT_EXCLUDED = ['kick_migrations', 'kick_migrations_lock']\n\n/** Minimal mysql2 surface introspection needs. Returns `[rows, fields]`. */\nexport interface MysqlIntrospectDb {\n  query<R = unknown>(sql: string, params?: readonly unknown[]): Promise<[R, unknown]>\n}\n\nexport interface IntrospectMysqlOptions {\n  excludeTables?: string[]\n}\n\ninterface ColumnRow {\n  COLUMN_NAME: string\n  DATA_TYPE: string\n  COLUMN_TYPE: string\n  IS_NULLABLE: 'YES' | 'NO'\n  COLUMN_DEFAULT: string | null\n  COLUMN_KEY: string\n  EXTRA: string\n}\n\ninterface IndexRow {\n  INDEX_NAME: string\n  COLUMN_NAME: string\n  NON_UNIQUE: number\n  SEQ_IN_INDEX: number\n}\n\ninterface FkRow {\n  CONSTRAINT_NAME: string\n  COLUMN_NAME: string\n  REF_TABLE: string\n  REF_COLUMN: string\n  DELETE_RULE: string\n  UPDATE_RULE: string\n  ORDINAL_POSITION: number\n}\n\nasync function rows<R>(db: MysqlIntrospectDb, sql: string, params: unknown[]): Promise<R[]> {\n  const [result] = await db.query<R[]>(sql, params)\n  return result\n}\n\n/**\n * Read the current MySQL database into a {@link SchemaSnapshot} via\n * `information_schema`. Types come back as the column's declared\n * `COLUMN_TYPE` (`varchar(200)`, `tinyint(1)`, …) lowercased — MySQL\n * doesn't preserve the original DSL type, so this powers `kick db\n * introspect` rather than byte-exact drift against a code-first snapshot.\n */\nexport async function introspectMysql(\n  db: MysqlIntrospectDb,\n  opts: IntrospectMysqlOptions = {},\n): Promise<SchemaSnapshot> {\n  const excluded = opts.excludeTables ?? DEFAULT_EXCLUDED\n\n  const tableRows = await rows<{ TABLE_NAME: string }>(\n    db,\n    `SELECT TABLE_NAME FROM information_schema.TABLES\n     WHERE TABLE_SCHEMA = DATABASE() AND TABLE_TYPE = 'BASE TABLE'\n     ORDER BY TABLE_NAME`,\n    [],\n  )\n\n  const tables: Record<string, TableSnapshot> = {}\n  for (const t of tableRows) {\n    if (excluded.includes(t.TABLE_NAME)) continue\n    tables[t.TABLE_NAME] = {\n      name: t.TABLE_NAME,\n      columns: await readColumns(db, t.TABLE_NAME),\n      indexes: await readIndexes(db, t.TABLE_NAME),\n      foreignKeys: await readForeignKeys(db, t.TABLE_NAME),\n      checks: [],\n    }\n  }\n  return { version: 1, dialect: 'mysql', tables }\n}\n\nasync function readColumns(\n  db: MysqlIntrospectDb,\n  table: string,\n): Promise<Record<string, ColumnSnapshot>> {\n  const cols = await rows<ColumnRow>(\n    db,\n    `SELECT COLUMN_NAME, DATA_TYPE, COLUMN_TYPE, IS_NULLABLE, COLUMN_DEFAULT, COLUMN_KEY, EXTRA\n     FROM information_schema.COLUMNS\n     WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ?\n     ORDER BY ORDINAL_POSITION`,\n    [table],\n  )\n  const out: Record<string, ColumnSnapshot> = {}\n  for (const c of cols) {\n    out[c.COLUMN_NAME] = {\n      name: c.COLUMN_NAME,\n      type: normalizeType(c),\n      nullable: c.IS_NULLABLE === 'YES',\n      default: c.COLUMN_DEFAULT,\n      primaryKey: c.COLUMN_KEY === 'PRI',\n    }\n  }\n  return out\n}\n\nasync function readIndexes(db: MysqlIntrospectDb, table: string): Promise<IndexSnapshot[]> {\n  const stats = await rows<IndexRow>(\n    db,\n    `SELECT INDEX_NAME, COLUMN_NAME, NON_UNIQUE, SEQ_IN_INDEX\n     FROM information_schema.STATISTICS\n     WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ? AND INDEX_NAME <> 'PRIMARY'\n     ORDER BY INDEX_NAME, SEQ_IN_INDEX`,\n    [table],\n  )\n  const byName = new Map<string, { cols: string[]; unique: boolean }>()\n  for (const r of stats) {\n    const e = byName.get(r.INDEX_NAME) ?? { cols: [], unique: r.NON_UNIQUE === 0 }\n    e.cols.push(r.COLUMN_NAME)\n    byName.set(r.INDEX_NAME, e)\n  }\n  return [...byName].map(([name, e]) => ({ name, columns: e.cols, unique: e.unique }))\n}\n\nasync function readForeignKeys(\n  db: MysqlIntrospectDb,\n  table: string,\n): Promise<ForeignKeySnapshot[]> {\n  const fkRows = await rows<FkRow>(\n    db,\n    `SELECT k.CONSTRAINT_NAME, k.COLUMN_NAME,\n            k.REFERENCED_TABLE_NAME AS REF_TABLE, k.REFERENCED_COLUMN_NAME AS REF_COLUMN,\n            r.DELETE_RULE, r.UPDATE_RULE, k.ORDINAL_POSITION\n     FROM information_schema.KEY_COLUMN_USAGE k\n     JOIN information_schema.REFERENTIAL_CONSTRAINTS r\n       ON r.CONSTRAINT_SCHEMA = k.TABLE_SCHEMA AND r.CONSTRAINT_NAME = k.CONSTRAINT_NAME\n     WHERE k.TABLE_SCHEMA = DATABASE() AND k.TABLE_NAME = ?\n       AND k.REFERENCED_TABLE_NAME IS NOT NULL\n     ORDER BY k.CONSTRAINT_NAME, k.ORDINAL_POSITION`,\n    [table],\n  )\n  const byName = new Map<string, FkRow[]>()\n  for (const r of fkRows) {\n    const g = byName.get(r.CONSTRAINT_NAME) ?? []\n    g.push(r)\n    byName.set(r.CONSTRAINT_NAME, g)\n  }\n  const out: ForeignKeySnapshot[] = []\n  for (const [name, group] of byName) {\n    const first = group[0]\n    out.push({\n      name,\n      columns: group.map((g) => g.COLUMN_NAME),\n      refTable: first.REF_TABLE,\n      refColumns: group.map((g) => g.REF_COLUMN),\n      onDelete: mapFkAction(first.DELETE_RULE),\n      onUpdate: mapFkAction(first.UPDATE_RULE),\n    })\n  }\n  return out\n}\n\nfunction mapFkAction(action: string): FkAction {\n  switch (action.toUpperCase()) {\n    case 'CASCADE':\n      return 'cascade'\n    case 'RESTRICT':\n      return 'restrict'\n    case 'SET NULL':\n      return 'set_null'\n    case 'SET DEFAULT':\n      return 'set_default'\n    default:\n      return 'no_action'\n  }\n}\n\n/** Use the declared `COLUMN_TYPE` (carries length), lowercased. */\nfunction normalizeType(c: ColumnRow): string {\n  return (c.COLUMN_TYPE || c.DATA_TYPE).trim().toLowerCase() || 'text'\n}\n","import type { Change, ChangeSet } from '../diff/types'\nimport type {\n  ColumnSnapshot,\n  ForeignKeySnapshot,\n  IndexSnapshot,\n  SchemaSnapshot,\n  TableSnapshot,\n} from '../snapshot/types'\nimport { quoteIdent, quoteLiteral } from './identifiers'\n\n/**\n * Raised when a change set needs a SQLite table rebuild but the emitter\n * wasn't given the resolved snapshots to build it from (it only has the\n * per-change diff). `generate()` always passes the snapshots, so this only\n * surfaces if `emitSqlite` is called bare with a rebuild-requiring change.\n */\nexport class SqliteRebuildRequiredError extends Error {\n  constructor(detail: string) {\n    super(\n      `kickjs-db: this SQLite change needs a table rebuild and no resolved ` +\n        `schema snapshot was supplied to build it — ${detail}. This is an ` +\n        `internal error; report it (generate() passes the snapshots).`,\n    )\n    this.name = 'SqliteRebuildRequiredError'\n  }\n}\n\n/**\n * Resolved before/after schema snapshots, threaded in by `generate()` so\n * the emitter can build the 12-step table-rebuild for changes SQLite's\n * `ALTER TABLE` can't express (column type/null/default changes, FK\n * add/drop on an existing table). `to` is the schema *after* the changes\n * apply; `from` is before — their column intersection drives the\n * `INSERT ... SELECT` data copy.\n */\nexport interface SqliteEmitContext {\n  from?: SchemaSnapshot\n  to?: SchemaSnapshot\n}\n\n/**\n * Emit SQLite DDL for a change set.\n *\n * Most operations map to a direct statement (CREATE/DROP/RENAME TABLE,\n * ADD/DROP/RENAME COLUMN, CREATE/DROP INDEX). The ones SQLite can't `ALTER`\n * directly — `alterColumn`, and foreign-key add/drop on an existing table —\n * are handled by a **table rebuild**: create a new table with the desired\n * shape, copy rows, drop the old, rename, recreate indexes. Foreign keys\n * are folded into `CREATE TABLE` (SQLite has no `ADD CONSTRAINT`).\n */\nexport function emitSqlite(changes: ChangeSet, ctx: SqliteEmitContext = {}): string {\n  const createdTables = new Set<string>()\n  for (const c of changes) if (c.kind === 'createTable') createdTables.add(c.table.name)\n\n  // Tables that need a rebuild (an ALTER SQLite can't express). A table\n  // created in this same change set is never rebuilt — its FKs inline into\n  // CREATE TABLE directly.\n  const rebuildTables = new Set<string>()\n  for (const c of changes) {\n    const t = perTableName(c)\n    if (!t || createdTables.has(t)) continue\n    if (c.kind === 'alterColumn' || c.kind === 'dropForeignKey' || c.kind === 'addForeignKey') {\n      rebuildTables.add(t)\n    }\n  }\n\n  const out: string[] = []\n\n  // 1. Emit every change that isn't subsumed by a rebuild.\n  for (const c of changes) {\n    const t = perTableName(c)\n    if (t && rebuildTables.has(t)) continue // folded into the rebuild below\n    const sql = emitChange(c)\n    if (sql) out.push(sql)\n  }\n\n  // 2. Emit one rebuild per affected table, from the resolved `to` snapshot.\n  for (const table of rebuildTables) {\n    out.push(emitRebuild(table, ctx))\n  }\n\n  return out.join('\\n')\n}\n\n/** The table a per-table change targets, or null for table-level changes. */\nfunction perTableName(change: Change): string | null {\n  switch (change.kind) {\n    case 'addColumn':\n    case 'dropColumn':\n    case 'renameColumn':\n    case 'alterColumn':\n    case 'addIndex':\n    case 'dropIndex':\n    case 'addForeignKey':\n    case 'dropForeignKey':\n      return change.table\n    default:\n      return null\n  }\n}\n\nfunction emitChange(change: Change): string {\n  switch (change.kind) {\n    case 'createTable':\n      return emitCreateTable(change.table.name, change.table)\n    case 'dropTable':\n      return `DROP TABLE ${quoteIdent(change.table.name)};`\n    case 'renameTable':\n      return `ALTER TABLE ${quoteIdent(change.from)} RENAME TO ${quoteIdent(change.to)};`\n    case 'addColumn':\n      return `ALTER TABLE ${quoteIdent(change.table)} ADD COLUMN ${emitColumnDecl(change.column)};`\n    case 'dropColumn':\n      return `ALTER TABLE ${quoteIdent(change.table)} DROP COLUMN ${quoteIdent(change.column.name)};`\n    case 'renameColumn':\n      return `ALTER TABLE ${quoteIdent(change.table)} RENAME COLUMN ${quoteIdent(change.from)} TO ${quoteIdent(change.to)};`\n    case 'addIndex':\n      return emitAddIndex(change.table, change.index)\n    case 'dropIndex':\n      return `DROP INDEX ${quoteIdent(change.index.name)};`\n    case 'addForeignKey':\n    case 'dropForeignKey':\n    case 'alterColumn':\n      // FK add/drop + column alters never emit a standalone statement:\n      // new-table FKs inline into CREATE TABLE, existing-table FK + column\n      // changes are subsumed by the table rebuild.\n      return ''\n    case 'createEnum':\n    case 'dropEnum':\n    case 'addEnumValue':\n    case 'removeEnumValue':\n      throw new Error(\n        `kickjs-db: enum changes are PostgreSQL-only and can't be emitted for SQLite. ` +\n          `Model the constrained set with a CHECK constraint or a lookup table instead.`,\n      )\n  }\n}\n\n/**\n * The SQLite-recommended safe table mutation: create the new table, copy\n * the rows that survive (column intersection of old + new), drop the old,\n * rename, and recreate indexes.\n *\n * Works for tables without inbound foreign-key references (the common\n * case for a column type/default change). Tables referenced by other\n * tables' FKs would need `PRAGMA foreign_keys=OFF` outside the migration\n * transaction — out of scope here.\n */\nfunction emitRebuild(table: string, ctx: SqliteEmitContext): string {\n  const next = ctx.to?.tables[table]\n  if (!next) {\n    throw new SqliteRebuildRequiredError(`no resolved snapshot for table '${table}'`)\n  }\n  const prev = ctx.from?.tables[table]\n\n  // Copy columns present in BOTH old and new (added columns get their\n  // default; dropped columns are simply not selected).\n  const newCols = Object.keys(next.columns)\n  const common = prev ? newCols.filter((c) => c in prev.columns) : newCols\n  const colList = common.map(quoteIdent).join(', ')\n\n  const tmp = `_kick_new_${table}`\n  const lines: string[] = [\n    emitCreateTable(tmp, next),\n    common.length > 0\n      ? `INSERT INTO ${quoteIdent(tmp)} (${colList})\\n  SELECT ${colList} FROM ${quoteIdent(table)};`\n      : `-- (no columns survive the rebuild; nothing to copy)`,\n    `DROP TABLE ${quoteIdent(table)};`,\n    `ALTER TABLE ${quoteIdent(tmp)} RENAME TO ${quoteIdent(table)};`,\n  ]\n  for (const idx of next.indexes) lines.push(emitAddIndex(table, idx))\n  return lines.join('\\n')\n}\n\nfunction emitCreateTable(name: string, t: TableSnapshot): string {\n  const columns = Object.values(t.columns)\n  const pkCols = columns.filter((c) => c.primaryKey)\n\n  // A single integer PK becomes the rowid alias only when declared inline\n  // as `INTEGER PRIMARY KEY`; composite/non-integer PKs use a table clause.\n  const inlinePk =\n    pkCols.length === 1 && sqliteType(pkCols[0].type) === 'INTEGER' ? pkCols[0] : null\n\n  const lines = columns.map((c) => emitColumnDecl(c, c === inlinePk))\n  if (!inlinePk && pkCols.length > 0) {\n    lines.push(`PRIMARY KEY (${pkCols.map((c) => quoteIdent(c.name)).join(', ')})`)\n  }\n  for (const fk of t.foreignKeys) lines.push(emitInlineFk(fk))\n\n  return `CREATE TABLE ${quoteIdent(name)} (\\n  ${lines.join(',\\n  ')}\\n);`\n}\n\nfunction emitColumnDecl(c: ColumnSnapshot, inlinePk = false): string {\n  let s = `${quoteIdent(c.name)} ${sqliteType(c.type)}`\n  if (inlinePk) {\n    s += ' PRIMARY KEY'\n    if (/serial/i.test(c.type)) s += ' AUTOINCREMENT'\n  }\n  if (!c.nullable && !inlinePk) s += ' NOT NULL'\n  if (c.default !== null) s += ` DEFAULT ${sqliteDefault(c.default)}`\n  return s\n}\n\nfunction emitAddIndex(table: string, i: IndexSnapshot): string {\n  const cols = i.columns.map(quoteIdent).join(', ')\n  return `CREATE${i.unique ? ' UNIQUE' : ''} INDEX ${quoteIdent(i.name)} ON ${quoteIdent(table)} (${cols});`\n}\n\nconst FK_ACTIONS: Record<string, string> = {\n  cascade: 'CASCADE',\n  restrict: 'RESTRICT',\n  set_null: 'SET NULL',\n  set_default: 'SET DEFAULT',\n  no_action: 'NO ACTION',\n}\n\nfunction emitInlineFk(fk: ForeignKeySnapshot): string {\n  const cols = fk.columns.map(quoteIdent).join(', ')\n  const refCols = fk.refColumns.map(quoteIdent).join(', ')\n  return (\n    `FOREIGN KEY (${cols}) REFERENCES ${quoteIdent(fk.refTable)} (${refCols}) ` +\n    `ON DELETE ${FK_ACTIONS[fk.onDelete]} ON UPDATE ${FK_ACTIONS[fk.onUpdate]}`\n  )\n}\n\n/** Map a Postgres column type string to a SQLite affinity type. */\nexport function sqliteType(pgType: string): string {\n  const base = pgType\n    .toLowerCase()\n    .replace(/\\(.*\\)/, '')\n    .replace(/\\[\\]$/, '')\n    .trim()\n\n  if (/^(serial|bigserial|smallserial|big|small)?int(eger|2|4|8)?$/.test(base)) return 'INTEGER'\n  if (base === 'serial' || base === 'bigserial' || base === 'smallserial') return 'INTEGER'\n  if (base === 'boolean' || base === 'bool') return 'INTEGER'\n  if (/^(real|float4|float8|double precision|float)$/.test(base)) return 'REAL'\n  if (/^(numeric|decimal|money)$/.test(base)) return 'NUMERIC'\n  if (base === 'bytea' || base === 'blob') return 'BLOB'\n  return 'TEXT'\n}\n\n/** Map a Postgres default expression to its SQLite equivalent. */\nfunction sqliteDefault(value: unknown): string {\n  if (typeof value === 'boolean') return value ? '1' : '0'\n  if (typeof value === 'number' || typeof value === 'bigint') return String(value)\n  const str = String(value).trim()\n\n  if (/^true$/i.test(str)) return '1'\n  if (/^false$/i.test(str)) return '0'\n  if (/^(gen_random_uuid|uuid_generate_v4)\\(\\)$/i.test(str)) return '(lower(hex(randomblob(16))))'\n  if (/^now\\(\\)$/i.test(str)) return 'CURRENT_TIMESTAMP'\n  if (/^(CURRENT_TIMESTAMP|CURRENT_DATE|CURRENT_TIME|NULL)$/i.test(str)) return str.toUpperCase()\n  if (/^-?\\d+(\\.\\d+)?$/.test(str)) return str\n  if (/^[a-z_][a-z0-9_]*\\s*\\([^)]*\\)$/i.test(str)) return str\n  return quoteLiteral(str)\n}\n","import type { Change, ChangeSet } from '../diff/types'\nimport type {\n  ColumnSnapshot,\n  ForeignKeySnapshot,\n  IndexSnapshot,\n  TableSnapshot,\n} from '../snapshot/types'\nimport { quoteLiteral } from './identifiers'\n\n/** MySQL quotes identifiers with backticks, not double quotes. */\nfunction ident(name: string): string {\n  return name\n    .split('.')\n    .map((part) => '`' + part.replace(/`/g, '``') + '`')\n    .join('.')\n}\n\n/**\n * Emit MySQL DDL for a change set.\n *\n * MySQL has full `ALTER TABLE` support (unlike SQLite), so this mirrors\n * the Postgres emitter's structure — column/FK/index changes map to direct\n * ALTERs. The MySQL-specific bits:\n * - backtick identifiers + PG→MySQL type mapping;\n * - a single integer PK is emitted inline as `... AUTO_INCREMENT PRIMARY\n *   KEY` (MySQL requires an auto-increment column to be a key);\n * - `alterColumn` uses `MODIFY COLUMN` (MySQL restates the whole column\n *   definition at once, rather than PG's separate SET TYPE / SET DEFAULT\n *   / SET NOT NULL clauses);\n * - `dropForeignKey` uses `DROP FOREIGN KEY` (not `DROP CONSTRAINT`).\n * - PG `ENUM` type changes are PG-only and throw (MySQL enums are inline\n *   column types, not standalone objects).\n */\nexport function emitMysql(changes: ChangeSet): string {\n  return changes\n    .map(emitChange)\n    .filter((s) => s.length > 0)\n    .join('\\n')\n}\n\nfunction emitChange(change: Change): string {\n  switch (change.kind) {\n    case 'createTable':\n      return emitCreateTable(change.table)\n    case 'dropTable':\n      return `DROP TABLE ${ident(change.table.name)};`\n    case 'renameTable':\n      return `ALTER TABLE ${ident(change.from)} RENAME TO ${ident(change.to)};`\n    case 'addColumn':\n      return `ALTER TABLE ${ident(change.table)} ADD COLUMN ${emitColumnDecl(change.column)};`\n    case 'dropColumn':\n      return `ALTER TABLE ${ident(change.table)} DROP COLUMN ${ident(change.column.name)};`\n    case 'renameColumn':\n      // MySQL 8.0+ supports RENAME COLUMN.\n      return `ALTER TABLE ${ident(change.table)} RENAME COLUMN ${ident(change.from)} TO ${ident(change.to)};`\n    case 'alterColumn':\n      // MySQL restates the full column definition in one MODIFY clause.\n      return `ALTER TABLE ${ident(change.table)} MODIFY COLUMN ${emitColumnDecl(change.after)};`\n    case 'addIndex':\n      return emitAddIndex(change.table, change.index)\n    case 'dropIndex':\n      return `DROP INDEX ${ident(change.index.name)} ON ${ident(change.table)};`\n    case 'addForeignKey':\n      return emitAddFk(change.table, change.fk)\n    case 'dropForeignKey':\n      return `ALTER TABLE ${ident(change.table)} DROP FOREIGN KEY ${ident(change.fk.name)};`\n    case 'createEnum':\n    case 'dropEnum':\n    case 'addEnumValue':\n    case 'removeEnumValue':\n      throw new Error(\n        `kickjs-db: standalone ENUM type changes are PostgreSQL-only and can't be ` +\n          `emitted for MySQL. Model the column as an inline MySQL ENUM(...) or a ` +\n          `CHECK constraint instead.`,\n      )\n  }\n}\n\nfunction emitCreateTable(t: TableSnapshot): string {\n  const columns = Object.values(t.columns)\n  const pkCols = columns.filter((c) => c.primaryKey)\n\n  // A single integer PK is emitted inline with AUTO_INCREMENT (when the\n  // column is serial) — MySQL requires an auto-increment column to be the\n  // key, declared on the column itself.\n  const inlinePk = pkCols.length === 1 && /serial/i.test(pkCols[0].type) ? pkCols[0] : null\n\n  const lines = columns.map((c) => emitColumnDecl(c, c === inlinePk))\n  if (!inlinePk && pkCols.length > 0) {\n    lines.push(`PRIMARY KEY (${pkCols.map((c) => ident(c.name)).join(', ')})`)\n  }\n  return `CREATE TABLE ${ident(t.name)} (\\n  ${lines.join(',\\n  ')}\\n);`\n}\n\nfunction emitColumnDecl(c: ColumnSnapshot, inlinePk = false): string {\n  let s = `${ident(c.name)} ${mysqlType(c.type)}`\n  if (!c.nullable) s += ' NOT NULL'\n  if (c.default !== null) s += ` DEFAULT ${mysqlDefault(c.default)}`\n  if (inlinePk) s += ' AUTO_INCREMENT PRIMARY KEY'\n  return s\n}\n\nfunction emitAddIndex(table: string, i: IndexSnapshot): string {\n  const cols = i.columns.map(ident).join(', ')\n  return `CREATE${i.unique ? ' UNIQUE' : ''} INDEX ${ident(i.name)} ON ${ident(table)} (${cols});`\n}\n\nconst FK_ACTIONS: Record<string, string> = {\n  cascade: 'CASCADE',\n  restrict: 'RESTRICT',\n  set_null: 'SET NULL',\n  set_default: 'SET DEFAULT',\n  no_action: 'NO ACTION',\n}\n\nfunction emitAddFk(table: string, fk: ForeignKeySnapshot): string {\n  const cols = fk.columns.map(ident).join(', ')\n  const refCols = fk.refColumns.map(ident).join(', ')\n  return (\n    `ALTER TABLE ${ident(table)} ADD CONSTRAINT ${ident(fk.name)} ` +\n    `FOREIGN KEY (${cols}) REFERENCES ${ident(fk.refTable)} (${refCols}) ` +\n    `ON DELETE ${FK_ACTIONS[fk.onDelete]} ON UPDATE ${FK_ACTIONS[fk.onUpdate]};`\n  )\n}\n\n/**\n * Map a Postgres column type string to a MySQL type.\n */\nexport function mysqlType(pgType: string): string {\n  const lower = pgType.toLowerCase().trim()\n  const base = lower\n    .replace(/\\(.*\\)/, '')\n    .replace(/\\[\\]$/, '')\n    .trim()\n  // Preserve an explicit length/precision, e.g. varchar(200) → VARCHAR(200).\n  const lenMatch = lower.match(/\\(([^)]*)\\)/)\n  const len = lenMatch ? `(${lenMatch[1]})` : ''\n\n  if (base === 'serial' || base === 'integer' || base === 'int' || base === 'int4') return 'INT'\n  if (base === 'bigserial' || base === 'bigint' || base === 'int8') return 'BIGINT'\n  if (base === 'smallserial' || base === 'smallint' || base === 'int2') return 'SMALLINT'\n  if (base === 'boolean' || base === 'bool') return 'TINYINT(1)'\n  if (base === 'real' || base === 'float4') return 'FLOAT'\n  if (base === 'double precision' || base === 'float8' || base === 'float') return 'DOUBLE'\n  if (base === 'numeric' || base === 'decimal') return `DECIMAL${len || '(10,0)'}`\n  if (base === 'money') return 'DECIMAL(19,4)'\n  if (base === 'uuid') return 'CHAR(36)'\n  if (base === 'varchar' || base === 'character varying') return `VARCHAR${len || '(255)'}`\n  if (base === 'char' || base === 'character' || base === 'bpchar') return `CHAR${len || '(1)'}`\n  if (base === 'text' || base === 'citext') return 'TEXT'\n  if (base === 'json' || base === 'jsonb') return 'JSON'\n  if (base === 'timestamp' || base === 'timestamptz') return 'TIMESTAMP'\n  if (base === 'date') return 'DATE'\n  if (base === 'time' || base === 'timetz') return 'TIME'\n  if (base === 'bytea' || base === 'blob') return 'BLOB'\n  // Pass anything else through uppercased with its length (best effort).\n  return base.toUpperCase() + len\n}\n\n/**\n * Map a Postgres default expression to its MySQL equivalent.\n */\nfunction mysqlDefault(value: unknown): string {\n  if (typeof value === 'boolean') return value ? '1' : '0'\n  if (typeof value === 'number' || typeof value === 'bigint') return String(value)\n  const str = String(value).trim()\n\n  if (/^true$/i.test(str)) return '1'\n  if (/^false$/i.test(str)) return '0'\n\n  // Postgres UUID/`now()` generators → MySQL equivalents.\n  if (/^(gen_random_uuid|uuid_generate_v4)\\(\\)$/i.test(str)) return '(UUID())'\n  if (/^now\\(\\)$/i.test(str)) return 'CURRENT_TIMESTAMP'\n  if (/^(CURRENT_TIMESTAMP|CURRENT_DATE|CURRENT_TIME|NULL)$/i.test(str)) return str.toUpperCase()\n  if (/^-?\\d+(\\.\\d+)?$/.test(str)) return str\n\n  // Other bare function calls pass through; everything else is a literal.\n  if (/^[a-z_][a-z0-9_]*\\s*\\([^)]*\\)$/i.test(str)) return str\n  return quoteLiteral(str)\n}\n","import { diff } from '../diff/engine'\nimport type { Change } from '../diff/types'\nimport type {\n  ColumnSnapshot,\n  Dialect,\n  ForeignKeySnapshot,\n  SchemaSnapshot,\n  TableSnapshot,\n} from '../snapshot/types'\nimport { sqliteType } from '../emit/sqlite'\nimport { mysqlType } from '../emit/mysql'\nimport { MigrationDriftError, type SchemaDiffSummary } from './errors'\n\n/**\n * SQLite and MySQL introspection is lossy against a code-first snapshot: a\n * `uuid()` column reads back as `text` / `char(36)`, default expressions\n * store in a normalised form, and SQLite doesn't preserve FK names.\n * Comparing the raw snapshots would flag drift on every migration.\n *\n * To get meaningful drift on those dialects we canonicalise BOTH sides\n * into the same shape before diffing: column types run through the emit\n * type-mapper (so `uuid` and `text` collapse together), defaults are\n * dropped (too divergent to align reliably), and FK names become a\n * structural key. This still catches the drift that matters — tables /\n * columns added or removed, type / nullability / PK changes, indexes —\n * without false positives. PostgreSQL round-trips faithfully, so it is\n * compared raw and keeps default-level drift detection.\n */\nfunction normalizeForDrift(snap: SchemaSnapshot): SchemaSnapshot {\n  if (snap.dialect === 'postgres') return snap\n\n  const tables: Record<string, TableSnapshot> = {}\n  for (const [name, t] of Object.entries(snap.tables)) {\n    const columns: Record<string, ColumnSnapshot> = {}\n    for (const [cn, c] of Object.entries(t.columns)) {\n      columns[cn] = { ...c, type: canonicalType(c.type, snap.dialect), default: null }\n    }\n    tables[name] = { ...t, columns, foreignKeys: t.foreignKeys.map(canonicalFk) }\n  }\n  return { ...snap, tables }\n}\n\nfunction canonicalType(type: string, dialect: Dialect): string {\n  if (dialect === 'sqlite') return sqliteType(type).toLowerCase()\n  if (dialect === 'mysql') return mysqlType(type).toLowerCase()\n  return type\n}\n\n/** Replace the FK name with a structural key (SQLite synthesizes names). */\nfunction canonicalFk(fk: ForeignKeySnapshot): ForeignKeySnapshot {\n  return {\n    name: `${fk.columns.join(',')}=>${fk.refTable}(${fk.refColumns.join(',')})`,\n    columns: fk.columns,\n    refTable: fk.refTable,\n    refColumns: fk.refColumns,\n    onDelete: fk.onDelete,\n    onUpdate: fk.onUpdate,\n  }\n}\n\nexport type DriftBehavior = 'error' | 'warn' | 'ignore'\n\nexport interface DriftLogger {\n  warn: (message: string) => void\n}\n\nexport async function checkDrift(\n  liveSnapshot: SchemaSnapshot,\n  expectedSnapshot: SchemaSnapshot,\n  behavior: DriftBehavior,\n  log: DriftLogger = console,\n): Promise<void> {\n  if (behavior === 'ignore') return\n  // diff(prev, next) reads expected as `prev` and live as `next` so 'added'\n  // means \"live has it but the snapshot doesn't\" — i.e. someone ran DDL\n  // outside the migration runner. Both sides are canonicalised first so\n  // SQLite/MySQL's lossy introspection doesn't flag phantom drift.\n  const changes = diff(normalizeForDrift(expectedSnapshot), normalizeForDrift(liveSnapshot))\n  if (changes.length === 0) return\n\n  const summary = summarize(changes)\n  const message = `Schema drift detected: ${summary.added.length} added, ${summary.removed.length} removed, ${summary.changed.length} changed`\n  if (behavior === 'warn') {\n    log.warn(message)\n    return\n  }\n  throw new MigrationDriftError(message, summary)\n}\n\nfunction summarize(changes: Change[]): SchemaDiffSummary {\n  const added: string[] = []\n  const removed: string[] = []\n  const changed: string[] = []\n  for (const c of changes) {\n    switch (c.kind) {\n      case 'createTable':\n        added.push(c.table.name)\n        break\n      case 'dropTable':\n        removed.push(c.table.name)\n        break\n      case 'addColumn':\n        added.push(`${c.table}.${c.column.name}`)\n        break\n      case 'dropColumn':\n        removed.push(`${c.table}.${c.column.name}`)\n        break\n      case 'alterColumn':\n        changed.push(`${c.table}.${c.column}`)\n        break\n      case 'renameColumn':\n        changed.push(`${c.table}.${c.from}→${c.to}`)\n        break\n      case 'renameTable':\n        changed.push(`${c.from}→${c.to}`)\n        break\n      case 'addIndex':\n        added.push(`${c.table}#${c.index.name}`)\n        break\n      case 'dropIndex':\n        removed.push(`${c.table}#${c.index.name}`)\n        break\n      case 'addForeignKey':\n        added.push(`${c.table}!${c.fk.name}`)\n        break\n      case 'dropForeignKey':\n        removed.push(`${c.table}!${c.fk.name}`)\n        break\n    }\n  }\n  return { added, removed, changed }\n}\n","import path from 'node:path'\nimport { readFile } from 'node:fs/promises'\n\nimport { readJournal, computeMigrationHash } from './journal'\nimport { MigrationLockError, MigrationHashError, UnreviewedMigrationError } from './errors'\nimport { checkDrift, type DriftBehavior, type DriftLogger } from './drift'\nimport { enforceEnumDropGate } from './enum-drop-gate'\nimport type { MigrationAdapter } from './adapter'\nimport type { SchemaSnapshot } from '../snapshot/types'\n\nexport interface RunnerOptions {\n  adapter: MigrationAdapter\n  migrationsDir: string\n  /** When true, refuse to apply migrations whose meta.json.reviewed is false. Defaults to true outside dev. */\n  requireReviewed?: boolean\n  /** Owner string written into the lock table for diagnostics. */\n  owner?: string\n  /** Drift detection mode. Default 'error'. */\n  driftCheck?: DriftBehavior\n  /** Logger surface for drift warnings. Defaults to console. */\n  log?: DriftLogger\n  /**\n   * Allow migrations carrying the `-- KICK ENUM REMOVE` header to\n   * apply. Default `false`. CLI exposes via `--confirm-enum-drop`.\n   * Spec: docs/db/spec-enum-value-removal.md.\n   */\n  confirmEnumDrop?: boolean\n}\n\nexport interface AppliedSummary {\n  applied: string[]\n  batch: number | null\n}\n\ninterface PreparedEntry {\n  id: string\n  tag: string\n  hash: string\n}\n\nasync function withLock<T>(opts: RunnerOptions, fn: () => Promise<T>): Promise<T> {\n  const owner = opts.owner ?? `${process.pid}@${new Date().toISOString()}`\n  const got = await opts.adapter.acquireLock(owner)\n  if (!got) {\n    throw new MigrationLockError('Another process holds the migration lock')\n  }\n  try {\n    return await fn()\n  } finally {\n    await opts.adapter.releaseLock()\n  }\n}\n\n/**\n * Verify pending entries: hash matches stored, meta.reviewed is true (if\n * requireReviewed). Throws MigrationHashError or UnreviewedMigrationError on\n * the first failure.\n */\nasync function verifyPending(\n  pending: PreparedEntry[],\n  migrationsDir: string,\n  requireReviewed: boolean,\n): Promise<void> {\n  for (const entry of pending) {\n    const dir = path.join(migrationsDir, entry.id)\n    const actualHash = await computeMigrationHash(dir)\n    if (actualHash !== entry.hash) {\n      throw new MigrationHashError(entry.id, entry.hash, actualHash)\n    }\n    if (requireReviewed) {\n      const meta = JSON.parse(await readFile(path.join(dir, 'meta.json'), 'utf8'))\n      if (meta.reviewed !== true) {\n        throw new UnreviewedMigrationError(entry.id)\n      }\n    }\n  }\n}\n\nasync function applyEntry(entry: PreparedEntry, batch: number, opts: RunnerOptions): Promise<void> {\n  const dir = path.join(opts.migrationsDir, entry.id)\n  const upSql = await readFile(path.join(dir, 'up.sql'), 'utf8')\n  const meta = JSON.parse(await readFile(path.join(dir, 'meta.json'), 'utf8'))\n  const useTx = meta.transaction !== false\n\n  // Enum-drop gate runs before any DB write so the runner can refuse\n  // a destructive migration without partial application.\n  enforceEnumDropGate(entry.id, upSql, opts.confirmEnumDrop ?? false)\n\n  if (useTx) {\n    await opts.adapter.applySqlInTx(upSql)\n  } else {\n    await opts.adapter.applySqlNoTx(upSql)\n  }\n  await opts.adapter.recordApplied({\n    id: entry.id,\n    name: entry.tag,\n    hash: entry.hash,\n    batch,\n    direction: 'up',\n  })\n}\n\nasync function runForward(opts: RunnerOptions, pending: PreparedEntry[]): Promise<AppliedSummary> {\n  if (pending.length === 0) {\n    return { applied: [], batch: null }\n  }\n\n  const requireReviewed = opts.requireReviewed ?? process.env.NODE_ENV !== 'development'\n  await verifyPending(pending, opts.migrationsDir, requireReviewed)\n\n  const applied = await opts.adapter.listApplied()\n  const nextBatch = (applied.length === 0 ? 0 : Math.max(...applied.map((r) => r.batch))) + 1\n\n  const ids: string[] = []\n  for (const entry of pending) {\n    await applyEntry(entry, nextBatch, opts)\n    ids.push(entry.id)\n  }\n  return { applied: ids, batch: nextBatch }\n}\n\nasync function listPending(opts: RunnerOptions): Promise<PreparedEntry[]> {\n  const journal = await readJournal(opts.migrationsDir, opts.adapter.dialect)\n  const applied = await opts.adapter.listApplied()\n  const appliedIds = new Set(applied.map((r) => r.id))\n  return journal.entries\n    .filter((e) => !appliedIds.has(e.id))\n    .map((e) => ({ id: e.id, tag: e.tag, hash: e.hash }))\n}\n\nasync function maybeCheckDrift(opts: RunnerOptions): Promise<void> {\n  const behavior = opts.driftCheck ?? 'error'\n  if (behavior === 'ignore') return\n  const applied = await opts.adapter.listApplied()\n  if (applied.length === 0) return // nothing to compare against\n  const sorted = [...applied].toSorted((a, b) =>\n    a.batch !== b.batch ? a.batch - b.batch : a.appliedAt.localeCompare(b.appliedAt),\n  )\n  const last = sorted[sorted.length - 1]\n  let expected: SchemaSnapshot\n  try {\n    expected = JSON.parse(\n      await readFile(path.join(opts.migrationsDir, last.id, 'snapshot.json'), 'utf8'),\n    )\n  } catch {\n    return // snapshot missing — diagnostic, not fatal here\n  }\n  const live = await opts.adapter.introspect()\n  await checkDrift(live, expected, behavior, opts.log)\n}\n\nexport async function migrateLatest(opts: RunnerOptions): Promise<AppliedSummary> {\n  await opts.adapter.ensureMigrationTables()\n  return withLock(opts, async () => {\n    await maybeCheckDrift(opts)\n    const pending = await listPending(opts)\n    return runForward(opts, pending)\n  })\n}\n\nexport async function migrateUp(opts: RunnerOptions): Promise<AppliedSummary> {\n  await opts.adapter.ensureMigrationTables()\n  return withLock(opts, async () => {\n    await maybeCheckDrift(opts)\n    const pending = await listPending(opts)\n    return runForward(opts, pending.slice(0, 1))\n  })\n}\n\nexport interface ReversedSummary {\n  reversed: string | null\n}\n\nasync function applyReverse(id: string, opts: RunnerOptions): Promise<void> {\n  const dir = path.join(opts.migrationsDir, id)\n  const downSql = await readFile(path.join(dir, 'down.sql'), 'utf8')\n  const meta = JSON.parse(await readFile(path.join(dir, 'meta.json'), 'utf8'))\n  const requireReviewed = opts.requireReviewed ?? process.env.NODE_ENV !== 'development'\n  if (requireReviewed && meta.reviewed !== true) {\n    throw new UnreviewedMigrationError(id)\n  }\n  const useTx = meta.transaction !== false\n  if (useTx) {\n    await opts.adapter.applySqlInTx(downSql)\n  } else {\n    await opts.adapter.applySqlNoTx(downSql)\n  }\n  await opts.adapter.removeApplied(id)\n}\n\nexport async function migrateDown(opts: RunnerOptions): Promise<ReversedSummary> {\n  await opts.adapter.ensureMigrationTables()\n  return withLock(opts, async () => {\n    const applied = await opts.adapter.listApplied()\n    if (applied.length === 0) return { reversed: null }\n    // Sort by batch then appliedAt so 'most recent' is unambiguous even if\n    // two migrations share a batch number (same `migrate latest` run).\n    const sorted = [...applied].toSorted((a, b) =>\n      a.batch !== b.batch ? a.batch - b.batch : a.appliedAt.localeCompare(b.appliedAt),\n    )\n    const last = sorted[sorted.length - 1]\n    await applyReverse(last.id, opts)\n    return { reversed: last.id }\n  })\n}\n\nexport interface RollbackSummary {\n  reversed: string[]\n  batch: number | null\n}\n\nexport interface StatusEntry {\n  id: string\n  tag: string\n  hash: string\n  state: 'applied' | 'pending'\n  batch: number | null\n  appliedAt: string | null\n  reviewed: boolean\n}\n\nexport async function migrateStatus(\n  opts: Pick<RunnerOptions, 'adapter' | 'migrationsDir'>,\n): Promise<StatusEntry[]> {\n  await opts.adapter.ensureMigrationTables()\n  const journal = await readJournal(opts.migrationsDir, opts.adapter.dialect)\n  const applied = await opts.adapter.listApplied()\n  const byId = new Map(applied.map((r) => [r.id, r]))\n\n  const entries: StatusEntry[] = []\n  for (const e of journal.entries) {\n    const row = byId.get(e.id)\n    let reviewed = false\n    try {\n      const meta = JSON.parse(\n        await readFile(path.join(opts.migrationsDir, e.id, 'meta.json'), 'utf8'),\n      )\n      reviewed = meta.reviewed === true\n    } catch {\n      // Missing meta.json — treat as un-reviewed; the runner will refuse to\n      // apply anyway. Don't fail status output for diagnostic purposes.\n    }\n    entries.push({\n      id: e.id,\n      tag: e.tag,\n      hash: e.hash,\n      state: row ? 'applied' : 'pending',\n      batch: row?.batch ?? null,\n      appliedAt: row?.appliedAt ?? null,\n      reviewed,\n    })\n  }\n  return entries\n}\n\nexport async function migrateRollback(opts: RunnerOptions): Promise<RollbackSummary> {\n  await opts.adapter.ensureMigrationTables()\n  return withLock(opts, async () => {\n    const applied = await opts.adapter.listApplied()\n    if (applied.length === 0) return { reversed: [], batch: null }\n\n    const lastBatch = Math.max(...applied.map((r) => r.batch))\n    // Reverse-applied order so teardown matches dependencies (drop FK before\n    // drop table etc).\n    const targets = applied\n      .filter((r) => r.batch === lastBatch)\n      .toSorted((a, b) => a.appliedAt.localeCompare(b.appliedAt))\n      .toReversed()\n\n    const reversed: string[] = []\n    for (const row of targets) {\n      await applyReverse(row.id, opts)\n      reversed.push(row.id)\n    }\n    return { reversed, batch: lastBatch }\n  })\n}\n","import { defineAdapter } from '@forinda/kickjs'\nimport type { InjectionToken } from '@forinda/kickjs'\n\nimport { migrateLatest, migrateStatus } from './migrate/runner'\nimport type { MigrationAdapter } from './migrate/adapter'\nimport type { DriftBehavior } from './migrate/drift'\n\nexport type MigrationsOnBoot = 'fail-if-pending' | 'apply' | 'ignore'\n\nexport interface KickDbAdapterConfig {\n  /** The driver-bound MigrationAdapter — pgAdapter() in @forinda/kickjs-db/pg, etc. */\n  migrationAdapter: MigrationAdapter\n  /** Directory containing the generated migrations + _journal.json. */\n  migrationsDir: string\n  /** Boot policy. Default 'fail-if-pending' — mirror the operator-explicit philosophy. */\n  migrationsOnBoot?: MigrationsOnBoot\n  /** Drift detection mode. Default 'error' outside dev. */\n  driftCheck?: DriftBehavior\n  /** Default true outside dev. */\n  requireReviewed?: boolean\n  /** Optional DI token to register the migrationAdapter under, for adopters who need direct access. */\n  token?: InjectionToken<MigrationAdapter>\n  /**\n   * Optional KickEventBus the adapter publishes migration events to.\n   * When set, `db:migration-applied` fires after a successful\n   * `migrateLatest()` on boot (apply policy only). Pair with\n   * `DEVTOOLS_BUS` so the events surface in the DevTools panel:\n   *\n   *   import { DEVTOOLS_BUS } from '@forinda/kickjs-devtools-kit/bus/token'\n   *   // Resolve only when devtools is actually wired — adopters who\n   *   // skip @forinda/kickjs-devtools never register the token, and\n   *   // resolve() throws on missing tokens.\n   *   const adapter = kickDbAdapter({\n   *     ...,\n   *     bus: container.has(DEVTOOLS_BUS) ? container.resolve(DEVTOOLS_BUS) : undefined,\n   *   })\n   *\n   * Type imported via `import type` so kickjs-db keeps devtools-kit\n   * as an optional peer.\n   */\n  bus?: import('@forinda/kickjs-devtools-kit/bus').KickEventBus\n}\n\n/**\n * KickJS lifecycle adapter for kickjs-db. Three jobs:\n *\n *  1. On boot, decide what to do about pending migrations per `migrationsOnBoot`.\n *     - 'fail-if-pending' (default): throw if any pending exists. Operators\n *       run `kick db migrate latest` explicitly before deploys land. Avoids\n *       the prisma footgun where migrations silently apply on deploy.\n *     - 'apply': run migrateLatest() automatically. Useful for dev / preview\n *       environments where convenience matters more than safety.\n *     - 'ignore': boot regardless. Last-resort escape hatch.\n *  2. On shutdown, close the migrationAdapter (drains the pool, etc).\n *  3. Register the migrationAdapter under an optional DI token so adopters\n *     can pull it for ad-hoc tooling. The KickDbClient (Task 19b) registers\n *     separately under DB_PRIMARY.\n */\nexport const kickDbAdapter = defineAdapter<KickDbAdapterConfig>({\n  name: 'kickjs-db',\n  build: (config) => ({\n    async beforeStart({ container }) {\n      const policy = config.migrationsOnBoot ?? 'fail-if-pending'\n      const status = await migrateStatus({\n        adapter: config.migrationAdapter,\n        migrationsDir: config.migrationsDir,\n      })\n      const pending = status.filter((s) => s.state === 'pending')\n\n      if (pending.length > 0) {\n        if (policy === 'fail-if-pending') {\n          throw new Error(\n            `kickjs-db: ${pending.length} pending migration(s); run \\`kick db migrate latest\\` before boot`,\n          )\n        }\n        if (policy === 'apply') {\n          const result = await migrateLatest({\n            adapter: config.migrationAdapter,\n            migrationsDir: config.migrationsDir,\n            requireReviewed: config.requireReviewed,\n            driftCheck: config.driftCheck,\n          })\n          // Republish to DevTools when a bus is wired so the panel\n          // can surface \"migrations ran on boot\" without polling.\n          // `applied` is the list of migration ids the runner ran;\n          // `batch` is the batch number the journal stamped them with.\n          if (config.bus) {\n            config.bus.emit('db:migration-applied', {\n              applied: result.applied,\n              batch: result.batch,\n            })\n          }\n        }\n        // 'ignore' falls through.\n      }\n\n      if (config.token) {\n        container.registerFactory(config.token, () => config.migrationAdapter)\n      }\n    },\n    async shutdown() {\n      await config.migrationAdapter.close()\n    },\n  }),\n})\n","import { createToken, type InjectionToken } from '@forinda/kickjs'\n\nimport type { KickDbClient } from './client/types'\n\n// First-party tokens own the reserved `kick/` namespace. Adopter-defined\n// tokens (e.g. additional shards / read replicas beyond the default pair)\n// should use the adopter's own scope (e.g. `app/db/tenants`).\nexport const DB_PRIMARY: InjectionToken<KickDbClient> = createToken<KickDbClient>('kick/db/primary')\nexport const DB_REPLICA: InjectionToken<KickDbClient> = createToken<KickDbClient>('kick/db/replica')\n\n/**\n * Alias for the default DB. Adopters who only have one database can inject\n * `DB_CLIENT` instead of remembering whether it's primary/replica.\n */\nexport const DB_CLIENT = DB_PRIMARY\n","import { EventEmitter } from 'node:events'\nimport type { KickDbClientEvents } from './types'\n\ntype Listener<E extends keyof KickDbClientEvents> = (\n  e: KickDbClientEvents[E],\n) => void | Promise<void>\n\n/**\n * Per-client typed event emitter. Wraps a Node EventEmitter to keep the\n * surface narrow (no `addListener`, no `removeAllListeners`, no `setMaxListeners`).\n *\n * The Kysely query interceptor surface is intentionally minimal in M1:\n * transactionStart/Commit/Rollback fire from createDbClient's transaction()\n * wrapper. The full beforeQuery / query / queryError emit pipeline lands in\n * M2 alongside `$extends` since it requires a proper Kysely query plugin\n * with access to the compiled SQL string + parameters. The types are stable\n * now so adopter code can wire listeners; only the runtime emit is deferred.\n */\nexport class KickDbEventEmitter {\n  private readonly emitter = new EventEmitter()\n\n  on<E extends keyof KickDbClientEvents>(event: E, listener: Listener<E>): void {\n    this.emitter.on(event, listener as (...args: unknown[]) => void)\n  }\n\n  off<E extends keyof KickDbClientEvents>(event: E, listener: Listener<E>): void {\n    this.emitter.off(event, listener as (...args: unknown[]) => void)\n  }\n\n  emit<E extends keyof KickDbClientEvents>(event: E, payload: KickDbClientEvents[E]): void {\n    this.emitter.emit(event, payload)\n  }\n}\n","import type { ColumnSnapshot, FkAction } from '../../snapshot/types'\n\n/**\n * Runtime + type representation of a column reference (e.g. `users.id`).\n * Carries the parent table name, the column's own name, plus runtime\n * accessors used by FK thunks and constraint builders.\n *\n * Exported so adopters can annotate self-referencing thunks without\n * spelling the shape inline:\n *\n *   parentId: uuid().references((): ColumnRef => categories.id)\n *\n * Without the annotation the initializer of a self-referencing const\n * trips TS7022 — TS needs to infer the const while the initializer\n * already references it.\n */\nexport interface ColumnRef {\n  __tableName: string\n  __name: string\n  __builder: ColumnBuilder\n  __state: () => ReturnType<ColumnBuilder['__state']>\n}\n\n/**\n * Resolved FK spec — `table` / `column` are pulled by invoking `thunk()`\n * lazily. The thunk pattern lets self-referencing tables work:\n *\n *   const categories = table('categories', {\n *     id: uuid().primaryKey().defaultRandom(),\n *     parentId: uuid().references((): ColumnRef => categories.id),\n *   })\n *\n * If we resolved at `.references()` call time, `categories` would TDZ-fail\n * inside its own initializer. Storing the thunk and resolving on read\n * (extract / render / emit) defers until after the const binding lands.\n */\nexport interface FkSpec {\n  thunk: () => ColumnRef\n  onDelete: FkAction\n  onUpdate: FkAction\n}\n\nexport interface ColumnState {\n  type: string\n  nullable: boolean\n  default: string | null\n  primaryKey: boolean\n  unique: boolean\n  references: FkSpec | null\n}\n\n/**\n * Type-only brand attached to a column when it's auto-assigned by the\n * database (serial / bigserial / smallserial), has a runtime default\n * (`.default(...)`), or carries an expression default\n * (`uuid().defaultRandom()`, `timestamp().defaultNow()`). `SchemaToTypes<S>`\n * reads this marker and wraps the column type in Kysely's `Generated<T>` so\n * adopters can omit the column on insert.\n *\n * Runtime is a no-op — the symbol never reaches a value.\n */\nexport const KICK_GENERATED = Symbol.for('@forinda/kickjs-db/Generated')\nexport type GeneratedBrand = { readonly [KICK_GENERATED]?: true }\n\n/**\n * Type-only brand attached to a column when `.notNull()` or `.primaryKey()`\n * is called. `SchemaToTypes<S>` reads this brand to decide whether the\n * column type is `T` (NOT NULL) or `T | null` (default nullable).\n *\n * Why a brand instead of a class generic: chained methods (notNull,\n * primaryKey) can return `this & NotNullBrand` to narrow nullability while\n * preserving the subclass identity — so `uuid().primaryKey().defaultRandom()`\n * still resolves `defaultRandom()` on `UuidBuilder`. A class generic\n * `<TNullable>` would collapse the subclass back to the parent.\n */\nexport const KICK_NOT_NULL = Symbol.for('@forinda/kickjs-db/NotNull')\nexport type NotNullBrand = { readonly [KICK_NOT_NULL]?: true }\n\n/**\n * Re-attach the nullability / generated brands after a transform that\n * must return a *new* builder type (e.g. `.array()` widening `T` to\n * `T[]`). Without this, `integer().notNull().array()` silently dropped\n * `NotNullBrand` and the row type regressed to `number[] | null`.\n *\n * Uses the same `extends` checks as `SchemaToTypes` (client/schema-types.ts)\n * so detection stays consistent in both directions.\n */\nexport type PreserveBrands<Self, Out> = Out &\n  (Self extends NotNullBrand ? NotNullBrand : unknown) &\n  (Self extends GeneratedBrand ? GeneratedBrand : unknown)\n\n/**\n * Phantom-typed column builder. The `T` generic carries the column's TS\n * value type (number / string / Date / etc.); nullability is tracked via\n * the `NotNullBrand` intersection rather than a class generic so chain\n * methods preserve subclass identity.\n *\n * Both `T` and the brand are erased at runtime; they exist purely so\n * `SchemaToTypes<S>` can pull them out per column.\n */\nexport class ColumnBuilder<T = unknown> {\n  // Phantom param shows up in the public surface so the type system sees\n  // it. Reading it at runtime is intentionally not supported.\n  declare readonly __t?: T\n\n  protected state: ColumnState\n\n  constructor(type: string, defaults: Partial<ColumnState> = {}) {\n    this.state = {\n      type,\n      nullable: defaults.nullable ?? true,\n      default: defaults.default ?? null,\n      primaryKey: defaults.primaryKey ?? false,\n      unique: defaults.unique ?? false,\n      references: defaults.references ?? null,\n    }\n  }\n\n  notNull(): this & NotNullBrand {\n    this.state.nullable = false\n    return this as this & NotNullBrand\n  }\n\n  primaryKey(): this & NotNullBrand {\n    this.state.primaryKey = true\n    this.state.nullable = false\n    return this as this & NotNullBrand\n  }\n\n  unique(): this {\n    this.state.unique = true\n    return this\n  }\n\n  array(): PreserveBrands<this, ColumnBuilder<T[]>> {\n    this.state.type = `${this.state.type}[]`\n    return this as unknown as PreserveBrands<this, ColumnBuilder<T[]>>\n  }\n\n  references(\n    target: () => ColumnRef,\n    opts: { onDelete?: FkAction; onUpdate?: FkAction } = {},\n  ): this {\n    // Store the thunk — do NOT invoke it here. Self-referencing tables\n    // pass `() => self.id` whose binding does not exist yet.\n    this.state.references = {\n      thunk: target,\n      onDelete: opts.onDelete ?? 'no_action',\n      onUpdate: opts.onUpdate ?? 'no_action',\n    }\n    return this\n  }\n\n  /**\n   * Mark the column as having a runtime / DB-assigned default. The\n   * `GeneratedBrand` flows into `SchemaToTypes<S>` so the column wraps\n   * in `Generated<T>` — adopters can `INSERT` without specifying it.\n   *\n   * Accepts the natural literal for the column type — `boolean().default(false)`,\n   * `integer().default(0)`, `varchar().default('active')`. Non-string\n   * literals are normalised to their SQL-literal text so the snapshot\n   * (`ColumnSnapshot.default: string | null`) and migration emitter stay\n   * string-only. For a quoted string default the text is the value\n   * itself (`'active'`); booleans/numbers emit bare (`false`, `0`).\n   */\n  default(value: string | number | boolean): this & GeneratedBrand {\n    this.state.default = typeof value === 'string' ? value : String(value)\n    return this as this & GeneratedBrand\n  }\n\n  toJSON(name: string): ColumnSnapshot {\n    return {\n      name,\n      type: this.state.type,\n      nullable: this.state.nullable,\n      default: this.state.default,\n      primaryKey: this.state.primaryKey,\n    }\n  }\n\n  // Internal accessor for table()/diff to read full state including unique/references.\n  __state(): Readonly<ColumnState> {\n    return this.state\n  }\n}\n","// customType<T>() — adopter-defined column type with optional driver\n// codecs. Lets a project introduce a typed column that doesn't ship\n// in the built-in DSL (encrypted strings, custom JSON shapes, citext,\n// PostGIS geometry, etc.) without forking the package.\n//\n// Schema usage:\n//\n//   const encrypted = customType<EncryptedString>({\n//     dataType: () => 'text',\n//     toDriver: (s) => encrypt(s),\n//     fromDriver: (raw) => decrypt(String(raw)),\n//   })\n//\n//   export const secrets = table('secrets', {\n//     id: serial().primaryKey(),\n//     value: encrypted().notNull(),\n//   })\n//\n// `SchemaToTypes<typeof schema>` reads the phantom T from the\n// CustomColumnBuilder so `db.selectFrom('secrets').select('value')`\n// types `value: EncryptedString` (not `string`). Driver codecs flow\n// through the lifecycle plugin landing in M2.F-T19; until then they\n// are stored on the builder for the runtime hookup to pick up.\n\nimport { ColumnBuilder } from './dsl/columns/types'\n\nexport interface CustomTypeOptions<TJs, TDriver = unknown> {\n  /**\n   * SQL data type as it would appear in `CREATE TABLE` — `'text'`,\n   * `'jsonb'`, `'citext'`, `'geometry(Point, 4326)'`, etc. Returned\n   * via a thunk so adopters can compute the type from runtime config\n   * (e.g. dialect-specific overrides).\n   */\n  dataType: () => string\n  /** Optional encode hook applied at insert / update time. */\n  toDriver?: (value: TJs) => TDriver\n  /** Optional decode hook applied to selected rows. */\n  fromDriver?: (driver: TDriver) => TJs\n}\n\n/**\n * ColumnBuilder subclass produced by `customType()`. Carries the\n * driver codecs so the (future) hooks pipeline can wire them through\n * a Kysely plugin without each consumer re-declaring its mapping.\n *\n * The phantom `T` flows through `SchemaToTypes<S>` exactly like any\n * other ColumnBuilder<T>, so adopters get full row-shape inference\n * for free.\n */\nexport class CustomColumnBuilder<TJs> extends ColumnBuilder<TJs> {\n  /** Encode hook — run on values heading into the database. */\n  readonly toDriver?: (value: TJs) => unknown\n  /** Decode hook — run on row values coming out of the database. */\n  readonly fromDriver?: (driver: unknown) => TJs\n\n  constructor(opts: CustomTypeOptions<TJs>) {\n    super(opts.dataType())\n    this.toDriver = opts.toDriver as never\n    this.fromDriver = opts.fromDriver as never\n  }\n}\n\n/**\n * Build a reusable column factory for a custom type. The returned\n * function is what callers use inside `table('foo', { col: factory() })`\n * — same shape as the built-in `varchar()`, `text()`, etc.\n *\n * @example\n * ```ts\n * const ulid = customType<string>({\n *   dataType: () => 'char(26)',\n *   toDriver: (s) => s,\n *   fromDriver: (raw) => String(raw),\n * })\n *\n * const events = table('events', {\n *   id: ulid().primaryKey(),\n *   ts: timestamp().notNull().defaultNow(),\n * })\n * ```\n */\nexport function customType<TJs>(opts: CustomTypeOptions<TJs>): () => CustomColumnBuilder<TJs> {\n  return () => new CustomColumnBuilder<TJs>(opts)\n}\n","// Codec plugin — wires CustomColumnBuilder codecs into Kysely.\n//\n// Two transforms in one plugin:\n//\n// - `transformQuery` walks the AST for INSERT and UPDATE statements\n//   and applies `toDriver(value)` to every ValueNode whose surrounding\n//   ColumnNode matches a column in the encoder map. Pass-through for\n//   `insert ... select`, `defaultValues`, references, and other\n//   non-literal value expressions.\n//\n// - `transformResult` walks selected rows and applies `fromDriver` per\n//   matching column name. Null/undefined pass through so codecs don't\n//   need a nullable branch.\n//\n// Both maps are keyed by COLUMN NAME (not table.column). Two tables\n// declaring the same name share a codec — the row shape returned from\n// joins doesn't always carry table provenance, so any table-aware\n// scheme would degrade silently. Adopters using clashing column names\n// across tables with different codecs should declare distinct\n// `customType` instances or rename the column.\n\nimport type {\n  KyselyPlugin,\n  PluginTransformQueryArgs,\n  PluginTransformResultArgs,\n  QueryResult,\n  RootOperationNode,\n  UnknownRow,\n} from 'kysely'\nimport {\n  ColumnNode,\n  ColumnUpdateNode,\n  InsertQueryNode,\n  PrimitiveValueListNode,\n  UpdateQueryNode,\n  ValueListNode,\n  ValueNode,\n  ValuesNode,\n  type OperationNode,\n  type ValuesItemNode,\n} from 'kysely'\n\nimport { CustomColumnBuilder } from '../custom-type'\nimport type { ColumnBuilder } from '../dsl/columns/types'\nimport type { TableDecl } from '../dsl/table'\n\n/** Map of column name → encoder/decoder. Built once at createDbClient time. */\nexport type CodecMap = Map<string, (value: unknown) => unknown>\n\nexport class CodecPlugin implements KyselyPlugin {\n  constructor(\n    private encoders: CodecMap,\n    private decoders: CodecMap,\n  ) {}\n\n  transformQuery(args: PluginTransformQueryArgs): RootOperationNode {\n    if (this.encoders.size === 0) return args.node\n    const node = args.node\n    if (InsertQueryNode.is(node)) return this.transformInsert(node)\n    if (UpdateQueryNode.is(node)) return this.transformUpdate(node)\n    return node\n  }\n\n  async transformResult(args: PluginTransformResultArgs): Promise<QueryResult<UnknownRow>> {\n    if (this.decoders.size === 0) return args.result\n    const rows = args.result.rows.map((row) => this.decodeRow(row))\n    return { ...args.result, rows }\n  }\n\n  // ---------------------------- query side ----------------------------\n\n  private transformInsert(node: InsertQueryNode): InsertQueryNode {\n    const cols = node.columns\n    const values = node.values\n    if (!cols || !values) return node\n    // Build per-position encoder lookup once. Positions without a\n    // matching encoder stay null so the inner loop can early-skip\n    // without re-hashing on every row.\n    const positional = this.positionalEncoders(cols)\n    if (!positional) return node\n\n    if (ValuesNode.is(values)) {\n      const items = values.values.map((item) => this.encodeValuesItem(item, positional))\n      // Reference equality preserved when no item changed.\n      const changed = items.some((item, i) => item !== values.values[i])\n      if (!changed) return node\n      // ValuesItemNode is the public union ValueListNode | PrimitiveValueListNode;\n      // every encodeValuesItem path either returns the original item (already a\n      // ValuesItemNode) or rebuilds via the matching factory, so the cast holds.\n      return InsertQueryNode.cloneWith(node, {\n        values: ValuesNode.create(items as unknown as ReadonlyArray<ValuesItemNode>),\n      })\n    }\n\n    // SelectQueryNode (insert from select), DefaultInsertValueNode, and\n    // any future shape: pass through. We can't safely transform values\n    // we didn't read literally.\n    return node\n  }\n\n  private transformUpdate(node: UpdateQueryNode): UpdateQueryNode {\n    const updates = node.updates\n    if (!updates || updates.length === 0) return node\n\n    let changed = false\n    const next = updates.map((u) => {\n      const col = u.column\n      if (!ColumnNode.is(col)) return u\n      const encoder = this.encoders.get(col.column.name)\n      if (!encoder) return u\n      const encoded = this.encodeValueNode(u.value, encoder)\n      if (encoded === u.value) return u\n      changed = true\n      return ColumnUpdateNode.create(col, encoded)\n    })\n    if (!changed) return node\n    // Kysely's UpdateQueryNode.cloneWithUpdates APPENDS to existing\n    // updates rather than replacing them — wrong semantics for our\n    // mutate-in-place flow. Spread directly. `node` is already\n    // narrowed to UpdateQueryNode so the override typechecks cleanly.\n    return { ...node, updates: next }\n  }\n\n  private positionalEncoders(\n    cols: ReadonlyArray<ColumnNode>,\n  ): Array<((v: unknown) => unknown) | null> | null {\n    const out: Array<((v: unknown) => unknown) | null> = Array.from({ length: cols.length })\n    let any = false\n    for (let i = 0; i < cols.length; i++) {\n      const enc = this.encoders.get(cols[i].column.name) ?? null\n      out[i] = enc\n      if (enc) any = true\n    }\n    return any ? out : null\n  }\n\n  private encodeValuesItem(\n    item: OperationNode,\n    positional: Array<((v: unknown) => unknown) | null>,\n  ): OperationNode {\n    if (ValueListNode.is(item)) {\n      const next = item.values.map((v, i) => {\n        const enc = positional[i]\n        if (!enc) return v\n        return this.encodeValueNode(v, enc)\n      })\n      const changed = next.some((v, i) => v !== item.values[i])\n      return changed ? ValueListNode.create(next) : item\n    }\n    if (PrimitiveValueListNode.is(item)) {\n      const next = item.values.map((v, i) => {\n        const enc = positional[i]\n        if (!enc) return v\n        return this.encodePrimitive(v, enc)\n      })\n      const changed = next.some((v, i) => v !== item.values[i])\n      return changed ? PrimitiveValueListNode.create(next) : item\n    }\n    return item\n  }\n\n  private encodeValueNode(node: OperationNode, encoder: (v: unknown) => unknown): OperationNode {\n    if (!ValueNode.is(node)) return node\n    const value = node.value\n    if (value === null || value === undefined) return node\n    const encoded = encoder(value)\n    if (encoded === value) return node\n    return ValueNode.create(encoded)\n  }\n\n  private encodePrimitive(value: unknown, encoder: (v: unknown) => unknown): unknown {\n    if (value === null || value === undefined) return value\n    return encoder(value)\n  }\n\n  // ---------------------------- result side ----------------------------\n\n  private decodeRow(row: UnknownRow): UnknownRow {\n    let mutated = false\n    const out: Record<string, unknown> = {}\n    for (const key of Object.keys(row)) {\n      const value = (row as Record<string, unknown>)[key]\n      const decoder = this.decoders.get(key)\n      if (decoder && value !== null && value !== undefined) {\n        out[key] = decoder(value)\n        mutated = true\n      } else {\n        out[key] = value\n      }\n    }\n    return (mutated ? out : row) as UnknownRow\n  }\n}\n\n/**\n * Walk a schema record and collect decoders from every column whose\n * builder is a `CustomColumnBuilder` with a `fromDriver` codec set.\n */\nexport function buildDecoderMap(schema: unknown): CodecMap {\n  return collectCodecs(schema, 'fromDriver')\n}\n\n/**\n * Walk a schema record and collect encoders from every column whose\n * builder is a `CustomColumnBuilder` with a `toDriver` codec set.\n */\nexport function buildEncoderMap(schema: unknown): CodecMap {\n  return collectCodecs(schema, 'toDriver')\n}\n\nfunction collectCodecs(schema: unknown, key: 'toDriver' | 'fromDriver'): CodecMap {\n  const out: CodecMap = new Map()\n  if (!schema || typeof schema !== 'object') return out\n\n  // Track which table first claimed each column name so a collision can\n  // name both sides. Codecs are keyed by column name (see the file\n  // header for why a table-aware scheme can't work on the decode path);\n  // a same-named column with a DIFFERENT codec in another table would\n  // otherwise silently corrupt one of them. First-write-wins +\n  // a loud warning makes the clash debuggable instead of invisible.\n  const owner = new Map<string, string>()\n\n  for (const value of Object.values(schema as Record<string, unknown>)) {\n    if (!isTableDecl(value)) continue\n    const tableName = value.__name\n    for (const [colName, col] of Object.entries(value.__columns)) {\n      if (!(col instanceof CustomColumnBuilder)) continue\n      const fn = col[key] as ((v: unknown) => unknown) | undefined\n      if (!fn) continue\n\n      const existing = out.get(colName)\n      if (existing === undefined) {\n        out.set(colName, fn)\n        owner.set(colName, tableName)\n      } else if (existing !== fn) {\n        // Same codec instance shared across tables (existing === fn) is\n        // the common, safe case and stays quiet. Only a genuinely\n        // different codec function triggers the warning.\n        console.warn(\n          `[kickjs-db] customType codec conflict: column '${colName}' maps to different ` +\n            `${key} codecs in tables '${owner.get(colName)}' and '${tableName}'. Codecs are ` +\n            `keyed by column name, so the first ('${owner.get(colName)}') wins and the other ` +\n            `is ignored — rename the column or share a single customType instance.`,\n        )\n      }\n    }\n  }\n  return out\n}\n\nfunction isTableDecl(value: unknown): value is TableDecl<string, Record<string, ColumnBuilder>> {\n  return (\n    typeof value === 'object' &&\n    value !== null &&\n    (value as { __isTable?: boolean }).__isTable === true\n  )\n}\n","// ResultExtensionPlugin — Kysely plugin that powers `$extends({ result })`.\n//\n// Two halves:\n//\n//   1. transformQuery walks SelectQueryNode + identifies the table,\n//      then injects ColumnNode references for every `needs` column\n//      not already in the SELECT list. Selects already using `*`\n//      (SelectAllNode) skip injection — the column is implicitly\n//      there.\n//\n//   2. transformResult walks the rows after the driver returns them,\n//      runs each compute(row) per matching table, and assigns the\n//      result to row[<computedKey>]. Null/undefined rows pass through\n//      untouched.\n//\n// The two halves share state via a per-queryId Map so transformResult\n// only fires for queries this plugin marked in transformQuery — joins,\n// sub-selects, multi-table FROMs, and other shapes we can't reliably\n// attribute to a single table pass through both halves untouched.\n// Aliased single-table selects (`.from('posts as p')`) ARE supported —\n// the alias unwrap walks through to the underlying TableNode.\n\nimport {\n  ColumnNode,\n  ReferenceNode,\n  SelectAllNode,\n  SelectQueryNode,\n  SelectionNode,\n  TableNode,\n  type KyselyPlugin,\n  type OperationNode,\n  type PluginTransformQueryArgs,\n  type PluginTransformResultArgs,\n  type QueryId,\n  type QueryResult,\n  type RootOperationNode,\n  type UnknownRow,\n} from 'kysely'\n\nimport type { ResultExtension, ResultExtensions } from './types'\n\n/** Per-table computed-field bag. */\ntype TableExtensionBag = Record<string, ResultExtension<UnknownRow>>\n\nexport class ResultExtensionPlugin implements KyselyPlugin {\n  private byTable: Map<string, TableExtensionBag>\n  /**\n   * Map of queryId → table name the query targets. Populated in\n   * transformQuery, consumed in transformResult, deleted after use so\n   * it doesn't leak across long-lived clients.\n   */\n  private pending = new Map<QueryId, string>()\n\n  constructor(extensions: ResultExtensions<unknown>) {\n    this.byTable = new Map()\n    for (const [tableName, bag] of Object.entries(extensions)) {\n      if (!bag) continue\n      const entries = Object.entries(bag) as Array<[string, ResultExtension<UnknownRow>]>\n      if (entries.length === 0) continue\n      this.byTable.set(tableName, Object.fromEntries(entries))\n    }\n  }\n\n  transformQuery(args: PluginTransformQueryArgs): RootOperationNode {\n    const { node, queryId } = args\n    if (!SelectQueryNode.is(node)) return node\n    const tableName = singleTableTarget(node)\n    if (!tableName) return node\n    const bag = this.byTable.get(tableName)\n    if (!bag) return node\n\n    // Tag the query so transformResult knows to apply computeds.\n    this.pending.set(queryId, tableName)\n\n    return injectNeeds(node, bag)\n  }\n\n  async transformResult(args: PluginTransformResultArgs): Promise<QueryResult<UnknownRow>> {\n    const tableName = this.pending.get(args.queryId)\n    if (!tableName) return args.result\n    this.pending.delete(args.queryId)\n\n    const bag = this.byTable.get(tableName)\n    if (!bag) return args.result\n    const computeds = Object.entries(bag) as Array<[string, ResultExtension<UnknownRow>]>\n    if (computeds.length === 0) return args.result\n\n    const rows = args.result.rows.map((row) => {\n      if (row === null || row === undefined) return row\n      const base = row as Record<string, unknown>\n      const next: Record<string, unknown> = { ...base }\n      // Pass `base` (the pristine row, not `next`) into compute so\n      // computeds can't read each other's outputs by accident — order\n      // independence keeps the contract simple. Cross-computed\n      // dependencies are an explicit non-feature.\n      for (const [key, ext] of computeds) {\n        try {\n          next[key] = ext.compute(base as UnknownRow)\n        } catch {\n          // A throwing compute shouldn't poison the entire row set;\n          // surface as undefined so the caller still gets the\n          // pre-existing columns.\n          next[key] = undefined\n        }\n      }\n      return next as UnknownRow\n    })\n    return { ...args.result, rows }\n  }\n}\n\n/**\n * Detect the single table this select reads from. Returns the table\n * name when from has exactly one TableNode (or AliasNode wrapping\n * one); returns null for joins, sub-selects, multi-table selects,\n * and anything we can't reliably attribute. The plugin only acts on\n * single-table selects in v1.\n */\nfunction singleTableTarget(node: SelectQueryNode): string | null {\n  const from = node.from\n  if (!from || from.froms.length !== 1) return null\n  const target = unwrapAlias(from.froms[0])\n  if (!TableNode.is(target)) return null\n  return target.table.identifier.name\n}\n\nfunction unwrapAlias(node: OperationNode): OperationNode {\n  // AliasNode wraps a child node in `.node`; we only care about the\n  // underlying TableNode. Anything else passes through.\n  if (node.kind === 'AliasNode') {\n    const aliased = (node as unknown as { node: OperationNode }).node\n    return aliased\n  }\n  return node\n}\n\n/**\n * Inject every needs column not already represented in the select\n * list. SelectAllNode (the `*` wildcard) means \"all columns\", in\n * which case there's nothing to add. Specific column references are\n * deduped by name so a column already selected explicitly stays put\n * exactly once.\n */\nfunction injectNeeds(node: SelectQueryNode, bag: TableExtensionBag): SelectQueryNode {\n  const selections = node.selections ?? []\n  // Wildcard select — every column is implicitly present.\n  if (selections.some(isSelectAll)) return node\n\n  const have = new Set<string>()\n  for (const sel of selections) {\n    const inner = sel.selection\n    if (ReferenceNode.is(inner) && ColumnNode.is(inner.column)) {\n      have.add(inner.column.column.name)\n    } else if (ColumnNode.is(inner as OperationNode)) {\n      have.add((inner as ColumnNode).column.name)\n    }\n  }\n\n  const allNeeded = new Set<string>()\n  for (const ext of Object.values(bag)) {\n    for (const col of Object.keys(ext.needs)) {\n      allNeeded.add(col)\n    }\n  }\n\n  const missing = [...allNeeded].filter((c) => !have.has(c))\n  if (missing.length === 0) return node\n\n  const additions: SelectionNode[] = missing.map((col) =>\n    SelectionNode.create(ReferenceNode.create(ColumnNode.create(col))),\n  )\n  return SelectQueryNode.cloneWithSelections(node, additions)\n}\n\nfunction isSelectAll(node: SelectionNode): boolean {\n  const inner = node.selection\n  if (SelectAllNode.is(inner)) return true\n  if (ReferenceNode.is(inner) && SelectAllNode.is(inner.column)) return true\n  return false\n}\n","// Runtime for `$extends({ model, result })`.\n//\n// Two extension surfaces, applied in order:\n//\n//   1. **result extensions** rebuild the client around a Kysely\n//      instance with the ResultExtensionPlugin appended. We can't\n//      mutate plugins on a live Kysely (it freezes the plugin chain\n//      at construction), but `qb.withPlugin(plugin)` returns a fresh\n//      Kysely with the plugin added — that's what we wrap. The new\n//      client shares the same InternalContext as the parent (events\n//      emitter identity stays stable across extensions, transactions\n//      keep working), but routes queries through the plugin.\n//\n//   2. **model extensions** layer a Proxy over whatever client the\n//      previous step produced. The Proxy's `get` returns the per-\n//      table method bag for keys that match a model entry; methods\n//      are pre-bound via Function.prototype.call so `this` inside\n//      the method is the extended proxy. That way chaining\n//      `this.<otherTable>.<method>` or `this.transaction(...)`\n//      resolves naturally regardless of which extension order ran.\n//\n// Lazy proxy reference: the bound methods need to capture `proxy`\n// itself, but the proxy can't exist until its handler is built.\n// Closure over a mutable `proxy` reference solves the cycle — by the\n// time any method actually runs, the binding has landed.\n\nimport type { KickDbClient } from '../client/types'\nimport type { ExtendedClient, ExtensionDefinition, ResultExtensions } from './types'\nimport { ResultExtensionPlugin } from './result-plugin'\nimport { wrap, type InternalContext } from '../client/wrap'\n\nexport function applyExtensions<DB, E extends ExtensionDefinition<DB>>(\n  client: KickDbClient<DB>,\n  ctx: InternalContext,\n  ext: E,\n): ExtendedClient<DB, E> {\n  // 1. Result extensions — rebuild Kysely around the plugin chain.\n  //    `wrap` and this module form an ESM cycle (wrap calls\n  //    applyExtensions for the client's `$extends`; we call wrap to\n  //    rebuild the client). ESM live bindings handle this fine as\n  //    long as nothing reads the binding at module top-level — both\n  //    sides only call into each other inside functions.\n  let baseClient: KickDbClient<DB> = client\n  if (hasResultExtensions(ext.result)) {\n    const plugin = new ResultExtensionPlugin(ext.result as ResultExtensions<unknown>)\n    const newQb = client.qb.withPlugin(plugin)\n    baseClient = wrap<DB>(newQb, ctx)\n  }\n\n  // 2. Model proxy — layered on top of whichever base client we got\n  //    so model methods see the result-augmented row types via `this`.\n  let proxy: ExtendedClient<DB, E>\n\n  const modelBag: Record<string, Record<string, (...args: unknown[]) => unknown>> = {}\n  const model = ext.model ?? {}\n  for (const tableName of Object.keys(model) as (keyof typeof model)[]) {\n    const methods = model[tableName]\n    if (!methods) continue\n    const bound: Record<string, (...args: unknown[]) => unknown> = {}\n    for (const [methodName, fn] of Object.entries(methods)) {\n      bound[methodName] = (...args) => (fn as (...a: unknown[]) => unknown).call(proxy, ...args)\n    }\n    modelBag[tableName as string] = bound\n  }\n\n  proxy = new Proxy(baseClient, {\n    get(target, prop) {\n      // Own-property check — `prop in modelBag` would also match\n      // inherited keys like `toString` / `hasOwnProperty` from\n      // Object.prototype, intercepting properties we never asked to\n      // own and breaking the underlying client's own equivalents.\n      if (typeof prop === 'string' && Object.prototype.hasOwnProperty.call(modelBag, prop)) {\n        return modelBag[prop]\n      }\n      // Fall through. Bound methods on the underlying KickDbClient\n      // (selectFrom, transaction, etc.) keep their original `this`\n      // since `wrap()` already bound them to kysely at create time.\n      const value = (target as unknown as Record<PropertyKey, unknown>)[prop as PropertyKey]\n      return value\n    },\n  }) as ExtendedClient<DB, E>\n\n  return proxy\n}\n\nfunction hasResultExtensions(result: unknown): boolean {\n  if (!result || typeof result !== 'object') return false\n  for (const bag of Object.values(result as Record<string, unknown>)) {\n    if (bag && typeof bag === 'object' && Object.keys(bag as object).length > 0) return true\n  }\n  return false\n}\n","/**\n * Runtime wire-up for `db.query.X.findMany({ with })`.\n *\n * `attachQueryNamespace` wraps a `KickDbClient` with a `query`\n * Proxy that materializes a `TableQueryNamespace` on first\n * property access. Each method (`findMany` / `findFirst` /\n * `findUnique`) builds a `CompiledQuery` via the dialect-specific\n * compiler, hands it to the underlying Kysely instance to execute,\n * and returns the rows.\n *\n * The compile + execute split keeps the compiler pure and testable\n * (snapshot SQL fixtures in `query-compile.test.ts`) while the\n * builder owns the I/O.\n *\n * Spec: docs/db/spec-relational-query.md §5.2.\n */\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport type { CompiledQuery, Kysely } from 'kysely'\nimport type { ResolvedRelations } from './relations'\nimport type { CompileMode, CompilePgOptions } from './compile-pg'\nimport type { FindManyOptions, QueryNamespace, TableQueryNamespace } from './types'\nimport type { TableSnapshot } from '../snapshot/types'\nimport { RelationalQueryCancelledError } from './errors'\n\n/**\n * Dialect-specific compile function. PG ships `compilePg`;\n * SQLite ships `compileSqlite`; MySQL provides a stub that throws\n * `RelationalQueryNotSupportedError`. The signature matches\n * `compilePg` so swapping compilers is a one-line change.\n *\n * `tables` is the snapshot's table-by-name map; the compiler reads\n * each target's column list to emit explicit selections inside\n * `jsonArrayFrom` / `jsonObjectFrom` (SQLite requires it; PG\n * accepts either form).\n */\nexport type CompileFn = (\n  qb: Kysely<any>,\n  table: string,\n  options: CompilePgOptions,\n  relations: ResolvedRelations,\n  tables: Record<string, TableSnapshot>,\n  mode: CompileMode,\n) => CompiledQuery\n\n/**\n * Build the per-table query namespace. The Proxy intercepts every\n * property access — adopters writing `db.query.users` get a fresh\n * namespace bound to that table name. The methods close over the\n * shared compiler + relations + tables + Kysely instance so each\n * call is independent.\n */\nexport function buildQueryNamespace<DB>(\n  qb: Kysely<DB>,\n  relations: ResolvedRelations,\n  tables: Record<string, TableSnapshot>,\n  compile: CompileFn,\n): QueryNamespace<DB> {\n  return new Proxy({} as QueryNamespace<DB>, {\n    get(_target, prop) {\n      if (typeof prop !== 'string') return undefined\n      return makeTableNamespace(qb, prop as never, relations, tables, compile)\n    },\n  })\n}\n\nfunction makeTableNamespace<DB, Table extends keyof DB & string>(\n  qb: Kysely<DB>,\n  table: Table,\n  relations: ResolvedRelations,\n  tables: Record<string, TableSnapshot>,\n  compile: CompileFn,\n): TableQueryNamespace<DB, Table> {\n  return {\n    async findMany(options?: unknown) {\n      const opts = (options ?? {}) as FindManyOptions\n      assertNotAlreadyAborted(opts.signal)\n      const compiled = compile(\n        qb as Kysely<any>,\n        table,\n        opts as CompilePgOptions,\n        relations,\n        tables,\n        'many',\n      )\n      const rows = await execute(qb, compiled, opts.signal)\n      return rows as never\n    },\n\n    async findFirst(options?: unknown) {\n      const opts = (options ?? {}) as FindManyOptions\n      assertNotAlreadyAborted(opts.signal)\n      const compiled = compile(\n        qb as Kysely<any>,\n        table,\n        opts as CompilePgOptions,\n        relations,\n        tables,\n        'first',\n      )\n      const rows = await execute(qb, compiled, opts.signal)\n      return (rows[0] ?? null) as never\n    },\n\n    async findUnique(options: unknown) {\n      const opts = options as FindManyOptions\n      assertNotAlreadyAborted(opts?.signal)\n      const compiled = compile(\n        qb as Kysely<any>,\n        table,\n        opts as CompilePgOptions,\n        relations,\n        tables,\n        'unique',\n      )\n      const rows = await execute(qb, compiled, opts?.signal)\n      return (rows[0] ?? null) as never\n    },\n  } as unknown as TableQueryNamespace<DB, Table>\n}\n\n/**\n * Short-circuit before compile when the caller passes an already-\n * aborted signal — no SQL generated, no DB round trip.\n */\nfunction assertNotAlreadyAborted(signal: AbortSignal | undefined): void {\n  if (signal?.aborted) {\n    throw new RelationalQueryCancelledError(signal.reason)\n  }\n}\n\n/**\n * Execute a `CompiledQuery` through Kysely's executor. Goes through\n * the same path Kysely's `.execute()` would — events, plugins, and\n * connection pooling all keep working without bypassing the wrapper.\n *\n * When `signal` is supplied, threads it into Kysely 0.29's\n * `executeQuery(q, { signal })` second arg. Kysely + the dialect\n * driver handle the actual cancellation (PG `pg_cancel_backend`,\n * SQLite synchronous abort, MySQL `KILL QUERY`). On abort, Kysely\n * rejects with an AbortError-shaped error which we map to the\n * adopter-facing `RelationalQueryCancelledError`.\n */\nasync function execute<DB>(\n  qb: Kysely<DB>,\n  compiled: CompiledQuery,\n  signal?: AbortSignal,\n): Promise<unknown[]> {\n  try {\n    // Kysely 0.29's default `inflightQueryAbortStrategy` is\n    // `'ignore query'` — it stops waiting for results on abort but\n    // lets the in-flight query finish on the DB side. The stricter\n    // `'cancel query'` strategy throws on dialects without\n    // `cancelQuery` support (better-sqlite3 has no such hook), so we\n    // can't safely default it across all dialects.\n    //\n    // Adopters who need `pg_cancel_backend` / `KILL QUERY` semantics\n    // for long-running PG/MySQL queries can wrap a Kysely call site\n    // directly (`db.qb.selectFrom(...).$call(qb => qb.executeQuery(c, { signal, inflightQueryAbortStrategy: 'cancel query' }))`)\n    // until a future release exposes a per-call override on\n    // FindManyOptions. The signal STILL fires correctly here — the\n    // promise rejects with RelationalQueryCancelledError as soon as\n    // the abort fires; only the DB-side resource cleanup is\n    // best-effort under the default strategy.\n    const result = await (\n      qb as unknown as {\n        executeQuery: (\n          q: CompiledQuery,\n          opts?: { signal?: AbortSignal },\n        ) => Promise<{ rows: unknown[] }>\n      }\n    ).executeQuery(compiled, signal ? { signal } : undefined)\n    return result.rows\n  } catch (err) {\n    // Two paths to a cancellation diagnosis:\n    //   1. The supplied signal is now aborted — Kysely 0.29 may\n    //      throw the abort `reason` verbatim (string, custom value,\n    //      or a DOMException), so we can't rely on the err shape.\n    //      The signal state is the authoritative signal here.\n    //   2. The driver/Kysely path returned an AbortError-shaped\n    //      rejection without a kickjs-supplied signal (e.g. the\n    //      caller wrapped their own AbortController upstream and\n    //      didn't pass it to us — defensive fallback).\n    if (signal?.aborted) {\n      throw new RelationalQueryCancelledError(signal.reason ?? err)\n    }\n    if (isAbortError(err)) {\n      throw new RelationalQueryCancelledError(err)\n    }\n    throw err\n  }\n}\n\n/**\n * Recognise the AbortError shapes the supported dialect drivers\n * throw on cancellation. Kysely 0.29 normalises the spec DOMException\n * shape; the underlying drivers (pg, mysql2, better-sqlite3) carry\n * dialect-specific markers that we keep checking for in case Kysely's\n * normalisation drifts.\n *\n * - DOM standard / Kysely:   err.name === 'AbortError'\n * - node-postgres:           err.code === '57014' (query_canceled SQLSTATE)\n * - mysql2:                  err.code === 'EAGAIN_QUERY_INTERRUPTED'\n * - better-sqlite3:          err.code === 'SQLITE_INTERRUPT'\n */\nfunction isAbortError(err: unknown): boolean {\n  if (!(err instanceof Error)) return false\n  if (err.name === 'AbortError') return true\n  const code = (err as { code?: unknown }).code\n  if (typeof code !== 'string') return false\n  return code === '57014' || code === 'EAGAIN_QUERY_INTERRUPTED' || code === 'SQLITE_INTERRUPT'\n}\n\n/**\n * Type alias used by the client wrap to declare the optional `query`\n * field without importing every helper individually.\n */\nexport type AttachedQuery<DB> = QueryNamespace<DB>\n\n/**\n * Per-options passthrough type — re-exported for contributors who\n * want to wrap the namespace (testing helpers, query loggers). Most\n * adopters never reach for this.\n */\nexport type AttachedFindManyOptions<DB, Table extends keyof DB & string> = FindManyOptions<\n  DB,\n  Table\n>\n","// Wraps a Kysely<DB> + InternalContext into a KickDbClient<DB>.\n//\n// Lives in its own module so consumers that need to rebuild the\n// client around a new Kysely instance — `$extends({ result })` adds a\n// result-extension Kysely plugin via `qb.withPlugin(...)`, then wraps\n// the new instance back into a client — can do so without an import\n// cycle through `client/create.ts`. Both `create.ts` and\n// `extend/apply.ts` import from here.\n//\n// `InternalContext` carries everything the wrap needs that lives\n// outside the Kysely instance itself: the lifecycle event emitter,\n// the cached dialect tag, and the savepoint counter. Sharing the same\n// ctx across re-wraps keeps the event listener identity stable —\n// adopters who attached `db.on('slowQuery', ...)` continue receiving\n// events from the rebuilt-after-`$extends` client.\n\nimport { Kysely, sql } from 'kysely'\n\nimport type { KickDbClient, TransactionEvent } from './types'\nimport { applyExtensions } from '../extend/apply'\nimport type { KickDbEventEmitter } from './events'\nimport type { CompileFn } from '../query/builder'\nimport { buildQueryNamespace } from '../query/builder'\nimport type { ResolvedRelations } from '../query/relations'\nimport type { TableSnapshot } from '../snapshot/types'\n\nexport interface InternalContext {\n  events: KickDbEventEmitter | null\n  dialect: KickDbClient['dialect']\n  /** Increments per savepoint open inside this client; used for SP_<n> names. */\n  savepointCounter: { value: number }\n  /**\n   * Resolved relation graph + per-table column metadata + dialect-\n   * specific compiler for the relational-query namespace. Always\n   * present after `createDbClient` runs — the compiler may be a\n   * throw-stub for unsupported dialects (MySQL until M4.A.3).\n   */\n  query: {\n    relations: ResolvedRelations\n    tables: Record<string, TableSnapshot>\n    compile: CompileFn\n  }\n}\n\nexport function wrap<DB>(qb: Kysely<DB>, ctx: InternalContext): KickDbClient<DB> {\n  const client: KickDbClient<DB> = {\n    qb,\n    dialect: ctx.dialect,\n    query: buildQueryNamespace<DB>(qb, ctx.query.relations, ctx.query.tables, ctx.query.compile),\n\n    selectFrom: qb.selectFrom.bind(qb),\n    insertInto: qb.insertInto.bind(qb),\n    updateTable: qb.updateTable.bind(qb),\n    deleteFrom: qb.deleteFrom.bind(qb),\n\n    on(event, listener) {\n      ctx.events?.on(event, listener)\n      return client\n    },\n    off(event, listener) {\n      ctx.events?.off(event, listener)\n      return client\n    },\n\n    transaction: ((\n      a: TransactionEvent | ((tx: KickDbClient<DB>) => Promise<unknown>),\n      b?: (tx: KickDbClient<DB>) => Promise<unknown>,\n    ) => {\n      const txOpts = typeof a === 'function' ? {} : a\n      const fn = (typeof a === 'function' ? a : b) as (tx: KickDbClient<DB>) => Promise<unknown>\n\n      const run = async () => {\n        ctx.events?.emit('transactionStart', { isolation: txOpts.isolation })\n        try {\n          const result = await qb.transaction().execute(async (tx) => {\n            if (txOpts.isolation) {\n              const level = txOpts.isolation.toUpperCase()\n              await sql.raw(`SET TRANSACTION ISOLATION LEVEL ${level}`).execute(tx)\n            }\n            const child = wrap<DB>(tx as unknown as Kysely<DB>, ctx)\n            return await fn(child)\n          })\n          ctx.events?.emit('transactionCommit', { isolation: txOpts.isolation })\n          return result\n        } catch (err) {\n          ctx.events?.emit('transactionRollback', {\n            isolation: txOpts.isolation,\n            error: err,\n          })\n          throw err\n        }\n      }\n      return run()\n    }) as KickDbClient<DB>['transaction'],\n\n    $extends(ext) {\n      return applyExtensions(client, ctx, ext)\n    },\n\n    async savepoint(fn) {\n      const name = `sp_${++ctx.savepointCounter.value}`\n      // Savepoints only make sense inside a transaction. The query\n      // builder's transaction proxies route SQL through the same\n      // connection; sql.raw() against the wrapper lands on that\n      // connection's tx context.\n      await sql.raw(`SAVEPOINT ${name}`).execute(qb)\n      try {\n        const result = await fn(wrap<DB>(qb, ctx))\n        await sql.raw(`RELEASE SAVEPOINT ${name}`).execute(qb)\n        return result\n      } catch (err) {\n        await sql.raw(`ROLLBACK TO SAVEPOINT ${name}`).execute(qb)\n        throw err\n      }\n    },\n\n    async destroy() {\n      await qb.destroy()\n    },\n  }\n  return client\n}\n","/**\n * Explicit dialect tagging for `createDbClient`'s dialect detection.\n *\n * The historical `detectDialect` inspected Kysely ctor names\n * (`/Postgres/i.test(...)`) with a silent fallback to `'sqlite'` — so a\n * hand-rolled or future Kysely dialect whose ctor name didn't match\n * `Postgres`/`Mysql` was silently treated as SQLite, emitting the wrong\n * JSON aggregation primitives at compile time.\n *\n * KickJS's own dialect factories (`pgDialect` / `mysqlDialect` /\n * `sqliteDialect`) now stamp this marker, so detection is exact for the\n * supported path. The ctor-name heuristic remains as the fallback for\n * raw Kysely dialects an adopter constructs directly.\n *\n * `Symbol.for` so the marker is shared across module-identity boundaries\n * (multiple copies of `@forinda/kickjs-db`).\n */\n// Typed as plain `symbol` (no annotation, no cast). `Symbol.for` can't\n// produce a `unique symbol` — TS requires that type to come from a\n// direct `Symbol()`/`Symbol.for()` const initializer with no\n// intervening cast, so any `: unique symbol` annotation here forces an\n// unsafe cast (`as never` / `as unknown as unique symbol`). We only use\n// this value as a computed property key, where `symbol` is sufficient.\nexport const KICK_DIALECT = Symbol.for('@forinda/kickjs-db/dialect')\n\nexport type DialectTag = 'postgres' | 'mysql' | 'sqlite'\n\nconst DIALECT_TAGS: ReadonlySet<string> = new Set<DialectTag>(['postgres', 'mysql', 'sqlite'])\n\n/** Type guard — `true` when `value` is a supported dialect tag. */\nexport function isDialectTag(value: unknown): value is DialectTag {\n  return typeof value === 'string' && DIALECT_TAGS.has(value)\n}\n\n/** Stamp a Kysely dialect object with its KickJS dialect tag (non-enumerable). */\nexport function markDialect<T extends object>(dialect: T, tag: DialectTag): T {\n  Object.defineProperty(dialect, KICK_DIALECT, {\n    value: tag,\n    enumerable: false,\n    configurable: true,\n    writable: false,\n  })\n  return dialect\n}\n\n/**\n * Read the KickJS dialect tag off a dialect, or `undefined` when\n * unmarked. A garbage value (the marker is a global `Symbol.for`, so a\n * rogue stamp is possible) is rejected — `undefined` falls the caller\n * back to ctor-name detection rather than an impossible dialect state.\n */\nexport function readDialectMark(dialect: object): DialectTag | undefined {\n  const raw = (dialect as Record<symbol, unknown>)[KICK_DIALECT]\n  return isDialectTag(raw) ? raw : undefined\n}\n","/**\n * Dialect-agnostic compile traversal for `db.query.X.findMany({ with })`.\n *\n * The compile algorithm is identical across PostgreSQL, SQLite, and\n * MySQL — only the JSON-aggregation primitives differ. Each dialect-\n * specific entry point (`compilePg`, `compileSqlite`, `compileMysql`)\n * passes its own `jsonArrayFrom` / `jsonObjectFrom` from the matching\n * `kysely/helpers/<dialect>` module into `runCompile`, which then\n * walks the `with` clause using shared helpers.\n *\n * Spec: docs/db/spec-relational-query-other-dialects.md §4.\n */\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport { type Kysely, type ExpressionBuilder, type Expression, type CompiledQuery } from 'kysely'\nimport { RelationalQueryDepthError, RelationalQueryUnknownRelationError } from './errors'\nimport type { ResolvedRelation, ResolvedRelations } from './relations'\nimport type { TableSnapshot } from '../snapshot/types'\n\nexport type CompileMode = 'many' | 'first' | 'unique'\n\nexport interface CompileOptions {\n  where?: (table: any, ops: ExpressionBuilder<any, any>) => Expression<unknown>\n  orderBy?: (\n    table: any,\n    ops: ExpressionBuilder<any, any>,\n  ) => Expression<unknown> | Array<Expression<unknown>>\n  limit?: number\n  offset?: number\n  maxDepth?: number\n  with?: Record<string, true | CompileOptions>\n}\n\nconst DEFAULT_MAX_DEPTH = 5\n\n/**\n * Helper bag passed in from each dialect entry point. Same shape as\n * Kysely's per-dialect helpers — the only thing that varies between\n * `kysely/helpers/postgres`, `kysely/helpers/sqlite`, and\n * `kysely/helpers/mysql`.\n */\nexport interface JsonHelpers {\n  jsonArrayFrom: (expr: Expression<unknown>) => Expression<unknown>\n  jsonObjectFrom: (expr: Expression<unknown>) => Expression<unknown>\n}\n\n/**\n * Build a Proxy that maps property reads to Kysely column refs.\n * Adopters can write `(u, eb) => eb('id', '=', u.id)` and the runtime\n * resolves `u.id` to `eb.ref('users_0.id')`. Most call sites use the\n * underscored form (`(_u, eb) => eb('id', '=', x)`) and this Proxy\n * silently no-ops.\n */\nfunction makeTableRefProxy(eb: ExpressionBuilder<any, any>, alias: string): unknown {\n  return new Proxy({} as Record<string, unknown>, {\n    get(_target, prop) {\n      if (typeof prop !== 'string') return undefined\n      return eb.ref(`${alias}.${prop}`)\n    },\n  })\n}\n\n/**\n * Build a stable alias from a table name + depth index. The depth\n * suffix disambiguates self-referencing or cyclic relations. Outer\n * is `${name}_0`; nested levels increment.\n */\nfunction makeAlias(name: string, depth: number): string {\n  return `${name}_${depth}`\n}\n\n/**\n * Top-level entry — dialect-specific compilers (`compilePg`,\n * `compileSqlite`, `compileMysql`) call this with the right Kysely\n * helper bag. Returns the compiled `{ sql, parameters }`.\n *\n * `tables` carries each target table's column list so inner\n * `jsonArrayFrom` / `jsonObjectFrom` subqueries can emit explicit\n * `.select([col1, col2, ...])` calls. SQLite's helper requires\n * this (the runtime can't infer the JSON object keys from\n * `.selectAll()`); PG's helper accepts either form.\n */\nexport function runCompile<DB>(\n  db: Kysely<DB>,\n  table: string,\n  options: CompileOptions,\n  relations: ResolvedRelations,\n  tables: Record<string, TableSnapshot>,\n  mode: CompileMode,\n  helpers: JsonHelpers,\n): CompiledQuery {\n  const maxDepth = options.maxDepth ?? DEFAULT_MAX_DEPTH\n\n  const outerAlias = makeAlias(table, 0)\n  // Outer `.selectAll()` is fine — the helpers only restrict inner\n  // subqueries passed to jsonArrayFrom / jsonObjectFrom.\n  let query: any = (db.selectFrom(`${table} as ${outerAlias}` as any) as any).selectAll()\n\n  if (options.with) {\n    query = applyWithSelects(\n      query,\n      table,\n      outerAlias,\n      options.with,\n      relations,\n      tables,\n      maxDepth,\n      [outerAlias],\n      helpers,\n    )\n  }\n\n  query = applyWhereOrderLimit(query, outerAlias, options, mode)\n\n  return query.compile() as CompiledQuery\n}\n\nfunction applyWithSelects(\n  query: any,\n  source: string,\n  sourceAlias: string,\n  withClause: Record<string, true | CompileOptions>,\n  relations: ResolvedRelations,\n  tables: Record<string, TableSnapshot>,\n  maxDepth: number,\n  trace: readonly string[],\n  helpers: JsonHelpers,\n): any {\n  if (trace.length > maxDepth) {\n    throw new RelationalQueryDepthError(maxDepth, trace)\n  }\n\n  return query.select((eb: ExpressionBuilder<any, any>) => {\n    const out: unknown[] = []\n    for (const [key, value] of Object.entries(withClause)) {\n      const rel = relations[source]?.[key]\n      if (!rel) {\n        throw new RelationalQueryUnknownRelationError(source, key)\n      }\n\n      const subOptions: CompileOptions = value === true ? {} : value\n      const innerAlias = makeAlias(rel.target, trace.length)\n      const inner = buildInnerSelect(\n        eb,\n        sourceAlias,\n        rel,\n        innerAlias,\n        subOptions,\n        relations,\n        tables,\n        maxDepth,\n        trace,\n        helpers,\n      )\n\n      if (rel.kind === 'many') {\n        out.push((helpers.jsonArrayFrom(inner as Expression<unknown>) as any).as(key))\n      } else {\n        out.push((helpers.jsonObjectFrom(inner as Expression<unknown>) as any).as(key))\n      }\n    }\n    return out\n  })\n}\n\nfunction buildInnerSelect(\n  eb: ExpressionBuilder<any, any>,\n  sourceAlias: string,\n  rel: ResolvedRelation,\n  innerAlias: string,\n  subOptions: CompileOptions,\n  relations: ResolvedRelations,\n  tables: Record<string, TableSnapshot>,\n  maxDepth: number,\n  trace: readonly string[],\n  helpers: JsonHelpers,\n): any {\n  // Explicit column list rather than `.selectAll()` — SQLite's\n  // jsonArrayFrom / jsonObjectFrom helpers require it. PG's\n  // helpers accept either form, so emitting columns explicitly\n  // keeps a single dialect-agnostic code path here.\n  const targetTable = tables[rel.target]\n  const columns = targetTable\n    ? Object.keys(targetTable.columns).map((c) => `${innerAlias}.${c}`)\n    : null\n\n  let sub: any = eb.selectFrom(`${rel.target} as ${innerAlias}` as any) as any\n  if (columns && columns.length > 0) {\n    sub = sub.select(columns)\n  } else {\n    // Fallback only when the table isn't in the snapshot (e.g.\n    // tests passing a hand-rolled relations map without a\n    // matching tables entry). PG accepts selectAll(); SQLite\n    // would throw with a clear Kysely error.\n    sub = sub.selectAll()\n  }\n\n  for (let i = 0; i < rel.sourceColumns.length; i++) {\n    sub = sub.whereRef(\n      `${innerAlias}.${rel.targetColumns[i]}`,\n      '=',\n      `${sourceAlias}.${rel.sourceColumns[i]}`,\n    )\n  }\n\n  const nextTrace = [...trace, innerAlias]\n\n  if (subOptions.with) {\n    sub = applyWithSelects(\n      sub,\n      rel.target,\n      innerAlias,\n      subOptions.with,\n      relations,\n      tables,\n      maxDepth,\n      nextTrace,\n      helpers,\n    )\n  }\n\n  sub = applyWhereOrderLimit(sub, innerAlias, subOptions, 'many')\n\n  if (rel.kind === 'one') {\n    sub = sub.limit(1)\n  }\n\n  return sub\n}\n\nfunction applyWhereOrderLimit(\n  query: any,\n  alias: string,\n  options: CompileOptions,\n  mode: CompileMode,\n): any {\n  let q = query\n\n  if (options.where) {\n    q = q.where((eb: ExpressionBuilder<any, any>) =>\n      options.where!(makeTableRefProxy(eb, alias), eb),\n    )\n  }\n\n  if (options.orderBy) {\n    q = q.orderBy((eb: ExpressionBuilder<any, any>) =>\n      options.orderBy!(makeTableRefProxy(eb, alias), eb),\n    )\n  }\n\n  if (typeof options.limit === 'number') {\n    q = q.limit(options.limit)\n  } else if (mode === 'first' || mode === 'unique') {\n    q = q.limit(1)\n  }\n\n  if (typeof options.offset === 'number') {\n    q = q.offset(options.offset)\n  }\n\n  return q\n}\n","/**\n * PostgreSQL compiler for `db.query.X.findMany({ with })`.\n *\n * Strategy locked in `docs/db/spec-relational-query.md` §4.1:\n *\n *  - Each `many` relation becomes a Kysely `jsonArrayFrom(...)`\n *    select expression (PG: `coalesce((select json_agg(agg) from\n *    (...) as agg), '[]')`). Empty inner result aggregates to `[]`,\n *    not `null`.\n *  - Each `one` relation becomes `jsonObjectFrom(...)` (PG:\n *    `(select to_json(obj) from (...) as obj)`). Empty inner result\n *    is `null`.\n *\n * After M4.A.2, the traversal logic lives in `compile-shared.ts`\n * and is shared with the SQLite + MySQL compilers. This file is a\n * thin wrapper that hands `kysely/helpers/postgres`'s helpers to\n * the shared runner.\n */\n\nimport { type Kysely, type CompiledQuery } from 'kysely'\nimport { jsonArrayFrom, jsonObjectFrom } from 'kysely/helpers/postgres'\nimport {\n  runCompile,\n  type CompileMode,\n  type CompileOptions,\n  type JsonHelpers,\n} from './compile-shared'\nimport type { ResolvedRelations } from './relations'\nimport type { TableSnapshot } from '../snapshot/types'\n\nexport type { CompileMode, CompileOptions as CompilePgOptions }\n\nconst PG_HELPERS: JsonHelpers = {\n  jsonArrayFrom: jsonArrayFrom as unknown as JsonHelpers['jsonArrayFrom'],\n  jsonObjectFrom: jsonObjectFrom as unknown as JsonHelpers['jsonObjectFrom'],\n}\n\nexport function compilePg<DB>(\n  db: Kysely<DB>,\n  table: string,\n  options: CompileOptions,\n  relations: ResolvedRelations,\n  tables: Record<string, TableSnapshot>,\n  mode: CompileMode = 'many',\n): CompiledQuery {\n  return runCompile(db, table, options, relations, tables, mode, PG_HELPERS)\n}\n","/**\n * SQLite compiler for `db.query.X.findMany({ with })`.\n *\n * Strategy locked in `docs/db/spec-relational-query-other-dialects.md`\n * §3.1: each `many` relation becomes a Kysely `jsonArrayFrom(...)`\n * select expression that compiles to\n * `coalesce(json_group_array(json_object(...)), '[]')`. Each `one`\n * becomes `jsonObjectFrom(...)`, compiling to a `json_object(...)`\n * call with `LIMIT 1`. The traversal logic is shared with the PG +\n * MySQL compilers via `runCompile`.\n *\n * Result-decoding: SQLite drivers return JSON columns as TEXT;\n * `createDbClient` auto-attaches `ParseJSONResultsPlugin` for the\n * SQLite dialect so the nested JSON round-trips back to JS objects\n * before the codec / row-handler chain runs.\n */\n\nimport { type Kysely, type CompiledQuery } from 'kysely'\nimport { jsonArrayFrom, jsonObjectFrom } from 'kysely/helpers/sqlite'\nimport {\n  runCompile,\n  type CompileMode,\n  type CompileOptions,\n  type JsonHelpers,\n} from './compile-shared'\nimport type { ResolvedRelations } from './relations'\nimport type { TableSnapshot } from '../snapshot/types'\n\nconst SQLITE_HELPERS: JsonHelpers = {\n  jsonArrayFrom: jsonArrayFrom as unknown as JsonHelpers['jsonArrayFrom'],\n  jsonObjectFrom: jsonObjectFrom as unknown as JsonHelpers['jsonObjectFrom'],\n}\n\nexport function compileSqlite<DB>(\n  db: Kysely<DB>,\n  table: string,\n  options: CompileOptions,\n  relations: ResolvedRelations,\n  tables: Record<string, TableSnapshot>,\n  mode: CompileMode = 'many',\n): CompiledQuery {\n  return runCompile(db, table, options, relations, tables, mode, SQLITE_HELPERS)\n}\n","/**\n * MySQL compiler for `db.query.X.findMany({ with })`.\n *\n * Strategy locked in `docs/db/spec-relational-query-other-dialects.md`\n * §3.2: each `many` relation becomes a Kysely `jsonArrayFrom(...)`\n * select expression that compiles to\n * `cast(coalesce(json_arrayagg(json_object(...)), '[]') as json)`.\n * Each `one` becomes `jsonObjectFrom(...)`, compiling to a\n * `JSON_OBJECT(...)` call with `LIMIT 1`. The traversal logic is\n * shared with the PG + SQLite compilers via `runCompile`.\n *\n * Result-decoding: MySQL drivers return JSON columns as TEXT (or\n * Buffers for older mysql2 configs); `createDbClient` auto-attaches\n * `ParseJSONResultsPlugin` for the MySQL dialect so the nested JSON\n * round-trips back to JS objects before the codec / row-handler\n * chain runs.\n *\n * MySQL minimum version: **8.0+**. `JSON_ARRAYAGG` shipped in 8.0;\n * earlier versions don't have it. The version check fires at the\n * adapter layer (`mysqlAdapter()` — M4.A.5) on first connection so\n * adopters get a clear error before any query reaches this\n * compiler. Spec R-1.\n */\n\nimport { type Kysely, type CompiledQuery } from 'kysely'\nimport { jsonArrayFrom, jsonObjectFrom } from 'kysely/helpers/mysql'\nimport {\n  runCompile,\n  type CompileMode,\n  type CompileOptions,\n  type JsonHelpers,\n} from './compile-shared'\nimport type { ResolvedRelations } from './relations'\nimport type { TableSnapshot } from '../snapshot/types'\n\nconst MYSQL_HELPERS: JsonHelpers = {\n  jsonArrayFrom: jsonArrayFrom as unknown as JsonHelpers['jsonArrayFrom'],\n  jsonObjectFrom: jsonObjectFrom as unknown as JsonHelpers['jsonObjectFrom'],\n}\n\nexport function compileMysql<DB>(\n  db: Kysely<DB>,\n  table: string,\n  options: CompileOptions,\n  relations: ResolvedRelations,\n  tables: Record<string, TableSnapshot>,\n  mode: CompileMode = 'many',\n): CompiledQuery {\n  return runCompile(db, table, options, relations, tables, mode, MYSQL_HELPERS)\n}\n","/**\n * Dispatch helper that selects the right relational-query compiler\n * for the runtime dialect detected by `createDbClient`. After M4.A.3\n * all three dialects ship real compilers — the throw-stub is\n * retired.\n *\n *   - PG     → `compilePg`     (kysely/helpers/postgres)\n *   - SQLite → `compileSqlite` (kysely/helpers/sqlite)\n *   - MySQL  → `compileMysql`  (kysely/helpers/mysql)\n *\n * Spec: docs/db/spec-relational-query.md §4.3 +\n * docs/db/spec-relational-query-other-dialects.md §4.\n */\n\nimport { compilePg } from './compile-pg'\nimport { compileSqlite } from './compile-sqlite'\nimport { compileMysql } from './compile-mysql'\nimport type { CompileFn } from './builder'\n\n/**\n * Pick a compiler by dialect tag. Used by `createDbClient` after it\n * detects the dialect from the Kysely instance's class name.\n */\nexport function pickCompiler(dialect: 'postgres' | 'sqlite' | 'mysql'): CompileFn {\n  switch (dialect) {\n    case 'postgres':\n      return compilePg as CompileFn\n    case 'sqlite':\n      return compileSqlite as CompileFn\n    case 'mysql':\n      return compileMysql as CompileFn\n  }\n}\n","import {\n  Kysely,\n  ParseJSONResultsPlugin,\n  type Dialect as KyselyDialect,\n  type KyselyPlugin,\n} from 'kysely'\n\nimport type { CreateDbClientOptions, KickDbClient } from './types'\nimport type { SchemaToTypes } from './schema-types'\nimport { KickDbEventEmitter } from './events'\nimport { CodecPlugin, buildDecoderMap, buildEncoderMap } from './codec-plugin'\nimport { wrap, type InternalContext } from './wrap'\nimport { extractRelations } from '../query/extract-relations'\nimport { readDialectMark } from '../dialect-marker'\nimport { pickCompiler } from '../query/compilers'\nimport { extractSnapshot } from '../snapshot/extract'\n\n// DB defaults to SchemaToTypes<TSchema> so the returned client is typed\n// directly from the schema parameter — no KickDbRegister lookup at the call\n// site. This breaks the `dbClient → RegisteredDB → KickDbRegister['db'] →\n// typeof dbClient` cycle that would otherwise resolve to `unknown`.\n// KickDbRegister is only consulted when consumers reference `KickDbClient`\n// with no explicit generic.\nexport function createDbClient<TSchema, DB = SchemaToTypes<TSchema>>(\n  opts: CreateDbClientOptions<TSchema, DB>,\n): KickDbClient<DB> {\n  // `slowQueryThresholdMs` and `bus` both imply events — listeners can't\n  // subscribe to slowQuery / queryError, and the bus republisher can't\n  // observe them, without the emitter being live.\n  const eventsEnabled = opts.events || opts.slowQueryThresholdMs != null || opts.bus != null\n  const events = eventsEnabled ? new KickDbEventEmitter() : null\n  const slowThreshold = opts.slowQueryThresholdMs ?? null\n  const bus = opts.bus ?? null\n\n  // Republish to the DevTools event bus when wired. Mirror the local\n  // event names under a `db:` namespace so adopter tabs / cross-cutting\n  // log consumers know they came from kickjs-db.\n  if (events && bus) {\n    events.on('slowQuery', (payload) => {\n      bus.emit('db:slow-query', payload)\n    })\n    events.on('queryError', (payload) => {\n      bus.emit('db:query-error', payload)\n    })\n  }\n\n  // Kysely's `log` config fires on every query — both success\n  // (level 'query') and failure (level 'error') — with the compiled\n  // SQL, params, and timing. Cleanest hook for the lifecycle events;\n  // a full KyselyPlugin (transformQuery / transformResult) is heavier\n  // and only worth it when we need to mutate the SQL tree.\n  // Build customType codec maps once. Both transforms short-circuit\n  // when their map is empty so the plugin is free of per-row /\n  // per-query cost when no customType is in play. Plugin only\n  // attached when at least one side has work to do.\n  const decoders = buildDecoderMap(opts.schema)\n  const encoders = buildEncoderMap(opts.schema)\n  const codecPlugin =\n    decoders.size > 0 || encoders.size > 0 ? new CodecPlugin(encoders, decoders) : null\n\n  // Detect dialect early — needed both to pick the relational query\n  // compiler (below) and to decide whether the JSON-results plugin\n  // ships in the Kysely plugin chain.\n  //\n  // SQLite + MySQL drivers return JSON columns as TEXT, so the\n  // kysely/helpers/<dialect> jsonArrayFrom / jsonObjectFrom won't\n  // round-trip without ParseJSONResultsPlugin. PG decodes JSON\n  // natively — skip the plugin there to keep the chain minimal.\n  // Spec: docs/db/spec-relational-query-other-dialects.md §5.\n  const dialectTag = detectDialect(opts.dialect)\n\n  // Unified per-query stream for the DevTools \"Database\" tab — every\n  // successful query republished as `db:query` with the dialect tag so\n  // the tab can render duration / SQL / dialect. Failures keep flowing on\n  // `db:query-error` (wired above); the tab subscribes to both. Tagging\n  // here (rather than the block above) keeps `dialectTag` in scope.\n  if (events && bus) {\n    events.on('query', (payload) => {\n      bus.emit('db:query', { ...payload, dialect: dialectTag })\n    })\n  }\n\n  const plugins: KyselyPlugin[] = []\n  if (codecPlugin) plugins.push(codecPlugin)\n  if (dialectTag === 'sqlite' || dialectTag === 'mysql') {\n    plugins.push(new ParseJSONResultsPlugin())\n  }\n  // M5.B.2 — adopter-supplied plugins (e.g. `safeNullComparison()`)\n  // append after the built-ins so the AST transforms run on a tree\n  // that already has the kickjs-internal codec / JSON rewriting in\n  // place. Order matches Kysely's documented \"plugins run top-down\".\n  if (opts.plugins && opts.plugins.length > 0) {\n    plugins.push(...opts.plugins)\n  }\n\n  const kysely = new Kysely<DB>({\n    dialect: opts.dialect,\n    plugins: plugins.length > 0 ? plugins : undefined,\n    log: events\n      ? (event) => {\n          if (event.level === 'query') {\n            const durationMs = event.queryDurationMillis\n            const payload = {\n              sql: event.query.sql,\n              parameters: event.query.parameters,\n              durationMs,\n            }\n            events.emit('query', payload)\n            if (slowThreshold != null && durationMs >= slowThreshold) {\n              events.emit('slowQuery', { ...payload, thresholdMs: slowThreshold })\n            }\n          } else if (event.level === 'error') {\n            events.emit('queryError', {\n              sql: event.query.sql,\n              parameters: event.query.parameters,\n              error: event.error,\n            })\n          }\n        }\n      : undefined,\n  })\n\n  // Resolve `relations()` declarations into the JSON-serializable\n  // sidecar consumed by the query compiler. Schemas without any\n  // `relations()` get an empty record — the compiler still works\n  // (errors clearly on `with` keys when nothing is declared).\n  const tables = extractSnapshot(opts.schema as Record<string, unknown>, dialectTag).tables\n  const relations = extractRelations(opts.schema as Record<string, unknown>, tables) ?? {}\n\n  const ctx: InternalContext = {\n    events,\n    dialect: dialectTag,\n    savepointCounter: { value: 0 },\n    query: {\n      relations,\n      tables,\n      compile: pickCompiler(dialectTag),\n    },\n  }\n  return wrap<DB>(kysely, ctx)\n}\n\nfunction detectDialect(dialect: KyselyDialect): KickDbClient['dialect'] {\n  // Fast path: KickJS's own dialect factories (`pgDialect` /\n  // `mysqlDialect` / `sqliteDialect`) stamp an explicit marker, so\n  // detection is exact and never silently mis-classifies.\n  const marked = readDialectMark(dialect)\n  if (marked) return marked\n\n  // Fallback for raw Kysely dialects an adopter constructs directly.\n  // Kysely's dialects have ctor names like PostgresDialect /\n  // SqliteDialect / MysqlDialect. Adopters who hand-roll the\n  // KyselyDialect interface (`{ createAdapter, ... }` literals)\n  // bypass that ctor — fall back to inspecting the adapter class\n  // returned by `createAdapter()`, which is the real kysely\n  // PostgresAdapter / SqliteAdapter / MysqlAdapter.\n  const dialectCtor = (dialect.constructor as { name?: string })?.name ?? ''\n  const adapterCtor = (dialect.createAdapter().constructor as { name?: string })?.name ?? ''\n  const tag = `${dialectCtor} ${adapterCtor}`\n  if (/Postgres/i.test(tag)) return 'postgres'\n  if (/Mysql/i.test(tag)) return 'mysql'\n  return 'sqlite'\n}\n","import {\n  BinaryOperationNode,\n  OperationNodeTransformer,\n  OperatorNode,\n  ValueNode,\n  type KyselyPlugin,\n  type PluginTransformQueryArgs,\n  type PluginTransformResultArgs,\n  type QueryResult,\n  type RootOperationNode,\n  type UnknownRow,\n} from 'kysely'\n\n// M5 follow-up — kickjs-side workaround for the broken\n// SafeNullComparisonPlugin shipped in Kysely 0.29\n// (kysely/dist/plugin/safe-null-comparison/safe-null-comparison-transformer.js).\n//\n// The upstream transformer rewrites `=` / `!=` / `<>` against\n// literal `null` to `IS` / `IS NOT` at AST level but keeps the null\n// operand as a `ValueNode(null)`, which the PG compiler then\n// parameterises. Result: `WHERE \"col\" IS $1` with `$1=null` —\n// invalid PostgreSQL syntax. PG's `IS` predicate grammar requires\n// specific predicates (`NULL`, `TRUE`, `FALSE`, `UNKNOWN`,\n// `DISTINCT FROM ...`), not an arbitrary parameter placeholder.\n//\n// Verified empirically against postgres:16-alpine in\n// `packages/db-pg/__tests__/integration/kysely-safe-null-broken-pg.test.ts`.\n// Tracked for upstream follow-up at #220.\n//\n// Fix: identical AST rewrite, but replace the null `ValueNode` with\n// `ValueNode.createImmediate(null)` so the PG compiler emits the\n// bare SQL keyword `null` inline (no parameter binding). Output is\n// `WHERE \"col\" IS NULL` / `WHERE \"col\" IS NOT NULL` — valid PG and\n// semantically correct under three-valued logic.\n//\n// When upstream Kysely fixes their transformer (issue #220), this\n// wrapper can collapse to a one-line re-export of\n// `kysely`'s plugin. The unit test in\n// `__tests__/unit/safe-null-comparison.test.ts` and the PG\n// integration test pin the current output, so the diff will surface\n// loudly at upgrade time.\n\nclass SafeNullComparisonTransformer extends OperationNodeTransformer {\n  protected override transformBinaryOperation(node: BinaryOperationNode): BinaryOperationNode {\n    const transformed = super.transformBinaryOperation(node)\n    const { operator, leftOperand, rightOperand } = transformed\n\n    if (!OperatorNode.is(operator)) return transformed\n    if (!ValueNode.is(rightOperand) || rightOperand.value !== null) return transformed\n\n    const op = operator.operator\n    if (op !== '=' && op !== '!=' && op !== '<>') return transformed\n\n    return BinaryOperationNode.create(\n      leftOperand,\n      OperatorNode.create(op === '=' ? 'is' : 'is not'),\n      // KEY DIFFERENCE vs Kysely's upstream transformer — `createImmediate`\n      // marks the value for inline emission, so the compiler writes the\n      // SQL keyword `null` instead of binding the value as a `$N` parameter.\n      ValueNode.createImmediate(null),\n    )\n  }\n}\n\nclass SafeNullComparisonPlugin implements KyselyPlugin {\n  readonly #transformer = new SafeNullComparisonTransformer()\n\n  transformQuery(args: PluginTransformQueryArgs): RootOperationNode {\n    return this.#transformer.transformNode(args.node)\n  }\n\n  async transformResult(args: PluginTransformResultArgs): Promise<QueryResult<UnknownRow>> {\n    return args.result\n  }\n}\n\n/**\n * Pass this to `createDbClient({ plugins: [...] })` so\n * `eb('col', '=', null)` (plus `!=` / `<>`) compiles to `IS NULL` /\n * `IS NOT NULL` instead of the silently-false `= NULL` default.\n *\n * Without the plugin, Kysely passes `null` through as a bound\n * parameter — the resulting `col = $1` evaluates to UNKNOWN under\n * three-valued logic, which filters out every row including the\n * ones the adopter intended to match. The plugin rewrites the AST\n * before compilation so the operator becomes `IS` / `IS NOT` and\n * the null literal flows inline (no `$N` parameter binding).\n *\n * ```ts\n * import { createDbClient, safeNullComparison } from '@forinda/kickjs-db'\n *\n * const db = createDbClient({\n *   schema,\n *   dialect: pgDialect({ pool }),\n *   plugins: [safeNullComparison()],\n * })\n *\n * await db.selectFrom('users').where('deletedAt', '=', null).selectAll().execute()\n * // → SQL: select * from \"users\" where \"deletedAt\" is null\n * ```\n *\n * Opt-in; default `createDbClient` chains stay byte-identical so\n * existing repos that work around the gotcha manually don't see a\n * behaviour change.\n *\n * **Why a kickjs-side helper rather than re-exporting Kysely's?**\n * Kysely 0.29's own `SafeNullComparisonPlugin` ships broken on PG —\n * it rewrites the operator but keeps the null operand parameterised,\n * producing `WHERE \"col\" IS $1` with `$1=null`, which PG rejects\n * with `syntax error at or near \"$1\"`. The kickjs version emits the\n * literal `null` keyword inline so PG accepts it. Tracked upstream\n * at <https://github.com/forinda/kick-js/issues/220>.\n */\nexport function safeNullComparison(): KyselyPlugin {\n  return new SafeNullComparisonPlugin()\n}\n","import path from 'node:path'\nimport { readFile, writeFile } from 'node:fs/promises'\nimport { existsSync } from 'node:fs'\n\nimport { computeMigrationHash } from './journal'\nimport type { Journal } from './journal'\n\nexport interface ReviewResult {\n  id: string\n  /** True when the migration was already reviewed (no-op). */\n  alreadyReviewed: boolean\n}\n\n/**\n * Mark a migration as reviewed: flip `meta.json.reviewed` to `true` —\n * the ONLY review state the runner checks. The SQL files carry an\n * immutable provenance banner (`-- Generated by @forinda/kickjs-db vX`),\n * so reviewing never touches them and the journal hash stays valid.\n *\n * Legacy migrations (generated before the banner) still carry mutable\n * `-- REVIEWED: false` markers inside the hashed files; for those we\n * keep the old behaviour — swap the markers and recompute the journal\n * hash so all three stay in sync.\n */\nexport async function reviewMigration(migrationsDir: string, id: string): Promise<ReviewResult> {\n  const dir = path.join(migrationsDir, id)\n  const metaPath = path.join(dir, 'meta.json')\n  if (!existsSync(metaPath)) {\n    throw new Error(`kickjs-db: migration '${id}' not found under ${migrationsDir}`)\n  }\n\n  const meta = JSON.parse(await readFile(metaPath, 'utf8')) as { reviewed?: boolean }\n  if (meta.reviewed === true) {\n    return { id, alreadyReviewed: true }\n  }\n\n  // 1. Legacy marker migration: swap `-- REVIEWED: false` if present.\n  //    New-style files (immutable banner) are left untouched.\n  let sqlChanged = false\n  for (const file of ['up.sql', 'down.sql']) {\n    const p = path.join(dir, file)\n    if (!existsSync(p)) continue\n    const sql = await readFile(p, 'utf8')\n    const next = sql.replace(/^-- REVIEWED: false$/m, '-- REVIEWED: true')\n    if (next !== sql) {\n      await writeFile(p, next, 'utf8')\n      sqlChanged = true\n    }\n  }\n\n  // 2. Flip the gate in meta.json (the value the runner actually checks).\n  meta.reviewed = true\n  await writeFile(metaPath, JSON.stringify(meta, null, 2) + '\\n', 'utf8')\n\n  // 3. Journal hash follows only when the hashed bytes changed (legacy\n  //    marker swap). Banner-style migrations skip this entirely.\n  if (sqlChanged) {\n    const journalPath = path.join(migrationsDir, '_journal.json')\n    const journal = JSON.parse(await readFile(journalPath, 'utf8')) as Journal\n    const entry = journal.entries.find((e) => e.id === id)\n    if (entry) {\n      entry.hash = await computeMigrationHash(dir)\n      await writeFile(journalPath, JSON.stringify(journal, null, 2) + '\\n', 'utf8')\n    }\n  }\n\n  return { id, alreadyReviewed: false }\n}\n","import path from 'node:path'\nimport { pathToFileURL } from 'node:url'\nimport type { Dialect } from '../snapshot/types'\nimport type { MigrationAdapter } from '../migrate/adapter'\nimport type { DriftBehavior } from '../migrate/drift'\n\nexport type MigrationAdapterFactory = () => MigrationAdapter | Promise<MigrationAdapter>\n\nexport interface DbConfig {\n  schemaPath: string\n  migrationsDir: string\n  dialect: Dialect\n  /**\n   * How `kick db migrate` reacts when the live DB has schema not recorded\n   * in the migrations (someone ran DDL out of band): `'error'` (default —\n   * refuse), `'warn'` (log + continue), `'ignore'` (skip the check). The\n   * check is dialect-normalised, so SQLite/MySQL's lossy introspection\n   * doesn't false-positive.\n   */\n  driftCheck?: DriftBehavior\n  /**\n   * Postgres connection string for the built-in pgAdapter path. Read from\n   * `db.connectionString` in kick.config.ts, or falls back to the\n   * DATABASE_URL env var. The CLI uses this when no `adapter` factory is\n   * provided.\n   */\n  connectionString?: string\n  /**\n   * Escape hatch: a factory returning a fully-constructed MigrationAdapter.\n   * Takes precedence over `connectionString` when both are set. Use this\n   * for non-default adapter wiring (custom pool, neon-serverless, etc).\n   */\n  adapter?: MigrationAdapterFactory\n}\n\nexport async function resolveDbConfig(opts: { configPath: string }): Promise<DbConfig> {\n  const abs = path.resolve(opts.configPath)\n  const mod = await import(pathToFileURL(abs).href)\n  const cfg = mod.default ?? mod\n  const db = cfg?.db ?? {}\n  return {\n    schemaPath: db.schemaPath ?? 'src/db/schema.ts',\n    migrationsDir: db.migrationsDir ?? 'db/migrations',\n    dialect: db.dialect ?? 'postgres',\n    connectionString: db.connectionString ?? process.env.DATABASE_URL,\n    adapter: db.adapter,\n    driftCheck: db.driftCheck,\n  }\n}\n","import path from 'node:path'\nimport { mkdir, readFile, writeFile, readdir } from 'node:fs/promises'\nimport { pathToFileURL, fileURLToPath } from 'node:url'\nimport { existsSync, readFileSync } from 'node:fs'\n\nimport { extractSnapshot } from '../snapshot/extract'\nimport { diff } from '../diff/engine'\nimport { invertChanges, hasAmbiguousReverse } from '../diff/invert'\nimport { CompositeEnumReferenceError, type CompositeRef } from '../diff/composite-detect'\nimport { emitPg } from '../emit/pg'\nimport { emitSqlite } from '../emit/sqlite'\nimport { emitMysql } from '../emit/mysql'\nimport { appendJournalEntry, computeMigrationHash } from '../migrate/journal'\nimport type { DbConfig } from './config'\nimport type { ChangeSet } from '../diff/types'\nimport type { Dialect, SchemaSnapshot } from '../snapshot/types'\nimport type { Change, RemoveEnumValue } from '../diff/types'\n\n/**\n * Emit migration DDL for the dialect. `from`/`to` are the schema snapshots\n * before/after the changes apply — the SQLite emitter uses them to build\n * table rebuilds (column alters, FK add/drop) it can't express via\n * `ALTER TABLE`. Postgres/MySQL ignore them.\n */\nfunction emitDdl(\n  dialect: Dialect,\n  changes: ChangeSet,\n  from: SchemaSnapshot,\n  to: SchemaSnapshot,\n): string {\n  switch (dialect) {\n    case 'sqlite':\n      return emitSqlite(changes, { from, to })\n    case 'mysql':\n      return emitMysql(changes)\n    case 'postgres':\n      return emitPg(changes)\n  }\n}\n\nexport interface GenerateOptions {\n  name: string\n  config: DbConfig\n  cwd: string\n  now?: () => Date\n  /**\n   * When true, skip the schema diff and emit an empty migration shell\n   * (up.sql / down.sql with just the generated-by banner, snapshot.json copying\n   * the prior schema state). Used for data migrations, seed inserts, or any\n   * change the diff engine can't author. Matches knex's `migrate:make`.\n   */\n  empty?: boolean\n  /**\n   * M4.C — generate-time gate for `removeEnumValue` changes. When the\n   * diff produces one or more, this callback is invoked once per\n   * affected enum to surface PG composite-type references. A non-empty\n   * result aborts generate with `CompositeEnumReferenceError` (the\n   * rename-recreate USING-cast can't reach into composite fields).\n   *\n   * Optional: when omitted, generate skips the check (no DB connection\n   * required). The CLI wires this for `dialect=postgres` workflows.\n   */\n  detectCompositeRefs?: (enumName: string) => Promise<readonly CompositeRef[]>\n}\n\nexport interface GenerateResult {\n  status: 'created' | 'no-changes'\n  migrationDir?: string\n  changeCount: number\n  empty?: boolean\n}\n\nexport async function generate(opts: GenerateOptions): Promise<GenerateResult> {\n  const migrationsAbs = path.resolve(opts.cwd, opts.config.migrationsDir)\n  const { snapshot: prev, id: previousId } = await readLatestSnapshotEntry(\n    migrationsAbs,\n    opts.config.dialect,\n  )\n\n  if (opts.empty) {\n    return await writeMigration({\n      opts,\n      migrationsAbs,\n      previousId,\n      // Empty migrations don't change schema state — keep the prior snapshot\n      // so the next diff-based generate stays consistent.\n      target: prev,\n      upBody: '',\n      downBody: '',\n      changeCount: 0,\n      draft: false,\n      empty: true,\n    })\n  }\n\n  const schemaAbs = path.resolve(opts.cwd, opts.config.schemaPath)\n  const schemaModule = await import(pathToFileURL(schemaAbs).href)\n  const target = extractSnapshot(schemaModule, opts.config.dialect)\n  const changes = diff(prev, target)\n\n  if (changes.length === 0) {\n    return { status: 'no-changes', changeCount: 0 }\n  }\n\n  await assertNoCompositeReferences(changes, opts.detectCompositeRefs)\n\n  const dialect = opts.config.dialect\n  return await writeMigration({\n    opts,\n    migrationsAbs,\n    previousId,\n    target,\n    // up: prev -> target. down: invert applied to target -> prev.\n    upBody: emitDdl(dialect, changes, prev, target),\n    downBody: emitDdl(dialect, invertChanges(changes), target, prev),\n    changeCount: changes.length,\n    draft: hasAmbiguousReverse(changes),\n    empty: false,\n  })\n}\n\ninterface WriteMigrationParams {\n  opts: GenerateOptions\n  migrationsAbs: string\n  previousId: string | null\n  target: SchemaSnapshot\n  upBody: string\n  downBody: string\n  changeCount: number\n  draft: boolean\n  empty: boolean\n}\n\n/**\n * Immutable provenance banner for generated SQL files. Replaces the old\n * mutable `-- REVIEWED: false` marker — review state lives ONLY in\n * `meta.json` (which the integrity hash does not cover), so reviewing a\n * migration never invalidates its journal hash. The old marker invited\n * hand-edits that broke the hash with an opaque mismatch error.\n */\nfunction generatedBanner(): string {\n  return `-- Generated by @forinda/kickjs-db v${ownPackageVersion()} — review state lives in meta.json\\n`\n}\n\nlet cachedVersion: string | null = null\nfunction ownPackageVersion(): string {\n  if (cachedVersion) return cachedVersion\n  // dist layout: dist/*.mjs → '../package.json'; source layout (vitest):\n  // src/cli/generate.ts → '../../package.json'. Probe both.\n  const here = path.dirname(fileURLToPath(import.meta.url))\n  for (const rel of ['../package.json', '../../package.json']) {\n    try {\n      const pkg = JSON.parse(readFileSync(path.resolve(here, rel), 'utf8')) as {\n        name?: string\n        version?: string\n      }\n      if (pkg.name === '@forinda/kickjs-db' && pkg.version) {\n        cachedVersion = pkg.version\n        return cachedVersion\n      }\n    } catch {\n      // keep probing\n    }\n  }\n  cachedVersion = 'unknown'\n  return cachedVersion\n}\n\nasync function writeMigration(p: WriteMigrationParams): Promise<GenerateResult> {\n  const id = formatId(p.opts.now?.() ?? new Date(), p.opts.name)\n  const dir = path.join(p.migrationsAbs, id)\n  await mkdir(dir, { recursive: true })\n\n  const upHeader = generatedBanner()\n  const upHint = p.empty\n    ? '-- Empty migration — author SQL below (data migration, seed, etc).\\n'\n    : ''\n  const upSql = upHeader + upHint + p.upBody + (p.upBody ? '\\n' : '')\n  await writeFile(path.join(dir, 'up.sql'), upSql, 'utf8')\n\n  const downHeader = generatedBanner()\n  const downDraft = p.draft\n    ? '-- DRAFT: ambiguous reverses present (drop column / drop table / type change). Audit before applying.\\n'\n    : ''\n  const downHint = p.empty ? '-- Empty migration — author the reverse SQL here.\\n' : ''\n  const downSql = downHeader + downDraft + downHint + p.downBody + (p.downBody ? '\\n' : '')\n  await writeFile(path.join(dir, 'down.sql'), downSql, 'utf8')\n\n  await writeFile(path.join(dir, 'snapshot.json'), JSON.stringify(p.target, null, 2) + '\\n', 'utf8')\n\n  await writeFile(\n    path.join(dir, 'meta.json'),\n    JSON.stringify(\n      {\n        id,\n        name: p.opts.name,\n        createdAt: (p.opts.now?.() ?? new Date()).toISOString(),\n        reviewed: false,\n        dialect: p.opts.config.dialect,\n        previousId: p.previousId,\n        downIsDraft: p.draft,\n        empty: p.empty,\n      },\n      null,\n      2,\n    ) + '\\n',\n    'utf8',\n  )\n\n  // Append to _journal.json so the runner has the canonical applied-order\n  // and integrity hash. Hash includes up + down + snapshot, so any later\n  // hand-edit of those files will surface as a MigrationHashError at apply.\n  const hash = await computeMigrationHash(dir)\n  await appendJournalEntry(p.migrationsAbs, p.opts.config.dialect, {\n    id,\n    tag: p.opts.name,\n    hash,\n    createdAt: (p.opts.now?.() ?? new Date()).toISOString(),\n  })\n\n  return { status: 'created', migrationDir: dir, changeCount: p.changeCount, empty: p.empty }\n}\n\ninterface LatestEntry {\n  snapshot: SchemaSnapshot\n  id: string | null\n}\n\nasync function readLatestSnapshotEntry(\n  migrationsDir: string,\n  dialect: Dialect,\n): Promise<LatestEntry> {\n  const empty: SchemaSnapshot = { version: 1, dialect, tables: {} }\n  if (!existsSync(migrationsDir)) {\n    return { snapshot: empty, id: null }\n  }\n  const entries = await readdir(migrationsDir)\n  const dirs = entries.filter((e) => /^\\d{8}_\\d{6}_/.test(e)).toSorted()\n  if (dirs.length === 0) {\n    return { snapshot: empty, id: null }\n  }\n  const latest = dirs[dirs.length - 1]\n  const file = path.join(migrationsDir, latest, 'snapshot.json')\n  const snapshot = JSON.parse(await readFile(file, 'utf8')) as SchemaSnapshot\n  return { snapshot, id: latest }\n}\n\n/**\n * M4.C gate. Walk the diff for `removeEnumValue` changes; if any are\n * present and the caller supplied a composite-detector, run it once\n * per enum and aggregate the references. Throws\n * `CompositeEnumReferenceError` when any references are found so the\n * operator restructures the composite before the migration is\n * committed to disk.\n */\nasync function assertNoCompositeReferences(\n  changes: readonly Change[],\n  detect: ((enumName: string) => Promise<readonly CompositeRef[]>) | undefined,\n): Promise<void> {\n  if (!detect) return\n  const removals = changes.filter((c): c is RemoveEnumValue => c.kind === 'removeEnumValue')\n  if (removals.length === 0) return\n\n  const allRefs: CompositeRef[] = []\n  // Detect once per distinct enum — multiple removals on the same enum\n  // collapse into a single check; the caller probably batched them.\n  const seen = new Set<string>()\n  for (const r of removals) {\n    if (seen.has(r.enum)) continue\n    seen.add(r.enum)\n    const refs = await detect(r.enum)\n    allRefs.push(...refs)\n  }\n  if (allRefs.length > 0) {\n    throw new CompositeEnumReferenceError(allRefs)\n  }\n}\n\nfunction formatId(date: Date, name: string): string {\n  const pad = (n: number) => n.toString().padStart(2, '0')\n  const ts =\n    date.getUTCFullYear().toString() +\n    pad(date.getUTCMonth() + 1) +\n    pad(date.getUTCDate()) +\n    '_' +\n    pad(date.getUTCHours()) +\n    pad(date.getUTCMinutes()) +\n    pad(date.getUTCSeconds())\n  const slug = name.replace(/[^a-z0-9]+/gi, '_').toLowerCase()\n  return `${ts}_${slug}`\n}\n","import { ColumnBuilder, type GeneratedBrand, type NotNullBrand } from './types'\n\n// ── helpers ───────────────────────────────────────────────────────────────\n\n/**\n * Type-level brand stamps. Runtime is identity; the cast attaches the\n * relevant brand so `SchemaToTypes<S>` reads them per column.\n */\nfunction brandGenerated<C>(col: C): C & GeneratedBrand {\n  return col as C & GeneratedBrand\n}\n\nfunction brandNotNull<C>(col: C): C & NotNullBrand {\n  return col as C & NotNullBrand\n}\n\nfunction formatNumeric(base: string, precision?: number, scale?: number): string {\n  if (precision === undefined) return base\n  if (scale === undefined) return `${base}(${precision})`\n  return `${base}(${precision}, ${scale})`\n}\n\n// ── auto-assigned identity columns (DB picks the value) ───────────────────\n//\n// Auto-identity columns are always NOT NULL by SQL semantics, so we stamp\n// both NotNullBrand (drop the `| null`) and GeneratedBrand (wrap in\n// Generated<T>) at the constructor.\n\nexport function serial(): ColumnBuilder<number> & GeneratedBrand & NotNullBrand {\n  return brandNotNull(brandGenerated(new ColumnBuilder<number>('serial', { nullable: false })))\n}\n\nexport function bigSerial(): ColumnBuilder<bigint> & GeneratedBrand & NotNullBrand {\n  return brandNotNull(brandGenerated(new ColumnBuilder<bigint>('bigserial', { nullable: false })))\n}\n\nexport function smallSerial(): ColumnBuilder<number> & GeneratedBrand & NotNullBrand {\n  return brandNotNull(brandGenerated(new ColumnBuilder<number>('smallserial', { nullable: false })))\n}\n\n// ── numeric ───────────────────────────────────────────────────────────────\n\nexport function integer(): ColumnBuilder<number> {\n  return new ColumnBuilder<number>('integer')\n}\n\nexport function bigint(): ColumnBuilder<bigint> {\n  return new ColumnBuilder<bigint>('bigint')\n}\n\nexport function smallint(): ColumnBuilder<number> {\n  return new ColumnBuilder<number>('smallint')\n}\n\nexport function decimal(precision?: number, scale?: number): ColumnBuilder<string> {\n  return new ColumnBuilder<string>(formatNumeric('decimal', precision, scale))\n}\n\nexport function numeric(precision?: number, scale?: number): ColumnBuilder<string> {\n  return new ColumnBuilder<string>(formatNumeric('numeric', precision, scale))\n}\n\nexport function real(): ColumnBuilder<number> {\n  return new ColumnBuilder<number>('real')\n}\n\nexport function doublePrecision(): ColumnBuilder<number> {\n  return new ColumnBuilder<number>('double precision')\n}\n\n// ── string-shaped ─────────────────────────────────────────────────────────\n\nexport function varchar(length = 255): ColumnBuilder<string> {\n  return new ColumnBuilder<string>(`varchar(${length})`)\n}\n\nexport function char(length = 1): ColumnBuilder<string> {\n  return new ColumnBuilder<string>(`char(${length})`)\n}\n\nexport function text(): ColumnBuilder<string> {\n  return new ColumnBuilder<string>('text')\n}\n\n// ── boolean ───────────────────────────────────────────────────────────────\n\nexport function boolean(): ColumnBuilder<boolean> {\n  return new ColumnBuilder<boolean>('boolean')\n}\n\n// ── date / time ───────────────────────────────────────────────────────────\n\n/**\n * Subtype builder so `defaultNow()` can mark the resulting column as\n * generated — when the DB will fill in `CURRENT_TIMESTAMP` if the adopter\n * omits the column on insert. Returns `this & GeneratedBrand` so the\n * subclass identity is preserved through the chain.\n */\nexport class TimestampBuilder extends ColumnBuilder<Date> {\n  constructor(typeName: string = 'timestamp') {\n    super(typeName)\n  }\n\n  defaultNow(): this & GeneratedBrand {\n    this.state.default = 'CURRENT_TIMESTAMP'\n    return brandGenerated(this)\n  }\n}\n\nexport function timestamp(): TimestampBuilder {\n  return new TimestampBuilder('timestamp')\n}\n\nexport function timestamptz(): TimestampBuilder {\n  return new TimestampBuilder('timestamptz')\n}\n\nexport function date(): ColumnBuilder<Date> {\n  return new ColumnBuilder<Date>('date')\n}\n\nexport function time(): ColumnBuilder<string> {\n  return new ColumnBuilder<string>('time')\n}\n\nexport function interval(): ColumnBuilder<string> {\n  return new ColumnBuilder<string>('interval')\n}\n\n// ── identity-shaped (uuid) ────────────────────────────────────────────────\n\n/**\n * Subtype builder so `defaultRandom()` can mark the resulting column as\n * generated — when the DB fills in `gen_random_uuid()` for omitted columns.\n * Returns `this & GeneratedBrand` so chaining works in either order:\n *   uuid().defaultRandom().primaryKey()\n *   uuid().primaryKey().defaultRandom()  ← also works\n */\nexport class UuidBuilder extends ColumnBuilder<string> {\n  constructor() {\n    super('uuid')\n  }\n\n  defaultRandom(): this & GeneratedBrand {\n    this.state.default = 'gen_random_uuid()'\n    return brandGenerated(this)\n  }\n}\n\nexport function uuid(): UuidBuilder {\n  return new UuidBuilder()\n}\n\n// ── structured / binary ───────────────────────────────────────────────────\n\n/**\n * The `T` generic exists so adopters can declare their JSON shape:\n *\n *   meta: jsonb<{ tags: string[] }>()\n *\n * `SchemaToTypes<S>` then sees `ColumnBuilder<{ tags: string[] }>` and the\n * row type narrows to `{ tags: string[] } | null`.\n */\nexport function json<T = unknown>(): ColumnBuilder<T> {\n  return new ColumnBuilder<T>('json')\n}\n\nexport function jsonb<T = unknown>(): ColumnBuilder<T> {\n  return new ColumnBuilder<T>('jsonb')\n}\n\nexport function bytea(): ColumnBuilder<Uint8Array> {\n  return new ColumnBuilder<Uint8Array>('bytea')\n}\n","import type { ColumnBuilder, ColumnRef } from './columns/types'\nimport type { IndexDecl } from './constraints'\n\nexport type { ColumnRef }\n\nexport interface TableDecl<\n  TName extends string = string,\n  C extends Record<string, ColumnBuilder> = Record<string, ColumnBuilder>,\n> {\n  __isTable: true\n  __name: TName\n  __columns: C\n  __indexes: IndexDecl[]\n}\n\ntype TableRefs<TName extends string, C extends Record<string, ColumnBuilder>> = TableDecl<\n  TName,\n  C\n> & {\n  [K in keyof C]: ColumnRef\n}\n\ntype ConstraintBuilder<C extends Record<string, ColumnBuilder>> = (refs: {\n  [K in keyof C]: ColumnRef\n}) => Record<string, IndexDecl>\n\n/**\n * Declare a typed table. The `TName extends string` generic narrows to the\n * literal table name so `SchemaToTypes<S>` can index by it without losing\n * the constant — `table('users', …)` widens to `TableDecl<'users', …>`,\n * not `TableDecl<string, …>`.\n */\nexport function table<TName extends string, C extends Record<string, ColumnBuilder>>(\n  name: TName,\n  columns: C,\n  constraints?: ConstraintBuilder<C>,\n): TableRefs<TName, C> {\n  const decl: TableDecl<TName, C> = {\n    __isTable: true,\n    __name: name,\n    __columns: columns,\n    __indexes: [],\n  }\n\n  const refs = {} as { [K in keyof C]: ColumnRef }\n  for (const [key, builder] of Object.entries(columns) as [keyof C, ColumnBuilder][]) {\n    refs[key] = {\n      __tableName: name,\n      __name: key as string,\n      __builder: builder,\n      __state: () => builder.__state(),\n    }\n  }\n\n  if (constraints) {\n    const declared = constraints(refs)\n    decl.__indexes = Object.values(declared)\n  }\n\n  return Object.assign(decl, refs)\n}\n","export interface IndexDecl {\n  name: string\n  columns: string[]\n  unique: boolean\n}\n\ninterface ColRef {\n  __name: string\n}\n\nexport function index(name: string) {\n  return {\n    on(...cols: ColRef[]): IndexDecl {\n      return { name, columns: cols.map((c) => c.__name), unique: false }\n    },\n  }\n}\n\nexport function unique(name: string) {\n  return {\n    on(...cols: ColRef[]): IndexDecl {\n      return { name, columns: cols.map((c) => c.__name), unique: true }\n    },\n  }\n}\n","import type { ColumnBuilder } from './columns/types'\nimport type { ColumnRef, TableDecl } from './table'\n\n/**\n * Generic over the target table so the typegen plugin can pull\n * `target['__name']` without losing the literal string at the type\n * level. Existing callers that only read `kind` / `fields` /\n * `references` see the same surface.\n */\nexport interface RelationOne<\n  TTarget extends TableDecl<string, Record<string, ColumnBuilder>> = TableDecl<\n    string,\n    Record<string, ColumnBuilder>\n  >,\n> {\n  kind: 'one'\n  target: TTarget\n  fields: ColumnRef[]\n  references: ColumnRef[]\n  /**\n   * Disambiguates this relation from sibling `one` relations on the\n   * same source table that point at the same target. Pair with the\n   * matching `relationName` on the inverse `many` side. See\n   * docs/db/spec-relation-name.md.\n   */\n  relationName?: string\n}\n\nexport interface RelationMany<\n  TTarget extends TableDecl<string, Record<string, ColumnBuilder>> = TableDecl<\n    string,\n    Record<string, ColumnBuilder>\n  >,\n> {\n  kind: 'many'\n  target: TTarget\n  /**\n   * Pairs with the matching `relationName` on the inverse `one`\n   * declaration. Required when the source table has multiple FKs\n   * to the same target; resolver throws\n   * `RelationalQueryMissingInverseError` otherwise.\n   */\n  relationName?: string\n}\n\nexport type Relation = RelationOne | RelationMany\n\n/**\n * Generic so the typegen plugin can read the source table name and\n * the per-relation kind/target via `RelationsDecl['__sourceTable']`\n * and `RelationsDecl['__relations']`. The runtime shape is\n * unchanged; the generic parameters narrow the type at call sites.\n */\nexport interface RelationsDecl<\n  TSource extends string = string,\n  TRelations extends Record<string, Relation> = Record<string, Relation>,\n> {\n  __isRelations: true\n  __sourceTable: TSource\n  __relations: TRelations\n}\n\ninterface Helpers {\n  one: <T extends TableDecl<string, Record<string, ColumnBuilder>>>(\n    target: T,\n    opts: { fields: ColumnRef[]; references: ColumnRef[]; relationName?: string },\n  ) => RelationOne<T>\n  many: <T extends TableDecl<string, Record<string, ColumnBuilder>>>(\n    target: T,\n    opts?: { relationName?: string },\n  ) => RelationMany<T>\n}\n\n/**\n * Declare a typed relation set for `source`. The return type\n * preserves `source.__name` and the literal `kind`/`target` of every\n * helper-built entry so `SchemaToRelationsRegister<S>` (re-exported\n * from `@forinda/kickjs-db`) can walk the schema barrel and emit a\n * matching `KickDbRelationsRegister` augmentation at typegen time.\n */\nexport function relations<\n  T extends TableDecl<string, Record<string, ColumnBuilder>>,\n  R extends Record<string, Relation>,\n>(source: T, builder: (h: Helpers) => R): RelationsDecl<T['__name'], R> {\n  const helpers: Helpers = {\n    one: (target, opts) => ({\n      kind: 'one',\n      target,\n      fields: opts.fields,\n      references: opts.references,\n      ...(opts.relationName !== undefined ? { relationName: opts.relationName } : {}),\n    }),\n    many: (target, opts) => ({\n      kind: 'many',\n      target,\n      ...(opts?.relationName !== undefined ? { relationName: opts.relationName } : {}),\n    }),\n  }\n  return {\n    __isRelations: true,\n    __sourceTable: source.__name,\n    __relations: builder(helpers),\n  } as RelationsDecl<T['__name'], R>\n}\n","/**\n * LIKE / ILIKE pattern safety helpers.\n *\n * User-supplied search text dropped straight into a `LIKE` pattern lets\n * the user inject wildcards: searching for `100%` matches everything,\n * `a_b` matches `axb`. Worse, a literal `%` from the user combined with a\n * leading wildcard (`%${input}%`) can blow up to a full scan. These\n * helpers escape the LIKE metacharacters so the input is matched\n * literally.\n *\n * Escapes `%`, `_`, and the escape character itself. The default escape\n * char is backslash, which Postgres and SQLite honour by default; MySQL\n * also defaults to backslash. When you build the query, pair the pattern\n * with the matching `ESCAPE '\\'` clause if your dialect/collation needs\n * it explicit.\n */\n\nexport type LikeMatchMode = 'contains' | 'startsWith' | 'endsWith' | 'exact'\n\n/**\n * Escape LIKE/ILIKE metacharacters in `input` so it matches literally.\n *\n * @example\n * ```ts\n * escapeLike('100%')        // '100\\\\%'\n * escapeLike('a_b\\\\c')      // 'a\\\\_b\\\\\\\\c'\n * ```\n */\nexport function escapeLike(input: string, escapeChar = '\\\\'): string {\n  // The escape char must be exactly one character and not a wildcard\n  // itself — `''` would be a no-op, `'%'`/`'_'` would over-escape and\n  // corrupt the literal match. This is a safety primitive, so reject\n  // bad config loudly rather than emit a silently-wrong pattern.\n  if (escapeChar.length !== 1 || escapeChar === '%' || escapeChar === '_') {\n    throw new Error(\"escapeLike: escapeChar must be a single character other than '%' or '_'\")\n  }\n  // Escape the escape char first so we don't double-escape the\n  // backslashes we add for % and _.\n  const e = escapeChar\n  return input\n    .replaceAll(e, e + e)\n    .replaceAll('%', e + '%')\n    .replaceAll('_', e + '_')\n}\n\n/**\n * Build a literal-safe LIKE pattern from user input.\n *\n * @example\n * ```ts\n * likePattern('john%', 'contains')    // '%john\\\\%%'\n * likePattern('admin', 'startsWith')  // 'admin%'\n * db.selectFrom('users')\n *   .where('email', 'like', likePattern(ctx.qs().search, 'contains'))\n * ```\n */\nexport function likePattern(\n  input: string,\n  mode: LikeMatchMode = 'contains',\n  escapeChar = '\\\\',\n): string {\n  const safe = escapeLike(input, escapeChar)\n  switch (mode) {\n    case 'contains':\n      return `%${safe}%`\n    case 'startsWith':\n      return `${safe}%`\n    case 'endsWith':\n      return `%${safe}`\n    case 'exact':\n      return safe\n    default: {\n      // Compile-time exhaustiveness + a runtime guard for JS callers /\n      // `as any` that pass an unsupported mode (would otherwise return\n      // undefined despite the `: string` signature).\n      const _exhaustive: never = mode\n      throw new Error(`likePattern: unsupported match mode ${String(_exhaustive)}`)\n    }\n  }\n}\n"],"mappings":"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"}