@hot-updater/server 1.0.0-rc.1 → 1.0.0-rc.16

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 (542) hide show
  1. package/dist/_virtual/_rolldown/runtime.cjs +1 -1
  2. package/dist/adapters/drizzle.cjs +35 -69
  3. package/dist/adapters/drizzle.d.cts +13 -6
  4. package/dist/adapters/drizzle.d.mts +13 -6
  5. package/dist/adapters/drizzle.mjs +34 -69
  6. package/dist/adapters/drizzleExecutor.cjs +114 -0
  7. package/dist/adapters/drizzleExecutor.d.cts +9 -0
  8. package/dist/adapters/drizzleExecutor.d.mts +9 -0
  9. package/dist/adapters/drizzleExecutor.mjs +112 -0
  10. package/dist/adapters/kysely.cjs +25 -31
  11. package/dist/adapters/kysely.d.cts +10 -7
  12. package/dist/adapters/kysely.d.mts +10 -7
  13. package/dist/adapters/kysely.mjs +25 -31
  14. package/dist/adapters/kyselyExecutor.cjs +32 -0
  15. package/dist/adapters/kyselyExecutor.d.cts +12 -0
  16. package/dist/adapters/kyselyExecutor.d.mts +12 -0
  17. package/dist/adapters/kyselyExecutor.mjs +32 -0
  18. package/dist/adapters/mongodb.cjs +28 -27
  19. package/dist/adapters/mongodb.d.cts +10 -5
  20. package/dist/adapters/mongodb.d.mts +10 -5
  21. package/dist/adapters/mongodb.mjs +28 -27
  22. package/dist/adapters/mongodbAdapter.cjs +174 -0
  23. package/dist/adapters/mongodbAdapter.d.cts +9 -0
  24. package/dist/adapters/mongodbAdapter.d.mts +9 -0
  25. package/dist/adapters/mongodbAdapter.mjs +173 -0
  26. package/dist/adapters/prisma.cjs +38 -220
  27. package/dist/adapters/prisma.d.cts +12 -8
  28. package/dist/adapters/prisma.d.mts +12 -8
  29. package/dist/adapters/prisma.mjs +38 -219
  30. package/dist/adapters/prismaExecutor.cjs +64 -0
  31. package/dist/adapters/prismaExecutor.mjs +64 -0
  32. package/dist/adapters/sqlProviders.cjs +9 -0
  33. package/dist/adapters/sqlProviders.mjs +9 -0
  34. package/dist/apiKeys.cjs +8 -8
  35. package/dist/apiKeys.d.cts +1 -24
  36. package/dist/apiKeys.d.mts +1 -24
  37. package/dist/apiKeys.mjs +5 -9
  38. package/dist/assembly/assemblePlugins.cjs +147 -0
  39. package/dist/assembly/assemblePlugins.d.cts +12 -0
  40. package/dist/assembly/assemblePlugins.d.mts +12 -0
  41. package/dist/assembly/assemblePlugins.mjs +146 -0
  42. package/dist/assembly/databasePlugins.cjs +23 -0
  43. package/dist/assembly/databasePlugins.d.cts +43 -0
  44. package/dist/assembly/databasePlugins.d.mts +43 -0
  45. package/dist/assembly/databasePlugins.mjs +22 -0
  46. package/dist/core/api.cjs +91 -0
  47. package/dist/core/api.d.cts +65 -0
  48. package/dist/core/api.d.mts +65 -0
  49. package/dist/core/api.mjs +87 -0
  50. package/dist/core/baseCandidates.cjs +71 -0
  51. package/dist/core/baseCandidates.d.cts +17 -0
  52. package/dist/core/baseCandidates.d.mts +17 -0
  53. package/dist/core/baseCandidates.mjs +69 -0
  54. package/dist/core/operations.cjs +350 -0
  55. package/dist/core/operations.mjs +350 -0
  56. package/dist/core/reads.cjs +273 -0
  57. package/dist/core/reads.d.cts +48 -0
  58. package/dist/core/reads.d.mts +48 -0
  59. package/dist/core/reads.mjs +267 -0
  60. package/dist/core/releases.cjs +193 -0
  61. package/dist/core/releases.mjs +190 -0
  62. package/dist/core/schema.cjs +279 -0
  63. package/dist/core/schema.d.cts +307 -0
  64. package/dist/core/schema.d.mts +307 -0
  65. package/dist/core/schema.mjs +277 -0
  66. package/dist/core/writes.cjs +96 -0
  67. package/dist/core/writes.mjs +91 -0
  68. package/dist/createHotUpdaterCore.cjs +61 -63
  69. package/dist/createHotUpdaterCore.d.cts +53 -45
  70. package/dist/createHotUpdaterCore.d.mts +53 -45
  71. package/dist/createHotUpdaterCore.mjs +61 -63
  72. package/dist/database/cursor.cjs +44 -0
  73. package/dist/database/cursor.d.cts +7 -0
  74. package/dist/database/cursor.d.mts +7 -0
  75. package/dist/database/cursor.mjs +40 -0
  76. package/dist/database/database.cjs +44 -0
  77. package/dist/database/database.d.cts +123 -0
  78. package/dist/database/database.d.mts +123 -0
  79. package/dist/database/database.mjs +44 -0
  80. package/dist/database/definitions.d.cts +68 -0
  81. package/dist/database/definitions.d.mts +68 -0
  82. package/dist/database/engine.cjs +37 -0
  83. package/dist/database/engine.d.cts +40 -0
  84. package/dist/database/engine.d.mts +40 -0
  85. package/dist/database/engine.mjs +37 -0
  86. package/dist/database/engineAggregates.cjs +115 -0
  87. package/dist/database/engineAggregates.mjs +112 -0
  88. package/dist/database/engineReads.cjs +180 -0
  89. package/dist/database/engineReads.d.cts +35 -0
  90. package/dist/database/engineReads.d.mts +35 -0
  91. package/dist/database/engineReads.mjs +179 -0
  92. package/dist/database/engineTransaction.cjs +403 -0
  93. package/dist/database/engineTransaction.d.cts +26 -0
  94. package/dist/database/engineTransaction.d.mts +26 -0
  95. package/dist/database/engineTransaction.mjs +402 -0
  96. package/dist/database/errors.cjs +27 -0
  97. package/dist/database/errors.d.cts +21 -0
  98. package/dist/database/errors.d.mts +21 -0
  99. package/dist/database/errors.mjs +24 -0
  100. package/dist/database/fence.cjs +124 -0
  101. package/dist/database/fence.d.cts +42 -0
  102. package/dist/database/fence.d.mts +42 -0
  103. package/dist/database/fence.mjs +116 -0
  104. package/dist/database/index.cjs +127 -0
  105. package/dist/database/index.d.cts +17 -0
  106. package/dist/database/index.d.mts +17 -0
  107. package/dist/database/index.mjs +15 -0
  108. package/dist/database/kv/kvAdapter.cjs +273 -0
  109. package/dist/database/kv/kvAdapter.d.cts +101 -0
  110. package/dist/database/kv/kvAdapter.d.mts +101 -0
  111. package/dist/database/kv/kvAdapter.mjs +272 -0
  112. package/dist/database/resolveSchema.cjs +196 -0
  113. package/dist/database/resolveSchema.d.cts +42 -0
  114. package/dist/database/resolveSchema.d.mts +42 -0
  115. package/dist/database/resolveSchema.mjs +193 -0
  116. package/dist/database/schema.cjs +21 -0
  117. package/dist/database/schema.d.cts +61 -0
  118. package/dist/database/schema.d.mts +61 -0
  119. package/dist/database/schema.mjs +20 -0
  120. package/dist/database/sql/sqlAdapter.cjs +282 -0
  121. package/dist/database/sql/sqlAdapter.d.cts +46 -0
  122. package/dist/database/sql/sqlAdapter.d.mts +46 -0
  123. package/dist/database/sql/sqlAdapter.mjs +279 -0
  124. package/dist/database/sql/sqlSchema.cjs +115 -0
  125. package/dist/database/sql/sqlSchema.d.cts +8 -0
  126. package/dist/database/sql/sqlSchema.d.mts +8 -0
  127. package/dist/database/sql/sqlSchema.mjs +111 -0
  128. package/dist/db/builtInDatabase.cjs +104 -0
  129. package/dist/db/builtInDatabase.d.cts +38 -0
  130. package/dist/db/builtInDatabase.d.mts +38 -0
  131. package/dist/db/builtInDatabase.mjs +97 -0
  132. package/dist/db/createBundleDiff.cjs +6 -6
  133. package/dist/db/createBundleDiff.d.cts +4 -7
  134. package/dist/db/createBundleDiff.d.mts +4 -7
  135. package/dist/db/createBundleDiff.mjs +5 -5
  136. package/dist/db/engineDrizzleSchema.cjs +54 -0
  137. package/dist/db/engineDrizzleSchema.mjs +54 -0
  138. package/dist/db/engineMigrator.cjs +53 -0
  139. package/dist/db/engineMigrator.mjs +53 -0
  140. package/dist/db/enginePrismaSchema.cjs +85 -0
  141. package/dist/db/enginePrismaSchema.d.cts +5 -0
  142. package/dist/db/enginePrismaSchema.d.mts +5 -0
  143. package/dist/db/enginePrismaSchema.mjs +84 -0
  144. package/dist/db/engineSql.cjs +26 -0
  145. package/dist/db/engineSql.d.cts +17 -0
  146. package/dist/db/engineSql.d.mts +17 -0
  147. package/dist/db/engineSql.mjs +25 -0
  148. package/dist/db/engineSqlMigrator.cjs +66 -0
  149. package/dist/db/engineSqlMigrator.mjs +66 -0
  150. package/dist/db/fixedMigratorShared.cjs +0 -11
  151. package/dist/db/fixedMigratorShared.mjs +1 -8
  152. package/dist/db/index.cjs +23 -8
  153. package/dist/db/index.d.cts +10 -4
  154. package/dist/db/index.d.mts +10 -4
  155. package/dist/db/index.mjs +16 -8
  156. package/dist/db/releaseCatalog.cjs +20 -44
  157. package/dist/db/releaseCatalog.d.cts +2 -3
  158. package/dist/db/releaseCatalog.d.mts +2 -3
  159. package/dist/db/releaseCatalog.mjs +20 -44
  160. package/dist/db/schemaSettings.cjs +63 -0
  161. package/dist/db/schemaSettings.d.cts +12 -0
  162. package/dist/db/schemaSettings.d.mts +12 -0
  163. package/dist/db/schemaSettings.mjs +62 -0
  164. package/dist/db/settingsMigrator.cjs +92 -0
  165. package/dist/db/settingsMigrator.mjs +89 -0
  166. package/dist/db/types.cjs +3 -12
  167. package/dist/db/types.d.cts +26 -69
  168. package/dist/db/types.d.mts +26 -69
  169. package/dist/db/types.mjs +2 -11
  170. package/dist/db/updateArtifacts.cjs +38 -68
  171. package/dist/db/updateArtifacts.mjs +40 -69
  172. package/dist/handler.cjs +72 -43
  173. package/dist/handler.d.cts +3 -6
  174. package/dist/handler.d.mts +3 -6
  175. package/dist/handler.mjs +73 -43
  176. package/dist/handlerAdminRoutes.cjs +375 -0
  177. package/dist/handlerAdminRoutes.mjs +373 -0
  178. package/dist/handlerParameters.cjs +6 -11
  179. package/dist/handlerParameters.mjs +6 -10
  180. package/dist/handlerReleaseCatalogRoutes.cjs +11 -14
  181. package/dist/handlerReleaseCatalogRoutes.mjs +11 -13
  182. package/dist/handlerTypes.d.cts +2 -56
  183. package/dist/handlerTypes.d.mts +2 -56
  184. package/dist/handlerVersionRoutes.cjs +20 -4
  185. package/dist/handlerVersionRoutes.d.cts +1 -0
  186. package/dist/handlerVersionRoutes.d.mts +1 -0
  187. package/dist/handlerVersionRoutes.mjs +20 -4
  188. package/dist/index.cjs +4 -7
  189. package/dist/index.d.cts +10 -9
  190. package/dist/index.d.mts +10 -9
  191. package/dist/index.mjs +4 -4
  192. package/dist/insights/domain.d.cts +53 -70
  193. package/dist/insights/domain.d.mts +53 -70
  194. package/dist/insights/errors.cjs +35 -8
  195. package/dist/insights/errors.mjs +35 -8
  196. package/dist/insights/eventInput.cjs +64 -24
  197. package/dist/insights/eventInput.mjs +63 -25
  198. package/dist/insights/provider.cjs +356 -0
  199. package/dist/insights/provider.d.cts +6 -0
  200. package/dist/insights/provider.d.mts +6 -0
  201. package/dist/insights/provider.mjs +355 -0
  202. package/dist/insights/queryInput.cjs +78 -43
  203. package/dist/insights/queryInput.mjs +76 -40
  204. package/dist/insights/routes.cjs +94 -34
  205. package/dist/insights/routes.mjs +93 -35
  206. package/dist/insights/types.d.cts +27 -12
  207. package/dist/insights/types.d.mts +27 -12
  208. package/dist/node.d.cts +1 -2
  209. package/dist/node.d.mts +1 -2
  210. package/dist/package.cjs +1 -1
  211. package/dist/package.mjs +1 -1
  212. package/dist/plugins/api-keys/index.cjs +50 -0
  213. package/dist/plugins/api-keys/index.d.cts +85 -0
  214. package/dist/plugins/api-keys/index.d.mts +85 -0
  215. package/dist/plugins/api-keys/index.mjs +47 -0
  216. package/dist/plugins/api-keys/model.cjs +58 -0
  217. package/dist/plugins/api-keys/model.d.cts +8 -0
  218. package/dist/plugins/api-keys/model.d.mts +8 -0
  219. package/dist/plugins/api-keys/model.mjs +58 -0
  220. package/dist/plugins/api-keys/schema.cjs +38 -0
  221. package/dist/plugins/api-keys/schema.d.cts +44 -0
  222. package/dist/plugins/api-keys/schema.d.mts +44 -0
  223. package/dist/plugins/api-keys/schema.mjs +39 -0
  224. package/dist/plugins/builtIn.cjs +7 -0
  225. package/dist/plugins/builtIn.mjs +6 -0
  226. package/dist/plugins/definePlugin.cjs +5 -0
  227. package/dist/plugins/definePlugin.d.cts +73 -0
  228. package/dist/plugins/definePlugin.d.mts +73 -0
  229. package/dist/plugins/definePlugin.mjs +5 -0
  230. package/dist/plugins/index.cjs +17 -0
  231. package/dist/plugins/index.d.cts +9 -0
  232. package/dist/plugins/index.d.mts +9 -0
  233. package/dist/plugins/index.mjs +7 -0
  234. package/dist/plugins/insights/index.cjs +48 -0
  235. package/dist/plugins/insights/index.d.cts +295 -0
  236. package/dist/plugins/insights/index.d.mts +295 -0
  237. package/dist/plugins/insights/index.mjs +44 -0
  238. package/dist/plugins/insights/model.cjs +17 -0
  239. package/dist/plugins/insights/model.d.cts +10 -0
  240. package/dist/plugins/insights/model.d.mts +10 -0
  241. package/dist/plugins/insights/model.mjs +17 -0
  242. package/dist/plugins/insights/reads.cjs +471 -0
  243. package/dist/plugins/insights/reads.mjs +466 -0
  244. package/dist/plugins/insights/recordEvent.cjs +135 -0
  245. package/dist/plugins/insights/recordEvent.d.cts +13 -0
  246. package/dist/plugins/insights/recordEvent.d.mts +13 -0
  247. package/dist/plugins/insights/recordEvent.mjs +132 -0
  248. package/dist/plugins/insights/schema.cjs +347 -0
  249. package/dist/plugins/insights/schema.d.cts +258 -0
  250. package/dist/plugins/insights/schema.d.mts +258 -0
  251. package/dist/plugins/insights/schema.mjs +344 -0
  252. package/dist/storageAccess.cjs +0 -1
  253. package/dist/types/index.d.cts +2 -29
  254. package/dist/types/index.d.mts +2 -29
  255. package/package.json +30 -7
  256. package/src/adapters/drizzle.conformance.integration.spec.ts +34 -0
  257. package/src/adapters/drizzle.readBudgets.integration.spec.ts +41 -0
  258. package/src/adapters/drizzle.spec.ts +277 -208
  259. package/src/adapters/drizzle.ts +48 -128
  260. package/src/adapters/drizzleExecutor.ts +166 -0
  261. package/src/adapters/kysely.conformance.integration.spec.ts +36 -0
  262. package/src/adapters/kysely.readBudgets.integration.spec.ts +42 -0
  263. package/src/adapters/kysely.spec.ts +212 -117
  264. package/src/adapters/kysely.ts +32 -87
  265. package/src/adapters/kyselyExecutor.ts +53 -0
  266. package/src/adapters/mongodb.integration.spec.ts +180 -0
  267. package/src/adapters/mongodb.readBudgets.integration.spec.ts +61 -0
  268. package/src/adapters/mongodb.ts +36 -65
  269. package/src/adapters/mongodbAdapter.ts +293 -0
  270. package/src/adapters/prisma.conformance.integration.spec.ts +36 -0
  271. package/src/adapters/prisma.integration.spec.ts +138 -0
  272. package/src/adapters/prisma.readBudgets.integration.spec.ts +40 -0
  273. package/src/adapters/prisma.spec.ts +226 -173
  274. package/src/adapters/prisma.ts +60 -451
  275. package/src/adapters/prismaExecutor.ts +107 -0
  276. package/src/adapters/prismaTestClients.ts +175 -0
  277. package/src/adapters/sqlProviders.ts +14 -0
  278. package/src/apiKeys.integration.spec.ts +19 -119
  279. package/src/apiKeys.spec.ts +39 -35
  280. package/src/apiKeys.ts +2 -8
  281. package/src/assembly/assemblePlugins.ts +269 -0
  282. package/src/assembly/assembly.spec.ts +325 -0
  283. package/src/assembly/assembly.types.spec.ts +155 -0
  284. package/src/assembly/builtInRoutes.spec.ts +213 -0
  285. package/src/assembly/databasePlugins.spec.ts +71 -0
  286. package/src/assembly/databasePlugins.ts +96 -0
  287. package/src/core/api.ts +139 -0
  288. package/src/core/baseCandidates.spec.ts +378 -0
  289. package/src/core/baseCandidates.ts +136 -0
  290. package/src/core/index.ts +44 -0
  291. package/src/core/operations.spec.ts +415 -0
  292. package/src/core/operations.ts +551 -0
  293. package/src/core/reads.spec.ts +300 -0
  294. package/src/core/reads.ts +417 -0
  295. package/src/core/releases.spec.ts +308 -0
  296. package/src/core/releases.ts +345 -0
  297. package/src/core/schema.ts +173 -0
  298. package/src/core/writes.ts +160 -0
  299. package/src/createHotUpdaterCore.ts +191 -167
  300. package/src/database/cursor.ts +65 -0
  301. package/src/database/database.ts +335 -0
  302. package/src/database/database.types.spec.ts +135 -0
  303. package/src/database/definitions.ts +72 -0
  304. package/src/database/engine.ts +62 -0
  305. package/src/database/engineAggregates.spec.ts +539 -0
  306. package/src/database/engineAggregates.ts +193 -0
  307. package/src/database/engineReads.spec.ts +219 -0
  308. package/src/database/engineReads.ts +302 -0
  309. package/src/database/engineTransaction.spec.ts +710 -0
  310. package/src/database/engineTransaction.ts +588 -0
  311. package/src/database/errors.ts +30 -0
  312. package/src/database/fence.spec.ts +223 -0
  313. package/src/database/fence.ts +171 -0
  314. package/src/database/index.ts +154 -0
  315. package/src/database/kv/kvAdapter.conformance.integration.spec.ts +17 -0
  316. package/src/database/kv/kvAdapter.readBudgets.integration.spec.ts +17 -0
  317. package/src/database/kv/kvAdapter.spec.ts +468 -0
  318. package/src/database/kv/kvAdapter.ts +450 -0
  319. package/src/database/kv/kvTestStore.ts +91 -0
  320. package/src/database/memory.readBudgets.integration.spec.ts +13 -0
  321. package/src/database/resolveSchema.spec.ts +230 -0
  322. package/src/database/resolveSchema.ts +372 -0
  323. package/src/database/schema.ts +169 -0
  324. package/src/database/schema.types.spec.ts +94 -0
  325. package/src/database/sql/docker-compose.yml +36 -0
  326. package/src/database/sql/sqlAdapter.integration.spec.ts +148 -0
  327. package/src/database/sql/sqlAdapter.readBudgets.integration.spec.ts +109 -0
  328. package/src/database/sql/sqlAdapter.spec.ts +255 -0
  329. package/src/database/sql/sqlAdapter.ts +532 -0
  330. package/src/database/sql/sqlSchema.ts +205 -0
  331. package/src/database/sql/sqlTestExecutors.ts +183 -0
  332. package/src/databaseTestSuite.spec.ts +39 -0
  333. package/src/db/builtInDatabase.ts +149 -0
  334. package/src/db/bundleRows.spec.ts +3 -3
  335. package/src/db/createBundleDiff.spec.ts +43 -29
  336. package/src/db/createBundleDiff.ts +13 -7
  337. package/src/db/engineDrizzleSchema.ts +72 -0
  338. package/src/db/engineMigrator.ts +105 -0
  339. package/src/db/enginePrismaSchema.ts +147 -0
  340. package/src/db/engineSql.spec.ts +129 -0
  341. package/src/db/engineSql.ts +48 -0
  342. package/src/db/engineSqlMigrator.ts +116 -0
  343. package/src/db/fixedMigratorShared.ts +1 -20
  344. package/src/db/index.spec.ts +116 -824
  345. package/src/db/index.ts +43 -14
  346. package/src/db/pluginTables.spec.ts +218 -0
  347. package/src/db/releaseCatalog.ts +48 -90
  348. package/src/db/schemaSettings.ts +104 -0
  349. package/src/db/settingsMigrator.spec.ts +65 -0
  350. package/src/db/settingsMigrator.ts +152 -0
  351. package/src/db/types.ts +25 -165
  352. package/src/db/updateArtifacts.spec.ts +170 -294
  353. package/src/db/updateArtifacts.ts +74 -142
  354. package/src/db/updateCheck.bench.ts +47 -0
  355. package/src/handler-standalone.integration.spec.ts +204 -412
  356. package/src/handler.spec.ts +134 -51
  357. package/src/handler.testFixtures.ts +14 -19
  358. package/src/handler.ts +163 -75
  359. package/src/handlerAdminRoutes.spec.ts +183 -0
  360. package/src/handlerAdminRoutes.ts +536 -0
  361. package/src/handlerAuth.integration.spec.ts +3 -3
  362. package/src/handlerManagement.spec.ts +136 -196
  363. package/src/handlerReleaseCatalogRoutes.ts +15 -17
  364. package/src/handlerTypes.ts +3 -80
  365. package/src/handlerVersionRoutes.ts +20 -7
  366. package/src/index.ts +7 -14
  367. package/src/insights/domain.ts +56 -77
  368. package/src/insights/errors.spec.ts +48 -0
  369. package/src/insights/errors.ts +50 -6
  370. package/src/insights/eventInput.ts +80 -27
  371. package/src/insights/insights.integration.spec.ts +525 -44
  372. package/src/insights/provider.spec.ts +574 -0
  373. package/src/insights/provider.ts +667 -0
  374. package/src/insights/queryInput.ts +113 -73
  375. package/src/insights/routes.ts +125 -69
  376. package/src/insights/types.ts +47 -36
  377. package/src/lintRules.spec.ts +76 -0
  378. package/src/plugins/api-keys/apiKeysPlugin.spec.ts +172 -0
  379. package/src/plugins/api-keys/index.ts +66 -0
  380. package/src/plugins/api-keys/model.ts +69 -0
  381. package/src/plugins/api-keys/schema.ts +22 -0
  382. package/src/plugins/builtIn.ts +5 -0
  383. package/src/plugins/definePlugin.ts +100 -0
  384. package/src/plugins/index.ts +55 -0
  385. package/src/plugins/insights/index.ts +86 -0
  386. package/src/plugins/insights/insightsRollout.integration.spec.ts +187 -0
  387. package/src/plugins/insights/model.spec.ts +66 -0
  388. package/src/plugins/insights/model.ts +19 -0
  389. package/src/plugins/insights/reads.spec.ts +725 -0
  390. package/src/plugins/insights/reads.ts +707 -0
  391. package/src/plugins/insights/recordEvent.spec.ts +443 -0
  392. package/src/plugins/insights/recordEvent.ts +238 -0
  393. package/src/plugins/insights/schema.ts +229 -0
  394. package/src/plugins/pluginTestHarness.spec.ts +56 -0
  395. package/src/readBudgets.testFixtures.ts +15 -0
  396. package/src/releaseCatalogRoutes.integration.spec.ts +47 -92
  397. package/src/runtime.spec.ts +91 -77
  398. package/src/runtime.testFixtures.ts +28 -44
  399. package/src/runtimeBundles.integration.spec.ts +112 -0
  400. package/src/testUtilsMutation.integration.spec.ts +215 -0
  401. package/src/testUtilsPackage.integration.spec.ts +176 -0
  402. package/src/types/index.ts +0 -32
  403. package/dist/adapters/databaseConstraintErrors.cjs +0 -23
  404. package/dist/adapters/databaseConstraintErrors.mjs +0 -21
  405. package/dist/adapters/databasePluginUtils.cjs +0 -117
  406. package/dist/adapters/databasePluginUtils.mjs +0 -106
  407. package/dist/adapters/drizzleCrud.cjs +0 -250
  408. package/dist/adapters/drizzleCrud.mjs +0 -249
  409. package/dist/adapters/drizzleLazyDB.cjs +0 -101
  410. package/dist/adapters/drizzleLazyDB.mjs +0 -101
  411. package/dist/adapters/drizzleQuery.cjs +0 -68
  412. package/dist/adapters/drizzleQuery.mjs +0 -67
  413. package/dist/adapters/kyselyCrud.cjs +0 -254
  414. package/dist/adapters/kyselyCrud.mjs +0 -253
  415. package/dist/adapters/kyselyQuery.cjs +0 -56
  416. package/dist/adapters/kyselyQuery.mjs +0 -55
  417. package/dist/adapters/mongodbCollections.cjs +0 -36
  418. package/dist/adapters/mongodbCollections.mjs +0 -30
  419. package/dist/adapters/mongodbQuery.cjs +0 -77
  420. package/dist/adapters/mongodbQuery.mjs +0 -70
  421. package/dist/adapters/mongodbReads.cjs +0 -148
  422. package/dist/adapters/mongodbReads.mjs +0 -147
  423. package/dist/adapters/mongodbWrites.cjs +0 -134
  424. package/dist/adapters/mongodbWrites.mjs +0 -133
  425. package/dist/adapters/prismaQuery.cjs +0 -58
  426. package/dist/adapters/prismaQuery.mjs +0 -56
  427. package/dist/adapters/prismaRows.cjs +0 -198
  428. package/dist/adapters/prismaRows.mjs +0 -188
  429. package/dist/db/databasePluginCore.cjs +0 -138
  430. package/dist/db/databasePluginCore.mjs +0 -137
  431. package/dist/db/fixedMigrator.cjs +0 -79
  432. package/dist/db/fixedMigrator.mjs +0 -78
  433. package/dist/db/fixedMigratorMongo.cjs +0 -319
  434. package/dist/db/fixedMigratorMongo.mjs +0 -319
  435. package/dist/db/mongoMigrationExecution.cjs +0 -11
  436. package/dist/db/mongoMigrationExecution.mjs +0 -11
  437. package/dist/db/schema/mongodb.cjs +0 -25
  438. package/dist/db/schema/mongodb.mjs +0 -25
  439. package/dist/db/schema/registry.cjs +0 -21
  440. package/dist/db/schema/registry.mjs +0 -17
  441. package/dist/db/schema/sql.cjs +0 -101
  442. package/dist/db/schema/sql.mjs +0 -97
  443. package/dist/db/schema/sqlOperations.cjs +0 -27
  444. package/dist/db/schema/sqlOperations.mjs +0 -26
  445. package/dist/db/schemaGenerators.cjs +0 -256
  446. package/dist/db/schemaGenerators.mjs +0 -254
  447. package/dist/db/schemaReadiness.cjs +0 -24
  448. package/dist/db/schemaReadiness.d.cts +0 -8
  449. package/dist/db/schemaReadiness.d.mts +0 -8
  450. package/dist/db/schemaReadiness.mjs +0 -23
  451. package/dist/db/sqlMigrationExecution.cjs +0 -67
  452. package/dist/db/sqlMigrationExecution.mjs +0 -66
  453. package/dist/handlerBundleRoutes.cjs +0 -155
  454. package/dist/handlerBundleRoutes.mjs +0 -155
  455. package/dist/handlerReleaseManagementRoutes.cjs +0 -125
  456. package/dist/handlerReleaseManagementRoutes.mjs +0 -124
  457. package/dist/insights/bounded/activeOverview.cjs +0 -87
  458. package/dist/insights/bounded/activeOverview.mjs +0 -85
  459. package/dist/insights/bounded/installationSearch.cjs +0 -42
  460. package/dist/insights/bounded/installationSearch.mjs +0 -42
  461. package/dist/insights/bounded/persistence.cjs +0 -39
  462. package/dist/insights/bounded/persistence.mjs +0 -38
  463. package/dist/insights/bounded/provider.cjs +0 -170
  464. package/dist/insights/bounded/provider.d.cts +0 -7
  465. package/dist/insights/bounded/provider.d.mts +0 -7
  466. package/dist/insights/bounded/provider.mjs +0 -170
  467. package/dist/insights/bounded/scan.cjs +0 -144
  468. package/dist/insights/bounded/scan.mjs +0 -138
  469. package/dist/insights/persistence.d.cts +0 -6
  470. package/dist/insights/persistence.d.mts +0 -6
  471. package/dist/schema/dsl.cjs +0 -103
  472. package/dist/schema/dsl.mjs +0 -87
  473. package/dist/schema/index.cjs +0 -6
  474. package/dist/schema/index.mjs +0 -7
  475. package/dist/schema/settings.cjs +0 -9
  476. package/dist/schema/settings.mjs +0 -9
  477. package/dist/schema/types.cjs +0 -8
  478. package/dist/schema/types.mjs +0 -6
  479. package/dist/schema/v1_0_0.cjs +0 -364
  480. package/dist/schema/v1_0_0.mjs +0 -357
  481. package/src/adapters/databaseConstraintErrors.ts +0 -25
  482. package/src/adapters/databasePluginTestDatabase.ts +0 -106
  483. package/src/adapters/databasePluginUtils.spec.ts +0 -29
  484. package/src/adapters/databasePluginUtils.ts +0 -214
  485. package/src/adapters/drizzleCrud.ts +0 -419
  486. package/src/adapters/drizzleLazyDB.ts +0 -257
  487. package/src/adapters/drizzleQuery.ts +0 -164
  488. package/src/adapters/kyselyCrud.ts +0 -588
  489. package/src/adapters/kyselyQuery.ts +0 -128
  490. package/src/adapters/mongodb.spec.ts +0 -141
  491. package/src/adapters/mongodbCollections.ts +0 -62
  492. package/src/adapters/mongodbQuery.ts +0 -226
  493. package/src/adapters/mongodbReads.ts +0 -311
  494. package/src/adapters/mongodbRows.spec.ts +0 -64
  495. package/src/adapters/mongodbRows.ts +0 -118
  496. package/src/adapters/mongodbTestClient.ts +0 -342
  497. package/src/adapters/mongodbTestFilter.ts +0 -166
  498. package/src/adapters/mongodbWrites.ts +0 -260
  499. package/src/adapters/prismaQuery.ts +0 -129
  500. package/src/adapters/prismaRows.spec.ts +0 -98
  501. package/src/adapters/prismaRows.ts +0 -301
  502. package/src/adapters/prismaTestClient.ts +0 -396
  503. package/src/calculatePagination.ts +0 -34
  504. package/src/db/databasePluginCore.spec.ts +0 -62
  505. package/src/db/databasePluginCore.testFixtures.ts +0 -76
  506. package/src/db/databasePluginCore.ts +0 -185
  507. package/src/db/databasePluginUpdateCheck.bench.ts +0 -107
  508. package/src/db/fixedMigrator.spec.ts +0 -231
  509. package/src/db/fixedMigrator.ts +0 -147
  510. package/src/db/fixedMigratorMongo.spec.ts +0 -192
  511. package/src/db/fixedMigratorMongo.ts +0 -425
  512. package/src/db/hotUpdaterSchema.ts +0 -5
  513. package/src/db/mongoMigrationExecution.ts +0 -23
  514. package/src/db/schema/definitions.ts +0 -1
  515. package/src/db/schema/mongodb.ts +0 -40
  516. package/src/db/schema/registry.ts +0 -55
  517. package/src/db/schema/sql.ts +0 -241
  518. package/src/db/schema/sqlOperations.ts +0 -63
  519. package/src/db/schema/types.ts +0 -1
  520. package/src/db/schemaGenerators.ts +0 -466
  521. package/src/db/schemaReadiness.ts +0 -34
  522. package/src/db/sqlMigrationExecution.spec.ts +0 -65
  523. package/src/db/sqlMigrationExecution.ts +0 -108
  524. package/src/db/types.spec.ts +0 -55
  525. package/src/handlerBundleRoutes.ts +0 -259
  526. package/src/handlerReleaseManagementRoutes.ts +0 -213
  527. package/src/insights/bounded/activeOverview.spec.ts +0 -189
  528. package/src/insights/bounded/activeOverview.ts +0 -148
  529. package/src/insights/bounded/installationSearch.spec.ts +0 -130
  530. package/src/insights/bounded/installationSearch.ts +0 -69
  531. package/src/insights/bounded/persistence.ts +0 -43
  532. package/src/insights/bounded/provider.spec.ts +0 -219
  533. package/src/insights/bounded/provider.ts +0 -229
  534. package/src/insights/bounded/scan.ts +0 -235
  535. package/src/insights/persistence.ts +0 -10
  536. package/src/schema/dsl-all-versions.spec.ts +0 -35
  537. package/src/schema/dsl.ts +0 -187
  538. package/src/schema/index.ts +0 -10
  539. package/src/schema/settings.ts +0 -15
  540. package/src/schema/types.ts +0 -79
  541. package/src/schema/v1_0_0.spec.ts +0 -146
  542. package/src/schema/v1_0_0.ts +0 -465
