react-native-nitro-version-check 1.0.2 → 1.1.0

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/README.md CHANGED
@@ -15,7 +15,7 @@
15
15
  ## Example
16
16
 
17
17
  ```ts
18
- import { VersionCheck, needsUpdate, getStoreUrl } from 'react-native-nitro-version-check'
18
+ import { VersionCheck } from 'react-native-nitro-version-check'
19
19
 
20
20
  // Sync — no bridge, no async
21
21
  VersionCheck.version // "1.2.0"
@@ -23,9 +23,12 @@ VersionCheck.buildNumber // "42"
23
23
  VersionCheck.packageName // "com.example.app"
24
24
  VersionCheck.installSource // "appstore" | "testflight" | "playstore" | undefined
25
25
 
26
+ // Or destructure properties
27
+ const { version, buildNumber, packageName, installSource } = VersionCheck
28
+
26
29
  // Check for updates
27
- if (await needsUpdate()) {
28
- Linking.openURL(await getStoreUrl())
30
+ if (await VersionCheck.needsUpdate()) {
31
+ Linking.openURL(await VersionCheck.getStoreUrl())
29
32
  }
30
33
  ```
31
34
 
@@ -35,6 +38,8 @@ if (await needsUpdate()) {
35
38
  bun add react-native-nitro-version-check
36
39
  ```
37
40
 
41
+ > Check the [full installation guide](https://alshehriali0.github.io/react-native-nitro-version-check/docs/installation) for platform setup and additional dependencies.
42
+
38
43
  ## Documentation
39
44
 
40
45
  - [**Nitro Version Check** docs 📚](https://alshehriali0.github.io/react-native-nitro-version-check/)
@@ -36,15 +36,17 @@ class HybridVersionCheck : HybridVersionCheckSpec() {
36
36
  return java.util.Locale.getDefault().country ?: "unknown"
37
37
  }
38
38
 
39
- override fun getStoreUrl(): Promise<String> {
39
+ override fun getStoreUrl(countryCode: String?): Promise<String> {
40
40
  return Promise.async {
41
+ // Country code is not used on Android Play Store, but parameter is kept for API consistency
41
42
  "https://play.google.com/store/apps/details?id=$packageName"
42
43
  }
43
44
  }
44
45
 
45
- override fun getLatestVersion(): Promise<String> {
46
+ override fun getLatestVersion(countryCode: String?): Promise<String> {
46
47
  return Promise.async {
47
48
  try {
49
+ // Country code is not used on Android Play Store, but parameter is kept for API consistency
48
50
  val url = URL("https://play.google.com/store/apps/details?id=$packageName&hl=en")
49
51
  val connection = url.openConnection() as HttpURLConnection
50
52
  connection.connectTimeout = TIMEOUT_MS
@@ -30,10 +30,12 @@ class HybridVersionCheck: HybridVersionCheckSpec {
30
30
  return Locale.current.regionCode ?? "unknown"
31
31
  }
32
32
 
33
- func getStoreUrl() throws -> Promise<String> {
34
- return Promise.async {
33
+ func getStoreUrl(countryCode: String? = nil) throws -> Promise<String> {
34
+ return Promise.async { [self] in
35
35
  let bundleId = Bundle.main.bundleIdentifier ?? ""
36
- let url = URL(string: "https://itunes.apple.com/lookup?bundleId=\(bundleId)")!
36
+ let country = countryCode ?? (try? self.getCountry()) ?? "US"
37
+ let urlString = "https://itunes.apple.com/\(country.lowercased())/lookup?bundleId=\(bundleId)"
38
+ let url = URL(string: urlString)!
37
39
  let (data, _) = try await HybridVersionCheck.session.data(from: url)
38
40
  guard let json = try JSONSerialization.jsonObject(with: data) as? [String: Any],
39
41
  let results = json["results"] as? [[String: Any]],
@@ -44,10 +46,12 @@ class HybridVersionCheck: HybridVersionCheckSpec {
44
46
  }
45
47
  }
46
48
 
47
- func getLatestVersion() throws -> Promise<String> {
48
- return Promise.async {
49
+ func getLatestVersion(countryCode: String? = nil) throws -> Promise<String> {
50
+ return Promise.async { [self] in
49
51
  let bundleId = Bundle.main.bundleIdentifier ?? ""
50
- let url = URL(string: "https://itunes.apple.com/lookup?bundleId=\(bundleId)")!
52
+ let country = countryCode ?? (try? self.getCountry()) ?? "US"
53
+ let urlString = "https://itunes.apple.com/\(country.lowercased())/lookup?bundleId=\(bundleId)"
54
+ let url = URL(string: urlString)!
51
55
  let (data, _) = try await HybridVersionCheck.session.data(from: url)
52
56
  guard let json = try JSONSerialization.jsonObject(with: data) as? [String: Any],
53
57
  let results = json["results"] as? [[String: Any]],
package/lib/index.d.ts CHANGED
@@ -1,62 +1,11 @@
1
1
  import type { UpdateLevel } from "./semver";
2
2
  import { compareVersions } from "./semver";
3
- /**
4
- * Returns the device's current 2-letter ISO country code.
5
- *
6
- * @example
7
- * ```ts
8
- * getCountry() // "US"
9
- * ```
10
- */
11
- export declare const getCountry: () => string;
12
- /**
13
- * Returns the store URL for this app.
14
- *
15
- * Automatically resolves to the App Store on iOS and Play Store on Android.
16
- *
17
- * @example
18
- * ```ts
19
- * const url = await getStoreUrl();
20
- * Linking.openURL(url);
21
- * ```
22
- */
23
- export declare const getStoreUrl: () => Promise<string>;
24
- /**
25
- * Fetches the latest version of this app available in the store.
26
- *
27
- * @example
28
- * ```ts
29
- * const latest = await getLatestVersion(); // "1.3.0"
30
- * ```
31
- */
32
- export declare const getLatestVersion: () => Promise<string>;
33
- /**
34
- * Checks whether an app update is available.
35
- *
36
- * Uses semantic version comparison. By default checks for any version
37
- * increase, but you can filter by granularity:
38
- *
39
- * - `"major"` — only returns `true` for major bumps (1.x → 2.x)
40
- * - `"minor"` — returns `true` for major or minor bumps
41
- * - `"patch"` — returns `true` for any version increase (default)
42
- *
43
- * @example
44
- * ```ts
45
- * if (await needsUpdate()) {
46
- * const url = await getStoreUrl();
47
- * Linking.openURL(url);
48
- * }
49
- *
50
- * // Only prompt for major updates
51
- * const majorUpdate = await needsUpdate({ level: "major" });
52
- * ```
53
- */
54
- export declare const needsUpdate: (options?: {
55
- level?: UpdateLevel;
56
- }) => Promise<boolean>;
57
3
  /**
58
4
  * All version-check APIs in one object.
59
5
  *
6
+ * Provides access to app version information, store URLs, and update checking.
7
+ * Sync properties are cached at module init for zero native overhead.
8
+ *
60
9
  * @example
61
10
  * ```ts
62
11
  * VersionCheck.version // "1.2.0"
@@ -65,6 +14,9 @@ export declare const needsUpdate: (options?: {
65
14
  * VersionCheck.getCountry() // "US"
66
15
  *
67
16
  * const url = await VersionCheck.getStoreUrl();
17
+ * if (await VersionCheck.needsUpdate()) {
18
+ * Linking.openURL(url);
19
+ * }
68
20
  * ```
69
21
  */
70
22
  export declare const VersionCheck: {
@@ -132,37 +84,84 @@ export declare const VersionCheck: {
132
84
  /**
133
85
  * Returns the App Store (iOS) or Play Store (Android) URL for this app.
134
86
  *
87
+ * @param options - Optional configuration
88
+ * @param options.countryCode - 2-letter ISO country code (e.g., "US", "GB")
89
+ * Defaults to the device's current country from `getCountry()`.
90
+ * Only used on iOS; ignored on Android.
91
+ *
135
92
  * @example
136
93
  * ```ts
137
94
  * const url = await VersionCheck.getStoreUrl();
95
+ * const urlUS = await VersionCheck.getStoreUrl({ countryCode: "US" });
138
96
  * Linking.openURL(url);
139
97
  * ```
140
98
  */
141
- readonly getStoreUrl: () => Promise<string>;
99
+ readonly getStoreUrl: (options?: {
100
+ countryCode?: string;
101
+ }) => Promise<string>;
142
102
  /**
143
103
  * Fetches the latest version of this app available in the store.
144
104
  *
145
105
  * Queries the iTunes API on iOS and the Play Store on Android.
106
+ * On iOS, uses the device's current country code by default but can be overridden.
107
+ *
108
+ * @param options - Optional configuration
109
+ * @param options.countryCode - 2-letter ISO country code (e.g., "US", "GB")
110
+ * Defaults to the device's current country from `getCountry()`.
111
+ * If the device region changes, the next call will use the new country.
112
+ * Only used on iOS; ignored on Android.
146
113
  *
147
114
  * @example
148
115
  * ```ts
149
- * const latest = await VersionCheck.getLatestVersion(); // "1.3.0"
116
+ * const latest = await VersionCheck.getLatestVersion(); // Uses current device country
117
+ * const latestUS = await VersionCheck.getLatestVersion({ countryCode: "US" });
118
+ * const latestGB = await VersionCheck.getLatestVersion({ countryCode: "GB" });
150
119
  * ```
151
120
  */
152
- readonly getLatestVersion: () => Promise<string>;
121
+ readonly getLatestVersion: (options?: {
122
+ countryCode?: string;
123
+ }) => Promise<string>;
153
124
  /**
154
125
  * Checks whether an app update is available by comparing the current
155
126
  * version against the latest store version.
156
127
  *
128
+ * Uses semantic version comparison. By default checks for any version
129
+ * increase, but you can filter by granularity:
130
+ *
131
+ * - `"major"` — only returns `true` for major bumps (1.x → 2.x)
132
+ * - `"minor"` — returns `true` for major or minor bumps
133
+ * - `"patch"` — returns `true` for any version increase (default)
134
+ *
157
135
  * @example
158
136
  * ```ts
159
137
  * if (await VersionCheck.needsUpdate()) {
160
138
  * const url = await VersionCheck.getStoreUrl();
161
139
  * Linking.openURL(url);
162
140
  * }
141
+ *
142
+ * // Only prompt for major updates
143
+ * const majorUpdate = await VersionCheck.needsUpdate({ level: "major" });
144
+ * ```
145
+ */
146
+ readonly needsUpdate: (options?: {
147
+ level?: UpdateLevel;
148
+ }) => Promise<boolean>;
149
+ /**
150
+ * Compares two semantic version strings.
151
+ *
152
+ * @returns -1 if v1 < v2, 0 if v1 === v2, 1 if v1 > v2
153
+ *
154
+ * @example
155
+ * ```ts
156
+ * VersionCheck.compareVersions('1.0.0', '1.0.1') // -1
157
+ * VersionCheck.compareVersions('2.0.0', '2.0.0') // 0
158
+ * VersionCheck.compareVersions('3.0.0', '2.9.9') // 1
159
+ *
160
+ * if (VersionCheck.compareVersions(currentVersion, minimumVersion) < 0) {
161
+ * // Current version is below minimum — force update
162
+ * }
163
163
  * ```
164
164
  */
165
- readonly needsUpdate: () => Promise<boolean>;
165
+ readonly compareVersions: typeof compareVersions;
166
166
  };
167
- export { compareVersions };
168
167
  export type { UpdateLevel };
package/lib/index.js CHANGED
@@ -6,64 +6,12 @@ const version = HybridVersionCheck.version;
6
6
  const buildNumber = HybridVersionCheck.buildNumber;
7
7
  const packageName = HybridVersionCheck.packageName;
8
8
  const installSource = HybridVersionCheck.installSource;
9
- /**
10
- * Returns the device's current 2-letter ISO country code.
11
- *
12
- * @example
13
- * ```ts
14
- * getCountry() // "US"
15
- * ```
16
- */
17
- export const getCountry = () => HybridVersionCheck.getCountry();
18
- /**
19
- * Returns the store URL for this app.
20
- *
21
- * Automatically resolves to the App Store on iOS and Play Store on Android.
22
- *
23
- * @example
24
- * ```ts
25
- * const url = await getStoreUrl();
26
- * Linking.openURL(url);
27
- * ```
28
- */
29
- export const getStoreUrl = () => HybridVersionCheck.getStoreUrl();
30
- /**
31
- * Fetches the latest version of this app available in the store.
32
- *
33
- * @example
34
- * ```ts
35
- * const latest = await getLatestVersion(); // "1.3.0"
36
- * ```
37
- */
38
- export const getLatestVersion = () => HybridVersionCheck.getLatestVersion();
39
- /**
40
- * Checks whether an app update is available.
41
- *
42
- * Uses semantic version comparison. By default checks for any version
43
- * increase, but you can filter by granularity:
44
- *
45
- * - `"major"` — only returns `true` for major bumps (1.x → 2.x)
46
- * - `"minor"` — returns `true` for major or minor bumps
47
- * - `"patch"` — returns `true` for any version increase (default)
48
- *
49
- * @example
50
- * ```ts
51
- * if (await needsUpdate()) {
52
- * const url = await getStoreUrl();
53
- * Linking.openURL(url);
54
- * }
55
- *
56
- * // Only prompt for major updates
57
- * const majorUpdate = await needsUpdate({ level: "major" });
58
- * ```
59
- */
60
- export const needsUpdate = async (options) => {
61
- const latest = await HybridVersionCheck.getLatestVersion();
62
- return isNewerVersion(version, latest, options?.level ?? "patch");
63
- };
64
9
  /**
65
10
  * All version-check APIs in one object.
66
11
  *
12
+ * Provides access to app version information, store URLs, and update checking.
13
+ * Sync properties are cached at module init for zero native overhead.
14
+ *
67
15
  * @example
68
16
  * ```ts
69
17
  * VersionCheck.version // "1.2.0"
@@ -72,6 +20,9 @@ export const needsUpdate = async (options) => {
72
20
  * VersionCheck.getCountry() // "US"
73
21
  *
74
22
  * const url = await VersionCheck.getStoreUrl();
23
+ * if (await VersionCheck.needsUpdate()) {
24
+ * Linking.openURL(url);
25
+ * }
75
26
  * ```
76
27
  */
77
28
  export const VersionCheck = {
@@ -135,40 +86,88 @@ export const VersionCheck = {
135
86
  * VersionCheck.getCountry() // "US"
136
87
  * ```
137
88
  */
138
- getCountry,
89
+ getCountry: () => HybridVersionCheck.getCountry(),
139
90
  /**
140
91
  * Returns the App Store (iOS) or Play Store (Android) URL for this app.
141
92
  *
93
+ * @param options - Optional configuration
94
+ * @param options.countryCode - 2-letter ISO country code (e.g., "US", "GB")
95
+ * Defaults to the device's current country from `getCountry()`.
96
+ * Only used on iOS; ignored on Android.
97
+ *
142
98
  * @example
143
99
  * ```ts
144
100
  * const url = await VersionCheck.getStoreUrl();
101
+ * const urlUS = await VersionCheck.getStoreUrl({ countryCode: "US" });
145
102
  * Linking.openURL(url);
146
103
  * ```
147
104
  */
148
- getStoreUrl,
105
+ getStoreUrl: async (options) => {
106
+ return HybridVersionCheck.getStoreUrl(options?.countryCode);
107
+ },
149
108
  /**
150
109
  * Fetches the latest version of this app available in the store.
151
110
  *
152
111
  * Queries the iTunes API on iOS and the Play Store on Android.
112
+ * On iOS, uses the device's current country code by default but can be overridden.
113
+ *
114
+ * @param options - Optional configuration
115
+ * @param options.countryCode - 2-letter ISO country code (e.g., "US", "GB")
116
+ * Defaults to the device's current country from `getCountry()`.
117
+ * If the device region changes, the next call will use the new country.
118
+ * Only used on iOS; ignored on Android.
153
119
  *
154
120
  * @example
155
121
  * ```ts
156
- * const latest = await VersionCheck.getLatestVersion(); // "1.3.0"
122
+ * const latest = await VersionCheck.getLatestVersion(); // Uses current device country
123
+ * const latestUS = await VersionCheck.getLatestVersion({ countryCode: "US" });
124
+ * const latestGB = await VersionCheck.getLatestVersion({ countryCode: "GB" });
157
125
  * ```
158
126
  */
159
- getLatestVersion,
127
+ getLatestVersion: async (options) => {
128
+ return HybridVersionCheck.getLatestVersion(options?.countryCode);
129
+ },
160
130
  /**
161
131
  * Checks whether an app update is available by comparing the current
162
132
  * version against the latest store version.
163
133
  *
134
+ * Uses semantic version comparison. By default checks for any version
135
+ * increase, but you can filter by granularity:
136
+ *
137
+ * - `"major"` — only returns `true` for major bumps (1.x → 2.x)
138
+ * - `"minor"` — returns `true` for major or minor bumps
139
+ * - `"patch"` — returns `true` for any version increase (default)
140
+ *
164
141
  * @example
165
142
  * ```ts
166
143
  * if (await VersionCheck.needsUpdate()) {
167
144
  * const url = await VersionCheck.getStoreUrl();
168
145
  * Linking.openURL(url);
169
146
  * }
147
+ *
148
+ * // Only prompt for major updates
149
+ * const majorUpdate = await VersionCheck.needsUpdate({ level: "major" });
150
+ * ```
151
+ */
152
+ needsUpdate: async (options) => {
153
+ const latest = await HybridVersionCheck.getLatestVersion();
154
+ return isNewerVersion(version, latest, options?.level ?? "patch");
155
+ },
156
+ /**
157
+ * Compares two semantic version strings.
158
+ *
159
+ * @returns -1 if v1 < v2, 0 if v1 === v2, 1 if v1 > v2
160
+ *
161
+ * @example
162
+ * ```ts
163
+ * VersionCheck.compareVersions('1.0.0', '1.0.1') // -1
164
+ * VersionCheck.compareVersions('2.0.0', '2.0.0') // 0
165
+ * VersionCheck.compareVersions('3.0.0', '2.9.9') // 1
166
+ *
167
+ * if (VersionCheck.compareVersions(currentVersion, minimumVersion) < 0) {
168
+ * // Current version is below minimum — force update
169
+ * }
170
170
  * ```
171
171
  */
172
- needsUpdate: () => HybridVersionCheck.needsUpdate(),
172
+ compareVersions,
173
173
  };
174
- export { compareVersions };
@@ -8,7 +8,7 @@ export interface VersionCheck extends HybridObject<{
8
8
  readonly packageName: string;
9
9
  readonly installSource: string | undefined;
10
10
  getCountry(): string;
11
- getStoreUrl(): Promise<string>;
12
- getLatestVersion(): Promise<string>;
11
+ getStoreUrl(countryCode?: string): Promise<string>;
12
+ getLatestVersion(countryCode?: string): Promise<string>;
13
13
  needsUpdate(): Promise<boolean>;
14
14
  }
@@ -77,9 +77,9 @@ namespace margelo::nitro::nitroversioncheck {
77
77
  auto __result = method(_javaPart);
78
78
  return __result->toStdString();
79
79
  }
80
- std::shared_ptr<Promise<std::string>> JHybridVersionCheckSpec::getStoreUrl() {
81
- static const auto method = javaClassStatic()->getMethod<jni::local_ref<JPromise::javaobject>()>("getStoreUrl");
82
- auto __result = method(_javaPart);
80
+ std::shared_ptr<Promise<std::string>> JHybridVersionCheckSpec::getStoreUrl(const std::optional<std::string>& countryCode) {
81
+ static const auto method = javaClassStatic()->getMethod<jni::local_ref<JPromise::javaobject>(jni::alias_ref<jni::JString> /* countryCode */)>("getStoreUrl");
82
+ auto __result = method(_javaPart, countryCode.has_value() ? jni::make_jstring(countryCode.value()) : nullptr);
83
83
  return [&]() {
84
84
  auto __promise = Promise<std::string>::create();
85
85
  __result->cthis()->addOnResolvedListener([=](const jni::alias_ref<jni::JObject>& __boxedResult) {
@@ -93,9 +93,9 @@ namespace margelo::nitro::nitroversioncheck {
93
93
  return __promise;
94
94
  }();
95
95
  }
96
- std::shared_ptr<Promise<std::string>> JHybridVersionCheckSpec::getLatestVersion() {
97
- static const auto method = javaClassStatic()->getMethod<jni::local_ref<JPromise::javaobject>()>("getLatestVersion");
98
- auto __result = method(_javaPart);
96
+ std::shared_ptr<Promise<std::string>> JHybridVersionCheckSpec::getLatestVersion(const std::optional<std::string>& countryCode) {
97
+ static const auto method = javaClassStatic()->getMethod<jni::local_ref<JPromise::javaobject>(jni::alias_ref<jni::JString> /* countryCode */)>("getLatestVersion");
98
+ auto __result = method(_javaPart, countryCode.has_value() ? jni::make_jstring(countryCode.value()) : nullptr);
99
99
  return [&]() {
100
100
  auto __promise = Promise<std::string>::create();
101
101
  __result->cthis()->addOnResolvedListener([=](const jni::alias_ref<jni::JObject>& __boxedResult) {
@@ -59,8 +59,8 @@ namespace margelo::nitro::nitroversioncheck {
59
59
  public:
60
60
  // Methods
61
61
  std::string getCountry() override;
62
- std::shared_ptr<Promise<std::string>> getStoreUrl() override;
63
- std::shared_ptr<Promise<std::string>> getLatestVersion() override;
62
+ std::shared_ptr<Promise<std::string>> getStoreUrl(const std::optional<std::string>& countryCode) override;
63
+ std::shared_ptr<Promise<std::string>> getLatestVersion(const std::optional<std::string>& countryCode) override;
64
64
  std::shared_ptr<Promise<bool>> needsUpdate() override;
65
65
 
66
66
  private:
@@ -66,11 +66,11 @@ abstract class HybridVersionCheckSpec: HybridObject() {
66
66
 
67
67
  @DoNotStrip
68
68
  @Keep
69
- abstract fun getStoreUrl(): Promise<String>
69
+ abstract fun getStoreUrl(countryCode: String?): Promise<String>
70
70
 
71
71
  @DoNotStrip
72
72
  @Keep
73
- abstract fun getLatestVersion(): Promise<String>
73
+ abstract fun getLatestVersion(countryCode: String?): Promise<String>
74
74
 
75
75
  @DoNotStrip
76
76
  @Keep
@@ -91,16 +91,16 @@ namespace margelo::nitro::nitroversioncheck {
91
91
  auto __value = std::move(__result.value());
92
92
  return __value;
93
93
  }
94
- inline std::shared_ptr<Promise<std::string>> getStoreUrl() override {
95
- auto __result = _swiftPart.getStoreUrl();
94
+ inline std::shared_ptr<Promise<std::string>> getStoreUrl(const std::optional<std::string>& countryCode) override {
95
+ auto __result = _swiftPart.getStoreUrl(countryCode);
96
96
  if (__result.hasError()) [[unlikely]] {
97
97
  std::rethrow_exception(__result.error());
98
98
  }
99
99
  auto __value = std::move(__result.value());
100
100
  return __value;
101
101
  }
102
- inline std::shared_ptr<Promise<std::string>> getLatestVersion() override {
103
- auto __result = _swiftPart.getLatestVersion();
102
+ inline std::shared_ptr<Promise<std::string>> getLatestVersion(const std::optional<std::string>& countryCode) override {
103
+ auto __result = _swiftPart.getLatestVersion(countryCode);
104
104
  if (__result.hasError()) [[unlikely]] {
105
105
  std::rethrow_exception(__result.error());
106
106
  }
@@ -17,8 +17,8 @@ public protocol HybridVersionCheckSpec_protocol: HybridObject {
17
17
 
18
18
  // Methods
19
19
  func getCountry() throws -> String
20
- func getStoreUrl() throws -> Promise<String>
21
- func getLatestVersion() throws -> Promise<String>
20
+ func getStoreUrl(countryCode: String?) throws -> Promise<String>
21
+ func getLatestVersion(countryCode: String?) throws -> Promise<String>
22
22
  func needsUpdate() throws -> Promise<Bool>
23
23
  }
24
24
 
@@ -169,9 +169,16 @@ open class HybridVersionCheckSpec_cxx {
169
169
  }
170
170
 
171
171
  @inline(__always)
172
- public final func getStoreUrl() -> bridge.Result_std__shared_ptr_Promise_std__string___ {
172
+ public final func getStoreUrl(countryCode: bridge.std__optional_std__string_) -> bridge.Result_std__shared_ptr_Promise_std__string___ {
173
173
  do {
174
- let __result = try self.__implementation.getStoreUrl()
174
+ let __result = try self.__implementation.getStoreUrl(countryCode: { () -> String? in
175
+ if bridge.has_value_std__optional_std__string_(countryCode) {
176
+ let __unwrapped = bridge.get_std__optional_std__string_(countryCode)
177
+ return String(__unwrapped)
178
+ } else {
179
+ return nil
180
+ }
181
+ }())
175
182
  let __resultCpp = { () -> bridge.std__shared_ptr_Promise_std__string__ in
176
183
  let __promise = bridge.create_std__shared_ptr_Promise_std__string__()
177
184
  let __promiseHolder = bridge.wrap_std__shared_ptr_Promise_std__string__(__promise)
@@ -188,9 +195,16 @@ open class HybridVersionCheckSpec_cxx {
188
195
  }
189
196
 
190
197
  @inline(__always)
191
- public final func getLatestVersion() -> bridge.Result_std__shared_ptr_Promise_std__string___ {
198
+ public final func getLatestVersion(countryCode: bridge.std__optional_std__string_) -> bridge.Result_std__shared_ptr_Promise_std__string___ {
192
199
  do {
193
- let __result = try self.__implementation.getLatestVersion()
200
+ let __result = try self.__implementation.getLatestVersion(countryCode: { () -> String? in
201
+ if bridge.has_value_std__optional_std__string_(countryCode) {
202
+ let __unwrapped = bridge.get_std__optional_std__string_(countryCode)
203
+ return String(__unwrapped)
204
+ } else {
205
+ return nil
206
+ }
207
+ }())
194
208
  let __resultCpp = { () -> bridge.std__shared_ptr_Promise_std__string__ in
195
209
  let __promise = bridge.create_std__shared_ptr_Promise_std__string__()
196
210
  let __promiseHolder = bridge.wrap_std__shared_ptr_Promise_std__string__(__promise)
@@ -54,8 +54,8 @@ namespace margelo::nitro::nitroversioncheck {
54
54
  public:
55
55
  // Methods
56
56
  virtual std::string getCountry() = 0;
57
- virtual std::shared_ptr<Promise<std::string>> getStoreUrl() = 0;
58
- virtual std::shared_ptr<Promise<std::string>> getLatestVersion() = 0;
57
+ virtual std::shared_ptr<Promise<std::string>> getStoreUrl(const std::optional<std::string>& countryCode) = 0;
58
+ virtual std::shared_ptr<Promise<std::string>> getLatestVersion(const std::optional<std::string>& countryCode) = 0;
59
59
  virtual std::shared_ptr<Promise<bool>> needsUpdate() = 0;
60
60
 
61
61
  protected:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-nitro-version-check",
3
- "version": "1.0.2",
3
+ "version": "1.1.0",
4
4
  "description": "A lightweight, fast version-checking library for React Native, powered by Nitro Modules",
5
5
  "main": "lib/index",
6
6
  "module": "lib/index",
@@ -8,9 +8,8 @@
8
8
  "react-native": "src/index",
9
9
  "source": "src/index",
10
10
  "files": [
11
- "src",
12
- "react-native.config.js",
13
11
  "lib",
12
+ "react-native.config.js",
14
13
  "nitrogen",
15
14
  "android/build.gradle",
16
15
  "android/gradle.properties",
@@ -34,6 +33,9 @@
34
33
  "release": "release-it",
35
34
  "build": "tsc",
36
35
  "typecheck": "tsc --noEmit",
36
+ "test": "jest",
37
+ "test:watch": "jest --watch",
38
+ "test:coverage": "jest --coverage",
37
39
  "lint": "biome check .",
38
40
  "lint:fix": "biome check --write .",
39
41
  "format": "biome format --write .",
@@ -149,12 +151,15 @@
149
151
  },
150
152
  "devDependencies": {
151
153
  "@release-it/conventional-changelog": "^10.0.5",
154
+ "@types/jest": "^29.5.12",
152
155
  "@types/react": "^19.1.03",
156
+ "jest": "^29.7.0",
153
157
  "nitrogen": "*",
154
158
  "react": "19.2.0",
155
159
  "react-native": "0.83.0",
156
160
  "react-native-nitro-modules": "*",
157
161
  "release-it": "^19.2.4",
162
+ "ts-jest": "^29.1.2",
158
163
  "typescript": "^5.8.3"
159
164
  },
160
165
  "peerDependencies": {
package/src/index.ts DELETED
@@ -1,185 +0,0 @@
1
- import { NitroModules } from "react-native-nitro-modules";
2
- import type { UpdateLevel } from "./semver";
3
- import { compareVersions, isNewerVersion } from "./semver";
4
- import type { VersionCheck as VersionCheckType } from "./specs/Version.nitro";
5
-
6
- const HybridVersionCheck = NitroModules.createHybridObject<VersionCheckType>("VersionCheck");
7
-
8
- // Cached at module init — plain JS values, no JSI overhead on repeated access.
9
- const version = HybridVersionCheck.version;
10
- const buildNumber = HybridVersionCheck.buildNumber;
11
- const packageName = HybridVersionCheck.packageName;
12
- const installSource = HybridVersionCheck.installSource;
13
-
14
- /**
15
- * Returns the device's current 2-letter ISO country code.
16
- *
17
- * @example
18
- * ```ts
19
- * getCountry() // "US"
20
- * ```
21
- */
22
- export const getCountry = () => HybridVersionCheck.getCountry();
23
-
24
- /**
25
- * Returns the store URL for this app.
26
- *
27
- * Automatically resolves to the App Store on iOS and Play Store on Android.
28
- *
29
- * @example
30
- * ```ts
31
- * const url = await getStoreUrl();
32
- * Linking.openURL(url);
33
- * ```
34
- */
35
- export const getStoreUrl = () => HybridVersionCheck.getStoreUrl();
36
-
37
- /**
38
- * Fetches the latest version of this app available in the store.
39
- *
40
- * @example
41
- * ```ts
42
- * const latest = await getLatestVersion(); // "1.3.0"
43
- * ```
44
- */
45
- export const getLatestVersion = () => HybridVersionCheck.getLatestVersion();
46
-
47
- /**
48
- * Checks whether an app update is available.
49
- *
50
- * Uses semantic version comparison. By default checks for any version
51
- * increase, but you can filter by granularity:
52
- *
53
- * - `"major"` — only returns `true` for major bumps (1.x → 2.x)
54
- * - `"minor"` — returns `true` for major or minor bumps
55
- * - `"patch"` — returns `true` for any version increase (default)
56
- *
57
- * @example
58
- * ```ts
59
- * if (await needsUpdate()) {
60
- * const url = await getStoreUrl();
61
- * Linking.openURL(url);
62
- * }
63
- *
64
- * // Only prompt for major updates
65
- * const majorUpdate = await needsUpdate({ level: "major" });
66
- * ```
67
- */
68
- export const needsUpdate = async (options?: { level?: UpdateLevel }): Promise<boolean> => {
69
- const latest = await HybridVersionCheck.getLatestVersion();
70
- return isNewerVersion(version, latest, options?.level ?? "patch");
71
- };
72
-
73
- /**
74
- * All version-check APIs in one object.
75
- *
76
- * @example
77
- * ```ts
78
- * VersionCheck.version // "1.2.0"
79
- * VersionCheck.buildNumber // "42"
80
- * VersionCheck.packageName // "com.example.app"
81
- * VersionCheck.getCountry() // "US"
82
- *
83
- * const url = await VersionCheck.getStoreUrl();
84
- * ```
85
- */
86
- export const VersionCheck = {
87
- /**
88
- * The current app version string.
89
- *
90
- * Read from `CFBundleShortVersionString` on iOS and `versionName` on Android.
91
- * Cached at module init, so repeated reads have zero native overhead.
92
- *
93
- * @example
94
- * ```ts
95
- * VersionCheck.version // "1.2.0"
96
- * ```
97
- */
98
- version,
99
- /**
100
- * The current build number.
101
- *
102
- * Read from `CFBundleVersion` on iOS and `versionCode` on Android.
103
- * Cached at module init.
104
- *
105
- * @example
106
- * ```ts
107
- * VersionCheck.buildNumber // "42"
108
- * ```
109
- */
110
- buildNumber,
111
- /**
112
- * The app's unique identifier.
113
- *
114
- * This is the Bundle ID on iOS and the Application ID on Android.
115
- * Cached at module init.
116
- *
117
- * @example
118
- * ```ts
119
- * VersionCheck.packageName // "com.example.app"
120
- * ```
121
- */
122
- packageName,
123
- /**
124
- * Where the app was installed from, or `undefined` for dev/sideloaded builds.
125
- *
126
- * - iOS: `"appstore"` | `"testflight"` | `undefined`
127
- * - Android: `"playstore"` | `undefined`
128
- *
129
- * @example
130
- * ```ts
131
- * if (VersionCheck.installSource === "testflight") {
132
- * // running a TestFlight build
133
- * }
134
- * ```
135
- */
136
- installSource,
137
- /**
138
- * Returns the device's current 2-letter ISO country code.
139
- *
140
- * This is a synchronous Nitro call, no `await` needed.
141
- *
142
- * @example
143
- * ```ts
144
- * VersionCheck.getCountry() // "US"
145
- * ```
146
- */
147
- getCountry,
148
- /**
149
- * Returns the App Store (iOS) or Play Store (Android) URL for this app.
150
- *
151
- * @example
152
- * ```ts
153
- * const url = await VersionCheck.getStoreUrl();
154
- * Linking.openURL(url);
155
- * ```
156
- */
157
- getStoreUrl,
158
- /**
159
- * Fetches the latest version of this app available in the store.
160
- *
161
- * Queries the iTunes API on iOS and the Play Store on Android.
162
- *
163
- * @example
164
- * ```ts
165
- * const latest = await VersionCheck.getLatestVersion(); // "1.3.0"
166
- * ```
167
- */
168
- getLatestVersion,
169
- /**
170
- * Checks whether an app update is available by comparing the current
171
- * version against the latest store version.
172
- *
173
- * @example
174
- * ```ts
175
- * if (await VersionCheck.needsUpdate()) {
176
- * const url = await VersionCheck.getStoreUrl();
177
- * Linking.openURL(url);
178
- * }
179
- * ```
180
- */
181
- needsUpdate: () => HybridVersionCheck.needsUpdate(),
182
- } as const;
183
-
184
- export { compareVersions };
185
- export type { UpdateLevel };
package/src/semver.ts DELETED
@@ -1,54 +0,0 @@
1
- export type UpdateLevel = "major" | "minor" | "patch";
2
-
3
- type SemVer = [major: number, minor: number, patch: number];
4
-
5
- function parseVersion(version: string): SemVer {
6
- const parts = version.split(".");
7
- return [Number(parts[0]) || 0, Number(parts[1]) || 0, Number(parts[2]) || 0];
8
- }
9
-
10
- /**
11
- * Compares two version strings.
12
- *
13
- * @returns `-1` if `v1 < v2`, `0` if equal, `1` if `v1 > v2`
14
- *
15
- * @example
16
- * ```ts
17
- * compareVersions("1.2.0", "1.3.0") // -1
18
- * compareVersions("2.0.0", "1.9.9") // 1
19
- * compareVersions("1.0.0", "1.0.0") // 0
20
- * ```
21
- */
22
- export function compareVersions(v1: string, v2: string): -1 | 0 | 1 {
23
- const a = parseVersion(v1);
24
- const b = parseVersion(v2);
25
-
26
- for (let i = 0; i < 3; i++) {
27
- if (a[i]! > b[i]!) return 1;
28
- if (a[i]! < b[i]!) return -1;
29
- }
30
-
31
- return 0;
32
- }
33
-
34
- /**
35
- * Checks whether `latest` is newer than `current` at the given granularity.
36
- *
37
- * - `"major"` — only returns `true` for major bumps (1.x → 2.x)
38
- * - `"minor"` — returns `true` for major or minor bumps
39
- * - `"patch"` — returns `true` for any version increase (default)
40
- */
41
- export function isNewerVersion(current: string, latest: string, level: UpdateLevel = "patch"): boolean {
42
- const [curMajor, curMinor, curPatch] = parseVersion(current);
43
- const [latMajor, latMinor, latPatch] = parseVersion(latest);
44
-
45
- if (latMajor > curMajor) return true;
46
- if (latMajor < curMajor) return false;
47
- if (level === "major") return false;
48
-
49
- if (latMinor > curMinor) return true;
50
- if (latMinor < curMinor) return false;
51
- if (level === "minor") return false;
52
-
53
- return latPatch > curPatch;
54
- }
@@ -1,16 +0,0 @@
1
- import type { HybridObject } from "react-native-nitro-modules";
2
-
3
- export interface VersionCheck
4
- extends HybridObject<{
5
- ios: "swift";
6
- android: "kotlin";
7
- }> {
8
- readonly version: string;
9
- readonly buildNumber: string;
10
- readonly packageName: string;
11
- readonly installSource: string | undefined;
12
- getCountry(): string;
13
- getStoreUrl(): Promise<string>;
14
- getLatestVersion(): Promise<string>;
15
- needsUpdate(): Promise<boolean>;
16
- }