mirror of
https://github.com/Wolvan/poll.horse.git
synced 2025-02-16 17:54:22 +01:00
Create rudimentary poll backend
This is currently untested, but the backend allows creating a new poll, getting results of an existing poll, voting and retrieving info of a poll for display purposes. Recaptcha is not yet implemented at this stage.
This commit is contained in:
parent
8c3001042b
commit
9d80a009ca
5 changed files with 238 additions and 4 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -110,4 +110,6 @@ testing/
|
||||||
*.sqlite
|
*.sqlite
|
||||||
*.sqlite3
|
*.sqlite3
|
||||||
*.db
|
*.db
|
||||||
*.db3
|
*.db3
|
||||||
|
# Data directory
|
||||||
|
data/
|
76
package-lock.json
generated
76
package-lock.json
generated
|
@ -11,16 +11,20 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"commander": "^8.3.0",
|
"commander": "^8.3.0",
|
||||||
"compression": "^1.7.4",
|
"compression": "^1.7.4",
|
||||||
"express": "^4.17.2"
|
"cookie-parser": "^1.4.6",
|
||||||
|
"express": "^4.17.2",
|
||||||
|
"node-persist": "^3.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/chai": "^4.2.22",
|
"@types/chai": "^4.2.22",
|
||||||
"@types/chai-as-promised": "^7.1.4",
|
"@types/chai-as-promised": "^7.1.4",
|
||||||
"@types/compression": "^1.7.2",
|
"@types/compression": "^1.7.2",
|
||||||
|
"@types/cookie-parser": "^1.4.2",
|
||||||
"@types/express": "^4.17.13",
|
"@types/express": "^4.17.13",
|
||||||
"@types/fs-extra": "^9.0.13",
|
"@types/fs-extra": "^9.0.13",
|
||||||
"@types/mocha": "^9.0.0",
|
"@types/mocha": "^9.0.0",
|
||||||
"@types/node": "^16.11.10",
|
"@types/node": "^16.11.10",
|
||||||
|
"@types/node-persist": "^3.1.2",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
||||||
"@typescript-eslint/parser": "^5.4.0",
|
"@typescript-eslint/parser": "^5.4.0",
|
||||||
"chai": "^4.3.4",
|
"chai": "^4.3.4",
|
||||||
|
@ -199,6 +203,15 @@
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/cookie-parser": {
|
||||||
|
"version": "1.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.2.tgz",
|
||||||
|
"integrity": "sha512-uwcY8m6SDQqciHsqcKDGbo10GdasYsPCYkH3hVegj9qAah6pX5HivOnOuI3WYmyQMnOATV39zv/Ybs0bC/6iVg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/express": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/express": {
|
"node_modules/@types/express": {
|
||||||
"version": "4.17.13",
|
"version": "4.17.13",
|
||||||
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz",
|
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz",
|
||||||
|
@ -255,6 +268,15 @@
|
||||||
"integrity": "sha512-3aRnHa1KlOEEhJ6+CvyHKK5vE9BcLGjtUpwvqYLRvYNQKMfabu3BwfJaA/SLW8dxe28LsNDjtHwePTuzn3gmOA==",
|
"integrity": "sha512-3aRnHa1KlOEEhJ6+CvyHKK5vE9BcLGjtUpwvqYLRvYNQKMfabu3BwfJaA/SLW8dxe28LsNDjtHwePTuzn3gmOA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/node-persist": {
|
||||||
|
"version": "3.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node-persist/-/node-persist-3.1.2.tgz",
|
||||||
|
"integrity": "sha512-aLFUB1951wOfR+tZ4f3TudLPblo9+PfnduMh6feuOTijD0Q6YkMdqPXSgQIjI23FGmCuoZaIZ9x6cvEG/TdiSg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/qs": {
|
"node_modules/@types/qs": {
|
||||||
"version": "6.9.7",
|
"version": "6.9.7",
|
||||||
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
|
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
|
||||||
|
@ -926,6 +948,18 @@
|
||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/cookie-parser": {
|
||||||
|
"version": "1.4.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz",
|
||||||
|
"integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==",
|
||||||
|
"dependencies": {
|
||||||
|
"cookie": "0.4.1",
|
||||||
|
"cookie-signature": "1.0.6"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/cookie-signature": {
|
"node_modules/cookie-signature": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
||||||
|
@ -2164,6 +2198,14 @@
|
||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/node-persist": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-persist/-/node-persist-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-/j+fd/u71wNgKf3V2bx4tnDm+3GvLnlCuvf2MXbJ3wern+67IAb6zN9Leu1tCWPlPNZ+v1hLSibVukkPK2HqJw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/normalize-path": {
|
"node_modules/normalize-path": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||||
|
@ -3201,6 +3243,15 @@
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/cookie-parser": {
|
||||||
|
"version": "1.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.2.tgz",
|
||||||
|
"integrity": "sha512-uwcY8m6SDQqciHsqcKDGbo10GdasYsPCYkH3hVegj9qAah6pX5HivOnOuI3WYmyQMnOATV39zv/Ybs0bC/6iVg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/express": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/express": {
|
"@types/express": {
|
||||||
"version": "4.17.13",
|
"version": "4.17.13",
|
||||||
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz",
|
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz",
|
||||||
|
@ -3257,6 +3308,15 @@
|
||||||
"integrity": "sha512-3aRnHa1KlOEEhJ6+CvyHKK5vE9BcLGjtUpwvqYLRvYNQKMfabu3BwfJaA/SLW8dxe28LsNDjtHwePTuzn3gmOA==",
|
"integrity": "sha512-3aRnHa1KlOEEhJ6+CvyHKK5vE9BcLGjtUpwvqYLRvYNQKMfabu3BwfJaA/SLW8dxe28LsNDjtHwePTuzn3gmOA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@types/node-persist": {
|
||||||
|
"version": "3.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node-persist/-/node-persist-3.1.2.tgz",
|
||||||
|
"integrity": "sha512-aLFUB1951wOfR+tZ4f3TudLPblo9+PfnduMh6feuOTijD0Q6YkMdqPXSgQIjI23FGmCuoZaIZ9x6cvEG/TdiSg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/qs": {
|
"@types/qs": {
|
||||||
"version": "6.9.7",
|
"version": "6.9.7",
|
||||||
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
|
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
|
||||||
|
@ -3748,6 +3808,15 @@
|
||||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz",
|
||||||
"integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA=="
|
"integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA=="
|
||||||
},
|
},
|
||||||
|
"cookie-parser": {
|
||||||
|
"version": "1.4.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz",
|
||||||
|
"integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==",
|
||||||
|
"requires": {
|
||||||
|
"cookie": "0.4.1",
|
||||||
|
"cookie-signature": "1.0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"cookie-signature": {
|
"cookie-signature": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
||||||
|
@ -4680,6 +4749,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
|
||||||
"integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
|
"integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
|
||||||
},
|
},
|
||||||
|
"node-persist": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-persist/-/node-persist-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-/j+fd/u71wNgKf3V2bx4tnDm+3GvLnlCuvf2MXbJ3wern+67IAb6zN9Leu1tCWPlPNZ+v1hLSibVukkPK2HqJw=="
|
||||||
|
},
|
||||||
"normalize-path": {
|
"normalize-path": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||||
|
|
|
@ -35,10 +35,12 @@
|
||||||
"@types/chai": "^4.2.22",
|
"@types/chai": "^4.2.22",
|
||||||
"@types/chai-as-promised": "^7.1.4",
|
"@types/chai-as-promised": "^7.1.4",
|
||||||
"@types/compression": "^1.7.2",
|
"@types/compression": "^1.7.2",
|
||||||
|
"@types/cookie-parser": "^1.4.2",
|
||||||
"@types/express": "^4.17.13",
|
"@types/express": "^4.17.13",
|
||||||
"@types/fs-extra": "^9.0.13",
|
"@types/fs-extra": "^9.0.13",
|
||||||
"@types/mocha": "^9.0.0",
|
"@types/mocha": "^9.0.0",
|
||||||
"@types/node": "^16.11.10",
|
"@types/node": "^16.11.10",
|
||||||
|
"@types/node-persist": "^3.1.2",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
||||||
"@typescript-eslint/parser": "^5.4.0",
|
"@typescript-eslint/parser": "^5.4.0",
|
||||||
"chai": "^4.3.4",
|
"chai": "^4.3.4",
|
||||||
|
@ -56,6 +58,8 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"commander": "^8.3.0",
|
"commander": "^8.3.0",
|
||||||
"compression": "^1.7.4",
|
"compression": "^1.7.4",
|
||||||
"express": "^4.17.2"
|
"cookie-parser": "^1.4.6",
|
||||||
|
"express": "^4.17.2",
|
||||||
|
"node-persist": "^3.1.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
153
src/backend.ts
153
src/backend.ts
|
@ -1,7 +1,158 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
import { Router } from "express";
|
import { Router } from "express";
|
||||||
|
import persist from "node-persist";
|
||||||
|
import { program } from "commander";
|
||||||
|
|
||||||
export default function init(router: Router): void {
|
type Poll = {
|
||||||
|
id: string,
|
||||||
|
title: string,
|
||||||
|
options: {
|
||||||
|
[option: string]: number
|
||||||
|
},
|
||||||
|
dupeCheckMode: "none" | "ip" | "cookie",
|
||||||
|
dupeData: null | string[] | string,
|
||||||
|
multiSelect: boolean,
|
||||||
|
captcha: boolean,
|
||||||
|
creationTime: Date,
|
||||||
|
};
|
||||||
|
|
||||||
|
function randomString(length = 10, charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") {
|
||||||
|
let result = "";
|
||||||
|
for (let i = 0; i < length; i++) {
|
||||||
|
result += charset.charAt(Math.floor(Math.random() * charset.length));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function init(router: Router): Promise<void> {
|
||||||
|
const polls = await persist.create({
|
||||||
|
dir: program.opts().dataDirectory
|
||||||
|
});
|
||||||
|
await polls.init();
|
||||||
|
|
||||||
|
router.get("/poll/:id", async (req, res) => {
|
||||||
|
try {
|
||||||
|
const id = req.params.id;
|
||||||
|
const poll: (Poll | undefined) = await polls.getItem(id);
|
||||||
|
if (!poll) return res.status(404).json({ error: "Poll not found" });
|
||||||
|
res.json(Object.assign({}, poll, {
|
||||||
|
options: Object.keys(poll.options),
|
||||||
|
dupeData: null
|
||||||
|
}));
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
if (error instanceof Error) res.status(500).json({
|
||||||
|
error: error.message
|
||||||
|
});
|
||||||
|
else res.status(500).json({
|
||||||
|
error: error
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get("/poll-result/:id", async (req, res) => {
|
||||||
|
try {
|
||||||
|
const id = req.params.id;
|
||||||
|
const poll: (Poll | undefined) = await polls.getItem(id);
|
||||||
|
if (!poll) return res.status(404).json({ error: "Poll not found" });
|
||||||
|
res.json({
|
||||||
|
title: poll.title,
|
||||||
|
votes: poll.options
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
if (error instanceof Error) res.status(500).json({
|
||||||
|
error: error.message
|
||||||
|
});
|
||||||
|
else res.status(500).json({
|
||||||
|
error: error
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post("/poll", async (req, res) => {
|
||||||
|
try {
|
||||||
|
const options = req.body.options;
|
||||||
|
if (!Array.isArray(options) || options.filter(i => i).length < 2)
|
||||||
|
return res.status(400).json({ error: "Options must be an array and have at least 2 entries" });
|
||||||
|
let id = randomString(6);
|
||||||
|
while (await polls.getItem(id)) id = randomString(6);
|
||||||
|
await polls.setItem(id, {});
|
||||||
|
const dupeCheckMode = ["none", "ip", "cookie"].includes(req.body.dupeCheckMode) ? req.body.dupeCheckMode : "ip";
|
||||||
|
const dupeData =
|
||||||
|
dupeCheckMode === "none" ? null :
|
||||||
|
dupeCheckMode === "ip" ? [] :
|
||||||
|
dupeCheckMode === "cookie" ? randomString(16) : null;
|
||||||
|
const poll: Poll = {
|
||||||
|
id,
|
||||||
|
title: req.body.title || "",
|
||||||
|
options: (() => {
|
||||||
|
const result: { [option: string]: number } = {};
|
||||||
|
for (const option of options) {
|
||||||
|
result[option] = 0;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
})(),
|
||||||
|
dupeCheckMode,
|
||||||
|
dupeData,
|
||||||
|
multiSelect: req.body.multiSelect || false,
|
||||||
|
captcha: req.body.captcha || false,
|
||||||
|
creationTime: new Date()
|
||||||
|
};
|
||||||
|
await polls.setItem(id, poll);
|
||||||
|
res.json({
|
||||||
|
id: id
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
if (error instanceof Error) res.status(500).json({
|
||||||
|
error: error.message
|
||||||
|
});
|
||||||
|
else res.status(500).json({
|
||||||
|
error: error
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post("/vote/:id", async (req, res) => {
|
||||||
|
try {
|
||||||
|
const id = req.params.id;
|
||||||
|
const poll: (Poll | undefined) = await polls.getItem(id);
|
||||||
|
if (!poll) return res.status(404).json({ error: "Poll not found" });
|
||||||
|
|
||||||
|
const votes = req.body.votes;
|
||||||
|
const possibleVotes = Object.keys(poll.options);
|
||||||
|
if (!Array.isArray(votes) || votes.filter(i => i && possibleVotes.includes(i)).length < 1)
|
||||||
|
return res.status(400).json({ error: "Votes must be an array and have at least 1 entry" });
|
||||||
|
if (!poll.multiSelect && votes.filter(i => i && possibleVotes.includes(i)).length > 1)
|
||||||
|
return res.status(400).json({ error: "Single-select polls can only have one vote" });
|
||||||
|
|
||||||
|
if (poll.dupeCheckMode === "ip") {
|
||||||
|
const ip = req.headers["x-forwarded-for"] || req.socket.remoteAddress || "";
|
||||||
|
if (Array.isArray(poll.dupeData) && poll.dupeData.includes(ip as string)) return res.status(200).json({ status: "ok", id });
|
||||||
|
if (Array.isArray(poll.dupeData)) poll.dupeData.push(ip as string);
|
||||||
|
} else if (poll.dupeCheckMode === "cookie") {
|
||||||
|
const cookie = req.cookies[poll.dupeData as string];
|
||||||
|
if (cookie) return res.status(200).json({ status: "ok", id });
|
||||||
|
res.cookie(poll.dupeData as string, "1", {
|
||||||
|
httpOnly: true,
|
||||||
|
maxAge: (1000 * 60 * 60 * 24 * 365) / 2
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
votes.filter(i => i && possibleVotes.includes(i)).forEach(vote => poll.options[vote]++);
|
||||||
|
await polls.setItem(id, poll);
|
||||||
|
|
||||||
|
res.json({ status: "ok", id });
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
if (error instanceof Error) res.status(500).json({
|
||||||
|
error: error.message
|
||||||
|
});
|
||||||
|
else res.status(500).json({
|
||||||
|
error: error
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
|
@ -4,12 +4,14 @@ import loadConfig from "./config-loader";
|
||||||
import { program } from "commander";
|
import { program } from "commander";
|
||||||
import express from "express";
|
import express from "express";
|
||||||
import compression from "compression";
|
import compression from "compression";
|
||||||
|
import cookiepaser from "cookie-parser";
|
||||||
import { resolve } from "path";
|
import { resolve } from "path";
|
||||||
|
|
||||||
async function main(): Promise<void> {
|
async function main(): Promise<void> {
|
||||||
await loadConfig([
|
await loadConfig([
|
||||||
["--no-frontend", "Do not start the frontend server"],
|
["--no-frontend", "Do not start the frontend server"],
|
||||||
["--no-backend", "Do not start the backend server"],
|
["--no-backend", "Do not start the backend server"],
|
||||||
|
["-d, --data-directory <path>", "Path to the data directory", "../data"],
|
||||||
["-p, --port <port>", "Port to listen on", (port: any) => parseInt(port), 6969],
|
["-p, --port <port>", "Port to listen on", (port: any) => parseInt(port), 6969],
|
||||||
["--backend-base-url <url>", "Base URL for the backend server", null],
|
["--backend-base-url <url>", "Base URL for the backend server", null],
|
||||||
], ".poll-horse-config");
|
], ".poll-horse-config");
|
||||||
|
@ -18,6 +20,7 @@ async function main(): Promise<void> {
|
||||||
const app = express();
|
const app = express();
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
app.use(compression());
|
app.use(compression());
|
||||||
|
app.use(cookiepaser());
|
||||||
|
|
||||||
if (opts.backend) {
|
if (opts.backend) {
|
||||||
console.log(`Mounting backend`);
|
console.log(`Mounting backend`);
|
||||||
|
|
Loading…
Reference in a new issue