tricu

An interpreted language for exploring Tree Calculus
Log | Files | Refs | README | LICENSE

draft-storage.ts (2222B)


      1 // One local recovery slot, never executable state or an automatic run request.
      2 // Browser limits are intentionally NOT persisted: recovery starts in Standard.
      3 export const DRAFT_KEY = 'arboricx.local-draft.v1';
      4 export interface SavedDraft {
      5   schema: 1;
      6   source: string;
      7   name: string;
      8   arguments: string;
      9   output: string;
     10   mode: 'pure' | 'io';
     11   demo?: { hash: string; environment: string };
     12 }
     13 export function savedDraft(raw: unknown): SavedDraft {
     14   if (!raw || typeof raw !== 'object' || Array.isArray(raw)) throw new Error('Invalid saved draft');
     15   const v = raw as Record<string, unknown>;
     16   for (const [key, max] of [['source', 32768], ['name', 256], ['arguments', 16000], ['output', 32]] as const)
     17     if (typeof v[key] !== 'string' || v[key].length > max) throw new Error('Invalid saved draft ' + key);
     18   if (v['schema'] !== 1 || (v['mode'] !== 'pure' && v['mode'] !== 'io')) throw new Error('Invalid saved draft version/mode');
     19   let demo: SavedDraft['demo'];
     20   if (v['demo'] !== undefined) {
     21     const d = v['demo'] as Record<string, unknown>;
     22     if (!d || typeof d !== 'object' || typeof d['hash'] !== 'string' || !/^[0-9a-f]{64}$/u.test(d['hash']) || typeof d['environment'] !== 'string' || !/^[A-Za-z0-9_-]{1,128}$/u.test(d['environment'])) throw new Error('Invalid saved demo context');
     23     demo = { hash: d['hash'], environment: d['environment'] };
     24   }
     25   return { schema: 1, source: v['source'] as string, name: v['name'] as string, arguments: v['arguments'] as string,
     26     output: v['output'] as string, mode: v['mode'], ...(demo ? { demo } : {}) };
     27 }
     28 export function readDraft(storage: Pick<Storage, 'getItem'>): SavedDraft | undefined {
     29   const text = storage.getItem(DRAFT_KEY);
     30   if (text === null) return undefined;
     31   if (text.length > 100000) throw new Error('Saved draft too large');
     32   return savedDraft(JSON.parse(text) as unknown);
     33 }
     34 export function writeDraft(storage: Pick<Storage, 'setItem' | 'getItem'>, draft: SavedDraft): void {
     35   const text = JSON.stringify(savedDraft(draft));
     36   if (text.length > 100000) throw new Error('Saved draft too large');
     37   storage.setItem(DRAFT_KEY, text);
     38   if (storage.getItem(DRAFT_KEY) !== text) throw new Error('Draft storage verification failed');
     39 }