diff --git a/dist/file-picker.esm.js b/dist/file-picker.esm.js deleted file mode 100644 index d9f7ac1..0000000 --- a/dist/file-picker.esm.js +++ /dev/null @@ -1,1194 +0,0 @@ -// node_modules/fflate/esm/browser.js -var u8 = Uint8Array; -var u16 = Uint16Array; -var i32 = Int32Array; -var fleb = new u8([ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 1, - 1, - 1, - 2, - 2, - 2, - 2, - 3, - 3, - 3, - 3, - 4, - 4, - 4, - 4, - 5, - 5, - 5, - 5, - 0, - /* unused */ - 0, - 0, - /* impossible */ - 0 -]); -var fdeb = new u8([ - 0, - 0, - 0, - 0, - 1, - 1, - 2, - 2, - 3, - 3, - 4, - 4, - 5, - 5, - 6, - 6, - 7, - 7, - 8, - 8, - 9, - 9, - 10, - 10, - 11, - 11, - 12, - 12, - 13, - 13, - /* unused */ - 0, - 0 -]); -var clim = new u8([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]); -var freb = function(eb, start) { - var b = new u16(31); - for (var i = 0; i < 31; ++i) { - b[i] = start += 1 << eb[i - 1]; - } - var r = new i32(b[30]); - for (var i = 1; i < 30; ++i) { - for (var j = b[i]; j < b[i + 1]; ++j) { - r[j] = j - b[i] << 5 | i; - } - } - return { b, r }; -}; -var _a = freb(fleb, 2); -var fl = _a.b; -var revfl = _a.r; -fl[28] = 258, revfl[258] = 28; -var _b = freb(fdeb, 0); -var fd = _b.b; -var revfd = _b.r; -var rev = new u16(32768); -for (i = 0; i < 32768; ++i) { - x = (i & 43690) >> 1 | (i & 21845) << 1; - x = (x & 52428) >> 2 | (x & 13107) << 2; - x = (x & 61680) >> 4 | (x & 3855) << 4; - rev[i] = ((x & 65280) >> 8 | (x & 255) << 8) >> 1; -} -var x; -var i; -var hMap = (function(cd, mb, r) { - var s = cd.length; - var i = 0; - var l = new u16(mb); - for (; i < s; ++i) { - if (cd[i]) - ++l[cd[i] - 1]; - } - var le = new u16(mb); - for (i = 1; i < mb; ++i) { - le[i] = le[i - 1] + l[i - 1] << 1; - } - var co; - if (r) { - co = new u16(1 << mb); - var rvb = 15 - mb; - for (i = 0; i < s; ++i) { - if (cd[i]) { - var sv = i << 4 | cd[i]; - var r_1 = mb - cd[i]; - var v = le[cd[i] - 1]++ << r_1; - for (var m = v | (1 << r_1) - 1; v <= m; ++v) { - co[rev[v] >> rvb] = sv; - } - } - } - } else { - co = new u16(s); - for (i = 0; i < s; ++i) { - if (cd[i]) { - co[i] = rev[le[cd[i] - 1]++] >> 15 - cd[i]; - } - } - } - return co; -}); -var flt = new u8(288); -for (i = 0; i < 144; ++i) - flt[i] = 8; -var i; -for (i = 144; i < 256; ++i) - flt[i] = 9; -var i; -for (i = 256; i < 280; ++i) - flt[i] = 7; -var i; -for (i = 280; i < 288; ++i) - flt[i] = 8; -var i; -var fdt = new u8(32); -for (i = 0; i < 32; ++i) - fdt[i] = 5; -var i; -var flrm = /* @__PURE__ */ hMap(flt, 9, 1); -var fdrm = /* @__PURE__ */ hMap(fdt, 5, 1); -var max = function(a) { - var m = a[0]; - for (var i = 1; i < a.length; ++i) { - if (a[i] > m) - m = a[i]; - } - return m; -}; -var bits = function(d, p, m) { - var o = p / 8 | 0; - return (d[o] | d[o + 1] << 8) >> (p & 7) & m; -}; -var bits16 = function(d, p) { - var o = p / 8 | 0; - return (d[o] | d[o + 1] << 8 | d[o + 2] << 16) >> (p & 7); -}; -var shft = function(p) { - return (p + 7) / 8 | 0; -}; -var slc = function(v, s, e) { - if (s == null || s < 0) - s = 0; - if (e == null || e > v.length) - e = v.length; - return new u8(v.subarray(s, e)); -}; -var ec = [ - "unexpected EOF", - "invalid block type", - "invalid length/literal", - "invalid distance", - "stream finished", - "no stream handler", - , - // determined by compression function - "no callback", - "invalid UTF-8 data", - "extra field too long", - "date not in range 1980-2099", - "filename too long", - "stream finishing", - "invalid zip data" - // determined by unknown compression method -]; -var err = function(ind, msg, nt) { - var e = new Error(msg || ec[ind]); - e.code = ind; - if (Error.captureStackTrace) - Error.captureStackTrace(e, err); - if (!nt) - throw e; - return e; -}; -var inflt = function(dat, st, buf, dict) { - var sl = dat.length, dl = dict ? dict.length : 0; - if (!sl || st.f && !st.l) - return buf || new u8(0); - var noBuf = !buf; - var resize = noBuf || st.i != 2; - var noSt = st.i; - if (noBuf) - buf = new u8(sl * 3); - var cbuf = function(l2) { - var bl = buf.length; - if (l2 > bl) { - var nbuf = new u8(Math.max(bl * 2, l2)); - nbuf.set(buf); - buf = nbuf; - } - }; - var final = st.f || 0, pos = st.p || 0, bt = st.b || 0, lm = st.l, dm = st.d, lbt = st.m, dbt = st.n; - var tbts = sl * 8; - do { - if (!lm) { - final = bits(dat, pos, 1); - var type = bits(dat, pos + 1, 3); - pos += 3; - if (!type) { - var s = shft(pos) + 4, l = dat[s - 4] | dat[s - 3] << 8, t = s + l; - if (t > sl) { - if (noSt) - err(0); - break; - } - if (resize) - cbuf(bt + l); - buf.set(dat.subarray(s, t), bt); - st.b = bt += l, st.p = pos = t * 8, st.f = final; - continue; - } else if (type == 1) - lm = flrm, dm = fdrm, lbt = 9, dbt = 5; - else if (type == 2) { - var hLit = bits(dat, pos, 31) + 257, hcLen = bits(dat, pos + 10, 15) + 4; - var tl = hLit + bits(dat, pos + 5, 31) + 1; - pos += 14; - var ldt = new u8(tl); - var clt = new u8(19); - for (var i = 0; i < hcLen; ++i) { - clt[clim[i]] = bits(dat, pos + i * 3, 7); - } - pos += hcLen * 3; - var clb = max(clt), clbmsk = (1 << clb) - 1; - var clm = hMap(clt, clb, 1); - for (var i = 0; i < tl; ) { - var r = clm[bits(dat, pos, clbmsk)]; - pos += r & 15; - var s = r >> 4; - if (s < 16) { - ldt[i++] = s; - } else { - var c = 0, n = 0; - if (s == 16) - n = 3 + bits(dat, pos, 3), pos += 2, c = ldt[i - 1]; - else if (s == 17) - n = 3 + bits(dat, pos, 7), pos += 3; - else if (s == 18) - n = 11 + bits(dat, pos, 127), pos += 7; - while (n--) - ldt[i++] = c; - } - } - var lt = ldt.subarray(0, hLit), dt = ldt.subarray(hLit); - lbt = max(lt); - dbt = max(dt); - lm = hMap(lt, lbt, 1); - dm = hMap(dt, dbt, 1); - } else - err(1); - if (pos > tbts) { - if (noSt) - err(0); - break; - } - } - if (resize) - cbuf(bt + 131072); - var lms = (1 << lbt) - 1, dms = (1 << dbt) - 1; - var lpos = pos; - for (; ; lpos = pos) { - var c = lm[bits16(dat, pos) & lms], sym = c >> 4; - pos += c & 15; - if (pos > tbts) { - if (noSt) - err(0); - break; - } - if (!c) - err(2); - if (sym < 256) - buf[bt++] = sym; - else if (sym == 256) { - lpos = pos, lm = null; - break; - } else { - var add = sym - 254; - if (sym > 264) { - var i = sym - 257, b = fleb[i]; - add = bits(dat, pos, (1 << b) - 1) + fl[i]; - pos += b; - } - var d = dm[bits16(dat, pos) & dms], dsym = d >> 4; - if (!d) - err(3); - pos += d & 15; - var dt = fd[dsym]; - if (dsym > 3) { - var b = fdeb[dsym]; - dt += bits16(dat, pos) & (1 << b) - 1, pos += b; - } - if (pos > tbts) { - if (noSt) - err(0); - break; - } - if (resize) - cbuf(bt + 131072); - var end = bt + add; - if (bt < dt) { - var shift = dl - dt, dend = Math.min(dt, end); - if (shift + bt < 0) - err(3); - for (; bt < dend; ++bt) - buf[bt] = dict[shift + bt]; - } - for (; bt < end; ++bt) - buf[bt] = buf[bt - dt]; - } - } - st.l = lm, st.p = lpos, st.b = bt, st.f = final; - if (lm) - final = 1, st.m = lbt, st.d = dm, st.n = dbt; - } while (!final); - return bt != buf.length && noBuf ? slc(buf, 0, bt) : buf.subarray(0, bt); -}; -var et = /* @__PURE__ */ new u8(0); -var b2 = function(d, b) { - return d[b] | d[b + 1] << 8; -}; -var b4 = function(d, b) { - return (d[b] | d[b + 1] << 8 | d[b + 2] << 16 | d[b + 3] << 24) >>> 0; -}; -var b8 = function(d, b) { - return b4(d, b) + b4(d, b + 4) * 4294967296; -}; -function inflateSync(data, opts) { - return inflt(data, { i: 2 }, opts && opts.out, opts && opts.dictionary); -} -var td = typeof TextDecoder != "undefined" && /* @__PURE__ */ new TextDecoder(); -var tds = 0; -try { - td.decode(et, { stream: true }); - tds = 1; -} catch (e) { -} -var dutf8 = function(d) { - for (var r = "", i = 0; ; ) { - var c = d[i++]; - var eb = (c > 127) + (c > 223) + (c > 239); - if (i + eb > d.length) - return { s: r, r: slc(d, i - 1) }; - if (!eb) - r += String.fromCharCode(c); - else if (eb == 3) { - c = ((c & 15) << 18 | (d[i++] & 63) << 12 | (d[i++] & 63) << 6 | d[i++] & 63) - 65536, r += String.fromCharCode(55296 | c >> 10, 56320 | c & 1023); - } else if (eb & 1) - r += String.fromCharCode((c & 31) << 6 | d[i++] & 63); - else - r += String.fromCharCode((c & 15) << 12 | (d[i++] & 63) << 6 | d[i++] & 63); - } -}; -function strFromU8(dat, latin1) { - if (latin1) { - var r = ""; - for (var i = 0; i < dat.length; i += 16384) - r += String.fromCharCode.apply(null, dat.subarray(i, i + 16384)); - return r; - } else if (td) { - return td.decode(dat); - } else { - var _a2 = dutf8(dat), s = _a2.s, r = _a2.r; - if (r.length) - err(8); - return s; - } -} -var slzh = function(d, b) { - return b + 30 + b2(d, b + 26) + b2(d, b + 28); -}; -var zh = function(d, b, z) { - var fnl = b2(d, b + 28), efl = b2(d, b + 30), fn = strFromU8(d.subarray(b + 46, b + 46 + fnl), !(b2(d, b + 8) & 2048)), es = b + 46 + fnl; - var _a2 = z64hs(d, es, efl, z, b4(d, b + 20), b4(d, b + 24), b4(d, b + 42)), sc = _a2[0], su = _a2[1], off = _a2[2]; - return [b2(d, b + 10), sc, su, fn, es + efl + b2(d, b + 32), off]; -}; -var z64hs = function(d, b, l, z, sc, su, off) { - var nsc = sc == 4294967295, nsu = su == 4294967295, noff = off == 4294967295, e = b + l; - var nf = nsc + nsu + noff; - if (z && nf) { - for (; b + 4 < e; b += 4 + b2(d, b + 2)) { - if (b2(d, b) == 1) { - return [ - nsc ? b8(d, b + 4 + 8 * nsu) : sc, - nsu ? b8(d, b + 4) : su, - noff ? b8(d, b + 4 + 8 * (nsu + nsc)) : off, - 1 - ]; - } - } - if (z < 2) - err(13); - } - return [sc, su, off, 0]; -}; -function unzipSync(data, opts) { - var files = {}; - var e = data.length - 22; - for (; b4(data, e) != 101010256; --e) { - if (!e || data.length - e > 65558) - err(13); - } - ; - var c = b2(data, e + 8); - if (!c) - return {}; - var o = b4(data, e + 16); - var z = b4(data, e - 20) == 117853008; - if (z) { - var ze = b4(data, e - 12); - z = b4(data, ze) == 101075792; - if (z) { - c = b4(data, ze + 32); - o = b4(data, ze + 48); - } - } - var fltr = opts && opts.filter; - for (var i = 0; i < c; ++i) { - var _a2 = zh(data, o, z), c_2 = _a2[0], sc = _a2[1], su = _a2[2], fn = _a2[3], no = _a2[4], off = _a2[5], b = slzh(data, off); - o = no; - if (!fltr || fltr({ - name: fn, - size: sc, - originalSize: su, - compression: c_2 - })) { - if (!c_2) - files[fn] = slc(data, b, b + sc); - else if (c_2 == 8) - files[fn] = inflateSync(data.subarray(b, b + sc), { out: new u8(su) }); - else - err(14, "unknown compression type " + c_2); - } - } - return files; -} - -// upload/frontend/table/rebase_tree.js -function rebaseTree(root, prefix) { - root.path = `${prefix}/${root.path}`; - if (root.file) root.file = new File([root.file], root.file.name, { lastModified: root.file.lastModified }); - root.children.forEach((child) => rebaseTree(child, prefix)); - return root; -} - -// upload/frontend/zip/list_zip_files.js -var DEFAULT_LIMITS = { - maxEntries: 1e3, - maxTotalBytes: 100 * 1024 * 1024, - maxEntryBytes: 50 * 1024 * 1024, - maxDepth: 20 -}; -function extensionAllowed(name, allowedExt) { - const lowerName = name.toLowerCase(); - return allowedExt.some((extension) => lowerName.endsWith(extension.toLowerCase())); -} -function makeFile(data, name) { - return new File([data], name.split("/").at(-1)); -} -function safeEntryParts(entryName) { - if (!entryName || entryName.startsWith("/") || entryName.includes("\\")) return null; - const parts = entryName.split("/"); - if (parts.some((part) => !part || part === "." || part === "..")) return null; - return parts; -} -function node(kind, name, path, children = [], file = null) { - return { id: crypto.randomUUID(), kind, name, path, children, file, expanded: kind === "file" }; -} -function addPath(root, parts, fileNode) { - let current = root; - parts.forEach((part, index) => { - const last = index === parts.length - 1; - let child = current.children.find((item) => item.name === part); - if (!child) { - child = last ? fileNode : node("folder", part, `${current.path}/${part}`); - current.children.push(child); - } - current = child; - }); -} -async function listEntries(data, zipName, allowedExt, depth, limits, budget) { - if (depth > limits.maxDepth) throw new Error("\u0421\u043B\u0438\u0448\u043A\u043E\u043C \u0433\u043B\u0443\u0431\u043E\u043A\u0430\u044F \u0432\u043B\u043E\u0436\u0435\u043D\u043D\u043E\u0441\u0442\u044C ZIP"); - const entries = unzipSync(data, { - filter: (entry) => { - budget.entries += 1; - if (budget.entries > limits.maxEntries) throw new Error("\u0421\u043B\u0438\u0448\u043A\u043E\u043C \u043C\u043D\u043E\u0433\u043E ZIP entries"); - const lowerName = entry.name.toLowerCase(); - if (!extensionAllowed(lowerName, allowedExt) && !lowerName.endsWith(".zip")) return false; - if (entry.originalSize > limits.maxEntryBytes) return false; - if (budget.totalBytes + entry.originalSize > limits.maxTotalBytes) { - throw new Error("\u041F\u0440\u0435\u0432\u044B\u0448\u0435\u043D \u0441\u0443\u043C\u043C\u0430\u0440\u043D\u044B\u0439 \u0440\u0430\u0437\u043C\u0435\u0440 \u0440\u0430\u0441\u043F\u0430\u043A\u043E\u0432\u0430\u043D\u043D\u044B\u0445 ZIP entries"); - } - budget.totalBytes += entry.originalSize; - return true; - } - }); - const root = node("zip", zipName, zipName); - for (const [entryName, entryData] of Object.entries(entries)) { - if (entryName.endsWith("/")) continue; - const parts = safeEntryParts(entryName); - if (!parts) continue; - const normalizedName = parts.join("/"); - if (normalizedName.toLowerCase().endsWith(".zip")) { - const nested = await listEntries(entryData, entryName, allowedExt, depth + 1, limits, budget); - if (nested) { - rebaseTree(nested, zipName); - nested.name = parts.at(-1); - addPath(root, parts, nested); - } - } else if (extensionAllowed(normalizedName, allowedExt)) { - const path = `${zipName}/${normalizedName}`; - const file = makeFile(entryData, path); - addPath(root, parts, node("file", parts.at(-1), path, [], file)); - } - } - return root.children.length ? root : null; -} -async function listZipFiles(file, allowedExt, customLimits = {}) { - const data = new Uint8Array(await file.arrayBuffer()); - const limits = { ...DEFAULT_LIMITS, ...customLimits }; - return listEntries(data, file.name, allowedExt, 0, limits, { entries: 0, totalBytes: 0 }); -} - -// upload/frontend/table/add_file_with_dedup.js -function addFileWithDedup(state, fileNode) { - const accept = (node2) => { - if (node2.kind === "file") { - const key = `${node2.path}\0${node2.file.size}`; - if (state.fileKeys.has(key)) return null; - state.fileKeys.add(key); - return node2; - } - node2.children = node2.children.map(accept).filter(Boolean); - return node2.children.length ? node2 : null; - }; - const accepted = accept(fileNode); - if (!accepted || accepted.kind !== "file" && !accepted.children.length) return false; - if (accepted.kind !== "file") { - const existing = state.nodes.find((node2) => node2.kind !== "file" && node2.path === accepted.path); - if (existing) { - mergeChildren(existing, accepted); - return true; - } - } - state.nodes.push(accepted); - return true; -} -function mergeChildren(target, incoming) { - incoming.children.forEach((child) => { - if (child.kind === "file") { - const duplicate = target.children.some((existing2) => existing2.kind === "file" && existing2.path === child.path && existing2.file.size === child.file.size); - if (!duplicate) target.children.push(child); - return; - } - const existing = target.children.find((candidate) => candidate.kind !== "file" && candidate.path === child.path); - if (existing) mergeChildren(existing, child); - else target.children.push(child); - }); -} - -// upload/frontend/table/esc.js -function esc(value) { - return String(value).replace(/[&<>"']/g, (character) => ({ - "&": "&", - "<": "<", - ">": ">", - '"': """, - "'": "'" - })[character]); -} - -// upload/frontend/table/fs.js -function fs(bytes) { - return bytes < 1024 ? `${bytes} B` : bytes < 1048576 ? `${(bytes / 1024).toFixed(1)} KB` : `${(bytes / 1048576).toFixed(1)} MB`; -} - -// upload/frontend/table/render.js -var DEFAULT_RENDER_CONFIG = { - labels: { - statusReady: "\u0433\u043E\u0442\u043E\u0432", - remove: "\u0423\u0434\u0430\u043B\u0438\u0442\u044C", - empty: "\u041D\u0435\u0442 \u0432\u044B\u0431\u0440\u0430\u043D\u043D\u044B\u0445 \u0444\u0430\u0439\u043B\u043E\u0432", - columns: { path: "\u041F\u0443\u0442\u044C", size: "\u0420\u0430\u0437\u043C\u0435\u0440", status: "\u0421\u0442\u0430\u0442\u0443\u0441" }, - count: (count, bytes) => `${count} \u0444\u0430\u0439\u043B\u043E\u0432 \xB7 ${fs(bytes)}` - }, - layout: { columns: ["path", "size", "status"] } -}; -function renderConfig(cfg = {}) { - return { - labels: { - ...DEFAULT_RENDER_CONFIG.labels, - ...cfg.labels || {}, - columns: { - ...DEFAULT_RENDER_CONFIG.labels.columns, - ...cfg.labels?.columns || {} - } - }, - layout: { ...DEFAULT_RENDER_CONFIG.layout, ...cfg.layout || {} } - }; -} -function renderNode(node2, depth, cfg) { - const isGroup = node2.kind !== "file"; - const padding = depth * 4; - const name = esc(node2.name); - const action = isGroup ? `` : `${name}`; - const remove = ``; - const pathAttribute = node2.kind === "file" ? ` data-path="${esc(node2.path)}"` : ""; - const cells = { - path: action, - size: node2.kind === "file" ? fs(node2.file.size) : "", - status: node2.error ? esc(node2.error) : node2.kind === "file" ? esc(cfg.labels.statusReady) : "" - }; - const columns = cfg.layout.columns?.length ? cfg.layout.columns : Object.keys(DEFAULT_RENDER_CONFIG.labels.columns); - const row = `` + columns.map((column) => `${cells[column] || ""}`).join("") + `${remove}`; - if (!isGroup || !node2.expanded) return row; - return row + node2.children.map((child) => renderNode(child, depth + 1, cfg)).join(""); -} -function render(state, elements, cfg) { - const normalized = renderConfig(cfg); - const columns = normalized.layout.columns?.length ? normalized.layout.columns : Object.keys(DEFAULT_RENDER_CONFIG.labels.columns); - elements.tableBodyEl.innerHTML = state.nodes.length ? state.nodes.map((node2) => renderNode(node2, 0, normalized)).join("") : `${esc(normalized.labels.empty)}`; - const files = []; - const visit = (node2) => { - if (node2.kind === "file") files.push(node2); - else node2.children.forEach(visit); - }; - state.nodes.forEach(visit); - const totalBytes = files.reduce((sum, node2) => sum + node2.file.size, 0); - elements.countEl.textContent = normalized.labels.count(files.length, totalBytes); -} -function findNode(nodes, id) { - for (const node2 of nodes) { - if (node2.id === id) return { node: node2, nodes }; - const found = findNode(node2.children || [], id); - if (found) return found; - } - return null; -} -function flattenFiles(nodes, result = []) { - nodes.forEach((node2) => { - if (node2.kind === "file") result.push({ path: node2.path, name: node2.name, size: node2.file.size, file: node2.file }); - else flattenFiles(node2.children, result); - }); - return result; -} - -// upload/frontend/table/on_files_change.js -async function addFiles(state, cfg, files, elements) { - for (const file of Array.from(files)) { - if (!file.name.toLowerCase().endsWith(".zip")) { - if (!cfg.allowedExt.some((extension) => file.name.toLowerCase().endsWith(extension.toLowerCase()))) { - continue; - } - addFileWithDedup(state, { - id: crypto.randomUUID(), - kind: "file", - name: file.name, - path: file.name, - file, - children: [], - expanded: true - }); - continue; - } - try { - const zipTree = await listZipFiles(file, cfg.allowedExt, cfg.limits); - if (zipTree) addFileWithDedup(state, zipTree); - } catch (error) { - if (typeof cfg.onError === "function") { - cfg.onError(error, file); - } else if (elements.statusEl) { - elements.statusEl.textContent = `\u041E\u0448\u0438\u0431\u043A\u0430 \u0447\u0442\u0435\u043D\u0438\u044F \u0430\u0440\u0445\u0438\u0432\u0430 ${file.name}: ${error.message}`; - } - continue; - } - } - render(state, elements, cfg); -} -function onFilesChange(state, cfg, elements) { - return async () => { - if (state.busy) return; - state.busy = true; - try { - await addFiles(state, cfg, elements.fileInputEl.files, elements); - } finally { - elements.fileInputEl.value = ""; - state.busy = false; - } - }; -} - -// upload/frontend/table/on_folder_change.js -function onFolderChange(state, cfg, elements) { - return async () => { - if (state.busy) return; - state.busy = true; - try { - const roots = /* @__PURE__ */ new Map(); - for (const file of Array.from(elements.folderInputEl.files)) { - const parts = (file.webkitRelativePath || file.name).split("/"); - const relativePath = parts.slice(1).join("/") || file.name; - const lowerPath = relativePath.toLowerCase(); - const rootName = parts[0] || file.name; - if (!roots.has(rootName)) { - roots.set(rootName, { - id: crypto.randomUUID(), - kind: "folder", - name: rootName, - path: rootName, - children: [], - expanded: false - }); - } - const root = roots.get(rootName); - const addToFolder = (node2) => { - let current = root; - const nodeParts = node2.path.split("/").slice(1); - nodeParts.forEach((part, index) => { - const last = index === nodeParts.length - 1; - let child = current.children.find((item) => item.name === part); - if (!child) { - child = last ? node2 : { - id: crypto.randomUUID(), - kind: "folder", - name: part, - path: `${rootName}/${nodeParts.slice(0, index + 1).join("/")}`, - children: [], - expanded: false - }; - current.children.push(child); - } - current = child; - }); - }; - if (lowerPath.endsWith(".zip")) { - try { - const zip = await listZipFiles(file, cfg.allowedExt, cfg.limits); - if (zip) { - rebaseTree(zip, rootName); - addToFolder(zip); - } - } catch (error) { - if (typeof cfg.onError === "function") { - cfg.onError(error, file); - } else if (elements.statusEl) { - elements.statusEl.textContent = `\u041E\u0448\u0438\u0431\u043A\u0430 \u0447\u0442\u0435\u043D\u0438\u044F \u0430\u0440\u0445\u0438\u0432\u0430 ${file.name}: ${error.message}`; - } - continue; - } - } else if (cfg.allowedExt.some((extension) => lowerPath.endsWith(extension))) { - addToFolder({ - id: crypto.randomUUID(), - kind: "file", - name: parts.at(-1), - path: `${rootName}/${relativePath}`, - file, - children: [], - expanded: true - }); - } - } - roots.forEach((root) => addFileWithDedup(state, root)); - elements.folderInputEl.value = ""; - render(state, elements, cfg); - } finally { - state.busy = false; - } - }; -} - -// upload/frontend/upload/put_to_vm.js -function putToVm(file, url, options = {}) { - return new Promise((resolve, reject) => { - const xhr = new XMLHttpRequest(); - if (options.onXHR) { - options.onXHR(xhr); - } - const abortHandler = () => { - xhr.abort(); - reject(new DOMException("Upload aborted", "AbortError")); - }; - if (options.signal) { - if (options.signal.aborted) { - reject(new DOMException("Upload aborted", "AbortError")); - return; - } - options.signal.addEventListener("abort", abortHandler, { once: true }); - } - xhr.open("PUT", url); - xhr.timeout = options.timeoutMs || 3e5; - xhr.upload.onprogress = (e) => { - if (e.lengthComputable && options.onProgress) { - const pct = Math.round(e.loaded / e.total * 100); - options.onProgress(pct, e.loaded, e.total); - } - }; - xhr.onload = () => { - if (options.signal) { - options.signal.removeEventListener("abort", abortHandler); - } - if (xhr.status >= 200 && xhr.status < 300) { - resolve(); - } else { - reject(new Error(`\u0411\u0443\u0444\u0435\u0440: HTTP ${xhr.status} ${xhr.statusText}`)); - } - }; - xhr.onerror = () => { - if (options.signal) { - options.signal.removeEventListener("abort", abortHandler); - } - reject(new Error("\u0421\u0435\u0442\u0435\u0432\u0430\u044F \u043E\u0448\u0438\u0431\u043A\u0430 \u043F\u0440\u0438 \u043E\u0442\u043F\u0440\u0430\u0432\u043A\u0435 \u0432 \u0431\u0443\u0444\u0435\u0440")); - }; - xhr.ontimeout = () => { - if (options.signal) { - options.signal.removeEventListener("abort", abortHandler); - } - reject(new Error(`\u0422\u0430\u0439\u043C\u0430\u0443\u0442 \u043E\u0436\u0438\u0434\u0430\u043D\u0438\u044F \u043E\u0442\u0432\u0435\u0442\u0430 \u0431\u0443\u0444\u0435\u0440\u0430 (${Math.round(xhr.timeout / 1e3)}\u0441)`)); - }; - xhr.onabort = () => { - if (options.signal) { - options.signal.removeEventListener("abort", abortHandler); - } - reject(new DOMException("Upload aborted", "AbortError")); - }; - xhr.send(file); - }); -} - -// upload/frontend/upload/upload_via_vm.js -function generateUuid() { - if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") { - return crypto.randomUUID(); - } - return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => { - const r = Math.random() * 16 | 0; - const v = c === "x" ? r : r & 3 | 8; - return v.toString(16); - }); -} -function normalizeFileEntry(item) { - if (item instanceof File || item instanceof Blob) { - return { name: item.name || "unnamed", size: item.size, file: item, path: item.name || "" }; - } - if (item && item.file) { - return { - name: item.name || item.file.name || "unnamed", - size: item.size ?? item.file.size ?? 0, - file: item.file, - path: item.path || item.name || "" - }; - } - throw new Error("\u041D\u0435\u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u044B\u0439 \u043E\u0431\u044A\u0435\u043A\u0442 \u0444\u0430\u0439\u043B\u0430"); -} -async function uploadViaVM(files, options = {}) { - if (!options.vmUploadUrl) { - return { ok: false, error: "\u041F\u0430\u0440\u0430\u043C\u0435\u0442\u0440 options.vmUploadUrl \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u0435\u043D" }; - } - const normalizedFiles = Array.from(files).map(normalizeFileEntry); - const total = normalizedFiles.length; - if (total === 0) { - return { ok: true, session: options.session || "", count: 0 }; - } - const backendUrl = options.backendUploadUrl || (options.apiBase || "") + "/api/upload_refs"; - const vmBase = options.vmUploadUrl.endsWith("/") ? options.vmUploadUrl : `${options.vmUploadUrl}/`; - let currentSession = options.session || ""; - let totalAdded = 0; - for (let k = 0; k < total; k++) { - if (options.signal?.aborted) { - return { ok: false, error: "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u043E\u0442\u043C\u0435\u043D\u0435\u043D\u0430", aborted: true, session: currentSession }; - } - const { name, size, file } = normalizedFiles[k]; - const fileKey = `${generateUuid()}_${k}`; - const fileUrl = `${vmBase}${fileKey}`; - if (options.onStatus) { - options.onStatus(`\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u0432 \u0431\u0443\u0444\u0435\u0440 (${k + 1}/${total}): ${name}`); - } - if (options.onFileStatus) { - options.onFileStatus(k, "\u23F3 \u0412 \u0431\u0443\u0444\u0435\u0440..."); - } - const t0 = performance.now(); - try { - await putToVm(file, fileUrl, { - signal: options.signal, - onXHR: options.onXHR, - onProgress(pct, loaded, fileTotal) { - const elapsed = (performance.now() - t0) / 1e3; - const speed = elapsed > 0 ? loaded / elapsed : 0; - if (options.onFileStatus) { - options.onFileStatus(k, `\u23F3 ${pct}% (${fs(speed)}/s)`); - } - if (options.onProgress) { - options.onProgress({ index: k, total, pct, speed, loaded, fileTotal, name }); - } - } - }); - } catch (err2) { - if (options.signal?.aborted) { - return { ok: false, error: "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u043E\u0442\u043C\u0435\u043D\u0435\u043D\u0430", aborted: true, session: currentSession }; - } - if (options.onFileStatus) { - options.onFileStatus(k, "\u2717 \u041E\u0448\u0438\u0431\u043A\u0430 \u0431\u0443\u0444\u0435\u0440\u0430"); - } - return { - ok: false, - error: `\u041E\u0448\u0438\u0431\u043A\u0430 \u043E\u0442\u043F\u0440\u0430\u0432\u043A\u0438 \u0444\u0430\u0439\u043B\u0430 ${name} \u0432 \u0431\u0443\u0444\u0435\u0440: ${err2.message}`, - failedIndex: k, - session: currentSession - }; - } - if (options.onStatus) { - options.onStatus(`\u041F\u0440\u0438\u0451\u043C \u0441\u0435\u0440\u0432\u0438\u0441\u043E\u043C (${k + 1}/${total}): ${name}`); - } - if (options.onFileStatus) { - options.onFileStatus(k, "\u26A1 \u0412 \u0441\u0435\u0441\u0441\u0438\u044E..."); - } - try { - const resp = await fetch(backendUrl, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - session: currentSession, - files: [{ name, size, url: fileUrl }] - }), - signal: options.signal - }); - if (!resp.ok) { - throw new Error(`HTTP ${resp.status} ${resp.statusText}`); - } - const data = await resp.json(); - if (!data.ok) { - throw new Error(data.error || "\u0411\u044D\u043A\u0435\u043D\u0434 \u0432\u0435\u0440\u043D\u0443\u043B \u043E\u0448\u0438\u0431\u043A\u0443"); - } - currentSession = data.session || currentSession; - totalAdded = data.count ?? totalAdded + 1; - if (options.onFileStatus) { - options.onFileStatus(k, "\u2713 \u0414\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D"); - } - if (options.onFileComplete) { - options.onFileComplete({ - fileIndex: k, - name, - size, - session: currentSession, - totalAdded - }); - } - } catch (err2) { - if (options.signal?.aborted) { - return { ok: false, error: "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u043E\u0442\u043C\u0435\u043D\u0435\u043D\u0430", aborted: true, session: currentSession }; - } - if (options.onFileStatus) { - options.onFileStatus(k, "\u2717 \u041E\u0448\u0438\u0431\u043A\u0430 \u043F\u0440\u0438\u0451\u043C\u0430"); - } - return { - ok: false, - error: `\u041E\u0448\u0438\u0431\u043A\u0430 \u043F\u0440\u0438\u0451\u043C\u0430 \u0444\u0430\u0439\u043B\u0430 ${name} \u0431\u044D\u043A\u0435\u043D\u0434\u043E\u043C: ${err2.message}`, - failedIndex: k, - session: currentSession - }; - } - } - if (options.onStatus) { - options.onStatus(`\u0417\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u043E. \u0423\u0441\u043F\u0435\u0448\u043D\u043E \u043F\u0435\u0440\u0435\u0434\u0430\u043D\u043E \u0444\u0430\u0439\u043B\u043E\u0432: ${total}`); - } - return { ok: true, session: currentSession, count: totalAdded }; -} - -// upload/frontend/index.js -var DEFAULTS = { - allowedExt: [], - labels: { - pickFiles: "\u0412\u044B\u0431\u0440\u0430\u0442\u044C \u0444\u0430\u0439\u043B\u044B", - pickFolder: "\u0412\u044B\u0431\u0440\u0430\u0442\u044C \u043F\u0430\u043F\u043A\u0443", - clear: "\u041E\u0447\u0438\u0441\u0442\u0438\u0442\u044C", - empty: "\u041D\u0435\u0442 \u0432\u044B\u0431\u0440\u0430\u043D\u043D\u044B\u0445 \u0444\u0430\u0439\u043B\u043E\u0432", - statusReady: "\u0433\u043E\u0442\u043E\u0432", - remove: "\u0423\u0434\u0430\u043B\u0438\u0442\u044C", - columns: { path: "\u041F\u0443\u0442\u044C", size: "\u0420\u0430\u0437\u043C\u0435\u0440", status: "\u0421\u0442\u0430\u0442\u0443\u0441" }, - count: (count, bytes) => `${count} \u0444\u0430\u0439\u043B\u043E\u0432 \xB7 ${bytes} B` - }, - layout: { columns: ["path", "size", "status"], controls: ["files", "folder", "clear"] }, - limits: { - maxEntries: 1e3, - maxTotalBytes: 100 * 1024 * 1024, - maxEntryBytes: 50 * 1024 * 1024, - maxDepth: 20 - } -}; -function resolveMount(mount) { - const element = typeof mount === "string" ? document.querySelector(mount) : mount; - if (!element) throw new Error("File picker mount element \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D"); - return element; -} -function normalizeConfig(config) { - return { - ...config, - allowedExt: config.allowedExt || DEFAULTS.allowedExt, - labels: { - ...DEFAULTS.labels, - ...config.labels || {}, - columns: { ...DEFAULTS.labels.columns, ...config.labels?.columns || {} } - }, - layout: { ...DEFAULTS.layout, ...config.layout || {} }, - limits: { ...DEFAULTS.limits, ...config.limits || {} } - }; -} -function injectStyles() { - if (document.querySelector("style[data-file-picker]")) return; - const style = document.createElement("style"); - style.dataset.filePicker = ""; - style.textContent = ` -.file-picker { color: #17211b; font-family: Georgia, 'Times New Roman', serif; } -.file-picker .fp-toolbar { display: flex; flex-wrap: wrap; gap: 10px; margin: 16px 0; } -.file-picker .fp-toolbar button { border: 0; border-radius: 4px; padding: 12px 17px; color: #f7faf4; background: #1f5a3b; font: 700 13px sans-serif; cursor: pointer; } -.file-picker .fp-toolbar button.secondary { color: #1f5a3b; background: #cbdcc9; } -.file-picker .fp-toolbar button.quiet { color: #5d6a61; background: transparent; } -.file-picker .fp-table-wrap { overflow-x: auto; border-top: 1px solid #b9c7ba; } -.file-picker .fp-table { width: 100%; border-collapse: collapse; font: 14px/1.4 sans-serif; } -.file-picker .fp-table th, .file-picker .fp-table td { padding: 14px 10px; border-bottom: 1px solid #cbd5cc; text-align: left; } -.file-picker .fp-table th { color: #56745f; font-size: 11px; text-transform: uppercase; letter-spacing: 1px; } -.file-picker .fp-status, .file-picker .fp-count { color: #5d6a61; font: 13px sans-serif; } -.file-picker .fp-count { min-height: 22px; } -.file-picker .tree-name { display: inline-flex; align-items: center; gap: 8px; min-width: 240px; padding-top: 0; padding-bottom: 0; border: 0; background: transparent; color: #17211b; font: inherit; text-align: left; } -.file-picker .tree-group { padding-left: 0; cursor: pointer; } -.file-picker .tree-chevron { display: inline-block; width: 12px; color: #78917d; font-size: 10px; } -.file-picker .remove-btn { padding: 2px 7px; color: #8c5148; background: transparent; font: 20px/1 sans-serif; } -.file-picker .tree-row td:first-child { white-space: nowrap; } -@media (max-width: 600px) { .file-picker .fp-toolbar button { flex: 1 1 42%; } } -`; - document.head.append(style); -} -function buildMarkup(root, cfg) { - const controls = cfg.layout.controls || []; - const control = (name, id, label, className = "") => controls.includes(name) ? `` : ""; - const columns = cfg.layout.columns?.length ? cfg.layout.columns : Object.keys(cfg.labels.columns); - const headings = columns.map((column) => `${esc(cfg.labels.columns[column] || column)}`).join(""); - root.innerHTML = ` -
-
- - - ${control("files", "fp-files-btn", cfg.labels.pickFiles)} - ${control("folder", "fp-folder-btn", cfg.labels.pickFolder, "secondary")} - ${control("clear", "fp-clear-btn", cfg.labels.clear, "quiet")} -
-

