@hot-updater/server 0.33.1 → 0.34.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 (198) hide show
  1. package/dist/_virtual/_rolldown/runtime.cjs +0 -2
  2. package/dist/adapters/drizzle.cjs +195 -2
  3. package/dist/adapters/drizzle.d.cts +7 -4
  4. package/dist/adapters/drizzle.d.mts +7 -4
  5. package/dist/adapters/drizzle.mjs +194 -2
  6. package/dist/adapters/drizzleLazyDB.cjs +53 -0
  7. package/dist/adapters/drizzleLazyDB.mjs +53 -0
  8. package/dist/adapters/kysely.cjs +154 -3
  9. package/dist/adapters/kysely.d.cts +18 -10
  10. package/dist/adapters/kysely.d.mts +18 -10
  11. package/dist/adapters/kysely.mjs +153 -3
  12. package/dist/adapters/mongodb.cjs +183 -2
  13. package/dist/adapters/mongodb.d.cts +5 -4
  14. package/dist/adapters/mongodb.d.mts +5 -4
  15. package/dist/adapters/mongodb.mjs +183 -2
  16. package/dist/adapters/prisma.cjs +200 -2
  17. package/dist/adapters/prisma.d.cts +9 -4
  18. package/dist/adapters/prisma.d.mts +9 -4
  19. package/dist/adapters/prisma.mjs +199 -2
  20. package/dist/db/bundleRows.cjs +82 -0
  21. package/dist/db/bundleRows.d.cts +33 -0
  22. package/dist/db/bundleRows.d.mts +33 -0
  23. package/dist/db/bundleRows.mjs +79 -0
  24. package/dist/db/fixedMigrator.cjs +136 -0
  25. package/dist/db/fixedMigrator.mjs +135 -0
  26. package/dist/db/index.cjs +17 -15
  27. package/dist/db/index.d.cts +3 -3
  28. package/dist/db/index.d.mts +3 -3
  29. package/dist/db/index.mjs +17 -15
  30. package/dist/db/pluginCore.cjs +13 -5
  31. package/dist/db/pluginCore.mjs +13 -5
  32. package/dist/db/schema/mongodb.cjs +17 -0
  33. package/dist/db/schema/mongodb.mjs +17 -0
  34. package/dist/db/schema/registry.cjs +23 -0
  35. package/dist/db/schema/registry.mjs +18 -0
  36. package/dist/db/schema/sql.cjs +84 -0
  37. package/dist/db/schema/sql.mjs +78 -0
  38. package/dist/db/schema/sqlMigrations.cjs +74 -0
  39. package/dist/db/schema/sqlMigrations.mjs +73 -0
  40. package/dist/db/schema/sqlOperations.cjs +27 -0
  41. package/dist/db/schema/sqlOperations.mjs +26 -0
  42. package/dist/db/schemaEnhancements.cjs +1 -152
  43. package/dist/db/schemaEnhancements.mjs +1 -149
  44. package/dist/db/schemaGenerators.cjs +222 -0
  45. package/dist/db/schemaGenerators.mjs +220 -0
  46. package/dist/db/schemaReadiness.cjs +23 -0
  47. package/dist/db/schemaReadiness.d.cts +8 -0
  48. package/dist/db/schemaReadiness.d.mts +8 -0
  49. package/dist/db/schemaReadiness.mjs +22 -0
  50. package/dist/db/types.cjs +10 -2
  51. package/dist/db/types.d.cts +58 -14
  52. package/dist/db/types.d.mts +58 -14
  53. package/dist/db/types.mjs +9 -1
  54. package/dist/index.cjs +2 -2
  55. package/dist/index.d.cts +3 -2
  56. package/dist/index.d.mts +3 -2
  57. package/dist/index.mjs +2 -2
  58. package/dist/{packages/server/package.cjs → package.cjs} +1 -1
  59. package/dist/{packages/server/package.mjs → package.mjs} +1 -1
  60. package/dist/runtime.cjs +9 -2
  61. package/dist/runtime.mjs +9 -2
  62. package/dist/schema/dsl.cjs +86 -0
  63. package/dist/schema/dsl.mjs +73 -0
  64. package/dist/schema/index.cjs +13 -0
  65. package/dist/schema/index.mjs +13 -0
  66. package/dist/schema/settings.cjs +9 -0
  67. package/dist/schema/settings.mjs +9 -0
  68. package/dist/schema/types.cjs +6 -0
  69. package/dist/schema/types.mjs +5 -0
  70. package/dist/schema/v0_21_0.cjs +33 -18
  71. package/dist/schema/v0_21_0.mjs +32 -18
  72. package/dist/schema/v0_29_0.cjs +40 -20
  73. package/dist/schema/v0_29_0.mjs +39 -20
  74. package/dist/schema/v0_31_0.cjs +77 -43
  75. package/dist/schema/v0_31_0.mjs +75 -43
  76. package/dist/version.cjs +1 -1
  77. package/dist/version.mjs +1 -1
  78. package/package.json +30 -16
  79. package/src/adapters/drizzle.spec.ts +75 -0
  80. package/src/adapters/drizzle.ts +328 -12
  81. package/src/adapters/drizzleLazyDB.ts +151 -0
  82. package/src/adapters/kysely.spec.ts +107 -0
  83. package/src/adapters/kysely.ts +349 -14
  84. package/src/adapters/mongodb.ts +298 -15
  85. package/src/adapters/prisma.ts +337 -12
  86. package/src/db/bundleRows.ts +140 -0
  87. package/src/db/fixedMigrator.spec.ts +89 -0
  88. package/src/db/fixedMigrator.ts +288 -0
  89. package/src/db/hotUpdaterSchema.ts +6 -0
  90. package/src/db/index.spec.ts +976 -13
  91. package/src/db/index.ts +37 -36
  92. package/src/db/pluginCore.spec.ts +17 -11
  93. package/src/db/pluginCore.ts +15 -6
  94. package/src/db/schema/definitions.ts +1 -0
  95. package/src/db/schema/mongodb.ts +26 -0
  96. package/src/db/schema/registry.ts +55 -0
  97. package/src/db/schema/sql.ts +200 -0
  98. package/src/db/schema/sqlMigrations.ts +219 -0
  99. package/src/db/schema/sqlOperations.ts +62 -0
  100. package/src/db/schema/types.ts +1 -0
  101. package/src/db/schemaEnhancements.ts +0 -405
  102. package/src/db/schemaGenerators.ts +382 -0
  103. package/src/db/schemaReadiness.ts +33 -0
  104. package/src/db/types.ts +69 -25
  105. package/src/runtime.spec.ts +70 -0
  106. package/src/runtime.ts +14 -2
  107. package/src/schema/dsl-all-versions.spec.ts +26 -0
  108. package/src/schema/dsl.ts +148 -0
  109. package/src/schema/index.ts +16 -0
  110. package/src/schema/settings.ts +15 -0
  111. package/src/schema/types.ts +73 -0
  112. package/src/schema/v0_21_0.ts +48 -18
  113. package/src/schema/v0_29_0.ts +58 -22
  114. package/src/schema/v0_31_0.spec.ts +73 -0
  115. package/src/schema/v0_31_0.ts +116 -54
  116. package/dist/_virtual/_rolldown/runtime.mjs +0 -6
  117. package/dist/calculatePagination.cjs +0 -25
  118. package/dist/calculatePagination.mjs +0 -25
  119. package/dist/db/ormCore.cjs +0 -577
  120. package/dist/db/ormCore.d.cts +0 -110
  121. package/dist/db/ormCore.d.mts +0 -110
  122. package/dist/db/ormCore.mjs +0 -575
  123. package/dist/node_modules/.pnpm/@noble_hashes@1.8.0/node_modules/@noble/hashes/_u64.cjs +0 -112
  124. package/dist/node_modules/.pnpm/@noble_hashes@1.8.0/node_modules/@noble/hashes/_u64.mjs +0 -108
  125. package/dist/node_modules/.pnpm/@noble_hashes@1.8.0/node_modules/@noble/hashes/cryptoNode.cjs +0 -22
  126. package/dist/node_modules/.pnpm/@noble_hashes@1.8.0/node_modules/@noble/hashes/cryptoNode.mjs +0 -18
  127. package/dist/node_modules/.pnpm/@noble_hashes@1.8.0/node_modules/@noble/hashes/sha3.cjs +0 -219
  128. package/dist/node_modules/.pnpm/@noble_hashes@1.8.0/node_modules/@noble/hashes/sha3.mjs +0 -214
  129. package/dist/node_modules/.pnpm/@noble_hashes@1.8.0/node_modules/@noble/hashes/utils.cjs +0 -275
  130. package/dist/node_modules/.pnpm/@noble_hashes@1.8.0/node_modules/@noble/hashes/utils.mjs +0 -270
  131. package/dist/node_modules/.pnpm/@paralleldrive_cuid2@2.3.1/node_modules/@paralleldrive/cuid2/index.cjs +0 -17
  132. package/dist/node_modules/.pnpm/@paralleldrive_cuid2@2.3.1/node_modules/@paralleldrive/cuid2/index.mjs +0 -13
  133. package/dist/node_modules/.pnpm/@paralleldrive_cuid2@2.3.1/node_modules/@paralleldrive/cuid2/src/index.cjs +0 -69
  134. package/dist/node_modules/.pnpm/@paralleldrive_cuid2@2.3.1/node_modules/@paralleldrive/cuid2/src/index.mjs +0 -65
  135. package/dist/node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare_workers-types@4.20260611.1_@electric-sql_pglite@0.4.1_@l_601a3995dfc55b0b7fac93cbe1e76579/node_modules/drizzle-orm/column.cjs +0 -52
  136. package/dist/node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare_workers-types@4.20260611.1_@electric-sql_pglite@0.4.1_@l_601a3995dfc55b0b7fac93cbe1e76579/node_modules/drizzle-orm/column.mjs +0 -52
  137. package/dist/node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare_workers-types@4.20260611.1_@electric-sql_pglite@0.4.1_@l_601a3995dfc55b0b7fac93cbe1e76579/node_modules/drizzle-orm/entity.cjs +0 -16
  138. package/dist/node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare_workers-types@4.20260611.1_@electric-sql_pglite@0.4.1_@l_601a3995dfc55b0b7fac93cbe1e76579/node_modules/drizzle-orm/entity.mjs +0 -15
  139. package/dist/node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare_workers-types@4.20260611.1_@electric-sql_pglite@0.4.1_@l_601a3995dfc55b0b7fac93cbe1e76579/node_modules/drizzle-orm/pg-core/columns/enum.cjs +0 -7
  140. package/dist/node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare_workers-types@4.20260611.1_@electric-sql_pglite@0.4.1_@l_601a3995dfc55b0b7fac93cbe1e76579/node_modules/drizzle-orm/pg-core/columns/enum.mjs +0 -7
  141. package/dist/node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare_workers-types@4.20260611.1_@electric-sql_pglite@0.4.1_@l_601a3995dfc55b0b7fac93cbe1e76579/node_modules/drizzle-orm/sql/expressions/conditions.cjs +0 -92
  142. package/dist/node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare_workers-types@4.20260611.1_@electric-sql_pglite@0.4.1_@l_601a3995dfc55b0b7fac93cbe1e76579/node_modules/drizzle-orm/sql/expressions/conditions.mjs +0 -78
  143. package/dist/node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare_workers-types@4.20260611.1_@electric-sql_pglite@0.4.1_@l_601a3995dfc55b0b7fac93cbe1e76579/node_modules/drizzle-orm/sql/expressions/select.cjs +0 -11
  144. package/dist/node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare_workers-types@4.20260611.1_@electric-sql_pglite@0.4.1_@l_601a3995dfc55b0b7fac93cbe1e76579/node_modules/drizzle-orm/sql/expressions/select.mjs +0 -10
  145. package/dist/node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare_workers-types@4.20260611.1_@electric-sql_pglite@0.4.1_@l_601a3995dfc55b0b7fac93cbe1e76579/node_modules/drizzle-orm/sql/sql.cjs +0 -383
  146. package/dist/node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare_workers-types@4.20260611.1_@electric-sql_pglite@0.4.1_@l_601a3995dfc55b0b7fac93cbe1e76579/node_modules/drizzle-orm/sql/sql.mjs +0 -366
  147. package/dist/node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare_workers-types@4.20260611.1_@electric-sql_pglite@0.4.1_@l_601a3995dfc55b0b7fac93cbe1e76579/node_modules/drizzle-orm/subquery.cjs +0 -17
  148. package/dist/node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare_workers-types@4.20260611.1_@electric-sql_pglite@0.4.1_@l_601a3995dfc55b0b7fac93cbe1e76579/node_modules/drizzle-orm/subquery.mjs +0 -17
  149. package/dist/node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare_workers-types@4.20260611.1_@electric-sql_pglite@0.4.1_@l_601a3995dfc55b0b7fac93cbe1e76579/node_modules/drizzle-orm/table.cjs +0 -60
  150. package/dist/node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare_workers-types@4.20260611.1_@electric-sql_pglite@0.4.1_@l_601a3995dfc55b0b7fac93cbe1e76579/node_modules/drizzle-orm/table.mjs +0 -59
  151. package/dist/node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare_workers-types@4.20260611.1_@electric-sql_pglite@0.4.1_@l_601a3995dfc55b0b7fac93cbe1e76579/node_modules/drizzle-orm/table.utils.cjs +0 -4
  152. package/dist/node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare_workers-types@4.20260611.1_@electric-sql_pglite@0.4.1_@l_601a3995dfc55b0b7fac93cbe1e76579/node_modules/drizzle-orm/table.utils.mjs +0 -4
  153. package/dist/node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare_workers-types@4.20260611.1_@electric-sql_pglite@0.4.1_@l_601a3995dfc55b0b7fac93cbe1e76579/node_modules/drizzle-orm/tracing.cjs +0 -6
  154. package/dist/node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare_workers-types@4.20260611.1_@electric-sql_pglite@0.4.1_@l_601a3995dfc55b0b7fac93cbe1e76579/node_modules/drizzle-orm/tracing.mjs +0 -6
  155. package/dist/node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare_workers-types@4.20260611.1_@electric-sql_pglite@0.4.1_@l_601a3995dfc55b0b7fac93cbe1e76579/node_modules/drizzle-orm/view-common.cjs +0 -4
  156. package/dist/node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare_workers-types@4.20260611.1_@electric-sql_pglite@0.4.1_@l_601a3995dfc55b0b7fac93cbe1e76579/node_modules/drizzle-orm/view-common.mjs +0 -4
  157. package/dist/node_modules/.pnpm/fumadb@0.2.2_mongodb@6.20.0_@aws-sdk_credential-providers@3.1066.0_socks@2.8.9__prisma@_ee79457f0e32f18f0beb5c2db02e4f73/node_modules/fumadb/dist/adapters/drizzle/index.cjs +0 -383
  158. package/dist/node_modules/.pnpm/fumadb@0.2.2_mongodb@6.20.0_@aws-sdk_credential-providers@3.1066.0_socks@2.8.9__prisma@_ee79457f0e32f18f0beb5c2db02e4f73/node_modules/fumadb/dist/adapters/drizzle/index.d.cts +0 -12
  159. package/dist/node_modules/.pnpm/fumadb@0.2.2_mongodb@6.20.0_@aws-sdk_credential-providers@3.1066.0_socks@2.8.9__prisma@_ee79457f0e32f18f0beb5c2db02e4f73/node_modules/fumadb/dist/adapters/drizzle/index.d.mts +0 -12
  160. package/dist/node_modules/.pnpm/fumadb@0.2.2_mongodb@6.20.0_@aws-sdk_credential-providers@3.1066.0_socks@2.8.9__prisma@_ee79457f0e32f18f0beb5c2db02e4f73/node_modules/fumadb/dist/adapters/drizzle/index.mjs +0 -383
  161. package/dist/node_modules/.pnpm/fumadb@0.2.2_mongodb@6.20.0_@aws-sdk_credential-providers@3.1066.0_socks@2.8.9__prisma@_ee79457f0e32f18f0beb5c2db02e4f73/node_modules/fumadb/dist/adapters/kysely/index.cjs +0 -4
  162. package/dist/node_modules/.pnpm/fumadb@0.2.2_mongodb@6.20.0_@aws-sdk_credential-providers@3.1066.0_socks@2.8.9__prisma@_ee79457f0e32f18f0beb5c2db02e4f73/node_modules/fumadb/dist/adapters/kysely/index.mjs +0 -5
  163. package/dist/node_modules/.pnpm/fumadb@0.2.2_mongodb@6.20.0_@aws-sdk_credential-providers@3.1066.0_socks@2.8.9__prisma@_ee79457f0e32f18f0beb5c2db02e4f73/node_modules/fumadb/dist/adapters/prisma/index.cjs +0 -339
  164. package/dist/node_modules/.pnpm/fumadb@0.2.2_mongodb@6.20.0_@aws-sdk_credential-providers@3.1066.0_socks@2.8.9__prisma@_ee79457f0e32f18f0beb5c2db02e4f73/node_modules/fumadb/dist/adapters/prisma/index.d.cts +0 -70
  165. package/dist/node_modules/.pnpm/fumadb@0.2.2_mongodb@6.20.0_@aws-sdk_credential-providers@3.1066.0_socks@2.8.9__prisma@_ee79457f0e32f18f0beb5c2db02e4f73/node_modules/fumadb/dist/adapters/prisma/index.d.mts +0 -70
  166. package/dist/node_modules/.pnpm/fumadb@0.2.2_mongodb@6.20.0_@aws-sdk_credential-providers@3.1066.0_socks@2.8.9__prisma@_ee79457f0e32f18f0beb5c2db02e4f73/node_modules/fumadb/dist/adapters/prisma/index.mjs +0 -339
  167. package/dist/node_modules/.pnpm/fumadb@0.2.2_mongodb@6.20.0_@aws-sdk_credential-providers@3.1066.0_socks@2.8.9__prisma@_ee79457f0e32f18f0beb5c2db02e4f73/node_modules/fumadb/dist/chunk-7PZK4ONR.cjs +0 -57
  168. package/dist/node_modules/.pnpm/fumadb@0.2.2_mongodb@6.20.0_@aws-sdk_credential-providers@3.1066.0_socks@2.8.9__prisma@_ee79457f0e32f18f0beb5c2db02e4f73/node_modules/fumadb/dist/chunk-7PZK4ONR.mjs +0 -56
  169. package/dist/node_modules/.pnpm/fumadb@0.2.2_mongodb@6.20.0_@aws-sdk_credential-providers@3.1066.0_socks@2.8.9__prisma@_ee79457f0e32f18f0beb5c2db02e4f73/node_modules/fumadb/dist/chunk-C6OTUURW.cjs +0 -330
  170. package/dist/node_modules/.pnpm/fumadb@0.2.2_mongodb@6.20.0_@aws-sdk_credential-providers@3.1066.0_socks@2.8.9__prisma@_ee79457f0e32f18f0beb5c2db02e4f73/node_modules/fumadb/dist/chunk-C6OTUURW.mjs +0 -326
  171. package/dist/node_modules/.pnpm/fumadb@0.2.2_mongodb@6.20.0_@aws-sdk_credential-providers@3.1066.0_socks@2.8.9__prisma@_ee79457f0e32f18f0beb5c2db02e4f73/node_modules/fumadb/dist/chunk-CHTIKPQU.cjs +0 -166
  172. package/dist/node_modules/.pnpm/fumadb@0.2.2_mongodb@6.20.0_@aws-sdk_credential-providers@3.1066.0_socks@2.8.9__prisma@_ee79457f0e32f18f0beb5c2db02e4f73/node_modules/fumadb/dist/chunk-CHTIKPQU.mjs +0 -163
  173. package/dist/node_modules/.pnpm/fumadb@0.2.2_mongodb@6.20.0_@aws-sdk_credential-providers@3.1066.0_socks@2.8.9__prisma@_ee79457f0e32f18f0beb5c2db02e4f73/node_modules/fumadb/dist/chunk-GUE4GMNC.cjs +0 -14
  174. package/dist/node_modules/.pnpm/fumadb@0.2.2_mongodb@6.20.0_@aws-sdk_credential-providers@3.1066.0_socks@2.8.9__prisma@_ee79457f0e32f18f0beb5c2db02e4f73/node_modules/fumadb/dist/chunk-GUE4GMNC.mjs +0 -13
  175. package/dist/node_modules/.pnpm/fumadb@0.2.2_mongodb@6.20.0_@aws-sdk_credential-providers@3.1066.0_socks@2.8.9__prisma@_ee79457f0e32f18f0beb5c2db02e4f73/node_modules/fumadb/dist/chunk-LHHP6UVP.cjs +0 -24
  176. package/dist/node_modules/.pnpm/fumadb@0.2.2_mongodb@6.20.0_@aws-sdk_credential-providers@3.1066.0_socks@2.8.9__prisma@_ee79457f0e32f18f0beb5c2db02e4f73/node_modules/fumadb/dist/chunk-LHHP6UVP.mjs +0 -24
  177. package/dist/node_modules/.pnpm/fumadb@0.2.2_mongodb@6.20.0_@aws-sdk_credential-providers@3.1066.0_socks@2.8.9__prisma@_ee79457f0e32f18f0beb5c2db02e4f73/node_modules/fumadb/dist/chunk-LVCPMTAT.cjs +0 -1190
  178. package/dist/node_modules/.pnpm/fumadb@0.2.2_mongodb@6.20.0_@aws-sdk_credential-providers@3.1066.0_socks@2.8.9__prisma@_ee79457f0e32f18f0beb5c2db02e4f73/node_modules/fumadb/dist/chunk-LVCPMTAT.mjs +0 -1189
  179. package/dist/node_modules/.pnpm/fumadb@0.2.2_mongodb@6.20.0_@aws-sdk_credential-providers@3.1066.0_socks@2.8.9__prisma@_ee79457f0e32f18f0beb5c2db02e4f73/node_modules/fumadb/dist/chunk-PK2W2SQ7.cjs +0 -197
  180. package/dist/node_modules/.pnpm/fumadb@0.2.2_mongodb@6.20.0_@aws-sdk_credential-providers@3.1066.0_socks@2.8.9__prisma@_ee79457f0e32f18f0beb5c2db02e4f73/node_modules/fumadb/dist/chunk-PK2W2SQ7.mjs +0 -197
  181. package/dist/node_modules/.pnpm/fumadb@0.2.2_mongodb@6.20.0_@aws-sdk_credential-providers@3.1066.0_socks@2.8.9__prisma@_ee79457f0e32f18f0beb5c2db02e4f73/node_modules/fumadb/dist/chunk-ZEQMAIFI.cjs +0 -410
  182. package/dist/node_modules/.pnpm/fumadb@0.2.2_mongodb@6.20.0_@aws-sdk_credential-providers@3.1066.0_socks@2.8.9__prisma@_ee79457f0e32f18f0beb5c2db02e4f73/node_modules/fumadb/dist/chunk-ZEQMAIFI.mjs +0 -400
  183. package/dist/node_modules/.pnpm/fumadb@0.2.2_mongodb@6.20.0_@aws-sdk_credential-providers@3.1066.0_socks@2.8.9__prisma@_ee79457f0e32f18f0beb5c2db02e4f73/node_modules/fumadb/dist/chunk-ZOCGSAWS.cjs +0 -213
  184. package/dist/node_modules/.pnpm/fumadb@0.2.2_mongodb@6.20.0_@aws-sdk_credential-providers@3.1066.0_socks@2.8.9__prisma@_ee79457f0e32f18f0beb5c2db02e4f73/node_modules/fumadb/dist/chunk-ZOCGSAWS.mjs +0 -212
  185. package/dist/node_modules/.pnpm/fumadb@0.2.2_mongodb@6.20.0_@aws-sdk_credential-providers@3.1066.0_socks@2.8.9__prisma@_ee79457f0e32f18f0beb5c2db02e4f73/node_modules/fumadb/dist/create-tg0451Y_.d.cts +0 -285
  186. package/dist/node_modules/.pnpm/fumadb@0.2.2_mongodb@6.20.0_@aws-sdk_credential-providers@3.1066.0_socks@2.8.9__prisma@_ee79457f0e32f18f0beb5c2db02e4f73/node_modules/fumadb/dist/create-tg0451Y_.d.mts +0 -285
  187. package/dist/node_modules/.pnpm/fumadb@0.2.2_mongodb@6.20.0_@aws-sdk_credential-providers@3.1066.0_socks@2.8.9__prisma@_ee79457f0e32f18f0beb5c2db02e4f73/node_modules/fumadb/dist/index-CMqePMTF.d.cts +0 -45
  188. package/dist/node_modules/.pnpm/fumadb@0.2.2_mongodb@6.20.0_@aws-sdk_credential-providers@3.1066.0_socks@2.8.9__prisma@_ee79457f0e32f18f0beb5c2db02e4f73/node_modules/fumadb/dist/index-CMqePMTF.d.mts +0 -45
  189. package/dist/node_modules/.pnpm/fumadb@0.2.2_mongodb@6.20.0_@aws-sdk_credential-providers@3.1066.0_socks@2.8.9__prisma@_ee79457f0e32f18f0beb5c2db02e4f73/node_modules/fumadb/dist/index.cjs +0 -69
  190. package/dist/node_modules/.pnpm/fumadb@0.2.2_mongodb@6.20.0_@aws-sdk_credential-providers@3.1066.0_socks@2.8.9__prisma@_ee79457f0e32f18f0beb5c2db02e4f73/node_modules/fumadb/dist/index.d.cts +0 -49
  191. package/dist/node_modules/.pnpm/fumadb@0.2.2_mongodb@6.20.0_@aws-sdk_credential-providers@3.1066.0_socks@2.8.9__prisma@_ee79457f0e32f18f0beb5c2db02e4f73/node_modules/fumadb/dist/index.d.mts +0 -49
  192. package/dist/node_modules/.pnpm/fumadb@0.2.2_mongodb@6.20.0_@aws-sdk_credential-providers@3.1066.0_socks@2.8.9__prisma@_ee79457f0e32f18f0beb5c2db02e4f73/node_modules/fumadb/dist/index.mjs +0 -67
  193. package/dist/node_modules/.pnpm/fumadb@0.2.2_mongodb@6.20.0_@aws-sdk_credential-providers@3.1066.0_socks@2.8.9__prisma@_ee79457f0e32f18f0beb5c2db02e4f73/node_modules/fumadb/dist/query/index.d.cts +0 -156
  194. package/dist/node_modules/.pnpm/fumadb@0.2.2_mongodb@6.20.0_@aws-sdk_credential-providers@3.1066.0_socks@2.8.9__prisma@_ee79457f0e32f18f0beb5c2db02e4f73/node_modules/fumadb/dist/query/index.d.mts +0 -156
  195. package/dist/node_modules/.pnpm/fumadb@0.2.2_mongodb@6.20.0_@aws-sdk_credential-providers@3.1066.0_socks@2.8.9__prisma@_ee79457f0e32f18f0beb5c2db02e4f73/node_modules/fumadb/dist/schema/index.cjs +0 -1
  196. package/dist/node_modules/.pnpm/fumadb@0.2.2_mongodb@6.20.0_@aws-sdk_credential-providers@3.1066.0_socks@2.8.9__prisma@_ee79457f0e32f18f0beb5c2db02e4f73/node_modules/fumadb/dist/schema/index.mjs +0 -2
  197. package/src/db/ormCore.ts +0 -1059
  198. package/src/db/ormUpdateCheck.bench.ts +0 -262
