@hot-updater/server 0.27.1 → 0.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/dist/adapters/drizzle.cjs +7 -7
  2. package/dist/adapters/drizzle.mjs +2 -0
  3. package/dist/adapters/kysely.cjs +7 -7
  4. package/dist/adapters/kysely.mjs +2 -0
  5. package/dist/adapters/mongodb.cjs +7 -7
  6. package/dist/adapters/mongodb.mjs +2 -0
  7. package/dist/adapters/prisma.cjs +7 -7
  8. package/dist/adapters/prisma.mjs +2 -0
  9. package/dist/calculatePagination.cjs +1 -3
  10. package/dist/{calculatePagination.js → calculatePagination.mjs} +1 -2
  11. package/dist/db/index.cjs +24 -15
  12. package/dist/db/index.d.cts +12 -9
  13. package/dist/db/index.d.mts +30 -0
  14. package/dist/db/index.mjs +45 -0
  15. package/dist/db/ormCore.cjs +247 -138
  16. package/dist/db/ormCore.d.cts +35 -17
  17. package/dist/db/ormCore.d.mts +44 -0
  18. package/dist/db/ormCore.mjs +386 -0
  19. package/dist/db/pluginCore.cjs +145 -40
  20. package/dist/db/pluginCore.mjs +176 -0
  21. package/dist/db/types.cjs +1 -3
  22. package/dist/db/types.d.cts +14 -21
  23. package/dist/db/types.d.mts +24 -0
  24. package/dist/db/{types.js → types.mjs} +1 -2
  25. package/dist/handler.cjs +117 -48
  26. package/dist/handler.d.cts +28 -18
  27. package/dist/handler.d.mts +47 -0
  28. package/dist/handler.mjs +217 -0
  29. package/dist/index.cjs +5 -5
  30. package/dist/index.d.cts +3 -3
  31. package/dist/index.d.mts +5 -0
  32. package/dist/index.mjs +4 -0
  33. package/dist/internalRouter.cjs +54 -0
  34. package/dist/internalRouter.mjs +52 -0
  35. package/dist/node.cjs +2 -3
  36. package/dist/node.d.cts +0 -1
  37. package/dist/{node.d.ts → node.d.mts} +1 -2
  38. package/dist/{node.js → node.mjs} +1 -2
  39. package/dist/route.cjs +7 -0
  40. package/dist/route.mjs +7 -0
  41. package/dist/runtime.cjs +42 -0
  42. package/dist/runtime.d.cts +21 -0
  43. package/dist/runtime.d.mts +21 -0
  44. package/dist/runtime.mjs +40 -0
  45. package/dist/schema/v0_21_0.cjs +1 -5
  46. package/dist/schema/{v0_21_0.js → v0_21_0.mjs} +1 -3
  47. package/dist/schema/v0_29_0.cjs +24 -0
  48. package/dist/schema/v0_29_0.mjs +24 -0
  49. package/dist/types/{index.d.ts → index.d.mts} +1 -1
  50. package/package.json +18 -18
  51. package/src/db/index.spec.ts +64 -29
  52. package/src/db/index.ts +55 -35
  53. package/src/db/ormCore.ts +438 -210
  54. package/src/db/ormUpdateCheck.bench.ts +261 -0
  55. package/src/db/pluginCore.ts +298 -49
  56. package/src/db/pluginUpdateCheck.bench.ts +250 -0
  57. package/src/db/types.ts +52 -27
  58. package/src/{handler-standalone-integration.spec.ts → handler-standalone.integration.spec.ts} +106 -0
  59. package/src/handler.spec.ts +156 -0
  60. package/src/handler.ts +296 -77
  61. package/src/internalRouter.ts +104 -0
  62. package/src/route.ts +7 -0
  63. package/src/runtime.spec.ts +277 -0
  64. package/src/runtime.ts +121 -0
  65. package/src/schema/v0_29_0.ts +26 -0
  66. package/dist/_virtual/rolldown_runtime.cjs +0 -25
  67. package/dist/adapters/drizzle.js +0 -3
  68. package/dist/adapters/kysely.js +0 -3
  69. package/dist/adapters/mongodb.js +0 -3
  70. package/dist/adapters/prisma.js +0 -3
  71. package/dist/db/index.d.ts +0 -27
  72. package/dist/db/index.js +0 -36
  73. package/dist/db/ormCore.d.ts +0 -26
  74. package/dist/db/ormCore.js +0 -273
  75. package/dist/db/pluginCore.js +0 -69
  76. package/dist/db/types.d.ts +0 -31
  77. package/dist/handler.d.ts +0 -37
  78. package/dist/handler.js +0 -146
  79. package/dist/index.d.ts +0 -5
  80. package/dist/index.js +0 -5
  81. /package/dist/adapters/{drizzle.d.ts → drizzle.d.mts} +0 -0
  82. /package/dist/adapters/{kysely.d.ts → kysely.d.mts} +0 -0
  83. /package/dist/adapters/{mongodb.d.ts → mongodb.d.mts} +0 -0
  84. /package/dist/adapters/{prisma.d.ts → prisma.d.mts} +0 -0
