Bump versions to 1.0.18 and remove unused plugins

This commit is contained in:
2026-01-15 15:02:22 +01:00
parent 931fb26796
commit 7cecc0c775
9 changed files with 61 additions and 133 deletions

View File

@@ -1,24 +1,21 @@
{
"name": "edh-stats-backend",
"version": "1.0.0",
"version": "1.0.18",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "edh-stats-backend",
"version": "1.0.0",
"version": "1.0.18",
"license": "MIT",
"dependencies": {
"@fastify/cors": "^8.4.0",
"@fastify/jwt": "^7.2.0",
"@fastify/rate-limit": "^9.0.1",
"@fastify/under-pressure": "^8.3.0",
"bcryptjs": "^2.4.3",
"better-sqlite3": "^9.2.2",
"close-with-grace": "^1.2.0",
"dotenv": "^16.3.1",
"fastify": "^4.24.3",
"fastify-metrics": "^10.0.1",
"pino-pretty": "^13.1.3",
"zod": "^3.22.4"
},
@@ -187,27 +184,6 @@
"fast-deep-equal": "^3.1.3"
}
},
"node_modules/@fastify/rate-limit": {
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/@fastify/rate-limit/-/rate-limit-9.1.0.tgz",
"integrity": "sha512-h5dZWCkuZXN0PxwqaFQLxeln8/LNwQwH9popywmDCFdKfgpi4b/HoMH1lluy6P+30CG9yzzpSpwTCIPNB9T1JA==",
"license": "MIT",
"dependencies": {
"@lukeed/ms": "^2.0.1",
"fastify-plugin": "^4.0.0",
"toad-cache": "^3.3.1"
}
},
"node_modules/@fastify/under-pressure": {
"version": "8.5.2",
"resolved": "https://registry.npmjs.org/@fastify/under-pressure/-/under-pressure-8.5.2.tgz",
"integrity": "sha512-aFLFN2Vt1UPlt4b1m1wEr8eOzwcPUKNhda6g9OFbQ+pHLE6aStm2nGrd7DujqHFJBYEf1j6mPh0ZpsZIqQQz2Q==",
"license": "MIT",
"dependencies": {
"@fastify/error": "^3.0.0",
"fastify-plugin": "^4.0.0"
}
},
"node_modules/@humanwhocodes/config-array": {
"version": "0.13.0",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
@@ -686,12 +662,6 @@
"file-uri-to-path": "1.0.0"
}
},
"node_modules/bintrees": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.2.tgz",
"integrity": "sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw==",
"license": "MIT"
},
"node_modules/bl": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
@@ -1908,19 +1878,6 @@
"toad-cache": "^3.3.0"
}
},
"node_modules/fastify-metrics": {
"version": "10.6.0",
"resolved": "https://registry.npmjs.org/fastify-metrics/-/fastify-metrics-10.6.0.tgz",
"integrity": "sha512-QIPncCnwBOEObMn+VaRhsBC1ox8qEsaiYF2sV/A1UbXj7ic70W8/HNn/hlEC2W8JQbBeZMx++o1um2fPfhsFDQ==",
"license": "MIT",
"dependencies": {
"fastify-plugin": "^4.3.0",
"prom-client": "^14.2.0"
},
"peerDependencies": {
"fastify": ">=4"
}
},
"node_modules/fastify-plugin": {
"version": "4.5.1",
"resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-4.5.1.tgz",
@@ -3559,18 +3516,6 @@
"integrity": "sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==",
"license": "MIT"
},
"node_modules/prom-client": {
"version": "14.2.0",
"resolved": "https://registry.npmjs.org/prom-client/-/prom-client-14.2.0.tgz",
"integrity": "sha512-sF308EhTenb/pDRPakm+WgiN+VdM/T1RaHj1x+MvAuT8UiQP8JmOEbxVqtkbfR4LrvOg5n7ic01kRBDGXjYikA==",
"license": "Apache-2.0",
"dependencies": {
"tdigest": "^0.1.1"
},
"engines": {
"node": ">=10"
}
},
"node_modules/proxy-addr": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
@@ -4356,15 +4301,6 @@
"node": ">=6"
}
},
"node_modules/tdigest": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/tdigest/-/tdigest-0.1.2.tgz",
"integrity": "sha512-+G0LLgjjo9BZX2MfdvPfH+MKLCrxlXSYec5DaPYP1fe6Iyhf0/fSmJ0bFiZ1F8BT6cGXl2LpltQptzjXKWEkKA==",
"license": "MIT",
"dependencies": {
"bintrees": "1.0.2"
}
},
"node_modules/text-table": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",

