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

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 (309) hide show
  1. package/dist/adapters/drizzle.cjs +5 -5
  2. package/dist/adapters/drizzle.mjs +4 -4
  3. package/dist/adapters/kysely.cjs +3 -3
  4. package/dist/adapters/kysely.mjs +2 -2
  5. package/dist/adapters/mongodb.cjs +3 -3
  6. package/dist/adapters/mongodb.mjs +2 -2
  7. package/dist/adapters/mongodbAdapter.cjs +19 -1
  8. package/dist/adapters/mongodbAdapter.mjs +19 -1
  9. package/dist/adapters/prisma.cjs +5 -5
  10. package/dist/adapters/prisma.mjs +4 -4
  11. package/dist/assembly/assemblePlugins.cjs +47 -28
  12. package/dist/assembly/assemblePlugins.d.cts +3 -7
  13. package/dist/assembly/assemblePlugins.d.mts +3 -7
  14. package/dist/assembly/assemblePlugins.mjs +46 -27
  15. package/dist/assembly/clientPlugins.cjs +86 -0
  16. package/dist/assembly/clientPlugins.d.cts +16 -0
  17. package/dist/assembly/clientPlugins.d.mts +16 -0
  18. package/dist/assembly/clientPlugins.mjs +86 -0
  19. package/dist/assembly/configError.cjs +7 -0
  20. package/dist/assembly/configError.d.cts +7 -0
  21. package/dist/assembly/configError.d.mts +7 -0
  22. package/dist/assembly/configError.mjs +7 -0
  23. package/dist/assembly/databasePlugins.cjs +5 -1
  24. package/dist/assembly/databasePlugins.d.cts +5 -5
  25. package/dist/assembly/databasePlugins.d.mts +5 -5
  26. package/dist/assembly/databasePlugins.mjs +5 -1
  27. package/dist/assembly/pluginCli.cjs +125 -0
  28. package/dist/assembly/pluginCli.d.cts +59 -0
  29. package/dist/assembly/pluginCli.d.mts +59 -0
  30. package/dist/assembly/pluginCli.mjs +121 -0
  31. package/dist/createHotUpdaterCore.cjs +14 -16
  32. package/dist/createHotUpdaterCore.d.cts +10 -3
  33. package/dist/createHotUpdaterCore.d.mts +10 -3
  34. package/dist/createHotUpdaterCore.mjs +11 -13
  35. package/dist/database/aggregateBatching.cjs +626 -0
  36. package/dist/database/aggregateBatching.d.cts +10 -0
  37. package/dist/database/aggregateBatching.d.mts +10 -0
  38. package/dist/database/aggregateBatching.mjs +625 -0
  39. package/dist/{insights/errors.cjs → database/busy.cjs} +2 -15
  40. package/dist/database/busy.d.cts +12 -0
  41. package/dist/database/busy.d.mts +12 -0
  42. package/dist/{insights/errors.mjs → database/busy.mjs} +3 -14
  43. package/dist/database/database.cjs +22 -3
  44. package/dist/database/database.d.cts +15 -2
  45. package/dist/database/database.d.mts +15 -2
  46. package/dist/database/database.mjs +22 -3
  47. package/dist/database/definitions.d.cts +10 -0
  48. package/dist/database/definitions.d.mts +10 -0
  49. package/dist/database/engine.d.cts +2 -1
  50. package/dist/database/engine.d.mts +2 -1
  51. package/dist/database/engineAggregates.cjs +7 -4
  52. package/dist/database/engineAggregates.mjs +8 -5
  53. package/dist/database/engineReads.cjs +5 -3
  54. package/dist/database/engineReads.mjs +6 -4
  55. package/dist/database/engineTransaction.cjs +2 -6
  56. package/dist/database/engineTransaction.mjs +2 -6
  57. package/dist/database/fence.cjs +2 -1
  58. package/dist/database/fence.mjs +2 -1
  59. package/dist/database/index.cjs +17 -8
  60. package/dist/database/index.d.cts +5 -4
  61. package/dist/database/index.d.mts +5 -4
  62. package/dist/database/index.mjs +6 -5
  63. package/dist/database/kv/kvAdapter.cjs +15 -3
  64. package/dist/database/kv/kvAdapter.d.cts +8 -0
  65. package/dist/database/kv/kvAdapter.d.mts +8 -0
  66. package/dist/database/kv/kvAdapter.mjs +16 -4
  67. package/dist/database/resolveSchema.cjs +4 -1
  68. package/dist/database/resolveSchema.d.cts +1 -1
  69. package/dist/database/resolveSchema.d.mts +1 -1
  70. package/dist/database/resolveSchema.mjs +4 -1
  71. package/dist/database/retention.cjs +92 -0
  72. package/dist/database/retention.mjs +90 -0
  73. package/dist/database/schema.cjs +5 -2
  74. package/dist/database/schema.d.cts +30 -1
  75. package/dist/database/schema.d.mts +30 -1
  76. package/dist/database/schema.mjs +5 -2
  77. package/dist/database/sql/sqlAdapter.cjs +8 -0
  78. package/dist/database/sql/sqlAdapter.mjs +9 -1
  79. package/dist/database/sql/sqlSchema.cjs +56 -0
  80. package/dist/database/sql/sqlSchema.mjs +55 -1
  81. package/dist/db/coreDatabase.cjs +85 -0
  82. package/dist/db/coreDatabase.d.cts +57 -0
  83. package/dist/db/coreDatabase.d.mts +57 -0
  84. package/dist/db/coreDatabase.mjs +78 -0
  85. package/dist/db/index.cjs +11 -3
  86. package/dist/db/index.d.cts +7 -3
  87. package/dist/db/index.d.mts +7 -3
  88. package/dist/db/index.mjs +6 -3
  89. package/dist/db/types.d.cts +3 -3
  90. package/dist/db/types.d.mts +3 -3
  91. package/dist/diff.cjs +3 -0
  92. package/dist/diff.d.cts +2 -0
  93. package/dist/diff.d.mts +2 -0
  94. package/dist/diff.mjs +2 -0
  95. package/dist/handler.cjs +2 -14
  96. package/dist/handler.mjs +1 -13
  97. package/dist/handlerReleaseCatalogRoutes.cjs +21 -2
  98. package/dist/handlerReleaseCatalogRoutes.mjs +21 -2
  99. package/dist/index.cjs +2 -6
  100. package/dist/index.d.cts +4 -7
  101. package/dist/index.d.mts +4 -7
  102. package/dist/index.mjs +2 -4
  103. package/dist/package.cjs +1 -1
  104. package/dist/package.mjs +1 -1
  105. package/dist/{apiKeys.cjs → plugins/api-keys/apiKeys.cjs} +1 -1
  106. package/dist/{apiKeys.d.cts → plugins/api-keys/apiKeys.d.cts} +2 -2
  107. package/dist/{apiKeys.d.mts → plugins/api-keys/apiKeys.d.mts} +2 -2
  108. package/dist/{apiKeys.mjs → plugins/api-keys/apiKeys.mjs} +1 -1
  109. package/dist/plugins/api-keys/cli.cjs +115 -0
  110. package/dist/plugins/api-keys/cli.mjs +114 -0
  111. package/dist/plugins/api-keys/index.cjs +9 -6
  112. package/dist/plugins/api-keys/index.d.cts +4 -5
  113. package/dist/plugins/api-keys/index.d.mts +4 -5
  114. package/dist/plugins/api-keys/index.mjs +9 -7
  115. package/dist/plugins/api-keys/model.d.cts +20 -2
  116. package/dist/plugins/api-keys/model.d.mts +20 -2
  117. package/dist/plugins/definePlugin.cjs +1 -1
  118. package/dist/plugins/definePlugin.d.cts +130 -3
  119. package/dist/plugins/definePlugin.d.mts +130 -3
  120. package/dist/plugins/definePlugin.mjs +1 -1
  121. package/dist/plugins/index.cjs +25 -4
  122. package/dist/plugins/index.d.cts +7 -4
  123. package/dist/plugins/index.d.mts +7 -4
  124. package/dist/plugins/index.mjs +6 -4
  125. package/dist/plugins/insights/contract.cjs +193 -0
  126. package/dist/plugins/insights/contract.mjs +189 -0
  127. package/dist/{insights → plugins/insights}/domain.d.cts +60 -15
  128. package/dist/{insights → plugins/insights}/domain.d.mts +60 -15
  129. package/dist/plugins/insights/errors.cjs +15 -0
  130. package/dist/plugins/insights/errors.mjs +14 -0
  131. package/dist/{insights → plugins/insights}/eventInput.cjs +155 -22
  132. package/dist/{insights → plugins/insights}/eventInput.mjs +155 -22
  133. package/dist/plugins/insights/eventRow.cjs +49 -0
  134. package/dist/plugins/insights/eventRow.d.cts +64 -0
  135. package/dist/plugins/insights/eventRow.d.mts +64 -0
  136. package/dist/plugins/insights/eventRow.mjs +47 -0
  137. package/dist/plugins/insights/index.cjs +106 -26
  138. package/dist/plugins/insights/index.d.cts +130 -27
  139. package/dist/plugins/insights/index.d.mts +130 -27
  140. package/dist/plugins/insights/index.mjs +106 -29
  141. package/dist/plugins/insights/model.cjs +2 -2
  142. package/dist/plugins/insights/model.d.cts +1 -1
  143. package/dist/plugins/insights/model.d.mts +1 -1
  144. package/dist/plugins/insights/model.mjs +1 -1
  145. package/dist/plugins/insights/modelTypes.d.cts +176 -0
  146. package/dist/plugins/insights/modelTypes.d.mts +176 -0
  147. package/dist/plugins/insights/overview.cjs +109 -0
  148. package/dist/plugins/insights/overview.d.cts +15 -0
  149. package/dist/plugins/insights/overview.d.mts +15 -0
  150. package/dist/plugins/insights/overview.mjs +107 -0
  151. package/dist/{insights → plugins/insights}/provider.cjs +33 -14
  152. package/dist/{insights → plugins/insights}/provider.d.cts +2 -2
  153. package/dist/{insights → plugins/insights}/provider.d.mts +2 -2
  154. package/dist/{insights → plugins/insights}/provider.mjs +30 -11
  155. package/dist/{insights → plugins/insights}/queryInput.cjs +2 -2
  156. package/dist/{insights → plugins/insights}/queryInput.mjs +2 -2
  157. package/dist/plugins/insights/reads.cjs +298 -88
  158. package/dist/plugins/insights/reads.d.cts +61 -0
  159. package/dist/plugins/insights/reads.d.mts +61 -0
  160. package/dist/plugins/insights/reads.mjs +298 -90
  161. package/dist/plugins/insights/recordEvent.cjs +223 -39
  162. package/dist/plugins/insights/recordEvent.d.cts +9 -4
  163. package/dist/plugins/insights/recordEvent.d.mts +9 -4
  164. package/dist/plugins/insights/recordEvent.mjs +221 -37
  165. package/dist/{insights → plugins/insights}/routes.cjs +3 -30
  166. package/dist/{insights → plugins/insights}/routes.mjs +4 -28
  167. package/dist/plugins/insights/schema.cjs +182 -40
  168. package/dist/plugins/insights/schema.d.cts +446 -6
  169. package/dist/plugins/insights/schema.d.mts +446 -6
  170. package/dist/plugins/insights/schema.mjs +180 -41
  171. package/dist/plugins/insights/testing/eventRow.d.mts +64 -0
  172. package/dist/plugins/insights/testing/expectInsightsIndex.mjs +18 -0
  173. package/dist/plugins/insights/testing/fixtures.d.mts +8 -0
  174. package/dist/plugins/insights/testing/fixtures.mjs +25 -0
  175. package/dist/plugins/insights/testing/index.d.mts +24 -0
  176. package/dist/plugins/insights/testing/index.mjs +25 -0
  177. package/dist/plugins/insights/testing/insightsModelTests.mjs +714 -0
  178. package/dist/plugins/insights/testing/modelTypes.d.mts +176 -0
  179. package/dist/plugins/insights/testing/setupInsightsHttpTestSuite.d.mts +11 -0
  180. package/dist/plugins/insights/testing/setupInsightsHttpTestSuite.mjs +107 -0
  181. package/dist/plugins/insights/testing/setupInsightsModelTestSuite.d.mts +11 -0
  182. package/dist/plugins/insights/testing/setupInsightsModelTestSuite.mjs +31 -0
  183. package/dist/plugins/insights/testing/types.d.mts +26 -0
  184. package/dist/{insights → plugins/insights}/types.d.cts +3 -2
  185. package/dist/{insights → plugins/insights}/types.d.mts +3 -2
  186. package/package.json +18 -7
  187. package/src/adapters/drizzle.conformance.integration.spec.ts +2 -2
  188. package/src/adapters/drizzle.readBudgets.integration.spec.ts +6 -4
  189. package/src/adapters/drizzle.spec.ts +15 -7
  190. package/src/adapters/drizzle.ts +6 -6
  191. package/src/adapters/kysely.conformance.integration.spec.ts +2 -2
  192. package/src/adapters/kysely.readBudgets.integration.spec.ts +4 -2
  193. package/src/adapters/kysely.spec.ts +13 -9
  194. package/src/adapters/kysely.ts +2 -2
  195. package/src/adapters/mongodb.integration.spec.ts +98 -7
  196. package/src/adapters/mongodb.ts +2 -2
  197. package/src/adapters/mongodbAdapter.ts +14 -0
  198. package/src/adapters/prisma.conformance.integration.spec.ts +2 -2
  199. package/src/adapters/prisma.integration.spec.ts +16 -8
  200. package/src/adapters/prisma.readBudgets.integration.spec.ts +5 -2
  201. package/src/adapters/prisma.spec.ts +17 -9
  202. package/src/adapters/prisma.ts +6 -6
  203. package/src/adapters/prismaTestClients.ts +8 -1
  204. package/src/assembly/assemblePlugins.ts +73 -40
  205. package/src/assembly/assembly.spec.ts +63 -11
  206. package/src/assembly/assembly.types.spec.ts +50 -2
  207. package/src/assembly/clientPlugins.ts +113 -0
  208. package/src/assembly/configError.ts +4 -0
  209. package/src/assembly/databasePlugins.ts +11 -5
  210. package/src/assembly/pluginCli.spec.ts +254 -0
  211. package/src/assembly/pluginCli.ts +248 -0
  212. package/src/assembly/{builtInRoutes.spec.ts → pluginRoutes.spec.ts} +10 -37
  213. package/src/createHotUpdaterCore.ts +21 -17
  214. package/src/database/aggregateBatching.spec.ts +577 -0
  215. package/src/database/aggregateBatching.ts +803 -0
  216. package/src/{insights/errors.spec.ts → database/busy.spec.ts} +2 -5
  217. package/src/{insights/errors.ts → database/busy.ts} +1 -13
  218. package/src/database/database.ts +39 -8
  219. package/src/database/definitions.ts +4 -0
  220. package/src/database/engineAggregates.spec.ts +4 -7
  221. package/src/database/engineAggregates.ts +5 -9
  222. package/src/database/engineReads.ts +7 -5
  223. package/src/database/engineTransaction.ts +1 -7
  224. package/src/database/fence.spec.ts +5 -5
  225. package/src/database/fence.ts +4 -0
  226. package/src/database/index.ts +13 -7
  227. package/src/database/kv/kvAdapter.batching.integration.spec.ts +15 -0
  228. package/src/database/kv/kvAdapter.conformance.integration.spec.ts +2 -0
  229. package/src/database/kv/kvAdapter.spec.ts +128 -1
  230. package/src/database/kv/kvAdapter.ts +30 -1
  231. package/src/database/kv/kvTestStore.ts +28 -1
  232. package/src/database/resolveSchema.ts +4 -1
  233. package/src/database/retention.spec.ts +314 -0
  234. package/src/database/retention.ts +129 -0
  235. package/src/database/schema.ts +44 -0
  236. package/src/database/sql/sqlAdapter.integration.spec.ts +4 -7
  237. package/src/database/sql/sqlAdapter.readBudgets.integration.spec.ts +18 -4
  238. package/src/database/sql/sqlAdapter.spec.ts +91 -3
  239. package/src/database/sql/sqlAdapter.ts +20 -0
  240. package/src/database/sql/sqlSchema.ts +81 -0
  241. package/src/databaseTestSuite.spec.ts +9 -4
  242. package/src/db/coreDatabase.ts +153 -0
  243. package/src/db/engineSql.spec.ts +8 -7
  244. package/src/db/index.ts +19 -2
  245. package/src/db/pluginTables.spec.ts +57 -27
  246. package/src/db/types.ts +3 -3
  247. package/src/diff.ts +6 -0
  248. package/src/handler-standalone.integration.spec.ts +2 -3
  249. package/src/handler.ts +1 -32
  250. package/src/handlerReleaseCatalogRoutes.ts +26 -2
  251. package/src/index.ts +0 -10
  252. package/src/{apiKeys.integration.spec.ts → plugins/api-keys/apiKeys.integration.spec.ts} +4 -4
  253. package/src/{apiKeys.spec.ts → plugins/api-keys/apiKeys.spec.ts} +3 -3
  254. package/src/{apiKeys.ts → plugins/api-keys/apiKeys.ts} +1 -1
  255. package/src/plugins/api-keys/apiKeysPlugin.spec.ts +11 -15
  256. package/src/plugins/api-keys/cli.spec.ts +187 -0
  257. package/src/plugins/api-keys/cli.ts +140 -0
  258. package/src/plugins/api-keys/index.ts +48 -41
  259. package/src/plugins/api-keys/model.ts +21 -2
  260. package/src/plugins/definePlugin.ts +144 -2
  261. package/src/plugins/index.ts +20 -2
  262. package/src/plugins/insights/contract.spec.ts +285 -0
  263. package/src/plugins/insights/contract.ts +372 -0
  264. package/src/{insights → plugins/insights}/domain.ts +73 -15
  265. package/src/plugins/insights/errors.ts +11 -0
  266. package/src/{insights → plugins/insights}/eventInput.ts +189 -29
  267. package/src/plugins/insights/eventRow.ts +209 -0
  268. package/src/plugins/insights/index.ts +181 -45
  269. package/src/{insights → plugins/insights}/insights.integration.spec.ts +330 -34
  270. package/src/plugins/insights/insightsRollout.integration.spec.ts +1 -2
  271. package/src/plugins/insights/model.spec.ts +3 -5
  272. package/src/plugins/insights/model.ts +2 -3
  273. package/src/plugins/insights/modelTypes.ts +197 -0
  274. package/src/plugins/insights/overview.spec.ts +64 -0
  275. package/src/plugins/insights/overview.ts +214 -0
  276. package/src/{insights → plugins/insights}/provider.spec.ts +21 -10
  277. package/src/{insights → plugins/insights}/provider.ts +58 -21
  278. package/src/{insights → plugins/insights}/queryInput.ts +2 -2
  279. package/src/plugins/insights/reads.spec.ts +340 -52
  280. package/src/plugins/insights/reads.ts +453 -123
  281. package/src/plugins/insights/recordEvent.spec.ts +474 -20
  282. package/src/plugins/insights/recordEvent.ts +301 -63
  283. package/src/plugins/insights/retention.spec.ts +115 -0
  284. package/src/{insights → plugins/insights}/routes.ts +1 -31
  285. package/src/plugins/insights/schema.ts +356 -176
  286. package/src/plugins/insights/testing/expectInsightsIndex.spec.ts +42 -0
  287. package/src/plugins/insights/testing/expectInsightsIndex.ts +20 -0
  288. package/src/plugins/insights/testing/fixtures.ts +30 -0
  289. package/src/plugins/insights/testing/index.ts +45 -0
  290. package/src/plugins/insights/testing/insightsModelTests.ts +860 -0
  291. package/src/plugins/insights/testing/setupInsightsHttpTestSuite.ts +152 -0
  292. package/src/plugins/insights/testing/setupInsightsModelTestSuite.ts +36 -0
  293. package/src/plugins/insights/testing/types.ts +30 -0
  294. package/src/{insights → plugins/insights}/types.ts +1 -1
  295. package/src/readBudgets.testFixtures.ts +2 -2
  296. package/src/releaseCatalogRoutes.integration.spec.ts +7 -0
  297. package/src/retention.spec.ts +73 -0
  298. package/src/runtime.spec.ts +11 -12
  299. package/src/runtime.testFixtures.ts +7 -2
  300. package/src/testUtilsMutation.integration.spec.ts +2 -1
  301. package/src/testUtilsPackage.integration.spec.ts +7 -3
  302. package/dist/db/builtInDatabase.cjs +0 -104
  303. package/dist/db/builtInDatabase.d.cts +0 -38
  304. package/dist/db/builtInDatabase.d.mts +0 -38
  305. package/dist/db/builtInDatabase.mjs +0 -97
  306. package/dist/plugins/builtIn.cjs +0 -7
  307. package/dist/plugins/builtIn.mjs +0 -6
  308. package/src/db/builtInDatabase.ts +0 -149
  309. package/src/plugins/builtIn.ts +0 -5
