@hot-updater/server 0.28.0 → 0.29.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 (84) hide show
  1. package/dist/adapters/drizzle.cjs +7 -7
  2. package/dist/adapters/drizzle.mjs +2 -0
  3. package/dist/adapters/kysely.cjs +7 -7
  4. package/dist/adapters/kysely.mjs +2 -0
  5. package/dist/adapters/mongodb.cjs +7 -7
  6. package/dist/adapters/mongodb.mjs +2 -0
  7. package/dist/adapters/prisma.cjs +7 -7
  8. package/dist/adapters/prisma.mjs +2 -0
  9. package/dist/calculatePagination.cjs +1 -3
  10. package/dist/{calculatePagination.js → calculatePagination.mjs} +1 -2
  11. package/dist/db/index.cjs +24 -15
  12. package/dist/db/index.d.cts +12 -9
  13. package/dist/db/index.d.mts +30 -0
  14. package/dist/db/index.mjs +45 -0
  15. package/dist/db/ormCore.cjs +247 -138
  16. package/dist/db/ormCore.d.cts +35 -17
  17. package/dist/db/ormCore.d.mts +44 -0
  18. package/dist/db/ormCore.mjs +386 -0
  19. package/dist/db/pluginCore.cjs +145 -40
  20. package/dist/db/pluginCore.mjs +176 -0
  21. package/dist/db/types.cjs +1 -3
  22. package/dist/db/types.d.cts +14 -21
  23. package/dist/db/types.d.mts +24 -0
  24. package/dist/db/{types.js → types.mjs} +1 -2
  25. package/dist/handler.cjs +117 -48
  26. package/dist/handler.d.cts +28 -18
  27. package/dist/handler.d.mts +47 -0
  28. package/dist/handler.mjs +217 -0
  29. package/dist/index.cjs +5 -5
  30. package/dist/index.d.cts +3 -3
  31. package/dist/index.d.mts +5 -0
  32. package/dist/index.mjs +4 -0
  33. package/dist/internalRouter.cjs +54 -0
  34. package/dist/internalRouter.mjs +52 -0
  35. package/dist/node.cjs +2 -3
  36. package/dist/node.d.cts +0 -1
  37. package/dist/{node.d.ts → node.d.mts} +1 -2
  38. package/dist/{node.js → node.mjs} +1 -2
  39. package/dist/route.cjs +7 -0
  40. package/dist/route.mjs +7 -0
  41. package/dist/runtime.cjs +42 -0
  42. package/dist/runtime.d.cts +21 -0
  43. package/dist/runtime.d.mts +21 -0
  44. package/dist/runtime.mjs +40 -0
  45. package/dist/schema/v0_21_0.cjs +1 -5
  46. package/dist/schema/{v0_21_0.js → v0_21_0.mjs} +1 -3
  47. package/dist/schema/v0_29_0.cjs +24 -0
  48. package/dist/schema/v0_29_0.mjs +24 -0
  49. package/dist/types/{index.d.ts → index.d.mts} +1 -1
  50. package/package.json +18 -18
  51. package/src/db/index.spec.ts +64 -29
  52. package/src/db/index.ts +55 -35
  53. package/src/db/ormCore.ts +438 -210
  54. package/src/db/ormUpdateCheck.bench.ts +261 -0
  55. package/src/db/pluginCore.ts +298 -49
  56. package/src/db/pluginUpdateCheck.bench.ts +250 -0
  57. package/src/db/types.ts +52 -27
  58. package/src/{handler-standalone-integration.spec.ts → handler-standalone.integration.spec.ts} +106 -0
  59. package/src/handler.spec.ts +156 -0
  60. package/src/handler.ts +296 -77
  61. package/src/internalRouter.ts +104 -0
  62. package/src/route.ts +7 -0
  63. package/src/runtime.spec.ts +277 -0
  64. package/src/runtime.ts +121 -0
  65. package/src/schema/v0_29_0.ts +26 -0
  66. package/dist/_virtual/rolldown_runtime.cjs +0 -25
  67. package/dist/adapters/drizzle.js +0 -3
  68. package/dist/adapters/kysely.js +0 -3
  69. package/dist/adapters/mongodb.js +0 -3
  70. package/dist/adapters/prisma.js +0 -3
  71. package/dist/db/index.d.ts +0 -27
  72. package/dist/db/index.js +0 -36
  73. package/dist/db/ormCore.d.ts +0 -26
  74. package/dist/db/ormCore.js +0 -273
  75. package/dist/db/pluginCore.js +0 -69
  76. package/dist/db/types.d.ts +0 -31
  77. package/dist/handler.d.ts +0 -37
  78. package/dist/handler.js +0 -146
  79. package/dist/index.d.ts +0 -5
  80. package/dist/index.js +0 -5
  81. /package/dist/adapters/{drizzle.d.ts → drizzle.d.mts} +0 -0
  82. /package/dist/adapters/{kysely.d.ts → kysely.d.mts} +0 -0
  83. /package/dist/adapters/{mongodb.d.ts → mongodb.d.mts} +0 -0
  84. /package/dist/adapters/{prisma.d.ts → prisma.d.mts} +0 -0
