strata-storage 2.4.2 → 2.5.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/AI-INTEGRATION-GUIDE.md +208 -0
- package/README.md +427 -181
- package/android/AGENTS.md +34 -0
- package/android/CLAUDE.md +51 -0
- package/android/src/main/java/com/strata/storage/SQLiteStorage.java +35 -0
- package/android/src/main/java/com/stratastorage/StrataStoragePlugin.java +191 -27
- package/dist/README.md +427 -181
- package/dist/adapters/capacitor/FilesystemAdapter.d.ts.map +1 -1
- package/dist/adapters/capacitor/FilesystemAdapter.js +2 -1
- package/dist/adapters/capacitor/PreferencesAdapter.d.ts.map +1 -1
- package/dist/adapters/capacitor/PreferencesAdapter.js +2 -1
- package/dist/adapters/capacitor/SecureAdapter.d.ts.map +1 -1
- package/dist/adapters/capacitor/SecureAdapter.js +2 -1
- package/dist/adapters/capacitor/SqliteAdapter.d.ts.map +1 -1
- package/dist/adapters/capacitor/SqliteAdapter.js +2 -1
- package/dist/adapters/web/CacheAdapter.d.ts.map +1 -1
- package/dist/adapters/web/CacheAdapter.js +11 -3
- package/dist/adapters/web/CookieAdapter.d.ts +37 -1
- package/dist/adapters/web/CookieAdapter.d.ts.map +1 -1
- package/dist/adapters/web/CookieAdapter.js +89 -9
- package/dist/adapters/web/IndexedDBAdapter.d.ts.map +1 -1
- package/dist/adapters/web/IndexedDBAdapter.js +10 -2
- package/dist/adapters/web/LocalStorageAdapter.d.ts +31 -0
- package/dist/adapters/web/LocalStorageAdapter.d.ts.map +1 -1
- package/dist/adapters/web/LocalStorageAdapter.js +92 -19
- package/dist/adapters/web/MemoryAdapter.d.ts +24 -0
- package/dist/adapters/web/MemoryAdapter.d.ts.map +1 -1
- package/dist/adapters/web/MemoryAdapter.js +69 -18
- package/dist/adapters/web/SessionStorageAdapter.d.ts +24 -0
- package/dist/adapters/web/SessionStorageAdapter.d.ts.map +1 -1
- package/dist/adapters/web/SessionStorageAdapter.js +71 -9
- package/dist/adapters/web/URLAdapter.d.ts +59 -0
- package/dist/adapters/web/URLAdapter.d.ts.map +1 -0
- package/dist/adapters/web/URLAdapter.js +234 -0
- package/dist/adapters/web/index.d.ts +1 -0
- package/dist/adapters/web/index.d.ts.map +1 -1
- package/dist/adapters/web/index.js +1 -0
- package/dist/android/AGENTS.md +34 -0
- package/dist/android/CLAUDE.md +51 -0
- package/dist/android/src/main/java/com/strata/storage/SQLiteStorage.java +35 -0
- package/dist/android/src/main/java/com/stratastorage/StrataStoragePlugin.java +191 -27
- package/dist/capacitor.d.ts.map +1 -1
- package/dist/capacitor.js +2 -1
- package/dist/config/support.d.ts +10 -0
- package/dist/config/support.d.ts.map +1 -0
- package/dist/config/support.js +9 -0
- package/dist/core/BaseAdapter.d.ts +8 -0
- package/dist/core/BaseAdapter.d.ts.map +1 -1
- package/dist/core/BaseAdapter.js +34 -14
- package/dist/core/Strata.d.ts +56 -2
- package/dist/core/Strata.d.ts.map +1 -1
- package/dist/core/Strata.js +501 -53
- package/dist/features/encryption.d.ts.map +1 -1
- package/dist/features/encryption.js +3 -2
- package/dist/features/integrity.d.ts +16 -0
- package/dist/features/integrity.d.ts.map +1 -0
- package/dist/features/integrity.js +28 -0
- package/dist/features/observer.d.ts.map +1 -1
- package/dist/features/observer.js +2 -1
- package/dist/features/query.d.ts +7 -1
- package/dist/features/query.d.ts.map +1 -1
- package/dist/features/query.js +9 -2
- package/dist/features/sync.d.ts.map +1 -1
- package/dist/features/sync.js +4 -3
- package/dist/index.d.ts +35 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +55 -30
- package/dist/integrations/angular/index.d.ts +158 -0
- package/dist/integrations/angular/index.d.ts.map +1 -0
- package/dist/integrations/angular/index.js +395 -0
- package/dist/integrations/index.d.ts +15 -0
- package/dist/integrations/index.d.ts.map +1 -0
- package/dist/integrations/index.js +18 -0
- package/dist/integrations/react/index.d.ts +75 -0
- package/dist/integrations/react/index.d.ts.map +1 -0
- package/dist/integrations/react/index.js +191 -0
- package/dist/integrations/vue/index.d.ts +103 -0
- package/dist/integrations/vue/index.d.ts.map +1 -0
- package/dist/integrations/vue/index.js +274 -0
- package/dist/ios/AGENTS.md +33 -0
- package/dist/ios/CLAUDE.md +49 -0
- package/dist/ios/Plugin/KeychainStorage.swift +139 -50
- package/dist/ios/Plugin/SQLiteStorage.swift +40 -0
- package/dist/ios/Plugin/StrataStoragePlugin.m +23 -0
- package/dist/ios/Plugin/StrataStoragePlugin.swift +201 -52
- package/dist/package.json +21 -5
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +2 -1
- package/dist/types/index.d.ts +58 -9
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +0 -13
- package/dist/utils/errors.d.ts +7 -0
- package/dist/utils/errors.d.ts.map +1 -1
- package/dist/utils/errors.js +15 -3
- package/dist/utils/index.d.ts +63 -5
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +109 -16
- package/dist/utils/logger.d.ts +31 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +63 -0
- package/ios/AGENTS.md +33 -0
- package/ios/CLAUDE.md +49 -0
- package/ios/Plugin/KeychainStorage.swift +139 -50
- package/ios/Plugin/SQLiteStorage.swift +40 -0
- package/ios/Plugin/StrataStoragePlugin.m +23 -0
- package/ios/Plugin/StrataStoragePlugin.swift +201 -52
- package/package.json +35 -23
- package/scripts/build.js +16 -5
- package/scripts/configure.js +2 -6
- package/scripts/postinstall.js +2 -2
- package/Readme.md +0 -271
|
@@ -1,19 +1,72 @@
|
|
|
1
1
|
import Foundation
|
|
2
2
|
import Security
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Keychain-backed secure storage.
|
|
6
|
+
*
|
|
7
|
+
* Security notes:
|
|
8
|
+
* - Items default to `kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly`,
|
|
9
|
+
* which keeps data available to background tasks after the first unlock
|
|
10
|
+
* while preventing it from leaving the device via encrypted backups.
|
|
11
|
+
* `kSecAttrAccessibleAlways` / `kSecAttrAccessibleAlwaysThisDeviceOnly`
|
|
12
|
+
* are deprecated and insecure and are intentionally NOT used.
|
|
13
|
+
* - Callers may pass a stricter accessibility class from JS via the
|
|
14
|
+
* `accessible` option (see KeychainAccessible in definitions.ts).
|
|
15
|
+
* - Secret values are never logged.
|
|
16
|
+
*/
|
|
4
17
|
@objc public class KeychainStorage: NSObject {
|
|
5
18
|
private let service: String
|
|
6
19
|
private let accessGroup: String?
|
|
7
|
-
|
|
20
|
+
private let defaultAccessible: CFString
|
|
21
|
+
|
|
8
22
|
@objc public init(service: String? = nil, accessGroup: String? = nil) {
|
|
9
23
|
self.service = service ?? Bundle.main.bundleIdentifier ?? "StrataStorage"
|
|
10
24
|
self.accessGroup = accessGroup
|
|
25
|
+
// After-first-unlock + this-device-only is a safe, widely-recommended
|
|
26
|
+
// default for app secrets. It is more permissive than whenUnlocked
|
|
27
|
+
// (so background access works) but still excluded from backups.
|
|
28
|
+
self.defaultAccessible = kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
|
|
11
29
|
super.init()
|
|
12
30
|
}
|
|
13
|
-
|
|
14
|
-
|
|
31
|
+
|
|
32
|
+
/// Maps a JS `KeychainAccessible` string to the matching Security framework
|
|
33
|
+
/// constant. Unknown / nil values fall back to the secure default.
|
|
34
|
+
private func accessibleConstant(for raw: String?) -> CFString {
|
|
35
|
+
switch raw {
|
|
36
|
+
case "whenUnlocked":
|
|
37
|
+
return kSecAttrAccessibleWhenUnlocked
|
|
38
|
+
case "afterFirstUnlock":
|
|
39
|
+
return kSecAttrAccessibleAfterFirstUnlock
|
|
40
|
+
case "whenUnlockedThisDeviceOnly":
|
|
41
|
+
return kSecAttrAccessibleWhenUnlockedThisDeviceOnly
|
|
42
|
+
case "afterFirstUnlockThisDeviceOnly":
|
|
43
|
+
return kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
|
|
44
|
+
case "whenPasscodeSetThisDeviceOnly":
|
|
45
|
+
return kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
|
|
46
|
+
default:
|
|
47
|
+
return defaultAccessible
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/// Builds an NSError that surfaces the OSStatus to the JS bridge without
|
|
52
|
+
/// leaking any stored secret value.
|
|
53
|
+
private func keychainError(_ status: OSStatus, operation: String) -> NSError {
|
|
54
|
+
let message: String
|
|
55
|
+
if #available(iOS 11.3, *), let str = SecCopyErrorMessageString(status, nil) as String? {
|
|
56
|
+
message = str
|
|
57
|
+
} else {
|
|
58
|
+
message = "OSStatus \(status)"
|
|
59
|
+
}
|
|
60
|
+
return NSError(
|
|
61
|
+
domain: "StrataStorage.KeychainStorage",
|
|
62
|
+
code: Int(status),
|
|
63
|
+
userInfo: [NSLocalizedDescriptionKey: "Keychain \(operation) failed: \(message)"]
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
@objc public func set(key: String, value: Any, accessible: String? = nil) throws -> Bool {
|
|
15
68
|
let data: Data
|
|
16
|
-
|
|
69
|
+
|
|
17
70
|
if let dataValue = value as? Data {
|
|
18
71
|
data = dataValue
|
|
19
72
|
} else if let stringValue = value as? String {
|
|
@@ -23,28 +76,43 @@ import Security
|
|
|
23
76
|
let jsonData = try JSONSerialization.data(withJSONObject: value, options: [])
|
|
24
77
|
data = jsonData
|
|
25
78
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
79
|
+
|
|
80
|
+
// Remove any existing item first so the accessibility class is applied
|
|
81
|
+
// cleanly (SecItemUpdate cannot change accessibility reliably).
|
|
82
|
+
let deleteQuery = createQuery(key: key)
|
|
83
|
+
SecItemDelete(deleteQuery as CFDictionary)
|
|
84
|
+
|
|
85
|
+
var newItem = createQuery(key: key, accessible: accessibleConstant(for: accessible))
|
|
31
86
|
newItem[kSecValueData as String] = data
|
|
32
|
-
|
|
87
|
+
|
|
33
88
|
let status = SecItemAdd(newItem as CFDictionary, nil)
|
|
34
|
-
|
|
89
|
+
guard status == errSecSuccess else {
|
|
90
|
+
throw keychainError(status, operation: "set")
|
|
91
|
+
}
|
|
92
|
+
return true
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Convenience overload kept for existing Objective-C callers.
|
|
96
|
+
@objc public func set(key: String, value: Any) throws -> Bool {
|
|
97
|
+
return try set(key: key, value: value, accessible: nil)
|
|
35
98
|
}
|
|
36
|
-
|
|
99
|
+
|
|
37
100
|
@objc public func get(key: String) throws -> Any? {
|
|
38
101
|
var query = createQuery(key: key)
|
|
39
102
|
query[kSecReturnData as String] = true
|
|
40
103
|
query[kSecMatchLimit as String] = kSecMatchLimitOne
|
|
41
|
-
|
|
104
|
+
|
|
42
105
|
var result: AnyObject?
|
|
43
106
|
let status = SecItemCopyMatching(query as CFDictionary, &result)
|
|
44
|
-
|
|
45
|
-
|
|
107
|
+
|
|
108
|
+
if status == errSecItemNotFound {
|
|
109
|
+
return nil
|
|
110
|
+
}
|
|
111
|
+
guard status == errSecSuccess else {
|
|
112
|
+
throw keychainError(status, operation: "get")
|
|
113
|
+
}
|
|
46
114
|
guard let data = result as? Data else { return nil }
|
|
47
|
-
|
|
115
|
+
|
|
48
116
|
// Try to parse as JSON first, fallback to string
|
|
49
117
|
if let jsonObject = try? JSONSerialization.jsonObject(with: data, options: []) {
|
|
50
118
|
return jsonObject
|
|
@@ -52,35 +120,41 @@ import Security
|
|
|
52
120
|
return String(data: data, encoding: .utf8)
|
|
53
121
|
}
|
|
54
122
|
}
|
|
55
|
-
|
|
123
|
+
|
|
56
124
|
@objc public func remove(key: String) throws -> Bool {
|
|
57
125
|
let query = createQuery(key: key)
|
|
58
126
|
let status = SecItemDelete(query as CFDictionary)
|
|
59
|
-
|
|
127
|
+
guard status == errSecSuccess || status == errSecItemNotFound else {
|
|
128
|
+
throw keychainError(status, operation: "remove")
|
|
129
|
+
}
|
|
130
|
+
return true
|
|
60
131
|
}
|
|
61
|
-
|
|
132
|
+
|
|
62
133
|
@objc public func clear(prefix: String? = nil) throws -> Bool {
|
|
63
134
|
if let prefix = prefix {
|
|
64
135
|
// Clear only keys with the given prefix
|
|
65
136
|
let keysToRemove = try keys(pattern: prefix)
|
|
66
|
-
var allSuccess = true
|
|
67
137
|
for key in keysToRemove {
|
|
68
|
-
|
|
69
|
-
allSuccess = false
|
|
70
|
-
}
|
|
138
|
+
_ = try remove(key: key)
|
|
71
139
|
}
|
|
72
|
-
return
|
|
140
|
+
return true
|
|
73
141
|
} else {
|
|
74
|
-
// Clear all keys
|
|
75
|
-
|
|
142
|
+
// Clear all keys for this service (and access group, if any).
|
|
143
|
+
var query: [String: Any] = [
|
|
76
144
|
kSecClass as String: kSecClassGenericPassword,
|
|
77
145
|
kSecAttrService as String: service
|
|
78
146
|
]
|
|
147
|
+
if let accessGroup = accessGroup {
|
|
148
|
+
query[kSecAttrAccessGroup as String] = accessGroup
|
|
149
|
+
}
|
|
79
150
|
let status = SecItemDelete(query as CFDictionary)
|
|
80
|
-
|
|
151
|
+
guard status == errSecSuccess || status == errSecItemNotFound else {
|
|
152
|
+
throw keychainError(status, operation: "clear")
|
|
153
|
+
}
|
|
154
|
+
return true
|
|
81
155
|
}
|
|
82
156
|
}
|
|
83
|
-
|
|
157
|
+
|
|
84
158
|
@objc public func keys(pattern: String? = nil) throws -> [String] {
|
|
85
159
|
var query: [String: Any] = [
|
|
86
160
|
kSecClass as String: kSecClassGenericPassword,
|
|
@@ -88,57 +162,72 @@ import Security
|
|
|
88
162
|
kSecReturnAttributes as String: true,
|
|
89
163
|
kSecMatchLimit as String: kSecMatchLimitAll
|
|
90
164
|
]
|
|
91
|
-
|
|
165
|
+
|
|
92
166
|
if let accessGroup = accessGroup {
|
|
93
167
|
query[kSecAttrAccessGroup as String] = accessGroup
|
|
94
168
|
}
|
|
95
|
-
|
|
169
|
+
|
|
96
170
|
var result: AnyObject?
|
|
97
171
|
let status = SecItemCopyMatching(query as CFDictionary, &result)
|
|
98
|
-
|
|
172
|
+
|
|
173
|
+
if status == errSecItemNotFound {
|
|
174
|
+
return []
|
|
175
|
+
}
|
|
99
176
|
guard status == errSecSuccess,
|
|
100
|
-
let items = result as? [[String: Any]] else {
|
|
101
|
-
|
|
177
|
+
let items = result as? [[String: Any]] else {
|
|
178
|
+
if status == errSecSuccess { return [] }
|
|
179
|
+
throw keychainError(status, operation: "keys")
|
|
180
|
+
}
|
|
181
|
+
|
|
102
182
|
let allKeys = items.compactMap { $0[kSecAttrAccount as String] as? String }
|
|
103
|
-
|
|
183
|
+
|
|
104
184
|
guard let pattern = pattern else {
|
|
105
185
|
return allKeys
|
|
106
186
|
}
|
|
107
|
-
|
|
108
|
-
// Filter keys by pattern (simple prefix matching)
|
|
187
|
+
|
|
188
|
+
// Filter keys by pattern (simple prefix / contains matching)
|
|
109
189
|
return allKeys.filter { key in
|
|
110
190
|
key.hasPrefix(pattern) || key.contains(pattern)
|
|
111
191
|
}
|
|
112
192
|
}
|
|
113
|
-
|
|
114
|
-
private func createQuery(key: String) -> [String: Any] {
|
|
193
|
+
|
|
194
|
+
private func createQuery(key: String, accessible: CFString? = nil) -> [String: Any] {
|
|
115
195
|
var query: [String: Any] = [
|
|
116
196
|
kSecClass as String: kSecClassGenericPassword,
|
|
117
197
|
kSecAttrService as String: service,
|
|
118
|
-
kSecAttrAccount as String: key
|
|
119
|
-
kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlockedThisDeviceOnly
|
|
198
|
+
kSecAttrAccount as String: key
|
|
120
199
|
]
|
|
121
|
-
|
|
200
|
+
|
|
201
|
+
// Accessibility only needs to be set when adding/writing an item.
|
|
202
|
+
// Including it on read/delete queries can over-constrain matching.
|
|
203
|
+
if let accessible = accessible {
|
|
204
|
+
query[kSecAttrAccessible as String] = accessible
|
|
205
|
+
}
|
|
206
|
+
|
|
122
207
|
if let accessGroup = accessGroup {
|
|
123
208
|
query[kSecAttrAccessGroup as String] = accessGroup
|
|
124
209
|
}
|
|
125
|
-
|
|
210
|
+
|
|
126
211
|
return query
|
|
127
212
|
}
|
|
128
|
-
|
|
213
|
+
|
|
129
214
|
@objc public func size() throws -> (total: Int, count: Int) {
|
|
130
215
|
let allKeys = try keys()
|
|
131
216
|
var totalSize = 0
|
|
132
|
-
|
|
217
|
+
|
|
133
218
|
for key in allKeys {
|
|
134
|
-
if let
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
219
|
+
if let value = try get(key: key) {
|
|
220
|
+
if let data = value as? Data {
|
|
221
|
+
totalSize += data.count
|
|
222
|
+
} else if let string = value as? String {
|
|
223
|
+
totalSize += string.data(using: .utf8)?.count ?? 0
|
|
224
|
+
} else if let jsonData = try? JSONSerialization.data(withJSONObject: value, options: []) {
|
|
225
|
+
totalSize += jsonData.count
|
|
226
|
+
}
|
|
138
227
|
}
|
|
139
228
|
totalSize += key.data(using: .utf8)?.count ?? 0
|
|
140
229
|
}
|
|
141
|
-
|
|
230
|
+
|
|
142
231
|
return (total: totalSize, count: allKeys.count)
|
|
143
232
|
}
|
|
144
|
-
}
|
|
233
|
+
}
|
|
@@ -291,4 +291,44 @@ import os.log
|
|
|
291
291
|
sqlite3_finalize(statement)
|
|
292
292
|
return (total: totalSize, count: count)
|
|
293
293
|
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Returns every row as `{ key, value }` where `value` is the decoded
|
|
297
|
+
* stored payload. The JS SqliteAdapter applies the real query `condition`
|
|
298
|
+
* by re-fetching and filtering each key, so this native side only needs to
|
|
299
|
+
* enumerate candidate rows. The `condition` argument is accepted for
|
|
300
|
+
* forward-compatibility but is not yet pushed down into SQL.
|
|
301
|
+
*/
|
|
302
|
+
@objc public func query(condition: [String: Any]) -> [[String: Any]] {
|
|
303
|
+
guard db != nil else {
|
|
304
|
+
os_log("Database not initialized", log: logger, type: .error)
|
|
305
|
+
return []
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
let querySQL = "SELECT key, value FROM \(tableName)"
|
|
309
|
+
var statement: OpaquePointer?
|
|
310
|
+
var rows: [[String: Any]] = []
|
|
311
|
+
|
|
312
|
+
if sqlite3_prepare_v2(db, querySQL, -1, &statement, nil) == SQLITE_OK {
|
|
313
|
+
while sqlite3_step(statement) == SQLITE_ROW {
|
|
314
|
+
guard let keyCString = sqlite3_column_text(statement, 0) else { continue }
|
|
315
|
+
let key = String(cString: keyCString)
|
|
316
|
+
|
|
317
|
+
var decoded: Any = NSNull()
|
|
318
|
+
if let blob = sqlite3_column_blob(statement, 1) {
|
|
319
|
+
let valueData = Data(bytes: blob, count: Int(sqlite3_column_bytes(statement, 1)))
|
|
320
|
+
if let jsonObject = try? JSONSerialization.jsonObject(with: valueData, options: []) {
|
|
321
|
+
decoded = jsonObject
|
|
322
|
+
} else if let str = String(data: valueData, encoding: .utf8) {
|
|
323
|
+
decoded = str
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
rows.append(["key": key, "value": decoded])
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
sqlite3_finalize(statement)
|
|
332
|
+
return rows
|
|
333
|
+
}
|
|
294
334
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#import <Foundation/Foundation.h>
|
|
2
|
+
#import <Capacitor/Capacitor.h>
|
|
3
|
+
|
|
4
|
+
// Registers the StrataStorage plugin and its methods with the Capacitor
|
|
5
|
+
// bridge. Without this macro block the @objc Swift methods are NOT exposed
|
|
6
|
+
// to the JavaScript layer and every call would fail with "method not
|
|
7
|
+
// implemented". The method names and the parameter list below MUST match
|
|
8
|
+
// the @objc func names in StrataStoragePlugin.swift and the JS plugin
|
|
9
|
+
// contract in src/plugin/definitions.ts.
|
|
10
|
+
CAP_PLUGIN(StrataStoragePlugin, "StrataStorage",
|
|
11
|
+
CAP_PLUGIN_METHOD(isAvailable, CAPPluginReturnPromise);
|
|
12
|
+
CAP_PLUGIN_METHOD(get, CAPPluginReturnPromise);
|
|
13
|
+
CAP_PLUGIN_METHOD(set, CAPPluginReturnPromise);
|
|
14
|
+
CAP_PLUGIN_METHOD(remove, CAPPluginReturnPromise);
|
|
15
|
+
CAP_PLUGIN_METHOD(clear, CAPPluginReturnPromise);
|
|
16
|
+
CAP_PLUGIN_METHOD(keys, CAPPluginReturnPromise);
|
|
17
|
+
CAP_PLUGIN_METHOD(size, CAPPluginReturnPromise);
|
|
18
|
+
CAP_PLUGIN_METHOD(query, CAPPluginReturnPromise);
|
|
19
|
+
CAP_PLUGIN_METHOD(getUserDefaults, CAPPluginReturnPromise);
|
|
20
|
+
CAP_PLUGIN_METHOD(setUserDefaults, CAPPluginReturnPromise);
|
|
21
|
+
CAP_PLUGIN_METHOD(getKeychain, CAPPluginReturnPromise);
|
|
22
|
+
CAP_PLUGIN_METHOD(setKeychain, CAPPluginReturnPromise);
|
|
23
|
+
)
|