feat: add SQS + EventBridge

This commit is contained in:
Zakaria
2026-09-24 22:34:04 -04:00
parent 9bbe80b5f2
commit 1b129e9dcf
37 changed files with 2902 additions and 66 deletions
@@ -1,9 +1,12 @@
import {describe, expect, test} from 'bun:test'
import {
GetBucketNotificationConfigurationCommand,
GetBucketTaggingCommand,
ListBucketsCommand,
PutBucketNotificationConfigurationCommand,
type S3Client,
} from '@aws-sdk/client-s3'
import {AddPermissionCommand, GetFunctionCommand, RemovePermissionCommand, type LambdaClient} from '@aws-sdk/client-lambda'
import {AwsStorageAdapter} from './AwsStorageAdapter'
function fakeS3(overrides: Partial<{
@@ -100,4 +103,90 @@ describe('AwsStorageAdapter', () => {
expect(result.map((r) => r.name).sort()).toEqual(['prod-assets', 'prod-logs'])
expect(requestedBuckets.sort()).toEqual(['prod-assets', 'prod-logs'])
})
test('adds an S3 Lambda trigger without replacing other bucket notifications', async () => {
const sent: unknown[] = []
const s3 = {
send: async (command: unknown) => {
sent.push(command)
if (command instanceof GetBucketNotificationConfigurationCommand) {
return {
QueueConfigurations: [{Id: 'queue-trigger', QueueArn: 'arn:aws:sqs:us-east-1:000000000000:jobs', Events: ['s3:ObjectCreated:*']}],
EventBridgeConfiguration: {},
}
}
if (command instanceof PutBucketNotificationConfigurationCommand) return {}
throw new Error(`Unexpected command: ${command?.constructor?.name}`)
},
} as unknown as S3Client
const lambda = fakeLambda()
const adapter = new AwsStorageAdapter(s3, lambda.client, '000000000000')
await adapter.createS3LambdaTrigger('uploads', {
functionName: 'thumbnailer',
events: ['s3:ObjectCreated:*'],
prefix: 'images/',
suffix: '.jpg',
})
const put = sent.find((command) => command instanceof PutBucketNotificationConfigurationCommand) as PutBucketNotificationConfigurationCommand
expect(put.input.NotificationConfiguration?.QueueConfigurations).toHaveLength(1)
expect(put.input.NotificationConfiguration?.EventBridgeConfiguration).toEqual({})
expect(put.input.NotificationConfiguration?.LambdaFunctionConfigurations).toEqual([{
Id: 'floci-ui-s3-thumbnailer-s3-ObjectCreated---images---jpg',
LambdaFunctionArn: 'arn:aws:lambda:us-east-1:000000000000:function:thumbnailer',
Events: ['s3:ObjectCreated:*'],
Filter: {Key: {FilterRules: [{Name: 'prefix', Value: 'images/'}, {Name: 'suffix', Value: '.jpg'}]}},
}])
const permission = lambda.sent.find((command) => command instanceof AddPermissionCommand) as AddPermissionCommand
expect(permission.input).toMatchObject({
FunctionName: 'thumbnailer',
Principal: 's3.amazonaws.com',
SourceArn: 'arn:aws:s3:::uploads',
SourceAccount: '000000000000',
})
})
test('removes the S3 permission only after the final bucket trigger for a Lambda is deleted', async () => {
const sent: unknown[] = []
const s3 = {
send: async (command: unknown) => {
sent.push(command)
if (command instanceof GetBucketNotificationConfigurationCommand) {
return {LambdaFunctionConfigurations: [{
Id: 'trigger-a',
LambdaFunctionArn: 'arn:aws:lambda:us-east-1:000000000000:function:thumbnailer',
Events: ['s3:ObjectCreated:*'],
}]}
}
if (command instanceof PutBucketNotificationConfigurationCommand) return {}
throw new Error(`Unexpected command: ${command?.constructor?.name}`)
},
} as unknown as S3Client
const lambda = fakeLambda()
const adapter = new AwsStorageAdapter(s3, lambda.client)
await adapter.deleteS3LambdaTrigger('uploads', 'trigger-a')
const put = sent.find((command) => command instanceof PutBucketNotificationConfigurationCommand) as PutBucketNotificationConfigurationCommand
expect(put.input.NotificationConfiguration?.LambdaFunctionConfigurations).toEqual([])
expect(lambda.sent.some((command) => command instanceof RemovePermissionCommand)).toBe(true)
})
})
function fakeLambda(): {client: LambdaClient; sent: unknown[]} {
const sent: unknown[] = []
return {
sent,
client: {
send: async (command: unknown) => {
sent.push(command)
if (command instanceof GetFunctionCommand) {
return {Configuration: {FunctionArn: 'arn:aws:lambda:us-east-1:000000000000:function:thumbnailer'}}
}
if (command instanceof AddPermissionCommand || command instanceof RemovePermissionCommand) return {}
throw new Error(`Unexpected command: ${command?.constructor?.name}`)
},
} as unknown as LambdaClient,
}
}