cookiecraft 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,24 @@
1
+ /**
2
+ * CategoryManager - Maps scripts to consent categories and manages patterns
3
+ */
4
+ import { ConsentCategories } from '../types';
5
+ export declare class CategoryManager {
6
+ private categories;
7
+ constructor();
8
+ /**
9
+ * Register a category with URL patterns
10
+ */
11
+ registerCategory(name: string, patterns: string[]): void;
12
+ /**
13
+ * Get category for a script element
14
+ */
15
+ getCategoryForScript(script: HTMLScriptElement): string | null;
16
+ /**
17
+ * Check if a category is allowed based on consent
18
+ */
19
+ isAllowed(category: string, consent: ConsentCategories): boolean;
20
+ /**
21
+ * Initialize default URL patterns for common tracking services
22
+ */
23
+ private initializeDefaultPatterns;
24
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * ScriptBlocker - Prevents scripts from executing before consent using MutationObserver
3
+ */
4
+ import { ConsentCategories } from '../types';
5
+ import { CategoryManager } from './CategoryManager';
6
+ import { EventEmitter } from '../core/EventEmitter';
7
+ export declare class ScriptBlocker {
8
+ private observer;
9
+ private blockedScripts;
10
+ private categoryManager;
11
+ private eventEmitter;
12
+ private currentConsent;
13
+ constructor(categoryManager: CategoryManager, eventEmitter: EventEmitter);
14
+ /**
15
+ * Initialize script blocking
16
+ */
17
+ init(): void;
18
+ /**
19
+ * Block all scripts (reset consent)
20
+ */
21
+ block(): void;
22
+ /**
23
+ * Unblock scripts based on consent categories
24
+ */
25
+ unblock(categories: ConsentCategories): void;
26
+ /**
27
+ * Destroy the blocker and stop observing
28
+ */
29
+ destroy(): void;
30
+ /**
31
+ * Block all existing scripts with data-cookieconsent attribute
32
+ */
33
+ private blockExistingScripts;
34
+ /**
35
+ * Observe DOM for dynamically added scripts
36
+ */
37
+ private observeDOM;
38
+ /**
39
+ * Process a script element - block or allow based on consent
40
+ */
41
+ private processScript;
42
+ /**
43
+ * Reactivate a blocked script by creating a new one with correct type
44
+ */
45
+ private reactivateScript;
46
+ /**
47
+ * Generate a stable, deterministic ID for a script element
48
+ */
49
+ private generateScriptId;
50
+ /**
51
+ * Simple hash function for content-based script identification
52
+ */
53
+ private simpleHash;
54
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * ConsentManager - Handles consent logic and validation
3
+ */
4
+ import { ConsentConfig, ConsentCategories, ConsentRecord } from '../types';
5
+ export declare class ConsentManager {
6
+ private consent;
7
+ private config;
8
+ constructor(config: ConsentConfig);
9
+ /**
10
+ * Validate consent categories
11
+ */
12
+ validateConsent(categories: ConsentCategories): boolean;
13
+ /**
14
+ * Update consent with new categories
15
+ */
16
+ updateConsent(categories: ConsentCategories): ConsentRecord;
17
+ /**
18
+ * Check if user needs to give consent
19
+ */
20
+ needsConsent(): boolean;
21
+ /**
22
+ * Check if stored consent needs update due to policy change
23
+ */
24
+ needsUpdate(storedConsent: ConsentRecord): boolean;
25
+ /**
26
+ * Get current consent record
27
+ */
28
+ getCurrentConsent(): ConsentRecord;
29
+ /**
30
+ * Create a new consent record
31
+ */
32
+ private createConsentRecord;
33
+ }
@@ -0,0 +1,76 @@
1
+ /**
2
+ * CookieConsent - Main orchestrator class
3
+ */
4
+ import { ConsentConfig, ConsentCategories } from '../types';
5
+ import '../styles/banner.css';
6
+ import '../styles/animations.css';
7
+ import '../styles/preferences.css';
8
+ import '../styles/widget.css';
9
+ export declare class CookieConsent {
10
+ private config;
11
+ private consentManager;
12
+ private storageManager;
13
+ private scriptBlocker;
14
+ private eventEmitter;
15
+ private banner;
16
+ private preferenceCenter;
17
+ private floatingWidget;
18
+ private gtmIntegration;
19
+ constructor(config: ConsentConfig);
20
+ /**
21
+ * Initialize the cookie consent system
22
+ */
23
+ init(): void;
24
+ /**
25
+ * Show the banner
26
+ */
27
+ show(): void;
28
+ /**
29
+ * Hide the banner
30
+ */
31
+ hide(): void;
32
+ /**
33
+ * Show preferences modal
34
+ */
35
+ showPreferences(): void;
36
+ /**
37
+ * Update consent with new categories
38
+ */
39
+ updateConsent(categories: ConsentCategories): void;
40
+ /**
41
+ * Get current consent
42
+ */
43
+ getConsent(): import("../types").ConsentRecord | null;
44
+ /**
45
+ * Reset consent (clear stored data and show banner)
46
+ */
47
+ reset(): void;
48
+ /**
49
+ * Register event handler
50
+ */
51
+ on(event: string, callback: Function): void;
52
+ /**
53
+ * Unregister event handler
54
+ */
55
+ off(event: string, callback: Function): void;
56
+ /**
57
+ * Destroy and cleanup all UI elements
58
+ */
59
+ destroy(): void;
60
+ /**
61
+ * Show the banner
62
+ */
63
+ private showBanner;
64
+ /**
65
+ * Show the floating widget
66
+ */
67
+ private showFloatingWidget;
68
+ /**
69
+ * Apply consent by unblocking allowed scripts and clearing denied cookies
70
+ */
71
+ private applyConsent;
72
+ /**
73
+ * Validate and set default config values
74
+ */
75
+ private validateConfig;
76
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * EventEmitter - Simple pub/sub pattern for internal and external events
3
+ */
4
+ export declare class EventEmitter {
5
+ private events;
6
+ /**
7
+ * Register an event handler
8
+ */
9
+ on(event: string, callback: Function): void;
10
+ /**
11
+ * Unregister an event handler
12
+ */
13
+ off(event: string, callback: Function): void;
14
+ /**
15
+ * Emit an event with optional data
16
+ */
17
+ emit(event: string, data?: any): void;
18
+ /**
19
+ * Clear all event handlers
20
+ */
21
+ clear(): void;
22
+ /**
23
+ * Clear handlers for a specific event
24
+ */
25
+ clearEvent(event: string): void;
26
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * StorageManager - Manages localStorage persistence for consent records
3
+ */
4
+ import { ConsentRecord } from '../types';
5
+ export declare class StorageManager {
6
+ private static readonly STORAGE_KEY;
7
+ static readonly EXPIRY_MONTHS = 13;
8
+ /**
9
+ * Save consent record to localStorage
10
+ */
11
+ save(consent: ConsentRecord): void;
12
+ /**
13
+ * Load consent record from localStorage
14
+ */
15
+ load(): ConsentRecord | null;
16
+ /**
17
+ * Clear consent record from localStorage
18
+ */
19
+ clear(): void;
20
+ /**
21
+ * Check if consent record has expired
22
+ */
23
+ isExpired(consent: ConsentRecord): boolean;
24
+ /**
25
+ * Validate consent record schema
26
+ */
27
+ private validateSchema;
28
+ /**
29
+ * Migrate old consent format to new format
30
+ * Returns null if migration fails
31
+ */
32
+ private migrate;
33
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * CookieCraft
3
+ * Lightweight GDPR-compliant cookie consent library
4
+ */
5
+ export { CookieConsent } from './core/CookieConsent';
6
+ export type { ConsentConfig, ConsentCategories, CategoryConfig, ConsentRecord, Translation, GTMConsent, ConsentEvent, } from './types';
@@ -0,0 +1,21 @@
1
+ /**
2
+ * DataLayerManager - Manages Google Tag Manager dataLayer communication
3
+ * Implements Google Consent Mode v2 correctly via gtag() API
4
+ */
5
+ export declare class DataLayerManager {
6
+ /**
7
+ * Initialize gtag function if not already present
8
+ * This must be called before GTM loads for consent defaults to work
9
+ */
10
+ private ensureGtag;
11
+ /**
12
+ * Push consent command via gtag (correct format for Google Consent Mode v2)
13
+ * Usage: pushConsent('default', {...}) or pushConsent('update', {...})
14
+ */
15
+ pushConsent(action: string, params: Record<string, string | number>): void;
16
+ /**
17
+ * Push a 'set' command via gtag for advanced features
18
+ * Usage: pushSet('url_passthrough', true) or pushSet('ads_data_redaction', true)
19
+ */
20
+ pushSet(key: string, value: boolean | string | number): void;
21
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * GTMConsentMode - Full integration with Google Consent Mode v2
3
+ *
4
+ * Implements all required signals:
5
+ * - ad_storage, ad_user_data, ad_personalization, analytics_storage (core GCM v2)
6
+ * - functionality_storage, personalization_storage, security_storage (non-core)
7
+ * - wait_for_update, url_passthrough, ads_data_redaction (advanced features)
8
+ */
9
+ import { ConsentCategories, ConsentConfig } from '../types';
10
+ import { DataLayerManager } from './DataLayerManager';
11
+ export declare class GTMConsentMode {
12
+ private dataLayerManager;
13
+ private config;
14
+ constructor(dataLayerManager: DataLayerManager, config: ConsentConfig);
15
+ /**
16
+ * Set default consent state (MUST be called BEFORE GTM loads)
17
+ * All non-essential consent types default to 'denied' per GDPR
18
+ */
19
+ setDefaultConsent(): void;
20
+ /**
21
+ * Update consent state based on user choices
22
+ * Called both on new consent and on page load for returning visitors
23
+ */
24
+ updateConsent(categories: ConsentCategories): void;
25
+ /**
26
+ * Map consent categories to GTM Consent Mode v2 format
27
+ */
28
+ private mapCategoriesToGTM;
29
+ }
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Type definitions for CookieCraft
3
+ */
4
+ export interface ConsentCategories {
5
+ necessary: boolean;
6
+ analytics: boolean;
7
+ marketing: boolean;
8
+ preferences?: boolean;
9
+ }
10
+ export interface CategoryConfig {
11
+ enabled: boolean;
12
+ readOnly: boolean;
13
+ label: string;
14
+ description: string;
15
+ }
16
+ export interface Translation {
17
+ title?: string;
18
+ description?: string;
19
+ acceptAll?: string;
20
+ rejectAll?: string;
21
+ essentialsOnly?: string;
22
+ customize?: string;
23
+ savePreferences?: string;
24
+ necessary?: string;
25
+ analytics?: string;
26
+ marketing?: string;
27
+ preferences?: string;
28
+ cookieSettings?: string;
29
+ cookies?: string;
30
+ privacyPolicyUrl?: string;
31
+ privacyPolicyLabel?: string;
32
+ preferencesTitle?: string;
33
+ }
34
+ export interface ConsentConfig {
35
+ mode: 'opt-in' | 'opt-out';
36
+ autoShow: boolean;
37
+ revision: number;
38
+ categories: {
39
+ necessary: CategoryConfig;
40
+ analytics: CategoryConfig;
41
+ marketing: CategoryConfig;
42
+ preferences?: CategoryConfig;
43
+ };
44
+ theme?: 'light' | 'dark' | 'auto';
45
+ position?: 'bottom' | 'top' | 'center' | 'bottom-left' | 'bottom-right';
46
+ layout?: 'bar' | 'box' | 'floating';
47
+ primaryColor?: string;
48
+ backdropBlur?: boolean;
49
+ animationStyle?: 'smooth' | 'minimal';
50
+ preferencesPosition?: 'center' | 'bottom-left' | 'bottom-right' | 'top-left' | 'top-right';
51
+ showWidget?: boolean;
52
+ widgetPosition?: 'bottom-left' | 'bottom-right' | 'top-left' | 'top-right';
53
+ widgetStyle?: 'compact' | 'full';
54
+ language?: string;
55
+ translations?: Translation;
56
+ gtmConsentMode?: boolean;
57
+ gtmWaitForUpdate?: number;
58
+ gtmUrlPassthrough?: boolean;
59
+ gtmAdsDataRedaction?: boolean;
60
+ cookieDomain?: string;
61
+ disablePageInteraction?: boolean;
62
+ onAccept?: (categories: ConsentCategories) => void;
63
+ onReject?: () => void;
64
+ onChange?: (categories: ConsentCategories) => void;
65
+ }
66
+ export interface ConsentRecord {
67
+ version: number;
68
+ timestamp: string;
69
+ categories: ConsentCategories;
70
+ userAgent: string;
71
+ expiresAt: string;
72
+ }
73
+ export interface GTMConsent {
74
+ [key: string]: 'granted' | 'denied';
75
+ ad_storage: 'granted' | 'denied';
76
+ ad_user_data: 'granted' | 'denied';
77
+ ad_personalization: 'granted' | 'denied';
78
+ analytics_storage: 'granted' | 'denied';
79
+ functionality_storage: 'granted' | 'denied';
80
+ personalization_storage: 'granted' | 'denied';
81
+ security_storage: 'granted' | 'denied';
82
+ }
83
+ export type ConsentEvent = 'consent:init' | 'consent:show' | 'consent:hide' | 'consent:accept' | 'consent:reject' | 'consent:update' | 'consent:load' | 'consent:expire' | 'preferences:show' | 'preferences:hide' | 'script:activated';
84
+ declare global {
85
+ interface Window {
86
+ dataLayer?: any[];
87
+ gtag?: (...args: any[]) => void;
88
+ cookieConsent?: any;
89
+ }
90
+ }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Banner - Cookie consent banner component
3
+ */
4
+ import { ConsentConfig } from '../types';
5
+ import { EventEmitter } from '../core/EventEmitter';
6
+ export declare class Banner {
7
+ private config;
8
+ private element;
9
+ private eventEmitter;
10
+ constructor(config: ConsentConfig, eventEmitter: EventEmitter);
11
+ /**
12
+ * Show the banner
13
+ */
14
+ show(): void;
15
+ /**
16
+ * Hide the banner
17
+ */
18
+ hide(): void;
19
+ /**
20
+ * Destroy the banner
21
+ */
22
+ destroy(): void;
23
+ /**
24
+ * Create DOM structure for banner
25
+ */
26
+ private createDOM;
27
+ /**
28
+ * Attach event listeners
29
+ */
30
+ private attachListeners;
31
+ /**
32
+ * Handle accept all action
33
+ */
34
+ private handleAcceptAll;
35
+ /**
36
+ * Handle reject all action
37
+ */
38
+ private handleRejectAll;
39
+ /**
40
+ * Handle customize action
41
+ */
42
+ private handleCustomize;
43
+ /**
44
+ * Generate description HTML with privacy policy link
45
+ */
46
+ private getDescriptionHTML;
47
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * FloatingWidget - Permanent cookie settings button
3
+ * Stays visible at all times for easy access to preferences
4
+ */
5
+ import { ConsentConfig } from '../types';
6
+ import { EventEmitter } from '../core/EventEmitter';
7
+ export declare class FloatingWidget {
8
+ private config;
9
+ private element;
10
+ private eventEmitter;
11
+ private isVisible;
12
+ constructor(config: ConsentConfig, eventEmitter: EventEmitter);
13
+ /**
14
+ * Show the floating widget
15
+ */
16
+ show(): void;
17
+ /**
18
+ * Hide the floating widget
19
+ */
20
+ hide(): void;
21
+ /**
22
+ * Destroy the widget
23
+ */
24
+ destroy(): void;
25
+ /**
26
+ * Check if widget is visible
27
+ */
28
+ getIsVisible(): boolean;
29
+ /**
30
+ * Create DOM structure for floating widget
31
+ */
32
+ private createDOM;
33
+ /**
34
+ * Attach event listeners
35
+ */
36
+ private attachListeners;
37
+ /**
38
+ * Handle widget click
39
+ */
40
+ private handleClick;
41
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * PreferenceCenter - Modal for granular cookie preferences
3
+ */
4
+ import { ConsentConfig, ConsentCategories } from '../types';
5
+ import { EventEmitter } from '../core/EventEmitter';
6
+ export declare class PreferenceCenter {
7
+ private config;
8
+ private element;
9
+ private eventEmitter;
10
+ private currentConsent;
11
+ constructor(config: ConsentConfig, eventEmitter: EventEmitter, currentConsent: ConsentCategories);
12
+ /**
13
+ * Show the preference center
14
+ */
15
+ show(): void;
16
+ /**
17
+ * Hide the preference center
18
+ */
19
+ hide(): void;
20
+ /**
21
+ * Destroy the preference center
22
+ */
23
+ destroy(): void;
24
+ /**
25
+ * Create DOM structure for preference center
26
+ */
27
+ private createDOM;
28
+ /**
29
+ * Render category toggles
30
+ */
31
+ private renderCategories;
32
+ /**
33
+ * Attach event listeners
34
+ */
35
+ private attachListeners;
36
+ /**
37
+ * Handle save preferences
38
+ */
39
+ private handleSave;
40
+ /**
41
+ * Handle reject all
42
+ */
43
+ private handleRejectAll;
44
+ /**
45
+ * Trap focus within modal
46
+ */
47
+ private trapFocus;
48
+ /**
49
+ * Adjust color brightness for hover effect
50
+ */
51
+ private adjustColorBrightness;
52
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Cookie utilities for clearing non-essential cookies on rejection/withdrawal
3
+ */
4
+ /**
5
+ * Clear cookies matching patterns for denied categories
6
+ */
7
+ export declare function clearCookiesForCategory(category: string): void;
8
+ /**
9
+ * Clear all non-essential cookies based on consent categories
10
+ */
11
+ export declare function clearDeniedCookies(categories: Record<string, boolean>): void;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Sanitization utilities to prevent XSS in HTML templates
3
+ */
4
+ /**
5
+ * Escape HTML entities in a string to prevent XSS
6
+ */
7
+ export declare function escapeHtml(str: string): string;
8
+ /**
9
+ * Sanitize a URL - only allow http(s) and relative URLs
10
+ */
11
+ export declare function sanitizeUrl(url: string): string;
12
+ /**
13
+ * Sanitize a CSS color value - only allow valid hex, rgb, hsl, named colors
14
+ */
15
+ export declare function sanitizeColor(color: string): string;
16
+ /**
17
+ * Sanitize a CSS property value to prevent injection
18
+ */
19
+ export declare function sanitizeCssValue(value: string): string;
package/package.json ADDED
@@ -0,0 +1,86 @@
1
+ {
2
+ "name": "cookiecraft",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "description": "Lightweight GDPR-compliant cookie consent library for any website",
6
+ "main": "dist/cookiecraft.js",
7
+ "module": "dist/cookiecraft.esm.js",
8
+ "types": "dist/types/index.d.ts",
9
+ "jsdelivr": "dist/cookiecraft.min.js",
10
+ "unpkg": "dist/cookiecraft.min.js",
11
+ "files": [
12
+ "dist",
13
+ "README.md",
14
+ "WEBFLOW_GUIDE.md"
15
+ ],
16
+ "scripts": {
17
+ "dev": "rollup -c -w",
18
+ "build": "rollup -c && npm run size",
19
+ "test": "jest",
20
+ "test:watch": "jest --watch",
21
+ "test:coverage": "jest --coverage",
22
+ "test:a11y": "jest --testMatch='**/accessibility/**/*.test.ts'",
23
+ "lint": "eslint src/**/*.ts",
24
+ "type-check": "tsc --noEmit",
25
+ "size": "size-limit",
26
+ "prepublishOnly": "npm run build"
27
+ },
28
+ "keywords": [
29
+ "cookie",
30
+ "consent",
31
+ "gdpr",
32
+ "rgpd",
33
+ "privacy",
34
+ "compliance",
35
+ "eprivacy",
36
+ "gtm",
37
+ "google-consent-mode",
38
+ "typescript",
39
+ "vanilla-js",
40
+ "cookie-banner",
41
+ "consent-management",
42
+ "webflow",
43
+ "wordpress",
44
+ "shopify"
45
+ ],
46
+ "author": "Fawsy",
47
+ "license": "MIT",
48
+ "repository": {
49
+ "type": "git",
50
+ "url": "https://github.com/Fz3dev/cookiecraft"
51
+ },
52
+ "devDependencies": {
53
+ "@rollup/plugin-commonjs": "^25.0.7",
54
+ "@rollup/plugin-node-resolve": "^15.2.3",
55
+ "@rollup/plugin-terser": "^0.4.4",
56
+ "@rollup/plugin-typescript": "^11.1.6",
57
+ "@size-limit/preset-small-lib": "^11.0.2",
58
+ "@types/jest": "^29.5.12",
59
+ "@typescript-eslint/eslint-plugin": "^7.1.0",
60
+ "@typescript-eslint/parser": "^7.1.0",
61
+ "autoprefixer": "^10.4.18",
62
+ "cssnano": "^6.1.0",
63
+ "eslint": "^8.57.0",
64
+ "jest": "^29.7.0",
65
+ "jest-axe": "^8.0.0",
66
+ "jest-environment-jsdom": "^29.7.0",
67
+ "postcss": "^8.4.35",
68
+ "rollup": "^4.13.0",
69
+ "rollup-plugin-postcss": "^4.0.2",
70
+ "rollup-plugin-visualizer": "^5.12.0",
71
+ "size-limit": "^11.0.2",
72
+ "ts-jest": "^29.1.2",
73
+ "tslib": "^2.8.1",
74
+ "typescript": "^5.4.2"
75
+ },
76
+ "size-limit": [
77
+ {
78
+ "path": "dist/cookiecraft.min.js",
79
+ "limit": "12 KB"
80
+ },
81
+ {
82
+ "path": "dist/cookiecraft.css",
83
+ "limit": "3 KB"
84
+ }
85
+ ]
86
+ }