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

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 (191) hide show
  1. package/dist/_virtual/_rolldown/runtime.cjs +1 -1
  2. package/dist/adapters/databaseConstraintErrors.cjs +0 -1
  3. package/dist/adapters/databasePluginUtils.cjs +0 -1
  4. package/dist/adapters/drizzle.cjs +10 -3
  5. package/dist/adapters/drizzle.d.cts +0 -1
  6. package/dist/adapters/drizzle.d.mts +0 -1
  7. package/dist/adapters/drizzle.mjs +11 -3
  8. package/dist/adapters/drizzleCrud.cjs +62 -1
  9. package/dist/adapters/drizzleCrud.mjs +61 -2
  10. package/dist/adapters/drizzleLazyDB.cjs +6 -1
  11. package/dist/adapters/drizzleLazyDB.mjs +6 -1
  12. package/dist/adapters/drizzleQuery.cjs +3 -2
  13. package/dist/adapters/drizzleQuery.mjs +3 -1
  14. package/dist/adapters/insightsTransaction.cjs +22 -0
  15. package/dist/adapters/insightsTransaction.mjs +22 -0
  16. package/dist/adapters/kysely.cjs +2 -1
  17. package/dist/adapters/kysely.d.cts +0 -1
  18. package/dist/adapters/kysely.d.mts +0 -1
  19. package/dist/adapters/kysely.mjs +3 -1
  20. package/dist/adapters/kyselyCrud.cjs +54 -3
  21. package/dist/adapters/kyselyCrud.mjs +54 -3
  22. package/dist/adapters/kyselyQuery.cjs +2 -2
  23. package/dist/adapters/kyselyQuery.mjs +2 -1
  24. package/dist/adapters/mongodb.cjs +27 -1
  25. package/dist/adapters/mongodb.d.cts +1 -1
  26. package/dist/adapters/mongodb.d.mts +1 -1
  27. package/dist/adapters/mongodb.mjs +28 -1
  28. package/dist/adapters/mongodbCollections.cjs +2 -0
  29. package/dist/adapters/mongodbCollections.mjs +2 -0
  30. package/dist/adapters/mongodbQuery.cjs +21 -4
  31. package/dist/adapters/mongodbQuery.mjs +21 -5
  32. package/dist/adapters/mongodbReads.cjs +91 -29
  33. package/dist/adapters/mongodbReads.mjs +92 -29
  34. package/dist/adapters/mongodbWrites.cjs +16 -2
  35. package/dist/adapters/mongodbWrites.mjs +18 -3
  36. package/dist/adapters/prisma.cjs +55 -7
  37. package/dist/adapters/prisma.d.cts +0 -1
  38. package/dist/adapters/prisma.d.mts +0 -1
  39. package/dist/adapters/prisma.mjs +56 -7
  40. package/dist/adapters/prismaQuery.cjs +0 -1
  41. package/dist/adapters/prismaRows.cjs +22 -1
  42. package/dist/adapters/prismaRows.mjs +22 -1
  43. package/dist/apiKeys.cjs +6 -2
  44. package/dist/apiKeys.d.cts +0 -1
  45. package/dist/apiKeys.d.mts +0 -1
  46. package/dist/apiKeys.mjs +3 -3
  47. package/dist/createHotUpdaterCore.cjs +24 -9
  48. package/dist/createHotUpdaterCore.d.cts +1 -1
  49. package/dist/createHotUpdaterCore.d.mts +1 -1
  50. package/dist/createHotUpdaterCore.mjs +23 -9
  51. package/dist/db/createBundleDiff.cjs +2 -2
  52. package/dist/db/createBundleDiff.d.cts +1 -5
  53. package/dist/db/createBundleDiff.d.mts +1 -5
  54. package/dist/db/databasePluginCore.cjs +0 -1
  55. package/dist/db/fixedMigrator.cjs +2 -2
  56. package/dist/db/fixedMigrator.mjs +2 -2
  57. package/dist/db/fixedMigratorMongo.cjs +6 -4
  58. package/dist/db/fixedMigratorMongo.mjs +6 -4
  59. package/dist/db/index.d.cts +0 -1
  60. package/dist/db/index.d.mts +0 -1
  61. package/dist/db/releaseCatalog.cjs +0 -1
  62. package/dist/db/releaseCatalog.d.cts +0 -1
  63. package/dist/db/releaseCatalog.d.mts +0 -1
  64. package/dist/db/schema/insightsCollation.cjs +14 -0
  65. package/dist/db/schema/insightsCollation.mjs +14 -0
  66. package/dist/db/schema/sql.cjs +11 -7
  67. package/dist/db/schema/sql.mjs +8 -8
  68. package/dist/db/schemaGenerators.cjs +28 -9
  69. package/dist/db/schemaGenerators.mjs +28 -9
  70. package/dist/db/schemaReadiness.cjs +2 -0
  71. package/dist/db/schemaReadiness.d.cts +1 -0
  72. package/dist/db/schemaReadiness.d.mts +1 -0
  73. package/dist/db/schemaReadiness.mjs +2 -0
  74. package/dist/db/sqlMigrationExecution.cjs +1 -1
  75. package/dist/db/sqlMigrationExecution.mjs +1 -0
  76. package/dist/db/types.cjs +3 -1
  77. package/dist/db/types.d.cts +3 -6
  78. package/dist/db/types.d.mts +3 -6
  79. package/dist/db/types.mjs +2 -2
  80. package/dist/db/updateArtifacts.cjs +0 -1
  81. package/dist/handler.d.cts +1 -2
  82. package/dist/handler.d.mts +1 -2
  83. package/dist/handlerReleaseCatalogRoutes.cjs +0 -1
  84. package/dist/handlerReleaseManagementRoutes.cjs +0 -1
  85. package/dist/handlerTypes.d.cts +0 -1
  86. package/dist/handlerTypes.d.mts +0 -1
  87. package/dist/handlerVersionRoutes.d.cts +1 -0
  88. package/dist/handlerVersionRoutes.d.mts +1 -0
  89. package/dist/index.cjs +1 -1
  90. package/dist/index.d.cts +4 -4
  91. package/dist/index.d.mts +4 -4
  92. package/dist/index.mjs +1 -1
  93. package/dist/insights/domain.d.cts +37 -69
  94. package/dist/insights/domain.d.mts +37 -69
  95. package/dist/insights/errors.cjs +1 -8
  96. package/dist/insights/errors.mjs +2 -8
  97. package/dist/insights/eventInput.cjs +49 -5
  98. package/dist/insights/eventInput.mjs +48 -6
  99. package/dist/insights/provider.cjs +314 -0
  100. package/dist/insights/provider.d.cts +6 -0
  101. package/dist/insights/provider.d.mts +6 -0
  102. package/dist/insights/provider.mjs +314 -0
  103. package/dist/insights/queryInput.cjs +78 -43
  104. package/dist/insights/queryInput.mjs +76 -40
  105. package/dist/insights/routes.cjs +20 -25
  106. package/dist/insights/routes.mjs +22 -27
  107. package/dist/insights/types.d.cts +27 -12
  108. package/dist/insights/types.d.mts +27 -12
  109. package/dist/node.d.cts +0 -1
  110. package/dist/node.d.mts +0 -1
  111. package/dist/package.cjs +1 -1
  112. package/dist/package.mjs +1 -1
  113. package/dist/schema/index.cjs +17 -3
  114. package/dist/schema/index.mjs +4 -4
  115. package/dist/schema/v1_0_0.cjs +72 -30
  116. package/dist/schema/v1_0_0.mjs +72 -31
  117. package/dist/storageAccess.cjs +0 -1
  118. package/dist/types/index.d.cts +0 -1
  119. package/dist/types/index.d.mts +0 -1
  120. package/package.json +7 -7
  121. package/src/adapters/databasePluginTestDatabase.ts +14 -0
  122. package/src/adapters/drizzle.spec.ts +99 -0
  123. package/src/adapters/drizzle.ts +21 -3
  124. package/src/adapters/drizzleCrud.ts +154 -2
  125. package/src/adapters/drizzleLazyDB.ts +17 -3
  126. package/src/adapters/insightsTransaction.ts +32 -0
  127. package/src/adapters/kysely.spec.ts +29 -0
  128. package/src/adapters/kysely.ts +10 -1
  129. package/src/adapters/kyselyCrud.ts +121 -0
  130. package/src/adapters/mongodb.integration.spec.ts +210 -0
  131. package/src/adapters/mongodb.spec.ts +69 -1
  132. package/src/adapters/mongodb.ts +66 -2
  133. package/src/adapters/mongodbCollections.ts +5 -0
  134. package/src/adapters/mongodbQuery.ts +32 -3
  135. package/src/adapters/mongodbReads.ts +69 -0
  136. package/src/adapters/mongodbTestClient.ts +41 -6
  137. package/src/adapters/mongodbTestFilter.ts +4 -1
  138. package/src/adapters/mongodbWrites.ts +27 -0
  139. package/src/adapters/prisma.spec.ts +97 -0
  140. package/src/adapters/prisma.ts +103 -3
  141. package/src/adapters/prismaRows.ts +37 -1
  142. package/src/adapters/prismaTestClient.ts +22 -5
  143. package/src/apiKeys.integration.spec.ts +1 -1
  144. package/src/createHotUpdaterCore.ts +21 -7
  145. package/src/db/databasePluginUpdateCheck.bench.ts +3 -0
  146. package/src/db/fixedMigrator.spec.ts +65 -0
  147. package/src/db/fixedMigratorMongo.spec.ts +56 -9
  148. package/src/db/fixedMigratorMongo.ts +10 -10
  149. package/src/db/index.spec.ts +8 -1
  150. package/src/db/schema/insightsCollation.ts +21 -0
  151. package/src/db/schema/sql.ts +8 -5
  152. package/src/db/schemaGenerators.ts +41 -13
  153. package/src/db/types.spec.ts +8 -0
  154. package/src/db/types.ts +10 -4
  155. package/src/handler-standalone.integration.spec.ts +5 -7
  156. package/src/index.ts +2 -2
  157. package/src/insights/domain.ts +39 -75
  158. package/src/insights/errors.ts +0 -7
  159. package/src/insights/eventInput.ts +60 -3
  160. package/src/insights/insights.integration.spec.ts +254 -17
  161. package/src/insights/provider.spec.ts +385 -0
  162. package/src/insights/provider.ts +591 -0
  163. package/src/insights/queryInput.ts +112 -73
  164. package/src/insights/routes.ts +37 -56
  165. package/src/insights/types.ts +47 -36
  166. package/src/schema/dsl-all-versions.spec.ts +3 -1
  167. package/src/schema/v1_0_0.spec.ts +77 -3
  168. package/src/schema/v1_0_0.ts +94 -30
  169. package/dist/insights/bounded/activeOverview.cjs +0 -87
  170. package/dist/insights/bounded/activeOverview.mjs +0 -85
  171. package/dist/insights/bounded/installationSearch.cjs +0 -42
  172. package/dist/insights/bounded/installationSearch.mjs +0 -42
  173. package/dist/insights/bounded/persistence.cjs +0 -39
  174. package/dist/insights/bounded/persistence.mjs +0 -38
  175. package/dist/insights/bounded/provider.cjs +0 -170
  176. package/dist/insights/bounded/provider.d.cts +0 -7
  177. package/dist/insights/bounded/provider.d.mts +0 -7
  178. package/dist/insights/bounded/provider.mjs +0 -170
  179. package/dist/insights/bounded/scan.cjs +0 -144
  180. package/dist/insights/bounded/scan.mjs +0 -138
  181. package/dist/insights/persistence.d.cts +0 -6
  182. package/dist/insights/persistence.d.mts +0 -6
  183. package/src/insights/bounded/activeOverview.spec.ts +0 -189
  184. package/src/insights/bounded/activeOverview.ts +0 -148
  185. package/src/insights/bounded/installationSearch.spec.ts +0 -130
  186. package/src/insights/bounded/installationSearch.ts +0 -69
  187. package/src/insights/bounded/persistence.ts +0 -43
  188. package/src/insights/bounded/provider.spec.ts +0 -219
  189. package/src/insights/bounded/provider.ts +0 -229
  190. package/src/insights/bounded/scan.ts +0 -235
  191. package/src/insights/persistence.ts +0 -10
