function createIssueSheet({ fetchJson, storage }) { let commentRequest = null; let closeRequest = 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; return { load(item) { return fetchJson(issuePath(item) + '/detail', { 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. */ } }, 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;