diff --git a/docs/netacea_unified_handler.md b/docs/netacea_unified_handler.md new file mode 100644 index 0000000..d044bbc --- /dev/null +++ b/docs/netacea_unified_handler.md @@ -0,0 +1,27 @@ +# Netacea Unified Handler + +This document contains instructions on how to deploy the Netacea CloudFront +integration using a single lambda definition that handles three event types. + +This is an alternative to using individual Viewer Request, Viewer Response, +and Origin Response handlers. + +Using the Unified handler is preferred when using Kinesis ingest, +as Kinesis ingest can be performed in the background while other tasks +are handled by the lambda. + +## Deployment + +The Unified Handler can be deployed in the same way as any of the three +individual lambdas would be, as documented in the +[Installation and Configuration](https://docs.netacea.com/netacea-plugin-information/cloudfront/installation-and-configuration) +section. + +However, the Handler should be specified as `NetaceaUnified.handler` +(rather than, for example, ViewerRequest.handler). + +Finally, these three triggers should specify the Unified Handler lambda: + +- Viewer Request (Include body) +- Viewer Response +- Origin Response diff --git a/package-lock.json b/package-lock.json index 86fc4b6..28c2294 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "1.0.0", "license": "MIT", "dependencies": { - "@netacea/cloudfront": "^6.0.69" + "@netacea/cloudfront": "^6.0.71" }, "devDependencies": { "@types/aws-lambda": "^8.10.119", @@ -216,9 +216,9 @@ } }, "node_modules/@netacea/cloudfront": { - "version": "6.0.69", - "resolved": "https://registry.npmjs.org/@netacea/cloudfront/-/cloudfront-6.0.69.tgz", - "integrity": "sha512-hryfhJy2+edn3aN0e+rcNT8MZ6k8AOR+YZXMvHBYN3bq1LcPIw44aVupNF/iFbvR58H9AqeX0svoNLtCwWbdlg==", + "version": "6.0.71", + "resolved": "https://registry.npmjs.org/@netacea/cloudfront/-/cloudfront-6.0.71.tgz", + "integrity": "sha512-xTOHooSNVRmXBdmXgYDU7fNyWx24tyXSRkNPYKw/ZRvcygLwxiVWCV3hT+mlspl91xLY3+jululLrl7JgsJNeg==", "license": "ISC", "dependencies": { "@types/aws-lambda": "^8.10.138", diff --git a/package.json b/package.json index b767d9b..453a7b9 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "xo": "^0.55.0" }, "dependencies": { - "@netacea/cloudfront": "^6.0.69" + "@netacea/cloudfront": "^6.0.71" }, "xo": { "space": true, diff --git a/src/NetaceaUnified.ts b/src/NetaceaUnified.ts new file mode 100644 index 0000000..c017809 --- /dev/null +++ b/src/NetaceaUnified.ts @@ -0,0 +1,87 @@ +/** + * This file provides an example of how to use a single lambda definition + * to handle multiple event types in AWS CloudFront. + * Please see docs/netacea_unified_handler.md for more information. + */ +import { + type CloudFrontResponse, + type CloudFrontResponseEvent, + type Callback, + type CloudFrontRequest, + type CloudFrontRequestEvent, + type CloudFrontResultResponse, + type Context, + type Handler, +} from 'aws-lambda' +import { + Cloudfront as NetaceaCloudfront, + type CloudfrontConstructorArgs, +} from '@netacea/cloudfront' +import * as NetaceaConfig from './NetaceaConfig.json' + +type EventType = 'origin-request' | 'origin-response' | 'viewer-request' | 'viewer-response' + +const worker = new NetaceaCloudfront(NetaceaConfig as CloudfrontConstructorArgs) + +export const handler: Handler = async ( + event: CloudFrontRequestEvent, + context: Context, + callback: Callback, +): Promise => { + context.callbackWaitsForEmptyEventLoop = false + + const eventType = event.Records[0]?.cf.config.eventType?.toLowerCase() as EventType + + if (eventType === 'viewer-request' || eventType === 'origin-request') { + return viewerRequestHandler(event, context, callback) + } + + if (eventType === 'origin-response') { + return originResponseHandler(event, context, callback) + } + + if (eventType === 'viewer-response') { + return viewerResponseHandler(event, context, callback) + } +} + +export const viewerRequestHandler: Handler = async ( + event: CloudFrontRequestEvent, + context: Context, + callback: Callback, +): Promise => { + const netaceaResponse = await worker.run(event) + + if (netaceaResponse.respondWith !== undefined) { + callback(null, netaceaResponse.respondWith) + return + } + + callback(null, event.Records[0].cf.request) +} + +export const originResponseHandler: Handler = async ( + event: CloudFrontResponseEvent, + context: Context, + callback: Callback, +): Promise => { + if (Number(event.Records[0].cf.response.status) >= 400) { + worker.addNetaceaCookiesToResponse(event) + void worker.ingest(event) + } + + callback(null, event.Records[0].cf.response) +} + +export const viewerResponseHandler: Handler = async ( + event: CloudFrontResponseEvent, + context: Context, + callback: Callback, +): Promise => { + if (Number(event.Records[0].cf.response.status) < 400) { + worker.addNetaceaCookiesToResponse(event) + void worker.ingest(event) + } + + callback(null, event.Records[0].cf.response) +}