Something went wrong. Try again.
Periodic backups of ATProto repos and blobs safekeeper.dummy.cafe
atproto backup
Something went wrong. Try again.
1.8 kB · 65 lines
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566// Storage abstraction//// All backup artifacts (repo CARs, blobs) go through this interface, so// swapping the backend (local FS today, S3/WebDAV tomorrow) is a drop-in.//// Paths are forward-slash logical paths (e.g. "repos/did:plc:abc/2026-04-18.car").// Backends are responsible for any on-disk encoding they need.
import { env } from '../env';import { LocalStorage } from './local';
export interface StorageUsage { // Bytes currently occupied by our stored artifacts. usedBytes: number; // Bytes free on the backing device, or null for backends where this is // not well-defined (e.g. S3). freeBytes: number | null; // Total bytes on the backing device, or null where not well-defined. totalBytes: number | null;}
export interface StorageEntry { path: string; size: number; mtime: Date;}
export interface Storage { put( path: string, data: Uint8Array | ReadableStream<Uint8Array> ): Promise<void>;
get(path: string): Promise<ReadableStream<Uint8Array> | null>;
exists(path: string): Promise<boolean>;
delete(path: string): Promise<void>;
stat(path: string): Promise<{ size: number; mtime: Date } | null>;
// Recursive listing. Yields every object under the prefix. list(prefix: string): AsyncIterable<StorageEntry>;
// Aggregate size under a prefix. Implementations may cache / optimise. sizeOf(prefix: string): Promise<number>;
// Overall backing-device usage stats. usage(): Promise<StorageUsage>;}
let _storage: Storage | null = null;
export function storage(): Storage { if (_storage) return _storage; switch (env.STORAGE_BACKEND) { case 'local': _storage = new LocalStorage(env.STORAGE_LOCAL_ROOT); return _storage; default: { const _exhaustive: never = env.STORAGE_BACKEND; throw new Error(`Unknown storage backend: ${_exhaustive}`); } }}