View File

@@ -1,6 +1,6 @@
{
"name": "edh-stats-backend",
"version": "1.0.0",
"version": "1.0.18",
"description": "Backend API for EDH/Commander stats tracking application",
"main": "src/server.js",
"type": "module",
@@ -17,14 +17,11 @@
"dependencies": {
"@fastify/cors": "^8.4.0",
"@fastify/jwt": "^7.2.0",
"@fastify/rate-limit": "^9.0.1",
"@fastify/under-pressure": "^8.3.0",
"bcryptjs": "^2.4.3",
"better-sqlite3": "^9.2.2",
"close-with-grace": "^1.2.0",
"dotenv": "^16.3.1",
"fastify": "^4.24.3",
"fastify-metrics": "^10.0.1",
"pino-pretty": "^13.1.3",
"zod": "^3.22.4"
},

View File

@@ -1,14 +1,11 @@
// JWT Authentication Middleware
import { jwtConfig } from '../config/jwt.js'
// Verify JWT token
export const verifyJWT = async (request, reply) => {
try {
await request.jwtVerify()
} catch (err) {
reply.code(401).send({
reply.code(401).send({
error: 'Unauthorized',
message: 'Invalid or expired token'
message: 'Invalid or expired token'
})
}
}
@@ -28,71 +25,72 @@ export const validateUser = async (request, reply) => {
try {
const user = request.user
if (!user) {
return reply.code(401).send({
return reply.code(401).send({
error: 'Unauthorized',
message: 'User not authenticated'
message: 'User not authenticated'
})
}
// You could add additional user validation here
// e.g., check if user is active, banned, etc.
} catch (err) {
reply.code(500).send({
reply.code(500).send({
error: 'Internal Server Error',
message: 'Failed to validate user'
message: 'Failed to validate user'
})
}
}
// Extract user ID from token and validate resource ownership
export const validateOwnership = (resourceParam = 'id', resourceTable = 'commanders') => {
export const validateOwnership = (
resourceParam = 'id',
resourceTable = 'commanders'
) => {
return async (request, reply) => {
try {
const user = request.user
if (!user) {
return reply.code(401).send({
return reply.code(401).send({
error: 'Unauthorized',
message: 'User not authenticated'
message: 'User not authenticated'
})
}
const resourceId = request.params[resourceParam]
if (!resourceId) {
return reply.code(400).send({
return reply.code(400).send({
error: 'Bad Request',
message: 'Resource ID not provided'
message: 'Resource ID not provided'
})
}
const db = await import('../config/database.js').then(m => m.default)
const db = await import('../config/database.js').then((m) => m.default)
const database = await db.initialize()
// Check if user owns the resource
const query = `SELECT user_id FROM ${resourceTable} WHERE id = ?`
const resource = database.prepare(query).get([resourceId])
if (!resource) {
return reply.code(404).send({
return reply.code(404).send({
error: 'Not Found',
message: 'Resource not found'
message: 'Resource not found'
})
}
if (resource.user_id !== user.id) {
return reply.code(403).send({
return reply.code(403).send({
error: 'Forbidden',
message: 'Access denied to this resource'
message: 'Access denied to this resource'
})
}
// Add resource to request object for later use
request.resourceId = resourceId
} catch (err) {
reply.code(500).send({
reply.code(500).send({
error: 'Internal Server Error',
message: 'Failed to validate ownership'
message: 'Failed to validate ownership'
})
}
}
@@ -118,4 +116,4 @@ export const rateLimitGeneral = {
skipOnError: false
}
}
}
}

View File

@@ -1,4 +1,3 @@
import { z } from 'zod'
import dbManager from '../config/database.js'
export default async function statsRoutes(fastify, options) {
@@ -80,20 +79,20 @@ export default async function statsRoutes(fastify, options) {
]
},
async (request, reply) => {
try {
const db = await dbManager.initialize()
const userId = request.user.id
try {
const db = await dbManager.initialize()
const userId = request.user.id
// Get detailed commander stats with at least 5 games, sorted by total games then win rate
const rawStats = db
.prepare(
`
// Get detailed commander stats with at least 5 games, sorted by total games then win rate
const rawStats = db
.prepare(
`
SELECT * FROM commander_stats
WHERE user_id = ? AND total_games >= 5
ORDER BY total_games DESC, win_rate DESC
`
)
.all([userId])
)
.all([userId])
// Convert snake_case to camelCase
const stats = rawStats.map((stat) => ({

View File

@@ -1,12 +1,10 @@
import fastify from 'fastify'
import cors from '@fastify/cors'
import jwt from '@fastify/jwt'
import underPressure from '@fastify/under-pressure'
import rateLimit from '@fastify/rate-limit'
import closeWithGrace from 'close-with-grace'
// Import configurations
import { jwtConfig, corsConfig, rateLimitConfig, serverConfig } from './config/jwt.js'
import { jwtConfig, corsConfig, serverConfig } from './config/jwt.js'
import dbManager from './config/database.js'
// Import routes
@@ -20,7 +18,7 @@ export default async function build(opts = {}) {
// Register plugins
await app.register(cors, corsConfig)
await app.register(jwt, {
secret: jwtConfig.secret
})
@@ -30,9 +28,9 @@ export default async function build(opts = {}) {
try {
await request.jwtVerify()
} catch (err) {
reply.code(401).send({
reply.code(401).send({
error: 'Unauthorized',
message: 'Invalid or expired token'
message: 'Invalid or expired token'
})
}
})
@@ -42,7 +40,7 @@ export default async function build(opts = {}) {
try {
await dbManager.initialize()
const dbHealthy = await dbManager.healthCheck()
const status = {
status: 'healthy',
timestamp: new Date().toISOString(),
@@ -50,7 +48,7 @@ export default async function build(opts = {}) {
memory: process.memoryUsage(),
database: dbHealthy ? 'connected' : 'disconnected'
}
if (dbHealthy) {
return status
} else {
@@ -86,7 +84,7 @@ export default async function build(opts = {}) {
// Root endpoint
app.get('/', async (request, reply) => {
return {
return {
message: 'EDH/Commander Stats API',
version: '1.0.0',
status: 'running'
@@ -104,7 +102,7 @@ export default async function build(opts = {}) {
// Error handler
app.setErrorHandler(async (error, request, reply) => {
app.log.error(error)
// Handle validation errors
if (error.validation) {
reply.code(400).send({
@@ -163,7 +161,7 @@ export default async function build(opts = {}) {
} else {
app.log.info({ signal }, 'Received signal')
}
try {
await dbManager.close()
await app.close()
@@ -188,18 +186,18 @@ async function start() {
// }
}
})
// Initialize database
await dbManager.initialize()
const port = serverConfig.port
const host = serverConfig.host
await app.listen({ port, host })
app.log.info(`Server listening on http://${host}:${port}`)
app.log.info(`Health check available at http://${host}:${port}/api/health`)
return app
} catch (error) {
console.error('Failed to start server:', error)

View File

@@ -1 +1 @@
1.0.17
1.0.18

View File

@@ -1,12 +1,12 @@
{
"name": "edh-stats-frontend",
"version": "1.0.0",
"version": "1.0.18",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "edh-stats-frontend",
"version": "1.0.0",
"version": "1.0.18",
"license": "MIT",
"dependencies": {
"alpinejs": "^3.13.3",

View File

@@ -1,6 +1,6 @@
{
"name": "edh-stats-frontend",
"version": "1.0.0",
"version": "1.0.18",
"description": "Frontend for EDH/Commander stats tracking application",
"type": "module",
"scripts": {
@@ -26,4 +26,4 @@
],
"author": "EDH Stats App",
"license": "MIT"
}
}

View File

@@ -1 +1 @@
1.0.17
1.0.18