@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,186 @@
1
+ import Foundation
2
+ import StoreKit
3
+
4
+ /**
5
+ * Native iOS implementation for the Rank plugin.
6
+ *
7
+ * This class contains pure platform logic and is isolated from the Capacitor bridge.
8
+ * Architectural constraints:
9
+ * - MUST NOT access CAPPluginCall.
10
+ * - MUST NOT depend on Capacitor bridge APIs directly.
11
+ * - MUST perform UI operations on the Main Thread.
12
+ */
13
+ @objc public final class RankImpl: NSObject {
14
+
15
+ // MARK: - Properties
16
+
17
+ /// Cached plugin configuration containing logging and behavioral flags.
18
+ private var config: RankConfig?
19
+
20
+ // MARK: - Initialization
21
+
22
+ /**
23
+ * Initializes the implementation instance.
24
+ */
25
+ override init() {
26
+ super.init()
27
+ }
28
+
29
+ // MARK: - Configuration
30
+
31
+ /**
32
+ * Applies static plugin configuration.
33
+ *
34
+ * This method MUST be called exactly once from the Plugin bridge layer during `load()`.
35
+ * It synchronizes the native logger state with the provided configuration.
36
+ *
37
+ * - Parameter config: The immutable configuration container.
38
+ */
39
+ func applyConfig(_ config: RankConfig) {
40
+ precondition(
41
+ self.config == nil,
42
+ "RankImpl.applyConfig(_:) must be called exactly once"
43
+ )
44
+ self.config = config
45
+ RankLogger.verbose = config.verboseLogging
46
+
47
+ RankLogger.debug(
48
+ "Configuration applied. Verbose logging:",
49
+ config.verboseLogging
50
+ )
51
+ }
52
+
53
+ // MARK: - Availability
54
+
55
+ /**
56
+ * Checks if the current iOS version supports the SKStoreReviewController API.
57
+ * Since the plugin target is iOS 15+, this generally returns true.
58
+ */
59
+ @objc public func isAvailable() -> Bool {
60
+ if #available(iOS 10.3, *) {
61
+ return true
62
+ }
63
+ return false
64
+ }
65
+
66
+ // MARK: - Product Page
67
+
68
+ /**
69
+ * Presents the App Store product page within the application.
70
+ * * - Parameter appId: The numeric Apple App ID.
71
+ * - Parameter completion: Callback to signal when the page has been loaded or failed.
72
+ */
73
+ @objc public func presentProductPage(appId: String, completion: @escaping (Bool, Error?) -> Void) {
74
+ let storeViewController = SKStoreProductViewController()
75
+ let parameters = [SKStoreProductParameterITunesItemIdentifier: appId]
76
+
77
+ // UI operations must be on the main thread
78
+ DispatchQueue.main.async {
79
+ storeViewController.loadProduct(withParameters: parameters) { success, error in
80
+ if success {
81
+ // Attempt to find the top-most view controller to present the sheet
82
+ if let rootVC = UIApplication.shared.windows.first?.rootViewController {
83
+ rootVC.present(storeViewController, animated: true) {
84
+ completion(true, nil)
85
+ }
86
+ } else {
87
+ completion(false, nil)
88
+ }
89
+ } else {
90
+ completion(false, error)
91
+ }
92
+ }
93
+ }
94
+ }
95
+
96
+ // MARK: - Review Methods
97
+
98
+ /**
99
+ * Triggers the native iOS In-App Review prompt.
100
+ *
101
+ * Uses the modern `requestReview(in:)` API for iOS 14+ by identifying the active foreground scene.
102
+ * Fallback logic is provided for older iOS versions (though the plugin target is iOS 15+).
103
+ *
104
+ * NOTE: The OS manages the frequency of this prompt; calling this does not guarantee a UI will appear.
105
+ */
106
+ @objc public func requestReview() {
107
+ if #available(iOS 14.0, *) {
108
+ let activeScene = UIApplication.shared.connectedScenes
109
+ .compactMap { $0 as? UIWindowScene }
110
+ .first { $0.activationState == .foregroundActive }
111
+
112
+ guard let windowScene = activeScene else {
113
+ // Diagnostic logging only: review prompt cannot be requested without an active scene
114
+ RankLogger.error("Cannot request review: no active UIWindowScene found")
115
+ return
116
+ }
117
+
118
+ RankLogger.debug("Requesting in-app review for active UIWindowScene")
119
+ SKStoreReviewController.requestReview(in: windowScene)
120
+ } else {
121
+ // Legacy fallback (not expected to be used due to iOS 15+ minimum target)
122
+ RankLogger.debug("Requesting in-app review using legacy API")
123
+ SKStoreReviewController.requestReview()
124
+ }
125
+ }
126
+
127
+ // MARK: - Store Navigation
128
+
129
+ /**
130
+ * Opens the App Store page for the specified application ID.
131
+ *
132
+ * This method constructs a deep link using the `itms-apps` scheme to direct the user
133
+ * to the review section of the application's store page.
134
+ *
135
+ * - Parameter appId: The numeric Apple App ID (e.g., "123456789").
136
+ */
137
+ @objc public func openStore(appId: String) {
138
+ guard let url = RankUtils.appStoreURL(appId: appId) else {
139
+ RankLogger.error("Invalid App Store URL for ID: \(appId)")
140
+ return
141
+ }
142
+
143
+ // RULE: All UI-related operations MUST be dispatched to the main thread.
144
+ DispatchQueue.main.async {
145
+ UIApplication.shared.open(url, options: [:]) { success in
146
+ if success {
147
+ RankLogger.debug("App Store opened successfully.")
148
+ } else {
149
+ RankLogger.error("Failed to open App Store URL.")
150
+ }
151
+ }
152
+ }
153
+ }
154
+
155
+ /**
156
+ * Opens the App Store product page for the specified application ID.
157
+ *
158
+ * This method constructs a deep link using the `itms-apps` scheme to direct the user
159
+ * to the product page of the application in the App Store.
160
+ *
161
+ * - Parameter appId: The numeric Apple App ID (e.g., "123456789").
162
+ */
163
+ @objc public func openStoreListing(appId: String) {
164
+ let urlString = "itms-apps://itunes.apple.com/app/id\(appId)"
165
+ if let url = URL(string: urlString) {
166
+ DispatchQueue.main.async {
167
+ UIApplication.shared.open(url)
168
+ }
169
+ }
170
+ }
171
+
172
+ /**
173
+ * Opens the App Store search page with the specified search terms.
174
+ *
175
+ * This method constructs a deep link using the `itms-apps` scheme to direct the user
176
+ * to the search results page in the App Store for the given terms.
177
+ *
178
+ * - Parameter terms: The search query string to find relevant apps in the App Store.
179
+ */
180
+ @objc public func search(terms: String) {
181
+ guard let url = RankUtils.searchURL(terms: terms) else { return }
182
+ DispatchQueue.main.async {
183
+ UIApplication.shared.open(url)
184
+ }
185
+ }
186
+ }
@@ -0,0 +1,258 @@
1
+ import Foundation
2
+ import Capacitor
3
+
4
+ /**
5
+ * Capacitor bridge for the Rank plugin.
6
+ *
7
+ * This class handles the communication between the JavaScript layer and the native iOS implementation.
8
+ * It is responsible for input validation, configuration merging, and thread safety.
9
+ */
10
+ @objc(RankPlugin)
11
+ public final class RankPlugin: CAPPlugin, CAPBridgedPlugin {
12
+
13
+ // MARK: - Properties
14
+
15
+ /// An instance of the implementation class that contains the plugin's core functionality.
16
+ private let implementation = RankImpl()
17
+
18
+ /// Internal storage for the plugin configuration read from capacitor.config.ts.
19
+ private var config: RankConfig?
20
+
21
+ /// The unique identifier for the plugin used by the Capacitor bridge.
22
+ public let identifier = "RankPlugin"
23
+
24
+ /// The name used to reference this plugin in JavaScript (e.g., Rank.requestReview()).
25
+ public let jsName = "Rank"
26
+
27
+ /**
28
+ * A list of methods exposed by this plugin to the JavaScript layer.
29
+ * All methods defined here must be implemented with the @objc attribute.
30
+ - `isAvailable`: Checks if the native review prompt can be shown on the current device.
31
+ - `requestReview`: Triggers the native iOS In-App Review prompt.
32
+ - `presentProductPage`: Navigates the user to the App Store product page within the app.
33
+ - `openStore`: Opens the app's page on the App Store for leaving a review or viewing details.
34
+ - `getPluginVersion`: A method that returns the version of the plugin.
35
+ */
36
+ public let pluginMethods: [CAPPluginMethod] = [
37
+ CAPPluginMethod(name: "isAvailable", returnType: CAPPluginReturnPromise),
38
+ CAPPluginMethod(name: "requestReview", returnType: CAPPluginReturnPromise),
39
+ CAPPluginMethod(name: "presentProductPage", returnType: CAPPluginReturnPromise),
40
+ CAPPluginMethod(name: "openStore", returnType: CAPPluginReturnPromise),
41
+ CAPPluginMethod(name: "getPluginVersion", returnType: CAPPluginReturnPromise)
42
+ ]
43
+
44
+ // MARK: - Lifecycle
45
+
46
+ /**
47
+ * Plugin lifecycle entry point.
48
+ *
49
+ * Called once when the plugin is loaded. This method initializes the configuration
50
+ * and prepares the native implementation.
51
+ */
52
+ override public func load() {
53
+ // Initialize RankConfig with the correct type
54
+ let cfg = RankConfig(plugin: self)
55
+ self.config = cfg
56
+ implementation.applyConfig(cfg)
57
+
58
+ // Log if verbose logging is enabled
59
+ RankLogger.debug("Rank plugin loaded.")
60
+ }
61
+
62
+ // MARK: - Error Mapping
63
+
64
+ /**
65
+ * Maps native RankError categories to standardized JS-facing error codes.
66
+ *
67
+ * - Parameters:
68
+ * - call: The CAPPluginCall to reject.
69
+ * - error: The native RankError encountered during execution.
70
+ */
71
+ private func reject(
72
+ _ call: CAPPluginCall,
73
+ error: RankError
74
+ ) {
75
+ let code: String
76
+
77
+ switch error {
78
+ case .unavailable:
79
+ code = "UNAVAILABLE"
80
+ case .permissionDenied:
81
+ code = "PERMISSION_DENIED"
82
+ case .initFailed:
83
+ code = "INIT_FAILED"
84
+ case .unknownType:
85
+ code = "UNKNOWN_TYPE"
86
+ }
87
+
88
+ call.reject(error.message, code)
89
+ }
90
+
91
+ // MARK: - Availability
92
+
93
+ /**
94
+ * Checks if the native In-App Review prompt can be displayed on the current device.
95
+ *
96
+ * This method verifies if the necessary APIs are available and if the OS version is compatible.
97
+ * It returns a boolean indicating availability, which can be used by the JavaScript layer to
98
+ * conditionally show review prompts or fallback UI.
99
+ *
100
+ * - Parameter call: CAPPluginCall used to return the availability result.
101
+ */
102
+ @objc func isAvailable(_ call: CAPPluginCall) {
103
+ let available = implementation.isAvailable()
104
+ call.resolve([
105
+ "value": available
106
+ ])
107
+ }
108
+
109
+ // MARK: - Product Page
110
+
111
+ /**
112
+ * Presents the App Store product page within the application.
113
+ *
114
+ * This method uses SKStoreProductViewController to display the product page without leaving the app.
115
+ * It accepts an optional appId parameter, which can override the global configuration.
116
+ *
117
+ * - Parameter call: CAPPluginCall containing:
118
+ * - appId (String, optional): The Apple App ID. Fallbacks to global config.
119
+ */
120
+ @objc func presentProductPage(_ call: CAPPluginCall) {
121
+ guard let appId = call.getString("appId") ?? config?.appleAppId else {
122
+ call.reject("Apple App ID is missing.", "INIT_FAILED")
123
+ return
124
+ }
125
+
126
+ implementation.presentProductPage(appId: appId) { success, error in
127
+ if success {
128
+ call.resolve()
129
+ } else {
130
+ call.reject(error?.localizedDescription ?? "Failed to load product page.", "INIT_FAILED")
131
+ }
132
+ }
133
+ }
134
+
135
+ // MARK: - Public Plugin Methods
136
+
137
+ /**
138
+ * Triggers the native iOS In-App Review prompt using SKStoreReviewController.
139
+ *
140
+ * This method resolves immediately as iOS does not provide a callback to determine
141
+ * if the prompt was shown or if the user interacted with it.
142
+ *
143
+ * - Parameter call: CAPPluginCall provided by the bridge.
144
+ */
145
+ @objc func requestReview(_ call: CAPPluginCall) {
146
+ // Log the request if verbose logging is enabled
147
+ RankLogger.debug("Requesting review prompt.")
148
+
149
+ // Native iOS SKStoreReviewController logic
150
+ implementation.requestReview()
151
+
152
+ // Always resolve immediately for iOS consistency
153
+ call.resolve()
154
+ }
155
+
156
+ // MARK: - Store Navigation
157
+
158
+ /**
159
+ * Navigates the user to the App Store page for a specific application.
160
+ *
161
+ * - Parameter call: CAPPluginCall containing:
162
+ * - appId (String, optional): The Apple App ID. Fallbacks to global config.
163
+ */
164
+ @objc func openStore(_ call: CAPPluginCall) {
165
+ // Attempt to retrieve the App ID from call parameters or static configuration
166
+ guard let appId = call.getString("appId") ?? config?.appleAppId else {
167
+ call.reject(
168
+ "Apple App ID is missing. Provide it in config or as a parameter.",
169
+ "INIT_FAILED"
170
+ )
171
+ return
172
+ }
173
+
174
+ RankLogger.debug("Opening App Store for ID: \(appId)")
175
+ implementation.openStore(appId: appId)
176
+ call.resolve()
177
+ }
178
+
179
+ /**
180
+ * Opens a collection page on the App Store.
181
+ *
182
+ * This method is not supported on iOS as there is no direct way to link to collections. It will reject with an appropriate message.
183
+ *
184
+ * - Parameter call: CAPPluginCall provided by the bridge.
185
+ */
186
+ @objc func openCollection(_ call: CAPPluginCall) {
187
+ call.unavailable("Collections are not supported on iOS.")
188
+ }
189
+
190
+ /**
191
+ * Opens the App Store page for the specified application ID.
192
+ *
193
+ * This method constructs a deep link using the `itms-apps` scheme to direct the user
194
+ * to the review section of the application's store page.
195
+ *
196
+ * - Parameter appId: The numeric Apple App ID (e.g., "123456789").
197
+ */
198
+ @objc func openStoreListing(_ call: CAPPluginCall) {
199
+ guard let appId = call.getString("appId") ?? config?.appleAppId else {
200
+ call.reject("Apple App ID is missing.", "INIT_FAILED")
201
+ return
202
+ }
203
+ implementation.openStoreListing(appId: appId)
204
+ call.resolve()
205
+ }
206
+
207
+ // MARK: - Search
208
+
209
+ /**
210
+ * Searches the App Store for the given terms.
211
+ *
212
+ * - Parameter call: CAPPluginCall containing:
213
+ * - terms (String): The search query to find apps or developers.
214
+ */
215
+ @objc func search(_ call: CAPPluginCall) {
216
+ guard let terms = call.getString("terms") else {
217
+ call.reject("Search terms are missing.")
218
+ return
219
+ }
220
+ implementation.search(terms: terms)
221
+ call.resolve()
222
+ }
223
+
224
+ // MARK: - Developer Page
225
+
226
+ /**
227
+ * Opens the developer's page on the App Store.
228
+ *
229
+ * Since iOS does not have a direct link for developer pages, this method performs a search using the developer's name or ID.
230
+ *
231
+ * - Parameter call: CAPPluginCall containing:
232
+ * - devId (String): The developer identifier or name to search for.
233
+ */
234
+ @objc func openDevPage(_ call: CAPPluginCall) {
235
+ guard let devId = call.getString("devId") else {
236
+ call.reject("devId is missing.")
237
+ return
238
+ }
239
+ implementation.search(terms: devId) // Fallback on iOS
240
+ call.resolve()
241
+ }
242
+
243
+ // MARK: - Version
244
+
245
+ /**
246
+ * Retrieves the current native plugin version.
247
+ *
248
+ * This version is synchronized from the project's package.json during the build process.
249
+ *
250
+ * - Parameter call: CAPPluginCall used to return the version string.
251
+ */
252
+ @objc func getPluginVersion(_ call: CAPPluginCall) {
253
+ // Standardized enum name across all CapKit plugins
254
+ call.resolve([
255
+ "version": PluginVersion.number
256
+ ])
257
+ }
258
+ }
@@ -0,0 +1,69 @@
1
+ import Capacitor
2
+
3
+ /**
4
+ Centralized native logger for the Rank plugin.
5
+
6
+ Responsibilities:
7
+ - Provide a single logging entry point
8
+ - Support runtime-controlled verbose logging
9
+ - Keep logging behavior consistent across files
10
+
11
+ Forbidden:
12
+ - Controlling application logic
13
+ - Being queried for flow decisions
14
+ */
15
+ enum RankLogger {
16
+
17
+ /**
18
+ Controls whether debug logs are printed.
19
+
20
+ This value MUST be set once during plugin initialization
21
+ based on static configuration.
22
+ */
23
+ static var verbose: Bool = false
24
+
25
+ /**
26
+ Prints a verbose / debug log message.
27
+
28
+ Debug logs are automatically silenced
29
+ when `verbose` is false.
30
+ */
31
+ static func debug(_ items: Any...) {
32
+ guard verbose else { return }
33
+ log(items)
34
+ }
35
+
36
+ /**
37
+ Prints an error log message.
38
+
39
+ Error logs are always printed regardless
40
+ of the verbose flag.
41
+ */
42
+ static func error(_ items: Any...) {
43
+ log(items)
44
+ }
45
+ }
46
+
47
+ // MARK: - Internal log printer
48
+
49
+ /**
50
+ Low-level log printer with a consistent prefix.
51
+
52
+ This function MUST NOT be used outside this file.
53
+ */
54
+ private func log(
55
+ _ items: [Any],
56
+ separator: String = " ",
57
+ terminator: String = "\n"
58
+ ) {
59
+ CAPLog.print("⚡️ Rank -", terminator: separator)
60
+
61
+ for (index, item) in items.enumerated() {
62
+ CAPLog.print(
63
+ item,
64
+ terminator: index == items.count - 1
65
+ ? terminator
66
+ : separator
67
+ )
68
+ }
69
+ }
@@ -0,0 +1,45 @@
1
+ import Foundation
2
+
3
+ /**
4
+ Utility helpers for the Rank plugin.
5
+
6
+ This type is intentionally empty and serves as a placeholder
7
+ for future shared helper functions.
8
+
9
+ Keeping a dedicated utilities file helps maintain a clean
10
+ separation between core logic and helper code.
11
+ */
12
+ struct RankUtils {
13
+ /**
14
+ Builds the App Store URL for the given Apple App ID.
15
+
16
+ - Parameter appId: The numeric Apple App ID.
17
+ - Returns: A valid App Store URL for opening the product page or review flow.
18
+ */
19
+ static func appStoreURL(appId: String) -> URL? {
20
+ let urlString = "itms-apps://itunes.apple.com/app/id\(appId)?action=write-review"
21
+ return URL(string: urlString)
22
+ }
23
+
24
+ /**
25
+ Builds the App Store search URL for the given search terms.
26
+
27
+ - Parameter terms: The search query string.
28
+ - Returns: A valid App Store URL for performing a search.
29
+ */
30
+ static func searchURL(terms: String) -> URL? {
31
+ let encoded = terms.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? ""
32
+ return URL(string: "itms-apps://itunes.apple.com/search?term=\(encoded)")
33
+ }
34
+
35
+ /**
36
+ Builds the App Store URL for a developer page based on the given developer identifier.
37
+
38
+ - Parameter devId: The developer identifier or name.
39
+ - Returns: A valid App Store URL for the developer's page or search results.
40
+ */
41
+ static func devPageURL(devId: String) -> URL? {
42
+ // iOS not have a direct link for DevID, so we use search as fallback
43
+ return searchURL(terms: devId)
44
+ }
45
+ }
@@ -0,0 +1,16 @@
1
+ // This file is automatically generated. Do not modify manually.
2
+ import Foundation
3
+
4
+ /**
5
+ Container for the plugin's version information.
6
+ This enum provides a centralized, single source of truth for the native
7
+ version string, synchronized directly from the project's 'package.json'.
8
+ It ensures parity across JavaScript, Android, and iOS platforms.
9
+ */
10
+ public enum PluginVersion {
11
+ /**
12
+ The semantic version string of the plugin.
13
+ Value synchronized from package.json: "8.0.0"
14
+ */
15
+ public static let number = "8.0.0"
16
+ }
@@ -0,0 +1,10 @@
1
+ import XCTest
2
+ @testable import Rank
3
+
4
+ /**
5
+ Basic functional tests for the Rank plugin native implementation.
6
+
7
+ These tests validate the core behavior of the implementation
8
+ independently from the Capacitor bridge.
9
+ */
10
+ class RankPluginTests: XCTestCase {}
package/package.json ADDED
@@ -0,0 +1,102 @@
1
+ {
2
+ "name": "@cap-kit/rank",
3
+ "version": "8.0.0",
4
+ "description": "Unified Capacitor v8 plugin for native In-App Reviews and cross-platform Store navigation.",
5
+ "type": "module",
6
+ "private": false,
7
+ "engines": {
8
+ "node": ">=24.0.0",
9
+ "pnpm": ">=10.0.0"
10
+ },
11
+ "main": "dist/plugin.cjs.js",
12
+ "module": "dist/esm/index.js",
13
+ "types": "dist/esm/index.d.ts",
14
+ "unpkg": "dist/plugin.js",
15
+ "files": [
16
+ "android/src/main/",
17
+ "android/build.gradle",
18
+ "dist/",
19
+ "ios/Sources",
20
+ "ios/Tests",
21
+ "Package.swift",
22
+ "CapKitRank.podspec",
23
+ "LICENSE"
24
+ ],
25
+ "author": "CapKit Team",
26
+ "license": "MIT",
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "git+https://github.com/cap-kit/capacitor-plugins.git",
30
+ "directory": "packages/rank"
31
+ },
32
+ "bugs": {
33
+ "url": "https://github.com/cap-kit/capacitor-plugins/issues"
34
+ },
35
+ "homepage": "https://github.com/cap-kit/capacitor-plugins/tree/main/packages/rank#readme",
36
+ "keywords": [
37
+ "capacitor",
38
+ "capacitor-plugin",
39
+ "cap-kit",
40
+ "mobile",
41
+ "native",
42
+ "ios",
43
+ "android",
44
+ "rank",
45
+ "market",
46
+ "review"
47
+ ],
48
+ "publishConfig": {
49
+ "access": "public"
50
+ },
51
+ "devDependencies": {
52
+ "@capacitor/cli": "^8.0.2",
53
+ "@capacitor/android": "^8.0.2",
54
+ "@capacitor/core": "^8.0.2",
55
+ "@capacitor/docgen": "^0.3.1",
56
+ "@capacitor/ios": "^8.0.2",
57
+ "@eslint/eslintrc": "^3.3.3",
58
+ "@eslint/js": "^9.39.2",
59
+ "eslint": "^9.39.2",
60
+ "eslint-plugin-import": "^2.32.0",
61
+ "globals": "^17.3.0",
62
+ "prettier": "^3.8.1",
63
+ "prettier-plugin-java": "^2.8.1",
64
+ "rimraf": "^6.1.2",
65
+ "rollup": "^4.57.1",
66
+ "swiftlint": "^2.0.0",
67
+ "typescript": "^5.9.3",
68
+ "typescript-eslint": "^8.54.0"
69
+ },
70
+ "peerDependencies": {
71
+ "@capacitor/core": ">=8.0.2"
72
+ },
73
+ "capacitor": {
74
+ "ios": {
75
+ "src": "ios"
76
+ },
77
+ "android": {
78
+ "src": "android"
79
+ }
80
+ },
81
+ "scripts": {
82
+ "verify": "pnpm run verify:ios && pnpm run verify:android && pnpm run verify:web",
83
+ "verify:ios": "node ./scripts/sync-version.js && xcodebuild -scheme CapKitRank -destination generic/platform=iOS",
84
+ "verify:android": "cd android && ./gradlew clean build test && cd ..",
85
+ "verify:web": "pnpm run build",
86
+ "lint:android": "cd android && ./gradlew ktlintCheck",
87
+ "fmt:android": "cd android && ./gradlew ktlintFormat",
88
+ "lint": "pnpm run eslint . && pnpm run swiftlint lint --strict || true && pnpm run lint:android || true",
89
+ "format:check": "prettier --check \"**/*.{css,html,ts,js,java}\" --plugin=prettier-plugin-java",
90
+ "format": "eslint --fix . && prettier --write \"**/*.{css,html,ts,js,java}\" --plugin=prettier-plugin-java && pnpm run swiftlint --fix --format && pnpm run fmt:android",
91
+ "eslint": "eslint",
92
+ "prettier": "prettier \"**/*.{css,html,ts,js,java}\" --plugin=prettier-plugin-java",
93
+ "swiftlint": "node-swiftlint lint ios/Sources",
94
+ "docgen": "docgen --api RankPlugin --output-readme README.md --output-json dist/docs.json",
95
+ "build": "node ./scripts/sync-version.js && pnpm run clean && pnpm run docgen && tsc && rollup -c rollup.config.mjs",
96
+ "clean": "rimraf ./dist",
97
+ "watch": "tsc --watch",
98
+ "test": "pnpm run verify",
99
+ "removePacked": "rimraf -g cap-kit-rank-*.tgz",
100
+ "publish:locally": "pnpm run removePacked && pnpm run build && pnpm pack"
101
+ }
102
+ }