"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.watchFileIfOutOfRoot = exports.lookupFile = exports.readBody = exports.cachedRead = void 0; const path_1 = __importDefault(require("path")); const fs_extra_1 = __importDefault(require("fs-extra")); const lru_cache_1 = __importDefault(require("lru-cache")); const stream_1 = require("stream"); const serverPluginServeStatic_1 = require("../server/serverPluginServeStatic"); const mime_types_1 = __importDefault(require("mime-types")); const getETag = require('etag'); const fsReadCache = new lru_cache_1.default({ max: 10000 }); /** * Read a file with in-memory cache. * Also sets appropriate headers and body on the Koa context. * This is exposed on middleware context as `ctx.read` with the `ctx` already * bound, so it can be used as `ctx.read(file)`. */ async function cachedRead(ctx, file) { const lastModified = fs_extra_1.default.statSync(file).mtimeMs; const cached = fsReadCache.get(file); if (ctx) { ctx.set('Cache-Control', 'no-cache'); ctx.type = mime_types_1.default.lookup(path_1.default.extname(file)) || 'application/octet-stream'; } if (cached && cached.lastModified === lastModified) { if (ctx) { // a private marker in case the user ticks "disable cache" during dev ctx.__notModified = true; ctx.etag = cached.etag; ctx.lastModified = new Date(cached.lastModified); if (ctx.get('If-None-Match') === ctx.etag && serverPluginServeStatic_1.seenUrls.has(ctx.url)) { ctx.status = 304; } serverPluginServeStatic_1.seenUrls.add(ctx.url); ctx.body = cached.content; } return cached.content; } // #395 some file is an binary file, eg. font let content = await fs_extra_1.default.readFile(file); // Populate the "sourcesContent" array and resolve relative paths in the // "sources" array, so the debugger can trace back to the original source. if (file.endsWith('.map')) { const map = JSON.parse(content.toString('utf8')); if (!map.sourcesContent || !map.sources.every(path_1.default.isAbsolute)) { const sourcesContent = map.sourcesContent || []; map.sources = await Promise.all(map.sources.map(async (source, i) => { const originalPath = path_1.default.resolve(path_1.default.dirname(file), source); if (!sourcesContent[i]) { const originalCode = await cachedRead(null, originalPath); sourcesContent[i] = originalCode.toString('utf8'); } return originalPath; })); map.sourcesContent = sourcesContent; content = Buffer.from(JSON.stringify(map)); } } const etag = getETag(content); fsReadCache.set(file, { content, etag, lastModified }); if (ctx) { ctx.etag = etag; ctx.lastModified = new Date(lastModified); ctx.body = content; ctx.status = 200; // watch the file if it's out of root. const { root, watcher } = ctx; watchFileIfOutOfRoot(watcher, root, file); } return content; } exports.cachedRead = cachedRead; /** * Read already set body on a Koa context and normalize it into a string. * Useful in post-processing middlewares. */ async function readBody(stream) { if (stream instanceof stream_1.Readable) { return new Promise((resolve, reject) => { let res = ''; stream .on('data', (chunk) => (res += chunk)) .on('error', reject) .on('end', () => { resolve(res); }); }); } else { return !stream || typeof stream === 'string' ? stream : stream.toString(); } } exports.readBody = readBody; function lookupFile(dir, formats, pathOnly = false) { for (const format of formats) { const fullPath = path_1.default.join(dir, format); if (fs_extra_1.default.existsSync(fullPath) && fs_extra_1.default.statSync(fullPath).isFile()) { return pathOnly ? fullPath : fs_extra_1.default.readFileSync(fullPath, 'utf-8'); } } const parentDir = path_1.default.dirname(dir); if (parentDir !== dir) { return lookupFile(parentDir, formats, pathOnly); } } exports.lookupFile = lookupFile; /** * Files under root are watched by default, but with user aliases we can still * serve files out of root. Add such files to the watcher (if not node_modules) */ function watchFileIfOutOfRoot(watcher, root, file) { if (!file.startsWith(root) && !/node_modules/.test(file)) { watcher.add(file); } } exports.watchFileIfOutOfRoot = watchFileIfOutOfRoot; //# sourceMappingURL=fsUtils.js.map