@@ -2,10 +2,8 @@ import { PGlite } from "@electric-sql/pglite";
2
2
  import type { Bundle } from "@hot-updater/core";
3
3
  import { NIL_UUID } from "@hot-updater/core";
4
4
  import { createStoragePlugin } from "@hot-updater/plugin-core";
5
- import { sql } from "drizzle-orm";
6
5
  import { Kysely } from "kysely";
7
6
  import { PGliteDialect } from "kysely-pglite-dialect";
8
- import { type ClientSession, MongoClient } from "mongodb";
9
7
  import {
10
8
  afterAll,
11
9
  afterEach,
@@ -17,143 +15,24 @@ import {
17
15
  vi,
18
16
  } from "vitest";
19
17
 
20
- import { createInMemoryDatabasePlugin } from "../../../test-utils/test/inMemoryDatabasePlugin";
21
18
  import { drizzleAdapter } from "../adapters/drizzle";
22
19
  import { kyselyAdapter } from "../adapters/kysely";
23
- import { mongoAdapter } from "../adapters/mongodb";
24
20
  import { prismaAdapter } from "../adapters/prisma";
21
+ import { HotUpdaterSchemaMigrationRequiredError } from "../database/fence";
25
22
  import {
26
23
  createHotUpdater as createRuntimeHotUpdater,
27
24
  type CreateHotUpdaterOptions,
28
25
  } from "../index";
29
- import { bundleToRow } from "./bundleRows";
30
- import { createTableSql, hotUpdaterSchemaVersions } from "./hotUpdaterSchema";
31
26
  import { createMigrator, generateSchema } from "./index";
32
- import { generateDrizzleSchema } from "./schemaGenerators";
33
- import type { DatabasePlugin, ORMProvider } from "./types";
34
27
 
35
28
  const createHotUpdater = (
36
29
  options: Omit<CreateHotUpdaterOptions, "clientAccess">,
37
30
  ) =>
38
31
  createRuntimeHotUpdater({
39
32
  ...options,
40
- clientAccess: { type: "public" },
33
+ clientAccess: "public",
41
34
  });
42
35
 
43
- const RAW_PRISMA_SCHEMA = `model bundles {
44
- id String @id
45
- platform String
46
- should_force_update Boolean
47
- enabled Boolean
48
- file_hash String
49
- git_commit_hash String?
50
- message String?
51
- channel String @default("production")
52
- storage_uri String
53
- target_app_version String?
54
- fingerprint_hash String?
55
- metadata Json
56
- manifest_storage_uri String?
57
- manifest_file_hash String?
58
- asset_base_storage_uri String?
59
- rollout_cohort_count Int @default(1000)
60
- target_cohorts Json?
61
- }
62
- model bundle_patches {
63
- id String @id
64
- bundle_id String
65
- base_bundle_id String
66
- base_file_hash String
67
- patch_file_hash String
68
- patch_storage_uri String
69
- order_index Int @default(0)
70
- bundle bundles @relation("bundle_patches_bundles_patches", fields: [bundle_id], references: [id], onUpdate: Restrict, onDelete: Cascade)
71
- baseBundle bundles @relation("bundle_patches_bundles_baseForPatches", fields: [base_bundle_id], references: [id], onUpdate: Restrict, onDelete: Cascade)
72
- }
73
- model private_hot_updater_settings {
74
- key String @id
75
- value String @default("0.36.0")
76
- }`;
77
-
78
- const RAW_DRIZZLE_SCHEMA = `import { relations } from "drizzle-orm";
79
- import {
80
- pgTable,
81
- uuid,
82
- text,
83
- boolean,
84
- json,
85
- integer,
86
- varchar,
87
- foreignKey,
88
- } from "drizzle-orm/pg-core";
89
-
90
- export const bundles = pgTable("bundles", {
91
- id: uuid("id").primaryKey().notNull(),
92
- platform: text("platform").notNull(),
93
- should_force_update: boolean("should_force_update").notNull(),
94
- enabled: boolean("enabled").notNull(),
95
- file_hash: text("file_hash").notNull(),
96
- git_commit_hash: text("git_commit_hash"),
97
- message: text("message"),
98
- channel: text("channel").notNull().default("production"),
99
- storage_uri: text("storage_uri").notNull(),
100
- target_app_version: text("target_app_version"),
101
- fingerprint_hash: text("fingerprint_hash"),
102
- metadata: json("metadata").notNull(),
103
- manifest_storage_uri: text("manifest_storage_uri"),
104
- manifest_file_hash: text("manifest_file_hash"),
105
- asset_base_storage_uri: text("asset_base_storage_uri"),
106
- rollout_cohort_count: integer("rollout_cohort_count")
107
- .notNull()
108
- .default(1000),
109
- target_cohorts: json("target_cohorts"),
110
- })
111
-
112
- export const bundle_patches = pgTable(
113
- "bundle_patches",
114
- {
115
- id: varchar("id", { length: 255 }).primaryKey().notNull(),
116
- bundle_id: uuid("bundle_id").notNull(),
117
- base_bundle_id: uuid("base_bundle_id").notNull(),
118
- base_file_hash: text("base_file_hash").notNull(),
119
- patch_file_hash: text("patch_file_hash").notNull(),
120
- patch_storage_uri: text("patch_storage_uri").notNull(),
121
- order_index: integer("order_index").notNull().default(0),
122
- }, (table) => [
123
- foreignKey({
124
- columns: [table.bundle_id],
125
- foreignColumns: [bundles.id],
126
- name: "bundle_patches_bundle_id_fk",
127
- })
128
- .onUpdate("restrict")
129
- .onDelete("cascade"),
130
- foreignKey({
131
- columns: [table.base_bundle_id],
132
- foreignColumns: [bundles.id],
133
- name: "bundle_patches_base_bundle_id_fk",
134
- })
135
- .onUpdate("restrict")
136
- .onDelete("cascade"),
137
- ])
138
-
139
- export const private_hot_updater_settings = pgTable("private_hot_updater_settings", {
140
- key: varchar("key", { length: 255 }).primaryKey().notNull(),
141
- version: varchar("version", { length: 255 }).notNull().default("0.36.0"),
142
- })
143
-
144
- export const bundle_patchesRelations = relations(bundle_patches, ({ one, many }) => ({
145
- bundle: one(bundles, {
146
- relationName: "bundle_patches_bundles_patches",
147
- fields: [bundle_patches.bundle_id],
148
- references: [bundles.id],
149
- }),
150
- baseBundle: one(bundles, {
151
- relationName: "bundle_patches_bundles_baseForPatches",
152
- fields: [bundle_patches.base_bundle_id],
153
- references: [bundles.id],
154
- }),
155
- }));`;
156
-
157
36
  function createTestStoragePlugin(
158
37
  protocol: string,
159
38
  readText: (storageUri: string) => Promise<string | null> = async () => null,
@@ -182,38 +61,6 @@ function createTestStoragePlugin(
182
61
  });
183
62
  }
