@capgo/capacitor-contacts 7.1.2 → 8.0.1

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.
@@ -1,9 +1,11 @@
1
1
  import Capacitor
2
2
  import Contacts
3
+ import ContactsUI
3
4
  import UIKit
4
5
 
5
6
  @objc(CapacitorContactsPlugin)
6
7
  public class CapacitorContactsPlugin: CAPPlugin, CAPBridgedPlugin {
8
+ private let pluginVersion: String = "8.0.1"
7
9
  public let identifier = "CapacitorContactsPlugin"
8
10
  public let jsName = "CapacitorContacts"
9
11
  public let pluginMethods: [CAPPluginMethod] = [
@@ -27,7 +29,8 @@ public class CapacitorContactsPlugin: CAPPlugin, CAPBridgedPlugin {
27
29
  CAPPluginMethod(name: "pickContacts", returnType: CAPPluginReturnPromise),
28
30
  CAPPluginMethod(name: "updateContactById", returnType: CAPPluginReturnPromise),
29
31
  CAPPluginMethod(name: "checkPermissions", returnType: CAPPluginReturnPromise),
30
- CAPPluginMethod(name: "requestPermissions", returnType: CAPPluginReturnPromise)
32
+ CAPPluginMethod(name: "requestPermissions", returnType: CAPPluginReturnPromise),
33
+ CAPPluginMethod(name: "getPluginVersion", returnType: CAPPluginReturnPromise)
31
34
  ]
32
35
 
33
36
  private let contactStore = CNContactStore()
@@ -151,6 +154,10 @@ public class CapacitorContactsPlugin: CAPPlugin, CAPBridgedPlugin {
151
154
  }
152
155
  }
153
156
 
157
+ @objc func getPluginVersion(_ call: CAPPluginCall) {
158
+ call.resolve(["version": self.pluginVersion])
159
+ }
160
+
154
161
  @objc override public func checkPermissions(_ call: CAPPluginCall) {
155
162
  let status = authorizationStatus()
156
163
  call.resolve(status)
@@ -177,24 +184,284 @@ public class CapacitorContactsPlugin: CAPPlugin, CAPBridgedPlugin {
177
184
  })
178
185
  }
179
186
 
