@capgo/capacitor-persistent-uuid 8.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst PersistentUuid = registerPlugin('PersistentUuid', {\n web: () => import('./web').then((m) => new m.PersistentUuidWeb()),\n});\nexport * from './definitions';\nexport { PersistentUuid };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nconst STORAGE_PREFIX = 'capgo:persistent-uuid:';\nconst DEFAULT_SCOPE = 'web';\nconst memoryStore = new Map();\nconst normalizeScope = (options) => {\n var _a;\n const scope = (_a = options === null || options === void 0 ? void 0 : options.scope) === null || _a === void 0 ? void 0 : _a.trim();\n return scope && scope.length > 0 ? scope : DEFAULT_SCOPE;\n};\nconst createUuid = () => {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (char) => {\n const random = Math.floor(Math.random() * 16);\n const value = char === 'x' ? random : (random & 0x3) | 0x8;\n return value.toString(16);\n });\n};\nconst readValue = (key) => {\n var _a, _b, _c, _d;\n try {\n return (_c = (_b = (_a = globalThis.localStorage) === null || _a === void 0 ? void 0 : _a.getItem(key)) !== null && _b !== void 0 ? _b : memoryStore.get(key)) !== null && _c !== void 0 ? _c : null;\n }\n catch (_e) {\n return (_d = memoryStore.get(key)) !== null && _d !== void 0 ? _d : null;\n }\n};\nconst writeValue = (key, value) => {\n var _a;\n memoryStore.set(key, value);\n try {\n (_a = globalThis.localStorage) === null || _a === void 0 ? void 0 : _a.setItem(key, value);\n }\n catch (_b) {\n // In-memory fallback already updated.\n }\n};\nexport class PersistentUuidWeb extends WebPlugin {\n async getId(options) {\n const scope = normalizeScope(options);\n const key = STORAGE_PREFIX + scope;\n const existing = readValue(key);\n if (existing) {\n return {\n id: existing,\n scope,\n created: false,\n };\n }\n const id = createUuid();\n writeValue(key, id);\n return {\n id,\n scope,\n created: true,\n };\n }\n async resetId(options) {\n const scope = normalizeScope(options);\n const id = createUuid();\n writeValue(STORAGE_PREFIX + scope, id);\n return {\n id,\n scope,\n created: true,\n };\n }\n async getPluginVersion() {\n return {\n version: 'web',\n };\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;;AACK,MAAC,cAAc,GAAGA,mBAAc,CAAC,gBAAgB,EAAE;AACxD,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,iBAAiB,EAAE,CAAC;AACrE,CAAC;;ACFD,MAAM,cAAc,GAAG,wBAAwB;AAC/C,MAAM,aAAa,GAAG,KAAK;AAC3B,MAAM,WAAW,GAAG,IAAI,GAAG,EAAE;AAC7B,MAAM,cAAc,GAAG,CAAC,OAAO,KAAK;AACpC,IAAI,IAAI,EAAE;AACV,IAAI,MAAM,KAAK,GAAG,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,KAAK,MAAM,IAAI,IAAI,EAAE,KAAK,MAAM,GAAG,MAAM,GAAG,EAAE,CAAC,IAAI,EAAE;AACvI,IAAI,OAAO,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,GAAG,KAAK,GAAG,aAAa;AAC5D,CAAC;AACD,MAAM,UAAU,GAAG,MAAM;AACzB,IAAI,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,OAAO,MAAM,CAAC,UAAU,KAAK,UAAU,EAAE;AAClF,QAAQ,OAAO,MAAM,CAAC,UAAU,EAAE;AAClC,IAAI;AACJ,IAAI,OAAO,sCAAsC,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,KAAK;AAC7E,QAAQ,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC;AACrD,QAAQ,MAAM,KAAK,GAAG,IAAI,KAAK,GAAG,GAAG,MAAM,GAAG,CAAC,MAAM,GAAG,GAAG,IAAI,GAAG;AAClE,QAAQ,OAAO,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;AACjC,IAAI,CAAC,CAAC;AACN,CAAC;AACD,MAAM,SAAS,GAAG,CAAC,GAAG,KAAK;AAC3B,IAAI,IAAI,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE;AACtB,IAAI,IAAI;AACR,QAAQ,OAAO,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,UAAU,CAAC,YAAY,MAAM,IAAI,IAAI,EAAE,KAAK,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,IAAI,IAAI,EAAE,KAAK,KAAK,CAAC,GAAG,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,IAAI,IAAI,EAAE,KAAK,KAAK,CAAC,GAAG,EAAE,GAAG,IAAI;AAC5M,IAAI;AACJ,IAAI,OAAO,EAAE,EAAE;AACf,QAAQ,OAAO,CAAC,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,IAAI,IAAI,EAAE,KAAK,MAAM,GAAG,EAAE,GAAG,IAAI;AAChF,IAAI;AACJ,CAAC;AACD,MAAM,UAAU,GAAG,CAAC,GAAG,EAAE,KAAK,KAAK;AACnC,IAAI,IAAI,EAAE;AACV,IAAI,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC;AAC/B,IAAI,IAAI;AACR,QAAQ,CAAC,EAAE,GAAG,UAAU,CAAC,YAAY,MAAM,IAAI,IAAI,EAAE,KAAK,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC;AAClG,IAAI;AACJ,IAAI,OAAO,EAAE,EAAE;AACf;AACA,IAAI;AACJ,CAAC;AACM,MAAM,iBAAiB,SAASC,cAAS,CAAC;AACjD,IAAI,MAAM,KAAK,CAAC,OAAO,EAAE;AACzB,QAAQ,MAAM,KAAK,GAAG,cAAc,CAAC,OAAO,CAAC;AAC7C,QAAQ,MAAM,GAAG,GAAG,cAAc,GAAG,KAAK;AAC1C,QAAQ,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC;AACvC,QAAQ,IAAI,QAAQ,EAAE;AACtB,YAAY,OAAO;AACnB,gBAAgB,EAAE,EAAE,QAAQ;AAC5B,gBAAgB,KAAK;AACrB,gBAAgB,OAAO,EAAE,KAAK;AAC9B,aAAa;AACb,QAAQ;AACR,QAAQ,MAAM,EAAE,GAAG,UAAU,EAAE;AAC/B,QAAQ,UAAU,CAAC,GAAG,EAAE,EAAE,CAAC;AAC3B,QAAQ,OAAO;AACf,YAAY,EAAE;AACd,YAAY,KAAK;AACjB,YAAY,OAAO,EAAE,IAAI;AACzB,SAAS;AACT,IAAI;AACJ,IAAI,MAAM,OAAO,CAAC,OAAO,EAAE;AAC3B,QAAQ,MAAM,KAAK,GAAG,cAAc,CAAC,OAAO,CAAC;AAC7C,QAAQ,MAAM,EAAE,GAAG,UAAU,EAAE;AAC/B,QAAQ,UAAU,CAAC,cAAc,GAAG,KAAK,EAAE,EAAE,CAAC;AAC9C,QAAQ,OAAO;AACf,YAAY,EAAE;AACd,YAAY,KAAK;AACjB,YAAY,OAAO,EAAE,IAAI;AACzB,SAAS;AACT,IAAI;AACJ,IAAI,MAAM,gBAAgB,GAAG;AAC7B,QAAQ,OAAO;AACf,YAAY,OAAO,EAAE,KAAK;AAC1B,SAAS;AACT,IAAI;AACJ;;;;;;;;;"}
package/dist/plugin.js ADDED
@@ -0,0 +1,92 @@
1
+ var capacitorPersistentUuid = (function (exports, core) {
2
+ 'use strict';
3
+
4
+ const PersistentUuid = core.registerPlugin('PersistentUuid', {
5
+ web: () => Promise.resolve().then(function () { return web; }).then((m) => new m.PersistentUuidWeb()),
6
+ });
7
+
8
+ const STORAGE_PREFIX = 'capgo:persistent-uuid:';
9
+ const DEFAULT_SCOPE = 'web';
10
+ const memoryStore = new Map();
11
+ const normalizeScope = (options) => {
12
+ var _a;
13
+ const scope = (_a = options === null || options === void 0 ? void 0 : options.scope) === null || _a === void 0 ? void 0 : _a.trim();
14
+ return scope && scope.length > 0 ? scope : DEFAULT_SCOPE;
15
+ };
16
+ const createUuid = () => {
17
+ if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
18
+ return crypto.randomUUID();
19
+ }
20
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (char) => {
21
+ const random = Math.floor(Math.random() * 16);
22
+ const value = char === 'x' ? random : (random & 0x3) | 0x8;
23
+ return value.toString(16);
24
+ });
25
+ };
26
+ const readValue = (key) => {
27
+ var _a, _b, _c, _d;
28
+ try {
29
+ return (_c = (_b = (_a = globalThis.localStorage) === null || _a === void 0 ? void 0 : _a.getItem(key)) !== null && _b !== void 0 ? _b : memoryStore.get(key)) !== null && _c !== void 0 ? _c : null;
30
+ }
31
+ catch (_e) {
32
+ return (_d = memoryStore.get(key)) !== null && _d !== void 0 ? _d : null;
33
+ }
34
+ };
35
+ const writeValue = (key, value) => {
36
+ var _a;
37
+ memoryStore.set(key, value);
38
+ try {
39
+ (_a = globalThis.localStorage) === null || _a === void 0 ? void 0 : _a.setItem(key, value);
40
+ }
41
+ catch (_b) {
42
+ // In-memory fallback already updated.
43
+ }
44
+ };
45
+ class PersistentUuidWeb extends core.WebPlugin {
46
+ async getId(options) {
47
+ const scope = normalizeScope(options);
48
+ const key = STORAGE_PREFIX + scope;
49
+ const existing = readValue(key);
50
+ if (existing) {
51
+ return {
52
+ id: existing,
53
+ scope,
54
+ created: false,
55
+ };
56
+ }
57
+ const id = createUuid();
58
+ writeValue(key, id);
59
+ return {
60
+ id,
61
+ scope,
62
+ created: true,
63
+ };
64
+ }
65
+ async resetId(options) {
66
+ const scope = normalizeScope(options);
67
+ const id = createUuid();
68
+ writeValue(STORAGE_PREFIX + scope, id);
69
+ return {
70
+ id,
71
+ scope,
72
+ created: true,
73
+ };
74
+ }
75
+ async getPluginVersion() {
76
+ return {
77
+ version: 'web',
78
+ };
79
+ }
80
+ }
81
+
82
+ var web = /*#__PURE__*/Object.freeze({
83
+ __proto__: null,
84
+ PersistentUuidWeb: PersistentUuidWeb
85
+ });
86
+
87
+ exports.PersistentUuid = PersistentUuid;
88
+
89
+ return exports;
90
+
91
+ })({}, capacitorExports);
92
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst PersistentUuid = registerPlugin('PersistentUuid', {\n web: () => import('./web').then((m) => new m.PersistentUuidWeb()),\n});\nexport * from './definitions';\nexport { PersistentUuid };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nconst STORAGE_PREFIX = 'capgo:persistent-uuid:';\nconst DEFAULT_SCOPE = 'web';\nconst memoryStore = new Map();\nconst normalizeScope = (options) => {\n var _a;\n const scope = (_a = options === null || options === void 0 ? void 0 : options.scope) === null || _a === void 0 ? void 0 : _a.trim();\n return scope && scope.length > 0 ? scope : DEFAULT_SCOPE;\n};\nconst createUuid = () => {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (char) => {\n const random = Math.floor(Math.random() * 16);\n const value = char === 'x' ? random : (random & 0x3) | 0x8;\n return value.toString(16);\n });\n};\nconst readValue = (key) => {\n var _a, _b, _c, _d;\n try {\n return (_c = (_b = (_a = globalThis.localStorage) === null || _a === void 0 ? void 0 : _a.getItem(key)) !== null && _b !== void 0 ? _b : memoryStore.get(key)) !== null && _c !== void 0 ? _c : null;\n }\n catch (_e) {\n return (_d = memoryStore.get(key)) !== null && _d !== void 0 ? _d : null;\n }\n};\nconst writeValue = (key, value) => {\n var _a;\n memoryStore.set(key, value);\n try {\n (_a = globalThis.localStorage) === null || _a === void 0 ? void 0 : _a.setItem(key, value);\n }\n catch (_b) {\n // In-memory fallback already updated.\n }\n};\nexport class PersistentUuidWeb extends WebPlugin {\n async getId(options) {\n const scope = normalizeScope(options);\n const key = STORAGE_PREFIX + scope;\n const existing = readValue(key);\n if (existing) {\n return {\n id: existing,\n scope,\n created: false,\n };\n }\n const id = createUuid();\n writeValue(key, id);\n return {\n id,\n scope,\n created: true,\n };\n }\n async resetId(options) {\n const scope = normalizeScope(options);\n const id = createUuid();\n writeValue(STORAGE_PREFIX + scope, id);\n return {\n id,\n scope,\n created: true,\n };\n }\n async getPluginVersion() {\n return {\n version: 'web',\n };\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":"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"}
@@ -0,0 +1,127 @@
1
+ import Foundation
2
+ import Security
3
+
4
+ @objc public class PersistentUuid: NSObject {
5
+ private let service = "app.capgo.persistent_uuid"
6
+ private let accountPrefix = "PersistentUuid:"
7
+ private let fallbackScope = "default"
8
+
9
+ @objc public func getId(_ scope: String?) throws -> [String: Any] {
10
+ let normalizedScope = normalizeScope(scope)
11
+ if let existing = try readUuid(scope: normalizedScope) {
12
+ return [
13
+ "id": existing,
14
+ "scope": normalizedScope,
15
+ "created": false
16
+ ]
17
+ }
18
+
19
+ let id = createUuid()
20
+ try saveUuid(id, scope: normalizedScope)
21
+ return [
22
+ "id": id,
23
+ "scope": normalizedScope,
24
+ "created": true
25
+ ]
26
+ }
27
+
28
+ @objc public func resetId(_ scope: String?) throws -> [String: Any] {
29
+ let normalizedScope = normalizeScope(scope)
30
+ let id = createUuid()
31
+ try saveUuid(id, scope: normalizedScope)
32
+ return [
33
+ "id": id,
34
+ "scope": normalizedScope,
35
+ "created": true
36
+ ]
37
+ }
38
+
39
+ @objc public func getPluginVersion() -> String {
40
+ return "8.0.0"
41
+ }
42
+
43
+ private func normalizeScope(_ scope: String?) -> String {
44
+ if let trimmed = scope?.trimmingCharacters(in: .whitespacesAndNewlines), !trimmed.isEmpty {
45
+ return trimmed
46
+ }
47
+
48
+ return Bundle.main.bundleIdentifier ?? fallbackScope
49
+ }
50
+
51
+ private func accountName(scope: String) -> String {
52
+ return "\(accountPrefix)\(scope)"
53
+ }
54
+
55
+ private func createUuid() -> String {
56
+ return UUID().uuidString.lowercased()
57
+ }
58
+
59
+ private func baseQuery(scope: String) -> [String: Any] {
60
+ return [
61
+ kSecClass as String: kSecClassGenericPassword,
62
+ kSecAttrService as String: service,
63
+ kSecAttrAccount as String: accountName(scope: scope)
64
+ ]
65
+ }
66
+
67
+ private func readUuid(scope: String) throws -> String? {
68
+ var query = baseQuery(scope: scope)
69
+ query[kSecReturnData as String] = true
70
+ query[kSecMatchLimit as String] = kSecMatchLimitOne
71
+
72
+ var item: CFTypeRef?
73
+ let status = SecItemCopyMatching(query as CFDictionary, &item)
74
+ if status == errSecItemNotFound {
75
+ return nil
76
+ }
77
+
78
+ guard status == errSecSuccess else {
79
+ throw NSError(
80
+ domain: NSOSStatusErrorDomain,
81
+ code: Int(status),
82
+ userInfo: [NSLocalizedDescriptionKey: "Keychain read failed: \(status)"]
83
+ )
84
+ }
85
+
86
+ guard let data = item as? Data else {
87
+ return nil
88
+ }
89
+
90
+ return String(data: data, encoding: .utf8)
91
+ }
92
+
93
+ private func saveUuid(_ id: String, scope: String) throws {
94
+ let data = Data(id.utf8)
95
+ let query = baseQuery(scope: scope)
96
+ let update: [String: Any] = [
97
+ kSecValueData as String: data,
98
+ kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
99
+ ]
100
+
101
+ let updateStatus = SecItemUpdate(query as CFDictionary, update as CFDictionary)
102
+ if updateStatus == errSecSuccess {
103
+ return
104
+ }
105
+
106
+ guard updateStatus == errSecItemNotFound else {
107
+ throw NSError(
108
+ domain: NSOSStatusErrorDomain,
109
+ code: Int(updateStatus),
110
+ userInfo: [NSLocalizedDescriptionKey: "Keychain update failed: \(updateStatus)"]
111
+ )
112
+ }
113
+
114
+ var attributes = query
115
+ attributes[kSecValueData as String] = data
116
+ attributes[kSecAttrAccessible as String] = kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
117
+
118
+ let addStatus = SecItemAdd(attributes as CFDictionary, nil)
119
+ guard addStatus == errSecSuccess else {
120
+ throw NSError(
121
+ domain: NSOSStatusErrorDomain,
122
+ code: Int(addStatus),
123
+ userInfo: [NSLocalizedDescriptionKey: "Keychain save failed: \(addStatus)"]
124
+ )
125
+ }
126
+ }
127
+ }
@@ -0,0 +1,37 @@
1
+ import Foundation
2
+ import Capacitor
3
+
4
+ @objc(PersistentUuidPlugin)
5
+ public class PersistentUuidPlugin: CAPPlugin, CAPBridgedPlugin {
6
+ public let identifier = "PersistentUuidPlugin"
7
+ public let jsName = "PersistentUuid"
8
+ public let pluginMethods: [CAPPluginMethod] = [
9
+ CAPPluginMethod(name: "getId", returnType: CAPPluginReturnPromise),
10
+ CAPPluginMethod(name: "resetId", returnType: CAPPluginReturnPromise),
11
+ CAPPluginMethod(name: "getPluginVersion", returnType: CAPPluginReturnPromise)
12
+ ]
13
+
14
+ private let implementation = PersistentUuid()
15
+
16
+ @objc func getId(_ call: CAPPluginCall) {
17
+ do {
18
+ call.resolve(try implementation.getId(call.getString("scope")))
19
+ } catch {
20
+ call.reject("Failed to get persistent UUID: \(error.localizedDescription)")
21
+ }
22
+ }
23
+
24
+ @objc func resetId(_ call: CAPPluginCall) {
25
+ do {
26
+ call.resolve(try implementation.resetId(call.getString("scope")))
27
+ } catch {
28
+ call.reject("Failed to reset persistent UUID: \(error.localizedDescription)")
29
+ }
30
+ }
31
+
32
+ @objc func getPluginVersion(_ call: CAPPluginCall) {
33
+ call.resolve([
34
+ "version": implementation.getPluginVersion()
35
+ ])
36
+ }
37
+ }
@@ -0,0 +1,20 @@
1
+ import XCTest
2
+ @testable import PersistentUuidPlugin
3
+
4
+ class PersistentUuidTests: XCTestCase {
5
+ func testGetPluginVersion() {
6
+ let implementation = PersistentUuid()
7
+ let result = implementation.getPluginVersion()
8
+
9
+ XCTAssertEqual("8.0.0", result)
10
+ }
11
+
12
+ func testResetIdCreatesUuid() throws {
13
+ let implementation = PersistentUuid()
14
+ let result = try implementation.resetId("test")
15
+
16
+ XCTAssertNotNil(result["id"] as? String)
17
+ XCTAssertEqual("test", result["scope"] as? String)
18
+ XCTAssertEqual(true, result["created"] as? Bool)
19
+ }
20
+ }
package/package.json ADDED
@@ -0,0 +1,88 @@
1
+ {
2
+ "name": "@capgo/capacitor-persistent-uuid",
3
+ "version": "8.1.0",
4
+ "description": "Capacitor plugin for a persistent app UUID that survives reinstalls and updates.",
5
+ "main": "dist/plugin.cjs.js",
6
+ "module": "dist/esm/index.js",
7
+ "types": "dist/esm/index.d.ts",
8
+ "unpkg": "dist/plugin.js",
9
+ "files": [
10
+ "android/src/main/",
11
+ "android/build.gradle",
12
+ "dist/",
13
+ "ios/Sources",
14
+ "ios/Tests",
15
+ "Package.swift",
16
+ "CapgoCapacitorPersistentUuid.podspec"
17
+ ],
18
+ "author": "Martin Donadieu <martin@capgo.app>",
19
+ "license": "MPL-2.0",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/Cap-go/capacitor-persistent-uuid.git"
23
+ },
24
+ "bugs": {
25
+ "url": "https://github.com/Cap-go/capacitor-persistent-uuid/issues"
26
+ },
27
+ "homepage": "https://capgo.app/docs/plugins/persistent-uuid/",
28
+ "keywords": [
29
+ "capacitor",
30
+ "uuid",
31
+ "persistent",
32
+ "identifier",
33
+ "device"
34
+ ],
35
+ "scripts": {
36
+ "verify": "bun run verify:ios && bun run verify:android && bun run verify:web",
37
+ "verify:ios": "xcodebuild -scheme CapgoCapacitorPersistentUuid -destination generic/platform=iOS",
38
+ "verify:android": "cd android && ./gradlew clean build test && cd ..",
39
+ "verify:web": "bun run build",
40
+ "lint": "bun run eslint && bun run prettier -- --check && bun run swiftlint -- lint",
41
+ "fmt": "bun run eslint -- --fix && bun run prettier -- --write && bun run swiftlint -- --fix --format",
42
+ "eslint": "eslint \"**/*.ts\"",
43
+ "prettier": "prettier-pretty-check \"**/*.{css,html,ts,js,java}\" --plugin=prettier-plugin-java",
44
+ "swiftlint": "node-swiftlint",
45
+ "docgen": "docgen --api PersistentUuidPlugin --output-readme README.md --output-json dist/docs.json",
46
+ "build": "bun run clean && bun run docgen && tsc && rollup -c rollup.config.mjs",
47
+ "clean": "rimraf ./dist",
48
+ "watch": "tsc --watch",
49
+ "prepublishOnly": "bun run build",
50
+ "check:wiring": "node scripts/check-capacitor-plugin-wiring.mjs"
51
+ },
52
+ "devDependencies": {
53
+ "@capacitor/android": "^8.3.4",
54
+ "@capacitor/cli": "^8.3.4",
55
+ "@capacitor/core": "^8.3.4",
56
+ "@capacitor/docgen": "^0.3.1",
57
+ "@capacitor/ios": "^8.3.4",
58
+ "@eslint/js": "^10.0.1",
59
+ "@ionic/prettier-config": "^4.0.0",
60
+ "@ionic/swiftlint-config": "^2.0.0",
61
+ "@types/node": "^25.9.1",
62
+ "eslint": "^10.4.0",
63
+ "eslint-config-prettier": "^10.1.8",
64
+ "eslint-plugin-import": "^2.32.0",
65
+ "husky": "^9.1.7",
66
+ "prettier": "^3.8.3",
67
+ "prettier-plugin-java": "^2.9.2",
68
+ "prettier-pretty-check": "^0.2.0",
69
+ "rimraf": "^6.1.3",
70
+ "rollup": "^4.60.4",
71
+ "swiftlint": "^2.0.0",
72
+ "typescript": "^6.0.3",
73
+ "typescript-eslint": "^8.59.4"
74
+ },
75
+ "peerDependencies": {
76
+ "@capacitor/core": ">=8.0.0"
77
+ },
78
+ "prettier": "@ionic/prettier-config",
79
+ "swiftlint": "@ionic/swiftlint-config",
80
+ "capacitor": {
81
+ "ios": {
82
+ "src": "ios"
83
+ },
84
+ "android": {
85
+ "src": "android"
86
+ }
87
+ }
88
+ }