@hot-updater/cloudflare 1.0.0-rc.0 → 1.0.0-rc.2
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/iac/index.cjs +1 -1
- package/dist/iac/index.mjs +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/worker/index.cjs +1 -1
- package/dist/worker/index.mjs +1 -1
- package/package.json +5 -5
- package/src/d1Implementation.ts +1 -1
- package/src/d1Rows.spec.ts +3 -3
- package/src/worker/d1Database.spec.ts +1 -1
- package/worker/dist/README.md +1 -1
- package/worker/dist/index.js +319 -319
- package/worker/dist/index.js.map +4 -4
- package/worker/migrations/0001_hot-updater_1.0.0.sql +9 -1
- package/worker/src/databaseMigration.integration.spec.ts +39 -23
- package/worker/migrations/0002_hot-updater_artifact_byte_sizes.sql +0 -11
package/worker/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ var __defProp = Object.defineProperty;
|
|
|
2
2
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
3
|
|
|
4
4
|
// ../../packages/server/dist/package.mjs
|
|
5
|
-
var version = "1.0.0-rc.
|
|
5
|
+
var version = "1.0.0-rc.1";
|
|
6
6
|
|
|
7
7
|
// ../../packages/server/dist/version.mjs
|
|
8
8
|
var HOT_UPDATER_SERVER_VERSION = version;
|
|
@@ -13,262 +13,6 @@ var createVersionRouteHandlers = /* @__PURE__ */ __name(() => ({ version: /* @__
|
|
|
13
13
|
version: HOT_UPDATER_SERVER_VERSION
|
|
14
14
|
}), "version") }), "createVersionRouteHandlers");
|
|
15
15
|
|
|
16
|
-
// ../../packages/server/dist/analytics/errors.mjs
|
|
17
|
-
var AnalyticsScanLimitExceededError = class extends Error {
|
|
18
|
-
static {
|
|
19
|
-
__name(this, "AnalyticsScanLimitExceededError");
|
|
20
|
-
}
|
|
21
|
-
constructor(limit) {
|
|
22
|
-
super(`Analytics event scan exceeded ${limit} rows.`);
|
|
23
|
-
this.limit = limit;
|
|
24
|
-
this.name = "AnalyticsScanLimitExceededError";
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
var AnalyticsBadRequestError = class extends Error {
|
|
28
|
-
static {
|
|
29
|
-
__name(this, "AnalyticsBadRequestError");
|
|
30
|
-
}
|
|
31
|
-
name = "AnalyticsBadRequestError";
|
|
32
|
-
};
|
|
33
|
-
var AnalyticsPayloadTooLargeError = class extends Error {
|
|
34
|
-
static {
|
|
35
|
-
__name(this, "AnalyticsPayloadTooLargeError");
|
|
36
|
-
}
|
|
37
|
-
name = "AnalyticsPayloadTooLargeError";
|
|
38
|
-
constructor(maximumBytes) {
|
|
39
|
-
super(`Event payload exceeds ${maximumBytes} bytes`);
|
|
40
|
-
this.maximumBytes = maximumBytes;
|
|
41
|
-
}
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
// ../../packages/server/dist/analytics/eventInput.mjs
|
|
45
|
-
var MAX_EVENT_STRING_LENGTH = 1024;
|
|
46
|
-
var EVENT_BODY_MAX_BYTES = 16 * 1024;
|
|
47
|
-
var eventKeys = /* @__PURE__ */ new Set([
|
|
48
|
-
"type",
|
|
49
|
-
"installId",
|
|
50
|
-
"toBundleId",
|
|
51
|
-
"userId",
|
|
52
|
-
"username",
|
|
53
|
-
"platform",
|
|
54
|
-
"appVersion",
|
|
55
|
-
"channel",
|
|
56
|
-
"cohort",
|
|
57
|
-
"fingerprintHash",
|
|
58
|
-
"fromBundleId",
|
|
59
|
-
"fromReleaseId",
|
|
60
|
-
"toReleaseId",
|
|
61
|
-
"updateStrategy",
|
|
62
|
-
"sdkVersion"
|
|
63
|
-
]);
|
|
64
|
-
function isRecord(value) {
|
|
65
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
66
|
-
}
|
|
67
|
-
__name(isRecord, "isRecord");
|
|
68
|
-
function requireStringField(payload, key) {
|
|
69
|
-
const value = payload[key];
|
|
70
|
-
if (typeof value !== "string" || value.length === 0 || value.length > MAX_EVENT_STRING_LENGTH) throw new AnalyticsBadRequestError(`Invalid event field: ${key}`);
|
|
71
|
-
return value;
|
|
72
|
-
}
|
|
73
|
-
__name(requireStringField, "requireStringField");
|
|
74
|
-
function requireNullableStringField(payload, key) {
|
|
75
|
-
if (payload[key] === null) return null;
|
|
76
|
-
return requireStringField(payload, key);
|
|
77
|
-
}
|
|
78
|
-
__name(requireNullableStringField, "requireNullableStringField");
|
|
79
|
-
async function readBoundedText(request) {
|
|
80
|
-
const contentLength = request.headers.get("content-length");
|
|
81
|
-
const declaredByteLength = Number(contentLength);
|
|
82
|
-
if (contentLength !== null && Number.isSafeInteger(declaredByteLength) && declaredByteLength > 16384) throw new AnalyticsPayloadTooLargeError(EVENT_BODY_MAX_BYTES);
|
|
83
|
-
if (request.body === null) return "";
|
|
84
|
-
const reader = request.body.getReader();
|
|
85
|
-
const decoder = new TextDecoder();
|
|
86
|
-
let byteLength = 0;
|
|
87
|
-
let text = "";
|
|
88
|
-
while (true) {
|
|
89
|
-
const result = await reader.read();
|
|
90
|
-
if (result.done) break;
|
|
91
|
-
byteLength += result.value.byteLength;
|
|
92
|
-
if (byteLength > 16384) {
|
|
93
|
-
await reader.cancel();
|
|
94
|
-
throw new AnalyticsPayloadTooLargeError(EVENT_BODY_MAX_BYTES);
|
|
95
|
-
}
|
|
96
|
-
text += decoder.decode(result.value, { stream: true });
|
|
97
|
-
}
|
|
98
|
-
return text + decoder.decode();
|
|
99
|
-
}
|
|
100
|
-
__name(readBoundedText, "readBoundedText");
|
|
101
|
-
async function parseJson(request) {
|
|
102
|
-
const text = await readBoundedText(request);
|
|
103
|
-
try {
|
|
104
|
-
return JSON.parse(text);
|
|
105
|
-
} catch (error) {
|
|
106
|
-
if (error instanceof SyntaxError) throw new AnalyticsBadRequestError("Invalid event payload");
|
|
107
|
-
throw error;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
__name(parseJson, "parseJson");
|
|
111
|
-
function requireEvent(payload) {
|
|
112
|
-
if (!isRecord(payload) || Object.keys(payload).some((key) => !eventKeys.has(key))) throw new AnalyticsBadRequestError("Invalid event payload");
|
|
113
|
-
const platform = requireStringField(payload, "platform");
|
|
114
|
-
if (platform !== "ios" && platform !== "android") throw new AnalyticsBadRequestError("Invalid event field: platform");
|
|
115
|
-
const base = {
|
|
116
|
-
installId: requireStringField(payload, "installId"),
|
|
117
|
-
toBundleId: requireStringField(payload, "toBundleId"),
|
|
118
|
-
...payload.userId === void 0 ? {} : { userId: requireStringField(payload, "userId") },
|
|
119
|
-
...payload.username === void 0 ? {} : { username: requireStringField(payload, "username") },
|
|
120
|
-
platform,
|
|
121
|
-
appVersion: requireStringField(payload, "appVersion"),
|
|
122
|
-
channel: requireStringField(payload, "channel"),
|
|
123
|
-
cohort: requireStringField(payload, "cohort"),
|
|
124
|
-
fingerprintHash: requireNullableStringField(payload, "fingerprintHash"),
|
|
125
|
-
sdkVersion: payload.sdkVersion === void 0 ? null : requireNullableStringField(payload, "sdkVersion"),
|
|
126
|
-
fromReleaseId: requireNullableStringField(payload, "fromReleaseId"),
|
|
127
|
-
toReleaseId: requireNullableStringField(payload, "toReleaseId")
|
|
128
|
-
};
|
|
129
|
-
const type = requireStringField(payload, "type");
|
|
130
|
-
switch (type) {
|
|
131
|
-
case "UPDATE_APPLIED":
|
|
132
|
-
case "RECOVERED":
|
|
133
|
-
case "RELEASE_ADOPTED": {
|
|
134
|
-
const updateStrategy = requireStringField(payload, "updateStrategy");
|
|
135
|
-
if (updateStrategy !== "fingerprint" && updateStrategy !== "appVersion") throw new AnalyticsBadRequestError("Invalid event field: updateStrategy");
|
|
136
|
-
return {
|
|
137
|
-
...base,
|
|
138
|
-
type,
|
|
139
|
-
fromBundleId: requireStringField(payload, "fromBundleId"),
|
|
140
|
-
updateStrategy
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
case "UNCHANGED":
|
|
144
|
-
if (payload.fromBundleId !== null || payload.updateStrategy !== null) throw new AnalyticsBadRequestError("Invalid unchanged event shape");
|
|
145
|
-
return {
|
|
146
|
-
...base,
|
|
147
|
-
type,
|
|
148
|
-
fromBundleId: null,
|
|
149
|
-
updateStrategy: null
|
|
150
|
-
};
|
|
151
|
-
default:
|
|
152
|
-
throw new AnalyticsBadRequestError("Invalid event field: type");
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
__name(requireEvent, "requireEvent");
|
|
156
|
-
async function parseBundleEventRequest(request) {
|
|
157
|
-
return requireEvent(await parseJson(request));
|
|
158
|
-
}
|
|
159
|
-
__name(parseBundleEventRequest, "parseBundleEventRequest");
|
|
160
|
-
|
|
161
|
-
// ../../packages/server/dist/analytics/queryInput.mjs
|
|
162
|
-
var EVENT_LIST_BOUNDS = {
|
|
163
|
-
defaultValue: 50,
|
|
164
|
-
maximum: 100,
|
|
165
|
-
minimum: 1
|
|
166
|
-
};
|
|
167
|
-
var EVENT_LIST_OFFSET_BOUNDS = {
|
|
168
|
-
defaultValue: 0,
|
|
169
|
-
minimum: 0
|
|
170
|
-
};
|
|
171
|
-
var MAX_USER_ID_LENGTH = 1024;
|
|
172
|
-
function parseInteger(url, key, bounds) {
|
|
173
|
-
const value = url.searchParams.get(key);
|
|
174
|
-
if (value === null) return bounds.defaultValue;
|
|
175
|
-
const parsed = Number(value);
|
|
176
|
-
if (!Number.isSafeInteger(parsed) || parsed < bounds.minimum || bounds.maximum !== void 0 && parsed > bounds.maximum) throw new AnalyticsBadRequestError(`Invalid '${key}' query parameter.`);
|
|
177
|
-
return parsed;
|
|
178
|
-
}
|
|
179
|
-
__name(parseInteger, "parseInteger");
|
|
180
|
-
var parsePagination = /* @__PURE__ */ __name((request) => {
|
|
181
|
-
const url = new URL(request.url);
|
|
182
|
-
return {
|
|
183
|
-
limit: parseInteger(url, "limit", EVENT_LIST_BOUNDS),
|
|
184
|
-
offset: parseInteger(url, "offset", EVENT_LIST_OFFSET_BOUNDS)
|
|
185
|
-
};
|
|
186
|
-
}, "parsePagination");
|
|
187
|
-
var parseAnalyticsQuery = /* @__PURE__ */ __name((request) => {
|
|
188
|
-
const window = new URL(request.url).searchParams.get("window") ?? "24h";
|
|
189
|
-
if (window !== "24h" && window !== "7d" && window !== "30d" && window !== "all") throw new AnalyticsBadRequestError("Invalid 'window' query parameter.");
|
|
190
|
-
return {
|
|
191
|
-
...parsePagination(request),
|
|
192
|
-
window
|
|
193
|
-
};
|
|
194
|
-
}, "parseAnalyticsQuery");
|
|
195
|
-
var parseActiveInstallationInput = /* @__PURE__ */ __name((request) => {
|
|
196
|
-
const url = new URL(request.url);
|
|
197
|
-
const windows = url.searchParams.getAll("window");
|
|
198
|
-
if (windows.length > 1) throw new AnalyticsBadRequestError("Duplicate 'window' query parameter.");
|
|
199
|
-
const window = windows[0] ?? "30d";
|
|
200
|
-
if (window !== "24h" && window !== "7d" && window !== "30d") throw new AnalyticsBadRequestError("Invalid 'window' query parameter.");
|
|
201
|
-
const userIds = url.searchParams.getAll("userId");
|
|
202
|
-
if (userIds.length > 1) throw new AnalyticsBadRequestError("Duplicate 'userId' query parameter.");
|
|
203
|
-
const userId = userIds[0];
|
|
204
|
-
if (userId !== void 0 && (userId.length === 0 || userId.length > MAX_USER_ID_LENGTH)) throw new AnalyticsBadRequestError("Invalid 'userId' query parameter.");
|
|
205
|
-
return userId === void 0 ? { window } : {
|
|
206
|
-
window,
|
|
207
|
-
userId
|
|
208
|
-
};
|
|
209
|
-
}, "parseActiveInstallationInput");
|
|
210
|
-
var parseSearchInput = /* @__PURE__ */ __name((request) => ({
|
|
211
|
-
...parsePagination(request),
|
|
212
|
-
query: new URL(request.url).searchParams.get("query")?.trim() ?? ""
|
|
213
|
-
}), "parseSearchInput");
|
|
214
|
-
|
|
215
|
-
// ../../packages/server/dist/analytics/routes.mjs
|
|
216
|
-
var json = /* @__PURE__ */ __name((body, status) => Response.json(body, {
|
|
217
|
-
headers: { "cache-control": "private, no-store" },
|
|
218
|
-
status
|
|
219
|
-
}), "json");
|
|
220
|
-
var requireParam = /* @__PURE__ */ __name((params, key) => {
|
|
221
|
-
const value = params[key];
|
|
222
|
-
if (value === void 0 || value.length === 0) throw new AnalyticsBadRequestError(`Missing route parameter: ${key}`);
|
|
223
|
-
return value;
|
|
224
|
-
}, "requireParam");
|
|
225
|
-
var run = /* @__PURE__ */ __name(async (operation) => {
|
|
226
|
-
try {
|
|
227
|
-
return await operation();
|
|
228
|
-
} catch (error) {
|
|
229
|
-
if (error instanceof AnalyticsBadRequestError) return json({ error: error.message }, 400);
|
|
230
|
-
if (error instanceof AnalyticsPayloadTooLargeError) return json({ error: error.message }, 413);
|
|
231
|
-
if (error instanceof AnalyticsScanLimitExceededError) return json({ error: {
|
|
232
|
-
code: "ANALYTICS_SCAN_LIMIT_EXCEEDED",
|
|
233
|
-
limit: error.limit
|
|
234
|
-
} }, 503);
|
|
235
|
-
throw error;
|
|
236
|
-
}
|
|
237
|
-
}, "run");
|
|
238
|
-
var query = /* @__PURE__ */ __name((operation) => run(async () => json(await operation(), 200)), "query");
|
|
239
|
-
var createAnalyticsRouteHandlers = /* @__PURE__ */ __name((provider) => ({
|
|
240
|
-
appendBundleEvent: /* @__PURE__ */ __name(async (_params, request) => run(async () => {
|
|
241
|
-
await provider.appendBundleEvent(await parseBundleEventRequest(request));
|
|
242
|
-
return new Response(null, { status: 204 });
|
|
243
|
-
}), "appendBundleEvent"),
|
|
244
|
-
getBundleEventSummary: /* @__PURE__ */ __name((params) => query(() => provider.getBundleEventSummary(requireParam(params, "id"))), "getBundleEventSummary"),
|
|
245
|
-
getBundleEventAnalytics: /* @__PURE__ */ __name((params, request) => query(() => {
|
|
246
|
-
const input = parseAnalyticsQuery(request);
|
|
247
|
-
return provider.getBundleEventAnalytics(requireParam(params, "id"), input.window, input.limit, input.offset);
|
|
248
|
-
}), "getBundleEventAnalytics"),
|
|
249
|
-
getBundleEventOverview: /* @__PURE__ */ __name(() => query(() => provider.getBundleEventOverview()), "getBundleEventOverview"),
|
|
250
|
-
getActiveInstallationOverview: /* @__PURE__ */ __name((_params, request) => query(() => provider.getActiveInstallationOverview(parseActiveInstallationInput(request))), "getActiveInstallationOverview"),
|
|
251
|
-
searchInstallations: /* @__PURE__ */ __name((_params, request) => query(() => {
|
|
252
|
-
const input = parseSearchInput(request);
|
|
253
|
-
return provider.searchInstallations(input.query, input.limit, input.offset);
|
|
254
|
-
}), "searchInstallations"),
|
|
255
|
-
getInstallationHistory: /* @__PURE__ */ __name((params, request) => query(() => {
|
|
256
|
-
const input = parsePagination(request);
|
|
257
|
-
return provider.getInstallationHistory(requireParam(params, "installId"), input.limit, input.offset);
|
|
258
|
-
}), "getInstallationHistory")
|
|
259
|
-
}), "createAnalyticsRouteHandlers");
|
|
260
|
-
var registerAnalyticsClientRoutes = /* @__PURE__ */ __name((add) => {
|
|
261
|
-
add("POST", "/events", "appendBundleEvent");
|
|
262
|
-
}, "registerAnalyticsClientRoutes");
|
|
263
|
-
var registerAnalyticsAdminRoutes = /* @__PURE__ */ __name((add) => {
|
|
264
|
-
add("GET", "/bundles/:id/events/summary", "getBundleEventSummary");
|
|
265
|
-
add("GET", "/bundles/:id/events/analytics", "getBundleEventAnalytics");
|
|
266
|
-
add("GET", "/installations/overview", "getBundleEventOverview");
|
|
267
|
-
add("GET", "/installations/active", "getActiveInstallationOverview");
|
|
268
|
-
add("GET", "/installations", "searchInstallations");
|
|
269
|
-
add("GET", "/installations/:installId/events", "getInstallationHistory");
|
|
270
|
-
}, "registerAnalyticsAdminRoutes");
|
|
271
|
-
|
|
272
16
|
// ../../packages/server/dist/handlerErrors.mjs
|
|
273
17
|
var HandlerBadRequestError = class extends Error {
|
|
274
18
|
static {
|
|
@@ -986,7 +730,7 @@ var databaseFields = {
|
|
|
986
730
|
};
|
|
987
731
|
|
|
988
732
|
// ../plugin-core/dist/databasePluginCrudValidationFields.mjs
|
|
989
|
-
var
|
|
733
|
+
var isRecord = /* @__PURE__ */ __name((value) => typeof value === "object" && value !== null && !Array.isArray(value), "isRecord");
|
|
990
734
|
var isChannelText2 = /* @__PURE__ */ __name((value) => {
|
|
991
735
|
if (typeof value !== "string" || value.length === 0) return false;
|
|
992
736
|
let codePointCount = 0;
|
|
@@ -1272,7 +1016,7 @@ var hasValidReleaseInvariants = /* @__PURE__ */ __name((data) => {
|
|
|
1272
1016
|
}, "hasValidReleaseInvariants");
|
|
1273
1017
|
var hasValidBundleEventInvariants = /* @__PURE__ */ __name((data) => (data.type === "UPDATE_APPLIED" || data.type === "RECOVERED" || data.type === "RELEASE_ADOPTED") && typeof data.from_bundle_id === "string" && (data.update_strategy === "fingerprint" || data.update_strategy === "appVersion") || data.type === "UNCHANGED" && data.from_bundle_id === null && data.update_strategy === null, "hasValidBundleEventInvariants");
|
|
1274
1018
|
var validateCreateData = /* @__PURE__ */ __name((model, data) => {
|
|
1275
|
-
if (!
|
|
1019
|
+
if (!isRecord(data)) throw new DatabasePluginInputError("invalid-data");
|
|
1276
1020
|
validateFields(model, Object.keys(data));
|
|
1277
1021
|
for (const field of databaseFields[model]) {
|
|
1278
1022
|
const validator = modelValidators[model][field];
|
|
@@ -1289,7 +1033,7 @@ var selectRow = /* @__PURE__ */ __name((row, input) => {
|
|
|
1289
1033
|
return Object.fromEntries(select.map((field) => [field, Reflect.get(row, field)]));
|
|
1290
1034
|
}, "selectRow");
|
|
1291
1035
|
var validateResult = /* @__PURE__ */ __name((model, row, select) => {
|
|
1292
|
-
if (!
|
|
1036
|
+
if (!isRecord(row)) throw new DatabasePluginInputError("invalid-result");
|
|
1293
1037
|
const fields = select ?? databaseFields[model];
|
|
1294
1038
|
for (const field of fields) {
|
|
1295
1039
|
const validator = modelValidators[model][field];
|
|
@@ -1317,10 +1061,10 @@ var validateMutationWhere = /* @__PURE__ */ __name((where) => {
|
|
|
1317
1061
|
var validateUpdateWhere = /* @__PURE__ */ __name((model, where) => {
|
|
1318
1062
|
const selector = where[0];
|
|
1319
1063
|
const primaryField = model === "release_catalogs" ? "scope_key" : "id";
|
|
1320
|
-
if (where.length !== 1 || !
|
|
1064
|
+
if (where.length !== 1 || !isRecord(selector) || selector.field !== primaryField || selector.operator !== void 0 && selector.operator !== "eq" || typeof selector.value !== "string" || selector.connector !== void 0 || selector.mode !== void 0) throw new DatabasePluginInputError("invalid-update-selector");
|
|
1321
1065
|
}, "validateUpdateWhere");
|
|
1322
1066
|
var validateBundleUpdateData = /* @__PURE__ */ __name((update) => {
|
|
1323
|
-
if (!
|
|
1067
|
+
if (!isRecord(update)) throw new DatabasePluginInputError("invalid-data");
|
|
1324
1068
|
for (const [field, value] of Object.entries(update)) {
|
|
1325
1069
|
if (field === "id") throw new DatabasePluginInputError("invalid-data");
|
|
1326
1070
|
validateField("bundles", field);
|
|
@@ -1329,7 +1073,7 @@ var validateBundleUpdateData = /* @__PURE__ */ __name((update) => {
|
|
|
1329
1073
|
}
|
|
1330
1074
|
}, "validateBundleUpdateData");
|
|
1331
1075
|
var validateApiKeyUpdateData = /* @__PURE__ */ __name((update) => {
|
|
1332
|
-
if (!
|
|
1076
|
+
if (!isRecord(update) || Reflect.ownKeys(update).length !== 1 || !Object.hasOwn(update, "revoked_at_ms") || !modelValidators.api_keys.revoked_at_ms(Reflect.get(update, "revoked_at_ms"))) throw new DatabasePluginInputError("invalid-data");
|
|
1333
1077
|
}, "validateApiKeyUpdateData");
|
|
1334
1078
|
var RELEASE_MUTABLE_FIELDS = /* @__PURE__ */ new Set([
|
|
1335
1079
|
"revision",
|
|
@@ -1344,7 +1088,7 @@ var RELEASE_MUTABLE_FIELDS = /* @__PURE__ */ new Set([
|
|
|
1344
1088
|
"updated_at_ms"
|
|
1345
1089
|
]);
|
|
1346
1090
|
var validateReleaseUpdateData = /* @__PURE__ */ __name((update) => {
|
|
1347
|
-
if (!
|
|
1091
|
+
if (!isRecord(update) || Reflect.ownKeys(update).length === 0) throw new DatabasePluginInputError("invalid-data");
|
|
1348
1092
|
for (const [field, value] of Object.entries(update)) {
|
|
1349
1093
|
if (!RELEASE_MUTABLE_FIELDS.has(field)) throw new DatabasePluginInputError("invalid-data");
|
|
1350
1094
|
const validator = modelValidators.releases[field];
|
|
@@ -1352,7 +1096,7 @@ var validateReleaseUpdateData = /* @__PURE__ */ __name((update) => {
|
|
|
1352
1096
|
}
|
|
1353
1097
|
}, "validateReleaseUpdateData");
|
|
1354
1098
|
var validateReleaseCatalogUpdateData = /* @__PURE__ */ __name((update) => {
|
|
1355
|
-
if (!
|
|
1099
|
+
if (!isRecord(update)) throw new DatabasePluginInputError("invalid-data");
|
|
1356
1100
|
const expectedFields = Object.keys(modelValidators.release_catalogs).filter((field) => field !== "scope_key");
|
|
1357
1101
|
if (Reflect.ownKeys(update).length !== expectedFields.length || expectedFields.some((field) => !Object.hasOwn(update, field))) throw new DatabasePluginInputError("invalid-data");
|
|
1358
1102
|
for (const [field, value] of Object.entries(update)) {
|
|
@@ -1433,7 +1177,7 @@ var validateWhere = /* @__PURE__ */ __name((model, where) => {
|
|
|
1433
1177
|
if (where === void 0) return;
|
|
1434
1178
|
if (!Array.isArray(where)) throw new DatabasePluginInputError("invalid-query");
|
|
1435
1179
|
for (const item of where) {
|
|
1436
|
-
if (!
|
|
1180
|
+
if (!isRecord(item)) throw new DatabasePluginInputError("invalid-query");
|
|
1437
1181
|
if (item.connector !== void 0 && item.connector !== "AND" && item.connector !== "OR") throw new DatabasePluginInputError("invalid-query");
|
|
1438
1182
|
validateWhereValue(model, item);
|
|
1439
1183
|
}
|
|
@@ -1450,7 +1194,7 @@ var validateOrderBy = /* @__PURE__ */ __name((model, orderBy) => {
|
|
|
1450
1194
|
if (!Array.isArray(orderBy) || orderBy.length === 0) throw new DatabasePluginInputError("invalid-query");
|
|
1451
1195
|
const fields = /* @__PURE__ */ new Set();
|
|
1452
1196
|
return orderBy.map((clause) => {
|
|
1453
|
-
if (!
|
|
1197
|
+
if (!isRecord(clause) || typeof clause.field !== "string") throw new DatabasePluginInputError("invalid-query");
|
|
1454
1198
|
validateField(model, clause.field);
|
|
1455
1199
|
if (!sortableFields[model].has(clause.field)) throw new DatabasePluginInputError("invalid-query");
|
|
1456
1200
|
if (clause.direction !== "asc" && clause.direction !== "desc") throw new DatabasePluginInputError("invalid-query");
|
|
@@ -1462,7 +1206,7 @@ var validateOrderBy = /* @__PURE__ */ __name((model, orderBy) => {
|
|
|
1462
1206
|
}, "validateOrderBy");
|
|
1463
1207
|
var validateDistinctOn = /* @__PURE__ */ __name((model, distinctOn, orderBy) => {
|
|
1464
1208
|
if (distinctOn === void 0) return;
|
|
1465
|
-
if (!
|
|
1209
|
+
if (!isRecord(distinctOn)) throw new DatabasePluginInputError("invalid-distinct");
|
|
1466
1210
|
const fields = validateDistinctFields(model, distinctOn.fields);
|
|
1467
1211
|
if (fields === void 0 || orderBy === void 0) throw new DatabasePluginInputError("invalid-distinct");
|
|
1468
1212
|
for (const [index, field] of fields.entries()) if (orderBy[index]?.field !== field) throw new DatabasePluginInputError("invalid-distinct");
|
|
@@ -1476,7 +1220,7 @@ var validateBundlePagination = /* @__PURE__ */ __name((options) => {
|
|
|
1476
1220
|
if (!Number.isSafeInteger(options.limit) || options.limit <= 0 || options.page !== void 0 && (!Number.isSafeInteger(options.page) || options.page <= 0) || options.page !== void 0 && options.cursor !== void 0) throw new DatabasePluginInputError("invalid-pagination");
|
|
1477
1221
|
const cursor = options.cursor;
|
|
1478
1222
|
if (cursor === void 0) return;
|
|
1479
|
-
if (!
|
|
1223
|
+
if (!isRecord(cursor)) throw new DatabasePluginInputError("invalid-pagination");
|
|
1480
1224
|
const hasAfter = Object.hasOwn(cursor, "after");
|
|
1481
1225
|
if (hasAfter === Object.hasOwn(cursor, "before")) throw new DatabasePluginInputError("invalid-pagination");
|
|
1482
1226
|
const value = hasAfter ? cursor.after : cursor.before;
|
|
@@ -1832,7 +1576,7 @@ var applyChange = /* @__PURE__ */ __name(async (database, change, changeIndex) =
|
|
|
1832
1576
|
}
|
|
1833
1577
|
return;
|
|
1834
1578
|
}
|
|
1835
|
-
case "
|
|
1579
|
+
case "insights":
|
|
1836
1580
|
await database.create({
|
|
1837
1581
|
model: "bundle_events",
|
|
1838
1582
|
data: change.row
|
|
@@ -1910,10 +1654,10 @@ var hasOnlyKeys = /* @__PURE__ */ __name((value, keys) => {
|
|
|
1910
1654
|
return Reflect.ownKeys(value).length === keys.length && keys.every((key) => Object.hasOwn(value, key));
|
|
1911
1655
|
}, "hasOnlyKeys");
|
|
1912
1656
|
var validateWhere2 = /* @__PURE__ */ __name((where, field, validateValue = (value) => typeof value === "string") => {
|
|
1913
|
-
if (!
|
|
1657
|
+
if (!isRecord(where) || !hasOnlyKeys(where, [field]) || !validateValue(Reflect.get(where, field))) throw new DatabasePluginInputError("invalid-data");
|
|
1914
1658
|
}, "validateWhere");
|
|
1915
1659
|
var validateDatabaseChange = /* @__PURE__ */ __name((change) => {
|
|
1916
|
-
if (!
|
|
1660
|
+
if (!isRecord(change)) throw new DatabasePluginInputError("invalid-data");
|
|
1917
1661
|
switch (change.model) {
|
|
1918
1662
|
case "bundles":
|
|
1919
1663
|
switch (change.operation) {
|
|
@@ -2028,7 +1772,7 @@ var validateDatabaseChange = /* @__PURE__ */ __name((change) => {
|
|
|
2028
1772
|
default:
|
|
2029
1773
|
throw new DatabasePluginInputError("invalid-operation");
|
|
2030
1774
|
}
|
|
2031
|
-
case "
|
|
1775
|
+
case "insights":
|
|
2032
1776
|
if (change.operation !== "insert" || !hasOnlyKeys(change, [
|
|
2033
1777
|
"model",
|
|
2034
1778
|
"operation",
|
|
@@ -2055,7 +1799,7 @@ var validateDatabaseChange = /* @__PURE__ */ __name((change) => {
|
|
|
2055
1799
|
"update"
|
|
2056
1800
|
])) throw new DatabasePluginInputError("invalid-data");
|
|
2057
1801
|
validateWhere2(change.where, "id");
|
|
2058
|
-
if (!
|
|
1802
|
+
if (!isRecord(change.update)) throw new DatabasePluginInputError("invalid-data");
|
|
2059
1803
|
if (!hasOnlyKeys(change.update, ["revokedAtMs"])) throw new DatabasePluginInputError("invalid-data");
|
|
2060
1804
|
validateApiKeyUpdateData({ revoked_at_ms: change.update.revokedAtMs });
|
|
2061
1805
|
return;
|
|
@@ -2067,7 +1811,7 @@ var validateDatabaseChange = /* @__PURE__ */ __name((change) => {
|
|
|
2067
1811
|
}
|
|
2068
1812
|
}, "validateDatabaseChange");
|
|
2069
1813
|
var validateDatabaseCommitExpectation = /* @__PURE__ */ __name((expectation) => {
|
|
2070
|
-
if (!
|
|
1814
|
+
if (!isRecord(expectation)) throw new DatabasePluginInputError("invalid-data");
|
|
2071
1815
|
if (expectation.model === "releases") {
|
|
2072
1816
|
if (!hasOnlyKeys(expectation, [
|
|
2073
1817
|
"model",
|
|
@@ -2087,7 +1831,7 @@ var validateDatabaseCommitExpectation = /* @__PURE__ */ __name((expectation) =>
|
|
|
2087
1831
|
throw new DatabasePluginInputError("invalid-model");
|
|
2088
1832
|
}, "validateDatabaseCommitExpectation");
|
|
2089
1833
|
function validateDatabaseCommit(input) {
|
|
2090
|
-
if (!
|
|
1834
|
+
if (!isRecord(input) || !Array.isArray(input.changes) || (Object.hasOwn(input, "expectations") ? !hasOnlyKeys(input, ["changes", "expectations"]) || !Array.isArray(input.expectations) : !hasOnlyKeys(input, ["changes"]))) throw new DatabasePluginInputError("invalid-data");
|
|
2091
1835
|
input.changes.forEach(validateDatabaseChange);
|
|
2092
1836
|
if (Array.isArray(input.expectations)) input.expectations.forEach(validateDatabaseCommitExpectation);
|
|
2093
1837
|
}
|
|
@@ -2307,7 +2051,7 @@ var createDatabasePluginAdapter = /* @__PURE__ */ __name((name, implementation)
|
|
|
2307
2051
|
return result;
|
|
2308
2052
|
}
|
|
2309
2053
|
},
|
|
2310
|
-
|
|
2054
|
+
insights: {
|
|
2311
2055
|
async append(row) {
|
|
2312
2056
|
await crud.create({
|
|
2313
2057
|
model: "bundle_events",
|
|
@@ -4012,7 +3756,7 @@ var createReleaseCatalogRouteHandlers = /* @__PURE__ */ __name((clientAccessHead
|
|
|
4012
3756
|
|
|
4013
3757
|
// ../../packages/server/dist/handlerReleaseManagementRoutes.mjs
|
|
4014
3758
|
var unavailable = /* @__PURE__ */ __name(() => Response.json({ error: "Not found" }, { status: 404 }), "unavailable");
|
|
4015
|
-
var
|
|
3759
|
+
var isRecord2 = /* @__PURE__ */ __name((value) => typeof value === "object" && value !== null && !Array.isArray(value), "isRecord");
|
|
4016
3760
|
var parseRevision = /* @__PURE__ */ __name((value) => {
|
|
4017
3761
|
if (value === void 0 || value === null || value === "") return void 0;
|
|
4018
3762
|
const revision = typeof value === "number" ? value : Number(value);
|
|
@@ -4021,7 +3765,7 @@ var parseRevision = /* @__PURE__ */ __name((value) => {
|
|
|
4021
3765
|
}, "parseRevision");
|
|
4022
3766
|
var parsePolicyInput = /* @__PURE__ */ __name(async (request) => {
|
|
4023
3767
|
const body = await request.json();
|
|
4024
|
-
if (!
|
|
3768
|
+
if (!isRecord2(body) || !isRecord2(body.patch)) throw new HandlerBadRequestError("Invalid Release policy mutation");
|
|
4025
3769
|
return {
|
|
4026
3770
|
expectedRevision: parseRevision(body.expectedRevision),
|
|
4027
3771
|
patch: body.patch
|
|
@@ -4130,6 +3874,262 @@ var createReleaseManagementRouteHandlers = /* @__PURE__ */ __name(() => ({
|
|
|
4130
3874
|
}, "commitDatabase")
|
|
4131
3875
|
}), "createReleaseManagementRouteHandlers");
|
|
4132
3876
|
|
|
3877
|
+
// ../../packages/server/dist/insights/errors.mjs
|
|
3878
|
+
var InsightsScanLimitExceededError = class extends Error {
|
|
3879
|
+
static {
|
|
3880
|
+
__name(this, "InsightsScanLimitExceededError");
|
|
3881
|
+
}
|
|
3882
|
+
constructor(limit) {
|
|
3883
|
+
super(`Insights event scan exceeded ${limit} rows.`);
|
|
3884
|
+
this.limit = limit;
|
|
3885
|
+
this.name = "InsightsScanLimitExceededError";
|
|
3886
|
+
}
|
|
3887
|
+
};
|
|
3888
|
+
var InsightsBadRequestError = class extends Error {
|
|
3889
|
+
static {
|
|
3890
|
+
__name(this, "InsightsBadRequestError");
|
|
3891
|
+
}
|
|
3892
|
+
name = "InsightsBadRequestError";
|
|
3893
|
+
};
|
|
3894
|
+
var InsightsPayloadTooLargeError = class extends Error {
|
|
3895
|
+
static {
|
|
3896
|
+
__name(this, "InsightsPayloadTooLargeError");
|
|
3897
|
+
}
|
|
3898
|
+
name = "InsightsPayloadTooLargeError";
|
|
3899
|
+
constructor(maximumBytes) {
|
|
3900
|
+
super(`Event payload exceeds ${maximumBytes} bytes`);
|
|
3901
|
+
this.maximumBytes = maximumBytes;
|
|
3902
|
+
}
|
|
3903
|
+
};
|
|
3904
|
+
|
|
3905
|
+
// ../../packages/server/dist/insights/eventInput.mjs
|
|
3906
|
+
var MAX_EVENT_STRING_LENGTH = 1024;
|
|
3907
|
+
var EVENT_BODY_MAX_BYTES = 16 * 1024;
|
|
3908
|
+
var eventKeys = /* @__PURE__ */ new Set([
|
|
3909
|
+
"type",
|
|
3910
|
+
"installId",
|
|
3911
|
+
"toBundleId",
|
|
3912
|
+
"userId",
|
|
3913
|
+
"username",
|
|
3914
|
+
"platform",
|
|
3915
|
+
"appVersion",
|
|
3916
|
+
"channel",
|
|
3917
|
+
"cohort",
|
|
3918
|
+
"fingerprintHash",
|
|
3919
|
+
"fromBundleId",
|
|
3920
|
+
"fromReleaseId",
|
|
3921
|
+
"toReleaseId",
|
|
3922
|
+
"updateStrategy",
|
|
3923
|
+
"sdkVersion"
|
|
3924
|
+
]);
|
|
3925
|
+
function isRecord3(value) {
|
|
3926
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3927
|
+
}
|
|
3928
|
+
__name(isRecord3, "isRecord");
|
|
3929
|
+
function requireStringField(payload, key) {
|
|
3930
|
+
const value = payload[key];
|
|
3931
|
+
if (typeof value !== "string" || value.length === 0 || value.length > MAX_EVENT_STRING_LENGTH) throw new InsightsBadRequestError(`Invalid event field: ${key}`);
|
|
3932
|
+
return value;
|
|
3933
|
+
}
|
|
3934
|
+
__name(requireStringField, "requireStringField");
|
|
3935
|
+
function requireNullableStringField(payload, key) {
|
|
3936
|
+
if (payload[key] === null) return null;
|
|
3937
|
+
return requireStringField(payload, key);
|
|
3938
|
+
}
|
|
3939
|
+
__name(requireNullableStringField, "requireNullableStringField");
|
|
3940
|
+
async function readBoundedText(request) {
|
|
3941
|
+
const contentLength = request.headers.get("content-length");
|
|
3942
|
+
const declaredByteLength = Number(contentLength);
|
|
3943
|
+
if (contentLength !== null && Number.isSafeInteger(declaredByteLength) && declaredByteLength > 16384) throw new InsightsPayloadTooLargeError(EVENT_BODY_MAX_BYTES);
|
|
3944
|
+
if (request.body === null) return "";
|
|
3945
|
+
const reader = request.body.getReader();
|
|
3946
|
+
const decoder = new TextDecoder();
|
|
3947
|
+
let byteLength = 0;
|
|
3948
|
+
let text = "";
|
|
3949
|
+
while (true) {
|
|
3950
|
+
const result = await reader.read();
|
|
3951
|
+
if (result.done) break;
|
|
3952
|
+
byteLength += result.value.byteLength;
|
|
3953
|
+
if (byteLength > 16384) {
|
|
3954
|
+
await reader.cancel();
|
|
3955
|
+
throw new InsightsPayloadTooLargeError(EVENT_BODY_MAX_BYTES);
|
|
3956
|
+
}
|
|
3957
|
+
text += decoder.decode(result.value, { stream: true });
|
|
3958
|
+
}
|
|
3959
|
+
return text + decoder.decode();
|
|
3960
|
+
}
|
|
3961
|
+
__name(readBoundedText, "readBoundedText");
|
|
3962
|
+
async function parseJson(request) {
|
|
3963
|
+
const text = await readBoundedText(request);
|
|
3964
|
+
try {
|
|
3965
|
+
return JSON.parse(text);
|
|
3966
|
+
} catch (error) {
|
|
3967
|
+
if (error instanceof SyntaxError) throw new InsightsBadRequestError("Invalid event payload");
|
|
3968
|
+
throw error;
|
|
3969
|
+
}
|
|
3970
|
+
}
|
|
3971
|
+
__name(parseJson, "parseJson");
|
|
3972
|
+
function requireEvent(payload) {
|
|
3973
|
+
if (!isRecord3(payload) || Object.keys(payload).some((key) => !eventKeys.has(key))) throw new InsightsBadRequestError("Invalid event payload");
|
|
3974
|
+
const platform = requireStringField(payload, "platform");
|
|
3975
|
+
if (platform !== "ios" && platform !== "android") throw new InsightsBadRequestError("Invalid event field: platform");
|
|
3976
|
+
const base = {
|
|
3977
|
+
installId: requireStringField(payload, "installId"),
|
|
3978
|
+
toBundleId: requireStringField(payload, "toBundleId"),
|
|
3979
|
+
...payload.userId === void 0 ? {} : { userId: requireStringField(payload, "userId") },
|
|
3980
|
+
...payload.username === void 0 ? {} : { username: requireStringField(payload, "username") },
|
|
3981
|
+
platform,
|
|
3982
|
+
appVersion: requireStringField(payload, "appVersion"),
|
|
3983
|
+
channel: requireStringField(payload, "channel"),
|
|
3984
|
+
cohort: requireStringField(payload, "cohort"),
|
|
3985
|
+
fingerprintHash: requireNullableStringField(payload, "fingerprintHash"),
|
|
3986
|
+
sdkVersion: payload.sdkVersion === void 0 ? null : requireNullableStringField(payload, "sdkVersion"),
|
|
3987
|
+
fromReleaseId: requireNullableStringField(payload, "fromReleaseId"),
|
|
3988
|
+
toReleaseId: requireNullableStringField(payload, "toReleaseId")
|
|
3989
|
+
};
|
|
3990
|
+
const type = requireStringField(payload, "type");
|
|
3991
|
+
switch (type) {
|
|
3992
|
+
case "UPDATE_APPLIED":
|
|
3993
|
+
case "RECOVERED":
|
|
3994
|
+
case "RELEASE_ADOPTED": {
|
|
3995
|
+
const updateStrategy = requireStringField(payload, "updateStrategy");
|
|
3996
|
+
if (updateStrategy !== "fingerprint" && updateStrategy !== "appVersion") throw new InsightsBadRequestError("Invalid event field: updateStrategy");
|
|
3997
|
+
return {
|
|
3998
|
+
...base,
|
|
3999
|
+
type,
|
|
4000
|
+
fromBundleId: requireStringField(payload, "fromBundleId"),
|
|
4001
|
+
updateStrategy
|
|
4002
|
+
};
|
|
4003
|
+
}
|
|
4004
|
+
case "UNCHANGED":
|
|
4005
|
+
if (payload.fromBundleId !== null || payload.updateStrategy !== null) throw new InsightsBadRequestError("Invalid unchanged event shape");
|
|
4006
|
+
return {
|
|
4007
|
+
...base,
|
|
4008
|
+
type,
|
|
4009
|
+
fromBundleId: null,
|
|
4010
|
+
updateStrategy: null
|
|
4011
|
+
};
|
|
4012
|
+
default:
|
|
4013
|
+
throw new InsightsBadRequestError("Invalid event field: type");
|
|
4014
|
+
}
|
|
4015
|
+
}
|
|
4016
|
+
__name(requireEvent, "requireEvent");
|
|
4017
|
+
async function parseBundleEventRequest(request) {
|
|
4018
|
+
return requireEvent(await parseJson(request));
|
|
4019
|
+
}
|
|
4020
|
+
__name(parseBundleEventRequest, "parseBundleEventRequest");
|
|
4021
|
+
|
|
4022
|
+
// ../../packages/server/dist/insights/queryInput.mjs
|
|
4023
|
+
var EVENT_LIST_BOUNDS = {
|
|
4024
|
+
defaultValue: 50,
|
|
4025
|
+
maximum: 100,
|
|
4026
|
+
minimum: 1
|
|
4027
|
+
};
|
|
4028
|
+
var EVENT_LIST_OFFSET_BOUNDS = {
|
|
4029
|
+
defaultValue: 0,
|
|
4030
|
+
minimum: 0
|
|
4031
|
+
};
|
|
4032
|
+
var MAX_USER_ID_LENGTH = 1024;
|
|
4033
|
+
function parseInteger(url, key, bounds) {
|
|
4034
|
+
const value = url.searchParams.get(key);
|
|
4035
|
+
if (value === null) return bounds.defaultValue;
|
|
4036
|
+
const parsed = Number(value);
|
|
4037
|
+
if (!Number.isSafeInteger(parsed) || parsed < bounds.minimum || bounds.maximum !== void 0 && parsed > bounds.maximum) throw new InsightsBadRequestError(`Invalid '${key}' query parameter.`);
|
|
4038
|
+
return parsed;
|
|
4039
|
+
}
|
|
4040
|
+
__name(parseInteger, "parseInteger");
|
|
4041
|
+
var parsePagination = /* @__PURE__ */ __name((request) => {
|
|
4042
|
+
const url = new URL(request.url);
|
|
4043
|
+
return {
|
|
4044
|
+
limit: parseInteger(url, "limit", EVENT_LIST_BOUNDS),
|
|
4045
|
+
offset: parseInteger(url, "offset", EVENT_LIST_OFFSET_BOUNDS)
|
|
4046
|
+
};
|
|
4047
|
+
}, "parsePagination");
|
|
4048
|
+
var parseInsightsQuery = /* @__PURE__ */ __name((request) => {
|
|
4049
|
+
const window = new URL(request.url).searchParams.get("window") ?? "24h";
|
|
4050
|
+
if (window !== "24h" && window !== "7d" && window !== "30d" && window !== "all") throw new InsightsBadRequestError("Invalid 'window' query parameter.");
|
|
4051
|
+
return {
|
|
4052
|
+
...parsePagination(request),
|
|
4053
|
+
window
|
|
4054
|
+
};
|
|
4055
|
+
}, "parseInsightsQuery");
|
|
4056
|
+
var parseActiveInstallationInput = /* @__PURE__ */ __name((request) => {
|
|
4057
|
+
const url = new URL(request.url);
|
|
4058
|
+
const windows = url.searchParams.getAll("window");
|
|
4059
|
+
if (windows.length > 1) throw new InsightsBadRequestError("Duplicate 'window' query parameter.");
|
|
4060
|
+
const window = windows[0] ?? "30d";
|
|
4061
|
+
if (window !== "24h" && window !== "7d" && window !== "30d") throw new InsightsBadRequestError("Invalid 'window' query parameter.");
|
|
4062
|
+
const userIds = url.searchParams.getAll("userId");
|
|
4063
|
+
if (userIds.length > 1) throw new InsightsBadRequestError("Duplicate 'userId' query parameter.");
|
|
4064
|
+
const userId = userIds[0];
|
|
4065
|
+
if (userId !== void 0 && (userId.length === 0 || userId.length > MAX_USER_ID_LENGTH)) throw new InsightsBadRequestError("Invalid 'userId' query parameter.");
|
|
4066
|
+
return userId === void 0 ? { window } : {
|
|
4067
|
+
window,
|
|
4068
|
+
userId
|
|
4069
|
+
};
|
|
4070
|
+
}, "parseActiveInstallationInput");
|
|
4071
|
+
var parseSearchInput = /* @__PURE__ */ __name((request) => ({
|
|
4072
|
+
...parsePagination(request),
|
|
4073
|
+
query: new URL(request.url).searchParams.get("query")?.trim() ?? ""
|
|
4074
|
+
}), "parseSearchInput");
|
|
4075
|
+
|
|
4076
|
+
// ../../packages/server/dist/insights/routes.mjs
|
|
4077
|
+
var json = /* @__PURE__ */ __name((body, status) => Response.json(body, {
|
|
4078
|
+
headers: { "cache-control": "private, no-store" },
|
|
4079
|
+
status
|
|
4080
|
+
}), "json");
|
|
4081
|
+
var requireParam = /* @__PURE__ */ __name((params, key) => {
|
|
4082
|
+
const value = params[key];
|
|
4083
|
+
if (value === void 0 || value.length === 0) throw new InsightsBadRequestError(`Missing route parameter: ${key}`);
|
|
4084
|
+
return value;
|
|
4085
|
+
}, "requireParam");
|
|
4086
|
+
var run = /* @__PURE__ */ __name(async (operation) => {
|
|
4087
|
+
try {
|
|
4088
|
+
return await operation();
|
|
4089
|
+
} catch (error) {
|
|
4090
|
+
if (error instanceof InsightsBadRequestError) return json({ error: error.message }, 400);
|
|
4091
|
+
if (error instanceof InsightsPayloadTooLargeError) return json({ error: error.message }, 413);
|
|
4092
|
+
if (error instanceof InsightsScanLimitExceededError) return json({ error: {
|
|
4093
|
+
code: "INSIGHTS_SCAN_LIMIT_EXCEEDED",
|
|
4094
|
+
limit: error.limit
|
|
4095
|
+
} }, 503);
|
|
4096
|
+
throw error;
|
|
4097
|
+
}
|
|
4098
|
+
}, "run");
|
|
4099
|
+
var query = /* @__PURE__ */ __name((operation) => run(async () => json(await operation(), 200)), "query");
|
|
4100
|
+
var createInsightsRouteHandlers = /* @__PURE__ */ __name((provider) => ({
|
|
4101
|
+
appendBundleEvent: /* @__PURE__ */ __name(async (_params, request) => run(async () => {
|
|
4102
|
+
await provider.appendBundleEvent(await parseBundleEventRequest(request));
|
|
4103
|
+
return new Response(null, { status: 204 });
|
|
4104
|
+
}), "appendBundleEvent"),
|
|
4105
|
+
getBundleEventSummary: /* @__PURE__ */ __name((params) => query(() => provider.getBundleEventSummary(requireParam(params, "id"))), "getBundleEventSummary"),
|
|
4106
|
+
getBundleEventInsights: /* @__PURE__ */ __name((params, request) => query(() => {
|
|
4107
|
+
const input = parseInsightsQuery(request);
|
|
4108
|
+
return provider.getBundleEventInsights(requireParam(params, "id"), input.window, input.limit, input.offset);
|
|
4109
|
+
}), "getBundleEventInsights"),
|
|
4110
|
+
getBundleEventOverview: /* @__PURE__ */ __name(() => query(() => provider.getBundleEventOverview()), "getBundleEventOverview"),
|
|
4111
|
+
getActiveInstallationOverview: /* @__PURE__ */ __name((_params, request) => query(() => provider.getActiveInstallationOverview(parseActiveInstallationInput(request))), "getActiveInstallationOverview"),
|
|
4112
|
+
searchInstallations: /* @__PURE__ */ __name((_params, request) => query(() => {
|
|
4113
|
+
const input = parseSearchInput(request);
|
|
4114
|
+
return provider.searchInstallations(input.query, input.limit, input.offset);
|
|
4115
|
+
}), "searchInstallations"),
|
|
4116
|
+
getInstallationHistory: /* @__PURE__ */ __name((params, request) => query(() => {
|
|
4117
|
+
const input = parsePagination(request);
|
|
4118
|
+
return provider.getInstallationHistory(requireParam(params, "installId"), input.limit, input.offset);
|
|
4119
|
+
}), "getInstallationHistory")
|
|
4120
|
+
}), "createInsightsRouteHandlers");
|
|
4121
|
+
var registerInsightsClientRoutes = /* @__PURE__ */ __name((add) => {
|
|
4122
|
+
add("POST", "/events", "appendBundleEvent");
|
|
4123
|
+
}, "registerInsightsClientRoutes");
|
|
4124
|
+
var registerInsightsAdminRoutes = /* @__PURE__ */ __name((add) => {
|
|
4125
|
+
add("GET", "/bundles/:id/events/summary", "getBundleEventSummary");
|
|
4126
|
+
add("GET", "/bundles/:id/events/insights", "getBundleEventInsights");
|
|
4127
|
+
add("GET", "/installations/overview", "getBundleEventOverview");
|
|
4128
|
+
add("GET", "/installations/active", "getActiveInstallationOverview");
|
|
4129
|
+
add("GET", "/installations", "searchInstallations");
|
|
4130
|
+
add("GET", "/installations/:installId/events", "getInstallationHistory");
|
|
4131
|
+
}, "registerInsightsAdminRoutes");
|
|
4132
|
+
|
|
4133
4133
|
// ../../packages/server/dist/internalRouter.mjs
|
|
4134
4134
|
var normalizePath = /* @__PURE__ */ __name((path) => {
|
|
4135
4135
|
if (!path) return "/";
|
|
@@ -4239,13 +4239,13 @@ var createDownloadStorageRouteHandler = /* @__PURE__ */ __name((downloadStorageO
|
|
|
4239
4239
|
statusText: response.statusText
|
|
4240
4240
|
});
|
|
4241
4241
|
}, "createDownloadStorageRouteHandler");
|
|
4242
|
-
function createHotUpdaterHandlers(api,
|
|
4242
|
+
function createHotUpdaterHandlers(api, insights, apiKeyAuth, downloadStorageObject) {
|
|
4243
4243
|
const routeHandlers = {
|
|
4244
4244
|
...createVersionRouteHandlers(),
|
|
4245
4245
|
...createReleaseCatalogRouteHandlers(apiKeyAuth?.headerName),
|
|
4246
4246
|
...createReleaseManagementRouteHandlers(),
|
|
4247
4247
|
...createBundleRouteHandlers(),
|
|
4248
|
-
...
|
|
4248
|
+
...insights === void 0 ? {} : createInsightsRouteHandlers(insights),
|
|
4249
4249
|
...downloadStorageObject === void 0 ? {} : { downloadStorageObject: createDownloadStorageRouteHandler(downloadStorageObject) }
|
|
4250
4250
|
};
|
|
4251
4251
|
const clientRouter = createRouter();
|
|
@@ -4255,7 +4255,7 @@ function createHotUpdaterHandlers(api, analytics, apiKeyAuth, downloadStorageObj
|
|
|
4255
4255
|
addClientRoute("GET", "/release-catalogs/app-version/:platform/:channelKey/:appVersion", "appVersionReleaseCatalog");
|
|
4256
4256
|
addClientRoute("GET", "/release-catalogs/fingerprint/:platform/:channelKey/:fingerprintHash", "fingerprintReleaseCatalog");
|
|
4257
4257
|
addClientRoute("GET", "/artifacts/:targetBundleId/from/:currentBundleId", "artifact");
|
|
4258
|
-
if (
|
|
4258
|
+
if (insights !== void 0) registerInsightsClientRoutes(addClientRoute);
|
|
4259
4259
|
const adminRouter = createRouter();
|
|
4260
4260
|
const addAdminRoute = /* @__PURE__ */ __name((method, path, handler) => addRoute(adminRouter, method, path, handler), "addAdminRoute");
|
|
4261
4261
|
addAdminRoute("GET", "/releases/:id", "getRelease");
|
|
@@ -4275,7 +4275,7 @@ function createHotUpdaterHandlers(api, analytics, apiKeyAuth, downloadStorageObj
|
|
|
4275
4275
|
addAdminRoute("POST", "/bundles", "createBundles");
|
|
4276
4276
|
addAdminRoute("PATCH", "/bundles/:id", "updateBundle");
|
|
4277
4277
|
addAdminRoute("DELETE", "/bundles/:id", "deleteBundle");
|
|
4278
|
-
if (
|
|
4278
|
+
if (insights !== void 0) registerInsightsAdminRoutes(addAdminRoute);
|
|
4279
4279
|
return Object.freeze({
|
|
4280
4280
|
client: createRequestHandler({
|
|
4281
4281
|
api,
|
|
@@ -4293,7 +4293,7 @@ function createHotUpdaterHandlers(api, analytics, apiKeyAuth, downloadStorageObj
|
|
|
4293
4293
|
}
|
|
4294
4294
|
__name(createHotUpdaterHandlers, "createHotUpdaterHandlers");
|
|
4295
4295
|
|
|
4296
|
-
// ../../packages/server/dist/
|
|
4296
|
+
// ../../packages/server/dist/insights/bounded/activeOverview.mjs
|
|
4297
4297
|
var HOUR_MS = 3600 * 1e3;
|
|
4298
4298
|
var DAY_MS = 24 * HOUR_MS;
|
|
4299
4299
|
var ACTIVE_BUNDLE_EVENT_TYPES = [
|
|
@@ -4381,11 +4381,11 @@ function collectActiveInstallationOverview(request) {
|
|
|
4381
4381
|
}
|
|
4382
4382
|
__name(collectActiveInstallationOverview, "collectActiveInstallationOverview");
|
|
4383
4383
|
|
|
4384
|
-
// ../../packages/server/dist/
|
|
4385
|
-
var
|
|
4386
|
-
var
|
|
4387
|
-
var
|
|
4388
|
-
var
|
|
4384
|
+
// ../../packages/server/dist/insights/bounded/scan.mjs
|
|
4385
|
+
var INSIGHTS_SCAN_MAX_ROWS = 5e4;
|
|
4386
|
+
var INSIGHTS_MATERIALIZATION_LIMIT = INSIGHTS_SCAN_MAX_ROWS + 1;
|
|
4387
|
+
var INSIGHTS_SCAN_PAGE_SIZE = 1e3;
|
|
4388
|
+
var INSIGHTS_LOWER_BOUND_ID = "00000000-0000-0000-0000-000000000000";
|
|
4389
4389
|
var compareCodePoints2 = /* @__PURE__ */ __name((left, right) => {
|
|
4390
4390
|
if (left < right) return -1;
|
|
4391
4391
|
if (left > right) return 1;
|
|
@@ -4398,23 +4398,23 @@ var materializeEventRows = /* @__PURE__ */ __name(async (scope) => {
|
|
|
4398
4398
|
const seenIds = /* @__PURE__ */ new Set();
|
|
4399
4399
|
let after = scope.lowerBoundMs === void 0 ? void 0 : {
|
|
4400
4400
|
receivedAtMs: scope.lowerBoundMs,
|
|
4401
|
-
id:
|
|
4401
|
+
id: INSIGHTS_LOWER_BOUND_ID
|
|
4402
4402
|
};
|
|
4403
|
-
while (rows.length <
|
|
4404
|
-
const limit = Math.min(
|
|
4403
|
+
while (rows.length < INSIGHTS_MATERIALIZATION_LIMIT) {
|
|
4404
|
+
const limit = Math.min(INSIGHTS_SCAN_PAGE_SIZE, INSIGHTS_MATERIALIZATION_LIMIT - rows.length);
|
|
4405
4405
|
const page = await scope.persistence.scan({
|
|
4406
4406
|
beforeReceivedAtMs: scope.cutoffMs,
|
|
4407
4407
|
...after === void 0 ? {} : { after },
|
|
4408
4408
|
limit
|
|
4409
4409
|
});
|
|
4410
4410
|
if (page.length === 0) break;
|
|
4411
|
-
if (page.length > limit) throw new
|
|
4411
|
+
if (page.length > limit) throw new InsightsPersistenceOrderError();
|
|
4412
4412
|
let previous = after === void 0 ? void 0 : {
|
|
4413
4413
|
received_at_ms: after.receivedAtMs,
|
|
4414
4414
|
id: after.id
|
|
4415
4415
|
};
|
|
4416
4416
|
for (const row of page) {
|
|
4417
|
-
if (row.received_at_ms >= scope.cutoffMs || previous !== void 0 && compareEventOldest(previous, row) >= 0 || seenIds.has(row.id)) throw new
|
|
4417
|
+
if (row.received_at_ms >= scope.cutoffMs || previous !== void 0 && compareEventOldest(previous, row) >= 0 || seenIds.has(row.id)) throw new InsightsPersistenceOrderError();
|
|
4418
4418
|
seenIds.add(row.id);
|
|
4419
4419
|
rows.push(row);
|
|
4420
4420
|
previous = row;
|
|
@@ -4424,17 +4424,17 @@ var materializeEventRows = /* @__PURE__ */ __name(async (scope) => {
|
|
|
4424
4424
|
receivedAtMs: last.received_at_ms,
|
|
4425
4425
|
id: last.id
|
|
4426
4426
|
};
|
|
4427
|
-
if (rows.length > 5e4) throw new
|
|
4427
|
+
if (rows.length > 5e4) throw new InsightsScanLimitExceededError(INSIGHTS_SCAN_MAX_ROWS);
|
|
4428
4428
|
}
|
|
4429
4429
|
return rows;
|
|
4430
4430
|
}, "materializeEventRows");
|
|
4431
|
-
var
|
|
4431
|
+
var InsightsPersistenceOrderError = class extends Error {
|
|
4432
4432
|
static {
|
|
4433
|
-
__name(this, "
|
|
4433
|
+
__name(this, "InsightsPersistenceOrderError");
|
|
4434
4434
|
}
|
|
4435
|
-
name = "
|
|
4435
|
+
name = "InsightsPersistenceOrderError";
|
|
4436
4436
|
constructor() {
|
|
4437
|
-
super("
|
|
4437
|
+
super("Insights persistence did not advance its scan cursor.");
|
|
4438
4438
|
}
|
|
4439
4439
|
};
|
|
4440
4440
|
var materializeActiveRows = /* @__PURE__ */ __name(async (scope, window) => {
|
|
@@ -4519,7 +4519,7 @@ var collectEventActivity = /* @__PURE__ */ __name((request) => {
|
|
|
4519
4519
|
};
|
|
4520
4520
|
}, "collectEventActivity");
|
|
4521
4521
|
|
|
4522
|
-
// ../../packages/server/dist/
|
|
4522
|
+
// ../../packages/server/dist/insights/bounded/installationSearch.mjs
|
|
4523
4523
|
function toSearchRow(row) {
|
|
4524
4524
|
return {
|
|
4525
4525
|
installId: row.install_id,
|
|
@@ -4562,7 +4562,7 @@ function searchEventInstallations(request) {
|
|
|
4562
4562
|
}
|
|
4563
4563
|
__name(searchEventInstallations, "searchEventInstallations");
|
|
4564
4564
|
|
|
4565
|
-
// ../../packages/server/dist/
|
|
4565
|
+
// ../../packages/server/dist/insights/bounded/persistence.mjs
|
|
4566
4566
|
function createBundleEventRow(input) {
|
|
4567
4567
|
const base = {
|
|
4568
4568
|
id: createUUIDv7(),
|
|
@@ -4601,7 +4601,7 @@ function createBundleEventRow(input) {
|
|
|
4601
4601
|
}
|
|
4602
4602
|
__name(createBundleEventRow, "createBundleEventRow");
|
|
4603
4603
|
|
|
4604
|
-
// ../../packages/server/dist/
|
|
4604
|
+
// ../../packages/server/dist/insights/bounded/provider.mjs
|
|
4605
4605
|
var isTransitionEventRow = /* @__PURE__ */ __name((row) => row.type === "UPDATE_APPLIED" || row.type === "RECOVERED", "isTransitionEventRow");
|
|
4606
4606
|
var toHistoryRow = /* @__PURE__ */ __name((row) => ({
|
|
4607
4607
|
id: row.id,
|
|
@@ -4619,7 +4619,7 @@ var toHistoryRow = /* @__PURE__ */ __name((row) => ({
|
|
|
4619
4619
|
var isInstalledForBundle = /* @__PURE__ */ __name((row, bundleId) => row.type === "UPDATE_APPLIED" && row.to_bundle_id === bundleId, "isInstalledForBundle");
|
|
4620
4620
|
var isRecoveredFromBundle = /* @__PURE__ */ __name((row, bundleId) => row.type === "RECOVERED" && row.from_bundle_id === bundleId, "isRecoveredFromBundle");
|
|
4621
4621
|
var countDistinctInstallations = /* @__PURE__ */ __name((rows) => new Set(rows.map(({ install_id }) => install_id)).size, "countDistinctInstallations");
|
|
4622
|
-
var
|
|
4622
|
+
var getInsightsResult = /* @__PURE__ */ __name(async (persistence, bundleId, window, limit, offset) => {
|
|
4623
4623
|
const scope = {
|
|
4624
4624
|
persistence,
|
|
4625
4625
|
cutoffMs: Date.now()
|
|
@@ -4660,8 +4660,8 @@ var getAnalyticsResult = /* @__PURE__ */ __name(async (persistence, bundleId, wi
|
|
|
4660
4660
|
}
|
|
4661
4661
|
}
|
|
4662
4662
|
};
|
|
4663
|
-
}, "
|
|
4664
|
-
var
|
|
4663
|
+
}, "getInsightsResult");
|
|
4664
|
+
var getInsightsSummaries = /* @__PURE__ */ __name(async (persistence, bundleIds, window) => {
|
|
4665
4665
|
const normalizedBundleIds = [...new Set(bundleIds)];
|
|
4666
4666
|
if (normalizedBundleIds.length === 0) return [];
|
|
4667
4667
|
const requestedBundleIds = new Set(normalizedBundleIds);
|
|
@@ -4684,10 +4684,10 @@ var getAnalyticsSummaries = /* @__PURE__ */ __name(async (persistence, bundleIds
|
|
|
4684
4684
|
installed: installedByBundleId.get(bundleId)?.size ?? 0,
|
|
4685
4685
|
recovered: recoveredByBundleId.get(bundleId)?.size ?? 0
|
|
4686
4686
|
}));
|
|
4687
|
-
}, "
|
|
4688
|
-
var
|
|
4687
|
+
}, "getInsightsSummaries");
|
|
4688
|
+
var createInsightsProvider = /* @__PURE__ */ __name((persistence) => Object.freeze({
|
|
4689
4689
|
mode: "bounded",
|
|
4690
|
-
maxMatchingRows:
|
|
4690
|
+
maxMatchingRows: INSIGHTS_SCAN_MAX_ROWS,
|
|
4691
4691
|
async appendBundleEvent(input) {
|
|
4692
4692
|
await persistence.append(createBundleEventRow(input));
|
|
4693
4693
|
},
|
|
@@ -4702,10 +4702,10 @@ var createAnalyticsProvider = /* @__PURE__ */ __name((persistence) => Object.fre
|
|
|
4702
4702
|
};
|
|
4703
4703
|
},
|
|
4704
4704
|
getBundleEventSummaries(bundleIds, window) {
|
|
4705
|
-
return
|
|
4705
|
+
return getInsightsSummaries(persistence, bundleIds, window);
|
|
4706
4706
|
},
|
|
4707
|
-
|
|
4708
|
-
return
|
|
4707
|
+
getBundleEventInsights(bundleId, window, limit, offset) {
|
|
4708
|
+
return getInsightsResult(persistence, bundleId, window, limit, offset);
|
|
4709
4709
|
},
|
|
4710
4710
|
async getBundleEventOverview() {
|
|
4711
4711
|
const rows = await materializeEventRows({
|
|
@@ -4764,7 +4764,7 @@ var createAnalyticsProvider = /* @__PURE__ */ __name((persistence) => Object.fre
|
|
|
4764
4764
|
}
|
|
4765
4765
|
};
|
|
4766
4766
|
}
|
|
4767
|
-
}), "
|
|
4767
|
+
}), "createInsightsProvider");
|
|
4768
4768
|
|
|
4769
4769
|
// ../../packages/server/dist/apiKeys.mjs
|
|
4770
4770
|
var API_KEY_HEADER_NAME = "x-api-key";
|
|
@@ -5297,7 +5297,7 @@ var sqlProviders = [
|
|
|
5297
5297
|
var noSqlProviders = ["mongodb"];
|
|
5298
5298
|
[...sqlProviders, ...noSqlProviders];
|
|
5299
5299
|
function isDatabasePlugin(plugin) {
|
|
5300
|
-
return typeof plugin === "object" && plugin !== null && "name" in plugin && typeof plugin.name === "string" && "models" in plugin && typeof plugin.models === "object" && plugin.models !== null && "bundles" in plugin.models && typeof plugin.models.bundles === "object" && plugin.models.bundles !== null && "findById" in plugin.models.bundles && typeof plugin.models.bundles.findById === "function" && "findMany" in plugin.models.bundles && typeof plugin.models.bundles.findMany === "function" && "count" in plugin.models.bundles && typeof plugin.models.bundles.count === "function" && "bundlePatches" in plugin.models && typeof plugin.models.bundlePatches === "object" && plugin.models.bundlePatches !== null && "findByBundleIds" in plugin.models.bundlePatches && typeof plugin.models.bundlePatches.findByBundleIds === "function" && "channels" in plugin.models && typeof plugin.models.channels === "object" && plugin.models.channels !== null && "insert" in plugin.models.channels && typeof plugin.models.channels.insert === "function" && "list" in plugin.models.channels && typeof plugin.models.channels.list === "function" && "delete" in plugin.models.channels && typeof plugin.models.channels.delete === "function" && "
|
|
5300
|
+
return typeof plugin === "object" && plugin !== null && "name" in plugin && typeof plugin.name === "string" && "models" in plugin && typeof plugin.models === "object" && plugin.models !== null && "bundles" in plugin.models && typeof plugin.models.bundles === "object" && plugin.models.bundles !== null && "findById" in plugin.models.bundles && typeof plugin.models.bundles.findById === "function" && "findMany" in plugin.models.bundles && typeof plugin.models.bundles.findMany === "function" && "count" in plugin.models.bundles && typeof plugin.models.bundles.count === "function" && "bundlePatches" in plugin.models && typeof plugin.models.bundlePatches === "object" && plugin.models.bundlePatches !== null && "findByBundleIds" in plugin.models.bundlePatches && typeof plugin.models.bundlePatches.findByBundleIds === "function" && "channels" in plugin.models && typeof plugin.models.channels === "object" && plugin.models.channels !== null && "insert" in plugin.models.channels && typeof plugin.models.channels.insert === "function" && "list" in plugin.models.channels && typeof plugin.models.channels.list === "function" && "delete" in plugin.models.channels && typeof plugin.models.channels.delete === "function" && "insights" in plugin.models && typeof plugin.models.insights === "object" && plugin.models.insights !== null && "append" in plugin.models.insights && typeof plugin.models.insights.append === "function" && "scan" in plugin.models.insights && typeof plugin.models.insights.scan === "function" && "apiKeys" in plugin.models && typeof plugin.models.apiKeys === "object" && plugin.models.apiKeys !== null && "create" in plugin.models.apiKeys && typeof plugin.models.apiKeys.create === "function" && "findByHash" in plugin.models.apiKeys && typeof plugin.models.apiKeys.findByHash === "function" && "list" in plugin.models.apiKeys && typeof plugin.models.apiKeys.list === "function" && "revoke" in plugin.models.apiKeys && typeof plugin.models.apiKeys.revoke === "function" && "commit" in plugin && typeof plugin.commit === "function" && (!("dispose" in plugin) || plugin.dispose === void 0 || typeof plugin.dispose === "function");
|
|
5301
5301
|
}
|
|
5302
5302
|
__name(isDatabasePlugin, "isDatabasePlugin");
|
|
5303
5303
|
|
|
@@ -5414,21 +5414,21 @@ function createHotUpdaterCore(options) {
|
|
|
5414
5414
|
readStorageText
|
|
5415
5415
|
});
|
|
5416
5416
|
const clientAccess = normalizeClientAccess(options.clientAccess);
|
|
5417
|
-
const
|
|
5417
|
+
const insights = createInsightsProvider({
|
|
5418
5418
|
async append(row) {
|
|
5419
5419
|
await assertSchemaReady();
|
|
5420
|
-
return plugin.models.
|
|
5420
|
+
return plugin.models.insights.append(row);
|
|
5421
5421
|
},
|
|
5422
5422
|
async scan(input) {
|
|
5423
5423
|
await assertSchemaReady();
|
|
5424
|
-
return plugin.models.
|
|
5424
|
+
return plugin.models.insights.scan(input);
|
|
5425
5425
|
}
|
|
5426
5426
|
});
|
|
5427
5427
|
const apiKeys = createApiKeyManagement({
|
|
5428
5428
|
apiKeys: plugin.models.apiKeys,
|
|
5429
5429
|
beforeOperation: assertSchemaReady
|
|
5430
5430
|
});
|
|
5431
|
-
const handlers = createHotUpdaterHandlers(core.api,
|
|
5431
|
+
const handlers = createHotUpdaterHandlers(core.api, insights, clientAccess.type === "api-key" ? {
|
|
5432
5432
|
authenticate: /* @__PURE__ */ __name((request) => authenticateApiKey({
|
|
5433
5433
|
apiKeys: plugin.models.apiKeys,
|
|
5434
5434
|
beforeLookup: assertSchemaReady,
|
|
@@ -5439,7 +5439,7 @@ function createHotUpdaterCore(options) {
|
|
|
5439
5439
|
} : void 0, downloadStorageObject);
|
|
5440
5440
|
const api = Object.assign({
|
|
5441
5441
|
adapterName: adapterCapabilities.adapterName ?? core.adapterName,
|
|
5442
|
-
|
|
5442
|
+
insights,
|
|
5443
5443
|
apiKeys,
|
|
5444
5444
|
handlers
|
|
5445
5445
|
}, core.api);
|
|
@@ -8331,7 +8331,7 @@ var changeQuery = /* @__PURE__ */ __name((change, guard) => {
|
|
|
8331
8331
|
...guard.params
|
|
8332
8332
|
]
|
|
8333
8333
|
};
|
|
8334
|
-
case "
|
|
8334
|
+
case "insights":
|
|
8335
8335
|
return insertQuery({ model: "bundle_events", data: change.row }, guard);
|
|
8336
8336
|
case "apiKeys":
|
|
8337
8337
|
return change.operation === "insert" ? insertQuery(
|