@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
package/dist/handler.d.cts
CHANGED
|
@@ -1,49 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { AppUpdateAvailableInfo, AppVersionGetBundlesArgs, Bundle, FingerprintGetBundlesArgs } from "@hot-updater/core";
|
|
3
|
-
import { DatabaseBundleQueryOptions, HotUpdaterContext } from "@hot-updater/plugin-core";
|
|
1
|
+
import { HandlerAPI, HotUpdaterHandler, HotUpdaterHandlers } from "./handlerTypes.cjs";
|
|
4
2
|
|
|
5
3
|
//#region src/handler.d.ts
|
|
6
|
-
|
|
7
|
-
getAppUpdateInfo: (args: AppVersionGetBundlesArgs | FingerprintGetBundlesArgs, context?: HotUpdaterContext<TContext>) => Promise<AppUpdateAvailableInfo | null>;
|
|
8
|
-
getBundleById: (id: string, context?: HotUpdaterContext<TContext>) => Promise<Bundle | null>;
|
|
9
|
-
getBundles: (options: DatabaseBundleQueryOptions, context?: HotUpdaterContext<TContext>) => Promise<PaginatedResult>;
|
|
10
|
-
insertBundle: (bundle: Bundle, context?: HotUpdaterContext<TContext>) => Promise<void>;
|
|
11
|
-
updateBundleById: (bundleId: string, bundle: Partial<Bundle>, context?: HotUpdaterContext<TContext>) => Promise<void>;
|
|
12
|
-
deleteBundleById: (bundleId: string, context?: HotUpdaterContext<TContext>) => Promise<void>;
|
|
13
|
-
getChannels: (context?: HotUpdaterContext<TContext>) => Promise<string[]>;
|
|
14
|
-
}
|
|
15
|
-
interface HandlerOptions {
|
|
16
|
-
/**
|
|
17
|
-
* Base path for all routes
|
|
18
|
-
* @default "/api"
|
|
19
|
-
*/
|
|
20
|
-
basePath?: string;
|
|
21
|
-
/**
|
|
22
|
-
* Route groups to mount. Omit this option to use the default route groups.
|
|
23
|
-
* When provided, both route groups must be specified explicitly.
|
|
24
|
-
* The `/version` endpoint is always mounted for diagnostics.
|
|
25
|
-
*/
|
|
26
|
-
routes?: HandlerRoutes;
|
|
27
|
-
}
|
|
28
|
-
interface HandlerRoutes {
|
|
29
|
-
/**
|
|
30
|
-
* Controls whether update-check routes are mounted.
|
|
31
|
-
* Defaults to `true` only when `routes` is omitted.
|
|
32
|
-
*/
|
|
33
|
-
updateCheck: boolean;
|
|
34
|
-
/**
|
|
35
|
-
* Controls whether bundle management routes are mounted.
|
|
36
|
-
* This includes `/api/bundles*`, which are used by the
|
|
37
|
-
* CLI `standaloneRepository` plugin.
|
|
38
|
-
* Defaults to `false` only when `routes` is omitted.
|
|
39
|
-
*/
|
|
40
|
-
bundles: boolean;
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Creates a Web Standard Request handler for Hot Updater API
|
|
44
|
-
* This handler is framework-agnostic and works with any runtime that
|
|
45
|
-
* supports standard Request/Response objects.
|
|
46
|
-
*/
|
|
47
|
-
declare function createHandler<TContext = unknown>(api: HandlerAPI<TContext>, options?: HandlerOptions): (request: Request, context?: HotUpdaterContext<TContext>) => Promise<Response>;
|
|
4
|
+
declare function createHandlers(api: HandlerAPI): HotUpdaterHandlers;
|
|
48
5
|
//#endregion
|
|
49
|
-
export {
|
|
6
|
+
export { createHandlers };
|
package/dist/handler.d.mts
CHANGED
|
@@ -1,49 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { DatabaseBundleQueryOptions, HotUpdaterContext } from "@hot-updater/plugin-core";
|
|
3
|
-
import { AppUpdateAvailableInfo, AppVersionGetBundlesArgs, Bundle as Bundle$1, FingerprintGetBundlesArgs } from "@hot-updater/core";
|
|
1
|
+
import { HandlerAPI, HotUpdaterHandler, HotUpdaterHandlers } from "./handlerTypes.mjs";
|
|
4
2
|
|
|
5
3
|
//#region src/handler.d.ts
|
|
6
|
-
|
|
7
|
-
getAppUpdateInfo: (args: AppVersionGetBundlesArgs | FingerprintGetBundlesArgs, context?: HotUpdaterContext<TContext>) => Promise<AppUpdateAvailableInfo | null>;
|
|
8
|
-
getBundleById: (id: string, context?: HotUpdaterContext<TContext>) => Promise<Bundle$1 | null>;
|
|
9
|
-
getBundles: (options: DatabaseBundleQueryOptions, context?: HotUpdaterContext<TContext>) => Promise<PaginatedResult>;
|
|
10
|
-
insertBundle: (bundle: Bundle$1, context?: HotUpdaterContext<TContext>) => Promise<void>;
|
|
11
|
-
updateBundleById: (bundleId: string, bundle: Partial<Bundle$1>, context?: HotUpdaterContext<TContext>) => Promise<void>;
|
|
12
|
-
deleteBundleById: (bundleId: string, context?: HotUpdaterContext<TContext>) => Promise<void>;
|
|
13
|
-
getChannels: (context?: HotUpdaterContext<TContext>) => Promise<string[]>;
|
|
14
|
-
}
|
|
15
|
-
interface HandlerOptions {
|
|
16
|
-
/**
|
|
17
|
-
* Base path for all routes
|
|
18
|
-
* @default "/api"
|
|
19
|
-
*/
|
|
20
|
-
basePath?: string;
|
|
21
|
-
/**
|
|
22
|
-
* Route groups to mount. Omit this option to use the default route groups.
|
|
23
|
-
* When provided, both route groups must be specified explicitly.
|
|
24
|
-
* The `/version` endpoint is always mounted for diagnostics.
|
|
25
|
-
*/
|
|
26
|
-
routes?: HandlerRoutes;
|
|
27
|
-
}
|
|
28
|
-
interface HandlerRoutes {
|
|
29
|
-
/**
|
|
30
|
-
* Controls whether update-check routes are mounted.
|
|
31
|
-
* Defaults to `true` only when `routes` is omitted.
|
|
32
|
-
*/
|
|
33
|
-
updateCheck: boolean;
|
|
34
|
-
/**
|
|
35
|
-
* Controls whether bundle management routes are mounted.
|
|
36
|
-
* This includes `/api/bundles*`, which are used by the
|
|
37
|
-
* CLI `standaloneRepository` plugin.
|
|
38
|
-
* Defaults to `false` only when `routes` is omitted.
|
|
39
|
-
*/
|
|
40
|
-
bundles: boolean;
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Creates a Web Standard Request handler for Hot Updater API
|
|
44
|
-
* This handler is framework-agnostic and works with any runtime that
|
|
45
|
-
* supports standard Request/Response objects.
|
|
46
|
-
*/
|
|
47
|
-
declare function createHandler<TContext = unknown>(api: HandlerAPI<TContext>, options?: HandlerOptions): (request: Request, context?: HotUpdaterContext<TContext>) => Promise<Response>;
|
|
4
|
+
declare function createHandlers(api: HandlerAPI): HotUpdaterHandlers;
|
|
48
5
|
//#endregion
|
|
49
|
-
export {
|
|
6
|
+
export { createHandlers };
|
package/dist/handler.mjs
CHANGED
|
@@ -1,293 +1,119 @@
|
|
|
1
|
+
import { HandlerBadRequestError } from "./handlerErrors.mjs";
|
|
2
|
+
import { createBundleRouteHandlers } from "./handlerBundleRoutes.mjs";
|
|
3
|
+
import { createReleaseCatalogRouteHandlers } from "./handlerReleaseCatalogRoutes.mjs";
|
|
4
|
+
import { createReleaseManagementRouteHandlers } from "./handlerReleaseManagementRoutes.mjs";
|
|
5
|
+
import { createVersionRouteHandlers } from "./handlerVersionRoutes.mjs";
|
|
6
|
+
import { createInsightsRouteHandlers, registerInsightsAdminRoutes, registerInsightsClientRoutes } from "./insights/routes.mjs";
|
|
1
7
|
import { addRoute, createRouter, findRoute } from "./internalRouter.mjs";
|
|
2
|
-
import { HOT_UPDATER_SERVER_VERSION } from "./version.mjs";
|
|
3
|
-
import { isGreaterOrEqual, normalize } from "verkit";
|
|
4
8
|
//#region src/handler.ts
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const EXPLICIT_NO_UPDATE_MIN_SDK_VERSION = "0.31.0";
|
|
13
|
-
const DEFAULT_BUNDLE_LIST_LIMIT = 50;
|
|
14
|
-
const MAX_BUNDLE_LIST_LIMIT = 100;
|
|
15
|
-
const supportsExplicitNoUpdateResponse = (request) => {
|
|
16
|
-
const sdkVersion = request.headers.get(SDK_VERSION_HEADER)?.trim();
|
|
17
|
-
if (!sdkVersion) return false;
|
|
18
|
-
const normalizedSdkVersion = normalize(sdkVersion);
|
|
19
|
-
return normalizedSdkVersion !== null && isGreaterOrEqual(normalizedSdkVersion, EXPLICIT_NO_UPDATE_MIN_SDK_VERSION);
|
|
20
|
-
};
|
|
21
|
-
const serializeUpdateInfo = (updateInfo, request) => {
|
|
22
|
-
if (updateInfo) return JSON.stringify(updateInfo);
|
|
23
|
-
if (supportsExplicitNoUpdateResponse(request)) return JSON.stringify({ status: "UP_TO_DATE" });
|
|
24
|
-
return JSON.stringify(null);
|
|
25
|
-
};
|
|
26
|
-
const handleVersion = async () => {
|
|
27
|
-
return new Response(JSON.stringify({ version: HOT_UPDATER_SERVER_VERSION }), {
|
|
28
|
-
status: 200,
|
|
29
|
-
headers: { "Content-Type": "application/json" }
|
|
9
|
+
const withPrivateNoStore = (response) => {
|
|
10
|
+
const headers = new Headers(response.headers);
|
|
11
|
+
headers.set("cache-control", "private, no-store");
|
|
12
|
+
return new Response(response.body, {
|
|
13
|
+
headers,
|
|
14
|
+
status: response.status,
|
|
15
|
+
statusText: response.statusText
|
|
30
16
|
});
|
|
31
17
|
};
|
|
32
|
-
const
|
|
33
|
-
|
|
18
|
+
const errorResponse = (error, status) => Response.json({ error }, {
|
|
19
|
+
headers: { "cache-control": "private, no-store" },
|
|
20
|
+
status
|
|
21
|
+
});
|
|
22
|
+
const requiresApiKey = (handlerName) => handlerName === "appVersionReleaseCatalog" || handlerName === "fingerprintReleaseCatalog" || handlerName === "artifact" || handlerName === "appendBundleEvent";
|
|
23
|
+
const createRequestHandler = ({ api, apiKeyAuth, privateResponses = false, routeHandlers, router }) => async (request) => {
|
|
34
24
|
try {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
25
|
+
const match = findRoute(router, request.method, new URL(request.url).pathname);
|
|
26
|
+
if (!match) return errorResponse("Not found", 404);
|
|
27
|
+
if (apiKeyAuth !== void 0 && requiresApiKey(match.data)) {
|
|
28
|
+
let authenticated;
|
|
29
|
+
try {
|
|
30
|
+
authenticated = await apiKeyAuth.authenticate(request);
|
|
31
|
+
} catch {
|
|
32
|
+
return errorResponse("Service unavailable", 503);
|
|
33
|
+
}
|
|
34
|
+
if (!authenticated) return errorResponse("Unauthorized", 401);
|
|
35
|
+
}
|
|
36
|
+
const handler = routeHandlers[match.data];
|
|
37
|
+
if (!handler) return errorResponse("Handler not found", 500);
|
|
38
|
+
const response = await handler(match.params, request, api);
|
|
39
|
+
return privateResponses ? withPrivateNoStore(response) : response;
|
|
40
|
+
} catch (error) {
|
|
41
|
+
if (error instanceof HandlerBadRequestError) return errorResponse(error.message, 400);
|
|
42
|
+
console.error("Hot Updater handler error:", error);
|
|
43
|
+
return Response.json({ error: "Internal server error" }, {
|
|
44
|
+
headers: { "cache-control": "private, no-store" },
|
|
45
|
+
status: 500
|
|
46
|
+
});
|
|
38
47
|
}
|
|
39
48
|
};
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const
|
|
45
|
-
if (!
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
if (value === "false") return false;
|
|
53
|
-
throw new HandlerBadRequestError(`The '${key}' query parameter must be 'true' or 'false'.`);
|
|
54
|
-
};
|
|
55
|
-
const parseNullableStringSearchParam = (url, key) => {
|
|
56
|
-
const value = url.searchParams.get(key);
|
|
57
|
-
if (value === null) return;
|
|
58
|
-
return value === "null" ? null : value;
|
|
59
|
-
};
|
|
60
|
-
const parseStringArraySearchParam = (url, key) => {
|
|
61
|
-
const values = url.searchParams.getAll(key);
|
|
62
|
-
return values.length > 0 ? values : void 0;
|
|
63
|
-
};
|
|
64
|
-
const parsePositiveIntegerSearchParam = (url, key, defaultValue, maxValue) => {
|
|
65
|
-
const value = url.searchParams.get(key);
|
|
66
|
-
if (value === null) return defaultValue;
|
|
67
|
-
const parsed = Number(value);
|
|
68
|
-
if (!Number.isInteger(parsed) || parsed < 1 || parsed > maxValue) throw new HandlerBadRequestError(`The '${key}' query parameter must be a positive integer between 1 and ${maxValue}.`);
|
|
69
|
-
return parsed;
|
|
70
|
-
};
|
|
71
|
-
const requirePlatformParam = (params) => {
|
|
72
|
-
const platform = requireRouteParam(params, "platform");
|
|
73
|
-
if (!isPlatform(platform)) throw new HandlerBadRequestError(`Invalid platform: ${platform}. Expected 'ios' or 'android'.`);
|
|
74
|
-
return platform;
|
|
75
|
-
};
|
|
76
|
-
const requireBundlePatchPayload = (payload, bundleId) => {
|
|
77
|
-
if (!payload || typeof payload !== "object" || Array.isArray(payload)) throw new HandlerBadRequestError("Invalid bundle payload");
|
|
78
|
-
const bundlePatch = payload;
|
|
79
|
-
if (bundlePatch.id !== void 0 && bundlePatch.id !== bundleId) throw new HandlerBadRequestError("Bundle id mismatch");
|
|
80
|
-
const { id: _ignoredId, ...rest } = bundlePatch;
|
|
81
|
-
return rest;
|
|
82
|
-
};
|
|
83
|
-
const handleFingerprintUpdateWithCohort = async (params, request, api, context) => {
|
|
84
|
-
const platform = requirePlatformParam(params);
|
|
85
|
-
const fingerprintHash = requireRouteParam(params, "fingerprintHash");
|
|
86
|
-
const channel = requireRouteParam(params, "channel");
|
|
87
|
-
const minBundleId = requireRouteParam(params, "minBundleId");
|
|
88
|
-
const bundleId = requireRouteParam(params, "bundleId");
|
|
89
|
-
const updateInfo = await api.getAppUpdateInfo({
|
|
90
|
-
_updateStrategy: "fingerprint",
|
|
91
|
-
platform,
|
|
92
|
-
fingerprintHash,
|
|
93
|
-
channel,
|
|
94
|
-
minBundleId,
|
|
95
|
-
bundleId,
|
|
96
|
-
cohort: decodeMaybe(params.cohort)
|
|
97
|
-
}, context);
|
|
98
|
-
return new Response(serializeUpdateInfo(updateInfo, request), {
|
|
99
|
-
status: 200,
|
|
100
|
-
headers: { "Content-Type": "application/json" }
|
|
101
|
-
});
|
|
102
|
-
};
|
|
103
|
-
const handleAppVersionUpdateWithCohort = async (params, request, api, context) => {
|
|
104
|
-
const platform = requirePlatformParam(params);
|
|
105
|
-
const appVersion = requireRouteParam(params, "appVersion");
|
|
106
|
-
const channel = requireRouteParam(params, "channel");
|
|
107
|
-
const minBundleId = requireRouteParam(params, "minBundleId");
|
|
108
|
-
const bundleId = requireRouteParam(params, "bundleId");
|
|
109
|
-
const updateInfo = await api.getAppUpdateInfo({
|
|
110
|
-
_updateStrategy: "appVersion",
|
|
111
|
-
platform,
|
|
112
|
-
appVersion,
|
|
113
|
-
channel,
|
|
114
|
-
minBundleId,
|
|
115
|
-
bundleId,
|
|
116
|
-
cohort: decodeMaybe(params.cohort)
|
|
117
|
-
}, context);
|
|
118
|
-
return new Response(serializeUpdateInfo(updateInfo, request), {
|
|
119
|
-
status: 200,
|
|
120
|
-
headers: { "Content-Type": "application/json" }
|
|
121
|
-
});
|
|
122
|
-
};
|
|
123
|
-
const handleGetBundle = async (params, _request, api, context) => {
|
|
124
|
-
const bundleId = requireRouteParam(params, "id");
|
|
125
|
-
const bundle = await api.getBundleById(bundleId, context);
|
|
126
|
-
if (!bundle) return new Response(JSON.stringify({ error: "Bundle not found" }), {
|
|
127
|
-
status: 404,
|
|
128
|
-
headers: { "Content-Type": "application/json" }
|
|
129
|
-
});
|
|
130
|
-
return new Response(JSON.stringify(bundle), {
|
|
131
|
-
status: 200,
|
|
132
|
-
headers: { "Content-Type": "application/json" }
|
|
49
|
+
const createDownloadStorageRouteHandler = (downloadStorageObject) => async (params) => {
|
|
50
|
+
const token = params.token;
|
|
51
|
+
const signature = params.signature;
|
|
52
|
+
if (!token || !signature) return errorResponse("Not found", 404);
|
|
53
|
+
const response = await downloadStorageObject(token, signature);
|
|
54
|
+
if (!response) return errorResponse("Not found", 404);
|
|
55
|
+
const headers = new Headers(response.headers);
|
|
56
|
+
if (!headers.has("cache-control")) headers.set("cache-control", "public, max-age=31536000, immutable");
|
|
57
|
+
return new Response(response.body, {
|
|
58
|
+
headers,
|
|
59
|
+
status: response.status,
|
|
60
|
+
statusText: response.statusText
|
|
133
61
|
});
|
|
134
62
|
};
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
const targetAppVersionIn = parseStringArraySearchParam(url, "targetAppVersionIn");
|
|
147
|
-
const targetAppVersionNotNull = parseBooleanSearchParam(url, "targetAppVersionNotNull");
|
|
148
|
-
const fingerprintHash = parseNullableStringSearchParam(url, "fingerprintHash");
|
|
149
|
-
const idEq = url.searchParams.get("idEq") ?? void 0;
|
|
150
|
-
const idGt = url.searchParams.get("idGt") ?? void 0;
|
|
151
|
-
const idGte = url.searchParams.get("idGte") ?? void 0;
|
|
152
|
-
const idLt = url.searchParams.get("idLt") ?? void 0;
|
|
153
|
-
const idLte = url.searchParams.get("idLte") ?? void 0;
|
|
154
|
-
const idIn = parseStringArraySearchParam(url, "idIn");
|
|
155
|
-
const page = pageParam === null ? void 0 : Number.isInteger(Number(pageParam)) && Number(pageParam) > 0 ? Number(pageParam) : null;
|
|
156
|
-
if (offset !== null) throw new HandlerBadRequestError("The 'offset' query parameter has been removed. Use 'after' or 'before' cursor pagination instead.");
|
|
157
|
-
if (page === null) throw new HandlerBadRequestError("The 'page' query parameter must be a positive integer.");
|
|
158
|
-
if (platform !== null && !isPlatform(platform)) throw new HandlerBadRequestError(`Invalid platform: ${platform}. Expected 'ios' or 'android'.`);
|
|
159
|
-
const result = await api.getBundles({
|
|
160
|
-
where: {
|
|
161
|
-
...channel && { channel },
|
|
162
|
-
...platform && { platform },
|
|
163
|
-
...enabled !== void 0 && { enabled },
|
|
164
|
-
...idEq || idGt || idGte || idLt || idLte || idIn && idIn.length > 0 ? { id: {
|
|
165
|
-
...idEq && { eq: idEq },
|
|
166
|
-
...idGt && { gt: idGt },
|
|
167
|
-
...idGte && { gte: idGte },
|
|
168
|
-
...idLt && { lt: idLt },
|
|
169
|
-
...idLte && { lte: idLte },
|
|
170
|
-
...idIn && idIn.length > 0 && { in: idIn }
|
|
171
|
-
} } : {},
|
|
172
|
-
...targetAppVersion !== void 0 && { targetAppVersion },
|
|
173
|
-
...targetAppVersionIn && { targetAppVersionIn },
|
|
174
|
-
...targetAppVersionNotNull !== void 0 && { targetAppVersionNotNull },
|
|
175
|
-
...fingerprintHash !== void 0 && { fingerprintHash }
|
|
176
|
-
},
|
|
177
|
-
limit,
|
|
178
|
-
page,
|
|
179
|
-
cursor: after || before ? {
|
|
180
|
-
after,
|
|
181
|
-
before
|
|
182
|
-
} : void 0
|
|
183
|
-
}, context);
|
|
184
|
-
return new Response(JSON.stringify(result), {
|
|
185
|
-
status: 200,
|
|
186
|
-
headers: { "Content-Type": "application/json" }
|
|
187
|
-
});
|
|
188
|
-
};
|
|
189
|
-
const handleCreateBundles = async (_params, request, api, context) => {
|
|
190
|
-
const body = await request.json();
|
|
191
|
-
const bundles = Array.isArray(body) ? body : [body];
|
|
192
|
-
for (const bundle of bundles) await api.insertBundle(bundle, context);
|
|
193
|
-
return new Response(JSON.stringify({ success: true }), {
|
|
194
|
-
status: 201,
|
|
195
|
-
headers: { "Content-Type": "application/json" }
|
|
196
|
-
});
|
|
197
|
-
};
|
|
198
|
-
const handleUpdateBundle = async (params, request, api, context) => {
|
|
199
|
-
const bundleId = requireRouteParam(params, "id");
|
|
200
|
-
const body = await request.json();
|
|
201
|
-
const bundlePatch = requireBundlePatchPayload(Array.isArray(body) ? body[0] : body, bundleId);
|
|
202
|
-
await api.updateBundleById(bundleId, bundlePatch, context);
|
|
203
|
-
return new Response(JSON.stringify({ success: true }), {
|
|
204
|
-
status: 200,
|
|
205
|
-
headers: { "Content-Type": "application/json" }
|
|
206
|
-
});
|
|
207
|
-
};
|
|
208
|
-
const handleDeleteBundle = async (params, _request, api, context) => {
|
|
209
|
-
const bundleId = requireRouteParam(params, "id");
|
|
210
|
-
await api.deleteBundleById(bundleId, context);
|
|
211
|
-
return new Response(JSON.stringify({ success: true }), {
|
|
212
|
-
status: 200,
|
|
213
|
-
headers: { "Content-Type": "application/json" }
|
|
214
|
-
});
|
|
215
|
-
};
|
|
216
|
-
const handleGetChannels = async (_params, _request, api, context) => {
|
|
217
|
-
const response = { data: { channels: await api.getChannels(context) } };
|
|
218
|
-
return new Response(JSON.stringify(response), {
|
|
219
|
-
status: 200,
|
|
220
|
-
headers: { "Content-Type": "application/json" }
|
|
221
|
-
});
|
|
222
|
-
};
|
|
223
|
-
const routes = {
|
|
224
|
-
version: handleVersion,
|
|
225
|
-
fingerprintUpdateWithCohort: handleFingerprintUpdateWithCohort,
|
|
226
|
-
appVersionUpdateWithCohort: handleAppVersionUpdateWithCohort,
|
|
227
|
-
getBundle: handleGetBundle,
|
|
228
|
-
getBundles: handleGetBundles,
|
|
229
|
-
createBundles: handleCreateBundles,
|
|
230
|
-
updateBundle: handleUpdateBundle,
|
|
231
|
-
deleteBundle: handleDeleteBundle,
|
|
232
|
-
getChannels: handleGetChannels
|
|
233
|
-
};
|
|
234
|
-
/**
|
|
235
|
-
* Creates a Web Standard Request handler for Hot Updater API
|
|
236
|
-
* This handler is framework-agnostic and works with any runtime that
|
|
237
|
-
* supports standard Request/Response objects.
|
|
238
|
-
*/
|
|
239
|
-
function createHandler(api, options = {}) {
|
|
240
|
-
const basePath = options.basePath ?? "/api";
|
|
241
|
-
const routeOptions = {
|
|
242
|
-
updateCheck: options.routes?.updateCheck ?? true,
|
|
243
|
-
bundles: options.routes?.bundles ?? false
|
|
244
|
-
};
|
|
245
|
-
const router = createRouter();
|
|
246
|
-
addRoute(router, "GET", "/version", "version");
|
|
247
|
-
if (routeOptions.updateCheck) {
|
|
248
|
-
addRoute(router, "GET", "/fingerprint/:platform/:fingerprintHash/:channel/:minBundleId/:bundleId", "fingerprintUpdateWithCohort");
|
|
249
|
-
addRoute(router, "GET", "/fingerprint/:platform/:fingerprintHash/:channel/:minBundleId/:bundleId/:cohort", "fingerprintUpdateWithCohort");
|
|
250
|
-
addRoute(router, "GET", "/app-version/:platform/:appVersion/:channel/:minBundleId/:bundleId", "appVersionUpdateWithCohort");
|
|
251
|
-
addRoute(router, "GET", "/app-version/:platform/:appVersion/:channel/:minBundleId/:bundleId/:cohort", "appVersionUpdateWithCohort");
|
|
252
|
-
}
|
|
253
|
-
if (routeOptions.bundles) {
|
|
254
|
-
addRoute(router, "GET", "/api/bundles/channels", "getChannels");
|
|
255
|
-
addRoute(router, "GET", "/api/bundles/:id", "getBundle");
|
|
256
|
-
addRoute(router, "GET", "/api/bundles", "getBundles");
|
|
257
|
-
addRoute(router, "POST", "/api/bundles", "createBundles");
|
|
258
|
-
addRoute(router, "PATCH", "/api/bundles/:id", "updateBundle");
|
|
259
|
-
addRoute(router, "DELETE", "/api/bundles/:id", "deleteBundle");
|
|
260
|
-
}
|
|
261
|
-
return async (request, context) => {
|
|
262
|
-
try {
|
|
263
|
-
const path = new URL(request.url).pathname;
|
|
264
|
-
const method = request.method;
|
|
265
|
-
const match = findRoute(router, method, path.startsWith(basePath) ? path.slice(basePath.length) : path);
|
|
266
|
-
if (!match) return new Response(JSON.stringify({ error: "Not found" }), {
|
|
267
|
-
status: 404,
|
|
268
|
-
headers: { "Content-Type": "application/json" }
|
|
269
|
-
});
|
|
270
|
-
const handler = routes[match.data];
|
|
271
|
-
if (!handler) return new Response(JSON.stringify({ error: "Handler not found" }), {
|
|
272
|
-
status: 500,
|
|
273
|
-
headers: { "Content-Type": "application/json" }
|
|
274
|
-
});
|
|
275
|
-
return await handler(match.params || {}, request, api, context);
|
|
276
|
-
} catch (error) {
|
|
277
|
-
if (error instanceof HandlerBadRequestError) return new Response(JSON.stringify({ error: error.message }), {
|
|
278
|
-
status: 400,
|
|
279
|
-
headers: { "Content-Type": "application/json" }
|
|
280
|
-
});
|
|
281
|
-
console.error("Hot Updater handler error:", error);
|
|
282
|
-
return new Response(JSON.stringify({
|
|
283
|
-
error: "Internal server error",
|
|
284
|
-
message: error instanceof Error ? error.message : "Unknown error"
|
|
285
|
-
}), {
|
|
286
|
-
status: 500,
|
|
287
|
-
headers: { "Content-Type": "application/json" }
|
|
288
|
-
});
|
|
289
|
-
}
|
|
63
|
+
function createHandlers(api) {
|
|
64
|
+
return createHotUpdaterHandlers(api);
|
|
65
|
+
}
|
|
66
|
+
function createHotUpdaterHandlers(api, insights, apiKeyAuth, downloadStorageObject) {
|
|
67
|
+
const routeHandlers = {
|
|
68
|
+
...createVersionRouteHandlers(),
|
|
69
|
+
...createReleaseCatalogRouteHandlers(apiKeyAuth?.headerName),
|
|
70
|
+
...createReleaseManagementRouteHandlers(),
|
|
71
|
+
...createBundleRouteHandlers(),
|
|
72
|
+
...insights === void 0 ? {} : createInsightsRouteHandlers(insights),
|
|
73
|
+
...downloadStorageObject === void 0 ? {} : { downloadStorageObject: createDownloadStorageRouteHandler(downloadStorageObject) }
|
|
290
74
|
};
|
|
75
|
+
const clientRouter = createRouter();
|
|
76
|
+
const addClientRoute = (method, path, handler) => addRoute(clientRouter, method, path, handler);
|
|
77
|
+
addClientRoute("GET", "/version", "version");
|
|
78
|
+
if (downloadStorageObject !== void 0) addClientRoute("GET", "/storage/:token/:signature", "downloadStorageObject");
|
|
79
|
+
addClientRoute("GET", "/release-catalogs/app-version/:platform/:channelKey/:appVersion", "appVersionReleaseCatalog");
|
|
80
|
+
addClientRoute("GET", "/release-catalogs/fingerprint/:platform/:channelKey/:fingerprintHash", "fingerprintReleaseCatalog");
|
|
81
|
+
addClientRoute("GET", "/artifacts/:targetBundleId/from/:currentBundleId", "artifact");
|
|
82
|
+
if (insights !== void 0) registerInsightsClientRoutes(addClientRoute);
|
|
83
|
+
const adminRouter = createRouter();
|
|
84
|
+
const addAdminRoute = (method, path, handler) => addRoute(adminRouter, method, path, handler);
|
|
85
|
+
addAdminRoute("GET", "/releases/:id", "getRelease");
|
|
86
|
+
addAdminRoute("GET", "/releases", "getReleases");
|
|
87
|
+
addAdminRoute("PATCH", "/releases/:id", "updateRelease");
|
|
88
|
+
addAdminRoute("POST", "/releases/:id/preflight", "preflightRelease");
|
|
89
|
+
addAdminRoute("DELETE", "/releases/:id", "deleteRelease");
|
|
90
|
+
addAdminRoute("GET", "/release-catalogs/:scopeKey", "getReleaseCatalogRow");
|
|
91
|
+
addAdminRoute("GET", "/release-catalogs", "getReleaseCatalogs");
|
|
92
|
+
addAdminRoute("POST", "/release-catalogs/:scopeKey/rebuild", "rebuildReleaseCatalog");
|
|
93
|
+
addAdminRoute("POST", "/database/commit", "commitDatabase");
|
|
94
|
+
addAdminRoute("GET", "/channels", "getChannels");
|
|
95
|
+
addAdminRoute("POST", "/channels", "createChannel");
|
|
96
|
+
addAdminRoute("DELETE", "/channels/:id", "deleteChannel");
|
|
97
|
+
addAdminRoute("GET", "/bundles/:id", "getBundle");
|
|
98
|
+
addAdminRoute("GET", "/bundles", "getBundles");
|
|
99
|
+
addAdminRoute("POST", "/bundles", "createBundles");
|
|
100
|
+
addAdminRoute("PATCH", "/bundles/:id", "updateBundle");
|
|
101
|
+
addAdminRoute("DELETE", "/bundles/:id", "deleteBundle");
|
|
102
|
+
if (insights !== void 0) registerInsightsAdminRoutes(addAdminRoute);
|
|
103
|
+
return Object.freeze({
|
|
104
|
+
client: createRequestHandler({
|
|
105
|
+
api,
|
|
106
|
+
apiKeyAuth,
|
|
107
|
+
routeHandlers,
|
|
108
|
+
router: clientRouter
|
|
109
|
+
}),
|
|
110
|
+
admin: createRequestHandler({
|
|
111
|
+
api,
|
|
112
|
+
privateResponses: true,
|
|
113
|
+
routeHandlers,
|
|
114
|
+
router: adminRouter
|
|
115
|
+
})
|
|
116
|
+
});
|
|
291
117
|
}
|
|
292
118
|
//#endregion
|
|
293
|
-
export {
|
|
119
|
+
export { createHandlers, createHotUpdaterHandlers };
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
const require_handlerErrors = require("./handlerErrors.cjs");
|
|
2
|
+
const require_handlerParameters = require("./handlerParameters.cjs");
|
|
3
|
+
//#region src/handlerBundleRoutes.ts
|
|
4
|
+
const BUNDLE_LIST_BOUNDS = {
|
|
5
|
+
defaultValue: 50,
|
|
6
|
+
maxValue: 100
|
|
7
|
+
};
|
|
8
|
+
const isChannelText = (value) => {
|
|
9
|
+
if (typeof value !== "string" || value.length === 0) return false;
|
|
10
|
+
let codePoints = 0;
|
|
11
|
+
for (const _codePoint of value) {
|
|
12
|
+
codePoints += 1;
|
|
13
|
+
if (codePoints > 255) return false;
|
|
14
|
+
}
|
|
15
|
+
return true;
|
|
16
|
+
};
|
|
17
|
+
const requireChannelInsertInput = (value) => {
|
|
18
|
+
if (!value || typeof value !== "object" || Array.isArray(value) || !("row" in value) || !value.row || typeof value.row !== "object" || Array.isArray(value.row) || !("id" in value.row) || !isChannelText(value.row.id) || !("name" in value.row) || !isChannelText(value.row.name) || !("onConflict" in value) || value.onConflict !== "returnExisting") throw new require_handlerErrors.HandlerBadRequestError("Invalid Channel insert payload");
|
|
19
|
+
return {
|
|
20
|
+
row: {
|
|
21
|
+
id: value.row.id,
|
|
22
|
+
name: value.row.name
|
|
23
|
+
},
|
|
24
|
+
onConflict: value.onConflict
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
const requireBundlePatchPayload = (payload, bundleId) => {
|
|
28
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload)) throw new require_handlerErrors.HandlerBadRequestError("Invalid bundle payload");
|
|
29
|
+
const bundlePatch = payload;
|
|
30
|
+
if (bundlePatch.id !== void 0 && bundlePatch.id !== bundleId) throw new require_handlerErrors.HandlerBadRequestError("Bundle id mismatch");
|
|
31
|
+
const { id: _ignoredId, ...rest } = bundlePatch;
|
|
32
|
+
return rest;
|
|
33
|
+
};
|
|
34
|
+
const createBundleRouteHandlers = () => ({
|
|
35
|
+
getBundle: async (params, _request, api) => {
|
|
36
|
+
const bundle = await api.getBundleById(require_handlerParameters.requireRouteParam(params, "id"));
|
|
37
|
+
if (!bundle) return new Response(JSON.stringify({ error: "Bundle not found" }), {
|
|
38
|
+
status: 404,
|
|
39
|
+
headers: { "Content-Type": "application/json" }
|
|
40
|
+
});
|
|
41
|
+
return new Response(JSON.stringify(bundle), {
|
|
42
|
+
status: 200,
|
|
43
|
+
headers: { "Content-Type": "application/json" }
|
|
44
|
+
});
|
|
45
|
+
},
|
|
46
|
+
getBundles: async (_params, request, api) => {
|
|
47
|
+
const url = new URL(request.url);
|
|
48
|
+
const platform = url.searchParams.get("platform");
|
|
49
|
+
const limit = require_handlerParameters.parsePositiveIntegerSearchParam(url, "limit", BUNDLE_LIST_BOUNDS);
|
|
50
|
+
const pageParam = url.searchParams.get("page");
|
|
51
|
+
const offset = url.searchParams.get("offset");
|
|
52
|
+
const after = url.searchParams.get("after") ?? void 0;
|
|
53
|
+
const before = url.searchParams.get("before") ?? void 0;
|
|
54
|
+
const orderDirection = url.searchParams.get("orderDirection");
|
|
55
|
+
const idEq = url.searchParams.get("idEq") ?? void 0;
|
|
56
|
+
const idGt = url.searchParams.get("idGt") ?? void 0;
|
|
57
|
+
const idGte = url.searchParams.get("idGte") ?? void 0;
|
|
58
|
+
const idLt = url.searchParams.get("idLt") ?? void 0;
|
|
59
|
+
const idLte = url.searchParams.get("idLte") ?? void 0;
|
|
60
|
+
const idIn = require_handlerParameters.parseStringArraySearchParam(url, "idIn");
|
|
61
|
+
const page = pageParam === null ? void 0 : Number.isSafeInteger(Number(pageParam)) && Number(pageParam) > 0 && Number.isSafeInteger((Number(pageParam) - 1) * limit) ? Number(pageParam) : null;
|
|
62
|
+
if (offset !== null) throw new require_handlerErrors.HandlerBadRequestError("The 'offset' query parameter has been removed. Use 'after' or 'before' cursor pagination instead.");
|
|
63
|
+
if (page === null) throw new require_handlerErrors.HandlerBadRequestError("The 'page' query parameter must be a positive integer.");
|
|
64
|
+
if (after !== void 0 && before !== void 0) throw new require_handlerErrors.HandlerBadRequestError("The 'after' and 'before' query parameters cannot be combined.");
|
|
65
|
+
if (page !== void 0 && (after !== void 0 || before !== void 0)) throw new require_handlerErrors.HandlerBadRequestError("The 'page' query parameter cannot be combined with 'after' or 'before'.");
|
|
66
|
+
if (platform !== null && !require_handlerParameters.isPlatform(platform)) throw new require_handlerErrors.HandlerBadRequestError(`Invalid platform: ${platform}. Expected 'ios' or 'android'.`);
|
|
67
|
+
if (orderDirection !== null && orderDirection !== "asc" && orderDirection !== "desc") throw new require_handlerErrors.HandlerBadRequestError("The 'orderDirection' query parameter must be 'asc' or 'desc'.");
|
|
68
|
+
const pagination = page === void 0 ? {
|
|
69
|
+
cursor: after !== void 0 ? { after } : before !== void 0 ? { before } : void 0,
|
|
70
|
+
page: void 0
|
|
71
|
+
} : {
|
|
72
|
+
cursor: void 0,
|
|
73
|
+
page
|
|
74
|
+
};
|
|
75
|
+
const result = await api.getBundles({
|
|
76
|
+
where: {
|
|
77
|
+
...platform && { platform },
|
|
78
|
+
...idEq || idGt || idGte || idLt || idLte || idIn?.length ? { id: {
|
|
79
|
+
...idEq && { eq: idEq },
|
|
80
|
+
...idGt && { gt: idGt },
|
|
81
|
+
...idGte && { gte: idGte },
|
|
82
|
+
...idLt && { lt: idLt },
|
|
83
|
+
...idLte && { lte: idLte },
|
|
84
|
+
...idIn?.length && { in: idIn }
|
|
85
|
+
} } : {}
|
|
86
|
+
},
|
|
87
|
+
limit,
|
|
88
|
+
...pagination,
|
|
89
|
+
...orderDirection && { orderBy: {
|
|
90
|
+
field: "id",
|
|
91
|
+
direction: orderDirection
|
|
92
|
+
} }
|
|
93
|
+
});
|
|
94
|
+
return new Response(JSON.stringify(result), {
|
|
95
|
+
status: 200,
|
|
96
|
+
headers: { "Content-Type": "application/json" }
|
|
97
|
+
});
|
|
98
|
+
},
|
|
99
|
+
createBundles: async (_params, request, api) => {
|
|
100
|
+
const body = await request.json();
|
|
101
|
+
const bundles = Array.isArray(body) ? body : [body];
|
|
102
|
+
if (api.insertBundles) await api.insertBundles(bundles);
|
|
103
|
+
else {
|
|
104
|
+
if (bundles.length > 1) throw new require_handlerErrors.HandlerBadRequestError("This server does not support atomic bundle batches");
|
|
105
|
+
const bundle = bundles[0];
|
|
106
|
+
if (bundle !== void 0) await api.insertBundle(bundle);
|
|
107
|
+
}
|
|
108
|
+
return new Response(JSON.stringify({ success: true }), {
|
|
109
|
+
status: 201,
|
|
110
|
+
headers: { "Content-Type": "application/json" }
|
|
111
|
+
});
|
|
112
|
+
},
|
|
113
|
+
updateBundle: async (params, request, api) => {
|
|
114
|
+
const bundleId = require_handlerParameters.requireRouteParam(params, "id");
|
|
115
|
+
const body = await request.json();
|
|
116
|
+
const payload = Array.isArray(body) ? body[0] : body;
|
|
117
|
+
await api.updateBundleById(bundleId, requireBundlePatchPayload(payload, bundleId));
|
|
118
|
+
return new Response(JSON.stringify({ success: true }), {
|
|
119
|
+
status: 200,
|
|
120
|
+
headers: { "Content-Type": "application/json" }
|
|
121
|
+
});
|
|
122
|
+
},
|
|
123
|
+
deleteBundle: async (params, _request, api) => {
|
|
124
|
+
await api.deleteBundleById(require_handlerParameters.requireRouteParam(params, "id"));
|
|
125
|
+
return new Response(JSON.stringify({ success: true }), {
|
|
126
|
+
status: 200,
|
|
127
|
+
headers: { "Content-Type": "application/json" }
|
|
128
|
+
});
|
|
129
|
+
},
|
|
130
|
+
getChannels: async (_params, _request, api) => {
|
|
131
|
+
const response = { data: { channels: await api.getChannels() } };
|
|
132
|
+
return new Response(JSON.stringify(response), {
|
|
133
|
+
status: 200,
|
|
134
|
+
headers: { "Content-Type": "application/json" }
|
|
135
|
+
});
|
|
136
|
+
},
|
|
137
|
+
createChannel: async (_params, request, api) => {
|
|
138
|
+
const result = await api.insertChannel(requireChannelInsertInput(await request.json()));
|
|
139
|
+
return new Response(JSON.stringify({ data: result }), {
|
|
140
|
+
status: result.inserted ? 201 : 200,
|
|
141
|
+
headers: { "Content-Type": "application/json" }
|
|
142
|
+
});
|
|
143
|
+
},
|
|
144
|
+
deleteChannel: async (params, _request, api) => {
|
|
145
|
+
const result = await api.deleteChannel({ id: require_handlerParameters.decodeMaybe(require_handlerParameters.requireRouteParam(params, "id")) ?? "" });
|
|
146
|
+
if (result.deleted) return new Response(null, { status: 204 });
|
|
147
|
+
const status = result.reason === "not_found" ? 404 : 409;
|
|
148
|
+
return new Response(JSON.stringify({ data: result }), {
|
|
149
|
+
status,
|
|
150
|
+
headers: { "Content-Type": "application/json" }
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
//#endregion
|
|
155
|
+
exports.createBundleRouteHandlers = createBundleRouteHandlers;
|