@hot-updater/cloudflare 0.36.7 → 1.0.0-rc.1
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 +988 -10
- package/dist/iac/index.mjs +991 -14
- package/dist/index.cjs +919 -6989
- package/dist/index.d.cts +11 -47
- package/dist/index.d.mts +11 -47
- package/dist/index.mjs +917 -7006
- package/dist/worker/index.cjs +898 -336
- package/dist/worker/index.d.cts +18 -33
- package/dist/worker/index.d.mts +18 -33
- package/dist/worker/index.mjs +899 -331
- package/package.json +7 -10
- package/sql/bundles.sql +183 -35
- package/src/d1Database.spec.ts +143 -392
- package/src/d1Database.ts +55 -650
- package/src/d1Implementation.spec.ts +252 -0
- package/src/d1Implementation.ts +742 -0
- package/src/d1Query.spec.ts +46 -0
- package/src/d1Query.ts +89 -0
- package/src/d1Rows.spec.ts +111 -0
- package/src/d1Rows.ts +326 -0
- package/src/d1Sql.spec.ts +30 -0
- package/src/d1Sql.ts +175 -0
- package/src/r2S3Storage.ts +93 -137
- package/src/r2Storage.spec.ts +120 -218
- package/src/r2Storage.ts +13 -61
- package/src/r2WorkerStorage.spec.ts +161 -50
- package/src/r2WorkerStorage.ts +85 -118
- package/src/worker/d1Database.spec.ts +33 -0
- package/src/worker/d1Database.ts +52 -0
- package/src/worker/index.ts +3 -31
- package/worker/dist/README.md +1 -1
- package/worker/dist/index.js +5968 -4701
- package/worker/dist/index.js.map +4 -4
- package/worker/migrations/0001_hot-updater_1.0.0.sql +205 -0
- package/worker/src/databaseMigration.integration.spec.ts +130 -0
- package/worker/src/databasePlugins.integration.spec.ts +292 -0
- package/worker/src/index.integration.spec.ts +102 -294
- package/worker/src/index.ts +14 -66
- package/worker/src/storagePlugin.integration.spec.ts +59 -0
- package/worker/wrangler.json +5 -2
- package/src/cloudflareWorkerDatabase.spec.ts +0 -260
- package/src/cloudflareWorkerDatabase.ts +0 -651
- package/src/r2WranglerStorage.ts +0 -193
- package/worker/migrations/0001_hot-updater_init.sql +0 -16
- package/worker/migrations/0002_hot-updater_0.13.0.sql +0 -8
- package/worker/migrations/0003_hot-updater_0.18.0.sql +0 -38
- package/worker/migrations/0004_hot-updater_0.29.0.sql +0 -11
- package/worker/migrations/0005_hot-updater_0.31.0.sql +0 -24
|
@@ -1,651 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
DEFAULT_ROLLOUT_COHORT_COUNT,
|
|
3
|
-
getAssetBaseStorageUri,
|
|
4
|
-
getBundlePatches,
|
|
5
|
-
getManifestFileHash,
|
|
6
|
-
getManifestStorageUri,
|
|
7
|
-
NIL_UUID,
|
|
8
|
-
stripBundleArtifactMetadata,
|
|
9
|
-
} from "@hot-updater/core";
|
|
10
|
-
import type {
|
|
11
|
-
Bundle,
|
|
12
|
-
DatabaseBundleQueryWhere,
|
|
13
|
-
HotUpdaterContext,
|
|
14
|
-
PaginationOptions,
|
|
15
|
-
RequestEnvContext,
|
|
16
|
-
} from "@hot-updater/plugin-core";
|
|
17
|
-
import {
|
|
18
|
-
calculatePagination,
|
|
19
|
-
createDatabasePlugin,
|
|
20
|
-
filterCompatibleAppVersions,
|
|
21
|
-
resolveUpdateInfoFromBundles,
|
|
22
|
-
} from "@hot-updater/plugin-core";
|
|
23
|
-
|
|
24
|
-
type D1Result<T> = {
|
|
25
|
-
results?: T[];
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
type D1PreparedStatement = {
|
|
29
|
-
bind: (...values: unknown[]) => {
|
|
30
|
-
all: <T>() => Promise<D1Result<T>>;
|
|
31
|
-
first: <T>() => Promise<T | null>;
|
|
32
|
-
run: () => Promise<unknown>;
|
|
33
|
-
};
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
type D1Like = {
|
|
37
|
-
prepare: (sql: string) => D1PreparedStatement;
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
export interface CloudflareWorkerDatabaseEnv {
|
|
41
|
-
DB: D1Like;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
interface CloudflareWorkerDatabaseConfig<
|
|
45
|
-
TContext extends RequestEnvContext<CloudflareWorkerDatabaseEnv>,
|
|
46
|
-
> {
|
|
47
|
-
getDb: (context?: HotUpdaterContext<TContext>) => D1Like;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
type QueryConditions = DatabaseBundleQueryWhere;
|
|
51
|
-
|
|
52
|
-
interface BuildQueryResult {
|
|
53
|
-
sql: string;
|
|
54
|
-
params: unknown[];
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const buildJsonEachInClause = (
|
|
58
|
-
columnName: string,
|
|
59
|
-
values: string[],
|
|
60
|
-
params: unknown[],
|
|
61
|
-
) => {
|
|
62
|
-
if (values.length === 0) {
|
|
63
|
-
return "1 = 0";
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
params.push(JSON.stringify(values));
|
|
67
|
-
return `${columnName} IN (SELECT value FROM json_each(?))`;
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
interface D1WorkerBundleRow {
|
|
71
|
-
id: string;
|
|
72
|
-
channel: string;
|
|
73
|
-
enabled: number | boolean;
|
|
74
|
-
should_force_update: number | boolean;
|
|
75
|
-
file_hash: string;
|
|
76
|
-
git_commit_hash: string | null;
|
|
77
|
-
message: string | null;
|
|
78
|
-
platform: "ios" | "android";
|
|
79
|
-
target_app_version: string | null;
|
|
80
|
-
storage_uri: string;
|
|
81
|
-
fingerprint_hash: string | null;
|
|
82
|
-
metadata: unknown;
|
|
83
|
-
manifest_storage_uri?: string | null;
|
|
84
|
-
manifest_file_hash?: string | null;
|
|
85
|
-
asset_base_storage_uri?: string | null;
|
|
86
|
-
rollout_cohort_count: number | null;
|
|
87
|
-
target_cohorts: string | null;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
interface D1WorkerBundlePatchRow {
|
|
91
|
-
id: string;
|
|
92
|
-
bundle_id: string;
|
|
93
|
-
base_bundle_id: string;
|
|
94
|
-
base_file_hash: string;
|
|
95
|
-
patch_file_hash: string;
|
|
96
|
-
patch_storage_uri: string;
|
|
97
|
-
order_index: number | null;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function buildWhereClause(
|
|
101
|
-
conditions: QueryConditions | undefined,
|
|
102
|
-
): BuildQueryResult {
|
|
103
|
-
if (!conditions) {
|
|
104
|
-
return { sql: "", params: [] };
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const clauses: string[] = [];
|
|
108
|
-
const params: unknown[] = [];
|
|
109
|
-
|
|
110
|
-
if (conditions.channel) {
|
|
111
|
-
clauses.push("channel = ?");
|
|
112
|
-
params.push(conditions.channel);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
if (conditions.platform) {
|
|
116
|
-
clauses.push("platform = ?");
|
|
117
|
-
params.push(conditions.platform);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
if (conditions.enabled !== undefined) {
|
|
121
|
-
clauses.push("enabled = ?");
|
|
122
|
-
params.push(conditions.enabled ? 1 : 0);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
if (conditions.id?.in) {
|
|
126
|
-
clauses.push(buildJsonEachInClause("id", conditions.id.in, params));
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
if (conditions.id?.eq) {
|
|
130
|
-
clauses.push("id = ?");
|
|
131
|
-
params.push(conditions.id.eq);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
if (conditions.id?.gt) {
|
|
135
|
-
clauses.push("id > ?");
|
|
136
|
-
params.push(conditions.id.gt);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
if (conditions.id?.gte) {
|
|
140
|
-
clauses.push("id >= ?");
|
|
141
|
-
params.push(conditions.id.gte);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
if (conditions.id?.lt) {
|
|
145
|
-
clauses.push("id < ?");
|
|
146
|
-
params.push(conditions.id.lt);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
if (conditions.id?.lte) {
|
|
150
|
-
clauses.push("id <= ?");
|
|
151
|
-
params.push(conditions.id.lte);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
if (conditions.targetAppVersionNotNull) {
|
|
155
|
-
clauses.push("target_app_version IS NOT NULL");
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
if (conditions.targetAppVersion !== undefined) {
|
|
159
|
-
if (conditions.targetAppVersion === null) {
|
|
160
|
-
clauses.push("target_app_version IS NULL");
|
|
161
|
-
} else {
|
|
162
|
-
clauses.push("target_app_version = ?");
|
|
163
|
-
params.push(conditions.targetAppVersion);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
if (conditions.targetAppVersionIn) {
|
|
168
|
-
clauses.push(
|
|
169
|
-
buildJsonEachInClause(
|
|
170
|
-
"target_app_version",
|
|
171
|
-
conditions.targetAppVersionIn,
|
|
172
|
-
params,
|
|
173
|
-
),
|
|
174
|
-
);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
if (conditions.fingerprintHash !== undefined) {
|
|
178
|
-
if (conditions.fingerprintHash === null) {
|
|
179
|
-
clauses.push("fingerprint_hash IS NULL");
|
|
180
|
-
} else {
|
|
181
|
-
clauses.push("fingerprint_hash = ?");
|
|
182
|
-
params.push(conditions.fingerprintHash);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
const whereClause =
|
|
187
|
-
clauses.length > 0 ? ` WHERE ${clauses.join(" AND ")}` : "";
|
|
188
|
-
|
|
189
|
-
return { sql: whereClause, params };
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
function parseTargetCohorts(value: unknown): string[] | null {
|
|
193
|
-
if (!value) return null;
|
|
194
|
-
if (Array.isArray(value)) {
|
|
195
|
-
return value.filter((item): item is string => typeof item === "string");
|
|
196
|
-
}
|
|
197
|
-
if (typeof value === "string") {
|
|
198
|
-
try {
|
|
199
|
-
const parsed = JSON.parse(value) as unknown;
|
|
200
|
-
if (Array.isArray(parsed)) {
|
|
201
|
-
return parsed.filter(
|
|
202
|
-
(item): item is string => typeof item === "string",
|
|
203
|
-
);
|
|
204
|
-
}
|
|
205
|
-
} catch {
|
|
206
|
-
return null;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
return null;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
const parseMetadata = (value: unknown): Bundle["metadata"] => {
|
|
213
|
-
if (!value) return undefined;
|
|
214
|
-
if (typeof value === "string") {
|
|
215
|
-
try {
|
|
216
|
-
return parseMetadata(JSON.parse(value) as unknown);
|
|
217
|
-
} catch {
|
|
218
|
-
return undefined;
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
return typeof value === "object" && !Array.isArray(value)
|
|
222
|
-
? (value as Bundle["metadata"])
|
|
223
|
-
: undefined;
|
|
224
|
-
};
|
|
225
|
-
|
|
226
|
-
const buildBundlePatchId = (bundleId: string, baseBundleId: string) =>
|
|
227
|
-
`${bundleId}:${baseBundleId}`;
|
|
228
|
-
|
|
229
|
-
const bundleToPatchRows = (bundle: Bundle): D1WorkerBundlePatchRow[] =>
|
|
230
|
-
getBundlePatches(bundle).map((patch, index) => ({
|
|
231
|
-
id: buildBundlePatchId(bundle.id, patch.baseBundleId),
|
|
232
|
-
bundle_id: bundle.id,
|
|
233
|
-
base_bundle_id: patch.baseBundleId,
|
|
234
|
-
base_file_hash: patch.baseFileHash,
|
|
235
|
-
patch_file_hash: patch.patchFileHash,
|
|
236
|
-
patch_storage_uri: patch.patchStorageUri,
|
|
237
|
-
order_index: index,
|
|
238
|
-
}));
|
|
239
|
-
|
|
240
|
-
function transformRowToBundle(
|
|
241
|
-
row: D1WorkerBundleRow,
|
|
242
|
-
patchRows: D1WorkerBundlePatchRow[] = [],
|
|
243
|
-
): Bundle {
|
|
244
|
-
const rawMetadata = parseMetadata(row.metadata);
|
|
245
|
-
const patches = patchRows
|
|
246
|
-
.slice()
|
|
247
|
-
.sort(
|
|
248
|
-
(left, right) =>
|
|
249
|
-
(left.order_index ?? 0) - (right.order_index ?? 0) ||
|
|
250
|
-
left.base_bundle_id.localeCompare(right.base_bundle_id),
|
|
251
|
-
)
|
|
252
|
-
.map((patch) => ({
|
|
253
|
-
baseBundleId: patch.base_bundle_id,
|
|
254
|
-
baseFileHash: patch.base_file_hash,
|
|
255
|
-
patchFileHash: patch.patch_file_hash,
|
|
256
|
-
patchStorageUri: patch.patch_storage_uri,
|
|
257
|
-
}));
|
|
258
|
-
const primaryPatch = patches[0] ?? null;
|
|
259
|
-
|
|
260
|
-
return {
|
|
261
|
-
id: row.id,
|
|
262
|
-
channel: row.channel,
|
|
263
|
-
enabled: Boolean(row.enabled),
|
|
264
|
-
shouldForceUpdate: Boolean(row.should_force_update),
|
|
265
|
-
fileHash: row.file_hash,
|
|
266
|
-
gitCommitHash: row.git_commit_hash,
|
|
267
|
-
message: row.message,
|
|
268
|
-
platform: row.platform,
|
|
269
|
-
targetAppVersion: row.target_app_version,
|
|
270
|
-
storageUri: row.storage_uri,
|
|
271
|
-
fingerprintHash: row.fingerprint_hash,
|
|
272
|
-
metadata: stripBundleArtifactMetadata(rawMetadata),
|
|
273
|
-
manifestStorageUri: row.manifest_storage_uri ?? null,
|
|
274
|
-
manifestFileHash: row.manifest_file_hash ?? null,
|
|
275
|
-
assetBaseStorageUri: row.asset_base_storage_uri ?? null,
|
|
276
|
-
patches,
|
|
277
|
-
patchBaseBundleId: primaryPatch?.baseBundleId ?? null,
|
|
278
|
-
patchBaseFileHash: primaryPatch?.baseFileHash ?? null,
|
|
279
|
-
patchFileHash: primaryPatch?.patchFileHash ?? null,
|
|
280
|
-
patchStorageUri: primaryPatch?.patchStorageUri ?? null,
|
|
281
|
-
rolloutCohortCount:
|
|
282
|
-
(row.rollout_cohort_count as number | null) ??
|
|
283
|
-
DEFAULT_ROLLOUT_COHORT_COUNT,
|
|
284
|
-
targetCohorts: parseTargetCohorts(row.target_cohorts as unknown),
|
|
285
|
-
};
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
const resolveDbFromContext = (
|
|
289
|
-
context?: RequestEnvContext<CloudflareWorkerDatabaseEnv>,
|
|
290
|
-
) => {
|
|
291
|
-
const db = context?.env?.DB;
|
|
292
|
-
|
|
293
|
-
if (!db) {
|
|
294
|
-
throw new Error(
|
|
295
|
-
"d1WorkerDatabase requires env.DB in the hot updater context.",
|
|
296
|
-
);
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
return db;
|
|
300
|
-
};
|
|
301
|
-
|
|
302
|
-
export const d1WorkerDatabase = <
|
|
303
|
-
TContext extends RequestEnvContext<CloudflareWorkerDatabaseEnv> =
|
|
304
|
-
RequestEnvContext<CloudflareWorkerDatabaseEnv>,
|
|
305
|
-
>() =>
|
|
306
|
-
createDatabasePlugin<CloudflareWorkerDatabaseConfig<TContext>, TContext>({
|
|
307
|
-
name: "d1WorkerDatabase",
|
|
308
|
-
factory: (config) => {
|
|
309
|
-
const queryAll = async <TRow>(
|
|
310
|
-
sql: string,
|
|
311
|
-
params: unknown[] = [],
|
|
312
|
-
context?: HotUpdaterContext<TContext>,
|
|
313
|
-
): Promise<TRow[]> => {
|
|
314
|
-
const result = await config
|
|
315
|
-
.getDb(context)
|
|
316
|
-
.prepare(sql)
|
|
317
|
-
.bind(...params)
|
|
318
|
-
.all<TRow>();
|
|
319
|
-
return result.results ?? [];
|
|
320
|
-
};
|
|
321
|
-
|
|
322
|
-
const queryFirst = async <TRow>(
|
|
323
|
-
sql: string,
|
|
324
|
-
params: unknown[] = [],
|
|
325
|
-
context?: HotUpdaterContext<TContext>,
|
|
326
|
-
): Promise<TRow | null> => {
|
|
327
|
-
const result = await config
|
|
328
|
-
.getDb(context)
|
|
329
|
-
.prepare(sql)
|
|
330
|
-
.bind(...params)
|
|
331
|
-
.first<TRow>();
|
|
332
|
-
return result ?? null;
|
|
333
|
-
};
|
|
334
|
-
|
|
335
|
-
const getPatchMap = async (
|
|
336
|
-
bundleIds: string[],
|
|
337
|
-
context?: HotUpdaterContext<TContext>,
|
|
338
|
-
) => {
|
|
339
|
-
const patchMap = new Map<string, D1WorkerBundlePatchRow[]>();
|
|
340
|
-
|
|
341
|
-
if (bundleIds.length === 0) {
|
|
342
|
-
return patchMap;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
const rows = await queryAll<D1WorkerBundlePatchRow>(
|
|
346
|
-
`
|
|
347
|
-
SELECT *
|
|
348
|
-
FROM bundle_patches
|
|
349
|
-
WHERE bundle_id IN (SELECT value FROM json_each(?))
|
|
350
|
-
ORDER BY order_index ASC, base_bundle_id ASC
|
|
351
|
-
`,
|
|
352
|
-
[JSON.stringify(bundleIds)],
|
|
353
|
-
context,
|
|
354
|
-
);
|
|
355
|
-
|
|
356
|
-
for (const row of rows) {
|
|
357
|
-
const current = patchMap.get(row.bundle_id) ?? [];
|
|
358
|
-
current.push(row);
|
|
359
|
-
patchMap.set(row.bundle_id, current);
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
return patchMap;
|
|
363
|
-
};
|
|
364
|
-
|
|
365
|
-
const queryBundlesForUpdateInfo = async (
|
|
366
|
-
conditions: QueryConditions,
|
|
367
|
-
context?: HotUpdaterContext<TContext>,
|
|
368
|
-
): Promise<Bundle[]> => {
|
|
369
|
-
const { sql: whereClause, params } = buildWhereClause(conditions);
|
|
370
|
-
const rows = await queryAll<D1WorkerBundleRow>(
|
|
371
|
-
`
|
|
372
|
-
SELECT * FROM bundles
|
|
373
|
-
${whereClause}
|
|
374
|
-
`,
|
|
375
|
-
params,
|
|
376
|
-
context,
|
|
377
|
-
);
|
|
378
|
-
const patchMap = await getPatchMap(
|
|
379
|
-
rows.map((row) => row.id),
|
|
380
|
-
context,
|
|
381
|
-
);
|
|
382
|
-
|
|
383
|
-
return rows.map((row) =>
|
|
384
|
-
transformRowToBundle(row, patchMap.get(row.id)),
|
|
385
|
-
);
|
|
386
|
-
};
|
|
387
|
-
|
|
388
|
-
const getTargetAppVersionsForUpdateInfo = async (
|
|
389
|
-
{
|
|
390
|
-
platform,
|
|
391
|
-
channel,
|
|
392
|
-
minBundleId,
|
|
393
|
-
}: {
|
|
394
|
-
platform: Bundle["platform"];
|
|
395
|
-
channel: string;
|
|
396
|
-
minBundleId: string;
|
|
397
|
-
},
|
|
398
|
-
context?: HotUpdaterContext<TContext>,
|
|
399
|
-
): Promise<string[]> => {
|
|
400
|
-
const rows = await queryAll<{ target_app_version: string }>(
|
|
401
|
-
`
|
|
402
|
-
SELECT target_app_version
|
|
403
|
-
FROM bundles
|
|
404
|
-
WHERE channel = ?
|
|
405
|
-
AND platform = ?
|
|
406
|
-
AND enabled = 1
|
|
407
|
-
AND id >= ?
|
|
408
|
-
AND target_app_version IS NOT NULL
|
|
409
|
-
GROUP BY target_app_version
|
|
410
|
-
`,
|
|
411
|
-
[channel, platform, minBundleId],
|
|
412
|
-
context,
|
|
413
|
-
);
|
|
414
|
-
|
|
415
|
-
return rows.map((row) => row.target_app_version);
|
|
416
|
-
};
|
|
417
|
-
|
|
418
|
-
return {
|
|
419
|
-
async getUpdateInfo(args, context) {
|
|
420
|
-
const channel = args.channel ?? "production";
|
|
421
|
-
const minBundleId = args.minBundleId ?? NIL_UUID;
|
|
422
|
-
|
|
423
|
-
if (args._updateStrategy === "appVersion") {
|
|
424
|
-
const targetAppVersions = await getTargetAppVersionsForUpdateInfo(
|
|
425
|
-
{
|
|
426
|
-
platform: args.platform,
|
|
427
|
-
channel,
|
|
428
|
-
minBundleId,
|
|
429
|
-
},
|
|
430
|
-
context,
|
|
431
|
-
);
|
|
432
|
-
const compatibleAppVersions = filterCompatibleAppVersions(
|
|
433
|
-
targetAppVersions,
|
|
434
|
-
args.appVersion,
|
|
435
|
-
);
|
|
436
|
-
const bundles =
|
|
437
|
-
compatibleAppVersions.length > 0
|
|
438
|
-
? await queryBundlesForUpdateInfo(
|
|
439
|
-
{
|
|
440
|
-
enabled: true,
|
|
441
|
-
platform: args.platform,
|
|
442
|
-
channel,
|
|
443
|
-
id: {
|
|
444
|
-
gte: minBundleId,
|
|
445
|
-
},
|
|
446
|
-
targetAppVersionIn: compatibleAppVersions,
|
|
447
|
-
},
|
|
448
|
-
context,
|
|
449
|
-
)
|
|
450
|
-
: [];
|
|
451
|
-
|
|
452
|
-
return resolveUpdateInfoFromBundles({
|
|
453
|
-
args: { ...args, channel, minBundleId },
|
|
454
|
-
bundles,
|
|
455
|
-
context,
|
|
456
|
-
});
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
const bundles = await queryBundlesForUpdateInfo(
|
|
460
|
-
{
|
|
461
|
-
enabled: true,
|
|
462
|
-
platform: args.platform,
|
|
463
|
-
channel,
|
|
464
|
-
id: {
|
|
465
|
-
gte: minBundleId,
|
|
466
|
-
},
|
|
467
|
-
fingerprintHash: args.fingerprintHash,
|
|
468
|
-
},
|
|
469
|
-
context,
|
|
470
|
-
);
|
|
471
|
-
|
|
472
|
-
return resolveUpdateInfoFromBundles({
|
|
473
|
-
args: { ...args, channel, minBundleId },
|
|
474
|
-
bundles,
|
|
475
|
-
context,
|
|
476
|
-
});
|
|
477
|
-
},
|
|
478
|
-
|
|
479
|
-
async getBundleById(bundleId, context) {
|
|
480
|
-
const [row, patchMap] = await Promise.all([
|
|
481
|
-
queryFirst<D1WorkerBundleRow>(
|
|
482
|
-
"SELECT * FROM bundles WHERE id = ? LIMIT 1",
|
|
483
|
-
[bundleId],
|
|
484
|
-
context,
|
|
485
|
-
),
|
|
486
|
-
getPatchMap([bundleId], context),
|
|
487
|
-
]);
|
|
488
|
-
|
|
489
|
-
return row ? transformRowToBundle(row, patchMap.get(bundleId)) : null;
|
|
490
|
-
},
|
|
491
|
-
|
|
492
|
-
async getBundles(options, context) {
|
|
493
|
-
const { where, limit, orderBy } = options;
|
|
494
|
-
const offset =
|
|
495
|
-
(("offset" in options ? options.offset : undefined) as
|
|
496
|
-
| number
|
|
497
|
-
| undefined) ?? 0;
|
|
498
|
-
const { sql: whereClause, params } = buildWhereClause(where);
|
|
499
|
-
const orderSql =
|
|
500
|
-
orderBy?.direction === "asc"
|
|
501
|
-
? "ORDER BY id ASC"
|
|
502
|
-
: "ORDER BY id DESC";
|
|
503
|
-
|
|
504
|
-
const countRows = await queryAll<{ total: number }>(
|
|
505
|
-
`SELECT COUNT(*) as total FROM bundles${whereClause}`,
|
|
506
|
-
params,
|
|
507
|
-
context,
|
|
508
|
-
);
|
|
509
|
-
const total = countRows[0]?.total ?? 0;
|
|
510
|
-
|
|
511
|
-
const rows = await queryAll<D1WorkerBundleRow>(
|
|
512
|
-
`SELECT * FROM bundles${whereClause} ${orderSql} LIMIT ? OFFSET ?`,
|
|
513
|
-
[...params, limit, offset],
|
|
514
|
-
context,
|
|
515
|
-
);
|
|
516
|
-
|
|
517
|
-
const patchMap = await getPatchMap(
|
|
518
|
-
rows.map((row) => row.id),
|
|
519
|
-
context,
|
|
520
|
-
);
|
|
521
|
-
const bundles = rows.map((row) =>
|
|
522
|
-
transformRowToBundle(row, patchMap.get(row.id)),
|
|
523
|
-
);
|
|
524
|
-
|
|
525
|
-
const paginationOptions: PaginationOptions = { limit, offset };
|
|
526
|
-
return {
|
|
527
|
-
data: bundles,
|
|
528
|
-
pagination: calculatePagination(total, paginationOptions),
|
|
529
|
-
};
|
|
530
|
-
},
|
|
531
|
-
|
|
532
|
-
async getChannels(context) {
|
|
533
|
-
const rows = await queryAll<{ channel: string }>(
|
|
534
|
-
"SELECT channel FROM bundles GROUP BY channel",
|
|
535
|
-
[],
|
|
536
|
-
context,
|
|
537
|
-
);
|
|
538
|
-
return rows.map((row) => row.channel);
|
|
539
|
-
},
|
|
540
|
-
|
|
541
|
-
async commitBundle({ changedSets }, context) {
|
|
542
|
-
if (changedSets.length === 0) {
|
|
543
|
-
return;
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
const db = config.getDb(context);
|
|
547
|
-
|
|
548
|
-
for (const operation of changedSets) {
|
|
549
|
-
if (operation.operation === "delete") {
|
|
550
|
-
await db
|
|
551
|
-
.prepare("DELETE FROM bundle_patches WHERE bundle_id = ?")
|
|
552
|
-
.bind(operation.data.id)
|
|
553
|
-
.run();
|
|
554
|
-
await db
|
|
555
|
-
.prepare("DELETE FROM bundle_patches WHERE base_bundle_id = ?")
|
|
556
|
-
.bind(operation.data.id)
|
|
557
|
-
.run();
|
|
558
|
-
await db
|
|
559
|
-
.prepare("DELETE FROM bundles WHERE id = ?")
|
|
560
|
-
.bind(operation.data.id)
|
|
561
|
-
.run();
|
|
562
|
-
continue;
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
const bundle = operation.data;
|
|
566
|
-
await db
|
|
567
|
-
.prepare(`
|
|
568
|
-
INSERT OR REPLACE INTO bundles (
|
|
569
|
-
id,
|
|
570
|
-
channel,
|
|
571
|
-
enabled,
|
|
572
|
-
should_force_update,
|
|
573
|
-
file_hash,
|
|
574
|
-
git_commit_hash,
|
|
575
|
-
message,
|
|
576
|
-
platform,
|
|
577
|
-
target_app_version,
|
|
578
|
-
storage_uri,
|
|
579
|
-
fingerprint_hash,
|
|
580
|
-
metadata,
|
|
581
|
-
manifest_storage_uri,
|
|
582
|
-
manifest_file_hash,
|
|
583
|
-
asset_base_storage_uri,
|
|
584
|
-
rollout_cohort_count,
|
|
585
|
-
target_cohorts
|
|
586
|
-
)
|
|
587
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
588
|
-
`)
|
|
589
|
-
.bind(
|
|
590
|
-
bundle.id,
|
|
591
|
-
bundle.channel,
|
|
592
|
-
bundle.enabled ? 1 : 0,
|
|
593
|
-
bundle.shouldForceUpdate ? 1 : 0,
|
|
594
|
-
bundle.fileHash,
|
|
595
|
-
bundle.gitCommitHash || null,
|
|
596
|
-
bundle.message || null,
|
|
597
|
-
bundle.platform,
|
|
598
|
-
bundle.targetAppVersion,
|
|
599
|
-
bundle.storageUri,
|
|
600
|
-
bundle.fingerprintHash,
|
|
601
|
-
JSON.stringify(
|
|
602
|
-
stripBundleArtifactMetadata(bundle.metadata) ?? {},
|
|
603
|
-
),
|
|
604
|
-
getManifestStorageUri(bundle),
|
|
605
|
-
getManifestFileHash(bundle),
|
|
606
|
-
getAssetBaseStorageUri(bundle),
|
|
607
|
-
bundle.rolloutCohortCount ?? DEFAULT_ROLLOUT_COHORT_COUNT,
|
|
608
|
-
bundle.targetCohorts
|
|
609
|
-
? JSON.stringify(bundle.targetCohorts)
|
|
610
|
-
: null,
|
|
611
|
-
)
|
|
612
|
-
.run();
|
|
613
|
-
|
|
614
|
-
await db
|
|
615
|
-
.prepare("DELETE FROM bundle_patches WHERE bundle_id = ?")
|
|
616
|
-
.bind(bundle.id)
|
|
617
|
-
.run();
|
|
618
|
-
|
|
619
|
-
const patchRows = bundleToPatchRows(bundle);
|
|
620
|
-
for (const patchRow of patchRows) {
|
|
621
|
-
await db
|
|
622
|
-
.prepare(`
|
|
623
|
-
INSERT OR REPLACE INTO bundle_patches (
|
|
624
|
-
id,
|
|
625
|
-
bundle_id,
|
|
626
|
-
base_bundle_id,
|
|
627
|
-
base_file_hash,
|
|
628
|
-
patch_file_hash,
|
|
629
|
-
patch_storage_uri,
|
|
630
|
-
order_index
|
|
631
|
-
)
|
|
632
|
-
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
633
|
-
`)
|
|
634
|
-
.bind(
|
|
635
|
-
patchRow.id,
|
|
636
|
-
patchRow.bundle_id,
|
|
637
|
-
patchRow.base_bundle_id,
|
|
638
|
-
patchRow.base_file_hash,
|
|
639
|
-
patchRow.patch_file_hash,
|
|
640
|
-
patchRow.patch_storage_uri,
|
|
641
|
-
patchRow.order_index ?? 0,
|
|
642
|
-
)
|
|
643
|
-
.run();
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
},
|
|
647
|
-
};
|
|
648
|
-
},
|
|
649
|
-
})({
|
|
650
|
-
getDb: resolveDbFromContext,
|
|
651
|
-
});
|