@hot-updater/cloudflare 0.29.5 → 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.
- package/dist/iac/index.cjs +7 -5
- package/dist/iac/index.mjs +8 -6
- package/dist/index.cjs +56 -1
- package/dist/index.mjs +57 -2
- package/dist/worker/index.cjs +46 -1
- package/dist/worker/index.mjs +47 -2
- package/package.json +7 -7
- package/src/cloudflareWorkerDatabase.ts +92 -1
- package/src/d1Database.spec.ts +35 -2
- package/src/d1Database.ts +89 -1
- package/worker/dist/README.md +1 -1
- package/worker/dist/index.js +386 -15
- package/worker/dist/index.js.map +4 -4
package/src/d1Database.ts
CHANGED
|
@@ -11,6 +11,7 @@ import type {
|
|
|
11
11
|
import {
|
|
12
12
|
calculatePagination,
|
|
13
13
|
createDatabasePlugin,
|
|
14
|
+
createDatabasePluginGetUpdateInfo,
|
|
14
15
|
} from "@hot-updater/plugin-core";
|
|
15
16
|
import Cloudflare from "cloudflare";
|
|
16
17
|
import minify from "pg-minify";
|
|
@@ -230,7 +231,90 @@ export const d1Database = createDatabasePlugin<D1DatabaseConfig>({
|
|
|
230
231
|
return rows.map(transformRowToBundle);
|
|
231
232
|
}
|
|
232
233
|
|
|
234
|
+
async function queryBundlesForUpdateInfo(
|
|
235
|
+
conditions: QueryConditions,
|
|
236
|
+
): Promise<Bundle[]> {
|
|
237
|
+
const { sql: whereClause, params } = buildWhereClause(conditions);
|
|
238
|
+
const sql = minify(`
|
|
239
|
+
SELECT * FROM bundles
|
|
240
|
+
${whereClause}
|
|
241
|
+
`);
|
|
242
|
+
|
|
243
|
+
const result = await cf.d1.database.query(config.databaseId, {
|
|
244
|
+
account_id: config.accountId,
|
|
245
|
+
sql,
|
|
246
|
+
params,
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
const rows = await resolvePage<SnakeCaseBundle>(result);
|
|
250
|
+
return rows.map(transformRowToBundle);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
async function getTargetAppVersionsForUpdateInfo({
|
|
254
|
+
platform,
|
|
255
|
+
channel,
|
|
256
|
+
minBundleId,
|
|
257
|
+
}: {
|
|
258
|
+
platform: Bundle["platform"];
|
|
259
|
+
channel: string;
|
|
260
|
+
minBundleId: string;
|
|
261
|
+
}): Promise<string[]> {
|
|
262
|
+
const sql = minify(`
|
|
263
|
+
SELECT target_app_version
|
|
264
|
+
FROM bundles
|
|
265
|
+
WHERE channel = ?
|
|
266
|
+
AND platform = ?
|
|
267
|
+
AND enabled = 1
|
|
268
|
+
AND id >= ?
|
|
269
|
+
AND target_app_version IS NOT NULL
|
|
270
|
+
GROUP BY target_app_version
|
|
271
|
+
`);
|
|
272
|
+
|
|
273
|
+
const result = await cf.d1.database.query(config.databaseId, {
|
|
274
|
+
account_id: config.accountId,
|
|
275
|
+
sql,
|
|
276
|
+
params: [channel, platform, minBundleId],
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
const rows = await resolvePage<{ target_app_version: string }>(result);
|
|
280
|
+
return rows.map((row) => row.target_app_version);
|
|
281
|
+
}
|
|
282
|
+
|
|
233
283
|
return {
|
|
284
|
+
getUpdateInfo: createDatabasePluginGetUpdateInfo({
|
|
285
|
+
listTargetAppVersions: getTargetAppVersionsForUpdateInfo,
|
|
286
|
+
getBundlesByTargetAppVersions(
|
|
287
|
+
{ platform, channel, minBundleId },
|
|
288
|
+
targetAppVersions,
|
|
289
|
+
) {
|
|
290
|
+
return queryBundlesForUpdateInfo({
|
|
291
|
+
enabled: true,
|
|
292
|
+
platform,
|
|
293
|
+
channel,
|
|
294
|
+
id: {
|
|
295
|
+
gte: minBundleId,
|
|
296
|
+
},
|
|
297
|
+
targetAppVersionIn: targetAppVersions,
|
|
298
|
+
});
|
|
299
|
+
},
|
|
300
|
+
getBundlesByFingerprint({
|
|
301
|
+
platform,
|
|
302
|
+
channel,
|
|
303
|
+
minBundleId,
|
|
304
|
+
fingerprintHash,
|
|
305
|
+
}) {
|
|
306
|
+
return queryBundlesForUpdateInfo({
|
|
307
|
+
enabled: true,
|
|
308
|
+
platform,
|
|
309
|
+
channel,
|
|
310
|
+
id: {
|
|
311
|
+
gte: minBundleId,
|
|
312
|
+
},
|
|
313
|
+
fingerprintHash,
|
|
314
|
+
});
|
|
315
|
+
},
|
|
316
|
+
}),
|
|
317
|
+
|
|
234
318
|
async getBundleById(bundleId) {
|
|
235
319
|
const sql = minify(/* sql */ `
|
|
236
320
|
SELECT * FROM bundles WHERE id = ? LIMIT 1`);
|
|
@@ -250,7 +334,11 @@ export const d1Database = createDatabasePlugin<D1DatabaseConfig>({
|
|
|
250
334
|
},
|
|
251
335
|
|
|
252
336
|
async getBundles(options) {
|
|
253
|
-
const { where = {}, limit,
|
|
337
|
+
const { where = {}, limit, orderBy } = options;
|
|
338
|
+
const offset =
|
|
339
|
+
(("offset" in options ? options.offset : undefined) as
|
|
340
|
+
| number
|
|
341
|
+
| undefined) ?? 0;
|
|
254
342
|
|
|
255
343
|
// 1. Get total count for pagination
|
|
256
344
|
const totalCount = await getTotalCount(where);
|
package/worker/dist/README.md
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
This folder contains the built output assets for the worker "hot-updater" generated at 2026-04-
|
|
1
|
+
This folder contains the built output assets for the worker "hot-updater" generated at 2026-04-09T04:37:25.139Z.
|
package/worker/dist/index.js
CHANGED
|
@@ -3318,12 +3318,78 @@ __name(mergeWith, "mergeWith");
|
|
|
3318
3318
|
|
|
3319
3319
|
// ../plugin-core/dist/createDatabasePlugin.mjs
|
|
3320
3320
|
var REPLACE_ON_UPDATE_KEYS = ["targetCohorts"];
|
|
3321
|
+
var DEFAULT_DESC_ORDER = {
|
|
3322
|
+
field: "id",
|
|
3323
|
+
direction: "desc"
|
|
3324
|
+
};
|
|
3325
|
+
function normalizePage(value) {
|
|
3326
|
+
if (!Number.isInteger(value) || value === void 0 || value < 1) return;
|
|
3327
|
+
return value;
|
|
3328
|
+
}
|
|
3329
|
+
__name(normalizePage, "normalizePage");
|
|
3321
3330
|
function mergeBundleUpdate(baseBundle, patch) {
|
|
3322
3331
|
return mergeWith(baseBundle, patch, (_targetValue, sourceValue, key) => {
|
|
3323
3332
|
if (REPLACE_ON_UPDATE_KEYS.includes(key)) return sourceValue;
|
|
3324
3333
|
});
|
|
3325
3334
|
}
|
|
3326
3335
|
__name(mergeBundleUpdate, "mergeBundleUpdate");
|
|
3336
|
+
function mergeIdFilter(base, patch) {
|
|
3337
|
+
return {
|
|
3338
|
+
...base,
|
|
3339
|
+
...patch
|
|
3340
|
+
};
|
|
3341
|
+
}
|
|
3342
|
+
__name(mergeIdFilter, "mergeIdFilter");
|
|
3343
|
+
function mergeWhereWithIdFilter(where, idFilter) {
|
|
3344
|
+
return {
|
|
3345
|
+
...where,
|
|
3346
|
+
id: mergeIdFilter(where?.id, idFilter)
|
|
3347
|
+
};
|
|
3348
|
+
}
|
|
3349
|
+
__name(mergeWhereWithIdFilter, "mergeWhereWithIdFilter");
|
|
3350
|
+
function buildCursorPageQuery(where, cursor, orderBy) {
|
|
3351
|
+
const direction = orderBy.direction;
|
|
3352
|
+
if (cursor.after) return {
|
|
3353
|
+
reverseData: false,
|
|
3354
|
+
where: mergeWhereWithIdFilter(where, { [direction === "desc" ? "lt" : "gt"]: cursor.after }),
|
|
3355
|
+
orderBy
|
|
3356
|
+
};
|
|
3357
|
+
if (cursor.before) return {
|
|
3358
|
+
reverseData: true,
|
|
3359
|
+
where: mergeWhereWithIdFilter(where, { [direction === "desc" ? "gt" : "lt"]: cursor.before }),
|
|
3360
|
+
orderBy: {
|
|
3361
|
+
field: orderBy.field,
|
|
3362
|
+
direction: direction === "desc" ? "asc" : "desc"
|
|
3363
|
+
}
|
|
3364
|
+
};
|
|
3365
|
+
return {
|
|
3366
|
+
reverseData: false,
|
|
3367
|
+
where: where ?? {},
|
|
3368
|
+
orderBy
|
|
3369
|
+
};
|
|
3370
|
+
}
|
|
3371
|
+
__name(buildCursorPageQuery, "buildCursorPageQuery");
|
|
3372
|
+
function buildCountBeforeWhere(where, firstBundleId, orderBy) {
|
|
3373
|
+
return mergeWhereWithIdFilter(where, { [orderBy.direction === "desc" ? "gt" : "lt"]: firstBundleId });
|
|
3374
|
+
}
|
|
3375
|
+
__name(buildCountBeforeWhere, "buildCountBeforeWhere");
|
|
3376
|
+
function createPaginatedResult(total, limit, startIndex, data) {
|
|
3377
|
+
const pagination = calculatePagination(total, {
|
|
3378
|
+
limit,
|
|
3379
|
+
offset: startIndex
|
|
3380
|
+
});
|
|
3381
|
+
const nextCursor = data.length > 0 && startIndex + data.length < total ? data.at(-1)?.id : void 0;
|
|
3382
|
+
const previousCursor = data.length > 0 && startIndex > 0 ? data[0]?.id : void 0;
|
|
3383
|
+
return {
|
|
3384
|
+
data,
|
|
3385
|
+
pagination: {
|
|
3386
|
+
...pagination,
|
|
3387
|
+
...nextCursor ? { nextCursor } : {},
|
|
3388
|
+
...previousCursor ? { previousCursor } : {}
|
|
3389
|
+
}
|
|
3390
|
+
};
|
|
3391
|
+
}
|
|
3392
|
+
__name(createPaginatedResult, "createPaginatedResult");
|
|
3327
3393
|
function createDatabasePlugin(options) {
|
|
3328
3394
|
return (config2, hooks) => {
|
|
3329
3395
|
let cachedMethods = null;
|
|
@@ -3339,6 +3405,59 @@ function createDatabasePlugin(options) {
|
|
|
3339
3405
|
data
|
|
3340
3406
|
});
|
|
3341
3407
|
}, "markChanged");
|
|
3408
|
+
const runGetBundles = /* @__PURE__ */ __name(async (options2, context2) => {
|
|
3409
|
+
if (context2 === void 0) return getMethods().getBundles(options2);
|
|
3410
|
+
return getMethods().getBundles(options2, context2);
|
|
3411
|
+
}, "runGetBundles");
|
|
3412
|
+
const getBundlesWithLegacyCursorFallback = /* @__PURE__ */ __name(async (options2, context2) => {
|
|
3413
|
+
const orderBy = options2.orderBy ?? DEFAULT_DESC_ORDER;
|
|
3414
|
+
const baseWhere = options2.where;
|
|
3415
|
+
const total = (await runGetBundles({
|
|
3416
|
+
where: baseWhere,
|
|
3417
|
+
limit: 1,
|
|
3418
|
+
offset: 0,
|
|
3419
|
+
orderBy
|
|
3420
|
+
}, context2)).pagination.total;
|
|
3421
|
+
if (!options2.cursor?.after && !options2.cursor?.before) {
|
|
3422
|
+
const firstPage = await runGetBundles({
|
|
3423
|
+
where: baseWhere,
|
|
3424
|
+
limit: options2.limit,
|
|
3425
|
+
offset: 0,
|
|
3426
|
+
orderBy
|
|
3427
|
+
}, context2);
|
|
3428
|
+
return createPaginatedResult(total, options2.limit, 0, firstPage.data);
|
|
3429
|
+
}
|
|
3430
|
+
const { where, orderBy: queryOrderBy, reverseData } = buildCursorPageQuery(baseWhere, options2.cursor, orderBy);
|
|
3431
|
+
const cursorPage = await runGetBundles({
|
|
3432
|
+
where,
|
|
3433
|
+
limit: options2.limit,
|
|
3434
|
+
offset: 0,
|
|
3435
|
+
orderBy: queryOrderBy
|
|
3436
|
+
}, context2);
|
|
3437
|
+
const data = reverseData ? cursorPage.data.slice().reverse() : cursorPage.data;
|
|
3438
|
+
if (data.length === 0) {
|
|
3439
|
+
const emptyStartIndex = options2.cursor.after ? total : 0;
|
|
3440
|
+
return {
|
|
3441
|
+
data,
|
|
3442
|
+
pagination: {
|
|
3443
|
+
...calculatePagination(total, {
|
|
3444
|
+
limit: options2.limit,
|
|
3445
|
+
offset: emptyStartIndex
|
|
3446
|
+
}),
|
|
3447
|
+
...options2.cursor.after ? { previousCursor: options2.cursor.after } : {},
|
|
3448
|
+
...options2.cursor.before ? { nextCursor: options2.cursor.before } : {}
|
|
3449
|
+
}
|
|
3450
|
+
};
|
|
3451
|
+
}
|
|
3452
|
+
const firstBundleId = data[0].id;
|
|
3453
|
+
const countBeforeResult = await runGetBundles({
|
|
3454
|
+
where: buildCountBeforeWhere(baseWhere, firstBundleId, orderBy),
|
|
3455
|
+
limit: 1,
|
|
3456
|
+
offset: 0,
|
|
3457
|
+
orderBy
|
|
3458
|
+
}, context2);
|
|
3459
|
+
return createPaginatedResult(total, options2.limit, countBeforeResult.pagination.total, data);
|
|
3460
|
+
}, "getBundlesWithLegacyCursorFallback");
|
|
3342
3461
|
const plugin = {
|
|
3343
3462
|
name: options.name,
|
|
3344
3463
|
async getBundleById(bundleId, context2) {
|
|
@@ -3346,8 +3465,35 @@ function createDatabasePlugin(options) {
|
|
|
3346
3465
|
return getMethods().getBundleById(bundleId, context2);
|
|
3347
3466
|
},
|
|
3348
3467
|
async getBundles(options2, context2) {
|
|
3349
|
-
if (
|
|
3350
|
-
|
|
3468
|
+
if (typeof options2 === "object" && options2 !== null && "offset" in options2 && options2.offset !== void 0) throw new Error("Bundle offset pagination has been removed. Use cursor.after or cursor.before instead.");
|
|
3469
|
+
const methods = getMethods();
|
|
3470
|
+
const normalizedOptions = {
|
|
3471
|
+
...options2,
|
|
3472
|
+
page: normalizePage(options2.page),
|
|
3473
|
+
orderBy: options2.orderBy ?? DEFAULT_DESC_ORDER
|
|
3474
|
+
};
|
|
3475
|
+
if (normalizedOptions.page !== void 0) {
|
|
3476
|
+
const { page, ...pageOptions } = normalizedOptions;
|
|
3477
|
+
const requestedOffset = (page - 1) * normalizedOptions.limit;
|
|
3478
|
+
let pageResult = await runGetBundles({
|
|
3479
|
+
...pageOptions,
|
|
3480
|
+
offset: requestedOffset
|
|
3481
|
+
}, context2);
|
|
3482
|
+
const total = pageResult.pagination.total;
|
|
3483
|
+
const totalPages = total === 0 ? 0 : Math.ceil(total / normalizedOptions.limit);
|
|
3484
|
+
const maxOffset = totalPages === 0 ? 0 : (Math.max(1, totalPages) - 1) * normalizedOptions.limit;
|
|
3485
|
+
const resolvedOffset = Math.min(requestedOffset, maxOffset);
|
|
3486
|
+
if (resolvedOffset !== requestedOffset) pageResult = await runGetBundles({
|
|
3487
|
+
...pageOptions,
|
|
3488
|
+
offset: resolvedOffset
|
|
3489
|
+
}, context2);
|
|
3490
|
+
return createPaginatedResult(total, normalizedOptions.limit, resolvedOffset, pageResult.data);
|
|
3491
|
+
}
|
|
3492
|
+
if (methods.supportsCursorPagination) {
|
|
3493
|
+
if (context2 === void 0) return methods.getBundles(normalizedOptions);
|
|
3494
|
+
return methods.getBundles(normalizedOptions, context2);
|
|
3495
|
+
}
|
|
3496
|
+
return getBundlesWithLegacyCursorFallback(normalizedOptions, context2);
|
|
3351
3497
|
},
|
|
3352
3498
|
async getChannels(context2) {
|
|
3353
3499
|
if (context2 === void 0) return getMethods().getChannels();
|
|
@@ -3428,6 +3574,14 @@ var semverSatisfies = /* @__PURE__ */ __name((targetAppVersion, currentVersion)
|
|
|
3428
3574
|
return import_semver.default.satisfies(currentCoerce.version, targetAppVersion);
|
|
3429
3575
|
}, "semverSatisfies");
|
|
3430
3576
|
|
|
3577
|
+
// ../plugin-core/dist/filterCompatibleAppVersions.mjs
|
|
3578
|
+
init_virtual_unenv_global_polyfill_cloudflare_unenv_preset_node_process();
|
|
3579
|
+
init_virtual_unenv_global_polyfill_cloudflare_unenv_preset_node_console();
|
|
3580
|
+
init_performance2();
|
|
3581
|
+
var filterCompatibleAppVersions = /* @__PURE__ */ __name((targetAppVersionList, currentVersion) => {
|
|
3582
|
+
return targetAppVersionList.filter((version2) => semverSatisfies(version2, currentVersion)).sort((a, b) => b.localeCompare(a));
|
|
3583
|
+
}, "filterCompatibleAppVersions");
|
|
3584
|
+
|
|
3431
3585
|
// ../js/dist/index.mjs
|
|
3432
3586
|
init_virtual_unenv_global_polyfill_cloudflare_unenv_preset_node_process();
|
|
3433
3587
|
init_virtual_unenv_global_polyfill_cloudflare_unenv_preset_node_console();
|
|
@@ -4716,6 +4870,107 @@ var import_semver2 = /* @__PURE__ */ __toESM2((/* @__PURE__ */ __commonJSMin((ex
|
|
|
4716
4870
|
rcompareIdentifiers: identifiers.rcompareIdentifiers
|
|
4717
4871
|
};
|
|
4718
4872
|
}))(), 1);
|
|
4873
|
+
var semverSatisfies2 = /* @__PURE__ */ __name((targetAppVersion, currentVersion) => {
|
|
4874
|
+
const currentCoerce = import_semver2.default.coerce(currentVersion);
|
|
4875
|
+
if (!currentCoerce) return false;
|
|
4876
|
+
return import_semver2.default.satisfies(currentCoerce.version, targetAppVersion);
|
|
4877
|
+
}, "semverSatisfies");
|
|
4878
|
+
var INIT_BUNDLE_ROLLBACK_UPDATE_INFO = {
|
|
4879
|
+
message: null,
|
|
4880
|
+
id: NIL_UUID,
|
|
4881
|
+
shouldForceUpdate: true,
|
|
4882
|
+
status: "ROLLBACK",
|
|
4883
|
+
storageUri: null,
|
|
4884
|
+
fileHash: null
|
|
4885
|
+
};
|
|
4886
|
+
var makeResponse = /* @__PURE__ */ __name((bundle, status) => ({
|
|
4887
|
+
id: bundle.id,
|
|
4888
|
+
message: bundle.message,
|
|
4889
|
+
shouldForceUpdate: status === "ROLLBACK" ? true : bundle.shouldForceUpdate,
|
|
4890
|
+
status,
|
|
4891
|
+
storageUri: bundle.storageUri,
|
|
4892
|
+
fileHash: bundle.fileHash
|
|
4893
|
+
}), "makeResponse");
|
|
4894
|
+
var isEligibleUpdateCandidate = /* @__PURE__ */ __name((bundle, cohort) => {
|
|
4895
|
+
return isCohortEligibleForUpdate(bundle.id, cohort, bundle.rolloutCohortCount, bundle.targetCohorts);
|
|
4896
|
+
}, "isEligibleUpdateCandidate");
|
|
4897
|
+
var findLatestEligibleUpdateCandidate = /* @__PURE__ */ __name((bundles, bundleId, cohort) => {
|
|
4898
|
+
let updateCandidate = null;
|
|
4899
|
+
for (const bundle of bundles) if (bundle.id.localeCompare(bundleId) > 0 && isEligibleUpdateCandidate(bundle, cohort) && (!updateCandidate || bundle.id.localeCompare(updateCandidate.id) > 0)) updateCandidate = bundle;
|
|
4900
|
+
return updateCandidate;
|
|
4901
|
+
}, "findLatestEligibleUpdateCandidate");
|
|
4902
|
+
var getUpdateInfo = /* @__PURE__ */ __name(async (bundles, args) => {
|
|
4903
|
+
switch (args._updateStrategy) {
|
|
4904
|
+
case "appVersion":
|
|
4905
|
+
return appVersionStrategy(bundles, args);
|
|
4906
|
+
case "fingerprint":
|
|
4907
|
+
return fingerprintStrategy(bundles, args);
|
|
4908
|
+
default:
|
|
4909
|
+
return null;
|
|
4910
|
+
}
|
|
4911
|
+
}, "getUpdateInfo");
|
|
4912
|
+
var appVersionStrategy = /* @__PURE__ */ __name(async (bundles, { channel: channel2 = "production", minBundleId = NIL_UUID, platform: platform2, appVersion, bundleId, cohort }) => {
|
|
4913
|
+
const candidateBundles = [];
|
|
4914
|
+
for (const b of bundles) {
|
|
4915
|
+
if (b.platform !== platform2 || b.channel !== channel2 || !b.targetAppVersion || !semverSatisfies2(b.targetAppVersion, appVersion) || !b.enabled || minBundleId && b.id.localeCompare(minBundleId) < 0) continue;
|
|
4916
|
+
candidateBundles.push(b);
|
|
4917
|
+
}
|
|
4918
|
+
if (candidateBundles.length === 0) {
|
|
4919
|
+
if (bundleId === NIL_UUID || minBundleId && bundleId.localeCompare(minBundleId) <= 0) return null;
|
|
4920
|
+
return INIT_BUNDLE_ROLLBACK_UPDATE_INFO;
|
|
4921
|
+
}
|
|
4922
|
+
let rollbackCandidate = null;
|
|
4923
|
+
let currentBundle;
|
|
4924
|
+
for (const b of candidateBundles) if (b.id === bundleId) currentBundle = b;
|
|
4925
|
+
else if (bundleId !== NIL_UUID && b.id.localeCompare(bundleId) < 0) {
|
|
4926
|
+
if (!rollbackCandidate || b.id.localeCompare(rollbackCandidate.id) > 0) rollbackCandidate = b;
|
|
4927
|
+
}
|
|
4928
|
+
const updateCandidate = findLatestEligibleUpdateCandidate(candidateBundles, bundleId, cohort);
|
|
4929
|
+
const currentBundleEligible = currentBundle ? isEligibleUpdateCandidate(currentBundle, cohort) : false;
|
|
4930
|
+
if (bundleId === NIL_UUID) {
|
|
4931
|
+
if (updateCandidate) return makeResponse(updateCandidate, "UPDATE");
|
|
4932
|
+
return null;
|
|
4933
|
+
}
|
|
4934
|
+
if (currentBundleEligible) {
|
|
4935
|
+
if (updateCandidate) return makeResponse(updateCandidate, "UPDATE");
|
|
4936
|
+
return null;
|
|
4937
|
+
}
|
|
4938
|
+
if (updateCandidate) return makeResponse(updateCandidate, "UPDATE");
|
|
4939
|
+
if (rollbackCandidate) return makeResponse(rollbackCandidate, "ROLLBACK");
|
|
4940
|
+
if (minBundleId && bundleId.localeCompare(minBundleId) <= 0) return null;
|
|
4941
|
+
return INIT_BUNDLE_ROLLBACK_UPDATE_INFO;
|
|
4942
|
+
}, "appVersionStrategy");
|
|
4943
|
+
var fingerprintStrategy = /* @__PURE__ */ __name(async (bundles, { channel: channel2 = "production", minBundleId = NIL_UUID, platform: platform2, fingerprintHash, bundleId, cohort }) => {
|
|
4944
|
+
const candidateBundles = [];
|
|
4945
|
+
for (const b of bundles) {
|
|
4946
|
+
if (b.platform !== platform2 || b.channel !== channel2 || !b.fingerprintHash || b.fingerprintHash !== fingerprintHash || !b.enabled || minBundleId && b.id.localeCompare(minBundleId) < 0) continue;
|
|
4947
|
+
candidateBundles.push(b);
|
|
4948
|
+
}
|
|
4949
|
+
if (candidateBundles.length === 0) {
|
|
4950
|
+
if (bundleId === NIL_UUID || minBundleId && bundleId.localeCompare(minBundleId) <= 0) return null;
|
|
4951
|
+
return INIT_BUNDLE_ROLLBACK_UPDATE_INFO;
|
|
4952
|
+
}
|
|
4953
|
+
let rollbackCandidate = null;
|
|
4954
|
+
let currentBundle;
|
|
4955
|
+
for (const b of candidateBundles) if (b.id === bundleId) currentBundle = b;
|
|
4956
|
+
else if (bundleId !== NIL_UUID && b.id.localeCompare(bundleId) < 0) {
|
|
4957
|
+
if (!rollbackCandidate || b.id.localeCompare(rollbackCandidate.id) > 0) rollbackCandidate = b;
|
|
4958
|
+
}
|
|
4959
|
+
const updateCandidate = findLatestEligibleUpdateCandidate(candidateBundles, bundleId, cohort);
|
|
4960
|
+
const currentBundleEligible = currentBundle ? isEligibleUpdateCandidate(currentBundle, cohort) : false;
|
|
4961
|
+
if (bundleId === NIL_UUID) {
|
|
4962
|
+
if (updateCandidate) return makeResponse(updateCandidate, "UPDATE");
|
|
4963
|
+
return null;
|
|
4964
|
+
}
|
|
4965
|
+
if (currentBundleEligible) {
|
|
4966
|
+
if (updateCandidate) return makeResponse(updateCandidate, "UPDATE");
|
|
4967
|
+
return null;
|
|
4968
|
+
}
|
|
4969
|
+
if (updateCandidate) return makeResponse(updateCandidate, "UPDATE");
|
|
4970
|
+
if (rollbackCandidate) return makeResponse(rollbackCandidate, "ROLLBACK");
|
|
4971
|
+
if (minBundleId && bundleId.localeCompare(minBundleId) <= 0) return null;
|
|
4972
|
+
return INIT_BUNDLE_ROLLBACK_UPDATE_INFO;
|
|
4973
|
+
}, "fingerprintStrategy");
|
|
4719
4974
|
var encoder = new TextEncoder();
|
|
4720
4975
|
var decoder = new TextDecoder();
|
|
4721
4976
|
function concat(...buffers) {
|
|
@@ -5863,6 +6118,32 @@ var signToken = /* @__PURE__ */ __name(async (key, jwtSecret) => {
|
|
|
5863
6118
|
return await new SignJWT({ key }).setProtectedHeader({ alg: "HS256" }).setExpirationTime("60s").sign(secretKey);
|
|
5864
6119
|
}, "signToken");
|
|
5865
6120
|
|
|
6121
|
+
// ../plugin-core/dist/createDatabasePluginGetUpdateInfo.mjs
|
|
6122
|
+
init_virtual_unenv_global_polyfill_cloudflare_unenv_preset_node_process();
|
|
6123
|
+
init_virtual_unenv_global_polyfill_cloudflare_unenv_preset_node_console();
|
|
6124
|
+
init_performance2();
|
|
6125
|
+
var normalizeAppVersionArgs = /* @__PURE__ */ __name((args) => ({
|
|
6126
|
+
...args,
|
|
6127
|
+
channel: args.channel ?? "production",
|
|
6128
|
+
minBundleId: args.minBundleId ?? NIL_UUID
|
|
6129
|
+
}), "normalizeAppVersionArgs");
|
|
6130
|
+
var normalizeFingerprintArgs = /* @__PURE__ */ __name((args) => ({
|
|
6131
|
+
...args,
|
|
6132
|
+
channel: args.channel ?? "production",
|
|
6133
|
+
minBundleId: args.minBundleId ?? NIL_UUID
|
|
6134
|
+
}), "normalizeFingerprintArgs");
|
|
6135
|
+
var createDatabasePluginGetUpdateInfo = /* @__PURE__ */ __name(({ getBundlesByFingerprint, getBundlesByTargetAppVersions, listTargetAppVersions }) => {
|
|
6136
|
+
return async (args, context2) => {
|
|
6137
|
+
if (args._updateStrategy === "appVersion") {
|
|
6138
|
+
const normalizedArgs2 = normalizeAppVersionArgs(args);
|
|
6139
|
+
const compatibleAppVersions = filterCompatibleAppVersions(await listTargetAppVersions(normalizedArgs2, context2), normalizedArgs2.appVersion);
|
|
6140
|
+
return getUpdateInfo(compatibleAppVersions.length > 0 ? await getBundlesByTargetAppVersions(normalizedArgs2, compatibleAppVersions, context2) : [], normalizedArgs2);
|
|
6141
|
+
}
|
|
6142
|
+
const normalizedArgs = normalizeFingerprintArgs(args);
|
|
6143
|
+
return getUpdateInfo(await getBundlesByFingerprint(normalizedArgs, context2), normalizedArgs);
|
|
6144
|
+
};
|
|
6145
|
+
}, "createDatabasePluginGetUpdateInfo");
|
|
6146
|
+
|
|
5866
6147
|
// ../../packages/server/src/db/pluginCore.ts
|
|
5867
6148
|
var PAGE_SIZE = 100;
|
|
5868
6149
|
var DESC_ORDER = { field: "id", direction: "desc" };
|
|
@@ -5905,7 +6186,7 @@ var sortBundles = /* @__PURE__ */ __name((bundles, orderBy) => {
|
|
|
5905
6186
|
return direction === "asc" ? result : -result;
|
|
5906
6187
|
});
|
|
5907
6188
|
}, "sortBundles");
|
|
5908
|
-
var
|
|
6189
|
+
var makeResponse2 = /* @__PURE__ */ __name((bundle, status) => ({
|
|
5909
6190
|
id: bundle.id,
|
|
5910
6191
|
message: bundle.message,
|
|
5911
6192
|
shouldForceUpdate: status === "ROLLBACK" ? true : bundle.shouldForceUpdate,
|
|
@@ -5913,7 +6194,7 @@ var makeResponse = /* @__PURE__ */ __name((bundle, status) => ({
|
|
|
5913
6194
|
storageUri: bundle.storageUri,
|
|
5914
6195
|
fileHash: bundle.fileHash
|
|
5915
6196
|
}), "makeResponse");
|
|
5916
|
-
var
|
|
6197
|
+
var INIT_BUNDLE_ROLLBACK_UPDATE_INFO2 = {
|
|
5917
6198
|
message: null,
|
|
5918
6199
|
id: NIL_UUID,
|
|
5919
6200
|
shouldForceUpdate: true,
|
|
@@ -5959,14 +6240,18 @@ function createPluginDatabaseCore(getPlugin, resolveFileUrl, options) {
|
|
|
5959
6240
|
isCandidate,
|
|
5960
6241
|
context: context2
|
|
5961
6242
|
}) => {
|
|
5962
|
-
let
|
|
6243
|
+
let after;
|
|
5963
6244
|
while (true) {
|
|
5964
6245
|
const { data, pagination } = await getSortedBundlePage(
|
|
5965
6246
|
{
|
|
5966
6247
|
where: queryWhere,
|
|
5967
6248
|
limit: PAGE_SIZE,
|
|
5968
|
-
|
|
5969
|
-
|
|
6249
|
+
orderBy: DESC_ORDER,
|
|
6250
|
+
...after ? {
|
|
6251
|
+
cursor: {
|
|
6252
|
+
after
|
|
6253
|
+
}
|
|
6254
|
+
} : {}
|
|
5970
6255
|
},
|
|
5971
6256
|
context2
|
|
5972
6257
|
);
|
|
@@ -5976,14 +6261,14 @@ function createPluginDatabaseCore(getPlugin, resolveFileUrl, options) {
|
|
|
5976
6261
|
}
|
|
5977
6262
|
if (args.bundleId === NIL_UUID) {
|
|
5978
6263
|
if (isEligibleForUpdate(bundle, args.cohort)) {
|
|
5979
|
-
return
|
|
6264
|
+
return makeResponse2(bundle, "UPDATE");
|
|
5980
6265
|
}
|
|
5981
6266
|
continue;
|
|
5982
6267
|
}
|
|
5983
6268
|
const compareResult = bundle.id.localeCompare(args.bundleId);
|
|
5984
6269
|
if (compareResult > 0) {
|
|
5985
6270
|
if (isEligibleForUpdate(bundle, args.cohort)) {
|
|
5986
|
-
return
|
|
6271
|
+
return makeResponse2(bundle, "UPDATE");
|
|
5987
6272
|
}
|
|
5988
6273
|
continue;
|
|
5989
6274
|
}
|
|
@@ -5993,12 +6278,15 @@ function createPluginDatabaseCore(getPlugin, resolveFileUrl, options) {
|
|
|
5993
6278
|
}
|
|
5994
6279
|
continue;
|
|
5995
6280
|
}
|
|
5996
|
-
return
|
|
6281
|
+
return makeResponse2(bundle, "ROLLBACK");
|
|
5997
6282
|
}
|
|
5998
6283
|
if (!pagination.hasNextPage) {
|
|
5999
6284
|
break;
|
|
6000
6285
|
}
|
|
6001
|
-
|
|
6286
|
+
after = data.at(-1)?.id;
|
|
6287
|
+
if (!after) {
|
|
6288
|
+
break;
|
|
6289
|
+
}
|
|
6002
6290
|
}
|
|
6003
6291
|
if (args.bundleId === NIL_UUID) {
|
|
6004
6292
|
return null;
|
|
@@ -6006,7 +6294,7 @@ function createPluginDatabaseCore(getPlugin, resolveFileUrl, options) {
|
|
|
6006
6294
|
if (args.minBundleId && args.bundleId.localeCompare(args.minBundleId) <= 0) {
|
|
6007
6295
|
return null;
|
|
6008
6296
|
}
|
|
6009
|
-
return
|
|
6297
|
+
return INIT_BUNDLE_ROLLBACK_UPDATE_INFO2;
|
|
6010
6298
|
}, "findUpdateInfoByScanning");
|
|
6011
6299
|
const getBaseWhere = /* @__PURE__ */ __name(({
|
|
6012
6300
|
platform: platform2,
|
|
@@ -6321,7 +6609,21 @@ var handleGetBundles = /* @__PURE__ */ __name(async (_params, request, api, cont
|
|
|
6321
6609
|
const channel2 = url.searchParams.get("channel") ?? void 0;
|
|
6322
6610
|
const platform2 = url.searchParams.get("platform");
|
|
6323
6611
|
const limit = Number(url.searchParams.get("limit")) || 50;
|
|
6324
|
-
const
|
|
6612
|
+
const pageParam = url.searchParams.get("page");
|
|
6613
|
+
const offset = url.searchParams.get("offset");
|
|
6614
|
+
const after = url.searchParams.get("after") ?? void 0;
|
|
6615
|
+
const before = url.searchParams.get("before") ?? void 0;
|
|
6616
|
+
const page = pageParam === null ? void 0 : Number.isInteger(Number(pageParam)) && Number(pageParam) > 0 ? Number(pageParam) : null;
|
|
6617
|
+
if (offset !== null) {
|
|
6618
|
+
throw new HandlerBadRequestError(
|
|
6619
|
+
"The 'offset' query parameter has been removed. Use 'after' or 'before' cursor pagination instead."
|
|
6620
|
+
);
|
|
6621
|
+
}
|
|
6622
|
+
if (page === null) {
|
|
6623
|
+
throw new HandlerBadRequestError(
|
|
6624
|
+
"The 'page' query parameter must be a positive integer."
|
|
6625
|
+
);
|
|
6626
|
+
}
|
|
6325
6627
|
if (platform2 !== null && !isPlatform(platform2)) {
|
|
6326
6628
|
throw new HandlerBadRequestError(
|
|
6327
6629
|
`Invalid platform: ${platform2}. Expected 'ios' or 'android'.`
|
|
@@ -6334,7 +6636,11 @@ var handleGetBundles = /* @__PURE__ */ __name(async (_params, request, api, cont
|
|
|
6334
6636
|
...platform2 && { platform: platform2 }
|
|
6335
6637
|
},
|
|
6336
6638
|
limit,
|
|
6337
|
-
|
|
6639
|
+
page,
|
|
6640
|
+
cursor: after || before ? {
|
|
6641
|
+
after,
|
|
6642
|
+
before
|
|
6643
|
+
} : void 0
|
|
6338
6644
|
},
|
|
6339
6645
|
context2
|
|
6340
6646
|
);
|
|
@@ -8892,7 +9198,71 @@ var d1WorkerDatabase = /* @__PURE__ */ __name(() => createDatabasePlugin({
|
|
|
8892
9198
|
const result = await config2.getDb(context2).prepare(sql).bind(...params).first();
|
|
8893
9199
|
return result ?? null;
|
|
8894
9200
|
}, "queryFirst");
|
|
9201
|
+
const queryBundlesForUpdateInfo = /* @__PURE__ */ __name(async (conditions, context2) => {
|
|
9202
|
+
const { sql: whereClause, params } = buildWhereClause(conditions);
|
|
9203
|
+
const rows = await queryAll(
|
|
9204
|
+
`
|
|
9205
|
+
SELECT * FROM bundles
|
|
9206
|
+
${whereClause}
|
|
9207
|
+
`,
|
|
9208
|
+
params,
|
|
9209
|
+
context2
|
|
9210
|
+
);
|
|
9211
|
+
return rows.map(transformRowToBundle);
|
|
9212
|
+
}, "queryBundlesForUpdateInfo");
|
|
9213
|
+
const getTargetAppVersionsForUpdateInfo = /* @__PURE__ */ __name(async ({
|
|
9214
|
+
platform: platform2,
|
|
9215
|
+
channel: channel2,
|
|
9216
|
+
minBundleId
|
|
9217
|
+
}, context2) => {
|
|
9218
|
+
const rows = await queryAll(
|
|
9219
|
+
`
|
|
9220
|
+
SELECT target_app_version
|
|
9221
|
+
FROM bundles
|
|
9222
|
+
WHERE channel = ?
|
|
9223
|
+
AND platform = ?
|
|
9224
|
+
AND enabled = 1
|
|
9225
|
+
AND id >= ?
|
|
9226
|
+
AND target_app_version IS NOT NULL
|
|
9227
|
+
GROUP BY target_app_version
|
|
9228
|
+
`,
|
|
9229
|
+
[channel2, platform2, minBundleId],
|
|
9230
|
+
context2
|
|
9231
|
+
);
|
|
9232
|
+
return rows.map((row) => row.target_app_version);
|
|
9233
|
+
}, "getTargetAppVersionsForUpdateInfo");
|
|
8895
9234
|
return {
|
|
9235
|
+
getUpdateInfo: createDatabasePluginGetUpdateInfo({
|
|
9236
|
+
listTargetAppVersions: getTargetAppVersionsForUpdateInfo,
|
|
9237
|
+
getBundlesByTargetAppVersions({ platform: platform2, channel: channel2, minBundleId }, targetAppVersions, context2) {
|
|
9238
|
+
return queryBundlesForUpdateInfo(
|
|
9239
|
+
{
|
|
9240
|
+
enabled: true,
|
|
9241
|
+
platform: platform2,
|
|
9242
|
+
channel: channel2,
|
|
9243
|
+
id: {
|
|
9244
|
+
gte: minBundleId
|
|
9245
|
+
},
|
|
9246
|
+
targetAppVersionIn: targetAppVersions
|
|
9247
|
+
},
|
|
9248
|
+
context2
|
|
9249
|
+
);
|
|
9250
|
+
},
|
|
9251
|
+
getBundlesByFingerprint({ platform: platform2, channel: channel2, minBundleId, fingerprintHash }, context2) {
|
|
9252
|
+
return queryBundlesForUpdateInfo(
|
|
9253
|
+
{
|
|
9254
|
+
enabled: true,
|
|
9255
|
+
platform: platform2,
|
|
9256
|
+
channel: channel2,
|
|
9257
|
+
id: {
|
|
9258
|
+
gte: minBundleId
|
|
9259
|
+
},
|
|
9260
|
+
fingerprintHash
|
|
9261
|
+
},
|
|
9262
|
+
context2
|
|
9263
|
+
);
|
|
9264
|
+
}
|
|
9265
|
+
}),
|
|
8896
9266
|
async getBundleById(bundleId, context2) {
|
|
8897
9267
|
const row = await queryFirst(
|
|
8898
9268
|
"SELECT * FROM bundles WHERE id = ? LIMIT 1",
|
|
@@ -8902,7 +9272,8 @@ var d1WorkerDatabase = /* @__PURE__ */ __name(() => createDatabasePlugin({
|
|
|
8902
9272
|
return row ? transformRowToBundle(row) : null;
|
|
8903
9273
|
},
|
|
8904
9274
|
async getBundles(options, context2) {
|
|
8905
|
-
const { where, limit,
|
|
9275
|
+
const { where, limit, orderBy } = options;
|
|
9276
|
+
const offset = ("offset" in options ? options.offset : void 0) ?? 0;
|
|
8906
9277
|
const { sql: whereClause, params } = buildWhereClause(where);
|
|
8907
9278
|
const orderSql = orderBy?.direction === "asc" ? "ORDER BY id ASC" : "ORDER BY id DESC";
|
|
8908
9279
|
const countRows = await queryAll(
|