diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1bb562ed..d78fa3d7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,7 +35,7 @@ jobs: name: Tests strategy: matrix: - node-version: ['14.x', '16.x', '18.x', '19.x'] + node-version: ['16.x', '18.x', '20.x'] mongo-version: ['5.0', '6.0'] include: - node-version: 'lts/*' @@ -65,7 +65,7 @@ jobs: REDIS_URL: '127.0.0.1:6379' MONGODB_HOST: '127.0.0.1:27017' - name: Submit coverage - if: matrix.node-version == '18.x' + if: matrix.node-version == '20.x' uses: coverallsapp/github-action@v2.2.0 with: github-token: ${{secrets.GITHUB_TOKEN}} diff --git a/Dockerfile b/Dockerfile index 673547e0..e8a11abd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ # Environment variables must be provided from the outside, eg. using docker-compose. # Do `docker container run $THIS_IMAGE --help` to see the list. -FROM node:18-alpine +FROM node:20-alpine WORKDIR /u-wave-core diff --git a/bin/u-wave-core.js b/bin/u-wave-core.js index a4c43aaf..c58fc052 100755 --- a/bin/u-wave-core.js +++ b/bin/u-wave-core.js @@ -1,7 +1,6 @@ #!/usr/bin/env node /* eslint-disable no-console,no-process-exit */ -import 'make-promises-safe'; import fs from 'node:fs'; import explain from 'explain-error'; import Ajv from 'ajv'; diff --git a/dev/u-wave-dev-server.js b/dev/u-wave-dev-server.js index 560fe303..8eae63ee 100755 --- a/dev/u-wave-dev-server.js +++ b/dev/u-wave-dev-server.js @@ -1,4 +1,3 @@ -import 'make-promises-safe'; import minimist from 'minimist'; import concat from 'concat-stream'; import explain from 'explain-error'; diff --git a/package.json b/package.json index a5f49bef..5650a947 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "u-wave-core": "bin/u-wave-core.js" }, "engines": { - "node": ">= 14.17.0" + "node": ">= 16.20.0" }, "dependencies": { "@twurple/api": "^6.0.6", @@ -45,7 +45,6 @@ "json-merge-patch": "^1.0.2", "jsonwebtoken": "^9.0.0", "lodash": "^4.17.15", - "make-promises-safe": "^5.1.0", "minimist": "^1.2.5", "mongoose": "^7.0.1", "ms": "^2.1.2", @@ -71,7 +70,7 @@ "yaml": "^2.0.0" }, "devDependencies": { - "@tsconfig/node16": "^1.0.3", + "@tsconfig/node16": "^16.1.0", "@types/bcryptjs": "^2.4.2", "@types/cookie": "^0.5.0", "@types/cookie-parser": "^1.4.2", @@ -93,7 +92,6 @@ "@types/qs": "^6.9.6", "@types/random-string": "^0.0.28", "@types/ratelimiter": "^3.4.1", - "@types/redlock": "^4.0.1", "@types/sinon": "^10.0.2", "@types/supertest": "^2.0.11", "@types/ultron": "^1.1.0", diff --git a/src/AuthRegistry.js b/src/AuthRegistry.js index 98cc53d1..1345584f 100644 --- a/src/AuthRegistry.js +++ b/src/AuthRegistry.js @@ -15,7 +15,7 @@ class AuthRegistry { } /** - * @param {import('./models').User} user + * @param {import('./models/index.js').User} user */ async createAuthToken(user) { const token = (await randomBytes(64)).toString('hex'); diff --git a/src/HttpApi.js b/src/HttpApi.js index 5330b1c4..2591e0bd 100644 --- a/src/HttpApi.js +++ b/src/HttpApi.js @@ -1,12 +1,12 @@ import fs from 'node:fs'; +import http from 'node:http'; import { randomUUID } from 'node:crypto'; import express from 'express'; import bodyParser from 'body-parser'; import cookieParser from 'cookie-parser'; import cors from 'cors'; import helmet from 'helmet'; -import http from 'node:http'; -import pinoHttp from 'pino-http'; +import { pinoHttp } from 'pino-http'; // routes import authenticate from './routes/authenticate.js'; @@ -70,7 +70,7 @@ function defaultCreatePasswordResetEmail({ token, requestUrl }) { */ /** - * @param {import('./Uwave').Boot} uw + * @param {import('./Uwave.js').Boot} uw * @param {HttpApiOptions} options */ async function httpApi(uw, options) { @@ -158,7 +158,7 @@ async function httpApi(uw, options) { } /** - * @param {import('./Uwave').Boot} uw + * @param {import('./Uwave.js').Boot} uw */ async function errorHandling(uw) { uw.logger.debug({ ns: 'uwave:http-api' }, 'setup HTTP error handling'); diff --git a/src/SocketServer.js b/src/SocketServer.js index 68e5baff..a378b99b 100644 --- a/src/SocketServer.js +++ b/src/SocketServer.js @@ -16,7 +16,7 @@ import { serializeUser } from './utils/serialize.js'; const { debounce, isEmpty } = lodash; /** - * @typedef {import('./models').User} User + * @typedef {import('./models/index.js').User} User */ /** @@ -59,7 +59,7 @@ function has(object, property) { class SocketServer { /** - * @param {import('./Uwave').Boot} uw + * @param {import('./Uwave.js').Boot} uw * @param {{ secret: Buffer|string }} options */ static async plugin(uw, options) { @@ -114,14 +114,14 @@ class SocketServer { /** * Handlers for commands that come in from the server side. * - * @type {import('./redisMessages').ServerActions} + * @type {import('./redisMessages.js').ServerActions} */ #serverActions; /** * Create a socket server. * - * @param {import('./Uwave').default} uw üWave Core instance. + * @param {import('./Uwave.js').default} uw üWave Core instance. * @param {object} options Socket server options. * @param {number} [options.timeout] Time in seconds to wait for disconnected * users to reconnect before removing them. @@ -143,7 +143,7 @@ class SocketServer { this.#redisSubscription = uw.redis.duplicate(); this.options = { - /** @type {(_socket: import('ws') | undefined, err: Error) => void} */ + /** @type {(_socket: import('ws').WebSocket | undefined, err: Error) => void} */ onError: (_socket, err) => { throw err; }, @@ -453,7 +453,7 @@ class SocketServer { } /** - * @param {import('ws')} socket + * @param {import('ws').WebSocket} socket * @param {import('http').IncomingMessage} request * @private */ @@ -467,7 +467,7 @@ class SocketServer { } /** - * @param {import('ws')} socket + * @param {import('ws').WebSocket} socket * @param {Error} error * @private */ @@ -502,7 +502,7 @@ class SocketServer { /** * Create a connection instance for an unauthenticated user. * - * @param {import('ws')} socket + * @param {import('ws').WebSocket} socket * @private */ createGuestConnection(socket) { diff --git a/src/Source.js b/src/Source.js index f24fe9a8..6e912d43 100644 --- a/src/Source.js +++ b/src/Source.js @@ -1,9 +1,9 @@ import { SourceNoImportError } from './errors/index.js'; /** - * @typedef {import('./models').User} User - * @typedef {import('./models').Playlist} Playlist - * @typedef {import('./plugins/playlists').PlaylistItemDesc} PlaylistItemDesc + * @typedef {import('./models/index.js').User} User + * @typedef {import('./models/index.js').Playlist} Playlist + * @typedef {import('./plugins/playlists.js').PlaylistItemDesc} PlaylistItemDesc */ /** @@ -34,7 +34,7 @@ import { SourceNoImportError } from './errors/index.js'; */ class SourceContext { /** - * @param {import('./Uwave').default} uw + * @param {import('./Uwave.js').default} uw * @param {Source} source * @param {User} user */ @@ -79,7 +79,7 @@ class ImportContext extends SourceContext { */ class Source { /** - * @param {import('./Uwave').default} uw + * @param {import('./Uwave.js').default} uw * @param {string} sourceType * @param {SourcePlugin} sourcePlugin */ diff --git a/src/Uwave.js b/src/Uwave.js index 579187d3..5526c7d3 100644 --- a/src/Uwave.js +++ b/src/Uwave.js @@ -26,7 +26,7 @@ const DEFAULT_MONGO_URL = 'mongodb://localhost:27017/uwave'; const DEFAULT_REDIS_URL = 'redis://localhost:6379'; /** - * @typedef {import('./Source').SourcePlugin} SourcePlugin + * @typedef {import('./Source.js').SourcePlugin} SourcePlugin */ /** @@ -40,7 +40,7 @@ const DEFAULT_REDIS_URL = 'redis://localhost:6379'; * mongo?: string, * redis?: string | RedisOptions, * logger?: import('pino').LoggerOptions, - * } & import('./HttpApi').HttpApiOptions} Options + * } & import('./HttpApi.js').HttpApiOptions} Options */ class UwaveServer extends EventEmitter { @@ -55,66 +55,66 @@ class UwaveServer extends EventEmitter { // @ts-expect-error TS2564 Definitely assigned in a plugin express; - /** @type {import('./models').Models} */ + /** @type {import('./models/index.js').Models} */ // @ts-expect-error TS2564 Definitely assigned in a plugin models; - /** @type {import('./plugins/acl').Acl} */ + /** @type {import('./plugins/acl.js').Acl} */ // @ts-expect-error TS2564 Definitely assigned in a plugin acl; - /** @type {import('./plugins/bans').Bans} */ + /** @type {import('./plugins/bans.js').Bans} */ // @ts-expect-error TS2564 Definitely assigned in a plugin bans; - /** @type {import('./plugins/booth').Booth} */ + /** @type {import('./plugins/booth.js').Booth} */ // @ts-expect-error TS2564 Definitely assigned in a plugin booth; - /** @type {import('./plugins/chat').Chat} */ + /** @type {import('./plugins/chat.js').Chat} */ // @ts-expect-error TS2564 Definitely assigned in a plugin chat; - /** @type {import('./plugins/configStore').ConfigStore} */ + /** @type {import('./plugins/configStore.js').ConfigStore} */ // @ts-expect-error TS2564 Definitely assigned in a plugin config; - /** @type {import('./plugins/emotes').Emotes|null} */ + /** @type {import('./plugins/emotes.js').Emotes|null} */ emotes = null; - /** @type {import('./plugins/history').HistoryRepository} */ + /** @type {import('./plugins/history.js').HistoryRepository} */ // @ts-expect-error TS2564 Definitely assigned in a plugin history; - /** @type {import('./plugins/migrations').Migrate} */ + /** @type {import('./plugins/migrations.js').Migrate} */ // @ts-expect-error TS2564 Definitely assigned in a plugin migrate; - /** @type {import('./plugins/motd').MOTD} */ + /** @type {import('./plugins/motd.js').MOTD} */ // @ts-expect-error TS2564 Definitely assigned in a plugin motd; - /** @type {import('./plugins/passport').Passport} */ + /** @type {import('./plugins/passport.js').Passport} */ // @ts-expect-error TS2564 Definitely assigned in a plugin passport; - /** @type {import('./plugins/playlists').PlaylistsRepository} */ + /** @type {import('./plugins/playlists.js').PlaylistsRepository} */ // @ts-expect-error TS2564 Definitely assigned in a plugin playlists; - /** @type {import('./plugins/users').UsersRepository} */ + /** @type {import('./plugins/users.js').UsersRepository} */ // @ts-expect-error TS2564 Definitely assigned in a plugin users; - /** @type {import('./plugins/waitlist').Waitlist} */ + /** @type {import('./plugins/waitlist.js').Waitlist} */ // @ts-expect-error TS2564 Definitely assigned in a plugin waitlist; - /** @type {import('./HttpApi').HttpApi} */ + /** @type {import('./HttpApi.js').HttpApi} */ // @ts-expect-error TS2564 Definitely assigned in a plugin httpApi; - /** @type {import('./SocketServer').default} */ + /** @type {import('./SocketServer.js').default} */ // @ts-expect-error TS2564 Definitely assigned in a plugin socketServer; @@ -304,9 +304,9 @@ class UwaveServer extends EventEmitter { /** * Publish an event to the üWave channel. * - * @template {keyof import('./redisMessages').ServerActionParameters} CommandName + * @template {keyof import('./redisMessages.js').ServerActionParameters} CommandName * @param {CommandName} command - * @param {import('./redisMessages').ServerActionParameters[CommandName]} data + * @param {import('./redisMessages.js').ServerActionParameters[CommandName]} data */ publish(command, data) { this.redis.publish('uwave', JSON.stringify({ diff --git a/src/auth/JWTStrategy.js b/src/auth/JWTStrategy.js index 837048b6..fdf551ab 100644 --- a/src/auth/JWTStrategy.js +++ b/src/auth/JWTStrategy.js @@ -3,7 +3,7 @@ import { Strategy } from 'passport'; import jwt from 'jsonwebtoken'; import { BannedError } from '../errors/index.js'; -/** @typedef {import('../models').User} User */ +/** @typedef {import('../models/index.js').User} User */ /** * @param {Record} cookies diff --git a/src/controllers/acl.js b/src/controllers/acl.js index 2b137f06..4050cff9 100644 --- a/src/controllers/acl.js +++ b/src/controllers/acl.js @@ -1,7 +1,7 @@ import toItemResponse from '../utils/toItemResponse.js'; /** - * @type {import('../types').AuthenticatedController} + * @type {import('../types.js').AuthenticatedController} */ async function list(req) { const { acl } = req.uwave; @@ -22,7 +22,7 @@ async function list(req) { */ /** - * @type {import('../types').AuthenticatedController} + * @type {import('../types.js').AuthenticatedController} */ async function createRole(req, res) { const { name } = req.params; @@ -38,7 +38,7 @@ async function createRole(req, res) { } /** - * @type {import('../types').AuthenticatedController} + * @type {import('../types.js').AuthenticatedController} */ async function deleteRole(req) { const { name } = req.params; diff --git a/src/controllers/authenticate.js b/src/controllers/authenticate.js index 308df162..53dece86 100644 --- a/src/controllers/authenticate.js +++ b/src/controllers/authenticate.js @@ -41,7 +41,7 @@ function seconds(str) { } /** - * @type {import('../types').Controller} + * @type {import('../types.js').Controller} */ async function getCurrentUser(req) { return toItemResponse(req.user ?? null, { @@ -50,7 +50,7 @@ async function getCurrentUser(req) { } /** - * @type {import('../types').Controller} + * @type {import('../types.js').Controller} */ async function getAuthStrategies(req) { const { passport } = req.uwave; @@ -65,8 +65,8 @@ async function getAuthStrategies(req) { /** * @param {import('express').Response} res - * @param {import('../HttpApi').HttpApi} api - * @param {import('../models').User} user + * @param {import('../HttpApi.js').HttpApi} api + * @param {import('../models/index.js').User} user * @param {AuthenticateOptions & { session: 'cookie' | 'token' }} options */ async function refreshSession(res, api, user, options) { @@ -99,7 +99,7 @@ async function refreshSession(res, api, user, options) { * @typedef {object} LoginQuery * @prop {'cookie'|'token'} [session] * - * @param {import('../types').AuthenticatedRequest<{}, LoginQuery, {}> & WithAuthOptions} req + * @param {import('../types.js').AuthenticatedRequest<{}, LoginQuery, {}> & WithAuthOptions} req * @param {import('express').Response} res */ async function login(req, res) { @@ -128,14 +128,14 @@ async function login(req, res) { } /** - * @param {import('../Uwave').default} uw - * @param {import('../models').User} user + * @param {import('../Uwave.js').default} uw + * @param {import('../models/index.js').User} user * @param {string} service */ async function getSocialAvatar(uw, user, service) { const { Authentication } = uw.models; - /** @type {import('../models').Authentication|null} */ + /** @type {import('../models/index.js').Authentication|null} */ const auth = await Authentication.findOne({ user: user._id, type: service, @@ -148,7 +148,7 @@ async function getSocialAvatar(uw, user, service) { /** * @param {string} service - * @param {import('../types').AuthenticatedRequest & WithAuthOptions} req + * @param {import('../types.js').AuthenticatedRequest & WithAuthOptions} req * @param {import('express').Response} res */ async function socialLoginCallback(service, req, res) { @@ -221,7 +221,7 @@ async function socialLoginCallback(service, req, res) { /** * @param {string} service - * @param {import('../types').Request<{}, SocialLoginFinishQuery, SocialLoginFinishBody> & + * @param {import('../types.js').Request<{}, SocialLoginFinishQuery, SocialLoginFinishBody> & * WithAuthOptions} req * @param {import('express').Response} res */ @@ -271,7 +271,7 @@ async function socialLoginFinish(service, req, res) { } /** - * @type {import('../types').AuthenticatedController} + * @type {import('../types.js').AuthenticatedController} */ async function getSocketToken(req) { const { user } = req; @@ -320,7 +320,7 @@ async function verifyCaptcha(responseString, options) { */ /** - * @param {import('../types').Request<{}, {}, RegisterBody> & WithAuthOptions} req + * @param {import('../types.js').Request<{}, {}, RegisterBody> & WithAuthOptions} req */ async function register(req) { const { users } = req.uwave; @@ -360,7 +360,7 @@ async function register(req) { */ /** - * @param {import('../types').Request<{}, {}, RequestPasswordResetBody> & WithAuthOptions} req + * @param {import('../types.js').Request<{}, {}, RequestPasswordResetBody> & WithAuthOptions} req */ async function reset(req) { const uw = req.uwave; @@ -402,7 +402,7 @@ async function reset(req) { */ /** - * @type {import('../types').Controller} + * @type {import('../types.js').Controller} */ async function changePassword(req) { const { users, redis } = req.uwave; @@ -431,7 +431,7 @@ async function changePassword(req) { } /** - * @param {import('../types').AuthenticatedRequest<{}, {}, {}> & WithAuthOptions} req + * @param {import('../types.js').AuthenticatedRequest<{}, {}, {}> & WithAuthOptions} req * @param {import('express').Response} res */ async function logout(req, res) { diff --git a/src/controllers/bans.js b/src/controllers/bans.js index 50aa4610..5b1063af 100644 --- a/src/controllers/bans.js +++ b/src/controllers/bans.js @@ -9,7 +9,7 @@ import toPaginatedResponse from '../utils/toPaginatedResponse.js'; */ /** - * @type {import('../types').AuthenticatedController<{}, GetBansQuery>} + * @type {import('../types.js').AuthenticatedController<{}, GetBansQuery>} */ async function getBans(req) { const { bans } = req.uwave; @@ -35,7 +35,7 @@ async function getBans(req) { */ /** - * @type {import('../types').AuthenticatedController<{}, {}, AddBanBody>} + * @type {import('../types.js').AuthenticatedController<{}, {}, AddBanBody>} */ async function addBan(req) { const { user: moderator } = req; @@ -70,7 +70,7 @@ async function addBan(req) { */ /** - * @type {import('../types').AuthenticatedController} + * @type {import('../types.js').AuthenticatedController} */ async function removeBan(req) { const { user: moderator } = req; diff --git a/src/controllers/booth.js b/src/controllers/booth.js index c54e8e04..91a34d7a 100644 --- a/src/controllers/booth.js +++ b/src/controllers/booth.js @@ -15,7 +15,7 @@ import toPaginatedResponse from '../utils/toPaginatedResponse.js'; const { ObjectId } = mongoose.Types; /** - * @param {import('../Uwave').default} uw + * @param {import('../Uwave.js').default} uw */ async function getBoothData(uw) { const { booth } = uw; @@ -43,7 +43,7 @@ async function getBoothData(uw) { } /** - * @type {import('../types').Controller} + * @type {import('../types.js').Controller} */ async function getBooth(req) { const uw = req.uwave; @@ -54,7 +54,7 @@ async function getBooth(req) { } /** - * @param {import('../Uwave').default} uw + * @param {import('../Uwave.js').default} uw * @returns {Promise} */ function getCurrentDJ(uw) { @@ -62,7 +62,7 @@ function getCurrentDJ(uw) { } /** - * @param {import('../Uwave').default} uw + * @param {import('../Uwave.js').default} uw * @param {string|null} moderatorID - `null` if a user is skipping their own turn. * @param {string} userID * @param {string|null} reason @@ -93,7 +93,7 @@ async function doSkip(uw, moderatorID, userID, reason, opts = {}) { */ /** - * @type {import('../types').AuthenticatedController<{}, {}, SkipBoothBody>} + * @type {import('../types.js').AuthenticatedController<{}, {}, SkipBoothBody>} */ async function skipBooth(req) { const { user } = req; @@ -131,7 +131,7 @@ async function skipBooth(req) { */ /** - * @type {import('../types').AuthenticatedController<{}, {}, ReplaceBoothBody>} + * @type {import('../types.js').AuthenticatedController<{}, {}, ReplaceBoothBody>} */ async function replaceBooth(req) { const uw = req.uwave; @@ -160,7 +160,7 @@ async function replaceBooth(req) { } /** - * @param {import('../Uwave').default} uw + * @param {import('../Uwave.js').default} uw * @param {string} userID * @param {1|-1} direction */ @@ -189,7 +189,7 @@ async function addVote(uw, userID, direction) { /** * Old way of voting: over the WebSocket * - * @param {import('../Uwave').default} uw + * @param {import('../Uwave.js').default} uw * @param {string} userID * @param {1|-1} direction */ @@ -212,7 +212,7 @@ async function socketVote(uw, userID, direction) { */ /** - * @type {import('../types').AuthenticatedController} + * @type {import('../types.js').AuthenticatedController} */ async function getVote(req) { const { uwave: uw, user } = req; @@ -253,7 +253,7 @@ async function getVote(req) { */ /** - * @type {import('../types').AuthenticatedController} + * @type {import('../types.js').AuthenticatedController} */ async function vote(req) { const { uwave: uw, user } = req; @@ -290,7 +290,7 @@ async function vote(req) { */ /** - * @type {import('../types').AuthenticatedController<{}, {}, FavoriteBody>} + * @type {import('../types.js').AuthenticatedController<{}, {}, FavoriteBody>} */ async function favorite(req) { const { user } = req; @@ -339,10 +339,10 @@ async function favorite(req) { /** * @typedef {object} GetRoomHistoryQuery - * @prop {import('../types').PaginationQuery & { media?: string }} [filter] + * @prop {import('../types.js').PaginationQuery & { media?: string }} [filter] */ /** - * @type {import('../types').Controller} + * @type {import('../types.js').Controller} */ async function getHistory(req) { const filter = {}; diff --git a/src/controllers/chat.js b/src/controllers/chat.js index 6fc4016a..f07e51eb 100644 --- a/src/controllers/chat.js +++ b/src/controllers/chat.js @@ -10,7 +10,7 @@ import toItemResponse from '../utils/toItemResponse.js'; */ /** - * @type {import('../types').AuthenticatedController} + * @type {import('../types.js').AuthenticatedController} */ async function muteUser(req) { const { user: moderator } = req; @@ -36,7 +36,7 @@ async function muteUser(req) { */ /** - * @type {import('../types').AuthenticatedController} + * @type {import('../types.js').AuthenticatedController} */ async function unmuteUser(req) { const { user: moderator } = req; @@ -56,7 +56,7 @@ async function unmuteUser(req) { } /** - * @type {import('../types').AuthenticatedController} + * @type {import('../types.js').AuthenticatedController} */ async function deleteAll(req) { const { user: moderator } = req; @@ -73,7 +73,7 @@ async function deleteAll(req) { */ /** - * @type {import('../types').AuthenticatedController} + * @type {import('../types.js').AuthenticatedController} */ async function deleteByUser(req) { const { user: moderator } = req; @@ -91,7 +91,7 @@ async function deleteByUser(req) { */ /** - * @type {import('../types').AuthenticatedController} + * @type {import('../types.js').AuthenticatedController} */ async function deleteMessage(req) { const { user: moderator } = req; diff --git a/src/controllers/emotes.js b/src/controllers/emotes.js index a756764d..f6ed8ce4 100644 --- a/src/controllers/emotes.js +++ b/src/controllers/emotes.js @@ -1,7 +1,7 @@ import toListResponse from '../utils/toListResponse.js'; /** - * @type {import('../types').Controller} + * @type {import('../types.js').Controller} */ async function getEmotes(req) { const { emotes } = req.uwave; diff --git a/src/controllers/import.js b/src/controllers/import.js index dbbf2e08..e34bb443 100644 --- a/src/controllers/import.js +++ b/src/controllers/import.js @@ -1,7 +1,7 @@ import { SourceNotFoundError, SourceNoImportError, APIError } from '../errors/index.js'; /** - * @param {import('../types').Request} req + * @param {import('../types.js').Request} req */ const getImportableSource = (req) => { const uw = req.uwave; @@ -19,7 +19,7 @@ const getImportableSource = (req) => { }; /** - * @param {import('../types').Request} req + * @param {import('../types.js').Request} req */ const mergeImportParameters = (req) => ({ ...req.query, @@ -28,7 +28,7 @@ const mergeImportParameters = (req) => ({ }); /** - * @type {import('../types').AuthenticatedController} + * @type {import('../types.js').AuthenticatedController} */ async function importAction(req) { const source = getImportableSource(req); diff --git a/src/controllers/motd.js b/src/controllers/motd.js index 29c706f0..771ea531 100644 --- a/src/controllers/motd.js +++ b/src/controllers/motd.js @@ -1,7 +1,7 @@ import toItemResponse from '../utils/toItemResponse.js'; /** - * @type {import('../types').Controller<{}, {}, {}>} + * @type {import('../types.js').Controller<{}, {}, {}>} */ async function getMotd(req) { const { motd } = req.uwave; @@ -15,7 +15,7 @@ async function getMotd(req) { } /** - * @type {import('../types').AuthenticatedController<{}, {}, { motd: string | null }>} + * @type {import('../types.js').AuthenticatedController<{}, {}, { motd: string | null }>} */ async function setMotd(req, res) { const { motd } = req.uwave; diff --git a/src/controllers/now.js b/src/controllers/now.js index c14d4cba..65f1ad1c 100644 --- a/src/controllers/now.js +++ b/src/controllers/now.js @@ -5,8 +5,8 @@ import { serializePlaylist, serializeUser } from '../utils/serialize.js'; const { ObjectId } = mongoose.mongo; /** - * @param {import('../Uwave').default} uw - * @param {Promise} activePlaylist + * @param {import('../Uwave.js').default} uw + * @param {Promise} activePlaylist */ async function getFirstItem(uw, activePlaylist) { try { @@ -31,13 +31,13 @@ function toInt(str) { } /** - * @param {import('../Uwave').default} uw + * @param {import('../Uwave.js').default} uw */ async function getOnlineUsers(uw) { const { User } = uw.models; const userIDs = await uw.redis.lrange('users', 0, -1); - /** @type {Omit[]} */ + /** @type {Omit[]} */ const users = await User.find({ _id: { $in: userIDs.map((id) => new ObjectId(id)), @@ -53,7 +53,7 @@ async function getOnlineUsers(uw) { } /** - * @param {import('../Uwave').default} uw + * @param {import('../Uwave.js').default} uw */ async function getGuestsCount(uw) { const guests = await uw.redis.get('http-api:guests'); @@ -61,7 +61,7 @@ async function getGuestsCount(uw) { } /** - * @type {import('../types').Controller} + * @type {import('../types.js').Controller} */ async function getState(req) { const uw = req.uwave; diff --git a/src/controllers/playlists.js b/src/controllers/playlists.js index 5147d6b0..3a165e0a 100644 --- a/src/controllers/playlists.js +++ b/src/controllers/playlists.js @@ -14,7 +14,7 @@ const { ObjectId } = mongoose.mongo; */ /** - * @type {import('../types').AuthenticatedController<{}, GetPlaylistsQuery>} + * @type {import('../types.js').AuthenticatedController<{}, GetPlaylistsQuery>} */ async function getPlaylists(req) { const { user } = req; @@ -42,7 +42,7 @@ async function getPlaylists(req) { */ /** - * @type {import('../types').AuthenticatedController} + * @type {import('../types.js').AuthenticatedController} */ async function getPlaylist(req) { const { user } = req; @@ -67,7 +67,7 @@ async function getPlaylist(req) { */ /** - * @type {import('../types').AuthenticatedController<{}, {}, CreatePlaylistBody>} + * @type {import('../types.js').AuthenticatedController<{}, {}, CreatePlaylistBody>} */ async function createPlaylist(req) { const { user } = req; @@ -95,7 +95,7 @@ async function createPlaylist(req) { */ /** - * @type {import('../types').AuthenticatedController} + * @type {import('../types.js').AuthenticatedController} */ async function deletePlaylist(req) { const { user } = req; @@ -122,7 +122,8 @@ const patchableKeys = ['name', 'description']; */ /** - * @type {import('../types').AuthenticatedController} + * @type {import('../types.js').AuthenticatedController< + * UpdatePlaylistParams, {}, UpdatePlaylistBody>} */ async function updatePlaylist(req) { const { user } = req; @@ -159,7 +160,8 @@ async function updatePlaylist(req) { */ /** - * @type {import('../types').AuthenticatedController} + * @type {import('../types.js').AuthenticatedController< + * RenamePlaylistParams, {}, RenamePlaylistBody>} */ async function renamePlaylist(req) { const { user } = req; @@ -186,7 +188,7 @@ async function renamePlaylist(req) { */ /** - * @type {import('../types').AuthenticatedController} + * @type {import('../types.js').AuthenticatedController} */ async function activatePlaylist(req) { const { user } = req; @@ -208,11 +210,12 @@ async function activatePlaylist(req) { * @typedef {object} GetPlaylistItemsParams * @prop {string} id * - * @typedef {import('../types').PaginationQuery & { filter?: string }} GetPlaylistItemsQuery + * @typedef {import('../types.js').PaginationQuery & { filter?: string }} GetPlaylistItemsQuery */ /** - * @type {import('../types').AuthenticatedController} + * @type {import('../types.js').AuthenticatedController< + * GetPlaylistItemsParams, GetPlaylistItemsQuery>} */ async function getPlaylistItems(req) { const { user } = req; @@ -237,7 +240,7 @@ async function getPlaylistItems(req) { } /** - * @typedef {import('../plugins/playlists').PlaylistItemDesc} PlaylistItemDesc + * @typedef {import('../plugins/playlists.js').PlaylistItemDesc} PlaylistItemDesc * * @typedef {object} AddPlaylistItemsParams * @prop {string} id @@ -254,7 +257,7 @@ async function getPlaylistItems(req) { */ /** - * @type {import('../types').AuthenticatedController< + * @type {import('../types.js').AuthenticatedController< * AddPlaylistItemsParams, {}, AddPlaylistItemsBody>} */ async function addPlaylistItems(req) { @@ -304,7 +307,7 @@ async function addPlaylistItems(req) { */ /** - * @type {import('../types').AuthenticatedController< + * @type {import('../types.js').AuthenticatedController< * RemovePlaylistItemsParams, {}, RemovePlaylistItemsBody>} */ async function removePlaylistItems(req) { @@ -335,7 +338,7 @@ async function removePlaylistItems(req) { */ /** - * @type {import('../types').AuthenticatedController< + * @type {import('../types.js').AuthenticatedController< * MovePlaylistItemsParams, {}, MovePlaylistItemsBody>} */ async function movePlaylistItems(req) { @@ -371,7 +374,7 @@ async function movePlaylistItems(req) { */ /** - * @type {import('../types').AuthenticatedController} + * @type {import('../types.js').AuthenticatedController} */ async function shufflePlaylistItems(req) { const { user } = req; @@ -395,7 +398,7 @@ async function shufflePlaylistItems(req) { */ /** - * @type {import('../types').AuthenticatedController} + * @type {import('../types.js').AuthenticatedController} */ async function getPlaylistItem(req) { const { user } = req; @@ -428,7 +431,7 @@ async function getPlaylistItem(req) { */ /** - * @type {import('../types').AuthenticatedController< + * @type {import('../types.js').AuthenticatedController< * UpdatePlaylistItemParams, {}, UpdatePlaylistItemBody>} */ async function updatePlaylistItem(req) { @@ -464,7 +467,7 @@ async function updatePlaylistItem(req) { */ /** - * @type {import('../types').AuthenticatedController} + * @type {import('../types.js').AuthenticatedController} */ async function removePlaylistItem(req) { const { user } = req; diff --git a/src/controllers/search.js b/src/controllers/search.js index 7fe498e1..6d39735f 100644 --- a/src/controllers/search.js +++ b/src/controllers/search.js @@ -5,13 +5,13 @@ import toListResponse from '../utils/toListResponse.js'; const { isEqual } = lodash; /** @typedef {import('mongodb').ObjectId} ObjectId */ -/** @typedef {import('../models').Playlist} Playlist */ -/** @typedef {import('../models').Media} Media */ -/** @typedef {import('../plugins/playlists').PlaylistItemDesc} PlaylistItemDesc */ +/** @typedef {import('../models/index.js').Playlist} Playlist */ +/** @typedef {import('../models/index.js').Media} Media */ +/** @typedef {import('../plugins/playlists.js').PlaylistItemDesc} PlaylistItemDesc */ // TODO should be deprecated once the Web client uses the better single-source route. /** - * @type {import('../types').AuthenticatedController} + * @type {import('../types.js').AuthenticatedController} */ async function searchAll(req) { const { user } = req; @@ -36,7 +36,7 @@ async function searchAll(req) { } /** - * @param {import('../Uwave').default} uw + * @param {import('../Uwave.js').default} uw * @param {Map} updates */ async function updateSourceData(uw, updates) { @@ -66,7 +66,7 @@ async function updateSourceData(uw, updates) { */ /** - * @type {import('../types').AuthenticatedController} + * @type {import('../types.js').AuthenticatedController} */ async function search(req) { const { user } = req; diff --git a/src/controllers/server.js b/src/controllers/server.js index 16f82f54..5351b20d 100644 --- a/src/controllers/server.js +++ b/src/controllers/server.js @@ -1,7 +1,7 @@ import toItemResponse from '../utils/toItemResponse.js'; /** - * @type {import('../types').Controller} + * @type {import('../types.js').Controller} */ async function getServerTime(req) { return toItemResponse({ @@ -10,7 +10,7 @@ async function getServerTime(req) { } /** - * @type {import('../types').AuthenticatedController} + * @type {import('../types.js').AuthenticatedController} */ async function getAllConfig(req) { const { config } = req.uwave; @@ -24,7 +24,7 @@ async function getAllConfig(req) { } /** - * @type {import('../types').AuthenticatedController} + * @type {import('../types.js').AuthenticatedController} */ async function getConfig(req) { const { config } = req.uwave; @@ -42,7 +42,7 @@ async function getConfig(req) { } /** - * @type {import('../types').AuthenticatedController} + * @type {import('../types.js').AuthenticatedController} */ async function updateConfig(req) { const { config } = req.uwave; diff --git a/src/controllers/users.js b/src/controllers/users.js index e6af18aa..a5a7155d 100644 --- a/src/controllers/users.js +++ b/src/controllers/users.js @@ -18,7 +18,7 @@ import { muteUser, unmuteUser } from './chat.js'; */ /** - * @type {import('../types').AuthenticatedController<{}, GetUsersQuery>} + * @type {import('../types.js').AuthenticatedController<{}, GetUsersQuery>} */ async function getUsers(req) { const { filter } = req.query; @@ -40,7 +40,7 @@ async function getUsers(req) { */ /** - * @type {import('../types').Controller} + * @type {import('../types.js').Controller} */ async function getUser(req) { const { users } = req.uwave; @@ -62,7 +62,7 @@ async function getUser(req) { */ /** - * @type {import('../types').Controller} + * @type {import('../types.js').Controller} */ async function getUserRoles(req) { const { acl, users } = req.uwave; @@ -87,7 +87,7 @@ async function getUserRoles(req) { */ /** - * @type {import('../types').AuthenticatedController} + * @type {import('../types.js').AuthenticatedController} */ async function addUserRole(req) { const { user: moderator } = req; @@ -118,7 +118,7 @@ async function addUserRole(req) { */ /** - * @type {import('../types').AuthenticatedController} + * @type {import('../types.js').AuthenticatedController} */ async function removeUserRole(req) { const { user: moderator } = req; @@ -151,7 +151,8 @@ async function removeUserRole(req) { */ /** - * @type {import('../types').AuthenticatedController} + * @type {import('../types.js').AuthenticatedController< + * ChangeUsernameParams, {}, ChangeUsernameBody>} */ async function changeUsername(req) { const { user: moderator } = req; @@ -180,7 +181,7 @@ async function changeAvatar() { } /** - * @param {import('../Uwave').default} uw + * @param {import('../Uwave.js').default} uw * @param {import('mongodb').ObjectId} userID */ async function disconnectUser(uw, userID) { @@ -203,7 +204,7 @@ async function disconnectUser(uw, userID) { */ /** - * @type {import('../types').Controller} + * @type {import('../types.js').Controller} */ async function getHistory(req) { const { id } = req.params; diff --git a/src/controllers/waitlist.js b/src/controllers/waitlist.js index 6c551a07..26ed5026 100644 --- a/src/controllers/waitlist.js +++ b/src/controllers/waitlist.js @@ -2,7 +2,7 @@ import toItemResponse from '../utils/toItemResponse.js'; import toListResponse from '../utils/toListResponse.js'; /** - * @type {import('../types').Controller} + * @type {import('../types.js').Controller} */ async function getWaitlist(req) { const { waitlist } = req.uwave; @@ -21,7 +21,7 @@ async function getWaitlist(req) { * POST waitlist/ entry point: used both for joining the waitlist, and for * adding someone else to the waitlist. * - * @type {import('../types').AuthenticatedController<{}, {}, AddToWaitlistBody>} + * @type {import('../types.js').AuthenticatedController<{}, {}, AddToWaitlistBody>} */ async function addToWaitlist(req) { const { user: moderator } = req; @@ -42,7 +42,7 @@ async function addToWaitlist(req) { */ /** - * @type {import('../types').AuthenticatedController<{}, {}, MoveWaitlistBody>} + * @type {import('../types.js').AuthenticatedController<{}, {}, MoveWaitlistBody>} */ async function moveWaitlist(req) { const { user: moderator } = req; @@ -62,7 +62,7 @@ async function moveWaitlist(req) { */ /** - * @type {import('../types').AuthenticatedController} + * @type {import('../types.js').AuthenticatedController} */ async function removeFromWaitlist(req) { const { user: moderator } = req; @@ -77,7 +77,7 @@ async function removeFromWaitlist(req) { } /** - * @type {import('../types').AuthenticatedController} + * @type {import('../types.js').AuthenticatedController} */ async function clearWaitlist(req) { const { user: moderator } = req; @@ -96,7 +96,7 @@ async function clearWaitlist(req) { */ /** - * @type {import('../types').AuthenticatedController<{}, {}, LockWaitlistBody>} + * @type {import('../types.js').AuthenticatedController<{}, {}, LockWaitlistBody>} */ async function lockWaitlist(req) { const { user: moderator } = req; diff --git a/src/index.js b/src/index.js index 368574df..ce73beae 100644 --- a/src/index.js +++ b/src/index.js @@ -4,7 +4,7 @@ import HttpApi from './HttpApi.js'; import SocketServer from './SocketServer.js'; /** - * @param {import('./Uwave').Options} opts + * @param {import('./Uwave.js').Options} opts * @returns {Uwave} */ export default function uwave(opts) { diff --git a/src/middleware/attachUwaveMeta.js b/src/middleware/attachUwaveMeta.js index 25c71f5e..503fa774 100644 --- a/src/middleware/attachUwaveMeta.js +++ b/src/middleware/attachUwaveMeta.js @@ -1,7 +1,7 @@ /** * - * @param {import('../HttpApi').HttpApi} httpApi - * @param {import('../Uwave').default} uw + * @param {import('../HttpApi.js').HttpApi} httpApi + * @param {import('../Uwave.js').default} uw * @returns {import('express').RequestHandler} */ function attachUwaveMeta(httpApi, uw) { diff --git a/src/middleware/requireActiveConnection.js b/src/middleware/requireActiveConnection.js index fa9d4939..19dbdcb6 100644 --- a/src/middleware/requireActiveConnection.js +++ b/src/middleware/requireActiveConnection.js @@ -5,8 +5,8 @@ const { BadRequest } = httpErrors; function requireActiveConnection() { /** - * @param {import('../Uwave').default} uwave - * @param {import('../models').User} user + * @param {import('../Uwave.js').default} uwave + * @param {import('../models/index.js').User} user */ async function isConnected(uwave, user) { const onlineIDs = await uwave.redis.lrange('users', 0, -1); diff --git a/src/models/index.js b/src/models/index.js index 3a3cb372..3a0aa7d0 100644 --- a/src/models/index.js +++ b/src/models/index.js @@ -9,15 +9,15 @@ import playlistItemSchema from './PlaylistItem.js'; import userSchema from './User.js'; /** - * @typedef {import('./AclRole').AclRole} AclRole - * @typedef {import('./Authentication').Authentication} Authentication - * @typedef {import('./Config').Config} Config - * @typedef {import('./History').HistoryEntry} HistoryEntry - * @typedef {import('./Media').Media} Media - * @typedef {import('./Migration').Migration} Migration - * @typedef {import('./Playlist').Playlist} Playlist - * @typedef {import('./PlaylistItem').PlaylistItem} PlaylistItem - * @typedef {import('./User').User} User + * @typedef {import('./AclRole.js').AclRole} AclRole + * @typedef {import('./Authentication.js').Authentication} Authentication + * @typedef {import('./Config.js').Config} Config + * @typedef {import('./History.js').HistoryEntry} HistoryEntry + * @typedef {import('./Media.js').Media} Media + * @typedef {import('./Migration.js').Migration} Migration + * @typedef {import('./Playlist.js').Playlist} Playlist + * @typedef {import('./PlaylistItem.js').PlaylistItem} PlaylistItem + * @typedef {import('./User.js').User} User * @typedef {{ * AclRole: import('mongoose').Model, * Authentication: import('mongoose').Model, @@ -32,7 +32,7 @@ import userSchema from './User.js'; */ /** - * @param {import('../Uwave').default} uw + * @param {import('../Uwave.js').default} uw */ async function models(uw) { uw.models = { diff --git a/src/plugins/acl.js b/src/plugins/acl.js index bbfbfe3f..5d42b495 100644 --- a/src/plugins/acl.js +++ b/src/plugins/acl.js @@ -2,8 +2,8 @@ import defaultRoles from '../config/defaultRoles.js'; import routes from '../routes/acl.js'; /** - * @typedef {import('../models').AclRole} AclRole - * @typedef {import('../models').User} User + * @typedef {import('../models/index.js').AclRole} AclRole + * @typedef {import('../models/index.js').User} User * @typedef {{ roles: AclRole[] }} PopulateRoles * @typedef {Omit & PopulateRoles} PopulatedAclRole */ @@ -24,7 +24,7 @@ class Acl { #logger; /** - * @param {import('../Uwave').default} uw + * @param {import('../Uwave.js').default} uw */ constructor(uw) { this.#uw = uw; @@ -224,7 +224,7 @@ class Acl { } /** - * @param {import('../Uwave').Boot} uw + * @param {import('../Uwave.js').Boot} uw */ async function acl(uw) { uw.acl = new Acl(uw); diff --git a/src/plugins/bans.js b/src/plugins/bans.js index 04544850..ee036a3f 100644 --- a/src/plugins/bans.js +++ b/src/plugins/bans.js @@ -6,9 +6,9 @@ import Page from '../Page.js'; const { clamp, omit } = lodash; /** - * @typedef {import('../models').User} User - * @typedef {import('../models/User').LeanUser} LeanUser - * @typedef {import('../models/User').LeanBanned} LeanBanned + * @typedef {import('../models/index.js').User} User + * @typedef {import('../models/User.js').LeanUser} LeanUser + * @typedef {import('../models/User.js').LeanBanned} LeanBanned * @typedef {LeanBanned & { user: Omit }} Ban */ @@ -30,7 +30,7 @@ class Bans { #uw; /** - * @param {import('../Uwave').default} uw + * @param {import('../Uwave.js').default} uw */ constructor(uw) { this.#uw = uw; @@ -75,7 +75,7 @@ class Bans { const total = await User.find().where(queryFilter).countDocuments(); - /** @type {(import('../models/User').LeanUser & { banned: LeanBanned })[]} */ + /** @type {(import('../models/User.js').LeanUser & { banned: LeanBanned })[]} */ const bannedUsers = await User.find() .where(queryFilter) .skip(offset) @@ -167,7 +167,7 @@ class Bans { } /** - * @param {import('../Uwave').default} uw + * @param {import('../Uwave.js').default} uw */ async function bans(uw) { uw.bans = new Bans(uw); // eslint-disable-line no-param-reassign diff --git a/src/plugins/booth.js b/src/plugins/booth.js index 2549ef24..00d92150 100644 --- a/src/plugins/booth.js +++ b/src/plugins/booth.js @@ -8,12 +8,12 @@ const { omit } = lodash; /** * @typedef {import('type-fest').JsonObject} JsonObject - * @typedef {import('../models').User} User - * @typedef {import('../models').Playlist} Playlist - * @typedef {import('../models').PlaylistItem} PlaylistItem - * @typedef {import('../models').HistoryEntry} HistoryEntry - * @typedef {import('../models/History').HistoryMedia} HistoryMedia - * @typedef {import('../models').Media} Media + * @typedef {import('../models/index.js').User} User + * @typedef {import('../models/index.js').Playlist} Playlist + * @typedef {import('../models/index.js').PlaylistItem} PlaylistItem + * @typedef {import('../models/index.js').HistoryEntry} HistoryEntry + * @typedef {import('../models/History.js').HistoryMedia} HistoryMedia + * @typedef {import('../models/index.js').Media} Media * @typedef {{ user: User }} PopulateUser * @typedef {{ playlist: Playlist }} PopulatePlaylist * @typedef {{ media: Omit & { media: Media } }} PopulateMedia @@ -47,7 +47,7 @@ class Booth { #awaitAdvance = null; /** - * @param {import('../Uwave').Boot} uw + * @param {import('../Uwave.js').Boot} uw */ constructor(uw) { this.#uw = uw; @@ -419,7 +419,7 @@ class Booth { } /** - * @param {import('../Uwave').Boot} uw + * @param {import('../Uwave.js').Boot} uw */ async function boothPlugin(uw) { uw.booth = new Booth(uw); diff --git a/src/plugins/chat.js b/src/plugins/chat.js index cd288198..fbc9b8eb 100644 --- a/src/plugins/chat.js +++ b/src/plugins/chat.js @@ -2,7 +2,7 @@ import { randomUUID } from 'node:crypto'; import routes from '../routes/chat.js'; /** - * @typedef {import('../models').User} User + * @typedef {import('../models/index.js').User} User * * @typedef {object} ChatOptions * @prop {number} maxLength @@ -20,7 +20,7 @@ class Chat { #options; /** - * @param {import('../Uwave').default} uw + * @param {import('../Uwave.js').default} uw * @param {Partial} [options] */ constructor(uw, options = {}) { @@ -115,7 +115,7 @@ class Chat { } /** - * @param {import('../Uwave').default} uw + * @param {import('../Uwave.js').default} uw * @param {Partial} [options] */ async function chat(uw, options = {}) { diff --git a/src/plugins/configStore.js b/src/plugins/configStore.js index 9c57d0ba..44db89d2 100644 --- a/src/plugins/configStore.js +++ b/src/plugins/configStore.js @@ -9,7 +9,7 @@ import ValidationError from '../errors/ValidationError.js'; const { omit } = lodash; -/** @typedef {import('../models').User} User */ +/** @typedef {import('../models/index.js').User} User */ /** * Extensible configuration store. @@ -33,7 +33,7 @@ class ConfigStore { #validators = new Map(); /** - * @param {import('../Uwave').Boot} uw + * @param {import('../Uwave.js').Boot} uw */ constructor(uw) { this.#uw = uw; @@ -69,7 +69,7 @@ class ConfigStore { /** * @type {undefined|{ * command: string, - * data: import('../redisMessages').ServerActionParameters['configStore:update'], + * data: import('../redisMessages.js').ServerActionParameters['configStore:update'], * }} */ const json = sjson.safeParse(rawCommand); @@ -233,7 +233,7 @@ class ConfigStore { } /** - * @param {import('../Uwave').Boot} uw + * @param {import('../Uwave.js').Boot} uw */ async function configStorePlugin(uw) { uw.config = new ConfigStore(uw); diff --git a/src/plugins/emotes.js b/src/plugins/emotes.js index cec625aa..4bfc960c 100644 --- a/src/plugins/emotes.js +++ b/src/plugins/emotes.js @@ -226,7 +226,7 @@ class Emotes { #ready = Promise.resolve(); /** - * @param {import('../Uwave').Boot} uw + * @param {import('../Uwave.js').Boot} uw */ constructor(uw) { this.#uw = uw; @@ -323,7 +323,7 @@ class Emotes { } /** - * @param {import('../Uwave').Boot} uw + * @param {import('../Uwave.js').Boot} uw * @returns {Promise} */ async function emotesPlugin(uw) { diff --git a/src/plugins/history.js b/src/plugins/history.js index a08c2724..e2ffd086 100644 --- a/src/plugins/history.js +++ b/src/plugins/history.js @@ -7,10 +7,10 @@ const DEFAULT_PAGE_SIZE = 50; const MAX_PAGE_SIZE = 100; /** - * @typedef {import('../models/History').HistoryMedia} HistoryMedia - * @typedef {import('../models').HistoryEntry} HistoryEntry - * @typedef {import('../models').User} User - * @typedef {import('../models').Media} Media + * @typedef {import('../models/History.js').HistoryMedia} HistoryMedia + * @typedef {import('../models/index.js').HistoryEntry} HistoryEntry + * @typedef {import('../models/index.js').User} User + * @typedef {import('../models/index.js').Media} Media * @typedef {{ media: Media }} PopulateMedia * @typedef {{ user: User }} PopulateUser * @typedef {HistoryMedia & PopulateMedia} PopulatedHistoryMedia @@ -22,7 +22,7 @@ class HistoryRepository { #uw; /** - * @param {import('../Uwave').default} uw + * @param {import('../Uwave.js').default} uw */ constructor(uw) { this.#uw = uw; @@ -82,7 +82,7 @@ class HistoryRepository { } /** - * @param {import('../Uwave').default} uw + * @param {import('../Uwave.js').default} uw */ async function history(uw) { uw.history = new HistoryRepository(uw); diff --git a/src/plugins/migrations.js b/src/plugins/migrations.js index c9c554ee..4cf2417c 100644 --- a/src/plugins/migrations.js +++ b/src/plugins/migrations.js @@ -3,7 +3,7 @@ import RedLock from 'redlock'; import { Umzug } from 'umzug'; /** - * @typedef {import('../Uwave').default} Uwave + * @typedef {import('../Uwave.js').default} Uwave */ /** diff --git a/src/plugins/motd.js b/src/plugins/motd.js index f5a0c031..cdfb90a5 100644 --- a/src/plugins/motd.js +++ b/src/plugins/motd.js @@ -4,7 +4,7 @@ class MOTD { #uw; /** - * @param {import('../Uwave').default} uw + * @param {import('../Uwave.js').default} uw */ constructor(uw) { this.#uw = uw; @@ -31,7 +31,7 @@ class MOTD { } /** - * @param {import('../Uwave').default} uw + * @param {import('../Uwave.js').default} uw */ async function motdPlugin(uw) { uw.motd = new MOTD(uw); diff --git a/src/plugins/passport.js b/src/plugins/passport.js index 01cd2d1b..7da669e4 100644 --- a/src/plugins/passport.js +++ b/src/plugins/passport.js @@ -10,7 +10,7 @@ const schema = JSON.parse( ); /** - * @typedef {import('../models/User').User} User + * @typedef {import('../models/User.js').User} User * * @typedef {{ * callbackURL?: string, @@ -32,7 +32,7 @@ class PassportPlugin extends Passport { #logger; /** - * @param {import('../Uwave').Boot} uw + * @param {import('../Uwave.js').Boot} uw * @param {{ secret: Buffer|string }} options */ constructor(uw, options) { @@ -155,7 +155,7 @@ class PassportPlugin extends Passport { } /** - * @param {import('../Uwave').Boot} uw + * @param {import('../Uwave.js').Boot} uw * @param {{ secret: Buffer|string }} options */ async function passportPlugin(uw, options) { diff --git a/src/plugins/playlists.js b/src/plugins/playlists.js index 3dd0ec82..d1a84a4e 100644 --- a/src/plugins/playlists.js +++ b/src/plugins/playlists.js @@ -16,11 +16,11 @@ const { groupBy, shuffle } = lodash; * @typedef {import('mongoose').PipelineStage} PipelineStage * @typedef {import('mongoose').PipelineStage.Facet['$facet'][string]} FacetPipelineStage * @typedef {import('mongodb').ObjectId} ObjectId - * @typedef {import('../models').User} User - * @typedef {import('../models').Playlist} Playlist - * @typedef {import('../models/Playlist').LeanPlaylist} LeanPlaylist - * @typedef {import('../models').PlaylistItem} PlaylistItem - * @typedef {import('../models').Media} Media + * @typedef {import('../models/index.js').User} User + * @typedef {import('../models/index.js').Playlist} Playlist + * @typedef {import('../models/Playlist.js').LeanPlaylist} LeanPlaylist + * @typedef {import('../models/index.js').PlaylistItem} PlaylistItem + * @typedef {import('../models/index.js').Media} Media * @typedef {{ media: Media }} PopulateMedia */ @@ -87,7 +87,7 @@ class PlaylistsRepository { #logger; /** - * @param {import('../Uwave').default} uw + * @param {import('../Uwave.js').default} uw */ constructor(uw) { this.#uw = uw; @@ -601,7 +601,7 @@ class PlaylistsRepository { } /** - * @param {import('../Uwave').default} uw + * @param {import('../Uwave.js').default} uw */ async function playlistsPlugin(uw) { uw.playlists = new PlaylistsRepository(uw); diff --git a/src/plugins/users.js b/src/plugins/users.js index b8c256d1..77324205 100644 --- a/src/plugins/users.js +++ b/src/plugins/users.js @@ -4,7 +4,8 @@ import Page from '../Page.js'; import { IncorrectPasswordError, UserNotFoundError } from '../errors/index.js'; /** - * @typedef {import('../models').User} User + * @typedef {import('../models/index.js').User} User + * @typedef {import('../models/index.js').Authentication} Authentication */ /** @@ -27,7 +28,7 @@ class UsersRepository { #logger; /** - * @param {import('../Uwave').default} uw + * @param {import('../Uwave.js').default} uw */ constructor(uw) { this.#uw = uw; @@ -125,7 +126,7 @@ class UsersRepository { async localLogin({ email, password }) { const { Authentication } = this.#uw.models; - /** @type {null | (import('../models').Authentication & { user: User })} */ + /** @type {null | (Authentication & { user: User })} */ const auth = /** @type {any} */ (await Authentication.findOne({ email: email.toLowerCase(), }).populate('user').exec()); @@ -179,7 +180,7 @@ class UsersRepository { // we need this type assertion because the `user` property actually contains // an ObjectId in this return value. We are definitely filling in a User object // below before using this variable. - /** @type {null | (Omit & { user: User })} */ + /** @type {null | (Omit & { user: User })} */ let auth = await Authentication.findOne({ type, id }); if (auth) { await auth.populate('user'); @@ -351,7 +352,7 @@ class UsersRepository { } /** - * @param {import('../Uwave').default} uw + * @param {import('../Uwave.js').default} uw */ async function usersPlugin(uw) { uw.users = new UsersRepository(uw); diff --git a/src/plugins/waitlist.js b/src/plugins/waitlist.js index 33fd91bb..db7a990f 100644 --- a/src/plugins/waitlist.js +++ b/src/plugins/waitlist.js @@ -15,7 +15,7 @@ const schema = JSON.parse( ); /** - * @typedef {import('../models').User} User + * @typedef {import('../models/index.js').User} User * * @typedef {{ cycle: boolean, locked: boolean }} WaitlistSettings */ @@ -81,7 +81,7 @@ class Waitlist { #uw; /** - * @param {import('../Uwave').Boot} uw + * @param {import('../Uwave.js').Boot} uw */ constructor(uw) { this.#uw = uw; @@ -361,7 +361,7 @@ class Waitlist { } /** - * @param {import('../Uwave').Boot} uw + * @param {import('../Uwave.js').Boot} uw * @returns {Promise} */ async function waitlistPlugin(uw) { diff --git a/src/route.js b/src/route.js index 4edabbf6..f73c3b72 100644 --- a/src/route.js +++ b/src/route.js @@ -4,14 +4,14 @@ * @template {import('type-fest').JsonObject} TBody * @template {any} TExtra * @param {( - * req: import('./types').Request & TExtra, + * req: import('./types.js').Request & TExtra, * res: import('express').Response, * ) => Promise} handler * @returns {import('express').RequestHandler} */ function route(handler) { return (rawReq, res, next) => { - /** @type {import('./types').Request & TExtra} */ + /** @type {import('./types.js').Request & TExtra} */ // @ts-expect-error TS2322 const req = rawReq; diff --git a/src/routes/authenticate.js b/src/routes/authenticate.js index b284802c..adab604e 100644 --- a/src/routes/authenticate.js +++ b/src/routes/authenticate.js @@ -6,7 +6,7 @@ import schema from '../middleware/schema.js'; import * as controller from '../controllers/authenticate.js'; /** - * @param {import('../controllers/authenticate').AuthenticateOptions} options + * @param {import('../controllers/authenticate.js').AuthenticateOptions} options * @returns {import('express').RequestHandler} */ function withOptions(options) { @@ -18,7 +18,7 @@ function withOptions(options) { /** * @param {import('passport').Authenticator} passport - * @param {import('../controllers/authenticate').AuthenticateOptions} options + * @param {import('../controllers/authenticate.js').AuthenticateOptions} options */ function authenticateRoutes(passport, options) { const auth = Router() @@ -91,7 +91,7 @@ function authenticateRoutes(passport, options) { passport.authenticate('google'), withOptions(options), (rawReq, res, next) => { - /** @type {import('../types').AuthenticatedRequest & controller.WithAuthOptions} */ + /** @type {import('../types.js').AuthenticatedRequest & controller.WithAuthOptions} */ // Correct type is guaranteed by `passport.authenticate()` and `withOptions()` middlewares. const req = /** @type {any} */ (rawReq); controller.socialLoginCallback('google', req, res).catch(next); diff --git a/src/sockets/AuthedConnection.js b/src/sockets/AuthedConnection.js index 8ced1a74..9e7edcb8 100644 --- a/src/sockets/AuthedConnection.js +++ b/src/sockets/AuthedConnection.js @@ -7,9 +7,9 @@ class AuthedConnection extends EventEmitter { #logger; /** - * @param {import('../Uwave').default} uw + * @param {import('../Uwave.js').default} uw * @param {import('ws').WebSocket} socket - * @param {import('../models').User} user + * @param {import('../models/index.js').User} user */ constructor(uw, socket, user) { super(); diff --git a/src/sockets/GuestConnection.js b/src/sockets/GuestConnection.js index bd9dfbd2..122e2470 100644 --- a/src/sockets/GuestConnection.js +++ b/src/sockets/GuestConnection.js @@ -5,9 +5,9 @@ class GuestConnection extends EventEmitter { #logger; /** - * @param {import('../Uwave').default} uw + * @param {import('../Uwave.js').default} uw * @param {import('ws').WebSocket} socket - * @param {{ authRegistry: import('../AuthRegistry').default }} options + * @param {{ authRegistry: import('../AuthRegistry.js').default }} options */ constructor(uw, socket, options) { super(); @@ -61,7 +61,7 @@ class GuestConnection extends EventEmitter { } /** - * @param {import('../models').User} user + * @param {import('../models/index.js').User} user */ isReconnect(user) { return this.uw.redis.exists(`http-api:disconnected:${user.id}`); diff --git a/src/sockets/LostConnection.js b/src/sockets/LostConnection.js index 6499f68a..56832a15 100644 --- a/src/sockets/LostConnection.js +++ b/src/sockets/LostConnection.js @@ -4,8 +4,8 @@ class LostConnection extends EventEmitter { #logger; /** - * @param {import('../Uwave').default} uw - * @param {import('../models').User} user + * @param {import('../Uwave.js').default} uw + * @param {import('../models/index.js').User} user */ constructor(uw, user, timeout = 30) { super(); diff --git a/src/utils/removeFromWaitlist.js b/src/utils/removeFromWaitlist.js index bf20a9e7..27c5172e 100644 --- a/src/utils/removeFromWaitlist.js +++ b/src/utils/removeFromWaitlist.js @@ -1,12 +1,12 @@ /** - * @param {import('../Uwave').default} uw + * @param {import('../Uwave.js').default} uw */ function getWaitingUserIDs(uw) { return uw.redis.lrange('waitlist', 0, -1); } /** - * @param {import('../Uwave').default} uw + * @param {import('../Uwave.js').default} uw * @param {import('mongodb').ObjectId} userID */ async function removeFromWaitlist(uw, userID) { diff --git a/src/utils/serialize.js b/src/utils/serialize.js index 4c273b90..2fcff093 100644 --- a/src/utils/serialize.js +++ b/src/utils/serialize.js @@ -1,5 +1,11 @@ /** - * @param {import('../models').Playlist | import('../models/Playlist').LeanPlaylist} model + * @typedef {import('../models/index.js').User} User + * @typedef {import('../models/index.js').Playlist} Playlist + * @typedef {import('../models/Playlist.js').LeanPlaylist} LeanPlaylist + */ + +/** + * @param {Playlist | LeanPlaylist} model */ export function serializePlaylist(model) { return { @@ -13,8 +19,7 @@ export function serializePlaylist(model) { } /** - * @param {Pick} model */ export function serializeUser(model) { diff --git a/src/utils/skipIfCurrentDJ.js b/src/utils/skipIfCurrentDJ.js index 974f4cd8..797fba45 100644 --- a/src/utils/skipIfCurrentDJ.js +++ b/src/utils/skipIfCurrentDJ.js @@ -1,12 +1,12 @@ /** - * @param {import('../Uwave').default} uw + * @param {import('../Uwave.js').default} uw */ function getCurrentDJ(uw) { return uw.redis.get('booth:currentDJ'); } /** - * @param {import('../Uwave').default} uw + * @param {import('../Uwave.js').default} uw * @param {import('mongodb').ObjectId} userID */ async function skipIfCurrentDJ(uw, userID) { diff --git a/src/utils/toPaginatedResponse.js b/src/utils/toPaginatedResponse.js index 6ab5d863..8bc35f5c 100644 --- a/src/utils/toPaginatedResponse.js +++ b/src/utils/toPaginatedResponse.js @@ -18,8 +18,8 @@ function appendQuery(base, query) { /** * @template {any} TItem * @template {{ offset: number }} TPagination - * @param {import('../Page').default} page - * @param {{ baseUrl?: string, included?: import('./toListResponse').IncludedOptions }} options + * @param {import('../Page.js').default} page + * @param {{ baseUrl?: string, included?: import('./toListResponse.js').IncludedOptions }} options */ function toPaginatedResponse( page, diff --git a/src/utils/wrapMiddleware.js b/src/utils/wrapMiddleware.js index add0e5ae..5903d85f 100644 --- a/src/utils/wrapMiddleware.js +++ b/src/utils/wrapMiddleware.js @@ -2,14 +2,14 @@ * Wrap `async` middleware into an express style callback. * * @param {( - * req: import('../types').Request, + * req: import('../types.js').Request, * res: import('express').Response * ) => Promise} middleware * @returns {import('express').RequestHandler} */ function wrapMiddleware(middleware) { return (rawReq, res, next) => { - /** @type {import('../types').Request} */ + /** @type {import('../types.js').Request} */ const req = /** @type {any} */ (rawReq); middleware(req, res) diff --git a/tsconfig.json b/tsconfig.json index cae9c06f..9c1614cd 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,6 +3,7 @@ "compilerOptions": { "strict": true, "module": "es2022", + "moduleResolution": "node", "useUnknownInCatchVariables": false, "allowJs": true, "checkJs": true,