@slango/ristretto 1.0.0
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/.turbo/turbo-build.log +4 -0
- package/CHANGELOG.md +7 -0
- package/LICENSE +201 -0
- package/README.md +1 -0
- package/dist/abortable/index.d.ts +18 -0
- package/dist/abortable/index.d.ts.map +1 -0
- package/dist/abortable/index.js +22 -0
- package/dist/abortable/index.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/index.d.ts +12 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +2 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/middleware/runner.d.ts +12 -0
- package/dist/middleware/runner.d.ts.map +1 -0
- package/dist/middleware/runner.js +48 -0
- package/dist/middleware/runner.js.map +1 -0
- package/dist/utils/HttpError.d.ts +5 -0
- package/dist/utils/HttpError.d.ts.map +1 -0
- package/dist/utils/HttpError.js +9 -0
- package/dist/utils/HttpError.js.map +1 -0
- package/dist/utils/abortableRequest.d.ts +7 -0
- package/dist/utils/abortableRequest.d.ts.map +1 -0
- package/dist/utils/abortableRequest.js +12 -0
- package/dist/utils/abortableRequest.js.map +1 -0
- package/dist/utils/auth.d.ts +4 -0
- package/dist/utils/auth.d.ts.map +1 -0
- package/dist/utils/auth.js +8 -0
- package/dist/utils/auth.js.map +1 -0
- package/dist/utils/baseUrl.d.ts +5 -0
- package/dist/utils/baseUrl.d.ts.map +1 -0
- package/dist/utils/baseUrl.js +8 -0
- package/dist/utils/baseUrl.js.map +1 -0
- package/dist/utils/body.d.ts +16 -0
- package/dist/utils/body.d.ts.map +1 -0
- package/dist/utils/body.js +37 -0
- package/dist/utils/body.js.map +1 -0
- package/dist/utils/httpMethod.d.ts +12 -0
- package/dist/utils/httpMethod.d.ts.map +1 -0
- package/dist/utils/httpMethod.js +13 -0
- package/dist/utils/httpMethod.js.map +1 -0
- package/dist/utils/queryParams.d.ts +8 -0
- package/dist/utils/queryParams.d.ts.map +1 -0
- package/dist/utils/queryParams.js +19 -0
- package/dist/utils/queryParams.js.map +1 -0
- package/dist/utils/request.d.ts +15 -0
- package/dist/utils/request.d.ts.map +1 -0
- package/dist/utils/request.js +28 -0
- package/dist/utils/request.js.map +1 -0
- package/dist/utils/status.d.ts +3 -0
- package/dist/utils/status.d.ts.map +1 -0
- package/dist/utils/status.js +13 -0
- package/dist/utils/status.js.map +1 -0
- package/eslint.config.js +1 -0
- package/lint-staged.config.js +1 -0
- package/package.json +46 -0
- package/src/abortable/index.ts +48 -0
- package/src/index.ts +34 -0
- package/src/middleware/index.ts +20 -0
- package/src/middleware/runner.spec.ts +174 -0
- package/src/middleware/runner.ts +65 -0
- package/src/utils/HttpError.ts +9 -0
- package/src/utils/abortableRequest.spec.ts +50 -0
- package/src/utils/abortableRequest.ts +22 -0
- package/src/utils/auth.spec.ts +58 -0
- package/src/utils/auth.ts +16 -0
- package/src/utils/baseUrl.ts +16 -0
- package/src/utils/body.spec.ts +123 -0
- package/src/utils/body.ts +74 -0
- package/src/utils/httpMethod.ts +11 -0
- package/src/utils/queryParams.spec.ts +75 -0
- package/src/utils/queryParams.ts +31 -0
- package/src/utils/request.spec.ts +180 -0
- package/src/utils/request.ts +57 -0
- package/src/utils/status.spec.ts +66 -0
- package/src/utils/status.ts +15 -0
- package/tsconfig.build.json +10 -0
- package/tsconfig.build.tsbuildinfo +1 -0
- package/tsconfig.json +9 -0
- package/vitest.config.js +1 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { AbortablePromise } from './abortableRequest.js';
|
|
2
|
+
import { Request } from './request.js';
|
|
3
|
+
export type QueryParams = Record<string, QueryParamValue | QueryParamValue[]>;
|
|
4
|
+
type QueryParamValue = boolean | null | number | string | undefined;
|
|
5
|
+
export declare const queryParamsToURLSearchParams: (query: QueryParams) => URLSearchParams;
|
|
6
|
+
export declare const withQueryParams: <Query extends QueryParams>(query: Query) => <Response, PromiseType extends AbortablePromise<Response> | Promise<Response>>(req: Request<Response, PromiseType>) => Request<Response, PromiseType>;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=queryParams.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queryParams.d.ts","sourceRoot":"","sources":["../../src/utils/queryParams.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,GAAG,eAAe,EAAE,CAAC,CAAC;AAC9E,KAAK,eAAe,GAAG,OAAO,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;AAEpE,eAAO,MAAM,4BAA4B,GAAI,OAAO,WAAW,KAAG,eAYjE,CAAC;AAEF,eAAO,MAAM,eAAe,GACzB,KAAK,SAAS,WAAW,EAAE,OAAO,KAAK,MACvC,QAAQ,EAAE,WAAW,SAAS,gBAAgB,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,EAC3E,KAAK,OAAO,CAAC,QAAQ,EAAE,WAAW,CAAC,KAClC,OAAO,CAAC,QAAQ,EAAE,WAAW,CAM/B,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export const queryParamsToURLSearchParams = (query) => {
|
|
2
|
+
const params = new URLSearchParams();
|
|
3
|
+
Object.entries(query).forEach(([key, value]) => {
|
|
4
|
+
if (Array.isArray(value)) {
|
|
5
|
+
value.forEach((v) => params.append(key, String(v)));
|
|
6
|
+
}
|
|
7
|
+
else if (value !== null && value !== undefined) {
|
|
8
|
+
params.append(key, String(value));
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
return params;
|
|
12
|
+
};
|
|
13
|
+
export const withQueryParams = (query) => (req) => (options = {}) => {
|
|
14
|
+
return req({
|
|
15
|
+
...options,
|
|
16
|
+
searchParams: queryParamsToURLSearchParams(query),
|
|
17
|
+
});
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=queryParams.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queryParams.js","sourceRoot":"","sources":["../../src/utils/queryParams.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,KAAkB,EAAmB,EAAE;IAClF,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;IAErC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE;QAC7C,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACtD,CAAC;aAAM,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACjD,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACpC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAC1B,CAA4B,KAAY,EAAE,EAAE,CAC5C,CACE,GAAmC,EACH,EAAE,CACpC,CAAC,OAAO,GAAG,EAAE,EAAE,EAAE;IACf,OAAO,GAAG,CAAC;QACT,GAAG,OAAO;QACV,YAAY,EAAE,4BAA4B,CAAC,KAAK,CAAC;KAClD,CAAC,CAAC;AACL,CAAC,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { AbortablePromise } from './abortableRequest.js';
|
|
2
|
+
import { BaseURL } from './baseUrl.js';
|
|
3
|
+
import { HttpMethod } from './httpMethod.js';
|
|
4
|
+
type PathOnly = `../${string}` | `./${string}` | `/${string}`;
|
|
5
|
+
export type RequestURL = BaseURL | PathOnly;
|
|
6
|
+
export type Request<Response, PromiseType extends AbortablePromise<Response> | Promise<Response>> = (options?: RequestOptionsWithoutUrl) => PromiseType;
|
|
7
|
+
export type RequestOptions = RequestInit & {
|
|
8
|
+
searchParams?: URLSearchParams;
|
|
9
|
+
url: RequestURL;
|
|
10
|
+
baseUrl?: BaseURL;
|
|
11
|
+
};
|
|
12
|
+
export type RequestOptionsWithoutUrl = Omit<RequestOptions, 'url'>;
|
|
13
|
+
export declare const request: <Response>(method: HttpMethod, options: RequestOptions) => Promise<Response>;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=request.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../src/utils/request.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,OAAO,EAAqB,MAAM,cAAc,CAAC;AAE1D,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,KAAK,QAAQ,GAAG,MAAM,MAAM,EAAE,GAAG,KAAK,MAAM,EAAE,GAAG,IAAI,MAAM,EAAE,CAAC;AAE9D,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,QAAQ,CAAC;AAE5C,MAAM,MAAM,OAAO,CACjB,QAAQ,EACR,WAAW,SAAS,gBAAgB,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,IAChE,CAAC,OAAO,CAAC,EAAE,wBAAwB,KAAK,WAAW,CAAC;AAExD,MAAM,MAAM,cAAc,GAAG,WAAW,GAAG;IACzC,YAAY,CAAC,EAAE,eAAe,CAAC;IAC/B,GAAG,EAAE,UAAU,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG,IAAI,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;AAEnE,eAAO,MAAM,OAAO,GAAU,QAAQ,EACpC,QAAQ,UAAU,EAClB,SAAS,cAAc,KACtB,OAAO,CAAC,QAAQ,CA8BlB,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { runPostResponse, runPreRequest } from '../middleware/runner.js';
|
|
2
|
+
import { getDefaultBaseUrl } from './baseUrl.js';
|
|
3
|
+
import { HttpError } from './HttpError.js';
|
|
4
|
+
export const request = async (method, options) => {
|
|
5
|
+
const fetchOptions = {
|
|
6
|
+
method,
|
|
7
|
+
...options,
|
|
8
|
+
};
|
|
9
|
+
const middlewareContext = { request: fetchOptions };
|
|
10
|
+
await runPreRequest(middlewareContext);
|
|
11
|
+
const { searchParams, url, baseUrl, ...requestOptions } = fetchOptions;
|
|
12
|
+
const fullUrl = new URL(url, baseUrl || getDefaultBaseUrl());
|
|
13
|
+
if (searchParams) {
|
|
14
|
+
searchParams.forEach((value, key) => {
|
|
15
|
+
fullUrl.searchParams.append(key, value);
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
const response = await fetch(fullUrl.toString(), requestOptions);
|
|
19
|
+
await runPostResponse({ ...middlewareContext, response });
|
|
20
|
+
if (!response.ok) {
|
|
21
|
+
throw new HttpError(response.status, response.statusText);
|
|
22
|
+
}
|
|
23
|
+
if (response.status === 204 || !response.body) {
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
return (await response.json());
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=request.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request.js","sourceRoot":"","sources":["../../src/utils/request.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAEzE,OAAO,EAAW,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAoB3C,MAAM,CAAC,MAAM,OAAO,GAAG,KAAK,EAC1B,MAAkB,EAClB,OAAuB,EACJ,EAAE;IACrB,MAAM,YAAY,GAAG;QACnB,MAAM;QACN,GAAG,OAAO;KACX,CAAC;IACF,MAAM,iBAAiB,GAAG,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC;IACpD,MAAM,aAAa,CAAC,iBAAiB,CAAC,CAAC;IAEvC,MAAM,EAAE,YAAY,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,cAAc,EAAE,GAAG,YAAY,CAAC;IAEvE,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,GAAG,EAAE,OAAO,IAAI,iBAAiB,EAAE,CAAC,CAAC;IAC7D,IAAI,YAAY,EAAE,CAAC;QACjB,YAAY,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;YAClC,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC1C,CAAC,CAAC,CAAC;IACL,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,cAAc,CAAC,CAAC;IAEjE,MAAM,eAAe,CAAC,EAAE,GAAG,iBAAiB,EAAE,QAAQ,EAAE,CAAC,CAAC;IAE1D,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC;IAC5D,CAAC;IAED,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QAC9C,OAAO,SAAqB,CAAC;IAC/B,CAAC;IAED,OAAO,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAa,CAAC;AAC7C,CAAC,CAAC"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { RequestOptionsWithoutUrl } from './request.js';
|
|
2
|
+
export declare const withNotFoundAsNull: <Response>(requestFn: (options?: RequestOptionsWithoutUrl) => Promise<Response>) => (options?: RequestOptionsWithoutUrl) => Promise<null | Response>;
|
|
3
|
+
//# sourceMappingURL=status.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/utils/status.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAExD,eAAO,MAAM,kBAAkB,GAC5B,QAAQ,EAAE,WAAW,CAAC,OAAO,CAAC,EAAE,wBAAwB,KAAK,OAAO,CAAC,QAAQ,CAAC,MACxE,UAAU,wBAAwB,KAAG,OAAO,CAAC,IAAI,GAAG,QAAQ,CASlE,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { HttpError } from './HttpError.js';
|
|
2
|
+
export const withNotFoundAsNull = (requestFn) => async (options) => {
|
|
3
|
+
try {
|
|
4
|
+
return await requestFn(options);
|
|
5
|
+
}
|
|
6
|
+
catch (error) {
|
|
7
|
+
if (error instanceof HttpError && error.status == 404) {
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
throw error;
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/utils/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAG3C,MAAM,CAAC,MAAM,kBAAkB,GAC7B,CAAW,SAAoE,EAAE,EAAE,CACnF,KAAK,EAAE,OAAkC,EAA4B,EAAE;IACrE,IAAI,CAAC;QACH,OAAO,MAAM,SAAS,CAAC,OAAO,CAAC,CAAC;IAClC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,SAAS,IAAI,KAAK,CAAC,MAAM,IAAI,GAAG,EAAE,CAAC;YACtD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC,CAAC"}
|
package/eslint.config.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@slango.configs/eslint/typescript-isomorphic.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@slango.configs/lint-staged/typescript.js';
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@slango/ristretto",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "Opinionated rest client",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
"./abortable": {
|
|
11
|
+
"import": "./dist/abortable/index.js",
|
|
12
|
+
"types": "./dist/abortable/index.d.ts"
|
|
13
|
+
},
|
|
14
|
+
"./middleware": {
|
|
15
|
+
"import": "./dist/middleware/index.js",
|
|
16
|
+
"types": "./dist/middleware/index.d.ts"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@slango/ts-utils": "1.0.2"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@types/node": "24.2.0",
|
|
24
|
+
"@vitest/coverage-v8": "3.2.4",
|
|
25
|
+
"@vitest/ui": "3.2.4",
|
|
26
|
+
"eslint": "9.32.0",
|
|
27
|
+
"type-fest": "4.41.0",
|
|
28
|
+
"typescript": "5.9.2",
|
|
29
|
+
"vitest": "3.2.4",
|
|
30
|
+
"@slango.configs/typescript": "1.0.4",
|
|
31
|
+
"@slango.configs/vitest": "1.0.21",
|
|
32
|
+
"@slango.configs/eslint": "1.0.28"
|
|
33
|
+
},
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "tsc -p tsconfig.build.json",
|
|
36
|
+
"build:force": "tsc -p tsconfig.build.json --incremental false",
|
|
37
|
+
"build:watch": "tsc -p tsconfig.build.json --watch",
|
|
38
|
+
"build:check": "tsc --noEmit",
|
|
39
|
+
"lint": "eslint . --max-warnings 0",
|
|
40
|
+
"lint:fix": "eslint . --fix --max-warnings 0",
|
|
41
|
+
"test": "vitest --run",
|
|
42
|
+
"test:watch": "vitest",
|
|
43
|
+
"test:coverage": "vitest --run --coverage",
|
|
44
|
+
"test:ui": "vitest --ui"
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { AbortablePromise, abortableRequest } from '../utils/abortableRequest.js';
|
|
2
|
+
import { HttpMethod } from '../utils/httpMethod.js';
|
|
3
|
+
import { Request as BaseRequest, RequestOptionsWithoutUrl, RequestURL } from '../utils/request.js';
|
|
4
|
+
|
|
5
|
+
export type { AbortablePromise } from '../utils/abortableRequest.js';
|
|
6
|
+
export { withBearerToken } from '../utils/auth.js';
|
|
7
|
+
export type { BaseURL } from '../utils/baseUrl.js';
|
|
8
|
+
export { withFormDataBody, withJsonBody } from '../utils/body.js';
|
|
9
|
+
export { HttpError } from '../utils/HttpError.js';
|
|
10
|
+
export { withQueryParams } from '../utils/queryParams.js';
|
|
11
|
+
export type { RequestOptionsWithoutUrl, RequestURL } from '../utils/request.js';
|
|
12
|
+
export { withNotFoundAsNull } from '../utils/status.js';
|
|
13
|
+
|
|
14
|
+
export type Request<Response> = BaseRequest<Response, AbortablePromise<Response>>;
|
|
15
|
+
|
|
16
|
+
const abortableRequestFactory =
|
|
17
|
+
(method: HttpMethod) =>
|
|
18
|
+
<Response>(url: RequestURL) =>
|
|
19
|
+
(options?: RequestOptionsWithoutUrl): AbortablePromise<Response> =>
|
|
20
|
+
abortableRequest<Response>(method, { ...options, url });
|
|
21
|
+
|
|
22
|
+
export const get = abortableRequestFactory(HttpMethod.GET);
|
|
23
|
+
|
|
24
|
+
export const del = abortableRequestFactory(HttpMethod.DELETE);
|
|
25
|
+
|
|
26
|
+
export const post = abortableRequestFactory(HttpMethod.POST);
|
|
27
|
+
|
|
28
|
+
export const put = abortableRequestFactory(HttpMethod.PUT);
|
|
29
|
+
|
|
30
|
+
export const patch = abortableRequestFactory(HttpMethod.PATCH);
|
|
31
|
+
|
|
32
|
+
export const withTransformer =
|
|
33
|
+
<Input, Output>(transformFn: (input: Input) => Output) =>
|
|
34
|
+
(req: Request<Input>): Request<Output> =>
|
|
35
|
+
(options?: RequestOptionsWithoutUrl) => {
|
|
36
|
+
const abortablePromise = req(options);
|
|
37
|
+
|
|
38
|
+
const wrappedPromise = abortablePromise.then((result: Input) =>
|
|
39
|
+
transformFn ? transformFn(result) : result,
|
|
40
|
+
) as AbortablePromise<Output>;
|
|
41
|
+
|
|
42
|
+
if ('abort' in abortablePromise) {
|
|
43
|
+
// Assign the abort function if it's an AbortablePromise
|
|
44
|
+
wrappedPromise.abort = abortablePromise.abort;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return wrappedPromise;
|
|
48
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { HttpMethod } from './utils/httpMethod.js';
|
|
2
|
+
import {
|
|
3
|
+
Request as BaseRequest,
|
|
4
|
+
request,
|
|
5
|
+
RequestOptionsWithoutUrl,
|
|
6
|
+
RequestURL,
|
|
7
|
+
} from './utils/request.js';
|
|
8
|
+
|
|
9
|
+
export { withBearerToken } from './utils/auth.js';
|
|
10
|
+
export type { BaseURL } from './utils/baseUrl.js';
|
|
11
|
+
export { withFormDataBody, withJsonBody } from './utils/body.js';
|
|
12
|
+
export { HttpError } from './utils/HttpError.js';
|
|
13
|
+
export { withQueryParams } from './utils/queryParams.js';
|
|
14
|
+
export type { RequestOptionsWithoutUrl, RequestURL } from './utils/request.js';
|
|
15
|
+
|
|
16
|
+
export { withNotFoundAsNull } from './utils/status.js';
|
|
17
|
+
|
|
18
|
+
export type Request<Response> = BaseRequest<Response, Promise<Response>>;
|
|
19
|
+
|
|
20
|
+
const requestFactory =
|
|
21
|
+
(method: HttpMethod) =>
|
|
22
|
+
<Response>(url: RequestURL): Request<Response> =>
|
|
23
|
+
(options?: RequestOptionsWithoutUrl): Promise<Response> =>
|
|
24
|
+
request<Response>(method, { ...options, url });
|
|
25
|
+
|
|
26
|
+
export const get = requestFactory(HttpMethod.GET);
|
|
27
|
+
|
|
28
|
+
export const del = requestFactory(HttpMethod.DELETE);
|
|
29
|
+
|
|
30
|
+
export const post = requestFactory(HttpMethod.POST);
|
|
31
|
+
|
|
32
|
+
export const put = requestFactory(HttpMethod.PUT);
|
|
33
|
+
|
|
34
|
+
export const patch = requestFactory(HttpMethod.PATCH);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Promisable } from 'type-fest';
|
|
2
|
+
|
|
3
|
+
import { RequestOptions } from '../utils/request.js';
|
|
4
|
+
|
|
5
|
+
export type PreRequestMiddlewareContext = {
|
|
6
|
+
request: RequestOptions;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export type PostResponseMiddlewareContext = PreRequestMiddlewareContext & {
|
|
10
|
+
response: Response;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export type MiddlewareNext = (error?: Error) => Promisable<void>;
|
|
14
|
+
|
|
15
|
+
export type Middleware<Context> = (ctx: Context, next: MiddlewareNext) => Promisable<void>;
|
|
16
|
+
|
|
17
|
+
export {
|
|
18
|
+
addPostResponseMiddleware as usePostResponse,
|
|
19
|
+
addPreRequestMiddleware as usePreRequest,
|
|
20
|
+
} from './runner.js';
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
MiddlewareNext,
|
|
5
|
+
PostResponseMiddlewareContext,
|
|
6
|
+
PreRequestMiddlewareContext,
|
|
7
|
+
} from './index.js';
|
|
8
|
+
import {
|
|
9
|
+
addPostResponseMiddleware,
|
|
10
|
+
addPreRequestMiddleware,
|
|
11
|
+
clearPostResponseMiddlewares,
|
|
12
|
+
clearPreRequestMiddlewares,
|
|
13
|
+
removePostResponseMiddleware,
|
|
14
|
+
removePreRequestMiddleware,
|
|
15
|
+
runPostResponse,
|
|
16
|
+
runPreRequest,
|
|
17
|
+
} from './runner.js';
|
|
18
|
+
|
|
19
|
+
const createPreRequestContext = (): PreRequestMiddlewareContext => ({
|
|
20
|
+
request: { url: 'https://example.com', method: 'GET', headers: {} },
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const createPostResponseContext = (): PostResponseMiddlewareContext => ({
|
|
24
|
+
request: { url: 'https://example.com', method: 'GET', headers: {} },
|
|
25
|
+
response: new Response(null, { status: 200 }),
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
describe('runner.ts', () => {
|
|
29
|
+
beforeEach(() => {
|
|
30
|
+
clearPostResponseMiddlewares();
|
|
31
|
+
clearPreRequestMiddlewares();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should add and remove pre-request middleware', async () => {
|
|
35
|
+
const middleware1 = vi.fn((ctx, next: MiddlewareNext) => next());
|
|
36
|
+
const middleware2 = vi.fn();
|
|
37
|
+
|
|
38
|
+
addPreRequestMiddleware(middleware1);
|
|
39
|
+
addPreRequestMiddleware(middleware2);
|
|
40
|
+
await runPreRequest(createPreRequestContext());
|
|
41
|
+
expect(middleware1).toHaveBeenCalledTimes(1);
|
|
42
|
+
expect(middleware2).toHaveBeenCalledTimes(1);
|
|
43
|
+
|
|
44
|
+
removePreRequestMiddleware(middleware2);
|
|
45
|
+
await runPreRequest(createPreRequestContext());
|
|
46
|
+
expect(middleware1).toHaveBeenCalledTimes(2);
|
|
47
|
+
expect(middleware2).toHaveBeenCalledTimes(1);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('should add and remove post-request middleware', async () => {
|
|
51
|
+
const middleware1 = vi.fn((ctx, next: MiddlewareNext) => next());
|
|
52
|
+
const middleware2 = vi.fn();
|
|
53
|
+
|
|
54
|
+
addPostResponseMiddleware(middleware1);
|
|
55
|
+
addPostResponseMiddleware(middleware2);
|
|
56
|
+
await runPostResponse(createPostResponseContext());
|
|
57
|
+
expect(middleware1).toHaveBeenCalledTimes(1);
|
|
58
|
+
expect(middleware2).toHaveBeenCalledTimes(1);
|
|
59
|
+
|
|
60
|
+
removePostResponseMiddleware(middleware2);
|
|
61
|
+
await runPostResponse(createPostResponseContext());
|
|
62
|
+
expect(middleware1).toHaveBeenCalledTimes(2);
|
|
63
|
+
expect(middleware2).toHaveBeenCalledTimes(1);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('should run pre-request middlewares in order and modify context', async () => {
|
|
67
|
+
const middleware1 = vi.fn(async (ctx: PreRequestMiddlewareContext, next: MiddlewareNext) => {
|
|
68
|
+
(ctx.request.headers! as Record<string, string>)['X-Test'] = 'Middleware1';
|
|
69
|
+
(ctx.request.headers! as Record<string, string>)['X-Override'] = 'Middleware1';
|
|
70
|
+
await next();
|
|
71
|
+
});
|
|
72
|
+
const middleware2 = vi.fn(async (ctx: PreRequestMiddlewareContext, next: MiddlewareNext) => {
|
|
73
|
+
(ctx.request.headers! as Record<string, string>)['X-Chain'] = 'Middleware2';
|
|
74
|
+
(ctx.request.headers! as Record<string, string>)['X-Override'] = 'Middleware2';
|
|
75
|
+
await next();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
addPreRequestMiddleware(middleware1);
|
|
79
|
+
addPreRequestMiddleware(middleware2);
|
|
80
|
+
|
|
81
|
+
const context = createPreRequestContext();
|
|
82
|
+
await runPreRequest(context);
|
|
83
|
+
|
|
84
|
+
expect(middleware1).toHaveBeenCalledOnce();
|
|
85
|
+
expect(middleware2).toHaveBeenCalledOnce();
|
|
86
|
+
expect(context.request.headers).toEqual({
|
|
87
|
+
'X-Test': 'Middleware1',
|
|
88
|
+
'X-Chain': 'Middleware2',
|
|
89
|
+
'X-Override': 'Middleware2',
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('should run post-response middlewares in order and modify context', async () => {
|
|
94
|
+
const middleware1 = vi.fn(async (ctx: PostResponseMiddlewareContext, next: MiddlewareNext) => {
|
|
95
|
+
ctx.response.headers.set('X-Test', 'Middleware1');
|
|
96
|
+
ctx.response.headers.set('X-Override', 'Middleware1');
|
|
97
|
+
await next();
|
|
98
|
+
});
|
|
99
|
+
const middleware2 = vi.fn(async (ctx: PostResponseMiddlewareContext, next: MiddlewareNext) => {
|
|
100
|
+
ctx.response.headers.set('X-Chain', 'Middleware2');
|
|
101
|
+
ctx.response.headers.set('X-Override', 'Middleware2');
|
|
102
|
+
|
|
103
|
+
await next();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
addPostResponseMiddleware(middleware1);
|
|
107
|
+
addPostResponseMiddleware(middleware2);
|
|
108
|
+
|
|
109
|
+
const context = createPostResponseContext();
|
|
110
|
+
await runPostResponse(context);
|
|
111
|
+
|
|
112
|
+
expect(middleware1).toHaveBeenCalledOnce();
|
|
113
|
+
expect(middleware2).toHaveBeenCalledOnce();
|
|
114
|
+
expect(context.response.headers.get('X-Test')).toBe('Middleware1');
|
|
115
|
+
expect(context.response.headers.get('X-Chain')).toBe('Middleware2');
|
|
116
|
+
expect(context.response.headers.get('X-Override')).toBe('Middleware2');
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('should handle errors in pre-request middlewares and stop pipeline', async () => {
|
|
120
|
+
const middleware1 = vi.fn(async (ctx: PreRequestMiddlewareContext, next: MiddlewareNext) => {
|
|
121
|
+
await next();
|
|
122
|
+
});
|
|
123
|
+
const errorMiddleware = vi.fn(() => {
|
|
124
|
+
throw new Error('Test error');
|
|
125
|
+
});
|
|
126
|
+
const middleware2 = vi.fn(async (ctx: PreRequestMiddlewareContext, next: MiddlewareNext) => {
|
|
127
|
+
await next();
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
addPreRequestMiddleware(middleware1);
|
|
131
|
+
addPreRequestMiddleware(errorMiddleware);
|
|
132
|
+
addPreRequestMiddleware(middleware2);
|
|
133
|
+
|
|
134
|
+
const context = createPreRequestContext();
|
|
135
|
+
|
|
136
|
+
await expect(runPreRequest(context)).rejects.toThrow('Test error');
|
|
137
|
+
|
|
138
|
+
expect(middleware1).toHaveBeenCalledOnce();
|
|
139
|
+
expect(errorMiddleware).toHaveBeenCalledOnce();
|
|
140
|
+
expect(middleware2).not.toHaveBeenCalled();
|
|
141
|
+
|
|
142
|
+
removePreRequestMiddleware(middleware1);
|
|
143
|
+
removePreRequestMiddleware(errorMiddleware);
|
|
144
|
+
removePreRequestMiddleware(middleware2);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('should handle errors in post-response middlewares and stop pipeline', async () => {
|
|
148
|
+
const middleware1 = vi.fn(async (ctx: PostResponseMiddlewareContext, next: MiddlewareNext) => {
|
|
149
|
+
await next();
|
|
150
|
+
});
|
|
151
|
+
const errorMiddleware = vi.fn(() => {
|
|
152
|
+
throw new Error('Test error');
|
|
153
|
+
});
|
|
154
|
+
const middleware2 = vi.fn(async (ctx: PostResponseMiddlewareContext, next: MiddlewareNext) => {
|
|
155
|
+
await next();
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
addPostResponseMiddleware(middleware1);
|
|
159
|
+
addPostResponseMiddleware(errorMiddleware);
|
|
160
|
+
addPostResponseMiddleware(middleware2);
|
|
161
|
+
|
|
162
|
+
const context = createPostResponseContext();
|
|
163
|
+
|
|
164
|
+
await expect(runPostResponse(context)).rejects.toThrow('Test error');
|
|
165
|
+
|
|
166
|
+
expect(middleware1).toHaveBeenCalledOnce();
|
|
167
|
+
expect(errorMiddleware).toHaveBeenCalledOnce();
|
|
168
|
+
expect(middleware2).not.toHaveBeenCalled();
|
|
169
|
+
|
|
170
|
+
removePostResponseMiddleware(middleware1);
|
|
171
|
+
removePostResponseMiddleware(errorMiddleware);
|
|
172
|
+
removePostResponseMiddleware(middleware2);
|
|
173
|
+
});
|
|
174
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Middleware,
|
|
3
|
+
MiddlewareNext,
|
|
4
|
+
PostResponseMiddlewareContext,
|
|
5
|
+
PreRequestMiddlewareContext,
|
|
6
|
+
} from './index.js';
|
|
7
|
+
|
|
8
|
+
export type PostResponseMiddleWare = Middleware<PostResponseMiddlewareContext>;
|
|
9
|
+
export type PreRequestMiddleWare = Middleware<PreRequestMiddlewareContext>;
|
|
10
|
+
|
|
11
|
+
const preRequestMiddlewares: PreRequestMiddleWare[] = [];
|
|
12
|
+
const postResponseMiddlewares: PostResponseMiddleWare[] = [];
|
|
13
|
+
|
|
14
|
+
export const addPreRequestMiddleware = (middleware: PreRequestMiddleWare) => {
|
|
15
|
+
preRequestMiddlewares.push(middleware);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const addPostResponseMiddleware = (middleware: PostResponseMiddleWare) => {
|
|
19
|
+
postResponseMiddlewares.push(middleware);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const removePreRequestMiddleware = (middleware: PreRequestMiddleWare) => {
|
|
23
|
+
const index = preRequestMiddlewares.findIndex((m) => m === middleware);
|
|
24
|
+
if (index !== -1) preRequestMiddlewares.splice(index, 1);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const removePostResponseMiddleware = (middleware: PostResponseMiddleWare) => {
|
|
28
|
+
const index = postResponseMiddlewares.findIndex((m) => m === middleware);
|
|
29
|
+
if (index !== -1) postResponseMiddlewares.splice(index, 1);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const clearPreRequestMiddlewares = () => {
|
|
33
|
+
preRequestMiddlewares.length = 0;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const clearPostResponseMiddlewares = () => {
|
|
37
|
+
postResponseMiddlewares.length = 0;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const runMiddlewares = <Context>(middlewares: Middleware<Context>[]) => {
|
|
41
|
+
return async (context: Context): Promise<void> => {
|
|
42
|
+
let index = 0;
|
|
43
|
+
|
|
44
|
+
const next: MiddlewareNext = async (error?: Error) => {
|
|
45
|
+
if (error) {
|
|
46
|
+
throw error;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (index < middlewares.length) {
|
|
50
|
+
const currentMiddleware = middlewares[index];
|
|
51
|
+
index++;
|
|
52
|
+
try {
|
|
53
|
+
await currentMiddleware(context, next);
|
|
54
|
+
} catch (err) {
|
|
55
|
+
await next(err as Error);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
await next();
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export const runPreRequest = runMiddlewares(preRequestMiddlewares);
|
|
65
|
+
export const runPostResponse = runMiddlewares(postResponseMiddlewares);
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { abortableRequest } from './abortableRequest.js';
|
|
4
|
+
import { HttpMethod } from './httpMethod.js';
|
|
5
|
+
import { request, RequestOptions } from './request.js';
|
|
6
|
+
|
|
7
|
+
vi.mock('./request', () => ({
|
|
8
|
+
request: vi.fn(),
|
|
9
|
+
}));
|
|
10
|
+
|
|
11
|
+
const requestMock = vi.mocked(request);
|
|
12
|
+
|
|
13
|
+
afterEach(() => {
|
|
14
|
+
vi.clearAllMocks();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
describe('abortableRequest', () => {
|
|
18
|
+
it('should create a request with the given method and options', async () => {
|
|
19
|
+
const method = HttpMethod.GET;
|
|
20
|
+
const options: RequestOptions = {
|
|
21
|
+
headers: { 'Content-Type': 'application/json' },
|
|
22
|
+
url: '/api/test',
|
|
23
|
+
};
|
|
24
|
+
const mockResponse = Promise.resolve('response');
|
|
25
|
+
requestMock.mockReturnValue(mockResponse);
|
|
26
|
+
|
|
27
|
+
const result = abortableRequest(method, options);
|
|
28
|
+
|
|
29
|
+
expect(request).toHaveBeenCalledWith(method, {
|
|
30
|
+
...options,
|
|
31
|
+
signal: expect.any(AbortSignal) as AbortSignal,
|
|
32
|
+
});
|
|
33
|
+
await expect(result).resolves.toBe('response');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('should abort the request when abort is called', async () => {
|
|
37
|
+
const method = HttpMethod.POST;
|
|
38
|
+
const options: RequestOptions = { url: '/api/test' };
|
|
39
|
+
|
|
40
|
+
const mockedResponse = new Promise((_, reject) => {
|
|
41
|
+
setTimeout(() => reject(new DOMException('Aborted', 'AbortError')));
|
|
42
|
+
});
|
|
43
|
+
requestMock.mockReturnValueOnce(mockedResponse);
|
|
44
|
+
|
|
45
|
+
const abortable = abortableRequest(method, options);
|
|
46
|
+
abortable.abort();
|
|
47
|
+
|
|
48
|
+
await expect(abortable).rejects.toThrowError('Aborted');
|
|
49
|
+
});
|
|
50
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { HttpMethod } from './httpMethod.js';
|
|
2
|
+
import { request, RequestOptions } from './request.js';
|
|
3
|
+
|
|
4
|
+
export interface AbortablePromise<Response> extends Promise<Response> {
|
|
5
|
+
abort: () => void;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const abortableRequest = <Response>(
|
|
9
|
+
method: HttpMethod,
|
|
10
|
+
options: RequestOptions,
|
|
11
|
+
): AbortablePromise<Response> => {
|
|
12
|
+
const controller = new AbortController();
|
|
13
|
+
const signal = controller.signal;
|
|
14
|
+
|
|
15
|
+
const r = request(method, {
|
|
16
|
+
signal,
|
|
17
|
+
...options,
|
|
18
|
+
}) as AbortablePromise<Response>;
|
|
19
|
+
r.abort = () => controller.abort();
|
|
20
|
+
|
|
21
|
+
return r;
|
|
22
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { get, post, put } from '../index.js';
|
|
4
|
+
import { withBearerToken } from './auth.js';
|
|
5
|
+
import { request } from './request.js';
|
|
6
|
+
|
|
7
|
+
vi.mock('./request.js', () => ({
|
|
8
|
+
request: vi.fn(),
|
|
9
|
+
}));
|
|
10
|
+
|
|
11
|
+
const requestMock = vi.mocked(request);
|
|
12
|
+
|
|
13
|
+
const getRequest = get('/api/data/get');
|
|
14
|
+
const postRequest = post('/api/data/post');
|
|
15
|
+
const putRequest = put('/api/data/put');
|
|
16
|
+
|
|
17
|
+
afterEach(() => {
|
|
18
|
+
vi.clearAllMocks();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe('withBearerToken', () => {
|
|
22
|
+
it('should add the Authorization header with the provided bearer token', async () => {
|
|
23
|
+
const bearerToken = 'test-token';
|
|
24
|
+
await withBearerToken(bearerToken)(getRequest)();
|
|
25
|
+
const requestHeaders = requestMock.mock.calls[0][1].headers!;
|
|
26
|
+
|
|
27
|
+
expect(requestHeaders).toEqual({
|
|
28
|
+
Authorization: `Bearer ${bearerToken}`,
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('should merge the Authorization header with existing headers', async () => {
|
|
33
|
+
const bearerToken = 'test-token';
|
|
34
|
+
await withBearerToken(bearerToken)(postRequest)({
|
|
35
|
+
headers: { 'X-Test': 'Value' },
|
|
36
|
+
});
|
|
37
|
+
const requestHeaders = requestMock.mock.calls[0][1].headers!;
|
|
38
|
+
|
|
39
|
+
expect(requestHeaders).toEqual({
|
|
40
|
+
Authorization: `Bearer ${bearerToken}`,
|
|
41
|
+
'X-Test': 'Value',
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('should override any existing Authorization header with the provided bearer token', async () => {
|
|
46
|
+
const bearerToken = 'new-token';
|
|
47
|
+
await withBearerToken(bearerToken)(putRequest)({
|
|
48
|
+
headers: {
|
|
49
|
+
Authorization: `Bearer Test Test`,
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
const requestHeaders = requestMock.mock.calls[0][1].headers!;
|
|
53
|
+
|
|
54
|
+
expect(requestHeaders).toEqual({
|
|
55
|
+
Authorization: `Bearer ${bearerToken}`,
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
});
|