180
- // MARK: - Not yet implemented operations
187
+ // MARK: - Write operations
188
+
189
+ @objc func createContact(_ call: CAPPluginCall) {
190
+ guard let options = call.options["options"] as? JSObject,
191
+ let contactData = options["contact"] as? JSObject else {
192
+ call.reject("Missing contact data.")
193
+ return
194
+ }
195
+
196
+ ensureAuthorized(call) {
197
+ let newContact = CNMutableContact()
198
+ self.populateContact(newContact, from: contactData)
199
+
200
+ let saveRequest = CNSaveRequest()
201
+ saveRequest.add(newContact, toContainerWithIdentifier: nil)
181
202
 
182
- private func notImplemented(_ call: CAPPluginCall) {
183
- call.reject("Method not implemented yet.")
203
+ do {
204
+ try self.contactStore.execute(saveRequest)
205
+ call.resolve(["id": newContact.identifier])
206
+ } catch {
207
+ call.reject("Failed to create contact.", nil, error)
208
+ }
209
+ }
184
210
  }
185
211
 
186
- @objc func createContact(_ call: CAPPluginCall) { notImplemented(call) }
187
- @objc func createGroup(_ call: CAPPluginCall) { notImplemented(call) }
188
- @objc func deleteContactById(_ call: CAPPluginCall) { notImplemented(call) }
189
- @objc func deleteGroupById(_ call: CAPPluginCall) { notImplemented(call) }
190
- @objc func displayContactById(_ call: CAPPluginCall) { notImplemented(call) }
191
- @objc func displayCreateContact(_ call: CAPPluginCall) { notImplemented(call) }
192
- @objc func displayUpdateContactById(_ call: CAPPluginCall) { notImplemented(call) }
193
- @objc func getGroupById(_ call: CAPPluginCall) { notImplemented(call) }
194
- @objc func getGroups(_ call: CAPPluginCall) { notImplemented(call) }
195
- @objc func pickContact(_ call: CAPPluginCall) { notImplemented(call) }
196
- @objc func pickContacts(_ call: CAPPluginCall) { notImplemented(call) }
197
- @objc func updateContactById(_ call: CAPPluginCall) { notImplemented(call) }
212
+ @objc func updateContactById(_ call: CAPPluginCall) {
213
+ guard let options = call.options["options"] as? JSObject,
214
+ let identifier = options["id"] as? String,
215
+ let contactData = options["contact"] as? JSObject else {
216
+ call.reject("Missing contact identifier or data.")
217
+ return
218
+ }
219
+
220
+ ensureAuthorized(call) {
221
+ do {
222
+ let keysToFetch: [CNKeyDescriptor] = [
223
+ CNContactIdentifierKey as CNKeyDescriptor,
224
+ CNContactGivenNameKey as CNKeyDescriptor,
225
+ CNContactFamilyNameKey as CNKeyDescriptor,
226
+ CNContactMiddleNameKey as CNKeyDescriptor,
227
+ CNContactNamePrefixKey as CNKeyDescriptor,
228
+ CNContactNameSuffixKey as CNKeyDescriptor,
229
+ CNContactOrganizationNameKey as CNKeyDescriptor,
230
+ CNContactJobTitleKey as CNKeyDescriptor,
231
+ CNContactEmailAddressesKey as CNKeyDescriptor,
232
+ CNContactPhoneNumbersKey as CNKeyDescriptor,
233
+ CNContactPostalAddressesKey as CNKeyDescriptor,
234
+ CNContactUrlAddressesKey as CNKeyDescriptor,
235
+ CNContactBirthdayKey as CNKeyDescriptor,
236
+ CNContactNoteKey as CNKeyDescriptor,
237
+ CNContactImageDataKey as CNKeyDescriptor
238
+ ]
239
+
240
+ let contact = try self.contactStore.unifiedContact(withIdentifier: identifier, keysToFetch: keysToFetch)
241
+ let mutableContact = contact.mutableCopy() as! CNMutableContact
242
+
243
+ self.populateContact(mutableContact, from: contactData)
244
+
245
+ let saveRequest = CNSaveRequest()
246
+ saveRequest.update(mutableContact)
247
+
248
+ try self.contactStore.execute(saveRequest)
249
+ call.resolve()
250
+ } catch {
251
+ call.reject("Failed to update contact.", nil, error)
252
+ }
253
+ }
254
+ }
255
+
256
+ @objc func deleteContactById(_ call: CAPPluginCall) {
257
+ guard let options = call.options["options"] as? JSObject,
258
+ let identifier = options["id"] as? String else {
259
+ call.reject("Missing contact identifier.")
260
+ return
261
+ }
262
+
263
+ ensureAuthorized(call) {
264
+ do {
265
+ let keysToFetch: [CNKeyDescriptor] = [CNContactIdentifierKey as CNKeyDescriptor]
266
+ let contact = try self.contactStore.unifiedContact(withIdentifier: identifier, keysToFetch: keysToFetch)
267
+ let mutableContact = contact.mutableCopy() as! CNMutableContact
268
+
269
+ let saveRequest = CNSaveRequest()
270
+ saveRequest.delete(mutableContact)
271
+
272
+ try self.contactStore.execute(saveRequest)
273
+ call.resolve()
274
+ } catch {
275
+ call.reject("Failed to delete contact.", nil, error)
276
+ }
277
+ }
278
+ }
279
+
280
+ // MARK: - Group operations
281
+
282
+ @objc func getGroups(_ call: CAPPluginCall) {
283
+ ensureAuthorized(call) {
284
+ do {
285
+ let groups = try self.contactStore.groups(matching: nil)
286
+ let serialized: [JSObject] = groups.map { group in
287
+ var result: JSObject = [:]
288
+ result["id"] = group.identifier
289
+ result["name"] = group.name
290
+ return result
291
+ }
292
+ call.resolve(["groups": serialized])
293
+ } catch {
294
+ call.reject("Failed to fetch groups.", nil, error)
295
+ }
296
+ }
297
+ }
298
+
299
+ @objc func getGroupById(_ call: CAPPluginCall) {
300
+ guard let options = call.options["options"] as? JSObject,
301
+ let identifier = options["id"] as? String else {
302
+ call.reject("Missing group identifier.")
303
+ return
304
+ }
305
+
306
+ ensureAuthorized(call) {
307
+ do {
308
+ let groups = try self.contactStore.groups(matching: nil)
309
+ if let group = groups.first(where: { $0.identifier == identifier }) {
310
+ var result: JSObject = [:]
311
+ result["id"] = group.identifier
312
+ result["name"] = group.name
313
+ call.resolve(["group": result])
314
+ } else {
315
+ call.resolve(["group": nil])
316
+ }
317
+ } catch {
318
+ call.reject("Failed to fetch group.", nil, error)
319
+ }
320
+ }
321
+ }
322
+
323
+ @objc func createGroup(_ call: CAPPluginCall) {
324
+ guard let options = call.options["options"] as? JSObject,
325
+ let groupData = options["group"] as? JSObject,
326
+ let name = groupData["name"] as? String else {
327
+ call.reject("Missing group name.")
328
+ return
329
+ }
330
+
331
+ ensureAuthorized(call) {
332
+ let newGroup = CNMutableGroup()
333
+ newGroup.name = name
334
+
335
+ let saveRequest = CNSaveRequest()
336
+ saveRequest.add(newGroup, toContainerWithIdentifier: nil)
337
+
338
+ do {
339
+ try self.contactStore.execute(saveRequest)
340
+ call.resolve(["id": newGroup.identifier])
341
+ } catch {
342
+ call.reject("Failed to create group.", nil, error)
343
+ }
344
+ }
345
+ }
346
+
347
+ @objc func deleteGroupById(_ call: CAPPluginCall) {
348
+ guard let options = call.options["options"] as? JSObject,
349
+ let identifier = options["id"] as? String else {
350
+ call.reject("Missing group identifier.")
351
+ return
352
+ }
353
+
354
+ ensureAuthorized(call) {
355
+ do {
356
+ let groups = try self.contactStore.groups(matching: nil)
357
+ if let group = groups.first(where: { $0.identifier == identifier }) {
358
+ let mutableGroup = group.mutableCopy() as! CNMutableGroup
359
+ let saveRequest = CNSaveRequest()
360
+ saveRequest.delete(mutableGroup)
361
+ try self.contactStore.execute(saveRequest)
362
+ call.resolve()
363
+ } else {
364
+ call.reject("Group not found.")
365
+ }
366
+ } catch {
367
+ call.reject("Failed to delete group.", nil, error)
368
+ }
369
+ }
370
+ }
371
+
372
+ // MARK: - UI picker and display operations
373
+
374
+ private var currentPickerCall: CAPPluginCall?
375
+
376
+ @objc func pickContact(_ call: CAPPluginCall) {
377
+ DispatchQueue.main.async {
378
+ self.currentPickerCall = call
379
+ let picker = CNContactPickerViewController()
380
+ picker.delegate = self
381
+ self.bridge?.viewController?.present(picker, animated: true)
382
+ }
383
+ }
384
+
385
+ @objc func pickContacts(_ call: CAPPluginCall) {
386
+ DispatchQueue.main.async {
387
+ self.currentPickerCall = call
388
+ let picker = CNContactPickerViewController()
389
+ picker.delegate = self
390
+ self.bridge?.viewController?.present(picker, animated: true)
391
+ }
392
+ }
393
+
394
+ @objc func displayContactById(_ call: CAPPluginCall) {
395
+ guard let options = call.options["options"] as? JSObject,
396
+ let identifier = options["id"] as? String else {
397
+ call.reject("Missing contact identifier.")
398
+ return
399
+ }
400
+
401
+ ensureAuthorized(call) {
402
+ do {
403
+ let keysToFetch = self.keysToFetch(for: nil)
404
+ let contact = try self.contactStore.unifiedContact(withIdentifier: identifier, keysToFetch: keysToFetch)
405
+
406
+ DispatchQueue.main.async {
407
+ let viewController = CNContactViewController(for: contact)
408
+ viewController.allowsEditing = false
409
+ let navController = UINavigationController(rootViewController: viewController)
410
+ self.bridge?.viewController?.present(navController, animated: true)
411
+ call.resolve()
412
+ }
413
+ } catch {
414
+ call.reject("Failed to display contact.", nil, error)
415
+ }
416
+ }
417
+ }
418
+
419
+ @objc func displayCreateContact(_ call: CAPPluginCall) {
420
+ DispatchQueue.main.async {
421
+ let newContact = CNMutableContact()
422
+
423
+ if let options = call.options["options"] as? JSObject,
424
+ let contactData = options["contact"] as? JSObject {
425
+ self.populateContact(newContact, from: contactData)
426
+ }
427
+
428
+ let viewController = CNContactViewController(forNewContact: newContact)
429
+ viewController.delegate = self
430
+ viewController.contactStore = self.contactStore
431
+
432
+ let navController = UINavigationController(rootViewController: viewController)
433
+ self.currentPickerCall = call
434
+ self.bridge?.viewController?.present(navController, animated: true)
435
+ }
436
+ }
437
+
438
+ @objc func displayUpdateContactById(_ call: CAPPluginCall) {
439
+ guard let options = call.options["options"] as? JSObject,
440
+ let identifier = options["id"] as? String else {
441
+ call.reject("Missing contact identifier.")
442
+ return
443
+ }
444
+
445
+ ensureAuthorized(call) {
446
+ do {
447
+ let keysToFetch = self.keysToFetch(for: nil)
448
+ let contact = try self.contactStore.unifiedContact(withIdentifier: identifier, keysToFetch: keysToFetch)
449
+
450
+ DispatchQueue.main.async {
451
+ let mutableContact = contact.mutableCopy() as! CNMutableContact
452
+ let viewController = CNContactViewController(for: mutableContact)
453
+ viewController.allowsEditing = true
454
+ viewController.contactStore = self.contactStore
455
+
456
+ let navController = UINavigationController(rootViewController: viewController)
457
+ self.bridge?.viewController?.present(navController, animated: true)
458
+ call.resolve()
459
+ }
460
+ } catch {
461
+ call.reject("Failed to display contact for editing.", nil, error)
462
+ }
463
+ }
464
+ }
198
465
 
199
466
  // MARK: - Helpers
200
467
 
@@ -512,4 +779,230 @@ public class CapacitorContactsPlugin: CAPPlugin, CAPBridgedPlugin {
512
779
  return "unknown"
513
780
  }
514
781
  }
