@hot-updater/firebase 1.0.0-rc.27 → 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.27";
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
- 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, "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);
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);
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";
@@ -8037,6 +8038,8 @@ function readFailure(value) {
8037
8038
  const failure = isRecord$1(value) ? value : {};
8038
8039
  const httpStatus = failure.httpStatus;
8039
8040
  const originCode = readCode(failure.originCode);
8041
+ const errorMessage = typeof failure.errorMessage === "string" && failure.errorMessage.length <= 2048 ? failure.errorMessage : void 0;
8042
+ const errorStack = typeof failure.errorStack === "string" && failure.errorStack.length <= 4096 ? failure.errorStack : void 0;
8040
8043
  const previousProcessExit = readCode(failure.previousProcessExit);
8041
8044
  return {
8042
8045
  stage: oneOf(STAGES, failure.stage),
@@ -8045,9 +8048,22 @@ function readFailure(value) {
8045
8048
  ...Number.isSafeInteger(httpStatus) && httpStatus >= 100 && httpStatus <= 599 ? { httpStatus } : {},
8046
8049
  ...failure.transport == null ? {} : { transport: oneOf(TRANSPORTS, failure.transport) },
8047
8050
  ...originCode === void 0 ? {} : { originCode },
8051
+ ...errorMessage === void 0 ? {} : { errorMessage },
8052
+ ...errorStack === void 0 ? {} : { errorStack },
8048
8053
  ...previousProcessExit === void 0 ? {} : { previousProcessExit }
8049
8054
  };
8050
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
+ }
8051
8067
  async function readBoundedText(request) {
8052
8068
  const contentLength = request.headers.get("content-length");
8053
8069
  const declaredByteLength = Number(contentLength);
@@ -8083,7 +8099,10 @@ function requireEvent(payload) {
8083
8099
  const platform = requireStringField(payload, "platform");
8084
8100
  if (platform !== "ios" && platform !== "android") throw new InsightsBadRequestError("Invalid event field: platform");
8085
8101
  const eventId = readEventId(payload);
8102
+ const metadata = readMetadata(payload);
8103
+ const httpMetadata = metadata.httpResponse === void 0 ? {} : { httpResponse: readHttpResponse(metadata.httpResponse) };
8086
8104
  const base = {
8105
+ ...metadata.httpResponse === void 0 ? {} : { metadata: httpMetadata },
8087
8106
  ...eventId === void 0 ? {} : { eventId },
8088
8107
  installId: requireIdentityField(payload, "installId"),
8089
8108
  toBundleId: requireStringField(payload, "toBundleId"),
@@ -8107,11 +8126,11 @@ function requireEvent(payload) {
8107
8126
  updateStrategy
8108
8127
  };
8109
8128
  };
8110
- const metadata = readMetadata(payload);
8111
8129
  switch (type) {
8112
8130
  case "UPDATE_DOWNLOADED": {
8113
8131
  const delivery = metadata.delivery;
8114
8132
  const read = {
8133
+ ...httpMetadata,
8115
8134
  ...delivery == null ? {} : { delivery: oneOf(DELIVERIES, delivery) },
8116
8135
  ...metadata.patchFallback === true ? { patchFallback: true } : {}
8117
8136
  };
@@ -8130,13 +8149,19 @@ function requireEvent(payload) {
8130
8149
  return {
8131
8150
  ...movement(),
8132
8151
  type,
8133
- ...previousProcessExit === void 0 ? {} : { metadata: { previousProcessExit } }
8152
+ ...previousProcessExit === void 0 ? {} : { metadata: {
8153
+ ...httpMetadata,
8154
+ previousProcessExit
8155
+ } }
8134
8156
  };
8135
8157
  }
8136
8158
  case "UPDATE_FAILED": return {
8137
8159
  ...movement(),
8138
8160
  type,
8139
- metadata: { failure: readFailure(metadata.failure) }
8161
+ metadata: {
8162
+ ...httpMetadata,
8163
+ failure: readFailure(metadata.failure)
8164
+ }
8140
8165
  };
8141
8166
  case "UNCHANGED":
8142
8167
  if (payload.fromBundleId !== null || payload.updateStrategy !== null) throw new InsightsBadRequestError("Invalid unchanged event shape");
@@ -8166,7 +8191,16 @@ function createBundleEventRow(input) {
8166
8191
  to_release_id: input.toReleaseId,
8167
8192
  user_id: input.userId ?? null
8168
8193
  };
8194
+ const response = input.metadata?.httpResponse;
8169
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
+ } } : {},
8170
8204
  cohort: input.cohort,
8171
8205
  fingerprint_hash: input.fingerprintHash,
8172
8206
  sdk_version: input.sdkVersion ?? null,
@@ -8215,6 +8249,8 @@ function createBundleEventRow(input) {
8215
8249
  failure: {
8216
8250
  stage: failure.stage,
8217
8251
  reason: failure.reason,
8252
+ ...failure.errorMessage === void 0 ? {} : { error_message: failure.errorMessage },
8253
+ ...failure.errorStack === void 0 ? {} : { error_stack: failure.errorStack },
8218
8254
  ...failure.resource === void 0 ? {} : { resource: failure.resource },
8219
8255
  ...failure.httpStatus === void 0 ? {} : { http_status: failure.httpStatus },
8220
8256
  ...failure.transport === void 0 ? {} : { transport: failure.transport },
@@ -8378,6 +8414,8 @@ const assertEventRows = (rows, input) => {
8378
8414
  const toFailure = (failure) => ({
8379
8415
  stage: failure.stage,
8380
8416
  reason: failure.reason,
8417
+ ...failure.error_message === void 0 ? {} : { errorMessage: failure.error_message },
8418
+ ...failure.error_stack === void 0 ? {} : { errorStack: failure.error_stack },
8381
8419
  ...failure.resource === void 0 ? {} : { resource: failure.resource },
8382
8420
  ...failure.http_status === void 0 ? {} : { httpStatus: failure.http_status },
8383
8421
  ...failure.transport === void 0 ? {} : { transport: failure.transport },
@@ -8386,12 +8424,22 @@ const toFailure = (failure) => ({
8386
8424
  });
8387
8425
  /** What a row's metadata adds for its type: a failure, a delivery, an exit reason. */
8388
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
+ } } : {},
8389
8435
  ...type === "UPDATE_FAILED" && metadata.failure !== void 0 ? { failure: toFailure(metadata.failure) } : {},
8390
8436
  ...type === "UPDATE_DOWNLOADED" && metadata.delivery !== void 0 ? { delivery: metadata.delivery } : {},
8391
8437
  ...type === "UPDATE_DOWNLOADED" && metadata.patch_fallback === true ? { patchFallback: true } : {},
8392
8438
  ...type === "RECOVERED" && metadata.previous_process_exit !== void 0 ? { previousProcessExit: metadata.previous_process_exit } : {}
8393
8439
  });
8394
8440
  const toEventHistoryRow = (row) => ({
8441
+ ...row.to_release_id == null ? {} : { toReleaseId: row.to_release_id },
8442
+ ...row.metadata.sdk_version == null ? {} : { sdkVersion: row.metadata.sdk_version },
8395
8443
  appVersion: row.app_version,
8396
8444
  channel: row.channel,
8397
8445
  cohort: row.metadata.cohort,
@@ -8406,6 +8454,7 @@ const toEventHistoryRow = (row) => ({
8406
8454
  ...eventDetails(row)
8407
8455
  });
8408
8456
  const toInstallationRow = (row) => ({
8457
+ ...eventDetails(row).httpResponse ? { httpResponse: eventDetails(row).httpResponse } : {},
8409
8458
  appVersion: row.app_version,
8410
8459
  channel: row.channel,
8411
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. */
@@ -50,9 +51,19 @@ type BundleEventFailure = DatabaseJsonObject & {
50
51
  readonly transport?: "timeout" | "dns" | "tls" | "connection" | "offline" | "cancelled" | "unknown";
51
52
  /** The storage origin's error code, such as `ExpiredToken`. */
52
53
  readonly origin_code?: string;
54
+ readonly error_message?: string;
55
+ readonly error_stack?: string;
53
56
  /** Android's `ApplicationExitInfo` reason for the process before this one. */
54
57
  readonly previous_process_exit?: string;
55
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
+ };
56
67
  /** Ancillary report data; queryable identity and lifecycle fields stay on the row. */
57
68
  type DatabaseBundleEventMetadata = DatabaseJsonObject & {
58
69
  readonly cohort: string;
@@ -61,6 +72,7 @@ type DatabaseBundleEventMetadata = DatabaseJsonObject & {
61
72
  readonly sdk_version: string | null;
62
73
  /** `UPDATE_FAILED`: what failed. */
63
74
  readonly failure?: BundleEventFailure;
75
+ readonly http_response?: DatabaseHttpResponse;
64
76
  /** `UPDATE_DOWNLOADED`: how the bundle arrived. */
65
77
  readonly delivery?: "patch" | "manifest" | "archive" | "unknown";
66
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. */
@@ -50,9 +51,19 @@ type BundleEventFailure = DatabaseJsonObject & {
50
51
  readonly transport?: "timeout" | "dns" | "tls" | "connection" | "offline" | "cancelled" | "unknown";
51
52
  /** The storage origin's error code, such as `ExpiredToken`. */
52
53
  readonly origin_code?: string;
54
+ readonly error_message?: string;
55
+ readonly error_stack?: string;
53
56
  /** Android's `ApplicationExitInfo` reason for the process before this one. */
54
57
  readonly previous_process_exit?: string;
55
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
+ };
56
67
  /** Ancillary report data; queryable identity and lifecycle fields stay on the row. */
57
68
  type DatabaseBundleEventMetadata = DatabaseJsonObject & {
58
69
  readonly cohort: string;
@@ -61,6 +72,7 @@ type DatabaseBundleEventMetadata = DatabaseJsonObject & {
61
72
  readonly sdk_version: string | null;
62
73
  /** `UPDATE_FAILED`: what failed. */
63
74
  readonly failure?: BundleEventFailure;
75
+ readonly http_response?: DatabaseHttpResponse;
64
76
  /** `UPDATE_DOWNLOADED`: how the bundle arrived. */
65
77
  readonly delivery?: "patch" | "manifest" | "archive" | "unknown";
66
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.27",
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.27",
41
- "@hot-updater/plugin-core": "1.0.0-rc.27",
42
- "@hot-updater/server": "1.0.0-rc.27",
43
- "@hot-updater/protocol": "1.0.0-rc.27"
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": "*",