Multi-project workspace manager for Firesystem with support for multiple sources
npm install @firesystem/workspaceRevolutionary Multi-Project Workspace Manager - The first file system workspace that enables multiple projects running simultaneously in parallel, breaking the traditional "one project = one filesystem" paradigm. Unlike IDEs that switch between projects, Firesystem Workspace keeps ALL projects active and accessible at once.




Traditional development environments work with one active project at a time:
``typescript`
// โ Traditional approach (VSCode, etc.)
await closeProject("frontend"); // Lost from memory
await openProject("backend"); // Only this is accessible
await closeProject("backend"); // Lost from memory
await openProject("database"); // Only this is accessible
Firesystem Workspace revolutionizes this:
`typescript
// โ
Revolutionary approach - ALL PROJECTS ACTIVE SIMULTANEOUSLY
const frontend = workspace.getProject("frontend"); // Always accessible
const backend = workspace.getProject("backend"); // Always accessible
const database = workspace.getProject("database"); // Always accessible
// Cross-project operations without switching context
const config = await backend.fs.readFile("/config/database.json");
await database.fs.writeFile("/import/backend-config.json", config);
await frontend.fs.writeFile("/src/api-config.json", config);
// One project focused for UI, but ALL remain active
workspace.setActiveProject("frontend"); // Just changes UI focus
`
`bash`
npm install @firesystem/workspace @firesystem/coreor
yarn add @firesystem/workspace @firesystem/core or
pnpm add @firesystem/workspace @firesystem/core
`typescript
import { WorkspaceFileSystem } from "@firesystem/workspace";
import { memoryProvider } from "@firesystem/memory/provider";
import { indexedDBProvider } from "@firesystem/indexeddb/provider";
// Create workspace and register providers
const workspace = new WorkspaceFileSystem();
workspace.registerProvider(memoryProvider);
workspace.registerProvider(indexedDBProvider);
// Initialize (restores previous state automatically)
await workspace.initialize();
// Load multiple projects simultaneously
const devProject = await workspace.loadProject({
id: "dev-env",
name: "Development Environment",
source: {
type: "memory",
config: {
initialData: {
"/src/app.ts": { content: "console.log('dev');" },
"/config/dev.json": { content: JSON.stringify({ env: "development" }) }
}
}
}
});
const prodBackup = await workspace.loadProject({
id: "prod-backup",
name: "Production Backup",
source: {
type: "indexeddb",
config: { dbName: "production-backup" }
}
});
// ALL PROJECTS ARE NOW ACTIVE AND ACCESSIBLE!
console.log("Active projects:", workspace.getProjects().length); // 2
// Cross-project operations (the revolutionary part!)
const prodConfig = await prodBackup.fs.readFile("/config/production.json");
await devProject.fs.writeFile("/config/prod-copy.json", prodConfig.content);
// Work with the focused project transparently
workspace.setActiveProject("dev-env");
await workspace.writeFile("/test.js", "// This goes to dev-env");
// But other projects remain accessible
await prodBackup.fs.writeFile("/logs/import.log", "Config copied to dev");
`
Unlike traditional workspaces that handle one project at a time:
`typescript
// Traditional: Only one project accessible
const currentProject = getCurrentProject(); // Only this exists
// Firesystem: All projects accessible simultaneously
const projects = workspace.getProjects(); // All active projects
const dev = workspace.getProject("dev");
const staging = workspace.getProject("staging");
const prod = workspace.getProject("prod");
// Work with all at once
const devConfig = await dev.fs.readFile("/config.json");
const stagingData = await staging.fs.glob("*/.log");
await prod.fs.writeFile("/backup/dev-config.json", devConfig.content);
`
- Active Projects: Loaded in memory, consuming resources, ready for operations
- Focused Project: The project shown in UI (File Explorer), receives direct operations
- Disabled Projects: Configuration preserved but not loaded, zero resource usage
`typescript
// Load multiple projects - all become active
await workspace.loadProject({ id: "app", source: { type: "memory" } });
await workspace.loadProject({ id: "docs", source: { type: "indexeddb" } });
await workspace.loadProject({ id: "assets", source: { type: "s3" } });
// Set focus for UI - others remain active
await workspace.setActiveProject("app"); // File Explorer shows "app"
// Direct access to any project
const docs = workspace.getProject("docs");
const assets = workspace.getProject("assets");
// Proxy operations go to focused project
await workspace.writeFile("/test.txt", "content"); // Goes to "app"
// Direct operations go to specific project
await docs.fs.writeFile("/readme.md", "# Documentation");
await assets.fs.writeFile("/logo.png", imageData);
`
`typescript
// Disable projects for performance (keeps config)
await workspace.disableProject("large-dataset"); // Frees memory, keeps config
// Re-enable when needed
await workspace.enableProject("large-dataset"); // Reconstructs from config
// Batch operations
await workspace.disableProjects(["old-1", "old-2", "old-3"]);
await workspace.enableProjects(["needed-1", "needed-2"]);
// Auto-optimization settings
const workspace = new WorkspaceFileSystem({
settings: {
maxActiveProjects: 5, // Auto-disable least recently used
autoDisableAfter: 30 60 1000, // 30 minutes of inactivity
keepFocusedActive: true // Never auto-disable focused project
}
});
`
Delete projects with full control over data cleanup:
`typescript
// Delete project configuration only (preserves data)
await workspace.deleteProject("temp-project");
// Delete project AND its data
await workspace.deleteProject("old-project", {
deleteData: true
});
// With confirmation event
workspace.events.on("project:delete-confirm", (event) => {
if (!confirm(Delete ${event.project.name}?)) {
event.cancelled = true; // Cancel deletion
}
});
// Skip confirmation for automation
await workspace.deleteProject("temp-project", {
skipConfirmation: true,
deleteData: true
});
`
The workspace is completely agnostic about file systems. Providers encapsulate all implementation knowledge:
| Provider | Package | Type | Description |
|----------|---------|------|-------------|
| Memory | @firesystem/memory/provider | "memory" | In-memory, fast iteration |@firesystem/indexeddb/provider
| IndexedDB | | "indexeddb" | Browser persistent storage |@firesystem/s3/provider
| S3* | | "s3" | AWS S3 cloud storage |@firesystem/github/provider
| GitHub* | | "github" | GitHub repository |@firesystem/api/provider
| API* | | "api" | REST API backend |
*Coming soon
`typescript
import { WorkspaceFileSystem } from "@firesystem/workspace";
import { memoryProvider } from "@firesystem/memory/provider";
import { indexedDBProvider } from "@firesystem/indexeddb/provider";
const workspace = new WorkspaceFileSystem();
// Register only what you need
workspace.registerProvider(memoryProvider);
workspace.registerProvider(indexedDBProvider);
// Provider capabilities are automatically detected
const memoryCapabilities = workspace.getProvider("memory")?.getCapabilities();
console.log(memoryCapabilities.supportsWatch); // true
console.log(memoryCapabilities.readonly); // false
`
`typescript
import type { SourceProvider } from "@firesystem/workspace";
import { withEvents } from "@firesystem/core";
class DropboxProvider implements SourceProvider {
readonly scheme = "dropbox";
readonly displayName = "Dropbox Storage";
async createFileSystem(config: DropboxConfig) {
const baseFs = new DropboxFileSystem(config);
return withEvents(baseFs); // Add reactive events
}
getCapabilities() {
return {
readonly: false,
caseSensitive: false,
atomicRename: true,
supportsWatch: false, // Dropbox limitation
supportsMetadata: true,
maxFileSize: 150 1024 1024 // 150MB
};
}
async validateConfiguration(config: any) {
const errors = [];
if (!config.accessToken) errors.push("Access token required");
return { valid: errors.length === 0, errors };
}
// Optional: Data management methods
deleteProjectData?(config: DropboxConfig): Promise
// Remove Dropbox app folder if needed
}
hasLocalData(): boolean {
return false; // Dropbox is cloud storage
}
async estimateDataSize(config: DropboxConfig): Promise
// Could query Dropbox API for folder size
return null;
}
}
// Register and use
workspace.registerProvider(new DropboxProvider());
await workspace.loadProject({
id: "my-dropbox",
name: "Dropbox Files",
source: {
type: "dropbox",
config: { accessToken: "...", path: "/projects" }
}
});
`
The revolutionary feature that enables true multi-project workflows:
`typescript
// Load different storage types
const memory = await workspace.loadProject({
id: "temp",
source: { type: "memory", config: {} }
});
const persistent = await workspace.loadProject({
id: "storage",
source: { type: "indexeddb", config: { dbName: "app-data" } }
});
// Copy files between different storage types
await workspace.copyFiles(
"temp", // Source project
"/work/*.json", // Source pattern
"storage", // Target project
"/backup/" // Target directory
);
`
`typescript`
// Sync entire project from S3 to local IndexedDB
await workspace.syncProjects("s3-backup", "local-cache", {
direction: "source-to-target",
deleteOrphaned: false,
skipExisting: true
});
`typescript`
const diff = await workspace.compareProjects("dev", "staging");
console.log(diff.added); // Files in staging not in dev
console.log(diff.removed); // Files in dev not in staging
console.log(diff.modified); // Files that differ
`typescript
// Set up multi-stage data pipeline
const rawData = await workspace.loadProject({
id: "s3-raw",
source: { type: "s3", config: { bucket: "raw-data" } }
});
const processing = await workspace.loadProject({
id: "memory-work",
source: { type: "memory", config: {} }
});
const results = await workspace.loadProject({
id: "indexeddb-cache",
source: { type: "indexeddb", config: { dbName: "results" } }
});
// Process: S3 โ Memory โ IndexedDB
const files = await rawData.fs.glob("batch-*.json");
for (const file of files) {
// 1. Read from S3
const data = await rawData.fs.readFile(file);
// 2. Process in memory (fast)
const processed = await processData(JSON.parse(data.content));
await processing.fs.writeFile(/work${file}, JSON.stringify(processed));/final${file}
// 3. Save results to IndexedDB (persistent)
await results.fs.writeFile(, JSON.stringify(processed));`
}
Unified events across all projects with rich context:
`typescriptโ
${project.name} loaded (${project.source.type})
// Project lifecycle events
workspace.events.on("project:loaded", ({ project }) => {
console.log();
});
workspace.events.on("project:activated", ({ projectId, previousId }) => {
console.log(๐ Switched from ${previousId} to ${projectId});
});
// File operations with project context
workspace.events.on("project:file:written", ({ projectId, path, size }) => {
console.log(๐ ${path} written in ${projectId} (${size} bytes));
});
// Cross-project operations
workspace.events.on("workspace:sync:completed", ({ sourceId, targetId, stats }) => {
console.log(๐ Synced ${stats.files} files from ${sourceId} to ${targetId});
});
// Performance events with enhanced data
workspace.events.on("project:disabled", ({ projectId, hasLocalData, reason }) => {
console.log(๐ค ${projectId} disabled); Has local data: ${hasLocalData}
console.log(); Reason: ${reason}
console.log();
});
workspace.events.on("project:enabled", ({ projectId }) => {
console.log(โก ${projectId} re-enabled);
});
// Deletion events
workspace.events.on("project:deleted", ({ projectId, deletedData }) => {
console.log(๐๏ธ ${projectId} deleted${deletedData ? ' with data' : ''});`
});
`typescript
const workspace = new WorkspaceFileSystem();
await workspace.initialize(); // Automatically restores:
// - All previously loaded projects
// - Active project selection
// - Project configurations
// - Settings and preferences
// State is automatically saved when:
// - Projects are loaded/unloaded
// - Active project changes
// - Settings are modified
// - Projects are enabled/disabled
`
The workspace automatically handles corrupted state:
`typescript
// Before v1.0.3: Could crash with "NotFoundError"
// v1.0.3+: Automatically cleans up orphaned references
await workspace.initialize(); // Always succeeds
// Console output:
// โ ๏ธ Removing orphaned activeProjectId: deleted-project-123
// โ ๏ธ Removing orphaned recentProjectId: missing-project-456
// โน๏ธ Workspace state cleaned: removed orphaned project references
`
`typescript
// Discover existing IndexedDB projects
const discovered = await workspace.discoverIndexedDBProjects();
console.log("Found projects:", discovered.map(p => p.name));
// Load discovered projects
for (const project of discovered) {
await workspace.loadProject(project);
}
// Get all disabled projects (async now)
const disabledProjects = await workspace.getDisabledProjects();
console.log(${disabledProjects.length} projects are disabled);`
`bashS3 credentials
FIRESYSTEM_S3_ACCESS_KEY_ID=your_access_key
FIRESYSTEM_S3_SECRET_ACCESS_KEY=your_secret_key
FIRESYSTEM_S3_REGION=us-east-1
$3
`typescript
// Credentials requested when needed
const s3Project = await workspace.loadProject({
id: "cloud-files",
source: {
type: "s3",
config: { bucket: "my-bucket" }
// No credentials in config - resolved from environment
}
});// Custom credential providers
workspace.registerCredentialProvider("s3", new InteractiveCredentialProvider({
prompt: async (message, secure) => {
return await showCredentialDialog(message, secure);
}
}));
`$3
`typescript
// Exports are automatically sanitized
const exportData = await workspace.exportWorkspace({
includeFiles: true,
includeCredentials: false // Never exports credentials
});// Safe for sharing/version control
await workspace.exportToGitHubGist({
token: "ghp_...",
description: "Team Workspace Configuration",
public: false
});
`โ๏ธ Framework Integration
$3
`typescript
import { create } from "zustand";
import { WorkspaceFileSystem } from "@firesystem/workspace";interface WorkspaceStore {
workspace: WorkspaceFileSystem | null;
projects: Project[];
activeProject: Project | null;
initWorkspace: () => Promise;
createProject: (name: string, type: string) => Promise;
switchProject: (projectId: string) => Promise;
deleteProject: (projectId: string, deleteData?: boolean) => Promise;
}
const useWorkspaceStore = create((set, get) => ({
workspace: null,
projects: [],
activeProject: null,
async initWorkspace() {
const workspace = new WorkspaceFileSystem();
await workspace.initialize(); // Auto-restores state
// Setup reactive events
workspace.events.on("project:loaded", ({ project }) => {
set(state => ({
projects: [...state.projects, project]
}));
});
workspace.events.on("project:activated", ({ projectId }) => {
const project = workspace.getProject(projectId);
set({ activeProject: project });
});
workspace.events.on("project:deleted", ({ projectId }) => {
set(state => ({
projects: state.projects.filter(p => p.id !== projectId),
activeProject: state.activeProject?.id === projectId ? null : state.activeProject
}));
});
set({
workspace,
projects: workspace.getProjects(),
activeProject: workspace.getActiveProject()
});
},
async createProject(name: string, type: string) {
const { workspace } = get();
if (!workspace) return;
const project = await workspace.loadProject({
id:
project-${Date.now()},
name,
source: { type, config: {} }
});
await workspace.setActiveProject(project.id);
}, async switchProject(projectId: string) {
const { workspace } = get();
if (!workspace) return;
await workspace.setActiveProject(projectId);
},
async deleteProject(projectId: string, deleteData = false) {
const { workspace } = get();
if (!workspace) return;
await workspace.deleteProject(projectId, { deleteData });
}
}));
// React component
function MultiProjectIDE() {
const {
workspace,
projects,
activeProject,
initWorkspace,
createProject,
switchProject,
deleteProject
} = useWorkspaceStore();
useEffect(() => {
initWorkspace();
}, []);
return (
{/ Project tabs - all remain active /}
{projects.map(project => (
key={project.id}
onClick={() => switchProject(project.id)}
className={activeProject?.id === project.id ? 'active' : ''}
>
{project.name}
({project.source.type})
))}
{/ File explorer for active project /}
{activeProject && (
)}
{/ Cross-project operations /}
projects={projects}
onCopyFiles={(source, target, pattern) =>
workspace?.copyFiles(source, pattern, target, "/")
}
onSyncProjects={(source, target) =>
workspace?.syncProjects(source, target)
}
/>
);
}
`$3
`typescript
import { ref, reactive, onMounted } from 'vue';
import { WorkspaceFileSystem } from '@firesystem/workspace';export function useWorkspace() {
const workspace = ref(null);
const projects = ref([]);
const activeProject = ref(null);
const initWorkspace = async () => {
workspace.value = new WorkspaceFileSystem();
await workspace.value.initialize();
workspace.value.events.on('project:loaded', ({ project }) => {
projects.value.push(project);
});
workspace.value.events.on('project:activated', ({ projectId }) => {
activeProject.value = workspace.value!.getProject(projectId);
});
workspace.value.events.on('project:deleted', ({ projectId }) => {
projects.value = projects.value.filter(p => p.id !== projectId);
if (activeProject.value?.id === projectId) {
activeProject.value = null;
}
});
projects.value = workspace.value.getProjects();
activeProject.value = workspace.value.getActiveProject();
};
const createProject = async (name: string, type: string) => {
if (!workspace.value) return;
const project = await workspace.value.loadProject({
id:
project-${Date.now()},
name,
source: { type, config: {} }
});
await workspace.value.setActiveProject(project.id);
};
const deleteProject = async (projectId: string, deleteData = false) => {
if (!workspace.value) return;
await workspace.value.deleteProject(projectId, { deleteData });
};
return {
workspace,
projects,
activeProject,
initWorkspace,
createProject,
deleteProject
};
}
`๐ Real-World Use Cases
$3
`typescript
class DevelopmentWorkspace {
async setup() {
// Load all environments simultaneously
const local = await workspace.loadProject({
id: "local-dev",
source: { type: "memory", config: {} }
});
const staging = await workspace.loadProject({
id: "staging-mirror",
source: { type: "indexeddb", config: { dbName: "staging-cache" } }
});
const production = await workspace.loadProject({
id: "prod-readonly",
source: { type: "s3", config: { bucket: "prod-backup" } }
});
// Copy production config to development
const prodConfig = await production.fs.readFile("/config/app.json");
await local.fs.writeFile("/config/prod-like.json", prodConfig.content);
// Sync staging data for testing
await workspace.syncProjects("staging-mirror", "local-dev", {
include: ["data/*/.json"],
exclude: ["data/sensitive/**"]
});
}
}
`$3
`typescript
class ContentPipeline {
async processContent() {
// Multiple content sources active simultaneously
const cms = await workspace.loadProject({
id: "cms-api",
source: { type: "api", config: { baseUrl: "https://cms.example.com" } }
});
const assets = await workspace.loadProject({
id: "cdn-assets",
source: { type: "s3", config: { bucket: "cdn-assets" } }
});
const cache = await workspace.loadProject({
id: "local-cache",
source: { type: "indexeddb", config: { dbName: "content-cache" } }
});
// Process content across all sources
const articles = await cms.fs.glob("/articles/*.json");
for (const article of articles) {
const content = await cms.fs.readFile(article);
const processed = await this.processArticle(content);
// Cache processed content
await cache.fs.writeFile(article, processed);
// Upload assets
if (processed.images) {
for (const image of processed.images) {
await assets.fs.writeFile(/images/${image.name}, image.data);
}
}
}
}
}
`$3
`typescript
class DataAnalysisWorkspace {
async analyzeData() {
// Load datasets from different sources
const rawData = await workspace.loadProject({
id: "data-lake",
source: { type: "s3", config: { bucket: "analytics-data" } }
});
const processing = await workspace.loadProject({
id: "analysis-memory",
source: { type: "memory", config: {} }
});
const results = await workspace.loadProject({
id: "results-db",
source: { type: "indexeddb", config: { dbName: "analysis-results" } }
});
// Cross-dataset analysis
const datasets = await rawData.fs.glob("datasets/*/.csv");
const analysis = {
totalRows: 0,
correlations: {},
summaries: {}
};
// Process each dataset in memory for speed
for (const dataset of datasets) {
const data = await rawData.fs.readFile(dataset);
const processed = await this.analyzeDataset(data.content);
// Store intermediate results in memory
await processing.fs.writeFile(/processed/${dataset}, processed);
// Aggregate analysis
analysis.totalRows += processed.rows;
analysis.summaries[dataset] = processed.summary;
}
// Save final results
await results.fs.writeFile("/analysis/summary.json", JSON.stringify(analysis));
}
}
`๐ Performance & Best Practices
$3
`typescript
// Configure auto-optimization
const workspace = new WorkspaceFileSystem({
settings: {
maxActiveProjects: 5, // Auto-disable oldest
autoDisableAfter: 30 60 1000, // 30 minutes inactive
keepFocusedActive: true, // Never disable focused
memoryThreshold: 500 1024 1024 // 500MB threshold
}
});// Manual optimization
const stats = await workspace.getProjectStats();
console.log(stats);
// {
// total: 15,
// active: 5,
// disabled: 10,
// memoryUsage: "245MB",
// connections: { s3: 2, api: 1 }
// }
// Optimize when needed
if (stats.memoryUsage > threshold) {
await workspace.optimizeMemoryUsage();
}
`$3
`typescript
// Batch operations across projects
const operations = [
{ project: "dev", operation: () => dev.fs.writeFile("/a.txt", "content") },
{ project: "staging", operation: () => staging.fs.writeFile("/b.txt", "content") },
{ project: "prod", operation: () => prod.fs.readFile("/config.json") }
];await Promise.all(operations.map(op => op.operation()));
// Use project capabilities efficiently
const provider = workspace.getProvider("s3");
if (provider?.getCapabilities().supportsGlob) {
const files = await s3Project.fs.glob("*/.log");
} else {
// Fallback for providers without glob
const files = await this.manualGlob(s3Project, "*/.log");
}
`$3
`typescript
// Robust multi-project error handling
async function robustOperation() {
const results = { success: [], failed: [] };
for (const project of workspace.getProjects()) {
try {
await project.fs.writeFile("/health-check.txt", new Date().toISOString());
results.success.push(project.id);
} catch (error) {
console.warn(Health check failed for ${project.id}:, error.message);
results.failed.push({ project: project.id, error: error.message });
// Auto-disable problematic projects
if (error.message.includes("network") || error.message.includes("credentials")) {
await workspace.disableProject(project.id);
}
}
}
return results;
}
`๐งช Testing
The workspace includes comprehensive test coverage with a focus on core functionality:
`bash
Run all tests
pnpm testCore functionality tests
pnpm test tests/core/Specific test suites
pnpm test tests/core/ProjectManagement.test.ts # Load/unload/delete
pnpm test tests/core/ProjectStateManagement.test.ts # Enable/disable
pnpm test tests/core/CrossProjectOperations.test.ts # Multi-project ops
pnpm test tests/core/FileSystemProxy.test.ts # Transparent proxy
pnpm test tests/core/ProviderValidation.test.ts # Provider system
`$3
- Unit Tests: Core workspace logic with mocked providers (fast, deterministic)
- Integration Tests: Real provider implementations (in individual packages)
- Mocked Providers: Complete FileSystem mocks with configurable capabilities
- Edge Cases: Orphaned references, capability limitations, error scenarios
๐ Documentation
Explore our comprehensive guides to master Firesystem Workspace:
- Project Lifecycle Management - Complete guide to loading, enabling/disabling, and deleting projects
- Event System Guide - Master the reactive event system for real-time updates
- Provider System Guide - Learn how to work with providers and create custom storage implementations
- Cross-Project Operations - Unlock the power of multi-project workflows
- React Integration Guide - Build modern React apps with Firesystem Workspace
For code examples, check out the examples directory.
๐ API Reference
$3
`typescript
class WorkspaceFileSystem implements IReactiveFileSystem {
// Project Management
async loadProject(config: ProjectConfig): Promise
async unloadProject(projectId: string): Promise
getProject(projectId: string): Project | null
getProjects(): Project[]
async setActiveProject(projectId: string): Promise
getActiveProject(): Project | null
// Project Lifecycle
async deleteProject(projectId: string, options?: DeleteProjectOptions): Promise
async disableProject(projectId: string): Promise
async enableProject(projectId: string): Promise
async disableProjects(projectIds: string[]): Promise
async enableProjects(projectIds: string[]): Promise
isProjectEnabled(projectId: string): boolean
async getDisabledProjects(): Promise
// Cross-Project Operations
async copyFiles(sourceId: string, pattern: string, targetId: string, targetPath: string): Promise
async syncProjects(sourceId: string, targetId: string, options?: SyncOptions): Promise
async compareProjects(projectId1: string, projectId2: string): Promise
// Provider Management
registerProvider(provider: SourceProvider): void
unregisterProvider(scheme: string): void
getProvider(scheme: string): SourceProvider | undefined
getRegisteredProviders(): SourceProvider[]
// Performance & Statistics
async getProjectStats(): Promise
async getProjectMetrics(projectId: string): Promise
async optimizeMemoryUsage(): Promise
// Discovery & Persistence
async discoverIndexedDBProjects(): Promise
async exportWorkspace(options?: ExportOptions): Promise
async importFromUrl(url: string): Promise
// All IReactiveFileSystem methods (proxied to active project)
async readFile(path: string): Promise
async writeFile(path: string, content: any): Promise
// ... (all file system operations)
// Event System
readonly events: TypedEventEmitter
// Lifecycle
async initialize(config?: WorkspaceConfig): Promise
async clear(): Promise
async close(): Promise
}
`$3
`typescript
interface Project {
id: string
name: string
source: ProjectSource
fs: IReactiveFileSystem
metadata: ProjectMetadata
state: "loading" | "loaded" | "error" | "disabled"
lastAccessed: Date
accessCount: number
memoryUsage: number
}interface ProjectSource {
type: "memory" | "indexeddb" | "s3" | "github" | "api" | "json-url"
config: any
auth?: SourceAuth
}
interface DeleteProjectOptions {
deleteData?: boolean // Also delete project data (provider-specific)
skipConfirmation?: boolean // Skip confirmation event
}
interface SourceProvider {
readonly scheme: string
readonly displayName: string
createFileSystem(config: any): Promise
getCapabilities(): IFileSystemCapabilities
validateConfiguration?(config: any): Promise<{ valid: boolean; errors?: string[] }>
dispose?(fs: IReactiveFileSystem): Promise
// Optional data management methods
deleteProjectData?(config: any): Promise
hasLocalData?(): boolean
estimateDataSize?(config: any): Promise
}
interface WorkspaceSettings {
maxActiveProjects?: number // Auto-disable when exceeded
autoDisableAfter?: number // Ms of inactivity before auto-disable
keepFocusedActive?: boolean // Never auto-disable focused project
autoSave?: boolean
autoSaveInterval?: number
memoryThreshold?: number // Bytes before optimization
}
`๐ง Configuration
$3
`bash
S3 Configuration
FIRESYSTEM_S3_ACCESS_KEY_ID=your_access_key
FIRESYSTEM_S3_SECRET_ACCESS_KEY=your_secret_key
FIRESYSTEM_S3_REGION=us-east-1GitHub Configuration
FIRESYSTEM_GITHUB_TOKEN=ghp_xxxxxxxxxxxx
GITHUB_TOKEN=ghp_xxxxxxxxxxxx # FallbackAPI Configuration
FIRESYSTEM_API_API_KEY=your_api_key
FIRESYSTEM_API_BASE_URL=https://api.example.com
`$3
`typescript
const workspace = new WorkspaceFileSystem({
settings: {
maxActiveProjects: 10, // Keep 10 projects active max
autoDisableAfter: 1800000, // 30 minutes
keepFocusedActive: true, // Protect focused project
autoSave: true, // Auto-save state changes
autoSaveInterval: 60000, // Save every minute
memoryThreshold: 512 1024 1024 // 512MB threshold
}
});
`๐จ Migration Guide
$3
`typescript
// Before: Single project at a time
class OldWorkflow {
async switchToProject(projectId: string) {
await this.closeCurrentProject(); // Lost from memory
await this.openProject(projectId); // Load from scratch
}
async copyToOtherProject(file: string, targetProject: string) {
const content = await this.readFile(file);
await this.closeCurrentProject(); // Lose current context
await this.openProject(targetProject);
await this.writeFile(file, content);
await this.closeCurrentProject(); // Lose target context
await this.openOriginalProject(); // Reload original
}
}// After: Multi-project simultaneous access
class NewWorkflow {
async switchToProject(projectId: string) {
await workspace.setActiveProject(projectId); // Just change focus
// All other projects remain active and accessible!
}
async copyToOtherProject(file: string, targetProjectId: string) {
const source = workspace.getActiveProject();
const target = workspace.getProject(targetProjectId);
const content = await source.fs.readFile(file);
await target.fs.writeFile(file, content);
// Both projects remain active, no context loss!
}
}
`$3
| Version | Release Date | Key Features |
|---------|-------------|--------------|
| v1.0.7 | 2025-07-02 | ๐๏ธ Complete deleteProject, provider data management |
| v1.0.4 | 2025-06-30 | ๐งช Comprehensive test suite, robust validation |
| v1.0.3 | 2025-06-30 | ๐งน Auto-cleanup, empty-by-design, robust validation |
| v1.0.2 | 2025-06-30 | ๐ Complete workspace system with persistence |
| v1.0.1 | 2025-06-30 | ๐ฆ Initial release with multi-project support |
๐ค Contributing
We welcome contributions! Please see our Contributing Guide for details.
$3
`bash
Clone the repository
git clone https://github.com/firesystem/firesystem.git
cd firesystem/packages/workspaceInstall dependencies
pnpm installRun tests
pnpm testType checking
pnpm typecheckBuild
pnpm build
``MIT ยฉ Anderson D. Rosa
- Built on top of the robust @firesystem/core foundation
- Inspired by VSCode's multi-root workspace concept, but taken to the next level
- Thanks to the TypeScript team for excellent type system
- IndexedDB API for reliable browser persistence
- The open source community for continuous inspiration
---
๐ฅ Transform your development workflow with true multi-project parallelism!