@@ -0,0 +1,217 @@
1
+ import { addRoute, createRouter, findRoute } from "./internalRouter.mjs";
2
+ //#region src/handler.ts
3
+ var HandlerBadRequestError = class extends Error {
4
+ constructor(message) {
5
+ super(message);
6
+ this.name = "HandlerBadRequestError";
7
+ }
8
+ };
9
+ const handleVersion = async () => {
10
+ return new Response(JSON.stringify({ version: "0.29.0" }), {
11
+ status: 200,
12
+ headers: { "Content-Type": "application/json" }
13
+ });
14
+ };
15
+ const decodeMaybe = (value) => {
16
+ if (value === void 0) return void 0;
17
+ try {
18
+ return decodeURIComponent(value);
19
+ } catch {
20
+ return value;
21
+ }
22
+ };
23
+ const isPlatform = (value) => {
24
+ return value === "ios" || value === "android";
25
+ };
26
+ const requireRouteParam = (params, key) => {
27
+ const value = params[key];
28
+ if (!value) throw new HandlerBadRequestError(`Missing route parameter: ${key}`);
29
+ return value;
30
+ };
31
+ const requirePlatformParam = (params) => {
32
+ const platform = requireRouteParam(params, "platform");
33
+ if (!isPlatform(platform)) throw new HandlerBadRequestError(`Invalid platform: ${platform}. Expected 'ios' or 'android'.`);
34
+ return platform;
35
+ };
36
+ const requireBundlePatchPayload = (payload, bundleId) => {
37
+ if (!payload || typeof payload !== "object" || Array.isArray(payload)) throw new HandlerBadRequestError("Invalid bundle payload");
38
+ const bundlePatch = payload;
39
+ if (bundlePatch.id !== void 0 && bundlePatch.id !== bundleId) throw new HandlerBadRequestError("Bundle id mismatch");
40
+ const { id: _ignoredId, ...rest } = bundlePatch;
41
+ return rest;
42
+ };
43
+ const handleFingerprintUpdateWithCohort = async (params, _request, api, context) => {
44
+ const platform = requirePlatformParam(params);
45
+ const fingerprintHash = requireRouteParam(params, "fingerprintHash");
46
+ const channel = requireRouteParam(params, "channel");
47
+ const minBundleId = requireRouteParam(params, "minBundleId");
48
+ const bundleId = requireRouteParam(params, "bundleId");
49
+ const updateInfo = await api.getAppUpdateInfo({
50
+ _updateStrategy: "fingerprint",
51
+ platform,
52
+ fingerprintHash,
53
+ channel,
54
+ minBundleId,
55
+ bundleId,
56
+ cohort: decodeMaybe(params.cohort)
57
+ }, context);
58
+ return new Response(JSON.stringify(updateInfo), {
59
+ status: 200,
60
+ headers: { "Content-Type": "application/json" }
61
+ });
62
+ };
63
+ const handleAppVersionUpdateWithCohort = async (params, _request, api, context) => {
64
+ const platform = requirePlatformParam(params);
65
+ const appVersion = requireRouteParam(params, "appVersion");
66
+ const channel = requireRouteParam(params, "channel");
67
+ const minBundleId = requireRouteParam(params, "minBundleId");
68
+ const bundleId = requireRouteParam(params, "bundleId");
69
+ const updateInfo = await api.getAppUpdateInfo({
70
+ _updateStrategy: "appVersion",
71
+ platform,
72
+ appVersion,
73
+ channel,
74
+ minBundleId,
75
+ bundleId,
76
+ cohort: decodeMaybe(params.cohort)
77
+ }, context);
78
+ return new Response(JSON.stringify(updateInfo), {
79
+ status: 200,
80
+ headers: { "Content-Type": "application/json" }
81
+ });
82
+ };
83
+ const handleGetBundle = async (params, _request, api, context) => {
84
+ const bundleId = requireRouteParam(params, "id");
85
+ const bundle = await api.getBundleById(bundleId, context);
86
+ if (!bundle) return new Response(JSON.stringify({ error: "Bundle not found" }), {
87
+ status: 404,
88
+ headers: { "Content-Type": "application/json" }
89
+ });
90
+ return new Response(JSON.stringify(bundle), {
91
+ status: 200,
92
+ headers: { "Content-Type": "application/json" }
93
+ });
94
+ };
95
+ const handleGetBundles = async (_params, request, api, context) => {
96
+ const url = new URL(request.url);
97
+ const channel = url.searchParams.get("channel") ?? void 0;
98
+ const platform = url.searchParams.get("platform");
99
+ const limit = Number(url.searchParams.get("limit")) || 50;
100
+ const offset = Number(url.searchParams.get("offset")) || 0;
101
+ if (platform !== null && !isPlatform(platform)) throw new HandlerBadRequestError(`Invalid platform: ${platform}. Expected 'ios' or 'android'.`);
102
+ const result = await api.getBundles({
103
+ where: {
104
+ ...channel && { channel },
105
+ ...platform && { platform }
106
+ },
107
+ limit,
108
+ offset
109
+ }, context);
110
+ return new Response(JSON.stringify(result.data), {
111
+ status: 200,
112
+ headers: { "Content-Type": "application/json" }
113
+ });
114
+ };
115
+ const handleCreateBundles = async (_params, request, api, context) => {
116
+ const body = await request.json();
117
+ const bundles = Array.isArray(body) ? body : [body];
118
+ for (const bundle of bundles) await api.insertBundle(bundle, context);
119
+ return new Response(JSON.stringify({ success: true }), {
120
+ status: 201,
121
+ headers: { "Content-Type": "application/json" }
122
+ });
123
+ };
124
+ const handleUpdateBundle = async (params, request, api, context) => {
125
+ const bundleId = requireRouteParam(params, "id");
126
+ const body = await request.json();
127
+ const bundlePatch = requireBundlePatchPayload(Array.isArray(body) ? body[0] : body, bundleId);
128
+ await api.updateBundleById(bundleId, bundlePatch, context);
129
+ return new Response(JSON.stringify({ success: true }), {
130
+ status: 200,
131
+ headers: { "Content-Type": "application/json" }
132
+ });
133
+ };
134
+ const handleDeleteBundle = async (params, _request, api, context) => {
135
+ const bundleId = requireRouteParam(params, "id");
136
+ await api.deleteBundleById(bundleId, context);
137
+ return new Response(JSON.stringify({ success: true }), {
138
+ status: 200,
139
+ headers: { "Content-Type": "application/json" }
140
+ });
141
+ };
142
+ const handleGetChannels = async (_params, _request, api, context) => {
143
+ const channels = await api.getChannels(context);
144
+ return new Response(JSON.stringify({ channels }), {
145
+ status: 200,
146
+ headers: { "Content-Type": "application/json" }
147
+ });
148
+ };
149
+ const routes = {
150
+ version: handleVersion,
151
+ fingerprintUpdateWithCohort: handleFingerprintUpdateWithCohort,
152
+ appVersionUpdateWithCohort: handleAppVersionUpdateWithCohort,
153
+ getBundle: handleGetBundle,
154
+ getBundles: handleGetBundles,
155
+ createBundles: handleCreateBundles,
156
+ updateBundle: handleUpdateBundle,
157
+ deleteBundle: handleDeleteBundle,
158
+ getChannels: handleGetChannels
159
+ };
160
+ /**
161
+ * Creates a Web Standard Request handler for Hot Updater API
162
+ * This handler is framework-agnostic and works with any runtime that
163
+ * supports standard Request/Response objects.
164
+ */
165
+ function createHandler(api, options = {}) {
166
+ const basePath = options.basePath ?? "/api";
167
+ const updateCheckEnabled = options.routes?.updateCheck ?? true;
168
+ const bundlesEnabled = options.routes?.bundles ?? true;
169
+ const router = createRouter();
170
+ if (updateCheckEnabled) {
171
+ addRoute(router, "GET", "/fingerprint/:platform/:fingerprintHash/:channel/:minBundleId/:bundleId", "fingerprintUpdateWithCohort");
172
+ addRoute(router, "GET", "/fingerprint/:platform/:fingerprintHash/:channel/:minBundleId/:bundleId/:cohort", "fingerprintUpdateWithCohort");
173
+ addRoute(router, "GET", "/app-version/:platform/:appVersion/:channel/:minBundleId/:bundleId", "appVersionUpdateWithCohort");
174
+ addRoute(router, "GET", "/app-version/:platform/:appVersion/:channel/:minBundleId/:bundleId/:cohort", "appVersionUpdateWithCohort");
175
+ }
176
+ if (bundlesEnabled) {
177
+ addRoute(router, "GET", "/version", "version");
178
+ addRoute(router, "GET", "/api/bundles/channels", "getChannels");
179
+ addRoute(router, "GET", "/api/bundles/:id", "getBundle");
180
+ addRoute(router, "GET", "/api/bundles", "getBundles");
181
+ addRoute(router, "POST", "/api/bundles", "createBundles");
182
+ addRoute(router, "PATCH", "/api/bundles/:id", "updateBundle");
183
+ addRoute(router, "DELETE", "/api/bundles/:id", "deleteBundle");
184
+ }
185
+ return async (request, context) => {
186
+ try {
187
+ const path = new URL(request.url).pathname;
188
+ const method = request.method;
189
+ const match = findRoute(router, method, path.startsWith(basePath) ? path.slice(basePath.length) : path);
190
+ if (!match) return new Response(JSON.stringify({ error: "Not found" }), {
191
+ status: 404,
192
+ headers: { "Content-Type": "application/json" }
193
+ });
194
+ const handler = routes[match.data];
195
+ if (!handler) return new Response(JSON.stringify({ error: "Handler not found" }), {
196
+ status: 500,
197
+ headers: { "Content-Type": "application/json" }
198
+ });
199
+ return await handler(match.params || {}, request, api, context);
200
+ } catch (error) {
201
+ if (error instanceof HandlerBadRequestError) return new Response(JSON.stringify({ error: error.message }), {
202
+ status: 400,
203
+ headers: { "Content-Type": "application/json" }
204
+ });
205
+ console.error("Hot Updater handler error:", error);
206
+ return new Response(JSON.stringify({
207
+ error: "Internal server error",
208
+ message: error instanceof Error ? error.message : "Unknown error"
209
+ }), {
210
+ status: 500,
211
+ headers: { "Content-Type": "application/json" }
212
+ });
213
+ }
214
+ };
215
+ }
216
+ //#endregion
217
+ export { createHandler };
package/dist/index.cjs CHANGED
@@ -1,7 +1,7 @@
1
- const require_handler = require('./handler.cjs');
2
- const require_ormCore = require('./db/ormCore.cjs');
3
- const require_index = require('./db/index.cjs');
4
-
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_handler = require("./handler.cjs");
3
+ const require_ormCore = require("./db/ormCore.cjs");
4
+ const require_index = require("./db/index.cjs");
5
5
  exports.HotUpdaterDB = require_ormCore.HotUpdaterDB;
