@easy-cookie/policy 0.0.0-stage → 0.1.1
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.
- package/LICENSE +21 -0
- package/README.md +182 -2
- package/dist/chunk-HDY2VYU4.js +23 -0
- package/dist/chunk-HDY2VYU4.js.map +1 -0
- package/dist/chunk-P3F5NQPR.js +224 -0
- package/dist/chunk-P3F5NQPR.js.map +1 -0
- package/dist/client.cjs +50 -0
- package/dist/client.cjs.map +1 -0
- package/dist/client.d.cts +51 -0
- package/dist/client.d.ts +51 -0
- package/dist/client.js +13 -0
- package/dist/client.js.map +1 -0
- package/dist/easy-cookie-legal.css +129 -0
- package/dist/index.cjs +1091 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +91 -0
- package/dist/index.d.ts +91 -0
- package/dist/index.js +820 -0
- package/dist/index.js.map +1 -0
- package/dist/legal-document.cjs +72 -0
- package/dist/legal-document.cjs.map +1 -0
- package/dist/legal-document.js +48 -0
- package/dist/legal-document.js.map +1 -0
- package/dist/react.cjs +219 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.d.cts +49 -0
- package/dist/react.d.ts +49 -0
- package/dist/react.js +80 -0
- package/dist/react.js.map +1 -0
- package/dist/render-DYrvn1cT.d.cts +115 -0
- package/dist/render-DYrvn1cT.d.ts +115 -0
- package/package.json +75 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/model.ts","../src/render.ts","../src/legal.ts","../src/legal-client.ts","../src/templates/cookie.ts","../src/templates/privacy.ts","../src/templates/terms.ts","../src/templates/index.ts"],"sourcesContent":["export {\n POLICY_LABELS,\n autoClearRules,\n buildPolicyModel,\n formatPolicyDate,\n matchesRule,\n prettyCookiePattern,\n type AutoClearRule,\n type BuildPolicyOptions,\n type PolicyCategory,\n type PolicyCookie,\n type PolicyLabels,\n type PolicyModel,\n type PolicyService,\n} from './model';\nexport { escapeHtml, policyRows, renderPolicyHtml, renderPolicyMarkdown, type PolicyRow, type RenderPolicyOptions } from './render';\nexport {\n LEGAL_KINDS,\n LEGAL_LABELS,\n PLACEHOLDER_RE,\n countPlaceholders,\n fetchLegalDocument,\n fillSiteVariables,\n isLegalKind,\n isSafeLegalUrl,\n legalContentError,\n legalDocumentUrl,\n pickLegalLanguage,\n renderLegalDocument,\n type FetchLegalDocumentOptions,\n type LegalDocContent,\n type LegalKind,\n type LegalLabels,\n type LegalTranslation,\n type PublishedLegalDocument,\n type RenderLegalOptions,\n type RenderedLegalDocument,\n} from './legal';\nexport { LEGAL_TEMPLATES, LEGAL_TEMPLATE_LANGUAGES, legalTemplate } from './templates';\n","import { localize, resolveConfig, type EasyCookieConfig } from '@easy-cookie/core/shared';\n\nexport interface PolicyLabels {\n cookie: string;\n service: string;\n provider: string;\n duration: string;\n purpose: string;\n /** Prefix of the \"last updated\" line. */\n updated: string;\n revision: string;\n alwaysOn: string;\n privacyPolicy: string;\n /** Shown in a category without services. */\n noCookies: string;\n /** Shown in the cookie column for a service that sets no cookies. */\n noCookie: string;\n /** Table caption: `{category}` is replaced with the category title. */\n caption: string;\n}\n\n/** Built-in table headers and labels. Unknown languages fall back to English. */\nexport const POLICY_LABELS: Record<'it' | 'en', PolicyLabels> = {\n it: {\n cookie: 'Cookie',\n service: 'Servizio',\n provider: 'Fornitore',\n duration: 'Durata',\n purpose: 'Finalità',\n updated: 'Ultimo aggiornamento',\n revision: 'Revisione',\n alwaysOn: 'Sempre attivi',\n privacyPolicy: 'Privacy policy',\n noCookies: 'Nessun cookie dichiarato in questa categoria.',\n noCookie: '—',\n caption: 'Cookie della categoria «{category}»',\n },\n en: {\n cookie: 'Cookie',\n service: 'Service',\n provider: 'Provider',\n duration: 'Duration',\n purpose: 'Purpose',\n updated: 'Last updated',\n revision: 'Revision',\n alwaysOn: 'Always on',\n privacyPolicy: 'Privacy policy',\n noCookies: 'No cookies declared in this category.',\n noCookie: '—',\n caption: 'Cookies in the “{category}” category',\n },\n};\n\nexport interface PolicyCookie {\n /** Name as declared (a regular expression source when `pattern` is true). */\n name: string;\n /** Human-friendly name: anchors stripped, `.*` shown as `*` for patterns. */\n displayName: string;\n pattern: boolean;\n duration: string;\n description: string;\n domain?: string;\n}\n\nexport interface PolicyService {\n id: string;\n label: string;\n provider: string;\n privacyUrl?: string;\n purpose: string;\n cookies: PolicyCookie[];\n}\n\nexport interface PolicyCategory {\n id: string;\n title: string;\n description: string;\n readOnly: boolean;\n color: string;\n services: PolicyService[];\n}\n\nexport interface PolicyModel {\n lang: string;\n revision: string;\n /** ISO date (YYYY-MM-DD) of the revision, when known. */\n date?: string;\n policyUrl?: string;\n labels: PolicyLabels;\n categories: PolicyCategory[];\n}\n\nexport interface BuildPolicyOptions {\n /** Date of this revision (ISO). Defaults to the revision itself when it starts with YYYY-MM-DD. */\n date?: string | Date;\n /** Override some labels. */\n labels?: Partial<PolicyLabels>;\n}\n\n/** Make a cookie-name regular expression readable: `^_ga_.*$` → `_ga_*`. */\nexport function prettyCookiePattern(source: string): string {\n return source\n .replace(/^\\^/, '')\n .replace(/\\$$/, '')\n .replace(/\\(([^()]*)\\)\\?/g, '[$1]')\n .replace(/\\.\\*|\\.\\+|\\[\\^[^\\]]*\\]\\*|\\\\d\\+|\\\\w\\+/g, '*')\n .replace(/\\\\(.)/g, '$1');\n}\n\nfunction isoDate(value: string | Date | undefined, revision: string): string | undefined {\n if (value instanceof Date) return Number.isNaN(value.getTime()) ? undefined : value.toISOString().slice(0, 10);\n if (typeof value === 'string') return value.slice(0, 10);\n const m = /^\\d{4}-\\d{2}-\\d{2}/.exec(revision);\n return m ? m[0] : undefined;\n}\n\n/**\n * Turn the config into a localized, render-agnostic cookie policy model:\n * categories → services → cookies. Pure and DOM-free.\n */\nexport function buildPolicyModel(config: EasyCookieConfig, lang: string, opts: BuildPolicyOptions = {}): PolicyModel {\n const resolved = resolveConfig(config);\n const fallback = resolved.language.default;\n const l = (v: Parameters<typeof localize>[0]) => localize(v, lang, fallback);\n const labels = { ...((POLICY_LABELS as Record<string, PolicyLabels>)[lang] ?? POLICY_LABELS.en), ...opts.labels };\n const services = config.services ?? {};\n\n return {\n lang,\n revision: config.revision,\n date: isoDate(opts.date, config.revision),\n policyUrl: config.policyUrl ? l(config.policyUrl) : undefined,\n labels,\n categories: resolved.resolvedCategories.map((cat) => ({\n id: cat.id,\n title: l(cat.title),\n description: l(cat.description),\n readOnly: cat.readOnly,\n color: cat.color,\n services: cat.services.map((id) => {\n const s = services[id];\n return {\n id,\n label: s.label ? l(s.label) : id,\n provider: s.provider ?? '',\n privacyUrl: s.privacyUrl,\n purpose: l(s.purpose),\n cookies: (s.cookies ?? []).map((ck) => ({\n name: ck.name,\n displayName: ck.pattern ? prettyCookiePattern(ck.name) : ck.name,\n pattern: !!ck.pattern,\n duration: l(ck.duration),\n description: l(ck.description),\n domain: ck.domain,\n })),\n };\n }),\n })),\n };\n}\n\n/** Format the model date for display, e.g. \"13 novembre 2026\" / \"November 13, 2026\". */\nexport function formatPolicyDate(model: Pick<PolicyModel, 'date' | 'lang'>): string | undefined {\n if (!model.date) return undefined;\n const d = new Date(`${model.date}T00:00:00Z`);\n if (Number.isNaN(d.getTime())) return model.date;\n try {\n return new Intl.DateTimeFormat(model.lang, { dateStyle: 'long', timeZone: 'UTC' }).format(d);\n } catch {\n return model.date;\n }\n}\n\nexport interface AutoClearRule {\n /** Cookie name, or a regular expression source when `pattern` is true. */\n name: string;\n pattern: boolean;\n domain?: string;\n service: string;\n}\n\n/**\n * Cookies to delete when a category is withdrawn, per category id.\n * Read-only (necessary) categories are omitted: they cannot be withdrawn.\n */\nexport function autoClearRules(config: EasyCookieConfig): Record<string, AutoClearRule[]> {\n const out: Record<string, AutoClearRule[]> = {};\n for (const [id, cat] of Object.entries(config.categories)) if (!cat.readOnly) out[id] = [];\n for (const [service, s] of Object.entries(config.services ?? {})) {\n const list = out[s.category];\n if (!list) continue;\n for (const ck of s.cookies ?? [])\n list.push({ name: ck.name, pattern: !!ck.pattern, ...(ck.domain ? { domain: ck.domain } : {}), service });\n }\n return out;\n}\n\n/** True when `cookieName` matches the rule. */\nexport function matchesRule(rule: Pick<AutoClearRule, 'name' | 'pattern'>, cookieName: string): boolean {\n if (!rule.pattern) return rule.name === cookieName;\n try {\n return new RegExp(rule.name).test(cookieName);\n } catch {\n return false;\n }\n}\n","import { formatPolicyDate, type PolicyCategory, type PolicyModel, type PolicyService } from './model';\n\nexport interface RenderPolicyOptions {\n /** Heading level of category titles (2 → `<h2>`). Default 2. */\n headingLevel?: 2 | 3 | 4 | 5 | 6;\n /** Prefix for section ids (`#ec-policy-measurement`). Default `ec-policy-`. */\n idPrefix?: string;\n /** Show the \"last updated / revision\" line. Default true. */\n meta?: boolean;\n /** Omit categories without services. Default false. */\n hideEmpty?: boolean;\n}\n\nconst ESC: Record<string, string> = { '&': '&', '<': '<', '>': '>', '\"': '"', \"'\": ''' };\nexport function escapeHtml(value: string): string {\n return value.replace(/[&<>\"']/g, (c) => ESC[c]);\n}\n\nfunction safeUrl(url: string): string | undefined {\n return /^(https?:|mailto:|\\/|#)/i.test(url.trim()) ? url : undefined;\n}\n\nexport interface PolicyRow {\n service: PolicyService;\n cookie?: PolicyService['cookies'][number];\n /** First row of this service (for grouping). */\n first: boolean;\n}\n\n/** Flatten a category to table rows: one per cookie, or one per service without cookies. */\nexport function policyRows(cat: PolicyCategory): PolicyRow[] {\n const rows: PolicyRow[] = [];\n for (const service of cat.services) {\n if (service.cookies.length === 0) rows.push({ service, first: true });\n else service.cookies.forEach((cookie, i) => rows.push({ service, cookie, first: i === 0 }));\n }\n return rows;\n}\n\nfunction visible(model: PolicyModel, opts: RenderPolicyOptions): PolicyCategory[] {\n return opts.hideEmpty ? model.categories.filter((c) => c.services.length > 0) : model.categories;\n}\n\n/**\n * Semantic HTML for the cookie section of a policy: one `<section>` and one\n * `<table>` per category. Class names only (`ec-policy*`), no inline styles.\n */\nexport function renderPolicyHtml(model: PolicyModel, opts: RenderPolicyOptions = {}): string {\n const h = `h${opts.headingLevel ?? 2}`;\n const prefix = opts.idPrefix ?? 'ec-policy-';\n const L = model.labels;\n const e = escapeHtml;\n const out: string[] = [`<div class=\"ec-policy\" lang=\"${e(model.lang)}\">`];\n\n if (opts.meta !== false) {\n const parts: string[] = [];\n const date = formatPolicyDate(model);\n if (date) parts.push(`${e(L.updated)}: <time datetime=\"${e(model.date!)}\">${e(date)}</time>`);\n parts.push(`${e(L.revision)}: <span class=\"ec-policy__revision\">${e(model.revision)}</span>`);\n out.push(`<p class=\"ec-policy__meta\">${parts.join(' · ')}</p>`);\n }\n\n for (const cat of visible(model, opts)) {\n const id = `${prefix}${cat.id}`;\n out.push(\n `<section class=\"ec-policy__category\" id=\"${e(id)}\" data-category=\"${e(cat.id)}\" aria-labelledby=\"${e(id)}-title\">`,\n );\n out.push(`<${h} class=\"ec-policy__title\" id=\"${e(id)}-title\">${e(cat.title)}</${h}>`);\n if (cat.readOnly) out.push(`<p class=\"ec-policy__badge\">${e(L.alwaysOn)}</p>`);\n if (cat.description) out.push(`<p class=\"ec-policy__description\">${e(cat.description)}</p>`);\n\n const rows = policyRows(cat);\n if (rows.length === 0) {\n out.push(`<p class=\"ec-policy__empty\">${e(L.noCookies)}</p>`);\n } else {\n out.push('<div class=\"ec-policy__table-wrap\">');\n out.push('<table class=\"ec-policy__table\">');\n out.push(`<caption class=\"ec-policy__caption\">${e(L.caption.replace('{category}', cat.title))}</caption>`);\n out.push(\n '<thead><tr>' +\n [L.cookie, L.service, L.provider, L.duration, L.purpose].map((t) => `<th scope=\"col\">${e(t)}</th>`).join('') +\n '</tr></thead>',\n );\n out.push('<tbody>');\n for (const { service, cookie } of rows) {\n const name = cookie\n ? `<code class=\"ec-policy__cookie\"${cookie.pattern ? ` title=\"${e(cookie.name)}\"` : ''}>${e(cookie.displayName)}</code>` +\n (cookie.domain ? ` <span class=\"ec-policy__domain\">${e(cookie.domain)}</span>` : '')\n : `<span class=\"ec-policy__none\">${e(L.noCookie)}</span>`;\n const url = service.privacyUrl ? safeUrl(service.privacyUrl) : undefined;\n const provider = url\n ? `<a class=\"ec-policy__link\" href=\"${e(url)}\" rel=\"noopener noreferrer\" target=\"_blank\">${e(service.provider || L.privacyPolicy)}</a>`\n : e(service.provider);\n const purpose = cookie?.description || service.purpose;\n out.push(\n `<tr data-service=\"${e(service.id)}\">` +\n `<th scope=\"row\">${name}</th>` +\n `<td class=\"ec-policy__service\">${e(service.label)}</td>` +\n `<td class=\"ec-policy__provider\">${provider}</td>` +\n `<td class=\"ec-policy__duration\">${e(cookie?.duration ?? '')}</td>` +\n `<td class=\"ec-policy__purpose\">${e(purpose)}</td>` +\n '</tr>',\n );\n }\n out.push('</tbody></table></div>');\n }\n out.push('</section>');\n }\n out.push('</div>');\n return out.join('\\n');\n}\n\nfunction mdCell(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/\\|/g, '\\\\|').replace(/\\r?\\n/g, ' ');\n}\n\n/** GitHub-flavoured Markdown version of the policy (one table per category). */\nexport function renderPolicyMarkdown(model: PolicyModel, opts: Pick<RenderPolicyOptions, 'headingLevel' | 'meta' | 'hideEmpty'> = {}): string {\n const hashes = '#'.repeat(opts.headingLevel ?? 2);\n const L = model.labels;\n const out: string[] = [];\n if (opts.meta !== false) {\n const date = formatPolicyDate(model);\n out.push([date ? `${L.updated}: ${date}` : '', `${L.revision}: ${model.revision}`].filter(Boolean).join(' · '), '');\n }\n for (const cat of visible(model, opts)) {\n out.push(`${hashes} ${cat.title}`, '');\n if (cat.readOnly) out.push(`*${L.alwaysOn}*`, '');\n if (cat.description) out.push(cat.description, '');\n const rows = policyRows(cat);\n if (rows.length === 0) {\n out.push(L.noCookies, '');\n continue;\n }\n out.push(`| ${[L.cookie, L.service, L.provider, L.duration, L.purpose].map(mdCell).join(' | ')} |`);\n out.push('| --- | --- | --- | --- | --- |');\n for (const { service, cookie } of rows) {\n const name = cookie ? `\\`${cookie.displayName.replace(/`/g, '')}\\`` : L.noCookie;\n const provider = service.privacyUrl\n ? `[${mdCell(service.provider || L.privacyPolicy).replace(/[[\\]]/g, '\\\\$&')}](${service.privacyUrl.replace(/[()\\s]/g, encodeURIComponent)})`\n : mdCell(service.provider);\n out.push(\n `| ${name} | ${mdCell(service.label)} | ${provider} | ${mdCell(cookie?.duration ?? '')} | ${mdCell(cookie?.description || service.purpose)} |`,\n );\n }\n out.push('');\n }\n return out.join('\\n').trimEnd() + '\\n';\n}\n","import { findCatalogEntry } from '@easy-cookie/core/catalog';\nimport { localize, resolveConfig, type EasyCookieConfig } from '@easy-cookie/core/shared';\nimport MarkdownIt from 'markdown-it';\nimport { buildPolicyModel } from './model';\nimport { escapeHtml, renderPolicyHtml } from './render';\nimport type { LegalDocContent } from './legal-client';\n\nexport * from './legal-client';\n\nexport interface RenderLegalOptions {\n /**\n * Banner config used to expand `{{cookie-table}}` and `{{services-list}}`\n * (the published one for visitors, the draft one for previews). Without it\n * those directives render a short notice.\n */\n config?: EasyCookieConfig | null;\n /** Version id being shown (written as `data-version`). */\n version?: string;\n /** Publication date for `{{last-updated}}`. Defaults to now (previews). */\n publishedAt?: string | Date;\n /** Values for `{{site.name}}` / `{{site.domain}}` left in the text. */\n site?: { name?: string; domain?: string };\n /** Put the title in an `<h1 class=\"ec-legal__title\">` at the top of the HTML. Default true. */\n heading?: boolean;\n /**\n * Where `{{preferences-link}}` points when the banner is not on the page\n * (e.g. the consent server's hosted page links back to the site). By default\n * it is `href=\"#\" data-ec-open-preferences`, bound by the core runtime.\n */\n preferencesHref?: string;\n}\n\nexport interface RenderedLegalDocument {\n /** Language actually rendered (after fallback). */\n lang: string;\n title: string;\n html: string;\n}\n\nexport interface LegalLabels {\n updated: string;\n preferences: string;\n privacyPolicy: string;\n category: string;\n transfer: string;\n noServices: string;\n noConfig: string;\n}\n\n/** Visitor-facing strings used by the directives. Unknown languages fall back to English. */\nexport const LEGAL_LABELS: Record<'it' | 'en', LegalLabels> = {\n it: {\n updated: 'Ultimo aggiornamento',\n preferences: 'Modifica le preferenze sui cookie',\n privacyPolicy: 'Informativa privacy',\n category: 'Categoria',\n transfer: 'Trasferimento dei dati',\n noServices: 'Nessun servizio di terze parti dichiarato.',\n noConfig: 'L’elenco dei cookie sarà disponibile dopo la pubblicazione del banner.',\n },\n en: {\n updated: 'Last updated',\n preferences: 'Change your cookie preferences',\n privacyPolicy: 'Privacy policy',\n category: 'Category',\n transfer: 'Data transfer',\n noServices: 'No third-party services declared.',\n noConfig: 'The list of cookies will be available once the banner is published.',\n },\n};\n\nconst labelsFor = (lang: string): LegalLabels => (LEGAL_LABELS as Record<string, LegalLabels>)[lang] ?? LEGAL_LABELS.en;\n\n/** `[[Something to fill in]]`: a placeholder the owner must replace. */\nexport const PLACEHOLDER_RE = /\\[\\[([^[\\]\\n]+?)\\]\\]/g;\n\n/** Number of `[[…]]` placeholders left in every title and body. */\nexport function countPlaceholders(content: LegalDocContent | null | undefined): number {\n let n = 0;\n for (const t of Object.values(content?.translations ?? {})) {\n n += (String(t?.title ?? '').match(PLACEHOLDER_RE) ?? []).length;\n n += (String(t?.body ?? '').match(PLACEHOLDER_RE) ?? []).length;\n }\n return n;\n}\n\n/** Replace `{{site.name}}` and `{{site.domain}}` in a template text. */\nexport function fillSiteVariables(text: string, site: { name?: string; domain?: string }): string {\n return text.replace(/\\{\\{\\s*site\\.(name|domain)\\s*\\}\\}/g, (all, key: 'name' | 'domain') => site[key] ?? all);\n}\n\n/**\n * Language to show: `lang` when the document has it, then `defaultLang`, then\n * the first translation. Undefined when there are no translations.\n */\nexport function pickLegalLanguage(content: LegalDocContent, lang?: string | null, defaultLang?: string | null): string | undefined {\n const langs = Object.keys(content?.translations ?? {});\n if (lang && langs.includes(lang)) return lang;\n if (lang) {\n const base = lang.toLowerCase().split('-')[0];\n const hit = langs.find((l) => l.toLowerCase() === base);\n if (hit) return hit;\n }\n if (defaultLang && langs.includes(defaultLang)) return defaultLang;\n return langs[0];\n}\n\n/** Validate a `LegalDocContent`. Returns an error message or null. */\nexport function legalContentError(value: unknown): string | null {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return 'Must be an object';\n const tr = (value as { translations?: unknown }).translations;\n if (typeof tr !== 'object' || tr === null || Array.isArray(tr)) return 'translations: must be an object';\n for (const [lang, t] of Object.entries(tr)) {\n if (!/^[a-z]{2,3}(-[A-Za-z0-9]{2,8})*$/.test(lang)) return `translations.${lang}: invalid language code`;\n if (typeof t !== 'object' || t === null) return `translations.${lang}: must be { title, body }`;\n const { title, body } = t as Record<string, unknown>;\n if (typeof title !== 'string' || title.length > 300) return `translations.${lang}.title: string (max 300)`;\n if (typeof body !== 'string' || body.length > 200_000) return `translations.${lang}.body: string (max 200000)`;\n }\n return null;\n}\n\n// ---- Markdown ---------------------------------------------------------------\n\nconst BLOCK_DIRECTIVES = new Set(['cookie-table', 'services-list', 'preferences-link', 'last-updated']);\nconst INLINE_DIRECTIVES = new Set(['preferences-link', 'last-updated', 'site.name', 'site.domain']);\nconst INLINE_RE = /\\{\\{\\s*([a-z.-]+)\\s*\\}\\}|\\[\\[([^[\\]\\n]+?)\\]\\]/g;\n\n/** Only http(s), mailto and relative URLs. */\nexport function isSafeLegalUrl(url: string): boolean {\n const u = url.trim();\n // Strip characters browsers ignore inside a scheme (e.g. \"java\\tscript:\").\n let probe = u;\n try {\n probe = decodeURIComponent(u);\n } catch {\n /* keep the raw value */\n }\n probe = probe.replace(/[\\u0000-\\u001f\\u007f\\s]/g, '').toLowerCase();\n if (/^[a-z][a-z0-9+.-]*:/.test(probe)) return /^(https?|mailto):/.test(probe);\n return !probe.startsWith('\\\\');\n}\n\ninterface RenderEnv {\n lang: string;\n labels: LegalLabels;\n render: (name: string, block: boolean) => string;\n}\n\nfunction createMarkdown(): MarkdownIt {\n const md = new MarkdownIt({ html: false, linkify: true, typographer: false });\n md.validateLink = isSafeLegalUrl;\n\n // `{{directive}}` alone on a line → a block token.\n md.block.ruler.before(\n 'paragraph',\n 'ec_directive',\n (state, startLine, _endLine, silent) => {\n if (state.sCount[startLine] - state.blkIndent >= 4) return false;\n const line = state.src.slice(state.bMarks[startLine] + state.tShift[startLine], state.eMarks[startLine]).trim();\n const m = /^\\{\\{\\s*([a-z.-]+)\\s*\\}\\}$/.exec(line);\n if (!m || !BLOCK_DIRECTIVES.has(m[1])) return false;\n if (silent) return true;\n const token = state.push('ec_directive', '', 0);\n token.meta = { name: m[1] };\n token.block = true;\n token.map = [startLine, startLine + 1];\n state.line = startLine + 1;\n return true;\n },\n { alt: ['paragraph'] },\n );\n\n // Inline `{{directive}}` and `[[placeholder]]` inside text tokens. Runs\n // before linkify, so `{{site.name}}` is never turned into a link.\n md.core.ruler.before('linkify', 'ec_inline', (state) => {\n for (const block of state.tokens) {\n if (block.type !== 'inline' || !block.children) continue;\n // Join adjacent text tokens first: `[` starts a new token while parsing.\n const joined: typeof block.children = [];\n for (const tok of block.children) {\n const prev = joined[joined.length - 1];\n if (tok.type === 'text' && prev?.type === 'text') prev.content += tok.content;\n else joined.push(tok);\n }\n const out: typeof block.children = [];\n let inLink = 0;\n for (const tok of joined) {\n if (tok.type === 'link_open') inLink++;\n if (tok.type === 'link_close') inLink--;\n if (tok.type !== 'text' || !/\\{\\{|\\[\\[/.test(tok.content)) {\n out.push(tok);\n continue;\n }\n let last = 0;\n const text = tok.content;\n for (const m of text.matchAll(INLINE_RE)) {\n const isDirective = m[1] !== undefined;\n if (isDirective && (!INLINE_DIRECTIVES.has(m[1]) || (inLink && m[1] === 'preferences-link'))) continue;\n if (m.index! > last) {\n const t = new state.Token('text', '', 0);\n t.content = text.slice(last, m.index);\n out.push(t);\n }\n const t = new state.Token(isDirective ? 'ec_inline_directive' : 'ec_todo', '', 0);\n t.meta = { name: m[1] };\n t.content = isDirective ? m[0] : m[2];\n out.push(t);\n last = m.index! + m[0].length;\n }\n if (last === 0) {\n out.push(tok);\n continue;\n }\n if (last < text.length) {\n const t = new state.Token('text', '', 0);\n t.content = text.slice(last);\n out.push(t);\n }\n }\n block.children = out;\n }\n });\n\n md.renderer.rules.ec_directive = (tokens, idx, _o, env: RenderEnv) => env.render(tokens[idx].meta.name, true) + '\\n';\n md.renderer.rules.ec_inline_directive = (tokens, idx, _o, env: RenderEnv) => env.render(tokens[idx].meta.name, false);\n md.renderer.rules.ec_todo = (tokens, idx) => `<mark class=\"ec-legal__todo\">${escapeHtml(tokens[idx].content)}</mark>`;\n\n // External links open safely.\n const linkOpen = md.renderer.rules.link_open ?? ((tokens, idx, options, _env, self) => self.renderToken(tokens, idx, options));\n md.renderer.rules.link_open = (tokens, idx, options, env, self) => {\n const href = tokens[idx].attrGet('href') ?? '';\n if (/^https?:\\/\\//i.test(href)) tokens[idx].attrSet('rel', 'noopener noreferrer');\n return linkOpen(tokens, idx, options, env, self);\n };\n\n // Stable anchors on headings (\"## 4.2 Purchasing Credits\" → id=\"4-2-purchasing-credits\"),\n // so pages and checkboxes can link to a section. Duplicates get -2, -3…\n md.core.ruler.push('ec_heading_ids', (state) => {\n const seen = new Map<string, number>();\n const tokens = state.tokens;\n for (let i = 0; i < tokens.length; i++) {\n if (tokens[i].type !== 'heading_open') continue;\n const text = tokens[i + 1]?.children?.map((t) => (t.type === 'text' || t.type === 'code_inline' ? t.content : '')).join('') ?? '';\n const base = slugify(text) || 'section';\n const n = (seen.get(base) ?? 0) + 1;\n seen.set(base, n);\n tokens[i].attrSet('id', n === 1 ? base : `${base}-${n}`);\n }\n return true;\n });\n return md;\n}\n\n/** URL-safe heading slug: accents folded, lowercase, non-alphanumerics → \"-\". */\nexport function slugify(text: string): string {\n return text\n .normalize('NFKD')\n .replace(/[\\u0300-\\u036f]/g, '')\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 80);\n}\n\nlet markdown: MarkdownIt | undefined;\nconst getMarkdown = () => (markdown ??= createMarkdown());\n\n// ---- directives -------------------------------------------------------------\n\nfunction isoDay(value: string | Date | undefined): string {\n const d = value === undefined ? new Date() : new Date(value);\n return Number.isNaN(d.getTime()) ? new Date().toISOString().slice(0, 10) : d.toISOString().slice(0, 10);\n}\n\nfunction formatDay(day: string, lang: string): string {\n try {\n return new Intl.DateTimeFormat(lang, { dateStyle: 'long', timeZone: 'UTC' }).format(new Date(`${day}T00:00:00Z`));\n } catch {\n return day;\n }\n}\n\nfunction regionName(code: string, lang: string): string {\n try {\n return new Intl.DisplayNames([lang, 'en'], { type: 'region' }).of(code) ?? code;\n } catch {\n return code;\n }\n}\n\nfunction servicesList(config: EasyCookieConfig, lang: string, L: LegalLabels): string {\n const resolved = resolveConfig(config);\n const fallback = resolved.language.default;\n const l = (v: Parameters<typeof localize>[0]) => localize(v, lang, fallback);\n const categoryTitle = new Map(resolved.resolvedCategories.map((c) => [c.id, l(c.title)]));\n const e = escapeHtml;\n const items = Object.entries(config.services ?? {})\n .filter(([, s]) => s && typeof s === 'object' && s.provider)\n .map(([id, s]) => {\n const transfer = s.from ? findCatalogEntry(s.from)?.transfer : undefined;\n const meta: string[] = [];\n const cat = categoryTitle.get(s.category);\n if (cat) meta.push(`${e(L.category)}: ${e(cat)}`);\n if (transfer?.countries.length) {\n const where = transfer.countries.map((c) => regionName(c, lang)).join(', ');\n const how = transfer.safeguard ? ` (${l(transfer.safeguard)})` : '';\n meta.push(`${e(L.transfer)}: ${e(where + how)}`);\n }\n if (s.privacyUrl && isSafeLegalUrl(s.privacyUrl) && /^(https?:|mailto:|\\/)/i.test(s.privacyUrl.trim()))\n meta.push(`<a href=\"${e(s.privacyUrl)}\" rel=\"noopener noreferrer\">${e(L.privacyPolicy)}</a>`);\n const purpose = l(s.purpose);\n return (\n `<li class=\"ec-legal__service\" data-service=\"${e(id)}\">` +\n `<p class=\"ec-legal__service-name\"><strong>${e(s.label ? l(s.label) : id)}</strong> · ${e(s.provider!)}</p>` +\n (purpose ? `<p class=\"ec-legal__service-purpose\">${e(purpose)}</p>` : '') +\n (meta.length ? `<p class=\"ec-legal__service-meta\">${meta.join(' · ')}</p>` : '') +\n '</li>'\n );\n });\n if (!items.length) return `<p class=\"ec-legal__empty\">${e(L.noServices)}</p>`;\n return `<ul class=\"ec-legal__services\">\\n${items.join('\\n')}\\n</ul>`;\n}\n\n/**\n * Render a legal document to safe HTML: Markdown (raw HTML disabled, only\n * http/https/mailto/relative links), directives expanded against `config`,\n * `[[placeholders]]` highlighted. Picks the translation for `lang`, falling\n * back to the config's default language, then to the first translation.\n */\nexport function renderLegalDocument(content: LegalDocContent, lang: string, opts: RenderLegalOptions = {}): RenderedLegalDocument {\n const config = opts.config ?? null;\n const shown = pickLegalLanguage(content, lang, config?.language?.default) ?? lang;\n const tr = content?.translations?.[shown] ?? { title: '', body: '' };\n const L = labelsFor(shown);\n const e = escapeHtml;\n const day = isoDay(opts.publishedAt);\n const site = opts.site ?? {};\n\n const render = (name: string, block: boolean): string => {\n switch (name) {\n case 'cookie-table':\n if (!config) return `<p class=\"ec-legal__notice\">${e(L.noConfig)}</p>`;\n return renderPolicyHtml(buildPolicyModel(config, shown), { headingLevel: 3, meta: false });\n case 'services-list':\n if (!config) return `<p class=\"ec-legal__notice\">${e(L.noConfig)}</p>`;\n return servicesList(config, shown, L);\n case 'preferences-link': {\n const href = opts.preferencesHref && isSafeLegalUrl(opts.preferencesHref) ? opts.preferencesHref : undefined;\n const a = href\n ? `<a href=\"${e(href)}\" class=\"ec-legal__preferences\">${e(L.preferences)}</a>`\n : `<a href=\"#\" class=\"ec-legal__preferences\" data-ec-open-preferences>${e(L.preferences)}</a>`;\n return block ? `<p>${a}</p>` : a;\n }\n case 'last-updated': {\n const time = `<time datetime=\"${day}\">${e(formatDay(day, shown))}</time>`;\n return block ? `<p class=\"ec-legal__updated\">${e(L.updated)}: ${time}</p>` : time;\n }\n case 'site.name':\n case 'site.domain': {\n const v = site[name === 'site.name' ? 'name' : 'domain'];\n return e(v ?? `{{${name}}}`);\n }\n default:\n return e(`{{${name}}}`);\n }\n };\n\n const env: RenderEnv = { lang: shown, labels: L, render };\n const body = getMarkdown().render(tr.body ?? '', env);\n const titleText = fillSiteVariables(tr.title ?? '', site);\n const titleHtml = titleText.replace(/[^[]+|\\[\\[([^[\\]\\n]+?)\\]\\]|\\[/g, (m, todo?: string) =>\n todo !== undefined ? `<mark class=\"ec-legal__todo\">${e(todo)}</mark>` : e(m),\n );\n const heading = opts.heading === false || !titleText ? '' : `<h1 class=\"ec-legal__title\">${titleHtml}</h1>\\n`;\n const version = opts.version ? ` data-version=\"${e(opts.version)}\"` : '';\n return {\n lang: shown,\n title: titleText.replace(PLACEHOLDER_RE, '$1'),\n html: `<div class=\"ec-legal\" lang=\"${e(shown)}\"${version}>\\n${heading}${body}</div>`,\n };\n}\n\n","/**\n * Legal document types and the fetch client. Kept free of the Markdown\n * renderer so browser bundles (React component, Next.js) stay small.\n */\n\n/** The three legal documents every site has. */\nexport type LegalKind = 'cookie' | 'privacy' | 'terms';\nexport const LEGAL_KINDS: readonly LegalKind[] = ['cookie', 'privacy', 'terms'];\nexport const isLegalKind = (v: unknown): v is LegalKind => typeof v === 'string' && (LEGAL_KINDS as readonly string[]).includes(v);\n\nexport interface LegalTranslation {\n title: string;\n /** Markdown, rendered with raw HTML disabled. */\n body: string;\n}\n\n/** Content of a legal document: one entry per language it is written in. */\nexport interface LegalDocContent {\n translations: Record<string, LegalTranslation>;\n}\n\n/** A published document as served by `GET /v1/sites/:publicKey/legal/:kind.json`. */\nexport interface PublishedLegalDocument {\n kind: LegalKind;\n /** Language actually shown (after fallback). */\n lang: string;\n /** Every language the document is written in. */\n languages: string[];\n title: string;\n /** Rendered, safe HTML wrapped in `<div class=\"ec-legal\" lang=\"…\">`. */\n html: string;\n version: string;\n publishedAt: string;\n}\n\nexport interface FetchLegalDocumentOptions {\n /** Base URL of the consent server. */\n endpoint: string;\n /** Public site key (`pk_…`). */\n siteKey: string;\n kind: LegalKind;\n lang?: string;\n /** Extra fetch options (e.g. Next's `next: { revalidate }`). */\n init?: RequestInit & Record<string, unknown>;\n /** Custom fetch implementation. */\n fetch?: typeof fetch;\n}\n\n/** URL of the published document JSON on the consent server. */\nexport function legalDocumentUrl(opts: Pick<FetchLegalDocumentOptions, 'endpoint' | 'siteKey' | 'kind' | 'lang'>): string {\n const base = opts.endpoint.replace(/\\/+$/, '');\n const q = opts.lang ? `?lang=${encodeURIComponent(opts.lang)}` : '';\n return `${base}/v1/sites/${encodeURIComponent(opts.siteKey)}/legal/${encodeURIComponent(opts.kind)}.json${q}`;\n}\n\n/**\n * Fetch a published legal document from the consent server.\n * Resolves to null when nothing is published yet (404); throws on other errors.\n */\nexport async function fetchLegalDocument(opts: FetchLegalDocumentOptions): Promise<PublishedLegalDocument | null> {\n const f = opts.fetch ?? fetch;\n const res = await f(legalDocumentUrl(opts), { credentials: 'omit', ...opts.init });\n if (res.status === 404) return null;\n if (!res.ok) throw new Error(`[easy-cookie] could not load the ${opts.kind} document (${res.status})`);\n return (await res.json()) as PublishedLegalDocument;\n}\n","import type { LegalTranslation } from '../legal';\n\n/** Built-in cookie policy template. A starting draft, not legal advice. */\nexport const cookie: Record<'it' | 'en', LegalTranslation> = {\n it: {\n title: 'Cookie policy',\n body: `[[BOZZA: questo testo è un modello generico, non è una consulenza legale. Completa i campi evidenziati, verifica che l’elenco dei cookie corrisponda a quello che il sito usa davvero e fallo controllare da un professionista prima di pubblicarlo. Poi elimina questa riga.]]\n\nQuesta pagina spiega quali cookie e strumenti simili usa {{site.domain}}, a cosa servono e come puoi gestire il tuo consenso.\n\n## Cosa sono i cookie\n\nI cookie sono piccoli file di testo che un sito salva nel tuo browser per ricordare informazioni sulla tua visita. Strumenti simili, come il local storage, i pixel e gli script di terze parti, funzionano in modo analogo: in questa pagina li chiamiamo tutti «cookie».\n\nI cookie possono essere **di prima parte**, se li imposta questo sito, o **di terze parti**, se li impostano altri servizi, ad esempio un video incorporato o uno strumento di statistica.\n\n## Come li usiamo\n\nSecondo l’art. 122 del Codice privacy e le linee guida del Garante per la protezione dei dati personali del 10 giugno 2021:\n\n- i **cookie tecnici** (necessari) sono usati senza il tuo consenso, perché servono a far funzionare il sito e a ricordare le tue scelte;\n- tutti gli **altri cookie** sono attivati solo dopo il tuo consenso. Fino ad allora sono bloccati.\n\nChiudere il banner con la X equivale a rifiutare i cookie non necessari.\n\n## Categorie\n\n- **Necessari**: servono al funzionamento del sito, ad esempio per la sessione e per ricordare la tua scelta sui cookie. Non si possono disattivare.\n- **Funzionalità**: abilitano funzioni aggiuntive come la chat di assistenza o le preferenze salvate.\n- **Esperienza**: permettono di mostrare contenuti di terze parti incorporati, come video e mappe.\n- **Misurazione**: ci aiutano a capire come viene usato il sito, con statistiche sulle visite.\n- **Marketing**: servono a misurare le campagne pubblicitarie e a mostrarti annunci più pertinenti, anche su altri siti.\n\nIl sito usa solo le categorie elencate nella tabella qui sotto.\n\n## Cookie usati su questo sito\n\n{{cookie-table}}\n\nI cookie di terze parti sono gestiti dai rispettivi fornitori: per sapere come trattano i dati consulta le loro informative, collegate nella tabella.\n\n## Come gestire il consenso\n\nAlla prima visita un banner ti chiede di scegliere: puoi accettare tutti i cookie, rifiutarli tutti o scegliere categoria per categoria. Ricordiamo la tua scelta per [[Durata del consenso, ad esempio 6 mesi]], poi te la chiediamo di nuovo. Te la chiediamo di nuovo anche se cambiano in modo rilevante i cookie che usiamo.\n\nPuoi cambiare idea in qualsiasi momento: {{preferences-link}}. Quando revochi il consenso, i cookie della categoria vengono cancellati, dove tecnicamente possibile.\n\n## Impostazioni del browser\n\nPuoi anche bloccare o cancellare i cookie dalle impostazioni del browser. Bloccare i cookie necessari può impedire ad alcune parti del sito di funzionare.\n\n- [Google Chrome](https://support.google.com/chrome/answer/95647)\n- [Mozilla Firefox](https://support.mozilla.org/kb/clear-cookies-and-site-data-firefox)\n- [Apple Safari](https://support.apple.com/guide/safari/manage-cookies-sfri11471/mac)\n- [Microsoft Edge](https://support.microsoft.com/microsoft-edge/delete-cookies-in-microsoft-edge-63947406-40ac-c3b8-57b9-2a946a29ae09)\n\n## Titolare del trattamento\n\nIl titolare del trattamento è [[Ragione sociale o nome e cognome del titolare]], [[Indirizzo completo]], [[Indirizzo email di contatto]]. Per sapere come trattiamo i dati personali e come esercitare i tuoi diritti leggi l’informativa sulla privacy: [[Link all’informativa sulla privacy]].\n\n## Ultimo aggiornamento\n\n{{last-updated}}\n`,\n },\n en: {\n title: 'Cookie policy',\n body: `[[DRAFT: this text is a generic template, not legal advice. Fill in the highlighted fields, check that the list of cookies matches what the site really uses and have it reviewed by a professional before publishing it. Then delete this line.]]\n\nThis page explains which cookies and similar technologies {{site.domain}} uses, what they are for and how you can manage your consent.\n\n## What cookies are\n\nCookies are small text files that a site stores in your browser to remember information about your visit. Similar technologies, such as local storage, pixels and third-party scripts, work in a similar way: on this page we call them all “cookies”.\n\nCookies can be **first-party**, when this site sets them, or **third-party**, when other services set them, for example an embedded video or an analytics tool.\n\n## How we use them\n\nIn line with the ePrivacy Directive and, in Italy, the guidelines of the Italian Data Protection Authority (Garante) of 10 June 2021:\n\n- **technical** (necessary) cookies are used without your consent, because the site needs them to work and to remember your choices;\n- all **other cookies** are turned on only after you consent. Until then they are blocked.\n\nClosing the banner with the X counts as rejecting non-essential cookies.\n\n## Categories\n\n- **Necessary**: required for the site to work, for example for the session and to remember your cookie choice. They cannot be turned off.\n- **Functionality**: enable extra features such as the support chat or saved preferences.\n- **Experience**: allow embedded third-party content such as videos and maps.\n- **Measurement**: help us understand how the site is used, through visit statistics.\n- **Marketing**: measure advertising campaigns and show you more relevant ads, including on other sites.\n\nThe site uses only the categories listed in the table below.\n\n## Cookies used on this site\n\n{{cookie-table}}\n\nThird-party cookies are managed by their providers: to learn how they process data, read their policies, linked in the table.\n\n## Managing your consent\n\nOn your first visit a banner asks you to choose: you can accept all cookies, reject them all or choose category by category. We remember your choice for [[Consent duration, for example 6 months]], then we ask again. We also ask again if the cookies we use change significantly.\n\nYou can change your mind at any time: {{preferences-link}}. When you withdraw consent, the cookies of that category are deleted where technically possible.\n\n## Browser settings\n\nYou can also block or delete cookies in your browser settings. Blocking necessary cookies may stop parts of the site from working.\n\n- [Google Chrome](https://support.google.com/chrome/answer/95647)\n- [Mozilla Firefox](https://support.mozilla.org/kb/clear-cookies-and-site-data-firefox)\n- [Apple Safari](https://support.apple.com/guide/safari/manage-cookies-sfri11471/mac)\n- [Microsoft Edge](https://support.microsoft.com/microsoft-edge/delete-cookies-in-microsoft-edge-63947406-40ac-c3b8-57b9-2a946a29ae09)\n\n## Data controller\n\nThe data controller is [[Company name or full name of the controller]], [[Full address]], [[Contact email]]. To learn how we process personal data and how to exercise your rights, read the privacy policy: [[Link to the privacy policy]].\n\n## Last updated\n\n{{last-updated}}\n`,\n },\n};\n","import type { LegalTranslation } from '../legal';\n\n/** Built-in privacy policy template (GDPR art. 13). A starting draft, not legal advice. */\nexport const privacy: Record<'it' | 'en', LegalTranslation> = {\n it: {\n title: 'Informativa sulla privacy',\n body: `[[BOZZA: questo testo è un modello generico, non è una consulenza legale. Completa i campi evidenziati, adattalo a come tratti davvero i dati e fallo verificare da un professionista prima di pubblicarlo. Poi elimina questa riga.]]\n\nQuesta informativa spiega come {{site.name}} tratta i dati personali di chi visita {{site.domain}} e di chi usa i suoi servizi, ai sensi degli articoli 13 e 14 del Regolamento (UE) 2016/679 («GDPR») e del Codice in materia di protezione dei dati personali (d.lgs. 196/2003).\n\n## 1. Titolare del trattamento\n\nIl titolare del trattamento è [[Ragione sociale o nome e cognome del titolare]], con sede in [[Indirizzo completo]], P. IVA / C.F. [[Partita IVA o codice fiscale]] (di seguito «Titolare»).\n\nPuoi contattare il Titolare scrivendo a [[Indirizzo email per la privacy]].\n\n[[Se hai nominato un Responsabile della protezione dei dati (DPO), indica qui il nome e il contatto; altrimenti elimina questa riga.]]\n\n## 2. Quali dati trattiamo\n\n- **Dati di navigazione.** I sistemi che fanno funzionare il sito raccolgono automaticamente alcuni dati, come l’indirizzo IP, il tipo di browser e di dispositivo, le pagine richieste, la data e l’ora della richiesta. Servono a far funzionare il sito e a proteggerlo.\n- **Dati che ci fornisci.** Quando ci scrivi, compili un modulo, ti registri o acquisti, trattiamo i dati che inserisci, ad esempio nome, cognome, indirizzo email e [[Altri dati raccolti, ad esempio telefono, indirizzo di fatturazione]].\n- **Cookie e strumenti simili.** Li descriviamo nella cookie policy: [[Link alla cookie policy]].\n- [[Altre categorie di dati che tratti, ad esempio dati di pagamento o dati dell’account. Elimina questa voce se non serve.]]\n\n[[Conferma o modifica:]] Non chiediamo dati appartenenti a categorie particolari (art. 9 GDPR), come dati sulla salute. Ti chiediamo di non inviarceli.\n\n## 3. Finalità e basi giuridiche\n\n| Finalità | Base giuridica (art. 6 GDPR) |\n| --- | --- |\n| Rispondere alle tue richieste di contatto | Misure precontrattuali richieste da te (art. 6.1.b) o nostro legittimo interesse a rispondere (art. 6.1.f) |\n| Fornire il servizio o il prodotto richiesto e gestire il contratto | Esecuzione di un contratto (art. 6.1.b) |\n| Adempiere agli obblighi di legge, ad esempio fiscali e contabili | Obbligo legale (art. 6.1.c) |\n| Garantire la sicurezza del sito e prevenire abusi | Legittimo interesse (art. 6.1.f) |\n| Statistiche, contenuti incorporati e marketing tramite cookie non tecnici | Consenso (art. 6.1.a), che puoi revocare in ogni momento |\n| [[Altra finalità, ad esempio l’invio della newsletter]] | [[Base giuridica, ad esempio il consenso (art. 6.1.a)]] |\n\nQuando la base giuridica è il legittimo interesse, puoi opporti al trattamento in qualsiasi momento (vedi la sezione «I tuoi diritti»).\n\n## 4. Natura del conferimento\n\nI dati di navigazione sono necessari per usare il sito. Il conferimento degli altri dati è facoltativo, ma senza i dati richiesti come obbligatori non possiamo rispondere alla tua richiesta o fornire il servizio.\n\n## 5. Modalità del trattamento e conservazione\n\nTrattiamo i dati con strumenti elettronici e con misure tecniche e organizzative adeguate a proteggerli. Li conserviamo solo per il tempo necessario:\n\n- richieste di contatto: [[Periodo di conservazione, ad esempio 12 mesi dall’ultima comunicazione]];\n- dati relativi al contratto e alla fatturazione: per la durata del contratto e poi per il tempo previsto dalla legge per gli obblighi fiscali e contabili ([[Periodo, di norma 10 anni]]);\n- dati di navigazione (log tecnici): [[Periodo di conservazione dei log]];\n- prova del consenso ai cookie: [[Periodo di conservazione della prova del consenso]];\n- cookie: per la durata indicata nella cookie policy.\n\nAl termine li cancelliamo o li rendiamo anonimi.\n\n## 6. Destinatari dei dati\n\nI dati possono essere comunicati a:\n\n- fornitori che li trattano per nostro conto come responsabili del trattamento (art. 28 GDPR), ad esempio i servizi di hosting, di posta elettronica e [[Altri fornitori]];\n- professionisti e consulenti che ci assistono, ad esempio [[Commercialista, consulente legale]];\n- autorità pubbliche, quando la legge lo richiede.\n\nI dati non vengono diffusi. L’elenco aggiornato dei responsabili è disponibile su richiesta.\n\n### Servizi di terze parti usati dal sito\n\n{{services-list}}\n\n## 7. Trasferimento dei dati fuori dallo Spazio economico europeo\n\nAlcuni fornitori possono trattare dati al di fuori dello Spazio economico europeo (SEE). In questi casi il trasferimento avviene solo sulla base di una decisione di adeguatezza della Commissione europea (art. 45 GDPR), come l’EU-US Data Privacy Framework per le società statunitensi certificate, oppure con garanzie adeguate come le clausole contrattuali standard approvate dalla Commissione (art. 46 GDPR). I paesi e le garanzie, quando noti, sono indicati nell’elenco dei servizi qui sopra. Puoi chiedere una copia delle garanzie scrivendo a [[Indirizzo email per la privacy]].\n\n## 8. I tuoi diritti\n\nIn qualsiasi momento puoi esercitare i diritti previsti dagli articoli 15–22 del GDPR:\n\n- **accesso** ai tuoi dati e alle informazioni sul trattamento (art. 15);\n- **rettifica** dei dati inesatti o incompleti (art. 16);\n- **cancellazione** dei dati (art. 17);\n- **limitazione** del trattamento (art. 18);\n- **portabilità** dei dati che ci hai fornito, in un formato strutturato e leggibile da dispositivo automatico (art. 20);\n- **opposizione** al trattamento basato sul legittimo interesse e, sempre, al marketing diretto (art. 21);\n- non essere sottoposto a **decisioni basate unicamente su un trattamento automatizzato** che producono effetti giuridici o incidono in modo analogo significativamente sulla tua persona (art. 22).\n\nQuando il trattamento si basa sul consenso, puoi **revocarlo** in qualsiasi momento, senza pregiudicare la liceità del trattamento svolto prima della revoca (art. 7.3). Per i cookie: {{preferences-link}}.\n\nPer esercitare i diritti scrivi a [[Indirizzo email per la privacy]]. Rispondiamo senza ingiustificato ritardo e comunque entro un mese, prorogabile di due mesi nei casi previsti dall’art. 12.3 GDPR.\n\n[[Conferma o modifica: il Titolare non adotta processi decisionali automatizzati, compresa la profilazione, che producano effetti giuridici sugli interessati.]]\n\n## 9. Reclamo all’autorità di controllo\n\nSe ritieni che il trattamento violi il GDPR, hai il diritto di proporre reclamo al Garante per la protezione dei dati personali (www.garanteprivacy.it) o all’autorità di controllo dello Stato membro in cui risiedi, lavori o in cui è avvenuta la presunta violazione (art. 77 GDPR).\n\n## 10. Modifiche a questa informativa\n\nPossiamo aggiornare questa informativa, ad esempio per cambiamenti normativi o dei servizi che usiamo. La versione in vigore è sempre pubblicata su questa pagina, con la data dell’ultimo aggiornamento.\n\n## 11. Contatti\n\n[[Ragione sociale o nome e cognome del titolare]] · [[Indirizzo completo]] · [[Indirizzo email per la privacy]]\n\n{{last-updated}}\n`,\n },\n en: {\n title: 'Privacy policy',\n body: `[[DRAFT: this text is a generic template, not legal advice. Fill in the highlighted fields, adapt it to how you actually process data and have it reviewed by a professional before publishing it. Then delete this line.]]\n\nThis policy explains how {{site.name}} processes the personal data of people who visit {{site.domain}} and use its services, under Articles 13 and 14 of Regulation (EU) 2016/679 (“GDPR”).\n\n## 1. Data controller\n\nThe data controller is [[Company name or full name of the controller]], located at [[Full address]], VAT / tax number [[VAT or tax number]] (the “Controller”).\n\nYou can contact the Controller at [[Privacy contact email]].\n\n[[If you have appointed a Data Protection Officer (DPO), give their name and contact here; otherwise delete this line.]]\n\n## 2. Data we process\n\n- **Browsing data.** The systems that run the site automatically collect some data, such as the IP address, the type of browser and device, the pages requested, and the date and time of the request. We need it to run and protect the site.\n- **Data you give us.** When you write to us, fill in a form, sign up or buy, we process the data you enter, for example your name, email address and [[Other data collected, for example phone number, billing address]].\n- **Cookies and similar technologies.** They are described in the cookie policy: [[Link to the cookie policy]].\n- [[Other categories of data you process, for example payment or account data. Delete this item if not needed.]]\n\n[[Confirm or change:]] We do not ask for special categories of data (Article 9 GDPR), such as health data. Please do not send them to us.\n\n## 3. Purposes and legal bases\n\n| Purpose | Legal basis (Article 6 GDPR) |\n| --- | --- |\n| Replying to your contact requests | Pre-contractual steps you asked for (Art. 6(1)(b)) or our legitimate interest in replying (Art. 6(1)(f)) |\n| Providing the service or product you asked for and managing the contract | Performance of a contract (Art. 6(1)(b)) |\n| Meeting legal obligations, for example tax and accounting | Legal obligation (Art. 6(1)(c)) |\n| Keeping the site secure and preventing abuse | Legitimate interest (Art. 6(1)(f)) |\n| Statistics, embedded content and marketing through non-essential cookies | Consent (Art. 6(1)(a)), which you can withdraw at any time |\n| [[Other purpose, for example sending the newsletter]] | [[Legal basis, for example consent (Art. 6(1)(a))]] |\n\nWhere the legal basis is legitimate interest, you can object to the processing at any time (see “Your rights”).\n\n## 4. Whether you must provide data\n\nBrowsing data is needed to use the site. Providing other data is optional, but without the data marked as required we cannot answer your request or provide the service.\n\n## 5. How we process and keep data\n\nWe process data electronically, with technical and organisational measures appropriate to protect it. We keep it only as long as needed:\n\n- contact requests: [[Retention period, for example 12 months after the last message]];\n- contract and billing data: for the duration of the contract, then for the period the law requires for tax and accounting obligations ([[Period, usually 10 years in Italy]]);\n- browsing data (technical logs): [[Log retention period]];\n- proof of cookie consent: [[Retention period of the consent proof]];\n- cookies: for the duration shown in the cookie policy.\n\nAfterwards we delete or anonymise it.\n\n## 6. Recipients\n\nData may be shared with:\n\n- providers that process it on our behalf as processors (Article 28 GDPR), for example hosting, email and [[Other providers]];\n- professionals and advisers who assist us, for example [[Accountant, legal adviser]];\n- public authorities, when the law requires it.\n\nData is not made public. The current list of processors is available on request.\n\n### Third-party services used by the site\n\n{{services-list}}\n\n## 7. Transfers outside the European Economic Area\n\nSome providers may process data outside the European Economic Area (EEA). In that case the transfer takes place only on the basis of a European Commission adequacy decision (Article 45 GDPR), such as the EU-US Data Privacy Framework for certified US companies, or with appropriate safeguards such as the standard contractual clauses approved by the Commission (Article 46 GDPR). Countries and safeguards, when known, are listed with the services above. You can ask for a copy of the safeguards at [[Privacy contact email]].\n\n## 8. Your rights\n\nAt any time you can exercise the rights in Articles 15–22 GDPR:\n\n- **access** to your data and to information about the processing (Art. 15);\n- **rectification** of inaccurate or incomplete data (Art. 16);\n- **erasure** of your data (Art. 17);\n- **restriction** of processing (Art. 18);\n- **portability** of the data you gave us, in a structured, machine-readable format (Art. 20);\n- **objection** to processing based on legitimate interest and, always, to direct marketing (Art. 21);\n- not to be subject to **decisions based solely on automated processing** that produce legal effects concerning you or similarly significantly affect you (Art. 22).\n\nWhere processing is based on consent, you can **withdraw** it at any time, without affecting the lawfulness of processing before the withdrawal (Art. 7(3)). For cookies: {{preferences-link}}.\n\nTo exercise your rights, write to [[Privacy contact email]]. We reply without undue delay and in any case within one month, which may be extended by two months in the cases set out in Article 12(3) GDPR.\n\n[[Confirm or change: the Controller does not use automated decision-making, including profiling, that produces legal effects on data subjects.]]\n\n## 9. Complaints to a supervisory authority\n\nIf you believe the processing infringes the GDPR, you have the right to lodge a complaint with the Italian Data Protection Authority (Garante per la protezione dei dati personali, www.garanteprivacy.it) or with the supervisory authority of the Member State where you live, work or where the alleged infringement took place (Article 77 GDPR).\n\n## 10. Changes to this policy\n\nWe may update this policy, for example when the law or the services we use change. The current version is always published on this page, with the date of the last update.\n\n## 11. Contact\n\n[[Company name or full name of the controller]] · [[Full address]] · [[Privacy contact email]]\n\n{{last-updated}}\n`,\n },\n};\n","import type { LegalTranslation } from '../legal';\n\n/** Built-in terms of use skeleton. A starting draft, not legal advice. */\nexport const terms: Record<'it' | 'en', LegalTranslation> = {\n it: {\n title: 'Termini e condizioni',\n body: `[[BOZZA: questo testo è uno schema generico, non è una consulenza legale. Termini e condizioni dipendono molto dall’attività: completa i campi evidenziati, elimina le sezioni che non ti riguardano e fallo verificare da un professionista prima di pubblicarlo. Poi elimina questa riga.]]\n\n## 1. Oggetto\n\nQuesti termini regolano l’uso del sito {{site.domain}} e dei servizi offerti da {{site.name}} (di seguito «Servizio»). Usando il Servizio accetti questi termini. Se non li accetti, non usare il Servizio.\n\n## 2. Chi siamo\n\nIl Servizio è gestito da [[Ragione sociale o nome e cognome]], con sede in [[Indirizzo completo]], P. IVA [[Partita IVA]], email [[Indirizzo email di contatto]], [[PEC, se disponibile]].\n\n## 3. Descrizione del Servizio\n\n[[Descrivi in modo semplice cosa offre il sito o il servizio, a chi si rivolge e se è gratuito o a pagamento.]]\n\n## 4. Uso consentito\n\nTi impegni a usare il Servizio nel rispetto della legge e di questi termini. In particolare non puoi:\n\n- usarlo per attività illecite o per violare diritti altrui;\n- tentare di accedere senza autorizzazione a sistemi, account o dati;\n- comprometterne il funzionamento, ad esempio con attacchi automatizzati o carichi eccessivi;\n- [[Altri divieti specifici del tuo Servizio]].\n\n## 5. Account\n\n[[Se il Servizio prevede un account: requisiti per registrarsi (ad esempio l’età minima), responsabilità per la custodia delle credenziali, modalità di chiusura dell’account. Altrimenti elimina questa sezione.]]\n\n## 6. Prezzi e pagamenti\n\n[[Se il Servizio è a pagamento: prezzi (IVA inclusa o esclusa), modalità di pagamento, rinnovi e disdetta, fatturazione. Altrimenti elimina questa sezione.]]\n\n## 7. Diritto di recesso\n\n[[Se vendi a consumatori a distanza: indica le condizioni del diritto di recesso previsto dal Codice del consumo (d.lgs. 206/2005), di regola 14 giorni, e le eventuali esclusioni. Altrimenti elimina questa sezione.]]\n\n## 8. Proprietà intellettuale\n\nTesti, immagini, marchi, loghi, software e altri contenuti del Servizio appartengono a [[Ragione sociale o nome e cognome]] o ai rispettivi titolari e sono protetti dalla legge. Non puoi copiarli, modificarli o distribuirli senza autorizzazione scritta, salvo i casi consentiti dalla legge.\n\n## 9. Contenuti degli utenti\n\n[[Se gli utenti possono pubblicare contenuti: chi ne resta titolare, quale licenza ci concedono, regole sui contenuti vietati e come li rimuoviamo. Altrimenti elimina questa sezione.]]\n\n## 10. Link a siti di terzi\n\nIl Servizio può contenere link a siti di terzi. Non controlliamo questi siti e non siamo responsabili dei loro contenuti o delle loro pratiche sulla privacy.\n\n## 11. Disponibilità e modifiche del Servizio\n\nFacciamo il possibile perché il Servizio sia disponibile e funzioni correttamente, ma potrebbe essere interrotto per manutenzione, aggiornamenti o cause indipendenti dalla nostra volontà. Possiamo modificare o sospendere il Servizio, dandone [[Modalità e tempi di preavviso]] quando la modifica ti riguarda in modo rilevante.\n\n## 12. Responsabilità\n\nNei limiti consentiti dalla legge, non siamo responsabili per danni indiretti derivanti dall’uso o dall’impossibilità di usare il Servizio. Nulla in questi termini esclude o limita la responsabilità che per legge non può essere esclusa o limitata, né i diritti che la legge riconosce ai consumatori.\n\n[[Eventuali limitazioni ulteriori, da verificare con un professionista.]]\n\n## 13. Privacy\n\nTrattiamo i dati personali come descritto nell’informativa sulla privacy: [[Link all’informativa sulla privacy]].\n\n## 14. Modifiche ai termini\n\nPossiamo aggiornare questi termini. La versione in vigore è sempre pubblicata su questa pagina, con la data dell’ultimo aggiornamento. Se le modifiche sono rilevanti te lo comunicheremo [[Come: ad esempio via email o con un avviso sul sito]].\n\n## 15. Legge applicabile e foro competente\n\nQuesti termini sono regolati dalla [[Legge applicabile, ad esempio la legge italiana]]. Se sei un consumatore, per le controversie è competente il giudice del luogo in cui risiedi o hai il domicilio. Negli altri casi è competente in via esclusiva il foro di [[Città]].\n\n## 16. Contatti\n\nPer domande su questi termini scrivi a [[Indirizzo email di contatto]].\n\n{{last-updated}}\n`,\n },\n en: {\n title: 'Terms and conditions',\n body: `[[DRAFT: this text is a generic skeleton, not legal advice. Terms depend heavily on the business: fill in the highlighted fields, delete the sections that do not apply and have it reviewed by a professional before publishing it. Then delete this line.]]\n\n## 1. Scope\n\nThese terms govern the use of the site {{site.domain}} and of the services offered by {{site.name}} (the “Service”). By using the Service you accept these terms. If you do not accept them, do not use the Service.\n\n## 2. Who we are\n\nThe Service is run by [[Company name or full name]], located at [[Full address]], VAT number [[VAT number]], email [[Contact email]].\n\n## 3. The Service\n\n[[Describe in plain words what the site or service offers, who it is for and whether it is free or paid.]]\n\n## 4. Acceptable use\n\nYou agree to use the Service lawfully and in line with these terms. In particular you must not:\n\n- use it for unlawful activities or to infringe the rights of others;\n- try to access systems, accounts or data without authorisation;\n- disrupt it, for example with automated attacks or excessive load;\n- [[Other restrictions specific to your Service]].\n\n## 5. Accounts\n\n[[If the Service has accounts: sign-up requirements (for example a minimum age), responsibility for keeping credentials safe, how to close the account. Otherwise delete this section.]]\n\n## 6. Prices and payments\n\n[[If the Service is paid: prices (including or excluding VAT), payment methods, renewals and cancellation, invoicing. Otherwise delete this section.]]\n\n## 7. Right of withdrawal\n\n[[If you sell to consumers at a distance: state the conditions of the statutory right of withdrawal (in the EU, usually 14 days) and any exceptions. Otherwise delete this section.]]\n\n## 8. Intellectual property\n\nTexts, images, trademarks, logos, software and other content of the Service belong to [[Company name or full name]] or to their respective owners and are protected by law. You may not copy, modify or distribute them without written permission, except where the law allows it.\n\n## 9. User content\n\n[[If users can publish content: who keeps ownership, which licence they grant you, rules on prohibited content and how you remove it. Otherwise delete this section.]]\n\n## 10. Third-party links\n\nThe Service may link to third-party sites. We do not control those sites and are not responsible for their content or privacy practices.\n\n## 11. Availability and changes to the Service\n\nWe do our best to keep the Service available and working, but it may be interrupted for maintenance, updates or causes beyond our control. We may change or suspend the Service, giving [[Notice period and how]] when a change affects you significantly.\n\n## 12. Liability\n\nTo the extent permitted by law, we are not liable for indirect damages arising from the use of, or the inability to use, the Service. Nothing in these terms excludes or limits any liability that cannot be excluded or limited by law, or the rights the law gives to consumers.\n\n[[Any further limitations, to be checked with a professional.]]\n\n## 13. Privacy\n\nWe process personal data as described in the privacy policy: [[Link to the privacy policy]].\n\n## 14. Changes to these terms\n\nWe may update these terms. The current version is always published on this page, with the date of the last update. If the changes are significant we will tell you [[How: for example by email or with a notice on the site]].\n\n## 15. Governing law and jurisdiction\n\nThese terms are governed by [[Governing law, for example Italian law]]. If you are a consumer, the courts of the place where you live have jurisdiction, and you keep the protection of the mandatory rules of your country of residence. Otherwise the courts of [[City]] have exclusive jurisdiction.\n\n## 16. Contact\n\nFor questions about these terms, write to [[Contact email]].\n\n{{last-updated}}\n`,\n },\n};\n","import { fillSiteVariables, type LegalKind, type LegalTranslation } from '../legal';\nimport { cookie } from './cookie';\nimport { privacy } from './privacy';\nimport { terms } from './terms';\n\n/**\n * Built-in starting drafts for the three legal documents, in Italian and\n * English. They are templates, not legal advice: every owner-specific value is\n * a `[[placeholder]]`, and the first line asks for a professional review.\n */\nexport const LEGAL_TEMPLATES: Record<LegalKind, Record<'it' | 'en', LegalTranslation>> = { cookie, privacy, terms };\n\n/** Languages the built-in templates are written in. */\nexport const LEGAL_TEMPLATE_LANGUAGES = ['it', 'en'] as const;\n\n/**\n * The built-in template for `kind` in `lang` (unknown languages get English),\n * with `{{site.name}}` / `{{site.domain}}` replaced when `site` is given.\n */\nexport function legalTemplate(kind: LegalKind, lang: string, site?: { name?: string; domain?: string }): LegalTranslation {\n const base = lang.toLowerCase().split('-')[0];\n const t = (LEGAL_TEMPLATES[kind] as Record<string, LegalTranslation>)[base] ?? LEGAL_TEMPLATES[kind].en;\n if (!site) return { ...t };\n return { title: fillSiteVariables(t.title, site), body: fillSiteVariables(t.body, site) };\n}\n"],"mappings":"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","names":["cookie","import_shared","MarkdownIt","t"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
export { A as AutoClearRule, B as BuildPolicyOptions, P as POLICY_LABELS, a as PolicyCategory, b as PolicyCookie, c as PolicyLabels, d as PolicyModel, e as PolicyRow, f as PolicyService, R as RenderPolicyOptions, g as autoClearRules, h as buildPolicyModel, i as escapeHtml, j as formatPolicyDate, m as matchesRule, p as policyRows, k as prettyCookiePattern, r as renderPolicyHtml, l as renderPolicyMarkdown } from './render-DYrvn1cT.cjs';
|
|
2
|
+
import { EasyCookieConfig } from '@easy-cookie/core/shared';
|
|
3
|
+
import { LegalDocContent, LegalKind, LegalTranslation } from './client.cjs';
|
|
4
|
+
export { FetchLegalDocumentOptions, LEGAL_KINDS, PublishedLegalDocument, fetchLegalDocument, isLegalKind, legalDocumentUrl } from './client.cjs';
|
|
5
|
+
|
|
6
|
+
interface RenderLegalOptions {
|
|
7
|
+
/**
|
|
8
|
+
* Banner config used to expand `{{cookie-table}}` and `{{services-list}}`
|
|
9
|
+
* (the published one for visitors, the draft one for previews). Without it
|
|
10
|
+
* those directives render a short notice.
|
|
11
|
+
*/
|
|
12
|
+
config?: EasyCookieConfig | null;
|
|
13
|
+
/** Version id being shown (written as `data-version`). */
|
|
14
|
+
version?: string;
|
|
15
|
+
/** Publication date for `{{last-updated}}`. Defaults to now (previews). */
|
|
16
|
+
publishedAt?: string | Date;
|
|
17
|
+
/** Values for `{{site.name}}` / `{{site.domain}}` left in the text. */
|
|
18
|
+
site?: {
|
|
19
|
+
name?: string;
|
|
20
|
+
domain?: string;
|
|
21
|
+
};
|
|
22
|
+
/** Put the title in an `<h1 class="ec-legal__title">` at the top of the HTML. Default true. */
|
|
23
|
+
heading?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Where `{{preferences-link}}` points when the banner is not on the page
|
|
26
|
+
* (e.g. the consent server's hosted page links back to the site). By default
|
|
27
|
+
* it is `href="#" data-ec-open-preferences`, bound by the core runtime.
|
|
28
|
+
*/
|
|
29
|
+
preferencesHref?: string;
|
|
30
|
+
}
|
|
31
|
+
interface RenderedLegalDocument {
|
|
32
|
+
/** Language actually rendered (after fallback). */
|
|
33
|
+
lang: string;
|
|
34
|
+
title: string;
|
|
35
|
+
html: string;
|
|
36
|
+
}
|
|
37
|
+
interface LegalLabels {
|
|
38
|
+
updated: string;
|
|
39
|
+
preferences: string;
|
|
40
|
+
privacyPolicy: string;
|
|
41
|
+
category: string;
|
|
42
|
+
transfer: string;
|
|
43
|
+
noServices: string;
|
|
44
|
+
noConfig: string;
|
|
45
|
+
}
|
|
46
|
+
/** Visitor-facing strings used by the directives. Unknown languages fall back to English. */
|
|
47
|
+
declare const LEGAL_LABELS: Record<'it' | 'en', LegalLabels>;
|
|
48
|
+
/** `[[Something to fill in]]`: a placeholder the owner must replace. */
|
|
49
|
+
declare const PLACEHOLDER_RE: RegExp;
|
|
50
|
+
/** Number of `[[…]]` placeholders left in every title and body. */
|
|
51
|
+
declare function countPlaceholders(content: LegalDocContent | null | undefined): number;
|
|
52
|
+
/** Replace `{{site.name}}` and `{{site.domain}}` in a template text. */
|
|
53
|
+
declare function fillSiteVariables(text: string, site: {
|
|
54
|
+
name?: string;
|
|
55
|
+
domain?: string;
|
|
56
|
+
}): string;
|
|
57
|
+
/**
|
|
58
|
+
* Language to show: `lang` when the document has it, then `defaultLang`, then
|
|
59
|
+
* the first translation. Undefined when there are no translations.
|
|
60
|
+
*/
|
|
61
|
+
declare function pickLegalLanguage(content: LegalDocContent, lang?: string | null, defaultLang?: string | null): string | undefined;
|
|
62
|
+
/** Validate a `LegalDocContent`. Returns an error message or null. */
|
|
63
|
+
declare function legalContentError(value: unknown): string | null;
|
|
64
|
+
/** Only http(s), mailto and relative URLs. */
|
|
65
|
+
declare function isSafeLegalUrl(url: string): boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Render a legal document to safe HTML: Markdown (raw HTML disabled, only
|
|
68
|
+
* http/https/mailto/relative links), directives expanded against `config`,
|
|
69
|
+
* `[[placeholders]]` highlighted. Picks the translation for `lang`, falling
|
|
70
|
+
* back to the config's default language, then to the first translation.
|
|
71
|
+
*/
|
|
72
|
+
declare function renderLegalDocument(content: LegalDocContent, lang: string, opts?: RenderLegalOptions): RenderedLegalDocument;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Built-in starting drafts for the three legal documents, in Italian and
|
|
76
|
+
* English. They are templates, not legal advice: every owner-specific value is
|
|
77
|
+
* a `[[placeholder]]`, and the first line asks for a professional review.
|
|
78
|
+
*/
|
|
79
|
+
declare const LEGAL_TEMPLATES: Record<LegalKind, Record<'it' | 'en', LegalTranslation>>;
|
|
80
|
+
/** Languages the built-in templates are written in. */
|
|
81
|
+
declare const LEGAL_TEMPLATE_LANGUAGES: readonly ["it", "en"];
|
|
82
|
+
/**
|
|
83
|
+
* The built-in template for `kind` in `lang` (unknown languages get English),
|
|
84
|
+
* with `{{site.name}}` / `{{site.domain}}` replaced when `site` is given.
|
|
85
|
+
*/
|
|
86
|
+
declare function legalTemplate(kind: LegalKind, lang: string, site?: {
|
|
87
|
+
name?: string;
|
|
88
|
+
domain?: string;
|
|
89
|
+
}): LegalTranslation;
|
|
90
|
+
|
|
91
|
+
export { LEGAL_LABELS, LEGAL_TEMPLATES, LEGAL_TEMPLATE_LANGUAGES, LegalDocContent, LegalKind, type LegalLabels, LegalTranslation, PLACEHOLDER_RE, type RenderLegalOptions, type RenderedLegalDocument, countPlaceholders, fillSiteVariables, isSafeLegalUrl, legalContentError, legalTemplate, pickLegalLanguage, renderLegalDocument };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
export { A as AutoClearRule, B as BuildPolicyOptions, P as POLICY_LABELS, a as PolicyCategory, b as PolicyCookie, c as PolicyLabels, d as PolicyModel, e as PolicyRow, f as PolicyService, R as RenderPolicyOptions, g as autoClearRules, h as buildPolicyModel, i as escapeHtml, j as formatPolicyDate, m as matchesRule, p as policyRows, k as prettyCookiePattern, r as renderPolicyHtml, l as renderPolicyMarkdown } from './render-DYrvn1cT.js';
|
|
2
|
+
import { EasyCookieConfig } from '@easy-cookie/core/shared';
|
|
3
|
+
import { LegalDocContent, LegalKind, LegalTranslation } from './client.js';
|
|
4
|
+
export { FetchLegalDocumentOptions, LEGAL_KINDS, PublishedLegalDocument, fetchLegalDocument, isLegalKind, legalDocumentUrl } from './client.js';
|
|
5
|
+
|
|
6
|
+
interface RenderLegalOptions {
|
|
7
|
+
/**
|
|
8
|
+
* Banner config used to expand `{{cookie-table}}` and `{{services-list}}`
|
|
9
|
+
* (the published one for visitors, the draft one for previews). Without it
|
|
10
|
+
* those directives render a short notice.
|
|
11
|
+
*/
|
|
12
|
+
config?: EasyCookieConfig | null;
|
|
13
|
+
/** Version id being shown (written as `data-version`). */
|
|
14
|
+
version?: string;
|
|
15
|
+
/** Publication date for `{{last-updated}}`. Defaults to now (previews). */
|
|
16
|
+
publishedAt?: string | Date;
|
|
17
|
+
/** Values for `{{site.name}}` / `{{site.domain}}` left in the text. */
|
|
18
|
+
site?: {
|
|
19
|
+
name?: string;
|
|
20
|
+
domain?: string;
|
|
21
|
+
};
|
|
22
|
+
/** Put the title in an `<h1 class="ec-legal__title">` at the top of the HTML. Default true. */
|
|
23
|
+
heading?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Where `{{preferences-link}}` points when the banner is not on the page
|
|
26
|
+
* (e.g. the consent server's hosted page links back to the site). By default
|
|
27
|
+
* it is `href="#" data-ec-open-preferences`, bound by the core runtime.
|
|
28
|
+
*/
|
|
29
|
+
preferencesHref?: string;
|
|
30
|
+
}
|
|
31
|
+
interface RenderedLegalDocument {
|
|
32
|
+
/** Language actually rendered (after fallback). */
|
|
33
|
+
lang: string;
|
|
34
|
+
title: string;
|
|
35
|
+
html: string;
|
|
36
|
+
}
|
|
37
|
+
interface LegalLabels {
|
|
38
|
+
updated: string;
|
|
39
|
+
preferences: string;
|
|
40
|
+
privacyPolicy: string;
|
|
41
|
+
category: string;
|
|
42
|
+
transfer: string;
|
|
43
|
+
noServices: string;
|
|
44
|
+
noConfig: string;
|
|
45
|
+
}
|
|
46
|
+
/** Visitor-facing strings used by the directives. Unknown languages fall back to English. */
|
|
47
|
+
declare const LEGAL_LABELS: Record<'it' | 'en', LegalLabels>;
|
|
48
|
+
/** `[[Something to fill in]]`: a placeholder the owner must replace. */
|
|
49
|
+
declare const PLACEHOLDER_RE: RegExp;
|
|
50
|
+
/** Number of `[[…]]` placeholders left in every title and body. */
|
|
51
|
+
declare function countPlaceholders(content: LegalDocContent | null | undefined): number;
|
|
52
|
+
/** Replace `{{site.name}}` and `{{site.domain}}` in a template text. */
|
|
53
|
+
declare function fillSiteVariables(text: string, site: {
|
|
54
|
+
name?: string;
|
|
55
|
+
domain?: string;
|
|
56
|
+
}): string;
|
|
57
|
+
/**
|
|
58
|
+
* Language to show: `lang` when the document has it, then `defaultLang`, then
|
|
59
|
+
* the first translation. Undefined when there are no translations.
|
|
60
|
+
*/
|
|
61
|
+
declare function pickLegalLanguage(content: LegalDocContent, lang?: string | null, defaultLang?: string | null): string | undefined;
|
|
62
|
+
/** Validate a `LegalDocContent`. Returns an error message or null. */
|
|
63
|
+
declare function legalContentError(value: unknown): string | null;
|
|
64
|
+
/** Only http(s), mailto and relative URLs. */
|
|
65
|
+
declare function isSafeLegalUrl(url: string): boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Render a legal document to safe HTML: Markdown (raw HTML disabled, only
|
|
68
|
+
* http/https/mailto/relative links), directives expanded against `config`,
|
|
69
|
+
* `[[placeholders]]` highlighted. Picks the translation for `lang`, falling
|
|
70
|
+
* back to the config's default language, then to the first translation.
|
|
71
|
+
*/
|
|
72
|
+
declare function renderLegalDocument(content: LegalDocContent, lang: string, opts?: RenderLegalOptions): RenderedLegalDocument;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Built-in starting drafts for the three legal documents, in Italian and
|
|
76
|
+
* English. They are templates, not legal advice: every owner-specific value is
|
|
77
|
+
* a `[[placeholder]]`, and the first line asks for a professional review.
|
|
78
|
+
*/
|
|
79
|
+
declare const LEGAL_TEMPLATES: Record<LegalKind, Record<'it' | 'en', LegalTranslation>>;
|
|
80
|
+
/** Languages the built-in templates are written in. */
|
|
81
|
+
declare const LEGAL_TEMPLATE_LANGUAGES: readonly ["it", "en"];
|
|
82
|
+
/**
|
|
83
|
+
* The built-in template for `kind` in `lang` (unknown languages get English),
|
|
84
|
+
* with `{{site.name}}` / `{{site.domain}}` replaced when `site` is given.
|
|
85
|
+
*/
|
|
86
|
+
declare function legalTemplate(kind: LegalKind, lang: string, site?: {
|
|
87
|
+
name?: string;
|
|
88
|
+
domain?: string;
|
|
89
|
+
}): LegalTranslation;
|
|
90
|
+
|
|
91
|
+
export { LEGAL_LABELS, LEGAL_TEMPLATES, LEGAL_TEMPLATE_LANGUAGES, LegalDocContent, LegalKind, type LegalLabels, LegalTranslation, PLACEHOLDER_RE, type RenderLegalOptions, type RenderedLegalDocument, countPlaceholders, fillSiteVariables, isSafeLegalUrl, legalContentError, legalTemplate, pickLegalLanguage, renderLegalDocument };
|