@hot-updater/server 0.36.7 → 1.0.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (291) hide show
  1. package/dist/adapters/databaseConstraintErrors.cjs +23 -0
  2. package/dist/adapters/databaseConstraintErrors.mjs +21 -0
  3. package/dist/adapters/databasePluginUtils.cjs +117 -0
  4. package/dist/adapters/databasePluginUtils.mjs +106 -0
  5. package/dist/adapters/drizzle.cjs +53 -176
  6. package/dist/adapters/drizzle.d.cts +6 -4
  7. package/dist/adapters/drizzle.d.mts +6 -4
  8. package/dist/adapters/drizzle.mjs +54 -177
  9. package/dist/adapters/drizzleCrud.cjs +250 -0
  10. package/dist/adapters/drizzleCrud.mjs +249 -0
  11. package/dist/adapters/drizzleLazyDB.cjs +84 -36
  12. package/dist/adapters/drizzleLazyDB.mjs +84 -36
  13. package/dist/adapters/drizzleQuery.cjs +68 -0
  14. package/dist/adapters/drizzleQuery.mjs +67 -0
  15. package/dist/adapters/kysely.cjs +18 -138
  16. package/dist/adapters/kysely.d.cts +3 -12
  17. package/dist/adapters/kysely.d.mts +3 -12
  18. package/dist/adapters/kysely.mjs +19 -139
  19. package/dist/adapters/kyselyCrud.cjs +254 -0
  20. package/dist/adapters/kyselyCrud.mjs +253 -0
  21. package/dist/adapters/kyselyQuery.cjs +56 -0
  22. package/dist/adapters/kyselyQuery.mjs +55 -0
  23. package/dist/adapters/mongodb.cjs +21 -174
  24. package/dist/adapters/mongodb.d.cts +3 -2
  25. package/dist/adapters/mongodb.d.mts +3 -2
  26. package/dist/adapters/mongodb.mjs +21 -174
  27. package/dist/adapters/mongodbCollections.cjs +36 -0
  28. package/dist/adapters/mongodbCollections.mjs +30 -0
  29. package/dist/adapters/mongodbQuery.cjs +77 -0
  30. package/dist/adapters/mongodbQuery.mjs +70 -0
  31. package/dist/adapters/mongodbReads.cjs +148 -0
  32. package/dist/adapters/mongodbReads.mjs +147 -0
  33. package/dist/adapters/mongodbWrites.cjs +134 -0
  34. package/dist/adapters/mongodbWrites.mjs +133 -0
  35. package/dist/adapters/prisma.cjs +205 -180
  36. package/dist/adapters/prisma.d.cts +3 -3
  37. package/dist/adapters/prisma.d.mts +3 -3
  38. package/dist/adapters/prisma.mjs +206 -181
  39. package/dist/adapters/prismaQuery.cjs +58 -0
  40. package/dist/adapters/prismaQuery.mjs +56 -0
  41. package/dist/adapters/prismaRows.cjs +198 -0
  42. package/dist/adapters/prismaRows.mjs +188 -0
  43. package/dist/analytics/bounded/activeOverview.cjs +87 -0
  44. package/dist/analytics/bounded/activeOverview.mjs +85 -0
  45. package/dist/analytics/bounded/installationSearch.cjs +42 -0
  46. package/dist/analytics/bounded/installationSearch.mjs +42 -0
  47. package/dist/analytics/bounded/persistence.cjs +39 -0
  48. package/dist/analytics/bounded/persistence.mjs +38 -0
  49. package/dist/analytics/bounded/provider.cjs +170 -0
  50. package/dist/analytics/bounded/provider.d.cts +7 -0
  51. package/dist/analytics/bounded/provider.d.mts +7 -0
  52. package/dist/analytics/bounded/provider.mjs +170 -0
  53. package/dist/analytics/bounded/scan.cjs +144 -0
  54. package/dist/analytics/bounded/scan.mjs +138 -0
  55. package/dist/analytics/domain.d.cts +121 -0
  56. package/dist/analytics/domain.d.mts +121 -0
  57. package/dist/analytics/errors.cjs +22 -0
  58. package/dist/analytics/errors.mjs +20 -0
  59. package/dist/analytics/eventInput.cjs +111 -0
  60. package/dist/analytics/eventInput.mjs +111 -0
  61. package/dist/analytics/persistence.d.cts +6 -0
  62. package/dist/analytics/persistence.d.mts +6 -0
  63. package/dist/analytics/queryInput.cjs +58 -0
  64. package/dist/analytics/queryInput.mjs +55 -0
  65. package/dist/analytics/routes.cjs +63 -0
  66. package/dist/analytics/routes.mjs +61 -0
  67. package/dist/analytics/types.d.cts +17 -0
  68. package/dist/analytics/types.d.mts +17 -0
  69. package/dist/apiKeys.cjs +139 -0
  70. package/dist/apiKeys.d.cts +50 -0
  71. package/dist/apiKeys.d.mts +50 -0
  72. package/dist/apiKeys.mjs +133 -0
  73. package/dist/createHotUpdaterCore.cjs +48 -26
  74. package/dist/createHotUpdaterCore.d.cts +49 -17
  75. package/dist/createHotUpdaterCore.d.mts +49 -17
  76. package/dist/createHotUpdaterCore.mjs +51 -29
  77. package/dist/db/createBundleDiff.cjs +45 -68
  78. package/dist/db/createBundleDiff.d.cts +3 -3
  79. package/dist/db/createBundleDiff.d.mts +3 -3
  80. package/dist/db/createBundleDiff.mjs +47 -68
  81. package/dist/db/databasePluginCore.cjs +138 -0
  82. package/dist/db/databasePluginCore.mjs +137 -0
  83. package/dist/db/fixedMigrator.cjs +36 -93
  84. package/dist/db/fixedMigrator.mjs +36 -93
  85. package/dist/db/fixedMigratorMongo.cjs +319 -0
  86. package/dist/db/fixedMigratorMongo.mjs +319 -0
  87. package/dist/db/fixedMigratorShared.cjs +23 -0
  88. package/dist/db/fixedMigratorShared.mjs +18 -0
  89. package/dist/db/mongoMigrationExecution.cjs +11 -0
  90. package/dist/db/mongoMigrationExecution.mjs +11 -0
  91. package/dist/db/releaseCatalog.cjs +66 -0
  92. package/dist/db/releaseCatalog.d.cts +17 -0
  93. package/dist/db/releaseCatalog.d.mts +17 -0
  94. package/dist/db/releaseCatalog.mjs +64 -0
  95. package/dist/db/schema/mongodb.cjs +14 -6
  96. package/dist/db/schema/mongodb.mjs +14 -6
  97. package/dist/db/schema/registry.cjs +0 -2
  98. package/dist/db/schema/registry.mjs +1 -2
  99. package/dist/db/schema/sql.cjs +31 -14
  100. package/dist/db/schema/sql.mjs +32 -13
  101. package/dist/db/schema/sqlOperations.cjs +4 -4
  102. package/dist/db/schema/sqlOperations.mjs +5 -5
  103. package/dist/db/schemaGenerators.cjs +52 -18
  104. package/dist/db/schemaGenerators.mjs +52 -18
  105. package/dist/db/schemaReadiness.cjs +4 -3
  106. package/dist/db/schemaReadiness.mjs +4 -3
  107. package/dist/db/sqlMigrationExecution.cjs +67 -0
  108. package/dist/db/sqlMigrationExecution.mjs +66 -0
  109. package/dist/db/types.cjs +2 -6
  110. package/dist/db/types.d.cts +60 -16
  111. package/dist/db/types.d.mts +60 -16
  112. package/dist/db/types.mjs +3 -6
  113. package/dist/db/updateArtifacts.cjs +114 -60
  114. package/dist/db/updateArtifacts.mjs +117 -62
  115. package/dist/handler.cjs +108 -282
  116. package/dist/handler.d.cts +3 -46
  117. package/dist/handler.d.mts +3 -46
  118. package/dist/handler.mjs +107 -281
  119. package/dist/handlerBundleRoutes.cjs +155 -0
  120. package/dist/handlerBundleRoutes.mjs +155 -0
  121. package/dist/handlerErrors.cjs +9 -0
  122. package/dist/handlerErrors.mjs +9 -0
  123. package/dist/handlerParameters.cjs +39 -0
  124. package/dist/handlerParameters.mjs +34 -0
  125. package/dist/handlerReleaseCatalogRoutes.cjs +111 -0
  126. package/dist/handlerReleaseCatalogRoutes.mjs +110 -0
  127. package/dist/handlerReleaseManagementRoutes.cjs +125 -0
  128. package/dist/handlerReleaseManagementRoutes.mjs +124 -0
  129. package/dist/handlerTypes.d.cts +63 -0
  130. package/dist/handlerTypes.d.mts +63 -0
  131. package/dist/handlerVersionRoutes.cjs +10 -0
  132. package/dist/handlerVersionRoutes.d.cts +4 -0
  133. package/dist/handlerVersionRoutes.d.mts +4 -0
  134. package/dist/handlerVersionRoutes.mjs +9 -0
  135. package/dist/index.cjs +10 -1
  136. package/dist/index.d.cts +9 -3
  137. package/dist/index.d.mts +9 -3
  138. package/dist/index.mjs +5 -2
  139. package/dist/node.cjs +19 -12
  140. package/dist/node.d.cts +15 -10
  141. package/dist/node.d.mts +15 -10
  142. package/dist/node.mjs +19 -13
  143. package/dist/package.cjs +1 -1
  144. package/dist/package.mjs +1 -1
  145. package/dist/schema/dsl.cjs +19 -2
  146. package/dist/schema/dsl.mjs +17 -3
  147. package/dist/schema/index.cjs +1 -8
  148. package/dist/schema/index.mjs +2 -8
  149. package/dist/schema/types.cjs +3 -1
  150. package/dist/schema/types.mjs +3 -2
  151. package/dist/schema/v1_0_0.cjs +364 -0
  152. package/dist/schema/v1_0_0.mjs +357 -0
  153. package/dist/storageAccess.cjs +69 -25
  154. package/dist/storageAccess.mjs +68 -25
  155. package/dist/types/index.d.cts +4 -3
  156. package/dist/types/index.d.mts +5 -4
  157. package/package.json +8 -7
  158. package/src/adapters/databaseConstraintErrors.ts +25 -0
  159. package/src/adapters/databasePluginTestDatabase.ts +106 -0
  160. package/src/adapters/databasePluginUtils.spec.ts +29 -0
  161. package/src/adapters/databasePluginUtils.ts +214 -0
  162. package/src/adapters/drizzle.spec.ts +208 -47
  163. package/src/adapters/drizzle.ts +106 -293
  164. package/src/adapters/drizzleCrud.ts +419 -0
  165. package/src/adapters/drizzleLazyDB.ts +206 -100
  166. package/src/adapters/drizzleQuery.ts +164 -0
  167. package/src/adapters/kysely.spec.ts +126 -88
  168. package/src/adapters/kysely.ts +76 -334
  169. package/src/adapters/kyselyCrud.ts +588 -0
  170. package/src/adapters/kyselyQuery.ts +128 -0
  171. package/src/adapters/mongodb.spec.ts +141 -0
  172. package/src/adapters/mongodb.ts +60 -288
  173. package/src/adapters/mongodbCollections.ts +62 -0
  174. package/src/adapters/mongodbQuery.ts +226 -0
  175. package/src/adapters/mongodbReads.ts +311 -0
  176. package/src/adapters/mongodbRows.spec.ts +64 -0
  177. package/src/adapters/mongodbRows.ts +118 -0
  178. package/src/adapters/mongodbTestClient.ts +342 -0
  179. package/src/adapters/mongodbTestFilter.ts +166 -0
  180. package/src/adapters/mongodbWrites.ts +260 -0
  181. package/src/adapters/prisma.spec.ts +196 -0
  182. package/src/adapters/prisma.ts +417 -292
  183. package/src/adapters/prismaQuery.ts +129 -0
  184. package/src/adapters/prismaRows.spec.ts +98 -0
  185. package/src/adapters/prismaRows.ts +301 -0
  186. package/src/adapters/prismaTestClient.ts +396 -0
  187. package/src/analytics/analytics.integration.spec.ts +144 -0
  188. package/src/analytics/bounded/activeOverview.spec.ts +189 -0
  189. package/src/analytics/bounded/activeOverview.ts +148 -0
  190. package/src/analytics/bounded/installationSearch.spec.ts +130 -0
  191. package/src/analytics/bounded/installationSearch.ts +69 -0
  192. package/src/analytics/bounded/persistence.ts +43 -0
  193. package/src/analytics/bounded/provider.spec.ts +219 -0
  194. package/src/analytics/bounded/provider.ts +229 -0
  195. package/src/analytics/bounded/scan.ts +235 -0
  196. package/src/analytics/domain.ts +139 -0
  197. package/src/analytics/errors.ts +18 -0
  198. package/src/analytics/eventInput.ts +168 -0
  199. package/src/analytics/persistence.ts +10 -0
  200. package/src/analytics/queryInput.ts +102 -0
  201. package/src/analytics/routes.ts +123 -0
  202. package/src/analytics/types.ts +44 -0
  203. package/src/apiKeys.integration.spec.ts +192 -0
  204. package/src/apiKeys.spec.ts +162 -0
  205. package/src/apiKeys.ts +220 -0
  206. package/src/createHotUpdaterCore.ts +164 -100
  207. package/src/db/bundleRows.spec.ts +164 -0
  208. package/src/db/bundleRows.ts +10 -140
  209. package/src/db/createBundleDiff.spec.ts +172 -127
  210. package/src/db/createBundleDiff.ts +91 -110
  211. package/src/db/databasePluginCore.spec.ts +62 -0
  212. package/src/db/databasePluginCore.testFixtures.ts +76 -0
  213. package/src/db/databasePluginCore.ts +185 -0
  214. package/src/db/databasePluginUpdateCheck.bench.ts +107 -0
  215. package/src/db/fixedMigrator.spec.ts +184 -42
  216. package/src/db/fixedMigrator.ts +64 -205
  217. package/src/db/fixedMigratorMongo.spec.ts +192 -0
  218. package/src/db/fixedMigratorMongo.ts +425 -0
  219. package/src/db/fixedMigratorShared.ts +36 -0
  220. package/src/db/hotUpdaterSchema.ts +0 -1
  221. package/src/db/index.spec.ts +333 -1025
  222. package/src/db/mongoMigrationExecution.ts +23 -0
  223. package/src/db/node-sqlite.d.ts +25 -0
  224. package/src/db/releaseCatalog.ts +148 -0
  225. package/src/db/schema/mongodb.ts +20 -6
  226. package/src/db/schema/sql.ts +52 -11
  227. package/src/db/schema/sqlOperations.ts +5 -4
  228. package/src/db/schemaGenerators.ts +107 -23
  229. package/src/db/schemaReadiness.ts +2 -1
  230. package/src/db/sqlMigrationExecution.spec.ts +65 -0
  231. package/src/db/sqlMigrationExecution.ts +108 -0
  232. package/src/db/types.spec.ts +55 -0
  233. package/src/db/types.ts +129 -65
  234. package/src/db/updateArtifacts.spec.ts +359 -0
  235. package/src/db/updateArtifacts.ts +290 -126
  236. package/src/handler-standalone.integration.spec.ts +401 -364
  237. package/src/handler.spec.ts +137 -582
  238. package/src/handler.testFixtures.ts +30 -0
  239. package/src/handler.ts +218 -616
  240. package/src/handlerAuth.integration.spec.ts +33 -0
  241. package/src/handlerBundleRoutes.ts +259 -0
  242. package/src/handlerErrors.ts +7 -0
  243. package/src/handlerManagement.spec.ts +262 -0
  244. package/src/handlerParameters.ts +105 -0
  245. package/src/handlerReleaseCatalogRoutes.ts +154 -0
  246. package/src/handlerReleaseManagementRoutes.ts +213 -0
  247. package/src/handlerTypes.ts +96 -0
  248. package/src/handlerVersionRoutes.ts +12 -0
  249. package/src/index.ts +22 -2
  250. package/src/node.spec.ts +79 -10
  251. package/src/node.ts +20 -17
  252. package/src/releaseCatalogRoutes.integration.spec.ts +238 -0
  253. package/src/runtime.spec.ts +126 -959
  254. package/src/runtime.testFixtures.ts +71 -0
  255. package/src/schema/dsl-all-versions.spec.ts +26 -17
  256. package/src/schema/dsl.ts +41 -2
  257. package/src/schema/index.ts +3 -9
  258. package/src/schema/types.ts +9 -3
  259. package/src/schema/v1_0_0.spec.ts +146 -0
  260. package/src/schema/v1_0_0.ts +465 -0
  261. package/src/storageAccess.spec.ts +127 -32
  262. package/src/storageAccess.ts +106 -55
  263. package/src/types/index.ts +2 -1
  264. package/dist/db/bundleRows.cjs +0 -82
  265. package/dist/db/bundleRows.d.cts +0 -33
  266. package/dist/db/bundleRows.d.mts +0 -33
  267. package/dist/db/bundleRows.mjs +0 -79
  268. package/dist/db/pluginCore.cjs +0 -242
  269. package/dist/db/pluginCore.mjs +0 -241
  270. package/dist/db/schema/sqlMigrations.cjs +0 -74
  271. package/dist/db/schema/sqlMigrations.mjs +0 -73
  272. package/dist/db/schemaEnhancements.cjs +0 -20
  273. package/dist/db/schemaEnhancements.mjs +0 -19
  274. package/dist/route.cjs +0 -7
  275. package/dist/route.mjs +0 -7
  276. package/dist/schema/v0_21_0.cjs +0 -38
  277. package/dist/schema/v0_21_0.mjs +0 -37
  278. package/dist/schema/v0_29_0.cjs +0 -45
  279. package/dist/schema/v0_29_0.mjs +0 -44
  280. package/dist/schema/v0_31_0.cjs +0 -82
  281. package/dist/schema/v0_31_0.mjs +0 -80
  282. package/src/db/pluginCore.spec.ts +0 -1095
  283. package/src/db/pluginCore.ts +0 -475
  284. package/src/db/pluginUpdateCheck.bench.ts +0 -254
  285. package/src/db/schema/sqlMigrations.ts +0 -219
  286. package/src/db/schemaEnhancements.ts +0 -55
  287. package/src/route.ts +0 -7
  288. package/src/schema/v0_21_0.ts +0 -52
  289. package/src/schema/v0_29_0.ts +0 -62
  290. package/src/schema/v0_31_0.spec.ts +0 -73
  291. package/src/schema/v0_31_0.ts +0 -120