@@ -0,0 +1,121 @@
1
+ import { HotUpdaterConfigError } from "./configError.mjs";
2
+ import { clientPluginsOf } from "./clientPlugins.mjs";
3
+ import { assemblePlugins } from "./assemblePlugins.mjs";
4
+ import { createDatabasePluginApis } from "./databasePlugins.mjs";
5
+ import { createMemoryAdapter } from "@hot-updater/plugin-core/internal";
6
+ //#region src/assembly/pluginCli.ts
7
+ const COMMAND_NAME = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/u;
8
+ const ARGUMENT_NAME = /^[A-Za-z][A-Za-z0-9]*$/u;
9
+ const RESERVED_ARGUMENT = "configPath";
10
+ const fail = (message) => {
11
+ throw new HotUpdaterConfigError(message);
12
+ };
13
+ const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
14
+ const pluginsOf = (value) => Array.isArray(value) ? value.filter(isRecord) : fail("plugins must be an array of plugins.");
15
+ const checkCommand = (plugin, value, path) => {
16
+ const at = `Plugin "${plugin}" command "${[...path, isRecord(value) ? String(value.name) : "?"].join(" ")}"`;
17
+ if (!isRecord(value) || typeof value.name !== "string" || !COMMAND_NAME.test(value.name) || typeof value.description !== "string") return fail(`${at} needs a name of lowercase words joined by hyphens and a description.`);
18
+ const command = value;
19
+ if (typeof command.run === "function" === (command.commands !== void 0)) fail(`${at} needs either subcommands or run, not both.`);
20
+ const names = /* @__PURE__ */ new Set();
21
+ for (const argument of command.arguments ?? []) {
22
+ if (!isRecord(argument) || typeof argument.name !== "string" || !ARGUMENT_NAME.test(argument.name) || argument.name === RESERVED_ARGUMENT || names.has(argument.name) || typeof argument.description !== "string") fail(`${at} has an argument that needs a unique camelCase name other than "${RESERVED_ARGUMENT}" and a description.`);
23
+ names.add(argument.name);
24
+ }
25
+ for (const option of command.options ?? []) if (!isRecord(option) || typeof option.flags !== "string" || !option.flags.includes("--") || typeof option.description !== "string") fail(`${at} has an option that needs --flags and a description.`);
26
+ if (command.commands !== void 0) {
27
+ if (!Array.isArray(command.commands) || command.commands.length === 0) fail(`${at} needs at least one subcommand.`);
28
+ const subcommands = /* @__PURE__ */ new Set();
29
+ for (const subcommand of command.commands) {
30
+ const checked = checkCommand(plugin, subcommand, [...path, command.name]);
31
+ if (subcommands.has(checked.name)) fail(`${at} has two subcommands named "${checked.name}".`);
32
+ subcommands.add(checked.name);
33
+ }
34
+ }
35
+ return command;
36
+ };
37
+ /**
38
+ * The top-level commands the plugins add, each checked. Two plugins may not
39
+ * add the same command.
40
+ */
41
+ const pluginCommandsOf = (plugins) => {
42
+ const entries = [];
43
+ for (const plugin of pluginsOf(plugins)) {
44
+ const commands = plugin.cli?.commands;
45
+ if (commands === void 0) continue;
46
+ const id = String(plugin.id);
47
+ if (!Array.isArray(commands)) fail(`Plugin "${id}" cli.commands must be an array.`);
48
+ for (const value of commands) {
49
+ const command = checkCommand(id, value, []);
50
+ const taken = entries.find((entry) => entry.command.name === command.name);
51
+ if (taken !== void 0) fail(`Plugins "${taken.plugin}" and "${id}" both add the command "${command.name}"; keep one.`);
52
+ entries.push({
53
+ plugin: id,
54
+ command
55
+ });
56
+ }
57
+ }
58
+ return entries;
59
+ };
60
+ /** The clientAuth plugin's credential contribution, checked. */
61
+ const credentialOf = (plugins) => {
62
+ const plugin = pluginsOf(plugins).find(({ provides }) => provides?.clientAuth === true);
63
+ if (plugin === void 0) return void 0;
64
+ const id = String(plugin.id);
65
+ const credential = plugin.cli?.clientCredential;
66
+ if (!isRecord(credential) || typeof credential.label !== "string" || typeof credential.header !== "string" || typeof credential.env !== "string" || typeof credential.generate !== "function" || typeof credential.provision !== "function") return fail(`Plugin "${id}" provides clientAuth but no cli.clientCredential with a label, header, env, generate, and provision, so init cannot give an app its credential.`);
67
+ return {
68
+ plugin: id,
69
+ credential
70
+ };
71
+ };
72
+ /**
73
+ * The client-route policy the plugins set: the plugin that provides
74
+ * clientAuth, the headers its decision reads, and the credential an app
75
+ * sends. Undefined when client routes are public. The plugins initialize on
76
+ * a throwaway in-memory database, since `varyHeaders` live on the instance.
77
+ */
78
+ const clientAuthOf = (plugins) => {
79
+ const found = credentialOf(plugins);
80
+ if (found === void 0) return void 0;
81
+ const { clientAuth } = assemblePlugins(plugins, createMemoryAdapter());
82
+ const { label, header, env } = found.credential;
83
+ return {
84
+ plugin: found.plugin,
85
+ varyHeaders: (clientAuth?.varyHeaders ?? []).map((name) => name.toLowerCase()),
86
+ credential: {
87
+ label,
88
+ header: header.toLowerCase(),
89
+ env
90
+ }
91
+ };
92
+ };
93
+ /**
94
+ * A new client credential, made without a database, so tooling can save it
95
+ * before it registers it. Undefined when client routes are public.
96
+ */
97
+ const generateClientCredential = (plugins) => credentialOf(plugins)?.credential.generate();
98
+ /**
99
+ * Provisions the credential an app sends to client routes, through the
100
+ * plugin that provides clientAuth, on the tables the server reads: a
101
+ * credential saved in `env` is registered again rather than replaced.
102
+ * Undefined when client routes are public.
103
+ */
104
+ const provisionClientCredential = async (database, plugins, input) => {
105
+ const found = credentialOf(plugins);
106
+ if (found === void 0) return void 0;
107
+ const { label, header, env, provision } = found.credential;
108
+ const existing = input.env[env]?.trim();
109
+ const value = await provision(createDatabasePluginApis(database, plugins)[found.plugin], {
110
+ ...existing ? { existing } : {},
111
+ name: input.name
112
+ });
113
+ return {
114
+ label,
115
+ header: header.toLowerCase(),
116
+ env,
117
+ value
118
+ };
119
+ };
120
+ //#endregion
121
+ export { clientAuthOf, clientPluginsOf, generateClientCredential, pluginCommandsOf, provisionClientCredential };
@@ -1,4 +1,5 @@
1
- const require_builtInDatabase = require("./db/builtInDatabase.cjs");
1
+ const require_coreDatabase = require("./db/coreDatabase.cjs");
2
+ const require_configError = require("./assembly/configError.cjs");
2
3
  const require_assemblePlugins = require("./assembly/assemblePlugins.cjs");
