forked from svrjs/svrjs
Compare commits
54 commits
Author | SHA1 | Date | |
---|---|---|---|
317acff5d6 | |||
f4fc6ba165 | |||
3bf8ff799e | |||
9e227bbec6 | |||
27c613f28e | |||
215f1fae25 | |||
d44ee67e57 | |||
effc654f05 | |||
997b03c2a2 | |||
45d8b9bcd3 | |||
78e7c8c967 | |||
25280b310c | |||
73b062d306 | |||
2ae73966ec | |||
5e031fe997 | |||
1c6e707f58 | |||
4a1a59f15d | |||
67680fc97f | |||
40f100db94 | |||
7d144c95b6 | |||
3b25b33583 | |||
c70e078b26 | |||
3abc31e2aa | |||
0161b04e1f | |||
d7b0fc463e | |||
3d411c3be1 | |||
9c49df9d87 | |||
06712f35b5 | |||
91f2d3b50f | |||
688c850c50 | |||
26214c9eb8 | |||
4928ac1d2c | |||
27e62da887 | |||
d25f912c06 | |||
19f7345762 | |||
a63e1a893b | |||
a755e32bc7 | |||
c380c469ef | |||
faecaa8b8a | |||
ae3cf033be | |||
9fa9c047d1 | |||
faa043cb99 | |||
7587932250 | |||
9406ffda5f | |||
10ee128136 | |||
|
91d8d0df63 | ||
71b5727b6c | |||
c6960061b7 | |||
55262f73c5 | |||
750a312b2f | |||
e0f0cb69d8 | |||
d01064cc17 | |||
c9df74c745 | |||
46a256d31f |
18 changed files with 1360 additions and 1325 deletions
|
@ -8,10 +8,10 @@
|
|||
It's free as in freedom, scalable, secure, and configurable.
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="https://svrjs.org/docs" target="_blank"><img alt="Static Badge" src="https://img.shields.io/badge/Documentation-green"></a>
|
||||
<a href="https://svrjs.org/docs/tentative" target="_blank"><img alt="Static Badge" src="https://img.shields.io/badge/Documentation-green"></a>
|
||||
<a href="https://svrjs.org" target="_blank"><img alt="Website" src="https://img.shields.io/website?url=https%3A%2F%2Fsvrjs.org"></a>
|
||||
<a href="https://hub.docker.com/r/svrjs/svrjs" target="_blank"><img alt="Docker Pulls" src="https://img.shields.io/docker/pulls/svrjs/svrjs"></a>
|
||||
<a href="https://github.com/svr-js/svrjs" target="_blank"><img alt="GitHub Repo stars" src="https://img.shields.io/github/stars/svr-js/svrjs"></a>
|
||||
<a href="https://github.com/svr-js/svrjs/tree/next" target="_blank"><img alt="GitHub Repo stars" src="https://img.shields.io/github/stars/svr-js/svrjs"></a>
|
||||
<a href="https://x.com/SVR_JS" target="_blank"><img alt="X (formerly Twitter) Follow" src="https://img.shields.io/twitter/follow/SVR_JS"></a>
|
||||
<a href="https://mastodon.social/@svrjs" target="_blank"><img alt="Mastodon Follow" src="https://img.shields.io/mastodon/follow/111643338718098121"></a>
|
||||
</p>
|
||||
|
@ -87,7 +87,7 @@ After running the command, you will get bundled SVR.JS script, around with built
|
|||
|
||||
To install SVR.JS you just built from the source code, you can install it via SVR.JS installer for GNU/Linux or manually.
|
||||
|
||||
If you want to install SVR.JS manually, you can read the [server documentation](https://svrjs.org/docs).
|
||||
If you want to install SVR.JS manually, you can read the [server documentation](https://svrjs.org/docs/tentative).
|
||||
|
||||
If you want to install via SVR.JS installer for GNU/Linux, run this command:
|
||||
```bash
|
||||
|
@ -102,7 +102,7 @@ After installation, SVR.JS should be listening at http://localhost.
|
|||
|
||||
## SVR.JS documentation
|
||||
|
||||
You can read the [SVR.JS documentation](https://svrjs.org/docs) to get information on how to use SVR.JS.
|
||||
You can read the [SVR.JS documentation](https://svrjs.org/docs/tentative) to get information on how to use SVR.JS.
|
||||
|
||||
## npm scripts
|
||||
|
||||
|
|
|
@ -59,6 +59,5 @@
|
|||
"disableTrailingSlashRedirects": false,
|
||||
"environmentVariables": {},
|
||||
"allowDoubleSlashes": false,
|
||||
"optOutOfStatisticsServer": false,
|
||||
"disableConfigurationSaving": false
|
||||
"optOutOfStatisticsServer": false
|
||||
}
|
||||
|
|
|
@ -4,36 +4,15 @@ const fs = require("fs");
|
|||
const zlib = require("zlib");
|
||||
const ejs = require("ejs");
|
||||
const archiver = require("archiver");
|
||||
const chokidar = require("chokidar");
|
||||
const svrjsInfo = JSON.parse(fs.readFileSync(__dirname + "/svrjs.json"));
|
||||
const { version } = svrjsInfo;
|
||||
const isDev = process.env.NODE_ENV == "development";
|
||||
|
||||
// Create the dist directory if it doesn't exist
|
||||
if (!fs.existsSync(__dirname + "/dist")) fs.mkdirSync(__dirname + "/dist");
|
||||
if (!fs.existsSync(__dirname + "/dist/log"))
|
||||
fs.mkdirSync(__dirname + "/dist/log");
|
||||
if (!fs.existsSync(__dirname + "/dist/mods"))
|
||||
fs.mkdirSync(__dirname + "/dist/mods");
|
||||
if (!fs.existsSync(__dirname + "/dist/temp"))
|
||||
fs.mkdirSync(__dirname + "/dist/temp");
|
||||
|
||||
// Create the out directory if it doesn't exist and if not building for development
|
||||
if (!isDev && !fs.existsSync(__dirname + "/out")) fs.mkdirSync(__dirname + "/out");
|
||||
|
||||
function generateAssets() {
|
||||
// Variables from "svrjs.json" file
|
||||
const svrjsInfo = JSON.parse(fs.readFileSync(__dirname + "/svrjs.json"));
|
||||
const { name, version, documentationURL, changes } = svrjsInfo;
|
||||
|
||||
// Dependency-related variables
|
||||
const dependencies =
|
||||
const dependencies =
|
||||
JSON.parse(fs.readFileSync(__dirname + "/package.json")).dependencies || {};
|
||||
const requiredDependencyList = Object.keys(dependencies);
|
||||
let dependencyList = Object.keys(dependencies);
|
||||
const requiredDependencyList = Object.keys(dependencies);
|
||||
let dependencyList = Object.keys(dependencies);
|
||||
const svrjsInfo = JSON.parse(fs.readFileSync(__dirname + "/svrjs.json"));
|
||||
const { name, version, documentationURL, changes } = svrjsInfo;
|
||||
|
||||
// Function to find and add all dependencies into the dependencyList array.
|
||||
const findAllDependencies = (curList) => {
|
||||
// Function to find and add all dependencies into the dependencyList array.
|
||||
function findAllDependencies(curList) {
|
||||
// If no curList parameter is specified, use dependencyList.
|
||||
if (!curList) curList = dependencyList;
|
||||
curList.forEach((dependency) => {
|
||||
|
@ -60,42 +39,42 @@ function generateAssets() {
|
|||
// Call findAllDependencies for the dependency list.
|
||||
findAllDependencies(noDupNewDepList);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
// Get list of all dependencies
|
||||
findAllDependencies();
|
||||
dependencyList = dependencyList.sort();
|
||||
// Get list of all dependencies
|
||||
findAllDependencies();
|
||||
dependencyList = dependencyList.sort();
|
||||
|
||||
// Create and populate an object, where whenever the dependencies are required are listed.
|
||||
let dependenciesAreRequired = {};
|
||||
dependencyList.forEach((dependency) => {
|
||||
// Create and populate an object, where whenever the dependencies are required are listed.
|
||||
let dependenciesAreRequired = {};
|
||||
dependencyList.forEach((dependency) => {
|
||||
dependenciesAreRequired[dependency] = false;
|
||||
});
|
||||
requiredDependencyList.forEach((dependency) => {
|
||||
});
|
||||
requiredDependencyList.forEach((dependency) => {
|
||||
dependenciesAreRequired[dependency] = true;
|
||||
});
|
||||
});
|
||||
|
||||
// Create the template functions using EJS
|
||||
const layoutTemplate = ejs.compile(
|
||||
// Create the template functions using EJS
|
||||
const layoutTemplate = ejs.compile(
|
||||
fs.readFileSync(__dirname + "/templates/layout.ejs").toString()
|
||||
);
|
||||
const testsTemplate = ejs.compile(
|
||||
);
|
||||
const testsTemplate = ejs.compile(
|
||||
fs.readFileSync(__dirname + "/templates/tests.ejs").toString()
|
||||
);
|
||||
const indexTemplate = ejs.compile(
|
||||
);
|
||||
const indexTemplate = ejs.compile(
|
||||
fs.readFileSync(__dirname + "/templates/index.ejs").toString()
|
||||
);
|
||||
const licensesTemplate = ejs.compile(
|
||||
);
|
||||
const licensesTemplate = ejs.compile(
|
||||
fs.readFileSync(__dirname + "/templates/licenses.ejs").toString()
|
||||
);
|
||||
const licenseElementTemplate = ejs.compile(
|
||||
);
|
||||
const licenseElementTemplate = ejs.compile(
|
||||
fs.readFileSync(__dirname + "/templates/licenseElement.ejs").toString()
|
||||
);
|
||||
);
|
||||
|
||||
let licenseElements = "";
|
||||
let licenseElements = "";
|
||||
|
||||
// Generate the licenses list in HTML
|
||||
dependencyList.forEach((dependency) => {
|
||||
// Generate the licenses list in HTML
|
||||
dependencyList.forEach((dependency) => {
|
||||
const packageJSON = JSON.parse(
|
||||
fs
|
||||
.readFileSync(
|
||||
|
@ -114,27 +93,27 @@ function generateAssets() {
|
|||
author: packageJSON.author ? packageJSON.author.name : packageJSON.author,
|
||||
required: dependenciesAreRequired[dependency]
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Generate pages
|
||||
const licensesPage = layoutTemplate({
|
||||
// Generate pages
|
||||
const licensesPage = layoutTemplate({
|
||||
title: name + " " + version + " Licenses",
|
||||
content: licensesTemplate({
|
||||
name: name,
|
||||
version: version,
|
||||
licenses: licenseElements
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
const testsPage = layoutTemplate({
|
||||
const testsPage = layoutTemplate({
|
||||
title: name + " " + version + " Tests",
|
||||
content: testsTemplate({
|
||||
name: name,
|
||||
version: version
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
const indexPage = layoutTemplate({
|
||||
const indexPage = layoutTemplate({
|
||||
title: name + " " + version,
|
||||
content: indexTemplate({
|
||||
name: name,
|
||||
|
@ -142,57 +121,45 @@ function generateAssets() {
|
|||
documentationURL: documentationURL,
|
||||
changes: changes
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
// Create the generated assets directory if it doesn't exist
|
||||
if (!fs.existsSync(__dirname + "/generatedAssets"))
|
||||
fs.mkdirSync(__dirname + "/generatedAssets");
|
||||
// Remove the generated assets directory if exists, and create a new one.
|
||||
if (fs.existsSync(__dirname + "/generatedAssets")) {
|
||||
if (fs.rmSync) fs.rmSync(__dirname + "/generatedAssets", { recursive: true });
|
||||
else fs.rmdirSync(__dirname + "/generatedAssets", { recursive: true });
|
||||
}
|
||||
fs.mkdirSync(__dirname + "/generatedAssets");
|
||||
|
||||
// Create a licenses directory
|
||||
if (!fs.existsSync(__dirname + "/generatedAssets/licenses"))
|
||||
fs.mkdirSync(__dirname + "/generatedAssets/licenses");
|
||||
// Remove the dist directory if exists, and create a new one.
|
||||
if (fs.existsSync(__dirname + "/dist")) {
|
||||
if (fs.rmSync) fs.rmSync(__dirname + "/dist", { recursive: true });
|
||||
else fs.rmdirSync(__dirname + "/dist", { recursive: true });
|
||||
}
|
||||
fs.mkdirSync(__dirname + "/dist");
|
||||
fs.mkdirSync(__dirname + "/dist/log");
|
||||
fs.mkdirSync(__dirname + "/dist/mods");
|
||||
fs.mkdirSync(__dirname + "/dist/temp");
|
||||
|
||||
// Write to HTML files
|
||||
fs.writeFileSync(__dirname + "/generatedAssets/index.html", indexPage);
|
||||
fs.writeFileSync(__dirname + "/generatedAssets/tests.html", testsPage);
|
||||
fs.writeFileSync(
|
||||
// Remove the out directory if exists, and create a new one.
|
||||
if (fs.existsSync(__dirname + "/out")) {
|
||||
if (fs.rmSync) fs.rmSync(__dirname + "/out", { recursive: true });
|
||||
else fs.rmdirSync(__dirname + "/out", { recursive: true });
|
||||
}
|
||||
fs.mkdirSync(__dirname + "/out");
|
||||
|
||||
// Create a licenses directory
|
||||
fs.mkdirSync(__dirname + "/generatedAssets/licenses");
|
||||
|
||||
// Write to HTML files
|
||||
fs.writeFileSync(__dirname + "/generatedAssets/index.html", indexPage);
|
||||
fs.writeFileSync(__dirname + "/generatedAssets/tests.html", testsPage);
|
||||
fs.writeFileSync(
|
||||
__dirname + "/generatedAssets/licenses/index.html",
|
||||
licensesPage
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
if (!isDev) {
|
||||
// Generate assets
|
||||
generateAssets();
|
||||
} else {
|
||||
// Generate assets with watching
|
||||
const watcher = chokidar.watch([
|
||||
__dirname + "/templates",
|
||||
__dirname + "/package.json",
|
||||
__dirname + "/svrjs.json"
|
||||
]);
|
||||
watcher.on("change", () => {
|
||||
try {
|
||||
generateAssets();
|
||||
} catch (err) {
|
||||
console.error("There is a problem when regenerating assets!");
|
||||
console.error("Stack:");
|
||||
console.error(err.stack);
|
||||
}
|
||||
}).on("ready", () => {
|
||||
try {
|
||||
generateAssets();
|
||||
} catch (err) {
|
||||
console.error("There is a problem when regenerating assets!");
|
||||
console.error("Stack:");
|
||||
console.error(err.stack);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!isDev) {
|
||||
// Bundle the source and copy the assets using esbuild and esbuild-plugin-copy
|
||||
esbuild
|
||||
// Bundle the source and copy the assets using esbuild and esbuild-plugin-copy
|
||||
esbuild
|
||||
.build({
|
||||
entryPoints: ["src/index.js"],
|
||||
bundle: true,
|
||||
|
@ -247,9 +214,7 @@ if (!isDev) {
|
|||
"svr.js." +
|
||||
version.toLowerCase().replace(/[^0-9a-z]+/g, ".") +
|
||||
".zip";
|
||||
const output = fs.createWriteStream(
|
||||
__dirname + "/out/" + archiveName
|
||||
);
|
||||
const output = fs.createWriteStream(__dirname + "/out/" + archiveName);
|
||||
const archive = archiver("zip", {
|
||||
zlib: { level: 9 }
|
||||
});
|
||||
|
@ -284,82 +249,3 @@ if (!isDev) {
|
|||
.catch((err) => {
|
||||
throw err;
|
||||
});
|
||||
} else {
|
||||
// Bundle the source and copy the assets using esbuild and esbuild-plugin-copy with watching
|
||||
esbuild
|
||||
.context({
|
||||
entryPoints: ["src/index.js"],
|
||||
bundle: true,
|
||||
outfile: "dist/svr.js",
|
||||
platform: "node",
|
||||
target: "es2017",
|
||||
plugins: [
|
||||
esbuildCopyPlugin.copy({
|
||||
resolveFrom: __dirname,
|
||||
assets: {
|
||||
from: ["./assets/**/*"],
|
||||
to: ["./dist"]
|
||||
},
|
||||
globbyOptions: {
|
||||
dot: true
|
||||
},
|
||||
watch: {}
|
||||
}),
|
||||
esbuildCopyPlugin.copy({
|
||||
resolveFrom: __dirname,
|
||||
assets: {
|
||||
from: ["./generatedAssets/**/*"],
|
||||
to: ["./dist"]
|
||||
},
|
||||
watch: {}
|
||||
})
|
||||
]
|
||||
})
|
||||
.then((ctx) => {
|
||||
ctx
|
||||
.watch()
|
||||
.then(() => {
|
||||
const utilFilesAndDirectories = fs.existsSync(
|
||||
__dirname + "/src/extraScripts"
|
||||
)
|
||||
? fs.readdirSync(__dirname + "/src/extraScripts")
|
||||
: [];
|
||||
const utilFiles = [];
|
||||
utilFilesAndDirectories.forEach((entry) => {
|
||||
if (fs.statSync(__dirname + "/src/extraScripts/" + entry).isFile())
|
||||
utilFiles.push(entry);
|
||||
});
|
||||
|
||||
// Transpile utilities using esbuild
|
||||
esbuild
|
||||
.context({
|
||||
entryPoints: utilFiles.map(
|
||||
(filename) => "src/extraScripts/" + filename
|
||||
),
|
||||
bundle: true,
|
||||
outdir: "dist",
|
||||
platform: "node",
|
||||
target: "es2017"
|
||||
})
|
||||
.then((ctx) => {
|
||||
ctx
|
||||
.watch()
|
||||
.then(() => {
|
||||
console.log("Watching for changes in SVR.JS source code...");
|
||||
})
|
||||
.catch((err) => {
|
||||
throw err;
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
throw err;
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
throw err;
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"watch": [
|
||||
"dist/svr.js",
|
||||
"dist/config.json"
|
||||
]
|
||||
}
|
1731
package-lock.json
generated
1731
package-lock.json
generated
File diff suppressed because it is too large
Load diff
12
package.json
12
package.json
|
@ -3,10 +3,9 @@
|
|||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "npm run clean && NODE_ENV=production node esbuild.config.js",
|
||||
"build": "node esbuild.config.js",
|
||||
"cz": "cz",
|
||||
"clean": "rimraf dist && rimraf out && rimraf generatedAssets",
|
||||
"dev": "npm run clean && concurrently \"NODE_ENV=development node esbuild.config.js\" \"wait-on dist/svr.js && nodemon dist/svr.js --stdout-notty --no-save-config\"",
|
||||
"dev": "npm run build && npm run start",
|
||||
"lint": "eslint --no-error-on-unmatched-pattern src/**/*.js src/*.js tests/**/*.test.js tests/**/*.js tests/*.test.js tests/*.js",
|
||||
"lint:fix": "npm run lint -- --fix",
|
||||
"prepare": "husky",
|
||||
|
@ -21,9 +20,7 @@
|
|||
"@commitlint/config-conventional": "^19.4.1",
|
||||
"@eslint/js": "^9.9.0",
|
||||
"archiver": "^7.0.1",
|
||||
"chokidar": "^4.0.1",
|
||||
"commitizen": "^4.3.0",
|
||||
"concurrently": "^9.1.0",
|
||||
"cz-conventional-changelog": "^3.3.0",
|
||||
"ejs": "^3.1.10",
|
||||
"esbuild": "^0.23.1",
|
||||
|
@ -37,10 +34,7 @@
|
|||
"jest": "^29.7.0",
|
||||
"lint-staged": "^15.2.10",
|
||||
"node-mocks-http": "^1.15.1",
|
||||
"nodemon": "^3.1.7",
|
||||
"prettier": "^3.3.3",
|
||||
"rimraf": "^5.0.10",
|
||||
"wait-on": "^8.0.1"
|
||||
"prettier": "^3.3.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"formidable": "^2.1.2",
|
||||
|
|
|
@ -12,9 +12,6 @@ let serverconsole = {};
|
|||
function clientErrorHandler(err, socket) {
|
||||
const config = deepClone(process.serverConfig);
|
||||
|
||||
// Determine the webroot from the current working directory if it is not configured
|
||||
if (config.wwwroot === undefined) config.wwwroot = process.cwd();
|
||||
|
||||
config.generateServerString = () =>
|
||||
generateServerString(config.exposeServerVersion);
|
||||
|
||||
|
@ -185,14 +182,14 @@ function clientErrorHandler(err, socket) {
|
|||
fs.access(config.page404, fs.constants.F_OK, (err) => {
|
||||
if (err) {
|
||||
fs.access(
|
||||
config.wwwroot + "/." + errorCode.toString(),
|
||||
"." + errorCode.toString(),
|
||||
fs.constants.F_OK,
|
||||
(err) => {
|
||||
try {
|
||||
if (err) {
|
||||
callback(errorCode.toString() + ".html");
|
||||
} else {
|
||||
callback(config.wwwroot + "/." + errorCode.toString());
|
||||
callback("." + errorCode.toString());
|
||||
}
|
||||
} catch (err2) {
|
||||
callServerError(500, err2);
|
||||
|
@ -208,21 +205,17 @@ function clientErrorHandler(err, socket) {
|
|||
}
|
||||
});
|
||||
} else {
|
||||
fs.access(
|
||||
config.wwwroot + "/." + errorCode.toString(),
|
||||
fs.constants.F_OK,
|
||||
(err) => {
|
||||
fs.access("." + errorCode.toString(), fs.constants.F_OK, (err) => {
|
||||
try {
|
||||
if (err) {
|
||||
callback(errorCode.toString() + ".html");
|
||||
} else {
|
||||
callback(config.wwwroot + "/." + errorCode.toString());
|
||||
callback("." + errorCode.toString());
|
||||
}
|
||||
} catch (err2) {
|
||||
callServerError(500, err2);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -464,15 +457,15 @@ function clientErrorHandler(err, socket) {
|
|||
} sent invalid request.`
|
||||
);
|
||||
try {
|
||||
head = fs.existsSync(`${config.wwwroot}/.head`)
|
||||
? fs.readFileSync(`${config.wwwroot}/.head`).toString()
|
||||
: fs.existsSync(`${config.wwwroot}/head.html`)
|
||||
? fs.readFileSync(`${config.wwwroot}/head.html`).toString()
|
||||
head = fs.existsSync("./.head")
|
||||
? fs.readFileSync("./.head").toString()
|
||||
: fs.existsSync("./head.html")
|
||||
? fs.readFileSync("./head.html").toString()
|
||||
: ""; // header
|
||||
foot = fs.existsSync(`${config.wwwroot}/.foot`)
|
||||
? fs.readFileSync(`${config.wwwroot}/.foot`).toString()
|
||||
: fs.existsSync(`${config.wwwroot}/foot.html`)
|
||||
? fs.readFileSync(`${config.wwwroot}/foot.html`).toString()
|
||||
foot = fs.existsSync("./.foot")
|
||||
? fs.readFileSync("./.foot").toString()
|
||||
: fs.existsSync("./foot.html")
|
||||
? fs.readFileSync("./foot.html").toString()
|
||||
: ""; // footer
|
||||
|
||||
if (
|
||||
|
|
|
@ -32,9 +32,6 @@ function proxyHandler(req, socket, head) {
|
|||
// SVR.JS configuration object (modified)
|
||||
const config = deepClone(process.serverConfig);
|
||||
|
||||
// Determine the webroot from the current working directory if it is not configured
|
||||
if (config.wwwroot === undefined) config.wwwroot = process.cwd();
|
||||
|
||||
config.generateServerString = () =>
|
||||
generateServerString(config.exposeServerVersion);
|
||||
|
||||
|
|
|
@ -37,9 +37,6 @@ function requestHandler(req, res) {
|
|||
config.generateServerString = () =>
|
||||
generateServerString(config.exposeServerVersion);
|
||||
|
||||
// Determine the webroot from the current working directory if it is not configured
|
||||
if (config.wwwroot === undefined) config.wwwroot = process.cwd();
|
||||
|
||||
// getCustomHeaders() in SVR.JS 3.x
|
||||
config.getCustomHeaders = () => {
|
||||
let ph = Object.assign({}, config.customHeaders);
|
||||
|
@ -348,14 +345,14 @@ function requestHandler(req, res) {
|
|||
fs.access(config.page404, fs.constants.F_OK, (err) => {
|
||||
if (err) {
|
||||
fs.access(
|
||||
config.wwwroot + "/." + errorCode.toString(),
|
||||
"." + errorCode.toString(),
|
||||
fs.constants.F_OK,
|
||||
(err) => {
|
||||
try {
|
||||
if (err) {
|
||||
callback(errorCode.toString() + ".html");
|
||||
} else {
|
||||
callback(config.wwwroot + "/." + errorCode.toString());
|
||||
callback("." + errorCode.toString());
|
||||
}
|
||||
} catch (err2) {
|
||||
res.error(500, err2);
|
||||
|
@ -371,21 +368,17 @@ function requestHandler(req, res) {
|
|||
}
|
||||
});
|
||||
} else {
|
||||
fs.access(
|
||||
config.wwwroot + "/." + errorCode.toString(),
|
||||
fs.constants.F_OK,
|
||||
(err) => {
|
||||
fs.access("." + errorCode.toString(), fs.constants.F_OK, (err) => {
|
||||
try {
|
||||
if (err) {
|
||||
callback(errorCode.toString() + ".html");
|
||||
} else {
|
||||
callback(config.wwwroot + "/." + errorCode.toString());
|
||||
callback("." + errorCode.toString());
|
||||
}
|
||||
} catch (err2) {
|
||||
res.error(500, err2);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -640,15 +633,15 @@ function requestHandler(req, res) {
|
|||
};
|
||||
|
||||
try {
|
||||
res.head = fs.existsSync(`${config.wwwroot}/.head`)
|
||||
? fs.readFileSync(`${config.wwwroot}/.head`).toString()
|
||||
: fs.existsSync(`${config.wwwroot}/head.html`)
|
||||
? fs.readFileSync(`${config.wwwroot}/head.html`).toString()
|
||||
res.head = fs.existsSync("./.head")
|
||||
? fs.readFileSync("./.head").toString()
|
||||
: fs.existsSync("./head.html")
|
||||
? fs.readFileSync("./head.html").toString()
|
||||
: ""; // header
|
||||
res.foot = fs.existsSync(`${config.wwwroot}/.foot`)
|
||||
? fs.readFileSync(`${config.wwwroot}/.foot`).toString()
|
||||
: fs.existsSync(`${config.wwwroot}/foot.html`)
|
||||
? fs.readFileSync(`${config.wwwroot}/foot.html`).toString()
|
||||
res.foot = fs.existsSync("./.foot")
|
||||
? fs.readFileSync("./.foot").toString()
|
||||
: fs.existsSync("./foot.html")
|
||||
? fs.readFileSync("./foot.html").toString()
|
||||
: ""; // footer
|
||||
} catch (err) {
|
||||
res.error(500, err);
|
||||
|
|
33
src/index.js
33
src/index.js
|
@ -117,7 +117,7 @@ if (process.versions) process.versions.svrjs = version; // Inject SVR.JS into pr
|
|||
function printUsage() {
|
||||
console.log(`${name} usage:`);
|
||||
console.log(
|
||||
"node svr.js [-h] [--help] [-?] [/h] [/?] [--secure] [--reset] [--clean] [--disable-mods] [--single-threaded] [--stdout-notty] [--no-save-config] [-v] [--version]"
|
||||
"node svr.js [-h] [--help] [-?] [/h] [/?] [--secure] [--reset] [--clean] [--disable-mods] [--single-threaded] [-v] [--version]"
|
||||
);
|
||||
console.log("-h -? /h /? --help -- Displays help");
|
||||
console.log("--clean -- Cleans up files created by " + name);
|
||||
|
@ -127,18 +127,12 @@ function printUsage() {
|
|||
console.log("--secure -- Runs HTTPS server");
|
||||
console.log("--disable-mods -- Disables mods (safe mode)");
|
||||
console.log("--single-threaded -- Run single-threaded");
|
||||
console.log(
|
||||
"--stdout-notty -- Enable stdout even when stdout is not a TTY. May decrease the performace"
|
||||
);
|
||||
console.log("--no-save-config -- Don't save configuration file");
|
||||
console.log("-v --version -- Display server version");
|
||||
}
|
||||
|
||||
let exiting = false;
|
||||
let forceSecure = false;
|
||||
let disableMods = false;
|
||||
let stdoutNoTTY = false;
|
||||
let noSaveConfig = false;
|
||||
|
||||
// Handle command line arguments
|
||||
const args = process.argv;
|
||||
|
@ -190,10 +184,6 @@ for (
|
|||
disableMods = true;
|
||||
} else if (args[i] == "--single-threaded") {
|
||||
process.singleThreaded = true;
|
||||
} else if (args[i] == "--stdout-notty") {
|
||||
stdoutNoTTY = true;
|
||||
} else if (args[i] == "--no-save-config") {
|
||||
noSaveConfig = true;
|
||||
} else {
|
||||
console.log(`Unrecognized argument: ${args[i]}`);
|
||||
printUsage();
|
||||
|
@ -339,11 +329,6 @@ if (process.serverConfig.allowPostfixDoubleSlashes === undefined)
|
|||
process.serverConfig.allowPostfixDoubleSlashes = false;
|
||||
if (process.serverConfig.optOutOfStatisticsServer === undefined)
|
||||
process.serverConfig.optOutOfStatisticsServer = false;
|
||||
if (process.serverConfig.disableConfigurationSaving === undefined)
|
||||
process.serverConfig.disableConfigurationSaving = false;
|
||||
|
||||
// Don't save configuration if disableConfigurationSaving option is set to true
|
||||
if (process.serverConfig.disableConfigurationSaving) noSaveConfig = true;
|
||||
|
||||
// Compatiblity for very old SVR.JS mods
|
||||
process.serverConfig.version = version;
|
||||
|
@ -400,7 +385,7 @@ try {
|
|||
// Failed to get inspector URL
|
||||
}
|
||||
|
||||
if (!stdoutNoTTY && !process.stdout.isTTY && !inspectorURL) {
|
||||
if (!process.stdout.isTTY && !inspectorURL) {
|
||||
// When stdout is not a terminal and not attached to an Node.JS inspector, disable it to improve performance of SVR.JS
|
||||
console.log = () => {};
|
||||
process.stdout.write = () => {};
|
||||
|
@ -812,11 +797,7 @@ if (!disableMods) {
|
|||
}
|
||||
|
||||
// Determine path of server-side script file
|
||||
let SSJSPath = `${
|
||||
process.serverConfig.wwwroot != undefined
|
||||
? process.serverConfig.wwwroot
|
||||
: process.dirname
|
||||
}/serverSideScript.js`;
|
||||
let SSJSPath = "./serverSideScript.js";
|
||||
if (!process.serverConfig.useWebRootServerSideScript)
|
||||
SSJSPath = process.dirname + "/serverSideScript.js";
|
||||
|
||||
|
@ -1705,8 +1686,6 @@ function saveConfig() {
|
|||
configJSONobj.allowDoubleSlashes = false;
|
||||
if (configJSONobj.optOutOfStatisticsServer === undefined)
|
||||
configJSONobj.optOutOfStatisticsServer = false;
|
||||
if (configJSONobj.disableConfigurationSaving === undefined)
|
||||
configJSONobj.disableConfigurationSaving = false;
|
||||
|
||||
fs.writeFileSync(
|
||||
process.dirname + "/config.json",
|
||||
|
@ -1999,7 +1978,6 @@ function start(init) {
|
|||
let workersToFork = 1;
|
||||
|
||||
if (cluster.isPrimary === undefined) {
|
||||
if (!noSaveConfig) {
|
||||
setInterval(() => {
|
||||
try {
|
||||
saveConfig();
|
||||
|
@ -2008,9 +1986,7 @@ function start(init) {
|
|||
throw new Error(err);
|
||||
}
|
||||
}, 300000);
|
||||
}
|
||||
} else if (cluster.isPrimary) {
|
||||
if (!noSaveConfig) {
|
||||
setInterval(() => {
|
||||
let allWorkers = Object.keys(cluster.workers);
|
||||
let goodWorkers = [];
|
||||
|
@ -2066,7 +2042,6 @@ function start(init) {
|
|||
});
|
||||
}, 300000);
|
||||
}
|
||||
}
|
||||
|
||||
if (!cluster.isPrimary && cluster.isPrimary !== undefined) {
|
||||
process.on("message", (line) => {
|
||||
|
@ -2454,7 +2429,7 @@ if (cluster.isPrimary || cluster.isPrimary === undefined) {
|
|||
|
||||
process.on("exit", (code) => {
|
||||
try {
|
||||
if (!configJSONRErr && !configJSONPErr && !noSaveConfig) {
|
||||
if (!configJSONRErr && !configJSONPErr) {
|
||||
saveConfig();
|
||||
}
|
||||
} catch (err) {
|
||||
|
|
|
@ -8,12 +8,8 @@ const {
|
|||
} = require("../utils/forbiddenPaths.js");
|
||||
const svrjsInfo = require("../../svrjs.json");
|
||||
const { name } = svrjsInfo;
|
||||
const wwwroot =
|
||||
process.serverConfig && process.serverConfig.wwwroot !== undefined
|
||||
? process.serverConfig.wwwroot
|
||||
: ".";
|
||||
|
||||
forbiddenPaths.config = getInitializePath(`${wwwroot}/config.json`);
|
||||
forbiddenPaths.config = getInitializePath("./config.json");
|
||||
forbiddenPaths.certificates = [];
|
||||
if (process.serverConfig.secure) {
|
||||
forbiddenPaths.certificates.push(
|
||||
|
@ -30,8 +26,7 @@ if (process.serverConfig.secure) {
|
|||
});
|
||||
}
|
||||
forbiddenPaths.svrjs = getInitializePath(
|
||||
wwwroot +
|
||||
"/" +
|
||||
"./" +
|
||||
(process.dirname[process.dirname.length - 1] != "/"
|
||||
? process.filename.replace(process.dirname + "/", "")
|
||||
: process.filename.replace(process.dirname, ""))
|
||||
|
@ -41,18 +36,16 @@ if (process.serverConfig.useWebRootServerSideScript) {
|
|||
forbiddenPaths.serverSideScripts.push("/serverSideScript.js");
|
||||
} else {
|
||||
forbiddenPaths.serverSideScripts.push(
|
||||
getInitializePath(`${wwwroot}/serverSideScript.js`)
|
||||
getInitializePath("./serverSideScript.js")
|
||||
);
|
||||
}
|
||||
forbiddenPaths.serverSideScriptDirectories = [];
|
||||
forbiddenPaths.serverSideScriptDirectories.push(
|
||||
getInitializePath(`${wwwroot}/node_modules`)
|
||||
getInitializePath("./node_modules")
|
||||
);
|
||||
forbiddenPaths.serverSideScriptDirectories.push(
|
||||
getInitializePath(wwwroot + "/mods")
|
||||
);
|
||||
forbiddenPaths.temp = getInitializePath(`${wwwroot}/temp`);
|
||||
forbiddenPaths.log = getInitializePath(`${wwwroot}/log`);
|
||||
forbiddenPaths.serverSideScriptDirectories.push(getInitializePath("./mods"));
|
||||
forbiddenPaths.temp = getInitializePath("./temp");
|
||||
forbiddenPaths.log = getInitializePath("./log");
|
||||
|
||||
module.exports = (req, res, logFacilities, config, next) => {
|
||||
let decodedHrefWithoutDuplicateSlashes = "";
|
||||
|
|
|
@ -9,9 +9,7 @@ module.exports = (req, res, logFacilities, config, next) => {
|
|||
req.originalParsedURL.pathname[req.originalParsedURL.pathname.length - 1] !=
|
||||
"/"
|
||||
) {
|
||||
fs.stat(
|
||||
config.wwwroot + decodeURIComponent(req.parsedURL.pathname),
|
||||
(err, stats) => {
|
||||
fs.stat("." + decodeURIComponent(req.parsedURL.pathname), (err, stats) => {
|
||||
if (err || !stats.isDirectory()) {
|
||||
try {
|
||||
next();
|
||||
|
@ -26,8 +24,7 @@ module.exports = (req, res, logFacilities, config, next) => {
|
|||
(req.parsedURL.hash ? req.parsedURL.hash : "")
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ module.exports = (req, res, logFacilities, config, next) => {
|
|||
!_fileState
|
||||
) {
|
||||
fs.stat(
|
||||
config.wwwroot + decodeURIComponent(req.parsedURL.pathname),
|
||||
"." + decodeURIComponent(req.parsedURL.pathname),
|
||||
(err, stats) => {
|
||||
let _fileState = 3;
|
||||
if (err) {
|
||||
|
|
|
@ -86,7 +86,7 @@ module.exports = (req, res, logFacilities, config, next) => {
|
|||
res.error(400);
|
||||
return;
|
||||
}
|
||||
let readFrom = config.wwwroot + dHref;
|
||||
let readFrom = "." + dHref;
|
||||
let dirImagesMissing = false;
|
||||
fs.stat(readFrom, (err, stats) => {
|
||||
if (err) {
|
||||
|
@ -502,16 +502,13 @@ module.exports = (req, res, logFacilities, config, next) => {
|
|||
|
||||
const getCustomDirListingHeader = (callback) => {
|
||||
fs.readFile(
|
||||
(config.wwwroot + dHref + "/.dirhead").replace(/\/+/g, "/"),
|
||||
("." + dHref + "/.dirhead").replace(/\/+/g, "/"),
|
||||
(err, data) => {
|
||||
if (err) {
|
||||
if (err.code == "ENOENT" || err.code == "EISDIR") {
|
||||
if (os.platform != "win32" || href != "/") {
|
||||
fs.readFile(
|
||||
(config.wwwroot + dHref + "/HEAD.html").replace(
|
||||
/\/+/g,
|
||||
"/"
|
||||
),
|
||||
("." + dHref + "/HEAD.html").replace(/\/+/g, "/"),
|
||||
(err, data) => {
|
||||
if (err) {
|
||||
if (err.code == "ENOENT" || err.code == "EISDIR") {
|
||||
|
@ -541,16 +538,13 @@ module.exports = (req, res, logFacilities, config, next) => {
|
|||
|
||||
const getCustomDirListingFooter = (callback) => {
|
||||
fs.readFile(
|
||||
(config.wwwroot + dHref + "/.dirfoot").replace(/\/+/g, "/"),
|
||||
("." + dHref + "/.dirfoot").replace(/\/+/g, "/"),
|
||||
(err, data) => {
|
||||
if (err) {
|
||||
if (err.code == "ENOENT" || err.code == "EISDIR") {
|
||||
if (os.platform != "win32" || href != "/") {
|
||||
fs.readFile(
|
||||
(config.wwwroot + dHref + "/FOOT.html").replace(
|
||||
/\/+/g,
|
||||
"/"
|
||||
),
|
||||
("." + dHref + "/FOOT.html").replace(/\/+/g, "/"),
|
||||
(err, data) => {
|
||||
if (err) {
|
||||
if (err.code == "ENOENT" || err.code == "EISDIR") {
|
||||
|
@ -652,7 +646,7 @@ module.exports = (req, res, logFacilities, config, next) => {
|
|||
|
||||
if (
|
||||
fs.existsSync(
|
||||
config.wwwroot +
|
||||
"." +
|
||||
decodeURIComponent(href) +
|
||||
"/.maindesc".replace(/\/+/g, "/")
|
||||
)
|
||||
|
@ -660,7 +654,7 @@ module.exports = (req, res, logFacilities, config, next) => {
|
|||
htmlFoot =
|
||||
"</table><hr/>" +
|
||||
fs.readFileSync(
|
||||
config.wwwroot +
|
||||
"." +
|
||||
decodeURIComponent(href) +
|
||||
"/.maindesc".replace(/\/+/g, "/")
|
||||
) +
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
{
|
||||
"version": "Nightly-GitNext",
|
||||
"version": "4.1.0",
|
||||
"name": "SVR.JS",
|
||||
"documentationURL": "https://svrjs.org/docs",
|
||||
"statisticsServerCollectEndpoint": "https://statistics.svrjs.org/collect.svr",
|
||||
"changes": [
|
||||
"INSERT CHANGES THERE"
|
||||
"Added experimental support for Deno 2."
|
||||
]
|
||||
}
|
||||
|
|
|
@ -73,8 +73,7 @@
|
|||
"disableTrailingSlashRedirects": false,
|
||||
"environmentVariables": {},
|
||||
"allowDoubleSlashes": false,
|
||||
"optOutOfStatisticsServer": false,
|
||||
"disableConfigurationSaving": false
|
||||
"optOutOfStatisticsServer": false
|
||||
}</pre>
|
||||
</code>
|
||||
<p>Changes:</p>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
const middleware = require("../../src/utils/ipBlockList.js");
|
||||
const cluster = require("../../src/utils/clusterShim.js");
|
||||
const cluster = require("../../src/utils/clusterBunShim.js");
|
||||
|
||||
jest.mock("../../src/utils/ipBlockList.js");
|
||||
jest.mock("../../src/utils/clusterShim.js");
|
||||
jest.mock("../../src/utils/clusterBunShim.js");
|
||||
|
||||
const ipBlockListAdd = jest.fn();
|
||||
const ipBlockListCheck = jest.fn();
|
||||
|
|
|
@ -2,13 +2,13 @@ const sha256 = require("../../src/utils/sha256.js");
|
|||
const ipMatch = require("../../src/utils/ipMatch.js");
|
||||
const matchHostname = require("../../src/utils/matchHostname.js");
|
||||
const ipBlockList = require("../../src/utils/ipBlockList.js");
|
||||
const cluster = require("../../src/utils/clusterShim.js");
|
||||
const cluster = require("../../src/utils/clusterBunShim.js");
|
||||
|
||||
jest.mock("../../src/utils/sha256.js");
|
||||
jest.mock("../../src/utils/ipMatch.js");
|
||||
jest.mock("../../src/utils/matchHostname.js");
|
||||
jest.mock("../../src/utils/ipBlockList.js");
|
||||
jest.mock("../../src/utils/clusterShim.js");
|
||||
jest.mock("../../src/utils/clusterBunShim.js");
|
||||
|
||||
let mockScryptHash = "mocked-scrypt-hash";
|
||||
let mockPbkdf2Hash = "mocked-pbkdf2-hash";
|
||||
|
|
Reference in a new issue