react-native-3rddigital-appupdate 1.0.7 → 1.0.8
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.
|
@@ -7,15 +7,16 @@ import DeviceInfo from 'react-native-device-info';
|
|
|
7
7
|
import hotUpdate from 'react-native-ota-hot-update';
|
|
8
8
|
import { AppAlertDialog } from "./AppAlertDialog.js";
|
|
9
9
|
import { AppLoader } from "./AppLoader.js";
|
|
10
|
-
const API_URL = 'https://dev.3rddigital.com/appupdate-api/api/';
|
|
11
10
|
export const checkOTAUpdate = async ({
|
|
12
11
|
key,
|
|
13
12
|
iosPackage,
|
|
14
13
|
androidPackage,
|
|
15
14
|
loaderOptions,
|
|
16
|
-
dialogOptions
|
|
15
|
+
dialogOptions,
|
|
16
|
+
baseUrl
|
|
17
17
|
}) => {
|
|
18
18
|
try {
|
|
19
|
+
const API_URL = baseUrl;
|
|
19
20
|
const response = await axios.get(`${API_URL}projects/get-bundle?key=${key}&iosPackage=${iosPackage}&androidPackage=${androidPackage}`);
|
|
20
21
|
const currentVersion = await hotUpdate.getCurrentVersion();
|
|
21
22
|
const data = Platform.OS === 'android' ? response?.data?.android : response?.data?.ios;
|
|
@@ -25,7 +26,7 @@ export const checkOTAUpdate = async ({
|
|
|
25
26
|
const bundleId = data?.bundleId ?? '';
|
|
26
27
|
const currentAppVersion = DeviceInfo.getVersion();
|
|
27
28
|
const bundleAppVersion = data?.appVersion ?? currentAppVersion;
|
|
28
|
-
if (version <= currentVersion || currentAppVersion
|
|
29
|
+
if (version <= currentVersion || currentAppVersion !== bundleAppVersion) {
|
|
29
30
|
return;
|
|
30
31
|
}
|
|
31
32
|
const downloadAndReport = () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["axios","Platform","ReactNativeBlobUtil","DeviceInfo","hotUpdate","AppAlertDialog","AppLoader","
|
|
1
|
+
{"version":3,"names":["axios","Platform","ReactNativeBlobUtil","DeviceInfo","hotUpdate","AppAlertDialog","AppLoader","checkOTAUpdate","key","iosPackage","androidPackage","loaderOptions","dialogOptions","baseUrl","API_URL","response","get","currentVersion","getCurrentVersion","data","OS","android","ios","version","forceUpdate","url","bundleId","currentAppVersion","getVersion","bundleAppVersion","appVersion","downloadAndReport","show","downloadBundleUri","progress","received","total","showProgress","percentage","Number","toFixed","updateProgress","updateSuccess","post","status","headers","finally","hide","updateFail","error","JSON","stringify","deviceInfo","model","getModel","brand","getBrand","systemName","getSystemName","systemVersion","getSystemVersion","restartAfterInstall","restartDelay","showMessage","title","message","confirmText","cancelText","onConfirm","onCancel","err","console","warn"],"sourceRoot":"../../src","sources":["checkOTAUpdate.ts"],"mappings":";;AAAA,OAAOA,KAAK,MAAM,OAAO;AACzB,SAASC,QAAQ,QAAQ,cAAc;AACvC,OAAOC,mBAAmB,MAAM,wBAAwB;AACxD,OAAOC,UAAU,MAAM,0BAA0B;AACjD,OAAOC,SAAS,MAAM,6BAA6B;AACnD,SAASC,cAAc,QAA4B,qBAAkB;AACrE,SAASC,SAAS,QAA4B,gBAAa;AAW3D,OAAO,MAAMC,cAAc,GAAG,MAAAA,CAAO;EACnCC,GAAG;EACHC,UAAU;EACVC,cAAc;EACdC,aAAa;EACbC,aAAa;EACbC;AACc,CAAC,KAAK;EACpB,IAAI;IACF,MAAMC,OAAO,GAAGD,OAAO;IACvB,MAAME,QAAQ,GAAG,MAAMf,KAAK,CAACgB,GAAG,CAC9B,GAAGF,OAAO,2BAA2BN,GAAG,eAAeC,UAAU,mBAAmBC,cAAc,EACpG,CAAC;IAED,MAAMO,cAAc,GAAG,MAAMb,SAAS,CAACc,iBAAiB,CAAC,CAAC;IAC1D,MAAMC,IAAI,GACRlB,QAAQ,CAACmB,EAAE,KAAK,SAAS,GAAGL,QAAQ,EAAEI,IAAI,EAAEE,OAAO,GAAGN,QAAQ,EAAEI,IAAI,EAAEG,GAAG;IAC3E,MAAMC,OAAO,GAAGJ,IAAI,EAAEI,OAAO,IAAI,CAAC;IAClC,MAAMC,WAAW,GAAGL,IAAI,EAAEK,WAAW,IAAI,KAAK;IAC9C,MAAMC,GAAG,GAAGN,IAAI,EAAEM,GAAG,IAAI,EAAE;IAC3B,MAAMC,QAAQ,GAAGP,IAAI,EAAEO,QAAQ,IAAI,EAAE;IACrC,MAAMC,iBAAiB,GAAGxB,UAAU,CAACyB,UAAU,CAAC,CAAC;IACjD,MAAMC,gBAAgB,GAAGV,IAAI,EAAEW,UAAU,IAAIH,iBAAiB;IAE9D,IAAIJ,OAAO,IAAIN,cAAc,IAAIU,iBAAiB,KAAKE,gBAAgB,EAAE;MACvE;IACF;IAEA,MAAME,iBAAiB,GAAGA,CAAA,KAAM;MAC9BzB,SAAS,CAAC0B,IAAI,CAACrB,aAAa,CAAC;MAC7BP,SAAS,CAAC6B,iBAAiB,CAAC/B,mBAAmB,EAAEuB,GAAG,EAAEF,OAAO,EAAE;QAC7DW,QAAQ,EAAEA,CAACC,QAAQ,EAAEC,KAAK,KAAK;UAC7B,IAAIzB,aAAa,EAAE0B,YAAY,EAAE;YAC/B,MAAMC,UAAU,GAAG,CAChBC,MAAM,CAACJ,QAAQ,CAAC,GAAGI,MAAM,CAACH,KAAK,CAAC,GACjC,GAAG,EACHI,OAAO,CAAC,CAAC,CAAC;YACZlC,SAAS,CAACmC,cAAc,CAACF,MAAM,CAACD,UAAU,CAAC,CAAC;UAC9C;QACF,CAAC;QACDI,aAAa,EAAEA,CAAA,KAAM;UACnB1C,KAAK,CACF2C,IAAI,CACH,GAAG7B,OAAO,WAAWY,QAAQ,QAAQ,EACrC;YAAEkB,MAAM,EAAE;UAAU,CAAC,EACrB;YAAEC,OAAO,EAAE;cAAE,cAAc,EAAE;YAAmB;UAAE,CACpD,CAAC,CACAC,OAAO,CAAC,MAAMxC,SAAS,CAACyC,IAAI,CAAC,CAAC,CAAC;QACpC,CAAC;QACDC,UAAU,EAAGC,KAAK,IAAK;UACrBjD,KAAK,CACF2C,IAAI,CACH,GAAG7B,OAAO,WAAWY,QAAQ,QAAQ,EACrC;YACEkB,MAAM,EAAE,SAAS;YACjBK,KAAK,EAAEC,IAAI,CAACC,SAAS,CAACF,KAAK,CAAC;YAC5BG,UAAU,EAAE;cACVC,KAAK,EAAElD,UAAU,CAACmD,QAAQ,CAAC,CAAC;cAC5BC,KAAK,EAAEpD,UAAU,CAACqD,QAAQ,CAAC,CAAC;cAC5BC,UAAU,EAAEtD,UAAU,CAACuD,aAAa,CAAC,CAAC;cACtCC,aAAa,EAAExD,UAAU,CAACyD,gBAAgB,CAAC;YAC7C;UACF,CAAC,EACD;YAAEf,OAAO,EAAE;cAAE,cAAc,EAAE;YAAmB;UAAE,CACpD,CAAC,CACAC,OAAO,CAAC,MAAMxC,SAAS,CAACyC,IAAI,CAAC,CAAC,CAAC;QACpC,CAAC;QACDc,mBAAmB,EAAE,IAAI;QACzBC,YAAY,EAAE;MAChB,CAAC,CAAC;IACJ,CAAC;IAED,IAAItC,WAAW,EAAE;MACfO,iBAAiB,CAAC,CAAC;IACrB,CAAC,MAAM;MACL1B,cAAc,CAAC0D,WAAW,CAAC;QACzBC,KAAK,EAAE,mBAAmB;QAC1BC,OAAO,EAAE,sCAAsC;QAC/CC,WAAW,EAAE,QAAQ;QACrBC,UAAU,EAAE,QAAQ;QACpBC,SAAS,EAAErC,iBAAiB;QAC5BsC,QAAQ,EAAEA,CAAA,KAAM,CAAC,CAAC;QAClB,GAAGzD;MACL,CAAC,CAAC;IACJ;EACF,CAAC,CAAC,OAAO0D,GAAG,EAAE;IACZC,OAAO,CAACC,IAAI,CAAC,0BAA0B,EAAEF,GAAG,CAAC;EAC/C;AACF,CAAC","ignoreList":[]}
|
|
@@ -6,6 +6,7 @@ export type OTAUpdateProps = {
|
|
|
6
6
|
androidPackage: string;
|
|
7
7
|
loaderOptions?: LoaderOptions;
|
|
8
8
|
dialogOptions?: Omit<DialogOptions, 'onConfirm' | 'onCancel'>;
|
|
9
|
+
baseUrl: string;
|
|
9
10
|
};
|
|
10
|
-
export declare const checkOTAUpdate: ({ key, iosPackage, androidPackage, loaderOptions, dialogOptions, }: OTAUpdateProps) => Promise<void>;
|
|
11
|
+
export declare const checkOTAUpdate: ({ key, iosPackage, androidPackage, loaderOptions, dialogOptions, baseUrl, }: OTAUpdateProps) => Promise<void>;
|
|
11
12
|
//# sourceMappingURL=checkOTAUpdate.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkOTAUpdate.d.ts","sourceRoot":"","sources":["../../../src/checkOTAUpdate.ts"],"names":[],"mappings":"AAKA,OAAO,EAAkB,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtE,OAAO,EAAa,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"checkOTAUpdate.d.ts","sourceRoot":"","sources":["../../../src/checkOTAUpdate.ts"],"names":[],"mappings":"AAKA,OAAO,EAAkB,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtE,OAAO,EAAa,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5D,MAAM,MAAM,cAAc,GAAG;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,aAAa,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE,WAAW,GAAG,UAAU,CAAC,CAAC;IAC9D,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,eAAO,MAAM,cAAc,GAAU,6EAOlC,cAAc,kBAiFhB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-3rddigital-appupdate",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"description": "A React Native library for seamless over-the-air (OTA) updates with version checks, automatic bundle download, and customizable user prompts for iOS and Android.",
|
|
5
5
|
"main": "./lib/module/index.js",
|
|
6
6
|
"types": "./lib/typescript/src/index.d.ts",
|
|
@@ -157,12 +157,15 @@
|
|
|
157
157
|
"version": "0.54.3"
|
|
158
158
|
},
|
|
159
159
|
"dependencies": {
|
|
160
|
+
"@aws-sdk/client-s3": "^3.995.0",
|
|
160
161
|
"@inquirer/prompts": "^7.8.6",
|
|
161
162
|
"axios": "^1.12.2",
|
|
163
|
+
"dotenv": "^17.3.1",
|
|
162
164
|
"form-data": "^4.0.4",
|
|
163
165
|
"react-native-blob-util": "^0.22.2",
|
|
164
166
|
"react-native-device-info": "^14.1.1",
|
|
165
|
-
"react-native-ota-hot-update": "^2.3.4"
|
|
167
|
+
"react-native-ota-hot-update": "^2.3.4",
|
|
168
|
+
"uuid": "^13.0.0"
|
|
166
169
|
},
|
|
167
170
|
"bin": {
|
|
168
171
|
"appupdate": "./scripts/bundle.js"
|
package/scripts/bundle.js
CHANGED
|
@@ -1,12 +1,71 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
require('dotenv').config();
|
|
2
3
|
const { execSync } = require('child_process');
|
|
3
4
|
const path = require('path');
|
|
4
5
|
const fs = require('fs');
|
|
5
6
|
const axios = require('axios');
|
|
6
|
-
const FormData = require('form-data');
|
|
7
7
|
const { input, select, confirm } = require('@inquirer/prompts');
|
|
8
|
+
const { PutObjectCommand, S3Client } = require('@aws-sdk/client-s3');
|
|
9
|
+
const { v4: uuidv4 } = require('uuid');
|
|
8
10
|
|
|
9
|
-
const
|
|
11
|
+
const APPUPDATE_BASE_URL = process.env.APPUPDATE_BASE_URL;
|
|
12
|
+
const APPUPDATE_AWS_REGION = process.env.APPUPDATE_AWS_REGION;
|
|
13
|
+
const APPUPDATE_AWS_ACCESS_KEY_ID = process.env.APPUPDATE_AWS_ACCESS_KEY_ID;
|
|
14
|
+
const APPUPDATE_AWS_SECRET_ACCESS_KEY =
|
|
15
|
+
process.env.APPUPDATE_AWS_SECRET_ACCESS_KEY;
|
|
16
|
+
const APPUPDATE_AWS_BUCKET_NAME = process.env.APPUPDATE_AWS_BUCKET_NAME;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Decrypt helper logic
|
|
20
|
+
*/
|
|
21
|
+
function DecriptEnv(wrappedKey) {
|
|
22
|
+
if (!wrappedKey) return '';
|
|
23
|
+
if (typeof wrappedKey !== 'string')
|
|
24
|
+
throw new TypeError('wrappedKey must be a string');
|
|
25
|
+
if (wrappedKey.length <= 8) throw new Error('wrappedKey too short to unwrap');
|
|
26
|
+
const trimmed = wrappedKey.slice(4, -2);
|
|
27
|
+
const result = trimmed.slice(0, 2) + trimmed.slice(4);
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const s3Client = new S3Client({
|
|
32
|
+
region: DecriptEnv(APPUPDATE_AWS_REGION),
|
|
33
|
+
credentials: {
|
|
34
|
+
accessKeyId: DecriptEnv(APPUPDATE_AWS_ACCESS_KEY_ID),
|
|
35
|
+
secretAccessKey: DecriptEnv(APPUPDATE_AWS_SECRET_ACCESS_KEY),
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Uploads local file to S3
|
|
41
|
+
*/
|
|
42
|
+
async function uploadFileToS3(filePath, bucketName, folder) {
|
|
43
|
+
const fileName = path.basename(filePath);
|
|
44
|
+
const cleanFileName = fileName.replace(/\s+/g, '_');
|
|
45
|
+
const uniqueId = uuidv4();
|
|
46
|
+
const fileKey = `${folder}/${uniqueId}/${cleanFileName}`;
|
|
47
|
+
const fileBuffer = fs.readFileSync(filePath);
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
const command = new PutObjectCommand({
|
|
51
|
+
Bucket: bucketName,
|
|
52
|
+
Key: fileKey,
|
|
53
|
+
Body: fileBuffer,
|
|
54
|
+
ContentType: 'application/zip',
|
|
55
|
+
ACL: 'public-read',
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
await s3Client.send(command);
|
|
59
|
+
|
|
60
|
+
const region = DecriptEnv(APPUPDATE_AWS_REGION);
|
|
61
|
+
const location = `https://${bucketName}.s3.${region}.amazonaws.com/${fileKey}`;
|
|
62
|
+
|
|
63
|
+
return { Location: location, Key: fileKey, Bucket: bucketName };
|
|
64
|
+
} catch (error) {
|
|
65
|
+
console.error('❌ S3 Upload Error:', error);
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
10
69
|
|
|
11
70
|
/**
|
|
12
71
|
* Run a shell command synchronously.
|
|
@@ -23,38 +82,56 @@ function run(command) {
|
|
|
23
82
|
}
|
|
24
83
|
|
|
25
84
|
/**
|
|
26
|
-
*
|
|
85
|
+
* Step 1: Upload to S3
|
|
86
|
+
* Step 2: Register with Backend
|
|
27
87
|
*/
|
|
28
88
|
async function uploadBundle({ filePath, platform, config }) {
|
|
29
|
-
console.log(`📤
|
|
89
|
+
console.log(`📤 Starting upload process for ${platform}...`);
|
|
30
90
|
|
|
31
91
|
if (!fs.existsSync(filePath)) {
|
|
32
92
|
console.error(`❌ File not found: ${filePath}`);
|
|
33
93
|
process.exit(1);
|
|
34
94
|
}
|
|
35
95
|
|
|
36
|
-
const fileStream = fs.createReadStream(filePath);
|
|
37
|
-
const form = new FormData();
|
|
38
|
-
form.append('bundle', fileStream);
|
|
39
|
-
form.append('projectId', config.PROJECT_ID);
|
|
40
|
-
form.append('environment', config.ENVIRONMENT);
|
|
41
|
-
form.append('platform', platform);
|
|
42
|
-
form.append('version', config.VERSION);
|
|
43
|
-
form.append('forceUpdate', String(config.FORCE_UPDATE));
|
|
44
|
-
|
|
45
96
|
try {
|
|
46
|
-
|
|
97
|
+
// 1. Upload to S3
|
|
98
|
+
const s3Result = await uploadFileToS3(
|
|
99
|
+
filePath,
|
|
100
|
+
DecriptEnv(APPUPDATE_AWS_BUCKET_NAME),
|
|
101
|
+
config.ENVIRONMENT === 'development'
|
|
102
|
+
? 'uploads/development'
|
|
103
|
+
: 'uploads/production'
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
console.log(`✅ S3 Upload Complete: ${s3Result.Key}`);
|
|
107
|
+
|
|
108
|
+
// 2. Prepare Payload for Backend
|
|
109
|
+
const stats = fs.statSync(filePath);
|
|
110
|
+
const payload = {
|
|
111
|
+
projectId: config.PROJECT_ID,
|
|
112
|
+
environment: config.ENVIRONMENT,
|
|
113
|
+
platform: platform,
|
|
114
|
+
version: config.VERSION,
|
|
115
|
+
forceUpdate: config.FORCE_UPDATE,
|
|
116
|
+
s3Key: s3Result.Key,
|
|
117
|
+
s3Url: s3Result.Location,
|
|
118
|
+
fileName: path.basename(filePath),
|
|
119
|
+
fileSize: stats.size,
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const res = await axios.post(`${APPUPDATE_BASE_URL}/bundles`, payload, {
|
|
47
123
|
headers: {
|
|
48
|
-
|
|
49
|
-
Authorization: `Bearer ${config.API_TOKEN}`,
|
|
124
|
+
'Content-Type': 'application/json',
|
|
125
|
+
'Authorization': `Bearer ${config.API_TOKEN}`,
|
|
50
126
|
},
|
|
51
127
|
});
|
|
128
|
+
|
|
52
129
|
console.log(
|
|
53
|
-
`✅ ${platform} bundle
|
|
130
|
+
`✅ ${platform} bundle registered! Response:`,
|
|
54
131
|
JSON.stringify(res.data, null, 2)
|
|
55
132
|
);
|
|
56
133
|
} catch (err) {
|
|
57
|
-
console.error(`❌ ${platform} bundle upload failed!`);
|
|
134
|
+
console.error(`❌ ${platform} bundle upload/registration failed!`);
|
|
58
135
|
if (err.response) {
|
|
59
136
|
console.error('Status:', err.response.status);
|
|
60
137
|
console.error('Data:', err.response.data);
|
package/src/checkOTAUpdate.ts
CHANGED
|
@@ -6,14 +6,13 @@ import hotUpdate from 'react-native-ota-hot-update';
|
|
|
6
6
|
import { AppAlertDialog, type DialogOptions } from './AppAlertDialog';
|
|
7
7
|
import { AppLoader, type LoaderOptions } from './AppLoader';
|
|
8
8
|
|
|
9
|
-
const API_URL = 'https://dev.3rddigital.com/appupdate-api/api/';
|
|
10
|
-
|
|
11
9
|
export type OTAUpdateProps = {
|
|
12
10
|
key: string;
|
|
13
11
|
iosPackage: string;
|
|
14
12
|
androidPackage: string;
|
|
15
13
|
loaderOptions?: LoaderOptions;
|
|
16
14
|
dialogOptions?: Omit<DialogOptions, 'onConfirm' | 'onCancel'>;
|
|
15
|
+
baseUrl: string;
|
|
17
16
|
};
|
|
18
17
|
|
|
19
18
|
export const checkOTAUpdate = async ({
|
|
@@ -22,8 +21,10 @@ export const checkOTAUpdate = async ({
|
|
|
22
21
|
androidPackage,
|
|
23
22
|
loaderOptions,
|
|
24
23
|
dialogOptions,
|
|
24
|
+
baseUrl,
|
|
25
25
|
}: OTAUpdateProps) => {
|
|
26
26
|
try {
|
|
27
|
+
const API_URL = baseUrl;
|
|
27
28
|
const response = await axios.get(
|
|
28
29
|
`${API_URL}projects/get-bundle?key=${key}&iosPackage=${iosPackage}&androidPackage=${androidPackage}`
|
|
29
30
|
);
|
|
@@ -38,7 +39,7 @@ export const checkOTAUpdate = async ({
|
|
|
38
39
|
const currentAppVersion = DeviceInfo.getVersion();
|
|
39
40
|
const bundleAppVersion = data?.appVersion ?? currentAppVersion;
|
|
40
41
|
|
|
41
|
-
if (version <= currentVersion || currentAppVersion
|
|
42
|
+
if (version <= currentVersion || currentAppVersion !== bundleAppVersion) {
|
|
42
43
|
return;
|
|
43
44
|
}
|
|
44
45
|
|