@webority-technologies/mobile-core 0.0.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 (102) hide show
  1. package/README.md +15 -0
  2. package/lib/commonjs/api/publicClient.js +80 -0
  3. package/lib/commonjs/api/userClient.js +368 -0
  4. package/lib/commonjs/auth/authStore.js +155 -0
  5. package/lib/commonjs/auth/index.js +44 -0
  6. package/lib/commonjs/auth/jwt.js +88 -0
  7. package/lib/commonjs/config/index.js +65 -0
  8. package/lib/commonjs/formatters/currency.js +69 -0
  9. package/lib/commonjs/formatters/date.js +168 -0
  10. package/lib/commonjs/formatters/index.js +77 -0
  11. package/lib/commonjs/formatters/initials.js +32 -0
  12. package/lib/commonjs/formatters/number.js +88 -0
  13. package/lib/commonjs/formatters/phone.js +67 -0
  14. package/lib/commonjs/index.js +383 -0
  15. package/lib/commonjs/initSDK.js +45 -0
  16. package/lib/commonjs/initUserAuth.js +38 -0
  17. package/lib/commonjs/logger/index.js +137 -0
  18. package/lib/commonjs/network/index.js +25 -0
  19. package/lib/commonjs/network/networkStatus.js +98 -0
  20. package/lib/commonjs/package.json +1 -0
  21. package/lib/commonjs/permissions/index.js +200 -0
  22. package/lib/commonjs/storage/index.js +193 -0
  23. package/lib/commonjs/utils/imageCompression.js +75 -0
  24. package/lib/commonjs/utils/index.js +13 -0
  25. package/lib/commonjs/validators/index.js +193 -0
  26. package/lib/commonjs/versionCheck/index.js +395 -0
  27. package/lib/module/api/publicClient.js +76 -0
  28. package/lib/module/api/userClient.js +360 -0
  29. package/lib/module/auth/authStore.js +148 -0
  30. package/lib/module/auth/index.js +5 -0
  31. package/lib/module/auth/jwt.js +82 -0
  32. package/lib/module/config/index.js +57 -0
  33. package/lib/module/formatters/currency.js +64 -0
  34. package/lib/module/formatters/date.js +160 -0
  35. package/lib/module/formatters/index.js +8 -0
  36. package/lib/module/formatters/initials.js +27 -0
  37. package/lib/module/formatters/number.js +81 -0
  38. package/lib/module/formatters/phone.js +61 -0
  39. package/lib/module/index.js +30 -0
  40. package/lib/module/initSDK.js +40 -0
  41. package/lib/module/initUserAuth.js +34 -0
  42. package/lib/module/logger/index.js +133 -0
  43. package/lib/module/network/index.js +4 -0
  44. package/lib/module/network/networkStatus.js +91 -0
  45. package/lib/module/package.json +1 -0
  46. package/lib/module/permissions/index.js +197 -0
  47. package/lib/module/storage/index.js +189 -0
  48. package/lib/module/utils/imageCompression.js +69 -0
  49. package/lib/module/utils/index.js +4 -0
  50. package/lib/module/validators/index.js +171 -0
  51. package/lib/module/versionCheck/index.js +390 -0
  52. package/lib/typescript/commonjs/api/publicClient.d.ts +11 -0
  53. package/lib/typescript/commonjs/api/userClient.d.ts +49 -0
  54. package/lib/typescript/commonjs/auth/authStore.d.ts +43 -0
  55. package/lib/typescript/commonjs/auth/index.d.ts +5 -0
  56. package/lib/typescript/commonjs/auth/jwt.d.ts +31 -0
  57. package/lib/typescript/commonjs/config/index.d.ts +49 -0
  58. package/lib/typescript/commonjs/formatters/currency.d.ts +24 -0
  59. package/lib/typescript/commonjs/formatters/date.d.ts +22 -0
  60. package/lib/typescript/commonjs/formatters/index.d.ts +8 -0
  61. package/lib/typescript/commonjs/formatters/initials.d.ts +11 -0
  62. package/lib/typescript/commonjs/formatters/number.d.ts +15 -0
  63. package/lib/typescript/commonjs/formatters/phone.d.ts +13 -0
  64. package/lib/typescript/commonjs/index.d.ts +30 -0
  65. package/lib/typescript/commonjs/initSDK.d.ts +40 -0
  66. package/lib/typescript/commonjs/initUserAuth.d.ts +22 -0
  67. package/lib/typescript/commonjs/logger/index.d.ts +42 -0
  68. package/lib/typescript/commonjs/network/index.d.ts +3 -0
  69. package/lib/typescript/commonjs/network/networkStatus.d.ts +27 -0
  70. package/lib/typescript/commonjs/package.json +1 -0
  71. package/lib/typescript/commonjs/permissions/index.d.ts +20 -0
  72. package/lib/typescript/commonjs/storage/index.d.ts +42 -0
  73. package/lib/typescript/commonjs/utils/imageCompression.d.ts +31 -0
  74. package/lib/typescript/commonjs/utils/index.d.ts +3 -0
  75. package/lib/typescript/commonjs/validators/index.d.ts +46 -0
  76. package/lib/typescript/commonjs/versionCheck/index.d.ts +80 -0
  77. package/lib/typescript/module/api/publicClient.d.ts +11 -0
  78. package/lib/typescript/module/api/userClient.d.ts +49 -0
  79. package/lib/typescript/module/auth/authStore.d.ts +43 -0
  80. package/lib/typescript/module/auth/index.d.ts +5 -0
  81. package/lib/typescript/module/auth/jwt.d.ts +31 -0
  82. package/lib/typescript/module/config/index.d.ts +49 -0
  83. package/lib/typescript/module/formatters/currency.d.ts +24 -0
  84. package/lib/typescript/module/formatters/date.d.ts +22 -0
  85. package/lib/typescript/module/formatters/index.d.ts +8 -0
  86. package/lib/typescript/module/formatters/initials.d.ts +11 -0
  87. package/lib/typescript/module/formatters/number.d.ts +15 -0
  88. package/lib/typescript/module/formatters/phone.d.ts +13 -0
  89. package/lib/typescript/module/index.d.ts +30 -0
  90. package/lib/typescript/module/initSDK.d.ts +40 -0
  91. package/lib/typescript/module/initUserAuth.d.ts +22 -0
  92. package/lib/typescript/module/logger/index.d.ts +42 -0
  93. package/lib/typescript/module/network/index.d.ts +3 -0
  94. package/lib/typescript/module/network/networkStatus.d.ts +27 -0
  95. package/lib/typescript/module/package.json +1 -0
  96. package/lib/typescript/module/permissions/index.d.ts +20 -0
  97. package/lib/typescript/module/storage/index.d.ts +42 -0
  98. package/lib/typescript/module/utils/imageCompression.d.ts +31 -0
  99. package/lib/typescript/module/utils/index.d.ts +3 -0
  100. package/lib/typescript/module/validators/index.d.ts +46 -0
  101. package/lib/typescript/module/versionCheck/index.d.ts +80 -0
  102. package/package.json +112 -0
