@statewalker/webrun-streams 0.1.1 → 0.2.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.
Files changed (47) hide show
  1. package/README.md +87 -8
  2. package/dist/collect.d.ts +7 -0
  3. package/dist/collect.d.ts.map +1 -0
  4. package/dist/duplex.d.ts +52 -0
  5. package/dist/duplex.d.ts.map +1 -0
  6. package/dist/emulate-mux.d.ts +39 -0
  7. package/dist/emulate-mux.d.ts.map +1 -0
  8. package/dist/errors.d.ts +8 -0
  9. package/dist/errors.d.ts.map +1 -0
  10. package/dist/flow-control.d.ts +71 -0
  11. package/dist/flow-control.d.ts.map +1 -0
  12. package/dist/index.d.ts +16 -0
  13. package/dist/index.d.ts.map +1 -0
  14. package/dist/{index.mjs → index.js} +200 -52
  15. package/dist/jsonl.d.ts +5 -0
  16. package/dist/jsonl.d.ts.map +1 -0
  17. package/dist/lines.d.ts +5 -0
  18. package/dist/lines.d.ts.map +1 -0
  19. package/dist/map.d.ts +3 -0
  20. package/dist/map.d.ts.map +1 -0
  21. package/dist/new-async-generator.d.ts +70 -0
  22. package/dist/new-async-generator.d.ts.map +1 -0
  23. package/dist/normalize.d.ts +8 -0
  24. package/dist/normalize.d.ts.map +1 -0
  25. package/dist/readable-streams.d.ts +13 -0
  26. package/dist/readable-streams.d.ts.map +1 -0
  27. package/dist/recieve-iterator.d.ts +14 -0
  28. package/dist/recieve-iterator.d.ts.map +1 -0
  29. package/dist/send-iterator.d.ts +15 -0
  30. package/dist/send-iterator.d.ts.map +1 -0
  31. package/dist/text.d.ts +5 -0
  32. package/dist/text.d.ts.map +1 -0
  33. package/dist/to-chunks.d.ts +11 -0
  34. package/dist/to-chunks.d.ts.map +1 -0
  35. package/dist/uint32.d.ts +25 -0
  36. package/dist/uint32.d.ts.map +1 -0
  37. package/package.json +10 -5
  38. package/src/duplex.ts +59 -0
  39. package/src/emulate-mux.ts +98 -84
  40. package/src/flow-control.ts +146 -0
  41. package/src/index.ts +2 -0
  42. package/src/readable-streams.ts +49 -13
  43. package/src/uint32.ts +34 -0
  44. package/LICENSE +0 -21
  45. package/dist/index.d.mts +0 -244
  46. package/dist/index.d.mts.map +0 -1
  47. package/dist/index.mjs.map +0 -1
