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

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 (239) hide show
  1. package/android/src/main/java/com/hotupdater/BundleFileStorageService.kt +357 -6
  2. package/android/src/main/java/com/hotupdater/BundleMetadata.kt +268 -34
  3. package/android/src/main/java/com/hotupdater/HotUpdaterImpl.kt +75 -9
  4. package/android/src/main/java/com/hotupdater/NativeConfigUtils.kt +2 -16
  5. package/android/src/main/java/com/hotupdater/ReleaseCatalogCacheService.kt +166 -0
  6. package/android/src/main/java/com/hotupdater/SignatureVerifier.kt +1 -2
  7. package/android/src/newarch/HotUpdater.kt +1 -1
  8. package/android/src/newarch/HotUpdaterModule.kt +116 -0
  9. package/android/src/oldarch/HotUpdater.kt +1 -1
  10. package/android/src/oldarch/HotUpdaterModule.kt +128 -0
  11. package/android/src/oldarch/HotUpdaterSpec.kt +38 -0
  12. package/android/src/test/java/com/hotupdater/BundleFileStorageServiceTest.kt +280 -2
  13. package/android/src/test/java/com/hotupdater/HotUpdaterImplTest.kt +57 -2
  14. package/android/src/test/java/com/hotupdater/ReleaseCatalogCacheServiceTest.kt +118 -0
  15. package/ios/HotUpdater/Internal/BundleFileStorageService.swift +491 -30
  16. package/ios/HotUpdater/Internal/BundleMetadata.swift +229 -6
  17. package/ios/HotUpdater/Internal/HotUpdater.mm +122 -0
  18. package/ios/HotUpdater/Internal/HotUpdaterImpl.swift +176 -7
  19. package/ios/HotUpdater/Internal/ReleaseCatalogCacheService.swift +213 -0
  20. package/lib/commonjs/catalogCacheNative.js +44 -0
  21. package/lib/commonjs/catalogCacheNative.js.map +1 -0
  22. package/lib/commonjs/catalogCacheNative.spec.js +31 -0
  23. package/lib/commonjs/catalogCacheNative.spec.js.map +1 -0
  24. package/lib/commonjs/checkForUpdate.js +231 -60
  25. package/lib/commonjs/checkForUpdate.js.map +1 -1
  26. package/lib/commonjs/checkForUpdate.releaseCatalog.spec.js +604 -0
  27. package/lib/commonjs/checkForUpdate.releaseCatalog.spec.js.map +1 -0
  28. package/lib/commonjs/error.js +8 -1
  29. package/lib/commonjs/error.js.map +1 -1
  30. package/lib/commonjs/{fetchUpdateInfo.js → fetchJSON.js} +11 -14
  31. package/lib/commonjs/fetchJSON.js.map +1 -0
  32. package/lib/commonjs/httpClient.js +153 -0
  33. package/lib/commonjs/httpClient.js.map +1 -0
  34. package/lib/commonjs/httpClient.spec.js +102 -0
  35. package/lib/commonjs/httpClient.spec.js.map +1 -0
  36. package/lib/commonjs/index.js +47 -70
  37. package/lib/commonjs/index.js.map +1 -1
  38. package/lib/commonjs/index.spec.js +115 -159
  39. package/lib/commonjs/index.spec.js.map +1 -1
  40. package/lib/commonjs/iosInterop.spec.js +18 -0
  41. package/lib/commonjs/iosInterop.spec.js.map +1 -0
  42. package/lib/commonjs/native.js +222 -53
  43. package/lib/commonjs/native.js.map +1 -1
  44. package/lib/commonjs/native.spec.js +226 -12
  45. package/lib/commonjs/native.spec.js.map +1 -1
  46. package/lib/commonjs/notifyAppReadyAnalytics.boundary.spec.js +218 -0
  47. package/lib/commonjs/notifyAppReadyAnalytics.boundary.spec.js.map +1 -0
  48. package/lib/commonjs/notifyAppReadyAnalytics.js +133 -0
  49. package/lib/commonjs/notifyAppReadyAnalytics.js.map +1 -0
  50. package/lib/commonjs/notifyAppReadyAnalytics.spec.js +246 -0
  51. package/lib/commonjs/notifyAppReadyAnalytics.spec.js.map +1 -0
  52. package/lib/commonjs/notifyAppReadyAnalytics.test-utils.js +24 -0
  53. package/lib/commonjs/notifyAppReadyAnalytics.test-utils.js.map +1 -0
  54. package/lib/commonjs/notifyAppReadyAnalytics.transport.spec.js +117 -0
  55. package/lib/commonjs/notifyAppReadyAnalytics.transport.spec.js.map +1 -0
  56. package/lib/commonjs/releaseCatalogCache.js +179 -0
  57. package/lib/commonjs/releaseCatalogCache.js.map +1 -0
  58. package/lib/commonjs/releaseCatalogCache.spec.js +195 -0
  59. package/lib/commonjs/releaseCatalogCache.spec.js.map +1 -0
  60. package/lib/commonjs/releaseCatalogCacheNativeContract.spec.js +64 -0
  61. package/lib/commonjs/releaseCatalogCacheNativeContract.spec.js.map +1 -0
  62. package/lib/commonjs/sdkVersion.js +1 -1
  63. package/lib/commonjs/sdkVersion.js.map +1 -1
  64. package/lib/commonjs/specs/NativeHotUpdater.js.map +1 -1
  65. package/lib/commonjs/types.js +0 -12
  66. package/lib/commonjs/types.js.map +1 -1
  67. package/lib/commonjs/wrap.js +7 -82
  68. package/lib/commonjs/wrap.js.map +1 -1
  69. package/lib/commonjs/wrap.spec.js +203 -56
  70. package/lib/commonjs/wrap.spec.js.map +1 -1
  71. package/lib/commonjs/wrap.types.js +6 -0
  72. package/lib/commonjs/wrap.types.js.map +1 -0
  73. package/lib/module/catalogCacheNative.js +36 -0
  74. package/lib/module/catalogCacheNative.js.map +1 -0
  75. package/lib/module/catalogCacheNative.spec.js +31 -0
  76. package/lib/module/catalogCacheNative.spec.js.map +1 -0
  77. package/lib/module/checkForUpdate.js +233 -62
  78. package/lib/module/checkForUpdate.js.map +1 -1
  79. package/lib/module/checkForUpdate.releaseCatalog.spec.js +603 -0
  80. package/lib/module/checkForUpdate.releaseCatalog.spec.js.map +1 -0
  81. package/lib/module/error.js +6 -0
  82. package/lib/module/error.js.map +1 -1
  83. package/lib/module/{fetchUpdateInfo.js → fetchJSON.js} +9 -12
  84. package/lib/module/fetchJSON.js.map +1 -0
  85. package/lib/module/httpClient.js +148 -0
  86. package/lib/module/httpClient.js.map +1 -0
  87. package/lib/module/httpClient.spec.js +102 -0
  88. package/lib/module/httpClient.spec.js.map +1 -0
  89. package/lib/module/index.js +48 -65
  90. package/lib/module/index.js.map +1 -1
  91. package/lib/module/index.spec.js +115 -159
  92. package/lib/module/index.spec.js.map +1 -1
  93. package/lib/module/iosInterop.spec.js +18 -0
  94. package/lib/module/iosInterop.spec.js.map +1 -0
  95. package/lib/module/native.js +206 -49
  96. package/lib/module/native.js.map +1 -1
  97. package/lib/module/native.spec.js +226 -12
  98. package/lib/module/native.spec.js.map +1 -1
  99. package/lib/module/notifyAppReadyAnalytics.boundary.spec.js +217 -0
  100. package/lib/module/notifyAppReadyAnalytics.boundary.spec.js.map +1 -0
  101. package/lib/module/notifyAppReadyAnalytics.js +128 -0
  102. package/lib/module/notifyAppReadyAnalytics.js.map +1 -0
  103. package/lib/module/notifyAppReadyAnalytics.spec.js +245 -0
  104. package/lib/module/notifyAppReadyAnalytics.spec.js.map +1 -0
  105. package/lib/module/notifyAppReadyAnalytics.test-utils.js +18 -0
  106. package/lib/module/notifyAppReadyAnalytics.test-utils.js.map +1 -0
  107. package/lib/module/notifyAppReadyAnalytics.transport.spec.js +116 -0
  108. package/lib/module/notifyAppReadyAnalytics.transport.spec.js.map +1 -0
  109. package/lib/module/releaseCatalogCache.js +171 -0
  110. package/lib/module/releaseCatalogCache.js.map +1 -0
  111. package/lib/module/releaseCatalogCache.spec.js +195 -0
  112. package/lib/module/releaseCatalogCache.spec.js.map +1 -0
  113. package/lib/module/releaseCatalogCacheNativeContract.spec.js +64 -0
  114. package/lib/module/releaseCatalogCacheNativeContract.spec.js.map +1 -0
  115. package/lib/module/sdkVersion.js +1 -1
  116. package/lib/module/sdkVersion.js.map +1 -1
  117. package/lib/module/specs/NativeHotUpdater.js.map +1 -1
  118. package/lib/module/types.js +0 -12
  119. package/lib/module/types.js.map +1 -1
  120. package/lib/module/wrap.js +6 -81
  121. package/lib/module/wrap.js.map +1 -1
  122. package/lib/module/wrap.spec.js +203 -56
  123. package/lib/module/wrap.spec.js.map +1 -1
  124. package/lib/module/wrap.types.js +4 -0
  125. package/lib/module/wrap.types.js.map +1 -0
  126. package/lib/typescript/commonjs/catalogCacheNative.d.ts +4 -0
  127. package/lib/typescript/commonjs/catalogCacheNative.d.ts.map +1 -0
  128. package/lib/typescript/commonjs/checkForUpdate.d.ts +14 -4
  129. package/lib/typescript/commonjs/checkForUpdate.d.ts.map +1 -1
  130. package/lib/typescript/commonjs/error.d.ts +3 -0
  131. package/lib/typescript/commonjs/error.d.ts.map +1 -1
  132. package/lib/typescript/commonjs/fetchJSON.d.ts +6 -0
  133. package/lib/typescript/commonjs/fetchJSON.d.ts.map +1 -0
  134. package/lib/typescript/commonjs/httpClient.d.ts +56 -0
  135. package/lib/typescript/commonjs/httpClient.d.ts.map +1 -0
  136. package/lib/typescript/commonjs/index.d.ts +31 -40
  137. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  138. package/lib/typescript/commonjs/native.d.ts +84 -17
  139. package/lib/typescript/commonjs/native.d.ts.map +1 -1
  140. package/lib/typescript/commonjs/notifyAppReadyAnalytics.d.ts +13 -0
  141. package/lib/typescript/commonjs/notifyAppReadyAnalytics.d.ts.map +1 -0
  142. package/lib/typescript/commonjs/notifyAppReadyAnalytics.test-utils.d.ts +8 -0
  143. package/lib/typescript/commonjs/notifyAppReadyAnalytics.test-utils.d.ts.map +1 -0
  144. package/lib/typescript/commonjs/releaseCatalogCache.d.ts +25 -0
  145. package/lib/typescript/commonjs/releaseCatalogCache.d.ts.map +1 -0
  146. package/lib/typescript/commonjs/sdkVersion.d.ts +1 -1
  147. package/lib/typescript/commonjs/sdkVersion.d.ts.map +1 -1
  148. package/lib/typescript/commonjs/specs/NativeHotUpdater.d.ts +40 -5
  149. package/lib/typescript/commonjs/specs/NativeHotUpdater.d.ts.map +1 -1
  150. package/lib/typescript/commonjs/types.d.ts +0 -118
  151. package/lib/typescript/commonjs/types.d.ts.map +1 -1
  152. package/lib/typescript/commonjs/wrap.d.ts +2 -191
  153. package/lib/typescript/commonjs/wrap.d.ts.map +1 -1
  154. package/lib/typescript/commonjs/wrap.types.d.ts +65 -0
  155. package/lib/typescript/commonjs/wrap.types.d.ts.map +1 -0
  156. package/lib/typescript/module/catalogCacheNative.d.ts +4 -0
  157. package/lib/typescript/module/catalogCacheNative.d.ts.map +1 -0
  158. package/lib/typescript/module/checkForUpdate.d.ts +14 -4
  159. package/lib/typescript/module/checkForUpdate.d.ts.map +1 -1
  160. package/lib/typescript/module/error.d.ts +3 -0
  161. package/lib/typescript/module/error.d.ts.map +1 -1
  162. package/lib/typescript/module/fetchJSON.d.ts +6 -0
  163. package/lib/typescript/module/fetchJSON.d.ts.map +1 -0
  164. package/lib/typescript/module/httpClient.d.ts +56 -0
  165. package/lib/typescript/module/httpClient.d.ts.map +1 -0
  166. package/lib/typescript/module/index.d.ts +31 -40
  167. package/lib/typescript/module/index.d.ts.map +1 -1
  168. package/lib/typescript/module/native.d.ts +84 -17
  169. package/lib/typescript/module/native.d.ts.map +1 -1
  170. package/lib/typescript/module/notifyAppReadyAnalytics.d.ts +13 -0
  171. package/lib/typescript/module/notifyAppReadyAnalytics.d.ts.map +1 -0
  172. package/lib/typescript/module/notifyAppReadyAnalytics.test-utils.d.ts +8 -0
  173. package/lib/typescript/module/notifyAppReadyAnalytics.test-utils.d.ts.map +1 -0
  174. package/lib/typescript/module/releaseCatalogCache.d.ts +25 -0
  175. package/lib/typescript/module/releaseCatalogCache.d.ts.map +1 -0
  176. package/lib/typescript/module/sdkVersion.d.ts +1 -1
  177. package/lib/typescript/module/sdkVersion.d.ts.map +1 -1
  178. package/lib/typescript/module/specs/NativeHotUpdater.d.ts +40 -5
  179. package/lib/typescript/module/specs/NativeHotUpdater.d.ts.map +1 -1
  180. package/lib/typescript/module/types.d.ts +0 -118
  181. package/lib/typescript/module/types.d.ts.map +1 -1
  182. package/lib/typescript/module/wrap.d.ts +2 -191
  183. package/lib/typescript/module/wrap.d.ts.map +1 -1
  184. package/lib/typescript/module/wrap.types.d.ts +65 -0
  185. package/lib/typescript/module/wrap.types.d.ts.map +1 -0
  186. package/package.json +6 -24
  187. package/src/catalogCacheNative.spec.ts +63 -0
  188. package/src/catalogCacheNative.ts +74 -0
  189. package/src/checkForUpdate.releaseCatalog.spec.ts +596 -0
  190. package/src/checkForUpdate.ts +367 -96
  191. package/src/error.ts +7 -0
  192. package/src/{fetchUpdateInfo.ts → fetchJSON.ts} +8 -15
  193. package/src/httpClient.spec.ts +132 -0
  194. package/src/httpClient.ts +261 -0
  195. package/src/index.spec.ts +108 -201
  196. package/src/index.ts +68 -91
  197. package/src/iosInterop.spec.ts +30 -0
  198. package/src/native.spec.ts +226 -10
  199. package/src/native.ts +385 -81
  200. package/src/notifyAppReadyAnalytics.boundary.spec.ts +234 -0
  201. package/src/notifyAppReadyAnalytics.spec.ts +243 -0
  202. package/src/notifyAppReadyAnalytics.test-utils.ts +31 -0
  203. package/src/notifyAppReadyAnalytics.transport.spec.ts +130 -0
  204. package/src/notifyAppReadyAnalytics.ts +194 -0
  205. package/src/releaseCatalogCache.spec.ts +282 -0
  206. package/src/releaseCatalogCache.ts +341 -0
  207. package/src/releaseCatalogCacheNativeContract.spec.ts +80 -0
  208. package/src/sdkVersion.ts +1 -1
  209. package/src/specs/NativeHotUpdater.ts +51 -5
  210. package/src/types.ts +0 -140
  211. package/src/wrap.spec.ts +251 -56
  212. package/src/wrap.tsx +23 -318
  213. package/src/wrap.types.ts +78 -0
  214. package/android/src/main/java/com/hotupdater/StringResourceUtils.kt +0 -45
  215. package/app.plugin.js +0 -1
  216. package/ios/HotUpdater/Internal/HotUpdaterCrashHandler.h +0 -7
  217. package/ios/HotUpdater/Internal/HotUpdaterCrashHandler.mm +0 -4
  218. package/lib/commonjs/DefaultResolver.js +0 -50
  219. package/lib/commonjs/DefaultResolver.js.map +0 -1
  220. package/lib/commonjs/DefaultResolver.spec.js +0 -144
  221. package/lib/commonjs/DefaultResolver.spec.js.map +0 -1
  222. package/lib/commonjs/fetchUpdateInfo.js.map +0 -1
  223. package/lib/module/DefaultResolver.js +0 -46
  224. package/lib/module/DefaultResolver.js.map +0 -1
  225. package/lib/module/DefaultResolver.spec.js +0 -144
  226. package/lib/module/DefaultResolver.spec.js.map +0 -1
  227. package/lib/module/fetchUpdateInfo.js.map +0 -1
  228. package/lib/typescript/commonjs/DefaultResolver.d.ts +0 -11
  229. package/lib/typescript/commonjs/DefaultResolver.d.ts.map +0 -1
  230. package/lib/typescript/commonjs/fetchUpdateInfo.d.ts +0 -7
  231. package/lib/typescript/commonjs/fetchUpdateInfo.d.ts.map +0 -1
  232. package/lib/typescript/module/DefaultResolver.d.ts +0 -11
  233. package/lib/typescript/module/DefaultResolver.d.ts.map +0 -1
  234. package/lib/typescript/module/fetchUpdateInfo.d.ts +0 -7
  235. package/lib/typescript/module/fetchUpdateInfo.d.ts.map +0 -1
  236. package/plugin/build/transformers.js +0 -314
  237. package/plugin/build/withHotUpdater.js +0 -228
  238. package/src/DefaultResolver.spec.ts +0 -193
  239. package/src/DefaultResolver.ts +0 -63
