332 lines
9.3 KiB
TypeScript
332 lines
9.3 KiB
TypeScript
import * as plugins from '../plugins.js';
|
|
|
|
// Import interfaces from shared types
|
|
// Note: In bundled form these are inlined
|
|
export interface IS3Object {
|
|
key: string;
|
|
size?: number;
|
|
lastModified?: string;
|
|
isPrefix?: boolean;
|
|
}
|
|
|
|
export interface IMongoDatabase {
|
|
name: string;
|
|
sizeOnDisk?: number;
|
|
empty?: boolean;
|
|
}
|
|
|
|
export interface IMongoCollection {
|
|
name: string;
|
|
count?: number;
|
|
}
|
|
|
|
export interface IMongoIndex {
|
|
name: string;
|
|
keys: Record<string, number>;
|
|
unique?: boolean;
|
|
sparse?: boolean;
|
|
}
|
|
|
|
export interface ICollectionStats {
|
|
count: number;
|
|
size: number;
|
|
avgObjSize: number;
|
|
storageSize: number;
|
|
indexCount: number;
|
|
}
|
|
|
|
/**
|
|
* API service for communicating with the tsview backend
|
|
*/
|
|
export class ApiService {
|
|
private baseUrl: string;
|
|
|
|
constructor() {
|
|
// Use current origin for API calls - TypedServer expects /typedrequest endpoint
|
|
this.baseUrl = window.location.origin + '/typedrequest';
|
|
}
|
|
|
|
/**
|
|
* Make a typed request to the backend
|
|
*/
|
|
private async request<TReq, TRes>(method: string, requestData: TReq): Promise<TRes> {
|
|
const typedRequest = new plugins.typedrequest.TypedRequest<{
|
|
method: string;
|
|
request: TReq;
|
|
response: TRes;
|
|
}>(this.baseUrl, method);
|
|
|
|
const response = await typedRequest.fire(requestData);
|
|
return response;
|
|
}
|
|
|
|
// ===========================================
|
|
// S3 API Methods
|
|
// ===========================================
|
|
|
|
async listBuckets(): Promise<string[]> {
|
|
const result = await this.request<{}, { buckets: string[] }>('listBuckets', {});
|
|
return result.buckets;
|
|
}
|
|
|
|
async createBucket(bucketName: string): Promise<boolean> {
|
|
const result = await this.request<{ bucketName: string }, { success: boolean }>(
|
|
'createBucket',
|
|
{ bucketName }
|
|
);
|
|
return result.success;
|
|
}
|
|
|
|
async deleteBucket(bucketName: string): Promise<boolean> {
|
|
const result = await this.request<{ bucketName: string }, { success: boolean }>(
|
|
'deleteBucket',
|
|
{ bucketName }
|
|
);
|
|
return result.success;
|
|
}
|
|
|
|
async listObjects(
|
|
bucketName: string,
|
|
prefix?: string,
|
|
delimiter?: string
|
|
): Promise<{ objects: IS3Object[]; prefixes: string[] }> {
|
|
return this.request('listObjects', { bucketName, prefix, delimiter });
|
|
}
|
|
|
|
async getObject(
|
|
bucketName: string,
|
|
key: string
|
|
): Promise<{ content: string; contentType: string; size: number; lastModified: string }> {
|
|
return this.request('getObject', { bucketName, key });
|
|
}
|
|
|
|
async getObjectMetadata(
|
|
bucketName: string,
|
|
key: string
|
|
): Promise<{ contentType: string; size: number; lastModified: string }> {
|
|
return this.request('getObjectMetadata', { bucketName, key });
|
|
}
|
|
|
|
async putObject(
|
|
bucketName: string,
|
|
key: string,
|
|
content: string,
|
|
contentType: string
|
|
): Promise<boolean> {
|
|
const result = await this.request<
|
|
{ bucketName: string; key: string; content: string; contentType: string },
|
|
{ success: boolean }
|
|
>('putObject', { bucketName, key, content, contentType });
|
|
return result.success;
|
|
}
|
|
|
|
async deleteObject(bucketName: string, key: string): Promise<boolean> {
|
|
const result = await this.request<
|
|
{ bucketName: string; key: string },
|
|
{ success: boolean }
|
|
>('deleteObject', { bucketName, key });
|
|
return result.success;
|
|
}
|
|
|
|
async copyObject(
|
|
sourceBucket: string,
|
|
sourceKey: string,
|
|
destBucket: string,
|
|
destKey: string
|
|
): Promise<boolean> {
|
|
const result = await this.request<
|
|
{ sourceBucket: string; sourceKey: string; destBucket: string; destKey: string },
|
|
{ success: boolean }
|
|
>('copyObject', { sourceBucket, sourceKey, destBucket, destKey });
|
|
return result.success;
|
|
}
|
|
|
|
// ===========================================
|
|
// MongoDB API Methods
|
|
// ===========================================
|
|
|
|
async listDatabases(): Promise<IMongoDatabase[]> {
|
|
const result = await this.request<{}, { databases: IMongoDatabase[] }>(
|
|
'listDatabases',
|
|
{}
|
|
);
|
|
return result.databases;
|
|
}
|
|
|
|
async createDatabase(databaseName: string): Promise<boolean> {
|
|
const result = await this.request<{ databaseName: string }, { success: boolean }>(
|
|
'createDatabase',
|
|
{ databaseName }
|
|
);
|
|
return result.success;
|
|
}
|
|
|
|
async dropDatabase(databaseName: string): Promise<boolean> {
|
|
const result = await this.request<{ databaseName: string }, { success: boolean }>(
|
|
'dropDatabase',
|
|
{ databaseName }
|
|
);
|
|
return result.success;
|
|
}
|
|
|
|
async listCollections(databaseName: string): Promise<IMongoCollection[]> {
|
|
const result = await this.request<
|
|
{ databaseName: string },
|
|
{ collections: IMongoCollection[] }
|
|
>('listCollections', { databaseName });
|
|
return result.collections;
|
|
}
|
|
|
|
async createCollection(databaseName: string, collectionName: string): Promise<boolean> {
|
|
const result = await this.request<
|
|
{ databaseName: string; collectionName: string },
|
|
{ success: boolean }
|
|
>('createCollection', { databaseName, collectionName });
|
|
return result.success;
|
|
}
|
|
|
|
async dropCollection(databaseName: string, collectionName: string): Promise<boolean> {
|
|
const result = await this.request<
|
|
{ databaseName: string; collectionName: string },
|
|
{ success: boolean }
|
|
>('dropCollection', { databaseName, collectionName });
|
|
return result.success;
|
|
}
|
|
|
|
async findDocuments(
|
|
databaseName: string,
|
|
collectionName: string,
|
|
options?: {
|
|
filter?: Record<string, unknown>;
|
|
projection?: Record<string, unknown>;
|
|
sort?: Record<string, number>;
|
|
skip?: number;
|
|
limit?: number;
|
|
}
|
|
): Promise<{ documents: Record<string, unknown>[]; total: number }> {
|
|
return this.request('findDocuments', {
|
|
databaseName,
|
|
collectionName,
|
|
...options,
|
|
});
|
|
}
|
|
|
|
async getDocument(
|
|
databaseName: string,
|
|
collectionName: string,
|
|
documentId: string
|
|
): Promise<Record<string, unknown> | null> {
|
|
const result = await this.request<
|
|
{ databaseName: string; collectionName: string; documentId: string },
|
|
{ document: Record<string, unknown> | null }
|
|
>('getDocument', { databaseName, collectionName, documentId });
|
|
return result.document;
|
|
}
|
|
|
|
async insertDocument(
|
|
databaseName: string,
|
|
collectionName: string,
|
|
document: Record<string, unknown>
|
|
): Promise<string> {
|
|
const result = await this.request<
|
|
{ databaseName: string; collectionName: string; document: Record<string, unknown> },
|
|
{ insertedId: string }
|
|
>('insertDocument', { databaseName, collectionName, document });
|
|
return result.insertedId;
|
|
}
|
|
|
|
async updateDocument(
|
|
databaseName: string,
|
|
collectionName: string,
|
|
documentId: string,
|
|
update: Record<string, unknown>
|
|
): Promise<{ success: boolean; modifiedCount: number }> {
|
|
return this.request('updateDocument', {
|
|
databaseName,
|
|
collectionName,
|
|
documentId,
|
|
update,
|
|
});
|
|
}
|
|
|
|
async deleteDocument(
|
|
databaseName: string,
|
|
collectionName: string,
|
|
documentId: string
|
|
): Promise<{ success: boolean; deletedCount: number }> {
|
|
return this.request('deleteDocument', { databaseName, collectionName, documentId });
|
|
}
|
|
|
|
async runAggregation(
|
|
databaseName: string,
|
|
collectionName: string,
|
|
pipeline: Record<string, unknown>[]
|
|
): Promise<Record<string, unknown>[]> {
|
|
const result = await this.request<
|
|
{ databaseName: string; collectionName: string; pipeline: Record<string, unknown>[] },
|
|
{ results: Record<string, unknown>[] }
|
|
>('runAggregation', { databaseName, collectionName, pipeline });
|
|
return result.results;
|
|
}
|
|
|
|
async listIndexes(
|
|
databaseName: string,
|
|
collectionName: string
|
|
): Promise<IMongoIndex[]> {
|
|
const result = await this.request<
|
|
{ databaseName: string; collectionName: string },
|
|
{ indexes: IMongoIndex[] }
|
|
>('listIndexes', { databaseName, collectionName });
|
|
return result.indexes;
|
|
}
|
|
|
|
async createIndex(
|
|
databaseName: string,
|
|
collectionName: string,
|
|
keys: Record<string, number>,
|
|
options?: { unique?: boolean; sparse?: boolean; name?: string }
|
|
): Promise<string> {
|
|
const result = await this.request<
|
|
{
|
|
databaseName: string;
|
|
collectionName: string;
|
|
keys: Record<string, number>;
|
|
options?: { unique?: boolean; sparse?: boolean; name?: string };
|
|
},
|
|
{ indexName: string }
|
|
>('createIndex', { databaseName, collectionName, keys, options });
|
|
return result.indexName;
|
|
}
|
|
|
|
async dropIndex(
|
|
databaseName: string,
|
|
collectionName: string,
|
|
indexName: string
|
|
): Promise<boolean> {
|
|
const result = await this.request<
|
|
{ databaseName: string; collectionName: string; indexName: string },
|
|
{ success: boolean }
|
|
>('dropIndex', { databaseName, collectionName, indexName });
|
|
return result.success;
|
|
}
|
|
|
|
async getCollectionStats(
|
|
databaseName: string,
|
|
collectionName: string
|
|
): Promise<ICollectionStats> {
|
|
const result = await this.request<
|
|
{ databaseName: string; collectionName: string },
|
|
{ stats: ICollectionStats }
|
|
>('getCollectionStats', { databaseName, collectionName });
|
|
return result.stats;
|
|
}
|
|
|
|
async getServerStatus(): Promise<{
|
|
version: string;
|
|
uptime: number;
|
|
connections: { current: number; available: number };
|
|
}> {
|
|
return this.request('getServerStatus', {});
|
|
}
|
|
}
|