@hot-updater/cloudflare 1.1.4 → 1.1.5

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.
@@ -4,6 +4,7 @@ import {
4
4
  createStorageUri,
5
5
  parseStorageUri,
6
6
  type StorageAdapterWith,
7
+ type StorageObject,
7
8
  } from "@hot-updater/plugin-core";
8
9
 
9
10
  import { presignR2GetUrl, type R2Credentials } from "./presignR2Url";
@@ -28,6 +29,16 @@ export type CloudflareWorkerStorageConfig = {
28
29
 
29
30
  /** Devices download right after the update check that returns the URL. */
30
31
  const PRESIGNED_URL_EXPIRES_IN_SECONDS = 3600;
32
+ /** Keys the binding deletes in one call. */
33
+ const DELETE_BATCH_SIZE = 1000;
34
+
35
+ type R2WorkerOperations =
36
+ | "put"
37
+ | "get"
38
+ | "exists"
39
+ | "delete"
40
+ | "listObjects"
41
+ | "deleteObjects";
31
42
 
32
43
  /**
33
44
  * Storage on the Worker's R2 binding. With R2's S3-compatible credentials,
@@ -39,14 +50,15 @@ export function r2WorkerStorage(
39
50
  config: CloudflareWorkerStorageConfig & {
40
51
  readonly credentials: R2Credentials;
41
52
  },
42
- ): StorageAdapterWith<"put" | "get" | "getDownloadUrl" | "exists" | "delete">;
53
+ ): StorageAdapterWith<R2WorkerOperations | "getDownloadUrl">;
43
54
  export function r2WorkerStorage(
44
55
  config: CloudflareWorkerStorageConfig,
45
- ): StorageAdapterWith<"put" | "get" | "exists" | "delete">;
56
+ ): StorageAdapterWith<R2WorkerOperations>;
46
57
  export function r2WorkerStorage(
47
58
  config: CloudflareWorkerStorageConfig,
48
- ): StorageAdapterWith<"put" | "get" | "exists" | "delete"> {
59
+ ): StorageAdapterWith<R2WorkerOperations> {
49
60
  const getStorageKey = createStorageKeyBuilder(config.basePath);
61
+ const basePrefix = getStorageKey() ? `${getStorageKey()}/` : "";
50
62
 
51
63
  const parseAndValidate = (storageUri: string) => {
52
64
  const parsed = parseStorageUri(storageUri, "r2");
@@ -128,5 +140,46 @@ export function r2WorkerStorage(
128
140
  await config.bucket.delete(key);
129
141
  return { deleted: true };
130
142
  },
143
+ async listObjects(prefix) {
144
+ const folder = getStorageKey(prefix ?? "");
145
+ const objects: StorageObject[] = [];
146
+ let cursor: string | undefined;
147
+ do {
148
+ const listed = await config.bucket.list({
149
+ prefix: folder ? `${folder}/` : "",
150
+ ...(cursor === undefined ? {} : { cursor }),
151
+ });
152
+ for (const object of listed.objects) {
153
+ if (!object.key.startsWith(basePrefix)) continue;
154
+ // A key no `put` writes, such as a folder marker, has no URI.
155
+ let storageUri: string;
156
+ try {
157
+ storageUri = createStorageUri({
158
+ protocol: "r2",
159
+ bucket: config.bucketName,
160
+ key: object.key,
161
+ });
162
+ } catch {
163
+ continue;
164
+ }
165
+ objects.push({
166
+ key: object.key.slice(basePrefix.length),
167
+ lastModifiedAt: object.uploaded,
168
+ size: object.size,
169
+ storageUri,
170
+ });
171
+ }
172
+ cursor = listed.truncated ? listed.cursor : undefined;
173
+ } while (cursor !== undefined);
174
+ return objects;
175
+ },
176
+ async deleteObjects(relativeKeys) {
177
+ const keys = relativeKeys.map((key) => getStorageKey(key));
178
+ for (let offset = 0; offset < keys.length; offset += DELETE_BATCH_SIZE) {
179
+ await config.bucket.delete(
180
+ keys.slice(offset, offset + DELETE_BATCH_SIZE),
181
+ );
182
+ }
183
+ },
131
184
  });
132
185
  }
@@ -1 +1 @@
1
- This folder contains the built output assets for the worker "hot-updater" generated at 2026-10-27T13:22:06.921Z.
1
+ This folder contains the built output assets for the worker "hot-updater" generated at 2026-10-29T12:33:57.070Z.
@@ -4512,7 +4512,7 @@ var createSqlAdapter = /* @__PURE__ */ __name(({ executor, tablePrefix = "", max
4512
4512
  }, "createSqlAdapter");
4513
4513
 
4514
4514
  // ../../packages/server/dist/package.mjs
4515
- var version = "1.1.4";
4515
+ var version = "1.1.5";
4516
4516
 
4517
4517
  // ../../packages/server/dist/version.mjs
4518
4518
  var HOT_UPDATER_SERVER_VERSION = version;
@@ -13243,8 +13243,10 @@ var presignR2GetUrl = /* @__PURE__ */ __name(async ({
13243
13243
 
13244
13244
  // src/r2WorkerStorage.ts
13245
13245
  var PRESIGNED_URL_EXPIRES_IN_SECONDS = 3600;
13246
+ var DELETE_BATCH_SIZE = 1e3;
13246
13247
  function r2WorkerStorage(config) {
13247
13248
  const getStorageKey = createStorageKeyBuilder(config.basePath);
13249
+ const basePrefix = getStorageKey() ? `${getStorageKey()}/` : "";
13248
13250
  const parseAndValidate = /* @__PURE__ */ __name((storageUri) => {
13249
13251
  const parsed = parseStorageUri(storageUri, "r2");
13250
13252
  if (parsed.bucket !== config.bucketName) {
@@ -13321,6 +13323,46 @@ function r2WorkerStorage(config) {
13321
13323
  const { key } = parseAndValidate(storageUri);
13322
13324
  await config.bucket.delete(key);
13323
13325
  return { deleted: true };
13326
+ },
13327
+ async listObjects(prefix) {
13328
+ const folder = getStorageKey(prefix ?? "");
13329
+ const objects = [];
13330
+ let cursor;
13331
+ do {
13332
+ const listed2 = await config.bucket.list({
13333
+ prefix: folder ? `${folder}/` : "",
13334
+ ...cursor === void 0 ? {} : { cursor }
13335
+ });
13336
+ for (const object of listed2.objects) {
13337
+ if (!object.key.startsWith(basePrefix)) continue;
13338
+ let storageUri;
13339
+ try {
13340
+ storageUri = createStorageUri({
13341
+ protocol: "r2",
13342
+ bucket: config.bucketName,
13343
+ key: object.key
13344
+ });
13345
+ } catch {
13346
+ continue;
13347
+ }
13348
+ objects.push({
13349
+ key: object.key.slice(basePrefix.length),
13350
+ lastModifiedAt: object.uploaded,
13351
+ size: object.size,
13352
+ storageUri
13353
+ });
13354
+ }
13355
+ cursor = listed2.truncated ? listed2.cursor : void 0;
13356
+ } while (cursor !== void 0);
13357
+ return objects;
13358
+ },
13359
+ async deleteObjects(relativeKeys) {
13360
+ const keys = relativeKeys.map((key) => getStorageKey(key));
13361
+ for (let offset = 0; offset < keys.length; offset += DELETE_BATCH_SIZE) {
13362
+ await config.bucket.delete(
13363
+ keys.slice(offset, offset + DELETE_BATCH_SIZE)
13364
+ );
13365
+ }
13324
13366
  }
13325
13367
  });
13326
13368
  }