Buckets:
| import { beforeAll, beforeEach, describe, expect, mock, test } from "bun:test" | |
| import { ServerScope } from "./server-scope" | |
| type PersistTestingType = typeof import("./persist").PersistTesting | |
| type PersistType = typeof import("./persist").Persist | |
| type RemovePersistedType = typeof import("./persist").removePersisted | |
| class MemoryStorage implements Storage { | |
| private values = new Map<string, string>() | |
| readonly events: string[] = [] | |
| readonly calls = { get: 0, set: 0, remove: 0 } | |
| clear() { | |
| this.values.clear() | |
| } | |
| get length() { | |
| return this.values.size | |
| } | |
| key(index: number) { | |
| return Array.from(this.values.keys())[index] ?? null | |
| } | |
| getItem(key: string) { | |
| this.calls.get += 1 | |
| this.events.push(`get:${key}`) | |
| if (key.startsWith("opencode.throw")) throw new Error("storage get failed") | |
| return this.values.get(key) ?? null | |
| } | |
| setItem(key: string, value: string) { | |
| this.calls.set += 1 | |
| this.events.push(`set:${key}`) | |
| if (key.startsWith("opencode.quota")) throw new DOMException("quota", "QuotaExceededError") | |
| if (key.startsWith("opencode.throw")) throw new Error("storage set failed") | |
| this.values.set(key, value) | |
| } | |
| removeItem(key: string) { | |
| this.calls.remove += 1 | |
| this.events.push(`remove:${key}`) | |
| if (key.startsWith("opencode.throw")) throw new Error("storage remove failed") | |
| this.values.delete(key) | |
| } | |
| } | |
| const storage = new MemoryStorage() | |
| let persistTesting: PersistTestingType | |
| let Persist: PersistType | |
| let removePersisted: RemovePersistedType | |
| beforeAll(async () => { | |
| mock.module("@/context/platform", () => ({ | |
| usePlatform: () => ({ platform: "web" }), | |
| })) | |
| const mod = await import("./persist") | |
| persistTesting = mod.PersistTesting | |
| Persist = mod.Persist | |
| removePersisted = mod.removePersisted | |
| }) | |
| beforeEach(() => { | |
| storage.clear() | |
| storage.events.length = 0 | |
| storage.calls.get = 0 | |
| storage.calls.set = 0 | |
| storage.calls.remove = 0 | |
| Object.defineProperty(globalThis, "localStorage", { | |
| value: storage, | |
| configurable: true, | |
| }) | |
| }) | |
| describe("persist localStorage resilience", () => { | |
| test("does not cache values as persisted when quota write and eviction fail", () => { | |
| const storageApi = persistTesting.localStorageWithPrefix("opencode.quota.scope") | |
| storageApi.setItem("value", '{"value":1}') | |
| expect(storage.getItem("opencode.quota.scope:value")).toBeNull() | |
| expect(storageApi.getItem("value")).toBeNull() | |
| }) | |
| test("disables only the failing scope when storage throws", () => { | |
| const bad = persistTesting.localStorageWithPrefix("opencode.throw.scope") | |
| bad.setItem("value", '{"value":1}') | |
| const before = storage.calls.set | |
| bad.setItem("value", '{"value":2}') | |
| expect(storage.calls.set).toBe(before) | |
| expect(bad.getItem("value")).toBeNull() | |
| const healthy = persistTesting.localStorageWithPrefix("opencode.safe.scope") | |
| healthy.setItem("value", '{"value":3}') | |
| expect(storage.getItem("opencode.safe.scope:value")).toBe('{"value":3}') | |
| }) | |
| test("failing fallback scope does not poison direct storage scope", () => { | |
| const broken = persistTesting.localStorageWithPrefix("opencode.throw.scope2") | |
| broken.setItem("value", '{"value":1}') | |
| const direct = persistTesting.localStorageDirect() | |
| direct.setItem("direct-value", '{"value":5}') | |
| expect(storage.getItem("direct-value")).toBe('{"value":5}') | |
| }) | |
| test("normalizer rejects malformed JSON payloads", () => { | |
| const result = persistTesting.normalize({ value: "ok" }, '{"value":"\\x"}') | |
| expect(result).toBeUndefined() | |
| }) | |
| test("workspace storage sanitizes Windows filename characters", () => { | |
| const result = persistTesting.workspaceStorage("C:\\Users\\foo") | |
| expect(result).toStartWith("opencode.workspace.") | |
| expect(result.endsWith(".dat")).toBeTrue() | |
| expect(/[:\\/]/.test(result)).toBeFalse() | |
| }) | |
| test("workspace target keeps raw path storage as legacy fallback", () => { | |
| const target = Persist.workspace("C:\\Users\\foo", "vcs") | |
| expect(target.storage).toBe(persistTesting.workspaceStorage("C:/Users/foo")) | |
| expect(target.legacyStorageNames).toEqual([persistTesting.workspaceStorage("C:\\Users\\foo")]) | |
| }) | |
| test("workspace target keeps backslash storage as fallback for normalized Windows paths", () => { | |
| const target = Persist.workspace("C:/Users/foo", "vcs") | |
| expect(target.storage).toBe(persistTesting.workspaceStorage("C:/Users/foo")) | |
| expect(target.legacyStorageNames).toEqual([persistTesting.workspaceStorage("C:\\Users\\foo")]) | |
| }) | |
| test("migrates direct legacy keys into scoped storage", () => { | |
| storage.setItem("legacy.workspace", '{"value":2}') | |
| const target = Persist.workspace("C:/Users/foo", "demo", ["legacy.workspace"]) | |
| const current = persistTesting.localStorageWithPrefix(target.storage!) | |
| const legacyStore = persistTesting.localStorageDirect() | |
| const result = persistTesting.migrateLegacy({ | |
| current, | |
| legacyStore, | |
| stores: [], | |
| keys: target.legacy!, | |
| key: target.key, | |
| defaults: { value: 1 }, | |
| }) | |
| expect(result).toBe('{"value":2}') | |
| expect(storage.getItem(`${target.storage}:${target.key}`)).toBe('{"value":2}') | |
| expect(legacyStore.getItem("legacy.workspace")).toBeNull() | |
| expect(storage.getItem("legacy.workspace")).toBeNull() | |
| }) | |
| test("removes legacy workspace storage when removing persisted target", () => { | |
| const target = Persist.workspace("C:\\Users\\foo", "terminal") | |
| storage.setItem(`${target.storage}:${target.key}`, '{"value":1}') | |
| storage.setItem(`${target.legacyStorageNames![0]}:${target.key}`, '{"value":2}') | |
| removePersisted(target) | |
| expect(storage.getItem(`${target.storage}:${target.key}`)).toBeNull() | |
| expect(storage.getItem(`${target.legacyStorageNames![0]}:${target.key}`)).toBeNull() | |
| }) | |
| test("draft target isolates storage per draft and namespaces keys", () => { | |
| const a = Persist.draft("draft-a", "prompt") | |
| const b = Persist.draft("draft-b", "prompt") | |
| expect(a.key).toBe("draft:prompt") | |
| expect(a.storage).not.toBe(b.storage) | |
| expect(a.storage).not.toBe(Persist.workspace("/home/luke/repo", "prompt").storage) | |
| }) | |
| test("removes draft storage when removing persisted target", () => { | |
| const target = Persist.draft("draft-a", "prompt") | |
| storage.setItem(`${target.storage}:${target.key}`, '{"value":1}') | |
| removePersisted(target) | |
| expect(storage.getItem(`${target.storage}:${target.key}`)).toBeNull() | |
| }) | |
| test("server workspace target preserves local storage and isolates remote storage", () => { | |
| const local = Persist.serverWorkspace(ServerScope.local, "/home/luke/repo", "prompt") | |
| const windows = Persist.serverWorkspace("https://windows.example" as ServerScope, "/home/luke/repo", "prompt") | |
| const debian = Persist.serverWorkspace("https://debian.example" as ServerScope, "/home/luke/repo", "prompt") | |
| expect(local).toEqual(Persist.workspace("/home/luke/repo", "prompt")) | |
| expect(windows.storage).not.toBe(local.storage) | |
| expect(debian.storage).not.toBe(local.storage) | |
| expect(debian.storage).not.toBe(windows.storage) | |
| expect(windows.legacyStorageNames).toBeUndefined() | |
| expect(debian.legacyStorageNames).toBeUndefined() | |
| }) | |
| test("server global target preserves local key and isolates remote keys", () => { | |
| expect(Persist.serverGlobal(ServerScope.local, "notification")).toEqual(Persist.global("notification")) | |
| expect(Persist.serverGlobal("https://debian.example" as ServerScope, "notification")).toEqual({ | |
| storage: "opencode.global.dat", | |
| key: "https://debian.example\0notification", | |
| }) | |
| }) | |
| test("server global target cannot collide when scope and key contain colons", () => { | |
| expect(Persist.serverGlobal("a:b" as ServerScope, "c")).not.toEqual(Persist.serverGlobal("a" as ServerScope, "b:c")) | |
| }) | |
| }) | |
Xet Storage Details
- Size:
- 7.86 kB
- Xet hash:
- ee3e11a3b5efd421fd8ebdd160161aad0cfa4ec5e92157d1aea0103f74e0d5d2
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.