@hot-updater/standalone 1.0.0-rc.2 → 1.0.0-rc.22
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 +171 -594
- package/dist/index.d.cts +25 -19
- package/dist/index.d.mts +25 -19
- package/dist/index.mjs +171 -596
- package/package.json +10 -4
package/dist/index.cjs
CHANGED
|
@@ -1,227 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
let _hot_updater_plugin_core = require("@hot-updater/plugin-core");
|
|
3
|
-
//#region src/standaloneBundleRows.ts
|
|
4
|
-
async function loadRows(remote, model) {
|
|
5
|
-
return model === "bundles" ? remote.loadBundleRows() : (await remote.loadBundles()).flatMap(_hot_updater_plugin_core.bundleToPatchRows);
|
|
6
|
-
}
|
|
7
|
-
//#endregion
|
|
8
|
-
//#region src/standaloneDatabaseQuery.ts
|
|
9
|
-
const compare$1 = (left, right) => {
|
|
10
|
-
if (typeof left === "number" && typeof right === "number") return left - right;
|
|
11
|
-
return String(left).localeCompare(String(right));
|
|
12
|
-
};
|
|
13
|
-
const compareString = (actual, expected, mode, predicate) => {
|
|
14
|
-
if (typeof actual !== "string") return false;
|
|
15
|
-
return mode === "insensitive" ? predicate(actual.toLocaleLowerCase(), expected.toLocaleLowerCase()) : predicate(actual, expected);
|
|
16
|
-
};
|
|
17
|
-
const matchesCondition = (row, condition) => {
|
|
18
|
-
const actual = Reflect.get(row, condition.field);
|
|
19
|
-
const expected = Reflect.get(condition, "value");
|
|
20
|
-
switch (Reflect.get(condition, "operator") ?? "eq") {
|
|
21
|
-
case "eq":
|
|
22
|
-
if (typeof expected === "string") return compareString(actual, expected, Reflect.get(condition, "mode"), (value, query) => value === query);
|
|
23
|
-
return actual === expected;
|
|
24
|
-
case "ne":
|
|
25
|
-
if (actual === null || actual === void 0) return false;
|
|
26
|
-
if (typeof expected === "string") return !compareString(actual, expected, Reflect.get(condition, "mode"), (value, query) => value === query);
|
|
27
|
-
return actual !== expected;
|
|
28
|
-
case "gt":
|
|
29
|
-
if (actual === null || actual === void 0) return false;
|
|
30
|
-
return compare$1(actual, expected) > 0;
|
|
31
|
-
case "gte":
|
|
32
|
-
if (actual === null || actual === void 0) return false;
|
|
33
|
-
return compare$1(actual, expected) >= 0;
|
|
34
|
-
case "lt":
|
|
35
|
-
if (actual === null || actual === void 0) return false;
|
|
36
|
-
return compare$1(actual, expected) < 0;
|
|
37
|
-
case "lte":
|
|
38
|
-
if (actual === null || actual === void 0) return false;
|
|
39
|
-
return compare$1(actual, expected) <= 0;
|
|
40
|
-
case "in": return Array.isArray(expected) && expected.some((candidate) => candidate === actual);
|
|
41
|
-
case "not_in": return Array.isArray(expected) && (expected.length === 0 || actual !== null && actual !== void 0 && expected.every((candidate) => candidate !== actual));
|
|
42
|
-
case "contains": return typeof expected === "string" ? compareString(actual, expected, Reflect.get(condition, "mode"), (value, query) => value.includes(query)) : false;
|
|
43
|
-
case "starts_with": return typeof expected === "string" ? compareString(actual, expected, Reflect.get(condition, "mode"), (value, query) => value.startsWith(query)) : false;
|
|
44
|
-
case "ends_with": return typeof expected === "string" ? compareString(actual, expected, Reflect.get(condition, "mode"), (value, query) => value.endsWith(query)) : false;
|
|
45
|
-
default: return false;
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
const matchesStandaloneWhere = (row, where) => {
|
|
49
|
-
if (!where || where.length === 0) return true;
|
|
50
|
-
let result = matchesCondition(row, where[0]);
|
|
51
|
-
for (const condition of where.slice(1)) {
|
|
52
|
-
const current = matchesCondition(row, condition);
|
|
53
|
-
result = condition.connector === "OR" ? result || current : result && current;
|
|
54
|
-
}
|
|
55
|
-
return result;
|
|
56
|
-
};
|
|
57
|
-
const queryStandaloneRows = (rows, input) => {
|
|
58
|
-
const filtered = rows.filter((row) => matchesStandaloneWhere(row, input.where));
|
|
59
|
-
if (input.orderBy) {
|
|
60
|
-
const direction = input.orderBy.direction === "asc" ? 1 : -1;
|
|
61
|
-
filtered.sort((left, right) => compare$1(Reflect.get(left, input.orderBy?.field ?? "id"), Reflect.get(right, input.orderBy?.field ?? "id")) * direction);
|
|
62
|
-
}
|
|
63
|
-
const offset = input.offset ?? 0;
|
|
64
|
-
return filtered.slice(offset, offset + (input.limit ?? filtered.length));
|
|
65
|
-
};
|
|
66
|
-
//#endregion
|
|
67
|
-
//#region src/standaloneBundleReads.ts
|
|
68
|
-
const compare = (left, right) => {
|
|
69
|
-
if (typeof left === "number" && typeof right === "number") return left - right;
|
|
70
|
-
return String(left).localeCompare(String(right));
|
|
71
|
-
};
|
|
72
|
-
const queryBundleRows = (rows, input) => {
|
|
73
|
-
const filtered = queryStandaloneRows(rows, { where: input.where });
|
|
74
|
-
const orderBy = input.orderBy;
|
|
75
|
-
if (orderBy !== void 0) filtered.sort((left, right) => {
|
|
76
|
-
for (const clause of orderBy) {
|
|
77
|
-
const leftValue = Reflect.get(left, clause.field);
|
|
78
|
-
const rightValue = Reflect.get(right, clause.field);
|
|
79
|
-
if (leftValue === rightValue) continue;
|
|
80
|
-
if (leftValue === null || rightValue === null) {
|
|
81
|
-
const nulls = clause.nulls ?? (clause.direction === "asc" ? "last" : "first");
|
|
82
|
-
return leftValue === null ? nulls === "first" ? -1 : 1 : nulls === "first" ? 1 : -1;
|
|
83
|
-
}
|
|
84
|
-
const result = compare(leftValue, rightValue);
|
|
85
|
-
if (result !== 0) return clause.direction === "asc" ? result : -result;
|
|
86
|
-
}
|
|
87
|
-
return 0;
|
|
88
|
-
});
|
|
89
|
-
return (input.distinctOn === void 0 ? filtered : filtered.filter((row, index, ordered) => ordered.findIndex((candidate) => JSON.stringify(input.distinctOn?.fields.map((field) => Reflect.get(candidate, field))) === JSON.stringify(input.distinctOn?.fields.map((field) => Reflect.get(row, field)))) === index)).slice(input.offset, input.offset + input.limit);
|
|
90
|
-
};
|
|
91
|
-
const countDistinctRows = (rows, fields) => fields === void 0 ? rows.length : new Set(rows.map((row) => JSON.stringify(fields.map((field) => Reflect.get(row, field))))).size;
|
|
92
|
-
const createBundleReads = (remote) => ({
|
|
93
|
-
async count(input) {
|
|
94
|
-
switch (input.model) {
|
|
95
|
-
case "bundles": {
|
|
96
|
-
const where = input.where;
|
|
97
|
-
if (input.distinct === void 0) {
|
|
98
|
-
const remoteWindow = await remote.loadBundleWindow({
|
|
99
|
-
where,
|
|
100
|
-
limit: 1,
|
|
101
|
-
offset: 0
|
|
102
|
-
});
|
|
103
|
-
if (remoteWindow) return remoteWindow.total;
|
|
104
|
-
}
|
|
105
|
-
const rows = queryStandaloneRows(await loadRows(remote, "bundles"), { where });
|
|
106
|
-
return countDistinctRows(rows, input.distinct);
|
|
107
|
-
}
|
|
108
|
-
case "bundle_patches": {
|
|
109
|
-
const rows = queryStandaloneRows(await loadRows(remote, "bundle_patches"), { where: input.where });
|
|
110
|
-
return countDistinctRows(rows, input.distinct);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
},
|
|
114
|
-
async findOne(input) {
|
|
115
|
-
if (input.model === "bundles") {
|
|
116
|
-
const idSelector = input.where?.length === 1 ? input.where[0] : void 0;
|
|
117
|
-
if (idSelector?.field === "id" && (idSelector.operator === void 0 || idSelector.operator === "eq") && typeof idSelector.value === "string") {
|
|
118
|
-
const row = await remote.loadBundleRow(idSelector.value);
|
|
119
|
-
return row && matchesStandaloneWhere(row, input.where) ? row : null;
|
|
120
|
-
}
|
|
121
|
-
return queryStandaloneRows(await loadRows(remote, "bundles"), {
|
|
122
|
-
where: input.where,
|
|
123
|
-
limit: 1
|
|
124
|
-
})[0] ?? null;
|
|
125
|
-
}
|
|
126
|
-
return queryStandaloneRows(await loadRows(remote, "bundle_patches"), {
|
|
127
|
-
where: input.where,
|
|
128
|
-
limit: 1
|
|
129
|
-
})[0] ?? null;
|
|
130
|
-
},
|
|
131
|
-
async findMany(input) {
|
|
132
|
-
switch (input.model) {
|
|
133
|
-
case "bundles": {
|
|
134
|
-
const where = input.where;
|
|
135
|
-
const orderBy = input.orderBy;
|
|
136
|
-
const remoteSort = orderBy?.length === 1 && orderBy[0]?.field === "id" ? orderBy[0] : void 0;
|
|
137
|
-
if (input.distinctOn === void 0 && (orderBy === void 0 || remoteSort)) {
|
|
138
|
-
const remoteWindow = await remote.loadBundleWindow({
|
|
139
|
-
where,
|
|
140
|
-
limit: input.limit,
|
|
141
|
-
offset: input.offset,
|
|
142
|
-
orderBy: remoteSort
|
|
143
|
-
});
|
|
144
|
-
if (remoteWindow) return remoteWindow.rows;
|
|
145
|
-
}
|
|
146
|
-
return queryBundleRows(await loadRows(remote, "bundles"), {
|
|
147
|
-
distinctOn: input.distinctOn,
|
|
148
|
-
where,
|
|
149
|
-
limit: input.limit,
|
|
150
|
-
offset: input.offset,
|
|
151
|
-
orderBy: input.orderBy
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
case "bundle_patches": return queryBundleRows(await loadRows(remote, "bundle_patches"), {
|
|
155
|
-
distinctOn: input.distinctOn,
|
|
156
|
-
where: input.where,
|
|
157
|
-
limit: input.limit,
|
|
158
|
-
offset: input.offset,
|
|
159
|
-
orderBy: input.orderBy
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
|
-
//#endregion
|
|
165
|
-
//#region src/standaloneBundleReader.ts
|
|
166
|
-
const createStandaloneBundleReader = (remote) => createBundleReads(remote);
|
|
167
|
-
//#endregion
|
|
168
|
-
//#region src/standaloneBundleWhere.ts
|
|
169
|
-
const appendBundleWhere = (url, where) => {
|
|
170
|
-
const usedParameters = /* @__PURE__ */ new Set();
|
|
171
|
-
const setParameter = (parameter, value) => {
|
|
172
|
-
if (usedParameters.has(parameter)) return false;
|
|
173
|
-
usedParameters.add(parameter);
|
|
174
|
-
url.searchParams.set(parameter, value);
|
|
175
|
-
return true;
|
|
176
|
-
};
|
|
177
|
-
const appendParameter = (parameter, values) => {
|
|
178
|
-
if (values.length === 0 || usedParameters.has(parameter)) return false;
|
|
179
|
-
usedParameters.add(parameter);
|
|
180
|
-
for (const value of values) url.searchParams.append(parameter, value);
|
|
181
|
-
return true;
|
|
182
|
-
};
|
|
183
|
-
for (const [index, condition] of (where ?? []).entries()) {
|
|
184
|
-
if (index > 0 && condition.connector === "OR") return false;
|
|
185
|
-
const operator = condition.operator ?? "eq";
|
|
186
|
-
switch (condition.field) {
|
|
187
|
-
case "platform":
|
|
188
|
-
if (operator !== "eq" || typeof condition.value !== "string") return false;
|
|
189
|
-
if (!setParameter("platform", condition.value)) return false;
|
|
190
|
-
break;
|
|
191
|
-
case "id": {
|
|
192
|
-
let parameter;
|
|
193
|
-
switch (operator) {
|
|
194
|
-
case "eq":
|
|
195
|
-
parameter = "idEq";
|
|
196
|
-
break;
|
|
197
|
-
case "gt":
|
|
198
|
-
parameter = "idGt";
|
|
199
|
-
break;
|
|
200
|
-
case "gte":
|
|
201
|
-
parameter = "idGte";
|
|
202
|
-
break;
|
|
203
|
-
case "lt":
|
|
204
|
-
parameter = "idLt";
|
|
205
|
-
break;
|
|
206
|
-
case "lte": parameter = "idLte";
|
|
207
|
-
}
|
|
208
|
-
if (parameter && typeof condition.value === "string") {
|
|
209
|
-
if (!setParameter(parameter, condition.value)) return false;
|
|
210
|
-
break;
|
|
211
|
-
}
|
|
212
|
-
if (operator === "in" && Array.isArray(condition.value)) {
|
|
213
|
-
if (!condition.value.every((value) => typeof value === "string")) return false;
|
|
214
|
-
if (!appendParameter("idIn", condition.value)) return false;
|
|
215
|
-
break;
|
|
216
|
-
}
|
|
217
|
-
return false;
|
|
218
|
-
}
|
|
219
|
-
default: return false;
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
return true;
|
|
223
|
-
};
|
|
224
|
-
//#endregion
|
|
225
3
|
//#region src/standaloneHttp.ts
|
|
226
4
|
var StandaloneDatabaseError = class extends Error {
|
|
227
5
|
code;
|
|
@@ -233,7 +11,7 @@ var StandaloneDatabaseError = class extends Error {
|
|
|
233
11
|
this.status = status;
|
|
234
12
|
}
|
|
235
13
|
};
|
|
236
|
-
const isRecord$
|
|
14
|
+
const isRecord$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
237
15
|
const createStandaloneHttp = (config) => {
|
|
238
16
|
const baseUrl = config.baseUrl.replace(/\/+$/, "");
|
|
239
17
|
const buildUrl = (path) => `${baseUrl}${path}`;
|
|
@@ -246,8 +24,8 @@ const createStandaloneHttp = (config) => {
|
|
|
246
24
|
let message = `Database request failed with status ${response.status}.`;
|
|
247
25
|
try {
|
|
248
26
|
const body = await response.json();
|
|
249
|
-
if (isRecord$
|
|
250
|
-
else if (isRecord$
|
|
27
|
+
if (isRecord$1(body) && typeof body.message === "string") message = body.message;
|
|
28
|
+
else if (isRecord$1(body) && typeof body.error === "string") message = body.error;
|
|
251
29
|
} catch (error) {
|
|
252
30
|
if (!(error instanceof SyntaxError)) throw error;
|
|
253
31
|
}
|
|
@@ -261,409 +39,206 @@ const createStandaloneHttp = (config) => {
|
|
|
261
39
|
throw new StandaloneDatabaseError("invalid-response", "Database response must contain JSON.", response.status);
|
|
262
40
|
}
|
|
263
41
|
};
|
|
264
|
-
const load = async (route, searchParams, isResult, invalidMessage, signal) => {
|
|
265
|
-
const url = new URL(buildUrl(route.path));
|
|
266
|
-
for (const [key, value] of Object.entries(searchParams)) url.searchParams.set(key, value);
|
|
267
|
-
const response = await fetch(url, {
|
|
268
|
-
method: "GET",
|
|
269
|
-
headers: headers(route.headers),
|
|
270
|
-
signal
|
|
271
|
-
});
|
|
272
|
-
const value = await parseJson(response);
|
|
273
|
-
if (!isResult(value)) throw new StandaloneDatabaseError("invalid-response", invalidMessage, response.status);
|
|
274
|
-
return value;
|
|
275
|
-
};
|
|
276
42
|
return {
|
|
277
43
|
buildUrl,
|
|
278
44
|
headers,
|
|
279
|
-
|
|
280
|
-
parseJson,
|
|
281
|
-
requestFailed
|
|
45
|
+
parseJson
|
|
282
46
|
};
|
|
283
47
|
};
|
|
284
48
|
//#endregion
|
|
285
|
-
//#region src/
|
|
286
|
-
|
|
287
|
-
const
|
|
288
|
-
const
|
|
289
|
-
const
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
49
|
+
//#region src/standaloneCore.ts
|
|
50
|
+
/** The admin API protocol this client speaks; the server's `/version` must report it or a later one. */
|
|
51
|
+
const STANDALONE_ADMIN_PROTOCOL = 2;
|
|
52
|
+
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
53
|
+
const MANAGEMENT_CODES = /* @__PURE__ */ new Set([
|
|
54
|
+
"ENABLED_RELEASE",
|
|
55
|
+
"RELEASE_NOT_FOUND",
|
|
56
|
+
"SCOPE_MOVE_UNSUPPORTED",
|
|
57
|
+
"TARGET_RELEASE_INVALID",
|
|
58
|
+
"VERSION_CONFLICT"
|
|
59
|
+
]);
|
|
60
|
+
const CATALOG_CODES = /* @__PURE__ */ new Set([
|
|
61
|
+
"CATALOG_GENERATION_EXHAUSTED",
|
|
62
|
+
"CATALOG_IDENTITY_MISSING",
|
|
63
|
+
"INVALID_SCOPE",
|
|
64
|
+
"NON_MONOTONIC_RELEASE_ID"
|
|
65
|
+
]);
|
|
66
|
+
/** A refusal the server named, as the error core throws in process; anything else as a request failure. */
|
|
67
|
+
const refusal = (status, value, fallback) => {
|
|
68
|
+
const code = isRecord(value) ? value.code : void 0;
|
|
69
|
+
const message = isRecord(value) && typeof value.error === "string" ? value.error : fallback;
|
|
70
|
+
if (typeof code === "string" && MANAGEMENT_CODES.has(code)) return new _hot_updater_plugin_core.ReleaseManagementError(code, message);
|
|
71
|
+
if (typeof code === "string" && CATALOG_CODES.has(code)) return new _hot_updater_plugin_core.ReleaseCatalogMutationError(code, message);
|
|
72
|
+
if (code === "BUNDLE_NOT_FOUND" && isRecord(value)) {
|
|
73
|
+
const id = /"([^"]+)"/u.exec(message)?.[1] ?? "";
|
|
74
|
+
return new _hot_updater_plugin_core.DatabaseBundleNotFoundError(id);
|
|
296
75
|
}
|
|
297
|
-
return
|
|
298
|
-
};
|
|
299
|
-
const isChannelRow = (value) => isRecord$1(value) && isChannelText(value.id) && isChannelText(value.name);
|
|
300
|
-
const isBundle = (value) => isRecord$1(value) && typeof value.id === "string" && (value.platform === "ios" || value.platform === "android") && typeof value.fileHash === "string" && typeof value.storageUri === "string" && isByteSize(value.archiveByteSize) && (value.patches === void 0 || value.patches === null || Array.isArray(value.patches) && value.patches.every(isBundlePatch));
|
|
301
|
-
const isPaginationInfo = (value) => isRecord$1(value) && isNonNegativeInteger(value.total) && typeof value.hasNextPage === "boolean" && typeof value.hasPreviousPage === "boolean" && isNonNegativeInteger(value.currentPage) && value.currentPage >= 1 && isNonNegativeInteger(value.totalPages);
|
|
302
|
-
const isPaginatedResult = (value) => isRecord$1(value) && Array.isArray(value.data) && value.data.every(isBundle) && isPaginationInfo(value.pagination);
|
|
303
|
-
const hasChannels = (value) => isRecord$1(value) && isRecord$1(value.data) && Array.isArray(value.data.channels) && value.data.channels.every(isChannelRow);
|
|
304
|
-
const hasChannelInsertResult = (value) => isRecord$1(value) && isRecord$1(value.data) && isChannelRow(value.data.row) && typeof value.data.inserted === "boolean";
|
|
305
|
-
const hasChannelDeleteResult = (value) => isRecord$1(value) && isRecord$1(value.data) && (value.data.deleted === true || value.data.deleted === false && (value.data.reason === "not_empty" || value.data.reason === "not_found"));
|
|
306
|
-
//#endregion
|
|
307
|
-
//#region src/standaloneRoutes.ts
|
|
308
|
-
function bundlePath(bundleId) {
|
|
309
|
-
return `/bundles/${encodeURIComponent(bundleId)}`;
|
|
310
|
-
}
|
|
311
|
-
function channelPath(channelId) {
|
|
312
|
-
return `/channels/${encodeURIComponent(channelId)}`;
|
|
313
|
-
}
|
|
314
|
-
const defaultRoutes$1 = {
|
|
315
|
-
create: () => ({ path: "/bundles" }),
|
|
316
|
-
update: (bundleId) => ({ path: bundlePath(bundleId) }),
|
|
317
|
-
list: () => ({
|
|
318
|
-
path: "/bundles",
|
|
319
|
-
headers: { "Cache-Control": "no-cache" }
|
|
320
|
-
}),
|
|
321
|
-
channels: () => ({
|
|
322
|
-
path: "/channels",
|
|
323
|
-
headers: { "Cache-Control": "no-cache" }
|
|
324
|
-
}),
|
|
325
|
-
deleteChannel: (channelId) => ({
|
|
326
|
-
path: channelPath(channelId),
|
|
327
|
-
headers: {}
|
|
328
|
-
}),
|
|
329
|
-
retrieve: (bundleId) => ({
|
|
330
|
-
path: bundlePath(bundleId),
|
|
331
|
-
headers: { Accept: "application/json" }
|
|
332
|
-
}),
|
|
333
|
-
delete: (bundleId) => ({ path: bundlePath(bundleId) })
|
|
76
|
+
return new StandaloneDatabaseError("request-failed", message, status);
|
|
334
77
|
};
|
|
335
|
-
const
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
}
|
|
78
|
+
const keysetParams = ({ order, after, limit }) => ({
|
|
79
|
+
v: String(2),
|
|
80
|
+
limit: String(limit),
|
|
81
|
+
...order === void 0 ? {} : { order },
|
|
82
|
+
...after === void 0 ? {} : { cursor: after }
|
|
341
83
|
});
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
deleteChannel: defaultRoutes$1.deleteChannel,
|
|
350
|
-
create: () => createRoute$1(defaultRoutes$1.create(), config.routes?.create?.()),
|
|
351
|
-
update: (bundleId) => createRoute$1(defaultRoutes$1.update(bundleId), config.routes?.update?.(bundleId)),
|
|
352
|
-
retrieve: (bundleId) => createRoute$1(defaultRoutes$1.retrieve(bundleId), config.routes?.retrieve?.(bundleId)),
|
|
353
|
-
delete: (bundleId) => createRoute$1(defaultRoutes$1.delete(bundleId), config.routes?.delete?.(bundleId))
|
|
354
|
-
};
|
|
355
|
-
const http = createStandaloneHttp(config);
|
|
356
|
-
const loadBundles = async () => {
|
|
357
|
-
const bundles = [];
|
|
358
|
-
for (let page = 1;; page += 1) {
|
|
359
|
-
const route = routes.list();
|
|
360
|
-
const url = new URL(http.buildUrl(route.path));
|
|
361
|
-
url.searchParams.set("limit", String(PAGE_SIZE));
|
|
362
|
-
url.searchParams.set("page", String(page));
|
|
363
|
-
const response = await fetch(url, {
|
|
364
|
-
method: "GET",
|
|
365
|
-
headers: http.headers(route.headers)
|
|
366
|
-
});
|
|
367
|
-
const value = await http.parseJson(response);
|
|
368
|
-
if (!isPaginatedResult(value)) throw new StandaloneDatabaseError("invalid-response", "Invalid bundle list response.", response.status);
|
|
369
|
-
bundles.push(...value.data);
|
|
370
|
-
if (value.data.length < PAGE_SIZE || value.pagination.hasNextPage === false || bundles.length >= value.pagination.total) return bundles;
|
|
371
|
-
}
|
|
372
|
-
};
|
|
373
|
-
const loadChannels = async () => {
|
|
374
|
-
const route = routes.channels();
|
|
375
|
-
const response = await fetch(http.buildUrl(route.path), {
|
|
376
|
-
method: "GET",
|
|
377
|
-
headers: http.headers(route.headers)
|
|
378
|
-
});
|
|
379
|
-
const value = await http.parseJson(response);
|
|
380
|
-
if (!hasChannels(value)) throw new StandaloneDatabaseError("invalid-response", "Invalid channels response.", response.status);
|
|
381
|
-
return value.data.channels;
|
|
382
|
-
};
|
|
383
|
-
const bundlesToRows = async (bundles) => bundles.map((bundle) => (0, _hot_updater_plugin_core.bundleToRow)(bundle));
|
|
384
|
-
const loadBundleWindow = async (input) => {
|
|
385
|
-
if (input.limit === 0) return {
|
|
386
|
-
rows: [],
|
|
387
|
-
total: 0
|
|
84
|
+
const filterParams = (filter) => {
|
|
85
|
+
switch (filter.kind) {
|
|
86
|
+
case "all": return {};
|
|
87
|
+
case "bundle": return { bundleId: filter.bundleId };
|
|
88
|
+
case "scope": return {
|
|
89
|
+
scopeKey: filter.scopeKey,
|
|
90
|
+
...filter.enabled === void 0 ? {} : { enabled: String(filter.enabled) }
|
|
388
91
|
};
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
if (input.orderBy !== void 0) url.searchParams.set("orderDirection", input.orderBy.direction);
|
|
394
|
-
const pageAligned = input.limit > 0 && input.offset % input.limit === 0;
|
|
395
|
-
const remoteLimit = pageAligned ? input.limit : input.offset + input.limit;
|
|
396
|
-
if (remoteLimit > PAGE_SIZE) return null;
|
|
397
|
-
url.searchParams.set("limit", String(remoteLimit));
|
|
398
|
-
url.searchParams.set("page", String(pageAligned ? input.offset / input.limit + 1 : 1));
|
|
399
|
-
const response = await fetch(url, {
|
|
400
|
-
method: "GET",
|
|
401
|
-
headers: http.headers(route.headers)
|
|
402
|
-
});
|
|
403
|
-
const value = await http.parseJson(response);
|
|
404
|
-
if (!isPaginatedResult(value)) throw new StandaloneDatabaseError("invalid-response", "Invalid bundle list response.", response.status);
|
|
405
|
-
const bundles = pageAligned ? value.data : value.data.slice(input.offset, input.offset + input.limit);
|
|
406
|
-
return {
|
|
407
|
-
rows: await bundlesToRows(bundles),
|
|
408
|
-
total: value.pagination.total
|
|
92
|
+
case "channelPlatform": return {
|
|
93
|
+
channelId: filter.channelId,
|
|
94
|
+
platform: filter.platform,
|
|
95
|
+
...filter.enabled === void 0 ? {} : { enabled: String(filter.enabled) }
|
|
409
96
|
};
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Core's API over a self-hosted server's admin handler, protocol 2: the CLI's
|
|
101
|
+
* path to a database it cannot open itself. The first call checks that the
|
|
102
|
+
* server speaks protocol 2, so an older server fails fast.
|
|
103
|
+
*/
|
|
104
|
+
const createStandaloneCoreApi = (config) => {
|
|
105
|
+
const http = createStandaloneHttp(config);
|
|
106
|
+
let checked;
|
|
107
|
+
const checkProtocol = async () => {
|
|
108
|
+
const response = await fetch(http.buildUrl("/version"), { headers: http.headers({ "Cache-Control": "no-cache" }) });
|
|
109
|
+
const body = response.status === 404 ? {} : await http.parseJson(response);
|
|
110
|
+
const protocol = isRecord(body) ? body.adminProtocol : void 0;
|
|
111
|
+
if (typeof protocol !== "number" || protocol < 2) throw new StandaloneDatabaseError("request-failed", `The server at ${config.baseUrl} speaks admin API protocol ${typeof protocol === "number" ? protocol : 1}, and this CLI needs 2. Upgrade @hot-updater/server on the server.`, response.status);
|
|
410
112
|
};
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
body: JSON.stringify(input)
|
|
113
|
+
/** 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 } = {}) => {
|
|
115
|
+
checked ??= checkProtocol().catch((error) => {
|
|
116
|
+
checked = void 0;
|
|
117
|
+
throw error;
|
|
417
118
|
});
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
const response = await fetch(http.buildUrl(route.path), {
|
|
426
|
-
method: "DELETE",
|
|
427
|
-
headers: http.headers(route.headers)
|
|
119
|
+
await checked;
|
|
120
|
+
const url = new URL(http.buildUrl(path));
|
|
121
|
+
for (const [key, value] of Object.entries(query)) url.searchParams.set(key, value);
|
|
122
|
+
const response = await fetch(url, {
|
|
123
|
+
method,
|
|
124
|
+
headers: http.headers(method === "GET" ? { "Cache-Control": "no-cache" } : void 0),
|
|
125
|
+
...body === void 0 ? {} : { body: JSON.stringify(body) }
|
|
428
126
|
});
|
|
429
|
-
if (response.status === 204) return
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
throw
|
|
127
|
+
if (response.status === 204) return null;
|
|
128
|
+
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);
|
|
130
|
+
if (!response.ok) {
|
|
131
|
+
const failure = await response.json().catch(() => null);
|
|
132
|
+
throw refusal(response.status, failure, `${method} ${path} failed with status ${response.status}.`);
|
|
435
133
|
}
|
|
436
|
-
if (!hasChannelDeleteResult(value)) throw new StandaloneDatabaseError("invalid-response", "Invalid Channel delete response.", response.status);
|
|
437
|
-
return value.data;
|
|
438
|
-
};
|
|
439
|
-
const loadBundle = async (bundleId) => {
|
|
440
|
-
const route = routes.retrieve(bundleId);
|
|
441
|
-
const response = await fetch(http.buildUrl(route.path), {
|
|
442
|
-
method: "GET",
|
|
443
|
-
headers: http.headers(route.headers)
|
|
444
|
-
});
|
|
445
|
-
if (response.status === 404) return null;
|
|
446
134
|
const value = await http.parseJson(response);
|
|
447
|
-
if (!
|
|
135
|
+
if (!isRecord(value)) throw new StandaloneDatabaseError("invalid-response", `The server answered ${method} ${path} with no JSON object.`, response.status);
|
|
448
136
|
return value;
|
|
449
137
|
};
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
const route = routes.update(bundle.id);
|
|
457
|
-
const response = await fetch(http.buildUrl(route.path), {
|
|
458
|
-
method: "PATCH",
|
|
459
|
-
headers: http.headers(route.headers),
|
|
460
|
-
body: JSON.stringify(bundle)
|
|
461
|
-
});
|
|
462
|
-
await http.parseJson(response);
|
|
463
|
-
};
|
|
464
|
-
const createBundles = async (bundles) => {
|
|
465
|
-
const route = routes.create();
|
|
466
|
-
const response = await fetch(http.buildUrl(route.path), {
|
|
467
|
-
method: "POST",
|
|
468
|
-
headers: http.headers(route.headers),
|
|
469
|
-
body: JSON.stringify(bundles)
|
|
470
|
-
});
|
|
471
|
-
await http.parseJson(response);
|
|
472
|
-
};
|
|
473
|
-
const deleteBundle = async (bundleId) => {
|
|
474
|
-
const route = routes.delete(bundleId);
|
|
475
|
-
const response = await fetch(http.buildUrl(route.path), {
|
|
476
|
-
method: "DELETE",
|
|
477
|
-
headers: http.headers(route.headers)
|
|
478
|
-
});
|
|
479
|
-
await http.parseJson(response);
|
|
480
|
-
};
|
|
481
|
-
return {
|
|
482
|
-
createBundle: (bundle) => createBundles([bundle]),
|
|
483
|
-
createBundles,
|
|
484
|
-
deleteBundle,
|
|
485
|
-
deleteChannel,
|
|
486
|
-
insertChannel,
|
|
487
|
-
loadBundle,
|
|
488
|
-
loadBundleRow,
|
|
489
|
-
loadBundleRows,
|
|
490
|
-
loadBundles,
|
|
491
|
-
loadBundleWindow,
|
|
492
|
-
loadChannels,
|
|
493
|
-
updateBundle
|
|
138
|
+
/** A request's `data`, or null when it found nothing. */
|
|
139
|
+
const call = async (...args) => {
|
|
140
|
+
const value = await request(...args);
|
|
141
|
+
if (value === null) return null;
|
|
142
|
+
if (!("data" in value)) throw new StandaloneDatabaseError("invalid-response", `The server answered ${args[0]} ${args[1]} without data.`);
|
|
143
|
+
return value.data;
|
|
494
144
|
};
|
|
495
|
-
};
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
499
|
-
const data = (value, message) => {
|
|
500
|
-
if (!isRecord(value) || !("data" in value)) throw new StandaloneDatabaseError("invalid-response", message);
|
|
501
|
-
return value.data;
|
|
502
|
-
};
|
|
503
|
-
const createStandaloneReleaseRemote = (config) => {
|
|
504
|
-
const http = createStandaloneHttp(config);
|
|
505
|
-
const headers = () => http.headers({ "Cache-Control": "no-cache" });
|
|
145
|
+
const list = async (path, query) => await call("GET", path, { query }) ?? [];
|
|
146
|
+
const v2 = { v: String(2) };
|
|
147
|
+
const encode = encodeURIComponent;
|
|
506
148
|
return {
|
|
507
|
-
async
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
149
|
+
ready: async () => {
|
|
150
|
+
await list("/release-catalogs", {
|
|
151
|
+
...v2,
|
|
152
|
+
limit: "1"
|
|
153
|
+
});
|
|
511
154
|
},
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
const
|
|
519
|
-
|
|
520
|
-
|
|
155
|
+
getBundle: (id) => call("GET", `/bundles/${encode(id)}`, { query: v2 }),
|
|
156
|
+
listBundles: ({ platform, ...input }) => list("/bundles", {
|
|
157
|
+
...keysetParams(input),
|
|
158
|
+
...platform === void 0 ? {} : { platform }
|
|
159
|
+
}),
|
|
160
|
+
countBundles: async (platform) => {
|
|
161
|
+
const total = await call("GET", "/bundles/count", { query: {
|
|
162
|
+
...v2,
|
|
163
|
+
...platform === void 0 ? {} : { platform }
|
|
164
|
+
} });
|
|
165
|
+
if (typeof total !== "number") throw new StandaloneDatabaseError("invalid-response", "The server answered a bundle count without a number.");
|
|
166
|
+
return total;
|
|
521
167
|
},
|
|
522
|
-
async
|
|
523
|
-
const
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
return rows;
|
|
168
|
+
countBundleChildren: async (baseBundleIds) => {
|
|
169
|
+
const ids = [...new Set(baseBundleIds)];
|
|
170
|
+
if (ids.length === 0) return {};
|
|
171
|
+
return await call("GET", "/bundles/child-counts", { query: {
|
|
172
|
+
...v2,
|
|
173
|
+
ids: ids.join(",")
|
|
174
|
+
} }) ?? {};
|
|
530
175
|
},
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
176
|
+
listPatchesFromBase: (baseBundleId, input) => list(`/bundles/${encode(baseBundleId)}/children`, keysetParams(input)),
|
|
177
|
+
findBaseBundleIds: (candidateKey, bundleId, limit) => list(`/base-candidates/${encode(candidateKey)}`, {
|
|
178
|
+
before: bundleId,
|
|
179
|
+
limit: String(limit)
|
|
180
|
+
}),
|
|
181
|
+
getRelease: (id) => call("GET", `/releases/${encode(id)}`),
|
|
182
|
+
listReleases: ({ filter, ...input }) => list("/releases", {
|
|
183
|
+
...keysetParams(input),
|
|
184
|
+
...filterParams(filter)
|
|
185
|
+
}),
|
|
186
|
+
getReleaseCatalogRow: (scopeKey) => call("GET", `/release-catalogs/${encode(scopeKey)}`),
|
|
187
|
+
listReleaseCatalogs: (input) => list("/release-catalogs", keysetParams(input)),
|
|
188
|
+
listChannels: () => list("/channels", v2),
|
|
189
|
+
findChannelByName: (name) => call("GET", "/channels", { query: {
|
|
190
|
+
...v2,
|
|
191
|
+
name
|
|
192
|
+
} }),
|
|
193
|
+
deploy: async (deployments) => await call("POST", "/releases", { body: { deployments } }),
|
|
194
|
+
updateReleasePolicy: async ({ releaseId, ...input }) => await call("PATCH", `/releases/${encode(releaseId)}`, { body: input }),
|
|
195
|
+
preflightReleasePolicy: async ({ releaseId, ...input }) => await call("POST", `/releases/${encode(releaseId)}/preflight`, { body: input }),
|
|
196
|
+
deleteRelease: async ({ releaseId, expectedRevision }) => await call("DELETE", `/releases/${encode(releaseId)}`, { query: {
|
|
197
|
+
confirm: releaseId,
|
|
198
|
+
...expectedRevision === void 0 ? {} : { expectedRevision: String(expectedRevision) }
|
|
199
|
+
} }),
|
|
200
|
+
promoteRelease: async ({ releaseId, ...input }) => await call("POST", `/releases/${encode(releaseId)}/promote`, { body: input }),
|
|
201
|
+
rebuildReleaseCatalog: async (scopeKey) => await call("POST", `/release-catalogs/${encode(scopeKey)}/rebuild`),
|
|
202
|
+
preflightReleaseCatalogRebuild: async (scopeKey) => await call("POST", `/release-catalogs/${encode(scopeKey)}/preflight`),
|
|
203
|
+
ensureChannel: async (name) => await call("POST", "/channels", {
|
|
204
|
+
query: v2,
|
|
205
|
+
body: { name }
|
|
206
|
+
}),
|
|
207
|
+
deleteChannel: async (id) => {
|
|
208
|
+
return await call("DELETE", `/channels/${encode(id)}`).catch((error) => {
|
|
209
|
+
if (error instanceof StandaloneDatabaseError && error.status === 409) return {
|
|
210
|
+
deleted: false,
|
|
211
|
+
reason: "not_empty"
|
|
212
|
+
};
|
|
213
|
+
if (error instanceof StandaloneDatabaseError && error.status === 404) return {
|
|
214
|
+
deleted: false,
|
|
215
|
+
reason: "not_found"
|
|
216
|
+
};
|
|
217
|
+
throw error;
|
|
218
|
+
}) ?? { deleted: true };
|
|
535
219
|
},
|
|
536
|
-
async
|
|
537
|
-
|
|
538
|
-
url.searchParams.set("limit", String(input.limit));
|
|
539
|
-
if (input.afterScopeKey !== void 0) url.searchParams.set("afterScopeKey", input.afterScopeKey);
|
|
540
|
-
const response = await fetch(url, { headers: headers() });
|
|
541
|
-
const rows = data(await http.parseJson(response), "Invalid Release catalog list response.");
|
|
542
|
-
if (!Array.isArray(rows)) throw new StandaloneDatabaseError("invalid-response", "Invalid Release catalog list response.", response.status);
|
|
543
|
-
return rows;
|
|
220
|
+
updateBundle: async (id, update) => {
|
|
221
|
+
await request("PATCH", `/bundles/${encode(id)}`, { body: update });
|
|
544
222
|
},
|
|
545
|
-
async
|
|
546
|
-
|
|
547
|
-
body: JSON.stringify(input),
|
|
548
|
-
headers: http.headers(),
|
|
549
|
-
method: "POST"
|
|
550
|
-
});
|
|
551
|
-
return data(await http.parseJson(response), "Invalid database commit response.");
|
|
223
|
+
deleteBundles: async (ids) => {
|
|
224
|
+
await request("POST", "/bundles/delete", { body: { ids } });
|
|
552
225
|
}
|
|
553
226
|
};
|
|
554
227
|
};
|
|
555
228
|
//#endregion
|
|
556
229
|
//#region src/standaloneRepository.ts
|
|
557
|
-
const toBundleWhere = (where) => {
|
|
558
|
-
if (!where) return [];
|
|
559
|
-
const filters = [];
|
|
560
|
-
if (where.platform !== void 0) filters.push({
|
|
561
|
-
field: "platform",
|
|
562
|
-
value: where.platform
|
|
563
|
-
});
|
|
564
|
-
if (where.id?.eq !== void 0) filters.push({
|
|
565
|
-
field: "id",
|
|
566
|
-
value: where.id.eq
|
|
567
|
-
});
|
|
568
|
-
if (where.id?.gt !== void 0) filters.push({
|
|
569
|
-
field: "id",
|
|
570
|
-
operator: "gt",
|
|
571
|
-
value: where.id.gt
|
|
572
|
-
});
|
|
573
|
-
if (where.id?.gte !== void 0) filters.push({
|
|
574
|
-
field: "id",
|
|
575
|
-
operator: "gte",
|
|
576
|
-
value: where.id.gte
|
|
577
|
-
});
|
|
578
|
-
if (where.id?.lt !== void 0) filters.push({
|
|
579
|
-
field: "id",
|
|
580
|
-
operator: "lt",
|
|
581
|
-
value: where.id.lt
|
|
582
|
-
});
|
|
583
|
-
if (where.id?.lte !== void 0) filters.push({
|
|
584
|
-
field: "id",
|
|
585
|
-
operator: "lte",
|
|
586
|
-
value: where.id.lte
|
|
587
|
-
});
|
|
588
|
-
if (where.id?.in !== void 0) filters.push({
|
|
589
|
-
field: "id",
|
|
590
|
-
operator: "in",
|
|
591
|
-
value: where.id.in
|
|
592
|
-
});
|
|
593
|
-
return filters;
|
|
594
|
-
};
|
|
595
230
|
/**
|
|
596
|
-
*
|
|
597
|
-
*
|
|
598
|
-
*
|
|
599
|
-
*
|
|
231
|
+
* A self-hosted server's database for the CLI and console: core's API over
|
|
232
|
+
* the server's admin API protocol 2, and GETs on its admin handler for the
|
|
233
|
+
* routes core does not cover, which its plugins serve. Plugins' tables belong
|
|
234
|
+
* to the server's own database.
|
|
600
235
|
*/
|
|
601
236
|
const standaloneRepository = (config) => {
|
|
602
|
-
const
|
|
603
|
-
const releaseRemote = createStandaloneReleaseRemote(config);
|
|
604
|
-
const bundleReader = createStandaloneBundleReader(remote);
|
|
237
|
+
const http = createStandaloneHttp(config);
|
|
605
238
|
return Object.freeze({
|
|
606
239
|
name: "standalone-repository",
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
async findById(id) {
|
|
610
|
-
return await bundleReader.findOne({
|
|
611
|
-
model: "bundles",
|
|
612
|
-
where: [{
|
|
613
|
-
field: "id",
|
|
614
|
-
value: id
|
|
615
|
-
}]
|
|
616
|
-
});
|
|
617
|
-
},
|
|
618
|
-
async findMany(query) {
|
|
619
|
-
return await bundleReader.findMany({
|
|
620
|
-
model: "bundles",
|
|
621
|
-
where: toBundleWhere(query.where),
|
|
622
|
-
limit: query.limit,
|
|
623
|
-
offset: query.offset,
|
|
624
|
-
orderBy: [query.orderBy]
|
|
625
|
-
});
|
|
626
|
-
},
|
|
627
|
-
count: (where) => bundleReader.count({
|
|
628
|
-
model: "bundles",
|
|
629
|
-
where: toBundleWhere(where)
|
|
630
|
-
})
|
|
631
|
-
},
|
|
632
|
-
bundlePatches: { async findByBundleIds(bundleIds) {
|
|
633
|
-
if (bundleIds.length === 0) return [];
|
|
634
|
-
return await bundleReader.findMany({
|
|
635
|
-
model: "bundle_patches",
|
|
636
|
-
where: [{
|
|
637
|
-
field: "bundle_id",
|
|
638
|
-
operator: "in",
|
|
639
|
-
value: bundleIds
|
|
640
|
-
}],
|
|
641
|
-
orderBy: [{
|
|
642
|
-
field: "id",
|
|
643
|
-
direction: "asc"
|
|
644
|
-
}],
|
|
645
|
-
limit: Number.MAX_SAFE_INTEGER,
|
|
646
|
-
offset: 0
|
|
647
|
-
});
|
|
648
|
-
} },
|
|
649
|
-
releases: {
|
|
650
|
-
findById: (id) => releaseRemote.findReleaseById(id),
|
|
651
|
-
findMany: (input) => releaseRemote.findReleases(input),
|
|
652
|
-
findManyByScope: (input) => releaseRemote.findReleasesByScope(input)
|
|
653
|
-
},
|
|
654
|
-
releaseCatalogs: {
|
|
655
|
-
findByScopeKey: (scopeKey) => releaseRemote.findCatalogByScopeKey(scopeKey),
|
|
656
|
-
findMany: (input) => releaseRemote.findCatalogs(input)
|
|
657
|
-
},
|
|
658
|
-
channels: {
|
|
659
|
-
insert: (input) => remote.insertChannel(input),
|
|
660
|
-
delete: (input) => remote.deleteChannel(input),
|
|
661
|
-
async list() {
|
|
662
|
-
return { channels: await remote.loadChannels() };
|
|
663
|
-
}
|
|
664
|
-
}
|
|
665
|
-
},
|
|
666
|
-
commit: (input) => releaseRemote.commit(input)
|
|
240
|
+
core: createStandaloneCoreApi(config),
|
|
241
|
+
fetchAdmin: (path) => fetch(http.buildUrl(path), { headers: http.headers({ "Cache-Control": "no-cache" }) })
|
|
667
242
|
});
|
|
668
243
|
};
|
|
669
244
|
//#endregion
|
|
@@ -705,7 +280,7 @@ const standaloneStorage = (config) => {
|
|
|
705
280
|
if (!response.ok && response.status !== 404) throw new Error(`Failed to ${routeName} storage object: ${response.statusText}`);
|
|
706
281
|
return response;
|
|
707
282
|
};
|
|
708
|
-
return (0, _hot_updater_plugin_core.
|
|
283
|
+
return (0, _hot_updater_plugin_core.createStorageAdapter)({
|
|
709
284
|
name: "standaloneStorage",
|
|
710
285
|
protocol: config.protocol,
|
|
711
286
|
async put({ key, body, contentType, contentLength }) {
|
|
@@ -746,6 +321,8 @@ const standaloneStorage = (config) => {
|
|
|
746
321
|
});
|
|
747
322
|
};
|
|
748
323
|
//#endregion
|
|
324
|
+
exports.STANDALONE_ADMIN_PROTOCOL = STANDALONE_ADMIN_PROTOCOL;
|
|
749
325
|
exports.StandaloneDatabaseError = StandaloneDatabaseError;
|
|
326
|
+
exports.createStandaloneCoreApi = createStandaloneCoreApi;
|
|
750
327
|
exports.standaloneRepository = standaloneRepository;
|
|
751
328
|
exports.standaloneStorage = standaloneStorage;
|