@hot-updater/plugin-insights 1.0.0-rc.38 → 1.0.0-rc.40

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.
@@ -179,6 +179,10 @@ type ReportingOverview = InsightsScope & {
179
179
  readonly bundle?: {
180
180
  readonly bundleId: string;
181
181
  readonly reportingInstallations: InsightsCountMeasurement;
182
+ /**
183
+ * Download reports of the bundle, and in whole hours the downloads a
184
+ * launch or crash implied when its download report never arrived.
185
+ */
182
186
  readonly downloadedReports: InsightsCountMeasurement;
183
187
  readonly appliedReports: InsightsCountMeasurement;
184
188
  readonly recoveredReports: InsightsCountMeasurement;
@@ -179,6 +179,10 @@ type ReportingOverview = InsightsScope & {
179
179
  readonly bundle?: {
180
180
  readonly bundleId: string;
181
181
  readonly reportingInstallations: InsightsCountMeasurement;
182
+ /**
183
+ * Download reports of the bundle, and in whole hours the downloads a
184
+ * launch or crash implied when its download report never arrived.
185
+ */
182
186
  readonly downloadedReports: InsightsCountMeasurement;
183
187
  readonly appliedReports: InsightsCountMeasurement;
184
188
  readonly recoveredReports: InsightsCountMeasurement;
@@ -152,7 +152,11 @@ const countRaw = async (db, filter, from, to) => {
152
152
  }
153
153
  return total;
154
154
  };
155
- /** Whole hours from outcome counters; the partial hours at either edge from raw events. */
155
+ /**
156
+ * Whole hours from outcome counters; the partial hours at either edge from
157
+ * raw events. A download filter's whole hours count the downloads a launch
158
+ * or crash implied too, which its raw events do not hold.
159
+ */
156
160
  const countEvents = async (db, input) => {
157
161
  const { filter, sinceMs, beforeReceivedAtMs } = input;
158
162
  const start = hourCeil(sinceMs);
@@ -171,8 +175,9 @@ const countEvents = async (db, input) => {
171
175
  return await countRaw(db, filter, sinceMs, start) + hours.reduce((sum, row) => sum + row.events, 0) + await countRaw(db, filter, end, beforeReceivedAtMs);
172
176
  };
173
177
  /**
174
- * A bundle filter's stored events in each interval of whole hours: one read
175
- * of its hourly counts, every interval present.
178
+ * A bundle filter's stored events in each interval of whole hours, and for a
179
+ * download filter the downloads a launch or crash implied: one read of its
180
+ * hourly counts, every interval present.
176
181
  */
177
182
  const countEventSeries = async (db, input) => {
178
183
  const { filter, intervalMs } = input;
@@ -152,7 +152,11 @@ const countRaw = async (db, filter, from, to) => {
152
152
  }
153
153
  return total;
154
154
  };
155
- /** Whole hours from outcome counters; the partial hours at either edge from raw events. */
155
+ /**
156
+ * Whole hours from outcome counters; the partial hours at either edge from
157
+ * raw events. A download filter's whole hours count the downloads a launch
158
+ * or crash implied too, which its raw events do not hold.
159
+ */
156
160
  const countEvents = async (db, input) => {
157
161
  const { filter, sinceMs, beforeReceivedAtMs } = input;
158
162
  const start = hourCeil(sinceMs);
@@ -171,8 +175,9 @@ const countEvents = async (db, input) => {
171
175
  return await countRaw(db, filter, sinceMs, start) + hours.reduce((sum, row) => sum + row.events, 0) + await countRaw(db, filter, end, beforeReceivedAtMs);
172
176
  };
173
177
  /**
174
- * A bundle filter's stored events in each interval of whole hours: one read
175
- * of its hourly counts, every interval present.
178
+ * A bundle filter's stored events in each interval of whole hours, and for a
179
+ * download filter the downloads a launch or crash implied: one read of its
180
+ * hourly counts, every interval present.
176
181
  */
177
182
  const countEventSeries = async (db, input) => {
178
183
  const { filter, intervalMs } = input;
@@ -137,17 +137,25 @@ const countEvent = (tx, event) => {
137
137
  };
138
138
  /**
139
139
  * A stored event's outcome rows: its bundle filter's hour, when it has one
140
- * (`bundleRefsOf`), and every stored event's UTC day.
140
+ * (`bundleRefsOf`), and every stored event's UTC day. A download that a
141
+ * launch or crash implied counts in its bundle's download hour too, in the
142
+ * hour of that launch or crash, so the download series covers what the
143
+ * release's downloads count; the launch or crash is its row.
141
144
  */
142
145
  const countOutcome = (tx, event) => {
143
146
  const shardBy = event.install_id;
144
- for (const bundleRef of require_schema.bundleRefsOf(event)) tx.aggregate("insights_outcomes", {
147
+ const hour = (type, bundleRef) => tx.aggregate("insights_outcomes", {
145
148
  platform: event.platform,
146
149
  channel: event.channel,
147
- type: event.type,
150
+ type,
148
151
  bundle_ref: bundleRef,
149
152
  bucket_start_ms: hourOf(event.received_at_ms)
150
153
  }, { events: 1 }, { shardBy });
154
+ for (const bundleRef of require_schema.bundleRefsOf(event)) hour(event.type, bundleRef);
155
+ if (event.metadata.implied_download === true) hour("UPDATE_DOWNLOADED", require_schema.bundleRefOfFilter({
156
+ type: "UPDATE_DOWNLOADED",
157
+ toBundleId: event.type === "RECOVERED" ? event.from_bundle_id : event.to_bundle_id
158
+ }));
151
159
  tx.aggregate("insights_outcomes", {
152
160
  ...require_schema.DAILY_EVENTS,
153
161
  bucket_start_ms: dayOf(event.received_at_ms)
@@ -1,5 +1,5 @@
1
1
  import { runningBuiltinBundleId } from "./eventRow.mjs";
2
- import { DAILY_EVENTS, DAY_MS, HOUR_MS, bundleRefsOf, isLaunch } from "./schema.mjs";
2
+ import { DAILY_EVENTS, DAY_MS, HOUR_MS, bundleRefOfFilter, bundleRefsOf, isLaunch } from "./schema.mjs";
3
3
  import { assertBundleEventRow } from "./contract.mjs";
4
4
  import { insightsKey, insightsOverviewDeltas, insightsOverviewId } from "./overview.mjs";
5
5
  import { addDistinct, compareUtf8, extractTimestampFromUUIDv7, isUUIDv7 } from "@hot-updater/plugin-core";
@@ -137,17 +137,25 @@ const countEvent = (tx, event) => {
137
137
  };
138
138
  /**
139
139
  * A stored event's outcome rows: its bundle filter's hour, when it has one
140
- * (`bundleRefsOf`), and every stored event's UTC day.
140
+ * (`bundleRefsOf`), and every stored event's UTC day. A download that a
141
+ * launch or crash implied counts in its bundle's download hour too, in the
142
+ * hour of that launch or crash, so the download series covers what the
143
+ * release's downloads count; the launch or crash is its row.
141
144
  */
142
145
  const countOutcome = (tx, event) => {
143
146
  const shardBy = event.install_id;
144
- for (const bundleRef of bundleRefsOf(event)) tx.aggregate("insights_outcomes", {
147
+ const hour = (type, bundleRef) => tx.aggregate("insights_outcomes", {
145
148
  platform: event.platform,
146
149
  channel: event.channel,
147
- type: event.type,
150
+ type,
148
151
  bundle_ref: bundleRef,
149
152
  bucket_start_ms: hourOf(event.received_at_ms)
150
153
  }, { events: 1 }, { shardBy });
154
+ for (const bundleRef of bundleRefsOf(event)) hour(event.type, bundleRef);
155
+ if (event.metadata.implied_download === true) hour("UPDATE_DOWNLOADED", bundleRefOfFilter({
156
+ type: "UPDATE_DOWNLOADED",
157
+ toBundleId: event.type === "RECOVERED" ? event.from_bundle_id : event.to_bundle_id
158
+ }));
151
159
  tx.aggregate("insights_outcomes", {
152
160
  ...DAILY_EVENTS,
153
161
  bucket_start_ms: dayOf(event.received_at_ms)
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.38",
4
+ "version": "1.0.0-rc.40",
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.38"
36
+ "@hot-updater/protocol": "1.0.0-rc.40"
37
37
  },
38
38
  "peerDependencies": {
39
- "@hot-updater/plugin-core": "^1.0.0-rc.38"
39
+ "@hot-updater/plugin-core": "^1.0.0-rc.40"
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/plugin-core": "1.0.0-rc.38",
50
- "@hot-updater/test-utils": "1.0.0-rc.38"
49
+ "@hot-updater/plugin-core": "1.0.0-rc.40",
50
+ "@hot-updater/test-utils": "1.0.0-rc.40"
51
51
  },
52
52
  "nx": {
53
53
  "implicitDependencies": [