-
${headings}
-

-
`; -} -function notify(cfg, state) { - if (typeof cfg.onChange === "function") cfg.onChange([...flattenFiles(state.nodes)]); -} -function removeMetadata(state, node2) { - if (node2.kind === "file") { - state.fileKeys.delete(`${node2.path}\0${node2.file.size}`); - return; - } - node2.children.forEach((child) => removeMetadata(state, child)); -} -function removeNode(state, id) { - const found = findNode(state.nodes, id); - if (!found) return false; - removeMetadata(state, found.node); - found.nodes.splice(found.nodes.indexOf(found.node), 1); - return true; -} -function initFilePicker(config) { - const cfg = normalizeConfig(config); - const mount = resolveMount(cfg.mount); - injectStyles(); - buildMarkup(mount, cfg); - const root = mount.firstElementChild; - const elements = { - fileInputEl: root.querySelector(".fp-file-input"), - folderInputEl: root.querySelector(".fp-folder-input"), - statusEl: root.querySelector(".fp-status"), - tableBodyEl: root.querySelector(".fp-table-body"), - countEl: root.querySelector(".fp-count") - }; - const state = { nodes: [], fileKeys: /* @__PURE__ */ new Set(), busy: false }; - const listeners = []; - const listen = (target, event, handler) => { - target.addEventListener(event, handler); - listeners.push(() => target.removeEventListener(event, handler)); - }; - const redraw = () => render(state, elements, cfg); - const filesChange = onFilesChange(state, cfg, elements); - const folderChange = onFolderChange(state, cfg, elements); - listen(elements.fileInputEl, "change", async () => { - await filesChange(); - notify(cfg, state); - }); - listen(elements.folderInputEl, "change", async () => { - await folderChange(); - notify(cfg, state); - }); - listen(elements.tableBodyEl, "click", (event) => { - const toggle = event.target.closest("[data-toggle]"); - if (toggle) { - const found = findNode(state.nodes, toggle.dataset.toggle); - if (found) found.node.expanded = !found.node.expanded; - redraw(); - return; - } - const remove = event.target.closest("[data-remove]"); - if (remove) { - if (removeNode(state, remove.dataset.remove)) { - redraw(); - notify(cfg, state); - } - } - }); - if (root.querySelector("#fp-files-btn")) listen(root.querySelector("#fp-files-btn"), "click", () => elements.fileInputEl.click()); - if (root.querySelector("#fp-folder-btn")) listen(root.querySelector("#fp-folder-btn"), "click", () => elements.folderInputEl.click()); - if (root.querySelector("#fp-clear-btn")) listen(root.querySelector("#fp-clear-btn"), "click", () => { - state.nodes = []; - state.fileKeys.clear(); - redraw(); - notify(cfg, state); - }); - redraw(); - return { - pickFiles: () => elements.fileInputEl.click(), - pickFolder: () => elements.folderInputEl.click(), - addFiles: async (files) => { - await addFiles(state, cfg, files, elements); - notify(cfg, state); - }, - getFiles: () => [...flattenFiles(state.nodes)], - remove: (id) => { - if (removeNode(state, id)) { - redraw(); - notify(cfg, state); - } - }, - clear: () => { - state.nodes = []; - state.fileKeys.clear(); - redraw(); - notify(cfg, state); - }, - render: redraw, - destroy: () => { - listeners.forEach((removeListener) => removeListener()); - state.nodes = []; - state.fileKeys.clear(); - mount.replaceChildren(); - } - }; -} -export { - DEFAULTS, - initFilePicker, - putToVm, - uploadViaVM -}; diff --git a/dist/file-picker.iife.js b/dist/file-picker.iife.js deleted file mode 100644 index 0659d05..0000000 --- a/dist/file-picker.iife.js +++ /dev/null @@ -1,1218 +0,0 @@ -var FilePicker = (() => { - var __defProp = Object.defineProperty; - var __getOwnPropDesc = Object.getOwnPropertyDescriptor; - var __getOwnPropNames = Object.getOwnPropertyNames; - var __hasOwnProp = Object.prototype.hasOwnProperty; - var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); - }; - var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; - }; - var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); - - // upload/frontend/index.js - var index_exports = {}; - __export(index_exports, { - DEFAULTS: () => DEFAULTS, - initFilePicker: () => initFilePicker, - putToVm: () => putToVm, - uploadViaVM: () => uploadViaVM - }); - - // node_modules/fflate/esm/browser.js - var u8 = Uint8Array; - var u16 = Uint16Array; - var i32 = Int32Array; - var fleb = new u8([ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 1, - 1, - 1, - 2, - 2, - 2, - 2, - 3, - 3, - 3, - 3, - 4, - 4, - 4, - 4, - 5, - 5, - 5, - 5, - 0, - /* unused */ - 0, - 0, - /* impossible */ - 0 - ]); - var fdeb = new u8([ - 0, - 0, - 0, - 0, - 1, - 1, - 2, - 2, - 3, - 3, - 4, - 4, - 5, - 5, - 6, - 6, - 7, - 7, - 8, - 8, - 9, - 9, - 10, - 10, - 11, - 11, - 12, - 12, - 13, - 13, - /* unused */ - 0, - 0 - ]); - var clim = new u8([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]); - var freb = function(eb, start) { - var b = new u16(31); - for (var i = 0; i < 31; ++i) { - b[i] = start += 1 << eb[i - 1]; - } - var r = new i32(b[30]); - for (var i = 1; i < 30; ++i) { - for (var j = b[i]; j < b[i + 1]; ++j) { - r[j] = j - b[i] << 5 | i; - } - } - return { b, r }; - }; - var _a = freb(fleb, 2); - var fl = _a.b; - var revfl = _a.r; - fl[28] = 258, revfl[258] = 28; - var _b = freb(fdeb, 0); - var fd = _b.b; - var revfd = _b.r; - var rev = new u16(32768); - for (i = 0; i < 32768; ++i) { - x = (i & 43690) >> 1 | (i & 21845) << 1; - x = (x & 52428) >> 2 | (x & 13107) << 2; - x = (x & 61680) >> 4 | (x & 3855) << 4; - rev[i] = ((x & 65280) >> 8 | (x & 255) << 8) >> 1; - } - var x; - var i; - var hMap = (function(cd, mb, r) { - var s = cd.length; - var i = 0; - var l = new u16(mb); - for (; i < s; ++i) { - if (cd[i]) - ++l[cd[i] - 1]; - } - var le = new u16(mb); - for (i = 1; i < mb; ++i) { - le[i] = le[i - 1] + l[i - 1] << 1; - } - var co; - if (r) { - co = new u16(1 << mb); - var rvb = 15 - mb; - for (i = 0; i < s; ++i) { - if (cd[i]) { - var sv = i << 4 | cd[i]; - var r_1 = mb - cd[i]; - var v = le[cd[i] - 1]++ << r_1; - for (var m = v | (1 << r_1) - 1; v <= m; ++v) { - co[rev[v] >> rvb] = sv; - } - } - } - } else { - co = new u16(s); - for (i = 0; i < s; ++i) { - if (cd[i]) { - co[i] = rev[le[cd[i] - 1]++] >> 15 - cd[i]; - } - } - } - return co; - }); - var flt = new u8(288); - for (i = 0; i < 144; ++i) - flt[i] = 8; - var i; - for (i = 144; i < 256; ++i) - flt[i] = 9; - var i; - for (i = 256; i < 280; ++i) - flt[i] = 7; - var i; - for (i = 280; i < 288; ++i) - flt[i] = 8; - var i; - var fdt = new u8(32); - for (i = 0; i < 32; ++i) - fdt[i] = 5; - var i; - var flrm = /* @__PURE__ */ hMap(flt, 9, 1); - var fdrm = /* @__PURE__ */ hMap(fdt, 5, 1); - var max = function(a) { - var m = a[0]; - for (var i = 1; i < a.length; ++i) { - if (a[i] > m) - m = a[i]; - } - return m; - }; - var bits = function(d, p, m) { - var o = p / 8 | 0; - return (d[o] | d[o + 1] << 8) >> (p & 7) & m; - }; - var bits16 = function(d, p) { - var o = p / 8 | 0; - return (d[o] | d[o + 1] << 8 | d[o + 2] << 16) >> (p & 7); - }; - var shft = function(p) { - return (p + 7) / 8 | 0; - }; - var slc = function(v, s, e) { - if (s == null || s < 0) - s = 0; - if (e == null || e > v.length) - e = v.length; - return new u8(v.subarray(s, e)); - }; - var ec = [ - "unexpected EOF", - "invalid block type", - "invalid length/literal", - "invalid distance", - "stream finished", - "no stream handler", - , - // determined by compression function - "no callback", - "invalid UTF-8 data", - "extra field too long", - "date not in range 1980-2099", - "filename too long", - "stream finishing", - "invalid zip data" - // determined by unknown compression method - ]; - var err = function(ind, msg, nt) { - var e = new Error(msg || ec[ind]); - e.code = ind; - if (Error.captureStackTrace) - Error.captureStackTrace(e, err); - if (!nt) - throw e; - return e; - }; - var inflt = function(dat, st, buf, dict) { - var sl = dat.length, dl = dict ? dict.length : 0; - if (!sl || st.f && !st.l) - return buf || new u8(0); - var noBuf = !buf; - var resize = noBuf || st.i != 2; - var noSt = st.i; - if (noBuf) - buf = new u8(sl * 3); - var cbuf = function(l2) { - var bl = buf.length; - if (l2 > bl) { - var nbuf = new u8(Math.max(bl * 2, l2)); - nbuf.set(buf); - buf = nbuf; - } - }; - var final = st.f || 0, pos = st.p || 0, bt = st.b || 0, lm = st.l, dm = st.d, lbt = st.m, dbt = st.n; - var tbts = sl * 8; - do { - if (!lm) { - final = bits(dat, pos, 1); - var type = bits(dat, pos + 1, 3); - pos += 3; - if (!type) { - var s = shft(pos) + 4, l = dat[s - 4] | dat[s - 3] << 8, t = s + l; - if (t > sl) { - if (noSt) - err(0); - break; - } - if (resize) - cbuf(bt + l); - buf.set(dat.subarray(s, t), bt); - st.b = bt += l, st.p = pos = t * 8, st.f = final; - continue; - } else if (type == 1) - lm = flrm, dm = fdrm, lbt = 9, dbt = 5; - else if (type == 2) { - var hLit = bits(dat, pos, 31) + 257, hcLen = bits(dat, pos + 10, 15) + 4; - var tl = hLit + bits(dat, pos + 5, 31) + 1; - pos += 14; - var ldt = new u8(tl); - var clt = new u8(19); - for (var i = 0; i < hcLen; ++i) { - clt[clim[i]] = bits(dat, pos + i * 3, 7); - } - pos += hcLen * 3; - var clb = max(clt), clbmsk = (1 << clb) - 1; - var clm = hMap(clt, clb, 1); - for (var i = 0; i < tl; ) { - var r = clm[bits(dat, pos, clbmsk)]; - pos += r & 15; - var s = r >> 4; - if (s < 16) { - ldt[i++] = s; - } else { - var c = 0, n = 0; - if (s == 16) - n = 3 + bits(dat, pos, 3), pos += 2, c = ldt[i - 1]; - else if (s == 17) - n = 3 + bits(dat, pos, 7), pos += 3; - else if (s == 18) - n = 11 + bits(dat, pos, 127), pos += 7; - while (n--) - ldt[i++] = c; - } - } - var lt = ldt.subarray(0, hLit), dt = ldt.subarray(hLit); - lbt = max(lt); - dbt = max(dt); - lm = hMap(lt, lbt, 1); - dm = hMap(dt, dbt, 1); - } else - err(1); - if (pos > tbts) { - if (noSt) - err(0); - break; - } - } - if (resize) - cbuf(bt + 131072); - var lms = (1 << lbt) - 1, dms = (1 << dbt) - 1; - var lpos = pos; - for (; ; lpos = pos) { - var c = lm[bits16(dat, pos) & lms], sym = c >> 4; - pos += c & 15; - if (pos > tbts) { - if (noSt) - err(0); - break; - } - if (!c) - err(2); - if (sym < 256) - buf[bt++] = sym; - else if (sym == 256) { - lpos = pos, lm = null; - break; - } else { - var add = sym - 254; - if (sym > 264) { - var i = sym - 257, b = fleb[i]; - add = bits(dat, pos, (1 << b) - 1) + fl[i]; - pos += b; - } - var d = dm[bits16(dat, pos) & dms], dsym = d >> 4; - if (!d) - err(3); - pos += d & 15; - var dt = fd[dsym]; - if (dsym > 3) { - var b = fdeb[dsym]; - dt += bits16(dat, pos) & (1 << b) - 1, pos += b; - } - if (pos > tbts) { - if (noSt) - err(0); - break; - } - if (resize) - cbuf(bt + 131072); - var end = bt + add; - if (bt < dt) { - var shift = dl - dt, dend = Math.min(dt, end); - if (shift + bt < 0) - err(3); - for (; bt < dend; ++bt) - buf[bt] = dict[shift + bt]; - } - for (; bt < end; ++bt) - buf[bt] = buf[bt - dt]; - } - } - st.l = lm, st.p = lpos, st.b = bt, st.f = final; - if (lm) - final = 1, st.m = lbt, st.d = dm, st.n = dbt; - } while (!final); - return bt != buf.length && noBuf ? slc(buf, 0, bt) : buf.subarray(0, bt); - }; - var et = /* @__PURE__ */ new u8(0); - var b2 = function(d, b) { - return d[b] | d[b + 1] << 8; - }; - var b4 = function(d, b) { - return (d[b] | d[b + 1] << 8 | d[b + 2] << 16 | d[b + 3] << 24) >>> 0; - }; - var b8 = function(d, b) { - return b4(d, b) + b4(d, b + 4) * 4294967296; - }; - function inflateSync(data, opts) { - return inflt(data, { i: 2 }, opts && opts.out, opts && opts.dictionary); - } - var td = typeof TextDecoder != "undefined" && /* @__PURE__ */ new TextDecoder(); - var tds = 0; - try { - td.decode(et, { stream: true }); - tds = 1; - } catch (e) { - } - var dutf8 = function(d) { - for (var r = "", i = 0; ; ) { - var c = d[i++]; - var eb = (c > 127) + (c > 223) + (c > 239); - if (i + eb > d.length) - return { s: r, r: slc(d, i - 1) }; - if (!eb) - r += String.fromCharCode(c); - else if (eb == 3) { - c = ((c & 15) << 18 | (d[i++] & 63) << 12 | (d[i++] & 63) << 6 | d[i++] & 63) - 65536, r += String.fromCharCode(55296 | c >> 10, 56320 | c & 1023); - } else if (eb & 1) - r += String.fromCharCode((c & 31) << 6 | d[i++] & 63); - else - r += String.fromCharCode((c & 15) << 12 | (d[i++] & 63) << 6 | d[i++] & 63); - } - }; - function strFromU8(dat, latin1) { - if (latin1) { - var r = ""; - for (var i = 0; i < dat.length; i += 16384) - r += String.fromCharCode.apply(null, dat.subarray(i, i + 16384)); - return r; - } else if (td) { - return td.decode(dat); - } else { - var _a2 = dutf8(dat), s = _a2.s, r = _a2.r; - if (r.length) - err(8); - return s; - } - } - var slzh = function(d, b) { - return b + 30 + b2(d, b + 26) + b2(d, b + 28); - }; - var zh = function(d, b, z) { - var fnl = b2(d, b + 28), efl = b2(d, b + 30), fn = strFromU8(d.subarray(b + 46, b + 46 + fnl), !(b2(d, b + 8) & 2048)), es = b + 46 + fnl; - var _a2 = z64hs(d, es, efl, z, b4(d, b + 20), b4(d, b + 24), b4(d, b + 42)), sc = _a2[0], su = _a2[1], off = _a2[2]; - return [b2(d, b + 10), sc, su, fn, es + efl + b2(d, b + 32), off]; - }; - var z64hs = function(d, b, l, z, sc, su, off) { - var nsc = sc == 4294967295, nsu = su == 4294967295, noff = off == 4294967295, e = b + l; - var nf = nsc + nsu + noff; - if (z && nf) { - for (; b + 4 < e; b += 4 + b2(d, b + 2)) { - if (b2(d, b) == 1) { - return [ - nsc ? b8(d, b + 4 + 8 * nsu) : sc, - nsu ? b8(d, b + 4) : su, - noff ? b8(d, b + 4 + 8 * (nsu + nsc)) : off, - 1 - ]; - } - } - if (z < 2) - err(13); - } - return [sc, su, off, 0]; - }; - function unzipSync(data, opts) { - var files = {}; - var e = data.length - 22; - for (; b4(data, e) != 101010256; --e) { - if (!e || data.length - e > 65558) - err(13); - } - ; - var c = b2(data, e + 8); - if (!c) - return {}; - var o = b4(data, e + 16); - var z = b4(data, e - 20) == 117853008; - if (z) { - var ze = b4(data, e - 12); - z = b4(data, ze) == 101075792; - if (z) { - c = b4(data, ze + 32); - o = b4(data, ze + 48); - } - } - var fltr = opts && opts.filter; - for (var i = 0; i < c; ++i) { - var _a2 = zh(data, o, z), c_2 = _a2[0], sc = _a2[1], su = _a2[2], fn = _a2[3], no = _a2[4], off = _a2[5], b = slzh(data, off); - o = no; - if (!fltr || fltr({ - name: fn, - size: sc, - originalSize: su, - compression: c_2 - })) { - if (!c_2) - files[fn] = slc(data, b, b + sc); - else if (c_2 == 8) - files[fn] = inflateSync(data.subarray(b, b + sc), { out: new u8(su) }); - else - err(14, "unknown compression type " + c_2); - } - } - return files; - } - - // upload/frontend/table/rebase_tree.js - function rebaseTree(root, prefix) { - root.path = `${prefix}/${root.path}`; - if (root.file) root.file = new File([root.file], root.file.name, { lastModified: root.file.lastModified }); - root.children.forEach((child) => rebaseTree(child, prefix)); - return root; - } - - // upload/frontend/zip/list_zip_files.js - var DEFAULT_LIMITS = { - maxEntries: 1e3, - maxTotalBytes: 100 * 1024 * 1024, - maxEntryBytes: 50 * 1024 * 1024, - maxDepth: 20 - }; - function extensionAllowed(name, allowedExt) { - const lowerName = name.toLowerCase(); - return allowedExt.some((extension) => lowerName.endsWith(extension.toLowerCase())); - } - function makeFile(data, name) { - return new File([data], name.split("/").at(-1)); - } - function safeEntryParts(entryName) { - if (!entryName || entryName.startsWith("/") || entryName.includes("\\")) return null; - const parts = entryName.split("/"); - if (parts.some((part) => !part || part === "." || part === "..")) return null; - return parts; - } - function node(kind, name, path, children = [], file = null) { - return { id: crypto.randomUUID(), kind, name, path, children, file, expanded: kind === "file" }; - } - function addPath(root, parts, fileNode) { - let current = root; - parts.forEach((part, index) => { - const last = index === parts.length - 1; - let child = current.children.find((item) => item.name === part); - if (!child) { - child = last ? fileNode : node("folder", part, `${current.path}/${part}`); - current.children.push(child); - } - current = child; - }); - } - async function listEntries(data, zipName, allowedExt, depth, limits, budget) { - if (depth > limits.maxDepth) throw new Error("\u0421\u043B\u0438\u0448\u043A\u043E\u043C \u0433\u043B\u0443\u0431\u043E\u043A\u0430\u044F \u0432\u043B\u043E\u0436\u0435\u043D\u043D\u043E\u0441\u0442\u044C ZIP"); - const entries = unzipSync(data, { - filter: (entry) => { - budget.entries += 1; - if (budget.entries > limits.maxEntries) throw new Error("\u0421\u043B\u0438\u0448\u043A\u043E\u043C \u043C\u043D\u043E\u0433\u043E ZIP entries"); - const lowerName = entry.name.toLowerCase(); - if (!extensionAllowed(lowerName, allowedExt) && !lowerName.endsWith(".zip")) return false; - if (entry.originalSize > limits.maxEntryBytes) return false; - if (budget.totalBytes + entry.originalSize > limits.maxTotalBytes) { - throw new Error("\u041F\u0440\u0435\u0432\u044B\u0448\u0435\u043D \u0441\u0443\u043C\u043C\u0430\u0440\u043D\u044B\u0439 \u0440\u0430\u0437\u043C\u0435\u0440 \u0440\u0430\u0441\u043F\u0430\u043A\u043E\u0432\u0430\u043D\u043D\u044B\u0445 ZIP entries"); - } - budget.totalBytes += entry.originalSize; - return true; - } - }); - const root = node("zip", zipName, zipName); - for (const [entryName, entryData] of Object.entries(entries)) { - if (entryName.endsWith("/")) continue; - const parts = safeEntryParts(entryName); - if (!parts) continue; - const normalizedName = parts.join("/"); - if (normalizedName.toLowerCase().endsWith(".zip")) { - const nested = await listEntries(entryData, entryName, allowedExt, depth + 1, limits, budget); - if (nested) { - rebaseTree(nested, zipName); - nested.name = parts.at(-1); - addPath(root, parts, nested); - } - } else if (extensionAllowed(normalizedName, allowedExt)) { - const path = `${zipName}/${normalizedName}`; - const file = makeFile(entryData, path); - addPath(root, parts, node("file", parts.at(-1), path, [], file)); - } - } - return root.children.length ? root : null; - } - async function listZipFiles(file, allowedExt, customLimits = {}) { - const data = new Uint8Array(await file.arrayBuffer()); - const limits = { ...DEFAULT_LIMITS, ...customLimits }; - return listEntries(data, file.name, allowedExt, 0, limits, { entries: 0, totalBytes: 0 }); - } - - // upload/frontend/table/add_file_with_dedup.js - function addFileWithDedup(state, fileNode) { - const accept = (node2) => { - if (node2.kind === "file") { - const key = `${node2.path}\0${node2.file.size}`; - if (state.fileKeys.has(key)) return null; - state.fileKeys.add(key); - return node2; - } - node2.children = node2.children.map(accept).filter(Boolean); - return node2.children.length ? node2 : null; - }; - const accepted = accept(fileNode); - if (!accepted || accepted.kind !== "file" && !accepted.children.length) return false; - if (accepted.kind !== "file") { - const existing = state.nodes.find((node2) => node2.kind !== "file" && node2.path === accepted.path); - if (existing) { - mergeChildren(existing, accepted); - return true; - } - } - state.nodes.push(accepted); - return true; - } - function mergeChildren(target, incoming) { - incoming.children.forEach((child) => { - if (child.kind === "file") { - const duplicate = target.children.some((existing2) => existing2.kind === "file" && existing2.path === child.path && existing2.file.size === child.file.size); - if (!duplicate) target.children.push(child); - return; - } - const existing = target.children.find((candidate) => candidate.kind !== "file" && candidate.path === child.path); - if (existing) mergeChildren(existing, child); - else target.children.push(child); - }); - } - - // upload/frontend/table/esc.js - function esc(value) { - return String(value).replace(/[&<>"']/g, (character) => ({ - "&": "&", - "<": "<", - ">": ">", - '"': """, - "'": "'" - })[character]); - } - - // upload/frontend/table/fs.js - function fs(bytes) { - return bytes < 1024 ? `${bytes} B` : bytes < 1048576 ? `${(bytes / 1024).toFixed(1)} KB` : `${(bytes / 1048576).toFixed(1)} MB`; - } - - // upload/frontend/table/render.js - var DEFAULT_RENDER_CONFIG = { - labels: { - statusReady: "\u0433\u043E\u0442\u043E\u0432", - remove: "\u0423\u0434\u0430\u043B\u0438\u0442\u044C", - empty: "\u041D\u0435\u0442 \u0432\u044B\u0431\u0440\u0430\u043D\u043D\u044B\u0445 \u0444\u0430\u0439\u043B\u043E\u0432", - columns: { path: "\u041F\u0443\u0442\u044C", size: "\u0420\u0430\u0437\u043C\u0435\u0440", status: "\u0421\u0442\u0430\u0442\u0443\u0441" }, - count: (count, bytes) => `${count} \u0444\u0430\u0439\u043B\u043E\u0432 \xB7 ${fs(bytes)}` - }, - layout: { columns: ["path", "size", "status"] } - }; - function renderConfig(cfg = {}) { - return { - labels: { - ...DEFAULT_RENDER_CONFIG.labels, - ...cfg.labels || {}, - columns: { - ...DEFAULT_RENDER_CONFIG.labels.columns, - ...cfg.labels?.columns || {} - } - }, - layout: { ...DEFAULT_RENDER_CONFIG.layout, ...cfg.layout || {} } - }; - } - function renderNode(node2, depth, cfg) { - const isGroup = node2.kind !== "file"; - const padding = depth * 4; - const name = esc(node2.name); - const action = isGroup ? `` : `${name}`; - const remove = ``; - const pathAttribute = node2.kind === "file" ? ` data-path="${esc(node2.path)}"` : ""; - const cells = { - path: action, - size: node2.kind === "file" ? fs(node2.file.size) : "", - status: node2.error ? esc(node2.error) : node2.kind === "file" ? esc(cfg.labels.statusReady) : "" - }; - const columns = cfg.layout.columns?.length ? cfg.layout.columns : Object.keys(DEFAULT_RENDER_CONFIG.labels.columns); - const row = `` + columns.map((column) => `${cells[column] || ""}`).join("") + `${remove}`; - if (!isGroup || !node2.expanded) return row; - return row + node2.children.map((child) => renderNode(child, depth + 1, cfg)).join(""); - } - function render(state, elements, cfg) { - const normalized = renderConfig(cfg); - const columns = normalized.layout.columns?.length ? normalized.layout.columns : Object.keys(DEFAULT_RENDER_CONFIG.labels.columns); - elements.tableBodyEl.innerHTML = state.nodes.length ? state.nodes.map((node2) => renderNode(node2, 0, normalized)).join("") : `${esc(normalized.labels.empty)}`; - const files = []; - const visit = (node2) => { - if (node2.kind === "file") files.push(node2); - else node2.children.forEach(visit); - }; - state.nodes.forEach(visit); - const totalBytes = files.reduce((sum, node2) => sum + node2.file.size, 0); - elements.countEl.textContent = normalized.labels.count(files.length, totalBytes); - } - function findNode(nodes, id) { - for (const node2 of nodes) { - if (node2.id === id) return { node: node2, nodes }; - const found = findNode(node2.children || [], id); - if (found) return found; - } - return null; - } - function flattenFiles(nodes, result = []) { - nodes.forEach((node2) => { - if (node2.kind === "file") result.push({ path: node2.path, name: node2.name, size: node2.file.size, file: node2.file }); - else flattenFiles(node2.children, result); - }); - return result; - } - - // upload/frontend/table/on_files_change.js - async function addFiles(state, cfg, files, elements) { - for (const file of Array.from(files)) { - if (!file.name.toLowerCase().endsWith(".zip")) { - if (!cfg.allowedExt.some((extension) => file.name.toLowerCase().endsWith(extension.toLowerCase()))) { - continue; - } - addFileWithDedup(state, { - id: crypto.randomUUID(), - kind: "file", - name: file.name, - path: file.name, - file, - children: [], - expanded: true - }); - continue; - } - try { - const zipTree = await listZipFiles(file, cfg.allowedExt, cfg.limits); - if (zipTree) addFileWithDedup(state, zipTree); - } catch (error) { - if (typeof cfg.onError === "function") { - cfg.onError(error, file); - } else if (elements.statusEl) { - elements.statusEl.textContent = `\u041E\u0448\u0438\u0431\u043A\u0430 \u0447\u0442\u0435\u043D\u0438\u044F \u0430\u0440\u0445\u0438\u0432\u0430 ${file.name}: ${error.message}`; - } - continue; - } - } - render(state, elements, cfg); - } - function onFilesChange(state, cfg, elements) { - return async () => { - if (state.busy) return; - state.busy = true; - try { - await addFiles(state, cfg, elements.fileInputEl.files, elements); - } finally { - elements.fileInputEl.value = ""; - state.busy = false; - } - }; - } - - // upload/frontend/table/on_folder_change.js - function onFolderChange(state, cfg, elements) { - return async () => { - if (state.busy) return; - state.busy = true; - try { - const roots = /* @__PURE__ */ new Map(); - for (const file of Array.from(elements.folderInputEl.files)) { - const parts = (file.webkitRelativePath || file.name).split("/"); - const relativePath = parts.slice(1).join("/") || file.name; - const lowerPath = relativePath.toLowerCase(); - const rootName = parts[0] || file.name; - if (!roots.has(rootName)) { - roots.set(rootName, { - id: crypto.randomUUID(), - kind: "folder", - name: rootName, - path: rootName, - children: [], - expanded: false - }); - } - const root = roots.get(rootName); - const addToFolder = (node2) => { - let current = root; - const nodeParts = node2.path.split("/").slice(1); - nodeParts.forEach((part, index) => { - const last = index === nodeParts.length - 1; - let child = current.children.find((item) => item.name === part); - if (!child) { - child = last ? node2 : { - id: crypto.randomUUID(), - kind: "folder", - name: part, - path: `${rootName}/${nodeParts.slice(0, index + 1).join("/")}`, - children: [], - expanded: false - }; - current.children.push(child); - } - current = child; - }); - }; - if (lowerPath.endsWith(".zip")) { - try { - const zip = await listZipFiles(file, cfg.allowedExt, cfg.limits); - if (zip) { - rebaseTree(zip, rootName); - addToFolder(zip); - } - } catch (error) { - if (typeof cfg.onError === "function") { - cfg.onError(error, file); - } else if (elements.statusEl) { - elements.statusEl.textContent = `\u041E\u0448\u0438\u0431\u043A\u0430 \u0447\u0442\u0435\u043D\u0438\u044F \u0430\u0440\u0445\u0438\u0432\u0430 ${file.name}: ${error.message}`; - } - continue; - } - } else if (cfg.allowedExt.some((extension) => lowerPath.endsWith(extension))) { - addToFolder({ - id: crypto.randomUUID(), - kind: "file", - name: parts.at(-1), - path: `${rootName}/${relativePath}`, - file, - children: [], - expanded: true - }); - } - } - roots.forEach((root) => addFileWithDedup(state, root)); - elements.folderInputEl.value = ""; - render(state, elements, cfg); - } finally { - state.busy = false; - } - }; - } - - // upload/frontend/upload/put_to_vm.js - function putToVm(file, url, options = {}) { - return new Promise((resolve, reject) => { - const xhr = new XMLHttpRequest(); - if (options.onXHR) { - options.onXHR(xhr); - } - const abortHandler = () => { - xhr.abort(); - reject(new DOMException("Upload aborted", "AbortError")); - }; - if (options.signal) { - if (options.signal.aborted) { - reject(new DOMException("Upload aborted", "AbortError")); - return; - } - options.signal.addEventListener("abort", abortHandler, { once: true }); - } - xhr.open("PUT", url); - xhr.timeout = options.timeoutMs || 3e5; - xhr.upload.onprogress = (e) => { - if (e.lengthComputable && options.onProgress) { - const pct = Math.round(e.loaded / e.total * 100); - options.onProgress(pct, e.loaded, e.total); - } - }; - xhr.onload = () => { - if (options.signal) { - options.signal.removeEventListener("abort", abortHandler); - } - if (xhr.status >= 200 && xhr.status < 300) { - resolve(); - } else { - reject(new Error(`\u0411\u0443\u0444\u0435\u0440: HTTP ${xhr.status} ${xhr.statusText}`)); - } - }; - xhr.onerror = () => { - if (options.signal) { - options.signal.removeEventListener("abort", abortHandler); - } - reject(new Error("\u0421\u0435\u0442\u0435\u0432\u0430\u044F \u043E\u0448\u0438\u0431\u043A\u0430 \u043F\u0440\u0438 \u043E\u0442\u043F\u0440\u0430\u0432\u043A\u0435 \u0432 \u0431\u0443\u0444\u0435\u0440")); - }; - xhr.ontimeout = () => { - if (options.signal) { - options.signal.removeEventListener("abort", abortHandler); - } - reject(new Error(`\u0422\u0430\u0439\u043C\u0430\u0443\u0442 \u043E\u0436\u0438\u0434\u0430\u043D\u0438\u044F \u043E\u0442\u0432\u0435\u0442\u0430 \u0431\u0443\u0444\u0435\u0440\u0430 (${Math.round(xhr.timeout / 1e3)}\u0441)`)); - }; - xhr.onabort = () => { - if (options.signal) { - options.signal.removeEventListener("abort", abortHandler); - } - reject(new DOMException("Upload aborted", "AbortError")); - }; - xhr.send(file); - }); - } - - // upload/frontend/upload/upload_via_vm.js - function generateUuid() { - if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") { - return crypto.randomUUID(); - } - return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => { - const r = Math.random() * 16 | 0; - const v = c === "x" ? r : r & 3 | 8; - return v.toString(16); - }); - } - function normalizeFileEntry(item) { - if (item instanceof File || item instanceof Blob) { - return { name: item.name || "unnamed", size: item.size, file: item, path: item.name || "" }; - } - if (item && item.file) { - return { - name: item.name || item.file.name || "unnamed", - size: item.size ?? item.file.size ?? 0, - file: item.file, - path: item.path || item.name || "" - }; - } - throw new Error("\u041D\u0435\u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u044B\u0439 \u043E\u0431\u044A\u0435\u043A\u0442 \u0444\u0430\u0439\u043B\u0430"); - } - async function uploadViaVM(files, options = {}) { - if (!options.vmUploadUrl) { - return { ok: false, error: "\u041F\u0430\u0440\u0430\u043C\u0435\u0442\u0440 options.vmUploadUrl \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u0435\u043D" }; - } - const normalizedFiles = Array.from(files).map(normalizeFileEntry); - const total = normalizedFiles.length; - if (total === 0) { - return { ok: true, session: options.session || "", count: 0 }; - } - const backendUrl = options.backendUploadUrl || (options.apiBase || "") + "/api/upload_refs"; - const vmBase = options.vmUploadUrl.endsWith("/") ? options.vmUploadUrl : `${options.vmUploadUrl}/`; - let currentSession = options.session || ""; - let totalAdded = 0; - for (let k = 0; k < total; k++) { - if (options.signal?.aborted) { - return { ok: false, error: "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u043E\u0442\u043C\u0435\u043D\u0435\u043D\u0430", aborted: true, session: currentSession }; - } - const { name, size, file } = normalizedFiles[k]; - const fileKey = `${generateUuid()}_${k}`; - const fileUrl = `${vmBase}${fileKey}`; - if (options.onStatus) { - options.onStatus(`\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u0432 \u0431\u0443\u0444\u0435\u0440 (${k + 1}/${total}): ${name}`); - } - if (options.onFileStatus) { - options.onFileStatus(k, "\u23F3 \u0412 \u0431\u0443\u0444\u0435\u0440..."); - } - const t0 = performance.now(); - try { - await putToVm(file, fileUrl, { - signal: options.signal, - onXHR: options.onXHR, - onProgress(pct, loaded, fileTotal) { - const elapsed = (performance.now() - t0) / 1e3; - const speed = elapsed > 0 ? loaded / elapsed : 0; - if (options.onFileStatus) { - options.onFileStatus(k, `\u23F3 ${pct}% (${fs(speed)}/s)`); - } - if (options.onProgress) { - options.onProgress({ index: k, total, pct, speed, loaded, fileTotal, name }); - } - } - }); - } catch (err2) { - if (options.signal?.aborted) { - return { ok: false, error: "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u043E\u0442\u043C\u0435\u043D\u0435\u043D\u0430", aborted: true, session: currentSession }; - } - if (options.onFileStatus) { - options.onFileStatus(k, "\u2717 \u041E\u0448\u0438\u0431\u043A\u0430 \u0431\u0443\u0444\u0435\u0440\u0430"); - } - return { - ok: false, - error: `\u041E\u0448\u0438\u0431\u043A\u0430 \u043E\u0442\u043F\u0440\u0430\u0432\u043A\u0438 \u0444\u0430\u0439\u043B\u0430 ${name} \u0432 \u0431\u0443\u0444\u0435\u0440: ${err2.message}`, - failedIndex: k, - session: currentSession - }; - } - if (options.onStatus) { - options.onStatus(`\u041F\u0440\u0438\u0451\u043C \u0441\u0435\u0440\u0432\u0438\u0441\u043E\u043C (${k + 1}/${total}): ${name}`); - } - if (options.onFileStatus) { - options.onFileStatus(k, "\u26A1 \u0412 \u0441\u0435\u0441\u0441\u0438\u044E..."); - } - try { - const resp = await fetch(backendUrl, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - session: currentSession, - files: [{ name, size, url: fileUrl }] - }), - signal: options.signal - }); - if (!resp.ok) { - throw new Error(`HTTP ${resp.status} ${resp.statusText}`); - } - const data = await resp.json(); - if (!data.ok) { - throw new Error(data.error || "\u0411\u044D\u043A\u0435\u043D\u0434 \u0432\u0435\u0440\u043D\u0443\u043B \u043E\u0448\u0438\u0431\u043A\u0443"); - } - currentSession = data.session || currentSession; - totalAdded = data.count ?? totalAdded + 1; - if (options.onFileStatus) { - options.onFileStatus(k, "\u2713 \u0414\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D"); - } - if (options.onFileComplete) { - options.onFileComplete({ - fileIndex: k, - name, - size, - session: currentSession, - totalAdded - }); - } - } catch (err2) { - if (options.signal?.aborted) { - return { ok: false, error: "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u043E\u0442\u043C\u0435\u043D\u0435\u043D\u0430", aborted: true, session: currentSession }; - } - if (options.onFileStatus) { - options.onFileStatus(k, "\u2717 \u041E\u0448\u0438\u0431\u043A\u0430 \u043F\u0440\u0438\u0451\u043C\u0430"); - } - return { - ok: false, - error: `\u041E\u0448\u0438\u0431\u043A\u0430 \u043F\u0440\u0438\u0451\u043C\u0430 \u0444\u0430\u0439\u043B\u0430 ${name} \u0431\u044D\u043A\u0435\u043D\u0434\u043E\u043C: ${err2.message}`, - failedIndex: k, - session: currentSession - }; - } - } - if (options.onStatus) { - options.onStatus(`\u0417\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u043E. \u0423\u0441\u043F\u0435\u0448\u043D\u043E \u043F\u0435\u0440\u0435\u0434\u0430\u043D\u043E \u0444\u0430\u0439\u043B\u043E\u0432: ${total}`); - } - return { ok: true, session: currentSession, count: totalAdded }; - } - - // upload/frontend/index.js - var DEFAULTS = { - allowedExt: [], - labels: { - pickFiles: "\u0412\u044B\u0431\u0440\u0430\u0442\u044C \u0444\u0430\u0439\u043B\u044B", - pickFolder: "\u0412\u044B\u0431\u0440\u0430\u0442\u044C \u043F\u0430\u043F\u043A\u0443", - clear: "\u041E\u0447\u0438\u0441\u0442\u0438\u0442\u044C", - empty: "\u041D\u0435\u0442 \u0432\u044B\u0431\u0440\u0430\u043D\u043D\u044B\u0445 \u0444\u0430\u0439\u043B\u043E\u0432", - statusReady: "\u0433\u043E\u0442\u043E\u0432", - remove: "\u0423\u0434\u0430\u043B\u0438\u0442\u044C", - columns: { path: "\u041F\u0443\u0442\u044C", size: "\u0420\u0430\u0437\u043C\u0435\u0440", status: "\u0421\u0442\u0430\u0442\u0443\u0441" }, - count: (count, bytes) => `${count} \u0444\u0430\u0439\u043B\u043E\u0432 \xB7 ${bytes} B` - }, - layout: { columns: ["path", "size", "status"], controls: ["files", "folder", "clear"] }, - limits: { - maxEntries: 1e3, - maxTotalBytes: 100 * 1024 * 1024, - maxEntryBytes: 50 * 1024 * 1024, - maxDepth: 20 - } - }; - function resolveMount(mount) { - const element = typeof mount === "string" ? document.querySelector(mount) : mount; - if (!element) throw new Error("File picker mount element \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D"); - return element; - } - function normalizeConfig(config) { - return { - ...config, - allowedExt: config.allowedExt || DEFAULTS.allowedExt, - labels: { - ...DEFAULTS.labels, - ...config.labels || {}, - columns: { ...DEFAULTS.labels.columns, ...config.labels?.columns || {} } - }, - layout: { ...DEFAULTS.layout, ...config.layout || {} }, - limits: { ...DEFAULTS.limits, ...config.limits || {} } - }; - } - function injectStyles() { - if (document.querySelector("style[data-file-picker]")) return; - const style = document.createElement("style"); - style.dataset.filePicker = ""; - style.textContent = ` -.file-picker { color: #17211b; font-family: Georgia, 'Times New Roman', serif; } -.file-picker .fp-toolbar { display: flex; flex-wrap: wrap; gap: 10px; margin: 16px 0; } -.file-picker .fp-toolbar button { border: 0; border-radius: 4px; padding: 12px 17px; color: #f7faf4; background: #1f5a3b; font: 700 13px sans-serif; cursor: pointer; } -.file-picker .fp-toolbar button.secondary { color: #1f5a3b; background: #cbdcc9; } -.file-picker .fp-toolbar button.quiet { color: #5d6a61; background: transparent; } -.file-picker .fp-table-wrap { overflow-x: auto; border-top: 1px solid #b9c7ba; } -.file-picker .fp-table { width: 100%; border-collapse: collapse; font: 14px/1.4 sans-serif; } -.file-picker .fp-table th, .file-picker .fp-table td { padding: 14px 10px; border-bottom: 1px solid #cbd5cc; text-align: left; } -.file-picker .fp-table th { color: #56745f; font-size: 11px; text-transform: uppercase; letter-spacing: 1px; } -.file-picker .fp-status, .file-picker .fp-count { color: #5d6a61; font: 13px sans-serif; } -.file-picker .fp-count { min-height: 22px; } -.file-picker .tree-name { display: inline-flex; align-items: center; gap: 8px; min-width: 240px; padding-top: 0; padding-bottom: 0; border: 0; background: transparent; color: #17211b; font: inherit; text-align: left; } -.file-picker .tree-group { padding-left: 0; cursor: pointer; } -.file-picker .tree-chevron { display: inline-block; width: 12px; color: #78917d; font-size: 10px; } -.file-picker .remove-btn { padding: 2px 7px; color: #8c5148; background: transparent; font: 20px/1 sans-serif; } -.file-picker .tree-row td:first-child { white-space: nowrap; } -@media (max-width: 600px) { .file-picker .fp-toolbar button { flex: 1 1 42%; } } -`; - document.head.append(style); - } - function buildMarkup(root, cfg) { - const controls = cfg.layout.controls || []; - const control = (name, id, label, className = "") => controls.includes(name) ? `` : ""; - const columns = cfg.layout.columns?.length ? cfg.layout.columns : Object.keys(cfg.labels.columns); - const headings = columns.map((column) => `${esc(cfg.labels.columns[column] || column)}`).join(""); - root.innerHTML = ` -
-
- - - ${control("files", "fp-files-btn", cfg.labels.pickFiles)} - ${control("folder", "fp-folder-btn", cfg.labels.pickFolder, "secondary")} - ${control("clear", "fp-clear-btn", cfg.labels.clear, "quiet")} -
-

-
${headings}
-

-
`; - } - function notify(cfg, state) { - if (typeof cfg.onChange === "function") cfg.onChange([...flattenFiles(state.nodes)]); - } - function removeMetadata(state, node2) { - if (node2.kind === "file") { - state.fileKeys.delete(`${node2.path}\0${node2.file.size}`); - return; - } - node2.children.forEach((child) => removeMetadata(state, child)); - } - function removeNode(state, id) { - const found = findNode(state.nodes, id); - if (!found) return false; - removeMetadata(state, found.node); - found.nodes.splice(found.nodes.indexOf(found.node), 1); - return true; - } - function initFilePicker(config) { - const cfg = normalizeConfig(config); - const mount = resolveMount(cfg.mount); - injectStyles(); - buildMarkup(mount, cfg); - const root = mount.firstElementChild; - const elements = { - fileInputEl: root.querySelector(".fp-file-input"), - folderInputEl: root.querySelector(".fp-folder-input"), - statusEl: root.querySelector(".fp-status"), - tableBodyEl: root.querySelector(".fp-table-body"), - countEl: root.querySelector(".fp-count") - }; - const state = { nodes: [], fileKeys: /* @__PURE__ */ new Set(), busy: false }; - const listeners = []; - const listen = (target, event, handler) => { - target.addEventListener(event, handler); - listeners.push(() => target.removeEventListener(event, handler)); - }; - const redraw = () => render(state, elements, cfg); - const filesChange = onFilesChange(state, cfg, elements); - const folderChange = onFolderChange(state, cfg, elements); - listen(elements.fileInputEl, "change", async () => { - await filesChange(); - notify(cfg, state); - }); - listen(elements.folderInputEl, "change", async () => { - await folderChange(); - notify(cfg, state); - }); - listen(elements.tableBodyEl, "click", (event) => { - const toggle = event.target.closest("[data-toggle]"); - if (toggle) { - const found = findNode(state.nodes, toggle.dataset.toggle); - if (found) found.node.expanded = !found.node.expanded; - redraw(); - return; - } - const remove = event.target.closest("[data-remove]"); - if (remove) { - if (removeNode(state, remove.dataset.remove)) { - redraw(); - notify(cfg, state); - } - } - }); - if (root.querySelector("#fp-files-btn")) listen(root.querySelector("#fp-files-btn"), "click", () => elements.fileInputEl.click()); - if (root.querySelector("#fp-folder-btn")) listen(root.querySelector("#fp-folder-btn"), "click", () => elements.folderInputEl.click()); - if (root.querySelector("#fp-clear-btn")) listen(root.querySelector("#fp-clear-btn"), "click", () => { - state.nodes = []; - state.fileKeys.clear(); - redraw(); - notify(cfg, state); - }); - redraw(); - return { - pickFiles: () => elements.fileInputEl.click(), - pickFolder: () => elements.folderInputEl.click(), - addFiles: async (files) => { - await addFiles(state, cfg, files, elements); - notify(cfg, state); - }, - getFiles: () => [...flattenFiles(state.nodes)], - remove: (id) => { - if (removeNode(state, id)) { - redraw(); - notify(cfg, state); - } - }, - clear: () => { - state.nodes = []; - state.fileKeys.clear(); - redraw(); - notify(cfg, state); - }, - render: redraw, - destroy: () => { - listeners.forEach((removeListener) => removeListener()); - state.nodes = []; - state.fileKeys.clear(); - mount.replaceChildren(); - } - }; - } - return __toCommonJS(index_exports); -})();