From d47badbda24bb4540c767046049867e07815d542 Mon Sep 17 00:00:00 2001 From: will Farrell Date: Fri, 13 Dec 2024 09:29:30 -0700 Subject: [PATCH 01/14] feat: add in new router Closes #1260 --- packages/cloudformation-router/README.md | 46 +++++++++++ packages/cloudformation-router/index.js | 52 ++++++++++++ packages/cloudformation-router/package.json | 73 +++++++++++++++++ website/docs/routers/cloudformation-router.md | 79 +++++++++++++++++++ 4 files changed, 250 insertions(+) create mode 100644 packages/cloudformation-router/README.md create mode 100644 packages/cloudformation-router/index.js create mode 100644 packages/cloudformation-router/package.json create mode 100644 website/docs/routers/cloudformation-router.md diff --git a/packages/cloudformation-router/README.md b/packages/cloudformation-router/README.md new file mode 100644 index 000000000..2a10c20e9 --- /dev/null +++ b/packages/cloudformation-router/README.md @@ -0,0 +1,46 @@ +
+

Middy cloudformation-router lambda handler

+ Middy logo +

CloudFormation Custom Response router for the middy framework, the stylish Node.js middleware engine for AWS Lambda

+

+ + npm version + + + npm install size + + + GitHub Actions CI status badge + +
+ + Standard Code Style + + + Known Vulnerabilities + + + CodeQL + + + Core Infrastructure Initiative (CII) Best Practices + +
+ + Chat on Gitter + + + Ask questions on StackOverflow + +

+

You can read the documentation at: https://middy.js.org/docs/routers/cloudformation-router

