@hot-updater/plugin-insights 1.0.0-rc.32 → 1.0.0-rc.34
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/contract.cjs +1 -1
- package/dist/server/contract.mjs +1 -1
- 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.d.cts +3 -3
- package/dist/server/index.d.mts +3 -3
- package/dist/server/index.mjs +1 -1
- package/dist/server/modelTypes.d.cts +4 -1
- package/dist/server/modelTypes.d.mts +4 -1
- package/dist/server/overview.cjs +14 -16
- package/dist/server/overview.mjs +14 -16
- package/dist/server/provider.cjs +3 -5
- package/dist/server/provider.mjs +3 -5
- package/dist/server/reads.cjs +32 -47
- package/dist/server/reads.d.cts +0 -11
- package/dist/server/reads.d.mts +0 -11
- package/dist/server/reads.mjs +32 -47
- package/dist/server/recordEvent.cjs +1 -19
- package/dist/server/recordEvent.mjs +1 -19
- package/dist/server/schema.cjs +35 -24
- package/dist/server/schema.d.cts +6 -6
- package/dist/server/schema.d.mts +6 -6
- package/dist/server/schema.mjs +35 -24
- 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/contract.cjs
CHANGED
|
@@ -166,7 +166,7 @@ const createValidatedInsightsModel = (model) => ({
|
|
|
166
166
|
async getReleaseActivity(input) {
|
|
167
167
|
if (!require_eventRow.isRecord(input) || !hasOnlyKeys(input, ["releases"]) || !Array.isArray(input.releases) || input.releases.length < 1 || input.releases.length > 100 || !input.releases.every(isReleaseReference)) invalidQuery();
|
|
168
168
|
const result = await model.getReleaseActivity(input);
|
|
169
|
-
if (!require_eventRow.isRecord(result) || !isTimestamp(result.measuredAtMs) || !Array.isArray(result.data) || result.data.some((item) => !require_eventRow.isRecord(item) || !isReleaseReference(item.release) || !require_eventRow.isRecord(item.metrics) || !isTimestamp(item.metrics.downloads) || !isTimestamp(item.metrics.
|
|
169
|
+
if (!require_eventRow.isRecord(result) || !isTimestamp(result.measuredAtMs) || !Array.isArray(result.data) || result.data.some((item) => !require_eventRow.isRecord(item) || !isReleaseReference(item.release) || !require_eventRow.isRecord(item.metrics) || !isTimestamp(item.metrics.downloads) || !isTimestamp(item.metrics.applies) || !isTimestamp(item.metrics.failedLaunches))) invalidResult();
|
|
170
170
|
return result;
|
|
171
171
|
},
|
|
172
172
|
async getAppUsage(input) {
|
package/dist/server/contract.mjs
CHANGED
|
@@ -166,7 +166,7 @@ const createValidatedInsightsModel = (model) => ({
|
|
|
166
166
|
async getReleaseActivity(input) {
|
|
167
167
|
if (!isRecord(input) || !hasOnlyKeys(input, ["releases"]) || !Array.isArray(input.releases) || input.releases.length < 1 || input.releases.length > 100 || !input.releases.every(isReleaseReference)) invalidQuery();
|
|
168
168
|
const result = await model.getReleaseActivity(input);
|
|
169
|
-
if (!isRecord(result) || !isTimestamp(result.measuredAtMs) || !Array.isArray(result.data) || result.data.some((item) => !isRecord(item) || !isReleaseReference(item.release) || !isRecord(item.metrics) || !isTimestamp(item.metrics.downloads) || !isTimestamp(item.metrics.
|
|
169
|
+
if (!isRecord(result) || !isTimestamp(result.measuredAtMs) || !Array.isArray(result.data) || result.data.some((item) => !isRecord(item) || !isReleaseReference(item.release) || !isRecord(item.metrics) || !isTimestamp(item.metrics.downloads) || !isTimestamp(item.metrics.applies) || !isTimestamp(item.metrics.failedLaunches))) invalidResult();
|
|
170
170
|
return result;
|
|
171
171
|
},
|
|
172
172
|
async getAppUsage(input) {
|
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.d.cts
CHANGED
|
@@ -180,7 +180,7 @@ declare const insights: (options?: InsightsOptions) => import("@hot-updater/plug
|
|
|
180
180
|
readonly bucket_start_ms: {
|
|
181
181
|
readonly type: "integer";
|
|
182
182
|
};
|
|
183
|
-
}, "downloads" | "
|
|
183
|
+
}, "downloads" | "failed_launches" | "patch_downloads" | "patch_fallbacks", {
|
|
184
184
|
readonly window: {
|
|
185
185
|
readonly eq: readonly ["identity"];
|
|
186
186
|
readonly sort: readonly ["bucket_start_ms"];
|
|
@@ -208,7 +208,7 @@ declare const insights: (options?: InsightsOptions) => import("@hot-updater/plug
|
|
|
208
208
|
readonly bucket_start_ms: {
|
|
209
209
|
readonly type: "integer";
|
|
210
210
|
};
|
|
211
|
-
}, "downloads" | "
|
|
211
|
+
}, "downloads" | "failed_launches" | "patch_downloads" | "patch_fallbacks", {
|
|
212
212
|
readonly window: {
|
|
213
213
|
readonly eq: readonly ["identity"];
|
|
214
214
|
readonly sort: readonly ["bucket_start_ms"];
|
|
@@ -236,7 +236,7 @@ declare const insights: (options?: InsightsOptions) => import("@hot-updater/plug
|
|
|
236
236
|
readonly bucket_start_ms: {
|
|
237
237
|
readonly type: "integer";
|
|
238
238
|
};
|
|
239
|
-
}, "downloads" | "
|
|
239
|
+
}, "downloads" | "failed_launches" | "patch_downloads" | "patch_fallbacks" | "applies" | "failed_updates", {
|
|
240
240
|
readonly window: {
|
|
241
241
|
readonly eq: readonly ["identity"];
|
|
242
242
|
readonly sort: readonly ["bucket_start_ms"];
|
package/dist/server/index.d.mts
CHANGED
|
@@ -180,7 +180,7 @@ declare const insights: (options?: InsightsOptions) => import("@hot-updater/plug
|
|
|
180
180
|
readonly bucket_start_ms: {
|
|
181
181
|
readonly type: "integer";
|
|
182
182
|
};
|
|
183
|
-
}, "downloads" | "
|
|
183
|
+
}, "downloads" | "failed_launches" | "patch_downloads" | "patch_fallbacks", {
|
|
184
184
|
readonly window: {
|
|
185
185
|
readonly eq: readonly ["identity"];
|
|
186
186
|
readonly sort: readonly ["bucket_start_ms"];
|
|
@@ -208,7 +208,7 @@ declare const insights: (options?: InsightsOptions) => import("@hot-updater/plug
|
|
|
208
208
|
readonly bucket_start_ms: {
|
|
209
209
|
readonly type: "integer";
|
|
210
210
|
};
|
|
211
|
-
}, "downloads" | "
|
|
211
|
+
}, "downloads" | "failed_launches" | "patch_downloads" | "patch_fallbacks", {
|
|
212
212
|
readonly window: {
|
|
213
213
|
readonly eq: readonly ["identity"];
|
|
214
214
|
readonly sort: readonly ["bucket_start_ms"];
|
|
@@ -236,7 +236,7 @@ declare const insights: (options?: InsightsOptions) => import("@hot-updater/plug
|
|
|
236
236
|
readonly bucket_start_ms: {
|
|
237
237
|
readonly type: "integer";
|
|
238
238
|
};
|
|
239
|
-
}, "downloads" | "
|
|
239
|
+
}, "downloads" | "failed_launches" | "patch_downloads" | "patch_fallbacks" | "applies" | "failed_updates", {
|
|
240
240
|
readonly window: {
|
|
241
241
|
readonly eq: readonly ["identity"];
|
|
242
242
|
readonly sort: readonly ["bucket_start_ms"];
|
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);
|
|
@@ -95,8 +95,11 @@ type InsightsCoverage = {
|
|
|
95
95
|
* which are kept.
|
|
96
96
|
*/
|
|
97
97
|
interface ReleaseActivityMetrics {
|
|
98
|
+
/** Download reports of the release. */
|
|
98
99
|
readonly downloads: number;
|
|
99
|
-
|
|
100
|
+
/** Apply reports of the release: installations that started running it. */
|
|
101
|
+
readonly applies: number;
|
|
102
|
+
/** Launches that crashed on the release and recovered to the one before. */
|
|
100
103
|
readonly failedLaunches: number;
|
|
101
104
|
}
|
|
102
105
|
interface InsightsGetReleaseActivityInput {
|
|
@@ -95,8 +95,11 @@ type InsightsCoverage = {
|
|
|
95
95
|
* which are kept.
|
|
96
96
|
*/
|
|
97
97
|
interface ReleaseActivityMetrics {
|
|
98
|
+
/** Download reports of the release. */
|
|
98
99
|
readonly downloads: number;
|
|
99
|
-
|
|
100
|
+
/** Apply reports of the release: installations that started running it. */
|
|
101
|
+
readonly applies: number;
|
|
102
|
+
/** Launches that crashed on the release and recovered to the one before. */
|
|
100
103
|
readonly failedLaunches: number;
|
|
101
104
|
}
|
|
102
105
|
interface InsightsGetReleaseActivityInput {
|
package/dist/server/overview.cjs
CHANGED
|
@@ -31,7 +31,7 @@ const insightsOverviewDeltas = (event) => {
|
|
|
31
31
|
counters.set(key, {
|
|
32
32
|
identity,
|
|
33
33
|
downloads: (previous?.downloads ?? 0) + values.downloads,
|
|
34
|
-
|
|
34
|
+
applies: (previous?.applies ?? 0) + values.applies,
|
|
35
35
|
failedLaunches: (previous?.failedLaunches ?? 0) + values.failedLaunches,
|
|
36
36
|
activityIdentity: previous?.activityIdentity ?? values.activityIdentity
|
|
37
37
|
});
|
|
@@ -39,7 +39,7 @@ const insightsOverviewDeltas = (event) => {
|
|
|
39
39
|
const metric = (releaseId, values) => {
|
|
40
40
|
const windowed = {
|
|
41
41
|
...values,
|
|
42
|
-
|
|
42
|
+
applies: 0
|
|
43
43
|
};
|
|
44
44
|
if (releaseId !== null) for (const [periodKind, start] of [["lifetime", 0], ["hour", bucketStartMs]]) append({
|
|
45
45
|
scopeKind: "release",
|
|
@@ -66,21 +66,19 @@ const insightsOverviewDeltas = (event) => {
|
|
|
66
66
|
};
|
|
67
67
|
if (event.type === "UPDATE_DOWNLOADED") metric(event.to_release_id, {
|
|
68
68
|
downloads: 1,
|
|
69
|
-
|
|
69
|
+
applies: 0,
|
|
70
70
|
failedLaunches: 0
|
|
71
71
|
});
|
|
72
|
-
else if (event.type
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
});
|
|
83
|
-
}
|
|
72
|
+
else if (event.type === "UPDATE_APPLIED") metric(event.to_release_id, {
|
|
73
|
+
downloads: 0,
|
|
74
|
+
applies: 1,
|
|
75
|
+
failedLaunches: 0
|
|
76
|
+
});
|
|
77
|
+
else if (event.type === "RECOVERED") metric(event.from_release_id, {
|
|
78
|
+
downloads: 0,
|
|
79
|
+
applies: 0,
|
|
80
|
+
failedLaunches: 1
|
|
81
|
+
});
|
|
84
82
|
for (const platform of [event.platform, "all"]) for (const appVersionKind of ["specific", "all"]) append({
|
|
85
83
|
scopeKind: "usage",
|
|
86
84
|
releaseKind: "all",
|
|
@@ -93,7 +91,7 @@ const insightsOverviewDeltas = (event) => {
|
|
|
93
91
|
bucketStartMs
|
|
94
92
|
}, {
|
|
95
93
|
downloads: 0,
|
|
96
|
-
|
|
94
|
+
applies: 0,
|
|
97
95
|
failedLaunches: 0,
|
|
98
96
|
activityIdentity: event.install_id
|
|
99
97
|
});
|
package/dist/server/overview.mjs
CHANGED
|
@@ -31,7 +31,7 @@ const insightsOverviewDeltas = (event) => {
|
|
|
31
31
|
counters.set(key, {
|
|
32
32
|
identity,
|
|
33
33
|
downloads: (previous?.downloads ?? 0) + values.downloads,
|
|
34
|
-
|
|
34
|
+
applies: (previous?.applies ?? 0) + values.applies,
|
|
35
35
|
failedLaunches: (previous?.failedLaunches ?? 0) + values.failedLaunches,
|
|
36
36
|
activityIdentity: previous?.activityIdentity ?? values.activityIdentity
|
|
37
37
|
});
|
|
@@ -39,7 +39,7 @@ const insightsOverviewDeltas = (event) => {
|
|
|
39
39
|
const metric = (releaseId, values) => {
|
|
40
40
|
const windowed = {
|
|
41
41
|
...values,
|
|
42
|
-
|
|
42
|
+
applies: 0
|
|
43
43
|
};
|
|
44
44
|
if (releaseId !== null) for (const [periodKind, start] of [["lifetime", 0], ["hour", bucketStartMs]]) append({
|
|
45
45
|
scopeKind: "release",
|
|
@@ -66,21 +66,19 @@ const insightsOverviewDeltas = (event) => {
|
|
|
66
66
|
};
|
|
67
67
|
if (event.type === "UPDATE_DOWNLOADED") metric(event.to_release_id, {
|
|
68
68
|
downloads: 1,
|
|
69
|
-
|
|
69
|
+
applies: 0,
|
|
70
70
|
failedLaunches: 0
|
|
71
71
|
});
|
|
72
|
-
else if (event.type
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
});
|
|
83
|
-
}
|
|
72
|
+
else if (event.type === "UPDATE_APPLIED") metric(event.to_release_id, {
|
|
73
|
+
downloads: 0,
|
|
74
|
+
applies: 1,
|
|
75
|
+
failedLaunches: 0
|
|
76
|
+
});
|
|
77
|
+
else if (event.type === "RECOVERED") metric(event.from_release_id, {
|
|
78
|
+
downloads: 0,
|
|
79
|
+
applies: 0,
|
|
80
|
+
failedLaunches: 1
|
|
81
|
+
});
|
|
84
82
|
for (const platform of [event.platform, "all"]) for (const appVersionKind of ["specific", "all"]) append({
|
|
85
83
|
scopeKind: "usage",
|
|
86
84
|
releaseKind: "all",
|
|
@@ -93,7 +91,7 @@ const insightsOverviewDeltas = (event) => {
|
|
|
93
91
|
bucketStartMs
|
|
94
92
|
}, {
|
|
95
93
|
downloads: 0,
|
|
96
|
-
|
|
94
|
+
applies: 0,
|
|
97
95
|
failedLaunches: 0,
|
|
98
96
|
activityIdentity: event.install_id
|
|
99
97
|
});
|
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 },
|