@@ -0,0 +1,71 @@
1
+ import type { Bundle } from "@hot-updater/core";
2
+ import type {
3
+ DatabasePlugin,
4
+ StoragePlugin,
5
+ StoragePluginWith,
6
+ } from "@hot-updater/plugin-core";
7
+ import { createStoragePlugin } from "@hot-updater/plugin-core";
8
+
9
+ import { createInMemoryDatabasePlugin } from "../../test-utils/test/inMemoryDatabasePlugin";
10
+ import type { DatabaseAdapterCapabilities, Migrator } from "./db/types";
11
+
12
+ export const runtimeBundle: Bundle = {
13
+ id: "00000000-0000-0000-0000-000000000001",
14
+ platform: "ios",
15
+ fileHash: "hash123",
16
+ gitCommitHash: null,
17
+ storageUri: "s3://test-bucket/bundles/bundle.zip",
18
+ archiveByteSize: 3_000_000_001,
19
+ };
20
+
21
+ export const createRuntimeStorage = (
22
+ get: NonNullable<StoragePlugin["get"]> = async () => ({ response: null }),
23
+ getDownloadUrl?: StoragePlugin["getDownloadUrl"],
24
+ ): StoragePluginWith<"get"> =>
25
+ createStoragePlugin({
26
+ name: "testStorage",
27
+ protocol: "s3",
28
+ get,
29
+ ...(getDownloadUrl ? { getDownloadUrl } : {}),
30
+ });
31
+
32
+ const createMigrator = (version: string | undefined): Migrator => ({
33
+ async getVersion() {
34
+ return version;
35
+ },
36
+ async getNameVariants() {
37
+ return {};
38
+ },
39
+ async next() {
40
+ return undefined;
41
+ },
42
+ async previous() {
43
+ return undefined;
44
+ },
45
+ async up() {
46
+ throw new Error("not implemented");
47
+ },
48
+ async down() {
49
+ throw new Error("not implemented");
50
+ },
51
+ async migrateTo() {
52
+ throw new Error("not implemented");
53
+ },
54
+ async migrateToLatest() {
55
+ throw new Error("not implemented");
56
+ },
57
+ });
58
+
59
+ export const createRuntimeDatabase = (): DatabasePlugin => ({
60
+ ...createInMemoryDatabasePlugin(),
61
+ name: "testDatabase",
62
+ });
63
+
64
+ export const createSchemaManagedDatabase = (
65
+ adapterName: string,
66
+ version: string | undefined,
67
+ ): DatabasePlugin & DatabaseAdapterCapabilities => ({
68
+ ...createRuntimeDatabase(),
69
+ adapterName,
70
+ createMigrator: () => createMigrator(version),
71
+ });
@@ -1,26 +1,35 @@
1
1
  import { describe, expect, it } from "vitest";