3
4
  const require_handler = require("./handler.cjs");
4
5
  const require_storageAccess = require("./storageAccess.cjs");
@@ -15,21 +16,15 @@ const isAdapter = (value) => isRecord(value) && [
15
16
  const databaseOf = (value) => {
16
17
  if (isRecord(value) && typeof value.name === "string") {
17
18
  if (isAdapter(value.adapter)) return value;
18
- if ("core" in value && "fetchAdmin" in value) throw new require_assemblePlugins.HotUpdaterConfigError("standaloneRepository reaches a server's admin API from the CLI and console. createHotUpdater needs the server's own database, such as kyselyAdapter(...).");
19
+ if ("core" in value && "fetchAdmin" in value) throw new require_configError.HotUpdaterConfigError("standaloneRepository reaches a server's admin API from the CLI and console. createHotUpdater needs the server's own database, such as kyselyAdapter(...).");
19
20
  }
20
- throw new require_assemblePlugins.HotUpdaterConfigError("database must be a Hot Updater 1.0 database, such as kyselyAdapter(...) or postgres(...). Upgrade the provider package that created it.");
21
+ throw new require_configError.HotUpdaterConfigError("database must be a Hot Updater 1.0 database, such as kyselyAdapter(...) or postgres(...). Upgrade the provider package that created it.");
21
22
  };
22
- /** A release candidate's config moving to 1.0 also needs `insights()`. */
23
- const KEEP_INSIGHTS = "To keep Insights, which the release candidates ran by default, add insights() from @hot-updater/server/plugins/insights to plugins.";
24
- /** `"public"`, or nothing; a `clientAccess` object names what replaced it. */
23
+ /** `"public"`, or nothing; a `clientAccess` object says what replaced it. */
25
24
  const isPublic = (value) => {
26
25
  if (value === void 0) return false;
27
26
  if (value === "public") return true;
28
- if (isRecord(value)) {
29
- const type = value.type;
30
- throw new require_assemblePlugins.HotUpdaterConfigError(type === "api-key" ? `clientAccess: { type: "api-key" } was removed in 1.0. Remove it and add apiKeys(${value.headerName === void 0 ? "" : `{ headerName: ${JSON.stringify(value.headerName)} }`}) from @hot-updater/server/plugins/api-keys to plugins, which protects client routes the same way. ${KEEP_INSIGHTS}` : `clientAccess objects were removed in 1.0. Use clientAccess: "public", or add apiKeys() from @hot-updater/server/plugins/api-keys to plugins. ${KEEP_INSIGHTS}`);
31
- }
32
- throw new require_assemblePlugins.HotUpdaterConfigError("clientAccess must be \"public\"; to protect client routes, add apiKeys() from @hot-updater/server/plugins/api-keys to plugins.");
27
+ throw new require_configError.HotUpdaterConfigError(isRecord(value) ? "clientAccess objects were removed in 1.0. Set clientAccess: \"public\", or add a plugin that provides clientAuth to plugins." : "clientAccess must be \"public\"; to protect client routes, add a plugin that provides clientAuth to plugins.");
33
28
  };
34
29
  const hotUpdaterCoreMetadata = Symbol.for("@hot-updater/server/core-metadata");
35
30
  function getHotUpdaterCoreMetadata(hotUpdater) {
@@ -49,11 +44,12 @@ function createHotUpdater(options) {
49
44
  readStorageText,
50
45
  resolveFileUrl
51
46
  },
52
- ...database.onCachedRoutesChange === void 0 ? {} : { onCachedRoutesChange: () => database.onCachedRoutesChange() }
47
+ ...database.onCachedRoutesChange === void 0 ? {} : { onCachedRoutesChange: () => database.onCachedRoutesChange() },
48
+ ...database.aggregateBatching === void 0 ? {} : { batching: database.aggregateBatching }
53
49
  });
