feat(tsview): add database and S3 handlers, tswatch/watch scripts, web utilities, assets and release config

This commit is contained in:
2026-01-25 11:02:53 +00:00
parent cf07f8cad9
commit afc32f3578
52 changed files with 1078 additions and 237 deletions

View File

@@ -87,6 +87,43 @@ export async function registerMongoHandlers(
)
);
// Create database (by creating a placeholder collection)
typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<interfaces.IReq_CreateDatabase>(
'createDatabase',
async (reqData) => {
try {
const client = await getMongoClient();
const db = client.db(reqData.databaseName);
// Create a placeholder collection to materialize the database
await db.createCollection('_tsview_init');
return { success: true };
} catch (err) {
console.error('Error creating database:', err);
return { success: false };
}
}
)
);
// Drop database
typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<interfaces.IReq_DropDatabase>(
'dropDatabase',
async (reqData) => {
try {
const client = await getMongoClient();
const db = client.db(reqData.databaseName);
await db.dropDatabase();
return { success: true };
} catch (err) {
console.error('Error dropping database:', err);
return { success: false };
}
}
)
);
// Create collection
typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<interfaces.IReq_CreateCollection>(
@@ -105,6 +142,24 @@ export async function registerMongoHandlers(
)
);
// Drop collection
typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<interfaces.IReq_DropCollection>(
'dropCollection',
async (reqData) => {
try {
const client = await getMongoClient();
const db = client.db(reqData.databaseName);
await db.dropCollection(reqData.collectionName);
return { success: true };
} catch (err) {
console.error('Error dropping collection:', err);
return { success: false };
}
}
)
);
// Find documents
typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<interfaces.IReq_FindDocuments>(

View File

@@ -9,20 +9,29 @@ export async function registerS3Handlers(
typedrouter: plugins.typedrequest.TypedRouter,
tsview: TsView
): Promise<void> {
console.log('Registering S3 handlers...');
// List all buckets
console.log('Registering listBuckets handler');
typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<interfaces.IReq_ListBuckets>(
'listBuckets',
async () => {
console.log('listBuckets handler called');
const smartbucket = await tsview.getSmartBucket();
console.log('smartbucket:', smartbucket ? 'initialized' : 'null');
if (!smartbucket) {
console.log('returning empty buckets');
return { buckets: [] };
}
try {
const command = new plugins.s3.ListBucketsCommand({});
console.log('sending ListBucketsCommand...');
const response = await smartbucket.s3Client.send(command) as plugins.s3.ListBucketsCommandOutput;
console.log('response:', response);
const buckets = response.Buckets?.map(b => b.Name).filter((name): name is string => !!name) || [];
console.log('returning buckets:', buckets);
return { buckets };
} catch (err) {
console.error('Error listing buckets:', err);
@@ -169,10 +178,21 @@ export async function registerS3Handlers(
'html': 'text/html',
'css': 'text/css',
'js': 'application/javascript',
'ts': 'text/plain',
'tsx': 'text/plain',
'jsx': 'text/plain',
'md': 'text/markdown',
'csv': 'text/csv',
'yaml': 'text/yaml',
'yml': 'text/yaml',
'log': 'text/plain',
'sh': 'text/plain',
'env': 'text/plain',
'png': 'image/png',
'jpg': 'image/jpeg',
'jpeg': 'image/jpeg',
'gif': 'image/gif',
'webp': 'image/webp',
'svg': 'image/svg+xml',
'pdf': 'application/pdf',
'xml': 'application/xml',
@@ -216,11 +236,26 @@ export async function registerS3Handlers(
'json': 'application/json',
'txt': 'text/plain',
'html': 'text/html',
'css': 'text/css',
'js': 'application/javascript',
'ts': 'text/plain',
'tsx': 'text/plain',
'jsx': 'text/plain',
'md': 'text/markdown',
'csv': 'text/csv',
'yaml': 'text/yaml',
'yml': 'text/yaml',
'log': 'text/plain',
'sh': 'text/plain',
'env': 'text/plain',
'png': 'image/png',
'jpg': 'image/jpeg',
'jpeg': 'image/jpeg',
'gif': 'image/gif',
'webp': 'image/webp',
'svg': 'image/svg+xml',
'pdf': 'application/pdf',
'xml': 'application/xml',
};
const contentType = contentTypeMap[ext] || 'application/octet-stream';