@@ -0,0 +1,193 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.minLength = exports.maxLength = exports.isUrl = exports.isStrongPassword = exports.isPhone = exports.isPan = exports.isNumeric = exports.isNonEmpty = exports.isInteger = exports.isIndianPincode = exports.isIndianMobile = exports.isIfsc = exports.isHexColor = exports.isGstin = exports.isEmail = exports.isBetween = exports.isAlphanumeric = exports.isAadhaar = void 0;
7
+ /**
8
+ * Generic validators returning `boolean`. All accept `null`/`undefined` safely.
9
+ *
10
+ * Tradeoff: regexes are pragmatic, not RFC-strict. They reject the things real users
11
+ * typo and accept the long tail of legitimate inputs. For RFC-grade validation use
12
+ * a dedicated library at the boundary.
13
+ */
14
+
15
+ const RE_EMAIL = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
16
+ const RE_INDIAN_MOBILE = /^[6-9]\d{9}$/;
17
+ const RE_NUMERIC = /^-?\d+(?:\.\d+)?$/;
18
+ const RE_INTEGER = /^-?\d+$/;
19
+ const RE_ALPHANUMERIC = /^[a-zA-Z0-9]+$/;
20
+ const RE_PINCODE_IN = /^[1-9]\d{5}$/;
21
+ const RE_PAN = /^[A-Z]{5}\d{4}[A-Z]$/;
22
+ const RE_GSTIN = /^\d{2}[A-Z]{5}\d{4}[A-Z][1-9A-Z]Z[0-9A-Z]$/;
23
+ const RE_AADHAAR = /^\d{12}$/;
24
+ const RE_IFSC = /^[A-Z]{4}0[A-Z0-9]{6}$/;
25
+ const RE_HEX_COLOR = /^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
26
+ const asString = v => {
27
+ if (typeof v === 'string') {
28
+ return v.trim();
29
+ }
30
+ return null;
31
+ };
32
+ const isNonEmpty = value => {
33
+ const s = asString(value);
34
+ return !!s && s.length > 0;
35
+ };
36
+ exports.isNonEmpty = isNonEmpty;
37
+ const isEmail = value => {
38
+ const s = asString(value);
39
+ return !!s && RE_EMAIL.test(s);
40
+ };
41
+
42
+ /**
43
+ * Validate an Indian mobile number. Accepts:
44
+ * - 10-digit number starting with 6-9
45
+ * - Optional `+91` or `91` country code prefix
46
+ */
47
+ exports.isEmail = isEmail;
48
+ const isIndianMobile = value => {
49
+ const s = asString(value);
50
+ if (!s) {
51
+ return false;
52
+ }
53
+ const digits = s.replace(/\D/g, '');
54
+ const tail = digits.startsWith('91') && digits.length === 12 ? digits.slice(2) : digits;
55
+ return RE_INDIAN_MOBILE.test(tail);
56
+ };
57
+
58
+ /**
59
+ * Generic phone validator: 7–15 digits, optional `+` prefix.
60
+ * Use `isIndianMobile` when you specifically need an Indian mobile number.
61
+ */
62
+ exports.isIndianMobile = isIndianMobile;
63
+ const isPhone = value => {
64
+ const s = asString(value);
65
+ if (!s) {
66
+ return false;
67
+ }
68
+ const digits = s.replace(/[^\d+]/g, '').replace(/^\+/, '');
69
+ return digits.length >= 7 && digits.length <= 15 && /^\d+$/.test(digits);
70
+ };
71
+ exports.isPhone = isPhone;
72
+ const isUrl = value => {
73
+ const s = asString(value);
74
+ if (!s) {
75
+ return false;
76
+ }
77
+ try {
78
+ // URL constructor is available on Hermes & JSC.
79
+
80
+ new URL(s);
81
+ return /^https?:\/\//i.test(s) || /^[a-z][a-z0-9+\-.]*:\/\//i.test(s);
82
+ } catch {
83
+ return false;
84
+ }
85
+ };
86
+ exports.isUrl = isUrl;
87
+ const isNumeric = value => {
88
+ if (typeof value === 'number') {
89
+ return Number.isFinite(value);
90
+ }
91
+ const s = asString(value);
92
+ return !!s && RE_NUMERIC.test(s);
93
+ };
94
+ exports.isNumeric = isNumeric;
95
+ const isInteger = value => {
96
+ if (typeof value === 'number') {
97
+ return Number.isInteger(value);
98
+ }
99
+ const s = asString(value);
100
+ return !!s && RE_INTEGER.test(s);
101
+ };
102
+ exports.isInteger = isInteger;
103
+ const isAlphanumeric = value => {
104
+ const s = asString(value);
105
+ return !!s && RE_ALPHANUMERIC.test(s);
106
+ };
107
+ exports.isAlphanumeric = isAlphanumeric;
108
+ /**
109
+ * Common password complexity check. Defaults to 8+ chars,
110
+ * one uppercase, one lowercase, one digit.
111
+ */
112
+ const isStrongPassword = (value, rules = {}) => {
113
+ if (typeof value !== 'string') {
114
+ return false;
115
+ }
116
+ const {
117
+ minLength = 8,
118
+ requireUppercase = true,
119
+ requireLowercase = true,
120
+ requireNumber = true,
121
+ requireSymbol = false
122
+ } = rules;
123
+ if (value.length < minLength) {
124
+ return false;
125
+ }
126
+ if (requireUppercase && !/[A-Z]/.test(value)) {
127
+ return false;
128
+ }
129
+ if (requireLowercase && !/[a-z]/.test(value)) {
130
+ return false;
131
+ }
132
+ if (requireNumber && !/\d/.test(value)) {
133
+ return false;
134
+ }
135
+ if (requireSymbol && !/[^A-Za-z0-9]/.test(value)) {
136
+ return false;
137
+ }
138
+ return true;
139
+ };
140
+ exports.isStrongPassword = isStrongPassword;
141
+ const isIndianPincode = value => {
142
+ const s = asString(value);
143
+ return !!s && RE_PINCODE_IN.test(s);
144
+ };
145
+ exports.isIndianPincode = isIndianPincode;
146
+ const isPan = value => {
147
+ const s = asString(value);
148
+ return !!s && RE_PAN.test(s.toUpperCase());
149
+ };
150
+ exports.isPan = isPan;
151
+ const isGstin = value => {
152
+ const s = asString(value);
153
+ return !!s && RE_GSTIN.test(s.toUpperCase());
154
+ };
155
+ exports.isGstin = isGstin;
156
+ const isAadhaar = value => {
157
+ const s = asString(value);
158
+ if (!s) {
159
+ return false;
160
+ }
161
+ const digits = s.replace(/\s/g, '');
162
+ return RE_AADHAAR.test(digits);
163
+ };
164
+ exports.isAadhaar = isAadhaar;
165
+ const isIfsc = value => {
166
+ const s = asString(value);
167
+ return !!s && RE_IFSC.test(s.toUpperCase());
168
+ };
169
+ exports.isIfsc = isIfsc;
170
+ const isHexColor = value => {
171
+ const s = asString(value);
172
+ return !!s && RE_HEX_COLOR.test(s);
173
+ };
174
+ exports.isHexColor = isHexColor;
175
+ const isBetween = (value, min, max, inclusive = true) => {
176
+ const n = typeof value === 'number' ? value : Number(asString(value));
177
+ if (!Number.isFinite(n)) {
178
+ return false;
179
+ }
180
+ return inclusive ? n >= min && n <= max : n > min && n < max;
181
+ };
182
+ exports.isBetween = isBetween;
183
+ const minLength = (value, length) => {
184
+ const s = asString(value);
185
+ return !!s && s.length >= length;
186
+ };
187
+ exports.minLength = minLength;
188
+ const maxLength = (value, length) => {
189
+ const s = asString(value);
190
+ return s == null ? true : s.length <= length;
191
+ };
192
+ exports.maxLength = maxLength;
193
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,395 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useVersionCheck = exports.setDeviceInfoImplementation = exports.default = exports.VersionCheck = void 0;
7
+ var _react = require("react");
8
+ var _index = require("../config/index.js");
9
+ var _index2 = require("../logger/index.js");
10
+ // Type-only — erased at compile time; react-native stays lazily required below.
11
+
12
+ /**
13
+ * Minimal device-info shape we depend on.
14
+ *
15
+ * This is a LAST RESORT, not the primary path. `Platform.OS` already gives the
16
+ * platform, and every Webority app carries its own store id and version in
17
+ * `appsettings.Compiled.json` — so `setConfig({ appId, appVersion })` covers
18
+ * both remaining values without a native module. The injector below exists for
19
+ * apps that would rather hand us a `react-native-device-info` instance than
20
+ * wire two config keys.
21
+ */
22
+
23
+ let deviceInfo = null;
24
+
25
+ /**
26
+ * Supply the app identity from a native module instead of config.
27
+ * Prefer `setConfig({ appId, appVersion })` — it needs no native dependency.
28
+ * Pass `null` to clear.
29
+ */
30
+ const setDeviceInfoImplementation = impl => {
31
+ deviceInfo = impl;
32
+ };
33
+ exports.setDeviceInfoImplementation = setDeviceInfoImplementation;
34
+ const missing = (what, configKey) => {
35
+ const err = new Error(`[VersionCheck] the app's ${what} is not available. Call ` + `setConfig({ ${configKey}: '...' }) — every Webority app already has this value in ` + 'appsettings.Compiled.json — or setDeviceInfoImplementation() with a native provider.');
36
+ _index2.Logger.error(err.message);
37
+ return err;
38
+ };
39
+
40
+ // Platform comes from React Native itself; there has never been a reason to
41
+ // cross a native module boundary for it.
42
+ const getSystemName = () => {
43
+ const {
44
+ Platform
45
+ } = require('react-native');
46
+ return Platform.OS;
47
+ };
48
+ const getBundleId = () => {
49
+ const fromConfig = (0, _index.getConfigValue)('appId');
50
+ if (fromConfig) {
51
+ return fromConfig;
52
+ }
53
+ if (deviceInfo) {
54
+ return deviceInfo.getBundleId();
55
+ }
56
+ throw missing('store identifier', 'appId');
57
+ };
58
+ const getVersion = () => {
59
+ const fromConfig = (0, _index.getConfigValue)('appVersion');
60
+ if (fromConfig) {
61
+ return fromConfig;
62
+ }
63
+ if (deviceInfo) {
64
+ return deviceInfo.getVersion();
65
+ }
66
+ throw missing('version', 'appVersion');
67
+ };
68
+
69
+ // Constants
70
+ const MAX_RETRIES = 3;
71
+ const RETRY_DELAY = 3000; // 3 seconds
72
+
73
+ const getCountry = () => (0, _index.getConfigValue)('country', 'in').toLowerCase();
74
+ // Utility function to parse and coerce version to a valid format
75
+ const parseVersion = version => {
76
+ _index2.Logger.info(`Parsing version: ${version}`);
77
+ const coercedVersion = version.replace(/[^0-9.]/g, '');
78
+ const versionParts = coercedVersion.split('.').map(Number);
79
+ return {
80
+ major: versionParts[0] || 0,
81
+ minor: versionParts[1] || 0,
82
+ patch: versionParts[2] || 0,
83
+ prerelease: version.includes('-') ? version.split('-')[1] ?? '' : ''
84
+ };
85
+ };
86
+
87
+ // Utility function to compare two versions loosely
88
+ const diffLoose = (version1, version2) => {
89
+ _index2.Logger.info(`Comparing versions: ${version1} and ${version2}`);
90
+ if (version1 === version2) {
91
+ return null;
92
+ }
93
+ const v1 = parseVersion(version1);
94
+ const v2 = parseVersion(version2);
95
+ if (v1.major < v2.major) {
96
+ return 'major';
97
+ }
98
+ if (v1.major > v2.major) {
99
+ return null;
100
+ }
101
+ if (v1.minor < v2.minor) {
102
+ return 'minor';
103
+ }
104
+ if (v1.minor > v2.minor) {
105
+ return null;
106
+ }
107
+ if (v1.patch < v2.patch) {
108
+ return 'patch';
109
+ }
110
+ if (v1.patch > v2.patch) {
111
+ return null;
112
+ }
113
+ if (v1.prerelease && !v2.prerelease) {
114
+ return 'prerelease';
115
+ }
116
+ if (!v1.prerelease && v2.prerelease) {
117
+ return null;
118
+ }
119
+ if (v1.prerelease < v2.prerelease) {
120
+ return 'prerelease';
121
+ }
122
+ if (v1.prerelease > v2.prerelease) {
123
+ return null;
124
+ }
125
+ return null;
126
+ };
127
+
128
+ // Function to compare current version with the latest version
129
+ const versionCompare = (currentVersion, latestVersion) => {
130
+ _index2.Logger.info(`Comparing current version: ${currentVersion} with latest version: ${latestVersion}`);
131
+ if (!latestVersion) {
132
+ return {
133
+ needsUpdate: false,
134
+ updateType: null,
135
+ notice: 'Error: could not get latest version'
136
+ };
137
+ }
138
+ try {
139
+ const updateType = diffLoose(currentVersion, latestVersion);
140
+ return {
141
+ needsUpdate: !!updateType,
142
+ updateType
143
+ };
144
+ } catch (e) {
145
+ const message = e instanceof Error ? e.message : String(e);
146
+ _index2.Logger.error(`Error comparing versions: ${message}`);
147
+ const needsUpdate = currentVersion !== latestVersion && latestVersion > currentVersion;
148
+ const updateType = needsUpdate ? 'minor' : null;
149
+ return {
150
+ needsUpdate,
151
+ updateType,
152
+ notice: message.replace(/^Invalid Version:/, 'Not a valid version:')
153
+ };
154
+ }
155
+ };
156
+
157
+ // Function to fetch version details from Google Play Store
158
+ const fetchAndroidVersion = async url => {
159
+ _index2.Logger.info(`Fetching Android version from URL: ${url}`);
160
+ let response;
161
+ try {
162
+ response = await fetch(url, {
163
+ headers: {
164
+ 'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.96 Mobile Safari/537.36',
165
+ 'sec-fetch-site': 'same-origin'
166
+ }
167
+ });
168
+ } catch (error) {
169
+ const message = error instanceof Error ? error.message : String(error);
170
+ _index2.Logger.error(`Error fetching data from Google Play Store: ${message}`);
171
+ throw new Error('Error fetching data from Google Play Store.');
172
+ }
173
+ if (!response.ok) {
174
+ if (response.status === 404) {
175
+ _index2.Logger.error('App with app ID not found in Google Play.');
176
+ throw new Error(`App with app ID not found in Google Play.`);
177
+ }
178
+ _index2.Logger.error(`Error fetching data: ${response.statusText}`);
179
+ throw new Error(response.statusText);
180
+ }
181
+ const text = await response.text();
182
+
183
+ // Primary regex pattern for current Play Store format
184
+ let versionMatch = text.match(/\[\[\[['"]((\d+\.)+\d+)['"]\]\],/);
185
+
186
+ // Alternate patterns as fallbacks
187
+ if (!versionMatch) {
188
+ // Fallback 1: Look for version in "current version" text
189
+ versionMatch = text.match(/Current Version[^\d]+((\d+\.)+\d+)/i);
190
+ }
191
+ if (!versionMatch) {
192
+ // Fallback 2: Look for itemprop="softwareVersion"
193
+ versionMatch = text.match(/itemprop="softwareVersion"[^>]*>((\d+\.)+\d+)</i);
194
+ }
195
+ if (!versionMatch) {
196
+ // Fallback 3: Try a more generic pattern for version numbers
197
+ const allVersions = text.match(/(\d+\.\d+(\.\d+)?)/g);
198
+ // If we found multiple version-like strings, use the first one
199
+ versionMatch = allVersions && allVersions.length > 0 ? [null, allVersions[0]] : null;
200
+ }
201
+ const version = versionMatch ? versionMatch[1] ?? null : null;
202
+ if (!version) {
203
+ _index2.Logger.warn('Could not extract version from Play Store. Using fallback method.');
204
+ }
205
+ const notesMatch = text.match(/<div itemprop="description">(.*?)<\/div>/);
206
+ const notes = notesMatch ? notesMatch[1] ?? '' : '';
207
+ return {
208
+ version,
209
+ releasedAt: new Date().toISOString(),
210
+ notes,
211
+ url,
212
+ lastChecked: new Date().toISOString()
213
+ };
214
+ };
215
+ // Function to fetch version details from Apple App Store
216
+ const fetchIosVersion = async url => {
217
+ _index2.Logger.info(`Fetching iOS version from URL: ${url}`);
218
+ let response;
219
+ try {
220
+ response = await fetch(url);
221
+ } catch {
222
+ _index2.Logger.error('Error connecting to iTunes.');
223
+ throw new Error('Error connecting to iTunes.');
224
+ }
225
+ const data = await response.json();
226
+ if (!data || !('results' in data)) {
227
+ _index2.Logger.error('Unknown error connecting to iTunes.');
228
+ throw new Error('Unknown error connecting to iTunes.');
229
+ }
230
+ if (!data.results.length) {
231
+ _index2.Logger.error('App for this bundle ID not found.');
232
+ throw new Error('App for this bundle ID not found.');
233
+ }
234
+ const result = data.results[0];
235
+ return {
236
+ version: result.version || null,
237
+ released: result.currentVersionReleaseDate || result.releaseDate || null,
238
+ notes: result.releaseNotes || '',
239
+ url: result.trackViewUrl || result.artistViewUrl || result.sellerUrl || null,
240
+ country: getCountry(),
241
+ lastChecked: new Date().toISOString()
242
+ };
243
+ };
244
+
245
+ // Function to lookup version based on platform
246
+ const lookupVersion = async (platform, identifier) => {
247
+ _index2.Logger.info(`Looking up version for platform: ${platform}, identifier: ${identifier}`);
248
+ const country = getCountry();
249
+ const url = platform === 'ios' ? `https://itunes.apple.com/lookup?bundleId=${identifier}&country=${country}&_=${new Date().valueOf()}` : `https://play.google.com/store/apps/details?id=${identifier}&hl=${country}`;
250
+ return platform === 'ios' ? fetchIosVersion(url) : fetchAndroidVersion(url);
251
+ };
252
+
253
+ /**
254
+ * Check for new version with retry logic
255
+ */
256
+ const checkForUpdates = async () => {
257
+ const platform = getSystemName().toLowerCase();
258
+ const identifier = getBundleId();
259
+ const currentVersion = getVersion();
260
+
261
+ // Implement retry mechanism
262
+ let retryCount = 0;
263
+ let lastError = null;
264
+ while (retryCount <= MAX_RETRIES) {
265
+ try {
266
+ _index2.Logger.info(`Checking if new version is available (attempt ${retryCount + 1}/${MAX_RETRIES + 1})`);
267
+ _index2.Logger.info(`Platform: ${platform}, identifier: ${identifier}, current version: ${currentVersion}`);
268
+ const latestVersionInfo = await lookupVersion(platform, identifier);
269
+ const comparison = versionCompare(currentVersion, latestVersionInfo.version);
270
+ return {
271
+ isNewVersionAvailable: comparison.needsUpdate,
272
+ updateType: comparison.updateType,
273
+ url: latestVersionInfo.url
274
+ };
275
+ } catch (error) {
276
+ lastError = error;
277
+ const message = error instanceof Error ? error.message : String(error);
278
+ _index2.Logger.error(`Error checking version (attempt ${retryCount + 1}/${MAX_RETRIES + 1}): ${message}`);
279
+
280
+ // If we've reached max retries, throw the last error
281
+ if (retryCount === MAX_RETRIES) {
282
+ throw error;
283
+ }
284
+
285
+ // Otherwise, wait and retry
286
+ retryCount++;
287
+ _index2.Logger.info(`Retrying version check in ${RETRY_DELAY}ms...`);
288
+ await new Promise(resolve => setTimeout(resolve, RETRY_DELAY));
289
+ }
290
+ }
291
+
292
+ // This should never be reached due to the throw above, but just in case
293
+ throw lastError instanceof Error ? lastError : new Error('Failed to check for updates after multiple attempts');
294
+ };
295
+
296
+ /**
297
+ * Get fallback store URL based on platform
298
+ */
299
+ const getFallbackStoreUrl = () => {
300
+ const platform = getSystemName().toLowerCase();
301
+ const bundleId = getBundleId();
302
+ const country = getCountry();
303
+ return platform === 'ios' ? `https://apps.apple.com/${country}/app/${bundleId}` : `https://play.google.com/store/apps/details?id=${bundleId}&hl=${country}`;
304
+ };
305
+ // Version check functionality
306
+ const VersionCheck = exports.VersionCheck = {
307
+ isNewVersionAvailable: async () => {
308
+ return checkForUpdates();
309
+ },
310
+ openUpdateUrl: async url => {
311
+ const {
312
+ Linking
313
+ } = require('react-native');
314
+ try {
315
+ if (url) {
316
+ _index2.Logger.info(`Opening app store URL: ${url}`);
317
+ await Linking.openURL(url);
318
+ } else {
319
+ const fallbackUrl = getFallbackStoreUrl();
320
+ _index2.Logger.info(`Opening fallback store URL: ${fallbackUrl}`);
321
+ await Linking.openURL(fallbackUrl);
322
+ }
323
+ return true;
324
+ } catch (error) {
325
+ const message = error instanceof Error ? error.message : String(error);
326
+ _index2.Logger.error(`Failed to open store URL: ${message}`);
327
+
328
+ // Try with fallback URL if the original failed
329
+ try {
330
+ if (url) {
331
+ // Only try fallback if we were using a specific URL before
332
+ const fallbackUrl = getFallbackStoreUrl();
333
+ _index2.Logger.info(`Trying fallback store URL: ${fallbackUrl}`);
334
+ await Linking.openURL(fallbackUrl);
335
+ return true;
336
+ }
337
+ } catch (fallbackError) {
338
+ const fbMessage = fallbackError instanceof Error ? fallbackError.message : String(fallbackError);
339
+ _index2.Logger.error(`Failed to open fallback URL: ${fbMessage}`);
340
+ }
341
+ return false;
342
+ }
343
+ },
344
+ getFallbackStoreUrl
345
+ };
346
+
347
+ /**
348
+ * Custom hook to check for required app updates.
349
+ *
350
+ * @param isAppReady - Whether the app is ready to perform the check
351
+ * @param environment - The app environment (defaults to the one in config)
352
+ */
353
+ const useVersionCheck = (isAppReady, environment = (0, _index.getConfigValue)('environment', 'Development')) => {
354
+ const [updateInfo, setUpdateInfo] = (0, _react.useState)({
355
+ isUpdateRequired: false,
356
+ updateUrl: null
357
+ });
358
+ (0, _react.useEffect)(() => {
359
+ let isMounted = true;
360
+ const checkVersion = async () => {
361
+ try {
362
+ // All retry logic is handled in the VersionCheck module
363
+ const {
364
+ isNewVersionAvailable,
365
+ url
366
+ } = await VersionCheck.isNewVersionAvailable();
367
+ if (isNewVersionAvailable && isMounted) {
368
+ _index2.Logger.info('Update required. URL:', url || 'Not available yet');
369
+ setUpdateInfo({
370
+ isUpdateRequired: true,
371
+ updateUrl: url
372
+ });
373
+ } else if (isMounted) {
374
+ _index2.Logger.info('App is up to date');
375
+ }
376
+ } catch (error) {
377
+ _index2.Logger.error('Error checking app version:', error);
378
+ }
379
+ };
380
+
381
+ // Only run version check in Production environment when app is ready
382
+ if (isAppReady && environment === 'Production') {
383
+ void checkVersion();
384
+ }
385
+ return () => {
386
+ isMounted = false;
387
+ };
388
+ }, [isAppReady, environment]);
389
+ return updateInfo;
390
+ };
391
+
392
+ // Export for backward compatibility
393
+ exports.useVersionCheck = useVersionCheck;
394
+ var _default = exports.default = VersionCheck;
395
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+
3
+ import axios from 'axios';
4
+ import axiosRetry from 'axios-retry';
5
+ import { getConfigValue } from "../config/index.js";
6
+ import { Logger } from "../logger/index.js";
7
+
8
+ // Define timeout for requests
9
+ const REQUEST_TIMEOUT = 30000; // 30 seconds
10
+
11
+ /**
12
+ * Public Axios Client
13
+ * - Base URL: Set your public API base URL.
14
+ * - No Authorization header is attached.
15
+ * - Includes timeout configuration and error handling.
16
+ * - Handles specific HTTP status codes.
17
+ */
18
+ const publicClient = axios.create({
19
+ baseURL: getConfigValue('baseUrl') ?? undefined,
20
+ headers: {
21
+ 'Content-Type': 'application/json',
22
+ Accept: 'application/json',
23
+ 'Accept-Encoding': 'gzip, deflate, br'
24
+ },
25
+ timeout: REQUEST_TIMEOUT
26
+ });
27
+
28
+ // Configure axios-retry with modified exponential backoff
29
+ const retryConfig = {
30
+ retries: 3,
31
+ retryDelay: retryCount => retryCount === 0 ? 0 : Math.pow(2, retryCount) * 1000,
32
+ // Immediate retry for the first attempt
33
+ retryCondition: error => {
34
+ // Status-based ONLY, deliberately: a bare network error must never be
35
+ // retried here. This client carries login and OTP, which are not
36
+ // idempotent — the request may well have reached the server before the
37
+ // connection broke, so a retry can create a second session the user never
38
+ // sees. axios-retry's isNetworkOrIdempotentRequestError does NOT protect
39
+ // against this: its isNetworkError branch never looks at the HTTP method,
40
+ // so it retried POSTs too.
41
+ const status = error.response?.status;
42
+ return typeof status === 'number' && (status === 429 || status >= 500 && status <= 599);
43
+ }
44
+ };
45
+ axiosRetry(publicClient, retryConfig);
46
+
47
+ // Add request interceptor for logging
48
+ publicClient.interceptors.request.use(config => {
49
+ Logger.info(`Request: ${config.method?.toUpperCase()} ${config.url}`);
50
+ return config;
51
+ }, error => {
52
+ const message = error instanceof Error ? error.message : String(error);
53
+ Logger.error('Request error:', message);
54
+ return Promise.reject(error);
55
+ });
56
+
57
+ // Add response interceptor for error handling
58
+ publicClient.interceptors.response.use(response => {
59
+ Logger.info(`Response: ${response.status} from ${response.config.url}`);
60
+ return response;
61
+ }, error => {
62
+ if (axios.isAxiosError(error)) {
63
+ const originalRequest = error.config;
64
+ if (!error.response) {
65
+ Logger.error(`Network error or no response from server: ${error.message}, URL: ${originalRequest?.url}`);
66
+ } else {
67
+ Logger.error(`Response error: ${error.response.data ?? error.message}, URL: ${originalRequest?.url}, Status: ${error.response.status}`);
68
+ }
69
+ } else {
70
+ const message = error instanceof Error ? error.message : String(error);
71
+ Logger.error(`Unknown response error: ${message}`);
72
+ }
73
+ return Promise.reject(error);
74
+ });
75
+ export default publicClient;
76
+ //# sourceMappingURL=publicClient.js.map