Skip to content
Merged

7.1.3 #1581

Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
6a453cc
docs: fix website build
willfarrell Feb 24, 2026
17e9c77
Merge branch 'main' into develop
willfarrell Feb 24, 2026
bf5bbb9
chore: improve types
willfarrell Feb 25, 2026
b892b86
feat: add in missin gtypes
willfarrell Feb 25, 2026
0941336
fix: http status codes
willfarrell Feb 25, 2026
abefbac
feat: update in missing types
willfarrell Feb 25, 2026
310ef8b
fix: improve tests and types
willfarrell Feb 25, 2026
c8e9fd2
chore: more type clean up
willfarrell Feb 25, 2026
8e63f35
test: improve testing name patterns
willfarrell Feb 25, 2026
6c01568
chore: clean up test naming
willfarrell Feb 25, 2026
f7da36a
chore: clean up tests naming
willfarrell Feb 25, 2026
336dbaa
test: add in more type tests
willfarrell Feb 25, 2026
99abc48
test: bump testing up to 100%
willfarrell Feb 25, 2026
a527008
chore: remove gitHead
willfarrell Feb 25, 2026
6a59f7d
chore: more clean up
willfarrell Feb 25, 2026
221c03b
fix: small perf boost
willfarrell Feb 25, 2026
e424b5d
docs: typo
willfarrell Feb 25, 2026
bad733c
chore: clean up
willfarrell Feb 25, 2026
ce763cd
chore: pref improvements
willfarrell Feb 26, 2026
fde400f
chore: lint
willfarrell Feb 26, 2026
c172783
chore: add in missing dep
willfarrell Feb 26, 2026
fa5d737
fix: small perf improvement
willfarrell Feb 26, 2026
9d97cc2
fix: small perf improvements
willfarrell Feb 26, 2026
2374031
test: fix undefined
willfarrell Feb 26, 2026
7787f7a
chore: small perf improvements
willfarrell Feb 26, 2026
7c9cd1f
docs: improve code coverage
willfarrell Feb 26, 2026
f73de7c
chore: small perf improvements
willfarrell Feb 26, 2026
d910713
fix: validator regression
willfarrell Mar 3, 2026
6894646
docs: update to match current types
willfarrell Mar 3, 2026
701dc93
chore: dep update
willfarrell Mar 3, 2026
dc8305a
Merge branch 'main' into develop
willfarrell Mar 3, 2026
bc2e9ee
chore: version bump
willfarrell Mar 3, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
chore: small perf improvements
Signed-off-by: will Farrell <willfarrell@proton.me>
  • Loading branch information
willfarrell committed Feb 26, 2026
commit 7787f7af941b784dad8be3d311e99e58fd5328a7
5 changes: 3 additions & 2 deletions packages/appconfig/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,10 @@ const appConfigMiddleware = (opts = {}) => {
});
}

