@hot-updater/react-native 0.22.1 → 0.22.2

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hot-updater/react-native",
3
- "version": "0.22.1",
3
+ "version": "0.22.2",
4
4
  "description": "React Native OTA solution for self-hosted",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",
@@ -27,7 +27,7 @@
27
27
  "ios",
28
28
  "cpp",
29
29
  "app.plugin.js",
30
- "plugin/build/withHotUpdater.js",
30
+ "plugin/build",
31
31
  "*.podspec",
32
32
  "react-native.config.js",
33
33
  "!ios/build",
@@ -119,14 +119,14 @@
119
119
  "react-native": "0.79.1",
120
120
  "react-native-builder-bob": "^0.40.10",
121
121
  "typescript": "^5.8.3",
122
- "hot-updater": "0.22.1"
122
+ "hot-updater": "0.22.2"
123
123
  },
124
124
  "dependencies": {
125
125
  "use-sync-external-store": "1.5.0",
126
- "@hot-updater/cli-tools": "0.22.1",
127
- "@hot-updater/js": "0.22.1",
128
- "@hot-updater/core": "0.22.1",
129
- "@hot-updater/plugin-core": "0.22.1"
126
+ "@hot-updater/core": "0.22.2",
127
+ "@hot-updater/js": "0.22.2",
128
+ "@hot-updater/plugin-core": "0.22.2",
129
+ "@hot-updater/cli-tools": "0.22.2"
130
130
  },
