Skip to content

Commit

Permalink
Merge pull request #51 from supabase-community/fix-cdn
Browse files Browse the repository at this point in the history
feat: Add Smart CDN Caching
  • Loading branch information
mats16 authored Jun 29, 2023
2 parents f74a629 + 005ffb2 commit 2b5bed8
Show file tree
Hide file tree
Showing 14 changed files with 468 additions and 141 deletions.
5 changes: 5 additions & 0 deletions .projen/deps.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions .projenrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const project = new awscdk.AwsCdkTypeScriptApp({
'@databases/pg',
'@types/aws-lambda',
'cdk-bootstrapless-synthesizer@^2.2.2',
'hono@^3.2.6',
'jsonwebtoken@^8.5.1',
'utf8',
],
Expand Down
1 change: 1 addition & 0 deletions package.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

File renamed without changes.
11 changes: 8 additions & 3 deletions src/aws-waf-for-cloudfront.ts → src/aws-waf/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as path from 'path';
import * as cdk from 'aws-cdk-lib';
import * as iam from 'aws-cdk-lib/aws-iam';
import * as lambda from 'aws-cdk-lib/aws-lambda';
Expand All @@ -8,12 +9,14 @@ import { Construct } from 'constructs';
export class WebAcl extends cdk.NestedStack {
webAclArn: string;

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

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

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

/** Web ACL */
const resource = new cdk.CustomResource(this, 'Resource', {
resourceType: 'Custom::WebACL',
serviceToken: crProvider.serviceToken,
properties: {
Name: this.node.path.replace(/\//g, '-'),
Description: this.node.path,
Fingerprint: cdk.FileSystem.fingerprint('./src/functions/create-web-acl.ts'),
Fingerprint: cdk.FileSystem.fingerprint(path.resolve(__dirname, 'cr-web-acl.ts')),
},
});
this.webAclArn = resource.getAttString('Arn');

this.webAclArn = resource.getAttString('Arn');
}
};
36 changes: 0 additions & 36 deletions src/functions/cdn-cache-manager/api.ts

This file was deleted.

80 changes: 0 additions & 80 deletions src/functions/db-secret-sync.ts

This file was deleted.

47 changes: 47 additions & 0 deletions src/supabase-cdn/cache-manager/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { Logger } from '@aws-lambda-powertools/logger';
import { Tracer } from '@aws-lambda-powertools/tracer';
import { SQSClient, SendMessageCommand } from '@aws-sdk/client-sqs';
import { Handler } from 'aws-lambda';
import { Hono } from 'hono';
import { handle } from 'hono/aws-lambda';
import { bearerAuth } from 'hono/bearer-auth';
import { WebhookEvent } from './types';

const region = process.env.AWS_REGION;
const queueUrl = process.env.QUEUE_URL;
const token = process.env.API_KEY!;
const eventList = process.env.EVENT_LIST!.split(',');

const logger = new Logger();
const tracer = new Tracer();
const sqs = tracer.captureAWSv3Client(new SQSClient({ region }));

/**
* Send message to SQS
* @param message webhook event
* @returns void
*/
const enqueue = async (message: object) => {
const cmd = new SendMessageCommand({
QueueUrl: queueUrl,
MessageBody: JSON.stringify(message),
});
await sqs.send(cmd);
};

/** Hono app */
const app = new Hono();

/** Webhook endpoint */
app.post('/', bearerAuth({ token }), async (c) => {
const body: WebhookEvent = await c.req.json();
console.log(JSON.stringify(body));

if (eventList.includes(body.event.type)) {
await enqueue(body);
}
return c.text('Accepted', 202);
});

/** Lambda handler */
export const handler = handle(app) as Handler;
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const logger = new Logger();
const tracer = new Tracer();
const cloudfront = tracer.captureAWSv3Client(new CloudFrontClient({ region: 'us-east-1' }));

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

/** Convert webhook event to CloudFront paths. */
const eventToPath = (event: WebhookEvent): string[] => {
const bucketId = event.event.payload.bucketId;
const objectName = event.event.payload.name;
return [`/storage/v1/object/${bucketId}/${objectName}`, `/storage/v1/object/public/${bucketId}/${objectName}`];
const objectPaths = [
`/storage/v1/object/${bucketId}/${objectName}*`,
`/storage/v1/object/sign/${bucketId}/${objectName}*`,
`/storage/v1/object/public/${bucketId}/${objectName}*`,
];
return objectPaths;
};

export const handler: SQSHandler = async (event, context) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export type ObjectMetadata = {
httpStatusCode: number;
}

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

// https://github.com/supabase/storage-api/blob/master/src/queue/events/object-created.ts
interface ObjectCreatedEvent extends BasePayload {
name: string;
bucketId: string;
metadata: ObjectMetadata;
}

// https://github.com/supabase/storage-api/blob/master/src/queue/events/object-removed.ts
interface ObjectRemovedEvent extends BasePayload {
name: string;
bucketId: string;
}

// https://github.com/supabase/storage-api/blob/master/src/queue/events/object-updated.ts
interface ObjectUpdatedMetadataEvent extends BasePayload {
name: string;
bucketId: string;
metadata: ObjectMetadata;
}

type EventName = 'ObjectCreated:Put'|'ObjectCreated:Post'|'ObjectCreated:Copy'|'ObjectCreated:Move'|'ObjectRemoved:Delete'|'ObjectRemoved:Move'|'ObjectUpdated:Metadata'

// https://github.com/supabase/storage-api/blob/master/src/queue/events/webhook.ts#L9
export interface WebhookEvent {
type: string;
event: {
$version: string;
type: string;
type: EventName;
payload: ObjectCreatedEvent|ObjectRemovedEvent|ObjectUpdatedMetadataEvent;
applyTime: number;
};
Expand Down
Loading

0 comments on commit 2b5bed8

Please sign in to comment.