+
+ +## License + +Licensed under [MIT License](LICENSE). Copyright (c) 2017-2024 [Luciano Mammino](https://github.com/lmammino), [will Farrell](https://github.com/willfarrell), and the [Middy team](https://github.com/middyjs/middy/graphs/contributors). + + + FOSSA Status + diff --git a/packages/cloudformation-router/index.js b/packages/cloudformation-router/index.js new file mode 100644 index 000000000..25680b5d8 --- /dev/null +++ b/packages/cloudformation-router/index.js @@ -0,0 +1,52 @@ +import { createError } from '@middy/util' +const defaults = { + routes: [], + notFoundResponse: ({ requestType }) => { + const err = createError(404, 'Route does not exist', { + cause: { + package: '@middy/cloudformation-router', + data: { requestType } + } + }) + throw err + } +} +const cloudformationCustomResourceRouteHandler = (opts = {}) => { + if (Array.isArray(opts)) { + opts = { routes: opts } + } + const { routes, notFoundResponse } = { ...defaults, ...opts } + + const routesStatic = {} + for (const route of routes) { + const { requestType, handler } = route + + // Static + routesStatic[requestType] = handler + } + + return (event, context, abort) => { + const { RequestType: requestType } = event + if (!requestType) { + throw new Error('Unknown CloudFormation event format', { + cause: { package: '@middy/cloudformation-router' } + }) + } + + // Static + const handler = routesStatic[requestType] + if (typeof handler !== 'undefined') { + const response = handler(event, context, abort) + response.Status ??= 'SUCCESS' + response.RequestId ??= event.RequestId + response.LogicalResourceId ??= event.LogicalResourceId + response.StackId ??= event.StackId + return response + } + + // Not Found + return notFoundResponse({ requestType }) + } +} + +export default cloudformationCustomResourceRouteHandler diff --git a/packages/cloudformation-router/package.json b/packages/cloudformation-router/package.json new file mode 100644 index 000000000..a3ce24a62 --- /dev/null +++ b/packages/cloudformation-router/package.json @@ -0,0 +1,73 @@ +{ + "name": "@middy/cloudformation-router", + "version": "6.0.0", + "description": "CloudFormation Custom Response event router for the middy framework", + "type": "module", + "engines": { + "node": ">=20" + }, + "engineStrict": true, + "publishConfig": { + "access": "public" + }, + "module": "./index.js", + "exports": { + ".": { + "import": { + "types": "./index.d.ts", + "default": "./index.js" + }, + "require": { + "default": "./index.js" + } + } + }, + "types": "index.d.ts", + "files": [ + "index.js", + "index.d.ts" + ], + "scripts": { + "test": "npm run test:unit", + "test:unit": "node --test __tests__/index.js", + "test:benchmark": "node __benchmarks__/index.js" + }, + "license": "MIT", + "keywords": [ + "Lambda", + "Middleware", + "Serverless", + "Framework", + "AWS", + "AWS Lambda", + "Middy", + "CloudFormation", + "Custom Response", + "router" + ], + "author": { + "name": "Middy contributors", + "url": "https://github.com/middyjs/middy/graphs/contributors" + }, + "repository": { + "type": "git", + "url": "github:middyjs/middy", + "directory": "packages/cloudformation-router" + }, + "bugs": { + "url": "https://github.com/middyjs/middy/issues" + }, + "homepage": "https://middy.js.org", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/willfarrell" + }, + "dependencies": { + "@middy/util": "6.0.0" + }, + "devDependencies": { + "@middy/core": "6.0.0", + "@types/aws-lambda": "^8.10.100" + }, + "gitHead": "7a6c0fbb8ab71d6a2171e678697de9f237568431" +} diff --git a/website/docs/routers/cloudformation-router.md b/website/docs/routers/cloudformation-router.md new file mode 100644 index 000000000..424751a22 --- /dev/null +++ b/website/docs/routers/cloudformation-router.md @@ -0,0 +1,79 @@ +--- +title: cloudformation-router +--- + +This handler can route to requests to one of a nested handler based on `requestType` of a CloudFormation Custom Response event. + +## Install + +To install this middleware you can use NPM: + +```bash +npm install --save @middy/cloudformation-router +``` + +## Options + +- `routes` (array[\{routeKey, handler\}]) (required): Array of route objects. + - `routeKey` (string) (required): AWS formatted request type. ie `Create`, `Update`, `Delete` + - `handler` (function) (required): Any `handler(event, context, {signal})` function +- `notFoundHandler` (function): Override default 404 error thrown with your own custom response. Passes in `{requestType}` + +NOTES: + +- Reponse parameters are automatically applied for `Status`, `RequestId`, `LogicalResourceId`, and/or `StackId` when not present. +- Errors should be handled as part of the router middleware stack **or** the lambdaHandler middleware stack. Handled errors in the later will trigger the `after` middleware stack of the former. +- Shared middlewares, connected to the router middleware stack, can only be run before the lambdaHandler middleware stack. + +## Sample usage + +```javascript +import middy from '@middy/core' +import cloudformationRouterHandler from '@middy/cloudformation-router' +import validatorMiddleware from '@middy/validator' + +const createHandler = middy() + .use(validatorMiddleware({eventSchema: {...} })) + .handler((event, context) => { + return { + PhysicalResourceId: '...', + Data:{} + } + }) + +const updateHandler = middy() + .use(validatorMiddleware({eventSchema: {...} })) + .handler((event, context) => { + return { + PhysicalResourceId: '...', + Data: {} + } + }) + +const deleteHandler = middy() + .use(validatorMiddleware({eventSchema: {...} })) + .handler((event, context) => { + return { + PhysicalResourceId: '...' + } + }) + +const routes = [ + { + requesType: 'Create', + handler: createHandler + }, + { + requesType: 'Update', + handler: updateHandler + }, + { + routeKey: 'delete', + handler: deleteHandler + } +] + +export const handler = middy() + .use(wsResponseMiddleware()) + .handler(cloudformationRouterHandler(routes)) +``` From 371d9a63c6483f658d1eb5165948c97b532fb181 Mon Sep 17 00:00:00 2001 From: will Farrell Date: Fri, 13 Dec 2024 09:41:44 -0700 Subject: [PATCH 02/14] feat: update error response --- packages/cloudformation-router/index.js | 3 +-- packages/cloudformation-router/package.json | 3 --- website/docs/routers/cloudformation-router.md | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/cloudformation-router/index.js b/packages/cloudformation-router/index.js index 25680b5d8..2196473cc 100644 --- a/packages/cloudformation-router/index.js +++ b/packages/cloudformation-router/index.js @@ -1,8 +1,7 @@ -import { createError } from '@middy/util' const defaults = { routes: [], notFoundResponse: ({ requestType }) => { - const err = createError(404, 'Route does not exist', { + const err = new Error('Route does not exist', { cause: { package: '@middy/cloudformation-router', data: { requestType } diff --git a/packages/cloudformation-router/package.json b/packages/cloudformation-router/package.json index a3ce24a62..095be145f 100644 --- a/packages/cloudformation-router/package.json +++ b/packages/cloudformation-router/package.json @@ -62,9 +62,6 @@ "type": "github", "url": "https://github.com/sponsors/willfarrell" }, - "dependencies": { - "@middy/util": "6.0.0" - }, "devDependencies": { "@middy/core": "6.0.0", "@types/aws-lambda": "^8.10.100" diff --git a/website/docs/routers/cloudformation-router.md b/website/docs/routers/cloudformation-router.md index 424751a22..0fe5f2bd0 100644 --- a/website/docs/routers/cloudformation-router.md +++ b/website/docs/routers/cloudformation-router.md @@ -17,7 +17,7 @@ npm install --save @middy/cloudformation-router - `routes` (array[\{routeKey, handler\}]) (required): Array of route objects. - `routeKey` (string) (required): AWS formatted request type. ie `Create`, `Update`, `Delete` - `handler` (function) (required): Any `handler(event, context, {signal})` function -- `notFoundHandler` (function): Override default 404 error thrown with your own custom response. Passes in `{requestType}` +- `notFoundHandler` (function): Override default error thrown with your own custom response. Passes in `{requestType}` NOTES: From 1c2eaaa351c6cf599c713f0fa1b65ddf3dac3385 Mon Sep 17 00:00:00 2001 From: will Farrell Date: Fri, 13 Dec 2024 09:46:55 -0700 Subject: [PATCH 03/14] feat: update response to use FAILED --- packages/cloudformation-router/index.js | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/packages/cloudformation-router/index.js b/packages/cloudformation-router/index.js index 2196473cc..84fcc4755 100644 --- a/packages/cloudformation-router/index.js +++ b/packages/cloudformation-router/index.js @@ -1,13 +1,10 @@ const defaults = { routes: [], notFoundResponse: ({ requestType }) => { - const err = new Error('Route does not exist', { - cause: { - package: '@middy/cloudformation-router', - data: { requestType } - } - }) - throw err + return { + Status: 'FAILED', + Reason: `Route ${requestType} does not exist. @middy/cloudformation-router` + } } } const cloudformationCustomResourceRouteHandler = (opts = {}) => { @@ -27,9 +24,7 @@ const cloudformationCustomResourceRouteHandler = (opts = {}) => { return (event, context, abort) => { const { RequestType: requestType } = event if (!requestType) { - throw new Error('Unknown CloudFormation event format', { - cause: { package: '@middy/cloudformation-router' } - }) + return notFoundResponse({ requestType }) } // Static From 65280c5d5f033337582e4bcb1913dc3570ef2fc2 Mon Sep 17 00:00:00 2001 From: will Farrell Date: Fri, 13 Dec 2024 10:28:53 -0700 Subject: [PATCH 04/14] Update website/docs/routers/cloudformation-router.md Co-authored-by: David Wells --- website/docs/routers/cloudformation-router.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/routers/cloudformation-router.md b/website/docs/routers/cloudformation-router.md index 0fe5f2bd0..f6016d52f 100644 --- a/website/docs/routers/cloudformation-router.md +++ b/website/docs/routers/cloudformation-router.md @@ -68,7 +68,7 @@ const routes = [ handler: updateHandler }, { - routeKey: 'delete', + routeKey: 'Delete', handler: deleteHandler } ] From 77c66b7b42fd8b5530a59e09ba22dd0e256f5efc Mon Sep 17 00:00:00 2001 From: will Farrell Date: Thu, 2 Jan 2025 17:19:44 -0700 Subject: [PATCH 05/14] feat: split into two pacakge to match ws pattern --- packages/cloudformation-response/README.md | 46 +++++++ .../cloudformation-response/__tests__/fuzz.js | 23 ++++ .../__tests__/index.js | 88 +++++++++++++ packages/cloudformation-response/index.js | 25 ++++ packages/cloudformation-response/package.json | 69 +++++++++++ .../cloudformation-router/__tests__/fuzz.js | 55 ++++++++ .../cloudformation-router/__tests__/index.js | 117 ++++++++++++++++++ packages/cloudformation-router/index.js | 39 +++--- website/docs/events/cloud-formation.md | 49 +++++++- .../middlewares/cloudformation-response.md | 34 +++++ website/docs/routers/cloudformation-router.md | 5 +- 11 files changed, 531 insertions(+), 19 deletions(-) create mode 100644 packages/cloudformation-response/README.md create mode 100644 packages/cloudformation-response/__tests__/fuzz.js create mode 100644 packages/cloudformation-response/__tests__/index.js create mode 100644 packages/cloudformation-response/index.js create mode 100644 packages/cloudformation-response/package.json create mode 100644 packages/cloudformation-router/__tests__/fuzz.js create mode 100644 packages/cloudformation-router/__tests__/index.js create mode 100644 website/docs/middlewares/cloudformation-response.md diff --git a/packages/cloudformation-response/README.md b/packages/cloudformation-response/README.md new file mode 100644 index 000000000..beb6620f2 --- /dev/null +++ b/packages/cloudformation-response/README.md @@ -0,0 +1,46 @@ +
+

