[PULSE-60] Frontend hardening, UX polish, and security #35

Merged
uz1mani merged 41 commits from staging into main 2026-02-22 21:43:06 +00:00
54 changed files with 1436 additions and 229 deletions
Showing only changes of commit 5d234b30d6 - Show all commits

View File

@@ -18,6 +18,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
- **Link previews for public dashboards.** Sharing a public dashboard link on social media now shows a proper preview with the site name and description.
- **Faster login redirects.** If you're not signed in and try to open a dashboard or settings page, you're redirected to login immediately instead of seeing a blank page first. Already-signed-in users who visit the login page are sent straight to the dashboard.
- **Graceful error recovery.** If a page crashes, you now see a friendly error screen with a "Try again" button instead of a blank white page. Each section of the app has its own error message so you know exactly what went wrong.
- **Security headers.** All pages now include clickjacking protection, MIME-sniffing prevention, a strict referrer policy, and HSTS. Browser APIs like camera and microphone are explicitly disabled.
## [0.10.0-alpha] - 2026-02-21

View File

@@ -21,6 +21,27 @@ const nextConfig: NextConfig = {
},
],
},
async headers() {
return [
{
source: '/(.*)',
headers: [
{ key: 'X-Frame-Options', value: 'DENY' },
{ key: 'X-Content-Type-Options', value: 'nosniff' },
{ key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
{
key: 'Permissions-Policy',
value: 'camera=(), microphone=(), geolocation=(), interest-cohort=()',
},
{ key: 'X-XSS-Protection', value: '1; mode=block' },
{
greptile-apps[bot] commented 2026-02-22 21:47:13 +00:00 (Migrated from github.com)
Review

interest-cohort is not a recognized Permissions-Policy directive

interest-cohort was a Chrome-only proposal (FLoC) that was abandoned and replaced by the Topics API. Modern browsers will ignore or warn about this unrecognized directive. It can be safely removed, or you could replace it with browsing-topics=() if you want to opt out of the Topics API:

            value: 'camera=(), microphone=(), geolocation=(), browsing-topics=()',
Prompt To Fix With AI
This is a comment left during a code review.
Path: next.config.ts
Line: 37

Comment:
**`interest-cohort` is not a recognized Permissions-Policy directive**

`interest-cohort` was a Chrome-only proposal (FLoC) that was abandoned and replaced by the Topics API. Modern browsers will ignore or warn about this unrecognized directive. It can be safely removed, or you could replace it with `browsing-topics=()` if you want to opt out of the Topics API:

```suggestion
            value: 'camera=(), microphone=(), geolocation=(), browsing-topics=()',
```

How can I resolve this? If you propose a fix, please make it concise.
**`interest-cohort` is not a recognized Permissions-Policy directive** `interest-cohort` was a Chrome-only proposal (FLoC) that was abandoned and replaced by the Topics API. Modern browsers will ignore or warn about this unrecognized directive. It can be safely removed, or you could replace it with `browsing-topics=()` if you want to opt out of the Topics API: ```suggestion value: 'camera=(), microphone=(), geolocation=(), browsing-topics=()', ``` <details><summary>Prompt To Fix With AI</summary> `````markdown This is a comment left during a code review. Path: next.config.ts Line: 37 Comment: **`interest-cohort` is not a recognized Permissions-Policy directive** `interest-cohort` was a Chrome-only proposal (FLoC) that was abandoned and replaced by the Topics API. Modern browsers will ignore or warn about this unrecognized directive. It can be safely removed, or you could replace it with `browsing-topics=()` if you want to opt out of the Topics API: ```suggestion value: 'camera=(), microphone=(), geolocation=(), browsing-topics=()', ``` How can I resolve this? If you propose a fix, please make it concise. ````` </details>
key: 'Strict-Transport-Security',
value: 'max-age=63072000; includeSubDomains; preload',
},
],
},
]
},
async redirects() {
return [
{