const fetchDataKeys = Object.keys(options.fetchData);
const fetchRequest = (request, cachedValues = {}) => {
const values = {};
for (const internalKey of Object.keys(options.fetchData)) {
for (const internalKey of fetchDataKeys) {
if (cachedValues[internalKey]) continue;
if (typeof configurationTokenCache[internalKey] === "undefined") {
const command = new StartConfigurationSessionCommand(
Expand Down Expand Up @@ -113,7 +114,7 @@ const appConfigMiddleware = (opts = {}) => {
const { value } = processCache(options, fetchRequest, request);
Object.assign(request.internal, value);
if (options.setToContext) {
const data = await getInternal(Object.keys(options.fetchData), request);
const data = await getInternal(fetchDataKeys, request);
Object.assign(request.context, data);
}
};
Expand Down
10 changes: 5 additions & 5 deletions packages/core/executionModeDurableContext.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const executionModeDurableContext = (
) => {
const middy = withDurableExecution(async (event, context) => {
const request = middyRequest(event, context);
plugin.requestStart?.(request);
plugin.requestStart(request);

// normalize context with executionModeStandard
// https://docs.aws.amazon.com/lambda/latest/dg/typescript-context.html
Expand All @@ -33,7 +33,7 @@ export const executionModeDurableContext = (
onErrorMiddlewares,
plugin,
);
await plugin.requestEnd?.(request);
await plugin.requestEnd(request);
return response;
});
middy.handler = (replaceLambdaHandler) => {
Expand All @@ -44,7 +44,7 @@ export const executionModeDurableContext = (
};

const copyKeys = (to, from, keys) => {
keys.forEach((key) => {
to[key] = from[key];
});
for (let i = 0, len = keys.length; i < len; i++) {
to[keys[i]] = from[keys[i]];
}
};
4 changes: 2 additions & 2 deletions packages/core/executionModeStandard.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const executionModeStandard = (
) => {
const middy = async (event, context) => {
const request = middyRequest(event, context);
plugin.requestStart?.(request);
plugin.requestStart(request);

const response = await runRequest(
request,
Expand All @@ -20,7 +20,7 @@ export const executionModeStandard = (
onErrorMiddlewares,
plugin,
);
await plugin.requestEnd?.(request);
await plugin.requestEnd(request);
return response;
};
middy.handler = (replaceLambdaHandler) => {
Expand Down
4 changes: 2 additions & 2 deletions packages/core/executionModeStreamifyResponse.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export const executionModeStreamifyResponse = (
const middy = awslambda.streamifyResponse(
async (event, lambdaResponseStream, context) => {
const request = middyRequest(event, context);
plugin.requestStart?.(request);
plugin.requestStart(request);
const handlerResponse = await runRequest(
request,
beforeMiddlewares,
Expand Down Expand Up @@ -55,7 +55,7 @@ export const executionModeStreamifyResponse = (
}

await pipeline(handlerStream, responseStream);
await plugin.requestEnd?.(request);
await plugin.requestEnd(request);
},
);

Expand Down
19 changes: 14 additions & 5 deletions packages/core/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { setTimeout } from "node:timers";
import { executionModeStandard } from "./executionModeStandard.js";

const defaultLambdaHandler = () => {};
const noop = () => {};
const defaultPluginConfig = {
timeoutEarlyInMillis: 5,
timeoutEarlyResponse: () => {
Expand All @@ -29,6 +30,14 @@ export const middy = (setupLambdaHandler, pluginConfig) => {
}
plugin.timeoutEarly = plugin.timeoutEarlyInMillis > 0;

// Pre-compute single-call plugin hooks as noop to avoid optional chaining
// Note: beforeMiddleware/afterMiddleware kept as optional chaining in runMiddlewares
// because V8 optimizes ?.() null-checks faster than noop calls in tight loops
plugin.requestStart ??= noop;
plugin.requestEnd ??= noop;
plugin.beforeHandler ??= noop;
plugin.afterHandler ??= noop;

plugin.beforePrefetch?.();
const beforeMiddlewares = [];
const afterMiddlewares = [];
Expand Down Expand Up @@ -115,7 +124,7 @@ const runRequest = async (

// Check if before stack hasn't exit early
if (!Object.hasOwn(request, "earlyResponse")) {
plugin.beforeHandler?.();
plugin.beforeHandler();

// Can't manually abort and timeout with same AbortSignal
// https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/timeout_static
Expand Down Expand Up @@ -154,7 +163,7 @@ const runRequest = async (
clearTimeout(timeoutID);
}

plugin.afterHandler?.();
plugin.afterHandler();
await runMiddlewares(request, afterMiddlewares, plugin);
}
} catch (err) {
Expand Down Expand Up @@ -182,11 +191,11 @@ const runRequest = async (
return request.response;
};

const runMiddlewares = async (request, middlewares, pluginConfig) => {
const runMiddlewares = async (request, middlewares, plugin) => {
for (const nextMiddleware of middlewares) {
pluginConfig.beforeMiddleware?.(nextMiddleware.name);
plugin.beforeMiddleware?.(nextMiddleware.name);
const res = await nextMiddleware(request);
pluginConfig.afterMiddleware?.(nextMiddleware.name);
plugin.afterMiddleware?.(nextMiddleware.name);
// short circuit chaining and respond early
if (typeof res !== "undefined") {
request.earlyResponse = res;
Expand Down
7 changes: 4 additions & 3 deletions packages/dynamodb/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,17 @@ const dynamodbMiddleware = (opts = {}) => {
fetchData: structuredClone({ ...defaults.fetchData, ...opts.fetchData }),
};

const fetchDataKeys = Object.keys(options.fetchData);
// force marshall of Key during cold start
for (const internalKey of Object.keys(options.fetchData)) {
for (const internalKey of fetchDataKeys) {
options.fetchData[internalKey].Key = marshall(
options.fetchData[internalKey].Key,
);
}

const fetchRequest = (request, cachedValues = {}) => {
const values = {};
for (const internalKey of Object.keys(options.fetchData)) {
for (const internalKey of fetchDataKeys) {
if (cachedValues[internalKey]) continue;
const inputParameters = options.fetchData[internalKey];
const command = new GetItemCommand(inputParameters);
Expand Down Expand Up @@ -71,7 +72,7 @@ const dynamodbMiddleware = (opts = {}) => {
const { value } = processCache(options, fetchRequest, request);
Object.assign(request.internal, value);
if (options.setToContext) {
const data = await getInternal(Object.keys(options.fetchData), request);
const data = await getInternal(fetchDataKeys, request);
Object.assign(request.context, data);
}
};
Expand Down
36 changes: 21 additions & 15 deletions packages/http-content-encoding/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@ import { Readable } from "node:stream";
import { ReadableStream } from "node:stream/web";
import {
createBrotliCompress as brotliCompressStream,
brotliCompressSync,
createDeflate as deflateCompressStream,
deflateSync,
createGzip as gzipCompressStream,
gzipSync,
createZstdCompress as zstdCompressStream,
zstdCompressSync,
} from "node:zlib";
import { normalizeHttpResponse } from "@middy/util";

Expand All @@ -18,6 +22,13 @@ const contentEncodingStreams = {
zstd: zstdCompressStream,
};

const contentEncodingSync = {
br: brotliCompressSync,
deflate: deflateSync,
gzip: gzipSync,
zstd: zstdCompressSync,
};

const defaults = {
br: undefined,
deflate: undefined,
Expand Down Expand Up @@ -67,21 +78,19 @@ const httpContentEncodingMiddleware = (opts = {}) => {
return;
}

let contentEncodingStream = contentEncodingStreams[preferredEncoding](
options[preferredEncoding],
);
// Resolve encoding choice before creating any stream
let contentEncoding = preferredEncoding;
for (const encoding of options.overridePreferredEncoding) {
if (!preferredEncodings.includes(encoding)) continue;
contentEncodingStream = contentEncodingStreams[encoding](
options[encoding],
);
contentEncoding = encoding;
break;
}

// Support streamifyResponse
if (isNodeStream || isWebStream) {
const contentEncodingStream = contentEncodingStreams[contentEncoding](
options[contentEncoding],
);
request.response.headers["Content-Encoding"] = contentEncoding;
if (isNodeStream) {
request.response.body = request.response.body.pipe(
Expand All @@ -95,15 +104,12 @@ const httpContentEncodingMiddleware = (opts = {}) => {
addHeaderPart(response, "Vary", "Accept-Encoding");
return;
}
// isString
const stream = Readable.from(response.body).pipe(contentEncodingStream);

const chunks = [];
for await (const chunk of stream) {
chunks.push(chunk);
}

const body = Buffer.concat(chunks).toString("base64");
// isString/isBuffer — use sync compression (avoids stream overhead)
const inputBuffer = Buffer.isBuffer(response.body)
? response.body
: Buffer.from(response.body);
const compressed = contentEncodingSync[contentEncoding](inputBuffer);
const body = compressed.toString("base64");

// Only apply encoding if it's smaller
if (body.length < response.body.length) {
Expand Down
5 changes: 3 additions & 2 deletions packages/rds-signer/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,10 @@ const defaults = {
const rdsSignerMiddleware = (opts = {}) => {
const options = { ...defaults, ...opts };

const fetchDataKeys = Object.keys(options.fetchData);
const fetchRequest = (request, cachedValues = {}) => {
const values = {};
for (const internalKey of Object.keys(options.fetchData)) {
for (const internalKey of fetchDataKeys) {
if (cachedValues[internalKey]) continue;

const client = new options.AwsClient({
Expand Down Expand Up @@ -64,7 +65,7 @@ const rdsSignerMiddleware = (opts = {}) => {
Object.assign(request.internal, value);

if (options.setToContext) {
const data = await getInternal(Object.keys(options.fetchData), request);
const data = await getInternal(fetchDataKeys, request);
Object.assign(request.context, data);
}
};
Expand Down
5 changes: 3 additions & 2 deletions packages/s3/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,10 @@ const s3Middleware = (opts = {}) => {
...defaults,
...opts,
};
const fetchDataKeys = Object.keys(options.fetchData);
const fetchRequest = (request, cachedValues = {}) => {
const values = {};
for (const internalKey of Object.keys(options.fetchData)) {
for (const internalKey of fetchDataKeys) {
if (cachedValues[internalKey]) continue;
const command = new GetObjectCommand(options.fetchData[internalKey]);
values[internalKey] = client
Expand Down Expand Up @@ -67,7 +68,7 @@ const s3Middleware = (opts = {}) => {
const { value } = processCache(options, fetchRequest, request);
Object.assign(request.internal, value);
if (options.setToContext) {
const data = await getInternal(Object.keys(options.fetchData), request);
const data = await getInternal(fetchDataKeys, request);
Object.assign(request.context, data);
}
};
Expand Down
5 changes: 3 additions & 2 deletions packages/secrets-manager/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,11 @@ const secretsManagerMiddleware = (opts = {}) => {
cacheKeyExpiry: { ...defaults.cacheKeyExpiry, ...opts.cacheKeyExpiry },
};

const fetchDataKeys = Object.keys(options.fetchData);
const fetchRequest = (request, cachedValues = {}) => {
const values = {};

for (const internalKey of Object.keys(options.fetchData)) {
for (const internalKey of fetchDataKeys) {
if (cachedValues[internalKey]) continue;

const fetchRotation =
Expand Down Expand Up @@ -115,7 +116,7 @@ const secretsManagerMiddleware = (opts = {}) => {
Object.assign(request.internal, value);

if (options.setToContext) {
const data = await getInternal(Object.keys(options.fetchData), request);
const data = await getInternal(fetchDataKeys, request);
Object.assign(request.context, data);
}
};
Expand Down
5 changes: 3 additions & 2 deletions packages/service-discovery/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@ const defaults = {
const serviceDiscoveryMiddleware = (opts = {}) => {
const options = { ...defaults, ...opts };

const fetchDataKeys = Object.keys(options.fetchData);
const fetchRequest = (request, cachedValues = {}) => {
const values = {};

for (const internalKey of Object.keys(options.fetchData)) {
for (const internalKey of fetchDataKeys) {
if (cachedValues[internalKey]) continue;

const command = new DiscoverInstancesCommand(
Expand Down Expand Up @@ -71,7 +72,7 @@ const serviceDiscoveryMiddleware = (opts = {}) => {
Object.assign(request.internal, value);

if (options.setToContext) {
const data = await getInternal(Object.keys(options.fetchData), request);
const data = await getInternal(fetchDataKeys, request);
Object.assign(request.context, data);
}
};
Expand Down
17 changes: 9 additions & 8 deletions packages/ssm/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,12 @@ const defaults = {
const ssmMiddleware = (opts = {}) => {
const options = { ...defaults, ...opts };

const fetchDataKeys = Object.keys(options.fetchData);
const fetchDataValues = Object.values(options.fetchData);
const fetchRequest = (request, cachedValues) => {
return {
...fetchSingleRequest(request, cachedValues),
...fetchByPathRequest(request, cachedValues),
};
const single = fetchSingleRequest(request, cachedValues);
const path = fetchByPathRequest(request, cachedValues);
return Object.assign(single, path);
};

const fetchSingleRequest = (request, cachedValues = {}) => {
Expand All @@ -48,8 +49,8 @@ const ssmMiddleware = (opts = {}) => {
const batchKeys = new Map();
const namedKeys = [];

const internalKeys = Object.keys(options.fetchData);
const fetchKeys = Object.values(options.fetchData);
const internalKeys = fetchDataKeys;
const fetchKeys = fetchDataValues;
for (const internalKey of internalKeys) {
if (cachedValues[internalKey]) continue;
if (options.fetchData[internalKey].endsWith("/")) continue; // Skip path passed in
Expand Down Expand Up @@ -124,7 +125,7 @@ const ssmMiddleware = (opts = {}) => {

const fetchByPathRequest = (request, cachedValues = {}) => {
const values = {};
for (const internalKey of Object.keys(options.fetchData)) {
for (const internalKey of fetchDataKeys) {
if (cachedValues[internalKey]) continue;
const fetchKey = options.fetchData[internalKey];
if (!fetchKey.endsWith("/")) continue; // Skip not path passed in
Expand Down Expand Up @@ -182,7 +183,7 @@ const ssmMiddleware = (opts = {}) => {
Object.assign(request.internal, value);

if (options.setToContext) {
const data = await getInternal(Object.keys(options.fetchData), request);
const data = await getInternal(fetchDataKeys, request);
Object.assign(request.context, data);
}
};
Expand Down
Loading