api-def 0.12.1 → 0.14.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/README.md +3 -0
  2. package/bin/index.js +312 -313
  3. package/cjs/Api.d.ts +1 -1
  4. package/cjs/Api.js +99 -145
  5. package/cjs/ApiTypes.d.ts +3 -2
  6. package/cjs/ApiUtils.js +30 -32
  7. package/cjs/Endpoint.d.ts +1 -1
  8. package/cjs/Endpoint.js +112 -175
  9. package/cjs/EndpointBuilder.d.ts +17 -0
  10. package/cjs/EndpointBuilder.js +55 -36
  11. package/cjs/QueryHandling.js +12 -13
  12. package/cjs/RequestConfig.js +54 -36
  13. package/cjs/RequestContext.d.ts +2 -1
  14. package/cjs/RequestContext.js +143 -180
  15. package/cjs/RequestError.js +16 -19
  16. package/cjs/Requester.js +231 -312
  17. package/cjs/TextDecoding.js +31 -31
  18. package/cjs/Utils.d.ts +1 -0
  19. package/cjs/Utils.js +74 -25
  20. package/cjs/Validation.d.ts +8 -1
  21. package/cjs/backend/AxiosRequestBackend.d.ts +1 -1
  22. package/cjs/backend/AxiosRequestBackend.js +65 -172
  23. package/cjs/backend/FetchRequestBackend.d.ts +1 -1
  24. package/cjs/backend/FetchRequestBackend.js +108 -154
  25. package/cjs/backend/MockRequestBackend.d.ts +1 -1
  26. package/cjs/backend/MockRequestBackend.js +146 -208
  27. package/cjs/cache/ClientCaching.js +26 -74
  28. package/cjs/cache/LocalForageClientCacheBackend.js +15 -83
  29. package/cjs/cache/LocalStorageClientCacheBackend.js +14 -73
  30. package/cjs/index.d.ts +11 -11
  31. package/cjs/index.js +24 -21
  32. package/cjs/middleware/ClientCacheMiddleware.js +80 -103
  33. package/cjs/middleware/LoggingMiddleware.js +71 -42
  34. package/cjs/util/retry/index.js +42 -9
  35. package/cjs/util/retry/lib/retry.js +25 -27
  36. package/cjs/util/retry/lib/retryOperation.d.ts +1 -26
  37. package/cjs/util/retry/lib/retryOperation.js +21 -23
  38. package/esm/Api.d.ts +6 -6
  39. package/esm/Api.js +12 -25
  40. package/esm/ApiConstants.d.ts +1 -1
  41. package/esm/ApiTypes.d.ts +7 -6
  42. package/esm/ApiUtils.d.ts +2 -2
  43. package/esm/ApiUtils.js +4 -5
  44. package/esm/Endpoint.d.ts +6 -6
  45. package/esm/Endpoint.js +22 -28
  46. package/esm/EndpointBuilder.d.ts +21 -4
  47. package/esm/EndpointBuilder.js +38 -10
  48. package/esm/MockingTypes.d.ts +1 -1
  49. package/esm/QueryHandling.d.ts +1 -1
  50. package/esm/QueryHandling.js +2 -3
  51. package/esm/RequestConfig.d.ts +1 -1
  52. package/esm/RequestConfig.js +6 -7
  53. package/esm/RequestContext.d.ts +8 -7
  54. package/esm/RequestContext.js +33 -27
  55. package/esm/RequestError.d.ts +3 -3
  56. package/esm/RequestError.js +2 -3
  57. package/esm/Requester.d.ts +2 -2
  58. package/esm/Requester.js +45 -50
  59. package/esm/UtilTypes.d.ts +1 -1
  60. package/esm/Utils.d.ts +1 -0
  61. package/esm/Utils.js +54 -2
  62. package/esm/Validation.d.ts +8 -1
  63. package/esm/backend/AxiosRequestBackend.d.ts +4 -4
  64. package/esm/backend/AxiosRequestBackend.js +47 -84
  65. package/esm/backend/FetchRequestBackend.d.ts +5 -5
  66. package/esm/backend/FetchRequestBackend.js +50 -64
  67. package/esm/backend/MockRequestBackend.d.ts +4 -4
  68. package/esm/backend/MockRequestBackend.js +105 -136
  69. package/esm/backend/RequestBackend.d.ts +2 -2
  70. package/esm/cache/ClientCaching.d.ts +1 -1
  71. package/esm/cache/ClientCaching.js +8 -17
  72. package/esm/cache/LocalForageClientCacheBackend.d.ts +1 -1
  73. package/esm/cache/LocalForageClientCacheBackend.js +8 -25
  74. package/esm/cache/LocalStorageClientCacheBackend.d.ts +1 -1
  75. package/esm/cache/LocalStorageClientCacheBackend.js +9 -26
  76. package/esm/index.d.ts +16 -16
  77. package/esm/index.js +15 -15
  78. package/esm/middleware/ClientCacheMiddleware.d.ts +1 -1
  79. package/esm/middleware/ClientCacheMiddleware.js +8 -17
  80. package/esm/middleware/LoggingMiddleware.d.ts +1 -1
  81. package/esm/middleware/LoggingMiddleware.js +5 -6
  82. package/esm/util/retry/index.js +1 -1
  83. package/esm/util/retry/lib/retry.d.ts +1 -1
  84. package/esm/util/retry/lib/retry.js +13 -7
  85. package/esm/util/retry/lib/retryOperation.d.ts +1 -26
  86. package/esm/util/retry/lib/retryOperation.js +1 -1
  87. package/package.json +67 -28
