@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
@@ -0,0 +1,175 @@
1
+ import { execFile } from "node:child_process";
2
+ import { mkdtemp, rm, writeFile } from "node:fs/promises";
3
+ import { createRequire } from "node:module";
4
+ import os from "node:os";
5
+ import path from "node:path";
6
+ import type { DatabaseSync, SqliteValue } from "node:sqlite";
7
+ import { promisify } from "node:util";
8
+
9
+ import type { PGlite, Transaction } from "@electric-sql/pglite";
10
+ import type { Pool as MysqlPool, PoolConnection } from "mysql2/promise";
11
+
12
+ import { prismaAdapter, type PrismaProvider } from "./prisma";
13
+ import type {
14
+ PrismaRawClient,
15
+ PrismaTransactionalClient,
16
+ } from "./prismaExecutor";
17
+
18
+ /** A database error as Prisma reports a failed raw query: P2010, with the database's code. */
19
+ const prismaError = (error: unknown) => {
20
+ const { code, errcode, errno, message } = error as Record<string, unknown>;
21
+ const database = String(errcode ?? errno ?? code);
22
+ return Object.assign(
23
+ new Error(
24
+ `Raw query failed. Code: \`${database}\`. Message: \`${String(message)}\``,
25
+ ),
26
+ {
27
+ name: "PrismaClientKnownRequestError",
28
+ code: "P2010",
29
+ meta: { code: database, message: String(message) },
30
+ },
31
+ );
32
+ };
33
+
34
+ const raw = (
35
+ query: (sql: string, params: unknown[]) => Promise<unknown[]>,
36
+ execute: (sql: string, params: unknown[]) => Promise<number>,
37
+ ): PrismaRawClient => ({
38
+ $queryRawUnsafe: (sql, ...params) =>
39
+ query(sql, params).catch((error: unknown) => {
40
+ throw prismaError(error);
41
+ }),
42
+ $executeRawUnsafe: (sql, ...params) =>
43
+ execute(sql, params).catch((error: unknown) => {
44
+ throw prismaError(error);
45
+ }),
46
+ });
47
+
48
+ /** Prisma's raw query API over PGlite, as the Prisma client answers it. */
49
+ export const pglitePrisma = (db: PGlite): PrismaTransactionalClient => {
50
+ const over = (runner: PGlite | Transaction) =>
51
+ raw(
52
+ async (sql, params) => (await runner.query(sql, params)).rows,
53
+ async (sql, params) =>
54
+ (await runner.query(sql, params)).affectedRows ?? 0,
55
+ );
56
+ return {
57
+ ...over(db),
58
+ $transaction: (fn) => db.transaction((tx) => fn(over(tx))),
59
+ };
60
+ };
61
+
62
+ /**
63
+ * Prisma's raw query API over `node:sqlite`. Like Prisma's SQLite client, it
64
+ * runs one operation at a time, and begins transactions deferred.
65
+ */
66
+ export const sqlitePrisma = (db: DatabaseSync): PrismaTransactionalClient => {
67
+ const over = raw(
68
+ async (sql, params) => db.prepare(sql).all(...(params as SqliteValue[])),
69
+ async (sql, params) =>
70
+ Number(db.prepare(sql).run(...(params as SqliteValue[])).changes),
71
+ );
72
+ let queue: Promise<unknown> = Promise.resolve();
73
+ const serial = <T>(task: () => Promise<T>) => {
74
+ const result = queue.then(task);
75
+ queue = result.catch(() => undefined);
76
+ return result;
77
+ };
78
+ return {
79
+ $queryRawUnsafe: (sql, ...params) =>
80
+ serial(() => over.$queryRawUnsafe(sql, ...params)),
81
+ $executeRawUnsafe: (sql, ...params) =>
82
+ serial(() => over.$executeRawUnsafe(sql, ...params)),
83
+ $transaction: (fn) =>
84
+ serial(async () => {
85
+ db.exec("BEGIN");
86
+ try {
87
+ const result = await fn(over);
88
+ db.exec("COMMIT");
89
+ return result;
90
+ } catch (error) {
91
+ db.exec("ROLLBACK");
92
+ throw error;
93
+ }
94
+ }),
95
+ };
96
+ };
97
+
98
+ /** Prisma's raw query API over a mysql2 pool. */
99
+ export const mysqlPrisma = (pool: MysqlPool): PrismaTransactionalClient => {
100
+ const over = (runner: MysqlPool | PoolConnection) =>
101
+ raw(
102
+ async (sql, params) => (await runner.query(sql, params))[0] as unknown[],
103
+ async (sql, params) => {
104
+ const [result] = await runner.query(sql, params);
105
+ return (result as { affectedRows: number }).affectedRows;
106
+ },
107
+ );
108
+ return {
109
+ ...over(pool),
110
+ async $transaction(fn) {
111
+ const connection = await pool.getConnection();
112
+ try {
113
+ await connection.beginTransaction();
114
+ const result = await fn(over(connection));
115
+ await connection.commit();
116
+ return result;
117
+ } catch (error) {
118
+ await connection.rollback().catch(() => undefined);
119
+ throw error;
120
+ } finally {
121
+ connection.release();
122
+ }
123
+ },
124
+ };
125
+ };
126
+
127
+ const prismaCli = createRequire(import.meta.url).resolve(
128
+ "prisma/build/index.js",
129
+ );
130
+ const urls: Record<PrismaProvider, string> = {
131
+ sqlite: "file:./unused.db",
132
+ postgresql: "postgresql://unused@localhost/unused",
133
+ mysql: "mysql://unused@localhost/unused",
134
+ };
135
+
136
+ /** The DDL `prisma db push` runs for the generated models on an empty database, from Prisma's CLI. */
137
+ export const prismaPushSql = async (
138
+ provider: PrismaProvider,
139
+ ): Promise<string> => {
140
+ const directory = await mkdtemp(
141
+ path.join(os.tmpdir(), "hot-updater-prisma-"),
142
+ );
143
+ try {
144
+ const file = path.join(directory, "schema.prisma");
145
+ const models = prismaAdapter({ prisma: {}, provider }).generateSchema!(
146
+ "latest",
147
+ ).code;
148
+ await writeFile(
149
+ file,
150
+ `datasource db {\n provider = "${provider}"\n url = "${urls[provider]}"\n}\n\n${models}\n`,
151
+ );
152
+ const { stdout } = await promisify(execFile)(
153
+ process.execPath,
154
+ [
155
+ prismaCli,
156
+ "migrate",
157
+ "diff",
158
+ "--from-empty",
159
+ "--to-schema-datamodel",
160
+ file,
161
+ "--script",
162
+ ],
163
+ {
164
+ env: {
165
+ ...process.env,
166
+ CHECKPOINT_DISABLE: "1",
167
+ PRISMA_HIDE_UPDATE_MESSAGE: "1",
168
+ },
169
+ },
170
+ );
171
+ return stdout;
172
+ } finally {
173
+ await rm(directory, { recursive: true, force: true });
174
+ }
175
+ };
@@ -0,0 +1,14 @@
1
+ import { sqlProviders, type ORMSQLProvider } from "../db/types";
2
+
3
+ /** The provider an adapter was given, when Hot Updater's SQL core runs on it. */
4
+ export const checkSqlProvider = <TProvider extends ORMSQLProvider>(
5
+ adapter: string,
6
+ provider: TProvider,
7
+ ): TProvider => {
8
+ if (!(sqlProviders as readonly string[]).includes(provider)) {
9
+ throw new Error(
10
+ `${adapter}: provider "${String(provider)}" is not supported. Use ${sqlProviders.map((name) => `"${name}"`).join(", ")}; CockroachDB and SQL Server were dropped in 1.0.`,
11
+ );
12
+ }
13
+ return provider;
14
+ };
@@ -1,8 +1,9 @@
1
- import { describe, expect, it, vi } from "vitest";
1
+ import { describe, expect, it } from "vitest";
2
2
 
