@workspace-fs/core
Version:
Multi-project workspace manager for Firesystem with support for multiple sources
974 lines (963 loc) • 26.2 kB
TypeScript
import { FileSystemEventPayloads, IReactiveFileSystem, IFileSystemCapabilities, TypedEventEmitter, FileEntry, FileStat, FSEvent, Disposable } from '@firesystem/core';
export { Disposable, FSEvent, FileEntry, FileMetadata, FileStat, FileSystemEventPayloads, FileSystemEvents, IFileSystem, IReactiveFileSystem } from '@firesystem/core';
/**
* Project configuration for loading
*/
interface ProjectConfig {
id: string;
name: string;
source: ProjectSource;
metadata?: Record<string, any>;
}
/**
* Source configuration for different storage types
*/
interface ProjectSource {
type: "memory" | "indexeddb" | "s3" | "json-url" | "api" | "github" | "git";
config: any;
auth?: SourceAuth;
}
/**
* Authentication configuration for sources
*/
interface SourceAuth {
type: "bearer" | "basic" | "token" | "oauth2";
credentials: any;
refresh?: () => Promise<SourceAuth>;
}
/**
* Project metadata
*/
interface ProjectMetadata {
created: Date;
modified: Date;
lastOpened: Date;
size?: number;
fileCount?: number;
[key: string]: any;
}
/**
* Project state
*/
type ProjectState = "loading" | "loaded" | "error" | "unloading" | "disabled";
/**
* Active project with file system
*/
interface Project {
id: string;
name: string;
source: ProjectSource;
fs: IReactiveFileSystem;
metadata: ProjectMetadata;
state: ProjectState;
error?: Error;
lastAccessed: Date;
memoryUsage?: number;
accessCount: number;
}
/**
* Workspace configuration
*/
interface WorkspaceConfig {
version: string;
projects: ProjectConfig[];
activeProjectId?: string;
settings?: WorkspaceSettings;
}
/**
* Workspace settings
*/
interface WorkspaceSettings {
maxActiveProjects?: number;
autoDisableAfter?: number;
keepFocusedActive?: boolean;
autoSave?: boolean;
autoSaveInterval?: number;
memoryThreshold?: number;
[key: string]: any;
}
/**
* Source loader interface
*/
interface SourceLoader {
type: string;
/**
* Create the appropriate file system for this source
*/
createFileSystem(source: ProjectSource): Promise<IReactiveFileSystem>;
/**
* Initialize the file system with data from source
*/
initialize(fs: IReactiveFileSystem, source: ProjectSource): Promise<void>;
/**
* Optional: Save file system back to source
*/
save?(fs: IReactiveFileSystem, source: ProjectSource): Promise<void>;
}
/**
* Workspace events
*/
interface WorkspaceEventPayloads extends FileSystemEventPayloads {
"project:loading": {
projectId: string;
};
"project:loaded": {
project: Project;
};
"project:activated": {
projectId: string;
previousId?: string;
};
"project:deactivated": {
projectId: string;
};
"project:unloading": {
projectId: string;
};
"project:unloaded": {
projectId: string;
};
"project:error": {
projectId: string;
error: Error;
};
"project:file:reading": {
projectId: string;
path: string;
};
"project:file:read": {
projectId: string;
path: string;
size: number;
};
"project:file:writing": {
projectId: string;
path: string;
size?: number;
};
"project:file:written": {
projectId: string;
path: string;
size: number;
};
"project:file:deleting": {
projectId: string;
path: string;
};
"project:file:deleted": {
projectId: string;
path: string;
};
"project:dir:creating": {
projectId: string;
path: string;
recursive: boolean;
};
"project:dir:created": {
projectId: string;
path: string;
};
"project:dir:deleting": {
projectId: string;
path: string;
recursive: boolean;
};
"project:dir:deleted": {
projectId: string;
path: string;
};
"project:converting": {
projectId: string;
targetSource: ProjectSource;
};
"project:converted": {
projectId: string;
source: ProjectSource;
};
"project:syncing": {
projectId: string;
targetSource: ProjectSource;
};
"project:synced": {
projectId: string;
source: ProjectSource;
};
"workspace:initializing": void;
"workspace:initialized": {
projectCount: number;
};
"workspace:clearing": void;
"workspace:cleared": void;
"workspace:error": {
error: Error;
};
"workspace:importing": {
source: string;
};
"workspace:imported": {
source: string;
};
"workspace:import-failed": {
source: string;
error: any;
};
"project:removed": {
projectId: string;
};
"project:delete-confirm": {
projectId: string;
project: any;
cancelled?: boolean;
};
"project:deleted": {
projectId: string;
deletedData: boolean;
};
"project:disabling": {
projectId: string;
};
"project:disabled": {
projectId: string;
hasLocalData: boolean;
reason: string;
};
"project:enabled": {
projectId: string;
};
"project:files-copied": {
sourceId: string;
targetId: string;
fileCount: number;
};
}
/**
* Memory source configuration
*/
interface MemorySourceConfig {
initialData?: {
files: Array<{
path: string;
type: "file" | "directory";
content?: any;
metadata?: Record<string, any>;
}>;
};
initialDataUrl?: string;
}
/**
* IndexedDB source configuration
*/
interface IndexedDBSourceConfig {
dbName: string;
version?: number;
}
/**
* JSON URL source configuration
*/
interface JsonUrlSourceConfig {
url: string;
headers?: Record<string, string>;
}
/**
* API source configuration
*/
interface ApiSourceConfig {
baseUrl: string;
projectId: string;
headers?: Record<string, string>;
endpoints?: {
files?: string;
file?: string;
upload?: string;
};
}
/**
* GitHub source configuration
*/
interface GitHubSourceConfig {
owner: string;
repo: string;
branch?: string;
path?: string;
readOnly?: boolean;
}
/**
* Source configurations map
*/
interface SourceConfigMap {
memory: MemorySourceConfig;
indexeddb: IndexedDBSourceConfig;
"json-url": JsonUrlSourceConfig;
api: ApiSourceConfig;
github: GitHubSourceConfig;
}
/**
* Project statistics
*/
interface ProjectStats {
fileCount: number;
directoryCount: number;
totalSize: number;
lastModified: Date;
}
/**
* Workspace statistics
*/
interface WorkspaceStats {
total: number;
active: number;
disabled: number;
focused: string | null;
memoryUsage: string;
connections: Record<string, number>;
}
/**
* Project metrics
*/
interface ProjectMetrics {
fileCount: number;
totalSize: number;
lastModified: Date;
accessCount: number;
averageFileSize: number;
largestFile: {
path: string;
size: number;
};
}
/**
* Sync options for cross-project operations
*/
interface SyncOptions {
overwrite?: boolean;
filter?: (path: string) => boolean;
progress?: (copied: number, total: number) => void;
}
/**
* Project diff result
*/
interface ProjectDiff {
added: string[];
modified: string[];
deleted: string[];
unchanged: string[];
}
/**
* Memory optimization report
*/
interface OptimizationReport {
projectsDisabled: string[];
memoryFreed: number;
connectionsReleased: number;
}
/**
* Provider interface para integração de file systems com o workspace
* Segue o padrão de providers do VSCode
*/
interface SourceProvider {
/**
* Identificador único do provider (ex: "memory", "indexeddb", "s3")
*/
readonly scheme: string;
/**
* Display name amigável do provider
*/
readonly displayName: string;
/**
* Cria uma nova instância do file system
* @param config Configuração específica do provider
*/
createFileSystem(config: any): Promise<IReactiveFileSystem>;
/**
* Valida se uma configuração é válida para este provider
* @param config Configuração a ser validada
*/
validateConfiguration?(config: any): Promise<{
valid: boolean;
errors?: string[];
}>;
/**
* Retorna as capacidades do file system
* Útil para o workspace saber limitações antes de criar
*/
getCapabilities(): IFileSystemCapabilities;
/**
* Destrói/limpa uma instância do file system
* Importante para liberar recursos (conexões, memória, etc)
*/
dispose?(fs: IReactiveFileSystem): Promise<void>;
/**
* Deleta dados permanentes do projeto (opcional)
* Cada provider decide o que fazer baseado no tipo:
* - IndexedDB: deleta o banco
* - S3: não faz nada (dados remotos)
* - Memory: não faz nada (volátil)
* @param config Configuração do projeto para identificar os dados
*/
deleteProjectData?(config: any): Promise<void>;
/**
* Informa se o provider armazena dados localmente
* @returns true se os dados são armazenados localmente (ex: IndexedDB), false se remotos (ex: S3)
*/
hasLocalData?(): boolean;
/**
* Estima o tamanho dos dados locais em bytes (se aplicável)
* @param config Configuração do projeto
* @returns Tamanho estimado em bytes ou null se não aplicável
*/
estimateDataSize?(config: any): Promise<number | null>;
}
/**
* Interface para providers que suportam persistência
*/
interface PersistableSourceProvider extends SourceProvider {
/**
* Salva o estado atual do file system
*/
save(fs: IReactiveFileSystem, config: any): Promise<void>;
/**
* Carrega o estado salvo para o file system
*/
load(fs: IReactiveFileSystem, config: any): Promise<void>;
}
/**
* Interface para providers que suportam conversão
*/
interface ConvertibleSourceProvider extends SourceProvider {
/**
* Converte o file system para outro tipo
* @param fs File system fonte
* @param targetScheme Scheme do provider alvo
* @param targetConfig Configuração para o provider alvo
*/
convertTo(fs: IReactiveFileSystem, targetScheme: string, targetConfig: any): Promise<{
config: any;
initialData?: any;
}>;
}
/**
* Registro de providers no workspace
*/
interface ProviderRegistry {
/**
* Registra um provider
*/
registerProvider(provider: SourceProvider): void;
/**
* Remove um provider do registro
*/
unregisterProvider(scheme: string): void;
/**
* Obtém um provider pelo scheme
*/
getProvider(scheme: string): SourceProvider | undefined;
/**
* Lista todos os providers registrados
*/
getRegisteredProviders(): SourceProvider[];
}
interface StoredProject {
id: string;
name: string;
source: any;
metadata: ProjectMetadata;
lastAccessed: Date;
enabled?: boolean;
disabledAt?: Date;
enabledAt?: Date;
}
interface WorkspaceState {
id: "current";
activeProjectId: string | null;
recentProjectIds: string[];
settings: WorkspaceSettings;
}
/**
* Manages workspace persistence in IndexedDB
*/
declare class WorkspaceDatabase {
private db;
private dbName;
private dbVersion;
constructor(dbName?: string, dbVersion?: number);
/**
* Open or create the workspace database
*/
open(): Promise<void>;
/**
* Ensure database is open
*/
private ensureOpen;
/**
* Close the database
*/
close(): void;
/**
* Save or update a project configuration
*/
saveProject(project: StoredProject): Promise<void>;
/**
* Get a project by ID
*/
getProject(id: string): Promise<StoredProject | null>;
/**
* List all projects
*/
listProjects(): Promise<StoredProject[]>;
/**
* List recent projects
*/
listRecentProjects(limit?: number): Promise<StoredProject[]>;
/**
* Delete a project
*/
deleteProject(id: string): Promise<void>;
/**
* Update project last accessed time
*/
touchProject(id: string): Promise<void>;
/**
* Update project state
*/
updateProjectState(id: string, updates: Partial<Pick<StoredProject, "enabled" | "disabledAt" | "enabledAt">>): Promise<void>;
/**
* Save workspace state
*/
saveWorkspaceState(state: WorkspaceState): Promise<void>;
/**
* Get workspace state
*/
getWorkspaceState(): Promise<WorkspaceState | null>;
/**
* Clear all data
*/
clear(): Promise<void>;
/**
* Check if a project exists by checking IndexedDB databases
*/
static projectDatabaseExists(dbName: string): Promise<boolean>;
/**
* Discover existing Firesystem IndexedDB databases
*/
discoverIndexedDBProjects(): Promise<string[]>;
}
interface WorkspaceExport {
version: string;
exportedAt: Date;
workspace: {
settings?: any;
activeProjectId?: string;
};
projects: Array<{
id: string;
name: string;
type: "memory" | "indexeddb" | "s3";
config?: any;
files?: Array<{
path: string;
content: string;
metadata?: Record<string, any>;
}>;
}>;
}
/**
* Handles import/export of workspace configurations
*/
declare class WorkspaceImporter {
/**
* Import workspace from JSON URL
*/
static fromJsonUrl(url: string): Promise<WorkspaceConfig>;
/**
* Import workspace from GitHub Gist
*/
static fromGitHubGist(gistId: string, token?: string): Promise<WorkspaceConfig>;
/**
* Import workspace from API endpoint
*/
static fromApi(url: string, options?: {
headers?: Record<string, string>;
method?: string;
body?: any;
}): Promise<WorkspaceConfig>;
/**
* Parse export data into workspace config
*/
private static parseExport;
}
interface ExportOptions {
includeFiles?: boolean;
includeCredentials?: boolean;
projectIds?: string[];
}
/**
* Handles exporting workspace configurations
*/
declare class WorkspaceExporter {
/**
* Export workspace to JSON
*/
static toJson(projects: Project[], activeProjectId: string | null, settings: WorkspaceSettings, options?: ExportOptions): Promise<WorkspaceExport>;
/**
* Export to GitHub Gist
*/
static toGitHubGist(exportData: WorkspaceExport, options: {
token: string;
description?: string;
public?: boolean;
}): Promise<string>;
/**
* Export to API endpoint
*/
static toApi(exportData: WorkspaceExport, url: string, options?: {
headers?: Record<string, string>;
method?: string;
}): Promise<void>;
/**
* Extract all files from a file system
*/
private static extractFiles;
}
/**
* Options for deleting a project
*/
interface DeleteProjectOptions {
deleteData?: boolean;
skipConfirmation?: boolean;
}
/**
* Multi-project workspace manager for Firesystem
*/
declare class WorkspaceFileSystem implements IReactiveFileSystem, ProviderRegistry {
private activeProjectId;
private providers;
private database;
private credentialManager;
private recentProjectIds;
private settings;
private projectManager;
private performanceManager;
private persistenceManager;
private eventManager;
private projectOperations;
private fileSystemProxy;
/**
* Event system for workspace events
*/
readonly events: TypedEventEmitter<WorkspaceEventPayloads>;
constructor(config?: WorkspaceConfig);
/**
* Initialize workspace with optional config
*/
initialize(config?: WorkspaceConfig): Promise<void>;
/**
* Load a project into the workspace
*/
loadProject(config: ProjectConfig): Promise<Project>;
/**
* Unload a project from the workspace
*/
unloadProject(projectId: string): Promise<void>;
/**
* Get a project by ID
*/
getProject(projectId: string): Project | null;
/**
* Get all loaded projects
*/
getProjects(): Project[];
/**
* Set the active project
*/
setActiveProject(projectId: string): Promise<void>;
/**
* Get the active project
*/
getActiveProject(): Project | null;
/**
* Disable a project (unload but keep configuration)
*/
disableProject(projectId: string): Promise<void>;
/**
* Enable a disabled project
*/
enableProject(projectId: string): Promise<void>;
/**
* Batch disable projects
*/
disableProjects(projectIds: string[]): Promise<void>;
/**
* Batch enable projects
*/
enableProjects(projectIds: string[]): Promise<void>;
/**
* Get disabled projects
*/
getDisabledProjects(): Promise<StoredProject[]>;
/**
* Check if project is enabled
*/
isProjectEnabled(projectId: string): boolean;
/**
* Copy files between projects
*/
copyFiles(sourceId: string, pattern: string, targetId: string, targetPath: string): Promise<void>;
/**
* Sync projects
*/
syncProjects(sourceId: string, targetId: string, options?: SyncOptions): Promise<void>;
/**
* Compare projects
*/
compareProjects(projectId1: string, projectId2: string): Promise<ProjectDiff>;
/**
* Get workspace statistics
*/
getProjectStats(): Promise<WorkspaceStats>;
/**
* Get project metrics
*/
getProjectMetrics(projectId: string): Promise<ProjectMetrics>;
/**
* Optimize memory usage
*/
optimizeMemoryUsage(): Promise<OptimizationReport>;
/**
* Provider Registry Implementation
*/
registerProvider(provider: SourceProvider): void;
unregisterProvider(scheme: string): void;
getProvider(scheme: string): SourceProvider | undefined;
getRegisteredProviders(): SourceProvider[];
/**
* Convert a project to a different source
*/
convertProject(projectId: string, targetSource: ProjectSource): Promise<void>;
/**
* Convert to IndexedDB (convenience method)
*/
convertToIndexedDB(projectId: string): Promise<void>;
/**
* Export workspace configuration
*/
export(): Promise<WorkspaceConfig>;
/**
* Import workspace configuration
*/
import(config: WorkspaceConfig): Promise<void>;
/**
* Clear all projects
*/
clear(): Promise<void>;
readFile(path: string): Promise<FileEntry>;
writeFile(path: string, content: any, metadata?: Record<string, any>): Promise<FileEntry>;
deleteFile(path: string): Promise<void>;
mkdir(path: string, recursive?: boolean): Promise<FileEntry>;
rmdir(path: string, recursive?: boolean): Promise<void>;
exists(path: string): Promise<boolean>;
stat(path: string): Promise<FileStat>;
readDir(path: string): Promise<FileEntry[]>;
rename(oldPath: string, newPath: string): Promise<FileEntry>;
copy(sourcePath: string, targetPath: string): Promise<FileEntry>;
move(sourcePaths: string[], targetPath: string): Promise<void>;
glob(pattern: string): Promise<string[]>;
watch(path: string, callback: (event: FSEvent) => void): Disposable;
watchGlob?(pattern: string, callback: (event: FSEvent) => void): Disposable;
size(): Promise<number>;
canModify(path: string): Promise<boolean>;
canCreateIn(parentPath: string): Promise<boolean>;
/**
* Save current workspace state to database
*/
private saveWorkspaceState;
/**
* List all registered projects from database
*/
listStoredProjects(): Promise<StoredProject[]>;
/**
* List recent projects
*/
listRecentProjects(limit?: number): Promise<StoredProject[]>;
/**
* Delete a project from workspace and optionally delete its data
*/
deleteProject(projectId: string, options?: DeleteProjectOptions): Promise<void>;
/**
* Discover existing IndexedDB projects
*/
discoverIndexedDBProjects(): Promise<ProjectConfig[]>;
/**
* Import workspace configuration from URL
*/
importFromUrl(url: string): Promise<void>;
/**
* Import workspace from GitHub Gist
*/
importFromGitHubGist(gistId: string, token?: string): Promise<void>;
/**
* Import workspace configuration
*/
private importWorkspaceConfig;
/**
* Export workspace configuration
*/
exportWorkspace(options?: ExportOptions): Promise<any>;
/**
* Export workspace to GitHub Gist
*/
exportToGitHubGist(options: {
token: string;
description?: string;
public?: boolean;
includeFiles?: boolean;
}): Promise<string>;
/**
* Export workspace to API endpoint
*/
exportToApi(url: string, options?: {
headers?: Record<string, string>;
method?: string;
includeFiles?: boolean;
}): Promise<void>;
/**
* Register a custom credential provider
*/
registerCredentialProvider(sourceType: string, provider: any): void;
/**
* Get credentials for a project (useful for debugging)
*/
getProjectCredentials(projectId: string): Promise<any>;
/**
* Clear cached credentials
*/
clearCredentialCache(projectId?: string): void;
/**
* Close workspace and database connection
*/
close(): Promise<void>;
/**
* Check if a project exists and can be accessed
*/
private isProjectAccessible;
}
interface CredentialProvider {
/**
* Get credentials for a specific project
*/
getCredentials(projectId: string, source: ProjectSource): Promise<any>;
/**
* Store credentials securely
*/
storeCredentials(projectId: string, credentials: any): Promise<void>;
/**
* Remove stored credentials
*/
removeCredentials(projectId: string): Promise<void>;
}
/**
* Manages credentials for different project sources
*/
declare class CredentialManager {
private providers;
private memoryCache;
/**
* Register a credential provider
*/
registerProvider(name: string, provider: CredentialProvider): void;
/**
* Get credentials for a project source
*/
getCredentials(projectId: string, source: ProjectSource): Promise<any>;
/**
* Extract credentials from auth config
*/
private extractCredentials;
/**
* Clear cached credentials
*/
clearCache(projectId?: string): void;
}
/**
* Browser-based credential provider using Web Crypto API
*/
declare class BrowserCredentialProvider implements CredentialProvider {
private dbName;
private storeName;
getCredentials(projectId: string, source: ProjectSource): Promise<any>;
storeCredentials(projectId: string, credentials: any): Promise<void>;
removeCredentials(projectId: string): Promise<void>;
}
/**
* Environment variable credential provider (for Node.js)
*/
declare class EnvCredentialProvider implements CredentialProvider {
getCredentials(projectId: string, source: ProjectSource): Promise<any>;
storeCredentials(): Promise<void>;
removeCredentials(): Promise<void>;
}
/**
* Interactive credential provider that prompts user
*/
declare class InteractiveCredentialProvider implements CredentialProvider {
private prompter;
constructor(prompter: (message: string, secure?: boolean) => Promise<string>);
getCredentials(projectId: string, source: ProjectSource): Promise<any>;
storeCredentials(): Promise<void>;
removeCredentials(): Promise<void>;
}
/**
* Validates and builds source configurations with credentials
*/
declare class SourceConfigBuilder {
/**
* Build IndexedDB source config
*/
static indexedDB(dbName?: string): ProjectSource;
/**
* Build Memory source config
*/
static memory(initialData?: any): ProjectSource;
/**
* Build S3 source config
*/
static s3(config: {
bucket: string;
prefix?: string;
region?: string;
credentials?: {
accessKeyId: string;
secretAccessKey: string;
};
}): ProjectSource;
/**
* Build GitHub source config
*/
static github(config: {
owner: string;
repo: string;
branch?: string;
path?: string;
token?: string;
}): ProjectSource;
/**
* Build API source config
*/
static api(config: {
baseUrl: string;
projectEndpoint?: string;
headers?: Record<string, string>;
apiKey?: string;
}): ProjectSource;
/**
* Validate source configuration
*/
static validate(source: ProjectSource): {
valid: boolean;
errors: string[];
};
/**
* Sanitize source for export (remove credentials)
*/
static sanitize(source: ProjectSource): ProjectSource;
}
export { type ApiSourceConfig, BrowserCredentialProvider, type ConvertibleSourceProvider, CredentialManager, type DeleteProjectOptions, EnvCredentialProvider, type ExportOptions, type GitHubSourceConfig, type IndexedDBSourceConfig, InteractiveCredentialProvider, type JsonUrlSourceConfig, type MemorySourceConfig, type OptimizationReport, type PersistableSourceProvider, type Project, type ProjectConfig, type ProjectDiff, type ProjectMetadata, type ProjectMetrics, type ProjectSource, type ProjectState, type ProjectStats, type ProviderRegistry, type SourceAuth, SourceConfigBuilder, type SourceConfigMap, type SourceLoader, type SourceProvider, type SyncOptions, type WorkspaceConfig, WorkspaceDatabase, type WorkspaceEventPayloads, type WorkspaceExport, WorkspaceExporter, WorkspaceFileSystem, WorkspaceImporter, type WorkspaceSettings, type WorkspaceStats };