api-def 0.14.2 → 0.15.0-alpha.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.
@@ -29,5 +29,6 @@ export declare const ResponseType: {
29
29
  readonly TEXT: "text";
30
30
  readonly ARRAY_BUFFER: "arraybuffer";
31
31
  readonly STREAM: "stream";
32
+ readonly WEBSOCKET: "websocket";
32
33
  };
33
34
  export type ResponseType = EnumOf<typeof ResponseType>;
@@ -27,4 +27,5 @@ exports.ResponseType = {
27
27
  TEXT: "text",
28
28
  ARRAY_BUFFER: "arraybuffer",
29
29
  STREAM: "stream",
30
+ WEBSOCKET: "websocket",
30
31
  };
@@ -4,7 +4,7 @@ import type { ResponseType } from "./ApiConstants";
4
4
  import type { Body, Params, Query, RawHeaders, State } from "./ApiTypes";
5
5
  import Endpoint, { type EndpointOptions } from "./Endpoint";
6
6
  import type { BodyValidationOptions, ValidationOptions } from "./Validation";
7
- type DefaultResponseOf<T extends ResponseType | undefined> = T extends "text" ? string : T extends "arraybuffer" ? ArrayBuffer : "stream" extends T ? AsyncIterable<Uint8Array> : unknown;
7
+ type DefaultResponseOf<T extends ResponseType | undefined> = T extends "text" ? string : T extends "arraybuffer" ? ArrayBuffer : T extends "stream" ? AsyncIterable<Uint8Array> : T extends "websocket" ? WebSocket : unknown;
8
8
  export type EndpointBuildOptions<TResponse = unknown, TParams extends Params | undefined = undefined, TQuery extends Query | undefined = undefined, TBody extends Body | undefined = undefined, TState extends State = State, TRequestHeaders extends RawHeaders | undefined = RawHeaders | undefined, TResponseHeaders extends RawHeaders | undefined = RawHeaders | undefined, TPath extends string = string, TResponseType extends ResponseType | undefined = undefined> = Omit<EndpointOptions<TResponse, TParams, TQuery, TBody, TState, TPath, TRequestHeaders, TResponseHeaders>, "validation"> & {
9
9
  responseType?: TResponseType;
10
10
  };
