Files
iptvnator/package.json
T
4grayandClaude Opus 5 61ac15372c perf(website): serve fonts and the avatar locally, load comments on demand
Every page pulled its three typefaces from fonts.googleapis.com and
fonts.gstatic.com, each blog post fetched the author avatar from
githubusercontent.com, and the giscus client script ran on page load. That is
four outside origins contacted before a reader does anything, each costing a
DNS lookup and a TLS handshake on the critical path.

Fonts now come from the @fontsource packages the app already uses and are
emitted as .woff2 beside the site; the avatar is a 3 KB file in public/; and
the giscus embed is created by a "Show comments" button that carries the
configuration as data attributes, so the script is only built when a reader
asks for it.

A delivered page now makes no third-party request at all, verified across the
whole build. The variable Bricolage package names itself "Bricolage Grotesque
Variable", so that exact name leads the display stack in the Tailwind config.
The giscus test now checks the button configuration and asserts the client
script is absent from the delivered HTML.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 17:19:04 +02:00

291 lines
13 KiB
JSON

{
"name": "iptvnator",
"version": "0.23.0",
"engines": {
"node": "^22.13.0 || >=24.0.0"
},
"license": "MIT",
"description": "IPTV player application.",
"homepage": "https://github.com/4gray/iptvnator",
"author": {
"name": "4gray",
"email": "fourgray@proton.me"
},
"keywords": [
"angular",
"electron",
"typescript",
"m3u",
"m3u8",
"player",
"iptv",
"video",
"tv"
],
"scripts": {
"postinstall": "electron-builder install-app-deps",
"build:frontend": "nx build web",
"build:frontend:pwa": "nx build web --configuration=pwa",
"build:backend": "nx build electron-backend --configuration=production",
"serve:frontend": "nx serve web --no-tui",
"serve:frontend:pwa": "nx serve web --configuration=pwa --no-tui",
"serve:backend": "nx serve electron-backend",
"serve:marketing-demo": "nx run-many --target=serve --projects=xtream-mock-server,electron-backend --parallel=2",
"serve:marketing-demo:web": "nx run-many --target=serve --projects=xtream-mock-server,web --parallel=2",
"test:frontend": "nx test web",
"test:backend": "nx test electron-backend",
"test:unit:all": "nx run-many --target=test --all --parallel=3",
"test:unit:ci": "nx run-many --target=test --all --parallel=3 --output-style=static",
"deps:nx:test": "node --test tools/dependencies/check-nx-version-sync.test.mjs",
"deps:nx:check": "node tools/dependencies/check-nx-version-sync.mjs",
"deps:nx:validate": "pnpm run deps:nx:test && pnpm run deps:nx:check",
"deps:vite:test": "node --test tools/dependencies/vite-transform-filter.test.mjs",
"deps:electron-builder:test": "node --test tools/dependencies/app-builder-lib-keychain-password.test.mjs",
"styles:inputs:test": "node --test tools/nx/check-stylesheet-inputs.test.mjs",
"styles:inputs:check": "node tools/nx/check-stylesheet-inputs.mjs",
"styles:inputs:validate": "pnpm run styles:inputs:test && pnpm run styles:inputs:check",
"coverage:tools:test": "node --test tools/coverage/coverage-integrity.test.mjs",
"coverage:unit:ci": "node tools/coverage/run-tier-a-coverage.mjs",
"coverage:merge": "node tools/coverage/merge-coverage.mjs",
"coverage:health": "node tools/coverage/coverage-health.mjs",
"coverage:policy:check": "node tools/coverage/check-coverage-policy.mjs",
"coverage:ci": "pnpm run coverage:tools:test && pnpm run coverage:policy:check && pnpm run coverage:unit:ci && pnpm run coverage:merge && node tools/coverage/coverage-health.mjs --require-report",
"coverage:e2e:summary": "node tools/coverage/e2e-semantic-summary.mjs",
"coverage:e2e:v8:web": "node tools/coverage/e2e-v8-web.mjs",
"typecheck:web": "tsc -p apps/web/tsconfig.app.json --noEmit",
"typecheck:backend": "tsc -p apps/electron-backend/tsconfig.app.json --noEmit",
"typecheck:ci": "pnpm run typecheck:web && pnpm run typecheck:backend",
"verify:package-layout": "node tools/packaging/verify-electron-package-layout.mjs",
"embedded-mpv:build-native:homebrew": "IPTVNATOR_EMBEDDED_MPV_ALLOW_HOMEBREW=1 nx run electron-backend:build-embedded-mpv",
"embedded-mpv:build-runtime": "node tools/embedded-mpv/build-macos-runtime.mjs",
"embedded-mpv:build-runtime:linux": "node tools/embedded-mpv/build-linux-runtime.mjs",
"embedded-mpv:stage-runtime": "node tools/embedded-mpv/stage-runtime.mjs",
"embedded-mpv:stage-runtime:macos": "node tools/embedded-mpv/stage-macos-runtime.mjs",
"embedded-mpv:stage-runtime:windows-archive": "node tools/embedded-mpv/stage-windows-runtime-archive.mjs",
"embedded-mpv:windows-runtime-pin:check": "node tools/embedded-mpv/windows-runtime-pin.mjs",
"embedded-mpv:windows-runtime-pin:refresh": "node tools/embedded-mpv/update-windows-runtime-pin.mjs",
"serve:backend:embedded-mpv": "pnpm embedded-mpv:build-native:homebrew && IPTVNATOR_EMBEDDED_MPV_ALLOW_HOMEBREW=1 IPTVNATOR_ENABLE_EMBEDDED_MPV_EXPERIMENT=1 pnpm serve:backend",
"package:app": "nx run electron-backend:make --prepackageOnly",
"make:app": "nx run electron-backend:make",
"smoke:packaged": "node tools/testing/launch-packaged-electron.mjs",
"serve:website": "nx serve website",
"build:website": "nx build website",
"i18n:check": "node tools/i18n/check-drift.mjs",
"skills:validate": "node tools/skills/validate-repository-skills.mjs",
"release:artwork:dry-run": "tsx --tsconfig tsconfig.base.json tools/release/generate-marketing-artwork.ts --dry-run",
"release:artwork:manifest": "tsx --tsconfig tsconfig.base.json tools/release/generate-marketing-artwork.ts --manifest",
"release:artwork:generate": "tsx --tsconfig tsconfig.base.json tools/release/generate-marketing-artwork.ts --generate",
"release:artwork:validate": "tsx --tsconfig tsconfig.base.json tools/release/generate-marketing-artwork.ts --validate",
"release:notes:validate": "node tools/release/build-release-notes.mjs --validate",
"release:notes:github": "node tools/release/build-release-notes.mjs --format github",
"release:notes:changelog": "node tools/release/build-release-notes.mjs --format changelog",
"release:notes:blog": "node tools/release/build-release-notes.mjs --format blog",
"release:notes:telegram": "node tools/release/build-release-notes.mjs --format telegram",
"release:notes:reddit": "node tools/release/build-release-notes.mjs --format reddit",
"release:verify:draft": "node tools/release/verify-draft-release.mjs",
"release:cards:dry-run": "node tools/release/generate-highlight-cards.mjs --dry-run",
"release:cards:generate": "node tools/release/generate-highlight-cards.mjs --generate",
"release:screenshots": "tsx tools/release/capture-release-screenshots.ts",
"lint": "nx run-many --target=lint --all",
"build": "nx build electron-backend"
},
"private": true,
"packageManager": "pnpm@10.33.0+sha512.10568bb4a6afb58c9eb3630da90cc9516417abebd3fabbe6739f0ae795728da1491e9db5a544c76ad8eb7570f5c4bb3d6c637b2cb41bfdcdb47fa823c8649319",
"dependencies": {
"@angular/animations": "21.2.19",
"@angular/cdk": "21.2.14",
"@angular/common": "21.2.19",
"@angular/compiler": "21.2.19",
"@angular/core": "21.2.19",
"@angular/forms": "21.2.19",
"@angular/material": "21.2.14",
"@angular/platform-browser": "21.2.19",
"@angular/platform-browser-dynamic": "21.2.19",
"@angular/router": "21.2.19",
"@ngrx/effects": "21.1.1",
"@ngrx/entity": "21.1.1",
"@ngrx/router-store": "21.1.1",
"@ngrx/signals": "21.1.1",
"@ngrx/store": "21.1.1",
"@ngrx/store-devtools": "21.1.1",
"@ngx-pwa/local-storage": "21.0.0",
"@yangkghjh/videojs-aspect-ratio-panel": "0.0.1",
"angularx-qrcode": "21.0.5",
"artplayer": "5.4.0",
"axios": "1.20.0",
"better-sqlite3": "13.0.3",
"date-fns": "4.4.0",
"drizzle-orm": "0.45.2",
"electron-conf": "1.3.0",
"electron-updater": "6.8.9",
"epg-parser": "^0.5.0",
"fix-path": "5.0.0",
"hls.js": "1.7.1",
"iptv-playlist-parser": "github:4gray/iptv-playlist-parser#v0.15.2-iptvnator.2",
"marked": "18.0.11",
"mpegts.js": "1.8.1",
"ms": "2.1.3",
"ngx-indexed-db": "22.0.0",
"ngx-skeleton-loader": "11.3.0",
"rxjs": "7.8.2",
"saxes": "6.0.0",
"shaka-player": "5.2.4",
"video.js": "8.24.0",
"videojs-contrib-quality-levels": "4.1.0",
"videojs-quality-selector-hls": "1.1.1",
"zone.js": "~0.16.2"
},
"devDependencies": {
"@angular-devkit/core": "21.2.19",
"@angular-devkit/schematics": "21.2.21",
"@angular-eslint/builder": "21.3.1",
"@angular-eslint/eslint-plugin": "21.3.1",
"@angular-eslint/eslint-plugin-template": "21.3.1",
"@angular-eslint/schematics": "21.3.1",
"@angular-eslint/template-parser": "21.3.1",
"@angular/build": "21.2.19",
"@angular/cli": "21.2.21",
"@angular/common": "21.2.19",
"@angular/compiler": "21.2.19",
"@angular/compiler-cli": "21.2.19",
"@angular/core": "21.2.19",
"@angular/forms": "21.2.19",
"@angular/language-service": "21.2.19",
"@angular/platform-browser": "21.2.19",
"@angular/platform-browser-dynamic": "21.2.19",
"@angular/router": "21.2.19",
"@angular/service-worker": "21.2.19",
"@astrojs/mdx": "7.0.7",
"@astrojs/sitemap": "3.7.4",
"@electron/asar": "3.4.1",
"@eslint/eslintrc": "3.3.7",
"@eslint/js": "^9.38.0",
"@faker-js/faker": "10.6.0",
"@fontsource-variable/bricolage-grotesque": "5.3.0",
"@fontsource/crimson-pro": "5.3.0",
"@fontsource/dm-sans": "5.3.0",
"@fontsource/ibm-plex-mono": "5.3.0",
"@fontsource/jetbrains-mono": "5.3.0",
"@fontsource/roboto": "5.3.0",
"@ngrx/eslint-plugin": "^21.1.1",
"@ngx-translate/core": "16.0.4",
"@ngx-translate/http-loader": "16.0.1",
"@nx/angular": "22.7.8",
"@nx/devkit": "22.7.8",
"@nx/esbuild": "22.7.8",
"@nx/eslint": "22.7.8",
"@nx/eslint-plugin": "22.7.8",
"@nx/jest": "22.7.8",
"@nx/js": "22.7.8",
"@nx/playwright": "22.7.8",
"@nx/web": "22.7.8",
"@nx/workspace": "22.7.8",
"@playwright/test": "^1.62.1",
"@schematics/angular": "21.2.19",
"@swc-node/register": "1.12.1",
"@swc/core": "1.16.1",
"@swc/helpers": "0.5.23",
"@tailwindcss/typography": "0.5.20",
"@types/better-sqlite3": "^7.6.12",
"@types/cors": "2.8.19",
"@types/express": "5.0.6",
"@types/jest": "^30.0.0",
"@types/mocha": "9.0.0",
"@types/node": "20.19.9",
"@types/video.js": "7.3.58",
"@typescript-eslint/eslint-plugin": "^8.69.0",
"@typescript-eslint/parser": "^8.69.0",
"@typescript-eslint/utils": "^8.69.0",
"angular-eslint": "21.4.0",
"astro": "7.2.4",
"autoprefixer": "10.5.4",
"cookie": "2.0.1",
"cors": "2.8.6",
"drizzle-kit": "0.31.10",
"electron": "^43.3.0",
"electron-builder": "^26.15.7",
"electron-playwright-helpers": "1.8.2",
"esbuild": "0.28.2",
"eslint": "^9.8.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-import": "2.32.0",
"eslint-plugin-playwright": "^1.6.2",
"express": "5.2.1",
"globals": "15.9.0",
"html-escaper": "3.0.3",
"istanbul-lib-coverage": "3.2.2",
"istanbul-lib-report": "3.0.1",
"istanbul-reports": "3.2.0",
"jest": "^30.5.1",
"jest-environment-jsdom": "^30.5.1",
"jest-environment-node": "^30.5.1",
"jest-preset-angular": "~15.0.0",
"jest-util": "^30.5.1",
"jsonc-eslint-parser": "^2.1.0",
"material-design-icons-iconfont": "6.7.0",
"mrmime": "2.0.1",
"ng-mocks": "14.17.3",
"nx": "22.7.8",
"nx-electron": "22.0.0",
"prettier": "^3.9.6",
"sharp": "0.35.4",
"tailwindcss": "^3.4.19",
"ts-jest": "^29.4.12",
"ts-node": "10.9.2",
"tslib": "^2.8.1",
"tsx": "4.23.13",
"typescript": "5.9.3",
"typescript-eslint": "^8.69.0",
"yaml": "2.9.0",
"zod": "4.5.4"
},
"pnpm": {
"overrides": {
"@esbuild-kit/core-utils>esbuild": "0.25.12",
"@hono/node-server@1.19.9": "1.19.17",
"@humanfs/node@0.16.7": "0.16.8",
"@xmldom/xmldom@0.8.11": "0.8.15",
"ajv@6.12.6": "6.14.0",
"ajv@8.17.1": "8.18.0",
"brace-expansion@1.1.12": "1.1.18",
"browserslist@4.28.1": "4.28.8",
"defu@6.1.4": "6.1.6",
"devalue@5.6.2": "5.6.4",
"express-rate-limit@8.2.1": "8.3.0",
"fast-uri@3.1.0": "3.1.6",
"flatted@3.3.3": "3.4.2",
"follow-redirects@1.15.11": "1.16.0",
"form-data@4.0.5": "4.0.6",
"h3@1.15.5": "1.15.10",
"hono@4.12.0": "4.12.34",
"immutable@5.1.4": "5.1.9",
"ip-address@10.1.0": "10.5.0",
"js-yaml@4.1.1": "4.3.1",
"js-yaml@4.3.0": "4.3.1",
"jsdom>ws": "8.21.3",
"lodash-es@4.17.22": "4.18.1",
"minimatch@3.1.2": "3.1.5",
"node-forge@1.3.3": "1.4.0",
"path-to-regexp@0.1.12": "0.1.13",
"picomatch@2.3.1": "2.3.2",
"picomatch@4.0.3": "4.0.5",
"postcss-selector-parser@6.1.2": "6.1.4",
"postcss@8.5.6": "8.5.26",
"qs@6.14.1": "6.15.3",
"rollup@4.52.3": "4.59.0",
"serialize-javascript@6.0.2": "7.1.0",
"smol-toml@1.6.0": "1.6.1",
"svgo@3.3.2": "3.3.3",
"svgo@4.0.0": "4.0.2",
"undici@7.28.0": "7.29.0",
"uuid@8.3.2": "11.1.1",
"yaml@1.10.2": "1.10.3"
},
"patchedDependencies": {
"nx-electron@22.0.0": "patches/nx-electron@22.0.0.patch",
"vite@7.3.6": "patches/vite@7.3.6.patch",
"app-builder-lib@26.15.7": "patches/app-builder-lib@26.15.7.patch"
}
}
}