npm package: @laravelka/zeroconf
Description: Zero configuration networking (zeroconf) plugin for Capacitor
Author: Your Name
Latest version: 1.0.0

# @laravelka/zeroconf

Capacitor plugin for Zeroconf (mDNS) service discovery and broadcasting.

## Install

```bash
npm install @laravelka/zeroconf
npx cap sync
```

## iOS Setup

### Prerequisites
- Xcode 15.0+
- CocoaPods

### Configuration

1. Open your project in Xcode:
```bash
npx cap open ios
```

2. Add the following keys to your `Info.plist` file:
```xml
<!-- Local Network Usage Description -->
<key>NSLocalNetworkUsageDescription</key>
<string>This app needs access to find and connect to local network devices</string>

<!-- Bonjour Services -->
<key>NSBonjourServices</key>
<array>
    <string>_http._tcp.</string>
    <!-- Add other service types your app will use -->
</array>
```

## Android Setup

### Prerequisites
- Android Studio Electric Eel (2022.1.1) or newer
- Android SDK and Platform Tools installed
- Java 17 or newer

### Configuration

1. Open your project in Android Studio:
```bash
npx cap open android
```

2. Add the following permissions to your `android/app/src/main/AndroidManifest.xml`:
```xml
<!-- Required permissions -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
```

3. Update your `android/variables.gradle` to ensure compatibility:
```gradle
ext {
    minSdkVersion = 26
    compileSdkVersion = 34
    targetSdkVersion = 34
    androidxActivityVersion = '1.7.0'
}
```

4. Make sure your `android/build.gradle` has the correct Java version:
```gradle
android {
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_17
        targetCompatibility JavaVersion.VERSION_17
    }
}
```

## Usage

```typescript
import { ZeroConf } from '@laravelka/zeroconf';
import type { PluginListenerHandle, ZeroConfWatchResult } from '@laravelka/zeroconf';

let listener: PluginListenerHandle;

// Listen for service discovery events
const setupListeners = async () => {
  listener = await ZeroConf.addListener('discover', (result: ZeroConfWatchResult) => {
    console.log('Service discovered:', result);
    // result.action will be 'added', 'removed', or 'resolved'
    // result.service contains service information
  });
};

// Register a service
await ZeroConf.register({
  type: '_http._tcp.',
  domain: 'local.',
  name: 'MyService',
  port: 3000,
  txtRecord: {
    path: '/api'
  }
});

// Start watching for services
await ZeroConf.watch({
  type: '_http._tcp.',
  domain: 'local.'
});

// Cleanup listeners when done
await listener?.remove();

// Later: stop watching and cleanup
await ZeroConf.unwatch({
  type: '_http._tcp.',
  domain: 'local.'
});

await ZeroConf.unregister({
  type: '_http._tcp.',
  domain: 'local.',
  name: 'MyService'
});

// Stop all discoveries and unregister all services
await ZeroConf.stop();

// Clean up resources when done
await ZeroConf.close();
```

## Configuration

Add the following to your `capacitor.config.ts`:

```typescript
/// <reference types="@laravelka/zeroconf" />

import { CapacitorConfig } from '@capacitor/cli';

const config: CapacitorConfig = {
  plugins: {
    ZeroConf: {
      // Optional configuration options can be added here
    }
  }
};

export default config;
```

## API

<docgen-index>