package/cjs/Requester.js CHANGED
@@ -112,7 +112,8 @@ const makeRequest = async (context) => {
112
112
  context.addCanceller(canceler);
113
113
  const response = await promise;
114
114
  const parsedResponse = (await parseResponse(context, response));
115
- if (!(0, ApiUtils_1.isAcceptableStatus)(parsedResponse.status, context.requestConfig.acceptableStatus)) {
115
+ if (!(context.responseType === "websocket" && parsedResponse.status === 101) &&
116
+ !(0, ApiUtils_1.isAcceptableStatus)(parsedResponse.status, context.requestConfig.acceptableStatus)) {
116
117
  throw (0, RequestError_1.convertToRequestError)({
117
118
  error: new Error(`[api-def] Invalid response status code '${parsedResponse.status}'`),
118
119
  response: parsedResponse,
package/cjs/Utils.js CHANGED
@@ -105,6 +105,10 @@ const toFormDataValue = (value) => {
105
105
  }
106
106
  return String(value);
107
107
  };
108
+ const getBlobFileName = (value) => {
109
+ const name = value.name;
110
+ return typeof name === "string" && name ? name : "blob";
111
+ };
108
112
  const toFormData = (body) => {
109
113
  if ((0, exports.isFormDataLike)(body)) {
110
114
  return body;
@@ -132,7 +136,13 @@ const toFormData = (body) => {
132
136
  }
133
137
  return;
134
138
  }
135
- formData.append(key, toFormDataValue(value));
139
+ const formValue = toFormDataValue(value);
140
+ if (isBlob(formValue)) {
141
+ formData.append(key, formValue, getBlobFileName(formValue));
142
+ }
143
+ else {
144
+ formData.append(key, formValue);
145
+ }
136
146
  };
137
147
  for (const key of Object.keys(body)) {
138
148
  appendValue(key, body[key]);
@@ -82,6 +82,9 @@ class AxiosRequestBackend {
82
82
  };
83
83
  }
84
84
  makeRequest(context) {
85
+ if (context.responseType === "websocket") {
86
+ throw new Error("[api-def] WebSocket responseType is only supported by FetchRequestBackend");
87
+ }
85
88
  const { requestConfig } = context;
86
89
  const url = context.requestUrl;
87
90
  let canceler = null;
@@ -83,6 +83,12 @@ class FetchRequestBackend {
83
83
  else if (responseType === "stream") {
84
84
  data = response.body;
85
85
  }
86
+ else if (responseType === "websocket") {
87
+ data = response.webSocket;
88
+ if (!data) {
89
+ throw new Error("[api-def] WebSocket upgrade response did not include a webSocket");
90
+ }
91
+ }
86
92
  else {
87
93
  data = await response.text();
88
94
  }
@@ -115,6 +121,8 @@ class FetchRequestBackend {
115
121
  const headers = Utils.assign({
116
122
  // logic from axios
117
123
  "Content-Type": bodyJsonify ? "application/json;charset=utf-8" : undefined,
124
+ Connection: context.responseType === "websocket" ? "Upgrade" : undefined,
125
+ Upgrade: context.responseType === "websocket" ? "websocket" : undefined,
118
126
  }, requestConfig.headers);
119
127
  const parsedHeaders = Object.keys(headers).reduce((parsedHeaders, key) => {
120
128
  const value = headers[key];
@@ -149,7 +157,7 @@ class FetchRequestBackend {
149
157
  }
150
158
  const promise = this.fetch(request).then((response) => {
151
159
  responded = true;
152
- if (!response.ok) {
160
+ if (!response.ok && !(context.responseType === "websocket" && response.status === 101)) {
153
161
  const error = new FetchError("Fetch failed");
154
162
  error.response = response;
155
163
  throw error;
@@ -29,5 +29,6 @@ export declare const ResponseType: {
29
29
  readonly TEXT: "text";
30
30
  readonly ARRAY_BUFFER: "arraybuffer";
31
31
  readonly STREAM: "stream";
32
+ readonly WEBSOCKET: "websocket";
32
33
  };
33
34
  export type ResponseType = EnumOf<typeof ResponseType>;
@@ -24,4 +24,5 @@ export const ResponseType = {
24
24
  TEXT: "text",
25
25
  ARRAY_BUFFER: "arraybuffer",
26
26
  STREAM: "stream",
27
+ WEBSOCKET: "websocket",
27
28
  };
@@ -4,7 +4,7 @@ import type { ResponseType } from "./ApiConstants.js";
4
4
  import type { Body, Params, Query, RawHeaders, State } from "./ApiTypes.js";
5
5
  import Endpoint, { type EndpointOptions } from "./Endpoint.js";
6
6
  import type { BodyValidationOptions, ValidationOptions } from "./Validation.js";
7
- type DefaultResponseOf<T extends ResponseType | undefined> = T extends "text" ? string : T extends "arraybuffer" ? ArrayBuffer : "stream" extends T ? AsyncIterable<Uint8Array> : unknown;
7
+ type DefaultResponseOf<T extends ResponseType | undefined> = T extends "text" ? string : T extends "arraybuffer" ? ArrayBuffer : T extends "stream" ? AsyncIterable<Uint8Array> : T extends "websocket" ? WebSocket : unknown;
8
8
  export type EndpointBuildOptions<TResponse = unknown, TParams extends Params | undefined = undefined, TQuery extends Query | undefined = undefined, TBody extends Body | undefined = undefined, TState extends State = State, TRequestHeaders extends RawHeaders | undefined = RawHeaders | undefined, TResponseHeaders extends RawHeaders | undefined = RawHeaders | undefined, TPath extends string = string, TResponseType extends ResponseType | undefined = undefined> = Omit<EndpointOptions<TResponse, TParams, TQuery, TBody, TState, TPath, TRequestHeaders, TResponseHeaders>, "validation"> & {
9
9
  responseType?: TResponseType;
10
10
  };
package/esm/Requester.js CHANGED
@@ -105,7 +105,8 @@ const makeRequest = async (context) => {
105
105
  context.addCanceller(canceler);
106
106
  const response = await promise;
107
107
  const parsedResponse = (await parseResponse(context, response));
108
- if (!isAcceptableStatus(parsedResponse.status, context.requestConfig.acceptableStatus)) {
108
+ if (!(context.responseType === "websocket" && parsedResponse.status === 101) &&
109
+ !isAcceptableStatus(parsedResponse.status, context.requestConfig.acceptableStatus)) {
109
110
  throw convertToRequestError({
110
111
  error: new Error(`[api-def] Invalid response status code '${parsedResponse.status}'`),
111
112
  response: parsedResponse,
package/esm/Utils.js CHANGED
@@ -94,6 +94,10 @@ const toFormDataValue = (value) => {
94
94
  }
95
95
  return String(value);
96
96
  };
97
+ const getBlobFileName = (value) => {
98
+ const name = value.name;
99
+ return typeof name === "string" && name ? name : "blob";
100
+ };
97
101
  export const toFormData = (body) => {
98
102
  if (isFormDataLike(body)) {
99
103
  return body;
@@ -121,7 +125,13 @@ export const toFormData = (body) => {
121
125
  }
122
126
  return;
123
127
  }
124
- formData.append(key, toFormDataValue(value));
128
+ const formValue = toFormDataValue(value);
129
+ if (isBlob(formValue)) {
130
+ formData.append(key, formValue, getBlobFileName(formValue));
131
+ }
132
+ else {
133
+ formData.append(key, formValue);
134
+ }
125
135
  };
126
136
  for (const key of Object.keys(body)) {
127
137
  appendValue(key, body[key]);
@@ -78,6 +78,9 @@ export default class AxiosRequestBackend {
78
78
  };
79
79
  }
80
80
  makeRequest(context) {
81
+ if (context.responseType === "websocket") {
82
+ throw new Error("[api-def] WebSocket responseType is only supported by FetchRequestBackend");
83
+ }
81
84
  const { requestConfig } = context;
82
85
  const url = context.requestUrl;
83
86
  let canceler = null;
@@ -48,6 +48,12 @@ export default class FetchRequestBackend {
48
48
  else if (responseType === "stream") {
49
49
  data = response.body;
50
50
  }
51
+ else if (responseType === "websocket") {
52
+ data = response.webSocket;
53
+ if (!data) {
54
+ throw new Error("[api-def] WebSocket upgrade response did not include a webSocket");
55
+ }
56
+ }
51
57
  else {
52
58
  data = await response.text();
53
59
  }
@@ -80,6 +86,8 @@ export default class FetchRequestBackend {
80
86
  const headers = Utils.assign({
81
87
  // logic from axios
82
88
  "Content-Type": bodyJsonify ? "application/json;charset=utf-8" : undefined,
89
+ Connection: context.responseType === "websocket" ? "Upgrade" : undefined,
90
+ Upgrade: context.responseType === "websocket" ? "websocket" : undefined,
83
91
  }, requestConfig.headers);
84
92
  const parsedHeaders = Object.keys(headers).reduce((parsedHeaders, key) => {
85
93
  const value = headers[key];
@@ -114,7 +122,7 @@ export default class FetchRequestBackend {
114
122
  }
115
123
  const promise = this.fetch(request).then((response) => {
116
124
  responded = true;
117
- if (!response.ok) {
125
+ if (!response.ok && !(context.responseType === "websocket" && response.status === 101)) {
118
126
  const error = new FetchError("Fetch failed");
119
127
  error.response = response;
120
128
  throw error;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "api-def",
3
- "version": "0.14.2",
3
+ "version": "0.15.0-alpha.0",
4
4
  "description": "Typed API definitions with middleware support",
5
5
  "main": "cjs/index.js",
6
6
  "types": "esm/index.d.ts",