@hot-updater/standalone 1.1.4 → 1.2.0-rc.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.
- package/dist/index.cjs +35 -5
- package/dist/index.mjs +35 -5
- package/package.json +4 -4
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
|
|
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\`
|
|
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
|
|
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\`
|
|
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.
|
|
3
|
+
"version": "1.2.0-rc.0",
|
|
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.
|
|
46
|
-
"@hot-updater/plugin-core": "1.
|
|
45
|
+
"@hot-updater/protocol": "1.2.0-rc.0",
|
|
46
|
+
"@hot-updater/plugin-core": "1.2.0-rc.0"
|
|
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.
|
|
55
|
+
"@hot-updater/test-utils": "1.2.0-rc.0"
|
|
56
56
|
},
|
|
57
57
|
"nx": {
|
|
58
58
|
"implicitDependencies": [
|