Something went wrong. Try again.
opencode v2 mirror
Something went wrong. Try again.
TypeScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267import { describe, expect, test } from "bun:test"import { Schema } from "effect"import { IconState, ModelState, ProjectState, VcsState, serverState } from "./persistence"import { createRoot } from "solid-js"import { isServer } from "solid-js/web"import { Persist, persisted } from "@/runtime/persistence/storage"import { Persistence } from "@/runtime/persistence/schema"
const initial = { list: [], hidden: {}, projects: {}, lastProject: {}, recentlyClosed: {} }
function serverSchema(canonical?: () => string | undefined) { return Persistence.withInitial(serverState(canonical), initial)}
describe("server persistence schema", () => { test("migrates legacy auth and writes only current server objects", () => { const schema = serverSchema() const input = { list: [ "http://localhost:4096", { url: "https://flat.example", username: "legacy", password: "first" }, { type: "http", displayName: "Remote", label: "Production", authToken: true, http: { url: "https://nested.example", username: "legacy", password: "second" }, }, ], projects: { local: [{ worktree: "/project", expanded: true }] }, } const state = Schema.decodeUnknownSync(schema)(input) expect(state).toEqual({ list: [ { type: "http", http: { url: "http://localhost:4096" } }, { type: "http", http: { url: "https://flat.example", password: "first" } }, { type: "http", displayName: "Remote", label: "Production", authToken: true, http: { url: "https://nested.example", password: "second" }, }, ], hidden: {}, projects: input.projects, lastProject: {}, recentlyClosed: {}, }) expect(input.list[1]).toHaveProperty("username", "legacy") const encoded = Schema.encodeSync(schema)(state) expect(encoded).toEqual(state) expect(Schema.decodeUnknownSync(schema)(encoded)).toEqual(state) })
test("defaults missing or malformed fields and drops invalid entries independently", () => { const decode = Schema.decodeUnknownSync(serverSchema()) const empty = { list: [], hidden: {}, projects: {}, lastProject: {}, recentlyClosed: {} } expect(decode({})).toEqual(empty) expect(decode({ list: null, hidden: [], projects: false, lastProject: 1, recentlyClosed: "bad" })).toEqual(empty) expect( decode({ list: [null, 1, {}, { type: "http", http: { url: 12 } }, "https://valid.example"], projects: { local: [null, {}, { worktree: 1 }, { worktree: "/project" }], remote: false }, recentlyClosed: { local: [null, 1, "/closed"], remote: null }, }), ).toEqual({ ...empty, list: [{ type: "http", http: { url: "https://valid.example" } }], projects: { local: [{ worktree: "/project", expanded: true }], remote: [] }, recentlyClosed: { local: ["/closed"], remote: [] }, }) })
test("moves canonical project buckets without changing server keys or unrelated scopes", () => { const schema = serverSchema(() => "https://opencode.example.com") const state = Schema.decodeUnknownSync(schema)({ list: ["https://opencode.example.com"], hidden: { "https://opencode.example.com": true }, projects: { local: [{ worktree: "/local", expanded: false }], "https://opencode.example.com": [ { worktree: "/local", expanded: true }, { worktree: "/remote", expanded: true }, { worktree: "/remote", expanded: false }, ], other: [{ worktree: "/other", expanded: true }], }, lastProject: { local: "/local", "https://opencode.example.com": "/remote", other: "/other" }, recentlyClosed: { local: ["/closed"], "https://opencode.example.com": ["/old-closed"] }, }) expect(state.projects).toEqual({ local: [ { worktree: "/local", expanded: false }, { worktree: "/remote", expanded: true }, ], other: [{ worktree: "/other", expanded: true }], }) expect(state.lastProject).toEqual({ local: "/local", other: "/other" }) expect(state.list[0]?.http.url).toBe("https://opencode.example.com") expect(state.hidden).toEqual({ "https://opencode.example.com": true }) expect(state.recentlyClosed).toEqual({ local: ["/closed"], "https://opencode.example.com": ["/old-closed"] }) expect(Schema.encodeSync(schema)(state)).toEqual(state) expect(Schema.decodeUnknownSync(schema)(state)).toEqual(state) })
test("reads the latest canonical local prop on each decode", () => { const props: { canonicalLocalServer?: string } = {} const schema = serverSchema(() => props.canonicalLocalServer) const decode = Schema.decodeUnknownSync(schema) const input = { projects: { remote: [{ worktree: "/project", expanded: true }] }, lastProject: { remote: "/project" }, } expect(decode(input).projects).toEqual(input.projects) props.canonicalLocalServer = "remote" expect(decode(input).projects).toEqual({ local: [{ worktree: "/project", expanded: true }] }) expect(decode(input).lastProject).toEqual({ local: "/project" }) props.canonicalLocalServer = "local" expect(decode(input).projects).toEqual(input.projects) expect(input.lastProject).toEqual({ remote: "/project" }) })
test("migrates a last project without a project list", () => { expect(Schema.decodeUnknownSync(serverSchema(() => "remote"))({ lastProject: { remote: "/project" } })).toEqual({ list: [], hidden: {}, projects: {}, lastProject: { local: "/project" }, recentlyClosed: {}, }) })})
describe("model persistence schema", () => { test("defaults missing state and keeps valid entries beside malformed entries", () => { const decode = Schema.decodeUnknownSync(Persistence.withInitial(ModelState, { user: [], recent: [], variant: {} })) expect(decode({})).toEqual({ user: [], recent: [], variant: {} }) expect(decode({ user: null, recent: 1, variant: [] })).toEqual({ user: [], recent: [], variant: {} }) const state = decode({ user: [ null, { providerID: "provider", modelID: "model", visibility: "show", favorite: true }, { providerID: "provider", modelID: "invalid", visibility: "invalid" }, { providerID: "provider", modelID: "hidden", visibility: "hide" }, ], recent: [false, { providerID: "provider", modelID: "model" }, { providerID: "missing-model" }], variant: { model: "high" }, }) expect(state).toEqual({ user: [ { providerID: "provider", modelID: "model", visibility: "show", favorite: true }, { providerID: "provider", modelID: "hidden", visibility: "hide" }, ], recent: [{ providerID: "provider", modelID: "model" }], variant: { model: "high" }, }) expect(Schema.encodeSync(ModelState)(state)).toEqual(state) })})
describe("directory cache schemas", () => { test("defaults missing and malformed VCS caches but retains optional branch metadata", () => { const decode = Schema.decodeUnknownSync(Persistence.withInitial(VcsState, { value: undefined })) expect(decode({})).toEqual({ value: undefined }) expect(decode({ value: null })).toEqual({ value: undefined }) expect(decode({ value: { branch: 1 } })).toEqual({ value: undefined }) expect(decode({ value: { default_branch: "main" } })).toEqual({ value: { default_branch: "main" } }) const state = decode({ value: { branch: "feature", default_branch: "main", obsolete: true } }) expect(state).toEqual({ value: { branch: "feature", default_branch: "main" } }) expect(Schema.encodeSync(VcsState)(state)).toEqual(state) })
test("validates project name, icon overrides and startup commands", () => { const decode = Schema.decodeUnknownSync(Persistence.withInitial(ProjectState, { value: undefined })) expect(decode({})).toEqual({ value: undefined }) expect(decode({ value: [] })).toEqual({ value: undefined }) expect(decode({ value: { icon: { override: 1 } } })).toEqual({ value: undefined }) expect(decode({ value: { commands: { start: false } } })).toEqual({ value: undefined }) expect(decode({ value: {} })).toEqual({ value: {} }) const state = decode({ value: { name: "Project", icon: { override: "data:image/png;base64,abc", color: "blue" }, commands: { start: "bun dev" }, }, }) expect(Schema.encodeSync(ProjectState)(state)).toEqual(state) expect(state.value).toEqual({ name: "Project", icon: { override: "data:image/png;base64,abc", color: "blue" }, commands: { start: "bun dev" }, }) })
test("validates optional icon strings", () => { const decode = Schema.decodeUnknownSync(Persistence.withInitial(IconState, { value: undefined })) expect(decode({})).toEqual({ value: undefined }) expect(decode({ value: 42 })).toEqual({ value: undefined }) expect(decode({ value: null })).toEqual({ value: undefined }) expect(decode({ value: "" })).toEqual({ value: "" }) expect(Schema.encodeSync(IconState)(decode({ value: "data:image/png;base64,abc" }))).toEqual({ value: "data:image/png;base64,abc", }) })})
test.skipIf(isServer)( "persisted server relocation hydrates migrated state and writes current schema on updates", async () => { const values = new Map([ [ "default:server.v3", JSON.stringify({ list: [{ url: "https://remote.example", username: "legacy", password: "secret" }], projects: { "https://remote.example": [{ worktree: "/project", expanded: false }] }, lastProject: { "https://remote.example": "/project" }, }), ], ]) const root = createRoot((dispose) => ({ dispose, state: persisted( { ...Persist.global("server"), previousKey: "server.v3" }, serverState(() => "https://remote.example"), initial, { platform: "desktop", windowID: "test", openExternal() {}, restart: async () => {}, notify: async () => {}, openDirectoryPickerDialog: async () => null, storage: (name = "default") => ({ getItem: async (key) => values.get(`${name}:${key}`) ?? null, setItem: async (key, value) => { values.set(`${name}:${key}`, value) }, removeItem: async (key) => { values.delete(`${name}:${key}`) }, }), }, ), })) try { await root.state[3].promise expect(values.has("default:server.v3")).toBe(false) expect(root.state[0].list).toEqual([ { type: "http", http: { url: "https://remote.example", password: "secret" } }, ]) expect(root.state[0].projects).toEqual({ local: [{ worktree: "/project", expanded: false }] }) expect(root.state[0].lastProject).toEqual({ local: "/project" }) root.state[1]("projects", "local", 0, "expanded", true) const stored = values.get("opencode.global.dat:server") expect(stored).toBeDefined() if (!stored) throw new Error("server state was not written") const decoded = Schema.decodeUnknownSync(Schema.fromJsonString(serverSchema()))(stored) expect(decoded.projects.local).toEqual([{ worktree: "/project", expanded: true }]) expect(stored).not.toContain("username") expect(decoded.list).toEqual(root.state[0].list) } finally { root.dispose() } },)