@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
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { HandlerBadRequestError } from "./handlerErrors.mjs";
|
|
2
|
+
import { decodeMaybe, requireRouteParam } from "./handlerParameters.mjs";
|
|
3
|
+
import { ReleaseCatalogMutationError, ReleaseManagementError } from "@hot-updater/plugin-core";
|
|
4
|
+
//#region src/handlerReleaseManagementRoutes.ts
|
|
5
|
+
const unavailable = () => Response.json({ error: "Not found" }, { status: 404 });
|
|
6
|
+
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7
|
+
const parseRevision = (value) => {
|
|
8
|
+
if (value === void 0 || value === null || value === "") return void 0;
|
|
9
|
+
const revision = typeof value === "number" ? value : Number(value);
|
|
10
|
+
if (!Number.isSafeInteger(revision) || revision < 1) throw new HandlerBadRequestError("Invalid expected Release revision");
|
|
11
|
+
return revision;
|
|
12
|
+
};
|
|
13
|
+
const parsePolicyInput = async (request) => {
|
|
14
|
+
const body = await request.json();
|
|
15
|
+
if (!isRecord(body) || !isRecord(body.patch)) throw new HandlerBadRequestError("Invalid Release policy mutation");
|
|
16
|
+
return {
|
|
17
|
+
expectedRevision: parseRevision(body.expectedRevision),
|
|
18
|
+
patch: body.patch
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
const mutationResponse = async (operation) => {
|
|
22
|
+
try {
|
|
23
|
+
return Response.json({ data: await operation() });
|
|
24
|
+
} catch (error) {
|
|
25
|
+
if (error instanceof ReleaseManagementError || error instanceof ReleaseCatalogMutationError) {
|
|
26
|
+
const status = error.code === "RELEASE_NOT_FOUND" ? 404 : error.code === "VERSION_CONFLICT" ? 409 : 400;
|
|
27
|
+
return Response.json({
|
|
28
|
+
code: error.code,
|
|
29
|
+
error: error.message
|
|
30
|
+
}, { status });
|
|
31
|
+
}
|
|
32
|
+
throw error;
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
const createReleaseManagementRouteHandlers = () => ({
|
|
36
|
+
getRelease: async (params, _request, api) => {
|
|
37
|
+
if (api.getReleaseById === void 0) return unavailable();
|
|
38
|
+
const row = await api.getReleaseById(requireRouteParam(params, "id"));
|
|
39
|
+
return row === null ? unavailable() : Response.json({ data: row }, { status: 200 });
|
|
40
|
+
},
|
|
41
|
+
getReleases: async (_params, request, api) => {
|
|
42
|
+
const url = new URL(request.url);
|
|
43
|
+
const scopeKey = url.searchParams.get("scopeKey");
|
|
44
|
+
const limit = Number(url.searchParams.get("limit") ?? "100");
|
|
45
|
+
if (!Number.isSafeInteger(limit) || limit <= 0 || limit > 1e3) throw new HandlerBadRequestError("Invalid Release scope query");
|
|
46
|
+
if (scopeKey !== null) {
|
|
47
|
+
if (scopeKey.length === 0 || api.getReleasesByScope === void 0) throw new HandlerBadRequestError("Invalid Release scope query");
|
|
48
|
+
const afterReleaseId = url.searchParams.get("afterReleaseId") ?? void 0;
|
|
49
|
+
return Response.json({ data: await api.getReleasesByScope({
|
|
50
|
+
...afterReleaseId === void 0 ? {} : { afterReleaseId },
|
|
51
|
+
limit,
|
|
52
|
+
scopeKey
|
|
53
|
+
}) });
|
|
54
|
+
}
|
|
55
|
+
if (api.getReleases === void 0) return unavailable();
|
|
56
|
+
const enabledValue = url.searchParams.get("enabled");
|
|
57
|
+
const enabled = enabledValue === null ? void 0 : enabledValue === "true" ? true : enabledValue === "false" ? false : null;
|
|
58
|
+
const platformValue = url.searchParams.get("platform");
|
|
59
|
+
const platform = platformValue === null ? void 0 : platformValue === "ios" || platformValue === "android" ? platformValue : null;
|
|
60
|
+
if (enabled === null || platform === null) throw new HandlerBadRequestError("Invalid Release list filter");
|
|
61
|
+
return Response.json({ data: await api.getReleases({
|
|
62
|
+
afterReleaseId: url.searchParams.get("afterReleaseId") ?? void 0,
|
|
63
|
+
beforeReleaseId: url.searchParams.get("beforeReleaseId") ?? void 0,
|
|
64
|
+
bundleId: url.searchParams.get("bundleId") ?? void 0,
|
|
65
|
+
channelId: url.searchParams.get("channelId") ?? void 0,
|
|
66
|
+
enabled,
|
|
67
|
+
limit,
|
|
68
|
+
platform,
|
|
69
|
+
targetAppVersion: url.searchParams.get("targetAppVersion") ?? void 0
|
|
70
|
+
}) });
|
|
71
|
+
},
|
|
72
|
+
getReleaseCatalogRow: async (params, _request, api) => {
|
|
73
|
+
if (api.getReleaseCatalogByScopeKey === void 0) return unavailable();
|
|
74
|
+
const row = await api.getReleaseCatalogByScopeKey(decodeMaybe(requireRouteParam(params, "scopeKey")) ?? "");
|
|
75
|
+
return row === null ? unavailable() : Response.json({ data: row }, { status: 200 });
|
|
76
|
+
},
|
|
77
|
+
getReleaseCatalogs: async (_params, request, api) => {
|
|
78
|
+
if (api.getReleaseCatalogs === void 0) return unavailable();
|
|
79
|
+
const url = new URL(request.url);
|
|
80
|
+
const limit = Number(url.searchParams.get("limit") ?? "100");
|
|
81
|
+
if (!Number.isSafeInteger(limit) || limit <= 0 || limit > 1e3) throw new HandlerBadRequestError("Invalid Release catalog list query");
|
|
82
|
+
return Response.json({ data: await api.getReleaseCatalogs({
|
|
83
|
+
afterScopeKey: url.searchParams.get("afterScopeKey") ?? void 0,
|
|
84
|
+
limit
|
|
85
|
+
}) });
|
|
86
|
+
},
|
|
87
|
+
updateRelease: async (params, request, api) => {
|
|
88
|
+
if (api.updateReleasePolicy === void 0) return unavailable();
|
|
89
|
+
const input = await parsePolicyInput(request);
|
|
90
|
+
return mutationResponse(() => api.updateReleasePolicy({
|
|
91
|
+
...input,
|
|
92
|
+
releaseId: requireRouteParam(params, "id")
|
|
93
|
+
}));
|
|
94
|
+
},
|
|
95
|
+
preflightRelease: async (params, request, api) => {
|
|
96
|
+
if (api.preflightReleasePolicy === void 0) return unavailable();
|
|
97
|
+
const input = await parsePolicyInput(request);
|
|
98
|
+
return mutationResponse(() => api.preflightReleasePolicy({
|
|
99
|
+
...input,
|
|
100
|
+
releaseId: requireRouteParam(params, "id")
|
|
101
|
+
}));
|
|
102
|
+
},
|
|
103
|
+
deleteRelease: async (params, request, api) => {
|
|
104
|
+
if (api.deleteRelease === void 0) return unavailable();
|
|
105
|
+
const releaseId = requireRouteParam(params, "id");
|
|
106
|
+
const url = new URL(request.url);
|
|
107
|
+
if (url.searchParams.get("confirm") !== releaseId) throw new HandlerBadRequestError("Release hard deletion requires confirm=<release-id>");
|
|
108
|
+
return mutationResponse(() => api.deleteRelease({
|
|
109
|
+
expectedRevision: parseRevision(url.searchParams.get("expectedRevision")),
|
|
110
|
+
releaseId
|
|
111
|
+
}));
|
|
112
|
+
},
|
|
113
|
+
rebuildReleaseCatalog: async (params, _request, api) => {
|
|
114
|
+
if (api.rebuildReleaseCatalog === void 0) return unavailable();
|
|
115
|
+
return mutationResponse(() => api.rebuildReleaseCatalog(decodeMaybe(requireRouteParam(params, "scopeKey")) ?? ""));
|
|
116
|
+
},
|
|
117
|
+
commitDatabase: async (_params, request, api) => {
|
|
118
|
+
if (api.commitDatabase === void 0) return unavailable();
|
|
119
|
+
const input = await request.json();
|
|
120
|
+
return Response.json({ data: await api.commitDatabase(input) });
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
//#endregion
|
|
124
|
+
export { createReleaseManagementRouteHandlers };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { ReleaseCatalogRequest } from "./db/releaseCatalog.cjs";
|
|
2
|
+
import { PaginatedResult } from "./types/index.cjs";
|
|
3
|
+
import { ArtifactInfo, Bundle, ReleaseCatalog } from "@hot-updater/core";
|
|
4
|
+
import { ChannelDeleteInput, ChannelDeleteResult, ChannelInsertInput, ChannelInsertResult, ChannelRow, DatabaseBundleQueryOptions, DatabaseCommit, DatabaseCommitResult, ReleaseCatalogMutationPreflight, ReleaseCatalogMutationResult, ReleaseCatalogRebuildResult, ReleaseCatalogRow, ReleasePolicyPatch, ReleaseRow } from "@hot-updater/plugin-core";
|
|
5
|
+
|
|
6
|
+
//#region src/handlerTypes.d.ts
|
|
7
|
+
interface HandlerAPI {
|
|
8
|
+
getReleaseCatalog?: (input: ReleaseCatalogRequest) => Promise<ReleaseCatalog | null>;
|
|
9
|
+
getArtifactInfo?: (targetBundleId: string, currentBundleId: string) => Promise<ArtifactInfo | null>;
|
|
10
|
+
getReleaseById?: (id: string) => Promise<ReleaseRow | null>;
|
|
11
|
+
getReleasesByScope?: (input: {
|
|
12
|
+
readonly scopeKey: string;
|
|
13
|
+
readonly afterReleaseId?: string;
|
|
14
|
+
readonly limit: number;
|
|
15
|
+
}) => Promise<readonly ReleaseRow[]>;
|
|
16
|
+
getReleases?: (input: {
|
|
17
|
+
readonly afterReleaseId?: string;
|
|
18
|
+
readonly beforeReleaseId?: string;
|
|
19
|
+
readonly bundleId?: string;
|
|
20
|
+
readonly channelId?: string;
|
|
21
|
+
readonly enabled?: boolean;
|
|
22
|
+
readonly platform?: "ios" | "android";
|
|
23
|
+
readonly targetAppVersion?: string;
|
|
24
|
+
readonly limit: number;
|
|
25
|
+
}) => Promise<readonly ReleaseRow[]>;
|
|
26
|
+
getReleaseCatalogByScopeKey?: (scopeKey: string) => Promise<ReleaseCatalogRow | null>;
|
|
27
|
+
getReleaseCatalogs?: (input: {
|
|
28
|
+
readonly afterScopeKey?: string;
|
|
29
|
+
readonly limit: number;
|
|
30
|
+
}) => Promise<readonly ReleaseCatalogRow[]>;
|
|
31
|
+
updateReleasePolicy?: (input: {
|
|
32
|
+
readonly expectedRevision?: number;
|
|
33
|
+
readonly patch: ReleasePolicyPatch;
|
|
34
|
+
readonly releaseId: string;
|
|
35
|
+
}) => Promise<ReleaseCatalogMutationResult>;
|
|
36
|
+
preflightReleasePolicy?: (input: {
|
|
37
|
+
readonly expectedRevision?: number;
|
|
38
|
+
readonly patch: ReleasePolicyPatch;
|
|
39
|
+
readonly releaseId: string;
|
|
40
|
+
}) => Promise<ReleaseCatalogMutationPreflight>;
|
|
41
|
+
deleteRelease?: (input: {
|
|
42
|
+
readonly expectedRevision?: number;
|
|
43
|
+
readonly releaseId: string;
|
|
44
|
+
}) => Promise<ReleaseCatalogMutationResult>;
|
|
45
|
+
rebuildReleaseCatalog?: (scopeKey: string) => Promise<ReleaseCatalogRebuildResult>;
|
|
46
|
+
commitDatabase?: (input: DatabaseCommit) => Promise<DatabaseCommitResult>;
|
|
47
|
+
getBundleById: (id: string) => Promise<Bundle | null>;
|
|
48
|
+
getBundles: (options: DatabaseBundleQueryOptions) => Promise<PaginatedResult>;
|
|
49
|
+
insertBundle: (bundle: Bundle) => Promise<void>;
|
|
50
|
+
insertBundles?: (bundles: readonly Bundle[]) => Promise<void>;
|
|
51
|
+
updateBundleById: (bundleId: string, bundle: Partial<Bundle>) => Promise<void>;
|
|
52
|
+
deleteBundleById: (bundleId: string) => Promise<void>;
|
|
53
|
+
getChannels: () => Promise<readonly ChannelRow[]>;
|
|
54
|
+
insertChannel: (input: ChannelInsertInput) => Promise<ChannelInsertResult>;
|
|
55
|
+
deleteChannel: (input: ChannelDeleteInput) => Promise<ChannelDeleteResult>;
|
|
56
|
+
}
|
|
57
|
+
type HotUpdaterHandler = (request: Request) => Promise<Response>;
|
|
58
|
+
interface HotUpdaterHandlers {
|
|
59
|
+
readonly client: HotUpdaterHandler;
|
|
60
|
+
readonly admin: HotUpdaterHandler;
|
|
61
|
+
}
|
|
62
|
+
//#endregion
|
|
63
|
+
export { HandlerAPI, HotUpdaterHandler, HotUpdaterHandlers };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { ReleaseCatalogRequest } from "./db/releaseCatalog.mjs";
|
|
2
|
+
import { PaginatedResult } from "./types/index.mjs";
|
|
3
|
+
import { ChannelDeleteInput, ChannelDeleteResult, ChannelInsertInput, ChannelInsertResult, ChannelRow, DatabaseBundleQueryOptions, DatabaseCommit, DatabaseCommitResult, ReleaseCatalogMutationPreflight, ReleaseCatalogMutationResult, ReleaseCatalogRebuildResult, ReleaseCatalogRow, ReleasePolicyPatch, ReleaseRow } from "@hot-updater/plugin-core";
|
|
4
|
+
import { ArtifactInfo, Bundle as Bundle$1, ReleaseCatalog } from "@hot-updater/core";
|
|
5
|
+
|
|
6
|
+
//#region src/handlerTypes.d.ts
|
|
7
|
+
interface HandlerAPI {
|
|
8
|
+
getReleaseCatalog?: (input: ReleaseCatalogRequest) => Promise<ReleaseCatalog | null>;
|
|
9
|
+
getArtifactInfo?: (targetBundleId: string, currentBundleId: string) => Promise<ArtifactInfo | null>;
|
|
10
|
+
getReleaseById?: (id: string) => Promise<ReleaseRow | null>;
|
|
11
|
+
getReleasesByScope?: (input: {
|
|
12
|
+
readonly scopeKey: string;
|
|
13
|
+
readonly afterReleaseId?: string;
|
|
14
|
+
readonly limit: number;
|
|
15
|
+
}) => Promise<readonly ReleaseRow[]>;
|
|
16
|
+
getReleases?: (input: {
|
|
17
|
+
readonly afterReleaseId?: string;
|
|
18
|
+
readonly beforeReleaseId?: string;
|
|
19
|
+
readonly bundleId?: string;
|
|
20
|
+
readonly channelId?: string;
|
|
21
|
+
readonly enabled?: boolean;
|
|
22
|
+
readonly platform?: "ios" | "android";
|
|
23
|
+
readonly targetAppVersion?: string;
|
|
24
|
+
readonly limit: number;
|
|
25
|
+
}) => Promise<readonly ReleaseRow[]>;
|
|
26
|
+
getReleaseCatalogByScopeKey?: (scopeKey: string) => Promise<ReleaseCatalogRow | null>;
|
|
27
|
+
getReleaseCatalogs?: (input: {
|
|
28
|
+
readonly afterScopeKey?: string;
|
|
29
|
+
readonly limit: number;
|
|
30
|
+
}) => Promise<readonly ReleaseCatalogRow[]>;
|
|
31
|
+
updateReleasePolicy?: (input: {
|
|
32
|
+
readonly expectedRevision?: number;
|
|
33
|
+
readonly patch: ReleasePolicyPatch;
|
|
34
|
+
readonly releaseId: string;
|
|
35
|
+
}) => Promise<ReleaseCatalogMutationResult>;
|
|
36
|
+
preflightReleasePolicy?: (input: {
|
|
37
|
+
readonly expectedRevision?: number;
|
|
38
|
+
readonly patch: ReleasePolicyPatch;
|
|
39
|
+
readonly releaseId: string;
|
|
40
|
+
}) => Promise<ReleaseCatalogMutationPreflight>;
|
|
41
|
+
deleteRelease?: (input: {
|
|
42
|
+
readonly expectedRevision?: number;
|
|
43
|
+
readonly releaseId: string;
|
|
44
|
+
}) => Promise<ReleaseCatalogMutationResult>;
|
|
45
|
+
rebuildReleaseCatalog?: (scopeKey: string) => Promise<ReleaseCatalogRebuildResult>;
|
|
46
|
+
commitDatabase?: (input: DatabaseCommit) => Promise<DatabaseCommitResult>;
|
|
47
|
+
getBundleById: (id: string) => Promise<Bundle$1 | null>;
|
|
48
|
+
getBundles: (options: DatabaseBundleQueryOptions) => Promise<PaginatedResult>;
|
|
49
|
+
insertBundle: (bundle: Bundle$1) => Promise<void>;
|
|
50
|
+
insertBundles?: (bundles: readonly Bundle$1[]) => Promise<void>;
|
|
51
|
+
updateBundleById: (bundleId: string, bundle: Partial<Bundle$1>) => Promise<void>;
|
|
52
|
+
deleteBundleById: (bundleId: string) => Promise<void>;
|
|
53
|
+
getChannels: () => Promise<readonly ChannelRow[]>;
|
|
54
|
+
insertChannel: (input: ChannelInsertInput) => Promise<ChannelInsertResult>;
|
|
55
|
+
deleteChannel: (input: ChannelDeleteInput) => Promise<ChannelDeleteResult>;
|
|
56
|
+
}
|
|
57
|
+
type HotUpdaterHandler = (request: Request) => Promise<Response>;
|
|
58
|
+
interface HotUpdaterHandlers {
|
|
59
|
+
readonly client: HotUpdaterHandler;
|
|
60
|
+
readonly admin: HotUpdaterHandler;
|
|
61
|
+
}
|
|
62
|
+
//#endregion
|
|
63
|
+
export { HandlerAPI, HotUpdaterHandler, HotUpdaterHandlers };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const require_version = require("./version.cjs");
|
|
2
|
+
//#region src/handlerVersionRoutes.ts
|
|
3
|
+
const HOT_UPDATER_INFRASTRUCTURE_GENERATION = 1;
|
|
4
|
+
const createVersionRouteHandlers = () => ({ version: async () => Response.json({
|
|
5
|
+
infrastructureGeneration: 1,
|
|
6
|
+
version: require_version.HOT_UPDATER_SERVER_VERSION
|
|
7
|
+
}) });
|
|
8
|
+
//#endregion
|
|
9
|
+
exports.HOT_UPDATER_INFRASTRUCTURE_GENERATION = HOT_UPDATER_INFRASTRUCTURE_GENERATION;
|
|
10
|
+
exports.createVersionRouteHandlers = createVersionRouteHandlers;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { HOT_UPDATER_SERVER_VERSION } from "./version.mjs";
|
|
2
|
+
//#region src/handlerVersionRoutes.ts
|
|
3
|
+
const HOT_UPDATER_INFRASTRUCTURE_GENERATION = 1;
|
|
4
|
+
const createVersionRouteHandlers = () => ({ version: async () => Response.json({
|
|
5
|
+
infrastructureGeneration: 1,
|
|
6
|
+
version: HOT_UPDATER_SERVER_VERSION
|
|
7
|
+
}) });
|
|
8
|
+
//#endregion
|
|
9
|
+
export { HOT_UPDATER_INFRASTRUCTURE_GENERATION, createVersionRouteHandlers };
|
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_version = require("./version.cjs");
|
|
3
|
+
const require_handlerVersionRoutes = require("./handlerVersionRoutes.cjs");
|
|
3
4
|
const require_handler = require("./handler.cjs");
|
|
5
|
+
const require_provider = require("./insights/bounded/provider.cjs");
|
|
6
|
+
const require_apiKeys = require("./apiKeys.cjs");
|
|
4
7
|
const require_createHotUpdaterCore = require("./createHotUpdaterCore.cjs");
|
|
8
|
+
exports.API_KEY_HEADER_NAME = require_apiKeys.API_KEY_HEADER_NAME;
|
|
9
|
+
exports.HOT_UPDATER_INFRASTRUCTURE_GENERATION = require_handlerVersionRoutes.HOT_UPDATER_INFRASTRUCTURE_GENERATION;
|
|
5
10
|
exports.HOT_UPDATER_SERVER_VERSION = require_version.HOT_UPDATER_SERVER_VERSION;
|
|
6
|
-
exports.
|
|
11
|
+
exports.createApiKey = require_apiKeys.createApiKey;
|
|
12
|
+
exports.createHandlers = require_handler.createHandlers;
|
|
7
13
|
exports.createHotUpdater = require_createHotUpdaterCore.createHotUpdater;
|
|
14
|
+
exports.createInsightsProvider = require_provider.createInsightsProvider;
|
|
15
|
+
exports.provisionApiKey = require_apiKeys.provisionApiKey;
|
|
16
|
+
exports.registerApiKey = require_apiKeys.registerApiKey;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { API_KEY_HEADER_NAME, ApiKeyManagementAPI, ApiKeyMetadata, CreatedApiKey, createApiKey, provisionApiKey, registerApiKey } from "./apiKeys.cjs";
|
|
2
|
+
import { HandlerAPI, HotUpdaterHandler, HotUpdaterHandlers } from "./handlerTypes.cjs";
|
|
3
|
+
import { ActiveInstallationInput, ActiveInstallationOverview, ActiveInstallationWindow, BundleEventInsightsResult, BundleEventInsightsWindow, BundleEventOverview, BundleEventSummary, BundleEventSummaryByBundle, CreateBundleEventRequest, CreateBundleEventRequestBase, InsightsCohortPoint, InsightsSeriesPoint, InstallationHistoryRow, InstallationSearchRow, OffsetPaginationResult } from "./insights/domain.cjs";
|
|
4
|
+
import { InsightsProvider } from "./insights/types.cjs";
|
|
5
|
+
import { createHandlers } from "./handler.cjs";
|
|
6
|
+
import { ClientAccessPolicy, CreateHotUpdaterOptions, HotUpdaterAPI, RuntimeHotUpdaterAPI, createHotUpdater } from "./createHotUpdaterCore.cjs";
|
|
3
7
|
import { Bundle, ChannelsResponse, DataResponse, Paginated, PaginatedResult, PaginationInfo, PaginationOptions } from "./types/index.cjs";
|
|
4
8
|
import { HOT_UPDATER_SERVER_VERSION } from "./version.cjs";
|
|
5
|
-
|
|
9
|
+
import { createInsightsProvider } from "./insights/bounded/provider.cjs";
|
|
10
|
+
import { HOT_UPDATER_INFRASTRUCTURE_GENERATION } from "./handlerVersionRoutes.cjs";
|
|
11
|
+
export { API_KEY_HEADER_NAME, ActiveInstallationInput, ActiveInstallationOverview, ActiveInstallationWindow, type ApiKeyManagementAPI, type ApiKeyMetadata, Bundle, BundleEventInsightsResult, BundleEventInsightsWindow, BundleEventOverview, BundleEventSummary, BundleEventSummaryByBundle, ChannelsResponse, type ClientAccessPolicy, CreateBundleEventRequest, CreateBundleEventRequestBase, type CreateHotUpdaterOptions, type CreatedApiKey, DataResponse, HOT_UPDATER_INFRASTRUCTURE_GENERATION, HOT_UPDATER_SERVER_VERSION, type HandlerAPI, type HotUpdaterAPI, type HotUpdaterHandler, type HotUpdaterHandlers, InsightsCohortPoint, type InsightsProvider, InsightsSeriesPoint, InstallationHistoryRow, InstallationSearchRow, OffsetPaginationResult, Paginated, PaginatedResult, PaginationInfo, PaginationOptions, type RuntimeHotUpdaterAPI, createApiKey, createHandlers, createHotUpdater, createInsightsProvider, provisionApiKey, registerApiKey };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { API_KEY_HEADER_NAME, ApiKeyManagementAPI, ApiKeyMetadata, CreatedApiKey, createApiKey, provisionApiKey, registerApiKey } from "./apiKeys.mjs";
|
|
2
|
+
import { HandlerAPI, HotUpdaterHandler, HotUpdaterHandlers } from "./handlerTypes.mjs";
|
|
3
|
+
import { ActiveInstallationInput, ActiveInstallationOverview, ActiveInstallationWindow, BundleEventInsightsResult, BundleEventInsightsWindow, BundleEventOverview, BundleEventSummary, BundleEventSummaryByBundle, CreateBundleEventRequest, CreateBundleEventRequestBase, InsightsCohortPoint, InsightsSeriesPoint, InstallationHistoryRow, InstallationSearchRow, OffsetPaginationResult } from "./insights/domain.mjs";
|
|
4
|
+
import { InsightsProvider } from "./insights/types.mjs";
|
|
5
|
+
import { createHandlers } from "./handler.mjs";
|
|
6
|
+
import { ClientAccessPolicy, CreateHotUpdaterOptions, HotUpdaterAPI, RuntimeHotUpdaterAPI, createHotUpdater } from "./createHotUpdaterCore.mjs";
|
|
3
7
|
import { Bundle, ChannelsResponse, DataResponse, Paginated, PaginatedResult, PaginationInfo, PaginationOptions } from "./types/index.mjs";
|
|
4
8
|
import { HOT_UPDATER_SERVER_VERSION } from "./version.mjs";
|
|
5
|
-
|
|
9
|
+
import { createInsightsProvider } from "./insights/bounded/provider.mjs";
|
|
10
|
+
import { HOT_UPDATER_INFRASTRUCTURE_GENERATION } from "./handlerVersionRoutes.mjs";
|
|
11
|
+
export { API_KEY_HEADER_NAME, ActiveInstallationInput, ActiveInstallationOverview, ActiveInstallationWindow, type ApiKeyManagementAPI, type ApiKeyMetadata, Bundle, BundleEventInsightsResult, BundleEventInsightsWindow, BundleEventOverview, BundleEventSummary, BundleEventSummaryByBundle, ChannelsResponse, type ClientAccessPolicy, CreateBundleEventRequest, CreateBundleEventRequestBase, type CreateHotUpdaterOptions, type CreatedApiKey, DataResponse, HOT_UPDATER_INFRASTRUCTURE_GENERATION, HOT_UPDATER_SERVER_VERSION, type HandlerAPI, type HotUpdaterAPI, type HotUpdaterHandler, type HotUpdaterHandlers, InsightsCohortPoint, type InsightsProvider, InsightsSeriesPoint, InstallationHistoryRow, InstallationSearchRow, OffsetPaginationResult, Paginated, PaginatedResult, PaginationInfo, PaginationOptions, type RuntimeHotUpdaterAPI, createApiKey, createHandlers, createHotUpdater, createInsightsProvider, provisionApiKey, registerApiKey };
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { HOT_UPDATER_SERVER_VERSION } from "./version.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { HOT_UPDATER_INFRASTRUCTURE_GENERATION } from "./handlerVersionRoutes.mjs";
|
|
3
|
+
import { createHandlers } from "./handler.mjs";
|
|
4
|
+
import { createInsightsProvider } from "./insights/bounded/provider.mjs";
|
|
5
|
+
import { API_KEY_HEADER_NAME, createApiKey, provisionApiKey, registerApiKey } from "./apiKeys.mjs";
|
|
3
6
|
import { createHotUpdater } from "./createHotUpdaterCore.mjs";
|
|
4
|
-
export { HOT_UPDATER_SERVER_VERSION,
|
|
7
|
+
export { API_KEY_HEADER_NAME, HOT_UPDATER_INFRASTRUCTURE_GENERATION, HOT_UPDATER_SERVER_VERSION, createApiKey, createHandlers, createHotUpdater, createInsightsProvider, provisionApiKey, registerApiKey };
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
//#region src/insights/bounded/activeOverview.ts
|
|
2
|
+
const HOUR_MS = 3600 * 1e3;
|
|
3
|
+
const DAY_MS = 24 * HOUR_MS;
|
|
4
|
+
const ACTIVE_BUNDLE_EVENT_TYPES = [
|
|
5
|
+
"UPDATE_APPLIED",
|
|
6
|
+
"RECOVERED",
|
|
7
|
+
"RELEASE_ADOPTED",
|
|
8
|
+
"UNCHANGED"
|
|
9
|
+
];
|
|
10
|
+
const activeWindowDefinitions = {
|
|
11
|
+
"24h": {
|
|
12
|
+
bucketCount: 24,
|
|
13
|
+
bucketSizeMs: HOUR_MS
|
|
14
|
+
},
|
|
15
|
+
"7d": {
|
|
16
|
+
bucketCount: 7,
|
|
17
|
+
bucketSizeMs: DAY_MS
|
|
18
|
+
},
|
|
19
|
+
"30d": {
|
|
20
|
+
bucketCount: 30,
|
|
21
|
+
bucketSizeMs: DAY_MS
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
function getActiveWindowDefinition(window) {
|
|
25
|
+
return activeWindowDefinitions[window];
|
|
26
|
+
}
|
|
27
|
+
function compareCodePoints(left, right) {
|
|
28
|
+
if (left < right) return -1;
|
|
29
|
+
if (left > right) return 1;
|
|
30
|
+
return 0;
|
|
31
|
+
}
|
|
32
|
+
function isNewer(candidate, current) {
|
|
33
|
+
return candidate.received_at_ms > current.received_at_ms || candidate.received_at_ms === current.received_at_ms && compareCodePoints(candidate.id, current.id) > 0;
|
|
34
|
+
}
|
|
35
|
+
function collectActiveInstallationOverview(request) {
|
|
36
|
+
const definition = getActiveWindowDefinition(request.window);
|
|
37
|
+
const windowStartMs = request.asOfMs - definition.bucketCount * definition.bucketSizeMs;
|
|
38
|
+
const rows = request.rows.filter((row) => row.received_at_ms >= windowStartMs && row.received_at_ms < request.asOfMs);
|
|
39
|
+
const latestByInstall = /* @__PURE__ */ new Map();
|
|
40
|
+
for (const row of rows) {
|
|
41
|
+
const current = latestByInstall.get(row.install_id);
|
|
42
|
+
if (current === void 0 || isNewer(row, current)) latestByInstall.set(row.install_id, row);
|
|
43
|
+
}
|
|
44
|
+
const selectedRows = [...latestByInstall.values()].filter((row) => request.userId === void 0 || row.user_id === request.userId);
|
|
45
|
+
const selectedInstallIds = new Set(selectedRows.map((row) => row.install_id));
|
|
46
|
+
const bundleCounts = /* @__PURE__ */ new Map();
|
|
47
|
+
for (const row of selectedRows) bundleCounts.set(row.to_bundle_id, (bundleCounts.get(row.to_bundle_id) ?? 0) + 1);
|
|
48
|
+
const latestByBucket = Array.from({ length: definition.bucketCount }, () => /* @__PURE__ */ new Map());
|
|
49
|
+
for (const row of rows) {
|
|
50
|
+
if (!selectedInstallIds.has(row.install_id)) continue;
|
|
51
|
+
const bucket = latestByBucket[Math.floor((row.received_at_ms - windowStartMs) / definition.bucketSizeMs)];
|
|
52
|
+
if (bucket === void 0) continue;
|
|
53
|
+
const current = bucket.get(row.install_id);
|
|
54
|
+
if (current === void 0 || isNewer(row, current)) bucket.set(row.install_id, row);
|
|
55
|
+
}
|
|
56
|
+
const bundleCountsByBucket = latestByBucket.map((bucket) => {
|
|
57
|
+
const counts = /* @__PURE__ */ new Map();
|
|
58
|
+
for (const row of bucket.values()) counts.set(row.to_bundle_id, (counts.get(row.to_bundle_id) ?? 0) + 1);
|
|
59
|
+
return counts;
|
|
60
|
+
});
|
|
61
|
+
const bundleObservationTotals = /* @__PURE__ */ new Map();
|
|
62
|
+
for (const counts of bundleCountsByBucket) for (const [bundleId, count] of counts) bundleObservationTotals.set(bundleId, (bundleObservationTotals.get(bundleId) ?? 0) + count);
|
|
63
|
+
return {
|
|
64
|
+
asOfMs: request.asOfMs,
|
|
65
|
+
window: request.window,
|
|
66
|
+
activeInstallations: selectedInstallIds.size,
|
|
67
|
+
series: latestByBucket.map((bucket, index) => ({
|
|
68
|
+
bucketStartMs: windowStartMs + index * definition.bucketSizeMs,
|
|
69
|
+
value: bucket.size
|
|
70
|
+
})),
|
|
71
|
+
bundleSeries: [...bundleObservationTotals].sort(([leftId, leftTotal], [rightId, rightTotal]) => rightTotal - leftTotal || compareCodePoints(leftId, rightId)).map(([bundleId]) => ({
|
|
72
|
+
bundleId,
|
|
73
|
+
series: bundleCountsByBucket.map((counts, index) => ({
|
|
74
|
+
bucketStartMs: windowStartMs + index * definition.bucketSizeMs,
|
|
75
|
+
value: counts.get(bundleId) ?? 0
|
|
76
|
+
}))
|
|
77
|
+
})),
|
|
78
|
+
bundles: [...bundleCounts].map(([bundleId, installations]) => ({
|
|
79
|
+
bundleId,
|
|
80
|
+
installations
|
|
81
|
+
})).sort((left, right) => right.installations - left.installations || compareCodePoints(left.bundleId, right.bundleId))
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
//#endregion
|
|
85
|
+
exports.ACTIVE_BUNDLE_EVENT_TYPES = ACTIVE_BUNDLE_EVENT_TYPES;
|
|
86
|
+
exports.collectActiveInstallationOverview = collectActiveInstallationOverview;
|
|
87
|
+
exports.getActiveWindowDefinition = getActiveWindowDefinition;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
//#region src/insights/bounded/activeOverview.ts
|
|
2
|
+
const HOUR_MS = 3600 * 1e3;
|
|
3
|
+
const DAY_MS = 24 * HOUR_MS;
|
|
4
|
+
const ACTIVE_BUNDLE_EVENT_TYPES = [
|
|
5
|
+
"UPDATE_APPLIED",
|
|
6
|
+
"RECOVERED",
|
|
7
|
+
"RELEASE_ADOPTED",
|
|
8
|
+
"UNCHANGED"
|
|
9
|
+
];
|
|
10
|
+
const activeWindowDefinitions = {
|
|
11
|
+
"24h": {
|
|
12
|
+
bucketCount: 24,
|
|
13
|
+
bucketSizeMs: HOUR_MS
|
|
14
|
+
},
|
|
15
|
+
"7d": {
|
|
16
|
+
bucketCount: 7,
|
|
17
|
+
bucketSizeMs: DAY_MS
|
|
18
|
+
},
|
|
19
|
+
"30d": {
|
|
20
|
+
bucketCount: 30,
|
|
21
|
+
bucketSizeMs: DAY_MS
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
function getActiveWindowDefinition(window) {
|
|
25
|
+
return activeWindowDefinitions[window];
|
|
26
|
+
}
|
|
27
|
+
function compareCodePoints(left, right) {
|
|
28
|
+
if (left < right) return -1;
|
|
29
|
+
if (left > right) return 1;
|
|
30
|
+
return 0;
|
|
31
|
+
}
|
|
32
|
+
function isNewer(candidate, current) {
|
|
33
|
+
return candidate.received_at_ms > current.received_at_ms || candidate.received_at_ms === current.received_at_ms && compareCodePoints(candidate.id, current.id) > 0;
|
|
34
|
+
}
|
|
35
|
+
function collectActiveInstallationOverview(request) {
|
|
36
|
+
const definition = getActiveWindowDefinition(request.window);
|
|
37
|
+
const windowStartMs = request.asOfMs - definition.bucketCount * definition.bucketSizeMs;
|
|
38
|
+
const rows = request.rows.filter((row) => row.received_at_ms >= windowStartMs && row.received_at_ms < request.asOfMs);
|
|
39
|
+
const latestByInstall = /* @__PURE__ */ new Map();
|
|
40
|
+
for (const row of rows) {
|
|
41
|
+
const current = latestByInstall.get(row.install_id);
|
|
42
|
+
if (current === void 0 || isNewer(row, current)) latestByInstall.set(row.install_id, row);
|
|
43
|
+
}
|
|
44
|
+
const selectedRows = [...latestByInstall.values()].filter((row) => request.userId === void 0 || row.user_id === request.userId);
|
|
45
|
+
const selectedInstallIds = new Set(selectedRows.map((row) => row.install_id));
|
|
46
|
+
const bundleCounts = /* @__PURE__ */ new Map();
|
|
47
|
+
for (const row of selectedRows) bundleCounts.set(row.to_bundle_id, (bundleCounts.get(row.to_bundle_id) ?? 0) + 1);
|
|
48
|
+
const latestByBucket = Array.from({ length: definition.bucketCount }, () => /* @__PURE__ */ new Map());
|
|
49
|
+
for (const row of rows) {
|
|
50
|
+
if (!selectedInstallIds.has(row.install_id)) continue;
|
|
51
|
+
const bucket = latestByBucket[Math.floor((row.received_at_ms - windowStartMs) / definition.bucketSizeMs)];
|
|
52
|
+
if (bucket === void 0) continue;
|
|
53
|
+
const current = bucket.get(row.install_id);
|
|
54
|
+
if (current === void 0 || isNewer(row, current)) bucket.set(row.install_id, row);
|
|
55
|
+
}
|
|
56
|
+
const bundleCountsByBucket = latestByBucket.map((bucket) => {
|
|
57
|
+
const counts = /* @__PURE__ */ new Map();
|
|
58
|
+
for (const row of bucket.values()) counts.set(row.to_bundle_id, (counts.get(row.to_bundle_id) ?? 0) + 1);
|
|
59
|
+
return counts;
|
|
60
|
+
});
|
|
61
|
+
const bundleObservationTotals = /* @__PURE__ */ new Map();
|
|
62
|
+
for (const counts of bundleCountsByBucket) for (const [bundleId, count] of counts) bundleObservationTotals.set(bundleId, (bundleObservationTotals.get(bundleId) ?? 0) + count);
|
|
63
|
+
return {
|
|
64
|
+
asOfMs: request.asOfMs,
|
|
65
|
+
window: request.window,
|
|
66
|
+
activeInstallations: selectedInstallIds.size,
|
|
67
|
+
series: latestByBucket.map((bucket, index) => ({
|
|
68
|
+
bucketStartMs: windowStartMs + index * definition.bucketSizeMs,
|
|
69
|
+
value: bucket.size
|
|
70
|
+
})),
|
|
71
|
+
bundleSeries: [...bundleObservationTotals].sort(([leftId, leftTotal], [rightId, rightTotal]) => rightTotal - leftTotal || compareCodePoints(leftId, rightId)).map(([bundleId]) => ({
|
|
72
|
+
bundleId,
|
|
73
|
+
series: bundleCountsByBucket.map((counts, index) => ({
|
|
74
|
+
bucketStartMs: windowStartMs + index * definition.bucketSizeMs,
|
|
75
|
+
value: counts.get(bundleId) ?? 0
|
|
76
|
+
}))
|
|
77
|
+
})),
|
|
78
|
+
bundles: [...bundleCounts].map(([bundleId, installations]) => ({
|
|
79
|
+
bundleId,
|
|
80
|
+
installations
|
|
81
|
+
})).sort((left, right) => right.installations - left.installations || compareCodePoints(left.bundleId, right.bundleId))
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
//#endregion
|
|
85
|
+
export { ACTIVE_BUNDLE_EVENT_TYPES, collectActiveInstallationOverview, getActiveWindowDefinition };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const require_scan = require("./scan.cjs");
|
|
2
|
+
//#region src/insights/bounded/installationSearch.ts
|
|
3
|
+
function toSearchRow(row) {
|
|
4
|
+
return {
|
|
5
|
+
installId: row.install_id,
|
|
6
|
+
username: row.username,
|
|
7
|
+
userId: row.user_id,
|
|
8
|
+
lastKnownBundleId: row.to_bundle_id,
|
|
9
|
+
latestStatus: row.type,
|
|
10
|
+
platform: row.platform,
|
|
11
|
+
appVersion: row.app_version,
|
|
12
|
+
channel: row.channel,
|
|
13
|
+
cohort: row.cohort,
|
|
14
|
+
receivedAtMs: row.received_at_ms
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function matchesIdentity(row, query) {
|
|
18
|
+
return row.install_id.toLowerCase().includes(query) || row.user_id?.toLowerCase().includes(query) === true || row.username?.toLowerCase().includes(query) === true;
|
|
19
|
+
}
|
|
20
|
+
function searchEventInstallations(request) {
|
|
21
|
+
const query = request.query.toLowerCase();
|
|
22
|
+
const matchingInstallIds = /* @__PURE__ */ new Set();
|
|
23
|
+
for (const row of request.rows) if (query.length === 0 || matchesIdentity(row, query)) matchingInstallIds.add(row.install_id);
|
|
24
|
+
const latestByInstall = /* @__PURE__ */ new Map();
|
|
25
|
+
for (const row of request.rows) {
|
|
26
|
+
if (!matchingInstallIds.has(row.install_id)) continue;
|
|
27
|
+
const current = latestByInstall.get(row.install_id);
|
|
28
|
+
if (current === void 0 || require_scan.compareEventNewest(row, current) < 0) latestByInstall.set(row.install_id, row);
|
|
29
|
+
}
|
|
30
|
+
const matchingRows = [...latestByInstall.values()].sort((left, right) => require_scan.compareCodePoints(left.install_id, right.install_id));
|
|
31
|
+
const pageSize = Math.min(Math.max(request.limit, 0), 100);
|
|
32
|
+
return {
|
|
33
|
+
data: matchingRows.slice(request.offset, request.offset + pageSize).map(toSearchRow),
|
|
34
|
+
pagination: {
|
|
35
|
+
total: matchingRows.length,
|
|
36
|
+
limit: request.limit,
|
|
37
|
+
offset: request.offset
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
//#endregion
|
|
42
|
+
exports.searchEventInstallations = searchEventInstallations;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { compareCodePoints, compareEventNewest } from "./scan.mjs";
|
|
2
|
+
//#region src/insights/bounded/installationSearch.ts
|
|
3
|
+
function toSearchRow(row) {
|
|
4
|
+
return {
|
|
5
|
+
installId: row.install_id,
|
|
6
|
+
username: row.username,
|
|
7
|
+
userId: row.user_id,
|
|
8
|
+
lastKnownBundleId: row.to_bundle_id,
|
|
9
|
+
latestStatus: row.type,
|
|
10
|
+
platform: row.platform,
|
|
11
|
+
appVersion: row.app_version,
|
|
12
|
+
channel: row.channel,
|
|
13
|
+
cohort: row.cohort,
|
|
14
|
+
receivedAtMs: row.received_at_ms
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function matchesIdentity(row, query) {
|
|
18
|
+
return row.install_id.toLowerCase().includes(query) || row.user_id?.toLowerCase().includes(query) === true || row.username?.toLowerCase().includes(query) === true;
|
|
19
|
+
}
|
|
20
|
+
function searchEventInstallations(request) {
|
|
21
|
+
const query = request.query.toLowerCase();
|
|
22
|
+
const matchingInstallIds = /* @__PURE__ */ new Set();
|
|
23
|
+
for (const row of request.rows) if (query.length === 0 || matchesIdentity(row, query)) matchingInstallIds.add(row.install_id);
|
|
24
|
+
const latestByInstall = /* @__PURE__ */ new Map();
|
|
25
|
+
for (const row of request.rows) {
|
|
26
|
+
if (!matchingInstallIds.has(row.install_id)) continue;
|
|
27
|
+
const current = latestByInstall.get(row.install_id);
|
|
28
|
+
if (current === void 0 || compareEventNewest(row, current) < 0) latestByInstall.set(row.install_id, row);
|
|
29
|
+
}
|
|
30
|
+
const matchingRows = [...latestByInstall.values()].sort((left, right) => compareCodePoints(left.install_id, right.install_id));
|
|
31
|
+
const pageSize = Math.min(Math.max(request.limit, 0), 100);
|
|
32
|
+
return {
|
|
33
|
+
data: matchingRows.slice(request.offset, request.offset + pageSize).map(toSearchRow),
|
|
34
|
+
pagination: {
|
|
35
|
+
total: matchingRows.length,
|
|
36
|
+
limit: request.limit,
|
|
37
|
+
offset: request.offset
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
//#endregion
|
|
42
|
+
export { searchEventInstallations };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require("../../_virtual/_rolldown/runtime.cjs");
|
|
2
|
+
let _hot_updater_plugin_core = require("@hot-updater/plugin-core");
|
|
3
|
+
//#region src/insights/bounded/persistence.ts
|
|
4
|
+
function createBundleEventRow(input) {
|
|
5
|
+
const base = {
|
|
6
|
+
id: (0, _hot_updater_plugin_core.createUUIDv7)(),
|
|
7
|
+
install_id: input.installId,
|
|
8
|
+
user_id: input.userId ?? null,
|
|
9
|
+
username: input.username ?? null,
|
|
10
|
+
from_release_id: input.fromReleaseId,
|
|
11
|
+
to_release_id: input.toReleaseId,
|
|
12
|
+
to_bundle_id: input.toBundleId,
|
|
13
|
+
platform: input.platform,
|
|
14
|
+
app_version: input.appVersion,
|
|
15
|
+
channel: input.channel,
|
|
16
|
+
cohort: input.cohort,
|
|
17
|
+
fingerprint_hash: input.fingerprintHash,
|
|
18
|
+
sdk_version: input.sdkVersion ?? null,
|
|
19
|
+
received_at_ms: Date.now()
|
|
20
|
+
};
|
|
21
|
+
switch (input.type) {
|
|
22
|
+
case "UPDATE_APPLIED":
|
|
23
|
+
case "RECOVERED":
|
|
24
|
+
case "RELEASE_ADOPTED": return {
|
|
25
|
+
...base,
|
|
26
|
+
type: input.type,
|
|
27
|
+
from_bundle_id: input.fromBundleId,
|
|
28
|
+
update_strategy: input.updateStrategy
|
|
29
|
+
};
|
|
30
|
+
case "UNCHANGED": return {
|
|
31
|
+
...base,
|
|
32
|
+
type: input.type,
|
|
33
|
+
from_bundle_id: null,
|
|
34
|
+
update_strategy: null
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
//#endregion
|
|
39
|
+
exports.createBundleEventRow = createBundleEventRow;
|