@hot-updater/standalone 0.29.2 → 0.29.4

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/index.cjs CHANGED
@@ -35,6 +35,10 @@ const defaultRoutes$1 = {
35
35
  path: "/api/bundles",
36
36
  headers: { "Cache-Control": "no-cache" }
37
37
  }),
38
+ channels: () => ({
39
+ path: "/api/bundles/channels",
40
+ headers: { "Cache-Control": "no-cache" }
41
+ }),
38
42
  retrieve: (bundleId) => ({
39
43
  path: `/api/bundles/${bundleId}`,
40
44
  headers: { Accept: "application/json" }
@@ -48,40 +52,28 @@ const createRoute$1 = (defaultRoute, customRoute) => ({
48
52
  ...customRoute?.headers
49
53
  }
50
54
  });
51
- const bundleMatchesQueryWhere = (bundle, where) => {
52
- if (!where) return true;
53
- if (where.channel !== void 0 && bundle.channel !== where.channel) return false;
54
- if (where.platform !== void 0 && bundle.platform !== where.platform) return false;
55
- if (where.enabled !== void 0 && bundle.enabled !== where.enabled) return false;
56
- if (where.id?.eq !== void 0 && bundle.id !== where.id.eq) return false;
57
- if (where.id?.gt !== void 0 && bundle.id.localeCompare(where.id.gt) <= 0) return false;
58
- if (where.id?.gte !== void 0 && bundle.id.localeCompare(where.id.gte) < 0) return false;
59
- if (where.id?.lt !== void 0 && bundle.id.localeCompare(where.id.lt) >= 0) return false;
60
- if (where.id?.lte !== void 0 && bundle.id.localeCompare(where.id.lte) > 0) return false;
61
- if (where.id?.in && !where.id.in.includes(bundle.id)) return false;
62
- if (where.targetAppVersionNotNull && bundle.targetAppVersion === null) return false;
63
- if (where.targetAppVersion !== void 0 && bundle.targetAppVersion !== where.targetAppVersion) return false;
64
- if (where.targetAppVersionIn && !where.targetAppVersionIn.includes(bundle.targetAppVersion ?? "")) return false;
65
- if (where.fingerprintHash !== void 0 && bundle.fingerprintHash !== where.fingerprintHash) return false;
66
- return true;
67
- };
68
- const sortBundles = (bundles, orderBy) => {
69
- if (!orderBy) return bundles;
70
- const direction = orderBy?.direction ?? "desc";
71
- return bundles.slice().sort((a, b) => {
72
- const result = a.id.localeCompare(b.id);
73
- return direction === "asc" ? result : -result;
74
- });
75
- };
55
+ const appendPathSegment = (path, segment) => `${path.replace(/\/+$/, "")}/${segment}`;
56
+ const isRecord = (value) => typeof value === "object" && value !== null;
57
+ const isStringArray = (value) => Array.isArray(value) && value.every((item) => typeof item === "string");
58
+ const isPaginatedResult = (value) => isRecord(value) && Array.isArray(value.data) && isRecord(value.pagination);
59
+ const hasDataChannels = (value) => isRecord(value) && isRecord(value.data) && isStringArray(value.data.channels);
76
60
  const standaloneRepository = (0, _hot_updater_plugin_core.createDatabasePlugin)({
77
61
  name: "standalone-repository",
78
62
  factory: (config) => {
79
- const legacyUpsertRoute = config.routes?.upsert;
63
+ const customListRoute = config.routes?.list?.();
80
64
  const routes = {
81
- create: () => createRoute$1(defaultRoutes$1.create(), config.routes?.create?.() ?? legacyUpsertRoute?.()),
65
+ list: () => createRoute$1(defaultRoutes$1.list(), customListRoute),
66
+ channels: () => {
67
+ return createRoute$1(customListRoute ? {
68
+ path: appendPathSegment(customListRoute.path, "channels"),
69
+ headers: {
70
+ ...defaultRoutes$1.channels().headers,
71
+ ...customListRoute.headers
72
+ }
73
+ } : defaultRoutes$1.channels(), config.routes?.channels?.());
74
+ },
75
+ create: () => createRoute$1(defaultRoutes$1.create(), config.routes?.create?.()),
82
76
  update: (bundleId) => createRoute$1(defaultRoutes$1.update(bundleId), config.routes?.update?.(bundleId)),
83
- legacyUpsert: () => legacyUpsertRoute ? createRoute$1(defaultRoutes$1.create(), legacyUpsertRoute()) : null,
84
- list: () => createRoute$1(defaultRoutes$1.list(), config.routes?.list?.()),
85
77
  retrieve: (bundleId) => createRoute$1(defaultRoutes$1.retrieve(bundleId), config.routes?.retrieve?.(bundleId)),
86
78
  delete: (bundleId) => createRoute$1(defaultRoutes$1.delete(bundleId), config.routes?.delete?.(bundleId))
87
79
  };
@@ -106,32 +98,32 @@ const standaloneRepository = (0, _hot_updater_plugin_core.createDatabasePlugin)(
106
98
  }
107
99
  },
108
100
  async getBundles(options) {
109
- const { where, limit, offset = 0, orderBy } = options ?? {};
101
+ const { where, limit, offset = 0 } = options ?? {};
110
102
  const { path, headers: routeHeaders } = routes.list();
111
- const response = await fetch(buildUrl(path), {
103
+ const url = new URL(buildUrl(path));
104
+ if (where?.channel !== void 0) url.searchParams.set("channel", where.channel);
105
+ if (where?.platform !== void 0) url.searchParams.set("platform", where.platform);
106
+ if (limit !== void 0) url.searchParams.set("limit", String(limit));
107
+ url.searchParams.set("offset", String(offset));
108
+ const response = await fetch(url.toString(), {
112
109
  method: "GET",
113
110
  headers: getHeaders(routeHeaders)
114
111
  });
115
112
  if (!response.ok) throw new Error(`API Error: ${response.statusText}`);
116
- const filteredBundles = sortBundles((await response.json()).filter((bundle) => bundleMatchesQueryWhere(bundle, where)), orderBy);
117
- const total = filteredBundles.length;
118
- return {
119
- data: limit ? filteredBundles.slice(offset, offset + limit) : filteredBundles,
120
- pagination: (0, _hot_updater_plugin_core.calculatePagination)(total, {
121
- limit,
122
- offset
123
- })
124
- };
113
+ const result = await response.json();
114
+ if (isPaginatedResult(result)) return result;
115
+ throw new Error("API Error: Invalid bundle list response");
125
116
  },
126
117
  async getChannels() {
127
- const { path, headers: routeHeaders } = routes.list();
118
+ const { path, headers: routeHeaders } = routes.channels();
128
119
  const response = await fetch(buildUrl(path), {
129
120
  method: "GET",
130
121
  headers: getHeaders(routeHeaders)
131
122
  });
132
123
  if (!response.ok) throw new Error(`API Error: ${response.statusText}`);
133
- const channels = (await response.json()).map((b) => b.channel);
134
- return [...new Set(channels)];
124
+ const result = await response.json();
125
+ if (hasDataChannels(result)) return result.data.channels;
126
+ throw new Error("API Error: Invalid channels response");
135
127
  },
136
128
  async commitBundle({ changedSets }) {
137
129
  if (changedSets.length === 0) return;
@@ -147,7 +139,7 @@ const standaloneRepository = (0, _hot_updater_plugin_core.createDatabasePlugin)(
147
139
  }
148
140
  if (response.headers.get("content-type")?.includes("application/json")) try {
149
141
  await response.json();
150
- } catch (_jsonError) {
142
+ } catch {
151
143
  if (!response.ok) throw new Error("Failed to parse response");
152
144
  }
153
145
  } else if (op.operation === "insert") {
@@ -160,12 +152,11 @@ const standaloneRepository = (0, _hot_updater_plugin_core.createDatabasePlugin)(
160
152
  if (!response.ok) throw new Error(`API Error: ${response.statusText}`);
161
153
  if (!(await response.json()).success) throw new Error("Failed to commit bundle");
162
154
  } else if (op.operation === "update") {
163
- const legacyRoute = !config.routes?.update && routes.legacyUpsert();
164
- const { path, headers: routeHeaders } = legacyRoute ? legacyRoute : routes.update(op.data.id);
155
+ const { path, headers: routeHeaders } = routes.update(op.data.id);
165
156
  const response = await fetch(buildUrl(path), {
166
- method: legacyRoute ? "POST" : "PATCH",
157
+ method: "PATCH",
167
158
  headers: getHeaders(routeHeaders),
168
- body: JSON.stringify(legacyRoute ? [op.data] : op.data)
159
+ body: JSON.stringify(op.data)
169
160
  });
170
161
  if (!response.ok) throw new Error(`API Error: ${response.statusText}`);
171
162
  if (!(await response.json()).success) throw new Error("Failed to commit bundle");
package/dist/index.d.cts CHANGED
@@ -7,13 +7,10 @@ interface RouteConfig {
7
7
  headers?: Record<string, string>;
8
8
  }
9
9
  interface Routes {
10
- /**
11
- * @deprecated Use `create` and `update`. Kept for backward compatibility.
12
- */
13
- upsert?: () => RouteConfig;
14
10
  create?: () => RouteConfig;
15
11
  update?: (bundleId: string) => RouteConfig;
16
12
  list?: () => RouteConfig;
13
+ channels?: () => RouteConfig;
17
14
  retrieve?: (bundleId: string) => RouteConfig;
18
15
  delete?: (bundleId: string) => RouteConfig;
19
16
  }
package/dist/index.d.mts CHANGED
@@ -7,13 +7,10 @@ interface RouteConfig {
7
7
  headers?: Record<string, string>;
8
8
  }
9
9
  interface Routes {
10
- /**
11
- * @deprecated Use `create` and `update`. Kept for backward compatibility.
12
- */
13
- upsert?: () => RouteConfig;
14
10
  create?: () => RouteConfig;
15
11
  update?: (bundleId: string) => RouteConfig;
16
12
  list?: () => RouteConfig;
13
+ channels?: () => RouteConfig;
17
14
  retrieve?: (bundleId: string) => RouteConfig;
18
15
  delete?: (bundleId: string) => RouteConfig;
19
16
  }
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { calculatePagination, createDatabasePlugin } from "@hot-updater/plugin-core";
1
+ import { createDatabasePlugin } from "@hot-updater/plugin-core";
2
2
  import fs from "fs/promises";
3
3
  import path from "path";
4
4
  //#region \0rolldown/runtime.js
@@ -32,6 +32,10 @@ const defaultRoutes$1 = {
32
32
  path: "/api/bundles",
33
33
  headers: { "Cache-Control": "no-cache" }
34
34
  }),
35
+ channels: () => ({
36
+ path: "/api/bundles/channels",
37
+ headers: { "Cache-Control": "no-cache" }
38
+ }),
35
39
  retrieve: (bundleId) => ({
36
40
  path: `/api/bundles/${bundleId}`,
37
41
  headers: { Accept: "application/json" }
@@ -45,40 +49,28 @@ const createRoute$1 = (defaultRoute, customRoute) => ({
45
49
  ...customRoute?.headers
46
50
  }
47
51
  });
48
- const bundleMatchesQueryWhere = (bundle, where) => {
49
- if (!where) return true;
50
- if (where.channel !== void 0 && bundle.channel !== where.channel) return false;
51
- if (where.platform !== void 0 && bundle.platform !== where.platform) return false;
52
- if (where.enabled !== void 0 && bundle.enabled !== where.enabled) return false;
53
- if (where.id?.eq !== void 0 && bundle.id !== where.id.eq) return false;
54
- if (where.id?.gt !== void 0 && bundle.id.localeCompare(where.id.gt) <= 0) return false;
55
- if (where.id?.gte !== void 0 && bundle.id.localeCompare(where.id.gte) < 0) return false;
56
- if (where.id?.lt !== void 0 && bundle.id.localeCompare(where.id.lt) >= 0) return false;
57
- if (where.id?.lte !== void 0 && bundle.id.localeCompare(where.id.lte) > 0) return false;
58
- if (where.id?.in && !where.id.in.includes(bundle.id)) return false;
59
- if (where.targetAppVersionNotNull && bundle.targetAppVersion === null) return false;
60
- if (where.targetAppVersion !== void 0 && bundle.targetAppVersion !== where.targetAppVersion) return false;
61
- if (where.targetAppVersionIn && !where.targetAppVersionIn.includes(bundle.targetAppVersion ?? "")) return false;
62
- if (where.fingerprintHash !== void 0 && bundle.fingerprintHash !== where.fingerprintHash) return false;
63
- return true;
64
- };
65
- const sortBundles = (bundles, orderBy) => {
66
- if (!orderBy) return bundles;
67
- const direction = orderBy?.direction ?? "desc";
68
- return bundles.slice().sort((a, b) => {
69
- const result = a.id.localeCompare(b.id);
70
- return direction === "asc" ? result : -result;
71
- });
72
- };
52
+ const appendPathSegment = (path, segment) => `${path.replace(/\/+$/, "")}/${segment}`;
53
+ const isRecord = (value) => typeof value === "object" && value !== null;
54
+ const isStringArray = (value) => Array.isArray(value) && value.every((item) => typeof item === "string");
55
+ const isPaginatedResult = (value) => isRecord(value) && Array.isArray(value.data) && isRecord(value.pagination);
56
+ const hasDataChannels = (value) => isRecord(value) && isRecord(value.data) && isStringArray(value.data.channels);
73
57
  const standaloneRepository = createDatabasePlugin({
74
58
  name: "standalone-repository",
75
59
  factory: (config) => {
76
- const legacyUpsertRoute = config.routes?.upsert;
60
+ const customListRoute = config.routes?.list?.();
77
61
  const routes = {
78
- create: () => createRoute$1(defaultRoutes$1.create(), config.routes?.create?.() ?? legacyUpsertRoute?.()),
62
+ list: () => createRoute$1(defaultRoutes$1.list(), customListRoute),
63
+ channels: () => {
64
+ return createRoute$1(customListRoute ? {
65
+ path: appendPathSegment(customListRoute.path, "channels"),
66
+ headers: {
67
+ ...defaultRoutes$1.channels().headers,
68
+ ...customListRoute.headers
69
+ }
70
+ } : defaultRoutes$1.channels(), config.routes?.channels?.());
71
+ },
72
+ create: () => createRoute$1(defaultRoutes$1.create(), config.routes?.create?.()),
79
73
  update: (bundleId) => createRoute$1(defaultRoutes$1.update(bundleId), config.routes?.update?.(bundleId)),
80
- legacyUpsert: () => legacyUpsertRoute ? createRoute$1(defaultRoutes$1.create(), legacyUpsertRoute()) : null,
81
- list: () => createRoute$1(defaultRoutes$1.list(), config.routes?.list?.()),
82
74
  retrieve: (bundleId) => createRoute$1(defaultRoutes$1.retrieve(bundleId), config.routes?.retrieve?.(bundleId)),
83
75
  delete: (bundleId) => createRoute$1(defaultRoutes$1.delete(bundleId), config.routes?.delete?.(bundleId))
84
76
  };
@@ -103,32 +95,32 @@ const standaloneRepository = createDatabasePlugin({
103
95
  }
104
96
  },
105
97
  async getBundles(options) {
106
- const { where, limit, offset = 0, orderBy } = options ?? {};
98
+ const { where, limit, offset = 0 } = options ?? {};
107
99
  const { path, headers: routeHeaders } = routes.list();
108
- const response = await fetch(buildUrl(path), {
100
+ const url = new URL(buildUrl(path));
101
+ if (where?.channel !== void 0) url.searchParams.set("channel", where.channel);
102
+ if (where?.platform !== void 0) url.searchParams.set("platform", where.platform);
103
+ if (limit !== void 0) url.searchParams.set("limit", String(limit));
104
+ url.searchParams.set("offset", String(offset));
105
+ const response = await fetch(url.toString(), {
109
106
  method: "GET",
110
107
  headers: getHeaders(routeHeaders)
111
108
  });
112
109
  if (!response.ok) throw new Error(`API Error: ${response.statusText}`);
113
- const filteredBundles = sortBundles((await response.json()).filter((bundle) => bundleMatchesQueryWhere(bundle, where)), orderBy);
114
- const total = filteredBundles.length;
115
- return {
116
- data: limit ? filteredBundles.slice(offset, offset + limit) : filteredBundles,
117
- pagination: calculatePagination(total, {
118
- limit,
119
- offset
120
- })
121
- };
110
+ const result = await response.json();
111
+ if (isPaginatedResult(result)) return result;
112
+ throw new Error("API Error: Invalid bundle list response");
122
113
  },
123
114
  async getChannels() {
124
- const { path, headers: routeHeaders } = routes.list();
115
+ const { path, headers: routeHeaders } = routes.channels();
125
116
  const response = await fetch(buildUrl(path), {
126
117
  method: "GET",
127
118
  headers: getHeaders(routeHeaders)
128
119
  });
129
120
  if (!response.ok) throw new Error(`API Error: ${response.statusText}`);
130
- const channels = (await response.json()).map((b) => b.channel);
131
- return [...new Set(channels)];
121
+ const result = await response.json();
122
+ if (hasDataChannels(result)) return result.data.channels;
123
+ throw new Error("API Error: Invalid channels response");
132
124
  },
133
125
  async commitBundle({ changedSets }) {
134
126
  if (changedSets.length === 0) return;
@@ -144,7 +136,7 @@ const standaloneRepository = createDatabasePlugin({
144
136
  }
145
137
  if (response.headers.get("content-type")?.includes("application/json")) try {
146
138
  await response.json();
147
- } catch (_jsonError) {
139
+ } catch {
148
140
  if (!response.ok) throw new Error("Failed to parse response");
149
141
  }
150
142
  } else if (op.operation === "insert") {
@@ -157,12 +149,11 @@ const standaloneRepository = createDatabasePlugin({
157
149
  if (!response.ok) throw new Error(`API Error: ${response.statusText}`);
158
150
  if (!(await response.json()).success) throw new Error("Failed to commit bundle");
159
151
  } else if (op.operation === "update") {
160
- const legacyRoute = !config.routes?.update && routes.legacyUpsert();
161
- const { path, headers: routeHeaders } = legacyRoute ? legacyRoute : routes.update(op.data.id);
152
+ const { path, headers: routeHeaders } = routes.update(op.data.id);
162
153
  const response = await fetch(buildUrl(path), {
163
- method: legacyRoute ? "POST" : "PATCH",
154
+ method: "PATCH",
164
155
  headers: getHeaders(routeHeaders),
165
- body: JSON.stringify(legacyRoute ? [op.data] : op.data)
156
+ body: JSON.stringify(op.data)
166
157
  });
167
158
  if (!response.ok) throw new Error(`API Error: ${response.statusText}`);
168
159
  if (!(await response.json()).success) throw new Error("Failed to commit bundle");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hot-updater/standalone",
3
- "version": "0.29.2",
3
+ "version": "0.29.4",
4
4
  "type": "module",
5
5
  "description": "React Native OTA solution for self-hosted",
6
6
  "sideEffects": false,
@@ -39,8 +39,8 @@
39
39
  "access": "public"
40
40
  },
41
41
  "dependencies": {
42
- "@hot-updater/core": "0.29.2",
43
- "@hot-updater/plugin-core": "0.29.2"
42
+ "@hot-updater/core": "0.29.4",
43
+ "@hot-updater/plugin-core": "0.29.4"
44
44
  },
45
45
  "devDependencies": {
46
46
  "mime": "2.6.0",