spaces-storage

Spaces Object Storage Skill

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "spaces-storage" with this command: npx skills add vanman2024/ai-dev-marketplace/vanman2024-ai-dev-marketplace-spaces-storage

Spaces Object Storage Skill

Overview

DigitalOcean Spaces provides S3-compatible object storage. Use it for:

  • File uploads (images, documents, media)

  • Static asset hosting

  • Application backups

  • Data lake storage

Setup

Create Space

doctl spaces create my-space --region nyc3

CDN (Built-in)

Enable CDN for faster global access to your assets.

CDN endpoint

https://my-space.nyc3.cdn.digitaloceanspaces.com/file.jpg

Direct endpoint

https://my-space.nyc3.digitaloceanspaces.com/file.jpg

SDK Integration

Node.js (@aws-sdk/client-s3)

import { S3Client, PutObjectCommand, GetObjectCommand, DeleteObjectCommand, ListObjectsV2Command, } from '@aws-sdk/client-s3'; import { getSignedUrl } from '@aws-sdk/s3-request-presigner';

const s3 = new S3Client({ endpoint: 'https://nyc3.digitaloceanspaces.com', region: 'nyc3', credentials: { accessKeyId: process.env.DIGITALOCEAN_SPACES_ACCESS_KEY!, secretAccessKey: process.env.DIGITALOCEAN_SPACES_SECRET_KEY!, }, });

const BUCKET = 'my-space';

// Upload file async function uploadFile(key: string, body: Buffer, contentType: string) { await s3.send( new PutObjectCommand({ Bucket: BUCKET, Key: key, Body: body, ContentType: contentType, ACL: 'public-read', // or "private" }) );

return https://${BUCKET}.nyc3.cdn.digitaloceanspaces.com/${key}; }

// Download file async function downloadFile(key: string) { const response = await s3.send( new GetObjectCommand({ Bucket: BUCKET, Key: key, }) );

return response.Body; }

// Generate presigned URL (for private uploads) async function getPresignedUploadUrl(key: string, expiresIn = 3600) { const command = new PutObjectCommand({ Bucket: BUCKET, Key: key, });

return getSignedUrl(s3, command, { expiresIn }); }

// Generate presigned download URL (for private files) async function getPresignedDownloadUrl(key: string, expiresIn = 3600) { const command = new GetObjectCommand({ Bucket: BUCKET, Key: key, });

return getSignedUrl(s3, command, { expiresIn }); }

// List files async function listFiles(prefix = '') { const response = await s3.send( new ListObjectsV2Command({ Bucket: BUCKET, Prefix: prefix, }) );

return response.Contents || []; }

// Delete file async function deleteFile(key: string) { await s3.send( new DeleteObjectCommand({ Bucket: BUCKET, Key: key, }) ); }

Python (boto3)

import boto3 from botocore.config import Config

session = boto3.session.Session() s3 = session.client( 's3', region_name='nyc3', endpoint_url='https://nyc3.digitaloceanspaces.com', aws_access_key_id=os.environ['DIGITALOCEAN_SPACES_ACCESS_KEY'], aws_secret_access_key=os.environ['DIGITALOCEAN_SPACES_SECRET_KEY'] )

BUCKET = 'my-space'

Upload file

def upload_file(key: str, file_path: str, content_type: str = None): extra_args = {'ACL': 'public-read'} if content_type: extra_args['ContentType'] = content_type

s3.upload_file(file_path, BUCKET, key, ExtraArgs=extra_args)
return f'https://{BUCKET}.nyc3.cdn.digitaloceanspaces.com/{key}'

Upload from memory

def upload_bytes(key: str, data: bytes, content_type: str): s3.put_object( Bucket=BUCKET, Key=key, Body=data, ContentType=content_type, ACL='public-read' ) return f'https://{BUCKET}.nyc3.cdn.digitaloceanspaces.com/{key}'

Download file

def download_file(key: str, file_path: str): s3.download_file(BUCKET, key, file_path)

Generate presigned URL

def get_presigned_url(key: str, expires_in: int = 3600): return s3.generate_presigned_url( 'get_object', Params={'Bucket': BUCKET, 'Key': key}, ExpiresIn=expires_in )

