mappersmith
Advanced tools
Comparing version 2.43.4 to 2.44.0
# Changelog | ||
## 2.44.0 | ||
### Minor Changes | ||
- 3a3c092: # Add support for abort signals | ||
The [AbortSignal](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) interface represents a signal object that allows you to communicate with an asynchronous operation (such as a fetch request) and abort it if required via an AbortController object. All gateway APIs (Fetch, HTTP and XHR) support this interface via the `signal` parameter: | ||
```javascript | ||
const abortController = new AbortController() | ||
// Start a long running task... | ||
client.Bitcoin.mine({ signal: abortController.signal }) | ||
// This takes too long, abort! | ||
abortController.abort() | ||
``` | ||
# Minor type fixes | ||
The return value of some functions on `Request` have been updated to highlight that they might return undefined: | ||
- `Request#body()` | ||
- `Request#auth()` | ||
- `Request#timeout()` | ||
The reasoning behind this change is that if you didn't pass them (and no middleware set them) they might simply be undefined. So the types were simply wrong before. If you experience a "breaking change" due to this change, then it means you have a potential bug that you didn't properly handle before. | ||
## 2.43.4 | ||
@@ -4,0 +30,0 @@ |
@@ -18,5 +18,5 @@ /// <reference types="node" /> | ||
delete(): void; | ||
performRequest(method: Method): void; | ||
performRequest(requestMethod: Method): void; | ||
createResponse(fetchResponse: globalThis.Response, data: string | ArrayBuffer | Buffer): Response<import("../response").ParsedJSON>; | ||
} | ||
export default Fetch; |
@@ -59,3 +59,3 @@ "use strict"; | ||
} | ||
performRequest(method) { | ||
performRequest(requestMethod) { | ||
const fetch = import_mappersmith.configs.fetch; | ||
@@ -68,3 +68,3 @@ if (!fetch) { | ||
const customHeaders = {}; | ||
const body = this.prepareBody(method, customHeaders); | ||
const body = this.prepareBody(requestMethod, customHeaders); | ||
const auth = this.request.auth(); | ||
@@ -77,4 +77,5 @@ if (auth) { | ||
const headers = (0, import_utils.assign)(customHeaders, this.request.headers()); | ||
const requestMethod = this.shouldEmulateHTTP() ? "post" : method; | ||
const init = (0, import_utils.assign)({ method: requestMethod, headers, body }, this.options().Fetch); | ||
const method = this.shouldEmulateHTTP() ? "post" : requestMethod; | ||
const signal = this.request.signal(); | ||
const init = (0, import_utils.assign)({ method, headers, body, signal }, this.options().Fetch); | ||
const timeout = this.request.timeout(); | ||
@@ -81,0 +82,0 @@ let timer = null; |
@@ -15,3 +15,3 @@ /// <reference types="node" /> | ||
delete(): void; | ||
performRequest(method: Method): void; | ||
performRequest(requestMethod: Method): void; | ||
onResponse(httpResponse: http.IncomingMessage, httpOptions: Partial<HTTPGatewayConfiguration>, requestParams: HTTPRequestParams): void; | ||
@@ -18,0 +18,0 @@ onError(e: Error): void; |
@@ -62,8 +62,9 @@ "use strict"; | ||
} | ||
performRequest(method) { | ||
performRequest(requestMethod) { | ||
const headers = {}; | ||
const defaults = url.parse(this.request.url()); | ||
const requestMethod = this.shouldEmulateHTTP() ? "post" : method; | ||
const body = this.prepareBody(method, headers); | ||
const method = this.shouldEmulateHTTP() ? "post" : requestMethod; | ||
const body = this.prepareBody(requestMethod, headers); | ||
const timeout = this.request.timeout(); | ||
const signal = this.request.signal(); | ||
this.canceled = false; | ||
@@ -75,3 +76,3 @@ if (body && typeof body !== "boolean" && typeof body !== "number" && typeof body.length === "number") { | ||
const requestParams = (0, import_utils.assign)(defaults, { | ||
method: requestMethod, | ||
method, | ||
headers: (0, import_utils.assign)(headers, this.request.headers()) | ||
@@ -95,2 +96,5 @@ }); | ||
} | ||
if (signal) { | ||
requestParams.signal = signal; | ||
} | ||
const httpRequest = handler.request( | ||
@@ -97,0 +101,0 @@ requestParams, |
@@ -16,2 +16,3 @@ import { Gateway } from './gateway'; | ||
configureTimeout(xmlHttpRequest: XMLHttpRequest): void; | ||
configureAbort(xmlHttpRequest: XMLHttpRequest): void; | ||
configureCallbacks(xmlHttpRequest: XMLHttpRequest): void; | ||
@@ -18,0 +19,0 @@ performRequest(method: Method): void; |
@@ -54,2 +54,3 @@ "use strict"; | ||
this.configureBinary(xmlHttpRequest); | ||
this.configureAbort(xmlHttpRequest); | ||
xmlHttpRequest.send(); | ||
@@ -63,2 +64,3 @@ } | ||
this.configureBinary(xmlHttpRequest); | ||
this.configureAbort(xmlHttpRequest); | ||
xmlHttpRequest.send(); | ||
@@ -102,2 +104,16 @@ } | ||
} | ||
configureAbort(xmlHttpRequest) { | ||
const signal = this.request.signal(); | ||
if (signal) { | ||
signal.addEventListener("abort", () => { | ||
xmlHttpRequest.abort(); | ||
}); | ||
xmlHttpRequest.addEventListener("abort", () => { | ||
this.dispatchClientError( | ||
"The operation was aborted", | ||
new Error("The operation was aborted") | ||
); | ||
}); | ||
} | ||
} | ||
configureCallbacks(xmlHttpRequest) { | ||
@@ -142,2 +158,3 @@ xmlHttpRequest.addEventListener("load", () => { | ||
this.configureBinary(xmlHttpRequest); | ||
this.configureAbort(xmlHttpRequest); | ||
xmlHttpRequest.send(body); | ||
@@ -144,0 +161,0 @@ } |
@@ -23,14 +23,15 @@ import { MethodDescriptor, MethodDescriptorParams } from './method-descriptor'; | ||
export interface ManifestOptions<Resources extends ResourceTypeConstraint> { | ||
host: string; | ||
allowResourceHostOverride?: boolean; | ||
parameterEncoder?: ParameterEncoderFn; | ||
authAttr?: string; | ||
bodyAttr?: string; | ||
clientId?: string; | ||
gatewayConfigs?: Partial<GatewayConfiguration>; | ||
headersAttr?: string; | ||
authAttr?: string; | ||
timeoutAttr?: string; | ||
host: string; | ||
hostAttr?: string; | ||
clientId?: string; | ||
gatewayConfigs?: Partial<GatewayConfiguration>; | ||
middleware?: Middleware[]; | ||
parameterEncoder?: ParameterEncoderFn; | ||
resources?: Resources; | ||
middleware?: Middleware[]; | ||
signalAttr?: string; | ||
timeoutAttr?: string; | ||
/** | ||
@@ -58,15 +59,16 @@ * @deprecated - use `middleware` instead | ||
export declare class Manifest<Resources extends ResourceTypeConstraint> { | ||
host: string; | ||
allowResourceHostOverride: boolean; | ||
parameterEncoder: ParameterEncoderFn; | ||
authAttr?: string; | ||
bodyAttr?: string; | ||
clientId: string | null; | ||
context: Context; | ||
gatewayConfigs: GatewayConfiguration; | ||
headersAttr?: string; | ||
authAttr?: string; | ||
timeoutAttr?: string; | ||
host: string; | ||
hostAttr?: string; | ||
clientId: string | null; | ||
gatewayConfigs: GatewayConfiguration; | ||
middleware: Middleware[]; | ||
parameterEncoder: ParameterEncoderFn; | ||
resources: Resources; | ||
context: Context; | ||
middleware: Middleware[]; | ||
signalAttr?: string; | ||
timeoutAttr?: string; | ||
constructor(options: ManifestOptions<Resources>, { gatewayConfigs, middleware, context }: GlobalConfigs); | ||
@@ -73,0 +75,0 @@ eachResource(callback: EachResourceCallbackFn): void; |
@@ -28,28 +28,30 @@ "use strict"; | ||
class Manifest { | ||
host; | ||
allowResourceHostOverride; | ||
parameterEncoder; | ||
authAttr; | ||
bodyAttr; | ||
clientId; | ||
context; | ||
gatewayConfigs; | ||
headersAttr; | ||
authAttr; | ||
timeoutAttr; | ||
host; | ||
hostAttr; | ||
clientId; | ||
gatewayConfigs; | ||
middleware; | ||
parameterEncoder; | ||
resources; | ||
context; | ||
middleware; | ||
signalAttr; | ||
timeoutAttr; | ||
constructor(options, { gatewayConfigs, middleware = [], context = {} }) { | ||
this.host = options.host; | ||
this.allowResourceHostOverride = options.allowResourceHostOverride || false; | ||
this.parameterEncoder = options.parameterEncoder || encodeURIComponent; | ||
this.authAttr = options.authAttr; | ||
this.bodyAttr = options.bodyAttr; | ||
this.clientId = options.clientId || null; | ||
this.context = context; | ||
this.gatewayConfigs = (0, import_utils.assign)({}, gatewayConfigs, options.gatewayConfigs); | ||
this.headersAttr = options.headersAttr; | ||
this.authAttr = options.authAttr; | ||
this.timeoutAttr = options.timeoutAttr; | ||
this.host = options.host; | ||
this.hostAttr = options.hostAttr; | ||
this.clientId = options.clientId || null; | ||
this.gatewayConfigs = (0, import_utils.assign)({}, gatewayConfigs, options.gatewayConfigs); | ||
this.parameterEncoder = options.parameterEncoder || encodeURIComponent; | ||
this.resources = options.resources || {}; | ||
this.context = context; | ||
this.signalAttr = options.signalAttr; | ||
this.timeoutAttr = options.timeoutAttr; | ||
const clientMiddleware = options.middleware || options.middlewares || []; | ||
@@ -91,3 +93,4 @@ if (options.ignoreGlobalMiddleware) { | ||
timeoutAttr: this.timeoutAttr, | ||
hostAttr: this.hostAttr | ||
hostAttr: this.hostAttr, | ||
signalAttr: this.signalAttr | ||
}, | ||
@@ -94,0 +97,0 @@ definition |
@@ -5,3 +5,2 @@ import type { Headers, RequestParams, ParameterEncoderFn, Params } from './types'; | ||
allowResourceHostOverride?: boolean; | ||
parameterEncoder?: ParameterEncoderFn; | ||
authAttr?: string; | ||
@@ -17,2 +16,3 @@ binary?: boolean; | ||
middlewares?: Array<Middleware>; | ||
parameterEncoder?: ParameterEncoderFn; | ||
params?: Params; | ||
@@ -22,2 +22,3 @@ path: string | ((args: RequestParams) => string); | ||
queryParamAlias?: Record<string, string>; | ||
signalAttr?: string; | ||
timeoutAttr?: string; | ||
@@ -44,2 +45,3 @@ } | ||
* @param {Object} params.queryParamAlias | ||
* @param {Number} params.signalAttr - signal attribute name. Default: 'signal' | ||
* @param {Number} params.timeoutAttr - timeout attribute name. Default: 'timeout' | ||
@@ -49,3 +51,2 @@ */ | ||
readonly allowResourceHostOverride: boolean; | ||
readonly parameterEncoder: ParameterEncoderFn; | ||
readonly authAttr: string; | ||
@@ -60,2 +61,3 @@ readonly binary: boolean; | ||
readonly middleware: Middleware[]; | ||
readonly parameterEncoder: ParameterEncoderFn; | ||
readonly params?: RequestParams; | ||
@@ -65,2 +67,3 @@ readonly path: string | ((args: RequestParams) => string); | ||
readonly queryParamAlias: Record<string, string>; | ||
readonly signalAttr: string; | ||
readonly timeoutAttr: string; | ||
@@ -67,0 +70,0 @@ constructor(params: MethodDescriptorParams); |
@@ -27,3 +27,2 @@ "use strict"; | ||
allowResourceHostOverride; | ||
parameterEncoder; | ||
authAttr; | ||
@@ -38,2 +37,3 @@ binary; | ||
middleware; | ||
parameterEncoder; | ||
params; | ||
@@ -43,6 +43,6 @@ path; | ||
queryParamAlias; | ||
signalAttr; | ||
timeoutAttr; | ||
constructor(params) { | ||
this.allowResourceHostOverride = params.allowResourceHostOverride || false; | ||
this.parameterEncoder = params.parameterEncoder || encodeURIComponent; | ||
this.binary = params.binary || false; | ||
@@ -52,2 +52,3 @@ this.headers = params.headers; | ||
this.method = params.method || "get"; | ||
this.parameterEncoder = params.parameterEncoder || encodeURIComponent; | ||
this.params = params.params; | ||
@@ -61,2 +62,3 @@ this.path = params.path; | ||
this.pathAttr = params.pathAttr || "path"; | ||
this.signalAttr = params.signalAttr || "signal"; | ||
this.timeoutAttr = params.timeoutAttr || "timeout"; | ||
@@ -63,0 +65,0 @@ const resourceMiddleware = params.middleware || params.middlewares || []; |
{ | ||
"name": "mappersmith", | ||
"version": "2.43.4", | ||
"version": "2.44.0", | ||
"description": "It is a lightweight rest client for node.js and the browser", | ||
@@ -214,38 +214,38 @@ "author": "Tulio Ornelas <ornelas.tulio@gmail.com>", | ||
"devDependencies": { | ||
"@babel/preset-env": "^7.23.9", | ||
"@babel/preset-typescript": "^7.22.11", | ||
"@babel/register": "^7.23.7", | ||
"@changesets/cli": "^2.27.1", | ||
"@chiragrupani/karma-chromium-edge-launcher": "^2.3.1", | ||
"@babel/preset-env": "^7.25.4", | ||
"@babel/preset-typescript": "^7.24.7", | ||
"@babel/register": "^7.24.6", | ||
"@changesets/cli": "^2.27.8", | ||
"@chiragrupani/karma-chromium-edge-launcher": "^2.4.1", | ||
"@types/jest": "^29.5.12", | ||
"@types/karma": "^6.3.4", | ||
"@types/node": "^20.11.16", | ||
"@types/karma": "^6.3.8", | ||
"@types/node": "^22.5.4", | ||
"@types/webpack": "^5.28.5", | ||
"@typescript-eslint/eslint-plugin": "^6.20.0", | ||
"@typescript-eslint/parser": "^6.21.0", | ||
"babel-jest": "^29.6.4", | ||
"@typescript-eslint/eslint-plugin": "^7.6.0", | ||
"@typescript-eslint/parser": "^7.13.0", | ||
"babel-jest": "^29.7.0", | ||
"babel-loader": "^9.1.3", | ||
"babel-plugin-minify-replace": "^0.5.0", | ||
"body-parser": "^1.20.2", | ||
"body-parser": "^1.20.3", | ||
"browser-resolve": "^2.0.0", | ||
"concurrently": "^8.2.1", | ||
"cookie-parser": "^1.4.5", | ||
"concurrently": "^9.0.0", | ||
"cookie-parser": "^1.4.6", | ||
"copyfiles": "^2.4.1", | ||
"core-js": "^3.35.1", | ||
"core-js": "^3.38.1", | ||
"cross-env": "^7.0.3", | ||
"esbuild-plugin-file-path-extensions": "^2.0.0", | ||
"eslint": "^8.56.0", | ||
"eslint-config-prettier": "^9.0.0", | ||
"esbuild-plugin-file-path-extensions": "^2.1.2", | ||
"eslint": "^8.57.0", | ||
"eslint-config-prettier": "^9.1.0", | ||
"eslint-config-standard": "^17.1.0", | ||
"eslint-plugin-import": "^2.29.1", | ||
"eslint-plugin-n": "^16.6.2", | ||
"eslint-plugin-promise": "^6.1.1", | ||
"express": "^4.18.2", | ||
"eslint-plugin-import": "^2.30.0", | ||
"eslint-plugin-n": "^17.10.2", | ||
"eslint-plugin-promise": "^7.1.0", | ||
"express": "^4.20.0", | ||
"faux-jax-tulios": "^5.0.9", | ||
"jasmine": "^5.1.0", | ||
"jasmine-core": "^5.1.2", | ||
"jest": "^29.6.4", | ||
"jest-environment-jsdom": "^29.6.4", | ||
"jasmine": "^5.3.0", | ||
"jasmine-core": "^5.3.0", | ||
"jest": "^29.7.0", | ||
"jest-environment-jsdom": "^29.7.0", | ||
"js-md5": "^0.8.3", | ||
"karma": "^6.4.2", | ||
"karma": "^6.4.4", | ||
"karma-chrome-launcher": "^3.2.0", | ||
@@ -259,14 +259,14 @@ "karma-jasmine": "^5.1.0", | ||
"node-fetch": "<3.0.0", | ||
"prettier": "^3.2.5", | ||
"puppeteer": "^21.7.0", | ||
"regenerator-runtime": "^0.14.0", | ||
"ts-jest": "^29.1.2", | ||
"ts-node": "^10.9.1", | ||
"tsup": "^8.0.2", | ||
"typescript": "^5.2.2", | ||
"wait-on": "^7.0.1", | ||
"webpack": "^5.90.1", | ||
"prettier": "^3.3.3", | ||
"puppeteer": "^23.3.0", | ||
"regenerator-runtime": "^0.14.1", | ||
"ts-jest": "^29.2.5", | ||
"ts-node": "^10.9.2", | ||
"tsup": "^8.2.4", | ||
"typescript": "<5.5.0", | ||
"wait-on": "^8.0.1", | ||
"webpack": "^5.94.0", | ||
"whatwg-fetch": "^3.6.20" | ||
}, | ||
"packageManager": "yarn@4.0.2" | ||
"packageManager": "yarn@4.4.1" | ||
} |
@@ -20,2 +20,3 @@ [![npm version](https://badge.fury.io/js/mappersmith.svg)](http://badge.fury.io/js/mappersmith) | ||
- [Timeout](#timeout) | ||
- [Abort Signal](#abort-signal) | ||
- [Alternative host](#alternative-host) | ||
@@ -323,2 +324,30 @@ - [Alternative path](#alternative-path) | ||
### <a name="abort-signal"></a> Abort Signal | ||
The [AbortSignal](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) interface represents a signal object that allows you to communicate with an asynchronous operation (such as a fetch request) and abort it if required via an AbortController object. All gateway APIs (Fetch, HTTP and XHR) support this interface via the `signal` parameter: | ||
```javascript | ||
const abortController = new AbortController() | ||
client.User.all({ signal: abortController.signal }) | ||
// abort! | ||
abortController.abort() | ||
``` | ||
If `signal` is not possible as a special parameter for your API you can configure it through the param `signalAttr`: | ||
```javascript | ||
// ... | ||
{ | ||
all: { path: '/users', signalAttr: 'abortSignal' } | ||
} | ||
// ... | ||
const abortController = new AbortController() | ||
client.User.all({ abortSignal: abortController.signal }) | ||
// abort! | ||
abortController.abort() | ||
``` | ||
__NOTE__: The `signalAttr` param can be set at manifest level. | ||
### <a name="alternative-host"></a> Alternative host | ||
@@ -1189,3 +1218,3 @@ | ||
Mappersmith has a pluggable transport layer and it includes by default three gateways: xhr, http and fetch. Mappersmith will pick the correct gateway based on the environment you are running (nodejs or the browser). | ||
Mappersmith has a pluggable transport layer and it includes by default three gateways: xhr, http and fetch. Mappersmith will pick the correct gateway based on the environment you are running (nodejs, service worker or the browser). | ||
@@ -1192,0 +1221,0 @@ You can write your own gateway, take a look at [XHR](https://github.com/tulios/mappersmith/blob/master/src/gateway/xhr.js) for an example. To configure, import the `configs` object and assign the gateway option, like: |
@@ -66,5 +66,6 @@ import { MethodDescriptor } from './method-descriptor'; | ||
header<T extends string | number | boolean>(name: string): T | undefined; | ||
body(): Body; | ||
auth(): Auth; | ||
timeout(): number; | ||
body(): Body | undefined; | ||
auth(): Auth | undefined; | ||
timeout(): number | undefined; | ||
signal(): AbortSignal | undefined; | ||
/** | ||
@@ -71,0 +72,0 @@ * Enhances current request returning a new Request |
@@ -39,3 +39,3 @@ "use strict"; | ||
isParam(key) { | ||
return key !== this.methodDescriptor.headersAttr && key !== this.methodDescriptor.bodyAttr && key !== this.methodDescriptor.authAttr && key !== this.methodDescriptor.timeoutAttr && key !== this.methodDescriptor.hostAttr && key !== this.methodDescriptor.pathAttr; | ||
return key !== this.methodDescriptor.headersAttr && key !== this.methodDescriptor.bodyAttr && key !== this.methodDescriptor.authAttr && key !== this.methodDescriptor.timeoutAttr && key !== this.methodDescriptor.hostAttr && key !== this.methodDescriptor.signalAttr && key !== this.methodDescriptor.pathAttr; | ||
} | ||
@@ -197,2 +197,5 @@ params() { | ||
} | ||
signal() { | ||
return this.requestParams[this.methodDescriptor.signalAttr]; | ||
} | ||
/** | ||
@@ -216,2 +219,3 @@ * Enhances current request returning a new Request | ||
const pathKey = this.methodDescriptor.pathAttr; | ||
const signalKey = this.methodDescriptor.signalAttr; | ||
const requestParams = (0, import_utils.assign)({}, this.requestParams, extras.params); | ||
@@ -226,2 +230,3 @@ const headers = this.requestParams[headerKey]; | ||
extras.path && (requestParams[pathKey] = extras.path); | ||
extras.signal && (requestParams[signalKey] = extras.signal); | ||
const nextContext = { ...this.requestContext, ...requestContext }; | ||
@@ -228,0 +233,0 @@ return new Request(this.methodDescriptor, requestParams, nextContext); |
@@ -6,3 +6,7 @@ import { ClientBuilder } from './client-builder' | ||
import Request from './request' | ||
import Response from './response' | ||
import { getManifest, getManifestWithResourceConf } from '../spec/ts-helper' | ||
import MockGateway from './gateway/mock' | ||
import { configs as defaultConfigs } from './index' | ||
import { mockRequest } from './test/index' | ||
@@ -100,2 +104,45 @@ describe('ClientBuilder', () => { | ||
it('accepts manifest level timeoutAttr', async () => { | ||
mockRequest({ | ||
method: 'get', | ||
url: 'http://example.org/users/1?timeout=123', | ||
response: { | ||
status: 200, | ||
body: { | ||
name: 'John Doe', | ||
}, | ||
}, | ||
}) | ||
const GatewayClassFactory = () => MockGateway | ||
const manifest = { ...getManifest(), timeoutAttr: 'customTimeout' } | ||
const clientBuilder = new ClientBuilder(manifest, GatewayClassFactory, defaultConfigs) | ||
const client = clientBuilder.build() | ||
await expect(client.User.byId({ id: 1, timeout: 123, customTimeout: 456 })).resolves.toEqual( | ||
expect.any(Response) | ||
) | ||
}) | ||
it('accepts manifest level signalAttr', async () => { | ||
mockRequest({ | ||
method: 'get', | ||
url: 'http://example.org/users/1?signal=123', | ||
response: { | ||
status: 200, | ||
body: { | ||
name: 'John Doe', | ||
}, | ||
}, | ||
}) | ||
const GatewayClassFactory = () => MockGateway | ||
const manifest = { ...getManifest(), signalAttr: 'customSignal' } | ||
const clientBuilder = new ClientBuilder(manifest, GatewayClassFactory, defaultConfigs) | ||
const client = clientBuilder.build() | ||
const abortController = new AbortController() | ||
await expect( | ||
client.User.byId({ id: 1, signal: 123, customSignal: abortController.signal }) | ||
).resolves.toEqual(expect.any(Response)) | ||
}) | ||
describe('when a resource method is called', () => { | ||
@@ -102,0 +149,0 @@ it('calls the gateway with the correct request', async () => { |
@@ -40,3 +40,3 @@ import { Gateway } from './gateway' | ||
performRequest(method: Method) { | ||
performRequest(requestMethod: Method) { | ||
const fetch = configs.fetch | ||
@@ -51,3 +51,3 @@ | ||
const customHeaders: Record<string, string> = {} | ||
const body = this.prepareBody(method, customHeaders) as BodyInit | ||
const body = this.prepareBody(requestMethod, customHeaders) as BodyInit | ||
const auth = this.request.auth() | ||
@@ -62,4 +62,5 @@ | ||
const headers = assign(customHeaders, this.request.headers()) | ||
const requestMethod = this.shouldEmulateHTTP() ? 'post' : method | ||
const init: RequestInit = assign({ method: requestMethod, headers, body }, this.options().Fetch) | ||
const method = this.shouldEmulateHTTP() ? 'post' : requestMethod | ||
const signal = this.request.signal() | ||
const init: RequestInit = assign({ method, headers, body, signal }, this.options().Fetch) | ||
const timeout = this.request.timeout() | ||
@@ -66,0 +67,0 @@ |
@@ -42,3 +42,3 @@ import * as url from 'url' | ||
performRequest(method: Method) { | ||
performRequest(requestMethod: Method) { | ||
const headers: Record<string, Primitive> = {} | ||
@@ -48,5 +48,6 @@ // FIXME: Deprecated API | ||
const defaults = url.parse(this.request.url()) | ||
const requestMethod = this.shouldEmulateHTTP() ? 'post' : method | ||
const body = this.prepareBody(method, headers) | ||
const method = this.shouldEmulateHTTP() ? 'post' : requestMethod | ||
const body = this.prepareBody(requestMethod, headers) | ||
const timeout = this.request.timeout() | ||
const signal = this.request.signal() | ||
@@ -66,5 +67,5 @@ this.canceled = false | ||
const requestParams: HTTPRequestParams = assign(defaults, { | ||
method: requestMethod, | ||
headers: assign(headers, this.request.headers()), | ||
const requestParams: http.RequestOptions = assign(defaults, { | ||
method, | ||
headers: assign(headers, this.request.headers() as http.OutgoingHttpHeaders), | ||
}) | ||
@@ -93,2 +94,6 @@ | ||
if (signal) { | ||
requestParams.signal = signal | ||
} | ||
const httpRequest = handler.request(requestParams, (httpResponse) => | ||
@@ -95,0 +100,0 @@ this.onResponse(httpResponse, httpOptions, requestParams) |
@@ -25,2 +25,3 @@ import { Gateway } from './gateway' | ||
this.configureBinary(xmlHttpRequest) | ||
this.configureAbort(xmlHttpRequest) | ||
xmlHttpRequest.send() | ||
@@ -35,2 +36,3 @@ } | ||
this.configureBinary(xmlHttpRequest) | ||
this.configureAbort(xmlHttpRequest) | ||
xmlHttpRequest.send() | ||
@@ -85,2 +87,17 @@ } | ||
configureAbort(xmlHttpRequest: XMLHttpRequest) { | ||
const signal = this.request.signal() | ||
if (signal) { | ||
signal.addEventListener('abort', () => { | ||
xmlHttpRequest.abort() | ||
}) | ||
xmlHttpRequest.addEventListener('abort', () => { | ||
this.dispatchClientError( | ||
'The operation was aborted', | ||
new Error('The operation was aborted') | ||
) | ||
}) | ||
} | ||
} | ||
configureCallbacks(xmlHttpRequest: XMLHttpRequest) { | ||
@@ -134,2 +151,3 @@ xmlHttpRequest.addEventListener('load', () => { | ||
this.configureBinary(xmlHttpRequest) | ||
this.configureAbort(xmlHttpRequest) | ||
@@ -136,0 +154,0 @@ xmlHttpRequest.send(body) |
@@ -25,14 +25,15 @@ import { MethodDescriptor, MethodDescriptorParams } from './method-descriptor' | ||
export interface ManifestOptions<Resources extends ResourceTypeConstraint> { | ||
host: string | ||
allowResourceHostOverride?: boolean | ||
parameterEncoder?: ParameterEncoderFn | ||
authAttr?: string | ||
bodyAttr?: string | ||
clientId?: string | ||
gatewayConfigs?: Partial<GatewayConfiguration> | ||
headersAttr?: string | ||
authAttr?: string | ||
timeoutAttr?: string | ||
host: string | ||
hostAttr?: string | ||
clientId?: string | ||
gatewayConfigs?: Partial<GatewayConfiguration> | ||
middleware?: Middleware[] | ||
parameterEncoder?: ParameterEncoderFn | ||
resources?: Resources | ||
middleware?: Middleware[] | ||
signalAttr?: string | ||
timeoutAttr?: string | ||
/** | ||
@@ -60,15 +61,16 @@ * @deprecated - use `middleware` instead | ||
export class Manifest<Resources extends ResourceTypeConstraint> { | ||
public host: string | ||
public allowResourceHostOverride: boolean | ||
public parameterEncoder: ParameterEncoderFn | ||
public authAttr?: string | ||
public bodyAttr?: string | ||
public clientId: string | null | ||
public context: Context | ||
public gatewayConfigs: GatewayConfiguration | ||
public headersAttr?: string | ||
public authAttr?: string | ||
public timeoutAttr?: string | ||
public host: string | ||
public hostAttr?: string | ||
public clientId: string | null | ||
public gatewayConfigs: GatewayConfiguration | ||
public middleware: Middleware[] | ||
public parameterEncoder: ParameterEncoderFn | ||
public resources: Resources | ||
public context: Context | ||
public middleware: Middleware[] | ||
public signalAttr?: string | ||
public timeoutAttr?: string | ||
@@ -79,14 +81,15 @@ constructor( | ||
) { | ||
this.host = options.host | ||
this.allowResourceHostOverride = options.allowResourceHostOverride || false | ||
this.parameterEncoder = options.parameterEncoder || encodeURIComponent | ||
this.authAttr = options.authAttr | ||
this.bodyAttr = options.bodyAttr | ||
this.clientId = options.clientId || null | ||
this.context = context | ||
this.gatewayConfigs = assign({}, gatewayConfigs, options.gatewayConfigs) | ||
this.headersAttr = options.headersAttr | ||
this.authAttr = options.authAttr | ||
this.timeoutAttr = options.timeoutAttr | ||
this.host = options.host | ||
this.hostAttr = options.hostAttr | ||
this.clientId = options.clientId || null | ||
this.gatewayConfigs = assign({}, gatewayConfigs, options.gatewayConfigs) | ||
this.parameterEncoder = options.parameterEncoder || encodeURIComponent | ||
this.resources = options.resources || ({} as Resources) | ||
this.context = context | ||
this.signalAttr = options.signalAttr | ||
this.timeoutAttr = options.timeoutAttr | ||
@@ -136,2 +139,3 @@ // TODO: deprecate obj.middlewares in favor of obj.middleware | ||
hostAttr: this.hostAttr, | ||
signalAttr: this.signalAttr, | ||
}, | ||
@@ -138,0 +142,0 @@ definition |
@@ -6,3 +6,2 @@ import type { Headers, RequestParams, ParameterEncoderFn, Params } from './types' | ||
allowResourceHostOverride?: boolean | ||
parameterEncoder?: ParameterEncoderFn | ||
authAttr?: string | ||
@@ -18,2 +17,3 @@ binary?: boolean | ||
middlewares?: Array<Middleware> | ||
parameterEncoder?: ParameterEncoderFn | ||
params?: Params | ||
@@ -23,2 +23,3 @@ path: string | ((args: RequestParams) => string) | ||
queryParamAlias?: Record<string, string> | ||
signalAttr?: string | ||
timeoutAttr?: string | ||
@@ -46,2 +47,3 @@ } | ||
* @param {Object} params.queryParamAlias | ||
* @param {Number} params.signalAttr - signal attribute name. Default: 'signal' | ||
* @param {Number} params.timeoutAttr - timeout attribute name. Default: 'timeout' | ||
@@ -51,3 +53,2 @@ */ | ||
public readonly allowResourceHostOverride: boolean | ||
public readonly parameterEncoder: ParameterEncoderFn | ||
public readonly authAttr: string | ||
@@ -62,2 +63,3 @@ public readonly binary: boolean | ||
public readonly middleware: Middleware[] | ||
public readonly parameterEncoder: ParameterEncoderFn | ||
public readonly params?: RequestParams | ||
@@ -67,2 +69,3 @@ public readonly path: string | ((args: RequestParams) => string) | ||
public readonly queryParamAlias: Record<string, string> | ||
public readonly signalAttr: string | ||
public readonly timeoutAttr: string | ||
@@ -72,3 +75,2 @@ | ||
this.allowResourceHostOverride = params.allowResourceHostOverride || false | ||
this.parameterEncoder = params.parameterEncoder || encodeURIComponent | ||
this.binary = params.binary || false | ||
@@ -78,2 +80,3 @@ this.headers = params.headers | ||
this.method = params.method || 'get' | ||
this.parameterEncoder = params.parameterEncoder || encodeURIComponent | ||
this.params = params.params | ||
@@ -88,2 +91,3 @@ this.path = params.path | ||
this.pathAttr = params.pathAttr || 'path' | ||
this.signalAttr = params.signalAttr || 'signal' | ||
this.timeoutAttr = params.timeoutAttr || 'timeout' | ||
@@ -90,0 +94,0 @@ |
@@ -180,2 +180,14 @@ import MethodDescriptor from './method-descriptor' | ||
it('ignores "special" params', async () => { | ||
const abortController = new AbortController() | ||
const request = new Request(methodDescriptor, { | ||
...requestParams, | ||
timeout: 123, | ||
signal: abortController.signal, | ||
}) | ||
expect(request.path()).toEqual( | ||
'/path?param=request-value&method-desc-param=method-desc-value&request-param=request-value' | ||
) | ||
}) | ||
it('returns result of method descriptor path function', async () => { | ||
@@ -738,2 +750,7 @@ const methodDescriptor = new MethodDescriptor({ | ||
}) | ||
it('can return undefined', () => { | ||
const request = new Request(methodDescriptor, { ...requestParams, body: undefined }) | ||
expect(request.body()).toBeUndefined() | ||
}) | ||
}) | ||
@@ -756,2 +773,7 @@ | ||
}) | ||
it('can return undefined', () => { | ||
const request = new Request(methodDescriptor, { ...requestParams, auth: undefined }) | ||
expect(request.auth()).toBeUndefined() | ||
}) | ||
}) | ||
@@ -773,4 +795,35 @@ | ||
}) | ||
it('can return undefined', () => { | ||
const request = new Request(methodDescriptor, { ...requestParams, timeout: undefined }) | ||
expect(request.timeout()).toBeUndefined() | ||
}) | ||
}) | ||
describe('#signal', () => { | ||
it('returns requestParams signal', async () => { | ||
const abortController = new AbortController() | ||
const params = { ...requestParams, signal: abortController.signal } | ||
const request = new Request(methodDescriptor, params) | ||
expect(request.signal()).toEqual(params.signal) | ||
}) | ||
it('returns the configured signal param from params', () => { | ||
const methodDescriptor = new MethodDescriptor({ | ||
...methodDescriptorArgs, | ||
signalAttr: 'differentSignalParam', | ||
}) | ||
const abortController = new AbortController() | ||
const request = new Request(methodDescriptor, { | ||
differentSignalParam: abortController.signal, | ||
}) | ||
expect(request.signal()).toEqual(abortController.signal) | ||
}) | ||
it('can return undefined', () => { | ||
const request = new Request(methodDescriptor, requestParams) | ||
expect(request.signal()).toBeUndefined() | ||
}) | ||
}) | ||
describe('#isBinary', () => { | ||
@@ -789,2 +842,3 @@ it('returns method descriptor binary value', async () => { | ||
it('returns a new request enhanced by current request', async () => { | ||
const abortController = new AbortController() | ||
const request = new Request(methodDescriptor, requestParams) | ||
@@ -798,2 +852,3 @@ const extras = { | ||
timeout: 100, | ||
signal: abortController.signal, | ||
} | ||
@@ -810,2 +865,3 @@ expect(request.enhance(extras)).toEqual( | ||
timeout: 100, | ||
signal: abortController.signal, | ||
}) | ||
@@ -860,2 +916,12 @@ ) | ||
it('creates a new request based on the current request replacing the signal', () => { | ||
const abortController = new AbortController() | ||
const abortController2 = new AbortController() | ||
const request = new Request(methodDescriptor, { signal: abortController.signal }) | ||
const enhancedRequest = request.enhance({ signal: abortController2.signal }) | ||
expect(enhancedRequest).not.toEqual(request) | ||
expect(enhancedRequest.signal()).toEqual(abortController2.signal) | ||
expect(enhancedRequest.signal()).toEqual(abortController.signal) | ||
}) | ||
it('creates a new request based on the current request replacing the path', () => { | ||
@@ -886,2 +952,9 @@ const request = new Request({ ...methodDescriptor, params: {} }) | ||
it('does not remove the previously assigned "signal"', () => { | ||
const abortController = new AbortController() | ||
const request = new Request(methodDescriptor, { signal: abortController.signal }) | ||
const enhancedRequest = request.enhance({}) | ||
expect(enhancedRequest.signal()).toEqual(abortController.signal) | ||
}) | ||
it('does not remove the previously assigned "host" if allowResourceHostOverride=true', () => { | ||
@@ -958,2 +1031,16 @@ const methodDescriptor = new MethodDescriptor({ | ||
describe('for requests with a different "signal" key', () => { | ||
it('creates a new request based on the current request replacing the custom "signal"', () => { | ||
const abortController = new AbortController() | ||
const methodDescriptor = new MethodDescriptor({ | ||
...methodDescriptorArgs, | ||
timeoutAttr: 'snowflake', | ||
}) | ||
const request = new Request(methodDescriptor, { snowflake: 1000 }) | ||
const enhancedRequest = request.enhance({ signal: abortController.signal }) | ||
expect(enhancedRequest).not.toEqual(request) | ||
expect(enhancedRequest.signal()).toEqual(abortController.signal) | ||
}) | ||
}) | ||
describe('for requests with a different "host" key', () => { | ||
@@ -960,0 +1047,0 @@ it('creates a new request based on the current request replacing the custom "host"', () => { |
@@ -52,2 +52,3 @@ import { MethodDescriptor } from './method-descriptor' | ||
key !== this.methodDescriptor.hostAttr && | ||
key !== this.methodDescriptor.signalAttr && | ||
key !== this.methodDescriptor.pathAttr | ||
@@ -242,13 +243,17 @@ ) | ||
public body() { | ||
return this.requestParams[this.methodDescriptor.bodyAttr] as Body | ||
return this.requestParams[this.methodDescriptor.bodyAttr] as Body | undefined | ||
} | ||
public auth() { | ||
return this.requestParams[this.methodDescriptor.authAttr] as Auth | ||
return this.requestParams[this.methodDescriptor.authAttr] as Auth | undefined | ||
} | ||
public timeout() { | ||
return this.requestParams[this.methodDescriptor.timeoutAttr] as number | ||
return this.requestParams[this.methodDescriptor.timeoutAttr] as number | undefined | ||
} | ||
public signal() { | ||
return this.requestParams[this.methodDescriptor.signalAttr] as AbortSignal | undefined | ||
} | ||
/** | ||
@@ -272,2 +277,3 @@ * Enhances current request returning a new Request | ||
const pathKey = this.methodDescriptor.pathAttr | ||
const signalKey = this.methodDescriptor.signalAttr | ||
@@ -287,2 +293,3 @@ // Note: The result of merging an instance of RequestParams with instance of Params | ||
extras.path && (requestParams[pathKey] = extras.path) | ||
extras.signal && (requestParams[signalKey] = extras.signal) | ||
@@ -289,0 +296,0 @@ const nextContext = { ...this.requestContext, ...requestContext } |
@@ -41,2 +41,3 @@ export type Primitive = string | number | boolean | ||
readonly timeout?: number | ||
readonly signal?: AbortSignal | ||
[param: string]: object | Primitive | undefined | null | NestedParam | NestedParamArray | ||
@@ -43,0 +44,0 @@ } |
@@ -1,1 +0,1 @@ | ||
export const version = '2.43.4' | ||
export const version = '2.44.0' |
@@ -82,4 +82,3 @@ "use strict"; | ||
mocks.forEach((mock) => { | ||
if (mock.calls.length === 0) | ||
count++; | ||
if (mock.calls.length === 0) count++; | ||
}); | ||
@@ -86,0 +85,0 @@ return count; |
@@ -30,4 +30,5 @@ export type Primitive = string | number | boolean; | ||
readonly timeout?: number; | ||
readonly signal?: AbortSignal; | ||
[param: string]: object | Primitive | undefined | null | NestedParam | NestedParamArray; | ||
} | ||
export type ParameterEncoderFn = (arg: Primitive) => string; |
@@ -1,1 +0,1 @@ | ||
export declare const version = "2.43.4"; | ||
export declare const version = "2.44.0"; |
@@ -24,3 +24,3 @@ "use strict"; | ||
module.exports = __toCommonJS(version_exports); | ||
const version = "2.43.4"; | ||
const version = "2.44.0"; | ||
// Annotate the CommonJS export names for ESM import in node: | ||
@@ -27,0 +27,0 @@ 0 && (module.exports = { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
997637
12986
1480