@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
@@ -1,273 +0,0 @@
1
- import { calculatePagination } from "../calculatePagination.js";
2
- import { v0_21_0 } from "../schema/v0_21_0.js";
3
- import { NIL_UUID } from "@hot-updater/core";
4
- import { filterCompatibleAppVersions } from "@hot-updater/plugin-core";
5
- import { fumadb } from "fumadb";
6
-
7
- //#region src/db/ormCore.ts
8
- const HotUpdaterDB = fumadb({
9
- namespace: "hot_updater",
10
- schemas: [v0_21_0]
11
- });
12
- function createOrmDatabaseCore({ database, resolveFileUrl }) {
13
- const client = HotUpdaterDB.client(database);
14
- return {
15
- api: {
16
- async getBundleById(id) {
17
- const version = await client.version();
18
- const result = await client.orm(version).findFirst("bundles", {
19
- select: [
20
- "id",
21
- "platform",
22
- "should_force_update",
23
- "enabled",
24
- "file_hash",
25
- "git_commit_hash",
26
- "message",
27
- "channel",
28
- "storage_uri",
29
- "target_app_version",
30
- "fingerprint_hash",
31
- "metadata"
32
- ],
33
- where: (b) => b("id", "=", id)
34
- });
35
- if (!result) return null;
36
- return {
37
- id: result.id,
38
- platform: result.platform,
39
- shouldForceUpdate: Boolean(result.should_force_update),
40
- enabled: Boolean(result.enabled),
41
- fileHash: result.file_hash,
42
- gitCommitHash: result.git_commit_hash ?? null,
43
- message: result.message ?? null,
44
- channel: result.channel,
45
- storageUri: result.storage_uri,
46
- targetAppVersion: result.target_app_version ?? null,
47
- fingerprintHash: result.fingerprint_hash ?? null
48
- };
49
- },
50
- async getUpdateInfo(args) {
51
- const version = await client.version();
52
- const orm = client.orm(version);
53
- const toUpdateInfo = (row, status) => ({
54
- id: row.id,
55
- shouldForceUpdate: status === "ROLLBACK" ? true : Boolean(row.should_force_update),
56
- message: row.message ?? null,
57
- status,
58
- storageUri: row.storage_uri ?? null,
59
- fileHash: row.file_hash ?? null
60
- });
61
- const INIT_BUNDLE_ROLLBACK_UPDATE_INFO = {
62
- id: NIL_UUID,
63
- message: null,
64
- shouldForceUpdate: true,
65
- status: "ROLLBACK",
66
- storageUri: null,
67
- fileHash: null
68
- };
69
- const appVersionStrategy = async ({ platform, appVersion, bundleId, minBundleId = NIL_UUID, channel = "production" }) => {
70
- const versionRows = await orm.findMany("bundles", {
71
- select: ["target_app_version"],
72
- where: (b) => b.and(b("platform", "=", platform))
73
- });
74
- const compatibleVersions = filterCompatibleAppVersions(Array.from(new Set((versionRows ?? []).map((r) => r.target_app_version).filter((v) => Boolean(v)))), appVersion);
75
- const candidates = ((compatibleVersions.length === 0 ? [] : await orm.findMany("bundles", {
76
- select: [
77
- "id",
78
- "should_force_update",
79
- "message",
80
- "storage_uri",
81
- "file_hash",
82
- "channel",
83
- "target_app_version",
84
- "enabled"
85
- ],
86
- where: (b) => b.and(b("enabled", "=", true), b("platform", "=", platform), b("id", ">=", minBundleId ?? NIL_UUID), b("channel", "=", channel), b.isNotNull("target_app_version"))
87
- })) ?? []).filter((r) => r.target_app_version ? compatibleVersions.includes(r.target_app_version) : false);
88
- const byIdDesc = (a, b) => b.id.localeCompare(a.id);
89
- const sorted = (candidates ?? []).slice().sort(byIdDesc);
90
- const latestCandidate = sorted[0] ?? null;
91
- const currentBundle = sorted.find((b) => b.id === bundleId);
92
- const updateCandidate = sorted.find((b) => b.id.localeCompare(bundleId) > 0) ?? null;
93
- const rollbackCandidate = sorted.find((b) => b.id.localeCompare(bundleId) < 0) ?? null;
94
- if (bundleId === NIL_UUID) {
95
- if (latestCandidate && latestCandidate.id !== bundleId) return toUpdateInfo(latestCandidate, "UPDATE");
96
- return null;
97
- }
98
- if (currentBundle) {
99
- if (latestCandidate && latestCandidate.id.localeCompare(currentBundle.id) > 0) return toUpdateInfo(latestCandidate, "UPDATE");
100
- return null;
101
- }
102
- if (updateCandidate) return toUpdateInfo(updateCandidate, "UPDATE");
103
- if (rollbackCandidate) return toUpdateInfo(rollbackCandidate, "ROLLBACK");
104
- if (minBundleId && bundleId.localeCompare(minBundleId) <= 0) return null;
105
- return INIT_BUNDLE_ROLLBACK_UPDATE_INFO;
106
- };
107
- const fingerprintStrategy = async ({ platform, fingerprintHash, bundleId, minBundleId = NIL_UUID, channel = "production" }) => {
108
- const candidates = await orm.findMany("bundles", {
109
- select: [
110
- "id",
111
- "should_force_update",
112
- "message",
113
- "storage_uri",
114
- "file_hash",
115
- "channel",
116
- "fingerprint_hash",
117
- "enabled"
118
- ],
119
- where: (b) => b.and(b("enabled", "=", true), b("platform", "=", platform), b("id", ">=", minBundleId ?? NIL_UUID), b("channel", "=", channel), b("fingerprint_hash", "=", fingerprintHash))
120
- });
121
- const byIdDesc = (a, b) => b.id.localeCompare(a.id);
122
- const sorted = (candidates ?? []).slice().sort(byIdDesc);
123
- const latestCandidate = sorted[0] ?? null;
124
- const currentBundle = sorted.find((b) => b.id === bundleId);
125
- const updateCandidate = sorted.find((b) => b.id.localeCompare(bundleId) > 0) ?? null;
126
- const rollbackCandidate = sorted.find((b) => b.id.localeCompare(bundleId) < 0) ?? null;
127
- if (bundleId === NIL_UUID) {
128
- if (latestCandidate && latestCandidate.id !== bundleId) return toUpdateInfo(latestCandidate, "UPDATE");
129
- return null;
130
- }
131
- if (currentBundle) {
132
- if (latestCandidate && latestCandidate.id.localeCompare(currentBundle.id) > 0) return toUpdateInfo(latestCandidate, "UPDATE");
133
- return null;
134
- }
135
- if (updateCandidate) return toUpdateInfo(updateCandidate, "UPDATE");
136
- if (rollbackCandidate) return toUpdateInfo(rollbackCandidate, "ROLLBACK");
137
- if (minBundleId && bundleId.localeCompare(minBundleId) <= 0) return null;
138
- return INIT_BUNDLE_ROLLBACK_UPDATE_INFO;
139
- };
140
- if (args._updateStrategy === "appVersion") return appVersionStrategy(args);
141
- if (args._updateStrategy === "fingerprint") return fingerprintStrategy(args);
142
- return null;
143
- },
144
- async getAppUpdateInfo(args) {
145
- const info = await this.getUpdateInfo(args);
146
- if (!info) return null;
147
- const { storageUri,...rest } = info;
148
- const fileUrl = await resolveFileUrl(storageUri ?? null);
149
- return {
150
- ...rest,
151
- fileUrl
152
- };
153
- },
154
- async getChannels() {
155
- const version = await client.version();
156
- const rows = await client.orm(version).findMany("bundles", { select: ["channel"] });
157
- const set = new Set(rows?.map((r) => r.channel) ?? []);
158
- return Array.from(set);
159
- },
160
- async getBundles(options) {
161
- const version = await client.version();
162
- const orm = client.orm(version);
163
- const { where, limit, offset } = options;
164
- const all = (await orm.findMany("bundles", {
165
- select: [
166
- "id",
167
- "platform",
168
- "should_force_update",
169
- "enabled",
170
- "file_hash",
171
- "git_commit_hash",
172
- "message",
173
- "channel",
174
- "storage_uri",
175
- "target_app_version",
176
- "fingerprint_hash",
177
- "metadata"
178
- ],
179
- where: (b) => {
180
- const conditions = [];
181
- if (where?.channel) conditions.push(b("channel", "=", where.channel));
182
- if (where?.platform) conditions.push(b("platform", "=", where.platform));
183
- return conditions.length > 0 ? b.and(...conditions) : true;
184
- }
185
- })).map((r) => ({
186
- id: r.id,
187
- platform: r.platform,
188
- shouldForceUpdate: Boolean(r.should_force_update),
189
- enabled: Boolean(r.enabled),
190
- fileHash: r.file_hash,
191
- gitCommitHash: r.git_commit_hash ?? null,
192
- message: r.message ?? null,
193
- channel: r.channel,
194
- storageUri: r.storage_uri,
195
- targetAppVersion: r.target_app_version ?? null,
196
- fingerprintHash: r.fingerprint_hash ?? null
197
- })).sort((a, b) => b.id.localeCompare(a.id));
198
- const total = all.length;
199
- return {
200
- data: all.slice(offset, offset + limit),
201
- pagination: calculatePagination(total, {
202
- limit,
203
- offset
204
- })
205
- };
206
- },
207
- async insertBundle(bundle) {
208
- const version = await client.version();
209
- const orm = client.orm(version);
210
- const values = {
211
- id: bundle.id,
212
- platform: bundle.platform,
213
- should_force_update: bundle.shouldForceUpdate,
214
- enabled: bundle.enabled,
215
- file_hash: bundle.fileHash,
216
- git_commit_hash: bundle.gitCommitHash,
217
- message: bundle.message,
218
- channel: bundle.channel,
219
- storage_uri: bundle.storageUri,
220
- target_app_version: bundle.targetAppVersion,
221
- fingerprint_hash: bundle.fingerprintHash,
222
- metadata: bundle.metadata ?? {}
223
- };
224
- const { id,...updateValues } = values;
225
- await orm.upsert("bundles", {
226
- where: (b) => b("id", "=", id),
227
- create: values,
228
- update: updateValues
229
- });
230
- },
231
- async updateBundleById(bundleId, newBundle) {
232
- const version = await client.version();
233
- const orm = client.orm(version);
234
- const current = await this.getBundleById(bundleId);
235
- if (!current) throw new Error("targetBundleId not found");
236
- const merged = {
237
- ...current,
238
- ...newBundle
239
- };
240
- const values = {
241
- id: merged.id,
242
- platform: merged.platform,
243
- should_force_update: merged.shouldForceUpdate,
244
- enabled: merged.enabled,
245
- file_hash: merged.fileHash,
246
- git_commit_hash: merged.gitCommitHash,
247
- message: merged.message,
248
- channel: merged.channel,
249
- storage_uri: merged.storageUri,
250
- target_app_version: merged.targetAppVersion,
251
- fingerprint_hash: merged.fingerprintHash,
252
- metadata: merged.metadata ?? {}
253
- };
254
- const { id: id2,...updateValues2 } = values;
255
- await orm.upsert("bundles", {
256
- where: (b) => b("id", "=", id2),
257
- create: values,
258
- update: updateValues2
259
- });
260
- },
261
- async deleteBundleById(bundleId) {
262
- const version = await client.version();
263
- await client.orm(version).deleteMany("bundles", { where: (b) => b("id", "=", bundleId) });
264
- }
265
- },
266
- adapterName: client.adapter.name,
267
- createMigrator: () => client.createMigrator(),
268
- generateSchema: client.generateSchema
269
- };
270
- }
271
-
272
- //#endregion
273
- export { HotUpdaterDB, createOrmDatabaseCore };
@@ -1,69 +0,0 @@
1
- import { getUpdateInfo } from "@hot-updater/js";
2
-
3
- //#region src/db/pluginCore.ts
4
- function createPluginDatabaseCore(plugin, resolveFileUrl) {
5
- return {
6
- api: {
7
- async getBundleById(id) {
8
- return plugin.getBundleById(id);
9
- },
10
- async getUpdateInfo(args) {
11
- const where = {};
12
- if ("platform" in args && args.platform) where.platform = args.platform;
13
- where.channel = "channel" in args && args.channel ? args.channel : "production";
14
- const { pagination } = await plugin.getBundles({
15
- where,
16
- limit: 1,
17
- offset: 0
18
- });
19
- if (pagination.total === 0) return getUpdateInfo([], args);
20
- const { data } = await plugin.getBundles({
21
- where,
22
- limit: pagination.total,
23
- offset: 0
24
- });
25
- return getUpdateInfo(data, args);
26
- },
27
- async getAppUpdateInfo(args) {
28
- const info = await this.getUpdateInfo(args);
29
- if (!info) return null;
30
- const { storageUri,...rest } = info;
31
- const fileUrl = await resolveFileUrl(storageUri ?? null);
32
- return {
33
- ...rest,
34
- fileUrl
35
- };
36
- },
37
- async getChannels() {
38
- return plugin.getChannels();
39
- },
40
- async getBundles(options) {
41
- return plugin.getBundles(options);
42
- },
43
- async insertBundle(bundle) {
44
- await plugin.appendBundle(bundle);
45
- await plugin.commitBundle();
46
- },
47
- async updateBundleById(bundleId, newBundle) {
48
- await plugin.updateBundle(bundleId, newBundle);
49
- await plugin.commitBundle();
50
- },
51
- async deleteBundleById(bundleId) {
52
- const bundle = await plugin.getBundleById(bundleId);
53
- if (!bundle) return;
54
- await plugin.deleteBundle(bundle);
55
- await plugin.commitBundle();
56
- }
57
- },
58
- adapterName: plugin.name,
59
- createMigrator: () => {
60
- throw new Error("createMigrator is only available for Kysely/Prisma/Drizzle database adapters.");
61
- },
62
- generateSchema: () => {
63
- throw new Error("generateSchema is only available for Kysely/Prisma/Drizzle database adapters.");
64
- }
65
- };
66
- }
67
-
68
- //#endregion
69
- export { createPluginDatabaseCore };
@@ -1,31 +0,0 @@
1
- import { PaginationInfo } from "../types/index.js";
2
- import { AppUpdateInfo, Bundle, GetBundlesArgs, UpdateInfo } from "@hot-updater/core";
3
- import { DatabasePlugin, StoragePlugin } from "@hot-updater/plugin-core";
4
- import { FumaDBAdapter } from "fumadb/adapters";
5
-
6
- //#region src/db/types.d.ts
7
- type DatabasePluginFactory = () => DatabasePlugin;
8
- type DatabaseAdapter = FumaDBAdapter | DatabasePlugin | DatabasePluginFactory;
9
- interface DatabaseAPI {
10
- getBundleById(id: string): Promise<Bundle | null>;
11
- getUpdateInfo(args: GetBundlesArgs): Promise<UpdateInfo | null>;
12
- getAppUpdateInfo(args: GetBundlesArgs): Promise<AppUpdateInfo | null>;
13
- getChannels(): Promise<string[]>;
14
- getBundles(options: {
15
- where?: {
16
- channel?: string;
17
- platform?: string;
18
- };
19
- limit: number;
20
- offset: number;
21
- }): Promise<{
22
- data: Bundle[];
23
- pagination: PaginationInfo;
24
- }>;
25
- insertBundle(bundle: Bundle): Promise<void>;
26
- updateBundleById(bundleId: string, newBundle: Partial<Bundle>): Promise<void>;
27
- deleteBundleById(bundleId: string): Promise<void>;
28
- }
29
- type StoragePluginFactory = () => StoragePlugin;
30
- //#endregion
31
- export { DatabaseAPI, DatabaseAdapter, StoragePluginFactory };
package/dist/handler.d.ts DELETED
@@ -1,37 +0,0 @@
1
- import { PaginationInfo } from "./types/index.js";
2
- import { AppUpdateInfo, AppVersionGetBundlesArgs, Bundle, FingerprintGetBundlesArgs } from "@hot-updater/core";
3
-
4
- //#region src/handler.d.ts
5
- interface HandlerAPI {
6
- getAppUpdateInfo: (args: AppVersionGetBundlesArgs | FingerprintGetBundlesArgs) => Promise<AppUpdateInfo | null>;
7
- getBundleById: (id: string) => Promise<Bundle | null>;
8
- getBundles: (options: {
9
- where?: {
10
- channel?: string;
11
- platform?: string;
12
- };
13
- limit: number;
14
- offset: number;
15
- }) => Promise<{
16
- data: Bundle[];
17
- pagination: PaginationInfo;
18
- }>;
19
- insertBundle: (bundle: Bundle) => Promise<void>;
20
- deleteBundleById: (bundleId: string) => Promise<void>;
21
- getChannels: () => Promise<string[]>;
22
- }
23
- interface HandlerOptions {
24
- /**
25
- * Base path for all routes
26
- * @default "/api"
27
- */
28
- basePath?: string;
29
- }
30
- /**
31
- * Creates a Web Standard Request handler for Hot Updater API
32
- * This handler is framework-agnostic and works with any framework
33
- * that supports Web Standard Request/Response (Hono, Elysia, etc.)
34
- */
35
- declare function createHandler(api: HandlerAPI, options?: HandlerOptions): (request: Request) => Promise<Response>;
36
- //#endregion
37
- export { HandlerAPI, HandlerOptions, createHandler };
package/dist/handler.js DELETED
@@ -1,146 +0,0 @@
1
- import { addRoute, createRouter, findRoute } from "rou3";
2
-
3
- //#region src/handler.ts
4
- const handleVersion = async () => {
5
- return new Response(JSON.stringify({ version: "0.27.1" }), {
6
- status: 200,
7
- headers: { "Content-Type": "application/json" }
8
- });
9
- };
10
- const handleFingerprintUpdate = async (params, _request, api) => {
11
- const updateInfo = await api.getAppUpdateInfo({
12
- _updateStrategy: "fingerprint",
13
- platform: params.platform,
14
- fingerprintHash: params.fingerprintHash,
15
- channel: params.channel,
16
- minBundleId: params.minBundleId,
17
- bundleId: params.bundleId
18
- });
19
- return new Response(JSON.stringify(updateInfo), {
20
- status: 200,
21
- headers: { "Content-Type": "application/json" }
22
- });
23
- };
24
- const handleAppVersionUpdate = async (params, _request, api) => {
25
- const updateInfo = await api.getAppUpdateInfo({
26
- _updateStrategy: "appVersion",
27
- platform: params.platform,
28
- appVersion: params.appVersion,
29
- channel: params.channel,
30
- minBundleId: params.minBundleId,
31
- bundleId: params.bundleId
32
- });
33
- return new Response(JSON.stringify(updateInfo), {
34
- status: 200,
35
- headers: { "Content-Type": "application/json" }
36
- });
37
- };
38
- const handleGetBundle = async (params, _request, api) => {
39
- const bundle = await api.getBundleById(params.id);
40
- if (!bundle) return new Response(JSON.stringify({ error: "Bundle not found" }), {
41
- status: 404,
42
- headers: { "Content-Type": "application/json" }
43
- });
44
- return new Response(JSON.stringify(bundle), {
45
- status: 200,
46
- headers: { "Content-Type": "application/json" }
47
- });
48
- };
49
- const handleGetBundles = async (_params, request, api) => {
50
- const url = new URL(request.url);
51
- const channel = url.searchParams.get("channel") ?? void 0;
52
- const platform = url.searchParams.get("platform") ?? void 0;
53
- const limit = Number(url.searchParams.get("limit")) || 50;
54
- const offset = Number(url.searchParams.get("offset")) || 0;
55
- const result = await api.getBundles({
56
- where: {
57
- ...channel && { channel },
58
- ...platform && { platform }
59
- },
60
- limit,
61
- offset
62
- });
63
- return new Response(JSON.stringify(result.data), {
64
- status: 200,
65
- headers: { "Content-Type": "application/json" }
66
- });
67
- };
68
- const handleCreateBundles = async (_params, request, api) => {
69
- const body = await request.json();
70
- const bundles = Array.isArray(body) ? body : [body];
71
- for (const bundle of bundles) await api.insertBundle(bundle);
72
- return new Response(JSON.stringify({ success: true }), {
73
- status: 201,
74
- headers: { "Content-Type": "application/json" }
75
- });
76
- };
77
- const handleDeleteBundle = async (params, _request, api) => {
78
- await api.deleteBundleById(params.id);
79
- return new Response(JSON.stringify({ success: true }), {
80
- status: 200,
81
- headers: { "Content-Type": "application/json" }
82
- });
83
- };
84
- const handleGetChannels = async (_params, _request, api) => {
85
- const channels = await api.getChannels();
86
- return new Response(JSON.stringify({ channels }), {
87
- status: 200,
88
- headers: { "Content-Type": "application/json" }
89
- });
90
- };
91
- const routes = {
92
- version: handleVersion,
93
- fingerprintUpdate: handleFingerprintUpdate,
94
- appVersionUpdate: handleAppVersionUpdate,
95
- getBundle: handleGetBundle,
96
- getBundles: handleGetBundles,
97
- createBundles: handleCreateBundles,
98
- deleteBundle: handleDeleteBundle,
99
- getChannels: handleGetChannels
100
- };
101
- /**
102
- * Creates a Web Standard Request handler for Hot Updater API
103
- * This handler is framework-agnostic and works with any framework
104
- * that supports Web Standard Request/Response (Hono, Elysia, etc.)
105
- */
106
- function createHandler(api, options = {}) {
107
- const basePath = options.basePath ?? "/api";
108
- const router = createRouter();
109
- addRoute(router, "GET", "/version", "version");
110
- addRoute(router, "GET", "/fingerprint/:platform/:fingerprintHash/:channel/:minBundleId/:bundleId", "fingerprintUpdate");
111
- addRoute(router, "GET", "/app-version/:platform/:appVersion/:channel/:minBundleId/:bundleId", "appVersionUpdate");
112
- addRoute(router, "GET", "/api/bundles/channels", "getChannels");
113
- addRoute(router, "GET", "/api/bundles/:id", "getBundle");
114
- addRoute(router, "GET", "/api/bundles", "getBundles");
115
- addRoute(router, "POST", "/api/bundles", "createBundles");
116
- addRoute(router, "DELETE", "/api/bundles/:id", "deleteBundle");
117
- return async (request) => {
118
- try {
119
- const path = new URL(request.url).pathname;
120
- const method = request.method;
121
- const match = findRoute(router, method, path.startsWith(basePath) ? path.slice(basePath.length) : path);
122
- if (!match) return new Response(JSON.stringify({ error: "Not found" }), {
123
- status: 404,
124
- headers: { "Content-Type": "application/json" }
125
- });
126
- const handler = routes[match.data];
127
- if (!handler) return new Response(JSON.stringify({ error: "Handler not found" }), {
128
- status: 500,
129
- headers: { "Content-Type": "application/json" }
130
- });
131
- return await handler(match.params || {}, request, api);
132
- } catch (error) {
133
- console.error("Hot Updater handler error:", error);
134
- return new Response(JSON.stringify({
135
- error: "Internal server error",
136
- message: error instanceof Error ? error.message : "Unknown error"
137
- }), {
138
- status: 500,
139
- headers: { "Content-Type": "application/json" }
140
- });
141
- }
142
- };
143
- }
144
-
145
- //#endregion
146
- export { createHandler };
package/dist/index.d.ts DELETED
@@ -1,5 +0,0 @@
1
- import { Bundle, PaginatedResult, PaginationInfo, PaginationOptions } from "./types/index.js";
2
- import { HotUpdaterClient, HotUpdaterDB, Migrator } from "./db/ormCore.js";
3
- import { HotUpdaterAPI, createHotUpdater } from "./db/index.js";
4
- import { HandlerAPI, HandlerOptions, createHandler } from "./handler.js";
5
- export { Bundle, HandlerAPI, HandlerOptions, HotUpdaterAPI, HotUpdaterClient, HotUpdaterDB, Migrator, PaginatedResult, PaginationInfo, PaginationOptions, createHandler, createHotUpdater };
package/dist/index.js DELETED
@@ -1,5 +0,0 @@
1
- import { createHandler } from "./handler.js";
2
- import { HotUpdaterDB } from "./db/ormCore.js";
3
- import { createHotUpdater } from "./db/index.js";
4
-
5
- export { HotUpdaterDB, createHandler, createHotUpdater };
File without changes
File without changes
File without changes
File without changes