function createIssueSheet({ fetchJson, storage }) { let commentRequest = null; let closeRequest = null; let labelRequest = null; const issuePath = item => 'api/v1/repos/' + item.repository.split('/').map(encodeURIComponent).join('/') + '/issues/' + encodeURIComponent(item.number); const draftKey = item => 'stackchain.issue-comment.v1:' + item.repository + '#' + item.number; const labelDraftKey = item => 'stackchain.issue-labels.v1:' + item.repository + '#' + item.number; return { load(item) { return fetchJson(issuePath(item) + '/detail', { headers: { Accept: 'application/json' }, }); }, loadLabels(item) { return fetchJson(issuePath(item) + '/labels', { headers: { Accept: 'application/json' }, }); }, loadDraft(item) { try { return storage?.getItem(draftKey(item)) || ''; } catch (_error) { return ''; } }, saveDraft(item, body) { try { storage?.setItem(draftKey(item), body); } catch (_error) { /* The textarea remains the fallback. */ } }, loadLabelDraft(item) { try { const value = JSON.parse(storage?.getItem(labelDraftKey(item)) || '[]'); return Array.isArray(value) ? value.filter(Number.isInteger) : []; } catch (_error) { return []; } }, updateLabels(item, labelIds) { if (labelRequest) return labelRequest; try { storage?.setItem(labelDraftKey(item), JSON.stringify(labelIds)); } catch (_error) { /* The checked controls remain the fallback. */ } labelRequest = fetchJson(issuePath(item) + '/labels', { method: 'PATCH', headers: { Accept: 'application/json', 'Content-Type': 'application/json' }, body: JSON.stringify({ label_ids: labelIds }), }).then(result => { if (result?.number !== item.number || !Array.isArray(result.labels)) { throw new Error('Issue labels were not confirmed.'); } try { storage?.removeItem(labelDraftKey(item)); } catch (_error) { /* The upstream label set is authoritative. */ } return result; }).finally(() => { labelRequest = null; }); return labelRequest; }, close(item) { if (closeRequest) return closeRequest; closeRequest = fetchJson(issuePath(item) + '/close', { method: 'PATCH', headers: { Accept: 'application/json' }, }).then(result => { if (result?.state !== 'closed') throw new Error('Issue closure was not confirmed.'); return result; }).finally(() => { closeRequest = null; }); return closeRequest; }, comment(item, body) { if (commentRequest) return commentRequest; this.saveDraft(item, body); commentRequest = fetchJson(issuePath(item) + '/comments', { method: 'POST', headers: { Accept: 'application/json', 'Content-Type': 'application/json' }, body: JSON.stringify({ body }), }).then(result => { try { storage?.removeItem(draftKey(item)); } catch (_error) { /* The upstream comment is authoritative. */ } return result; }).finally(() => { commentRequest = null; }); return commentRequest; }, }; } if (typeof module !== 'undefined' && module.exports) module.exports = createIssueSheet;