From 32913d582ab2b49bdab6803e89cdc012122cc9c4 Mon Sep 17 00:00:00 2001 From: shoofle Date: Fri, 27 Sep 2024 11:40:14 -0400 Subject: [PATCH] moving to server/db sameness and express-session --- client/package-lock.json | 16 + client/package.json | 1 + client/src/App.jsx | 14 +- client/src/apiTools.jsx | 32 +- client/src/index.jsx | 8 +- client/src/landing/Landing.css | 5 +- client/src/landing/Landing.jsx | 9 +- client/src/login/LogIn.jsx | 33 +- client/src/login/Register.jsx | 37 ++ client/src/page/Pages.css | 5 +- client/src/reportWebVitals.js | 13 - db/initialize_db.js | 17 + server/api.js | 128 +++-- server/dbHelper.js | 19 - server/db_scripts/copy_db.js | 31 ++ server/db_scripts/initialize_db.js | 48 ++ server/db_scripts/list_tables.js | 4 + server/graphStuff.js | 4 +- server/package-lock.json | 818 +++++++++++++++++++++++++++++ server/package.json | 6 + server/server.js | 17 + 21 files changed, 1169 insertions(+), 96 deletions(-) create mode 100644 client/src/login/Register.jsx delete mode 100644 client/src/reportWebVitals.js delete mode 100644 server/dbHelper.js create mode 100644 server/db_scripts/copy_db.js create mode 100644 server/db_scripts/initialize_db.js create mode 100644 server/db_scripts/list_tables.js diff --git a/client/package-lock.json b/client/package-lock.json index 0e7a8dad..5e7a0103 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -20,6 +20,7 @@ "graphology-layout-force": "^0.2.4", "react": "^18.3.1", "react-dom": "^18.3.1", + "react-hook-form": "^7.53.0", "react-router-dom": "^6.26.2", "react-sigma": "^1.2.35", "sigma": "^3.0.0-beta.29", @@ -3088,6 +3089,21 @@ "react": "^18.3.1" } }, + "node_modules/react-hook-form": { + "version": "7.53.0", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.53.0.tgz", + "integrity": "sha512-M1n3HhqCww6S2hxLxciEXy2oISPnAzxY7gvwVPrtlczTM/1dDadXgUxDpHMrMTblDOcm/AXtXxHwZ3jpg1mqKQ==", + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-hook-form" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17 || ^18 || ^19" + } + }, "node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", diff --git a/client/package.json b/client/package.json index 3751466c..bc8215e5 100644 --- a/client/package.json +++ b/client/package.json @@ -15,6 +15,7 @@ "graphology-layout-force": "^0.2.4", "react": "^18.3.1", "react-dom": "^18.3.1", + "react-hook-form": "^7.53.0", "react-router-dom": "^6.26.2", "react-sigma": "^1.2.35", "sigma": "^3.0.0-beta.29", diff --git a/client/src/App.jsx b/client/src/App.jsx index 0a1b44e4..1fc43b6d 100644 --- a/client/src/App.jsx +++ b/client/src/App.jsx @@ -1,10 +1,12 @@ -import { QueryClient, QueryClientProvider } from '@tanstack/react-query' +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { BrowserRouter, Routes, Route } from 'react-router-dom'; -import Landing from '/src/landing/Landing.jsx' -import PageView from '/src/page/PageView.jsx' -import PageEdit from '/src/page/PageEdit.jsx' +import Landing from '/src/landing/Landing.jsx'; +import PageView from '/src/page/PageView.jsx'; +import PageEdit from '/src/page/PageEdit.jsx'; +import LogIn from '/src/login/LogIn.jsx'; +import Register from '/src/login/Register.jsx'; -import './App.css' +import './App.css'; const queryClient = new QueryClient(); @@ -14,6 +16,8 @@ function App() { }/> + }/> + }/> }/> }/> diff --git a/client/src/apiTools.jsx b/client/src/apiTools.jsx index af9ad6f0..38bd9d55 100644 --- a/client/src/apiTools.jsx +++ b/client/src/apiTools.jsx @@ -4,8 +4,19 @@ import Graph from 'graphology'; export const apiUrl = `${window.location.origin}/api`; + +//lil helper to throw errorrs from the promise when we get not-ok results +export const shoofetch = (url, config) => fetch(url, {...config, ...defaults}) + .then(async (res) => { + if (!res.ok) { + throw new Error(`got an error from the server: ${await res.text()}`); + } + return res.json(); + }); + const defaults = { - headers: {'Content-Type': 'application/json'} + headers: {'Content-Type': 'application/json'}, + credentials: 'include' }; export async function postNewPage() { @@ -41,7 +52,6 @@ export async function postPage({id, title, description}) { export async function deletePage(id) { return fetch(`${apiUrl}/page/${id}`, { method: 'DELETE', - headers: {'Content-Type': 'application/json'}, ...defaults }) } @@ -56,4 +66,22 @@ export async function fetchGraph() { graph.import(serialized); return graph; }) +} + +export async function createAccount({name, password, nonce}) { + return shoofetch(`${apiUrl}/register`, { + method: 'POST', + body: JSON.stringify({name: name, password: password, nonce: nonce}) + }) +} + +export async function logIn({name, password}) { + return shoofetch(`${apiUrl}/login`, { + method: 'POST', + body: JSON.stringify({name: name, password: password}) + }) +} + +export async function logOut() { + return shoofetch(`${apiUrl}/logout`, { method: 'POST' }); } \ No newline at end of file diff --git a/client/src/index.jsx b/client/src/index.jsx index 00a1a24c..9ab63f85 100644 --- a/client/src/index.jsx +++ b/client/src/index.jsx @@ -1,7 +1,6 @@ import React from 'react'; import ReactDOM from 'react-dom/client'; import App from './App.jsx'; -import reportWebVitals from './reportWebVitals'; const root = ReactDOM.createRoot(document.getElementById('root')); @@ -9,9 +8,4 @@ root.render( -); - -// If you want to start measuring performance in your app, pass a function -// to log results (for example: reportWebVitals(console.log)) -// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals -reportWebVitals(); +); \ No newline at end of file diff --git a/client/src/landing/Landing.css b/client/src/landing/Landing.css index 0b0be1c0..e63efdd9 100644 --- a/client/src/landing/Landing.css +++ b/client/src/landing/Landing.css @@ -1,7 +1,8 @@ .landing-page { - padding-left:10rem; - padding-right: 10rem; + width: 76ch; + margin-left: auto; + margin-right: auto; padding-top: 3rem; color: white; } diff --git a/client/src/landing/Landing.jsx b/client/src/landing/Landing.jsx index 9b768f11..fcb5fa42 100644 --- a/client/src/landing/Landing.jsx +++ b/client/src/landing/Landing.jsx @@ -1,7 +1,7 @@ import { useNavigate, Link } from 'react-router-dom' import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; -import { fetchPageList, postNewPage } from '../apiTools.jsx'; +import { fetchPageList, postNewPage, logOut } from '../apiTools.jsx'; import { useFixLinks } from '../clientStuff.jsx'; import PageList from './PageList.jsx'; @@ -37,9 +37,10 @@ function Landing() {
-
-
-
+
+
+
+
diff --git a/client/src/login/LogIn.jsx b/client/src/login/LogIn.jsx index 948c7e34..0c3e24c5 100644 --- a/client/src/login/LogIn.jsx +++ b/client/src/login/LogIn.jsx @@ -1 +1,32 @@ -LogIn.jsx \ No newline at end of file +import { useForm } from "react-hook-form"; +import { useNavigate } from 'react-router-dom'; +import { logIn } from '../apiTools.jsx'; + +function LogIn() { + const { register, handleSubmit } = useForm(); + const navigate = useNavigate(); + + const onSubmit = (d) => { + logIn(d) + .then(() => navigate('/')) + .catch((error) => console.log('error logging in: ', error)); + }; + + return ( +
+ + + +
+ ); +} + +export default LogIn; \ No newline at end of file diff --git a/client/src/login/Register.jsx b/client/src/login/Register.jsx new file mode 100644 index 00000000..b977bd61 --- /dev/null +++ b/client/src/login/Register.jsx @@ -0,0 +1,37 @@ +import { useForm } from "react-hook-form"; +import { useNavigate } from "react-router-dom"; +import { createAccount } from "../apiTools.jsx"; + +function Register() { + const { register, handleSubmit } = useForm(); + const navigate = useNavigate(); + + const onSubmit = (d) => { + createAccount(d) + .then(() => navigate("/login")) + .catch((error) => console.log("error: ", error)); + }; + + return ( +
+ + + + +
+ ); +} + +export default Register; \ No newline at end of file diff --git a/client/src/page/Pages.css b/client/src/page/Pages.css index 779683a4..0d212f67 100644 --- a/client/src/page/Pages.css +++ b/client/src/page/Pages.css @@ -1,7 +1,8 @@ .page-container { - padding-left:10rem; - padding-right: 10rem; + width: 76ch; + margin-left: auto; + margin-right: auto; padding-top: 3rem; color: white; } diff --git a/client/src/reportWebVitals.js b/client/src/reportWebVitals.js deleted file mode 100644 index 5253d3ad..00000000 --- a/client/src/reportWebVitals.js +++ /dev/null @@ -1,13 +0,0 @@ -const reportWebVitals = onPerfEntry => { - if (onPerfEntry && onPerfEntry instanceof Function) { - import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { - getCLS(onPerfEntry); - getFID(onPerfEntry); - getFCP(onPerfEntry); - getLCP(onPerfEntry); - getTTFB(onPerfEntry); - }); - } -}; - -export default reportWebVitals; diff --git a/db/initialize_db.js b/db/initialize_db.js index c10364db..a4d0e0c3 100644 --- a/db/initialize_db.js +++ b/db/initialize_db.js @@ -10,6 +10,18 @@ create table if not exists pages ( ) `; +const createUsers = ` +create table if not exists users ( + name varchar(64) primary key, + password varchar(128) +) +`; + +const createTokens = ` +create table if not exists tokens ( +) +`; + async function initDb() { const config = { url: "http://127.0.0.1:8000" @@ -19,6 +31,7 @@ async function initDb() { const converter = new showdown.Converter(); + console.log("creating page table") console.log(await db.execute(createPages)); console.log("finding pages that havent been rendered"); @@ -35,7 +48,11 @@ async function initDb() { sql: `replace into pages (id, title, description, html) values (?, ?, ?, ?)`, args: [id, title, description, renderedPage] }); + }); + + console.log("creating user table"); + console.log(await db.execute(createUsers)); } initDb(); \ No newline at end of file diff --git a/server/api.js b/server/api.js index 0aa3bcb7..d7a53f17 100644 --- a/server/api.js +++ b/server/api.js @@ -1,72 +1,122 @@ const express = require('express'); const showdown = require('showdown'); +const argon2 = require('argon2'); + const { query } = require('./dbHelper.js'); const { graphFromList } = require('./graphStuff.js'); const app = express.Router(); const converter = new showdown.Converter(); +const sqlite = require("better-sqlite3"); +const db = new sqlite('the_big_db.db', { verbose: console.log }); +console.log(db); + app.get('/pages', (req, res) => { - query('select id, title from pages', []) - .then((r) => r.rows) - .then((row) => row.map(([id, title]) => {return {"id": id, "title": title};})) - .then((pages) => res.status(200).json(pages)) - .catch((error) => res.status(500).json({"error": error})); + try { + const pages = db.prepare('select id, title from pages').all(); + res.status(200).json(pages); + } catch (error) { + res.status(500).json({"error": error}); + } }); app.post('/page/new', (req, res) => { - query('insert into pages (title, description) values (?, ?) returning id', - ["new page", "this page is new!"]) - .then((r) => r.rows[0]) - .then((row) => res.status(200).json({id: row[0]})) - .catch((error) => res.status(500).json({"error": error})) + try { + const newPage = db.prepare('insert into pages (title, description) values (?, ?) returning id') + .get("new page", "this page is new!"); + res.status(200).json(newPage); + } catch (error) { + res.status(500).json({"error": error}); + } }); app.get('/page/:id', (req, res) => { - query('select * from pages where id=?', [req.params.id]) - .then((r) => { - if (r.rows.length == 0) res.status(404).json({"error": "page not found in db"}); - else return r.rows[0]; - }).then((row) => res.status(200).json(row)) - .catch((error) => res.status(500).json({"error": error})); + try { + const page = db.prepare('select * from pages where id=:id').get(req.params); + if (page === undefined) res.status(404).json({"error": "page not found"}); + else res.status(200).json(page); + } catch (error) { + res.status(500).json({"error": error}); + } }); app.post('/page/:id', (req, res) => { - const html = converter.makeHtml(req.body.description); - query('replace into pages (id, title, description, html) values (?, ?, ?, ?)', - [req.params.id, req.body.title, req.body.description, html]) - .then(() => res.status(200).json({})) - .catch((error) => res.status(500).json({"error": error})); + try { + const html = converter.makeHtml(req.body.description); + const changes = db.prepare('replace into pages (id, title, descriptioon, html) values (?, ?, ?, ?)') + .run(req.params.id, req.body.title, req.body.description, html); + res.status(200).json(changes); + } catch (error) { + res.status(500).json({"error": error}); + } }); app.delete('/page/:id', (req, res) => { - query('delete from pages where id = ?', [req.params.id]) - .then(() => res.status(200).json({id: req.params.id})) - .catch((error) => res.status(500).json({"error": error})) + try { + const changes = db.prepare('delete from pages where id = ?').run(req.params.id); + res.status(200).json({id: req.params.id}); + } catch (error) { + res.status(500).json({"error": error}); + } }) app.get('/graph', (req, res) => { - query('select id, html from pages', []) - .then((r) => r.rows) - .then((stuff) => graphFromList(stuff)) - .then((graph) => res.json(graph)) - .catch((error) => res.status(500).json({"error": error})); + try { + const rows = db.prepare('select id, html from pages').all(); + const graph = graphFromList(rows); + res.status(200).json(graph); + } catch (error) { + res.status(500).json({"error": error}); + } }); // auth stuff -app.post('/register', (req, res) => { - // parse the body, which miight be url-encoded? +app.post('/register', async (req, res) => { + const {name, password, nonce} = req.body; + + const oldUser = db.prepare('select name from users where name=?').get(name); + if (oldUser) return res.status(500).json({"error": "user name already in use"}); + // check if the nonce password is correctt - // hash the password - // add tthe user to the users database + if (nonce != "a softer birdsong") return res.status(500).json({"error": "wrong nonce"}); + + try { + // i'm told argon2 is the good one nowatimes + const hash = await argon2.hash(password); + const inserted = db.prepare('insert into users (name, password) values (?, ?)').run(name, hash); + res.status(200).json(inserted); + } catch (error) { + res.status(500).json({"error": error}); + } +}); + +app.post('/login', async (req, res) => { + if (req.session.name) { + return res.status(200).json({message: "already logged in", name: req.session.name}); + } + + const {name, password} = req.body; + + // fetch username and passswords from the db + const storedUser = db.prepare('select name, password from users where name = ?').get(name); + if (!storedUser) { + return res.status(401).json({"error": "password/username combo not found in database"}); + } + + //check if the passss hashes mattch and log in + if (!(await argon2.verify(storedUser.password, password))) { + return res.status(401).json({"error": "password/username combo not found in database"}); + } + + // set the session cookie and rreturn 200! + req.session.name = name; + return res.status(200).json({message: "successfully logged in!", name: name}); }); -app.post('/login', (req, res) => { - // hash the password - // check if the user/hashed pass matches - // if not, throw an error - // create a valid ttoken? - // return token +app.post('/logout', (req, res) => { + req.session.destroy(); + res.status(200).json({message: "successfully logged out"}); }); module.exports = app; \ No newline at end of file diff --git a/server/dbHelper.js b/server/dbHelper.js deleted file mode 100644 index e26a657d..00000000 --- a/server/dbHelper.js +++ /dev/null @@ -1,19 +0,0 @@ -// helper function(s?) to make a query to the database - -const db_url = 'http://127.0.0.1:8000' - -async function query(q, params) { - return fetch(db_url, { - method: 'POST', - headers: {'Content-Type': 'application/json'}, - body: JSON.stringify({ - statements: [{ - q: q, - params: params - }] - }) - }).then((res) => res.json()) - .then((data) => data[0].results); -} - -module.exports = { query: query }; \ No newline at end of file diff --git a/server/db_scripts/copy_db.js b/server/db_scripts/copy_db.js new file mode 100644 index 00000000..2820fafa --- /dev/null +++ b/server/db_scripts/copy_db.js @@ -0,0 +1,31 @@ +const sqlite = require("better-sqlite3"); +const sqlite3_db = new sqlite('./the_big_db.db', { verbose: console.log }); + +const libsql = require("@libsql/client"); +const config = {url: "http://127.0.0.1:8000"}; +const libsql_db = libsql.createClient(config); + +async function copyPages() { + console.log("copying everythting from hte old db"); + const pages = (await libsql_db.execute(`select id, title, description, html from pages`)).rows; + + const insertPage = sqlite3_db.prepare(`replace into pages (id, title, description, html) values (:id, :title, :description, :html)`); + pages.forEach((page) => { + console.log(`inserting page ${page.id}`) + insertPage.run(page); + }); +} + +async function copyUsers() { + console.log("copying users now"); + const users = (await libsql_db.execute(`select name, password from users`)).rows; + + const insertUser = sqlite3_db.prepare(`replace into users (name, password) values (:name, :password)`); + users.forEach((user) => { + console.log(`inserting ${user.name}, ${user.password}`); + insertUser.run(user); + }); +} + +copyPages(); +copyUsers(); \ No newline at end of file diff --git a/server/db_scripts/initialize_db.js b/server/db_scripts/initialize_db.js new file mode 100644 index 00000000..bf9c9ae1 --- /dev/null +++ b/server/db_scripts/initialize_db.js @@ -0,0 +1,48 @@ +const sqlite = require("better-sqlite3"); +const showdown = require("showdown"); +const db = new sqlite('./the_big_db.db', { verbose: console.log }); + +const converter = new showdown.Converter(); + +const createPages = db.prepare(` +create table if not exists pages ( + id integer primary key, + title varchar(255), + description text, + html text +) +`); + +const createUsers = db.prepare(` +create table if not exists users ( + name varchar(64) primary key, + password varchar(128) +) +`); + + +function initDb() { + console.log("creating page table") + console.log(createPages.run()); + + console.log("finding pages that havent been rendered"); + rows = db.prepare(`select * from pages where html is null`).all(); + console.log(rows); + + const insertPage = db.prepare(`replace into pages (id, title, description, html) values (:id, :title, :description, :html)`); + + rows.forEach((pageData) => { + const {id, title, description, html} = pageData; + console.log(`rendering page number ${id}`) + console.log(`${id}. ${title}: ${description} ( ${html} )`); + + const renderedPage = converter.makeHtml(description); + + insertPage.run({...pageData, html: renderedPage}); + }); + + console.log("creating user table"); + console.log(createUsers.run()); +} + +initDb(); \ No newline at end of file diff --git a/server/db_scripts/list_tables.js b/server/db_scripts/list_tables.js new file mode 100644 index 00000000..333f7486 --- /dev/null +++ b/server/db_scripts/list_tables.js @@ -0,0 +1,4 @@ +const sqlite = require("better-sqlite3"); +const db = new sqlite('./the_big_db.db', { verbose: console.log }); + +console.log(db.prepare("select name from sqlite_master where type='table'").all()); \ No newline at end of file diff --git a/server/graphStuff.js b/server/graphStuff.js index 2925fa28..bd65e3a8 100644 --- a/server/graphStuff.js +++ b/server/graphStuff.js @@ -4,12 +4,12 @@ const { circular } = require('graphology-layout'); function graphFromList(allTheStuff) { const graph = new graphology.Graph(); + for (const {id, html} of allTheStuff) { - for (const [id, html] of allTheStuff) { graph.addNode(id); } - for (const [id, html] of allTheStuff) { + for (const {id, html} of allTheStuff) { const { document } = (new JSDOM(html)).window; const links = document.querySelectorAll('a'); links.forEach((link) => { diff --git a/server/package-lock.json b/server/package-lock.json index be8c3c60..e93604f5 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -9,7 +9,13 @@ "version": "1.0.0", "license": "ISC", "dependencies": { + "@libsql/client": "^0.14.0", + "argon2": "^0.41.1", + "better-sqlite3": "^11.3.0", + "better-sqlite3-session-store": "^0.1.0", + "client-sessions": "^0.8.0", "express": "^4.21.0", + "express-session": "^1.18.0", "graphology": "^0.25.4", "graphology-layout": "^0.6.1", "graphology-layout-force": "^0.2.4", @@ -19,6 +25,167 @@ "showdown": "^2.1.0" } }, + "node_modules/@libsql/client": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@libsql/client/-/client-0.14.0.tgz", + "integrity": "sha512-/9HEKfn6fwXB5aTEEoMeFh4CtG0ZzbncBb1e++OCdVpgKZ/xyMsIVYXm0w7Pv4RUel803vE6LwniB3PqD72R0Q==", + "dependencies": { + "@libsql/core": "^0.14.0", + "@libsql/hrana-client": "^0.7.0", + "js-base64": "^3.7.5", + "libsql": "^0.4.4", + "promise-limit": "^2.7.0" + } + }, + "node_modules/@libsql/core": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@libsql/core/-/core-0.14.0.tgz", + "integrity": "sha512-nhbuXf7GP3PSZgdCY2Ecj8vz187ptHlZQ0VRc751oB2C1W8jQUXKKklvt7t1LJiUTQBVJuadF628eUk+3cRi4Q==", + "dependencies": { + "js-base64": "^3.7.5" + } + }, + "node_modules/@libsql/darwin-arm64": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/@libsql/darwin-arm64/-/darwin-arm64-0.4.5.tgz", + "integrity": "sha512-xLdnn0NrgSk6OMi716FFs/27Hs33jtSd2fkKi/72Ey/qBtPWcB1BMurDQekzi0yAcfQTjGqIz7tpOibyjiEPyQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@libsql/darwin-x64": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/@libsql/darwin-x64/-/darwin-x64-0.4.5.tgz", + "integrity": "sha512-rZsEWj0H7oCqd5Y2pe0RzKmuQXC2OB1RbnFy4CvjeAjT6MP6mFp+Vx9mTCAUuJMhuoSVMsFPUJRpAQznl9E3Tg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@libsql/hrana-client": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@libsql/hrana-client/-/hrana-client-0.7.0.tgz", + "integrity": "sha512-OF8fFQSkbL7vJY9rfuegK1R7sPgQ6kFMkDamiEccNUvieQ+3urzfDFI616oPl8V7T9zRmnTkSjMOImYCAVRVuw==", + "dependencies": { + "@libsql/isomorphic-fetch": "^0.3.1", + "@libsql/isomorphic-ws": "^0.1.5", + "js-base64": "^3.7.5", + "node-fetch": "^3.3.2" + } + }, + "node_modules/@libsql/isomorphic-fetch": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@libsql/isomorphic-fetch/-/isomorphic-fetch-0.3.1.tgz", + "integrity": "sha512-6kK3SUK5Uu56zPq/Las620n5aS9xJq+jMBcNSOmjhNf/MUvdyji4vrMTqD7ptY7/4/CAVEAYDeotUz60LNQHtw==", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@libsql/isomorphic-ws": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@libsql/isomorphic-ws/-/isomorphic-ws-0.1.5.tgz", + "integrity": "sha512-DtLWIH29onUYR00i0GlQ3UdcTRC6EP4u9w/h9LxpUZJWRMARk6dQwZ6Jkd+QdwVpuAOrdxt18v0K2uIYR3fwFg==", + "dependencies": { + "@types/ws": "^8.5.4", + "ws": "^8.13.0" + } + }, + "node_modules/@libsql/linux-arm64-gnu": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/@libsql/linux-arm64-gnu/-/linux-arm64-gnu-0.4.5.tgz", + "integrity": "sha512-VR09iu6KWGJ6fauCn59u/jJ9OA+/A2yQ0dr2HDN2zkRueLC6D2oGYt4gPfLZPFKf+WJpVMtIhNfd+Ru9MMaFkA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@libsql/linux-arm64-musl": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/@libsql/linux-arm64-musl/-/linux-arm64-musl-0.4.5.tgz", + "integrity": "sha512-74hvD5ej4rBshhxFGNYU16a3m8B/NjIPvhlZ/flG1Oeydfo6AuUXSSNFi+H5+zi9/uWuzyz5TLVeQcraoUV10A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@libsql/linux-x64-gnu": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/@libsql/linux-x64-gnu/-/linux-x64-gnu-0.4.5.tgz", + "integrity": "sha512-gb5WObGO3+rbuG8h9font1N02iF+zgYAgY0wNa8BNiZ5A9UolZKFxiqGFS7eHaAYfemHJKKTT+aAt3X2p5TibA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@libsql/linux-x64-musl": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/@libsql/linux-x64-musl/-/linux-x64-musl-0.4.5.tgz", + "integrity": "sha512-JfyE6OVC5X4Nr4cFF77VhB1o+hBRxAqYT9YdeqnWdAQSYc/ASi5HnRALLAQEsGacFPZZ32pixfraQmPE3iJFfw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@libsql/win32-x64-msvc": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/@libsql/win32-x64-msvc/-/win32-x64-msvc-0.4.5.tgz", + "integrity": "sha512-57GGurNJhOhq3XIopLdGnCoQ4kQAcmbmzzFoC4tpvDE/KSbwZ/13zqJWhQA41nMGk/PKM1XKfKmbIybKx1+eqA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@neon-rs/load": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@neon-rs/load/-/load-0.0.4.tgz", + "integrity": "sha512-kTPhdZyTQxB+2wpiRcFWrDcejc4JI6tkPuS7UZCG4l6Zvc5kU/gGQ/ozvHTh1XR5tS+UlfAfGuPajjzQjCiHCw==" + }, + "node_modules/@phc/format": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@phc/format/-/format-1.0.0.tgz", + "integrity": "sha512-m7X9U6BG2+J+R1lSOdCiITLLrxm+cWlNI3HUFA92oLO77ObGNzaKdh8pMLqdZcshtkKuV84olNNXDfMc4FezBQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/@types/node": { + "version": "22.7.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.3.tgz", + "integrity": "sha512-qXKfhXXqGTyBskvWEzJZPUxSslAiLaB6JGP1ic/XTH9ctGgzdgYguuLP1C601aRTSDNlLb0jbKqXjZ48GNraSA==", + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "node_modules/@types/ws": { + "version": "8.5.12", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz", + "integrity": "sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -75,6 +242,20 @@ "node": ">= 8" } }, + "node_modules/argon2": { + "version": "0.41.1", + "resolved": "https://registry.npmjs.org/argon2/-/argon2-0.41.1.tgz", + "integrity": "sha512-dqCW8kJXke8Ik+McUcMDltrbuAWETPyU6iq+4AhxqKphWi7pChB/Zgd/Tp/o8xRLbg8ksMj46F/vph9wnxpTzQ==", + "hasInstallScript": true, + "dependencies": { + "@phc/format": "^1.0.0", + "node-addon-api": "^8.1.0", + "node-gyp-build": "^4.8.1" + }, + "engines": { + "node": ">=16.17.0" + } + }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -90,6 +271,43 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/better-sqlite3": { + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-11.3.0.tgz", + "integrity": "sha512-iHt9j8NPYF3oKCNOO5ZI4JwThjt3Z6J6XrcwG85VNMVzv1ByqrHWv5VILEbCMFWDsoHhXvQ7oC8vgRXFAKgl9w==", + "hasInstallScript": true, + "dependencies": { + "bindings": "^1.5.0", + "prebuild-install": "^7.1.1" + } + }, + "node_modules/better-sqlite3-session-store": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/better-sqlite3-session-store/-/better-sqlite3-session-store-0.1.0.tgz", + "integrity": "sha512-O4EO5jOGTEa/c1DbZpP3C7VTDLSWe5lrOu1S/j86ipdGZxrSb8bSUVuRgWCgl/SCgEGmyeEqvlMY9HtyOSMOWA==", + "dependencies": { + "date-fns": "2.16.1" + } + }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", @@ -101,6 +319,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, "node_modules/body-parser": { "version": "1.20.3", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", @@ -144,6 +380,29 @@ "node": ">=8" } }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -193,6 +452,22 @@ "fsevents": "~2.3.2" } }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, + "node_modules/client-sessions": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/client-sessions/-/client-sessions-0.8.0.tgz", + "integrity": "sha512-XERL6B5cJYGEaAigTADRr8NrUhkGmIUdrlHBzRM62uZEtFben5QYbaOxgWX79wFbCIvABhgZCWch1glw2fcyiQ==", + "dependencies": { + "cookies": "^0.7.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -249,6 +524,26 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, + "node_modules/cookies": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/cookies/-/cookies-0.7.3.tgz", + "integrity": "sha512-+gixgxYSgQLTaTIilDHAdlNPZDENDQernEMiIcZpYYP14zgHsCt4Ce1FEjFtcp6GefhozebB6orvhAAWx/IS0A==", + "dependencies": { + "depd": "~1.1.2", + "keygrip": "~1.0.3" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cookies/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/cssstyle": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.1.0.tgz", @@ -260,6 +555,14 @@ "node": ">=18" } }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "engines": { + "node": ">= 12" + } + }, "node_modules/data-urls": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", @@ -272,6 +575,18 @@ "node": ">=18" } }, + "node_modules/date-fns": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.16.1.tgz", + "integrity": "sha512-sAJVKx/FqrLYHAQeN7VpJrPhagZc9R4ImZIWYRFZaaohR3KzmuK88touwsSwSVT8Qcbd4zoDsnGfX4GFB4imyQ==", + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, "node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -285,6 +600,28 @@ "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==" }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -326,6 +663,14 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "engines": { + "node": ">=8" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -339,6 +684,14 @@ "node": ">= 0.8" } }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dependencies": { + "once": "^1.4.0" + } + }, "node_modules/entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", @@ -390,6 +743,14 @@ "node": ">=0.8.x" } }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "engines": { + "node": ">=6" + } + }, "node_modules/express": { "version": "4.21.0", "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", @@ -431,6 +792,56 @@ "node": ">= 0.10.0" } }, + "node_modules/express-session": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.0.tgz", + "integrity": "sha512-m93QLWr0ju+rOwApSsyso838LQwgfs44QtOP/WBiwtAgPIo/SAh1a5c6nn2BR6mFNZehTpqKDESzP+fRHVbxwQ==", + "dependencies": { + "cookie": "0.6.0", + "cookie-signature": "1.0.7", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-headers": "~1.0.2", + "parseurl": "~1.3.3", + "safe-buffer": "5.2.1", + "uid-safe": "~2.1.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/express-session/node_modules/cookie-signature": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==" + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -472,6 +883,17 @@ "node": ">= 6" } }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -488,6 +910,11 @@ "node": ">= 0.6" } }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -527,6 +954,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" + }, "node_modules/glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", @@ -764,6 +1196,25 @@ "node": ">=0.10.0" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/ignore-by-default": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", @@ -774,6 +1225,11 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -825,6 +1281,11 @@ "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==" }, + "node_modules/js-base64": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.7.tgz", + "integrity": "sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==" + }, "node_modules/jsdom": { "version": "25.0.0", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-25.0.0.tgz", @@ -864,6 +1325,50 @@ } } }, + "node_modules/keygrip": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.0.3.tgz", + "integrity": "sha512-/PpesirAIfaklxUzp4Yb7xBper9MwP6hNRA6BGGUFCgbJ+BM5CKBtsoxinNXkLHAr+GXS1/lSlF2rP7cv5Fl+g==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/libsql": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/libsql/-/libsql-0.4.5.tgz", + "integrity": "sha512-sorTJV6PNt94Wap27Sai5gtVLIea4Otb2LUiAUyr3p6BPOScGMKGt5F1b5X/XgkNtcsDKeX5qfeBDj+PdShclQ==", + "cpu": [ + "x64", + "arm64", + "wasm32" + ], + "os": [ + "darwin", + "linux", + "win32" + ], + "dependencies": { + "@neon-rs/load": "^0.0.4", + "detect-libc": "2.0.2" + }, + "optionalDependencies": { + "@libsql/darwin-arm64": "0.4.5", + "@libsql/darwin-x64": "0.4.5", + "@libsql/linux-arm64-gnu": "0.4.5", + "@libsql/linux-arm64-musl": "0.4.5", + "@libsql/linux-x64-gnu": "0.4.5", + "@libsql/linux-x64-musl": "0.4.5", + "@libsql/win32-x64-msvc": "0.4.5" + } + }, + "node_modules/libsql/node_modules/detect-libc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", + "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", + "engines": { + "node": ">=8" + } + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -918,6 +1423,17 @@ "node": ">= 0.6" } }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -929,6 +1445,19 @@ "node": "*" } }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" + }, "node_modules/mnemonist": { "version": "0.39.8", "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.39.8.tgz", @@ -942,6 +1471,11 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, + "node_modules/napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" + }, "node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -950,6 +1484,70 @@ "node": ">= 0.6" } }, + "node_modules/node-abi": { + "version": "3.68.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.68.0.tgz", + "integrity": "sha512-7vbj10trelExNjFSBm5kTvZXXa7pZyKWx9RCKIyqe6I9Ev3IzGpQoqBP3a+cOdxY+pWj6VkP28n/2wWysBHD/A==", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-addon-api": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.1.0.tgz", + "integrity": "sha512-yBY+qqWSv3dWKGODD6OGE6GnTX7Q2r+4+DfpqxHSHh8x0B4EKP9+wVGLS6U/AM1vxSNNmUEuIV5EGhYwPpfOwQ==", + "engines": { + "node": "^18 || ^20 || >= 21" + } + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/node-gyp-build": { + "version": "4.8.2", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.2.tgz", + "integrity": "sha512-IRUxE4BVsHWXkV/SFOut4qTlagw2aM8T5/vnTsmrHJvVoKueJHRc/JaFND7QDDc61kLYUJ6qlZM3sqTSyx2dTw==", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, "node_modules/nodemon": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.5.tgz", @@ -1038,6 +1636,22 @@ "node": ">= 0.8" } }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, "node_modules/pandemonium": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/pandemonium/-/pandemonium-2.4.1.tgz", @@ -1081,6 +1695,36 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/prebuild-install": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.2.tgz", + "integrity": "sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==", + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/promise-limit": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/promise-limit/-/promise-limit-2.7.0.tgz", + "integrity": "sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw==" + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -1103,6 +1747,15 @@ "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==" }, + "node_modules/pump": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", + "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -1130,6 +1783,14 @@ "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" }, + "node_modules/random-bytes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", + "integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -1152,6 +1813,33 @@ "node": ">= 0.8" } }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -1322,6 +2010,49 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "node_modules/simple-update-notifier": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", @@ -1341,6 +2072,22 @@ "node": ">= 0.8" } }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -1357,6 +2104,32 @@ "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" }, + "node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -1409,6 +2182,17 @@ "node": ">=18" } }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -1421,11 +2205,27 @@ "node": ">= 0.6" } }, + "node_modules/uid-safe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", + "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", + "dependencies": { + "random-bytes": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/undefsafe": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==" }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==" + }, "node_modules/universalify": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", @@ -1451,6 +2251,11 @@ "requires-port": "^1.0.0" } }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -1478,6 +2283,14 @@ "node": ">=18" } }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "engines": { + "node": ">= 8" + } + }, "node_modules/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", @@ -1528,6 +2341,11 @@ "node": ">=18" } }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, "node_modules/ws": { "version": "8.18.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", diff --git a/server/package.json b/server/package.json index 4053197c..c9d4d8c4 100644 --- a/server/package.json +++ b/server/package.json @@ -14,7 +14,13 @@ "author": "", "license": "ISC", "dependencies": { + "@libsql/client": "^0.14.0", + "argon2": "^0.41.1", + "better-sqlite3": "^11.3.0", + "better-sqlite3-session-store": "^0.1.0", + "client-sessions": "^0.8.0", "express": "^4.21.0", + "express-session": "^1.18.0", "graphology": "^0.25.4", "graphology-layout": "^0.6.1", "graphology-layout-force": "^0.2.4", diff --git a/server/server.js b/server/server.js index 14e3d88b..7d585247 100644 --- a/server/server.js +++ b/server/server.js @@ -1,11 +1,28 @@ const express = require('express'); +const session = require('express-session'); +const sqlite = require('better-sqlite3'); + const apiRoutes = require('./api.js'); const port = process.env.PORT || 3001; // Use the port provided by the host or default to 3000 +const db = new sqlite('the_big_db.db', { verbose: console.log }); +const SqliteStore = require('better-sqlite3-session-store')(session); const app = express(); app.use(express.json()); +app.use(session({ + store: new SqliteStore({ + client: db, + expired: { + clear: true, + intervalMs: 15*60*1000 + } + }), + secret: "dno'tt check me into versino control", + resave: false +})); + app.use("/api", apiRoutes); app.listen(port, () => {