54
50
  const clientAuth = plugins.clientAuth;
55
- if (clientAuth !== void 0 && publicClients) throw new require_assemblePlugins.HotUpdaterConfigError(`Plugin "${clientAuth.plugin}" provides clientAuth, so remove clientAccess.`);
56
- if (clientAuth === void 0 && !publicClients) throw new require_assemblePlugins.HotUpdaterConfigError("Set clientAccess to \"public\", or add a plugin that provides clientAuth.");
51
+ if (clientAuth !== void 0 && publicClients) throw new require_configError.HotUpdaterConfigError(`Plugin "${clientAuth.plugin}" provides clientAuth, so remove clientAccess.`);
52
+ if (clientAuth === void 0 && !publicClients) throw new require_configError.HotUpdaterConfigError("Set clientAccess to \"public\", or add a plugin that provides clientAuth.");
57
53
  const clientPolicy = clientAuth === void 0 ? void 0 : {
58
54
  varyHeaders: clientAuth.varyHeaders.map((header) => header.toLowerCase()),
59
55
  authenticate: (request) => clientAuth.authenticate(request.headers)
@@ -69,13 +65,15 @@ function createHotUpdater(options) {
69
65
  adapterName: database.name,
70
66
  handlers,
71
67
  core: plugins.core,
72
- api: plugins.api
68
+ api: plugins.api,
69
+ flush: plugins.flush
73
70
  };
74
71
  Object.defineProperty(api, hotUpdaterCoreMetadata, {
75
72
  enumerable: false,
76
73
  value: {
77
74
  database,
78
- target: require_builtInDatabase.toolingTargetOf(options.plugins ?? [])
75
+ target: require_coreDatabase.toolingTargetOf(options.plugins ?? []),
76
+ plugins: options.plugins ?? []
79
77
  }
80
78
  });
81
79
  return api;
@@ -1,6 +1,6 @@
1
1
  import { ToolingDatabase } from "./db/types.cjs";
2
- import { CoreApi } from "./core/api.cjs";
3
2
  import { AnyHotUpdaterPlugin, PluginApis } from "./plugins/definePlugin.cjs";
3
+ import { CoreApi } from "./core/api.cjs";
4
4
  import { HotUpdaterHandlers } from "./handlerTypes.cjs";
5
5
  import "./handler.cjs";
6
6
  import { StoragePlugin } from "@hot-updater/plugin-core";
@@ -13,9 +13,16 @@ type RuntimeHotUpdaterAPI<TPlugins extends readonly AnyHotUpdaterPlugin[] = read
13
13
  readonly api: PluginApis<TPlugins>;
14
14
  /** The database's name, which `hot-updater db` commands read. */
15
15
  readonly adapterName: string;
16
+ /**
17
+ * Applies aggregate changes the database batches that are still pending:
18
+ * this process's buffer, and the log rows no compaction has merged yet.
19
+ * A long-lived server with `aggregateBatching: { mode: "memory" }` calls
20
+ * it before it exits.
21
+ */
22
+ readonly flush: () => Promise<void>;
16
23
  };
