Files
pulse/middleware.ts
Usman Baig e444985295 refactor: extract frustration tracking into separate add-on script
Move rage click and dead click detection (35% of script.js) into
script.frustration.js as an optional add-on. Core script drops from
8.1KB to 5.7KB gzipped. Add-on auto-discovers core via window.pulse
polling and supports opt-out via data-no-rage/data-no-dead attributes.

- Expose cleanPath on window.pulse for add-on consumption
- Add script.frustration.js to middleware PUBLIC_ROUTES
- Update integration guides, ScriptSetupBlock, and FrustrationTable
  empty state to reference the add-on script
2026-03-16 16:59:37 +01:00

70 lines
2.0 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
const PUBLIC_ROUTES = new Set([
'/',
'/login',
'/signup',
'/auth/callback',
'/pricing',
'/features',
'/about',
'/faq',
'/changelog',
'/installation',
'/script.js', // * Tracking script must load without auth for embedded sites (Shopify, etc.)
'/script.frustration.js', // * Frustration tracking add-on (rage clicks, dead clicks)
])
const PUBLIC_PREFIXES = [
'/share/',
'/integrations',
'/docs',
]
function isPublicRoute(pathname: string): boolean {
if (PUBLIC_ROUTES.has(pathname)) return true
return PUBLIC_PREFIXES.some((prefix) => pathname.startsWith(prefix))
}
const AUTH_ONLY_ROUTES = new Set(['/login', '/signup'])
export function middleware(request: NextRequest) {
const { pathname } = request.nextUrl
const hasAccess = request.cookies.has('access_token')
const hasRefresh = request.cookies.has('refresh_token')
const hasSession = hasAccess || hasRefresh
// * Authenticated user (with access token) hitting /login or /signup → send them home.
// * Only check access_token; stale refresh_token alone must not block login (fixes post-inactivity sign-in).
if (hasAccess && AUTH_ONLY_ROUTES.has(pathname)) {
return NextResponse.redirect(new URL('/', request.url))
}
// * Public route → allow through
if (isPublicRoute(pathname)) {
return NextResponse.next()
}
// * Protected route without a session → redirect to login
if (!hasSession) {
const loginUrl = new URL('/login', request.url)
return NextResponse.redirect(loginUrl)
}
return NextResponse.next()
}
export const config = {
matcher: [
/*
* Match all routes except:
* - _next/static, _next/image (Next.js internals)
* - favicon.ico, manifest.json, icons, images (static assets)
* - api routes (handled by their own auth)
*/
'/((?!_next/static|_next/image|favicon\\.ico|manifest\\.json|sitemap\\.xml|robots\\.txt|llms\\.txt|.*\\.png$|.*\\.svg$|.*\\.ico$|api/).*)',
],
}