Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
import { idb } from "$lib/remult.js"; | |
import { snapshot } from "$lib/utils/object.svelte"; | |
import { dequal } from "dequal"; | |
import { Entity, Fields, repo } from "remult"; | |
import { conversations, type ConversationEntityMembers } from "./conversations.svelte"; | |
import { ProjectEntity, projects } from "./projects.svelte"; | |
"checkpoint") | (|
export class Checkpoint { | |
cuid() | .|
id!: string; | |
boolean() | .|
favorite: boolean = false; | |
createdAt() | .|
timestamp!: Date; | |
json() | .|
conversations: ConversationEntityMembers[] = []; | |
string() | .|
projectId!: string; | |
} | |
const checkpointsRepo = repo(Checkpoint, idb); | |
class Checkpoints { | |
#checkpoints: Record<ProjectEntity["id"], Checkpoint[]> = $state({}); | |
for(projectId: ProjectEntity["id"]) { | |
// Async load from db | |
checkpointsRepo | |
.find({ | |
where: { | |
projectId, | |
}, | |
}) | |
.then(c => { | |
// Dequal to avoid infinite loops | |
if (dequal(c, this.#checkpoints[projectId])) return; | |
this.#checkpoints[projectId] = c; | |
}); | |
return ( | |
this.#checkpoints[projectId]?.toSorted((a, b) => { | |
const aTime = a.timestamp?.getTime() ?? new Date().getTime(); | |
const bTime = b.timestamp?.getTime() ?? new Date().getTime(); | |
return bTime - aTime; | |
}) ?? [] | |
); | |
} | |
async commit(projectId: ProjectEntity["id"]) { | |
const project = projects.all.find(p => p.id == projectId); | |
if (!project) return; | |
const newCheckpoint = await checkpointsRepo.save( | |
snapshot({ | |
conversations: conversations.for(project.id).map(c => c.data), | |
timestamp: new Date(), | |
projectId: project.id, | |
}) | |
); | |
// Hack because dates are formatted to string by save | |
newCheckpoint.conversations.forEach((c, i) => { | |
newCheckpoint.conversations[i] = { ...c, createdAt: new Date(c.createdAt) }; | |
}); | |
const prev: Checkpoint[] = this.#checkpoints[projectId] ?? []; | |
this.#checkpoints[projectId] = [...prev, newCheckpoint]; | |
} | |
restore(checkpoint: Checkpoint) { | |
const cloned = snapshot(checkpoint); | |
const modified = { | |
...cloned, | |
conversations: cloned.conversations.map(c => ({ | |
...c, | |
projectId: cloned.projectId, | |
})), | |
}; | |
const project = projects.all.find(p => p.id == modified.projectId); | |
if (!project) return; | |
projects.activeId = modified.projectId; | |
// conversations.deleteAllFrom(cloned.projectId); | |
const prev = conversations.for(modified.projectId); | |
modified.conversations.forEach((c, i) => { | |
const prevC = prev[i]; | |
if (prevC) return prevC.update({ ...c }); | |
conversations.create({ | |
...c, | |
projectId: modified.projectId, | |
}); | |
}); | |
if (modified.conversations.length < prev.length) { | |
prev.forEach((p, i) => { | |
if (i < modified.conversations.length) return; | |
conversations.delete(p.data); | |
}); | |
} | |
} | |
async toggleFavorite({ id, projectId }: Checkpoint) { | |
if (!id) return; | |
const p = await checkpointsRepo.findFirst({ id }); | |
if (!p) return; | |
await checkpointsRepo.update(id, { favorite: !p.favorite }); | |
const prev: Checkpoint[] = snapshot(this.#checkpoints[projectId] ?? []); | |
this.#checkpoints[projectId] = prev.map(c => { | |
if (c.id !== id) return c; | |
return { ...c, favorite: !c.favorite }; | |
}); | |
} | |
async delete({ id, projectId }: Checkpoint) { | |
if (!id) return; | |
await checkpointsRepo.delete(id); | |
const prev: Checkpoint[] = this.#checkpoints[projectId] ?? []; | |
this.#checkpoints[projectId] = prev.filter(c => c.id != id); | |
} | |
async clear(projectId: ProjectEntity["id"]) { | |
await checkpointsRepo.deleteMany({ where: { projectId } }); | |
this.#checkpoints[projectId] = []; | |
} | |
async migrate(from: ProjectEntity["id"], to: ProjectEntity["id"]) { | |
await checkpointsRepo.updateMany({ where: { projectId: from }, set: { projectId: to } }); | |
const fromArr = snapshot(this.#checkpoints[from] ?? []); | |
this.#checkpoints[to] = [ | |
...fromArr.map(c => ({ | |
...c, | |
projectId: to, | |
conversations: c.conversations.map(cn => ({ ...cn, projectId: to })), | |
})), | |
]; | |
this.#checkpoints[from] = []; | |
} | |
} | |
export const checkpoints = new Checkpoints(); | |