fake-api-middleware
Version:
Express/Connect middleware for dummy responses
249 lines (240 loc) • 7.52 kB
JavaScript
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
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 __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var src_exports = {};
__export(src_exports, {
debounce: () => debounce,
delay: () => delay,
isString: () => isString,
middleware: () => middleware,
vitePlugin: () => vitePlugin
});
module.exports = __toCommonJS(src_exports);
// src/middleware.ts
var import_node_http = require("http");
var querystring = __toESM(require("querystring"));
var import_co_body = __toESM(require("co-body"));
// src/responsesLoader.ts
var import_node_events = require("events");
var chokidar = __toESM(require("chokidar"));
// src/helpers.ts
var delay = (time) => {
return new Promise((r) => {
setTimeout(r, time);
});
};
var isString = (value) => {
return typeof value === "string" || value instanceof String;
};
var debounce = (func, wait, immediate = false) => {
let timeout = null;
return (...args) => {
const later = () => {
timeout = null;
if (!immediate) {
func.apply(void 0, args);
}
};
const callNow = immediate && !timeout;
if (timeout) {
clearTimeout(timeout);
}
timeout = setTimeout(later, wait);
if (callNow) {
func.apply(void 0, args);
}
};
};
// src/module.ts
var path = __toESM(require("path"));
var fs = __toESM(require("fs"));
var module2 = __toESM(require("module"));
var import_esbuild = require("esbuild");
var _require = module2.createRequire(process.cwd());
var executeModule = (filePath, bundledCode) => {
filePath = path.resolve(process.cwd(), filePath);
const extension = path.extname(filePath);
const extensions = module2.Module._extensions;
const defaultLoader = extensions[extension];
extensions[extension] = (module3, filename) => {
if (filename === filePath) {
module3._compile(bundledCode, filename);
} else {
defaultLoader(module3, filename);
}
};
if (_require && _require.cache) {
delete _require.cache[filePath];
}
const raw = _require(filePath);
const config = raw.__esModule ? raw.default : raw;
if (defaultLoader) {
extensions[extension] = defaultLoader;
}
return config;
};
var extendedRequire = async (filePath) => {
const pkg = JSON.parse(
fs.readFileSync(path.join(process.cwd(), "package.json"), "utf8")
);
const srcCode = await (async () => {
const result = await (0, import_esbuild.build)({
entryPoints: [filePath],
outfile: "out.js",
write: false,
platform: "node",
bundle: true,
format: "cjs",
metafile: true,
target: "es2015",
external: [
"esbuild",
...Object.keys(pkg.dependencies || {}),
...Object.keys(pkg.devDependencies || {}),
...Object.keys(pkg.peerDependencies || {})
],
logLevel: "silent"
});
const { text } = result.outputFiles[0];
return text;
})();
return await executeModule(filePath, srcCode);
};
// src/responsesLoader.ts
var ResponsesLoader = class extends import_node_events.EventEmitter {
constructor({
responsesFile,
watchFiles
}) {
super();
this.responsesFile = responsesFile;
if (isString(watchFiles)) {
watchFiles = [watchFiles];
}
this.watchFiles = watchFiles || [];
chokidar.watch([this.responsesFile, ...this.watchFiles]).on(
"all",
debounce(async () => {
try {
const responsesConfig = await extendedRequire(this.responsesFile);
this.emit("update", responsesConfig);
} catch (e) {
this.emit("error", e);
}
}, 100)
);
}
};
// src/middleware.ts
var import_path_to_regexp = require("path-to-regexp");
var middleware = (middlewareOptions) => {
const prepareResponses = (responses) => {
const result = [];
for (const [key, response] of Object.entries(responses)) {
const [method, apiPath] = key.split(" ");
result.push({
method,
apiPath,
matchUrlFn: (0, import_path_to_regexp.match)(apiPath, { decode: decodeURIComponent }),
response
});
}
return result;
};
let preparedResponses = prepareResponses(middlewareOptions.responses || {});
if (middlewareOptions.responsesFile) {
const responsesConfigLoader = new ResponsesLoader({
responsesFile: middlewareOptions.responsesFile,
watchFiles: middlewareOptions.watchFiles
});
let wasErrorLastTime = false;
responsesConfigLoader.on("update", (newResponses) => {
preparedResponses = prepareResponses(newResponses);
if (wasErrorLastTime) {
console.info("[FakeResponses]", "Responses successfully loaded");
}
});
responsesConfigLoader.on("error", (err) => {
console.error("[FakeResponses]", err);
wasErrorLastTime = true;
});
}
return async (req, res, next) => {
if (middlewareOptions.enable !== void 0 && !middlewareOptions.enable) {
return next();
}
for (const { method, matchUrlFn, response } of preparedResponses) {
const [url, queryStr] = req.url.split("?");
const matchResult = matchUrlFn(url);
if (matchResult && req.method === method) {
if (middlewareOptions.responseDelay) {
await delay(middlewareOptions.responseDelay);
}
let body = {};
try {
body = await (0, import_co_body.default)(req);
} catch {
}
if (typeof response === "function") {
const responseResult = await response({
body,
query: querystring.parse(queryStr),
headers: req.headers,
params: matchResult.params,
req,
res
});
if (responseResult === void 0) {
return;
}
if (responseResult instanceof import_node_http.ServerResponse) {
return responseResult;
}
res.setHeader("Content-Type", "application/json");
return res.end(JSON.stringify(responseResult));
}
res.writeHead(200, { "Content-Type": "application/json" });
return res.end(JSON.stringify(response));
}
}
return next();
};
};
// src/vitePlugin.ts
var vitePlugin = (middlewareOptions) => {
return {
name: "vite-plugin-fake-response",
configureServer(server) {
server.middlewares.use(middleware(middlewareOptions));
}
};
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
debounce,
delay,
isString,
middleware,
vitePlugin
});