Skip to content

feat(net): add isPortAvailable#7204

Open
Xavrir wants to merge 2 commits into
denoland:mainfrom
Xavrir:feat/net-is-port-available
Open

feat(net): add isPortAvailable#7204
Xavrir wants to merge 2 commits into
denoland:mainfrom
Xavrir:feat/net-is-port-available

Conversation

@Xavrir

@Xavrir Xavrir commented Jun 30, 2026

Copy link
Copy Markdown

Closes #7196.

@std/net only had getAvailablePort, so there was no quick way to ask "is this specific port free?" without writing the Deno.listen plus catch yourself. This adds that:

isPortAvailable(port: number, options?: { hostname?: string }): boolean

It returns true when the TCP port can be listened on, false on Deno.errors.AddrInUse, and rethrows any other error (including PermissionDenied for privileged ports or a missing net permission). hostname defaults to 0.0.0.0. Since net is stable, it lives in unstable_is_port_available.ts as the @std/net/unstable-is-port-available export and isn't re-exported from mod.ts.

The doc comment is upfront about the obvious race: the port can be taken between the check and your own listen, so it points back to port: 0 / getAvailablePort for cases where you own the listener.

Tests cover an available port, a port already in use, the hostname option, and the rethrow path for errors other than AddrInUse. deno task lint, deno fmt --check, and deno test -A --doc pass locally.

One open question: happy to also add getAvailablePorts(count, options?) here if that would be useful, or keep this PR to the single function.

@github-actions github-actions Bot added the net label Jun 30, 2026
@CLAassistant

CLAassistant commented Jun 30, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@codecov

codecov Bot commented Jun 30, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.84%. Comparing base (0e5b1f2) to head (c996483).

Additional details and impacted files
@@           Coverage Diff            @@
##             main    #7204    +/-   ##
========================================
  Coverage   94.83%   94.84%            
========================================
  Files         617      618     +1     
  Lines       51674    51438   -236     
  Branches     9350     9305    -45     
========================================
- Hits        49007    48785   -222     
+ Misses       2121     2112     -9     
+ Partials      546      541     -5     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@yuhr

yuhr commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Great work! Looks good to me, Thanks. I'd go for keeping this one small at this time.

Comment thread net/unstable_is_port_available.ts Outdated
Comment on lines +66 to +69
using _listener = Deno.listen({
port,
hostname: options?.hostname ?? "0.0.0.0",
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like "0.0.0.0" is already the default in Deno.ListenOptions.

Suggested change
using _listener = Deno.listen({
port,
hostname: options?.hostname ?? "0.0.0.0",
});
using _listener = Deno.listen({ port, hostname: options?.hostname });

@Xavrir Xavrir Jul 1, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. The literal hostname: options?.hostname trips exactOptionalPropertyTypes (passing hostname: undefined is not assignable to hostname?: string), so I forward the hostname only when it is set and otherwise omit it, letting Deno.ListenOptions apply its 0.0.0.0 default:

using _listener = Deno.listen(
  options?.hostname !== undefined
    ? { port, hostname: options.hostname }
    : { port },
);

That drops the redundant literal without widening what gets forwarded to Deno.listen. Updated in the latest push.

@Xavrir Xavrir force-pushed the feat/net-is-port-available branch from 1e1db52 to 8b01f2b Compare July 1, 2026 11:12
@Xavrir Xavrir force-pushed the feat/net-is-port-available branch from 8b01f2b to c996483 Compare July 1, 2026 11:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

@std/net: Add isPortAvailable, etc.

4 participants