@rest-vir/define-service 1.2.5 → 1.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,11 +1,56 @@
1
+ import { type IsEqual, type IsNever } from 'type-fest';
2
+ import { type NoParam } from '../util/no-param.js';
1
3
  /**
2
- * Extracts all path parameters from an endpoint path.
4
+ * Extracts all named path parameters from an endpoint path.
3
5
  *
4
6
  * @category Internal
5
7
  * @category Package : @rest-vir/define-service
6
8
  * @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
7
9
  */
8
- export type PathParams<EndpointPath extends string> = string extends EndpointPath ? Record<string, string> : EndpointPath extends `${string}:${infer Param}/${infer Rest}` ? Param | PathParams<`/${Rest}`> : EndpointPath extends `${string}:${infer Param}` ? Param : never;
10
+ export type NamedPathParams<EndpointPath extends string> = string extends EndpointPath ? string : EndpointPath extends `${string}:${infer Param}/${infer Rest}` ? Param | NamedPathParams<`/${Rest}`> : EndpointPath extends `${string}:${infer Param}` ? Param : IsEqual<`/${string}`, EndpointPath> extends true ? string : never;
11
+ /**
12
+ * Determines if the given endpoint path has a trailing wildcard.
13
+ *
14
+ * @category Internal
15
+ * @category Package : @rest-vir/define-service
16
+ * @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
17
+ */
18
+ export type HasWildcardParam<EndpointPath extends string> = string extends EndpointPath ? boolean : EndpointPath extends `${string}/*` ? true : IsEqual<`/${string}`, EndpointPath> extends true ? boolean : false;
19
+ /**
20
+ * Extracts named and wildcard path params.
21
+ *
22
+ * @category Internal
23
+ * @category Package : @rest-vir/define-service
24
+ * @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
25
+ */
26
+ export type PathParams<EndpointPath extends string> = {
27
+ namedParams: NamedPathParams<EndpointPath>;
28
+ hasWildcard: HasWildcardParam<EndpointPath>;
29
+ };
30
+ export type GenericPathParams = {
31
+ pathParams: Readonly<Record<string, string>>;
32
+ wildcard: string | undefined;
33
+ };
34
+ /**
35
+ * Converts an endpoint path into the fetch params needed for its to operate.
36
+ *
37
+ * @category Internal
38
+ * @category Package : @rest-vir/define-service
39
+ * @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
40
+ */
41
+ export type ConstructPathParams<EndpointPath extends string | NoParam> = EndpointPath extends NoParam ? GenericPathParams : (IsEqual<PathParams<Exclude<EndpointPath, NoParam>>['hasWildcard'], true> extends true ? Readonly<{
42
+ wildcard: string;
43
+ }> : IsEqual<PathParams<Exclude<EndpointPath, NoParam>>['hasWildcard'], false> extends true ? Readonly<{
44
+ wildcard?: undefined;
45
+ }> : Readonly<{
46
+ wildcard?: string | undefined;
47
+ }>) & (IsNever<PathParams<Exclude<EndpointPath, NoParam>>['namedParams']> extends true ? Readonly<{
48
+ pathParams?: undefined;
49
+ }> : PathParams<Exclude<EndpointPath, NoParam>>['namedParams'] extends string ? Readonly<{
50
+ pathParams: Readonly<Record<PathParams<Exclude<EndpointPath, NoParam>>['namedParams'], string>>;
51
+ }> : Readonly<{
52
+ pathParams?: undefined;
53
+ }>);
9
54
  /**
10
55
  * Base requirement for endpoint paths.
11
56
  *
@@ -1,6 +1,5 @@
1
1
  import { type RequiredKeysOf, type SelectFrom } from '@augment-vir/common';
2
- import { type IsNever } from 'type-fest';
3
- import { type PathParams } from '../endpoint/endpoint-path.js';
2
+ import { type ConstructPathParams } from '../endpoint/endpoint-path.js';
4
3
  import { type NoParam } from '../util/no-param.js';
5
4
  import { type CommonWebSocket } from '../web-socket/common-web-socket.js';
6
5
  import { type ClientWebSocket, type ConnectWebSocketListeners, type GenericConnectWebSocketParams } from '../web-socket/overwrite-web-socket-methods.js';
@@ -51,16 +50,7 @@ export type ConnectWebSocketParams<WebSocketToConnect extends Readonly<SelectFro
51
50
  * requiring externally adding them.
52
51
  */
53
52
  listeners?: ConnectWebSocketListeners<WebSocketToConnect, WebSocketClass>;
