@devioarts/capacitor-mdns 0.1.0 → 0.2.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/CHANGELOG.md +110 -0
- package/DevioartsCapacitorMdns.podspec +3 -3
- package/Package.swift +1 -1
- package/README.md +221 -37
- package/android/build.gradle +3 -9
- package/android/src/main/java/com/devioarts/capacitor/mdns/AndroidNsdBackend.kt +145 -0
- package/android/src/main/java/com/devioarts/capacitor/mdns/MdnsOptions.kt +32 -0
- package/android/src/main/java/com/devioarts/capacitor/mdns/MdnsValidation.kt +26 -0
- package/android/src/main/java/com/devioarts/capacitor/mdns/NsdBackend.kt +59 -0
- package/android/src/main/java/com/devioarts/capacitor/mdns/mDNS.kt +467 -243
- package/android/src/main/java/com/devioarts/capacitor/mdns/mDNSPlugin.kt +80 -57
- package/dist/docs.json +250 -14
- package/dist/esm/definitions.d.ts +64 -17
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/index.js +22 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/web.d.ts +6 -1
- package/dist/esm/web.js +23 -0
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +45 -2
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +45 -2
- package/dist/plugin.js.map +1 -1
- package/docs/electron.md +29 -3
- package/docs/platform-setup.md +6 -0
- package/docs/playground.md +33 -2
- package/docs/runtime-behavior.md +68 -2
- package/electron/dist/plugin-settings.js +10 -3
- package/electron/dist/plugin-settings.js.map +1 -1
- package/electron/dist/plugin.cjs.js +519 -89
- package/electron/dist/plugin.cjs.js.map +1 -1
- package/electron/mdns-bridge.cjs +25 -2
- package/electron/mdns.ts +514 -81
- package/electron/rollup.config.mjs +1 -1
- package/electron/src/index.ts +1 -0
- package/electron/src/plugin-settings.ts +10 -3
- package/electron/types-public/index.d.ts +25 -3
- package/ios/Sources/mDNSPlugin/mDNS.swift +407 -117
- package/ios/Sources/mDNSPlugin/mDNSPlugin.swift +77 -24
- package/ios/Tests/mDNSPluginTests/BridgeTests.swift +46 -0
- package/ios/Tests/mDNSPluginTests/MDNSTests.swift +490 -0
- package/package.json +11 -4
- package/ios/Tests/mDNSPluginTests/mDNSPluginTests.swift +0 -9
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { PluginListenerHandle } from '@capacitor/core';
|
|
1
2
|
/**
|
|
2
3
|
* Key–value map for TXT records of a Bonjour/mDNS service.
|
|
3
4
|
* Values are UTF-8 strings; binary payloads are not supported by this API.
|
|
@@ -24,8 +25,10 @@ export interface MdnsPluginPlatformResult {
|
|
|
24
25
|
*
|
|
25
26
|
* @remarks
|
|
26
27
|
* - `hosts` contains resolved IPv4/IPv6 numeric addresses (no DNS names).
|
|
27
|
-
* -
|
|
28
|
-
*
|
|
28
|
+
* - IPv4 addresses precede IPv6; order within each family follows discovery order.
|
|
29
|
+
* - Native IPv6 scope suffixes are preserved (`%<scope-id>` on iOS; the OS-provided scope on Android).
|
|
30
|
+
* Electron may return link-local IPv6 without a scope; callers must not assume every address is reachable.
|
|
31
|
+
* - Resolved TXT records are returned when present.
|
|
29
32
|
* - `domain` is typically `"local."`.
|
|
30
33
|
*
|
|
31
34
|
* @public
|
|
@@ -37,16 +40,18 @@ export interface MdnsService {
|
|
|
37
40
|
type: string;
|
|
38
41
|
/** Service domain; typically `"local."`. */
|
|
39
42
|
domain: string;
|
|
40
|
-
/**
|
|
43
|
+
/** Port the service advertises. */
|
|
41
44
|
port: number;
|
|
42
45
|
/**
|
|
43
|
-
* Resolved numeric IP addresses
|
|
46
|
+
* Resolved numeric IP addresses, IPv4 first, then IPv6 with any available scope suffix.
|
|
44
47
|
* @example
|
|
45
48
|
* `["192.168.1.42", "fe80::1234:abcd:..."]`
|
|
46
49
|
*/
|
|
47
50
|
hosts: string[];
|
|
51
|
+
/** Host name when supplied by the platform, e.g. `"my-device.local."`. */
|
|
52
|
+
hostname?: string;
|
|
48
53
|
/**
|
|
49
|
-
* TXT dictionary (key → value).
|
|
54
|
+
* TXT dictionary (key → value).
|
|
50
55
|
* @remarks Not all services publish TXT data.
|
|
51
56
|
*/
|
|
52
57
|
txt?: MdnsTxt;
|
|
@@ -55,9 +60,10 @@ export interface MdnsService {
|
|
|
55
60
|
* Options for starting a Bonjour/mDNS advertisement.
|
|
56
61
|
*
|
|
57
62
|
* @remarks
|
|
58
|
-
* -
|
|
63
|
+
* - Service types accept an optional trailing dot; results always include it.
|
|
59
64
|
* - Instance `name` should be short and human-readable; the OS may append `" (n)"` to ensure uniqueness.
|
|
60
|
-
*
|
|
65
|
+
* Electron rejects a name conflict instead of renaming the service.
|
|
66
|
+
* - Advertising TXT is supported on iOS, Android and Electron. Invalid input preserves the active advertisement.
|
|
61
67
|
* - Native implementations guard publish with a timeout and return `error: true` instead of
|
|
62
68
|
* leaving the Promise pending when the OS does not deliver a publish callback.
|
|
63
69
|
* - Only one advertisement is active at a time. Starting a new one stops the previous one first.
|
|
@@ -72,9 +78,9 @@ export interface MdnsBroadcastOptions {
|
|
|
72
78
|
*/
|
|
73
79
|
type?: string;
|
|
74
80
|
/**
|
|
75
|
-
* Service instance name.
|
|
81
|
+
* Service instance name (maximum 63 UTF-8 bytes). Defaults to `DevIOArtsMDNS`.
|
|
76
82
|
*/
|
|
77
|
-
name
|
|
83
|
+
name?: string;
|
|
78
84
|
/**
|
|
79
85
|
* TCP port to advertise.
|
|
80
86
|
* @remarks Must be a positive integer (1–65535).
|
|
@@ -82,7 +88,7 @@ export interface MdnsBroadcastOptions {
|
|
|
82
88
|
port: number;
|
|
83
89
|
/**
|
|
84
90
|
* Optional TXT key–value pairs (UTF-8 strings).
|
|
85
|
-
* @remarks
|
|
91
|
+
* @remarks Keys must be unique ignoring case, nonempty printable ASCII without `=`. Each `key=value` entry must fit in 255 UTF-8 bytes. The complete record is limited to 1300 bytes including length prefixes. Non-string values are rejected.
|
|
86
92
|
*/
|
|
87
93
|
txt?: MdnsTxt;
|
|
88
94
|
}
|
|
@@ -93,8 +99,9 @@ export interface MdnsBroadcastOptions {
|
|
|
93
99
|
* - The `name` filter matches the normalized name and also accepts prefix matches
|
|
94
100
|
* (to handle OS-added `" (n)"` suffixes).
|
|
95
101
|
* - When `useNW` is `true` on iOS, discovery uses `NWBrowser` for better P2P behavior.
|
|
96
|
-
* -
|
|
97
|
-
*
|
|
102
|
+
* - A valid new discovery replaces the previous request with an error on every platform.
|
|
103
|
+
* - Dots and hyphens are equivalent when matching names; returned names retain their advertised spelling.
|
|
104
|
+
* - Without a name filter, browsing continues for the entire timeout. With a filter it may finish once a matching IP address resolves.
|
|
98
105
|
*
|
|
99
106
|
* @public
|
|
100
107
|
*/
|
|
@@ -111,7 +118,7 @@ export interface MdnsDiscoverOptions {
|
|
|
111
118
|
*/
|
|
112
119
|
name?: string;
|
|
113
120
|
/**
|
|
114
|
-
* Discovery timeout in milliseconds.
|
|
121
|
+
* Discovery timeout in milliseconds. Finite numbers only; fractions are truncated and the delay is clamped to 0–2147483647.
|
|
115
122
|
* @defaultValue `3000`
|
|
116
123
|
*/
|
|
117
124
|
timeout?: number;
|
|
@@ -134,7 +141,7 @@ export interface MdnsBroadcastResult {
|
|
|
134
141
|
errorMessage: string | null;
|
|
135
142
|
/** Final (possibly uniquified) service instance name. Empty on failure. */
|
|
136
143
|
name: string;
|
|
137
|
-
/** Whether
|
|
144
|
+
/** Whether an advertiser is active, or may still be active after failed cleanup. */
|
|
138
145
|
publishing: boolean;
|
|
139
146
|
}
|
|
140
147
|
/**
|
|
@@ -148,7 +155,7 @@ export interface MdnsDiscoverResult {
|
|
|
148
155
|
errorMessage: string | null;
|
|
149
156
|
/** Convenience count equal to services.length. */
|
|
150
157
|
servicesFound: number;
|
|
151
|
-
/**
|
|
158
|
+
/** Resolved services with numeric addresses. Empty on error; partial results are discarded. */
|
|
152
159
|
services: MdnsService[];
|
|
153
160
|
}
|
|
154
161
|
/**
|
|
@@ -161,9 +168,36 @@ export interface MdnsStopResult {
|
|
|
161
168
|
error: boolean;
|
|
162
169
|
/** Error description or null on success. */
|
|
163
170
|
errorMessage: string | null;
|
|
164
|
-
/**
|
|
171
|
+
/** False after confirmed stop; true when stopping failed and the advertiser may still be active. */
|
|
165
172
|
publishing: boolean;
|
|
166
173
|
}
|
|
174
|
+
/** Options for continuous discovery on iOS, Android and Electron. */
|
|
175
|
+
export interface MdnsWatchOptions {
|
|
176
|
+
/** Nonempty list of service types. Trailing dots are optional; duplicates are merged. */
|
|
177
|
+
types: string[];
|
|
178
|
+
}
|
|
179
|
+
/** Native browsers have been requested; later failures are reported through `watchError`. */
|
|
180
|
+
export interface MdnsWatchResult {
|
|
181
|
+
error: boolean;
|
|
182
|
+
errorMessage: string | null;
|
|
183
|
+
watchersStarted: number;
|
|
184
|
+
}
|
|
185
|
+
/** Stops watching independently of any active broadcast. */
|
|
186
|
+
export interface MdnsWatchStopResult {
|
|
187
|
+
error: boolean;
|
|
188
|
+
errorMessage: string | null;
|
|
189
|
+
watching: boolean;
|
|
190
|
+
}
|
|
191
|
+
/** Both found and lost events contain a complete service snapshot, including `hosts`. */
|
|
192
|
+
export interface MdnsServiceEvent {
|
|
193
|
+
service: MdnsService;
|
|
194
|
+
}
|
|
195
|
+
/** Browser failures stop the watch; exhausted service resolution retries leave it running. */
|
|
196
|
+
export interface MdnsWatchErrorEvent {
|
|
197
|
+
type: string;
|
|
198
|
+
errorMessage: string;
|
|
199
|
+
watching: boolean;
|
|
200
|
+
}
|
|
167
201
|
/**
|
|
168
202
|
* Public API surface of the Capacitor mDNS plugin.
|
|
169
203
|
*
|
|
@@ -210,7 +244,20 @@ export interface mDNSPlugin {
|
|
|
210
244
|
*
|
|
211
245
|
* @param options - {@link MdnsDiscoverOptions}
|
|
212
246
|
* @returns Promise resolving to `MdnsDiscoverResult`.
|
|
213
|
-
* @remarks The result list is normalized across platforms.
|
|
247
|
+
* @remarks The result list is normalized across platforms.
|
|
214
248
|
*/
|
|
215
249
|
discover(options?: MdnsDiscoverOptions): Promise<MdnsDiscoverResult>;
|
|
250
|
+
/**
|
|
251
|
+
* Continuously watch several service types. A valid call replaces the previous watch.
|
|
252
|
+
* Register listeners before starting. Each resolved service emits `serviceFound` once;
|
|
253
|
+
* disappearance emits `serviceLost` with its last snapshot. No loss is emitted for an
|
|
254
|
+
* unresolved service. Watching and one-shot discovery can run together.
|
|
255
|
+
* Thanks to Idrimi for contributing the original continuous discovery feature (PR #7).
|
|
256
|
+
*/
|
|
257
|
+
watchServices(options: MdnsWatchOptions): Promise<MdnsWatchResult>;
|
|
258
|
+
/** Stop all watchers. No events from that watch are emitted after this resolves. */
|
|
259
|
+
stopWatching(): Promise<MdnsWatchStopResult>;
|
|
260
|
+
addListener(eventName: 'serviceFound' | 'serviceLost', handler: (event: MdnsServiceEvent) => void): Promise<PluginListenerHandle>;
|
|
261
|
+
addListener(eventName: 'watchError', handler: (event: MdnsWatchErrorEvent) => void): Promise<PluginListenerHandle>;
|
|
262
|
+
removeAllListeners(): Promise<void>;
|
|
216
263
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"AAAA,qBAAqB","sourcesContent":["// src/definitions.ts\n\n/**\n * Key–value map for TXT records of a Bonjour/mDNS service.\n * Values are UTF-8 strings; binary payloads are not supported by this API.\n * @public\n */\nexport type MdnsTxt = Record<string, string>;\n\n/**\n * Runtime implementation that handled a plugin call.\n * @public\n */\nexport type MdnsPluginPlatform = 'ios' | 'android' | 'electron' | 'web';\n\n/**\n * Result of getPluginPlatform(). Useful for validating that calls are routed\n * through the expected platform bridge.\n * @public\n */\nexport interface MdnsPluginPlatformResult {\n /** Platform implementation that produced this result. */\n platform: MdnsPluginPlatform;\n}\n\n/**\n * Normalized description of a discovered Bonjour/mDNS service.\n * Returned from {@link mDNSPlugin.discover}.\n *\n * @remarks\n * - `hosts` contains resolved IPv4/IPv6 numeric addresses (no DNS names).\n * - iOS returns `txt` when present. Android (NSD) does not expose TXT records via public APIs,\n * so `txt` is usually omitted on Android.\n * - `domain` is typically `\"local.\"`.\n *\n * @public\n */\nexport interface MdnsService {\n /** Instance name of the service (may be uniqued by the OS, e.g. \"My App (2)\"). */\n name: string;\n\n /** Full service type including the trailing dot, e.g. `\"_http._tcp.\"`. */\n type: string;\n\n /** Service domain; typically `\"local.\"`. */\n domain: string;\n\n /** TCP port the service advertises. */\n port: number;\n\n /**\n * Resolved numeric IP addresses (IPv4/IPv6).\n * @example\n * `[\"192.168.1.42\", \"fe80::1234:abcd:...\"]`\n */\n hosts: string[];\n\n /**\n * TXT dictionary (key → value). Usually present on iOS; Android NSD does not populate this.\n * @remarks Not all services publish TXT data.\n */\n txt?: MdnsTxt;\n}\n\n/**\n * Options for starting a Bonjour/mDNS advertisement.\n *\n * @remarks\n * - The `type` **must** end with a dot (`.`). If omitted, the implementation appends it.\n * - Instance `name` should be short and human-readable; the OS may append `\" (n)\"` to ensure uniqueness.\n * - Android NSD does not expose TXT records to other apps; advertising TXT is supported on iOS.\n * - Native implementations guard publish with a timeout and return `error: true` instead of\n * leaving the Promise pending when the OS does not deliver a publish callback.\n * - Only one advertisement is active at a time. Starting a new one stops the previous one first.\n *\n * @public\n */\nexport interface MdnsBroadcastOptions {\n /**\n * Service type (including the trailing dot).\n * @defaultValue `\"_http._tcp.\"`\n * @example `\"_myapp._tcp.\"`\n */\n type?: string;\n\n /**\n * Service instance name.\n */\n name: string;\n\n /**\n * TCP port to advertise.\n * @remarks Must be a positive integer (1–65535).\n */\n port: number;\n\n /**\n * Optional TXT key–value pairs (UTF-8 strings).\n * @remarks May be ignored on Android due to platform limitations.\n */\n txt?: MdnsTxt;\n}\n\n/**\n * Options for Bonjour/mDNS discovery.\n *\n * @remarks\n * - The `name` filter matches the normalized name and also accepts prefix matches\n * (to handle OS-added `\" (n)\"` suffixes).\n * - When `useNW` is `true` on iOS, discovery uses `NWBrowser` for better P2P behavior.\n * - Discovery is timeboxed. Concurrent discovery requests are serialized or safely replace\n * the previous native session so old callbacks cannot complete a newer request.\n *\n * @public\n */\nexport interface MdnsDiscoverOptions {\n /**\n * Service type (including the trailing dot).\n * @defaultValue `\"_http._tcp.\"`\n * @example `\"_comm._tcp.\"`\n */\n type?: string;\n\n /**\n * Optional instance name filter (prefix-safe).\n * @example `\"MyAppName\"`\n */\n name?: string;\n\n /**\n * Discovery timeout in milliseconds.\n * @defaultValue `3000`\n */\n timeout?: number;\n\n /**\n * iOS-only hint to use `NWBrowser` instead of `NetServiceBrowser`.\n * @defaultValue `true`\n */\n useNW?: boolean;\n}\n\n/**\n * Result of startBroadcast(). Indicates whether advertising is active\n * and the final service name. On failure, `error` is true and `errorMessage`\n * describes the issue.\n * @public\n */\nexport interface MdnsBroadcastResult {\n /** True if the operation failed. */\n error: boolean;\n /** Error description or null on success. */\n errorMessage: string | null;\n /** Final (possibly uniquified) service instance name. Empty on failure. */\n name: string;\n /** Whether the advertiser is currently active. */\n publishing: boolean;\n}\n\n/**\n * Result of discover(). Contains normalized services and error information.\n * @public\n */\nexport interface MdnsDiscoverResult {\n /** True if discovery encountered an error (partial results may still be present). */\n error: boolean;\n /** Error description or null when no error occurred. */\n errorMessage: string | null;\n /** Convenience count equal to services.length. */\n servicesFound: number;\n /** Normalized list of discovered services. */\n services: MdnsService[];\n}\n\n/**\n * Result of stopBroadcast(). Indicates whether the advertiser is active\n * after the call (normally false) and includes error information.\n * @public\n */\nexport interface MdnsStopResult {\n /** True if an error occurred while stopping. */\n error: boolean;\n /** Error description or null on success. */\n errorMessage: string | null;\n /** Whether the advertiser remains active (should be false on success). */\n publishing: boolean;\n}\n\n/**\n * Public API surface of the Capacitor mDNS plugin.\n *\n * @example\n * ```ts\n * import { mDNS } from 'capacitor-mdns';\n *\n * // Start advertising\n * await mDNS.startBroadcast({ type: '_http._tcp.', name: 'my.app.id', port: 9235 });\n *\n * // Discover services\n * const { services } = await mDNS.discover({ type: '_http._tcp.', timeout: 3000 });\n *\n * // Stop advertising\n * await mDNS.stopBroadcast();\n * ```\n *\n * @public\n */\nexport interface mDNSPlugin {\n /**\n * Return the platform implementation currently serving plugin calls.\n *\n * @returns Promise resolving to `MdnsPluginPlatformResult`.\n */\n getPluginPlatform(): Promise<MdnsPluginPlatformResult>;\n\n /**\n * Start advertising a Bonjour/mDNS service.\n *\n * @param options - {@link MdnsBroadcastOptions}\n * @returns Promise resolving to `MdnsBroadcastResult` (`true` on success).\n */\n startBroadcast(options: MdnsBroadcastOptions): Promise<MdnsBroadcastResult>;\n\n /**\n * Stop advertising the currently registered service (no-op if none).\n *\n * @returns Promise resolving to `MdnsStopResult`.\n * @remarks The `publishing` flag may be `false` after a successful stop.\n * Stopping is idempotent and is safe to call even if publishing never fully started.\n */\n stopBroadcast(): Promise<MdnsStopResult>;\n\n /**\n * Discover services of a given type and optionally filter by instance name.\n *\n * @param options - {@link MdnsDiscoverOptions}\n * @returns Promise resolving to `MdnsDiscoverResult`.\n * @remarks The result list is normalized across platforms. On Android, `txt` is typically absent.\n */\n discover(options?: MdnsDiscoverOptions): Promise<MdnsDiscoverResult>;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"AAAA,qBAAqB","sourcesContent":["// src/definitions.ts\n\nimport type { PluginListenerHandle } from '@capacitor/core';\n\n/**\n * Key–value map for TXT records of a Bonjour/mDNS service.\n * Values are UTF-8 strings; binary payloads are not supported by this API.\n * @public\n */\nexport type MdnsTxt = Record<string, string>;\n\n/**\n * Runtime implementation that handled a plugin call.\n * @public\n */\nexport type MdnsPluginPlatform = 'ios' | 'android' | 'electron' | 'web';\n\n/**\n * Result of getPluginPlatform(). Useful for validating that calls are routed\n * through the expected platform bridge.\n * @public\n */\nexport interface MdnsPluginPlatformResult {\n /** Platform implementation that produced this result. */\n platform: MdnsPluginPlatform;\n}\n\n/**\n * Normalized description of a discovered Bonjour/mDNS service.\n * Returned from {@link mDNSPlugin.discover}.\n *\n * @remarks\n * - `hosts` contains resolved IPv4/IPv6 numeric addresses (no DNS names).\n * - IPv4 addresses precede IPv6; order within each family follows discovery order.\n * - Native IPv6 scope suffixes are preserved (`%<scope-id>` on iOS; the OS-provided scope on Android).\n * Electron may return link-local IPv6 without a scope; callers must not assume every address is reachable.\n * - Resolved TXT records are returned when present.\n * - `domain` is typically `\"local.\"`.\n *\n * @public\n */\nexport interface MdnsService {\n /** Instance name of the service (may be uniqued by the OS, e.g. \"My App (2)\"). */\n name: string;\n\n /** Full service type including the trailing dot, e.g. `\"_http._tcp.\"`. */\n type: string;\n\n /** Service domain; typically `\"local.\"`. */\n domain: string;\n\n /** Port the service advertises. */\n port: number;\n\n /**\n * Resolved numeric IP addresses, IPv4 first, then IPv6 with any available scope suffix.\n * @example\n * `[\"192.168.1.42\", \"fe80::1234:abcd:...\"]`\n */\n hosts: string[];\n\n /** Host name when supplied by the platform, e.g. `\"my-device.local.\"`. */\n hostname?: string;\n\n /**\n * TXT dictionary (key → value).\n * @remarks Not all services publish TXT data.\n */\n txt?: MdnsTxt;\n}\n\n/**\n * Options for starting a Bonjour/mDNS advertisement.\n *\n * @remarks\n * - Service types accept an optional trailing dot; results always include it.\n * - Instance `name` should be short and human-readable; the OS may append `\" (n)\"` to ensure uniqueness.\n * Electron rejects a name conflict instead of renaming the service.\n * - Advertising TXT is supported on iOS, Android and Electron. Invalid input preserves the active advertisement.\n * - Native implementations guard publish with a timeout and return `error: true` instead of\n * leaving the Promise pending when the OS does not deliver a publish callback.\n * - Only one advertisement is active at a time. Starting a new one stops the previous one first.\n *\n * @public\n */\nexport interface MdnsBroadcastOptions {\n /**\n * Service type (including the trailing dot).\n * @defaultValue `\"_http._tcp.\"`\n * @example `\"_myapp._tcp.\"`\n */\n type?: string;\n\n /**\n * Service instance name (maximum 63 UTF-8 bytes). Defaults to `DevIOArtsMDNS`.\n */\n name?: string;\n\n /**\n * TCP port to advertise.\n * @remarks Must be a positive integer (1–65535).\n */\n port: number;\n\n /**\n * Optional TXT key–value pairs (UTF-8 strings).\n * @remarks Keys must be unique ignoring case, nonempty printable ASCII without `=`. Each `key=value` entry must fit in 255 UTF-8 bytes. The complete record is limited to 1300 bytes including length prefixes. Non-string values are rejected.\n */\n txt?: MdnsTxt;\n}\n\n/**\n * Options for Bonjour/mDNS discovery.\n *\n * @remarks\n * - The `name` filter matches the normalized name and also accepts prefix matches\n * (to handle OS-added `\" (n)\"` suffixes).\n * - When `useNW` is `true` on iOS, discovery uses `NWBrowser` for better P2P behavior.\n * - A valid new discovery replaces the previous request with an error on every platform.\n * - Dots and hyphens are equivalent when matching names; returned names retain their advertised spelling.\n * - Without a name filter, browsing continues for the entire timeout. With a filter it may finish once a matching IP address resolves.\n *\n * @public\n */\nexport interface MdnsDiscoverOptions {\n /**\n * Service type (including the trailing dot).\n * @defaultValue `\"_http._tcp.\"`\n * @example `\"_comm._tcp.\"`\n */\n type?: string;\n\n /**\n * Optional instance name filter (prefix-safe).\n * @example `\"MyAppName\"`\n */\n name?: string;\n\n /**\n * Discovery timeout in milliseconds. Finite numbers only; fractions are truncated and the delay is clamped to 0–2147483647.\n * @defaultValue `3000`\n */\n timeout?: number;\n\n /**\n * iOS-only hint to use `NWBrowser` instead of `NetServiceBrowser`.\n * @defaultValue `true`\n */\n useNW?: boolean;\n}\n\n/**\n * Result of startBroadcast(). Indicates whether advertising is active\n * and the final service name. On failure, `error` is true and `errorMessage`\n * describes the issue.\n * @public\n */\nexport interface MdnsBroadcastResult {\n /** True if the operation failed. */\n error: boolean;\n /** Error description or null on success. */\n errorMessage: string | null;\n /** Final (possibly uniquified) service instance name. Empty on failure. */\n name: string;\n /** Whether an advertiser is active, or may still be active after failed cleanup. */\n publishing: boolean;\n}\n\n/**\n * Result of discover(). Contains normalized services and error information.\n * @public\n */\nexport interface MdnsDiscoverResult {\n /** True if discovery encountered an error (partial results may still be present). */\n error: boolean;\n /** Error description or null when no error occurred. */\n errorMessage: string | null;\n /** Convenience count equal to services.length. */\n servicesFound: number;\n /** Resolved services with numeric addresses. Empty on error; partial results are discarded. */\n services: MdnsService[];\n}\n\n/**\n * Result of stopBroadcast(). Indicates whether the advertiser is active\n * after the call (normally false) and includes error information.\n * @public\n */\nexport interface MdnsStopResult {\n /** True if an error occurred while stopping. */\n error: boolean;\n /** Error description or null on success. */\n errorMessage: string | null;\n /** False after confirmed stop; true when stopping failed and the advertiser may still be active. */\n publishing: boolean;\n}\n\n/** Options for continuous discovery on iOS, Android and Electron. */\nexport interface MdnsWatchOptions {\n /** Nonempty list of service types. Trailing dots are optional; duplicates are merged. */\n types: string[];\n}\n\n/** Native browsers have been requested; later failures are reported through `watchError`. */\nexport interface MdnsWatchResult {\n error: boolean;\n errorMessage: string | null;\n watchersStarted: number;\n}\n\n/** Stops watching independently of any active broadcast. */\nexport interface MdnsWatchStopResult {\n error: boolean;\n errorMessage: string | null;\n watching: boolean;\n}\n\n/** Both found and lost events contain a complete service snapshot, including `hosts`. */\nexport interface MdnsServiceEvent {\n service: MdnsService;\n}\n\n/** Browser failures stop the watch; exhausted service resolution retries leave it running. */\nexport interface MdnsWatchErrorEvent {\n type: string;\n errorMessage: string;\n watching: boolean;\n}\n\n/**\n * Public API surface of the Capacitor mDNS plugin.\n *\n * @example\n * ```ts\n * import { mDNS } from 'capacitor-mdns';\n *\n * // Start advertising\n * await mDNS.startBroadcast({ type: '_http._tcp.', name: 'my.app.id', port: 9235 });\n *\n * // Discover services\n * const { services } = await mDNS.discover({ type: '_http._tcp.', timeout: 3000 });\n *\n * // Stop advertising\n * await mDNS.stopBroadcast();\n * ```\n *\n * @public\n */\nexport interface mDNSPlugin {\n /**\n * Return the platform implementation currently serving plugin calls.\n *\n * @returns Promise resolving to `MdnsPluginPlatformResult`.\n */\n getPluginPlatform(): Promise<MdnsPluginPlatformResult>;\n\n /**\n * Start advertising a Bonjour/mDNS service.\n *\n * @param options - {@link MdnsBroadcastOptions}\n * @returns Promise resolving to `MdnsBroadcastResult` (`true` on success).\n */\n startBroadcast(options: MdnsBroadcastOptions): Promise<MdnsBroadcastResult>;\n\n /**\n * Stop advertising the currently registered service (no-op if none).\n *\n * @returns Promise resolving to `MdnsStopResult`.\n * @remarks The `publishing` flag may be `false` after a successful stop.\n * Stopping is idempotent and is safe to call even if publishing never fully started.\n */\n stopBroadcast(): Promise<MdnsStopResult>;\n\n /**\n * Discover services of a given type and optionally filter by instance name.\n *\n * @param options - {@link MdnsDiscoverOptions}\n * @returns Promise resolving to `MdnsDiscoverResult`.\n * @remarks The result list is normalized across platforms.\n */\n discover(options?: MdnsDiscoverOptions): Promise<MdnsDiscoverResult>;\n\n /**\n * Continuously watch several service types. A valid call replaces the previous watch.\n * Register listeners before starting. Each resolved service emits `serviceFound` once;\n * disappearance emits `serviceLost` with its last snapshot. No loss is emitted for an\n * unresolved service. Watching and one-shot discovery can run together.\n * Thanks to Idrimi for contributing the original continuous discovery feature (PR #7).\n */\n watchServices(options: MdnsWatchOptions): Promise<MdnsWatchResult>;\n\n /** Stop all watchers. No events from that watch are emitted after this resolves. */\n stopWatching(): Promise<MdnsWatchStopResult>;\n\n addListener(\n eventName: 'serviceFound' | 'serviceLost',\n handler: (event: MdnsServiceEvent) => void,\n ): Promise<PluginListenerHandle>;\n addListener(eventName: 'watchError', handler: (event: MdnsWatchErrorEvent) => void): Promise<PluginListenerHandle>;\n removeAllListeners(): Promise<void>;\n}\n"]}
|
package/dist/esm/index.js
CHANGED
|
@@ -1,7 +1,27 @@
|
|
|
1
1
|
import { registerPlugin } from '@capacitor/core';
|
|
2
|
-
const
|
|
2
|
+
const platformPlugin = registerPlugin('mDNS', {
|
|
3
3
|
web: () => import('./web').then((m) => new m.mDNSWeb()),
|
|
4
|
-
electron: () =>
|
|
4
|
+
electron: () => {
|
|
5
|
+
var _a, _b;
|
|
6
|
+
const plugin = (_b = (_a = window.CapacitorCustomPlatform) === null || _a === void 0 ? void 0 : _a.plugins) === null || _b === void 0 ? void 0 : _b.mDNS;
|
|
7
|
+
if (!plugin)
|
|
8
|
+
throw new Error('mDNS Electron plugin is not registered; run npx cap-electron sync in the app');
|
|
9
|
+
return Promise.resolve(plugin);
|
|
10
|
+
},
|
|
11
|
+
});
|
|
12
|
+
const mDNS = new Proxy(platformPlugin, {
|
|
13
|
+
get(target, property, receiver) {
|
|
14
|
+
if (property !== 'discover')
|
|
15
|
+
return Reflect.get(target, property, receiver);
|
|
16
|
+
return (options) => {
|
|
17
|
+
const timeout = options === null || options === void 0 ? void 0 : options.timeout;
|
|
18
|
+
// Native JSON bridges turn NaN/Infinity into null, losing the invalid input.
|
|
19
|
+
if (timeout != null && (typeof timeout !== 'number' || !Number.isFinite(timeout))) {
|
|
20
|
+
return Promise.resolve({ error: true, errorMessage: 'Invalid timeout', servicesFound: 0, services: [] });
|
|
21
|
+
}
|
|
22
|
+
return target.discover(options);
|
|
23
|
+
};
|
|
24
|
+
},
|
|
5
25
|
});
|
|
6
26
|
export * from './definitions';
|
|
7
27
|
export { mDNS };
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAIjD,MAAM,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAIjD,MAAM,cAAc,GAAG,cAAc,CAAa,MAAM,EAAE;IACxD,GAAG,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;IACvD,QAAQ,EAAE,GAAG,EAAE;;QACb,MAAM,MAAM,GAAG,MAAA,MAAC,MAAc,CAAC,uBAAuB,0CAAE,OAAO,0CAAE,IAA8B,CAAC;QAChG,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,8EAA8E,CAAC,CAAC;QAC7G,OAAO,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACjC,CAAC;CACF,CAAC,CAAC;AAEH,MAAM,IAAI,GAAG,IAAI,KAAK,CAAC,cAAc,EAAE;IACrC,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ;QAC5B,IAAI,QAAQ,KAAK,UAAU;YAAE,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAC5E,OAAO,CAAC,OAA6B,EAAE,EAAE;YACvC,MAAM,OAAO,GAAG,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,OAAO,CAAC;YACjC,6EAA6E;YAC7E,IAAI,OAAO,IAAI,IAAI,IAAI,CAAC,OAAO,OAAO,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;gBAClF,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC;YAC3G,CAAC;YACD,OAAO,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAClC,CAAC,CAAC;IACJ,CAAC;CACF,CAAC,CAAC;AAEH,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,IAAI,EAAE,CAAC","sourcesContent":["import { registerPlugin } from '@capacitor/core';\n\nimport type { MdnsDiscoverOptions, mDNSPlugin } from './definitions';\n\nconst platformPlugin = registerPlugin<mDNSPlugin>('mDNS', {\n web: () => import('./web').then((m) => new m.mDNSWeb()),\n electron: () => {\n const plugin = (window as any).CapacitorCustomPlatform?.plugins?.mDNS as mDNSPlugin | undefined;\n if (!plugin) throw new Error('mDNS Electron plugin is not registered; run npx cap-electron sync in the app');\n return Promise.resolve(plugin);\n },\n});\n\nconst mDNS = new Proxy(platformPlugin, {\n get(target, property, receiver) {\n if (property !== 'discover') return Reflect.get(target, property, receiver);\n return (options?: MdnsDiscoverOptions) => {\n const timeout = options?.timeout;\n // Native JSON bridges turn NaN/Infinity into null, losing the invalid input.\n if (timeout != null && (typeof timeout !== 'number' || !Number.isFinite(timeout))) {\n return Promise.resolve({ error: true, errorMessage: 'Invalid timeout', servicesFound: 0, services: [] });\n }\n return target.discover(options);\n };\n },\n});\n\nexport * from './definitions';\nexport { mDNS };\n"]}
|
package/dist/esm/web.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { WebPlugin } from '@capacitor/core';
|
|
2
|
-
import type {
|
|
2
|
+
import type { PluginListenerHandle } from '@capacitor/core';
|
|
3
|
+
import type { mDNSPlugin, MdnsBroadcastOptions, MdnsDiscoverOptions, MdnsBroadcastResult, MdnsStopResult, MdnsDiscoverResult, MdnsPluginPlatformResult, MdnsWatchOptions, MdnsWatchResult, MdnsWatchStopResult } from './definitions';
|
|
3
4
|
/**
|
|
4
5
|
* Web implementation of the mDNS plugin.
|
|
5
6
|
*
|
|
@@ -16,4 +17,8 @@ export declare class mDNSWeb extends WebPlugin implements mDNSPlugin {
|
|
|
16
17
|
startBroadcast(options: MdnsBroadcastOptions): Promise<MdnsBroadcastResult>;
|
|
17
18
|
stopBroadcast(): Promise<MdnsStopResult>;
|
|
18
19
|
discover(options?: MdnsDiscoverOptions): Promise<MdnsDiscoverResult>;
|
|
20
|
+
watchServices(options: MdnsWatchOptions): Promise<MdnsWatchResult>;
|
|
21
|
+
stopWatching(): Promise<MdnsWatchStopResult>;
|
|
22
|
+
addListener(eventName: string, handler: (data: any) => void): Promise<PluginListenerHandle>;
|
|
23
|
+
removeAllListeners(): Promise<void>;
|
|
19
24
|
}
|
package/dist/esm/web.js
CHANGED
|
@@ -46,5 +46,28 @@ export class mDNSWeb extends WebPlugin {
|
|
|
46
46
|
console.log('[WEB_NOT_SUPPORTED] discover', options);
|
|
47
47
|
return { services: [], error: true, errorMessage: this.unsupportedMessage, servicesFound: 0 };
|
|
48
48
|
}
|
|
49
|
+
async watchServices(options) {
|
|
50
|
+
var _a;
|
|
51
|
+
if ((_a = this.electronApi) === null || _a === void 0 ? void 0 : _a.watchServices)
|
|
52
|
+
return this.electronApi.watchServices(options);
|
|
53
|
+
return { error: true, errorMessage: this.unsupportedMessage, watchersStarted: 0 };
|
|
54
|
+
}
|
|
55
|
+
async stopWatching() {
|
|
56
|
+
var _a;
|
|
57
|
+
if ((_a = this.electronApi) === null || _a === void 0 ? void 0 : _a.stopWatching)
|
|
58
|
+
return this.electronApi.stopWatching();
|
|
59
|
+
return { watching: false, error: false, errorMessage: null };
|
|
60
|
+
}
|
|
61
|
+
async addListener(eventName, handler) {
|
|
62
|
+
var _a;
|
|
63
|
+
if ((_a = this.electronApi) === null || _a === void 0 ? void 0 : _a.addListener)
|
|
64
|
+
return this.electronApi.addListener(eventName, handler);
|
|
65
|
+
return super.addListener(eventName, handler);
|
|
66
|
+
}
|
|
67
|
+
async removeAllListeners() {
|
|
68
|
+
var _a, _b;
|
|
69
|
+
await ((_b = (_a = this.electronApi) === null || _a === void 0 ? void 0 : _a.removeAllListeners) === null || _b === void 0 ? void 0 : _b.call(_a));
|
|
70
|
+
await super.removeAllListeners();
|
|
71
|
+
}
|
|
49
72
|
}
|
|
50
73
|
//# sourceMappingURL=web.js.map
|
package/dist/esm/web.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,aAAa;AACb,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"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","sourcesContent":["// src/web.ts\nimport { WebPlugin } from '@capacitor/core';\nimport type { PluginListenerHandle } from '@capacitor/core';\n\nimport type {\n mDNSPlugin,\n MdnsBroadcastOptions,\n MdnsDiscoverOptions,\n MdnsBroadcastResult,\n MdnsStopResult,\n MdnsDiscoverResult,\n MdnsPluginPlatformResult,\n MdnsWatchOptions,\n MdnsWatchResult,\n MdnsWatchStopResult,\n} from './definitions';\n\n/**\n * Web implementation of the mDNS plugin.\n *\n * This class behaves as a thin proxy:\n * - In Electron (when a preload exposes window.mDNS/window.mdns), calls are forwarded over IPC.\n * - In a regular browser, mDNS is not available; methods resolve with well-shaped stub values\n * and log a console message with the [WEB_NOT_SUPPORTED] tag.\n */\nexport class mDNSWeb extends WebPlugin implements mDNSPlugin {\n private readonly unsupportedMessage = 'mDNS is not supported in this browser runtime';\n\n /** Electron preload bridge (if present). */\n private get electronApi():\n | undefined\n | {\n startBroadcast(o: MdnsBroadcastOptions): Promise<MdnsBroadcastResult>;\n stopBroadcast(): Promise<MdnsStopResult>;\n discover(o?: MdnsDiscoverOptions): Promise<MdnsDiscoverResult>;\n getPluginPlatform?(): Promise<MdnsPluginPlatformResult>;\n watchServices?(options: MdnsWatchOptions): Promise<MdnsWatchResult>;\n stopWatching?(): Promise<MdnsWatchStopResult>;\n addListener?(eventName: string, handler: (data: any) => void): Promise<PluginListenerHandle>;\n removeAllListeners?(): Promise<void>;\n } {\n if (typeof window === 'undefined') return undefined;\n return (window as any).mDNS || (window as any).mdns;\n }\n\n async getPluginPlatform(): Promise<MdnsPluginPlatformResult> {\n const api = this.electronApi;\n if (api?.getPluginPlatform) return api.getPluginPlatform();\n return { platform: 'web' };\n }\n\n async startBroadcast(options: MdnsBroadcastOptions): Promise<MdnsBroadcastResult> {\n const api = this.electronApi;\n if (api?.startBroadcast) return api.startBroadcast(options);\n console.log('[WEB_NOT_SUPPORTED] startBroadcast', options);\n return { publishing: false, name: '', error: true, errorMessage: this.unsupportedMessage };\n }\n\n async stopBroadcast(): Promise<MdnsStopResult> {\n const api = this.electronApi;\n if (api?.stopBroadcast) return api.stopBroadcast();\n console.log('[WEB_NOT_SUPPORTED] stopBroadcast');\n return { publishing: false, error: false, errorMessage: null };\n }\n\n async discover(options: MdnsDiscoverOptions = {}): Promise<MdnsDiscoverResult> {\n const api = this.electronApi;\n if (api?.discover) return api.discover(options);\n console.log('[WEB_NOT_SUPPORTED] discover', options);\n return { services: [], error: true, errorMessage: this.unsupportedMessage, servicesFound: 0 };\n }\n\n async watchServices(options: MdnsWatchOptions): Promise<MdnsWatchResult> {\n if (this.electronApi?.watchServices) return this.electronApi.watchServices(options);\n return { error: true, errorMessage: this.unsupportedMessage, watchersStarted: 0 };\n }\n\n async stopWatching(): Promise<MdnsWatchStopResult> {\n if (this.electronApi?.stopWatching) return this.electronApi.stopWatching();\n return { watching: false, error: false, errorMessage: null };\n }\n\n async addListener(eventName: string, handler: (data: any) => void): Promise<PluginListenerHandle> {\n if (this.electronApi?.addListener) return this.electronApi.addListener(eventName, handler);\n return super.addListener(eventName, handler);\n }\n\n async removeAllListeners(): Promise<void> {\n await this.electronApi?.removeAllListeners?.();\n await super.removeAllListeners();\n }\n}\n"]}
|
package/dist/plugin.cjs.js
CHANGED
|
@@ -2,9 +2,29 @@
|
|
|
2
2
|
|
|
3
3
|
var core = require('@capacitor/core');
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const platformPlugin = core.registerPlugin('mDNS', {
|
|
6
6
|
web: () => Promise.resolve().then(function () { return web; }).then((m) => new m.mDNSWeb()),
|
|
7
|
-
electron: () =>
|
|
7
|
+
electron: () => {
|
|
8
|
+
var _a, _b;
|
|
9
|
+
const plugin = (_b = (_a = window.CapacitorCustomPlatform) === null || _a === void 0 ? void 0 : _a.plugins) === null || _b === void 0 ? void 0 : _b.mDNS;
|
|
10
|
+
if (!plugin)
|
|
11
|
+
throw new Error('mDNS Electron plugin is not registered; run npx cap-electron sync in the app');
|
|
12
|
+
return Promise.resolve(plugin);
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
const mDNS = new Proxy(platformPlugin, {
|
|
16
|
+
get(target, property, receiver) {
|
|
17
|
+
if (property !== 'discover')
|
|
18
|
+
return Reflect.get(target, property, receiver);
|
|
19
|
+
return (options) => {
|
|
20
|
+
const timeout = options === null || options === void 0 ? void 0 : options.timeout;
|
|
21
|
+
// Native JSON bridges turn NaN/Infinity into null, losing the invalid input.
|
|
22
|
+
if (timeout != null && (typeof timeout !== 'number' || !Number.isFinite(timeout))) {
|
|
23
|
+
return Promise.resolve({ error: true, errorMessage: 'Invalid timeout', servicesFound: 0, services: [] });
|
|
24
|
+
}
|
|
25
|
+
return target.discover(options);
|
|
26
|
+
};
|
|
27
|
+
},
|
|
8
28
|
});
|
|
9
29
|
|
|
10
30
|
// src/web.ts
|
|
@@ -54,6 +74,29 @@ class mDNSWeb extends core.WebPlugin {
|
|
|
54
74
|
console.log('[WEB_NOT_SUPPORTED] discover', options);
|
|
55
75
|
return { services: [], error: true, errorMessage: this.unsupportedMessage, servicesFound: 0 };
|
|
56
76
|
}
|
|
77
|
+
async watchServices(options) {
|
|
78
|
+
var _a;
|
|
79
|
+
if ((_a = this.electronApi) === null || _a === void 0 ? void 0 : _a.watchServices)
|
|
80
|
+
return this.electronApi.watchServices(options);
|
|
81
|
+
return { error: true, errorMessage: this.unsupportedMessage, watchersStarted: 0 };
|
|
82
|
+
}
|
|
83
|
+
async stopWatching() {
|
|
84
|
+
var _a;
|
|
85
|
+
if ((_a = this.electronApi) === null || _a === void 0 ? void 0 : _a.stopWatching)
|
|
86
|
+
return this.electronApi.stopWatching();
|
|
87
|
+
return { watching: false, error: false, errorMessage: null };
|
|
88
|
+
}
|
|
89
|
+
async addListener(eventName, handler) {
|
|
90
|
+
var _a;
|
|
91
|
+
if ((_a = this.electronApi) === null || _a === void 0 ? void 0 : _a.addListener)
|
|
92
|
+
return this.electronApi.addListener(eventName, handler);
|
|
93
|
+
return super.addListener(eventName, handler);
|
|
94
|
+
}
|
|
95
|
+
async removeAllListeners() {
|
|
96
|
+
var _a, _b;
|
|
97
|
+
await ((_b = (_a = this.electronApi) === null || _a === void 0 ? void 0 : _a.removeAllListeners) === null || _b === void 0 ? void 0 : _b.call(_a));
|
|
98
|
+
await super.removeAllListeners();
|
|
99
|
+
}
|
|
57
100
|
}
|
|
58
101
|
|
|
59
102
|
var web = /*#__PURE__*/Object.freeze({
|
package/dist/plugin.cjs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst
|
|
1
|
+
{"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst platformPlugin = registerPlugin('mDNS', {\n web: () => import('./web').then((m) => new m.mDNSWeb()),\n electron: () => {\n var _a, _b;\n const plugin = (_b = (_a = window.CapacitorCustomPlatform) === null || _a === void 0 ? void 0 : _a.plugins) === null || _b === void 0 ? void 0 : _b.mDNS;\n if (!plugin)\n throw new Error('mDNS Electron plugin is not registered; run npx cap-electron sync in the app');\n return Promise.resolve(plugin);\n },\n});\nconst mDNS = new Proxy(platformPlugin, {\n get(target, property, receiver) {\n if (property !== 'discover')\n return Reflect.get(target, property, receiver);\n return (options) => {\n const timeout = options === null || options === void 0 ? void 0 : options.timeout;\n // Native JSON bridges turn NaN/Infinity into null, losing the invalid input.\n if (timeout != null && (typeof timeout !== 'number' || !Number.isFinite(timeout))) {\n return Promise.resolve({ error: true, errorMessage: 'Invalid timeout', servicesFound: 0, services: [] });\n }\n return target.discover(options);\n };\n },\n});\nexport * from './definitions';\nexport { mDNS };\n//# sourceMappingURL=index.js.map","// src/web.ts\nimport { WebPlugin } from '@capacitor/core';\n/**\n * Web implementation of the mDNS plugin.\n *\n * This class behaves as a thin proxy:\n * - In Electron (when a preload exposes window.mDNS/window.mdns), calls are forwarded over IPC.\n * - In a regular browser, mDNS is not available; methods resolve with well-shaped stub values\n * and log a console message with the [WEB_NOT_SUPPORTED] tag.\n */\nexport class mDNSWeb extends WebPlugin {\n constructor() {\n super(...arguments);\n this.unsupportedMessage = 'mDNS is not supported in this browser runtime';\n }\n /** Electron preload bridge (if present). */\n get electronApi() {\n if (typeof window === 'undefined')\n return undefined;\n return window.mDNS || window.mdns;\n }\n async getPluginPlatform() {\n const api = this.electronApi;\n if (api === null || api === void 0 ? void 0 : api.getPluginPlatform)\n return api.getPluginPlatform();\n return { platform: 'web' };\n }\n async startBroadcast(options) {\n const api = this.electronApi;\n if (api === null || api === void 0 ? void 0 : api.startBroadcast)\n return api.startBroadcast(options);\n console.log('[WEB_NOT_SUPPORTED] startBroadcast', options);\n return { publishing: false, name: '', error: true, errorMessage: this.unsupportedMessage };\n }\n async stopBroadcast() {\n const api = this.electronApi;\n if (api === null || api === void 0 ? void 0 : api.stopBroadcast)\n return api.stopBroadcast();\n console.log('[WEB_NOT_SUPPORTED] stopBroadcast');\n return { publishing: false, error: false, errorMessage: null };\n }\n async discover(options = {}) {\n const api = this.electronApi;\n if (api === null || api === void 0 ? void 0 : api.discover)\n return api.discover(options);\n console.log('[WEB_NOT_SUPPORTED] discover', options);\n return { services: [], error: true, errorMessage: this.unsupportedMessage, servicesFound: 0 };\n }\n async watchServices(options) {\n var _a;\n if ((_a = this.electronApi) === null || _a === void 0 ? void 0 : _a.watchServices)\n return this.electronApi.watchServices(options);\n return { error: true, errorMessage: this.unsupportedMessage, watchersStarted: 0 };\n }\n async stopWatching() {\n var _a;\n if ((_a = this.electronApi) === null || _a === void 0 ? void 0 : _a.stopWatching)\n return this.electronApi.stopWatching();\n return { watching: false, error: false, errorMessage: null };\n }\n async addListener(eventName, handler) {\n var _a;\n if ((_a = this.electronApi) === null || _a === void 0 ? void 0 : _a.addListener)\n return this.electronApi.addListener(eventName, handler);\n return super.addListener(eventName, handler);\n }\n async removeAllListeners() {\n var _a, _b;\n await ((_b = (_a = this.electronApi) === null || _a === void 0 ? void 0 : _a.removeAllListeners) === null || _b === void 0 ? void 0 : _b.call(_a));\n await super.removeAllListeners();\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;;AACA,MAAM,cAAc,GAAGA,mBAAc,CAAC,MAAM,EAAE;AAC9C,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;AAC3D,IAAI,QAAQ,EAAE,MAAM;AACpB,QAAQ,IAAI,EAAE,EAAE,EAAE;AAClB,QAAQ,MAAM,MAAM,GAAG,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,MAAM,CAAC,uBAAuB,MAAM,IAAI,IAAI,EAAE,KAAK,MAAM,GAAG,MAAM,GAAG,EAAE,CAAC,OAAO,MAAM,IAAI,IAAI,EAAE,KAAK,MAAM,GAAG,MAAM,GAAG,EAAE,CAAC,IAAI;AAChK,QAAQ,IAAI,CAAC,MAAM;AACnB,YAAY,MAAM,IAAI,KAAK,CAAC,8EAA8E,CAAC;AAC3G,QAAQ,OAAO,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC;AACtC,IAAI,CAAC;AACL,CAAC,CAAC;AACG,MAAC,IAAI,GAAG,IAAI,KAAK,CAAC,cAAc,EAAE;AACvC,IAAI,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE;AACpC,QAAQ,IAAI,QAAQ,KAAK,UAAU;AACnC,YAAY,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC;AAC1D,QAAQ,OAAO,CAAC,OAAO,KAAK;AAC5B,YAAY,MAAM,OAAO,GAAG,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,OAAO;AAC7F;AACA,YAAY,IAAI,OAAO,IAAI,IAAI,KAAK,OAAO,OAAO,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,EAAE;AAC/F,gBAAgB,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;AACxH,YAAY;AACZ,YAAY,OAAO,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC;AAC3C,QAAQ,CAAC;AACT,IAAI,CAAC;AACL,CAAC;;ACxBD;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,OAAO,SAASC,cAAS,CAAC;AACvC,IAAI,WAAW,GAAG;AAClB,QAAQ,KAAK,CAAC,GAAG,SAAS,CAAC;AAC3B,QAAQ,IAAI,CAAC,kBAAkB,GAAG,+CAA+C;AACjF,IAAI;AACJ;AACA,IAAI,IAAI,WAAW,GAAG;AACtB,QAAQ,IAAI,OAAO,MAAM,KAAK,WAAW;AACzC,YAAY,OAAO,SAAS;AAC5B,QAAQ,OAAO,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI;AACzC,IAAI;AACJ,IAAI,MAAM,iBAAiB,GAAG;AAC9B,QAAQ,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW;AACpC,QAAQ,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,MAAM,GAAG,MAAM,GAAG,GAAG,CAAC,iBAAiB;AAC3E,YAAY,OAAO,GAAG,CAAC,iBAAiB,EAAE;AAC1C,QAAQ,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE;AAClC,IAAI;AACJ,IAAI,MAAM,cAAc,CAAC,OAAO,EAAE;AAClC,QAAQ,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW;AACpC,QAAQ,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,MAAM,GAAG,MAAM,GAAG,GAAG,CAAC,cAAc;AACxE,YAAY,OAAO,GAAG,CAAC,cAAc,CAAC,OAAO,CAAC;AAC9C,QAAQ,OAAO,CAAC,GAAG,CAAC,oCAAoC,EAAE,OAAO,CAAC;AAClE,QAAQ,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,CAAC,kBAAkB,EAAE;AAClG,IAAI;AACJ,IAAI,MAAM,aAAa,GAAG;AAC1B,QAAQ,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW;AACpC,QAAQ,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,MAAM,GAAG,MAAM,GAAG,GAAG,CAAC,aAAa;AACvE,YAAY,OAAO,GAAG,CAAC,aAAa,EAAE;AACtC,QAAQ,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC;AACxD,QAAQ,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE;AACtE,IAAI;AACJ,IAAI,MAAM,QAAQ,CAAC,OAAO,GAAG,EAAE,EAAE;AACjC,QAAQ,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW;AACpC,QAAQ,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,MAAM,GAAG,MAAM,GAAG,GAAG,CAAC,QAAQ;AAClE,YAAY,OAAO,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC;AACxC,QAAQ,OAAO,CAAC,GAAG,CAAC,8BAA8B,EAAE,OAAO,CAAC;AAC5D,QAAQ,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,CAAC,kBAAkB,EAAE,aAAa,EAAE,CAAC,EAAE;AACrG,IAAI;AACJ,IAAI,MAAM,aAAa,CAAC,OAAO,EAAE;AACjC,QAAQ,IAAI,EAAE;AACd,QAAQ,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,WAAW,MAAM,IAAI,IAAI,EAAE,KAAK,MAAM,GAAG,MAAM,GAAG,EAAE,CAAC,aAAa;AACzF,YAAY,OAAO,IAAI,CAAC,WAAW,CAAC,aAAa,CAAC,OAAO,CAAC;AAC1D,QAAQ,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,CAAC,kBAAkB,EAAE,eAAe,EAAE,CAAC,EAAE;AACzF,IAAI;AACJ,IAAI,MAAM,YAAY,GAAG;AACzB,QAAQ,IAAI,EAAE;AACd,QAAQ,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,WAAW,MAAM,IAAI,IAAI,EAAE,KAAK,MAAM,GAAG,MAAM,GAAG,EAAE,CAAC,YAAY;AACxF,YAAY,OAAO,IAAI,CAAC,WAAW,CAAC,YAAY,EAAE;AAClD,QAAQ,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE;AACpE,IAAI;AACJ,IAAI,MAAM,WAAW,CAAC,SAAS,EAAE,OAAO,EAAE;AAC1C,QAAQ,IAAI,EAAE;AACd,QAAQ,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,WAAW,MAAM,IAAI,IAAI,EAAE,KAAK,MAAM,GAAG,MAAM,GAAG,EAAE,CAAC,WAAW;AACvF,YAAY,OAAO,IAAI,CAAC,WAAW,CAAC,WAAW,CAAC,SAAS,EAAE,OAAO,CAAC;AACnE,QAAQ,OAAO,KAAK,CAAC,WAAW,CAAC,SAAS,EAAE,OAAO,CAAC;AACpD,IAAI;AACJ,IAAI,MAAM,kBAAkB,GAAG;AAC/B,QAAQ,IAAI,EAAE,EAAE,EAAE;AAClB,QAAQ,OAAO,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,WAAW,MAAM,IAAI,IAAI,EAAE,KAAK,MAAM,GAAG,MAAM,GAAG,EAAE,CAAC,kBAAkB,MAAM,IAAI,IAAI,EAAE,KAAK,MAAM,GAAG,MAAM,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAC1J,QAAQ,MAAM,KAAK,CAAC,kBAAkB,EAAE;AACxC,IAAI;AACJ;;;;;;;;;"}
|
package/dist/plugin.js
CHANGED
|
@@ -1,9 +1,29 @@
|
|
|
1
1
|
var capacitormDNS = (function (exports, core) {
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
const
|
|
4
|
+
const platformPlugin = core.registerPlugin('mDNS', {
|
|
5
5
|
web: () => Promise.resolve().then(function () { return web; }).then((m) => new m.mDNSWeb()),
|
|
6
|
-
electron: () =>
|
|
6
|
+
electron: () => {
|
|
7
|
+
var _a, _b;
|
|
8
|
+
const plugin = (_b = (_a = window.CapacitorCustomPlatform) === null || _a === void 0 ? void 0 : _a.plugins) === null || _b === void 0 ? void 0 : _b.mDNS;
|
|
9
|
+
if (!plugin)
|
|
10
|
+
throw new Error('mDNS Electron plugin is not registered; run npx cap-electron sync in the app');
|
|
11
|
+
return Promise.resolve(plugin);
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
const mDNS = new Proxy(platformPlugin, {
|
|
15
|
+
get(target, property, receiver) {
|
|
16
|
+
if (property !== 'discover')
|
|
17
|
+
return Reflect.get(target, property, receiver);
|
|
18
|
+
return (options) => {
|
|
19
|
+
const timeout = options === null || options === void 0 ? void 0 : options.timeout;
|
|
20
|
+
// Native JSON bridges turn NaN/Infinity into null, losing the invalid input.
|
|
21
|
+
if (timeout != null && (typeof timeout !== 'number' || !Number.isFinite(timeout))) {
|
|
22
|
+
return Promise.resolve({ error: true, errorMessage: 'Invalid timeout', servicesFound: 0, services: [] });
|
|
23
|
+
}
|
|
24
|
+
return target.discover(options);
|
|
25
|
+
};
|
|
26
|
+
},
|
|
7
27
|
});
|
|
8
28
|
|
|
9
29
|
// src/web.ts
|
|
@@ -53,6 +73,29 @@ var capacitormDNS = (function (exports, core) {
|
|
|
53
73
|
console.log('[WEB_NOT_SUPPORTED] discover', options);
|
|
54
74
|
return { services: [], error: true, errorMessage: this.unsupportedMessage, servicesFound: 0 };
|
|
55
75
|
}
|
|
76
|
+
async watchServices(options) {
|
|
77
|
+
var _a;
|
|
78
|
+
if ((_a = this.electronApi) === null || _a === void 0 ? void 0 : _a.watchServices)
|
|
79
|
+
return this.electronApi.watchServices(options);
|
|
80
|
+
return { error: true, errorMessage: this.unsupportedMessage, watchersStarted: 0 };
|
|
81
|
+
}
|
|
82
|
+
async stopWatching() {
|
|
83
|
+
var _a;
|
|
84
|
+
if ((_a = this.electronApi) === null || _a === void 0 ? void 0 : _a.stopWatching)
|
|
85
|
+
return this.electronApi.stopWatching();
|
|
86
|
+
return { watching: false, error: false, errorMessage: null };
|
|
87
|
+
}
|
|
88
|
+
async addListener(eventName, handler) {
|
|
89
|
+
var _a;
|
|
90
|
+
if ((_a = this.electronApi) === null || _a === void 0 ? void 0 : _a.addListener)
|
|
91
|
+
return this.electronApi.addListener(eventName, handler);
|
|
92
|
+
return super.addListener(eventName, handler);
|
|
93
|
+
}
|
|
94
|
+
async removeAllListeners() {
|
|
95
|
+
var _a, _b;
|
|
96
|
+
await ((_b = (_a = this.electronApi) === null || _a === void 0 ? void 0 : _a.removeAllListeners) === null || _b === void 0 ? void 0 : _b.call(_a));
|
|
97
|
+
await super.removeAllListeners();
|
|
98
|
+
}
|
|
56
99
|
}
|
|
57
100
|
|
|
58
101
|
var web = /*#__PURE__*/Object.freeze({
|
package/dist/plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst
|
|
1
|
+
{"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst platformPlugin = registerPlugin('mDNS', {\n web: () => import('./web').then((m) => new m.mDNSWeb()),\n electron: () => {\n var _a, _b;\n const plugin = (_b = (_a = window.CapacitorCustomPlatform) === null || _a === void 0 ? void 0 : _a.plugins) === null || _b === void 0 ? void 0 : _b.mDNS;\n if (!plugin)\n throw new Error('mDNS Electron plugin is not registered; run npx cap-electron sync in the app');\n return Promise.resolve(plugin);\n },\n});\nconst mDNS = new Proxy(platformPlugin, {\n get(target, property, receiver) {\n if (property !== 'discover')\n return Reflect.get(target, property, receiver);\n return (options) => {\n const timeout = options === null || options === void 0 ? void 0 : options.timeout;\n // Native JSON bridges turn NaN/Infinity into null, losing the invalid input.\n if (timeout != null && (typeof timeout !== 'number' || !Number.isFinite(timeout))) {\n return Promise.resolve({ error: true, errorMessage: 'Invalid timeout', servicesFound: 0, services: [] });\n }\n return target.discover(options);\n };\n },\n});\nexport * from './definitions';\nexport { mDNS };\n//# sourceMappingURL=index.js.map","// src/web.ts\nimport { WebPlugin } from '@capacitor/core';\n/**\n * Web implementation of the mDNS plugin.\n *\n * This class behaves as a thin proxy:\n * - In Electron (when a preload exposes window.mDNS/window.mdns), calls are forwarded over IPC.\n * - In a regular browser, mDNS is not available; methods resolve with well-shaped stub values\n * and log a console message with the [WEB_NOT_SUPPORTED] tag.\n */\nexport class mDNSWeb extends WebPlugin {\n constructor() {\n super(...arguments);\n this.unsupportedMessage = 'mDNS is not supported in this browser runtime';\n }\n /** Electron preload bridge (if present). */\n get electronApi() {\n if (typeof window === 'undefined')\n return undefined;\n return window.mDNS || window.mdns;\n }\n async getPluginPlatform() {\n const api = this.electronApi;\n if (api === null || api === void 0 ? void 0 : api.getPluginPlatform)\n return api.getPluginPlatform();\n return { platform: 'web' };\n }\n async startBroadcast(options) {\n const api = this.electronApi;\n if (api === null || api === void 0 ? void 0 : api.startBroadcast)\n return api.startBroadcast(options);\n console.log('[WEB_NOT_SUPPORTED] startBroadcast', options);\n return { publishing: false, name: '', error: true, errorMessage: this.unsupportedMessage };\n }\n async stopBroadcast() {\n const api = this.electronApi;\n if (api === null || api === void 0 ? void 0 : api.stopBroadcast)\n return api.stopBroadcast();\n console.log('[WEB_NOT_SUPPORTED] stopBroadcast');\n return { publishing: false, error: false, errorMessage: null };\n }\n async discover(options = {}) {\n const api = this.electronApi;\n if (api === null || api === void 0 ? void 0 : api.discover)\n return api.discover(options);\n console.log('[WEB_NOT_SUPPORTED] discover', options);\n return { services: [], error: true, errorMessage: this.unsupportedMessage, servicesFound: 0 };\n }\n async watchServices(options) {\n var _a;\n if ((_a = this.electronApi) === null || _a === void 0 ? void 0 : _a.watchServices)\n return this.electronApi.watchServices(options);\n return { error: true, errorMessage: this.unsupportedMessage, watchersStarted: 0 };\n }\n async stopWatching() {\n var _a;\n if ((_a = this.electronApi) === null || _a === void 0 ? void 0 : _a.stopWatching)\n return this.electronApi.stopWatching();\n return { watching: false, error: false, errorMessage: null };\n }\n async addListener(eventName, handler) {\n var _a;\n if ((_a = this.electronApi) === null || _a === void 0 ? void 0 : _a.addListener)\n return this.electronApi.addListener(eventName, handler);\n return super.addListener(eventName, handler);\n }\n async removeAllListeners() {\n var _a, _b;\n await ((_b = (_a = this.electronApi) === null || _a === void 0 ? void 0 : _a.removeAllListeners) === null || _b === void 0 ? void 0 : _b.call(_a));\n await super.removeAllListeners();\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":"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"}
|
package/docs/electron.md
CHANGED
|
@@ -20,6 +20,10 @@ The Electron runtime generator reads plugin metadata from:
|
|
|
20
20
|
import { pluginSettings } from '@devioarts/capacitor-mdns/electron/settings';
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
+
After installing or updating the plugin, run `npx cap-electron sync` in the application. If the
|
|
24
|
+
generated runtime has no `mDNS` plugin, the root API rejects with an error identifying this step.
|
|
25
|
+
This is a runtime setup error, before a platform implementation can return an operation result.
|
|
26
|
+
|
|
23
27
|
The Electron main-process plugin class is exported from:
|
|
24
28
|
|
|
25
29
|
```ts
|
|
@@ -28,22 +32,33 @@ import { mDNS } from '@devioarts/capacitor-mdns/electron';
|
|
|
28
32
|
|
|
29
33
|
## Manual bridge
|
|
30
34
|
|
|
35
|
+
Continuous discovery uses the same `watchServices`, `stopWatching` and `addListener` API as native
|
|
36
|
+
platforms. After updating the plugin, run `npx cap-electron sync` so the generated metadata includes
|
|
37
|
+
the new methods and the `serviceFound`, `serviceLost`, `watchError` events.
|
|
38
|
+
|
|
31
39
|
The older manual bridge remains available for apps that do not use
|
|
32
40
|
`devioarts/capacitor-electron`.
|
|
33
41
|
|
|
34
|
-
|
|
42
|
+
The Electron runtime needs `bonjour-service`. It is declared as an optional peer dependency
|
|
43
|
+
(only Electron apps need it), so install it in the Electron app:
|
|
35
44
|
|
|
36
45
|
```shell
|
|
37
|
-
npm i bonjour-service
|
|
46
|
+
npm i bonjour-service@~1.4.0
|
|
38
47
|
```
|
|
39
48
|
|
|
49
|
+
The supported range is `~1.4.0` because probe cleanup uses Bonjour 1.4 service behavior. Before widening
|
|
50
|
+
it, run the real-registry regressions for conflicts, pending announcements and goodbye packets.
|
|
51
|
+
|
|
40
52
|
### Main process
|
|
41
53
|
|
|
42
54
|
```ts
|
|
43
55
|
import { app } from 'electron';
|
|
44
56
|
import { mDNS } from '@devioarts/capacitor-mdns/electron';
|
|
45
57
|
|
|
46
|
-
const mdns = new mDNS(
|
|
58
|
+
const mdns = new mDNS(undefined, {
|
|
59
|
+
// Only needed for an exact development server or a custom application origin:
|
|
60
|
+
// trustedOrigins: ['http://localhost:5173'],
|
|
61
|
+
});
|
|
47
62
|
|
|
48
63
|
app.whenReady().then(() => {
|
|
49
64
|
mdns.init();
|
|
@@ -63,3 +78,14 @@ const { createMDNSAPI } = require('@devioarts/capacitor-mdns/electron/mdns-bridg
|
|
|
63
78
|
contextBridge.exposeInMainWorld('mDNS', createMDNSAPI({ ipcRenderer }));
|
|
64
79
|
contextBridge.exposeInMainWorld('mdns', createMDNSAPI({ ipcRenderer }));
|
|
65
80
|
```
|
|
81
|
+
|
|
82
|
+
### IPC trust
|
|
83
|
+
|
|
84
|
+
Manual handlers accept calls only from a trusted top-level frame. By default these are
|
|
85
|
+
`capacitor-electron://localhost` and `file:` documents inside `app.getAppPath()`.
|
|
86
|
+
Unpackaged apps also accept the Capacitor Electron default dev origin `http://localhost:5173`;
|
|
87
|
+
that default dev origin is disabled in packaged apps.
|
|
88
|
+
For a custom protocol or development server, configure its exact origin with `trustedOrigins`.
|
|
89
|
+
Third-party pages, child frames and other origins are rejected. Event delivery uses the same
|
|
90
|
+
URL allowlist, so windows displaying remote pages do not receive service data. The generated
|
|
91
|
+
Capacitor Electron route additionally applies its runtime's sender validation.
|
package/docs/platform-setup.md
CHANGED
|
@@ -45,8 +45,14 @@ Add the local network permissions and every Bonjour service type your app uses t
|
|
|
45
45
|
<key>NSBonjourServices</key>
|
|
46
46
|
<array>
|
|
47
47
|
<string>_http._tcp</string>
|
|
48
|
+
<string>_airplay._tcp</string>
|
|
49
|
+
<string>_googlecast._tcp</string>
|
|
48
50
|
</array>
|
|
49
51
|
```
|
|
50
52
|
|
|
51
53
|
For a custom service such as `_capmdnse2e._tcp.`, add `_capmdnse2e._tcp` to
|
|
52
54
|
`NSBonjourServices`.
|
|
55
|
+
|
|
56
|
+
For continuous watching, include every type passed to `watchServices`. For example, watching
|
|
57
|
+
`['_http._tcp.', '_airplay._tcp.', '_googlecast._tcp.']` requires all three entries shown above. A denied
|
|
58
|
+
Local Network permission is reported through `watchError` and stops the watch group.
|