184
63
 
185
- function createSchemaOnlyAdapter({
186
- code,
187
- name,
188
- provider,
189
- path,
190
- }: {
191
- code: string;
192
- name: string;
193
- provider: ORMProvider;
194
- path: string;
195
- }): DatabasePlugin {
196
- return {
197
- ...createInMemoryDatabasePlugin(),
198
- adapterName: name,
199
- provider,
200
- generateSchema: (_version, schemaName = name) => ({
201
- code,
202
- path: path || schemaName,
203
- }),
204
- };
205
- }
206
-
207
- const transactionBundle: Bundle = {
208
- archiveByteSize: 1_024,
209
- id: "00000000-0000-0000-0000-000000000777",
210
- platform: "ios",
211
- fileHash: "transaction-hash",
212
- gitCommitHash: null,
213
- storageUri: "s3://test-bucket/transaction.zip",
214
- };
215
- const transactionChannelId = "00000000-0000-0000-0000-000000000700";
216
-
217
64
  describe("server/db hotUpdater (PGlite + Kysely)", async () => {
218
65
  const db = new PGlite();
219
66
 
@@ -239,51 +86,8 @@ describe("server/db hotUpdater (PGlite + Kysely)", async () => {
239
86
  createTestStoragePlugin("gs", readStoredText),
240
87
  ],
241
88
  });
242
- const prismaSchemaHotUpdater = createHotUpdater({
243
- database: createSchemaOnlyAdapter({
244
- code: RAW_PRISMA_SCHEMA,
245
- name: "prisma",
246
- path: "schema.prisma",
247
- provider: "postgresql",
248
- }),
249
- });
250
- const sqlitePrismaSchemaHotUpdater = createHotUpdater({
251
- database: createSchemaOnlyAdapter({
252
- code: RAW_PRISMA_SCHEMA,
253
- name: "prisma",
254
- path: "schema.prisma",
255
- provider: "sqlite",
256
- }),
257
- });
258
- const drizzleSchemaHotUpdater = createHotUpdater({
259
- database: createSchemaOnlyAdapter({
260
- code: RAW_DRIZZLE_SCHEMA,
261
- name: "drizzle",
262
- path: "hot-updater-schema.ts",
263
- provider: "postgresql",
264
- }),
265
- });
266
-
267
89
  it("uses the default generated schema artifact path for Drizzle", () => {
268
- const adapter = drizzleAdapter({
269
- db: {
270
- _: {
271
- fullSchema: {
272
- bundle_patches: {},
273
- bundles: {},
274
- },
275
- },
276
- $count: vi.fn(),
277
- delete: vi.fn(),
278
- insert: vi.fn(),
279
- query: {
280
- bundle_patches: { findFirst: vi.fn(), findMany: vi.fn() },
281
- bundles: { findFirst: vi.fn(), findMany: vi.fn() },
282
- },
283
- update: vi.fn(),
284
- },
285
- provider: "sqlite",
286
- });
90
+ const adapter = drizzleAdapter({ db: {}, provider: "sqlite" });
287
91
 
288
92
  expect(adapter.generateSchema?.("latest").path).toBe(
289
93
  "hot-updater-schema.ts",
@@ -301,145 +105,71 @@ describe("server/db hotUpdater (PGlite + Kysely)", async () => {
301
105
 
302
106
  beforeEach(async () => {
303
107
  storageTexts.clear();
304
- await db.exec("DELETE FROM release_catalogs");
305
- await db.exec("DELETE FROM releases");
306
- await db.exec("DELETE FROM bundle_patches");
307
- await db.exec("DELETE FROM bundles");
308
- await db.exec("DELETE FROM channels");
108
+ // Every table but the settings rows, aggregates included.
109
+ const { rows } = await db.query<{ tablename: string }>(
110
+ "SELECT tablename FROM pg_tables WHERE schemaname = 'public' AND tablename <> 'private_hot_updater_settings'",
111
+ );
112
+ await db.exec(
113
+ `TRUNCATE ${rows.map(({ tablename }) => `"${tablename}"`).join(", ")}`,
114
+ );
309
115
  });
310
116
 
117
+ /** Stores a bundle with a disabled release, one deploy each. */
118
+ const deployBundle = (bundle: Bundle) =>
119
+ hotUpdater.core.deploy([
120
+ {
121
+ bundle,
122
+ release: {
123
+ channel: "production",
124
+ enabled: false,
125
+ fingerprintHash: null,
126
+ message: null,
127
+ shouldForceUpdate: false,
128
+ targetAppVersion: "*",
129
+ },
130
+ },
131
+ ]);
132
+
311
133
  afterAll(async () => {
312
134
  await kysely.destroy();
313
135
  await db.close();
314
136
  });
315
137
 
316
138
  describe("schema generation", () => {
317
- it("includes relations, defaults, and indexes in Prisma output", () => {
318
- const code = generateSchema(prismaSchemaHotUpdater, "latest").code;
319
-
320
- expect(code).toContain('metadata Json @default("{}")');
321
- expect(code).toContain('value String @default("1.0.0")');
322
- expect(code).toContain("model channels {");
323
- expect(code).toContain("id String @db.VarChar(255) @id");
324
- expect(code).toContain("name String @db.VarChar(255)");
325
- expect(code).toContain('@@unique([name], map: "channels_name_key")');
326
- expect(code).toContain("channel_id String @db.VarChar(255)");
327
- expect(code).toContain(
328
- 'channelRecord channels @relation("releases_channels", fields: [channel_id], references: [id], onUpdate: Restrict, onDelete: Restrict)',
329
- );
330
- expect(code).toContain(
331
- 'patches bundle_patches[] @relation("bundle_patches_bundles_patches")',
332
- );
333
- expect(code).toContain(
334
- 'baseForPatches bundle_patches[] @relation("bundle_patches_bundles_baseForPatches")',
335
- );
336
- expect(code).toContain(
337
- 'bundle bundles @relation("bundle_patches_bundles_patches"',
338
- );
339
- expect(code).toContain(
340
- 'baseBundle bundles @relation("bundle_patches_bundles_baseForPatches"',
341
- );
342
- expect(code).not.toContain(
343
- '@@index([channel], map: "bundles_channel_idx")',
344
- );
345
- expect(code).toContain(
346
- '@@index([scope_key, id], map: "releases_scope_order_idx")',
347
- );
348
- expect(code).toContain("scope_key String @db.VarChar(2048) @id");
349
- expect(code).not.toContain("bundles_platform_idx");
350
- expect(code).toContain(
351
- '@@index([bundle_id], map: "bundle_patches_bundle_id_idx")',
352
- );
353
- });
354
-
355
- it("omits the metadata JSON default for SQLite Prisma output", () => {
356
- const code = generateSchema(sqlitePrismaSchemaHotUpdater, "latest").code;
357
-
358
- expect(code).toContain("metadata Json");
359
- expect(code).not.toContain('metadata Json @default("{}")');
139
+ it("passes the Prisma adapter's engine models through unchanged", () => {
140
+ const database = prismaAdapter({ prisma: {}, provider: "postgresql" });
141
+ const code = generateSchema(
142
+ createHotUpdater({ database }),
143
+ "latest",
144
+ ).code;
145
+
146
+ expect(code).toBe(database.generateSchema?.("latest").code);
147
+ expect(code).toContain("model bundle_totals {");
148
+ expect(code).toContain("model private_hot_updater_settings {");
360
149
  });
361
150
 
362
151
  it("rejects generating a retired schema snapshot", () => {
363
- expect(() => generateSchema(prismaSchemaHotUpdater, "0.21.0")).toThrow(
364
- "Unsupported Hot Updater schema version: 0.21.0",
365
- );
152
+ const database = prismaAdapter({ prisma: {}, provider: "postgresql" });
153
+ expect(() =>
154
+ generateSchema(createHotUpdater({ database }), "0.21.0"),
155
+ ).toThrow("Invalid version 0.21.0");
366
156
  });
367
157
 
368
- it("includes foreign keys and indexes in Drizzle output", () => {
369
- const code = generateSchema(drizzleSchemaHotUpdater, "latest").code;
370
- const bundlesBlock = code.match(
371
- /export const bundles = [\s\S]*?(?=\n\nexport const bundle_patches = )/,
372
- )?.[0];
373
- const bundlePatchesBlock = code.match(
374
- /export const bundle_patches = [\s\S]*?(?=\n\nexport const bundle_patchesRelations = )/,
375
- )?.[0];
158
+ it("passes the Drizzle adapter's engine schema through unchanged", () => {
159
+ const database = drizzleAdapter({ db: {}, provider: "postgresql" });
160
+ const code = generateSchema(
161
+ createHotUpdater({ database }),
162
+ "latest",
163
+ ).code;
376
164
 
377
- expect(code).toContain(
378
- 'metadata: json("metadata").notNull().default({})',
379
- );
380
- expect(code).toContain('name: "bundle_patches_bundle_id_fk"');
381
- expect(code).toContain('name: "bundle_patches_base_bundle_id_fk"');
382
- expect(code).toContain('.onDelete("cascade")');
383
- expect(bundlesBlock).not.toContain("bundles_channel_idx");
384
- expect(bundlesBlock).not.toContain("bundles_platform_idx");
385
- expect(bundlesBlock).not.toContain("target_app_version");
386
- expect(bundlesBlock).not.toContain(
387
- 'index("bundle_patches_bundle_id_idx").on(table.bundle_id)',
388
- );
389
- expect(bundlePatchesBlock).toContain(
390
- 'index("bundle_patches_bundle_id_idx").on(table.bundle_id)',
391
- );
392
- expect(code).toContain(
393
- 'index("releases_scope_order_idx").on(table.scope_key, table.id)',
394
- );
395
- expect(code).toContain(
396
- 'scope_key: varchar("scope_key", { length: 2048 }).primaryKey().notNull()',
397
- );
398
- const generatedCode = generateDrizzleSchema("postgresql");
399
- expect(generatedCode).toContain(
400
- 'id: varchar("id", { length: 255 }).primaryKey().notNull()',
401
- );
402
- expect(generatedCode).toContain(
403
- 'version: varchar("version", { length: 255 }).notNull().default("1.0.0")',
404
- );
405
- expect(generatedCode).toContain(
406
- 'uniqueIndex("channels_name_key").on(table.name)',
407
- );
408
- expect(generatedCode).toContain('name: "releases_channel_id_fk"');
409
- expect(generatedCode).toContain(
410
- 'index("releases_channel_platform_order_idx").on(table.channel_id, table.platform, table.id)',
411
- );
412
- expect(generatedCode).not.toContain('key: varchar("key"');
413
- expect(generatedCode).not.toContain('value: text("value"');
165
+ expect(code).toBe(database.generateSchema?.("latest").code);
166
+ expect(code).toContain('pgTable("bundle_totals"');
167
+ expect(code).toContain('pgTable("private_hot_updater_settings"');
414
168
  });
415
169
  });
416
170
 
417
171
  describe("migrator enhancements", () => {
418
- it("registers only schema 1.0.0", () => {
419
- expect(hotUpdaterSchemaVersions.map((schema) => schema.version)).toEqual([
420
- "1.0.0",
421
- ]);
422
- });
423
-
424
- it("omits MySQL defaults for text and JSON columns", () => {
425
- const sql = createTableSql("mysql").join("\n");
426
-
427
- expect(sql).toContain("create table channels");
428
- expect(sql).toContain("metadata json not null");
429
- expect(sql).not.toContain("metadata json not null default");
430
- expect(sql).toContain("`key` varchar(255) primary key");
431
- expect(sql).not.toContain("\nkey varchar(255) primary key");
432
- expect(sql).toContain(
433
- "create table api_keys (\nid varchar(255) primary key not null",
434
- );
435
- expect(sql).not.toContain("create table api_keys (\nid text primary key");
436
- expect(sql).toContain(
437
- "create index bundle_patches_bundle_id_idx on bundle_patches(bundle_id)",
438
- );
439
- expect(sql).not.toContain("bundle_id(255)");
440
- });
441
-
442
- it("adds custom indexes and constraints to generated SQL", async () => {
172
+ it("generates the engine's tables, indexes, and settings rows, without foreign keys", async () => {
443
173
  const migrationDb = new PGlite();
444
174
  const migrationKysely = new Kysely<object>({
445
175
  dialect: new PGliteDialect(migrationDb),
@@ -460,24 +190,15 @@ describe("server/db hotUpdater (PGlite + Kysely)", async () => {
460
190
  const sql = result.getSQL?.() ?? "";
461
191
 
462
192
  expect(sql).toContain(
463
- "create index releases_scope_order_idx on releases",
464
- );
465
- expect(sql).toContain(
466
- "add constraint releases_strategy_target_check check",
193
+ 'CREATE INDEX IF NOT EXISTS "releases_byScope" ON "releases" ("scope_key", "id")',
467
194
  );
195
+ expect(sql).not.toContain("FOREIGN KEY");
468
196
  expect(sql).toContain(
469
- "add constraint bundle_patches_bundle_id_fk foreign key",
197
+ `INSERT INTO "private_hot_updater_settings" ("key", "value", "_v") VALUES ('schema.engine', '1', 0)`,
470
198
  );
471
- expect(sql).toContain(
472
- "create index bundle_patches_bundle_id_idx on bundle_patches",
473
- );
474
- expect(sql).toContain("insert into private_hot_updater_settings");
199
+ // `updateSettings: false` leaves the settings step out of the plan only
475
200
  expect(result.operations).not.toContainEqual(
476
- expect.objectContaining({
477
- sql: expect.stringContaining(
478
- "insert into private_hot_updater_settings",
479
- ),
480
- }),
201
+ expect.objectContaining({ type: "custom" }),
481
202
  );
482
203
  } finally {
483
204
  await migrationKysely.destroy();
@@ -520,121 +241,6 @@ describe("server/db hotUpdater (PGlite + Kysely)", async () => {
520
241
  }
521
242
  });
522
243
 
523
- it("honors soft relation mode by omitting SQL foreign keys", async () => {
524
- const migrationDb = new PGlite();
525
- const migrationKysely = new Kysely<object>({
526
- dialect: new PGliteDialect(migrationDb),
527
- });
528
- const migrationHotUpdater = createHotUpdater({
529
- database: kyselyAdapter({
530
- db: migrationKysely,
531
- provider: "postgresql",
532
- relationMode: "fumadb",
533
- }),
534
- });
535
-
536
- try {
537
- const migrator = createMigrator(migrationHotUpdater);
538
- const result = await migrator.migrateToLatest({
539
- mode: "from-schema",
540
- updateSettings: false,
541
- });
542
- const sql = result.getSQL?.() ?? "";
543
-
544
- expect(sql).not.toContain("add constraint bundle_patches_bundle_id_fk");
545
- expect(result.operations).not.toContainEqual(
546
- expect.objectContaining({
547
- sql: expect.stringContaining("bundle_patches_bundle_id_fk"),
548
- }),
549
- );
550
- } finally {
551
- await migrationKysely.destroy();
552
- await migrationDb.close();
553
- }
554
- });
555
-
556
- it("omits unsupported SQLite alter constraint statements", async () => {
557
- const migrationDb = new PGlite();
558
- const migrationKysely = new Kysely<object>({
559
- dialect: new PGliteDialect(migrationDb),
560
- });
561
- const migrationHotUpdater = createHotUpdater({
562
- database: kyselyAdapter({
563
- db: migrationKysely,
564
- provider: "sqlite",
565
- }),
566
- });
567
-
568
- try {
569
- const migrator = createMigrator(migrationHotUpdater);
570
- const result = await migrator.migrateToLatest({
571
- mode: "from-schema",
572
- updateSettings: false,
573
- });
574
- const sql = result.getSQL?.() ?? "";
575
-
576
- expect(sql).not.toContain("alter table bundles add constraint");
577
- expect(sql).not.toContain("alter table bundle_patches add constraint");
578
- expect(result.operations).not.toContainEqual(
579
- expect.objectContaining({
580
- sql: expect.stringContaining("add constraint"),
581
- }),
582
- );
583
- } finally {
584
- await migrationKysely.destroy();
585
- await migrationDb.close();
586
- }
587
- });
588
-
589
- it("creates MongoDB indexes for runtime query fields", async () => {
590
- const collection = {
591
- find: vi.fn(() => ({
592
- limit: () => ({ toArray: async () => [] }),
593
- })),
594
- listIndexes: () => ({ toArray: async () => [] }),
595
- };
596
- const client = {
597
- db: () => ({
598
- collection: () => collection,
599
- }),
600
- } as unknown as MongoClient;
601
- const mongoHotUpdater = createHotUpdater({
602
- database: mongoAdapter({ client }),
603
- });
604
- const result = await createMigrator(mongoHotUpdater).migrateToLatest({
605
- mode: "from-schema",
606
- });
607
-
608
- expect(result.operations).toEqual(
609
- expect.arrayContaining([
610
- expect.objectContaining({
611
- description:
612
- "Create unique MongoDB index: bundles_id_idx on bundles(id)",
613
- }),
614
- expect.objectContaining({
615
- description:
616
- "Create unique MongoDB index: bundle_patches_id_idx on bundle_patches(id)",
617
- }),
618
- expect.objectContaining({
619
- description:
620
- "Create unique MongoDB index: release_catalogs_scope_key_idx on release_catalogs(scope_key)",
621
- }),
622
- expect.objectContaining({
623
- description:
624
- "Create MongoDB index: releases_fingerprint_hash_idx on releases(fingerprint_hash)",
625
- }),
626
- expect.objectContaining({
627
- description:
628
- "Create MongoDB index: bundles_platform_idx on bundles(platform)",
629
- }),
630
- expect.objectContaining({
631
- description:
632
- "Create MongoDB index: bundle_patches_base_bundle_id_idx on bundle_patches(base_bundle_id)",
633
- }),
634
- ]),
635
- );
636
- });
637
-
638
244
  it("rejects from-database migrations explicitly", async () => {
639
245
  const migrationDb = new PGlite();
640
246
  const migrationKysely = new Kysely<object>({
@@ -675,9 +281,9 @@ describe("server/db hotUpdater (PGlite + Kysely)", async () => {
675
281
 
676
282
  try {
677
283
  await expect(
678
- migrationHotUpdater.getBundles({ limit: 10 }),
284
+ migrationHotUpdater.core.listBundles({ limit: 10 }),
679
285
  ).rejects.toThrow(
680
- "Hot Updater database schema is not initialized for kysely.",
286
+ 'Hot Updater schema setting "schema.engine" for kysely is missing',
681
287
  );
682
288
  } finally {
683
289
  await migrationKysely.destroy();
@@ -707,338 +313,40 @@ describe("server/db hotUpdater (PGlite + Kysely)", async () => {
707
313
  values ('version', '0.21.0');
708
314
  `);
709
315
 
710
- await expect(migrationHotUpdater.getChannels()).rejects.toThrow(
711
- "Hot Updater v1 cannot migrate schema 0.21.0 in place.",
712
- );
316
+ await expect(
317
+ migrationHotUpdater.core.listChannels(),
318
+ ).rejects.toBeInstanceOf(HotUpdaterSchemaMigrationRequiredError);
713
319
  } finally {
714
320
  await migrationKysely.destroy();
715
321
  await migrationDb.close();
716
322
  }
717
323
  });
718
-
719
- it("rejects runtime access when a MongoDB schema is stale", async () => {
720
- const settings = {
721
- find: vi.fn(({ key }: { readonly key: string }) => ({
722
- limit: () => ({
723
- toArray: async () =>
724
- key === "version" ? [{ key, value: "0.21.0" }] : [],
725
- }),
726
- })),
727
- };
728
- const bundles = {
729
- countDocuments: vi.fn(async () => 0),
730
- find: vi.fn(),
731
- findOne: vi.fn(),
732
- };
733
- const patches = {
734
- find: vi.fn(),
735
- };
736
- const client = {
737
- db: () => ({
738
- collection: (name: string) => {
739
- if (name === "private_hot_updater_settings") return settings;
740
- if (name === "bundle_patches") return patches;
741
- return bundles;
742
- },
743
- }),
744
- } as unknown as MongoClient;
745
- const mongoHotUpdater = createHotUpdater({
746
- database: mongoAdapter({ client }),
747
- });
748
-
749
- await expect(mongoHotUpdater.getBundles({ limit: 10 })).rejects.toThrow(
750
- "Hot Updater v1 cannot migrate schema 0.21.0 in place.",
751
- );
752
- expect(bundles.countDocuments).not.toHaveBeenCalled();
753
- });
754
- });
755
-
756
- describe("adapter filters", () => {
757
- it("returns an empty Kysely page for empty set filters", async () => {
758
- const byId = await hotUpdater.getBundles({
759
- limit: 10,
760
- where: { id: { in: [] } },
761
- });
762
- expect(byId.data).toEqual([]);
763
- expect(byId.pagination.total).toBe(0);
764
- });
765
-
766
- it("commits Prisma bundle changes inside a transaction when available", async () => {
767
- const rootBundles = {
768
- count: vi.fn(),
769
- create: vi.fn(),
770
- deleteMany: vi.fn(),
771
- findFirst: vi.fn(),
772
- findMany: vi.fn(),
773
- update: vi.fn(),
774
- upsert: vi.fn(),
775
- };
776
- const rootPatches = {
777
- count: vi.fn(),
778
- create: vi.fn(),
779
- deleteMany: vi.fn(),
780
- findFirst: vi.fn(),
781
- findMany: vi.fn(),
782
- update: vi.fn(),
783
- upsert: vi.fn(),
784
- };
785
- const channels = {
786
- count: vi.fn(),
787
- create: vi.fn(),
788
- deleteMany: vi.fn(),
789
- findFirst: vi.fn(async () => ({
790
- id: transactionChannelId,
791
- name: "production",
792
- })),
793
- findMany: vi.fn(),
794
- update: vi.fn(),
795
- upsert: vi.fn(),
796
- };
797
- const txBundles = {
798
- ...rootBundles,
799
- create: vi.fn(async ({ data }) => data),
800
- };
801
- const txPatches = { ...rootPatches };
802
- const $transaction = vi.fn(
803
- async (operation: (tx: Record<string, unknown>) => Promise<unknown>) =>
804
- operation({
805
- bundle_patches: txPatches,
806
- bundles: txBundles,
807
- channels,
808
- }),
809
- );
810
- const adapter = prismaAdapter({
811
- prisma: {
812
- $transaction,
813
- bundle_patches: rootPatches,
814
- bundles: rootBundles,
815
- channels,
816
- },
817
- provider: "postgresql",
818
- });
819
-
820
- await adapter.commit({
821
- changes: [
822
- {
823
- model: "bundles",
824
- operation: "insert",
825
- row: bundleToRow(transactionBundle),
826
- },
827
- ],
828
- });
829
-
830
- expect($transaction).toHaveBeenCalledTimes(1);
831
- expect(txBundles.create).toHaveBeenCalledTimes(1);
832
- expect(rootBundles.create).not.toHaveBeenCalled();
833
- });
834
-
835
- it("commits Drizzle bundle changes inside a transaction when available", async () => {
836
- const tables = {
837
- bundle_events: {
838
- id: "event_id",
839
- },
840
- bundle_patches: {
841
- bundle_id: "bundle_id",
842
- id: "patch_id",
843
- order_index: "order_index",
844
- },
845
- bundles: {
846
- id: "id",
847
- },
848
- channels: {
849
- id: sql.raw("channel_id"),
850
- name: sql.raw("channel_name"),
851
- },
852
- api_keys: {
853
- id: "access_key_id",
854
- },
855
- release_catalogs: {
856
- scope_key: "scope_key",
857
- },
858
- releases: {
859
- id: "release_id",
860
- scope_key: "scope_key",
861
- },
862
- };
863
- const rootInsert = vi.fn(() => ({
864
- values: vi.fn(() => ({ execute: vi.fn(async () => undefined) })),
865
- }));
866
- const txInsert = vi.fn(() => ({
867
- values: vi.fn(() => ({ execute: vi.fn(async () => undefined) })),
868
- }));
869
- const createDb = (insert: typeof rootInsert) => ({
870
- _: { fullSchema: tables },
871
- $count: vi.fn(),
872
- delete: vi.fn(() => ({
873
- where: vi.fn(async () => undefined),
874
- })),
875
- insert,
876
- query: {
877
- bundle_events: {
878
- findFirst: vi.fn(),
879
- findMany: vi.fn(),
880
- },
881
- bundle_patches: {
882
- findFirst: vi.fn(),
883
- findMany: vi.fn(),
884
- },
885
- bundles: {
886
- findFirst: vi.fn(async () => undefined),
887
- findMany: vi.fn(),
888
- },
889
- channels: {
890
- findFirst: vi.fn(async () => ({
891
- id: transactionChannelId,
892
- name: "production",
893
- })),
894
- findMany: vi.fn(),
895
- },
896
- api_keys: {
897
- findFirst: vi.fn(),
898
- findMany: vi.fn(),
899
- },
900
- release_catalogs: {
901
- findFirst: vi.fn(),
902
- findMany: vi.fn(),
903
- },
904
- releases: {
905
- findFirst: vi.fn(),
906
- findMany: vi.fn(),
907
- },
908
- },
909
- select: vi.fn(),
910
- update: vi.fn(() => ({
911
- set: vi.fn(() => ({
912
- where: vi.fn(async () => undefined),
913
- })),
914
- })),
915
- });
916
- const txDb = createDb(txInsert);
917
- const transaction = vi.fn(
918
- async (operation: (tx: typeof txDb) => Promise<unknown>) =>
919
- operation(txDb),
920
- );
921
- const db = {
922
- ...createDb(rootInsert),
923
- transaction,
924
- };
925
- const adapter = drizzleAdapter({
926
- db,
927
- provider: "postgresql",
928
- });
929
-
930
- await adapter.commit({
931
- changes: [
932
- {
933
- model: "bundles",
934
- operation: "insert",
935
- row: bundleToRow(transactionBundle),
936
- },
937
- ],
938
- });
939
-
940
- expect(transaction).toHaveBeenCalledTimes(1);
941
- expect(txInsert).toHaveBeenCalledTimes(1);
942
- expect(rootInsert).not.toHaveBeenCalled();
943
- });
944
-
945
- it("does not expose an implicit MongoDB transaction", () => {
946
- const bundles = {
947
- countDocuments: vi.fn(),
948
- deleteMany: vi.fn(),
949
- distinct: vi.fn(),
950
- find: vi.fn(),
951
- findOne: vi.fn(),
952
- updateOne: vi.fn(async () => undefined),
953
- };
954
- const patches = {
955
- deleteMany: vi.fn(async () => undefined),
956
- find: vi.fn(),
957
- insertMany: vi.fn(),
958
- };
959
- const client = {
960
- db: () => ({
961
- collection: (name: string) =>
962
- name === "bundle_patches" ? patches : bundles,
963
- }),
964
- } as unknown as MongoClient;
965
- const adapter = mongoAdapter({ client });
966
-
967
- expect(Reflect.has(adapter, "transaction")).toBe(false);
968
- });
969
-
970
- it("uses a MongoDB session when transactions are enabled", async () => {
971
- const client = new MongoClient("mongodb://localhost");
972
- const session = client.startSession();
973
- const withTransaction = vi.fn(
974
- async (operation: (session: ClientSession) => Promise<unknown>) =>
975
- operation(session),
976
- );
977
- Object.defineProperty(session, "withTransaction", {
978
- value: withTransaction,
979
- });
980
- const insertOne = vi.fn(async () => undefined);
981
- Object.defineProperty(client, "db", {
982
- value: () => ({
983
- collection: () => ({
984
- findOne: vi.fn(async () => ({
985
- id: transactionChannelId,
986
- name: "production",
987
- })),
988
- insertOne,
989
- updateOne: vi.fn(async () => ({ matchedCount: 1 })),
990
- }),
991
- }),
992
- });
993
- const withSession = vi.fn(
994
- async (operation: (session: ClientSession) => Promise<unknown>) =>
995
- operation(session),
996
- );
997
- Object.defineProperty(client, "withSession", { value: withSession });
998
- const adapter = mongoAdapter({ client, transactions: true });
999
-
1000
- await adapter.commit({
1001
- changes: [
1002
- {
1003
- model: "bundles",
1004
- operation: "insert",
1005
- row: bundleToRow(transactionBundle),
1006
- },
1007
- ],
1008
- });
1009
-
1010
- expect(withSession).toHaveBeenCalledTimes(1);
1011
- expect(withTransaction).toHaveBeenCalledTimes(1);
1012
- expect(insertOne).toHaveBeenCalledWith(bundleToRow(transactionBundle), {
1013
- session,
1014
- });
1015
- });
1016
324
  });
1017
325
 
1018
- describe("getBundleById", () => {
326
+ describe("getBundle", () => {
1019
327
  it("should retrieve bundle by id without Prisma validation errors", async () => {
1020
328
  const bundle: Bundle = {
1021
- archiveByteSize: 1_024,
1022
329
  id: "00000000-0000-0000-0000-000000000010",
1023
330
  platform: "ios",
1024
- fileHash: "test-hash",
1025
331
  gitCommitHash: null,
1026
- storageUri: "s3://test-bucket/test.zip",
332
+ manifestStorageUri: "s3://test-bucket/test/manifest.json",
333
+ manifestFileHash: "test-manifest-hash",
334
+ assetBaseStorageUri: "s3://test-bucket/assets",
1027
335
  };
1028
336
 
1029
- await hotUpdater.insertBundle(bundle);
337
+ await deployBundle(bundle);
1030
338
 
1031
- // This should not throw a Prisma validation error
1032
- const retrieved = await hotUpdater.getBundleById(bundle.id);
339
+ const retrieved = await hotUpdater.core.getBundle(bundle.id);
1033
340
 
1034
- expect(retrieved).not.toBeNull();
1035
- expect(retrieved?.id).toBe(bundle.id);
1036
- expect(retrieved?.platform).toBe(bundle.platform);
1037
- expect(retrieved?.fileHash).toBe(bundle.fileHash);
341
+ expect(retrieved?.bundle).toMatchObject({
342
+ id: bundle.id,
343
+ platform: bundle.platform,
344
+ manifest_file_hash: bundle.manifestFileHash,
345
+ });
1038
346
  });
1039
347
 
1040
348
  it("should return null for non-existent bundle id", async () => {
1041
- const retrieved = await hotUpdater.getBundleById(
349
+ const retrieved = await hotUpdater.core.getBundle(
1042
350
  "99999999-9999-9999-9999-999999999999",
1043
351
  );
1044
352
 
@@ -1046,18 +354,12 @@ describe("server/db hotUpdater (PGlite + Kysely)", async () => {
1046
354
  });
1047
355
  });
1048
356
 
1049
- describe("getChannels", () => {
1050
- it("retrieves canonical Channel rows without Prisma validation errors", async () => {
1051
- await hotUpdater.insertChannel({
1052
- onConflict: "returnExisting",
1053
- row: { id: "channel-production", name: "production" },
1054
- });
1055
- await hotUpdater.insertChannel({
1056
- onConflict: "returnExisting",
1057
- row: { id: "channel-staging", name: "staging" },
1058
- });
357
+ describe("listChannels", () => {
358
+ it("lists channel rows by name", async () => {
359
+ await hotUpdater.core.ensureChannel("staging");
360
+ await hotUpdater.core.ensureChannel("production");
1059
361
 
1060
- const channels = await hotUpdater.getChannels();
362
+ const channels = await hotUpdater.core.listChannels();
1061
363
 
1062
364
  expect(channels).toHaveLength(2);
1063
365
  expect(channels.map(({ name }) => name)).toEqual([
@@ -1066,8 +368,8 @@ describe("server/db hotUpdater (PGlite + Kysely)", async () => {
1066
368
  ]);
1067
369
  });
1068
370
 
1069
- it("should return empty array when no bundles exist", async () => {
1070
- const channels = await hotUpdater.getChannels();
371
+ it("should return empty array when no channels exist", async () => {
372
+ const channels = await hotUpdater.core.listChannels();
1071
373
  expect(channels).toEqual([]);
1072
374
  });
1073
375
  });
@@ -1083,23 +385,34 @@ describe("server/db hotUpdater (PGlite + Kysely)", async () => {
1083
385
  vi.useRealTimers();
1084
386
  });
1085
387
 
1086
- it("resolves s3:// storage URI to signed URL via s3StoragePlugin", async () => {
388
+ it("resolves manifest and asset URIs via s3StoragePlugin", async () => {
1087
389
  const bundle: Bundle = {
1088
- archiveByteSize: 1_024,
1089
390
  id: "00000000-0000-0000-0000-000000000001",
1090
391
  platform: "ios",
1091
- fileHash: "hash123",
1092
392
  gitCommitHash: null,
1093
- storageUri: "s3://test-bucket/bundles/bundle.zip",
393
+ manifestStorageUri: "s3://test-bucket/bundles/bundle/manifest.json",
394
+ manifestFileHash: "manifest-hash",
395
+ assetBaseStorageUri: "s3://test-bucket/assets",
1094
396
  };
397
+ storageTexts.set(
398
+ bundle.manifestStorageUri,
399
+ JSON.stringify({
400
+ bundleId: bundle.id,
401
+ assets: { "assets/logo.png": { fileHash: "logo-hash" } },
402
+ }),
403
+ );
1095
404
 
1096
- await hotUpdater.insertBundle(bundle);
405
+ await deployBundle(bundle);
1097
406
 
1098
- const updateInfo = await hotUpdater.getArtifactInfo(bundle.id, NIL_UUID);
407
+ const updateInfo = await hotUpdater.core.getArtifactInfo(
408
+ bundle.id,
409
+ NIL_UUID,
410
+ 1,
411
+ );
1099
412
 
1100
413
  expect(updateInfo).not.toBeNull();
1101
- expect(updateInfo?.fileUrl).toBe(
1102
- "https://s3.example.com/test-bucket/bundles/bundle.zip",
414
+ expect(updateInfo?.manifestUrl).toBe(
415
+ "https://s3.example.com/test-bucket/bundles/bundle/manifest.json",
1103
416
  );
1104
417
  });
1105
418
 
@@ -1109,34 +422,26 @@ describe("server/db hotUpdater (PGlite + Kysely)", async () => {
1109
422
  const nextManifestStorageUri =
1110
423
  "s3://test-bucket/releases/bundles/00000000-0000-0000-0000-000000000102/manifest.json";
1111
424
  const olderBundle: Bundle = {
1112
- archiveByteSize: 1_024,
1113
425
  id: "00000000-0000-0000-0000-000000000100",
1114
426
  platform: "ios",
1115
- fileHash: "hash-older-zip",
1116
427
  gitCommitHash: null,
1117
- storageUri:
1118
- "s3://test-bucket/releases/bundles/00000000-0000-0000-0000-000000000100/bundle.zip",
428
+ assetBaseStorageUri: "s3://test-bucket/releases/assets",
429
+ manifestFileHash: "manifest-older",
430
+ manifestStorageUri:
431
+ "s3://test-bucket/releases/bundles/00000000-0000-0000-0000-000000000100/manifest.json",
1119
432
  };
1120
433
  const currentBundle: Bundle = {
1121
- archiveByteSize: 1_024,
1122
434
  id: "00000000-0000-0000-0000-000000000101",
1123
435
  platform: "ios",
1124
- fileHash: "hash-current-zip",
1125
436
  gitCommitHash: null,
1126
- storageUri:
1127
- "s3://test-bucket/releases/bundles/00000000-0000-0000-0000-000000000101/bundle.zip",
1128
437
  assetBaseStorageUri: "s3://test-bucket/releases/assets",
1129
438
  manifestFileHash: "sig:manifest-current",
1130
439
  manifestStorageUri: currentManifestStorageUri,
1131
440
  };
1132
441
  const nextBundle: Bundle = {
1133
- archiveByteSize: 1_024,
1134
442
  id: "00000000-0000-0000-0000-000000000102",
1135
443
  platform: "ios",
1136
- fileHash: "hash-next-zip",
1137
444
  gitCommitHash: null,
1138
- storageUri:
1139
- "s3://test-bucket/releases/bundles/00000000-0000-0000-0000-000000000102/bundle.zip",
1140
445
  assetBaseStorageUri: "s3://test-bucket/releases/assets",
1141
446
  manifestFileHash: "sig:manifest-next",
1142
447
  manifestStorageUri: nextManifestStorageUri,
@@ -1193,35 +498,26 @@ describe("server/db hotUpdater (PGlite + Kysely)", async () => {
1193
498
  });
1194
499
  });
1195
500
 
1196
- await hotUpdater.insertBundle(olderBundle);
1197
- await hotUpdater.insertBundle(currentBundle);
1198
- await hotUpdater.insertBundle(nextBundle);
501
+ await deployBundle(olderBundle);
502
+ await deployBundle(currentBundle);
503
+ await deployBundle(nextBundle);
1199
504
  vi.stubGlobal("fetch", fetchMock);
1200
505
 
1201
506
  try {
1202
507
  await expect(
1203
- hotUpdater.getArtifactInfo(nextBundle.id, currentBundle.id),
1204
- ).resolves.toEqual({
1205
- changedAssets: {
508
+ hotUpdater.core.getArtifactInfo(nextBundle.id, currentBundle.id, 1),
509
+ ).resolves.toMatchObject({
510
+ artifactProtocolVersion: 1,
511
+ assets: {
512
+ "assets/logo.png": {
513
+ file: { url: expect.any(String) },
514
+ fileHash: "hash-logo",
515
+ },
1206
516
  "index.ios.bundle": {
1207
- file: {
1208
- compression: "br",
1209
- url: "https://s3.example.com/test-bucket/releases/assets/sha256/ha/hash-new-bundle.br",
1210
- },
517
+ file: { url: expect.any(String) },
1211
518
  fileHash: "hash-new-bundle",
1212
- patch: {
1213
- algorithm: "bsdiff",
1214
- baseBundleId: currentBundle.id,
1215
- baseFileHash: "hash-old-bundle",
1216
- patchFileHash: "hash-bsdiff",
1217
- patchUrl:
1218
- "https://s3.example.com/test-bucket/releases/bundles/00000000-0000-0000-0000-000000000102/patches/00000000-0000-0000-0000-000000000101/index.ios.bundle.bsdiff",
1219
- },
1220
519
  },
1221
520
  },
1222
- fileHash: "hash-next-zip",
1223
- fileUrl:
1224
- "https://s3.example.com/test-bucket/releases/bundles/00000000-0000-0000-0000-000000000102/bundle.zip",
1225
521
  manifestFileHash: "sig:manifest-next",
1226
522
  manifestUrl:
1227
523
  "https://s3.example.com/test-bucket/releases/bundles/00000000-0000-0000-0000-000000000102/manifest.json",
@@ -1236,26 +532,22 @@ describe("server/db hotUpdater (PGlite + Kysely)", async () => {
1236
532
  const nextManifestStorageUri =
1237
533
  "s3://test-bucket/releases/bundles/00000000-0000-0000-0000-000000000109/manifest.json";
1238
534
  const nextBundle: Bundle = {
1239
- archiveByteSize: 1_024,
1240
535
  id: "00000000-0000-0000-0000-000000000109",
1241
536
  platform: "ios",
1242
- fileHash: "hash-next-zip",
1243
537
  gitCommitHash: null,
1244
- storageUri:
1245
- "s3://test-bucket/releases/bundles/00000000-0000-0000-0000-000000000109/bundle.zip",
1246
538
  assetBaseStorageUri: "s3://test-bucket/releases/assets",
1247
539
  manifestFileHash: "sig:manifest-next",
1248
540
  manifestStorageUri: nextManifestStorageUri,
1249
541
  };
1250
542
 
1251
- await hotUpdater.insertBundle(nextBundle);
543
+ await deployBundle(nextBundle);
1252
544
  storageTexts.set(
1253
545
  nextManifestStorageUri,
1254
546
  new Error("storage read failed"),
1255
547
  );
1256
548
 
1257
549
  await expect(
1258
- hotUpdater.getArtifactInfo(nextBundle.id, NIL_UUID),
550
+ hotUpdater.core.getArtifactInfo(nextBundle.id, NIL_UUID, 1),
1259
551
  ).rejects.toThrow("storage read failed");
1260
552
  });
1261
553
  });