@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/dist/iac/index.cjs
CHANGED
|
@@ -10837,8 +10837,8 @@ const getWranglerLoginAuthToken = () => {
|
|
|
10837
10837
|
};
|
|
10838
10838
|
//#endregion
|
|
10839
10839
|
//#region iac/index.ts
|
|
10840
|
-
const
|
|
10841
|
-
return new _hot_updater_cli_tools.ConfigBuilder().setBuildType(build).setStorage({
|
|
10840
|
+
const getConfigScaffold = (build) => {
|
|
10841
|
+
return (0, _hot_updater_cli_tools.createHotUpdaterConfigScaffoldFromBuilder)(new _hot_updater_cli_tools.ConfigBuilder().setBuildType(build).setStorage({
|
|
10842
10842
|
imports: [{
|
|
10843
10843
|
pkg: "@hot-updater/cloudflare",
|
|
10844
10844
|
named: ["r2Storage"]
|
|
@@ -10858,7 +10858,7 @@ const getConfigTemplate = (build) => {
|
|
|
10858
10858
|
accountId: process.env.HOT_UPDATER_CLOUDFLARE_ACCOUNT_ID!,
|
|
10859
10859
|
cloudflareApiToken: process.env.HOT_UPDATER_CLOUDFLARE_API_TOKEN!,
|
|
10860
10860
|
})`
|
|
10861
|
-
})
|
|
10861
|
+
}));
|
|
10862
10862
|
};
|
|
10863
10863
|
const SOURCE_TEMPLATE = `// add this to your App.tsx
|
|
10864
10864
|
import { HotUpdater } from "@hot-updater/react-native";
|
|
@@ -11066,7 +11066,7 @@ const runInit = async ({ build }) => {
|
|
|
11066
11066
|
d1DatabaseName,
|
|
11067
11067
|
r2BucketName: selectedBucketName
|
|
11068
11068
|
});
|
|
11069
|
-
await
|
|
11069
|
+
const configWriteResult = await (0, _hot_updater_cli_tools.writeHotUpdaterConfig)(getConfigScaffold(build));
|
|
11070
11070
|
await (0, _hot_updater_cli_tools.makeEnv)({
|
|
11071
11071
|
HOT_UPDATER_CLOUDFLARE_API_TOKEN: apiToken,
|
|
11072
11072
|
HOT_UPDATER_CLOUDFLARE_ACCOUNT_ID: accountId,
|
|
@@ -11074,7 +11074,9 @@ const runInit = async ({ build }) => {
|
|
|
11074
11074
|
HOT_UPDATER_CLOUDFLARE_D1_DATABASE_ID: selectedD1DatabaseId
|
|
11075
11075
|
});
|
|
11076
11076
|
_hot_updater_cli_tools.p.log.success("Generated '.env.hotupdater' file with Cloudflare settings.");
|
|
11077
|
-
_hot_updater_cli_tools.p.log.success("Generated 'hot-updater.config.ts' file with Cloudflare settings.");
|
|
11077
|
+
if (configWriteResult.status === "created") _hot_updater_cli_tools.p.log.success("Generated 'hot-updater.config.ts' file with Cloudflare settings.");
|
|
11078
|
+
else if (configWriteResult.status === "merged") _hot_updater_cli_tools.p.log.success("Updated 'hot-updater.config.ts' file with Cloudflare settings.");
|
|
11079
|
+
else _hot_updater_cli_tools.p.log.warn(`Kept existing 'hot-updater.config.ts' unchanged: ${configWriteResult.reason}`);
|
|
11078
11080
|
if (subdomains.subdomain) _hot_updater_cli_tools.p.note((0, _hot_updater_cli_tools.transformTemplate)(SOURCE_TEMPLATE, { source: `https://${workerName}.${subdomains.subdomain}.workers.dev/api/check-update` }));
|
|
11079
11081
|
_hot_updater_cli_tools.p.log.message(`Next step: ${(0, _hot_updater_cli_tools.link)("https://hot-updater.dev/docs/managed/cloudflare#step-4-add-hotupdater-to-your-project")}`);
|
|
11080
11082
|
_hot_updater_cli_tools.p.log.success("Done! 🎉");
|
package/dist/iac/index.mjs
CHANGED
|
@@ -2,7 +2,7 @@ import { createRequire } from "node:module";
|
|
|
2
2
|
import crypto from "crypto";
|
|
3
3
|
import fs from "fs/promises";
|
|
4
4
|
import path from "path";
|
|
5
|
-
import { ConfigBuilder, copyDirToTmp, getCwd, link, makeEnv, p, transformTemplate } from "@hot-updater/cli-tools";
|
|
5
|
+
import { ConfigBuilder, copyDirToTmp, createHotUpdaterConfigScaffoldFromBuilder, getCwd, link, makeEnv, p, transformTemplate, writeHotUpdaterConfig } from "@hot-updater/cli-tools";
|
|
6
6
|
import { Cloudflare } from "cloudflare";
|
|
7
7
|
import { fileURLToPath } from "node:url";
|
|
8
8
|
import { ChildProcess, execFile, spawn, spawnSync } from "node:child_process";
|
|
@@ -10829,8 +10829,8 @@ const getWranglerLoginAuthToken = () => {
|
|
|
10829
10829
|
};
|
|
10830
10830
|
//#endregion
|
|
10831
10831
|
//#region iac/index.ts
|
|
10832
|
-
const
|
|
10833
|
-
return new ConfigBuilder().setBuildType(build).setStorage({
|
|
10832
|
+
const getConfigScaffold = (build) => {
|
|
10833
|
+
return createHotUpdaterConfigScaffoldFromBuilder(new ConfigBuilder().setBuildType(build).setStorage({
|
|
10834
10834
|
imports: [{
|
|
10835
10835
|
pkg: "@hot-updater/cloudflare",
|
|
10836
10836
|
named: ["r2Storage"]
|
|
@@ -10850,7 +10850,7 @@ const getConfigTemplate = (build) => {
|
|
|
10850
10850
|
accountId: process.env.HOT_UPDATER_CLOUDFLARE_ACCOUNT_ID!,
|
|
10851
10851
|
cloudflareApiToken: process.env.HOT_UPDATER_CLOUDFLARE_API_TOKEN!,
|
|
10852
10852
|
})`
|
|
10853
|
-
})
|
|
10853
|
+
}));
|
|
10854
10854
|
};
|
|
10855
10855
|
const SOURCE_TEMPLATE = `// add this to your App.tsx
|
|
10856
10856
|
import { HotUpdater } from "@hot-updater/react-native";
|
|
@@ -11058,7 +11058,7 @@ const runInit = async ({ build }) => {
|
|
|
11058
11058
|
d1DatabaseName,
|
|
11059
11059
|
r2BucketName: selectedBucketName
|
|
11060
11060
|
});
|
|
11061
|
-
await
|
|
11061
|
+
const configWriteResult = await writeHotUpdaterConfig(getConfigScaffold(build));
|
|
11062
11062
|
await makeEnv({
|
|
11063
11063
|
HOT_UPDATER_CLOUDFLARE_API_TOKEN: apiToken,
|
|
11064
11064
|
HOT_UPDATER_CLOUDFLARE_ACCOUNT_ID: accountId,
|
|
@@ -11066,7 +11066,9 @@ const runInit = async ({ build }) => {
|
|
|
11066
11066
|
HOT_UPDATER_CLOUDFLARE_D1_DATABASE_ID: selectedD1DatabaseId
|
|
11067
11067
|
});
|
|
11068
11068
|
p.log.success("Generated '.env.hotupdater' file with Cloudflare settings.");
|
|
11069
|
-
p.log.success("Generated 'hot-updater.config.ts' file with Cloudflare settings.");
|
|
11069
|
+
if (configWriteResult.status === "created") p.log.success("Generated 'hot-updater.config.ts' file with Cloudflare settings.");
|
|
11070
|
+
else if (configWriteResult.status === "merged") p.log.success("Updated 'hot-updater.config.ts' file with Cloudflare settings.");
|
|
11071
|
+
else p.log.warn(`Kept existing 'hot-updater.config.ts' unchanged: ${configWriteResult.reason}`);
|
|
11070
11072
|
if (subdomains.subdomain) p.note(transformTemplate(SOURCE_TEMPLATE, { source: `https://${workerName}.${subdomains.subdomain}.workers.dev/api/check-update` }));
|
|
11071
11073
|
p.log.message(`Next step: ${link("https://hot-updater.dev/docs/managed/cloudflare#step-4-add-hotupdater-to-your-project")}`);
|
|
11072
11074
|
p.log.success("Done! 🎉");
|
package/dist/index.cjs
CHANGED
|
@@ -404,7 +404,61 @@ const d1Database = (0, _hot_updater_plugin_core.createDatabasePlugin)({
|
|
|
404
404
|
params
|
|
405
405
|
}))).map(transformRowToBundle);
|
|
406
406
|
}
|
|
407
|
+
async function queryBundlesForUpdateInfo(conditions) {
|
|
408
|
+
const { sql: whereClause, params } = buildWhereClause(conditions);
|
|
409
|
+
const sql = (0, import_lib.default)(`
|
|
410
|
+
SELECT * FROM bundles
|
|
411
|
+
${whereClause}
|
|
412
|
+
`);
|
|
413
|
+
return (await resolvePage(await cf.d1.database.query(config.databaseId, {
|
|
414
|
+
account_id: config.accountId,
|
|
415
|
+
sql,
|
|
416
|
+
params
|
|
417
|
+
}))).map(transformRowToBundle);
|
|
418
|
+
}
|
|
419
|
+
async function getTargetAppVersionsForUpdateInfo({ platform, channel, minBundleId }) {
|
|
420
|
+
const sql = (0, import_lib.default)(`
|
|
421
|
+
SELECT target_app_version
|
|
422
|
+
FROM bundles
|
|
423
|
+
WHERE channel = ?
|
|
424
|
+
AND platform = ?
|
|
425
|
+
AND enabled = 1
|
|
426
|
+
AND id >= ?
|
|
427
|
+
AND target_app_version IS NOT NULL
|
|
428
|
+
GROUP BY target_app_version
|
|
429
|
+
`);
|
|
430
|
+
return (await resolvePage(await cf.d1.database.query(config.databaseId, {
|
|
431
|
+
account_id: config.accountId,
|
|
432
|
+
sql,
|
|
433
|
+
params: [
|
|
434
|
+
channel,
|
|
435
|
+
platform,
|
|
436
|
+
minBundleId
|
|
437
|
+
]
|
|
438
|
+
}))).map((row) => row.target_app_version);
|
|
439
|
+
}
|
|
407
440
|
return {
|
|
441
|
+
getUpdateInfo: (0, _hot_updater_plugin_core.createDatabasePluginGetUpdateInfo)({
|
|
442
|
+
listTargetAppVersions: getTargetAppVersionsForUpdateInfo,
|
|
443
|
+
getBundlesByTargetAppVersions({ platform, channel, minBundleId }, targetAppVersions) {
|
|
444
|
+
return queryBundlesForUpdateInfo({
|
|
445
|
+
enabled: true,
|
|
446
|
+
platform,
|
|
447
|
+
channel,
|
|
448
|
+
id: { gte: minBundleId },
|
|
449
|
+
targetAppVersionIn: targetAppVersions
|
|
450
|
+
});
|
|
451
|
+
},
|
|
452
|
+
getBundlesByFingerprint({ platform, channel, minBundleId, fingerprintHash }) {
|
|
453
|
+
return queryBundlesForUpdateInfo({
|
|
454
|
+
enabled: true,
|
|
455
|
+
platform,
|
|
456
|
+
channel,
|
|
457
|
+
id: { gte: minBundleId },
|
|
458
|
+
fingerprintHash
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
}),
|
|
408
462
|
async getBundleById(bundleId) {
|
|
409
463
|
const sql = (0, import_lib.default)(`
|
|
410
464
|
SELECT * FROM bundles WHERE id = ? LIMIT 1`);
|
|
@@ -417,7 +471,8 @@ const d1Database = (0, _hot_updater_plugin_core.createDatabasePlugin)({
|
|
|
417
471
|
return transformRowToBundle(rows[0]);
|
|
418
472
|
},
|
|
419
473
|
async getBundles(options) {
|
|
420
|
-
const { where = {}, limit,
|
|
474
|
+
const { where = {}, limit, orderBy } = options;
|
|
475
|
+
const offset = ("offset" in options ? options.offset : void 0) ?? 0;
|
|
421
476
|
const totalCount = await getTotalCount(where);
|
|
422
477
|
return {
|
|
423
478
|
data: await getPaginatedBundles(where, limit, offset, orderBy),
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
import { DEFAULT_ROLLOUT_COHORT_COUNT } from "@hot-updater/core";
|
|
3
|
-
import { calculatePagination, createDatabasePlugin, createStorageKeyBuilder, createStoragePlugin, getContentType, parseStorageUri } from "@hot-updater/plugin-core";
|
|
3
|
+
import { calculatePagination, createDatabasePlugin, createDatabasePluginGetUpdateInfo, createStorageKeyBuilder, createStoragePlugin, getContentType, parseStorageUri } from "@hot-updater/plugin-core";
|
|
4
4
|
import Cloudflare from "cloudflare";
|
|
5
5
|
import path from "path";
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
@@ -400,7 +400,61 @@ const d1Database = createDatabasePlugin({
|
|
|
400
400
|
params
|
|
401
401
|
}))).map(transformRowToBundle);
|
|
402
402
|
}
|
|
403
|
+
async function queryBundlesForUpdateInfo(conditions) {
|
|
404
|
+
const { sql: whereClause, params } = buildWhereClause(conditions);
|
|
405
|
+
const sql = (0, import_lib.default)(`
|
|
406
|
+
SELECT * FROM bundles
|
|
407
|
+
${whereClause}
|
|
408
|
+
`);
|
|
409
|
+
return (await resolvePage(await cf.d1.database.query(config.databaseId, {
|
|
410
|
+
account_id: config.accountId,
|
|
411
|
+
sql,
|
|
412
|
+
params
|
|
413
|
+
}))).map(transformRowToBundle);
|
|
414
|
+
}
|
|
415
|
+
async function getTargetAppVersionsForUpdateInfo({ platform, channel, minBundleId }) {
|
|
416
|
+
const sql = (0, import_lib.default)(`
|
|
417
|
+
SELECT target_app_version
|
|
418
|
+
FROM bundles
|
|
419
|
+
WHERE channel = ?
|
|
420
|
+
AND platform = ?
|
|
421
|
+
AND enabled = 1
|
|
422
|
+
AND id >= ?
|
|
423
|
+
AND target_app_version IS NOT NULL
|
|
424
|
+
GROUP BY target_app_version
|
|
425
|
+
`);
|
|
426
|
+
return (await resolvePage(await cf.d1.database.query(config.databaseId, {
|
|
427
|
+
account_id: config.accountId,
|
|
428
|
+
sql,
|
|
429
|
+
params: [
|
|
430
|
+
channel,
|
|
431
|
+
platform,
|
|
432
|
+
minBundleId
|
|
433
|
+
]
|
|
434
|
+
}))).map((row) => row.target_app_version);
|
|
435
|
+
}
|
|
403
436
|
return {
|
|
437
|
+
getUpdateInfo: createDatabasePluginGetUpdateInfo({
|
|
438
|
+
listTargetAppVersions: getTargetAppVersionsForUpdateInfo,
|
|
439
|
+
getBundlesByTargetAppVersions({ platform, channel, minBundleId }, targetAppVersions) {
|
|
440
|
+
return queryBundlesForUpdateInfo({
|
|
441
|
+
enabled: true,
|
|
442
|
+
platform,
|
|
443
|
+
channel,
|
|
444
|
+
id: { gte: minBundleId },
|
|
445
|
+
targetAppVersionIn: targetAppVersions
|
|
446
|
+
});
|
|
447
|
+
},
|
|
448
|
+
getBundlesByFingerprint({ platform, channel, minBundleId, fingerprintHash }) {
|
|
449
|
+
return queryBundlesForUpdateInfo({
|
|
450
|
+
enabled: true,
|
|
451
|
+
platform,
|
|
452
|
+
channel,
|
|
453
|
+
id: { gte: minBundleId },
|
|
454
|
+
fingerprintHash
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
}),
|
|
404
458
|
async getBundleById(bundleId) {
|
|
405
459
|
const sql = (0, import_lib.default)(`
|
|
406
460
|
SELECT * FROM bundles WHERE id = ? LIMIT 1`);
|
|
@@ -413,7 +467,8 @@ const d1Database = createDatabasePlugin({
|
|
|
413
467
|
return transformRowToBundle(rows[0]);
|
|
414
468
|
},
|
|
415
469
|
async getBundles(options) {
|
|
416
|
-
const { where = {}, limit,
|
|
470
|
+
const { where = {}, limit, orderBy } = options;
|
|
471
|
+
const offset = ("offset" in options ? options.offset : void 0) ?? 0;
|
|
417
472
|
const totalCount = await getTotalCount(where);
|
|
418
473
|
return {
|
|
419
474
|
data: await getPaginatedBundles(where, limit, offset, orderBy),
|
package/dist/worker/index.cjs
CHANGED
|
@@ -111,13 +111,58 @@ const d1WorkerDatabase = () => (0, _hot_updater_plugin_core.createDatabasePlugin
|
|
|
111
111
|
const queryFirst = async (sql, params = [], context) => {
|
|
112
112
|
return await config.getDb(context).prepare(sql).bind(...params).first() ?? null;
|
|
113
113
|
};
|
|
114
|
+
const queryBundlesForUpdateInfo = async (conditions, context) => {
|
|
115
|
+
const { sql: whereClause, params } = buildWhereClause(conditions);
|
|
116
|
+
return (await queryAll(`
|
|
117
|
+
SELECT * FROM bundles
|
|
118
|
+
${whereClause}
|
|
119
|
+
`, params, context)).map(transformRowToBundle);
|
|
120
|
+
};
|
|
121
|
+
const getTargetAppVersionsForUpdateInfo = async ({ platform, channel, minBundleId }, context) => {
|
|
122
|
+
return (await queryAll(`
|
|
123
|
+
SELECT target_app_version
|
|
124
|
+
FROM bundles
|
|
125
|
+
WHERE channel = ?
|
|
126
|
+
AND platform = ?
|
|
127
|
+
AND enabled = 1
|
|
128
|
+
AND id >= ?
|
|
129
|
+
AND target_app_version IS NOT NULL
|
|
130
|
+
GROUP BY target_app_version
|
|
131
|
+
`, [
|
|
132
|
+
channel,
|
|
133
|
+
platform,
|
|
134
|
+
minBundleId
|
|
135
|
+
], context)).map((row) => row.target_app_version);
|
|
136
|
+
};
|
|
114
137
|
return {
|
|
138
|
+
getUpdateInfo: (0, _hot_updater_plugin_core.createDatabasePluginGetUpdateInfo)({
|
|
139
|
+
listTargetAppVersions: getTargetAppVersionsForUpdateInfo,
|
|
140
|
+
getBundlesByTargetAppVersions({ platform, channel, minBundleId }, targetAppVersions, context) {
|
|
141
|
+
return queryBundlesForUpdateInfo({
|
|
142
|
+
enabled: true,
|
|
143
|
+
platform,
|
|
144
|
+
channel,
|
|
145
|
+
id: { gte: minBundleId },
|
|
146
|
+
targetAppVersionIn: targetAppVersions
|
|
147
|
+
}, context);
|
|
148
|
+
},
|
|
149
|
+
getBundlesByFingerprint({ platform, channel, minBundleId, fingerprintHash }, context) {
|
|
150
|
+
return queryBundlesForUpdateInfo({
|
|
151
|
+
enabled: true,
|
|
152
|
+
platform,
|
|
153
|
+
channel,
|
|
154
|
+
id: { gte: minBundleId },
|
|
155
|
+
fingerprintHash
|
|
156
|
+
}, context);
|
|
157
|
+
}
|
|
158
|
+
}),
|
|
115
159
|
async getBundleById(bundleId, context) {
|
|
116
160
|
const row = await queryFirst("SELECT * FROM bundles WHERE id = ? LIMIT 1", [bundleId], context);
|
|
117
161
|
return row ? transformRowToBundle(row) : null;
|
|
118
162
|
},
|
|
119
163
|
async getBundles(options, context) {
|
|
120
|
-
const { where, limit,
|
|
164
|
+
const { where, limit, orderBy } = options;
|
|
165
|
+
const offset = ("offset" in options ? options.offset : void 0) ?? 0;
|
|
121
166
|
const { sql: whereClause, params } = buildWhereClause(where);
|
|
122
167
|
const orderSql = orderBy?.direction === "asc" ? "ORDER BY id ASC" : "ORDER BY id DESC";
|
|
123
168
|
const total = (await queryAll(`SELECT COUNT(*) as total FROM bundles${whereClause}`, params, context))[0]?.total ?? 0;
|
package/dist/worker/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { signToken, verifyJwtSignedUrl } from "@hot-updater/js";
|
|
2
2
|
import { DEFAULT_ROLLOUT_COHORT_COUNT } from "@hot-updater/core";
|
|
3
|
-
import { calculatePagination, createDatabasePlugin } from "@hot-updater/plugin-core";
|
|
3
|
+
import { calculatePagination, createDatabasePlugin, createDatabasePluginGetUpdateInfo } from "@hot-updater/plugin-core";
|
|
4
4
|
//#region src/cloudflareWorkerDatabase.ts
|
|
5
5
|
function buildWhereClause(conditions) {
|
|
6
6
|
if (!conditions) return {
|
|
@@ -110,13 +110,58 @@ const d1WorkerDatabase = () => createDatabasePlugin({
|
|
|
110
110
|
const queryFirst = async (sql, params = [], context) => {
|
|
111
111
|
return await config.getDb(context).prepare(sql).bind(...params).first() ?? null;
|
|
112
112
|
};
|
|
113
|
+
const queryBundlesForUpdateInfo = async (conditions, context) => {
|
|
114
|
+
const { sql: whereClause, params } = buildWhereClause(conditions);
|
|
115
|
+
return (await queryAll(`
|
|
116
|
+
SELECT * FROM bundles
|
|
117
|
+
${whereClause}
|
|
118
|
+
`, params, context)).map(transformRowToBundle);
|
|
119
|
+
};
|
|
120
|
+
const getTargetAppVersionsForUpdateInfo = async ({ platform, channel, minBundleId }, context) => {
|
|
121
|
+
return (await queryAll(`
|
|
122
|
+
SELECT target_app_version
|
|
123
|
+
FROM bundles
|
|
124
|
+
WHERE channel = ?
|
|
125
|
+
AND platform = ?
|
|
126
|
+
AND enabled = 1
|
|
127
|
+
AND id >= ?
|
|
128
|
+
AND target_app_version IS NOT NULL
|
|
129
|
+
GROUP BY target_app_version
|
|
130
|
+
`, [
|
|
131
|
+
channel,
|
|
132
|
+
platform,
|
|
133
|
+
minBundleId
|
|
134
|
+
], context)).map((row) => row.target_app_version);
|
|
135
|
+
};
|
|
113
136
|
return {
|
|
137
|
+
getUpdateInfo: createDatabasePluginGetUpdateInfo({
|
|
138
|
+
listTargetAppVersions: getTargetAppVersionsForUpdateInfo,
|
|
139
|
+
getBundlesByTargetAppVersions({ platform, channel, minBundleId }, targetAppVersions, context) {
|
|
140
|
+
return queryBundlesForUpdateInfo({
|
|
141
|
+
enabled: true,
|
|
142
|
+
platform,
|
|
143
|
+
channel,
|
|
144
|
+
id: { gte: minBundleId },
|
|
145
|
+
targetAppVersionIn: targetAppVersions
|
|
146
|
+
}, context);
|
|
147
|
+
},
|
|
148
|
+
getBundlesByFingerprint({ platform, channel, minBundleId, fingerprintHash }, context) {
|
|
149
|
+
return queryBundlesForUpdateInfo({
|
|
150
|
+
enabled: true,
|
|
151
|
+
platform,
|
|
152
|
+
channel,
|
|
153
|
+
id: { gte: minBundleId },
|
|
154
|
+
fingerprintHash
|
|
155
|
+
}, context);
|
|
156
|
+
}
|
|
157
|
+
}),
|
|
114
158
|
async getBundleById(bundleId, context) {
|
|
115
159
|
const row = await queryFirst("SELECT * FROM bundles WHERE id = ? LIMIT 1", [bundleId], context);
|
|
116
160
|
return row ? transformRowToBundle(row) : null;
|
|
117
161
|
},
|
|
118
162
|
async getBundles(options, context) {
|
|
119
|
-
const { where, limit,
|
|
163
|
+
const { where, limit, orderBy } = options;
|
|
164
|
+
const offset = ("offset" in options ? options.offset : void 0) ?? 0;
|
|
120
165
|
const { sql: whereClause, params } = buildWhereClause(where);
|
|
121
166
|
const orderSql = orderBy?.direction === "asc" ? "ORDER BY id ASC" : "ORDER BY id DESC";
|
|
122
167
|
const total = (await queryAll(`SELECT COUNT(*) as total FROM bundles${whereClause}`, params, context))[0]?.total ?? 0;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hot-updater/cloudflare",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.29.
|
|
4
|
+
"version": "0.29.6",
|
|
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/
|
|
54
|
-
"@hot-updater/
|
|
55
|
-
"@hot-updater/
|
|
56
|
-
"@hot-updater/
|
|
57
|
-
"@hot-updater/
|
|
53
|
+
"@hot-updater/cli-tools": "0.29.6",
|
|
54
|
+
"@hot-updater/core": "0.29.6",
|
|
55
|
+
"@hot-updater/js": "0.29.6",
|
|
56
|
+
"@hot-updater/plugin-core": "0.29.6",
|
|
57
|
+
"@hot-updater/server": "0.29.6"
|
|
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.
|
|
74
|
+
"@hot-updater/test-utils": "0.29.6"
|
|
75
75
|
},
|
|
76
76
|
"scripts": {
|
|
77
77
|
"build": "tsdown && pnpm build:worker",
|
|
@@ -12,6 +12,7 @@ import type {
|
|
|
12
12
|
import {
|
|
13
13
|
calculatePagination,
|
|
14
14
|
createDatabasePlugin,
|
|
15
|
+
createDatabasePluginGetUpdateInfo,
|
|
15
16
|
} from "@hot-updater/plugin-core";
|
|
16
17
|
|
|
17
18
|
type D1Result<T> = {
|
|
@@ -235,7 +236,93 @@ export const d1WorkerDatabase = <
|
|
|
235
236
|
return result ?? null;
|
|
236
237
|
};
|
|
237
238
|
|
|
239
|
+
const queryBundlesForUpdateInfo = async (
|
|
240
|
+
conditions: QueryConditions,
|
|
241
|
+
context?: HotUpdaterContext<TContext>,
|
|
242
|
+
): Promise<Bundle[]> => {
|
|
243
|
+
const { sql: whereClause, params } = buildWhereClause(conditions);
|
|
244
|
+
const rows = await queryAll<SnakeCaseBundle>(
|
|
245
|
+
`
|
|
246
|
+
SELECT * FROM bundles
|
|
247
|
+
${whereClause}
|
|
248
|
+
`,
|
|
249
|
+
params,
|
|
250
|
+
context,
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
return rows.map(transformRowToBundle);
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
const getTargetAppVersionsForUpdateInfo = async (
|
|
257
|
+
{
|
|
258
|
+
platform,
|
|
259
|
+
channel,
|
|
260
|
+
minBundleId,
|
|
261
|
+
}: {
|
|
262
|
+
platform: Bundle["platform"];
|
|
263
|
+
channel: string;
|
|
264
|
+
minBundleId: string;
|
|
265
|
+
},
|
|
266
|
+
context?: HotUpdaterContext<TContext>,
|
|
267
|
+
): Promise<string[]> => {
|
|
268
|
+
const rows = await queryAll<{ target_app_version: string }>(
|
|
269
|
+
`
|
|
270
|
+
SELECT target_app_version
|
|
271
|
+
FROM bundles
|
|
272
|
+
WHERE channel = ?
|
|
273
|
+
AND platform = ?
|
|
274
|
+
AND enabled = 1
|
|
275
|
+
AND id >= ?
|
|
276
|
+
AND target_app_version IS NOT NULL
|
|
277
|
+
GROUP BY target_app_version
|
|
278
|
+
`,
|
|
279
|
+
[channel, platform, minBundleId],
|
|
280
|
+
context,
|
|
281
|
+
);
|
|
282
|
+
|
|
283
|
+
return rows.map((row) => row.target_app_version);
|
|
284
|
+
};
|
|
285
|
+
|
|
238
286
|
return {
|
|
287
|
+
getUpdateInfo: createDatabasePluginGetUpdateInfo({
|
|
288
|
+
listTargetAppVersions: getTargetAppVersionsForUpdateInfo,
|
|
289
|
+
getBundlesByTargetAppVersions(
|
|
290
|
+
{ platform, channel, minBundleId },
|
|
291
|
+
targetAppVersions,
|
|
292
|
+
context,
|
|
293
|
+
) {
|
|
294
|
+
return queryBundlesForUpdateInfo(
|
|
295
|
+
{
|
|
296
|
+
enabled: true,
|
|
297
|
+
platform,
|
|
298
|
+
channel,
|
|
299
|
+
id: {
|
|
300
|
+
gte: minBundleId,
|
|
301
|
+
},
|
|
302
|
+
targetAppVersionIn: targetAppVersions,
|
|
303
|
+
},
|
|
304
|
+
context,
|
|
305
|
+
);
|
|
306
|
+
},
|
|
307
|
+
getBundlesByFingerprint(
|
|
308
|
+
{ platform, channel, minBundleId, fingerprintHash },
|
|
309
|
+
context,
|
|
310
|
+
) {
|
|
311
|
+
return queryBundlesForUpdateInfo(
|
|
312
|
+
{
|
|
313
|
+
enabled: true,
|
|
314
|
+
platform,
|
|
315
|
+
channel,
|
|
316
|
+
id: {
|
|
317
|
+
gte: minBundleId,
|
|
318
|
+
},
|
|
319
|
+
fingerprintHash,
|
|
320
|
+
},
|
|
321
|
+
context,
|
|
322
|
+
);
|
|
323
|
+
},
|
|
324
|
+
}),
|
|
325
|
+
|
|
239
326
|
async getBundleById(bundleId, context) {
|
|
240
327
|
const row = await queryFirst<SnakeCaseBundle>(
|
|
241
328
|
"SELECT * FROM bundles WHERE id = ? LIMIT 1",
|
|
@@ -247,7 +334,11 @@ export const d1WorkerDatabase = <
|
|
|
247
334
|
},
|
|
248
335
|
|
|
249
336
|
async getBundles(options, context) {
|
|
250
|
-
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;
|
|
251
342
|
const { sql: whereClause, params } = buildWhereClause(where);
|
|
252
343
|
const orderSql =
|
|
253
344
|
orderBy?.direction === "asc"
|
package/src/d1Database.spec.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import type { DatabasePlugin } from "@hot-updater/plugin-core";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
setupBundleMethodsTestSuite,
|
|
4
|
+
setupGetUpdateInfoTestSuite,
|
|
5
|
+
} from "@hot-updater/test-utils";
|
|
3
6
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
4
7
|
|
|
5
8
|
import { d1Database } from "./d1Database";
|
|
@@ -178,6 +181,23 @@ vi.mock("cloudflare", () => ({
|
|
|
178
181
|
return createPage(result);
|
|
179
182
|
}
|
|
180
183
|
|
|
184
|
+
if (
|
|
185
|
+
normalizedSql.startsWith("select target_app_version from bundles")
|
|
186
|
+
) {
|
|
187
|
+
const { filteredRows } = getFilteredRows(sql, params);
|
|
188
|
+
const result = Array.from(
|
|
189
|
+
new Set(
|
|
190
|
+
filteredRows
|
|
191
|
+
.map((row) => row.target_app_version)
|
|
192
|
+
.filter((version): version is string => Boolean(version)),
|
|
193
|
+
),
|
|
194
|
+
).map((targetAppVersion) => ({
|
|
195
|
+
target_app_version: targetAppVersion,
|
|
196
|
+
}));
|
|
197
|
+
|
|
198
|
+
return createPage(result);
|
|
199
|
+
}
|
|
200
|
+
|
|
181
201
|
if (
|
|
182
202
|
normalizedSql.startsWith(
|
|
183
203
|
"select channel from bundles group by channel",
|
|
@@ -256,6 +276,19 @@ describe("d1Database plugin", () => {
|
|
|
256
276
|
},
|
|
257
277
|
});
|
|
258
278
|
|
|
279
|
+
setupGetUpdateInfoTestSuite({
|
|
280
|
+
getUpdateInfo: async (bundles, args) => {
|
|
281
|
+
rows.clear();
|
|
282
|
+
|
|
283
|
+
for (const bundle of bundles) {
|
|
284
|
+
await plugin.appendBundle(bundle);
|
|
285
|
+
}
|
|
286
|
+
await plugin.commitBundle();
|
|
287
|
+
|
|
288
|
+
return plugin.getUpdateInfo?.(args) ?? null;
|
|
289
|
+
},
|
|
290
|
+
});
|
|
291
|
+
|
|
259
292
|
it("refreshes bundle data before merging an update after a previous list request", async () => {
|
|
260
293
|
const bundleId = "bundle-stale-cache";
|
|
261
294
|
const initialRow: D1Row = {
|
|
@@ -276,7 +309,7 @@ describe("d1Database plugin", () => {
|
|
|
276
309
|
};
|
|
277
310
|
rows.set(bundleId, initialRow);
|
|
278
311
|
|
|
279
|
-
await plugin.getBundles({ limit: 20
|
|
312
|
+
await plugin.getBundles({ limit: 20 });
|
|
280
313
|
|
|
281
314
|
rows.set(bundleId, {
|
|
282
315
|
...initialRow,
|