@hot-updater/server 0.36.6 → 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
package/src/handler.spec.ts
CHANGED
|
@@ -1,635 +1,190 @@
|
|
|
1
|
-
import
|
|
1
|
+
import type { ReleaseCatalog } from "@hot-updater/core";
|
|
2
|
+
import { Hono } from "hono";
|
|
2
3
|
import { describe, expect, it, vi } from "vitest";
|
|
3
4
|
|
|
4
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
createHandlers,
|
|
7
|
+
createHotUpdaterHandlers,
|
|
8
|
+
type HandlerAPI,
|
|
9
|
+
} from "./handler";
|
|
10
|
+
import { createApi } from "./handler.testFixtures";
|
|
11
|
+
import { HOT_UPDATER_INFRASTRUCTURE_GENERATION } from "./handlerVersionRoutes";
|
|
5
12
|
import { HOT_UPDATER_SERVER_VERSION } from "./version";
|
|
6
13
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
tenantId: string;
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
type TestContext = {
|
|
15
|
-
env: TestEnv;
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
const testBundle: Bundle = {
|
|
19
|
-
id: "bundle-1",
|
|
20
|
-
platform: "ios",
|
|
21
|
-
shouldForceUpdate: false,
|
|
22
|
-
enabled: true,
|
|
23
|
-
fileHash: "hash123",
|
|
24
|
-
gitCommitHash: null,
|
|
25
|
-
message: "Test bundle",
|
|
26
|
-
channel: "production",
|
|
27
|
-
storageUri: "s3://test-bucket/bundles/bundle-1.zip",
|
|
28
|
-
targetAppVersion: "1.0.0",
|
|
29
|
-
fingerprintHash: null,
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
const createApi = () =>
|
|
33
|
-
({
|
|
34
|
-
getAppUpdateInfo: vi
|
|
35
|
-
.fn<HandlerAPI<TestContext>["getAppUpdateInfo"]>()
|
|
36
|
-
.mockResolvedValue({
|
|
37
|
-
fileHash: null,
|
|
38
|
-
fileUrl: null,
|
|
39
|
-
id: NIL_UUID,
|
|
40
|
-
message: null,
|
|
41
|
-
shouldForceUpdate: true,
|
|
42
|
-
status: "ROLLBACK",
|
|
43
|
-
}),
|
|
44
|
-
getBundleById: vi.fn<HandlerAPI<TestContext>["getBundleById"]>(),
|
|
45
|
-
getBundles: vi.fn<HandlerAPI<TestContext>["getBundles"]>(),
|
|
46
|
-
getChannels: vi
|
|
47
|
-
.fn<HandlerAPI<TestContext>["getChannels"]>()
|
|
48
|
-
.mockResolvedValue(["production"]),
|
|
49
|
-
insertBundle: vi.fn<HandlerAPI<TestContext>["insertBundle"]>(),
|
|
50
|
-
updateBundleById: vi.fn<HandlerAPI<TestContext>["updateBundleById"]>(),
|
|
51
|
-
deleteBundleById: vi.fn<HandlerAPI<TestContext>["deleteBundleById"]>(),
|
|
52
|
-
}) satisfies HandlerAPI<TestContext>;
|
|
53
|
-
|
|
54
|
-
const createManagementHandler = (
|
|
55
|
-
api: HandlerAPI<TestContext>,
|
|
56
|
-
routes: Partial<HandlerRoutes> = {},
|
|
57
|
-
) =>
|
|
58
|
-
createHandler(api, {
|
|
59
|
-
basePath: "/hot-updater",
|
|
60
|
-
routes: {
|
|
61
|
-
updateCheck: true,
|
|
62
|
-
bundles: true,
|
|
63
|
-
...routes,
|
|
64
|
-
},
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
describe("createHandler", () => {
|
|
68
|
-
it("supports the app-version route without a cohort segment", async () => {
|
|
69
|
-
const api = createApi();
|
|
70
|
-
const handler = createHandler(api, { basePath: "/hot-updater" });
|
|
71
|
-
|
|
72
|
-
const response = await handler(
|
|
73
|
-
new Request(
|
|
74
|
-
"http://localhost/hot-updater/app-version/ios/1.0.0/production/default/default",
|
|
75
|
-
),
|
|
76
|
-
{
|
|
77
|
-
env: {
|
|
78
|
-
tenantId: "tenant-a",
|
|
79
|
-
},
|
|
80
|
-
},
|
|
81
|
-
);
|
|
82
|
-
|
|
83
|
-
expect(response.status).toBe(200);
|
|
84
|
-
expect(api.getAppUpdateInfo).toHaveBeenCalledWith(
|
|
85
|
-
{
|
|
86
|
-
_updateStrategy: "appVersion",
|
|
87
|
-
appVersion: "1.0.0",
|
|
88
|
-
bundleId: "default",
|
|
89
|
-
channel: "production",
|
|
90
|
-
cohort: undefined,
|
|
91
|
-
minBundleId: "default",
|
|
92
|
-
platform: "ios",
|
|
93
|
-
},
|
|
94
|
-
{
|
|
95
|
-
env: {
|
|
96
|
-
tenantId: "tenant-a",
|
|
97
|
-
},
|
|
98
|
-
},
|
|
99
|
-
);
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
it("keeps legacy no-update responses as null when SDK version is missing", async () => {
|
|
103
|
-
const api = createApi();
|
|
104
|
-
api.getAppUpdateInfo.mockResolvedValueOnce(null);
|
|
105
|
-
const handler = createHandler(api, { basePath: "/hot-updater" });
|
|
106
|
-
|
|
107
|
-
const response = await handler(
|
|
108
|
-
new Request(
|
|
109
|
-
"http://localhost/hot-updater/app-version/ios/1.0.0/production/default/default",
|
|
110
|
-
),
|
|
111
|
-
);
|
|
112
|
-
|
|
113
|
-
expect(response.status).toBe(200);
|
|
114
|
-
await expect(response.json()).resolves.toBeNull();
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
it("returns UP_TO_DATE for no-update responses from SDK-versioned clients", async () => {
|
|
118
|
-
const api = createApi();
|
|
119
|
-
api.getAppUpdateInfo.mockResolvedValueOnce(null);
|
|
120
|
-
const handler = createHandler(api, { basePath: "/hot-updater" });
|
|
121
|
-
|
|
122
|
-
const response = await handler(
|
|
123
|
-
new Request(
|
|
124
|
-
"http://localhost/hot-updater/app-version/ios/1.0.0/production/default/default",
|
|
125
|
-
{
|
|
126
|
-
headers: {
|
|
127
|
-
"Hot-Updater-SDK-Version": NEXT_SDK_VERSION_FOR_TEST,
|
|
128
|
-
},
|
|
129
|
-
},
|
|
130
|
-
),
|
|
131
|
-
);
|
|
14
|
+
describe("createHandlers client routes", () => {
|
|
15
|
+
it("reports the v1 infrastructure generation", async () => {
|
|
16
|
+
const handler = createHandlers(createApi()).client;
|
|
17
|
+
const response = await handler(new Request("http://localhost/version"));
|
|
132
18
|
|
|
133
19
|
expect(response.status).toBe(200);
|
|
134
20
|
await expect(response.json()).resolves.toEqual({
|
|
135
|
-
|
|
136
|
-
});
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
it("keeps no-update responses as null for unsupported SDK versions", async () => {
|
|
140
|
-
const api = createApi();
|
|
141
|
-
api.getAppUpdateInfo.mockResolvedValueOnce(null);
|
|
142
|
-
const handler = createHandler(api, { basePath: "/hot-updater" });
|
|
143
|
-
|
|
144
|
-
const response = await handler(
|
|
145
|
-
new Request(
|
|
146
|
-
"http://localhost/hot-updater/app-version/ios/1.0.0/production/default/default",
|
|
147
|
-
{
|
|
148
|
-
headers: {
|
|
149
|
-
"Hot-Updater-SDK-Version": CURRENT_PACKAGE_SDK_VERSION,
|
|
150
|
-
},
|
|
151
|
-
},
|
|
152
|
-
),
|
|
153
|
-
);
|
|
154
|
-
|
|
155
|
-
expect(response.status).toBe(200);
|
|
156
|
-
await expect(response.json()).resolves.toBeNull();
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
it("keeps no-update responses as null for invalid SDK versions", async () => {
|
|
160
|
-
const api = createApi();
|
|
161
|
-
api.getAppUpdateInfo.mockResolvedValueOnce(null);
|
|
162
|
-
const handler = createHandler(api, { basePath: "/hot-updater" });
|
|
163
|
-
|
|
164
|
-
const response = await handler(
|
|
165
|
-
new Request(
|
|
166
|
-
"http://localhost/hot-updater/app-version/ios/1.0.0/production/default/default",
|
|
167
|
-
{
|
|
168
|
-
headers: {
|
|
169
|
-
"Hot-Updater-SDK-Version": "invalid",
|
|
170
|
-
},
|
|
171
|
-
},
|
|
172
|
-
),
|
|
173
|
-
);
|
|
174
|
-
|
|
175
|
-
expect(response.status).toBe(200);
|
|
176
|
-
await expect(response.json()).resolves.toBeNull();
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
it("supports the fingerprint route without a cohort segment", async () => {
|
|
180
|
-
const api = createApi();
|
|
181
|
-
const handler = createHandler(api, { basePath: "/hot-updater" });
|
|
182
|
-
|
|
183
|
-
const response = await handler(
|
|
184
|
-
new Request(
|
|
185
|
-
"http://localhost/hot-updater/fingerprint/android/fingerprint-123/production/default/default",
|
|
186
|
-
),
|
|
187
|
-
);
|
|
188
|
-
|
|
189
|
-
expect(response.status).toBe(200);
|
|
190
|
-
expect(api.getAppUpdateInfo).toHaveBeenCalledWith(
|
|
191
|
-
{
|
|
192
|
-
_updateStrategy: "fingerprint",
|
|
193
|
-
bundleId: "default",
|
|
194
|
-
channel: "production",
|
|
195
|
-
cohort: undefined,
|
|
196
|
-
fingerprintHash: "fingerprint-123",
|
|
197
|
-
minBundleId: "default",
|
|
198
|
-
platform: "android",
|
|
199
|
-
},
|
|
200
|
-
undefined,
|
|
201
|
-
);
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
it("keeps version mounted when bundle routes are disabled", async () => {
|
|
205
|
-
const api = createApi();
|
|
206
|
-
const handler = createHandler(api, {
|
|
207
|
-
basePath: "/hot-updater",
|
|
208
|
-
routes: {
|
|
209
|
-
updateCheck: true,
|
|
210
|
-
bundles: false,
|
|
211
|
-
},
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
const versionResponse = await handler(
|
|
215
|
-
new Request("http://localhost/hot-updater/version"),
|
|
216
|
-
);
|
|
217
|
-
const bundlesResponse = await handler(
|
|
218
|
-
new Request("http://localhost/hot-updater/api/bundles"),
|
|
219
|
-
);
|
|
220
|
-
const updateResponse = await handler(
|
|
221
|
-
new Request(
|
|
222
|
-
"http://localhost/hot-updater/app-version/ios/1.0.0/production/default/default",
|
|
223
|
-
),
|
|
224
|
-
);
|
|
225
|
-
|
|
226
|
-
expect(versionResponse.status).toBe(200);
|
|
227
|
-
await expect(versionResponse.json()).resolves.toEqual({
|
|
21
|
+
infrastructureGeneration: HOT_UPDATER_INFRASTRUCTURE_GENERATION,
|
|
228
22
|
version: HOT_UPDATER_SERVER_VERSION,
|
|
229
23
|
});
|
|
230
|
-
expect(bundlesResponse.status).toBe(404);
|
|
231
|
-
expect(updateResponse.status).toBe(200);
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
it("does not mount bundle routes by default", async () => {
|
|
235
|
-
const api = createApi();
|
|
236
|
-
const handler = createHandler(api, { basePath: "/hot-updater" });
|
|
237
|
-
|
|
238
|
-
const versionResponse = await handler(
|
|
239
|
-
new Request("http://localhost/hot-updater/version"),
|
|
240
|
-
);
|
|
241
|
-
const bundlesResponse = await handler(
|
|
242
|
-
new Request("http://localhost/hot-updater/api/bundles"),
|
|
243
|
-
);
|
|
244
|
-
const updateResponse = await handler(
|
|
245
|
-
new Request(
|
|
246
|
-
"http://localhost/hot-updater/app-version/ios/1.0.0/production/default/default",
|
|
247
|
-
),
|
|
248
|
-
);
|
|
249
|
-
|
|
250
|
-
expect(versionResponse.status).toBe(200);
|
|
251
|
-
expect(bundlesResponse.status).toBe(404);
|
|
252
|
-
expect(updateResponse.status).toBe(200);
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
it("mounts bundle routes when explicitly enabled", async () => {
|
|
256
|
-
const api = createApi();
|
|
257
|
-
api.getBundles.mockResolvedValueOnce({
|
|
258
|
-
data: [],
|
|
259
|
-
pagination: {
|
|
260
|
-
total: 0,
|
|
261
|
-
hasNextPage: false,
|
|
262
|
-
hasPreviousPage: false,
|
|
263
|
-
currentPage: 1,
|
|
264
|
-
totalPages: 0,
|
|
265
|
-
},
|
|
266
|
-
});
|
|
267
|
-
const handler = createHandler(api, {
|
|
268
|
-
basePath: "/hot-updater",
|
|
269
|
-
routes: {
|
|
270
|
-
updateCheck: true,
|
|
271
|
-
bundles: true,
|
|
272
|
-
},
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
const response = await handler(
|
|
276
|
-
new Request("http://localhost/hot-updater/api/bundles"),
|
|
277
|
-
);
|
|
278
|
-
|
|
279
|
-
expect(response.status).toBe(200);
|
|
280
|
-
expect(api.getBundles).toHaveBeenCalledWith(
|
|
281
|
-
{
|
|
282
|
-
cursor: undefined,
|
|
283
|
-
limit: 50,
|
|
284
|
-
page: undefined,
|
|
285
|
-
where: {},
|
|
286
|
-
},
|
|
287
|
-
undefined,
|
|
288
|
-
);
|
|
289
|
-
});
|
|
290
|
-
|
|
291
|
-
it("keeps update-check routes mounted for partial runtime route config", async () => {
|
|
292
|
-
const api = createApi();
|
|
293
|
-
const handler = createHandler(api, {
|
|
294
|
-
basePath: "/hot-updater",
|
|
295
|
-
routes: JSON.parse('{"bundles":true}') as HandlerRoutes,
|
|
296
|
-
});
|
|
297
|
-
|
|
298
|
-
const updateResponse = await handler(
|
|
299
|
-
new Request(
|
|
300
|
-
"http://localhost/hot-updater/app-version/ios/1.0.0/production/default/default",
|
|
301
|
-
),
|
|
302
|
-
);
|
|
303
|
-
|
|
304
|
-
expect(updateResponse.status).toBe(200);
|
|
305
24
|
});
|
|
306
25
|
|
|
307
|
-
it(
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
updateCheck: false,
|
|
313
|
-
bundles: false,
|
|
314
|
-
},
|
|
315
|
-
});
|
|
26
|
+
it.each([
|
|
27
|
+
"/app-version/ios/1.0.0/production/default/default",
|
|
28
|
+
"/fingerprint/android/fingerprint-123/production/default/default",
|
|
29
|
+
])("does not expose the v0 route %s", async (path) => {
|
|
30
|
+
const handler = createHandlers(createApi()).client;
|
|
316
31
|
|
|
317
|
-
const
|
|
318
|
-
new Request("http://localhost/hot-updater/version"),
|
|
319
|
-
);
|
|
320
|
-
const bundlesResponse = await handler(
|
|
321
|
-
new Request("http://localhost/hot-updater/api/bundles"),
|
|
322
|
-
);
|
|
323
|
-
const updateResponse = await handler(
|
|
324
|
-
new Request(
|
|
325
|
-
"http://localhost/hot-updater/app-version/ios/1.0.0/production/default/default",
|
|
326
|
-
),
|
|
327
|
-
);
|
|
32
|
+
const response = await handler(new Request(`http://localhost${path}`));
|
|
328
33
|
|
|
329
|
-
expect(
|
|
330
|
-
await expect(versionResponse.json()).resolves.toEqual({
|
|
331
|
-
version: HOT_UPDATER_SERVER_VERSION,
|
|
332
|
-
});
|
|
333
|
-
expect(bundlesResponse.status).toBe(404);
|
|
334
|
-
expect(updateResponse.status).toBe(404);
|
|
34
|
+
expect(response.status).toBe(404);
|
|
335
35
|
});
|
|
336
36
|
|
|
337
|
-
it(
|
|
338
|
-
|
|
339
|
-
|
|
37
|
+
it.each([
|
|
38
|
+
"/v2/release-catalogs/app-version/ios/cHJvZHVjdGlvbg/1.0.0",
|
|
39
|
+
"/v2/artifacts/target-bundle/from/current-bundle",
|
|
40
|
+
])("does not expose the version-prefixed route %s", async (path) => {
|
|
41
|
+
const handler = createHandlers(createApi()).client;
|
|
340
42
|
|
|
341
|
-
const
|
|
342
|
-
new Request("http://localhost/hot-updater/version"),
|
|
343
|
-
);
|
|
344
|
-
const channelsResponse = await handler(
|
|
345
|
-
new Request("http://localhost/hot-updater/api/bundles/channels"),
|
|
346
|
-
);
|
|
347
|
-
const updateResponse = await handler(
|
|
348
|
-
new Request(
|
|
349
|
-
"http://localhost/hot-updater/app-version/ios/1.0.0/production/default/default",
|
|
350
|
-
),
|
|
351
|
-
);
|
|
43
|
+
const response = await handler(new Request(`http://localhost${path}`));
|
|
352
44
|
|
|
353
|
-
expect(
|
|
354
|
-
await expect(versionResponse.json()).resolves.toEqual({
|
|
355
|
-
version: HOT_UPDATER_SERVER_VERSION,
|
|
356
|
-
});
|
|
357
|
-
expect(channelsResponse.status).toBe(200);
|
|
358
|
-
await expect(channelsResponse.json()).resolves.toEqual({
|
|
359
|
-
data: {
|
|
360
|
-
channels: ["production"],
|
|
361
|
-
},
|
|
362
|
-
});
|
|
363
|
-
expect(api.getChannels).toHaveBeenCalledWith(undefined);
|
|
364
|
-
expect(updateResponse.status).toBe(404);
|
|
45
|
+
expect(response.status).toBe(404);
|
|
365
46
|
});
|
|
366
47
|
|
|
367
|
-
it("
|
|
368
|
-
const
|
|
369
|
-
api.getBundles.mockResolvedValue({
|
|
370
|
-
data: [testBundle],
|
|
371
|
-
pagination: {
|
|
372
|
-
total: 51,
|
|
373
|
-
hasNextPage: true,
|
|
374
|
-
hasPreviousPage: true,
|
|
375
|
-
currentPage: 6,
|
|
376
|
-
totalPages: 26,
|
|
377
|
-
},
|
|
378
|
-
});
|
|
379
|
-
const handler = createManagementHandler(api);
|
|
48
|
+
it("does not match the admin mount namespace", async () => {
|
|
49
|
+
const handler = createHandlers(createApi()).client;
|
|
380
50
|
|
|
381
51
|
const response = await handler(
|
|
382
|
-
new Request(
|
|
383
|
-
"http://localhost/hot-updater/api/bundles?channel=production&platform=ios&limit=2",
|
|
384
|
-
),
|
|
52
|
+
new Request("http://localhost/admin/channels"),
|
|
385
53
|
);
|
|
386
54
|
|
|
387
|
-
expect(response.status).toBe(
|
|
388
|
-
expect(response.headers.get("X-Total-Count")).toBeNull();
|
|
389
|
-
await expect(response.json()).resolves.toEqual({
|
|
390
|
-
data: [testBundle],
|
|
391
|
-
pagination: {
|
|
392
|
-
total: 51,
|
|
393
|
-
hasNextPage: true,
|
|
394
|
-
hasPreviousPage: true,
|
|
395
|
-
currentPage: 6,
|
|
396
|
-
totalPages: 26,
|
|
397
|
-
},
|
|
398
|
-
});
|
|
399
|
-
expect(api.getBundles).toHaveBeenCalledWith(
|
|
400
|
-
{
|
|
401
|
-
where: {
|
|
402
|
-
channel: "production",
|
|
403
|
-
platform: "ios",
|
|
404
|
-
},
|
|
405
|
-
limit: 2,
|
|
406
|
-
page: undefined,
|
|
407
|
-
},
|
|
408
|
-
undefined,
|
|
409
|
-
);
|
|
55
|
+
expect(response.status).toBe(404);
|
|
410
56
|
});
|
|
411
57
|
|
|
412
|
-
it("
|
|
413
|
-
const
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
58
|
+
it("returns the stored Catalog identity without accepting identity parameters", async () => {
|
|
59
|
+
const catalog = {
|
|
60
|
+
catalogId: "project-a",
|
|
61
|
+
catalogHash: "sha256:catalog",
|
|
62
|
+
fallbackPolicy: "BUILTIN_IF_ACTIVE_INELIGIBLE",
|
|
63
|
+
generation: 1,
|
|
64
|
+
releases: [],
|
|
65
|
+
schemaVersion: 1,
|
|
66
|
+
scopeKey: "v1:fingerprint:android:cHJvZHVjdGlvbg:fingerprint-123",
|
|
67
|
+
} satisfies ReleaseCatalog;
|
|
68
|
+
const getReleaseCatalog = vi
|
|
69
|
+
.fn<NonNullable<HandlerAPI["getReleaseCatalog"]>>()
|
|
70
|
+
.mockResolvedValue(catalog);
|
|
71
|
+
const handler = createHandlers({
|
|
72
|
+
...createApi(),
|
|
73
|
+
getReleaseCatalog,
|
|
74
|
+
}).client;
|
|
75
|
+
const url =
|
|
76
|
+
"http://localhost/release-catalogs/fingerprint/android/" +
|
|
77
|
+
"cHJvZHVjdGlvbg/fingerprint-123";
|
|
425
78
|
|
|
426
|
-
const response = await handler(
|
|
427
|
-
new Request(
|
|
428
|
-
"http://localhost/hot-updater/api/bundles?channel=production&platform=ios&enabled=true&idLt=bundle-9&targetAppVersion=1.0.x&targetAppVersionNotNull=true&fingerprintHash=null&limit=5",
|
|
429
|
-
),
|
|
430
|
-
);
|
|
79
|
+
const response = await handler(new Request(url));
|
|
431
80
|
|
|
432
81
|
expect(response.status).toBe(200);
|
|
433
|
-
expect(
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
82
|
+
await expect(response.json()).resolves.toMatchObject({
|
|
83
|
+
catalogId: "project-a",
|
|
84
|
+
});
|
|
85
|
+
expect(getReleaseCatalog).toHaveBeenCalledWith({
|
|
86
|
+
channelKey: "cHJvZHVjdGlvbg",
|
|
87
|
+
fingerprintHash: "fingerprint-123",
|
|
88
|
+
platform: "android",
|
|
89
|
+
strategy: "FINGERPRINT",
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const legacyAuthorityPath = await handler(
|
|
93
|
+
new Request(url.replace("/android/", "/project-a/android/")),
|
|
94
|
+
);
|
|
95
|
+
expect(legacyAuthorityPath.status).toBe(404);
|
|
96
|
+
expect(getReleaseCatalog).toHaveBeenCalledOnce();
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it("serves client-relative storage paths under a framework mount", async () => {
|
|
100
|
+
const api = {
|
|
101
|
+
...createApi(),
|
|
102
|
+
getArtifactInfo: vi.fn().mockResolvedValue({
|
|
103
|
+
changedAssets: {
|
|
104
|
+
"index.bundle": {
|
|
105
|
+
file: {
|
|
106
|
+
url: "/storage/asset-token/asset-signature",
|
|
107
|
+
},
|
|
108
|
+
fileHash: "asset-hash",
|
|
109
|
+
patch: {
|
|
110
|
+
algorithm: "bsdiff",
|
|
111
|
+
baseBundleId: "bundle-1",
|
|
112
|
+
baseFileHash: "base-hash",
|
|
113
|
+
patchFileHash: "patch-hash",
|
|
114
|
+
patchUrl: "/storage/patch-token/patch-signature",
|
|
115
|
+
},
|
|
441
116
|
},
|
|
442
|
-
targetAppVersion: "1.0.x",
|
|
443
|
-
targetAppVersionNotNull: true,
|
|
444
|
-
fingerprintHash: null,
|
|
445
|
-
},
|
|
446
|
-
limit: 5,
|
|
447
|
-
page: undefined,
|
|
448
|
-
},
|
|
449
|
-
undefined,
|
|
450
|
-
);
|
|
451
|
-
});
|
|
452
|
-
|
|
453
|
-
it("passes cursor pagination params through to getBundles", async () => {
|
|
454
|
-
const api = createApi();
|
|
455
|
-
api.getBundles.mockResolvedValue({
|
|
456
|
-
data: [testBundle],
|
|
457
|
-
pagination: {
|
|
458
|
-
total: 51,
|
|
459
|
-
hasNextPage: true,
|
|
460
|
-
hasPreviousPage: true,
|
|
461
|
-
currentPage: 2,
|
|
462
|
-
totalPages: 26,
|
|
463
|
-
nextCursor: "bundle-1",
|
|
464
|
-
previousCursor: "bundle-9",
|
|
465
|
-
},
|
|
466
|
-
});
|
|
467
|
-
const handler = createManagementHandler(api);
|
|
468
|
-
|
|
469
|
-
const response = await handler(
|
|
470
|
-
new Request(
|
|
471
|
-
"http://localhost/hot-updater/api/bundles?channel=production&limit=20&after=bundle-20",
|
|
472
|
-
),
|
|
473
|
-
);
|
|
474
|
-
|
|
475
|
-
expect(response.status).toBe(200);
|
|
476
|
-
expect(api.getBundles).toHaveBeenCalledWith(
|
|
477
|
-
{
|
|
478
|
-
where: {
|
|
479
|
-
channel: "production",
|
|
480
117
|
},
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
118
|
+
fileHash: "archive-hash",
|
|
119
|
+
fileUrl: "/storage/archive-token/archive-signature",
|
|
120
|
+
manifestFileHash: "manifest-hash",
|
|
121
|
+
manifestUrl: "/storage/manifest-token/manifest-signature",
|
|
122
|
+
}),
|
|
123
|
+
};
|
|
124
|
+
const handlers = createHotUpdaterHandlers(
|
|
125
|
+
api,
|
|
488
126
|
undefined,
|
|
489
|
-
);
|
|
490
|
-
});
|
|
491
|
-
|
|
492
|
-
it("supports cursor pagination without a legacy offset query param", async () => {
|
|
493
|
-
const api = createApi();
|
|
494
|
-
api.getBundles.mockResolvedValue({
|
|
495
|
-
data: [testBundle],
|
|
496
|
-
pagination: {
|
|
497
|
-
total: 1,
|
|
498
|
-
hasNextPage: false,
|
|
499
|
-
hasPreviousPage: false,
|
|
500
|
-
currentPage: 1,
|
|
501
|
-
totalPages: 1,
|
|
502
|
-
nextCursor: null,
|
|
503
|
-
previousCursor: null,
|
|
504
|
-
},
|
|
505
|
-
});
|
|
506
|
-
const handler = createManagementHandler(api);
|
|
507
|
-
|
|
508
|
-
const response = await handler(
|
|
509
|
-
new Request(
|
|
510
|
-
"http://localhost/hot-updater/api/bundles?channel=production&limit=20&after=bundle-20",
|
|
511
|
-
),
|
|
512
|
-
);
|
|
513
|
-
|
|
514
|
-
expect(response.status).toBe(200);
|
|
515
|
-
expect(api.getBundles).toHaveBeenCalledWith(
|
|
516
|
-
{
|
|
517
|
-
where: {
|
|
518
|
-
channel: "production",
|
|
519
|
-
},
|
|
520
|
-
limit: 20,
|
|
521
|
-
page: undefined,
|
|
522
|
-
cursor: {
|
|
523
|
-
after: "bundle-20",
|
|
524
|
-
before: undefined,
|
|
525
|
-
},
|
|
526
|
-
},
|
|
527
127
|
undefined,
|
|
128
|
+
async () => new Response("bundle archive"),
|
|
528
129
|
);
|
|
529
|
-
|
|
130
|
+
const app = new Hono();
|
|
131
|
+
app.mount("/hot-updater", handlers.client);
|
|
530
132
|
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
const handler = createManagementHandler(api);
|
|
534
|
-
|
|
535
|
-
const response = await handler(
|
|
536
|
-
new Request(
|
|
537
|
-
"http://localhost/hot-updater/api/bundles?limit=20&offset=40",
|
|
538
|
-
),
|
|
539
|
-
);
|
|
540
|
-
|
|
541
|
-
expect(response.status).toBe(400);
|
|
542
|
-
await expect(response.json()).resolves.toEqual({
|
|
543
|
-
error:
|
|
544
|
-
"The 'offset' query parameter has been removed. Use 'after' or 'before' cursor pagination instead.",
|
|
545
|
-
});
|
|
546
|
-
expect(api.getBundles).not.toHaveBeenCalled();
|
|
547
|
-
});
|
|
548
|
-
|
|
549
|
-
it("passes page-aligned pagination params through to getBundles", async () => {
|
|
550
|
-
const api = createApi();
|
|
551
|
-
api.getBundles.mockResolvedValue({
|
|
552
|
-
data: [testBundle],
|
|
553
|
-
pagination: {
|
|
554
|
-
total: 121,
|
|
555
|
-
hasNextPage: true,
|
|
556
|
-
hasPreviousPage: true,
|
|
557
|
-
currentPage: 2,
|
|
558
|
-
totalPages: 7,
|
|
559
|
-
nextCursor: "bundle-1",
|
|
560
|
-
previousCursor: "bundle-9",
|
|
561
|
-
},
|
|
562
|
-
});
|
|
563
|
-
const handler = createManagementHandler(api);
|
|
564
|
-
|
|
565
|
-
const response = await handler(
|
|
566
|
-
new Request(
|
|
567
|
-
"http://localhost/hot-updater/api/bundles?channel=production&limit=20&page=2&after=bundle-20",
|
|
568
|
-
),
|
|
133
|
+
const response = await app.request(
|
|
134
|
+
"/hot-updater/artifacts/bundle-2/from/bundle-1",
|
|
569
135
|
);
|
|
570
136
|
|
|
571
137
|
expect(response.status).toBe(200);
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
138
|
+
const info = (await response.json()) as {
|
|
139
|
+
changedAssets: Record<
|
|
140
|
+
string,
|
|
141
|
+
{ file: { url: string }; patch: { patchUrl: string } }
|
|
142
|
+
>;
|
|
143
|
+
fileUrl: string;
|
|
144
|
+
manifestUrl: string;
|
|
145
|
+
};
|
|
146
|
+
expect(info).toMatchObject({
|
|
147
|
+
changedAssets: {
|
|
148
|
+
"index.bundle": {
|
|
149
|
+
file: { url: "/storage/asset-token/asset-signature" },
|
|
150
|
+
patch: { patchUrl: "/storage/patch-token/patch-signature" },
|
|
582
151
|
},
|
|
583
152
|
},
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
});
|
|
587
|
-
|
|
588
|
-
it("returns 400 when bundle list requests send an invalid page", async () => {
|
|
589
|
-
const api = createApi();
|
|
590
|
-
const handler = createManagementHandler(api);
|
|
591
|
-
|
|
592
|
-
const response = await handler(
|
|
593
|
-
new Request("http://localhost/hot-updater/api/bundles?limit=20&page=0"),
|
|
594
|
-
);
|
|
595
|
-
|
|
596
|
-
expect(response.status).toBe(400);
|
|
597
|
-
await expect(response.json()).resolves.toEqual({
|
|
598
|
-
error: "The 'page' query parameter must be a positive integer.",
|
|
153
|
+
fileUrl: "/storage/archive-token/archive-signature",
|
|
154
|
+
manifestUrl: "/storage/manifest-token/manifest-signature",
|
|
599
155
|
});
|
|
600
|
-
expect(api.getBundles).not.toHaveBeenCalled();
|
|
601
|
-
});
|
|
602
|
-
|
|
603
|
-
it("returns 400 when bundle list limit exceeds the maximum", async () => {
|
|
604
|
-
const api = createApi();
|
|
605
|
-
const handler = createManagementHandler(api);
|
|
606
156
|
|
|
607
|
-
const
|
|
608
|
-
|
|
609
|
-
);
|
|
610
|
-
|
|
611
|
-
expect(response.status).toBe(400);
|
|
612
|
-
await expect(response.json()).resolves.toEqual({
|
|
613
|
-
error:
|
|
614
|
-
"The 'limit' query parameter must be a positive integer between 1 and 100.",
|
|
615
|
-
});
|
|
616
|
-
expect(api.getBundles).not.toHaveBeenCalled();
|
|
157
|
+
const download = await app.request(`/hot-updater${info.fileUrl}`);
|
|
158
|
+
expect(download.status).toBe(200);
|
|
159
|
+
await expect(download.text()).resolves.toBe("bundle archive");
|
|
617
160
|
});
|
|
618
161
|
|
|
619
|
-
it("
|
|
620
|
-
const api =
|
|
621
|
-
|
|
162
|
+
it("does not expose provider errors from the public client handler", async () => {
|
|
163
|
+
const api = {
|
|
164
|
+
...createApi(),
|
|
165
|
+
getReleaseCatalog: vi
|
|
166
|
+
.fn()
|
|
167
|
+
.mockRejectedValue(new Error("private database connection details")),
|
|
168
|
+
};
|
|
169
|
+
const consoleError = vi
|
|
170
|
+
.spyOn(console, "error")
|
|
171
|
+
.mockImplementation(() => {});
|
|
172
|
+
const handler = createHandlers(api).client;
|
|
622
173
|
|
|
623
174
|
const response = await handler(
|
|
624
175
|
new Request(
|
|
625
|
-
"http://localhost/
|
|
176
|
+
"http://localhost/release-catalogs/app-version/ios/cHJvZHVjdGlvbg/1.0.0",
|
|
626
177
|
),
|
|
627
178
|
);
|
|
628
179
|
|
|
180
|
+
expect(response.status).toBe(500);
|
|
629
181
|
await expect(response.json()).resolves.toEqual({
|
|
630
|
-
error: "
|
|
182
|
+
error: "Internal server error",
|
|
631
183
|
});
|
|
632
|
-
expect(
|
|
633
|
-
|
|
184
|
+
expect(consoleError).toHaveBeenCalledWith(
|
|
185
|
+
"Hot Updater handler error:",
|
|
186
|
+
expect.any(Error),
|
|
187
|
+
);
|
|
188
|
+
consoleError.mockRestore();
|
|
634
189
|
});
|
|
635
190
|
});
|