@zlink-systems/stream-connector 0.25.0 → 0.27.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.
@@ -1,5 +1,6 @@
1
1
  import type { ZlinkStreamCompression, ZlinkStreamDispatchMode, ZlinkStreamTransport } from './ZlinkStreamEnums';
2
2
  import type { ZlinkStreamEncodedPayload } from './ZlinkStreamModels';
3
+ export declare const ZLINK_STREAM_DEFAULT_PAYLOAD_BYTES: number;
3
4
  export interface ZlinkStreamConnectorOptions {
4
5
  readonly endpoint: string;
5
6
  readonly codec?: ZlinkStreamPayloadCodec;
@@ -1,3 +1,4 @@
1
+ export { ZlinkStreamMessageKind, ZlinkStreamHeaderFlags } from '@zlink-systems/stream-wire';
1
2
  export declare enum ZlinkStreamTransport {
2
3
  WebSocket = "webSocket",
3
4
  WebSocketSecure = "webSocketSecure"
@@ -11,23 +12,7 @@ export declare enum ZlinkStreamDispatchMode {
11
12
  Manual = "manual",
12
13
  Immediate = "immediate"
13
14
  }
14
- export declare enum ZlinkStreamMessageKind {
15
- Send = 1,
16
- Request = 2,
17
- Response = 3,
18
- Error = 4,
19
- Control = 5
20
- }
21
- export declare enum ZlinkStreamHeaderFlags {
22
- None = 0,
23
- HasRequestSeq = 1,
24
- HasMetadata = 2,
25
- PayloadCompressed = 4,
26
- HasCorrelationId = 8,
27
- HasFlowId = 16,
28
- HasActorSlot = 32
29
- }
30
- export type ZlinkStreamCloseReason = 'ClientClose' | 'IdleTimeout' | 'HeartbeatTimeout' | 'ServerDrain' | 'ProtocolError' | 'TransportError';
15
+ export type { ZlinkStreamCloseReason } from '@zlink-systems/stream-wire';
31
16
  export declare enum ZlinkStreamErrorCode {
32
17
  Disconnected = "disconnected",
33
18
  ConfigurationError = "configurationError",
@@ -39,6 +24,7 @@ export declare enum ZlinkStreamErrorCode {
39
24
  SendFailed = "sendFailed",
40
25
  CompressionFailed = "compressionFailed",
41
26
  DecompressionFailed = "decompressionFailed",
27
+ TlsValidationFailed = "tlsValidationFailed",
42
28
  UserCallbackFailed = "userCallbackFailed",
43
29
  RemoteError = "remoteError"
44
30
  }
@@ -1,6 +1,6 @@
1
1
  export { ZlinkStreamTransport, ZlinkStreamCodec, ZlinkStreamCompression, ZlinkStreamDispatchMode, ZlinkStreamMessageKind, ZlinkStreamHeaderFlags, ZlinkStreamErrorCode, ZlinkStreamConnectionState } from './ZlinkStreamEnums';
2
2
  export type { ZlinkStreamCloseReason } from './ZlinkStreamEnums';
3
- export * from './ZlinkStreamConnectorOptions';
3
+ export type { ZlinkStreamConnectorOptions, ZlinkStreamHeartbeatOptions, ZlinkStreamReconnectOptions, ZlinkStreamPacketNameResolver, ZlinkStreamPayloadCodec, ZlinkStreamCompressionCodec, ZlinkStreamTransportFactory, ZlinkStreamConnection, RequiredZlinkStreamConnectorOptions } from './ZlinkStreamConnectorOptions';
4
4
  export * from './ZlinkStreamInterfaces';
5
5
  export * from './ZlinkStreamMetadata';
6
6
  export type { ZlinkStreamEncodedPayload, ZlinkStreamMessage, ZlinkStreamRequestSendingContext, ZlinkStreamReplyReceivedContext, ZlinkStreamError, ZlinkStreamConnectionStateChanged, ZlinkStreamResult, ZlinkStreamResultOf } from './ZlinkStreamModels';
@@ -19,8 +19,9 @@ export declare class ZlinkStreamSendBuilder implements ZlinkStreamSendCall {
19
19
  export declare class ZlinkStreamRequestBuilder implements ZlinkStreamRequestCall {
20
20
  private readonly connector;
21
21
  private readonly payload;
22
+ private readonly enqueueCallback;
22
23
  private readonly state;
23
- constructor(connector: ZlinkStreamConnectorSubmitter, name: string | undefined, payload: ZlinkStreamEncodedPayload, actorSlot?: number, validateActor?: () => void);
24
+ constructor(connector: ZlinkStreamConnectorSubmitter, name: string | undefined, payload: ZlinkStreamEncodedPayload, enqueueCallback: (callback: () => void) => void, actorSlot?: number, validateActor?: () => void);
24
25
  packetName(name: string): this;
25
26
  metadata(key: string, value: string): this;
26
27
  metadata(metadata: ZlinkStreamMetadata): this;
@@ -1,7 +1,2 @@
1
- import type { ZlinkStreamCloseReason } from '../../Contracts';
2
- export declare const ZLINK_SESSION_CLOSING = "session-closing";
3
- export declare function decodeSessionClosing(payload: Uint8Array): {
4
- readonly closeReason: ZlinkStreamCloseReason;
5
- readonly diagnostic?: string;
6
- };
7
- export declare function encodeSessionClosing(reason: ZlinkStreamCloseReason, diagnostic?: string): Uint8Array;
1
+ export { decodeStreamWireSessionClosing as decodeSessionClosing } from '@zlink-systems/stream-wire';
2
+ export declare const ZLINK_SESSION_CLOSING: "session-closing";
@@ -1,8 +1,7 @@
1
- import type { RequiredZlinkStreamConnectorOptions, ZlinkStreamEncodedPayload, ZlinkStreamMetadata } from '../../Contracts';
2
- import { ZlinkStreamMessageKind } from '../../Contracts';
1
+ import { type RequiredZlinkStreamConnectorOptions, type ZlinkStreamEncodedPayload, type ZlinkStreamMetadata, ZlinkStreamMessageKind } from '../../Contracts';
3
2
  import type { ZlinkStreamHeader } from '../../Contracts/ZlinkStreamModels';
4
- export declare const ZLINK_STREAM_HEARTBEAT_PING = "$zlink.heartbeat.ping";
5
- export declare const ZLINK_STREAM_HEARTBEAT_PONG = "$zlink.heartbeat.pong";
3
+ export declare const ZLINK_STREAM_HEARTBEAT_PING: "$zlink.heartbeat.ping";
4
+ export declare const ZLINK_STREAM_HEARTBEAT_PONG: "$zlink.heartbeat.pong";
6
5
  export declare class ZlinkStreamFrameProtocol {
7
6
  private readonly options;
8
7
  constructor(options: RequiredZlinkStreamConnectorOptions);
@@ -1,7 +1,5 @@
1
1
  import { ZlinkStreamMetadata } from '../../Contracts';
2
- export declare const ZLINK_STREAM_MAX_METADATA_BYTES = 1024;
2
+ export { ZLINK_STREAM_MAX_METADATA_BYTES } from '@zlink-systems/stream-wire';
3
3
  export declare class ZlinkStreamMetadataCodec {
4
4
  static size(metadata: ZlinkStreamMetadata): number;
5
- static write(metadata: ZlinkStreamMetadata, destination: Uint8Array): void;
6
- static decode(metadata: Uint8Array): ZlinkStreamMetadata;
7
5
  }
@@ -1,5 +1,4 @@
1
- import { ZlinkStreamConnection, ZlinkStreamTransportFactory } from '../../Contracts';
2
- import type { RequiredZlinkStreamConnectorOptions } from '../../Contracts';
1
+ import { type RequiredZlinkStreamConnectorOptions, ZlinkStreamConnection, ZlinkStreamTransportFactory } from '../../Contracts';
3
2
  interface BrowserWebSocketEventMap {
4
3
  open: unknown;
5
4
  close: unknown;
@@ -31,6 +30,11 @@ export declare class BrowserWebSocketConnection implements ZlinkStreamConnection
31
30
  constructor(socket: BrowserWebSocket);
32
31
  write(frame: Uint8Array, signal?: AbortSignal): Promise<void>;
33
32
  read(signal?: AbortSignal): Promise<Uint8Array | undefined>;
33
+ /**
34
+ * Spec stream-connector 32 §7: closing does not wait for the peer to read or
35
+ * answer. `WebSocket.close` sends the close frame after the data already
36
+ * handed to `send`, so a frame whose write completed is not torn.
37
+ */
34
38
  close(signal?: AbortSignal): Promise<void>;
35
39
  private readonly onMessage;
36
40
  private readonly onClose;
@@ -1,6 +1,6 @@
1
- import type { Disposable, ZlinkStreamActor, ZlinkStreamEncodedPayload, ZlinkStreamMessage, ZlinkStreamRequestCall, ZlinkStreamSendCall } from '../Contracts';
2
- import type { ZlinkStreamReceivedMessages } from './ZlinkStreamReceivedMessages';
1
+ import { type Disposable, type ZlinkStreamActor, type ZlinkStreamEncodedPayload, type ZlinkStreamMessage, type ZlinkStreamRequestCall, type ZlinkStreamSendCall } from '../Contracts';
3
2
  import type { ZlinkStreamConnectorEvents } from './ZlinkStreamConnectorEvents';
3
+ import type { ZlinkStreamReceivedMessages } from './ZlinkStreamReceivedMessages';
4
4
  export declare const zlinkStreamActorBinding: unique symbol;
5
5
  interface ActorConnector {
6
6
  sendForActor(actor: DefaultZlinkStreamActor, payload: unknown, messageType?: Function): ZlinkStreamSendCall;
@@ -26,7 +26,6 @@ export declare class ZlinkStreamActors {
26
26
  private readonly events;
27
27
  private readonly bySlot;
28
28
  private readonly byId;
29
- private readonly issued;
30
29
  private readonly boundHandlers;
31
30
  private readonly unboundHandlers;
32
31
  constructor(connector: ActorConnector, receivedMessages: ZlinkStreamReceivedMessages, events: ZlinkStreamConnectorEvents);
@@ -40,6 +39,5 @@ export declare class ZlinkStreamActors {
40
39
  private bind;
41
40
  private unbind;
42
41
  private queue;
43
- private invoke;
44
42
  }
45
43
  export {};
@@ -1,8 +1,8 @@
1
1
  import { Disposable, RequiredZlinkStreamConnectorOptions, ZlinkStreamConnectionState, ZlinkStreamConnectionStateChanged, ZlinkStreamConnector, ZlinkStreamConnectorOptions, ZlinkStreamEncodedPayload, ZlinkStreamError, ZlinkStreamExpectNoneCall, ZlinkStreamMessage, ZlinkStreamRequestSendingContext, ZlinkStreamReplyReceivedContext, ZlinkStreamMessageKind, ZlinkStreamMetadata, ZlinkStreamRequestCall, ZlinkStreamActor, ZlinkStreamSendCall, ZlinkStreamSequenceCall, ZlinkStreamWaitCall } from '../Contracts';
2
2
  import { DefaultZlinkStreamActor } from './ZlinkStreamActors';
3
3
  export declare class DefaultZlinkStreamConnector implements ZlinkStreamConnector {
4
- static readonly heartbeatPingName = "$zlink.heartbeat.ping";
5
- static readonly heartbeatPongName = "$zlink.heartbeat.pong";
4
+ static readonly heartbeatPingName: "$zlink.heartbeat.ping";
5
+ static readonly heartbeatPongName: "$zlink.heartbeat.pong";
6
6
  private readonly receivedMessages;
7
7
  private readonly lifecycle;
8
8
  private readonly events;
@@ -16,7 +16,7 @@ export declare class DefaultZlinkStreamConnector implements ZlinkStreamConnector
16
16
  readonly options: RequiredZlinkStreamConnectorOptions;
17
17
  constructor(options: ZlinkStreamConnectorOptions);
18
18
  get isConnected(): boolean;
19
- get closeReason(): import("..").ZlinkStreamCloseReason | undefined;
19
+ get closeReason(): "ClientClose" | "IdleTimeout" | "HeartbeatTimeout" | "ServerDrain" | "ProtocolError" | "TransportError" | undefined;
20
20
  get state(): ZlinkStreamConnectionState;
21
21
  get pendingDispatchCount(): number;
22
22
  get actors(): readonly ZlinkStreamActor[];
@@ -71,7 +71,7 @@ export declare class DefaultZlinkStreamConnector implements ZlinkStreamConnector
71
71
  private encodePayload;
72
72
  private decodePayload;
73
73
  private decodeWaitPayload;
74
- sendEncoded(kind: ZlinkStreamMessageKind, name: string, payload: ZlinkStreamEncodedPayload, metadata: ZlinkStreamMetadata, compress: boolean, requestSeq: bigint | undefined, signal?: AbortSignal, correlationId?: string, actorSlot?: number): Promise<void>;
74
+ sendEncoded(kind: ZlinkStreamMessageKind, name: string, payload: ZlinkStreamEncodedPayload, metadata: ZlinkStreamMetadata, compress: boolean, requestSeq: bigint | undefined, signal?: AbortSignal, correlationId?: string, actorSlot?: number, expiry?: Promise<unknown>, onAccepted?: () => void): Promise<void>;
75
75
  /**
76
76
  * Per-connector monotonic correlation id (hex). The client generates it on each request
77
77
  * and the server echoes it back on the reply.
@@ -1,13 +1,28 @@
1
1
  import type { Disposable, ZlinkStreamConnectionStateChanged, ZlinkStreamError } from '../Contracts';
2
2
  export declare class ZlinkStreamConnectorEvents {
3
+ private readonly enqueueCallback;
4
+ /**
5
+ * @param enqueueCallback Queues a callback that calls the number of handlers
6
+ * `callbacks` reports for the handlers registered at that moment.
7
+ */
8
+ constructor(enqueueCallback: (callback: () => void, callbacks: () => number) => void);
3
9
  private readonly errorHandlers;
4
10
  private readonly disconnectedHandlers;
5
11
  private readonly stateHandlers;
6
12
  onError(handler: (error: ZlinkStreamError, signal?: AbortSignal) => Promise<void> | void): Disposable;
7
13
  onDisconnected(handler: (signal?: AbortSignal) => Promise<void> | void): Disposable;
8
14
  onStateChanged(handler: (change: ZlinkStreamConnectionStateChanged, signal?: AbortSignal) => Promise<void> | void): Disposable;
9
- publishError(error: ZlinkStreamError, signal?: AbortSignal): Promise<void>;
10
- publishDisconnected(signal?: AbortSignal): Promise<void>;
11
- publishStateChanged(change: ZlinkStreamConnectionStateChanged, signal?: AbortSignal): Promise<void>;
15
+ publishError(error: ZlinkStreamError, signal?: AbortSignal): void;
16
+ publishDisconnected(signal?: AbortSignal): void;
17
+ publishStateChanged(change: ZlinkStreamConnectionStateChanged, signal?: AbortSignal): void;
18
+ /**
19
+ * Spec stream-connector 32 §7: the connector runs a registered callback and
20
+ * does not wait for it to finish. A thrown or rejected failure reaches the
21
+ * error handlers as `UserCallbackFailed`.
22
+ */
23
+ runUserCallback(run: () => Promise<void> | void, failureMessage: string, signal?: AbortSignal): void;
12
24
  private publish;
25
+ private reportFailure;
26
+ private reportToRemaining;
27
+ private invoke;
13
28
  }
@@ -1,12 +1,10 @@
1
- import type { RequiredZlinkStreamConnectorOptions, ZlinkStreamConnection } from '../Contracts';
2
- import { ZlinkStreamConnectionState } from '../Contracts';
3
- import type { ZlinkStreamCloseReason } from '../Contracts';
1
+ import { type RequiredZlinkStreamConnectorOptions, type ZlinkStreamCloseReason, type ZlinkStreamConnection, ZlinkStreamConnectionState } from '../Contracts';
2
+ import type { ZlinkStreamActors } from './ZlinkStreamActors';
4
3
  import type { ZlinkStreamConnectorEvents } from './ZlinkStreamConnectorEvents';
5
4
  import type { ZlinkStreamFrameSender } from './ZlinkStreamFrameSender';
6
5
  import type { ZlinkStreamPendingRequests } from './ZlinkStreamPendingRequests';
7
- import type { ZlinkStreamReceiveDispatcher } from './ZlinkStreamReceiveDispatcher';
6
+ import { type ZlinkStreamReceiveDispatcher } from './ZlinkStreamReceiveDispatcher';
8
7
  import type { ZlinkStreamReceivedMessages } from './ZlinkStreamReceivedMessages';
9
- import type { ZlinkStreamActors } from './ZlinkStreamActors';
10
8
  export declare class ZlinkStreamConnectorLifecycle {
11
9
  private readonly options;
12
10
  private readonly pendingRequests;
@@ -27,17 +25,30 @@ export declare class ZlinkStreamConnectorLifecycle {
27
25
  private lastInboundAt;
28
26
  private closeTask;
29
27
  private connectTask;
28
+ private connectAbort;
30
29
  private disconnectTask;
31
30
  private closeRequested;
32
31
  private disconnectedPublished;
33
32
  private closeReasonValue?;
34
- private lateConnectCleanupError;
35
33
  constructor(options: RequiredZlinkStreamConnectorOptions, pendingRequests: ZlinkStreamPendingRequests, frameSender: ZlinkStreamFrameSender, receiveDispatcher: ZlinkStreamReceiveDispatcher, receivedMessages: ZlinkStreamReceivedMessages, actors: ZlinkStreamActors, events: ZlinkStreamConnectorEvents);
36
34
  get isConnected(): boolean;
37
35
  get state(): ZlinkStreamConnectionState;
38
36
  get closeReason(): ZlinkStreamCloseReason | undefined;
39
37
  connect(signal?: AbortSignal): Promise<void>;
38
+ /**
39
+ * Spec stream-connector 32 §7: close does not wait for a connect attempt or a
40
+ * reconnect delay to run its course. The attempts listen to one controller
41
+ * the lifecycle owns; close aborts it, and the caller's signal is forwarded
42
+ * to it.
43
+ */
40
44
  private connectOnce;
45
+ /**
46
+ * Spec stream-connector 32 §7: a `close` called outside the registered
47
+ * handlers and callbacks returns once the close work has ended. One called
48
+ * from inside them returns right after starting it; the result goes to the
49
+ * outside caller, so a callback never waits for the close of the path that
50
+ * is running it.
51
+ */
41
52
  close(signal?: AbortSignal): Promise<void>;
42
53
  serverClosing(reason: ZlinkStreamCloseReason): Promise<void>;
43
54
  private closeOnce;
@@ -64,10 +75,23 @@ export declare class ZlinkStreamConnectorLifecycle {
64
75
  private releaseReceiveLoopSettled;
65
76
  private shouldContinueReceiveLoop;
66
77
  private runHeartbeatTick;
78
+ /**
79
+ * @param reason Given only where the reason is not read from `error`: a
80
+ * server `session-closing` and the heartbeat timeout. Every other ending
81
+ * takes it from {@link closeReasonFor}.
82
+ */
67
83
  private disconnectForTransportFailure;
68
84
  private isCurrentConnection;
69
- /** Transport teardown only — no application callback runs from here. */
85
+ /**
86
+ * Ends the current connection, for close and for transport loss alike. No
87
+ * application callback runs before terminal operations settle. Spec stream-connector 32 §7 and §9:
88
+ * every operation the ending connection fails (the frames it has not
89
+ * written, the one it is writing and the pending requests) fails with
90
+ * `Disconnected`, whatever ended it; the cause stays in the close reason.
91
+ * The transport is closed without waiting for the frames.
92
+ */
70
93
  private tearDownConnection;
94
+ private closeTransport;
71
95
  /**
72
96
  * Runs once the teardown promise has settled, so a handler reached from here
73
97
  * may call `connect` without waiting for a task its own caller still holds.
@@ -78,35 +102,13 @@ export declare class ZlinkStreamConnectorLifecycle {
78
102
  */
79
103
  private announceDisconnect;
80
104
  private shouldReconnect;
81
- private claimDisconnectedPublish;
82
- private publishDisconnectedOnce;
83
105
  /**
84
- * Spec stream-connector 32 §7: the connector runs the registered handler, it
85
- * does not wait for it to finish. `close` returns once its own work is done —
86
- * the drain, the transport close, the pending requests — having run the
87
- * disconnect handler but without looking at whether that handler has ended.
88
- *
89
- * Starting the publish without awaiting it still runs every handler right
90
- * here: an `async` function body runs synchronously up to its first `await`,
91
- * and `publishDisconnected` reaches each handler before that point. So the
92
- * handler has run by the time `close` returns, which is what the spec asks
93
- * for, while a handler that calls `close` no longer waits for the very
94
- * `closeTask` it is running inside. Java and C++ hand the handler to a queue
95
- * and return the same way.
96
- *
97
- * `claimDisconnectedPublish` is taken by the same call and before any await,
98
- * so deferring the completion never turns the one notification into two.
99
- *
100
- * Nothing awaits the promise, so a rejection would reach the process as an
101
- * unhandled rejection and kill it. Handler failures are already contained
102
- * where they were before this call stopped waiting — the `Promise.allSettled`
103
- * in `publishDisconnected` — and this `catch` covers what is left rather than
104
- * reporting the same failure a second time on the error surface.
106
+ * Spec stream-connector 32 §6 and §7: one disconnect notification per
107
+ * lifecycle event, handed to the dispatch queue. The connector does not wait
108
+ * for the handler; `Manual` runs it when the application pumps dispatch.
109
+ * The flag is tested and set synchronously, so concurrent callers for the
110
+ * same event claim it once.
105
111
  */
106
- private publishDisconnectedWithoutWaiting;
107
- private queueDisconnected;
108
- private queueState;
112
+ private publishDisconnected;
109
113
  private setState;
110
- private transitionState;
111
- private publishStateChange;
112
114
  }
@@ -1,4 +1,5 @@
1
1
  import { RequiredZlinkStreamConnectorOptions, ZlinkStreamConnectorOptions, ZlinkStreamPacketNameResolver } from '../Contracts';
2
+ export { ZLINK_STREAM_DEFAULT_PAYLOAD_BYTES as ZLINK_STREAM_DEFAULT_PAYLOAD_SIZE } from '../Contracts/ZlinkStreamConnectorOptions';
2
3
  export declare function normalizeOptions(options: ZlinkStreamConnectorOptions, defaultTransportFactory: RequiredZlinkStreamConnectorOptions['transportFactory']): RequiredZlinkStreamConnectorOptions;
3
4
  /**
4
5
  * Spec stream-connector 32 §5 and the TypeScript projection §4: a payload type
@@ -1,11 +1,27 @@
1
- import type { ZlinkStreamConnection, ZlinkStreamEncodedPayload, ZlinkStreamMetadata, ZlinkStreamMessageKind } from '../Contracts';
1
+ import type { ZlinkStreamConnection, ZlinkStreamEncodedPayload, ZlinkStreamError, ZlinkStreamMetadata, ZlinkStreamMessageKind } from '../Contracts';
2
2
  import type { ZlinkStreamFrameProtocol } from './Protocol/ZlinkStreamFrameProtocol';
3
3
  export declare class ZlinkStreamFrameSender {
4
4
  private readonly protocol;
5
- private readonly pendingWrites;
5
+ private readonly queues;
6
6
  constructor(protocol: ZlinkStreamFrameProtocol);
7
- send(connection: ZlinkStreamConnection, kind: ZlinkStreamMessageKind, name: string, payload: ZlinkStreamEncodedPayload, metadata: ZlinkStreamMetadata, compress: boolean, requestSeq: bigint | undefined, signal?: AbortSignal, correlationId?: string, actorSlot?: number): Promise<void>;
8
- sendControl(connection: ZlinkStreamConnection, name: string, signal?: AbortSignal): Promise<void>;
9
- drain(signal?: AbortSignal): Promise<void>;
7
+ send(connection: ZlinkStreamConnection, kind: ZlinkStreamMessageKind, name: string, payload: ZlinkStreamEncodedPayload, metadata: ZlinkStreamMetadata, compress: boolean, requestSeq: bigint | undefined, signal?: AbortSignal, correlationId?: string, actorSlot?: number, expiry?: Promise<unknown>, onAccepted?: () => void): Promise<void>;
8
+ /**
9
+ * Writes a control frame (heartbeat ping or pong). A control frame belongs to
10
+ * no operation: its write failure ends the connection through the write
11
+ * queue like any other write (spec stream-connector 32 §9), and a connection
12
+ * that has already ended does not write it. The promise settles when the
13
+ * write has ended either way.
14
+ */
15
+ sendControl(connection: ZlinkStreamConnection, name: string): Promise<void>;
16
+ /**
17
+ * Gives a connection that has just been established its own write queue.
18
+ * `writeFailed` ends that connection when one of its transport writes fails.
19
+ */
20
+ open(connection: ZlinkStreamConnection, writeFailed: (error: ZlinkStreamError) => void): void;
21
+ /**
22
+ * Ends the write queue of a connection that has ended, by close and by
23
+ * transport loss alike. Every operation still in it fails with `error`.
24
+ */
25
+ failUnwritten(connection: ZlinkStreamConnection, error: unknown): void;
10
26
  private write;
11
27
  }
@@ -2,13 +2,13 @@ import { ZlinkStreamEncodedPayload, ZlinkStreamError, ZlinkStreamMessage, ZlinkS
2
2
  export interface PendingZlinkStreamRequest {
3
3
  readonly requestSeq: bigint;
4
4
  readonly promise: Promise<ZlinkStreamMessage<ZlinkStreamEncodedPayload>>;
5
+ startTimeout(): void;
5
6
  }
6
7
  export declare class ZlinkStreamPendingRequests {
7
8
  private nextRequestSeq;
8
9
  private readonly active;
9
- get count(): number;
10
10
  create(packetName: string, timeoutMs: number): PendingZlinkStreamRequest;
11
- resolve(requestSeq: bigint, value: ZlinkStreamEncodedPayload, metadata: ZlinkStreamMetadata): boolean;
11
+ resolve(requestSeq: bigint, value: () => ZlinkStreamEncodedPayload, metadata: ZlinkStreamMetadata): boolean;
12
12
  reject(requestSeq: bigint, error: ZlinkStreamError): boolean;
13
13
  cancel(requestSeq: bigint): void;
14
14
  failAll(error: ZlinkStreamError): void;
@@ -1,4 +1,4 @@
1
- import type { ZlinkStreamConnection } from '../Contracts';
1
+ import type { ZlinkStreamConnection, ZlinkStreamError } from '../Contracts';
2
2
  import type { ZlinkStreamFrameProtocol } from './Protocol/ZlinkStreamFrameProtocol';
3
3
  import type { ZlinkStreamConnectorEvents } from './ZlinkStreamConnectorEvents';
4
4
  import type { ZlinkStreamFrameSender } from './ZlinkStreamFrameSender';
@@ -6,6 +6,18 @@ import type { ZlinkStreamPendingRequests } from './ZlinkStreamPendingRequests';
6
6
  import type { ZlinkStreamReceivedMessages } from './ZlinkStreamReceivedMessages';
7
7
  import type { ZlinkStreamCloseReason } from '../Contracts';
8
8
  import { type ZlinkStreamActors } from './ZlinkStreamActors';
9
+ /**
10
+ * Spec stream-connector 32 §9: the one mapping from the error that ended a
11
+ * connection to its close reason. A frame or header the connector cannot
12
+ * decode and a payload over the receive limit are protocol violations; every
13
+ * other failure — a transport read or write — is a transport error.
14
+ */
15
+ export declare function closeReasonFor(error: ZlinkStreamError): ZlinkStreamCloseReason;
16
+ /** A receive failure that ends the connection; {@link closeReasonFor} names its reason. */
17
+ export declare class ZlinkStreamConnectionEnd extends Error {
18
+ readonly error: ZlinkStreamError;
19
+ constructor(error: ZlinkStreamError);
20
+ }
9
21
  export interface ZlinkStreamReceiveResult {
10
22
  readonly available: boolean;
11
23
  readonly inbound: boolean;
@@ -28,11 +40,15 @@ export declare class ZlinkStreamReceiveDispatcher {
28
40
  * the recheck the rest of a dead connection's batch lands on the new
29
41
  * connection's state, and the §10 arrival counts, which start at 0 when a
30
42
  * connection is established, take the stale frames on top.
31
- * @param connectionForSend Resolves the connection a reply belongs on at the
32
- * moment it is written. The captured `connection` is the one the batch was
33
- * read from, which a reconnect may already have replaced.
34
43
  */
35
- readAndDispatch(connection: ZlinkStreamConnection | undefined, signal?: AbortSignal, isCurrent?: () => boolean, connectionForSend?: () => ZlinkStreamConnection): Promise<ZlinkStreamReceiveResult>;
44
+ readAndDispatch(connection: ZlinkStreamConnection | undefined, signal?: AbortSignal, isCurrent?: () => boolean): Promise<ZlinkStreamReceiveResult>;
45
+ /**
46
+ * Spec stream-connector 32 §4.7 and §9: a decompressed payload over the
47
+ * receive limit is `FrameTooLarge` and ends the connection as a protocol
48
+ * error, like a wire payload over the limit. A payload that does not
49
+ * decompress fails only its packet.
50
+ */
51
+ private decodePayload;
36
52
  private dispatch;
37
53
  private dispatchControl;
38
54
  }
@@ -1,5 +1,6 @@
1
1
  import { Disposable, ZlinkStreamEncodedPayload, ZlinkStreamMessage } from '../Contracts';
2
2
  import type { ZlinkStreamConnectorEvents } from './ZlinkStreamConnectorEvents';
3
+ import { type DefaultZlinkStreamActor } from './ZlinkStreamActors';
3
4
  type EncodedMessageHandler = (message: ZlinkStreamMessage<ZlinkStreamEncodedPayload>, signal?: AbortSignal) => Promise<void> | void;
4
5
  /**
5
6
  * A wait surface (`waitFor`, `expectNone`, `waitForSequence`) reading the queue
@@ -13,9 +14,9 @@ export declare class ZlinkStreamReceivedMessages {
13
14
  private readonly handlers;
14
15
  private readonly observers;
15
16
  private readonly queue;
17
+ private readonly deliverable;
16
18
  private queueHead;
17
19
  private queuedCount;
18
- private drainTask;
19
20
  private draining;
20
21
  private readonly receivedCounts;
21
22
  /**
@@ -25,7 +26,11 @@ export declare class ZlinkStreamReceivedMessages {
25
26
  * queue in both modes, so they never depend on this flag.
26
27
  */
27
28
  constructor(events: ZlinkStreamConnectorEvents, deliverOnArrival: boolean);
28
- on(name: string, handler: EncodedMessageHandler): Disposable;
29
+ /**
30
+ * @param actor The Actor handle that registers the handler, if any. Its
31
+ * handler receives only that Actor's packets.
32
+ */
33
+ on(name: string, handler: EncodedMessageHandler, actor?: DefaultZlinkStreamActor): Disposable;
29
34
  /**
30
35
  * Registers a wait surface over the receive queue. Spec stream-connector 32
31
36
  * §7: these are not registered callbacks — they observe and consume the
@@ -74,25 +79,42 @@ export declare class ZlinkStreamReceivedMessages {
74
79
  */
75
80
  connectionEnded(): void;
76
81
  enqueue(message: ZlinkStreamMessage<ZlinkStreamEncodedPayload>, signal?: AbortSignal): void;
77
- enqueueCallback(callback: () => Promise<void> | void): void;
82
+ /**
83
+ * @param callbacks The number of handler calls `callback` makes when it runs
84
+ * with the handlers registered at that moment; a callback that runs a set
85
+ * of handlers reads the set's size. One callback by default.
86
+ */
87
+ enqueueCallback(callback: () => Promise<void> | void, callbacks?: () => number): void;
78
88
  /**
79
89
  * Runs the registered handlers the receive path left queued. `Manual` calls
80
- * this from `dispatch`; `Immediate` has already drained on arrival.
90
+ * this from `dispatch`; `Immediate` drains on arrival.
81
91
  *
82
- * A handler that calls `dispatch` arrives back here from inside the drain it
83
- * was started by. `scheduleDrain` would find `drainTask` already set and
84
- * return, and the await below would then be the drain waiting on itself —
85
- * a deadlock with neither timeout nor error. The drain loop already takes
86
- * every message a handler exists for, so there is nothing a second drain
87
- * would deliver and returning is the whole of the correct behaviour.
92
+ * The drain is synchronous: the connector does not wait for a handler
93
+ * (spec stream-connector 32 §7), so nothing inside it awaits. A handler that
94
+ * calls `dispatch` arrives back here from inside the drain it was started by;
95
+ * the running loop already takes every deliverable entry, so returning is the
96
+ * whole of the correct behaviour.
88
97
  */
89
- pump(): Promise<void>;
98
+ pump(): void;
99
+ /**
100
+ * True while a registered callback runs from {@link pump}: the execution
101
+ * context spec stream-connector 32 §7 calls "inside a handler".
102
+ */
103
+ get dispatching(): boolean;
104
+ get pendingCallbacks(): number;
90
105
  private offerQueued;
91
- private scheduleDrain;
92
- private drain;
93
106
  private removeAt;
94
107
  private findDeliverableIndex;
95
- private hasQueuedMessage;
108
+ private indexDeliverable;
109
+ private isDeliverable;
110
+ /**
111
+ * Spec stream-connector 32 §7 and §10: the handlers that receive `message`
112
+ * are the connector handlers for its name and the handle handlers of the
113
+ * Actor it carries. A packet no handler receives stays in the queue for the
114
+ * wait surfaces. This is the one place that decides it.
115
+ */
116
+ private receiversOf;
117
+ private removeDeliverable;
96
118
  private advanceHead;
97
119
  private compactQueue;
98
120
  }
@@ -1,16 +1,17 @@
1
1
  import { Disposable, ZlinkStreamError, ZlinkStreamErrorCode, ZlinkStreamException } from '../Contracts';
2
+ /** Returns whether the consumed prefix should compact the backing array. */
3
+ export declare function shouldCompactBackingArray(head: number, length: number): boolean;
2
4
  export declare function connectorError(code: ZlinkStreamErrorCode, message: string, cause?: unknown): ZlinkStreamException;
3
5
  export declare function toStreamError(cause: unknown, code: ZlinkStreamErrorCode, message: string): ZlinkStreamError;
4
6
  export declare function unwrapStreamError(error: unknown): ZlinkStreamError;
5
7
  export declare function subscription(dispose: () => void): Disposable;
8
+ /** Snapshot order is preserved; membership owns each registration's lifetime. */
9
+ export declare function currentRegistrations<T>(registrations: ReadonlySet<T>, snapshot?: readonly T[]): IterableIterator<T>;
10
+ export interface HandlerRegistration<T> {
11
+ readonly handler: T;
12
+ }
13
+ export declare function registerHandler<T>(handlers: Set<HandlerRegistration<T>>, handler: T): Disposable;
6
14
  export declare function throwIfAborted(signal: AbortSignal | undefined): void;
7
15
  export declare function delay(delayMs: number, signal: AbortSignal | undefined): Promise<void>;
8
- export declare function readLength(source: Uint8Array, offset: number, bytes: 1 | 2, label: string): number;
9
- export declare function writeUInt16BE(destination: Uint8Array, offset: number, value: number): void;
10
- export declare function writeUInt32BE(destination: Uint8Array, offset: number, value: number): void;
11
- export declare function readUInt16BE(source: Uint8Array, offset: number): number;
12
- export declare function readUInt32BE(source: Uint8Array, offset: number): number;
13
- export declare function writeBigUInt64BE(destination: Uint8Array, offset: number, value: bigint): void;
14
- export declare function readBigUInt64BE(source: Uint8Array, offset: number): bigint;
15
16
  export declare function utf8Encode(value: string): Uint8Array;
16
17
  export declare function utf8Decode(value: Uint8Array): string;