import { env } from 'cloudflare:workers'; import { seed } from './seed'; import type { State,StateStore,Bot,Recipe,Home } from './types'; function migrate(raw:any):State{ const defaults=seed(); const recipes:Recipe[]=(raw.recipes??defaults.recipes).map((r:Recipe)=>r); for(const recipe of defaults.recipes){ if(!recipes.some(r=>r.id===recipe.id))recipes.push(structuredClone(recipe)); } const homes:Home[]=(raw.homes??defaults.homes).map((h:Home)=>h); for(const home of defaults.homes){ if(!homes.some(h=>h.id===home.id))homes.push(structuredClone(home)); } const bots:Bot[]=(raw.bots??[]).map((b:any)=>{ const seeded=defaults.bots.find(x=>x.id===b.id); const home=homes.find(h=>h.residentIds.includes(b.id)); return { ...b, tier:b.tier??seeded?.tier??'resident', mortal:b.mortal??true, plotArmorHpFloor:b.plotArmorHpFloor??seeded?.plotArmorHpFloor??0, simulationBand:b.simulationBand??seeded?.simulationBand??(b.status==='online'?'background':'dormant'), homeId:b.homeId??seeded?.homeId??home?.id, routine:b.routine??seeded?.routine??{wakeHour:7,sleepHour:23,preferredZones:[b.zone].filter(Boolean)}, autonomy:{managed:b.autonomy?.managed??false,...(b.autonomy??{})} }; }); for(const hero of defaults.bots.filter(b=>b.tier==='hero')){ if(!bots.some(b=>b.id===hero.id||b.name.toLowerCase()===hero.name.toLowerCase()))bots.push(structuredClone(hero)); } for(const home of homes){ home.residentIds=home.residentIds.filter(id=>bots.some(b=>b.id===id)); } for(const bot of bots){ if(bot.homeId){ const home=homes.find(h=>h.id===bot.homeId); if(home&&!home.residentIds.includes(bot.id)&&home.residentIds.length{ if(!env.DB) throw new Error('Realm database unavailable'); const initial=seed(); await env.DB.prepare('INSERT OR IGNORE INTO realm_state (id,revision,payload) VALUES (?,?,?)').bind('realm',0,JSON.stringify(initial)).run(); const row=await env.DB.prepare('SELECT payload FROM realm_state WHERE id=?').bind('realm').first<{payload:string}>(); if(!row)throw new Error('Realm state unavailable'); return migrate(JSON.parse(row.payload)); } async save(s:State,expected:number){ s.revision=expected+1; const result=await env.DB!.prepare('UPDATE realm_state SET revision=?,payload=? WHERE id=? AND revision=?').bind(s.revision,JSON.stringify(s),'realm',expected).run(); if(result.meta.changes!==1)throw new Error('State changed in another request. Refresh and try again.'); } }