Files
oldboy/src/lib/project-system/project-manager.ts
2025-10-14 21:32:35 +02:00

344 lines
8.6 KiB
TypeScript

import type { CsoundProject, CreateProjectData, UpdateProjectData, Result } from './types';
import { projectDb } from './db';
import { compressProject, decompressProject, projectToShareUrl, projectFromShareUrl } from './compression';
const CSOUND_VERSION = '7.0.0'; // This should be detected from @csound/browser
/**
* Generate a unique ID for a project
*/
function generateId(): string {
return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
}
/**
* Get the current ISO timestamp
*/
function getCurrentTimestamp(): string {
return new Date().toISOString();
}
/**
* Project Manager - Main API for managing Csound projects
*/
export class ProjectManager {
/**
* Initialize the project manager (initializes database)
*/
async init(): Promise<void> {
await projectDb.init();
}
/**
* Create a new project
*/
async createProject(data: CreateProjectData): Promise<Result<CsoundProject>> {
try {
const now = getCurrentTimestamp();
const project: CsoundProject = {
id: generateId(),
title: data.title,
author: data.author,
dateCreated: now,
dateModified: now,
saveCount: 0,
content: data.content || '',
tags: data.tags || [],
csoundVersion: CSOUND_VERSION,
};
await projectDb.put(project);
return { success: true, data: project };
} catch (error) {
return {
success: false,
error: error instanceof Error ? error : new Error('Failed to create project'),
};
}
}
/**
* Get a project by ID
*/
async getProject(id: string): Promise<Result<CsoundProject>> {
try {
const project = await projectDb.get(id);
if (!project) {
return {
success: false,
error: new Error(`Project not found: ${id}`),
};
}
return { success: true, data: project };
} catch (error) {
return {
success: false,
error: error instanceof Error ? error : new Error('Failed to get project'),
};
}
}
/**
* Get all projects
*/
async getAllProjects(): Promise<Result<CsoundProject[]>> {
try {
const projects = await projectDb.getAll();
return { success: true, data: projects };
} catch (error) {
return {
success: false,
error: error instanceof Error ? error : new Error('Failed to get projects'),
};
}
}
/**
* Update an existing project
*/
async updateProject(data: UpdateProjectData): Promise<Result<CsoundProject>> {
try {
const existingProject = await projectDb.get(data.id);
if (!existingProject) {
return {
success: false,
error: new Error(`Project not found: ${data.id}`),
};
}
const updatedProject: CsoundProject = {
...existingProject,
...(data.title !== undefined && { title: data.title }),
...(data.author !== undefined && { author: data.author }),
...(data.content !== undefined && { content: data.content }),
...(data.tags !== undefined && { tags: data.tags }),
dateModified: getCurrentTimestamp(),
saveCount: existingProject.saveCount + 1,
};
await projectDb.put(updatedProject);
return { success: true, data: updatedProject };
} catch (error) {
return {
success: false,
error: error instanceof Error ? error : new Error('Failed to update project'),
};
}
}
/**
* Delete a project
*/
async deleteProject(id: string): Promise<Result<void>> {
try {
await projectDb.delete(id);
return { success: true, data: undefined };
} catch (error) {
return {
success: false,
error: error instanceof Error ? error : new Error('Failed to delete project'),
};
}
}
/**
* Search projects by tag
*/
async getProjectsByTag(tag: string): Promise<Result<CsoundProject[]>> {
try {
const projects = await projectDb.getByTag(tag);
return { success: true, data: projects };
} catch (error) {
return {
success: false,
error: error instanceof Error ? error : new Error('Failed to search projects by tag'),
};
}
}
/**
* Search projects by author
*/
async getProjectsByAuthor(author: string): Promise<Result<CsoundProject[]>> {
try {
const projects = await projectDb.getByAuthor(author);
return { success: true, data: projects };
} catch (error) {
return {
success: false,
error: error instanceof Error ? error : new Error('Failed to search projects by author'),
};
}
}
/**
* Export a project to a shareable URL
*/
async exportProjectToUrl(id: string, baseUrl?: string): Promise<Result<string>> {
try {
const project = await projectDb.get(id);
if (!project) {
return {
success: false,
error: new Error(`Project not found: ${id}`),
};
}
const url = projectToShareUrl(project, baseUrl);
return { success: true, data: url };
} catch (error) {
return {
success: false,
error: error instanceof Error ? error : new Error('Failed to export project'),
};
}
}
/**
* Export a project to compressed data (for copying to clipboard, etc.)
*/
async exportProjectToCompressed(id: string): Promise<Result<string>> {
try {
const project = await projectDb.get(id);
if (!project) {
return {
success: false,
error: new Error(`Project not found: ${id}`),
};
}
const compressed = compressProject(project);
return { success: true, data: compressed.data };
} catch (error) {
return {
success: false,
error: error instanceof Error ? error : new Error('Failed to export project'),
};
}
}
/**
* Import a project from a URL
*/
async importProjectFromUrl(url: string): Promise<Result<CsoundProject>> {
try {
const project = projectFromShareUrl(url);
// Generate a new ID and reset timestamps
const now = getCurrentTimestamp();
const importedProject: CsoundProject = {
...project,
id: generateId(),
dateCreated: now,
dateModified: now,
saveCount: 0,
title: `${project.title} (imported)`,
};
await projectDb.put(importedProject);
return { success: true, data: importedProject };
} catch (error) {
return {
success: false,
error: error instanceof Error ? error : new Error('Failed to import project'),
};
}
}
/**
* Import a project from compressed data
*/
async importProjectFromCompressed(compressedData: string): Promise<Result<CsoundProject>> {
try {
const project = decompressProject({
data: compressedData,
version: 1,
});
// Generate a new ID and reset timestamps
const now = getCurrentTimestamp();
const importedProject: CsoundProject = {
...project,
id: generateId(),
dateCreated: now,
dateModified: now,
saveCount: 0,
title: `${project.title} (imported)`,
};
await projectDb.put(importedProject);
return { success: true, data: importedProject };
} catch (error) {
return {
success: false,
error: error instanceof Error ? error : new Error('Failed to import project'),
};
}
}
/**
* Duplicate a project
*/
async duplicateProject(id: string): Promise<Result<CsoundProject>> {
try {
const originalProject = await projectDb.get(id);
if (!originalProject) {
return {
success: false,
error: new Error(`Project not found: ${id}`),
};
}
const now = getCurrentTimestamp();
const duplicatedProject: CsoundProject = {
...originalProject,
id: generateId(),
title: `${originalProject.title} (copy)`,
dateCreated: now,
dateModified: now,
saveCount: 0,
};
await projectDb.put(duplicatedProject);
return { success: true, data: duplicatedProject };
} catch (error) {
return {
success: false,
error: error instanceof Error ? error : new Error('Failed to duplicate project'),
};
}
}
/**
* Clear all projects (use with caution!)
*/
async clearAllProjects(): Promise<Result<void>> {
try {
await projectDb.clear();
return { success: true, data: undefined };
} catch (error) {
return {
success: false,
error: error instanceof Error ? error : new Error('Failed to clear projects'),
};
}
}
}
// Export singleton instance
export const projectManager = new ProjectManager();