@consentry/next
Version:
Next.js + React integration layer for the Consentry SDK. Manages cookie preferences, script injection, and analytics sync.
1 lines • 9.1 kB
Source Map (JSON)
{"version":3,"sources":["../src/Scripts.tsx","../src/ConsentManagerProvider.tsx","../src/utils/extractScriptTagAttrs.ts"],"sourcesContent":["\"use client\";\n\nimport Script from \"next/script\";\nimport React from \"react\";\nimport { useConsentManager } from \"./ConsentManagerProvider\";\nimport { getAllowedScripts } from \"@consentry/core\";\nimport type { ConsentScript, ConsentConfig } from \"@consentry/core\";\nimport { extractScriptTagAttrs } from \"./utils/extractScriptTagAttrs\";\n\nexport function Scripts({ config }: { config: ConsentConfig }) {\n const { cookiePreferences, isConsentKnown } = useConsentManager();\n const debug = config.debug ?? false;\n\n if (!isConsentKnown) return null; // 👈 Prevent premature script evaluation\n\n const allowedScripts: ConsentScript[] = getAllowedScripts(config, cookiePreferences, debug);\n\n const handleScriptError = (id: string, src?: string) => {\n console.warn(`[consentry] Script \"${id}\" failed to load.`, { src });\n };\n\n return (\n <>\n {allowedScripts.map(script => {\n let parsed = null;\n\n // Try parsing content if it looks like a <script> tag\n if (script.content?.trim().startsWith(\"<script\")) {\n parsed = extractScriptTagAttrs(script.content);\n\n if (parsed) {\n if (debug) {\n console.warn(\n `[consentry] Script \"${script.id}\" used <script> in content. Parsed as src-based script for safety.`\n );\n }\n }\n }\n\n const isInline = !parsed && script.content;\n\n return (\n <React.Fragment key={script.id}>\n <Script\n id={script.id}\n strategy={script.strategy || \"afterInteractive\"}\n src={parsed?.src || script.src}\n dangerouslySetInnerHTML={isInline ? { __html: script.content as string } : undefined}\n onError={() => handleScriptError(script.id, parsed?.src || script.src)}\n {...(parsed?.attrs || script.attributes || {})}\n />\n {script.noscript && <noscript dangerouslySetInnerHTML={{ __html: script.noscript }} />}\n </React.Fragment>\n );\n })}\n </>\n );\n}\n","\"use client\";\n\nimport { type ReactNode, useEffect, useState, createContext, useContext } from \"react\";\n\nimport {\n fallbackDefaults,\n getConsentPreferences,\n setConsentPreferences,\n updateConsentSettings,\n type CookiePreferences,\n type ConsentConfig,\n} from \"@consentry/core\";\n\nimport { Scripts } from \"./Scripts\";\n\ninterface ConsentManagerContextValue {\n cookiePreferences: CookiePreferences;\n setCookiePreferences: (prefs: CookiePreferences) => void;\n showConsentBanner: boolean;\n isConsentKnown: boolean;\n}\n\nconst ConsentManagerContext = createContext<ConsentManagerContextValue | undefined>(undefined);\n\nexport const ConsentManagerProvider = ({\n config,\n children,\n}: {\n config: ConsentConfig;\n children: ReactNode;\n onConsentUpdate?: (prefs: CookiePreferences) => void;\n}) => {\n const [cookiePreferences, setCookiePreferencesState] = useState<CookiePreferences>({\n ...fallbackDefaults,\n ...config.defaults,\n });\n\n const [showConsentBanner, setShowConsentBanner] = useState(false);\n const [isConsentKnown, setIsConsentKnown] = useState(false); // 👈 key for clean loading\n\n // On mount: load saved preferences if they exist\n useEffect(() => {\n const saved = getConsentPreferences();\n\n if (saved) {\n setCookiePreferencesState(saved);\n setShowConsentBanner(false);\n } else {\n setShowConsentBanner(true);\n }\n\n setIsConsentKnown(true); // 👈 mark loading complete\n }, []);\n\n // When user accepts or updates preferences\n const setCookiePreferences = (prefs: CookiePreferences) => {\n setCookiePreferencesState(prefs);\n setConsentPreferences(prefs);\n setShowConsentBanner(false);\n\n // Optional: sync with Google Consent Mode\n const { performance, advertising, social } = prefs;\n updateConsentSettings(\"update\", {\n analytics_storage: performance ? \"granted\" : \"denied\",\n ad_storage: advertising ? \"granted\" : \"denied\",\n ad_user_data: advertising ? \"granted\" : \"denied\",\n ad_personalization: social ? \"granted\" : \"denied\",\n });\n };\n\n return (\n <ConsentManagerContext.Provider\n value={{\n cookiePreferences,\n setCookiePreferences,\n showConsentBanner,\n isConsentKnown,\n }}\n >\n <Scripts config={config} />\n {children}\n </ConsentManagerContext.Provider>\n );\n};\n\n// Hook\nexport const useConsentManager = () => {\n const ctx = useContext(ConsentManagerContext);\n if (!ctx) {\n throw new Error(\"useConsentManager must be used within a ConsentManagerProvider\");\n }\n\n const { cookiePreferences, setCookiePreferences, showConsentBanner, isConsentKnown } = ctx;\n\n const setCategoryConsent = (category: keyof CookiePreferences, value: boolean) => {\n setCookiePreferences({\n ...cookiePreferences,\n [category]: value,\n });\n };\n\n const hasConsentedTo = (category: keyof CookiePreferences) =>\n cookiePreferences[category] === true;\n\n return {\n cookiePreferences,\n setCookiePreferences,\n setCategoryConsent,\n hasConsentedTo,\n showConsentBanner,\n isConsentKnown,\n };\n};\n","export function extractScriptTagAttrs(\n html: string\n): { src?: string; attrs?: Record<string, string> } | null {\n if (typeof window === \"undefined\") return null; // SSR safety\n\n try {\n const parser = new DOMParser();\n const doc = parser.parseFromString(html, \"text/html\");\n const scriptEl = doc.querySelector(\"script\");\n\n if (!scriptEl) return null;\n\n const src = scriptEl.getAttribute(\"src\") || undefined;\n\n const attrs: Record<string, string> = {};\n for (const attr of Array.from(scriptEl.attributes)) {\n attrs[attr.name] = attr.value;\n }\n\n return { src, attrs };\n } catch (e) {\n console.warn(\"[consentry] Failed to parse script content:\", e);\n return null;\n }\n}\n"],"mappings":"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","names":["jsx","jsxs"]}