snapreq 0.0.1 → 0.0.3
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 +16 -3
- package/package.json +21 -4
- package/src/websocket/websocket-client.js +10 -5
- package/types/capabilities.d.ts +47 -0
- package/types/errors.d.ts +64 -0
- package/types/headers.d.ts +50 -0
- package/types/request.d.ts +35 -0
- package/types/response.d.ts +74 -0
- package/types/retry.d.ts +73 -0
- package/types/snap-req.d.ts +233 -0
- package/types/transports/fetch-transport.d.ts +35 -0
- package/types/transports/node-transport.d.ts +112 -0
- package/types/transports/select.d.ts +38 -0
- package/types/transports/xhr-transport.d.ts +25 -0
- package/types/websocket/websocket-channel.d.ts +92 -0
- package/types/websocket/websocket-client.d.ts +364 -0
- package/types/websocket/websocket-connection.d.ts +94 -0
- package/src/index.js +0 -22
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A small WebSocket client that mirrors simple HTTP-style calls and channel
|
|
3
|
+
* subscriptions over `globalThis.WebSocket`, so the same code runs on web, Expo
|
|
4
|
+
* / React Native and Node. Supports optional auto-reconnect with exponential
|
|
5
|
+
* backoff, session resumption and listener re-subscription.
|
|
6
|
+
*
|
|
7
|
+
* Response bodies are returned as raw parsed JSON; apps that need their own
|
|
8
|
+
* (de)serialization should apply it around `post`/`get` and the response
|
|
9
|
+
* `json()`.
|
|
10
|
+
*/
|
|
11
|
+
export default class SnapReqWebSocketClient {
|
|
12
|
+
/**
|
|
13
|
+
* @param {object} args - Options object.
|
|
14
|
+
* @param {string} args.url - Full WebSocket URL, e.g. `ws://localhost:3006/websocket`.
|
|
15
|
+
* @param {boolean} [args.autoReconnect] - Enable auto-reconnect with exponential backoff.
|
|
16
|
+
* @param {boolean} [args.debug] - Whether to log debug output.
|
|
17
|
+
* @param {{getIsOnline?: () => boolean | Promise<boolean>, subscribe?: (callback: (isOnline: boolean) => void) => (() => void) | {remove: () => void}}} [args.networkMonitor] - Optional online-state adapter. When provided, auto-reconnect can wait for the network to report online before reconnecting, and open sockets are closed when the monitor reports offline.
|
|
18
|
+
* @param {number[]} [args.reconnectDelays] - Backoff delays in ms (default: [1000, 2000, 4000, 8000, 15000]).
|
|
19
|
+
* @param {{get: () => string | null | undefined | Promise<string | null | undefined>, set: (sessionId: string) => void | Promise<void>, clear: () => void | Promise<void>}} [args.sessionStore] - Optional sessionId persistence hook surviving reloads (localStorage, a cookie, SQLite, etc.).
|
|
20
|
+
* @param {(value: any) => any} [args.deserialize] - Optional transform applied to a response body inside `response.json()`. Lets an app re-hydrate its own wire format. Defaults to identity.
|
|
21
|
+
*/
|
|
22
|
+
constructor({ autoReconnect, debug, deserialize, networkMonitor, reconnectDelays, sessionStore, url }?: {
|
|
23
|
+
url: string;
|
|
24
|
+
autoReconnect?: boolean;
|
|
25
|
+
debug?: boolean;
|
|
26
|
+
networkMonitor?: {
|
|
27
|
+
getIsOnline?: () => boolean | Promise<boolean>;
|
|
28
|
+
subscribe?: (callback: (isOnline: boolean) => void) => (() => void) | {
|
|
29
|
+
remove: () => void;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
reconnectDelays?: number[];
|
|
33
|
+
sessionStore?: {
|
|
34
|
+
get: () => string | null | undefined | Promise<string | null | undefined>;
|
|
35
|
+
set: (sessionId: string) => void | Promise<void>;
|
|
36
|
+
clear: () => void | Promise<void>;
|
|
37
|
+
};
|
|
38
|
+
deserialize?: (value: any) => any;
|
|
39
|
+
});
|
|
40
|
+
/** @type {Map<string, {reject: (error: unknown) => void, resolve: (response: SnapReqWebSocketResponse) => void}>} */
|
|
41
|
+
pendingRequests: Map<string, {
|
|
42
|
+
reject: (error: unknown) => void;
|
|
43
|
+
resolve: (response: SnapReqWebSocketResponse) => void;
|
|
44
|
+
}>;
|
|
45
|
+
/** @type {Map<string, {reject: (error: unknown) => void, resolve: (value?: void) => void}>} */
|
|
46
|
+
pendingSubscriptions: Map<string, {
|
|
47
|
+
reject: (error: unknown) => void;
|
|
48
|
+
resolve: (value?: void) => void;
|
|
49
|
+
}>;
|
|
50
|
+
/** @type {Map<string, {callbacks: Set<(payload: any) => void>, channel: string, params: Record<string, any> | undefined, ready: Promise<void>}>} */
|
|
51
|
+
listeners: Map<string, {
|
|
52
|
+
callbacks: Set<(payload: any) => void>;
|
|
53
|
+
channel: string;
|
|
54
|
+
params: Record<string, any> | undefined;
|
|
55
|
+
ready: Promise<void>;
|
|
56
|
+
}>;
|
|
57
|
+
/** @type {(value: any) => any} */
|
|
58
|
+
_deserialize: (value: any) => any;
|
|
59
|
+
/** @type {boolean} */
|
|
60
|
+
autoReconnect: boolean;
|
|
61
|
+
debug: boolean;
|
|
62
|
+
/** @type {number | null} */
|
|
63
|
+
disconnectedSince: number | null;
|
|
64
|
+
/** @type {number} */
|
|
65
|
+
reconnectAttempt: number;
|
|
66
|
+
/** @type {number} */
|
|
67
|
+
connectionAttempts: number;
|
|
68
|
+
/** @type {number[]} */
|
|
69
|
+
reconnectDelays: number[];
|
|
70
|
+
/** @type {ReturnType<typeof setTimeout> | null} */
|
|
71
|
+
reconnectTimer: ReturnType<typeof setTimeout> | null;
|
|
72
|
+
url: string;
|
|
73
|
+
nextID: number;
|
|
74
|
+
/** @type {(() => void | Promise<void>) | null} */
|
|
75
|
+
onReconnect: (() => void | Promise<void>) | null;
|
|
76
|
+
/** @type {Record<string, any>} */
|
|
77
|
+
_metadata: Record<string, any>;
|
|
78
|
+
/** @type {Map<string, SnapReqWebSocketConnection>} */
|
|
79
|
+
_connections: Map<string, SnapReqWebSocketConnection>;
|
|
80
|
+
/** @type {Map<string, SnapReqWebSocketChannel>} */
|
|
81
|
+
_channelSubscriptions: Map<string, SnapReqWebSocketChannel>;
|
|
82
|
+
_nextConnectionIdSeq: number;
|
|
83
|
+
_nextSubscriptionIdSeq: number;
|
|
84
|
+
/** @type {string | null} - sessionId received from `session-established`; sent on reconnect for resumption. */
|
|
85
|
+
_sessionId: string | null;
|
|
86
|
+
/** @type {boolean} - true between a reconnect and the session-resumed / session-gone reply. */
|
|
87
|
+
_awaitingResume: boolean;
|
|
88
|
+
/** @type {boolean} - true once the current socket has an active session ready for app messages. */
|
|
89
|
+
_sessionReady: boolean;
|
|
90
|
+
/** @type {string | null} - provisional session id announced before a resume attempt finishes. */
|
|
91
|
+
_pendingSessionId: string | null;
|
|
92
|
+
/** @type {Promise<void> | null} */
|
|
93
|
+
_sessionReadyPromise: Promise<void> | null;
|
|
94
|
+
/** @type {(() => void) | null} */
|
|
95
|
+
_resolveSessionReady: (() => void) | null;
|
|
96
|
+
/** @type {unknown | null} */
|
|
97
|
+
_sessionReadyError: unknown | null;
|
|
98
|
+
/** @type {{get: () => string | null | undefined | Promise<string | null | undefined>, set: (sessionId: string) => void | Promise<void>, clear: () => void | Promise<void>} | undefined} */
|
|
99
|
+
_sessionStore: {
|
|
100
|
+
get: () => string | null | undefined | Promise<string | null | undefined>;
|
|
101
|
+
set: (sessionId: string) => void | Promise<void>;
|
|
102
|
+
clear: () => void | Promise<void>;
|
|
103
|
+
} | undefined;
|
|
104
|
+
/** @type {boolean} - true once the sessionStore has been consulted for a restored id. */
|
|
105
|
+
_sessionStoreRestored: boolean;
|
|
106
|
+
/** @type {{getIsOnline?: () => boolean | Promise<boolean>, subscribe?: (callback: (isOnline: boolean) => void) => (() => void) | {remove: () => void}} | undefined} */
|
|
107
|
+
_networkMonitor: {
|
|
108
|
+
getIsOnline?: () => boolean | Promise<boolean>;
|
|
109
|
+
subscribe?: (callback: (isOnline: boolean) => void) => (() => void) | {
|
|
110
|
+
remove: () => void;
|
|
111
|
+
};
|
|
112
|
+
} | undefined;
|
|
113
|
+
/** @type {null | (() => void) | {remove: () => void}} */
|
|
114
|
+
_networkMonitorSubscription: null | (() => void) | {
|
|
115
|
+
remove: () => void;
|
|
116
|
+
};
|
|
117
|
+
/** @type {boolean} */
|
|
118
|
+
_waitingForOnline: boolean;
|
|
119
|
+
/** @returns {boolean} - Whether the socket is open. */
|
|
120
|
+
isOpen(): boolean;
|
|
121
|
+
/** @returns {boolean} - Whether the session is ready for app messages. */
|
|
122
|
+
isSessionReady(): boolean;
|
|
123
|
+
/**
|
|
124
|
+
* Opens a 1:1 connection of the given type against the server. Requires the
|
|
125
|
+
* socket to already be connected (call `connect()` first).
|
|
126
|
+
* @param {string} connectionType - Name the server registered the class under.
|
|
127
|
+
* @param {{params?: Record<string, any>, onConnect?: () => void, onMessage?: (body: any) => void, onDisconnect?: () => void, onResume?: () => void, onClose?: (reason: string) => void}} [options] - Connection options.
|
|
128
|
+
* @returns {SnapReqWebSocketConnection} - The connection handle.
|
|
129
|
+
*/
|
|
130
|
+
openConnection(connectionType: string, options?: {
|
|
131
|
+
params?: Record<string, any>;
|
|
132
|
+
onConnect?: () => void;
|
|
133
|
+
onMessage?: (body: any) => void;
|
|
134
|
+
onDisconnect?: () => void;
|
|
135
|
+
onResume?: () => void;
|
|
136
|
+
onClose?: (reason: string) => void;
|
|
137
|
+
}): SnapReqWebSocketConnection;
|
|
138
|
+
/**
|
|
139
|
+
* Drops a connection handle from the registry.
|
|
140
|
+
* @param {string} connectionId - The connection id.
|
|
141
|
+
* @returns {void}
|
|
142
|
+
*/
|
|
143
|
+
_removeConnection(connectionId: string): void;
|
|
144
|
+
/**
|
|
145
|
+
* Subscribes to a named channel. If the socket is not yet open, the
|
|
146
|
+
* subscription is queued and sent once a connection is established.
|
|
147
|
+
* @param {string} channelType - Name the server registered the channel under.
|
|
148
|
+
* @param {{params?: Record<string, any>, lastEventId?: string, onMessage?: (body: any) => void, onDisconnect?: () => void, onResume?: () => void, onClose?: (reason: string) => void}} [options] - Subscription options.
|
|
149
|
+
* @returns {SnapReqWebSocketChannel} - The subscription handle.
|
|
150
|
+
*/
|
|
151
|
+
subscribeChannel(channelType: string, options?: {
|
|
152
|
+
params?: Record<string, any>;
|
|
153
|
+
lastEventId?: string;
|
|
154
|
+
onMessage?: (body: any) => void;
|
|
155
|
+
onDisconnect?: () => void;
|
|
156
|
+
onResume?: () => void;
|
|
157
|
+
onClose?: (reason: string) => void;
|
|
158
|
+
}): SnapReqWebSocketChannel;
|
|
159
|
+
/**
|
|
160
|
+
* @param {string} subscriptionId - The subscription id.
|
|
161
|
+
* @returns {void}
|
|
162
|
+
*/
|
|
163
|
+
_removeChannelSubscription(subscriptionId: string): void;
|
|
164
|
+
/**
|
|
165
|
+
* @param {SnapReqWebSocketChannel} subscription - The subscription to send.
|
|
166
|
+
* @returns {void}
|
|
167
|
+
*/
|
|
168
|
+
_sendChannelSubscribe(subscription: SnapReqWebSocketChannel): void;
|
|
169
|
+
/** @returns {void} */
|
|
170
|
+
_sendPendingChannelSubscriptions(): void;
|
|
171
|
+
/** @returns {Promise<boolean>} - Whether the network reports online. */
|
|
172
|
+
_isOnline(): Promise<boolean>;
|
|
173
|
+
/** @returns {Promise<boolean>} - Whether reconnect should wait for online. */
|
|
174
|
+
_shouldWaitForOnline(): Promise<boolean>;
|
|
175
|
+
/** @returns {void} */
|
|
176
|
+
_ensureNetworkMonitorSubscription(): void;
|
|
177
|
+
/** @returns {void} */
|
|
178
|
+
_teardownNetworkMonitorSubscription(): void;
|
|
179
|
+
/**
|
|
180
|
+
* Sets a global metadata value that is sent to the server. When the socket is
|
|
181
|
+
* open, a metadata update message is sent immediately.
|
|
182
|
+
* @param {string} key - Metadata key.
|
|
183
|
+
* @param {any} value - Metadata value (null to clear).
|
|
184
|
+
* @returns {void}
|
|
185
|
+
*/
|
|
186
|
+
setMetadata(key: string, value: any): void;
|
|
187
|
+
/** @returns {Record<string, any>} - Current metadata. */
|
|
188
|
+
getMetadata(): Record<string, any>;
|
|
189
|
+
/**
|
|
190
|
+
* Ensures a WebSocket connection is open. Auto-reconnect and online gating are
|
|
191
|
+
* enabled by default.
|
|
192
|
+
* @param {{autoReconnect?: boolean, waitForOnline?: boolean, resetReconnectState?: boolean}} [options] - Connect options.
|
|
193
|
+
* @returns {Promise<void>} - Resolves once connected and the session is ready.
|
|
194
|
+
*/
|
|
195
|
+
connect({ autoReconnect, waitForOnline, resetReconnectState }?: {
|
|
196
|
+
autoReconnect?: boolean;
|
|
197
|
+
waitForOnline?: boolean;
|
|
198
|
+
resetReconnectState?: boolean;
|
|
199
|
+
}): Promise<void>;
|
|
200
|
+
connectPromise: Promise<any>;
|
|
201
|
+
socket: WebSocket;
|
|
202
|
+
/**
|
|
203
|
+
* Closes the WebSocket and clears pending state.
|
|
204
|
+
* @returns {Promise<void>} - Resolves once closed.
|
|
205
|
+
*/
|
|
206
|
+
close(): Promise<void>;
|
|
207
|
+
/**
|
|
208
|
+
* Disables auto-reconnect and closes the WebSocket.
|
|
209
|
+
* @returns {Promise<void>} - Resolves once closed.
|
|
210
|
+
*/
|
|
211
|
+
disconnectAndStopReconnect(): Promise<void>;
|
|
212
|
+
/**
|
|
213
|
+
* Closes the raw socket without disabling auto-reconnect. Used by tests to
|
|
214
|
+
* simulate an unexpected network drop.
|
|
215
|
+
* @returns {Promise<void>} - Resolves once the socket has closed.
|
|
216
|
+
*/
|
|
217
|
+
dropConnection(): Promise<void>;
|
|
218
|
+
/**
|
|
219
|
+
* Performs a POST request over the WebSocket.
|
|
220
|
+
* @param {string} path - Path.
|
|
221
|
+
* @param {any} [body] - Request body.
|
|
222
|
+
* @param {{headers?: Record<string, string>}} [options] - Request options such as headers.
|
|
223
|
+
* @returns {Promise<SnapReqWebSocketResponse>} - The response.
|
|
224
|
+
*/
|
|
225
|
+
post(path: string, body?: any, options?: {
|
|
226
|
+
headers?: Record<string, string>;
|
|
227
|
+
}): Promise<SnapReqWebSocketResponse>;
|
|
228
|
+
/**
|
|
229
|
+
* Performs a GET request over the WebSocket.
|
|
230
|
+
* @param {string} path - Path.
|
|
231
|
+
* @param {{headers?: Record<string, string>}} [options] - Request options such as headers.
|
|
232
|
+
* @returns {Promise<SnapReqWebSocketResponse>} - The response.
|
|
233
|
+
*/
|
|
234
|
+
get(path: string, options?: {
|
|
235
|
+
headers?: Record<string, string>;
|
|
236
|
+
}): Promise<SnapReqWebSocketResponse>;
|
|
237
|
+
/**
|
|
238
|
+
* Subscribes to a channel for server-sent events.
|
|
239
|
+
* @param {string} channel - Channel name.
|
|
240
|
+
* @param {(payload: any) => void} callback - Callback function.
|
|
241
|
+
* @returns {() => void} - Unsubscribe function.
|
|
242
|
+
*/
|
|
243
|
+
on(channel: string, callback: (payload: any) => void): () => void;
|
|
244
|
+
/**
|
|
245
|
+
* Returns a snapshot of the client's connection state.
|
|
246
|
+
* @returns {{disconnectedSince: number | null, isOpen: boolean, listenerCount: number}} - State snapshot.
|
|
247
|
+
*/
|
|
248
|
+
state(): {
|
|
249
|
+
disconnectedSince: number | null;
|
|
250
|
+
isOpen: boolean;
|
|
251
|
+
listenerCount: number;
|
|
252
|
+
};
|
|
253
|
+
/**
|
|
254
|
+
* Subscribes to a channel for server-sent events with optional params.
|
|
255
|
+
* @param {string} channel - Channel name.
|
|
256
|
+
* @param {{lastEventId?: string, params?: Record<string, any>}} options - Subscription options.
|
|
257
|
+
* @param {(payload: any, message?: Record<string, any>) => void} callback - Callback function.
|
|
258
|
+
* @returns {(() => void) & {ready: Promise<void>}} - Unsubscribe function with readiness promise.
|
|
259
|
+
*/
|
|
260
|
+
subscribe(channel: string, options: {
|
|
261
|
+
lastEventId?: string;
|
|
262
|
+
params?: Record<string, any>;
|
|
263
|
+
}, callback: (payload: any, message?: Record<string, any>) => void): (() => void) & {
|
|
264
|
+
ready: Promise<void>;
|
|
265
|
+
};
|
|
266
|
+
/**
|
|
267
|
+
* Subscribes to a channel and waits until the server acknowledges it.
|
|
268
|
+
* @param {string} channel - Channel name.
|
|
269
|
+
* @param {{lastEventId?: string, params?: Record<string, any>}} options - Subscription options.
|
|
270
|
+
* @param {(payload: any, message?: Record<string, any>) => void} callback - Callback function.
|
|
271
|
+
* @returns {Promise<(() => void) & {ready: Promise<void>}>} - Ready unsubscribe handle.
|
|
272
|
+
*/
|
|
273
|
+
subscribeAndWait(channel: string, options: {
|
|
274
|
+
lastEventId?: string;
|
|
275
|
+
params?: Record<string, any>;
|
|
276
|
+
}, callback: (payload: any, message?: Record<string, any>) => void): Promise<(() => void) & {
|
|
277
|
+
ready: Promise<void>;
|
|
278
|
+
}>;
|
|
279
|
+
/**
|
|
280
|
+
* @param {string} method - HTTP method.
|
|
281
|
+
* @param {string} path - Path.
|
|
282
|
+
* @param {object} [options] - Options object.
|
|
283
|
+
* @param {any} [options.body] - Request body.
|
|
284
|
+
* @param {Record<string, string>} [options.headers] - Header list.
|
|
285
|
+
* @returns {Promise<SnapReqWebSocketResponse>} - The response.
|
|
286
|
+
*/
|
|
287
|
+
request(method: string, path: string, { body, headers }?: {
|
|
288
|
+
body?: any;
|
|
289
|
+
headers?: Record<string, string>;
|
|
290
|
+
}): Promise<SnapReqWebSocketResponse>;
|
|
291
|
+
/**
|
|
292
|
+
* @param {MessageEvent<any>} event - Event payload.
|
|
293
|
+
* @returns {void}
|
|
294
|
+
*/
|
|
295
|
+
onMessage: (event: MessageEvent<any>) => void;
|
|
296
|
+
/**
|
|
297
|
+
* @param {string} channel - Channel name.
|
|
298
|
+
* @param {Record<string, any> | undefined} params - Subscription params.
|
|
299
|
+
* @returns {string} - Stable subscription key.
|
|
300
|
+
*/
|
|
301
|
+
_subscriptionKey(channel: string, params: Record<string, any> | undefined): string;
|
|
302
|
+
/**
|
|
303
|
+
* Rejects all pending requests when the socket closes. Schedules reconnect if
|
|
304
|
+
* enabled.
|
|
305
|
+
* @returns {void}
|
|
306
|
+
*/
|
|
307
|
+
onClose: () => void;
|
|
308
|
+
/**
|
|
309
|
+
* @param {Record<string, any>} payload - Payload data.
|
|
310
|
+
* @returns {void}
|
|
311
|
+
*/
|
|
312
|
+
_sendMessage(payload: Record<string, any>): void;
|
|
313
|
+
/** @returns {void} */
|
|
314
|
+
_cancelPendingReconnect(): void;
|
|
315
|
+
/** @returns {void} */
|
|
316
|
+
_scheduleReconnect(): void;
|
|
317
|
+
/** @returns {Promise<void>} */
|
|
318
|
+
_attemptReconnect(): Promise<void>;
|
|
319
|
+
/**
|
|
320
|
+
* Re-sends subscribe messages for all active listeners after reconnection.
|
|
321
|
+
* @returns {void}
|
|
322
|
+
*/
|
|
323
|
+
_resubscribeActiveListeners(): void;
|
|
324
|
+
/**
|
|
325
|
+
* @param {...any} args - Log arguments.
|
|
326
|
+
* @returns {void}
|
|
327
|
+
*/
|
|
328
|
+
_debug(...args: any[]): void;
|
|
329
|
+
/**
|
|
330
|
+
* @param {string} sessionId - Id to persist through the configured sessionStore.
|
|
331
|
+
* @returns {void}
|
|
332
|
+
*/
|
|
333
|
+
_persistSessionId(sessionId: string): void;
|
|
334
|
+
/** @returns {void} */
|
|
335
|
+
_clearPersistedSessionId(): void;
|
|
336
|
+
/** @returns {Promise<void>} - Resolves once the session is ready. */
|
|
337
|
+
_waitForSessionReady(): Promise<void>;
|
|
338
|
+
/** @returns {void} */
|
|
339
|
+
_markSessionReady(): void;
|
|
340
|
+
/**
|
|
341
|
+
* @param {unknown} [error] - Reason for the reset.
|
|
342
|
+
* @returns {void}
|
|
343
|
+
*/
|
|
344
|
+
_resetSessionReadyState(error?: unknown): void;
|
|
345
|
+
}
|
|
346
|
+
/** A response to a request made over the WebSocket transport. */
|
|
347
|
+
export class SnapReqWebSocketResponse {
|
|
348
|
+
/**
|
|
349
|
+
* @param {object} message - The response message.
|
|
350
|
+
* @param {(value: any) => any} [deserialize] - Transform applied to the parsed body in `json()`. Defaults to identity.
|
|
351
|
+
*/
|
|
352
|
+
constructor(message: object, deserialize?: (value: any) => any);
|
|
353
|
+
body: any;
|
|
354
|
+
headers: Record<string, any>;
|
|
355
|
+
id: string | number;
|
|
356
|
+
statusCode: number;
|
|
357
|
+
statusMessage: string;
|
|
358
|
+
type: string;
|
|
359
|
+
_deserialize: (value: any) => any;
|
|
360
|
+
/** @returns {any} - The parsed (and optionally deserialized) JSON body. */
|
|
361
|
+
json(): any;
|
|
362
|
+
}
|
|
363
|
+
import SnapReqWebSocketConnection from "./websocket-connection.js";
|
|
364
|
+
import SnapReqWebSocketChannel from "./websocket-channel.js";
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-side handle for a 1:1 connection opened via
|
|
3
|
+
* `SnapReqWebSocketClient.openConnection()`. Mirrors the server's connection
|
|
4
|
+
* lifecycle — `onConnect` / `onMessage` / `onClose` plus `sendMessage` /
|
|
5
|
+
* `close`.
|
|
6
|
+
*/
|
|
7
|
+
export default class SnapReqWebSocketConnection {
|
|
8
|
+
/**
|
|
9
|
+
* @param {object} args - Connection arguments.
|
|
10
|
+
* @param {import("./websocket-client.js").default} args.client - Owning client.
|
|
11
|
+
* @param {string} args.connectionId - Generated id unique within the session.
|
|
12
|
+
* @param {string} args.connectionType - Name the server registered the class under.
|
|
13
|
+
* @param {Record<string, any>} [args.params] - Opaque params forwarded to the server.
|
|
14
|
+
* @param {() => void} [args.onConnect] - Fired after the server confirms `connection-opened`.
|
|
15
|
+
* @param {(body: any) => void} [args.onMessage] - Fired on each `connection-message` from the server.
|
|
16
|
+
* @param {() => void} [args.onDisconnect] - Fired when the socket drops; connection is preserved pending resume.
|
|
17
|
+
* @param {() => void} [args.onResume] - Fired when the session successfully resumes after a drop.
|
|
18
|
+
* @param {(reason: string) => void} [args.onClose] - Fired exactly once when the handle closes permanently.
|
|
19
|
+
*/
|
|
20
|
+
constructor({ client, connectionId, connectionType, params, onConnect, onMessage, onDisconnect, onResume, onClose }: {
|
|
21
|
+
client: import("./websocket-client.js").default;
|
|
22
|
+
connectionId: string;
|
|
23
|
+
connectionType: string;
|
|
24
|
+
params?: Record<string, any>;
|
|
25
|
+
onConnect?: () => void;
|
|
26
|
+
onMessage?: (body: any) => void;
|
|
27
|
+
onDisconnect?: () => void;
|
|
28
|
+
onResume?: () => void;
|
|
29
|
+
onClose?: (reason: string) => void;
|
|
30
|
+
});
|
|
31
|
+
client: import("./websocket-client.js").default;
|
|
32
|
+
connectionId: string;
|
|
33
|
+
connectionType: string;
|
|
34
|
+
params: Record<string, any>;
|
|
35
|
+
_onConnect: () => void;
|
|
36
|
+
_onMessage: (body: any) => void;
|
|
37
|
+
_onDisconnect: () => void;
|
|
38
|
+
_onResume: () => void;
|
|
39
|
+
_onClose: (reason: string) => void;
|
|
40
|
+
_connected: boolean;
|
|
41
|
+
_closed: boolean;
|
|
42
|
+
/** @type {Promise<void>} - Resolves once the server sends `connection-opened`. */
|
|
43
|
+
ready: Promise<void>;
|
|
44
|
+
_resolveReady: (value: void | PromiseLike<void>) => void;
|
|
45
|
+
_rejectReady: (reason?: any) => void;
|
|
46
|
+
/**
|
|
47
|
+
* Called by the client dispatcher when `{type: "connection-opened"}` arrives.
|
|
48
|
+
* Fires the user's `onConnect` and resolves `ready`.
|
|
49
|
+
* @returns {void}
|
|
50
|
+
*/
|
|
51
|
+
_handleOpened(): void;
|
|
52
|
+
/**
|
|
53
|
+
* Called by the client dispatcher for each `connection-message` targeted at
|
|
54
|
+
* this connection id.
|
|
55
|
+
* @param {any} body - Message payload.
|
|
56
|
+
* @returns {void}
|
|
57
|
+
*/
|
|
58
|
+
_handleMessage(body: any): void;
|
|
59
|
+
/**
|
|
60
|
+
* Called by the client when the underlying socket drops. The connection stays
|
|
61
|
+
* alive pending session resume.
|
|
62
|
+
* @returns {void}
|
|
63
|
+
*/
|
|
64
|
+
_handleDisconnected(): void;
|
|
65
|
+
/**
|
|
66
|
+
* Called by the client after `session-resumed` confirms the server still has
|
|
67
|
+
* this connection.
|
|
68
|
+
* @returns {void}
|
|
69
|
+
*/
|
|
70
|
+
_handleResumed(): void;
|
|
71
|
+
/**
|
|
72
|
+
* Called by the client dispatcher when the connection closes for any reason.
|
|
73
|
+
* Fires `onClose(reason)` at most once.
|
|
74
|
+
* @param {string} reason - Why the connection closed.
|
|
75
|
+
* @returns {void}
|
|
76
|
+
*/
|
|
77
|
+
_handleClosed(reason: string): void;
|
|
78
|
+
/**
|
|
79
|
+
* Sends a message to the server side of this connection.
|
|
80
|
+
* @param {any} body - Message payload.
|
|
81
|
+
* @returns {void}
|
|
82
|
+
*/
|
|
83
|
+
sendMessage(body: any): void;
|
|
84
|
+
/**
|
|
85
|
+
* Closes the connection from the client side. Fires `onClose("client_close")`
|
|
86
|
+
* locally and notifies the server. No-op if already closed.
|
|
87
|
+
* @returns {void}
|
|
88
|
+
*/
|
|
89
|
+
close(): void;
|
|
90
|
+
/** @returns {boolean} - Whether the connection is closed. */
|
|
91
|
+
isClosed(): boolean;
|
|
92
|
+
/** @returns {boolean} - Whether the connection is open. */
|
|
93
|
+
isConnected(): boolean;
|
|
94
|
+
}
|
package/src/index.js
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
|
-
import SnapReq from "./snap-req.js"
|
|
4
|
-
|
|
5
|
-
export default SnapReq
|
|
6
|
-
export {default as SnapReq} from "./snap-req.js"
|
|
7
|
-
export {default as SnapReqResponse} from "./response.js"
|
|
8
|
-
export {default as SnapReqHeaders} from "./headers.js"
|
|
9
|
-
export {
|
|
10
|
-
SnapReqError,
|
|
11
|
-
SnapReqHttpError,
|
|
12
|
-
SnapReqUnsupportedFeatureError,
|
|
13
|
-
SnapReqAbortError
|
|
14
|
-
} from "./errors.js"
|
|
15
|
-
export {defaultRetryableError} from "./retry.js"
|
|
16
|
-
export {detectRuntime, selectTransport} from "./transports/select.js"
|
|
17
|
-
export {default as FetchTransport} from "./transports/fetch-transport.js"
|
|
18
|
-
export {default as XhrTransport} from "./transports/xhr-transport.js"
|
|
19
|
-
|
|
20
|
-
// The WebSocket client is exported from its own module so importing the HTTP
|
|
21
|
-
// client never pulls WebSocket code into a bundle that does not need it.
|
|
22
|
-
export {default as SnapReqWebSocketClient} from "./websocket/websocket-client.js"
|