Setting the file. One moment.
Live Browser Session · Impeccable · pbakaus/impeccable · Skills Docs
ContentsBack to the top of the page (opens in a new tab)
scripts/ live-browser-session.js
JavaScript · 144 lines · 4 KB
12
if
(
!
prefix)
throw
new
Error
(
'prefix required'
);
13 const store = storage || root.localStorage;
14 const makeId = idFactory || function () { return Math. random (). toString ( 16 ). slice ( 2 , 10 ); };
15 const sessionKey = prefix + '-session' ;
16 const handledKey = sessionKey + '-handled' ;
17 const scrollKey = sessionKey + '-scroll' ;
18 let checkpointRevision = 0 ;
19 const owner = makeId ();
20
21 function safeRead ( key ) {
22 try { return store. getItem (key); } catch { return null ; }
23 }
24
25 function safeWrite ( key , value ) {
26 try { store. setItem (key, value); } catch { /* quota exceeded or private mode */ }
27 }
28
29 function safeRemove ( key ) {
30 try { store. removeItem (key); } catch { /* unavailable storage */ }
31 }
32
33 function loadSession () {
34 try {
35 const raw = safeRead (sessionKey);
36 if ( ! raw) return null ;
37 const parsed = JSON . parse (raw);
38 if (Number. isInteger (parsed.checkpointRevision)) {
39 checkpointRevision = Math. max (checkpointRevision, parsed.checkpointRevision);
40 }
41 return parsed;
42 } catch { return null ; }
43 }
44
45 function saveSession ( session ) {
46 if ( ! session || ! session.id) return ;
47 const payload = {
48 ... session,
49 checkpointRevision,
50 };
51 safeWrite (sessionKey, JSON . stringify (payload));
52 }
53
54 function clearSession () {
55 safeRemove (sessionKey);
56 }
57
58 function nextCheckpointRevision () {
59 checkpointRevision += 1 ;
60 const existing = loadSession ();
61 if (existing?.id) saveSession (existing);
62 return checkpointRevision;
63 }
64
65 function seedCheckpointRevision ( value ) {
66 if (Number. isInteger (value)) checkpointRevision = Math. max (checkpointRevision, value);
67 return checkpointRevision;
68 }
69
70 function currentCheckpointRevision () {
71 return checkpointRevision;
72 }
73
74 function readHandledIds () {
75 const raw = safeRead (handledKey);
76 if ( ! raw) return [];
77 try {
78 const parsed = JSON . parse (raw);
79 if (Array. isArray (parsed)) {
80 return parsed. filter ( id => typeof id === 'string' && id);
81 }
82 if ( typeof parsed === 'string' && parsed) return [parsed];
83 } catch { /* legacy values were stored as a plain session id */ }
84 return [raw];
85 }
86
87 function markHandled ( id ) {
88 if ( ! id) return ;
89 const ids = readHandledIds (). filter ( existing => existing !== id);
90 ids. push (id);
91 safeWrite (handledKey, JSON . stringify (ids. slice ( - 8 )));
92 }
93
94 function isHandled ( id ) {
95 return !! id && readHandledIds (). includes (id);
96 }
97
98 function clearHandled ( id ) {
99 if ( ! id) {
100 safeRemove (handledKey);
101 return ;
102 }
103 const remaining = readHandledIds (). filter ( existing => existing !== id);
104 if (remaining. length > 0 ) safeWrite (handledKey, JSON . stringify (remaining));
105 else safeRemove (handledKey);
106 }
107
108 function writeScrollY ( y ) {
109 safeWrite (scrollKey, String (y));
110 }
111
112 function readScrollY () {
113 const raw = safeRead (scrollKey);
114 if (raw == null ) return null ;
115 const n = parseFloat (raw);
116 return isFinite (n) ? n : null ;
117 }
118
119 function clearScrollY () {
120 safeRemove (scrollKey);
121 }
122
123 return {
124 owner,
125 sessionKey,
126 handledKey,
127 scrollKey,
128 saveSession,
129 loadSession,
130 clearSession,
131 nextCheckpointRevision,
132 seedCheckpointRevision,
133 currentCheckpointRevision,
134 markHandled,
135 isHandled,
136 clearHandled,
137 writeScrollY,
138 readScrollY,
139 clearScrollY,
140 };
141 }
142
143 root.__IMPECCABLE_LIVE_SESSION__ = { createLiveBrowserSessionState };
144 })( typeof window !== 'undefined' ? window : globalThis);