Spaces:
Running
Running
File size: 2,091 Bytes
0d57d79 874bd3c 0d57d79 874bd3c d594446 874bd3c 0d57d79 874bd3c 0d57d79 d594446 0d57d79 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | export interface StoreEntry {
path: string;
size: number;
uploadedAt?: Date;
}
/**
* Minimal object-store abstraction. Paths are bucket-relative, use `/` separators,
* and never start with `/`.
*/
export interface BucketStore {
/** Resolves null when the object does not exist. */
get(path: string): Promise<Uint8Array | null>;
/** Creates or overwrites. */
put(path: string, bytes: Uint8Array, contentType?: string): Promise<void>;
/**
* Appends bytes to an existing object, creating it if missing. Not atomic on every
* backend: a crash mid-append may leave a truncated final line, so readers must
* tolerate a trailing partial line.
*/
append(path: string, bytes: Uint8Array): Promise<void>;
/**
* Lists files whose path starts with `prefix`, sorted by path. The prefix must be `''`
* (the whole store) or end with `/`, so it always matches within a directory.
*/
list(prefix: string): Promise<StoreEntry[]>;
/** Deletes objects; missing ones are ignored. */
delete(paths: string[]): Promise<void>;
/** Server-side copy. Rejects if `src` does not exist. */
copy(src: string, dst: string): Promise<void>;
}
const SEGMENT_RE = /^[A-Za-z0-9._-]+$/;
export function assertValidPath(path: string): void {
if (path.length === 0 || path.length > 512) throw new Error(`Invalid path: ${path}`);
if (path.startsWith('/') || path.endsWith('/')) throw new Error(`Invalid path: ${path}`);
if (path.endsWith('.tmp')) throw new Error(`Invalid path: ${path}`);
for (const seg of path.split('/')) {
if (seg === '' || seg === '.' || seg === '..' || !SEGMENT_RE.test(seg)) throw new Error(`Invalid path: ${path}`);
}
}
/** Validates a `list` prefix: either `''` or a valid path followed by `/`. */
export function assertValidPrefix(prefix: string): void {
if (prefix === '') return;
if (!prefix.endsWith('/')) throw new Error(`Invalid prefix: ${prefix}`);
assertValidPath(prefix.slice(0, -1));
}
export const encodeText = (s: string): Uint8Array => new TextEncoder().encode(s);
export const decodeText = (b: Uint8Array): string => new TextDecoder().decode(b);
|