@hot-updater/server 0.36.7 → 1.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/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/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/insights/bounded/activeOverview.cjs +87 -0
- package/dist/insights/bounded/activeOverview.mjs +85 -0
- package/dist/insights/bounded/installationSearch.cjs +42 -0
- package/dist/insights/bounded/installationSearch.mjs +42 -0
- package/dist/insights/bounded/persistence.cjs +39 -0
- package/dist/insights/bounded/persistence.mjs +38 -0
- package/dist/insights/bounded/provider.cjs +170 -0
- package/dist/insights/bounded/provider.d.cts +7 -0
- package/dist/insights/bounded/provider.d.mts +7 -0
- package/dist/insights/bounded/provider.mjs +170 -0
- package/dist/insights/bounded/scan.cjs +144 -0
- package/dist/insights/bounded/scan.mjs +138 -0
- package/dist/insights/domain.d.cts +121 -0
- package/dist/insights/domain.d.mts +121 -0
- package/dist/insights/errors.cjs +22 -0
- package/dist/insights/errors.mjs +20 -0
- package/dist/insights/eventInput.cjs +111 -0
- package/dist/insights/eventInput.mjs +111 -0
- package/dist/insights/persistence.d.cts +6 -0
- package/dist/insights/persistence.d.mts +6 -0
- package/dist/insights/queryInput.cjs +58 -0
- package/dist/insights/queryInput.mjs +55 -0
- package/dist/insights/routes.cjs +63 -0
- package/dist/insights/routes.mjs +61 -0
- package/dist/insights/types.d.cts +17 -0
- package/dist/insights/types.d.mts +17 -0
- 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/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/insights/bounded/activeOverview.spec.ts +189 -0
- package/src/insights/bounded/activeOverview.ts +148 -0
- package/src/insights/bounded/installationSearch.spec.ts +130 -0
- package/src/insights/bounded/installationSearch.ts +69 -0
- package/src/insights/bounded/persistence.ts +43 -0
- package/src/insights/bounded/provider.spec.ts +219 -0
- package/src/insights/bounded/provider.ts +229 -0
- package/src/insights/bounded/scan.ts +235 -0
- package/src/insights/domain.ts +139 -0
- package/src/insights/errors.ts +18 -0
- package/src/insights/eventInput.ts +168 -0
- package/src/insights/insights.integration.spec.ts +144 -0
- package/src/insights/persistence.ts +10 -0
- package/src/insights/queryInput.ts +102 -0
- package/src/insights/routes.ts +123 -0
- package/src/insights/types.ts +44 -0
- 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,55 +1,109 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
RuntimeStoragePlugin,
|
|
1
|
+
import {
|
|
2
|
+
assertStorageOperations,
|
|
3
|
+
type StoragePlugin,
|
|
5
4
|
} from "@hot-updater/plugin-core";
|
|
6
|
-
import { assertRuntimeStoragePlugin } from "@hot-updater/plugin-core";
|
|
7
5
|
|
|
8
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
authenticateApiKey,
|
|
8
|
+
createApiKeyManagement,
|
|
9
|
+
normalizeApiKeyHeaderName,
|
|
10
|
+
} from "./apiKeys";
|
|
11
|
+
import type { ApiKeyManagementAPI } from "./apiKeys";
|
|
12
|
+
import { createDatabasePluginCore } from "./db/databasePluginCore";
|
|
9
13
|
import { createSchemaReadinessChecker } from "./db/schemaReadiness";
|
|
10
14
|
import {
|
|
11
|
-
type DatabaseAdapter,
|
|
12
15
|
type DatabaseAdapterCapabilities,
|
|
13
16
|
type DatabaseAPI,
|
|
17
|
+
type DatabasePlugin,
|
|
14
18
|
isDatabasePlugin,
|
|
15
|
-
isDatabasePluginFactory,
|
|
16
|
-
type StoragePluginFactory,
|
|
17
19
|
} from "./db/types";
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
+
import { createHotUpdaterHandlers, type HotUpdaterHandlers } from "./handler";
|
|
21
|
+
import { createInsightsProvider } from "./insights/bounded/provider";
|
|
22
|
+
import type { InsightsProvider } from "./insights/types";
|
|
20
23
|
import { createStorageAccess } from "./storageAccess";
|
|
21
24
|
|
|
22
|
-
export type RuntimeHotUpdaterAPI
|
|
23
|
-
readonly
|
|
24
|
-
readonly handler: (
|
|
25
|
-
request: Request,
|
|
26
|
-
context?: HotUpdaterContext<TContext>,
|
|
27
|
-
) => Promise<Response>;
|
|
25
|
+
export type RuntimeHotUpdaterAPI = DatabaseAPI & {
|
|
26
|
+
readonly handlers: HotUpdaterHandlers;
|
|
28
27
|
readonly adapterName: string;
|
|
28
|
+
/**
|
|
29
|
+
* Built-in Insights provider. Client ingestion and admin query routes are
|
|
30
|
+
* always mounted; React Native clients report lifecycle events by default
|
|
31
|
+
* and can opt out with `HotUpdater.init({ insights: false })`.
|
|
32
|
+
*/
|
|
33
|
+
readonly insights: InsightsProvider;
|
|
34
|
+
/**
|
|
35
|
+
* In-process API key lifecycle operations for trusted server tooling.
|
|
36
|
+
* Creation returns the plaintext once; list and revoke expose only metadata.
|
|
37
|
+
* This capability is never mounted on the client or admin HTTP handlers.
|
|
38
|
+
*/
|
|
39
|
+
readonly apiKeys: ApiKeyManagementAPI;
|
|
29
40
|
};
|
|
30
41
|
|
|
31
|
-
export type HotUpdaterAPI
|
|
42
|
+
export type HotUpdaterAPI = RuntimeHotUpdaterAPI;
|
|
32
43
|
|
|
33
|
-
export
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
44
|
+
export type ClientAccessPolicy =
|
|
45
|
+
| {
|
|
46
|
+
/**
|
|
47
|
+
* Leaves Release Catalog, artifact, and Insights ingestion routes
|
|
48
|
+
* publicly accessible without a client credential.
|
|
49
|
+
*/
|
|
50
|
+
readonly type: "public";
|
|
51
|
+
}
|
|
52
|
+
| {
|
|
53
|
+
/**
|
|
54
|
+
* Requires a key registered in `database.models.apiKeys` for
|
|
55
|
+
* Release Catalog, artifact, and Insights ingestion requests.
|
|
56
|
+
*/
|
|
57
|
+
readonly type: "api-key";
|
|
58
|
+
/**
|
|
59
|
+
* Request header containing the API key. Defaults to
|
|
60
|
+
* `x-api-key`. Clients must send the same header; Release Catalog
|
|
61
|
+
* responses include it in `Vary` to preserve cache isolation.
|
|
62
|
+
*/
|
|
63
|
+
readonly headerName?: string;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export interface CreateHotUpdaterOptions {
|
|
67
|
+
readonly database: DatabasePlugin;
|
|
39
68
|
/**
|
|
40
|
-
*
|
|
69
|
+
* Required client-route access policy. This choice is explicit so a server
|
|
70
|
+
* cannot accidentally change between public and authenticated OTA access.
|
|
71
|
+
* `/version`, storage downloads, and admin-handler routes are unaffected.
|
|
41
72
|
*/
|
|
42
|
-
readonly
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
)[];
|
|
46
|
-
readonly basePath?: string;
|
|
47
|
-
readonly cwd?: string;
|
|
48
|
-
readonly routes?: HandlerRoutes;
|
|
73
|
+
readonly clientAccess: ClientAccessPolicy;
|
|
74
|
+
/** Storage implementations used to read provider-specific storage URIs. */
|
|
75
|
+
readonly storage?: readonly StoragePlugin[];
|
|
49
76
|
}
|
|
50
77
|
|
|
51
|
-
|
|
52
|
-
|
|
78
|
+
const normalizeClientAccess = (
|
|
79
|
+
value: unknown,
|
|
80
|
+
):
|
|
81
|
+
| { readonly type: "public" }
|
|
82
|
+
| {
|
|
83
|
+
readonly type: "api-key";
|
|
84
|
+
readonly headerName: string;
|
|
85
|
+
} => {
|
|
86
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
87
|
+
throw new TypeError("clientAccess must be an object.");
|
|
88
|
+
}
|
|
89
|
+
const policy = value as {
|
|
90
|
+
readonly headerName?: unknown;
|
|
91
|
+
readonly type?: unknown;
|
|
92
|
+
};
|
|
93
|
+
if (policy.type === "public") return { type: "public" };
|
|
94
|
+
if (policy.type === "api-key") {
|
|
95
|
+
return {
|
|
96
|
+
headerName: normalizeApiKeyHeaderName(policy.headerName),
|
|
97
|
+
type: "api-key",
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
throw new TypeError(
|
|
101
|
+
'clientAccess.type must be either "public" or "api-key".',
|
|
102
|
+
);
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
type DatabasePluginCore = {
|
|
106
|
+
readonly api: DatabaseAPI;
|
|
53
107
|
readonly adapterName: string;
|
|
54
108
|
readonly createMigrator: () => never;
|
|
55
109
|
readonly generateSchema: () => never;
|
|
@@ -59,110 +113,120 @@ export const hotUpdaterCoreMetadata = Symbol.for(
|
|
|
59
113
|
"@hot-updater/server/core-metadata",
|
|
60
114
|
);
|
|
61
115
|
|
|
62
|
-
export type HotUpdaterCoreMetadata
|
|
116
|
+
export type HotUpdaterCoreMetadata = {
|
|
63
117
|
readonly adapterCapabilities: DatabaseAdapterCapabilities;
|
|
64
|
-
readonly core:
|
|
118
|
+
readonly core: DatabasePluginCore;
|
|
65
119
|
};
|
|
66
120
|
|
|
67
|
-
export type HotUpdaterCore
|
|
68
|
-
readonly api: RuntimeHotUpdaterAPI
|
|
121
|
+
export type HotUpdaterCore = {
|
|
122
|
+
readonly api: RuntimeHotUpdaterAPI;
|
|
69
123
|
readonly adapterCapabilities: DatabaseAdapterCapabilities;
|
|
70
|
-
readonly core:
|
|
124
|
+
readonly core: DatabasePluginCore;
|
|
71
125
|
};
|
|
72
126
|
|
|
73
|
-
export function getHotUpdaterCoreMetadata
|
|
74
|
-
hotUpdater: RuntimeHotUpdaterAPI
|
|
75
|
-
): HotUpdaterCoreMetadata
|
|
127
|
+
export function getHotUpdaterCoreMetadata(
|
|
128
|
+
hotUpdater: RuntimeHotUpdaterAPI,
|
|
129
|
+
): HotUpdaterCoreMetadata | undefined {
|
|
76
130
|
return (
|
|
77
|
-
hotUpdater as RuntimeHotUpdaterAPI
|
|
78
|
-
readonly [hotUpdaterCoreMetadata]?: HotUpdaterCoreMetadata
|
|
131
|
+
hotUpdater as RuntimeHotUpdaterAPI & {
|
|
132
|
+
readonly [hotUpdaterCoreMetadata]?: HotUpdaterCoreMetadata;
|
|
79
133
|
}
|
|
80
134
|
)[hotUpdaterCoreMetadata];
|
|
81
135
|
}
|
|
82
136
|
|
|
83
|
-
export function createHotUpdaterCore
|
|
84
|
-
options: CreateHotUpdaterOptions
|
|
85
|
-
): HotUpdaterCore
|
|
137
|
+
export function createHotUpdaterCore(
|
|
138
|
+
options: CreateHotUpdaterOptions,
|
|
139
|
+
): HotUpdaterCore {
|
|
140
|
+
for (const key of ["authorityId", "catalogId"]) {
|
|
141
|
+
if (Object.hasOwn(options, key)) {
|
|
142
|
+
throw new TypeError(
|
|
143
|
+
`Remove ${key} from createHotUpdater options. Catalog identity is managed internally.`,
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
86
147
|
const database = options.database;
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
return storagePlugin;
|
|
93
|
-
},
|
|
94
|
-
);
|
|
95
|
-
const { readStorageText, resolveFileUrl } =
|
|
148
|
+
const storagePlugins = (options.storage ?? []).map((storage) => {
|
|
149
|
+
assertStorageOperations(storage, ["get", "getDownloadUrl"]);
|
|
150
|
+
return storage;
|
|
151
|
+
});
|
|
152
|
+
const { downloadStorageObject, readStorageText, resolveFileUrl } =
|
|
96
153
|
createStorageAccess(storagePlugins);
|
|
154
|
+
const adapterCapabilities: DatabaseAdapterCapabilities = database;
|
|
97
155
|
|
|
98
|
-
if (!
|
|
156
|
+
if (!isDatabasePlugin(database)) {
|
|
99
157
|
throw new Error("@hot-updater/server only supports database plugins.");
|
|
100
158
|
}
|
|
101
159
|
|
|
102
|
-
const
|
|
103
|
-
const plugin: DatabasePlugin<TContext> = isDatabasePluginFactory(database)
|
|
104
|
-
? database()
|
|
105
|
-
: database;
|
|
160
|
+
const plugin: DatabasePlugin = database;
|
|
106
161
|
const adapterName = adapterCapabilities.adapterName ?? plugin.name;
|
|
107
162
|
const assertSchemaReady = createSchemaReadinessChecker(
|
|
108
163
|
adapterName,
|
|
109
164
|
adapterCapabilities.createMigrator,
|
|
110
165
|
);
|
|
111
|
-
const core =
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
166
|
+
const core = createDatabasePluginCore(plugin, resolveFileUrl, {
|
|
167
|
+
beforeOperation: assertSchemaReady,
|
|
168
|
+
readStorageText,
|
|
169
|
+
});
|
|
170
|
+
const clientAccess = normalizeClientAccess(options.clientAccess);
|
|
171
|
+
const insights = createInsightsProvider({
|
|
172
|
+
async append(row) {
|
|
173
|
+
await assertSchemaReady();
|
|
174
|
+
return plugin.models.insights.append(row);
|
|
175
|
+
},
|
|
176
|
+
async scan(input) {
|
|
177
|
+
await assertSchemaReady();
|
|
178
|
+
return plugin.models.insights.scan(input);
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
const apiKeys = createApiKeyManagement({
|
|
182
|
+
apiKeys: plugin.models.apiKeys,
|
|
183
|
+
beforeOperation: assertSchemaReady,
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
const handlers = createHotUpdaterHandlers(
|
|
187
|
+
core.api,
|
|
188
|
+
insights,
|
|
189
|
+
clientAccess.type === "api-key"
|
|
115
190
|
? {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
191
|
+
authenticate: (request) =>
|
|
192
|
+
authenticateApiKey({
|
|
193
|
+
apiKeys: plugin.models.apiKeys,
|
|
194
|
+
beforeLookup: assertSchemaReady,
|
|
195
|
+
headerName: clientAccess.headerName,
|
|
196
|
+
request,
|
|
197
|
+
}),
|
|
198
|
+
headerName: clientAccess.headerName,
|
|
119
199
|
}
|
|
120
|
-
:
|
|
200
|
+
: undefined,
|
|
201
|
+
downloadStorageObject,
|
|
121
202
|
);
|
|
122
203
|
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
request,
|
|
133
|
-
context,
|
|
134
|
-
...extraArgs: unknown[]
|
|
135
|
-
) => {
|
|
136
|
-
if (extraArgs.length > 0) {
|
|
137
|
-
return internalHandler(request);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
return internalHandler(request, context);
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
const api = {
|
|
144
|
-
basePath,
|
|
145
|
-
adapterName: adapterCapabilities.adapterName ?? core.adapterName,
|
|
146
|
-
handler,
|
|
147
|
-
};
|
|
148
|
-
Object.defineProperties(api, Object.getOwnPropertyDescriptors(core.api));
|
|
204
|
+
const api: RuntimeHotUpdaterAPI = Object.assign(
|
|
205
|
+
{
|
|
206
|
+
adapterName: adapterCapabilities.adapterName ?? core.adapterName,
|
|
207
|
+
insights,
|
|
208
|
+
apiKeys,
|
|
209
|
+
handlers,
|
|
210
|
+
},
|
|
211
|
+
core.api,
|
|
212
|
+
);
|
|
149
213
|
Object.defineProperty(api, hotUpdaterCoreMetadata, {
|
|
150
214
|
enumerable: false,
|
|
151
215
|
value: {
|
|
152
216
|
adapterCapabilities,
|
|
153
217
|
core,
|
|
154
|
-
} satisfies HotUpdaterCoreMetadata
|
|
218
|
+
} satisfies HotUpdaterCoreMetadata,
|
|
155
219
|
});
|
|
156
220
|
|
|
157
221
|
return {
|
|
158
|
-
api
|
|
222
|
+
api,
|
|
159
223
|
adapterCapabilities,
|
|
160
224
|
core,
|
|
161
225
|
};
|
|
162
226
|
}
|
|
163
227
|
|
|
164
|
-
export function createHotUpdater
|
|
165
|
-
options: CreateHotUpdaterOptions
|
|
166
|
-
): RuntimeHotUpdaterAPI
|
|
228
|
+
export function createHotUpdater(
|
|
229
|
+
options: CreateHotUpdaterOptions,
|
|
230
|
+
): RuntimeHotUpdaterAPI {
|
|
167
231
|
return createHotUpdaterCore(options).api;
|
|
168
232
|
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import type { Bundle } from "@hot-updater/core";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
BundleRowHydrationError,
|
|
6
|
+
bundleToPatchRows,
|
|
7
|
+
bundleToRow,
|
|
8
|
+
rowsToBundles,
|
|
9
|
+
type BundlePatchRow,
|
|
10
|
+
type BundleRow,
|
|
11
|
+
} from "./bundleRows";
|
|
12
|
+
|
|
13
|
+
const createBundle = (id: string): Bundle => ({
|
|
14
|
+
id,
|
|
15
|
+
platform: "ios",
|
|
16
|
+
fileHash: `hash-${id}`,
|
|
17
|
+
gitCommitHash: null,
|
|
18
|
+
storageUri: `s3://bucket/${id}.zip`,
|
|
19
|
+
archiveByteSize: 3_000_000_001,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const toRow = (bundle: Bundle): BundleRow => bundleToRow(bundle);
|
|
23
|
+
|
|
24
|
+
const createPatchRow = (
|
|
25
|
+
id: string,
|
|
26
|
+
bundleId: string,
|
|
27
|
+
baseBundleId: string,
|
|
28
|
+
orderIndex: number,
|
|
29
|
+
): BundlePatchRow => ({
|
|
30
|
+
id,
|
|
31
|
+
bundle_id: bundleId,
|
|
32
|
+
base_bundle_id: baseBundleId,
|
|
33
|
+
base_file_hash: `base-hash-${id}`,
|
|
34
|
+
patch_file_hash: `patch-hash-${id}`,
|
|
35
|
+
patch_storage_uri: `s3://bucket/${id}.patch`,
|
|
36
|
+
byte_size: 3_000_000_002,
|
|
37
|
+
order_index: orderIndex,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
describe("bundle row conversion", () => {
|
|
41
|
+
it("round-trips bundle fields without embedding patch artifacts in the bundle row", () => {
|
|
42
|
+
const baseBundle = createBundle("base");
|
|
43
|
+
const bundle: Bundle = {
|
|
44
|
+
...createBundle("target"),
|
|
45
|
+
metadata: { app_version: "1.0.0" },
|
|
46
|
+
manifestStorageUri: "s3://bucket/manifest.json",
|
|
47
|
+
manifestFileHash: "manifest-hash",
|
|
48
|
+
assetBaseStorageUri: "s3://bucket/assets",
|
|
49
|
+
patches: [
|
|
50
|
+
{
|
|
51
|
+
baseBundleId: baseBundle.id,
|
|
52
|
+
baseFileHash: "base-hash",
|
|
53
|
+
byteSize: 3_000_000_002,
|
|
54
|
+
patchFileHash: "patch-hash",
|
|
55
|
+
patchStorageUri: "s3://bucket/target.patch",
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const row = toRow(bundle);
|
|
61
|
+
const patchRows = bundleToPatchRows(bundle);
|
|
62
|
+
const hydratedBundles = rowsToBundles([row], patchRows, [
|
|
63
|
+
toRow(baseBundle),
|
|
64
|
+
]);
|
|
65
|
+
|
|
66
|
+
expect(row).not.toHaveProperty("patches");
|
|
67
|
+
expect(row).not.toHaveProperty("patch_file_hash");
|
|
68
|
+
expect(row).not.toHaveProperty("channel");
|
|
69
|
+
expect(row).not.toHaveProperty("enabled");
|
|
70
|
+
expect(hydratedBundles).toHaveLength(1);
|
|
71
|
+
expect(hydratedBundles[0]).toEqual(bundle);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("orders multiple patches deterministically", () => {
|
|
75
|
+
const oldest = createBundle("oldest");
|
|
76
|
+
const newest = createBundle("newest");
|
|
77
|
+
const target = createBundle("target");
|
|
78
|
+
const rows: readonly BundleRow[] = [toRow(target)];
|
|
79
|
+
const later = createPatchRow("later", target.id, newest.id, 1);
|
|
80
|
+
const firstById = createPatchRow("a-first", target.id, oldest.id, 0);
|
|
81
|
+
const secondById = createPatchRow("z-second", target.id, newest.id, 0);
|
|
82
|
+
|
|
83
|
+
const [hydrated] = rowsToBundles(
|
|
84
|
+
rows,
|
|
85
|
+
[later, secondById, firstById],
|
|
86
|
+
[toRow(oldest), toRow(newest)],
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
expect(hydrated?.patches?.map((patch) => patch.patchFileHash)).toEqual([
|
|
90
|
+
firstById.patch_file_hash,
|
|
91
|
+
secondById.patch_file_hash,
|
|
92
|
+
later.patch_file_hash,
|
|
93
|
+
]);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it("hydrates an empty patch set", () => {
|
|
97
|
+
const bundle = createBundle("without-patches");
|
|
98
|
+
|
|
99
|
+
const [hydrated] = rowsToBundles([toRow(bundle)], [], []);
|
|
100
|
+
|
|
101
|
+
expect(hydrated).toMatchObject({ patches: [] });
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it("preserves nested metadata at the row boundary", () => {
|
|
105
|
+
const row: BundleRow = {
|
|
106
|
+
...toRow(createBundle("nested-metadata")),
|
|
107
|
+
metadata: { release: { flags: [true, null, 3] } },
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const [hydrated] = rowsToBundles([row], [], []);
|
|
111
|
+
|
|
112
|
+
expect(hydrated).toMatchObject({
|
|
113
|
+
metadata: { release: { flags: [true, null, 3] } },
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it("rejects duplicate patch ids during aggregate hydration", () => {
|
|
118
|
+
const base = createBundle("base");
|
|
119
|
+
const target = createBundle("target");
|
|
120
|
+
const patch = createPatchRow("duplicate", target.id, base.id, 0);
|
|
121
|
+
const duplicate = { ...patch, base_file_hash: "different-hash" };
|
|
122
|
+
|
|
123
|
+
const hydrate = () =>
|
|
124
|
+
rowsToBundles([toRow(target)], [patch, duplicate], [toRow(base)]);
|
|
125
|
+
|
|
126
|
+
expect(hydrate).toThrowError(BundleRowHydrationError);
|
|
127
|
+
expect(hydrate).toThrowError(
|
|
128
|
+
expect.objectContaining({
|
|
129
|
+
reason: "duplicate_patch_id",
|
|
130
|
+
patchId: patch.id,
|
|
131
|
+
}),
|
|
132
|
+
);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it("rejects a patch whose owner bundle row is absent", () => {
|
|
136
|
+
const base = createBundle("base");
|
|
137
|
+
const patch = createPatchRow("orphan-owner", "missing", base.id, 0);
|
|
138
|
+
|
|
139
|
+
const hydrate = () => rowsToBundles([], [patch], [toRow(base)]);
|
|
140
|
+
|
|
141
|
+
expect(hydrate).toThrowError(
|
|
142
|
+
expect.objectContaining({
|
|
143
|
+
reason: "orphan_patch_owner",
|
|
144
|
+
patchId: patch.id,
|
|
145
|
+
bundleId: patch.bundle_id,
|
|
146
|
+
}),
|
|
147
|
+
);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it("rejects a patch whose base bundle row is absent", () => {
|
|
151
|
+
const target = createBundle("target");
|
|
152
|
+
const patch = createPatchRow("orphan-base", target.id, "missing", 0);
|
|
153
|
+
|
|
154
|
+
const hydrate = () => rowsToBundles([toRow(target)], [patch], []);
|
|
155
|
+
|
|
156
|
+
expect(hydrate).toThrowError(
|
|
157
|
+
expect.objectContaining({
|
|
158
|
+
reason: "orphan_patch_base",
|
|
159
|
+
patchId: patch.id,
|
|
160
|
+
bundleId: patch.base_bundle_id,
|
|
161
|
+
}),
|
|
162
|
+
);
|
|
163
|
+
});
|
|
164
|
+
});
|
package/src/db/bundleRows.ts
CHANGED
|
@@ -1,140 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
import { parseBundleMetadata } from "./updateArtifacts";
|
|
12
|
-
|
|
13
|
-
export type BundleRow = {
|
|
14
|
-
readonly id: string;
|
|
15
|
-
readonly platform: string;
|
|
16
|
-
readonly should_force_update: unknown;
|
|
17
|
-
readonly enabled: unknown;
|
|
18
|
-
readonly file_hash: string;
|
|
19
|
-
readonly git_commit_hash: string | null;
|
|
20
|
-
readonly message: string | null;
|
|
21
|
-
readonly channel: string;
|
|
22
|
-
readonly storage_uri: string;
|
|
23
|
-
readonly target_app_version: string | null;
|
|
24
|
-
readonly fingerprint_hash: string | null;
|
|
25
|
-
readonly metadata?: unknown;
|
|
26
|
-
readonly manifest_storage_uri?: string | null;
|
|
27
|
-
readonly manifest_file_hash?: string | null;
|
|
28
|
-
readonly asset_base_storage_uri?: string | null;
|
|
29
|
-
readonly rollout_cohort_count?: number | null;
|
|
30
|
-
readonly target_cohorts?: unknown;
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
export type BundlePatchRow = {
|
|
34
|
-
readonly id: string;
|
|
35
|
-
readonly bundle_id: string;
|
|
36
|
-
readonly base_bundle_id: string;
|
|
37
|
-
readonly base_file_hash: string;
|
|
38
|
-
readonly patch_file_hash: string;
|
|
39
|
-
readonly patch_storage_uri: string;
|
|
40
|
-
readonly order_index?: number | null;
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
const parseTargetCohorts = (value: unknown): string[] | null => {
|
|
44
|
-
if (!value) return null;
|
|
45
|
-
if (Array.isArray(value)) {
|
|
46
|
-
return value.filter((item): item is string => typeof item === "string");
|
|
47
|
-
}
|
|
48
|
-
if (typeof value !== "string") return null;
|
|
49
|
-
try {
|
|
50
|
-
const parsed = JSON.parse(value) as unknown;
|
|
51
|
-
return Array.isArray(parsed)
|
|
52
|
-
? parsed.filter((item): item is string => typeof item === "string")
|
|
53
|
-
: null;
|
|
54
|
-
} catch {
|
|
55
|
-
return null;
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
const buildBundlePatchId = (bundleId: string, baseBundleId: string) =>
|
|
60
|
-
`${bundleId}:${baseBundleId}`;
|
|
61
|
-
|
|
62
|
-
export const bundleToRow = (bundle: Bundle): BundleRow => ({
|
|
63
|
-
id: bundle.id,
|
|
64
|
-
platform: bundle.platform,
|
|
65
|
-
should_force_update: bundle.shouldForceUpdate,
|
|
66
|
-
enabled: bundle.enabled,
|
|
67
|
-
file_hash: bundle.fileHash,
|
|
68
|
-
git_commit_hash: bundle.gitCommitHash,
|
|
69
|
-
message: bundle.message,
|
|
70
|
-
channel: bundle.channel,
|
|
71
|
-
storage_uri: bundle.storageUri,
|
|
72
|
-
target_app_version: bundle.targetAppVersion,
|
|
73
|
-
fingerprint_hash: bundle.fingerprintHash,
|
|
74
|
-
metadata: stripBundleArtifactMetadata(bundle.metadata) ?? {},
|
|
75
|
-
manifest_storage_uri: getManifestStorageUri(bundle),
|
|
76
|
-
manifest_file_hash: getManifestFileHash(bundle),
|
|
77
|
-
asset_base_storage_uri: getAssetBaseStorageUri(bundle),
|
|
78
|
-
rollout_cohort_count:
|
|
79
|
-
bundle.rolloutCohortCount ?? DEFAULT_ROLLOUT_COHORT_COUNT,
|
|
80
|
-
target_cohorts: bundle.targetCohorts ?? null,
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
export const bundleToPatchRows = (bundle: Bundle): BundlePatchRow[] =>
|
|
84
|
-
getBundlePatches(bundle).map((patch, index) => ({
|
|
85
|
-
id: buildBundlePatchId(bundle.id, patch.baseBundleId),
|
|
86
|
-
bundle_id: bundle.id,
|
|
87
|
-
base_bundle_id: patch.baseBundleId,
|
|
88
|
-
base_file_hash: patch.baseFileHash,
|
|
89
|
-
patch_file_hash: patch.patchFileHash,
|
|
90
|
-
patch_storage_uri: patch.patchStorageUri,
|
|
91
|
-
order_index: index,
|
|
92
|
-
}));
|
|
93
|
-
|
|
94
|
-
const mapPatchRowToPatch = (record: BundlePatchRow): BundlePatchArtifact => ({
|
|
95
|
-
baseBundleId: record.base_bundle_id,
|
|
96
|
-
baseFileHash: record.base_file_hash,
|
|
97
|
-
patchFileHash: record.patch_file_hash,
|
|
98
|
-
patchStorageUri: record.patch_storage_uri,
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
export const rowToBundle = (
|
|
102
|
-
record: BundleRow,
|
|
103
|
-
patchRecords: readonly BundlePatchRow[] = [],
|
|
104
|
-
): Bundle => {
|
|
105
|
-
const patches = patchRecords
|
|
106
|
-
.slice()
|
|
107
|
-
.sort(
|
|
108
|
-
(left, right) =>
|
|
109
|
-
(left.order_index ?? 0) - (right.order_index ?? 0) ||
|
|
110
|
-
left.base_bundle_id.localeCompare(right.base_bundle_id),
|
|
111
|
-
)
|
|
112
|
-
.map(mapPatchRowToPatch);
|
|
113
|
-
const primaryPatch = patches[0] ?? null;
|
|
114
|
-
|
|
115
|
-
return {
|
|
116
|
-
id: record.id,
|
|
117
|
-
platform: record.platform as Platform,
|
|
118
|
-
shouldForceUpdate: Boolean(record.should_force_update),
|
|
119
|
-
enabled: Boolean(record.enabled),
|
|
120
|
-
fileHash: record.file_hash,
|
|
121
|
-
gitCommitHash: record.git_commit_hash ?? null,
|
|
122
|
-
message: record.message ?? null,
|
|
123
|
-
channel: record.channel,
|
|
124
|
-
storageUri: record.storage_uri,
|
|
125
|
-
targetAppVersion: record.target_app_version ?? null,
|
|
126
|
-
fingerprintHash: record.fingerprint_hash ?? null,
|
|
127
|
-
metadata: parseBundleMetadata(record.metadata),
|
|
128
|
-
manifestStorageUri: record.manifest_storage_uri ?? null,
|
|
129
|
-
manifestFileHash: record.manifest_file_hash ?? null,
|
|
130
|
-
assetBaseStorageUri: record.asset_base_storage_uri ?? null,
|
|
131
|
-
patches,
|
|
132
|
-
patchBaseBundleId: primaryPatch?.baseBundleId ?? null,
|
|
133
|
-
patchBaseFileHash: primaryPatch?.baseFileHash ?? null,
|
|
134
|
-
patchFileHash: primaryPatch?.patchFileHash ?? null,
|
|
135
|
-
patchStorageUri: primaryPatch?.patchStorageUri ?? null,
|
|
136
|
-
rolloutCohortCount:
|
|
137
|
-
record.rollout_cohort_count ?? DEFAULT_ROLLOUT_COHORT_COUNT,
|
|
138
|
-
targetCohorts: parseTargetCohorts(record.target_cohorts),
|
|
139
|
-
};
|
|
140
|
-
};
|
|
1
|
+
export {
|
|
2
|
+
BundleRowHydrationError,
|
|
3
|
+
BundleRowHydrationErrorReason,
|
|
4
|
+
bundleToPatchRows,
|
|
5
|
+
bundleToRow,
|
|
6
|
+
rowToBundle,
|
|
7
|
+
rowsToBundles,
|
|
8
|
+
} from "@hot-updater/plugin-core";
|
|
9
|
+
|
|
10
|
+
export type { BundlePatchRow, BundleRow } from "@hot-updater/plugin-core";
|