ota-manager 1.0.14 → 1.0.16

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/lib/ota-build.cjs CHANGED
@@ -49,6 +49,44 @@ if (fs.existsSync(envPath)) {
49
49
  });
50
50
  }
51
51
 
52
+ function isBase64(str) {
53
+ if (!str) return false;
54
+ const clean = str.replace(/\s+/g, '');
55
+ if (clean.length === 0) return false;
56
+ const regex = /^[A-Za-z0-9+/=]+$/;
57
+ return regex.test(clean);
58
+ }
59
+
60
+ function getBase64OrFileContent(val) {
61
+ if (!val) return '';
62
+ try {
63
+ if (fs.existsSync(val)) {
64
+ const fileContent = fs.readFileSync(val);
65
+ const textContent = fileContent.toString('utf8').trim();
66
+
67
+ if (textContent.includes('=')) {
68
+ const match = textContent.match(/^\s*[\w.-]+\s*=\s*(.*)?\s*$/);
69
+ if (match && match[1]) {
70
+ const cleanVal = match[1].trim();
71
+ if (isBase64(cleanVal)) {
72
+ return cleanVal;
73
+ }
74
+ }
75
+ }
76
+
77
+ if (isBase64(textContent)) {
78
+ return textContent;
79
+ }
80
+
81
+ return fileContent.toString('base64');
82
+ }
83
+ } catch (e) {
84
+ console.warn(`⚠️ Warning: Error reading file at "${val}":`, e.message);
85
+ }
86
+ return val;
87
+ }
88
+
89
+
52
90
  const rawArgs = process.argv.slice(2).map(a => a.toLowerCase());
53
91
  const hasNv = rawArgs.includes('-nv') || rawArgs.includes('--nv') || rawArgs.includes('--no-version') || rawArgs.includes('nover') || rawArgs.includes('no-ver') || rawArgs.includes('-no') || rawArgs.includes('--no') || rawArgs.includes('no') || rawArgs.includes('-norev') || rawArgs.includes('--norev') || rawArgs.includes('norev');
54
92
 
