@statewalker/webrun-rpc 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -62,7 +62,7 @@ Stream tier and adapter:
62
62
  | `serve(params: PortParams, handler)` | Registers a `Duplex` handler. Resolves an idempotent teardown that abandons live streams, then closes the mux. |
63
63
  | `PortParams` | `{ mux: PortMuxFactory; timeout?: number }`. |
64
64
  | `PortMuxFactory`, `OnPort` | `(onPort?: OnPort) => PortMux \| Promise<PortMux>`; `(port, meta?) => boolean \| undefined`, `false` rejects. |
65
- | `overPipe(pipe, options: OverPipeOptions)` | A factory over one pipe via `multiplexPort`. Options: `codec`, `side`, `maxPorts`, `maxMessageSize`. |
65
+ | `overPipe(pipe, options: OverPipeOptions)` | A factory over one pipe via `multiplexPort`. Options: `codec`, `side`, `maxPorts`, `maxMessageSize`, `signal`, `window`, `frameSize`. |
66
66
  | `overPorts(factory)` | Pass-through, for a mux this package knows nothing about. |
67
67
  | `duplexOverPort(port, options?)` | A `Duplex` running one stream on `port`. |
68
68
  | `serveDuplexOverPort(port, handler, options?)` | The serving half. Returns an idempotent teardown that abandons the stream and notifies the peer. |
@@ -75,8 +75,10 @@ Port multiplexing:
75
75
  | --- | --- |
76
76
  | `multiplexPort(port, options: PortMuxOptions)` | Emulated multiplexing over one port. |
77
77
  | `transferPortMux(target, options?: TransferPortMuxOptions)` | Multiplexing with real transferred `MessagePort`s. |
78
- | `PortMux` | `openPort(meta?)`, `close()`, `maxMessageSize`. |
79
- | `PortCodec`, `PortEnvelope` | The wire seam: `post(port, envelope, transfer?)`, `read(event)`. |
78
+ | `PortMux` | `openPort(meta?, { signal }?)`, `close(reason?)`, `ports?()`, `maxMessageSize`. |
79
+ | `portBufferedAmount(port)`, `whenPortReady(port, below?)` | A windowed port's queued bytes, and a promise for room. See below. |
80
+ | `PortInfo`, `OpenPortOptions` | What `ports()` reports per port (`id`, `meta`, `openedAt`, `lastActivity`); `openPort`'s options. |
81
+ | `PortCodec`, `PortEnvelope` | The wire seam: `post(port, envelope, transfer?)`, `read(event)`, and optionally `encode(envelope)` / `decode(data)` for byte codecs (exact window sizes, frames). |
80
82
  | `structuredCodec` | Envelopes passed through unencoded. |
81
83
  | `DEFAULT_MAX_PORTS` | `1024`. |
82
84
  | `PORT_TRANSFER` | `"webrun-rpc:port-transfer"`, the `type` of the message that carries a port. |
@@ -278,8 +280,9 @@ multiplexer's port, and the RPC tier runs over a virtual port with no byte-strea
278
280
 
279
281
  ### A port sends and receives messages, nothing more
280
282
 
281
- `multiplexPort` has no backpressure, acknowledgements, credit or buffer ceiling. That matches
282
- `MessagePort` semantics; waiting strategies belong above. The one safety property it holds: **a
283
+ Without `window`, `multiplexPort` has no backpressure, acknowledgements, credit or buffer ceiling.
284
+ That matches `MessagePort` semantics; waiting strategies belong above, or in the opt-in window
285
+ described below. The one safety property it always holds: **a
283
286
  message for a port with no consumer is dropped, never queued**, so a peer flooding an unaccepted
284
287
  port cannot grow memory here.
285
288
 
@@ -292,22 +295,213 @@ port cannot grow memory here.
292
295
  | `side` | `"initiator"` (default) allocates even ids, `"responder"` odd, so both ends can open concurrently with no negotiation. The two ends of one pipe must disagree. |
293
296
  | `maxPorts` | Ceiling on concurrently open ports, default `DEFAULT_MAX_PORTS` (1024). Closing a port frees its slot. It bounds the id table, never the total over time, and never delays a message. A peer `open` past the limit is answered with `close` reason `"max-ports"`. |
