@rest-vir/define-service 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/LICENSE-CC0 +121 -0
  2. package/LICENSE-MIT +21 -0
  3. package/README.md +88 -0
  4. package/dist/augments/json.d.ts +8 -0
  5. package/dist/augments/json.js +13 -0
  6. package/dist/dev-port/find-dev-port.d.ts +132 -0
  7. package/dist/dev-port/find-dev-port.js +156 -0
  8. package/dist/endpoint/endpoint-path.d.ts +27 -0
  9. package/dist/endpoint/endpoint-path.js +14 -0
  10. package/dist/endpoint/endpoint.d.ts +198 -0
  11. package/dist/endpoint/endpoint.js +80 -0
  12. package/dist/frontend-connect/connect-web-socket.d.ts +95 -0
  13. package/dist/frontend-connect/connect-web-socket.js +64 -0
  14. package/dist/frontend-connect/fetch-endpoint.d.ts +199 -0
  15. package/dist/frontend-connect/fetch-endpoint.js +135 -0
  16. package/dist/frontend-connect/generate-api.d.ts +102 -0
  17. package/dist/frontend-connect/generate-api.js +83 -0
  18. package/dist/frontend-connect/mock-client-web-socket.d.ts +187 -0
  19. package/dist/frontend-connect/mock-client-web-socket.js +198 -0
  20. package/dist/frontend-connect/web-socket-protocol-parse.d.ts +10 -0
  21. package/dist/frontend-connect/web-socket-protocol-parse.js +111 -0
  22. package/dist/index.d.ts +23 -0
  23. package/dist/index.js +23 -0
  24. package/dist/service/define-service.d.ts +19 -0
  25. package/dist/service/define-service.js +133 -0
  26. package/dist/service/match-url.d.ts +30 -0
  27. package/dist/service/match-url.js +31 -0
  28. package/dist/service/minimal-service.d.ts +44 -0
  29. package/dist/service/minimal-service.js +1 -0
  30. package/dist/service/service-definition.d.ts +80 -0
  31. package/dist/service/service-definition.error.d.ts +35 -0
  32. package/dist/service/service-definition.error.js +34 -0
  33. package/dist/service/service-definition.js +1 -0
  34. package/dist/util/mock-fetch.d.ts +107 -0
  35. package/dist/util/mock-fetch.js +199 -0
  36. package/dist/util/no-param.d.ts +16 -0
  37. package/dist/util/no-param.js +8 -0
  38. package/dist/util/origin.d.ts +43 -0
  39. package/dist/util/origin.js +19 -0
  40. package/dist/util/path-to-regexp.d.ts +54 -0
  41. package/dist/util/path-to-regexp.js +307 -0
  42. package/dist/util/search-params.d.ts +9 -0
  43. package/dist/util/search-params.js +1 -0
  44. package/dist/web-socket/common-web-socket.d.ts +103 -0
  45. package/dist/web-socket/common-web-socket.js +28 -0
  46. package/dist/web-socket/overwrite-web-socket-methods.d.ts +276 -0
  47. package/dist/web-socket/overwrite-web-socket-methods.js +210 -0
  48. package/dist/web-socket/web-socket-definition.d.ts +170 -0
  49. package/dist/web-socket/web-socket-definition.js +78 -0
  50. package/package.json +68 -0