@@ -1,314 +0,0 @@
1
- "use strict";
2
- /**
3
- * Pure transformation functions for HotUpdater code injection
4
- * These utilities handle code transformations for different React Native patterns
5
- */
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.transformAndroid = transformAndroid;
8
- exports.transformIOS = transformIOS;
9
- function findMatchingClosingParen(source, openParenIndex) {
10
- let depth = 0;
11
- for (let i = openParenIndex; i < source.length; i += 1) {
12
- const char = source[i];
13
- if (char === "(") {
14
- depth += 1;
15
- continue;
16
- }
17
- if (char === ")") {
18
- depth -= 1;
19
- if (depth === 0) {
20
- return i;
21
- }
22
- }
23
- }
24
- return -1;
25
- }
26
- /**
27
- * Helper to add lines if they don't exist, anchored by a specific string.
28
- */
29
- function addLinesOnce(contents, anchor, linesToAdd) {
30
- if (linesToAdd.every((line) => contents.includes(line))) {
31
- // All lines already exist, do nothing
32
- return contents;
33
- }
34
- // Check if the anchor exists
35
- if (!contents.includes(anchor)) {
36
- // Anchor not found, cannot add lines reliably.
37
- return contents;
38
- }
39
- // Add lines after the anchor
40
- return contents.replace(anchor, `${anchor}\n${linesToAdd.join("\n")}`);
41
- }
42
- /**
43
- * Android: handle getDefaultReactHost pattern (RN 0.82+ style).
44
- * Adds jsBundleFilePath parameter to the call.
45
- */
46
- function transformAndroidReactHost(contents) {
47
- const kotlinImport = "import com.hotupdater.HotUpdater";
48
- const kotlinImportAnchor = "import com.facebook.react.ReactApplication";
49
- // Quick pattern detection: only touch files using getDefaultReactHost
50
- // with the new RN 0.82+ parameter style.
51
- if (!contents.includes("getDefaultReactHost(") ||
52
- !contents.includes("packageList =")) {
53
- return contents;
54
- }
55
- // 1. Ensure HotUpdater import exists (idempotent via addLinesOnce)
56
- const result = addLinesOnce(contents, kotlinImportAnchor, [kotlinImport]);
57
- const callNeedle = "getDefaultReactHost(";
58
- const callStartIndex = result.indexOf(callNeedle);
59
- if (callStartIndex === -1) {
60
- return result;
61
- }
62
- const openParenIndex = callStartIndex + callNeedle.length - 1;
63
- const closeParenIndex = findMatchingClosingParen(result, openParenIndex);
64
- if (closeParenIndex === -1) {
65
- return result;
66
- }
67
- const callContents = result.slice(callStartIndex, closeParenIndex + 1);
68
- const kotlinLegacyBundlePathRegex = /^([ \t]*)jsBundleFilePath = HotUpdater\.getJSBundleFile\(applicationContext\),[ \t]*\r?$/m;
69
- const legacyBundlePathMatch = callContents.match(kotlinLegacyBundlePathRegex);
70
- if (legacyBundlePathMatch) {
71
- const paramIndent = legacyBundlePathMatch[1];
72
- const jsBundleLines = [
73
- `${paramIndent}jsBundleFilePath = if (BuildConfig.DEBUG) {`,
74
- `${paramIndent} null`,
75
- `${paramIndent}} else {`,
76
- `${paramIndent} HotUpdater.getJSBundleFile(applicationContext)`,
77
- `${paramIndent}},`,
78
- ];
79
- const migratedCallContents = callContents.replace(kotlinLegacyBundlePathRegex, jsBundleLines.join("\n"));
80
- return `${result.slice(0, callStartIndex)}${migratedCallContents}${result.slice(closeParenIndex + 1)}`;
81
- }
82
- if (callContents.includes("jsBundleFilePath")) {
83
- return result;
84
- }
85
- const callLines = callContents.split("\n");
86
- // Determine the indentation used for parameters (e.g. " ")
87
- let paramIndent = "";
88
- for (let i = 1; i < callLines.length; i += 1) {
89
- const line = callLines[i];
90
- const trimmed = line.trim();
91
- if (trimmed.length === 0) {
92
- continue;
93
- }
94
- if (trimmed.startsWith(")")) {
95
- // No parameters detected, give up safely.
96
- return result;
97
- }
98
- const indentMatch = line.match(/^(\s*)/);
99
- paramIndent = indentMatch ? indentMatch[1] : "";
100
- break;
101
- }
102
- if (!paramIndent) {
103
- return result;
104
- }
105
- const closingLineStartIndex = result.lastIndexOf("\n", closeParenIndex);
106
- const insertionIndex = closingLineStartIndex === -1 ? 0 : closingLineStartIndex + 1;
107
- let prefix = result.slice(0, insertionIndex);
108
- const suffix = result.slice(insertionIndex);
109
- let prevNonWhitespaceIndex = prefix.length - 1;
110
- while (prevNonWhitespaceIndex >= 0 &&
111
- /\s/.test(prefix[prevNonWhitespaceIndex])) {
112
- prevNonWhitespaceIndex -= 1;
113
- }
114
- if (prevNonWhitespaceIndex >= 0 &&
115
- prefix[prevNonWhitespaceIndex] !== "," &&
116
- prefix[prevNonWhitespaceIndex] !== "(") {
117
- prefix = `${prefix.slice(0, prevNonWhitespaceIndex + 1)},${prefix.slice(prevNonWhitespaceIndex + 1)}`;
118
- }
119
- const jsBundleLines = [
120
- `${paramIndent}jsBundleFilePath = if (BuildConfig.DEBUG) {`,
121
- `${paramIndent} null`,
122
- `${paramIndent}} else {`,
123
- `${paramIndent} HotUpdater.getJSBundleFile(applicationContext)`,
124
- `${paramIndent}},`,
125
- ];
126
- return `${prefix}${jsBundleLines.join("\n")}\n${suffix}`;
127
- }
128
- /**
129
- * Android: DefaultReactNativeHost pattern (RN 0.81 / Expo 54).
130
- * Adds getJSBundleFile() override to the host.
131
- */
132
- function transformAndroidDefaultHost(contents) {
133
- const kotlinImport = "import com.hotupdater.HotUpdater";
134
- const kotlinImportAnchor = "import com.facebook.react.ReactApplication";
135
- const kotlinReactNativeHostAnchor = "object : DefaultReactNativeHost(this) {";
136
- const kotlinMethodCheck = "HotUpdater.getJSBundleFile(applicationContext)";
137
- const kotlinLegacyMethodRegex = /^([ \t]*)override fun getJSBundleFile\(\): String\? \{[ \t]*\r?\n([ \t]*)return HotUpdater\.getJSBundleFile\(applicationContext\)[ \t]*\r?\n\1\}[ \t]*$/m;
138
- const kotlinExistingMethodRegex = /^\s*override fun getJSBundleFile\(\): String\?\s*\{[\s\S]*?^\s*\}/gm;
139
- const kotlinHermesAnchor = "override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED";
140
- const kotlinNewArchAnchor = "override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED";
141
- // Check if this is the old pattern with DefaultReactNativeHost
142
- if (!contents.includes(kotlinReactNativeHostAnchor)) {
143
- return contents;
144
- }
145
- // 1. Add import if missing
146
- let result = addLinesOnce(contents, kotlinImportAnchor, [kotlinImport]);
147
- const legacyMethodMatch = result.match(kotlinLegacyMethodRegex);
148
- if (legacyMethodMatch) {
149
- const methodIndent = legacyMethodMatch[1];
150
- const bodyIndent = legacyMethodMatch[2];
151
- const methodLines = [
152
- `${methodIndent}override fun getJSBundleFile(): String? {`,
153
- `${bodyIndent}return if (BuildConfig.DEBUG) {`,
154
- `${bodyIndent} null`,
155
- `${bodyIndent}} else {`,
156
- `${bodyIndent} HotUpdater.getJSBundleFile(applicationContext)`,
157
- `${bodyIndent}}`,
158
- `${methodIndent}}`,
159
- ];
160
- result = result.replace(kotlinLegacyMethodRegex, methodLines.join("\n"));
161
- }
162
- // 2. Add/Replace getJSBundleFile method if needed
163
- if (!result.includes(kotlinMethodCheck)) {
164
- // Remove potentially existing (different) override first
165
- result = result.replace(kotlinExistingMethodRegex, "");
166
- const lines = result.split("\n");
167
- const findLineIndex = (needle) => {
168
- for (let i = 0; i < lines.length; i += 1) {
169
- if (lines[i].includes(needle)) {
170
- return i;
171
- }
172
- }
173
- return -1;
174
- };
175
- // Prefer inserting after Hermes line, then after new architecture line
176
- let anchorIndex = findLineIndex(kotlinHermesAnchor);
177
- if (anchorIndex === -1) {
178
- anchorIndex = findLineIndex(kotlinNewArchAnchor);
179
- }
180
- if (anchorIndex !== -1) {
181
- const indentMatch = lines[anchorIndex].match(/^\s*/);
182
- const indent = indentMatch ? indentMatch[0] : "";
183
- const objectLine = lines.find((line) => line.includes("object : DefaultReactNativeHost"));
184
- let indentSize = 2;
185
- if (objectLine) {
186
- const objectIndent = (objectLine.match(/^\s*/)?.[0] || "").length;
187
- const propertyIndent = indent.length;
188
- const diff = propertyIndent - objectIndent;
189
- if (diff > 0) {
190
- indentSize = diff;
191
- }
192
- }
193
- const spaces = indentSize === 2 ? " " : " ";
194
- const bodyIndent = indent + spaces;
195
- const methodLines = [
196
- "", // blank line
197
- `${indent}override fun getJSBundleFile(): String? {`,
198
- `${bodyIndent}return if (BuildConfig.DEBUG) {`,
199
- `${bodyIndent} null`,
200
- `${bodyIndent}} else {`,
201
- `${bodyIndent} HotUpdater.getJSBundleFile(applicationContext)`,
202
- `${bodyIndent}}`,
203
- `${indent}}`,
204
- ];
205
- const insertIndex = anchorIndex + 1;
206
- lines.splice(insertIndex, 0, ...methodLines);
207
- result = lines.join("\n");
208
- }
209
- else {
210
- // Fallback: insert before the closing brace of the object block
211
- const hostStartIndex = lines.findIndex((line) => line.includes("object : DefaultReactNativeHost"));
212
- if (hostStartIndex === -1) {
213
- throw new Error("[transformAndroidDefaultHost] Could not find DefaultReactNativeHost block.");
214
- }
215
- let hostEndIndex = -1;
216
- for (let i = lines.length - 1; i > hostStartIndex; i -= 1) {
217
- if (lines[i].trim() === "}") {
218
- hostEndIndex = i;
219
- break;
220
- }
221
- }
222
- if (hostEndIndex === -1) {
223
- throw new Error("[transformAndroidDefaultHost] Could not find end of DefaultReactNativeHost block.");
224
- }
225
- const indentMatch = lines[hostEndIndex].match(/^\s*/);
226
- const indent = indentMatch ? indentMatch[0] : "";
227
- const bodyIndent = `${indent} `;
228
- const methodLines = [
229
- `${indent}override fun getJSBundleFile(): String? {`,
230
- `${bodyIndent}return if (BuildConfig.DEBUG) {`,
231
- `${bodyIndent} null`,
232
- `${bodyIndent}} else {`,
233
- `${bodyIndent} HotUpdater.getJSBundleFile(applicationContext)`,
234
- `${bodyIndent}}`,
235
- `${indent}}`,
236
- ];
237
- lines.splice(hostEndIndex, 0, ...methodLines);
238
- result = lines.join("\n");
239
- }
240
- }
241
- return result;
242
- }
243
- /**
244
- * Public Android transformer that applies all Android-specific transforms.
245
- */
246
- function transformAndroid(contents) {
247
- let result = contents;
248
- result = transformAndroidReactHost(result);
249
- result = transformAndroidDefaultHost(result);
250
- return result;
251
- }
252
- /**
253
- * iOS: Objective-C AppDelegate transformation.
254
- * Replaces NSBundle-based bundleURL with HotUpdater bundleURL.
255
- */
256
- function transformIOSObjC(contents) {
257
- const iosImport = "#import <HotUpdater/HotUpdater.h>";
258
- const iosBundleUrl = "[HotUpdater bundleURL]";
259
- const iosOriginalBundleUrlRegex = /\[\[NSBundle mainBundle\] URLForResource:@"main" withExtension:@"jsbundle"\]/g;
260
- const iosAppDelegateHeader = '#import "AppDelegate.h"';
261
- // Check if it's likely Obj-C
262
- if (!contents.includes(iosAppDelegateHeader)) {
263
- return contents;
264
- }
265
- let result = contents;
266
- // 1. Ensure HotUpdater import is present
267
- if (!result.includes(iosImport)) {
268
- result = addLinesOnce(result, iosAppDelegateHeader, [iosImport]);
269
- }
270
- // 2. Swap NSBundle-based URL with HotUpdater bundleURL, but only once
271
- if (!result.includes(iosBundleUrl) &&
272
- iosOriginalBundleUrlRegex.test(result)) {
273
- result = result.replace(iosOriginalBundleUrlRegex, iosBundleUrl);
274
- }
275
- return result;
276
- }
277
- /**
278
- * iOS: Swift / Expo AppDelegate transformation.
279
- * Replaces Bundle.main.url-based bundleURL with HotUpdater.bundleURL().
280
- */
281
- function transformIOSSwift(contents) {
282
- const swiftImport = "import HotUpdater";
283
- const swiftBundleUrl = "HotUpdater.bundleURL()";
284
- const swiftOriginalBundleUrlRegex = /Bundle\.main\.url\(forResource: "?main"?, withExtension: "jsbundle"\)/g;
285
- // Check if it's likely Swift AppDelegate code
286
- if (!contents.includes("import ")) {
287
- return contents;
288
- }
289
- // 1. Add import if missing - find the last import statement and add after it
290
- let result = contents;
291
- if (!result.includes(swiftImport)) {
292
- // Find the last import statement
293
- const lastImportMatch = result.match(/^import .*$/gm);
294
- if (lastImportMatch) {
295
- const lastImport = lastImportMatch[lastImportMatch.length - 1];
296
- result = result.replace(lastImport, `${lastImport}\n${swiftImport}`);
297
- }
298
- }
299
- // 2. Replace bundleURL provider if the original exists and hasn't been replaced
300
- if (!result.includes(swiftBundleUrl) &&
301
- swiftOriginalBundleUrlRegex.test(result)) {
302
- result = result.replace(swiftOriginalBundleUrlRegex, swiftBundleUrl);
303
- }
304
- return result;
305
- }
306
- /**
307
- * Public iOS transformer that applies both Objective-C and Swift transforms.
308
- */
309
- function transformIOS(contents) {
310
- let result = contents;
311
- result = transformIOSObjC(result);
312
- result = transformIOSSwift(result);
313
- return result;
314
- }
@@ -1,228 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.getPublicKeyFromConfig = void 0;
7
- const promises_1 = require("node:fs/promises");
8
- const path_1 = __importDefault(require("path"));
9
- const config_plugins_1 = require("expo/config-plugins");
10
- const package_json_1 = __importDefault(require("../../package.json"));
11
- const transformers_1 = require("./transformers");
12
- const loadCliTools = () => import("@hot-updater/cli-tools");
13
- const loadHotUpdater = () => import("hot-updater");
14
- const ANDROID_META_DATA_KEYS = {
15
- channel: "com.hotupdater.CHANNEL",
16
- fingerprintHash: "com.hotupdater.FINGERPRINT_HASH",
17
- publicKey: "com.hotupdater.PUBLIC_KEY",
18
- };
19
- const removeAndroidMetaData = (application, name) => {
20
- const metaData = application["meta-data"];
21
- if (!metaData) {
22
- return;
23
- }
24
- const filtered = (Array.isArray(metaData) ? metaData : [metaData]).filter((item) => item?.$?.["android:name"] !== name);
25
- if (filtered.length === 0) {
26
- delete application["meta-data"];
27
- }
28
- else {
29
- application["meta-data"] = filtered;
30
- }
31
- };
32
- const upsertAndroidMetaData = (application, name, value) => {
33
- removeAndroidMetaData(application, name);
34
- const metaData = Array.isArray(application["meta-data"])
35
- ? application["meta-data"]
36
- : application["meta-data"]
37
- ? [application["meta-data"]]
38
- : [];
39
- metaData.push({
40
- $: {
41
- "android:name": name,
42
- "android:value": value,
43
- },
44
- });
45
- application["meta-data"] = metaData;
46
- };
47
- let fingerprintCache = null;
48
- const getFingerprint = async () => {
49
- if (fingerprintCache) {
50
- return fingerprintCache;
51
- }
52
- const { createFingerprintJSON, generateFingerprints } = await loadHotUpdater();
53
- fingerprintCache = await generateFingerprints();
54
- await createFingerprintJSON(fingerprintCache);
55
- return fingerprintCache;
56
- };
57
- /**
58
- * Extract public key for embedding in native configs.
59
- * Supports multiple sources with priority order:
60
- * 1. HOT_UPDATER_PRIVATE_KEY environment variable
61
- * 2. Private key file (extract public key)
62
- * 3. Public key file (derived from privateKeyPath)
63
- * 4. Skip with warning (graceful fallback)
64
- */
65
- const getPublicKeyFromConfig = async (signingConfig) => {
66
- // If signing not enabled, no public key needed
67
- if (!signingConfig?.enabled) {
68
- return null;
69
- }
70
- const envPrivateKey = process.env.HOT_UPDATER_PRIVATE_KEY;
71
- if (envPrivateKey) {
72
- try {
73
- const { getPublicKeyFromPrivate, loadPrivateKey } = await loadHotUpdater();
74
- const envPrivateKeyPEM = envPrivateKey.includes("-----BEGIN")
75
- ? envPrivateKey
76
- : await loadPrivateKey(envPrivateKey);
77
- const publicKeyPEM = getPublicKeyFromPrivate(envPrivateKeyPEM);
78
- console.log("[hot-updater] Using public key extracted from HOT_UPDATER_PRIVATE_KEY environment variable");
79
- return publicKeyPEM.trim();
80
- }
81
- catch (error) {
82
- console.warn("[hot-updater] WARNING: Failed to extract public key from HOT_UPDATER_PRIVATE_KEY:\n" +
83
- `${error instanceof Error ? error.message : String(error)}\n`);
84
- // Continue to try other methods
85
- }
86
- }
87
- // If no privateKeyPath configured, can't proceed with file-based methods
88
- if (!signingConfig.privateKeyPath) {
89
- console.warn("[hot-updater] WARNING: signing.enabled is true but no privateKeyPath configured.\n" +
90
- "Public key will not be embedded. Set HOT_UPDATER_PRIVATE_KEY environment variable or configure privateKeyPath.");
91
- return null;
92
- }
93
- // Resolve paths
94
- const privateKeyPath = path_1.default.isAbsolute(signingConfig.privateKeyPath)
95
- ? signingConfig.privateKeyPath
96
- : path_1.default.resolve(process.cwd(), signingConfig.privateKeyPath);
97
- const publicKeyPath = privateKeyPath.replace(/private-key\.pem$/, "public-key.pem");
98
- try {
99
- // Priority 2: Private key file (existing method)
100
- const { getPublicKeyFromPrivate, loadPrivateKey } = await loadHotUpdater();
101
- const privateKeyPEM = await loadPrivateKey(privateKeyPath);
102
- const publicKeyPEM = getPublicKeyFromPrivate(privateKeyPEM);
103
- console.log(`[hot-updater] Extracted public key from ${privateKeyPath}`);
104
- return publicKeyPEM.trim();
105
- }
106
- catch {
107
- try {
108
- // Priority 3: Public key file (fallback)
109
- const publicKeyPEM = await (0, promises_1.readFile)(publicKeyPath, "utf-8");
110
- console.log(`[hot-updater] Using public key from ${publicKeyPath}`);
111
- return publicKeyPEM.trim();
112
- }
113
- catch {
114
- // Priority 4: All sources failed - throw error
115
- throw new Error("[hot-updater] Failed to load public key for bundle signing.\n\n" +
116
- "Signing is enabled (signing.enabled: true) but no public key sources found.\n\n" +
117
- "For EAS builds, use EAS Secrets:\n" +
118
- ' eas env:create --name HOT_UPDATER_PRIVATE_KEY --value "$(cat keys/private-key.pem)"\n\n' +
119
- "Or add to eas.json:\n" +
120
- ' "env": { "HOT_UPDATER_PRIVATE_KEY": "-----BEGIN PRIVATE KEY-----\\n..." }\n\n' +
121
- "For local development:\n" +
122
- " npx hot-updater keys generate\n\n" +
123
- `Searched locations:\n` +
124
- ` - HOT_UPDATER_PRIVATE_KEY environment variable\n` +
125
- ` - Private key file: ${privateKeyPath}\n` +
126
- ` - Public key file: ${publicKeyPath}\n`);
127
- }
128
- }
129
- };
130
- exports.getPublicKeyFromConfig = getPublicKeyFromConfig;
131
- /**
132
- * Native code modifications - should only run once
133
- */
134
- const withHotUpdaterNativeCode = (config) => {
135
- let modifiedConfig = config;
136
- // === iOS: Objective-C & Swift in AppDelegate ===
137
- modifiedConfig = (0, config_plugins_1.withAppDelegate)(modifiedConfig, (cfg) => {
138
- let contents = cfg.modResults.contents;
139
- contents = (0, transformers_1.transformIOS)(contents);
140
- cfg.modResults.contents = contents;
141
- return cfg;
142
- });
143
- // === Android: Kotlin in MainApplication ===
144
- modifiedConfig = (0, config_plugins_1.withMainApplication)(modifiedConfig, (cfg) => {
145
- let contents = cfg.modResults.contents;
146
- contents = (0, transformers_1.transformAndroid)(contents);
147
- cfg.modResults.contents = contents;
148
- return cfg;
149
- });
150
- return modifiedConfig;
151
- };
152
- /**
153
- * Configuration updates - should run every time
154
- */
155
- const withHotUpdaterConfigAsync = (props) => (config) => {
156
- const channel = props.channel || "production";
157
- let modifiedConfig = config;
158
- // === iOS: Add channel and fingerprint to Info.plist ===
159
- modifiedConfig = (0, config_plugins_1.withInfoPlist)(modifiedConfig, async (cfg) => {
160
- let fingerprintHash = null;
161
- const { loadConfig } = await loadCliTools();
162
- const config = await loadConfig(null);
163
- if (config.updateStrategy !== "appVersion") {
164
- const fingerprint = await getFingerprint();
165
- fingerprintHash = fingerprint.ios.hash;
166
- }
167
- // Load public key if signing is enabled
168
- const publicKey = await (0, exports.getPublicKeyFromConfig)(config.signing);
169
- cfg.modResults.HOT_UPDATER_CHANNEL = channel;
170
- if (fingerprintHash) {
171
- cfg.modResults.HOT_UPDATER_FINGERPRINT_HASH = fingerprintHash;
172
- }
173
- if (publicKey) {
174
- cfg.modResults.HOT_UPDATER_PUBLIC_KEY = publicKey;
175
- }
176
- return cfg;
177
- });
178
- // === Android: Add channel and fingerprint to AndroidManifest.xml ===
179
- modifiedConfig = (0, config_plugins_1.withAndroidManifest)(modifiedConfig, async (cfg) => {
180
- let fingerprintHash = null;
181
- const { loadConfig } = await loadCliTools();
182
- const config = await loadConfig(null);
183
- if (config.updateStrategy !== "appVersion") {
184
- const fingerprint = await getFingerprint();
185
- fingerprintHash = fingerprint.android.hash;
186
- }
187
- // Load public key if signing is enabled
188
- const publicKey = await (0, exports.getPublicKeyFromConfig)(config.signing);
189
- const application = cfg.modResults.manifest.application?.[0];
190
- if (!application) {
191
- return cfg;
192
- }
193
- upsertAndroidMetaData(application, ANDROID_META_DATA_KEYS.channel, channel);
194
- if (fingerprintHash) {
195
- upsertAndroidMetaData(application, ANDROID_META_DATA_KEYS.fingerprintHash, fingerprintHash);
196
- }
197
- if (publicKey) {
198
- upsertAndroidMetaData(application, ANDROID_META_DATA_KEYS.publicKey, publicKey);
199
- }
200
- return cfg;
201
- });
202
- // Remove legacy Hot Updater string resources when prebuild reuses a tree.
203
- modifiedConfig = (0, config_plugins_1.withStringsXml)(modifiedConfig, (cfg) => {
204
- const strings = cfg.modResults.resources?.string;
205
- if (!strings) {
206
- return cfg;
207
- }
208
- cfg.modResults.resources.string = (Array.isArray(strings) ? strings : [strings]).filter((item) => item.$?.name !== "hot_updater_channel" &&
209
- item.$?.name !== "hot_updater_fingerprint_hash" &&
210
- item.$?.name !== "hot_updater_public_key");
211
- return cfg;
212
- });
213
- return modifiedConfig;
214
- };
215
- /**
216
- * Main plugin that combines both native code (run once) and config (run always)
217
- */
218
- const withHotUpdater = (config, props = {}) => {
219
- // Apply plugins in order
220
- return (0, config_plugins_1.withPlugins)(config, [
221
- // Native code modifications - wrapped with createRunOncePlugin
222
- (0, config_plugins_1.createRunOncePlugin)(withHotUpdaterNativeCode, `${package_json_1.default.name}-native`, package_json_1.default.version),
223
- // Configuration updates - runs every time
224
- withHotUpdaterConfigAsync(props),
225
- ]);
226
- };
227
- // Export the main plugin
228
- exports.default = withHotUpdater;