@middy/util 7.1.1 → 7.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/README.md +17 -0
  2. package/index.d.ts +25 -19
  3. package/index.js +55 -20
  4. package/package.json +3 -4
package/README.md CHANGED
@@ -30,6 +30,23 @@
30
30
  <p>You can read the documentation at: <a href="https://middy.js.org/docs/intro/utilities">https://middy.js.org/docs/intro/utilities</a></p>
31
31
  </div>
32
32
 
33
+ ## Install
34
+
35
+ ```bash
36
+ npm install --save @middy/util
37
+ ```
38
+
39
+
40
+ ## Documentation and examples
41
+
42
+ For documentation and examples, refer to the main [Middy monorepo on GitHub](https://github.com/middyjs/middy) or [Middy official website](https://middy.js.org/docs/intro/utilities).
43
+
44
+
45
+ ## Contributing
46
+
47
+ Everyone is very welcome to contribute to this repository. Feel free to [raise issues](https://github.com/middyjs/middy/issues) or to [submit Pull Requests](https://github.com/middyjs/middy/pulls).
48
+
49
+
33
50
  ## License
34
51
 
35
52
  Licensed under [MIT License](LICENSE). Copyright (c) 2017-2026 [will Farrell](https://github.com/willfarrell), [Luciano Mammino](https://github.com/lmammino), and [Middy contributors](https://github.com/middyjs/middy/graphs/contributors).
package/index.d.ts CHANGED
@@ -12,7 +12,7 @@ import type {
12
12
  } from "./type-utils.d.ts";
13
13
 
14
14
  export interface Options<Client, ClientOptions> {
15
- AwsClient?: new (...[config]: [any] | any) => Client;
15
+ AwsClient?: new (config: ClientOptions) => Client;
16
16
  awsClientOptions?: Partial<ClientOptions>;
17
17
  awsClientAssumeRole?: string;
18
18
  awsClientCapture?: (service: Client) => Client;
@@ -20,6 +20,7 @@ export interface Options<Client, ClientOptions> {
20
20
  disablePrefetch?: boolean;
21
21
  cacheKey?: string;
22
22
  cacheExpiry?: number;
23
+ cacheKeyExpiry?: Record<string, number>;
23
24
  setToContext?: boolean;
24
25
  }
25
26
 
@@ -27,8 +28,8 @@ export declare class HttpError extends Error {
27
28
  status: number;
28
29
  statusCode: number;
29
30
  expose: boolean;
30
- [key: string]: any;
31
- [key: number]: any;
31
+ [key: string]: unknown;
32
+ [key: number]: unknown;
32
33
  }
33
34
 
34
35
  declare function createPrefetchClient<Client, ClientOptions>(
@@ -118,43 +119,48 @@ declare function sanitizeKey<T extends string>(key: T): SanitizeKey<T>;
118
119
 
119
120
  declare function processCache<Client, ClientOptions>(
120
121
  options: Options<Client, ClientOptions>,
121
- fetch: (request: middy.Request, cachedValues: any) => any,
122
+ fetch: (request: middy.Request, cachedValues: unknown) => unknown,
122
123
  request?: middy.Request,
123
- ): { value: any; expiry: number };
124
+ ): { value: unknown; expiry: number };
124
125
 
125
- declare function getCache(keys: string): any;
126
+ declare function getCache(keys: string): unknown;
126
127
 
127
128
  declare function clearCache(keys?: string | string[] | null): void;
128
129
 
129
130
  declare function jsonSafeParse(
130
131
  string: string,
131
- reviver?: (key: string, value: any) => any,
132
- ): any;
132
+ reviver?: (key: string, value: unknown) => unknown,
133
+ ): unknown;
133
134
 
134
135
  declare function normalizeHttpResponse(
135
- request: any,
136
- fallbackResponse?: any,
137
- ): any;
136
+ request: middy.Request,
137
+ fallbackResponse?: Record<string, unknown>,
138
+ ): Record<string, unknown>;
138
139
 
139
140
  declare function createError(
140
141
  code: number,
141
142
  message: string,
142
- properties?: Record<string, any>,
143
+ properties?: Record<string, unknown>,
143
144
  ): HttpError;
144
145
 
145
- declare function modifyCache(cacheKey: string, value: any): void;
146
+ declare function modifyCache(cacheKey: string, value: unknown): void;
146
147
 
147
148
  declare function catchInvalidSignatureException<Client, Command>(
148
149
  e: Error & { __type?: string },
149
150
  client: Client,
150
151
  command: Command,
151
- ): Promise<any>;
152
+ ): Promise<unknown>;
152
153
 
153
154
  declare function jsonSafeStringify(
154
- value: any,
155
- replacer?: (key: string, value: any) => any,
155
+ value: unknown,
156
+ replacer?: (key: string, value: unknown) => unknown,
156
157
  space?: string | number,
157
- ): string | any;
158
+ ): string | unknown;
159
+
160
+ declare function decodeBody(event: {
161
+ body?: string | null;
162
+ isBase64Encoded?: boolean;
163
+ }): string | null | undefined;
158
164
 
