Skip to content

Commit 9484757

Browse files
authored
chore(middleware-recursion-detection): add no-op middleware outside of Node.js (#7326)
1 parent 7b0c4e9 commit 9484757

File tree

8 files changed

+116
-97
lines changed

8 files changed

+116
-97
lines changed

packages/middleware-recursion-detection/package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,5 +53,9 @@
5353
"downlevel-dts": "0.10.1",
5454
"rimraf": "3.0.2",
5555
"typescript": "~5.8.3"
56-
}
56+
},
57+
"browser": {
58+
"./dist-es/recursionDetectionMiddleware": "./dist-es/recursionDetectionMiddleware.browser"
59+
},
60+
"react-native": {}
5761
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { AbsoluteLocation, BuildHandlerOptions } from "@smithy/types";
2+
3+
/**
4+
* @internal
5+
*/
6+
export const recursionDetectionMiddlewareOptions: BuildHandlerOptions & AbsoluteLocation = {
7+
step: "build",
8+
tags: ["RECURSION_DETECTION"],
9+
name: "recursionDetectionMiddleware",
10+
override: true,
11+
priority: "low",
12+
};
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { Pluggable } from "@smithy/types";
2+
3+
import { recursionDetectionMiddlewareOptions } from "./configuration";
4+
import { recursionDetectionMiddleware } from "./recursionDetectionMiddleware";
5+
6+
/**
7+
* @internal
8+
*/
9+
export const getRecursionDetectionPlugin = (options: any): Pluggable<any, any> => ({
10+
applyToStack: (clientStack) => {
11+
clientStack.add(recursionDetectionMiddleware(), recursionDetectionMiddlewareOptions);
12+
},
13+
});
Lines changed: 2 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,2 @@
1-
import { HttpRequest } from "@smithy/protocol-http";
2-
import {
3-
AbsoluteLocation,
4-
BuildHandler,
5-
BuildHandlerArguments,
6-
BuildHandlerOptions,
7-
BuildHandlerOutput,
8-
BuildMiddleware,
9-
MetadataBearer,
10-
Pluggable,
11-
} from "@smithy/types";
12-
13-
const TRACE_ID_HEADER_NAME = "X-Amzn-Trace-Id";
14-
const ENV_LAMBDA_FUNCTION_NAME = "AWS_LAMBDA_FUNCTION_NAME";
15-
const ENV_TRACE_ID = "_X_AMZN_TRACE_ID";
16-
17-
interface PreviouslyResolved {
18-
runtime: string;
19-
}
20-
21-
/**
22-
* Inject to trace ID to request header to detect recursion invocation in Lambda.
23-
* @internal
24-
*/
25-
export const recursionDetectionMiddleware =
26-
(options: PreviouslyResolved): BuildMiddleware<any, any> =>
27-
<Output extends MetadataBearer>(next: BuildHandler<any, Output>): BuildHandler<any, Output> =>
28-
async (args: BuildHandlerArguments<any>): Promise<BuildHandlerOutput<Output>> => {
29-
const { request } = args;
30-
if (!HttpRequest.isInstance(request) || options.runtime !== "node") {
31-
return next(args);
32-
}
33-
const traceIdHeader =
34-
Object.keys(request.headers ?? {}).find((h) => h.toLowerCase() === TRACE_ID_HEADER_NAME.toLowerCase()) ??
35-
TRACE_ID_HEADER_NAME;
36-
37-
if (request.headers.hasOwnProperty(traceIdHeader)) {
38-
return next(args);
39-
}
40-
const functionName = process.env[ENV_LAMBDA_FUNCTION_NAME];
41-
const traceId = process.env[ENV_TRACE_ID];
42-
const nonEmptyString = (str: unknown): str is string => typeof str === "string" && str.length > 0;
43-
if (nonEmptyString(functionName) && nonEmptyString(traceId)) {
44-
request.headers[TRACE_ID_HEADER_NAME] = traceId;
45-
}
46-
return next({
47-
...args,
48-
request,
49-
});
50-
};
51-
52-
// @internal
53-
/**
54-
* @internal
55-
*/
56-
export const addRecursionDetectionMiddlewareOptions: BuildHandlerOptions & AbsoluteLocation = {
57-
step: "build",
58-
tags: ["RECURSION_DETECTION"],
59-
name: "recursionDetectionMiddleware",
60-
override: true,
61-
priority: "low",
62-
};
63-
64-
// @internal
65-
/**
66-
* @internal
67-
*/
68-
export const getRecursionDetectionPlugin = (options: PreviouslyResolved): Pluggable<any, any> => ({
69-
applyToStack: (clientStack) => {
70-
clientStack.add(recursionDetectionMiddleware(options), addRecursionDetectionMiddlewareOptions);
71-
},
72-
});
1+
export * from "./getRecursionDetectionPlugin";
2+
export * from "./recursionDetectionMiddleware";
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import {
2+
BuildHandler,
3+
BuildHandlerArguments,
4+
BuildHandlerOutput,
5+
BuildMiddleware,
6+
MetadataBearer,
7+
} from "@smithy/types";
8+
9+
/**
10+
* No-op middleware for runtimes outside of Node.js
11+
* @internal
12+
*/
13+
export const recursionDetectionMiddleware =
14+
(): BuildMiddleware<any, any> =>
15+
<Output extends MetadataBearer>(next: BuildHandler<any, Output>): BuildHandler<any, Output> =>
16+
async (args: BuildHandlerArguments<any>): Promise<BuildHandlerOutput<Output>> =>
17+
next(args);
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import {
2+
BuildHandler,
3+
BuildHandlerArguments,
4+
BuildHandlerOutput,
5+
BuildMiddleware,
6+
MetadataBearer,
7+
} from "@smithy/types";
8+
9+
/**
10+
* No-op middleware for runtimes outside of Node.js
11+
* @internal
12+
*/
13+
export const recursionDetectionMiddleware =
14+
(): BuildMiddleware<any, any> =>
15+
<Output extends MetadataBearer>(next: BuildHandler<any, Output>): BuildHandler<any, Output> =>
16+
async (args: BuildHandlerArguments<any>): Promise<BuildHandlerOutput<Output>> =>
17+
next(args);

