@hot-updater/firebase 1.0.0-rc.37 → 1.0.0-rc.39

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.
@@ -4524,7 +4524,7 @@ const createKvAdapter = ({ store, tablePrefix = "" }) => {
4524
4524
  };
4525
4525
  //#endregion
4526
4526
  //#region ../../packages/server/dist/version.mjs
4527
- const HOT_UPDATER_SERVER_VERSION = "1.0.0-rc.37";
4527
+ const HOT_UPDATER_SERVER_VERSION = "1.0.0-rc.39";
4528
4528
  //#endregion
4529
4529
  //#region ../../packages/server/dist/handlerVersionRoutes.mjs
4530
4530
  /**
@@ -9471,17 +9471,25 @@ const countEvent = (tx, event) => {
9471
9471
  };
9472
9472
  /**
9473
9473
  * A stored event's outcome rows: its bundle filter's hour, when it has one
9474
- * (`bundleRefsOf`), and every stored event's UTC day.
9474
+ * (`bundleRefsOf`), and every stored event's UTC day. A download that a
9475
+ * launch or crash implied counts in its bundle's download hour too, in the
9476
+ * hour of that launch or crash, so the download series covers what the
9477
+ * release's downloads count; the launch or crash is its row.
9475
9478
  */
9476
9479
  const countOutcome = (tx, event) => {
9477
9480
  const shardBy = event.install_id;
9478
- for (const bundleRef of bundleRefsOf(event)) tx.aggregate("insights_outcomes", {
9481
+ const hour = (type, bundleRef) => tx.aggregate("insights_outcomes", {
9479
9482
  platform: event.platform,
9480
9483
  channel: event.channel,
9481
- type: event.type,
9484
+ type,
9482
9485
  bundle_ref: bundleRef,
9483
9486
  bucket_start_ms: hourOf(event.received_at_ms)
9484
9487
  }, { events: 1 }, { shardBy });
9488
+ for (const bundleRef of bundleRefsOf(event)) hour(event.type, bundleRef);
9489
+ if (event.metadata.implied_download === true) hour("UPDATE_DOWNLOADED", bundleRefOfFilter({
9490
+ type: "UPDATE_DOWNLOADED",
9491
+ toBundleId: event.type === "RECOVERED" ? event.from_bundle_id : event.to_bundle_id
9492
+ }));
9485
9493
  tx.aggregate("insights_outcomes", {
9486
9494
  ...DAILY_EVENTS,
9487
9495
  bucket_start_ms: dayOf(event.received_at_ms)
@@ -9596,19 +9604,25 @@ const minBundleIdOf = (row) => row.metadata?.min_bundle_id;
9596
9604
  /** When the client made a report, from the UUIDv7 it gave it. */
9597
9605
  const madeAt = (id) => isUUIDv7(id) ? extractTimestampFromUUIDv7(id) : null;
9598
9606
  /**
9599
- * A report that arrived after its installation moved past it: a download or
9600
- * an apply of the bundle the head already runs, or an UNCHANGED report of the
9601
- * bundle an apply head left, made before that apply. A reload can cut one
9602
- * runtime's report short and deliver it after the next runtime's. It stays
9603
- * in history but moves and counts nothing.
9607
+ * A report its installation already moved past, which stays in history but
9608
+ * moves and counts nothing:
9609
+ * - a download or an apply of the bundle the head already runs, or a
9610
+ * download that repeats the head's pending one, from the same bundle to
9611
+ * the same bundle: the installation's download or launch already counted;
9612
+ * - an UNCHANGED report made, by its UUIDv7, before the head's report, even
9613
+ * after a later report replaced the apply it preceded: a reload can cut
9614
+ * one runtime's report short and deliver it after the next runtime's.
9615
+ *
9616
+ * Report IDs are made on the device, so a device whose clock jumps back has
9617
+ * its launch reports judged late until its clock passes its latest report.
9604
9618
  */
9605
9619
  const isLate = (event, head) => {
9606
9620
  if (head === null) return false;
9607
- if (event.type === "UPDATE_DOWNLOADED" || event.type === "UPDATE_APPLIED") return event.to_bundle_id === runningOf(head).bundle_id;
9608
- if (event.type === "UNCHANGED" && head.type === "UPDATE_APPLIED" && event.to_bundle_id === head.from_bundle_id) {
9621
+ if (event.type === "UPDATE_DOWNLOADED" || event.type === "UPDATE_APPLIED") return event.to_bundle_id === runningOf(head).bundle_id || event.type === "UPDATE_DOWNLOADED" && head.type === "UPDATE_DOWNLOADED" && event.from_bundle_id === head.from_bundle_id && event.to_bundle_id === head.to_bundle_id;
9622
+ if (event.type === "UNCHANGED") {
9609
9623
  const made = madeAt(event.id);
9610
- const applied = madeAt(head.id);
9611
- return made !== null && applied !== null && made < applied;
9624
+ const latest = madeAt(head.id);
9625
+ return made !== null && latest !== null && made < latest;
9612
9626
  }
9613
9627
  return false;
9614
9628
  };
@@ -9908,7 +9922,11 @@ const countRaw = async (db, filter, from, to) => {
9908
9922
  }
9909
9923
  return total;
9910
9924
  };
9911
- /** Whole hours from outcome counters; the partial hours at either edge from raw events. */
9925
+ /**
9926
+ * Whole hours from outcome counters; the partial hours at either edge from
9927
+ * raw events. A download filter's whole hours count the downloads a launch
9928
+ * or crash implied too, which its raw events do not hold.
9929
+ */
9912
9930
  const countEvents = async (db, input) => {
9913
9931
  const { filter, sinceMs, beforeReceivedAtMs } = input;
9914
9932
  const start = hourCeil(sinceMs);
@@ -9927,8 +9945,9 @@ const countEvents = async (db, input) => {
9927
9945
  return await countRaw(db, filter, sinceMs, start) + hours.reduce((sum, row) => sum + row.events, 0) + await countRaw(db, filter, end, beforeReceivedAtMs);
9928
9946
  };
9929
9947
  /**
9930
- * A bundle filter's stored events in each interval of whole hours: one read
9931
- * of its hourly counts, every interval present.
9948
+ * A bundle filter's stored events in each interval of whole hours, and for a
9949
+ * download filter the downloads a launch or crash implied: one read of its
9950
+ * hourly counts, every interval present.
9932
9951
  */
9933
9952
  const countEventSeries = async (db, input) => {
9934
9953
  const { filter, intervalMs } = input;
package/dist/index.d.cts CHANGED
@@ -99,9 +99,10 @@ type DatabaseBundleEventMetadata = DatabaseJsonObject & {
99
99
  /** A kept `UNCHANGED` row: what it changed, which the server sets. */
100
100
  readonly change?: BundleEventChange;
101
101
  /**
102
- * A download or apply that arrived after its installation already ran its
103
- * target, as when a reload cut the first runtime's report short: the
104
- * server keeps it in history, but it moves and counts nothing.
102
+ * A download or apply of a target its installation already ran, as when
103
+ * a reload cut the first runtime's report short, or a download that
104
+ * repeats the pending one: the server keeps it in history, but it moves
105
+ * and counts nothing.
105
106
  */
106
107
  readonly late?: true;
107
108
  /**
package/dist/index.d.mts CHANGED
@@ -99,9 +99,10 @@ type DatabaseBundleEventMetadata = DatabaseJsonObject & {
99
99
  /** A kept `UNCHANGED` row: what it changed, which the server sets. */
100
100
  readonly change?: BundleEventChange;
101
101
  /**
102
- * A download or apply that arrived after its installation already ran its
103
- * target, as when a reload cut the first runtime's report short: the
104
- * server keeps it in history, but it moves and counts nothing.
102
+ * A download or apply of a target its installation already ran, as when
103
+ * a reload cut the first runtime's report short, or a download that
104
+ * repeats the pending one: the server keeps it in history, but it moves
105
+ * and counts nothing.
105
106
  */
106
107
  readonly late?: true;
107
108
  /**
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@hot-updater/firebase",
3
3
  "type": "module",
4
- "version": "1.0.0-rc.37",
4
+ "version": "1.0.0-rc.39",
5
5
  "description": "React Native OTA solution for self-hosted",
6
6
  "main": "dist/index.cjs",
7
7
  "types": "dist/index.d.cts",
@@ -37,10 +37,10 @@
37
37
  ],
38
38
  "dependencies": {
39
39
  "hono": "4.12.34",
40
- "@hot-updater/cli-tools": "1.0.0-rc.37",
41
- "@hot-updater/protocol": "1.0.0-rc.37",
42
- "@hot-updater/plugin-core": "1.0.0-rc.37",
43
- "@hot-updater/server": "1.0.0-rc.37"
40
+ "@hot-updater/protocol": "1.0.0-rc.39",
41
+ "@hot-updater/plugin-core": "1.0.0-rc.39",
42
+ "@hot-updater/server": "1.0.0-rc.39",
43
+ "@hot-updater/cli-tools": "1.0.0-rc.39"
44
44
  },
45
45
  "publishConfig": {
46
46
  "access": "public"
@@ -55,8 +55,8 @@
55
55
  "firebase-tools": "15.29.0",
56
56
  "fkill": "^9.0.0",
57
57
  "mime": "^4.0.4",
58
- "@hot-updater/mock": "1.0.0-rc.37",
59
- "@hot-updater/test-utils": "1.0.0-rc.37"
58
+ "@hot-updater/test-utils": "1.0.0-rc.39",
59
+ "@hot-updater/mock": "1.0.0-rc.39"
60
60
  },
61
61
  "peerDependencies": {
62
62
  "firebase-admin": "*",