17
24
  type HotUpdaterAPI = RuntimeHotUpdaterAPI;
18
- declare const REMOVED_CLIENT_ACCESS = "clientAccess objects were removed in 1.0: set clientAccess: \"public\", or add apiKeys() from @hot-updater/server/plugins/api-keys to plugins";
25
+ declare const REMOVED_CLIENT_ACCESS = "clientAccess objects were removed in 1.0: set clientAccess: \"public\", or add a plugin that provides clientAuth";
19
26
  /**
20
27
  * A `clientAccess` object from before 1.0. Its `type` names the fix, so
21
28
  * TypeScript reports it where the object is written.
@@ -57,7 +64,7 @@ type CreateHotUpdaterOptions<TPlugins extends readonly AnyHotUpdaterPlugin[] = r
57
64
  readonly database: ToolingDatabase;
58
65
  /** Storage implementations used to read provider-specific storage URIs. */
59
66
  readonly storage?: readonly StoragePlugin[];
60
- /** Built-in and third-party plugins; at most one provides clientAuth. Defaults to none. */
67
+ /** The plugins the server runs; at most one provides clientAuth. Defaults to none. */
61
68
  readonly plugins?: TPlugins;
62
69
  } & ClientAccessRule<TPlugins>;
63
70
  declare function createHotUpdater<const TPlugins extends readonly AnyHotUpdaterPlugin[] = readonly []>(options: CreateHotUpdaterOptions<TPlugins>): RuntimeHotUpdaterAPI<NoInfer<TPlugins>>;
