@discloai/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +218 -0
- package/dist/discloai.min.js +1 -0
- package/dist/index.d.mts +152 -0
- package/dist/index.d.ts +152 -0
- package/dist/index.js +795 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +764 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +58 -0
- package/src/__tests__/audit.test.ts +117 -0
- package/src/__tests__/init.test.ts +49 -0
- package/src/__tests__/wcag.test.ts +260 -0
- package/src/audit.ts +155 -0
- package/src/components/AIContentLabel.ts +108 -0
- package/src/components/BiometricNotice.ts +82 -0
- package/src/components/ChatbotDisclosure.ts +188 -0
- package/src/components/DeepfakeLabel.ts +123 -0
- package/src/config.ts +191 -0
- package/src/i18n/bg.json +9 -0
- package/src/i18n/cs.json +9 -0
- package/src/i18n/da.json +9 -0
- package/src/i18n/de.json +9 -0
- package/src/i18n/el.json +9 -0
- package/src/i18n/en.json +9 -0
- package/src/i18n/es.json +9 -0
- package/src/i18n/et.json +9 -0
- package/src/i18n/fi.json +9 -0
- package/src/i18n/fr.json +9 -0
- package/src/i18n/ga.json +9 -0
- package/src/i18n/hr.json +9 -0
- package/src/i18n/hu.json +9 -0
- package/src/i18n/index.ts +145 -0
- package/src/i18n/it.json +9 -0
- package/src/i18n/lt.json +9 -0
- package/src/i18n/lv.json +9 -0
- package/src/i18n/mt.json +9 -0
- package/src/i18n/nl.json +9 -0
- package/src/i18n/pl.json +9 -0
- package/src/i18n/pt.json +9 -0
- package/src/i18n/ro.json +9 -0
- package/src/i18n/sk.json +9 -0
- package/src/i18n/sl.json +9 -0
- package/src/i18n/sv.json +9 -0
- package/src/index.ts +19 -0
- package/src/init.ts +56 -0
- package/src/vendors.ts +29 -0
- package/src/version.ts +1 -0
- package/src/wcag.ts +46 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,795 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var src_exports = {};
|
|
22
|
+
__export(src_exports, {
|
|
23
|
+
VENDOR_PRESETS: () => VENDOR_PRESETS,
|
|
24
|
+
init: () => init,
|
|
25
|
+
resolveVendorSelector: () => resolveVendorSelector,
|
|
26
|
+
sanitizeCSS: () => sanitizeCSS,
|
|
27
|
+
sendAuditEvent: () => sendAuditEvent
|
|
28
|
+
});
|
|
29
|
+
module.exports = __toCommonJS(src_exports);
|
|
30
|
+
|
|
31
|
+
// src/config.ts
|
|
32
|
+
var DEFAULTS = {
|
|
33
|
+
locale: "en"
|
|
34
|
+
};
|
|
35
|
+
var FORBIDDEN_CSS_PATTERNS = [
|
|
36
|
+
/url\s*\(/i,
|
|
37
|
+
/@import/i,
|
|
38
|
+
/expression\s*\(/i,
|
|
39
|
+
/javascript:/i
|
|
40
|
+
];
|
|
41
|
+
function sanitizeCSS(css) {
|
|
42
|
+
const normalized = css.replace(/\\[0-9a-fA-F]{1,6}\s?/g, "ESCAPED");
|
|
43
|
+
for (const pattern of FORBIDDEN_CSS_PATTERNS) {
|
|
44
|
+
if (pattern.test(normalized)) {
|
|
45
|
+
console.warn("[DiscloAI] Custom CSS blocked: forbidden pattern detected");
|
|
46
|
+
return "";
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return css;
|
|
50
|
+
}
|
|
51
|
+
async function fetchRemoteConfig(siteId, configEndpoint) {
|
|
52
|
+
const controller = new AbortController();
|
|
53
|
+
const timeoutId = setTimeout(() => controller.abort(), 2e3);
|
|
54
|
+
const defaultUrl = `https://api.discloai.com/v1/config/${encodeURIComponent(siteId)}`;
|
|
55
|
+
const rawUrl = configEndpoint ?? defaultUrl;
|
|
56
|
+
const isLocalDev = rawUrl.startsWith("http://localhost") || rawUrl.startsWith("http://127.0.0.1");
|
|
57
|
+
const url = rawUrl.startsWith("https://") || isLocalDev ? rawUrl : defaultUrl;
|
|
58
|
+
try {
|
|
59
|
+
const response = await fetch(url, { signal: controller.signal });
|
|
60
|
+
if (!response.ok) return null;
|
|
61
|
+
const raw = await response.json();
|
|
62
|
+
return extractSafeConfigShape(raw);
|
|
63
|
+
} catch {
|
|
64
|
+
return null;
|
|
65
|
+
} finally {
|
|
66
|
+
clearTimeout(timeoutId);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function extractSafeConfigShape(raw) {
|
|
70
|
+
if (typeof raw !== "object" || raw === null) return null;
|
|
71
|
+
const obj = raw;
|
|
72
|
+
const safe = {};
|
|
73
|
+
if (typeof obj["locale"] === "string") {
|
|
74
|
+
safe.locale = obj["locale"];
|
|
75
|
+
}
|
|
76
|
+
if (typeof obj["chatbotDisclosure"] === "object" && obj["chatbotDisclosure"] !== null) {
|
|
77
|
+
safe.chatbotDisclosure = obj["chatbotDisclosure"];
|
|
78
|
+
}
|
|
79
|
+
if (typeof obj["aiContentLabel"] === "object" && obj["aiContentLabel"] !== null) {
|
|
80
|
+
safe.aiContentLabel = obj["aiContentLabel"];
|
|
81
|
+
}
|
|
82
|
+
if (typeof obj["deepfakeLabel"] === "object" && obj["deepfakeLabel"] !== null) {
|
|
83
|
+
safe.deepfakeLabel = obj["deepfakeLabel"];
|
|
84
|
+
}
|
|
85
|
+
if (typeof obj["biometricNotice"] === "object" && obj["biometricNotice"] !== null) {
|
|
86
|
+
safe.biometricNotice = obj["biometricNotice"];
|
|
87
|
+
}
|
|
88
|
+
return safe;
|
|
89
|
+
}
|
|
90
|
+
async function resolveConfig(local) {
|
|
91
|
+
const remote = await fetchRemoteConfig(local.siteId, local.configEndpoint);
|
|
92
|
+
return {
|
|
93
|
+
siteId: local.siteId,
|
|
94
|
+
locale: local.locale ?? remote?.locale ?? DEFAULTS.locale,
|
|
95
|
+
chatbotDisclosure: local.chatbotDisclosure ?? remote?.chatbotDisclosure,
|
|
96
|
+
aiContentLabel: local.aiContentLabel ?? remote?.aiContentLabel,
|
|
97
|
+
deepfakeLabel: local.deepfakeLabel ?? remote?.deepfakeLabel,
|
|
98
|
+
biometricNotice: local.biometricNotice ?? remote?.biometricNotice
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// src/audit.ts
|
|
103
|
+
var DEFAULT_AUDIT_ENDPOINT = "https://app.discloai.com/api/v1/audit/event";
|
|
104
|
+
async function sha256Hex(input) {
|
|
105
|
+
const encoded = new TextEncoder().encode(input);
|
|
106
|
+
const buffer = await crypto.subtle.digest("SHA-256", encoded);
|
|
107
|
+
return hexFromBuffer(buffer);
|
|
108
|
+
}
|
|
109
|
+
function hexFromBuffer(buffer) {
|
|
110
|
+
return Array.from(new Uint8Array(buffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
111
|
+
}
|
|
112
|
+
async function sendAuditEvent(params) {
|
|
113
|
+
try {
|
|
114
|
+
const cfg = typeof window !== "undefined" ? window.__DISCLOAI_CONFIG__ ?? {} : {};
|
|
115
|
+
const siteId = cfg.siteId ?? "";
|
|
116
|
+
const rawEndpoint = cfg.auditEndpoint ?? DEFAULT_AUDIT_ENDPOINT;
|
|
117
|
+
const isLocalDev = rawEndpoint.startsWith("http://localhost") || rawEndpoint.startsWith("http://127.0.0.1");
|
|
118
|
+
const endpoint = rawEndpoint.startsWith("https://") || isLocalDev ? rawEndpoint : DEFAULT_AUDIT_ENDPOINT;
|
|
119
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
120
|
+
const pageHref = typeof globalThis.location !== "undefined" ? globalThis.location.href : "";
|
|
121
|
+
const [pageUrlHash, sessionHash] = await Promise.all([
|
|
122
|
+
sha256Hex(pageHref),
|
|
123
|
+
sha256Hex(params.sessionId)
|
|
124
|
+
]);
|
|
125
|
+
const body = JSON.stringify({
|
|
126
|
+
siteId,
|
|
127
|
+
timestamp,
|
|
128
|
+
// C-1: No signature — authentication is via Origin header on the server
|
|
129
|
+
pageUrlHash,
|
|
130
|
+
sessionHash,
|
|
131
|
+
disclosureType: params.disclosureType,
|
|
132
|
+
componentVersion: params.componentVersion,
|
|
133
|
+
rendered: params.rendered ?? true
|
|
134
|
+
});
|
|
135
|
+
const blob = new Blob([body], { type: "application/json" });
|
|
136
|
+
if (typeof navigator !== "undefined" && typeof navigator.sendBeacon === "function") {
|
|
137
|
+
navigator.sendBeacon(endpoint, blob);
|
|
138
|
+
} else {
|
|
139
|
+
void fetch(endpoint, {
|
|
140
|
+
method: "POST",
|
|
141
|
+
body: blob,
|
|
142
|
+
keepalive: true
|
|
143
|
+
}).catch(() => {
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
} catch {
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// src/i18n/en.json
|
|
151
|
+
var en_default = {
|
|
152
|
+
"chatbot.disclosure.default": "You are talking to an AI assistant.",
|
|
153
|
+
"chatbot.disclosure.prominent": "This chat is powered by artificial intelligence.",
|
|
154
|
+
"content.label.default": "AI-generated content",
|
|
155
|
+
"content.label.artistic": "AI-assisted creative work",
|
|
156
|
+
"deepfake.label.default": "AI-generated image",
|
|
157
|
+
"deepfake.label.artistic": "AI-generated artistic content",
|
|
158
|
+
"biometric.notice.default": "This system processes biometric data. EU AI Act Article 50 \xA73 applies."
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
// src/i18n/fr.json
|
|
162
|
+
var fr_default = {
|
|
163
|
+
"chatbot.disclosure.default": "Vous discutez avec un assistant IA.",
|
|
164
|
+
"chatbot.disclosure.prominent": "Cette conversation est aliment\xE9e par l'intelligence artificielle.",
|
|
165
|
+
"content.label.default": "Contenu g\xE9n\xE9r\xE9 par IA",
|
|
166
|
+
"content.label.artistic": "\u0152uvre cr\xE9ative assist\xE9e par IA",
|
|
167
|
+
"deepfake.label.default": "Image g\xE9n\xE9r\xE9e par IA",
|
|
168
|
+
"deepfake.label.artistic": "Contenu artistique g\xE9n\xE9r\xE9 par IA",
|
|
169
|
+
"biometric.notice.default": "Ce syst\xE8me traite des donn\xE9es biom\xE9triques. L'article 50 \xA73 de la loi europ\xE9enne sur l'IA s'applique."
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
// src/i18n/de.json
|
|
173
|
+
var de_default = {
|
|
174
|
+
"chatbot.disclosure.default": "Sie sprechen mit einem KI-Assistenten.",
|
|
175
|
+
"chatbot.disclosure.prominent": "Dieser Chat wird durch k\xFCnstliche Intelligenz betrieben.",
|
|
176
|
+
"content.label.default": "KI-generierter Inhalt",
|
|
177
|
+
"content.label.artistic": "KI-unterst\xFCtztes kreatives Werk",
|
|
178
|
+
"deepfake.label.default": "KI-generiertes Bild",
|
|
179
|
+
"deepfake.label.artistic": "KI-generierter k\xFCnstlerischer Inhalt",
|
|
180
|
+
"biometric.notice.default": "Dieses System verarbeitet biometrische Daten. EU-KI-Gesetz Artikel 50 \xA73 gilt."
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
// src/i18n/es.json
|
|
184
|
+
var es_default = {
|
|
185
|
+
"chatbot.disclosure.default": "Est\xE1s hablando con un asistente de IA.",
|
|
186
|
+
"chatbot.disclosure.prominent": "Este chat est\xE1 impulsado por inteligencia artificial.",
|
|
187
|
+
"content.label.default": "Contenido generado por IA",
|
|
188
|
+
"content.label.artistic": "Obra creativa asistida por IA",
|
|
189
|
+
"deepfake.label.default": "Imagen generada por IA",
|
|
190
|
+
"deepfake.label.artistic": "Contenido art\xEDstico generado por IA",
|
|
191
|
+
"biometric.notice.default": "Este sistema procesa datos biom\xE9tricos. Se aplica el art\xEDculo 50 \xA73 de la Ley de IA de la UE."
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
// src/i18n/bg.json
|
|
195
|
+
var bg_default = {
|
|
196
|
+
"chatbot.disclosure.default": "\u0420\u0430\u0437\u0433\u043E\u0432\u0430\u0440\u044F\u0442\u0435 \u0441 AI \u0430\u0441\u0438\u0441\u0442\u0435\u043D\u0442.",
|
|
197
|
+
"chatbot.disclosure.prominent": "\u0422\u043E\u0437\u0438 \u0447\u0430\u0442 \u0435 \u0437\u0430\u0445\u0440\u0430\u043D\u0432\u0430\u043D \u043E\u0442 \u0438\u0437\u043A\u0443\u0441\u0442\u0432\u0435\u043D \u0438\u043D\u0442\u0435\u043B\u0435\u043A\u0442.",
|
|
198
|
+
"content.label.default": "\u0421\u044A\u0434\u044A\u0440\u0436\u0430\u043D\u0438\u0435, \u0433\u0435\u043D\u0435\u0440\u0438\u0440\u0430\u043D\u043E \u043E\u0442 AI",
|
|
199
|
+
"content.label.artistic": "\u0422\u0432\u043E\u0440\u0447\u0435\u0441\u043A\u0430 \u0440\u0430\u0431\u043E\u0442\u0430 \u0441 \u043F\u043E\u043C\u043E\u0449\u0442\u0430 \u043D\u0430 AI",
|
|
200
|
+
"deepfake.label.default": "AI-\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u0430\u043D\u043E \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435",
|
|
201
|
+
"deepfake.label.artistic": "AI-\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u0430\u043D\u043E \u0445\u0443\u0434\u043E\u0436\u0435\u0441\u0442\u0432\u0435\u043D\u043E \u0441\u044A\u0434\u044A\u0440\u0436\u0430\u043D\u0438\u0435",
|
|
202
|
+
"biometric.notice.default": "\u0422\u0430\u0437\u0438 \u0441\u0438\u0441\u0442\u0435\u043C\u0430 \u043E\u0431\u0440\u0430\u0431\u043E\u0442\u0432\u0430 \u0431\u0438\u043E\u043C\u0435\u0442\u0440\u0438\u0447\u043D\u0438 \u0434\u0430\u043D\u043D\u0438. \u041F\u0440\u0438\u043B\u0430\u0433\u0430 \u0441\u0435 \u0427\u043B\u0435\u043D 50 \xA73 \u043E\u0442 \u0417\u0430\u043A\u043E\u043D\u0430 \u0437\u0430 AI \u043D\u0430 \u0415\u0421."
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
// src/i18n/hr.json
|
|
206
|
+
var hr_default = {
|
|
207
|
+
"chatbot.disclosure.default": "Razgovarate s AI asistentom.",
|
|
208
|
+
"chatbot.disclosure.prominent": "Ovaj chat pokre\u0107e umjetna inteligencija.",
|
|
209
|
+
"content.label.default": "Sadr\u017Eaj generiran AI-jem",
|
|
210
|
+
"content.label.artistic": "Kreativni rad uz pomo\u0107 AI-ja",
|
|
211
|
+
"deepfake.label.default": "AI-generirana slika",
|
|
212
|
+
"deepfake.label.artistic": "AI-generirani umjetni\u010Dki sadr\u017Eaj",
|
|
213
|
+
"biometric.notice.default": "Ovaj sustav obra\u0111uje biometrijske podatke. Primjenjuje se \u010Clanak 50 \xA73 Zakona EU o AI."
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
// src/i18n/cs.json
|
|
217
|
+
var cs_default = {
|
|
218
|
+
"chatbot.disclosure.default": "Mluv\xEDte s AI asistentem.",
|
|
219
|
+
"chatbot.disclosure.prominent": "Tento chat je poh\xE1n\u011Bn um\u011Blou inteligenc\xED.",
|
|
220
|
+
"content.label.default": "Obsah generovan\xFD AI",
|
|
221
|
+
"content.label.artistic": "Kreativn\xED pr\xE1ce s pomoc\xED AI",
|
|
222
|
+
"deepfake.label.default": "Obr\xE1zek generovan\xFD AI",
|
|
223
|
+
"deepfake.label.artistic": "Um\u011Bleck\xFD obsah generovan\xFD AI",
|
|
224
|
+
"biometric.notice.default": "Tento syst\xE9m zpracov\xE1v\xE1 biometrick\xE9 \xFAdaje. Plat\xED \u010Dl. 50 \xA73 z\xE1kona EU o AI."
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
// src/i18n/da.json
|
|
228
|
+
var da_default = {
|
|
229
|
+
"chatbot.disclosure.default": "Du taler med en AI-assistent.",
|
|
230
|
+
"chatbot.disclosure.prominent": "Denne chat drives af kunstig intelligens.",
|
|
231
|
+
"content.label.default": "AI-genereret indhold",
|
|
232
|
+
"content.label.artistic": "AI-assisteret kreativt arbejde",
|
|
233
|
+
"deepfake.label.default": "AI-genereret billede",
|
|
234
|
+
"deepfake.label.artistic": "AI-genereret kunstnerisk indhold",
|
|
235
|
+
"biometric.notice.default": "Dette system behandler biometriske data. EU AI Act artikel 50 \xA73 finder anvendelse."
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
// src/i18n/el.json
|
|
239
|
+
var el_default = {
|
|
240
|
+
"chatbot.disclosure.default": "\u039C\u03B9\u03BB\u03AC\u03C4\u03B5 \u03BC\u03B5 \u03AD\u03BD\u03B1\u03BD \u03B2\u03BF\u03B7\u03B8\u03CC AI.",
|
|
241
|
+
"chatbot.disclosure.prominent": "\u0391\u03C5\u03C4\u03AE \u03B7 \u03C3\u03C5\u03BD\u03BF\u03BC\u03B9\u03BB\u03AF\u03B1 \u03C4\u03C1\u03BF\u03C6\u03BF\u03B4\u03BF\u03C4\u03B5\u03AF\u03C4\u03B1\u03B9 \u03B1\u03C0\u03CC \u03C4\u03B5\u03C7\u03BD\u03B7\u03C4\u03AE \u03BD\u03BF\u03B7\u03BC\u03BF\u03C3\u03CD\u03BD\u03B7.",
|
|
242
|
+
"content.label.default": "\u03A0\u03B5\u03C1\u03B9\u03B5\u03C7\u03CC\u03BC\u03B5\u03BD\u03BF \u03C0\u03BF\u03C5 \u03B4\u03B7\u03BC\u03B9\u03BF\u03C5\u03C1\u03B3\u03AE\u03B8\u03B7\u03BA\u03B5 \u03B1\u03C0\u03CC AI",
|
|
243
|
+
"content.label.artistic": "\u0394\u03B7\u03BC\u03B9\u03BF\u03C5\u03C1\u03B3\u03B9\u03BA\u03AE \u03B5\u03C1\u03B3\u03B1\u03C3\u03AF\u03B1 \u03BC\u03B5 \u03B2\u03BF\u03AE\u03B8\u03B5\u03B9\u03B1 AI",
|
|
244
|
+
"deepfake.label.default": "\u0395\u03B9\u03BA\u03CC\u03BD\u03B1 \u03C0\u03BF\u03C5 \u03B4\u03B7\u03BC\u03B9\u03BF\u03C5\u03C1\u03B3\u03AE\u03B8\u03B7\u03BA\u03B5 \u03B1\u03C0\u03CC AI",
|
|
245
|
+
"deepfake.label.artistic": "\u039A\u03B1\u03BB\u03BB\u03B9\u03C4\u03B5\u03C7\u03BD\u03B9\u03BA\u03CC \u03C0\u03B5\u03C1\u03B9\u03B5\u03C7\u03CC\u03BC\u03B5\u03BD\u03BF \u03C0\u03BF\u03C5 \u03B4\u03B7\u03BC\u03B9\u03BF\u03C5\u03C1\u03B3\u03AE\u03B8\u03B7\u03BA\u03B5 \u03B1\u03C0\u03CC AI",
|
|
246
|
+
"biometric.notice.default": "\u0391\u03C5\u03C4\u03CC \u03C4\u03BF \u03C3\u03CD\u03C3\u03C4\u03B7\u03BC\u03B1 \u03B5\u03C0\u03B5\u03BE\u03B5\u03C1\u03B3\u03AC\u03B6\u03B5\u03C4\u03B1\u03B9 \u03B2\u03B9\u03BF\u03BC\u03B5\u03C4\u03C1\u03B9\u03BA\u03AC \u03B4\u03B5\u03B4\u03BF\u03BC\u03AD\u03BD\u03B1. \u0399\u03C3\u03C7\u03CD\u03B5\u03B9 \u0386\u03C1\u03B8\u03C1\u03BF 50 \xA73 \u039D\u03CC\u03BC\u03BF\u03C5 \u0395\u0395 \u03B3\u03B9\u03B1 AI."
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
// src/i18n/et.json
|
|
250
|
+
var et_default = {
|
|
251
|
+
"chatbot.disclosure.default": "R\xE4\xE4gite AI-assistendiga.",
|
|
252
|
+
"chatbot.disclosure.prominent": "Seda vestlust k\xE4itab tehisintellekt.",
|
|
253
|
+
"content.label.default": "AI loodud sisu",
|
|
254
|
+
"content.label.artistic": "AI-abistatud loominguline t\xF6\xF6",
|
|
255
|
+
"deepfake.label.default": "AI loodud pilt",
|
|
256
|
+
"deepfake.label.artistic": "AI loodud kunstiline sisu",
|
|
257
|
+
"biometric.notice.default": "See s\xFCsteem t\xF6\xF6tleb biomeetrilisi andmeid. Kohaldub EL AI seaduse artikkel 50 \xA73."
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
// src/i18n/fi.json
|
|
261
|
+
var fi_default = {
|
|
262
|
+
"chatbot.disclosure.default": "Puhut AI-assistentin kanssa.",
|
|
263
|
+
"chatbot.disclosure.prominent": "T\xE4m\xE4 chat toimii teko\xE4lyn avulla.",
|
|
264
|
+
"content.label.default": "Teko\xE4lyn tuottama sis\xE4lt\xF6",
|
|
265
|
+
"content.label.artistic": "Teko\xE4lyavusteinen luova ty\xF6",
|
|
266
|
+
"deepfake.label.default": "Teko\xE4lyn luoma kuva",
|
|
267
|
+
"deepfake.label.artistic": "Teko\xE4lyn luoma taiteellinen sis\xE4lt\xF6",
|
|
268
|
+
"biometric.notice.default": "T\xE4m\xE4 j\xE4rjestelm\xE4 k\xE4sittelee biometrisi\xE4 tietoja. EU:n teko\xE4lylain 50 artiklan 3 kohta soveltuu."
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
// src/i18n/ga.json
|
|
272
|
+
var ga_default = {
|
|
273
|
+
"chatbot.disclosure.default": "T\xE1 t\xFA ag caint le c\xFAnt\xF3ir AI.",
|
|
274
|
+
"chatbot.disclosure.prominent": "T\xE1 an comhr\xE1 seo faoi chumhacht na hintleachta saorga.",
|
|
275
|
+
"content.label.default": "\xC1bhar arna ghini\xFAint ag AI",
|
|
276
|
+
"content.label.artistic": "Obair chruthaitheach le c\xFAnamh AI",
|
|
277
|
+
"deepfake.label.default": "\xCDomh\xE1 arna ghini\xFAint ag AI",
|
|
278
|
+
"deepfake.label.artistic": "\xC1bhar eala\xEDne arna ghini\xFAint ag AI",
|
|
279
|
+
"biometric.notice.default": "Pr\xF3ise\xE1lann an c\xF3ras seo sonra\xED bithfh\xE9ini\xFAlachta. T\xE1 Airteagal 50 \xA73 de Dhl\xED AI an AE infheidhme."
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
// src/i18n/hu.json
|
|
283
|
+
var hu_default = {
|
|
284
|
+
"chatbot.disclosure.default": "AI-asszisztenssel besz\xE9l.",
|
|
285
|
+
"chatbot.disclosure.prominent": "Ez a cseveg\xE9s mesters\xE9ges intelligencia \xE1ltal m\u0171k\xF6dik.",
|
|
286
|
+
"content.label.default": "AI \xE1ltal gener\xE1lt tartalom",
|
|
287
|
+
"content.label.artistic": "AI-val t\xE1mogatott kreat\xEDv munka",
|
|
288
|
+
"deepfake.label.default": "AI \xE1ltal gener\xE1lt k\xE9p",
|
|
289
|
+
"deepfake.label.artistic": "AI \xE1ltal gener\xE1lt m\u0171v\xE9szeti tartalom",
|
|
290
|
+
"biometric.notice.default": "Ez a rendszer biometrikus adatokat dolgoz fel. Az EU MI-t\xF6rv\xE9ny 50. cikk 3. \xA7-a alkalmazand\xF3."
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
// src/i18n/it.json
|
|
294
|
+
var it_default = {
|
|
295
|
+
"chatbot.disclosure.default": "Stai parlando con un assistente AI.",
|
|
296
|
+
"chatbot.disclosure.prominent": "Questa chat \xE8 alimentata dall'intelligenza artificiale.",
|
|
297
|
+
"content.label.default": "Contenuto generato dall'AI",
|
|
298
|
+
"content.label.artistic": "Lavoro creativo assistito dall'AI",
|
|
299
|
+
"deepfake.label.default": "Immagine generata dall'AI",
|
|
300
|
+
"deepfake.label.artistic": "Contenuto artistico generato dall'AI",
|
|
301
|
+
"biometric.notice.default": "Questo sistema elabora dati biometrici. Si applica l'Articolo 50 \xA73 della Legge AI dell'UE."
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
// src/i18n/lv.json
|
|
305
|
+
var lv_default = {
|
|
306
|
+
"chatbot.disclosure.default": "J\u016Bs run\u0101jat ar AI asistentu.",
|
|
307
|
+
"chatbot.disclosure.prominent": "\u0160o t\u0113rz\u0113\u0161anu darbina m\u0101ksl\u012Bgais intelekts.",
|
|
308
|
+
"content.label.default": "AI \u0123ener\u0113ts saturs",
|
|
309
|
+
"content.label.artistic": "AI asist\u0113ts rado\u0161s darbs",
|
|
310
|
+
"deepfake.label.default": "AI \u0123ener\u0113ts att\u0113ls",
|
|
311
|
+
"deepfake.label.artistic": "AI \u0123ener\u0113ts m\u0101ksliniecisks saturs",
|
|
312
|
+
"biometric.notice.default": "\u0160\u012B sist\u0113ma apstr\u0101d\u0101 biometriskos datus. Piem\u0113rojams ES MI likuma 50. pants \xA73."
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
// src/i18n/lt.json
|
|
316
|
+
var lt_default = {
|
|
317
|
+
"chatbot.disclosure.default": "J\u016Bs kalbat\u0117s su AI asistentu.",
|
|
318
|
+
"chatbot.disclosure.prominent": "\u0160is pokalbis vyksta dirbtinio intelekto pagalba.",
|
|
319
|
+
"content.label.default": "AI sugeneruotas turinys",
|
|
320
|
+
"content.label.artistic": "AI padedamas k\u016Brybinis darbas",
|
|
321
|
+
"deepfake.label.default": "AI sugeneruotas vaizdas",
|
|
322
|
+
"deepfake.label.artistic": "AI sugeneruotas meninis turinys",
|
|
323
|
+
"biometric.notice.default": "\u0160i sistema apdoroja biometrinius duomenis. Taikomas ES DI \u012Fstatymo 50 straipsnio 3 dalis."
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
// src/i18n/mt.json
|
|
327
|
+
var mt_default = {
|
|
328
|
+
"chatbot.disclosure.default": "Qed titkellem ma' assistent AI.",
|
|
329
|
+
"chatbot.disclosure.prominent": "Dan il-chat huwa m\u0127addem mill-intelli\u0121enza artifi\u010Bjali.",
|
|
330
|
+
"content.label.default": "Kontenut i\u0121\u0121enerat minn AI",
|
|
331
|
+
"content.label.artistic": "Xog\u0127ol kreattiv assistit minn AI",
|
|
332
|
+
"deepfake.label.default": "Imma\u0121ni i\u0121\u0121enerata minn AI",
|
|
333
|
+
"deepfake.label.artistic": "Kontenut artistiku i\u0121\u0121enerat minn AI",
|
|
334
|
+
"biometric.notice.default": "Dan is-sistema tippro\u010Bessa data bijometrika. Japplika l-Artikolu 50 \xA73 tal-Li\u0121i AI tal-UE."
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
// src/i18n/nl.json
|
|
338
|
+
var nl_default = {
|
|
339
|
+
"chatbot.disclosure.default": "U praat met een AI-assistent.",
|
|
340
|
+
"chatbot.disclosure.prominent": "Deze chat wordt aangedreven door kunstmatige intelligentie.",
|
|
341
|
+
"content.label.default": "AI-gegenereerde inhoud",
|
|
342
|
+
"content.label.artistic": "AI-ondersteund creatief werk",
|
|
343
|
+
"deepfake.label.default": "AI-gegenereerde afbeelding",
|
|
344
|
+
"deepfake.label.artistic": "AI-gegenereerde artistieke inhoud",
|
|
345
|
+
"biometric.notice.default": "Dit systeem verwerkt biometrische gegevens. EU AI-wet artikel 50 \xA73 is van toepassing."
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
// src/i18n/pl.json
|
|
349
|
+
var pl_default = {
|
|
350
|
+
"chatbot.disclosure.default": "Rozmawiasz z asystentem AI.",
|
|
351
|
+
"chatbot.disclosure.prominent": "Ten czat jest obs\u0142ugiwany przez sztuczn\u0105 inteligencj\u0119.",
|
|
352
|
+
"content.label.default": "Tre\u015B\u0107 wygenerowana przez AI",
|
|
353
|
+
"content.label.artistic": "Praca tw\xF3rcza wspierana przez AI",
|
|
354
|
+
"deepfake.label.default": "Obraz wygenerowany przez AI",
|
|
355
|
+
"deepfake.label.artistic": "Artystyczne tre\u015Bci wygenerowane przez AI",
|
|
356
|
+
"biometric.notice.default": "Ten system przetwarza dane biometryczne. Stosuje si\u0119 art. 50 \xA73 Ustawy UE o AI."
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
// src/i18n/pt.json
|
|
360
|
+
var pt_default = {
|
|
361
|
+
"chatbot.disclosure.default": "Voc\xEA est\xE1 falando com um assistente de IA.",
|
|
362
|
+
"chatbot.disclosure.prominent": "Este chat \xE9 alimentado por intelig\xEAncia artificial.",
|
|
363
|
+
"content.label.default": "Conte\xFAdo gerado por IA",
|
|
364
|
+
"content.label.artistic": "Trabalho criativo assistido por IA",
|
|
365
|
+
"deepfake.label.default": "Imagem gerada por IA",
|
|
366
|
+
"deepfake.label.artistic": "Conte\xFAdo art\xEDstico gerado por IA",
|
|
367
|
+
"biometric.notice.default": "Este sistema processa dados biom\xE9tricos. Aplica-se o Artigo 50 \xA73 da Lei de IA da UE."
|
|
368
|
+
};
|
|
369
|
+
|
|
370
|
+
// src/i18n/ro.json
|
|
371
|
+
var ro_default = {
|
|
372
|
+
"chatbot.disclosure.default": "Vorbi\u021Bi cu un asistent AI.",
|
|
373
|
+
"chatbot.disclosure.prominent": "Acest chat este alimentat de inteligen\u021Ba artificial\u0103.",
|
|
374
|
+
"content.label.default": "Con\u021Binut generat de AI",
|
|
375
|
+
"content.label.artistic": "Lucrare creativ\u0103 asistat\u0103 de AI",
|
|
376
|
+
"deepfake.label.default": "Imagine generat\u0103 de AI",
|
|
377
|
+
"deepfake.label.artistic": "Con\u021Binut artistic generat de AI",
|
|
378
|
+
"biometric.notice.default": "Acest sistem proceseaz\u0103 date biometrice. Se aplic\u0103 Articolul 50 \xA73 din Legea AI a UE."
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
// src/i18n/sk.json
|
|
382
|
+
var sk_default = {
|
|
383
|
+
"chatbot.disclosure.default": "Hovor\xEDte s AI asistentom.",
|
|
384
|
+
"chatbot.disclosure.prominent": "Tento chat je poh\xE1\u0148an\xFD umelou inteligenciou.",
|
|
385
|
+
"content.label.default": "Obsah generovan\xFD AI",
|
|
386
|
+
"content.label.artistic": "Kreat\xEDvna pr\xE1ca s pomocou AI",
|
|
387
|
+
"deepfake.label.default": "Obr\xE1zok generovan\xFD AI",
|
|
388
|
+
"deepfake.label.artistic": "Umeleck\xFD obsah generovan\xFD AI",
|
|
389
|
+
"biometric.notice.default": "Tento syst\xE9m sprac\xFAva biometrick\xE9 \xFAdaje. Plat\xED \u010Dl. 50 \xA73 z\xE1kona E\xDA o AI."
|
|
390
|
+
};
|
|
391
|
+
|
|
392
|
+
// src/i18n/sl.json
|
|
393
|
+
var sl_default = {
|
|
394
|
+
"chatbot.disclosure.default": "Pogovarjate se z AI pomo\u010Dnikom.",
|
|
395
|
+
"chatbot.disclosure.prominent": "Ta klepet poganja umetna inteligenca.",
|
|
396
|
+
"content.label.default": "Vsebina, ustvarjena z AI",
|
|
397
|
+
"content.label.artistic": "Ustvarjalno delo s pomo\u010Djo AI",
|
|
398
|
+
"deepfake.label.default": "Slika, ustvarjena z AI",
|
|
399
|
+
"deepfake.label.artistic": "Umetni\u0161ka vsebina, ustvarjena z AI",
|
|
400
|
+
"biometric.notice.default": "Ta sistem obdeluje biometri\u010Dne podatke. Velja \u010Clen 50 \xA73 Zakona EU o AI."
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
// src/i18n/sv.json
|
|
404
|
+
var sv_default = {
|
|
405
|
+
"chatbot.disclosure.default": "Du pratar med en AI-assistent.",
|
|
406
|
+
"chatbot.disclosure.prominent": "Denna chatt drivs av artificiell intelligens.",
|
|
407
|
+
"content.label.default": "AI-genererat inneh\xE5ll",
|
|
408
|
+
"content.label.artistic": "AI-assisterat kreativt arbete",
|
|
409
|
+
"deepfake.label.default": "AI-genererad bild",
|
|
410
|
+
"deepfake.label.artistic": "AI-genererat konstn\xE4rligt inneh\xE5ll",
|
|
411
|
+
"biometric.notice.default": "Detta system behandlar biometriska uppgifter. EU AI-lagens artikel 50 \xA73 \xE4r till\xE4mplig."
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
// src/i18n/index.ts
|
|
415
|
+
var SUPPORTED_LOCALES = [
|
|
416
|
+
"bg",
|
|
417
|
+
"hr",
|
|
418
|
+
"cs",
|
|
419
|
+
"da",
|
|
420
|
+
"de",
|
|
421
|
+
"el",
|
|
422
|
+
"en",
|
|
423
|
+
"es",
|
|
424
|
+
"et",
|
|
425
|
+
"fi",
|
|
426
|
+
"fr",
|
|
427
|
+
"ga",
|
|
428
|
+
"hu",
|
|
429
|
+
"it",
|
|
430
|
+
"lv",
|
|
431
|
+
"lt",
|
|
432
|
+
"mt",
|
|
433
|
+
"nl",
|
|
434
|
+
"pl",
|
|
435
|
+
"pt",
|
|
436
|
+
"ro",
|
|
437
|
+
"sk",
|
|
438
|
+
"sl",
|
|
439
|
+
"sv"
|
|
440
|
+
];
|
|
441
|
+
var messages = {
|
|
442
|
+
bg: bg_default,
|
|
443
|
+
hr: hr_default,
|
|
444
|
+
cs: cs_default,
|
|
445
|
+
da: da_default,
|
|
446
|
+
de: de_default,
|
|
447
|
+
el: el_default,
|
|
448
|
+
en: en_default,
|
|
449
|
+
es: es_default,
|
|
450
|
+
et: et_default,
|
|
451
|
+
fi: fi_default,
|
|
452
|
+
fr: fr_default,
|
|
453
|
+
ga: ga_default,
|
|
454
|
+
hu: hu_default,
|
|
455
|
+
it: it_default,
|
|
456
|
+
lv: lv_default,
|
|
457
|
+
lt: lt_default,
|
|
458
|
+
mt: mt_default,
|
|
459
|
+
nl: nl_default,
|
|
460
|
+
pl: pl_default,
|
|
461
|
+
pt: pt_default,
|
|
462
|
+
ro: ro_default,
|
|
463
|
+
sk: sk_default,
|
|
464
|
+
sl: sl_default,
|
|
465
|
+
sv: sv_default
|
|
466
|
+
};
|
|
467
|
+
function resolveLocale() {
|
|
468
|
+
if (typeof navigator === "undefined") return "en";
|
|
469
|
+
const lang = navigator.language;
|
|
470
|
+
if (SUPPORTED_LOCALES.includes(lang)) return lang;
|
|
471
|
+
const prefix = lang.split("-")[0];
|
|
472
|
+
if (prefix !== void 0 && SUPPORTED_LOCALES.includes(prefix)) {
|
|
473
|
+
return prefix;
|
|
474
|
+
}
|
|
475
|
+
return "en";
|
|
476
|
+
}
|
|
477
|
+
function t(key, locale) {
|
|
478
|
+
const resolved = locale ?? resolveLocale();
|
|
479
|
+
const dict = messages[resolved];
|
|
480
|
+
const value = dict[key];
|
|
481
|
+
if (value !== void 0) return value;
|
|
482
|
+
const fallback = messages["en"][key];
|
|
483
|
+
if (fallback !== void 0) return fallback;
|
|
484
|
+
return key;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// src/version.ts
|
|
488
|
+
var VERSION = "0.1.0";
|
|
489
|
+
|
|
490
|
+
// src/components/AIContentLabel.ts
|
|
491
|
+
var DEFAULT_LABEL_CSS = '[data-discloai-label="ai-content"] { position: relative; display: inline-block; background: #e0e7ff; color: #3730a3; font-size: 0.75rem; padding: 2px 6px; border-radius: 3px; font-family: sans-serif; white-space: nowrap; }';
|
|
492
|
+
function renderAIContentLabel(siteId, config, cspNonce) {
|
|
493
|
+
try {
|
|
494
|
+
if (typeof document === "undefined") return;
|
|
495
|
+
if (config.exemptions?.editorialControl === true && typeof config.exemptions?.editorialResponsibility === "string") {
|
|
496
|
+
void sendAuditEvent({
|
|
497
|
+
disclosureType: "AIContentLabel",
|
|
498
|
+
componentVersion: VERSION,
|
|
499
|
+
sessionId: siteId,
|
|
500
|
+
rendered: false
|
|
501
|
+
});
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
const selector = config.selector ?? '[data-discloai-content="true"]';
|
|
505
|
+
const elements = Array.from(document.querySelectorAll(selector));
|
|
506
|
+
const labelText = config.variant === "artistic" ? t("content.label.artistic") : t("content.label.default");
|
|
507
|
+
for (const element of elements) {
|
|
508
|
+
if (element.hasAttribute("data-discloai-labeled")) continue;
|
|
509
|
+
const span = document.createElement("span");
|
|
510
|
+
span.textContent = labelText;
|
|
511
|
+
span.setAttribute("data-discloai-label", "ai-content");
|
|
512
|
+
span.setAttribute("role", "img");
|
|
513
|
+
span.setAttribute("aria-label", labelText);
|
|
514
|
+
if (element.parentNode) {
|
|
515
|
+
element.parentNode.insertBefore(span, element);
|
|
516
|
+
}
|
|
517
|
+
element.setAttribute("data-discloai-labeled", "true");
|
|
518
|
+
}
|
|
519
|
+
const styleEl = document.createElement("style");
|
|
520
|
+
styleEl.textContent = DEFAULT_LABEL_CSS;
|
|
521
|
+
if (cspNonce) styleEl.setAttribute("nonce", cspNonce);
|
|
522
|
+
document.head.appendChild(styleEl);
|
|
523
|
+
if (config.customCSS) {
|
|
524
|
+
const sanitized = sanitizeCSS(config.customCSS);
|
|
525
|
+
if (sanitized) {
|
|
526
|
+
const customStyleEl = document.createElement("style");
|
|
527
|
+
customStyleEl.textContent = sanitized;
|
|
528
|
+
if (cspNonce) customStyleEl.setAttribute("nonce", cspNonce);
|
|
529
|
+
document.head.appendChild(customStyleEl);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
void sendAuditEvent({
|
|
533
|
+
disclosureType: "AIContentLabel",
|
|
534
|
+
componentVersion: VERSION,
|
|
535
|
+
sessionId: siteId,
|
|
536
|
+
rendered: true
|
|
537
|
+
});
|
|
538
|
+
} catch (_e) {
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
// src/components/DeepfakeLabel.ts
|
|
543
|
+
function wrapAndLabel(element, labelText, topOffset, leftOffset) {
|
|
544
|
+
if (!element.parentNode) return;
|
|
545
|
+
const wrapper = document.createElement("div");
|
|
546
|
+
wrapper.style.cssText = "position: relative; display: inline-block;";
|
|
547
|
+
element.parentNode.insertBefore(wrapper, element);
|
|
548
|
+
wrapper.appendChild(element);
|
|
549
|
+
const labelDiv = document.createElement("div");
|
|
550
|
+
labelDiv.textContent = labelText;
|
|
551
|
+
labelDiv.setAttribute("role", "img");
|
|
552
|
+
labelDiv.setAttribute("aria-label", labelText);
|
|
553
|
+
labelDiv.style.cssText = "position: absolute; top: " + topOffset + "; left: " + leftOffset + "; z-index: 2147483647; background: rgba(0,0,0,0.7); color: #fff; font-size: 0.75rem; padding: 2px 8px; border-radius: 3px; pointer-events: none;";
|
|
554
|
+
wrapper.appendChild(labelDiv);
|
|
555
|
+
}
|
|
556
|
+
function renderDeepfakeLabel(siteId, config, cspNonce) {
|
|
557
|
+
try {
|
|
558
|
+
if (typeof document === "undefined") return;
|
|
559
|
+
const useArtistic = config.exemptions?.artisticContext === true || config.variant === "artistic";
|
|
560
|
+
const labelText = useArtistic ? t("deepfake.label.artistic") : t("deepfake.label.default");
|
|
561
|
+
let elements;
|
|
562
|
+
if (config.selector) {
|
|
563
|
+
elements = Array.from(document.querySelectorAll(config.selector)).filter(
|
|
564
|
+
(el) => el.tagName === "VIDEO" || el.tagName === "IMG"
|
|
565
|
+
);
|
|
566
|
+
} else {
|
|
567
|
+
elements = [
|
|
568
|
+
...Array.from(document.querySelectorAll("video")),
|
|
569
|
+
...Array.from(document.querySelectorAll("img"))
|
|
570
|
+
];
|
|
571
|
+
}
|
|
572
|
+
for (const element of elements) {
|
|
573
|
+
if (element.hasAttribute("data-discloai-labeled")) continue;
|
|
574
|
+
const isVideo = element.tagName === "VIDEO";
|
|
575
|
+
const offset = isVideo ? "8px" : "4px";
|
|
576
|
+
wrapAndLabel(element, labelText, offset, offset);
|
|
577
|
+
element.setAttribute("data-discloai-labeled", "true");
|
|
578
|
+
}
|
|
579
|
+
if (config.customCSS) {
|
|
580
|
+
const sanitized = sanitizeCSS(config.customCSS);
|
|
581
|
+
if (sanitized) {
|
|
582
|
+
const customStyleEl = document.createElement("style");
|
|
583
|
+
customStyleEl.textContent = sanitized;
|
|
584
|
+
if (cspNonce) customStyleEl.setAttribute("nonce", cspNonce);
|
|
585
|
+
document.head.appendChild(customStyleEl);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
void sendAuditEvent({
|
|
589
|
+
disclosureType: "DeepfakeLabel",
|
|
590
|
+
componentVersion: VERSION,
|
|
591
|
+
sessionId: siteId,
|
|
592
|
+
rendered: true
|
|
593
|
+
});
|
|
594
|
+
} catch (_e) {
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
// src/components/ChatbotDisclosure.ts
|
|
599
|
+
var VENDOR_SELECTOR_MAP = {
|
|
600
|
+
intercom: "#intercom-container",
|
|
601
|
+
crisp: "#crisp-chatbox",
|
|
602
|
+
tidio: "#tidio-chat",
|
|
603
|
+
zendesk: "#launcher",
|
|
604
|
+
drift: "#drift-frame-controller",
|
|
605
|
+
livechat: "#chat-widget-container"
|
|
606
|
+
};
|
|
607
|
+
function renderChatbotDisclosure(siteId, config, cspNonce) {
|
|
608
|
+
try {
|
|
609
|
+
if (typeof document === "undefined") return;
|
|
610
|
+
const storageKey = `discloai:${siteId}:ChatbotDisclosure:seen`;
|
|
611
|
+
try {
|
|
612
|
+
if (typeof sessionStorage !== "undefined" && sessionStorage.getItem(storageKey) === "true") {
|
|
613
|
+
return;
|
|
614
|
+
}
|
|
615
|
+
} catch (_e) {
|
|
616
|
+
}
|
|
617
|
+
if (config.exemptions?.obviousContext === true) {
|
|
618
|
+
console.info(
|
|
619
|
+
"[DiscloAI] ChatbotDisclosure: obviousContext exemption applied"
|
|
620
|
+
);
|
|
621
|
+
void sendAuditEvent({
|
|
622
|
+
disclosureType: "ChatbotDisclosure",
|
|
623
|
+
componentVersion: VERSION,
|
|
624
|
+
sessionId: siteId,
|
|
625
|
+
rendered: false
|
|
626
|
+
});
|
|
627
|
+
return;
|
|
628
|
+
}
|
|
629
|
+
const showDisclosure = () => {
|
|
630
|
+
const overlay = document.createElement("div");
|
|
631
|
+
overlay.setAttribute("role", "alert");
|
|
632
|
+
overlay.setAttribute("aria-live", "polite");
|
|
633
|
+
overlay.style.cssText = "position: fixed; bottom: 80px; right: 24px; z-index: 2147483647; background: #fff; border: 1px solid #c7d2fe; border-radius: 8px; padding: 12px 16px; max-width: 320px; box-shadow: 0 4px 16px rgba(0,0,0,0.12); font-family: sans-serif;";
|
|
634
|
+
const labelText = config.variant === "prominent" ? t("chatbot.disclosure.prominent") : t("chatbot.disclosure.default");
|
|
635
|
+
const p = document.createElement("p");
|
|
636
|
+
p.textContent = labelText;
|
|
637
|
+
overlay.appendChild(p);
|
|
638
|
+
const closeOverlay = () => {
|
|
639
|
+
if (overlay.parentNode) {
|
|
640
|
+
overlay.parentNode.removeChild(overlay);
|
|
641
|
+
}
|
|
642
|
+
try {
|
|
643
|
+
if (typeof sessionStorage !== "undefined") {
|
|
644
|
+
sessionStorage.setItem(storageKey, "true");
|
|
645
|
+
}
|
|
646
|
+
} catch (_e) {
|
|
647
|
+
}
|
|
648
|
+
};
|
|
649
|
+
const closeBtn = document.createElement("button");
|
|
650
|
+
closeBtn.textContent = "\u2715";
|
|
651
|
+
closeBtn.addEventListener("click", closeOverlay);
|
|
652
|
+
overlay.appendChild(closeBtn);
|
|
653
|
+
if (config.customCSS) {
|
|
654
|
+
const sanitized = sanitizeCSS(config.customCSS);
|
|
655
|
+
if (sanitized) {
|
|
656
|
+
const styleEl = document.createElement("style");
|
|
657
|
+
styleEl.textContent = sanitized;
|
|
658
|
+
if (cspNonce) styleEl.setAttribute("nonce", cspNonce);
|
|
659
|
+
document.head.appendChild(styleEl);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
document.body.appendChild(overlay);
|
|
663
|
+
setTimeout(closeOverlay, 8e3);
|
|
664
|
+
void sendAuditEvent({
|
|
665
|
+
disclosureType: "ChatbotDisclosure",
|
|
666
|
+
componentVersion: VERSION,
|
|
667
|
+
sessionId: siteId,
|
|
668
|
+
rendered: true
|
|
669
|
+
});
|
|
670
|
+
};
|
|
671
|
+
const triggerEvent = config.triggerEvent ?? "on-load";
|
|
672
|
+
if (triggerEvent === "on-load") {
|
|
673
|
+
showDisclosure();
|
|
674
|
+
return;
|
|
675
|
+
}
|
|
676
|
+
let vendorSelector = "";
|
|
677
|
+
if (config.vendor) {
|
|
678
|
+
vendorSelector = VENDOR_SELECTOR_MAP[config.vendor] ?? "";
|
|
679
|
+
} else if (config.selector) {
|
|
680
|
+
vendorSelector = config.selector;
|
|
681
|
+
}
|
|
682
|
+
if (!vendorSelector) {
|
|
683
|
+
showDisclosure();
|
|
684
|
+
return;
|
|
685
|
+
}
|
|
686
|
+
const observer = new MutationObserver(() => {
|
|
687
|
+
const target = document.querySelector(vendorSelector);
|
|
688
|
+
if (target) {
|
|
689
|
+
const style = window.getComputedStyle(target);
|
|
690
|
+
if (style.display !== "none" && style.visibility !== "hidden") {
|
|
691
|
+
observer.disconnect();
|
|
692
|
+
showDisclosure();
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
});
|
|
696
|
+
observer.observe(document.body, {
|
|
697
|
+
childList: true,
|
|
698
|
+
subtree: true,
|
|
699
|
+
attributes: true
|
|
700
|
+
});
|
|
701
|
+
} catch (_e) {
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
// src/components/BiometricNotice.ts
|
|
706
|
+
function renderBiometricNotice(siteId, config, cspNonce) {
|
|
707
|
+
try {
|
|
708
|
+
if (typeof document === "undefined") return;
|
|
709
|
+
const banner = document.createElement("div");
|
|
710
|
+
banner.setAttribute("role", "alert");
|
|
711
|
+
banner.setAttribute("aria-live", "assertive");
|
|
712
|
+
banner.style.cssText = "position: fixed; top: 0; left: 0; right: 0; z-index: 2147483647; background: #fef3c7; border-bottom: 2px solid #f59e0b; padding: 12px 24px; font-family: sans-serif; font-size: 0.875rem; text-align: center;";
|
|
713
|
+
const noticeText = t("biometric.notice.default");
|
|
714
|
+
const textSpan = document.createElement("span");
|
|
715
|
+
textSpan.textContent = noticeText;
|
|
716
|
+
banner.appendChild(textSpan);
|
|
717
|
+
const closeBtn = document.createElement("button");
|
|
718
|
+
closeBtn.textContent = "\u2715";
|
|
719
|
+
closeBtn.addEventListener("click", () => {
|
|
720
|
+
if (banner.parentNode) {
|
|
721
|
+
banner.parentNode.removeChild(banner);
|
|
722
|
+
}
|
|
723
|
+
});
|
|
724
|
+
banner.appendChild(closeBtn);
|
|
725
|
+
if (config.customCSS) {
|
|
726
|
+
const sanitized = sanitizeCSS(config.customCSS);
|
|
727
|
+
if (sanitized) {
|
|
728
|
+
const styleEl = document.createElement("style");
|
|
729
|
+
styleEl.textContent = sanitized;
|
|
730
|
+
if (cspNonce) styleEl.setAttribute("nonce", cspNonce);
|
|
731
|
+
document.head.appendChild(styleEl);
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
document.body.appendChild(banner);
|
|
735
|
+
void sendAuditEvent({
|
|
736
|
+
disclosureType: "BiometricNotice",
|
|
737
|
+
componentVersion: VERSION,
|
|
738
|
+
sessionId: siteId,
|
|
739
|
+
rendered: true
|
|
740
|
+
});
|
|
741
|
+
} catch (_e) {
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
// src/init.ts
|
|
746
|
+
function init(options) {
|
|
747
|
+
if (!options?.siteId) {
|
|
748
|
+
console.warn("[DiscloAI] siteId is required");
|
|
749
|
+
return;
|
|
750
|
+
}
|
|
751
|
+
const cspNonce = options.cspNonce;
|
|
752
|
+
void resolveConfig(options).then((config) => {
|
|
753
|
+
injectComponents(config, cspNonce);
|
|
754
|
+
});
|
|
755
|
+
}
|
|
756
|
+
function injectComponents(config, cspNonce) {
|
|
757
|
+
const { siteId } = config;
|
|
758
|
+
if (config.aiContentLabel?.enabled !== false) {
|
|
759
|
+
renderAIContentLabel(siteId, config.aiContentLabel ?? {}, cspNonce);
|
|
760
|
+
}
|
|
761
|
+
if (config.deepfakeLabel?.enabled !== false) {
|
|
762
|
+
renderDeepfakeLabel(siteId, config.deepfakeLabel ?? {}, cspNonce);
|
|
763
|
+
}
|
|
764
|
+
if (config.chatbotDisclosure?.enabled !== false) {
|
|
765
|
+
renderChatbotDisclosure(siteId, config.chatbotDisclosure ?? {}, cspNonce);
|
|
766
|
+
}
|
|
767
|
+
if (config.biometricNotice?.enabled !== false) {
|
|
768
|
+
renderBiometricNotice(siteId, config.biometricNotice ?? {}, cspNonce);
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
// src/vendors.ts
|
|
773
|
+
var VENDOR_PRESETS = {
|
|
774
|
+
intercom: "#intercom-frame, .intercom-launcher",
|
|
775
|
+
crisp: ".crisp-client, #crisp-chatbox",
|
|
776
|
+
tidio: "#tidio-chat, #tidio-chat-iframe",
|
|
777
|
+
zendesk: "#launcher, .zEWidget-launcher",
|
|
778
|
+
drift: "#drift-widget, .drift-widget-welcome",
|
|
779
|
+
livechat: "#chat-widget-container, .livechat-widget"
|
|
780
|
+
};
|
|
781
|
+
function resolveVendorSelector(vendor) {
|
|
782
|
+
if (vendor in VENDOR_PRESETS) {
|
|
783
|
+
return VENDOR_PRESETS[vendor];
|
|
784
|
+
}
|
|
785
|
+
return null;
|
|
786
|
+
}
|
|
787
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
788
|
+
0 && (module.exports = {
|
|
789
|
+
VENDOR_PRESETS,
|
|
790
|
+
init,
|
|
791
|
+
resolveVendorSelector,
|
|
792
|
+
sanitizeCSS,
|
|
793
|
+
sendAuditEvent
|
|
794
|
+
});
|
|
795
|
+
//# sourceMappingURL=index.js.map
|