@@ -12,6 +12,7 @@ import {
12
12
  } from "@hot-updater/test-utils";
13
13
  import { Kysely } from "kysely";
14
14
  import { PGliteDialect } from "kysely-pglite-dialect";
15
+ import type { MongoClient } from "mongodb";
15
16
  import {
16
17
  afterAll,
17
18
  afterEach,
@@ -23,9 +24,19 @@ import {
23
24
  vi,
24
25
  } from "vitest";
25
26
 
27
+ import { drizzleAdapter } from "../adapters/drizzle";
26
28
  import { kyselyAdapter } from "../adapters/kysely";
29
+ import { mongoAdapter } from "../adapters/mongodb";
30
+ import { prismaAdapter } from "../adapters/prisma";
31
+ import { bundleToRow } from "./bundleRows";
32
+ import {
33
+ createSchemaMigrationSql,
34
+ createTableSql,
35
+ hotUpdaterSchemaVersions,
36
+ } from "./hotUpdaterSchema";
27
37
  import { createHotUpdater } from "./index";
28
- import type { ORMDatabaseAdapter, ORMProvider } from "./types";
38
+ import { generateDrizzleSchema } from "./schemaGenerators";
39
+ import type { DatabasePluginFactory, ORMProvider } from "./types";
29
40
 
30
41
  const RAW_PRISMA_SCHEMA = `model bundles {
31
42
  id String @id
@@ -168,25 +179,74 @@ function createSchemaOnlyAdapter({
168
179
  name: string;
169
180
  provider: ORMProvider;
170
181
  path: string;
171
- }): ORMDatabaseAdapter {
172
- return {
182
+ }): DatabasePluginFactory {
183
+ const factory: DatabasePluginFactory = () => ({
173
184
  name,
174
- provider,
175
- createORM() {
176
- throw new Error("Schema-only adapter cannot create ORM");
177
- },
178
- async getSchemaVersion() {
179
- return undefined;
185
+ async getBundleById() {
186
+ return null;
180
187
  },
181
- generateSchema(_schema, schemaName) {
188
+ async getBundles() {
182
189
  return {
183
- code,
184
- path: path || schemaName,
190
+ data: [],
191
+ pagination: {
192
+ currentPage: 1,
193
+ hasNextPage: false,
194
+ hasPreviousPage: false,
195
+ total: 0,
196
+ totalPages: 0,
197
+ },
185
198
  };
186
199
  },
200
+ async getChannels() {
201
+ return [];
202
+ },
203
+ async appendBundle() {},
204
+ async updateBundle() {},
205
+ async deleteBundle() {},
206
+ async commitBundle() {},
207
+ });
208
+ factory.adapterName = name;
209
+ factory.provider = provider;
210
+ factory.generateSchema = (_version, schemaName = name) => {
211
+ return {
212
+ code,
213
+ path: path || schemaName,
214
+ };
187
215
  };
216
+ return factory;
188
217
  }
189
218
 
219
+ const transactionBundle: Bundle = {
220
+ id: "00000000-0000-0000-0000-000000000777",
221
+ platform: "ios",
222
+ shouldForceUpdate: false,
223
+ enabled: true,
224
+ fileHash: "transaction-hash",
225
+ gitCommitHash: null,
226
+ message: "transaction bundle",
227
+ channel: "production",
228
+ storageUri: "s3://test-bucket/transaction.zip",
229
+ targetAppVersion: "1.0.0",
230
+ fingerprintHash: null,
231
+ };
232
+
233
+ const appVersionFastPathBundle: Bundle = {
234
+ ...transactionBundle,
235
+ id: "00000000-0000-0000-0000-000000000778",
236
+ fileHash: "app-version-fast-path-hash",
237
+ message: "app version fast path bundle",
238
+ targetAppVersion: "1.0.0",
239
+ };
240
+
241
+ const fingerprintFastPathBundle: Bundle = {
242
+ ...transactionBundle,
243
+ id: "00000000-0000-0000-0000-000000000779",
244
+ fileHash: "fingerprint-fast-path-hash",
245
+ fingerprintHash: "fingerprint-fast-path",
246
+ message: "fingerprint fast path bundle",
247
+ targetAppVersion: null,
248
+ };
249
+
190
250
  describe("server/db hotUpdater getUpdateInfo (PGlite + Kysely)", async () => {
191
251
  const db = new PGlite();
192
252
 
@@ -268,8 +328,18 @@ describe("server/db hotUpdater getUpdateInfo (PGlite + Kysely)", async () => {
268
328
  }),
269
329
  });
270
330
 
331
+ it("uses the default generated schema artifact path for Drizzle", () => {
332
+ const adapter = drizzleAdapter({
333
+ db: { _: { fullSchema: {} } },
334
+ provider: "sqlite",
335
+ });
336
+
337
+ expect(adapter.generateSchema?.("latest").path).toBe(
338
+ "hot-updater-schema.ts",
339
+ );
340
+ });
341
+
271
342
  beforeAll(async () => {
272
- // Initialize FumaDB schema to latest (creates tables under the hood)
273
343
  const migrator = hotUpdater.createMigrator();
274
344
  const result = await migrator.migrateToLatest({
275
345
  mode: "from-schema",
@@ -316,6 +386,7 @@ describe("server/db hotUpdater getUpdateInfo (PGlite + Kysely)", async () => {
316
386
 
317
387
  expect(code).toContain('channel String @default("production")');
318
388
  expect(code).toContain('metadata Json @default("{}")');
389
+ expect(code).toContain('value String @default("0.31.0")');
319
390
  expect(code).toContain(
320
391
  'patches bundle_patches[] @relation("bundle_patches_bundles_patches")',
321
392
  );
@@ -329,6 +400,7 @@ describe("server/db hotUpdater getUpdateInfo (PGlite + Kysely)", async () => {
329
400
  'baseBundle bundles @relation("bundle_patches_bundles_baseForPatches"',
330
401
  );
331
402
  expect(code).toContain('@@index([channel], map: "bundles_channel_idx")');
403
+ expect(code).not.toContain("bundles_platform_idx");
332
404
  expect(code).toContain(
333
405
  '@@index([bundle_id], map: "bundle_patches_bundle_id_idx")',
334
406
  );
@@ -341,6 +413,14 @@ describe("server/db hotUpdater getUpdateInfo (PGlite + Kysely)", async () => {
341
413
  expect(code).not.toContain('metadata Json @default("{}")');
342
414
  });
343
415
 
416
+ it("generates ORM schema from the requested version snapshot", () => {
417
+ const code = prismaSchemaHotUpdater.generateSchema("0.21.0").code;
418
+
419
+ expect(code).toContain('value String @default("0.21.0")');
420
+ expect(code).not.toContain("rollout_cohort_count");
421
+ expect(code).not.toContain("bundle_patches");
422
+ });
423
+
344
424
  it("includes foreign keys and indexes in Drizzle output", () => {
345
425
  const code = drizzleSchemaHotUpdater.generateSchema("latest").code;
346
426
  const bundlesBlock = code.match(
@@ -361,6 +441,7 @@ describe("server/db hotUpdater getUpdateInfo (PGlite + Kysely)", async () => {
361
441
  expect(bundlesBlock).toContain(
362
442
  'index("bundles_channel_idx").on(table.channel)',
363
443
  );
444
+ expect(bundlesBlock).not.toContain("bundles_platform_idx");
364
445
  expect(bundlesBlock).toContain(
365
446
  'index("bundles_target_app_version_idx").on(table.target_app_version)',
366
447
  );
@@ -373,10 +454,65 @@ describe("server/db hotUpdater getUpdateInfo (PGlite + Kysely)", async () => {
373
454
  expect(bundlePatchesBlock).not.toContain(
374
455
  'index("bundles_target_app_version_idx").on(table.target_app_version)',
375
456
  );
457
+ const generatedCode = generateDrizzleSchema("postgresql");
458
+ expect(generatedCode).toContain(
459
+ 'id: varchar("id", { length: 255 }).primaryKey().notNull()',
460
+ );
461
+ expect(generatedCode).toContain(
462
+ 'version: varchar("version", { length: 255 }).notNull().default("0.31.0")',
463
+ );
464
+ expect(generatedCode).not.toContain('key: varchar("key"');
465
+ expect(generatedCode).not.toContain('value: text("value"');
376
466
  });
377
467
  });
378
468
 
379
469
  describe("migrator enhancements", () => {
470
+ it("derives incremental migrations from versioned schemas", () => {
471
+ expect(hotUpdaterSchemaVersions.map((schema) => schema.version)).toEqual([
472
+ "0.21.0",
473
+ "0.29.0",
474
+ "0.31.0",
475
+ ]);
476
+
477
+ const v029Sql = createSchemaMigrationSql(
478
+ "0.21.0",
479
+ "0.29.0",
480
+ "postgresql",
481
+ ).join("\n");
482
+ const v031Sql = createSchemaMigrationSql(
483
+ "0.29.0",
484
+ "0.31.0",
485
+ "postgresql",
486
+ ).join("\n");
487
+
488
+ expect(v029Sql).toContain(
489
+ "alter table bundles add column rollout_cohort_count",
490
+ );
491
+ expect(v029Sql).not.toContain("bundle_patches");
492
+ expect(v031Sql).toContain(
493
+ "alter table bundles add column manifest_storage_uri",
494
+ );
495
+ expect(v031Sql).toContain("create table if not exists bundle_patches");
496
+ expect(v031Sql).toContain(
497
+ "add constraint bundle_patches_bundle_id_fk foreign key",
498
+ );
499
+ });
500
+
501
+ it("omits MySQL defaults for text and JSON columns", () => {
502
+ const sql = createTableSql("mysql").join("\n");
503
+
504
+ expect(sql).toContain("channel text not null");
505
+ expect(sql).not.toContain("channel text not null default");
506
+ expect(sql).toContain("metadata json not null");
507
+ expect(sql).not.toContain("metadata json not null default");
508
+ expect(sql).toContain("`key` varchar(255) primary key");
509
+ expect(sql).not.toContain("\nkey varchar(255) primary key");
510
+ expect(sql).toContain(
511
+ "create index bundle_patches_bundle_id_idx on bundle_patches(bundle_id)",
512
+ );
513
+ expect(sql).not.toContain("bundle_id(255)");
514
+ });
515
+
380
516
  it("adds custom indexes and constraints to generated SQL", async () => {
381
517
  const migrationDb = new PGlite();
382
518
  const migrationKysely = new Kysely({
@@ -401,14 +537,841 @@ describe("server/db hotUpdater getUpdateInfo (PGlite + Kysely)", async () => {
401
537
  expect(sql).toContain(
402
538
  "add constraint check_version_or_fingerprint check",
403
539
  );
540
+ expect(sql).toContain(
541
+ "add constraint bundle_patches_bundle_id_fk foreign key",
542
+ );
404
543
  expect(sql).toContain(
405
544
  "create index bundle_patches_bundle_id_idx on bundle_patches",
406
545
  );
546
+ expect(sql).toContain("insert into private_hot_updater_settings");
547
+ expect(result.operations).not.toContainEqual(
548
+ expect.objectContaining({
549
+ sql: expect.stringContaining(
550
+ "insert into private_hot_updater_settings",
551
+ ),
552
+ }),
553
+ );
554
+ } finally {
555
+ await migrationKysely.destroy();
556
+ await migrationDb.close();
557
+ }
558
+ });
559
+
560
+ it("migrates existing 0.21.0 Kysely schemas incrementally", async () => {
561
+ const migrationDb = new PGlite();
562
+ const migrationKysely = new Kysely({
563
+ dialect: new PGliteDialect(migrationDb),
564
+ });
565
+ const migrationHotUpdater = createHotUpdater({
566
+ database: kyselyAdapter({
567
+ db: migrationKysely,
568
+ provider: "postgresql",
569
+ }),
570
+ });
571
+
572
+ try {
573
+ await migrationDb.exec(`
574
+ create table bundles (
575
+ id uuid primary key,
576
+ platform text not null,
577
+ should_force_update boolean not null,
578
+ enabled boolean not null,
579
+ file_hash text not null,
580
+ git_commit_hash text,
581
+ message text,
582
+ channel text not null default 'production',
583
+ storage_uri text not null,
584
+ target_app_version text,
585
+ fingerprint_hash text,
586
+ metadata json not null default '{}'::json
587
+ );
588
+ create table private_hot_updater_settings (
589
+ key varchar(255) primary key,
590
+ value text not null
591
+ );
592
+ insert into private_hot_updater_settings (key, value)
593
+ values ('version', '0.21.0');
594
+ `);
595
+
596
+ const migrator = migrationHotUpdater.createMigrator();
597
+ const result = await migrator.migrateToLatest({
598
+ mode: "from-schema",
599
+ updateSettings: true,
600
+ });
601
+ const sql = result.getSQL?.() ?? "";
602
+
603
+ expect(sql).toContain(
604
+ "alter table bundles add column rollout_cohort_count",
605
+ );
606
+ expect(sql).toContain(
607
+ "alter table bundles add column manifest_storage_uri",
608
+ );
609
+ expect(sql).toContain("create table if not exists bundle_patches");
610
+ expect(sql).not.toContain("create table if not exists bundles");
611
+
612
+ await result.execute();
613
+
614
+ const version = await migrationDb.query<{ value: string }>(
615
+ "select value from private_hot_updater_settings where key = 'version'",
616
+ );
617
+ expect(version.rows[0]?.value).toBe("0.31.0");
618
+ await migrationDb.query(
619
+ "select rollout_cohort_count, target_cohorts, manifest_storage_uri from bundles limit 0",
620
+ );
621
+ await migrationDb.query("select * from bundle_patches limit 0");
622
+ } finally {
623
+ await migrationKysely.destroy();
624
+ await migrationDb.close();
625
+ }
626
+ });
627
+
628
+ it("honors soft relation mode by omitting SQL foreign keys", async () => {
629
+ const migrationDb = new PGlite();
630
+ const migrationKysely = new Kysely({
631
+ dialect: new PGliteDialect(migrationDb),
632
+ });
633
+ const migrationHotUpdater = createHotUpdater({
634
+ database: kyselyAdapter({
635
+ db: migrationKysely,
636
+ provider: "postgresql",
637
+ relationMode: "fumadb",
638
+ }),
639
+ });
640
+
641
+ try {
642
+ const migrator = migrationHotUpdater.createMigrator();
643
+ const result = await migrator.migrateToLatest({
644
+ mode: "from-schema",
645
+ updateSettings: false,
646
+ });
647
+ const sql = result.getSQL?.() ?? "";
648
+
649
+ expect(sql).not.toContain("add constraint bundle_patches_bundle_id_fk");
650
+ expect(result.operations).not.toContainEqual(
651
+ expect.objectContaining({
652
+ sql: expect.stringContaining("bundle_patches_bundle_id_fk"),
653
+ }),
654
+ );
655
+ } finally {
656
+ await migrationKysely.destroy();
657
+ await migrationDb.close();
658
+ }
659
+ });
660
+
661
+ it("omits unsupported SQLite alter constraint statements", async () => {
662
+ const migrationDb = new PGlite();
663
+ const migrationKysely = new Kysely({
664
+ dialect: new PGliteDialect(migrationDb),
665
+ });
666
+ const migrationHotUpdater = createHotUpdater({
667
+ database: kyselyAdapter({
668
+ db: migrationKysely,
669
+ provider: "sqlite",
670
+ }),
671
+ });
672
+
673
+ try {
674
+ const migrator = migrationHotUpdater.createMigrator();
675
+ const result = await migrator.migrateToLatest({
676
+ mode: "from-schema",
677
+ updateSettings: false,
678
+ });
679
+ const sql = result.getSQL?.() ?? "";
680
+
681
+ expect(sql).not.toContain("alter table bundles add constraint");
682
+ expect(sql).not.toContain("alter table bundle_patches add constraint");
683
+ expect(result.operations).not.toContainEqual(
684
+ expect.objectContaining({
685
+ sql: expect.stringContaining("add constraint"),
686
+ }),
687
+ );
688
+ } finally {
689
+ await migrationKysely.destroy();
690
+ await migrationDb.close();
691
+ }
692
+ });
693
+
694
+ it("creates MongoDB indexes for runtime query fields", async () => {
695
+ const collection = {
696
+ findOne: vi.fn(async () => null),
697
+ };
698
+ const client = {
699
+ db: () => ({
700
+ collection: () => collection,
701
+ }),
702
+ } as unknown as MongoClient;
703
+ const mongoHotUpdater = createHotUpdater({
704
+ database: mongoAdapter({ client }),
705
+ });
706
+ const result = await mongoHotUpdater
707
+ .createMigrator()
708
+ .migrateToLatest({ mode: "from-schema" });
709
+
710
+ expect(result.operations).toEqual(
711
+ expect.arrayContaining([
712
+ expect.objectContaining({
713
+ sql: "create index bundles_id_idx on bundles(id)",
714
+ }),
715
+ expect.objectContaining({
716
+ sql: "create index bundles_target_app_version_idx on bundles(target_app_version)",
717
+ }),
718
+ expect.objectContaining({
719
+ sql: "create index bundles_fingerprint_hash_idx on bundles(fingerprint_hash)",
720
+ }),
721
+ expect.objectContaining({
722
+ sql: "create index bundles_platform_idx on bundles(platform)",
723
+ }),
724
+ expect.objectContaining({
725
+ sql: "create index bundle_patches_base_bundle_id_idx on bundle_patches(base_bundle_id)",
726
+ }),
727
+ ]),
728
+ );
729
+ });
730
+
731
+ it("rejects from-database migrations explicitly", async () => {
732
+ const migrationDb = new PGlite();
733
+ const migrationKysely = new Kysely({
734
+ dialect: new PGliteDialect(migrationDb),
735
+ });
736
+ const migrationHotUpdater = createHotUpdater({
737
+ database: kyselyAdapter({
738
+ db: migrationKysely,
739
+ provider: "postgresql",
740
+ }),
741
+ });
742
+
743
+ try {
744
+ await expect(
745
+ migrationHotUpdater.createMigrator().migrateToLatest({
746
+ mode: "from-database",
747
+ }),
748
+ ).rejects.toThrow(
749
+ "Hot Updater migrations support only mode: 'from-schema'.",
750
+ );
751
+ } finally {
752
+ await migrationKysely.destroy();
753
+ await migrationDb.close();
754
+ }
755
+ });
756
+
757
+ it("rejects runtime access when a Kysely schema is not initialized", async () => {
758
+ const migrationDb = new PGlite();
759
+ const migrationKysely = new Kysely({
760
+ dialect: new PGliteDialect(migrationDb),
761
+ });
762
+ const migrationHotUpdater = createHotUpdater({
763
+ database: kyselyAdapter({
764
+ db: migrationKysely,
765
+ provider: "postgresql",
766
+ }),
767
+ });
768
+
769
+ try {
770
+ await expect(
771
+ migrationHotUpdater.getBundles({ limit: 10 }),
772
+ ).rejects.toThrow(
773
+ "Hot Updater database schema is not initialized for kysely.",
774
+ );
775
+ } finally {
776
+ await migrationKysely.destroy();
777
+ await migrationDb.close();
778
+ }
779
+ });
780
+
781
+ it("rejects runtime access when a Kysely schema is stale", async () => {
782
+ const migrationDb = new PGlite();
783
+ const migrationKysely = new Kysely({
784
+ dialect: new PGliteDialect(migrationDb),
785
+ });
786
+ const migrationHotUpdater = createHotUpdater({
787
+ database: kyselyAdapter({
788
+ db: migrationKysely,
789
+ provider: "postgresql",
790
+ }),
791
+ });
792
+
793
+ try {
794
+ await migrationDb.exec(`
795
+ create table private_hot_updater_settings (
796
+ key varchar(255) primary key,
797
+ value text not null
798
+ );
799
+ insert into private_hot_updater_settings (key, value)
800
+ values ('version', '0.21.0');
801
+ `);
802
+
803
+ await expect(migrationHotUpdater.getChannels()).rejects.toThrow(
804
+ "Hot Updater database schema version 0.21.0 is not supported by kysely.",
805
+ );
407
806
  } finally {
408
807
  await migrationKysely.destroy();
409
808
  await migrationDb.close();
410
809
  }
411
810
  });
811
+
812
+ it("rejects runtime access when a MongoDB schema is stale", async () => {
813
+ const settings = {
814
+ findOne: vi.fn(async () => ({ key: "version", value: "0.21.0" })),
815
+ };
816
+ const bundles = {
817
+ countDocuments: vi.fn(async () => 0),
818
+ find: vi.fn(),
819
+ findOne: vi.fn(),
820
+ };
821
+ const patches = {
822
+ find: vi.fn(),
823
+ };
824
+ const client = {
825
+ db: () => ({
826
+ collection: (name: string) => {
827
+ if (name === "private_hot_updater_settings") return settings;
828
+ if (name === "bundle_patches") return patches;
829
+ return bundles;
830
+ },
831
+ }),
832
+ } as unknown as MongoClient;
833
+ const mongoHotUpdater = createHotUpdater({
834
+ database: mongoAdapter({ client }),
835
+ });
836
+
837
+ await expect(mongoHotUpdater.getBundles({ limit: 10 })).rejects.toThrow(
838
+ "Hot Updater database schema version 0.21.0 is not supported by mongodb.",
839
+ );
840
+ expect(bundles.countDocuments).not.toHaveBeenCalled();
841
+ });
842
+ });
843
+
844
+ describe("adapter filters", () => {
845
+ it("returns an empty Kysely page for empty set filters", async () => {
846
+ const byId = await hotUpdater.getBundles({
847
+ limit: 10,
848
+ where: { id: { in: [] } },
849
+ });
850
+ const byTargetAppVersion = await hotUpdater.getBundles({
851
+ limit: 10,
852
+ where: { targetAppVersionIn: [] },
853
+ });
854
+
855
+ expect(byId.data).toEqual([]);
856
+ expect(byId.pagination.total).toBe(0);
857
+ expect(byTargetAppVersion.data).toEqual([]);
858
+ expect(byTargetAppVersion.pagination.total).toBe(0);
859
+ });
860
+
861
+ it("combines Prisma targetAppVersion filters without overwriting", async () => {
862
+ const bundles = {
863
+ count: vi.fn(async () => 0),
864
+ createMany: vi.fn(),
865
+ deleteMany: vi.fn(),
866
+ findFirst: vi.fn(),
867
+ findMany: vi.fn(async () => []),
868
+ upsert: vi.fn(),
869
+ };
870
+ const patches = {
871
+ count: vi.fn(),
872
+ createMany: vi.fn(),
873
+ deleteMany: vi.fn(),
874
+ findFirst: vi.fn(),
875
+ findMany: vi.fn(async () => []),
876
+ upsert: vi.fn(),
877
+ };
878
+ const plugin = prismaAdapter({
879
+ prisma: { bundles, bundle_patches: patches },
880
+ provider: "postgresql",
881
+ })();
882
+
883
+ await plugin.getBundles({
884
+ limit: 10,
885
+ where: {
886
+ targetAppVersion: "1.0.x",
887
+ targetAppVersionNotNull: true,
888
+ },
889
+ });
890
+
891
+ expect(bundles.findMany).toHaveBeenCalledWith(
892
+ expect.objectContaining({
893
+ where: expect.objectContaining({
894
+ AND: [
895
+ { target_app_version: "1.0.x" },
896
+ { target_app_version: { not: null } },
897
+ ],
898
+ }),
899
+ }),
900
+ );
901
+ });
902
+
903
+ it("combines MongoDB targetAppVersion filters without overwriting", async () => {
904
+ const toArray = vi.fn(async () => []);
905
+ const limit = vi.fn(() => ({ toArray }));
906
+ const skip = vi.fn(() => ({ limit }));
907
+ const sort = vi.fn(() => ({ skip }));
908
+ const bundles = {
909
+ countDocuments: vi.fn(async () => 0),
910
+ distinct: vi.fn(),
911
+ find: vi.fn(() => ({ sort })),
912
+ findOne: vi.fn(),
913
+ };
914
+ const patches = {
915
+ deleteMany: vi.fn(),
916
+ find: vi.fn(() => ({
917
+ sort: vi.fn(() => ({ toArray: vi.fn(async () => []) })),
918
+ })),
919
+ insertMany: vi.fn(),
920
+ };
921
+ const client = {
922
+ db: () => ({
923
+ collection: (name: string) =>
924
+ name === "bundle_patches" ? patches : bundles,
925
+ }),
926
+ } as unknown as MongoClient;
927
+ const plugin = mongoAdapter({ client })();
928
+
929
+ await plugin.getBundles({
930
+ limit: 10,
931
+ where: {
932
+ targetAppVersion: "1.0.x",
933
+ targetAppVersionNotNull: true,
934
+ },
935
+ });
936
+
937
+ expect(bundles.countDocuments).toHaveBeenCalledWith({
938
+ $and: [
939
+ { target_app_version: "1.0.x" },
940
+ { target_app_version: { $exists: true, $nin: [null, ""] } },
941
+ ],
942
+ });
943
+ });
944
+
945
+ it("uses Prisma update-check queries without generic list pagination", async () => {
946
+ const appVersionRow = bundleToRow(appVersionFastPathBundle);
947
+ const fingerprintRow = bundleToRow(fingerprintFastPathBundle);
948
+ const bundles = {
949
+ count: vi.fn(async () => {
950
+ throw new Error("unexpected generic Prisma count");
951
+ }),
952
+ createMany: vi.fn(),
953
+ deleteMany: vi.fn(),
954
+ findFirst: vi.fn(),
955
+ findMany: vi
956
+ .fn()
957
+ .mockResolvedValueOnce([
958
+ { target_app_version: appVersionRow.target_app_version },
959
+ ])
960
+ .mockResolvedValueOnce([appVersionRow])
961
+ .mockResolvedValueOnce([fingerprintRow]),
962
+ upsert: vi.fn(),
963
+ };
964
+ const patches = {
965
+ count: vi.fn(),
966
+ createMany: vi.fn(),
967
+ deleteMany: vi.fn(),
968
+ findFirst: vi.fn(),
969
+ findMany: vi.fn(async () => []),
970
+ upsert: vi.fn(),
971
+ };
972
+ const plugin = prismaAdapter({
973
+ prisma: { bundles, bundle_patches: patches },
974
+ provider: "postgresql",
975
+ })();
976
+
977
+ await expect(
978
+ plugin.getUpdateInfo?.({
979
+ _updateStrategy: "appVersion",
980
+ appVersion: "1.0.0",
981
+ bundleId: NIL_UUID,
982
+ platform: "ios",
983
+ }),
984
+ ).resolves.toMatchObject({
985
+ id: appVersionFastPathBundle.id,
986
+ status: "UPDATE",
987
+ });
988
+ await expect(
989
+ plugin.getUpdateInfo?.({
990
+ _updateStrategy: "fingerprint",
991
+ bundleId: NIL_UUID,
992
+ fingerprintHash: "fingerprint-fast-path",
993
+ platform: "ios",
994
+ }),
995
+ ).resolves.toMatchObject({
996
+ id: fingerprintFastPathBundle.id,
997
+ status: "UPDATE",
998
+ });
999
+
1000
+ expect(bundles.count).not.toHaveBeenCalled();
1001
+ expect(bundles.findMany).toHaveBeenNthCalledWith(
1002
+ 1,
1003
+ expect.objectContaining({
1004
+ select: { target_app_version: true },
1005
+ where: expect.objectContaining({
1006
+ channel: "production",
1007
+ id: { gte: NIL_UUID },
1008
+ }),
1009
+ }),
1010
+ );
1011
+ expect(bundles.findMany).toHaveBeenNthCalledWith(
1012
+ 2,
1013
+ expect.objectContaining({
1014
+ where: expect.objectContaining({
1015
+ target_app_version: { in: ["1.0.0"] },
1016
+ }),
1017
+ }),
1018
+ );
1019
+ expect(bundles.findMany).toHaveBeenNthCalledWith(
1020
+ 3,
1021
+ expect.objectContaining({
1022
+ where: expect.objectContaining({
1023
+ fingerprint_hash: "fingerprint-fast-path",
1024
+ }),
1025
+ }),
1026
+ );
1027
+ expect(patches.findMany).toHaveBeenCalledTimes(2);
1028
+ });
1029
+
1030
+ it("uses Drizzle update-check queries without generic list pagination", async () => {
1031
+ const appVersionRow = bundleToRow(appVersionFastPathBundle);
1032
+ const fingerprintRow = bundleToRow(fingerprintFastPathBundle);
1033
+ const tables = {
1034
+ bundle_patches: {
1035
+ bundle_id: "bundle_id",
1036
+ id: "patch_id",
1037
+ order_index: "order_index",
1038
+ },
1039
+ bundles: {
1040
+ channel: "channel",
1041
+ enabled: "enabled",
1042
+ fingerprint_hash: "fingerprint_hash",
1043
+ id: "id",
1044
+ platform: "platform",
1045
+ target_app_version: "target_app_version",
1046
+ },
1047
+ };
1048
+ const bundleFindMany = vi
1049
+ .fn()
1050
+ .mockResolvedValueOnce([
1051
+ { target_app_version: appVersionRow.target_app_version },
1052
+ ])
1053
+ .mockResolvedValueOnce([appVersionRow])
1054
+ .mockResolvedValueOnce([fingerprintRow]);
1055
+ const patchFindMany = vi.fn(async () => []);
1056
+ const db = {
1057
+ _: { fullSchema: tables },
1058
+ $count: vi.fn(async () => {
1059
+ throw new Error("unexpected generic Drizzle count");
1060
+ }),
1061
+ delete: vi.fn(() => ({
1062
+ where: vi.fn(async () => undefined),
1063
+ })),
1064
+ insert: vi.fn(),
1065
+ query: {
1066
+ bundle_patches: {
1067
+ findMany: patchFindMany,
1068
+ },
1069
+ bundles: {
1070
+ findFirst: vi.fn(),
1071
+ findMany: bundleFindMany,
1072
+ },
1073
+ },
1074
+ select: vi.fn(),
1075
+ update: vi.fn(),
1076
+ };
1077
+ const plugin = drizzleAdapter({
1078
+ db,
1079
+ provider: "postgresql",
1080
+ })();
1081
+
1082
+ await expect(
1083
+ plugin.getUpdateInfo?.({
1084
+ _updateStrategy: "appVersion",
1085
+ appVersion: "1.0.0",
1086
+ bundleId: NIL_UUID,
1087
+ platform: "ios",
1088
+ }),
1089
+ ).resolves.toMatchObject({
1090
+ id: appVersionFastPathBundle.id,
1091
+ status: "UPDATE",
1092
+ });
1093
+ await expect(
1094
+ plugin.getUpdateInfo?.({
1095
+ _updateStrategy: "fingerprint",
1096
+ bundleId: NIL_UUID,
1097
+ fingerprintHash: "fingerprint-fast-path",
1098
+ platform: "ios",
1099
+ }),
1100
+ ).resolves.toMatchObject({
1101
+ id: fingerprintFastPathBundle.id,
1102
+ status: "UPDATE",
1103
+ });
1104
+
1105
+ expect(db.$count).not.toHaveBeenCalled();
1106
+ expect(bundleFindMany).toHaveBeenNthCalledWith(
1107
+ 1,
1108
+ expect.objectContaining({
1109
+ columns: { target_app_version: true },
1110
+ }),
1111
+ );
1112
+ const appVersionWhere = JSON.stringify(bundleFindMany.mock.calls[0]?.[0]);
1113
+ const fingerprintWhere = JSON.stringify(
1114
+ bundleFindMany.mock.calls[2]?.[0],
1115
+ );
1116
+ expect(appVersionWhere).toContain("production");
1117
+ expect(appVersionWhere).toContain(NIL_UUID);
1118
+ expect(fingerprintWhere).toContain("production");
1119
+ expect(fingerprintWhere).toContain(NIL_UUID);
1120
+ expect(fingerprintWhere).toContain("fingerprint-fast-path");
1121
+ expect(bundleFindMany).toHaveBeenCalledTimes(3);
1122
+ expect(patchFindMany).toHaveBeenCalledTimes(2);
1123
+ });
1124
+
1125
+ it("uses MongoDB update-check queries without generic list pagination", async () => {
1126
+ const appVersionRow = bundleToRow(appVersionFastPathBundle);
1127
+ const fingerprintRow = bundleToRow(fingerprintFastPathBundle);
1128
+ const projectToArray = vi.fn(async () => [
1129
+ { target_app_version: appVersionRow.target_app_version },
1130
+ ]);
1131
+ const sortToArray = vi
1132
+ .fn()
1133
+ .mockResolvedValueOnce([appVersionRow])
1134
+ .mockResolvedValueOnce([fingerprintRow]);
1135
+ const project = vi.fn(() => ({ toArray: projectToArray }));
1136
+ const sort = vi.fn(() => ({ toArray: sortToArray }));
1137
+ const bundles = {
1138
+ countDocuments: vi.fn(async () => {
1139
+ throw new Error("unexpected generic MongoDB count");
1140
+ }),
1141
+ deleteMany: vi.fn(),
1142
+ distinct: vi.fn(),
1143
+ find: vi.fn((filter: Record<string, unknown>) => {
1144
+ const targetAppVersion = filter["target_app_version"];
1145
+ if (
1146
+ typeof targetAppVersion === "object" &&
1147
+ targetAppVersion !== null &&
1148
+ "$exists" in targetAppVersion
1149
+ ) {
1150
+ return { project };
1151
+ }
1152
+ return { sort };
1153
+ }),
1154
+ findOne: vi.fn(),
1155
+ updateOne: vi.fn(),
1156
+ };
1157
+ const patches = {
1158
+ deleteMany: vi.fn(),
1159
+ find: vi.fn(() => ({
1160
+ sort: vi.fn(() => ({ toArray: vi.fn(async () => []) })),
1161
+ })),
1162
+ insertMany: vi.fn(),
1163
+ };
1164
+ const client = {
1165
+ db: () => ({
1166
+ collection: (name: string) =>
1167
+ name === "bundle_patches" ? patches : bundles,
1168
+ }),
1169
+ } as unknown as MongoClient;
1170
+ const plugin = mongoAdapter({ client })();
1171
+
1172
+ await expect(
1173
+ plugin.getUpdateInfo?.({
1174
+ _updateStrategy: "appVersion",
1175
+ appVersion: "1.0.0",
1176
+ bundleId: NIL_UUID,
1177
+ platform: "ios",
1178
+ }),
1179
+ ).resolves.toMatchObject({
1180
+ id: appVersionFastPathBundle.id,
1181
+ status: "UPDATE",
1182
+ });
1183
+ await expect(
1184
+ plugin.getUpdateInfo?.({
1185
+ _updateStrategy: "fingerprint",
1186
+ bundleId: NIL_UUID,
1187
+ fingerprintHash: "fingerprint-fast-path",
1188
+ platform: "ios",
1189
+ }),
1190
+ ).resolves.toMatchObject({
1191
+ id: fingerprintFastPathBundle.id,
1192
+ status: "UPDATE",
1193
+ });
1194
+
1195
+ expect(bundles.countDocuments).not.toHaveBeenCalled();
1196
+ expect(bundles.find).toHaveBeenNthCalledWith(
1197
+ 1,
1198
+ expect.objectContaining({
1199
+ channel: "production",
1200
+ id: { $gte: NIL_UUID },
1201
+ target_app_version: { $exists: true, $nin: [null, ""] },
1202
+ }),
1203
+ );
1204
+ expect(bundles.find).toHaveBeenNthCalledWith(
1205
+ 2,
1206
+ expect.objectContaining({
1207
+ target_app_version: { $in: ["1.0.0"] },
1208
+ }),
1209
+ );
1210
+ expect(bundles.find).toHaveBeenNthCalledWith(
1211
+ 3,
1212
+ expect.objectContaining({
1213
+ fingerprint_hash: "fingerprint-fast-path",
1214
+ }),
1215
+ );
1216
+ expect(patches.find).toHaveBeenCalledTimes(2);
1217
+ });
1218
+
1219
+ it("commits Prisma bundle changes inside a transaction when available", async () => {
1220
+ const rootBundles = {
1221
+ count: vi.fn(),
1222
+ createMany: vi.fn(),
1223
+ deleteMany: vi.fn(),
1224
+ findFirst: vi.fn(),
1225
+ findMany: vi.fn(),
1226
+ upsert: vi.fn(),
1227
+ };
1228
+ const rootPatches = {
1229
+ count: vi.fn(),
1230
+ createMany: vi.fn(),
1231
+ deleteMany: vi.fn(),
1232
+ findFirst: vi.fn(),
1233
+ findMany: vi.fn(),
1234
+ upsert: vi.fn(),
1235
+ };
1236
+ const txBundles = {
1237
+ ...rootBundles,
1238
+ upsert: vi.fn(async () => undefined),
1239
+ };
1240
+ const txPatches = {
1241
+ ...rootPatches,
1242
+ deleteMany: vi.fn(async () => undefined),
1243
+ };
1244
+ const $transaction = vi.fn(
1245
+ async (operation: (tx: Record<string, unknown>) => Promise<unknown>) =>
1246
+ operation({
1247
+ bundle_patches: txPatches,
1248
+ bundles: txBundles,
1249
+ }),
1250
+ );
1251
+ const plugin = prismaAdapter({
1252
+ prisma: {
1253
+ $transaction,
1254
+ bundle_patches: rootPatches,
1255
+ bundles: rootBundles,
1256
+ },
1257
+ provider: "postgresql",
1258
+ })();
1259
+
1260
+ await plugin.appendBundle(transactionBundle);
1261
+ await plugin.commitBundle();
1262
+
1263
+ expect($transaction).toHaveBeenCalledTimes(1);
1264
+ expect(txBundles.upsert).toHaveBeenCalledTimes(1);
1265
+ expect(rootBundles.upsert).not.toHaveBeenCalled();
1266
+ });
1267
+
1268
+ it("commits Drizzle bundle changes inside a transaction when available", async () => {
1269
+ const tables = {
1270
+ bundle_patches: {
1271
+ bundle_id: "bundle_id",
1272
+ id: "patch_id",
1273
+ order_index: "order_index",
1274
+ },
1275
+ bundles: {
1276
+ id: "id",
1277
+ },
1278
+ };
1279
+ const rootInsert = vi.fn(() => ({
1280
+ values: vi.fn(() => ({ execute: vi.fn(async () => undefined) })),
1281
+ }));
1282
+ const txInsert = vi.fn(() => ({
1283
+ values: vi.fn(() => ({ execute: vi.fn(async () => undefined) })),
1284
+ }));
1285
+ const createDb = (insert: typeof rootInsert) => ({
1286
+ _: { fullSchema: tables },
1287
+ $count: vi.fn(),
1288
+ delete: vi.fn(() => ({
1289
+ where: vi.fn(async () => undefined),
1290
+ })),
1291
+ insert,
1292
+ query: {
1293
+ bundle_patches: {
1294
+ findMany: vi.fn(),
1295
+ },
1296
+ bundles: {
1297
+ findFirst: vi.fn(async () => undefined),
1298
+ findMany: vi.fn(),
1299
+ },
1300
+ },
1301
+ select: vi.fn(),
1302
+ update: vi.fn(() => ({
1303
+ set: vi.fn(() => ({
1304
+ where: vi.fn(async () => undefined),
1305
+ })),
1306
+ })),
1307
+ });
1308
+ const txDb = createDb(txInsert);
1309
+ const transaction = vi.fn(
1310
+ async (operation: (tx: typeof txDb) => Promise<unknown>) =>
1311
+ operation(txDb),
1312
+ );
1313
+ const db = {
1314
+ ...createDb(rootInsert),
1315
+ transaction,
1316
+ };
1317
+ const plugin = drizzleAdapter({
1318
+ db,
1319
+ provider: "postgresql",
1320
+ })();
1321
+
1322
+ await plugin.appendBundle(transactionBundle);
1323
+ await plugin.commitBundle();
1324
+
1325
+ expect(transaction).toHaveBeenCalledTimes(1);
1326
+ expect(txInsert).toHaveBeenCalledTimes(1);
1327
+ expect(rootInsert).not.toHaveBeenCalled();
1328
+ });
1329
+
1330
+ it("commits MongoDB bundle changes inside a session transaction when available", async () => {
1331
+ const session = {
1332
+ endSession: vi.fn(async () => undefined),
1333
+ withTransaction: vi.fn(async (operation: () => Promise<void>) =>
1334
+ operation(),
1335
+ ),
1336
+ };
1337
+ const bundles = {
1338
+ countDocuments: vi.fn(),
1339
+ deleteMany: vi.fn(),
1340
+ distinct: vi.fn(),
1341
+ find: vi.fn(),
1342
+ findOne: vi.fn(),
1343
+ updateOne: vi.fn(async () => undefined),
1344
+ };
1345
+ const patches = {
1346
+ deleteMany: vi.fn(async () => undefined),
1347
+ find: vi.fn(),
1348
+ insertMany: vi.fn(),
1349
+ };
1350
+ const client = {
1351
+ db: () => ({
1352
+ collection: (name: string) =>
1353
+ name === "bundle_patches" ? patches : bundles,
1354
+ }),
1355
+ startSession: vi.fn(() => session),
1356
+ } as unknown as MongoClient;
1357
+ const plugin = mongoAdapter({ client })();
1358
+
1359
+ await plugin.appendBundle(transactionBundle);
1360
+ await plugin.commitBundle();
1361
+
1362
+ expect(client.startSession).toHaveBeenCalledTimes(1);
1363
+ expect(session.withTransaction).toHaveBeenCalledTimes(1);
1364
+ expect(bundles.updateOne).toHaveBeenCalledWith(
1365
+ { id: transactionBundle.id },
1366
+ expect.any(Object),
1367
+ expect.objectContaining({ session, upsert: true }),
1368
+ );
1369
+ expect(patches.deleteMany).toHaveBeenCalledWith(
1370
+ { bundle_id: transactionBundle.id },
1371
+ { session },
1372
+ );
1373
+ expect(session.endSession).toHaveBeenCalledTimes(1);
1374
+ });
412
1375
  });
413
1376
 
414
1377
  describe("bundle validation", () => {