diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a16f7e9f..d2f911d52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,14 @@ Changelog _Note: Gaps between patch versions are faulty, broken or test releases._ +## v4.0.0-alpha.51 (2024-12-02) + +#### :rocket: New Feature + +* Added support for propagating status code and headers from exactly one request of the composition +via `propagateStatusAndHeaders` option `core/request/engines/composition` +* Added support for `redirect` option `core/request/engines/fetch` + ## v4.0.0-alpha.50 (2024-11-26) #### :rocket: New Feature diff --git a/package.json b/package.json index 29b281f51..b44ebd28a 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "lib/core/index.js", "typings": "index.d.ts", "license": "MIT", - "version": "4.0.0-alpha.50", + "version": "4.0.0-alpha.51", "author": "kobezzza (https://github.com/kobezzza)", "repository": { "type": "git", diff --git a/src/core/request/engines/composition/CHANGELOG.md b/src/core/request/engines/composition/CHANGELOG.md index 472842725..b297d586e 100644 --- a/src/core/request/engines/composition/CHANGELOG.md +++ b/src/core/request/engines/composition/CHANGELOG.md @@ -9,6 +9,13 @@ Changelog > - :house: [Internal] > - :nail_care: [Polish] +## v4.0.0-alpha.51 (2024-12-02) + +#### :rocket: New Feature + +* Added support for propagating status code and headers from exactly one request of the composition +via `propagateStatusAndHeaders` option + ## v4.0.0-alpha.40 (2024-07-02) #### :bug: Bug Fix diff --git a/src/core/request/engines/composition/index.ts b/src/core/request/engines/composition/index.ts index 5d6632c98..1e69c69dd 100644 --- a/src/core/request/engines/composition/index.ts +++ b/src/core/request/engines/composition/index.ts @@ -24,7 +24,8 @@ import type { CompositionEngineOpts, CompositionRequestEngine, CompositionRequest, - CompositionRequestOptions + CompositionRequestOptions, + GatheredRequestsData } from 'core/request/engines/composition/interface'; @@ -75,26 +76,43 @@ export function compositionEngine( const promises = compositionRequests.map((r) => SyncPromise.resolve(r.requestFilter?.(options)) .then((filterValue) => { if (filterValue === false) { - return; + return {}; } return r.request(options) .then(boundRequest.bind(null, async)) - .then((request) => isRequestResponseObject(request) ? request.data : request) + .then(async (request) => { + if (isRequestResponseObject(request)) { + return { + data: await request.data, + headers: request.response.headers, + status: request.response.status + }; + } + + return { + data: await request, + headers: {}, + status: statusCodes.OK + }; + }) .catch((err) => { if (r.failCompositionOnError) { throw err; } + + return {}; }); })); - gatherDataFromRequests(promises, options).then((data) => { + gatherDataFromRequests(promises, options).then(({data, status, headers}) => { resolve(new Response(data, { parent: requestOptions.parent, important: requestOptions.important, responseType: 'object', okStatuses: requestOptions.okStatuses, - status: statusCodes.OK, + status: status ?? statusCodes.OK, + headers: headers ?? {}, decoder: requestOptions.decoders, noContentStatuses: requestOptions.noContentStatuses })); @@ -153,10 +171,12 @@ function boundRequest( * @param options - Options related to composition requests. */ async function gatherDataFromRequests( - promises: Array>, + promises: Array>, options: CompositionRequestOptions -): Promise { - const accumulator = {}; +): Promise { + const accumulator = { + data: {} + }; if (options.engineOptions?.aggregateErrors) { await Promise.allSettled(promises) @@ -191,25 +211,33 @@ async function gatherDataFromRequests( } /** - * Accumulates data into an accumulator object based on the composition request. + * Accumulates new data into an accumulator object based on the composition request. * * @param accumulator - * @param data + * @param newData * @param compositionRequest */ function accumulateData( - accumulator: Dictionary, - data: unknown, + accumulator: GatheredRequestsData, + newData: GatheredRequestsData, compositionRequest: CompositionRequest -): Dictionary { +): GatheredRequestsData { const - {as} = compositionRequest; + {as} = compositionRequest, + {status, headers, data} = newData; + + accumulator.data ??= {}; if (as === compositionEngineSpreadResult) { - Object.assign(accumulator, data); + Object.assign(accumulator.data, data); } else { - Object.set(accumulator, as, data); + Object.set(accumulator.data, as, data); + } + + if (compositionRequest.propagateStatusAndHeaders === true) { + accumulator.status = status; + accumulator.headers = headers; } return accumulator; diff --git a/src/core/request/engines/composition/interface.ts b/src/core/request/engines/composition/interface.ts index c9d870780..4bf2e9795 100644 --- a/src/core/request/engines/composition/interface.ts +++ b/src/core/request/engines/composition/interface.ts @@ -9,6 +9,8 @@ import type Provider from 'core/data'; import type { ProviderOptions } from 'core/data'; import type { RequestOptions, RequestResponseObject, MiddlewareParams, RequestPromise, RequestEngine } from 'core/request'; +import type { RawHeaders } from 'core/request/headers'; +import type { StatusCodes } from 'core/status-codes'; export interface CompositionEngineOpts { /** @@ -130,6 +132,13 @@ export interface CompositionRequest { * If false / undefined, request errors will be ignored. */ failCompositionOnError?: boolean; + + /** + * If true, status code and reponse headers will be propagated from this request to the whole + * composition. Note that if there are more than one request with this option set to true, + * only last request's data will be propagated. + */ + propagateStatusAndHeaders?: boolean; } export interface CompositionRequestOptions { @@ -166,3 +175,9 @@ export interface CompositionRequestEngine extends RequestEngine { dropCache: NonNullable; destroy: NonNullable; } + +export interface GatheredRequestsData { + data?: Dictionary; + headers?: RawHeaders; + status?: StatusCodes; +} diff --git a/src/core/request/engines/fetch/CHANGELOG.md b/src/core/request/engines/fetch/CHANGELOG.md index 8d470f530..e3365d5e9 100644 --- a/src/core/request/engines/fetch/CHANGELOG.md +++ b/src/core/request/engines/fetch/CHANGELOG.md @@ -9,6 +9,12 @@ Changelog > - :house: [Internal] > - :nail_care: [Polish] +## v4.0.0-alpha.51 (2024-12-02) + +#### :rocket: New Feature + +* Added support for `redirect` option + ## v3.78.0 (2022-03-16) #### :rocket: New Feature diff --git a/src/core/request/engines/fetch/index.ts b/src/core/request/engines/fetch/index.ts index e5d14a183..437d4f9ca 100644 --- a/src/core/request/engines/fetch/index.ts +++ b/src/core/request/engines/fetch/index.ts @@ -57,10 +57,18 @@ const request: RequestEngine = (params) => { credentials = 'include'; } + let + redirect: RequestRedirect = 'follow'; + + if (Object.isString(p.redirect)) { + redirect = p.redirect; + } + const fetchOpts: RequestInit = { body, headers, credentials, + redirect, method: p.method, signal: abortController.signal }; diff --git a/src/core/request/interface.ts b/src/core/request/interface.ts index c9e0d2eea..5b3d142ab 100644 --- a/src/core/request/interface.ts +++ b/src/core/request/interface.ts @@ -718,6 +718,7 @@ export interface RequestOptions { readonly important?: boolean; readonly credentials?: boolean | RequestCredentials; + readonly redirect?: RequestRedirect; } /**