159
165
  declare const lambdaContextKeys: string[];
160
166
 
@@ -166,12 +172,12 @@ declare function executionContext(
166
172
  request: middy.Request,
167
173
  key: string,
168
174
  context: LambdaContext,
169
- ): any;
175
+ ): unknown;
170
176
 
171
177
  declare function lambdaContext(
172
178
  request: middy.Request,
173
179
  key: string,
174
180
  context: LambdaContext,
175
- ): any;
181
+ ): unknown;
176
182
 
177
183
  declare const httpErrorCodes: Record<number, string>;
package/index.js CHANGED
@@ -61,6 +61,36 @@ export const getInternal = async (variables, request) => {
61
61
  keys = Object.keys(variables);
62
62
  values = Object.values(variables);
63
63
  }
64
+ // Fast synchronous path: when all internal values are already resolved
65
+ // (warm/cached invocations), skip all Promise machinery entirely
66
+ let allSync = true;
67
+ const syncResults = new Array(values.length);
68
+ for (let i = 0; i < values.length; i++) {
69
+ const internalKey = values[i];
70
+ const dotIndex = internalKey.indexOf(".");
71
+ const rootKey =
72
+ dotIndex === -1 ? internalKey : internalKey.substring(0, dotIndex);
73
+ let value = request.internal[rootKey];
74
+ if (isPromise(value)) {
75
+ allSync = false;
76
+ break;
77
+ }
78
+ if (dotIndex !== -1) {
79
+ for (const part of internalKey.substring(dotIndex + 1).split(".")) {
80
+ value = value?.[part];
81
+ }
82
+ }
83
+ syncResults[i] = value;
84
+ }
85
+ if (allSync) {
86
+ const obj = {};
87
+ for (let i = 0; i < keys.length; i++) {
88
+ obj[sanitizeKey(keys[i])] = syncResults[i];
89
+ }
90
+ return obj;
91
+ }
92
+
93
+ // Async fallback: for cold/first invocations with pending promises
64
94
  const promises = [];
65
95
  for (const internalKey of values) {
66
96
  // 'internal.key.sub_value' -> { [key]: internal.key.sub_value }
@@ -79,18 +109,21 @@ export const getInternal = async (variables, request) => {
79
109
  // ensure promise has resolved by the time it's needed
80
110
  // If one of the promises throws it will bubble up to @middy/core
81
111
  values = await Promise.allSettled(promises);
82
- const errors = values
83
- .filter((res) => res.status === "rejected")
84
- .map((res) => res.reason);
85
- if (errors.length) {
112
+ const obj = {};
113
+ let errors;
114
+ for (let i = 0; i < keys.length; i++) {
115
+ if (values[i].status === "rejected") {
116
+ errors ??= [];
117
+ errors.push(values[i].reason);
118
+ } else {
119
+ obj[sanitizeKey(keys[i])] = values[i].value;
120
+ }
121
+ }
122
+ if (errors) {
86
123
  throw new Error("Failed to resolve internal values", {
87
124
  cause: { package: "@middy/util", data: errors },
88
125
  });
89
126
  }
90
- const obj = {};
91
- for (let i = keys.length; i--; ) {
92
- obj[sanitizeKey(keys[i])] = values[i].value;
93
- }
94
127
  return obj;
95
128
  };
96
129
 
@@ -125,7 +158,8 @@ export const processCache = (
125
158
  cache[cacheKey] = { value: cached.value, expiry: cached.expiry };
126
159
  return cache[cacheKey];
127
160
  }
128
- return { ...cached, cache: true };
161
+ cached.cache = true;
162
+ return cached;
129
163
  }
130
164
  }