54
- } & (IsNever<PathParams<WebSocketToConnect['path']>> extends true ? {
55
- /** This WebSocket has no path parameters to configure. */
56
- pathParams?: undefined;
57
- } : PathParams<WebSocketToConnect['path']> extends string ? {
58
- /** Required path params for this WebSocket's path. */
59
- pathParams: Readonly<Record<PathParams<WebSocketToConnect['path']>, string>>;
60
- } : {
61
- /** This WebSocket has no path parameters to configure. */
62
- pathParams?: undefined;
63
- }) & (AllowWebSocketMock extends true ? Pick<GenericConnectWebSocketParams<WebSocketClass>, 'webSocketConstructor'> : unknown) & (WebSocketToConnect['protocolsShape'] extends undefined ? {
53
+ } & ConstructPathParams<WebSocketToConnect['path']> & (AllowWebSocketMock extends true ? Pick<GenericConnectWebSocketParams<WebSocketClass>, 'webSocketConstructor'> : unknown) & (WebSocketToConnect['protocolsShape'] extends undefined ? {
64
54
  protocols?: string[];
65
55
  } : {
66
56
  protocols: WebSocketToConnect['ProtocolsType'];
@@ -1,6 +1,6 @@
1
- import { HttpMethod, type ExtractKeysWithMatchingValues, type KeyCount, type MaybePromise, type RequiredKeysOf, type SelectFrom } from '@augment-vir/common';
1
+ import { HttpMethod, type ExtractKeysWithMatchingValues, type KeyCount, type MaybePromise, type PartialWithUndefined, type RequiredKeysOf, type SelectFrom } from '@augment-vir/common';
2
2
  import { type IsEqual, type IsNever } from 'type-fest';
3
- import { type PathParams } from '../endpoint/endpoint-path.js';
3
+ import { type ConstructPathParams, type GenericPathParams } from '../endpoint/endpoint-path.js';
4
4
  import { type EndpointDefinition, type EndpointExecutorData, type GenericEndpointDefinition } from '../endpoint/endpoint.js';
5
5
  import { type NoParam } from '../util/no-param.js';
6
6
  import { type BaseSearchParams } from '../util/search-params.js';
@@ -12,8 +12,7 @@ import { type BaseSearchParams } from '../util/search-params.js';
12
12
  * @category Package : @rest-vir/define-service
13
13
  * @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
14
14
  */
15
- export type GenericFetchEndpointParams = {
16
- pathParams?: Record<string, string> | undefined;
15
+ export type GenericFetchEndpointParams = PartialWithUndefined<GenericPathParams> & {
17
16
  requestData?: any;
18
17
  searchParams?: BaseSearchParams | undefined;
19
18
  bypassResponseValidation?: undefined | boolean;
@@ -45,15 +44,7 @@ export type FetchEndpointParams<EndpointToFetch extends SelectFrom<EndpointDefin
45
44
  requestDataShape: true;
46
45
  responseDataShape: true;
47
46
  methods: true;
48
- }>, AllowFetchMock extends boolean = true> = EndpointToFetch extends EndpointDefinition ? Readonly<(IsNever<PathParams<EndpointToFetch['path']>> extends true ? {
49
- /** This endpoint has no path parameters to configure. */
50
- pathParams?: undefined;
51
- } : PathParams<EndpointToFetch['path']> extends string ? {
52
- pathParams: Readonly<Record<PathParams<EndpointToFetch['path']>, string>>;
53
- } : {
54
- /** This endpoint has no path parameters to configure. */
55
- pathParams?: undefined;
56
- }) & (EndpointToFetch['SearchParamsType'] extends undefined ? {
47
+ }>, AllowFetchMock extends boolean = true> = EndpointToFetch extends EndpointDefinition ? Readonly<ConstructPathParams<EndpointToFetch['path']> & (EndpointToFetch['SearchParamsType'] extends undefined ? {
57
48
  searchParams?: never;
58
49
  } : {
59
50
  searchParams: EndpointToFetch['SearchParamsType'];
@@ -181,7 +172,7 @@ export declare function buildEndpointRequestInit<const EndpointToFetch extends R
181
172
  serviceOrigin: true;
182
173
  serviceName: true;
183
174
  };
184
- }>, ...[{ method, options, pathParams, requestData, searchParams },]: CollapsedFetchEndpointParams<EndpointToFetch, false>): {
175
+ }>, ...[{ method, options, pathParams, requestData, searchParams, wildcard },]: CollapsedFetchEndpointParams<EndpointToFetch, false>): {
185
176
  url: string;
186
177
  requestInit: RequestInit;
187
178
  };
@@ -212,4 +203,4 @@ export declare function buildEndpointUrl<const EndpointToFetch extends Readonly<
212
203
  searchParamsShape: true;
213
204
  responseDataShape: true;
214
205
  methods: true;
215
- }>, { pathParams, searchParams, }: Pick<EndpointToFetch extends NoParam ? Readonly<GenericFetchEndpointParams> : Readonly<FetchEndpointParams<Exclude<EndpointToFetch, NoParam>>>, 'pathParams' | 'searchParams'>): string;
206
+ }>, { pathParams, searchParams, wildcard, }: Pick<EndpointToFetch extends NoParam ? Readonly<GenericFetchEndpointParams> : Readonly<FetchEndpointParams<Exclude<EndpointToFetch, NoParam>>>, 'pathParams' | 'searchParams' | 'wildcard'>): string;
@@ -93,7 +93,7 @@ export async function fetchEndpoint(endpoint, ...params) {
93
93
  * @category Package : @rest-vir/define-service
94
94
  * @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
95
95
  */
96
- export function buildEndpointRequestInit(endpoint, ...[{ method, options = {}, pathParams, requestData, searchParams } = {},]) {
96
+ export function buildEndpointRequestInit(endpoint, ...[{ method, options = {}, pathParams, requestData, searchParams, wildcard } = {},]) {
97
97
  const headers = options.headers instanceof Headers
98
98
  ? Object.fromEntries(options.headers.entries())
99
99
  : check.isArray(options.headers)
@@ -115,6 +115,7 @@ export function buildEndpointRequestInit(endpoint, ...[{ method, options = {}, p
115
115
  const url = buildEndpointUrl(endpoint, {
116
116
  pathParams,
117
117
  searchParams,
118
+ wildcard,
118
119
  });
119
120
  const requestInit = {
120
121
  ...options,
@@ -142,7 +143,7 @@ export function buildEndpointRequestInit(endpoint, ...[{ method, options = {}, p
142
143
  * @category Package : @rest-vir/define-service
143
144
  * @package [`@rest-vir/define-service`](https://www.npmjs.com/package/@rest-vir/define-service)
144
145
  */
145
- export function buildEndpointUrl(endpoint, { pathParams, searchParams, }) {
146
+ export function buildEndpointUrl(endpoint, { pathParams, searchParams, wildcard, }) {
146
147
  let pathParamsCount = 0;
147
148
  if (endpoint.searchParamsShape) {
148
149
  assertValidShape(searchParams, endpoint.searchParamsShape, {
@@ -150,20 +151,26 @@ export function buildEndpointUrl(endpoint, { pathParams, searchParams, }) {
150
151
  allowExtraKeys: true,
151
152
  }, `Invalid search params given to '${endpoint.path}' in service '${endpoint.service.serviceName}'`);
152
153
  }
154
+ if (endpoint.path.endsWith('/*') && wildcard == undefined) {
155
+ throw new Error('Missing value for wildcard param.');
156
+ }
157
+ const pathname = endpoint.path
158
+ .replaceAll(/\/:([^/]+)/g, (wholeMatch, paramName) => {
159
+ pathParamsCount++;
160
+ if (pathParams && check.hasKey(pathParams, paramName) && pathParams[paramName]) {
161
+ return addPrefix({
162
+ value: pathParams[paramName],
163
+ prefix: '/',
164
+ });
165
+ }
166
+ else {
167
+ throw new Error(`Missing value for path param '${paramName}'.`);
168
+ }
169
+ })
170
+ .replace(/\/\*$/, addPrefix({ value: wildcard || '', prefix: '/' }));
153
171
  const builtUrl = buildUrl(endpoint.service.serviceOrigin, {
154
172
  search: searchParams,
155
- pathname: endpoint.path.replaceAll(/\/:([^/]+)/g, (wholeMatch, paramName) => {
156
- pathParamsCount++;
157
- if (pathParams && check.hasKey(pathParams, paramName) && pathParams[paramName]) {
158
- return addPrefix({
159
- value: pathParams[paramName],
160
- prefix: '/',
161
- });
162
- }
163
- else {
164
- throw new Error(`Missing value for path param '${paramName}'.`);
165
- }
166
- }),
173
+ pathname,
167
174
  }).href;
168
175
  if (!pathParamsCount && pathParams) {
169
176
  throw new Error(`'${endpoint.path}' in service '${endpoint.service.serviceName}' does not allow any path params but some where set.`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rest-vir/define-service",
3
- "version": "1.2.5",
3
+ "version": "1.2.6",
4
4
  "description": "Define an connect to a declarative and type safe REST and WebSocket service.",
5
5
  "keywords": [
6
6
  "rest",
@@ -40,14 +40,14 @@
40
40
  "test:update": "npm test update"
41
41
  },
42
42
  "dependencies": {
43
- "@augment-vir/assert": "^31.40.0",
44
- "@augment-vir/common": "^31.40.0",
43
+ "@augment-vir/assert": "^31.46.1",
44
+ "@augment-vir/common": "^31.46.1",
45
45
  "date-vir": "^8.0.0",
46
46
  "type-fest": "^5.1.0",
47
47
  "url-vir": "^2.1.6"
48
48
  },
49
49
  "devDependencies": {
50
- "@augment-vir/test": "^31.40.0",
50
+ "@augment-vir/test": "^31.46.1",
51
51
  "@web/dev-server-esbuild": "^1.0.4",
52
52
  "@web/test-runner": "^0.20.2",
53
53
  "@web/test-runner-commands": "^0.9.0",
@@ -55,7 +55,7 @@
55
55
  "@web/test-runner-visual-regression": "^0.10.0",
56
56
  "istanbul-smart-text-reporter": "^1.1.5",
57
57
  "markdown-code-example-inserter": "^3.0.3",
58
- "object-shape-tester": "^6.9.2",
58
+ "object-shape-tester": "^6.9.3",
59
59
  "typedoc": "^0.28.14",
60
60
  "ws": "^8.18.3"
61
61
  },