(function (root, factory) { const createConversationReplyDraftStore = factory(); if (typeof module === 'object' && module.exports) module.exports = createConversationReplyDraftStore; else root.createConversationReplyDraftStore = createConversationReplyDraftStore; })(typeof globalThis !== 'undefined' ? globalThis : this, function () { 'use strict'; const dbName = 'stackchain-conversation-reply-drafts-v1'; const storeName = 'drafts'; function requestResult(request) { return new Promise((resolve, reject) => { request.onsuccess = () => resolve(request.result ?? null); request.onerror = () => reject(request.error || new Error('Conversation photo draft storage failed.')); }); } function createTransaction(indexedDB) { if (!indexedDB) return null; let databasePromise; function database() { if (!databasePromise) databasePromise = new Promise((resolve, reject) => { const request = indexedDB.open(dbName, 1); request.onupgradeneeded = () => { if (!request.result.objectStoreNames.contains(storeName)) { request.result.createObjectStore(storeName, { keyPath:'id' }); } }; request.onsuccess = () => resolve(request.result); request.onerror = () => reject(request.error || new Error('Conversation photo draft storage is unavailable.')); }); return databasePromise; } return async (operation, key, value) => { const db = await database(); const transaction = db.transaction(storeName, operation === 'get' ? 'readonly' : 'readwrite'); const records = transaction.objectStore(storeName); if (operation === 'put') return requestResult(records.put(value)); if (operation === 'delete') return requestResult(records.delete(key)); return requestResult(records.get(key)); }; } function normalizedTarget(target) { const kind = String(target?.kind || ''); if (kind === 'update') { const notificationId = Number(target?.notificationId || target?.notification_id || 0); if (!Number.isInteger(notificationId) || notificationId < 1) { throw new Error('Open an unread update before saving photo evidence.'); } return { kind, notificationId }; } const repository = String(target?.repository || ''); const number = Number(target?.number || 0); if (!['issue', 'pull'].includes(kind) || !repository || !Number.isInteger(number) || number < 1) { throw new Error('Open a conversation before saving photo evidence.'); } return { kind, repository, number }; } function attachment(value) { const blob = value?.blob; const data = String(value?.data || ''); if (!blob && !data) throw new Error('A saved conversation photo is unavailable.'); const note = String(value?.note || '').replace(/\s+/g, ' ').trim().slice(0, 240); const operationId = String(value?.operationId || '').slice(0, 128); const markdown = String(value?.confirmed?.markdown || ''); return { filename:String(value?.filename || ''), contentType:String(value?.contentType || ''), ...(blob ? { blob } : { data }), ...(note ? { note } : {}), ...(operationId ? { operationId } : {}), ...(markdown ? { confirmed:{ markdown } } : {}), }; } return function createConversationReplyDraftStore({ indexedDB = globalThis.indexedDB, transaction, getOwnerLogin = () => '', } = {}) { const transact = transaction || createTransaction(indexedDB); function identity(target) { const ownerLogin = String(getOwnerLogin() || '').trim(); if (!ownerLogin) throw new Error('Confirm your Gitea account before saving conversation photos.'); const normalized = normalizedTarget(target); const targetKey = normalized.kind === 'update' ? normalized.notificationId : normalized.repository + ':' + normalized.number; return { ownerLogin, target:normalized, id:[ownerLogin, normalized.kind, targetKey].map(value => encodeURIComponent(String(value))).join(':'), }; } async function save(target, values) { if (!transact) throw new Error('Photo draft storage needs IndexedDB. Your current photos are still here.'); const { id, ownerLogin, target:normalized } = identity(target); const list = (Array.isArray(values) ? values : [values]).filter(Boolean).slice(0, 5).map(attachment); if (!list.length) { await transact('delete', id); return null; } await transact('put', id, { id, version:1, ownerLogin, ...normalized, attachments:list }); return list; } async function load(target) { if (!transact) return null; const { id, ownerLogin, target:normalized } = identity(target); const record = await transact('get', id); const same = record?.version === 1 && record.ownerLogin === ownerLogin && record.kind === normalized.kind && (normalized.kind === 'update' ? Number(record.notificationId) === normalized.notificationId : record.repository === normalized.repository && Number(record.number) === normalized.number); if (!same || !Array.isArray(record.attachments) || !record.attachments.length) return null; return record.attachments.slice(0, 5).map(attachment); } async function remove(target) { if (!transact) return false; const { id } = identity(target); await transact('delete', id); return true; } return { save, load, remove }; }; });