packages/middleware-recursion-detection/src/index.spec.ts renamed to packages/middleware-recursion-detection/src/recursionDetectionMiddleware.spec.ts

Lines changed: 7 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { HttpRequest } from "@smithy/protocol-http";
22
import { afterAll, beforeEach, describe, expect, test as it, vi } from "vitest";
33

4-
import { recursionDetectionMiddleware } from "./index";
4+
import { recursionDetectionMiddleware } from "./recursionDetectionMiddleware";
55

66
describe(recursionDetectionMiddleware.name, () => {
77
const mockNextHandler = vi.fn();
@@ -22,7 +22,7 @@ describe(recursionDetectionMiddleware.name, () => {
2222
AWS_LAMBDA_FUNCTION_NAME: "some-function",
2323
_X_AMZN_TRACE_ID: "some-trace-id",
2424
};
25-
const handler = recursionDetectionMiddleware({ runtime: "node" })(mockNextHandler, {} as any);
25+
const handler = recursionDetectionMiddleware()(mockNextHandler, {} as any);
2626
await handler({
2727
input: {},
2828
request: new HttpRequest({}),
@@ -37,7 +37,7 @@ describe(recursionDetectionMiddleware.name, () => {
3737
process.env = {
3838
_X_AMZN_TRACE_ID: "some-trace-id",
3939
};
40-
const handler = recursionDetectionMiddleware({ runtime: "node" })(mockNextHandler, {} as any);
40+
const handler = recursionDetectionMiddleware()(mockNextHandler, {} as any);
4141
await handler({
4242
input: {},
4343
request: new HttpRequest({}),
@@ -54,7 +54,7 @@ describe(recursionDetectionMiddleware.name, () => {
5454
AWS_LAMBDA_FUNCTION_NAME: "some-function",
5555
_X_AMZN_TRACE_ID: "some-trace-id",
5656
};
57-
const handler = recursionDetectionMiddleware({ runtime: "node" })(mockNextHandler, {} as any);
57+
const handler = recursionDetectionMiddleware()(mockNextHandler, {} as any);
5858
await handler({
5959
input: {},
6060
request: new HttpRequest({
@@ -75,7 +75,7 @@ describe(recursionDetectionMiddleware.name, () => {
7575
AWS_LAMBDA_FUNCTION_NAME: "some-function",
7676
_X_AMZN_TRACE_ID: "some-trace-id",
7777
};
78-
const handler = recursionDetectionMiddleware({ runtime: "node" })(mockNextHandler, {} as any);
78+
const handler = recursionDetectionMiddleware()(mockNextHandler, {} as any);
7979
await handler({
8080
input: {},
8181
request: new HttpRequest({
@@ -100,7 +100,7 @@ describe(recursionDetectionMiddleware.name, () => {
100100
AWS_LAMBDA_FUNCTION_NAME: "some-function",
101101
_X_AMZN_TRACE_ID: "some-trace-id",
102102
};
103-
const handler = recursionDetectionMiddleware({ runtime: "node" })(mockNextHandler, {} as any);
103+
const handler = recursionDetectionMiddleware()(mockNextHandler, {} as any);
104104
await handler({
105105
input: {},
106106
request: new HttpRequest({
@@ -125,7 +125,7 @@ describe(recursionDetectionMiddleware.name, () => {
125125
AWS_LAMBDA_FUNCTION_NAME: "some-function",
126126
_X_AMZN_TRACE_ID: "some-trace-id",
127127
};
128-
const handler = recursionDetectionMiddleware({ runtime: "node" })(mockNextHandler, {} as any);
128+
const handler = recursionDetectionMiddleware()(mockNextHandler, {} as any);
129129
await handler({
130130
input: {},
131131
request: new HttpRequest({
@@ -144,21 +144,4 @@ describe(recursionDetectionMiddleware.name, () => {
144144
expect(existingTraceHeader).toBeDefined();
145145
expect(request.headers[existingTraceHeader!]).toBe("some-real-trace-id");
146146
});
147-
148-
it("has no effect for browser runtime", async () => {
149-
process.env = {
150-
AWS_LAMBDA_FUNCTION_NAME: "some-function",
151-
_X_AMZN_TRACE_ID: "some-trace-id",
152-
};
153-
const handler = recursionDetectionMiddleware({ runtime: "browser" })(mockNextHandler, {} as any);
154-
await handler({
155-
input: {},
156-
request: new HttpRequest({}),
157-
});
158-
159-
const { calls } = (mockNextHandler as any).mock;
160-
expect(calls.length).toBe(1);
161-
const { request } = mockNextHandler.mock.calls[0][0];
162-
expect(request.headers[TRACE_ID_HEADER_NAME]).toBeUndefined();
163-
});
164147
});
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { HttpRequest } from "@smithy/protocol-http";
2+
import {
3+
BuildHandler,
4+
BuildHandlerArguments,
5+
BuildHandlerOutput,
6+
BuildMiddleware,
7+
MetadataBearer,
8+
} from "@smithy/types";
9+
10+
const TRACE_ID_HEADER_NAME = "X-Amzn-Trace-Id";
11+
const ENV_LAMBDA_FUNCTION_NAME = "AWS_LAMBDA_FUNCTION_NAME";
12+
const ENV_TRACE_ID = "_X_AMZN_TRACE_ID";
13+
14+
/**
15+
* Inject to trace ID to request header to detect recursion invocation in Lambda.
16+
* @internal
17+
*/
18+
export const recursionDetectionMiddleware =
19+
(): BuildMiddleware<any, any> =>
20+
<Output extends MetadataBearer>(next: BuildHandler<any, Output>): BuildHandler<any, Output> =>
21+
async (args: BuildHandlerArguments<any>): Promise<BuildHandlerOutput<Output>> => {
22+
const { request } = args;
23+
if (!HttpRequest.isInstance(request)) {
24+
return next(args);
25+
}
26+
const traceIdHeader =
27+
Object.keys(request.headers ?? {}).find((h) => h.toLowerCase() === TRACE_ID_HEADER_NAME.toLowerCase()) ??
28+
TRACE_ID_HEADER_NAME;
29+
30+
if (request.headers.hasOwnProperty(traceIdHeader)) {
31+
return next(args);
32+
}
33+
const functionName = process.env[ENV_LAMBDA_FUNCTION_NAME];
34+
const traceId = process.env[ENV_TRACE_ID];
35+
const nonEmptyString = (str: unknown): str is string => typeof str === "string" && str.length > 0;
36+
if (nonEmptyString(functionName) && nonEmptyString(traceId)) {
37+
request.headers[TRACE_ID_HEADER_NAME] = traceId;
38+
}
39+
return next({
40+
...args,
41+
request,
42+
});
43+
};

0 commit comments

Comments
 (0)