Agent skill

S3

Use AWS S3 for object storage, file uploads, static assets, and backup storage with high availability.

Stars 10
Forks 1

Install this agent skill to your Project

npx add-skill https://github.com/hivellm/rulebook/tree/main/templates/skills/services/s3

SKILL.md

AWS S3 Storage Instructions

CRITICAL: Use AWS S3 for object storage, file uploads, static assets, and backup storage with high availability.

Core Features

Connection

typescript
// Using @aws-sdk/client-s3
import { S3Client, PutObjectCommand, GetObjectCommand, DeleteObjectCommand } from '@aws-sdk/client-s3'

const s3Client = new S3Client({
  region: process.env.AWS_REGION || 'us-east-1',
  credentials: {
    accessKeyId: process.env.AWS_ACCESS_KEY_ID || '',
    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY || '',
  },
})

// Using AWS SDK v2
import AWS from 'aws-sdk'

const s3 = new AWS.S3({
  accessKeyId: process.env.AWS_ACCESS_KEY_ID,
  secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
  region: process.env.AWS_REGION || 'us-east-1',
})

Basic Operations

typescript
// Upload file
const uploadParams = {
  Bucket: process.env.S3_BUCKET || 'my-bucket',
  Key: 'path/to/file.jpg',
  Body: fileBuffer,
  ContentType: 'image/jpeg',
  ACL: 'private', // or 'public-read'
}

await s3Client.send(new PutObjectCommand(uploadParams))

// Upload with metadata
await s3Client.send(new PutObjectCommand({
  ...uploadParams,
  Metadata: {
    userId: '123',
    originalName: 'photo.jpg',
  },
  TagSet: [
    { Key: 'category', Value: 'profile' },
  ],
}))

// Get file
const getParams = {
  Bucket: process.env.S3_BUCKET,
  Key: 'path/to/file.jpg',
}

const response = await s3Client.send(new GetObjectCommand(getParams))
const fileContent = await response.Body?.transformToByteArray()

// Delete file
await s3Client.send(new DeleteObjectCommand({
  Bucket: process.env.S3_BUCKET,
  Key: 'path/to/file.jpg',
}))

Advanced Features

typescript
// Presigned URL for upload
import { getSignedUrl } from '@aws-sdk/s3-request-presigner'

const command = new PutObjectCommand({
  Bucket: process.env.S3_BUCKET,
  Key: 'uploads/file.jpg',
  ContentType: 'image/jpeg',
})

const presignedUrl = await getSignedUrl(s3Client, command, { expiresIn: 3600 })

// Presigned URL for download
const getCommand = new GetObjectCommand({
  Bucket: process.env.S3_BUCKET,
  Key: 'path/to/file.jpg',
})

const downloadUrl = await getSignedUrl(s3Client, getCommand, { expiresIn: 3600 })

// Multipart upload (for large files)
import { CreateMultipartUploadCommand, UploadPartCommand, CompleteMultipartUploadCommand } from '@aws-sdk/client-s3'

const createCommand = new CreateMultipartUploadCommand({
  Bucket: process.env.S3_BUCKET,
  Key: 'large-file.zip',
  ContentType: 'application/zip',
})

const { UploadId } = await s3Client.send(createCommand)

// Upload parts
const part1 = await s3Client.send(new UploadPartCommand({
  Bucket: process.env.S3_BUCKET,
  Key: 'large-file.zip',
  PartNumber: 1,
  UploadId,
  Body: part1Buffer,
}))

// Complete upload
await s3Client.send(new CompleteMultipartUploadCommand({
  Bucket: process.env.S3_BUCKET,
  Key: 'large-file.zip',
  UploadId,
  MultipartUpload: {
    Parts: [
      { PartNumber: 1, ETag: part1.ETag },
    ],
  },
}))

// List objects
import { ListObjectsV2Command } from '@aws-sdk/client-s3'

const listCommand = new ListObjectsV2Command({
  Bucket: process.env.S3_BUCKET,
  Prefix: 'uploads/',
  MaxKeys: 100,
})

const { Contents } = await s3Client.send(listCommand)

Common Patterns

File Upload Handler

typescript
async function uploadFile(file: Buffer, filename: string, userId: string) {
  const key = `users/${userId}/${Date.now()}-${filename}`
  
  await s3Client.send(new PutObjectCommand({
    Bucket: process.env.S3_BUCKET,
    Key: key,
    Body: file,
    ContentType: getContentType(filename),
    Metadata: {
      userId,
      originalName: filename,
      uploadedAt: new Date().toISOString(),
    },
  }))
  
  return {
    key,
    url: `https://${process.env.S3_BUCKET}.s3.${process.env.AWS_REGION}.amazonaws.com/${key}`,
  }
}

Temporary File Access

typescript
async function generateTemporaryDownloadUrl(key: string, expiresIn: number = 3600) {
  const command = new GetObjectCommand({
    Bucket: process.env.S3_BUCKET,
    Key: key,
  })
  
  return await getSignedUrl(s3Client, command, { expiresIn })
}

File Cleanup

typescript
async function deleteFilesByPrefix(prefix: string) {
  const listCommand = new ListObjectsV2Command({
    Bucket: process.env.S3_BUCKET,
    Prefix: prefix,
  })
  
  let continuationToken: string | undefined
  
  do {
    const response = await s3Client.send({
      ...listCommand,
      ContinuationToken: continuationToken,
    })
    
    if (response.Contents) {
      for (const object of response.Contents) {
        if (object.Key) {
          await s3Client.send(new DeleteObjectCommand({
            Bucket: process.env.S3_BUCKET,
            Key: object.Key,
          }))
        }
      }
    }
    
    continuationToken = response.NextContinuationToken
  } while (continuationToken)
}

Best Practices

DO:

  • Use presigned URLs for client uploads
  • Set appropriate Content-Type headers
  • Use versioning for important files
  • Implement lifecycle policies for cleanup
  • Use multipart upload for files > 5MB
  • Enable encryption (SSE-S3 or SSE-KMS)
  • Use appropriate storage classes (Standard, IA, Glacier)
  • Implement proper error handling
  • Use bucket policies for access control
  • Monitor bucket usage and costs

DON'T:

  • Store sensitive data without encryption
  • Use public-read ACL unnecessarily
  • Hardcode credentials
  • Ignore error handling
  • Skip content-type validation
  • Store large files without multipart upload
  • Ignore lifecycle policies
  • Skip access logging
  • Use default bucket policies
  • Ignore cost optimization

Configuration

Environment Variables

bash
AWS_REGION=us-east-1
AWS_ACCESS_KEY_ID=your-access-key
AWS_SECRET_ACCESS_KEY=your-secret-key
S3_BUCKET=my-bucket

IAM Policy

json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:PutObject",
        "s3:GetObject",
        "s3:DeleteObject"
      ],
      "Resource": "arn:aws:s3:::my-bucket/*"
    }
  ]
}

Integration with Development

Testing

typescript
// Use test bucket or LocalStack
const testS3Client = new S3Client({
  endpoint: 'http://localhost:4566', // LocalStack
  region: 'us-east-1',
  credentials: {
    accessKeyId: 'test',
    secretAccessKey: 'test',
  },
  forcePathStyle: true,
})

// Clean up after tests
afterEach(async () => {
  // Delete test files
})

Health Checks

typescript
async function checkS3Health(): Promise<boolean> {
  try {
    await s3Client.send(new ListObjectsV2Command({
      Bucket: process.env.S3_BUCKET,
      MaxKeys: 1,
    }))
    return true
  } catch {
    return false
  }
}

Didn't find tool you were looking for?

Be as detailed as possible for better results