782
+
783
+ private func populateContact(_ contact: CNMutableContact, from data: JSObject) {
784
+ if let givenName = data["givenName"] as? String {
785
+ contact.givenName = givenName
786
+ }
787
+ if let familyName = data["familyName"] as? String {
788
+ contact.familyName = familyName
789
+ }
790
+ if let middleName = data["middleName"] as? String {
791
+ contact.middleName = middleName
792
+ }
793
+ if let namePrefix = data["namePrefix"] as? String {
794
+ contact.namePrefix = namePrefix
795
+ }
796
+ if let nameSuffix = data["nameSuffix"] as? String {
797
+ contact.nameSuffix = nameSuffix
798
+ }
799
+ if let organizationName = data["organizationName"] as? String {
800
+ contact.organizationName = organizationName
801
+ }
802
+ if let jobTitle = data["jobTitle"] as? String {
803
+ contact.jobTitle = jobTitle
804
+ }
805
+ if let note = data["note"] as? String {
806
+ contact.note = note
807
+ }
808
+
809
+ if let emailAddresses = data["emailAddresses"] as? [[String: Any]] {
810
+ contact.emailAddresses = emailAddresses.compactMap { emailData in
811
+ guard let value = emailData["value"] as? String else { return nil }
812
+ let label = emailData["type"] as? String ?? "OTHER"
813
+ let cnLabel = reverseMapEmailLabel(label, customLabel: emailData["label"] as? String)
814
+ return CNLabeledValue(label: cnLabel, value: value as NSString)
815
+ }
816
+ }
817
+
818
+ if let phoneNumbers = data["phoneNumbers"] as? [[String: Any]] {
819
+ contact.phoneNumbers = phoneNumbers.compactMap { phoneData in
820
+ guard let value = phoneData["value"] as? String else { return nil }
821
+ let label = phoneData["type"] as? String ?? "OTHER"
822
+ let cnLabel = reverseMapPhoneLabel(label, customLabel: phoneData["label"] as? String)
823
+ return CNLabeledValue(label: cnLabel, value: CNPhoneNumber(stringValue: value))
824
+ }
825
+ }
826
+
827
+ if let postalAddresses = data["postalAddresses"] as? [[String: Any]] {
828
+ contact.postalAddresses = postalAddresses.compactMap { addressData in
829
+ let postalAddress = CNMutablePostalAddress()
830
+ if let street = addressData["street"] as? String {
831
+ postalAddress.street = street
832
+ }
833
+ if let city = addressData["city"] as? String {
834
+ postalAddress.city = city
835
+ }
836
+ if let state = addressData["state"] as? String {
837
+ postalAddress.state = state
838
+ }
839
+ if let postalCode = addressData["postalCode"] as? String {
840
+ postalAddress.postalCode = postalCode
841
+ }
842
+ if let country = addressData["country"] as? String {
843
+ postalAddress.country = country
844
+ }
845
+ if let isoCountryCode = addressData["isoCountryCode"] as? String {
846
+ postalAddress.isoCountryCode = isoCountryCode
847
+ }
848
+ let label = addressData["type"] as? String ?? "OTHER"
849
+ let cnLabel = reverseMapPostalLabel(label, customLabel: addressData["label"] as? String)
850
+ return CNLabeledValue(label: cnLabel, value: postalAddress)
851
+ }
852
+ }
853
+
854
+ if let urlAddresses = data["urlAddresses"] as? [[String: Any]] {
855
+ contact.urlAddresses = urlAddresses.compactMap { urlData in
856
+ guard let value = urlData["value"] as? String else { return nil }
857
+ let label = urlData["type"] as? String ?? "OTHER"
858
+ let cnLabel = reverseMapURLLabel(label, customLabel: urlData["label"] as? String)
859
+ return CNLabeledValue(label: cnLabel, value: value as NSString)
860
+ }
861
+ }
862
+
863
+ if let birthdayData = data["birthday"] as? [String: Any] {
864
+ var dateComponents = DateComponents()
865
+ if let day = birthdayData["day"] as? Int {
866
+ dateComponents.day = day
867
+ }
868
+ if let month = birthdayData["month"] as? Int {
869
+ dateComponents.month = month
870
+ }
871
+ if let year = birthdayData["year"] as? Int {
872
+ dateComponents.year = year
873
+ }
874
+ contact.birthday = dateComponents
875
+ }
876
+
877
+ if let photoBase64 = data["photo"] as? String,
878
+ let photoData = Data(base64Encoded: photoBase64) {
879
+ contact.imageData = photoData
880
+ }
881
+ }
882
+
883
+ private func reverseMapEmailLabel(_ type: String, customLabel: String?) -> String {
884
+ switch type {
885
+ case "HOME":
886
+ return CNLabelHome
887
+ case "WORK":
888
+ return CNLabelWork
889
+ case "ICLOUD":
890
+ return CNLabelEmailiCloud
891
+ case "OTHER":
892
+ return CNLabelOther
893
+ case "CUSTOM":
894
+ return customLabel ?? CNLabelOther
895
+ default:
896
+ return CNLabelOther
897
+ }
898
+ }
899
+
900
+ private func reverseMapPhoneLabel(_ type: String, customLabel: String?) -> String {
901
+ switch type {
902
+ case "MOBILE":
903
+ return CNLabelPhoneNumberMobile
904
+ case "IPHONE":
905
+ return CNLabelPhoneNumberiPhone
906
+ case "MAIN":
907
+ return CNLabelPhoneNumberMain
908
+ case "HOME_FAX":
909
+ return CNLabelPhoneNumberHomeFax
910
+ case "WORK_FAX":
911
+ return CNLabelPhoneNumberWorkFax
912
+ case "OTHER_FAX":
913
+ return CNLabelPhoneNumberOtherFax
914
+ case "PAGER":
915
+ return CNLabelPhoneNumberPager
916
+ case "HOME":
917
+ return CNLabelHome
918
+ case "WORK":
919
+ return CNLabelWork
920
+ case "OTHER":
921
+ return CNLabelOther
922
+ case "CUSTOM":
923
+ return customLabel ?? CNLabelOther
924
+ default:
925
+ return CNLabelOther
926
+ }
927
+ }
928
+
929
+ private func reverseMapPostalLabel(_ type: String, customLabel: String?) -> String {
930
+ switch type {
931
+ case "HOME":
932
+ return CNLabelHome
933
+ case "WORK":
934
+ return CNLabelWork
935
+ case "OTHER":
936
+ return CNLabelOther
937
+ case "CUSTOM":
938
+ return customLabel ?? CNLabelOther
939
+ default:
940
+ return CNLabelOther
941
+ }
942
+ }
943
+
944
+ private func reverseMapURLLabel(_ type: String, customLabel: String?) -> String {
945
+ switch type {
946
+ case "HOMEPAGE":
947
+ return CNLabelURLAddressHomePage
948
+ case "HOME":
949
+ return CNLabelHome
950
+ case "WORK":
951
+ return CNLabelWork
952
+ case "OTHER":
953
+ return CNLabelOther
954
+ case "CUSTOM":
955
+ return customLabel ?? CNLabelOther
956
+ default:
957
+ return CNLabelOther
958
+ }
959
+ }
960
+ }
961
+
962
+ // MARK: - CNContactPickerDelegate
963
+
964
+ extension CapacitorContactsPlugin: CNContactPickerDelegate {
965
+ public func contactPicker(_ picker: CNContactPickerViewController, didSelect contacts: [CNContact]) {
966
+ guard let call = currentPickerCall else { return }
967
+ currentPickerCall = nil
968
+
969
+ let includeGroupIds = true
970
+ var membership: [String: [String]] = [:]
971
+ let contactIds = contacts.map(\.identifier)
972
+ membership = groupMembershipMap(for: contactIds)
973
+
974
+ let serialized = contacts.map { serialize(contact: $0, fields: nil, membership: membership) }
975
+ call.resolve(["contacts": serialized])
976
+ }
977
+
978
+ public func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact) {
979
+ guard let call = currentPickerCall else { return }
980
+ currentPickerCall = nil
981
+
982
+ let membership = groupMembershipMap(for: [contact.identifier])
983
+ let serialized = serialize(contact: contact, fields: nil, membership: membership)
984
+ call.resolve(["contacts": [serialized]])
985
+ }
986
+
987
+ public func contactPickerDidCancel(_ picker: CNContactPickerViewController) {
988
+ guard let call = currentPickerCall else { return }
989
+ currentPickerCall = nil
990
+ call.resolve(["contacts": []])
991
+ }
992
+ }
993
+
994
+ // MARK: - CNContactViewControllerDelegate
995
+
996
+ extension CapacitorContactsPlugin: CNContactViewControllerDelegate {
997
+ public func contactViewController(_ viewController: CNContactViewController, didCompleteWith contact: CNContact?) {
998
+ viewController.dismiss(animated: true)
999
+ guard let call = currentPickerCall else { return }
1000
+ currentPickerCall = nil
1001
+
1002
+ if let contact = contact {
1003
+ call.resolve(["id": contact.identifier])
1004
+ } else {
1005
+ call.resolve([:])
1006
+ }
1007
+ }
515
1008
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/capacitor-contacts",
3
- "version": "7.1.2",
3
+ "version": "8.0.1",
4
4
  "description": "Work with device contacts using Capacitor APIs",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",
@@ -16,7 +16,7 @@
16
16
  "CapgoCapacitorContacts.podspec"
17
17
  ],
