(function (root, factory) { const api = factory(); if (typeof module !== 'undefined' && module.exports) module.exports = api; else root.createOfflineWorkStore = api; })(typeof self !== 'undefined' ? self : this, function () { 'use strict'; const ENABLED_KEY = 'stackchain.offline-work.enabled.v1'; const SNAPSHOT_KEY = 'stackchain.offline-work.snapshot.v1'; const DETAILS_KEY = 'stackchain.offline-work.details.v1'; const VERSION = 1; const DEFAULT_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000; const ITEM_FIELDS = [ 'id', 'number', 'title', 'state', 'repository', 'labels', 'assignees', 'updated_at', 'due_date', 'milestone', 'url', 'work_reasons', ]; const NOTIFICATION_FIELDS = [ 'id', 'number', 'title', 'unread', 'repository', 'subject_type', 'updated_at', 'url', ]; const DETAIL_FIELDS = [ 'title', 'body', 'state', 'labels', 'assignees', 'author', 'url', 'due_date', 'milestone', ]; const COMMENT_FIELDS = ['id', 'author', 'body', 'created_at', 'updated_at', 'url']; function pick(source, fields) { const output = {}; fields.forEach(field => { if (source && source[field] !== undefined) output[field] = source[field]; }); return output; } function createOfflineWorkStore({ storage, now = () => new Date(), maxAgeMs = DEFAULT_MAX_AGE_MS, maxDetails = 10, }) { function enabled() { try { return storage.getItem(ENABLED_KEY) === 'true'; } catch (_) { return false; } } function clear() { try { storage.removeItem(SNAPSHOT_KEY); storage.removeItem(DETAILS_KEY); } catch (_) { return false; } return true; } function detailKey(item) { const kind = item?.kind === 'pull' ? 'pull' : item?.kind === 'issue' ? 'issue' : ''; const repository = String(item?.repository || ''); const number = Number(item?.number || 0); return kind && repository && number > 0 ? [kind, repository, number].join(':') : ''; } function readDetails() { try { const value = JSON.parse(storage.getItem(DETAILS_KEY) || '[]'); return Array.isArray(value) ? value : []; } catch (_) { try { storage.removeItem(DETAILS_KEY); } catch (_error) { /* Best effort purge. */ } return []; } } function saveDetail(login, item, detail) { const key = detailKey(item); login = String(login || '').trim(); if (!enabled() || !login || !key || !detail) return false; const conversation = detail.conversation || {}; const record = { key, user_login: login, saved_at: now().toISOString(), data: { ...pick(detail, DETAIL_FIELDS), conversation: { comments: (conversation.comments || []).slice(-20).map(comment => pick(comment, COMMENT_FIELDS)), page: Number(conversation.page || 1), older_page: conversation.older_page ?? null, total: Number(conversation.total || 0), }, }, }; const records = readDetails().filter(candidate => !(candidate?.key === key && candidate?.user_login === login) ); records.push(record); try { storage.setItem(DETAILS_KEY, JSON.stringify(records.slice(-Math.max(1, maxDetails)))); } catch (_) { return false; } return true; } function loadDetail(login, item) { const key = detailKey(item); login = String(login || '').trim(); if (!login || !key) return null; const records = readDetails(); const currentTime = now().getTime(); const valid = records.filter(record => { const savedAt = Date.parse(record?.saved_at || ''); return record?.key && record?.user_login && record?.data && Number.isFinite(savedAt) && currentTime - savedAt <= maxAgeMs; }); if (valid.length !== records.length) { try { storage.setItem(DETAILS_KEY, JSON.stringify(valid)); } catch (_) { /* Best effort purge. */ } } const record = valid.find(candidate => candidate.key === key && candidate.user_login === login); return record ? { ...record.data, saved_at: record.saved_at } : null; } function setEnabled(value) { try { storage.setItem(ENABLED_KEY, value ? 'true' : 'false'); if (!value) clear(); return true; } catch (_) { return false; } } function save(snapshot) { if (!enabled() || !snapshot?.user?.login) return false; const record = { version: VERSION, user_login: String(snapshot.user.login), saved_at: now().toISOString(), data: { user: pick(snapshot.user, ['login', 'full_name']), issues: (snapshot.issues || []).map(item => pick(item, ITEM_FIELDS)), pull_requests: (snapshot.pull_requests || []).map(item => pick(item, ITEM_FIELDS)), notifications: (snapshot.notifications || []).map(item => pick(item, NOTIFICATION_FIELDS)), work_pagination: snapshot.work_pagination || {}, notification_pagination: snapshot.notification_pagination || {}, }, }; try { storage.setItem(SNAPSHOT_KEY, JSON.stringify(record)); } catch (_) { return false; } return true; } function load(expectedLogin) { let record; try { record = JSON.parse(storage.getItem(SNAPSHOT_KEY) || 'null'); } catch (_) { clear(); return null; } const savedAt = Date.parse(record?.saved_at || ''); const invalid = record?.version !== VERSION || !record?.user_login || !record?.data || !Number.isFinite(savedAt); const expired = Number.isFinite(savedAt) && now().getTime() - savedAt > maxAgeMs; if (invalid || expired) { clear(); return null; } if (expectedLogin && record.user_login !== expectedLogin) return null; return { ...record.data, saved_at: record.saved_at }; } return { enabled, setEnabled, save, load, saveDetail, loadDetail, clear }; } return createOfflineWorkStore; });