@hot-updater/plugin-insights 1.0.0-rc.33 → 1.0.0-rc.35
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/client/index.cjs +2 -4
- package/dist/client/index.mjs +2 -4
- package/dist/server/domain.d.cts +1 -11
- package/dist/server/domain.d.mts +1 -11
- package/dist/server/eventInput.cjs +7 -31
- package/dist/server/eventInput.mjs +7 -31
- package/dist/server/eventRow.cjs +2 -2
- package/dist/server/eventRow.d.cts +0 -4
- package/dist/server/eventRow.d.mts +0 -4
- package/dist/server/eventRow.mjs +2 -2
- package/dist/server/index.cjs +1 -1
- package/dist/server/index.mjs +1 -1
- package/dist/server/provider.cjs +3 -5
- package/dist/server/provider.mjs +3 -5
- package/dist/server/reads.cjs +31 -46
- package/dist/server/reads.d.cts +0 -11
- package/dist/server/reads.d.mts +0 -11
- package/dist/server/reads.mjs +31 -46
- package/dist/server/recordEvent.cjs +0 -18
- package/dist/server/recordEvent.mjs +0 -18
- package/dist/server/schema.cjs +6 -8
- package/dist/server/schema.mjs +6 -8
- package/package.json +5 -5
package/dist/client/index.cjs
CHANGED
|
@@ -112,8 +112,7 @@ const insights = (options = {}) => {
|
|
|
112
112
|
fromReleaseId: result.fromReleaseId,
|
|
113
113
|
toBundleId: result.toBundleId,
|
|
114
114
|
toReleaseId: result.toReleaseId,
|
|
115
|
-
updateStrategy: result.updateStrategy
|
|
116
|
-
...result.status === "RECOVERED" && result.previousProcessExit !== null ? { metadata: { previousProcessExit: result.previousProcessExit } } : {}
|
|
115
|
+
updateStrategy: result.updateStrategy
|
|
117
116
|
}));
|
|
118
117
|
};
|
|
119
118
|
const onUpdateCheck = (result) => {
|
|
@@ -168,8 +167,7 @@ const insights = (options = {}) => {
|
|
|
168
167
|
...error.resource === void 0 ? {} : { resource: error.resource },
|
|
169
168
|
...error.httpStatus === void 0 ? {} : { httpStatus: error.httpStatus },
|
|
170
169
|
...error.transport === void 0 ? {} : { transport: error.transport },
|
|
171
|
-
...error.originCode === void 0 ? {} : { originCode: error.originCode }
|
|
172
|
-
...error.previousProcessExit === void 0 ? {} : { previousProcessExit: error.previousProcessExit }
|
|
170
|
+
...error.originCode === void 0 ? {} : { originCode: error.originCode }
|
|
173
171
|
} }
|
|
174
172
|
}, (now, installId) => require_eventId.createKeyedUUIDv7([
|
|
175
173
|
installId,
|
package/dist/client/index.mjs
CHANGED
|
@@ -111,8 +111,7 @@ const insights = (options = {}) => {
|
|
|
111
111
|
fromReleaseId: result.fromReleaseId,
|
|
112
112
|
toBundleId: result.toBundleId,
|
|
113
113
|
toReleaseId: result.toReleaseId,
|
|
114
|
-
updateStrategy: result.updateStrategy
|
|
115
|
-
...result.status === "RECOVERED" && result.previousProcessExit !== null ? { metadata: { previousProcessExit: result.previousProcessExit } } : {}
|
|
114
|
+
updateStrategy: result.updateStrategy
|
|
116
115
|
}));
|
|
117
116
|
};
|
|
118
117
|
const onUpdateCheck = (result) => {
|
|
@@ -167,8 +166,7 @@ const insights = (options = {}) => {
|
|
|
167
166
|
...error.resource === void 0 ? {} : { resource: error.resource },
|
|
168
167
|
...error.httpStatus === void 0 ? {} : { httpStatus: error.httpStatus },
|
|
169
168
|
...error.transport === void 0 ? {} : { transport: error.transport },
|
|
170
|
-
...error.originCode === void 0 ? {} : { originCode: error.originCode }
|
|
171
|
-
...error.previousProcessExit === void 0 ? {} : { previousProcessExit: error.previousProcessExit }
|
|
169
|
+
...error.originCode === void 0 ? {} : { originCode: error.originCode }
|
|
172
170
|
} }
|
|
173
171
|
}, (now, installId) => createKeyedUUIDv7([
|
|
174
172
|
installId,
|
package/dist/server/domain.d.cts
CHANGED
|
@@ -18,8 +18,6 @@ type BundleEventFailureInput = {
|
|
|
18
18
|
/** Original client error text, bounded to fit the event payload. */
|
|
19
19
|
readonly errorMessage?: string;
|
|
20
20
|
readonly errorStack?: string;
|
|
21
|
-
/** Android's `ApplicationExitInfo` reason for the process before this one. */
|
|
22
|
-
readonly previousProcessExit?: string;
|
|
23
21
|
};
|
|
24
22
|
/**
|
|
25
23
|
* The body of `POST /events`. Fields the server does not know are ignored, so
|
|
@@ -62,13 +60,7 @@ type CreateBundleEventRequest = (Movement & {
|
|
|
62
60
|
readonly patchFallback?: true;
|
|
63
61
|
};
|
|
64
62
|
}) | (Movement & {
|
|
65
|
-
readonly type: "UPDATE_APPLIED";
|
|
66
|
-
}) | (Movement & {
|
|
67
|
-
readonly type: "RECOVERED";
|
|
68
|
-
readonly metadata?: {
|
|
69
|
-
/** Android's `ApplicationExitInfo` reason for the crashed process. */
|
|
70
|
-
readonly previousProcessExit?: string;
|
|
71
|
-
};
|
|
63
|
+
readonly type: "UPDATE_APPLIED" | "RECOVERED";
|
|
72
64
|
}) | (Movement & {
|
|
73
65
|
/**
|
|
74
66
|
* An update check, download, or install that failed: `fromBundleId`
|
|
@@ -105,8 +97,6 @@ type EventHistoryRow = {
|
|
|
105
97
|
readonly delivery?: NonNullable<DatabaseBundleEventMetadata["delivery"]>;
|
|
106
98
|
/** `UPDATE_DOWNLOADED`: a patch failed, and the files or the archive came instead. */
|
|
107
99
|
readonly patchFallback?: true;
|
|
108
|
-
/** `RECOVERED`: Android's reason the crashed process exited. */
|
|
109
|
-
readonly previousProcessExit?: string;
|
|
110
100
|
};
|
|
111
101
|
type InstallationHistoryRow = EventHistoryRow & {
|
|
112
102
|
readonly type: "UPDATE_DOWNLOADED" | "UPDATE_APPLIED" | "RECOVERED" | "UPDATE_FAILED";
|
package/dist/server/domain.d.mts
CHANGED
|
@@ -18,8 +18,6 @@ type BundleEventFailureInput = {
|
|
|
18
18
|
/** Original client error text, bounded to fit the event payload. */
|
|
19
19
|
readonly errorMessage?: string;
|
|
20
20
|
readonly errorStack?: string;
|
|
21
|
-
/** Android's `ApplicationExitInfo` reason for the process before this one. */
|
|
22
|
-
readonly previousProcessExit?: string;
|
|
23
21
|
};
|
|
24
22
|
/**
|
|
25
23
|
* The body of `POST /events`. Fields the server does not know are ignored, so
|
|
@@ -62,13 +60,7 @@ type CreateBundleEventRequest = (Movement & {
|
|
|
62
60
|
readonly patchFallback?: true;
|
|
63
61
|
};
|
|
64
62
|
}) | (Movement & {
|
|
65
|
-
readonly type: "UPDATE_APPLIED";
|
|
66
|
-
}) | (Movement & {
|
|
67
|
-
readonly type: "RECOVERED";
|
|
68
|
-
readonly metadata?: {
|
|
69
|
-
/** Android's `ApplicationExitInfo` reason for the crashed process. */
|
|
70
|
-
readonly previousProcessExit?: string;
|
|
71
|
-
};
|
|
63
|
+
readonly type: "UPDATE_APPLIED" | "RECOVERED";
|
|
72
64
|
}) | (Movement & {
|
|
73
65
|
/**
|
|
74
66
|
* An update check, download, or install that failed: `fromBundleId`
|
|
@@ -105,8 +97,6 @@ type EventHistoryRow = {
|
|
|
105
97
|
readonly delivery?: NonNullable<DatabaseBundleEventMetadata["delivery"]>;
|
|
106
98
|
/** `UPDATE_DOWNLOADED`: a patch failed, and the files or the archive came instead. */
|
|
107
99
|
readonly patchFallback?: true;
|
|
108
|
-
/** `RECOVERED`: Android's reason the crashed process exited. */
|
|
109
|
-
readonly previousProcessExit?: string;
|
|
110
100
|
};
|
|
111
101
|
type InstallationHistoryRow = EventHistoryRow & {
|
|
112
102
|
readonly type: "UPDATE_DOWNLOADED" | "UPDATE_APPLIED" | "RECOVERED" | "UPDATE_FAILED";
|
|
@@ -69,7 +69,7 @@ const DELIVERIES = [
|
|
|
69
69
|
"manifest",
|
|
70
70
|
"archive"
|
|
71
71
|
];
|
|
72
|
-
/** A storage error code
|
|
72
|
+
/** A storage error code: letters, digits, and `._-`. */
|
|
73
73
|
const CODE = /^[A-Za-z0-9._-]{1,64}$/;
|
|
74
74
|
const readCode = (value) => typeof value === "string" && CODE.test(value) ? value : void 0;
|
|
75
75
|
const readMetadata = (payload) => isRecord(payload.metadata) ? payload.metadata : {};
|
|
@@ -85,7 +85,6 @@ function readFailure(value) {
|
|
|
85
85
|
const originCode = readCode(failure.originCode);
|
|
86
86
|
const errorMessage = typeof failure.errorMessage === "string" && failure.errorMessage.length <= 2048 ? failure.errorMessage : void 0;
|
|
87
87
|
const errorStack = typeof failure.errorStack === "string" && failure.errorStack.length <= 4096 ? failure.errorStack : void 0;
|
|
88
|
-
const previousProcessExit = readCode(failure.previousProcessExit);
|
|
89
88
|
return {
|
|
90
89
|
stage: oneOf(STAGES, failure.stage),
|
|
91
90
|
reason: oneOf(REASONS, failure.reason),
|
|
@@ -94,8 +93,7 @@ function readFailure(value) {
|
|
|
94
93
|
...failure.transport == null ? {} : { transport: oneOf(TRANSPORTS, failure.transport) },
|
|
95
94
|
...originCode === void 0 ? {} : { originCode },
|
|
96
95
|
...errorMessage === void 0 ? {} : { errorMessage },
|
|
97
|
-
...errorStack === void 0 ? {} : { errorStack }
|
|
98
|
-
...previousProcessExit === void 0 ? {} : { previousProcessExit }
|
|
96
|
+
...errorStack === void 0 ? {} : { errorStack }
|
|
99
97
|
};
|
|
100
98
|
}
|
|
101
99
|
function readHttpResponse(value) {
|
|
@@ -185,21 +183,11 @@ function requireEvent(payload) {
|
|
|
185
183
|
...Object.keys(read).length === 0 ? {} : { metadata: read }
|
|
186
184
|
};
|
|
187
185
|
}
|
|
188
|
-
case "UPDATE_APPLIED":
|
|
186
|
+
case "UPDATE_APPLIED":
|
|
187
|
+
case "RECOVERED": return {
|
|
189
188
|
...movement(),
|
|
190
189
|
type
|
|
191
190
|
};
|
|
192
|
-
case "RECOVERED": {
|
|
193
|
-
const previousProcessExit = readCode(metadata.previousProcessExit);
|
|
194
|
-
return {
|
|
195
|
-
...movement(),
|
|
196
|
-
type,
|
|
197
|
-
...previousProcessExit === void 0 ? {} : { metadata: {
|
|
198
|
-
...httpMetadata,
|
|
199
|
-
previousProcessExit
|
|
200
|
-
} }
|
|
201
|
-
};
|
|
202
|
-
}
|
|
203
191
|
case "UPDATE_FAILED": return {
|
|
204
192
|
...movement(),
|
|
205
193
|
type,
|
|
@@ -265,24 +253,13 @@ function createBundleEventRow(input) {
|
|
|
265
253
|
}
|
|
266
254
|
};
|
|
267
255
|
}
|
|
268
|
-
case "UPDATE_APPLIED":
|
|
256
|
+
case "UPDATE_APPLIED":
|
|
257
|
+
case "RECOVERED": return {
|
|
269
258
|
...base,
|
|
270
259
|
from_bundle_id: input.fromBundleId,
|
|
271
260
|
type: input.type,
|
|
272
261
|
metadata
|
|
273
262
|
};
|
|
274
|
-
case "RECOVERED": {
|
|
275
|
-
const exit = input.metadata?.previousProcessExit;
|
|
276
|
-
return {
|
|
277
|
-
...base,
|
|
278
|
-
from_bundle_id: input.fromBundleId,
|
|
279
|
-
type: input.type,
|
|
280
|
-
metadata: {
|
|
281
|
-
...metadata,
|
|
282
|
-
...exit === void 0 ? {} : { previous_process_exit: exit }
|
|
283
|
-
}
|
|
284
|
-
};
|
|
285
|
-
}
|
|
286
263
|
case "UPDATE_FAILED": {
|
|
287
264
|
const { failure } = input.metadata;
|
|
288
265
|
return {
|
|
@@ -299,8 +276,7 @@ function createBundleEventRow(input) {
|
|
|
299
276
|
...failure.resource === void 0 ? {} : { resource: failure.resource },
|
|
300
277
|
...failure.httpStatus === void 0 ? {} : { http_status: failure.httpStatus },
|
|
301
278
|
...failure.transport === void 0 ? {} : { transport: failure.transport },
|
|
302
|
-
...failure.originCode === void 0 ? {} : { origin_code: failure.originCode }
|
|
303
|
-
...failure.previousProcessExit === void 0 ? {} : { previous_process_exit: failure.previousProcessExit }
|
|
279
|
+
...failure.originCode === void 0 ? {} : { origin_code: failure.originCode }
|
|
304
280
|
}
|
|
305
281
|
}
|
|
306
282
|
};
|
|
@@ -69,7 +69,7 @@ const DELIVERIES = [
|
|
|
69
69
|
"manifest",
|
|
70
70
|
"archive"
|
|
71
71
|
];
|
|
72
|
-
/** A storage error code
|
|
72
|
+
/** A storage error code: letters, digits, and `._-`. */
|
|
73
73
|
const CODE = /^[A-Za-z0-9._-]{1,64}$/;
|
|
74
74
|
const readCode = (value) => typeof value === "string" && CODE.test(value) ? value : void 0;
|
|
75
75
|
const readMetadata = (payload) => isRecord(payload.metadata) ? payload.metadata : {};
|
|
@@ -85,7 +85,6 @@ function readFailure(value) {
|
|
|
85
85
|
const originCode = readCode(failure.originCode);
|
|
86
86
|
const errorMessage = typeof failure.errorMessage === "string" && failure.errorMessage.length <= 2048 ? failure.errorMessage : void 0;
|
|
87
87
|
const errorStack = typeof failure.errorStack === "string" && failure.errorStack.length <= 4096 ? failure.errorStack : void 0;
|
|
88
|
-
const previousProcessExit = readCode(failure.previousProcessExit);
|
|
89
88
|
return {
|
|
90
89
|
stage: oneOf(STAGES, failure.stage),
|
|
91
90
|
reason: oneOf(REASONS, failure.reason),
|
|
@@ -94,8 +93,7 @@ function readFailure(value) {
|
|
|
94
93
|
...failure.transport == null ? {} : { transport: oneOf(TRANSPORTS, failure.transport) },
|
|
95
94
|
...originCode === void 0 ? {} : { originCode },
|
|
96
95
|
...errorMessage === void 0 ? {} : { errorMessage },
|
|
97
|
-
...errorStack === void 0 ? {} : { errorStack }
|
|
98
|
-
...previousProcessExit === void 0 ? {} : { previousProcessExit }
|
|
96
|
+
...errorStack === void 0 ? {} : { errorStack }
|
|
99
97
|
};
|
|
100
98
|
}
|
|
101
99
|
function readHttpResponse(value) {
|
|
@@ -185,21 +183,11 @@ function requireEvent(payload) {
|
|
|
185
183
|
...Object.keys(read).length === 0 ? {} : { metadata: read }
|
|
186
184
|
};
|
|
187
185
|
}
|
|
188
|
-
case "UPDATE_APPLIED":
|
|
186
|
+
case "UPDATE_APPLIED":
|
|
187
|
+
case "RECOVERED": return {
|
|
189
188
|
...movement(),
|
|
190
189
|
type
|
|
191
190
|
};
|
|
192
|
-
case "RECOVERED": {
|
|
193
|
-
const previousProcessExit = readCode(metadata.previousProcessExit);
|
|
194
|
-
return {
|
|
195
|
-
...movement(),
|
|
196
|
-
type,
|
|
197
|
-
...previousProcessExit === void 0 ? {} : { metadata: {
|
|
198
|
-
...httpMetadata,
|
|
199
|
-
previousProcessExit
|
|
200
|
-
} }
|
|
201
|
-
};
|
|
202
|
-
}
|
|
203
191
|
case "UPDATE_FAILED": return {
|
|
204
192
|
...movement(),
|
|
205
193
|
type,
|
|
@@ -265,24 +253,13 @@ function createBundleEventRow(input) {
|
|
|
265
253
|
}
|
|
266
254
|
};
|
|
267
255
|
}
|
|
268
|
-
case "UPDATE_APPLIED":
|
|
256
|
+
case "UPDATE_APPLIED":
|
|
257
|
+
case "RECOVERED": return {
|
|
269
258
|
...base,
|
|
270
259
|
from_bundle_id: input.fromBundleId,
|
|
271
260
|
type: input.type,
|
|
272
261
|
metadata
|
|
273
262
|
};
|
|
274
|
-
case "RECOVERED": {
|
|
275
|
-
const exit = input.metadata?.previousProcessExit;
|
|
276
|
-
return {
|
|
277
|
-
...base,
|
|
278
|
-
from_bundle_id: input.fromBundleId,
|
|
279
|
-
type: input.type,
|
|
280
|
-
metadata: {
|
|
281
|
-
...metadata,
|
|
282
|
-
...exit === void 0 ? {} : { previous_process_exit: exit }
|
|
283
|
-
}
|
|
284
|
-
};
|
|
285
|
-
}
|
|
286
263
|
case "UPDATE_FAILED": {
|
|
287
264
|
const { failure } = input.metadata;
|
|
288
265
|
return {
|
|
@@ -299,8 +276,7 @@ function createBundleEventRow(input) {
|
|
|
299
276
|
...failure.resource === void 0 ? {} : { resource: failure.resource },
|
|
300
277
|
...failure.httpStatus === void 0 ? {} : { http_status: failure.httpStatus },
|
|
301
278
|
...failure.transport === void 0 ? {} : { transport: failure.transport },
|
|
302
|
-
...failure.originCode === void 0 ? {} : { origin_code: failure.originCode }
|
|
303
|
-
...failure.previousProcessExit === void 0 ? {} : { previous_process_exit: failure.previousProcessExit }
|
|
279
|
+
...failure.originCode === void 0 ? {} : { origin_code: failure.originCode }
|
|
304
280
|
}
|
|
305
281
|
}
|
|
306
282
|
};
|
package/dist/server/eventRow.cjs
CHANGED
|
@@ -4,8 +4,8 @@ const isOptional = (value, key, valid) => !Object.hasOwn(value, key) || valid(va
|
|
|
4
4
|
const isString = (value) => typeof value === "string";
|
|
5
5
|
const isDatabaseHttpResponse = (value) => (0, _hot_updater_plugin_core.isDatabaseJsonObject)(value) && (value.resource === "catalog" || value.resource === "artifact") && isString(value.path) && Number.isSafeInteger(value.status) && (value.body === null || isString(value.body)) && typeof value.body_truncated === "boolean" && Number.isSafeInteger(value.received_at_ms);
|
|
6
6
|
/** An `UPDATE_FAILED` report's stored failure: a stage and a reason, and what else the client knew. */
|
|
7
|
-
const isDatabaseBundleEventFailure = (value) => (0, _hot_updater_plugin_core.isDatabaseJsonObject)(value) && isString(value.stage) && isString(value.reason) && isOptional(value, "resource", isString) && isOptional(value, "http_status", (status) => Number.isSafeInteger(status)) && isOptional(value, "transport", isString) && isOptional(value, "origin_code", isString) && isOptional(value, "error_message", isString) && isOptional(value, "error_stack", isString)
|
|
8
|
-
const isDatabaseBundleEventMetadata = (value) => (0, _hot_updater_plugin_core.isDatabaseJsonObject)(value) && typeof value.cohort === "string" && (value.update_strategy === null || value.update_strategy === "fingerprint" || value.update_strategy === "appVersion") && (value.fingerprint_hash === null || typeof value.fingerprint_hash === "string") && (value.sdk_version === null || typeof value.sdk_version === "string") && isOptional(value, "failure", isDatabaseBundleEventFailure) && isOptional(value, "http_response", isDatabaseHttpResponse) && isOptional(value, "delivery", isString) && isOptional(value, "patch_fallback", (flag) => typeof flag === "boolean")
|
|
7
|
+
const isDatabaseBundleEventFailure = (value) => (0, _hot_updater_plugin_core.isDatabaseJsonObject)(value) && isString(value.stage) && isString(value.reason) && isOptional(value, "resource", isString) && isOptional(value, "http_status", (status) => Number.isSafeInteger(status)) && isOptional(value, "transport", isString) && isOptional(value, "origin_code", isString) && isOptional(value, "error_message", isString) && isOptional(value, "error_stack", isString);
|
|
8
|
+
const isDatabaseBundleEventMetadata = (value) => (0, _hot_updater_plugin_core.isDatabaseJsonObject)(value) && typeof value.cohort === "string" && (value.update_strategy === null || value.update_strategy === "fingerprint" || value.update_strategy === "appVersion") && (value.fingerprint_hash === null || typeof value.fingerprint_hash === "string") && (value.sdk_version === null || typeof value.sdk_version === "string") && isOptional(value, "failure", isDatabaseBundleEventFailure) && isOptional(value, "http_response", isDatabaseHttpResponse) && isOptional(value, "delivery", isString) && isOptional(value, "patch_fallback", (flag) => typeof flag === "boolean");
|
|
9
9
|
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
10
10
|
const isIdentity = (value) => typeof value === "string" && value.length > 0 && value.length <= 255;
|
|
11
11
|
const isTextOrNull = (value) => value === null || typeof value === "string";
|
|
@@ -16,8 +16,6 @@ type BundleEventFailure = DatabaseJsonObject & {
|
|
|
16
16
|
readonly origin_code?: string;
|
|
17
17
|
readonly error_message?: string;
|
|
18
18
|
readonly error_stack?: string;
|
|
19
|
-
/** Android's `ApplicationExitInfo` reason for the process before this one. */
|
|
20
|
-
readonly previous_process_exit?: string;
|
|
21
19
|
};
|
|
22
20
|
type DatabaseHttpResponse = DatabaseJsonObject & {
|
|
23
21
|
readonly resource: "catalog" | "artifact";
|
|
@@ -40,8 +38,6 @@ type DatabaseBundleEventMetadata = DatabaseJsonObject & {
|
|
|
40
38
|
readonly delivery?: "patch" | "manifest" | "archive" | "unknown";
|
|
41
39
|
/** `UPDATE_DOWNLOADED`: a patch failed and the full files came instead. */
|
|
42
40
|
readonly patch_fallback?: boolean;
|
|
43
|
-
/** `RECOVERED`: Android's `ApplicationExitInfo` reason for the crashed process. */
|
|
44
|
-
readonly previous_process_exit?: string;
|
|
45
41
|
};
|
|
46
42
|
type BundleEventRowBase = {
|
|
47
43
|
readonly id: string;
|
|
@@ -16,8 +16,6 @@ type BundleEventFailure = DatabaseJsonObject & {
|
|
|
16
16
|
readonly origin_code?: string;
|
|
17
17
|
readonly error_message?: string;
|
|
18
18
|
readonly error_stack?: string;
|
|
19
|
-
/** Android's `ApplicationExitInfo` reason for the process before this one. */
|
|
20
|
-
readonly previous_process_exit?: string;
|
|
21
19
|
};
|
|
22
20
|
type DatabaseHttpResponse = DatabaseJsonObject & {
|
|
23
21
|
readonly resource: "catalog" | "artifact";
|
|
@@ -40,8 +38,6 @@ type DatabaseBundleEventMetadata = DatabaseJsonObject & {
|
|
|
40
38
|
readonly delivery?: "patch" | "manifest" | "archive" | "unknown";
|
|
41
39
|
/** `UPDATE_DOWNLOADED`: a patch failed and the full files came instead. */
|
|
42
40
|
readonly patch_fallback?: boolean;
|
|
43
|
-
/** `RECOVERED`: Android's `ApplicationExitInfo` reason for the crashed process. */
|
|
44
|
-
readonly previous_process_exit?: string;
|
|
45
41
|
};
|
|
46
42
|
type BundleEventRowBase = {
|
|
47
43
|
readonly id: string;
|
package/dist/server/eventRow.mjs
CHANGED
|
@@ -4,8 +4,8 @@ const isOptional = (value, key, valid) => !Object.hasOwn(value, key) || valid(va
|
|
|
4
4
|
const isString = (value) => typeof value === "string";
|
|
5
5
|
const isDatabaseHttpResponse = (value) => isDatabaseJsonObject(value) && (value.resource === "catalog" || value.resource === "artifact") && isString(value.path) && Number.isSafeInteger(value.status) && (value.body === null || isString(value.body)) && typeof value.body_truncated === "boolean" && Number.isSafeInteger(value.received_at_ms);
|
|
6
6
|
/** An `UPDATE_FAILED` report's stored failure: a stage and a reason, and what else the client knew. */
|
|
7
|
-
const isDatabaseBundleEventFailure = (value) => isDatabaseJsonObject(value) && isString(value.stage) && isString(value.reason) && isOptional(value, "resource", isString) && isOptional(value, "http_status", (status) => Number.isSafeInteger(status)) && isOptional(value, "transport", isString) && isOptional(value, "origin_code", isString) && isOptional(value, "error_message", isString) && isOptional(value, "error_stack", isString)
|
|
8
|
-
const isDatabaseBundleEventMetadata = (value) => isDatabaseJsonObject(value) && typeof value.cohort === "string" && (value.update_strategy === null || value.update_strategy === "fingerprint" || value.update_strategy === "appVersion") && (value.fingerprint_hash === null || typeof value.fingerprint_hash === "string") && (value.sdk_version === null || typeof value.sdk_version === "string") && isOptional(value, "failure", isDatabaseBundleEventFailure) && isOptional(value, "http_response", isDatabaseHttpResponse) && isOptional(value, "delivery", isString) && isOptional(value, "patch_fallback", (flag) => typeof flag === "boolean")
|
|
7
|
+
const isDatabaseBundleEventFailure = (value) => isDatabaseJsonObject(value) && isString(value.stage) && isString(value.reason) && isOptional(value, "resource", isString) && isOptional(value, "http_status", (status) => Number.isSafeInteger(status)) && isOptional(value, "transport", isString) && isOptional(value, "origin_code", isString) && isOptional(value, "error_message", isString) && isOptional(value, "error_stack", isString);
|
|
8
|
+
const isDatabaseBundleEventMetadata = (value) => isDatabaseJsonObject(value) && typeof value.cohort === "string" && (value.update_strategy === null || value.update_strategy === "fingerprint" || value.update_strategy === "appVersion") && (value.fingerprint_hash === null || typeof value.fingerprint_hash === "string") && (value.sdk_version === null || typeof value.sdk_version === "string") && isOptional(value, "failure", isDatabaseBundleEventFailure) && isOptional(value, "http_response", isDatabaseHttpResponse) && isOptional(value, "delivery", isString) && isOptional(value, "patch_fallback", (flag) => typeof flag === "boolean");
|
|
9
9
|
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
10
10
|
const isIdentity = (value) => typeof value === "string" && value.length > 0 && value.length <= 255;
|
|
11
11
|
const isTextOrNull = (value) => value === null || typeof value === "string";
|
package/dist/server/index.cjs
CHANGED
|
@@ -88,7 +88,7 @@ const insights = (options = {}) => {
|
|
|
88
88
|
const plugin = (0, _hot_updater_plugin_core.definePlugin)({
|
|
89
89
|
id: "insights",
|
|
90
90
|
namespace: false,
|
|
91
|
-
schemaVersion: "1.
|
|
91
|
+
schemaVersion: "1.0.0",
|
|
92
92
|
schema: require_schema.createInsightsSchema(retention),
|
|
93
93
|
init: ({ db, now }) => {
|
|
94
94
|
const api = createInsightsApi(db, now, retention);
|
package/dist/server/index.mjs
CHANGED
|
@@ -87,7 +87,7 @@ const insights = (options = {}) => {
|
|
|
87
87
|
const plugin = definePlugin({
|
|
88
88
|
id: "insights",
|
|
89
89
|
namespace: false,
|
|
90
|
-
schemaVersion: "1.
|
|
90
|
+
schemaVersion: "1.0.0",
|
|
91
91
|
schema: createInsightsSchema(retention),
|
|
92
92
|
init: ({ db, now }) => {
|
|
93
93
|
const api = createInsightsApi(db, now, retention);
|
package/dist/server/provider.cjs
CHANGED
|
@@ -152,10 +152,9 @@ const toFailure = (failure) => ({
|
|
|
152
152
|
...failure.resource === void 0 ? {} : { resource: failure.resource },
|
|
153
153
|
...failure.http_status === void 0 ? {} : { httpStatus: failure.http_status },
|
|
154
154
|
...failure.transport === void 0 ? {} : { transport: failure.transport },
|
|
155
|
-
...failure.origin_code === void 0 ? {} : { originCode: failure.origin_code }
|
|
156
|
-
...failure.previous_process_exit === void 0 ? {} : { previousProcessExit: failure.previous_process_exit }
|
|
155
|
+
...failure.origin_code === void 0 ? {} : { originCode: failure.origin_code }
|
|
157
156
|
});
|
|
158
|
-
/** What a row's metadata adds for its type: a failure
|
|
157
|
+
/** What a row's metadata adds for its type: a failure or a delivery. */
|
|
159
158
|
const eventDetails = ({ type, metadata }) => ({
|
|
160
159
|
...metadata.http_response !== void 0 ? { httpResponse: {
|
|
161
160
|
resource: metadata.http_response.resource,
|
|
@@ -167,8 +166,7 @@ const eventDetails = ({ type, metadata }) => ({
|
|
|
167
166
|
} } : {},
|
|
168
167
|
...type === "UPDATE_FAILED" && metadata.failure !== void 0 ? { failure: toFailure(metadata.failure) } : {},
|
|
169
168
|
...type === "UPDATE_DOWNLOADED" && metadata.delivery !== void 0 ? { delivery: metadata.delivery } : {},
|
|
170
|
-
...type === "UPDATE_DOWNLOADED" && metadata.patch_fallback === true ? { patchFallback: true } : {}
|
|
171
|
-
...type === "RECOVERED" && metadata.previous_process_exit !== void 0 ? { previousProcessExit: metadata.previous_process_exit } : {}
|
|
169
|
+
...type === "UPDATE_DOWNLOADED" && metadata.patch_fallback === true ? { patchFallback: true } : {}
|
|
172
170
|
});
|
|
173
171
|
const toEventHistoryRow = (row) => ({
|
|
174
172
|
...row.to_release_id == null ? {} : { toReleaseId: row.to_release_id },
|
package/dist/server/provider.mjs
CHANGED
|
@@ -152,10 +152,9 @@ const toFailure = (failure) => ({
|
|
|
152
152
|
...failure.resource === void 0 ? {} : { resource: failure.resource },
|
|
153
153
|
...failure.http_status === void 0 ? {} : { httpStatus: failure.http_status },
|
|
154
154
|
...failure.transport === void 0 ? {} : { transport: failure.transport },
|
|
155
|
-
...failure.origin_code === void 0 ? {} : { originCode: failure.origin_code }
|
|
156
|
-
...failure.previous_process_exit === void 0 ? {} : { previousProcessExit: failure.previous_process_exit }
|
|
155
|
+
...failure.origin_code === void 0 ? {} : { originCode: failure.origin_code }
|
|
157
156
|
});
|
|
158
|
-
/** What a row's metadata adds for its type: a failure
|
|
157
|
+
/** What a row's metadata adds for its type: a failure or a delivery. */
|
|
159
158
|
const eventDetails = ({ type, metadata }) => ({
|
|
160
159
|
...metadata.http_response !== void 0 ? { httpResponse: {
|
|
161
160
|
resource: metadata.http_response.resource,
|
|
@@ -167,8 +166,7 @@ const eventDetails = ({ type, metadata }) => ({
|
|
|
167
166
|
} } : {},
|
|
168
167
|
...type === "UPDATE_FAILED" && metadata.failure !== void 0 ? { failure: toFailure(metadata.failure) } : {},
|
|
169
168
|
...type === "UPDATE_DOWNLOADED" && metadata.delivery !== void 0 ? { delivery: metadata.delivery } : {},
|
|
170
|
-
...type === "UPDATE_DOWNLOADED" && metadata.patch_fallback === true ? { patchFallback: true } : {}
|
|
171
|
-
...type === "RECOVERED" && metadata.previous_process_exit !== void 0 ? { previousProcessExit: metadata.previous_process_exit } : {}
|
|
169
|
+
...type === "UPDATE_DOWNLOADED" && metadata.patch_fallback === true ? { patchFallback: true } : {}
|
|
172
170
|
});
|
|
173
171
|
const toEventHistoryRow = (row) => ({
|
|
174
172
|
...row.to_release_id == null ? {} : { toReleaseId: row.to_release_id },
|
package/dist/server/reads.cjs
CHANGED
|
@@ -474,21 +474,18 @@ const isText = (value, maxLength) => typeof value === "string" && value.length >
|
|
|
474
474
|
const failed = (...rows) => (0, _hot_updater_plugin_core.countDistinct)((0, _hot_updater_plugin_core.mergeDistinct)(rows.flat().map((row) => row.failed_users)));
|
|
475
475
|
/** Entries of a count map, most first, then in key order. */
|
|
476
476
|
const mostFirst = (counts) => [...counts].sort(([leftKey, left], [rightKey, right]) => right.events - left.events || (0, _hot_updater_plugin_core.compareUtf8)(leftKey, rightKey)).map(([, entry]) => entry);
|
|
477
|
-
/**
|
|
477
|
+
/** The stages a failure row records: where an update failed. */
|
|
478
|
+
const FAILURE_STAGES = /* @__PURE__ */ new Set([
|
|
479
|
+
"check",
|
|
480
|
+
"download",
|
|
481
|
+
"install",
|
|
482
|
+
"unknown"
|
|
483
|
+
]);
|
|
484
|
+
/** Failure rows as their breakdown by stage, reason, and detail. */
|
|
478
485
|
const breakdownOf = (rows) => {
|
|
479
486
|
const failures = /* @__PURE__ */ new Map();
|
|
480
|
-
const exits = /* @__PURE__ */ new Map();
|
|
481
487
|
for (const { stage, reason, detail, events } of rows) {
|
|
482
488
|
if (events <= 0) continue;
|
|
483
|
-
if (stage === "launch") {
|
|
484
|
-
const exit = exits.get(reason) ?? {
|
|
485
|
-
value: reason,
|
|
486
|
-
events: 0
|
|
487
|
-
};
|
|
488
|
-
exit.events += events;
|
|
489
|
-
exits.set(reason, exit);
|
|
490
|
-
continue;
|
|
491
|
-
}
|
|
492
489
|
const key = JSON.stringify([stage, reason]);
|
|
493
490
|
const entry = failures.get(key) ?? {
|
|
494
491
|
value: {
|
|
@@ -507,37 +504,30 @@ const breakdownOf = (rows) => {
|
|
|
507
504
|
entry.details.set(detail, known);
|
|
508
505
|
failures.set(key, entry);
|
|
509
506
|
}
|
|
510
|
-
return {
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
}),
|
|
528
|
-
byExitReason: mostFirst(exits).map(({ value, events }) => ({
|
|
529
|
-
exitReason: value,
|
|
530
|
-
events
|
|
531
|
-
}))
|
|
532
|
-
};
|
|
507
|
+
return mostFirst(failures).map(({ value, events }) => {
|
|
508
|
+
const { details } = failures.get(JSON.stringify([value.stage, value.reason]));
|
|
509
|
+
return {
|
|
510
|
+
...value,
|
|
511
|
+
events,
|
|
512
|
+
details: mostFirst(details).map(({ value: detail, events }) => {
|
|
513
|
+
const [resource, httpStatus, originCode, transport] = JSON.parse(detail);
|
|
514
|
+
return {
|
|
515
|
+
resource,
|
|
516
|
+
httpStatus,
|
|
517
|
+
originCode,
|
|
518
|
+
transport,
|
|
519
|
+
events
|
|
520
|
+
};
|
|
521
|
+
})
|
|
522
|
+
};
|
|
523
|
+
});
|
|
533
524
|
};
|
|
534
525
|
/**
|
|
535
526
|
* A release's or a channel's update failures. Since a release's first
|
|
536
527
|
* report: its lifetime counters and failed installations. Over a time range
|
|
537
|
-
* of at most 30 days: failures, failed checks, the breakdown by stage,
|
|
538
|
-
* reason, and detail,
|
|
539
|
-
*
|
|
540
|
-
* failed installations from their sketches. A release reads hourly rows, a
|
|
528
|
+
* of at most 30 days: failures, failed checks, and the breakdown by stage,
|
|
529
|
+
* reason, and detail, all summed from the breakdown's hourly rows; downloads
|
|
530
|
+
* from the counters; failed installations from their sketches. A release reads hourly rows, a
|
|
541
531
|
* channel daily rows past 48 hours like its activity; the breakdown's rows
|
|
542
532
|
* are hourly, so its coverage is the raw period's.
|
|
543
533
|
*/
|
|
@@ -624,13 +614,12 @@ const getUpdateFailures = async (db, input, now, retention) => {
|
|
|
624
614
|
}))
|
|
625
615
|
]);
|
|
626
616
|
const total = (field) => counters.reduce((sum, row) => sum + row[field], 0);
|
|
627
|
-
const scoped =
|
|
617
|
+
const scoped = rows.filter((row) => FAILURE_STAGES.has(row.stage) && (releaseId === void 0 || row.release_id === releaseId));
|
|
628
618
|
const failuresAt = (counted) => scoped.reduce((sum, row) => sum + (counted(row.stage) ? Math.max(0, row.events) : 0), 0);
|
|
629
|
-
const { breakdown, byExitReason } = breakdownOf(scoped);
|
|
630
619
|
return {
|
|
631
620
|
coverage: coverageOf(timeRange.start, kept.hour),
|
|
632
621
|
measuredAtMs: at,
|
|
633
|
-
failedUpdates: failuresAt((stage) => stage !== "check"
|
|
622
|
+
failedUpdates: failuresAt((stage) => stage !== "check"),
|
|
634
623
|
failedInstallations: failed(failures),
|
|
635
624
|
downloads: total("downloads"),
|
|
636
625
|
patchDownloads: total("patch_downloads"),
|
|
@@ -640,11 +629,7 @@ const getUpdateFailures = async (db, input, now, retention) => {
|
|
|
640
629
|
failedInstallations: failed(checks),
|
|
641
630
|
activeInstallations: (0, _hot_updater_plugin_core.countDistinct)((0, _hot_updater_plugin_core.mergeDistinct)(active.map((row) => row.activity_users)))
|
|
642
631
|
} } : {},
|
|
643
|
-
breakdown
|
|
644
|
-
recoveries: {
|
|
645
|
-
failedLaunches: total("failed_launches"),
|
|
646
|
-
byExitReason
|
|
647
|
-
}
|
|
632
|
+
breakdown: breakdownOf(scoped)
|
|
648
633
|
};
|
|
649
634
|
};
|
|
650
635
|
//#endregion
|
package/dist/server/reads.d.cts
CHANGED
|
@@ -44,17 +44,6 @@ interface InsightsUpdateFailures {
|
|
|
44
44
|
};
|
|
45
45
|
/** Over a time range: failures by stage and reason, most first. */
|
|
46
46
|
readonly breakdown?: readonly InsightsFailureBreakdown[];
|
|
47
|
-
/**
|
|
48
|
-
* Over a time range: failed launches, and the recoveries whose crashed
|
|
49
|
-
* process exited for a reason Android 11+ reported, by reason, most first.
|
|
50
|
-
*/
|
|
51
|
-
readonly recoveries?: {
|
|
52
|
-
readonly failedLaunches: number;
|
|
53
|
-
readonly byExitReason: readonly {
|
|
54
|
-
readonly exitReason: string;
|
|
55
|
-
readonly events: number;
|
|
56
|
-
}[];
|
|
57
|
-
};
|
|
58
47
|
}
|
|
59
48
|
//#endregion
|
|
60
49
|
export { InsightsFailureBreakdown, InsightsUpdateFailures, InsightsUpdateFailuresInput };
|
package/dist/server/reads.d.mts
CHANGED
|
@@ -44,17 +44,6 @@ interface InsightsUpdateFailures {
|
|
|
44
44
|
};
|
|
45
45
|
/** Over a time range: failures by stage and reason, most first. */
|
|
46
46
|
readonly breakdown?: readonly InsightsFailureBreakdown[];
|
|
47
|
-
/**
|
|
48
|
-
* Over a time range: failed launches, and the recoveries whose crashed
|
|
49
|
-
* process exited for a reason Android 11+ reported, by reason, most first.
|
|
50
|
-
*/
|
|
51
|
-
readonly recoveries?: {
|
|
52
|
-
readonly failedLaunches: number;
|
|
53
|
-
readonly byExitReason: readonly {
|
|
54
|
-
readonly exitReason: string;
|
|
55
|
-
readonly events: number;
|
|
56
|
-
}[];
|
|
57
|
-
};
|
|
58
47
|
}
|
|
59
48
|
//#endregion
|
|
60
49
|
export { InsightsFailureBreakdown, InsightsUpdateFailures, InsightsUpdateFailuresInput };
|
package/dist/server/reads.mjs
CHANGED
|
@@ -474,21 +474,18 @@ const isText = (value, maxLength) => typeof value === "string" && value.length >
|
|
|
474
474
|
const failed = (...rows) => countDistinct(mergeDistinct(rows.flat().map((row) => row.failed_users)));
|
|
475
475
|
/** Entries of a count map, most first, then in key order. */
|
|
476
476
|
const mostFirst = (counts) => [...counts].sort(([leftKey, left], [rightKey, right]) => right.events - left.events || compareUtf8(leftKey, rightKey)).map(([, entry]) => entry);
|
|
477
|
-
/**
|
|
477
|
+
/** The stages a failure row records: where an update failed. */
|
|
478
|
+
const FAILURE_STAGES = /* @__PURE__ */ new Set([
|
|
479
|
+
"check",
|
|
480
|
+
"download",
|
|
481
|
+
"install",
|
|
482
|
+
"unknown"
|
|
483
|
+
]);
|
|
484
|
+
/** Failure rows as their breakdown by stage, reason, and detail. */
|
|
478
485
|
const breakdownOf = (rows) => {
|
|
479
486
|
const failures = /* @__PURE__ */ new Map();
|
|
480
|
-
const exits = /* @__PURE__ */ new Map();
|
|
481
487
|
for (const { stage, reason, detail, events } of rows) {
|
|
482
488
|
if (events <= 0) continue;
|
|
483
|
-
if (stage === "launch") {
|
|
484
|
-
const exit = exits.get(reason) ?? {
|
|
485
|
-
value: reason,
|
|
486
|
-
events: 0
|
|
487
|
-
};
|
|
488
|
-
exit.events += events;
|
|
489
|
-
exits.set(reason, exit);
|
|
490
|
-
continue;
|
|
491
|
-
}
|
|
492
489
|
const key = JSON.stringify([stage, reason]);
|
|
493
490
|
const entry = failures.get(key) ?? {
|
|
494
491
|
value: {
|
|
@@ -507,37 +504,30 @@ const breakdownOf = (rows) => {
|
|
|
507
504
|
entry.details.set(detail, known);
|
|
508
505
|
failures.set(key, entry);
|
|
509
506
|
}
|
|
510
|
-
return {
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
}),
|
|
528
|
-
byExitReason: mostFirst(exits).map(({ value, events }) => ({
|
|
529
|
-
exitReason: value,
|
|
530
|
-
events
|
|
531
|
-
}))
|
|
532
|
-
};
|
|
507
|
+
return mostFirst(failures).map(({ value, events }) => {
|
|
508
|
+
const { details } = failures.get(JSON.stringify([value.stage, value.reason]));
|
|
509
|
+
return {
|
|
510
|
+
...value,
|
|
511
|
+
events,
|
|
512
|
+
details: mostFirst(details).map(({ value: detail, events }) => {
|
|
513
|
+
const [resource, httpStatus, originCode, transport] = JSON.parse(detail);
|
|
514
|
+
return {
|
|
515
|
+
resource,
|
|
516
|
+
httpStatus,
|
|
517
|
+
originCode,
|
|
518
|
+
transport,
|
|
519
|
+
events
|
|
520
|
+
};
|
|
521
|
+
})
|
|
522
|
+
};
|
|
523
|
+
});
|
|
533
524
|
};
|
|
534
525
|
/**
|
|
535
526
|
* A release's or a channel's update failures. Since a release's first
|
|
536
527
|
* report: its lifetime counters and failed installations. Over a time range
|
|
537
|
-
* of at most 30 days: failures, failed checks, the breakdown by stage,
|
|
538
|
-
* reason, and detail,
|
|
539
|
-
*
|
|
540
|
-
* failed installations from their sketches. A release reads hourly rows, a
|
|
528
|
+
* of at most 30 days: failures, failed checks, and the breakdown by stage,
|
|
529
|
+
* reason, and detail, all summed from the breakdown's hourly rows; downloads
|
|
530
|
+
* from the counters; failed installations from their sketches. A release reads hourly rows, a
|
|
541
531
|
* channel daily rows past 48 hours like its activity; the breakdown's rows
|
|
542
532
|
* are hourly, so its coverage is the raw period's.
|
|
543
533
|
*/
|
|
@@ -624,13 +614,12 @@ const getUpdateFailures = async (db, input, now, retention) => {
|
|
|
624
614
|
}))
|
|
625
615
|
]);
|
|
626
616
|
const total = (field) => counters.reduce((sum, row) => sum + row[field], 0);
|
|
627
|
-
const scoped =
|
|
617
|
+
const scoped = rows.filter((row) => FAILURE_STAGES.has(row.stage) && (releaseId === void 0 || row.release_id === releaseId));
|
|
628
618
|
const failuresAt = (counted) => scoped.reduce((sum, row) => sum + (counted(row.stage) ? Math.max(0, row.events) : 0), 0);
|
|
629
|
-
const { breakdown, byExitReason } = breakdownOf(scoped);
|
|
630
619
|
return {
|
|
631
620
|
coverage: coverageOf(timeRange.start, kept.hour),
|
|
632
621
|
measuredAtMs: at,
|
|
633
|
-
failedUpdates: failuresAt((stage) => stage !== "check"
|
|
622
|
+
failedUpdates: failuresAt((stage) => stage !== "check"),
|
|
634
623
|
failedInstallations: failed(failures),
|
|
635
624
|
downloads: total("downloads"),
|
|
636
625
|
patchDownloads: total("patch_downloads"),
|
|
@@ -640,11 +629,7 @@ const getUpdateFailures = async (db, input, now, retention) => {
|
|
|
640
629
|
failedInstallations: failed(checks),
|
|
641
630
|
activeInstallations: countDistinct(mergeDistinct(active.map((row) => row.activity_users)))
|
|
642
631
|
} } : {},
|
|
643
|
-
breakdown
|
|
644
|
-
recoveries: {
|
|
645
|
-
failedLaunches: total("failed_launches"),
|
|
646
|
-
byExitReason
|
|
647
|
-
}
|
|
632
|
+
breakdown: breakdownOf(scoped)
|
|
648
633
|
};
|
|
649
634
|
};
|
|
650
635
|
//#endregion
|
|
@@ -235,23 +235,6 @@ const countFailure = (tx, event) => {
|
|
|
235
235
|
detail: failureDetail(failure)
|
|
236
236
|
}, { events: 1 }, { shardBy });
|
|
237
237
|
};
|
|
238
|
-
/**
|
|
239
|
-
* A recovery's exit reason, which Android 11+ reports, in the breakdown of
|
|
240
|
-
* the release whose launch failed: stage `launch`, the reason as its reason.
|
|
241
|
-
*/
|
|
242
|
-
const countExit = (tx, event) => {
|
|
243
|
-
const exit = event.metadata.previous_process_exit;
|
|
244
|
-
if (event.type !== "RECOVERED" || exit === void 0) return;
|
|
245
|
-
tx.aggregate("insights_failures", {
|
|
246
|
-
platform: event.platform,
|
|
247
|
-
channel: event.channel,
|
|
248
|
-
bucket_start_ms: hourOf(event.received_at_ms),
|
|
249
|
-
release_id: event.from_release_id ?? "",
|
|
250
|
-
stage: "launch",
|
|
251
|
-
reason: exit,
|
|
252
|
-
detail: ""
|
|
253
|
-
}, { events: 1 }, { shardBy: event.install_id });
|
|
254
|
-
};
|
|
255
238
|
const isNewer = (event, head) => event.received_at_ms !== head.received_at_ms ? event.received_at_ms > head.received_at_ms : (0, _hot_updater_plugin_core.compareUtf8)(event.id, head.id) > 0;
|
|
256
239
|
/** What an UNCHANGED report must share with its installation's head to repeat it. */
|
|
257
240
|
const REPEATED_FIELDS = [
|
|
@@ -296,7 +279,6 @@ const recordEvent = (db, event) => {
|
|
|
296
279
|
return;
|
|
297
280
|
}
|
|
298
281
|
countEvent(tx, event);
|
|
299
|
-
countExit(tx, event);
|
|
300
282
|
if (previous !== null && !isNewer(event, previous)) return;
|
|
301
283
|
if (previous === null) tx.create("bundle_event_heads", event);
|
|
302
284
|
else {
|
|
@@ -235,23 +235,6 @@ const countFailure = (tx, event) => {
|
|
|
235
235
|
detail: failureDetail(failure)
|
|
236
236
|
}, { events: 1 }, { shardBy });
|
|
237
237
|
};
|
|
238
|
-
/**
|
|
239
|
-
* A recovery's exit reason, which Android 11+ reports, in the breakdown of
|
|
240
|
-
* the release whose launch failed: stage `launch`, the reason as its reason.
|
|
241
|
-
*/
|
|
242
|
-
const countExit = (tx, event) => {
|
|
243
|
-
const exit = event.metadata.previous_process_exit;
|
|
244
|
-
if (event.type !== "RECOVERED" || exit === void 0) return;
|
|
245
|
-
tx.aggregate("insights_failures", {
|
|
246
|
-
platform: event.platform,
|
|
247
|
-
channel: event.channel,
|
|
248
|
-
bucket_start_ms: hourOf(event.received_at_ms),
|
|
249
|
-
release_id: event.from_release_id ?? "",
|
|
250
|
-
stage: "launch",
|
|
251
|
-
reason: exit,
|
|
252
|
-
detail: ""
|
|
253
|
-
}, { events: 1 }, { shardBy: event.install_id });
|
|
254
|
-
};
|
|
255
238
|
const isNewer = (event, head) => event.received_at_ms !== head.received_at_ms ? event.received_at_ms > head.received_at_ms : compareUtf8(event.id, head.id) > 0;
|
|
256
239
|
/** What an UNCHANGED report must share with its installation's head to repeat it. */
|
|
257
240
|
const REPEATED_FIELDS = [
|
|
@@ -296,7 +279,6 @@ const recordEvent = (db, event) => {
|
|
|
296
279
|
return;
|
|
297
280
|
}
|
|
298
281
|
countEvent(tx, event);
|
|
299
|
-
countExit(tx, event);
|
|
300
282
|
if (previous !== null && !isNewer(event, previous)) return;
|
|
301
283
|
if (previous === null) tx.create("bundle_event_heads", event);
|
|
302
284
|
else {
|
package/dist/server/schema.cjs
CHANGED
|
@@ -265,14 +265,12 @@ const lifetimeSketches = () => (0, _hot_updater_plugin_core.defineAggregate)(ide
|
|
|
265
265
|
indexes: { window }
|
|
266
266
|
});
|
|
267
267
|
/**
|
|
268
|
-
* Update failures by what failed,
|
|
269
|
-
*
|
|
270
|
-
*
|
|
271
|
-
*
|
|
272
|
-
*
|
|
273
|
-
*
|
|
274
|
-
* `launch` and its reason the exit reason, with an empty detail. Every index
|
|
275
|
-
* is in key order, so its counters stay blind increments.
|
|
268
|
+
* Update failures by what failed, a row an hour. `release_id` is the failed
|
|
269
|
+
* update's target release, or empty for a failed check or an unknown target.
|
|
270
|
+
* `stage` and `reason` say where and why it failed, and `detail` what else
|
|
271
|
+
* the client knew, as the JSON array `[resource, httpStatus, originCode,
|
|
272
|
+
* transport]`. Every index is in key order, so its counters stay blind
|
|
273
|
+
* increments.
|
|
276
274
|
*/
|
|
277
275
|
const insightsFailures = (retention) => (0, _hot_updater_plugin_core.defineAggregate)({
|
|
278
276
|
platform: {
|
package/dist/server/schema.mjs
CHANGED
|
@@ -265,14 +265,12 @@ const lifetimeSketches = () => defineAggregate(identityFields, {
|
|
|
265
265
|
indexes: { window }
|
|
266
266
|
});
|
|
267
267
|
/**
|
|
268
|
-
* Update failures by what failed,
|
|
269
|
-
*
|
|
270
|
-
*
|
|
271
|
-
*
|
|
272
|
-
*
|
|
273
|
-
*
|
|
274
|
-
* `launch` and its reason the exit reason, with an empty detail. Every index
|
|
275
|
-
* is in key order, so its counters stay blind increments.
|
|
268
|
+
* Update failures by what failed, a row an hour. `release_id` is the failed
|
|
269
|
+
* update's target release, or empty for a failed check or an unknown target.
|
|
270
|
+
* `stage` and `reason` say where and why it failed, and `detail` what else
|
|
271
|
+
* the client knew, as the JSON array `[resource, httpStatus, originCode,
|
|
272
|
+
* transport]`. Every index is in key order, so its counters stay blind
|
|
273
|
+
* increments.
|
|
276
274
|
*/
|
|
277
275
|
const insightsFailures = (retention) => defineAggregate({
|
|
278
276
|
platform: {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hot-updater/plugin-insights",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.0-rc.
|
|
4
|
+
"version": "1.0.0-rc.35",
|
|
5
5
|
"description": "Hot Updater's Insights plugin: launch, download, and update failure events, for the server and the React Native app",
|
|
6
6
|
"exports": {
|
|
7
7
|
"./client": {
|
|
@@ -33,10 +33,10 @@
|
|
|
33
33
|
"package.json"
|
|
34
34
|
],
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@hot-updater/protocol": "1.0.0-rc.
|
|
36
|
+
"@hot-updater/protocol": "1.0.0-rc.35"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
|
-
"@hot-updater/plugin-core": "^1.0.0-rc.
|
|
39
|
+
"@hot-updater/plugin-core": "^1.0.0-rc.35"
|
|
40
40
|
},
|
|
41
41
|
"peerDependenciesMeta": {
|
|
42
42
|
"@hot-updater/plugin-core": {
|
|
@@ -46,8 +46,8 @@
|
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"@types/node": "^20",
|
|
48
48
|
"vitest": "4.1.4",
|
|
49
|
-
"@hot-updater/
|
|
50
|
-
"@hot-updater/
|
|
49
|
+
"@hot-updater/test-utils": "1.0.0-rc.35",
|
|
50
|
+
"@hot-updater/plugin-core": "1.0.0-rc.35"
|
|
51
51
|
},
|
|
52
52
|
"nx": {
|
|
53
53
|
"implicitDependencies": [
|