* [`addListener('discover', ...)`](#addlistenerdiscover-)
* [`getHostname()`](#gethostname)
* [`register(...)`](#register)
* [`unregister(...)`](#unregister)
* [`watch(...)`](#watch)
* [`unwatch(...)`](#unwatch)
* [`stop()`](#stop)
* [`close()`](#close)
* [Interfaces](#interfaces)

</docgen-index>

<docgen-api>
<!--Update the source file JSDoc comments and rerun docgen to update the docs below-->

Main ZeroConf plugin interface.

### addListener('discover', ...)

```typescript
addListener(eventName: 'discover', listenerFunc: (result: ZeroConfWatchResult) => void) => Promise<PluginListenerHandle>
```

Add a listener for service discovery events.

| Param              | Type                                                                                     | Description                                                          |
| ------------------ | ---------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
| **`eventName`**    | <code>'discover'</code>                                                                  | - The name of the event to listen for                                |
| **`listenerFunc`** | <code>(result: <a href="#zeroconfwatchresult">ZeroConfWatchResult</a>) =&gt; void</code> | - Callback function that will be called when a service is discovered |

**Returns:** <code>Promise&lt;<a href="#pluginlistenerhandle">PluginListenerHandle</a>&gt;</code>

**Since:** 1.0.0

--------------------


### getHostname()

```typescript
getHostname() => Promise<{ hostname: string; }>
```

Get the hostname of the device.

**Returns:** <code>Promise&lt;{ hostname: string; }&gt;</code>

**Since:** 1.0.0

--------------------


### register(...)

```typescript
register(options: { type: string; domain?: string | undefined; name: string; port: number; txtRecord?: { [key: string]: string; } | undefined; }) => Promise<void>
```

Register a new service.

| Param         | Type                                                                                                                | Description                    |
| ------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------------ |
| **`options`** | <code>{ type: string; domain?: string; name: string; port: number; txtRecord?: { [key: string]: string; }; }</code> | - Service registration options |

**Since:** 1.0.0

--------------------


### unregister(...)

```typescript
unregister(options: { type: string; name: string; }) => Promise<void>
```

Unregister a previously registered service.

| Param         | Type                                         | Description                      |
| ------------- | -------------------------------------------- | -------------------------------- |
| **`options`** | <code>{ type: string; name: string; }</code> | - Service unregistration options |

**Since:** 1.0.0

--------------------


### watch(...)

```typescript
watch(options: { type: string; domain?: string; }) => Promise<void>
```

Start watching for services of a specific type.

| Param         | Type                                            | Description             |
| ------------- | ----------------------------------------------- | ----------------------- |
| **`options`** | <code>{ type: string; domain?: string; }</code> | - Service watch options |

**Since:** 1.0.0

--------------------


### unwatch(...)

```typescript
unwatch(options: { type: string; }) => Promise<void>
```

Stop watching for services of a specific type.

| Param         | Type                           | Description               |
| ------------- | ------------------------------ | ------------------------- |
| **`options`** | <code>{ type: string; }</code> | - Service unwatch options |

**Since:** 1.0.0

--------------------


### stop()

```typescript
stop() => Promise<void>
```

Stop all ongoing service discoveries and unregister all services.

**Since:** 1.0.0

--------------------


### close()

```typescript
close() => Promise<void>
```

Close the Zeroconf instance and clean up resources.

**Since:** 1.0.0

--------------------


### Interfaces


#### PluginListenerHandle

| Prop         | Type                                      |
| ------------ | ----------------------------------------- |
| **`remove`** | <code>() =&gt; Promise&lt;void&gt;</code> |


#### ZeroConfWatchResult

Result of a ZeroConf service discovery event.

| Prop          | Type                                                        |
| ------------- | ----------------------------------------------------------- |
| **`action`**  | <code>'added' \| 'removed' \| 'resolved'</code>             |
| **`service`** | <code><a href="#zeroconfservice">ZeroConfService</a></code> |


#### ZeroConfService

Represents a discovered ZeroConf service.

| Prop                | Type                                    |
| ------------------- | --------------------------------------- |
| **`domain`**        | <code>string</code>                     |
| **`type`**          | <code>string</code>                     |
| **`name`**          | <code>string</code>                     |
| **`port`**          | <code>number</code>                     |
| **`hostname`**      | <code>string</code>                     |
| **`ipv4Addresses`** | <code>string[]</code>                   |
| **`ipv6Addresses`** | <code>string[]</code>                   |
| **`txtRecord`**     | <code>{ [key: string]: string; }</code> |

</docgen-api>

## Example Usage

```typescript
import { ZeroConf } from '@laravelka/zeroconf';
import type { PluginListenerHandle, ZeroConfWatchResult } from '@laravelka/zeroconf';

class ZeroConfExample {
  private listener: PluginListenerHandle | null = null;

  async initialize() {
    // Setup event listener
    this.listener = await ZeroConf.addListener('discover', (result: ZeroConfWatchResult) => {
      console.log('Service discovered:', result);
      // result.action will be 'added', 'removed', or 'resolved'
      // result.service contains service information
    });

    // Register our service
    await ZeroConf.register({
      type: '_http._tcp.',
      domain: 'local.',
      name: 'MyService',
      port: 3000,
      txtRecord: {
        path: '/api'
      }
    });

    // Start watching for services
    await ZeroConf.watch({
      type: '_http._tcp.',
      domain: 'local.'
    });
  }

  async cleanup() {
    // Remove event listener
    if (this.listener) {
      await this.listener.remove();
      this.listener = null;
    }

    // Stop watching for services
    await ZeroConf.unwatch({
      type: '_http._tcp.',
      domain: 'local.'
    });

    // Unregister our service
    await ZeroConf.unregister({
      type: '_http._tcp.',
      domain: 'local.',
      name: 'MyService'
    });

    // Stop all discoveries and unregister all services
    await ZeroConf.stop();

    // Clean up resources
    await ZeroConf.close();
  }
}
```

## Platform Support

- ✅ Android (using JmDNS)
- ✅ iOS (using Network.framework and NetService)

## Requirements

- Capacitor 7.0.0 or newer
- iOS 13.0 or newer (Xcode 15.0+)
- Android API 26 (Android 8.0) or newer

## License

MIT