@hot-updater/cloudflare 1.1.3 → 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.
- package/dist/index.cjs +6 -85
- package/dist/index.d.cts +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +7 -86
- package/dist/worker/index.cjs +39 -0
- package/dist/worker/index.d.cts +3 -2
- package/dist/worker/index.d.mts +3 -2
- package/dist/worker/index.mjs +39 -0
- package/package.json +10 -9
- package/src/r2S3Storage.ts +14 -139
- package/src/r2Storage.ts +2 -3
- package/src/r2WorkerStorage.ts +56 -3
- package/worker/dist/README.md +1 -1
- package/worker/dist/index.js +43 -1
- package/worker/dist/index.js.map +3 -3
package/src/r2WorkerStorage.ts
CHANGED
|
@@ -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<
|
|
53
|
+
): StorageAdapterWith<R2WorkerOperations | "getDownloadUrl">;
|
|
43
54
|
export function r2WorkerStorage(
|
|
44
55
|
config: CloudflareWorkerStorageConfig,
|
|
45
|
-
): StorageAdapterWith<
|
|
56
|
+
): StorageAdapterWith<R2WorkerOperations>;
|
|
46
57
|
export function r2WorkerStorage(
|
|
47
58
|
config: CloudflareWorkerStorageConfig,
|
|
48
|
-
): StorageAdapterWith<
|
|
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
|
}
|
package/worker/dist/README.md
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
This folder contains the built output assets for the worker "hot-updater" generated at 2026-10-
|
|
1
|
+
This folder contains the built output assets for the worker "hot-updater" generated at 2026-10-29T12:33:57.070Z.
|
package/worker/dist/index.js
CHANGED
|
@@ -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.
|
|
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
|
}
|