@happyvertical/smrt-core 0.40.69 → 0.41.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (237) hide show
  1. package/AGENTS.md +29 -4
  2. package/README.md +20 -1
  3. package/agents/change-feed.md +1 -1
  4. package/agents/query-bounds.md +45 -0
  5. package/agents/schema-paths.md +786 -0
  6. package/dist/browser.d.ts +1 -0
  7. package/dist/browser.d.ts.map +1 -1
  8. package/dist/browser.js +5 -3
  9. package/dist/cascade.d.ts +120 -0
  10. package/dist/cascade.d.ts.map +1 -0
  11. package/dist/cascade.js +430 -0
  12. package/dist/cascade.js.map +1 -0
  13. package/dist/change-feed.d.ts +34 -2
  14. package/dist/change-feed.d.ts.map +1 -1
  15. package/dist/change-feed.js +52 -11
  16. package/dist/change-feed.js.map +1 -1
  17. package/dist/class.d.ts +36 -3
  18. package/dist/class.d.ts.map +1 -1
  19. package/dist/class.js +87 -9
  20. package/dist/class.js.map +1 -1
  21. package/dist/collection-cache.js +0 -0
  22. package/dist/collection-cache.js.map +1 -1
  23. package/dist/collection.d.ts +130 -2
  24. package/dist/collection.d.ts.map +1 -1
  25. package/dist/collection.js +290 -57
  26. package/dist/collection.js.map +1 -1
  27. package/dist/config.d.ts +10 -0
  28. package/dist/config.d.ts.map +1 -1
  29. package/dist/config.js.map +1 -1
  30. package/dist/database.d.ts +8 -0
  31. package/dist/database.d.ts.map +1 -1
  32. package/dist/database.js +16 -8
  33. package/dist/database.js.map +1 -1
  34. package/dist/db-errors.d.ts +105 -0
  35. package/dist/db-errors.d.ts.map +1 -0
  36. package/dist/db-errors.js +382 -0
  37. package/dist/db-errors.js.map +1 -0
  38. package/dist/decorators/index.d.ts +80 -6
  39. package/dist/decorators/index.d.ts.map +1 -1
  40. package/dist/decorators/index.js +102 -12
  41. package/dist/decorators/index.js.map +1 -1
  42. package/dist/dispatch/bus.d.ts.map +1 -1
  43. package/dist/dispatch/bus.js +4 -3
  44. package/dist/dispatch/bus.js.map +1 -1
  45. package/dist/dispatch/collections/Dispatches.d.ts.map +1 -1
  46. package/dist/dispatch/collections/Dispatches.js +19 -4
  47. package/dist/dispatch/collections/Dispatches.js.map +1 -1
  48. package/dist/dispatch/types.d.ts +5 -0
  49. package/dist/dispatch/types.d.ts.map +1 -1
  50. package/dist/embedded-write-queue.d.ts +46 -0
  51. package/dist/embedded-write-queue.d.ts.map +1 -0
  52. package/dist/embedded-write-queue.js +66 -0
  53. package/dist/embedded-write-queue.js.map +1 -0
  54. package/dist/embeddings/storage.d.ts +7 -0
  55. package/dist/embeddings/storage.d.ts.map +1 -1
  56. package/dist/embeddings/storage.js +29 -12
  57. package/dist/embeddings/storage.js.map +1 -1
  58. package/dist/errors.d.ts +31 -3
  59. package/dist/errors.d.ts.map +1 -1
  60. package/dist/errors.js +34 -2
  61. package/dist/errors.js.map +1 -1
  62. package/dist/generators/changes-route.d.ts.map +1 -1
  63. package/dist/generators/changes-route.js +6 -3
  64. package/dist/generators/changes-route.js.map +1 -1
  65. package/dist/generators/mcp-runtime-template.d.ts +8 -0
  66. package/dist/generators/mcp-runtime-template.d.ts.map +1 -1
  67. package/dist/generators/mcp-runtime-template.js +38 -4
  68. package/dist/generators/mcp-runtime-template.js.map +1 -1
  69. package/dist/generators/mcp.d.ts +16 -0
  70. package/dist/generators/mcp.d.ts.map +1 -1
  71. package/dist/generators/mcp.js +41 -3
  72. package/dist/generators/mcp.js.map +1 -1
  73. package/dist/generators/rest.d.ts +22 -0
  74. package/dist/generators/rest.d.ts.map +1 -1
  75. package/dist/generators/rest.js +34 -3
  76. package/dist/generators/rest.js.map +1 -1
  77. package/dist/hierarchical.js +1 -1
  78. package/dist/index.d.ts +7 -1
  79. package/dist/index.d.ts.map +1 -1
  80. package/dist/index.js +12 -5
  81. package/dist/interceptors.d.ts +21 -0
  82. package/dist/interceptors.d.ts.map +1 -1
  83. package/dist/interceptors.js +27 -1
  84. package/dist/interceptors.js.map +1 -1
  85. package/dist/manifest/generator.d.ts.map +1 -1
  86. package/dist/manifest/generator.js +4 -7
  87. package/dist/manifest/generator.js.map +1 -1
  88. package/dist/manifest/static-manifest.js +10 -10
  89. package/dist/manifest/static-manifest.js.map +1 -1
  90. package/dist/manifest/store.js +1 -1
  91. package/dist/manifest/store.js.map +1 -1
  92. package/dist/manifest.json +19 -19
  93. package/dist/migrations/differ.d.ts +211 -9
  94. package/dist/migrations/differ.d.ts.map +1 -1
  95. package/dist/migrations/differ.js +613 -50
  96. package/dist/migrations/differ.js.map +1 -1
  97. package/dist/migrations/generator.d.ts +31 -4
  98. package/dist/migrations/generator.d.ts.map +1 -1
  99. package/dist/migrations/generator.js +49 -5
  100. package/dist/migrations/generator.js.map +1 -1
  101. package/dist/migrations/index.d.ts +4 -2
  102. package/dist/migrations/index.d.ts.map +1 -1
  103. package/dist/migrations/index.js +6 -3
  104. package/dist/migrations/minor-units.d.ts +162 -0
  105. package/dist/migrations/minor-units.d.ts.map +1 -0
  106. package/dist/migrations/minor-units.js +381 -0
  107. package/dist/migrations/minor-units.js.map +1 -0
  108. package/dist/migrations/orchestrate.js +35 -6
  109. package/dist/migrations/orchestrate.js.map +1 -1
  110. package/dist/migrations/sqlite-rebuild.d.ts +142 -0
  111. package/dist/migrations/sqlite-rebuild.d.ts.map +1 -0
  112. package/dist/migrations/sqlite-rebuild.js +514 -0
  113. package/dist/migrations/sqlite-rebuild.js.map +1 -0
  114. package/dist/migrations/tracker.d.ts +114 -1
  115. package/dist/migrations/tracker.d.ts.map +1 -1
  116. package/dist/migrations/tracker.js +331 -16
  117. package/dist/migrations/tracker.js.map +1 -1
  118. package/dist/migrations/types.d.ts +19 -4
  119. package/dist/migrations/types.d.ts.map +1 -1
  120. package/dist/migrations.js +6 -3
  121. package/dist/object.d.ts +142 -10
  122. package/dist/object.d.ts.map +1 -1
  123. package/dist/object.js +196 -41
  124. package/dist/object.js.map +1 -1
  125. package/dist/postgres-timeouts.d.ts +240 -0
  126. package/dist/postgres-timeouts.d.ts.map +1 -0
  127. package/dist/postgres-timeouts.js +204 -0
  128. package/dist/postgres-timeouts.js.map +1 -0
  129. package/dist/query-bounds.d.ts +101 -0
  130. package/dist/query-bounds.d.ts.map +1 -0
  131. package/dist/query-bounds.js +177 -0
  132. package/dist/query-bounds.js.map +1 -0
  133. package/dist/registry/class-registration.d.ts.map +1 -1
  134. package/dist/registry/class-registration.js +3 -1
  135. package/dist/registry/class-registration.js.map +1 -1
  136. package/dist/registry/manifest-field-merge.d.ts +12 -0
  137. package/dist/registry/manifest-field-merge.d.ts.map +1 -1
  138. package/dist/registry/manifest-field-merge.js +14 -2
  139. package/dist/registry/manifest-field-merge.js.map +1 -1
  140. package/dist/registry/schema-builder.d.ts +22 -1
  141. package/dist/registry/schema-builder.d.ts.map +1 -1
  142. package/dist/registry/schema-builder.js +205 -165
  143. package/dist/registry/schema-builder.js.map +1 -1
  144. package/dist/registry/types.d.ts +35 -3
  145. package/dist/registry/types.d.ts.map +1 -1
  146. package/dist/registry.d.ts +41 -46
  147. package/dist/registry.d.ts.map +1 -1
  148. package/dist/registry.js +61 -83
  149. package/dist/registry.js.map +1 -1
  150. package/dist/scanner/manifest-generator.d.ts +45 -0
  151. package/dist/scanner/manifest-generator.d.ts.map +1 -1
  152. package/dist/scanner/manifest-generator.js +92 -28
  153. package/dist/scanner/manifest-generator.js.map +1 -1
  154. package/dist/scanner/types.d.ts +5 -0
  155. package/dist/scanner/types.d.ts.map +1 -1
  156. package/dist/scanner/types.js.map +1 -1
  157. package/dist/schema/conflict-target.d.ts +104 -0
  158. package/dist/schema/conflict-target.d.ts.map +1 -0
  159. package/dist/schema/conflict-target.js +129 -0
  160. package/dist/schema/conflict-target.js.map +1 -0
  161. package/dist/schema/ddl/base-strategy.d.ts.map +1 -1
  162. package/dist/schema/ddl/base-strategy.js +2 -2
  163. package/dist/schema/ddl/base-strategy.js.map +1 -1
  164. package/dist/schema/ddl/duckdb-strategy.d.ts.map +1 -1
  165. package/dist/schema/ddl/duckdb-strategy.js +2 -1
  166. package/dist/schema/ddl/duckdb-strategy.js.map +1 -1
  167. package/dist/schema/ddl/postgres-strategy.d.ts.map +1 -1
  168. package/dist/schema/ddl/postgres-strategy.js +12 -1
  169. package/dist/schema/ddl/postgres-strategy.js.map +1 -1
  170. package/dist/schema/generator.d.ts +307 -6
  171. package/dist/schema/generator.d.ts.map +1 -1
  172. package/dist/schema/generator.js +510 -87
  173. package/dist/schema/generator.js.map +1 -1
  174. package/dist/schema/index-utils.d.ts +120 -0
  175. package/dist/schema/index-utils.d.ts.map +1 -1
  176. package/dist/schema/index-utils.js +242 -1
  177. package/dist/schema/index-utils.js.map +1 -1
  178. package/dist/schema/index.d.ts +3 -0
  179. package/dist/schema/index.d.ts.map +1 -1
  180. package/dist/schema/index.js +4 -1
  181. package/dist/schema/live-parity.d.ts +90 -0
  182. package/dist/schema/live-parity.d.ts.map +1 -0
  183. package/dist/schema/live-parity.js +602 -0
  184. package/dist/schema/live-parity.js.map +1 -0
  185. package/dist/schema/manifest-schema.d.ts +121 -0
  186. package/dist/schema/manifest-schema.d.ts.map +1 -0
  187. package/dist/schema/manifest-schema.js +267 -0
  188. package/dist/schema/manifest-schema.js.map +1 -0
  189. package/dist/schema/schema-aggregator.d.ts +24 -10
  190. package/dist/schema/schema-aggregator.d.ts.map +1 -1
  191. package/dist/schema/schema-aggregator.js +35 -90
  192. package/dist/schema/schema-aggregator.js.map +1 -1
  193. package/dist/schema/system-table-shapes.d.ts +65 -0
  194. package/dist/schema/system-table-shapes.d.ts.map +1 -0
  195. package/dist/schema/system-table-shapes.js +187 -0
  196. package/dist/schema/system-table-shapes.js.map +1 -0
  197. package/dist/schema/types.d.ts +103 -4
  198. package/dist/schema/types.d.ts.map +1 -1
  199. package/dist/schema/utils.d.ts +2 -1
  200. package/dist/schema/utils.d.ts.map +1 -1
  201. package/dist/schema/utils.js +5 -3
  202. package/dist/schema/utils.js.map +1 -1
  203. package/dist/schema.js +4 -1
  204. package/dist/smrt-knowledge.json +20 -8
  205. package/dist/sync/apply.d.ts.map +1 -1
  206. package/dist/sync/apply.js +9 -16
  207. package/dist/sync/apply.js.map +1 -1
  208. package/dist/system/compatibility.d.ts +42 -0
  209. package/dist/system/compatibility.d.ts.map +1 -1
  210. package/dist/system/compatibility.js +182 -9
  211. package/dist/system/compatibility.js.map +1 -1
  212. package/dist/system/index.d.ts +1 -0
  213. package/dist/system/index.d.ts.map +1 -1
  214. package/dist/system/index.js +3 -2
  215. package/dist/system/retention.d.ts +237 -0
  216. package/dist/system/retention.d.ts.map +1 -0
  217. package/dist/system/retention.js +497 -0
  218. package/dist/system/retention.js.map +1 -0
  219. package/dist/system/schema.d.ts +100 -15
  220. package/dist/system/schema.d.ts.map +1 -1
  221. package/dist/system/schema.js +81 -45
  222. package/dist/system/schema.js.map +1 -1
  223. package/dist/system/types.d.ts +0 -2
  224. package/dist/system/types.d.ts.map +1 -1
  225. package/dist/testing/database.d.ts.map +1 -1
  226. package/dist/testing/database.js +1 -0
  227. package/dist/testing/database.js.map +1 -1
  228. package/dist/vite-plugin/index.d.ts.map +1 -1
  229. package/dist/vite-plugin/index.js +4 -9
  230. package/dist/vite-plugin/index.js.map +1 -1
  231. package/dist/vite-plugin/sveltekit-generator.d.ts.map +1 -1
  232. package/dist/vite-plugin/sveltekit-generator.js +71 -5
  233. package/dist/vite-plugin/sveltekit-generator.js.map +1 -1
  234. package/dist/vite-plugin/web-collections.d.ts.map +1 -1
  235. package/dist/vite-plugin/web-collections.js +6 -4
  236. package/dist/vite-plugin/web-collections.js.map +1 -1
  237. package/package.json +5 -5
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite-rebuild.js","names":[],"sources":["../../src/migrations/sqlite-rebuild.ts"],"sourcesContent":["/**\n * SQLite table-rebuild migrations (issue #2370)\n *\n * SQLite has no `ALTER TABLE ... ALTER COLUMN ... TYPE`. Before this module\n * every type-bucket change on SQLite (the canonical one being a numeric\n * default edited from `0` to `0.0`, i.e. INTEGER → REAL) turned into an\n * advisory differ comment, which `db:migrate` classifies as\n * *manual intervention* and exits 1 for — forever, because nothing in the\n * toolchain could ever perform the change.\n *\n * This module turns that comment into the executable rebuild SQLite's own\n * documentation prescribes (\"Making Other Kinds Of Table Schema Changes\",\n * lang_altertable.html):\n *\n * 1. `PRAGMA defer_foreign_keys = ON` — defers foreign-key enforcement to\n * COMMIT so the window where the table does not exist cannot raise. It is\n * honored *inside* a transaction (unlike `PRAGMA foreign_keys`, which is a\n * silent no-op there) and resets itself at COMMIT/ROLLBACK.\n * 2. Create a new table under a reserved `_smrt_rebuild_` name carrying the\n * target shape.\n * 3. Copy every row across.\n * 4. Drop the original table.\n * 5. Rename the new table into its place, with `PRAGMA legacy_alter_table`\n * ON for the rename itself (see {@link buildSqliteRebuildStatements}).\n * 6. Recreate the indexes and triggers that died with the original table.\n *\n * The whole plan is a plain statement list, so it is executed by the\n * `MigrationTracker` inside the same transaction as the rest of the batch:\n * a failure anywhere rolls the table back to its original shape and contents.\n *\n * ## The target shape comes from the live DDL, not from the manifest\n *\n * The new table is the *original* `CREATE TABLE` text with only the drifted\n * columns' type tokens replaced. That deliberately preserves everything the\n * manifest does not model or does not own here: columns the manifest has\n * dropped (SMRT is additive — a rebuild must not become an implicit\n * `DROP COLUMN`), table-level constraints, `CHECK`s, collations, and table\n * options such as `WITHOUT ROWID`. The `add_column` changes in the same batch\n * still run their own `ALTER TABLE ... ADD COLUMN`, against the rebuilt table\n * — {@link planSqliteTableRebuilds} hoists the rebuild ahead of them for\n * exactly that reason.\n *\n * ## Why the copy carries no CAST\n *\n * The copy is a plain `INSERT INTO new SELECT ... FROM old`; SQLite applies\n * the destination column's *affinity* on insert, which is exactly the\n * conversion a fresh table would have performed (integer `1` becomes real\n * `1.0` in a REAL column). An explicit `CAST` would be strictly worse: casting\n * a non-numeric TEXT value to REAL/INTEGER silently yields `0`, and casting an\n * ISO timestamp string to SQLite's NUMERIC-affinity `DATETIME` silently yields\n * the leading year. Affinity conversion leaves values it cannot convert\n * untouched instead of destroying them.\n *\n * ## When the rebuild refuses\n *\n * With `PRAGMA foreign_keys` enabled — which the SMRT SQLite adapter is by\n * default — `DROP TABLE` performs an implicit `DELETE FROM` that fires\n * `ON DELETE` actions on children. A child with `ON DELETE CASCADE` therefore\n * loses its rows, and `defer_foreign_keys` does not help: it defers\n * constraint *checks*, not FK *actions*. So when any table declares a foreign\n * key onto the rebuild target and enforcement is on, the plan is refused and\n * the change stays a manual intervention. That includes the target's own\n * self-references, because the staging table copies them and so becomes a\n * child of the table being dropped.\n */\n\nimport { createLogger } from '@happyvertical/logger';\nimport { quoteIdentifier } from '../schema/sql-identifiers.js';\nimport type { SchemaChange, SQLDataType } from '../schema/types.js';\nimport type { DatabaseInterface } from './types.js';\n\nconst logger = createLogger({ level: 'info' });\n\n/**\n * Prefix of the reserved staging table a rebuild creates. `_smrt_`-prefixed\n * names are SMRT system tables, which the differ's dropped-table sweep skips,\n * so a staging table left behind by a non-transactional adapter cannot be\n * mistaken for user data.\n */\nexport const SQLITE_REBUILD_TABLE_PREFIX = '_smrt_rebuild_';\n\n/**\n * The advisory SQL the differ emits for a SQLite type upgrade it cannot\n * perform with an `ALTER TABLE`. `planSqliteTableRebuilds` replaces it with an\n * executable plan; when it cannot, the comment survives and `db:migrate`\n * reports the column as manual drift exactly as it did before #2370.\n */\nexport function sqliteRebuildPlaceholderSql(columnName: string): string {\n return `-- SQLite: Type upgrade for ${quoteIdentifier(columnName)} requires table recreation`;\n}\n\n/**\n * True when `sql` is the differ's \"requires table recreation\" placeholder —\n * i.e. a type upgrade waiting for this module to turn it into a rebuild.\n */\nexport function isSqliteRebuildPlaceholder(sql: string | undefined): boolean {\n return typeof sql === 'string' && sql.includes('requires table recreation');\n}\n\nfunction blockedSql(columnName: string, reason: string): string {\n // Must stay a single line, and must not read as a no-op: the CLI classifies\n // any comment that says \"no change needed\" as noop and drops it silently.\n return `-- SQLite: ${quoteIdentifier(columnName)} requires a table rebuild, blocked: ${reason}`;\n}\n\nfunction coveredSql(columnName: string, rebuiltWith: string): string {\n // Classified `noop` by the CLI (`no change needed`): the sibling change\n // carrying the plan rebuilds the whole table, this column included.\n return `-- SQLite: ${quoteIdentifier(columnName)} is rebuilt with ${quoteIdentifier(rebuiltWith)} in one table rebuild (no change needed)`;\n}\n\n/** A rebuild plan: the ordered statements plus what they touch. */\nexport interface SqliteTableRebuildPlan {\n /** Ordered, executable statements. Run them in one transaction. */\n statements: string[];\n /** Columns copied from the old table into the new one, in table order. */\n copiedColumns: string[];\n /** Names of the indexes and triggers recreated after the swap. */\n recreatedObjects: string[];\n}\n\n/** Live SQLite state a rebuild needs before it can plan anything. */\ninterface SqliteRebuildContext {\n /** `sqlite_master.sql` for the table (SQLite normalizes IF NOT EXISTS away). */\n createTableSql: string;\n /**\n * Column names in `PRAGMA table_info` order. That pragma omits generated\n * columns, which is what the copy wants: they are not insertable and the\n * preserved DDL recomputes them in the new table.\n */\n columns: string[];\n /** Indexes and triggers that will die with the dropped table. */\n objects: { name: string; sql: string }[];\n /** Whether `PRAGMA foreign_keys` enforcement is on for this connection. */\n foreignKeysEnabled: boolean;\n /** Current `PRAGMA legacy_alter_table` value, restored after the rename. */\n legacyAlterTable: boolean;\n /** Other tables declaring a foreign key onto this table. */\n inboundReferences: string[];\n}\n\nexport interface PlanSqliteTableRebuildsOptions {\n db: DatabaseInterface;\n tableName: string;\n /** The table's changes, as produced by the differ's column comparison. */\n changes: SchemaChange[];\n /** Abstract → SQLite type mapping (the engine's DDL strategy `mapType`). */\n mapType: (type: SQLDataType) => string;\n}\n\n/**\n * Replace every \"requires table recreation\" placeholder for `tableName` with\n * one executable rebuild.\n *\n * All of the table's drifted columns are retyped by a *single* rebuild, so the\n * first placeholder carries the plan and the rest become no-ops that reference\n * it. Returns the changes unchanged when there is nothing to rebuild, and\n * leaves the placeholders in place (annotated with the reason) when the\n * rebuild cannot be planned safely — the pre-#2370 manual-intervention\n * behavior.\n *\n * When a plan is produced, the rebuild is hoisted to the front of the table's\n * changes. The plan's staging DDL and copy list are captured from the live\n * schema *at diff time*, so a same-batch `ALTER TABLE ... ADD COLUMN` that ran\n * first would be silently undone by the rebuild — both statements succeed, the\n * transaction commits, and the new column is simply gone. The differ emits\n * changes in manifest field order, which puts an `add_column` first whenever\n * the new field is declared above the retyped one, so the order has to be\n * imposed here rather than assumed. Rebuild first, then add columns to the\n * rebuilt table.\n */\nexport async function planSqliteTableRebuilds(\n options: PlanSqliteTableRebuildsOptions,\n): Promise<SchemaChange[]> {\n const { db, tableName, changes, mapType } = options;\n\n const pending = changes.filter(\n (change) =>\n change.type === 'type_upgrade' &&\n change.name &&\n change.column &&\n isSqliteRebuildPlaceholder(change.sql),\n );\n if (pending.length === 0) {\n return changes;\n }\n\n const block = (reason: string): SchemaChange[] => {\n logger.debug(\n `[SQLiteRebuild] Cannot rebuild ${tableName}: ${reason}; leaving ${pending.length} type upgrade(s) as manual drift`,\n );\n return changes.map((change) =>\n pending.includes(change)\n ? { ...change, sql: blockedSql(change.name as string, reason) }\n : change,\n );\n };\n\n let context: SqliteRebuildContext;\n try {\n context = await readSqliteRebuildContext(db, tableName);\n } catch (error) {\n return block(\n `live schema introspection failed (${error instanceof Error ? error.message : String(error)})`,\n );\n }\n\n if (!context.createTableSql) {\n return block('no CREATE TABLE statement found in sqlite_master');\n }\n if (context.columns.length === 0) {\n return block('PRAGMA table_info returned no columns');\n }\n if (context.foreignKeysEnabled && context.inboundReferences.length > 0) {\n return block(\n `PRAGMA foreign_keys is ON and ${context.inboundReferences\n .map((name) => `\"${name}\"`)\n .join(\n ', ',\n )} declare a foreign key onto this table, so DROP TABLE would fire their ON DELETE actions`,\n );\n }\n\n const columnTypes = new Map<string, string>();\n for (const change of pending) {\n columnTypes.set(\n change.name as string,\n mapType((change.column as { type: SQLDataType }).type),\n );\n }\n\n const plan = buildSqliteRebuildStatements({\n tableName,\n createTableSql: context.createTableSql,\n columnTypes,\n columns: context.columns,\n objects: context.objects,\n legacyAlterTable: context.legacyAlterTable,\n });\n\n if (!plan) {\n return block(\n 'the live CREATE TABLE statement could not be rewritten for the target column types',\n );\n }\n\n const [primary, ...covered] = pending;\n const rebuilt = changes.map((change) => {\n if (change === primary) {\n return {\n ...change,\n // `sql` stays a real statement so the CLI classifies this upgrade as\n // executable; every consumer that actually runs the change prefers\n // `sqlStatements`.\n sql: plan.statements[0],\n sqlStatements: plan.statements,\n };\n }\n if (covered.includes(change)) {\n const { sqlStatements: _dropped, ...rest } = change;\n return {\n ...rest,\n sql: coveredSql(change.name as string, primary.name as string),\n };\n }\n return change;\n });\n\n // Hoist the rebuild ahead of the table's other column changes, keeping both\n // groups in their original relative order. Consumers execute `diff.changes`\n // in order, and the plan was built from the pre-batch table shape.\n const rebuildPositions = new Set(\n pending.map((change) => changes.indexOf(change)),\n );\n return [\n ...rebuilt.filter((_, index) => rebuildPositions.has(index)),\n ...rebuilt.filter((_, index) => !rebuildPositions.has(index)),\n ];\n}\n\n/**\n * Read everything the rebuild needs from the live database.\n *\n * Every query is SQLite-only (`sqlite_master`, `PRAGMA`), and the caller only\n * reaches this for an engine already detected as SQLite.\n */\nasync function readSqliteRebuildContext(\n db: DatabaseInterface,\n tableName: string,\n): Promise<SqliteRebuildContext> {\n const tableRows = await db.query(\n `SELECT sql FROM sqlite_master WHERE type = 'table' AND name = ?`,\n tableName,\n );\n const createTableSql = readString(\n (tableRows.rows[0] as { sql?: unknown } | undefined)?.sql,\n );\n\n const columnRows = await db.query(\n `PRAGMA table_info(${quoteIdentifier(tableName)})`,\n );\n const columns = columnRows.rows\n .map((row) => readString((row as { name?: unknown }).name))\n .filter((name): name is string => Boolean(name));\n\n // `sql IS NULL` marks the implicit indexes SQLite creates for inline\n // PRIMARY KEY / UNIQUE constraints; those are carried by the CREATE TABLE\n // text and must not be replayed separately.\n const objectRows = await db.query(\n `SELECT name, sql FROM sqlite_master\n WHERE tbl_name = ? AND sql IS NOT NULL\n AND type IN ('index', 'trigger') AND name NOT LIKE 'sqlite_%'`,\n tableName,\n );\n const objects: { name: string; sql: string }[] = [];\n for (const row of objectRows.rows as { name?: unknown; sql?: unknown }[]) {\n const name = readString(row.name);\n const sql = readString(row.sql);\n if (name && sql) {\n objects.push({ name, sql });\n }\n }\n\n const foreignKeysEnabled = readPragmaFlag(\n await db.query('PRAGMA foreign_keys'),\n );\n const legacyAlterTable = readPragmaFlag(\n await db.query('PRAGMA legacy_alter_table'),\n );\n\n const inboundReferences = foreignKeysEnabled\n ? await readInboundForeignKeys(db, tableName)\n : [];\n\n return {\n createTableSql,\n columns,\n objects,\n foreignKeysEnabled,\n legacyAlterTable,\n inboundReferences,\n };\n}\n\n/**\n * Names of tables that declare a foreign key onto `tableName`.\n *\n * The table itself counts. A self-reference is copied verbatim into the\n * staging table, which therefore becomes a real child of the live table, and\n * `DROP TABLE` then cascades the *staged* rows away — verified: a two-row\n * self-referencing table finishes the rebuild holding one row.\n */\nasync function readInboundForeignKeys(\n db: DatabaseInterface,\n tableName: string,\n): Promise<string[]> {\n const tables = await db.query(\n `SELECT name FROM sqlite_master\n WHERE type = 'table' AND name NOT LIKE 'sqlite_%'`,\n );\n\n const referencing: string[] = [];\n const target = tableName.toLowerCase();\n for (const row of tables.rows as { name?: unknown }[]) {\n const name = readString(row.name);\n if (!name) continue;\n const fks = await db.query(\n `PRAGMA foreign_key_list(${quoteIdentifier(name)})`,\n );\n const referencesTarget = (fks.rows as { table?: unknown }[]).some(\n (fk) => readString(fk.table).toLowerCase() === target,\n );\n if (referencesTarget) {\n referencing.push(name);\n }\n }\n\n return referencing;\n}\n\nfunction readString(value: unknown): string {\n return typeof value === 'string' ? value : '';\n}\n\n/** Read a single-row/single-column PRAGMA result as a boolean. */\nfunction readPragmaFlag(result: { rows: Record<string, unknown>[] }): boolean {\n const row = result.rows[0];\n if (!row) return false;\n const value = Object.values(row)[0];\n if (typeof value === 'number') return value !== 0;\n if (typeof value === 'boolean') return value;\n if (typeof value === 'string') return value !== '0' && value !== '';\n return false;\n}\n\nexport interface BuildSqliteRebuildStatementsInput {\n tableName: string;\n /** The live `sqlite_master.sql` CREATE TABLE text. */\n createTableSql: string;\n /** Column name → target SQLite type, for the columns being retyped. */\n columnTypes: Map<string, string>;\n /** Every column of the live table, in `PRAGMA table_info` order. */\n columns: string[];\n /** Indexes and triggers to replay after the swap. */\n objects: { name: string; sql: string }[];\n /** Current `PRAGMA legacy_alter_table` value, restored after the rename. */\n legacyAlterTable: boolean;\n}\n\n/**\n * Build the ordered statement list for one table rebuild.\n *\n * Returns `null` when the live `CREATE TABLE` text cannot be rewritten (an\n * unparsable statement, or a requested column that is not in it) — the caller\n * then leaves the change as manual drift rather than emitting SQL that would\n * \"succeed\" without fixing the column, which would re-diff forever.\n *\n * `PRAGMA legacy_alter_table` brackets the rename because SQLite ≥ 3.25\n * re-parses the whole schema on `ALTER TABLE ... RENAME`: a view left\n * referencing the just-dropped table makes the rename fail outright\n * (\"error in view … no such table\"). Legacy mode renames the table without\n * that reference rewriting, which is exactly what a rebuild wants — the name\n * the views refer to is about to exist again. It is restored to its previous\n * value immediately afterwards; a rolled-back batch leaves it set, which is\n * inert for SMRT (nothing else in the toolchain renames a table) but is\n * documented in `packages/core/agents/schema-paths.md`.\n */\nexport function buildSqliteRebuildStatements(\n input: BuildSqliteRebuildStatementsInput,\n): SqliteTableRebuildPlan | null {\n const {\n tableName,\n createTableSql,\n columnTypes,\n columns,\n objects,\n legacyAlterTable,\n } = input;\n\n const stagingTable = `${SQLITE_REBUILD_TABLE_PREFIX}${tableName}`;\n const createStaging = rewriteSqliteCreateTable(createTableSql, {\n tableName: stagingTable,\n columnTypes,\n });\n if (!createStaging) {\n return null;\n }\n\n const quotedTable = quoteIdentifier(tableName);\n const quotedStaging = quoteIdentifier(stagingTable);\n const columnList = columns.map((name) => quoteIdentifier(name)).join(', ');\n\n const statements = [\n // Deferred FK enforcement survives the window where the table is absent.\n // Unlike `PRAGMA foreign_keys`, this one is honored inside a transaction\n // and resets itself at COMMIT/ROLLBACK.\n 'PRAGMA defer_foreign_keys = ON',\n // Idempotent for a retry after a partially applied non-transactional run.\n `DROP TABLE IF EXISTS ${quotedStaging}`,\n createStaging,\n `INSERT INTO ${quotedStaging} (${columnList}) SELECT ${columnList} FROM ${quotedTable}`,\n `DROP TABLE ${quotedTable}`,\n 'PRAGMA legacy_alter_table = ON',\n `ALTER TABLE ${quotedStaging} RENAME TO ${quotedTable}`,\n `PRAGMA legacy_alter_table = ${legacyAlterTable ? 'ON' : 'OFF'}`,\n // The indexes and triggers went down with the dropped table. Their\n // original text still names the table correctly (it was renamed back), so\n // replaying it verbatim preserves partial predicates, expression indexes,\n // and trigger bodies that a manifest-driven regeneration would flatten.\n ...objects.map((object) => object.sql),\n ];\n\n return {\n statements,\n copiedColumns: [...columns],\n recreatedObjects: objects.map((object) => object.name),\n };\n}\n\n/**\n * Rewrite a live `CREATE TABLE` statement into the rebuild's target shape:\n * the same body under a new table name, with the declared type of each column\n * in `columnTypes` replaced.\n *\n * Everything else is preserved verbatim — other columns, their defaults,\n * `NOT NULL`/`PRIMARY KEY`/`CHECK`/`COLLATE` clauses, table-level\n * constraints, and trailing table options (`WITHOUT ROWID`, `STRICT`).\n *\n * Returns `null` if the statement cannot be parsed or if any requested column\n * is not present in it.\n */\nexport function rewriteSqliteCreateTable(\n createTableSql: string,\n target: { tableName: string; columnTypes: Map<string, string> },\n): string | null {\n const parsed = parseCreateTableBody(createTableSql);\n if (!parsed) {\n return null;\n }\n\n const wanted = new Map<string, string>();\n for (const [name, type] of target.columnTypes) {\n wanted.set(name.toLowerCase(), type);\n }\n\n const rewritten: string[] = [];\n for (const item of parsed.items) {\n const columnName = readColumnDefinitionName(item);\n const newType = columnName ? wanted.get(columnName.toLowerCase()) : null;\n if (!columnName || !newType) {\n rewritten.push(item);\n continue;\n }\n const replaced = replaceColumnType(item, newType);\n if (!replaced) {\n return null;\n }\n rewritten.push(replaced);\n wanted.delete(columnName.toLowerCase());\n }\n\n if (wanted.size > 0) {\n // A column the differ wants retyped is not in the live DDL. Rebuilding\n // would not fix the drift, so refuse instead of emitting a no-op plan.\n return null;\n }\n\n const tail = parsed.tail ? ` ${parsed.tail}` : '';\n return `CREATE TABLE ${quoteIdentifier(target.tableName)} (\\n ${rewritten.join(\n ',\\n ',\n )}\\n)${tail}`;\n}\n\ninterface ParsedCreateTable {\n /** Top-level, comma-separated column and constraint definitions. */\n items: string[];\n /** Table options after the closing paren (`WITHOUT ROWID`, `STRICT`). */\n tail: string;\n}\n\n/**\n * Split a `CREATE TABLE` statement into its top-level definition items plus\n * any trailing table options, honoring SQLite's quoting (`'…'`, `\"…\"`,\n * `` `…` ``, `[…]`) and comments so a quoted comma or paren cannot split the\n * body.\n *\n * @internal exported for testing\n */\nexport function parseCreateTableBody(sql: string): ParsedCreateTable | null {\n let index = 0;\n let open = -1;\n while (index < sql.length) {\n const skipped = skipQuotedOrComment(sql, index);\n if (skipped !== null) {\n index = skipped;\n continue;\n }\n if (sql[index] === '(') {\n open = index;\n break;\n }\n index++;\n }\n if (open === -1) {\n return null;\n }\n\n const items: string[] = [];\n let depth = 1;\n let itemStart = open + 1;\n let close = -1;\n index = open + 1;\n while (index < sql.length) {\n const skipped = skipQuotedOrComment(sql, index);\n if (skipped !== null) {\n index = skipped;\n continue;\n }\n const char = sql[index];\n if (char === '(') {\n depth++;\n } else if (char === ')') {\n depth--;\n if (depth === 0) {\n close = index;\n items.push(sql.slice(itemStart, index));\n break;\n }\n } else if (char === ',' && depth === 1) {\n items.push(sql.slice(itemStart, index));\n itemStart = index + 1;\n }\n index++;\n }\n\n if (close === -1) {\n return null;\n }\n\n const trimmed = items.map((item) => item.trim()).filter(Boolean);\n if (trimmed.length === 0) {\n return null;\n }\n\n return {\n items: trimmed,\n tail: sql\n .slice(close + 1)\n .trim()\n .replace(/;+$/, '')\n .trim(),\n };\n}\n\n/**\n * If `sql[index]` opens a quoted identifier, string literal, or comment,\n * return the index just past its end. Otherwise return `null`.\n */\nfunction skipQuotedOrComment(sql: string, index: number): number | null {\n const char = sql[index];\n\n if (char === \"'\" || char === '\"' || char === '`') {\n let cursor = index + 1;\n while (cursor < sql.length) {\n if (sql[cursor] === char) {\n // A doubled delimiter is an escaped one, not the end of the token.\n if (sql[cursor + 1] === char) {\n cursor += 2;\n continue;\n }\n return cursor + 1;\n }\n cursor++;\n }\n return sql.length;\n }\n\n if (char === '[') {\n const end = sql.indexOf(']', index + 1);\n return end === -1 ? sql.length : end + 1;\n }\n\n if (char === '-' && sql[index + 1] === '-') {\n const end = sql.indexOf('\\n', index);\n return end === -1 ? sql.length : end + 1;\n }\n\n if (char === '/' && sql[index + 1] === '*') {\n const end = sql.indexOf('*/', index + 2);\n return end === -1 ? sql.length : end + 2;\n }\n\n return null;\n}\n\n/**\n * Keywords that start a *table*-level constraint, i.e. a body item that is not\n * a column definition.\n */\nconst TABLE_CONSTRAINT_KEYWORDS = new Set([\n 'constraint',\n 'primary',\n 'unique',\n 'check',\n 'foreign',\n]);\n\n/**\n * Keywords that end a column's type name and start its constraint list.\n */\nconst COLUMN_CONSTRAINT_KEYWORDS = new Set([\n 'constraint',\n 'primary',\n 'not',\n 'null',\n 'unique',\n 'check',\n 'default',\n 'collate',\n 'references',\n 'generated',\n 'as',\n]);\n\ninterface Identifier {\n name: string;\n end: number;\n}\n\n/** Read the leading identifier of a body item (quoted or bare). */\nfunction readLeadingIdentifier(item: string): Identifier | null {\n let index = 0;\n while (index < item.length && /\\s/.test(item[index])) index++;\n if (index >= item.length) return null;\n\n const char = item[index];\n if (char === '\"' || char === '`' || char === '[') {\n const end = skipQuotedOrComment(item, index);\n if (end === null) return null;\n const raw = item.slice(index + 1, end - 1);\n // `[…]` has no escape form; `\"…\"` / `` `…` `` double the delimiter.\n return {\n name: char === '[' ? raw : raw.split(char + char).join(char),\n end,\n };\n }\n\n const match = /^[A-Za-z_][\\w$]*/.exec(item.slice(index));\n if (!match) return null;\n return { name: match[0], end: index + match[0].length };\n}\n\n/**\n * The column name of a body item, or `null` when the item is a table-level\n * constraint rather than a column definition.\n *\n * @internal exported for testing\n */\nexport function readColumnDefinitionName(item: string): string | null {\n const identifier = readLeadingIdentifier(item);\n if (!identifier) return null;\n\n const isQuoted = /^\\s*[\"`[]/.test(item);\n if (\n !isQuoted &&\n TABLE_CONSTRAINT_KEYWORDS.has(identifier.name.toLowerCase())\n ) {\n return null;\n }\n return identifier.name;\n}\n\n/**\n * Replace the declared type of a column definition, keeping its name and every\n * constraint that follows. A column declared without a type gets one inserted.\n *\n * @internal exported for testing\n */\nexport function replaceColumnType(\n item: string,\n newType: string,\n): string | null {\n const identifier = readLeadingIdentifier(item);\n if (!identifier) return null;\n\n const head = item.slice(0, identifier.end);\n let index = identifier.end;\n\n // The type name is one or more bare words followed by an optional\n // `(size[, size])` — everything before the first column-constraint keyword.\n let typeEnd = index;\n while (index < item.length) {\n while (index < item.length && /\\s/.test(item[index])) index++;\n const match = /^[A-Za-z_][\\w$]*/.exec(item.slice(index));\n if (!match || COLUMN_CONSTRAINT_KEYWORDS.has(match[0].toLowerCase())) {\n break;\n }\n index += match[0].length;\n typeEnd = index;\n }\n\n // Optional parenthesized type argument, e.g. VARCHAR(255).\n if (typeEnd > identifier.end) {\n let cursor = typeEnd;\n while (cursor < item.length && /\\s/.test(item[cursor])) cursor++;\n if (item[cursor] === '(') {\n let depth = 0;\n while (cursor < item.length) {\n const skipped = skipQuotedOrComment(item, cursor);\n if (skipped !== null) {\n cursor = skipped;\n continue;\n }\n if (item[cursor] === '(') depth++;\n else if (item[cursor] === ')') {\n depth--;\n if (depth === 0) {\n typeEnd = cursor + 1;\n break;\n }\n }\n cursor++;\n }\n }\n }\n\n const rest = item.slice(typeEnd);\n const separator = rest.length === 0 || /^\\s/.test(rest) ? '' : ' ';\n return `${head} ${newType}${separator}${rest}`;\n}\n"],"mappings":"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"}
@@ -1,6 +1,36 @@
1
+ import { parsePostgresTimeoutMs } from '../postgres-timeouts.js';
1
2
  import { DatabaseEngine } from '../schema/ddl/types.js';
2
3
  import { DriftReport, MigrationDefinition, MigrationResult, MigrationStatus, SchemaMigrationRecord } from '../schema/types.js';
3
4
  import { ApplyMigrationsOptions, MigrationTrackerOptions, RollbackOptions } from './types.js';
5
+ /**
6
+ * Extract the index name from a `CREATE [UNIQUE] INDEX …` statement.
7
+ *
8
+ * Returns the unquoted identifier, or `null` when the statement is not a
9
+ * CREATE INDEX (a drop, a reindex, or unrelated DDL).
10
+ *
11
+ * Exported for unit testing and because the CLI's index rollout needs the
12
+ * same correlation to explain what it repaired.
13
+ */
14
+ export declare function extractCreatedIndexName(sql: string): string | null;
15
+ /**
16
+ * Parse a PostgreSQL timeout string into milliseconds.
17
+ *
18
+ * The implementation lives in `src/postgres-timeouts.ts`, the leaf module the
19
+ * runtime pool bounds are built from (#2377), so `migrations.postgres.*` and a
20
+ * runtime `timeouts` config are parsed by literally the same function rather
21
+ * than by two copies that can drift. It is re-exported here — and from
22
+ * `./index.ts` — because `@happyvertical/smrt-core/migrations` is the public
23
+ * subpath `db:migrate` reads it through.
24
+ */
25
+ export { parsePostgresTimeoutMs };
26
+ /**
27
+ * Statements split out of the atomic batch for PostgreSQL concurrent-index
28
+ * mode, keyed by migration definition id.
29
+ */
30
+ type ConcurrentIndexPlan = Map<string, {
31
+ regular: string[];
32
+ concurrent: string[];
33
+ }>;
4
34
  /**
5
35
  * MigrationTracker class
6
36
  *
@@ -26,6 +56,15 @@ export declare class MigrationTracker {
26
56
  */
27
57
  private initializePromise;
28
58
  private currentBatch;
59
+ /**
60
+ * Statements deferred out of the current atomic batch by PostgreSQL
61
+ * concurrent-index mode. The parent tracker sets this on the
62
+ * transaction-scoped tracker before phase 1 so `apply()` executes only the
63
+ * transaction-safe statements and leaves the migration record in `running`;
64
+ * the parent finalizes those records after the transaction commits and the
65
+ * `CONCURRENTLY` DDL has run. `null` on every ordinary path.
66
+ */
67
+ private concurrentIndexPlan;
29
68
  constructor(options: MigrationTrackerOptions);
30
69
  /**
31
70
  * Detect the database engine. Honors an explicit `engineHint` (passed via
@@ -73,9 +112,71 @@ export declare class MigrationTracker {
73
112
  */
74
113
  apply(definition: MigrationDefinition, options?: ApplyMigrationsOptions): Promise<MigrationResult>;
75
114
  /**
76
- * Apply multiple migrations in order
115
+ * Apply multiple migrations in order.
116
+ *
117
+ * On PostgreSQL the atomic path always bounds itself with
118
+ * `SET LOCAL lock_timeout` / `SET LOCAL statement_timeout` so a migration
119
+ * that queues behind a long-running writer fails fast and rolls back
120
+ * instead of stalling every writer behind its already-held locks
121
+ * (issue #2362).
122
+ *
123
+ * `options.postgresSafe` additionally enables **concurrent-index mode**:
124
+ * non-index DDL still runs in the one atomic transaction, then every index
125
+ * statement runs `CONCURRENTLY` on a pinned session after that transaction
126
+ * commits. That mode trades atomicity for availability — a failure part way
127
+ * through the index phase leaves the committed non-index DDL in place, and
128
+ * the unfinished index migrations are recorded `failed` so the next run
129
+ * retries them, resuming at the index phase rather than re-running the
130
+ * non-index statements that already committed.
77
131
  */
78
132
  applyAll(definitions: MigrationDefinition[], options?: ApplyMigrationsOptions): Promise<MigrationResult[]>;
133
+ /**
134
+ * Phase 2 of PostgreSQL concurrent-index mode.
135
+ *
136
+ * Runs every deferred index statement on one pinned session, outside the
137
+ * committed transaction, bounded by session `lock_timeout` /
138
+ * `statement_timeout`. INVALID indexes left behind by an earlier failed
139
+ * `CREATE INDEX CONCURRENTLY` are dropped first so the retry rebuilds them
140
+ * rather than skipping over a stump that reads as present.
141
+ *
142
+ * On failure the batch stops: the failing migration and every migration it
143
+ * did not reach are recorded `failed`, which the CLI's reconciling
144
+ * `db:migrate` retries on the next run.
145
+ */
146
+ private applyDeferredConcurrentIndexes;
147
+ /**
148
+ * Pin one connection for the concurrent-index phase.
149
+ *
150
+ * PostgreSQL pools hand each top-level `query` an arbitrary connection, so
151
+ * a `SET lock_timeout` issued through the pool may not apply to the DDL
152
+ * that follows. Adapters that expose `acquireSession` give us a pinned
153
+ * connection; anything else (SQLite, DuckDB, test doubles) is
154
+ * single-connection anyway and falls back to the plain interface.
155
+ */
156
+ private acquireMigrationSession;
157
+ /**
158
+ * Read the names of INVALID indexes that an unqualified index name in this
159
+ * session would actually resolve to.
160
+ *
161
+ * `pg_indexes` (what the SQL adapter's introspection reads) lists an
162
+ * INVALID index exactly like a healthy one, so the schema differ believes a
163
+ * failed `CREATE INDEX CONCURRENTLY` succeeded. `pg_index.indisvalid` is the
164
+ * authoritative flag.
165
+ *
166
+ * Scoped to `current_schemas(false)` — the session's search path — because
167
+ * migration DDL names indexes unqualified, and so does the
168
+ * `DROP INDEX CONCURRENTLY IF EXISTS "<name>"` repair. Scanning every schema
169
+ * would let an unrelated invalid index of the same name in another schema
170
+ * trigger a drop that then resolves to a *different* object. Where the same
171
+ * name appears in several search-path schemas, the earliest on the path wins
172
+ * — the same rule PostgreSQL uses to resolve the name.
173
+ *
174
+ * A role without catalog access degrades to "no known invalid indexes"
175
+ * rather than aborting the migration.
176
+ */
177
+ private readInvalidIndexNames;
178
+ private recordConcurrentIndexSuccess;
179
+ private recordConcurrentIndexFailure;
79
180
  /**
80
181
  * Rollback a migration
81
182
  */
@@ -110,6 +211,18 @@ export declare class MigrationTracker {
110
211
  */
111
212
  private executePostgresStatements;
112
213
  }
214
+ /**
215
+ * Build the PostgreSQL concurrent-index plan for an atomic batch.
216
+ *
217
+ * Returns one entry per migration definition that has at least one statement
218
+ * which must leave the transaction, mapping it to the transaction-safe
219
+ * statements (phase 1) and the `CONCURRENTLY` statements (phase 2).
220
+ * Definitions with nothing to defer are omitted so the caller can treat
221
+ * `plan.has(id)` as "this migration finishes in phase 2".
222
+ *
223
+ * Exported for unit testing.
224
+ */
225
+ export declare function buildConcurrentIndexPlan(definitions: MigrationDefinition[], useConcurrentIndexes: boolean): ConcurrentIndexPlan;
113
226
  /**
114
227
  * Split a batch of SQL statements into a transaction-safe set and a
115
228
  * concurrent set, applying `--postgres-safe` rewriting if requested.
@@ -1 +1 @@
1
- {"version":3,"file":"tracker.d.ts","sourceRoot":"","sources":["../../src/migrations/tracker.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAWH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,KAAK,EACV,WAAW,EACX,mBAAmB,EACnB,eAAe,EACf,eAAe,EACf,qBAAqB,EACtB,MAAM,oBAAoB,CAAC;AAO5B,OAAO,KAAK,EACV,sBAAsB,EAEtB,uBAAuB,EACvB,eAAe,EAChB,MAAM,YAAY,CAAC;AAkEpB;;;;;;;;;GASG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,EAAE,CAAoB;IAC9B,OAAO,CAAC,OAAO,CAA+D;IAC9E,OAAO,CAAC,UAAU,CAAC,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAiB;IACjC;;;;;;;OAOG;IACH,OAAO,CAAC,iBAAiB,CAA8B;IACvD,OAAO,CAAC,YAAY,CAAuB;gBAE/B,OAAO,EAAE,uBAAuB;IAa5C;;;;;;OAMG;IACH,OAAO,CAAC,cAAc;IAQtB;;OAEG;IACH,SAAS,IAAI,cAAc;IAI3B;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;YAUnB,gBAAgB;IAiB9B;;OAEG;IACG,oBAAoB,IAAI,OAAO,CAAC,qBAAqB,EAAE,CAAC;IAe9D;;OAEG;IACG,oBAAoB,CACxB,WAAW,EAAE,mBAAmB,EAAE,GACjC,OAAO,CAAC,mBAAmB,EAAE,CAAC;IAMjC;;OAEG;IACG,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAWtD;;OAEG;IACG,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC;IAmBvE;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC;IAWrC;;OAEG;IACG,WAAW,CACf,WAAW,EAAE,mBAAmB,EAAE,GACjC,OAAO,CAAC,WAAW,EAAE,CAAC;IAkDzB;;OAEG;IACG,KAAK,CACT,UAAU,EAAE,mBAAmB,EAC/B,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,eAAe,CAAC;IA6L3B;;OAEG;IACG,QAAQ,CACZ,WAAW,EAAE,mBAAmB,EAAE,EAClC,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,eAAe,EAAE,CAAC;IAsF7B;;OAEG;IACG,QAAQ,CACZ,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,mBAAmB,EAC/B,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,eAAe,CAAC;IAiF3B;;OAEG;IACG,UAAU,CACd,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,IAAI,CAAC;QAAC,MAAM,CAAC,EAAE,eAAe,CAAA;KAAO,GACvE,OAAO,CAAC,qBAAqB,EAAE,CAAC;IAiCnC;;OAEG;YACW,iBAAiB;IAW/B;;OAEG;YACW,sBAAsB;IAepC;;;;;;;;;;;OAWG;YACW,yBAAyB;CAqCxC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,MAAM,EAAE,EACpB,oBAAoB,EAAE,OAAO,GAC5B;IAAE,UAAU,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAgC7C"}
1
+ {"version":3,"file":"tracker.d.ts","sourceRoot":"","sources":["../../src/migrations/tracker.ts"],"names":[],"mappings":"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"}