@hot-updater/server 0.36.7 → 1.0.0-rc.0
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/adapters/databaseConstraintErrors.cjs +23 -0
- package/dist/adapters/databaseConstraintErrors.mjs +21 -0
- package/dist/adapters/databasePluginUtils.cjs +117 -0
- package/dist/adapters/databasePluginUtils.mjs +106 -0
- package/dist/adapters/drizzle.cjs +53 -176
- package/dist/adapters/drizzle.d.cts +6 -4
- package/dist/adapters/drizzle.d.mts +6 -4
- package/dist/adapters/drizzle.mjs +54 -177
- package/dist/adapters/drizzleCrud.cjs +250 -0
- package/dist/adapters/drizzleCrud.mjs +249 -0
- package/dist/adapters/drizzleLazyDB.cjs +84 -36
- package/dist/adapters/drizzleLazyDB.mjs +84 -36
- package/dist/adapters/drizzleQuery.cjs +68 -0
- package/dist/adapters/drizzleQuery.mjs +67 -0
- package/dist/adapters/kysely.cjs +18 -138
- package/dist/adapters/kysely.d.cts +3 -12
- package/dist/adapters/kysely.d.mts +3 -12
- package/dist/adapters/kysely.mjs +19 -139
- package/dist/adapters/kyselyCrud.cjs +254 -0
- package/dist/adapters/kyselyCrud.mjs +253 -0
- package/dist/adapters/kyselyQuery.cjs +56 -0
- package/dist/adapters/kyselyQuery.mjs +55 -0
- package/dist/adapters/mongodb.cjs +21 -174
- package/dist/adapters/mongodb.d.cts +3 -2
- package/dist/adapters/mongodb.d.mts +3 -2
- package/dist/adapters/mongodb.mjs +21 -174
- package/dist/adapters/mongodbCollections.cjs +36 -0
- package/dist/adapters/mongodbCollections.mjs +30 -0
- package/dist/adapters/mongodbQuery.cjs +77 -0
- package/dist/adapters/mongodbQuery.mjs +70 -0
- package/dist/adapters/mongodbReads.cjs +148 -0
- package/dist/adapters/mongodbReads.mjs +147 -0
- package/dist/adapters/mongodbWrites.cjs +134 -0
- package/dist/adapters/mongodbWrites.mjs +133 -0
- package/dist/adapters/prisma.cjs +205 -180
- package/dist/adapters/prisma.d.cts +3 -3
- package/dist/adapters/prisma.d.mts +3 -3
- package/dist/adapters/prisma.mjs +206 -181
- package/dist/adapters/prismaQuery.cjs +58 -0
- package/dist/adapters/prismaQuery.mjs +56 -0
- package/dist/adapters/prismaRows.cjs +198 -0
- package/dist/adapters/prismaRows.mjs +188 -0
- package/dist/analytics/bounded/activeOverview.cjs +87 -0
- package/dist/analytics/bounded/activeOverview.mjs +85 -0
- package/dist/analytics/bounded/installationSearch.cjs +42 -0
- package/dist/analytics/bounded/installationSearch.mjs +42 -0
- package/dist/analytics/bounded/persistence.cjs +39 -0
- package/dist/analytics/bounded/persistence.mjs +38 -0
- package/dist/analytics/bounded/provider.cjs +170 -0
- package/dist/analytics/bounded/provider.d.cts +7 -0
- package/dist/analytics/bounded/provider.d.mts +7 -0
- package/dist/analytics/bounded/provider.mjs +170 -0
- package/dist/analytics/bounded/scan.cjs +144 -0
- package/dist/analytics/bounded/scan.mjs +138 -0
- package/dist/analytics/domain.d.cts +121 -0
- package/dist/analytics/domain.d.mts +121 -0
- package/dist/analytics/errors.cjs +22 -0
- package/dist/analytics/errors.mjs +20 -0
- package/dist/analytics/eventInput.cjs +111 -0
- package/dist/analytics/eventInput.mjs +111 -0
- package/dist/analytics/persistence.d.cts +6 -0
- package/dist/analytics/persistence.d.mts +6 -0
- package/dist/analytics/queryInput.cjs +58 -0
- package/dist/analytics/queryInput.mjs +55 -0
- package/dist/analytics/routes.cjs +63 -0
- package/dist/analytics/routes.mjs +61 -0
- package/dist/analytics/types.d.cts +17 -0
- package/dist/analytics/types.d.mts +17 -0
- package/dist/apiKeys.cjs +139 -0
- package/dist/apiKeys.d.cts +50 -0
- package/dist/apiKeys.d.mts +50 -0
- package/dist/apiKeys.mjs +133 -0
- package/dist/createHotUpdaterCore.cjs +48 -26
- package/dist/createHotUpdaterCore.d.cts +49 -17
- package/dist/createHotUpdaterCore.d.mts +49 -17
- package/dist/createHotUpdaterCore.mjs +51 -29
- package/dist/db/createBundleDiff.cjs +45 -68
- package/dist/db/createBundleDiff.d.cts +3 -3
- package/dist/db/createBundleDiff.d.mts +3 -3
- package/dist/db/createBundleDiff.mjs +47 -68
- package/dist/db/databasePluginCore.cjs +138 -0
- package/dist/db/databasePluginCore.mjs +137 -0
- package/dist/db/fixedMigrator.cjs +36 -93
- package/dist/db/fixedMigrator.mjs +36 -93
- package/dist/db/fixedMigratorMongo.cjs +319 -0
- package/dist/db/fixedMigratorMongo.mjs +319 -0
- package/dist/db/fixedMigratorShared.cjs +23 -0
- package/dist/db/fixedMigratorShared.mjs +18 -0
- package/dist/db/mongoMigrationExecution.cjs +11 -0
- package/dist/db/mongoMigrationExecution.mjs +11 -0
- package/dist/db/releaseCatalog.cjs +66 -0
- package/dist/db/releaseCatalog.d.cts +17 -0
- package/dist/db/releaseCatalog.d.mts +17 -0
- package/dist/db/releaseCatalog.mjs +64 -0
- package/dist/db/schema/mongodb.cjs +14 -6
- package/dist/db/schema/mongodb.mjs +14 -6
- package/dist/db/schema/registry.cjs +0 -2
- package/dist/db/schema/registry.mjs +1 -2
- package/dist/db/schema/sql.cjs +31 -14
- package/dist/db/schema/sql.mjs +32 -13
- package/dist/db/schema/sqlOperations.cjs +4 -4
- package/dist/db/schema/sqlOperations.mjs +5 -5
- package/dist/db/schemaGenerators.cjs +52 -18
- package/dist/db/schemaGenerators.mjs +52 -18
- package/dist/db/schemaReadiness.cjs +4 -3
- package/dist/db/schemaReadiness.mjs +4 -3
- package/dist/db/sqlMigrationExecution.cjs +67 -0
- package/dist/db/sqlMigrationExecution.mjs +66 -0
- package/dist/db/types.cjs +2 -6
- package/dist/db/types.d.cts +60 -16
- package/dist/db/types.d.mts +60 -16
- package/dist/db/types.mjs +3 -6
- package/dist/db/updateArtifacts.cjs +114 -60
- package/dist/db/updateArtifacts.mjs +117 -62
- package/dist/handler.cjs +108 -282
- package/dist/handler.d.cts +3 -46
- package/dist/handler.d.mts +3 -46
- package/dist/handler.mjs +107 -281
- package/dist/handlerBundleRoutes.cjs +155 -0
- package/dist/handlerBundleRoutes.mjs +155 -0
- package/dist/handlerErrors.cjs +9 -0
- package/dist/handlerErrors.mjs +9 -0
- package/dist/handlerParameters.cjs +39 -0
- package/dist/handlerParameters.mjs +34 -0
- package/dist/handlerReleaseCatalogRoutes.cjs +111 -0
- package/dist/handlerReleaseCatalogRoutes.mjs +110 -0
- package/dist/handlerReleaseManagementRoutes.cjs +125 -0
- package/dist/handlerReleaseManagementRoutes.mjs +124 -0
- package/dist/handlerTypes.d.cts +63 -0
- package/dist/handlerTypes.d.mts +63 -0
- package/dist/handlerVersionRoutes.cjs +10 -0
- package/dist/handlerVersionRoutes.d.cts +4 -0
- package/dist/handlerVersionRoutes.d.mts +4 -0
- package/dist/handlerVersionRoutes.mjs +9 -0
- package/dist/index.cjs +10 -1
- package/dist/index.d.cts +9 -3
- package/dist/index.d.mts +9 -3
- package/dist/index.mjs +5 -2
- package/dist/node.cjs +19 -12
- package/dist/node.d.cts +15 -10
- package/dist/node.d.mts +15 -10
- package/dist/node.mjs +19 -13
- package/dist/package.cjs +1 -1
- package/dist/package.mjs +1 -1
- package/dist/schema/dsl.cjs +19 -2
- package/dist/schema/dsl.mjs +17 -3
- package/dist/schema/index.cjs +1 -8
- package/dist/schema/index.mjs +2 -8
- package/dist/schema/types.cjs +3 -1
- package/dist/schema/types.mjs +3 -2
- package/dist/schema/v1_0_0.cjs +364 -0
- package/dist/schema/v1_0_0.mjs +357 -0
- package/dist/storageAccess.cjs +69 -25
- package/dist/storageAccess.mjs +68 -25
- package/dist/types/index.d.cts +4 -3
- package/dist/types/index.d.mts +5 -4
- package/package.json +8 -7
- package/src/adapters/databaseConstraintErrors.ts +25 -0
- package/src/adapters/databasePluginTestDatabase.ts +106 -0
- package/src/adapters/databasePluginUtils.spec.ts +29 -0
- package/src/adapters/databasePluginUtils.ts +214 -0
- package/src/adapters/drizzle.spec.ts +208 -47
- package/src/adapters/drizzle.ts +106 -293
- package/src/adapters/drizzleCrud.ts +419 -0
- package/src/adapters/drizzleLazyDB.ts +206 -100
- package/src/adapters/drizzleQuery.ts +164 -0
- package/src/adapters/kysely.spec.ts +126 -88
- package/src/adapters/kysely.ts +76 -334
- package/src/adapters/kyselyCrud.ts +588 -0
- package/src/adapters/kyselyQuery.ts +128 -0
- package/src/adapters/mongodb.spec.ts +141 -0
- package/src/adapters/mongodb.ts +60 -288
- package/src/adapters/mongodbCollections.ts +62 -0
- package/src/adapters/mongodbQuery.ts +226 -0
- package/src/adapters/mongodbReads.ts +311 -0
- package/src/adapters/mongodbRows.spec.ts +64 -0
- package/src/adapters/mongodbRows.ts +118 -0
- package/src/adapters/mongodbTestClient.ts +342 -0
- package/src/adapters/mongodbTestFilter.ts +166 -0
- package/src/adapters/mongodbWrites.ts +260 -0
- package/src/adapters/prisma.spec.ts +196 -0
- package/src/adapters/prisma.ts +417 -292
- package/src/adapters/prismaQuery.ts +129 -0
- package/src/adapters/prismaRows.spec.ts +98 -0
- package/src/adapters/prismaRows.ts +301 -0
- package/src/adapters/prismaTestClient.ts +396 -0
- package/src/analytics/analytics.integration.spec.ts +144 -0
- package/src/analytics/bounded/activeOverview.spec.ts +189 -0
- package/src/analytics/bounded/activeOverview.ts +148 -0
- package/src/analytics/bounded/installationSearch.spec.ts +130 -0
- package/src/analytics/bounded/installationSearch.ts +69 -0
- package/src/analytics/bounded/persistence.ts +43 -0
- package/src/analytics/bounded/provider.spec.ts +219 -0
- package/src/analytics/bounded/provider.ts +229 -0
- package/src/analytics/bounded/scan.ts +235 -0
- package/src/analytics/domain.ts +139 -0
- package/src/analytics/errors.ts +18 -0
- package/src/analytics/eventInput.ts +168 -0
- package/src/analytics/persistence.ts +10 -0
- package/src/analytics/queryInput.ts +102 -0
- package/src/analytics/routes.ts +123 -0
- package/src/analytics/types.ts +44 -0
- package/src/apiKeys.integration.spec.ts +192 -0
- package/src/apiKeys.spec.ts +162 -0
- package/src/apiKeys.ts +220 -0
- package/src/createHotUpdaterCore.ts +164 -100
- package/src/db/bundleRows.spec.ts +164 -0
- package/src/db/bundleRows.ts +10 -140
- package/src/db/createBundleDiff.spec.ts +172 -127
- package/src/db/createBundleDiff.ts +91 -110
- package/src/db/databasePluginCore.spec.ts +62 -0
- package/src/db/databasePluginCore.testFixtures.ts +76 -0
- package/src/db/databasePluginCore.ts +185 -0
- package/src/db/databasePluginUpdateCheck.bench.ts +107 -0
- package/src/db/fixedMigrator.spec.ts +184 -42
- package/src/db/fixedMigrator.ts +64 -205
- package/src/db/fixedMigratorMongo.spec.ts +192 -0
- package/src/db/fixedMigratorMongo.ts +425 -0
- package/src/db/fixedMigratorShared.ts +36 -0
- package/src/db/hotUpdaterSchema.ts +0 -1
- package/src/db/index.spec.ts +333 -1025
- package/src/db/mongoMigrationExecution.ts +23 -0
- package/src/db/node-sqlite.d.ts +25 -0
- package/src/db/releaseCatalog.ts +148 -0
- package/src/db/schema/mongodb.ts +20 -6
- package/src/db/schema/sql.ts +52 -11
- package/src/db/schema/sqlOperations.ts +5 -4
- package/src/db/schemaGenerators.ts +107 -23
- package/src/db/schemaReadiness.ts +2 -1
- package/src/db/sqlMigrationExecution.spec.ts +65 -0
- package/src/db/sqlMigrationExecution.ts +108 -0
- package/src/db/types.spec.ts +55 -0
- package/src/db/types.ts +129 -65
- package/src/db/updateArtifacts.spec.ts +359 -0
- package/src/db/updateArtifacts.ts +290 -126
- package/src/handler-standalone.integration.spec.ts +401 -364
- package/src/handler.spec.ts +137 -582
- package/src/handler.testFixtures.ts +30 -0
- package/src/handler.ts +218 -616
- package/src/handlerAuth.integration.spec.ts +33 -0
- package/src/handlerBundleRoutes.ts +259 -0
- package/src/handlerErrors.ts +7 -0
- package/src/handlerManagement.spec.ts +262 -0
- package/src/handlerParameters.ts +105 -0
- package/src/handlerReleaseCatalogRoutes.ts +154 -0
- package/src/handlerReleaseManagementRoutes.ts +213 -0
- package/src/handlerTypes.ts +96 -0
- package/src/handlerVersionRoutes.ts +12 -0
- package/src/index.ts +22 -2
- package/src/node.spec.ts +79 -10
- package/src/node.ts +20 -17
- package/src/releaseCatalogRoutes.integration.spec.ts +238 -0
- package/src/runtime.spec.ts +126 -959
- package/src/runtime.testFixtures.ts +71 -0
- package/src/schema/dsl-all-versions.spec.ts +26 -17
- package/src/schema/dsl.ts +41 -2
- package/src/schema/index.ts +3 -9
- package/src/schema/types.ts +9 -3
- package/src/schema/v1_0_0.spec.ts +146 -0
- package/src/schema/v1_0_0.ts +465 -0
- package/src/storageAccess.spec.ts +127 -32
- package/src/storageAccess.ts +106 -55
- package/src/types/index.ts +2 -1
- package/dist/db/bundleRows.cjs +0 -82
- package/dist/db/bundleRows.d.cts +0 -33
- package/dist/db/bundleRows.d.mts +0 -33
- package/dist/db/bundleRows.mjs +0 -79
- package/dist/db/pluginCore.cjs +0 -242
- package/dist/db/pluginCore.mjs +0 -241
- package/dist/db/schema/sqlMigrations.cjs +0 -74
- package/dist/db/schema/sqlMigrations.mjs +0 -73
- package/dist/db/schemaEnhancements.cjs +0 -20
- package/dist/db/schemaEnhancements.mjs +0 -19
- package/dist/route.cjs +0 -7
- package/dist/route.mjs +0 -7
- package/dist/schema/v0_21_0.cjs +0 -38
- package/dist/schema/v0_21_0.mjs +0 -37
- package/dist/schema/v0_29_0.cjs +0 -45
- package/dist/schema/v0_29_0.mjs +0 -44
- package/dist/schema/v0_31_0.cjs +0 -82
- package/dist/schema/v0_31_0.mjs +0 -80
- package/src/db/pluginCore.spec.ts +0 -1095
- package/src/db/pluginCore.ts +0 -475
- package/src/db/pluginUpdateCheck.bench.ts +0 -254
- package/src/db/schema/sqlMigrations.ts +0 -219
- package/src/db/schemaEnhancements.ts +0 -55
- package/src/route.ts +0 -7
- package/src/schema/v0_21_0.ts +0 -52
- package/src/schema/v0_29_0.ts +0 -62
- package/src/schema/v0_31_0.spec.ts +0 -73
- package/src/schema/v0_31_0.ts +0 -120
|
@@ -1,7 +1,20 @@
|
|
|
1
|
-
import { getManifestAssetDownloadPath, resolveManifestAssetStorageUri } from "@hot-updater/plugin-core";
|
|
2
|
-
import { getAssetBaseStorageUri, getBundlePatch, getManifestFileHash, getManifestStorageUri
|
|
1
|
+
import { getManifestAssetDownloadPath, isContentAddressedAssetFileHash, resolveManifestAssetStorageUri } from "@hot-updater/plugin-core";
|
|
2
|
+
import { getAssetBaseStorageUri, getBundlePatch, getManifestFileHash, getManifestStorageUri } from "@hot-updater/core";
|
|
3
3
|
//#region src/db/updateArtifacts.ts
|
|
4
4
|
const HBC_ASSET_PATH_RE = /\.bundle$/;
|
|
5
|
+
const asByteSize = (value) => typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : null;
|
|
6
|
+
const sumByteSizes = (byteSizes) => {
|
|
7
|
+
let total = 0;
|
|
8
|
+
for (const byteSize of byteSizes) {
|
|
9
|
+
if (byteSize === null || total > Number.MAX_SAFE_INTEGER - byteSize) return null;
|
|
10
|
+
total += byteSize;
|
|
11
|
+
}
|
|
12
|
+
return total;
|
|
13
|
+
};
|
|
14
|
+
const shouldUseArchive = (targetBundle, downloadByteSize) => {
|
|
15
|
+
const archiveByteSize = asByteSize(targetBundle.archiveByteSize);
|
|
16
|
+
return archiveByteSize !== null && downloadByteSize !== null && downloadByteSize >= archiveByteSize;
|
|
17
|
+
};
|
|
5
18
|
const resolveUniqueHbcAssetPath = (manifest) => {
|
|
6
19
|
const candidates = Object.keys(manifest.assets).sort((left, right) => left.localeCompare(right)).filter((candidate) => HBC_ASSET_PATH_RE.test(candidate));
|
|
7
20
|
return candidates.length === 1 ? candidates[0] : null;
|
|
@@ -17,19 +30,8 @@ const isBundleManifest = (value) => {
|
|
|
17
30
|
return typeof manifestAsset.fileHash === "string" && (manifestAsset.signature === void 0 || typeof manifestAsset.signature === "string");
|
|
18
31
|
});
|
|
19
32
|
};
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
let parsedValue = value;
|
|
23
|
-
if (typeof parsedValue === "string") try {
|
|
24
|
-
parsedValue = JSON.parse(parsedValue);
|
|
25
|
-
} catch {
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
if (!parsedValue || typeof parsedValue !== "object" || Array.isArray(parsedValue)) return;
|
|
29
|
-
return stripBundleArtifactMetadata(parsedValue);
|
|
30
|
-
};
|
|
31
|
-
async function fetchBundleManifest(storageUri, readStorageText, resolveFileUrl, context) {
|
|
32
|
-
const [storageText, fileUrl] = await Promise.all([readStorageText(storageUri, context), resolveFileUrl(storageUri, context)]);
|
|
33
|
+
async function fetchBundleManifest(storageUri, readStorageText) {
|
|
34
|
+
const storageText = await readStorageText(storageUri);
|
|
33
35
|
if (storageText === null) return null;
|
|
34
36
|
let payload;
|
|
35
37
|
try {
|
|
@@ -38,88 +40,141 @@ async function fetchBundleManifest(storageUri, readStorageText, resolveFileUrl,
|
|
|
38
40
|
return null;
|
|
39
41
|
}
|
|
40
42
|
if (!isBundleManifest(payload)) return null;
|
|
41
|
-
if (!fileUrl) return null;
|
|
42
43
|
return {
|
|
43
|
-
|
|
44
|
+
byteSize: asByteSize(new TextEncoder().encode(storageText).byteLength),
|
|
44
45
|
manifest: payload
|
|
45
46
|
};
|
|
46
47
|
}
|
|
47
|
-
|
|
48
|
-
const
|
|
48
|
+
function resolveHbcPatchPlan({ currentBundle, targetBundle, targetManifest }) {
|
|
49
|
+
const matchingPatch = currentBundle ? getBundlePatch(targetBundle, currentBundle.id) : null;
|
|
50
|
+
const patchAssetPath = resolveUniqueHbcAssetPath(targetManifest);
|
|
51
|
+
if (!currentBundle || !matchingPatch || !patchAssetPath || !matchingPatch.patchStorageUri || !matchingPatch.patchFileHash || !matchingPatch.baseFileHash) return null;
|
|
52
|
+
return {
|
|
53
|
+
assetPath: patchAssetPath,
|
|
54
|
+
patch: {
|
|
55
|
+
baseBundleId: matchingPatch.baseBundleId,
|
|
56
|
+
baseFileHash: matchingPatch.baseFileHash,
|
|
57
|
+
byteSize: asByteSize(matchingPatch.byteSize),
|
|
58
|
+
patchFileHash: matchingPatch.patchFileHash,
|
|
59
|
+
storageUri: matchingPatch.patchStorageUri
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function createManifestArtifactPlan({ assetBaseStorageUri, currentManifest, currentBundle, targetBundle, targetManifest, targetManifestByteSize }) {
|
|
64
|
+
const patchCandidate = resolveHbcPatchPlan({
|
|
49
65
|
currentBundle,
|
|
50
|
-
resolveFileUrl,
|
|
51
66
|
targetBundle,
|
|
52
|
-
targetManifest
|
|
53
|
-
context
|
|
67
|
+
targetManifest
|
|
54
68
|
});
|
|
55
|
-
const
|
|
56
|
-
if ((currentManifest?.assets[assetPath])?.fileHash === asset.fileHash) return
|
|
69
|
+
const changedAssets = Object.entries(targetManifest.assets).flatMap(([assetPath, asset]) => {
|
|
70
|
+
if ((currentManifest?.assets[assetPath])?.fileHash === asset.fileHash) return [];
|
|
71
|
+
const downloadByteSize = asByteSize(asset.downloadByteSize);
|
|
57
72
|
const downloadPath = getManifestAssetDownloadPath(assetPath);
|
|
58
|
-
const
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
73
|
+
const isTransformedDownload = downloadPath !== assetPath;
|
|
74
|
+
const hasValidDownloadFileHash = isContentAddressedAssetFileHash(asset.downloadFileHash);
|
|
75
|
+
const file = {
|
|
76
|
+
byteSize: downloadByteSize !== null && (hasValidDownloadFileHash || !isTransformedDownload && asset.downloadFileHash === void 0) ? downloadByteSize : null,
|
|
77
|
+
storageUri: resolveManifestAssetStorageUri({
|
|
78
|
+
assetBaseStorageUri,
|
|
79
|
+
assetPath: downloadPath,
|
|
80
|
+
downloadFileHash: asset.downloadFileHash,
|
|
81
|
+
fileHash: asset.fileHash
|
|
82
|
+
})
|
|
83
|
+
};
|
|
84
|
+
if (isTransformedDownload) file.compression = "br";
|
|
85
|
+
const patch = patchCandidate?.assetPath === assetPath ? patchCandidate.patch : null;
|
|
86
|
+
return [{
|
|
87
|
+
assetPath,
|
|
88
|
+
file,
|
|
89
|
+
fileHash: asset.fileHash,
|
|
90
|
+
patch
|
|
91
|
+
}];
|
|
92
|
+
});
|
|
93
|
+
const allPossibleByteSizesKnown = targetManifestByteSize !== null && changedAssets.every((asset) => asset.file.byteSize !== null && (asset.patch === null || asset.patch.byteSize !== null));
|
|
94
|
+
const primaryByteSizes = changedAssets.map((asset) => {
|
|
95
|
+
if (!asset.patch) return asset.file.byteSize;
|
|
96
|
+
if (asset.patch.byteSize === null || asset.file.byteSize === null) return null;
|
|
97
|
+
return Math.min(asset.patch.byteSize, asset.file.byteSize);
|
|
98
|
+
});
|
|
99
|
+
return {
|
|
100
|
+
allPossibleByteSizesKnown,
|
|
101
|
+
changedAssets,
|
|
102
|
+
manifestByteSize: targetManifestByteSize,
|
|
103
|
+
minimumDownloadByteSize: allPossibleByteSizesKnown ? sumByteSizes([targetManifestByteSize, ...primaryByteSizes]) : null
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
async function resolveChangedAssets(plan, resolveFileUrl) {
|
|
107
|
+
const patchAsset = plan.changedAssets.find((asset) => asset.patch !== null);
|
|
108
|
+
let resolvedPatch = null;
|
|
109
|
+
if (patchAsset?.patch) {
|
|
110
|
+
const patchUrl = await resolveFileUrl(patchAsset.patch.storageUri);
|
|
111
|
+
if (patchUrl) resolvedPatch = {
|
|
112
|
+
assetPath: patchAsset.assetPath,
|
|
113
|
+
patch: {
|
|
114
|
+
algorithm: "bsdiff",
|
|
115
|
+
baseBundleId: patchAsset.patch.baseBundleId,
|
|
116
|
+
baseFileHash: patchAsset.patch.baseFileHash,
|
|
117
|
+
patchFileHash: patchAsset.patch.patchFileHash,
|
|
118
|
+
patchUrl
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
const changedEntries = await Promise.all(plan.changedAssets.map(async (asset) => {
|
|
123
|
+
let patch = resolvedPatch?.assetPath === asset.assetPath ? resolvedPatch.patch : null;
|
|
65
124
|
let fileUrl = null;
|
|
66
125
|
try {
|
|
67
|
-
fileUrl = await resolveFileUrl(storageUri
|
|
126
|
+
fileUrl = await resolveFileUrl(asset.file.storageUri);
|
|
68
127
|
} catch (error) {
|
|
69
128
|
if (!patch) throw error;
|
|
70
129
|
}
|
|
71
|
-
if (
|
|
130
|
+
if (fileUrl && patch && asset.file.byteSize !== null && asset.patch !== null && asset.patch.byteSize !== null && asset.patch.byteSize >= asset.file.byteSize) patch = null;
|
|
131
|
+
if (!fileUrl && !patch) return null;
|
|
72
132
|
const changedAsset = { fileHash: asset.fileHash };
|
|
73
133
|
if (fileUrl) {
|
|
74
134
|
changedAsset.file = { url: fileUrl };
|
|
75
|
-
if (
|
|
135
|
+
if (asset.file.compression) changedAsset.file.compression = asset.file.compression;
|
|
76
136
|
}
|
|
77
137
|
if (patch) changedAsset.patch = patch;
|
|
78
|
-
return
|
|
138
|
+
return {
|
|
139
|
+
asset: [asset.assetPath, changedAsset],
|
|
140
|
+
primaryByteSize: patch ? asset.patch?.byteSize ?? null : asset.file.byteSize
|
|
141
|
+
};
|
|
79
142
|
}));
|
|
80
|
-
if (changedEntries.some((entry) => entry ===
|
|
81
|
-
|
|
82
|
-
}
|
|
83
|
-
async function resolveHbcPatchDescriptor({ currentBundle, resolveFileUrl, targetBundle, targetManifest, context }) {
|
|
84
|
-
const matchingPatch = targetBundle && currentBundle ? getBundlePatch(targetBundle, currentBundle.id) : null;
|
|
85
|
-
const patchAssetPath = resolveUniqueHbcAssetPath(targetManifest);
|
|
86
|
-
if (!currentBundle || !matchingPatch || !patchAssetPath || !matchingPatch.patchStorageUri || !matchingPatch.patchFileHash || !matchingPatch.baseFileHash) return null;
|
|
87
|
-
const patchUrl = await resolveFileUrl(matchingPatch.patchStorageUri, context);
|
|
88
|
-
if (!patchUrl) return null;
|
|
143
|
+
if (changedEntries.some((entry) => entry === null)) return null;
|
|
144
|
+
const resolvedEntries = changedEntries.filter((entry) => entry !== null);
|
|
89
145
|
return {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
algorithm: "bsdiff",
|
|
93
|
-
baseBundleId: matchingPatch.baseBundleId,
|
|
94
|
-
baseFileHash: matchingPatch.baseFileHash,
|
|
95
|
-
patchFileHash: matchingPatch.patchFileHash,
|
|
96
|
-
patchUrl
|
|
97
|
-
}
|
|
146
|
+
changedAssets: Object.fromEntries(resolvedEntries.map((entry) => entry.asset)),
|
|
147
|
+
primaryByteSizes: resolvedEntries.map((entry) => entry.primaryByteSize)
|
|
98
148
|
};
|
|
99
149
|
}
|
|
100
|
-
async function resolveManifestArtifacts({ currentBundle, resolveFileUrl, readStorageText, targetBundle
|
|
150
|
+
async function resolveManifestArtifacts({ archiveUrlUsable, currentBundle, resolveFileUrl, readStorageText, targetBundle }) {
|
|
101
151
|
const manifestStorageUri = targetBundle ? getManifestStorageUri(targetBundle) : null;
|
|
102
152
|
const manifestFileHash = targetBundle ? getManifestFileHash(targetBundle) : null;
|
|
103
153
|
const assetBaseStorageUri = targetBundle ? getAssetBaseStorageUri(targetBundle) : null;
|
|
104
|
-
if (!manifestStorageUri || !manifestFileHash || !assetBaseStorageUri) return null;
|
|
154
|
+
if (!targetBundle || !manifestStorageUri || !manifestFileHash || !assetBaseStorageUri) return null;
|
|
105
155
|
const currentManifestStorageUri = currentBundle ? getManifestStorageUri(currentBundle) : null;
|
|
106
|
-
const [targetManifestResult, currentManifestResult] = await Promise.all([fetchBundleManifest(manifestStorageUri, readStorageText
|
|
156
|
+
const [targetManifestResult, currentManifestResult] = await Promise.all([fetchBundleManifest(manifestStorageUri, readStorageText), currentManifestStorageUri ? fetchBundleManifest(currentManifestStorageUri, readStorageText) : null]);
|
|
107
157
|
if (!targetManifestResult) return null;
|
|
108
|
-
const
|
|
158
|
+
const plan = createManifestArtifactPlan({
|
|
109
159
|
assetBaseStorageUri,
|
|
110
160
|
currentManifest: currentManifestResult?.manifest ?? null,
|
|
111
161
|
currentBundle,
|
|
112
|
-
resolveFileUrl,
|
|
113
162
|
targetBundle,
|
|
114
163
|
targetManifest: targetManifestResult.manifest,
|
|
115
|
-
|
|
164
|
+
targetManifestByteSize: targetManifestResult.byteSize
|
|
116
165
|
});
|
|
117
|
-
if (
|
|
166
|
+
if (archiveUrlUsable && plan.allPossibleByteSizesKnown && shouldUseArchive(targetBundle, plan.minimumDownloadByteSize)) return null;
|
|
167
|
+
const manifestUrl = await resolveFileUrl(manifestStorageUri);
|
|
168
|
+
if (!manifestUrl) return null;
|
|
169
|
+
const resolved = await resolveChangedAssets(plan, resolveFileUrl);
|
|
170
|
+
if (!resolved) return null;
|
|
171
|
+
const resolvedDownloadByteSize = sumByteSizes([plan.manifestByteSize, ...resolved.primaryByteSizes]);
|
|
172
|
+
if (archiveUrlUsable && shouldUseArchive(targetBundle, resolvedDownloadByteSize)) return null;
|
|
118
173
|
return {
|
|
119
|
-
changedAssets,
|
|
174
|
+
changedAssets: resolved.changedAssets,
|
|
120
175
|
manifestFileHash,
|
|
121
|
-
manifestUrl
|
|
176
|
+
manifestUrl
|
|
122
177
|
};
|
|
123
178
|
}
|
|
124
179
|
//#endregion
|
|
125
|
-
export {
|
|
180
|
+
export { resolveManifestArtifacts };
|
package/dist/handler.cjs
CHANGED
|
@@ -1,294 +1,120 @@
|
|
|
1
|
-
require("./
|
|
1
|
+
const require_routes = require("./analytics/routes.cjs");
|
|
2
|
+
const require_handlerErrors = require("./handlerErrors.cjs");
|
|
3
|
+
const require_handlerBundleRoutes = require("./handlerBundleRoutes.cjs");
|
|
4
|
+
const require_handlerReleaseCatalogRoutes = require("./handlerReleaseCatalogRoutes.cjs");
|
|
5
|
+
const require_handlerReleaseManagementRoutes = require("./handlerReleaseManagementRoutes.cjs");
|
|
6
|
+
const require_handlerVersionRoutes = require("./handlerVersionRoutes.cjs");
|
|
2
7
|
const require_internalRouter = require("./internalRouter.cjs");
|
|
3
|
-
const require_version = require("./version.cjs");
|
|
4
|
-
let verkit = require("verkit");
|
|
5
8
|
//#region src/handler.ts
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const EXPLICIT_NO_UPDATE_MIN_SDK_VERSION = "0.31.0";
|
|
14
|
-
const DEFAULT_BUNDLE_LIST_LIMIT = 50;
|
|
15
|
-
const MAX_BUNDLE_LIST_LIMIT = 100;
|
|
16
|
-
const supportsExplicitNoUpdateResponse = (request) => {
|
|
17
|
-
const sdkVersion = request.headers.get(SDK_VERSION_HEADER)?.trim();
|
|
18
|
-
if (!sdkVersion) return false;
|
|
19
|
-
const normalizedSdkVersion = (0, verkit.normalize)(sdkVersion);
|
|
20
|
-
return normalizedSdkVersion !== null && (0, verkit.isGreaterOrEqual)(normalizedSdkVersion, EXPLICIT_NO_UPDATE_MIN_SDK_VERSION);
|
|
21
|
-
};
|
|
22
|
-
const serializeUpdateInfo = (updateInfo, request) => {
|
|
23
|
-
if (updateInfo) return JSON.stringify(updateInfo);
|
|
24
|
-
if (supportsExplicitNoUpdateResponse(request)) return JSON.stringify({ status: "UP_TO_DATE" });
|
|
25
|
-
return JSON.stringify(null);
|
|
26
|
-
};
|
|
27
|
-
const handleVersion = async () => {
|
|
28
|
-
return new Response(JSON.stringify({ version: require_version.HOT_UPDATER_SERVER_VERSION }), {
|
|
29
|
-
status: 200,
|
|
30
|
-
headers: { "Content-Type": "application/json" }
|
|
9
|
+
const withPrivateNoStore = (response) => {
|
|
10
|
+
const headers = new Headers(response.headers);
|
|
11
|
+
headers.set("cache-control", "private, no-store");
|
|
12
|
+
return new Response(response.body, {
|
|
13
|
+
headers,
|
|
14
|
+
status: response.status,
|
|
15
|
+
statusText: response.statusText
|
|
31
16
|
});
|
|
32
17
|
};
|
|
33
|
-
const
|
|
34
|
-
|
|
18
|
+
const errorResponse = (error, status) => Response.json({ error }, {
|
|
19
|
+
headers: { "cache-control": "private, no-store" },
|
|
20
|
+
status
|
|
21
|
+
});
|
|
22
|
+
const requiresApiKey = (handlerName) => handlerName === "appVersionReleaseCatalog" || handlerName === "fingerprintReleaseCatalog" || handlerName === "artifact" || handlerName === "appendBundleEvent";
|
|
23
|
+
const createRequestHandler = ({ api, apiKeyAuth, privateResponses = false, routeHandlers, router }) => async (request) => {
|
|
35
24
|
try {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
25
|
+
const match = require_internalRouter.findRoute(router, request.method, new URL(request.url).pathname);
|
|
26
|
+
if (!match) return errorResponse("Not found", 404);
|
|
27
|
+
if (apiKeyAuth !== void 0 && requiresApiKey(match.data)) {
|
|
28
|
+
let authenticated;
|
|
29
|
+
try {
|
|
30
|
+
authenticated = await apiKeyAuth.authenticate(request);
|
|
31
|
+
} catch {
|
|
32
|
+
return errorResponse("Service unavailable", 503);
|
|
33
|
+
}
|
|
34
|
+
if (!authenticated) return errorResponse("Unauthorized", 401);
|
|
35
|
+
}
|
|
36
|
+
const handler = routeHandlers[match.data];
|
|
37
|
+
if (!handler) return errorResponse("Handler not found", 500);
|
|
38
|
+
const response = await handler(match.params, request, api);
|
|
39
|
+
return privateResponses ? withPrivateNoStore(response) : response;
|
|
40
|
+
} catch (error) {
|
|
41
|
+
if (error instanceof require_handlerErrors.HandlerBadRequestError) return errorResponse(error.message, 400);
|
|
42
|
+
console.error("Hot Updater handler error:", error);
|
|
43
|
+
return Response.json({ error: "Internal server error" }, {
|
|
44
|
+
headers: { "cache-control": "private, no-store" },
|
|
45
|
+
status: 500
|
|
46
|
+
});
|
|
39
47
|
}
|
|
40
48
|
};
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const
|
|
46
|
-
if (!
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if (value === "false") return false;
|
|
54
|
-
throw new HandlerBadRequestError(`The '${key}' query parameter must be 'true' or 'false'.`);
|
|
55
|
-
};
|
|
56
|
-
const parseNullableStringSearchParam = (url, key) => {
|
|
57
|
-
const value = url.searchParams.get(key);
|
|
58
|
-
if (value === null) return;
|
|
59
|
-
return value === "null" ? null : value;
|
|
60
|
-
};
|
|
61
|
-
const parseStringArraySearchParam = (url, key) => {
|
|
62
|
-
const values = url.searchParams.getAll(key);
|
|
63
|
-
return values.length > 0 ? values : void 0;
|
|
64
|
-
};
|
|
65
|
-
const parsePositiveIntegerSearchParam = (url, key, defaultValue, maxValue) => {
|
|
66
|
-
const value = url.searchParams.get(key);
|
|
67
|
-
if (value === null) return defaultValue;
|
|
68
|
-
const parsed = Number(value);
|
|
69
|
-
if (!Number.isInteger(parsed) || parsed < 1 || parsed > maxValue) throw new HandlerBadRequestError(`The '${key}' query parameter must be a positive integer between 1 and ${maxValue}.`);
|
|
70
|
-
return parsed;
|
|
71
|
-
};
|
|
72
|
-
const requirePlatformParam = (params) => {
|
|
73
|
-
const platform = requireRouteParam(params, "platform");
|
|
74
|
-
if (!isPlatform(platform)) throw new HandlerBadRequestError(`Invalid platform: ${platform}. Expected 'ios' or 'android'.`);
|
|
75
|
-
return platform;
|
|
76
|
-
};
|
|
77
|
-
const requireBundlePatchPayload = (payload, bundleId) => {
|
|
78
|
-
if (!payload || typeof payload !== "object" || Array.isArray(payload)) throw new HandlerBadRequestError("Invalid bundle payload");
|
|
79
|
-
const bundlePatch = payload;
|
|
80
|
-
if (bundlePatch.id !== void 0 && bundlePatch.id !== bundleId) throw new HandlerBadRequestError("Bundle id mismatch");
|
|
81
|
-
const { id: _ignoredId, ...rest } = bundlePatch;
|
|
82
|
-
return rest;
|
|
83
|
-
};
|
|
84
|
-
const handleFingerprintUpdateWithCohort = async (params, request, api, context) => {
|
|
85
|
-
const platform = requirePlatformParam(params);
|
|
86
|
-
const fingerprintHash = requireRouteParam(params, "fingerprintHash");
|
|
87
|
-
const channel = requireRouteParam(params, "channel");
|
|
88
|
-
const minBundleId = requireRouteParam(params, "minBundleId");
|
|
89
|
-
const bundleId = requireRouteParam(params, "bundleId");
|
|
90
|
-
const updateInfo = await api.getAppUpdateInfo({
|
|
91
|
-
_updateStrategy: "fingerprint",
|
|
92
|
-
platform,
|
|
93
|
-
fingerprintHash,
|
|
94
|
-
channel,
|
|
95
|
-
minBundleId,
|
|
96
|
-
bundleId,
|
|
97
|
-
cohort: decodeMaybe(params.cohort)
|
|
98
|
-
}, context);
|
|
99
|
-
return new Response(serializeUpdateInfo(updateInfo, request), {
|
|
100
|
-
status: 200,
|
|
101
|
-
headers: { "Content-Type": "application/json" }
|
|
102
|
-
});
|
|
103
|
-
};
|
|
104
|
-
const handleAppVersionUpdateWithCohort = async (params, request, api, context) => {
|
|
105
|
-
const platform = requirePlatformParam(params);
|
|
106
|
-
const appVersion = requireRouteParam(params, "appVersion");
|
|
107
|
-
const channel = requireRouteParam(params, "channel");
|
|
108
|
-
const minBundleId = requireRouteParam(params, "minBundleId");
|
|
109
|
-
const bundleId = requireRouteParam(params, "bundleId");
|
|
110
|
-
const updateInfo = await api.getAppUpdateInfo({
|
|
111
|
-
_updateStrategy: "appVersion",
|
|
112
|
-
platform,
|
|
113
|
-
appVersion,
|
|
114
|
-
channel,
|
|
115
|
-
minBundleId,
|
|
116
|
-
bundleId,
|
|
117
|
-
cohort: decodeMaybe(params.cohort)
|
|
118
|
-
}, context);
|
|
119
|
-
return new Response(serializeUpdateInfo(updateInfo, request), {
|
|
120
|
-
status: 200,
|
|
121
|
-
headers: { "Content-Type": "application/json" }
|
|
122
|
-
});
|
|
123
|
-
};
|
|
124
|
-
const handleGetBundle = async (params, _request, api, context) => {
|
|
125
|
-
const bundleId = requireRouteParam(params, "id");
|
|
126
|
-
const bundle = await api.getBundleById(bundleId, context);
|
|
127
|
-
if (!bundle) return new Response(JSON.stringify({ error: "Bundle not found" }), {
|
|
128
|
-
status: 404,
|
|
129
|
-
headers: { "Content-Type": "application/json" }
|
|
130
|
-
});
|
|
131
|
-
return new Response(JSON.stringify(bundle), {
|
|
132
|
-
status: 200,
|
|
133
|
-
headers: { "Content-Type": "application/json" }
|
|
49
|
+
const createDownloadStorageRouteHandler = (downloadStorageObject) => async (params) => {
|
|
50
|
+
const token = params.token;
|
|
51
|
+
const signature = params.signature;
|
|
52
|
+
if (!token || !signature) return errorResponse("Not found", 404);
|
|
53
|
+
const response = await downloadStorageObject(token, signature);
|
|
54
|
+
if (!response) return errorResponse("Not found", 404);
|
|
55
|
+
const headers = new Headers(response.headers);
|
|
56
|
+
if (!headers.has("cache-control")) headers.set("cache-control", "public, max-age=31536000, immutable");
|
|
57
|
+
return new Response(response.body, {
|
|
58
|
+
headers,
|
|
59
|
+
status: response.status,
|
|
60
|
+
statusText: response.statusText
|
|
134
61
|
});
|
|
135
62
|
};
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
const targetAppVersionIn = parseStringArraySearchParam(url, "targetAppVersionIn");
|
|
148
|
-
const targetAppVersionNotNull = parseBooleanSearchParam(url, "targetAppVersionNotNull");
|
|
149
|
-
const fingerprintHash = parseNullableStringSearchParam(url, "fingerprintHash");
|
|
150
|
-
const idEq = url.searchParams.get("idEq") ?? void 0;
|
|
151
|
-
const idGt = url.searchParams.get("idGt") ?? void 0;
|
|
152
|
-
const idGte = url.searchParams.get("idGte") ?? void 0;
|
|
153
|
-
const idLt = url.searchParams.get("idLt") ?? void 0;
|
|
154
|
-
const idLte = url.searchParams.get("idLte") ?? void 0;
|
|
155
|
-
const idIn = parseStringArraySearchParam(url, "idIn");
|
|
156
|
-
const page = pageParam === null ? void 0 : Number.isInteger(Number(pageParam)) && Number(pageParam) > 0 ? Number(pageParam) : null;
|
|
157
|
-
if (offset !== null) throw new HandlerBadRequestError("The 'offset' query parameter has been removed. Use 'after' or 'before' cursor pagination instead.");
|
|
158
|
-
if (page === null) throw new HandlerBadRequestError("The 'page' query parameter must be a positive integer.");
|
|
159
|
-
if (platform !== null && !isPlatform(platform)) throw new HandlerBadRequestError(`Invalid platform: ${platform}. Expected 'ios' or 'android'.`);
|
|
160
|
-
const result = await api.getBundles({
|
|
161
|
-
where: {
|
|
162
|
-
...channel && { channel },
|
|
163
|
-
...platform && { platform },
|
|
164
|
-
...enabled !== void 0 && { enabled },
|
|
165
|
-
...idEq || idGt || idGte || idLt || idLte || idIn && idIn.length > 0 ? { id: {
|
|
166
|
-
...idEq && { eq: idEq },
|
|
167
|
-
...idGt && { gt: idGt },
|
|
168
|
-
...idGte && { gte: idGte },
|
|
169
|
-
...idLt && { lt: idLt },
|
|
170
|
-
...idLte && { lte: idLte },
|
|
171
|
-
...idIn && idIn.length > 0 && { in: idIn }
|
|
172
|
-
} } : {},
|
|
173
|
-
...targetAppVersion !== void 0 && { targetAppVersion },
|
|
174
|
-
...targetAppVersionIn && { targetAppVersionIn },
|
|
175
|
-
...targetAppVersionNotNull !== void 0 && { targetAppVersionNotNull },
|
|
176
|
-
...fingerprintHash !== void 0 && { fingerprintHash }
|
|
177
|
-
},
|
|
178
|
-
limit,
|
|
179
|
-
page,
|
|
180
|
-
cursor: after || before ? {
|
|
181
|
-
after,
|
|
182
|
-
before
|
|
183
|
-
} : void 0
|
|
184
|
-
}, context);
|
|
185
|
-
return new Response(JSON.stringify(result), {
|
|
186
|
-
status: 200,
|
|
187
|
-
headers: { "Content-Type": "application/json" }
|
|
188
|
-
});
|
|
189
|
-
};
|
|
190
|
-
const handleCreateBundles = async (_params, request, api, context) => {
|
|
191
|
-
const body = await request.json();
|
|
192
|
-
const bundles = Array.isArray(body) ? body : [body];
|
|
193
|
-
for (const bundle of bundles) await api.insertBundle(bundle, context);
|
|
194
|
-
return new Response(JSON.stringify({ success: true }), {
|
|
195
|
-
status: 201,
|
|
196
|
-
headers: { "Content-Type": "application/json" }
|
|
197
|
-
});
|
|
198
|
-
};
|
|
199
|
-
const handleUpdateBundle = async (params, request, api, context) => {
|
|
200
|
-
const bundleId = requireRouteParam(params, "id");
|
|
201
|
-
const body = await request.json();
|
|
202
|
-
const bundlePatch = requireBundlePatchPayload(Array.isArray(body) ? body[0] : body, bundleId);
|
|
203
|
-
await api.updateBundleById(bundleId, bundlePatch, context);
|
|
204
|
-
return new Response(JSON.stringify({ success: true }), {
|
|
205
|
-
status: 200,
|
|
206
|
-
headers: { "Content-Type": "application/json" }
|
|
207
|
-
});
|
|
208
|
-
};
|
|
209
|
-
const handleDeleteBundle = async (params, _request, api, context) => {
|
|
210
|
-
const bundleId = requireRouteParam(params, "id");
|
|
211
|
-
await api.deleteBundleById(bundleId, context);
|
|
212
|
-
return new Response(JSON.stringify({ success: true }), {
|
|
213
|
-
status: 200,
|
|
214
|
-
headers: { "Content-Type": "application/json" }
|
|
215
|
-
});
|
|
216
|
-
};
|
|
217
|
-
const handleGetChannels = async (_params, _request, api, context) => {
|
|
218
|
-
const response = { data: { channels: await api.getChannels(context) } };
|
|
219
|
-
return new Response(JSON.stringify(response), {
|
|
220
|
-
status: 200,
|
|
221
|
-
headers: { "Content-Type": "application/json" }
|
|
222
|
-
});
|
|
223
|
-
};
|
|
224
|
-
const routes = {
|
|
225
|
-
version: handleVersion,
|
|
226
|
-
fingerprintUpdateWithCohort: handleFingerprintUpdateWithCohort,
|
|
227
|
-
appVersionUpdateWithCohort: handleAppVersionUpdateWithCohort,
|
|
228
|
-
getBundle: handleGetBundle,
|
|
229
|
-
getBundles: handleGetBundles,
|
|
230
|
-
createBundles: handleCreateBundles,
|
|
231
|
-
updateBundle: handleUpdateBundle,
|
|
232
|
-
deleteBundle: handleDeleteBundle,
|
|
233
|
-
getChannels: handleGetChannels
|
|
234
|
-
};
|
|
235
|
-
/**
|
|
236
|
-
* Creates a Web Standard Request handler for Hot Updater API
|
|
237
|
-
* This handler is framework-agnostic and works with any runtime that
|
|
238
|
-
* supports standard Request/Response objects.
|
|
239
|
-
*/
|
|
240
|
-
function createHandler(api, options = {}) {
|
|
241
|
-
const basePath = options.basePath ?? "/api";
|
|
242
|
-
const routeOptions = {
|
|
243
|
-
updateCheck: options.routes?.updateCheck ?? true,
|
|
244
|
-
bundles: options.routes?.bundles ?? false
|
|
245
|
-
};
|
|
246
|
-
const router = require_internalRouter.createRouter();
|
|
247
|
-
require_internalRouter.addRoute(router, "GET", "/version", "version");
|
|
248
|
-
if (routeOptions.updateCheck) {
|
|
249
|
-
require_internalRouter.addRoute(router, "GET", "/fingerprint/:platform/:fingerprintHash/:channel/:minBundleId/:bundleId", "fingerprintUpdateWithCohort");
|
|
250
|
-
require_internalRouter.addRoute(router, "GET", "/fingerprint/:platform/:fingerprintHash/:channel/:minBundleId/:bundleId/:cohort", "fingerprintUpdateWithCohort");
|
|
251
|
-
require_internalRouter.addRoute(router, "GET", "/app-version/:platform/:appVersion/:channel/:minBundleId/:bundleId", "appVersionUpdateWithCohort");
|
|
252
|
-
require_internalRouter.addRoute(router, "GET", "/app-version/:platform/:appVersion/:channel/:minBundleId/:bundleId/:cohort", "appVersionUpdateWithCohort");
|
|
253
|
-
}
|
|
254
|
-
if (routeOptions.bundles) {
|
|
255
|
-
require_internalRouter.addRoute(router, "GET", "/api/bundles/channels", "getChannels");
|
|
256
|
-
require_internalRouter.addRoute(router, "GET", "/api/bundles/:id", "getBundle");
|
|
257
|
-
require_internalRouter.addRoute(router, "GET", "/api/bundles", "getBundles");
|
|
258
|
-
require_internalRouter.addRoute(router, "POST", "/api/bundles", "createBundles");
|
|
259
|
-
require_internalRouter.addRoute(router, "PATCH", "/api/bundles/:id", "updateBundle");
|
|
260
|
-
require_internalRouter.addRoute(router, "DELETE", "/api/bundles/:id", "deleteBundle");
|
|
261
|
-
}
|
|
262
|
-
return async (request, context) => {
|
|
263
|
-
try {
|
|
264
|
-
const path = new URL(request.url).pathname;
|
|
265
|
-
const method = request.method;
|
|
266
|
-
const match = require_internalRouter.findRoute(router, method, path.startsWith(basePath) ? path.slice(basePath.length) : path);
|
|
267
|
-
if (!match) return new Response(JSON.stringify({ error: "Not found" }), {
|
|
268
|
-
status: 404,
|
|
269
|
-
headers: { "Content-Type": "application/json" }
|
|
270
|
-
});
|
|
271
|
-
const handler = routes[match.data];
|
|
272
|
-
if (!handler) return new Response(JSON.stringify({ error: "Handler not found" }), {
|
|
273
|
-
status: 500,
|
|
274
|
-
headers: { "Content-Type": "application/json" }
|
|
275
|
-
});
|
|
276
|
-
return await handler(match.params || {}, request, api, context);
|
|
277
|
-
} catch (error) {
|
|
278
|
-
if (error instanceof HandlerBadRequestError) return new Response(JSON.stringify({ error: error.message }), {
|
|
279
|
-
status: 400,
|
|
280
|
-
headers: { "Content-Type": "application/json" }
|
|
281
|
-
});
|
|
282
|
-
console.error("Hot Updater handler error:", error);
|
|
283
|
-
return new Response(JSON.stringify({
|
|
284
|
-
error: "Internal server error",
|
|
285
|
-
message: error instanceof Error ? error.message : "Unknown error"
|
|
286
|
-
}), {
|
|
287
|
-
status: 500,
|
|
288
|
-
headers: { "Content-Type": "application/json" }
|
|
289
|
-
});
|
|
290
|
-
}
|
|
63
|
+
function createHandlers(api) {
|
|
64
|
+
return createHotUpdaterHandlers(api);
|
|
65
|
+
}
|
|
66
|
+
function createHotUpdaterHandlers(api, analytics, apiKeyAuth, downloadStorageObject) {
|
|
67
|
+
const routeHandlers = {
|
|
68
|
+
...require_handlerVersionRoutes.createVersionRouteHandlers(),
|
|
69
|
+
...require_handlerReleaseCatalogRoutes.createReleaseCatalogRouteHandlers(apiKeyAuth?.headerName),
|
|
70
|
+
...require_handlerReleaseManagementRoutes.createReleaseManagementRouteHandlers(),
|
|
71
|
+
...require_handlerBundleRoutes.createBundleRouteHandlers(),
|
|
72
|
+
...analytics === void 0 ? {} : require_routes.createAnalyticsRouteHandlers(analytics),
|
|
73
|
+
...downloadStorageObject === void 0 ? {} : { downloadStorageObject: createDownloadStorageRouteHandler(downloadStorageObject) }
|
|
291
74
|
};
|
|
75
|
+
const clientRouter = require_internalRouter.createRouter();
|
|
76
|
+
const addClientRoute = (method, path, handler) => require_internalRouter.addRoute(clientRouter, method, path, handler);
|
|
77
|
+
addClientRoute("GET", "/version", "version");
|
|
78
|
+
if (downloadStorageObject !== void 0) addClientRoute("GET", "/storage/:token/:signature", "downloadStorageObject");
|
|
79
|
+
addClientRoute("GET", "/release-catalogs/app-version/:platform/:channelKey/:appVersion", "appVersionReleaseCatalog");
|
|
80
|
+
addClientRoute("GET", "/release-catalogs/fingerprint/:platform/:channelKey/:fingerprintHash", "fingerprintReleaseCatalog");
|
|
81
|
+
addClientRoute("GET", "/artifacts/:targetBundleId/from/:currentBundleId", "artifact");
|
|
82
|
+
if (analytics !== void 0) require_routes.registerAnalyticsClientRoutes(addClientRoute);
|
|
83
|
+
const adminRouter = require_internalRouter.createRouter();
|
|
84
|
+
const addAdminRoute = (method, path, handler) => require_internalRouter.addRoute(adminRouter, method, path, handler);
|
|
85
|
+
addAdminRoute("GET", "/releases/:id", "getRelease");
|
|
86
|
+
addAdminRoute("GET", "/releases", "getReleases");
|
|
87
|
+
addAdminRoute("PATCH", "/releases/:id", "updateRelease");
|
|
88
|
+
addAdminRoute("POST", "/releases/:id/preflight", "preflightRelease");
|
|
89
|
+
addAdminRoute("DELETE", "/releases/:id", "deleteRelease");
|
|
90
|
+
addAdminRoute("GET", "/release-catalogs/:scopeKey", "getReleaseCatalogRow");
|
|
91
|
+
addAdminRoute("GET", "/release-catalogs", "getReleaseCatalogs");
|
|
92
|
+
addAdminRoute("POST", "/release-catalogs/:scopeKey/rebuild", "rebuildReleaseCatalog");
|
|
93
|
+
addAdminRoute("POST", "/database/commit", "commitDatabase");
|
|
94
|
+
addAdminRoute("GET", "/channels", "getChannels");
|
|
95
|
+
addAdminRoute("POST", "/channels", "createChannel");
|
|
96
|
+
addAdminRoute("DELETE", "/channels/:id", "deleteChannel");
|
|
97
|
+
addAdminRoute("GET", "/bundles/:id", "getBundle");
|
|
98
|
+
addAdminRoute("GET", "/bundles", "getBundles");
|
|
99
|
+
addAdminRoute("POST", "/bundles", "createBundles");
|
|
100
|
+
addAdminRoute("PATCH", "/bundles/:id", "updateBundle");
|
|
101
|
+
addAdminRoute("DELETE", "/bundles/:id", "deleteBundle");
|
|
102
|
+
if (analytics !== void 0) require_routes.registerAnalyticsAdminRoutes(addAdminRoute);
|
|
103
|
+
return Object.freeze({
|
|
104
|
+
client: createRequestHandler({
|
|
105
|
+
api,
|
|
106
|
+
apiKeyAuth,
|
|
107
|
+
routeHandlers,
|
|
108
|
+
router: clientRouter
|
|
109
|
+
}),
|
|
110
|
+
admin: createRequestHandler({
|
|
111
|
+
api,
|
|
112
|
+
privateResponses: true,
|
|
113
|
+
routeHandlers,
|
|
114
|
+
router: adminRouter
|
|
115
|
+
})
|
|
116
|
+
});
|
|
292
117
|
}
|
|
293
118
|
//#endregion
|
|
294
|
-
exports.
|
|
119
|
+
exports.createHandlers = createHandlers;
|
|
120
|
+
exports.createHotUpdaterHandlers = createHotUpdaterHandlers;
|