@@ -0,0 +1,135 @@
1
+ import { check } from '@augment-vir/assert';
2
+ import { addPrefix, filterMap, getObjectTypedEntries, HttpMethod, } from '@augment-vir/common';
3
+ import { assertValidShape } from 'object-shape-tester';
4
+ import { buildUrl } from 'url-vir';
5
+ function defaultFetch(...[url, requestInit,]) {
6
+ return fetch(url, requestInit);
7
+ }
8
+ /**
9
+ * Extracts an array of all allowed methods for the given endpoint definition.
10
+ *
11
+ * @category Internal
12
+ * @category Package : @rest-vir/define-service
13
+ * @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
14
+ */
15
+ export function getAllowedEndpointMethods(endpoint) {
16
+ return filterMap(getObjectTypedEntries(endpoint.methods), ([methodName,]) => methodName, (methodName, [, allowed,]) => allowed);
17
+ }
18
+ function filterToValidMethod(endpoint, chosenMethod) {
19
+ if (chosenMethod && (chosenMethod === HttpMethod.Options || endpoint.methods[chosenMethod])) {
20
+ return chosenMethod;
21
+ }
22
+ else if (chosenMethod) {
23
+ throw new Error(`Given HTTP method '${chosenMethod}' is not allowed for endpoint '${endpoint.path}' in service '${endpoint.service.serviceName}'`);
24
+ }
25
+ const allowedMethods = getAllowedEndpointMethods(endpoint);
26
+ if (check.isLengthExactly(allowedMethods, 1)) {
27
+ return allowedMethods[0];
28
+ }
29
+ else if (allowedMethods.length) {
30
+ throw new Error(`Endpoint '${endpoint.path}' in service '${endpoint.service.serviceName}' allows multiple HTTP methods, one must be chosen.`);
31
+ }
32
+ else {
33
+ throw new Error(`Endpoint '${endpoint.path}' in service '${endpoint.service.serviceName}' has no allowed HTTP methods. Requests cannot be sent.`);
34
+ }
35
+ }
36
+ /**
37
+ * Send a request to an endpoint definition with type safe parameters.
38
+ *
39
+ * This can safely be used in frontend _or_ backend code.
40
+ *
41
+ * @category Client (Frontend) Connection
42
+ * @category Package : @rest-vir/define-service
43
+ * @example
44
+ *
45
+ * ```ts
46
+ * import {fetchEndpoint} from '@rest-vir/define-service';
47
+ *
48
+ * const {data, response} = await fetchEndpoint(myService.endpoints['/my-endpoint']);
49
+ * ```
50
+ *
51
+ * @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
52
+ */
53
+ export async function fetchEndpoint(endpoint, ...params) {
54
+ const { requestData, fetch } = params[0] || {};
55
+ if (requestData) {
56
+ if (endpoint.requestDataShape) {
57
+ assertValidShape(requestData, endpoint.requestDataShape, { allowExtraKeys: true });
58
+ }
59
+ else {
60
+ throw new Error(`Request data was given but endpoint '${endpoint.path}' is not expecting any request data.`);
61
+ }
62
+ }
63
+ const { requestInit, url } = buildEndpointRequestInit(endpoint, ...params);
64
+ /* node:coverage ignore next: all tests mock fetch so we're never going to have a fallback here. */
65
+ const response = await (fetch || defaultFetch)(url, requestInit, endpoint);
66
+ const responseData = endpoint.responseDataShape ? await response.json() : undefined;
67
+ if (endpoint.responseDataShape) {
68
+ assertValidShape(responseData, endpoint.responseDataShape, { allowExtraKeys: true });
69
+ }
70
+ return {
71
+ data: responseData,
72
+ response,
73
+ };
74
+ }
75
+ /**
76
+ * Build request init and URL for fetching an endpoint. Used in {@link fetchEndpoint}.
77
+ *
78
+ * @category Internal
79
+ * @category Package : @rest-vir/define-service
80
+ * @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
81
+ */
82
+ export function buildEndpointRequestInit(endpoint, ...[{ method, options = {}, pathParams, requestData } = {},]) {
83
+ const headers = options.headers instanceof Headers
84
+ ? Object.fromEntries(options.headers.entries())
85
+ : check.isArray(options.headers)
86
+ ? Object.fromEntries(options.headers)
87
+ : options.headers || {};
88
+ const hasContentTypeHeader = Object.keys(headers).some((headerKey) => headerKey.toLowerCase() === 'content-type');
89
+ if (!hasContentTypeHeader && check.isObject(requestData)) {
90
+ headers['content-type'] = 'application/json';
91
+ }
92
+ const url = buildEndpointUrl(endpoint, { pathParams });
93
+ const requestInit = {
94
+ ...options,
95
+ headers,
96
+ method: filterToValidMethod(endpoint, method),
97
+ ...(requestData
98
+ ? {
99
+ body: JSON.stringify(requestData),
100
+ }
101
+ : {}),
102
+ };
103
+ return {
104
+ url,
105
+ requestInit,
106
+ };
107
+ }
108
+ /**
109
+ * Creates and finalizes a URL for sending fetches to the given endpoint.
110
+ *
111
+ * @category Internal
112
+ * @category Package : @rest-vir/define-service
113
+ * @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
114
+ */
115
+ export function buildEndpointUrl(endpoint, { pathParams, }) {
116
+ let pathParamsCount = 0;
117
+ const builtUrl = buildUrl(endpoint.service.serviceOrigin, {
118
+ pathname: endpoint.path.replaceAll(/\/:([^/]+)/g, (wholeMatch, paramName) => {
119
+ pathParamsCount++;
120
+ if (pathParams && check.hasKey(pathParams, paramName) && pathParams[paramName]) {
121
+ return addPrefix({
122
+ value: pathParams[paramName],
123
+ prefix: '/',
124
+ });
125
+ }
126
+ else {
127
+ throw new Error(`Missing value for path param '${paramName}'.`);
128
+ }
129
+ }),
130
+ }).href;
131
+ if (!pathParamsCount && pathParams) {
132
+ throw new Error(`Endpoint '${endpoint.path}' in service '${endpoint.service.serviceName}' does not allow any path params but some where set.`);
133
+ }
134
+ return builtUrl;
135
+ }
@@ -0,0 +1,102 @@
1
+ import { MaybePromise, Overwrite, PartialWithUndefined, type Values } from '@augment-vir/common';
2
+ import type { GenericEndpointDefinition } from '../endpoint/endpoint.js';
3
+ import type { ServiceDefinition } from '../service/service-definition.js';
4
+ import type { CommonWebSocket } from '../web-socket/common-web-socket.js';
5
+ import { ClientWebSocket, GenericConnectWebSocketParams } from '../web-socket/overwrite-web-socket-methods.js';
6
+ import type { WebSocketDefinition } from '../web-socket/web-socket-definition.js';
7
+ import { CollapsedConnectWebSocketParams } from './connect-web-socket.js';
8
+ import { CollapsedFetchEndpointParams, FetchEndpointOutput } from './fetch-endpoint.js';
9
+ /**
10
+ * An API generated by {@link generateApi}. This can be easily mocked by wrapping this API in
11
+ * {@link makeMockApi}.
12
+ *
13
+ * @category Internal
14
+ * @category Package : @rest-vir/define-service
15
+ * @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
16
+ */
17
+ export type RestVirApi<SpecificService extends ServiceDefinition> = {
18
+ endpoints: {
19
+ [EndpointPath in keyof SpecificService['endpoints']]: SpecificService['endpoints'][EndpointPath] extends GenericEndpointDefinition ? SpecificService['endpoints'][EndpointPath] & {
20
+ /** Send a fetch request to this endpoint. */
21
+ fetch(...params: CollapsedFetchEndpointParams<SpecificService['endpoints'][EndpointPath]>): Promise<FetchEndpointOutput<SpecificService['endpoints'][EndpointPath]>>;
22
+ } : never;
23
+ };
24
+ webSockets: {
25
+ [WebSocketPath in keyof SpecificService['webSockets']]: SpecificService['webSockets'][WebSocketPath] extends WebSocketDefinition ? SpecificService['webSockets'][WebSocketPath] & {
26
+ /** Connect to this WebSocket. */
27
+ connect(...params: CollapsedConnectWebSocketParams<SpecificService['webSockets'][WebSocketPath], false, globalThis.WebSocket>): Promise<ClientWebSocket<SpecificService['webSockets'][WebSocketPath], globalThis.WebSocket>>;
28
+ } : never;
29
+ };
30
+ };
31
+ /**
32
+ * Creates an API from the given service definition, with automatically generated endpoint fetch and
33
+ * WebSocket connect methods.
34
+ *
35
+ * Use this to ship auto-generated API objects to internal or external teams so they have type safe
36
+ * access to your REST and WebSocket server.
37
+ *
38
+ * The generated API can easily mocked by wrapping it in {@link makeMockApi}.
39
+ *
40
+ * @category Create API
41
+ * @category Package : @rest-vir/define-service
42
+ * @example
43
+ *
44
+ * ```ts
45
+ * import {generateApi} from '@rest-vir/define-service';
46
+ *
47
+ * export const myApi = generateApi(myServiceDefinition);
48
+ *
49
+ * myApi.endpoints['/my-endpoint'].fetch();
50
+ * myApi.webSockets['/my-web-socket'].connect();
51
+ * ```
52
+ *
53
+ * @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
54
+ */
55
+ export declare function generateApi<const SpecificService extends ServiceDefinition>(service: SpecificService): RestVirApi<SpecificService>;
56
+ /**
57
+ * Mock inputs for {@link makeMockApi}.
58
+ *
59
+ * @category Internal
60
+ * @category Package : @rest-vir/define-service
61
+ * @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
62
+ */
63
+ export type RestVirApiMocks<Api extends RestVirApi<any>, WebSocketClass extends CommonWebSocket> = PartialWithUndefined<{
64
+ /**
65
+ * A custom fetch mock that will override the default, if provided. This can safely be omitted
66
+ * to use the default JavaScript built-in global `fetch` function.
67
+ *
68
+ * See {@link createMockEndpointFetch} or {@link createMockEndpointResponse} for assistance
69
+ * mocking this.
70
+ *
71
+ * @default globalThis.fetch
72
+ */
73
+ fetch?: (url: string, requestInit: RequestInit, endpoint?: Values<Api['endpoints']> | undefined) => MaybePromise<Response>;
74
+ webSocketConstructor?: GenericConnectWebSocketParams<WebSocketClass>['webSocketConstructor'];
75
+ }>;
76
+ /**
77
+ * Overwrites types for an existing {@link RestVirApi} instance with mocks. This is created by
78
+ * {@link makeMockApi}.
79
+ *
80
+ * @category Internal
81
+ * @category Package : @rest-vir/define-service
82
+ * @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
83
+ */
84
+ export type MockExistingApi<Api extends RestVirApi<any>, WebSocketClass extends CommonWebSocket> = Overwrite<Api, {
85
+ webSockets: {
86
+ [WebSocketPath in keyof Api['webSockets']]: Api['webSockets'][WebSocketPath] extends WebSocketDefinition ? Overwrite<Api['webSockets'][WebSocketPath], {
87
+ /** Connect to this WebSocket. */
88
+ connect(...params: CollapsedConnectWebSocketParams<Api['webSockets'][WebSocketPath], false, WebSocketClass>): Promise<ClientWebSocket<Api['webSockets'][WebSocketPath], WebSocketClass>>;
89
+ }> : never;
90
+ };
91
+ }>;
92
+ /**
93
+ * Overwrites a generated API's fetch and WebSocket connect methods with a mocked fetch function and
94
+ * a mocked WebSocket constructor so you can have full control over them for unit-testing purposes.
95
+ *
96
+ * With this, you can unit test your clients without spinning up a mock API server.
97
+ *
98
+ * @category Testing : Client (Frontend)
99
+ * @category Package : @rest-vir/define-service
100
+ * @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
101
+ */
102
+ export declare function makeMockApi<const Api extends RestVirApi<any>, const WebSocketClass extends CommonWebSocket>(api: Readonly<Api>, mocks: RestVirApiMocks<Api, WebSocketClass>): MockExistingApi<Api, WebSocketClass>;
@@ -0,0 +1,83 @@
1
+ import { mapObjectValues, } from '@augment-vir/common';
2
+ import { connectWebSocket } from './connect-web-socket.js';
3
+ import { fetchEndpoint, } from './fetch-endpoint.js';
4
+ /**
5
+ * Creates an API from the given service definition, with automatically generated endpoint fetch and
6
+ * WebSocket connect methods.
7
+ *
8
+ * Use this to ship auto-generated API objects to internal or external teams so they have type safe
9
+ * access to your REST and WebSocket server.
10
+ *
11
+ * The generated API can easily mocked by wrapping it in {@link makeMockApi}.
12
+ *
13
+ * @category Create API
14
+ * @category Package : @rest-vir/define-service
15
+ * @example
16
+ *
17
+ * ```ts
18
+ * import {generateApi} from '@rest-vir/define-service';
19
+ *
20
+ * export const myApi = generateApi(myServiceDefinition);
21
+ *
22
+ * myApi.endpoints['/my-endpoint'].fetch();
23
+ * myApi.webSockets['/my-web-socket'].connect();
24
+ * ```
25
+ *
26
+ * @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
27
+ */
28
+ export function generateApi(service) {
29
+ return {
30
+ endpoints: mapObjectValues(service.endpoints, (endpointPath, endpointDefinition) => {
31
+ return {
32
+ ...endpointDefinition,
33
+ fetch: (...params) => {
34
+ return fetchEndpoint(endpointDefinition, ...params);
35
+ },
36
+ };
37
+ }),
38
+ webSockets: mapObjectValues(service.webSockets, (webSocketPath, webSocketDefinition) => {
39
+ return {
40
+ ...webSocketDefinition,
41
+ connect: (...params) => {
42
+ return connectWebSocket(webSocketDefinition, ...params);
43
+ },
44
+ };
45
+ }),
46
+ };
47
+ }
48
+ /**
49
+ * Overwrites a generated API's fetch and WebSocket connect methods with a mocked fetch function and
50
+ * a mocked WebSocket constructor so you can have full control over them for unit-testing purposes.
51
+ *
52
+ * With this, you can unit test your clients without spinning up a mock API server.
53
+ *
54
+ * @category Testing : Client (Frontend)
55
+ * @category Package : @rest-vir/define-service
56
+ * @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
57
+ */
58
+ export function makeMockApi(api, mocks) {
59
+ return {
60
+ endpoints: mapObjectValues(api.endpoints, (endpointPath, endpointDefinition) => {
61
+ return {
62
+ ...endpointDefinition,
63
+ fetch: (...params) => {
64
+ return fetchEndpoint(endpointDefinition, {
65
+ fetch: mocks.fetch,
66
+ ...params[0],
67
+ });
68
+ },
69
+ };
70
+ }),
71
+ webSockets: mapObjectValues(api.webSockets, (webSocketPath, webSocketDefinition) => {
72
+ return {
73
+ ...webSocketDefinition,
74
+ connect: (...params) => {
75
+ return connectWebSocket(webSocketDefinition, {
76
+ webSocketConstructor: mocks.webSocketConstructor,
77
+ ...params[0],
78
+ });
79
+ },
80
+ };
81
+ }),
82
+ };
83
+ }
@@ -0,0 +1,187 @@
1
+ import { type MaybePromise, type PartialWithUndefined } from '@augment-vir/common';
2
+ import { CommonWebSocket, CommonWebSocketEventMap, CommonWebSocketState } from '../web-socket/common-web-socket.js';
3
+ import { GenericConnectWebSocketParams, WebSocketLocation, type ClientWebSocket } from '../web-socket/overwrite-web-socket-methods.js';
4
+ import { WebSocketDefinition } from '../web-socket/web-socket-definition.js';
5
+ /**
6
+ * Parameters for {@link MockClientWebSocketClientSendCallback}.
7
+ *
8
+ * @category Internal
9
+ * @category Package : @rest-vir/define-service
10
+ * @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
11
+ */
12
+ export type MockClientWebSocketClientSendCallbackParams<WebSocketToConnect extends WebSocketDefinition> = {
13
+ webSocket: ClientWebSocket<WebSocketToConnect, MockClientWebSocket<WebSocketToConnect>>;
14
+ messageData: WebSocketToConnect['MessageFromClientType'];
15
+ messageSource: WebSocketLocation;
16
+ };
17
+ /**
18
+ * Type for {@link MockClientWebSocket.sendCallback}.
19
+ *
20
+ * @category Internal
21
+ * @category Package : @rest-vir/define-service
22
+ * @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
23
+ */
24
+ export type MockClientWebSocketClientSendCallback<WebSocketToConnect extends WebSocketDefinition> = (params: MockClientWebSocketClientSendCallbackParams<WebSocketToConnect>) => MaybePromise<void>;
25
+ /**
26
+ * Options for {@link MockClientWebSocket} and {@link createMockClientWebSocketConstructor}.
27
+ *
28
+ * @category Internal
29
+ * @category Package : @rest-vir/define-service
30
+ * @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
31
+ */
32
+ export type MockClientWebSocketOptions<WebSocketToConnect extends WebSocketDefinition> = PartialWithUndefined<{
33
+ /**
34
+ * Set this to `true` if you want to prevent this mock WebSocket from immediately opening
35
+ * itself. You can then use `.open()` at any time to manually open it.
36
+ */
37
+ preventImmediateOpen: boolean;
38
+ sendCallback: MockClientWebSocketClientSendCallback<WebSocketToConnect>;
39
+ }>;
40
+ /**
41
+ * Use this to create a mock WebSocket constructor for unit testing Web Socket connection.
42
+ *
43
+ * This creates a {@link MockClientWebSocket} constructor for connections from the client side with
44
+ * types for the given {@link WebSocketDefinition} and utilizing the given
45
+ * {@link MockClientWebSocketOptions} instance. This can be passed to `connectWebSocket` as the
46
+ * `webSocketConstructor` to allow unit testing on a client without spinning up an entire host to
47
+ * serve the WebSocket connection.
48
+ *
49
+ * @category Testing : Client (Frontend)
50
+ * @category Package : @rest-vir/define-service
51
+ * @example
52
+ *
53
+ * ```ts
54
+ * import {
55
+ * connectWebSocket,
56
+ * createMockClientWebSocketConstructor,
57
+ * } from '@rest-vir/define-service';
58
+ *
59
+ * const webSocket = await connectWebSocket(myService.webSockets['/my-path'], {
60
+ * webSocketConstructor: createMockClientWebSocketConstructor(
61
+ * myService.webSockets['/my-path'],
62
+ * {preventImmediateOpen: true},
63
+ * ),
64
+ * });
65
+ *
66
+ * // mock server responses without an actual server
67
+ * webSocket.sendFromHost(myMessage);
68
+ * ```
69
+ *
70
+ * @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
71
+ */
72
+ export declare function createMockClientWebSocketConstructor<const WebSocketToConnect extends WebSocketDefinition>(webSocketToConnect: Readonly<WebSocketToConnect>, options?: Readonly<MockClientWebSocketOptions<WebSocketToConnect>>): typeof MockClientWebSocket<WebSocketToConnect>;
73
+ /**
74
+ * Type for {@link MockClientWebSocket.listeners}.
75
+ *
76
+ * @category Internal
77
+ * @category Package : @rest-vir/define-service
78
+ * @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
79
+ */
80
+ export type MockClientWebSocketListeners = Partial<{
81
+ [EventName in keyof CommonWebSocketEventMap]: Set<(event: CommonWebSocketEventMap[EventName]) => void>;
82
+ }>;
83
+ /**
84
+ * A mock WebSocket constructor for connections from the client side. This can be passed to
85
+ * `connectWebSocket` as the `webSocketConstructor` to allow unit testing on a client without
86
+ * spinning up an entire host to serve the WebSocket connection.
87
+ *
88
+ * @category Internal
89
+ * @category Package : @rest-vir/define-service
90
+ * @example
91
+ *
92
+ * ```ts
93
+ * import {connectWebSocket, MockClientWebSocket} from '@rest-vir/define-service';
94
+ *
95
+ * const webSocket = await connectWebSocket(myService.webSockets['/my-path'], {
96
+ * webSocketConstructor: MockClientWebSocket<(typeof myService.webSockets)['/my-path']>,
97
+ * });
98
+ *
99
+ * // mock server responses without an actual server
100
+ * webSocket.sendFromHost(myMessage);
101
+ * ```
102
+ *
103
+ * @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
104
+ */
105
+ export declare class MockClientWebSocket<const WebSocketToConnect extends WebSocketDefinition = any> implements CommonWebSocket {
106
+ /**
107
+ * Mocked WebSocket event listeners. While this is public, you should attach a listener using
108
+ * {@link MockClientWebSocket.addEventListener} method and remove them with
109
+ * {@link MockClientWebSocket.removeEventListener}, as you would with a normal WebSocket
110
+ * instance.
111
+ */
112
+ listeners: MockClientWebSocketListeners;
113
+ /**
114
+ * Implements and mocks the standard `WebSocket.readyState` property.
115
+ *
116
+ * @see https://developer.mozilla.org/docs/Web/API/WebSocket/readyState
117
+ */
118
+ readyState: CommonWebSocketState;
119
+ /**
120
+ * This callback will be called whenever a message is sent to or from the WebSocket. This is set
121
+ * via the constructor option `sendCallback`.
122
+ *
123
+ * @example
124
+ *
125
+ * ```ts
126
+ * import {MockClientWebSocket, connectWebSocket} from '@rest-vir/define-service';
127
+ *
128
+ * const webSocket = await connectWebSocket(myService.webSockets['/my-socket'], {
129
+ * webSocketConstructor: createMockClientWebSocketConstructor(
130
+ * myService.webSockets['/my-socket'],
131
+ * {
132
+ * sendCallback: (message) => {
133
+ * // handle the sent message here
134
+ * console.log('handled message:', message);
135
+ * },
136
+ * },
137
+ * ),
138
+ * });
139
+ * ```
140
+ */
141
+ sendCallback: MockClientWebSocketClientSendCallback<WebSocketToConnect> | undefined;
142
+ constructor(...[, , , options,]: [
143
+ ...ConstructorParameters<NonNullable<GenericConnectWebSocketParams<any>['webSocketConstructor']>>,
144
+ options?: Readonly<MockClientWebSocketOptions<WebSocketToConnect>>
145
+ ]);
146
+ /**
147
+ * Manually set the WebSocket connection as opened. This is only necessary to use if you've set
148
+ * the constructor options to
149
+ */
150
+ open(): void;
151
+ /** Manually close and cleanup the WebSocket. */
152
+ close(): void;
153
+ /**
154
+ * Dispatch a WebSocket event. This is primarily used within the MockClientWebSocket class
155
+ * itself but may also be used externally to test various WebSocket scenarios.
156
+ *
157
+ * Note that dispatching `'open'` and `'close'` events will not actually close or open the
158
+ * WebSocket. Use the {@link MockClientWebSocket.open} and {@link MockClientWebSocket.close}
159
+ * methods instead (which appropriately dispatch their events).
160
+ */
161
+ dispatchEvent<const EventName extends keyof CommonWebSocketEventMap>(eventName: EventName, event: Omit<CommonWebSocketEventMap[EventName], 'type' | 'target'>): void;
162
+ /**
163
+ * Implements and mocks the standard `WebSocket.addEventListener` property but with message type
164
+ * safety.
165
+ *
166
+ * @see https://developer.mozilla.org/docs/Web/API/EventTarget/addEventListener
167
+ */
168
+ addEventListener<const EventName extends keyof CommonWebSocketEventMap>(eventName: EventName, listener: (event: CommonWebSocketEventMap[EventName]) => void): void;
169
+ /**
170
+ * Implements and mocks the standard `WebSocket.removeEventListener` property but with message
171
+ * type safety.
172
+ *
173
+ * @see https://developer.mozilla.org/docs/Web/API/EventTarget/removeEventListener
174
+ */
175
+ removeEventListener<const EventName extends keyof CommonWebSocketEventMap>(eventName: EventName, listener: (event: CommonWebSocketEventMap[EventName]) => void): void;
176
+ /**
177
+ * Implements and mocks the standard `WebSocket.send` property but with message type safety.
178
+ *
179
+ * @see https://developer.mozilla.org/docs/Web/API/WebSocket/send
180
+ */
181
+ send(data: any): void;
182
+ /**
183
+ * Sends a message as if it came from the WebSocket host. Use this to unit test client-side
184
+ * WebSockets without needing a running host.
185
+ */
186
+ sendFromHost(data: WebSocketToConnect['MessageFromHostType']): void;
187
+ }