@hot-updater/standalone 1.1.4 → 1.2.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/index.cjs CHANGED
@@ -13,8 +13,7 @@ var StandaloneDatabaseError = class extends Error {
13
13
  };
14
14
  const isRecord$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
15
15
  const createStandaloneHttp = (config) => {
16
- const baseUrl = config.baseUrl.replace(/\/+$/, "");
17
- const buildUrl = (path) => `${baseUrl}${path}`;
16
+ const buildUrl = (path) => `${config.baseUrl.replace(/\/+$/, "")}${path}`;
18
17
  const headers = (routeHeaders) => ({
19
18
  "Content-Type": "application/json",
20
19
  ...config.commonHeaders,
@@ -75,6 +74,11 @@ const refusal = (status, value, fallback) => {
75
74
  }
76
75
  return new StandaloneDatabaseError("request-failed", message, status);
77
76
  };
77
+ const nativeBuildScopeParams = ({ platform, channel, fingerprintHash, appVersion }) => ({
78
+ platform,
79
+ channel,
80
+ ...fingerprintHash === null ? { appVersion } : { fingerprintHash }
81
+ });
78
82
  const keysetParams = ({ order, after, limit }) => ({
79
83
  limit: String(limit),
80
84
  ...order === void 0 ? {} : { order },
@@ -111,7 +115,7 @@ const createStandaloneCoreApi = (config) => {
111
115
  if (!isRecord(body) || !Array.isArray(body.plugins)) throw new StandaloneDatabaseError("request-failed", `The server at ${config.baseUrl} answered /version as its client mount, without the plugins list of handlers.admin. Set baseUrl to the path where the server mounts handlers.admin, such as https://example.com/hot-updater/admin.`, response.status);
112
116
  };
113
117
  /** One admin request's JSON body, or null for 204 and for a GET that finds nothing; `/version` is checked once before the first. */
114
- const request = async (method, path, { query = {}, body } = {}) => {
118
+ const request = async (method, path, { query = {}, body, requiredRoute } = {}) => {
115
119
  checked ??= checkProtocol().catch((error) => {
116
120
  checked = void 0;
117
121
  throw error;
@@ -125,8 +129,9 @@ const createStandaloneCoreApi = (config) => {
125
129
  ...body === void 0 ? {} : { body: JSON.stringify(body) }
126
130
  });
127
131
  if (response.status === 204) return null;
132
+ if (requiredRoute !== void 0 && response.status === 404) throw new StandaloneDatabaseError("request-failed", `The server at ${config.baseUrl} has no ${requiredRoute} route (${method} ${path} answered 404). Upgrade the server's @hot-updater/server, migrate its database, and try again.`, 404);
128
133
  if (method === "GET" && response.status === 404) return null;
129
- if (response.status === 503) throw new StandaloneDatabaseError("request-failed", `The server at ${config.baseUrl} answered ${method} ${path} with 503: its database is not ready. If it needs migrations, run \`hot-updater db migrate\` where the server's database is configured.`, 503);
134
+ if (response.status === 503) throw new StandaloneDatabaseError("request-failed", `The server at ${config.baseUrl} answered ${method} ${path} with 503: its database is not ready. If it needs migrations, run \`hot-updater db migrate\` in the server's project as you deploy it.`, 503);
130
135
  if (!response.ok) {
131
136
  const failure = await response.json().catch(() => null);
132
137
  throw refusal(response.status, failure, `${method} ${path} failed with status ${response.status}.`);
@@ -177,6 +182,22 @@ const createStandaloneCoreApi = (config) => {
177
182
  listReleaseCatalogs: (input) => list("/release-catalogs", keysetParams(input)),
178
183
  listChannels: () => list("/channels", {}),
179
184
  findChannelByName: (name) => call("GET", "/channels", { query: { name } }),
185
+ getNativeBuild: (id) => call("GET", `/native-builds/${encode(id)}`, { requiredRoute: "native build" }),
186
+ findNativeBuild: async (scope, options) => {
187
+ const buildKey = options?.buildKey;
188
+ const row = await call("GET", "/native-builds/latest", {
189
+ query: {
190
+ ...nativeBuildScopeParams(scope),
191
+ ...buildKey === void 0 ? {} : { buildKey }
192
+ },
193
+ requiredRoute: "native build"
194
+ });
195
+ return buildKey !== void 0 && row?.build_key !== buildKey ? null : row;
196
+ },
197
+ listNativeBuilds: ({ channelId, ...input }) => list("/native-builds", {
198
+ ...keysetParams(input),
199
+ ...channelId === void 0 ? {} : { channelId }
200
+ }),
180
201
  deploy: async (deployments) => await call("POST", "/releases", { body: { deployments } }),
181
202
  updateReleasePolicy: async ({ releaseId, ...input }) => await call("PATCH", `/releases/${encode(releaseId)}`, { body: input }),
182
203
  preflightReleasePolicy: async ({ releaseId, ...input }) => await call("POST", `/releases/${encode(releaseId)}/preflight`, { body: input }),
@@ -206,7 +227,16 @@ const createStandaloneCoreApi = (config) => {
206
227
  },
207
228
  deleteBundles: async (ids) => {
208
229
  await request("POST", "/bundles/delete", { body: { ids } });
209
- }
230
+ },
231
+ registerNativeBuild: async (registration) => await call("POST", "/native-builds", {
232
+ body: registration,
233
+ requiredRoute: "native build"
234
+ }),
235
+ recordNativeBuildSubmission: (id, submission) => call("POST", `/native-builds/${encode(id)}/submission`, {
236
+ body: submission,
237
+ requiredRoute: "native build submission"
238
+ }),
239
+ deleteNativeBuild: async (id) => await call("DELETE", `/native-builds/${encode(id)}`, { requiredRoute: "native build deletion" })
210
240
  };
211
241
  };
212
242
  //#endregion
package/dist/index.mjs CHANGED
@@ -12,8 +12,7 @@ var StandaloneDatabaseError = class extends Error {
12
12
  };
13
13
  const isRecord$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
14
14
  const createStandaloneHttp = (config) => {
15
- const baseUrl = config.baseUrl.replace(/\/+$/, "");
16
- const buildUrl = (path) => `${baseUrl}${path}`;
15
+ const buildUrl = (path) => `${config.baseUrl.replace(/\/+$/, "")}${path}`;
17
16
  const headers = (routeHeaders) => ({
18
17
  "Content-Type": "application/json",
19
18
  ...config.commonHeaders,
@@ -74,6 +73,11 @@ const refusal = (status, value, fallback) => {
74
73
  }
75
74
  return new StandaloneDatabaseError("request-failed", message, status);
76
75
  };
76
+ const nativeBuildScopeParams = ({ platform, channel, fingerprintHash, appVersion }) => ({
77
+ platform,
78
+ channel,
79
+ ...fingerprintHash === null ? { appVersion } : { fingerprintHash }
80
+ });
77
81
  const keysetParams = ({ order, after, limit }) => ({
78
82
  limit: String(limit),
79
83
  ...order === void 0 ? {} : { order },
@@ -110,7 +114,7 @@ const createStandaloneCoreApi = (config) => {
110
114
  if (!isRecord(body) || !Array.isArray(body.plugins)) throw new StandaloneDatabaseError("request-failed", `The server at ${config.baseUrl} answered /version as its client mount, without the plugins list of handlers.admin. Set baseUrl to the path where the server mounts handlers.admin, such as https://example.com/hot-updater/admin.`, response.status);
111
115
  };
112
116
  /** One admin request's JSON body, or null for 204 and for a GET that finds nothing; `/version` is checked once before the first. */
113
- const request = async (method, path, { query = {}, body } = {}) => {
117
+ const request = async (method, path, { query = {}, body, requiredRoute } = {}) => {
114
118
  checked ??= checkProtocol().catch((error) => {
115
119
  checked = void 0;
116
120
  throw error;
@@ -124,8 +128,9 @@ const createStandaloneCoreApi = (config) => {
124
128
  ...body === void 0 ? {} : { body: JSON.stringify(body) }
125
129
  });
126
130
  if (response.status === 204) return null;
131
+ if (requiredRoute !== void 0 && response.status === 404) throw new StandaloneDatabaseError("request-failed", `The server at ${config.baseUrl} has no ${requiredRoute} route (${method} ${path} answered 404). Upgrade the server's @hot-updater/server, migrate its database, and try again.`, 404);
127
132
  if (method === "GET" && response.status === 404) return null;
128
- if (response.status === 503) throw new StandaloneDatabaseError("request-failed", `The server at ${config.baseUrl} answered ${method} ${path} with 503: its database is not ready. If it needs migrations, run \`hot-updater db migrate\` where the server's database is configured.`, 503);
133
+ if (response.status === 503) throw new StandaloneDatabaseError("request-failed", `The server at ${config.baseUrl} answered ${method} ${path} with 503: its database is not ready. If it needs migrations, run \`hot-updater db migrate\` in the server's project as you deploy it.`, 503);
129
134
  if (!response.ok) {
130
135
  const failure = await response.json().catch(() => null);
131
136
  throw refusal(response.status, failure, `${method} ${path} failed with status ${response.status}.`);
@@ -176,6 +181,22 @@ const createStandaloneCoreApi = (config) => {
176
181
  listReleaseCatalogs: (input) => list("/release-catalogs", keysetParams(input)),
177
182
  listChannels: () => list("/channels", {}),
178
183
  findChannelByName: (name) => call("GET", "/channels", { query: { name } }),
184
+ getNativeBuild: (id) => call("GET", `/native-builds/${encode(id)}`, { requiredRoute: "native build" }),
185
+ findNativeBuild: async (scope, options) => {
186
+ const buildKey = options?.buildKey;
187
+ const row = await call("GET", "/native-builds/latest", {
188
+ query: {
189
+ ...nativeBuildScopeParams(scope),
190
+ ...buildKey === void 0 ? {} : { buildKey }
191
+ },
192
+ requiredRoute: "native build"
193
+ });
194
+ return buildKey !== void 0 && row?.build_key !== buildKey ? null : row;
195
+ },
196
+ listNativeBuilds: ({ channelId, ...input }) => list("/native-builds", {
197
+ ...keysetParams(input),
198
+ ...channelId === void 0 ? {} : { channelId }
199
+ }),
179
200
  deploy: async (deployments) => await call("POST", "/releases", { body: { deployments } }),
180
201
  updateReleasePolicy: async ({ releaseId, ...input }) => await call("PATCH", `/releases/${encode(releaseId)}`, { body: input }),
181
202
  preflightReleasePolicy: async ({ releaseId, ...input }) => await call("POST", `/releases/${encode(releaseId)}/preflight`, { body: input }),
@@ -205,7 +226,16 @@ const createStandaloneCoreApi = (config) => {
205
226
  },
206
227
  deleteBundles: async (ids) => {
207
228
  await request("POST", "/bundles/delete", { body: { ids } });
208
- }
229
+ },
230
+ registerNativeBuild: async (registration) => await call("POST", "/native-builds", {
231
+ body: registration,
232
+ requiredRoute: "native build"
233
+ }),
234
+ recordNativeBuildSubmission: (id, submission) => call("POST", `/native-builds/${encode(id)}/submission`, {
235
+ body: submission,
236
+ requiredRoute: "native build submission"
237
+ }),
238
+ deleteNativeBuild: async (id) => await call("DELETE", `/native-builds/${encode(id)}`, { requiredRoute: "native build deletion" })
209
239
  };
210
240
  };
211
241
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hot-updater/standalone",
3
- "version": "1.1.4",
3
+ "version": "1.2.0-rc.1",
4
4
  "type": "module",
5
5
  "description": "React Native OTA solution for self-hosted",
6
6
  "sideEffects": false,
@@ -42,8 +42,8 @@
42
42
  "access": "public"
43
43
  },
44
44
  "dependencies": {
45
- "@hot-updater/protocol": "1.1.4",
46
- "@hot-updater/plugin-core": "1.1.4"
45
+ "@hot-updater/protocol": "1.2.0-rc.1",
46
+ "@hot-updater/plugin-core": "1.2.0-rc.1"
47
47
  },
48
48
  "devDependencies": {
49
49
  "mime": "2.6.0",
@@ -52,7 +52,7 @@
52
52
  "msw": "^2.7.0",
53
53
  "verkit": "0.4.0",
54
54
  "vitest": "4.1.4",
55
- "@hot-updater/test-utils": "1.1.4"
55
+ "@hot-updater/test-utils": "1.2.0-rc.1"
56
56
  },
57
57
  "nx": {
58
58
  "implicitDependencies": [