← back to Tk 10965 Zero Price Analysis
vienna-offline-adapter.mjs
35 lines
// Deterministic file-backed test adapter. All supported CLI writers hold the
// same state-file lock across the entire journey, including compare and write.
// Reads never write logs or cached record state back to disk.
import {readRegular,durableWrite,key} from './vienna-executor.mjs';
export function openOfflineAdapter(file,expectedStore) {
const pinned=JSON.stringify(expectedStore);
const load=()=>{
const state=JSON.parse(readRegular(file));
if(state.fixture!==true || state.version!==1 || !Array.isArray(state.records) || !Array.isArray(state.calls)) throw new Error('Offline fixture required');
if(JSON.stringify(state.store)!==pinned) throw new Error('Adapter store mismatch');
return state;
};
load();
return {
async shop(){return load().store;},
async read(r){return load().records.find(x=>key(x)===key(r));},
async set(r,before,after) {
const state=load();
const actual=state.records.find(x=>key(x)===key(r));
// Recompare full current identity/preconditions, not a previously read object.
if(JSON.stringify(actual)!==JSON.stringify({...r,onHand:before})) return {kind:'rejected',confirmedNoWrite:true};
state.calls.push({method:'set',key:key(r)});
const persist=()=>durableWrite(file,JSON.stringify(state,null,2)+'\n');
persist();
const fault=state.faults?.[key(r)];
if(fault==='reject') return {kind:'rejected',confirmedNoWrite:true};
if(fault==='throw-before') throw new Error('Simulated transport failure before response');
actual.onHand=after; persist();
if(fault==='throw-after') throw new Error('Simulated transport failure after persisted write');
if(fault==='bad-postread') { actual.variantId='gid://shopify/ProductVariant/999';persist(); }
return {kind:'success',key:key(r),quantity:after};
}
};
}