📜 Description
IdempotencyInterceptor uses an async callback inside the RxJS map operator in handleNewRequest().
return next.handle().pipe(
map(async (response) => {
await this.setCache(...);
return response;
}),
);
Since async functions always return a Promise, the map operator emits Promise<Response> instead of Response. RxJS map does not await Promises.
As a result, downstream interceptors (such as ResponseInterceptor) receive a Promise rather than the resolved response and may wrap or serialize it incorrectly (e.g. { data: Promise }).
The callback performs asynchronous work (await this.setCache(...)), so a flattening operator such as mergeMap should be used instead of map.
👟 Reproduction steps
-
Start the API with idempotency enabled.
-
Send a POST or PATCH request containing a valid Idempotency-Key header.
-
Ensure the request reaches IdempotencyInterceptor.handleNewRequest().
-
Observe that the interceptor executes:
map(async (response) => ...)
-
Inspect the value emitted by the observable or the response received by downstream interceptors.
👍 Expected behavior
The interceptor should emit the resolved response object after caching it.
The observable should emit:
Asynchronous cache writes should be flattened using mergeMap, concatMap, or another appropriate RxJS flattening operator.
👎 Actual Behavior with Screenshots
The interceptor emits:
Observable<Promise<Response>>
instead of:
This can cause downstream interceptors to receive a Promise instead of the actual response, resulting in incorrect response wrapping or serialization.
Novu version
Novu SaaS
npm version
NA
node version
NA
📃 Provide any additional context for the Bug.
NA
👀 Have you spent some time to check if this bug has been raised before?
🏢 Have you read the Contributing Guidelines?
Are you willing to submit PR?
Yes I am willing to submit a PR!
📜 Description
IdempotencyInterceptoruses anasynccallback inside the RxJSmapoperator inhandleNewRequest().Since
asyncfunctions always return aPromise, themapoperator emitsPromise<Response>instead ofResponse. RxJSmapdoes not await Promises.As a result, downstream interceptors (such as
ResponseInterceptor) receive aPromiserather than the resolved response and may wrap or serialize it incorrectly (e.g.{ data: Promise }).The callback performs asynchronous work (
await this.setCache(...)), so a flattening operator such asmergeMapshould be used instead ofmap.👟 Reproduction steps
Start the API with idempotency enabled.
Send a
POSTorPATCHrequest containing a validIdempotency-Keyheader.Ensure the request reaches
IdempotencyInterceptor.handleNewRequest().Observe that the interceptor executes:
Inspect the value emitted by the observable or the response received by downstream interceptors.
👍 Expected behavior
The interceptor should emit the resolved response object after caching it.
The observable should emit:
Asynchronous cache writes should be flattened using
mergeMap,concatMap, or another appropriate RxJS flattening operator.👎 Actual Behavior with Screenshots
The interceptor emits:
instead of:
This can cause downstream interceptors to receive a
Promiseinstead of the actual response, resulting in incorrect response wrapping or serialization.Novu version
Novu SaaS
npm version
NA
node version
NA
📃 Provide any additional context for the Bug.
NA
👀 Have you spent some time to check if this bug has been raised before?
🏢 Have you read the Contributing Guidelines?
Are you willing to submit PR?
Yes I am willing to submit a PR!