294
297
  | `maxMessageSize` | Largest payload a chunk may carry, if the transport has a limit. Reported to the stream tier, never enforced. See below. |
298
+ | `signal` | The transport's life. On abort the mux closes with `signal.reason`; an already-aborted signal gives a closed mux. See below. |
299
+ | `window` | Per-port flow control in bytes, off when unset. See "A port with a window holds only its own bytes" below. |
300
+ | `frameSize` | Fair framing in bytes, off when unset; needs `window`. See "Large messages take turns with small ones" below. |
301
+ | `keepalive` | `{ intervalMs, misses? }`, off when unset: ping the peer and close the mux after `misses` unanswered pings from a peer that answered before. See "A port lives until its transport or its user lets go" below. |
302
+ | `onLeak` | Development aid, off when unset: called with a port's `PortInfo` when its consumer dropped it without `close()`, and the port is freed. See "A port lives until its transport or its user lets go" below. |
303
+
304
+ ### A port with a window holds only its own bytes
305
+
306
+ Without a window, a port has no backpressure: a slow consumer turns into unbounded memory, and
307
+ every other port waits behind the shared queue. With `window: n`, each port this mux opens asks
308
+ for flow control in its `open`, and the peer's mux applies it to that port in both directions.
309
+ Each side may then have at most `n` bytes of a port's messages delivered to the other side and
310
+ not yet consumed. What exceeds the window waits in the port's send queue:
311
+
312
+ - `portBufferedAmount(port)` returns the queued bytes;
313
+ - `whenPortReady(port, below = 0)` resolves once at most `below` bytes are queued.
314
+
315
+ A sender that must not queue without bound awaits `whenPortReady` before posting more. It always
316
+ resolves on a later task, never synchronously: a producer loop with room to spare would otherwise
317
+ never yield, and the transport's own events (the credit that refills the window, the socket's
318
+ writes) would never run.
319
+
320
+ A message counts as consumed once every listener has returned, or, for a listener that returns a
321
+ promise, once it settles. A consumer that takes messages from its own queue returns a promise
322
+ that settles when it takes them. **A listener whose promise never settles keeps its port's window
323
+ spent for good**: correct for backpressure, and visible in `mux.ports()`, whose `unconsumed`
324
+ stays at the window (with `queued` and `outstanding` on the sending side).
325
+
326
+ Credit goes back in batches: at once from a quarter of the window, else on the next task. 10,000
327
+ small messages and their echoes take fewer than 200 credit envelopes.
328
+
329
+ **What a message costs.** When both ends' codecs implement `encode` / `decode`, as `msgpackCodec`
330
+ does, the window counts the encoded bytes, envelope included, and the message is encoded once,
331
+ when it is posted. Each end says so in its `open` or its ack (`exact: true`); if either cannot,
332
+ both count an estimate computed from the same value: byte length for `ArrayBuffer`s and typed
333
+ arrays, a string's length, an object's values 4 levels deep and at most 256 of them, and at least
334
+ 64 bytes. Two ends counting different sizes would leak window on every message until the port
335
+ wedged. A message larger than the window is sent once nothing else is outstanding.
336
+
337
+ **Older peers.** A peer from before the window reads `window` in an `open` but never sends
338
+ credit, and a codec from before it drops `credit` envelopes. So neither end holds back until the
339
+ other has shown it reads credit: the responder acknowledges the window with a zero-byte `credit`
340
+ before `onPort` runs (so what `onPort` posts reaches the opener after it, counted the same way on
341
+ both ends), and the opener answers that ack with one of its own. Until then
342
+ each end counts bytes but holds nothing back, so a port to an older peer, or over an older codec,
343
+ keeps running without flow control, as it always did; `ports()` reports `window` only once it is
344
+ in force. A peer's `window` that is not a positive integer is ignored.
345
+
346
+ **Closing does not wait for credit.** A port closed with messages still queued sends them at once,
347
+ then its close, regardless of the window: a peer that stopped returning credit (a listener that
348
+ never settles) must still learn the port is closed, and nothing is kept for a port nobody holds.
349
+ A message that has to wait in the queue is copied when posted (`structuredClone`, or encoded at
350
+ once by a byte codec), as `postMessage` copies at once, so a caller reusing its buffer does not
351
+ change what is sent. `listenPort` counts a request as consumed when it reaches its handler, not
352
+ when the handler finishes, so a handler waiting on a later call on the same port does not hold
353
+ the window that call needs. The window is off by default: 256 KiB favours latency under load, 1-4 MiB favours bulk
354
+ throughput.
355
+
356
+ ### Large messages take turns with small ones
357
+
358
+ All ports share one pipe, and a message leaves whole. So without more, a port sending 1 MiB holds
359
+ the pipe for the whole megabyte, and a 64-byte message on another port waits behind it: the
360
+ window bounds how much is in flight, not the order on the wire. With `frameSize: n`:
361
+
362
+ - every windowed port's messages, and every port's `close`, wait in a per-port queue, and the
363
+ queues take turns, one item each, whenever the pipe has room (a port without a window posts its
364
+ messages at once, as without `frameSize`);
365
+ - a message whose encoding is larger than `n` is split into `frame` envelopes of `n` bytes, which
366
+ the peer reassembles before delivery.
367
+
368
+ A small message then waits for one frame, not for a whole large message. **It needs the pipe to
369
+ report when it is full**: `MessageTarget`'s optional `whenDrained()` (and `bufferedAmount`), which
370
+ `messageTargetOverStream` in `@statewalker/webrun-streams-libp2p` provides. A pipe without it,
371
+ such as a `MessagePort`, accepts everything at once, so the queues empty in one go and only the
372
+ frames of messages posted together interleave.
373
+
374
+ It also needs `window` and byte codecs (`encode` / `decode`) on both ends. A side frames only on a
375
+ port whose window is in force with exact sizes agreed (`exact: true` in the `open` and in its
376
+ acknowledgement), and accepts frames only there; a frame anywhere else is dropped. An older peer,
377
+ or one whose codec cannot decode, gets whole messages. A frame sequence buffers no more than the
378
+ same message sent whole would. If the pipe's `whenDrained()` rejects, the mux closes with that
379
+ error, so the ports waiting behind it fail instead of hanging. 16-64 KiB frames cost one small envelope each (about 15 bytes with
380
+ `msgpackCodec`).
295
381
 
