@flighthq/socket 0.5.1-edge.1058.751c53a → 0.5.1-edge.1349.05b053d

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
@@ -13,5 +13,5 @@ Import the supported application-facing API from `@flighthq/socket`. The `@fligh
13
13
  This package is part of the locked-version Flight SDK graph. Applications may instead install and import `@flighthq/sdk` when package-level tree shaking is sufficient.
14
14
 
15
15
  - [Flight project](https://github.com/flighthq/flight)
16
- - [Source for @flighthq/socket@0.5.1-edge.1058.751c53a](https://github.com/flighthq/flight/tree/751c53a7765e345d4c3e29d3a6089601b35c2bad/packages/socket)
17
- - [License](https://github.com/flighthq/flight/blob/751c53a7765e345d4c3e29d3a6089601b35c2bad/LICENSE.md)
16
+ - [Source for @flighthq/socket@0.5.1-edge.1349.05b053d](https://github.com/flighthq/flight/tree/05b053d22f5f4864112afbed6f0d255d360c783f/packages/socket)
17
+ - [License](https://github.com/flighthq/flight/blob/05b053d22f5f4864112afbed6f0d255d360c783f/LICENSE.md)
@@ -1,5 +1,4 @@
1
1
  export * from './enableSocketGuards';
2
2
  export * from './explainSocketSendFailure';
3
3
  export * from './socket';
4
- export { initializeWebSocketBackend } from './socket';
5
4
  //# sourceMappingURL=contract.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,UAAU,CAAC;AACzB,OAAO,EAAE,0BAA0B,EAAE,MAAM,UAAU,CAAC"}
1
+ {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,UAAU,CAAC"}
package/dist/contract.js CHANGED
@@ -1,5 +1,4 @@
1
1
  export * from './enableSocketGuards';
2
2
  export * from './explainSocketSendFailure';
3
3
  export * from './socket';
4
- export { initializeWebSocketBackend } from './socket';
5
4
  //# sourceMappingURL=contract.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,UAAU,CAAC;AACzB,OAAO,EAAE,0BAA0B,EAAE,MAAM,UAAU,CAAC"}
1
+ {"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,UAAU,CAAC"}
package/dist/socket.d.ts CHANGED
@@ -1,14 +1,12 @@
1
- import type { Entity, EntityConstruction, HasNetSocket, Socket, SocketBackend, SocketGuard, SocketOptions, SocketReadyState, SocketSignals, TcpSocketConnection, TcpSocketOptions } from '@flighthq/types/contract';
1
+ import type { HostSocketProvider, Socket, SocketGuard, SocketOptions, SocketReadyState, SocketSignals, TcpSocketConnection, TcpSocketOptions } from '@flighthq/types/contract';
2
2
  export declare function attachSocket(socket: Socket): void;
3
3
  export declare function closeSocket(socket: Socket, code?: number, reason?: string): void;
4
- export declare function createSocket(host: HasNetSocket, options: Readonly<SocketOptions>): Socket;
5
- export declare function createWebSocketBackend(): SocketBackend & Entity;
4
+ export declare function createSocket(hostSocket: Readonly<HostSocketProvider>, options: Readonly<SocketOptions>): Socket;
6
5
  export declare function detachSocket(socket: Socket): void;
7
6
  export declare function disposeSocket(socket: Socket): void;
8
7
  export declare function enableSocketSignals(socket: Socket): SocketSignals;
9
8
  export declare function getSocketReadyState(socket: Readonly<Socket>): SocketReadyState;
10
- export declare function initializeWebSocketBackend(out: EntityConstruction<SocketBackend & Entity>): void;
11
- export declare function openTcpSocket(host: HasNetSocket, options: Readonly<TcpSocketOptions>): TcpSocketConnection | null;
9
+ export declare function openTcpSocket(hostSocket: Readonly<HostSocketProvider>, options: Readonly<TcpSocketOptions>): TcpSocketConnection | null;
12
10
  export declare function sendSocketMessage(socket: Readonly<Socket>, data: string | ArrayBuffer): boolean;
13
11
  export declare function setSocketGuard(guard: SocketGuard | null): void;
14
12
  //# sourceMappingURL=socket.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"socket.d.ts","sourceRoot":"","sources":["../src/socket.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,MAAM,EACN,kBAAkB,EAClB,YAAY,EACZ,MAAM,EACN,aAAa,EAIb,WAAW,EAEX,aAAa,EACb,gBAAgB,EAEhB,aAAa,EACb,mBAAmB,EACnB,gBAAgB,EACjB,MAAM,0BAA0B,CAAC;AAKlC,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAGjD;AAKD,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAShF;AAQD,wBAAgB,YAAY,CAAC,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,CAAC,aAAa,CAAC,GAAG,MAAM,CAkBzF;AAED,wBAAgB,sBAAsB,IAAI,aAAa,GAAG,MAAM,CAI/D;AAID,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAEjD;AAKD,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CASlD;AAMD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,CAcjE;AAGD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,gBAAgB,CAE9E;AAMD,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,kBAAkB,CAAC,aAAa,GAAG,MAAM,CAAC,GAAG,IAAI,CAwBhG;AAKD,wBAAgB,aAAa,CAAC,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,CAAC,gBAAgB,CAAC,GAAG,mBAAmB,GAAG,IAAI,CAEjH;AAKD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,OAAO,CAQ/F;AAID,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,GAAG,IAAI,CAE9D"}
1
+ {"version":3,"file":"socket.d.ts","sourceRoot":"","sources":["../src/socket.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,kBAAkB,EAClB,MAAM,EAGN,WAAW,EAEX,aAAa,EACb,gBAAgB,EAEhB,aAAa,EACb,mBAAmB,EACnB,gBAAgB,EACjB,MAAM,0BAA0B,CAAC;AAKlC,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAGjD;AAKD,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAShF;AAQD,wBAAgB,YAAY,CAAC,UAAU,EAAE,QAAQ,CAAC,kBAAkB,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,aAAa,CAAC,GAAG,MAAM,CAkB/G;AAID,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAEjD;AAKD,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CASlD;AAMD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,CAcjE;AAGD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,gBAAgB,CAE9E;AAKD,wBAAgB,aAAa,CAC3B,UAAU,EAAE,QAAQ,CAAC,kBAAkB,CAAC,EACxC,OAAO,EAAE,QAAQ,CAAC,gBAAgB,CAAC,GAClC,mBAAmB,GAAG,IAAI,CAE5B;AAKD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,OAAO,CAQ/F;AAID,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,GAAG,IAAI,CAE9D"}
package/dist/socket.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { allocateEntity, finishEntity } from '@flighthq/entity/contract';
2
2
  import { createSignal, emitSignal } from '@flighthq/signals/contract';
3
- // Resumes delivery of backend events to the socket's signals (idempotent). Pair with detachSocket.
3
+ // Resumes delivery of provider events to the socket's signals (idempotent). Pair with detachSocket.
4
4
  // createSocket leaves a new socket attached, so this is only needed to resume after detachSocket. A
5
5
  // disposed socket is terminal and cannot be reattached.
6
6
  export function attachSocket(socket) {
@@ -9,7 +9,7 @@ export function attachSocket(socket) {
9
9
  socket.runtime.delivering = true;
10
10
  }
11
11
  // Begins a clean close of the live connection. Transitions readyState connecting/open → 'closing';
12
- // the backend's close event later transitions it to 'closed'. A no-op when already closing or closed.
12
+ // the provider's close event later transitions it to 'closed'. A no-op when already closing or closed.
13
13
  // This is the connection command, distinct from disposeSocket (which releases the entity to GC).
14
14
  export function closeSocket(socket, code, reason) {
15
15
  const runtime = socket.runtime;
@@ -24,11 +24,11 @@ export function closeSocket(socket, code, reason) {
24
24
  }
25
25
  // Allocates a Socket entity plus its runtime and opens the connection through the host's socket
26
26
  // provider,
27
- // wiring the backend's open/message/close/error into the socket's (still inert) signal group. The
27
+ // wiring the provider's open/message/close/error into the socket's (still inert) signal group. The
28
28
  // socket starts in 'connecting' and is left attached (delivering). Enable signals with
29
- // enableSocketSignals to observe events. A backend that does not support the transport yields a null
29
+ // enableSocketSignals to observe events. A provider that does not support the transport yields a null
30
30
  // connection and the socket stays in 'connecting' until closed.
31
- export function createSocket(host, options) {
31
+ export function createSocket(hostSocket, options) {
32
32
  const runtime = {
33
33
  connection: null,
34
34
  signals: null,
@@ -42,18 +42,13 @@ export function createSocket(host, options) {
42
42
  // The provider comes from the host the caller passed. A host that carries no socket transport
43
43
  // yields no connection rather than reaching a process-global fallback: absence is an answer here,
44
44
  // and the guard reports it.
45
- const backend = host.net.socket;
45
+ const backend = hostSocket;
46
46
  runtime.connection = backend === undefined ? null : backend.openSocket(options, makeSocketEventSink(runtime));
47
47
  if (runtime.connection === null)
48
48
  _guard?.({ operation: 'createSocket', reason: 'no-connection', socket });
49
49
  return socket;
50
50
  }
51
- export function createWebSocketBackend() {
52
- const out = allocateEntity();
53
- initializeWebSocketBackend(out);
54
- return finishEntity(out);
55
- }
56
- // Stops delivery of backend events to the socket's signals. The live connection is untouched — use
51
+ // Stops delivery of provider events to the socket's signals. The live connection is untouched — use
57
52
  // closeSocket to close it. Safe to call repeatedly; resume with attachSocket.
58
53
  export function detachSocket(socket) {
59
54
  socket.runtime.delivering = false;
@@ -92,48 +87,19 @@ export function enableSocketSignals(socket) {
92
87
  }
93
88
  return runtime.signals;
94
89
  }
95
- // The socket's current connection phase, tracked on the runtime from backend events and closeSocket.
90
+ // The socket's current connection phase, tracked on the runtime from provider events and closeSocket.
96
91
  export function getSocketReadyState(socket) {
97
92
  return socket.runtime.readyState;
98
93
  }
99
- // Builds the web backend over the DOM WebSocket. Nothing constructs one at import time, so importing
100
- // the package has no side effect; a host composes this value into its own net group. Returns a
101
- // null connection when WebSocket is unavailable (non-browser host) rather than throwing; raw TCP/UDP
102
- // is likewise unsupported here and only reachable through a native backend.
103
- export function initializeWebSocketBackend(out) {
104
- out.openSocket = (options, events) => {
105
- if (typeof WebSocket === 'undefined')
106
- return null;
107
- const ws = options.protocols !== undefined
108
- ? new WebSocket(options.url, options.protocols)
109
- : new WebSocket(options.url);
110
- ws.binaryType = options.binaryType ?? 'arraybuffer';
111
- ws.onopen = () => events.handleSocketOpen();
112
- ws.onmessage = (event) => events.handleSocketMessage(toSocketMessage(event.data));
113
- ws.onclose = (event) => events.handleSocketClose({ code: event.code, reason: event.reason, wasClean: event.wasClean });
114
- ws.onerror = () => events.handleSocketError();
115
- return {
116
- sendSocketFrame(data) {
117
- if (ws.readyState !== WebSocket.OPEN)
118
- return false;
119
- ws.send(data);
120
- return true;
121
- },
122
- closeSocketConnection(code, reason) {
123
- ws.close(code, reason);
124
- },
125
- };
126
- };
127
- }
128
94
  // Opens a raw TCP byte stream through the socket provider selected by the caller's host. Browser and
129
95
  // other framed-only providers omit openTcpSocket, so unsupported raw TCP returns null without trying
130
96
  // openSocket or interpreting the endpoint as a WebSocket URL.
131
- export function openTcpSocket(host, options) {
132
- return host.net.socket?.openTcpSocket?.(options) ?? null;
97
+ export function openTcpSocket(hostSocket, options) {
98
+ return hostSocket?.openTcpSocket?.(options) ?? null;
133
99
  }
134
100
  // Sends a text or binary frame over the live connection without mutating or copying either argument.
135
101
  // Returns false — a sentinel, not a throw — when the socket is disposed, not open, has no connection,
136
- // or the backend rejects the send. explainSocketSendFailure diagnoses the deterministic preflight paths.
102
+ // or the provider rejects the send. explainSocketSendFailure diagnoses the deterministic preflight paths.
137
103
  export function sendSocketMessage(socket, data) {
138
104
  const runtime = socket.runtime;
139
105
  if (runtime.disposed) {
@@ -150,9 +116,9 @@ export function setSocketGuard(guard) {
150
116
  _guard = guard;
151
117
  }
152
118
  let _guard = null;
153
- // Builds the backend→entity sink bound to one socket's runtime: it updates readyState and emits the
119
+ // Builds the provider→entity sink bound to one socket's runtime: it updates readyState and emits the
154
120
  // opt-in signals. Every handler is a no-op once the runtime stops delivering (detach/dispose), so a
155
- // late backend event after teardown fires nothing.
121
+ // late provider event after teardown fires nothing.
156
122
  function makeSocketEventSink(runtime) {
157
123
  return {
158
124
  handleSocketOpen() {
@@ -183,11 +149,4 @@ function makeSocketEventSink(runtime) {
183
149
  },
184
150
  };
185
151
  }
186
- // Maps a raw WebSocket message payload onto a SocketMessage. A string is a text frame; anything else
187
- // (with binaryType 'arraybuffer', an ArrayBuffer) is a binary frame.
188
- function toSocketMessage(data) {
189
- if (typeof data === 'string')
190
- return { data, binary: false };
191
- return { data: data, binary: true };
192
- }
193
152
  //# sourceMappingURL=socket.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"socket.js","sourceRoot":"","sources":["../src/socket.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"socket.js","sourceRoot":"","sources":["../src/socket.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flighthq/socket",
3
- "version": "0.5.1-edge.1058.751c53a",
3
+ "version": "0.5.1-edge.1349.05b053d",
4
4
  "author": "Joshua Granick and other contributors",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -38,10 +38,10 @@
38
38
  "clean:dist": "tsx ../../scripts/clean-package-dist.ts"
39
39
  },
40
40
  "dependencies": {
41
- "@flighthq/entity": "0.5.1-edge.1058.751c53a",
42
- "@flighthq/log": "0.5.1-edge.1058.751c53a",
43
- "@flighthq/signals": "0.5.1-edge.1058.751c53a",
44
- "@flighthq/types": "0.5.1-edge.1058.751c53a"
41
+ "@flighthq/entity": "0.5.1-edge.1349.05b053d",
42
+ "@flighthq/log": "0.5.1-edge.1349.05b053d",
43
+ "@flighthq/signals": "0.5.1-edge.1349.05b053d",
44
+ "@flighthq/types": "0.5.1-edge.1349.05b053d"
45
45
  },
46
46
  "devDependencies": {
47
47
  "typescript": "^5.3.0"
@@ -1,5 +1,5 @@
1
1
  import { addLogSink, createMemoryLogSink, getMemoryLogSinkEntries, removeLogSink } from '@flighthq/log/contract';
2
- import type { HasNetSocket, LogEntry, SocketBackend } from '@flighthq/types/contract';
2
+ import type { HostSocketProvider, LogEntry } from '@flighthq/types/contract';
3
3
 
4
4
  import { areSocketGuardsEnabled, disableSocketGuards, enableSocketGuards } from './enableSocketGuards';
5
5
  import { closeSocket, createSocket, disposeSocket, enableSocketSignals, sendSocketMessage } from './socket';
@@ -15,7 +15,7 @@ function captureLog(run: () => void): readonly LogEntry[] {
15
15
  }
16
16
  }
17
17
 
18
- function backend(hasConnection: boolean): SocketBackend {
18
+ function backend(hasConnection: boolean): HostSocketProvider {
19
19
  return {
20
20
  openSocket() {
21
21
  if (!hasConnection) return null;
@@ -28,8 +28,8 @@ afterEach(() => {
28
28
  disableSocketGuards();
29
29
  });
30
30
 
31
- function hostOf(backend: SocketBackend): HasNetSocket {
32
- return { net: { socket: backend } } as HasNetSocket;
31
+ function hostOf(backend: HostSocketProvider): { readonly net: { readonly socket: HostSocketProvider } } {
32
+ return { net: { socket: backend } } as { readonly net: { readonly socket: HostSocketProvider } };
33
33
  }
34
34
 
35
35
  describe('areSocketGuardsEnabled', () => {
@@ -46,7 +46,7 @@ describe('disableSocketGuards', () => {
46
46
  enableSocketGuards();
47
47
  disableSocketGuards();
48
48
  const host = hostOf(backend(false));
49
- expect(captureLog(() => createSocket(host, { url: 'tcp://silent' }))).toEqual([]);
49
+ expect(captureLog(() => createSocket(host.net.socket, { url: 'tcp://silent' }))).toEqual([]);
50
50
  });
51
51
  });
52
52
 
@@ -55,8 +55,8 @@ describe('enableSocketGuards', () => {
55
55
  enableSocketGuards();
56
56
  const host = hostOf(backend(false));
57
57
  const entries = captureLog(() => {
58
- createSocket(host, { url: 'tcp://unsupported' });
59
- createSocket(host, { url: 'tcp://unsupported-again' });
58
+ createSocket(host.net.socket, { url: 'tcp://unsupported' });
59
+ createSocket(host.net.socket, { url: 'tcp://unsupported-again' });
60
60
  });
61
61
  expect(entries).toHaveLength(1);
62
62
  expect(entries[0]).toMatchObject({ channel: 'socket' });
@@ -71,7 +71,7 @@ describe('enableSocketGuards', () => {
71
71
  it('warns once per command issued after terminal disposal', () => {
72
72
  enableSocketGuards();
73
73
  const host = hostOf(backend(true));
74
- const socket = createSocket(host, { url: 'ws://disposed' });
74
+ const socket = createSocket(host.net.socket, { url: 'ws://disposed' });
75
75
  disposeSocket(socket);
76
76
  const entries = captureLog(() => {
77
77
  closeSocket(socket);
@@ -94,7 +94,7 @@ describe('enableSocketGuards', () => {
94
94
  it('stays silent for ordinary pre-open sends and closes', () => {
95
95
  enableSocketGuards();
96
96
  const host = hostOf(backend(true));
97
- const socket = createSocket(host, { url: 'ws://connecting' });
97
+ const socket = createSocket(host.net.socket, { url: 'ws://connecting' });
98
98
  const entries = captureLog(() => {
99
99
  sendSocketMessage(socket, 'early');
100
100
  closeSocket(socket);
@@ -1,4 +1,4 @@
1
- import type { HasNetSocket, SocketBackend, SocketEventSink } from '@flighthq/types/contract';
1
+ import type { HostSocketProvider, SocketEventSink } from '@flighthq/types/contract';
2
2
 
3
3
  import { explainSocketSendFailure } from './explainSocketSendFailure';
4
4
  import { createSocket, disposeSocket, sendSocketMessage } from './socket';
@@ -6,9 +6,9 @@ import { createSocket, disposeSocket, sendSocketMessage } from './socket';
6
6
  function installBackend(
7
7
  hasConnection: boolean,
8
8
  sendResult = true,
9
- ): { host: HasNetSocket; sink: () => SocketEventSink } {
9
+ ): { host: { readonly net: { readonly socket: HostSocketProvider } }; sink: () => SocketEventSink } {
10
10
  let sink!: SocketEventSink;
11
- const backend: SocketBackend = {
11
+ const backend: HostSocketProvider = {
12
12
  openSocket(_options, events) {
13
13
  sink = events;
14
14
  if (!hasConnection) return null;
@@ -21,14 +21,14 @@ function installBackend(
21
21
  return { host: hostOf(backend), sink: () => sink };
22
22
  }
23
23
 
24
- function hostOf(backend: SocketBackend): HasNetSocket {
25
- return { net: { socket: backend } } as HasNetSocket;
24
+ function hostOf(backend: HostSocketProvider): { readonly net: { readonly socket: HostSocketProvider } } {
25
+ return { net: { socket: backend } } as { readonly net: { readonly socket: HostSocketProvider } };
26
26
  }
27
27
 
28
28
  describe('explainSocketSendFailure', () => {
29
29
  it('identifies an unsupported backend with no connection', () => {
30
30
  const { host } = installBackend(false);
31
- const socket = createSocket(host, { url: 'tcp://host' });
31
+ const socket = createSocket(host.net.socket, { url: 'tcp://host' });
32
32
  expect(explainSocketSendFailure(socket)).toEqual({
33
33
  reason: 'no-connection',
34
34
  readyState: 'connecting',
@@ -38,7 +38,7 @@ describe('explainSocketSendFailure', () => {
38
38
 
39
39
  it('reports the current non-open phase when a connection exists', () => {
40
40
  const { host } = installBackend(true);
41
- const socket = createSocket(host, { url: 'ws://host' });
41
+ const socket = createSocket(host.net.socket, { url: 'ws://host' });
42
42
  expect(explainSocketSendFailure(socket)).toEqual({
43
43
  reason: 'not-open',
44
44
  readyState: 'connecting',
@@ -48,7 +48,7 @@ describe('explainSocketSendFailure', () => {
48
48
 
49
49
  it('returns null once the socket can reach its backend, even when that backend returns false', () => {
50
50
  const { host, sink: getSink } = installBackend(true, false);
51
- const socket = createSocket(host, { url: 'ws://host' });
51
+ const socket = createSocket(host.net.socket, { url: 'ws://host' });
52
52
  getSink().handleSocketOpen();
53
53
  expect(sendSocketMessage(socket, 'frame')).toBe(false);
54
54
  expect(explainSocketSendFailure(socket)).toBeNull();
@@ -56,7 +56,7 @@ describe('explainSocketSendFailure', () => {
56
56
 
57
57
  it('distinguishes terminal disposal from other closed or disconnected states', () => {
58
58
  const { host } = installBackend(true);
59
- const socket = createSocket(host, { url: 'ws://host' });
59
+ const socket = createSocket(host.net.socket, { url: 'ws://host' });
60
60
  disposeSocket(socket);
61
61
  expect(explainSocketSendFailure(socket)).toEqual({
62
62
  reason: 'disposed',
@@ -1,7 +1,6 @@
1
1
  import { connectSignal } from '@flighthq/signals/contract';
2
2
  import type {
3
- HasNetSocket,
4
- SocketBackend,
3
+ HostSocketProvider,
5
4
  SocketCloseInfo,
6
5
  SocketConnection,
7
6
  SocketEventSink,
@@ -15,18 +14,16 @@ import {
15
14
  attachSocket,
16
15
  closeSocket,
17
16
  createSocket,
18
- createWebSocketBackend,
19
17
  detachSocket,
20
18
  disposeSocket,
21
19
  enableSocketSignals,
22
20
  getSocketReadyState,
23
- initializeWebSocketBackend,
24
21
  sendSocketMessage,
25
22
  setSocketGuard,
26
23
  } from './socket';
27
24
 
28
25
  interface FakeSocket {
29
- backend: SocketBackend;
26
+ backend: HostSocketProvider;
30
27
  sink: SocketEventSink;
31
28
  sent: (string | ArrayBuffer)[];
32
29
  closes: { code?: number; reason?: string }[];
@@ -46,7 +43,7 @@ function fakeBackend(): FakeSocket {
46
43
  sendReturns: true,
47
44
  lastOptions: null,
48
45
  sink: null as unknown as SocketEventSink,
49
- backend: null as unknown as SocketBackend,
46
+ backend: null as unknown as HostSocketProvider,
50
47
  };
51
48
  state.backend = {
52
49
  openSocket(options, events): SocketConnection | null {
@@ -71,8 +68,8 @@ afterEach(() => {
71
68
  setSocketGuard(null);
72
69
  });
73
70
 
74
- function hostOf(backend: SocketBackend): HasNetSocket {
75
- return { net: { socket: backend } } as HasNetSocket;
71
+ function hostOf(backend: HostSocketProvider): { readonly net: { readonly socket: HostSocketProvider } } {
72
+ return { net: { socket: backend } } as { readonly net: { readonly socket: HostSocketProvider } };
76
73
  }
77
74
 
78
75
  function tcpConnection(): TcpSocketConnection {
@@ -87,7 +84,7 @@ describe('attachSocket', () => {
87
84
  it('resumes delivery after a detach', () => {
88
85
  const fake = fakeBackend();
89
86
  const host = hostOf(fake.backend);
90
- const socket = createSocket(host, { url: 'ws://x' });
87
+ const socket = createSocket(host.net.socket, { url: 'ws://x' });
91
88
  const signals = enableSocketSignals(socket);
92
89
  let opens = 0;
93
90
  connectSignal(signals.onSocketOpen, () => opens++);
@@ -100,7 +97,7 @@ describe('attachSocket', () => {
100
97
  it('cannot resume delivery after terminal disposal', () => {
101
98
  const fake = fakeBackend();
102
99
  const host = hostOf(fake.backend);
103
- const socket = createSocket(host, { url: 'ws://x' });
100
+ const socket = createSocket(host.net.socket, { url: 'ws://x' });
104
101
  const signals = enableSocketSignals(socket);
105
102
  let opens = 0;
106
103
  connectSignal(signals.onSocketOpen, () => opens++);
@@ -116,7 +113,7 @@ describe('closeSocket', () => {
116
113
  it('transitions to closing and forwards code/reason to the connection', () => {
117
114
  const fake = fakeBackend();
118
115
  const host = hostOf(fake.backend);
119
- const socket = createSocket(host, { url: 'ws://x' });
116
+ const socket = createSocket(host.net.socket, { url: 'ws://x' });
120
117
  fake.sink.handleSocketOpen();
121
118
  closeSocket(socket, 1000, 'bye');
122
119
  expect(getSocketReadyState(socket)).toBe('closing');
@@ -126,7 +123,7 @@ describe('closeSocket', () => {
126
123
  it('reaches closed once the backend close event arrives', () => {
127
124
  const fake = fakeBackend();
128
125
  const host = hostOf(fake.backend);
129
- const socket = createSocket(host, { url: 'ws://x' });
126
+ const socket = createSocket(host.net.socket, { url: 'ws://x' });
130
127
  fake.sink.handleSocketOpen();
131
128
  closeSocket(socket);
132
129
  fake.sink.handleSocketClose({ code: 1000, reason: '', wasClean: true });
@@ -136,7 +133,7 @@ describe('closeSocket', () => {
136
133
  it('is a no-op when already closed', () => {
137
134
  const fake = fakeBackend();
138
135
  const host = hostOf(fake.backend);
139
- const socket = createSocket(host, { url: 'ws://x' });
136
+ const socket = createSocket(host.net.socket, { url: 'ws://x' });
140
137
  fake.sink.handleSocketOpen();
141
138
  closeSocket(socket);
142
139
  fake.sink.handleSocketClose({ code: 1000, reason: '', wasClean: true });
@@ -147,7 +144,7 @@ describe('closeSocket', () => {
147
144
  it('stays closed and does not close the connection again after disposal', () => {
148
145
  const fake = fakeBackend();
149
146
  const host = hostOf(fake.backend);
150
- const socket = createSocket(host, { url: 'ws://x' });
147
+ const socket = createSocket(host.net.socket, { url: 'ws://x' });
151
148
  disposeSocket(socket);
152
149
  closeSocket(socket);
153
150
  expect(getSocketReadyState(socket)).toBe('closed');
@@ -159,7 +156,7 @@ describe('createSocket', () => {
159
156
  it('opens through the backend in the connecting state and records the url', () => {
160
157
  const fake = fakeBackend();
161
158
  const host = hostOf(fake.backend);
162
- const socket = createSocket(host, { url: 'ws://host/path' });
159
+ const socket = createSocket(host.net.socket, { url: 'ws://host/path' });
163
160
  expect(socket.url).toBe('ws://host/path');
164
161
  expect(getSocketReadyState(socket)).toBe('connecting');
165
162
  expect(fake.lastOptions?.url).toBe('ws://host/path');
@@ -168,7 +165,7 @@ describe('createSocket', () => {
168
165
  it('passes protocols and binaryType through to the backend', () => {
169
166
  const fake = fakeBackend();
170
167
  const host = hostOf(fake.backend);
171
- createSocket(host, { url: 'ws://x', protocols: ['a', 'b'], binaryType: 'arraybuffer' });
168
+ createSocket(host.net.socket, { url: 'ws://x', protocols: ['a', 'b'], binaryType: 'arraybuffer' });
172
169
  expect(fake.lastOptions?.protocols).toEqual(['a', 'b']);
173
170
  expect(fake.lastOptions?.binaryType).toBe('arraybuffer');
174
171
  });
@@ -177,7 +174,7 @@ describe('createSocket', () => {
177
174
  const fake = fakeBackend();
178
175
  fake.openReturnsNull = true;
179
176
  const host = hostOf(fake.backend);
180
- const socket = createSocket(host, { url: 'tcp://x' });
177
+ const socket = createSocket(host.net.socket, { url: 'tcp://x' });
181
178
  expect(getSocketReadyState(socket)).toBe('connecting');
182
179
  expect(sendSocketMessage(socket, 'x')).toBe(false);
183
180
  });
@@ -185,7 +182,7 @@ describe('createSocket', () => {
185
182
  it('emits a text message with binary false and a binary message with binary true', () => {
186
183
  const fake = fakeBackend();
187
184
  const host = hostOf(fake.backend);
188
- const socket = createSocket(host, { url: 'ws://x' });
185
+ const socket = createSocket(host.net.socket, { url: 'ws://x' });
189
186
  const signals = enableSocketSignals(socket);
190
187
  const received: SocketMessage[] = [];
191
188
  connectSignal(signals.onSocketMessage, (m) => received.push(m));
@@ -202,7 +199,7 @@ describe('createSocket', () => {
202
199
  it('emits close info with code, reason, and wasClean', () => {
203
200
  const fake = fakeBackend();
204
201
  const host = hostOf(fake.backend);
205
- const socket = createSocket(host, { url: 'ws://x' });
202
+ const socket = createSocket(host.net.socket, { url: 'ws://x' });
206
203
  const signals = enableSocketSignals(socket);
207
204
  const infos: SocketCloseInfo[] = [];
208
205
  connectSignal(signals.onSocketClose, (i) => infos.push(i));
@@ -213,7 +210,7 @@ describe('createSocket', () => {
213
210
  it('emits onSocketError', () => {
214
211
  const fake = fakeBackend();
215
212
  const host = hostOf(fake.backend);
216
- const socket = createSocket(host, { url: 'ws://x' });
213
+ const socket = createSocket(host.net.socket, { url: 'ws://x' });
217
214
  const signals = enableSocketSignals(socket);
218
215
  let errors = 0;
219
216
  connectSignal(signals.onSocketError, () => errors++);
@@ -222,102 +219,11 @@ describe('createSocket', () => {
222
219
  });
223
220
  });
224
221
 
225
- describe('createWebSocketBackend', () => {
226
- it('constructs a WebSocket with url and protocols and sets binaryType', () => {
227
- const restore = installFakeWebSocket();
228
- try {
229
- createWebSocketBackend().openSocket(
230
- { url: 'ws://host', protocols: ['chat'], binaryType: 'arraybuffer' },
231
- noopSink(),
232
- );
233
- const ws = FakeWebSocket.last!;
234
- expect(ws.url).toBe('ws://host');
235
- expect(ws.protocols).toEqual(['chat']);
236
- expect(ws.binaryType).toBe('arraybuffer');
237
- } finally {
238
- restore();
239
- }
240
- });
241
-
242
- it('translates an incoming string message to binary false', () => {
243
- const restore = installFakeWebSocket();
244
- try {
245
- const received: SocketMessage[] = [];
246
- createWebSocketBackend().openSocket({ url: 'ws://x' }, sinkCollecting(received));
247
- FakeWebSocket.last!.onmessage!({ data: 'hello' } as MessageEvent);
248
- expect(received).toEqual([{ data: 'hello', binary: false }]);
249
- } finally {
250
- restore();
251
- }
252
- });
253
-
254
- it('translates an incoming ArrayBuffer message to binary true', () => {
255
- const restore = installFakeWebSocket();
256
- try {
257
- const received: SocketMessage[] = [];
258
- createWebSocketBackend().openSocket({ url: 'ws://x' }, sinkCollecting(received));
259
- const buffer = new Uint8Array([9]).buffer;
260
- FakeWebSocket.last!.onmessage!({ data: buffer } as MessageEvent);
261
- expect(received[0]).toEqual({ data: buffer, binary: true });
262
- } finally {
263
- restore();
264
- }
265
- });
266
-
267
- it('maps close events and open into the sink', () => {
268
- const restore = installFakeWebSocket();
269
- try {
270
- let opened = false;
271
- const closes: SocketCloseInfo[] = [];
272
- const sink: SocketEventSink = {
273
- ...noopSink(),
274
- handleSocketOpen: () => (opened = true),
275
- handleSocketClose: (i) => closes.push(i),
276
- };
277
- createWebSocketBackend().openSocket({ url: 'ws://x' }, sink);
278
- const ws = FakeWebSocket.last!;
279
- ws.onopen!(new Event('open'));
280
- ws.onclose!({ code: 1000, reason: 'done', wasClean: true } as CloseEvent);
281
- expect(opened).toBe(true);
282
- expect(closes).toEqual([{ code: 1000, reason: 'done', wasClean: true }]);
283
- } finally {
284
- restore();
285
- }
286
- });
287
-
288
- it('sends only when the WebSocket is OPEN and closes with code/reason', () => {
289
- const restore = installFakeWebSocket();
290
- try {
291
- const connection = createWebSocketBackend().openSocket({ url: 'ws://x' }, noopSink())!;
292
- const ws = FakeWebSocket.last!;
293
- ws.readyState = FakeWebSocket.CONNECTING;
294
- expect(connection.sendSocketFrame('x')).toBe(false);
295
- ws.readyState = FakeWebSocket.OPEN;
296
- expect(connection.sendSocketFrame('y')).toBe(true);
297
- expect(ws.sent).toEqual(['y']);
298
- connection.closeSocketConnection(1001, 'later');
299
- expect(ws.closed).toEqual({ code: 1001, reason: 'later' });
300
- } finally {
301
- restore();
302
- }
303
- });
304
-
305
- it('returns a null connection when WebSocket is unavailable', () => {
306
- const original = (globalThis as { WebSocket?: unknown }).WebSocket;
307
- (globalThis as { WebSocket?: unknown }).WebSocket = undefined;
308
- try {
309
- expect(createWebSocketBackend().openSocket({ url: 'ws://x' }, noopSink())).toBeNull();
310
- } finally {
311
- (globalThis as { WebSocket?: unknown }).WebSocket = original;
312
- }
313
- });
314
- });
315
-
316
222
  describe('detachSocket', () => {
317
223
  it('stops backend events from reaching the signals', () => {
318
224
  const fake = fakeBackend();
319
225
  const host = hostOf(fake.backend);
320
- const socket = createSocket(host, { url: 'ws://x' });
226
+ const socket = createSocket(host.net.socket, { url: 'ws://x' });
321
227
  const signals = enableSocketSignals(socket);
322
228
  let opens = 0;
323
229
  connectSignal(signals.onSocketOpen, () => opens++);
@@ -331,7 +237,7 @@ describe('disposeSocket', () => {
331
237
  it('closes an open connection and detaches so later events fire no signal', () => {
332
238
  const fake = fakeBackend();
333
239
  const host = hostOf(fake.backend);
334
- const socket = createSocket(host, { url: 'ws://x' });
240
+ const socket = createSocket(host.net.socket, { url: 'ws://x' });
335
241
  const signals = enableSocketSignals(socket);
336
242
  let messages = 0;
337
243
  connectSignal(signals.onSocketMessage, () => messages++);
@@ -347,7 +253,7 @@ describe('disposeSocket', () => {
347
253
  it('is safe to call on a fresh socket', () => {
348
254
  const fake = fakeBackend();
349
255
  const host = hostOf(fake.backend);
350
- const socket = createSocket(host, { url: 'ws://x' });
256
+ const socket = createSocket(host.net.socket, { url: 'ws://x' });
351
257
  expect(() => disposeSocket(socket)).not.toThrow();
352
258
  });
353
259
  });
@@ -356,21 +262,21 @@ describe('enableSocketSignals', () => {
356
262
  it('returns the same group on repeated calls', () => {
357
263
  const fake = fakeBackend();
358
264
  const host = hostOf(fake.backend);
359
- const socket = createSocket(host, { url: 'ws://x' });
265
+ const socket = createSocket(host.net.socket, { url: 'ws://x' });
360
266
  expect(enableSocketSignals(socket)).toBe(enableSocketSignals(socket));
361
267
  });
362
268
 
363
269
  it('leaves a bare socket without signals', () => {
364
270
  const fake = fakeBackend();
365
271
  const host = hostOf(fake.backend);
366
- const socket = createSocket(host, { url: 'ws://x' });
272
+ const socket = createSocket(host.net.socket, { url: 'ws://x' });
367
273
  expect(socket.runtime.signals).toBeNull();
368
274
  });
369
275
 
370
276
  it('returns an inert stable group without reviving a disposed socket', () => {
371
277
  const fake = fakeBackend();
372
278
  const host = hostOf(fake.backend);
373
- const socket = createSocket(host, { url: 'ws://x' });
279
+ const socket = createSocket(host.net.socket, { url: 'ws://x' });
374
280
  disposeSocket(socket);
375
281
  const first = enableSocketSignals(socket);
376
282
  expect(enableSocketSignals(socket)).toBe(first);
@@ -383,7 +289,7 @@ describe('getSocketReadyState', () => {
383
289
  it('reflects connecting → open → closing → closed transitions', () => {
384
290
  const fake = fakeBackend();
385
291
  const host = hostOf(fake.backend);
386
- const socket = createSocket(host, { url: 'ws://x' });
292
+ const socket = createSocket(host.net.socket, { url: 'ws://x' });
387
293
  expect(getSocketReadyState(socket)).toBe('connecting');
388
294
  fake.sink.handleSocketOpen();
389
295
  expect(getSocketReadyState(socket)).toBe('open');
@@ -394,46 +300,43 @@ describe('getSocketReadyState', () => {
394
300
  });
395
301
  });
396
302
 
397
- describe('initializeWebSocketBackend', () => {
398
- it('is the construction initializer of createWebSocketBackend', () => {
399
- expect(typeof initializeWebSocketBackend).toBe('function');
400
- });
401
- });
402
-
403
303
  describe('openTcpSocket', () => {
404
304
  it('forwards the endpoint unchanged and returns the backend connection by identity', () => {
405
305
  const expected = tcpConnection();
406
306
  const options: TcpSocketOptions = { host: 'db.internal', port: 5432 };
407
307
  const openTcpSocketBackend = vi.fn(() => expected);
408
- const backend: SocketBackend = {
308
+ const backend: HostSocketProvider = {
409
309
  openSocket: vi.fn(() => null),
410
310
  openTcpSocket: openTcpSocketBackend,
411
311
  };
412
312
 
413
- expect(openTcpSocket(hostOf(backend), options)).toBe(expected);
313
+ expect(openTcpSocket(hostOf(backend).net.socket, options)).toBe(expected);
414
314
  expect(openTcpSocketBackend).toHaveBeenCalledWith(options);
415
315
  });
416
316
 
417
317
  it('returns null when the host carries no socket backend', () => {
418
- const host = { net: {} } as HasNetSocket;
419
- expect(openTcpSocket(host, { host: 'localhost', port: 9000 })).toBeNull();
318
+ const host = { net: {} } as { readonly net: { readonly socket: HostSocketProvider } };
319
+ expect(openTcpSocket(host.net.socket, { host: 'localhost', port: 9000 })).toBeNull();
420
320
  });
421
321
 
422
- it('returns null for the web backend without attempting framed openSocket', () => {
423
- const backend = createWebSocketBackend();
322
+ // A framed-only provider — the shape every browser transport takes — omits openTcpSocket entirely.
323
+ // Raw TCP must then report absence rather than falling through to openSocket and reinterpreting the
324
+ // endpoint as a WebSocket URL.
325
+ it('returns null for a framed-only backend without attempting framed openSocket', () => {
326
+ const backend: HostSocketProvider = { openSocket: vi.fn(() => null) };
424
327
  const openSocket = vi.spyOn(backend, 'openSocket');
425
328
 
426
- expect(openTcpSocket(hostOf(backend), { host: 'localhost', port: 9000 })).toBeNull();
329
+ expect(openTcpSocket(hostOf(backend).net.socket, { host: 'localhost', port: 9000 })).toBeNull();
427
330
  expect(openSocket).not.toHaveBeenCalled();
428
331
  });
429
332
 
430
333
  it('preserves an explicit null from a backend that cannot open the endpoint', () => {
431
- const backend: SocketBackend = {
334
+ const backend: HostSocketProvider = {
432
335
  openSocket: vi.fn(() => null),
433
336
  openTcpSocket: vi.fn(() => null),
434
337
  };
435
338
 
436
- expect(openTcpSocket(hostOf(backend), { host: 'unreachable.internal', port: 22 })).toBeNull();
339
+ expect(openTcpSocket(hostOf(backend).net.socket, { host: 'unreachable.internal', port: 22 })).toBeNull();
437
340
  });
438
341
  });
439
342
 
@@ -441,7 +344,7 @@ describe('sendSocketMessage', () => {
441
344
  it('sends through the connection and returns true when open', () => {
442
345
  const fake = fakeBackend();
443
346
  const host = hostOf(fake.backend);
444
- const socket = createSocket(host, { url: 'ws://x' });
347
+ const socket = createSocket(host.net.socket, { url: 'ws://x' });
445
348
  fake.sink.handleSocketOpen();
446
349
  expect(sendSocketMessage(socket, 'ping')).toBe(true);
447
350
  expect(fake.sent).toEqual(['ping']);
@@ -450,7 +353,7 @@ describe('sendSocketMessage', () => {
450
353
  it('returns false without throwing when not open', () => {
451
354
  const fake = fakeBackend();
452
355
  const host = hostOf(fake.backend);
453
- const socket = createSocket(host, { url: 'ws://x' });
356
+ const socket = createSocket(host.net.socket, { url: 'ws://x' });
454
357
  expect(sendSocketMessage(socket, 'ping')).toBe(false);
455
358
  expect(fake.sent).toEqual([]);
456
359
  });
@@ -458,7 +361,7 @@ describe('sendSocketMessage', () => {
458
361
  it('returns false after disposal without reaching the released connection', () => {
459
362
  const fake = fakeBackend();
460
363
  const host = hostOf(fake.backend);
461
- const socket = createSocket(host, { url: 'ws://x' });
364
+ const socket = createSocket(host.net.socket, { url: 'ws://x' });
462
365
  fake.sink.handleSocketOpen();
463
366
  disposeSocket(socket);
464
367
  expect(sendSocketMessage(socket, 'ping')).toBe(false);
@@ -469,7 +372,7 @@ describe('sendSocketMessage', () => {
469
372
  const fake = fakeBackend();
470
373
  fake.openReturnsNull = true;
471
374
  const host = hostOf(fake.backend);
472
- const socket = createSocket(host, { url: 'tcp://x' });
375
+ const socket = createSocket(host.net.socket, { url: 'tcp://x' });
473
376
  fake.sink.handleSocketOpen();
474
377
  expect(getSocketReadyState(socket)).toBe('open');
475
378
  expect(sendSocketMessage(socket, 'ping')).toBe(false);
@@ -479,7 +382,7 @@ describe('sendSocketMessage', () => {
479
382
  const fake = fakeBackend();
480
383
  fake.sendReturns = false;
481
384
  const host = hostOf(fake.backend);
482
- const socket = createSocket(host, { url: 'ws://x' });
385
+ const socket = createSocket(host.net.socket, { url: 'ws://x' });
483
386
  fake.sink.handleSocketOpen();
484
387
  Object.freeze(socket.runtime);
485
388
  Object.freeze(socket);
@@ -489,62 +392,6 @@ describe('sendSocketMessage', () => {
489
392
  });
490
393
  });
491
394
 
492
- function noopSink(): SocketEventSink {
493
- return {
494
- handleSocketOpen() {},
495
- handleSocketMessage() {},
496
- handleSocketClose() {},
497
- handleSocketError() {},
498
- };
499
- }
500
-
501
- function sinkCollecting(received: SocketMessage[]): SocketEventSink {
502
- return { ...noopSink(), handleSocketMessage: (m) => received.push(m) };
503
- }
504
-
505
- // A minimal stand-in for the DOM WebSocket, recording constructor args, sends, and close, and
506
- // exposing dispatchable onopen/onmessage/onclose/onerror handlers.
507
- class FakeWebSocket {
508
- static CONNECTING = 0;
509
- static OPEN = 1;
510
- static CLOSING = 2;
511
- static CLOSED = 3;
512
- static last: FakeWebSocket | null = null;
513
-
514
- url: string;
515
- protocols?: readonly string[];
516
- binaryType = 'blob';
517
- readyState = FakeWebSocket.CONNECTING;
518
- sent: (string | ArrayBuffer)[] = [];
519
- closed: { code?: number; reason?: string } | null = null;
520
- onopen: ((event: Event) => void) | null = null;
521
- onmessage: ((event: MessageEvent) => void) | null = null;
522
- onclose: ((event: CloseEvent) => void) | null = null;
523
- onerror: ((event: Event) => void) | null = null;
524
-
525
- constructor(url: string, protocols?: string | string[]) {
526
- this.url = url;
527
- if (protocols !== undefined) this.protocols = typeof protocols === 'string' ? [protocols] : protocols;
528
- FakeWebSocket.last = this;
529
- }
530
-
531
- send(data: string | ArrayBuffer): void {
532
- this.sent.push(data);
533
- }
534
-
535
- close(code?: number, reason?: string): void {
536
- this.closed = { code, reason };
537
- }
538
- }
539
-
540
- function installFakeWebSocket(): () => void {
541
- const original = (globalThis as { WebSocket?: unknown }).WebSocket;
542
- FakeWebSocket.last = null;
543
- (globalThis as { WebSocket?: unknown }).WebSocket = FakeWebSocket;
544
- return () => {
545
- (globalThis as { WebSocket?: unknown }).WebSocket = original;
546
- };
547
- }
548
395
  describe('setSocketGuard', () => {
549
396
  it('installs and removes the core notice hook', () => {
550
397
  const notices: string[] = [];
@@ -552,10 +399,10 @@ describe('setSocketGuard', () => {
552
399
  const unsupported = fakeBackend();
553
400
  unsupported.openReturnsNull = true;
554
401
  const host = hostOf(unsupported.backend);
555
- createSocket(host, { url: 'tcp://x' });
402
+ createSocket(host.net.socket, { url: 'tcp://x' });
556
403
 
557
404
  const supported = fakeBackend();
558
- const socket = createSocket(hostOf(supported.backend), { url: 'ws://x' });
405
+ const socket = createSocket(hostOf(supported.backend).net.socket, { url: 'ws://x' });
559
406
  disposeSocket(socket);
560
407
  closeSocket(socket);
561
408
  sendSocketMessage(socket, 'x');
@@ -1,8 +1,8 @@
1
- import type { HasNetSocket, SocketBackend, SocketConnection, SocketEventSink } from '@flighthq/types/contract';
1
+ import type { HostSocketProvider, SocketConnection, SocketEventSink } from '@flighthq/types/contract';
2
2
 
3
3
  import { createSocket, getSocketReadyState } from './socket';
4
4
 
5
- function recordingBackend(label: string, opened: string[]): SocketBackend {
5
+ function recordingBackend(label: string, opened: string[]): HostSocketProvider {
6
6
  return {
7
7
  openSocket(_options, events: SocketEventSink): SocketConnection | null {
8
8
  opened.push(label);
@@ -17,14 +17,16 @@ function recordingBackend(label: string, opened: string[]): SocketBackend {
17
17
  };
18
18
  }
19
19
 
20
- function hostWith(backend: SocketBackend | undefined): HasNetSocket {
21
- return { net: backend === undefined ? {} : { socket: backend } } as HasNetSocket;
20
+ function hostWith(backend: HostSocketProvider | undefined): { readonly net: { readonly socket: HostSocketProvider } } {
21
+ return { net: backend === undefined ? {} : { socket: backend } } as {
22
+ readonly net: { readonly socket: HostSocketProvider };
23
+ };
22
24
  }
23
25
 
24
26
  describe('createSocket', () => {
25
27
  it('opens through the provider carried by the host it is given', () => {
26
28
  const opened: string[] = [];
27
- createSocket(hostWith(recordingBackend('a', opened)), { url: 'wss://example.test' });
29
+ createSocket(hostWith(recordingBackend('a', opened)).net.socket, { url: 'wss://example.test' });
28
30
  expect(opened).toEqual(['a']);
29
31
  });
30
32
 
@@ -33,8 +35,8 @@ describe('createSocket', () => {
33
35
  // it carried — this is the property the migration exists to create.
34
36
  it('keeps two hosts independent', () => {
35
37
  const opened: string[] = [];
36
- createSocket(hostWith(recordingBackend('first', opened)), { url: 'wss://one.test' });
37
- createSocket(hostWith(recordingBackend('second', opened)), { url: 'wss://two.test' });
38
+ createSocket(hostWith(recordingBackend('first', opened)).net.socket, { url: 'wss://one.test' });
39
+ createSocket(hostWith(recordingBackend('second', opened)).net.socket, { url: 'wss://two.test' });
38
40
  expect(opened).toEqual(['first', 'second']);
39
41
  });
40
42
 
@@ -42,7 +44,7 @@ describe('createSocket', () => {
42
44
  // quietly reaching a process-global web backend. The socket stays 'connecting', which is the
43
45
  // documented shape for a backend that cannot open the transport.
44
46
  it('yields no connection when the host carries no socket provider', () => {
45
- const socket = createSocket(hostWith(undefined), { url: 'wss://absent.test' });
47
+ const socket = createSocket(hostWith(undefined).net.socket, { url: 'wss://absent.test' });
46
48
  expect(socket.runtime.connection).toBeNull();
47
49
  expect(getSocketReadyState(socket)).toBe('connecting');
48
50
  });
@@ -50,7 +52,7 @@ describe('createSocket', () => {
50
52
  it('does not consult one host provider when another host is passed', () => {
51
53
  const opened: string[] = [];
52
54
  const unused = recordingBackend('unused', opened);
53
- createSocket(hostWith(recordingBackend('used', opened)), { url: 'wss://x.test' });
55
+ createSocket(hostWith(recordingBackend('used', opened)).net.socket, { url: 'wss://x.test' });
54
56
  expect(opened).not.toContain('unused');
55
57
  expect(unused).toBeDefined();
56
58
  });