@workspace-fs/core
Version:
Multi-project workspace manager for Firesystem with support for multiple sources
173 lines (153 loc) • 4.25 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,
};
}
}