@@ -1,25 +1,66 @@
1
- const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
2
- const require_calculatePagination = require('../calculatePagination.cjs');
3
- const require_v0_21_0 = require('../schema/v0_21_0.cjs');
4
- let __hot_updater_core = require("@hot-updater/core");
5
- __hot_updater_core = require_rolldown_runtime.__toESM(__hot_updater_core);
6
- let __hot_updater_plugin_core = require("@hot-updater/plugin-core");
7
- __hot_updater_plugin_core = require_rolldown_runtime.__toESM(__hot_updater_plugin_core);
1
+ const require_calculatePagination = require("../calculatePagination.cjs");
2
+ const require_v0_21_0 = require("../schema/v0_21_0.cjs");
3
+ const require_v0_29_0 = require("../schema/v0_29_0.cjs");
4
+ let _hot_updater_core = require("@hot-updater/core");
5
+ let _hot_updater_plugin_core = require("@hot-updater/plugin-core");
8
6
  let fumadb = require("fumadb");
9
- fumadb = require_rolldown_runtime.__toESM(fumadb);
10
-
11
7
  //#region src/db/ormCore.ts
8
+ const parseTargetCohorts = (value) => {
9
+ if (!value) return null;
10
+ if (Array.isArray(value)) return value.filter((v) => typeof v === "string");
11
+ if (typeof value === "string") try {
12
+ const parsed = JSON.parse(value);
13
+ if (Array.isArray(parsed)) return parsed.filter((v) => typeof v === "string");
14
+ } catch {
15
+ return null;
16
+ }
17
+ return null;
18
+ };
19
+ const schemas = [require_v0_21_0.v0_21_0, require_v0_29_0.v0_29_0];
20
+ const getLastItem = (items) => items.at(-1);
12
21
  const HotUpdaterDB = (0, fumadb.fumadb)({
13
22
  namespace: "hot_updater",
14
- schemas: [require_v0_21_0.v0_21_0]
23
+ schemas
15
24
  });
16
25
  function createOrmDatabaseCore({ database, resolveFileUrl }) {
17
26
  const client = HotUpdaterDB.client(database);
27
+ const UPDATE_CHECK_PAGE_SIZE = 100;
28
+ const isMongoAdapter = client.adapter.name.toLowerCase().includes("mongodb");
29
+ const ensureORM = async () => {
30
+ const lastSchemaVersion = getLastItem(schemas).version;
31
+ try {
32
+ const currentVersion = await client.createMigrator().getVersion();
33
+ if (currentVersion === void 0) throw new Error("Database is not initialized. Please run 'npx hot-updater migrate' to set up the database schema.");
34
+ if (currentVersion !== lastSchemaVersion) throw new Error(`Database schema version mismatch. Expected version ${lastSchemaVersion}, but database is on version ${currentVersion}. Please run 'npx hot-updater migrate' to update your database schema.`);
35
+ return client.orm(lastSchemaVersion);
36
+ } catch (error) {
37
+ if (error instanceof Error && error.message.includes("doesn't support migration")) return client.orm(lastSchemaVersion);
38
+ throw error;
39
+ }
40
+ };
41
+ const buildBundleWhere = (where) => (b) => {
42
+ if (where?.id?.in && where.id.in.length === 0) return false;
43
+ if (where?.targetAppVersionIn && where.targetAppVersionIn.length === 0) return false;
44
+ const conditions = [];
45
+ if (where?.channel !== void 0) conditions.push(b("channel", "=", where.channel));
46
+ if (where?.platform !== void 0) conditions.push(b("platform", "=", where.platform));
47
+ if (where?.enabled !== void 0) conditions.push(b("enabled", "=", where.enabled));
48
+ if (where?.id?.eq !== void 0) conditions.push(b("id", "=", where.id.eq));
49
+ if (where?.id?.gt !== void 0) conditions.push(b("id", ">", where.id.gt));
50
+ if (where?.id?.gte !== void 0) conditions.push(b("id", ">=", where.id.gte));
51
+ if (where?.id?.lt !== void 0) conditions.push(b("id", "<", where.id.lt));
52
+ if (where?.id?.lte !== void 0) conditions.push(b("id", "<=", where.id.lte));
53
+ if (where?.id?.in) conditions.push(b("id", "in", where.id.in));
54
+ if (where?.targetAppVersionNotNull) conditions.push(b.isNotNull("target_app_version"));
55
+ if (where?.targetAppVersion !== void 0) conditions.push(where.targetAppVersion === null ? b.isNull("target_app_version") : b("target_app_version", "=", where.targetAppVersion));
56
+ if (where?.targetAppVersionIn) conditions.push(b("target_app_version", "in", where.targetAppVersionIn));
57
+ if (where?.fingerprintHash !== void 0) conditions.push(where.fingerprintHash === null ? b.isNull("fingerprint_hash") : b("fingerprint_hash", "=", where.fingerprintHash));
58
+ return conditions.length > 0 ? b.and(...conditions) : true;
59
+ };
18
60
  return {
19
61
  api: {
20
62
  async getBundleById(id) {
21
- const version = await client.version();
22
- const result = await client.orm(version).findFirst("bundles", {
63
+ const result = await (await ensureORM()).findFirst("bundles", {
23
64
  select: [
24
65
  "id",
25
66
  "platform",
@@ -32,7 +73,9 @@ function createOrmDatabaseCore({ database, resolveFileUrl }) {
32
73
  "storage_uri",
33
74
  "target_app_version",
34
75
  "fingerprint_hash",
35
- "metadata"
76
+ "metadata",
77
+ "rollout_cohort_count",
78
+ "target_cohorts"
36
79
  ],
37
80
  where: (b) => b("id", "=", id)
38
81
  });
@@ -48,12 +91,13 @@ function createOrmDatabaseCore({ database, resolveFileUrl }) {
48
91
  channel: result.channel,
49
92
  storageUri: result.storage_uri,
50
93
  targetAppVersion: result.target_app_version ?? null,
51
- fingerprintHash: result.fingerprint_hash ?? null
94
+ fingerprintHash: result.fingerprint_hash ?? null,
95
+ rolloutCohortCount: result.rollout_cohort_count ?? _hot_updater_core.DEFAULT_ROLLOUT_COHORT_COUNT,
96
+ targetCohorts: parseTargetCohorts(result.target_cohorts)
52
97
  };
53
98
  },
54
99
  async getUpdateInfo(args) {
55
- const version = await client.version();
56
- const orm = client.orm(version);
100
+ const orm = await ensureORM();
57
101
  const toUpdateInfo = (row, status) => ({
58
102
  id: row.id,
59
103
  shouldForceUpdate: status === "ROLLBACK" ? true : Boolean(row.should_force_update),
@@ -63,145 +107,210 @@ function createOrmDatabaseCore({ database, resolveFileUrl }) {
63
107
  fileHash: row.file_hash ?? null
64
108
  });
65
109
  const INIT_BUNDLE_ROLLBACK_UPDATE_INFO = {
66
- id: __hot_updater_core.NIL_UUID,
110
+ id: _hot_updater_core.NIL_UUID,
67
111
  message: null,
68
112
  shouldForceUpdate: true,
69
113
  status: "ROLLBACK",
70
114
  storageUri: null,
71
115
  fileHash: null
72
116
  };
73
- const appVersionStrategy = async ({ platform, appVersion, bundleId, minBundleId = __hot_updater_core.NIL_UUID, channel = "production" }) => {
74
- const versionRows = await orm.findMany("bundles", {
75
- select: ["target_app_version"],
76
- where: (b) => b.and(b("platform", "=", platform))
77
- });
78
- const compatibleVersions = (0, __hot_updater_plugin_core.filterCompatibleAppVersions)(Array.from(new Set((versionRows ?? []).map((r) => r.target_app_version).filter((v) => Boolean(v)))), appVersion);
79
- const candidates = ((compatibleVersions.length === 0 ? [] : await orm.findMany("bundles", {
80
- select: [
81
- "id",
82
- "should_force_update",
83
- "message",
84
- "storage_uri",
85
- "file_hash",
86
- "channel",
87
- "target_app_version",
88
- "enabled"
89
- ],
90
- where: (b) => b.and(b("enabled", "=", true), b("platform", "=", platform), b("id", ">=", minBundleId ?? __hot_updater_core.NIL_UUID), b("channel", "=", channel), b.isNotNull("target_app_version"))
91
- })) ?? []).filter((r) => r.target_app_version ? compatibleVersions.includes(r.target_app_version) : false);
92
- const byIdDesc = (a, b) => b.id.localeCompare(a.id);
93
- const sorted = (candidates ?? []).slice().sort(byIdDesc);
94
- const latestCandidate = sorted[0] ?? null;
95
- const currentBundle = sorted.find((b) => b.id === bundleId);
96
- const updateCandidate = sorted.find((b) => b.id.localeCompare(bundleId) > 0) ?? null;
97
- const rollbackCandidate = sorted.find((b) => b.id.localeCompare(bundleId) < 0) ?? null;
98
- if (bundleId === __hot_updater_core.NIL_UUID) {
99
- if (latestCandidate && latestCandidate.id !== bundleId) return toUpdateInfo(latestCandidate, "UPDATE");
100
- return null;
117
+ const isEligibleForUpdate = (row, cohort) => {
118
+ return (0, _hot_updater_core.isCohortEligibleForUpdate)(row.id, cohort, row.rollout_cohort_count ?? null, parseTargetCohorts(row.target_cohorts));
119
+ };
120
+ const findUpdateInfoByScanning = async ({ args, where, isCandidate }) => {
121
+ if (isMongoAdapter) {
122
+ const rows = await orm.findMany("bundles", {
123
+ select: [
124
+ "id",
125
+ "should_force_update",
126
+ "message",
127
+ "storage_uri",
128
+ "file_hash",
129
+ "rollout_cohort_count",
130
+ "target_cohorts",
131
+ "target_app_version",
132
+ "fingerprint_hash"
133
+ ],
134
+ where: buildBundleWhere(where)
135
+ });
136
+ rows.sort((a, b) => b.id.localeCompare(a.id));
137
+ for (const row of rows) {
138
+ if (!isCandidate(row)) continue;
139
+ if (args.bundleId === _hot_updater_core.NIL_UUID) {
140
+ if (isEligibleForUpdate(row, args.cohort)) return toUpdateInfo(row, "UPDATE");
141
+ continue;
142
+ }
143
+ const compareResult = row.id.localeCompare(args.bundleId);
144
+ if (compareResult > 0) {
145
+ if (isEligibleForUpdate(row, args.cohort)) return toUpdateInfo(row, "UPDATE");
146
+ continue;
147
+ }
148
+ if (compareResult === 0) {
149
+ if (isEligibleForUpdate(row, args.cohort)) return null;
150
+ continue;
151
+ }
152
+ return toUpdateInfo(row, "ROLLBACK");
153
+ }
154
+ if (args.bundleId === _hot_updater_core.NIL_UUID) return null;
155
+ if (args.minBundleId && args.bundleId.localeCompare(args.minBundleId) <= 0) return null;
156
+ return INIT_BUNDLE_ROLLBACK_UPDATE_INFO;
101
157
  }
102
- if (currentBundle) {
103
- if (latestCandidate && latestCandidate.id.localeCompare(currentBundle.id) > 0) return toUpdateInfo(latestCandidate, "UPDATE");
104
- return null;
158
+ let offset = 0;
159
+ while (true) {
160
+ const rows = await orm.findMany("bundles", {
161
+ select: [
162
+ "id",
163
+ "should_force_update",
164
+ "message",
165
+ "storage_uri",
166
+ "file_hash",
167
+ "rollout_cohort_count",
168
+ "target_cohorts",
169
+ "target_app_version",
170
+ "fingerprint_hash"
171
+ ],
172
+ where: buildBundleWhere(where),
173
+ orderBy: [["id", "desc"]],
174
+ limit: UPDATE_CHECK_PAGE_SIZE,
175
+ offset
176
+ });
177
+ for (const row of rows) {
178
+ if (!isCandidate(row)) continue;
179
+ if (args.bundleId === _hot_updater_core.NIL_UUID) {
180
+ if (isEligibleForUpdate(row, args.cohort)) return toUpdateInfo(row, "UPDATE");
181
+ continue;
182
+ }
183
+ const compareResult = row.id.localeCompare(args.bundleId);
184
+ if (compareResult > 0) {
185
+ if (isEligibleForUpdate(row, args.cohort)) return toUpdateInfo(row, "UPDATE");
186
+ continue;
187
+ }
188
+ if (compareResult === 0) {
189
+ if (isEligibleForUpdate(row, args.cohort)) return null;
190
+ continue;
191
+ }
192
+ return toUpdateInfo(row, "ROLLBACK");
193
+ }
194
+ if (rows.length < UPDATE_CHECK_PAGE_SIZE) break;
195
+ offset += UPDATE_CHECK_PAGE_SIZE;
105
196
  }
106
- if (updateCandidate) return toUpdateInfo(updateCandidate, "UPDATE");
107
- if (rollbackCandidate) return toUpdateInfo(rollbackCandidate, "ROLLBACK");
108
- if (minBundleId && bundleId.localeCompare(minBundleId) <= 0) return null;
197
+ if (args.bundleId === _hot_updater_core.NIL_UUID) return null;
198
+ if (args.minBundleId && args.bundleId.localeCompare(args.minBundleId) <= 0) return null;
109
199
  return INIT_BUNDLE_ROLLBACK_UPDATE_INFO;
110
200
  };
111
- const fingerprintStrategy = async ({ platform, fingerprintHash, bundleId, minBundleId = __hot_updater_core.NIL_UUID, channel = "production" }) => {
112
- const candidates = await orm.findMany("bundles", {
113
- select: [
114
- "id",
115
- "should_force_update",
116
- "message",
117
- "storage_uri",
118
- "file_hash",
119
- "channel",
120
- "fingerprint_hash",
121
- "enabled"
122
- ],
123
- where: (b) => b.and(b("enabled", "=", true), b("platform", "=", platform), b("id", ">=", minBundleId ?? __hot_updater_core.NIL_UUID), b("channel", "=", channel), b("fingerprint_hash", "=", fingerprintHash))
201
+ const appVersionStrategy = async ({ platform, appVersion, bundleId, minBundleId = _hot_updater_core.NIL_UUID, channel = "production", cohort }) => {
202
+ return findUpdateInfoByScanning({
203
+ args: {
204
+ _updateStrategy: "appVersion",
205
+ platform,
206
+ appVersion,
207
+ bundleId,
208
+ minBundleId,
209
+ channel,
210
+ cohort
211
+ },
212
+ where: {
213
+ enabled: true,
214
+ platform,
215
+ channel,
216
+ id: { gte: minBundleId },
217
+ targetAppVersionNotNull: true
218
+ },
219
+ isCandidate: (row) => !!row.target_app_version && (0, _hot_updater_plugin_core.semverSatisfies)(row.target_app_version, appVersion)
220
+ });
221
+ };
222
+ const fingerprintStrategy = async ({ platform, fingerprintHash, bundleId, minBundleId = _hot_updater_core.NIL_UUID, channel = "production", cohort }) => {
223
+ return findUpdateInfoByScanning({
224
+ args: {
225
+ _updateStrategy: "fingerprint",
226
+ platform,
227
+ fingerprintHash,
228
+ bundleId,
229
+ minBundleId,
230
+ channel,
231
+ cohort
232
+ },
233
+ where: {
234
+ enabled: true,
235
+ platform,
236
+ channel,
237
+ id: { gte: minBundleId },
238
+ fingerprintHash
239
+ },
240
+ isCandidate: (row) => row.fingerprint_hash === fingerprintHash
124
241
  });
125
- const byIdDesc = (a, b) => b.id.localeCompare(a.id);
126
- const sorted = (candidates ?? []).slice().sort(byIdDesc);
127
- const latestCandidate = sorted[0] ?? null;
128
- const currentBundle = sorted.find((b) => b.id === bundleId);
129
- const updateCandidate = sorted.find((b) => b.id.localeCompare(bundleId) > 0) ?? null;
130
- const rollbackCandidate = sorted.find((b) => b.id.localeCompare(bundleId) < 0) ?? null;
131
- if (bundleId === __hot_updater_core.NIL_UUID) {
132
- if (latestCandidate && latestCandidate.id !== bundleId) return toUpdateInfo(latestCandidate, "UPDATE");
133
- return null;
134
- }
135
- if (currentBundle) {
136
- if (latestCandidate && latestCandidate.id.localeCompare(currentBundle.id) > 0) return toUpdateInfo(latestCandidate, "UPDATE");
137
- return null;
138
- }
139
- if (updateCandidate) return toUpdateInfo(updateCandidate, "UPDATE");
140
- if (rollbackCandidate) return toUpdateInfo(rollbackCandidate, "ROLLBACK");
141
- if (minBundleId && bundleId.localeCompare(minBundleId) <= 0) return null;
142
- return INIT_BUNDLE_ROLLBACK_UPDATE_INFO;
143
242
  };
144
243
  if (args._updateStrategy === "appVersion") return appVersionStrategy(args);
145
244
  if (args._updateStrategy === "fingerprint") return fingerprintStrategy(args);
146
245
  return null;
147
246
  },
148
- async getAppUpdateInfo(args) {
247
+ async getAppUpdateInfo(args, context) {
149
248
  const info = await this.getUpdateInfo(args);
150
249
  if (!info) return null;
151
- const { storageUri,...rest } = info;
152
- const fileUrl = await resolveFileUrl(storageUri ?? null);
250
+ const { storageUri, ...rest } = info;
251
+ const fileUrl = await resolveFileUrl(storageUri ?? null, context);
153
252
  return {
154
253
  ...rest,
155
254
  fileUrl
156
255
  };
157
256
  },
158
257
  async getChannels() {
159
- const version = await client.version();
160
- const rows = await client.orm(version).findMany("bundles", { select: ["channel"] });
258
+ const rows = await (await ensureORM()).findMany("bundles", {
259
+ select: ["channel"],
260
+ orderBy: [["channel", "asc"]]
261
+ });
161
262
  const set = new Set(rows?.map((r) => r.channel) ?? []);
162
263
  return Array.from(set);
163
264
  },
164
265
  async getBundles(options) {
165
- const version = await client.version();
166
- const orm = client.orm(version);
167
- const { where, limit, offset } = options;
168
- const all = (await orm.findMany("bundles", {
169
- select: [
170
- "id",
171
- "platform",
172
- "should_force_update",
173
- "enabled",
174
- "file_hash",
175
- "git_commit_hash",
176
- "message",
177
- "channel",
178
- "storage_uri",
179
- "target_app_version",
180
- "fingerprint_hash",
181
- "metadata"
182
- ],
183
- where: (b) => {
184
- const conditions = [];
185
- if (where?.channel) conditions.push(b("channel", "=", where.channel));
186
- if (where?.platform) conditions.push(b("platform", "=", where.platform));
187
- return conditions.length > 0 ? b.and(...conditions) : true;
188
- }
189
- })).map((r) => ({
190
- id: r.id,
191
- platform: r.platform,
192
- shouldForceUpdate: Boolean(r.should_force_update),
193
- enabled: Boolean(r.enabled),
194
- fileHash: r.file_hash,
195
- gitCommitHash: r.git_commit_hash ?? null,
196
- message: r.message ?? null,
197
- channel: r.channel,
198
- storageUri: r.storage_uri,
199
- targetAppVersion: r.target_app_version ?? null,
200
- fingerprintHash: r.fingerprint_hash ?? null
201
- })).sort((a, b) => b.id.localeCompare(a.id));
202
- const total = all.length;
266
+ const orm = await ensureORM();
267
+ const { where, limit, offset, orderBy } = options;
268
+ const total = await orm.count("bundles", { where: buildBundleWhere(where) });
269
+ const selectedColumns = [
270
+ "id",
271
+ "platform",
272
+ "should_force_update",
273
+ "enabled",
274
+ "file_hash",
275
+ "git_commit_hash",
276
+ "message",
277
+ "channel",
278
+ "storage_uri",
279
+ "target_app_version",
280
+ "fingerprint_hash",
281
+ "metadata",
282
+ "rollout_cohort_count",
283
+ "target_cohorts"
284
+ ];
203
285
  return {
204
- data: all.slice(offset, offset + limit),
286
+ data: (isMongoAdapter ? (await orm.findMany("bundles", {
287
+ select: selectedColumns,
288
+ where: buildBundleWhere(where)
289
+ })).sort((a, b) => {
290
+ const direction = orderBy?.direction ?? "desc";
291
+ const result = a.id.localeCompare(b.id);
292
+ return direction === "asc" ? result : -result;
293
+ }).slice(offset, offset + limit) : await orm.findMany("bundles", {
294
+ select: selectedColumns,
295
+ where: buildBundleWhere(where),
296
+ orderBy: [[orderBy?.field ?? "id", orderBy?.direction ?? "desc"]],
297
+ limit,
298
+ offset
299
+ })).map((r) => ({
300
+ id: r.id,
301
+ platform: r.platform,
302
+ shouldForceUpdate: Boolean(r.should_force_update),
303
+ enabled: Boolean(r.enabled),
304
+ fileHash: r.file_hash,
305
+ gitCommitHash: r.git_commit_hash ?? null,
306
+ message: r.message ?? null,
307
+ channel: r.channel,
308
+ storageUri: r.storage_uri,
309
+ targetAppVersion: r.target_app_version ?? null,
310
+ fingerprintHash: r.fingerprint_hash ?? null,
311
+ rolloutCohortCount: r.rollout_cohort_count ?? _hot_updater_core.DEFAULT_ROLLOUT_COHORT_COUNT,
312
+ targetCohorts: parseTargetCohorts(r.target_cohorts)
313
+ })),
205
314
  pagination: require_calculatePagination.calculatePagination(total, {
206
315
  limit,
207
316
  offset
@@ -209,8 +318,7 @@ function createOrmDatabaseCore({ database, resolveFileUrl }) {
209
318
  };
210
319
  },
211
320
  async insertBundle(bundle) {
212
- const version = await client.version();
213
- const orm = client.orm(version);
321
+ const orm = await ensureORM();
214
322
  const values = {
215
323
  id: bundle.id,
216
324
  platform: bundle.platform,
@@ -223,9 +331,11 @@ function createOrmDatabaseCore({ database, resolveFileUrl }) {
223
331
  storage_uri: bundle.storageUri,
224
332
  target_app_version: bundle.targetAppVersion,
225
333
  fingerprint_hash: bundle.fingerprintHash,
226
- metadata: bundle.metadata ?? {}
334
+ metadata: bundle.metadata ?? {},
335
+ rollout_cohort_count: bundle.rolloutCohortCount ?? _hot_updater_core.DEFAULT_ROLLOUT_COHORT_COUNT,
336
+ target_cohorts: bundle.targetCohorts ?? null
227
337
  };
228
- const { id,...updateValues } = values;
338
+ const { id, ...updateValues } = values;
229
339
  await orm.upsert("bundles", {
230
340
  where: (b) => b("id", "=", id),
231
341
  create: values,
@@ -233,8 +343,7 @@ function createOrmDatabaseCore({ database, resolveFileUrl }) {
233
343
  });
234
344
  },
235
345
  async updateBundleById(bundleId, newBundle) {
236
- const version = await client.version();
237
- const orm = client.orm(version);
346
+ const orm = await ensureORM();
238
347
  const current = await this.getBundleById(bundleId);
239
348
  if (!current) throw new Error("targetBundleId not found");
240
349
  const merged = {
@@ -253,9 +362,11 @@ function createOrmDatabaseCore({ database, resolveFileUrl }) {
253
362
  storage_uri: merged.storageUri,
254
363
  target_app_version: merged.targetAppVersion,
255
364
  fingerprint_hash: merged.fingerprintHash,
256
- metadata: merged.metadata ?? {}
365
+ metadata: merged.metadata ?? {},
366
+ rollout_cohort_count: merged.rolloutCohortCount ?? _hot_updater_core.DEFAULT_ROLLOUT_COHORT_COUNT,
367
+ target_cohorts: merged.targetCohorts ?? null
257
368
  };
258
- const { id: id2,...updateValues2 } = values;
369
+ const { id: id2, ...updateValues2 } = values;
259
370
  await orm.upsert("bundles", {
260
371
  where: (b) => b("id", "=", id2),
261
372
  create: values,
@@ -263,8 +374,7 @@ function createOrmDatabaseCore({ database, resolveFileUrl }) {
263
374
  });
264
375
  },
265
376
  async deleteBundleById(bundleId) {
266
- const version = await client.version();
267
- await client.orm(version).deleteMany("bundles", { where: (b) => b("id", "=", bundleId) });
377
+ await (await ensureORM()).deleteMany("bundles", { where: (b) => b("id", "=", bundleId) });
268
378
  }
269
379
  },
270
380
  adapterName: client.adapter.name,
@@ -272,7 +382,6 @@ function createOrmDatabaseCore({ database, resolveFileUrl }) {
272
382
  generateSchema: client.generateSchema
273
383
  };
274
384
  }
275
-
276
385
  //#endregion
277
386
  exports.HotUpdaterDB = HotUpdaterDB;
278
- exports.createOrmDatabaseCore = createOrmDatabaseCore;
387
+ exports.createOrmDatabaseCore = createOrmDatabaseCore;
@@ -1,25 +1,43 @@
1
- import * as fumadb_schema0 from "fumadb/schema";
2
- import * as fumadb0 from "fumadb";
1
+ import { HotUpdaterContext } from "@hot-updater/plugin-core";
2
+ import * as _$fumadb_schema0 from "fumadb/schema";
3
+ import * as _$fumadb from "fumadb";
3
4
  import { InferFumaDB } from "fumadb";
4
5
  import { FumaDBAdapter } from "fumadb/adapters";
5
6
 
6
7
  //#region src/db/ormCore.d.ts
7
- declare const HotUpdaterDB: fumadb0.FumaDBFactory<fumadb_schema0.Schema<"0.21.0", {
8
- bundles: fumadb_schema0.Table<{
9
- id: fumadb_schema0.IdColumn<"uuid", string, string>;
10
- platform: fumadb_schema0.Column<"string", string, string>;
11
- should_force_update: fumadb_schema0.Column<"bool", boolean, boolean>;
12
- enabled: fumadb_schema0.Column<"bool", boolean, boolean>;
13
- file_hash: fumadb_schema0.Column<"string", string, string>;
14
- git_commit_hash: fumadb_schema0.Column<"string", string | null, string | null>;
15
- message: fumadb_schema0.Column<"string", string | null, string | null>;
16
- channel: fumadb_schema0.Column<"string", string, string>;
17
- storage_uri: fumadb_schema0.Column<"string", string, string>;
18
- target_app_version: fumadb_schema0.Column<"string", string | null, string | null>;
19
- fingerprint_hash: fumadb_schema0.Column<"string", string | null, string | null>;
20
- metadata: fumadb_schema0.Column<"json", unknown, unknown>;
8
+ declare const HotUpdaterDB: _$fumadb.FumaDBFactory<[_$fumadb_schema0.Schema<"0.21.0", {
9
+ bundles: _$fumadb_schema0.Table<{
10
+ id: _$fumadb_schema0.IdColumn<"uuid", string, string>;
11
+ platform: _$fumadb_schema0.Column<"string", string, string>;
12
+ should_force_update: _$fumadb_schema0.Column<"bool", boolean, boolean>;
13
+ enabled: _$fumadb_schema0.Column<"bool", boolean, boolean>;
14
+ file_hash: _$fumadb_schema0.Column<"string", string, string>;
15
+ git_commit_hash: _$fumadb_schema0.Column<"string", string | null, string | null>;
16
+ message: _$fumadb_schema0.Column<"string", string | null, string | null>;
17
+ channel: _$fumadb_schema0.Column<"string", string, string>;
18
+ storage_uri: _$fumadb_schema0.Column<"string", string, string>;
19
+ target_app_version: _$fumadb_schema0.Column<"string", string | null, string | null>;
20
+ fingerprint_hash: _$fumadb_schema0.Column<"string", string | null, string | null>;
21
+ metadata: _$fumadb_schema0.Column<"json", unknown, unknown>;
21
22
  }, {}>;
22
- }>[]>;
23
+ }>, _$fumadb_schema0.Schema<"0.29.0", {
24
+ bundles: _$fumadb_schema0.Table<{
25
+ id: _$fumadb_schema0.IdColumn<"uuid", string, string>;
26
+ platform: _$fumadb_schema0.Column<"string", string, string>;
27
+ should_force_update: _$fumadb_schema0.Column<"bool", boolean, boolean>;
28
+ enabled: _$fumadb_schema0.Column<"bool", boolean, boolean>;
29
+ file_hash: _$fumadb_schema0.Column<"string", string, string>;
30
+ git_commit_hash: _$fumadb_schema0.Column<"string", string | null, string | null>;
31
+ message: _$fumadb_schema0.Column<"string", string | null, string | null>;
32
+ channel: _$fumadb_schema0.Column<"string", string, string>;
33
+ storage_uri: _$fumadb_schema0.Column<"string", string, string>;
34
+ target_app_version: _$fumadb_schema0.Column<"string", string | null, string | null>;
35
+ fingerprint_hash: _$fumadb_schema0.Column<"string", string | null, string | null>;
36
+ metadata: _$fumadb_schema0.Column<"json", unknown, unknown>;
37
+ rollout_cohort_count: _$fumadb_schema0.Column<"integer", number | null, number>;
38
+ target_cohorts: _$fumadb_schema0.Column<"json", unknown, unknown>;
39
+ }, {}>;
40
+ }>]>;
23
41
  type HotUpdaterClient = InferFumaDB<typeof HotUpdaterDB>;
24
42
  type Migrator = ReturnType<HotUpdaterClient["createMigrator"]>;
25
43
  //#endregion
@@ -0,0 +1,44 @@
1
+ import { HotUpdaterContext } from "@hot-updater/plugin-core";
2
+ import * as _$fumadb from "fumadb";
3
+ import { InferFumaDB } from "fumadb";
4
+ import * as _$fumadb_schema0 from "fumadb/schema";
5
+ import { FumaDBAdapter } from "fumadb/adapters";
6
+
7
+ //#region src/db/ormCore.d.ts
8
+ declare const HotUpdaterDB: _$fumadb.FumaDBFactory<[_$fumadb_schema0.Schema<"0.21.0", {
9
+ bundles: _$fumadb_schema0.Table<{
10
+ id: _$fumadb_schema0.IdColumn<"uuid", string, string>;
11
+ platform: _$fumadb_schema0.Column<"string", string, string>;
12
+ should_force_update: _$fumadb_schema0.Column<"bool", boolean, boolean>;
13
+ enabled: _$fumadb_schema0.Column<"bool", boolean, boolean>;
14
+ file_hash: _$fumadb_schema0.Column<"string", string, string>;
15
+ git_commit_hash: _$fumadb_schema0.Column<"string", string | null, string | null>;
16
+ message: _$fumadb_schema0.Column<"string", string | null, string | null>;
17
+ channel: _$fumadb_schema0.Column<"string", string, string>;
18
+ storage_uri: _$fumadb_schema0.Column<"string", string, string>;
19
+ target_app_version: _$fumadb_schema0.Column<"string", string | null, string | null>;
20
+ fingerprint_hash: _$fumadb_schema0.Column<"string", string | null, string | null>;
21
+ metadata: _$fumadb_schema0.Column<"json", unknown, unknown>;
22
+ }, {}>;
23
+ }>, _$fumadb_schema0.Schema<"0.29.0", {
24
+ bundles: _$fumadb_schema0.Table<{
25
+ id: _$fumadb_schema0.IdColumn<"uuid", string, string>;
26
+ platform: _$fumadb_schema0.Column<"string", string, string>;
27
+ should_force_update: _$fumadb_schema0.Column<"bool", boolean, boolean>;
28
+ enabled: _$fumadb_schema0.Column<"bool", boolean, boolean>;
29
+ file_hash: _$fumadb_schema0.Column<"string", string, string>;
30
+ git_commit_hash: _$fumadb_schema0.Column<"string", string | null, string | null>;
31
+ message: _$fumadb_schema0.Column<"string", string | null, string | null>;
32
+ channel: _$fumadb_schema0.Column<"string", string, string>;
33
+ storage_uri: _$fumadb_schema0.Column<"string", string, string>;
34
+ target_app_version: _$fumadb_schema0.Column<"string", string | null, string | null>;
35
+ fingerprint_hash: _$fumadb_schema0.Column<"string", string | null, string | null>;
36
+ metadata: _$fumadb_schema0.Column<"json", unknown, unknown>;
37
+ rollout_cohort_count: _$fumadb_schema0.Column<"integer", number | null, number>;
38
+ target_cohorts: _$fumadb_schema0.Column<"json", unknown, unknown>;
39
+ }, {}>;
40
+ }>]>;
41
+ type HotUpdaterClient = InferFumaDB<typeof HotUpdaterDB>;
42
+ type Migrator = ReturnType<HotUpdaterClient["createMigrator"]>;
43
+ //#endregion
44
+ export { HotUpdaterClient, HotUpdaterDB, Migrator };