@hot-updater/cloudflare 0.29.2 → 0.29.3

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.
package/dist/index.cjs CHANGED
@@ -378,7 +378,6 @@ function transformRowToBundle(row) {
378
378
  const d1Database = (0, _hot_updater_plugin_core.createDatabasePlugin)({
379
379
  name: "d1Database",
380
380
  factory: (config) => {
381
- let bundles = [];
382
381
  const cf = new cloudflare.default({ apiToken: config.cloudflareApiToken });
383
382
  async function getTotalCount(conditions) {
384
383
  const { sql: whereClause, params } = buildWhereClause(conditions);
@@ -407,8 +406,6 @@ const d1Database = (0, _hot_updater_plugin_core.createDatabasePlugin)({
407
406
  }
408
407
  return {
409
408
  async getBundleById(bundleId) {
410
- const found = bundles.find((b) => b.id === bundleId);
411
- if (found) return found;
412
409
  const sql = (0, import_lib.default)(`
413
410
  SELECT * FROM bundles WHERE id = ? LIMIT 1`);
414
411
  const rows = await resolvePage(await cf.d1.database.query(config.databaseId, {
@@ -422,14 +419,12 @@ const d1Database = (0, _hot_updater_plugin_core.createDatabasePlugin)({
422
419
  async getBundles(options) {
423
420
  const { where = {}, limit, offset, orderBy } = options;
424
421
  const totalCount = await getTotalCount(where);
425
- bundles = await getPaginatedBundles(where, limit, offset, orderBy);
426
- const pagination = (0, _hot_updater_plugin_core.calculatePagination)(totalCount, {
427
- limit,
428
- offset
429
- });
430
422
  return {
431
- data: bundles,
432
- pagination
423
+ data: await getPaginatedBundles(where, limit, offset, orderBy),
424
+ pagination: (0, _hot_updater_plugin_core.calculatePagination)(totalCount, {
425
+ limit,
426
+ offset
427
+ })
433
428
  };
434
429
  },
435
430
  async getChannels() {
@@ -453,7 +448,6 @@ const d1Database = (0, _hot_updater_plugin_core.createDatabasePlugin)({
453
448
  sql: deleteSql,
454
449
  params: [op.data.id]
455
450
  });
456
- bundles = bundles.filter((b) => b.id !== op.data.id);
457
451
  } else if (op.operation === "insert" || op.operation === "update") {
458
452
  const bundle = op.data;
459
453
  const upsertSql = (0, import_lib.default)(`
package/dist/index.mjs CHANGED
@@ -374,7 +374,6 @@ function transformRowToBundle(row) {
374
374
  const d1Database = createDatabasePlugin({
375
375
  name: "d1Database",
376
376
  factory: (config) => {
377
- let bundles = [];
378
377
  const cf = new Cloudflare({ apiToken: config.cloudflareApiToken });
379
378
  async function getTotalCount(conditions) {
380
379
  const { sql: whereClause, params } = buildWhereClause(conditions);
@@ -403,8 +402,6 @@ const d1Database = createDatabasePlugin({
403
402
  }
404
403
  return {
405
404
  async getBundleById(bundleId) {
406
- const found = bundles.find((b) => b.id === bundleId);
407
- if (found) return found;
408
405
  const sql = (0, import_lib.default)(`
409
406
  SELECT * FROM bundles WHERE id = ? LIMIT 1`);
410
407
  const rows = await resolvePage(await cf.d1.database.query(config.databaseId, {
@@ -418,14 +415,12 @@ const d1Database = createDatabasePlugin({
418
415
  async getBundles(options) {
419
416
  const { where = {}, limit, offset, orderBy } = options;
420
417
  const totalCount = await getTotalCount(where);
421
- bundles = await getPaginatedBundles(where, limit, offset, orderBy);
422
- const pagination = calculatePagination(totalCount, {
423
- limit,
424
- offset
425
- });
426
418
  return {
427
- data: bundles,
428
- pagination
419
+ data: await getPaginatedBundles(where, limit, offset, orderBy),
420
+ pagination: calculatePagination(totalCount, {
421
+ limit,
422
+ offset
423
+ })
429
424
  };
430
425
  },
431
426
  async getChannels() {
@@ -449,7 +444,6 @@ const d1Database = createDatabasePlugin({
449
444
  sql: deleteSql,
450
445
  params: [op.data.id]
451
446
  });
452
- bundles = bundles.filter((b) => b.id !== op.data.id);
453
447
  } else if (op.operation === "insert" || op.operation === "update") {
454
448
  const bundle = op.data;
455
449
  const upsertSql = (0, import_lib.default)(`
@@ -105,7 +105,6 @@ const resolveDbFromContext = (context) => {
105
105
  const d1WorkerDatabase = () => (0, _hot_updater_plugin_core.createDatabasePlugin)({
106
106
  name: "d1WorkerDatabase",
107
107
  factory: (config) => {
108
- let bundles = [];
109
108
  const queryAll = async (sql, params = [], context) => {
110
109
  return (await config.getDb(context).prepare(sql).bind(...params).all()).results ?? [];
111
110
  };
@@ -114,8 +113,6 @@ const d1WorkerDatabase = () => (0, _hot_updater_plugin_core.createDatabasePlugin
114
113
  };
115
114
  return {
116
115
  async getBundleById(bundleId, context) {
117
- const found = bundles.find((bundle) => bundle.id === bundleId);
118
- if (found) return found;
119
116
  const row = await queryFirst("SELECT * FROM bundles WHERE id = ? LIMIT 1", [bundleId], context);
120
117
  return row ? transformRowToBundle(row) : null;
121
118
  },
@@ -124,13 +121,12 @@ const d1WorkerDatabase = () => (0, _hot_updater_plugin_core.createDatabasePlugin
124
121
  const { sql: whereClause, params } = buildWhereClause(where);
125
122
  const orderSql = orderBy?.direction === "asc" ? "ORDER BY id ASC" : "ORDER BY id DESC";
126
123
  const total = (await queryAll(`SELECT COUNT(*) as total FROM bundles${whereClause}`, params, context))[0]?.total ?? 0;
127
- bundles = (await queryAll(`SELECT * FROM bundles${whereClause} ${orderSql} LIMIT ? OFFSET ?`, [
128
- ...params,
129
- limit,
130
- offset
131
- ], context)).map(transformRowToBundle);
132
124
  return {
133
- data: bundles,
125
+ data: (await queryAll(`SELECT * FROM bundles${whereClause} ${orderSql} LIMIT ? OFFSET ?`, [
126
+ ...params,
127
+ limit,
128
+ offset
129
+ ], context)).map(transformRowToBundle),
134
130
  pagination: (0, _hot_updater_plugin_core.calculatePagination)(total, {
135
131
  limit,
136
132
  offset
@@ -146,7 +142,6 @@ const d1WorkerDatabase = () => (0, _hot_updater_plugin_core.createDatabasePlugin
146
142
  for (const operation of changedSets) {
147
143
  if (operation.operation === "delete") {
148
144
  await db.prepare("DELETE FROM bundles WHERE id = ?").bind(operation.data.id).run();
149
- bundles = bundles.filter((bundle) => bundle.id !== operation.data.id);
150
145
  continue;
151
146
  }
152
147
  const bundle = operation.data;
@@ -104,7 +104,6 @@ const resolveDbFromContext = (context) => {
104
104
  const d1WorkerDatabase = () => createDatabasePlugin({
105
105
  name: "d1WorkerDatabase",
106
106
  factory: (config) => {
107
- let bundles = [];
108
107
  const queryAll = async (sql, params = [], context) => {
109
108
  return (await config.getDb(context).prepare(sql).bind(...params).all()).results ?? [];
110
109
  };
@@ -113,8 +112,6 @@ const d1WorkerDatabase = () => createDatabasePlugin({
113
112
  };
114
113
  return {
115
114
  async getBundleById(bundleId, context) {
116
- const found = bundles.find((bundle) => bundle.id === bundleId);
117
- if (found) return found;
118
115
  const row = await queryFirst("SELECT * FROM bundles WHERE id = ? LIMIT 1", [bundleId], context);
119
116
  return row ? transformRowToBundle(row) : null;
120
117
  },
@@ -123,13 +120,12 @@ const d1WorkerDatabase = () => createDatabasePlugin({
123
120
  const { sql: whereClause, params } = buildWhereClause(where);
124
121
  const orderSql = orderBy?.direction === "asc" ? "ORDER BY id ASC" : "ORDER BY id DESC";
125
122
  const total = (await queryAll(`SELECT COUNT(*) as total FROM bundles${whereClause}`, params, context))[0]?.total ?? 0;
126
- bundles = (await queryAll(`SELECT * FROM bundles${whereClause} ${orderSql} LIMIT ? OFFSET ?`, [
127
- ...params,
128
- limit,
129
- offset
130
- ], context)).map(transformRowToBundle);
131
123
  return {
132
- data: bundles,
124
+ data: (await queryAll(`SELECT * FROM bundles${whereClause} ${orderSql} LIMIT ? OFFSET ?`, [
125
+ ...params,
126
+ limit,
127
+ offset
128
+ ], context)).map(transformRowToBundle),
133
129
  pagination: calculatePagination(total, {
134
130
  limit,
135
131
  offset
@@ -145,7 +141,6 @@ const d1WorkerDatabase = () => createDatabasePlugin({
145
141
  for (const operation of changedSets) {
146
142
  if (operation.operation === "delete") {
147
143
  await db.prepare("DELETE FROM bundles WHERE id = ?").bind(operation.data.id).run();
148
- bundles = bundles.filter((bundle) => bundle.id !== operation.data.id);
149
144
  continue;
150
145
  }
151
146
  const bundle = operation.data;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@hot-updater/cloudflare",
3
3
  "type": "module",
4
- "version": "0.29.2",
4
+ "version": "0.29.3",
5
5
  "description": "React Native OTA solution for self-hosted",
6
6
  "main": "dist/index.cjs",
7
7
  "module": "dist/index.mjs",
@@ -50,11 +50,11 @@
50
50
  "cloudflare": "4.2.0",
51
51
  "hono": "4.12.9",
52
52
  "uuidv7": "^1.0.2",
53
- "@hot-updater/cli-tools": "0.29.2",
54
- "@hot-updater/core": "0.29.2",
55
- "@hot-updater/js": "0.29.2",
56
- "@hot-updater/plugin-core": "0.29.2",
57
- "@hot-updater/server": "0.29.2"
53
+ "@hot-updater/core": "0.29.3",
54
+ "@hot-updater/plugin-core": "0.29.3",
55
+ "@hot-updater/server": "0.29.3",
56
+ "@hot-updater/cli-tools": "0.29.3",
57
+ "@hot-updater/js": "0.29.3"
58
58
  },
59
59
  "devDependencies": {
60
60
  "@cloudflare/vitest-pool-workers": "0.13.0",
@@ -71,7 +71,7 @@
71
71
  "vitest": "4.1.0",
72
72
  "wrangler": "^4.5.0",
73
73
  "xdg-app-paths": "^8.3.0",
74
- "@hot-updater/test-utils": "0.29.2"
74
+ "@hot-updater/test-utils": "0.29.3"
75
75
  },
76
76
  "scripts": {
77
77
  "build": "tsdown && pnpm build:worker",
@@ -209,8 +209,6 @@ export const d1WorkerDatabase = <
209
209
  createDatabasePlugin<CloudflareWorkerDatabaseConfig<TContext>, TContext>({
210
210
  name: "d1WorkerDatabase",
211
211
  factory: (config) => {
212
- let bundles: Bundle[] = [];
213
-
214
212
  const queryAll = async <TRow>(
215
213
  sql: string,
216
214
  params: unknown[] = [],
@@ -239,11 +237,6 @@ export const d1WorkerDatabase = <
239
237
 
240
238
  return {
241
239
  async getBundleById(bundleId, context) {
242
- const found = bundles.find((bundle) => bundle.id === bundleId);
243
- if (found) {
244
- return found;
245
- }
246
-
247
240
  const row = await queryFirst<SnakeCaseBundle>(
248
241
  "SELECT * FROM bundles WHERE id = ? LIMIT 1",
249
242
  [bundleId],
@@ -274,7 +267,7 @@ export const d1WorkerDatabase = <
274
267
  context,
275
268
  );
276
269
 
277
- bundles = rows.map(transformRowToBundle);
270
+ const bundles = rows.map(transformRowToBundle);
278
271
 
279
272
  const paginationOptions: PaginationOptions = { limit, offset };
280
273
  return {
@@ -305,9 +298,6 @@ export const d1WorkerDatabase = <
305
298
  .prepare("DELETE FROM bundles WHERE id = ?")
306
299
  .bind(operation.data.id)
307
300
  .run();
308
- bundles = bundles.filter(
309
- (bundle) => bundle.id !== operation.data.id,
310
- );
311
301
  continue;
312
302
  }
313
303
 
@@ -1,6 +1,6 @@
1
1
  import type { DatabasePlugin } from "@hot-updater/plugin-core";
2
2
  import { setupBundleMethodsTestSuite } from "@hot-updater/test-utils";
3
- import { beforeEach, describe, vi } from "vitest";
3
+ import { beforeEach, describe, expect, it, vi } from "vitest";
4
4
  import { d1Database } from "./d1Database";
5
5
 
6
6
  type D1Row = {
@@ -40,6 +40,18 @@ const getFilteredRows = (sql: string, params: any[]) => {
40
40
  let filteredRows = Array.from(rows.values());
41
41
  let index = 0;
42
42
 
43
+ const consumeInValues = (pattern: RegExp) => {
44
+ const match = sql.match(pattern);
45
+ if (!match) {
46
+ return null;
47
+ }
48
+
49
+ const count = (match[1]?.match(/\?/g) ?? []).length;
50
+ const values = params.slice(index, index + count);
51
+ index += count;
52
+ return values;
53
+ };
54
+
43
55
  if (sql.includes("channel = ?")) {
44
56
  const channel = params[index++];
45
57
  filteredRows = filteredRows.filter((row) => row.channel === channel);
@@ -50,6 +62,78 @@ const getFilteredRows = (sql: string, params: any[]) => {
50
62
  filteredRows = filteredRows.filter((row) => row.platform === platform);
51
63
  }
52
64
 
65
+ if (sql.includes("enabled = ?")) {
66
+ const enabled = Number(params[index++]);
67
+ filteredRows = filteredRows.filter(
68
+ (row) => Number(row.enabled) === enabled,
69
+ );
70
+ }
71
+
72
+ const idInValues = consumeInValues(/id IN \(([^)]+)\)/);
73
+ if (idInValues) {
74
+ filteredRows = filteredRows.filter((row) => idInValues.includes(row.id));
75
+ }
76
+
77
+ if (sql.includes("id = ?")) {
78
+ const id = params[index++];
79
+ filteredRows = filteredRows.filter((row) => row.id === id);
80
+ }
81
+
82
+ if (sql.includes("id > ?")) {
83
+ const id = params[index++];
84
+ filteredRows = filteredRows.filter((row) => row.id.localeCompare(id) > 0);
85
+ }
86
+
87
+ if (sql.includes("id >= ?")) {
88
+ const id = params[index++];
89
+ filteredRows = filteredRows.filter((row) => row.id.localeCompare(id) >= 0);
90
+ }
91
+
92
+ if (sql.includes("id < ?")) {
93
+ const id = params[index++];
94
+ filteredRows = filteredRows.filter((row) => row.id.localeCompare(id) < 0);
95
+ }
96
+
97
+ if (sql.includes("id <= ?")) {
98
+ const id = params[index++];
99
+ filteredRows = filteredRows.filter((row) => row.id.localeCompare(id) <= 0);
100
+ }
101
+
102
+ if (sql.includes("target_app_version IS NOT NULL")) {
103
+ filteredRows = filteredRows.filter(
104
+ (row) => row.target_app_version !== null,
105
+ );
106
+ }
107
+
108
+ if (sql.includes("target_app_version IS NULL")) {
109
+ filteredRows = filteredRows.filter(
110
+ (row) => row.target_app_version === null,
111
+ );
112
+ } else if (sql.includes("target_app_version = ?")) {
113
+ const targetAppVersion = params[index++];
114
+ filteredRows = filteredRows.filter(
115
+ (row) => row.target_app_version === targetAppVersion,
116
+ );
117
+ }
118
+
119
+ const targetAppVersionInValues = consumeInValues(
120
+ /target_app_version IN \(([^)]+)\)/,
121
+ );
122
+ if (targetAppVersionInValues) {
123
+ filteredRows = filteredRows.filter((row) =>
124
+ targetAppVersionInValues.includes(row.target_app_version),
125
+ );
126
+ }
127
+
128
+ if (sql.includes("fingerprint_hash IS NULL")) {
129
+ filteredRows = filteredRows.filter((row) => row.fingerprint_hash === null);
130
+ } else if (sql.includes("fingerprint_hash = ?")) {
131
+ const fingerprintHash = params[index++];
132
+ filteredRows = filteredRows.filter(
133
+ (row) => row.fingerprint_hash === fingerprintHash,
134
+ );
135
+ }
136
+
53
137
  return { filteredRows, index };
54
138
  };
55
139
 
@@ -170,4 +254,44 @@ describe("d1Database plugin", () => {
170
254
  await plugin.commitBundle();
171
255
  },
172
256
  });
257
+
258
+ it("refreshes bundle data before merging an update after a previous list request", async () => {
259
+ const bundleId = "bundle-stale-cache";
260
+ const initialRow: D1Row = {
261
+ id: bundleId,
262
+ channel: "production",
263
+ enabled: 1,
264
+ should_force_update: 0,
265
+ file_hash: "hash-1",
266
+ git_commit_hash: "commit-1",
267
+ message: "stale message",
268
+ platform: "ios",
269
+ target_app_version: "1.0.0",
270
+ storage_uri: "s3://bucket/stale.zip",
271
+ fingerprint_hash: null,
272
+ metadata: JSON.stringify({ source: "initial" }),
273
+ rollout_cohort_count: 1000,
274
+ target_cohorts: null,
275
+ };
276
+ rows.set(bundleId, initialRow);
277
+
278
+ await plugin.getBundles({ limit: 20, offset: 0 });
279
+
280
+ rows.set(bundleId, {
281
+ ...initialRow,
282
+ message: "fresh message",
283
+ metadata: JSON.stringify({ source: "fresh" }),
284
+ });
285
+
286
+ await plugin.updateBundle(bundleId, { enabled: false });
287
+ await plugin.commitBundle();
288
+
289
+ expect(rows.get(bundleId)).toEqual(
290
+ expect.objectContaining({
291
+ enabled: 0,
292
+ message: "fresh message",
293
+ metadata: JSON.stringify({ source: "fresh" }),
294
+ }),
295
+ );
296
+ });
173
297
  });
package/src/d1Database.ts CHANGED
@@ -176,7 +176,6 @@ function transformRowToBundle(row: SnakeCaseBundle): Bundle {
176
176
  export const d1Database = createDatabasePlugin<D1DatabaseConfig>({
177
177
  name: "d1Database",
178
178
  factory: (config) => {
179
- let bundles: Bundle[] = [];
180
179
  const cf = new Cloudflare({
181
180
  apiToken: config.cloudflareApiToken,
182
181
  });
@@ -233,11 +232,6 @@ export const d1Database = createDatabasePlugin<D1DatabaseConfig>({
233
232
 
234
233
  return {
235
234
  async getBundleById(bundleId) {
236
- const found = bundles.find((b) => b.id === bundleId);
237
- if (found) {
238
- return found;
239
- }
240
-
241
235
  const sql = minify(/* sql */ `
242
236
  SELECT * FROM bundles WHERE id = ? LIMIT 1`);
243
237
  const singlePage = await cf.d1.database.query(config.databaseId, {
@@ -262,7 +256,12 @@ export const d1Database = createDatabasePlugin<D1DatabaseConfig>({
262
256
  const totalCount = await getTotalCount(where);
263
257
 
264
258
  // 2. Get paginated bundles
265
- bundles = await getPaginatedBundles(where, limit, offset, orderBy);
259
+ const bundles = await getPaginatedBundles(
260
+ where,
261
+ limit,
262
+ offset,
263
+ orderBy,
264
+ );
266
265
 
267
266
  // 3. Calculate pagination metadata
268
267
  const paginationOptions: PaginationOptions = { limit, offset };
@@ -306,9 +305,6 @@ export const d1Database = createDatabasePlugin<D1DatabaseConfig>({
306
305
  sql: deleteSql,
307
306
  params: [op.data.id],
308
307
  });
309
-
310
- // Update local bundles array
311
- bundles = bundles.filter((b) => b.id !== op.data.id);
312
308
  } else if (op.operation === "insert" || op.operation === "update") {
313
309
  // Handle insert and update operations
314
310
  const bundle = op.data;
@@ -1 +1 @@
1
- This folder contains the built output assets for the worker "hot-updater" generated at 2026-04-03T14:22:57.023Z.
1
+ This folder contains the built output assets for the worker "hot-updater" generated at 2026-04-04T12:00:04.101Z.
@@ -3326,12 +3326,12 @@ function mergeBundleUpdate(baseBundle, patch) {
3326
3326
  __name(mergeBundleUpdate, "mergeBundleUpdate");
3327
3327
  function createDatabasePlugin(options) {
3328
3328
  return (config2, hooks) => {
3329
+ let cachedMethods = null;
3330
+ const getMethods = /* @__PURE__ */ __name(() => {
3331
+ if (!cachedMethods) cachedMethods = options.factory(config2);
3332
+ return cachedMethods;
3333
+ }, "getMethods");
3329
3334
  return () => {
3330
- let cachedMethods = null;
3331
- const getMethods = /* @__PURE__ */ __name(() => {
3332
- if (!cachedMethods) cachedMethods = options.factory(config2);
3333
- return cachedMethods;
3334
- }, "getMethods");
3335
3335
  const changedMap = /* @__PURE__ */ new Map();
3336
3336
  const markChanged = /* @__PURE__ */ __name((operation, data) => {
3337
3337
  changedMap.set(data.id, {
@@ -3362,8 +3362,8 @@ function createDatabasePlugin(options) {
3362
3362
  const params = { changedSets: Array.from(changedMap.values()) };
3363
3363
  if (context2 === void 0) await methods.commitBundle(params);
3364
3364
  else await methods.commitBundle(params, context2);
3365
- await hooks?.onDatabaseUpdated?.();
3366
3365
  changedMap.clear();
3366
+ await hooks?.onDatabaseUpdated?.();
3367
3367
  },
3368
3368
  async updateBundle(targetBundleId, newBundle, context2) {
3369
3369
  const pendingChange = changedMap.get(targetBundleId);
@@ -3460,18 +3460,28 @@ var INIT_BUNDLE_ROLLBACK_UPDATE_INFO = {
3460
3460
  storageUri: null,
3461
3461
  fileHash: null
3462
3462
  };
3463
- function createPluginDatabaseCore(plugin, resolveFileUrl) {
3464
- const getSortedBundlePage = /* @__PURE__ */ __name(async (options, context2) => {
3465
- const result = await plugin.getBundles(
3463
+ function createPluginDatabaseCore(getPlugin, resolveFileUrl, options) {
3464
+ const runWithMutationPlugin = /* @__PURE__ */ __name(async (operation) => {
3465
+ const plugin = options?.createMutationPlugin?.() ?? getPlugin();
3466
+ try {
3467
+ return await operation(plugin);
3468
+ } finally {
3469
+ if (options?.createMutationPlugin) {
3470
+ await options.cleanupMutationPlugin?.(plugin);
3471
+ }
3472
+ }
3473
+ }, "runWithMutationPlugin");
3474
+ const getSortedBundlePage = /* @__PURE__ */ __name(async (options2, context2) => {
3475
+ const result = await getPlugin().getBundles(
3466
3476
  {
3467
- ...options,
3468
- orderBy: options.orderBy ?? DESC_ORDER
3477
+ ...options2,
3478
+ orderBy: options2.orderBy ?? DESC_ORDER
3469
3479
  },
3470
3480
  context2
3471
3481
  );
3472
3482
  return {
3473
3483
  ...result,
3474
- data: sortBundles(result.data, options.orderBy ?? DESC_ORDER)
3484
+ data: sortBundles(result.data, options2.orderBy ?? DESC_ORDER)
3475
3485
  };
3476
3486
  }, "getSortedBundlePage");
3477
3487
  const isEligibleForUpdate = /* @__PURE__ */ __name((bundle, cohort) => {
@@ -3551,7 +3561,7 @@ function createPluginDatabaseCore(plugin, resolveFileUrl) {
3551
3561
  }), "getBaseWhere");
3552
3562
  const api = {
3553
3563
  async getBundleById(id, context2) {
3554
- return plugin.getBundleById(id, context2);
3564
+ return getPlugin().getBundleById(id, context2);
3555
3565
  },
3556
3566
  async getUpdateInfo(args, context2) {
3557
3567
  const channel2 = args.channel ?? "production";
@@ -3595,31 +3605,37 @@ function createPluginDatabaseCore(plugin, resolveFileUrl) {
3595
3605
  return { ...rest, fileUrl };
3596
3606
  },
3597
3607
  async getChannels(context2) {
3598
- return plugin.getChannels(context2);
3608
+ return getPlugin().getChannels(context2);
3599
3609
  },
3600
- async getBundles(options, context2) {
3601
- return plugin.getBundles(options, context2);
3610
+ async getBundles(options2, context2) {
3611
+ return getPlugin().getBundles(options2, context2);
3602
3612
  },
3603
3613
  async insertBundle(bundle, context2) {
3604
- await plugin.appendBundle(bundle, context2);
3605
- await plugin.commitBundle(context2);
3614
+ await runWithMutationPlugin(async (plugin) => {
3615
+ await plugin.appendBundle(bundle, context2);
3616
+ await plugin.commitBundle(context2);
3617
+ });
3606
3618
  },
3607
3619
  async updateBundleById(bundleId, newBundle, context2) {
3608
- await plugin.updateBundle(bundleId, newBundle, context2);
3609
- await plugin.commitBundle(context2);
3620
+ await runWithMutationPlugin(async (plugin) => {
3621
+ await plugin.updateBundle(bundleId, newBundle, context2);
3622
+ await plugin.commitBundle(context2);
3623
+ });
3610
3624
  },
3611
3625
  async deleteBundleById(bundleId, context2) {
3612
- const bundle = await plugin.getBundleById(bundleId, context2);
3613
- if (!bundle) {
3614
- return;
3615
- }
3616
- await plugin.deleteBundle(bundle, context2);
3617
- await plugin.commitBundle(context2);
3626
+ await runWithMutationPlugin(async (plugin) => {
3627
+ const bundle = await plugin.getBundleById(bundleId, context2);
3628
+ if (!bundle) {
3629
+ return;
3630
+ }
3631
+ await plugin.deleteBundle(bundle, context2);
3632
+ await plugin.commitBundle(context2);
3633
+ });
3618
3634
  }
3619
3635
  };
3620
3636
  return {
3621
3637
  api,
3622
- adapterName: plugin.name,
3638
+ adapterName: getPlugin().name,
3623
3639
  createMigrator: /* @__PURE__ */ __name(() => {
3624
3640
  throw new Error(
3625
3641
  "createMigrator is only available for Kysely/Prisma/Drizzle database adapters."
@@ -3856,7 +3872,7 @@ var handleGetBundles = /* @__PURE__ */ __name(async (_params, request, api, cont
3856
3872
  },
3857
3873
  context2
3858
3874
  );
3859
- return new Response(JSON.stringify(result.data), {
3875
+ return new Response(JSON.stringify(result), {
3860
3876
  status: 200,
3861
3877
  headers: { "Content-Type": "application/json" }
3862
3878
  });
@@ -3893,7 +3909,12 @@ var handleDeleteBundle = /* @__PURE__ */ __name(async (params, _request, api, co
3893
3909
  }, "handleDeleteBundle");
3894
3910
  var handleGetChannels = /* @__PURE__ */ __name(async (_params, _request, api, context2) => {
3895
3911
  const channels = await api.getChannels(context2);
3896
- return new Response(JSON.stringify({ channels }), {
3912
+ const response = {
3913
+ data: {
3914
+ channels
3915
+ }
3916
+ };
3917
+ return new Response(JSON.stringify(response), {
3897
3918
  status: 200,
3898
3919
  headers: { "Content-Type": "application/json" }
3899
3920
  });
@@ -4006,6 +4027,7 @@ var normalizeBasePath = /* @__PURE__ */ __name((basePath) => {
4006
4027
 
4007
4028
  // ../../packages/server/src/runtime.ts
4008
4029
  function createHotUpdater(options) {
4030
+ const database = options.database;
4009
4031
  const basePath = normalizeBasePath(options.basePath ?? "/api");
4010
4032
  const storagePlugins = (options.storages ?? options.storagePlugins ?? []).map(
4011
4033
  (plugin2) => typeof plugin2 === "function" ? plugin2() : plugin2
@@ -4031,15 +4053,18 @@ function createHotUpdater(options) {
4031
4053
  }
4032
4054
  return fileUrl;
4033
4055
  }, "resolveStoragePluginUrl");
4034
- if (!isDatabasePluginFactory(options.database) && !isDatabasePlugin(options.database)) {
4056
+ if (!isDatabasePluginFactory(database) && !isDatabasePlugin(database)) {
4035
4057
  throw new Error(
4036
4058
  "@hot-updater/server/runtime only supports database plugins."
4037
4059
  );
4038
4060
  }
4039
- const plugin = isDatabasePluginFactory(options.database) ? options.database() : options.database;
4061
+ const plugin = isDatabasePluginFactory(database) ? database() : database;
4040
4062
  const core = createPluginDatabaseCore(
4041
- plugin,
4042
- resolveStoragePluginUrl
4063
+ () => plugin,
4064
+ resolveStoragePluginUrl,
4065
+ isDatabasePluginFactory(database) ? {
4066
+ createMutationPlugin: /* @__PURE__ */ __name(() => database(), "createMutationPlugin")
4067
+ } : void 0
4043
4068
  );
4044
4069
  const api = {
4045
4070
  ...core.api,
@@ -8828,7 +8853,6 @@ var resolveDbFromContext = /* @__PURE__ */ __name((context2) => {
8828
8853
  var d1WorkerDatabase = /* @__PURE__ */ __name(() => createDatabasePlugin({
8829
8854
  name: "d1WorkerDatabase",
8830
8855
  factory: /* @__PURE__ */ __name((config2) => {
8831
- let bundles = [];
8832
8856
  const queryAll = /* @__PURE__ */ __name(async (sql, params = [], context2) => {
8833
8857
  const result = await config2.getDb(context2).prepare(sql).bind(...params).all();
8834
8858
  return result.results ?? [];
@@ -8839,10 +8863,6 @@ var d1WorkerDatabase = /* @__PURE__ */ __name(() => createDatabasePlugin({
8839
8863
  }, "queryFirst");
8840
8864
  return {
8841
8865
  async getBundleById(bundleId, context2) {
8842
- const found = bundles.find((bundle) => bundle.id === bundleId);
8843
- if (found) {
8844
- return found;
8845
- }
8846
8866
  const row = await queryFirst(
8847
8867
  "SELECT * FROM bundles WHERE id = ? LIMIT 1",
8848
8868
  [bundleId],
@@ -8865,7 +8885,7 @@ var d1WorkerDatabase = /* @__PURE__ */ __name(() => createDatabasePlugin({
8865
8885
  [...params, limit, offset],
8866
8886
  context2
8867
8887
  );
8868
- bundles = rows.map(transformRowToBundle);
8888
+ const bundles = rows.map(transformRowToBundle);
8869
8889
  const paginationOptions = { limit, offset };
8870
8890
  return {
8871
8891
  data: bundles,
@@ -8888,9 +8908,6 @@ var d1WorkerDatabase = /* @__PURE__ */ __name(() => createDatabasePlugin({
8888
8908
  for (const operation of changedSets) {
8889
8909
  if (operation.operation === "delete") {
8890
8910
  await db.prepare("DELETE FROM bundles WHERE id = ?").bind(operation.data.id).run();
8891
- bundles = bundles.filter(
8892
- (bundle2) => bundle2.id !== operation.data.id
8893
- );
8894
8911
  continue;
8895
8912
  }
8896
8913
  const bundle = operation.data;