UNPKG

c15t

Version:

<div align="center"> <img src="https://c15t.com/logo-icon.png" alt="c15t Logo" width="64" height="64" /> <h1>c15t</h1> <p>Transform privacy consent from a compliance checkbox into a fully observable system</p>

1,519 lines 63.8 kB
import * as __WEBPACK_EXTERNAL_MODULE__c15t_translations_cdae900b__ from "@c15t/translations";
import * as __WEBPACK_EXTERNAL_MODULE_zustand_vanilla_8a8e4ffb__ from "zustand/vanilla";
const API_ENDPOINTS = {
    SHOW_CONSENT_BANNER: '/show-consent-banner',
    SET_CONSENT: '/consent/set',
    VERIFY_CONSENT: '/consent/verify'
};
const gdpr_consentTypes = [
    {
        defaultValue: true,
        description: 'These trackers are used for activities that are strictly necessary to operate or deliver the service you requested from us and, therefore, do not require you to consent.',
        disabled: true,
        display: true,
        gdprType: 1,
        name: 'necessary'
    },
    {
        defaultValue: false,
        description: 'These trackers enable basic interactions and functionalities that allow you to access selected features of our service and facilitate your communication with us.',
        display: false,
        gdprType: 2,
        name: 'functionality'
    },
    {
        defaultValue: false,
        description: 'These trackers help us to measure traffic and analyze your behavior to improve our service.',
        display: false,
        gdprType: 4,
        name: 'measurement'
    },
    {
        defaultValue: false,
        description: 'These trackers help us to improve the quality of your user experience and enable interactions with external content, networks, and platforms.',
        display: false,
        gdprType: 3,
        name: 'experience'
    },
    {
        defaultValue: false,
        description: 'These trackers help us to deliver personalized ads or marketing content to you, and to measure their performance.',
        display: false,
        gdprType: 5,
        name: 'marketing'
    }
];
const DEFAULT_RETRY_CONFIG = {
    maxRetries: 3,
    initialDelayMs: 100,
    backoffFactor: 2,
    retryableStatusCodes: [
        500,
        502,
        503,
        504
    ],
    nonRetryableStatusCodes: [
        400,
        401,
        403,
        404
    ],
    retryOnNetworkError: true,
    shouldRetry: void 0
};
const ABSOLUTE_URL_REGEX = /^(?:[a-z+]+:)?\/\//i;
const LEADING_SLASHES_REGEX = /^\/+/;
const TRAILING_SLASHES_REGEX = /\/+$/;
const delay = (ms)=>new Promise((resolve)=>setTimeout(resolve, ms));
function generateUUID() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c)=>{
        const r = 16 * Math.random() | 0;
        const v = 'x' === c ? r : 0x3 & r | 0x8;
        return v.toString(16);
    });
}
class C15tClient {
    backendURL;
    headers;
    customFetch;
    callbacks;
    corsMode;
    retryConfig;
    constructor(options){
        this.backendURL = options.backendURL.endsWith('/') ? options.backendURL.slice(0, -1) : options.backendURL;
        this.headers = {
            'Content-Type': 'application/json',
            ...options.headers
        };
        this.customFetch = options.customFetch;
        this.callbacks = options.callbacks;
        this.corsMode = options.corsMode || 'cors';
        this.retryConfig = {
            maxRetries: options.retryConfig?.maxRetries ?? DEFAULT_RETRY_CONFIG.maxRetries ?? 3,
            initialDelayMs: options.retryConfig?.initialDelayMs ?? DEFAULT_RETRY_CONFIG.initialDelayMs ?? 100,
            backoffFactor: options.retryConfig?.backoffFactor ?? DEFAULT_RETRY_CONFIG.backoffFactor ?? 2,
            retryableStatusCodes: options.retryConfig?.retryableStatusCodes ?? DEFAULT_RETRY_CONFIG.retryableStatusCodes,
            nonRetryableStatusCodes: options.retryConfig?.nonRetryableStatusCodes ?? DEFAULT_RETRY_CONFIG.nonRetryableStatusCodes,
            shouldRetry: options.retryConfig?.shouldRetry ?? DEFAULT_RETRY_CONFIG.shouldRetry,
            retryOnNetworkError: options.retryConfig?.retryOnNetworkError ?? DEFAULT_RETRY_CONFIG.retryOnNetworkError
        };
        this.checkPendingConsentSubmissions();
    }
    resolveUrl(backendURL, path) {
        if (ABSOLUTE_URL_REGEX.test(backendURL)) {
            const backendURLObj = new URL(backendURL);
            const basePath = backendURLObj.pathname.replace(TRAILING_SLASHES_REGEX, '');
            const cleanPath = path.replace(LEADING_SLASHES_REGEX, '');
            const newPath = `${basePath}/${cleanPath}`;
            backendURLObj.pathname = newPath;
            return backendURLObj.toString();
        }
        const cleanBase = backendURL.replace(TRAILING_SLASHES_REGEX, '');
        const cleanPath = path.replace(LEADING_SLASHES_REGEX, '');
        return `${cleanBase}/${cleanPath}`;
    }
    getCallbacks() {
        return this.callbacks;
    }
    setCallbacks(callbacks) {
        this.callbacks = callbacks;
    }
    createResponseContext(isSuccess, data = null, error = null, response = null) {
        return {
            data,
            error,
            ok: isSuccess,
            response
        };
    }
    async fetcher(path, options) {
        const finalRetryConfig = {
            ...this.retryConfig,
            ...options?.retryConfig || {},
            retryableStatusCodes: options?.retryConfig?.retryableStatusCodes ?? this.retryConfig.retryableStatusCodes ?? DEFAULT_RETRY_CONFIG.retryableStatusCodes,
            nonRetryableStatusCodes: options?.retryConfig?.nonRetryableStatusCodes ?? this.retryConfig.nonRetryableStatusCodes ?? DEFAULT_RETRY_CONFIG.nonRetryableStatusCodes
        };
        const { maxRetries, initialDelayMs, backoffFactor, retryableStatusCodes, nonRetryableStatusCodes, retryOnNetworkError } = finalRetryConfig;
        let attemptsMade = 0;
        let currentDelay = initialDelayMs;
        let lastErrorResponse = null;
        while(attemptsMade <= (maxRetries ?? 0)){
            const requestId = generateUUID();
            const fetchImpl = this.customFetch || globalThis.fetch;
            const resolvedUrl = this.resolveUrl(this.backendURL, path);
            let url;
            try {
                url = new URL(resolvedUrl);
            } catch  {
                url = new URL(resolvedUrl, window.location.origin);
            }
            if (options?.query) {
                for (const [key, value] of Object.entries(options.query))if (void 0 !== value) url.searchParams.append(key, String(value));
            }
            const requestOptions = {
                method: options?.method || 'GET',
                mode: this.corsMode,
                credentials: 'include',
                headers: {
                    ...this.headers,
                    'X-Request-ID': requestId,
                    ...options?.headers
                },
                ...options?.fetchOptions
            };
            if (options?.body && 'GET' !== requestOptions.method) requestOptions.body = JSON.stringify(options.body);
            try {
                const response = await fetchImpl(url.toString(), requestOptions);
                let data = null;
                let parseError = null;
                try {
                    const contentType = response.headers.get('content-type');
                    if (contentType?.includes('application/json') && 204 !== response.status && '0' !== response.headers.get('content-length')) data = await response.json();
                    else if (204 === response.status) data = null;
                } catch (err) {
                    parseError = err;
                }
                if (parseError) {
                    const errorResponse = this.createResponseContext(false, null, {
                        message: 'Failed to parse response',
                        status: response.status,
                        code: 'PARSE_ERROR',
                        cause: parseError
                    }, response);
                    options?.onError?.(errorResponse, path);
                    this.callbacks?.onError?.(errorResponse, path);
                    if (options?.throw) throw new Error('Failed to parse response');
                    return errorResponse;
                }
                const isSuccess = response.status >= 200 && response.status < 300;
                if (isSuccess) {
                    const successResponse = this.createResponseContext(true, data, null, response);
                    options?.onSuccess?.(successResponse);
                    return successResponse;
                }
                const errorData = data;
                const errorResponse = this.createResponseContext(false, null, {
                    message: errorData?.message || `Request failed with status ${response.status}`,
                    status: response.status,
                    code: errorData?.code || 'API_ERROR',
                    details: errorData?.details || null
                }, response);
                lastErrorResponse = errorResponse;
                let shouldRetryThisRequest = false;
                if (nonRetryableStatusCodes?.includes(response.status)) {
                    console.debug(`Not retrying request to ${path} with status ${response.status} (nonRetryableStatusCodes)`);
                    shouldRetryThisRequest = false;
                } else if ('function' == typeof finalRetryConfig.shouldRetry) try {
                    shouldRetryThisRequest = finalRetryConfig.shouldRetry(response, {
                        attemptsMade,
                        url: url.toString(),
                        method: requestOptions.method || 'GET'
                    });
                    console.debug(`Custom retry strategy for ${path} with status ${response.status}: ${shouldRetryThisRequest}`);
                } catch  {
                    shouldRetryThisRequest = retryableStatusCodes?.includes(response.status) ?? false;
                    console.debug(`Custom retry strategy failed, falling back to status code check: ${shouldRetryThisRequest}`);
                }
                else {
                    shouldRetryThisRequest = retryableStatusCodes?.includes(response.status) ?? false;
                    console.debug(`Standard retry check for ${path} with status ${response.status}: ${shouldRetryThisRequest}`);
                }
                if (!shouldRetryThisRequest || attemptsMade >= (maxRetries ?? 0)) {
                    options?.onError?.(errorResponse, path);
                    this.callbacks?.onError?.(errorResponse, path);
                    if (options?.throw) throw new Error(errorResponse.error?.message || 'Request failed');
                    return errorResponse;
                }
                attemptsMade++;
                await delay(currentDelay ?? 0);
                currentDelay = (currentDelay ?? 0) * (backoffFactor ?? 2);
            } catch (fetchError) {
                if (fetchError && 'Failed to parse response' === fetchError.message) throw fetchError;
                const isNetworkError = !(fetchError instanceof Response);
                const errorResponse = this.createResponseContext(false, null, {
                    message: fetchError instanceof Error ? fetchError.message : String(fetchError),
                    status: 0,
                    code: 'NETWORK_ERROR',
                    cause: fetchError
                }, null);
                lastErrorResponse = errorResponse;
                const shouldRetryThisRequest = isNetworkError && retryOnNetworkError;
                if (!shouldRetryThisRequest || attemptsMade >= (maxRetries ?? 0)) {
                    options?.onError?.(errorResponse, path);
                    this.callbacks?.onError?.(errorResponse, path);
                    if (options?.throw) throw fetchError;
                    return errorResponse;
                }
                attemptsMade++;
                await delay(currentDelay ?? 0);
                currentDelay = (currentDelay ?? 0) * (backoffFactor ?? 2);
            }
        }
        const maxRetriesErrorResponse = lastErrorResponse || this.createResponseContext(false, null, {
            message: `Request failed after ${maxRetries} retries`,
            status: 0,
            code: 'MAX_RETRIES_EXCEEDED'
        }, null);
        options?.onError?.(maxRetriesErrorResponse, path);
        this.callbacks?.onError?.(maxRetriesErrorResponse, path);
        if (options?.throw) throw new Error(`Request failed after ${maxRetries} retries`);
        return maxRetriesErrorResponse;
    }
    async showConsentBanner(options) {
        try {
            const response = await this.fetcher(API_ENDPOINTS.SHOW_CONSENT_BANNER, {
                method: 'GET',
                ...options
            });
            if (response.ok || options?.testing) {
                if (this.callbacks?.onConsentBannerFetched && response.data) {
                    const callbackPayload = {
                        ok: response.ok,
                        error: response.error,
                        response: null,
                        data: {
                            showConsentBanner: response.data.showConsentBanner,
                            jurisdiction: response.data.jurisdiction,
                            location: {
                                countryCode: response.data.location.countryCode,
                                regionCode: response.data.location.regionCode
                            }
                        }
                    };
                    this.callbacks.onConsentBannerFetched(callbackPayload);
                }
                return response;
            }
            console.warn('API request failed, falling back to offline mode for consent banner');
            return this.offlineFallbackForConsentBanner(options);
        } catch (error) {
            if (options?.testing || options?.disableFallback) {
                const errorResponse = this.createResponseContext(false, null, {
                    message: error instanceof Error ? error.message : String(error),
                    status: 0,
                    code: 'NETWORK_ERROR',
                    cause: error
                }, null);
                if (options?.onError) await options.onError(errorResponse, API_ENDPOINTS.SHOW_CONSENT_BANNER);
                return errorResponse;
            }
            console.warn('Error fetching consent banner info, falling back to offline mode:', error);
            return this.offlineFallbackForConsentBanner(options);
        }
    }
    async offlineFallbackForConsentBanner(options) {
        let shouldShow = true;
        let hasLocalStorageAccess = false;
        try {
            if ('undefined' != typeof window && window.localStorage) {
                window.localStorage.setItem('c15t-storage-test-key', 'test');
                window.localStorage.removeItem('c15t-storage-test-key');
                hasLocalStorageAccess = true;
                const storedConsent = window.localStorage.getItem('c15t-consent');
                shouldShow = null === storedConsent;
            }
        } catch (error) {
            console.warn('Failed to access localStorage in offline fallback:', error);
            shouldShow = false;
        }
        const response = this.createResponseContext(true, {
            showConsentBanner: shouldShow && hasLocalStorageAccess,
            jurisdiction: {
                code: 'NONE',
                message: 'Unknown (offline mode)'
            },
            location: {
                countryCode: 'XX',
                regionCode: null
            }
        }, null, null);
        if (options?.onSuccess) await options.onSuccess(response);
        if (this.callbacks?.onConsentBannerFetched && response.data) {
            const callbackPayload = {
                ok: response.ok,
                error: response.error,
                response: null,
                data: {
                    showConsentBanner: response.data.showConsentBanner,
                    jurisdiction: response.data.jurisdiction,
                    location: {
                        countryCode: response.data.location.countryCode,
                        regionCode: response.data.location.regionCode
                    }
                }
            };
            this.callbacks.onConsentBannerFetched(callbackPayload);
        }
        return response;
    }
    async setConsent(options) {
        try {
            const response = await this.fetcher(API_ENDPOINTS.SET_CONSENT, {
                method: 'POST',
                ...options
            });
            if (response.ok && response.data || options?.testing) {
                if (this.callbacks?.onConsentSet) {
                    const callbackPayload = {
                        ok: response.ok,
                        error: response.error,
                        response: null,
                        data: {
                            type: options?.body?.type || 'cookie_banner',
                            preferences: options?.body?.preferences || {},
                            domain: options?.body?.domain
                        }
                    };
                    this.callbacks.onConsentSet(callbackPayload);
                }
                return response;
            }
            console.warn('API request failed, falling back to offline mode for setting consent');
            return this.offlineFallbackForSetConsent(options);
        } catch (error) {
            if (options?.testing || options?.disableFallback) {
                const errorResponse = this.createResponseContext(false, null, {
                    message: error instanceof Error ? error.message : String(error),
                    status: 0,
                    code: 'NETWORK_ERROR',
                    cause: error
                }, null);
                if (options?.onError) await options.onError(errorResponse, API_ENDPOINTS.SET_CONSENT);
                return errorResponse;
            }
            console.warn('Error setting consent, falling back to offline mode:', error);
            return this.offlineFallbackForSetConsent(options);
        }
    }
    async offlineFallbackForSetConsent(options) {
        const pendingSubmissionsKey = 'c15t-pending-consent-submissions';
        try {
            if ('undefined' != typeof window && window.localStorage) {
                window.localStorage.setItem('c15t-storage-test-key', 'test');
                window.localStorage.removeItem('c15t-storage-test-key');
                window.localStorage.setItem('c15t-consent', JSON.stringify({
                    timestamp: new Date().toISOString(),
                    preferences: options?.body?.preferences || {}
                }));
                if (options?.body) {
                    let pendingSubmissions = [];
                    try {
                        const storedSubmissions = window.localStorage.getItem(pendingSubmissionsKey);
                        if (storedSubmissions) pendingSubmissions = JSON.parse(storedSubmissions);
                    } catch (e) {
                        console.warn('Error parsing pending submissions:', e);
                        pendingSubmissions = [];
                    }
                    const newSubmission = options.body;
                    const isDuplicate = pendingSubmissions.some((submission)=>JSON.stringify(submission) === JSON.stringify(newSubmission));
                    if (!isDuplicate) {
                        pendingSubmissions.push(newSubmission);
                        window.localStorage.setItem(pendingSubmissionsKey, JSON.stringify(pendingSubmissions));
                        console.log('Queued consent submission for retry on next page load');
                    }
                }
            }
        } catch (error) {
            console.warn('Failed to write to localStorage in offline fallback:', error);
        }
        const response = this.createResponseContext(true, null, null, null);
        if (options?.onSuccess) await options.onSuccess(response);
        if (this.callbacks?.onConsentSet) {
            const callbackPayload = {
                ...response,
                data: {
                    type: options?.body?.type || 'cookie_banner',
                    preferences: options?.body?.preferences || {},
                    domain: options?.body?.domain
                }
            };
            this.callbacks.onConsentSet(callbackPayload);
        }
        return response;
    }
    async verifyConsent(options) {
        const response = await this.fetcher(API_ENDPOINTS.VERIFY_CONSENT, {
            method: 'POST',
            ...options
        });
        if (response.ok && this.callbacks?.onConsentVerified && response.data) {
            const callbackPayload = {
                ok: response.ok,
                error: response.error,
                response: null,
                data: {
                    type: options?.body?.type || 'cookie_banner',
                    preferences: options?.body?.preferences || [],
                    valid: response.data.isValid,
                    domain: options?.body?.domain
                }
            };
            this.callbacks.onConsentVerified(callbackPayload);
        }
        return response;
    }
    async $fetch(path, options) {
        return await this.fetcher(path, options);
    }
    checkPendingConsentSubmissions() {
        const pendingSubmissionsKey = 'c15t-pending-consent-submissions';
        if ('undefined' == typeof window || !window.localStorage) return;
        try {
            window.localStorage.setItem('c15t-storage-test-key', 'test');
            window.localStorage.removeItem('c15t-storage-test-key');
            const pendingSubmissionsStr = window.localStorage.getItem(pendingSubmissionsKey);
            if (!pendingSubmissionsStr) return;
            const pendingSubmissions = JSON.parse(pendingSubmissionsStr);
            if (!pendingSubmissions.length) return void window.localStorage.removeItem(pendingSubmissionsKey);
            console.log(`Found ${pendingSubmissions.length} pending consent submission(s) to retry`);
            setTimeout(()=>{
                this.processPendingSubmissions(pendingSubmissions);
            }, 2000);
        } catch (error) {
            console.warn('Failed to check for pending consent submissions:', error);
        }
    }
    async processPendingSubmissions(submissions) {
        const pendingSubmissionsKey = 'c15t-pending-consent-submissions';
        const maxRetries = 3;
        const remainingSubmissions = [
            ...submissions
        ];
        for(let i = 0; i < maxRetries && remainingSubmissions.length > 0; i++){
            const successfulSubmissions = [];
            for(let j = 0; j < remainingSubmissions.length; j++){
                const submission = remainingSubmissions[j];
                try {
                    console.log('Retrying consent submission:', submission);
                    const response = await this.fetcher(API_ENDPOINTS.SET_CONSENT, {
                        method: 'POST',
                        body: submission
                    });
                    if (response.ok) {
                        console.log('Successfully resubmitted consent');
                        successfulSubmissions.push(j);
                    }
                } catch (error) {
                    console.warn('Failed to resend consent submission:', error);
                }
            }
            for(let k = successfulSubmissions.length - 1; k >= 0; k--){
                const index = successfulSubmissions[k];
                if (void 0 !== index) remainingSubmissions.splice(index, 1);
            }
            if (0 === remainingSubmissions.length) break;
            if (i < maxRetries - 1) await delay(1000 * (i + 1));
        }
        try {
            if ('undefined' != typeof window && window.localStorage) if (remainingSubmissions.length > 0) {
                window.localStorage.setItem(pendingSubmissionsKey, JSON.stringify(remainingSubmissions));
                console.log(`${remainingSubmissions.length} consent submissions still pending for future retry`);
            } else {
                window.localStorage.removeItem(pendingSubmissionsKey);
                console.log('All pending consent submissions processed successfully');
            }
        } catch (error) {
            console.warn('Error updating pending submissions storage:', error);
        }
    }
}
const client_custom_LEADING_SLASHES_REGEX = /^\/+/;
class CustomClient {
    endpointHandlers;
    dynamicHandlers = {};
    callbacks;
    constructor(options){
        this.endpointHandlers = options.endpointHandlers;
        this.callbacks = options.callbacks;
    }
    getCallbacks() {
        return this.callbacks;
    }
    setCallbacks(callbacks) {
        this.callbacks = callbacks;
    }
    createErrorResponse(message, status = 500, code = 'HANDLER_ERROR', cause) {
        return {
            data: null,
            error: {
                message,
                status,
                code,
                cause
            },
            ok: false,
            response: null
        };
    }
    async executeHandler(handlerKey, options, callbackKey) {
        const handler = this.endpointHandlers[handlerKey];
        if (!handler) {
            const errorResponse = this.createErrorResponse(`No endpoint handler found for '${String(handlerKey)}'`, 404, 'ENDPOINT_NOT_FOUND');
            this.callbacks?.onError?.(errorResponse, String(handlerKey));
            if (options?.throw) throw new Error(`No endpoint handler found for '${String(handlerKey)}'`);
            return errorResponse;
        }
        try {
            const response = await handler(options);
            const normalizedResponse = {
                data: response.data,
                error: response.error,
                ok: response.ok ?? !response.error,
                response: response.response
            };
            if (normalizedResponse.ok && callbackKey && this.callbacks?.[callbackKey]) {
                const callback = this.callbacks[callbackKey];
                let callbackPayload;
                if ('onConsentBannerFetched' === callbackKey && normalizedResponse.data) {
                    const data = normalizedResponse.data;
                    callbackPayload = {
                        ...normalizedResponse,
                        data: {
                            showConsentBanner: data.showConsentBanner,
                            jurisdiction: data.jurisdiction,
                            location: {
                                countryCode: data.location.countryCode || 'GB',
                                regionCode: data.location.regionCode || null
                            }
                        }
                    };
                } else callbackPayload = 'onConsentSet' === callbackKey && normalizedResponse.data ? {
                    ...normalizedResponse,
                    data: {
                        type: options?.body?.type || 'cookie_banner',
                        preferences: options?.body?.preferences || {},
                        domain: options?.body?.domain
                    }
                } : 'onConsentVerified' === callbackKey && normalizedResponse.data ? {
                    ...normalizedResponse,
                    data: {
                        type: options?.body?.type || 'cookie_banner',
                        preferences: options?.body?.preferences || [],
                        valid: true,
                        domain: options?.body?.domain
                    }
                } : normalizedResponse;
                callback(callbackPayload);
            }
            return normalizedResponse;
        } catch (error) {
            const errorResponse = this.createErrorResponse(error instanceof Error ? error.message : String(error), 0, 'HANDLER_ERROR', error);
            this.callbacks?.onError?.(errorResponse, String(handlerKey));
            if (options?.throw) throw error;
            return errorResponse;
        }
    }
    async showConsentBanner(options) {
        return await this.executeHandler('showConsentBanner', options, 'onConsentBannerFetched');
    }
    async setConsent(options) {
        return await this.executeHandler('setConsent', options, 'onConsentSet');
    }
    async verifyConsent(options) {
        return await this.executeHandler('verifyConsent', options, 'onConsentVerified');
    }
    registerHandler(path, handler) {
        this.dynamicHandlers[path] = handler;
    }
    async $fetch(path, options) {
        const endpointName = path.replace(client_custom_LEADING_SLASHES_REGEX, '').split('/')[0];
        if (path in this.dynamicHandlers) {
            const handler = this.dynamicHandlers[path];
            try {
                return await handler(options);
            } catch (error) {
                const errorResponse = this.createErrorResponse(error instanceof Error ? error.message : String(error), 0, 'HANDLER_ERROR', error);
                this.callbacks?.onError?.(errorResponse, path);
                return errorResponse;
            }
        }
        if (!endpointName || !(endpointName in this.endpointHandlers)) {
            const errorResponse = this.createErrorResponse(`No endpoint handler found for '${path}'`, 404, 'ENDPOINT_NOT_FOUND');
            this.callbacks?.onError?.(errorResponse, path);
            return errorResponse;
        }
        return await this.executeHandler(endpointName, options);
    }
}
const defaultTranslationConfig = {
    translations: {
        en: __WEBPACK_EXTERNAL_MODULE__c15t_translations_cdae900b__.enTranslations
    },
    defaultLanguage: 'en',
    disableAutoLanguageSwitch: false
};
class OfflineClient {
    callbacks;
    constructor(options = {}){
        this.callbacks = options.callbacks;
    }
    getCallbacks() {
        return this.callbacks;
    }
    setCallbacks(callbacks) {
        this.callbacks = callbacks;
    }
    createResponseContext(data = null) {
        return {
            data,
            error: null,
            ok: true,
            response: null
        };
    }
    async handleOfflineResponse(options, callbackKey, callbackPayload) {
        const emptyResponse = this.createResponseContext();
        if (options?.onSuccess) await options.onSuccess(emptyResponse);
        if (callbackKey && this.callbacks?.[callbackKey]) {
            const callback = this.callbacks[callbackKey];
            const payload = callbackPayload ? this.createResponseContext(callbackPayload) : emptyResponse;
            callback(payload);
        }
        return emptyResponse;
    }
    async showConsentBanner(options) {
        let shouldShow = true;
        try {
            if ('undefined' != typeof window && window.localStorage) {
                window.localStorage.setItem('c15t-storage-test-key', 'test');
                window.localStorage.removeItem('c15t-storage-test-key');
                const storedConsent = window.localStorage.getItem('c15t-consent');
                shouldShow = null === storedConsent;
            }
        } catch (error) {
            console.warn('Failed to access localStorage:', error);
            shouldShow = false;
        }
        const response = this.createResponseContext({
            showConsentBanner: shouldShow,
            jurisdiction: {
                code: 'GDPR',
                message: 'EU'
            },
            location: {
                countryCode: 'GB',
                regionCode: null
            },
            translations: {
                language: defaultTranslationConfig.defaultLanguage,
                translations: defaultTranslationConfig.translations[defaultTranslationConfig.defaultLanguage ?? 'en']
            }
        });
        if (this.callbacks?.onConsentBannerFetched && response.data) {
            const callbackPayload = this.createResponseContext({
                showConsentBanner: response.data.showConsentBanner,
                jurisdiction: response.data.jurisdiction,
                location: {
                    countryCode: response.data.location.countryCode || 'GB',
                    regionCode: response.data.location.regionCode || null
                }
            });
            this.callbacks.onConsentBannerFetched(callbackPayload);
        }
        if (options?.onSuccess) await options.onSuccess(response);
        return response;
    }
    async setConsent(options) {
        try {
            if ('undefined' != typeof window && window.localStorage) {
                window.localStorage.setItem('c15t-storage-test-key', 'test');
                window.localStorage.removeItem('c15t-storage-test-key');
                window.localStorage.setItem('c15t-consent', JSON.stringify({
                    timestamp: new Date().toISOString(),
                    preferences: options?.body?.preferences || {}
                }));
            }
        } catch (error) {
            console.warn('Failed to write to localStorage:', error);
        }
        const setConsentCallbackPayload = {
            type: options?.body?.type || 'cookie_banner',
            preferences: options?.body?.preferences || {},
            domain: options?.body?.domain || ''
        };
        return await this.handleOfflineResponse(options, 'onConsentSet', setConsentCallbackPayload);
    }
    async verifyConsent(options) {
        const verifiedCallbackPayload = {
            type: options?.body?.type || 'cookie_banner',
            preferences: options?.body?.preferences || [],
            valid: true,
            domain: options?.body?.domain || ''
        };
        return await this.handleOfflineResponse(options, 'onConsentVerified', verifiedCallbackPayload);
    }
    async $fetch(_path, options) {
        return await this.handleOfflineResponse(options);
    }
}
const DEFAULT_BACKEND_URL = '/api/c15t';
const DEFAULT_CLIENT_MODE = 'c15t';
const clientRegistry = new Map();
function getClientCacheKey(options) {
    if ('offline' === options.mode) return 'offline';
    if ('custom' === options.mode) {
        const handlerKeys = Object.keys(options.endpointHandlers || {}).sort().join(',');
        return `custom:${handlerKeys}`;
    }
    let headersPart = '';
    if ('headers' in options && options.headers) {
        const headerKeys = Object.keys(options.headers).sort();
        headersPart = `:headers:${headerKeys.map((k)=>`${k}=${options.headers?.[k]}`).join(',')}`;
    }
    return `c15t:${options.backendURL || ''}${headersPart}`;
}
function configureConsentManager(options) {
    const cacheKey = getClientCacheKey(options);
    if (clientRegistry.has(cacheKey)) {
        if ('offline' !== options.mode && 'custom' !== options.mode && 'headers' in options && options.headers) {
            const existingClient = clientRegistry.get(cacheKey);
            if (existingClient instanceof C15tClient) existingClient.headers = {
                'Content-Type': 'application/json',
                ...options.headers
            };
        }
        const existingClient = clientRegistry.get(cacheKey);
        if (existingClient) return new Proxy(existingClient, {
            get (target, prop) {
                if ('getCallbacks' === prop) return ()=>options.callbacks;
                return target[prop];
            }
        });
    }
    const mode = options.mode || DEFAULT_CLIENT_MODE;
    let client;
    switch(mode){
        case 'custom':
            {
                const customOptions = options;
                client = new CustomClient({
                    endpointHandlers: customOptions.endpointHandlers,
                    callbacks: customOptions.callbacks
                });
                break;
            }
        case 'offline':
            client = new OfflineClient({
                callbacks: options.callbacks
            });
            break;
        default:
            {
                const c15tOptions = options;
                client = new C15tClient({
                    backendURL: c15tOptions.backendURL || DEFAULT_BACKEND_URL,
                    headers: c15tOptions.headers,
                    customFetch: c15tOptions.customFetch,
                    callbacks: c15tOptions.callbacks,
                    retryConfig: c15tOptions.retryConfig
                });
                break;
            }
    }
    clientRegistry.set(cacheKey, client);
    return client;
}
function getEffectiveConsents(consents, honorDoNotTrack) {
    if (honorDoNotTrack && 'undefined' != typeof window && '1' === window.navigator.doNotTrack) return Object.keys(consents).reduce((acc, key)=>{
        if (key in consents) acc[key] = 'necessary' === key;
        return acc;
    }, {});
    return consents;
}
function hasConsentFor(consentType, consents, honorDoNotTrack) {
    const effectiveConsents = getEffectiveConsents(consents, honorDoNotTrack);
    return effectiveConsents[consentType] || false;
}
function consent_utils_hasConsented(consentInfo) {
    return null !== consentInfo;
}
function checkLocalStorageAccess(set) {
    try {
        if (window.localStorage) {
            window.localStorage.setItem('c15t-storage-test-key', 'test');
            window.localStorage.removeItem('c15t-storage-test-key');
            return true;
        }
    } catch (error) {
        console.warn('localStorage not available, skipping consent banner:', error);
        set({
            isLoadingConsentInfo: false,
            showPopup: false
        });
    }
    return false;
}
function updateStore(data, { set, get, initialTranslationConfig }, hasLocalStorageAccess) {
    const { consentInfo, setDetectedCountry, callbacks, ignoreGeoLocation } = get();
    const { translations, location, jurisdiction, showConsentBanner } = data;
    const updatedStore = {
        isLoadingConsentInfo: false,
        ...null === consentInfo ? {
            showPopup: showConsentBanner && hasLocalStorageAccess || ignoreGeoLocation
        } : {},
        ...'NONE' === data.jurisdiction.code && !data.showConsentBanner && {
            consents: {
                necessary: true,
                functionality: true,
                experience: true,
                marketing: true,
                measurement: true
            }
        },
        locationInfo: {
            countryCode: location?.countryCode ?? '',
            regionCode: location?.regionCode ?? ''
        },
        jurisdictionInfo: jurisdiction
    };
    if (translations) {
        const translationConfig = (0, __WEBPACK_EXTERNAL_MODULE__c15t_translations_cdae900b__.prepareTranslationConfig)({
            translations: {
                [translations.language]: translations.translations
            },
            disableAutoLanguageSwitch: true,
            defaultLanguage: translations.language
        }, initialTranslationConfig);
        updatedStore.translationConfig = translationConfig;
    }
    if (data.location?.countryCode) {
        setDetectedCountry(data.location.countryCode);
        if (data.location.regionCode) callbacks.onLocationDetected?.({
            countryCode: data.location.countryCode,
            regionCode: data.location.regionCode
        });
    }
    set(updatedStore);
}
async function fetchConsentBannerInfo(config) {
    const { get, set, manager, initialData } = config;
    const { hasConsented, callbacks } = get();
    if ('undefined' == typeof window || hasConsented()) return void set({
        isLoadingConsentInfo: false
    });
    const hasLocalStorageAccess = checkLocalStorageAccess(set);
    if (!hasLocalStorageAccess) return;
    set({
        isLoadingConsentInfo: true
    });
    if (initialData) {
        const showConsentBanner = await initialData;
        if (showConsentBanner) {
            set({
                isLoadingConsentInfo: false
            });
            updateStore(showConsentBanner, config, true);
            return showConsentBanner;
        }
    }
    try {
        const { data, error } = await manager.showConsentBanner({
            onError: callbacks.onError ? (context)=>{
                if (callbacks.onError) callbacks.onError(context.error?.message || 'Unknown error');
            } : void 0
        });
        if (error || !data) throw new Error(`Failed to fetch consent banner info: ${error?.message}`);
        updateStore(data, config, hasLocalStorageAccess);
        return data;
    } catch (error) {
        console.error('Error fetching consent banner information:', error);
        set({
            isLoadingConsentInfo: false
        });
        const errorMessage = error instanceof Error ? error.message : 'Unknown error fetching consent banner information';
        callbacks.onError?.(errorMessage);
        set({
            showPopup: false
        });
        return;
    }
}
const DEFAULT_DOMAIN_CONSENT_MAP = {
    'www.google-analytics.com': 'measurement',
    'analytics.google.com': 'measurement',
    'www.googletagmanager.com': 'measurement',
    'stats.g.doubleclick.net': 'measurement',
    'ampcid.google.com': 'measurement',
    'analytics.twitter.com': 'measurement',
    'analytics.pinterest.com': 'measurement',
    'dc.services.visualstudio.com': 'measurement',
    'www.clarity.ms': 'measurement',
    'www.hotjar.com': 'measurement',
    'static.hotjar.com': 'measurement',
    "script.hotjar.com": 'measurement',
    'insights.hotjar.com': 'measurement',
    'mouseflow.com': 'measurement',
    'api.mouseflow.com': 'measurement',
    'tools.mouseflow.com': 'measurement',
    'cdn.heapanalytics.com': 'measurement',
    'plausible.io': 'measurement',
    'matomo.cloud': 'measurement',
    'matomo.org': 'measurement',
    'mixpanel.com': 'measurement',
    'api.mixpanel.com': 'measurement',
    'sentry.io': 'measurement',
    'browser.sentry-cdn.com': 'measurement',
    'js.monitor.azure.com': 'measurement',
    'stats.wp.com': 'measurement',
    'pixel.wp.com': 'measurement',
    'analytics.amplitude.com': 'measurement',
    'api2.amplitude.com': 'measurement',
    'cdn.amplitude.com': 'measurement',
    'api.segment.io': 'measurement',
    'cdn.segment.com': 'measurement',
    'api.segment.com': 'measurement',
    'pendo.io': 'measurement',
    'data.pendo.io': 'measurement',
    'cdn.pendo.io': 'measurement',
    'connect.facebook.net': 'marketing',
    'platform.twitter.com': 'marketing',
    'platform.linkedin.com': 'marketing',
    'www.googleadservices.com': 'marketing',
    'doubleclick.net': 'marketing',
    'googleads.g.doubleclick.net': 'marketing',
    'ad.doubleclick.net': 'marketing',
    'www.facebook.com': 'marketing',
    'ads.linkedin.com': 'marketing',
    'ads-api.tiktok.com': 'marketing',
    'analytics.tiktok.com': 'marketing',
    'business.tiktok.com': 'marketing',
    'ads.pinterest.com': 'marketing',
    'log.pinterest.com': 'marketing',
    'ads-twitter.com': 'marketing',
    'static.ads-twitter.com': 'marketing',
    'advertising.twitter.com': 'marketing',
    'ads.yahoo.com': 'marketing',
    'sp.analytics.yahoo.com': 'marketing',
    'gemini.yahoo.com': 'marketing',
    'adroll.com': 'marketing',
    'a.adroll.com': 'marketing',
    'd.adroll.com': 'marketing',
    's.adroll.com': 'marketing',
    'adform.net': 'marketing',
    'track.adform.net': 'marketing',
    'dmp.adform.net': 'marketing',
    'criteo.com': 'marketing',
    'static.criteo.net': 'marketing',
    'bidder.criteo.com': 'marketing',
    'dynamic.criteo.com': 'marketing',
    'gum.criteo.com': 'marketing',
    'taboola.com': 'marketing',
    'cdn.taboola.com': 'marketing',
    'trc.taboola.com': 'marketing',
    'outbrain.com': 'marketing',
    'widgets.outbrain.com': 'marketing',
    'tr.outbrain.com': 'marketing',
    'amplify.outbrain.com': 'marketing',
    'bing.com': 'marketing',
    'bat.bing.com': 'marketing',
    'clarity.ms': 'marketing',
    'quantserve.com': 'marketing',
    'secure.quantserve.com': 'marketing',
    'pixel.quantserve.com': 'marketing',
    'exelator.com': 'marketing',
    'load.exelator.com': 'marketing',
    'api.exelator.com': 'marketing',
    'ad.360yield.com': 'marketing',
    'match.360yield.com': 'marketing',
    'ad.turn.com': 'marketing',
    'r.turn.com': 'marketing',
    'd.turn.com': 'marketing',
    'cdn.jsdelivr.net': 'functionality',
    'ajax.googleapis.com': 'functionality',
    'fonts.googleapis.com': 'functionality',
    'maps.googleapis.com': 'functionality',
    'www.recaptcha.net': 'functionality',
    'recaptcha.net': 'functionality',
    'www.gstatic.com': 'functionality',
    'fonts.gstatic.com': 'functionality',
    'cdnjs.cloudflare.com': 'functionality',
    'unpkg.com': 'functionality',
    'code.jquery.com': 'functionality',
    'maxcdn.bootstrapcdn.com': 'functionality',
    'cdn.datatables.net': 'functionality',
    'js.stripe.com': 'functionality',
    'api.stripe.com': 'functionality',
    'checkout.stripe.com': 'functionality',
    'js.braintreegateway.com': 'functionality',
    'api.braintreegateway.com': 'functionality',
    'cdn.shopify.com': 'functionality',
    'js.intercomcdn.com': 'functionality',
    'widget.intercom.io': 'functionality',
    'cdn.auth0.com': 'functionality',
    'js.pusher.com': 'functionality',
    'sockjs.pusher.com': 'functionality',
    'app.optimizely.com': 'experience',
    'cdn.optimizely.com': 'experience',
    'logx.optimizely.com': 'experience',
    'cdn.mouseflow.com': 'experience',
    'fullstory.com': 'experience',
    'rs.fullstory.com': 'experience',
    'edge.fullstory.com': 'experience',
    'vwo.com': 'experience',
    'dev.visualwebsiteoptimizer.com': 'experience',
    'assets.adobedtm.com': 'experience',
    'cdn.tt.omtrdc.net': 'experience',
    'demdex.net': 'experience',
    'sc.omtrdc.net': 'experience',
    'crazyegg.com': 'experience',
    "script.crazyegg.com": 'experience',
    'tracking.crazyegg.com': 'experience',
    'luckyorange.com': 'experience',
    'cdn.luckyorange.com': 'experience',
    'w1.luckyorange.com': 'experience',
    'upload.luckyorange.com': 'experience',
    'clicktale.net': 'experience',
    'cdn.clicktale.net': 'experience',
    'conductor.clicktale.net': 'experience',
    'userzoom.com': 'experience',
    'cdn.userzoom.com': 'experience',
    'api.userzoom.com': 'experience',
    'contentsquare.net': 'experience',
    't.contentsquare.net': 'experience',
    'app.contentsquare.com': 'experience'
};
const tracking_domains = DEFAULT_DOMAIN_CONSENT_MAP;
function createDefaultConsentState() {
    return {
        experience: false,
        functionality: false,
        marketing: false,
        measurement: false,
        necessary: true
    };
}
const WWW_PREFIX_REGEX = /^www\./;
const PORT_NUMBER_REGEX = /:\d+$/;
function createTrackingBlocker(config = {}, initialConsents) {
    const blockerConfig = {
        disableAutomaticBlocking: false,
        ...config,
        domainConsentMap: config.overrideDomainConsentMap ? config.domainConsentMap : {
            ...tracking_domains,
            ...config.domainConsentMap
        }
    };
    let consents = initialConsents || createDefaultConsentState();
    const originalFetch = window.fetch;
    const originalXHR = window.XMLHttpRequest;
    function normalizeDomain(domain) {
        return domain.toLowerCase().replace(WWW_PREFIX_REGEX, '').replace(PORT_NUMBER_REGEX, '').trim();
    }
    function findMatchingDomain(domain, domainMap) {
        const normalizedDomain = normalizeDomain(domain);
        const directMatch = domainMap[normalizedDomain];
        if (directMatch) return directMatch;
        for (const [mapDomain, consent] of Object.entries(domainMap)){
            const normalizedMapDomain = normalizeDomain(mapDomain);
            if (normalizedDomain.endsWith(`.${normalizedMapDomain}`) || normalizedDomain === normalizedMapDomain) return consent;
        }
    }
    function isRequestAllowed(url) {
        try {
            const domain = new URL(url).hostname;
            const requiredConsent = findMatchingDomain(domain, blockerConfig.domainConsentMap || {});
            if (!requiredConsent) return true;
            const isAllowed = true === consents[requiredConsent];
            return isAllowed;
        } catch  {
            return true;
        }
    }
    function dispatchConsentBlockedEvent(url) {
        document.dispatchEvent(new CustomEvent('ConsentBlockedRequest', {
            detail: {
                url
            }
        }));
    }
    function interceptNetworkRequests() {
        if (window.fetch === originalFetch) window.fetch = async (input, init)=>{
            const url = input instanceof Request ? input.url : input.toString();
            if (!isRequestAllowed(url)) {
                dispatchConsentBlockedEvent(url);
                return Promise.reject(new Error(`Request to ${url} blocked due to missing consent`));
            }
            return await originalFetch.call(window, input, init);
        };
        if (window.XMLHttpRequest === originalXHR) window.XMLHttpRequest = class extends originalXHR {
            open(method, url, async = true, username, password) {
                if (!isRequestAllowed(url.toString())) {
                    dispatchConsentBlockedEvent(url.toString());
                    throw new Error(`Request to ${url} blocked due to missing consent`);
                }
                super.open(method, url, async, username, password);
            }
        };
    }
    function restoreOriginalRequests() {
        if (window.fetch !== originalFetch) window.fetch = originalFetch;
        if (window.XMLHttpRequest !== originalXHR) window.XMLHttpRequest = originalXHR;
    }
    if (!blockerConfig.disableAutomaticBlocking) interceptNetworkRequests();
    return {
        updateConsents: (newConsents)=>{
            consents = {
                ...consents,
                ...newConsents
            };
        },
        destroy: ()=>{
            restoreOriginalRequests();
        }
    };
}
const version = '1.5.0';
const initialState = {
    config: {
        pkg: 'c15t',
        version: version,
        mode: 'Unknown'
    },
    consents: gdpr_consentTypes.reduce((acc, consent)=>{
        acc[consent.name] = consent.defaultValue;
        return acc;
    }, {}),
    consentInfo: null,
    showPopup: true,
    isLoadingConsentInfo: false,
    gdprTypes: [
        'necessary',
        'marketing'
    ],
    isPrivacyDialogOpen: false,
    isConsentDomain: false,
    complianceSettings: {
        gdpr: {
            enabled: true,
            appliesGlobally: true,
            applies: true
        },
        ccpa: {
            enabled: true,
            appliesGlobally: false,
            applies: void 0
        },
        lgpd: {
            enabled: false,
            appliesGlobally: false,
            applies: void 0
        },
        usStatePrivacy: {
            enabled: true,
            appliesGlobally: false,
            applies: void 0
        }
    },
    callbacks: {},
    detectedCountry: null,
    locationInfo: null,
    jurisdictionInfo: null,
    privacySettings: {
        honorDoNotTrack: true
    },
    translationConfig: defaultTranslationConfig,
    includeNonDisplayedConsents: false,
    consentTypes: gdpr_consentTypes,
    ignoreGeoLocation: false,
    setConsent: ()=>{},
    setShowPopup: ()=>{},
    setIsPrivacyDialogOpen: ()=>{},
    saveConsents: ()=>{},
    resetConsents: ()=>{},
    setGdprTypes: ()=>{},
    setComplianceSetting: ()=>{},
    resetComplianceSettings: ()=>{},
    setCallback: ()=>{},
    setDetectedCountry: ()=>{},
    setLocationInfo: ()=>{},
    getDisplayedConsents: ()=>[],
    hasConsented: ()=>false,
    setTranslationConfig: ()=>{}
};
const DEFAULT_GTM_CONSENT_CONFIG = {
    functionality_storage: 'denied',
    security_storage: 'denied',
    analytics_storage: 'denied',
    ad_storage: 'denied',
    ad_user_data: 'denied',
    ad_personalization: 'denied',
    personalization_storage: 'denied'
};
const CONSENT_STATE_TO_GTM_MAPPING = {
    necessary: [
        'security_storage'
    ],
    functionality: [
        'functionality_storage'
    ],
    measurement: [
        'analytics_storage'
    ],
    marketing: [
        'ad_storage',
        'ad_user_data',
        'ad_personalization'
    ],
    experience: [
        'personalization_storage'
    ]
};
function mapConsentStateToGTM(consentState) {
    const gtmConfig = {
        ...DEFAULT_GTM_CONSENT_CONFIG
    };
    for (const consentType of Object.keys(consentState)){
        const isGranted = consentState[consentType];
        const gtmConsentTypes = CONSENT_STATE_TO_GTM_MAPPING[consentType];
        for (const gtmType of gtmConsentTypes)gtmConfig[gtmType] = isGranted ? 'granted' : 'denied';
    }
    return gtmConfig;
}
function initializeGTMDataLayer(gtm) {
    const gtmConsent = gtm.consentState ? mapConsentStateToGTM(gtm.consentState) : DEFAULT_GTM_CONSENT_CONFIG;
    const gtmSetupScript = document.createElement("script");
    gtmSetupScript.textContent = `
    window.dataLayer = window.dataLayer || [];
    window.gtag = function gtag() {
      window.dataLayer.push(arguments);
    };
    window.gtag('consent', 'default', {
      ...${JSON.stringify(gtmConsent)},
    });
    window.dataLayer.push({
      'gtm.start': Date.now(),
      event: 'gtm.js',
    });
  `;
    if (!document.head) throw new Error("Document head is not available for script injection");
    document.head.appendChild(gtmSetupScript);
}
function createGTMScript(gtm) {
    const gtmScript = document.createElement("script");
    gtmScript.async = true;
    gtmScript.src = gtm.customScriptUrl ? gtm.customScriptUrl : `https://www.googletagmanager.com/gtm.js?id=${gtm.id}`;
    if (!document.head) throw new Error("Document head is not available for script injection");
    document.head.appendChild(gtmScript);
}
function setupGTM(gtm) {
    const id = gtm.id;
    if (!id || 0 === id.trim().length) throw new Error('GTM container ID is required and must be a non-empty string');
    if ('undefined' == typeof window || 'undefined' == typeof document) return;
    initializeGTMDataLayer(gtm);
    createGTMScript(gtm);
}
function updateGTMConsent(consentState) {
    if (!window.gtag) return;
    window.gtag('consent', 'update', mapConsentStateToGTM(consentState));
}
const STORAGE_KEY = 'privacy-consent-storage';
const getStoredConsent = ()=>{
    if ('undefined' == typeof window) return null;
    const stored = localStorage.getItem(STORAGE_KEY);
    if (!stored) return null;
    try {
        return JSON.parse(stored);
    } catch (e) {
        console.error('Failed to parse stored consent:', e);
        return null;
    }
};
const createConsentManagerStore = (manager, options = {})=>{
    const { namespace = 'c15tStore', trackingBlockerConfig, isConsentDomain = false, translationConfig } = options;
    const storedConsent = getStoredConsent();
    const trackingBlocker = 'undefined' != typeof window ? createTrackingBlocker(trackingBlockerConfig || {}, storedConsent?.consents || initialState.consents) : null;
    const clientCallbacks = manager.getCallbacks();
    const mergedCallbacks = clientCallbacks ? {
        onError: clientCallbacks.onError ? (message)=>clientCallbacks.onError?.({
                data: null,
                error: {
                    message,
                    status: 0
                },
                ok: false,
                response: null
            }, 'store') : void 0,
        ...initialState.callbacks
    } : initialState.callbacks;
    const store = (0, __WEBPACK_EXTERNAL_MODULE_zustand_vanilla_8a8e4ffb__.createStore)((set, get)=>({
            ...initialState,
            ignoreGeoLocation: options.ignoreGeoLocation ?? false,
            config: options.config ?? initialState.config,
            isConsentDomain,
            callbacks: mergedCallbacks,
            translationConfig: translationConfig || initialState.translationConfig,
            ...storedConsent ? {
                consents: storedConsent.consents,
                consentInfo: storedConsent.consentInfo,
                showPopup: false,
                isLoadingConsentInfo: false
            } : {
                showPopup: false,
                isLoadingConsentInfo: true
            },
            setConsent: (name, value)=>{
                set((state)=>{
                    const consentType = state.consentTypes.find((type)=>type.name === name);
                    if (consentType?.disabled) return state;
                    const newConsents = {
                        ...state.consents,
                        [name]: value
                    };
                    trackingBlocker?.updateConsents(newConsents);
                    updateGTMConsent(newConsents);
                    return {
                        consents: newConsents
                    };
                });
            },
            setShowPopup: (show, force = false)=>{
                if (!show) return void set({
                    showPopup: false
                });
                const state = get();
                const storedConsent = getStoredConsent();
                if (force || !storedConsent && !state.consentInfo && !state.isLoadingConsentInfo) set({
                    showPopup: true
                });
            },
            setIsPrivacyDialogOpen: (isOpen)=>{
                set({
                    isPrivacyDialogOpen: isOpen
                });
                if (!isOpen) queueMicrotask(()=>{});
            },
            saveConsents: async (type)=>{
                const { callbacks, consents, consentTypes } = get();
                const newConsents = {
                    ...consents
                };
                if ('all' === type) for (const consent of consentTypes)newConsents[consent.name] = true;
                else if ('necessary' === type) for (const consent of consentTypes)newConsents[consent.name] = 'necessary' === consent.name;
                const consentInfo = {
                    time: Date.now(),
                    type: type
                };
                set({
                    consents: newConsents,
                    showPopup: false,
                    consentInfo
                });
                trackingBlocker?.updateConsents(newConsents);
                updateGTMConsent(newConsents);
                try {
                    localStorage.setItem(STORAGE_KEY, JSON.stringify({
                        consents: newConsents,
                        consentInfo
                    }));
                } catch (e) {
                    console.warn('Failed to persist consents to localStorage:', e);
                }
                callbacks.onConsentGiven?.();
                callbacks.onPreferenceExpressed?.();
                const consent = await manager.setConsent({
                    body: {
                        type: 'cookie_banner',
                        domain: window.location.hostname,
                        preferences: newConsents,
                        metadata: {
                            source: 'consent_widget',
                            acceptanceMethod: type
                        }
                    }
                });
                if (!consent.ok) {
                    const errorMsg = consent.error?.message ?? 'Failed to save consents';
                    callbacks.onError?.(errorMsg);
                    if (!callbacks.onError) console.error(errorMsg);
                }
            },
            resetConsents: ()=>{
                set(()=>{
                    const resetState = {
                        consents: gdpr_consentTypes.reduce((acc, consent)=>{
                            acc[consent.name] = consent.defaultValue;
                            return acc;
                        }, {}),
                        consentInfo: null
                    };
                    localStorage.removeItem(STORAGE_KEY);
                    return resetState;
                });
            },
            setGdprTypes: (types)=>set({
                    gdprTypes: types
                }),
            setComplianceSetting: (region, settings)=>set((state)=>({
                        complianceSettings: {
                            ...state.complianceSettings,
                            [region]: {
                                ...state.complianceSettings[region],
                                ...settings
                            }
                        }
                    })),
            resetComplianceSettings: ()=>set({
                    complianceSettings: initialState.complianceSettings
                }),
            setCallback: (name, callback)=>set((state)=>({
                        callbacks: {
                            ...state.callbacks,
                            [name]: callback
                        }
                    })),
            setDetectedCountry: (country)=>set({
                    detectedCountry: country
                }),
            setLocationInfo: (location)=>set({
                    locationInfo: location
                }),
            fetchConsentBannerInfo: ()=>fetchConsentBannerInfo({
                    manager,
                    initialData: options._initialData,
                    initialTranslationConfig: options.initialTranslationConfig,
                    get,
                    set
                }),
            getDisplayedConsents: ()=>{
                const { gdprTypes, consentTypes } = get();
                return consentTypes.filter((consent)=>gdprTypes.includes(consent.name));
            },
            hasConsented: ()=>{
                const { consentInfo } = get();
                return consent_utils_hasConsented(consentInfo);
            },
            getEffectiveConsents: ()=>{
                const { consents, privacySettings } = get();
                return getEffectiveConsents(consents, privacySettings.honorDoNotTrack);
            },
            hasConsentFor: (consentType)=>{
                const { consents, privacySettings } = get();
                return hasConsentFor(consentType, consents, privacySettings.honorDoNotTrack);
            },
            setTranslationConfig: (config)=>{
                set({
                    translationConfig: config
                });
            }
        }));
    if ('undefined' != typeof window) {
        window[namespace] = store;
        if (options.unstable_googleTagManager) try {
            setupGTM({
                ...options.unstable_googleTagManager,
                consentState: store.getState().consents
            });
        } catch (e) {
            console.error('Failed to setup Google Tag Manager:', e);
        }
        if (!getStoredConsent()) store.getState().fetchConsentBannerInfo();
    }
    return store;
};
var __webpack_exports__deepMergeTranslations = __WEBPACK_EXTERNAL_MODULE__c15t_translations_cdae900b__.deepMergeTranslations;
var __webpack_exports__detectBrowserLanguage = __WEBPACK_EXTERNAL_MODULE__c15t_translations_cdae900b__.detectBrowserLanguage;
var __webpack_exports__mergeTranslationConfigs = __WEBPACK_EXTERNAL_MODULE__c15t_translations_cdae900b__.mergeTranslationConfigs;
var __webpack_exports__prepareTranslationConfig = __WEBPACK_EXTERNAL_MODULE__c15t_translations_cdae900b__.prepareTranslationConfig;
export { API_ENDPOINTS, C15tClient, CustomClient, OfflineClient, configureConsentManager, gdpr_consentTypes as consentTypes, createConsentManagerStore, createTrackingBlocker, defaultTranslationConfig, __webpack_exports__deepMergeTranslations as deepMergeTranslations, __webpack_exports__detectBrowserLanguage as detectBrowserLanguage, __webpack_exports__mergeTranslationConfigs as mergeTranslationConfigs, __webpack_exports__prepareTranslationConfig as prepareTranslationConfig };