@@ -1,6 +1,6 @@
1
1
  import { ToolingDatabase } from "./db/types.mjs";
2
- import { CoreApi } from "./core/api.mjs";
3
2
  import { AnyHotUpdaterPlugin, PluginApis } from "./plugins/definePlugin.mjs";
3
+ import { CoreApi } from "./core/api.mjs";
4
4
  import { HotUpdaterHandlers } from "./handlerTypes.mjs";
5
5
  import "./handler.mjs";
6
6
  import { StoragePlugin } from "@hot-updater/plugin-core";
@@ -13,9 +13,16 @@ type RuntimeHotUpdaterAPI<TPlugins extends readonly AnyHotUpdaterPlugin[] = read
13
13
  readonly api: PluginApis<TPlugins>;
14
14
  /** The database's name, which `hot-updater db` commands read. */
15
15
  readonly adapterName: string;
16
+ /**
17
+ * Applies aggregate changes the database batches that are still pending:
18
+ * this process's buffer, and the log rows no compaction has merged yet.
19
+ * A long-lived server with `aggregateBatching: { mode: "memory" }` calls
20
+ * it before it exits.
21
+ */
22
+ readonly flush: () => Promise<void>;
16
23
  };
17
24
  type HotUpdaterAPI = RuntimeHotUpdaterAPI;
