From 56a5da7389b724db88fbd7b86ec86683e7839eee Mon Sep 17 00:00:00 2001 From: Mikhail Kormanovskii Date: Wed, 6 Nov 2024 12:42:31 +0300 Subject: [PATCH 1/9] feat: add .redirect to RequestOptions and support in fetch engine --- src/core/request/engines/fetch/index.ts | 8 ++++++++ src/core/request/interface.ts | 1 + 2 files changed, 9 insertions(+) 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; } /** From 31052f3b08953d624fad756c711ed9684090425f Mon Sep 17 00:00:00 2001 From: Mikhail Kormanovskii Date: Thu, 7 Nov 2024 19:48:28 +0300 Subject: [PATCH 2/9] chore: up changelogs --- CHANGELOG.md | 8 +++++++- src/core/request/engines/fetch/CHANGELOG.md | 6 ++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cdf2372e2..b71396099 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,13 @@ Changelog > - :house: [Internal] > - :nail_care: [Polish] -_Note: Gaps between patch versions are faulty, broken or test releases._ +_Note: Gaps between patch versions are faulty, broken or test releases. + +## v?.??.? (????-??-??) + +#### :rocket: New Feature + +* Added support for `redirect` option `core/request/engines/fetch` ## v4.0.0-alpha.49 (2024-10-31) diff --git a/src/core/request/engines/fetch/CHANGELOG.md b/src/core/request/engines/fetch/CHANGELOG.md index 8d470f530..e1314f3cf 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] +## v?.??.? (????-??-??) + +#### :rocket: New Feature + +* Added support for `redirect` option + ## v3.78.0 (2022-03-16) #### :rocket: New Feature From 4e0487c6000df8aca417c736ab52ebae6495f0f1 Mon Sep 17 00:00:00 2001 From: Mikhail Kormanovskii Date: Fri, 8 Nov 2024 00:06:59 +0300 Subject: [PATCH 3/9] feat: support status and headers propagation in composition engine --- CHANGELOG.md | 7 +++ .../request/engines/composition/CHANGELOG.md | 7 +++ src/core/request/engines/composition/index.ts | 51 ++++++++++++++----- .../request/engines/composition/interface.ts | 15 ++++++ 4 files changed, 66 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b71396099..c3e5a61a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,13 @@ _Note: Gaps between patch versions are faulty, broken or test releases. ## v?.??.? (????-??-??) +#### :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` + +## v?.??.? (????-??-??) + #### :rocket: New Feature * Added support for `redirect` option `core/request/engines/fetch` diff --git a/src/core/request/engines/composition/CHANGELOG.md b/src/core/request/engines/composition/CHANGELOG.md index 472842725..b55256e38 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] +## v?.??.? (????-??-??) + +#### :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..62eb30a29 100644 --- a/src/core/request/engines/composition/index.ts +++ b/src/core/request/engines/composition/index.ts @@ -13,10 +13,10 @@ import Async from 'core/async'; import type { Provider } from 'core/data'; -import statusCodes from 'core/status-codes'; +import statusCodes, { StatusCodes } from 'core/status-codes'; import AbortablePromise from 'core/promise/abortable'; import { SyncPromise } from 'core/prelude/structures'; -import { RequestOptions, Response, MiddlewareParams, RequestResponseObject } from 'core/request'; +import { RequestOptions, Response, MiddlewareParams, RequestResponseObject, ResponseOptions } from 'core/request'; import type { @@ -24,11 +24,13 @@ import type { CompositionEngineOpts, CompositionRequestEngine, CompositionRequest, - CompositionRequestOptions + CompositionRequestOptions, + GatheredRequestsData } from 'core/request/engines/composition/interface'; import { compositionEngineSpreadResult } from 'core/request/engines/composition/const'; +import { RawHeaders } from 'core/request/headers'; export * from 'core/request/engines/composition/const'; export * from 'core/request/engines/composition/interface'; @@ -80,7 +82,6 @@ export function compositionEngine( return r.request(options) .then(boundRequest.bind(null, async)) - .then((request) => isRequestResponseObject(request) ? request.data : request) .catch((err) => { if (r.failCompositionOnError) { throw err; @@ -88,13 +89,14 @@ export function compositionEngine( }); })); - 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, + headers, decoder: requestOptions.decoders, noContentStatuses: requestOptions.noContentStatuses })); @@ -153,10 +155,14 @@ 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: {}, + status: StatusCodes.OK, + headers: {} + }; if (options.engineOptions?.aggregateErrors) { await Promise.allSettled(promises) @@ -198,18 +204,35 @@ async function gatherDataFromRequests( * @param compositionRequest */ function accumulateData( - accumulator: Dictionary, - data: unknown, + accumulator: GatheredRequestsData, + responseOrData: RequestResponseObject | unknown, compositionRequest: CompositionRequest -): Dictionary { +): GatheredRequestsData { const {as} = compositionRequest; + let + data: unknown = {}, + {status, headers} = accumulator; + + if (isRequestResponseObject(responseOrData)) { + data = responseOrData.data; + status = responseOrData.response.status; + headers = responseOrData.response.headers; + } else { + data = responseOrData; + } + 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..5987bd59d 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; +} From 47c1badd88971f3c1bba1eb2d278dc5c890d1e85 Mon Sep 17 00:00:00 2001 From: Mikhail Kormanovskii Date: Fri, 8 Nov 2024 00:28:04 +0300 Subject: [PATCH 4/9] fix: fixed usage of a type instead of a const --- src/core/request/engines/composition/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/request/engines/composition/index.ts b/src/core/request/engines/composition/index.ts index 62eb30a29..c23c549b6 100644 --- a/src/core/request/engines/composition/index.ts +++ b/src/core/request/engines/composition/index.ts @@ -13,7 +13,7 @@ import Async from 'core/async'; import type { Provider } from 'core/data'; -import statusCodes, { StatusCodes } from 'core/status-codes'; +import statusCodes from 'core/status-codes'; import AbortablePromise from 'core/promise/abortable'; import { SyncPromise } from 'core/prelude/structures'; import { RequestOptions, Response, MiddlewareParams, RequestResponseObject, ResponseOptions } from 'core/request'; @@ -160,7 +160,7 @@ async function gatherDataFromRequests( ): Promise { const accumulator = { data: {}, - status: StatusCodes.OK, + status: statusCodes.OK, headers: {} }; From 7bc0aeec2c2181c97a1eff297a518055f93ac168 Mon Sep 17 00:00:00 2001 From: Mikhail Kormanovskii Date: Fri, 8 Nov 2024 16:04:03 +0300 Subject: [PATCH 5/9] fix: fixed incorrect behaviour of propagateStatusAndHeaders in composition engine --- src/core/request/engines/composition/index.ts | 50 +++++++++++-------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/src/core/request/engines/composition/index.ts b/src/core/request/engines/composition/index.ts index c23c549b6..e75c7a466 100644 --- a/src/core/request/engines/composition/index.ts +++ b/src/core/request/engines/composition/index.ts @@ -16,7 +16,7 @@ import type { Provider } from 'core/data'; import statusCodes from 'core/status-codes'; import AbortablePromise from 'core/promise/abortable'; import { SyncPromise } from 'core/prelude/structures'; -import { RequestOptions, Response, MiddlewareParams, RequestResponseObject, ResponseOptions } from 'core/request'; +import { RequestOptions, Response, MiddlewareParams, RequestResponseObject } from 'core/request'; import type { @@ -30,7 +30,6 @@ import type { } from 'core/request/engines/composition/interface'; import { compositionEngineSpreadResult } from 'core/request/engines/composition/const'; -import { RawHeaders } from 'core/request/headers'; export * from 'core/request/engines/composition/const'; export * from 'core/request/engines/composition/interface'; @@ -77,15 +76,37 @@ export function compositionEngine( const promises = compositionRequests.map((r) => SyncPromise.resolve(r.requestFilter?.(options)) .then((filterValue) => { if (filterValue === false) { - return; + return Promise.resolve( + {data: {}, headers: {}, status: statusCodes.NO_CONTENT} + ); } return r.request(options) .then(boundRequest.bind(null, async)) + .then( + (request) => isRequestResponseObject(request) ? + ({ + data: request.data, + headers: request.response.headers, + status: request.response.status + }) : ({ + data: request, + headers: {}, + status: statusCodes.OK + }) + ) .catch((err) => { if (r.failCompositionOnError) { throw err; } + + const details = err.details.deref()!; + + return { + data: {}, + status: details.response.status, + headers: details.response.headers + }; }); })); @@ -155,7 +176,7 @@ function boundRequest( * @param options - Options related to composition requests. */ async function gatherDataFromRequests( - promises: Array>, + promises: Array>, options: CompositionRequestOptions ): Promise { const accumulator = { @@ -197,31 +218,20 @@ 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: GatheredRequestsData, - responseOrData: RequestResponseObject | unknown, + newData: GatheredRequestsData, compositionRequest: CompositionRequest ): GatheredRequestsData { const - {as} = compositionRequest; - - let - data: unknown = {}, - {status, headers} = accumulator; - - if (isRequestResponseObject(responseOrData)) { - data = responseOrData.data; - status = responseOrData.response.status; - headers = responseOrData.response.headers; - } else { - data = responseOrData; - } + {as} = compositionRequest, + {status, headers, data} = newData; if (as === compositionEngineSpreadResult) { Object.assign(accumulator.data, data); From 9bc8cb395a52ae0f13959af12e4a8a5486c15698 Mon Sep 17 00:00:00 2001 From: Mikhail Kormanovskii Date: Mon, 11 Nov 2024 01:31:22 +0300 Subject: [PATCH 6/9] fix: await request / request.data in promises array --- src/core/request/engines/composition/index.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/request/engines/composition/index.ts b/src/core/request/engines/composition/index.ts index e75c7a466..a62c643c9 100644 --- a/src/core/request/engines/composition/index.ts +++ b/src/core/request/engines/composition/index.ts @@ -84,13 +84,13 @@ export function compositionEngine( return r.request(options) .then(boundRequest.bind(null, async)) .then( - (request) => isRequestResponseObject(request) ? + async (request) => isRequestResponseObject(request) ? ({ - data: request.data, + data: await request.data, headers: request.response.headers, status: request.response.status }) : ({ - data: request, + data: await request, headers: {}, status: statusCodes.OK }) From b639fb3547bf17878ff68c645e9890808f726a1f Mon Sep 17 00:00:00 2001 From: Mikhail Kormanovskii Date: Mon, 11 Nov 2024 02:00:33 +0300 Subject: [PATCH 7/9] chore: do not return meaningless status codes and data --- src/core/request/engines/composition/index.ts | 22 ++++++------------- .../request/engines/composition/interface.ts | 6 ++--- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/src/core/request/engines/composition/index.ts b/src/core/request/engines/composition/index.ts index a62c643c9..188fbbef0 100644 --- a/src/core/request/engines/composition/index.ts +++ b/src/core/request/engines/composition/index.ts @@ -76,9 +76,7 @@ export function compositionEngine( const promises = compositionRequests.map((r) => SyncPromise.resolve(r.requestFilter?.(options)) .then((filterValue) => { if (filterValue === false) { - return Promise.resolve( - {data: {}, headers: {}, status: statusCodes.NO_CONTENT} - ); + return {}; } return r.request(options) @@ -100,13 +98,7 @@ export function compositionEngine( throw err; } - const details = err.details.deref()!; - - return { - data: {}, - status: details.response.status, - headers: details.response.headers - }; + return {}; }); })); @@ -116,8 +108,8 @@ export function compositionEngine( important: requestOptions.important, responseType: 'object', okStatuses: requestOptions.okStatuses, - status, - headers, + status: status ?? statusCodes.OK, + headers: headers ?? {}, decoder: requestOptions.decoders, noContentStatuses: requestOptions.noContentStatuses })); @@ -180,9 +172,7 @@ async function gatherDataFromRequests( options: CompositionRequestOptions ): Promise { const accumulator = { - data: {}, - status: statusCodes.OK, - headers: {} + data: {} }; if (options.engineOptions?.aggregateErrors) { @@ -233,6 +223,8 @@ function accumulateData( {as} = compositionRequest, {status, headers, data} = newData; + accumulator.data ??= {}; + if (as === compositionEngineSpreadResult) { Object.assign(accumulator.data, data); diff --git a/src/core/request/engines/composition/interface.ts b/src/core/request/engines/composition/interface.ts index 5987bd59d..4bf2e9795 100644 --- a/src/core/request/engines/composition/interface.ts +++ b/src/core/request/engines/composition/interface.ts @@ -177,7 +177,7 @@ export interface CompositionRequestEngine extends RequestEngine { } export interface GatheredRequestsData { - data: Dictionary; - headers: RawHeaders; - status: StatusCodes; + data?: Dictionary; + headers?: RawHeaders; + status?: StatusCodes; } From 2f9ffab2d774fac2163defb7908e6c8196288684 Mon Sep 17 00:00:00 2001 From: Mikhail Kormanovskii Date: Mon, 2 Dec 2024 11:24:58 +0300 Subject: [PATCH 8/9] chore: up version 4.0.0-alpha.51 --- CHANGELOG.md | 9 ++------- package.json | 2 +- src/core/request/engines/composition/CHANGELOG.md | 2 +- src/core/request/engines/fetch/CHANGELOG.md | 2 +- 4 files changed, 5 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cad62f8c4..d2f911d52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,19 +9,14 @@ Changelog > - :house: [Internal] > - :nail_care: [Polish] -_Note: Gaps between patch versions are faulty, broken or test releases. +_Note: Gaps between patch versions are faulty, broken or test releases._ -## v?.??.? (????-??-??) +## 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` - -## v?.??.? (????-??-??) - -#### :rocket: New Feature - * Added support for `redirect` option `core/request/engines/fetch` ## v4.0.0-alpha.50 (2024-11-26) 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 b55256e38..b297d586e 100644 --- a/src/core/request/engines/composition/CHANGELOG.md +++ b/src/core/request/engines/composition/CHANGELOG.md @@ -9,7 +9,7 @@ Changelog > - :house: [Internal] > - :nail_care: [Polish] -## v?.??.? (????-??-??) +## v4.0.0-alpha.51 (2024-12-02) #### :rocket: New Feature diff --git a/src/core/request/engines/fetch/CHANGELOG.md b/src/core/request/engines/fetch/CHANGELOG.md index e1314f3cf..e3365d5e9 100644 --- a/src/core/request/engines/fetch/CHANGELOG.md +++ b/src/core/request/engines/fetch/CHANGELOG.md @@ -9,7 +9,7 @@ Changelog > - :house: [Internal] > - :nail_care: [Polish] -## v?.??.? (????-??-??) +## v4.0.0-alpha.51 (2024-12-02) #### :rocket: New Feature From 180790e57bb7b38624ceb90cedea2c7eb019fb5b Mon Sep 17 00:00:00 2001 From: Mikhail Kormanovskii Date: Mon, 2 Dec 2024 11:32:52 +0300 Subject: [PATCH 9/9] chore: fix linters --- src/core/request/engines/composition/index.ts | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/core/request/engines/composition/index.ts b/src/core/request/engines/composition/index.ts index 188fbbef0..1e69c69dd 100644 --- a/src/core/request/engines/composition/index.ts +++ b/src/core/request/engines/composition/index.ts @@ -81,18 +81,21 @@ export function compositionEngine( return r.request(options) .then(boundRequest.bind(null, async)) - .then( - async (request) => isRequestResponseObject(request) ? - ({ + .then(async (request) => { + if (isRequestResponseObject(request)) { + return { data: await request.data, headers: request.response.headers, status: request.response.status - }) : ({ - data: await request, - headers: {}, - status: statusCodes.OK - }) - ) + }; + } + + return { + data: await request, + headers: {}, + status: statusCodes.OK + }; + }) .catch((err) => { if (r.failCompositionOnError) { throw err;