3
- import { createInMemoryDatabasePlugin } from "../../test-utils/test/inMemoryDatabasePlugin";
4
- import { registerApiKey } from "./apiKeys";
5
3
  import { API_KEY_HEADER_NAME, createHotUpdater } from "./index";
4
+ import { apiKeys } from "./plugins/api-keys";
5
+ import { insights } from "./plugins/insights";
6
+ import { createRuntimeDatabase } from "./runtime.testFixtures";
6
7
 
7
8
  const API_KEY = "AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE";
8
9
  const updateUrl =
@@ -18,30 +19,19 @@ const withApiKey = (url: string, init?: RequestInit) =>
18
19
  },
19
20
  });
20
21
 
21
- describe("createHotUpdater API keys", () => {
22
- it("rejects an invalid API key header name", () => {
23
- expect(() =>
24
- createHotUpdater({
25
- clientAccess: {
26
- headerName: "invalid header",
27
- type: "api-key",
28
- },
29
- database: createInMemoryDatabasePlugin(),
30
- }),
31
- ).toThrow("clientAccess.headerName must be a valid header name.");
22
+ /** A server whose client routes the apiKeys() plugin protects, with one registered key. */
23
+ const start = async () => {
24
+ const hotUpdater = createHotUpdater({
25
+ database: createRuntimeDatabase(),
26
+ plugins: [apiKeys(), insights()],
32
27
  });
28
+ await hotUpdater.api.apiKeys.register({ apiKey: API_KEY, name: "App" });
29
+ return hotUpdater;
30
+ };
33
31
 
32
+ describe("createHotUpdater with the apiKeys() plugin", () => {
34
33
  it("protects only client OTA and Insights write routes", async () => {
35
- const database = createInMemoryDatabasePlugin();
36
- await registerApiKey({
37
- apiKeys: database.models.apiKeys,
38
- apiKey: API_KEY,
39
- name: "App",
40
- });
41
- const hotUpdater = createHotUpdater({
42
- clientAccess: { type: "api-key" },
43
- database,
44
- });
34
+ const hotUpdater = await start();
45
35
 
46
36
  expect(
47
37
  (await hotUpdater.handlers.client(new Request(updateUrl))).status,
@@ -59,44 +49,14 @@ describe("createHotUpdater API keys", () => {
59
49
  expect(
60
50
  (
61
51
  await hotUpdater.handlers.admin(
62
- withApiKey("https://example.com/installations/overview"),
52
+ new Request("https://example.com/events"),
63
53
  )
64
54
  ).status,
65
55
  ).toBe(200);
66
56
  });
67
57
 
68
- it("creates, lists, and revokes API keys without exposing hashes", async () => {
69
- const hotUpdater = createHotUpdater({
70
- clientAccess: { type: "public" },
71
- database: createInMemoryDatabasePlugin(),
72
- });
73
-
74
- const created = await hotUpdater.apiKeys.create({ name: "Production" });
75
- expect(created.apiKey).toMatch(/^[A-Za-z0-9_-]{43}$/u);
76
- expect(created.record).not.toHaveProperty("hash");
77
-
78
- await expect(hotUpdater.apiKeys.list()).resolves.toEqual([created.record]);
79
- const revoked = await hotUpdater.apiKeys.revoke({
80
- id: created.record.id,
81
- });
82
- expect(revoked).toMatchObject({
83
- id: created.record.id,
84
- revoked_at_ms: expect.any(Number),
85
- });
86
- expect(revoked).not.toHaveProperty("hash");
87
- });
88
-
89
58
  it("authenticates before parsing Insights event bodies", async () => {
90
- const database = createInMemoryDatabasePlugin();
91
- await registerApiKey({
92
- apiKeys: database.models.apiKeys,
93
- apiKey: API_KEY,
94
- name: "App",
95
- });
96
- const hotUpdater = createHotUpdater({
97
- clientAccess: { type: "api-key" },
98
- database,
99
- });
59
+ const hotUpdater = await start();
100
60
  const invalidBody = {
101
61
  method: "POST",
102
62
  headers: { "content-type": "application/json" },
@@ -119,74 +79,14 @@ describe("createHotUpdater API keys", () => {
119
79
  ).toBe(400);
120
80
  });
121
81
 
122
- it("returns 503 when credential storage is unavailable", async () => {
123
- const database = createInMemoryDatabasePlugin();
124
- vi.spyOn(database.models.apiKeys, "findByHash").mockRejectedValue(
125
- new Error("database offline"),
126
- );
82
+ it('keeps client routes public with clientAccess: "public"', async () => {
127
83
  const hotUpdater = createHotUpdater({
128
- clientAccess: { type: "api-key" },
129
- database,
130
- });
131
-
132
- const response = await hotUpdater.handlers.client(withApiKey(updateUrl));
133
-
134
- expect(response.status).toBe(503);
135
- await expect(response.json()).resolves.toEqual({
136
- error: "Service unavailable",
137
- });
138
- });
139
-
140
- it("keeps client routes public with the public access policy", async () => {
141
- const hotUpdater = createHotUpdater({
142
- clientAccess: { type: "public" },
143
- database: createInMemoryDatabasePlugin(),
84
+ clientAccess: "public",
85
+ database: createRuntimeDatabase(),
144
86
  });
145
87
 
146
88
  expect(
147
89
  (await hotUpdater.handlers.client(new Request(updateUrl))).status,
148
90
  ).toBe(404);
149
91
  });
150
-
151
- it("reads API keys only from the configured header", async () => {
152
- const database = createInMemoryDatabasePlugin();
153
- await registerApiKey({
154
- apiKeys: database.models.apiKeys,
155
- apiKey: API_KEY,
156
- name: "App",
157
- });
158
- const hotUpdater = createHotUpdater({
159
- clientAccess: {
160
- headerName: "X-Hot-Updater-Key",
161
- type: "api-key",
162
- },
163
- database,
164
- });
165
- const invalidBody = {
166
- method: "POST",
167
- headers: { "content-type": "application/json" },
168
- body: "not-json",
169
- } satisfies RequestInit;
170
-
171
- expect(
172
- (
173
- await hotUpdater.handlers.client(
174
- withApiKey("https://example.com/events", invalidBody),
175
- )
176
- ).status,
177
- ).toBe(401);
178
- expect(
179
- (
180
- await hotUpdater.handlers.client(
181
- new Request("https://example.com/events", {
182
- ...invalidBody,
183
- headers: {
184
- ...invalidBody.headers,
185
- "x-hot-updater-key": API_KEY,
186
- },
187
- }),
188
- )
189
- ).status,
190
- ).toBe(400);
191
- });
192
92
  });
@@ -1,6 +1,6 @@
1
- import { describe, expect, it, vi } from "vitest";
1
+ import { createMemoryAdapter } from "@hot-updater/plugin-core/internal";
2
+ import { describe, expect, it } from "vitest";
2
3
 
3
- import { createInMemoryDatabasePlugin } from "../../test-utils/test/inMemoryDatabasePlugin";
4
4
  import {
5
5
  API_KEY_HEADER_NAME,
6
6
  authenticateApiKey,
@@ -11,6 +11,20 @@ import {
11
11
  provisionApiKey,
12
12
  registerApiKey,
13
13
  } from "./apiKeys";
14
+ import { createDatabaseEngine } from "./database/database";
15
+ import { resolveSchema } from "./database/resolveSchema";
16
+ import { apiKeysSchema, createApiKeyModel } from "./plugins/api-keys";
17
+
18
+ /** The api-keys plugin's table model on an empty in-memory database. */
19
+ const createModel = () => {
20
+ const module = { id: "apiKeys", schema: apiKeysSchema } as const;
21
+ return createApiKeyModel(
22
+ createDatabaseEngine({
23
+ adapter: createMemoryAdapter(),
24
+ schema: resolveSchema([module]),
25
+ }).database(module),
26
+ );
27
+ };
14
28
 
15
29
  const API_KEY = "AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE";
16
30
 
@@ -21,18 +35,18 @@ describe("API keys", () => {
21
35
  "x-hot-updater-key",
22
36
  );
23
37
  expect(() => normalizeApiKeyHeaderName("")).toThrow(
24
- "clientAccess.headerName must be a valid header name.",
38
+ "apiKeys({ headerName }) must name a valid header.",
25
39
  );
26
40
  expect(() => normalizeApiKeyHeaderName("invalid header")).toThrow(
27
- "clientAccess.headerName must be a valid header name.",
41
+ "apiKeys({ headerName }) must name a valid header.",
28
42
  );
29
43
  });
30
44
 
31
45
  it("persists only the digest and metadata for a registered key", async () => {
32
- const database = createInMemoryDatabasePlugin();
46
+ const model = createModel();
33
47
 
34
48
  const created = await registerApiKey({
35
- apiKeys: database.models.apiKeys,
49
+ apiKeys: model,
36
50
  apiKey: API_KEY,
37
51
  createdAtMs: 100,
38
52
  name: " Production app ",
@@ -49,28 +63,25 @@ describe("API keys", () => {
49
63
  });
50
64
  expect(created.record).not.toHaveProperty("hash");
51
65
  expect(created.record.id).not.toContain(await hashApiKey(API_KEY));
52
- expect(await database.models.apiKeys.list()).toEqual([
66
+ expect(await model.list()).toEqual([
53
67
  expect.objectContaining({ hash: await hashApiKey(API_KEY) }),
54
68
  ]);
55
- expect(JSON.stringify(await database.models.apiKeys.list())).not.toContain(
56
- API_KEY,
57
- );
69
+ expect(JSON.stringify(await model.list())).not.toContain(API_KEY);
58
70
 
59
71
  const registeredAgain = await registerApiKey({
60
- apiKeys: database.models.apiKeys,
72
+ apiKeys: model,
61
73
  apiKey: API_KEY,
62
74
  createdAtMs: 200,
63
75
  name: "Ignored replacement name",
64
76
  });
65
77
  expect(registeredAgain.record).toEqual(created.record);
66
- expect(await database.models.apiKeys.list()).toHaveLength(1);
78
+ expect(await model.list()).toHaveLength(1);
67
79
  });
68
80
 
69
- it("authenticates only active keys after the readiness check", async () => {
70
- const database = createInMemoryDatabasePlugin();
71
- const beforeLookup = vi.fn(async () => undefined);
81
+ it("authenticates only active keys", async () => {
82
+ const model = createModel();
72
83
  const { record } = await registerApiKey({
73
- apiKeys: database.models.apiKeys,
84
+ apiKeys: model,
74
85
  apiKey: API_KEY,
75
86
  name: "App",
76
87
  });
@@ -80,30 +91,28 @@ describe("API keys", () => {
80
91
 
81
92
  await expect(
82
93
  authenticateApiKey({
83
- apiKeys: database.models.apiKeys,
84
- beforeLookup,
94
+ apiKeys: model,
85
95
  request,
86
96
  }),
87
97
  ).resolves.toBe(true);
88
- expect(beforeLookup).toHaveBeenCalledOnce();
89
98
 
90
- await database.models.apiKeys.revoke({
99
+ await model.revoke({
91
100
  id: record.id,
92
101
  revokedAtMs: Date.now(),
93
102
  });
94
103
  await expect(
95
104
  authenticateApiKey({
96
- apiKeys: database.models.apiKeys,
105
+ apiKeys: model,
97
106
  request,
98
107
  }),
99
108
  ).resolves.toBe(false);
100
109
  });
101
110
 
102
111
  it("creates a canonical key and validates visible names", async () => {
103
- const database = createInMemoryDatabasePlugin();
112
+ const model = createModel();
104
113
 
105
114
  const created = await createApiKey({
106
- apiKeys: database.models.apiKeys,
115
+ apiKeys: model,
107
116
  name: "App",
108
117
  });
109
118
 
@@ -111,7 +120,7 @@ describe("API keys", () => {
111
120
  expect(created.record.prefix).toBe(created.apiKey.slice(0, 6));
112
121
  await expect(
113
122
  registerApiKey({
114
- apiKeys: database.models.apiKeys,
123
+ apiKeys: model,
115
124
  apiKey: API_KEY,
116
125
  name: " ",
117
126
  }),
@@ -119,29 +128,25 @@ describe("API keys", () => {
119
128
  });
120
129
 
121
130
  it("provisions a new key once and reuses an existing managed key", async () => {
122
- const database = createInMemoryDatabasePlugin();
131
+ const model = createModel();
123
132
 
124
133
  const created = await provisionApiKey({
125
- apiKeys: database.models.apiKeys,
134
+ apiKeys: model,
126
135
  name: "Managed init",
127
136
  });
128
137
  const reused = await provisionApiKey({
129
- apiKeys: database.models.apiKeys,
138
+ apiKeys: model,
130
139
  existingApiKey: created.apiKey,
131
140
  name: "Managed init rerun",
132
141
  });
133
142
 
134
143
  expect(reused).toEqual(created);
135
- expect(await database.models.apiKeys.list()).toHaveLength(1);
144
+ expect(await model.list()).toHaveLength(1);
136
145
  });
137
146
 
138
147
  it("manages keys without exposing stored hashes", async () => {
139
- const database = createInMemoryDatabasePlugin();
140
- const beforeOperation = vi.fn(async () => undefined);
141
- const apiKeys = createApiKeyManagement({
142
- apiKeys: database.models.apiKeys,
143
- beforeOperation,
144
- });
148
+ const model = createModel();
149
+ const apiKeys = createApiKeyManagement({ apiKeys: model });
145
150
 
146
151
  const created = await apiKeys.create({ name: "Production app" });
147
152
  expect(created.apiKey).toMatch(/^[A-Za-z0-9_-]{43}$/u);
@@ -157,6 +162,5 @@ describe("API keys", () => {
157
162
  revoked_at_ms: expect.any(Number),
158
163
  });
159
164
  expect(revoked).not.toHaveProperty("hash");
160
- expect(beforeOperation).toHaveBeenCalledTimes(3);
161
165
  });
162
166
  });
package/src/apiKeys.ts CHANGED
@@ -32,7 +32,7 @@ export const normalizeApiKeyHeaderName = (
32
32
  value: unknown = API_KEY_HEADER_NAME,
33
33
  ): string => {
34
34
  if (typeof value !== "string" || value.length === 0) {
35
- throw new TypeError("clientAccess.headerName must be a valid header name.");
35
+ throw new TypeError("apiKeys({ headerName }) must name a valid header.");
36
36
  }
37
37
 
38
38
  try {
@@ -40,7 +40,7 @@ export const normalizeApiKeyHeaderName = (
40
40
  headers.set(value, "");
41
41
  return headers.keys().next().value!;
42
42
  } catch {
43
- throw new TypeError("clientAccess.headerName must be a valid header name.");
43
+ throw new TypeError("apiKeys({ headerName }) must name a valid header.");
44
44
  }
45
45
  };
46
46
 
@@ -172,7 +172,6 @@ export const provisionApiKey = (input: {
172
172
  };
173
173
 
174
174
  export const authenticateApiKey = async (input: {
175
- readonly beforeLookup?: () => Promise<void>;
176
175
  readonly apiKeys: ApiKeyModel;
177
176
  readonly headerName?: string;
178
177
  readonly request: Request;
@@ -182,7 +181,6 @@ export const authenticateApiKey = async (input: {
182
181
  );
183
182
  if (apiKey === null || !isApiKey(apiKey)) return false;
184
183
  const hash = await hashApiKey(apiKey);
185
- await input.beforeLookup?.();
186
184
  const record = await input.apiKeys.findByHash(hash);
187
185
  return (
188
186
  record !== null &&
@@ -194,11 +192,9 @@ export const authenticateApiKey = async (input: {
194
192
 
195
193
  export const createApiKeyManagement = (input: {
196
194
  readonly apiKeys: ApiKeyModel;
197
- readonly beforeOperation: () => Promise<void>;
198
195
  }): ApiKeyManagementAPI =>
199
196
  Object.freeze({
200
197
  async create({ name }: { readonly name: string }) {
201
- await input.beforeOperation();
202
198
  const created = await createApiKey({ apiKeys: input.apiKeys, name });
203
199
  return Object.freeze({
204
200
  apiKey: created.apiKey,
@@ -206,11 +202,9 @@ export const createApiKeyManagement = (input: {
206
202
  });
207
203
  },
208
204
  async list() {
209
- await input.beforeOperation();
210
205
  return Object.freeze((await input.apiKeys.list()).map(toApiKeyMetadata));
211
206
  },
212
207
  async revoke({ id }: { readonly id: string }) {
213
- await input.beforeOperation();
214
208
  const record = await input.apiKeys.revoke({
215
209
  id,
216
210
  revokedAtMs: Date.now(),