18
- declare const REMOVED_CLIENT_ACCESS = "clientAccess objects were removed in 1.0: set clientAccess: \"public\", or add apiKeys() from @hot-updater/server/plugins/api-keys to plugins";
25
+ declare const REMOVED_CLIENT_ACCESS = "clientAccess objects were removed in 1.0: set clientAccess: \"public\", or add a plugin that provides clientAuth";
19
26
  /**
20
27
  * A `clientAccess` object from before 1.0. Its `type` names the fix, so
21
28
  * TypeScript reports it where the object is written.
@@ -57,7 +64,7 @@ type CreateHotUpdaterOptions<TPlugins extends readonly AnyHotUpdaterPlugin[] = r
57
64
  readonly database: ToolingDatabase;
58
65
  /** Storage implementations used to read provider-specific storage URIs. */
59
66
  readonly storage?: readonly StoragePlugin[];
60
- /** Built-in and third-party plugins; at most one provides clientAuth. Defaults to none. */
67
+ /** The plugins the server runs; at most one provides clientAuth. Defaults to none. */
61
68
  readonly plugins?: TPlugins;
62
69
  } & ClientAccessRule<TPlugins>;
63
70
  declare function createHotUpdater<const TPlugins extends readonly AnyHotUpdaterPlugin[] = readonly []>(options: CreateHotUpdaterOptions<TPlugins>): RuntimeHotUpdaterAPI<NoInfer<TPlugins>>;