6
6
  exports.createHandler = require_handler.createHandler;
7
- exports.createHotUpdater = require_index.createHotUpdater;
7
+ exports.createHotUpdater = require_index.createHotUpdater;
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Bundle, PaginatedResult, PaginationInfo, PaginationOptions } from "./types/index.cjs";
2
+ import { HandlerAPI, HandlerOptions, HandlerRoutes, createHandler } from "./handler.cjs";
2
3
  import { HotUpdaterClient, HotUpdaterDB, Migrator } from "./db/ormCore.cjs";
3
- import { HotUpdaterAPI, createHotUpdater } from "./db/index.cjs";
4
- import { HandlerAPI, HandlerOptions, createHandler } from "./handler.cjs";
5
- export { Bundle, HandlerAPI, HandlerOptions, HotUpdaterAPI, HotUpdaterClient, HotUpdaterDB, Migrator, PaginatedResult, PaginationInfo, PaginationOptions, createHandler, createHotUpdater };
4
+ import { CreateHotUpdaterOptions, HotUpdaterAPI, createHotUpdater } from "./db/index.cjs";
5
+ export { Bundle, CreateHotUpdaterOptions, HandlerAPI, HandlerOptions, HandlerRoutes, HotUpdaterAPI, HotUpdaterClient, HotUpdaterDB, Migrator, PaginatedResult, PaginationInfo, PaginationOptions, createHandler, createHotUpdater };
@@ -0,0 +1,5 @@
1
+ import { Bundle, PaginatedResult, PaginationInfo, PaginationOptions } from "./types/index.mjs";
2
+ import { HandlerAPI, HandlerOptions, HandlerRoutes, createHandler } from "./handler.mjs";
3
+ import { HotUpdaterClient, HotUpdaterDB, Migrator } from "./db/ormCore.mjs";
4
+ import { CreateHotUpdaterOptions, HotUpdaterAPI, createHotUpdater } from "./db/index.mjs";
5
+ export { Bundle, CreateHotUpdaterOptions, HandlerAPI, HandlerOptions, HandlerRoutes, HotUpdaterAPI, HotUpdaterClient, HotUpdaterDB, Migrator, PaginatedResult, PaginationInfo, PaginationOptions, createHandler, createHotUpdater };
package/dist/index.mjs ADDED
@@ -0,0 +1,4 @@
1
+ import { createHandler } from "./handler.mjs";
2
+ import { HotUpdaterDB } from "./db/ormCore.mjs";
3
+ import { createHotUpdater } from "./db/index.mjs";
4
+ export { HotUpdaterDB, createHandler, createHotUpdater };
@@ -0,0 +1,54 @@
1
+ //#region src/internalRouter.ts
2
+ const normalizePath = (path) => {
3
+ if (!path) return "/";
4
+ if (path === "/") return path;
5
+ const withLeadingSlash = path.startsWith("/") ? path : `/${path}`;
6
+ return withLeadingSlash.endsWith("/") ? withLeadingSlash.slice(0, -1) : withLeadingSlash;
7
+ };
8
+ const toSegments = (path) => {
9
+ const normalized = normalizePath(path);
10
+ return normalized === "/" ? [] : normalized.slice(1).split("/");
11
+ };
12
+ function createRouter() {
13
+ return { routes: [] };
14
+ }
15
+ function addRoute(router, method, path, data) {
16
+ const segments = toSegments(path);
17
+ const paramNames = segments.filter((segment) => segment.startsWith(":")).map((segment) => segment.slice(1));
18
+ router.routes.push({
19
+ data,
20
+ method: method.toUpperCase(),
21
+ paramNames,
22
+ segments
23
+ });
24
+ }
25
+ function findRoute(router, method, path) {
26
+ const normalizedMethod = method.toUpperCase();
27
+ const pathSegments = toSegments(path);
28
+ for (const route of router.routes) {
29
+ if (route.method !== normalizedMethod) continue;
30
+ if (route.segments.length !== pathSegments.length) continue;
31
+ const params = {};
32
+ let matched = true;
33
+ for (let index = 0; index < route.segments.length; index += 1) {
34
+ const routeSegment = route.segments[index];
35
+ const pathSegment = pathSegments[index];
36
+ if (routeSegment.startsWith(":")) {
37
+ params[routeSegment.slice(1)] = pathSegment;
38
+ continue;
39
+ }
40
+ if (routeSegment !== pathSegment) {
41
+ matched = false;
42
+ break;
43
+ }
44
+ }
45
+ if (matched) return {
46
+ data: route.data,
47
+ params
48
+ };
49
+ }
50
+ }
51
+ //#endregion
52
+ exports.addRoute = addRoute;
53
+ exports.createRouter = createRouter;
54
+ exports.findRoute = findRoute;
@@ -0,0 +1,52 @@
1
+ //#region src/internalRouter.ts
2
+ const normalizePath = (path) => {
3
+ if (!path) return "/";
4
+ if (path === "/") return path;
5
+ const withLeadingSlash = path.startsWith("/") ? path : `/${path}`;
6
+ return withLeadingSlash.endsWith("/") ? withLeadingSlash.slice(0, -1) : withLeadingSlash;
7
+ };
8
+ const toSegments = (path) => {
9
+ const normalized = normalizePath(path);
10
+ return normalized === "/" ? [] : normalized.slice(1).split("/");
11
+ };
12
+ function createRouter() {
13
+ return { routes: [] };
14
+ }
15
+ function addRoute(router, method, path, data) {
16
+ const segments = toSegments(path);
17
+ const paramNames = segments.filter((segment) => segment.startsWith(":")).map((segment) => segment.slice(1));
18
+ router.routes.push({
19
+ data,
20
+ method: method.toUpperCase(),
21
+ paramNames,
22
+ segments
23
+ });
24
+ }
25
+ function findRoute(router, method, path) {
26
+ const normalizedMethod = method.toUpperCase();
27
+ const pathSegments = toSegments(path);
28
+ for (const route of router.routes) {
29
+ if (route.method !== normalizedMethod) continue;
30
+ if (route.segments.length !== pathSegments.length) continue;
31
+ const params = {};
32
+ let matched = true;
33
+ for (let index = 0; index < route.segments.length; index += 1) {
34
+ const routeSegment = route.segments[index];
35
+ const pathSegment = pathSegments[index];
36
+ if (routeSegment.startsWith(":")) {
37
+ params[routeSegment.slice(1)] = pathSegment;
38
+ continue;
39
+ }
40
+ if (routeSegment !== pathSegment) {
41
+ matched = false;
42
+ break;
43
+ }
44
+ }
45
+ if (matched) return {
46
+ data: route.data,
47
+ params
48
+ };
49
+ }
50
+ }
51
+ //#endregion
52
+ export { addRoute, createRouter, findRoute };
package/dist/node.cjs CHANGED
@@ -1,4 +1,4 @@
1
-
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  //#region src/node.ts
3
3
  /**
4
4
  * Converts a Hot Updater handler to a Node.js-compatible middleware
@@ -46,6 +46,5 @@ function toNodeHandler(hotUpdater) {
46
46
  }
47
47
  };
48
48
  }
49
-
50
49
  //#endregion
51
- exports.toNodeHandler = toNodeHandler;
50
+ exports.toNodeHandler = toNodeHandler;
package/dist/node.d.cts CHANGED
@@ -1,7 +1,6 @@
1
1
  import { HotUpdaterAPI } from "./db/index.cjs";
2
2
 
3
3
  //#region src/node.d.ts
4
-
5
4
  /**
6
5
  * Converts a Hot Updater handler to a Node.js-compatible middleware
7
6
  * Works with Express, Connect, and other frameworks using Node.js req/res
@@ -1,7 +1,6 @@
1
- import { HotUpdaterAPI } from "./db/index.js";
1
+ import { HotUpdaterAPI } from "./db/index.mjs";
2
2
 
3
3
  //#region src/node.d.ts
4
-
5
4
  /**
6
5
  * Converts a Hot Updater handler to a Node.js-compatible middleware
7
6
  * Works with Express, Connect, and other frameworks using Node.js req/res
@@ -45,6 +45,5 @@ function toNodeHandler(hotUpdater) {
45
45
  }
46
46
  };
47
47
  }
48
-
49
48
  //#endregion
50
- export { toNodeHandler };
49
+ export { toNodeHandler };
package/dist/route.cjs ADDED
@@ -0,0 +1,7 @@
1
+ //#region src/route.ts
2
+ const normalizeBasePath = (basePath) => {
3
+ if (!basePath || basePath === "/") return "/";
4
+ return basePath.endsWith("/") ? basePath.slice(0, -1) : basePath;
5
+ };
6
+ //#endregion
7
+ exports.normalizeBasePath = normalizeBasePath;
package/dist/route.mjs ADDED
@@ -0,0 +1,7 @@
1
+ //#region src/route.ts
2
+ const normalizeBasePath = (basePath) => {
3
+ if (!basePath || basePath === "/") return "/";
4
+ return basePath.endsWith("/") ? basePath.slice(0, -1) : basePath;
5
+ };
6
+ //#endregion
7
+ export { normalizeBasePath };
@@ -0,0 +1,42 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_handler = require("./handler.cjs");
3
+ const require_route = require("./route.cjs");
4
+ const require_pluginCore = require("./db/pluginCore.cjs");
5
+ const require_types = require("./db/types.cjs");
6
+ //#region src/runtime.ts
7
+ function createHotUpdater(options) {
8
+ const basePath = require_route.normalizeBasePath(options.basePath ?? "/api");
9
+ const storagePlugins = (options.storages ?? options.storagePlugins ?? []).map((plugin) => typeof plugin === "function" ? plugin() : plugin);
10
+ const resolveStoragePluginUrl = async (storageUri, context) => {
11
+ if (!storageUri) return null;
12
+ const protocol = new URL(storageUri).protocol.replace(":", "");
13
+ if (protocol === "http" || protocol === "https") return storageUri;
14
+ const plugin = storagePlugins.find((item) => item.supportedProtocol === protocol);
15
+ if (!plugin) throw new Error(`No storage plugin for protocol: ${protocol}`);
16
+ const { fileUrl } = await plugin.getDownloadUrl(storageUri, context);
17
+ if (!fileUrl) throw new Error("Storage plugin returned empty fileUrl");
18
+ return fileUrl;
19
+ };
20
+ if (!require_types.isDatabasePluginFactory(options.database) && !require_types.isDatabasePlugin(options.database)) throw new Error("@hot-updater/server/runtime only supports database plugins.");
21
+ const core = require_pluginCore.createPluginDatabaseCore(require_types.isDatabasePluginFactory(options.database) ? options.database() : options.database, resolveStoragePluginUrl);
22
+ const api = {
23
+ ...core.api,
24
+ handler: require_handler.createHandler(core.api, {
25
+ basePath,
26
+ routes: options.routes
27
+ }),
28
+ adapterName: core.adapterName
29
+ };
30
+ const handler = (request, context, ...extraArgs) => {
31
+ if (extraArgs.length > 0) return api.handler(request);
32
+ return api.handler(request, context);
33
+ };
34
+ return {
35
+ ...api,
36
+ basePath,
37
+ handler
38
+ };
39
+ }
40
+ //#endregion
41
+ exports.createHandler = require_handler.createHandler;
42
+ exports.createHotUpdater = createHotUpdater;
@@ -0,0 +1,21 @@
1
+ import { HandlerRoutes, createHandler } from "./handler.cjs";
2
+ import { DatabaseAPI, DatabaseAdapter, StoragePluginFactory } from "./db/types.cjs";
3
+ import { HotUpdaterContext, StoragePlugin } from "@hot-updater/plugin-core";
4
+
5
+ //#region src/runtime.d.ts
6
+ type HotUpdaterAPI<TContext = unknown> = DatabaseAPI<TContext> & {
7
+ basePath: string;
8
+ handler: (request: Request, context?: HotUpdaterContext<TContext>) => Promise<Response>;
9
+ adapterName: string;
10
+ };
11
+ interface CreateHotUpdaterOptions<TContext = unknown> {
12
+ database: DatabaseAdapter<TContext>;
13
+ storages?: (StoragePlugin<TContext> | StoragePluginFactory<TContext>)[];
14
+ storagePlugins?: (StoragePlugin<TContext> | StoragePluginFactory<TContext>)[];
15
+ basePath?: string;
16
+ cwd?: string;
17
+ routes?: HandlerRoutes;
18
+ }
19
+ declare function createHotUpdater<TContext = unknown>(options: CreateHotUpdaterOptions<TContext>): HotUpdaterAPI<TContext>;
20
+ //#endregion
21
+ export { CreateHotUpdaterOptions, HotUpdaterAPI, createHandler, createHotUpdater };
@@ -0,0 +1,21 @@
1
+ import { HandlerRoutes, createHandler } from "./handler.mjs";
2
+ import { DatabaseAPI, DatabaseAdapter, StoragePluginFactory } from "./db/types.mjs";
3
+ import { HotUpdaterContext, StoragePlugin } from "@hot-updater/plugin-core";
4
+
5
+ //#region src/runtime.d.ts
6
+ type HotUpdaterAPI<TContext = unknown> = DatabaseAPI<TContext> & {
7
+ basePath: string;
8
+ handler: (request: Request, context?: HotUpdaterContext<TContext>) => Promise<Response>;
9
+ adapterName: string;
10
+ };
11
+ interface CreateHotUpdaterOptions<TContext = unknown> {
12
+ database: DatabaseAdapter<TContext>;
13
+ storages?: (StoragePlugin<TContext> | StoragePluginFactory<TContext>)[];
14
+ storagePlugins?: (StoragePlugin<TContext> | StoragePluginFactory<TContext>)[];
15
+ basePath?: string;
16
+ cwd?: string;
17
+ routes?: HandlerRoutes;
18
+ }
19
+ declare function createHotUpdater<TContext = unknown>(options: CreateHotUpdaterOptions<TContext>): HotUpdaterAPI<TContext>;
20
+ //#endregion
21
+ export { CreateHotUpdaterOptions, HotUpdaterAPI, createHandler, createHotUpdater };
@@ -0,0 +1,40 @@
1
+ import { createHandler } from "./handler.mjs";
2
+ import { normalizeBasePath } from "./route.mjs";
3
+ import { createPluginDatabaseCore } from "./db/pluginCore.mjs";
4
+ import { isDatabasePlugin, isDatabasePluginFactory } from "./db/types.mjs";
5
+ //#region src/runtime.ts
6
+ function createHotUpdater(options) {
7
+ const basePath = normalizeBasePath(options.basePath ?? "/api");
8
+ const storagePlugins = (options.storages ?? options.storagePlugins ?? []).map((plugin) => typeof plugin === "function" ? plugin() : plugin);
9
+ const resolveStoragePluginUrl = async (storageUri, context) => {
10
+ if (!storageUri) return null;
11
+ const protocol = new URL(storageUri).protocol.replace(":", "");
12
+ if (protocol === "http" || protocol === "https") return storageUri;
13
+ const plugin = storagePlugins.find((item) => item.supportedProtocol === protocol);
14
+ if (!plugin) throw new Error(`No storage plugin for protocol: ${protocol}`);
15
+ const { fileUrl } = await plugin.getDownloadUrl(storageUri, context);
16
+ if (!fileUrl) throw new Error("Storage plugin returned empty fileUrl");
17
+ return fileUrl;
18
+ };
19
+ if (!isDatabasePluginFactory(options.database) && !isDatabasePlugin(options.database)) throw new Error("@hot-updater/server/runtime only supports database plugins.");
20
+ const core = createPluginDatabaseCore(isDatabasePluginFactory(options.database) ? options.database() : options.database, resolveStoragePluginUrl);
21
+ const api = {
22
+ ...core.api,
23
+ handler: createHandler(core.api, {
24
+ basePath,
25
+ routes: options.routes
26
+ }),
27
+ adapterName: core.adapterName
28
+ };
29
+ const handler = (request, context, ...extraArgs) => {
30
+ if (extraArgs.length > 0) return api.handler(request);
31
+ return api.handler(request, context);
32
+ };
33
+ return {
34
+ ...api,
35
+ basePath,
36
+ handler
37
+ };
38
+ }
39
+ //#endregion
40
+ export { createHandler, createHotUpdater };
@@ -1,7 +1,4 @@
1
- const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
2
1
  let fumadb_schema = require("fumadb/schema");
3
- fumadb_schema = require_rolldown_runtime.__toESM(fumadb_schema);
4
-
5
2
  //#region src/schema/v0_21_0.ts
6
3
  const v0_21_0 = (0, fumadb_schema.schema)({
7
4
  version: "0.21.0",
@@ -21,6 +18,5 @@ const v0_21_0 = (0, fumadb_schema.schema)({
21
18
  }) },
22
19
  relations: {}
23
20
  });
24
-
25
21
  //#endregion
26
- exports.v0_21_0 = v0_21_0;
22
+ exports.v0_21_0 = v0_21_0;
@@ -1,5 +1,4 @@
1
1
  import { column, idColumn, schema, table } from "fumadb/schema";
2
-
3
2
  //#region src/schema/v0_21_0.ts
4
3
  const v0_21_0 = schema({
5
4
  version: "0.21.0",
@@ -19,6 +18,5 @@ const v0_21_0 = schema({
19
18
  }) },
20
19
  relations: {}
21
20
  });
22
-
23
21
  //#endregion
24
- export { v0_21_0 };
22
+ export { v0_21_0 };
@@ -0,0 +1,24 @@
1
+ let fumadb_schema = require("fumadb/schema");
2
+ //#region src/schema/v0_29_0.ts
3
+ const v0_29_0 = (0, fumadb_schema.schema)({
4
+ version: "0.29.0",
5
+ tables: { bundles: (0, fumadb_schema.table)("bundles", {
6
+ id: (0, fumadb_schema.idColumn)("id", "uuid"),
7
+ platform: (0, fumadb_schema.column)("platform", "string"),
8
+ should_force_update: (0, fumadb_schema.column)("should_force_update", "bool"),
9
+ enabled: (0, fumadb_schema.column)("enabled", "bool"),
10
+ file_hash: (0, fumadb_schema.column)("file_hash", "string"),
11
+ git_commit_hash: (0, fumadb_schema.column)("git_commit_hash", "string").nullable(),
12
+ message: (0, fumadb_schema.column)("message", "string").nullable(),
13
+ channel: (0, fumadb_schema.column)("channel", "string"),
14
+ storage_uri: (0, fumadb_schema.column)("storage_uri", "string"),
15
+ target_app_version: (0, fumadb_schema.column)("target_app_version", "string").nullable(),
16
+ fingerprint_hash: (0, fumadb_schema.column)("fingerprint_hash", "string").nullable(),
17
+ metadata: (0, fumadb_schema.column)("metadata", "json"),
18
+ rollout_cohort_count: (0, fumadb_schema.column)("rollout_cohort_count", "integer").defaultTo(1e3),
19
+ target_cohorts: (0, fumadb_schema.column)("target_cohorts", "json").nullable()
20
+ }) },
21
+ relations: {}
22
+ });
23
+ //#endregion
24
+ exports.v0_29_0 = v0_29_0;
@@ -0,0 +1,24 @@
1
+ import { column, idColumn, schema, table } from "fumadb/schema";
2
+ //#region src/schema/v0_29_0.ts
3
+ const v0_29_0 = schema({
4
+ version: "0.29.0",
5
+ tables: { bundles: table("bundles", {
6
+ id: idColumn("id", "uuid"),
7
+ platform: column("platform", "string"),
8
+ should_force_update: column("should_force_update", "bool"),
9
+ enabled: column("enabled", "bool"),
10
+ file_hash: column("file_hash", "string"),
11
+ git_commit_hash: column("git_commit_hash", "string").nullable(),
12
+ message: column("message", "string").nullable(),
13
+ channel: column("channel", "string"),
14
+ storage_uri: column("storage_uri", "string"),
15
+ target_app_version: column("target_app_version", "string").nullable(),
16
+ fingerprint_hash: column("fingerprint_hash", "string").nullable(),
17
+ metadata: column("metadata", "json"),
18
+ rollout_cohort_count: column("rollout_cohort_count", "integer").defaultTo(1e3),
19
+ target_cohorts: column("target_cohorts", "json").nullable()
20
+ }) },
21
+ relations: {}
22
+ });
23
+ //#endregion
24
+ export { v0_29_0 };
@@ -1,4 +1,4 @@
1
- import { HotUpdaterAPI } from "../db/index.js";
1
+ import { HotUpdaterAPI } from "../db/index.mjs";
2
2
  import { Bundle, Bundle as Bundle$1 } from "@hot-updater/core";
3
3
 
4
4
  //#region src/types/index.d.ts