Skip to content

Commit 37ee632

Browse files
Merge pull request #48 from DBB-Software/fea/PLATFORM-1628
feat/platform-1628: updated lambda functions
2 parents bdb68c9 + 52ae047 commit 37ee632

File tree

9 files changed

+112
-25
lines changed

9 files changed

+112
-25
lines changed

src/cacheHandler/strategy/s3.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ export class S3Cache implements CacheStrategy {
6666
const baseInput: PutObjectCommandInput = {
6767
Bucket: this.bucketName,
6868
Key: `${pageKey}/${cacheKey}`,
69+
Metadata: {
70+
'Cache-Fragment-Key': cacheKey
71+
},
6972
...(data.revalidate ? { CacheControl: `max-age=${data.revalidate}` } : undefined)
7073
}
7174

src/cdk/constructs/CloudFrontDistribution.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ interface CloudFrontPropsDistribution {
1212
renderServerDomain: string
1313
requestEdgeFunction: cloudfront.experimental.EdgeFunction
1414
responseEdgeFunction: cloudfront.experimental.EdgeFunction
15+
viewerResponseEdgeFunction: cloudfront.experimental.EdgeFunction
1516
cacheConfig: CacheConfig
1617
imageTTL?: number
1718
}
@@ -29,7 +30,15 @@ export class CloudFrontDistribution extends Construct {
2930
constructor(scope: Construct, id: string, props: CloudFrontPropsDistribution) {
3031
super(scope, id)
3132

32-
const { staticBucket, requestEdgeFunction, responseEdgeFunction, cacheConfig, renderServerDomain, imageTTL } = props
33+
const {
34+
staticBucket,
35+
requestEdgeFunction,
36+
responseEdgeFunction,
37+
viewerResponseEdgeFunction,
38+
cacheConfig,
39+
renderServerDomain,
40+
imageTTL
41+
} = props
3342

3443
const splitCachePolicy = new cloudfront.CachePolicy(this, 'SplitCachePolicy', {
3544
cachePolicyName: `${id}-SplitCachePolicy`,
@@ -86,6 +95,10 @@ export class CloudFrontDistribution extends Construct {
8695
{
8796
functionVersion: responseEdgeFunction.currentVersion,
8897
eventType: cloudfront.LambdaEdgeEventType.ORIGIN_RESPONSE
98+
},
99+
{
100+
functionVersion: viewerResponseEdgeFunction.currentVersion,
101+
eventType: cloudfront.LambdaEdgeEventType.VIEWER_RESPONSE
89102
}
90103
],
91104
cachePolicy: splitCachePolicy

src/cdk/constructs/RoutingLambdaEdge.ts renamed to src/cdk/constructs/OriginRequestLambdaEdge.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import path from 'node:path'
88
import { buildLambda } from '../../build/edge'
99
import { CacheConfig } from '../../types'
1010

11-
interface RoutingLambdaEdgeProps extends cdk.StackProps {
11+
interface OriginRequestLambdaEdgeProps extends cdk.StackProps {
1212
bucketName: string
1313
renderServerDomain: string
1414
buildOutputPath: string
@@ -22,15 +22,15 @@ const NodeJSEnvironmentMapping: Record<string, lambda.Runtime> = {
2222
'20': lambda.Runtime.NODEJS_20_X
2323
}
2424

25-
export class RoutingLambdaEdge extends Construct {
25+
export class OriginRequestLambdaEdge extends Construct {
2626
public readonly lambdaEdge: cloudfront.experimental.EdgeFunction
2727

28-
constructor(scope: Construct, id: string, props: RoutingLambdaEdgeProps) {
28+
constructor(scope: Construct, id: string, props: OriginRequestLambdaEdgeProps) {
2929
const { bucketName, bucketRegion, renderServerDomain, nodejs, buildOutputPath, cacheConfig } = props
3030
super(scope, id)
3131

3232
const nodeJSEnvironment = NodeJSEnvironmentMapping[nodejs ?? ''] ?? NodeJSEnvironmentMapping['20']
33-
const name = 'edgeRouting'
33+
const name = 'originRequest'
3434

3535
buildLambda(name, buildOutputPath, {
3636
define: {
@@ -41,13 +41,13 @@ export class RoutingLambdaEdge extends Construct {
4141
}
4242
})
4343

44-
const logGroup = new logs.LogGroup(this, 'RoutingLambdaEdgeLogGroup', {
45-
logGroupName: `/aws/lambda/${id}-edgeRouting`,
44+
const logGroup = new logs.LogGroup(this, 'OriginRequestLambdaEdgeLogGroup', {
45+
logGroupName: `/aws/lambda/${id}-originRequest`,
4646
removalPolicy: cdk.RemovalPolicy.DESTROY,
4747
retention: logs.RetentionDays.ONE_DAY
4848
})
4949

50-
this.lambdaEdge = new cloudfront.experimental.EdgeFunction(this, 'RoutingLambdaEdge', {
50+
this.lambdaEdge = new cloudfront.experimental.EdgeFunction(this, 'OriginRequestLambdaEdge', {
5151
runtime: nodeJSEnvironment,
5252
code: lambda.Code.fromAsset(path.join(buildOutputPath, 'server-functions', name)),
5353
handler: 'index.handler',

src/cdk/constructs/CheckExpirationLambdaEdge.ts renamed to src/cdk/constructs/OriginResponseLambdaEdge.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import path from 'node:path'
88
import { buildLambda } from '../../build/edge'
99
import { CacheConfig } from '../../types'
1010

11-
interface CheckExpirationLambdaEdgeProps extends cdk.StackProps {
11+
interface OriginResponseLambdaEdgeProps extends cdk.StackProps {
1212
renderWorkerQueueUrl: string
1313
renderWorkerQueueArn: string
1414
buildOutputPath: string
@@ -22,15 +22,15 @@ const NodeJSEnvironmentMapping: Record<string, lambda.Runtime> = {
2222
'20': lambda.Runtime.NODEJS_20_X
2323
}
2424

25-
export class CheckExpirationLambdaEdge extends Construct {
25+
export class OriginResponseLambdaEdge extends Construct {
2626
public readonly lambdaEdge: cloudfront.experimental.EdgeFunction
2727

28-
constructor(scope: Construct, id: string, props: CheckExpirationLambdaEdgeProps) {
28+
constructor(scope: Construct, id: string, props: OriginResponseLambdaEdgeProps) {
2929
const { nodejs, buildOutputPath, cacheConfig, renderWorkerQueueUrl, renderWorkerQueueArn, region } = props
3030
super(scope, id)
3131

3232
const nodeJSEnvironment = NodeJSEnvironmentMapping[nodejs ?? ''] ?? NodeJSEnvironmentMapping['20']
33-
const name = 'checkExpiration'
33+
const name = 'originResponse'
3434

3535
buildLambda(name, buildOutputPath, {
3636
define: {
@@ -40,13 +40,13 @@ export class CheckExpirationLambdaEdge extends Construct {
4040
}
4141
})
4242

43-
const logGroup = new logs.LogGroup(this, 'CheckExpirationLambdaEdgeLogGroup', {
44-
logGroupName: `/aws/lambda/${id}-checkExpiration`,
43+
const logGroup = new logs.LogGroup(this, 'OriginResponseLambdaEdgeLogGroup', {
44+
logGroupName: `/aws/lambda/${id}-originResponse`,
4545
removalPolicy: cdk.RemovalPolicy.DESTROY,
4646
retention: logs.RetentionDays.ONE_DAY
4747
})
4848

49-
this.lambdaEdge = new cloudfront.experimental.EdgeFunction(this, 'CheckExpirationLambdaEdge', {
49+
this.lambdaEdge = new cloudfront.experimental.EdgeFunction(this, 'OriginResponseLambdaEdge', {
5050
runtime: nodeJSEnvironment,
5151
code: lambda.Code.fromAsset(path.join(buildOutputPath, 'server-functions', name)),
5252
handler: 'index.handler',
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { Construct } from 'constructs'
2+
import * as lambda from 'aws-cdk-lib/aws-lambda'
3+
import * as cloudfront from 'aws-cdk-lib/aws-cloudfront'
4+
import path from 'node:path'
5+
import { buildLambda } from '../../build/edge'
6+
7+
const NodeJSEnvironmentMapping: Record<string, lambda.Runtime> = {
8+
'18': lambda.Runtime.NODEJS_18_X,
9+
'20': lambda.Runtime.NODEJS_20_X
10+
}
11+
12+
interface ViewerResponseLambdaEdgeProps {
13+
nodejs?: string
14+
buildOutputPath: string
15+
}
16+
17+
export class ViewerResponseLambdaEdge extends Construct {
18+
public readonly lambdaEdge: cloudfront.experimental.EdgeFunction
19+
20+
constructor(scope: Construct, id: string, props: ViewerResponseLambdaEdgeProps) {
21+
const { nodejs, buildOutputPath } = props
22+
super(scope, id)
23+
24+
const nodeJSEnvironment = NodeJSEnvironmentMapping[nodejs ?? ''] ?? NodeJSEnvironmentMapping['20']
25+
const name = 'viewerResponse'
26+
27+
buildLambda(name, buildOutputPath)
28+
29+
this.lambdaEdge = new cloudfront.experimental.EdgeFunction(this, 'ViewerResponseLambdaEdge', {
30+
runtime: nodeJSEnvironment,
31+
code: lambda.Code.fromAsset(path.join(buildOutputPath, 'server-functions', name)),
32+
handler: 'index.handler'
33+
})
34+
}
35+
}

src/cdk/stacks/NextCloudfrontStack.ts

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { Stack, type StackProps } from 'aws-cdk-lib'
22
import { Construct } from 'constructs'
33
import * as s3 from 'aws-cdk-lib/aws-s3'
4-
import { RoutingLambdaEdge } from '../constructs/RoutingLambdaEdge'
4+
import { OriginRequestLambdaEdge } from '../constructs/OriginRequestLambdaEdge'
55
import { CloudFrontDistribution } from '../constructs/CloudFrontDistribution'
66
import { CacheConfig } from '../../types'
7-
import { CheckExpirationLambdaEdge } from '../constructs/CheckExpirationLambdaEdge'
7+
import { OriginResponseLambdaEdge } from '../constructs/OriginResponseLambdaEdge'
8+
import { ViewerResponseLambdaEdge } from '../constructs/ViewerResponseLambdaEdge'
89

910
export interface NextCloudfrontStackProps extends StackProps {
1011
nodejs?: string
@@ -19,8 +20,9 @@ export interface NextCloudfrontStackProps extends StackProps {
1920
}
2021

2122
export class NextCloudfrontStack extends Stack {
22-
public readonly routingLambdaEdge: RoutingLambdaEdge
23-
public readonly checkExpLambdaEdge: CheckExpirationLambdaEdge
23+
public readonly originRequestLambdaEdge: OriginRequestLambdaEdge
24+
public readonly originResponseLambdaEdge: OriginResponseLambdaEdge
25+
public readonly viewerResponseLambdaEdge: ViewerResponseLambdaEdge
2426
public readonly cloudfront: CloudFrontDistribution
2527

2628
constructor(scope: Construct, id: string, props: NextCloudfrontStackProps) {
@@ -37,7 +39,7 @@ export class NextCloudfrontStack extends Stack {
3739
imageTTL
3840
} = props
3941

40-
this.routingLambdaEdge = new RoutingLambdaEdge(this, `${id}-RoutingLambdaEdge`, {
42+
this.originRequestLambdaEdge = new OriginRequestLambdaEdge(this, `${id}-OriginRequestLambdaEdge`, {
4143
nodejs,
4244
bucketName: staticBucketName,
4345
renderServerDomain,
@@ -46,7 +48,7 @@ export class NextCloudfrontStack extends Stack {
4648
bucketRegion: region
4749
})
4850

49-
this.checkExpLambdaEdge = new CheckExpirationLambdaEdge(this, `${id}-CheckExpirationLambdaEdge`, {
51+
this.originResponseLambdaEdge = new OriginResponseLambdaEdge(this, `${id}-OriginResponseLambdaEdge`, {
5052
nodejs,
5153
renderWorkerQueueUrl,
5254
buildOutputPath,
@@ -55,6 +57,11 @@ export class NextCloudfrontStack extends Stack {
5557
region
5658
})
5759

60+
this.viewerResponseLambdaEdge = new ViewerResponseLambdaEdge(this, `${id}-ViewerResponseLambdaEdge`, {
61+
nodejs,
62+
buildOutputPath
63+
})
64+
5865
const staticBucket = s3.Bucket.fromBucketAttributes(this, `${id}-StaticAssetsBucket`, {
5966
bucketName: staticBucketName,
6067
region
@@ -63,13 +70,14 @@ export class NextCloudfrontStack extends Stack {
6370
this.cloudfront = new CloudFrontDistribution(this, `${id}-NextCloudFront`, {
6471
staticBucket,
6572
renderServerDomain,
66-
requestEdgeFunction: this.routingLambdaEdge.lambdaEdge,
67-
responseEdgeFunction: this.checkExpLambdaEdge.lambdaEdge,
73+
requestEdgeFunction: this.originRequestLambdaEdge.lambdaEdge,
74+
responseEdgeFunction: this.originResponseLambdaEdge.lambdaEdge,
75+
viewerResponseEdgeFunction: this.viewerResponseLambdaEdge.lambdaEdge,
6876
cacheConfig,
6977
imageTTL
7078
})
7179

72-
staticBucket.grantRead(this.routingLambdaEdge.lambdaEdge)
73-
staticBucket.grantRead(this.checkExpLambdaEdge.lambdaEdge)
80+
staticBucket.grantRead(this.originRequestLambdaEdge.lambdaEdge)
81+
staticBucket.grantRead(this.originResponseLambdaEdge.lambdaEdge)
7482
}
7583
}
File renamed without changes.
File renamed without changes.

src/lambdas/viewerResponse.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import type { CloudFrontRequestCallback, Context, CloudFrontResponseEvent } from 'aws-lambda'
2+
3+
/**
4+
* Lambda@Edge viewer response handler that processes CloudFront responses.
5+
* This handler extracts the cache fragment key from x-amz-meta headers and
6+
* sets it as a standard Cache-Fragment-Key header while removing the original
7+
* x-amz-meta header.
8+
*
9+
* @param {CloudFrontResponseEvent} event - The CloudFront response event object
10+
* @param {Context} _context - AWS Lambda context object (unused)
11+
* @param {CloudFrontRequestCallback} callback - Callback to return the modified response
12+
* @returns {Promise<void>} - Returns nothing, uses callback to return response
13+
*/
14+
export const handler = async (
15+
event: CloudFrontResponseEvent,
16+
_context: Context,
17+
callback: CloudFrontRequestCallback
18+
) => {
19+
const response = event.Records[0].cf.response
20+
const fileCacheKey = response.headers['x-amz-meta-cache-fragment-key']?.[0].value
21+
22+
if (fileCacheKey) {
23+
response.headers['cache-fragment-key'] = [{ key: 'Cache-Fragment-Key', value: fileCacheKey }]
24+
response.headers['x-amz-meta-cache-fragment-key'] = []
25+
}
26+
27+
callback(null, response)
28+
}

0 commit comments

Comments
 (0)