Automerge backed Markdown editor for the Atmosphere
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177import 'fake-indexeddb/auto'import { beforeEach, describe, expect, it, vi } from 'vitest'import { parseCatalog, downloadCatalogBundle } from '../plugin-catalog'import { ExternalPluginStore } from '../external-plugin-store'import { PluginRegistry } from '../plugin-registry'import { deleteCatalogBundle, readCatalogBundles } from '../catalog-storage'import * as storage from '../catalog-storage'import * as catalog from '../plugin-catalog'import { createTestManifest } from './test-utils'import { webcrypto } from 'node:crypto'
const entry = { manifest: createTestManifest({ id: 'catalog-test' }), repository: 'https://github.com/test/plugin', notes: 'Insertion tested', testedAt: '2026-10-10', bundlePath: 'bundles/catalog-test/1.0.0/', files: { 'main.js': 'a'.repeat(64) },}
beforeEach(async () => { for (const bundle of await readCatalogBundles()) await deleteCatalogBundle(bundle.manifest.id) localStorage.clear()})
describe('curated catalog boundary', () => { it('finishes durable removal despite a throwing change observer', async () => { const store = new ExternalPluginStore() const registry = new PluginRegistry() await store.installCatalog({ manifest: entry.manifest, mainJs: 'catalog code', sourceUrl: entry.repository, installedAt: 1 }, registry) store.on('change', () => { throw new Error('Change observer failed') }) await store.uninstallCatalog(entry.manifest.id) expect(store.getAll()).toEqual([]) expect(await readCatalogBundles()).toEqual([]) }) it('leaves old manual bundles byte-for-byte intact through the catalog lifecycle', async () => { const legacy = createTestManifest({ id: 'legacy-manual' }) const saved = JSON.stringify({ [legacy.id]: { manifest: legacy, mainJs: 'legacy code', stylesCss: 'body { display: none }', installedAt: 1 } }) localStorage.setItem('reams:external-plugins', saved) const createUrl = vi.spyOn(URL, 'createObjectURL') const bundle = { manifest: entry.manifest, mainJs: 'catalog code', sourceUrl: entry.repository, installedAt: 1 } const store = new ExternalPluginStore() expect(createUrl).not.toHaveBeenCalled() expect(store.isExternal(legacy.id)).toBe(false) await store.installCatalog(bundle, new PluginRegistry()) store.cleanup() const restored = new ExternalPluginStore() await restored.restoreCatalog(new PluginRegistry()) restored.setStylesEnabled(entry.manifest.id, false) await restored.uninstallCatalog(entry.manifest.id) expect(localStorage.getItem('reams:external-plugins')).toBe(saved) expect(document.getElementById(`reams-plugin-styles-${legacy.id}`)).toBeNull() expect(createUrl).toHaveBeenCalledTimes(2) // Only the admitted install and restore. })
it('serializes competing versions without overwriting the admitted durable bundle', async () => { const save = storage.saveCatalogBundle let release!: () => void const pending = new Promise<void>(resolve => { release = resolve }) let started!: () => void const begun = new Promise<void>(resolve => { started = resolve }) const saving = vi.spyOn(storage, 'saveCatalogBundle').mockImplementation(async bundle => { started() await pending await save(bundle) }) const createUrl = vi.spyOn(URL, 'createObjectURL') const store = new ExternalPluginStore() const registry = new PluginRegistry() const first = { manifest: entry.manifest, mainJs: 'version one', sourceUrl: entry.repository, installedAt: 1 } const installing = store.installCatalog(first, registry) await begun const competing = store.installCatalog({ ...first, manifest: { ...entry.manifest, version: '2.0.0' }, mainJs: 'version two' }, registry) const rejected = expect(competing).rejects.toThrow(/already installed/) expect(saving).toHaveBeenCalledOnce() release() await Promise.all([installing, rejected]) expect((await readCatalogBundles())[0]).toEqual(first) expect(store.get(entry.manifest.id)?.manifest.version).toBe(first.manifest.version) expect(createUrl).toHaveBeenCalledOnce() store.cleanup() })
it('coalesces duplicate release admission and serializes a subsequent uninstall', async () => { const store = new ExternalPluginStore() const registry = new PluginRegistry() const bundle = { manifest: entry.manifest, mainJs: 'same version', sourceUrl: entry.repository, installedAt: 1 } const createUrl = vi.spyOn(URL, 'createObjectURL') await Promise.all([store.installCatalog(bundle, registry), store.installCatalog(bundle, registry)]) expect(createUrl).toHaveBeenCalledOnce() expect(await readCatalogBundles()).toEqual([bundle]) await store.uninstallCatalog(entry.manifest.id) expect(store.getAll()).toEqual([]) expect(await readCatalogBundles()).toEqual([]) })
it('orders uninstall after an outstanding download so late completion cannot resurrect the bundle', async () => { const bundle = { manifest: entry.manifest, mainJs: 'downloaded', sourceUrl: entry.repository, installedAt: 1 } let finish!: (value: typeof bundle) => void const downloaded = new Promise<typeof bundle>(resolve => { finish = resolve }) const download = vi.spyOn(catalog, 'downloadCatalogBundle').mockReturnValue(downloaded) const store = new ExternalPluginStore() const installing = store.installFromCatalog(entry, new PluginRegistry()) await vi.waitFor(() => expect(download).toHaveBeenCalledOnce()) const removing = store.uninstallCatalog(entry.manifest.id) finish(bundle) await Promise.all([installing, removing]) expect(await readCatalogBundles()).toEqual([]) expect(store.getAll()).toEqual([]) })
it('does not overwrite durable admission when independent tab stores install competing versions', async () => { const stores = [new ExternalPluginStore(), new ExternalPluginStore()] const registries = [new PluginRegistry(), new PluginRegistry()] await Promise.all(stores.map((store, i) => store.restoreCatalog(registries[i]))) const results = await Promise.allSettled(stores.map((store, i) => store.installCatalog({ manifest: { ...entry.manifest, version: `${i + 1}.0.0` }, mainJs: `version ${i + 1}`, sourceUrl: entry.repository, installedAt: i, }, registries[i]))) expect(results.filter(result => result.status === 'fulfilled')).toHaveLength(1) const winner = results.findIndex(result => result.status === 'fulfilled') expect((await readCatalogBundles())[0].manifest.version).toBe(stores[winner].get(entry.manifest.id)?.manifest.version) stores.forEach(store => store.cleanup()) })
it('retries catalog restoration on the same store after a transient storage failure', async () => { vi.spyOn(storage, 'readCatalogBundles').mockRejectedValueOnce(new Error('Storage temporarily unavailable')).mockResolvedValue([]) const store = new ExternalPluginStore() const registry = new PluginRegistry() await expect(store.restoreCatalog(registry)).rejects.toThrow('Storage temporarily unavailable') await store.installCatalog({ manifest: entry.manifest, mainJs: 'retried', sourceUrl: entry.repository, installedAt: 1 }, registry) expect(store.isExternal(entry.manifest.id)).toBe(true) store.cleanup() })
it('revokes its temporary module and rolls back persistence if runtime admission fails', async () => { const registry = new PluginRegistry() vi.spyOn(registry, 'register').mockImplementation(() => { throw new Error('Runtime registration failed') }) const createUrl = vi.spyOn(URL, 'createObjectURL') const revoke = vi.spyOn(URL, 'revokeObjectURL') const store = new ExternalPluginStore() await expect(store.installCatalog({ manifest: entry.manifest, mainJs: 'unadmitted', sourceUrl: entry.repository, installedAt: 1 }, registry)).rejects.toThrow('Runtime registration failed') expect(revoke).toHaveBeenCalledWith(createUrl.mock.results[0].value) expect(await readCatalogBundles()).toEqual([]) expect(store.getAll()).toEqual([]) }) it('rejects unsupported schemas, duplicate IDs and off-host bundle paths', () => { expect(() => parseCatalog({ schemaVersion: 2, plugins: [] })).toThrow() expect(() => parseCatalog({ schemaVersion: 1, plugins: [entry, entry] })).toThrow(/Duplicate/) expect(() => parseCatalog({ schemaVersion: 1, plugins: [{ ...entry, bundlePath: 'https://other.test/' }] })).toThrow(/path/) })
it('refuses downloaded code whose hash differs from the tested release', async () => { vi.stubGlobal('crypto', webcrypto) vi.stubGlobal('fetch', vi.fn().mockResolvedValue(new Response('changed upstream code'))) try { await expect(downloadCatalogBundle(entry)).rejects.toThrow(/does not match/) } finally { vi.unstubAllGlobals() } })
it('persists large admitted bundles, restores offline, keeps CSS disabled, and uninstalls durably', async () => { const bundle = { manifest: entry.manifest, mainJs: 'x'.repeat(6_000_000), stylesCss: 'body { color: red }', sourceUrl: entry.repository, installedAt: 1 } const store = new ExternalPluginStore() const registry = new PluginRegistry() await store.installCatalog(bundle, registry) expect(registry.get(entry.manifest.id)?.catalogAdmitted).toBe(true) expect(localStorage.getItem('reams:external-plugins')).toBeNull() store.cleanup() const restored = new ExternalPluginStore() await restored.restoreCatalog(new PluginRegistry()) expect(restored.isExternal(entry.manifest.id)).toBe(true) expect(document.getElementById('reams-plugin-styles-catalog-test')).toBeNull() restored.setStylesEnabled(entry.manifest.id, true) expect(document.getElementById('reams-plugin-styles-catalog-test')).not.toBeNull() restored.setStylesEnabled(entry.manifest.id, false) expect(document.getElementById('reams-plugin-styles-catalog-test')).toBeNull() await restored.uninstallCatalog(entry.manifest.id) expect(await readCatalogBundles()).toEqual([]) })})