@@ -1,5 +1,6 @@
1
- import { toolingTargetOf } from "./db/builtInDatabase.mjs";
2
- import { HotUpdaterConfigError, assemblePlugins } from "./assembly/assemblePlugins.mjs";
1
+ import { toolingTargetOf } from "./db/coreDatabase.mjs";
2
+ import { HotUpdaterConfigError } from "./assembly/configError.mjs";
3
+ import { assemblePlugins } from "./assembly/assemblePlugins.mjs";
3
4
  import { createHotUpdaterHandlers } from "./handler.mjs";
4
5
  import { createStorageAccess } from "./storageAccess.mjs";
5
6
  import { assertStorageOperations } from "@hot-updater/plugin-core";
@@ -19,17 +20,11 @@ const databaseOf = (value) => {
19
20
  }
20
21
  throw new HotUpdaterConfigError("database must be a Hot Updater 1.0 database, such as kyselyAdapter(...) or postgres(...). Upgrade the provider package that created it.");
21
22
  };
22
- /** A release candidate's config moving to 1.0 also needs `insights()`. */
23
- const KEEP_INSIGHTS = "To keep Insights, which the release candidates ran by default, add insights() from @hot-updater/server/plugins/insights to plugins.";
24
- /** `"public"`, or nothing; a `clientAccess` object names what replaced it. */
23
+ /** `"public"`, or nothing; a `clientAccess` object says what replaced it. */
25
24
  const isPublic = (value) => {
26
25
  if (value === void 0) return false;
27
26
  if (value === "public") return true;
28
- if (isRecord(value)) {
29
- const type = value.type;
30
- throw new HotUpdaterConfigError(type === "api-key" ? `clientAccess: { type: "api-key" } was removed in 1.0. Remove it and add apiKeys(${value.headerName === void 0 ? "" : `{ headerName: ${JSON.stringify(value.headerName)} }`}) from @hot-updater/server/plugins/api-keys to plugins, which protects client routes the same way. ${KEEP_INSIGHTS}` : `clientAccess objects were removed in 1.0. Use clientAccess: "public", or add apiKeys() from @hot-updater/server/plugins/api-keys to plugins. ${KEEP_INSIGHTS}`);
31
- }
32
- throw new HotUpdaterConfigError("clientAccess must be \"public\"; to protect client routes, add apiKeys() from @hot-updater/server/plugins/api-keys to plugins.");
27
+ throw new HotUpdaterConfigError(isRecord(value) ? "clientAccess objects were removed in 1.0. Set clientAccess: \"public\", or add a plugin that provides clientAuth to plugins." : "clientAccess must be \"public\"; to protect client routes, add a plugin that provides clientAuth to plugins.");
33
28
  };
34
29
  const hotUpdaterCoreMetadata = Symbol.for("@hot-updater/server/core-metadata");
35
30
  function getHotUpdaterCoreMetadata(hotUpdater) {
@@ -49,7 +44,8 @@ function createHotUpdater(options) {
49
44
  readStorageText,
50
45
  resolveFileUrl
51
46
  },
52
- ...database.onCachedRoutesChange === void 0 ? {} : { onCachedRoutesChange: () => database.onCachedRoutesChange() }
47
+ ...database.onCachedRoutesChange === void 0 ? {} : { onCachedRoutesChange: () => database.onCachedRoutesChange() },
48
+ ...database.aggregateBatching === void 0 ? {} : { batching: database.aggregateBatching }
53
49
  });
54
50
  const clientAuth = plugins.clientAuth;
55
51
  if (clientAuth !== void 0 && publicClients) throw new HotUpdaterConfigError(`Plugin "${clientAuth.plugin}" provides clientAuth, so remove clientAccess.`);
@@ -69,13 +65,15 @@ function createHotUpdater(options) {
69
65
  adapterName: database.name,
70
66
  handlers,
71
67
  core: plugins.core,
72
- api: plugins.api
68
+ api: plugins.api,
69
+ flush: plugins.flush
73
70
  };
74
71
  Object.defineProperty(api, hotUpdaterCoreMetadata, {
75
72
  enumerable: false,
76
73
  value: {
77
74
  database,
78
- target: toolingTargetOf(options.plugins ?? [])
75
+ target: toolingTargetOf(options.plugins ?? []),
76
+ plugins: options.plugins ?? []
79
77
  }
80
78
  });
81
79
  return api;