@hot-updater/firebase 1.0.0-rc.28 → 1.0.0-rc.29

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.28";
4527
+ const HOT_UPDATER_SERVER_VERSION = "1.0.0-rc.29";
4528
4528
  //#endregion
4529
4529
  //#region ../../packages/server/dist/handlerVersionRoutes.mjs
4530
4530
  /**
@@ -7684,9 +7684,10 @@ const apiKeys = (options = {}) => {
7684
7684
  //#region ../insights/dist/server/eventRow.mjs
7685
7685
  const isOptional = (value, key, valid) => !Object.hasOwn(value, key) || valid(value[key]);
7686
7686
  const isString = (value) => typeof value === "string";
7687
+ 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);
7687
7688
  /** An `UPDATE_FAILED` report's stored failure: a stage and a reason, and what else the client knew. */
7688
7689
  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) && isOptional(value, "previous_process_exit", isString);
7689
- 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, "delivery", isString) && isOptional(value, "patch_fallback", (flag) => typeof flag === "boolean") && isOptional(value, "previous_process_exit", isString);
7690
+ 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") && isOptional(value, "previous_process_exit", isString);
7690
7691
  const isRecord$2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
7691
7692
  const isIdentity$1 = (value) => typeof value === "string" && value.length > 0 && value.length <= 255;
7692
7693
  const isTextOrNull = (value) => value === null || typeof value === "string";
@@ -8052,6 +8053,17 @@ function readFailure(value) {
8052
8053
  ...previousProcessExit === void 0 ? {} : { previousProcessExit }
8053
8054
  };
8054
8055
  }
8056
+ function readHttpResponse(value) {
8057
+ if (!isRecord$1(value) || value.resource !== "catalog" && value.resource !== "artifact" || typeof value.path !== "string" || value.path.length > 1024 || !Number.isSafeInteger(value.status) || value.status < 100 || value.status > 599 || value.body !== null && (typeof value.body !== "string" || new TextEncoder().encode(JSON.stringify(value.body)).byteLength > 4096) || typeof value.bodyTruncated !== "boolean" || !Number.isSafeInteger(value.receivedAtMs) || value.receivedAtMs < 0) throw new InsightsBadRequestError("Invalid HTTP response details");
8058
+ return {
8059
+ resource: value.resource,
8060
+ path: value.path,
8061
+ status: value.status,
8062
+ body: value.body,
8063
+ bodyTruncated: value.bodyTruncated,
8064
+ receivedAtMs: value.receivedAtMs
8065
+ };
8066
+ }
8055
8067
  async function readBoundedText(request) {
8056
8068
  const contentLength = request.headers.get("content-length");
8057
8069
  const declaredByteLength = Number(contentLength);
@@ -8087,7 +8099,10 @@ function requireEvent(payload) {
8087
8099
  const platform = requireStringField(payload, "platform");
8088
8100
  if (platform !== "ios" && platform !== "android") throw new InsightsBadRequestError("Invalid event field: platform");
8089
8101
  const eventId = readEventId(payload);
8102
+ const metadata = readMetadata(payload);
8103
+ const httpMetadata = metadata.httpResponse === void 0 ? {} : { httpResponse: readHttpResponse(metadata.httpResponse) };
8090
8104
  const base = {
8105
+ ...metadata.httpResponse === void 0 ? {} : { metadata: httpMetadata },
8091
8106
  ...eventId === void 0 ? {} : { eventId },
8092
8107
  installId: requireIdentityField(payload, "installId"),
8093
8108
  toBundleId: requireStringField(payload, "toBundleId"),
@@ -8111,11 +8126,11 @@ function requireEvent(payload) {
8111
8126
  updateStrategy
8112
8127
  };
8113
8128
  };
8114
- const metadata = readMetadata(payload);
8115
8129
  switch (type) {
8116
8130
  case "UPDATE_DOWNLOADED": {
8117
8131
  const delivery = metadata.delivery;
8118
8132
  const read = {
8133
+ ...httpMetadata,
8119
8134
  ...delivery == null ? {} : { delivery: oneOf(DELIVERIES, delivery) },
8120
8135
  ...metadata.patchFallback === true ? { patchFallback: true } : {}
8121
8136
  };
@@ -8134,13 +8149,19 @@ function requireEvent(payload) {
8134
8149
  return {
8135
8150
  ...movement(),
8136
8151
  type,
8137
- ...previousProcessExit === void 0 ? {} : { metadata: { previousProcessExit } }
8152
+ ...previousProcessExit === void 0 ? {} : { metadata: {
8153
+ ...httpMetadata,
8154
+ previousProcessExit
8155
+ } }
8138
8156
  };
8139
8157
  }
8140
8158
  case "UPDATE_FAILED": return {
8141
8159
  ...movement(),
8142
8160
  type,
8143
- metadata: { failure: readFailure(metadata.failure) }
8161
+ metadata: {
8162
+ ...httpMetadata,
8163
+ failure: readFailure(metadata.failure)
8164
+ }
8144
8165
  };
8145
8166
  case "UNCHANGED":
8146
8167
  if (payload.fromBundleId !== null || payload.updateStrategy !== null) throw new InsightsBadRequestError("Invalid unchanged event shape");
@@ -8170,7 +8191,16 @@ function createBundleEventRow(input) {
8170
8191
  to_release_id: input.toReleaseId,
8171
8192
  user_id: input.userId ?? null
8172
8193
  };
8194
+ const response = input.metadata?.httpResponse;
8173
8195
  const metadata = {
8196
+ ...response ? { http_response: {
8197
+ resource: response.resource,
8198
+ path: response.path,
8199
+ status: response.status,
8200
+ body: response.body,
8201
+ body_truncated: response.bodyTruncated,
8202
+ received_at_ms: response.receivedAtMs
8203
+ } } : {},
8174
8204
  cohort: input.cohort,
8175
8205
  fingerprint_hash: input.fingerprintHash,
8176
8206
  sdk_version: input.sdkVersion ?? null,
@@ -8394,6 +8424,14 @@ const toFailure = (failure) => ({
8394
8424
  });
8395
8425
  /** What a row's metadata adds for its type: a failure, a delivery, an exit reason. */
8396
8426
  const eventDetails = ({ type, metadata }) => ({
8427
+ ...metadata.http_response !== void 0 ? { httpResponse: {
8428
+ resource: metadata.http_response.resource,
8429
+ path: metadata.http_response.path,
8430
+ status: metadata.http_response.status,
8431
+ body: metadata.http_response.body,
8432
+ bodyTruncated: metadata.http_response.body_truncated,
8433
+ receivedAtMs: metadata.http_response.received_at_ms
8434
+ } } : {},
8397
8435
  ...type === "UPDATE_FAILED" && metadata.failure !== void 0 ? { failure: toFailure(metadata.failure) } : {},
8398
8436
  ...type === "UPDATE_DOWNLOADED" && metadata.delivery !== void 0 ? { delivery: metadata.delivery } : {},
8399
8437
  ...type === "UPDATE_DOWNLOADED" && metadata.patch_fallback === true ? { patchFallback: true } : {},
@@ -8416,6 +8454,7 @@ const toEventHistoryRow = (row) => ({
8416
8454
  ...eventDetails(row)
8417
8455
  });
8418
8456
  const toInstallationRow = (row) => ({
8457
+ ...eventDetails(row).httpResponse ? { httpResponse: eventDetails(row).httpResponse } : {},
8419
8458
  appVersion: row.app_version,
8420
8459
  channel: row.channel,
8421
8460
  cohort: row.metadata.cohort,
package/dist/index.d.cts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { DatabaseJsonObject, EngineDatabase, Platform, PluginTables, StorageAdapterWith } from "@hot-updater/plugin-core";
2
2
  import { AppOptions } from "firebase-admin/app";
3
+ import "@hot-updater/protocol";
3
4
  //#region src/firebaseDatabase.d.ts
4
5
  type FirebaseDatabaseConfig = AppOptions & {
5
6
  /** The one collection the database keeps its items in. */
@@ -55,6 +56,14 @@ type BundleEventFailure = DatabaseJsonObject & {
55
56
  /** Android's `ApplicationExitInfo` reason for the process before this one. */
56
57
  readonly previous_process_exit?: string;
57
58
  };
59
+ type DatabaseHttpResponse = DatabaseJsonObject & {
60
+ readonly resource: "catalog" | "artifact";
61
+ readonly path: string;
62
+ readonly status: number;
63
+ readonly body: string | null;
64
+ readonly body_truncated: boolean;
65
+ readonly received_at_ms: number;
66
+ };
58
67
  /** Ancillary report data; queryable identity and lifecycle fields stay on the row. */
59
68
  type DatabaseBundleEventMetadata = DatabaseJsonObject & {
60
69
  readonly cohort: string;
@@ -63,6 +72,7 @@ type DatabaseBundleEventMetadata = DatabaseJsonObject & {
63
72
  readonly sdk_version: string | null;
64
73
  /** `UPDATE_FAILED`: what failed. */
65
74
  readonly failure?: BundleEventFailure;
75
+ readonly http_response?: DatabaseHttpResponse;
66
76
  /** `UPDATE_DOWNLOADED`: how the bundle arrived. */
67
77
  readonly delivery?: "patch" | "manifest" | "archive" | "unknown";
68
78
  /** `UPDATE_DOWNLOADED`: a patch failed and the full files came instead. */
package/dist/index.d.mts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { DatabaseJsonObject, EngineDatabase, Platform, PluginTables, StorageAdapterWith } from "@hot-updater/plugin-core";
2
2
  import { AppOptions } from "firebase-admin/app";
3
+ import "@hot-updater/protocol";
3
4
  //#region src/firebaseDatabase.d.ts
4
5
  type FirebaseDatabaseConfig = AppOptions & {
5
6
  /** The one collection the database keeps its items in. */
@@ -55,6 +56,14 @@ type BundleEventFailure = DatabaseJsonObject & {
55
56
  /** Android's `ApplicationExitInfo` reason for the process before this one. */
56
57
  readonly previous_process_exit?: string;
57
58
  };
59
+ type DatabaseHttpResponse = DatabaseJsonObject & {
60
+ readonly resource: "catalog" | "artifact";
61
+ readonly path: string;
62
+ readonly status: number;
63
+ readonly body: string | null;
64
+ readonly body_truncated: boolean;
65
+ readonly received_at_ms: number;
66
+ };
58
67
  /** Ancillary report data; queryable identity and lifecycle fields stay on the row. */
59
68
  type DatabaseBundleEventMetadata = DatabaseJsonObject & {
60
69
  readonly cohort: string;
@@ -63,6 +72,7 @@ type DatabaseBundleEventMetadata = DatabaseJsonObject & {
63
72
  readonly sdk_version: string | null;
64
73
  /** `UPDATE_FAILED`: what failed. */
65
74
  readonly failure?: BundleEventFailure;
75
+ readonly http_response?: DatabaseHttpResponse;
66
76
  /** `UPDATE_DOWNLOADED`: how the bundle arrived. */
67
77
  readonly delivery?: "patch" | "manifest" | "archive" | "unknown";
68
78
  /** `UPDATE_DOWNLOADED`: a patch failed and the full files came instead. */
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.28",
4
+ "version": "1.0.0-rc.29",
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.28",
41
- "@hot-updater/protocol": "1.0.0-rc.27",
42
- "@hot-updater/plugin-core": "1.0.0-rc.27",
43
- "@hot-updater/server": "1.0.0-rc.28"
40
+ "@hot-updater/cli-tools": "1.0.0-rc.29",
41
+ "@hot-updater/protocol": "1.0.0-rc.28",
42
+ "@hot-updater/plugin-core": "1.0.0-rc.28",
43
+ "@hot-updater/server": "1.0.0-rc.29"
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.27",
59
- "@hot-updater/test-utils": "1.0.0-rc.27"
58
+ "@hot-updater/mock": "1.0.0-rc.28",
59
+ "@hot-updater/test-utils": "1.0.0-rc.28"
60
60
  },
61
61
  "peerDependencies": {
62
62
  "firebase-admin": "*",