package/README.md CHANGED
@@ -17,6 +17,16 @@ Every higher-level package in the `webrun-*` family (and its consumers — scann
17
17
 
18
18
  The MessagePack codec that previously rode along here is split out to [`@statewalker/webrun-msgpack`](../webrun-msgpack) so consumers that don't need framing don't pull in `@ygoe/msgpack`.
19
19
 
20
+ ## Install
21
+
22
+ ```sh
23
+ npm install @statewalker/webrun-streams
24
+ ```
25
+
26
+ Zero runtime dependencies, zero peer dependencies. ESM only
27
+ (`"type": "module"`); runs in browsers, Node, Deno, Bun and Workers. This is the
28
+ foundation package — everything else in the workspace depends on it.
29
+
20
30
  ## How to use
21
31
 
22
32
  ```sh
@@ -239,14 +249,18 @@ const stop = serve(async function* handler(input) {
239
249
  | `side` | `"initiator"` | Id allocation: initiator uses even ids, responder odd. Pick one per peer so they cannot collide. |
240
250
  | `maxStreams` | `256` | Concurrent streams before new calls are refused. |
241
251
  | `mtu` | `65536` | Largest payload per DATA frame; bigger chunks are split. |
242
- | `maxStreamBuffer` | `8388608` | Inbound bytes one stream may hold for a consumer that has not drained them. Exceeding it tears down that stream alone. |
252
+ | `maxStreamBuffer` | `8388608` | The credit this side advertises to the peer, in bytes, and the hard cap on inbound bytes one stream may hold undrained. A peer that honours credit never reaches the cap; one that ignores it has that stream torn down. |
243
253
 
244
254
  ### Flow control
245
255
 
246
- One in-flight DATA frame per stream. The sender waits for an `ACK`, and the ACK
247
- is sent only once the consumer has pulled *past* that chunk — so a fast producer
248
- cannot run ahead of a slow consumer, and outbound is bounded to one `mtu` per
249
- stream even against a peer that never acknowledges.
256
+ Receiver-advertised credit. Each side puts its `maxStreamBuffer` in the frame it
257
+ opens with — `OPEN` for the caller, the `ACK` answering it for the responder —
258
+ and the sender may only send what it has been granted. Both sides start at zero,
259
+ so a caller pays one round trip per stream before its first DATA frame and none
260
+ thereafter. The receiver grants more once its consumer has actually drained,
261
+ batched at half the window and flushed as soon as its queue empties. A sender
262
+ therefore cannot overrun the receiver's buffer, and `maxStreamBuffer` bounds only
263
+ peers that ignore the protocol.
250
264
 
251
265
  Backpressure is **per-stream**, so a stalled stream does not block the others,
252
266
  and it applies symmetrically in both directions.
@@ -254,6 +268,10 @@ and it applies symmetrically in both directions.
254
268
  There is deliberately **no stall timeout**: a peer that never acknowledges
255
269
  blocks that producer indefinitely, exactly as a TCP receiver that never reads
256
270
  blocks its sender. `maxStreams` and `maxStreamBuffer` bound what that can cost.
271
+ The bound is per stream and there is no mux-wide budget, so the worst case is
272
+ `maxStreams × maxStreamBuffer` — 2 GiB at the defaults, against 16 MiB under the
273
+ one-frame-in-flight rule this replaced. Lower `maxStreamBuffer` if that matters
274
+ more than throughput.
257
275
 
258
276
  ### Behaviour on hostile input
259
277
 
@@ -263,6 +281,67 @@ rather than failing the connection — otherwise one malformed frame would tear
263
281
  down every stream sharing the mux. A stream that exceeds `maxStreamBuffer` is
264
282
  torn down on its own, with an error frame sent to the peer.
265
283
 
284
+ ## Exports
285
+
286
+ Everything is exported from the package root.
287
+
288
+ ### Seam types
289
+
290
+ | Export | Kind | Purpose |
291
+ | --- | --- | --- |
292
+ | `Duplex` | type | `(input) => AsyncGenerator<Uint8Array>` — one logical call. |
293
+ | `Connect<P>` | type | `(params) => Promise<{ call: Duplex; close() }>`. |
294
+ | `Serve<P>` | type | `(params, handler) => Promise<() => Promise<void>>`. |
295
+ | `ByteChannel` | type | `{ send, recv, closed, close }` — the minimum a transport must expose. |
296
+ | `ByteLike` | type | Accepted byte inputs before normalisation. |
297
+ | `emulateMux(channel, opts?)` | function | Multi-stream over a single `ByteChannel`. |
298
+ | `EmulateMuxOptions` | type | `maxStreams` (256), `mtu` (64 KiB), `maxStreamBuffer` (8 MiB), `side`. |
299
+ | `TransportClosedError` | class | Thrown when the transport closes with calls in flight. Catch via `instanceof` or `error.name`. |
300
+
301
+ The port multiplexing layer — `multiplexPort`, `PortMux`, `structuredCodec`,
302
+ `PortEnvelope` and the `MessageTarget` family of types — lives in
303
+ [`@statewalker/webrun-rpc`](../webrun-rpc#port-multiplexing), not here.
304
+
305
+ ### Credit
306
+
307
+ | Export | Kind | Purpose |
308
+ | --- | --- | --- |
309
+ | `newCreditLedger(initial?)` | function | Sender-side credit: `reserve(upTo)` waits for any credit and returns how much it got (`upTo` must be >= 1; less rejects with a `RangeError`), `grant(units)` releases waiters in order, `fail(err)` unwinds them. Starts at zero unless told otherwise. |
310
+ | `CreditLedger` | type | `{ available, reserve, grant, fail }`. |
311
+ | `newCreditGrantor(window, threshold?)` | function | Receiver-side: `consumed(units, queueEmpty)` returns the credit to hand back, batched at `threshold` (default half the window) and flushed once the queue empties. |
312
+ | `CreditGrantor` | type | `{ consumed(units, queueEmpty): number }`. |
313
+
314
+ The unit is whatever the caller counts. `emulateMux` counts bytes; a value-
315
+ oriented caller would count values. Nothing in this module interprets it.
316
+
317
+ ### Collectors and codecs
318
+
319
+ | Export | Purpose |
320
+ | --- | --- |
321
+ | `collect` / `collectBytes` / `collectString` | Drain an async iterable to an array / `Uint8Array` / `string`. |
322
+ | `encodeText` / `decodeText` | UTF-8 `string` ↔ `Uint8Array` streams. |
323
+ | `splitLines` / `joinLines` | Cross-chunk-safe line splitting and rejoining. |
324
+ | `encodeJsonl` / `decodeJsonl` | JSON values ↔ `\n`-delimited string stream. |
325
+ | `map` | Stream-map over an `AsyncIterable<T>`. |
326
+ | `toChunks` / `normalizeToUint8Array` | Coerce assorted byte-ish inputs into `Uint8Array` chunks. |
327
+
328
+ ### Iterator plumbing
329
+
330
+ | Export | Purpose |
331
+ | --- | --- |
332
+ | `newAsyncGenerator` | Backpressure-aware queue turning `next`/`done` callbacks into an async generator. |
333
+ | `sendIterator` / `recieveIterator` | Ship an async iterator across any transport. |
334
+ | `IteratorChunk` | type — the `{ done, value, error }` chunk envelope they exchange. |
335
+ | `ChunkSender` / `ChunkReceiver` / `ReceiverInstaller` | types — the transport-side callbacks those two are wired to. |
336
+ | `toReadableStream` / `fromReadableStream` | `AsyncIterator<Uint8Array>` ↔ WHATWG `ReadableStream<Uint8Array>`. |
337
+
338
+ ### Errors
339
+
340
+ | Export | Purpose |
341
+ | --- | --- |
342
+ | `serializeError` / `deserializeError` | Preserve `message`, `stack` and custom fields across JSON / structured-clone boundaries. |
343
+ | `SerializedError` | type — the wire shape those two produce and consume. |
344
+
266
345
  ## Internals
267
346
 
268
347
  ### `newAsyncGenerator` — backpressure queue
@@ -332,17 +411,17 @@ strict one-way converters: no queuing strategy tricks, no transform.
332
411
 
333
412
  **Zero runtime dependencies.**
334
413
 
335
- Dev: TypeScript, vitest, tsdown, rimraf, `@types/node`
414
+ Dev: TypeScript, vitest, rolldown, rimraf, `@types/node`
336
415
  (catalog versions from the monorepo root).
337
416
 
338
417
  ## Scripts
339
418
 
340
419
  ```sh
341
420
  pnpm test # vitest run
342
- pnpm run build # tsdown (publishes src + compiled dist)
421
+ pnpm run build # rolldown + tsc --emitDeclarationOnly (ships src + dist)
343
422
  pnpm lint # biome check
344
423
  ```
345
424
 
346
425
  ## License
347
426
 
348
- MIT © statewalker
427
+ MIT © statewalker — see [LICENSE](../../LICENSE).
@@ -0,0 +1,7 @@
1
+ /** Collect all items from an async iterable into an array. */
2
+ export declare function collect<T>(input: AsyncIterable<T>): Promise<T[]>;
3
+ /** Concatenate all Uint8Array chunks into a single Uint8Array. */
4
+ export declare function collectBytes(input: AsyncIterable<Uint8Array>): Promise<Uint8Array>;
5
+ /** Concatenate all string chunks into a single string. */
6
+ export declare function collectString(input: AsyncIterable<string>): Promise<string>;
7
+ //# sourceMappingURL=collect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collect.d.ts","sourceRoot":"","sources":["../src/collect.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,wBAAsB,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAItE;AAED,kEAAkE;AAClE,wBAAsB,YAAY,CAAC,KAAK,EAAE,aAAa,CAAC,UAAU,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,CAexF;AAED,0DAA0D;AAC1D,wBAAsB,aAAa,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAIjF"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * The transport seam every `webrun-streams-*` adapter and the conformance suite
3
+ * are written against.
4
+ *
5
+ * These types live here rather than beside an implementation on purpose: the
6
+ * emulated multiplexer that once declared them is scheduled for deletion, and a
7
+ * seam that disappears with its first implementation is not a seam.
8
+ */
9
+ /**
10
+ * Canonical seam for the webrun-streams transport family. A `Duplex` carries
11
+ * one logical call: caller emits an iterable of bytes as input, peer yields an
12
+ * async generator of bytes as output. Same shape on both sides — an in-process
13
+ * test can wire `const caller = handler` and run without any transport.
14
+ *
15
+ * Iterator semantics carry every signal:
16
+ * - Consumer `.return()` on the output → producer's `finally` runs.
17
+ * - Producer `throw` → consumer's `for await` throws.
18
+ * - Normal exhaustion on either side → matching end on the other side.
19
+ */
20
+ export type Duplex = (input: AsyncIterable<Uint8Array> | Iterable<Uint8Array>) => AsyncGenerator<Uint8Array>;
21
+ /**
22
+ * Adapter-side factory that stands up a transport connection and yields a
23
+ * caller `Duplex`. One `Connect` invocation owns one transport; each call
24
+ * to the resolved `call` opens a new sub-stream on it.
25
+ *
26
+ * A caller must either drain the returned generator or `.return()` it.
27
+ * Dropping the reference without doing either emits no observable signal:
28
+ * the abandoned consumer never acknowledges inbound data, so the peer's
29
+ * outbound pump blocks awaiting that acknowledgement, no end-of-stream is
30
+ * ever exchanged, and both peers hold the stream's slot open. There is no
31
+ * way for the transport to detect this — an unreferenced generator is not
32
+ * observable — so it is the consumer's obligation.
33
+ */
34
+ export type Connect<P> = (params: P) => Promise<{
35
+ call: Duplex;
36
+ close: () => Promise<void>;
37
+ }>;
38
+ /**
39
+ * Adapter-side factory that registers a handler `Duplex` against a transport.
40
+ * Returns an idempotent teardown.
41
+ */
42
+ export type Serve<P> = (params: P, handler: Duplex) => Promise<() => Promise<void>>;
43
+ /**
44
+ * Thrown by `emulateMux` and adapters when the underlying transport closes
45
+ * while one or more `Duplex` calls are in flight. Consumers can catch by
46
+ * `instanceof TransportClosedError` or by checking `error.name`.
47
+ */
48
+ export declare class TransportClosedError extends Error {
49
+ readonly name = "TransportClosedError";
50
+ constructor(message?: string);
51
+ }
52
+ //# sourceMappingURL=duplex.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"duplex.d.ts","sourceRoot":"","sources":["../src/duplex.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;;;;;;GAUG;AACH,MAAM,MAAM,MAAM,GAAG,CACnB,KAAK,EAAE,aAAa,CAAC,UAAU,CAAC,GAAG,QAAQ,CAAC,UAAU,CAAC,KACpD,cAAc,CAAC,UAAU,CAAC,CAAC;AAEhC;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,MAAM,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;AAEpF;;;;GAIG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,SAAkB,IAAI,0BAA0B;IAChD,YAAY,OAAO,SAAqB,EAEvC;CACF"}
@@ -0,0 +1,39 @@
1
+ import { type Duplex } from "./duplex.js";
2
+ /**
3
+ * The minimum a transport must expose to be wrapped by `emulateMux`. Inbound
4
+ * bytes are surfaced as an async iterable; outbound is imperative `send`. All
5
+ * five message-oriented transports (WebSocket, LiveKit data channel, PeerJS
6
+ * DataConnection, MessagePort, in-process pipe) match this shape after a thin
7
+ * wrapper.
8
+ */
9
+ export type ByteChannel = {
10
+ send(bytes: Uint8Array): void;
11
+ recv: AsyncIterable<Uint8Array>;
12
+ closed: Promise<void>;
13
+ close(): void;
14
+ };
15
+ export interface EmulateMuxOptions {
16
+ maxStreams?: number;
17
+ mtu?: number;
18
+ /**
19
+ * Cap on inbound bytes one stream may hold for a consumer that has not
20
+ * drained them. Exceeding it tears down that stream alone.
21
+ *
22
+ * It is also the credit this side advertises to the peer, so it must be at
23
+ * least 1 — a window of 0 authorises nothing and hangs the peer forever —
24
+ * and it travels in a uint32, so a value above `MAX_UINT32` (4 GiB - 1) is
25
+ * advertised as `MAX_UINT32`.
26
+ */
27
+ maxStreamBuffer?: number;
28
+ /**
29
+ * Stream-id allocation side. Initiator uses even ids (2, 4, …); responder
30
+ * uses odd ids (1, 3, …). Pick one per peer so allocations don't collide.
31
+ */
32
+ side?: "initiator" | "responder";
33
+ }
34
+ export declare function emulateMux(channel: ByteChannel, opts?: EmulateMuxOptions): {
35
+ call: Duplex;
36
+ serve: (handler: Duplex) => () => Promise<void>;
37
+ close: () => Promise<void>;
38
+ };
39
+ //# sourceMappingURL=emulate-mux.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emulate-mux.d.ts","sourceRoot":"","sources":["../src/emulate-mux.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAwB,MAAM,aAAa,CAAC;AAUhE;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,IAAI,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;IAChC,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,KAAK,IAAI,IAAI,CAAC;CACf,CAAC;AA4CF,MAAM,WAAW,iBAAiB;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;;;;;OAQG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,IAAI,CAAC,EAAE,WAAW,GAAG,WAAW,CAAC;CAClC;AAED,wBAAgB,UAAU,CACxB,OAAO,EAAE,WAAW,EACpB,IAAI,GAAE,iBAAsB,GAC3B;IACD,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B,CAuVA"}
@@ -0,0 +1,8 @@
1
+ export interface SerializedError {
2
+ message: string;
3
+ stack?: string;
4
+ [key: string]: unknown;
5
+ }
6
+ export declare function serializeError(error: unknown): SerializedError;
7
+ export declare function deserializeError(error: SerializedError | string): Error;
8
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,eAAe,CAY9D;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,GAAG,KAAK,CAGvE"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Credit-based flow control, as a pair of pure state machines with no I/O.
3
+ *
4
+ * The sender holds a {@link CreditLedger}: it reserves credit before it puts
5
+ * anything on the wire, and stalls at zero. The receiver holds a
6
+ * {@link CreditGrantor}: it counts what its consumer has actually drained and
7
+ * says when to hand the sender more.
8
+ *
9
+ * A sender therefore cannot overrun a receiver's buffer, because it was never
10
+ * granted permission to. That is the property a sender-side window cannot
11
+ * offer: the receiver's capacity is not knowable to the sender unless the
12
+ * receiver states it.
13
+ *
14
+ * **The unit is opaque.** This module never interprets the numbers it counts.
15
+ * `emulateMux` passes byte counts and advertises `maxStreamBuffer`; the RPC
16
+ * tier passes 1 per value and advertises a maximum in-flight value count.
17
+ * Nothing here depends on which.
18
+ */
19
+ export interface CreditLedger {
20
+ /** Units authorised by the peer and not yet reserved. */
21
+ readonly available: number;
22
+ /**
23
+ * Reserve up to `upTo` units, resolving with how many were actually
24
+ * granted — at least 1, never more than `upTo`. The caller sends exactly
25
+ * that much and calls `reserve` again for the rest.
26
+ *
27
+ * `upTo` must itself be at least 1; anything less rejects with a
28
+ * `RangeError` rather than resolving with 0, which would be a silent no-op
29
+ * that also consumed a waiter slot.
30
+ *
31
+ * Returning a partial amount rather than waiting for the full request is
32
+ * what makes the ledger deadlock-free: a peer that advertises less than
33
+ * one `upTo` still makes progress, one short piece at a time.
34
+ *
35
+ * Rejects if {@link fail} is called.
36
+ */
37
+ reserve(upTo: number): Promise<number>;
38
+ /** The peer authorised `units` more. */
39
+ grant(units: number): void;
40
+ /** Reject every pending and future reservation — transport or stream is gone. */
41
+ fail(err: Error): void;
42
+ }
43
+ export declare function newCreditLedger(initial?: number): CreditLedger;
44
+ export interface CreditGrantor {
45
+ /**
46
+ * Record that the consumer drained `units`, and whether the receive queue
47
+ * is now empty. Returns the credit to hand back to the peer, or `0` to stay
48
+ * silent and keep accumulating.
49
+ */
50
+ consumed(units: number, queueEmpty: boolean): number;
51
+ }
52
+ /**
53
+ * Grants are batched: replenishing on every chunk while the receiver is
54
+ * behind would reinvent the per-frame ACK this change exists to remove.
55
+ * `threshold` is the fraction of the window that must drain before a grant is
56
+ * emitted.
57
+ *
58
+ * The batch is flushed unconditionally once the receive queue is empty, even
59
+ * below the threshold, so the receiver never sits on credit it owes. Note what
60
+ * this is and is not: paired with a {@link CreditLedger}, a sender blocks only
61
+ * at *exactly* zero credit, and at that point the receiver holds the entire
62
+ * window as `pending` — above any threshold at or below the whole window — so
63
+ * the threshold alone cannot deadlock that pairing. The flush is what keeps
64
+ * that from being an argument about a global accounting identity: it is
65
+ * locally decidable from one boolean, and it returns owed credit now rather
66
+ * than at the next threshold crossing. It costs an extra frame only when the
67
+ * consumer is keeping pace, which is exactly when the sender is not blocked
68
+ * and the frame is cheap.
69
+ */
70
+ export declare function newCreditGrantor(window: number, threshold?: number): CreditGrantor;
71
+ //# sourceMappingURL=flow-control.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flow-control.d.ts","sourceRoot":"","sources":["../src/flow-control.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,MAAM,WAAW,YAAY;IAC3B,yDAAyD;IACzD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACvC,wCAAwC;IACxC,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,iFAAiF;IACjF,IAAI,CAAC,GAAG,EAAE,KAAK,GAAG,IAAI,CAAC;CACxB;AAQD,wBAAgB,eAAe,CAAC,OAAO,SAAI,GAAG,YAAY,CAqDzD;AAED,MAAM,WAAW,aAAa;IAC5B;;;;OAIG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,GAAG,MAAM,CAAC;CACtD;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,SAAM,GAAG,aAAa,CAa/E"}
@@ -0,0 +1,16 @@
1
+ export * from "./collect.js";
2
+ export * from "./duplex.js";
3
+ export * from "./emulate-mux.js";
4
+ export * from "./errors.js";
5
+ export * from "./flow-control.js";
6
+ export * from "./jsonl.js";
7
+ export * from "./lines.js";
8
+ export * from "./map.js";
9
+ export * from "./new-async-generator.js";
10
+ export * from "./normalize.js";
11
+ export * from "./readable-streams.js";
12
+ export * from "./recieve-iterator.js";
13
+ export * from "./send-iterator.js";
14
+ export * from "./text.js";
15
+ export * from "./to-chunks.js";
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,0BAA0B,CAAC;AACzC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,WAAW,CAAC;AAC1B,cAAc,gBAAgB,CAAC"}