| 1 | // In Shoal the viewer runs in a frame with scripts only (no same origin), where touching localStorage or |
| 2 | // sessionStorage throws. The upstream UI reads both (onboarding, the identity reveal, sound settings), some of it |
| 3 | // without a try, so the page gets in-memory stand-ins before any of it loads. |
| 4 | for (const name of ['localStorage', 'sessionStorage'] as const) { |
| 5 | try { |
| 6 | void window[name].length; |
| 7 | } catch { |
| 8 | const data = new Map<string, string>(); |
| 9 | const memory: Storage = { |
| 10 | get length() { |
| 11 | return data.size; |
| 12 | }, |
| 13 | clear: () => data.clear(), |
| 14 | getItem: (k) => data.get(k) ?? null, |
| 15 | key: (i) => [...data.keys()][i] ?? null, |
| 16 | removeItem: (k) => void data.delete(k), |
| 17 | setItem: (k, v) => void data.set(k, String(v)), |
| 18 | }; |
| 19 | try { |
| 20 | Object.defineProperty(window, name, { value: memory, configurable: true }); |
| 21 | } catch { |
| 22 | // nothing more to do: the upstream code that guards its storage keeps working |
| 23 | } |
| 24 | } |
| 25 | } |