18
18
  "author": "Cap-go <contact@capgo.app>",
19
- "license": "MIT",
19
+ "license": "MPL-2.0",
20
20
  "repository": {
21
21
  "type": "git",
22
22
  "url": "git+https://github.com/Cap-go/capacitor-contacts.git"
@@ -51,27 +51,27 @@
51
51
  "prepublishOnly": "npm run build"
52
52
  },
53
53
  "devDependencies": {
54
- "@capacitor/android": "^7.0.0",
55
- "@capacitor/cli": "^7.0.0",
56
- "@capacitor/core": "^7.0.0",
57
- "@capacitor/docgen": "^0.3.0",
58
- "@capacitor/ios": "^7.0.0",
54
+ "@capacitor/android": "^8.0.0",
55
+ "@capacitor/cli": "^8.0.0",
56
+ "@capacitor/core": "^8.0.0",
57
+ "@capacitor/docgen": "^0.3.1",
58
+ "@capacitor/ios": "^8.0.0",
59
59
  "@ionic/eslint-config": "^0.4.0",
60
60
  "@ionic/prettier-config": "^4.0.0",
61
61
  "@ionic/swiftlint-config": "^2.0.0",
62
- "@types/node": "^22.13.1",
63
- "eslint": "^8.57.0",
62
+ "@types/node": "^24.10.1",
63
+ "eslint": "^8.57.1",
64
64
  "eslint-plugin-import": "^2.31.0",
65
65
  "husky": "^9.1.7",
66
- "prettier": "^3.4.2",
67
- "prettier-plugin-java": "^2.6.7",
68
- "rimraf": "^6.0.1",
69
- "rollup": "^4.34.6",
66
+ "prettier": "^3.6.2",
67
+ "prettier-plugin-java": "^2.7.7",
68
+ "rimraf": "^6.1.0",
69
+ "rollup": "^4.53.2",
70
70
  "swiftlint": "^2.0.0",
71
- "typescript": "^5.7.3"
71
+ "typescript": "^5.9.3"
72
72
  },
73
73
  "peerDependencies": {
74
- "@capacitor/core": ">=7.0.0"
74
+ "@capacitor/core": ">=8.0.0"
75
75
  },
76
76
  "eslintConfig": {
77
77
  "extends": "@ionic/eslint-config/recommended"