@hot-updater/plugin-core 0.33.0 → 0.33.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/bundleUnitOfWork.cjs +158 -0
- package/dist/bundleUnitOfWork.mjs +158 -0
- package/dist/bundleUnitOfWorkStore.cjs +15 -0
- package/dist/bundleUnitOfWorkStore.mjs +15 -0
- package/dist/createBlobDatabasePlugin.cjs +80 -524
- package/dist/createBlobDatabasePlugin.d.cts +1 -4
- package/dist/createBlobDatabasePlugin.d.mts +1 -4
- package/dist/createBlobDatabasePlugin.mjs +80 -524
- package/dist/createDatabasePlugin.cjs +71 -32
- package/dist/createDatabasePlugin.mjs +71 -32
- package/dist/index.cjs +2 -1
- package/dist/index.d.cts +4 -4
- package/dist/index.d.mts +4 -4
- package/dist/index.mjs +3 -3
- package/dist/requestUpdateBundleState.cjs +15 -9
- package/dist/requestUpdateBundleState.d.cts +7 -1
- package/dist/requestUpdateBundleState.d.mts +7 -1
- package/dist/requestUpdateBundleState.mjs +15 -10
- package/dist/types/index.d.cts +1 -24
- package/dist/types/index.d.mts +1 -24
- package/package.json +8 -5
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { bundleMatchesQueryWhere, sortBundles } from "./queryBundles.mjs";
|
|
2
2
|
import { createDatabasePlugin } from "./createDatabasePlugin.mjs";
|
|
3
3
|
import { filterCompatibleAppVersions } from "./filterCompatibleAppVersions.mjs";
|
|
4
|
-
import { bundleMatchesQueryWhere, sortBundles } from "./queryBundles.mjs";
|
|
5
4
|
import { paginateBundles } from "./paginateBundles.mjs";
|
|
6
5
|
import { resolveUpdateInfoFromBundles } from "./resolveUpdateInfoFromBundles.mjs";
|
|
7
6
|
import { orderBy } from "es-toolkit";
|
|
@@ -65,140 +64,43 @@ function resolveStorageTarget({ targetAppVersion, fingerprintHash }) {
|
|
|
65
64
|
if (!target) throw new Error("target not found");
|
|
66
65
|
return target;
|
|
67
66
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
direction: "desc"
|
|
71
|
-
};
|
|
72
|
-
const MANAGEMENT_INDEX_PREFIX = "_index";
|
|
73
|
-
const MANAGEMENT_INDEX_VERSION = 1;
|
|
74
|
-
const DEFAULT_MANAGEMENT_INDEX_PAGE_SIZE = 128;
|
|
75
|
-
const ALL_SCOPE_CACHE_KEY = "*|*";
|
|
76
|
-
function summarizeManagementIndexArtifacts(artifacts) {
|
|
77
|
-
return {
|
|
78
|
-
pagesWritten: artifacts.pages.size,
|
|
79
|
-
scopesWritten: artifacts.scopes.length
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
function resolveManagementIndexPageSize(config) {
|
|
83
|
-
const pageSize = config.managementIndexPageSize ?? DEFAULT_MANAGEMENT_INDEX_PAGE_SIZE;
|
|
84
|
-
if (!Number.isInteger(pageSize) || pageSize < 1) throw new Error("managementIndexPageSize must be a positive integer.");
|
|
85
|
-
return pageSize;
|
|
86
|
-
}
|
|
87
|
-
function sortManagedBundles(bundles, orderBy = DEFAULT_DESC_ORDER) {
|
|
88
|
-
return sortBundles(bundles, orderBy);
|
|
89
|
-
}
|
|
90
|
-
function isDefaultManagementOrder(orderBy) {
|
|
91
|
-
return orderBy === void 0 || orderBy.field === DEFAULT_DESC_ORDER.field && orderBy.direction === DEFAULT_DESC_ORDER.direction;
|
|
67
|
+
function targetVersionMutationKey(bundle) {
|
|
68
|
+
return `${bundle.channel}/${bundle.platform}`;
|
|
92
69
|
}
|
|
93
|
-
function
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
70
|
+
function getTargetVersionMutation(mutations, bundle) {
|
|
71
|
+
const key = targetVersionMutationKey(bundle);
|
|
72
|
+
const existingMutation = mutations.get(key);
|
|
73
|
+
if (existingMutation) return existingMutation;
|
|
74
|
+
const mutation = {
|
|
75
|
+
additions: /* @__PURE__ */ new Set(),
|
|
76
|
+
channel: bundle.channel,
|
|
77
|
+
platform: bundle.platform,
|
|
78
|
+
removals: /* @__PURE__ */ new Set()
|
|
102
79
|
};
|
|
80
|
+
mutations.set(key, mutation);
|
|
81
|
+
return mutation;
|
|
103
82
|
}
|
|
104
|
-
function
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
return `${channel ?? "*"}|${platform ?? "*"}`;
|
|
109
|
-
}
|
|
110
|
-
function getManagementScopePrefix({ channel, platform }) {
|
|
111
|
-
if (channel && platform) return `${MANAGEMENT_INDEX_PREFIX}/channel/${encodeScopePart(channel)}/platform/${platform}`;
|
|
112
|
-
if (channel) return `${MANAGEMENT_INDEX_PREFIX}/channel/${encodeScopePart(channel)}`;
|
|
113
|
-
if (platform) return `${MANAGEMENT_INDEX_PREFIX}/platform/${platform}`;
|
|
114
|
-
return `${MANAGEMENT_INDEX_PREFIX}/all`;
|
|
115
|
-
}
|
|
116
|
-
function getManagementRootKey(scope) {
|
|
117
|
-
return `${getManagementScopePrefix(scope)}/root.json`;
|
|
118
|
-
}
|
|
119
|
-
function getManagementPageKey(scope, pageIndex) {
|
|
120
|
-
return `${getManagementScopePrefix(scope)}/pages/${String(pageIndex).padStart(4, "0")}.json`;
|
|
121
|
-
}
|
|
122
|
-
function createBundleWithUpdateJsonKey(bundle) {
|
|
123
|
-
const target = resolveStorageTarget(bundle);
|
|
124
|
-
return {
|
|
125
|
-
...bundle,
|
|
126
|
-
_updateJsonKey: `${bundle.channel}/${bundle.platform}/${target}/update.json`
|
|
127
|
-
};
|
|
83
|
+
function addTargetVersionAddition(mutations, bundle) {
|
|
84
|
+
const targetAppVersion = normalizeTargetAppVersion(bundle.targetAppVersion);
|
|
85
|
+
if (targetAppVersion == null) return;
|
|
86
|
+
getTargetVersionMutation(mutations, bundle).additions.add(targetAppVersion);
|
|
128
87
|
}
|
|
129
|
-
function
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
startOffsets.push(offset);
|
|
134
|
-
offset += page.count;
|
|
135
|
-
}
|
|
136
|
-
return startOffsets;
|
|
88
|
+
function addTargetVersionRemoval(mutations, bundle) {
|
|
89
|
+
const targetAppVersion = normalizeTargetAppVersion(bundle.targetAppVersion);
|
|
90
|
+
if (targetAppVersion == null) return;
|
|
91
|
+
getTargetVersionMutation(mutations, bundle).removals.add(targetAppVersion);
|
|
137
92
|
}
|
|
138
|
-
function
|
|
139
|
-
return {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
limit,
|
|
143
|
-
offset: 0
|
|
144
|
-
})
|
|
145
|
-
};
|
|
93
|
+
function getManagementListPrefixes(where) {
|
|
94
|
+
if (where?.channel && where.platform) return [`${where.channel}/${where.platform}/`];
|
|
95
|
+
if (where?.channel) return [`${where.channel}/`];
|
|
96
|
+
return [""];
|
|
146
97
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
if (!options?.includeChannels && scopeBundles.length === 0) return;
|
|
154
|
-
const pageKeys = [];
|
|
155
|
-
const pageDescriptors = [];
|
|
156
|
-
for (let pageIndex = 0; pageIndex * pageSize < scopeBundles.length; pageIndex++) {
|
|
157
|
-
const page = scopeBundles.slice(pageIndex * pageSize, (pageIndex + 1) * pageSize);
|
|
158
|
-
const key = getManagementPageKey(scope, pageIndex);
|
|
159
|
-
pages.set(key, page);
|
|
160
|
-
pageKeys.push(key);
|
|
161
|
-
pageDescriptors.push({
|
|
162
|
-
key,
|
|
163
|
-
count: page.length,
|
|
164
|
-
firstId: page[0].id,
|
|
165
|
-
lastId: page.at(-1).id
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
const root = {
|
|
169
|
-
version: MANAGEMENT_INDEX_VERSION,
|
|
170
|
-
pageSize,
|
|
171
|
-
total: scopeBundles.length,
|
|
172
|
-
pages: pageDescriptors,
|
|
173
|
-
...options?.includeChannels ? { channels } : {}
|
|
174
|
-
};
|
|
175
|
-
scopes.push({
|
|
176
|
-
cacheKey: getManagementScopeCacheKey(scope),
|
|
177
|
-
rootKey: getManagementRootKey(scope),
|
|
178
|
-
root,
|
|
179
|
-
pageKeys
|
|
180
|
-
});
|
|
181
|
-
};
|
|
182
|
-
addScope({}, sortedAllBundles, { includeChannels: true });
|
|
183
|
-
for (const channel of channels) {
|
|
184
|
-
const channelBundles = sortedAllBundles.filter((bundle) => bundle.channel === channel);
|
|
185
|
-
addScope({ channel }, channelBundles);
|
|
186
|
-
for (const platform of ["ios", "android"]) {
|
|
187
|
-
const scopedBundles = channelBundles.filter((bundle) => bundle.platform === platform);
|
|
188
|
-
addScope({
|
|
189
|
-
channel,
|
|
190
|
-
platform
|
|
191
|
-
}, scopedBundles);
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
for (const platform of ["ios", "android"]) {
|
|
195
|
-
const platformBundles = sortedAllBundles.filter((bundle) => bundle.platform === platform);
|
|
196
|
-
addScope({ platform }, platformBundles);
|
|
197
|
-
}
|
|
198
|
-
return {
|
|
199
|
-
pages,
|
|
200
|
-
scopes
|
|
201
|
-
};
|
|
98
|
+
const DEFAULT_DESC_ORDER = {
|
|
99
|
+
field: "id",
|
|
100
|
+
direction: "desc"
|
|
101
|
+
};
|
|
102
|
+
function sortManagedBundles(bundles, orderBy = DEFAULT_DESC_ORDER) {
|
|
103
|
+
return sortBundles(bundles, orderBy);
|
|
202
104
|
}
|
|
203
105
|
/**
|
|
204
106
|
* Creates a blob storage-based database plugin with lazy initialization.
|
|
@@ -209,11 +111,10 @@ function buildManagementIndexArtifacts(allBundles, pageSize) {
|
|
|
209
111
|
*/
|
|
210
112
|
const createBlobDatabasePlugin = ({ name, factory }) => {
|
|
211
113
|
return (config, hooks) => {
|
|
212
|
-
const managementIndexPageSize = resolveManagementIndexPageSize(config);
|
|
213
114
|
const { listObjects, loadObject, uploadObject, deleteObject, shouldSkipLoadObjectError, invalidatePaths, apiBasePath } = factory(config);
|
|
214
115
|
const bundlesMap = /* @__PURE__ */ new Map();
|
|
215
116
|
const pendingBundlesMap = /* @__PURE__ */ new Map();
|
|
216
|
-
const
|
|
117
|
+
const locallyDeletedBundleIds = /* @__PURE__ */ new Set();
|
|
217
118
|
const loadOptionalObject = async (key) => {
|
|
218
119
|
try {
|
|
219
120
|
return await loadObject(key);
|
|
@@ -222,291 +123,29 @@ const createBlobDatabasePlugin = ({ name, factory }) => {
|
|
|
222
123
|
throw error;
|
|
223
124
|
}
|
|
224
125
|
};
|
|
225
|
-
const
|
|
226
|
-
|
|
227
|
-
if (!allArtifact) throw new Error("all-bundles management index artifact not found");
|
|
228
|
-
return allArtifact;
|
|
229
|
-
};
|
|
230
|
-
const replaceManagementRootCache = (artifacts) => {
|
|
231
|
-
managementRootCache.clear();
|
|
232
|
-
for (const scope of artifacts.scopes) managementRootCache.set(scope.cacheKey, scope.root);
|
|
233
|
-
};
|
|
234
|
-
const createHydratedBundle = (bundle) => {
|
|
235
|
-
const hydratedBundle = createBundleWithUpdateJsonKey(bundle);
|
|
236
|
-
bundlesMap.set(hydratedBundle.id, hydratedBundle);
|
|
237
|
-
return hydratedBundle;
|
|
238
|
-
};
|
|
239
|
-
const loadStoredManagementRoot = async (scope) => {
|
|
240
|
-
const cacheKey = getManagementScopeCacheKey(scope);
|
|
241
|
-
const storedRoot = await loadOptionalObject(getManagementRootKey(scope));
|
|
242
|
-
if (storedRoot) {
|
|
243
|
-
managementRootCache.set(cacheKey, storedRoot);
|
|
244
|
-
return storedRoot;
|
|
245
|
-
}
|
|
246
|
-
managementRootCache.delete(cacheKey);
|
|
247
|
-
return null;
|
|
248
|
-
};
|
|
249
|
-
const loadManagementPage = async (descriptor, pageCache) => {
|
|
250
|
-
if (pageCache?.has(descriptor.key)) return pageCache.get(descriptor.key) ?? null;
|
|
251
|
-
const page = await loadOptionalObject(descriptor.key);
|
|
252
|
-
pageCache?.set(descriptor.key, page);
|
|
253
|
-
return page;
|
|
254
|
-
};
|
|
255
|
-
const loadBundleFromManagementRoot = async (root, bundleId) => {
|
|
256
|
-
const pageIndex = findPageIndexContainingId(root.pages, bundleId);
|
|
257
|
-
if (pageIndex < 0) return null;
|
|
258
|
-
const descriptor = root.pages[pageIndex];
|
|
259
|
-
const page = await loadManagementPage(descriptor);
|
|
260
|
-
if (!page) return null;
|
|
261
|
-
return page.find((item) => item.id === bundleId) ?? null;
|
|
262
|
-
};
|
|
263
|
-
const loadAllBundlesFromRoot = async (root) => {
|
|
264
|
-
const allBundles = [];
|
|
265
|
-
const pageCache = /* @__PURE__ */ new Map();
|
|
266
|
-
for (const descriptor of root.pages) {
|
|
267
|
-
const page = await loadManagementPage(descriptor, pageCache);
|
|
268
|
-
if (!page) return null;
|
|
269
|
-
allBundles.push(...page);
|
|
270
|
-
}
|
|
271
|
-
return allBundles;
|
|
272
|
-
};
|
|
273
|
-
const persistManagementIndexArtifacts = async (nextArtifacts, previousArtifacts) => {
|
|
274
|
-
await forEachWithConcurrency(Array.from(nextArtifacts.pages.entries()), STORAGE_OPERATION_CONCURRENCY, ([key, page]) => uploadObject(key, page));
|
|
275
|
-
await forEachWithConcurrency(nextArtifacts.scopes, STORAGE_OPERATION_CONCURRENCY, (scope) => uploadObject(scope.rootKey, scope.root));
|
|
276
|
-
if (!previousArtifacts) return;
|
|
277
|
-
const nextPageKeys = new Set(nextArtifacts.pages.keys());
|
|
278
|
-
const nextRootKeys = new Set(nextArtifacts.scopes.map((scope) => scope.rootKey));
|
|
279
|
-
await forEachWithConcurrency(Array.from(previousArtifacts.pages.keys()).filter((key) => !nextPageKeys.has(key)), STORAGE_OPERATION_CONCURRENCY, (key) => deleteObject(key).catch(() => {}));
|
|
280
|
-
await forEachWithConcurrency(previousArtifacts.scopes.filter((scope) => !nextRootKeys.has(scope.rootKey)), STORAGE_OPERATION_CONCURRENCY, (scope) => deleteObject(scope.rootKey).catch(() => {}));
|
|
281
|
-
};
|
|
282
|
-
const ensureAllManagementRoot = async () => {
|
|
283
|
-
const storedAllRoot = await loadStoredManagementRoot({});
|
|
284
|
-
if (storedAllRoot && storedAllRoot.pageSize === managementIndexPageSize) return storedAllRoot;
|
|
285
|
-
const rebuiltBundles = sortManagedBundles((await reloadBundles()).map((bundle) => removeBundleInternalKeys(bundle)));
|
|
286
|
-
const nextArtifacts = buildManagementIndexArtifacts(rebuiltBundles, managementIndexPageSize);
|
|
287
|
-
await persistManagementIndexArtifacts(nextArtifacts, storedAllRoot ? buildManagementIndexArtifacts(rebuiltBundles, storedAllRoot.pageSize) : void 0);
|
|
288
|
-
replaceManagementRootCache(nextArtifacts);
|
|
289
|
-
return getAllManagementArtifact(nextArtifacts).root;
|
|
290
|
-
};
|
|
291
|
-
const loadManagementScopeRoot = async (scope) => {
|
|
292
|
-
const cacheKey = getManagementScopeCacheKey(scope);
|
|
293
|
-
if (cacheKey === ALL_SCOPE_CACHE_KEY) return ensureAllManagementRoot();
|
|
294
|
-
const storedRoot = await loadStoredManagementRoot(scope);
|
|
295
|
-
if (storedRoot) return storedRoot;
|
|
296
|
-
await ensureAllManagementRoot();
|
|
297
|
-
const storedScopedRoot = await loadStoredManagementRoot(scope);
|
|
298
|
-
if (storedScopedRoot) return storedScopedRoot;
|
|
299
|
-
managementRootCache.set(cacheKey, null);
|
|
300
|
-
return null;
|
|
301
|
-
};
|
|
302
|
-
const loadAllBundlesForManagementFallback = async () => {
|
|
303
|
-
const allRoot = await loadManagementScopeRoot({});
|
|
304
|
-
if (allRoot) {
|
|
305
|
-
const pagedBundles = await loadAllBundlesFromRoot(allRoot);
|
|
306
|
-
if (pagedBundles) return pagedBundles;
|
|
307
|
-
}
|
|
308
|
-
return sortManagedBundles((await reloadBundles()).map((bundle) => removeBundleInternalKeys(bundle)));
|
|
309
|
-
};
|
|
310
|
-
const loadCurrentBundlesForIndexRebuild = async () => {
|
|
311
|
-
return loadAllBundlesForManagementFallback();
|
|
126
|
+
const loadAllBundlesForManagementFallback = async (where) => {
|
|
127
|
+
return sortManagedBundles((await reloadBundles(getManagementListPrefixes(where))).map((bundle) => removeBundleInternalKeys(bundle)));
|
|
312
128
|
};
|
|
313
|
-
const
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
const canonicalIds = new Set(canonicalBundles.map((bundle) => bundle.id));
|
|
320
|
-
const indexedIds = new Set(indexedBundles?.map((bundle) => bundle.id) ?? []);
|
|
321
|
-
const missingBundleIds = Array.from(canonicalIds).filter((id) => !indexedIds.has(id)).sort((left, right) => right.localeCompare(left));
|
|
322
|
-
const extraBundleIds = Array.from(indexedIds).filter((id) => !canonicalIds.has(id)).sort((left, right) => right.localeCompare(left));
|
|
323
|
-
return {
|
|
324
|
-
status: missingBundleIds.length === 0 && extraBundleIds.length === 0 && !rootMissing ? "ok" : rootMissing ? "missing" : "stale",
|
|
325
|
-
canonicalBundles: canonicalBundles.length,
|
|
326
|
-
indexedBundles: indexedBundles?.length ?? 0,
|
|
327
|
-
missingBundles: missingBundleIds.length,
|
|
328
|
-
extraBundles: extraBundleIds.length,
|
|
329
|
-
missingBundleIds: missingBundleIds.slice(0, 20),
|
|
330
|
-
extraBundleIds: extraBundleIds.slice(0, 20)
|
|
331
|
-
};
|
|
332
|
-
};
|
|
333
|
-
const findPageIndexContainingId = (pages, id) => {
|
|
334
|
-
return pages.findIndex((page) => id.localeCompare(page.firstId) <= 0 && id.localeCompare(page.lastId) >= 0);
|
|
335
|
-
};
|
|
336
|
-
const readPagedBundles = async ({ root, limit, offset, cursor }) => {
|
|
337
|
-
if (root.total === 0 || root.pages.length === 0) return createEmptyManagementResult(limit);
|
|
338
|
-
const pageStartOffsets = getPageStartOffsets(root.pages);
|
|
339
|
-
const pageCache = /* @__PURE__ */ new Map();
|
|
340
|
-
if (offset !== void 0) {
|
|
341
|
-
const normalizedOffset = Math.max(0, offset);
|
|
342
|
-
if (normalizedOffset >= root.total) return {
|
|
343
|
-
data: [],
|
|
344
|
-
pagination: calculatePagination(root.total, {
|
|
345
|
-
limit,
|
|
346
|
-
offset: normalizedOffset
|
|
347
|
-
})
|
|
348
|
-
};
|
|
349
|
-
let pageIndex = 0;
|
|
350
|
-
for (let index = pageStartOffsets.length - 1; index >= 0; index--) if ((pageStartOffsets[index] ?? 0) <= normalizedOffset) {
|
|
351
|
-
pageIndex = index;
|
|
352
|
-
break;
|
|
353
|
-
}
|
|
354
|
-
const startInPage = normalizedOffset - (pageStartOffsets[pageIndex] ?? 0);
|
|
355
|
-
const data = [];
|
|
356
|
-
for (let currentPageIndex = pageIndex; currentPageIndex < root.pages.length && (limit <= 0 || data.length < limit); currentPageIndex++) {
|
|
357
|
-
const descriptor = root.pages[currentPageIndex];
|
|
358
|
-
const page = await loadManagementPage(descriptor, pageCache);
|
|
359
|
-
if (!page) return paginateBundles({
|
|
360
|
-
bundles: await loadAllBundlesForManagementFallback(),
|
|
361
|
-
limit,
|
|
362
|
-
offset: normalizedOffset
|
|
363
|
-
});
|
|
364
|
-
data.push(...currentPageIndex === pageIndex ? page.slice(startInPage) : page);
|
|
365
|
-
}
|
|
366
|
-
const paginatedData = limit > 0 ? data.slice(0, limit) : data;
|
|
367
|
-
return {
|
|
368
|
-
data: paginatedData,
|
|
369
|
-
pagination: {
|
|
370
|
-
...calculatePagination(root.total, {
|
|
371
|
-
limit,
|
|
372
|
-
offset: normalizedOffset
|
|
373
|
-
}),
|
|
374
|
-
...paginatedData.length > 0 && normalizedOffset + paginatedData.length < root.total ? { nextCursor: paginatedData.at(-1)?.id } : {},
|
|
375
|
-
...paginatedData.length > 0 && normalizedOffset > 0 ? { previousCursor: paginatedData[0]?.id } : {}
|
|
376
|
-
}
|
|
377
|
-
};
|
|
378
|
-
}
|
|
379
|
-
if (cursor?.after) {
|
|
380
|
-
let pageIndex = root.pages.findIndex((page) => {
|
|
381
|
-
const containsCursor = cursor.after.localeCompare(page.firstId) <= 0 && cursor.after.localeCompare(page.lastId) >= 0;
|
|
382
|
-
const wholePageEligible = cursor.after.localeCompare(page.firstId) > 0;
|
|
383
|
-
return containsCursor || wholePageEligible;
|
|
384
|
-
});
|
|
385
|
-
if (pageIndex < 0) return {
|
|
386
|
-
data: [],
|
|
387
|
-
pagination: {
|
|
388
|
-
...calculatePagination(root.total, {
|
|
389
|
-
limit,
|
|
390
|
-
offset: root.total
|
|
391
|
-
}),
|
|
392
|
-
previousCursor: cursor.after
|
|
393
|
-
}
|
|
394
|
-
};
|
|
395
|
-
const data = [];
|
|
396
|
-
let startIndex = null;
|
|
397
|
-
while (pageIndex < root.pages.length && (limit <= 0 || data.length < limit)) {
|
|
398
|
-
const descriptor = root.pages[pageIndex];
|
|
399
|
-
const page = await loadManagementPage(descriptor, pageCache);
|
|
400
|
-
if (!page) return paginateBundles({
|
|
401
|
-
bundles: await loadAllBundlesForManagementFallback(),
|
|
402
|
-
limit,
|
|
403
|
-
cursor
|
|
404
|
-
});
|
|
405
|
-
const containsCursor = cursor.after.localeCompare(descriptor.firstId) <= 0 && cursor.after.localeCompare(descriptor.lastId) >= 0;
|
|
406
|
-
let eligiblePageBundles = page;
|
|
407
|
-
if (containsCursor) {
|
|
408
|
-
const startInPage = page.findIndex((bundle) => bundle.id.localeCompare(cursor.after) < 0);
|
|
409
|
-
if (startInPage < 0) eligiblePageBundles = [];
|
|
410
|
-
else {
|
|
411
|
-
eligiblePageBundles = page.slice(startInPage);
|
|
412
|
-
startIndex ??= (pageStartOffsets[pageIndex] ?? 0) + startInPage;
|
|
413
|
-
}
|
|
414
|
-
} else if (eligiblePageBundles.length > 0) startIndex ??= pageStartOffsets[pageIndex] ?? 0;
|
|
415
|
-
data.push(...eligiblePageBundles);
|
|
416
|
-
if (limit > 0 && data.length >= limit) break;
|
|
417
|
-
pageIndex += 1;
|
|
418
|
-
}
|
|
419
|
-
const paginatedData = limit > 0 ? data.slice(0, limit) : data;
|
|
420
|
-
const resolvedStartIndex = startIndex ?? root.total;
|
|
421
|
-
return {
|
|
422
|
-
data: paginatedData,
|
|
423
|
-
pagination: {
|
|
424
|
-
...calculatePagination(root.total, {
|
|
425
|
-
limit,
|
|
426
|
-
offset: resolvedStartIndex
|
|
427
|
-
}),
|
|
428
|
-
...paginatedData.length > 0 && resolvedStartIndex + paginatedData.length < root.total ? { nextCursor: paginatedData.at(-1)?.id } : {},
|
|
429
|
-
...paginatedData.length > 0 && resolvedStartIndex > 0 ? { previousCursor: paginatedData[0]?.id } : {}
|
|
430
|
-
}
|
|
431
|
-
};
|
|
432
|
-
}
|
|
433
|
-
if (cursor?.before) {
|
|
434
|
-
let pageIndex = -1;
|
|
435
|
-
for (let index = root.pages.length - 1; index >= 0; index--) {
|
|
436
|
-
const page = root.pages[index];
|
|
437
|
-
const containsCursor = cursor.before.localeCompare(page.firstId) <= 0 && cursor.before.localeCompare(page.lastId) >= 0;
|
|
438
|
-
const wholePageEligible = cursor.before.localeCompare(page.lastId) < 0;
|
|
439
|
-
if (containsCursor || wholePageEligible) {
|
|
440
|
-
pageIndex = index;
|
|
441
|
-
break;
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
if (pageIndex < 0) return createEmptyManagementResult(limit);
|
|
445
|
-
let startIndex = null;
|
|
446
|
-
let collected = [];
|
|
447
|
-
while (pageIndex >= 0 && (limit <= 0 || collected.length < limit)) {
|
|
448
|
-
const descriptor = root.pages[pageIndex];
|
|
449
|
-
const page = await loadManagementPage(descriptor, pageCache);
|
|
450
|
-
if (!page) return paginateBundles({
|
|
451
|
-
bundles: await loadAllBundlesForManagementFallback(),
|
|
452
|
-
limit,
|
|
453
|
-
cursor
|
|
454
|
-
});
|
|
455
|
-
const eligiblePageBundles = cursor.before.localeCompare(descriptor.firstId) <= 0 && cursor.before.localeCompare(descriptor.lastId) >= 0 ? page.filter((bundle) => bundle.id.localeCompare(cursor.before) > 0) : page;
|
|
456
|
-
collected = [...eligiblePageBundles, ...collected];
|
|
457
|
-
if (eligiblePageBundles.length > 0) startIndex = pageStartOffsets[pageIndex] ?? 0;
|
|
458
|
-
if (limit > 0 && collected.length >= limit) break;
|
|
459
|
-
pageIndex -= 1;
|
|
460
|
-
}
|
|
461
|
-
if (startIndex === null || collected.length === 0) return createEmptyManagementResult(limit);
|
|
462
|
-
let paginatedData = collected;
|
|
463
|
-
if (limit > 0 && collected.length > limit) {
|
|
464
|
-
const dropCount = collected.length - limit;
|
|
465
|
-
paginatedData = collected.slice(dropCount);
|
|
466
|
-
startIndex += dropCount;
|
|
467
|
-
}
|
|
468
|
-
const pagination = calculatePagination(root.total, {
|
|
469
|
-
limit,
|
|
470
|
-
offset: startIndex
|
|
471
|
-
});
|
|
472
|
-
return {
|
|
473
|
-
data: paginatedData,
|
|
474
|
-
pagination: {
|
|
475
|
-
...pagination,
|
|
476
|
-
...paginatedData.length > 0 && startIndex + paginatedData.length < root.total ? { nextCursor: paginatedData.at(-1)?.id } : {},
|
|
477
|
-
...paginatedData.length > 0 && startIndex > 0 ? { previousCursor: paginatedData[0]?.id } : {}
|
|
478
|
-
}
|
|
479
|
-
};
|
|
480
|
-
}
|
|
481
|
-
const pageIndex = 0;
|
|
482
|
-
const startInPage = 0;
|
|
483
|
-
const data = [];
|
|
484
|
-
for (let currentPageIndex = pageIndex; currentPageIndex < root.pages.length && (limit <= 0 || data.length < limit); currentPageIndex++) {
|
|
485
|
-
const descriptor = root.pages[currentPageIndex];
|
|
486
|
-
const page = await loadManagementPage(descriptor, pageCache);
|
|
487
|
-
if (!page) return paginateBundles({
|
|
488
|
-
bundles: await loadAllBundlesForManagementFallback(),
|
|
489
|
-
limit,
|
|
490
|
-
cursor
|
|
129
|
+
const cacheBundlesFromObject = (key, bundles) => {
|
|
130
|
+
for (const bundle of bundles) {
|
|
131
|
+
if (locallyDeletedBundleIds.has(bundle.id) || pendingBundlesMap.has(bundle.id)) continue;
|
|
132
|
+
bundlesMap.set(bundle.id, {
|
|
133
|
+
...bundle,
|
|
134
|
+
_updateJsonKey: key
|
|
491
135
|
});
|
|
492
|
-
data.push(...currentPageIndex === pageIndex ? page.slice(startInPage) : page);
|
|
493
136
|
}
|
|
494
|
-
const paginatedData = limit > 0 ? data.slice(0, limit) : data;
|
|
495
|
-
return {
|
|
496
|
-
data: paginatedData,
|
|
497
|
-
pagination: {
|
|
498
|
-
...calculatePagination(root.total, {
|
|
499
|
-
limit,
|
|
500
|
-
offset: 0
|
|
501
|
-
}),
|
|
502
|
-
...paginatedData.length > 0 && paginatedData.length < root.total ? { nextCursor: paginatedData.at(-1)?.id } : {}
|
|
503
|
-
}
|
|
504
|
-
};
|
|
505
137
|
};
|
|
506
|
-
async
|
|
138
|
+
const loadBundleObject = async (key) => {
|
|
139
|
+
const bundles = await loadOptionalObject(key) ?? [];
|
|
140
|
+
cacheBundlesFromObject(key, bundles);
|
|
141
|
+
return bundles;
|
|
142
|
+
};
|
|
143
|
+
async function reloadBundles(prefixes = [""]) {
|
|
507
144
|
bundlesMap.clear();
|
|
508
|
-
|
|
509
|
-
|
|
145
|
+
pendingBundlesMap.clear();
|
|
146
|
+
locallyDeletedBundleIds.clear();
|
|
147
|
+
const allBundles = (await mapWithConcurrency((await mapWithConcurrency(prefixes, STORAGE_OPERATION_CONCURRENCY, (prefix) => listObjects(prefix))).flat().filter((key) => /^[^/]+\/(?:ios|android)\/[^/]+\/update\.json$/.test(key)), STORAGE_OPERATION_CONCURRENCY, async (key) => {
|
|
148
|
+
return (await loadBundleObject(key)).map((bundle) => ({
|
|
510
149
|
...bundle,
|
|
511
150
|
_updateJsonKey: key
|
|
512
151
|
}));
|
|
@@ -515,39 +154,18 @@ const createBlobDatabasePlugin = ({ name, factory }) => {
|
|
|
515
154
|
for (const [id, bundle] of pendingBundlesMap.entries()) bundlesMap.set(id, bundle);
|
|
516
155
|
return orderBy(Array.from(bundlesMap.values()), [(v) => v.id], ["desc"]);
|
|
517
156
|
}
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
* Returns true if the file was updated, false if no changes were made.
|
|
521
|
-
*/
|
|
522
|
-
async function updateTargetVersionsForPlatform(platform) {
|
|
523
|
-
const updateJsonPattern = new RegExp(`^[^/]+/${platform}/[^/]+/update\\.json$`);
|
|
524
|
-
const targetVersionsPattern = new RegExp(`^[^/]+/${platform}/target-app-versions\\.json$`);
|
|
525
|
-
const allKeys = await listObjects("");
|
|
526
|
-
const updateJsonKeys = allKeys.filter((key) => updateJsonPattern.test(key));
|
|
527
|
-
const targetVersionsKeys = allKeys.filter((key) => targetVersionsPattern.test(key));
|
|
528
|
-
const keysByChannel = updateJsonKeys.reduce((acc, key) => {
|
|
529
|
-
const channel = key.split("/")[0];
|
|
530
|
-
acc[channel] = acc[channel] || [];
|
|
531
|
-
acc[channel].push(key);
|
|
532
|
-
return acc;
|
|
533
|
-
}, {});
|
|
534
|
-
for (const key of targetVersionsKeys) {
|
|
535
|
-
const channel = key.split("/")[0];
|
|
536
|
-
if (!keysByChannel[channel]) keysByChannel[channel] = [];
|
|
537
|
-
}
|
|
538
|
-
for (const channel of Object.keys(keysByChannel)) {
|
|
539
|
-
const updateKeys = keysByChannel[channel];
|
|
157
|
+
async function applyTargetVersionMutations(mutations) {
|
|
158
|
+
await Promise.all(Array.from(mutations.values()).map(async ({ additions, channel, platform, removals }) => {
|
|
540
159
|
const targetKey = `${channel}/${platform}/target-app-versions.json`;
|
|
541
|
-
const currentVersions = updateKeys.map((key) => key.split("/")[2]);
|
|
542
160
|
const oldTargetVersions = await loadOptionalObject(targetKey) ?? [];
|
|
543
|
-
const newTargetVersions = oldTargetVersions.filter((
|
|
544
|
-
for (const
|
|
161
|
+
const newTargetVersions = oldTargetVersions.filter((version) => !removals.has(version) || additions.has(version));
|
|
162
|
+
for (const version of additions) if (!newTargetVersions.includes(version)) newTargetVersions.push(version);
|
|
545
163
|
if (JSON.stringify(oldTargetVersions) !== JSON.stringify(newTargetVersions)) await uploadObject(targetKey, newTargetVersions);
|
|
546
|
-
}
|
|
164
|
+
}));
|
|
547
165
|
}
|
|
548
166
|
const getAppVersionUpdateInfo = async ({ appVersion, bundleId, channel = "production", cohort, minBundleId, platform }, context) => {
|
|
549
167
|
const bundles = (await mapWithConcurrency(filterCompatibleAppVersions(await loadOptionalObject(`${channel}/${platform}/target-app-versions.json`) ?? [], appVersion), STORAGE_OPERATION_CONCURRENCY, async (targetAppVersion) => {
|
|
550
|
-
return
|
|
168
|
+
return loadBundleObject(`${channel}/${platform}/${normalizeTargetAppVersion(targetAppVersion) ?? targetAppVersion}/update.json`);
|
|
551
169
|
})).flat();
|
|
552
170
|
return resolveUpdateInfoFromBundles({
|
|
553
171
|
args: {
|
|
@@ -564,7 +182,7 @@ const createBlobDatabasePlugin = ({ name, factory }) => {
|
|
|
564
182
|
});
|
|
565
183
|
};
|
|
566
184
|
const getFingerprintUpdateInfo = async ({ bundleId, channel = "production", cohort, fingerprintHash, minBundleId, platform }, context) => {
|
|
567
|
-
const bundles = await
|
|
185
|
+
const bundles = await loadBundleObject(`${channel}/${platform}/${fingerprintHash}/update.json`);
|
|
568
186
|
return resolveUpdateInfoFromBundles({
|
|
569
187
|
args: {
|
|
570
188
|
_updateStrategy: "fingerprint",
|
|
@@ -598,54 +216,16 @@ const createBlobDatabasePlugin = ({ name, factory }) => {
|
|
|
598
216
|
targetAppVersion
|
|
599
217
|
});
|
|
600
218
|
};
|
|
601
|
-
const bundleIndexDiagnostics = {
|
|
602
|
-
async check() {
|
|
603
|
-
const canonicalBundles = await loadCanonicalBundlesForIndexRepair();
|
|
604
|
-
const allRoot = await loadStoredManagementRoot({});
|
|
605
|
-
return compareBundleIndex({
|
|
606
|
-
canonicalBundles,
|
|
607
|
-
indexedBundles: allRoot ? await loadAllBundlesFromRoot(allRoot) : null,
|
|
608
|
-
rootMissing: !allRoot
|
|
609
|
-
});
|
|
610
|
-
},
|
|
611
|
-
async repair() {
|
|
612
|
-
const canonicalBundles = await loadCanonicalBundlesForIndexRepair();
|
|
613
|
-
const previousRoot = await loadStoredManagementRoot({});
|
|
614
|
-
const previousBundles = previousRoot ? await loadAllBundlesFromRoot(previousRoot) : null;
|
|
615
|
-
const previousArtifacts = previousRoot && previousBundles ? buildManagementIndexArtifacts(previousBundles, previousRoot.pageSize) : void 0;
|
|
616
|
-
const nextArtifacts = buildManagementIndexArtifacts(canonicalBundles, managementIndexPageSize);
|
|
617
|
-
const indexedObjectKeys = await listObjects(`${MANAGEMENT_INDEX_PREFIX}/`);
|
|
618
|
-
const nextObjectKeys = new Set([...nextArtifacts.pages.keys(), ...nextArtifacts.scopes.map((scope) => scope.rootKey)]);
|
|
619
|
-
await persistManagementIndexArtifacts(nextArtifacts, previousArtifacts);
|
|
620
|
-
await forEachWithConcurrency(indexedObjectKeys.filter((key) => !nextObjectKeys.has(key)), STORAGE_OPERATION_CONCURRENCY, (key) => deleteObject(key).catch(() => {}));
|
|
621
|
-
replaceManagementRootCache(nextArtifacts);
|
|
622
|
-
return {
|
|
623
|
-
scannedBundles: canonicalBundles.length,
|
|
624
|
-
indexedBundles: canonicalBundles.length,
|
|
625
|
-
...summarizeManagementIndexArtifacts(nextArtifacts)
|
|
626
|
-
};
|
|
627
|
-
}
|
|
628
|
-
};
|
|
629
219
|
const createPlugin = createDatabasePlugin({
|
|
630
220
|
name,
|
|
631
221
|
factory: () => ({
|
|
632
222
|
supportsCursorPagination: true,
|
|
633
223
|
async getBundleById(bundleId) {
|
|
224
|
+
if (locallyDeletedBundleIds.has(bundleId)) return null;
|
|
634
225
|
const pendingBundle = pendingBundlesMap.get(bundleId);
|
|
635
226
|
if (pendingBundle) return removeBundleInternalKeys(pendingBundle);
|
|
636
227
|
const bundle = bundlesMap.get(bundleId);
|
|
637
228
|
if (bundle) return removeBundleInternalKeys(bundle);
|
|
638
|
-
const allRoot = await loadManagementScopeRoot({});
|
|
639
|
-
if (allRoot) {
|
|
640
|
-
const matchedBundle = await loadBundleFromManagementRoot(allRoot, bundleId);
|
|
641
|
-
if (matchedBundle) return removeBundleInternalKeys(createHydratedBundle(matchedBundle));
|
|
642
|
-
managementRootCache.delete(ALL_SCOPE_CACHE_KEY);
|
|
643
|
-
const refreshedAllRoot = await loadStoredManagementRoot({});
|
|
644
|
-
if (refreshedAllRoot) {
|
|
645
|
-
const refreshedBundle = await loadBundleFromManagementRoot(refreshedAllRoot, bundleId);
|
|
646
|
-
if (refreshedBundle) return removeBundleInternalKeys(createHydratedBundle(refreshedBundle));
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
229
|
const matchedBundle = (await reloadBundles()).find((item) => item.id === bundleId);
|
|
650
230
|
if (!matchedBundle) return null;
|
|
651
231
|
return removeBundleInternalKeys(matchedBundle);
|
|
@@ -656,18 +236,7 @@ const createBlobDatabasePlugin = ({ name, factory }) => {
|
|
|
656
236
|
},
|
|
657
237
|
async getBundles(options) {
|
|
658
238
|
const { where, limit, offset, orderBy, cursor } = options;
|
|
659
|
-
|
|
660
|
-
if (scope) {
|
|
661
|
-
const root = await loadManagementScopeRoot(scope);
|
|
662
|
-
if (!root) return createEmptyManagementResult(limit);
|
|
663
|
-
return readPagedBundles({
|
|
664
|
-
root,
|
|
665
|
-
limit,
|
|
666
|
-
offset,
|
|
667
|
-
cursor
|
|
668
|
-
});
|
|
669
|
-
}
|
|
670
|
-
let allBundles = await loadAllBundlesForManagementFallback();
|
|
239
|
+
let allBundles = await loadAllBundlesForManagementFallback(where);
|
|
671
240
|
if (where) allBundles = allBundles.filter((bundle) => bundleMatchesQueryWhere(bundle, where));
|
|
672
241
|
return paginateBundles({
|
|
673
242
|
bundles: allBundles,
|
|
@@ -678,14 +247,15 @@ const createBlobDatabasePlugin = ({ name, factory }) => {
|
|
|
678
247
|
});
|
|
679
248
|
},
|
|
680
249
|
async getChannels() {
|
|
681
|
-
return (await
|
|
250
|
+
return [...new Set((await loadAllBundlesForManagementFallback()).map((bundle) => bundle.channel))].sort();
|
|
682
251
|
},
|
|
683
252
|
async commitBundle({ changedSets }) {
|
|
684
253
|
if (changedSets.length === 0) return;
|
|
685
254
|
const changedBundlesByKey = {};
|
|
686
255
|
const removalsByKey = {};
|
|
256
|
+
const targetVersionRemovalsByKey = {};
|
|
687
257
|
const pathsToInvalidate = /* @__PURE__ */ new Set();
|
|
688
|
-
const
|
|
258
|
+
const targetVersionMutations = /* @__PURE__ */ new Map();
|
|
689
259
|
for (const { operation, data } of changedSets) {
|
|
690
260
|
if (operation === "insert") {
|
|
691
261
|
const target = resolveStorageTarget(data);
|
|
@@ -694,11 +264,12 @@ const createBlobDatabasePlugin = ({ name, factory }) => {
|
|
|
694
264
|
...data,
|
|
695
265
|
_updateJsonKey: key
|
|
696
266
|
};
|
|
267
|
+
locallyDeletedBundleIds.delete(data.id);
|
|
697
268
|
bundlesMap.set(data.id, bundleWithKey);
|
|
698
269
|
pendingBundlesMap.set(data.id, bundleWithKey);
|
|
699
270
|
changedBundlesByKey[key] = changedBundlesByKey[key] || [];
|
|
700
271
|
changedBundlesByKey[key].push(removeBundleInternalKeys(bundleWithKey));
|
|
701
|
-
|
|
272
|
+
addTargetVersionAddition(targetVersionMutations, data);
|
|
702
273
|
addLookupInvalidationPaths(pathsToInvalidate, data);
|
|
703
274
|
continue;
|
|
704
275
|
}
|
|
@@ -708,10 +279,12 @@ const createBlobDatabasePlugin = ({ name, factory }) => {
|
|
|
708
279
|
if (!bundle) throw new Error("Bundle to delete not found");
|
|
709
280
|
bundlesMap.delete(data.id);
|
|
710
281
|
pendingBundlesMap.delete(data.id);
|
|
282
|
+
locallyDeletedBundleIds.add(data.id);
|
|
711
283
|
const key = bundle._updateJsonKey;
|
|
712
284
|
removalsByKey[key] = removalsByKey[key] || [];
|
|
713
285
|
removalsByKey[key].push(bundle.id);
|
|
714
|
-
|
|
286
|
+
targetVersionRemovalsByKey[key] = targetVersionRemovalsByKey[key] || [];
|
|
287
|
+
targetVersionRemovalsByKey[key].push(bundle);
|
|
715
288
|
addLookupInvalidationPaths(pathsToInvalidate, bundle);
|
|
716
289
|
continue;
|
|
717
290
|
}
|
|
@@ -728,11 +301,14 @@ const createBlobDatabasePlugin = ({ name, factory }) => {
|
|
|
728
301
|
const oldKey = bundle._updateJsonKey;
|
|
729
302
|
removalsByKey[oldKey] = removalsByKey[oldKey] || [];
|
|
730
303
|
removalsByKey[oldKey].push(bundle.id);
|
|
304
|
+
targetVersionRemovalsByKey[oldKey] = targetVersionRemovalsByKey[oldKey] || [];
|
|
305
|
+
targetVersionRemovalsByKey[oldKey].push(bundle);
|
|
731
306
|
changedBundlesByKey[newKey] = changedBundlesByKey[newKey] || [];
|
|
732
307
|
updatedBundle._oldUpdateJsonKey = oldKey;
|
|
733
308
|
updatedBundle._updateJsonKey = newKey;
|
|
734
309
|
bundlesMap.set(data.id, updatedBundle);
|
|
735
310
|
pendingBundlesMap.set(data.id, updatedBundle);
|
|
311
|
+
locallyDeletedBundleIds.delete(data.id);
|
|
736
312
|
changedBundlesByKey[newKey].push(removeBundleInternalKeys(updatedBundle));
|
|
737
313
|
const oldChannel = bundle.channel;
|
|
738
314
|
const nextChannel = updatedBundle.channel;
|
|
@@ -743,10 +319,7 @@ const createBlobDatabasePlugin = ({ name, factory }) => {
|
|
|
743
319
|
channel: nextChannel
|
|
744
320
|
});
|
|
745
321
|
}
|
|
746
|
-
|
|
747
|
-
targetVersionPlatforms.add(bundle.platform);
|
|
748
|
-
targetVersionPlatforms.add(updatedBundle.platform);
|
|
749
|
-
}
|
|
322
|
+
addTargetVersionAddition(targetVersionMutations, updatedBundle);
|
|
750
323
|
addLookupInvalidationPaths(pathsToInvalidate, updatedBundle);
|
|
751
324
|
if (bundle.targetAppVersion && bundle.targetAppVersion !== updatedBundle.targetAppVersion) addLookupInvalidationPaths(pathsToInvalidate, bundle);
|
|
752
325
|
continue;
|
|
@@ -754,17 +327,21 @@ const createBlobDatabasePlugin = ({ name, factory }) => {
|
|
|
754
327
|
const currentKey = bundle._updateJsonKey;
|
|
755
328
|
bundlesMap.set(data.id, updatedBundle);
|
|
756
329
|
pendingBundlesMap.set(data.id, updatedBundle);
|
|
330
|
+
locallyDeletedBundleIds.delete(data.id);
|
|
757
331
|
changedBundlesByKey[currentKey] = changedBundlesByKey[currentKey] || [];
|
|
758
332
|
changedBundlesByKey[currentKey].push(removeBundleInternalKeys(updatedBundle));
|
|
759
333
|
addLookupInvalidationPaths(pathsToInvalidate, updatedBundle);
|
|
334
|
+
addTargetVersionAddition(targetVersionMutations, updatedBundle);
|
|
760
335
|
if (bundle.targetAppVersion && bundle.targetAppVersion !== updatedBundle.targetAppVersion) addLookupInvalidationPaths(pathsToInvalidate, bundle);
|
|
761
336
|
}
|
|
762
337
|
}
|
|
763
338
|
await forEachWithConcurrency(Object.keys(removalsByKey), STORAGE_OPERATION_CONCURRENCY, async (oldKey) => {
|
|
764
339
|
const updatedBundles = (await loadOptionalObject(oldKey) ?? []).filter((b) => !removalsByKey[oldKey].includes(b.id));
|
|
765
340
|
updatedBundles.sort((a, b) => b.id.localeCompare(a.id));
|
|
766
|
-
if (updatedBundles.length === 0)
|
|
767
|
-
|
|
341
|
+
if (updatedBundles.length === 0) {
|
|
342
|
+
await deleteObject(oldKey);
|
|
343
|
+
for (const removedBundle of targetVersionRemovalsByKey[oldKey] ?? []) addTargetVersionRemoval(targetVersionMutations, removedBundle);
|
|
344
|
+
} else await uploadObject(oldKey, updatedBundles);
|
|
768
345
|
});
|
|
769
346
|
await forEachWithConcurrency(Object.keys(changedBundlesByKey), STORAGE_OPERATION_CONCURRENCY, async (key) => {
|
|
770
347
|
const currentBundles = await loadOptionalObject(key) ?? [];
|
|
@@ -777,22 +354,7 @@ const createBlobDatabasePlugin = ({ name, factory }) => {
|
|
|
777
354
|
currentBundles.sort((a, b) => b.id.localeCompare(a.id));
|
|
778
355
|
await uploadObject(key, currentBundles);
|
|
779
356
|
});
|
|
780
|
-
if (
|
|
781
|
-
const previousIndexBundles = await loadCurrentBundlesForIndexRebuild();
|
|
782
|
-
const storedIndexBundles = await loadStoredBundlesForIndexRebuild();
|
|
783
|
-
const nextIndexMap = new Map(storedIndexBundles.map((bundle) => [bundle.id, bundle]));
|
|
784
|
-
for (const { operation, data } of changedSets) {
|
|
785
|
-
if (operation === "delete") {
|
|
786
|
-
nextIndexMap.delete(data.id);
|
|
787
|
-
continue;
|
|
788
|
-
}
|
|
789
|
-
nextIndexMap.set(data.id, data);
|
|
790
|
-
}
|
|
791
|
-
const nextIndexBundles = sortManagedBundles(Array.from(nextIndexMap.values()));
|
|
792
|
-
const previousArtifacts = buildManagementIndexArtifacts(previousIndexBundles, managementIndexPageSize);
|
|
793
|
-
const nextArtifacts = buildManagementIndexArtifacts(nextIndexBundles, managementIndexPageSize);
|
|
794
|
-
await persistManagementIndexArtifacts(nextArtifacts, previousArtifacts);
|
|
795
|
-
replaceManagementRootCache(nextArtifacts);
|
|
357
|
+
if (targetVersionMutations.size > 0) await applyTargetVersionMutations(targetVersionMutations);
|
|
796
358
|
const encondedPaths = /* @__PURE__ */ new Set();
|
|
797
359
|
for (const path of pathsToInvalidate) encondedPaths.add(encodeURI(path));
|
|
798
360
|
await invalidatePaths(Array.from(encondedPaths));
|
|
@@ -801,13 +363,7 @@ const createBlobDatabasePlugin = ({ name, factory }) => {
|
|
|
801
363
|
})
|
|
802
364
|
})({}, hooks);
|
|
803
365
|
return () => {
|
|
804
|
-
|
|
805
|
-
Object.defineProperty(plugin, "diagnostics", {
|
|
806
|
-
configurable: true,
|
|
807
|
-
enumerable: true,
|
|
808
|
-
value: { bundleIndex: bundleIndexDiagnostics }
|
|
809
|
-
});
|
|
810
|
-
return plugin;
|
|
366
|
+
return createPlugin();
|
|
811
367
|
};
|
|
812
368
|
};
|
|
813
369
|
};
|