@@ -3,19 +3,19 @@ import { generatePrismaSchema } from "../db/schemaGenerators.mjs";
3
3
  import { isChannelDeleteReferencedError, translateChannelDeleteError } from "./databaseConstraintErrors.mjs";
4
4
  import { hasNullOrderOverrides, sortRowsByOrder } from "./databasePluginUtils.mjs";
5
5
  import { createPrismaOrderBy, createPrismaWhere } from "./prismaQuery.mjs";
6
- import { PrismaAdapterError, getPrismaDelegate, parsePrismaApiKeyRow, parsePrismaBundleEventRow, parsePrismaBundleRow, parsePrismaChannelRow, parsePrismaPatchRow, parsePrismaReleaseCatalogRow, parsePrismaReleaseRow, parsePrismaRows } from "./prismaRows.mjs";
6
+ import { PrismaAdapterError, getPrismaDelegate, parsePrismaApiKeyRow, parsePrismaBundleEventRow, parsePrismaBundleRow, parsePrismaChannelRow, parsePrismaInsightsInstallationRow, parsePrismaPatchRow, parsePrismaReleaseCatalogRow, parsePrismaReleaseRow, parsePrismaRows } from "./prismaRows.mjs";
7
7
  import { DatabasePluginInputError, createDatabasePlugin } from "@hot-updater/plugin-core";
