@cappitolian/network-discovery 0.0.12 → 0.0.14

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,158 +1,171 @@
1
1
  import Foundation
2
+ import Network
2
3
 
3
4
  @objc public class NetworkDiscovery: NSObject {
4
- private var netService: NetService?
5
- private var netServiceBrowser: NetServiceBrowser?
6
- private var discoveredServices: [NetService] = []
7
-
8
- weak var delegate: NetworkDiscoveryDelegate?
9
-
10
- @objc public func startAdvertising(
11
- serviceName: String,
12
- serviceType: String,
13
- port: Int,
14
- txtRecord: [String: String]?
15
- ) {
16
- netService = NetService(domain: "local.", type: serviceType, name: serviceName, port: Int32(port))
5
+ private var listener: NWListener?
6
+ private var browser: NWBrowser?
7
+ private var activeConnections: [NWConnection] = []
8
+
9
+ @objc public func startPublishing(name: String, type: String, port: Int, metadata: [String: String]) throws {
10
+ stopServer()
11
+ let nwPort = NWEndpoint.Port(integerLiteral: UInt16(port))
12
+ let cleanType = type.contains("_") ? type : "_\(type)._tcp"
17
13
 
18
- // Configurar TXT record
19
- if let txtRecord = txtRecord, !txtRecord.isEmpty {
20
- var txtData: [String: Data] = [:]
21
- for (key, value) in txtRecord {
22
- txtData[key] = value.data(using: .utf8)
23
- }
24
- let txtRecordData = NetService.data(fromTXTRecord: txtData)
25
- netService?.setTXTRecord(txtRecordData)
14
+ let ipForName = metadata["ip"] ?? ""
15
+ let displayName = ipForName.isEmpty ? name : "\(name)-\(ipForName)"
16
+
17
+ let mappedMetadata = metadata.mapValues { $0.data(using: .utf8)! }
18
+ let txtData = NetService.data(fromTXTRecord: mappedMetadata)
19
+
20
+ // --- CONFIGURACIÓN MEJORADA PARA COMPATIBILIDAD CROSS-PLATFORM ---
21
+ let params = NWParameters.tcp
22
+ params.includePeerToPeer = true
23
+ params.allowLocalEndpointReuse = true // Permite reutilización del puerto
24
+ params.acceptLocalOnly = false // Acepta conexiones de toda la red local
25
+
26
+ // Configuración adicional para que Android pueda resolver
27
+ if let tcpOptions = params.defaultProtocolStack.internetProtocol as? NWProtocolIP.Options {
28
+ tcpOptions.version = .any // IPv4 e IPv6
26
29
  }
27
30
 
28
- netService?.delegate = self
29
- netService?.publish()
30
- }
31
-
32
- @objc public func stopAdvertising() {
33
- netService?.stop()
34
- netService = nil
35
- }
36
-
37
- @objc public func startDiscovery(serviceType: String, domain: String = "local.") {
38
- netServiceBrowser = NetServiceBrowser()
39
- netServiceBrowser?.delegate = self
40
- netServiceBrowser?.searchForServices(ofType: serviceType, inDomain: domain)
41
- }
42
-
43
- @objc public func stopDiscovery() {
44
- netServiceBrowser?.stop()
45
- netServiceBrowser = nil
46
- discoveredServices.removeAll()
47
- }
48
- }
49
-
50
- // MARK: - NetServiceDelegate
51
- extension NetworkDiscovery: NetServiceDelegate {
52
- public func netServiceDidPublish(_ sender: NetService) {
53
- print("Service published: \(sender.name)")
54
- delegate?.advertisingDidStart()
55
- }
56
-
57
- public func netService(_ sender: NetService, didNotPublish errorDict: [String : NSNumber]) {
58
- print("Service did not publish: \(errorDict)")
59
- let errorCode = errorDict[NetService.errorCode]?.intValue ?? -1
60
- delegate?.advertisingDidFail(error: "Failed to publish service. Error code: \(errorCode)")
61
- }
62
- }
63
-
64
- // MARK: - NetServiceBrowserDelegate
65
- extension NetworkDiscovery: NetServiceBrowserDelegate {
66
- public func netServiceBrowserDidStopSearch(_ browser: NetServiceBrowser) {
67
- print("Service discovery stopped")
68
- }
69
-
70
- public func netServiceBrowser(_ browser: NetServiceBrowser, didNotSearch errorDict: [String : NSNumber]) {
71
- print("Service discovery failed: \(errorDict)")
72
- let errorCode = errorDict[NetService.errorCode]?.intValue ?? -1
73
- delegate?.discoveryDidFail(error: "Discovery failed. Error code: \(errorCode)")
74
- }
75
-
76
- public func netServiceBrowser(_ browser: NetServiceBrowser, didFind service: NetService, moreComing: Bool) {
77
- print("Service found: \(service.name)")
78
- discoveredServices.append(service)
79
- service.delegate = self
80
- service.resolve(withTimeout: 5.0)
81
- }
82
-
83
- public func netServiceBrowser(_ browser: NetServiceBrowser, didRemove service: NetService, moreComing: Bool) {
84
- print("Service lost: \(service.name)")
31
+ let service = NWListener.Service(name: displayName, type: cleanType, domain: nil, txtRecord: txtData)
32
+
33
+ listener = try NWListener(using: params, on: nwPort)
34
+ listener?.service = service
35
+
36
+ // --- HANDLER CRÍTICO: Aceptar conexiones entrantes ---
37
+ listener?.newConnectionHandler = { [weak self] connection in
38
+ print("NSD_LOG: iOS recibió conexión de: \(connection.endpoint)")
39
+
40
+ // Iniciar la conexión para que Android pueda resolver el servicio
41
+ connection.start(queue: .main)
42
+ self?.activeConnections.append(connection)
43
+
44
+ // Configurar handlers básicos
45
+ connection.stateUpdateHandler = { state in
46
+ if case .ready = state {
47
+ print("NSD_LOG: Conexión establecida con Android")
48
+ }
49
+ }
50
+
51
+ // Limpieza automática cuando la conexión termine
52
+ connection.receiveMessage { _, _, _, error in
53
+ if error != nil {
54
+ connection.cancel()
55
+ self?.activeConnections.removeAll { $0 === connection }
56
+ }
57
+ }
58
+ }
85
59
 
86
- let serviceData: [String: Any] = [
87
- "serviceName": service.name,
88
- "serviceType": service.type
89
- ]
60
+ listener?.stateUpdateHandler = { state in
61
+ switch state {
62
+ case .ready:
63
+ if let port = self.listener?.port {
64
+ print("NSD_LOG: ✅ iOS Servidor LISTO en puerto \(port): \(displayName)")
65
+ }
66
+ case .failed(let error):
67
+ print("NSD_LOG: ❌ iOS Servidor falló: \(error)")
68
+ case .waiting(let error):
69
+ print("NSD_LOG: ⏳ iOS Servidor esperando: \(error)")
70
+ default:
71
+ break
72
+ }
73
+ }
90
74
 
91
- delegate?.serviceLost(serviceData: serviceData)
75
+ listener?.start(queue: .main)
92
76
 
93
- if let index = discoveredServices.firstIndex(of: service) {
94
- discoveredServices.remove(at: index)
77
+ // Pequeño delay para asegurar que el servicio esté completamente publicado
78
+ DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
79
+ print("NSD_LOG: Servicio iOS completamente inicializado")
95
80
  }
96
81
  }
97
-
98
- public func netServiceDidResolveAddress(_ sender: NetService) {
99
- print("Service resolved: \(sender.name)")
82
+
83
+ @objc public func findService(name: String, type: String, timeout: TimeInterval, completion: @escaping ([String: Any]?) -> Void) {
84
+ stopDiscovery()
85
+ let cleanType = type.contains("_") ? type : "_\(type)._tcp"
100
86
 
101
- var addresses: [String] = []
87
+ // Configuración mejorada para el browser
88
+ let params = NWParameters()
89
+ params.includePeerToPeer = true
102
90
 
103
- if let addressesData = sender.addresses {
104
- for addressData in addressesData {
105
- let address = addressData.withUnsafeBytes { (pointer: UnsafeRawBufferPointer) -> String? in
106
- guard let baseAddress = pointer.baseAddress else { return nil }
107
- let data = baseAddress.assumingMemoryBound(to: sockaddr.self)
108
-
109
- var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
110
- if getnameinfo(data, socklen_t(addressData.count), &hostname, socklen_t(hostname.count), nil, 0, NI_NUMERICHOST) == 0 {
111
- return String(cString: hostname)
91
+ let browser = NWBrowser(for: .bonjour(type: cleanType, domain: nil), using: params)
92
+ self.browser = browser
93
+ var finished = false
94
+
95
+ browser.browseResultsChangedHandler = { [weak self] results, _ in
96
+ for result in results {
97
+ if case let .service(foundName, _, _, _) = result.endpoint, foundName.contains(name) {
98
+ if !finished {
99
+ finished = true
100
+
101
+ print("NSD_LOG: iOS Cliente encontró servicio: \(foundName)")
102
+
103
+ var meta: [String: String] = [:]
104
+ if case let .bonjour(txt) = result.metadata {
105
+ for (k, v) in txt.dictionary {
106
+ if let dataValue = v as? Data {
107
+ meta[k] = String(data: dataValue, encoding: .utf8) ?? ""
108
+ }
109
+ }
110
+ }
111
+
112
+ // --- LÓGICA DE EXTRACCIÓN ROBUSTA ---
113
+ var ip = meta["ip"] ?? ""
114
+
115
+ if (ip.isEmpty || ip == "0.0.0.0") && foundName.contains("-") {
116
+ ip = foundName.components(separatedBy: "-").last ?? ""
117
+ }
118
+
119
+ if ip.isEmpty || ip == "0.0.0.0" {
120
+ if case let .hostPort(host, _) = result.endpoint {
121
+ ip = "\(host)".components(separatedBy: "%").first ?? "\(host)"
122
+ }
123
+ }
124
+
125
+ print("NSD_LOG: IP extraída: \(ip)")
126
+
127
+ self?.stopDiscovery()
128
+ completion(["ip": ip, "port": 8081, "metadata": meta])
112
129
  }
113
- return nil
114
- }
115
-
116
- if let addr = address {
117
- addresses.append(addr)
130
+ return
118
131
  }
119
132
  }
120
133
  }
121
134
 
122
- var serviceData: [String: Any] = [
123
- "serviceName": sender.name,
124
- "serviceType": sender.type,
125
- "domain": sender.domain,
126
- "hostName": sender.hostName ?? "",
127
- "port": sender.port,
128
- "addresses": addresses
129
- ]
135
+ browser.stateUpdateHandler = { state in
136
+ switch state {
137
+ case .ready:
138
+ print("NSD_LOG: iOS Browser listo para buscar")
139
+ case .failed(let error):
140
+ print("NSD_LOG: iOS Browser falló: \(error)")
141
+ default:
142
+ break
143
+ }
144
+ }
130
145
 
131
- // Agregar TXT record
132
- if let txtData = sender.txtRecordData() {
133
- let txtRecord = NetService.dictionary(fromTXTRecord: txtData)
134
- var txtRecordDict: [String: String] = [:]
135
- for (key, value) in txtRecord {
136
- if let strValue = String(data: value, encoding: .utf8) {
137
- txtRecordDict[key] = strValue
138
- }
146
+ browser.start(queue: .main)
147
+ DispatchQueue.main.asyncAfter(deadline: .now() + timeout) { [weak self] in
148
+ if !finished {
149
+ finished = true
150
+ print("NSD_LOG: iOS Búsqueda timeout")
151
+ self?.stopDiscovery()
152
+ completion(nil)
139
153
  }
140
- serviceData["txtRecord"] = txtRecordDict
141
154
  }
155
+ }
156
+
157
+ @objc public func stopServer() {
158
+ // Limpiar todas las conexiones activas
159
+ activeConnections.forEach { $0.cancel() }
160
+ activeConnections.removeAll()
142
161
 
143
- delegate?.serviceFound(serviceData: serviceData)
162
+ listener?.cancel()
163
+ listener = nil
164
+ print("NSD_LOG: iOS Servidor detenido")
144
165
  }
145
166
 
146
- public func netService(_ sender: NetService, didNotResolve errorDict: [String : NSNumber]) {
147
- print("Service did not resolve: \(errorDict)")
167
+ @objc public func stopDiscovery() {
168
+ browser?.cancel()
169
+ browser = nil
148
170
  }
149
- }
150
-
151
- // MARK: - Delegate Protocol
152
- @objc public protocol NetworkDiscoveryDelegate: AnyObject {
153
- func advertisingDidStart()
154
- func advertisingDidFail(error: String)
155
- func serviceFound(serviceData: [String: Any])
156
- func serviceLost(serviceData: [String: Any])
157
- func discoveryDidFail(error: String)
158
171
  }
@@ -1,104 +1,43 @@
1
- import Foundation
2
- import Capacitor
3
-
4
- @objc(NetworkDiscoveryPlugin)
5
- public class NetworkDiscoveryPlugin: CAPPlugin, CAPBridgedPlugin, NetworkDiscoveryDelegate {
6
-
7
- // MARK: - CAPBridgedPlugin Properties
8
- public let identifier = "NetworkDiscoveryPlugin"
9
- public let jsName = "NetworkDiscovery"
10
- public let pluginMethods: [CAPPluginMethod] = [
11
- CAPPluginMethod(name: "startAdvertising", returnType: CAPPluginReturnPromise),
12
- CAPPluginMethod(name: "stopAdvertising", returnType: CAPPluginReturnPromise),
13
- CAPPluginMethod(name: "startDiscovery", returnType: CAPPluginReturnPromise),
14
- CAPPluginMethod(name: "stopDiscovery", returnType: CAPPluginReturnPromise)
15
- ]
16
-
17
- // MARK: - Properties
18
- private var implementation: NetworkDiscovery?
19
-
20
- // MARK: - Lifecycle
21
- public override func load() {
22
- print("✅ NetworkDiscoveryPlugin: Plugin loaded")
23
- implementation = NetworkDiscovery()
24
- implementation?.delegate = self
25
- }
26
-
27
- // MARK: - Plugin Methods
28
- @objc func startAdvertising(_ call: CAPPluginCall) {
29
- print("📞 NetworkDiscoveryPlugin: startAdvertising() called")
30
-
31
- guard let serviceName = call.getString("serviceName"),
32
- let serviceType = call.getString("serviceType"),
33
- let port = call.getInt("port") else {
34
- call.reject("Missing required parameters")
35
- return
36
- }
37
-
38
- let txtRecord = call.getObject("txtRecord") as? [String: String]
39
-
40
- print("📡 NetworkDiscoveryPlugin: Starting advertising - \(serviceName)")
41
-
42
- implementation?.startAdvertising(
43
- serviceName: serviceName,
44
- serviceType: serviceType,
45
- port: port,
46
- txtRecord: txtRecord
47
- )
48
-
49
- call.resolve(["success": true])
50
- }
51
-
52
- @objc func stopAdvertising(_ call: CAPPluginCall) {
53
- print("📞 NetworkDiscoveryPlugin: stopAdvertising() called")
54
- implementation?.stopAdvertising()
55
- call.resolve(["success": true])
56
- }
57
-
58
- @objc func startDiscovery(_ call: CAPPluginCall) {
59
- print("📞 NetworkDiscoveryPlugin: startDiscovery() called")
60
-
61
- guard let serviceType = call.getString("serviceType") else {
62
- call.reject("Missing serviceType parameter")
63
- return
64
- }
65
-
66
- let domain = call.getString("domain") ?? "local."
67
-
68
- print("🔍 NetworkDiscoveryPlugin: Starting discovery for \(serviceType)")
69
-
70
- implementation?.startDiscovery(serviceType: serviceType, domain: domain)
71
- call.resolve()
72
- }
73
-
74
- @objc func stopDiscovery(_ call: CAPPluginCall) {
75
- print("📞 NetworkDiscoveryPlugin: stopDiscovery() called")
76
- implementation?.stopDiscovery()
77
- call.resolve(["success": true])
78
- }
79
-
80
- // MARK: - NetworkDiscoveryDelegate
81
- public func advertisingDidStart() {
82
- print("✅ NetworkDiscoveryPlugin: Advertising started successfully")
83
- }
84
-
85
- public func advertisingDidFail(error: String) {
86
- print("❌ NetworkDiscoveryPlugin: Advertising failed - \(error)")
87
- }
88
-
89
- public func serviceFound(serviceData: [String : Any]) {
90
- print("📨 NetworkDiscoveryPlugin: Service found, notifying listeners")
91
- print(" Service data: \(serviceData)")
92
- notifyListeners("serviceFound", data: serviceData)
93
- }
94
-
95
- public func serviceLost(serviceData: [String : Any]) {
96
- print("📨 NetworkDiscoveryPlugin: Service lost, notifying listeners")
97
- print(" Service data: \(serviceData)")
98
- notifyListeners("serviceLost", data: serviceData)
99
- }
100
-
101
- public func discoveryDidFail(error: String) {
102
- print("❌ NetworkDiscoveryPlugin: Discovery failed - \(error)")
103
- }
1
+ import Foundation
2
+ import Capacitor
3
+
4
+ @objc(NetworkDiscoveryPlugin)
5
+ public class NetworkDiscoveryPlugin: CAPPlugin, CAPBridgedPlugin {
6
+ public let identifier = "NetworkDiscoveryPlugin"
7
+ public let jsName = "NetworkDiscovery"
8
+ public let pluginMethods: [CAPPluginMethod] = [
9
+ CAPPluginMethod(name: "startServer", returnType: CAPPluginReturnPromise),
10
+ CAPPluginMethod(name: "stopServer", returnType: CAPPluginReturnPromise),
11
+ CAPPluginMethod(name: "findServer", returnType: CAPPluginReturnPromise)
12
+ ]
13
+
14
+ private let implementation = NetworkDiscovery()
15
+
16
+ @objc func startServer(_ call: CAPPluginCall) {
17
+ guard let name = call.getString("serviceName"),
18
+ let type = call.getString("serviceType"),
19
+ let port = call.getInt("port") else { return call.reject("Faltan parámetros") }
20
+
21
+ let metadata = call.getObject("metadata") as? [String: String] ?? [:]
22
+ do {
23
+ try implementation.startPublishing(name: name, type: type, port: port, metadata: metadata)
24
+ call.resolve()
25
+ } catch { call.reject(error.localizedDescription) }
26
+ }
27
+
28
+ @objc func stopServer(_ call: CAPPluginCall) {
29
+ implementation.stopServer()
30
+ call.resolve()
31
+ }
32
+
33
+ @objc func findServer(_ call: CAPPluginCall) {
34
+ guard let name = call.getString("serviceName"),
35
+ let type = call.getString("serviceType") else { return call.reject("Faltan parámetros") }
36
+
37
+ let timeout = Double(call.getInt("timeout") ?? 10000) / 1000.0
38
+ implementation.findService(name: name, type: type, timeout: timeout) { result in
39
+ if let data = result { call.resolve(data) }
40
+ else { call.reject("TIMEOUT_ERROR") }
41
+ }
42
+ }
104
43
  }
package/package.json CHANGED
@@ -1,86 +1,86 @@
1
- {
2
- "name": "@cappitolian/network-discovery",
3
- "version": "0.0.12",
4
- "description": "A Capacitor plugin for network service discovery using mDNS/Bonjour. Allows automatic server-client connection without manual IP configuration.",
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
- "CappitolianNetworkDiscovery.podspec"
17
- ],
18
- "author": "Cappitolian",
19
- "license": "MIT",
20
- "repository": {
21
- "type": "git",
22
- "url": "git+https://github.com/alessandrycruz1987/network-discovery.git"
23
- },
24
- "bugs": {
25
- "url": "https://github.com/alessandrycruz1987/network-discovery.git/issues"
26
- },
27
- "keywords": [
28
- "capacitor",
29
- "plugin",
30
- "native",
31
- "network",
32
- "discovery",
33
- "mdns",
34
- "bonjour",
35
- "nsd",
36
- "zeroconf"
37
- ],
38
- "scripts": {
39
- "verify": "npm run verify:ios && npm run verify:android && npm run verify:web",
40
- "verify:ios": "xcodebuild -scheme CappitolianNetworkDiscovery -destination generic/platform=iOS",
41
- "verify:android": "cd android && ./gradlew clean build test && cd ..",
42
- "verify:web": "npm run build",
43
- "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint",
44
- "fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- --fix --format",
45
- "eslint": "eslint . --ext ts",
46
- "prettier": "prettier \"**/*.{css,html,ts,js,java}\" --plugin=prettier-plugin-java",
47
- "swiftlint": "node-swiftlint",
48
- "docgen": "docgen --api NetworkDiscoveryPlugin --output-readme README.md --output-json dist/docs.json",
49
- "build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.mjs",
50
- "clean": "rimraf ./dist",
51
- "watch": "tsc --watch",
52
- "prepublishOnly": "npm run build"
53
- },
54
- "devDependencies": {
55
- "@capacitor/android": "^7.4.5",
56
- "@capacitor/core": "^7.4.5",
57
- "@capacitor/docgen": "^0.3.1",
58
- "@capacitor/ios": "^7.4.5",
59
- "@ionic/eslint-config": "^0.4.0",
60
- "@ionic/prettier-config": "^4.0.0",
61
- "@ionic/swiftlint-config": "^2.0.0",
62
- "eslint": "^8.57.1",
63
- "prettier": "^3.6.2",
64
- "prettier-plugin-java": "^2.7.7",
65
- "rimraf": "^6.1.0",
66
- "rollup": "^4.53.2",
67
- "swiftlint": "^2.0.0",
68
- "typescript": "^5.9.3"
69
- },
70
- "peerDependencies": {
71
- "@capacitor/core": ">=7.0.0"
72
- },
73
- "prettier": "@ionic/prettier-config",
74
- "swiftlint": "@ionic/swiftlint-config",
75
- "eslintConfig": {
76
- "extends": "@ionic/eslint-config/recommended"
77
- },
78
- "capacitor": {
79
- "ios": {
80
- "src": "ios"
81
- },
82
- "android": {
83
- "src": "android"
84
- }
85
- }
1
+ {
2
+ "name": "@cappitolian/network-discovery",
3
+ "version": "0.0.14",
4
+ "description": "A Capacitor plugin for network service discovery using mDNS/Bonjour. Allows automatic server-client connection without manual IP configuration.",
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
+ "CappitolianNetworkDiscovery.podspec"
17
+ ],
18
+ "author": "Cappitolian",
19
+ "license": "MIT",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/alessandrycruz1987/network-discovery.git"
23
+ },
24
+ "bugs": {
25
+ "url": "https://github.com/alessandrycruz1987/network-discovery.git/issues"
26
+ },
27
+ "keywords": [
28
+ "capacitor",
29
+ "plugin",
30
+ "native",
31
+ "network",
32
+ "discovery",
33
+ "mdns",
34
+ "bonjour",
35
+ "nsd",
36
+ "zeroconf"
37
+ ],
38
+ "scripts": {
39
+ "verify": "npm run verify:ios && npm run verify:android && npm run verify:web",
40
+ "verify:ios": "xcodebuild -scheme CappitolianNetworkDiscovery -destination generic/platform=iOS",
41
+ "verify:android": "cd android && ./gradlew clean build test && cd ..",
42
+ "verify:web": "npm run build",
43
+ "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint",
44
+ "fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- --fix --format",
45
+ "eslint": "eslint . --ext ts",
46
+ "prettier": "prettier \"**/*.{css,html,ts,js,java}\" --plugin=prettier-plugin-java",
47
+ "swiftlint": "node-swiftlint",
48
+ "docgen": "docgen --api NetworkDiscoveryPlugin --output-readme README.md --output-json dist/docs.json",
49
+ "build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.mjs",
50
+ "clean": "rimraf ./dist",
51
+ "watch": "tsc --watch",
52
+ "prepublishOnly": "npm run build"
53
+ },
54
+ "devDependencies": {
55
+ "@capacitor/android": "^7.4.5",
56
+ "@capacitor/core": "^7.4.5",
57
+ "@capacitor/docgen": "^0.3.1",
58
+ "@capacitor/ios": "^7.4.5",
59
+ "@ionic/eslint-config": "^0.4.0",
60
+ "@ionic/prettier-config": "^4.0.0",
61
+ "@ionic/swiftlint-config": "^2.0.0",
62
+ "eslint": "^8.57.1",
63
+ "prettier": "^3.6.2",
64
+ "prettier-plugin-java": "^2.7.7",
65
+ "rimraf": "^6.1.0",
66
+ "rollup": "^4.53.2",
67
+ "swiftlint": "^2.0.0",
68
+ "typescript": "^5.9.3"
69
+ },
70
+ "peerDependencies": {
71
+ "@capacitor/core": ">=7.0.0"
72
+ },
73
+ "prettier": "@ionic/prettier-config",
74
+ "swiftlint": "@ionic/swiftlint-config",
75
+ "eslintConfig": {
76
+ "extends": "@ionic/eslint-config/recommended"
77
+ },
78
+ "capacitor": {
79
+ "ios": {
80
+ "src": "ios"
81
+ },
82
+ "android": {
83
+ "src": "android"
84
+ }
85
+ }
86
86
  }