296
382
  `openPort(meta?)` allocates a port, announces it and returns the local end without waiting for the
297
383
  peer to accept. That keeps layer 1 free of round trips: messages posted before a rejection are
298
384
  dropped at the far end and the port goes inert. It is asynchronous because a natively multiplexed
299
385
  transport cannot produce a port synchronously and both must share one shape. Its guard failures
300
386
  are rejections, not synchronous throws: `RangeError: webrun-rpc: maxPorts (<n>) reached` and
301
- `Error: webrun-rpc: the multiplexer is closed`. A duplicate `open` id from the peer is ignored
302
- rather than replacing a live port, and a local `openPort` skips ids the peer already claimed with
303
- the wrong parity.
304
-
305
- `PortEnvelope` is `{ type: "open", id, meta? }`, `{ type: "message", id, payload }` or
306
- `{ type: "close", id, reason? }`. `structuredCodec.read` accepts only objects with a non-negative
307
- integer `id` and one of those three types, so other traffic on a shared port is ignored.
387
+ `Error: webrun-rpc: the multiplexer is closed`. The `RangeError` goes on with the three commonest
388
+ `meta.kind`s among the open ports, `open ports by kind: http: 1000, ws: 24`, so a full table names
389
+ the consumer that filled it (`"?"` counts ports without a kind). A duplicate `open` id from the
390
+ peer is ignored rather than replacing a live port, and a local `openPort` skips ids the peer
391
+ already claimed with the wrong parity.
392
+
393
+ `PortEnvelope` is `{ type: "open", id, meta?, window?, exact? }`, `{ type: "message", id, payload }`,
394
+ `{ type: "close", id, reason? }`, with a window `{ type: "credit", id, bytes, exact? }`, with
395
+ `frameSize` `{ type: "frame", id, data, last? }`, and with `keepalive` `{ type: "ping", id }` /
396
+ `{ type: "pong", id }` (on `Number.MAX_SAFE_INTEGER`). The codecs' `read` accept only objects with a non-negative integer `id`
397
+ and one of those seven types, so other traffic on a shared port is
398
+ ignored.
308
399
  `structuredCodec` passes envelopes through unencoded, so `ArrayBuffer`s move zero-copy through the
