Skip to content

Commit 2b5bed8

Browse files
authored
Merge pull request #51 from supabase-community/fix-cdn
feat: Add Smart CDN Caching
2 parents f74a629 + 005ffb2 commit 2b5bed8

File tree

14 files changed

+468
-141
lines changed

14 files changed

+468
-141
lines changed

.projen/deps.json

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.projenrc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const project = new awscdk.AwsCdkTypeScriptApp({
2323
'@databases/pg',
2424
'@types/aws-lambda',
2525
'cdk-bootstrapless-synthesizer@^2.2.2',
26+
'hono@^3.2.6',
2627
'jsonwebtoken@^8.5.1',
2728
'utf8',
2829
],

package.json

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
File renamed without changes.

src/aws-waf-for-cloudfront.ts renamed to src/aws-waf/index.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import * as path from 'path';
12
import * as cdk from 'aws-cdk-lib';
23
import * as iam from 'aws-cdk-lib/aws-iam';
34
import * as lambda from 'aws-cdk-lib/aws-lambda';
@@ -8,12 +9,14 @@ import { Construct } from 'constructs';
89
export class WebAcl extends cdk.NestedStack {
910
webAclArn: string;
1011

12+
/** Default Web ACL */
1113
constructor(scope: Construct, id: string, props: cdk.NestedStackProps) {
1214
super(scope, id, props);
1315

16+
/** Custom resource handler */
1417
const crFunction = new NodejsFunction(this, 'Function', {
1518
description: `Supabase - Create Web ACL Function (${this.node.path}/Function)`,
16-
entry: './src/functions/create-web-acl.ts',
19+
entry: path.resolve(__dirname, 'cr-web-acl.ts'),
1720
runtime: lambda.Runtime.NODEJS_18_X,
1821
timeout: cdk.Duration.seconds(15),
1922
initialPolicy: [
@@ -40,18 +43,20 @@ export class WebAcl extends cdk.NestedStack {
4043
],
4144
});
4245

46+
/** Custom resource provider */
4347
const crProvider = new cr.Provider(this, 'Provider', { onEventHandler: crFunction });
4448

49+
/** Web ACL */
4550
const resource = new cdk.CustomResource(this, 'Resource', {
4651
resourceType: 'Custom::WebACL',
4752
serviceToken: crProvider.serviceToken,
4853
properties: {
4954
Name: this.node.path.replace(/\//g, '-'),
5055
Description: this.node.path,
51-
Fingerprint: cdk.FileSystem.fingerprint('./src/functions/create-web-acl.ts'),
56+
Fingerprint: cdk.FileSystem.fingerprint(path.resolve(__dirname, 'cr-web-acl.ts')),
5257
},
5358
});
54-
this.webAclArn = resource.getAttString('Arn');
5559

60+
this.webAclArn = resource.getAttString('Arn');
5661
}
5762
};

src/functions/cdn-cache-manager/api.ts

Lines changed: 0 additions & 36 deletions
This file was deleted.

src/functions/db-secret-sync.ts

Lines changed: 0 additions & 80 deletions
This file was deleted.
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { Logger } from '@aws-lambda-powertools/logger';
2+
import { Tracer } from '@aws-lambda-powertools/tracer';
3+
import { SQSClient, SendMessageCommand } from '@aws-sdk/client-sqs';
4+
import { Handler } from 'aws-lambda';
5+
import { Hono } from 'hono';
6+
import { handle } from 'hono/aws-lambda';
7+
import { bearerAuth } from 'hono/bearer-auth';
8+
import { WebhookEvent } from './types';
9+
10+
const region = process.env.AWS_REGION;
11+
const queueUrl = process.env.QUEUE_URL;
12+
const token = process.env.API_KEY!;
13+
const eventList = process.env.EVENT_LIST!.split(',');
14+
15+
const logger = new Logger();
16+
const tracer = new Tracer();
17+
const sqs = tracer.captureAWSv3Client(new SQSClient({ region }));
18+
19+
/**
20+
* Send message to SQS
21+
* @param message webhook event
22+
* @returns void
23+
*/
24+
const enqueue = async (message: object) => {
25+
const cmd = new SendMessageCommand({
26+
QueueUrl: queueUrl,
27+
MessageBody: JSON.stringify(message),
28+
});
29+
await sqs.send(cmd);
30+
};
31+
32+
/** Hono app */
33+
const app = new Hono();
34+
35+
/** Webhook endpoint */
36+
app.post('/', bearerAuth({ token }), async (c) => {
37+
const body: WebhookEvent = await c.req.json();
38+
console.log(JSON.stringify(body));
39+
40+
if (eventList.includes(body.event.type)) {
41+
await enqueue(body);
42+
}
43+
return c.text('Accepted', 202);
44+
});
45+
46+
/** Lambda handler */
47+
export const handler = handle(app) as Handler;

src/functions/cdn-cache-manager/queue-consumer.ts renamed to src/supabase-cdn/cache-manager/queue-consumer.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const logger = new Logger();
1010
const tracer = new Tracer();
1111
const cloudfront = tracer.captureAWSv3Client(new CloudFrontClient({ region: 'us-east-1' }));
1212

13+
/** Create CloudFront invalidation. */
1314
const createInvalidation = async(paths: string[], callerReference: string) => {
1415
const cmd = new CreateInvalidationCommand({
1516
DistributionId: distributionId,
@@ -25,10 +26,16 @@ const createInvalidation = async(paths: string[], callerReference: string) => {
2526
return output;
2627
};
2728

29+
/** Convert webhook event to CloudFront paths. */
2830
const eventToPath = (event: WebhookEvent): string[] => {
2931
const bucketId = event.event.payload.bucketId;
3032
const objectName = event.event.payload.name;
31-
return [`/storage/v1/object/${bucketId}/${objectName}`, `/storage/v1/object/public/${bucketId}/${objectName}`];
33+
const objectPaths = [
34+
`/storage/v1/object/${bucketId}/${objectName}*`,
35+
`/storage/v1/object/sign/${bucketId}/${objectName}*`,
36+
`/storage/v1/object/public/${bucketId}/${objectName}*`,
37+
];
38+
return objectPaths;
3239
};
3340

3441
export const handler: SQSHandler = async (event, context) => {

src/functions/cdn-cache-manager/types.ts renamed to src/supabase-cdn/cache-manager/types.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export type ObjectMetadata = {
1010
httpStatusCode: number;
1111
}
1212

13-
// https://github.com/supabase/storage-api/blob/master/src/queue/events/base-event.ts#L10
13+
// https://github.com/supabase/storage-api/blob/master/src/queue/events/base-event.ts
1414
export interface BasePayload {
1515
$version: string;
1616
tenant: {
@@ -19,27 +19,34 @@ export interface BasePayload {
1919
};
2020
}
2121

22+
// https://github.com/supabase/storage-api/blob/master/src/queue/events/object-created.ts
2223
interface ObjectCreatedEvent extends BasePayload {
2324
name: string;
2425
bucketId: string;
2526
metadata: ObjectMetadata;
2627
}
28+
29+
// https://github.com/supabase/storage-api/blob/master/src/queue/events/object-removed.ts
2730
interface ObjectRemovedEvent extends BasePayload {
2831
name: string;
2932
bucketId: string;
3033
}
34+
35+
// https://github.com/supabase/storage-api/blob/master/src/queue/events/object-updated.ts
3136
interface ObjectUpdatedMetadataEvent extends BasePayload {
3237
name: string;
3338
bucketId: string;
3439
metadata: ObjectMetadata;
3540
}
3641

42+
type EventName = 'ObjectCreated:Put'|'ObjectCreated:Post'|'ObjectCreated:Copy'|'ObjectCreated:Move'|'ObjectRemoved:Delete'|'ObjectRemoved:Move'|'ObjectUpdated:Metadata'
43+
3744
// https://github.com/supabase/storage-api/blob/master/src/queue/events/webhook.ts#L9
3845
export interface WebhookEvent {
3946
type: string;
4047
event: {
4148
$version: string;
42-
type: string;
49+
type: EventName;
4350
payload: ObjectCreatedEvent|ObjectRemovedEvent|ObjectUpdatedMetadataEvent;
4451
applyTime: number;
4552
};

0 commit comments

Comments
 (0)