Something went wrong. Try again.
Monorepo for Aesthetic.Computer aesthetic.computer
Something went wrong. Try again.
JavaScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134#!/usr/bin/env node
/** * Check Bucket Lifecycle Policies * * Inspect Digital Ocean Spaces bucket lifecycle rules * to see if guest uploads have expiration policies. */
import { S3Client, GetBucketLifecycleConfigurationCommand } from '@aws-sdk/client-s3';import { config } from 'dotenv';
config();
const client = new S3Client({ endpoint: process.env.DO_SPACES_ENDPOINT || 'https://nyc3.digitaloceanspaces.com', region: 'us-east-1', credentials: { accessKeyId: process.env.DO_SPACES_KEY, secretAccessKey: process.env.DO_SPACES_SECRET }});
async function checkLifecyclePolicy(bucketName) { console.log(`\nπ Checking lifecycle policy for bucket: ${bucketName}\n`); try { const command = new GetBucketLifecycleConfigurationCommand({ Bucket: bucketName }); const response = await client.send(command); if (response.Rules && response.Rules.length > 0) { console.log(`β
Found ${response.Rules.length} lifecycle rule(s):\n`); response.Rules.forEach((rule, i) => { console.log(`Rule ${i + 1}: ${rule.ID || '(unnamed)'}`); console.log(` Status: ${rule.Status}`); if (rule.Prefix) { console.log(` Prefix: ${rule.Prefix}`); } if (rule.Expiration) { if (rule.Expiration.Days) { console.log(` β° Expires after: ${rule.Expiration.Days} days`); } if (rule.Expiration.Date) { console.log(` β° Expires on: ${rule.Expiration.Date}`); } if (rule.Expiration.ExpiredObjectDeleteMarker) { console.log(` ποΈ Delete expired object markers: ${rule.Expiration.ExpiredObjectDeleteMarker}`); } } else { console.log(` βΎοΈ No expiration set (files are permanent)`); } if (rule.NoncurrentVersionExpiration) { console.log(` π¦ Non-current versions expire after: ${rule.NoncurrentVersionExpiration.NoncurrentDays} days`); } if (rule.AbortIncompleteMultipartUpload) { console.log(` π Abort incomplete uploads after: ${rule.AbortIncompleteMultipartUpload.DaysAfterInitiation} days`); } console.log(); }); } else { console.log(`β
No lifecycle rules configured`); console.log(` β Files are permanent (never expire)\n`); } } catch (error) { if (error.name === 'NoSuchLifecycleConfiguration') { console.log(`β
No lifecycle configuration found`); console.log(` β Files are permanent (never expire)\n`); } else { console.error(`β Error: ${error.message}\n`); throw error; } }}
async function main() { console.log(`ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ πͺ£ Bucket Lifecycle Policy Inspector ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ`);
if (!process.env.DO_SPACES_KEY || !process.env.DO_SPACES_SECRET) { console.error('β Error: Missing Digital Ocean credentials'); console.error('\nPlease set in .env or environment:'); console.error(' DO_SPACES_KEY=your-key'); console.error(' DO_SPACES_SECRET=your-secret\n'); process.exit(1); }
const buckets = [ process.env.ART_SPACE_NAME || 'art', process.env.USER_SPACE_NAME || 'aesthetic-computer', process.env.WAND_SPACE_NAME || 'wand' ];
console.log(`π¦ Checking buckets: ${buckets.join(', ')}\n`); console.log('β'.repeat(65));
for (const bucket of buckets) { await checkLifecyclePolicy(bucket); console.log('β'.repeat(65)); }
console.log(`π‘ Summary:
If a bucket shows "No lifecycle rules" or "Files are permanent",then guest uploads DO NOT expire automatically.
To set expiration (e.g., 24 hours for guest bucket): 1. Go to Digital Ocean Spaces console 2. Select bucket β Settings β Lifecycle 3. Add rule: Expire objects after 1 day
To keep files permanent (recommended for art bucket now): β No action needed if no lifecycle rules exist β Or remove any existing expiration rules`);}
main().catch(error => { console.error('\nπ₯ Fatal error:', error.message); process.exit(1);});