309
400
  transfer list; it omits an empty transfer list because some implementations reject one.
310
401
 
402
+ ### A port lives until its transport or its user lets go
403
+
404
+ A port leaves the table only when one side closes it or the mux closes. Nothing else frees it, and
405
+ a full table refuses every new port. So both lifetimes are wired in explicitly:
406
+
407
+ - **The transport.** A `MessagePort`, a terminated worker or a dead libp2p stream gives no close
408
+ event, so the mux cannot notice by itself. Pass `signal` and abort it from whatever does notice
409
+ (a worker's `exit`, a stream's `close`, a liveness lock): the mux closes with `signal.reason`,
410
+ every port's close signal aborts with it, and calls in flight reject at once instead of hanging.
411
+ `close(reason)` does the same by hand. A port opened from a close-signal listener while the mux
412
+ closes is refused, and a transport `close()` that rejects on this path is swallowed rather than
413
+ left as an unhandled rejection.
414
+ - **The user.** `openPort(meta, { signal })` closes the port when `signal` aborts, with
415
+ `signal.reason` as the reason of the port's close signal; a signal already aborted rejects
416
+ `openPort` with its reason and opens nothing. `transferPortMux` honours the signal too. Virtual
417
+ ports are also disposable where the runtime defines `Symbol.dispose`, so
418
+ `using port = (await mux.openPort()) as MessageTarget & Disposable` closes it on scope exit. The
419
+ cast is needed because the declared type leaves `Symbol.dispose` out: naming it would require
420
+ every consumer to compile with the `esnext.disposable` lib.
421
+
422
+ What aborts `signal` depends on the transport. A Node worker reports its death:
423
+
424
+ ```ts
425
+ import { Worker } from "node:worker_threads";
426
+
427
+ const worker = new Worker(new URL("./worker.js", import.meta.url));
428
+ const { port1, port2 } = new MessageChannel();
429
+ worker.postMessage({ port: port2 }, [port2]);
430
+ const exited = new AbortController();
431
+ worker.once("exit", (code) => exited.abort(new Error(`the worker exited (${code})`)));
432
+ const mux = multiplexPort(port1, { codec: structuredCodec, signal: exited.signal });
433
+ ```
434
+
435
+ A browser realm (a tab, an iframe, a worker) reports nothing, but the browser releases its
436
+ [Web Locks](https://developer.mozilla.org/docs/Web/API/Web_Locks_API) when it ends. The other realm
437
+ holds a lock for its whole life, and this side asks for the same lock, which it gets only then:
438
+
439
+ ```ts
440
+ // In the other realm: a name of its own (realms of one origin share locks), and
441
+ // "ready" only from inside the callback, once the lock is really held.
442
+ const lock = `realm:${crypto.randomUUID()}`;
443
+ navigator.locks.request(lock, () => {
444
+ port.postMessage({ ready: lock });
445
+ return new Promise(() => {}); // held until this realm ends
446
+ });
447
+
448
+ // Here, on that message (`{ ready }`) — asked before the lock is held, it would be granted at once:
449
+ const gone = new AbortController();
450
+ navigator.locks.request(message.ready, () => gone.abort(new Error("the other realm is gone")));
451
+ const mux = multiplexPort(port, { codec: structuredCodec, signal: gone.signal });
452
+ ```
453
+
454
+ Locks are per browser profile, so this works between realms of one origin, never across a
455
+ network. In Node 24 a worker's locks are not visible to the thread that started it (the parent's
456
+ request is granted while the worker holds the lock), so use `exit` there.
457
+
458
+ **When nothing reports the death, `keepalive` probes for it.** With
459
+ `keepalive: { intervalMs: 5000, misses: 3 }` the mux pings every 5 s, the peer answers, and
460
+ anything the peer sends counts as an answer. After 3 pings in a row with nothing back from a peer
461
+ that has answered before, the mux closes with `webrun-rpc: the peer did not answer 3 keepalive
462
+ pings, 5000 ms apart`, as if `signal` had aborted. The silence it takes is between `misses ×
463
+ intervalMs` and one interval more. That catches a realm that died with no lock to tell and one
464
+ that froze. It cannot tell a peer whose event loop is blocked for that long from a dead one, so
465
+ size the product above the longest pause you expect.
466
+
467
+ - **What counts as silence.** Misses are pings unanswered, not time since the last message, so
468
+ timer jitter cannot turn a prompt answer into a miss, and `misses: 1` is usable. A tick taken
469
+ while this end's own pipe reports a backlog (`bufferedAmount > 0`, as `messageTargetOverStream`
470
+ does) is not counted: a ping stuck behind this end's own upload has not reached the peer.
471
+ - **Who is held to it.** Every current mux answers pings, whether or not it sets `keepalive`, so
472
+ one end is enough, and the two ends' intervals need not match. An older peer never answers and
473
+ is never closed for it. Nor is a peer that dies before its first answer: wire `signal` as well
474
+ where the transport can report death.
475
+ - **What it does not catch.** A peer that keeps sending but stopped consuming is alive by this
476
+ measure; the window (`window`) is what bounds that.
477
+ - **Wire.** `ping` and `pong` are envelopes of their own, sent on the largest safe integer id,
478
+ which no port takes. An older mux whose codec passes unknown envelopes through reads them as a
479
+ close of that id, and so closes nothing. The bundled codecs of older versions drop them.
480
+
481
+ The interval timer is `unref`'d in Node, so it never keeps a process alive. `intervalMs` must be in
482
+ (0, 2³¹ − 1] (past that, timers fire at once) and `misses` a positive integer, or `multiplexPort`
483
+ throws a `RangeError`.
484
+
485
+ `ports()` lists what is open, with each port's `meta`, `openedAt` and `lastActivity` (the last
486
+ message either way), for finding a consumer that never closes.
487
+
488
+ **A dropped port can be reported (`onLeak`).** Weak references cannot free leaks on their own:
489
+ the mux must deliver to every open port, and an abandoned port's listeners usually close over the
490
+ port, so it stays reachable from the table. What they can do is catch the ports nothing else
491
+ holds. The mux keeps only its own record of a port, never the consumer's object, so with
492
+ `onLeak` a port its consumer dropped without `close()` is reported once the collector reclaims it
493
+ (`onLeak(info)`, with its `meta`). What happens next depends on its listeners:
494
+
495
+ - **No listener left:** nothing can reach the port again, so it is freed on both ends as a close
496
+ would free it. Its close signal aborts with `webrun-rpc: the port was dropped without close()`;
497
+ the peer's port closes as on any close (`webrun-rpc: the peer closed the port`).
498
+ - **A listener left** (a subscription that keeps only its handler): the port is still receiving,
499
+ so it is reported and left open. Hold the port, or close it, to silence the report.
500
+
501
+ A port whose own listener refers to it is never collected, so never reported; when the collector
502
+ runs is up to the runtime. It is a development aid: each port costs a `FinalizationRegistry`
503
+ entry.
504
+
311
505
  ### No close is observable at layer 1
