import { uid, timestamp } from './store.jsx';
const supported = ['pdf', 'docx', 'txt', 'md', 'sql'];
function deadline(promise, message, milliseconds = 10000) {
return new Promise((resolve, reject) => {
const timer = setTimeout(() => reject(new Error(message)), milliseconds);
promise.then(value => { clearTimeout(timer); resolve(value); }, error => { clearTimeout(timer); reject(error); });
});
}
function readFile(file) {
if (typeof FileReader === 'undefined') return file.arrayBuffer();
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.onerror = () => reject(new Error('Could not read this file. Select it again.'));
reader.onabort = () => reject(new Error('File reading was interrupted. Select it again.'));
reader.readAsArrayBuffer(file);
});
}
function openVault() {
return new Promise((resolve, reject) => {
let settled = false;
const fail = message => { if (!settled) { settled = true; clearTimeout(timer); reject(new Error(message)); } };
const timer = setTimeout(() => fail('File storage did not respond. Please try again.'), 10000);
const request = indexedDB.open('ccil-local-files', 1);
request.onupgradeneeded = () => { if (!request.result.objectStoreNames.contains('files')) request.result.createObjectStore('files'); };
request.onsuccess = () => { if (settled) request.result.close(); else { settled = true; clearTimeout(timer); resolve(request.result); } };
request.onerror = () => fail('File storage is unavailable. Please select the file again.');
request.onblocked = () => fail('File storage is busy. Close other studio tabs and try again.');
});
}
async function vault(mode, action) {
const db = await openVault();
try { await deadline(new Promise((resolve, reject) => { const transaction = db.transaction('files', mode); action(transaction.objectStore('files')); transaction.oncomplete = resolve; transaction.onerror = () => reject(new Error('Could not save this file. Please try again.')); transaction.onabort = () => reject(new Error('File saving was interrupted. Please try again.')); }), 'File saving did not finish. Please try again.'); } finally { db.close(); }
}
export async function stageFile(file, scope) {
const extension = file.name.split('.').pop().toLowerCase();
if (!supported.includes(extension)) throw new Error(`${file.name}: use PDF, DOCX, TXT, Markdown, or SQL.`);
if (file.size > 50 * 1024 * 1024) throw new Error(`${file.name}: maximum file size is 50 MB.`);
if (!file.size) throw new Error(`${file.name}: the file is empty.`);
const id = uid('source');
const buffer = await deadline(readFile(file), 'File reading did not finish. Please select it again.');
const digest = await crypto.subtle.digest('SHA-256', buffer);
const checksum = Array.from(new Uint8Array(digest)).map(b => b.toString(16).padStart(2, '0')).join('');
const text = ['txt', 'md', 'sql'].includes(extension) ? new TextDecoder().decode(buffer).slice(0, 150000) : '';
if (['txt', 'md', 'sql'].includes(extension) && !text.trim()) throw new Error(`${file.name}: no usable text was found.`);
await vault('readwrite', store => store.put(file, id));
return { id, name: file.name, kind: extension.toUpperCase(), size: `${(file.size / 1024).toFixed(1)} KB`, bytes: file.size, checksum, excerpt: text, revision: 1, status: 'Staged', synthetic: false, date: timestamp(), ...scope };
}
export async function openOriginal(document) {
const db = await openVault();
try {
const file = await new Promise((resolve, reject) => { const request = db.transaction('files', 'readonly').objectStore('files').get(document.id); request.onsuccess = () => resolve(request.result); request.onerror = reject; });
if (!file) throw new Error('The source file is unavailable in this browser. Reattach the original file.');
const url = URL.createObjectURL(file); const a = window.document.createElement('a'); a.href = url; a.download = document.name; a.click(); setTimeout(() => URL.revokeObjectURL(url), 1000);
} finally { db.close(); }
}
For further actions, you may consider blocking this person and/or reporting abuse
Top comments (0)