8
8
  import { createDatabasePluginAdapter } from "@hot-updater/plugin-core/internal";
9
9
  //#region src/adapters/prisma.ts
10
10
  const hasCallbackTransaction = (client) => "$transaction" in client && typeof client.$transaction === "function";
11
- const runPrismaTransaction = (client, isolationLevel, callback) => {
11
+ const runPrismaTransaction = (client, isolationLevel, callback, retryUniqueConflict = false) => {
12
12
  const execute = () => isolationLevel === "serializable" ? client.$transaction(callback, { isolationLevel: "Serializable" }) : client.$transaction(callback);
13
13
  if (isolationLevel === "default") return execute();
14
14
  return (async () => {
15
15
  for (let attempt = 0;; attempt += 1) try {
16
16
  return await execute();
17
17
  } catch (error) {
18
- if (attempt >= 2 || typeof error !== "object" || error === null || !("code" in error) || error.code !== "P2034") throw error;
18
+ if (attempt >= 2 || typeof error !== "object" || error === null || !("code" in error) || error.code !== "P2034" && !(retryUniqueConflict && error.code === "P2002")) throw error;
19
19
  }
20
20
  })();
21
21
  };
@@ -36,6 +36,7 @@ const findMany = async (client, input, provider) => {
36
36
  case "bundles": return parsePrismaRows(rows, parsePrismaBundleRow);
37
37
  case "bundle_patches": return parsePrismaRows(rows, parsePrismaPatchRow);
38
38
  case "bundle_events": return parsePrismaRows(rows, parsePrismaBundleEventRow);
39
+ case "bundle_installations": return parsePrismaRows(rows, parsePrismaInsightsInstallationRow);
39
40
  case "channels": return parsePrismaRows(rows, parsePrismaChannelRow);
40
41
  case "api_keys": return parsePrismaRows(rows, parsePrismaApiKeyRow);
41
42
  case "releases": return parsePrismaRows(rows, parsePrismaReleaseRow);
@@ -43,7 +44,7 @@ const findMany = async (client, input, provider) => {
43
44
  }
44
45
  };
45
46
  const assertPatchReferences = async (client, bundleId, baseBundleId) => {
46
- const ids = Array.from(new Set([bundleId, baseBundleId]));
47
+ const ids = Array.from(/* @__PURE__ */ new Set([bundleId, baseBundleId]));
47
48
  if (await getPrismaDelegate(client, "bundles").count({ where: { id: { in: ids } } }) !== ids.length) throw new PrismaAdapterError("patch references a missing bundle");
48
49
  };
49
50
  const createCrudImplementation = (client, provider, relationMode) => ({
@@ -90,7 +91,7 @@ const createCrudImplementation = (client, provider, relationMode) => ({
90
91
  const delegate = getPrismaDelegate(client, input.model);
91
92
  let row;
92
93
  if (input.onConflict === "ignore") {
93
- const where = input.model === "channels" ? { name: input.data.name } : { hash: input.data.hash };
94
+ const where = input.model === "channels" ? { name: input.data.name } : input.model === "api_keys" ? { hash: input.data.hash } : { install_id: input.data.install_id };
94
95
  row = await delegate.upsert({
95
96
  where,
96
97
  create: input.data,
@@ -101,6 +102,7 @@ const createCrudImplementation = (client, provider, relationMode) => ({
101
102
  case "bundles": return parsePrismaBundleRow(row);
102
103
  case "bundle_patches": return parsePrismaPatchRow(row);
103
104
  case "bundle_events": return parsePrismaBundleEventRow(row);
105
+ case "bundle_installations": return parsePrismaInsightsInstallationRow(row);
104
106
  case "channels": return parsePrismaChannelRow(row);
105
107
  case "api_keys": return parsePrismaApiKeyRow(row);
106
108
  case "releases": return parsePrismaReleaseRow(row);
@@ -108,6 +110,18 @@ const createCrudImplementation = (client, provider, relationMode) => ({
108
110
  }
109
111
  },
110
112
  update: async (input) => {
113
+ if (input.model === "bundle_installations") {
114
+ const installId = input.where.find((item) => item.field === "install_id" && (item.operator === void 0 || item.operator === "eq") && typeof item.value === "string")?.value;
115
+ if (typeof installId !== "string") throw new PrismaAdapterError("bundle_installations update requires install_id");
116
+ const delegate = getPrismaDelegate(client, "bundle_installations");
117
+ if (delegate.updateMany === void 0) throw new PrismaAdapterError("model delegate \"bundle_installations\" requires updateMany");
118
+ if ((await delegate.updateMany({
119
+ where: createPrismaWhere(input.where, provider),
120
+ data: input.update
121
+ })).count === 0) return null;
122
+ const stored = await delegate.findFirst({ where: { install_id: installId } });
123
+ return stored === null ? null : parsePrismaInsightsInstallationRow(stored);
124
+ }
111
125
  const id = input.where[0]?.value;
112
126
  if (typeof id !== "string") throw new PrismaAdapterError(`${input.model} update requires a string id`);
113
127
  if (input.model === "api_keys") {
@@ -153,7 +167,8 @@ const createCrudImplementation = (client, provider, relationMode) => ({
153
167
  },
154
168
  delete: async (input) => {
155
169
  if (input.model === "bundles" && relationMode === "prisma") {
156
- const ids = parsePrismaRows(await getPrismaDelegate(client, "bundles").findMany({ where: createPrismaWhere(input.where, provider) }), parsePrismaBundleRow).map(({ id }) => id);
170
+ const rows = await getPrismaDelegate(client, "bundles").findMany({ where: createPrismaWhere(input.where, provider) });
171
+ const ids = parsePrismaRows(rows, parsePrismaBundleRow).map(({ id }) => id);
157
172
  if (ids.length === 0) return;
158
173
  await getPrismaDelegate(client, "bundle_patches").deleteMany({ where: { OR: [{ bundle_id: { in: ids } }, { base_bundle_id: { in: ids } }] } });
159
174
  }
@@ -178,6 +193,7 @@ const createCrudImplementation = (client, provider, relationMode) => ({
178
193
  case "api_keys": return parsePrismaApiKeyRow(row);
179
194
  case "releases": return parsePrismaReleaseRow(row);
180
195
  case "release_catalogs": return parsePrismaReleaseCatalogRow(row);
196
+ case "bundle_installations": return parsePrismaInsightsInstallationRow(row);
181
197
  }
182
198
  },
183
199
  findMany: (input) => findMany(client, input, provider)
@@ -186,6 +202,26 @@ const createPrismaImplementation = (client, relationMode, provider) => {
186
202
  const crud = createCrudImplementation(client, provider, relationMode);
187
203
  const implementation = {
188
204
  ...crud,
205
+ recordInsights: (input) => {
206
+ if (!hasCallbackTransaction(client)) throw new PrismaAdapterError("Insights recording requires callback transactions");
207
+ return runPrismaTransaction(client, "serializable", async (transactionClient) => {
208
+ const events = getPrismaDelegate(transactionClient, "bundle_events");
209
+ if (await events.findFirst({ where: { id: input.event.id } }) !== null) return;
210
+ await events.create({ data: input.event });
211
+ const installations = getPrismaDelegate(transactionClient, "bundle_installations");
212
+ const existing = await installations.findFirst({ where: { install_id: input.installation.install_id } });
213
+ if (existing === null) {
214
+ await installations.create({ data: input.installation });
215
+ return;
216
+ }
217
+ const current = parsePrismaInsightsInstallationRow(existing);
218
+ if (current.received_at_ms > input.installation.received_at_ms || current.received_at_ms === input.installation.received_at_ms && current.id >= input.installation.id) return;
219
+ await installations.update({
220
+ where: { install_id: input.installation.install_id },
221
+ data: input.installation
222
+ });
223
+ }, true);
224
+ },
189
225
  deleteChannel: (input) => {
190
226
  if (!hasCallbackTransaction(client)) throw new PrismaAdapterError("channel deletion requires callback transactions");
191
227
  return runPrismaTransaction(client, "serializable", (transactionClient) => createCrudImplementation(transactionClient, provider, relationMode).deleteChannel(input));
@@ -210,9 +246,22 @@ const createPrismaImplementation = (client, relationMode, provider) => {
210
246
  const prismaAdapter = (config) => {
211
247
  assertPrismaProvider(config.provider);
212
248
  const adapter = createDatabasePluginAdapter("prisma", createPrismaImplementation(config.prisma, config.relationMode ?? "foreign-keys", config.provider));
249
+ const unsupportedMssqlInsights = async () => {
250
+ throw new PrismaAdapterError("SQL Server Insights is unsupported: string keys pad trailing spaces and do not provide the required exact UTF-8 identity ordering");
251
+ };
252
+ const insights = config.provider === "mssql" ? {
253
+ record: unsupportedMssqlInsights,
254
+ listEvents: unsupportedMssqlInsights,
255
+ findInstallations: unsupportedMssqlInsights,
256
+ countInstallations: unsupportedMssqlInsights,
257
+ countEvents: unsupportedMssqlInsights
258
+ } : adapter.models.insights;
213
259
  return Object.assign(createDatabasePlugin({
214
260
  name: "prisma",
215
- models: adapter.models,
261
+ models: {
262
+ ...adapter.models,
263
+ insights
264
+ },
216
265
  commit: adapter.commit
217
266
  }), {
218
267
  adapterName: "prisma",
@@ -1,4 +1,3 @@
1
- require("../_virtual/_rolldown/runtime.cjs");
2
1
  let _hot_updater_plugin_core = require("@hot-updater/plugin-core");
3
2
  //#region src/adapters/prismaQuery.ts
4
3
  const stringFilter = (operator, value, mode) => {
@@ -1,7 +1,7 @@
1
- require("../_virtual/_rolldown/runtime.cjs");
2
1
  let _hot_updater_plugin_core = require("@hot-updater/plugin-core");
3
2
  //#region src/adapters/prismaRows.ts
4
3
  var PrismaAdapterError = class extends Error {
4
+ reason;
5
5
  name = "PrismaAdapterError";
6
6
  constructor(reason) {
7
7
  super(`Invalid Prisma plugin state: ${reason}`);
@@ -14,6 +14,7 @@ const modelDelegates = {
14
14
  bundles: "bundles",
15
15
  bundle_patches: "bundle_patches",
16
16
  bundle_events: "bundle_events",
17
+ bundle_installations: "bundle_installations",
17
18
  channels: "channels",
18
19
  api_keys: "api_keys",
19
20
  releases: "releases",
@@ -114,6 +115,25 @@ const parsePrismaBundleEventRow = (value) => {
114
115
  received_at_ms: readNumber(value, "received_at_ms")
115
116
  };
116
117
  };
118
+ const parsePrismaInsightsInstallationRow = (value) => {
119
+ if (!isRecord(value)) throw new PrismaAdapterError("invalid installation row");
120
+ const platform = readString(value, "platform");
121
+ const type = readString(value, "type");
122
+ if (platform !== "ios" && platform !== "android" || type !== "UPDATE_APPLIED" && type !== "RECOVERED" && type !== "RELEASE_ADOPTED" && type !== "UNCHANGED") throw new PrismaAdapterError("invalid installation fields");
123
+ return {
124
+ install_id: readString(value, "install_id"),
125
+ id: readString(value, "id"),
126
+ user_id: readNullableString(value, "user_id"),
127
+ username: readNullableString(value, "username"),
128
+ to_bundle_id: readString(value, "to_bundle_id"),
129
+ type,
130
+ platform,
131
+ app_version: readString(value, "app_version"),
132
+ channel: readString(value, "channel"),
133
+ cohort: readString(value, "cohort"),
134
+ received_at_ms: readNumber(value, "received_at_ms")
135
+ };
136
+ };
117
137
  const parsePrismaApiKeyRow = (value) => {
118
138
  if (!isRecord(value)) throw new PrismaAdapterError("invalid API key row");
119
139
  const role = readString(value, "role");
@@ -192,6 +212,7 @@ exports.parsePrismaApiKeyRow = parsePrismaApiKeyRow;
192
212
  exports.parsePrismaBundleEventRow = parsePrismaBundleEventRow;
193
213
  exports.parsePrismaBundleRow = parsePrismaBundleRow;
194
214
  exports.parsePrismaChannelRow = parsePrismaChannelRow;
215
+ exports.parsePrismaInsightsInstallationRow = parsePrismaInsightsInstallationRow;
195
216
  exports.parsePrismaPatchRow = parsePrismaPatchRow;
196
217
  exports.parsePrismaReleaseCatalogRow = parsePrismaReleaseCatalogRow;
197
218
  exports.parsePrismaReleaseRow = parsePrismaReleaseRow;
@@ -1,6 +1,7 @@
1
1
  import { isDatabaseMetadataObject } from "@hot-updater/plugin-core";
2
2
  //#region src/adapters/prismaRows.ts
3
3
  var PrismaAdapterError = class extends Error {
4
+ reason;
4
5
  name = "PrismaAdapterError";
5
6
  constructor(reason) {
6
7
  super(`Invalid Prisma plugin state: ${reason}`);
@@ -13,6 +14,7 @@ const modelDelegates = {
13
14
  bundles: "bundles",
14
15
  bundle_patches: "bundle_patches",
15
16
  bundle_events: "bundle_events",
17
+ bundle_installations: "bundle_installations",
16
18
  channels: "channels",
17
19
  api_keys: "api_keys",
18
20
  releases: "releases",
@@ -113,6 +115,25 @@ const parsePrismaBundleEventRow = (value) => {
113
115
  received_at_ms: readNumber(value, "received_at_ms")
114
116
  };
115
117
  };
118
+ const parsePrismaInsightsInstallationRow = (value) => {
119
+ if (!isRecord(value)) throw new PrismaAdapterError("invalid installation row");
120
+ const platform = readString(value, "platform");
121
+ const type = readString(value, "type");
122
+ if (platform !== "ios" && platform !== "android" || type !== "UPDATE_APPLIED" && type !== "RECOVERED" && type !== "RELEASE_ADOPTED" && type !== "UNCHANGED") throw new PrismaAdapterError("invalid installation fields");
123
+ return {
124
+ install_id: readString(value, "install_id"),
125
+ id: readString(value, "id"),
126
+ user_id: readNullableString(value, "user_id"),
127
+ username: readNullableString(value, "username"),
128
+ to_bundle_id: readString(value, "to_bundle_id"),
129
+ type,
130
+ platform,
131
+ app_version: readString(value, "app_version"),
132
+ channel: readString(value, "channel"),
133
+ cohort: readString(value, "cohort"),
134
+ received_at_ms: readNumber(value, "received_at_ms")
135
+ };
136
+ };
116
137
  const parsePrismaApiKeyRow = (value) => {
117
138
  if (!isRecord(value)) throw new PrismaAdapterError("invalid API key row");
118
139
  const role = readString(value, "role");
@@ -185,4 +206,4 @@ const parsePrismaReleaseCatalogRow = (value) => {
185
206
  };
186
207
  const parsePrismaRows = (rows, parse) => rows.map(parse);
187
208
  //#endregion
188
- export { PrismaAdapterError, getPrismaDelegate, parsePrismaApiKeyRow, parsePrismaBundleEventRow, parsePrismaBundleRow, parsePrismaChannelRow, parsePrismaPatchRow, parsePrismaReleaseCatalogRow, parsePrismaReleaseRow, parsePrismaRows };
209
+ export { PrismaAdapterError, getPrismaDelegate, parsePrismaApiKeyRow, parsePrismaBundleEventRow, parsePrismaBundleRow, parsePrismaChannelRow, parsePrismaInsightsInstallationRow, parsePrismaPatchRow, parsePrismaReleaseCatalogRow, parsePrismaReleaseRow, parsePrismaRows };
package/dist/apiKeys.cjs CHANGED
@@ -33,7 +33,7 @@ const hashApiKey = async (apiKey) => {
33
33
  return bytesToBase64Url(new Uint8Array(digest));
34
34
  };
35
35
  const apiKeyId = () => {
36
- const bytes = new Uint8Array(16);
36
+ const bytes = /* @__PURE__ */ new Uint8Array(16);
37
37
  crypto.getRandomValues(bytes);
38
38
  return `api-${bytesToBase64Url(bytes)}`;
39
39
  };
@@ -70,7 +70,7 @@ const registerApiKey = async (input) => {
70
70
  });
71
71
  };
72
72
  const createApiKey = (input) => {
73
- const bytes = new Uint8Array(32);
73
+ const bytes = /* @__PURE__ */ new Uint8Array(32);
74
74
  crypto.getRandomValues(bytes);
75
75
  return registerApiKey({
76
76
  apiKey: bytesToBase64Url(bytes),
@@ -131,9 +131,13 @@ const createApiKeyManagement = (input) => Object.freeze({
131
131
  });
132
132
  //#endregion
133
133
  exports.API_KEY_HEADER_NAME = API_KEY_HEADER_NAME;
134
+ exports.apiKeyId = apiKeyId;
134
135
  exports.authenticateApiKey = authenticateApiKey;
135
136
  exports.createApiKey = createApiKey;
136
137
  exports.createApiKeyManagement = createApiKeyManagement;
138
+ exports.hashApiKey = hashApiKey;
139
+ exports.isApiKey = isApiKey;
137
140
  exports.normalizeApiKeyHeaderName = normalizeApiKeyHeaderName;
141
+ exports.normalizeApiKeyName = normalizeApiKeyName;
138
142
  exports.provisionApiKey = provisionApiKey;
139
143
  exports.registerApiKey = registerApiKey;
@@ -1,5 +1,4 @@
1
1
  import { ApiKeyModel, ApiKeyRow } from "@hot-updater/plugin-core";
2
-
3
2
  //#region src/apiKeys.d.ts
4
3
  declare const API_KEY_HEADER_NAME = "x-api-key";
5
4
  type ApiKeyMetadata = Omit<ApiKeyRow, "hash">;
@@ -1,5 +1,4 @@
1
1
  import { ApiKeyModel, ApiKeyRow } from "@hot-updater/plugin-core";
2
-
3
2
  //#region src/apiKeys.d.ts
4
3
  declare const API_KEY_HEADER_NAME = "x-api-key";
5
4
  type ApiKeyMetadata = Omit<ApiKeyRow, "hash">;
package/dist/apiKeys.mjs CHANGED
@@ -33,7 +33,7 @@ const hashApiKey = async (apiKey) => {
33
33
  return bytesToBase64Url(new Uint8Array(digest));
34
34
  };
35
35
  const apiKeyId = () => {
36
- const bytes = new Uint8Array(16);
36
+ const bytes = /* @__PURE__ */ new Uint8Array(16);
37
37
  crypto.getRandomValues(bytes);
38
38
  return `api-${bytesToBase64Url(bytes)}`;
39
39
  };
@@ -70,7 +70,7 @@ const registerApiKey = async (input) => {
70
70
  });
71
71
  };
72
72
  const createApiKey = (input) => {
73
- const bytes = new Uint8Array(32);
73
+ const bytes = /* @__PURE__ */ new Uint8Array(32);
74
74
  crypto.getRandomValues(bytes);
75
75
  return registerApiKey({
76
76
  apiKey: bytesToBase64Url(bytes),
@@ -130,4 +130,4 @@ const createApiKeyManagement = (input) => Object.freeze({
130
130
  }
131
131
  });
132
132
  //#endregion
133
- export { API_KEY_HEADER_NAME, authenticateApiKey, createApiKey, createApiKeyManagement, normalizeApiKeyHeaderName, provisionApiKey, registerApiKey };
133
+ export { API_KEY_HEADER_NAME, apiKeyId, authenticateApiKey, createApiKey, createApiKeyManagement, hashApiKey, isApiKey, normalizeApiKeyHeaderName, normalizeApiKeyName, provisionApiKey, registerApiKey };
@@ -1,6 +1,5 @@
1
- require("./_virtual/_rolldown/runtime.cjs");
2
1
  const require_handler = require("./handler.cjs");
3
- const require_provider = require("./insights/bounded/provider.cjs");
2
+ const require_provider = require("./insights/provider.cjs");
4
3
  const require_apiKeys = require("./apiKeys.cjs");
5
4
  const require_databasePluginCore = require("./db/databasePluginCore.cjs");
6
5
  const require_schemaReadiness = require("./db/schemaReadiness.cjs");
@@ -25,27 +24,41 @@ function getHotUpdaterCoreMetadata(hotUpdater) {
25
24
  function createHotUpdaterCore(options) {
26
25
  for (const key of ["authorityId", "catalogId"]) if (Object.hasOwn(options, key)) throw new TypeError(`Remove ${key} from createHotUpdater options. Catalog identity is managed internally.`);
27
26
  const database = options.database;
28
- const { downloadStorageObject, readStorageText, resolveFileUrl } = require_storageAccess.createStorageAccess((options.storage ?? []).map((storage) => {
27
+ const storagePlugins = (options.storage ?? []).map((storage) => {
29
28
  (0, _hot_updater_plugin_core.assertStorageOperations)(storage, ["get", "getDownloadUrl"]);
30
29
  return storage;
31
- }));
30
+ });
31
+ const { downloadStorageObject, readStorageText, resolveFileUrl } = require_storageAccess.createStorageAccess(storagePlugins);
32
32
  const adapterCapabilities = database;
33
33
  if (!require_types.isDatabasePlugin(database)) throw new Error("@hot-updater/server only supports database plugins.");
34
34
  const plugin = database;
35
- const assertSchemaReady = require_schemaReadiness.createSchemaReadinessChecker(adapterCapabilities.adapterName ?? plugin.name, adapterCapabilities.createMigrator);
35
+ const adapterName = adapterCapabilities.adapterName ?? plugin.name;
36
+ const assertSchemaReady = require_schemaReadiness.createSchemaReadinessChecker(adapterName, adapterCapabilities.createMigrator);
36
37
  const core = require_databasePluginCore.createDatabasePluginCore(plugin, resolveFileUrl, {
37
38
  beforeOperation: assertSchemaReady,
38
39
  readStorageText
39
40
  });
40
41
  const clientAccess = normalizeClientAccess(options.clientAccess);
41
42
  const insights = require_provider.createInsightsProvider({
42
- async append(row) {
43
+ async record(input) {
44
+ await assertSchemaReady();
45
+ return plugin.models.insights.record(input);
46
+ },
47
+ async listEvents(input) {
48
+ await assertSchemaReady();
49
+ return plugin.models.insights.listEvents(input);
50
+ },
51
+ async findInstallations(input) {
52
+ await assertSchemaReady();
53
+ return plugin.models.insights.findInstallations(input);
54
+ },
55
+ async countInstallations(input) {
43
56
  await assertSchemaReady();
44
- return plugin.models.insights.append(row);
57
+ return plugin.models.insights.countInstallations(input);
45
58
  },
46
- async scan(input) {
59
+ async countEvents(input) {
47
60
  await assertSchemaReady();
48
- return plugin.models.insights.scan(input);
61
+ return plugin.models.insights.countEvents(input);
49
62
  }
50
63
  });
51
64
  const apiKeys = require_apiKeys.createApiKeyManagement({
@@ -85,4 +98,6 @@ function createHotUpdater(options) {
85
98
  }
86
99
  //#endregion
87
100
  exports.createHotUpdater = createHotUpdater;
101
+ exports.createHotUpdaterCore = createHotUpdaterCore;
88
102
  exports.getHotUpdaterCoreMetadata = getHotUpdaterCoreMetadata;
103
+ exports.hotUpdaterCoreMetadata = hotUpdaterCoreMetadata;
@@ -1,9 +1,9 @@
1
1
  import { ApiKeyManagementAPI } from "./apiKeys.cjs";
2
2
  import { HotUpdaterHandlers } from "./handlerTypes.cjs";
3
3
  import { InsightsProvider } from "./insights/types.cjs";
4
+ import "./handler.cjs";
4
5
  import { DatabaseAPI, DatabasePlugin as DatabasePlugin$1 } from "./db/types.cjs";
5
6
  import { StoragePlugin } from "@hot-updater/plugin-core";
6
-
7
7
  //#region src/createHotUpdaterCore.d.ts
8
8
  type RuntimeHotUpdaterAPI = DatabaseAPI & {
9
9
  readonly handlers: HotUpdaterHandlers;
@@ -1,9 +1,9 @@
1
1
  import { ApiKeyManagementAPI } from "./apiKeys.mjs";
2
2
  import { HotUpdaterHandlers } from "./handlerTypes.mjs";
3
3
  import { InsightsProvider } from "./insights/types.mjs";
4
+ import "./handler.mjs";
4
5
  import { DatabaseAPI, DatabasePlugin as DatabasePlugin$1 } from "./db/types.mjs";
5
6
  import { StoragePlugin } from "@hot-updater/plugin-core";
6
-
7
7
  //#region src/createHotUpdaterCore.d.ts
8
8
  type RuntimeHotUpdaterAPI = DatabaseAPI & {
9
9
  readonly handlers: HotUpdaterHandlers;
@@ -1,5 +1,5 @@
1
1
  import { createHotUpdaterHandlers } from "./handler.mjs";
2
- import { createInsightsProvider } from "./insights/bounded/provider.mjs";
2
+ import { createInsightsProvider } from "./insights/provider.mjs";
3
3
  import { authenticateApiKey, createApiKeyManagement, normalizeApiKeyHeaderName } from "./apiKeys.mjs";
4
4
  import { createDatabasePluginCore } from "./db/databasePluginCore.mjs";
5
5
  import { createSchemaReadinessChecker } from "./db/schemaReadiness.mjs";
@@ -24,27 +24,41 @@ function getHotUpdaterCoreMetadata(hotUpdater) {
24
24
  function createHotUpdaterCore(options) {
25
25
  for (const key of ["authorityId", "catalogId"]) if (Object.hasOwn(options, key)) throw new TypeError(`Remove ${key} from createHotUpdater options. Catalog identity is managed internally.`);
26
26
  const database = options.database;
27
- const { downloadStorageObject, readStorageText, resolveFileUrl } = createStorageAccess((options.storage ?? []).map((storage) => {
27
+ const storagePlugins = (options.storage ?? []).map((storage) => {
28
28
  assertStorageOperations(storage, ["get", "getDownloadUrl"]);
29
29
  return storage;
30
- }));
30
+ });
31
+ const { downloadStorageObject, readStorageText, resolveFileUrl } = createStorageAccess(storagePlugins);
31
32
  const adapterCapabilities = database;
32
33
  if (!isDatabasePlugin(database)) throw new Error("@hot-updater/server only supports database plugins.");
33
34
  const plugin = database;
34
- const assertSchemaReady = createSchemaReadinessChecker(adapterCapabilities.adapterName ?? plugin.name, adapterCapabilities.createMigrator);
35
+ const adapterName = adapterCapabilities.adapterName ?? plugin.name;
36
+ const assertSchemaReady = createSchemaReadinessChecker(adapterName, adapterCapabilities.createMigrator);
35
37
  const core = createDatabasePluginCore(plugin, resolveFileUrl, {
36
38
  beforeOperation: assertSchemaReady,
37
39
  readStorageText
38
40
  });
39
41
  const clientAccess = normalizeClientAccess(options.clientAccess);
40
42
  const insights = createInsightsProvider({
41
- async append(row) {
43
+ async record(input) {
44
+ await assertSchemaReady();
45
+ return plugin.models.insights.record(input);
46
+ },
47
+ async listEvents(input) {
48
+ await assertSchemaReady();
49
+ return plugin.models.insights.listEvents(input);
50
+ },
51
+ async findInstallations(input) {
52
+ await assertSchemaReady();
53
+ return plugin.models.insights.findInstallations(input);
54
+ },
55
+ async countInstallations(input) {
42
56
  await assertSchemaReady();
43
- return plugin.models.insights.append(row);
57
+ return plugin.models.insights.countInstallations(input);
44
58
  },
45
- async scan(input) {
59
+ async countEvents(input) {
46
60
  await assertSchemaReady();
47
- return plugin.models.insights.scan(input);
61
+ return plugin.models.insights.countEvents(input);
48
62
  }
49
63
  });
50
64
  const apiKeys = createApiKeyManagement({
@@ -83,4 +97,4 @@ function createHotUpdater(options) {
83
97
  return createHotUpdaterCore(options).api;
84
98
  }
85
99
  //#endregion
86
- export { createHotUpdater, getHotUpdaterCoreMetadata };
100
+ export { createHotUpdater, createHotUpdaterCore, getHotUpdaterCoreMetadata, hotUpdaterCoreMetadata };
@@ -2,9 +2,9 @@ const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
2
2
  let _hot_updater_plugin_core = require("@hot-updater/plugin-core");
3
3
  let _hot_updater_core = require("@hot-updater/core");
4
4
  let node_crypto = require("node:crypto");
5
- node_crypto = require_runtime.__toESM(node_crypto);
5
+ node_crypto = require_runtime.__toESM(node_crypto, 1);
6
6
  let node_path = require("node:path");
7
- node_path = require_runtime.__toESM(node_path);
7
+ node_path = require_runtime.__toESM(node_path, 1);
8
8
  let node_util = require("node:util");
9
9
  let node_zlib = require("node:zlib");
10
10
  let _hot_updater_bsdiff = require("@hot-updater/bsdiff");
@@ -1,5 +1,4 @@
1
1
  import { Bundle, BundleRepository, StoragePluginWith } from "@hot-updater/plugin-core";
2
-
3
2
  //#region src/db/createBundleDiff.d.ts
4
3
  interface CreateBundleDiffInput {
5
4
  baseBundleId: string;
@@ -12,9 +11,6 @@ interface CreateBundleDiffDependencies {
12
11
  interface CreateBundleDiffOptions {
13
12
  makePrimary?: boolean;
14
13
  }
15
- declare function createBundleDiff({
16
- baseBundleId,
17
- bundleId
18
- }: CreateBundleDiffInput, deps: CreateBundleDiffDependencies, options?: CreateBundleDiffOptions): Promise<Bundle>;
14
+ declare function createBundleDiff({ baseBundleId, bundleId }: CreateBundleDiffInput, deps: CreateBundleDiffDependencies, options?: CreateBundleDiffOptions): Promise<Bundle>;
19
15
  //#endregion
20
16
  export { CreateBundleDiffDependencies, CreateBundleDiffInput, CreateBundleDiffOptions, createBundleDiff };
@@ -1,5 +1,4 @@
1
1
  import { Bundle, BundleRepository, StoragePluginWith } from "@hot-updater/plugin-core";
2
-
3
2
  //#region src/db/createBundleDiff.d.ts
4
3
  interface CreateBundleDiffInput {
5
4
  baseBundleId: string;
@@ -12,9 +11,6 @@ interface CreateBundleDiffDependencies {
12
11
  interface CreateBundleDiffOptions {
13
12
  makePrimary?: boolean;
14
13
  }
15
- declare function createBundleDiff({
16
- baseBundleId,
17
- bundleId
18
- }: CreateBundleDiffInput, deps: CreateBundleDiffDependencies, options?: CreateBundleDiffOptions): Promise<Bundle>;
14
+ declare function createBundleDiff({ baseBundleId, bundleId }: CreateBundleDiffInput, deps: CreateBundleDiffDependencies, options?: CreateBundleDiffOptions): Promise<Bundle>;
19
15
  //#endregion
20
16
  export { CreateBundleDiffDependencies, CreateBundleDiffInput, CreateBundleDiffOptions, createBundleDiff };
@@ -1,4 +1,3 @@
1
- require("../_virtual/_rolldown/runtime.cjs");
2
1
  const require_releaseCatalog = require("./releaseCatalog.cjs");
3
2
  let _hot_updater_plugin_core = require("@hot-updater/plugin-core");
4
3
  let _hot_updater_core = require("@hot-updater/core");
@@ -1,10 +1,9 @@
1
- require("../_virtual/_rolldown/runtime.cjs");
2
1
  const require_types = require("../schema/types.cjs");
3
2
  const require_fixedMigratorShared = require("./fixedMigratorShared.cjs");
4
3
  const require_sql = require("./schema/sql.cjs");
5
4
  const require_sqlOperations = require("./schema/sqlOperations.cjs");
6
5
  const require_sqlMigrationExecution = require("./sqlMigrationExecution.cjs");
7
- require("./fixedMigratorMongo.cjs");
6
+ const require_fixedMigratorMongo = require("./fixedMigratorMongo.cjs");
8
7
  let kysely = require("kysely");
9
8
  //#region src/db/fixedMigrator.ts
10
9
  const isMissingSettingsTableError = (error) => {
@@ -77,3 +76,4 @@ const createKyselyMigrator = ({ db, provider, relationMode = "foreign-keys" }) =
77
76
  };
78
77
  //#endregion
79
78
  exports.createKyselyMigrator = createKyselyMigrator;
79
+ exports.createMongoMigrator = require_fixedMigratorMongo.createMongoMigrator;
@@ -3,7 +3,7 @@ import { assertCurrentOrEmptySchemaVersion, assertSupportedMigrationMode, getEmp
3
3
  import { createTableSql } from "./schema/sql.mjs";
4
4
  import { createSqlCreateOperations, getSettingsInsertSql } from "./schema/sqlOperations.mjs";
5
5
  import { executeMigrationStatements } from "./sqlMigrationExecution.mjs";
6
- import "./fixedMigratorMongo.mjs";
6
+ import { createMongoMigrator } from "./fixedMigratorMongo.mjs";
7
7
  import { sql } from "kysely";
8
8
  //#region src/db/fixedMigrator.ts
9
9
  const isMissingSettingsTableError = (error) => {
@@ -75,4 +75,4 @@ const createKyselyMigrator = ({ db, provider, relationMode = "foreign-keys" }) =
75
75
  };
76
76
  };
77
77
  //#endregion
78
- export { createKyselyMigrator };
78
+ export { createKyselyMigrator, createMongoMigrator };
@@ -259,19 +259,21 @@ const createMongoMigrator = (client) => {
259
259
  await ensureSettingsKeyIndex();
260
260
  for (const table of require_registry.hotUpdaterSchema.tables) {
261
261
  if (table.internal) continue;
262
+ const isInsights = table.ormName === "bundle_events" || table.ormName === "bundle_installations";
262
263
  const collection = db.collection(table.ormName);
264
+ const collation = isInsights ? { locale: "simple" } : void 0;
263
265
  const primaryKey = table.columns.find((column) => column.primaryKey);
264
266
  if (!primaryKey) throw new Error(`MongoDB table ${table.ormName} does not define a primary key.`);
265
267
  const idIndexName = `${table.ormName}_${primaryKey.ormName}_idx`;
266
- const existingIdIndex = (await collection.listIndexes().toArray()).find(({ name }) => name === idIndexName);
267
- if (existingIdIndex && existingIdIndex.unique !== true) await collection.dropIndex(idIndexName);
268
268
  await collection.createIndex({ [primaryKey.ormName]: 1 }, {
269
269
  name: idIndexName,
270
- unique: true
270
+ unique: true,
271
+ ...collation ? { collation } : {}
271
272
  });
272
273
  for (const index of (table.indexes ?? []).filter((item) => require_registry.schemaIndexAppliesToProvider(item, "mongodb"))) await collection.createIndex(Object.fromEntries(index.columns.map((column) => [column, 1])), {
273
274
  name: index.name,
274
- ...index.unique ? { unique: true } : {}
275
+ ...index.unique ? { unique: true } : {},
276
+ ...collation ? { collation } : {}
275
277
  });
276
278
  }
277
279
  },
@@ -259,19 +259,21 @@ const createMongoMigrator = (client) => {
259
259
  await ensureSettingsKeyIndex();
260
260
  for (const table of hotUpdaterSchema.tables) {
261
261
  if (table.internal) continue;
262
+ const isInsights = table.ormName === "bundle_events" || table.ormName === "bundle_installations";
262
263
  const collection = db.collection(table.ormName);
264
+ const collation = isInsights ? { locale: "simple" } : void 0;
263
265
  const primaryKey = table.columns.find((column) => column.primaryKey);
264
266
  if (!primaryKey) throw new Error(`MongoDB table ${table.ormName} does not define a primary key.`);
265
267
  const idIndexName = `${table.ormName}_${primaryKey.ormName}_idx`;
266
- const existingIdIndex = (await collection.listIndexes().toArray()).find(({ name }) => name === idIndexName);
267
- if (existingIdIndex && existingIdIndex.unique !== true) await collection.dropIndex(idIndexName);
268
268
  await collection.createIndex({ [primaryKey.ormName]: 1 }, {
269
269
  name: idIndexName,
270
- unique: true
270
+ unique: true,
271
+ ...collation ? { collation } : {}
271
272
  });
272
273
  for (const index of (table.indexes ?? []).filter((item) => schemaIndexAppliesToProvider(item, "mongodb"))) await collection.createIndex(Object.fromEntries(index.columns.map((column) => [column, 1])), {
273
274
  name: index.name,
274
- ...index.unique ? { unique: true } : {}
275
+ ...index.unique ? { unique: true } : {},
276
+ ...collation ? { collation } : {}
275
277
  });
276
278
  }
277
279
  },
@@ -2,7 +2,6 @@ import { Migrator, SchemaGenerator } from "./types.cjs";
2
2
  import { CreateBundleDiffDependencies, CreateBundleDiffInput, CreateBundleDiffOptions, createBundleDiff } from "./createBundleDiff.cjs";
3
3
  import { HotUpdaterSchemaMigrationRequiredError } from "./schemaReadiness.cjs";
4
4
  import { HOT_UPDATER_SERVER_VERSION } from "../version.cjs";
5
-
6
5
  //#region src/db/index.d.ts
7
6
  type HotUpdaterDBTarget = {
8
7
  readonly adapterName: string;
@@ -2,7 +2,6 @@ import { Migrator, SchemaGenerator } from "./types.mjs";
2
2
  import { CreateBundleDiffDependencies, CreateBundleDiffInput, CreateBundleDiffOptions, createBundleDiff } from "./createBundleDiff.mjs";
3
3
  import { HotUpdaterSchemaMigrationRequiredError } from "./schemaReadiness.mjs";
4
4
  import { HOT_UPDATER_SERVER_VERSION } from "../version.mjs";
5
-
6
5
  //#region src/db/index.d.ts
7
6
  type HotUpdaterDBTarget = {
8
7
  readonly adapterName: string;
@@ -1,4 +1,3 @@
1
- require("../_virtual/_rolldown/runtime.cjs");
2
1
  const require_updateArtifacts = require("./updateArtifacts.cjs");
3
2
  let _hot_updater_plugin_core = require("@hot-updater/plugin-core");
4
3
  let _hot_updater_core = require("@hot-updater/core");
@@ -1,6 +1,5 @@
1
1
  import { ArtifactInfo, ReleaseCatalog } from "@hot-updater/core";
2
2
  import { DatabasePlugin } from "@hot-updater/plugin-core";
3
-
4
3
  //#region src/db/releaseCatalog.d.ts
5
4
  type ReleaseCatalogRequest = {
6
5
  readonly strategy: "APP_VERSION";