312
506
 
313
507
  `MessageTarget` has no close event and a virtual port exposes no state. When a port closes, its
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Makes `target` disposable with `await using`: installs `dispose` as its
3
+ * `[Symbol.asyncDispose]`, where the runtime defines the symbol. Hand-written
4
+ * iterators lose what a native generator gets from `AsyncIteratorPrototype`;
5
+ * this gives it back. A no-op where the symbol is missing. Kept off the
6
+ * declared types, which would require consumers to compile with the
7
+ * `esnext.disposable` lib.
8
+ */
9
+ export declare function asyncDisposable<T extends object>(target: T, dispose: () => Promise<unknown>): T;
10
+ //# sourceMappingURL=async-dispose.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"async-dispose.d.ts","sourceRoot":"","sources":["../src/async-dispose.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAa/F"}
@@ -1,6 +1,6 @@
1
1
  import type { Connect, Serve } from "@statewalker/webrun-streams";
2
2
  import type { MessageTarget } from "./message-target.js";
3
- import type { PortCodec, PortMux } from "./port-types.js";
3
+ import type { PortCodec, PortMux, PortMuxOptions } from "./port-types.js";
4
4
  /** What a mux calls when the peer opens a port. `false` rejects it. */
5
5
  export type OnPort = (port: MessageTarget, meta?: unknown) => boolean | undefined;
