Some checks failed
Veza CI / Notify on failure (push) Blocked by required conditions
Veza CI / Rust (Stream Server) (push) Successful in 5m12s
Security Scan / Secret Scanning (gitleaks) (push) Failing after 48s
Veza CI / Backend (Go) (push) Failing after 8m51s
E2E Playwright / e2e (full) (push) Has been cancelled
Veza CI / Frontend (Web) (push) Has been cancelled
Service worker now applies the strategies the roadmap asks for :
* Static assets : StaleWhileRevalidate (already in place)
* HLS segments : CacheFirst, max-age 7d, max 50 entries
* API GET : NetworkFirst, 3s timeout
Stayed on the hand-rolled fetch handlers rather than migrating to
Workbox — the existing implementation already covers push notifications
+ background sync + notificationclick, and Workbox would bring 200+ KB
of runtime + a build-step dependency for a feature set we already have.
Changes
- public/sw.js
* HLS_CACHE_MAX_ENTRIES (50) + HLS_CACHE_MAX_AGE_MS (7d) +
NETWORK_FIRST_TIMEOUT_MS (3s) tunable at the top of the file.
* cacheAudio : reads the cached response's date header to skip
stale entries (>7d), and prunes the cache FIFO after every put
so the entry count never exceeds 50. Network-down path still
serves stale entries (the offline-playback acceptance).
* networkFirst : races the network against a 3s timer ; if the
timer fires AND a cached entry exists, serve cached + let the
network keep updating in the background. Timeout without a
cached fallback lets the network race continue.
* isAudioRequest now matches .ts and .m4s segments too (HLS).
- scripts/stamp-sw-version.mjs (new) : postbuild step that replaces
the literal __BUILD_VERSION__ placeholder in dist/sw.js with
YYYYMMDDHHMM-<short-sha>. Pre-Day 16 the placeholder shipped
literally — same string across every deploy meant browser caches
were never invalidated. Wired into npm run build + build:ci.
- tests/e2e/31-sw-offline-cache.spec.ts : 2 tests gated behind
E2E_SW_TESTS=1 (SW only registers in prod builds — dev server
skips registration via import.meta.env.DEV check). When enabled :
(1) registration + activation, (2) cached resource served while
context.setOffline(true).
Acceptance (Day 16) : strategies match spec ; offline playback works
once the user has played the segment once before going offline. The
e2e self-skips on dev unless E2E_SW_TESTS=1 is set against vite preview.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
175 lines
7.1 KiB
JSON
175 lines
7.1 KiB
JSON
{
|
|
"name": "veza-frontend",
|
|
"private": true,
|
|
"version": "1.0.0",
|
|
"type": "module",
|
|
"scripts": {
|
|
"dev": "vite",
|
|
"dev:with-api": "bash scripts/start-backend-and-dev.sh",
|
|
"dev:lab": "bash ./scripts/start_lab.sh",
|
|
"dev:mocks": "VITE_USE_MSW=1 vite",
|
|
"build": "vite build && node scripts/stamp-sw-version.mjs",
|
|
"build:ci": "vite build && node scripts/stamp-sw-version.mjs && node scripts/check-bundle-size.mjs",
|
|
"preview": "vite preview",
|
|
"test": "vitest",
|
|
"test:ui": "vitest --ui",
|
|
"test:auth": "vitest run src/features/auth",
|
|
"test:tracks": "vitest run src/features/tracks",
|
|
"test:playlists": "vitest run src/features/playlists",
|
|
"test:player": "vitest run src/features/player",
|
|
"test:streaming": "vitest run src/features/streaming",
|
|
"test:settings-profile-chat": "vitest run src/features/settings src/features/profile src/features/chat",
|
|
"test:components-ui": "vitest run src/components/ui",
|
|
"test:components-other": "vitest run src/components/auth src/components/charts src/components/data src/components/feedback src/components/filters src/components/forms src/components/layout src/components/navigation src/components/search",
|
|
"test:services": "vitest run src/services",
|
|
"test:hooks": "vitest run src/hooks",
|
|
"test:misc": "vitest run src/config src/context src/lib src/router src/schemas src/stores src/utils src/__tests__",
|
|
"test:groups": "npm run test:auth && npm run test:tracks && npm run test:playlists && npm run test:player && npm run test:streaming && npm run test:settings-profile-chat && npm run test:components-ui && npm run test:components-other && npm run test:services && npm run test:hooks && npm run test:misc",
|
|
"test:e2e": "echo 'E2E tests moved to repo root: npm run e2e'",
|
|
"lint": "eslint . --ext ts,tsx",
|
|
"lint:fix": "eslint . --ext ts,tsx --fix",
|
|
"lint:ui": "eslint src/components src/features --ext ts,tsx",
|
|
"report:arbitrary": "node scripts/report-arbitrary-values.mjs",
|
|
"typecheck": "tsc --noEmit",
|
|
"generate:types": "bash ./scripts/generate-types.sh",
|
|
"check:types-sync": "bash ./scripts/check-types-sync.sh",
|
|
"validate:schemas": "vitest run src/schemas",
|
|
"validate:types": "npm run typecheck",
|
|
"validate:all": "npm run validate:types && npm run validate:schemas",
|
|
"fmt": "prettier --write \"src/**/*.{ts,tsx,js,jsx,json,css,md}\"",
|
|
"format": "prettier --write \"src/**/*.{ts,tsx,js,jsx,json,css,md}\"",
|
|
"format:check": "prettier --check \"src/**/*.{ts,tsx,js,jsx,json,css,md}\"",
|
|
"qa:smoke": "make smoke",
|
|
"qa:e2e": "make e2e",
|
|
"qa:postman": "echo 'Postman/Newman removed (security audit A06). Use Makefile.old if needed.'",
|
|
"qa:lh": "echo 'Lighthouse/LHCI removed (security audit A06). Use Makefile.old if needed.'",
|
|
"qa:k6": "make load",
|
|
"qa:visual": "make visual",
|
|
"qa:visual:update": "make visual-update",
|
|
"qa:backstop:ref": "make backstop-ref",
|
|
"qa:backstop:test": "make backstop-test",
|
|
"qa:loki": "make loki",
|
|
"qa:a11y": "echo 'pa11y-ci removed (security audit A06). Use Makefile.old if needed.'",
|
|
"a11y:audit": "npx --yes @axe-core/cli ${A11Y_URL:-http://localhost:5173} --tags wcag2aa --load-delay=2000",
|
|
"qa:all": "make qa-all",
|
|
"prepare": "husky",
|
|
"storybook": "cross-env VITE_API_URL=/api/v1 VITE_USE_MSW=true VITE_STORYBOOK=true storybook dev -p 6006",
|
|
"build-storybook": "cross-env VITE_API_URL=/api/v1 VITE_USE_MSW=true VITE_STORYBOOK=true storybook build",
|
|
"test:storybook": "node scripts/audit-storybook.js",
|
|
"test:storybook:playwright": "echo 'Storybook tests moved to repo root: npm run e2e -- --grep storybook'",
|
|
"validate:storybook": "node scripts/validate-storybook.cjs",
|
|
"chromatic": "chromatic --project-token=${CHROMATIC_PROJECT_TOKEN}",
|
|
"test:storybook:vitest": "vitest --config vitest.storybook.config.ts"
|
|
},
|
|
"dependencies": {
|
|
"@dnd-kit/core": "^6.3.1",
|
|
"@dnd-kit/sortable": "^10.0.0",
|
|
"@dnd-kit/utilities": "^3.2.2",
|
|
"@hookform/resolvers": "^3.3.4",
|
|
"@juspay-tech/hyper-js": "^2.1.0",
|
|
"@juspay-tech/react-hyper-js": "^1.3.0",
|
|
"@radix-ui/react-dialog": "^1.1.15",
|
|
"@radix-ui/react-slot": "^1.2.4",
|
|
"@sentry/react": "^10.32.1",
|
|
"@storybook/addon-mcp": "^0.4.2",
|
|
"@tanstack/react-query": "^5.17.0",
|
|
"@tanstack/react-virtual": "^3.13.12",
|
|
"axios": "^1.13.5",
|
|
"class-variance-authority": "^0.7.0",
|
|
"clsx": "^2.1.0",
|
|
"date-fns": "^4.1.0",
|
|
"dompurify": "^3.3.0",
|
|
"emoji-picker-react": "^4.16.1",
|
|
"framer-motion": "^12.29.2",
|
|
"hls.js": "^1.6.14",
|
|
"i18next": "^25.5.2",
|
|
"i18next-browser-languagedetector": "^8.2.0",
|
|
"immer": "^10.0.3",
|
|
"lucide-react": "^0.321.0",
|
|
"react": "^18.2.0",
|
|
"react-dom": "^18.2.0",
|
|
"react-dropzone": "^14.3.8",
|
|
"react-hook-form": "^7.49.3",
|
|
"react-hot-toast": "^2.6.0",
|
|
"react-i18next": "^15.7.3",
|
|
"react-router-dom": "^6.30.3",
|
|
"recharts": "^3.7.0",
|
|
"tailwind-merge": "^2.2.1",
|
|
"zod": "^3.25.76",
|
|
"zustand": "^4.5.0"
|
|
},
|
|
"devDependencies": {
|
|
"@storybook/addon-a11y": "^10.3.3",
|
|
"@storybook/addon-docs": "^10.3.3",
|
|
"@storybook/addon-vitest": "^10.3.3",
|
|
"@storybook/blocks": "^8.6.14",
|
|
"@storybook/builder-vite": "^10.3.3",
|
|
"@storybook/react-vite": "^10.3.3",
|
|
"@tailwindcss/postcss": "^4.0.0",
|
|
"@testing-library/jest-dom": "^6.4.2",
|
|
"@testing-library/react": "^14.2.1",
|
|
"@testing-library/user-event": "^14.5.2",
|
|
"@types/dompurify": "^3.0.5",
|
|
"@types/node": "^20.11.5",
|
|
"@types/react": "^18.2.48",
|
|
"@types/react-dom": "^18.2.18",
|
|
"@types/react-dropzone": "^4.2.2",
|
|
"@types/swagger-ui-react": "^5.18.0",
|
|
"@types/uuid": "^10.0.0",
|
|
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
"@typescript-eslint/parser": "^8.0.0",
|
|
"@vitejs/plugin-react": "^4.2.1",
|
|
"@vitest/browser": "^3.2.4",
|
|
"@vitest/coverage-v8": "^3.2.4",
|
|
"autoprefixer": "^10.4.17",
|
|
"babel-plugin-react-remove-properties": "^0.3.1",
|
|
"backstopjs": "^6.2.3",
|
|
"bundlesize": "^0.18.2",
|
|
"cross-env": "^7.0.3",
|
|
"eslint": "^9.0.0",
|
|
"eslint-plugin-jsx-a11y": "^6.10.2",
|
|
"eslint-plugin-react": "^7.37.0",
|
|
"eslint-plugin-react-hooks": "^5.0.0",
|
|
"eslint-plugin-react-refresh": "^0.4.5",
|
|
"eslint-plugin-storybook": "10.3.3",
|
|
"fast-check": "^4.7.0",
|
|
"husky": "^9.1.7",
|
|
"jsdom": "^24.0.0",
|
|
"msw": "^2.11.2",
|
|
"msw-storybook-addon": "^2.0.6",
|
|
"orval": "^8.8.1",
|
|
"pixelmatch": "^5.3.0",
|
|
"pngjs": "^7.0.0",
|
|
"prettier": "^3.2.5",
|
|
"rollup-plugin-visualizer": "^6.0.5",
|
|
"storybook": "^10.3.3",
|
|
"storybook-dark-mode": "^4.0.2",
|
|
"swagger-ui-dist": "^5.31.0",
|
|
"swagger-ui-react": "^5.31.0",
|
|
"tailwindcss": "^4.0.0",
|
|
"tw-animate-css": "^1.4.0",
|
|
"typescript": "5.9.3",
|
|
"vite": "^7.1.5",
|
|
"vitest": "^3.2.4"
|
|
},
|
|
"keywords": [
|
|
"react",
|
|
"typescript",
|
|
"vite",
|
|
"tailwindcss",
|
|
"sumi-design-system",
|
|
"zustand",
|
|
"websocket",
|
|
"music",
|
|
"streaming",
|
|
"collaboration"
|
|
],
|
|
"author": "Veza Team",
|
|
"license": "MIT",
|
|
"description": "Application web moderne pour la plateforme Veza de streaming et collaboration musicale",
|
|
"msw": {
|
|
"workerDirectory": [
|
|
"public"
|
|
]
|
|
}
|
|
}
|