131
165
  const value = middlewareFetch(middlewareFetchRequest);
@@ -161,8 +195,9 @@ export const getCache = (key) => {
161
195
  // Used to remove parts of a cache
162
196
  export const modifyCache = (cacheKey, value) => {
163
197
  if (!cache[cacheKey]) return;
164
- clearTimeout(cache[cacheKey]?.refresh);
165
- cache[cacheKey] = { ...cache[cacheKey], value, modified: true };
198
+ clearTimeout(cache[cacheKey].refresh);
199
+ cache[cacheKey].value = value;
200
+ cache[cacheKey].modified = true;
166
201
  };
167
202
 
168
203
  export const clearCache = (inputKeys = null) => {
@@ -192,18 +227,12 @@ export const lambdaContextKeys = [
192
227
  "callbackWaitsForEmptyEventLoop",
193
228
  ];
194
229
 
195
- export const executionContextKeys = [
196
- //'requestId',
197
- "tenantId",
198
- ];
230
+ export const executionContextKeys = ["tenantId"];
199
231
 
200
232
  export const isExecutionModeDurable = (context) => {
201
233
  // using `context instanceof DurableContextImpl` would be better
202
234
  // but would require an extra dependency
203
- if (context.constructor.name === "DurableContextImpl") {
204
- return true;
205
- }
206
- return false;
235
+ return context.constructor.name === "DurableContextImpl";
207
236
  };
208
237
 
209
238
  export const executionContext = (request, key, context) => {
@@ -239,6 +268,12 @@ export const jsonSafeStringify = (value, replacer, space) => {
239
268
  }
240
269
  };
241
270
 
271
+ export const decodeBody = (event) => {
272
+ const { body, isBase64Encoded } = event;
273
+ if (typeof body === "undefined" || body === null) return body;
274
+ return isBase64Encoded ? Buffer.from(body, "base64").toString() : body;
275
+ };
276
+
242
277
  export const normalizeHttpResponse = (request) => {
243
278
  let { response } = request;
244
279
  if (typeof response === "undefined") {
@@ -280,7 +315,7 @@ export const createError = (code, message, properties = {}) => {
280
315
  return new HttpError(code, message, properties);
281
316
  };
282
317
 
283
- const httpErrorCodes = {
318
+ export const httpErrorCodes = {
284
319
  100: "Continue",
285
320
  101: "Switching Protocols",
286
321
  102: "Processing",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@middy/util",
3
- "version": "7.1.1",
3
+ "version": "7.1.3",
4
4
  "description": "🛵 The stylish Node.js middleware engine for AWS Lambda (util package)",
5
5
  "type": "module",
6
6
  "engines": {
@@ -60,7 +60,7 @@
60
60
  },
61
61
  "devDependencies": {
62
62
  "@aws-sdk/client-ssm": "^3.0.0",
63
- "@middy/core": "7.1.1",
63
+ "@middy/core": "7.1.3",
64
64
  "@types/aws-lambda": "^8.0.0",
65
65
  "@types/node": "^22.0.0",
66
66
  "aws-xray-sdk": "^3.3.3"
@@ -69,6 +69,5 @@
69
69
  "funding": {
70
70
  "type": "github",
71
71
  "url": "https://github.com/sponsors/willfarrell"
72
- },
73
- "gitHead": "7a6c0fbb8ab71d6a2171e678697de9f237568431"
72
+ }
74
73
  }