6
6
  /**
@@ -80,6 +80,19 @@ export interface OverPipeOptions {
80
80
  * transport's real ceiling — see `PortMuxOptions.maxMessageSize`.
81
81
  */
82
82
  maxMessageSize?: number;
83
+ /** The pipe's life: aborting it closes the mux. See `PortMuxOptions.signal`. */
84
+ signal?: AbortSignal;
85
+ /** Experimental per-port flow control in bytes — see `PortMuxOptions.window`. */
86
+ window?: number;
87
+ /** Fair framing in bytes — see `PortMuxOptions.frameSize`. */
88
+ frameSize?: number;
89
+ /** Liveness of the peer by ping/pong — see `PortMuxOptions.keepalive`. */
90
+ keepalive?: {
91
+ intervalMs: number;
92
+ misses?: number;
93
+ };
94
+ /** Development aid: report ports dropped without `close()` — see `PortMuxOptions.onLeak`. */
95
+ onLeak?: PortMuxOptions["onLeak"];
83
96
  }
84
97
  /**
85
98
  * Ports over ONE PIPE OF BYTES — a `MessagePort`, a worker, a WebSocket.
@@ -1 +1 @@
1
- {"version":3,"file":"connect-serve.d.ts","sourceRoot":"","sources":["../src/connect-serve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAU,KAAK,EAAE,MAAM,6BAA6B,CAAC;AAM1E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAU1D,uEAAuE;AACvE,MAAM,MAAM,MAAM,GAAG,CAAC,IAAI,EAAE,aAAa,EAAE,IAAI,CAAC,EAAE,OAAO,KAAK,OAAO,GAAG,SAAS,CAAC;AAElF;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,MAAM,CAAC,EAAE,MAAM,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAE7E,MAAM,WAAW,UAAU;IACzB;;;;;;;;;;OAUG;IACH,GAAG,EAAE,cAAc,CAAC;IACpB;;;yEAGqE;IACrE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,OAAO,EAAE,OAAO,CAAC,UAAU,CA0BvC,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,KAAK,EAAE,KAAK,CAAC,UAAU,CAqDnC,CAAC;AAEF,MAAM,WAAW,eAAe;IAC9B,mFAAmF;IACnF,KAAK,EAAE,SAAS,CAAC;IACjB;;;;OAIG;IACH,IAAI,CAAC,EAAE,WAAW,GAAG,WAAW,CAAC;IACjC,oEAAoE;IACpE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,eAAe,GAAG,cAAc,CAEtF;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,cAAc,GAAG,cAAc,CAEjE"}
1
+ {"version":3,"file":"connect-serve.d.ts","sourceRoot":"","sources":["../src/connect-serve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAU,KAAK,EAAE,MAAM,6BAA6B,CAAC;AAM1E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAW1E,uEAAuE;AACvE,MAAM,MAAM,MAAM,GAAG,CAAC,IAAI,EAAE,aAAa,EAAE,IAAI,CAAC,EAAE,OAAO,KAAK,OAAO,GAAG,SAAS,CAAC;AAElF;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,MAAM,CAAC,EAAE,MAAM,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAE7E,MAAM,WAAW,UAAU;IACzB;;;;;;;;;;OAUG;IACH,GAAG,EAAE,cAAc,CAAC;IACpB;;;yEAGqE;IACrE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,OAAO,EAAE,OAAO,CAAC,UAAU,CAyCvC,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,KAAK,EAAE,KAAK,CAAC,UAAU,CAqDnC,CAAC;AAEF,MAAM,WAAW,eAAe;IAC9B,mFAAmF;IACnF,KAAK,EAAE,SAAS,CAAC;IACjB;;;;OAIG;IACH,IAAI,CAAC,EAAE,WAAW,GAAG,WAAW,CAAC;IACjC,oEAAoE;IACpE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gFAAgF;IAChF,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,SAAS,CAAC,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACpD,6FAA6F;IAC7F,MAAM,CAAC,EAAE,cAAc,CAAC,QAAQ,CAAC,CAAC;CACnC;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,eAAe,GAAG,cAAc,CAEtF;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,cAAc,GAAG,cAAc,CAEjE"}
@@ -1 +1 @@
1
- {"version":3,"file":"duplex-over-port.d.ts","sourceRoot":"","sources":["../src/duplex-over-port.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,MAAM,EAOZ,MAAM,6BAA6B,CAAC;AAIrC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGzD;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY,4BAA4B,CAAC;AActD,MAAM,WAAW,qBAAqB;IACpC;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6CAA6C;IAC7C,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;CACpC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,aAAa,EAAE,OAAO,GAAE,qBAA0B,GAAG,MAAM,CAE/F;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,aAAa,EACnB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,qBAA0B,GAClC,MAAM,IAAI,CA8BZ"}
1
+ {"version":3,"file":"duplex-over-port.d.ts","sourceRoot":"","sources":["../src/duplex-over-port.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,MAAM,EAOZ,MAAM,6BAA6B,CAAC;AAIrC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAIzD;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY,4BAA4B,CAAC;AActD,MAAM,WAAW,qBAAqB;IACpC;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6CAA6C;IAC7C,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;CACpC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,aAAa,EAAE,OAAO,GAAE,qBAA0B,GAAG,MAAM,CAE/F;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,aAAa,EACnB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,qBAA0B,GAClC,MAAM,IAAI,CA8BZ"}
package/dist/index.d.ts CHANGED
@@ -11,7 +11,8 @@ export * from "./listen-bidi.js";
11
11
  export * from "./listen-port.js";
12
12
  export * from "./message-target.js";
13
13
  export { DEFAULT_MAX_PORTS, MUX_CLOSED_MESSAGE, multiplexPort } from "./multiplex-port.js";
14
- export type { PortCodec, PortEnvelope, PortMux, PortMuxOptions } from "./port-types.js";
14
+ export { type PortSendState, portBufferedAmount, whenPortReady } from "./port-credit.js";
15
+ export type { OpenPortOptions, PortCodec, PortEnvelope, PortInfo, PortMux, PortMuxOptions, } from "./port-types.js";
15
16
  export * from "./recieve.js";
16
17
  export * from "./send.js";
17
18
  export { structuredCodec } from "./structured-codec.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,0BAA0B,EAAE,MAAM,mBAAmB,CAAC;AAC/D,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC;AACpC,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC3E,OAAO,EACL,OAAO,EACP,KAAK,MAAM,EACX,KAAK,eAAe,EACpB,QAAQ,EACR,SAAS,EACT,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,GACN,MAAM,oBAAoB,CAAC;AAC5B,cAAc,uBAAuB,CAAC;AACtC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAC3F,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACxF,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,cAAc,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,0BAA0B,EAAE,MAAM,mBAAmB,CAAC;AAC/D,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC;AACpC,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC3E,OAAO,EACL,OAAO,EACP,KAAK,MAAM,EACX,KAAK,eAAe,EACpB,QAAQ,EACR,SAAS,EACT,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,GACN,MAAM,oBAAoB,CAAC;AAC5B,cAAc,uBAAuB,CAAC;AACtC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAC3F,OAAO,EAAE,KAAK,aAAa,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACzF,YAAY,EACV,eAAe,EACf,SAAS,EACT,YAAY,EACZ,QAAQ,EACR,OAAO,EACP,cAAc,GACf,MAAM,iBAAiB,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,cAAc,wBAAwB,CAAC"}