UNPKG

rspack-plugin-mock

Version:
907 lines (849 loc) 30.6 kB
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/core/transform.ts var _utils = require('@pengzhanbo/utils'); // src/core/utils.ts var _fs = require('fs'); var _fs2 = _interopRequireDefault(_fs); var _os = require('os'); var _os2 = _interopRequireDefault(_os); var _path = require('path'); var _path2 = _interopRequireDefault(_path); var _querystring = require('querystring'); var _url = require('url'); var _debug = require('debug'); var _debug2 = _interopRequireDefault(_debug); var _memfs = require('memfs'); var _pathtoregexp = require('path-to-regexp'); var packageDir = getDirname(import.meta.url); var vfs = _memfs.createFsFromVolume.call(void 0, new (0, _memfs.Volume)()); function isStream(stream) { return stream !== null && typeof stream === "object" && typeof stream.pipe === "function"; } function isReadableStream(stream) { return isStream(stream) && stream.readable !== false && typeof stream._read === "function" && typeof stream._readableState === "object"; } function getDirname(importMetaUrl) { return _path2.default.dirname(_url.fileURLToPath.call(void 0, importMetaUrl)); } var debug = _debug2.default.call(void 0, "rspack:mock"); function lookupFile(dir, formats, options) { for (const format of formats) { const fullPath = _path2.default.join(dir, format); if (_fs2.default.existsSync(fullPath) && _fs2.default.statSync(fullPath).isFile()) { const result = _optionalChain([options, 'optionalAccess', _ => _.pathOnly]) ? fullPath : _fs2.default.readFileSync(fullPath, "utf-8"); if (!_optionalChain([options, 'optionalAccess', _2 => _2.predicate]) || options.predicate(result)) return result; } } const parentDir = _path2.default.dirname(dir); if (parentDir !== dir && (!_optionalChain([options, 'optionalAccess', _3 => _3.rootDir]) || parentDir.startsWith(_optionalChain([options, 'optionalAccess', _4 => _4.rootDir])))) { return lookupFile(parentDir, formats, options); } } function doesProxyContextMatchUrl(context, url, req) { if (typeof context === "function") { return context(url, req); } return context[0] === "^" && new RegExp(context).test(url) || url.startsWith(context); } function parseParams(pattern, url) { const urlMatch = _pathtoregexp.match.call(void 0, pattern, { decode: decodeURIComponent })(url) || { params: {} }; return urlMatch.params || {}; } function urlParse(input) { const url = new (0, _url.URL)(input, "http://example.com"); const pathname = decodeURIComponent(url.pathname); const query = _querystring.parse.call(void 0, url.search.replace(/^\?/, "")); return { pathname, query }; } var windowsSlashRE = /\\/g; var isWindows = _os2.default.platform() === "win32"; function slash(p) { return p.replace(windowsSlashRE, "/"); } function normalizePath(id) { return _path2.default.posix.normalize(isWindows ? slash(id) : id); } function waitingFor(onSuccess, maxRetry = 5) { return function wait(getter, retry = 0) { const value = getter(); if (value) { onSuccess(value); } else if (retry < maxRetry) { setTimeout(() => wait(getter, retry + 1), 100); } }; } // src/core/validator.ts function validate(request, validator) { return isObjectSubset(request.headers, validator.headers) && isObjectSubset(request.body, validator.body) && isObjectSubset(request.params, validator.params) && isObjectSubset(request.query, validator.query) && isObjectSubset(request.refererQuery, validator.refererQuery); } function isObjectSubset(source, target) { if (!target) return true; for (const key in target) { if (!isIncluded(source[key], target[key])) return false; } return true; } function isIncluded(source, target) { if (_utils.isArray.call(void 0, source) && _utils.isArray.call(void 0, target)) { const seen = /* @__PURE__ */ new Set(); return target.every( (ti) => source.some((si, i) => { if (seen.has(i)) return false; const included = isIncluded(si, ti); if (included) seen.add(i); return included; }) ); } if (_utils.isPlainObject.call(void 0, source) && _utils.isPlainObject.call(void 0, target)) return isObjectSubset(source, target); return Object.is(source, target); } // src/core/transform.ts function transformRawData(rawData) { return rawData.filter((item) => item[0]).map(([raw, __filepath__]) => { let mockConfig; if (raw.default) { if (Array.isArray(raw.default)) { mockConfig = raw.default.map((item) => ({ ...item, __filepath__ })); } else { mockConfig = { ...raw.default, __filepath__ }; } } else if ("url" in raw) { mockConfig = { ...raw, __filepath__ }; } else { mockConfig = []; Object.keys(raw || {}).forEach((key) => { if (Array.isArray(raw[key])) { mockConfig.push(...raw[key].map((item) => ({ ...item, __filepath__ }))); } else { mockConfig.push({ ...raw[key], __filepath__ }); } }); } return mockConfig; }); } function transformMockData(mockList) { const list = []; for (const [, handle] of mockList.entries()) { if (handle) list.push(..._utils.toArray.call(void 0, handle)); } const mocks = {}; list.filter((mock) => _utils.isPlainObject.call(void 0, mock) && mock.enabled !== false && mock.url).forEach((mock) => { const { pathname, query } = urlParse(mock.url); const list2 = mocks[pathname] ??= []; const current = { ...mock, url: pathname }; if (current.ws !== true) { const validator = current.validator; if (!_utils.isEmptyObject.call(void 0, query)) { if (_utils.isFunction.call(void 0, validator)) { current.validator = function(request) { return isObjectSubset(request.query, query) && validator(request); }; } else if (validator) { current.validator = { ...validator }; current.validator.query = current.validator.query ? { ...query, ...current.validator.query } : query; } else { current.validator = { query }; } } } list2.push(current); }); Object.keys(mocks).forEach((key) => { mocks[key] = sortByValidator(mocks[key]); }); return mocks; } function sortByValidator(mocks) { return _utils.sortBy.call(void 0, mocks, (item) => { if (item.ws === true) return 0; const { validator } = item; if (!validator || _utils.isEmptyObject.call(void 0, validator)) return 2; if (_utils.isFunction.call(void 0, validator)) return 0; const count = Object.keys(validator).reduce( (prev, key) => prev + keysCount(validator[key]), 0 ); return 1 / count; }); } function keysCount(obj) { if (!obj) return 0; return Object.keys(obj).length; } // src/core/requestRecovery.ts var _buffer = require('buffer'); var requestCollectCache = /* @__PURE__ */ new WeakMap(); function collectRequest(req) { const chunks = []; req.addListener("data", (chunk) => { chunks.push(_buffer.Buffer.from(chunk)); }); req.addListener("end", () => { if (chunks.length) requestCollectCache.set(req, _buffer.Buffer.concat(chunks)); }); } function rewriteRequest(proxyReq, req) { const buffer = requestCollectCache.get(req); if (buffer) { requestCollectCache.delete(req); if (!proxyReq.headersSent) proxyReq.setHeader("Content-Length", buffer.byteLength); if (!proxyReq.writableEnded) proxyReq.write(buffer); } } // src/core/baseMiddleware.ts var _cookies = require('cookies'); var _cookies2 = _interopRequireDefault(_cookies); var _httpstatus = require('http-status'); var _httpstatus2 = _interopRequireDefault(_httpstatus); var _mimetypes = require('mime-types'); var mime = _interopRequireWildcard(_mimetypes); var _picocolors = require('picocolors'); var _picocolors2 = _interopRequireDefault(_picocolors); // src/core/matchingWeight.ts var tokensCache = {}; function getTokens(rule) { if (tokensCache[rule]) return tokensCache[rule]; const tks = _pathtoregexp.parse.call(void 0, rule); const tokens = []; for (const tk of tks) { if (!_utils.isString.call(void 0, tk)) { tokens.push(tk); } else { const hasPrefix = tk[0] === "/"; const subTks = hasPrefix ? tk.slice(1).split("/") : tk.split("/"); tokens.push( `${hasPrefix ? "/" : ""}${subTks[0]}`, ...subTks.slice(1).map((t) => `/${t}`) ); } } tokensCache[rule] = tokens; return tokens; } function getHighest(rules) { let weights = rules.map((rule) => getTokens(rule).length); weights = weights.length === 0 ? [1] : weights; return Math.max(...weights) + 2; } function sortFn(rule) { const tokens = getTokens(rule); let w = 0; for (let i = 0; i < tokens.length; i++) { const token = tokens[i]; if (!_utils.isString.call(void 0, token)) w += 10 ** (i + 1); w += 10 ** (i + 1); } return w; } function preSort(rules) { let matched = []; const preMatch = []; for (const rule of rules) { const tokens = getTokens(rule); const len = tokens.filter((token) => typeof token !== "string").length; if (!preMatch[len]) preMatch[len] = []; preMatch[len].push(rule); } for (const match2 of preMatch.filter((v) => v && v.length > 0)) matched = [...matched, ..._utils.sortBy.call(void 0, match2, sortFn).reverse()]; return matched; } function defaultPriority(rules) { const highest = getHighest(rules); return _utils.sortBy.call(void 0, rules, (rule) => { const tokens = getTokens(rule); const dym = tokens.filter((token) => typeof token !== "string"); if (dym.length === 0) return 0; let weight = dym.length; let exp = 0; for (let i = 0; i < tokens.length; i++) { const token = tokens[i]; const isDynamic = !_utils.isString.call(void 0, token); const { pattern = "", modifier, prefix, name } = isDynamic ? token : {}; const isGlob = pattern && pattern.includes(".*"); const isSlash = prefix === "/"; const isNamed = _utils.isString.call(void 0, name); exp += isDynamic && isSlash ? 1 : 0; if (i === tokens.length - 1 && isGlob) { weight += 5 * 10 ** (tokens.length === 1 ? highest + 1 : highest); } else { if (isGlob) { weight += 3 * 10 ** (highest - 1); } else if (pattern) { if (isSlash) { weight += (isNamed ? 2 : 1) * 10 ** (exp + 1); } else { weight -= 1 * 10 ** exp; } } } if (modifier === "+") weight += 1 * 10 ** (highest - 1); if (modifier === "*") weight += 1 * 10 ** (highest - 1) + 1; if (modifier === "?") weight += 1 * 10 ** (exp + (isSlash ? 1 : 0)); } return weight; }); } function matchingWeight(rules, url, priority) { let matched = defaultPriority( preSort(rules.filter((rule) => _pathtoregexp.pathToRegexp.call(void 0, rule).test(url))) ); const { global = [], special = {} } = priority; if (global.length === 0 && _utils.isEmptyObject.call(void 0, special) || matched.length === 0) return matched; const [statics, dynamics] = twoPartMatch(matched); const globalMatch = global.filter((rule) => dynamics.includes(rule)); if (globalMatch.length > 0) { matched = _utils.uniq.call(void 0, [...statics, ...globalMatch, ...dynamics]); } if (_utils.isEmptyObject.call(void 0, special)) return matched; const specialRule = Object.keys(special).filter( (rule) => matched.includes(rule) )[0]; if (!specialRule) return matched; const options = special[specialRule]; const { rules: lowerRules, when } = _utils.isArray.call(void 0, options) ? { rules: options, when: [] } : options; if (lowerRules.includes(matched[0])) { if (when.length === 0 || when.some((path2) => _pathtoregexp.pathToRegexp.call(void 0, path2).test(url))) { matched = _utils.uniq.call(void 0, [specialRule, ...matched]); } } return matched; } function twoPartMatch(rules) { const statics = []; const dynamics = []; for (const rule of rules) { const tokens = getTokens(rule); const dym = tokens.filter((token) => typeof token !== "string"); if (dym.length > 0) dynamics.push(rule); else statics.push(rule); } return [statics, dynamics]; } // src/core/parseReqBody.ts var _cobody = require('co-body'); var _cobody2 = _interopRequireDefault(_cobody); var _formidable = require('formidable'); var _formidable2 = _interopRequireDefault(_formidable); async function parseReqBody(req, formidableOptions, bodyParserOptions = {}) { const method = req.method.toUpperCase(); if (["GET", "DELETE", "HEAD"].includes(method)) return void 0; const type = _optionalChain([req, 'access', _5 => _5.headers, 'access', _6 => _6["content-type"], 'optionalAccess', _7 => _7.toLocaleLowerCase, 'call', _8 => _8()]) || ""; const { limit, formLimit, jsonLimit, textLimit, ...rest } = bodyParserOptions; try { if (type.startsWith("application/json")) { return await _cobody2.default.json(req, { limit: jsonLimit || limit, ...rest }); } if (type.startsWith("application/x-www-form-urlencoded")) { return await _cobody2.default.form(req, { limit: formLimit || limit, ...rest }); } if (type.startsWith("text/plain")) { return await _cobody2.default.text(req, { limit: textLimit || limit, ...rest }); } if (type.startsWith("multipart/form-data")) return await parseMultipart(req, formidableOptions); } catch (e) { console.error(e); } return void 0; } async function parseMultipart(req, options) { const form = _formidable2.default.call(void 0, options); return new Promise((resolve, reject) => { form.parse(req, (error, fields, files) => { if (error) { reject(error); return; } resolve({ ...fields, ...files }); }); }); } // src/core/baseMiddleware.ts function baseMiddleware(compiler, { formidableOptions = {}, bodyParserOptions = {}, proxies, cookiesOptions, logger, priority = {} }) { return async function(req, res, next) { const startTime = _utils.timestamp.call(void 0, ); const { query, pathname } = urlParse(req.url); if (!pathname || proxies.length === 0 || !proxies.some((context) => doesProxyContextMatchUrl(context, req.url, req))) { return next(); } const mockData = compiler.mockData; const mockUrls = matchingWeight(Object.keys(mockData), pathname, priority); if (mockUrls.length === 0) { return next(); } collectRequest(req); const { query: refererQuery } = urlParse(req.headers.referer || ""); const reqBody = await parseReqBody(req, formidableOptions, bodyParserOptions); const cookies = new (0, _cookies2.default)(req, res, cookiesOptions); const getCookie = cookies.get.bind(cookies); const method = req.method.toUpperCase(); let mock; let _mockUrl; for (const mockUrl of mockUrls) { mock = fineMock(mockData[mockUrl], logger, { pathname, method, request: { query, refererQuery, body: reqBody, headers: req.headers, getCookie } }); if (mock) { _mockUrl = mockUrl; break; } } if (!mock) { const matched = mockUrls.map( (m) => m === _mockUrl ? _picocolors2.default.underline(_picocolors2.default.bold(m)) : _picocolors2.default.dim(m) ).join(", "); logger.warn( `${_picocolors2.default.green( pathname )} matches ${matched} , but mock data is not found.` ); return next(); } const request = req; const response = res; request.body = reqBody; request.query = query; request.refererQuery = refererQuery; request.params = parseParams(mock.url, pathname); request.getCookie = getCookie; response.setCookie = cookies.set.bind(cookies); const { body, delay, type = "json", response: responseFn, status = 200, statusText, log: logLevel, __filepath__: filepath } = mock; responseStatus(response, status, statusText); await provideHeaders(request, response, mock, logger); await provideCookies(request, response, mock, logger); logger.info(requestLog(request, filepath), logLevel); logger.debug( `${_picocolors2.default.magenta("DEBUG")} ${_picocolors2.default.underline( pathname )} matches: [ ${mockUrls.map( (m) => m === _mockUrl ? _picocolors2.default.underline(_picocolors2.default.bold(m)) : _picocolors2.default.dim(m) ).join(", ")} ] ` ); if (body) { try { const content = _utils.isFunction.call(void 0, body) ? await body(request) : body; await realDelay(startTime, delay); sendData(response, content, type); } catch (e) { logger.error( `${_picocolors2.default.red( `mock error at ${pathname}` )} ${e} at body (${_picocolors2.default.underline(filepath)})`, logLevel ); responseStatus(response, 500); res.end(""); } return; } if (responseFn) { try { await realDelay(startTime, delay); await responseFn(request, response, next); } catch (e) { logger.error( `${_picocolors2.default.red( `mock error at ${pathname}` )} ${e} at response (${_picocolors2.default.underline(filepath)})`, logLevel ); responseStatus(response, 500); res.end(""); } return; } res.end(""); }; } function fineMock(mockList, logger, { pathname, method, request }) { return mockList.find((mock) => { if (!pathname || !mock || !mock.url || mock.ws === true) return false; const methods = mock.method ? _utils.isArray.call(void 0, mock.method) ? mock.method : [mock.method] : ["GET", "POST"]; if (!methods.includes(method)) return false; const hasMock = _pathtoregexp.pathToRegexp.call(void 0, mock.url).test(pathname); if (hasMock && mock.validator) { const params = parseParams(mock.url, pathname); if (_utils.isFunction.call(void 0, mock.validator)) { return mock.validator({ params, ...request }); } else { try { return validate({ params, ...request }, mock.validator); } catch (e) { const file = mock.__filepath__; logger.error( `${_picocolors2.default.red( `mock error at ${pathname}` )} ${e} at validator (${_picocolors2.default.underline(file)})`, mock.log ); return false; } } } return hasMock; }); } function responseStatus(response, status = 200, statusText) { response.statusCode = status; response.statusMessage = statusText || getHTTPStatusText(status); } async function provideHeaders(req, res, mock, logger) { const { headers, type = "json" } = mock; const filepath = mock.__filepath__; const contentType2 = mime.contentType(type) || mime.contentType(mime.lookup(type) || ""); if (contentType2) res.setHeader("Content-Type", contentType2); res.setHeader("Cache-Control", "no-cache,max-age=0"); res.setHeader("X-Mock-Power-By", "vite-plugin-mock-dev-server"); if (filepath) res.setHeader("X-File-Path", filepath); if (!headers) return; try { const raw = _utils.isFunction.call(void 0, headers) ? await headers(req) : headers; Object.keys(raw).forEach((key) => { res.setHeader(key, raw[key]); }); } catch (e) { logger.error( `${_picocolors2.default.red( `mock error at ${req.url.split("?")[0]}` )} ${e} at headers (${_picocolors2.default.underline(filepath)})`, mock.log ); } } async function provideCookies(req, res, mock, logger) { const { cookies } = mock; const filepath = mock.__filepath__; if (!cookies) return; try { const raw = _utils.isFunction.call(void 0, cookies) ? await cookies(req) : cookies; Object.keys(raw).forEach((key) => { const cookie = raw[key]; if (_utils.isArray.call(void 0, cookie)) { const [value, options] = cookie; res.setCookie(key, value, options); } else { res.setCookie(key, cookie); } }); } catch (e) { logger.error( `${_picocolors2.default.red( `mock error at ${req.url.split("?")[0]}` )} ${e} at cookies (${_picocolors2.default.underline(filepath)})`, mock.log ); } } function sendData(res, raw, type) { if (isReadableStream(raw)) { raw.pipe(res); } else if (_buffer.Buffer.isBuffer(raw)) { res.end(type === "text" || type === "json" ? raw.toString("utf-8") : raw); } else { const content = typeof raw === "string" ? raw : JSON.stringify(raw); res.end(type === "buffer" ? _buffer.Buffer.from(content) : content); } } async function realDelay(startTime, delay) { if (!delay || typeof delay === "number" && delay <= 0 || _utils.isArray.call(void 0, delay) && delay.length !== 2) { return; } let realDelay2 = 0; if (_utils.isArray.call(void 0, delay)) { const [min, max] = delay; realDelay2 = _utils.random.call(void 0, min, max); } else { realDelay2 = delay - (_utils.timestamp.call(void 0, ) - startTime); } if (realDelay2 > 0) await _utils.sleep.call(void 0, realDelay2); } function getHTTPStatusText(status) { return _httpstatus2.default[status] || "Unknown"; } function requestLog(request, filepath) { const { url, method, query, params, body } = request; let { pathname } = new URL(url, "http://example.com"); pathname = _picocolors2.default.green(decodeURIComponent(pathname)); const format = (prefix, data) => { return !data || _utils.isEmptyObject.call(void 0, data) ? "" : ` ${_picocolors2.default.gray(`${prefix}:`)}${JSON.stringify(data)}`; }; const ms = _picocolors2.default.magenta(_picocolors2.default.bold(method)); const qs = format("query", query); const ps = format("params", params); const bs = format("body", body); const file = ` ${_picocolors2.default.dim(_picocolors2.default.underline(`(${filepath})`))}`; return `${ms} ${pathname}${qs}${ps}${bs}${file}`; } // src/core/mockWebsocket.ts var _ws = require('ws'); function mockWebSocket(compiler, httpServer, { wsProxies: proxies, cookiesOptions, logger }) { const hmrMap = /* @__PURE__ */ new Map(); const poolMap = /* @__PURE__ */ new Map(); const wssContextMap = /* @__PURE__ */ new WeakMap(); const getWssMap = (mockUrl) => { let wssMap = poolMap.get(mockUrl); if (!wssMap) poolMap.set(mockUrl, wssMap = /* @__PURE__ */ new Map()); return wssMap; }; const addHmr = (filepath, mockUrl) => { let urlList = hmrMap.get(filepath); if (!urlList) hmrMap.set(filepath, urlList = /* @__PURE__ */ new Set()); urlList.add(mockUrl); }; const setupWss = (wssMap, wss, mock, context, pathname, filepath) => { try { _optionalChain([mock, 'access', _9 => _9.setup, 'optionalCall', _10 => _10(wss, context)]); wss.on("close", () => wssMap.delete(pathname)); wss.on("error", (e) => { logger.error( `${_picocolors2.default.red( `WebSocket mock error at ${wss.path}` )} ${e} at setup (${filepath})`, mock.log ); }); } catch (e) { logger.error( `${_picocolors2.default.red( `WebSocket mock error at ${wss.path}` )} ${e} at setup (${filepath})`, mock.log ); } }; const restartWss = (wssMap, wss, mock, pathname, filepath) => { const { cleanupList, connectionList, context } = wssContextMap.get(wss); cleanupRunner(cleanupList); connectionList.forEach(({ ws }) => ws.removeAllListeners()); wss.removeAllListeners(); setupWss(wssMap, wss, mock, context, pathname, filepath); connectionList.forEach( ({ ws, req }) => emitConnection(wss, ws, req, connectionList) ); }; compiler.on("update", ({ filepath }) => { if (!hmrMap.has(filepath)) return; const mockUrlList = hmrMap.get(filepath); if (!mockUrlList) return; for (const mockUrl of mockUrlList.values()) { for (const mock of compiler.mockData[mockUrl]) { if (!mock.ws || mock.__filepath__ !== filepath) return; const wssMap = getWssMap(mockUrl); for (const [pathname, wss] of wssMap.entries()) restartWss(wssMap, wss, mock, pathname, filepath); } } }); _optionalChain([httpServer, 'optionalAccess', _11 => _11.on, 'call', _12 => _12("upgrade", (req, socket, head) => { const { pathname, query } = urlParse(req.url); if (!pathname || proxies.length === 0 || !proxies.some((context) => doesProxyContextMatchUrl(context, req.url, req))) { return; } const mockData = compiler.mockData; const mockUrl = Object.keys(mockData).find((key) => { return _pathtoregexp.pathToRegexp.call(void 0, key).test(pathname); }); if (!mockUrl) return; const mock = mockData[mockUrl].find((mock2) => { return mock2.url && mock2.ws && _pathtoregexp.pathToRegexp.call(void 0, mock2.url).test(pathname); }); if (!mock) return; const filepath = mock.__filepath__; addHmr(filepath, mockUrl); const wssMap = getWssMap(mockUrl); const wss = getWss(wssMap, pathname); let wssContext = wssContextMap.get(wss); if (!wssContext) { const cleanupList = []; const context = { onCleanup: (cleanup) => cleanupList.push(cleanup) }; wssContext = { cleanupList, context, connectionList: [] }; wssContextMap.set(wss, wssContext); setupWss(wssMap, wss, mock, context, pathname, filepath); } const request = req; const cookies = new (0, _cookies2.default)(req, req, cookiesOptions); const { query: refererQuery } = urlParse(req.headers.referer || ""); request.query = query; request.refererQuery = refererQuery; request.params = parseParams(mockUrl, pathname); request.getCookie = cookies.get.bind(cookies); wss.handleUpgrade(request, socket, head, (ws) => { logger.info( `${_picocolors2.default.magenta(_picocolors2.default.bold("WebSocket"))} ${_picocolors2.default.green( req.url )} connected ${_picocolors2.default.dim(`(${filepath})`)}`, mock.log ); wssContext.connectionList.push({ req: request, ws }); emitConnection(wss, ws, request, wssContext.connectionList); }); })]); _optionalChain([httpServer, 'optionalAccess', _13 => _13.on, 'call', _14 => _14("close", () => { for (const wssMap of poolMap.values()) { for (const wss of wssMap.values()) { const wssContext = wssContextMap.get(wss); cleanupRunner(wssContext.cleanupList); wss.close(); } wssMap.clear(); } poolMap.clear(); hmrMap.clear(); })]); } function getWss(wssMap, pathname) { let wss = wssMap.get(pathname); if (!wss) wssMap.set(pathname, wss = new (0, _ws.WebSocketServer)({ noServer: true })); return wss; } function emitConnection(wss, ws, req, connectionList) { wss.emit("connection", ws, req); ws.on("close", () => { const i = connectionList.findIndex((item) => item.ws === ws); if (i !== -1) connectionList.splice(i, 1); }); } function cleanupRunner(cleanupList) { let cleanup; while (cleanup = cleanupList.shift()) _optionalChain([cleanup, 'optionalCall', _15 => _15()]); } // src/core/logger.ts var logLevels = { silent: 0, error: 1, warn: 2, info: 3, debug: 4 }; function createLogger(prefix, defaultLevel = "info") { prefix = `[${prefix}]`; function output(type, msg, level) { level = _utils.isBoolean.call(void 0, level) ? level ? defaultLevel : "error" : level; const thresh = logLevels[level]; if (thresh >= logLevels[type]) { const method = type === "info" || type === "debug" ? "log" : type; const tag = type === "debug" ? _picocolors2.default.magenta(_picocolors2.default.bold(prefix)) : type === "info" ? _picocolors2.default.cyan(_picocolors2.default.bold(prefix)) : type === "warn" ? _picocolors2.default.yellow(_picocolors2.default.bold(prefix)) : _picocolors2.default.red(_picocolors2.default.bold(prefix)); const format = `${_picocolors2.default.dim( (/* @__PURE__ */ new Date()).toLocaleTimeString() )} ${tag} ${msg}`; console[method](format); } } const logger = { debug(msg, level = defaultLevel) { output("debug", msg, level); }, info(msg, level = defaultLevel) { output("info", msg, level); }, warn(msg, level = defaultLevel) { output("warn", msg, level); }, error(msg, level = defaultLevel) { output("error", msg, level); } }; return logger; } exports.packageDir = packageDir; exports.vfs = vfs; exports.lookupFile = lookupFile; exports.doesProxyContextMatchUrl = doesProxyContextMatchUrl; exports.urlParse = urlParse; exports.normalizePath = normalizePath; exports.waitingFor = waitingFor; exports.transformRawData = transformRawData; exports.transformMockData = transformMockData; exports.sortByValidator = sortByValidator; exports.rewriteRequest = rewriteRequest; exports.baseMiddleware = baseMiddleware; exports.mockWebSocket = mockWebSocket; exports.logLevels = logLevels; exports.createLogger = createLogger;