@@ -244,15 +282,28 @@ async function buildIos() {
244
282
  try {
245
283
  execSync('git add .', { stdio: 'ignore' });
246
284
  const status = execSync('git status --porcelain').toString();
285
+
286
+ let remoteName = 'origin';
287
+ try {
288
+ const remotes = execSync('git remote').toString().trim().split(/\s+/);
289
+ if (!remotes.includes('origin')) {
290
+ if (remotes.includes('github')) {
291
+ remoteName = 'github';
292
+ } else if (remotes.length > 0 && remotes[0]) {
293
+ remoteName = remotes[0];
294
+ }
295
+ }
296
+ } catch (err) {}
297
+
247
298
  if (status) {
248
- console.log('📤 Pushing changes to GitHub...');
299
+ console.log(`📤 Pushing changes to ${remoteName}...`);
249
300
  execSync('git commit -m "chore: automated build sync"', { stdio: 'ignore' });
250
- execSync(`git push origin ${branch}`, { stdio: 'ignore' });
301
+ execSync(`git push ${remoteName} ${branch}`, { stdio: 'ignore' });
251
302
  console.log('✅ Changes pushed!');
252
303
  await sleep(2000);
253
304
  } else {
254
- console.log('✅ No local file changes. Ensuring active branch ref is pushed to remote...');
255
- execSync(`git push origin ${branch}`, { stdio: 'ignore' });
305
+ console.log(`✅ No local file changes. Ensuring active branch ref is pushed to remote on ${remoteName}...`);
306
+ execSync(`git push ${remoteName} ${branch}`, { stdio: 'ignore' });
256
307
  }
257
308
  } catch (e) {
258
309
  console.log('⚠️ Git push skipped or branch already up to date on remote.');
@@ -261,13 +312,24 @@ async function buildIos() {
261
312
  console.log('🚀 Triggering GitHub Action...');
262
313
  try {
263
314
  const payload = { ref: branch };
264
- if (activeWorkflowId === 'ios-build.yml') {
265
- payload.inputs = {
266
- channel: process.env.PUBLIC_APP_CHANNEL || 'training',
267
- api_url: process.env.PUBLIC_API_URL || '',
268
- github_ota_pat: process.env.PUBLIC_GITHUB_OTA_PAT || '',
269
- ota_update_url: process.env.PUBLIC_OTA_UPDATE_URL || ''
270
- };
315
+ payload.inputs = {
316
+ channel: process.env.PUBLIC_APP_CHANNEL || 'training',
317
+ api_url: process.env.PUBLIC_API_URL || '',
318
+ github_ota_pat: process.env.PUBLIC_GITHUB_OTA_PAT || '',
319
+ ota_update_url: process.env.PUBLIC_OTA_UPDATE_URL || ''
320
+ };
321
+ if (activeWorkflowId === 'ios-release.yml') {
322
+ const certVal = process.env.APPLE_BUILD_CERTIFICATE_BASE64 || '';
323
+ const provVal = process.env.APPLE_BUILD_PROVISION_PROFILE_BASE64 || '';
324
+ const apiKeyVal = process.env.APP_STORE_CONNECT_API_KEY_BASE64 || '';
325
+
326
+ payload.inputs.apple_build_certificate_base64 = getBase64OrFileContent(certVal);
327
+ payload.inputs.apple_build_provision_profile_base64 = getBase64OrFileContent(provVal);
328
+ payload.inputs.app_store_connect_api_key_base64 = getBase64OrFileContent(apiKeyVal);
329
+ payload.inputs.app_store_connect_api_key_id = process.env.APP_STORE_CONNECT_API_KEY_ID || '';
330
+ payload.inputs.app_store_connect_api_issuer = process.env.APP_STORE_CONNECT_API_ISSUER || '';
331
+ payload.inputs.apple_p12_password = process.env.APPLE_P12_PASSWORD || '';
332
+ payload.inputs.apple_keychain_password = process.env.APPLE_KEYCHAIN_PASSWORD || '';
271
333
  }
272
334
  await githubApi(`/repos/${REPO}/actions/workflows/${activeWorkflowId}/dispatches`, 'POST', payload);
273
335
  console.log('✅ Trigger Success! Waiting for run to start...');
@@ -114,7 +114,8 @@ async function runSecurityAudit() {
114
114
 
115
115
  if (content.includes('"version"')) {
116
116
  const data = JSON.parse(content);
117
- console.log(`✅ Read Successful! Current Remote Version: v${data.version}`);
117
+ const remoteVer = data.version || data[channel]?.version || (data.live?.version || data.training?.version);
118
+ console.log(`✅ Read Successful! Current Remote Version: v${remoteVer}`);
118
119
  } else {
119
120
  console.log(`❌ Raw Response: ${content.substring(0, 100)}...`);
120
121
  throw new Error("Invalid content");
@@ -4,7 +4,7 @@ const path = require('path');
4
4
  const distDir = path.join(process.cwd(), 'dist');
5
5
  const filesToVerify = ['splash.html', 'index.html', 'home.html'];
6
6
 
7
- console.log('🔍 MEMULAI VERIFIKASI OTA ZIP (Pre-Flight Check)...\n');
7
+ console.log('🔍 STARTING OTA ZIP VERIFICATION (Pre-Flight Check)...\n');
8
8
 
9
9
  if (!fs.existsSync(distDir)) {
10
10
  console.log(`❌ Error: dist/ directory not found in ${process.cwd()}`);
@@ -16,70 +16,70 @@ let totalErrors = 0;
16
16
  filesToVerify.forEach(filename => {
17
17
  const filePath = path.join(distDir, filename);
18
18
  if (!fs.existsSync(filePath)) {
19
- console.log(`⚠️ WARNING: File utama ${filename} tidak ditemukan di dist/`);
19
+ console.log(`⚠️ WARNING: Main file ${filename} not found in dist/`);
20
20
  return;
21
21
  }
22
22
 
23
- console.log(`📄 Memeriksa: ${filename}`);
23
+ console.log(`📄 Verifying: ${filename}`);
24
24
  const content = fs.readFileSync(filePath, 'utf8');
25
25
 
26
- // Regex untuk mencari src="..." atau href="..."
26
+ // Regex to search for src="..." or href="..."
27
27
  const regex = /(?:src|href)=["']([^"']+)["']/g;
28
28
  let match;
29
29
 
30
30
  while ((match = regex.exec(content)) !== null) {
31
31
  const assetPath = match[1];
32
32
 
33
- // Abaikan link eksternal atau base64
33
+ // Ignore external links or base64
34
34
  if (assetPath.startsWith('http') || assetPath.startsWith('data:')) continue;
35
35
 
36
36
  let hasError = false;
37
37
 
38
- // CEK 1: Garis Miring Ilegal khusus untuk folder assets
38
+ // CHECK 1: Illegal slashes specifically for assets folder
39
39
  if (assetPath.startsWith('/assets') || assetPath.startsWith('.//')) {
40
- console.log(` ❌ ERROR JALUR: Ditemukan path ilegal -> "${assetPath}"`);
40
+ console.log(` ❌ PATH ERROR: Illegal path found -> "${assetPath}"`);
41
41
  hasError = true;
42
42
  totalErrors++;
43
43
  }
44
44
 
45
- // Abaikan validasi file fisik untuk navigasi HTML atau anchor SVG
45
+ // Ignore physical file validation for HTML navigation or SVG anchors
46
46
  if (assetPath.endsWith('.html') || assetPath.startsWith('#')) continue;
47
47
 
48
- // CEK 2: Apakah filenya benar-benar ada secara fisik?
49
- // Karena path kita harusnya relatif (misal: assets/file.css),
50
- // kita gabungkan dengan root folder dist/
48
+ // CHECK 2: Does the file physically exist?
49
+ // Since our paths must be relative (e.g., assets/file.css),
50
+ // we join them with the root dist/ folder
51
51
  const physicalPath = path.join(distDir, assetPath);
52
52
  if (!fs.existsSync(physicalPath)) {
53
- console.log(` ❌ ERROR FILE HILANG: File tidak ditemukan di -> "${assetPath}"`);
53
+ console.log(` ❌ MISSING FILE ERROR: File not found at -> "${assetPath}"`);
54
54
  hasError = true;
55
55
  totalErrors++;
56
56
  }
57
57
  }
58
- console.log(` ✅ ${filename} selesai diperiksa.`);
58
+ console.log(` ✅ ${filename} verification complete.`);
59
59
  });
60
60
 
61
- // Verifikasi isi folder dist/assets/
61
+ // Verify contents of dist/assets/ folder
62
62
  const assetsDir = path.join(distDir, 'assets');
63
63
  if (fs.existsSync(assetsDir)) {
64
- console.log('\n📁 Memeriksa file JS di folder dist/assets/...');
64
+ console.log('\n📁 Verifying JS files in dist/assets/...');
65
65
  const jsFiles = fs.readdirSync(assetsDir).filter(f => f.endsWith('.js'));
66
66
 
67
67
  jsFiles.forEach(f => {
68
68
  const content = fs.readFileSync(path.join(assetsDir, f), 'utf8');
69
69
  if (content.includes('return"/"+e') || content.includes('return "/" + e')) {
70
- console.log(` ❌ ERROR VITE PRELOAD: Ditemukan path absolut di file JS -> "${f}"`);
70
+ console.log(` ❌ VITE PRELOAD ERROR: Absolute dynamic path found in JS file -> "${f}"`);
71
71
  totalErrors++;
72
72
  }
73
73
  });
74
- console.log(' ✅ Verifikasi file JS di dist/assets/ selesai.');
74
+ console.log(' ✅ JS file verification in dist/assets/ complete.');
75
75
  }
76
76
 
77
77
  console.log('\n------------------------------------');
78
78
  if (totalErrors === 0) {
79
- console.log('🎉 VERIFIKASI SUKSES! Semua path relatif murni dan file fisik terdeteksi.');
80
- console.log('Bungkusan OTA ini 100% AMAN untuk dikirim.\n');
79
+ console.log('🎉 VERIFICATION SUCCESS! All paths are purely relative and physical files detected.');
80
+ console.log('This OTA bundle is 100% SAFE to deploy.\n');
81
81
  } else {
82
- console.log(`💥 VERIFIKASI GAGAL! Ditemukan ${totalErrors} error pada struktur path atau file.`);
83
- console.log('💡 WAJIB PERBAIKI sebelum mengirim OTA untuk menghindari blank screen di HP user!\n');
82
+ console.log(`💥 VERIFICATION FAILED! Found ${totalErrors} error(s) in path structure or files.`);
83
+ console.log('💡 MUST FIX before deploying OTA to avoid blank screens on users\' devices!\n');
84
84
  process.exit(1);
85
85
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ota-manager",
3
- "version": "1.0.14",
3
+ "version": "1.0.16",
4
4
  "description": "Multi-provider OTA update manager for Astro and static web projects.",
5
5
  "type": "module",
6
6
  "main": "index.js",