@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.
- package/LICENSE-CC0 +121 -0
- package/LICENSE-MIT +21 -0
- package/README.md +88 -0
- package/dist/augments/json.d.ts +8 -0
- package/dist/augments/json.js +13 -0
- package/dist/dev-port/find-dev-port.d.ts +132 -0
- package/dist/dev-port/find-dev-port.js +156 -0
- package/dist/endpoint/endpoint-path.d.ts +27 -0
- package/dist/endpoint/endpoint-path.js +14 -0
- package/dist/endpoint/endpoint.d.ts +198 -0
- package/dist/endpoint/endpoint.js +80 -0
- package/dist/frontend-connect/connect-web-socket.d.ts +95 -0
- package/dist/frontend-connect/connect-web-socket.js +64 -0
- package/dist/frontend-connect/fetch-endpoint.d.ts +199 -0
- package/dist/frontend-connect/fetch-endpoint.js +135 -0
- package/dist/frontend-connect/generate-api.d.ts +102 -0
- package/dist/frontend-connect/generate-api.js +83 -0
- package/dist/frontend-connect/mock-client-web-socket.d.ts +187 -0
- package/dist/frontend-connect/mock-client-web-socket.js +198 -0
- package/dist/frontend-connect/web-socket-protocol-parse.d.ts +10 -0
- package/dist/frontend-connect/web-socket-protocol-parse.js +111 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +23 -0
- package/dist/service/define-service.d.ts +19 -0
- package/dist/service/define-service.js +133 -0
- package/dist/service/match-url.d.ts +30 -0
- package/dist/service/match-url.js +31 -0
- package/dist/service/minimal-service.d.ts +44 -0
- package/dist/service/minimal-service.js +1 -0
- package/dist/service/service-definition.d.ts +80 -0
- package/dist/service/service-definition.error.d.ts +35 -0
- package/dist/service/service-definition.error.js +34 -0
- package/dist/service/service-definition.js +1 -0
- package/dist/util/mock-fetch.d.ts +107 -0
- package/dist/util/mock-fetch.js +199 -0
- package/dist/util/no-param.d.ts +16 -0
- package/dist/util/no-param.js +8 -0
- package/dist/util/origin.d.ts +43 -0
- package/dist/util/origin.js +19 -0
- package/dist/util/path-to-regexp.d.ts +54 -0
- package/dist/util/path-to-regexp.js +307 -0
- package/dist/util/search-params.d.ts +9 -0
- package/dist/util/search-params.js +1 -0
- package/dist/web-socket/common-web-socket.d.ts +103 -0
- package/dist/web-socket/common-web-socket.js +28 -0
- package/dist/web-socket/overwrite-web-socket-methods.d.ts +276 -0
- package/dist/web-socket/overwrite-web-socket-methods.js +210 -0
- package/dist/web-socket/web-socket-definition.d.ts +170 -0
- package/dist/web-socket/web-socket-definition.js +78 -0
- package/package.json +68 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { Overwrite } from '@augment-vir/common';
|
|
2
|
+
import { IsEqual, SetRequired } from 'type-fest';
|
|
3
|
+
import { EndpointPathBase } from '../endpoint/endpoint-path.js';
|
|
4
|
+
import { EndpointDefinition, EndpointInit, WithFinalEndpointProps } from '../endpoint/endpoint.js';
|
|
5
|
+
import { NoParam } from '../util/no-param.js';
|
|
6
|
+
import { OriginRequirement } from '../util/origin.js';
|
|
7
|
+
import { WebSocketDefinition, WebSocketInit, WithFinalWebSocketProps } from '../web-socket/web-socket-definition.js';
|
|
8
|
+
import { MinimalService } from './minimal-service.js';
|
|
9
|
+
/**
|
|
10
|
+
* A string used for type errors triggered when an endpoint path is defined without a leading slash.
|
|
11
|
+
*
|
|
12
|
+
* @category Internal
|
|
13
|
+
* @category Package : @rest-vir/define-service
|
|
14
|
+
* @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
|
|
15
|
+
*/
|
|
16
|
+
export type EndpointMustStartWithSlashTypeError = 'ERROR: endpoint must start with a slash';
|
|
17
|
+
/**
|
|
18
|
+
* Base type used for the right side of "extends" in type parameters for generic endpoint
|
|
19
|
+
* definitions.
|
|
20
|
+
*
|
|
21
|
+
* @category Internal
|
|
22
|
+
* @category Package : @rest-vir/define-service
|
|
23
|
+
* @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
|
|
24
|
+
*/
|
|
25
|
+
export type BaseServiceEndpointsInit = Record<EndpointPathBase, EndpointInit>;
|
|
26
|
+
/**
|
|
27
|
+
* Base type used for the right side of "extends" in type parameters for generic endpoint
|
|
28
|
+
* definitions.
|
|
29
|
+
*
|
|
30
|
+
* @category Internal
|
|
31
|
+
* @category Package : @rest-vir/define-service
|
|
32
|
+
* @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
|
|
33
|
+
*/
|
|
34
|
+
export type BaseServiceWebSocketsInit = Record<EndpointPathBase, WebSocketInit>;
|
|
35
|
+
/**
|
|
36
|
+
* Init for a service. This is used as an input to `defineService`.
|
|
37
|
+
*
|
|
38
|
+
* @category Internal
|
|
39
|
+
* @category Package : @rest-vir/define-service
|
|
40
|
+
* @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
|
|
41
|
+
*/
|
|
42
|
+
export type ServiceInit<ServiceName extends string, EndpointsInit extends BaseServiceEndpointsInit | NoParam, WebSocketsInit extends BaseServiceWebSocketsInit | NoParam> = MinimalService<ServiceName> & {
|
|
43
|
+
requiredClientOrigin: NonNullable<OriginRequirement>;
|
|
44
|
+
webSockets?: IsEqual<WebSocketsInit, NoParam> extends true ? Record<EndpointPathBase, WebSocketInit> : {
|
|
45
|
+
[WebSocketPath in keyof WebSocketsInit]: WebSocketPath extends EndpointPathBase ? WebSocketsInit[WebSocketPath] : WebSocketPath extends EndpointMustStartWithSlashTypeError ? never : EndpointMustStartWithSlashTypeError;
|
|
46
|
+
};
|
|
47
|
+
endpoints?: IsEqual<EndpointsInit, NoParam> extends true ? Record<EndpointPathBase, EndpointInit> : {
|
|
48
|
+
[EndpointPath in keyof EndpointsInit]: EndpointPath extends EndpointPathBase ? EndpointsInit[EndpointPath] : EndpointPath extends EndpointMustStartWithSlashTypeError ? never : EndpointMustStartWithSlashTypeError;
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* A fully defined service (without executable endpoint implementations).
|
|
53
|
+
*
|
|
54
|
+
* @category Internal
|
|
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 type ServiceDefinition<ServiceName extends string = any, EndpointsInit extends BaseServiceEndpointsInit | NoParam = NoParam, WebSocketsInit extends BaseServiceWebSocketsInit | NoParam = NoParam> = MinimalService<ServiceName> & {
|
|
59
|
+
requiredClientOrigin: NonNullable<OriginRequirement>;
|
|
60
|
+
/** Include the initial init object so a service can be composed. */
|
|
61
|
+
init: SetRequired<ServiceInit<ServiceName, EndpointsInit, WebSocketsInit>, 'endpoints' | 'webSockets'>;
|
|
62
|
+
webSockets: WebSocketsInit extends NoParam ? {
|
|
63
|
+
[WebSocketPath in EndpointPathBase]: Overwrite<WebSocketDefinition, {
|
|
64
|
+
searchParamsShape: any;
|
|
65
|
+
SearchParamsType: any;
|
|
66
|
+
protocolsShape: any;
|
|
67
|
+
ProtocolsType: any;
|
|
68
|
+
}>;
|
|
69
|
+
} : {
|
|
70
|
+
[WebSocketPath in keyof WebSocketsInit]: WebSocketPath extends EndpointPathBase ? WithFinalWebSocketProps<WebSocketsInit[WebSocketPath], WebSocketPath> : EndpointMustStartWithSlashTypeError;
|
|
71
|
+
};
|
|
72
|
+
endpoints: EndpointsInit extends NoParam ? {
|
|
73
|
+
[EndpointPath in EndpointPathBase]: Overwrite<EndpointDefinition, {
|
|
74
|
+
searchParamsShape: any;
|
|
75
|
+
SearchParamsType: any;
|
|
76
|
+
}>;
|
|
77
|
+
} : {
|
|
78
|
+
[EndpointPath in keyof EndpointsInit]: EndpointPath extends EndpointPathBase ? WithFinalEndpointProps<EndpointsInit[EndpointPath], EndpointPath> : EndpointMustStartWithSlashTypeError;
|
|
79
|
+
};
|
|
80
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type NoParam } from '../util/no-param.js';
|
|
2
|
+
/**
|
|
3
|
+
* Parameters for {@link ServiceDefinitionError}
|
|
4
|
+
*
|
|
5
|
+
* @category Internal
|
|
6
|
+
* @category Package : @rest-vir/define-service
|
|
7
|
+
* @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
|
|
8
|
+
*/
|
|
9
|
+
export type ServiceDefinitionErrorParams = {
|
|
10
|
+
serviceName: string | NoParam;
|
|
11
|
+
errorMessage: string;
|
|
12
|
+
path: string | undefined;
|
|
13
|
+
isWebSocket: boolean | undefined;
|
|
14
|
+
isEndpoint: boolean | undefined;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* An error thrown by endpoint and service validation assertions.
|
|
18
|
+
*
|
|
19
|
+
* @category Internal
|
|
20
|
+
* @category Package : @rest-vir/define-service
|
|
21
|
+
* @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
|
|
22
|
+
*/
|
|
23
|
+
export declare class ServiceDefinitionError extends Error {
|
|
24
|
+
name: string;
|
|
25
|
+
constructor({ serviceName, path, errorMessage, isEndpoint, isWebSocket, }: ServiceDefinitionErrorParams);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Ensures that the given error is a {@link ServiceDefinitionError} instance. If it's not, then a new
|
|
29
|
+
* {@link ServiceDefinitionError} is created with the given params.
|
|
30
|
+
*
|
|
31
|
+
* @category Internal
|
|
32
|
+
* @category Package : @rest-vir/define-service
|
|
33
|
+
* @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
|
|
34
|
+
*/
|
|
35
|
+
export declare function ensureServiceDefinitionError(error: unknown, params: Omit<ServiceDefinitionErrorParams, 'errorMessage'>): ServiceDefinitionError;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { ensureErrorClass, extractErrorMessage } from '@augment-vir/common';
|
|
2
|
+
/**
|
|
3
|
+
* An error thrown by endpoint and service validation assertions.
|
|
4
|
+
*
|
|
5
|
+
* @category Internal
|
|
6
|
+
* @category Package : @rest-vir/define-service
|
|
7
|
+
* @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
|
|
8
|
+
*/
|
|
9
|
+
export class ServiceDefinitionError extends Error {
|
|
10
|
+
name = 'ServiceDefinitionError';
|
|
11
|
+
constructor({ serviceName, path, errorMessage, isEndpoint, isWebSocket, }) {
|
|
12
|
+
const serviceNameMessage = `Service '${String(serviceName)}'`;
|
|
13
|
+
const routeType = isEndpoint ? 'Endpoint' : isWebSocket ? 'WebSocket' : undefined;
|
|
14
|
+
const nameMessage = path && routeType
|
|
15
|
+
? `${routeType} '${path}' on ${serviceNameMessage}`
|
|
16
|
+
: serviceNameMessage;
|
|
17
|
+
const fullErrorMessage = `Failed to define ${nameMessage}: ${errorMessage}`;
|
|
18
|
+
super(fullErrorMessage);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Ensures that the given error is a {@link ServiceDefinitionError} instance. If it's not, then a new
|
|
23
|
+
* {@link ServiceDefinitionError} is created with the given params.
|
|
24
|
+
*
|
|
25
|
+
* @category Internal
|
|
26
|
+
* @category Package : @rest-vir/define-service
|
|
27
|
+
* @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
|
|
28
|
+
*/
|
|
29
|
+
export function ensureServiceDefinitionError(error, params) {
|
|
30
|
+
return ensureErrorClass(error, ServiceDefinitionError, {
|
|
31
|
+
...params,
|
|
32
|
+
errorMessage: extractErrorMessage(error),
|
|
33
|
+
});
|
|
34
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { HttpStatus, type Overwrite, type PartialWithUndefined } from '@augment-vir/common';
|
|
2
|
+
import { type IsNever } from 'type-fest';
|
|
3
|
+
import { type EndpointDefinition } from '../endpoint/endpoint.js';
|
|
4
|
+
/**
|
|
5
|
+
* Options for {@link createMockEndpointResponse} and {@link createMockEndpointFetch}.
|
|
6
|
+
*
|
|
7
|
+
* @category Internal
|
|
8
|
+
* @category Package : @rest-vir/define-service
|
|
9
|
+
* @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
|
|
10
|
+
*/
|
|
11
|
+
export type MockEndpointResponseOptions<EndpointToMock extends EndpointDefinition> = Overwrite<MockResponseParams, IsNever<Extract<EndpointToMock['ResponseType'], undefined>> extends true ? {
|
|
12
|
+
body: EndpointToMock['ResponseType'];
|
|
13
|
+
} : {
|
|
14
|
+
body?: EndpointToMock['ResponseType'];
|
|
15
|
+
}>;
|
|
16
|
+
/**
|
|
17
|
+
* Creates a mocked fetch `Response` object for the given endpoint (requiring a type safe body). For
|
|
18
|
+
* more generic response mocking, see {@link createMockResponse}.
|
|
19
|
+
*
|
|
20
|
+
* @category Testing : Client (Frontend)
|
|
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 declare function createMockEndpointResponse<const EndpointToMock extends EndpointDefinition>(endpoint: EndpointToMock, params: Readonly<MockEndpointResponseOptions<EndpointToMock>>): Response;
|
|
25
|
+
/**
|
|
26
|
+
* Parameters for {@link createMockResponse}.
|
|
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 MockResponseParams = Overwrite<Partial<Pick<Response, 'redirected' | 'statusText' | 'type'>>, PartialWithUndefined<{
|
|
33
|
+
status: HttpStatus;
|
|
34
|
+
url: string | URL;
|
|
35
|
+
headers: HeadersInit;
|
|
36
|
+
body: unknown;
|
|
37
|
+
}>>;
|
|
38
|
+
/**
|
|
39
|
+
* A `ReadableStream` implementation used by {@link createMockResponse} to create its streamed `body`
|
|
40
|
+
* property.
|
|
41
|
+
*
|
|
42
|
+
* @category Internal
|
|
43
|
+
* @category Package : @rest-vir/define-service
|
|
44
|
+
* @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
|
|
45
|
+
*/
|
|
46
|
+
export declare class MockResponseBodyStream extends ReadableStream<Uint8Array> {
|
|
47
|
+
private getReaderCalled;
|
|
48
|
+
constructor(body: unknown, getReaderCalled: () => void);
|
|
49
|
+
getReader(...args: any): any;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Creates a mocked, but realistic, `Response` object. Use this when mocking `fetch`. See
|
|
53
|
+
* {@link createMockEndpointResponse} for a more type safe version, specific to individual
|
|
54
|
+
* endpoints.
|
|
55
|
+
*
|
|
56
|
+
* @category Internal
|
|
57
|
+
* @category Package : @rest-vir/define-service
|
|
58
|
+
* @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
|
|
59
|
+
*/
|
|
60
|
+
export declare function createMockResponse(params?: Readonly<MockResponseParams>): Response;
|
|
61
|
+
/**
|
|
62
|
+
* Creates a mock `fetch` function that returns a mock `Response` object that matches the
|
|
63
|
+
* expectations of the given endpoint. For more generic `fetch` mocking, see
|
|
64
|
+
* {@link createMockFetch}.
|
|
65
|
+
*
|
|
66
|
+
* @category Testing : Client (Frontend)
|
|
67
|
+
* @category Package : @rest-vir/define-service
|
|
68
|
+
* @example
|
|
69
|
+
*
|
|
70
|
+
* ```ts
|
|
71
|
+
* import {createMockEndpointFetch, fetchEndpoint} from '@rest-vir/define-service';
|
|
72
|
+
*
|
|
73
|
+
* fetchEndpoint(myService.endpoints['/my-path'], {
|
|
74
|
+
* fetch: createMockEndpointFetch(myService.endpoints['/my-path'], {
|
|
75
|
+
* body: 'some body',
|
|
76
|
+
* // there are other properties that can be mocked as well, see the types for more details
|
|
77
|
+
* }),
|
|
78
|
+
* });
|
|
79
|
+
* ```
|
|
80
|
+
*
|
|
81
|
+
* @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
|
|
82
|
+
*/
|
|
83
|
+
export declare function createMockEndpointFetch<const EndpointToMock extends EndpointDefinition>(endpoint: EndpointToMock, params: Readonly<Omit<MockEndpointResponseOptions<EndpointToMock>, 'url'>>): typeof globalThis.fetch;
|
|
84
|
+
/**
|
|
85
|
+
* Creates a mock `fetch` function that always returns a mock `Response` object based on the given
|
|
86
|
+
* response parameters. For more control over a mocked `fetch`, use {@link createMockResponse}
|
|
87
|
+
* directly. See {@link createMockEndpointFetch} for a more type safe version, specific to individual
|
|
88
|
+
* endpoints.
|
|
89
|
+
*
|
|
90
|
+
* @category Internal
|
|
91
|
+
* @category Package : @rest-vir/define-service
|
|
92
|
+
* @example
|
|
93
|
+
*
|
|
94
|
+
* ```ts
|
|
95
|
+
* import {createMockFetch, fetchEndpoint} from '@rest-vir/define-service';
|
|
96
|
+
*
|
|
97
|
+
* fetchEndpoint(myService.endpoints['/my-path'], {
|
|
98
|
+
* fetch: createMockFetch({
|
|
99
|
+
* body: 'some body',
|
|
100
|
+
* // there are other properties that can be mocked as well, see the types for more details
|
|
101
|
+
* }),
|
|
102
|
+
* });
|
|
103
|
+
* ```
|
|
104
|
+
*
|
|
105
|
+
* @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
|
|
106
|
+
*/
|
|
107
|
+
export declare function createMockFetch(params?: Readonly<Omit<MockResponseParams, 'url'>>): typeof globalThis.fetch;
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { check } from '@augment-vir/assert';
|
|
2
|
+
import { copyThroughJson, HttpStatus, isErrorHttpStatus, } from '@augment-vir/common';
|
|
3
|
+
/**
|
|
4
|
+
* Creates a mocked fetch `Response` object for the given endpoint (requiring a type safe body). For
|
|
5
|
+
* more generic response mocking, see {@link createMockResponse}.
|
|
6
|
+
*
|
|
7
|
+
* @category Testing : Client (Frontend)
|
|
8
|
+
* @category Package : @rest-vir/define-service
|
|
9
|
+
* @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
|
|
10
|
+
*/
|
|
11
|
+
export function createMockEndpointResponse(endpoint, params) {
|
|
12
|
+
return createMockResponse(params);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* A `ReadableStream` implementation used by {@link createMockResponse} to create its streamed `body`
|
|
16
|
+
* property.
|
|
17
|
+
*
|
|
18
|
+
* @category Internal
|
|
19
|
+
* @category Package : @rest-vir/define-service
|
|
20
|
+
* @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
|
|
21
|
+
*/
|
|
22
|
+
export class MockResponseBodyStream extends ReadableStream {
|
|
23
|
+
getReaderCalled;
|
|
24
|
+
constructor(body, getReaderCalled) {
|
|
25
|
+
super({
|
|
26
|
+
start(controller) {
|
|
27
|
+
if (body instanceof Uint8Array) {
|
|
28
|
+
controller.enqueue(body);
|
|
29
|
+
}
|
|
30
|
+
else if (check.isString(body)) {
|
|
31
|
+
controller.enqueue(new TextEncoder().encode(body));
|
|
32
|
+
}
|
|
33
|
+
else if (body) {
|
|
34
|
+
controller.enqueue(new TextEncoder().encode(JSON.stringify(body)));
|
|
35
|
+
}
|
|
36
|
+
controller.close();
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
this.getReaderCalled = getReaderCalled;
|
|
40
|
+
}
|
|
41
|
+
getReader(...args) {
|
|
42
|
+
this.getReaderCalled();
|
|
43
|
+
return super.getReader(...args);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Creates a mocked, but realistic, `Response` object. Use this when mocking `fetch`. See
|
|
48
|
+
* {@link createMockEndpointResponse} for a more type safe version, specific to individual
|
|
49
|
+
* endpoints.
|
|
50
|
+
*
|
|
51
|
+
* @category Internal
|
|
52
|
+
* @category Package : @rest-vir/define-service
|
|
53
|
+
* @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
|
|
54
|
+
*/
|
|
55
|
+
export function createMockResponse(params = {}) {
|
|
56
|
+
const { headers = [], status = HttpStatus.Ok, url = '', redirected, statusText = '', type = 'basic', body, } = params;
|
|
57
|
+
function createArrayBuffer() {
|
|
58
|
+
return check.instanceOf(body, ArrayBuffer)
|
|
59
|
+
? body
|
|
60
|
+
: new TextEncoder().encode(typeof body === 'string' ? body : JSON.stringify(body))
|
|
61
|
+
.buffer;
|
|
62
|
+
}
|
|
63
|
+
let bodyUsed = false;
|
|
64
|
+
return {
|
|
65
|
+
headers: new Headers(headers),
|
|
66
|
+
ok: !isErrorHttpStatus(status),
|
|
67
|
+
body: new MockResponseBodyStream(body, () => {
|
|
68
|
+
if (bodyUsed) {
|
|
69
|
+
throw new TypeError('Body is disturbed or locked.');
|
|
70
|
+
}
|
|
71
|
+
bodyUsed = true;
|
|
72
|
+
}),
|
|
73
|
+
get bodyUsed() {
|
|
74
|
+
return bodyUsed;
|
|
75
|
+
},
|
|
76
|
+
status,
|
|
77
|
+
arrayBuffer() {
|
|
78
|
+
if (bodyUsed) {
|
|
79
|
+
throw new TypeError('Body is disturbed or locked.');
|
|
80
|
+
}
|
|
81
|
+
bodyUsed = true;
|
|
82
|
+
return Promise.resolve(createArrayBuffer());
|
|
83
|
+
},
|
|
84
|
+
blob() {
|
|
85
|
+
if (bodyUsed) {
|
|
86
|
+
throw new TypeError('Body is disturbed or locked.');
|
|
87
|
+
}
|
|
88
|
+
bodyUsed = true;
|
|
89
|
+
return Promise.resolve(new Blob([createArrayBuffer()]));
|
|
90
|
+
},
|
|
91
|
+
bytes() {
|
|
92
|
+
if (bodyUsed) {
|
|
93
|
+
throw new TypeError('Body is disturbed or locked.');
|
|
94
|
+
}
|
|
95
|
+
bodyUsed = true;
|
|
96
|
+
return Promise.resolve(check.instanceOf(body, Uint8Array) ? body : new Uint8Array(createArrayBuffer()));
|
|
97
|
+
},
|
|
98
|
+
formData() {
|
|
99
|
+
if (bodyUsed) {
|
|
100
|
+
throw new TypeError('Body is disturbed or locked.');
|
|
101
|
+
}
|
|
102
|
+
bodyUsed = true;
|
|
103
|
+
const formData = new FormData();
|
|
104
|
+
if (check.isObject(body)) {
|
|
105
|
+
Object.entries(body).forEach(([key, value,]) => {
|
|
106
|
+
formData.append(key, check.isString(value)
|
|
107
|
+
? value
|
|
108
|
+
: check.instanceOf(value, Blob)
|
|
109
|
+
? value
|
|
110
|
+
: JSON.stringify(value));
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
return Promise.resolve(formData);
|
|
114
|
+
},
|
|
115
|
+
text() {
|
|
116
|
+
if (bodyUsed) {
|
|
117
|
+
throw new TypeError('Body is disturbed or locked.');
|
|
118
|
+
}
|
|
119
|
+
bodyUsed = true;
|
|
120
|
+
return Promise.resolve(check.isString(body) ? body : JSON.stringify(body));
|
|
121
|
+
},
|
|
122
|
+
json() {
|
|
123
|
+
if (bodyUsed) {
|
|
124
|
+
throw new TypeError('Body is disturbed or locked.');
|
|
125
|
+
}
|
|
126
|
+
bodyUsed = true;
|
|
127
|
+
return Promise.resolve(check.isString(body) ? JSON.parse(body) : copyThroughJson(body));
|
|
128
|
+
},
|
|
129
|
+
url: String(url),
|
|
130
|
+
redirected: !!redirected,
|
|
131
|
+
statusText,
|
|
132
|
+
type,
|
|
133
|
+
clone() {
|
|
134
|
+
return createMockResponse(params);
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Creates a mock `fetch` function that returns a mock `Response` object that matches the
|
|
140
|
+
* expectations of the given endpoint. For more generic `fetch` mocking, see
|
|
141
|
+
* {@link createMockFetch}.
|
|
142
|
+
*
|
|
143
|
+
* @category Testing : Client (Frontend)
|
|
144
|
+
* @category Package : @rest-vir/define-service
|
|
145
|
+
* @example
|
|
146
|
+
*
|
|
147
|
+
* ```ts
|
|
148
|
+
* import {createMockEndpointFetch, fetchEndpoint} from '@rest-vir/define-service';
|
|
149
|
+
*
|
|
150
|
+
* fetchEndpoint(myService.endpoints['/my-path'], {
|
|
151
|
+
* fetch: createMockEndpointFetch(myService.endpoints['/my-path'], {
|
|
152
|
+
* body: 'some body',
|
|
153
|
+
* // there are other properties that can be mocked as well, see the types for more details
|
|
154
|
+
* }),
|
|
155
|
+
* });
|
|
156
|
+
* ```
|
|
157
|
+
*
|
|
158
|
+
* @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
|
|
159
|
+
*/
|
|
160
|
+
export function createMockEndpointFetch(endpoint, params) {
|
|
161
|
+
return createMockFetch(params);
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Creates a mock `fetch` function that always returns a mock `Response` object based on the given
|
|
165
|
+
* response parameters. For more control over a mocked `fetch`, use {@link createMockResponse}
|
|
166
|
+
* directly. See {@link createMockEndpointFetch} for a more type safe version, specific to individual
|
|
167
|
+
* endpoints.
|
|
168
|
+
*
|
|
169
|
+
* @category Internal
|
|
170
|
+
* @category Package : @rest-vir/define-service
|
|
171
|
+
* @example
|
|
172
|
+
*
|
|
173
|
+
* ```ts
|
|
174
|
+
* import {createMockFetch, fetchEndpoint} from '@rest-vir/define-service';
|
|
175
|
+
*
|
|
176
|
+
* fetchEndpoint(myService.endpoints['/my-path'], {
|
|
177
|
+
* fetch: createMockFetch({
|
|
178
|
+
* body: 'some body',
|
|
179
|
+
* // there are other properties that can be mocked as well, see the types for more details
|
|
180
|
+
* }),
|
|
181
|
+
* });
|
|
182
|
+
* ```
|
|
183
|
+
*
|
|
184
|
+
* @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
|
|
185
|
+
*/
|
|
186
|
+
export function createMockFetch(params = {}) {
|
|
187
|
+
return (...args) => {
|
|
188
|
+
const url = check.instanceOf(args[0], URL)
|
|
189
|
+
? args[0].toString()
|
|
190
|
+
: check.isString(args[0])
|
|
191
|
+
? args[0]
|
|
192
|
+
: args[0].url;
|
|
193
|
+
const mockResponse = createMockResponse({
|
|
194
|
+
...params,
|
|
195
|
+
url,
|
|
196
|
+
});
|
|
197
|
+
return Promise.resolve(mockResponse);
|
|
198
|
+
};
|
|
199
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime value for {@link NoParam}.
|
|
3
|
+
*
|
|
4
|
+
* @category Internal
|
|
5
|
+
* @category Package : @rest-vir/define-service
|
|
6
|
+
* @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
|
|
7
|
+
*/
|
|
8
|
+
export declare const NoParam: unique symbol;
|
|
9
|
+
/**
|
|
10
|
+
* Use to keep track of type parameters that are generic and haven't received a specific type yet.
|
|
11
|
+
*
|
|
12
|
+
* @category Internal
|
|
13
|
+
* @category Package : @rest-vir/define-service
|
|
14
|
+
* @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
|
|
15
|
+
*/
|
|
16
|
+
export type NoParam = typeof NoParam;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime value for {@link NoParam}.
|
|
3
|
+
*
|
|
4
|
+
* @category Internal
|
|
5
|
+
* @category Package : @rest-vir/define-service
|
|
6
|
+
* @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
|
|
7
|
+
*/
|
|
8
|
+
export const NoParam = Symbol('no type parameter');
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { MaybePromise } from '@augment-vir/common';
|
|
2
|
+
/**
|
|
3
|
+
* Explicity denotes that any origin is allowed.
|
|
4
|
+
*
|
|
5
|
+
* @category Internal
|
|
6
|
+
* @category Package : @rest-vir/define-service
|
|
7
|
+
* @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
|
|
8
|
+
*/
|
|
9
|
+
export declare const AnyOrigin: unique symbol;
|
|
10
|
+
/**
|
|
11
|
+
* Type for {@link AnyOrigin} symbol.
|
|
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 AnyOrigin = typeof AnyOrigin;
|
|
18
|
+
/**
|
|
19
|
+
* Options explained:
|
|
20
|
+
*
|
|
21
|
+
* - `undefined`: when on an endpoint, this denotes that the endpoint defers origin checks to the
|
|
22
|
+
* parent service's origin requirement. When on the service, `undefined` is not allowed.
|
|
23
|
+
* - `string`: require all request origins to exactly match the given string.
|
|
24
|
+
* - `RegExp`: all request origins must match the RegExp.
|
|
25
|
+
* - {@link AnyOrigin}: allow any origin.
|
|
26
|
+
* - A function: allow custom checking. If this function returns something truthy, the origin is
|
|
27
|
+
* allowed.
|
|
28
|
+
* - An array: a combination of `string` values, `RegExp` values, or functions to compare against. If
|
|
29
|
+
* any of the array entries allow a request origin, it passes.
|
|
30
|
+
*
|
|
31
|
+
* @category Internal
|
|
32
|
+
* @category Package : @rest-vir/define-service
|
|
33
|
+
* @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
|
|
34
|
+
*/
|
|
35
|
+
export type OriginRequirement = undefined | string | RegExp | AnyOrigin | (((origin: string | undefined) => MaybePromise<boolean>) | string | RegExp)[] | ((origin: string | undefined) => MaybePromise<boolean>);
|
|
36
|
+
/**
|
|
37
|
+
* Shape definition for {@link OriginRequirement}.
|
|
38
|
+
*
|
|
39
|
+
* @category Internal
|
|
40
|
+
* @category Package : @rest-vir/define-service
|
|
41
|
+
* @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
|
|
42
|
+
*/
|
|
43
|
+
export declare const originRequirementShape: import("object-shape-tester").ShapeOr<[undefined, string, import("object-shape-tester").ShapeClass<[RegExpConstructor]>, () => void, import("object-shape-tester").ShapeOr<[string, import("object-shape-tester").ShapeClass<[RegExpConstructor]>, () => void]>[]]>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { classShape, or } from 'object-shape-tester';
|
|
2
|
+
/**
|
|
3
|
+
* Explicity denotes that any origin is allowed.
|
|
4
|
+
*
|
|
5
|
+
* @category Internal
|
|
6
|
+
* @category Package : @rest-vir/define-service
|
|
7
|
+
* @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
|
|
8
|
+
*/
|
|
9
|
+
export const AnyOrigin = Symbol('any-origin');
|
|
10
|
+
/**
|
|
11
|
+
* Shape definition for {@link OriginRequirement}.
|
|
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 const originRequirementShape = or(undefined, '', classShape(RegExp), () => { }, [
|
|
18
|
+
or('', classShape(RegExp), () => { }),
|
|
19
|
+
]);
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic parameter data for {@link MatchResult}.
|
|
3
|
+
*
|
|
4
|
+
* This is from the [path-to-regexp](https://www.npmjs.com/package/path-to-regexp) package.
|
|
5
|
+
*
|
|
6
|
+
* @category Internal
|
|
7
|
+
* @category Package : @rest-vir/define-service
|
|
8
|
+
* @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
|
|
9
|
+
*/
|
|
10
|
+
export type ParamData = Partial<Record<string, string | string[]>>;
|
|
11
|
+
/**
|
|
12
|
+
* A match result that contains data about the path match. Used in {@link Match}
|
|
13
|
+
*
|
|
14
|
+
* This is from the [path-to-regexp](https://www.npmjs.com/package/path-to-regexp) package.
|
|
15
|
+
*
|
|
16
|
+
* @category Internal
|
|
17
|
+
* @category Package : @rest-vir/define-service
|
|
18
|
+
* @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
|
|
19
|
+
*/
|
|
20
|
+
export type MatchResult = {
|
|
21
|
+
path: string;
|
|
22
|
+
params: ParamData;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* A match is either `false` (no match) or a match result.
|
|
26
|
+
*
|
|
27
|
+
* This is from the [path-to-regexp](https://www.npmjs.com/package/path-to-regexp) package.
|
|
28
|
+
*
|
|
29
|
+
* @category Internal
|
|
30
|
+
* @category Package : @rest-vir/define-service
|
|
31
|
+
* @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
|
|
32
|
+
*/
|
|
33
|
+
export type Match = false | MatchResult;
|
|
34
|
+
/**
|
|
35
|
+
* A match function that takes a string and returns whether it matched the path. Used in
|
|
36
|
+
* {@link match}.
|
|
37
|
+
*
|
|
38
|
+
* This is from the [path-to-regexp](https://www.npmjs.com/package/path-to-regexp) package.
|
|
39
|
+
*
|
|
40
|
+
* @category Internal
|
|
41
|
+
* @category Package : @rest-vir/define-service
|
|
42
|
+
* @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
|
|
43
|
+
*/
|
|
44
|
+
export type MatchFunction = (path: string) => Match;
|
|
45
|
+
/**
|
|
46
|
+
* Transform a path into a match function.
|
|
47
|
+
*
|
|
48
|
+
* This is from the [path-to-regexp](https://www.npmjs.com/package/path-to-regexp) package.
|
|
49
|
+
*
|
|
50
|
+
* @category Internal
|
|
51
|
+
* @category Package : @rest-vir/define-service
|
|
52
|
+
* @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
|
|
53
|
+
*/
|
|
54
|
+
export declare function match(path: string): MatchFunction;
|