react-native-bspatch 1.0.1 → 1.0.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": "react-native-bspatch",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Premium OTA Update Solution for React Native using TurboModules and bsdiff",
5
5
  "main": "lib/commonjs/index.js",
6
6
  "module": "lib/module/index.js",
@@ -81,86 +81,79 @@ REGISTRY_SHARED="$ROOT/ota_registry.json"
81
81
  # ── Registry Sync ──────────────────────────────────────────────────────────
82
82
  # Skip registry sync for reset/clean actions
83
83
  if [ "$ACTION" != "reset" ]; then
84
- # Download the latest ota_registry.json from server so we don't clobber other platforms
85
84
  echo "Syncing remote registry..."
86
85
 
87
- # Load credentials from environment variables (required for security)
88
- # Upload credentials are used by the build script
89
- BASE_URL="${OTA_BASE_URL:-https://sync-server.osp.com.vn}"
90
- UPCODE_USER="${OTA_UPLOAD_USER:-}"
91
- UPCODE_PASS="${OTA_UPLOAD_PASSWORD:-}"
92
- BASE_FOLDER="${OTA_FOLDER:-congplqg}"
93
-
94
- # Debug: show credentials (without exposing password)
95
- echo " Using URL: $BASE_URL"
96
- echo " Using User: $UPCODE_USER"
97
- echo " Using Folder: $BASE_FOLDER"
98
-
99
- # Validate required credentials
100
- if [[ -z "$UPCODE_USER" ]] || [[ -z "$UPCODE_PASS" ]]; then
101
- echo "ERROR: OTA upload credentials not set. Please set OTA_UPLOAD_USER and OTA_UPLOAD_PASSWORD in .env file."
102
- echo " OTA_UPLOAD_USER=\"your-username\""
103
- echo " OTA_UPLOAD_PASSWORD=\"your-password\""
104
- echo " Optional: OTA_BASE_URL OTA_FOLDER"
105
- exit 1
106
- fi
107
-
108
- # Debug: show curl command for manual testing
109
- echo " Login URL: ${BASE_URL}/public/authen/login"
110
-
111
- LOGIN_RES=$(curl -s -X "POST" "$BASE_URL/public/authen/login" \
112
- -H 'Content-Type: application/json; charset=utf-8' \
113
- -w "\n---HTTP_STATUS:%{http_code}" \
114
- -d "{\"username\": \"$UPCODE_USER\", \"password\": \"$UPCODE_PASS\"}")
115
-
116
- # Extract HTTP status and response body
117
- HTTP_STATUS=$(echo "$LOGIN_RES" | grep -o 'HTTP_STATUS:[0-9]*' | cut -d: -f2)
118
- LOGIN_BODY=$(echo "$LOGIN_RES" | sed 's/---HTTP_STATUS:.*//')
119
-
120
- # Debug: show login response on error or empty
121
- if [ -z "$LOGIN_BODY" ] || [ "$HTTP_STATUS" != "200" ]; then
122
- echo " ⚠ Login failed - HTTP $HTTP_STATUS"
123
- echo " ⚠ Response: $LOGIN_BODY"
124
- fi
125
-
126
- TOKEN=$(echo "$LOGIN_BODY" | node -e "
127
- try {
128
- const r = JSON.parse(require('fs').readFileSync(0, 'utf8'));
129
- console.log(r.data?.accessTokenInfo?.accessToken || '');
130
- } catch(e) { console.log(''); }
131
- ")
132
-
133
- if [[ -n "$TOKEN" ]]; then
134
- REGISTRY_REMOTE_PATH="$BASE_FOLDER/ota_registry.json"
135
- # Encode slash as %2F for MinIO API
136
- ENCODED_PATH=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$REGISTRY_REMOTE_PATH', safe=''))")
137
- GEN_LINK_URL="$BASE_URL/api/minio/gen-download-link?pathFile=$ENCODED_PATH"
138
-
139
- LINK_RES=$(curl -s -X "GET" "$GEN_LINK_URL" -H "Authorization: Bearer $TOKEN")
140
- REGISTRY_URL=$(echo "$LINK_RES" | node -e "
141
- try {
142
- const r = JSON.parse(require('fs').readFileSync(0, 'utf8'));
143
- console.log(r.data || '');
144
- } catch(e) { console.log(''); }
145
- ")
146
-
147
- if [[ -n "$REGISTRY_URL" ]]; then
148
- echo " Downloading remote registry..."
149
- curl -s -o "$REGISTRY_SHARED" "$REGISTRY_URL"
150
- echo " ✓ Registry synced"
86
+ BASE_URL="${OTA_BASE_URL:-https://sync-server.osp.com.vn}"
87
+ UPCODE_USER="${OTA_UPLOAD_USER:-}"
88
+ UPCODE_PASS="${OTA_UPLOAD_PASSWORD:-}"
89
+ BASE_FOLDER="${OTA_FOLDER:-ota}"
90
+
91
+ echo " Using URL: $BASE_URL"
92
+ echo " Using Folder: $BASE_FOLDER"
93
+
94
+ if [[ "$BASE_URL" == *"github"* ]] || [[ "$BASE_URL" == *"raw.githubusercontent"* ]]; then
95
+ echo " Downloading remote registry from GitHub..."
96
+ HTTP_CODE=$(curl -s -w "%{http_code}" -o "$REGISTRY_SHARED.tmp" "$BASE_URL/$BASE_FOLDER/ota_registry.json" 2>/dev/null || true)
97
+ if [ "$HTTP_CODE" != "200" ]; then
98
+ HTTP_CODE=$(curl -s -w "%{http_code}" -o "$REGISTRY_SHARED.tmp" "$BASE_URL/ota_registry.json" 2>/dev/null || true)
99
+ fi
100
+ if [ "$HTTP_CODE" = "200" ] && [ -s "$REGISTRY_SHARED.tmp" ]; then
101
+ mv "$REGISTRY_SHARED.tmp" "$REGISTRY_SHARED"
102
+ echo " ✓ Remote registry synced"
103
+ else
104
+ rm -f "$REGISTRY_SHARED.tmp"
105
+ echo " Notice: Remote registry not found on GitHub (starting fresh with local state)."
106
+ fi
151
107
  else
152
- echo " ⚠ Remote registry not found (starting fresh)."
153
- # Do not delete existing local registry if sync fails, just proceed
108
+ if [[ -n "$UPCODE_USER" ]] && [[ -n "$UPCODE_PASS" ]]; then
109
+ LOGIN_RES=$(curl -s -X "POST" "$BASE_URL/public/authen/login" \
110
+ -H 'Content-Type: application/json; charset=utf-8' \
111
+ -w "\n---HTTP_STATUS:%{http_code}" \
112
+ -d "{\"username\": \"$UPCODE_USER\", \"password\": \"$UPCODE_PASS\"}")
113
+ HTTP_STATUS=$(echo "$LOGIN_RES" | grep -o 'HTTP_STATUS:[0-9]*' | cut -d: -f2)
114
+ LOGIN_BODY=$(echo "$LOGIN_RES" | sed 's/---HTTP_STATUS:.*//')
115
+
116
+ TOKEN=$(echo "$LOGIN_BODY" | node -e "
117
+ try {
118
+ const r = JSON.parse(require('fs').readFileSync(0, 'utf8'));
119
+ console.log(r.data?.accessTokenInfo?.accessToken || '');
120
+ } catch(e) { console.log(''); }
121
+ ")
122
+
123
+ if [[ -n "$TOKEN" ]]; then
124
+ REGISTRY_REMOTE_PATH="$BASE_FOLDER/ota_registry.json"
125
+ ENCODED_PATH=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$REGISTRY_REMOTE_PATH', safe=''))")
126
+ GEN_LINK_URL="$BASE_URL/api/minio/gen-download-link?pathFile=$ENCODED_PATH"
127
+ LINK_RES=$(curl -s -X "GET" "$GEN_LINK_URL" -H "Authorization: Bearer $TOKEN")
128
+ REGISTRY_URL=$(echo "$LINK_RES" | node -e "
129
+ try {
130
+ const r = JSON.parse(require('fs').readFileSync(0, 'utf8'));
131
+ console.log(r.data || '');
132
+ } catch(e) { console.log(''); }
133
+ ")
134
+ if [[ -n "$REGISTRY_URL" ]]; then
135
+ curl -s -o "$REGISTRY_SHARED" "$REGISTRY_URL"
136
+ echo " ✓ Registry synced"
137
+ fi
138
+ else
139
+ echo " ⚠ MinIO login skipped. Proceeding with local state."
140
+ fi
141
+ else
142
+ echo " ⚠ No MinIO credentials. Proceeding with local state."
143
+ fi
154
144
  fi
155
- else
156
- echo " ⚠ Login failed during registry sync. Proceeding with local state."
157
- fi
158
145
  fi
159
146
 
160
147
  # ── Helper: Download from Server ──────────────────────────────────────────────
161
148
  download_from_minio() {
162
149
  local REMOTE_PATH="$1"
163
150
  local DEST="$2"
151
+
152
+ if [[ "$BASE_URL" == *"github"* ]] || [[ "$BASE_URL" == *"raw.githubusercontent"* ]]; then
153
+ curl -s -f -o "$DEST" "$BASE_URL/$REMOTE_PATH" 2>/dev/null || curl -s -f -o "$DEST" "$BASE_URL/$(basename "$REMOTE_PATH")" 2>/dev/null
154
+ return $?
155
+ fi
156
+
164
157
  if [[ -z "$TOKEN" ]]; then return 1; fi
165
158
 
166
159
  local ENCODED_PATH=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$REMOTE_PATH', safe=''))")
@@ -91,44 +91,24 @@ function patchPbxproj(content) {
91
91
  // Already patched?
92
92
  if (content.includes(XCODE_BUNDLE_SYNC_MARKER)) return content;
93
93
 
94
- // Find the Bundle React Native code and images shellScript value
95
- // Pattern: name = "Bundle React Native code and images"; ... shellScript = "...";
96
- // The shellScript ends with \n\";\n — we inject before the last closing \n\";
97
- const shellScriptRegex = /(00DD1BFF1BD5951E006B06BC[^;]*?shellScript = ")([\s\S]*?)(\s*";)/m;
98
- const match = content.match(shellScriptRegex);
99
- if (!match) {
100
- // Fallback: find by name
101
- console.log(' ⚠ Could not find "Bundle React Native code and images" build phase by UUID, trying by name...');
102
- // Simpler approach: find shellScript belonging to the bundle phase by name proximity
103
- const nameIdx = content.indexOf('name = "Bundle React Native code and images"');
104
- if (nameIdx === -1) {
105
- console.log(' ⚠ Could not find build phase. Please add the bundle sync snippet manually.');
106
- return content;
94
+ // Search by phase name
95
+ const nameIdx = content.indexOf('name = "Bundle React Native code and images";');
96
+ if (nameIdx !== -1) {
97
+ const shellScriptIdx = content.indexOf('shellScript = "', nameIdx);
98
+ if (shellScriptIdx !== -1) {
99
+ const endIdx = content.indexOf('";', shellScriptIdx + 15);
100
+ if (endIdx !== -1) {
101
+ return (
102
+ content.slice(0, endIdx) +
103
+ XCODE_BUNDLE_SYNC_SNIPPET +
104
+ content.slice(endIdx)
105
+ );
106
+ }
107
107
  }
108
- // Find the shellScript = "..." after this name line
109
- const afterName = content.indexOf('shellScript = "', nameIdx - 500);
110
- if (afterName === -1) return content;
111
-
112
- // Find the end of this shellScript: look for \n\"; after it
113
- const scriptEnd = content.indexOf('\\n";', afterName);
114
- if (scriptEnd === -1) return content;
115
-
116
- return (
117
- content.slice(0, scriptEnd) +
118
- XCODE_BUNDLE_SYNC_SNIPPET +
119
- content.slice(scriptEnd)
120
- );
121
108
  }
122
109
 
123
- // Insert before the closing \n\";
124
- const scriptBody = match[2];
125
- // Remove trailing \n if present before closing
126
- const insertPoint = match.index + match[1].length + scriptBody.length;
127
- return (
128
- content.slice(0, insertPoint) +
129
- XCODE_BUNDLE_SYNC_SNIPPET +
130
- content.slice(insertPoint)
131
- );
110
+ console.log(' ⚠ Could not find "Bundle React Native code and images" build phase in project.pbxproj.');
111
+ return content;
132
112
  }
133
113
 
134
114
  // ── iOS: AppDelegate.swift ────────────────────────────────────────────────────
@@ -229,8 +209,8 @@ function main() {
229
209
  // ── iOS ──
230
210
  console.log('\n[iOS]');
231
211
 
232
- // project.pbxproj
233
- const pbxprojFiles = findFile(IOS_DIR, (name) => name === 'project.pbxproj');
212
+ // project.pbxproj (ignore CocoaPods project file)
213
+ const pbxprojFiles = findFile(IOS_DIR, (name, fullPath) => name === 'project.pbxproj' && !fullPath.includes('Pods'));
234
214
  if (pbxprojFiles.length === 0) {
235
215
  console.log(' ⚠ No project.pbxproj found. Is this an iOS project?');
236
216
  } else {