Upgraded dependencies, bumped to Node 24.

This commit is contained in:
2026-07-12 05:27:14 +02:00
parent 2d4786a4fd
commit d745b10d24
181 changed files with 18720 additions and 23134 deletions

View File

@@ -1,13 +1,13 @@
import Router from 'express-promise-router';
import { Router } from 'express';
import omit from 'object.omit';
import {
createActor,
createActorRevision,
fetchActorRevisions,
fetchActors,
fetchActorsById,
createActor,
mergeActors,
fetchActorRevisions,
createActorRevision,
reviewActorRevision,
} from '../actors.js';

View File

@@ -1,12 +1,12 @@
import Router from 'express-promise-router';
import { Router } from 'express';
import {
fetchAlerts,
createAlert,
removeAlert,
fetchAlerts,
fetchNotifications,
updateNotifications,
removeAlert,
updateNotification,
updateNotifications,
} from '../alerts.js';
// actors and actorIds, stashes and stashIds are aliases for consistency

View File

@@ -1,15 +1,14 @@
/* eslint-disable no-param-reassign */
import { stringify } from '@brillout/json-serializer/stringify'; /* eslint-disable-line import/extensions */
import { stringify } from '@brillout/json-serializer/stringify';
import IPCIDR from 'ip-cidr';
import argv from '../argv.js';
import {
login,
signup,
fetchUserKeys,
createKey,
removeUserKey,
fetchUserKeys,
flushUserKeys,
login,
removeUserKey,
signup,
} from '../auth.js';
import { fetchUser } from '../users.js';
@@ -111,4 +110,3 @@ export async function flushUserKeysApi(req, res) {
res.status(204).send();
}
/* eslint-enable no-param-reassign */

View File