2
2
 
3
+ import { hotUpdaterSchemaVersions } from "./index";
3
4
  import { createSettingsTable } from "./settings";
4
- import { bundlesV021, v0_21_0 } from "./v0_21_0";
5
- import { bundlesV029, v0_29_0 } from "./v0_29_0";
6
- import { bundlesV031, v0_31_0 } from "./v0_31_0";
5
+ import {
6
+ bundlePatchesV100,
7
+ bundlesV100,
8
+ channelsV100,
9
+ releaseCatalogsV100,
10
+ releasesV100,
11
+ v1_0_0,
12
+ } from "./v1_0_0";
7
13
 
8
14
  describe("versioned schema DSL", () => {
9
- it("uses the local functional DSL for every versioned schema table", () => {
10
- expect(v0_21_0.dsl).toBe("schema");
11
- expect(v0_29_0.dsl).toBe("schema");
12
- expect(v0_31_0.dsl).toBe("schema");
15
+ it("uses the local functional DSL for the current schema", () => {
16
+ expect(v1_0_0.dsl).toBe("schema");
17
+ expect(channelsV100.dsl).toBe("table");
18
+ expect(bundlesV100.dsl).toBe("table");
19
+ expect(bundlePatchesV100.dsl).toBe("table");
20
+ expect(releasesV100.dsl).toBe("table");
21
+ expect(releaseCatalogsV100.dsl).toBe("table");
22
+ expect(createSettingsTable("1.0.0").dsl).toBe("table");
13
23
 
14
- expect(bundlesV021.dsl).toBe("table");
15
- expect(bundlesV029.dsl).toBe("table");
16
- expect(bundlesV031.dsl).toBe("table");
17
- expect(createSettingsTable("0.31.0").dsl).toBe("table");
18
-
19
- for (const schema of [v0_21_0, v0_29_0, v0_31_0]) {
20
- expect(Object.keys(schema)).not.toContain("dsl");
21
- for (const table of schema.tables) {
22
- expect(Object.keys(table)).not.toContain("dsl");
23
- }
24
+ expect(Object.keys(v1_0_0)).not.toContain("dsl");
25
+ for (const table of v1_0_0.tables) {
26
+ expect(Object.keys(table)).not.toContain("dsl");
24
27
  }
25
28
  });
29
+
30
+ it("registers only schema 1.0.0", () => {
31
+ expect(hotUpdaterSchemaVersions.map((item) => item.version)).toEqual([
32
+ "1.0.0",
33
+ ]);
34
+ });
26
35
  });
package/src/schema/dsl.ts CHANGED
@@ -10,7 +10,12 @@ import type {
10
10
  HotUpdaterVersionedSchema,
11
11
  } from "./types";
12
12
 
13
- type DefaultValue = boolean | number | string | Record<string, unknown>;
13
+ type DefaultValue =
14
+ | boolean
15
+ | number
16
+ | string
17
+ | Record<string, unknown>
18
+ | readonly unknown[];
14
19
 
15
20
  export type HotUpdaterColumnDsl = {
16
21
  readonly dsl: "column";
@@ -19,8 +24,14 @@ export type HotUpdaterColumnDsl = {
19
24
  readonly default?: HotUpdaterDefault;
20
25
  readonly nullableValue?: true;
21
26
  readonly primaryKeyValue?: true;
27
+ readonly providerCollations?: HotUpdaterColumnSchema["providerCollations"];
22
28
  readonly nullable: () => HotUpdaterColumnDsl;
23
29
  readonly primaryKey: () => HotUpdaterColumnDsl;
30
+ readonly collate: (
31
+ providerCollations: NonNullable<
32
+ HotUpdaterColumnSchema["providerCollations"]
33
+ >,
34
+ ) => HotUpdaterColumnDsl;
24
35
  readonly defaultTo: (value: DefaultValue) => HotUpdaterColumnDsl;
25
36
  };
26
37
 
@@ -45,6 +56,9 @@ const defaultValue = (value: DefaultValue): HotUpdaterDefault =>
45
56
  const columnSchema = (column: HotUpdaterColumnDsl): HotUpdaterColumnSchema => ({
46
57
  ormName: column.ormName,
47
58
  type: column.type,
59
+ ...(column.providerCollations
60
+ ? { providerCollations: column.providerCollations }
61
+ : {}),
48
62
  ...(column.nullableValue ? { nullable: true } : {}),
49
63
  ...(column.primaryKeyValue ? { primaryKey: true } : {}),
50
64
  ...(column.default ? { default: column.default } : {}),
@@ -59,11 +73,16 @@ const createColumn = (state: ColumnState): HotUpdaterColumnDsl => ({
59
73
  dsl: "column",
60
74
  ormName: state.ormName,
61
75
  type: state.type,
76
+ ...(state.providerCollations
77
+ ? { providerCollations: state.providerCollations }
78
+ : {}),
62
79
  ...(state.nullableValue ? { nullableValue: true } : {}),
63
80
  ...(state.primaryKeyValue ? { primaryKeyValue: true } : {}),
64
81
  ...(state.default ? { default: state.default } : {}),
65
82
  nullable: () => createColumn({ ...state, nullableValue: true }),
66
83
  primaryKey: () => createColumn({ ...state, primaryKeyValue: true }),
84
+ collate: (providerCollations) =>
85
+ createColumn({ ...state, providerCollations }),
67
86
  defaultTo: (value) =>
68
87
  createColumn({ ...state, default: defaultValue(value) }),
69
88
  });
@@ -88,6 +107,9 @@ export const uuid = (ormName: string): HotUpdaterColumnDsl =>
88
107
  export const integer = (ormName: string): HotUpdaterColumnDsl =>
89
108
  column(ormName, "integer");
90
109
 
110
+ export const float = (ormName: string): HotUpdaterColumnDsl =>
111
+ column(ormName, "float");
112
+
91
113
  export const bool = (ormName: string): HotUpdaterColumnDsl =>
92
114
  column(ormName, "bool");
93
115
 
@@ -97,6 +119,9 @@ export const json = (ormName: string): HotUpdaterColumnDsl =>
97
119
  export const stringColumn = (ormName: string): HotUpdaterColumnDsl =>
98
120
  column(ormName, "string");
99
121
 
122
+ export const largeString = (ormName: string): HotUpdaterColumnDsl =>
123
+ column(ormName, "large-string");
124
+
100
125
  export const index = (
101
126
  name: string,
102
127
  columns: readonly string[],
@@ -107,18 +132,32 @@ export const index = (
107
132
  ...(providers ? { providers } : {}),
108
133
  });
109
134
 
135
+ export const uniqueIndex = (
136
+ name: string,
137
+ columns: readonly string[],
138
+ providers?: HotUpdaterIndexSchema["providers"],
139
+ ): HotUpdaterIndexSchema => ({
140
+ name,
141
+ columns,
142
+ ...(providers ? { providers } : {}),
143
+ unique: true,
144
+ });
145
+
110
146
  export const foreignKey = (
111
147
  name: string,
112
148
  columns: readonly string[],
113
149
  referencedTable: string,
114
150
  referencedColumns: readonly string[],
151
+ options: {
152
+ readonly onDelete?: HotUpdaterForeignKeySchema["onDelete"];
153
+ } = {},
115
154
  ): HotUpdaterForeignKeySchema => ({
116
155
  name,
117
156
  columns,
118
157
  referencedTable,
119
158
  referencedColumns,
120
159
  onUpdate: "restrict",
121
- onDelete: "cascade",
160
+ onDelete: options.onDelete ?? "cascade",
122
161
  });
123
162
 
124
163
  export const check = (config: HotUpdaterCheckSchema): HotUpdaterCheckSchema =>
@@ -1,16 +1,10 @@
1
1
  import type { HotUpdaterVersionedSchema } from "./types";
2
- import { v0_21_0 } from "./v0_21_0";
3
- import { v0_29_0 } from "./v0_29_0";
4
- import { v0_31_0 } from "./v0_31_0";
2
+ import { v1_0_0 } from "./v1_0_0";
5
3
 
6
4
  export * from "./settings";
7
5
  export * from "./types";
8
- export * from "./v0_21_0";
9
- export * from "./v0_29_0";
10
- export * from "./v0_31_0";
6
+ export * from "./v1_0_0";
11
7
 
12
8
  export const hotUpdaterSchemaVersions: readonly HotUpdaterVersionedSchema[] = [
13
- v0_21_0,
14
- v0_29_0,
15
- v0_31_0,
9
+ v1_0_0,
16
10
  ];
@@ -1,12 +1,15 @@
1
1
  import type { ORMProvider } from "../db/types";
2
2
 
3
- export const HOT_UPDATER_SCHEMA_VERSION = "0.31.0";
3
+ export const HOT_UPDATER_SCHEMA_VERSION = "1.0.0";
4
+ export const HOT_UPDATER_CORE_SCHEMA_KEY = "schema.core";
4
5
  export const HOT_UPDATER_SETTINGS_TABLE = "private_hot_updater_settings";
5
6
 
6
7
  export type HotUpdaterColumnType =
7
8
  | "bool"
9
+ | "float"
8
10
  | "integer"
9
11
  | "json"
12
+ | "large-string"
10
13
  | "string"
11
14
  | "uuid"
12
15
  | `varchar(${number})`;
@@ -18,6 +21,7 @@ export type HotUpdaterDefault =
18
21
  export interface HotUpdaterColumnSchema {
19
22
  readonly ormName: string;
20
23
  readonly type: HotUpdaterColumnType;
24
+ readonly providerCollations?: Partial<Record<ORMProvider, string>>;
21
25
  readonly nullable?: boolean;
22
26
  readonly primaryKey?: boolean;
23
27
  readonly default?: HotUpdaterDefault;
@@ -27,11 +31,13 @@ export interface HotUpdaterIndexSchema {
27
31
  readonly name: string;
28
32
  readonly columns: readonly string[];
29
33
  readonly providers?: readonly ORMProvider[];
34
+ readonly unique?: true;
30
35
  }
31
36
 
32
37
  export interface HotUpdaterCheckSchema {
33
38
  readonly name: string;
34
39
  readonly expression: string;
40
+ readonly providerExpressions?: Partial<Record<ORMProvider, string>>;
35
41
  readonly sqliteInline?: boolean;
36
42
  }
37
43
 
@@ -41,7 +47,7 @@ export interface HotUpdaterForeignKeySchema {
41
47
  readonly referencedTable: string;
42
48
  readonly referencedColumns: readonly string[];
43
49
  readonly onUpdate: "restrict";
44
- readonly onDelete: "cascade";
50
+ readonly onDelete: "cascade" | "restrict" | "set null";
45
51
  }
46
52
 
47
53
  export interface HotUpdaterRelationSchema {
@@ -70,4 +76,4 @@ export interface HotUpdaterVersionedSchema {
70
76
  readonly tables: readonly HotUpdaterTableSchema[];
71
77
  }
72
78
 
73
- export type HotUpdaterSchemaVersion = "0.21.0" | "0.29.0" | "0.31.0";
79
+ export type HotUpdaterSchemaVersion = "1.0.0";
@@ -0,0 +1,146 @@
1
+ import { describe, expect, it } from "vitest";
2
+
3
+ import { createTableSql } from "../db/schema/sql";
4
+ import {
5
+ generateDrizzleSchema,
6
+ generatePrismaSchema,
7
+ } from "../db/schemaGenerators";
8
+ import {
9
+ bundleEventsV100,
10
+ bundlePatchesV100,
11
+ bundlesV100,
12
+ releaseCatalogsV100,
13
+ releasesV100,
14
+ v1_0_0,
15
+ } from "./v1_0_0";
16
+
17
+ describe("v1.0.0 Release Catalog schema", () => {
18
+ it("adds the canonical Release and catalog access paths", () => {
19
+ expect(v1_0_0.tables.map(({ ormName }) => ormName)).toContain("releases");
20
+ expect(v1_0_0.tables.map(({ ormName }) => ormName)).toContain(
21
+ "release_catalogs",
22
+ );
23
+ expect(releasesV100.indexes).toContainEqual({
24
+ columns: ["scope_key", "id"],
25
+ name: "releases_scope_order_idx",
26
+ });
27
+ expect(
28
+ releaseCatalogsV100.columns.find(({ ormName }) => ormName === "scope_key")
29
+ ?.primaryKey,
30
+ ).toBe(true);
31
+ });
32
+
33
+ it("keeps only immutable artifact fields on Bundle rows", () => {
34
+ const fields = bundlesV100.columns.map(({ ormName }) => ormName);
35
+
36
+ expect(fields).toEqual([
37
+ "id",
38
+ "platform",
39
+ "file_hash",
40
+ "git_commit_hash",
41
+ "storage_uri",
42
+ "archive_byte_size",
43
+ "metadata",
44
+ "manifest_storage_uri",
45
+ "manifest_file_hash",
46
+ "asset_base_storage_uri",
47
+ ]);
48
+ expect(fields).not.toContain("channel_id");
49
+ expect(fields).not.toContain("enabled");
50
+ expect(fields).not.toContain("target_app_version");
51
+ });
52
+
53
+ it("stores required archive and patch sizes as bounded floating columns", () => {
54
+ const archiveSize = bundlesV100.columns.find(
55
+ ({ ormName }) => ormName === "archive_byte_size",
56
+ );
57
+ const patchSize = bundlePatchesV100.columns.find(
58
+ ({ ormName }) => ormName === "byte_size",
59
+ );
60
+ const sql = createTableSql("postgresql").join("\n");
61
+ const prisma = generatePrismaSchema("postgresql", v1_0_0);
62
+ const drizzle = generateDrizzleSchema("postgresql", v1_0_0);
63
+
64
+ expect(archiveSize?.type).toBe("float");
65
+ expect(archiveSize?.nullable).toBeUndefined();
66
+ expect(patchSize?.type).toBe("float");
67
+ expect(patchSize?.nullable).toBeUndefined();
68
+ expect(sql).toContain("archive_byte_size double precision not null");
69
+ expect(sql).toContain("byte_size double precision not null");
70
+ expect(sql).toContain("archive_byte_size <= 9007199254740991");
71
+ expect(sql).toContain("byte_size <= 9007199254740991");
72
+ expect(prisma).toContain("archive_byte_size Float");
73
+ expect(prisma).toContain("byte_size Float");
74
+ expect(drizzle).toContain(
75
+ 'archive_byte_size: doublePrecision("archive_byte_size").notNull()',
76
+ );
77
+ expect(drizzle).toContain(
78
+ 'byte_size: doublePrecision("byte_size").notNull()',
79
+ );
80
+ });
81
+
82
+ it("keeps nullable sources while requiring the reported target Bundle", () => {
83
+ for (const field of [
84
+ "from_release_id",
85
+ "to_release_id",
86
+ "from_bundle_id",
87
+ ]) {
88
+ expect(
89
+ bundleEventsV100.columns.find(({ ormName }) => ormName === field)
90
+ ?.nullable,
91
+ ).toBe(true);
92
+ }
93
+ expect(
94
+ bundleEventsV100.columns.find(({ ormName }) => ormName === "to_bundle_id")
95
+ ?.nullable,
96
+ ).toBeUndefined();
97
+ });
98
+
99
+ it("generates nullable source and artifact relations with the intended deletion rules", () => {
100
+ const prisma = generatePrismaSchema("postgresql", v1_0_0);
101
+ const drizzle = generateDrizzleSchema("postgresql", v1_0_0);
102
+
103
+ expect(prisma).toContain("model releases {");
104
+ expect(prisma).toContain("sourceRelease releases? @relation(");
105
+ expect(prisma).toContain("onDelete: SetNull");
106
+ expect(prisma).toContain("bundle bundles? @relation(");
107
+ expect(drizzle).toContain("export const release_catalogs = pgTable(");
108
+ expect(drizzle).toContain('index("releases_scope_order_idx")');
109
+ expect(drizzle).toContain("foreignColumns: [table.id]");
110
+ expect(drizzle).not.toContain("foreignColumns: [releases.id]");
111
+ });
112
+
113
+ it("creates both projection tables and their constraints from empty", () => {
114
+ const sql = createTableSql("postgresql").join("\n");
115
+
116
+ expect(sql).toContain("create table releases");
117
+ expect(sql).toContain("create table release_catalogs");
118
+ expect(sql).toContain("releases_scope_order_idx");
119
+ expect(sql).toContain("release_catalogs_generation_check");
120
+ expect(sql).toContain("to_bundle_id uuid not null");
121
+ expect(sql).toContain("from_bundle_id is not null");
122
+ expect(sql).toContain("type = 'UNCHANGED' and from_bundle_id is null");
123
+ expect(sql).toContain("on delete set null");
124
+ });
125
+
126
+ it("uses byte-bounded MySQL catalog keys", () => {
127
+ const sql = createTableSql("mysql").join("\n");
128
+
129
+ expect(sql).toContain(
130
+ "scope_key varchar(2048) character set ascii collate ascii_bin",
131
+ );
132
+ expect(sql).toContain(
133
+ "channel_key varchar(1400) character set ascii collate ascii_bin",
134
+ );
135
+ expect(sql).toContain(
136
+ "create index releases_scope_order_idx on releases(scope_key, id)",
137
+ );
138
+ expect(sql).toContain("payload mediumtext not null");
139
+ expect(generatePrismaSchema("mysql", v1_0_0)).toContain(
140
+ "payload String @db.MediumText",
141
+ );
142
+ expect(generateDrizzleSchema("mysql", v1_0_0)).toContain(
143
+ 'payload: mediumtext("payload").notNull()',
144
+ );
145
+ });
146
+ });