@@ -1,24 +1,23 @@
1
- import { COMPUTED_CONFIG_SYMBOL, } from "./ApiTypes";
2
- import { DEFAULT_QUERY_PARSE, DEFAULT_QUERY_STRINGIFY } from "./QueryHandling";
3
- import * as Utils from "./Utils";
1
+ import { COMPUTED_CONFIG_SYMBOL, } from "./ApiTypes.js";
2
+ import { DEFAULT_QUERY_PARSE, DEFAULT_QUERY_STRINGIFY } from "./QueryHandling.js";
3
+ import * as Utils from "./Utils.js";
4
4
  const MERGED_CONFIG_KEYS = ["headers"];
5
5
  export const processRequestConfigs = (configs) => {
6
- var _a, _b;
7
6
  const computedConfig = Utils.assign({
8
7
  [COMPUTED_CONFIG_SYMBOL]: true,
9
8
  }, ...configs);
10
9
  // merge other values
11
10
  for (const key of MERGED_CONFIG_KEYS) {
12
11
  computedConfig[key] = Utils.assign({}, ...configs.reduce((acc, config) => {
13
- if (config === null || config === void 0 ? void 0 : config[key]) {
12
+ if (config?.[key]) {
14
13
  acc.push(config[key]);
15
14
  }
16
15
  return acc;
17
16
  }, []));
18
17
  }
19
18
  computedConfig.queryHandling = {
20
- parse: ((_a = computedConfig.queryHandling) === null || _a === void 0 ? void 0 : _a.parse) || DEFAULT_QUERY_PARSE,
21
- stringify: ((_b = computedConfig.queryHandling) === null || _b === void 0 ? void 0 : _b.stringify) || computedConfig.queryParser || DEFAULT_QUERY_STRINGIFY,
19
+ parse: computedConfig.queryHandling?.parse || DEFAULT_QUERY_PARSE,
20
+ stringify: computedConfig.queryHandling?.stringify || computedConfig.queryParser || DEFAULT_QUERY_STRINGIFY,
22
21
  };
23
22
  computedConfig.queryParser = undefined;
24
23
  const query = computedConfig.query;
@@ -1,10 +1,10 @@
1
- import type { Api } from "./Api";
2
- import type { RequestEvent, RequestMethod, ResponseType } from "./ApiConstants";
3
- import type { ApiResponse, Body, ComputedRequestConfig, EventResult, Params, Query, RawHeaders, RequestCacheInfo, RequestEventHandlers, RequestHost, RequestStats, State } from "./ApiTypes";
4
- import type { EndpointMockingConfig } from "./MockingTypes";
5
- import type { RequestError } from "./RequestError";
6
- import type { Validation } from "./Validation";
7
- import type RequestBackend from "./backend/RequestBackend";
1
+ import type { Api } from "./Api.js";
2
+ import type { RequestEvent, RequestMethod, ResponseType } from "./ApiConstants.js";
3
+ import type { ApiResponse, Body, ComputedRequestConfig, EventResult, Params, Query, RawHeaders, RequestCacheInfo, RequestEventHandlers, RequestHost, RequestStats, State } from "./ApiTypes.js";
4
+ import type RequestBackend from "./backend/RequestBackend.js";
5
+ import type { EndpointMockingConfig } from "./MockingTypes.js";
6
+ import type { RequestError } from "./RequestError.js";
7
+ import type { Validation } from "./Validation.js";
8
8
  export default class RequestContext<TResponse = any, TParams extends Params | undefined = Params | undefined, TQuery extends Query | undefined = Query | undefined, TBody extends Body | undefined = Body | undefined, TState extends State = State> {
9
9
  readonly id: number;
10
10
  readonly key: string;
@@ -42,6 +42,7 @@ export default class RequestContext<TResponse = any, TParams extends Params | un
42
42
  updateParams(params: Partial<Record<string, string>>): this;
43
43
  private parseRequestBody;
44
44
  getParsedBody(): any;
45
+ parseBody(): void;
45
46
  updateQuery(newQuery: Partial<TQuery>): this;
46
47
  triggerEvent(eventType: RequestEvent): Promise<EventResult<TResponse> | undefined>;
47
48
  addCanceller(canceler: () => void): void;
@@ -1,14 +1,5 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import { resolvePathParams, resolveUrl } from "./ApiUtils";
11
- import * as Utils from "./Utils";
1
+ import { resolvePathParams, resolveUrl } from "./ApiUtils.js";
2
+ import * as Utils from "./Utils.js";
12
3
  let contextIdCounter = 0;
13
4
  export default class RequestContext {
14
5
  constructor(backend, host, config, rawPath, mocking) {
@@ -100,18 +91,32 @@ export default class RequestContext {
100
91
  return this;
101
92
  }
102
93
  parseRequestBody() {
103
- var _a;
104
94
  if (this.requestConfig.body && this.requestConfig.headers) {
105
95
  const contentTypeKey = Object.keys(this.requestConfig.headers).find((key) => key.toLowerCase() === "content-type");
106
- const contentType = contentTypeKey && ((_a = this.requestConfig.headers[contentTypeKey]) === null || _a === void 0 ? void 0 : _a.toString().split(";")[0].trim());
96
+ const contentType = contentTypeKey && this.requestConfig.headers[contentTypeKey]?.toString().split(";")[0].trim();
97
+ const bodyEncoding = this.validation.bodyEncoding ?? "application/json";
98
+ if (!contentTypeKey && bodyEncoding === "application/x-www-form-urlencoded") {
99
+ this.requestConfig.headers["Content-Type"] = "application/x-www-form-urlencoded";
100
+ }
107
101
  if (contentType === "application/x-www-form-urlencoded") {
108
102
  const searchParams = new URLSearchParams();
109
103
  for (const key of Object.keys(this.requestConfig.body)) {
110
104
  const value = this.requestConfig.body[key];
111
- searchParams.append(key, value === null || value === void 0 ? void 0 : value.toString());
105
+ searchParams.append(key, value?.toString());
112
106
  }
113
107
  this.parsedBody = searchParams;
114
108
  }
109
+ else if (bodyEncoding === "application/x-www-form-urlencoded") {
110
+ const searchParams = new URLSearchParams();
111
+ for (const key of Object.keys(this.requestConfig.body)) {
112
+ const value = this.requestConfig.body[key];
113
+ searchParams.append(key, value?.toString());
114
+ }
115
+ this.parsedBody = searchParams;
116
+ }
117
+ else if (bodyEncoding === "multipart/form-data") {
118
+ this.parsedBody = Utils.toFormData(this.requestConfig.body);
119
+ }
115
120
  else {
116
121
  this.parsedBody = this.requestConfig.body;
117
122
  }
@@ -123,25 +128,26 @@ export default class RequestContext {
123
128
  getParsedBody() {
124
129
  return this.parsedBody;
125
130
  }
131
+ parseBody() {
132
+ this.parseRequestBody();
133
+ }
126
134
  updateQuery(newQuery) {
127
135
  this.requestConfig.queryObject = Utils.assign({}, this.requestConfig.queryObject, newQuery);
128
136
  this.computedRequestUrl = this.resolveRequestUrl();
129
137
  return this;
130
138
  }
131
- triggerEvent(eventType) {
132
- return __awaiter(this, void 0, void 0, function* () {
133
- const eventHandlers = this.eventHandlers[eventType];
134
- if (eventHandlers) {
135
- for (let i = 0; i < eventHandlers.length; i++) {
136
- const eventHandler = eventHandlers[i];
137
- const eventResult = yield eventHandler(this);
138
- if (eventResult) {
139
- return eventResult;
140
- }
139
+ async triggerEvent(eventType) {
140
+ const eventHandlers = this.eventHandlers[eventType];
141
+ if (eventHandlers) {
142
+ for (let i = 0; i < eventHandlers.length; i++) {
143
+ const eventHandler = eventHandlers[i];
144
+ const eventResult = await eventHandler(this);
145
+ if (eventResult) {
146
+ return eventResult;
141
147
  }
142
148
  }
143
- return undefined;
144
- });
149
+ }
150
+ return undefined;
145
151
  }
146
152
  addCanceller(canceler) {
147
153
  this.canceler = canceler;
@@ -170,7 +176,7 @@ export default class RequestContext {
170
176
  this.computedMethod = method;
171
177
  }
172
178
  updateBody(body) {
173
- // @ts-ignore
179
+ // @ts-expect-error
174
180
  this.requestConfig.body = body;
175
181
  this.parseRequestBody();
176
182
  }
@@ -1,6 +1,6 @@
1
- import type { ApiResponse } from "./ApiTypes";
2
- import type RequestContext from "./RequestContext";
3
- import type { EnumOf } from "./Utils";
1
+ import type { ApiResponse } from "./ApiTypes.js";
2
+ import type RequestContext from "./RequestContext.js";
3
+ import type { EnumOf } from "./Utils.js";
4
4
  export declare const RequestErrorCode: {
5
5
  readonly MISC_UNKNOWN_ERROR: "misc/unknown-error";
6
6
  readonly REQUEST_NETWORK_ERROR: "request/network-error";
@@ -46,7 +46,7 @@ export const convertToRequestError = (config) => {
46
46
  });
47
47
  try {
48
48
  Object.defineProperty(resultError, "message", {
49
- value: `A ${context.method.toUpperCase()} request to '${context.requestUrl.href}' failed${(response === null || response === void 0 ? void 0 : response.status) ? ` with status code ${response.status}` : ""} [${code}]: ${resultError.message}`,
49
+ value: `A ${context.method.toUpperCase()} request to '${context.requestUrl.href}' failed${response?.status ? ` with status code ${response.status}` : ""} [${code}]: ${resultError.message}`,
50
50
  });
51
51
  }
52
52
  catch (e) {
@@ -57,9 +57,8 @@ export const convertToRequestError = (config) => {
57
57
  return resultError;
58
58
  };
59
59
  export const getErrorResponse = (error) => {
60
- var _a;
61
60
  if (isRequestError(error)) {
62
- return (_a = error.response) !== null && _a !== void 0 ? _a : undefined;
61
+ return error.response ?? undefined;
63
62
  }
64
63
  return undefined;
65
64
  };
@@ -1,3 +1,3 @@
1
- import type { ApiResponse, Body, Params, Query, RequestConfig, RequestHost, State } from "./ApiTypes";
2
- import type { EndpointMockingConfig } from "./MockingTypes";
1
+ import type { ApiResponse, Body, Params, Query, RequestConfig, RequestHost, State } from "./ApiTypes.js";
2
+ import type { EndpointMockingConfig } from "./MockingTypes.js";
3
3
  export declare const submit: <TResponse, TParams extends Params | undefined, TQuery extends Query | undefined, TBody extends Body | undefined, TState extends State>(host: RequestHost, config: RequestConfig<TParams, TQuery, TBody, TState>, mocking: EndpointMockingConfig<TResponse, TParams, TQuery, TBody, TState> | null | undefined) => Promise<ApiResponse<TResponse>>;
package/esm/Requester.js CHANGED
@@ -1,23 +1,14 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import { EventResultType, RequestEvent } from "./ApiConstants";
11
- import { inferResponseType, isAcceptableStatus, isNetworkError } from "./ApiUtils";
12
- import RequestContext from "./RequestContext";
13
- import { RequestErrorCode, convertToRequestError, isRequestError } from "./RequestError";
14
- import { textDecode } from "./TextDecoding";
15
- import MockRequestBackend from "./backend/MockRequestBackend";
16
- import retry from "./util/retry";
1
+ import { EventResultType, RequestEvent } from "./ApiConstants.js";
2
+ import { inferResponseType, isAcceptableStatus, isNetworkError } from "./ApiUtils.js";
3
+ import MockRequestBackend from "./backend/MockRequestBackend.js";
4
+ import RequestContext from "./RequestContext.js";
5
+ import { convertToRequestError, isRequestError, RequestErrorCode } from "./RequestError.js";
6
+ import { textDecode } from "./TextDecoding.js";
7
+ import retry from "./util/retry/index.js";
17
8
  const locks = {};
18
9
  const runningOperations = {};
19
10
  const MOCK_REQUEST_BACKEND = new MockRequestBackend();
20
- export const submit = (host, config, mocking) => __awaiter(void 0, void 0, void 0, function* () {
11
+ export const submit = async (host, config, mocking) => {
21
12
  const computedConfig = host.computeConfig(config);
22
13
  const backend = mocking ? MOCK_REQUEST_BACKEND : host.getRequestBackend();
23
14
  const context = new RequestContext(backend, host, computedConfig, host.path, mocking);
@@ -39,8 +30,8 @@ export const submit = (host, config, mocking) => __awaiter(void 0, void 0, void
39
30
  locks[lock] = context;
40
31
  }
41
32
  try {
42
- let response = yield (runningOperations[key] = makeRequest(context));
43
- const successEventResult = yield context.triggerEvent(RequestEvent.SUCCESS);
33
+ let response = await (runningOperations[key] = makeRequest(context));
34
+ const successEventResult = await context.triggerEvent(RequestEvent.SUCCESS);
44
35
  if (successEventResult && successEventResult.type === EventResultType.RESPOND) {
45
36
  context.response = response = successEventResult.response;
46
37
  }
@@ -56,7 +47,7 @@ export const submit = (host, config, mocking) => __awaiter(void 0, void 0, void
56
47
  delete locks[lock];
57
48
  }
58
49
  }
59
- });
50
+ };
60
51
  const parseRetryOptions = (retryConfig) => {
61
52
  if (retryConfig && typeof retryConfig === "object") {
62
53
  return retryConfig;
@@ -66,9 +57,8 @@ const parseRetryOptions = (retryConfig) => {
66
57
  }
67
58
  return { maxAttempts: 0 };
68
59
  };
69
- const makeRequest = (context) => __awaiter(void 0, void 0, void 0, function* () {
70
- var _a, _b, _c;
71
- const beforeSendEventResult = yield context.triggerEvent(RequestEvent.BEFORE_SEND);
60
+ const makeRequest = async (context) => {
61
+ const beforeSendEventResult = await context.triggerEvent(RequestEvent.BEFORE_SEND);
72
62
  if (beforeSendEventResult && beforeSendEventResult.type === EventResultType.RESPOND) {
73
63
  return (context.response = beforeSendEventResult.response);
74
64
  }
@@ -98,22 +88,23 @@ const makeRequest = (context) => __awaiter(void 0, void 0, void 0, function* ()
98
88
  });
99
89
  }
100
90
  }
101
- const retryOptions = parseRetryOptions((_a = context.requestConfig) === null || _a === void 0 ? void 0 : _a.retry);
91
+ context.parseBody();
92
+ const retryOptions = parseRetryOptions(context.requestConfig?.retry);
102
93
  const internalRetryOptions = {
103
94
  retries: retryOptions.maxAttempts,
104
95
  // assume most users won't want to tune the delay between retries
105
- minTimeout: (_b = retryOptions.minDelay) !== null && _b !== void 0 ? _b : 200,
106
- maxTimeout: (_c = retryOptions.maxDelay) !== null && _c !== void 0 ? _c : 1000,
96
+ minTimeout: retryOptions.minDelay ?? 200,
97
+ maxTimeout: retryOptions.maxDelay ?? 1000,
107
98
  randomize: true,
108
99
  };
109
100
  context.stats.attempt = 0;
110
- const performRequest = (fnBail, attemptCount) => __awaiter(void 0, void 0, void 0, function* () {
101
+ const performRequest = async (fnBail, attemptCount) => {
111
102
  context.stats.attempt++;
112
103
  try {
113
104
  const { promise, canceler } = context.backend.makeRequest(context);
114
105
  context.addCanceller(canceler);
115
- const response = yield promise;
116
- const parsedResponse = (yield parseResponse(context, response));
106
+ const response = await promise;
107
+ const parsedResponse = (await parseResponse(context, response));
117
108
  if (!isAcceptableStatus(parsedResponse.status, context.requestConfig.acceptableStatus)) {
118
109
  throw convertToRequestError({
119
110
  error: new Error(`[api-def] Invalid response status code '${parsedResponse.status}'`),
@@ -130,12 +121,12 @@ const makeRequest = (context) => __awaiter(void 0, void 0, void 0, function* ()
130
121
  if (context.cancelled) {
131
122
  rawError.isCancelledRequest = true;
132
123
  }
133
- const error = yield parseError(context, rawError);
124
+ const error = await parseError(context, rawError);
134
125
  context.error = error;
135
126
  context.response = error.response;
136
127
  context.stats.endTimestamp = Date.now();
137
- const errorEventResult = yield context.triggerEvent(RequestEvent.ERROR);
138
- if ((errorEventResult === null || errorEventResult === void 0 ? void 0 : errorEventResult.type) === EventResultType.RESPOND) {
128
+ const errorEventResult = await context.triggerEvent(RequestEvent.ERROR);
129
+ if (errorEventResult?.type === EventResultType.RESPOND) {
139
130
  return errorEventResult.response;
140
131
  }
141
132
  // allow retry logic to handle network errors
@@ -144,7 +135,7 @@ const makeRequest = (context) => __awaiter(void 0, void 0, void 0, function* ()
144
135
  // throw error;
145
136
  //}
146
137
  // if we have an event that tells us to retry, we must do it
147
- const forceRetry = (errorEventResult === null || errorEventResult === void 0 ? void 0 : errorEventResult.type) === EventResultType.RETRY;
138
+ const forceRetry = errorEventResult?.type === EventResultType.RETRY;
148
139
  if (forceRetry) {
149
140
  return performRequest(fnBail, attemptCount);
150
141
  }
@@ -153,7 +144,7 @@ const makeRequest = (context) => __awaiter(void 0, void 0, void 0, function* ()
153
144
  throw error;
154
145
  }
155
146
  // error is unrecoverable, bail
156
- const unrecoverableErrorEventResult = yield context.triggerEvent(RequestEvent.UNRECOVERABLE_ERROR);
147
+ const unrecoverableErrorEventResult = await context.triggerEvent(RequestEvent.UNRECOVERABLE_ERROR);
157
148
  if (unrecoverableErrorEventResult) {
158
149
  if (unrecoverableErrorEventResult.type === EventResultType.RESPOND) {
159
150
  return unrecoverableErrorEventResult.response;
@@ -161,8 +152,8 @@ const makeRequest = (context) => __awaiter(void 0, void 0, void 0, function* ()
161
152
  }
162
153
  fnBail(error);
163
154
  }
164
- });
165
- const response = yield retry(performRequest, internalRetryOptions);
155
+ };
156
+ const response = await retry(performRequest, internalRetryOptions);
166
157
  if (context.validation.response) {
167
158
  try {
168
159
  response.data = context.validation.response.parse(response.data);
@@ -176,11 +167,10 @@ const makeRequest = (context) => __awaiter(void 0, void 0, void 0, function* ()
176
167
  }
177
168
  }
178
169
  return response;
179
- });
180
- const parseResponse = (context, response, error) => __awaiter(void 0, void 0, void 0, function* () {
181
- var _a;
170
+ };
171
+ const parseResponse = async (context, response, error) => {
182
172
  if (response) {
183
- const parsedResponse = yield context.backend.convertResponse(context, response);
173
+ const parsedResponse = await context.backend.convertResponse(context, response);
184
174
  const contentType = parsedResponse.headers.get("content-type");
185
175
  const inferredResponseType = inferResponseType(contentType);
186
176
  if (!error) {
@@ -197,7 +187,7 @@ const parseResponse = (context, response, error) => __awaiter(void 0, void 0, vo
197
187
  if (inferredResponseType === "arraybuffer" && context.responseType === "json") {
198
188
  if (parsedResponse.data && typeof parsedResponse.data === "object") {
199
189
  const data = response.data;
200
- if (((_a = data.constructor) === null || _a === void 0 ? void 0 : _a.name) === "ArrayBuffer") {
190
+ if (data.constructor?.name === "ArrayBuffer") {
201
191
  try {
202
192
  const decodedData = (response.data = textDecode(data));
203
193
  response.data = JSON.parse(decodedData);
@@ -217,18 +207,17 @@ const parseResponse = (context, response, error) => __awaiter(void 0, void 0, vo
217
207
  return parsedResponse;
218
208
  }
219
209
  return response;
220
- });
221
- const parseError = (context, rawError) => __awaiter(void 0, void 0, void 0, function* () {
222
- var _a;
210
+ };
211
+ const parseError = async (context, rawError) => {
223
212
  let error;
224
213
  if (isRequestError(rawError)) {
225
214
  error = rawError;
226
215
  }
227
216
  else {
228
- const extractedResponse = yield context.backend.extractResponseFromError(rawError);
229
- let errorResponse = undefined;
217
+ const extractedResponse = await context.backend.extractResponseFromError(rawError);
218
+ let errorResponse;
230
219
  if (extractedResponse !== undefined) {
231
- errorResponse = yield parseResponse(context, extractedResponse, true);
220
+ errorResponse = await parseResponse(context, extractedResponse, true);
232
221
  }
233
222
  let code = isNetworkError(rawError)
234
223
  ? RequestErrorCode.REQUEST_NETWORK_ERROR
@@ -239,12 +228,18 @@ const parseError = (context, rawError) => __awaiter(void 0, void 0, void 0, func
239
228
  }
240
229
  }
241
230
  else {
242
- if (rawError.code === "ENOTFOUND" || ((_a = rawError.cause) === null || _a === void 0 ? void 0 : _a.code) === "ENOTFOUND") {
231
+ if (rawError.code === "ENOTFOUND" || rawError.cause?.code === "ENOTFOUND") {
243
232
  code = RequestErrorCode.REQUEST_HOST_NAME_NOT_FOUND;
244
233
  }
245
234
  }
246
235
  const errorInfo = context.backend.getErrorInfo(rawError, errorResponse);
247
- error = convertToRequestError(Object.assign({ error: rawError, response: errorResponse, code: code, context: context }, errorInfo));
236
+ error = convertToRequestError({
237
+ error: rawError,
238
+ response: errorResponse,
239
+ code: code,
240
+ context: context,
241
+ ...errorInfo,
242
+ });
248
243
  }
249
244
  return error;
250
- });
245
+ };
@@ -1,4 +1,4 @@
1
- import type Endpoint from "./Endpoint";
1
+ import type Endpoint from "./Endpoint.js";
2
2
  export type ResponseOf<E extends Endpoint<any, any, any, any>> = E extends Endpoint<infer R, any, any, any> ? R : never;
3
3
  export type ParamsOf<E extends Endpoint<any, any, any, any>> = E extends Endpoint<any, infer P, any, any> ? P : never;
4
4
  export type QueryOf<E extends Endpoint<any, any, any, any>> = E extends Endpoint<any, any, infer Q, any> ? Q : never;
package/esm/Utils.d.ts CHANGED
@@ -14,3 +14,4 @@ export declare const noop: () => void;
14
14
  export declare const delayThenReturn: <T>(value: T, delayMs: number) => Promise<T>;
15
15
  export declare const randInt: (min: number, max: number) => number;
16
16
  export declare const isFormData: (value: any) => value is FormData;
17
+ export declare const toFormData: (body: any) => FormData;
package/esm/Utils.js CHANGED
@@ -1,4 +1,5 @@
1
1
  // polyfill from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
2
+ const hasOwn = (object, key) => Object.prototype.hasOwnProperty.call(object, key);
2
3
  export const assign = Object.assign ||
3
4
  ((target, ...varArgs) => {
4
5
  if (target === null || target === undefined) {
@@ -10,7 +11,7 @@ export const assign = Object.assign ||
10
11
  if (nextSource !== null && nextSource !== undefined) {
11
12
  for (const nextKey in nextSource) {
12
13
  // Avoid bugs when hasOwnProperty is shadowed
13
- if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
14
+ if (hasOwn(nextSource, nextKey)) {
14
15
  to[nextKey] = nextSource[nextKey];
15
16
  }
16
17
  }
@@ -63,5 +64,56 @@ export const randInt = (min, max) => {
63
64
  return Math.floor(Math.random() * (maxI - minI + 1)) + minI;
64
65
  };
65
66
  export const isFormData = (value) => {
66
- return value instanceof FormData;
67
+ return typeof FormData !== "undefined" && value instanceof FormData;
68
+ };
69
+ const isPlainObject = (value) => {
70
+ return Object.prototype.toString.call(value) === "[object Object]";
71
+ };
72
+ const isBlob = (value) => {
73
+ return typeof Blob !== "undefined" && value instanceof Blob;
74
+ };
75
+ const isArrayBuffer = (value) => {
76
+ return typeof ArrayBuffer !== "undefined" && value instanceof ArrayBuffer;
77
+ };
78
+ const isArrayBufferView = (value) => {
79
+ return typeof ArrayBuffer !== "undefined" && ArrayBuffer.isView(value);
80
+ };
81
+ const toFormDataValue = (value) => {
82
+ if (isBlob(value)) {
83
+ return value;
84
+ }
85
+ if ((isArrayBuffer(value) || isArrayBufferView(value)) && typeof Blob !== "undefined") {
86
+ return new Blob([value]);
87
+ }
88
+ return String(value);
89
+ };
90
+ export const toFormData = (body) => {
91
+ if (isFormData(body)) {
92
+ return body;
93
+ }
94
+ const formData = new FormData();
95
+ const appendValue = (key, value) => {
96
+ if (value === undefined || value === null) {
97
+ return;
98
+ }
99
+ if (Array.isArray(value)) {
100
+ for (const item of value) {
101
+ appendValue(key, item);
102
+ }
103
+ return;
104
+ }
105
+ if (isPlainObject(value) && !isBlob(value)) {
106
+ for (const nestedKey of Object.keys(value)) {
107
+ appendValue(`${key}.${nestedKey}`, value[nestedKey]);
108
+ }
109
+ return;
110
+ }
111
+ formData.append(key, toFormDataValue(value));
112
+ };
113
+ if (isPlainObject(body)) {
114
+ for (const key of Object.keys(body)) {
115
+ appendValue(key, body[key]);
116
+ }
117
+ }
118
+ return formData;
67
119
  };
@@ -1,9 +1,16 @@
1
1
  import type * as zod from "zod";
2
- import type { Body, Params, Query, State } from "./ApiTypes";
2
+ import type { Body, Params, Query, RequestBodyEncoding, State } from "./ApiTypes.js";
3
+ export interface ValidationOptions<TValue> {
4
+ schema?: zod.Schema<TValue>;
5
+ }
6
+ export interface BodyValidationOptions<TBody extends Body> extends ValidationOptions<TBody> {
7
+ encoding?: RequestBodyEncoding;
8
+ }
3
9
  export interface Validation<TResponse = any, TParams extends Params | undefined = Params | undefined, TQuery extends Query | undefined = Query | undefined, TBody extends Body | undefined = Body | undefined, TState extends State = State> {
4
10
  query?: zod.Schema<TQuery>;
5
11
  params?: zod.Schema<TParams>;
6
12
  body?: zod.Schema<TBody>;
13
+ bodyEncoding?: RequestBodyEncoding;
7
14
  response?: zod.Schema<TResponse>;
8
15
  state?: zod.Schema<TState>;
9
16
  }
@@ -1,8 +1,8 @@
1
1
  import type { AxiosError, AxiosResponse } from "axios";
2
- import type { ApiResponse } from "../ApiTypes";
3
- import type RequestContext from "../RequestContext";
4
- import type { ConvertedApiResponse, RequestBackendErrorInfo, RequestOperation } from "./RequestBackend";
5
- import type RequestBackend from "./RequestBackend";
2
+ import type { ApiResponse } from "../ApiTypes.js";
3
+ import type RequestContext from "../RequestContext.js";
4
+ import type RequestBackend from "./RequestBackend.js";
5
+ import type { ConvertedApiResponse, RequestBackendErrorInfo, RequestOperation } from "./RequestBackend.js";
6
6
  export declare const isAxiosError: (error: Error) => error is AxiosError;
7
7
  export default class AxiosRequestBackend implements RequestBackend<AxiosResponse> {
8
8
  readonly id = "axios";