Skip to content

Dial the address mDNS resolved instead of the .local name - #232

Merged
wizzomafizzo merged 3 commits into
feat/device-registryfrom
feat/device-mdns-resolution
Aug 16, 2026
Merged

Dial the address mDNS resolved instead of the .local name#232
wizzomafizzo merged 3 commits into
feat/device-registryfrom
feat/device-mdns-resolution

Conversation

@wizzomafizzo

Copy link
Copy Markdown
Member

Stacked on #231 — targets feat/device-registry and retargets to main once that merges.

A device saved from a network scan keeps its .local hostname, which is the identity that survives a DHCP move. iOS WebSockets do not reliably bootstrap multicast resolution themselves, so connecting to that hostname could simply never come up.

The provider now browses mDNS while the active record names a .local host, matches the announcement for that record on its service id (or hostname and port when it has none, never on an address — DHCP recycles those), and stores the resolved addresses on the endpoint. The socket and pairing dial the resolved address; the record still displays and stores the hostname, so the device is followed rather than duplicated when its IP changes. Browsing stops once the hostname is resolved on a live connection.

Discovery is shared rather than exclusive now that two callers want it: the ZeroConf watch is owned by refcount, so the scan modal closing cannot stop the browse the connection provider still needs, and both see the same device cache.

Also raises the licenses route test timeout — it renders the full production dependency list and was reaching the default 10s under a full parallel run.

https://claude.ai/code/session_01MevSjtLDnHofR1Eub9vKGN

Addresses were the device identity: DHCP moved them, mDNS gave one box two
names, and credentials keyed by address meant a device inheriting a recycled
IP picked up the previous device's auth token.

Devices now live in a registry keyed by an opaque recordId, with addresses
demoted to endpoints hanging off the record. Credentials are stored under
record:<recordId>, media and library caches namespace on the record key, and
the device detail route takes a recordId rather than an address.

Existing installs migrate once on hydrate: deviceHistory and deviceAddress
become records, each carrying legacyCredentialKey so the old credential stays
readable until the first authenticated connect re-keys it, after which both
legacy Preferences entries are deleted. Migration is covered end to end,
including the IPv6 normalisation change and corrupt-history recovery.

Claude-Session: https://claude.ai/code/session_01MevSjtLDnHofR1Eub9vKGN
A device saved from a network scan keeps its `.local` hostname, which is the
identity that survives a DHCP move. iOS WebSockets do not reliably bootstrap
multicast resolution themselves, so connecting to that hostname could simply
never come up.

The provider now browses mDNS while the active record names a `.local` host,
matches the announcement for that record on its service id (or hostname and
port when it has none, never on an address — DHCP recycles those), and stores
the resolved addresses on the endpoint. The socket and pairing dial the
resolved address; the record still displays and stores the hostname, so the
device is followed rather than duplicated when its IP changes. Browsing stops
once the hostname is resolved on a live connection.

Discovery is shared rather than exclusive now that two callers want it: the
ZeroConf watch is owned by refcount, so the scan modal closing cannot stop the
browse the connection provider still needs, and both see the same device cache.

Also raises the licenses route test timeout — it renders the full production
dependency list and was reaching the default 10s under a full parallel run.

Claude-Session: https://claude.ai/code/session_01MevSjtLDnHofR1Eub9vKGN
@coderabbitai

coderabbitai Bot commented Aug 15, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: b1ef4451-19bd-4089-980b-6a10f6b69523

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Aug 16, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.28261% with 5 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/hooks/useNetworkScan.ts 95.45% 4 Missing ⚠️
src/lib/devices/deviceRegistry.ts 97.91% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@wizzomafizzo
wizzomafizzo merged commit a400f78 into main Aug 16, 2026
6 checks passed
@wizzomafizzo
wizzomafizzo deleted the feat/device-mdns-resolution branch August 16, 2026 21:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant