Pārlūkot izejas kodu

Merge pull request #798 from thedevs-network/develop

Remove unused dependencies, misc. small fixes
Pouria Ezzati 11 mēneši atpakaļ
vecāks
revīzija
c8f96485d5

+ 8 - 9
docs/api/generate.js

@@ -1,6 +1,5 @@
-const { join, dirname } = require("path");
-
-const { promises: fs } = require("fs");
+const { join, dirname } = require("node:path");
+const { promises: fs } = require("node:fs");
 
 const api = require("./api");
 
@@ -26,19 +25,19 @@ const Api = output =>
 
 const Redoc = output =>
 	fs.copyFile(join(
-		dirname(require.resolve('redoc')), 
-		'redoc.standalone.js'),
+		dirname(require.resolve("redoc")),
+		"redoc.standalone.js"),
 		output);
 
 module.exports = (async () => {
-	const out = join(__dirname, 'static');
-	const apiFile = 'api.json';
-	const redocFile = 'redoc.js';
+	const out = join(__dirname, "static");
+	const apiFile = "api.json";
+	const redocFile = "redoc.js";
 	await fs.mkdir(out, { recursive: true });
 	return Promise.all([
 		Api(join(out, apiFile)),
 		Redoc(join(out, redocFile)),
-		Template(join(out, 'index.html'), {
+		Template(join(out, "index.html"), {
 			api: apiFile,
 			title: api.info.title,
 			redoc: redocFile

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 29 - 697
package-lock.json


+ 6 - 11
package.json

@@ -1,11 +1,11 @@
 {
   "name": "kutt",
-  "version": "3.1.2",
+  "version": "3.2.0",
   "description": "Modern URL shortener.",
   "main": "./server/server.js",
   "scripts": {
-    "dev": "cross-env NODE_ENV=development node --watch-path=./server --watch-path=./custom server/server.js",
-    "start": "cross-env NODE_ENV=production node server/server.js",
+    "dev": "node --watch-path=./server --watch-path=./custom server/server.js",
+    "start": "node server/server.js --production",
     "migrate": "knex migrate:latest",
     "migrate:make": "knex migrate:make",
     "docs:build": "cd docs/api && node generate && cd ../.."
@@ -25,12 +25,12 @@
   "homepage": "https://github.com/thedevs-network/kutt#readme",
   "dependencies": {
     "bcryptjs": "2.4.3",
+    "better-sqlite3": "11.8.1",
     "bull": "4.16.5",
     "cookie-parser": "1.4.7",
     "cors": "2.8.5",
-    "cross-env": "7.0.3",
     "date-fns": "2.30.0",
-    "dotenv": "16.0.3",
+    "dotenv": "16.4.7",
     "envalid": "8.0.0",
     "express": "4.21.2",
     "express-rate-limit": "7.5.0",
@@ -45,8 +45,6 @@
     "ms": "2.1.3",
     "mysql2": "3.12.0",
     "nanoid": "3.3.8",
-    "node-cron": "3.0.3",
-    "node-mailer": "0.1.1",
     "nodemailer": "6.9.16",
     "passport": "0.7.0",
     "passport-jwt": "4.0.1",
@@ -55,9 +53,7 @@
     "pg": "8.13.1",
     "pg-query-stream": "4.7.1",
     "rate-limit-redis": "4.2.0",
-    "sqlite3": "5.1.7",
-    "useragent": "2.3.0",
-    "uuid": "10.0.0"
+    "useragent": "2.3.0"
   },
   "devDependencies": {
     "@types/bcryptjs": "2.4.2",
@@ -68,7 +64,6 @@
     "@types/jsonwebtoken": "7.2.8",
     "@types/ms": "0.7.31",
     "@types/node": "18.11.9",
-    "@types/node-cron": "2.0.2",
     "@types/nodemailer": "6.4.6",
     "@types/pg": "8.11.10",
     "redoc": "2.2.0"

+ 2 - 5
server/cron.js

@@ -1,10 +1,7 @@
-const cron = require("node-cron");
-
 const query = require("./queries");
 const utils = require("./utils");
-const env = require("./env");
 
 // check and delete links 30 secoonds
-cron.schedule("*/30 * * * * *", function() {
+setInterval(function () {
   query.link.batchRemove({ expire_in: ["<", utils.dateToUTC(new Date())] }).catch();
-});
+}, 30_000);

+ 6 - 1
server/env.js

@@ -20,6 +20,11 @@ if (process.env.JWT_SECRET === "") {
   delete process.env.JWT_SECRET;
 }
 
+// if is started with the --production argument, then set NODE_ENV to production
+if (process.argv.includes("--production")) {
+  process.env.NODE_ENV = "production";
+}
+
 const env = cleanEnv(process.env, {
   PORT: num({ default: 3000 }),
   SITE_NAME: str({ example: "Kutt", default: "Kutt" }),
@@ -27,7 +32,7 @@ const env = cleanEnv(process.env, {
   LINK_LENGTH: num({ default: 6 }),
   LINK_CUSTOM_ALPHABET: str({ default: "abcdefghkmnpqrstuvwxyzABCDEFGHKLMNPQRSTUVWXYZ23456789" }),
   TRUST_PROXY: bool({ default: true }),
-  DB_CLIENT: str({ choices: supportedDBClients, default: "sqlite3" }),
+  DB_CLIENT: str({ choices: supportedDBClients, default: "better-sqlite3" }),
   DB_FILENAME: str({ default: "db/data" }),
   DB_HOST: str({ default: "localhost" }),
   DB_PORT: num({ default: 5432 }),

+ 4 - 4
server/handlers/auth.handler.js

@@ -1,7 +1,7 @@
-const { differenceInDays, differenceInMinutes, addMinutes, subMinutes } = require("date-fns");
+const { differenceInDays, addMinutes } = require("date-fns");
 const { nanoid } = require("nanoid");
 const passport = require("passport");
-const { v4: uuid } = require("uuid");
+const { randomUUID } = require("node:crypto");
 const bcrypt = require("bcryptjs");
 
 const { ROLES } = require("../consts");
@@ -227,7 +227,7 @@ async function resetPassword(req, res) {
   const user = await query.user.update(
     { email: req.body.email },
     {
-      reset_password_token: uuid(),
+      reset_password_token: randomUUID(),
       reset_password_expires: utils.dateToUTC(addMinutes(new Date(), 30))
     }
   );
@@ -298,7 +298,7 @@ async function changeEmailRequest(req, res) {
     { id: req.user.id },
     {
       change_email_address: email,
-      change_email_token: uuid(),
+      change_email_token: randomUUID(),
       change_email_expires: utils.dateToUTC(addMinutes(new Date(), 30))
     }
   );

+ 3 - 3
server/handlers/links.handler.js

@@ -1,9 +1,9 @@
 const { differenceInSeconds } = require("date-fns");
-const promisify = require("util").promisify;
+const promisify = require("node:util").promisify;
 const bcrypt = require("bcryptjs");
 const { isbot } = require("isbot");
-const URL = require("url");
-const dns = require("dns");
+const URL = require("node:url");
+const dns = require("node:dns");
 
 const validators = require("./validators.handler");
 const map = require("../utils/map.json");

+ 4 - 4
server/handlers/validators.handler.js

@@ -1,9 +1,9 @@
-const { isAfter, subDays, subHours, addMilliseconds, differenceInHours } = require("date-fns");
+const { addMilliseconds } = require("date-fns");
 const { body, param, query: queryValidator } = require("express-validator");
-const promisify = require("util").promisify;
+const promisify = require("node:util").promisify;
 const bcrypt = require("bcryptjs");
-const dns = require("dns");
-const URL = require("url");
+const dns = require("node:dns");
+const URL = require("node:url");
 const ms = require("ms");
 
 const { ROLES } = require("../consts");

+ 2 - 2
server/mail/mail.js

@@ -1,6 +1,6 @@
 const nodemailer = require("nodemailer");
-const path = require("path");
-const fs = require("fs");
+const path = require("node:path");
+const fs = require("node:fs");
 
 const { resetMailText, verifyMailText, changeEmailText } = require("./text");
 const { CustomError } = require("../utils");

+ 4 - 4
server/queries/user.queries.js

@@ -1,5 +1,5 @@
 const { addMinutes } = require("date-fns");
-const { v4: uuid } = require("uuid");
+const { randomUUID } = require("node:crypto");
 
 const { ROLES } = require("../consts");
 const utils = require("../utils");
@@ -42,7 +42,7 @@ async function add(params, user) {
     password: params.password,
     ...(params.role && { role: params.role }),
     ...(params.verified !== undefined && { verified: params.verified }),
-    verification_token: uuid(),
+    verification_token: randomUUID(),
     verification_expires: utils.dateToUTC(addMinutes(new Date(), 60))
   };
   
@@ -72,7 +72,7 @@ async function update(match, update, methods) {
     });
 
     const user = await query.select("id").first();
-    if (!user) return null;
+    if (!user) return {};
     
     const updateQuery = trx("users").where("id", user.id);
     if (methods?.increments) {
@@ -180,7 +180,7 @@ async function getAdmin(match, params) {
 async function totalAdmin(match, params) {
   const query = knex("users")
     .count("* as count")
-    .fromRaw('users')
+    .fromRaw("users")
     .where(normalizeMatch(match));
 
   if (params?.search) {

+ 3 - 3
server/queues/queues.js

@@ -1,5 +1,5 @@
 const Queue = require("bull");
-const path = require("path");
+const path = require("node:path");
 
 const env = require("../env");
 
@@ -19,8 +19,8 @@ if (env.REDIS_ENABLED) {
   visit.on("completed", job => job.remove());
   
   // TODO: handler error
-  // visit.on('error', function (error) {
-  //   console.log('error');
+  // visit.on("error", function (error) {
+  //   console.log("error");
   // });
 } else {
   const visitProcessor = require(path.resolve(__dirname, "visit.js"));

+ 1 - 1
server/queues/visit.js

@@ -1,6 +1,6 @@
 const useragent = require("useragent");
 const geoip = require("geoip-lite");
-const URL = require("url");
+const URL = require("node:url");
 
 const { removeWww } = require("../utils");
 const query = require("../queries");

+ 1 - 1
server/server.js

@@ -4,7 +4,7 @@ const cookieParser = require("cookie-parser");
 const passport = require("passport");
 const express = require("express");
 const helmet = require("helmet");
-const path = require("path");
+const path = require("node:path");
 const hbs = require("hbs");
 
 const helpers = require("./handlers/helpers.handler");

+ 1 - 1
server/utils/utils.js

@@ -360,7 +360,7 @@ function registerHandlebarsHelpers() {
   });
 
   hbs.registerHelper("block", function(name) {
-      const val = (blocks[name] || []).join('\n');
+      const val = (blocks[name] || []).join("\n");
       blocks[name] = [];
       return val;
   });

+ 56 - 56
static/scripts/main.js

@@ -2,7 +2,7 @@
 // htmx.logAll();
 
 // add text/html accept header to receive html instead of json for the requests
-document.body.addEventListener('htmx:configRequest', function(evt) {
+document.body.addEventListener("htmx:configRequest", function(evt) {
   evt.detail.headers["Accept"] = "text/html,*/*";
 });
 
@@ -21,8 +21,8 @@ function resetForm(id) {
     form.reset();
   }
 }
-document.body.addEventListener('resetChangePasswordForm', resetForm("change-password"));
-document.body.addEventListener('resetChangeEmailForm', resetForm("change-email"));
+document.body.addEventListener("resetChangePasswordForm", resetForm("change-password"));
+document.body.addEventListener("resetChangeEmailForm", resetForm("change-email"));
 
 // an htmx extension to use the specifed params in the path instead of the query or body
 htmx.defineExtension("path-params", {
@@ -31,7 +31,7 @@ htmx.defineExtension("path-params", {
       evt.detail.path = evt.detail.path.replace(/{([^}]+)}/g, function(_, param) {
         var val = evt.detail.parameters[param]
         delete evt.detail.parameters[param]
-        return val === undefined ? '{' + param + '}' : encodeURIComponent(val)
+        return val === undefined ? "{" + param + "}" : encodeURIComponent(val)
       })
     }
   }
@@ -145,8 +145,8 @@ window.addEventListener("click", function(event) {
 
 // handle navigation in the table of links
 function setLinksLimit(event) {
-  const buttons = Array.from(document.querySelectorAll('table .nav .limit button'));
-  const limitInput = document.querySelector('#limit');
+  const buttons = Array.from(document.querySelectorAll("table .nav .limit button"));
+  const limitInput = document.querySelector("#limit");
   if (!limitInput || !buttons || !buttons.length) return;
   limitInput.value = event.target.textContent;
   buttons.forEach(b => {
@@ -155,56 +155,56 @@ function setLinksLimit(event) {
 }
 
 function setLinksSkip(event, action) {
-  const buttons = Array.from(document.querySelectorAll('table .nav .pagination button'));
-  const limitElm = document.querySelector('#limit');
-  const totalElm = document.querySelector('#total');
-  const skipElm = document.querySelector('#skip');
+  const buttons = Array.from(document.querySelectorAll("table .nav .pagination button"));
+  const limitElm = document.querySelector("#limit");
+  const totalElm = document.querySelector("#total");
+  const skipElm = document.querySelector("#skip");
   if (!buttons || !limitElm || !totalElm || !skipElm) return;
   const skip = parseInt(skipElm.value);
   const limit = parseInt(limitElm.value);
   const total = parseInt(totalElm.value);
   skipElm.value = action === "next" ? skip + limit : Math.max(skip - limit, 0);
-  document.querySelectorAll('.pagination .next').forEach(elm => {
+  document.querySelectorAll(".pagination .next").forEach(elm => {
     elm.disabled = total <= parseInt(skipElm.value) + limit;
   });
-  document.querySelectorAll('.pagination .prev').forEach(elm => {
+  document.querySelectorAll(".pagination .prev").forEach(elm => {
     elm.disabled = parseInt(skipElm.value) <= 0;
   });
 }
 
 function updateLinksNav() {
-  const totalElm = document.querySelector('#total');
-  const skipElm = document.querySelector('#skip');
-  const limitElm = document.querySelector('#limit');
+  const totalElm = document.querySelector("#total");
+  const skipElm = document.querySelector("#skip");
+  const limitElm = document.querySelector("#limit");
   if (!totalElm || !skipElm || !limitElm) return;
   const total = parseInt(totalElm.value);
   const skip = parseInt(skipElm.value);
   const limit = parseInt(limitElm.value);
-  document.querySelectorAll('.pagination .next').forEach(elm => {
+  document.querySelectorAll(".pagination .next").forEach(elm => {
     elm.disabled = total <= skip + limit;
   });
-  document.querySelectorAll('.pagination .prev').forEach(elm => {
+  document.querySelectorAll(".pagination .prev").forEach(elm => {
     elm.disabled = skip <= 0;
   });
 }
 
 function resetTableNav() {
-  const totalElm = document.querySelector('#total');
-  const skipElm = document.querySelector('#skip');
-  const limitElm = document.querySelector('#limit');
+  const totalElm = document.querySelector("#total");
+  const skipElm = document.querySelector("#skip");
+  const limitElm = document.querySelector("#limit");
   if (!totalElm || !skipElm || !limitElm) return;
   skipElm.value = 0;
   limitElm.value = 10;
   const total = parseInt(totalElm.value);
   const skip = parseInt(skipElm.value);
   const limit = parseInt(limitElm.value);
-  document.querySelectorAll('.pagination .next').forEach(elm => {
+  document.querySelectorAll(".pagination .next").forEach(elm => {
     elm.disabled = total <= skip + limit;
   });
-  document.querySelectorAll('.pagination .prev').forEach(elm => {
+  document.querySelectorAll(".pagination .prev").forEach(elm => {
     elm.disabled = skip <= 0;
   });
-  document.querySelectorAll('table .nav .limit button').forEach(b => {
+  document.querySelectorAll("table .nav .limit button").forEach(b => {
     b.disabled = b.textContent === limit.toString();
   });
 }
@@ -261,43 +261,43 @@ onSearchInputLoad();
 
 // create user checkbox control
 function canSendVerificationEmail() {
-  const canSendVerificationEmail = !document.getElementById('create-user-verified').checked && !document.getElementById('create-user-banned').checked;
-  const checkbox = document.getElementById('send-email-label');
+  const canSendVerificationEmail = !document.getElementById("create-user-verified").checked && !document.getElementById("create-user-banned").checked;
+  const checkbox = document.getElementById("send-email-label");
   if (canSendVerificationEmail)
-    checkbox.classList.remove('hidden');
-  if (!canSendVerificationEmail && !checkbox.classList.contains('hidden'))
-    checkbox.classList.add('hidden');
+    checkbox.classList.remove("hidden");
+  if (!canSendVerificationEmail && !checkbox.classList.contains("hidden"))
+    checkbox.classList.add("hidden");
 }
 
 // htmx prefetch extension
 // https://github.com/bigskysoftware/htmx-extensions/blob/main/src/preload/README.md
-htmx.defineExtension('preload', {
+htmx.defineExtension("preload", {
   onEvent: function(name, event) {
-    if (name !== 'htmx:afterProcessNode') {
+    if (name !== "htmx:afterProcessNode") {
       return
     }
     var attr = function(node, property) {
       if (node == undefined) { return undefined }
-      return node.getAttribute(property) || node.getAttribute('data-' + property) || attr(node.parentElement, property)
+      return node.getAttribute(property) || node.getAttribute("data-" + property) || attr(node.parentElement, property)
     }
     var load = function(node) {
       var done = function(html) {
         if (!node.preloadAlways) {
-          node.preloadState = 'DONE'
+          node.preloadState = "DONE"
         }
 
-        if (attr(node, 'preload-images') == 'true') {
-          document.createElement('div').innerHTML = html
+        if (attr(node, "preload-images") == "true") {
+          document.createElement("div").innerHTML = html
         }
       }
 
       return function() {
-        if (node.preloadState !== 'READY') {
+        if (node.preloadState !== "READY") {
           return
         }
-        var hxGet = node.getAttribute('hx-get') || node.getAttribute('data-hx-get')
+        var hxGet = node.getAttribute("hx-get") || node.getAttribute("data-hx-get")
         if (hxGet) {
-          htmx.ajax('GET', hxGet, {
+          htmx.ajax("GET", hxGet, {
             source: node,
             handler: function(elt, info) {
               done(info.xhr.responseText)
@@ -305,30 +305,30 @@ htmx.defineExtension('preload', {
           })
           return
         }
-        if (node.getAttribute('href')) {
+        if (node.getAttribute("href")) {
           var r = new XMLHttpRequest()
-          r.open('GET', node.getAttribute('href'))
+          r.open("GET", node.getAttribute("href"))
           r.onload = function() { done(r.responseText) }
           r.send()
         }
       }
     }
     var init = function(node) {
-      if (node.getAttribute('href') + node.getAttribute('hx-get') + node.getAttribute('data-hx-get') == '') {
+      if (node.getAttribute("href") + node.getAttribute("hx-get") + node.getAttribute("data-hx-get") == "") {
         return
       }
       if (node.preloadState !== undefined) {
         return
       }
-      var on = attr(node, 'preload') || 'mousedown'
-      const always = on.indexOf('always') !== -1
+      var on = attr(node, "preload") || "mousedown"
+      const always = on.indexOf("always") !== -1
       if (always) {
-        on = on.replace('always', '').trim()
+        on = on.replace("always", "").trim()
       }
       node.addEventListener(on, function(evt) {
-        if (node.preloadState === 'PAUSE') {
-          node.preloadState = 'READY'
-          if (on === 'mouseover') {
+        if (node.preloadState === "PAUSE") {
+          node.preloadState = "READY"
+          if (on === "mouseover") {
             window.setTimeout(load(node), 100)
           } else {
             load(node)()
@@ -336,27 +336,27 @@ htmx.defineExtension('preload', {
         }
       })
       switch (on) {
-        case 'mouseover':
-          node.addEventListener('touchstart', load(node))
-          node.addEventListener('mouseout', function(evt) {
-            if ((evt.target === node) && (node.preloadState === 'READY')) {
-              node.preloadState = 'PAUSE'
+        case "mouseover":
+          node.addEventListener("touchstart", load(node))
+          node.addEventListener("mouseout", function(evt) {
+            if ((evt.target === node) && (node.preloadState === "READY")) {
+              node.preloadState = "PAUSE"
             }
           })
           break
 
-        case 'mousedown':
-          node.addEventListener('touchstart', load(node))
+        case "mousedown":
+          node.addEventListener("touchstart", load(node))
           break
       }
-      node.preloadState = 'PAUSE'
+      node.preloadState = "PAUSE"
       node.preloadAlways = always
-      htmx.trigger(node, 'preload:init')
+      htmx.trigger(node, "preload:init")
     }
     const parent = event.target || event.detail.elt;
     parent.querySelectorAll("[preload]").forEach(function(node) {
       init(node)
-      node.querySelectorAll('a,[hx-get],[data-hx-get]').forEach(init)
+      node.querySelectorAll("a,[hx-get],[data-hx-get]").forEach(init)
     })
   }
 })

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels