(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 = () => '', scope = 'conversation', } = {}) { const transact = transaction || createTransaction(indexedDB); const draftScope = String(scope || 'conversation').trim().slice(0, 64) || 'conversation'; 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; const identityParts = draftScope === 'conversation' ? [ownerLogin, normalized.kind, targetKey] : [ownerLogin, draftScope, normalized.kind, targetKey]; return { ownerLogin, scope:draftScope, target:normalized, id:identityParts.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, scope:recordScope, 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, scope:recordScope, ...normalized, attachments:list }); return list; } async function load(target) { if (!transact) return null; const { id, ownerLogin, scope:recordScope, target:normalized } = identity(target); const record = await transact('get', id); const scopeMatches = recordScope === 'conversation' ? (!record?.scope || record.scope === recordScope) : record?.scope === recordScope; const same = record?.version === 1 && record.ownerLogin === ownerLogin && scopeMatches && 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 }; }; });