v1.9.0: Full diagnostic sweep - 42 issues fixed

Critical fixes (7):
- Added global Express error handler (returns JSON instead of HTML)
- Removed caching from random endpoint (defeated purpose)
- Renamed share.jpg to share.png (MIME type mismatch)
- Fixed OG image dimensions (630 → 601)
- Fixed manifest.json icon sizes (192x192 → 512x512)
- Fixed implicit global event variable in console
- Added 9 missing endpoints to docs/endpoints.md

High fixes (12):
- Imported version from package.json (no hardcoded drift)
- Added dynamic endpoint count in stats
- Added input sanitization for mapper API (SSRF prevention)
- Added homepage caching (reduced 5 duplicate HTTP requests)
- Added rate limiting (100 requests/minute per IP)
- Added rel="noopener noreferrer" to all target="_blank" links
- Fixed trailing slash inconsistency in console
- Added noindex meta to 404.html
- Fixed docs/architecture.md controller filenames and dependency versions
- Fixed README.md dependency versions
- Added 12 missing endpoint tests

Medium fixes (22):
- Added escapeHtml helper for error messages
- Consistent favicon across all pages
- Added meta descriptions to privacy.html and tos.html
- Added OG/Twitter meta tags to privacy.html and tos.html
- Added aria-label to playground inputs
- Added aria-hidden to decorative SVGs
- Synced Twitter description with OG description
- Fixed robots.txt to disallow /api
- Added PWA fields to manifest.json
- Removed 5 unused imports
- Removed unused cookie-parser dependency
- Fixed inconsistent error handling in extractors
- Fixed resolvedSlug returning numeric ID
- Added /watch endpoint to streaming docs
- Improved test assertions and status code validation
- Deleted orphaned og-image.svg and logo.png

Low fixes (11):
- Removed redundant try/catch from extractPages
- Added max size eviction to cache
- Added cache key sorting in filter controller
- Added author meta tag
- Fixed favicon.svg font

Version bumped to 1.9.0
This commit is contained in:
Sʜɪɴᴇɪ Nᴏᴜᴢᴇɴ
2026-06-09 06:00:37 +05:30
parent 84c4877669
commit 100b9f9414
30 changed files with 404 additions and 139 deletions
-1
View File
@@ -15,7 +15,6 @@
* ======= • ======= • ======= • ======= • =======• =======
*/
import { headers } from "../configs/header.config.js";
import { URLS } from "../configs/dataUrl.js";
import { countPages } from "../helper/countPages.helper.js";
import { extractPages } from "../helper/extractPages.helper.js";
+3 -3
View File
@@ -56,7 +56,7 @@ const extractEpisodeList = async (slugOrId) => {
}
if (!animeId) {
return { animeId: 0, slug: resolvedSlug, totalEpisodes: 0, episodes: [] };
return { animeId: 0, slug: slugOrId, totalEpisodes: 0, episodes: [] };
}
try {
@@ -104,7 +104,7 @@ const extractEpisodeList = async (slugOrId) => {
return {
animeId,
slug: resolvedSlug,
slug: slugOrId,
totalEpisodes: episodes.length,
episodes
};
@@ -112,7 +112,7 @@ const extractEpisodeList = async (slugOrId) => {
// NOTE: Gracefully return empty list if AJAX call fails (e.g. network issue)
return {
animeId,
slug: resolvedSlug,
slug: slugOrId,
totalEpisodes: 0,
episodes: []
};
-1
View File
@@ -16,7 +16,6 @@
* ======= • ======= • ======= • ======= • =======• =======
*/
import * as cheerio from "cheerio";
import { headers } from "../configs/header.config.js";
import { URLS } from "../configs/dataUrl.js";
import { GENRE_IDS, TYPE_IDS, STATUS_IDS, RATING_IDS, SORT_IDS } from "../configs/ids.config.js";
+3
View File
@@ -19,6 +19,7 @@ import * as cheerio from "cheerio";
import axios from "axios";
import { headers } from "../configs/header.config.js";
import { URLS } from "../configs/dataUrl.js";
import { getCache, setCache } from "../helper/cache.helper.js";
// ══════════════════════════════════════════════════════════════
// HOME INFO EXTRACTOR
@@ -36,6 +37,8 @@ import { URLS } from "../configs/dataUrl.js";
* console.log(home.spotlights.length); // number of spotlight items
*/
const extractHomeInfo = async () => {
const cached = getCache("home");
if (cached) return cached;
try {
const { data } = await axios.get(URLS.home, { headers });
const $ = cheerio.load(data);
-1
View File
@@ -15,7 +15,6 @@
* ======= • ======= • ======= • ======= • =======• =======
*/
import * as cheerio from "cheerio";
import { headers } from "../configs/header.config.js";
import { URLS } from "../configs/dataUrl.js";
import { countPages } from "../helper/countPages.helper.js";
+1 -1
View File
@@ -42,7 +42,7 @@ const extractRandom = async () => {
try {
// NOTE: maxRedirects=5 ensures we follow the random redirect chain
// NOTE: validateStatus allows any 2xx/3xx response without throwing
const { data, request, response } = await axios.get(URLS.random, {
const { data, request } = await axios.get(URLS.random, {
headers,
maxRedirects: 5,
validateStatus: (status) => status < 400
+1 -1
View File
@@ -49,7 +49,7 @@ const extractSeasons = async (animeId) => {
return data || [];
} catch (error) {
// NOTE: Return empty array on error to maintain consistent API
return [];
throw error;
}
};
+5 -1
View File
@@ -139,7 +139,11 @@ const extractServerList = async (episodeIds) => {
*/
const extractMapperServers = async (malId, slug, timestamp) => {
try {
const url = `https://mapper.nekostream.site/api/mal/${malId}/${slug}/${timestamp}`;
// Validate and sanitize input to prevent SSRF
if (!Number.isFinite(Number(malId))) throw new Error("Invalid malId");
if (!/^[a-zA-Z0-9-]+$/.test(slug)) throw new Error("Invalid slug");
if (!Number.isFinite(Number(timestamp))) throw new Error("Invalid timestamp");
const url = `https://mapper.nekostream.site/api/mal/${encodeURIComponent(malId)}/${encodeURIComponent(slug)}/${encodeURIComponent(timestamp)}`;
const { data } = await axios.get(url, { headers });
const servers = [];
+1 -1
View File
@@ -49,7 +49,7 @@ const extractWatchOrder = async (animeId) => {
return data || [];
} catch (error) {
// NOTE: Return empty array on error to maintain consistent API
return [];
throw error;
}
};