Middy cloudformation lambda middleware

+ Middy logo +

CloudFormation Custom Response event response handling for the middy framework, the stylish Node.js middleware engine for AWS Lambda

+

+ + npm version + + + npm install size + + + GitHub Actions CI status badge + +
+ + Standard Code Style + + + Known Vulnerabilities + + + CodeQL + + + Core Infrastructure Initiative (CII) Best Practices + +
+ + Chat on Gitter + + + Ask questions on StackOverflow + +

+

You can read the documentation at: https://middy.js.org/docs/middleware/cloudformation-response

+
+ +## License + +Licensed under [MIT License](LICENSE). Copyright (c) 2017-2024 [Luciano Mammino](https://github.com/lmammino), [will Farrell](https://github.com/willfarrell), and the [Middy team](https://github.com/middyjs/middy/graphs/contributors). + + + FOSSA Status + diff --git a/packages/cloudformation-response/__tests__/fuzz.js b/packages/cloudformation-response/__tests__/fuzz.js new file mode 100644 index 000000000..f7cd82cd5 --- /dev/null +++ b/packages/cloudformation-response/__tests__/fuzz.js @@ -0,0 +1,23 @@ +import { test } from 'node:test' +import fc from 'fast-check' +import middy from '../../core/index.js' +import middleware from '../index.js' + +const handler = middy((event) => event).use(middleware({})) +const context = { + getRemainingTimeInMillis: () => 1000 +} + +test('fuzz `event` w/ `object`', async () => { + fc.assert( + fc.asyncProperty(fc.object(), async (event) => { + await handler(event, context) + }), + { + numRuns: 100_000, + verbose: 2, + + examples: [] + } + ) +}) diff --git a/packages/cloudformation-response/__tests__/index.js b/packages/cloudformation-response/__tests__/index.js new file mode 100644 index 000000000..9e6c46845 --- /dev/null +++ b/packages/cloudformation-response/__tests__/index.js @@ -0,0 +1,88 @@ +import { test } from 'node:test' +import { deepEqual } from 'node:assert/strict' + +import middy from '../../core/index.js' + +import cloudformationResponse from '../index.js' + +const defaultEvent = { + RequestType: 'Create', + RequestId: 'RequestId', + LogicalResourceId: 'LogicalResourceId', + StackId: 'StackId' +} +const context = { + getRemainingTimeInMillis: () => 1000 +} + +test('It should return SUCCESS when empty response', async (t) => { + const handler = middy((event, context) => {}) + + handler.use(cloudformationResponse({})) + + const event = defaultEvent + const response = await handler(event, context) + deepEqual(response, { + Status: 'SUCCESS', + RequestId: 'RequestId', + LogicalResourceId: 'LogicalResourceId', + StackId: 'StackId' + }) +}) + +test('It should return SUCCESS when empty object', async (t) => { + const handler = middy((event, context) => { + return {} + }) + + handler.use(cloudformationResponse({})) + + const event = defaultEvent + const response = await handler(event, context) + deepEqual(response, { + Status: 'SUCCESS', + RequestId: 'RequestId', + LogicalResourceId: 'LogicalResourceId', + StackId: 'StackId' + }) +}) + +test('It should return FAILURE when error thrown', async (t) => { + const handler = middy((event, context) => { + throw new Error('Internal Error') + }) + + handler.use(cloudformationResponse({})) + + const event = defaultEvent + const response = await handler(event, context) + deepEqual(response, { + Status: 'FAILED', + Reason: 'Internal Error', + RequestId: 'RequestId', + LogicalResourceId: 'LogicalResourceId', + StackId: 'StackId' + }) +}) + +test('It should not override response values', async (t) => { + const handler = middy((event, context) => { + return { + Status: 'FAILED', + RequestId: 'RequestId*', + LogicalResourceId: 'LogicalResourceId*', + StackId: 'StackId*' + } + }) + + handler.use(cloudformationResponse({})) + + const event = defaultEvent + const response = await handler(event, context) + deepEqual(response, { + Status: 'FAILED', + RequestId: 'RequestId*', + LogicalResourceId: 'LogicalResourceId*', + StackId: 'StackId*' + }) +}) diff --git a/packages/cloudformation-response/index.js b/packages/cloudformation-response/index.js new file mode 100644 index 000000000..7f6f5ca55 --- /dev/null +++ b/packages/cloudformation-response/index.js @@ -0,0 +1,25 @@ +const cloudformationCustomResourceMiddleware = () => { + const cloudformationCustomResourceMiddlewareAfter = (request) => { + let { response } = request + response ??= {} + response.Status ??= 'SUCCESS' + response.RequestId ??= request.event.RequestId + response.LogicalResourceId ??= request.event.LogicalResourceId + response.StackId ??= request.event.StackId + request.response = response + } + const cloudformationCustomResourceMiddlewareOnError = (request) => { + const response = { + Status: 'FAILED', + Reason: request.error.message + } + request.response = response + cloudformationCustomResourceMiddlewareAfter(request) + } + return { + after: cloudformationCustomResourceMiddlewareAfter, + onError: cloudformationCustomResourceMiddlewareOnError + } +} + +export default cloudformationCustomResourceMiddleware diff --git a/packages/cloudformation-response/package.json b/packages/cloudformation-response/package.json new file mode 100644 index 000000000..6d4d8a913 --- /dev/null +++ b/packages/cloudformation-response/package.json @@ -0,0 +1,69 @@ +{ + "name": "@middy/cloudformation-response", + "version": "6.0.0", + "description": "CloudFormation Custom Response event response handling for the middy framework", + "type": "module", + "engines": { + "node": ">=20" + }, + "engineStrict": true, + "publishConfig": { + "access": "public" + }, + "module": "./index.js", + "exports": { + ".": { + "import": { + "types": "./index.d.ts", + "default": "./index.js" + }, + "require": { + "default": "./index.js" + } + } + }, + "types": "index.d.ts", + "files": [ + "index.js", + "index.d.ts" + ], + "scripts": { + "test": "npm run test:unit", + "test:unit": "node --test __tests__/index.js", + "test:benchmark": "node __benchmarks__/index.js" + }, + "license": "MIT", + "keywords": [ + "Lambda", + "Middleware", + "Serverless", + "Framework", + "AWS", + "AWS Lambda", + "Middy", + "CloudFormation", + "Custom Response" + ], + "author": { + "name": "Middy contributors", + "url": "https://github.com/middyjs/middy/graphs/contributors" + }, + "repository": { + "type": "git", + "url": "github:middyjs/middy", + "directory": "packages/cloudformation-response" + }, + "bugs": { + "url": "https://github.com/middyjs/middy/issues" + }, + "homepage": "https://middy.js.org", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/willfarrell" + }, + "devDependencies": { + "@middy/core": "6.0.0", + "@types/aws-lambda": "^8.10.100" + }, + "gitHead": "7a6c0fbb8ab71d6a2171e678697de9f237568431" +} diff --git a/packages/cloudformation-router/__tests__/fuzz.js b/packages/cloudformation-router/__tests__/fuzz.js new file mode 100644 index 000000000..911652e44 --- /dev/null +++ b/packages/cloudformation-router/__tests__/fuzz.js @@ -0,0 +1,55 @@ +import { test } from 'node:test' +import fc from 'fast-check' +import middy from '../../core/index.js' +import router from '../index.js' + +const handler = middy(router()) +const context = { + getRemainingTimeInMillis: () => 1000 +} + +test('fuzz `event` w/ `object`', async () => { + fc.assert( + fc.asyncProperty(fc.object(), async (event) => { + try { + await handler(event, context) + } catch (e) { + if (e.cause?.package !== '@middy/cloudformation-router') { + throw e + } + } + }), + { + numRuns: 100_000, + verbose: 2, + + examples: [] + } + ) +}) + +test('fuzz `event` w/ `record`', async () => { + fc.assert( + fc.asyncProperty( + fc.record({ + requestContext: fc.record({ + routeKey: fc.string() + }) + }), + async (event) => { + try { + await handler(event, context) + } catch (e) { + if (e.cause?.package !== '@middy/ws-router') { + throw e + } + } + } + ), + { + numRuns: 100_000, + verbose: 2, + examples: [[{ requestContext: { routeKey: 'valueOf' } }]] + } + ) +}) diff --git a/packages/cloudformation-router/__tests__/index.js b/packages/cloudformation-router/__tests__/index.js new file mode 100644 index 000000000..4af8adfd2 --- /dev/null +++ b/packages/cloudformation-router/__tests__/index.js @@ -0,0 +1,117 @@ +import { test } from 'node:test' +import { ok, equal } from 'node:assert/strict' +import middy from '../../core/index.js' +import cloudformationRouter from '../index.js' + +// const event = {} +const context = { + getRemainingTimeInMillis: () => 1000 +} + +// Types of routes +test('It should route to a static route', async (t) => { + const event = { + RequestType: 'Create' + } + const handler = cloudformationRouter([ + { + requestType: 'Create', + handler: () => true + } + ]) + const response = await handler(event, context) + ok(response) +}) + +test('It should thrown FAILURE when route not found', async (t) => { + const event = { + RequestType: 'Update' + } + const handler = cloudformationRouter([ + { + requestType: 'Create', + handler: () => true + } + ]) + try { + await handler(event, context) + } catch (e) { + equal(e.message, 'Route does not exist') + } +}) + +test('It should thrown FAILURE when route not found, using notFoundResponse', async (t) => { + const event = { + RequestType: 'Update' + } + const handler = cloudformationRouter({ + routes: [ + { + requestType: 'Create', + handler: () => true + } + ], + notFoundResponse: (args) => { + return { + Status: 'SUCCESS' + } + } + }) + const res = await handler(event, context) + + equal(res.Status, 'SUCCESS') +}) + +// with middleware +test('It should run middleware that are part of route handler', async (t) => { + const event = { + RequestType: 'Create' + } + const handler = cloudformationRouter([ + { + requestType: 'Create', + handler: middy(() => false).after((request) => { + request.response = true + }) + } + ]) + const response = await handler(event, context) + ok(response) +}) + +test('It should middleware part of router', async (t) => { + const event = { + RequestType: 'Create' + } + const handler = middy( + cloudformationRouter([ + { + requestType: 'Create', + handler: () => false + } + ]) + ).after((request) => { + request.response = true + }) + const response = await handler(event, context) + ok(response) +}) + +// Errors + +test('It should throw when not a cloudformation event', async (t) => { + const event = { + path: '/' + } + const handler = cloudformationRouter([ + { + requestType: 'Create', + handler: () => true + } + ]) + try { + await handler(event, context) + } catch (e) { + equal(e.message, 'Unknown CloudFormation Custom Response event format') + } +}) diff --git a/packages/cloudformation-router/index.js b/packages/cloudformation-router/index.js index 84fcc4755..aba4c2220 100644 --- a/packages/cloudformation-router/index.js +++ b/packages/cloudformation-router/index.js @@ -1,10 +1,13 @@ const defaults = { routes: [], notFoundResponse: ({ requestType }) => { - return { - Status: 'FAILED', - Reason: `Route ${requestType} does not exist. @middy/cloudformation-router` - } + const err = new Error('Route does not exist', { + casue: { + package: '@middy/cloudformation-router', + data: { requestType } + } + }) + throw err } } const cloudformationCustomResourceRouteHandler = (opts = {}) => { @@ -21,21 +24,29 @@ const cloudformationCustomResourceRouteHandler = (opts = {}) => { routesStatic[requestType] = handler } + const requestTypes = { + Create: true, + Update: true, + Delete: true + } return (event, context, abort) => { const { RequestType: requestType } = event - if (!requestType) { - return notFoundResponse({ requestType }) + if ( + !requestType || + !Object.hasOwnProperty.call(requestTypes, requestType) + ) { + throw new Error('Unknown CloudFormation Custom Response event format', { + cause: { + package: '@middy/cloudformation-router', + data: { requestType } + } + }) } // Static - const handler = routesStatic[requestType] - if (typeof handler !== 'undefined') { - const response = handler(event, context, abort) - response.Status ??= 'SUCCESS' - response.RequestId ??= event.RequestId - response.LogicalResourceId ??= event.LogicalResourceId - response.StackId ??= event.StackId - return response + if (Object.hasOwnProperty.call(routesStatic, requestType)) { + const handler = routesStatic[requestType] + return handler(event, context, abort) } // Not Found diff --git a/website/docs/events/cloud-formation.md b/website/docs/events/cloud-formation.md index c8b081bd0..2b3744e80 100644 --- a/website/docs/events/cloud-formation.md +++ b/website/docs/events/cloud-formation.md @@ -14,9 +14,52 @@ This page is a work in progress. If you want to help us to make this page better ## Example ```javascript import middy from '@middy/core' +import cloudformationRouterHandler from '@middy/cloudformation-router' +import cloudformationResponseMiddleware from '@middy/cloudformation-response' +import validatorMiddleware from '@middy/validator' -export const handler = middy() - .handler((event, context, {signal}) => { - // ... +const createHandler = middy() + .use(validatorMiddleware({eventSchema: {...} })) + .handler((event, context) => { + return { + PhysicalResourceId: '...', + Data:{} + } + }) + +const updateHandler = middy() + .use(validatorMiddleware({eventSchema: {...} })) + .handler((event, context) => { + return { + PhysicalResourceId: '...', + Data: {} + } + }) + +const deleteHandler = middy() + .use(validatorMiddleware({eventSchema: {...} })) + .handler((event, context) => { + return { + PhysicalResourceId: '...' + } }) + +const routes = [ + { + requesType: 'Create', + handler: createHandler + }, + { + requesType: 'Update', + handler: updateHandler + }, + { + routeKey: 'Delete', + handler: deleteHandler + } +] + +export const handler = middy() + .use(cloudformationResponseMiddleware()) + .handler(cloudformationRouterHandler(routes)) ``` diff --git a/website/docs/middlewares/cloudformation-response.md b/website/docs/middlewares/cloudformation-response.md new file mode 100644 index 000000000..8ad7aa045 --- /dev/null +++ b/website/docs/middlewares/cloudformation-response.md @@ -0,0 +1,34 @@ +--- +title: cloudformation-response +--- + +Manage CloudFormation Custom Resource responses. + +## Install + +To install this middleware you can use NPM: + +```bash npm2yarn +npm install --save @middy/cloudformation-response +``` + +## Options + +None + +## Sample usage + +### General + +```javascript +import middy from '@middy/core' +import cloudformationResponse from '@middy/cloudformation-response' + +export const handler = middy((event, context) => { + return { + PhysicalResourceId:'...' + } +}) + +handler.use(cloudformationResponse()) +``` diff --git a/website/docs/routers/cloudformation-router.md b/website/docs/routers/cloudformation-router.md index f6016d52f..fc5e5732c 100644 --- a/website/docs/routers/cloudformation-router.md +++ b/website/docs/routers/cloudformation-router.md @@ -17,7 +17,7 @@ npm install --save @middy/cloudformation-router - `routes` (array[\{routeKey, handler\}]) (required): Array of route objects. - `routeKey` (string) (required): AWS formatted request type. ie `Create`, `Update`, `Delete` - `handler` (function) (required): Any `handler(event, context, {signal})` function -- `notFoundHandler` (function): Override default error thrown with your own custom response. Passes in `{requestType}` +- `notFoundHandler` (function): Override default FAILED response with your own custom response. Passes in `{requestType}` NOTES: @@ -30,6 +30,7 @@ NOTES: ```javascript import middy from '@middy/core' import cloudformationRouterHandler from '@middy/cloudformation-router' +import cloudformationResponseMiddleware from '@middy/cloudformation-response' import validatorMiddleware from '@middy/validator' const createHandler = middy() @@ -74,6 +75,6 @@ const routes = [ ] export const handler = middy() - .use(wsResponseMiddleware()) + .use(cloudformationResponseMiddleware()) .handler(cloudformationRouterHandler(routes)) ``` From 9960b8681ab118e60236b969332ea6b3801859cf Mon Sep 17 00:00:00 2001 From: will Farrell Date: Thu, 2 Jan 2025 17:34:04 -0700 Subject: [PATCH 06/14] feat: add in types --- .../__benchmarks__/index.js | 37 +++++++++++++++++++ packages/cloudformation-response/index.d.ts | 7 ++++ .../cloudformation-response/index.test-d.ts | 7 ++++ .../__benchmarks__/index.js | 37 +++++++++++++++++++ .../cloudformation-router/__tests__/fuzz.js | 9 +++-- packages/cloudformation-router/index.d.ts | 13 +++++++ .../cloudformation-router/index.test-d.ts | 28 ++++++++++++++ 7 files changed, 134 insertions(+), 4 deletions(-) create mode 100644 packages/cloudformation-response/__benchmarks__/index.js create mode 100644 packages/cloudformation-response/index.d.ts create mode 100644 packages/cloudformation-response/index.test-d.ts create mode 100644 packages/cloudformation-router/__benchmarks__/index.js create mode 100644 packages/cloudformation-router/index.d.ts create mode 100644 packages/cloudformation-router/index.test-d.ts diff --git a/packages/cloudformation-response/__benchmarks__/index.js b/packages/cloudformation-response/__benchmarks__/index.js new file mode 100644 index 000000000..8523fd16b --- /dev/null +++ b/packages/cloudformation-response/__benchmarks__/index.js @@ -0,0 +1,37 @@ +import { Bench } from 'tinybench' +import middy from '../../core/index.js' +import middleware from '../index.js' + +const bench = new Bench({ time: 1_000 }) + +const context = { + getRemainingTimeInMillis: () => 30000 +} +const setupHandler = (options = {}) => { + const baseHandler = () => {} + return middy(baseHandler).use( + middleware({ + ...options + }) + ) +} + +const coldHandler = setupHandler({ cacheExpiry: 0 }) +const warmHandler = setupHandler() + +const event = {} +await bench + .add('without cache', async () => { + try { + await coldHandler(event, context) + } catch (e) {} + }) + .add('with cache', async () => { + try { + await warmHandler(event, context) + } catch (e) {} + }) + + .run() + +console.table(bench.table()) diff --git a/packages/cloudformation-response/index.d.ts b/packages/cloudformation-response/index.d.ts new file mode 100644 index 000000000..13c81cbd7 --- /dev/null +++ b/packages/cloudformation-response/index.d.ts @@ -0,0 +1,7 @@ +import middy from '@middy/core' + +interface Options {} + +declare function cloudformationResponse(options?: Options): middy.MiddlewareObj + +export default cloudformationResponse diff --git a/packages/cloudformation-response/index.test-d.ts b/packages/cloudformation-response/index.test-d.ts new file mode 100644 index 000000000..b7dd402c1 --- /dev/null +++ b/packages/cloudformation-response/index.test-d.ts @@ -0,0 +1,7 @@ +import { expectType } from 'tsd' +import middy from '@middy/core' +import cloudformationResponse from '.' + +// use with default options +let middleware = cloudformationResponse() +expectType(middleware) diff --git a/packages/cloudformation-router/__benchmarks__/index.js b/packages/cloudformation-router/__benchmarks__/index.js new file mode 100644 index 000000000..8523fd16b --- /dev/null +++ b/packages/cloudformation-router/__benchmarks__/index.js @@ -0,0 +1,37 @@ +import { Bench } from 'tinybench' +import middy from '../../core/index.js' +import middleware from '../index.js' + +const bench = new Bench({ time: 1_000 }) + +const context = { + getRemainingTimeInMillis: () => 30000 +} +const setupHandler = (options = {}) => { + const baseHandler = () => {} + return middy(baseHandler).use( + middleware({ + ...options + }) + ) +} + +const coldHandler = setupHandler({ cacheExpiry: 0 }) +const warmHandler = setupHandler() + +const event = {} +await bench + .add('without cache', async () => { + try { + await coldHandler(event, context) + } catch (e) {} + }) + .add('with cache', async () => { + try { + await warmHandler(event, context) + } catch (e) {} + }) + + .run() + +console.table(bench.table()) diff --git a/packages/cloudformation-router/__tests__/fuzz.js b/packages/cloudformation-router/__tests__/fuzz.js index 911652e44..fc1f4b07e 100644 --- a/packages/cloudformation-router/__tests__/fuzz.js +++ b/packages/cloudformation-router/__tests__/fuzz.js @@ -32,15 +32,16 @@ test('fuzz `event` w/ `record`', async () => { fc.assert( fc.asyncProperty( fc.record({ - requestContext: fc.record({ - routeKey: fc.string() - }) + RequestType: fc.string(), + RequestId: fc.string(), + LogicalResourceId: fc.string(), + StackId: fc.string() }), async (event) => { try { await handler(event, context) } catch (e) { - if (e.cause?.package !== '@middy/ws-router') { + if (e.cause?.package !== '@middy/cloudformation-router') { throw e } } diff --git a/packages/cloudformation-router/index.d.ts b/packages/cloudformation-router/index.d.ts new file mode 100644 index 000000000..cebb151aa --- /dev/null +++ b/packages/cloudformation-router/index.d.ts @@ -0,0 +1,13 @@ +import middy from '@middy/core' +import { CloudFormationCustomResourceHandler } from 'aws-lambda' + +interface Route { + requestType: string + handler: CloudFormationCustomResourceHandler +} + +declare function cloudformationRouterHandler( + routes: Route[] +): middy.MiddyfiedHandler + +export default cloudformationRouterHandler diff --git a/packages/cloudformation-router/index.test-d.ts b/packages/cloudformation-router/index.test-d.ts new file mode 100644 index 000000000..3c44d2bcb --- /dev/null +++ b/packages/cloudformation-router/index.test-d.ts @@ -0,0 +1,28 @@ +import middy from '@middy/core' +//import { CloudFormationCustomResourceHandler } from 'aws-lambda' +import { expectType } from 'tsd' +import cloudformationRouterHandler from '.' + +const createLambdaHandler: any = async () => { + return { + Status: 'SUCCESS' + } +} + +const deleteLambdaHandler: any = async () => { + return { + Status: 'SUCCESS' + } +} + +const middleware = cloudformationRouterHandler([ + { + requestType: 'Create', + handler: createLambdaHandler + }, + { + requestType: 'Delete', + handler: deleteLambdaHandler + } +]) +expectType(middleware) From 40a613611769c060c4781839710551277f7b9a57 Mon Sep 17 00:00:00 2001 From: will Farrell Date: Thu, 2 Jan 2025 17:35:07 -0700 Subject: [PATCH 07/14] fix: remove unused opts --- packages/cloudformation-response/__tests__/index.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/cloudformation-response/__tests__/index.js b/packages/cloudformation-response/__tests__/index.js index 9e6c46845..d91de9526 100644 --- a/packages/cloudformation-response/__tests__/index.js +++ b/packages/cloudformation-response/__tests__/index.js @@ -18,7 +18,7 @@ const context = { test('It should return SUCCESS when empty response', async (t) => { const handler = middy((event, context) => {}) - handler.use(cloudformationResponse({})) + handler.use(cloudformationResponse()) const event = defaultEvent const response = await handler(event, context) @@ -35,7 +35,7 @@ test('It should return SUCCESS when empty object', async (t) => { return {} }) - handler.use(cloudformationResponse({})) + handler.use(cloudformationResponse()) const event = defaultEvent const response = await handler(event, context) @@ -52,7 +52,7 @@ test('It should return FAILURE when error thrown', async (t) => { throw new Error('Internal Error') }) - handler.use(cloudformationResponse({})) + handler.use(cloudformationResponse()) const event = defaultEvent const response = await handler(event, context) @@ -75,7 +75,7 @@ test('It should not override response values', async (t) => { } }) - handler.use(cloudformationResponse({})) + handler.use(cloudformationResponse()) const event = defaultEvent const response = await handler(event, context) From a575a5f5231a597e18d11878bf3feefca671ca4c Mon Sep 17 00:00:00 2001 From: will Farrell Date: Thu, 2 Jan 2025 17:36:16 -0700 Subject: [PATCH 08/14] ci: add new pkg to lock file --- package-lock.json | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/package-lock.json b/package-lock.json index 0e2ae13ab..10a804dc6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2488,6 +2488,10 @@ "resolved": "packages/appconfig", "link": true }, + "node_modules/@middy/cloudformation-response": { + "resolved": "packages/cloudformation-response", + "link": true + }, "node_modules/@middy/cloudformation-router": { "resolved": "packages/cloudformation-router", "link": true @@ -11319,6 +11323,22 @@ "url": "https://github.com/sponsors/willfarrell" } }, + "packages/cloudformation-response": { + "name": "@middy/cloudformation-response", + "version": "6.0.0", + "license": "MIT", + "devDependencies": { + "@middy/core": "6.0.0", + "@types/aws-lambda": "^8.10.100" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/willfarrell" + } + }, "packages/cloudformation-router": { "name": "@middy/cloudformation-router", "version": "6.0.0", From 3c769b50e1e861a5083cf024ab95ad301f63702a Mon Sep 17 00:00:00 2001 From: will Farrell Date: Thu, 2 Jan 2025 17:38:31 -0700 Subject: [PATCH 09/14] ci: fix lint --- packages/cloudformation-response/index.d.ts | 2 +- packages/cloudformation-response/index.test-d.ts | 2 +- packages/cloudformation-router/index.d.ts | 2 +- packages/cloudformation-router/index.test-d.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/cloudformation-response/index.d.ts b/packages/cloudformation-response/index.d.ts index 13c81cbd7..5476fdd41 100644 --- a/packages/cloudformation-response/index.d.ts +++ b/packages/cloudformation-response/index.d.ts @@ -2,6 +2,6 @@ import middy from '@middy/core' interface Options {} -declare function cloudformationResponse(options?: Options): middy.MiddlewareObj +declare function cloudformationResponse (options?: Options): middy.MiddlewareObj export default cloudformationResponse diff --git a/packages/cloudformation-response/index.test-d.ts b/packages/cloudformation-response/index.test-d.ts index b7dd402c1..c52b2154e 100644 --- a/packages/cloudformation-response/index.test-d.ts +++ b/packages/cloudformation-response/index.test-d.ts @@ -3,5 +3,5 @@ import middy from '@middy/core' import cloudformationResponse from '.' // use with default options -let middleware = cloudformationResponse() +const middleware = cloudformationResponse() expectType(middleware) diff --git a/packages/cloudformation-router/index.d.ts b/packages/cloudformation-router/index.d.ts index cebb151aa..84bf5af25 100644 --- a/packages/cloudformation-router/index.d.ts +++ b/packages/cloudformation-router/index.d.ts @@ -6,7 +6,7 @@ interface Route { handler: CloudFormationCustomResourceHandler } -declare function cloudformationRouterHandler( +declare function cloudformationRouterHandler ( routes: Route[] ): middy.MiddyfiedHandler diff --git a/packages/cloudformation-router/index.test-d.ts b/packages/cloudformation-router/index.test-d.ts index 3c44d2bcb..4fd634e3b 100644 --- a/packages/cloudformation-router/index.test-d.ts +++ b/packages/cloudformation-router/index.test-d.ts @@ -1,5 +1,5 @@ import middy from '@middy/core' -//import { CloudFormationCustomResourceHandler } from 'aws-lambda' +// import { CloudFormationCustomResourceHandler } from 'aws-lambda' import { expectType } from 'tsd' import cloudformationRouterHandler from '.' From 3955b3fbdb6e33ebfafbcd011f2f74ef2e5a9f37 Mon Sep 17 00:00:00 2001 From: will Farrell Date: Thu, 2 Jan 2025 17:39:17 -0700 Subject: [PATCH 10/14] ci: clean up passing options --- packages/cloudformation-response/__benchmarks__/index.js | 6 +----- packages/cloudformation-router/__benchmarks__/index.js | 6 +----- packages/http-router/index.js | 6 +++--- 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/packages/cloudformation-response/__benchmarks__/index.js b/packages/cloudformation-response/__benchmarks__/index.js index 8523fd16b..841c09bbe 100644 --- a/packages/cloudformation-response/__benchmarks__/index.js +++ b/packages/cloudformation-response/__benchmarks__/index.js @@ -9,11 +9,7 @@ const context = { } const setupHandler = (options = {}) => { const baseHandler = () => {} - return middy(baseHandler).use( - middleware({ - ...options - }) - ) + return middy(baseHandler).use(middleware(options)) } const coldHandler = setupHandler({ cacheExpiry: 0 }) diff --git a/packages/cloudformation-router/__benchmarks__/index.js b/packages/cloudformation-router/__benchmarks__/index.js index 8523fd16b..841c09bbe 100644 --- a/packages/cloudformation-router/__benchmarks__/index.js +++ b/packages/cloudformation-router/__benchmarks__/index.js @@ -9,11 +9,7 @@ const context = { } const setupHandler = (options = {}) => { const baseHandler = () => {} - return middy(baseHandler).use( - middleware({ - ...options - }) - ) + return middy(baseHandler).use(middleware(options)) } const coldHandler = setupHandler({ cacheExpiry: 0 }) diff --git a/packages/http-router/index.js b/packages/http-router/index.js index aa9dd8928..3dee4af4f 100644 --- a/packages/http-router/index.js +++ b/packages/http-router/index.js @@ -24,7 +24,7 @@ const httpRouteHandler = (opts = {}) => { // Prevents `routesType[method][path] = handler` from flagging: This assignment may alter Object.prototype if a malicious '__proto__' string is injected from library input. if (!enumMethods.includes(method)) { throw new Error('Method not allowed', { - cause: { package: '@middy/http-router', data: method } + cause: { package: '@middy/http-router', data: { method } } }) } @@ -48,12 +48,12 @@ const httpRouteHandler = (opts = {}) => { if (!method) { throw new Error('Unknown http event format', { - cause: { package: '@middy/http-router', data: method } + cause: { package: '@middy/http-router', data: { method } } }) } if (!path) { throw new Error('Unknown http event format', { - cause: { package: '@middy/http-router', data: path } + cause: { package: '@middy/http-router', data: { path } } }) } From 936f5a2e665b58e49640300da6e86191c3385a9b Mon Sep 17 00:00:00 2001 From: will Farrell Date: Thu, 2 Jan 2025 17:39:53 -0700 Subject: [PATCH 11/14] ci: remove unused options --- packages/cloudformation-response/__benchmarks__/index.js | 4 ++-- packages/cloudformation-router/__benchmarks__/index.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/cloudformation-response/__benchmarks__/index.js b/packages/cloudformation-response/__benchmarks__/index.js index 841c09bbe..d9c351138 100644 --- a/packages/cloudformation-response/__benchmarks__/index.js +++ b/packages/cloudformation-response/__benchmarks__/index.js @@ -7,9 +7,9 @@ const bench = new Bench({ time: 1_000 }) const context = { getRemainingTimeInMillis: () => 30000 } -const setupHandler = (options = {}) => { +const setupHandler = () => { const baseHandler = () => {} - return middy(baseHandler).use(middleware(options)) + return middy(baseHandler).use(middleware()) } const coldHandler = setupHandler({ cacheExpiry: 0 }) diff --git a/packages/cloudformation-router/__benchmarks__/index.js b/packages/cloudformation-router/__benchmarks__/index.js index 841c09bbe..d9c351138 100644 --- a/packages/cloudformation-router/__benchmarks__/index.js +++ b/packages/cloudformation-router/__benchmarks__/index.js @@ -7,9 +7,9 @@ const bench = new Bench({ time: 1_000 }) const context = { getRemainingTimeInMillis: () => 30000 } -const setupHandler = (options = {}) => { +const setupHandler = () => { const baseHandler = () => {} - return middy(baseHandler).use(middleware(options)) + return middy(baseHandler).use(middleware()) } const coldHandler = setupHandler({ cacheExpiry: 0 }) From dfc6c33c8a467e38ff7ad70e1cf661b9f8aadc42 Mon Sep 17 00:00:00 2001 From: will Farrell Date: Thu, 2 Jan 2025 17:42:51 -0700 Subject: [PATCH 12/14] fix: remove option types --- packages/cloudformation-response/index.d.ts | 4 +--- packages/cloudformation-response/index.test-d.ts | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/cloudformation-response/index.d.ts b/packages/cloudformation-response/index.d.ts index 5476fdd41..95d6904ee 100644 --- a/packages/cloudformation-response/index.d.ts +++ b/packages/cloudformation-response/index.d.ts @@ -1,7 +1,5 @@ import middy from '@middy/core' -interface Options {} - -declare function cloudformationResponse (options?: Options): middy.MiddlewareObj +declare function cloudformationResponse (): middy.MiddlewareObj export default cloudformationResponse diff --git a/packages/cloudformation-response/index.test-d.ts b/packages/cloudformation-response/index.test-d.ts index c52b2154e..b9d16f8af 100644 --- a/packages/cloudformation-response/index.test-d.ts +++ b/packages/cloudformation-response/index.test-d.ts @@ -1,5 +1,6 @@ import { expectType } from 'tsd' import middy from '@middy/core' + import cloudformationResponse from '.' // use with default options From 2eaff84e4352ab2e2fc0cb618e7b32bd11f70def Mon Sep 17 00:00:00 2001 From: will Farrell Date: Thu, 2 Jan 2025 17:43:57 -0700 Subject: [PATCH 13/14] test: remove unused --- packages/cloudformation-response/__benchmarks__/index.js | 8 +------- packages/cloudformation-router/__benchmarks__/index.js | 8 +------- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/packages/cloudformation-response/__benchmarks__/index.js b/packages/cloudformation-response/__benchmarks__/index.js index d9c351138..42c8ee848 100644 --- a/packages/cloudformation-response/__benchmarks__/index.js +++ b/packages/cloudformation-response/__benchmarks__/index.js @@ -12,8 +12,7 @@ const setupHandler = () => { return middy(baseHandler).use(middleware()) } -const coldHandler = setupHandler({ cacheExpiry: 0 }) -const warmHandler = setupHandler() +const coldHandler = setupHandler() const event = {} await bench @@ -22,11 +21,6 @@ await bench await coldHandler(event, context) } catch (e) {} }) - .add('with cache', async () => { - try { - await warmHandler(event, context) - } catch (e) {} - }) .run() diff --git a/packages/cloudformation-router/__benchmarks__/index.js b/packages/cloudformation-router/__benchmarks__/index.js index d9c351138..42c8ee848 100644 --- a/packages/cloudformation-router/__benchmarks__/index.js +++ b/packages/cloudformation-router/__benchmarks__/index.js @@ -12,8 +12,7 @@ const setupHandler = () => { return middy(baseHandler).use(middleware()) } -const coldHandler = setupHandler({ cacheExpiry: 0 }) -const warmHandler = setupHandler() +const coldHandler = setupHandler() const event = {} await bench @@ -22,11 +21,6 @@ await bench await coldHandler(event, context) } catch (e) {} }) - .add('with cache', async () => { - try { - await warmHandler(event, context) - } catch (e) {} - }) .run() From 49ec16178fe0695a2f400a18029fd7818c7d25e5 Mon Sep 17 00:00:00 2001 From: will Farrell Date: Thu, 2 Jan 2025 17:45:57 -0700 Subject: [PATCH 14/14] test: remove unused options --- packages/cloudformation-response/__tests__/fuzz.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cloudformation-response/__tests__/fuzz.js b/packages/cloudformation-response/__tests__/fuzz.js index f7cd82cd5..b39db8e3c 100644 --- a/packages/cloudformation-response/__tests__/fuzz.js +++ b/packages/cloudformation-response/__tests__/fuzz.js @@ -3,7 +3,7 @@ import fc from 'fast-check' import middy from '../../core/index.js' import middleware from '../index.js' -const handler = middy((event) => event).use(middleware({})) +const handler = middy((event) => event).use(middleware()) const context = { getRemainingTimeInMillis: () => 1000 }