@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
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import { HOT_UPDATER_CORE_SCHEMA_KEY, HOT_UPDATER_SCHEMA_VERSION, HOT_UPDATER_SETTINGS_TABLE } from "../schema/types.mjs";
|
|
2
|
+
import { assertCurrentOrEmptySchemaVersion, assertSupportedMigrationMode, getEmptyMigrationResult, inferLegacyCoreSchemaVersion, isCurrentSchemaVersion } from "./fixedMigratorShared.mjs";
|
|
3
|
+
import { hotUpdaterSchema, schemaIndexAppliesToProvider } from "./schema/registry.mjs";
|
|
4
|
+
import { executeMongoMigration } from "./mongoMigrationExecution.mjs";
|
|
5
|
+
import { createMongoMigrationOperations } from "./schema/mongodb.mjs";
|
|
6
|
+
//#region src/db/fixedMigratorMongo.ts
|
|
7
|
+
const isMongoNamespaceExistsError = (error) => {
|
|
8
|
+
if (!(error instanceof Error)) return false;
|
|
9
|
+
const mongoError = error;
|
|
10
|
+
return mongoError.code === 48 || mongoError.codeName === "NamespaceExists";
|
|
11
|
+
};
|
|
12
|
+
const isMongoNamespaceNotFoundError = (error) => {
|
|
13
|
+
if (!(error instanceof Error)) return false;
|
|
14
|
+
const mongoError = error;
|
|
15
|
+
return mongoError.code === 26 || mongoError.codeName === "NamespaceNotFound";
|
|
16
|
+
};
|
|
17
|
+
const ignoreExistingCollection = (error) => {
|
|
18
|
+
if (isMongoNamespaceExistsError(error)) return;
|
|
19
|
+
throw error;
|
|
20
|
+
};
|
|
21
|
+
const mongoNullableString = { bsonType: ["string", "null"] };
|
|
22
|
+
const mongoByteSize = {
|
|
23
|
+
bsonType: [
|
|
24
|
+
"double",
|
|
25
|
+
"int",
|
|
26
|
+
"long"
|
|
27
|
+
],
|
|
28
|
+
maximum: Number.MAX_SAFE_INTEGER,
|
|
29
|
+
minimum: 0
|
|
30
|
+
};
|
|
31
|
+
const mongoBundleValidator = { $and: [{ $jsonSchema: {
|
|
32
|
+
bsonType: "object",
|
|
33
|
+
properties: {
|
|
34
|
+
archive_byte_size: mongoByteSize,
|
|
35
|
+
asset_base_storage_uri: mongoNullableString,
|
|
36
|
+
file_hash: { bsonType: "string" },
|
|
37
|
+
git_commit_hash: mongoNullableString,
|
|
38
|
+
id: { bsonType: "string" },
|
|
39
|
+
manifest_file_hash: mongoNullableString,
|
|
40
|
+
manifest_storage_uri: mongoNullableString,
|
|
41
|
+
metadata: { bsonType: "object" },
|
|
42
|
+
platform: { enum: ["ios", "android"] },
|
|
43
|
+
storage_uri: { bsonType: "string" }
|
|
44
|
+
},
|
|
45
|
+
required: [
|
|
46
|
+
"id",
|
|
47
|
+
"platform",
|
|
48
|
+
"file_hash",
|
|
49
|
+
"git_commit_hash",
|
|
50
|
+
"storage_uri",
|
|
51
|
+
"archive_byte_size",
|
|
52
|
+
"metadata",
|
|
53
|
+
"manifest_storage_uri",
|
|
54
|
+
"manifest_file_hash",
|
|
55
|
+
"asset_base_storage_uri"
|
|
56
|
+
]
|
|
57
|
+
} }, { $expr: { $eq: [{ $trunc: "$archive_byte_size" }, "$archive_byte_size"] } }] };
|
|
58
|
+
const mongoPatchValidator = { $and: [{ $jsonSchema: {
|
|
59
|
+
bsonType: "object",
|
|
60
|
+
properties: {
|
|
61
|
+
base_bundle_id: { bsonType: "string" },
|
|
62
|
+
base_file_hash: { bsonType: "string" },
|
|
63
|
+
bundle_id: { bsonType: "string" },
|
|
64
|
+
id: { bsonType: "string" },
|
|
65
|
+
order_index: mongoByteSize,
|
|
66
|
+
byte_size: mongoByteSize,
|
|
67
|
+
patch_file_hash: { bsonType: "string" },
|
|
68
|
+
patch_storage_uri: { bsonType: "string" }
|
|
69
|
+
},
|
|
70
|
+
required: [
|
|
71
|
+
"id",
|
|
72
|
+
"bundle_id",
|
|
73
|
+
"base_bundle_id",
|
|
74
|
+
"base_file_hash",
|
|
75
|
+
"patch_file_hash",
|
|
76
|
+
"patch_storage_uri",
|
|
77
|
+
"byte_size",
|
|
78
|
+
"order_index"
|
|
79
|
+
]
|
|
80
|
+
} }, { $expr: { $and: [{ $eq: [{ $trunc: "$order_index" }, "$order_index"] }, { $eq: [{ $trunc: "$byte_size" }, "$byte_size"] }] } }] };
|
|
81
|
+
const mongoReleaseValidator = { $jsonSchema: {
|
|
82
|
+
bsonType: "object",
|
|
83
|
+
properties: {
|
|
84
|
+
bundle_id: mongoNullableString,
|
|
85
|
+
channel_id: { bsonType: "string" },
|
|
86
|
+
created_at_ms: { bsonType: [
|
|
87
|
+
"double",
|
|
88
|
+
"int",
|
|
89
|
+
"long"
|
|
90
|
+
] },
|
|
91
|
+
enabled: { bsonType: "bool" },
|
|
92
|
+
fingerprint_hash: mongoNullableString,
|
|
93
|
+
id: { bsonType: "string" },
|
|
94
|
+
kind: { enum: ["BUNDLE", "EMBEDDED"] },
|
|
95
|
+
message: mongoNullableString,
|
|
96
|
+
operation: { enum: [
|
|
97
|
+
"DEPLOY",
|
|
98
|
+
"PROMOTE",
|
|
99
|
+
"ROLLBACK"
|
|
100
|
+
] },
|
|
101
|
+
platform: { enum: ["ios", "android"] },
|
|
102
|
+
revision: { bsonType: ["int", "long"] },
|
|
103
|
+
rollout_cohort_count: { bsonType: ["int", "long"] },
|
|
104
|
+
scope_key: { bsonType: "string" },
|
|
105
|
+
should_force_update: { bsonType: "bool" },
|
|
106
|
+
source_release_id: mongoNullableString,
|
|
107
|
+
strategy: { enum: ["APP_VERSION", "FINGERPRINT"] },
|
|
108
|
+
target_app_version: mongoNullableString,
|
|
109
|
+
target_cohorts: {
|
|
110
|
+
bsonType: "array",
|
|
111
|
+
items: { bsonType: "string" }
|
|
112
|
+
},
|
|
113
|
+
updated_at_ms: { bsonType: [
|
|
114
|
+
"double",
|
|
115
|
+
"int",
|
|
116
|
+
"long"
|
|
117
|
+
] }
|
|
118
|
+
},
|
|
119
|
+
required: [
|
|
120
|
+
"id",
|
|
121
|
+
"revision",
|
|
122
|
+
"scope_key",
|
|
123
|
+
"channel_id",
|
|
124
|
+
"platform",
|
|
125
|
+
"kind",
|
|
126
|
+
"bundle_id",
|
|
127
|
+
"strategy",
|
|
128
|
+
"target_app_version",
|
|
129
|
+
"fingerprint_hash",
|
|
130
|
+
"enabled",
|
|
131
|
+
"should_force_update",
|
|
132
|
+
"message",
|
|
133
|
+
"rollout_cohort_count",
|
|
134
|
+
"target_cohorts",
|
|
135
|
+
"operation",
|
|
136
|
+
"source_release_id",
|
|
137
|
+
"created_at_ms",
|
|
138
|
+
"updated_at_ms"
|
|
139
|
+
]
|
|
140
|
+
} };
|
|
141
|
+
const mongoReleaseCatalogValidator = { $jsonSchema: {
|
|
142
|
+
bsonType: "object",
|
|
143
|
+
properties: {
|
|
144
|
+
catalog_id: { bsonType: "string" },
|
|
145
|
+
byte_size: { bsonType: ["int", "long"] },
|
|
146
|
+
catalog_hash: { bsonType: "string" },
|
|
147
|
+
channel_id: { bsonType: "string" },
|
|
148
|
+
channel_key: { bsonType: "string" },
|
|
149
|
+
fingerprint_hash: mongoNullableString,
|
|
150
|
+
generation: { bsonType: [
|
|
151
|
+
"double",
|
|
152
|
+
"int",
|
|
153
|
+
"long"
|
|
154
|
+
] },
|
|
155
|
+
is_tombstone: { bsonType: "bool" },
|
|
156
|
+
payload: { bsonType: "string" },
|
|
157
|
+
platform: { enum: ["ios", "android"] },
|
|
158
|
+
scope_key: { bsonType: "string" },
|
|
159
|
+
strategy: { enum: ["APP_VERSION", "FINGERPRINT"] },
|
|
160
|
+
updated_at_ms: { bsonType: [
|
|
161
|
+
"double",
|
|
162
|
+
"int",
|
|
163
|
+
"long"
|
|
164
|
+
] }
|
|
165
|
+
},
|
|
166
|
+
required: [
|
|
167
|
+
"scope_key",
|
|
168
|
+
"catalog_id",
|
|
169
|
+
"strategy",
|
|
170
|
+
"channel_id",
|
|
171
|
+
"channel_key",
|
|
172
|
+
"platform",
|
|
173
|
+
"fingerprint_hash",
|
|
174
|
+
"generation",
|
|
175
|
+
"payload",
|
|
176
|
+
"catalog_hash",
|
|
177
|
+
"byte_size",
|
|
178
|
+
"is_tombstone",
|
|
179
|
+
"updated_at_ms"
|
|
180
|
+
]
|
|
181
|
+
} };
|
|
182
|
+
const createSettingsKeyIndexOperation = () => ({
|
|
183
|
+
description: `Ensure unique MongoDB index: ${HOT_UPDATER_SETTINGS_TABLE}(key)`,
|
|
184
|
+
type: "custom"
|
|
185
|
+
});
|
|
186
|
+
const createMongoMigrator = (client) => {
|
|
187
|
+
const settings = client.db().collection(HOT_UPDATER_SETTINGS_TABLE);
|
|
188
|
+
const getSetting = async (key) => {
|
|
189
|
+
const [row, duplicate] = await settings.find({ key }).limit(2).toArray();
|
|
190
|
+
if (!row) return void 0;
|
|
191
|
+
if (duplicate) throw new Error(`Duplicate Hot Updater schema setting: ${key}`);
|
|
192
|
+
if (typeof row.value !== "string") throw new Error(`Invalid Hot Updater schema setting: ${key}`);
|
|
193
|
+
return row.value;
|
|
194
|
+
};
|
|
195
|
+
const getCoreVersion = () => getSetting(HOT_UPDATER_CORE_SCHEMA_KEY);
|
|
196
|
+
const getSchemaVersions = async () => {
|
|
197
|
+
return {
|
|
198
|
+
coreVersion: await getCoreVersion(),
|
|
199
|
+
legacyCoreVersion: inferLegacyCoreSchemaVersion(await getSetting("version"))
|
|
200
|
+
};
|
|
201
|
+
};
|
|
202
|
+
const getVersion = async () => {
|
|
203
|
+
const { coreVersion, legacyCoreVersion } = await getSchemaVersions();
|
|
204
|
+
return coreVersion ?? legacyCoreVersion;
|
|
205
|
+
};
|
|
206
|
+
const getSettingsKeyIndexState = async () => {
|
|
207
|
+
const index = (await settings.listIndexes().toArray().catch((error) => {
|
|
208
|
+
if (isMongoNamespaceNotFoundError(error)) return [];
|
|
209
|
+
throw error;
|
|
210
|
+
})).find(({ key }) => {
|
|
211
|
+
const fields = Object.entries(key);
|
|
212
|
+
return fields.length === 1 && fields[0]?.[0] === "key" && fields[0][1] === 1;
|
|
213
|
+
});
|
|
214
|
+
if (!index) return "missing";
|
|
215
|
+
return index.unique === true && index.sparse !== true && index.partialFilterExpression === void 0 ? "unique" : "non-unique";
|
|
216
|
+
};
|
|
217
|
+
const rejectNonUniqueSettingsKeyIndex = () => {
|
|
218
|
+
throw new Error("Hot Updater settings key index must enforce uniqueness for every key.");
|
|
219
|
+
};
|
|
220
|
+
const ensureSettingsKeyIndex = async () => {
|
|
221
|
+
const state = await getSettingsKeyIndexState();
|
|
222
|
+
if (state === "unique") return;
|
|
223
|
+
if (state === "non-unique") rejectNonUniqueSettingsKeyIndex();
|
|
224
|
+
await settings.createIndex({ key: 1 }, { unique: true });
|
|
225
|
+
};
|
|
226
|
+
const makeResult = async (options = {}) => {
|
|
227
|
+
assertSupportedMigrationMode(options);
|
|
228
|
+
const { coreVersion, legacyCoreVersion } = await getSchemaVersions();
|
|
229
|
+
const settingsKeyIndexState = await getSettingsKeyIndexState();
|
|
230
|
+
if (settingsKeyIndexState === "non-unique") rejectNonUniqueSettingsKeyIndex();
|
|
231
|
+
if (isCurrentSchemaVersion(coreVersion)) {
|
|
232
|
+
if (settingsKeyIndexState === "unique") return getEmptyMigrationResult();
|
|
233
|
+
return {
|
|
234
|
+
...getEmptyMigrationResult(),
|
|
235
|
+
execute: ensureSettingsKeyIndex,
|
|
236
|
+
operations: [createSettingsKeyIndexOperation()]
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
assertCurrentOrEmptySchemaVersion(coreVersion ?? legacyCoreVersion);
|
|
240
|
+
const settingsOperation = options.updateSettings === false ? void 0 : {
|
|
241
|
+
type: "custom",
|
|
242
|
+
key: HOT_UPDATER_CORE_SCHEMA_KEY,
|
|
243
|
+
value: HOT_UPDATER_SCHEMA_VERSION
|
|
244
|
+
};
|
|
245
|
+
return {
|
|
246
|
+
operations: [createSettingsKeyIndexOperation(), ...createMongoMigrationOperations(settingsOperation)],
|
|
247
|
+
execute: async () => {
|
|
248
|
+
const db = client.db();
|
|
249
|
+
await executeMongoMigration({
|
|
250
|
+
updateSettings: options.updateSettings !== false,
|
|
251
|
+
backend: {
|
|
252
|
+
ensureCollections: async () => {
|
|
253
|
+
for (const table of hotUpdaterSchema.tables) {
|
|
254
|
+
if (table.internal) continue;
|
|
255
|
+
await db.createCollection(table.ormName).catch(ignoreExistingCollection);
|
|
256
|
+
}
|
|
257
|
+
},
|
|
258
|
+
ensureIndexes: async () => {
|
|
259
|
+
await ensureSettingsKeyIndex();
|
|
260
|
+
for (const table of hotUpdaterSchema.tables) {
|
|
261
|
+
if (table.internal) continue;
|
|
262
|
+
const collection = db.collection(table.ormName);
|
|
263
|
+
const primaryKey = table.columns.find((column) => column.primaryKey);
|
|
264
|
+
if (!primaryKey) throw new Error(`MongoDB table ${table.ormName} does not define a primary key.`);
|
|
265
|
+
const idIndexName = `${table.ormName}_${primaryKey.ormName}_idx`;
|
|
266
|
+
const existingIdIndex = (await collection.listIndexes().toArray()).find(({ name }) => name === idIndexName);
|
|
267
|
+
if (existingIdIndex && existingIdIndex.unique !== true) await collection.dropIndex(idIndexName);
|
|
268
|
+
await collection.createIndex({ [primaryKey.ormName]: 1 }, {
|
|
269
|
+
name: idIndexName,
|
|
270
|
+
unique: true
|
|
271
|
+
});
|
|
272
|
+
for (const index of (table.indexes ?? []).filter((item) => schemaIndexAppliesToProvider(item, "mongodb"))) await collection.createIndex(Object.fromEntries(index.columns.map((column) => [column, 1])), {
|
|
273
|
+
name: index.name,
|
|
274
|
+
...index.unique ? { unique: true } : {}
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
},
|
|
278
|
+
enforceSchema: async () => {
|
|
279
|
+
for (const [collection, validator] of [
|
|
280
|
+
["bundles", mongoBundleValidator],
|
|
281
|
+
["bundle_patches", mongoPatchValidator],
|
|
282
|
+
["releases", mongoReleaseValidator],
|
|
283
|
+
["release_catalogs", mongoReleaseCatalogValidator]
|
|
284
|
+
]) await db.command({
|
|
285
|
+
collMod: collection,
|
|
286
|
+
validationAction: "error",
|
|
287
|
+
validationLevel: "strict",
|
|
288
|
+
validator
|
|
289
|
+
});
|
|
290
|
+
},
|
|
291
|
+
updateVersion: async () => {
|
|
292
|
+
await settings.updateOne({ key: HOT_UPDATER_CORE_SCHEMA_KEY }, { $set: { value: HOT_UPDATER_SCHEMA_VERSION } }, { upsert: true });
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
};
|
|
299
|
+
return {
|
|
300
|
+
getVersion,
|
|
301
|
+
getNameVariants: async () => void 0,
|
|
302
|
+
next: async () => {
|
|
303
|
+
const { coreVersion } = await getSchemaVersions();
|
|
304
|
+
return isCurrentSchemaVersion(coreVersion) ? void 0 : { version: HOT_UPDATER_SCHEMA_VERSION };
|
|
305
|
+
},
|
|
306
|
+
previous: async () => void 0,
|
|
307
|
+
up: makeResult,
|
|
308
|
+
down: async () => {
|
|
309
|
+
throw new Error("No previous schema to migrate to.");
|
|
310
|
+
},
|
|
311
|
+
migrateTo: async (version, options) => {
|
|
312
|
+
if (version !== "1.0.0") throw new Error(`Invalid version ${version}`);
|
|
313
|
+
return makeResult(options);
|
|
314
|
+
},
|
|
315
|
+
migrateToLatest: makeResult
|
|
316
|
+
};
|
|
317
|
+
};
|
|
318
|
+
//#endregion
|
|
319
|
+
export { createMongoMigrator };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const require_types = require("../schema/types.cjs");
|
|
2
|
+
//#region src/db/fixedMigratorShared.ts
|
|
3
|
+
const getEmptyMigrationResult = () => ({
|
|
4
|
+
operations: [],
|
|
5
|
+
execute: async () => {},
|
|
6
|
+
getSQL: () => ""
|
|
7
|
+
});
|
|
8
|
+
const assertSupportedMigrationMode = (options) => {
|
|
9
|
+
if (options.mode === "from-database") throw new Error("Hot Updater migrations support only mode: 'from-schema'.");
|
|
10
|
+
};
|
|
11
|
+
const unsupportedSchemaUpgradeMessage = (version) => `Hot Updater v1 cannot migrate schema ${version} in place. Create a new empty database and run migrate or generate against schema ${require_types.HOT_UPDATER_SCHEMA_VERSION}.`;
|
|
12
|
+
const assertCurrentOrEmptySchemaVersion = (currentVersion) => {
|
|
13
|
+
if (currentVersion !== void 0 && currentVersion !== "1.0.0") throw new Error(unsupportedSchemaUpgradeMessage(currentVersion));
|
|
14
|
+
};
|
|
15
|
+
const inferLegacyCoreSchemaVersion = (legacyVersion) => legacyVersion;
|
|
16
|
+
const isCurrentSchemaVersion = (currentVersion) => currentVersion === require_types.HOT_UPDATER_SCHEMA_VERSION;
|
|
17
|
+
//#endregion
|
|
18
|
+
exports.assertCurrentOrEmptySchemaVersion = assertCurrentOrEmptySchemaVersion;
|
|
19
|
+
exports.assertSupportedMigrationMode = assertSupportedMigrationMode;
|
|
20
|
+
exports.getEmptyMigrationResult = getEmptyMigrationResult;
|
|
21
|
+
exports.inferLegacyCoreSchemaVersion = inferLegacyCoreSchemaVersion;
|
|
22
|
+
exports.isCurrentSchemaVersion = isCurrentSchemaVersion;
|
|
23
|
+
exports.unsupportedSchemaUpgradeMessage = unsupportedSchemaUpgradeMessage;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { HOT_UPDATER_SCHEMA_VERSION } from "../schema/types.mjs";
|
|
2
|
+
//#region src/db/fixedMigratorShared.ts
|
|
3
|
+
const getEmptyMigrationResult = () => ({
|
|
4
|
+
operations: [],
|
|
5
|
+
execute: async () => {},
|
|
6
|
+
getSQL: () => ""
|
|
7
|
+
});
|
|
8
|
+
const assertSupportedMigrationMode = (options) => {
|
|
9
|
+
if (options.mode === "from-database") throw new Error("Hot Updater migrations support only mode: 'from-schema'.");
|
|
10
|
+
};
|
|
11
|
+
const unsupportedSchemaUpgradeMessage = (version) => `Hot Updater v1 cannot migrate schema ${version} in place. Create a new empty database and run migrate or generate against schema ${HOT_UPDATER_SCHEMA_VERSION}.`;
|
|
12
|
+
const assertCurrentOrEmptySchemaVersion = (currentVersion) => {
|
|
13
|
+
if (currentVersion !== void 0 && currentVersion !== "1.0.0") throw new Error(unsupportedSchemaUpgradeMessage(currentVersion));
|
|
14
|
+
};
|
|
15
|
+
const inferLegacyCoreSchemaVersion = (legacyVersion) => legacyVersion;
|
|
16
|
+
const isCurrentSchemaVersion = (currentVersion) => currentVersion === HOT_UPDATER_SCHEMA_VERSION;
|
|
17
|
+
//#endregion
|
|
18
|
+
export { assertCurrentOrEmptySchemaVersion, assertSupportedMigrationMode, getEmptyMigrationResult, inferLegacyCoreSchemaVersion, isCurrentSchemaVersion, unsupportedSchemaUpgradeMessage };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region src/db/mongoMigrationExecution.ts
|
|
2
|
+
const executeMongoMigration = async ({ backend, updateSettings }) => {
|
|
3
|
+
await backend.ensureCollections();
|
|
4
|
+
await backend.backfillData?.();
|
|
5
|
+
await backend.validateData?.();
|
|
6
|
+
await backend.ensureIndexes();
|
|
7
|
+
await backend.enforceSchema?.();
|
|
8
|
+
if (updateSettings) await backend.updateVersion();
|
|
9
|
+
};
|
|
10
|
+
//#endregion
|
|
11
|
+
exports.executeMongoMigration = executeMongoMigration;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region src/db/mongoMigrationExecution.ts
|
|
2
|
+
const executeMongoMigration = async ({ backend, updateSettings }) => {
|
|
3
|
+
await backend.ensureCollections();
|
|
4
|
+
await backend.backfillData?.();
|
|
5
|
+
await backend.validateData?.();
|
|
6
|
+
await backend.ensureIndexes();
|
|
7
|
+
await backend.enforceSchema?.();
|
|
8
|
+
if (updateSettings) await backend.updateVersion();
|
|
9
|
+
};
|
|
10
|
+
//#endregion
|
|
11
|
+
export { executeMongoMigration };
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
require("../_virtual/_rolldown/runtime.cjs");
|
|
2
|
+
const require_updateArtifacts = require("./updateArtifacts.cjs");
|
|
3
|
+
let _hot_updater_plugin_core = require("@hot-updater/plugin-core");
|
|
4
|
+
let _hot_updater_core = require("@hot-updater/core");
|
|
5
|
+
//#region src/db/releaseCatalog.ts
|
|
6
|
+
const parseCompiledCatalog = (payload, strategy) => {
|
|
7
|
+
const parsed = JSON.parse(payload);
|
|
8
|
+
if (typeof parsed !== "object" || parsed === null || Reflect.get(parsed, "schemaVersion") !== _hot_updater_core.RELEASE_CATALOG_SCHEMA_VERSION || Reflect.get(parsed, "strategy") !== strategy || Reflect.get(parsed, "fallbackPolicy") !== _hot_updater_core.RELEASE_CATALOG_FALLBACK_POLICY || !Array.isArray(Reflect.get(parsed, "releaseDescriptors"))) throw new Error("Stored Release catalog payload is invalid");
|
|
9
|
+
if (strategy === "APP_VERSION" && !Array.isArray(Reflect.get(parsed, "segments"))) throw new Error("Stored app-version Release catalog is invalid");
|
|
10
|
+
if (strategy === "FINGERPRINT" && !Array.isArray(Reflect.get(parsed, "releaseIndexes"))) throw new Error("Stored fingerprint Release catalog is invalid");
|
|
11
|
+
return parsed;
|
|
12
|
+
};
|
|
13
|
+
const createReleaseCatalogReader = (database) => async (input) => {
|
|
14
|
+
const scopeKey = input.strategy === "APP_VERSION" ? (0, _hot_updater_core.createReleaseCatalogScopeKey)({
|
|
15
|
+
channelKey: input.channelKey,
|
|
16
|
+
platform: input.platform,
|
|
17
|
+
strategy: "APP_VERSION"
|
|
18
|
+
}) : (0, _hot_updater_core.createReleaseCatalogScopeKey)({
|
|
19
|
+
channelKey: input.channelKey,
|
|
20
|
+
fingerprintHash: input.fingerprintHash,
|
|
21
|
+
platform: input.platform,
|
|
22
|
+
strategy: "FINGERPRINT"
|
|
23
|
+
});
|
|
24
|
+
const row = await database.models.releaseCatalogs.findByScopeKey(scopeKey);
|
|
25
|
+
if (row === null || row.platform !== input.platform || row.strategy !== input.strategy || row.channel_key !== input.channelKey || row.scope_key !== scopeKey || row.fingerprint_hash !== (input.strategy === "FINGERPRINT" ? input.fingerprintHash : null)) return null;
|
|
26
|
+
const compiled = parseCompiledCatalog(row.payload, input.strategy);
|
|
27
|
+
const releases = (0, _hot_updater_plugin_core.projectCompiledCatalog)(compiled, input.strategy === "APP_VERSION" ? input.appVersion : void 0);
|
|
28
|
+
const rollbackReleases = (0, _hot_updater_plugin_core.projectCompiledRollbackCatalog)(compiled, input.strategy === "APP_VERSION" ? input.appVersion : void 0);
|
|
29
|
+
return {
|
|
30
|
+
catalogId: row.catalog_id,
|
|
31
|
+
catalogHash: row.catalog_hash,
|
|
32
|
+
fallbackPolicy: _hot_updater_core.RELEASE_CATALOG_FALLBACK_POLICY,
|
|
33
|
+
generation: row.generation,
|
|
34
|
+
releases,
|
|
35
|
+
rollbackReleases,
|
|
36
|
+
schemaVersion: _hot_updater_core.RELEASE_CATALOG_SCHEMA_VERSION,
|
|
37
|
+
scopeKey
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
const createArtifactResolver = (input) => {
|
|
41
|
+
const databaseClient = (0, _hot_updater_plugin_core.createDatabaseClient)(input.database);
|
|
42
|
+
return async (targetBundleId, currentBundleId) => {
|
|
43
|
+
const [targetBundle, currentBundle] = await Promise.all([databaseClient.getBundleById(targetBundleId), currentBundleId === _hot_updater_core.NIL_UUID ? null : databaseClient.getBundleById(currentBundleId)]);
|
|
44
|
+
if (targetBundle === null) return null;
|
|
45
|
+
const fileUrl = await input.resolveFileUrl(targetBundle.storageUri);
|
|
46
|
+
const base = {
|
|
47
|
+
fileHash: targetBundle.fileHash,
|
|
48
|
+
fileUrl
|
|
49
|
+
};
|
|
50
|
+
if (input.readStorageText === void 0) return base;
|
|
51
|
+
const manifest = await require_updateArtifacts.resolveManifestArtifacts({
|
|
52
|
+
archiveUrlUsable: fileUrl !== null,
|
|
53
|
+
currentBundle,
|
|
54
|
+
readStorageText: input.readStorageText,
|
|
55
|
+
resolveFileUrl: input.resolveFileUrl,
|
|
56
|
+
targetBundle
|
|
57
|
+
});
|
|
58
|
+
return manifest === null ? base : {
|
|
59
|
+
...base,
|
|
60
|
+
...manifest
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
//#endregion
|
|
65
|
+
exports.createArtifactResolver = createArtifactResolver;
|
|
66
|
+
exports.createReleaseCatalogReader = createReleaseCatalogReader;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ArtifactInfo, ReleaseCatalog } from "@hot-updater/core";
|
|
2
|
+
import { DatabasePlugin } from "@hot-updater/plugin-core";
|
|
3
|
+
|
|
4
|
+
//#region src/db/releaseCatalog.d.ts
|
|
5
|
+
type ReleaseCatalogRequest = {
|
|
6
|
+
readonly strategy: "APP_VERSION";
|
|
7
|
+
readonly platform: "ios" | "android";
|
|
8
|
+
readonly channelKey: string;
|
|
9
|
+
readonly appVersion: string;
|
|
10
|
+
} | {
|
|
11
|
+
readonly strategy: "FINGERPRINT";
|
|
12
|
+
readonly platform: "ios" | "android";
|
|
13
|
+
readonly channelKey: string;
|
|
14
|
+
readonly fingerprintHash: string;
|
|
15
|
+
};
|
|
16
|
+
//#endregion
|
|
17
|
+
export { ReleaseCatalogRequest };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { DatabasePlugin } from "@hot-updater/plugin-core";
|
|
2
|
+
import { ArtifactInfo, ReleaseCatalog } from "@hot-updater/core";
|
|
3
|
+
|
|
4
|
+
//#region src/db/releaseCatalog.d.ts
|
|
5
|
+
type ReleaseCatalogRequest = {
|
|
6
|
+
readonly strategy: "APP_VERSION";
|
|
7
|
+
readonly platform: "ios" | "android";
|
|
8
|
+
readonly channelKey: string;
|
|
9
|
+
readonly appVersion: string;
|
|
10
|
+
} | {
|
|
11
|
+
readonly strategy: "FINGERPRINT";
|
|
12
|
+
readonly platform: "ios" | "android";
|
|
13
|
+
readonly channelKey: string;
|
|
14
|
+
readonly fingerprintHash: string;
|
|
15
|
+
};
|
|
16
|
+
//#endregion
|
|
17
|
+
export { ReleaseCatalogRequest };
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { resolveManifestArtifacts } from "./updateArtifacts.mjs";
|
|
2
|
+
import { createDatabaseClient, projectCompiledCatalog, projectCompiledRollbackCatalog } from "@hot-updater/plugin-core";
|
|
3
|
+
import { NIL_UUID, RELEASE_CATALOG_FALLBACK_POLICY, RELEASE_CATALOG_SCHEMA_VERSION, createReleaseCatalogScopeKey } from "@hot-updater/core";
|
|
4
|
+
//#region src/db/releaseCatalog.ts
|
|
5
|
+
const parseCompiledCatalog = (payload, strategy) => {
|
|
6
|
+
const parsed = JSON.parse(payload);
|
|
7
|
+
if (typeof parsed !== "object" || parsed === null || Reflect.get(parsed, "schemaVersion") !== RELEASE_CATALOG_SCHEMA_VERSION || Reflect.get(parsed, "strategy") !== strategy || Reflect.get(parsed, "fallbackPolicy") !== RELEASE_CATALOG_FALLBACK_POLICY || !Array.isArray(Reflect.get(parsed, "releaseDescriptors"))) throw new Error("Stored Release catalog payload is invalid");
|
|
8
|
+
if (strategy === "APP_VERSION" && !Array.isArray(Reflect.get(parsed, "segments"))) throw new Error("Stored app-version Release catalog is invalid");
|
|
9
|
+
if (strategy === "FINGERPRINT" && !Array.isArray(Reflect.get(parsed, "releaseIndexes"))) throw new Error("Stored fingerprint Release catalog is invalid");
|
|
10
|
+
return parsed;
|
|
11
|
+
};
|
|
12
|
+
const createReleaseCatalogReader = (database) => async (input) => {
|
|
13
|
+
const scopeKey = input.strategy === "APP_VERSION" ? createReleaseCatalogScopeKey({
|
|
14
|
+
channelKey: input.channelKey,
|
|
15
|
+
platform: input.platform,
|
|
16
|
+
strategy: "APP_VERSION"
|
|
17
|
+
}) : createReleaseCatalogScopeKey({
|
|
18
|
+
channelKey: input.channelKey,
|
|
19
|
+
fingerprintHash: input.fingerprintHash,
|
|
20
|
+
platform: input.platform,
|
|
21
|
+
strategy: "FINGERPRINT"
|
|
22
|
+
});
|
|
23
|
+
const row = await database.models.releaseCatalogs.findByScopeKey(scopeKey);
|
|
24
|
+
if (row === null || row.platform !== input.platform || row.strategy !== input.strategy || row.channel_key !== input.channelKey || row.scope_key !== scopeKey || row.fingerprint_hash !== (input.strategy === "FINGERPRINT" ? input.fingerprintHash : null)) return null;
|
|
25
|
+
const compiled = parseCompiledCatalog(row.payload, input.strategy);
|
|
26
|
+
const releases = projectCompiledCatalog(compiled, input.strategy === "APP_VERSION" ? input.appVersion : void 0);
|
|
27
|
+
const rollbackReleases = projectCompiledRollbackCatalog(compiled, input.strategy === "APP_VERSION" ? input.appVersion : void 0);
|
|
28
|
+
return {
|
|
29
|
+
catalogId: row.catalog_id,
|
|
30
|
+
catalogHash: row.catalog_hash,
|
|
31
|
+
fallbackPolicy: RELEASE_CATALOG_FALLBACK_POLICY,
|
|
32
|
+
generation: row.generation,
|
|
33
|
+
releases,
|
|
34
|
+
rollbackReleases,
|
|
35
|
+
schemaVersion: RELEASE_CATALOG_SCHEMA_VERSION,
|
|
36
|
+
scopeKey
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
const createArtifactResolver = (input) => {
|
|
40
|
+
const databaseClient = createDatabaseClient(input.database);
|
|
41
|
+
return async (targetBundleId, currentBundleId) => {
|
|
42
|
+
const [targetBundle, currentBundle] = await Promise.all([databaseClient.getBundleById(targetBundleId), currentBundleId === NIL_UUID ? null : databaseClient.getBundleById(currentBundleId)]);
|
|
43
|
+
if (targetBundle === null) return null;
|
|
44
|
+
const fileUrl = await input.resolveFileUrl(targetBundle.storageUri);
|
|
45
|
+
const base = {
|
|
46
|
+
fileHash: targetBundle.fileHash,
|
|
47
|
+
fileUrl
|
|
48
|
+
};
|
|
49
|
+
if (input.readStorageText === void 0) return base;
|
|
50
|
+
const manifest = await resolveManifestArtifacts({
|
|
51
|
+
archiveUrlUsable: fileUrl !== null,
|
|
52
|
+
currentBundle,
|
|
53
|
+
readStorageText: input.readStorageText,
|
|
54
|
+
resolveFileUrl: input.resolveFileUrl,
|
|
55
|
+
targetBundle
|
|
56
|
+
});
|
|
57
|
+
return manifest === null ? base : {
|
|
58
|
+
...base,
|
|
59
|
+
...manifest
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
//#endregion
|
|
64
|
+
export { createArtifactResolver, createReleaseCatalogReader };
|
|
@@ -3,14 +3,22 @@ const require_sql = require("./sql.cjs");
|
|
|
3
3
|
//#region src/db/schema/mongodb.ts
|
|
4
4
|
const createMongoMigrationOperations = (settingsOperation) => [
|
|
5
5
|
...require_sql.hotUpdaterCreateTableOperations,
|
|
6
|
-
{
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
...require_registry.hotUpdaterSchema.tables.filter((table) => !table.internal).map((table) => {
|
|
7
|
+
const primaryKey = table.columns.find((column) => column.primaryKey);
|
|
8
|
+
if (!primaryKey) throw new Error(`MongoDB table ${table.ormName} does not define a primary key.`);
|
|
9
|
+
return {
|
|
10
|
+
description: `Create unique MongoDB index: ${table.ormName}_${primaryKey.ormName}_idx on ${table.ormName}(${primaryKey.ormName})`,
|
|
11
|
+
type: "custom"
|
|
12
|
+
};
|
|
13
|
+
}),
|
|
10
14
|
...require_registry.hotUpdaterSchema.tables.flatMap((table) => (table.indexes ?? []).filter((index) => require_registry.schemaIndexAppliesToProvider(index, "mongodb")).map((index) => ({
|
|
11
|
-
|
|
12
|
-
|
|
15
|
+
description: `Create ${index.unique ? "unique " : ""}MongoDB index: ${index.name} on ${table.ormName}(${index.columns.join(", ")})`,
|
|
16
|
+
type: "custom"
|
|
13
17
|
}))),
|
|
18
|
+
{
|
|
19
|
+
description: "Enforce final MongoDB Bundle, Release, and catalog schemas",
|
|
20
|
+
type: "custom"
|
|
21
|
+
},
|
|
14
22
|
...settingsOperation ? [settingsOperation] : []
|
|
15
23
|
];
|
|
16
24
|
//#endregion
|
|
@@ -3,14 +3,22 @@ import { hotUpdaterCreateTableOperations } from "./sql.mjs";
|
|
|
3
3
|
//#region src/db/schema/mongodb.ts
|
|
4
4
|
const createMongoMigrationOperations = (settingsOperation) => [
|
|
5
5
|
...hotUpdaterCreateTableOperations,
|
|
6
|
-
{
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
...hotUpdaterSchema.tables.filter((table) => !table.internal).map((table) => {
|
|
7
|
+
const primaryKey = table.columns.find((column) => column.primaryKey);
|
|
8
|
+
if (!primaryKey) throw new Error(`MongoDB table ${table.ormName} does not define a primary key.`);
|
|
9
|
+
return {
|
|
10
|
+
description: `Create unique MongoDB index: ${table.ormName}_${primaryKey.ormName}_idx on ${table.ormName}(${primaryKey.ormName})`,
|
|
11
|
+
type: "custom"
|
|
12
|
+
};
|
|
13
|
+
}),
|
|
10
14
|
...hotUpdaterSchema.tables.flatMap((table) => (table.indexes ?? []).filter((index) => schemaIndexAppliesToProvider(index, "mongodb")).map((index) => ({
|
|
11
|
-
|
|
12
|
-
|
|
15
|
+
description: `Create ${index.unique ? "unique " : ""}MongoDB index: ${index.name} on ${table.ormName}(${index.columns.join(", ")})`,
|
|
16
|
+
type: "custom"
|
|
13
17
|
}))),
|
|
18
|
+
{
|
|
19
|
+
description: "Enforce final MongoDB Bundle, Release, and catalog schemas",
|
|
20
|
+
type: "custom"
|
|
21
|
+
},
|
|
14
22
|
...settingsOperation ? [settingsOperation] : []
|
|
15
23
|
];
|
|
16
24
|
//#endregion
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
const require_index = require("../../schema/index.cjs");
|
|
2
2
|
//#region src/db/schema/registry.ts
|
|
3
3
|
const hotUpdaterSchema = require_index.hotUpdaterSchemaVersions[require_index.hotUpdaterSchemaVersions.length - 1];
|
|
4
|
-
const getSchemaVersionIndex = (version) => require_index.hotUpdaterSchemaVersions.findIndex((schema) => schema.version === version);
|
|
5
4
|
const getHotUpdaterSchemaVersion = (version) => {
|
|
6
5
|
const schema = require_index.hotUpdaterSchemaVersions.find((item) => item.version === version);
|
|
7
6
|
if (!schema) throw new Error(`Unsupported Hot Updater schema version: ${version}`);
|
|
@@ -17,7 +16,6 @@ const schemaIndexAppliesToProvider = (index, provider) => !index.providers || in
|
|
|
17
16
|
//#endregion
|
|
18
17
|
exports.getHotUpdaterSchemaVersion = getHotUpdaterSchemaVersion;
|
|
19
18
|
exports.getSchemaColumn = getSchemaColumn;
|
|
20
|
-
exports.getSchemaVersionIndex = getSchemaVersionIndex;
|
|
21
19
|
exports.hotUpdaterDataTables = hotUpdaterDataTables;
|
|
22
20
|
exports.hotUpdaterSchema = hotUpdaterSchema;
|
|
23
21
|
exports.schemaIndexAppliesToProvider = schemaIndexAppliesToProvider;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { hotUpdaterSchemaVersions } from "../../schema/index.mjs";
|
|
2
2
|
//#region src/db/schema/registry.ts
|
|
3
3
|
const hotUpdaterSchema = hotUpdaterSchemaVersions[hotUpdaterSchemaVersions.length - 1];
|
|
4
|
-
const getSchemaVersionIndex = (version) => hotUpdaterSchemaVersions.findIndex((schema) => schema.version === version);
|
|
5
4
|
const getHotUpdaterSchemaVersion = (version) => {
|
|
6
5
|
const schema = hotUpdaterSchemaVersions.find((item) => item.version === version);
|
|
7
6
|
if (!schema) throw new Error(`Unsupported Hot Updater schema version: ${version}`);
|
|
@@ -15,4 +14,4 @@ const getSchemaColumn = (table, name) => {
|
|
|
15
14
|
const hotUpdaterDataTables = hotUpdaterSchema.tables.filter((table) => !table.internal);
|
|
16
15
|
const schemaIndexAppliesToProvider = (index, provider) => !index.providers || index.providers.includes(provider);
|
|
17
16
|
//#endregion
|
|
18
|
-
export { getHotUpdaterSchemaVersion, getSchemaColumn,
|
|
17
|
+
export { getHotUpdaterSchemaVersion, getSchemaColumn, hotUpdaterDataTables, hotUpdaterSchema, schemaIndexAppliesToProvider };
|