157 lines
5.1 KiB
TypeScript
157 lines
5.1 KiB
TypeScript
import { html } from '@design.estate/dees-element';
|
|
import type { IS3DataProvider, IS3Object } from './interfaces.js';
|
|
import './dees-s3-browser.js';
|
|
|
|
// Mock in-memory S3 data provider for demo purposes
|
|
class MockS3DataProvider implements IS3DataProvider {
|
|
private objects: Map<string, { content: string; contentType: string; size: number; lastModified: string }> = new Map();
|
|
|
|
constructor() {
|
|
const now = new Date().toISOString();
|
|
// Seed with sample data
|
|
this.objects.set('documents/readme.md', {
|
|
content: btoa('# Welcome\n\nThis is a demo S3 browser.\n'),
|
|
contentType: 'text/markdown',
|
|
size: 42,
|
|
lastModified: now,
|
|
});
|
|
this.objects.set('documents/config.json', {
|
|
content: btoa('{\n "name": "demo",\n "version": "1.0.0"\n}'),
|
|
contentType: 'application/json',
|
|
size: 48,
|
|
lastModified: now,
|
|
});
|
|
this.objects.set('documents/notes/todo.txt', {
|
|
content: btoa('Buy milk\nFix bug #42\nDeploy to production'),
|
|
contentType: 'text/plain',
|
|
size: 45,
|
|
lastModified: now,
|
|
});
|
|
this.objects.set('images/logo.png', {
|
|
content: btoa('fake-png-data'),
|
|
contentType: 'image/png',
|
|
size: 24500,
|
|
lastModified: now,
|
|
});
|
|
this.objects.set('images/banner.jpg', {
|
|
content: btoa('fake-jpg-data'),
|
|
contentType: 'image/jpeg',
|
|
size: 156000,
|
|
lastModified: now,
|
|
});
|
|
this.objects.set('scripts/deploy.sh', {
|
|
content: btoa('#!/bin/bash\necho "Deploying..."\n'),
|
|
contentType: 'text/plain',
|
|
size: 34,
|
|
lastModified: now,
|
|
});
|
|
this.objects.set('index.html', {
|
|
content: btoa('<!DOCTYPE html>\n<html>\n<body>\n <h1>Hello World</h1>\n</body>\n</html>'),
|
|
contentType: 'text/html',
|
|
size: 72,
|
|
lastModified: now,
|
|
});
|
|
this.objects.set('styles.css', {
|
|
content: btoa('body { margin: 0; font-family: sans-serif; }'),
|
|
contentType: 'text/css',
|
|
size: 44,
|
|
lastModified: now,
|
|
});
|
|
}
|
|
|
|
async listObjects(bucket: string, prefix?: string, delimiter?: string): Promise<{ objects: IS3Object[]; prefixes: string[] }> {
|
|
const pfx = prefix || '';
|
|
const objects: IS3Object[] = [];
|
|
const prefixes = new Set<string>();
|
|
|
|
for (const [key, data] of this.objects) {
|
|
if (!key.startsWith(pfx)) continue;
|
|
const rest = key.slice(pfx.length);
|
|
|
|
if (delimiter) {
|
|
const slashIndex = rest.indexOf(delimiter);
|
|
if (slashIndex >= 0) {
|
|
prefixes.add(pfx + rest.slice(0, slashIndex + 1));
|
|
} else {
|
|
objects.push({ key, size: data.size, lastModified: data.lastModified });
|
|
}
|
|
} else {
|
|
objects.push({ key, size: data.size, lastModified: data.lastModified });
|
|
}
|
|
}
|
|
|
|
return { objects, prefixes: Array.from(prefixes).sort() };
|
|
}
|
|
|
|
async getObject(bucket: string, key: string): Promise<{ content: string; contentType: string; size: number; lastModified: string }> {
|
|
const obj = this.objects.get(key);
|
|
if (!obj) throw new Error('Not found');
|
|
return { ...obj };
|
|
}
|
|
|
|
async putObject(bucket: string, key: string, base64Content: string, contentType: string): Promise<boolean> {
|
|
this.objects.set(key, {
|
|
content: base64Content,
|
|
contentType,
|
|
size: atob(base64Content).length,
|
|
lastModified: new Date().toISOString(),
|
|
});
|
|
return true;
|
|
}
|
|
|
|
async deleteObject(bucket: string, key: string): Promise<boolean> {
|
|
return this.objects.delete(key);
|
|
}
|
|
|
|
async deletePrefix(bucket: string, prefix: string): Promise<boolean> {
|
|
for (const key of this.objects.keys()) {
|
|
if (key.startsWith(prefix)) {
|
|
this.objects.delete(key);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
async getObjectUrl(bucket: string, key: string): Promise<string> {
|
|
const obj = this.objects.get(key);
|
|
if (!obj) return '';
|
|
const blob = new Blob([Uint8Array.from(atob(obj.content), c => c.charCodeAt(0))], { type: obj.contentType });
|
|
return URL.createObjectURL(blob);
|
|
}
|
|
|
|
async moveObject(bucket: string, sourceKey: string, destKey: string): Promise<{ success: boolean; error?: string }> {
|
|
const obj = this.objects.get(sourceKey);
|
|
if (!obj) return { success: false, error: 'Source not found' };
|
|
this.objects.set(destKey, { ...obj, lastModified: new Date().toISOString() });
|
|
this.objects.delete(sourceKey);
|
|
return { success: true };
|
|
}
|
|
|
|
async movePrefix(bucket: string, sourcePrefix: string, destPrefix: string): Promise<{ success: boolean; movedCount?: number; error?: string }> {
|
|
let count = 0;
|
|
const toMove = Array.from(this.objects.entries()).filter(([k]) => k.startsWith(sourcePrefix));
|
|
for (const [key, data] of toMove) {
|
|
const newKey = destPrefix + key.slice(sourcePrefix.length);
|
|
this.objects.set(newKey, { ...data, lastModified: new Date().toISOString() });
|
|
this.objects.delete(key);
|
|
count++;
|
|
}
|
|
return { success: true, movedCount: count };
|
|
}
|
|
}
|
|
|
|
export const demoFunc = () => html`
|
|
<style>
|
|
.demo-container {
|
|
height: 600px;
|
|
padding: 16px;
|
|
}
|
|
</style>
|
|
<div class="demo-container">
|
|
<dees-s3-browser
|
|
.dataProvider=${new MockS3DataProvider()}
|
|
.bucketName=${'demo-bucket'}
|
|
></dees-s3-browser>
|
|
</div>
|
|
`;
|