@odata2ts/http-client-base 0.2.0 → 0.3.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/CHANGELOG.md CHANGED
@@ -3,6 +3,20 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [0.3.0](https://github.com/odata2ts/http-client/compare/@odata2ts/http-client-base@0.2.0...@odata2ts/http-client-base@0.3.0) (2023-08-03)
7
+
8
+ ### Code Refactoring
9
+
10
+ * **http-client-base:** remove merge & retrieveBigNumbersAsString method ([2b1df56](https://github.com/odata2ts/http-client/commit/2b1df5677c42457430a968b3e61132818a83dc57))
11
+
12
+ ### Features
13
+
14
+ * allow for additional headers for all operations ([#10](https://github.com/odata2ts/http-client/issues/10)) ([75eedd3](https://github.com/odata2ts/http-client/commit/75eedd3ebb8534188a5a644aee9e69e17f1f0c80))
15
+
16
+ ### BREAKING CHANGES
17
+
18
+ * **http-client-base:** removed remove merge & retrieveBigNumbersAsString methods; use the additionalHeaders option on the appropriate operations
19
+
6
20
  # [0.2.0](https://github.com/odata2ts/http-client/compare/@odata2ts/http-client-base@0.1.0...@odata2ts/http-client-base@0.2.0) (2023-07-26)
7
21
 
8
22
  ### Features
@@ -14,15 +14,10 @@ export interface BaseHttpClientOptions {
14
14
  csrfTokenFetchUrl?: string;
15
15
  }
16
16
  export declare const DEFAULT_CSRF_TOKEN_KEY = "x-csrf-token";
17
- export declare const BIG_NUMBERS_CONFIG: {
18
- Accept: string;
19
- "Content-Type": string;
20
- };
21
17
  export declare abstract class BaseHttpClient<RequestConfigType> implements ODataHttpClient<RequestConfigType> {
22
18
  private baseOptions;
23
19
  private csrfToken;
24
20
  private csrfTokenKey;
25
- private bigNumbersAsString;
26
21
  protected retrieveErrorMessage: ErrorMessageRetriever;
27
22
  protected constructor(baseOptions?: BaseHttpClientOptions);
28
23
  /**
@@ -57,14 +52,13 @@ export declare abstract class BaseHttpClient<RequestConfigType> implements OData
57
52
  * @param url
58
53
  * @param data
59
54
  * @param requestConfig
55
+ * @param additionalHeaders
60
56
  * @private
61
57
  */
62
58
  private sendRequest;
63
- get<ResponseModel>(url: string, requestConfig?: RequestConfigType): Promise<HttpResponseModel<ResponseModel>>;
64
- post<ResponseModel>(url: string, data: any, requestConfig?: RequestConfigType): Promise<HttpResponseModel<ResponseModel>>;
65
- put<ResponseModel>(url: string, data: any, requestConfig?: RequestConfigType): Promise<HttpResponseModel<ResponseModel>>;
66
- patch<ResponseModel>(url: string, data: any, requestConfig?: RequestConfigType): Promise<HttpResponseModel<ResponseModel>>;
67
- merge<ResponseModel>(url: string, data: any, requestConfig?: RequestConfigType): Promise<HttpResponseModel<ResponseModel>>;
68
- delete(url: string, requestConfig?: RequestConfigType): Promise<HttpResponseModel<void>>;
69
- retrieveBigNumbersAsString(enabled: boolean): void;
59
+ get<ResponseModel>(url: string, requestConfig?: RequestConfigType, additionalHeaders?: Record<string, string>): Promise<HttpResponseModel<ResponseModel>>;
60
+ post<ResponseModel>(url: string, data: any, requestConfig?: RequestConfigType, additionalHeaders?: Record<string, string>): Promise<HttpResponseModel<ResponseModel>>;
61
+ put<ResponseModel>(url: string, data: any, requestConfig?: RequestConfigType, additionalHeaders?: Record<string, string>): Promise<HttpResponseModel<ResponseModel>>;
62
+ patch<ResponseModel>(url: string, data: any, requestConfig?: RequestConfigType, additionalHeaders?: Record<string, string>): Promise<HttpResponseModel<ResponseModel>>;
63
+ delete(url: string, requestConfig?: RequestConfigType, additionalHeaders?: Record<string, string>): Promise<HttpResponseModel<void>>;
70
64
  }
@@ -1,12 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.BaseHttpClient = exports.BIG_NUMBERS_CONFIG = exports.DEFAULT_CSRF_TOKEN_KEY = void 0;
3
+ exports.BaseHttpClient = exports.DEFAULT_CSRF_TOKEN_KEY = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const ErrorMessageRetriever_1 = require("./ErrorMessageRetriever");
6
6
  const HttpMethods_1 = require("./HttpMethods");
7
7
  exports.DEFAULT_CSRF_TOKEN_KEY = "x-csrf-token";
8
- const BIG_NUMBER_FORMAT = "application/json;IEEE754Compatible=true";
9
- exports.BIG_NUMBERS_CONFIG = { Accept: BIG_NUMBER_FORMAT, "Content-Type": BIG_NUMBER_FORMAT };
10
8
  const EDIT_METHODS = ["POST", "PUT", "PATCH", "DELETE"];
11
9
  const FAILURE_MISSING_CSRF_URL = "When automatic CSRF token handling is activated, the URL must be supplied via attribute [csrfTokenFetchUrl]!";
12
10
  const FAILURE_MISSING_URL = "Value for URL must be provided!";
@@ -15,7 +13,6 @@ class BaseHttpClient {
15
13
  var _a;
16
14
  this.baseOptions = baseOptions;
17
15
  this.csrfTokenKey = exports.DEFAULT_CSRF_TOKEN_KEY;
18
- this.bigNumbersAsString = false;
19
16
  this.retrieveErrorMessage = ErrorMessageRetriever_1.retrieveErrorMessage;
20
17
  if (baseOptions.useCsrfProtection && !((_a = baseOptions.csrfTokenFetchUrl) === null || _a === void 0 ? void 0 : _a.trim())) {
21
18
  throw new Error(FAILURE_MISSING_CSRF_URL);
@@ -52,20 +49,26 @@ class BaseHttpClient {
52
49
  * @param url
53
50
  * @param data
54
51
  * @param requestConfig
52
+ * @param additionalHeaders
55
53
  * @private
56
54
  */
57
- sendRequest(method, url, data, requestConfig) {
55
+ sendRequest(method, url, data, requestConfig, additionalHeaders) {
58
56
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
59
57
  // noinspection SuspiciousTypeOfGuard
60
58
  if (typeof url !== "string") {
61
59
  throw new Error(FAILURE_MISSING_URL);
62
60
  }
63
- let config = this.bigNumbersAsString ? this.addHeaderToRequestConfig(exports.BIG_NUMBERS_CONFIG) : requestConfig;
61
+ // use big numbers
62
+ let config = requestConfig;
63
+ // use additional headers
64
+ if (additionalHeaders) {
65
+ config = this.addHeaderToRequestConfig(additionalHeaders, config);
66
+ }
64
67
  // setup automatic CSRF token handling
65
68
  if (this.baseOptions.useCsrfProtection && EDIT_METHODS.includes(method)) {
66
69
  const [tokenKey, tokenValue] = yield this.setupSecurityToken();
67
70
  if (tokenValue) {
68
- config = this.addHeaderToRequestConfig({ [tokenKey]: tokenValue }, requestConfig);
71
+ config = this.addHeaderToRequestConfig({ [tokenKey]: tokenValue });
69
72
  }
70
73
  }
71
74
  try {
@@ -86,26 +89,20 @@ class BaseHttpClient {
86
89
  }
87
90
  });
88
91
  }
89
- get(url, requestConfig) {
90
- return this.sendRequest(HttpMethods_1.HttpMethods.Get, url, undefined, requestConfig);
91
- }
92
- post(url, data, requestConfig) {
93
- return this.sendRequest(HttpMethods_1.HttpMethods.Post, url, data, requestConfig);
94
- }
95
- put(url, data, requestConfig) {
96
- return this.sendRequest(HttpMethods_1.HttpMethods.Put, url, data, requestConfig);
92
+ get(url, requestConfig, additionalHeaders) {
93
+ return this.sendRequest(HttpMethods_1.HttpMethods.Get, url, undefined, requestConfig, additionalHeaders);
97
94
  }
98
- patch(url, data, requestConfig) {
99
- return this.sendRequest(HttpMethods_1.HttpMethods.Patch, url, data, requestConfig);
95
+ post(url, data, requestConfig, additionalHeaders) {
96
+ return this.sendRequest(HttpMethods_1.HttpMethods.Post, url, data, requestConfig, additionalHeaders);
100
97
  }
101
- merge(url, data, requestConfig) {
102
- return this.sendRequest(HttpMethods_1.HttpMethods.Post, url, data, this.addHeaderToRequestConfig({ "X-Http-Method": "MERGE" }, requestConfig));
98
+ put(url, data, requestConfig, additionalHeaders) {
99
+ return this.sendRequest(HttpMethods_1.HttpMethods.Put, url, data, requestConfig, additionalHeaders);
103
100
  }
104
- delete(url, requestConfig) {
105
- return this.sendRequest(HttpMethods_1.HttpMethods.Delete, url, undefined, requestConfig);
101
+ patch(url, data, requestConfig, additionalHeaders) {
102
+ return this.sendRequest(HttpMethods_1.HttpMethods.Patch, url, data, requestConfig, additionalHeaders);
106
103
  }
107
- retrieveBigNumbersAsString(enabled) {
108
- this.bigNumbersAsString = enabled;
104
+ delete(url, requestConfig, additionalHeaders) {
105
+ return this.sendRequest(HttpMethods_1.HttpMethods.Delete, url, undefined, requestConfig, additionalHeaders);
109
106
  }
110
107
  }
111
108
  exports.BaseHttpClient = BaseHttpClient;
@@ -1 +1 @@
1
- {"version":3,"file":"BaseHttpClient.js","sourceRoot":"","sources":["../src/BaseHttpClient.ts"],"names":[],"mappings":"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","sourcesContent":["import { HttpResponseModel, ODataClientError, ODataHttpClient } from \"@odata2ts/http-client-api\";\r\n\r\nimport { ErrorMessageRetriever, retrieveErrorMessage } from \"./ErrorMessageRetriever\";\r\nimport { HttpMethods } from \"./HttpMethods\";\r\n\r\nexport interface BaseHttpClientOptions {\r\n /**\r\n * Enable automatic CSRF token handling.\r\n */\r\n useCsrfProtection?: boolean;\r\n /**\r\n * Specify the URL from which the token is fetched.\r\n * This could be any path to your OData service, since the token is exchanged via HTTP request headers.\r\n * However, it should be a fast response and usually the root URL to the OData service is a good choice.\r\n */\r\n csrfTokenFetchUrl?: string;\r\n}\r\n\r\nexport const DEFAULT_CSRF_TOKEN_KEY = \"x-csrf-token\";\r\nconst BIG_NUMBER_FORMAT = \"application/json;IEEE754Compatible=true\";\r\nexport const BIG_NUMBERS_CONFIG = { Accept: BIG_NUMBER_FORMAT, \"Content-Type\": BIG_NUMBER_FORMAT };\r\n\r\nconst EDIT_METHODS = [\"POST\", \"PUT\", \"PATCH\", \"DELETE\"];\r\nconst FAILURE_MISSING_CSRF_URL =\r\n \"When automatic CSRF token handling is activated, the URL must be supplied via attribute [csrfTokenFetchUrl]!\";\r\nconst FAILURE_MISSING_URL = \"Value for URL must be provided!\";\r\n\r\nexport abstract class BaseHttpClient<RequestConfigType> implements ODataHttpClient<RequestConfigType> {\r\n private csrfToken: string | undefined;\r\n private csrfTokenKey = DEFAULT_CSRF_TOKEN_KEY;\r\n private bigNumbersAsString: boolean = false;\r\n\r\n protected retrieveErrorMessage: ErrorMessageRetriever = retrieveErrorMessage;\r\n\r\n protected constructor(private baseOptions: BaseHttpClientOptions = { useCsrfProtection: false }) {\r\n if (baseOptions.useCsrfProtection && !baseOptions.csrfTokenFetchUrl?.trim()) {\r\n throw new Error(FAILURE_MISSING_CSRF_URL);\r\n }\r\n }\r\n\r\n /**\r\n * Use the given headers to either create an entire new request config or merge them into the given\r\n * request config.\r\n *\r\n * @param headers\r\n * @param config\r\n * @returns request configuration\r\n */\r\n protected abstract addHeaderToRequestConfig(\r\n headers: Record<string, string>,\r\n config?: RequestConfigType\r\n ): RequestConfigType;\r\n\r\n /**\r\n * Main function to implement by any extending http client.\r\n * As it name suggests, the request gets executed in this method.\r\n * Additionally, failures should be handled and errors of type <code>HttpClientError</code> should be thrown.\r\n *\r\n * @param method\r\n * @param url\r\n * @param data\r\n * @param config\r\n */\r\n protected abstract executeRequest<ResponseModel>(\r\n method: HttpMethods,\r\n url: string,\r\n data: any,\r\n config?: RequestConfigType\r\n ): Promise<HttpResponseModel<ResponseModel>>;\r\n\r\n public getCsrfTokenKey() {\r\n return this.csrfTokenKey;\r\n }\r\n\r\n public setCsrfTokenKey(newKey: string) {\r\n this.csrfTokenKey = newKey || DEFAULT_CSRF_TOKEN_KEY;\r\n }\r\n\r\n public setErrorMessageRetriever(getErrorMsg: ErrorMessageRetriever) {\r\n this.retrieveErrorMessage = getErrorMsg;\r\n }\r\n\r\n protected async setupSecurityToken(): Promise<[string, string | undefined]> {\r\n if (!this.csrfToken) {\r\n this.csrfToken = await this.fetchSecurityToken();\r\n }\r\n return [this.csrfTokenKey, this.csrfToken];\r\n }\r\n\r\n protected async fetchSecurityToken(): Promise<string | undefined> {\r\n const fetchUrl = this.baseOptions!.csrfTokenFetchUrl!;\r\n const response = await this.get(fetchUrl, this.addHeaderToRequestConfig({ [this.csrfTokenKey]: \"Fetch\" }));\r\n\r\n return response.headers[this.csrfTokenKey];\r\n }\r\n\r\n /**\r\n * Follows the template pattern.\r\n *\r\n * @param method\r\n * @param url\r\n * @param data\r\n * @param requestConfig\r\n * @private\r\n */\r\n private async sendRequest<ResponseModel>(\r\n method: HttpMethods,\r\n url: string,\r\n data: any,\r\n requestConfig?: RequestConfigType\r\n ): Promise<HttpResponseModel<ResponseModel>> {\r\n // noinspection SuspiciousTypeOfGuard\r\n if (typeof url !== \"string\") {\r\n throw new Error(FAILURE_MISSING_URL);\r\n }\r\n\r\n let config = this.bigNumbersAsString ? this.addHeaderToRequestConfig(BIG_NUMBERS_CONFIG) : requestConfig;\r\n\r\n // setup automatic CSRF token handling\r\n if (this.baseOptions.useCsrfProtection && EDIT_METHODS.includes(method)) {\r\n const [tokenKey, tokenValue] = await this.setupSecurityToken();\r\n if (tokenValue) {\r\n config = this.addHeaderToRequestConfig({ [tokenKey]: tokenValue }, requestConfig);\r\n }\r\n }\r\n\r\n try {\r\n return await this.executeRequest<ResponseModel>(method, url, data, config);\r\n } catch (e) {\r\n const clientError = e as ODataClientError;\r\n\r\n // automatic CSRF token handling\r\n if (\r\n !!this.baseOptions.useCsrfProtection &&\r\n clientError.status === 403 &&\r\n !!clientError.headers &&\r\n clientError.headers[\"x-csrf-token\"] === \"Required\"\r\n ) {\r\n // token has expired: reset csrf token & perform the original request again\r\n this.csrfToken = undefined;\r\n return this.sendRequest<ResponseModel>(method, url, data, requestConfig);\r\n }\r\n\r\n throw e;\r\n }\r\n }\r\n\r\n public get<ResponseModel>(url: string, requestConfig?: RequestConfigType): Promise<HttpResponseModel<ResponseModel>> {\r\n return this.sendRequest<ResponseModel>(HttpMethods.Get, url, undefined, requestConfig);\r\n }\r\n public post<ResponseModel>(\r\n url: string,\r\n data: any,\r\n requestConfig?: RequestConfigType\r\n ): Promise<HttpResponseModel<ResponseModel>> {\r\n return this.sendRequest<ResponseModel>(HttpMethods.Post, url, data, requestConfig);\r\n }\r\n public put<ResponseModel>(\r\n url: string,\r\n data: any,\r\n requestConfig?: RequestConfigType\r\n ): Promise<HttpResponseModel<ResponseModel>> {\r\n return this.sendRequest<ResponseModel>(HttpMethods.Put, url, data, requestConfig);\r\n }\r\n public patch<ResponseModel>(\r\n url: string,\r\n data: any,\r\n requestConfig?: RequestConfigType\r\n ): Promise<HttpResponseModel<ResponseModel>> {\r\n return this.sendRequest<ResponseModel>(HttpMethods.Patch, url, data, requestConfig);\r\n }\r\n public merge<ResponseModel>(\r\n url: string,\r\n data: any,\r\n requestConfig?: RequestConfigType\r\n ): Promise<HttpResponseModel<ResponseModel>> {\r\n return this.sendRequest<ResponseModel>(\r\n HttpMethods.Post,\r\n url,\r\n data,\r\n this.addHeaderToRequestConfig({ \"X-Http-Method\": \"MERGE\" }, requestConfig)\r\n );\r\n }\r\n public delete(url: string, requestConfig?: RequestConfigType): Promise<HttpResponseModel<void>> {\r\n return this.sendRequest<void>(HttpMethods.Delete, url, undefined, requestConfig);\r\n }\r\n\r\n public retrieveBigNumbersAsString(enabled: boolean) {\r\n this.bigNumbersAsString = enabled;\r\n }\r\n}\r\n"]}
1
+ {"version":3,"file":"BaseHttpClient.js","sourceRoot":"","sources":["../src/BaseHttpClient.ts"],"names":[],"mappings":"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","sourcesContent":["import { HttpResponseModel, ODataClientError, ODataHttpClient } from \"@odata2ts/http-client-api\";\n\nimport { ErrorMessageRetriever, retrieveErrorMessage } from \"./ErrorMessageRetriever\";\nimport { HttpMethods } from \"./HttpMethods\";\n\nexport interface BaseHttpClientOptions {\n /**\n * Enable automatic CSRF token handling.\n */\n useCsrfProtection?: boolean;\n /**\n * Specify the URL from which the token is fetched.\n * This could be any path to your OData service, since the token is exchanged via HTTP request headers.\n * However, it should be a fast response and usually the root URL to the OData service is a good choice.\n */\n csrfTokenFetchUrl?: string;\n}\n\nexport const DEFAULT_CSRF_TOKEN_KEY = \"x-csrf-token\";\n\nconst EDIT_METHODS = [\"POST\", \"PUT\", \"PATCH\", \"DELETE\"];\nconst FAILURE_MISSING_CSRF_URL =\n \"When automatic CSRF token handling is activated, the URL must be supplied via attribute [csrfTokenFetchUrl]!\";\nconst FAILURE_MISSING_URL = \"Value for URL must be provided!\";\n\nexport abstract class BaseHttpClient<RequestConfigType> implements ODataHttpClient<RequestConfigType> {\n private csrfToken: string | undefined;\n private csrfTokenKey = DEFAULT_CSRF_TOKEN_KEY;\n\n protected retrieveErrorMessage: ErrorMessageRetriever = retrieveErrorMessage;\n\n protected constructor(private baseOptions: BaseHttpClientOptions = { useCsrfProtection: false }) {\n if (baseOptions.useCsrfProtection && !baseOptions.csrfTokenFetchUrl?.trim()) {\n throw new Error(FAILURE_MISSING_CSRF_URL);\n }\n }\n\n /**\n * Use the given headers to either create an entire new request config or merge them into the given\n * request config.\n *\n * @param headers\n * @param config\n * @returns request configuration\n */\n protected abstract addHeaderToRequestConfig(\n headers: Record<string, string>,\n config?: RequestConfigType\n ): RequestConfigType;\n\n /**\n * Main function to implement by any extending http client.\n * As it name suggests, the request gets executed in this method.\n * Additionally, failures should be handled and errors of type <code>HttpClientError</code> should be thrown.\n *\n * @param method\n * @param url\n * @param data\n * @param config\n */\n protected abstract executeRequest<ResponseModel>(\n method: HttpMethods,\n url: string,\n data: any,\n config?: RequestConfigType\n ): Promise<HttpResponseModel<ResponseModel>>;\n\n public getCsrfTokenKey() {\n return this.csrfTokenKey;\n }\n\n public setCsrfTokenKey(newKey: string) {\n this.csrfTokenKey = newKey || DEFAULT_CSRF_TOKEN_KEY;\n }\n\n public setErrorMessageRetriever(getErrorMsg: ErrorMessageRetriever) {\n this.retrieveErrorMessage = getErrorMsg;\n }\n\n protected async setupSecurityToken(): Promise<[string, string | undefined]> {\n if (!this.csrfToken) {\n this.csrfToken = await this.fetchSecurityToken();\n }\n return [this.csrfTokenKey, this.csrfToken];\n }\n\n protected async fetchSecurityToken(): Promise<string | undefined> {\n const fetchUrl = this.baseOptions!.csrfTokenFetchUrl!;\n const response = await this.get(fetchUrl, this.addHeaderToRequestConfig({ [this.csrfTokenKey]: \"Fetch\" }));\n\n return response.headers[this.csrfTokenKey];\n }\n\n /**\n * Follows the template pattern.\n *\n * @param method\n * @param url\n * @param data\n * @param requestConfig\n * @param additionalHeaders\n * @private\n */\n private async sendRequest<ResponseModel>(\n method: HttpMethods,\n url: string,\n data: any,\n requestConfig?: RequestConfigType,\n additionalHeaders?: Record<string, string>\n ): Promise<HttpResponseModel<ResponseModel>> {\n // noinspection SuspiciousTypeOfGuard\n if (typeof url !== \"string\") {\n throw new Error(FAILURE_MISSING_URL);\n }\n\n // use big numbers\n let config = requestConfig;\n\n // use additional headers\n if (additionalHeaders) {\n config = this.addHeaderToRequestConfig(additionalHeaders, config);\n }\n\n // setup automatic CSRF token handling\n if (this.baseOptions.useCsrfProtection && EDIT_METHODS.includes(method)) {\n const [tokenKey, tokenValue] = await this.setupSecurityToken();\n if (tokenValue) {\n config = this.addHeaderToRequestConfig({ [tokenKey]: tokenValue });\n }\n }\n\n try {\n return await this.executeRequest<ResponseModel>(method, url, data, config);\n } catch (e) {\n const clientError = e as ODataClientError;\n\n // automatic CSRF token handling\n if (\n !!this.baseOptions.useCsrfProtection &&\n clientError.status === 403 &&\n !!clientError.headers &&\n clientError.headers[\"x-csrf-token\"] === \"Required\"\n ) {\n // token has expired: reset csrf token & perform the original request again\n this.csrfToken = undefined;\n return this.sendRequest<ResponseModel>(method, url, data, requestConfig);\n }\n\n throw e;\n }\n }\n\n public get<ResponseModel>(\n url: string,\n requestConfig?: RequestConfigType,\n additionalHeaders?: Record<string, string>\n ): Promise<HttpResponseModel<ResponseModel>> {\n return this.sendRequest<ResponseModel>(HttpMethods.Get, url, undefined, requestConfig, additionalHeaders);\n }\n public post<ResponseModel>(\n url: string,\n data: any,\n requestConfig?: RequestConfigType,\n additionalHeaders?: Record<string, string>\n ): Promise<HttpResponseModel<ResponseModel>> {\n return this.sendRequest<ResponseModel>(HttpMethods.Post, url, data, requestConfig, additionalHeaders);\n }\n public put<ResponseModel>(\n url: string,\n data: any,\n requestConfig?: RequestConfigType,\n additionalHeaders?: Record<string, string>\n ): Promise<HttpResponseModel<ResponseModel>> {\n return this.sendRequest<ResponseModel>(HttpMethods.Put, url, data, requestConfig, additionalHeaders);\n }\n public patch<ResponseModel>(\n url: string,\n data: any,\n requestConfig?: RequestConfigType,\n additionalHeaders?: Record<string, string>\n ): Promise<HttpResponseModel<ResponseModel>> {\n return this.sendRequest<ResponseModel>(HttpMethods.Patch, url, data, requestConfig, additionalHeaders);\n }\n\n public delete(\n url: string,\n requestConfig?: RequestConfigType,\n additionalHeaders?: Record<string, string>\n ): Promise<HttpResponseModel<void>> {\n return this.sendRequest<void>(HttpMethods.Delete, url, undefined, requestConfig, additionalHeaders);\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@odata2ts/http-client-base",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -29,7 +29,7 @@
29
29
  "odata2ts"
30
30
  ],
31
31
  "dependencies": {
32
- "@odata2ts/http-client-api": "^0.3.0"
32
+ "@odata2ts/http-client-api": "^0.4.0"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@odata2ts/odata-core": "^0.3.7",
@@ -42,5 +42,5 @@
42
42
  "typescript": "5.0.4"
43
43
  },
44
44
  "types": "./lib/index.d.ts",
45
- "gitHead": "9babd2df3010673249e7e3fa26705a8ba84f2cef"
45
+ "gitHead": "dc6e29cef27b2f5fca6e838e4a22766b90249e8e"
46
46
  }