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