List files

def list_files(prefix: str = ''): response = s3.list_objects_v2(Bucket=BUCKET, Prefix=prefix) return response.get('Contents', [])

Delete file

def delete_file(key: str): s3.delete_object(Bucket=BUCKET, Key=key)

Next.js Integration

API Route for File Upload

// app/api/upload/route.ts import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3'; import { getSignedUrl } from '@aws-sdk/s3-request-presigner'; import { nanoid } from 'nanoid';

const s3 = new S3Client({ endpoint: 'https://nyc3.digitaloceanspaces.com', region: 'nyc3', credentials: { accessKeyId: process.env.DIGITALOCEAN_SPACES_ACCESS_KEY!, secretAccessKey: process.env.DIGITALOCEAN_SPACES_SECRET_KEY!, }, });

export async function POST(request: Request) { const { filename, contentType } = await request.json();

const key = uploads/${nanoid()}-${filename};

const command = new PutObjectCommand({ Bucket: process.env.DIGITALOCEAN_SPACES_BUCKET!, Key: key, ContentType: contentType, ACL: 'public-read', });

const uploadUrl = await getSignedUrl(s3, command, { expiresIn: 3600 }); const publicUrl = https://${process.env.DIGITALOCEAN_SPACES_BUCKET}.nyc3.cdn.digitaloceanspaces.com/${key};

return Response.json({ uploadUrl, publicUrl, key }); }

Client Upload Component

"use client";

import { useState } from "react";

export function FileUpload({ onUpload }: { onUpload: (url: string) => void }) { const [uploading, setUploading] = useState(false);

async function handleUpload(e: React.ChangeEvent<HTMLInputElement>) { const file = e.target.files?.[0]; if (!file) return;

setUploading(true);

try {
  // Get presigned URL
  const response = await fetch("/api/upload", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      filename: file.name,
      contentType: file.type,
    }),
  });

  const { uploadUrl, publicUrl } = await response.json();

  // Upload directly to Spaces
  await fetch(uploadUrl, {
    method: "PUT",
    headers: { "Content-Type": file.type },
    body: file,
  });

  onUpload(publicUrl);
} finally {
  setUploading(false);
}

}

return ( <input type="file" onChange={handleUpload} disabled={uploading} /> ); }

FastAPI Integration

from fastapi import FastAPI, UploadFile import boto3 from nanoid import generate

app = FastAPI()

s3 = boto3.client( 's3', region_name='nyc3', endpoint_url='https://nyc3.digitaloceanspaces.com', aws_access_key_id=os.environ['DIGITALOCEAN_SPACES_ACCESS_KEY'], aws_secret_access_key=os.environ['DIGITALOCEAN_SPACES_SECRET_KEY'] )

BUCKET = os.environ['DIGITALOCEAN_SPACES_BUCKET']

@app.post("/upload") async def upload_file(file: UploadFile): key = f"uploads/{generate()}-{file.filename}"

s3.upload_fileobj(
    file.file,
    BUCKET,
    key,
    ExtraArgs={
        'ACL': 'public-read',
        'ContentType': file.content_type
    }
)

return {
    "url": f"https://{BUCKET}.nyc3.cdn.digitaloceanspaces.com/{key}",
    "key": key
}

Environment Variables

.env

DIGITALOCEAN_SPACES_ACCESS_KEY=your_access_key DIGITALOCEAN_SPACES_SECRET_KEY=your_secret_key DIGITALOCEAN_SPACES_BUCKET=my-space DIGITALOCEAN_SPACES_REGION=nyc3 DIGITALOCEAN_SPACES_ENDPOINT=https://nyc3.digitaloceanspaces.com

CORS Configuration

Configure CORS via the DigitalOcean console or API:

{ "CORSRules": [ { "AllowedOrigins": ["https://myapp.com"], "AllowedMethods": ["GET", "PUT", "POST"], "AllowedHeaders": ["*"], "MaxAgeSeconds": 3000 } ] }

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

document-parsers

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

stt-integration

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

model-routing-patterns

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

react-email-templates

No summary provided by upstream source.

Repository SourceNeeds Review