chore: update Angular cache and TypeScript build info files
This commit is contained in:
Binary file not shown.
+42
-9
@@ -2,6 +2,24 @@ import express from 'express';
|
||||
import helmet from 'helmet';
|
||||
import cors from 'cors';
|
||||
import cookieParser from 'cookie-parser';
|
||||
|
||||
// Configuration CORS
|
||||
const corsOptions = {
|
||||
origin: ['http://localhost:4200', 'http://localhost:4000', 'http://localhost:3000'],
|
||||
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
|
||||
allowedHeaders: ['Content-Type', 'Authorization'],
|
||||
credentials: true,
|
||||
maxAge: 86400 // 24h
|
||||
};
|
||||
|
||||
// Middleware de logging
|
||||
const requestLogger = (req, res, next) => {
|
||||
console.log(`[${new Date().toISOString()}] ${req.method} ${req.originalUrl}`);
|
||||
console.log('Headers:', JSON.stringify(req.headers, null, 2));
|
||||
console.log('Query:', JSON.stringify(req.query, null, 2));
|
||||
console.log('Body:', JSON.stringify(req.body, null, 2));
|
||||
next();
|
||||
};
|
||||
import rateLimit from 'express-rate-limit';
|
||||
import bcrypt from 'bcryptjs';
|
||||
import jwt from 'jsonwebtoken';
|
||||
@@ -117,11 +135,16 @@ app.use(helmet({
|
||||
crossOriginResourcePolicy: { policy: 'cross-origin' },
|
||||
}));
|
||||
app.use(express.json());
|
||||
app.use(express.urlencoded({ extended: true }));
|
||||
app.use(cookieParser());
|
||||
app.use(cors({
|
||||
origin: true,
|
||||
credentials: true,
|
||||
}));
|
||||
app.use(cors(corsOptions));
|
||||
app.options('*', cors(corsOptions)); // Pré-vol CORS
|
||||
|
||||
// Logging des requêtes
|
||||
app.use(requestLogger);
|
||||
|
||||
// Routes API
|
||||
app.use('/api', r);
|
||||
|
||||
// Downloads directory
|
||||
const downloadsRoot = path.join(process.cwd(), 'tmp', 'downloads');
|
||||
@@ -1390,10 +1413,20 @@ app.all('/api/twitch-auth/*', (req, res) => forwardJson(req, res, 'https://id.tw
|
||||
// -------------------- Unified search endpoint (GET) --------------------
|
||||
app.get('/api/search', async (req, res) => {
|
||||
try {
|
||||
console.log('[SEARCH] Requête reçue - Query:', req.query);
|
||||
const { q, providers } = req.query;
|
||||
if (!q || typeof q !== 'string' || q.trim().length === 0) {
|
||||
return res.status(400).json({ error: 'missing_query' });
|
||||
|
||||
// Validation des paramètres
|
||||
if (!q || typeof q !== 'string' || q.trim().length < 2) {
|
||||
console.log('[SEARCH] Requête invalide - q manquant ou trop court:', q);
|
||||
return res.status(400).json({ error: 'q is required and must be at least 2 characters long' });
|
||||
}
|
||||
const pageNum = Math.max(1, Number(req.query.page || 1));
|
||||
const pageSize = Math.min(50, Math.max(1, Number(req.query.pageSize || 24)));
|
||||
// Optional sort parameter (normalized to known set)
|
||||
const allowedSort = new Set(['relevance', 'date', 'views']);
|
||||
let sort = (typeof req.query.sort === 'string' ? req.query.sort.trim().toLowerCase() : 'relevance');
|
||||
if (!allowedSort.has(sort)) sort = 'relevance';
|
||||
// Validate and normalize providers list (default to all supported when none/invalid)
|
||||
const requested = typeof providers === 'string' ? String(providers) : '';
|
||||
const validProviders = validateProviders(requested);
|
||||
@@ -1403,8 +1436,8 @@ app.get('/api/search', async (req, res) => {
|
||||
validProviders.map((providerId) => {
|
||||
const mod = providerRegistry[/** @type {any} */(providerId)];
|
||||
if (!mod || typeof mod.search !== 'function') return Promise.resolve([]);
|
||||
// Basic options: limit per provider; could be extended with page, etc.
|
||||
return Promise.resolve().then(() => mod.search(q, { limit: 10 }));
|
||||
// Basic options include pagination and sort hints
|
||||
return Promise.resolve().then(() => mod.search(q, { limit: pageSize, page: pageNum, sort }));
|
||||
})
|
||||
);
|
||||
|
||||
@@ -1420,7 +1453,7 @@ app.get('/api/search', async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
return res.json({ q, providers: validProviders, groups });
|
||||
return res.json({ q, providers: validProviders, groups, page: pageNum, pageSize, sort });
|
||||
} catch (e) {
|
||||
return res.status(500).json({ error: 'search_failed', details: String(e?.message || e) });
|
||||
}
|
||||
|
||||
@@ -10,18 +10,22 @@
|
||||
* @property {string=} type
|
||||
*/
|
||||
|
||||
/** @type {{ id: 'yt', label: string, search: (q: string, opts: { limit: number, page?: number }) => Promise<Suggestion[]> }} */
|
||||
/** @type {{ id: 'yt', label: string, search: (q: string, opts: { limit: number, page?: number, sort?: 'relevance'|'date'|'views' }) => Promise<Suggestion[]> }} */
|
||||
const handler = {
|
||||
id: 'yt',
|
||||
label: 'YouTube',
|
||||
async search(q, opts) {
|
||||
const { limit = 10 } = opts;
|
||||
const { limit = 10, sort = 'relevance' } = opts || {};
|
||||
try {
|
||||
const API_KEY = process.env.YOUTUBE_API_KEY;
|
||||
if (!API_KEY) {
|
||||
throw new Error('YOUTUBE_API_KEY not configured');
|
||||
}
|
||||
|
||||
let order = 'relevance';
|
||||
if (sort === 'date') order = 'date';
|
||||
else if (sort === 'views') order = 'viewCount';
|
||||
|
||||
const response = await fetch(
|
||||
`https://www.googleapis.com/youtube/v3/search?` +
|
||||
new URLSearchParams({
|
||||
@@ -30,7 +34,7 @@ const handler = {
|
||||
type: 'video',
|
||||
maxResults: Math.min(limit, 50).toString(),
|
||||
key: API_KEY,
|
||||
order: 'relevance'
|
||||
order
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user