@firesystem/workspace
Version:
Multi-project workspace manager for Firesystem with support for multiple sources
166 lines (147 loc) • 4.18 kB
text/typescript
import type { WorkspaceConfig, ProjectConfig } from "../types";
export 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
*/
export class WorkspaceImporter {
/**
* Import workspace from JSON URL
*/
static async fromJsonUrl(url: string): Promise<WorkspaceConfig> {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`Failed to fetch workspace: ${response.statusText}`);
}
const data: WorkspaceExport = await response.json();
return this.parseExport(data);
}
/**
* Import workspace from GitHub Gist
*/
static async fromGitHubGist(gistId: string, token?: string): Promise<WorkspaceConfig> {
const headers: Record<string, string> = {
"Accept": "application/vnd.github.v3+json"
};
if (token) {
headers["Authorization"] = `token ${token}`;
}
const response = await fetch(`https://api.github.com/gists/${gistId}`, {
headers
});
if (!response.ok) {
throw new Error(`Failed to fetch gist: ${response.statusText}`);
}
const gist = await response.json();
// Look for workspace.json file in the gist
const workspaceFile = Object.values(gist.files).find(
(file: any) => file.filename === "workspace.json"
) as any;
if (!workspaceFile) {
throw new Error("No workspace.json found in gist");
}
const data: WorkspaceExport = JSON.parse(workspaceFile.content);
return this.parseExport(data);
}
/**
* Import workspace from API endpoint
*/
static async fromApi(
url: string,
options?: {
headers?: Record<string, string>;
method?: string;
body?: any;
}
): Promise<WorkspaceConfig> {
const response = await fetch(url, {
method: options?.method || "GET",
headers: {
"Content-Type": "application/json",
...options?.headers
},
body: options?.body ? JSON.stringify(options.body) : undefined
});
if (!response.ok) {
throw new Error(`Failed to fetch from API: ${response.statusText}`);
}
const data: WorkspaceExport = await response.json();
return this.parseExport(data);
}
/**
* Parse export data into workspace config
*/
private static parseExport(data: WorkspaceExport): WorkspaceConfig {
// Validate version
if (!data.version || !data.version.startsWith("1.")) {
throw new Error(`Unsupported workspace version: ${data.version}`);
}
const projects: ProjectConfig[] = data.projects.map(p => {
// Determine source based on type and presence of files
let source: any;
if (p.files && p.files.length > 0) {
// If files are included, create memory source with initial data
source = {
type: "memory",
config: {
initialData: p.files.reduce((acc, file) => {
acc[file.path] = {
content: file.content,
metadata: file.metadata
};
return acc;
}, {} as Record<string, any>)
}
};
} else if (p.type === "indexeddb") {
// IndexedDB reference
source = {
type: "indexeddb",
config: {
dbName: p.config?.dbName || `firesystem-${p.id}`
}
};
} else if (p.type === "s3") {
// S3 reference
source = {
type: "s3",
config: p.config
};
} else {
// Default to empty memory
source = {
type: "memory",
config: {}
};
}
return {
id: p.id,
name: p.name,
source
};
});
return {
version: data.version,
projects,
activeProjectId: data.workspace.activeProjectId,
settings: data.workspace.settings
};
}
}