@devioarts/capacitor-mdns 0.0.2 → 0.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.
Files changed (38) hide show
  1. package/Package.swift +1 -1
  2. package/README.md +54 -67
  3. package/android/build.gradle +11 -11
  4. package/android/src/main/AndroidManifest.xml +2 -0
  5. package/android/src/main/java/com/devioarts/capacitor/mdns/mDNS.kt +217 -51
  6. package/android/src/main/java/com/devioarts/capacitor/mdns/mDNSPlugin.kt +20 -9
  7. package/dist/docs.json +65 -3
  8. package/dist/esm/definitions.d.ts +28 -2
  9. package/dist/esm/definitions.js.map +1 -1
  10. package/dist/esm/index.js +1 -0
  11. package/dist/esm/index.js.map +1 -1
  12. package/dist/esm/web.d.ts +3 -1
  13. package/dist/esm/web.js +12 -3
  14. package/dist/esm/web.js.map +1 -1
  15. package/dist/plugin.cjs.js +13 -3
  16. package/dist/plugin.cjs.js.map +1 -1
  17. package/dist/plugin.js +13 -3
  18. package/dist/plugin.js.map +1 -1
  19. package/docs/electron.md +65 -0
  20. package/docs/platform-setup.md +52 -0
  21. package/docs/playground.md +19 -0
  22. package/docs/runtime-behavior.md +14 -0
  23. package/electron/dist/plugin-settings.js +15 -0
  24. package/electron/dist/plugin-settings.js.map +1 -0
  25. package/electron/dist/plugin.cjs.js +344 -0
  26. package/electron/dist/plugin.cjs.js.map +1 -0
  27. package/electron/global.d.ts +2 -0
  28. package/electron/mdns-bridge.cjs +9 -4
  29. package/electron/mdns.ts +151 -63
  30. package/electron/rollup.config.mjs +22 -0
  31. package/electron/src/index.ts +1 -0
  32. package/electron/src/plugin-settings.ts +12 -0
  33. package/electron/tsconfig.json +21 -0
  34. package/electron/types-public/index.d.ts +25 -0
  35. package/ios/Sources/mDNSPlugin/mDNS.swift +95 -28
  36. package/ios/Sources/mDNSPlugin/mDNSPlugin.swift +12 -3
  37. package/ios/Tests/mDNSPluginTests/mDNSPluginTests.swift +3 -9
  38. package/package.json +47 -22
@@ -10,11 +10,14 @@ import Network
10
10
  /// - Resolves each candidate with `NetService` to obtain `port`, `hosts`, and optional TXT.
11
11
  /// - Produces a normalized array of dictionaries consumable by the Capacitor bridge.
