@sarfarajey/web-utils
v1.0.0
Published
Browser/SSR utility belt for Astro and React projects: theme management, safe redirects, and environment detection
Downloads
655
Maintainers
Readme
@sarfarajey/web-utils
Browser/SSR utility belt for Astro and React projects. Three focused modules, zero runtime dependencies.
Install
npm install @sarfarajey/web-utilsTheme Management
Full light/dark/device theme system with localStorage persistence, OS preference detection, and cross-tab sync.
import {
applyThemeMode,
getPreferredThemeMode,
persistThemeMode,
subscribeToSystemThemeChanges,
subscribeToThemeStorage,
} from '@sarfarajey/web-utils';
// Read and apply the stored (or document-embedded) theme on load
const mode = getPreferredThemeMode(); // 'light' | 'dark' | 'device'
applyThemeMode(mode); // sets data-theme-mode, .dark class, color-scheme
// Persist a user selection
function onThemeChange(selected: 'light' | 'dark' | 'device') {
persistThemeMode(selected);
applyThemeMode(selected);
}
// React to OS preference changes when mode === 'device'
const unsubOS = subscribeToSystemThemeChanges(() => applyThemeMode(getPreferredThemeMode()));
// Sync across tabs
const unsubStorage = subscribeToThemeStorage((mode) => applyThemeMode(mode));DOM side-effects of applyThemeMode(mode):
| Attribute / property | Value |
|----------------------|-------|
| html[data-theme-mode] | 'light' | 'dark' | 'device' |
| html[data-theme-resolved] | 'light' | 'dark' |
| html.classList | 'dark' class added/removed |
| html.style.colorScheme | 'light' | 'dark' |
Safe Redirect Sanitization
Prevent XSS and open-redirect attacks when sending users to a post-login destination.
import { sanitizeRedirectPath, getPostAuthRedirect } from '@sarfarajey/web-utils';
// On a sign-in page: ?redirect=/dashboard/
const destination = getPostAuthRedirect(window.location.search, '/home/');
// Validates the path, blocks external URLs, // prefixes, backslash bypasses, and /auth/* loops.
// Or validate raw values directly:
sanitizeRedirectPath('/dashboard/') // → '/dashboard/'
sanitizeRedirectPath('https://evil.com') // → null
sanitizeRedirectPath('//evil.com') // → null
sanitizeRedirectPath('/auth/reset') // → null (auth prefix blocked)Environment Detection
Distinguish 'development' / 'preview' / 'production' from hostname — works in browser and SSR.
import { configureEnv, getEnvironment, isCurrentEnv } from '@sarfarajey/web-utils';
// Call once at app bootstrap
configureEnv({
productionHosts: ['example.com', 'www.example.com'],
previewHosts: ['preview.example.com'],
});
getEnvironment(); // 'development' | 'preview' | 'production'
// Guard records that belong to a specific environment
isCurrentEnv(record.environment); // true when record.environment matches current envlocalhost and 127.0.0.1 are always 'development'. Cloudflare Pages *.pages.dev aliases are always 'preview'.
License
MIT
