Son CV dans un terminal web en Javascript!
https://terminal-cv.gregandev.fr
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
465 lines
12 KiB
465 lines
12 KiB
"use strict";
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
exports.default = void 0;
|
|
|
|
function _assert() {
|
|
const data = _interopRequireDefault(require("assert"));
|
|
|
|
_assert = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _path() {
|
|
const data = _interopRequireDefault(require("path"));
|
|
|
|
_path = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _url() {
|
|
const data = _interopRequireWildcard(require("url"));
|
|
|
|
_url = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _utils() {
|
|
const data = require("@parcel/utils");
|
|
|
|
_utils = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
var _serverErrors = _interopRequireDefault(require("./serverErrors"));
|
|
|
|
function _fs() {
|
|
const data = _interopRequireDefault(require("fs"));
|
|
|
|
_fs = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _ejs() {
|
|
const data = _interopRequireDefault(require("ejs"));
|
|
|
|
_ejs = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _connect() {
|
|
const data = _interopRequireDefault(require("connect"));
|
|
|
|
_connect = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _serveHandler() {
|
|
const data = _interopRequireDefault(require("serve-handler"));
|
|
|
|
_serveHandler = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _httpProxyMiddleware() {
|
|
const data = require("http-proxy-middleware");
|
|
|
|
_httpProxyMiddleware = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
|
|
|
|
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
|
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
|
|
function setHeaders(res) {
|
|
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
res.setHeader('Access-Control-Allow-Methods', 'GET, HEAD, PUT, PATCH, POST, DELETE');
|
|
res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Content-Type');
|
|
}
|
|
|
|
const SOURCES_ENDPOINT = '/__parcel_source_root';
|
|
|
|
const TEMPLATE_404 = _fs().default.readFileSync(_path().default.join(__dirname, 'templates/404.html'), 'utf8');
|
|
|
|
const TEMPLATE_500 = _fs().default.readFileSync(_path().default.join(__dirname, 'templates/500.html'), 'utf8');
|
|
|
|
class Server {
|
|
constructor(options) {
|
|
this.options = options;
|
|
|
|
try {
|
|
this.rootPath = new (_url().URL)(options.publicUrl).pathname;
|
|
} catch (e) {
|
|
this.rootPath = options.publicUrl;
|
|
}
|
|
|
|
this.pending = true;
|
|
this.pendingRequests = [];
|
|
this.bundleGraph = null;
|
|
this.requestBundle = null;
|
|
this.errors = null;
|
|
}
|
|
|
|
buildStart() {
|
|
this.pending = true;
|
|
}
|
|
|
|
buildSuccess(bundleGraph, requestBundle) {
|
|
this.bundleGraph = bundleGraph;
|
|
this.requestBundle = requestBundle;
|
|
this.errors = null;
|
|
this.pending = false;
|
|
|
|
if (this.pendingRequests.length > 0) {
|
|
let pendingRequests = this.pendingRequests;
|
|
this.pendingRequests = [];
|
|
|
|
for (let [req, res] of pendingRequests) {
|
|
this.respond(req, res);
|
|
}
|
|
}
|
|
}
|
|
|
|
async buildError(options, diagnostics) {
|
|
this.pending = false;
|
|
this.errors = await Promise.all(diagnostics.map(async d => {
|
|
var _d$documentationURL;
|
|
|
|
let ansiDiagnostic = await (0, _utils().prettyDiagnostic)(d, options);
|
|
return {
|
|
message: (0, _utils().ansiHtml)(ansiDiagnostic.message),
|
|
stack: ansiDiagnostic.codeframe ? (0, _utils().ansiHtml)(ansiDiagnostic.codeframe) : (0, _utils().ansiHtml)(ansiDiagnostic.stack),
|
|
hints: ansiDiagnostic.hints.map(hint => (0, _utils().ansiHtml)(hint)),
|
|
documentation: (_d$documentationURL = d.documentationURL) !== null && _d$documentationURL !== void 0 ? _d$documentationURL : ''
|
|
};
|
|
}));
|
|
}
|
|
|
|
respond(req, res) {
|
|
let {
|
|
pathname
|
|
} = _url().default.parse(req.originalUrl || req.url);
|
|
|
|
if (pathname == null) {
|
|
pathname = '/';
|
|
}
|
|
|
|
if (this.errors) {
|
|
return this.send500(req, res);
|
|
} else if (_path().default.extname(pathname) === '') {
|
|
// If the URL doesn't start with the public path, or the URL doesn't
|
|
// have a file extension, send the main HTML bundle.
|
|
return this.sendIndex(req, res);
|
|
} else if (pathname.startsWith(SOURCES_ENDPOINT)) {
|
|
req.url = pathname.slice(SOURCES_ENDPOINT.length);
|
|
return this.serve(this.options.inputFS, this.options.projectRoot, req, res, () => this.send404(req, res));
|
|
} else if (pathname.startsWith(this.rootPath)) {
|
|
// Otherwise, serve the file from the dist folder
|
|
req.url = this.rootPath === '/' ? pathname : pathname.slice(this.rootPath.length);
|
|
|
|
if (req.url[0] !== '/') {
|
|
req.url = '/' + req.url;
|
|
}
|
|
|
|
return this.serveBundle(req, res, () => this.sendIndex(req, res));
|
|
} else {
|
|
return this.send404(req, res);
|
|
}
|
|
}
|
|
|
|
sendIndex(req, res) {
|
|
if (this.bundleGraph) {
|
|
// If the main asset is an HTML file, serve it
|
|
let htmlBundleFilePaths = [];
|
|
this.bundleGraph.traverseBundles(bundle => {
|
|
if (bundle.type === 'html' && bundle.bundleBehavior !== 'inline') {
|
|
htmlBundleFilePaths.push(bundle.filePath);
|
|
}
|
|
});
|
|
htmlBundleFilePaths = htmlBundleFilePaths.map(p => {
|
|
return `/${(0, _utils().relativePath)(this.options.distDir, p, false)}`;
|
|
});
|
|
let indexFilePath = null;
|
|
|
|
if (htmlBundleFilePaths.length === 1) {
|
|
indexFilePath = htmlBundleFilePaths[0];
|
|
} else {
|
|
indexFilePath = htmlBundleFilePaths.filter(v => {
|
|
let dir = _path().default.posix.dirname(v);
|
|
|
|
let withoutExtension = _path().default.posix.basename(v, _path().default.posix.extname(v));
|
|
|
|
return withoutExtension === 'index' && req.url.startsWith(dir);
|
|
}).sort((a, b) => {
|
|
return b.length - a.length;
|
|
})[0];
|
|
}
|
|
|
|
if (indexFilePath) {
|
|
req.url = indexFilePath;
|
|
this.serveBundle(req, res, () => this.send404(req, res));
|
|
} else {
|
|
this.send404(req, res);
|
|
}
|
|
} else {
|
|
this.send404(req, res);
|
|
}
|
|
}
|
|
|
|
async serveBundle(req, res, next) {
|
|
let bundleGraph = this.bundleGraph;
|
|
|
|
if (bundleGraph) {
|
|
let {
|
|
pathname
|
|
} = _url().default.parse(req.url);
|
|
|
|
if (!pathname) {
|
|
this.send500(req, res);
|
|
return;
|
|
}
|
|
|
|
let requestedPath = _path().default.normalize(pathname.slice(1));
|
|
|
|
let bundle = bundleGraph.getBundles().find(b => _path().default.relative(this.options.distDir, b.filePath) === requestedPath);
|
|
|
|
if (!bundle) {
|
|
this.serveDist(req, res, next);
|
|
return;
|
|
}
|
|
|
|
(0, _assert().default)(this.requestBundle != null);
|
|
|
|
try {
|
|
await this.requestBundle(bundle);
|
|
} catch (err) {
|
|
this.send500(req, res);
|
|
return;
|
|
}
|
|
|
|
this.serveDist(req, res, next);
|
|
} else {
|
|
this.send404(req, res);
|
|
}
|
|
}
|
|
|
|
serveDist(req, res, next) {
|
|
return this.serve(this.options.outputFS, this.options.distDir, req, res, next);
|
|
}
|
|
|
|
async serve(fs, root, req, res, next) {
|
|
if (req.method !== 'GET' && req.method !== 'HEAD') {
|
|
// method not allowed
|
|
res.statusCode = 405;
|
|
res.setHeader('Allow', 'GET, HEAD');
|
|
res.setHeader('Content-Length', '0');
|
|
res.end();
|
|
return;
|
|
}
|
|
|
|
try {
|
|
var filePath = _url().default.parse(req.url).pathname || '';
|
|
filePath = decodeURIComponent(filePath);
|
|
} catch (err) {
|
|
return this.sendError(res, 400);
|
|
}
|
|
|
|
filePath = _path().default.normalize('.' + _path().default.sep + filePath); // malicious path
|
|
|
|
if (filePath.includes(_path().default.sep + '..' + _path().default.sep)) {
|
|
return this.sendError(res, 403);
|
|
} // join / normalize from the root dir
|
|
|
|
|
|
if (!_path().default.isAbsolute(filePath)) {
|
|
filePath = _path().default.normalize(_path().default.join(root, filePath));
|
|
}
|
|
|
|
try {
|
|
var stat = await fs.stat(filePath);
|
|
} catch (err) {
|
|
if (err.code === 'ENOENT') {
|
|
return next(req, res);
|
|
}
|
|
|
|
return this.sendError(res, 500);
|
|
} // Fall back to next handler if not a file
|
|
|
|
|
|
if (!stat || !stat.isFile()) {
|
|
return next(req, res);
|
|
}
|
|
|
|
if (req.method === 'HEAD') {
|
|
res.end();
|
|
return;
|
|
}
|
|
|
|
return (0, _serveHandler().default)(req, res, {
|
|
public: root,
|
|
cleanUrls: false
|
|
}, {
|
|
lstat: path => fs.stat(path),
|
|
realpath: path => fs.realpath(path),
|
|
createReadStream: (path, options) => fs.createReadStream(path, options),
|
|
readdir: path => fs.readdir(path)
|
|
});
|
|
}
|
|
|
|
sendError(res, statusCode) {
|
|
res.statusCode = statusCode;
|
|
setHeaders(res);
|
|
res.end();
|
|
}
|
|
|
|
send404(req, res) {
|
|
res.statusCode = 404;
|
|
setHeaders(res);
|
|
res.end(TEMPLATE_404);
|
|
}
|
|
|
|
send500(req, res) {
|
|
setHeaders(res);
|
|
res.setHeader('Content-Type', 'text/html; charset=utf-8');
|
|
res.writeHead(500);
|
|
|
|
if (this.errors) {
|
|
return res.end(_ejs().default.render(TEMPLATE_500, {
|
|
errors: this.errors
|
|
}));
|
|
}
|
|
}
|
|
|
|
logAccessIfVerbose(req) {
|
|
this.options.logger.verbose({
|
|
message: `Request: ${req.headers.host}${req.originalUrl || req.url}`
|
|
});
|
|
}
|
|
/**
|
|
* Load proxy table from package.json and apply them.
|
|
*/
|
|
|
|
|
|
async applyProxyTable(app) {
|
|
// avoid skipping project root
|
|
const fileInRoot = _path().default.join(this.options.projectRoot, '_');
|
|
|
|
const pkg = await (0, _utils().loadConfig)(this.options.inputFS, fileInRoot, ['.proxyrc.js', '.proxyrc', '.proxyrc.json'], this.options.projectRoot);
|
|
|
|
if (!pkg || !pkg.config || !pkg.files) {
|
|
return this;
|
|
}
|
|
|
|
const cfg = pkg.config;
|
|
|
|
const filename = _path().default.basename(pkg.files[0].filePath);
|
|
|
|
if (filename === '.proxyrc.js') {
|
|
if (typeof cfg !== 'function') {
|
|
this.options.logger.warn({
|
|
message: "Proxy configuration file '.proxyrc.js' should export a function. Skipping..."
|
|
});
|
|
return this;
|
|
}
|
|
|
|
cfg(app);
|
|
} else if (filename === '.proxyrc' || filename === '.proxyrc.json') {
|
|
if (typeof cfg !== 'object') {
|
|
this.options.logger.warn({
|
|
message: "Proxy table in '.proxyrc' should be of object type. Skipping..."
|
|
});
|
|
return this;
|
|
}
|
|
|
|
for (const [context, options] of Object.entries(cfg)) {
|
|
// each key is interpreted as context, and value as middleware options
|
|
app.use((0, _httpProxyMiddleware().createProxyMiddleware)(context, options));
|
|
}
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
async start() {
|
|
const app = (0, _connect().default)();
|
|
app.use((req, res, next) => {
|
|
setHeaders(res);
|
|
next();
|
|
});
|
|
await this.applyProxyTable(app);
|
|
app.use((req, res) => {
|
|
this.logAccessIfVerbose(req); // Wait for the parcelInstance to finish bundling if needed
|
|
|
|
if (this.pending) {
|
|
this.pendingRequests.push([req, res]);
|
|
} else {
|
|
this.respond(req, res);
|
|
}
|
|
});
|
|
let {
|
|
server,
|
|
stop
|
|
} = await (0, _utils().createHTTPServer)({
|
|
cacheDir: this.options.cacheDir,
|
|
https: this.options.https,
|
|
inputFS: this.options.inputFS,
|
|
listener: app,
|
|
outputFS: this.options.outputFS,
|
|
host: this.options.host
|
|
});
|
|
this.stopServer = stop;
|
|
server.listen(this.options.port, this.options.host);
|
|
return new Promise((resolve, reject) => {
|
|
server.once('error', err => {
|
|
this.options.logger.error({
|
|
message: (0, _serverErrors.default)(err, this.options.port)
|
|
});
|
|
reject(err);
|
|
});
|
|
server.once('listening', () => {
|
|
resolve(server);
|
|
});
|
|
});
|
|
}
|
|
|
|
async stop() {
|
|
(0, _assert().default)(this.stopServer != null);
|
|
await this.stopServer();
|
|
this.stopServer = null;
|
|
}
|
|
|
|
}
|
|
|
|
exports.default = Server; |