Usage

Porthoster has two halves, joined by a sync. On the client side you keep a local folder of plain JavaScript and author, edit and test handlers in it. On the server side a broker reads that same folder, opens each declared port, and routes accepted traffic to the matching handler.

The join between them is the filename. A top-level file is an entry point when its name matches the handler grammar, and the number in the name is exactly the port that gets opened:

port/
  echo.tcp.7000.port.js       →  TCP  :7000  public
  metrics.udp.9125.port.js    →  UDP  :9125  public
  relay.tcp.4000.port.js      →  TCP  :4000  public
  lib/framing.js              →  supporting code — imported, opens no port
  _scratch.tcp.7001.port.js   →  ignored (leading _ = local only)

Server →

The broker model: how one process opens every port, screens each connection, and hands it to your handler — the handler contract, the ctx, concurrency, and code examples.

Client →

The local workflow: the port folder, what syncs and what stays local, developing in place with an _ prefix, and how a set of edits goes live safely.

One folder, two roles

You never write a server. You write the logic for a connection or a datagram, and the broker does the plumbing — the listen, the accept loop, TLS, and the access checks. Because both sides read the same flat folder, there is nothing to wire up: rename a file to change its port, prefix it with _ to take it offline, drop the prefix to put it live.