@hot-updater/server 0.29.4 → 0.29.6

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.
@@ -18,6 +18,40 @@ const parseTargetCohorts = (value) => {
18
18
  };
19
19
  const schemas = [require_v0_21_0.v0_21_0, require_v0_29_0.v0_29_0];
20
20
  const getLastItem = (items) => items.at(-1);
21
+ const DEFAULT_BUNDLE_ORDER = {
22
+ field: "id",
23
+ direction: "desc"
24
+ };
25
+ const mergeIdFilter = (base, patch) => ({
26
+ ...base,
27
+ ...patch
28
+ });
29
+ const mergeWhereWithIdFilter = (where, idFilter) => ({
30
+ ...where,
31
+ id: mergeIdFilter(where?.id, idFilter)
32
+ });
33
+ const buildCursorPageWhere = (where, cursor, orderBy) => {
34
+ const direction = orderBy.direction;
35
+ if (cursor.after) return {
36
+ reverseData: false,
37
+ where: mergeWhereWithIdFilter(where, { [direction === "desc" ? "lt" : "gt"]: cursor.after }),
38
+ orderBy
39
+ };
40
+ if (cursor.before) return {
41
+ reverseData: true,
42
+ where: mergeWhereWithIdFilter(where, { [direction === "desc" ? "gt" : "lt"]: cursor.before }),
43
+ orderBy: {
44
+ field: orderBy.field,
45
+ direction: direction === "desc" ? "asc" : "desc"
46
+ }
47
+ };
48
+ return {
49
+ reverseData: false,
50
+ where: where ?? {},
51
+ orderBy
52
+ };
53
+ };
54
+ const buildCountBeforeWhere = (where, firstBundleId, orderBy) => mergeWhereWithIdFilter(where, { [orderBy.direction === "desc" ? "gt" : "lt"]: firstBundleId });
21
55
  const HotUpdaterDB = (0, fumadb.fumadb)({
22
56
  namespace: "hot_updater",
23
57
  schemas
@@ -264,7 +298,9 @@ function createOrmDatabaseCore({ database, resolveFileUrl }) {
264
298
  },
265
299
  async getBundles(options) {
266
300
  const orm = await ensureORM();
267
- const { where, limit, offset, orderBy } = options;
301
+ const { where, limit } = options;
302
+ const orderBy = options.orderBy ?? DEFAULT_BUNDLE_ORDER;
303
+ const offset = ("offset" in options ? options.offset : void 0) ?? 0;
268
304
  const total = await orm.count("bundles", { where: buildBundleWhere(where) });
269
305
  const selectedColumns = [
270
306
  "id",
@@ -282,39 +318,85 @@ function createOrmDatabaseCore({ database, resolveFileUrl }) {
282
318
  "rollout_cohort_count",
283
319
  "target_cohorts"
284
320
  ];
285
- return {
286
- data: (isMongoAdapter ? (await orm.findMany("bundles", {
321
+ const mapRowsToBundles = (rows) => rows.map((r) => ({
322
+ id: r.id,
323
+ platform: r.platform,
324
+ shouldForceUpdate: Boolean(r.should_force_update),
325
+ enabled: Boolean(r.enabled),
326
+ fileHash: r.file_hash,
327
+ gitCommitHash: r.git_commit_hash ?? null,
328
+ message: r.message ?? null,
329
+ channel: r.channel,
330
+ storageUri: r.storage_uri,
331
+ targetAppVersion: r.target_app_version ?? null,
332
+ fingerprintHash: r.fingerprint_hash ?? null,
333
+ rolloutCohortCount: r.rollout_cohort_count ?? _hot_updater_core.DEFAULT_ROLLOUT_COHORT_COUNT,
334
+ targetCohorts: parseTargetCohorts(r.target_cohorts)
335
+ }));
336
+ const findBundles = async ({ where, orderBy, limit, offset }) => {
337
+ return mapRowsToBundles(isMongoAdapter ? (await orm.findMany("bundles", {
287
338
  select: selectedColumns,
288
339
  where: buildBundleWhere(where)
289
340
  })).sort((a, b) => {
290
- const direction = orderBy?.direction ?? "desc";
291
341
  const result = a.id.localeCompare(b.id);
292
- return direction === "asc" ? result : -result;
342
+ return orderBy.direction === "asc" ? result : -result;
293
343
  }).slice(offset, offset + limit) : await orm.findMany("bundles", {
294
344
  select: selectedColumns,
295
345
  where: buildBundleWhere(where),
296
- orderBy: [[orderBy?.field ?? "id", orderBy?.direction ?? "desc"]],
346
+ orderBy: [[orderBy.field, orderBy.direction]],
297
347
  limit,
298
348
  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
- })),
314
- pagination: require_calculatePagination.calculatePagination(total, {
349
+ }));
350
+ };
351
+ if (!options.cursor?.after && !options.cursor?.before) {
352
+ const data = await findBundles({
353
+ where,
354
+ orderBy,
315
355
  limit,
316
356
  offset
317
- })
357
+ });
358
+ return {
359
+ data,
360
+ pagination: {
361
+ ...require_calculatePagination.calculatePagination(total, {
362
+ limit,
363
+ offset
364
+ }),
365
+ ...data.length > 0 && offset + data.length < total ? { nextCursor: data.at(-1)?.id } : {},
366
+ ...data.length > 0 && offset > 0 ? { previousCursor: data[0]?.id } : {}
367
+ }
368
+ };
369
+ }
370
+ const { where: cursorWhere, orderBy: cursorOrderBy, reverseData } = buildCursorPageWhere(where, options.cursor, orderBy);
371
+ const cursorPage = await findBundles({
372
+ where: cursorWhere,
373
+ orderBy: cursorOrderBy,
374
+ limit,
375
+ offset: 0
376
+ });
377
+ const data = reverseData ? cursorPage.slice().reverse() : cursorPage;
378
+ if (data.length === 0) return {
379
+ data,
380
+ pagination: {
381
+ ...require_calculatePagination.calculatePagination(total, {
382
+ limit,
383
+ offset: options.cursor.after ? total : 0
384
+ }),
385
+ ...options.cursor.after ? { previousCursor: options.cursor.after } : {},
386
+ ...options.cursor.before ? { nextCursor: options.cursor.before } : {}
387
+ }
388
+ };
389
+ const startIndex = await orm.count("bundles", { where: buildBundleWhere(buildCountBeforeWhere(where, data[0].id, orderBy)) });
390
+ return {
391
+ data,
392
+ pagination: {
393
+ ...require_calculatePagination.calculatePagination(total, {
394
+ limit,
395
+ offset: startIndex
396
+ }),
397
+ ...startIndex + data.length < total ? { nextCursor: data.at(-1)?.id } : {},
398
+ ...startIndex > 0 ? { previousCursor: data[0]?.id } : {}
399
+ }
318
400
  };
319
401
  },
320
402
  async insertBundle(bundle) {
@@ -18,6 +18,40 @@ const parseTargetCohorts = (value) => {
18
18
  };
19
19
  const schemas = [v0_21_0, v0_29_0];
20
20
  const getLastItem = (items) => items.at(-1);
21
+ const DEFAULT_BUNDLE_ORDER = {
22
+ field: "id",
23
+ direction: "desc"
24
+ };
25
+ const mergeIdFilter = (base, patch) => ({
26
+ ...base,
27
+ ...patch
28
+ });
29
+ const mergeWhereWithIdFilter = (where, idFilter) => ({
30
+ ...where,
31
+ id: mergeIdFilter(where?.id, idFilter)
32
+ });
33
+ const buildCursorPageWhere = (where, cursor, orderBy) => {
34
+ const direction = orderBy.direction;
35
+ if (cursor.after) return {
36
+ reverseData: false,
37
+ where: mergeWhereWithIdFilter(where, { [direction === "desc" ? "lt" : "gt"]: cursor.after }),
38
+ orderBy
39
+ };
40
+ if (cursor.before) return {
41
+ reverseData: true,
42
+ where: mergeWhereWithIdFilter(where, { [direction === "desc" ? "gt" : "lt"]: cursor.before }),
43
+ orderBy: {
44
+ field: orderBy.field,
45
+ direction: direction === "desc" ? "asc" : "desc"
46
+ }
47
+ };
48
+ return {
49
+ reverseData: false,
50
+ where: where ?? {},
51
+ orderBy
52
+ };
53
+ };
54
+ const buildCountBeforeWhere = (where, firstBundleId, orderBy) => mergeWhereWithIdFilter(where, { [orderBy.direction === "desc" ? "gt" : "lt"]: firstBundleId });
21
55
  const HotUpdaterDB = fumadb({
22
56
  namespace: "hot_updater",
23
57
  schemas
@@ -264,7 +298,9 @@ function createOrmDatabaseCore({ database, resolveFileUrl }) {
264
298
  },
265
299
  async getBundles(options) {
266
300
  const orm = await ensureORM();
267
- const { where, limit, offset, orderBy } = options;
301
+ const { where, limit } = options;
302
+ const orderBy = options.orderBy ?? DEFAULT_BUNDLE_ORDER;
303
+ const offset = ("offset" in options ? options.offset : void 0) ?? 0;
268
304
  const total = await orm.count("bundles", { where: buildBundleWhere(where) });
269
305
  const selectedColumns = [
270
306
  "id",
@@ -282,39 +318,85 @@ function createOrmDatabaseCore({ database, resolveFileUrl }) {
282
318
  "rollout_cohort_count",
283
319
  "target_cohorts"
284
320
  ];
285
- return {
286
- data: (isMongoAdapter ? (await orm.findMany("bundles", {
321
+ const mapRowsToBundles = (rows) => rows.map((r) => ({
322
+ id: r.id,
323
+ platform: r.platform,
324
+ shouldForceUpdate: Boolean(r.should_force_update),
325
+ enabled: Boolean(r.enabled),
326
+ fileHash: r.file_hash,
327
+ gitCommitHash: r.git_commit_hash ?? null,
328
+ message: r.message ?? null,
329
+ channel: r.channel,
330
+ storageUri: r.storage_uri,
331
+ targetAppVersion: r.target_app_version ?? null,
332
+ fingerprintHash: r.fingerprint_hash ?? null,
333
+ rolloutCohortCount: r.rollout_cohort_count ?? DEFAULT_ROLLOUT_COHORT_COUNT,
334
+ targetCohorts: parseTargetCohorts(r.target_cohorts)
335
+ }));
336
+ const findBundles = async ({ where, orderBy, limit, offset }) => {
337
+ return mapRowsToBundles(isMongoAdapter ? (await orm.findMany("bundles", {
287
338
  select: selectedColumns,
288
339
  where: buildBundleWhere(where)
289
340
  })).sort((a, b) => {
290
- const direction = orderBy?.direction ?? "desc";
291
341
  const result = a.id.localeCompare(b.id);
292
- return direction === "asc" ? result : -result;
342
+ return orderBy.direction === "asc" ? result : -result;
293
343
  }).slice(offset, offset + limit) : await orm.findMany("bundles", {
294
344
  select: selectedColumns,
295
345
  where: buildBundleWhere(where),
296
- orderBy: [[orderBy?.field ?? "id", orderBy?.direction ?? "desc"]],
346
+ orderBy: [[orderBy.field, orderBy.direction]],
297
347
  limit,
298
348
  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 ?? DEFAULT_ROLLOUT_COHORT_COUNT,
312
- targetCohorts: parseTargetCohorts(r.target_cohorts)
313
- })),
314
- pagination: calculatePagination(total, {
349
+ }));
350
+ };
351
+ if (!options.cursor?.after && !options.cursor?.before) {
352
+ const data = await findBundles({
353
+ where,
354
+ orderBy,
315
355
  limit,
316
356
  offset
317
- })
357
+ });
358
+ return {
359
+ data,
360
+ pagination: {
361
+ ...calculatePagination(total, {
362
+ limit,
363
+ offset
364
+ }),
365
+ ...data.length > 0 && offset + data.length < total ? { nextCursor: data.at(-1)?.id } : {},
366
+ ...data.length > 0 && offset > 0 ? { previousCursor: data[0]?.id } : {}
367
+ }
368
+ };
369
+ }
370
+ const { where: cursorWhere, orderBy: cursorOrderBy, reverseData } = buildCursorPageWhere(where, options.cursor, orderBy);
371
+ const cursorPage = await findBundles({
372
+ where: cursorWhere,
373
+ orderBy: cursorOrderBy,
374
+ limit,
375
+ offset: 0
376
+ });
377
+ const data = reverseData ? cursorPage.slice().reverse() : cursorPage;
378
+ if (data.length === 0) return {
379
+ data,
380
+ pagination: {
381
+ ...calculatePagination(total, {
382
+ limit,
383
+ offset: options.cursor.after ? total : 0
384
+ }),
385
+ ...options.cursor.after ? { previousCursor: options.cursor.after } : {},
386
+ ...options.cursor.before ? { nextCursor: options.cursor.before } : {}
387
+ }
388
+ };
389
+ const startIndex = await orm.count("bundles", { where: buildBundleWhere(buildCountBeforeWhere(where, data[0].id, orderBy)) });
390
+ return {
391
+ data,
392
+ pagination: {
393
+ ...calculatePagination(total, {
394
+ limit,
395
+ offset: startIndex
396
+ }),
397
+ ...startIndex + data.length < total ? { nextCursor: data.at(-1)?.id } : {},
398
+ ...startIndex > 0 ? { previousCursor: data[0]?.id } : {}
399
+ }
318
400
  };
319
401
  },
320
402
  async insertBundle(bundle) {
@@ -69,13 +69,13 @@ function createPluginDatabaseCore(getPlugin, resolveFileUrl, options) {
69
69
  return (0, _hot_updater_core.isCohortEligibleForUpdate)(bundle.id, cohort, bundle.rolloutCohortCount, bundle.targetCohorts);
70
70
  };
71
71
  const findUpdateInfoByScanning = async ({ args, queryWhere, isCandidate, context }) => {
72
- let offset = 0;
72
+ let after;
73
73
  while (true) {
74
74
  const { data, pagination } = await getSortedBundlePage({
75
75
  where: queryWhere,
76
76
  limit: PAGE_SIZE,
77
- offset,
78
- orderBy: DESC_ORDER
77
+ orderBy: DESC_ORDER,
78
+ ...after ? { cursor: { after } } : {}
79
79
  }, context);
80
80
  for (const bundle of data) {
81
81
  if (!bundleMatchesQueryWhere(bundle, queryWhere) || !isCandidate(bundle)) continue;
@@ -95,7 +95,8 @@ function createPluginDatabaseCore(getPlugin, resolveFileUrl, options) {
95
95
  return makeResponse(bundle, "ROLLBACK");
96
96
  }
97
97
  if (!pagination.hasNextPage) break;
98
- offset += PAGE_SIZE;
98
+ after = data.at(-1)?.id;
99
+ if (!after) break;
99
100
  }
100
101
  if (args.bundleId === _hot_updater_core.NIL_UUID) return null;
101
102
  if (args.minBundleId && args.bundleId.localeCompare(args.minBundleId) <= 0) return null;
@@ -113,6 +114,8 @@ function createPluginDatabaseCore(getPlugin, resolveFileUrl, options) {
113
114
  return getPlugin().getBundleById(id, context);
114
115
  },
115
116
  async getUpdateInfo(args, context) {
117
+ const directGetUpdateInfo = getPlugin().getUpdateInfo;
118
+ if (directGetUpdateInfo) return context === void 0 ? await directGetUpdateInfo(args) : await directGetUpdateInfo(args, context);
116
119
  const channel = args.channel ?? "production";
117
120
  const minBundleId = args.minBundleId ?? _hot_updater_core.NIL_UUID;
118
121
  const baseWhere = getBaseWhere({
@@ -69,13 +69,13 @@ function createPluginDatabaseCore(getPlugin, resolveFileUrl, options) {
69
69
  return isCohortEligibleForUpdate(bundle.id, cohort, bundle.rolloutCohortCount, bundle.targetCohorts);
70
70
  };
71
71
  const findUpdateInfoByScanning = async ({ args, queryWhere, isCandidate, context }) => {
72
- let offset = 0;
72
+ let after;
73
73
  while (true) {
74
74
  const { data, pagination } = await getSortedBundlePage({
75
75
  where: queryWhere,
76
76
  limit: PAGE_SIZE,
77
- offset,
78
- orderBy: DESC_ORDER
77
+ orderBy: DESC_ORDER,
78
+ ...after ? { cursor: { after } } : {}
79
79
  }, context);
80
80
  for (const bundle of data) {
81
81
  if (!bundleMatchesQueryWhere(bundle, queryWhere) || !isCandidate(bundle)) continue;
@@ -95,7 +95,8 @@ function createPluginDatabaseCore(getPlugin, resolveFileUrl, options) {
95
95
  return makeResponse(bundle, "ROLLBACK");
96
96
  }
97
97
  if (!pagination.hasNextPage) break;
98
- offset += PAGE_SIZE;
98
+ after = data.at(-1)?.id;
99
+ if (!after) break;
99
100
  }
100
101
  if (args.bundleId === NIL_UUID) return null;
101
102
  if (args.minBundleId && args.bundleId.localeCompare(args.minBundleId) <= 0) return null;
@@ -113,6 +114,8 @@ function createPluginDatabaseCore(getPlugin, resolveFileUrl, options) {
113
114
  return getPlugin().getBundleById(id, context);
114
115
  },
115
116
  async getUpdateInfo(args, context) {
117
+ const directGetUpdateInfo = getPlugin().getUpdateInfo;
118
+ if (directGetUpdateInfo) return context === void 0 ? await directGetUpdateInfo(args) : await directGetUpdateInfo(args, context);
116
119
  const channel = args.channel ?? "production";
117
120
  const minBundleId = args.minBundleId ?? NIL_UUID;
118
121
  const baseWhere = getBaseWhere({
package/dist/handler.cjs CHANGED
@@ -7,7 +7,7 @@ var HandlerBadRequestError = class extends Error {
7
7
  }
8
8
  };
9
9
  const handleVersion = async () => {
10
- return new Response(JSON.stringify({ version: "0.29.4" }), {
10
+ return new Response(JSON.stringify({ version: "0.29.6" }), {
11
11
  status: 200,
12
12
  headers: { "Content-Type": "application/json" }
13
13
  });
@@ -97,7 +97,13 @@ const handleGetBundles = async (_params, request, api, context) => {
97
97
  const channel = url.searchParams.get("channel") ?? void 0;
98
98
  const platform = url.searchParams.get("platform");
99
99
  const limit = Number(url.searchParams.get("limit")) || 50;
100
- const offset = Number(url.searchParams.get("offset")) || 0;
100
+ const pageParam = url.searchParams.get("page");
101
+ const offset = url.searchParams.get("offset");
102
+ const after = url.searchParams.get("after") ?? void 0;
103
+ const before = url.searchParams.get("before") ?? void 0;
104
+ const page = pageParam === null ? void 0 : Number.isInteger(Number(pageParam)) && Number(pageParam) > 0 ? Number(pageParam) : null;
105
+ if (offset !== null) throw new HandlerBadRequestError("The 'offset' query parameter has been removed. Use 'after' or 'before' cursor pagination instead.");
106
+ if (page === null) throw new HandlerBadRequestError("The 'page' query parameter must be a positive integer.");
101
107
  if (platform !== null && !isPlatform(platform)) throw new HandlerBadRequestError(`Invalid platform: ${platform}. Expected 'ios' or 'android'.`);
102
108
  const result = await api.getBundles({
103
109
  where: {
@@ -105,7 +111,11 @@ const handleGetBundles = async (_params, request, api, context) => {
105
111
  ...platform && { platform }
106
112
  },
107
113
  limit,
108
- offset
114
+ page,
115
+ cursor: after || before ? {
116
+ after,
117
+ before
118
+ } : void 0
109
119
  }, context);
110
120
  return new Response(JSON.stringify(result), {
111
121
  status: 200,
package/dist/handler.mjs CHANGED
@@ -7,7 +7,7 @@ var HandlerBadRequestError = class extends Error {
7
7
  }
8
8
  };
9
9
  const handleVersion = async () => {
10
- return new Response(JSON.stringify({ version: "0.29.4" }), {
10
+ return new Response(JSON.stringify({ version: "0.29.6" }), {
11
11
  status: 200,
12
12
  headers: { "Content-Type": "application/json" }
13
13
  });
@@ -97,7 +97,13 @@ const handleGetBundles = async (_params, request, api, context) => {
97
97
  const channel = url.searchParams.get("channel") ?? void 0;
98
98
  const platform = url.searchParams.get("platform");
99
99
  const limit = Number(url.searchParams.get("limit")) || 50;
100
- const offset = Number(url.searchParams.get("offset")) || 0;
100
+ const pageParam = url.searchParams.get("page");
101
+ const offset = url.searchParams.get("offset");
102
+ const after = url.searchParams.get("after") ?? void 0;
103
+ const before = url.searchParams.get("before") ?? void 0;
104
+ const page = pageParam === null ? void 0 : Number.isInteger(Number(pageParam)) && Number(pageParam) > 0 ? Number(pageParam) : null;
105
+ if (offset !== null) throw new HandlerBadRequestError("The 'offset' query parameter has been removed. Use 'after' or 'before' cursor pagination instead.");
106
+ if (page === null) throw new HandlerBadRequestError("The 'page' query parameter must be a positive integer.");
101
107
  if (platform !== null && !isPlatform(platform)) throw new HandlerBadRequestError(`Invalid platform: ${platform}. Expected 'ios' or 'android'.`);
102
108
  const result = await api.getBundles({
103
109
  where: {
@@ -105,7 +111,11 @@ const handleGetBundles = async (_params, request, api, context) => {
105
111
  ...platform && { platform }
106
112
  },
107
113
  limit,
108
- offset
114
+ page,
115
+ cursor: after || before ? {
116
+ after,
117
+ before
118
+ } : void 0
109
119
  }, context);
110
120
  return new Response(JSON.stringify(result), {
111
121
  status: 200,
@@ -8,6 +8,8 @@ interface PaginationInfo {
8
8
  hasPreviousPage: boolean;
9
9
  currentPage: number;
10
10
  totalPages: number;
11
+ nextCursor?: string | null;
12
+ previousCursor?: string | null;
11
13
  }
12
14
  interface PaginationOptions {
13
15
  limit: number;
@@ -8,6 +8,8 @@ interface PaginationInfo {
8
8
  hasPreviousPage: boolean;
9
9
  currentPage: number;
10
10
  totalPages: number;
11
+ nextCursor?: string | null;
12
+ previousCursor?: string | null;
11
13
  }
12
14
  interface PaginationOptions {
13
15
  limit: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hot-updater/server",
3
- "version": "0.29.4",
3
+ "version": "0.29.6",
4
4
  "type": "module",
5
5
  "description": "React Native OTA solution for self-hosted",
6
6
  "sideEffects": false,
@@ -53,9 +53,9 @@
53
53
  "fumadb": "0.2.2",
54
54
  "rou3": "0.7.9",
55
55
  "semver": "^7.7.2",
56
- "@hot-updater/plugin-core": "0.29.4",
57
- "@hot-updater/core": "0.29.4",
58
- "@hot-updater/js": "0.29.4"
56
+ "@hot-updater/plugin-core": "0.29.6",
57
+ "@hot-updater/js": "0.29.6",
58
+ "@hot-updater/core": "0.29.6"
59
59
  },
60
60
  "devDependencies": {
61
61
  "@electric-sql/pglite": "^0.2.17",
@@ -66,8 +66,8 @@
66
66
  "kysely-pglite-dialect": "^1.2.0",
67
67
  "msw": "^2.7.0",
68
68
  "uuidv7": "^1.0.2",
69
- "@hot-updater/standalone": "0.29.4",
70
- "@hot-updater/test-utils": "0.29.4"
69
+ "@hot-updater/test-utils": "0.29.6",
70
+ "@hot-updater/standalone": "0.29.6"
71
71
  },
72
72
  "scripts": {
73
73
  "build": "tsdown",