mirror of
https://github.com/stablyai/orca.git
synced 2026-09-29 16:02:50 +00:00
* perf(renderer): stop full durable-state save on every top-level view switch (#9002) Persist activeView in a tiny profile-scoped sidecar instead of mutating the monolithic recovery snapshot. Active-view-only updates now bypass the broad UI normalization and durable save scheduler, while a 100ms atomic writer coalesces rapid switches and a synchronous shutdown checkpoint closes the immediate-exit race. Legacy state remains a migration and downgrade fallback. Coordinate renderer shutdown capture through one guarded checkpoint so workspace sessions and the active-view preference both survive graceful reloads, restarts, and quit cancellation. Add a persistence-boundary test proving the sidecar stays below 64 bytes while orca-data.json remains byte-for-byte unchanged, plus repeated Windows Electron restart coverage and a path-normalization-safe restart fixture. * harden active-view sidecar: prototype-safe validator, race-free async swap, independent shutdown flush - isTopLevelView uses Object.hasOwn so a corrupt sidecar can't smuggle inherited keys (constructor/__proto__) through as a valid view. - writeAsync guards the generation check and rename synchronously (renameSync) so a shutdown flushOrThrow can no longer interleave and let a stale async rename clobber the freshly-written view. - shutdown checkpoint flushes the durable store and the active-view sidecar in independent try/catch blocks so one store's failure can't skip the other. Added regression tests for all three. Co-authored-by: Orca <help@stably.ai> --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com> Co-authored-by: Orca <help@stably.ai>
59 lines
2.1 KiB
TypeScript
59 lines
2.1 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
import { mkdtempSync, readFileSync, rmSync } from 'node:fs'
|
|
import { tmpdir } from 'node:os'
|
|
import { join } from 'node:path'
|
|
import { getActiveViewPreferenceFile } from './active-view-preference'
|
|
|
|
const testState = { dir: '' }
|
|
|
|
vi.mock('electron', () => ({
|
|
app: { getPath: () => testState.dir },
|
|
safeStorage: {
|
|
isEncryptionAvailable: () => true,
|
|
encryptString: (plaintext: string) => Buffer.from(`encrypted:${plaintext}`, 'utf-8'),
|
|
decryptString: (ciphertext: Buffer) => ciphertext.toString('utf-8').replace('encrypted:', '')
|
|
}
|
|
}))
|
|
|
|
vi.mock('./telemetry/client', () => ({ track: vi.fn() }))
|
|
vi.mock('./telemetry/cohort-classifier', () => ({ getCohortAtEmit: vi.fn() }))
|
|
vi.mock('./ssh/ssh-config-parser', () => ({
|
|
loadUserSshConfig: vi.fn(),
|
|
sshConfigHostsToTargets: vi.fn()
|
|
}))
|
|
|
|
describe('active-view persistence boundary', () => {
|
|
beforeEach(() => {
|
|
testState.dir = mkdtempSync(join(tmpdir(), 'orca-active-view-boundary-'))
|
|
})
|
|
|
|
afterEach(() => {
|
|
vi.useRealTimers()
|
|
rmSync(testState.dir, { recursive: true, force: true })
|
|
})
|
|
|
|
it('persists a view switch without changing the global durable snapshot', async () => {
|
|
vi.useFakeTimers()
|
|
vi.resetModules()
|
|
const { Store } = await import('./persistence')
|
|
const dataFile = join(testState.dir, 'orca-data.json')
|
|
const store = new Store({ dataFile })
|
|
store.flush()
|
|
const durableBefore = readFileSync(dataFile, 'utf-8')
|
|
|
|
store.updateUI({ activeView: 'settings' })
|
|
vi.advanceTimersByTime(1_000)
|
|
await store.waitForPendingWrite()
|
|
|
|
const preferenceFile = getActiveViewPreferenceFile(dataFile)
|
|
const preferencePayload = readFileSync(preferenceFile, 'utf-8')
|
|
expect(Buffer.byteLength(preferencePayload)).toBeLessThan(64)
|
|
expect(JSON.parse(preferencePayload)).toEqual({ activeView: 'settings' })
|
|
expect(readFileSync(dataFile, 'utf-8')).toBe(durableBefore)
|
|
expect(store.getUI().activeView).toBe('settings')
|
|
|
|
const reloaded = new Store({ dataFile })
|
|
expect(reloaded.getUI().activeView).toBe('settings')
|
|
})
|
|
})
|