feat(tsconnect): add TCPListener and tighten dial/listen network types
Type the new TCP listening surface from the tailscale submodule: - listen() is now overloaded: tcp/tcp4/tcp6 returns a TCPListener, udp/udp4/udp6 returns a PacketConn. The network parameter is a literal union instead of a bare string so callers get completion and typo protection. - TCPListener extends AsyncIterable<Conn>, so consumers can write `for await (const conn of listener)`. - dial() drops "udp" from its accepted networks. Connected UDP through a stream-shaped Conn was confusing; UDP belongs in listen(), and ICMP in listenICMP(). The Go side still accepts whatever string for callers who really want to bypass the type. Bumps the TS lib/target to ES2018 for AsyncIterable, bumps the tailscale submodule, and updates the test-app inline example to demonstrate `for await` over a TCP listener.
This commit is contained in:
@@ -46,7 +46,14 @@ ipn.login()
|
||||
// Once running, try the networking APIs:
|
||||
const conn = await ipn.dial("tcp", "some-peer:22")
|
||||
const pc = await ipn.listenICMP("icmp4")
|
||||
const tls = await ipn.dialTLS("some-peer.tail-scale.ts.net:443")</code></pre>
|
||||
const tls = await ipn.dialTLS("some-peer.tail-scale.ts.net:443")
|
||||
|
||||
// Accept incoming TCP connections via async iteration:
|
||||
const ln = await ipn.listen("tcp", "0.0.0.0:8080")
|
||||
for await (const c of ln) {
|
||||
console.log("got conn from", c.remoteAddr())
|
||||
c.close()
|
||||
}</code></pre>
|
||||
<p id="status">Loading…</p>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
|
||||
@@ -5,6 +5,7 @@ import type { IPN, IPNConfig } from "./types"
|
||||
export type {
|
||||
Conn,
|
||||
PacketConn,
|
||||
TCPListener,
|
||||
TLSDialOptions,
|
||||
IPN,
|
||||
IPNConfig,
|
||||
|
||||
@@ -83,6 +83,24 @@ export interface PacketConn {
|
||||
localAddr(): string
|
||||
}
|
||||
|
||||
/**
|
||||
* A TCP listener accepting incoming connections from the Tailscale network.
|
||||
*
|
||||
* Implements `AsyncIterable<Conn>` so callers can write:
|
||||
*
|
||||
* for await (const conn of listener) { ... }
|
||||
*
|
||||
* The iterator finishes cleanly when `close()` is called; any other accept
|
||||
* error rejects the iterator's pending `next()`.
|
||||
*/
|
||||
export interface TCPListener extends AsyncIterable<Conn> {
|
||||
/** Accept a single incoming connection. */
|
||||
accept(): Promise<Conn>
|
||||
close(): boolean
|
||||
/** The local listening address, e.g. "100.64.0.1:8080". */
|
||||
addr(): string
|
||||
}
|
||||
|
||||
export interface IPN {
|
||||
run(callbacks: IPNCallbacks): void
|
||||
login(): void
|
||||
@@ -109,18 +127,30 @@ export interface IPN {
|
||||
}>
|
||||
|
||||
/**
|
||||
* Dial a TCP or UDP connection to a Tailscale peer.
|
||||
* @param network - "tcp" or "udp"
|
||||
* Dial a TCP connection to a Tailscale peer.
|
||||
* @param network - "tcp", "tcp4", or "tcp6"
|
||||
* @param addr - "host:port" (host can be a Tailscale IP or MagicDNS name)
|
||||
*/
|
||||
dial(network: "tcp" | "udp", addr: string): Promise<Conn>
|
||||
dial(network: "tcp" | "tcp4" | "tcp6", addr: string): Promise<Conn>
|
||||
|
||||
/**
|
||||
* Listen for incoming TCP connections on the Tailscale network.
|
||||
* @param network - "tcp", "tcp4", or "tcp6"
|
||||
* @param addr - "host:port" to bind to (e.g. "0.0.0.0:0" for any address and port)
|
||||
*/
|
||||
listen(
|
||||
network: "tcp" | "tcp4" | "tcp6",
|
||||
addr: string
|
||||
): Promise<TCPListener>
|
||||
/**
|
||||
* Listen for incoming UDP packets on the Tailscale network.
|
||||
* @param network - "udp", "udp4", or "udp6"
|
||||
* @param addr - "host:port" to bind to (e.g. "0.0.0.0:0" for any)
|
||||
* @param addr - "host:port" to bind to (e.g. "0.0.0.0:0" for any address and port)
|
||||
*/
|
||||
listen(network: string, addr: string): Promise<PacketConn>
|
||||
listen(
|
||||
network: "udp" | "udp4" | "udp6",
|
||||
addr: string
|
||||
): Promise<PacketConn>
|
||||
|
||||
/**
|
||||
* Open an ICMP endpoint on the Tailscale network stack.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2017",
|
||||
"target": "ES2018",
|
||||
"module": "ES2020",
|
||||
"moduleResolution": "node",
|
||||
"strict": true,
|
||||
@@ -8,7 +8,7 @@
|
||||
"outDir": "out",
|
||||
"rootDir": "src",
|
||||
"sourceMap": true,
|
||||
"lib": ["ES2017", "DOM"]
|
||||
"lib": ["ES2018", "DOM"]
|
||||
},
|
||||
"include": ["src/**/*"]
|
||||
}
|
||||
|
||||
+1
-1
Submodule tailscale updated: fde5f11895...f961db8925
Reference in New Issue
Block a user