12
12
  public class MDNS: NSObject {
13
+ private static let publishTimeoutMs = 5000
13
14
 
14
15
  // MARK: - Advertising
15
16
 
16
17
  private var publisher: NetService?
17
18
  private var publishCompletion: ((Result<String, Error>) -> Void)?
19
+ private var publishTimeout: DispatchWorkItem?
20
+ private var publishSession: UInt64 = 0
18
21
 
19
22
  // MARK: - Discovery state
20
23
 
@@ -33,6 +36,8 @@ public class MDNS: NSObject {
33
36
 
34
37
  /// Completion invoked once with either success(array) or failure(error).
35
38
  private var discoverCompletion: ((Result<[[String: Any]], Error>) -> Void)?
39
+ private var discoveryError: Error?
40
+ private var discoverySession: UInt64 = 0
36
41
 
37
42
  /// Timers: hard timeout and short settle debounce.
38
43
  private var hardTimeout: DispatchWorkItem?
@@ -54,9 +59,20 @@ public class MDNS: NSObject {
54
59
  txt: [String: String]?,
55
60
  completion: @escaping (Result<String, Error>) -> Void
56
61
  ) {
62
+ guard (1...65535).contains(port) else {
63
+ completion(.failure(Self.error("Missing/invalid port")))
64
+ return
65
+ }
66
+
57
67
  runOnMain { [weak self] in
58
- guard let self = self else { return }
59
- self.stopPublisherIfNeeded()
68
+ guard let self = self else {
69
+ completion(.failure(Self.error("mDNS manager was released before publishing could start")))
70
+ return
71
+ }
72
+
73
+ self.publishSession &+= 1
74
+ let session = self.publishSession
75
+ self.stopPublisherIfNeeded(reason: "Replaced by a new broadcast request")
60
76
  self.publishCompletion = completion
61
77
 
62
78
  let svc = NetService(domain: "local.", type: type, name: name, port: Int32(port))
@@ -71,6 +87,7 @@ public class MDNS: NSObject {
71
87
 
72
88
  svc.delegate = self
73
89
  self.publisher = svc
90
+ self.schedulePublishTimeout(session: session)
74
91
  // Use default publish options; connection listening not required here.
75
92
  svc.publish()
76
93
  }
@@ -80,7 +97,7 @@ public class MDNS: NSObject {
80
97
  /// Exposed as `throws` by the bridge, but this implementation does not throw.
81
98
  public func stopBroadcast() throws {
82
99
  runOnMain { [weak self] in
83
- self?.stopPublisherIfNeeded()
100
+ self?.stopPublisherIfNeeded(reason: "Publish stopped before completion")
84
101
  }
85
102
  }
86
103
 
@@ -99,24 +116,35 @@ public class MDNS: NSObject {
99
116
  completion: @escaping (Result<[[String: Any]], Error>) -> Void
100
117
  ) {
101
118
  runOnMain { [weak self] in
102
- guard let self = self else { return }
119
+ guard let self = self else {
120
+ completion(.failure(Self.error("mDNS manager was released before discovery could start")))
121
+ return
122
+ }
123
+
124
+ if self.discoverCompletion != nil {
125
+ self.finishDiscovery(error: Self.error("Discovery replaced by a new request"))
126
+ }
127
+
128
+ self.discoverySession &+= 1
129
+ let session = self.discoverySession
103
130
  // Reset session state.
104
131
  self.cancelTimers()
105
132
  self.stopBrowsers()
106
133
  self.resolveMap.removeAll()
107
134
  self.discovered.removeAll()
108
135
  self.targetName = name
136
+ self.discoveryError = nil
109
137
  self.discoverCompletion = completion
110
138
 
111
139
  // Schedule hard timeout (always resolves/finishes).
112
- let ht = DispatchWorkItem { [weak self] in self?.finishDiscovery() }
140
+ let ht = DispatchWorkItem { [weak self] in self?.finishDiscovery(session: session) }
113
141
  self.hardTimeout = ht
114
142
  DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(max(0, timeoutMs)), execute: ht)
115
143
 
116
144
  // Start browsing: NWBrowser preferred when available and requested.
117
145
  #if canImport(Network)
118
146
  if useNW, #available(iOS 12.0, *) {
119
- self.startNWBrowse(typeWithDot: type)
147
+ self.startNWBrowse(typeWithDot: type, session: session)
120
148
  return
121
149
  }
122
150
  #endif
@@ -134,7 +162,7 @@ public class MDNS: NSObject {
134
162
 
135
163
  #if canImport(Network)
136
164
  @available(iOS 12.0, *)
137
- private func startNWBrowse(typeWithDot: String) {
165
+ private func startNWBrowse(typeWithDot: String, session: UInt64) {
138
166
  // NWBrowser expects type without trailing dot.
139
167
  let typeNoDot = typeWithDot.hasSuffix(".") ? String(typeWithDot.dropLast()) : typeWithDot
140
168
 
@@ -145,14 +173,11 @@ public class MDNS: NSObject {
145
173
  self.nwBrowser = browser
146
174
 
147
175
  browser.stateUpdateHandler = { state in
148
- // Intentionally quiet; errors are reflected via timeout or partial results.
149
- // print("[mDNS][NW] state: \(state)")
150
176
  switch state {
151
177
  case .failed(let err):
152
- // Do not finish immediately; let the hard timeout deliver partial results.
153
- // Optionally, one could trigger a fallback here.
154
- // print("[mDNS][NW] failed: \(err)")
155
- _ = err // silence unused
178
+ DispatchQueue.main.async { [weak self] in
179
+ self?.finishDiscovery(session: session, error: err)
180
+ }
156
181
  default:
157
182
  break
158
183
  }
@@ -160,6 +185,7 @@ public class MDNS: NSObject {
160
185
 
161
186
  browser.browseResultsChangedHandler = { [weak self] results, _ in
162
187
  guard let self = self else { return }
188
+ guard session == self.discoverySession, self.discoverCompletion != nil else { return }
163
189
  for r in results {
164
190
  guard case let NWEndpoint.service(name: n, type: t, domain: d, interface: _) = r.endpoint else { continue }
165
191
  if !self.matchesTarget(n) { continue }
@@ -180,7 +206,7 @@ public class MDNS: NSObject {
180
206
  resolver.resolve(withTimeout: 5.0)
181
207
 
182
208
  // Reschedule short settle window on each new find.
183
- self.scheduleSettleDebounce()
209
+ self.scheduleSettleDebounce(session: session)
184
210
  }
185
211
  }
186
212
 
@@ -191,7 +217,9 @@ public class MDNS: NSObject {
191
217
  // MARK: - Internal: finalize & helpers
192
218
 
193
219
  /// Build the final output and complete the discovery promise.
194
- private func finishDiscovery() {
220
+ private func finishDiscovery(session: UInt64? = nil, error: Error? = nil) {
221
+ if let session = session, session != discoverySession { return }
222
+
195
223
  cancelTimers()
196
224
  stopBrowsers()
197
225
 
@@ -219,10 +247,16 @@ public class MDNS: NSObject {
219
247
  resolveMap.removeAll()
220
248
  discovered.removeAll()
221
249
  targetName = nil
250
+ let finalError = error ?? discoveryError
251
+ discoveryError = nil
222
252
 
223
253
  let cb = discoverCompletion
224
254
  discoverCompletion = nil
225
- cb?(.success(out))
255
+ if let finalError = finalError {
256
+ cb?(.failure(finalError))
257
+ } else {
258
+ cb?(.success(out))
259
+ }
226
260
  }
227
261
 
228
262
  /// Cancel timers (hard timeout and settle debounce).
@@ -232,9 +266,10 @@ public class MDNS: NSObject {
232
266
  }
233
267
 
234
268
  /// Schedule a short debounce to finish discovery when the system becomes idle.
235
- private func scheduleSettleDebounce(_ ms: Int = 350) {
269
+ private func scheduleSettleDebounce(session: UInt64? = nil, _ ms: Int = 350) {
236
270
  settleDebounce?.cancel()
237
- let wi = DispatchWorkItem { [weak self] in self?.finishDiscovery() }
271
+ let session = session ?? discoverySession
272
+ let wi = DispatchWorkItem { [weak self] in self?.finishDiscovery(session: session) }
238
273
  settleDebounce = wi
239
274
  DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(ms), execute: wi)
240
275
  }
@@ -259,14 +294,27 @@ public class MDNS: NSObject {
259
294
  }
260
295
 
261
296
  /// Stop the current publisher, if any.
262
- private func stopPublisherIfNeeded() {
297
+ private func stopPublisherIfNeeded(reason: String) {
298
+ publishTimeout?.cancel()
299
+ publishTimeout = nil
263
300
  publisher?.stop()
264
301
  publisher?.delegate = nil
265
302
  publisher = nil
266
- // Do not call `publishCompletion` here: externally, `stopBroadcast()` should be considered a neutral action.
303
+ publishCompletion?(.failure(Self.error(reason)))
267
304
  publishCompletion = nil
268
305
  }
269
306
 
307
+ /// Enforce that NetService publish cannot leave a JS promise pending forever.
308
+ private func schedulePublishTimeout(session: UInt64) {
309
+ publishTimeout?.cancel()
310
+ let wi = DispatchWorkItem { [weak self] in
311
+ guard let self = self, session == self.publishSession, self.publishCompletion != nil else { return }
312
+ self.stopPublisherIfNeeded(reason: "Timed out waiting for service publish after \(Self.publishTimeoutMs)ms")
313
+ }
314
+ publishTimeout = wi
315
+ DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(Self.publishTimeoutMs), execute: wi)
316
+ }
317
+
270
318
  /// Normalize a service name by removing the system-appended `" (n)"` suffix.
271
319
  private func normalize(_ s: String) -> String {
272
320
  return s.replacingOccurrences(of: #" \(\d+\)$"#, with: "", options: .regularExpression)
@@ -288,6 +336,10 @@ public class MDNS: NSObject {
288
336
  private func runOnMain(_ block: @escaping () -> Void) {
289
337
  if Thread.isMainThread { block() } else { DispatchQueue.main.async(execute: block) }
290
338
  }
339
+
340
+ private static func error(_ message: String) -> NSError {
341
+ return NSError(domain: "mDNS", code: -1, userInfo: [NSLocalizedDescriptionKey: message])
342
+ }
291
343
  }
292
344
 
293
345
  // MARK: - NetServiceDelegate (publish + resolve)
@@ -296,12 +348,19 @@ extension MDNS: NetServiceDelegate {
296
348
 
297
349
  // Publish callbacks
298
350
  public func netServiceDidPublish(_ sender: NetService) {
351
+ guard sender === publisher else { return }
352
+ publishTimeout?.cancel()
353
+ publishTimeout = nil
299
354
  let cb = publishCompletion
300
355
  publishCompletion = nil
301
356
  cb?(.success(sender.name))
302
357
  }
303
358
 
304
359
  public func netService(_ sender: NetService, didNotPublish errorDict: [String: NSNumber]) {
360
+ guard sender === publisher else { return }
361
+ publishTimeout?.cancel()
362
+ publishTimeout = nil
363
+ publisher = nil
305
364
  let cb = publishCompletion
306
365
  publishCompletion = nil
307
366
  let code = (errorDict[NetService.errorCode] as NSNumber?)?.intValue ?? -1
@@ -318,8 +377,8 @@ extension MDNS: NetServiceDelegate {
318
377
  guard let box = resolveMap[sender] else { return }
319
378
  box.port = Int(sender.port)
320
379
  box.hosts = parseHosts(sender.addresses)
321
- if let txtData = sender.txtRecordData(),
322
- let dict = NetService.dictionary(fromTXTRecord: txtData) as? [String: Data] {
380
+ if let txtData = sender.txtRecordData() {
381
+ let dict = NetService.dictionary(fromTXTRecord: txtData)
323
382
  box.txt = dict.reduce(into: [:]) { acc, e in
324
383
  acc[e.key] = String(data: e.value, encoding: .utf8) ?? ""
325
384
  }
@@ -328,17 +387,17 @@ extension MDNS: NetServiceDelegate {
328
387
 
329
388
  // Early finish if a specific target is requested and this service matches it.
330
389
  if let t = targetName, !t.isEmpty, matchesTarget(sender.name) {
331
- finishDiscovery()
390
+ finishDiscovery(session: discoverySession)
332
391
  } else {
333
392
  // Otherwise, allow a brief settle window to collect late peers.
334
- scheduleSettleDebounce()
393
+ scheduleSettleDebounce(session: discoverySession)
335
394
  }
336
395
  }
337
396
 
338
397
  public func netService(_ sender: NetService, didNotResolve errorDict: [String: NSNumber]) {
339
398
  // Drop the unresolved service and try to continue with others.
340
399
  resolveMap.removeValue(forKey: sender)
341
- scheduleSettleDebounce()
400
+ scheduleSettleDebounce(session: discoverySession)
342
401
  }
343
402
  }
344
403
 
@@ -350,6 +409,9 @@ extension MDNS: NetServiceBrowserDelegate {
350
409
  // Early filter by instance name.
351
410
  guard matchesTarget(service.name) else { return }
352
411
 
412
+ let key = keyFor(name: service.name, type: service.type, domain: service.domain)
413
+ if discovered.contains(where: { $0.identityKey == key }) { return }
414
+
353
415
  // Create a dedicated resolver (do not reuse `service` directly).
354
416
  let resolver = NetService(domain: service.domain, type: service.type, name: service.name)
355
417
  resolver.includesPeerToPeer = true
@@ -363,7 +425,7 @@ extension MDNS: NetServiceBrowserDelegate {
363
425
  resolver.resolve(withTimeout: 5.0)
364
426
 
365
427
  // If this wave ends soon, schedule settle debounce; else wait for more.
366
- if !moreComing { scheduleSettleDebounce() }
428
+ if !moreComing { scheduleSettleDebounce(session: discoverySession) }
367
429
  }
368
430
 
369
431
  public func netServiceBrowser(_ browser: NetServiceBrowser, didRemove service: NetService, moreComing: Bool) {
@@ -371,8 +433,13 @@ extension MDNS: NetServiceBrowserDelegate {
371
433
  }
372
434
 
373
435
  public func netServiceBrowser(_ browser: NetServiceBrowser, didNotSearch errorDict: [String: NSNumber]) {
374
- // Gracefully complete with whatever we have (plugin will surface error=true).
375
- finishDiscovery()
436
+ let code = (errorDict[NetService.errorCode] as NSNumber?)?.intValue ?? -1
437
+ let err = NSError(
438
+ domain: "mDNS.discovery",
439
+ code: code,
440
+ userInfo: [NSLocalizedDescriptionKey: "Failed to search for services", "info": errorDict]
441
+ )
442
+ finishDiscovery(session: discoverySession, error: err)
376
443
  }
377
444
  }
378
445
 
@@ -20,6 +20,7 @@ public class mDNSPlugin: CAPPlugin, CAPBridgedPlugin {
20
20
  public let identifier = "mDNSPlugin"
21
21
  public let jsName = "mDNS"
22
22
  public let pluginMethods: [CAPPluginMethod] = [
23
+ CAPPluginMethod(name: "getPluginPlatform", returnType: CAPPluginReturnPromise),
23
24
  CAPPluginMethod(name: "startBroadcast", returnType: CAPPluginReturnPromise),
24
25
  CAPPluginMethod(name: "stopBroadcast", returnType: CAPPluginReturnPromise),
25
26
  CAPPluginMethod(name: "discover", returnType: CAPPluginReturnPromise)
@@ -34,13 +35,21 @@ public class mDNSPlugin: CAPPlugin, CAPBridgedPlugin {
34
35
  }
35
36
 
36
37
  private func normalizeType(_ raw: String?) -> String {
37
- var t = raw ?? "_http._tcp."
38
+ var t = raw?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
39
+ if t.isEmpty { t = "_http._tcp." }
38
40
  if t.last != "." { t += "." }
39
41
  return t
40
42
  }
41
43
 
42
44
  // MARK: - API
43
45
 
46
+ /// getPluginPlatform()
47
+ @objc public func getPluginPlatform(_ call: CAPPluginCall) {
48
+ call.resolve([
49
+ "platform": "ios"
50
+ ])
51
+ }
52
+
44
53
  /// startBroadcast({ type?, name?, port, txt? })
45
54
  @objc public func startBroadcast(_ call: CAPPluginCall) {
46
55
  let type = normalizeType(call.getString("type"))
@@ -48,7 +57,7 @@ public class mDNSPlugin: CAPPlugin, CAPBridgedPlugin {
48
57
  let port = call.getInt("port") ?? 0
49
58
  let txt = call.getObject("txt") as? [String: String]
50
59
 
51
- guard port > 0 else {
60
+ guard (1...65535).contains(port) else {
52
61
  call.resolve([
53
62
  "publishing": false,
54
63
  "name": "",
@@ -99,7 +108,7 @@ public class mDNSPlugin: CAPPlugin, CAPBridgedPlugin {
99
108
  /// discover({ type?, name?, timeout? })
100
109
  @objc public func discover(_ call: CAPPluginCall) {
101
110
  let type = normalizeType(call.getString("type"))
102
- let targetName = call.getString("name")
111
+ let targetName = (call.getString("name")?.trimmingCharacters(in: .whitespacesAndNewlines)).flatMap { $0.isEmpty ? nil : $0 }
103
112
  let timeout = call.getInt("timeout") ?? 3000
104
113
  let useNW = call.getBool("useNW") ?? true
105
114
 
@@ -2,14 +2,8 @@ import XCTest
2
2
  @testable import mDNSPlugin
3
3
 
4
4
  class mDNSTests: XCTestCase {
5
- func testEcho() {
6
- // This is an example of a functional test case for a plugin.
7
- // Use XCTAssert and related functions to verify your tests produce the correct results.
8
-
9
- let implementation = mDNS()
10
- let value = "Hello, World!"
11
- let result = implementation.echo(value)
12
-
13
- XCTAssertEqual(value, result)
5
+ func testManagerCanBeCreated() {
6
+ let implementation = MDNS()
7
+ XCTAssertNotNil(implementation)
14
8
  }
15
9
  }
package/package.json CHANGED
@@ -1,16 +1,42 @@
1
1
  {
2
2
  "name": "@devioarts/capacitor-mdns",
3
- "version": "0.0.2",
3
+ "version": "0.1.0",
4
4
  "description": "mDNS plugin for CapacitorJS",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",
7
7
  "types": "dist/esm/index.d.ts",
8
8
  "unpkg": "dist/plugin.js",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/esm/index.d.ts",
12
+ "import": "./dist/esm/index.js",
13
+ "require": "./dist/plugin.cjs.js",
14
+ "default": "./dist/esm/index.js"
15
+ },
16
+ "./electron": {
17
+ "types": "./electron/types-public/index.d.ts",
18
+ "require": "./electron/dist/plugin.cjs.js",
19
+ "default": "./electron/dist/plugin.cjs.js"
20
+ },
21
+ "./electron/settings": {
22
+ "types": "./electron/types-public/index.d.ts",
23
+ "require": "./electron/dist/plugin-settings.js",
24
+ "default": "./electron/dist/plugin-settings.js"
25
+ },
26
+ "./electron/mdns": {
27
+ "types": "./electron/types-public/index.d.ts",
28
+ "require": "./electron/dist/plugin.cjs.js",
29
+ "default": "./electron/dist/plugin.cjs.js"
30
+ },
31
+ "./electron/mdns-bridge.cjs": "./electron/mdns-bridge.cjs",
32
+ "./package.json": "./package.json"
33
+ },
9
34
  "files": [
10
35
  "android/src/main/",
11
36
  "android/build.gradle",
12
37
  "dist/",
13
38
  "electron/",
39
+ "docs/",
14
40
  "ios/Sources",
15
41
  "ios/Tests",
16
42
  "Package.swift",
@@ -45,43 +71,42 @@
45
71
  "verify:web": "npm run build",
46
72
  "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint",
47
73
  "fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- --fix --format",
48
- "eslint": "eslint . --ext ts",
74
+ "eslint": "eslint src electron --ext ts",
49
75
  "prettier": "prettier \"**/*.{css,html,ts,js,java}\" --plugin=prettier-plugin-java",
50
76
  "swiftlint": "node-swiftlint",
51
77
  "docgen": "docgen --api mDNSPlugin --output-readme README.md --output-json dist/docs.json",
52
- "build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.mjs",
53
- "clean": "rimraf ./dist",
78
+ "build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.mjs && npm run build-electron",
79
+ "build-electron": "tsc --project electron/tsconfig.json && rollup -c electron/rollup.config.mjs && rimraf ./electron/build",
80
+ "clean": "rimraf ./dist ./electron/dist ./electron/build",
54
81
  "watch": "tsc --watch",
55
- "test": "echo \"No test specified\"",
82
+ "test": "npm run test:e2e",
83
+ "test:e2e": "rimraf .tmp/e2e-build && tsc -p tsconfig.e2e.json && node --test test/e2e/*.e2e.cjs",
56
84
  "prepublishOnly": "npm run build",
57
85
  "release": "npm publish --access public"
58
86
  },
59
87
  "devDependencies": {
60
- "@capacitor/android": "^7.0.0",
61
- "@capacitor/core": "^7.0.0",
88
+ "@capacitor/android": "^8.0.0",
89
+ "@capacitor/core": "^8.0.0",
62
90
  "@capacitor/docgen": "^0.3.0",
63
- "@capacitor/ios": "^7.0.0",
64
- "@ionic/eslint-config": "^0.4.0",
91
+ "@capacitor/ios": "^8.0.0",
65
92
  "@ionic/prettier-config": "^4.0.0",
66
93
  "@ionic/swiftlint-config": "^2.0.0",
67
- "eslint": "^8.57.0",
68
- "prettier": "^3.4.2",
69
- "prettier-plugin-java": "^2.6.6",
70
- "rimraf": "^6.0.1",
71
- "rollup": "^4.30.1",
94
+ "@typescript-eslint/eslint-plugin": "^8.63.0",
95
+ "@typescript-eslint/parser": "^8.63.0",
96
+ "bonjour-service": "^1.4.0",
97
+ "electron": "^43.0.0",
98
+ "eslint": "^10.6.0",
99
+ "prettier": "^3.9.0",
100
+ "prettier-plugin-java": "^2.10.0",
101
+ "rimraf": "^6.1.0",
102
+ "rollup": "^4.62.0",
72
103
  "swiftlint": "^2.0.0",
73
- "typescript": "~4.1.5",
74
- "electron": "^37.3.1",
75
- "bonjour-service": "^1.3.0"
104
+ "typescript": "^6.0.0"
76
105
  },
77
106
  "peerDependencies": {
78
- "@capacitor/core": ">=7.0.0"
107
+ "@capacitor/core": ">=8.0.0"
79
108
  },
80
109
  "prettier": "@ionic/prettier-config",
81
- "swiftlint": "@ionic/swiftlint-config",
82
- "eslintConfig": {
83
- "extends": "@ionic/eslint-config/recommended"
84
- },
85
110
  "capacitor": {
86
111
  "ios": {
87
112
  "src": "ios"