131
131
  "scripts": {
132
132
  "build": "bob build && tsc -p plugin/tsconfig.build.json",
@@ -0,0 +1,269 @@
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
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
7
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
8
+ if (ar || !(i in from)) {
9
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
10
+ ar[i] = from[i];
11
+ }
12
+ }
13
+ return to.concat(ar || Array.prototype.slice.call(from));
14
+ };
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.transformAndroid = transformAndroid;
17
+ exports.transformIOS = transformIOS;
18
+ /**
19
+ * Helper to add lines if they don't exist, anchored by a specific string.
20
+ */
21
+ function addLinesOnce(contents, anchor, linesToAdd) {
22
+ if (linesToAdd.every(function (line) { return contents.includes(line); })) {
23
+ // All lines already exist, do nothing
24
+ return contents;
25
+ }
26
+ // Check if the anchor exists
27
+ if (!contents.includes(anchor)) {
28
+ // Anchor not found, cannot add lines reliably.
29
+ return contents;
30
+ }
31
+ // Add lines after the anchor
32
+ return contents.replace(anchor, "".concat(anchor, "\n").concat(linesToAdd.join("\n")));
33
+ }
34
+ /**
35
+ * Android: handle getDefaultReactHost pattern (RN 0.82+ style).
36
+ * Adds jsBundleFilePath parameter to the call.
37
+ */
38
+ function transformAndroidReactHost(contents) {
39
+ var kotlinImport = "import com.hotupdater.HotUpdater";
40
+ var kotlinImportAnchor = "import com.facebook.react.ReactApplication";
41
+ var kotlinMethodCheck = "HotUpdater.getJSBundleFile(applicationContext)";
42
+ // Quick pattern detection: only touch files using getDefaultReactHost
43
+ // with the new RN 0.82+ parameter style.
44
+ if (!contents.includes("getDefaultReactHost(") ||
45
+ !contents.includes("packageList =")) {
46
+ return contents;
47
+ }
48
+ // 1. Ensure HotUpdater import exists (idempotent via addLinesOnce)
49
+ var result = addLinesOnce(contents, kotlinImportAnchor, [kotlinImport]);
50
+ // 2. If jsBundleFilePath is already wired to HotUpdater, do nothing
51
+ if (result.includes(kotlinMethodCheck) &&
52
+ result.includes("jsBundleFilePath")) {
53
+ return result;
54
+ }
55
+ var lines = result.split("\n");
56
+ var callIndex = lines.findIndex(function (line) {
57
+ return line.includes("getDefaultReactHost(");
58
+ });
59
+ if (callIndex === -1) {
60
+ return result;
61
+ }
62
+ // Determine the indentation used for parameters (e.g. " ")
63
+ var paramIndent = "";
64
+ for (var i = callIndex + 1; i < lines.length; i += 1) {
65
+ var line = lines[i];
66
+ var trimmed = line.trim();
67
+ if (trimmed.length === 0) {
68
+ continue;
69
+ }
70
+ if (trimmed.startsWith(")")) {
71
+ // No parameters detected, give up safely.
72
+ return result;
73
+ }
74
+ var indentMatch = line.match(/^(\s*)/);
75
+ paramIndent = indentMatch ? indentMatch[1] : "";
76
+ break;
77
+ }
78
+ if (!paramIndent) {
79
+ return result;
80
+ }
81
+ // Find the closing line of the call (a line that is just ")" with indentation).
82
+ var closingIndex = -1;
83
+ for (var i = callIndex + 1; i < lines.length; i += 1) {
84
+ if (lines[i].trim() === ")") {
85
+ closingIndex = i;
86
+ break;
87
+ }
88
+ }
89
+ if (closingIndex === -1) {
90
+ return result;
91
+ }
92
+ // Avoid inserting twice if jsBundleFilePath already added somewhere in the call.
93
+ for (var i = callIndex; i < closingIndex; i += 1) {
94
+ if (lines[i].includes("jsBundleFilePath")) {
95
+ return result;
96
+ }
97
+ }
98
+ var jsBundleLine = "".concat(paramIndent, "jsBundleFilePath = HotUpdater.getJSBundleFile(applicationContext),");
99
+ lines.splice(closingIndex, 0, jsBundleLine);
100
+ return lines.join("\n");
101
+ }
102
+ /**
103
+ * Android: DefaultReactNativeHost pattern (RN 0.81 / Expo 54).
104
+ * Adds getJSBundleFile() override to the host.
105
+ */
106
+ function transformAndroidDefaultHost(contents) {
107
+ var _a;
108
+ var kotlinImport = "import com.hotupdater.HotUpdater";
109
+ var kotlinImportAnchor = "import com.facebook.react.ReactApplication";
110
+ var kotlinReactNativeHostAnchor = "object : DefaultReactNativeHost(this) {";
111
+ var kotlinMethodCheck = "HotUpdater.getJSBundleFile(applicationContext)";
112
+ var kotlinExistingMethodRegex = /^\s*override fun getJSBundleFile\(\): String\?\s*\{[\s\S]*?^\s*\}/gm;
113
+ var kotlinHermesAnchor = "override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED";
114
+ var kotlinNewArchAnchor = "override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED";
115
+ // Check if this is the old pattern with DefaultReactNativeHost
116
+ if (!contents.includes(kotlinReactNativeHostAnchor)) {
117
+ return contents;
118
+ }
119
+ // 1. Add import if missing
120
+ var result = addLinesOnce(contents, kotlinImportAnchor, [kotlinImport]);
121
+ // 2. Add/Replace getJSBundleFile method if needed
122
+ if (!result.includes(kotlinMethodCheck)) {
123
+ // Remove potentially existing (different) override first
124
+ result = result.replace(kotlinExistingMethodRegex, "");
125
+ var lines_1 = result.split("\n");
126
+ var findLineIndex = function (needle) {
127
+ for (var i = 0; i < lines_1.length; i += 1) {
128
+ if (lines_1[i].includes(needle)) {
129
+ return i;
130
+ }
131
+ }
132
+ return -1;
133
+ };
134
+ // Prefer inserting after Hermes line, then after new architecture line
135
+ var anchorIndex = findLineIndex(kotlinHermesAnchor);
136
+ if (anchorIndex === -1) {
137
+ anchorIndex = findLineIndex(kotlinNewArchAnchor);
138
+ }
139
+ if (anchorIndex !== -1) {
140
+ var indentMatch = lines_1[anchorIndex].match(/^\s*/);
141
+ var indent = indentMatch ? indentMatch[0] : "";
142
+ var objectLine = lines_1.find(function (line) {
143
+ return line.includes("object : DefaultReactNativeHost");
144
+ });
145
+ var indentSize = 2;
146
+ if (objectLine) {
147
+ var objectIndent = (((_a = objectLine.match(/^\s*/)) === null || _a === void 0 ? void 0 : _a[0]) || "").length;
148
+ var propertyIndent = indent.length;
149
+ var diff = propertyIndent - objectIndent;
150
+ if (diff > 0) {
151
+ indentSize = diff;
152
+ }
153
+ }
154
+ var spaces = indentSize === 2 ? " " : " ";
155
+ var bodyIndent = indent + spaces;
156
+ var methodLines = [
157
+ "", // blank line
158
+ "".concat(indent, "override fun getJSBundleFile(): String? {"),
159
+ "".concat(bodyIndent, "return HotUpdater.getJSBundleFile(applicationContext)"),
160
+ "".concat(indent, "}"),
161
+ ];
162
+ var insertIndex = anchorIndex + 1;
163
+ lines_1.splice.apply(lines_1, __spreadArray([insertIndex, 0], methodLines, false));
164
+ result = lines_1.join("\n");
165
+ }
166
+ else {
167
+ // Fallback: insert before the closing brace of the object block
168
+ var hostStartIndex = lines_1.findIndex(function (line) {
169
+ return line.includes("object : DefaultReactNativeHost");
170
+ });
171
+ if (hostStartIndex === -1) {
172
+ throw new Error("[transformAndroidDefaultHost] Could not find DefaultReactNativeHost block.");
173
+ }
174
+ var hostEndIndex = -1;
175
+ for (var i = lines_1.length - 1; i > hostStartIndex; i -= 1) {
176
+ if (lines_1[i].trim() === "}") {
177
+ hostEndIndex = i;
178
+ break;
179
+ }
180
+ }
181
+ if (hostEndIndex === -1) {
182
+ throw new Error("[transformAndroidDefaultHost] Could not find end of DefaultReactNativeHost block.");
183
+ }
184
+ var indentMatch = lines_1[hostEndIndex].match(/^\s*/);
185
+ var indent = indentMatch ? indentMatch[0] : "";
186
+ var bodyIndent = "".concat(indent, " ");
187
+ var methodLines = [
188
+ "".concat(indent, "override fun getJSBundleFile(): String? {"),
189
+ "".concat(bodyIndent, "return HotUpdater.getJSBundleFile(applicationContext)"),
190
+ "".concat(indent, "}"),
191
+ ];
192
+ lines_1.splice.apply(lines_1, __spreadArray([hostEndIndex, 0], methodLines, false));
193
+ result = lines_1.join("\n");
194
+ }
195
+ }
196
+ return result;
197
+ }
198
+ /**
199
+ * Public Android transformer that applies all Android-specific transforms.
200
+ */
201
+ function transformAndroid(contents) {
202
+ var result = contents;
203
+ result = transformAndroidReactHost(result);
204
+ result = transformAndroidDefaultHost(result);
205
+ return result;
206
+ }
207
+ /**
208
+ * iOS: Objective-C AppDelegate transformation.
209
+ * Replaces NSBundle-based bundleURL with HotUpdater bundleURL.
210
+ */
211
+ function transformIOSObjC(contents) {
212
+ var iosImport = "#import <HotUpdater/HotUpdater.h>";
213
+ var iosBundleUrl = "[HotUpdater bundleURL]";
214
+ var iosOriginalBundleUrlRegex = /\[\[NSBundle mainBundle\] URLForResource:@"main" withExtension:@"jsbundle"\]/g;
215
+ var iosAppDelegateHeader = '#import "AppDelegate.h"';
216
+ // Check if it's likely Obj-C
217
+ if (!contents.includes(iosAppDelegateHeader)) {
218
+ return contents;
219
+ }
220
+ var result = contents;
221
+ // 1. Ensure HotUpdater import is present
222
+ if (!result.includes(iosImport)) {
223
+ result = addLinesOnce(result, iosAppDelegateHeader, [iosImport]);
224
+ }
225
+ // 2. Swap NSBundle-based URL with HotUpdater bundleURL, but only once
226
+ if (!result.includes(iosBundleUrl) &&
227
+ iosOriginalBundleUrlRegex.test(result)) {
228
+ result = result.replace(iosOriginalBundleUrlRegex, iosBundleUrl);
229
+ }
230
+ return result;
231
+ }
232
+ /**
233
+ * iOS: Swift / Expo AppDelegate transformation.
234
+ * Replaces Bundle.main.url-based bundleURL with HotUpdater.bundleURL().
235
+ */
236
+ function transformIOSSwift(contents) {
237
+ var swiftImport = "import HotUpdater";
238
+ var swiftBundleUrl = "HotUpdater.bundleURL()";
239
+ var swiftOriginalBundleUrlRegex = /Bundle\.main\.url\(forResource: "?main"?, withExtension: "jsbundle"\)/g;
240
+ // Check if it's likely Swift AppDelegate code
241
+ if (!contents.includes("import ")) {
242
+ return contents;
243
+ }
244
+ // 1. Add import if missing - find the last import statement and add after it
245
+ var result = contents;
246
+ if (!result.includes(swiftImport)) {
247
+ // Find the last import statement
248
+ var lastImportMatch = result.match(/^import .*$/gm);
249
+ if (lastImportMatch) {
250
+ var lastImport = lastImportMatch[lastImportMatch.length - 1];
251
+ result = result.replace(lastImport, "".concat(lastImport, "\n").concat(swiftImport));
252
+ }
253
+ }
254
+ // 2. Replace bundleURL provider if the original exists and hasn't been replaced
255
+ if (!result.includes(swiftBundleUrl) &&
256
+ swiftOriginalBundleUrlRegex.test(result)) {
257
+ result = result.replace(swiftOriginalBundleUrlRegex, swiftBundleUrl);
258
+ }
259
+ return result;
260
+ }
261
+ /**
262
+ * Public iOS transformer that applies both Objective-C and Swift transforms.
263
+ */
264
+ function transformIOS(contents) {
265
+ var result = contents;
266
+ result = transformIOSObjC(result);
267
+ result = transformIOSSwift(result);
268
+ return result;
269
+ }