Expose every protection module as a use* function that starts its protection on call and returns a () => void cleanup function. No framework dependency. No React, Vue, or Svelte adapters.
// Drop-in (existing apps, zero restructure)
WebShield.init({ domains: [...], protections: { devtools: true } })
// Composable (any framework or vanilla)
const stop = useDomainLock({ domains: ['techiediaries.com'] })
const stop2 = useDevtools()
// Compose into a single teardown
function useShield(config) {
const stops = [useDomainLock(config), useDevtools(config), useAntiDebug(config)]
return () => stops.forEach(s => s())
}
Why use* naming?
Convention signals “stateful, has lifecycle, returns cleanup” — same pattern as vanilla JS utilities like useLocalStorage. Readers understand it without documentation.
Why vanilla JS only, not React hooks?
Ahmed explicitly ruled out React. The use* pattern is a naming convention for organization, not a framework primitive. Works identically in React, Vue, Svelte, or plain script tags — no adapter needed. Adding framework-specific exports would add complexity with no architectural benefit since each use* is just a function.
Why return a cleanup function instead of an object?
Simplest possible interface. One call to start, one call to stop. No .start()/.stop() method pairs, no event emitters. Composing multiple stops is one forEach.
Why dual API (init + use*)?
WebShield.init() — drop-in for existing apps, zero restructuring required, one config objectuse* — for apps that want selective protection or framework lifecycle integrationBoth read from the same shared config if init() was called. use* functions also accept local config overrides for per-module customisation.
Single monolithic init only: Would prevent per-module teardown and selective activation. Rejected — composability is a core goal.
Framework-specific adapters (React hooks, Vue composables): Unnecessary. The use* functions work as-is in any environment. Adapters would add maintenance surface for no functional gain.
Class-based API (new WebShield(config).start()): More verbose, no benefit over the function approach. Rejected.