Source identity
| Field | Recorded value |
|---|---|
| Source type | GitHub source |
| Original record | Janady13/feedthejoe / src/adapters/storage.js |
| Date | Not specified in source |
| Repository | Janady13/feedthejoe |
| Revision | 0e608a2b515a959bf35d2783428766624400ca3c |
| Branch | main |
| Path or archive member | src/adapters/storage.js |
| Original SHA-256 | 0c12e95f6f7414de0786e5d0ee78a3fe4aec1228ed01f6fff833e4f29d7a261d |
| Git blob SHA | 37a3137261ad54770d90bdf4cba5d6c68ecb5b99 |
| Reading-copy SHA-256 | 0c12e95f6f7414de0786e5d0ee78a3fe4aec1228ed01f6fff833e4f29d7a261d |
Recovered source transcript
Download complete source text ↓56 lines · 1.8 KB
/**
* Persistence adapter.
*
* sessionStorage, not localStorage, and not a cookie. The distinction is a
* privacy decision, not a technical one:
*
* - sessionStorage is scoped to the tab and dies when it closes. The model's
* opinion of a visitor does not outlive their visit.
* - It is never sent anywhere. There is no endpoint. There is no beacon.
* - Because nothing is transmitted or persisted across sessions, this is not
* tracking, and the site needs no consent banner to be lawful.
*
* Every access is wrapped: private windows, disabled site data and some
* embedded contexts throw on the *accessor itself*, not merely return null.
* A storage failure must degrade to "no memory", never to a broken page.
*/
const KEY = 'ftj.state.v1';
/** @param {number} dim @returns {import('../ports/types.js').StatePort} */
export function createStatePort(dim) {
return {
load() {
try {
const raw = sessionStorage.getItem(KEY);
if (!raw) return null;
const parsed = JSON.parse(raw);
if (!Array.isArray(parsed.interest) || parsed.interest.length !== dim) return null;
return {
interest: Float32Array.from(parsed.interest),
topics: parsed.topics ?? {},
impressions: parsed.impressions ?? {},
};
} catch {
return null;
}
},
save(state) {
try {
sessionStorage.setItem(KEY, JSON.stringify({
interest: Array.from(state.interest, (n) => Math.round(n * 1e4) / 1e4),
topics: state.topics,
impressions: state.impressions,
}));
} catch {
/* Full, blocked, or unavailable. The session simply has no memory. */
}
},
clear() {
try { sessionStorage.removeItem(KEY); } catch { /* nothing to do */ }
},
};
}