@@ -4,26 +4,26 @@ export default function consentHandler(req, res, next) {
if (Object.hasOwn(req.query, 'lgbt')) {
const lgbtFilters = Array.from(new Set([...(req.tagFilter || []).filter((tag) => !['gay', 'bisexual', 'transsexual'].includes(tag)), 'extreme-insertion']));
req.tagFilter = lgbtFilters; // eslint-disable-line no-param-reassign
req.tagFilter = lgbtFilters;
res.cookie('tags', JSON.stringify(lgbtFilters));
}
if (Object.hasOwn(req.query, 'straight')) {
const straightFilters = Array.from(new Set([...(req.tagFilter || []), 'gay', 'bisexual', 'transsexual', 'extreme-insertion']));
req.tagFilter = straightFilters; // eslint-disable-line no-param-reassign
req.tagFilter = straightFilters;
res.cookie('tags', JSON.stringify(straightFilters));
}
if (Object.hasOwn(req.query, 'consent')) {
req.session.hasConsent = true; // eslint-disable-line no-param-reassign
req.session.hasConsent = true;
res.redirect(redirect || req.path);
return;
}
if (!req.path.includes('/consent') && !req.session?.hasConsent) {
res.redirect(`/consent?redirect=${req.originalUrl === '/' ? '' : encodeURIComponent(req.originalUrl) }`);
res.redirect(`/consent?redirect=${req.originalUrl === '/' ? '' : encodeURIComponent(req.originalUrl)}`);
return;
}

View File

@@ -1,12 +1,12 @@
import { parseResolveInfo } from 'graphql-parse-resolve-info';
import { getIdsBySlug } from '../cache.js';
import {
fetchEntities,
fetchEntitiesById,
} from '../entities.js';
import { getIdsBySlug } from '../cache.js';
export async function fetchEntitiesApi(req, res) {
const entities = await fetchEntities(req.query);

View File

@@ -2,8 +2,8 @@ import config from 'config';
import { format } from 'date-fns';
import {
graphql,
buildSchema,
graphql,
GraphQLScalarType,
} from 'graphql';
@@ -12,56 +12,56 @@ import {
JSONResolver,
} from 'graphql-scalars';
import {
scenesSchema,
fetchScenesGraphql,
fetchScenesByIdGraphql,
} from './scenes.js';
import {
moviesSchema,
fetchMoviesGraphql,
fetchMoviesByIdGraphql,
} from './movies.js';
import {
entitiesSchema,
fetchEntitiesGraphql,
fetchEntitiesByIdGraphql,
} from './entities.js';
import { verifyKey } from '../auth.js';
import {
actorsSchema,
fetchActorsGraphql,
fetchActorsByIdGraphql,
fetchActorsGraphql,
} from './actors.js';
import {
stashesSchema,
fetchUserStashesGraphql,
fetchStashGraphql,
createStashGraphql,
updateStashGraphql,
removeStashGraphql,
stashSceneGraphql,
unstashSceneGraphql,
stashActorGraphql,
unstashActorGraphql,
stashMovieGraphql,
unstashMovieGraphql,
} from './stashes.js';
import {
alertsSchema,
fetchAlertsGraphql,
createAlertGraphql,
removeAlertGraphql,
fetchAlertsGraphql,
fetchNotificationsGraphql,
removeAlertGraphql,
updateNotificationGraphql,
updateNotificationsGraphql,
} from './alerts.js';
import { verifyKey } from '../auth.js';
import {
entitiesSchema,
fetchEntitiesByIdGraphql,
fetchEntitiesGraphql,
} from './entities.js';
import {
fetchMoviesByIdGraphql,
fetchMoviesGraphql,
moviesSchema,
} from './movies.js';
import {
fetchScenesByIdGraphql,
fetchScenesGraphql,
scenesSchema,
} from './scenes.js';
import {
createStashGraphql,
fetchStashGraphql,
fetchUserStashesGraphql,
removeStashGraphql,
stashActorGraphql,
stashesSchema,
stashMovieGraphql,
stashSceneGraphql,
unstashActorGraphql,
unstashMovieGraphql,
unstashSceneGraphql,
updateStashGraphql,
} from './stashes.js';
const schema = buildSchema(`
type Query {
@@ -114,7 +114,7 @@ export async function graphqlApi(req, res) {
await verifyKey(req.headers['api-user'], req.headers['api-key'], req);
req.user = { // eslint-disable-line no-param-reassign
req.user = {
id: Number(req.headers['api-user']),
};

View File

@@ -1,17 +1,19 @@
import config from 'config';
import { renderPage } from 'vike/server'; // eslint-disable-line import/extensions
import { renderPage } from 'vike/server';
import { socials } from '../../common/actors.mjs';
import { fetchUnseenNotificationsCount } from '../alerts.js';
import { fetchUserStashes } from '../stashes.js';
import { fetchUserTemplates } from '../users.js';
import { fetchUnseenNotificationsCount } from '../alerts.js';
import { socials } from '../../common/actors.mjs'; // eslint-disable-line import/namespace
export default async function mainHandler(req, res, next) {
const [stashes, templates, unseenNotifications] = req.user ? await Promise.all([
fetchUserStashes(req.user.id, req.user),
fetchUserTemplates(req.user),
fetchUnseenNotificationsCount(req.user),
]) : [];
const [stashes, templates, unseenNotifications] = req.user
? await Promise.all([
fetchUserStashes(req.user.id, req.user),
fetchUserTemplates(req.user),
fetchUnseenNotificationsCount(req.user),
])
: [];
const pageContextInit = {
urlOriginal: req.originalUrl,
@@ -27,12 +29,14 @@ export default async function mainHandler(req, res, next) {
abilities: req.user.abilities,
avatar: req.user.avatar,
},
assets: req.user ? {
stashes,
primaryStash: stashes.find((stash) => stash.isPrimary),
templates,
unseenNotifications,
} : null,
assets: req.user
? {
stashes,
primaryStash: stashes.find((stash) => stash.isPrimary),
templates,
unseenNotifications,
}
: null,
env: {
theme: req.cookies.theme || req.headers['sec-ch-prefers-color-scheme'] || 'light',
scenesView: req.cookies.scenesView || 'list',

View File

@@ -1,12 +1,12 @@
import { stringify } from '@brillout/json-serializer/stringify'; /* eslint-disable-line import/extensions */
import { stringify } from '@brillout/json-serializer/stringify';
import { fetchMovies, fetchMoviesById } from '../movies.js';
import { fetchStashByUsernameAndSlug } from '../stashes.js';
import { parseActorIdentifier } from '../query.js';
import { getIdsBySlug } from '../cache.js';
import slugify from '../../utils/slugify.js';
import promiseProps from '../../utils/promise-props.js';
import slugify from '../../utils/slugify.js';
import { getIdsBySlug } from '../cache.js';
import { HttpError } from '../errors.js';
import { fetchMovies, fetchMoviesById } from '../movies.js';
import { parseActorIdentifier } from '../query.js';
import { fetchStashByUsernameAndSlug } from '../stashes.js';
export async function curateMoviesQuery(query) {
return {

View File

@@ -1,6 +1,6 @@
import config from 'config';
import path from 'path';
import path from 'node:path';
import { Reader } from '@maxmind/geoip2-node';
import config from 'config';
import initLogger from '../logger.js';
@@ -69,7 +69,8 @@ export default async function initRestrictionHandler() {
req.restriction = restriction;
req.country = country;
} catch (error) {
}
catch (error) {
logger.error(`Failed Maxmind IP lookup for ${req.ip}: ${error.message}`);
req.session.restrictionIp = req.userIp;

View File

@@ -1,6 +1,6 @@
// https://stackoverflow.com/questions/46745014/alternative-for-dirname-in-node-when-using-the-experimental-modules-flag/50052194#50052194
import { dirname } from 'path';
import { fileURLToPath } from 'url';
import { dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
const __dirname = dirname(fileURLToPath(import.meta.url));
const root = `${__dirname}/..`;

View File

@@ -1,22 +1,22 @@
import Router from 'express-promise-router';
import { stringify } from '@brillout/json-serializer/stringify'; /* eslint-disable-line import/extensions */
import { stringify } from '@brillout/json-serializer/stringify';
import { Router } from 'express';
import promiseProps from '../../utils/promise-props.js';
import slugify from '../../utils/slugify.js';
import { getIdsBySlug } from '../cache.js';
import { HttpError } from '../errors.js';
import { parseActorIdentifier } from '../query.js';
import {
createSceneRevision,
fetchSceneRevisions,
fetchScenes,
fetchScenesById,
fetchSceneRevisions,
createSceneRevision,
reviewSceneRevision,
} from '../scenes.js';
import { fetchStashByUsernameAndSlug } from '../stashes.js';
import { parseActorIdentifier } from '../query.js';
import { getIdsBySlug } from '../cache.js';
import slugify from '../../utils/slugify.js';
import { HttpError } from '../errors.js';
import promiseProps from '../../utils/promise-props.js';
export async function curateScenesQuery(query) {
const splitYears = query.years?.split(',') || [];
const splitTags = query.tags?.split(',') || [];

View File

@@ -1,50 +1,50 @@
import config from 'config';
import path from 'path';
import express from 'express';
import boolParser from 'express-query-boolean';
import Router from 'express-promise-router';
import session from 'express-session';
import RedisStore from 'connect-redis';
import path from 'node:path';
import process from 'node:process';
import compression from 'compression';
import cookie from 'cookie';
import redis from '../redis.js';
import errorHandler from './error.js';
import consentHandler from './consent.js';
import initRestrictionHandler from './restrictions.js';
import { scenesRouter } from './scenes.js';
import { actorsRouter } from './actors.js';
import { syncRouter } from './sync.js';
import { fetchMoviesApi } from './movies.js';
import { fetchEntitiesApi } from './entities.js';
import { fetchTagsApi } from './tags.js';
import config from 'config';
import { RedisStore } from 'connect-redis';
import { parseCookie } from 'cookie';
import express, { Router } from 'express';
import session from 'express-session';
import { verifyKey } from '../auth.js';
import initLogger from '../logger.js';
import redis from '../redis.js';
import queryBoolean from '../utils/query-boolean.js';
import { actorsRouter } from './actors.js';
import { router as alertsRouter } from './alerts.js';
import {
createKeyApi,
fetchUserKeysApi,
flushUserKeysApi,
loginApi,
logoutApi,
removeUserKeyApi,
setUserApi,
signupApi,
} from './auth.js';
import consentHandler from './consent.js';
import { fetchEntitiesApi } from './entities.js';
import errorHandler from './error.js';
import { graphqlApi } from './graphql.js';
import mainHandler from './main.js';
import { fetchMoviesApi } from './movies.js';
import {
setUserApi,
loginApi,
logoutApi,
signupApi,
fetchUserKeysApi,
createKeyApi,
removeUserKeyApi,
flushUserKeysApi,
} from './auth.js';
import initRestrictionHandler from './restrictions.js';
import { scenesRouter } from './scenes.js';
import { router as userRouter } from './users.js';
import { router as stashesRouter } from './stashes.js';
import { router as alertsRouter } from './alerts.js';
import { syncRouter } from './sync.js';
import { initCachesApi } from './system.js';
import initLogger from '../logger.js';
import { fetchTagsApi } from './tags.js';
import { router as userRouter } from './users.js';
const logger = initLogger();
const isProduction = process.env.NODE_ENV === 'production';
@@ -57,8 +57,11 @@ export default async function initServer() {
app.use(compression());
app.disable('x-powered-by');
app.set('view engine', 'ejs');
// Express 5 defaults to the 'simple' query parser (Node's querystring) instead of 'extended'
// (qs), which drops support for the bracket/nested query syntax the app relies on.
app.set('query parser', 'extended');
router.use(boolParser());
router.use(queryBoolean());
router.use('/', express.static('public'));
router.use('/', express.static('static'));
@@ -66,12 +69,10 @@ export default async function initServer() {
router.use((req, _res, next) => {
if (req.headers.cookie) {
const cookies = cookie.parse(req.headers.cookie);
const cookies = parseCookie(req.headers.cookie);
/* eslint-disable no-param-reassign */
req.cookies = cookies;
req.tagFilter = cookies.tags ? JSON.parse(cookies.tags) : [];
/* eslint-enable no-param-reassign */
}
next();
@@ -99,7 +100,8 @@ export default async function initServer() {
// (In dev, Vite's middleware serves our static assets.)
const sirv = (await import('sirv')).default;
router.use(sirv('dist/client'));
} else {
}
else {
// We instantiate Vite's development server and integrate its middleware to our server.
// ⚠️ We instantiate it only in development. (It isn't needed in production and it
// would unnecessarily bloat our production server.)
@@ -121,7 +123,7 @@ export default async function initServer() {
res.sendFile(path.join(import.meta.dirname, '../../assets/consent.html'));
});
router.use('/api/*', async (req, _res, next) => {
router.use('/api/{*splat}', async (req, _res, next) => {
if (req.headers['api-user']) {
req.user = await verifyKey(req.headers['api-user'], req.headers['api-key'], req);
}
@@ -167,16 +169,14 @@ export default async function initServer() {
router.use(consentHandler);
router.use((_req, res, next) => {
/* eslint-disable no-param-reassign */
res.set('Accept-CH', 'Sec-CH-Prefers-Color-Scheme');
res.set('Vary', 'Sec-CH-Prefers-Color-Scheme');
res.set('Critical-CH', 'Sec-CH-Prefers-Color-Scheme');
/* eslint-enable no-param-reassign */
next();
});
router.get('*', mainHandler);
router.get('/{*splat}', mainHandler);
router.use(errorHandler);
app.use(router);

View File

@@ -1,17 +1,17 @@
import Router from 'express-promise-router';
import { Router } from 'express';
import {
fetchUserStashes,
createStash,
fetchStashByUsernameAndSlug,
fetchUserStashes,
removeStash,
stashActor,
stashScene,
stashMovie,
stashScene,
unstashActor,
unstashScene,
unstashMovie,
unstashScene,
updateStash,
fetchStashByUsernameAndSlug,
} from '../stashes.js';
export const stashesSchema = `

View File

@@ -1,15 +1,15 @@
import Router from 'express-promise-router';
import {
syncScenes,
syncMovies,
syncActors,
syncStashes,
syncQueue,
} from '../sync.js';
import { Router } from 'express';
import verifyAbility from '../../utils/verify-ability.js';
import {
syncActors,
syncMovies,
syncQueue,
syncScenes,
syncStashes,
} from '../sync.js';
export const syncRouter = Router();
async function syncScenesApi(req, res) {

View File

@@ -1,5 +1,5 @@
import { HttpError } from '../errors.js';
import { initCaches } from '../cache.js';
import { HttpError } from '../errors.js';
export async function initCachesApi(req, res) {
if (req.user?.role !== 'admin') {

View File

@@ -1,12 +1,12 @@
import Router from 'express-promise-router';
import { stringify } from '@brillout/json-serializer/stringify'; /* eslint-disable-line import/extensions */
import { stringify } from '@brillout/json-serializer/stringify';
import { Router } from 'express';
import {
createBan,
createTemplate,
fetchUser,
fetchUserTemplates,
createTemplate,
removeTemplate,
createBan,
} from '../users.js';
async function fetchUserApi(req, res) {