@hot-updater/react-native 1.0.0-rc.1 → 1.0.0-rc.15

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.
Files changed (227) hide show
  1. package/android/proguard-rules.pro +17 -2
  2. package/android/src/main/java/com/hotupdater/BuiltInAssetResolver.kt +286 -0
  3. package/android/src/main/java/com/hotupdater/BundleFileStorageService.kt +651 -637
  4. package/android/src/main/java/com/hotupdater/BundleMetadata.kt +10 -0
  5. package/android/src/main/java/com/hotupdater/HotUpdaterException.kt +0 -13
  6. package/android/src/main/java/com/hotupdater/HotUpdaterImpl.kt +10 -14
  7. package/android/src/main/java/com/hotupdater/HotUpdaterRecoveryManager.kt +37 -54
  8. package/android/src/main/java/com/hotupdater/HotUpdaterRecoveryState.kt +64 -0
  9. package/android/src/main/java/com/hotupdater/OkHttpDownloadService.kt +19 -0
  10. package/android/src/main/java/com/hotupdater/TarArchiveInputStream.kt +214 -375
  11. package/android/src/main/java/com/hotupdater/TarBrArchiveExtractor.kt +119 -0
  12. package/android/src/newarch/HotUpdater.kt +7 -9
  13. package/android/src/newarch/HotUpdaterModule.kt +40 -20
  14. package/android/src/oldarch/HotUpdater.kt +7 -9
  15. package/android/src/oldarch/HotUpdaterModule.kt +40 -20
  16. package/android/src/test/java/com/hotupdater/BundleFileStorageServiceTest.kt +1126 -74
  17. package/android/src/test/java/com/hotupdater/HotUpdaterImplTest.kt +4 -5
  18. package/android/src/test/java/com/hotupdater/HotUpdaterRecoveryStateTest.kt +97 -0
  19. package/android/src/test/java/com/hotupdater/PendingCrashRecoveryTest.kt +44 -0
  20. package/android/src/test/java/com/hotupdater/TarBrArchiveExtractorTest.kt +206 -0
  21. package/ios/HotUpdater/Internal/BrotliFileDecompressor.swift +167 -0
  22. package/ios/HotUpdater/Internal/BuiltInAssetResolver.swift +196 -0
  23. package/ios/HotUpdater/Internal/BundleFileStorageService.swift +773 -1016
  24. package/ios/HotUpdater/Internal/BundleMetadata.swift +5 -0
  25. package/ios/HotUpdater/Internal/FileUtilities.swift +64 -0
  26. package/ios/HotUpdater/Internal/HotUpdater-Bridging-Header.h +0 -1
  27. package/ios/HotUpdater/Internal/HotUpdater.mm +5 -27
  28. package/ios/HotUpdater/Internal/HotUpdaterImpl.swift +149 -51
  29. package/ios/HotUpdater/Internal/NotificationExtension.swift +0 -2
  30. package/ios/HotUpdater/Internal/TarArchiveExtractor.swift +182 -311
  31. package/ios/HotUpdater/Internal/URLSessionDownloadService.swift +13 -72
  32. package/ios/HotUpdater/Recovery/HotUpdaterRecovery.h +16 -0
  33. package/ios/HotUpdater/Recovery/HotUpdaterRecovery.mm +83 -0
  34. package/ios/HotUpdater/Recovery/HotUpdaterRecoveryHooks.mm +49 -0
  35. package/lib/commonjs/checkForUpdate.js +32 -23
  36. package/lib/commonjs/checkForUpdate.js.map +1 -1
  37. package/lib/commonjs/checkForUpdate.releaseCatalog.spec.js +97 -28
  38. package/lib/commonjs/checkForUpdate.releaseCatalog.spec.js.map +1 -1
  39. package/lib/commonjs/error.js +4 -13
  40. package/lib/commonjs/error.js.map +1 -1
  41. package/lib/commonjs/fetchJSON.js +9 -2
  42. package/lib/commonjs/fetchJSON.js.map +1 -1
  43. package/lib/commonjs/httpClient.js +46 -29
  44. package/lib/commonjs/httpClient.js.map +1 -1
  45. package/lib/commonjs/httpClient.spec.js +57 -5
  46. package/lib/commonjs/httpClient.spec.js.map +1 -1
  47. package/lib/commonjs/index.js +31 -14
  48. package/lib/commonjs/index.js.map +1 -1
  49. package/lib/commonjs/index.spec.js +56 -11
  50. package/lib/commonjs/index.spec.js.map +1 -1
  51. package/lib/commonjs/native.js +15 -14
  52. package/lib/commonjs/native.js.map +1 -1
  53. package/lib/commonjs/native.spec.js +128 -22
  54. package/lib/commonjs/native.spec.js.map +1 -1
  55. package/lib/commonjs/{notifyAppReadyAnalytics.boundary.spec.js → notifyAppReadyInsights.boundary.spec.js} +28 -21
  56. package/lib/commonjs/notifyAppReadyInsights.boundary.spec.js.map +1 -0
  57. package/lib/commonjs/notifyAppReadyInsights.js +188 -0
  58. package/lib/commonjs/notifyAppReadyInsights.js.map +1 -0
  59. package/lib/commonjs/{notifyAppReadyAnalytics.spec.js → notifyAppReadyInsights.spec.js} +161 -29
  60. package/lib/commonjs/notifyAppReadyInsights.spec.js.map +1 -0
  61. package/lib/commonjs/{notifyAppReadyAnalytics.test-utils.js → notifyAppReadyInsights.test-utils.js} +3 -3
  62. package/lib/commonjs/notifyAppReadyInsights.test-utils.js.map +1 -0
  63. package/lib/commonjs/{notifyAppReadyAnalytics.transport.spec.js → notifyAppReadyInsights.transport.spec.js} +14 -7
  64. package/lib/commonjs/notifyAppReadyInsights.transport.spec.js.map +1 -0
  65. package/lib/commonjs/sdkVersion.js +1 -1
  66. package/lib/commonjs/sdkVersion.js.map +1 -1
  67. package/lib/commonjs/specs/NativeHotUpdater.js.map +1 -1
  68. package/lib/commonjs/store.js +3 -10
  69. package/lib/commonjs/store.js.map +1 -1
  70. package/lib/commonjs/store.notification.spec.js +12 -4
  71. package/lib/commonjs/store.notification.spec.js.map +1 -1
  72. package/lib/commonjs/store.spec.js +2 -136
  73. package/lib/commonjs/store.spec.js.map +1 -1
  74. package/lib/commonjs/wrap.js +11 -12
  75. package/lib/commonjs/wrap.js.map +1 -1
  76. package/lib/commonjs/wrap.spec.js +97 -25
  77. package/lib/commonjs/wrap.spec.js.map +1 -1
  78. package/lib/module/checkForUpdate.js +32 -23
  79. package/lib/module/checkForUpdate.js.map +1 -1
  80. package/lib/module/checkForUpdate.releaseCatalog.spec.js +97 -28
  81. package/lib/module/checkForUpdate.releaseCatalog.spec.js.map +1 -1
  82. package/lib/module/error.js +4 -13
  83. package/lib/module/error.js.map +1 -1
  84. package/lib/module/fetchJSON.js +7 -1
  85. package/lib/module/fetchJSON.js.map +1 -1
  86. package/lib/module/httpClient.js +48 -31
  87. package/lib/module/httpClient.js.map +1 -1
  88. package/lib/module/httpClient.spec.js +57 -5
  89. package/lib/module/httpClient.spec.js.map +1 -1
  90. package/lib/module/index.js +32 -15
  91. package/lib/module/index.js.map +1 -1
  92. package/lib/module/index.spec.js +56 -11
  93. package/lib/module/index.spec.js.map +1 -1
  94. package/lib/module/native.js +13 -12
  95. package/lib/module/native.js.map +1 -1
  96. package/lib/module/native.spec.js +128 -22
  97. package/lib/module/native.spec.js.map +1 -1
  98. package/lib/module/{notifyAppReadyAnalytics.boundary.spec.js → notifyAppReadyInsights.boundary.spec.js} +23 -16
  99. package/lib/module/notifyAppReadyInsights.boundary.spec.js.map +1 -0
  100. package/lib/module/notifyAppReadyInsights.js +181 -0
  101. package/lib/module/notifyAppReadyInsights.js.map +1 -0
  102. package/lib/module/{notifyAppReadyAnalytics.spec.js → notifyAppReadyInsights.spec.js} +153 -21
  103. package/lib/module/notifyAppReadyInsights.spec.js.map +1 -0
  104. package/lib/module/{notifyAppReadyAnalytics.test-utils.js → notifyAppReadyInsights.test-utils.js} +3 -3
  105. package/lib/module/notifyAppReadyInsights.test-utils.js.map +1 -0
  106. package/lib/module/{notifyAppReadyAnalytics.transport.spec.js → notifyAppReadyInsights.transport.spec.js} +11 -4
  107. package/lib/module/notifyAppReadyInsights.transport.spec.js.map +1 -0
  108. package/lib/module/sdkVersion.js +1 -1
  109. package/lib/module/sdkVersion.js.map +1 -1
  110. package/lib/module/specs/NativeHotUpdater.js.map +1 -1
  111. package/lib/module/store.js +3 -10
  112. package/lib/module/store.js.map +1 -1
  113. package/lib/module/store.notification.spec.js +12 -4
  114. package/lib/module/store.notification.spec.js.map +1 -1
  115. package/lib/module/store.spec.js +2 -136
  116. package/lib/module/store.spec.js.map +1 -1
  117. package/lib/module/wrap.js +11 -12
  118. package/lib/module/wrap.js.map +1 -1
  119. package/lib/module/wrap.spec.js +99 -25
  120. package/lib/module/wrap.spec.js.map +1 -1
  121. package/lib/typescript/commonjs/checkForUpdate.d.ts +2 -3
  122. package/lib/typescript/commonjs/checkForUpdate.d.ts.map +1 -1
  123. package/lib/typescript/commonjs/error.d.ts +4 -13
  124. package/lib/typescript/commonjs/error.d.ts.map +1 -1
  125. package/lib/typescript/commonjs/fetchJSON.d.ts +4 -0
  126. package/lib/typescript/commonjs/fetchJSON.d.ts.map +1 -1
  127. package/lib/typescript/commonjs/httpClient.d.ts +6 -6
  128. package/lib/typescript/commonjs/httpClient.d.ts.map +1 -1
  129. package/lib/typescript/commonjs/index.d.ts +4 -7
  130. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  131. package/lib/typescript/commonjs/native.d.ts +5 -9
  132. package/lib/typescript/commonjs/native.d.ts.map +1 -1
  133. package/lib/typescript/commonjs/notifyAppReadyInsights.d.ts +25 -0
  134. package/lib/typescript/commonjs/notifyAppReadyInsights.d.ts.map +1 -0
  135. package/lib/typescript/commonjs/notifyAppReadyInsights.test-utils.d.ts +8 -0
  136. package/lib/typescript/commonjs/notifyAppReadyInsights.test-utils.d.ts.map +1 -0
  137. package/lib/typescript/commonjs/sdkVersion.d.ts +1 -1
  138. package/lib/typescript/commonjs/sdkVersion.d.ts.map +1 -1
  139. package/lib/typescript/commonjs/specs/NativeHotUpdater.d.ts +8 -35
  140. package/lib/typescript/commonjs/specs/NativeHotUpdater.d.ts.map +1 -1
  141. package/lib/typescript/commonjs/store.d.ts +1 -3
  142. package/lib/typescript/commonjs/store.d.ts.map +1 -1
  143. package/lib/typescript/commonjs/wrap.types.d.ts +5 -8
  144. package/lib/typescript/commonjs/wrap.types.d.ts.map +1 -1
  145. package/lib/typescript/module/checkForUpdate.d.ts +2 -3
  146. package/lib/typescript/module/checkForUpdate.d.ts.map +1 -1
  147. package/lib/typescript/module/error.d.ts +4 -13
  148. package/lib/typescript/module/error.d.ts.map +1 -1
  149. package/lib/typescript/module/fetchJSON.d.ts +4 -0
  150. package/lib/typescript/module/fetchJSON.d.ts.map +1 -1
  151. package/lib/typescript/module/httpClient.d.ts +6 -6
  152. package/lib/typescript/module/httpClient.d.ts.map +1 -1
  153. package/lib/typescript/module/index.d.ts +4 -7
  154. package/lib/typescript/module/index.d.ts.map +1 -1
  155. package/lib/typescript/module/native.d.ts +5 -9
  156. package/lib/typescript/module/native.d.ts.map +1 -1
  157. package/lib/typescript/module/notifyAppReadyInsights.d.ts +25 -0
  158. package/lib/typescript/module/notifyAppReadyInsights.d.ts.map +1 -0
  159. package/lib/typescript/module/notifyAppReadyInsights.test-utils.d.ts +8 -0
  160. package/lib/typescript/module/notifyAppReadyInsights.test-utils.d.ts.map +1 -0
  161. package/lib/typescript/module/sdkVersion.d.ts +1 -1
  162. package/lib/typescript/module/sdkVersion.d.ts.map +1 -1
  163. package/lib/typescript/module/specs/NativeHotUpdater.d.ts +8 -35
  164. package/lib/typescript/module/specs/NativeHotUpdater.d.ts.map +1 -1
  165. package/lib/typescript/module/store.d.ts +1 -3
  166. package/lib/typescript/module/store.d.ts.map +1 -1
  167. package/lib/typescript/module/wrap.types.d.ts +5 -8
  168. package/lib/typescript/module/wrap.types.d.ts.map +1 -1
  169. package/package.json +3 -3
  170. package/src/checkForUpdate.releaseCatalog.spec.ts +137 -61
  171. package/src/checkForUpdate.ts +35 -29
  172. package/src/error.ts +4 -14
  173. package/src/fetchJSON.ts +12 -1
  174. package/src/httpClient.spec.ts +70 -5
  175. package/src/httpClient.ts +78 -64
  176. package/src/index.spec.ts +59 -11
  177. package/src/index.ts +41 -17
  178. package/src/native.spec.ts +133 -22
  179. package/src/native.ts +21 -32
  180. package/src/{notifyAppReadyAnalytics.boundary.spec.ts → notifyAppReadyInsights.boundary.spec.ts} +25 -17
  181. package/src/{notifyAppReadyAnalytics.spec.ts → notifyAppReadyInsights.spec.ts} +141 -22
  182. package/src/{notifyAppReadyAnalytics.test-utils.ts → notifyAppReadyInsights.test-utils.ts} +4 -4
  183. package/src/{notifyAppReadyAnalytics.transport.spec.ts → notifyAppReadyInsights.transport.spec.ts} +13 -5
  184. package/src/notifyAppReadyInsights.ts +293 -0
  185. package/src/sdkVersion.ts +1 -1
  186. package/src/specs/NativeHotUpdater.ts +8 -36
  187. package/src/store.notification.spec.ts +13 -3
  188. package/src/store.spec.ts +0 -157
  189. package/src/store.ts +2 -23
  190. package/src/wrap.spec.ts +109 -31
  191. package/src/wrap.tsx +11 -11
  192. package/src/wrap.types.ts +5 -8
  193. package/android/src/main/java/com/hotupdater/DecompressService.kt +0 -89
  194. package/android/src/main/java/com/hotupdater/DecompressionStrategy.kt +0 -26
  195. package/android/src/main/java/com/hotupdater/TarBrDecompressionStrategy.kt +0 -117
  196. package/android/src/main/java/com/hotupdater/TarGzDecompressionStrategy.kt +0 -117
  197. package/android/src/main/java/com/hotupdater/ZipDecompressionStrategy.kt +0 -192
  198. package/android/src/test/java/com/hotupdater/TarArchiveInputStreamTest.kt +0 -68
  199. package/ios/HotUpdater/Internal/ArchiveExtractionUtilities.swift +0 -178
  200. package/ios/HotUpdater/Internal/DecompressService.swift +0 -112
  201. package/ios/HotUpdater/Internal/DecompressionStrategy.swift +0 -22
  202. package/ios/HotUpdater/Internal/StreamingTarArchiveExtractor.swift +0 -370
  203. package/ios/HotUpdater/Internal/TarBrDecompressionStrategy.swift +0 -39
  204. package/ios/HotUpdater/Internal/TarGzDecompressionStrategy.swift +0 -59
  205. package/ios/HotUpdater/Internal/ZipArchiveExtractor.swift +0 -482
  206. package/ios/HotUpdater/Internal/ZipDecompressionStrategy.swift +0 -56
  207. package/lib/commonjs/notifyAppReadyAnalytics.boundary.spec.js.map +0 -1
  208. package/lib/commonjs/notifyAppReadyAnalytics.js +0 -133
  209. package/lib/commonjs/notifyAppReadyAnalytics.js.map +0 -1
  210. package/lib/commonjs/notifyAppReadyAnalytics.spec.js.map +0 -1
  211. package/lib/commonjs/notifyAppReadyAnalytics.test-utils.js.map +0 -1
  212. package/lib/commonjs/notifyAppReadyAnalytics.transport.spec.js.map +0 -1
  213. package/lib/module/notifyAppReadyAnalytics.boundary.spec.js.map +0 -1
  214. package/lib/module/notifyAppReadyAnalytics.js +0 -128
  215. package/lib/module/notifyAppReadyAnalytics.js.map +0 -1
  216. package/lib/module/notifyAppReadyAnalytics.spec.js.map +0 -1
  217. package/lib/module/notifyAppReadyAnalytics.test-utils.js.map +0 -1
  218. package/lib/module/notifyAppReadyAnalytics.transport.spec.js.map +0 -1
  219. package/lib/typescript/commonjs/notifyAppReadyAnalytics.d.ts +0 -13
  220. package/lib/typescript/commonjs/notifyAppReadyAnalytics.d.ts.map +0 -1
  221. package/lib/typescript/commonjs/notifyAppReadyAnalytics.test-utils.d.ts +0 -8
  222. package/lib/typescript/commonjs/notifyAppReadyAnalytics.test-utils.d.ts.map +0 -1
  223. package/lib/typescript/module/notifyAppReadyAnalytics.d.ts +0 -13
  224. package/lib/typescript/module/notifyAppReadyAnalytics.d.ts.map +0 -1
  225. package/lib/typescript/module/notifyAppReadyAnalytics.test-utils.d.ts +0 -8
  226. package/lib/typescript/module/notifyAppReadyAnalytics.test-utils.d.ts.map +0 -1
  227. package/src/notifyAppReadyAnalytics.ts +0 -194
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../src/store.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAEV,6BAA6B,EAE9B,MAAM,UAAU,CAAC;AAGlB,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,YAAY,EAAE,SAAS,GAAG,MAAM,GAAG,IAAI,CAAC;IACxC,OAAO,EAAE,6BAA6B,GAAG,IAAI,CAAC;CAC/C,CAAC;AAkMF,eAAO,MAAM,eAAe;;yBAnEE,OAAO,CAAC,eAAe,CAAC;0BAuDvB,MAAM,IAAI;CAYa,CAAC;AAEvD,eAAO,MAAM,kBAAkB,GAAI,CAAC,GAAG,eAAe,aAC1C,CAAC,QAAQ,EAAE,eAAe,KAAK,CAAC,MAQ3C,CAAC"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../src/store.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAEV,6BAA6B,EAE9B,MAAM,UAAU,CAAC;AAGlB,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,EAAE,6BAA6B,GAAG,IAAI,CAAC;CAC/C,CAAC;AA+KF,eAAO,MAAM,eAAe;;yBApDE,OAAO,CAAC,eAAe,CAAC;0BAwCvB,MAAM,IAAI;CAYa,CAAC;AAEvD,eAAO,MAAM,kBAAkB,GAAI,CAAC,GAAG,eAAe,aAC1C,CAAC,QAAQ,EAAE,eAAe,KAAK,CAAC,MAQ3C,CAAC"}
@@ -14,8 +14,6 @@ export type UpdateStatus = "CHECK_FOR_UPDATE" | "UPDATING" | "UPDATE_PROCESS_COM
14
14
  export type HotUpdaterFallbackComponentProps = {
15
15
  status: Exclude<UpdateStatus, "UPDATE_PROCESS_COMPLETED">;
16
16
  progress: number;
17
- downloadedBytes: HotUpdaterState["downloadedBytes"];
18
- totalBytes: HotUpdaterState["totalBytes"];
19
17
  message: string | null;
20
18
  artifactType: HotUpdaterState["artifactType"];
21
19
  details: HotUpdaterState["details"];
@@ -23,9 +21,10 @@ export type HotUpdaterFallbackComponentProps = {
23
21
  interface CommonHotUpdaterOptions {
24
22
  /**
25
23
  * Sends app-ready transitions and same-Bundle Release adoptions to the
26
- * configured server. Omit or set to `false` to disable client reporting.
24
+ * configured server. Defaults to `true`; set to `false` to disable client
25
+ * reporting.
27
26
  */
28
- analytics?: boolean;
27
+ insights?: boolean;
29
28
  /** Base URL of a server exposing the Hot Updater v1 client HTTP protocol. */
30
29
  baseURL: HotUpdaterBaseURL;
31
30
  requestHeaders?: Record<string, string>;
@@ -43,7 +42,7 @@ export type AutoUpdateOptions = CommonHotUpdaterOptions & {
43
42
  export type HotUpdaterInitOptions = CommonHotUpdaterOptions;
44
43
  export type HotUpdaterOptions = AutoUpdateOptions;
45
44
  type InternalCommonOptions = {
46
- analytics?: boolean;
45
+ insights?: boolean;
47
46
  client: HotUpdaterHttpClient;
48
47
  requestHeaders?: Record<string, string>;
49
48
  requestTimeout?: number;
@@ -57,9 +56,7 @@ type InternalAutoUpdateOptions = InternalCommonOptions & {
57
56
  reloadOnForceUpdate?: boolean;
58
57
  onUpdateProcessCompleted?: (response: RunUpdateProcessResponse) => void;
59
58
  };
60
- export type InternalInitOptions = InternalCommonOptions & {
61
- analytics?: boolean;
62
- };
59
+ export type InternalInitOptions = InternalCommonOptions;
63
60
  export type InternalWrapOptions = InternalAutoUpdateOptions;
64
61
  export {};
65
62
  //# sourceMappingURL=wrap.types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"wrap.types.d.ts","sourceRoot":"","sources":["../../../src/wrap.types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"wrap.types.d.ts","sourceRoot":"","sources":["../../../src/wrap.types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hot-updater/react-native",
3
- "version": "1.0.0-rc.1",
3
+ "version": "1.0.0-rc.15",
4
4
  "description": "React Native OTA solution for self-hosted",
5
5
  "source": "./src/index.ts",
6
6
  "main": "./lib/commonjs/index.js",
@@ -120,8 +120,8 @@
120
120
  },
121
121
  "dependencies": {
122
122
  "use-sync-external-store": "1.5.0",
123
- "@hot-updater/core": "1.0.0-rc.0",
124
- "@hot-updater/plugin-core": "1.0.0-rc.0"
123
+ "@hot-updater/core": "1.0.0-rc.15",
124
+ "@hot-updater/plugin-core": "1.0.0-rc.15"
125
125
  },
126
126
  "scripts": {
127
127
  "build": "node ./scripts/sync-sdk-version.mjs run -- bob build",
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  createReleaseCatalogScopeKey,
3
3
  encodeChannelKey,
4
+ type ArtifactInfo,
4
5
  type PersistedSelectionReceipt,
5
6
  type ReleaseCatalog,
6
7
  } from "@hot-updater/core";
@@ -77,24 +78,29 @@ const createCatalog = (
77
78
 
78
79
  const createClient = (catalog = createCatalog()) => {
79
80
  const fetchReleaseCatalog = vi.fn(async () => catalog);
80
- const resolveArtifact = vi.fn(async () => ({
81
- fileHash: "bundle-hash",
82
- fileUrl: "https://updates.example.com/bundle.zip",
83
- }));
84
- const sendAnalyticsEvent = vi.fn(async () => undefined);
81
+ const artifact: ArtifactInfo = {
82
+ artifactProtocolVersion: 1,
83
+ assets: {},
84
+ manifestFileHash: "manifest-hash",
85
+ manifestUrl: "https://updates.example.com/manifest.json",
86
+ archiveUrl: "https://updates.example.com/bundle.tar.br",
87
+ };
88
+ const resolveArtifact = vi.fn(async () => artifact);
89
+ const sendInsightsEvent = vi.fn(async () => undefined);
85
90
  const session = {
86
91
  fetchReleaseCatalog,
87
92
  resolveArtifact,
88
- sendAnalyticsEvent,
93
+ sendInsightsEvent,
89
94
  };
90
95
  const client: HotUpdaterHttpClient = {
91
96
  createSession: vi.fn(async () => session),
92
97
  };
93
- return { client, fetchReleaseCatalog, resolveArtifact, sendAnalyticsEvent };
98
+ return { client, fetchReleaseCatalog, resolveArtifact, sendInsightsEvent };
94
99
  };
95
100
 
96
101
  describe("checkForUpdate Release catalog protocol", () => {
97
102
  beforeEach(() => {
103
+ vi.resetModules();
98
104
  vi.clearAllMocks();
99
105
  vi.stubGlobal("__DEV__", false);
100
106
  mocks.acceptReleaseCatalog.mockReturnValue(true);
@@ -109,6 +115,59 @@ describe("checkForUpdate Release catalog protocol", () => {
109
115
  mocks.updateBundle.mockResolvedValue(true);
110
116
  });
111
117
 
118
+ it("reports an optional download only after staging, without treating the target as running", async () => {
119
+ const { checkForUpdate } = await import("./checkForUpdate");
120
+ const { client, sendInsightsEvent } = createClient();
121
+ let complete!: (success: boolean) => void;
122
+ mocks.updateBundle.mockImplementationOnce(
123
+ () =>
124
+ new Promise<boolean>((resolve) => {
125
+ complete = resolve;
126
+ }),
127
+ );
128
+ const update = await checkForUpdate({
129
+ client,
130
+ insights: true,
131
+ updateStrategy: "appVersion",
132
+ });
133
+ expect(update?.shouldForceUpdate).toBe(false);
134
+ const pending = update!.updateBundle();
135
+ await vi.waitFor(() => expect(mocks.updateBundle).toHaveBeenCalledOnce());
136
+ expect(sendInsightsEvent).not.toHaveBeenCalled();
137
+ complete(true);
138
+ await expect(pending).resolves.toBe(true);
139
+ expect(sendInsightsEvent).toHaveBeenCalledExactlyOnceWith(
140
+ expect.objectContaining({
141
+ type: "UPDATE_DOWNLOADED",
142
+ fromBundleId: CURRENT_BUNDLE_ID,
143
+ toBundleId: TARGET_BUNDLE_ID,
144
+ fromReleaseId: null,
145
+ toReleaseId: RELEASE_ID,
146
+ updateStrategy: "appVersion",
147
+ }),
148
+ );
149
+ await update!.updateBundle();
150
+ expect(sendInsightsEvent).toHaveBeenCalledOnce();
151
+ });
152
+
153
+ it.each([false, "failure"])(
154
+ "does not report a download when staging returns %s",
155
+ async (result) => {
156
+ const { checkForUpdate } = await import("./checkForUpdate");
157
+ const { client, sendInsightsEvent } = createClient();
158
+ if (result === false) mocks.updateBundle.mockResolvedValueOnce(false);
159
+ else
160
+ mocks.updateBundle.mockRejectedValueOnce(new Error("download failed"));
161
+ const update = await checkForUpdate({
162
+ client,
163
+ insights: true,
164
+ updateStrategy: "appVersion",
165
+ });
166
+ await update!.updateBundle().catch(() => false);
167
+ expect(sendInsightsEvent).not.toHaveBeenCalled();
168
+ },
169
+ );
170
+
112
171
  it("selects locally and defers Bundle artifact resolution until install", async () => {
113
172
  const { checkForUpdate } = await import("./checkForUpdate");
114
173
  const { client, fetchReleaseCatalog, resolveArtifact } = createClient();
@@ -119,7 +178,7 @@ describe("checkForUpdate Release catalog protocol", () => {
119
178
  });
120
179
 
121
180
  expect(result).toMatchObject({
122
- id: TARGET_BUNDLE_ID,
181
+ id: RELEASE_ID,
123
182
  releaseId: RELEASE_ID,
124
183
  transitionKind: "INSTALL",
125
184
  });
@@ -145,6 +204,7 @@ describe("checkForUpdate Release catalog protocol", () => {
145
204
  expect(mocks.updateBundle).toHaveBeenCalledWith(
146
205
  expect.objectContaining({
147
206
  bundleId: TARGET_BUNDLE_ID,
207
+ archiveUrl: "https://updates.example.com/bundle.tar.br",
148
208
  selection: expect.objectContaining({
149
209
  catalogId: CATALOG_ID,
150
210
  releaseId: RELEASE_ID,
@@ -182,7 +242,7 @@ describe("checkForUpdate Release catalog protocol", () => {
182
242
  },
183
243
  ],
184
244
  });
185
- const { client, resolveArtifact, sendAnalyticsEvent } =
245
+ const { client, resolveArtifact, sendInsightsEvent } =
186
246
  createClient(forceCatalog);
187
247
 
188
248
  const result = await checkForUpdate({
@@ -191,13 +251,14 @@ describe("checkForUpdate Release catalog protocol", () => {
191
251
  });
192
252
 
193
253
  expect(result).toMatchObject({
254
+ id: RELEASE_ID,
194
255
  shouldForceUpdate: false,
195
256
  transitionKind: "ADOPT_RELEASE",
196
257
  });
197
258
  await expect(result?.updateBundle()).resolves.toBe(true);
198
259
  expect(resolveArtifact).not.toHaveBeenCalled();
199
260
  expect(mocks.updateBundle).not.toHaveBeenCalled();
200
- expect(sendAnalyticsEvent).not.toHaveBeenCalled();
261
+ expect(sendInsightsEvent).not.toHaveBeenCalled();
201
262
  expect(mocks.commitReleaseSelection).toHaveBeenCalledWith({
202
263
  guard: expect.objectContaining({ generation: 2, scopeKey: SCOPE_KEY }),
203
264
  selection: expect.objectContaining({
@@ -207,7 +268,7 @@ describe("checkForUpdate Release catalog protocol", () => {
207
268
  });
208
269
  });
209
270
 
210
- it("sends RELEASE_ADOPTED only when analytics is enabled", async () => {
271
+ it("reports same-file selection as UNCHANGED with the selected release identity", async () => {
211
272
  const active: PersistedSelectionReceipt = {
212
273
  catalogId: CATALOG_ID,
213
274
  bundleId: TARGET_BUNDLE_ID,
@@ -227,20 +288,23 @@ describe("checkForUpdate Release catalog protocol", () => {
227
288
  verificationPending: false,
228
289
  });
229
290
  const { checkForUpdate } = await import("./checkForUpdate");
230
- const { client, sendAnalyticsEvent } = createClient();
291
+ const { client, sendInsightsEvent } = createClient();
231
292
 
232
293
  const result = await checkForUpdate({
233
- analytics: true,
294
+ insights: true,
234
295
  client,
235
296
  updateStrategy: "appVersion",
236
297
  });
237
298
  await result?.updateBundle();
238
299
 
239
- expect(sendAnalyticsEvent).toHaveBeenCalledWith(
300
+ expect(sendInsightsEvent).toHaveBeenCalledWith(
240
301
  expect.objectContaining({
302
+ fromBundleId: null,
303
+ updateStrategy: null,
241
304
  fromReleaseId: MINIMUM_RELEASE_ID,
305
+ toBundleId: TARGET_BUNDLE_ID,
242
306
  toReleaseId: RELEASE_ID,
243
- type: "RELEASE_ADOPTED",
307
+ type: "UNCHANGED",
244
308
  }),
245
309
  );
246
310
  });
@@ -280,7 +344,7 @@ describe("checkForUpdate Release catalog protocol", () => {
280
344
  });
281
345
 
282
346
  expect(result).toMatchObject({
283
- id: TARGET_BUNDLE_ID,
347
+ id: RELEASE_ID,
284
348
  releaseId: RELEASE_ID,
285
349
  status: "UPDATE",
286
350
  transitionKind: "INSTALL",
@@ -315,7 +379,7 @@ describe("checkForUpdate Release catalog protocol", () => {
315
379
  });
316
380
 
317
381
  expect(result).toMatchObject({
318
- id: TARGET_BUNDLE_ID,
382
+ id: RELEASE_ID,
319
383
  releaseId: RELEASE_ID,
320
384
  transitionKind: "ADOPT_RELEASE",
321
385
  });
@@ -395,7 +459,7 @@ describe("checkForUpdate Release catalog protocol", () => {
395
459
  });
396
460
 
397
461
  expect(result).toMatchObject({
398
- id: TARGET_BUNDLE_ID,
462
+ id: RELEASE_ID,
399
463
  releaseId: RELEASE_ID,
400
464
  shouldForceUpdate: true,
401
465
  status: "ROLLBACK",
@@ -448,58 +512,70 @@ describe("checkForUpdate Release catalog protocol", () => {
448
512
  });
449
513
 
450
514
  expect(result).toMatchObject({
451
- id: TARGET_BUNDLE_ID,
515
+ id: RELEASE_ID,
452
516
  shouldForceUpdate: true,
453
517
  status: "ROLLBACK",
454
518
  transitionKind: "INSTALL",
455
519
  });
456
520
  });
457
521
 
458
- it("returns a forced built-in rollback only for an active OTA", async () => {
459
- const active: PersistedSelectionReceipt = {
460
- catalogId: CATALOG_ID,
461
- bundleId: CURRENT_BUNDLE_ID,
462
- catalogHash: `sha256:${"b".repeat(64)}`,
463
- channel: CHANNEL,
464
- generation: 1,
465
- kind: "BUNDLE",
466
- releaseId: ACTIVE_RELEASE_ID,
467
- scopeKey: SCOPE_KEY,
468
- selectionContextHash: "old-context",
469
- };
470
- mocks.getActiveUpdateState.mockReturnValueOnce({
471
- activeSelection: active,
472
- highestSeenCatalogs: {},
473
- stableSelection: active,
474
- verificationPending: false,
475
- });
476
- const { checkForUpdate } = await import("./checkForUpdate");
477
- const { client } = createClient(
478
- createCatalog({ releases: [], rollbackReleases: [] }),
479
- );
522
+ it.each(["EMBEDDED", "BUILTIN"] as const)(
523
+ "returns a forced %s rollback with its console ID or built-in fallback",
524
+ async (kind) => {
525
+ const active: PersistedSelectionReceipt = {
526
+ catalogId: CATALOG_ID,
527
+ bundleId: CURRENT_BUNDLE_ID,
528
+ catalogHash: `sha256:${"b".repeat(64)}`,
529
+ channel: CHANNEL,
530
+ generation: 1,
531
+ kind: "BUNDLE",
532
+ releaseId: MINIMUM_RELEASE_ID,
533
+ scopeKey: SCOPE_KEY,
534
+ selectionContextHash: "old-context",
535
+ };
536
+ mocks.getActiveUpdateState.mockReturnValueOnce({
537
+ activeSelection: active,
538
+ highestSeenCatalogs: {},
539
+ stableSelection: active,
540
+ verificationPending: false,
541
+ });
542
+ const { checkForUpdate } = await import("./checkForUpdate");
543
+ const { client, resolveArtifact } = createClient(
544
+ createCatalog({
545
+ releases:
546
+ kind === "EMBEDDED"
547
+ ? [{ ...createCatalog().releases[0]!, kind, bundleId: null }]
548
+ : [],
549
+ rollbackReleases: [],
550
+ }),
551
+ );
480
552
 
481
- const result = await checkForUpdate({
482
- client,
483
- updateStrategy: "appVersion",
484
- });
553
+ const result = await checkForUpdate({
554
+ client,
555
+ updateStrategy: "appVersion",
556
+ });
485
557
 
486
- expect(result).toMatchObject({
487
- id: MINIMUM_RELEASE_ID,
488
- releaseId: null,
489
- shouldForceUpdate: true,
490
- status: "ROLLBACK",
491
- transitionKind: "USE_BUILTIN",
492
- });
493
- await expect(result?.updateBundle()).resolves.toBe(true);
494
- expect(mocks.commitReleaseSelection).toHaveBeenCalledWith(
495
- expect.objectContaining({
496
- selection: expect.objectContaining({
497
- kind: "BUILTIN",
498
- releaseId: null,
558
+ expect(result).toMatchObject({
559
+ id: kind === "EMBEDDED" ? RELEASE_ID : MINIMUM_RELEASE_ID,
560
+ releaseId: kind === "EMBEDDED" ? RELEASE_ID : null,
561
+ shouldForceUpdate: true,
562
+ status: "ROLLBACK",
563
+ transitionKind: kind === "EMBEDDED" ? "USE_EMBEDDED" : "USE_BUILTIN",
564
+ });
565
+ await expect(result?.updateBundle()).resolves.toBe(true);
566
+ expect(mocks.commitReleaseSelection).toHaveBeenCalledWith(
567
+ expect.objectContaining({
568
+ selection: expect.objectContaining({
569
+ bundleId: MINIMUM_RELEASE_ID,
570
+ kind,
571
+ releaseId: kind === "EMBEDDED" ? RELEASE_ID : null,
572
+ }),
499
573
  }),
500
- }),
501
- );
502
- });
574
+ );
575
+ expect(resolveArtifact).not.toHaveBeenCalled();
576
+ expect(mocks.updateBundle).not.toHaveBeenCalled();
577
+ },
578
+ );
503
579
 
504
580
  it("does not surface a rollback when the app already uses built-in bytes", async () => {
505
581
  mocks.getBundleId.mockReturnValueOnce(MINIMUM_RELEASE_ID);
@@ -3,7 +3,6 @@ import {
3
3
  createReleaseSelectionContextHash,
4
4
  encodeChannelKey,
5
5
  selectDesiredRelease,
6
- type ArtifactInfo,
7
6
  type PersistedSelectionReceipt,
8
7
  type ReleaseCatalog,
9
8
  } from "@hot-updater/core";
@@ -30,6 +29,7 @@ import {
30
29
  isChannelSwitched,
31
30
  updateBundle,
32
31
  } from "./native";
32
+ import { reportBundleDownloaded } from "./notifyAppReadyInsights";
33
33
  import {
34
34
  hasExpectedReleaseCatalogScope,
35
35
  type ExpectedReleaseCatalogScope,
@@ -60,7 +60,7 @@ export interface CheckForUpdateOptions {
60
60
  requestTimeout?: number;
61
61
  }
62
62
 
63
- export type CheckForUpdateResult = ArtifactInfo & {
63
+ export type CheckForUpdateResult = {
64
64
  readonly id: string;
65
65
  readonly message: string | null;
66
66
  readonly rolloutCohortCount: number;
@@ -83,7 +83,7 @@ export type ReleaseTransitionKind =
83
83
  | "USE_BUILTIN";
84
84
 
85
85
  export interface InternalCheckForUpdateOptions extends CheckForUpdateOptions {
86
- analytics?: boolean;
86
+ insights?: boolean;
87
87
  client: HotUpdaterHttpClient;
88
88
  }
89
89
 
@@ -121,14 +121,12 @@ const resetProgress = () => {
121
121
  hotUpdaterStore.setState({
122
122
  artifactType: null,
123
123
  details: null,
124
- downloadedBytes: undefined,
125
124
  isUpdateDownloaded: false,
126
125
  progress: 0,
127
- totalBytes: undefined,
128
126
  });
129
127
  };
130
128
 
131
- const notifyReleaseAdoption = async (input: {
129
+ const notifyUnchangedSelection = async (input: {
132
130
  readonly active: PersistedSelectionReceipt | null;
133
131
  readonly desired: PersistedSelectionReceipt;
134
132
  readonly appVersion: string;
@@ -138,16 +136,15 @@ const notifyReleaseAdoption = async (input: {
138
136
  readonly session: HotUpdaterHttpSession;
139
137
  readonly requestHeaders?: Record<string, string>;
140
138
  readonly requestTimeout?: number;
141
- readonly updateStrategy: "appVersion" | "fingerprint";
142
139
  }): Promise<void> => {
143
140
  const { userId, username } = getPersistedUserIdentity();
144
141
  try {
145
- await input.session.sendAnalyticsEvent({
142
+ await input.session.sendInsightsEvent({
146
143
  appVersion: input.appVersion,
147
144
  channel: input.desired.channel,
148
145
  cohort: input.cohort,
149
146
  fingerprintHash: input.fingerprintHash,
150
- fromBundleId: input.desired.bundleId,
147
+ fromBundleId: null,
151
148
  fromReleaseId: input.active?.releaseId ?? null,
152
149
  installId: getInstallId(),
153
150
  platform: input.platform,
@@ -155,13 +152,13 @@ const notifyReleaseAdoption = async (input: {
155
152
  requestTimeout: input.requestTimeout,
156
153
  toBundleId: input.desired.bundleId,
157
154
  toReleaseId: input.desired.releaseId,
158
- type: "RELEASE_ADOPTED",
159
- updateStrategy: input.updateStrategy,
155
+ type: "UNCHANGED",
156
+ updateStrategy: null,
160
157
  ...(userId === undefined ? {} : { userId }),
161
158
  ...(username === undefined ? {} : { username }),
162
159
  });
163
160
  } catch (error) {
164
- console.warn("[HotUpdater] Release adoption analytics failed:", error);
161
+ console.warn("[HotUpdater] Unchanged selection insights failed:", error);
165
162
  }
166
163
  };
167
164
 
@@ -218,7 +215,8 @@ async function checkForReleaseCatalogUpdate(input: {
218
215
  const scopeKey = catalog.scopeKey;
219
216
 
220
217
  const crashedBundleIds = getCrashHistory();
221
- const active = getActiveUpdateState().activeSelection;
218
+ const activeState = getActiveUpdateState();
219
+ const active = activeState.activeSelection;
222
220
  const explicitScopeSwitch =
223
221
  input.explicitChannel !== undefined &&
224
222
  input.explicitChannel !== input.currentChannel;
@@ -340,12 +338,8 @@ async function checkForReleaseCatalogUpdate(input: {
340
338
  guard,
341
339
  selection: receipt,
342
340
  });
343
- if (
344
- committed &&
345
- transitionKind === "ADOPT_RELEASE" &&
346
- options.analytics
347
- ) {
348
- await notifyReleaseAdoption({
341
+ if (committed && transitionKind === "ADOPT_RELEASE" && options.insights) {
342
+ await notifyUnchangedSelection({
349
343
  active,
350
344
  appVersion: input.currentAppVersion,
351
345
  cohort: input.cohort,
@@ -355,7 +349,6 @@ async function checkForReleaseCatalogUpdate(input: {
355
349
  requestHeaders: options.requestHeaders,
356
350
  requestTimeout: options.requestTimeout,
357
351
  session,
358
- updateStrategy: options.updateStrategy,
359
352
  });
360
353
  }
361
354
  return committed;
@@ -370,24 +363,37 @@ async function checkForReleaseCatalogUpdate(input: {
370
363
  if (!isReleaseSelectionCurrent(guard)) {
371
364
  throw new StaleReleaseCatalogError();
372
365
  }
373
- return updateBundle({
366
+ const downloaded = await updateBundle({
367
+ assets: artifact.assets,
374
368
  bundleId: desired.bundleId,
375
- changedAssets: artifact.changedAssets ?? null,
376
369
  channel: input.targetChannel,
377
- fileHash: artifact.fileHash,
378
- fileUrl: artifact.fileUrl,
379
- manifestFileHash: artifact.manifestFileHash ?? null,
380
- manifestUrl: artifact.manifestUrl ?? null,
370
+ manifestFileHash: artifact.manifestFileHash,
371
+ manifestUrl: artifact.manifestUrl,
372
+ ...(artifact.archiveUrl ? { archiveUrl: artifact.archiveUrl } : {}),
381
373
  selection: receipt,
382
374
  shouldSkipCurrentBundleIdCheck: true,
383
375
  status: desired.status,
384
376
  });
377
+ if (downloaded) {
378
+ await reportBundleDownloaded(options, {
379
+ fromBundleId: input.currentBundleId,
380
+ fromReleaseId:
381
+ active?.bundleId === input.currentBundleId
382
+ ? active.releaseId
383
+ : activeState.stableSelection?.bundleId === input.currentBundleId
384
+ ? activeState.stableSelection.releaseId
385
+ : null,
386
+ toBundleId: desired.bundleId,
387
+ toReleaseId: desired.releaseId,
388
+ channel: input.targetChannel,
389
+ updateStrategy: options.updateStrategy,
390
+ });
391
+ }
392
+ return downloaded;
385
393
  };
386
394
 
387
395
  return {
388
- fileHash: null,
389
- fileUrl: null,
390
- id: desired.bundleId,
396
+ id: desired.releaseId ?? desired.bundleId,
391
397
  message: release?.message ?? null,
392
398
  releaseId: desired.releaseId,
393
399
  rolloutCohortCount: release?.rolloutCohortCount ?? 1000,
package/src/error.ts CHANGED
@@ -7,7 +7,7 @@
7
7
  *
8
8
  * Error Classification:
9
9
  * - Parameter Validation: Invalid or missing function parameters
10
- * - Bundle Storage: Errors during download, extraction, and storage
10
+ * - Bundle Storage: Errors during download, verification, and storage
11
11
  * - Signature Verification: Cryptographic verification failures (collapsed to a single public code)
12
12
  * - Internal: Platform-specific or unexpected errors
13
13
  *
@@ -27,8 +27,7 @@ export enum HotUpdaterErrorCode {
27
27
  MISSING_BUNDLE_ID = "MISSING_BUNDLE_ID",
28
28
 
29
29
  /**
30
- * File URL is invalid or malformed.
31
- * Thrown when fileUrl parameter cannot be parsed as a valid URL.
30
+ * Manifest or asset URL is invalid or malformed.
32
31
  * @retryable false
33
32
  */
34
33
  INVALID_FILE_URL = "INVALID_FILE_URL",
@@ -58,25 +57,16 @@ export enum HotUpdaterErrorCode {
58
57
  */
59
58
  INCOMPLETE_DOWNLOAD = "INCOMPLETE_DOWNLOAD",
60
59
 
61
- /**
62
- * Bundle archive format is invalid or corrupted.
63
- * Thrown when ZIP file has wrong magic bytes, invalid structure, or unsupported format.
64
- * Also thrown for path traversal attempts during extraction.
65
- * @retryable false - Indicates corrupted or malicious bundle
66
- */
67
- EXTRACTION_FORMAT_ERROR = "EXTRACTION_FORMAT_ERROR",
68
-
69
60
  /**
70
61
  * Bundle missing required platform files.
71
- * Thrown when extracted bundle doesn't contain index.android.bundle (Android)
62
+ * Thrown when the staged bundle doesn't contain index.android.bundle (Android)
72
63
  * or main.jsbundle (iOS).
73
64
  * @retryable false - Indicates incorrectly built bundle
74
65
  */
75
66
  INVALID_BUNDLE = "INVALID_BUNDLE",
76
67
 
77
68
  /**
78
- * Insufficient disk space for bundle download and extraction.
79
- * Thrown when available disk space is less than required (file size * 2).
69
+ * Insufficient disk space for bundle staging.
80
70
  * Error message includes required and available bytes.
81
71
  * @retryable false - User must free up disk space
82
72
  */
package/src/fetchJSON.ts CHANGED
@@ -1,3 +1,14 @@
1
+ export class FetchJSONResponseError extends Error {
2
+ constructor(
3
+ readonly status: number,
4
+ statusText: string,
5
+ ) {
6
+ super(
7
+ `Request failed with HTTP ${status}${statusText ? ` ${statusText}` : ""}`,
8
+ );
9
+ }
10
+ }
11
+
1
12
  export const fetchJSON = async <T>({
2
13
  url,
3
14
  requestHeaders,
@@ -19,7 +30,7 @@ export const fetchJSON = async <T>({
19
30
  signal: controller.signal,
20
31
  });
21
32
  if (response.status !== 200) {
22
- throw new Error(response.statusText);
33
+ throw new FetchJSONResponseError(response.status, response.statusText);
23
34
  }
24
35
  return (await response.json()) as T;
25
36
  } catch (error: unknown) {