@cap-kit/rank 8.0.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.
Files changed (36) hide show
  1. package/CapKitRank.podspec +17 -0
  2. package/LICENSE +21 -0
  3. package/Package.swift +28 -0
  4. package/README.md +574 -0
  5. package/android/build.gradle +110 -0
  6. package/android/src/main/AndroidManifest.xml +16 -0
  7. package/android/src/main/java/io/capkit/rank/RankConfig.kt +72 -0
  8. package/android/src/main/java/io/capkit/rank/RankError.kt +40 -0
  9. package/android/src/main/java/io/capkit/rank/RankImpl.kt +240 -0
  10. package/android/src/main/java/io/capkit/rank/RankPlugin.kt +312 -0
  11. package/android/src/main/java/io/capkit/rank/utils/RankLogger.kt +85 -0
  12. package/android/src/main/java/io/capkit/rank/utils/RankUtils.kt +14 -0
  13. package/android/src/main/res/.gitkeep +0 -0
  14. package/dist/docs.json +441 -0
  15. package/dist/esm/definitions.d.ts +330 -0
  16. package/dist/esm/definitions.js +21 -0
  17. package/dist/esm/definitions.js.map +1 -0
  18. package/dist/esm/index.d.ts +16 -0
  19. package/dist/esm/index.js +19 -0
  20. package/dist/esm/index.js.map +1 -0
  21. package/dist/esm/web.d.ts +81 -0
  22. package/dist/esm/web.js +157 -0
  23. package/dist/esm/web.js.map +1 -0
  24. package/dist/plugin.cjs.js +204 -0
  25. package/dist/plugin.cjs.js.map +1 -0
  26. package/dist/plugin.js +207 -0
  27. package/dist/plugin.js.map +1 -0
  28. package/ios/Sources/RankPlugin/RankConfig.swift +89 -0
  29. package/ios/Sources/RankPlugin/RankError.swift +49 -0
  30. package/ios/Sources/RankPlugin/RankImpl.swift +186 -0
  31. package/ios/Sources/RankPlugin/RankPlugin.swift +258 -0
  32. package/ios/Sources/RankPlugin/Utils/RankLogger.swift +69 -0
  33. package/ios/Sources/RankPlugin/Utils/RankUtils.swift +45 -0
  34. package/ios/Sources/RankPlugin/Version.swift +16 -0
  35. package/ios/Tests/RankPluginTests/RankPluginTests.swift +10 -0
  36. package/package.json +102 -0
