CI / build-and-test (push) Successful in 14m57s
P0 - Aucun secret servi au navigateur : /assets/config.local.js est généré par le serveur AVANT les montages statiques (il l'emporte sur le fichier local) et ne contient plus YOUTUBE_API_KEY(S) ; le fichier local n'est plus copié dans l'image Docker ni embarqué dans dist (angular ignore config.local.js) ; youtube-api.service n'appelle plus googleapis directement (fetchYouTube = /api/yt -> /proxy/api/yt), gardes « pas de clé => écran vide », rotation et carte de bans côté client supprimées ; readiness YouTube via /healthz (youtube.keys.count) ; messages d'erreur orientés configuration serveur. - CORS : origines pilotées par API_ALLOWED_ORIGINS (CSV), méthode PATCH ajoutée (requis par /user/preferences), header X-API-Key accepté. - Clés d'API longue durée : table api_keys (empreinte SHA-256 + préfixe affichable), routes GET/POST /api/keys et DELETE /api/keys/:id, jeton ntk_… affiché une seule fois, last_used_at à chaque usage ; X-API-Key accepté par authMiddleware ET authMiddlewareCookieAware. P1 - X-Request-Id renvoyé sur chaque réponse + journal JSON structuré en prod (ts, reqId, method, route, status, ms). - GET /metrics : exposition Prometheus sans dépendance (http_requests_total par route/code, somme+nombre de durées, uptime/mémoire ; METRICS_TOKEN verrouille l'accès si défini). - Rate-limit sur /api/details (DETAILS_RATE_LIMIT, 60/min, réponse JSON) — /transcript avait déjà le sien. - Version unique package.json : menu du compte, info.version de l'OpenAPI (+ schéma apiKeyAuth et chemins /keys / /metrics documentés). Tests : api_coverage +7 cas « production-ready » (sentinel de fuite de clé, X-Request-Id, /metrics, CORS PATCH, contrat/version, cycle complet des clés d'API), suggest, transcript, flags, filters, kind — verts. Build OK. Vérifs instance locale : config servie sans secret, /api/yt 200 avec la clé serveur, /metrics alimenté, menu 1.0.59 et 40 cartes rendues sans clé côté client.
91 lines
5.1 KiB
JSON
91 lines
5.1 KiB
JSON
{
|
|
"name": "newtube",
|
|
"private": true,
|
|
"version": "1.0.59",
|
|
"type": "module",
|
|
"scripts": {
|
|
"dev": "ng serve",
|
|
"build": "ng build",
|
|
"preview": "ng serve --configuration=production",
|
|
"api": "node --env-file=.env.local ./server/index.mjs",
|
|
"api:watch": "node --watch --env-file=.env.local ./server/index.mjs",
|
|
"mcp": "node ./mcp/server.mjs",
|
|
"mcp:dev": "node --env-file=.env.local ./mcp/server.mjs",
|
|
"test:mcp": "node --test ./mcp/server.test.mjs ./mcp/tools.test.mjs",
|
|
"test:api": "node --test ./server/tests/api_coverage.test.mjs ./server/tests/api_coverage2.test.mjs",
|
|
"test:playlists": "node ./server/tests/playlist_visibility.test.mjs",
|
|
"test:preferences": "node ./server/tests/preferences.test.mjs",
|
|
"test:search-e2e": "node ./server/tests/search.e2e.test.mjs",
|
|
"test:telemetry": "node ./server/tests/telemetry.test.mjs",
|
|
"test:downloads": "node ./server/tests/download_jobs.test.mjs",
|
|
"test:subscriptions": "node --loader ts-node/esm --experimental-specifier-resolution=node src/services/subscriptions.service.spec.ts",
|
|
"test:search": "node --loader ts-node/esm --experimental-specifier-resolution=node src/app/search/search.service.spec.ts && node --loader ts-node/esm --experimental-specifier-resolution=node src/app/search/search-components.spec.ts",
|
|
"test:suggest": "node --loader ts-node/esm --experimental-specifier-resolution=node src/app/search/suggest.spec.ts && node ./server/tests/suggest.test.mjs",
|
|
"test:filters": "node ./server/tests/search-filters.test.mjs",
|
|
"test:contract": "node ./server/tests/provider-contract.test.mjs",
|
|
"test:shapes": "node --test ./server/tests/provider_shapes.test.mjs",
|
|
"fixtures:record": "node ./server/tests/record_provider_shapes.mjs",
|
|
"doc:providers": "node ./server/tests/generate-provider-doc.mjs",
|
|
"test:rumble": "node ./server/tests/rumble-ld.test.mjs",
|
|
"test:live": "node ./server/tests/live_providers.test.mjs",
|
|
"test:odysee": "node ./server/tests/odysee-resolve.test.mjs",
|
|
"test:cache": "node ./server/tests/search-cache.test.mjs && node ./server/tests/env_ttl.test.mjs",
|
|
"test:videos": "node ./server/tests/videos_catalog.test.mjs",
|
|
"test:channelref": "node ./server/tests/channel_ref.test.mjs",
|
|
"test:flags": "node --test ./server/tests/contract_version.test.mjs ./server/tests/feature_flags_http.test.mjs",
|
|
"test:twitch": "node --test ./server/tests/twitch_sections.test.mjs",
|
|
"test:tokens": "node --test ./server/tests/page_tokens.test.mjs",
|
|
"test:banners": "node --test ./server/tests/channel_banner.test.mjs",
|
|
"test:provenance": "node --test ./server/tests/provenance.test.mjs ./server/tests/search_debug.test.mjs",
|
|
"test:stream": "node --test ./server/tests/search_stream.test.mjs ./server/tests/search_stream_provider.test.mjs",
|
|
"test:adapter": "node --test ./server/tests/adapter_contract.test.mjs",
|
|
"test:shorts-catalog": "node --loader ts-node/esm --experimental-specifier-resolution=node src/app/search/shorts-catalog.spec.ts",
|
|
"test:provider-health": "node --loader ts-node/esm --experimental-specifier-resolution=node src/app/search/provider-health.service.spec.ts",
|
|
"test:provenance-front": "node --loader ts-node/esm --experimental-specifier-resolution=node src/app/search/adapters/provenance.spec.ts",
|
|
"test:transcript": "node --test server/tests/transcript.test.mjs",
|
|
"test:history": "node server/tests/history_filters.test.mjs",
|
|
"test:highlight": "node --loader ts-node/esm --experimental-specifier-resolution=node src/components/account/history/highlight.util.spec.ts",
|
|
"test:kind": "node --loader ts-node/esm --experimental-specifier-resolution=node src/app/shared/utils/video-kind.spec.ts",
|
|
"test:section": "node --loader ts-node/esm --experimental-specifier-resolution=node src/app/shared/utils/section-policy.spec.ts",
|
|
"test:ytscrape": "node server/tests/youtube-scrape.test.mjs",
|
|
"test:ytinnertube": "node server/tests/youtube-innertube.test.mjs",
|
|
"ytdlp:update": "yt-dlp -U || python3 -m yt_dlp -U || echo \"yt-dlp update: installez yt-dlp puis relancez\""
|
|
},
|
|
"dependencies": {
|
|
"@angular/build": "^20.1.0",
|
|
"@angular/cdk": "^20.2.4",
|
|
"@angular/cli": "^20.1.0",
|
|
"@angular/common": "^20.1.0",
|
|
"@angular/compiler": "^20.1.0",
|
|
"@angular/compiler-cli": "^20.1.0",
|
|
"@angular/core": "^20.1.0",
|
|
"@angular/forms": "^20.1.0",
|
|
"@angular/platform-browser": "^20.1.0",
|
|
"@angular/platform-browser-dynamic": "~20.2.4",
|
|
"@angular/router": "^20.1.6-0",
|
|
"@google/genai": "latest",
|
|
"axios": "^1.12.1",
|
|
"bcryptjs": "^2.4.3",
|
|
"better-sqlite3": "^9.6.0",
|
|
"cheerio": "^1.1.2",
|
|
"cookie-parser": "^1.4.6",
|
|
"cors": "^2.8.5",
|
|
"express": "^4.19.2",
|
|
"express-rate-limit": "^7.1.5",
|
|
"ffmpeg-static": "^5.2.0",
|
|
"helmet": "^7.1.0",
|
|
"jsonwebtoken": "^9.0.2",
|
|
"rxjs": "^7.8.2",
|
|
"tailwindcss": "latest",
|
|
"youtube-dl-exec": "^3.0.0",
|
|
"youtubei.js": "18.1.0",
|
|
"zone.js": "~0.15.1"
|
|
},
|
|
"devDependencies": {
|
|
"@types/node": "^22.14.0",
|
|
"ts-node": "^10.9.2",
|
|
"typescript": "~5.8.2",
|
|
"vite": "^6.2.0"
|
|
}
|
|
}
|