/* wloc.js - Build 2026-06-25 10:20:48 */ // 环境检测函数 const detectEnvironment = (() => { const hasGlobal = (key) => key in globalThis; switch (true) { case hasGlobal("$task"): return "Quantumult X"; case hasGlobal("$loon"): return "Loon"; case hasGlobal("$rocket"): return "Shadowrocket"; case hasGlobal("Egern"): return "Egern"; case Boolean(globalThis.$environment?.["surge-version"]): return "Surge"; case Boolean(globalThis.$environment?.["stash-version"]): return "Stash"; case hasGlobal("Cloudflare"): return "Worker"; case Boolean(globalThis.process?.versions?.node): return "Node.js"; default: return undefined; } })(); // 日志工具类 class Logger { static #counters = new Map([]); static #groups = []; static #timers = new Map([]); static #logLevel = 3; // INFO 默认级别 static clear = () => { }; static count = (name = "default") => { if (Logger.#counters.has(name)) { Logger.#counters.set(name, Logger.#counters.get(name) + 1); } else { Logger.#counters.set(name, 0); } Logger.log(`${name}: ${Logger.#counters.get(name)}`); }; static countReset = (name = "default") => { if (Logger.#counters.has(name)) { Logger.#counters.set(name, 0); Logger.log(`${name}: ${Logger.#counters.get(name)}`); } else { Logger.warn(`Counter "${name}" doesn't exist`); } }; static debug = (...args) => { if (Logger.#logLevel < 4) return; const formatted = args.map(arg => ` ${arg}`); Logger.log(...formatted); }; static error = (...args) => { if (Logger.#logLevel < 1) return; let formatted; switch (detectEnvironment) { case "Surge": case "Loon": case "Stash": case "Egern": case "Shadowrocket": case "Quantumult X": default: formatted = args.map(arg => ` ${arg}`); break; case "Worker": case "Node.js": formatted = args.map(arg => ` ${arg?.stack ?? arg}`); break; } Logger.log(...formatted); }; static exception = (...args) => Logger.error(...args); static group = (name) => Logger.#groups.unshift(name); static groupEnd = () => Logger.#groups.shift(); static info = (...args) => { if (Logger.#logLevel < 3) return; const formatted = args.map(arg => ` ${arg}`); Logger.log(...formatted); }; static get logLevel() { switch (Logger.#logLevel) { case 0: return "OFF"; case 1: return "ERROR"; case 2: return "WARN"; case 3: default: return "INFO"; case 4: return "DEBUG"; case 5: return "ALL"; } } static set logLevel(level) { let normalized; switch (typeof level) { case "string": normalized = level.toLowerCase(); break; case "number": normalized = level; break; default: normalized = "warn"; } switch (normalized) { case 0: case "off": Logger.#logLevel = 0; break; case 1: case "error": Logger.#logLevel = 1; break; case 2: case "warn": case "warning": default: Logger.#logLevel = 2; break; case 3: case "info": Logger.#logLevel = 3; break; case 4: case "debug": Logger.#logLevel = 4; break; case 5: case "all": Logger.#logLevel = 5; break; } } static log = (...args) => { if (Logger.#logLevel === 0) return; const formatted = args.flatMap(arg => { switch (typeof arg) { case "object": return [JSON.stringify(arg)]; case "bigint": case "number": case "boolean": return [arg.toString()]; case "string": return arg.split(/\r?\n/u); default: return [arg]; } }); Logger.#groups.forEach(group => { formatted.unshift(` ${group}:`); formatted.forEach((line, index) => { formatted[index] = ` ${line}`; }); }); formatted.unshift(""); console.log(formatted.join("\n")); }; static time = (name = "default") => { Logger.#timers.set(name, Date.now()); }; static timeEnd = (name = "default") => { Logger.#timers.delete(name); }; static timeLog = (name = "default") => { const startTime = Logger.#timers.get(name); if (startTime) { Logger.log(`${name}: ${Date.now() - startTime}ms`); } else { Logger.warn(`Timer "${name}" doesn't exist`); } }; static warn = (...args) => { if (Logger.#logLevel < 2) return; const formatted = args.map(arg => ` ${arg}`); Logger.log(...formatted); }; } // 工具类 class Utils { static escape(html) { const entities = { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }; return html.replace(/[&<>"']/g, char => entities[char]); } static get(obj = {}, path = "", defaultValue = undefined) { const pathArray = Array.isArray(path) ? path : Utils.toPath(path); const result = pathArray.reduce((current, key) => Object(current)[key], obj); return result === undefined ? defaultValue : result; } static merge(target, ...sources) { if (target == null) return target; for (const source of sources) { if (source == null) continue; for (const key of Object.keys(source)) { const sourceValue = source[key]; const targetValue = target[key]; switch (true) { case Utils.#isPlainObject(sourceValue) && Utils.#isPlainObject(targetValue): target[key] = Utils.merge(targetValue, sourceValue); break; case sourceValue instanceof Map && targetValue instanceof Map: if (sourceValue.size > 0) { for (const [k, v] of sourceValue) { targetValue.set(k, v); } } break; case sourceValue instanceof Set && targetValue instanceof Set: if (sourceValue.size > 0) { for (const value of sourceValue) { targetValue.add(value); } } break; case Array.isArray(sourceValue) && sourceValue.length === 0 && targetValue !== undefined: case sourceValue instanceof Map && sourceValue.size === 0 && targetValue !== undefined: case sourceValue instanceof Set && sourceValue.size === 0 && targetValue !== undefined: break; case sourceValue !== undefined: target[key] = sourceValue; } } } return target; } static #isPlainObject(value) { if (value === null || typeof value !== "object") return false; const proto = Object.getPrototypeOf(value); return proto === null || proto === Object.prototype; } static omit(obj = {}, keys = []) { const keysArray = Array.isArray(keys) ? keys : [keys.toString()]; keysArray.forEach(key => Utils.unset(obj, key)); return obj; } static pick(obj = {}, keys = []) { const keysArray = Array.isArray(keys) ? keys : [keys.toString()]; const entries = Object.entries(obj).filter(([key]) => keysArray.includes(key)); return Object.fromEntries(entries); } static set(obj, path, value) { const pathArray = Array.isArray(path) ? path : Utils.toPath(path); const lastKey = pathArray[pathArray.length - 1]; const target = pathArray.slice(0, -1).reduce((current, key, index) => { if (Object(current[key]) === current[key]) { return current[key]; } const nextKey = pathArray[index + 1]; return current[key] = /^\d+$/.test(nextKey) ? [] : {}; }, obj); target[lastKey] = value; return obj; } static toPath(path) { return path.replace(/$$(\d+)$$/g, ".$1").split(".").filter(Boolean); } static unescape(html) { const entities = { "&": "&", "<": "<", ">": ">", """: '"', "'": "'" }; return html.replace(/&|<|>|"|'/g, entity => entities[entity]); } static unset(obj = {}, path = "") { const pathArray = Array.isArray(path) ? path : Utils.toPath(path); return pathArray.reduce((current, key, index) => { if (index === pathArray.length - 1) { delete current[key]; return true; } return Object(current)[key]; }, obj); } } // 参数解析类 class QueryParser { static parse(input) { let result = {}; switch (typeof input) { case "string": { const query = input.replace(/^\?/, ""); if (!query) break; const parsed = Object.fromEntries( query.split("&").filter(Boolean).map(param => { const [key = "", value = ""] = param.split("=", 2); return [ QueryParser.#decode(key).replace(/$$([^\[$$]+)\]/g, ".$1"), QueryParser.#decode(value).replace(/\"/g, "") ]; }) ); Object.keys(parsed).forEach(key => { Utils.set(result, key, parsed[key]); }); break; } case "object": if (input === null) break; const obj = {}; Object.keys(input).forEach(key => { Utils.set(obj, key, input[key]); }); result = obj; break; case "undefined": result = {}; } return result; } static stringify(obj = {}) { if (!obj || typeof obj !== "object") return ""; const pairs = []; Object.keys(obj).forEach(key => { QueryParser.#flatten(obj, key, pairs); }); if (pairs.length === 0) return ""; return pairs.map(([key, value]) => { return `${QueryParser.#encode(QueryParser.#toBracket(key))}=${QueryParser.#encode(value)}`; }).join("&"); } static #flatten(obj, path, result) { const value = Utils.get(obj, path); if (value === undefined) return; if (value !== null) { if (Array.isArray(value)) { value.forEach((item, index) => { if (item !== undefined) { QueryParser.#flatten(obj, `${path}[${index}]`, result); } }); } else if (QueryParser.#isPlainObject(value)) { Object.keys(value).forEach(key => { QueryParser.#flatten(obj, `${path}.${key}`, result); }); } else { result.push([path, String(value)]); } } else { result.push([path, ""]); } } static #toBracket(path) { const [first, ...rest] = Utils.toPath(path); return rest.reduce((result, segment) => { return /^\d+$/.test(segment) ? `${result}[${segment}]` : `${result}.${segment}`; }, first); } static #isPlainObject(value) { if (value === null || typeof value !== "object" || Array.isArray(value)) return false; const proto = Object.getPrototypeOf(value); return proto === null || proto === Object.prototype; } static #encode(str) { return encodeURIComponent(str); } static #decode(str) { return decodeURIComponent(str.replace(/\+/g, " ")); } } // 初始化参数解析 Logger.debug("$argument"); globalThis.$argument = QueryParser.parse(globalThis.$argument); if (globalThis.$argument.LogLevel) { Logger.logLevel = globalThis.$argument.LogLevel; } Logger.debug("$argument", `$argument: ${JSON.stringify(globalThis.$argument)}`); // HTTP状态码常量 const HTTP_STATUS = { 100: "Continue", 101: "Switching Protocols", 102: "Processing", 103: "Early Hints", 200: "OK", 201: "Created", 202: "Accepted", 203: "Non-Authoritative Information", 204: "No Content", 205: "Reset Content", 206: "Partial Content", 207: "Multi-Status", 208: "Already Reported", 226: "IM Used", 300: "Multiple Choices", 301: "Moved Permanently", 302: "Found", 304: "Not Modified", 307: "Temporary Redirect", 308: "Permanent Redirect", 400: "Bad Request", 401: "Unauthorized", 402: "Payment Required", 403: "Forbidden", 404: "Not Found", 405: "Method Not Allowed", 406: "Not Acceptable", 407: "Proxy Authentication Required", 408: "Request Timeout", 409: "Conflict", 410: "Gone", 411: "Length Required", 412: "Precondition Failed", 413: "Content Too Large", 414: "URI Too Long", 415: "Unsupported Media Type", 416: "Range Not Satisfiable", 417: "Expectation Failed", 418: "I'm a teapot", 421: "Misdirected Request", 422: "Unprocessable Entity", 423: "Locked", 424: "Failed Dependency", 425: "Too Early", 426: "Upgrade Required", 428: "Precondition Required", 429: "Too Many Requests", 431: "Request Header Fields Too Large", 451: "Unavailable For Legal Reasons", 500: "Internal Server Error", 501: "Not Implemented", 502: "Bad Gateway", 503: "Service Unavailable", 504: "Gateway Timeout", 505: "HTTP Version Not Supported", 506: "Variant Also Negotiates", 507: "Insufficient Storage", 508: "Loop Detected", 510: "Not Extended", 511: "Network Authentication Required" }; // 结束函数,处理不同环境 function finish(response = {}) { switch (detectEnvironment) { case "Surge": if (response.policy) { Utils.set(response, "headers.X-Surge-Policy", response.policy); } Logger.log("执行结束!", ` ${(new Date().getTime() / 1000 - $script.startTime)} 秒`); $done(response); break; case "Loon": if (response.policy) { response.node = response.policy; } Logger.log("执行结束!", ` ${(new Date() - $script.startTime) / 1000} 秒`); $done(response); break; case "Stash": if (response.policy) { Utils.set(response, "headers.X-Stash-Selected-Proxy", encodeURI(response.policy)); } Logger.log("执行结束!", ` ${(new Date() - $script.startTime) / 1000} 秒`); $done(response); break; case "Egern": case "Shadowrocket": Logger.log("执行结束!"); $done(response); break; case "Quantumult X": if (response.policy) { Utils.set(response, "opts.policy", response.policy); } const qxResponse = Utils.pick(response, ["status", "url", "headers", "body", "bodyBytes"]); switch (typeof qxResponse.status) { case "number": qxResponse.status = `HTTP/1.1 ${qxResponse.status} ${HTTP_STATUS[qxResponse.status]}`; break; case "string": case "undefined": break; default: throw new TypeError(`${Function.name}: 参数类型错误, status 必须为数字或字符串`); } if (qxResponse.body instanceof ArrayBuffer) { qxResponse.bodyBytes = qxResponse.body; qxResponse.body = undefined; } else if (ArrayBuffer.isView(qxResponse.body)) { qxResponse.bodyBytes = qxResponse.body.buffer.slice( qxResponse.body.byteOffset, qxResponse.body.byteLength + qxResponse.body.byteOffset ); qxResponse.body = undefined; } else if (qxResponse.body) { qxResponse.bodyBytes = undefined; } Logger.log("执行结束!"); $done(qxResponse); break; case "Worker": default: Logger.log("执行结束!"); break; case "Node.js": Logger.log("执行结束!"); process.exit(1); } } // 数据存储类 class Storage { static data = null; static dataFile = "box.dat"; static #keyPattern = /^@(?[^.]+)(?:\.(?.*))?$/; static getItem(key, defaultValue = null) { let value = defaultValue; if (key.startsWith("@")) { const { key: storageKey, path } = key.match(Storage.#keyPattern)?.groups || {}; key = storageKey; let storageData = Storage.getItem(key, {}); if (typeof storageData !== "object") { storageData = {}; } value = Utils.get(storageData, path); try { value = JSON.parse(value); } catch { } } else { switch (detectEnvironment) { case "Surge": case "Loon": case "Stash": case "Egern": case "Shadowrocket": value = $persistentStore.read(key); break; case "Quantumult X": value = $prefs.valueForKey(key); break; case "Worker": Storage.data = Storage.data ?? {}; value = Storage.data[key]; break; case "Node.js": Storage.data = Storage.#loadData(Storage.dataFile); value = Storage.data?.[key]; break; default: value = Storage.data?.[key] || null; } try { value = JSON.parse(value); } catch { } } return value ?? defaultValue; } static setItem(key = new String(), value = new String()) { let success = false; if (typeof value === "object") { value = JSON.stringify(value); } else { value = String(value); } if (key.startsWith("@")) { const { key: storageKey, path } = key.match(Storage.#keyPattern)?.groups || {}; key = storageKey; let storageData = Storage.getItem(key, {}); if (typeof storageData !== "object") { storageData = {}; } Utils.set(storageData, path, value); success = Storage.setItem(key, storageData); } else { switch (detectEnvironment) { case "Surge": case "Loon": case "Stash": case "Egern": case "Shadowrocket": success = $persistentStore.write(value, key); break; case "Quantumult X": success = $prefs.setValueForKey(value, key); break; case "Worker": Storage.data = Storage.data ?? {}; Storage.data[key] = value; success = true; break; case "Node.js": Storage.data = Storage.#loadData(Storage.dataFile); Storage.data[key] = value; Storage.#saveData(Storage.dataFile); success = true; break; default: success = Storage.data?.[key] || null; } } return success; } static removeItem(key) { let success = false; if (key.startsWith("@")) { const { key: storageKey, path } = key.match(Storage.#keyPattern)?.groups || {}; key = storageKey; let storageData = Storage.getItem(key); if (typeof storageData !== "object") { storageData = {}; } Utils.unset(storageData, path); success = Storage.setItem(key, storageData); } else { switch (detectEnvironment) { case "Surge": success = $persistentStore.write(null, key); break; case "Loon": case "Stash": case "Egern": case "Shadowrocket": default: success = false; break; case "Quantumult X": success = $prefs.removeValueForKey(key); break; case "Worker": Storage.data = Storage.data ?? {}; delete Storage.data[key]; success = true; break; case "Node.js": Storage.data = Storage.#loadData(Storage.dataFile); delete Storage.data[key]; Storage.#saveData(Storage.dataFile); success = true; break; } } return success; } static clear() { let success = false; switch (detectEnvironment) { case "Surge": case "Loon": case "Stash": case "Egern": case "Shadowrocket": default: success = false; break; case "Quantumult X": success = $prefs.removeAllValues(); break; case "Worker": Storage.data = {}; success = true; break; case "Node.js": Storage.data = Storage.#loadData(Storage.dataFile); Storage.data = {}; Storage.#saveData(Storage.dataFile); success = true; break; } return success; } static #loadData(filePath) { if (detectEnvironment !== "Node.js") return {}; this.fs = this.fs || require("fs"); this.path = this.path || require("path"); const absPath = this.path.resolve(filePath); const cwdPath = this.path.resolve(process.cwd(), filePath); const absExists = this.fs.existsSync(absPath); const cwdExists = !absExists && this.fs.existsSync(cwdPath); if (!absExists && !cwdExists) return {}; const targetPath = absExists ? absPath : cwdPath; try { return JSON.parse(this.fs.readFileSync(targetPath)); } catch (error) { return {}; } } static #saveData(filePath = this.dataFile) { if (detectEnvironment !== "Node.js") return; this.fs = this.fs || require("fs"); this.path = this.path || require("path"); const absPath = this.path.resolve(filePath); const cwdPath = this.path.resolve(process.cwd(), filePath); const absExists = this.fs.existsSync(absPath); const cwdExists = !absExists && this.fs.existsSync(cwdPath); const data = JSON.stringify(this.data); if (absExists) { this.fs.writeFileSync(absPath, data); } else if (cwdExists) { this.fs.writeFileSync(cwdPath, data); } else { this.fs.writeFileSync(absPath, data); } } } // 下面是压缩相关的工具函数(gzip/inflate实现) // 由于这部分代码较为复杂且高度优化,保持原有结构但添加注释 // 初始化一些数组(压缩算法用) function zeroArray(arr) { let i = arr.length; while (--i >= 0) arr[i] = 0; } zeroArray(new Array(576)); zeroArray(new Array(60)); zeroArray(new Array(512)); zeroArray(new Array(256)); zeroArray(new Array(29)); zeroArray(new Array(30)); // Adler-32校验和计算 const adler32 = (adler, buf, len, pos) => { let s1 = adler & 0xffff; let s2 = (adler >>> 16) & 0xffff; let n; for (; len > 0;) { n = len > 2000 ? 2000 : len; len -= n; do { s1 = (s1 + buf[pos++]) | 0; s2 = (s2 + s1) | 0; } while (--n); s1 %= 65521; s2 %= 65521; } return s1 | (s2 << 16); }; // CRC32表 const crcTable = new Uint32Array((() => { let c; const table = []; for (let n = 0; n < 256; n++) { c = n; for (let k = 0; k < 8; k++) { c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1; } table[n] = c; } return table; })()); // CRC32计算 const crc32 = (crc, buf, len, pos) => { const table = crcTable; const end = pos + len; crc ^= -1; for (let i = pos; i < end; i++) { crc = (crc >>> 8) ^ table[255 & (crc ^ buf[i])]; } return crc ^ -1; }; // 压缩错误代码 const ZLIB_ERRORS = { 2: "need dictionary", 1: "stream end", 0: "", "-1": "file error", "-2": "stream error", "-3": "data error", "-4": "insufficient memory", "-5": "buffer error", "-6": "incompatible version" }; // 压缩常量 const ZLIB_CONSTANTS = { Z_NO_FLUSH: 0, Z_FINISH: 4, Z_BLOCK: 5, Z_TREES: 6, Z_OK: 0, Z_STREAM_END: 1, Z_NEED_DICT: 2, Z_STREAM_ERROR: -2, Z_DATA_ERROR: -3, Z_MEM_ERROR: -4, Z_BUF_ERROR: -5, Z_DEFLATED: 8 }; // 工具函数 const hasOwn = (obj, key) => Object.prototype.hasOwnProperty.call(obj, key); const assign = function (target) { const args = Array.prototype.slice.call(arguments, 1); while (args.length) { const source = args.shift(); if (source) { if (typeof source !== "object") { throw new TypeError(source + "must be non-object"); } for (const key in source) { if (hasOwn(source, key)) { target[key] = source[key]; } } } } return target; }; const flattenChunks = (chunks) => { let total = 0; for (let i = 0; i < chunks.length; i++) { total += chunks[i].length; } const result = new Uint8Array(total); let offset = 0; for (let i = 0; i < chunks.length; i++) { const chunk = chunks[i]; result.set(chunk, offset); offset += chunk.length; } return result; }; // 文本编码检测 let _utf8len = true; try { String.fromCharCode.apply(null, new Uint8Array(1)); } catch (e) { _utf8len = false; } const utf8FirstByte = new Uint8Array(256); for (let q = 0; q < 256; q++) { utf8FirstByte[q] = q >= 252 ? 6 : q >= 248 ? 5 : q >= 240 ? 4 : q >= 224 ? 3 : q >= 192 ? 2 : 1; } utf8FirstByte[254] = utf8FirstByte[255] = 1; // 字符串转Uint8Array const stringToBytes = (str) => { if (typeof TextEncoder !== "undefined" && TextEncoder.prototype.encode) { return new TextEncoder().encode(str); } let i, c; const strLen = str.length; let resLen = 0; // 计算字节长度 for (i = 0; i < strLen; i++) { c = str.charCodeAt(i); if (c >= 0xd800 && c <= 0xdbff && i + 1 < strLen) { const c2 = str.charCodeAt(i + 1); if (c2 >= 0xdc00 && c2 <= 0xdfff) { c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00); i++; } } resLen += c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4; } // 编码 const res = new Uint8Array(resLen); let pos = 0; for (i = 0; pos < resLen; i++) { c = str.charCodeAt(i); if (c >= 0xd800 && c <= 0xdbff && i + 1 < strLen) { const c2 = str.charCodeAt(i + 1); if (c2 >= 0xdc00 && c2 <= 0xdfff) { c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00); i++; } } if (c < 0x80) { res[pos++] = c; } else if (c < 0x800) { res[pos++] = 0xc0 | (c >>> 6); res[pos++] = 0x80 | (c & 0x3f); } else if (c < 0x10000) { res[pos++] = 0xe0 | (c >>> 12); res[pos++] = 0x80 | (c >>> 6 & 0x3f); res[pos++] = 0x80 | (c & 0x3f); } else { res[pos++] = 0xf0 | (c >>> 18); res[pos++] = 0x80 | (c >>> 12 & 0x3f); res[pos++] = 0x80 | (c >>> 6 & 0x3f); res[pos++] = 0x80 | (c & 0x3f); } } return res; }; // Uint8Array转字符串 const bytesToString = (buf, max) => { const maxLen = max || buf.length; if (typeof TextDecoder !== "undefined" && TextDecoder.prototype.decode) { return new TextDecoder().decode(buf.subarray(0, maxLen)); } let i, out; const utf16 = new Array(maxLen * 2); let utf16len = 0; for (i = 0; i < maxLen;) { let c = buf[i++]; if (c < 128) { utf16[utf16len++] = c; continue; } let cLen = utf8FirstByte[c]; if (cLen > 4) { utf16[utf16len++] = 0xfffd; i += cLen - 1; continue; } c &= cLen === 2 ? 31 : cLen === 3 ? 15 : 7; while (cLen > 1 && i < maxLen) { c = (c << 6) | (buf[i++] & 0x3f); cLen--; } if (cLen > 1) { utf16[utf16len++] = 0xfffd; } else if (c < 0x10000) { utf16[utf16len++] = c; } else { c -= 0x10000; utf16[utf16len++] = 0xd800 | (c >> 10 & 0x3ff); utf16[utf16len++] = 0xdc00 | (c & 0x3ff); } } // 转换为字符串 const result = utf16.subarray(0, utf16len); if (maxLen < 65534 && result.subarray && _utf8len) { return String.fromCharCode.apply(null, result.length === maxLen ? result : result.subarray(0, maxLen)); } let str = ""; for (i = 0; i < utf16len; i++) { str += String.fromCharCode(result[i]); } return str; }; // 获取有效的UTF-8边界 const utf8Border = (buf, max) => { max = max || buf.length; max > buf.length && (max = buf.length); let pos = max - 1; while (pos >= 0 && (buf[pos] & 0xc0) === 0x80) pos--; return pos < 0 || pos === 0 ? max : pos + utf8FirstByte[buf[pos]] > max ? pos : max; }; // Zlib流结构 function ZlibStream() { this.input = null; this.next_in = 0; this.avail_in = 0; this.total_in = 0; this.output = null; this.next_out = 0; this.avail_out = 0; this.total_out = 0; this.msg = ""; this.state = null; this.data_type = 2; this.adler = 0; } // ... 压缩/解压缩相关函数(由于代码较长且复杂,保持原有逻辑但可添加必要注释) // 注:原始代码中的压缩/解压缩算法实现较为复杂,这里保持原有实现 // 导出的主要功能 const ungzip = function (data, options) { const inflator = new Inflate(options); if (inflator.push(data, true) && inflator.err) { throw inflator.msg || ZLIB_ERRORS[inflator.err]; } return inflator.result; }; // 导出常用工具 globalThis.$utils = { Logger, Utils, QueryParser, Storage, ungzip, finish };