@@ -0,0 +1,17 @@
1
+ require 'json'
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = 'CapKitRank'
7
+ s.version = package['version']
8
+ s.summary = package['description']
9
+ s.license = package['license']
10
+ s.homepage = package['repository']['url']
11
+ s.author = package['author']
12
+ s.source = { :git => package['repository']['url'], :tag => s.version.to_s }
13
+ s.source_files = 'ios/Sources/**/*.{swift,h,m,c,cc,mm,cpp}'
14
+ s.ios.deployment_target = '15.0'
15
+ s.dependency 'Capacitor'
16
+ s.swift_version = '5.1'
17
+ end
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 CapKit Team
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/Package.swift ADDED
@@ -0,0 +1,28 @@
1
+ // swift-tools-version: 5.9
2
+ import PackageDescription
3
+
4
+ let package = Package(
5
+ name: "CapKitRank",
6
+ platforms: [.iOS(.v15)],
7
+ products: [
8
+ .library(
9
+ name: "CapKitRank",
10
+ targets: ["RankPlugin"])
11
+ ],
12
+ dependencies: [
13
+ .package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "8.0.2")
14
+ ],
15
+ targets: [
16
+ .target(
17
+ name: "RankPlugin",
18
+ dependencies: [
19
+ .product(name: "Capacitor", package: "capacitor-swift-pm"),
20
+ .product(name: "Cordova", package: "capacitor-swift-pm")
21
+ ],
22
+ path: "ios/Sources/RankPlugin",
23
+ linkerSettings: [
24
+ .linkedFramework("StoreKit")
25
+ ]
26
+ )
27
+ ]
28
+ )
package/README.md ADDED
@@ -0,0 +1,574 @@
1
+ <p align="center">
2
+ <img
3
+ src="https://raw.githubusercontent.com/cap-kit/capacitor-plugins/main/assets/logo.png"
4
+ alt="CapKit Logo"
5
+ width="128"
6
+ />
7
+ </p>
8
+
9
+ <h3 align="center">Rank</h3>
10
+ <p align="center">
11
+ <strong>
12
+ <code>@cap-kit/rank</code>
13
+ </strong>
14
+ </p>
15
+
16
+ <p align="center">
17
+ A high-performance Capacitor v8 plugin for unified <strong>In-App Reviews</strong> and <strong>Market Navigation</strong>.<br>
18
+ Built with a strict <strong>layered architecture</strong>, it serves as both a production-ready tool for app growth and an architectural reference for the CapKit ecosystem.<br>
19
+ </p>
20
+
21
+ <p align="center">
22
+ <a href="https://www.npmjs.com/package/@cap-kit/rank">
23
+ <img src="https://img.shields.io/npm/v/@cap-kit/rank?color=blue&label=npm&logo=npm&style=flat-square" alt="npm version">
24
+ </a>
25
+ <a href="https://github.com/cap-kit/capacitor-plugins/actions">
26
+ <img src="https://img.shields.io/github/actions/workflow/status/cap-kit/capacitor-plugins/ci.yml?branch=main&label=CI&logo=github&style=flat-square" alt="CI Status" />
27
+ </a>
28
+ <a href="https://capacitorjs.com/">
29
+ <img src="https://img.shields.io/badge/Capacitor-Plugin-blue?logo=capacitor&style=flat-square" alt="Capacitor Plugin">
30
+ </a>
31
+ <a href="https://www.npmjs.com/package/@cap-kit/rank">
32
+ <img src="https://img.shields.io/npm/dm/@cap-kit/rank?style=flat-square" alt="Downloads" />
33
+ </a>
34
+ <a href="./LICENSE">
35
+ <img src="https://img.shields.io/npm/l/@cap-kit/rank?style=flat-square&logo=open-source-initiative&logoColor=white&color=green" alt="License" />
36
+ </a>
37
+ <img src="https://img.shields.io/maintenance/yes/2026?style=flat-square" alt="Maintained" />
38
+ </p>
39
+ <br>
40
+
41
+ ## Install
42
+
43
+ ```bash
44
+ pnpm add @cap-kit/rank
45
+ npx cap sync
46
+
47
+ ```
48
+
49
+ ## Configuration
50
+
51
+ Configuration options for the Rank plugin.
52
+
53
+ | Prop | Type | Description | Default | Since |
54
+ | ------------------------ | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | ----- |
55
+ | **`verboseLogging`** | <code>boolean</code> | Enables verbose native logging. When enabled, additional debug information is printed to the native console (Logcat on Android, Xcode on iOS). | <code>false</code> | 8.0.0 |
56
+ | **`appleAppId`** | <code>string</code> | The Apple App ID used for App Store redirection on iOS. Example: '123456789' \* @since 8.0.0 | | |
57
+ | **`androidPackageName`** | <code>string</code> | The Android Package Name used for Play Store redirection. Example: 'com.example.app' \* @since 8.0.0 | | |
58
+ | **`fireAndForget`** | <code>boolean</code> | If true, the `requestReview` method will resolve immediately without waiting for the native OS review flow to complete. \* @default false | | 8.0.0 |
59
+
60
+ ### Examples
61
+
62
+ In `capacitor.config.json`:
63
+
64
+ ```json
65
+ {
66
+ "plugins": {
67
+ "Rank": {
68
+ "verboseLogging": true,
69
+ "appleAppId": "123456789",
70
+ "androidPackageName": "com.example.app",
71
+ "fireAndForget": false
72
+ }
73
+ }
74
+ }
75
+ ```
76
+
77
+ In `capacitor.config.ts`:
78
+
79
+ ```ts
80
+ /// <reference types="@cap-kit/rank" />
81
+
82
+ import { CapacitorConfig } from '@capacitor/cli';
83
+
84
+ const config: CapacitorConfig = {
85
+ plugins: {
86
+ Rank: {
87
+ verboseLogging: true,
88
+ appleAppId: '123456789',
89
+ androidPackageName: 'com.example.app',
90
+ fireAndForget: false,
91
+ },
92
+ },
93
+ };
94
+
95
+ export default config;
96
+ ```
97
+
98
+ ## Native Requirements
99
+
100
+ ### Android
101
+
102
+ - Requires **Google Play Services** for In-App Reviews.
103
+ - To support **Android 11+ (API 30+)** and allow navigation to the Play Store, you must include the following in your `AndroidManifest.xml`:
104
+
105
+ ```xml
106
+ <queries>
107
+ <intent>
108
+ <action android:name="android.intent.action.VIEW" />
109
+ <data android:scheme="market" />
110
+ </intent>
111
+ <intent>
112
+ <action android:name="android.intent.action.VIEW" />
113
+ <data android:scheme="https" android:host="play.google.com" />
114
+ </intent>
115
+ </queries>
116
+ ```
117
+
118
+ ### iOS
119
+
120
+ - Requires **Xcode 26** and **iOS 15+**.
121
+ - To allow the plugin to open the App Store review page, ensure your `Info.plist` includes the appropriate URL schemes if you perform programmatic checks.
122
+
123
+ ---
124
+
125
+ ## Permissions
126
+
127
+ ### Android
128
+
129
+ This plugin requires the following permission, which is automatically merged into your application's `AndroidManifest.xml`:
130
+
131
+ - `android.permission.INTERNET`: Required to communicate with Google Play Services for the review flow and store navigation.
132
+
133
+ ### iOS
134
+
135
+ No specific usage descriptions (Privacy Manifest) are required for the standard `SKStoreReviewController` flow.
136
+
137
+ ---
138
+
139
+ ## API
140
+
141
+ <docgen-index>
142
+
143
+ * [`isAvailable()`](#isavailable)
144
+ * [`checkReviewEnvironment()`](#checkreviewenvironment)
145
+ * [`requestReview(...)`](#requestreview)
146
+ * [`presentProductPage(...)`](#presentproductpage)
147
+ * [`openStore(...)`](#openstore)
148
+ * [`openStoreListing(...)`](#openstorelisting)
149
+ * [`search(...)`](#search)
150
+ * [`openDevPage(...)`](#opendevpage)
151
+ * [`openCollection(...)`](#opencollection)
152
+ * [`getPluginVersion()`](#getpluginversion)
153
+ * [Interfaces](#interfaces)
154
+
155
+ </docgen-index>
156
+
157
+ <docgen-api>
158
+ <!--Update the source file JSDoc comments and rerun docgen to update the docs below-->
159
+
160
+ Public JavaScript API for the Rank Capacitor plugin.
161
+
162
+ This interface defines a stable, platform-agnostic API.
163
+ All methods behave consistently across Android, iOS, and Web.
164
+
165
+ ### isAvailable()
166
+
167
+ ```typescript
168
+ isAvailable() => Promise<AvailabilityResult>
169
+ ```
170
+
171
+ Checks if the native In-App Review UI can be displayed.
172
+ On Android, it verifies Google Play Services availability.
173
+ On iOS, it checks the OS version compatibility.
174
+
175
+ **Returns:** <code>Promise&lt;<a href="#availabilityresult">AvailabilityResult</a>&gt;</code>
176
+
177
+ **Since:** 8.0.0
178
+
179
+ #### Example
180
+
181
+ ```ts
182
+ const { value } = await Rank.isAvailable();
183
+ if (value) {
184
+ // Show review prompt or related UI
185
+ } else {
186
+ // Fallback behavior for unsupported platforms
187
+ }
188
+ ```
189
+
190
+ --------------------
191
+
192
+
193
+ ### checkReviewEnvironment()
194
+
195
+ ```typescript
196
+ checkReviewEnvironment() => Promise<ReviewEnvironmentResult>
197
+ ```
198
+
199
+ Performs a diagnostic check to determine whether the
200
+ Google Play In-App Review dialog can be displayed.
201
+
202
+ This does NOT trigger the review flow.
203
+ Android-only. On other platforms, it resolves as unavailable.
204
+
205
+ **Returns:** <code>Promise&lt;<a href="#reviewenvironmentresult">ReviewEnvironmentResult</a>&gt;</code>
206
+
207
+ **Since:** 8.0.0
208
+
209
+ --------------------
210
+
211
+
212
+ ### requestReview(...)
213
+
214
+ ```typescript
215
+ requestReview(options?: ReviewOptions | undefined) => Promise<void>
216
+ ```
217
+
218
+ Requests the display of the native review popup.
219
+ On Web, this operation calls unimplemented().
220
+
221
+ | Param | Type | Description |
222
+ | ------------- | ------------------------------------------------------- | ---------------------------------------- |
223
+ | **`options`** | <code><a href="#reviewoptions">ReviewOptions</a></code> | Optional review configuration overrides. |
224
+
225
+ **Since:** 8.0.0
226
+
227
+ #### Example
228
+
229
+ ```ts
230
+ // Basic usage with default configuration
231
+ await Rank.requestReview();
232
+
233
+ // Usage with fire-and-forget behavior
234
+ await Rank.requestReview({ fireAndForget: true });
235
+ ```
236
+
237
+ --------------------
238
+
239
+
240
+ ### presentProductPage(...)
241
+
242
+ ```typescript
243
+ presentProductPage(options?: StoreOptions | undefined) => Promise<void>
244
+ ```
245
+
246
+ Opens the App Store product page internally (iOS) or redirects to the Store (Android/Web).
247
+
248
+ | Param | Type | Description |
249
+ | ------------- | ----------------------------------------------------- | --------------------- |
250
+ | **`options`** | <code><a href="#storeoptions">StoreOptions</a></code> | Store identification. |
251
+
252
+ **Since:** 8.0.0
253
+
254
+ #### Example
255
+
256
+ ```ts
257
+ // On iOS, this will open an internal App Store overlay.
258
+ await Rank.presentProductPage({
259
+ appId: '123456789' // iOS App ID for URL generation
260
+ });
261
+
262
+ // On Android, this will redirect to the Play Store.
263
+ await Rank.presentProductPage({
264
+ packageName: 'com.example.app' // Android Package Name for URL generation
265
+ });
266
+ ```
267
+
268
+ --------------------
269
+
270
+
271
+ ### openStore(...)
272
+
273
+ ```typescript
274
+ openStore(options?: StoreOptions | undefined) => Promise<void>
275
+ ```
276
+
277
+ Opens the app's page in the App Store (iOS) or Play Store (Android).
278
+ On Web, it performs a URL redirect if parameters are provided.
279
+
280
+ | Param | Type | Description |
281
+ | ------------- | ----------------------------------------------------- | ---------------------------------------- |
282
+ | **`options`** | <code><a href="#storeoptions">StoreOptions</a></code> | Optional store identification overrides. |
283
+
284
+ **Since:** 8.0.0
285
+
286
+ #### Example
287
+
288
+ ```ts
289
+ // On Web, this will open the store page in a new tab if identifiers are provided.
290
+ await Rank.openStore({
291
+ appId: '123456789', // iOS App ID for URL generation
292
+ packageName: 'com.example.app' // Android Package Name for URL generation
293
+ });
294
+ ```
295
+
296
+ --------------------
297
+
298
+
299
+ ### openStoreListing(...)
300
+
301
+ ```typescript
302
+ openStoreListing(options?: { appId?: string | undefined; } | undefined) => Promise<void>
303
+ ```
304
+
305
+ Opens the App Store listing page for a specific app.
306
+ If no appId is provided, it uses the one from the plugin configuration.
307
+
308
+ | Param | Type |
309
+ | ------------- | -------------------------------- |
310
+ | **`options`** | <code>{ appId?: string; }</code> |
311
+
312
+ **Since:** 8.0.0
313
+
314
+ #### Example
315
+
316
+ ```ts
317
+ // Opens the store listing page.
318
+ // Uses the provided appId or falls back to the one in capacitor.config.ts
319
+ await Rank.openStoreListing({
320
+ appId: '123456789'
321
+ });
322
+ ```
323
+
324
+ --------------------
325
+
326
+
327
+ ### search(...)
328
+
329
+ ```typescript
330
+ search(options: { terms: string; }) => Promise<void>
331
+ ```
332
+
333
+ Performs a search in the app store for the given terms.
334
+
335
+ | Param | Type |
336
+ | ------------- | ------------------------------- |
337
+ | **`options`** | <code>{ terms: string; }</code> |
338
+
339
+ **Since:** 8.0.0
340
+
341
+ #### Example
342
+
343
+ ```ts
344
+ // Searches the store for specific terms.
345
+ // Android: market://search | iOS: itms-apps search
346
+ await Rank.search({
347
+ terms: 'Capacitor Plugins'
348
+ });
349
+ ```
350
+
351
+ --------------------
352
+
353
+
354
+ ### openDevPage(...)
355
+
356
+ ```typescript
357
+ openDevPage(options: { devId: string; }) => Promise<void>
358
+ ```
359
+
360
+ Opens the developer's page in the app store.
361
+
362
+ | Param | Type |
363
+ | ------------- | ------------------------------- |
364
+ | **`options`** | <code>{ devId: string; }</code> |
365
+
366
+ **Since:** 8.0.0
367
+
368
+ #### Example
369
+
370
+ ```ts
371
+ // Navigates to a developer or brand page.
372
+ await Rank.openDevPage({
373
+ devId: '543216789'
374
+ });
375
+ ```
376
+
377
+ --------------------
378
+
379
+
380
+ ### openCollection(...)
381
+
382
+ ```typescript
383
+ openCollection(options: { name: string; }) => Promise<void>
384
+ ```
385
+
386
+ Opens a specific app collection (Android Only).
387
+
388
+ | Param | Type |
389
+ | ------------- | ------------------------------ |
390
+ | **`options`** | <code>{ name: string; }</code> |
391
+
392
+ **Since:** 8.0.0
393
+
394
+ #### Example
395
+
396
+ ```ts
397
+ // Opens a curated collection (Android only).
398
+ await Rank.openCollection({
399
+ name: 'editors_choice'
400
+ });
401
+ ```
402
+
403
+ --------------------
404
+
405
+
406
+ ### getPluginVersion()
407
+
408
+ ```typescript
409
+ getPluginVersion() => Promise<PluginVersionResult>
410
+ ```
411
+
412
+ Returns the native plugin version.
413
+
414
+ The returned version corresponds to the native implementation
415
+ bundled with the application.
416
+
417
+ **Returns:** <code>Promise&lt;<a href="#pluginversionresult">PluginVersionResult</a>&gt;</code>
418
+
419
+ **Since:** 8.0.0
420
+
421
+ #### Example
422
+
423
+ ```ts
424
+ const { version } = await Rank.getPluginVersion();
425
+ ```
426
+
427
+ --------------------
428
+
429
+
430
+ ### Interfaces
431
+
432
+
433
+ #### AvailabilityResult
434
+
435
+ Result object returned by the `isAvailable()` method.
436
+
437
+ | Prop | Type | Description |
438
+ | ----------- | -------------------- | ----------------------------------------------------------- |
439
+ | **`value`** | <code>boolean</code> | Indicates whether the native In-App Review UI is available. |
440
+
441
+
442
+ #### ReviewEnvironmentResult
443
+
444
+ Diagnostic result for Android In-App Review availability.
445
+
446
+ This result describes whether the Google Play Review
447
+ flow can actually be displayed in the current environment.
448
+
449
+ | Prop | Type | Description |
450
+ | ---------------------- | -------------------------------------------------------------------------- | ------------------------------------------------------------------ |
451
+ | **`canRequestReview`** | <code>boolean</code> | True if the environment supports showing the review dialog. |
452
+ | **`reason`** | <code>'PLAY_STORE_NOT_AVAILABLE' \| 'NOT_INSTALLED_FROM_PLAY_STORE'</code> | Optional diagnostic reason when the review dialog cannot be shown. |
453
+
454
+
455
+ #### ReviewOptions
456
+
457
+ Options for the `requestReview` method.
458
+
459
+ | Prop | Type | Description |
460
+ | ------------------- | -------------------- | --------------------------------------------------------------------------------------------------------------------- |
461
+ | **`fireAndForget`** | <code>boolean</code> | Override the global configuration to determine if the promise should resolve immediately or wait for the native flow. |
462
+
463
+
464
+ #### StoreOptions
465
+
466
+ Options for the `openStore` method.
467
+
468
+ | Prop | Type | Description |
469
+ | ----------------- | ------------------- | ---------------------------------------------- |
470
+ | **`appId`** | <code>string</code> | Runtime override for the Apple App ID on iOS. |
471
+ | **`packageName`** | <code>string</code> | Runtime override for the Android Package Name. |
472
+
473
+
474
+ #### PluginVersionResult
475
+
476
+ Result object returned by the `getPluginVersion()` method.
477
+
478
+ | Prop | Type | Description |
479
+ | ------------- | ------------------- | --------------------------------- |
480
+ | **`version`** | <code>string</code> | The native plugin version string. |
481
+
482
+ </docgen-api>
483
+
484
+ ---
485
+
486
+ ## Limitations
487
+
488
+ ### General
489
+
490
+ - **`openCollection`**: This feature is specific to the Google Play Store and is unavailable on iOS/Web.
491
+ - **`openDevPage`**: On iOS, this method performs a store search for the developer name as a fallback, as direct developer page IDs are not consistently supported via deep links.
492
+
493
+ ### iOS
494
+
495
+ - The in-app review prompt is **not guaranteed to appear**.
496
+ Apple internally controls when and how often the review dialog is shown.
497
+ - Calling `requestReview()` may result in **no visible UI**, even if the API is available.
498
+
499
+ ### Android
500
+
501
+ - Google Play In-App Review requires **Google Play Services** to be available on the device.
502
+ - The review flow may silently fail if Play Services are missing, outdated, or restricted.
503
+ - As with iOS, the system ultimately decides whether the review dialog is displayed.
504
+
505
+ ---
506
+
507
+ ## Best practices
508
+
509
+ - Call `requestReview()` only after a **positive user interaction**
510
+ (e.g. completed task, successful checkout, achieved milestone).
511
+ - Avoid calling the review prompt on app startup or without user context.
512
+ - Always check availability first:
513
+
514
+ ```ts
515
+ const { value } = await Rank.isAvailable();
516
+ if (value) {
517
+ await Rank.requestReview();
518
+ }
519
+ ```
520
+
521
+ - Use `fireAndForget: true` only when you do not need to track completion
522
+ and want to avoid blocking UI flows.
523
+
524
+ ---
525
+
526
+ ## Error handling
527
+
528
+ All Rank plugin methods return Promises and may reject in case of failure.
529
+ Consumers should always handle errors using `try / catch`.
530
+
531
+ ### Example
532
+
533
+ ```ts
534
+ import { Rank, RankErrorCode } from '@cap-kit/rank';
535
+
536
+ try {
537
+ await Rank.requestReview();
538
+ } catch (err: any) {
539
+ switch (err.code) {
540
+ case RankErrorCode.UNAVAILABLE:
541
+ // Feature not supported on this device or platform
542
+ break;
543
+
544
+ case RankErrorCode.INIT_FAILED:
545
+ // Native initialization or runtime failure
546
+ break;
547
+
548
+ default:
549
+ // Unknown or unexpected error
550
+ console.error(err.message);
551
+ }
552
+ }
553
+ ```
554
+
555
+ ### Error codes
556
+
557
+ The following error codes may be returned by the plugin:
558
+
559
+ - `UNAVAILABLE` — The feature is not supported on the current device or platform
560
+ - `PERMISSION_DENIED` — A required permission was denied (platform-dependent)
561
+ - `INIT_FAILED` — Native initialization or runtime failure
562
+ - `UNKNOWN_TYPE` — Invalid or unsupported input
563
+
564
+ ---
565
+
566
+ ## Contributing
567
+
568
+ Contributions are welcome! Please read the [contributing guide](CONTRIBUTING.md) before submitting a pull request.
569
+
570
+ ---
571
+
572
+ ## License
573
+
574
+ MIT