@@ -17,6 +17,22 @@ import { CurrentTestRunInfo } from './simulationContext';
1717const compress = promisify ( zlib . brotliCompress ) ;
1818const decompress = promisify ( zlib . brotliDecompress ) ;
1919
20+ /**
21+ * Yield to the libuv event loop.
22+ *
23+ * The previous `@keyv/sqlite` store was backed by the asynchronous `sqlite3`
24+ * driver, so every individual store operation resolved on a later loop tick.
25+ * Some consumers rely on that boundary: e.g. the panel multi-file edit flow
26+ * applies one code block's edits while the next code block's code-mapper request
27+ * is awaiting its cached response, so the next request is built against the
28+ * already-edited document. `node:sqlite`'s `DatabaseSync` is synchronous, so we
29+ * reintroduce the async boundary on every store operation to preserve that
30+ * interleaving (and thus compatibility with the recorded cache).
31+ */
32+ function yieldEventLoop ( ) : Promise < void > {
33+ return new Promise < void > ( resolve => setImmediate ( resolve ) ) ;
34+ }
35+
2036const DefaultCachePath = process . env . VITEST ? path . resolve ( __dirname , '..' , 'simulation' , 'cache' ) : path . resolve ( __dirname , '..' , 'test' , 'simulation' , 'cache' ) ;
2137
2238async function getGitRoot ( cwd : string ) : Promise < string > {
@@ -48,19 +64,32 @@ class SqliteKeyValueStore {
4864 return `${ SqliteKeyValueStore . NAMESPACE } :${ key } ` ;
4965 }
5066
67+ private static _decodeJsonBufferValue ( value : string ) : string {
68+ if ( value . startsWith ( ':base64:' ) ) {
69+ return value . slice ( ':base64:' . length ) ;
70+ }
71+ if ( value . startsWith ( ':' ) ) {
72+ return value . slice ( 1 ) ;
73+ }
74+ return value ;
75+ }
76+
5177 async get ( key : string ) : Promise < string | undefined > {
78+ await yieldEventLoop ( ) ;
5279 const row = this . db . prepare ( 'SELECT value FROM keyv WHERE key = ?' ) . get ( this . _namespacedKey ( key ) ) as { value : string } | undefined ;
5380 if ( ! row ) {
5481 return undefined ;
5582 }
56- return JSON . parse ( row . value ) . value as string ;
83+ return SqliteKeyValueStore . _decodeJsonBufferValue ( JSON . parse ( row . value ) . value as string ) ;
5784 }
5885
5986 async set ( key : string , value : string ) : Promise < void > {
87+ await yieldEventLoop ( ) ;
6088 this . db . prepare ( 'INSERT OR REPLACE INTO keyv (key, value) VALUES (?, ?)' ) . run ( this . _namespacedKey ( key ) , JSON . stringify ( { value } ) ) ;
6189 }
6290
6391 async has ( key : string ) : Promise < boolean > {
92+ await yieldEventLoop ( ) ;
6493 const row = this . db . prepare ( 'SELECT 1 FROM keyv WHERE key = ?' ) . get ( this . _namespacedKey ( key ) ) ;
6594 return row !== undefined ;
6695 }
0 commit comments