@entree_pos/beacon
v1.0.1
Published
Zero-dependency UDP service discovery for Node.js applications on a local network.
Maintainers
Readme
@entree_pos/beacon
Find a Node.js service on the same local network without asking users to enter an IP address.
@entree_pos/beacon is a zero-dependency UDP discovery library for Node.js 18+.
A server listens for a short service name. A client broadcasts that name and
receives the server address and port.
npm install @entree_pos/beaconSee the visual guide for the protocol flow, copy-ready examples, and option reference.
Quick start
Start a service beacon:
const beacon = require("@entree_pos/beacon");
const info = { address: "192.168.1.20", port: 8888 };
const listener = beacon.create("Entree POS").listen(15666, true, info);
await listener.ready;
console.log("Ready for discovery");Discover it from another machine on the LAN:
import beacon from "@entree_pos/beacon";
const service = await beacon.create("Entree POS").connect(15666);
console.log(service);
// { address: "192.168.1.20", port: 8888 }Both sides must use the same beacon name and discovery port. UDP broadcast must also be allowed by the client network and host firewall.
Use the sender address
When the application service uses port 8888, the listener can omit info:
const listener = beacon.create("Entree POS").listen(15666);The listener replies with HELLO Entree POS. The client uses the UDP sender's
address and port 8888 by default:
const service = await beacon.create("Entree POS").connect({
defaultServicePort: 8888
});This is useful when a machine has several network interfaces and the address seen by the client is more reliable than a configured address.
Resolve service information per client
Pass a function when the advertised address depends on the requesting client:
const listener = beacon.create("Kitchen API").listen({
info(client) {
return {
address: addressFor(client.address),
port: 9100
};
}
});Cancel discovery
Discovery retries until the timeout is reached. Use an AbortSignal when a
screen closes or the application is shutting down:
const controller = new AbortController();
const pending = beacon.create("Entree POS").connect({
timeout: 15000,
retryInterval: 3000,
signal: controller.signal
});
controller.abort();
await pending;A timeout rejects with BeaconTimeoutError and code BEACON_TIMEOUT.
Close the listener
listen() returns an independent listener. Close it during application
shutdown so Node.js can exit cleanly:
await listener.close();The listener emits listening, query, response, error, and close
events. It also exposes a ready promise and an address() method.
Port or options object
Use a port for the shortest form:
await beacon.create("Entree POS").connect(15666);Use an object when discovery needs additional controls:
await beacon.create("Entree POS").connect({
port: 15666,
timeout: 10000,
retryInterval: 2000,
signal: controller.signal
});The callback form also works:
beacon.create("Entree POS").connect(15666, (service) => {
console.log(service.address, service.port);
});The original create().listen() and create().connect() design is the primary
API. Unlike the internal module, create() now returns an independent
instance. Multiple names and simultaneous discovery requests do not share one
mutable global socket.
Android compatibility
By default, every matching request also sends ANDROID <name> to the client's
discovery port. This preserves the Entree POS Android discovery behavior.
Disable it for other protocols:
beacon.create("My API").listen({
androidEcho: false
});Defaults
| Setting | Default |
| --- | --- |
| Beacon name | BEACON TOWER |
| Discovery port | 15666 |
| Legacy service port | 8888 |
| Retry interval | 3000ms |
| Discovery timeout | 15000ms |
| Broadcast address | 255.255.255.255 |
| Android echo | Enabled |
Use timeout: 0 only when another part of the application owns cancellation.
Documentation
Requirements
- Node.js 18 or newer
- IPv4 UDP broadcast on the local network
- No runtime dependencies
License
MIT
