@disclos/sdk-web 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/dist/batch-GICDMFCN.mjs +63 -0
- package/dist/batch-GICDMFCN.mjs.map +1 -0
- package/dist/batch-UBSRBBS5.cjs +65 -0
- package/dist/batch-UBSRBBS5.cjs.map +1 -0
- package/dist/cdn/sdk.min.global.js +122 -0
- package/dist/chatbot-banner-DGXTYL6P.cjs +15 -0
- package/dist/chatbot-banner-DGXTYL6P.cjs.map +1 -0
- package/dist/chatbot-banner-TN4LWAYQ.mjs +6 -0
- package/dist/chatbot-banner-TN4LWAYQ.mjs.map +1 -0
- package/dist/chunk-32Z4Q6ZD.cjs +68 -0
- package/dist/chunk-32Z4Q6ZD.cjs.map +1 -0
- package/dist/chunk-4JEHEDQP.mjs +56 -0
- package/dist/chunk-4JEHEDQP.mjs.map +1 -0
- package/dist/chunk-4KTDVK7J.cjs +53 -0
- package/dist/chunk-4KTDVK7J.cjs.map +1 -0
- package/dist/chunk-4QR2B5RG.cjs +46 -0
- package/dist/chunk-4QR2B5RG.cjs.map +1 -0
- package/dist/chunk-BHR3367P.mjs +48 -0
- package/dist/chunk-BHR3367P.mjs.map +1 -0
- package/dist/chunk-CZLDE2OZ.cjs +28 -0
- package/dist/chunk-CZLDE2OZ.cjs.map +1 -0
- package/dist/chunk-DG3Z3IAG.mjs +57 -0
- package/dist/chunk-DG3Z3IAG.mjs.map +1 -0
- package/dist/chunk-ESP33I43.mjs +67 -0
- package/dist/chunk-ESP33I43.mjs.map +1 -0
- package/dist/chunk-GFU3F3ZX.mjs +66 -0
- package/dist/chunk-GFU3F3ZX.mjs.map +1 -0
- package/dist/chunk-GYNG67I6.cjs +64 -0
- package/dist/chunk-GYNG67I6.cjs.map +1 -0
- package/dist/chunk-H724IVG6.cjs +119 -0
- package/dist/chunk-H724IVG6.cjs.map +1 -0
- package/dist/chunk-I7K3XSEO.cjs +71 -0
- package/dist/chunk-I7K3XSEO.cjs.map +1 -0
- package/dist/chunk-LNXULTZ5.mjs +62 -0
- package/dist/chunk-LNXULTZ5.mjs.map +1 -0
- package/dist/chunk-NFEGQTCC.mjs +24 -0
- package/dist/chunk-NFEGQTCC.mjs.map +1 -0
- package/dist/chunk-PZM26IE6.mjs +44 -0
- package/dist/chunk-PZM26IE6.mjs.map +1 -0
- package/dist/chunk-Q3245KZ2.cjs +58 -0
- package/dist/chunk-Q3245KZ2.cjs.map +1 -0
- package/dist/chunk-QOGWEWJP.cjs +62 -0
- package/dist/chunk-QOGWEWJP.cjs.map +1 -0
- package/dist/chunk-TTJMXFXE.cjs +186 -0
- package/dist/chunk-TTJMXFXE.cjs.map +1 -0
- package/dist/chunk-UU6VG7CJ.mjs +117 -0
- package/dist/chunk-UU6VG7CJ.mjs.map +1 -0
- package/dist/chunk-YJEYWPLR.mjs +182 -0
- package/dist/chunk-YJEYWPLR.mjs.map +1 -0
- package/dist/content-label-ITJPDODX.mjs +6 -0
- package/dist/content-label-ITJPDODX.mjs.map +1 -0
- package/dist/content-label-JFRT3OGU.cjs +15 -0
- package/dist/content-label-JFRT3OGU.cjs.map +1 -0
- package/dist/deepfake-marker-5FNO7W5J.cjs +15 -0
- package/dist/deepfake-marker-5FNO7W5J.cjs.map +1 -0
- package/dist/deepfake-marker-ILF66NVN.mjs +6 -0
- package/dist/deepfake-marker-ILF66NVN.mjs.map +1 -0
- package/dist/index.cjs +51 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +157 -0
- package/dist/index.d.ts +157 -0
- package/dist/index.mjs +10 -0
- package/dist/index.mjs.map +1 -0
- package/dist/logger-IEU35PCN.cjs +14 -0
- package/dist/logger-IEU35PCN.cjs.map +1 -0
- package/dist/logger-X67CWRL4.mjs +5 -0
- package/dist/logger-X67CWRL4.mjs.map +1 -0
- package/dist/queue-CHODSJ4I.mjs +4 -0
- package/dist/queue-CHODSJ4I.mjs.map +1 -0
- package/dist/queue-LF4IPDT3.cjs +25 -0
- package/dist/queue-LF4IPDT3.cjs.map +1 -0
- package/dist/register-BA3KW4AJ.cjs +15 -0
- package/dist/register-BA3KW4AJ.cjs.map +1 -0
- package/dist/register-BBBSBMAF.mjs +13 -0
- package/dist/register-BBBSBMAF.mjs.map +1 -0
- package/dist/sender-EXBUUDTU.cjs +15 -0
- package/dist/sender-EXBUUDTU.cjs.map +1 -0
- package/dist/sender-RUX2MZKR.mjs +6 -0
- package/dist/sender-RUX2MZKR.mjs.map +1 -0
- package/dist/trust-page-HALUJVZU.cjs +15 -0
- package/dist/trust-page-HALUJVZU.cjs.map +1 -0
- package/dist/trust-page-NLFTM3WT.mjs +6 -0
- package/dist/trust-page-NLFTM3WT.mjs.map +1 -0
- package/package.json +60 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __esm = (fn, res) => function __init() {
|
|
6
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
7
|
+
};
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
21
|
+
|
|
22
|
+
export { __esm, __export, __toCommonJS };
|
|
23
|
+
//# sourceMappingURL=chunk-NFEGQTCC.mjs.map
|
|
24
|
+
//# sourceMappingURL=chunk-NFEGQTCC.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-NFEGQTCC.mjs"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { persistFailedBatch } from './chunk-DG3Z3IAG.mjs';
|
|
2
|
+
import { init_state, getState } from './chunk-BHR3367P.mjs';
|
|
3
|
+
|
|
4
|
+
// src/log/sender.ts
|
|
5
|
+
init_state();
|
|
6
|
+
var RETRY_DELAYS_MS = [1e3, 2e3, 4e3];
|
|
7
|
+
var DEFAULT_ENDPOINT = "https://ingest.disclos.dev";
|
|
8
|
+
async function sendBatch(events, attempt = 0) {
|
|
9
|
+
const state = getState();
|
|
10
|
+
const endpoint = state.config?.ingestionEndpoint ?? state.options?.endpoint ?? DEFAULT_ENDPOINT;
|
|
11
|
+
try {
|
|
12
|
+
const res = await fetch(`${endpoint}/v1/events`, {
|
|
13
|
+
method: "POST",
|
|
14
|
+
headers: {
|
|
15
|
+
"Content-Type": "application/json",
|
|
16
|
+
Authorization: `Bearer ${state.apiKey}`
|
|
17
|
+
},
|
|
18
|
+
body: JSON.stringify({ events }),
|
|
19
|
+
// keepalive ensures the request survives page navigation
|
|
20
|
+
keepalive: true
|
|
21
|
+
});
|
|
22
|
+
if (res.ok || res.status === 202) return;
|
|
23
|
+
if (res.status >= 400 && res.status < 500) {
|
|
24
|
+
if (state.debug) console.warn(`[Disclos] Ingest rejected batch (${res.status})`);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
throw new Error(`HTTP ${res.status}`);
|
|
28
|
+
} catch (err) {
|
|
29
|
+
const delay = RETRY_DELAYS_MS[attempt];
|
|
30
|
+
if (delay !== void 0) {
|
|
31
|
+
await sleep(delay);
|
|
32
|
+
return sendBatch(events, attempt + 1);
|
|
33
|
+
}
|
|
34
|
+
if (state.debug) console.error("[Disclos] Batch failed after retries, queuing for next session:", err);
|
|
35
|
+
persistFailedBatch(events);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function sleep(ms) {
|
|
39
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export { sendBatch };
|
|
43
|
+
//# sourceMappingURL=chunk-PZM26IE6.mjs.map
|
|
44
|
+
//# sourceMappingURL=chunk-PZM26IE6.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/log/sender.ts"],"names":[],"mappings":";;;;AAEA,UAAA,EAAA;AAGA,IAAM,eAAA,GAAkB,CAAC,GAAA,EAAO,GAAA,EAAO,GAAK,CAAA;AAC5C,IAAM,gBAAA,GAAmB,4BAAA;AAQzB,eAAsB,SAAA,CAAU,MAAA,EAAyB,OAAA,GAAU,CAAA,EAAkB;AACnF,EAAA,MAAM,QAAQ,QAAA,EAAS;AACvB,EAAA,MAAM,WAAW,KAAA,CAAM,MAAA,EAAQ,iBAAA,IAAqB,KAAA,CAAM,SAAS,QAAA,IAAY,gBAAA;AAE/E,EAAA,IAAI;AACF,IAAA,MAAM,GAAA,GAAM,MAAM,KAAA,CAAM,CAAA,EAAG,QAAQ,CAAA,UAAA,CAAA,EAAc;AAAA,MAC/C,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS;AAAA,QACP,cAAA,EAAgB,kBAAA;AAAA,QAChB,aAAA,EAAe,CAAA,OAAA,EAAU,KAAA,CAAM,MAAM,CAAA;AAAA,OACvC;AAAA,MACA,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,EAAE,QAAQ,CAAA;AAAA;AAAA,MAE/B,SAAA,EAAW;AAAA,KACZ,CAAA;AAGD,IAAA,IAAI,GAAA,CAAI,EAAA,IAAM,GAAA,CAAI,MAAA,KAAW,GAAA,EAAK;AAGlC,IAAA,IAAI,GAAA,CAAI,MAAA,IAAU,GAAA,IAAO,GAAA,CAAI,SAAS,GAAA,EAAK;AACzC,MAAA,IAAI,MAAM,KAAA,EAAO,OAAA,CAAQ,KAAK,CAAA,iCAAA,EAAoC,GAAA,CAAI,MAAM,CAAA,CAAA,CAAG,CAAA;AAC/E,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,KAAA,EAAQ,GAAA,CAAI,MAAM,CAAA,CAAE,CAAA;AAAA,EACtC,SAAS,GAAA,EAAK;AACZ,IAAA,MAAM,KAAA,GAAQ,gBAAgB,OAAO,CAAA;AACrC,IAAA,IAAI,UAAU,MAAA,EAAW;AACvB,MAAA,MAAM,MAAM,KAAK,CAAA;AACjB,MAAA,OAAO,SAAA,CAAU,MAAA,EAAQ,OAAA,GAAU,CAAC,CAAA;AAAA,IACtC;AAEA,IAAA,IAAI,KAAA,CAAM,KAAA,EAAO,OAAA,CAAQ,KAAA,CAAM,mEAAmE,GAAG,CAAA;AACrG,IAAA,kBAAA,CAAmB,MAAM,CAAA;AAAA,EAC3B;AACF;AAEA,SAAS,MAAM,EAAA,EAA2B;AACxC,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,YAAY,UAAA,CAAW,OAAA,EAAS,EAAE,CAAC,CAAA;AACzD","file":"chunk-PZM26IE6.mjs","sourcesContent":["// Network sender with exponential-backoff retry and localStorage fallback\nimport type { InternalEvent } from '../core/types';\nimport { getState } from '../core/state';\nimport { persistFailedBatch } from './queue';\n\nconst RETRY_DELAYS_MS = [1_000, 2_000, 4_000];\nconst DEFAULT_ENDPOINT = 'https://ingest.disclos.dev';\n\n/**\n * Sends a batch to the ingestion endpoint with up to 3 retries.\n * On exhausted retries, persists the batch to localStorage for next-session replay.\n *\n * Uses `keepalive: true` so the request survives page unload (e.g. navigate-away).\n */\nexport async function sendBatch(events: InternalEvent[], attempt = 0): Promise<void> {\n const state = getState();\n const endpoint = state.config?.ingestionEndpoint ?? state.options?.endpoint ?? DEFAULT_ENDPOINT;\n\n try {\n const res = await fetch(`${endpoint}/v1/events`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${state.apiKey}`,\n },\n body: JSON.stringify({ events }),\n // keepalive ensures the request survives page navigation\n keepalive: true,\n });\n\n // 202 Accepted is the success status from the ingest Worker\n if (res.ok || res.status === 202) return;\n\n // 4xx errors are client errors — don't retry\n if (res.status >= 400 && res.status < 500) {\n if (state.debug) console.warn(`[Disclos] Ingest rejected batch (${res.status})`);\n return;\n }\n\n throw new Error(`HTTP ${res.status}`);\n } catch (err) {\n const delay = RETRY_DELAYS_MS[attempt];\n if (delay !== undefined) {\n await sleep(delay);\n return sendBatch(events, attempt + 1);\n }\n // All retries exhausted\n if (state.debug) console.error('[Disclos] Batch failed after retries, queuing for next session:', err);\n persistFailedBatch(events);\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n"]}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkTTJMXFXE_cjs = require('./chunk-TTJMXFXE.cjs');
|
|
4
|
+
|
|
5
|
+
// src/components/chatbot-banner.ts
|
|
6
|
+
var STYLES = `
|
|
7
|
+
:host {
|
|
8
|
+
display: flex;
|
|
9
|
+
align-items: flex-start;
|
|
10
|
+
gap: 10px;
|
|
11
|
+
font-family: var(--disclos-font, system-ui, -apple-system, sans-serif);
|
|
12
|
+
font-size: var(--disclos-font-size, 0.875rem);
|
|
13
|
+
line-height: 1.5;
|
|
14
|
+
color: var(--disclos-text, #1e3a5f);
|
|
15
|
+
background: var(--disclos-bg, #eff6ff);
|
|
16
|
+
border: 1px solid var(--disclos-border, #bfdbfe);
|
|
17
|
+
border-radius: var(--disclos-radius, 8px);
|
|
18
|
+
padding: var(--disclos-padding, 12px 16px);
|
|
19
|
+
box-sizing: border-box;
|
|
20
|
+
}
|
|
21
|
+
.icon { flex-shrink: 0; font-size: 1.1em; margin-top: 1px; }
|
|
22
|
+
.text { flex: 1; }
|
|
23
|
+
`;
|
|
24
|
+
var ChatbotBanner = class extends chunkTTJMXFXE_cjs.DisclosElement {
|
|
25
|
+
static get observedAttributes() {
|
|
26
|
+
return ["system-name", "operator-name"];
|
|
27
|
+
}
|
|
28
|
+
_html(config) {
|
|
29
|
+
const systemName = this.getAttribute("system-name") ?? "";
|
|
30
|
+
const operatorName = this.getAttribute("operator-name") ?? "";
|
|
31
|
+
let text = config?.disclosures.chatbot ?? "You are interacting with an AI system.";
|
|
32
|
+
text = text.replace(/\{\{system_name\}\}/g, systemName).replace(/\{\{operator_name\}\}/g, operatorName);
|
|
33
|
+
return `<style>${STYLES}</style>
|
|
34
|
+
<span class="icon" aria-hidden="true">\u{1F916}</span>
|
|
35
|
+
<span class="text" role="note" aria-live="polite">${escapeHtml(text)}</span>`;
|
|
36
|
+
}
|
|
37
|
+
_onVisible() {
|
|
38
|
+
void import('./logger-IEU35PCN.cjs').then(({ log }) => {
|
|
39
|
+
log({
|
|
40
|
+
type: "disclosure_shown",
|
|
41
|
+
metadata: {
|
|
42
|
+
component: "chatbot-banner",
|
|
43
|
+
system_name: this.getAttribute("system-name") ?? void 0
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
function escapeHtml(s) {
|
|
50
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
51
|
+
}
|
|
52
|
+
if (!customElements.get("disclos-chatbot-banner")) {
|
|
53
|
+
customElements.define("disclos-chatbot-banner", ChatbotBanner);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
exports.ChatbotBanner = ChatbotBanner;
|
|
57
|
+
//# sourceMappingURL=chunk-Q3245KZ2.cjs.map
|
|
58
|
+
//# sourceMappingURL=chunk-Q3245KZ2.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/chatbot-banner.ts"],"names":["DisclosElement"],"mappings":";;;;;AAKA,IAAM,MAAA,GAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAmBR,IAAM,aAAA,GAAN,cAA4BA,gCAAA,CAAe;AAAA,EAChD,WAAW,kBAAA,GAA+B;AACxC,IAAA,OAAO,CAAC,eAAe,eAAe,CAAA;AAAA,EACxC;AAAA,EAEU,MAAM,MAAA,EAAqC;AACnD,IAAA,MAAM,UAAA,GAAa,IAAA,CAAK,YAAA,CAAa,aAAa,CAAA,IAAK,EAAA;AACvD,IAAA,MAAM,YAAA,GAAe,IAAA,CAAK,YAAA,CAAa,eAAe,CAAA,IAAK,EAAA;AAC3D,IAAA,IAAI,IAAA,GAAO,MAAA,EAAQ,WAAA,CAAY,OAAA,IAAW,wCAAA;AAC1C,IAAA,IAAA,GAAO,KACJ,OAAA,CAAQ,sBAAA,EAAwB,UAAU,CAAA,CAC1C,OAAA,CAAQ,0BAA0B,YAAY,CAAA;AAEjD,IAAA,OAAO,UAAU,MAAM,CAAA;AAAA;AAAA,kDAAA,EAEyB,UAAA,CAAW,IAAI,CAAC,CAAA,OAAA,CAAA;AAAA,EAClE;AAAA,EAEU,UAAA,GAAmB;AAC3B,IAAA,KAAK,OAAO,uBAAe,CAAA,CAAE,KAAK,CAAC,EAAE,KAAI,KAAM;AAC7C,MAAA,GAAA,CAAI;AAAA,QACF,IAAA,EAAM,kBAAA;AAAA,QACN,QAAA,EAAU;AAAA,UACR,SAAA,EAAW,gBAAA;AAAA,UACX,WAAA,EAAa,IAAA,CAAK,YAAA,CAAa,aAAa,CAAA,IAAK;AAAA;AACnD,OACD,CAAA;AAAA,IACH,CAAC,CAAA;AAAA,EACH;AACF;AAEA,SAAS,WAAW,CAAA,EAAmB;AACrC,EAAA,OAAO,CAAA,CAAE,OAAA,CAAQ,IAAA,EAAM,OAAO,EAAE,OAAA,CAAQ,IAAA,EAAM,MAAM,CAAA,CAAE,QAAQ,IAAA,EAAM,MAAM,CAAA,CAAE,OAAA,CAAQ,MAAM,QAAQ,CAAA;AACpG;AAEA,IAAI,CAAC,cAAA,CAAe,GAAA,CAAI,wBAAwB,CAAA,EAAG;AACjD,EAAA,cAAA,CAAe,MAAA,CAAO,0BAA0B,aAAa,CAAA;AAC/D","file":"chunk-Q3245KZ2.cjs","sourcesContent":["// <disclos-chatbot-banner> — Article 50(1)(a) chatbot identity disclosure\n// Fires disclosure_shown when ≥50% of the element is visible.\nimport { DisclosElement } from './base';\nimport type { RemoteConfig } from '../core/types';\n\nconst STYLES = `\n:host {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n font-family: var(--disclos-font, system-ui, -apple-system, sans-serif);\n font-size: var(--disclos-font-size, 0.875rem);\n line-height: 1.5;\n color: var(--disclos-text, #1e3a5f);\n background: var(--disclos-bg, #eff6ff);\n border: 1px solid var(--disclos-border, #bfdbfe);\n border-radius: var(--disclos-radius, 8px);\n padding: var(--disclos-padding, 12px 16px);\n box-sizing: border-box;\n}\n.icon { flex-shrink: 0; font-size: 1.1em; margin-top: 1px; }\n.text { flex: 1; }\n`;\n\nexport class ChatbotBanner extends DisclosElement {\n static get observedAttributes(): string[] {\n return ['system-name', 'operator-name'];\n }\n\n protected _html(config: RemoteConfig | null): string {\n const systemName = this.getAttribute('system-name') ?? '';\n const operatorName = this.getAttribute('operator-name') ?? '';\n let text = config?.disclosures.chatbot ?? 'You are interacting with an AI system.';\n text = text\n .replace(/\\{\\{system_name\\}\\}/g, systemName)\n .replace(/\\{\\{operator_name\\}\\}/g, operatorName);\n\n return `<style>${STYLES}</style>\n<span class=\"icon\" aria-hidden=\"true\">🤖</span>\n<span class=\"text\" role=\"note\" aria-live=\"polite\">${escapeHtml(text)}</span>`;\n }\n\n protected _onVisible(): void {\n void import('../log/logger').then(({ log }) => {\n log({\n type: 'disclosure_shown',\n metadata: {\n component: 'chatbot-banner',\n system_name: this.getAttribute('system-name') ?? undefined,\n },\n });\n });\n }\n}\n\nfunction escapeHtml(s: string): string {\n return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\n}\n\nif (!customElements.get('disclos-chatbot-banner')) {\n customElements.define('disclos-chatbot-banner', ChatbotBanner);\n}\n"]}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/log/queue.ts
|
|
4
|
+
var QUEUE_KEY = "disclos_event_queue";
|
|
5
|
+
var MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
6
|
+
function isStorageAvailable() {
|
|
7
|
+
try {
|
|
8
|
+
const k = "__disclos_test__";
|
|
9
|
+
localStorage.setItem(k, "1");
|
|
10
|
+
localStorage.removeItem(k);
|
|
11
|
+
return true;
|
|
12
|
+
} catch {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function persistFailedBatch(events) {
|
|
17
|
+
if (!isStorageAvailable()) return;
|
|
18
|
+
try {
|
|
19
|
+
const queue = loadRawQueue();
|
|
20
|
+
const fresh = queue.filter((e) => Date.now() - e.savedAt < MAX_AGE_MS);
|
|
21
|
+
fresh.push({ events, savedAt: Date.now() });
|
|
22
|
+
localStorage.setItem(QUEUE_KEY, JSON.stringify(fresh));
|
|
23
|
+
} catch {
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function loadQueue() {
|
|
27
|
+
return loadRawQueue().filter((e) => Date.now() - e.savedAt < MAX_AGE_MS);
|
|
28
|
+
}
|
|
29
|
+
function clearQueue() {
|
|
30
|
+
try {
|
|
31
|
+
localStorage.removeItem(QUEUE_KEY);
|
|
32
|
+
} catch {
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function loadRawQueue() {
|
|
36
|
+
try {
|
|
37
|
+
const raw = localStorage.getItem(QUEUE_KEY);
|
|
38
|
+
if (!raw) return [];
|
|
39
|
+
return JSON.parse(raw);
|
|
40
|
+
} catch {
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
async function drainQueue() {
|
|
45
|
+
const entries = loadQueue();
|
|
46
|
+
if (entries.length === 0) return;
|
|
47
|
+
clearQueue();
|
|
48
|
+
const { sendBatch } = await import('./sender-EXBUUDTU.cjs');
|
|
49
|
+
for (const entry of entries) {
|
|
50
|
+
try {
|
|
51
|
+
await sendBatch(entry.events);
|
|
52
|
+
} catch {
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
exports.clearQueue = clearQueue;
|
|
58
|
+
exports.drainQueue = drainQueue;
|
|
59
|
+
exports.loadQueue = loadQueue;
|
|
60
|
+
exports.persistFailedBatch = persistFailedBatch;
|
|
61
|
+
//# sourceMappingURL=chunk-QOGWEWJP.cjs.map
|
|
62
|
+
//# sourceMappingURL=chunk-QOGWEWJP.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/log/queue.ts"],"names":[],"mappings":";;;AAIA,IAAM,SAAA,GAAY,qBAAA;AAClB,IAAM,UAAA,GAAa,CAAA,GAAI,EAAA,GAAK,EAAA,GAAK,EAAA,GAAK,GAAA;AAOtC,SAAS,kBAAA,GAA8B;AACrC,EAAA,IAAI;AACF,IAAA,MAAM,CAAA,GAAI,kBAAA;AACV,IAAA,YAAA,CAAa,OAAA,CAAQ,GAAG,GAAG,CAAA;AAC3B,IAAA,YAAA,CAAa,WAAW,CAAC,CAAA;AACzB,IAAA,OAAO,IAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,KAAA;AAAA,EACT;AACF;AAEO,SAAS,mBAAmB,MAAA,EAA+B;AAChE,EAAA,IAAI,CAAC,oBAAmB,EAAG;AAC3B,EAAA,IAAI;AACF,IAAA,MAAM,QAAQ,YAAA,EAAa;AAE3B,IAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,MAAA,CAAO,CAAC,CAAA,KAAM,KAAK,GAAA,EAAI,GAAI,CAAA,CAAE,OAAA,GAAU,UAAU,CAAA;AACrE,IAAA,KAAA,CAAM,KAAK,EAAE,MAAA,EAAQ,SAAS,IAAA,CAAK,GAAA,IAAO,CAAA;AAC1C,IAAA,YAAA,CAAa,OAAA,CAAQ,SAAA,EAAW,IAAA,CAAK,SAAA,CAAU,KAAK,CAAC,CAAA;AAAA,EACvD,CAAA,CAAA,MAAQ;AAAA,EAER;AACF;AAEO,SAAS,SAAA,GAA0B;AACxC,EAAA,OAAO,YAAA,EAAa,CAAE,MAAA,CAAO,CAAC,CAAA,KAAM,KAAK,GAAA,EAAI,GAAI,CAAA,CAAE,OAAA,GAAU,UAAU,CAAA;AACzE;AAEO,SAAS,UAAA,GAAmB;AACjC,EAAA,IAAI;AACF,IAAA,YAAA,CAAa,WAAW,SAAS,CAAA;AAAA,EACnC,CAAA,CAAA,MAAQ;AAAA,EAER;AACF;AAEA,SAAS,YAAA,GAA6B;AACpC,EAAA,IAAI;AACF,IAAA,MAAM,GAAA,GAAM,YAAA,CAAa,OAAA,CAAQ,SAAS,CAAA;AAC1C,IAAA,IAAI,CAAC,GAAA,EAAK,OAAO,EAAC;AAClB,IAAA,OAAO,IAAA,CAAK,MAAM,GAAG,CAAA;AAAA,EACvB,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,EAAC;AAAA,EACV;AACF;AAOA,eAAsB,UAAA,GAA4B;AAChD,EAAA,MAAM,UAAU,SAAA,EAAU;AAC1B,EAAA,IAAI,OAAA,CAAQ,WAAW,CAAA,EAAG;AAC1B,EAAA,UAAA,EAAW;AAGX,EAAA,MAAM,EAAE,SAAA,EAAU,GAAI,MAAM,OAAO,uBAAU,CAAA;AAC7C,EAAA,KAAA,MAAW,SAAS,OAAA,EAAS;AAC3B,IAAA,IAAI;AACF,MAAA,MAAM,SAAA,CAAU,MAAM,MAAM,CAAA;AAAA,IAC9B,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF;AACF","file":"chunk-QOGWEWJP.cjs","sourcesContent":["// localStorage persistence queue — events survive page unload / transient network errors.\n// Drained on next init(). No network calls here; purely storage operations.\nimport type { InternalEvent } from '../core/types';\n\nconst QUEUE_KEY = 'disclos_event_queue';\nconst MAX_AGE_MS = 7 * 24 * 60 * 60 * 1_000; // 7 days\n\ninterface QueueEntry {\n events: InternalEvent[];\n savedAt: number;\n}\n\nfunction isStorageAvailable(): boolean {\n try {\n const k = '__disclos_test__';\n localStorage.setItem(k, '1');\n localStorage.removeItem(k);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function persistFailedBatch(events: InternalEvent[]): void {\n if (!isStorageAvailable()) return;\n try {\n const queue = loadRawQueue();\n // Prune expired entries and append the new one\n const fresh = queue.filter((e) => Date.now() - e.savedAt < MAX_AGE_MS);\n fresh.push({ events, savedAt: Date.now() });\n localStorage.setItem(QUEUE_KEY, JSON.stringify(fresh));\n } catch {\n /* storage quota exceeded */\n }\n}\n\nexport function loadQueue(): QueueEntry[] {\n return loadRawQueue().filter((e) => Date.now() - e.savedAt < MAX_AGE_MS);\n}\n\nexport function clearQueue(): void {\n try {\n localStorage.removeItem(QUEUE_KEY);\n } catch {\n /* noop */\n }\n}\n\nfunction loadRawQueue(): QueueEntry[] {\n try {\n const raw = localStorage.getItem(QUEUE_KEY);\n if (!raw) return [];\n return JSON.parse(raw) as QueueEntry[];\n } catch {\n return [];\n }\n}\n\n/**\n * Drains stored events from previous page sessions.\n * Called by init() after the batcher is ready.\n * Clears the queue before re-sending (prevents growth on persistent failure).\n */\nexport async function drainQueue(): Promise<void> {\n const entries = loadQueue();\n if (entries.length === 0) return;\n clearQueue();\n\n // Lazy-import sender to avoid circular deps\n const { sendBatch } = await import('./sender');\n for (const entry of entries) {\n try {\n await sendBatch(entry.events);\n } catch {\n /* best-effort — give up on entries that fail again */\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunk4KTDVK7J_cjs = require('./chunk-4KTDVK7J.cjs');
|
|
4
|
+
var chunkCZLDE2OZ_cjs = require('./chunk-CZLDE2OZ.cjs');
|
|
5
|
+
|
|
6
|
+
// src/core/config.ts
|
|
7
|
+
var DEFAULT_CDN = "https://cdn.disclos.dev/v1/config";
|
|
8
|
+
var CACHE_KEY_PREFIX = "disclos_cfg_";
|
|
9
|
+
var FETCH_TIMEOUT_MS = 3e3;
|
|
10
|
+
var DEFAULT_CONFIG = {
|
|
11
|
+
version: 1,
|
|
12
|
+
locale: "en",
|
|
13
|
+
ingestionEndpoint: "https://ingest.disclos.dev",
|
|
14
|
+
samplingRate: 1,
|
|
15
|
+
disclosures: {
|
|
16
|
+
chatbot: "You are interacting with an AI system.",
|
|
17
|
+
contentLabel: {
|
|
18
|
+
text: "AI-generated text",
|
|
19
|
+
image: "AI-generated image",
|
|
20
|
+
audio: "AI-generated audio",
|
|
21
|
+
video: "AI-generated video"
|
|
22
|
+
},
|
|
23
|
+
deepfake: "This content has been artificially generated or manipulated using AI."
|
|
24
|
+
},
|
|
25
|
+
features: { contentLabeling: true, trustPage: false },
|
|
26
|
+
ttl: 36e5
|
|
27
|
+
// 1 hour
|
|
28
|
+
};
|
|
29
|
+
function cacheKey(apiKey) {
|
|
30
|
+
return CACHE_KEY_PREFIX + apiKey.slice(-8);
|
|
31
|
+
}
|
|
32
|
+
function saveToCacheStorage(apiKey, config) {
|
|
33
|
+
try {
|
|
34
|
+
localStorage.setItem(
|
|
35
|
+
cacheKey(apiKey),
|
|
36
|
+
JSON.stringify({ ...config, cachedAt: Date.now() })
|
|
37
|
+
);
|
|
38
|
+
} catch {
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function loadFromCacheStorage(apiKey) {
|
|
42
|
+
try {
|
|
43
|
+
const raw = localStorage.getItem(cacheKey(apiKey));
|
|
44
|
+
if (!raw) return null;
|
|
45
|
+
return JSON.parse(raw);
|
|
46
|
+
} catch {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function isFresh(config) {
|
|
51
|
+
if (!config.cachedAt) return false;
|
|
52
|
+
return Date.now() - config.cachedAt < config.ttl;
|
|
53
|
+
}
|
|
54
|
+
async function fetchConfig(apiKey, locale, endpointOverride) {
|
|
55
|
+
const cached = loadFromCacheStorage(apiKey);
|
|
56
|
+
if (cached && isFresh(cached)) return cached;
|
|
57
|
+
const endpoint = endpointOverride ?? DEFAULT_CDN;
|
|
58
|
+
try {
|
|
59
|
+
const url = new URL(endpoint);
|
|
60
|
+
url.searchParams.set("key", apiKey);
|
|
61
|
+
url.searchParams.set("locale", locale);
|
|
62
|
+
const res = await fetch(url.toString(), {
|
|
63
|
+
headers: { Accept: "application/json" },
|
|
64
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
|
|
65
|
+
});
|
|
66
|
+
if (res.ok) {
|
|
67
|
+
const data = await res.json();
|
|
68
|
+
data.cachedAt = Date.now();
|
|
69
|
+
saveToCacheStorage(apiKey, data);
|
|
70
|
+
return data;
|
|
71
|
+
}
|
|
72
|
+
} catch {
|
|
73
|
+
}
|
|
74
|
+
if (cached) return cached;
|
|
75
|
+
return { ...DEFAULT_CONFIG, locale };
|
|
76
|
+
}
|
|
77
|
+
function getConfig() {
|
|
78
|
+
try {
|
|
79
|
+
const { getState: getState2 } = (chunk4KTDVK7J_cjs.init_state(), chunkCZLDE2OZ_cjs.__toCommonJS(chunk4KTDVK7J_cjs.state_exports));
|
|
80
|
+
return getState2().config;
|
|
81
|
+
} catch {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// src/components/base.ts
|
|
87
|
+
chunk4KTDVK7J_cjs.init_state();
|
|
88
|
+
|
|
89
|
+
// src/core/init.ts
|
|
90
|
+
chunk4KTDVK7J_cjs.init_state();
|
|
91
|
+
var CONFIG_LOADED_EVENT = "disclos:config-loaded";
|
|
92
|
+
async function init(options) {
|
|
93
|
+
const state = chunk4KTDVK7J_cjs.getState();
|
|
94
|
+
if (state.initialized) {
|
|
95
|
+
if (state.debug) console.warn("[Disclos] Already initialized \u2014 ignoring duplicate init()");
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (!options.apiKey) throw new Error("[Disclos] apiKey is required");
|
|
99
|
+
if (!options.aiSystemId) throw new Error("[Disclos] aiSystemId is required");
|
|
100
|
+
const [{ EventBatcher }, { drainQueue }, { registerElements }] = await Promise.all([
|
|
101
|
+
import('./batch-UBSRBBS5.cjs'),
|
|
102
|
+
import('./queue-LF4IPDT3.cjs'),
|
|
103
|
+
import('./register-BA3KW4AJ.cjs')
|
|
104
|
+
]);
|
|
105
|
+
chunk4KTDVK7J_cjs.setState({
|
|
106
|
+
initialized: true,
|
|
107
|
+
apiKey: options.apiKey,
|
|
108
|
+
aiSystemId: options.aiSystemId,
|
|
109
|
+
locale: options.locale ?? "en",
|
|
110
|
+
debug: options.debug ?? false,
|
|
111
|
+
logContent: options.logContent ?? false,
|
|
112
|
+
options,
|
|
113
|
+
batcher: new EventBatcher(options)
|
|
114
|
+
});
|
|
115
|
+
registerElements();
|
|
116
|
+
void fetchConfig(options.apiKey, options.locale ?? "en", options.configEndpoint).then((config) => {
|
|
117
|
+
chunk4KTDVK7J_cjs.setState({ config });
|
|
118
|
+
if (typeof window !== "undefined") {
|
|
119
|
+
window.dispatchEvent(new CustomEvent(CONFIG_LOADED_EVENT, { detail: config }));
|
|
120
|
+
}
|
|
121
|
+
if (options.debug) console.debug("[Disclos] Config loaded:", config);
|
|
122
|
+
}).catch((err) => {
|
|
123
|
+
if (options.debug) console.error("[Disclos] Config fetch error:", err);
|
|
124
|
+
});
|
|
125
|
+
void drainQueue().catch((err) => {
|
|
126
|
+
if (options.debug) console.warn("[Disclos] Queue drain error:", err);
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// src/components/base.ts
|
|
131
|
+
var DisclosElement = class extends HTMLElement {
|
|
132
|
+
constructor() {
|
|
133
|
+
super(...arguments);
|
|
134
|
+
this._observer = null;
|
|
135
|
+
this._disclosed = false;
|
|
136
|
+
this._onConfigLoaded = () => this._update();
|
|
137
|
+
}
|
|
138
|
+
connectedCallback() {
|
|
139
|
+
if (!this.shadowRoot) this.attachShadow({ mode: "open" });
|
|
140
|
+
this._update();
|
|
141
|
+
this._trackVisibility();
|
|
142
|
+
window.addEventListener(CONFIG_LOADED_EVENT, this._onConfigLoaded);
|
|
143
|
+
}
|
|
144
|
+
disconnectedCallback() {
|
|
145
|
+
this._observer?.disconnect();
|
|
146
|
+
window.removeEventListener(CONFIG_LOADED_EVENT, this._onConfigLoaded);
|
|
147
|
+
}
|
|
148
|
+
attributeChangedCallback() {
|
|
149
|
+
if (this.shadowRoot) this._update();
|
|
150
|
+
}
|
|
151
|
+
/** Called once when the element becomes ≥50% visible in the viewport */
|
|
152
|
+
_onVisible() {
|
|
153
|
+
}
|
|
154
|
+
getConfig() {
|
|
155
|
+
return chunk4KTDVK7J_cjs.getState().config;
|
|
156
|
+
}
|
|
157
|
+
_update() {
|
|
158
|
+
if (!this.shadowRoot) return;
|
|
159
|
+
this.shadowRoot.innerHTML = this._html(this.getConfig());
|
|
160
|
+
}
|
|
161
|
+
_trackVisibility() {
|
|
162
|
+
if (typeof IntersectionObserver === "undefined") {
|
|
163
|
+
if (!this._disclosed) {
|
|
164
|
+
this._disclosed = true;
|
|
165
|
+
this._onVisible();
|
|
166
|
+
}
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
this._observer = new IntersectionObserver(
|
|
170
|
+
([entry]) => {
|
|
171
|
+
if (entry?.isIntersecting && !this._disclosed) {
|
|
172
|
+
this._disclosed = true;
|
|
173
|
+
this._onVisible();
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
{ threshold: 0.5 }
|
|
177
|
+
);
|
|
178
|
+
this._observer.observe(this);
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
exports.DisclosElement = DisclosElement;
|
|
183
|
+
exports.getConfig = getConfig;
|
|
184
|
+
exports.init = init;
|
|
185
|
+
//# sourceMappingURL=chunk-TTJMXFXE.cjs.map
|
|
186
|
+
//# sourceMappingURL=chunk-TTJMXFXE.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/config.ts","../src/components/base.ts","../src/core/init.ts"],"names":["getState","init_state","__toCommonJS","state_exports","setState"],"mappings":"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","file":"chunk-TTJMXFXE.cjs","sourcesContent":["// Remote config: fetch, cache, fallback chain.\n// Priority: remote CDN → localStorage (stale-ok) → bundled default\nimport type { RemoteConfig } from './types';\n\nconst DEFAULT_CDN = 'https://cdn.disclos.dev/v1/config';\nconst CACHE_KEY_PREFIX = 'disclos_cfg_';\nconst FETCH_TIMEOUT_MS = 3_000;\n\n// ── Bundled default (no network dependency) ───────────────────────────────────\n\nexport const DEFAULT_CONFIG: RemoteConfig = {\n version: 1,\n locale: 'en',\n ingestionEndpoint: 'https://ingest.disclos.dev',\n samplingRate: 1.0,\n disclosures: {\n chatbot: 'You are interacting with an AI system.',\n contentLabel: {\n text: 'AI-generated text',\n image: 'AI-generated image',\n audio: 'AI-generated audio',\n video: 'AI-generated video',\n },\n deepfake: 'This content has been artificially generated or manipulated using AI.',\n },\n features: { contentLabeling: true, trustPage: false },\n ttl: 3_600_000, // 1 hour\n};\n\n// ── localStorage helpers ──────────────────────────────────────────────────────\n\nfunction cacheKey(apiKey: string): string {\n return CACHE_KEY_PREFIX + apiKey.slice(-8);\n}\n\nfunction saveToCacheStorage(apiKey: string, config: RemoteConfig): void {\n try {\n localStorage.setItem(\n cacheKey(apiKey),\n JSON.stringify({ ...config, cachedAt: Date.now() }),\n );\n } catch {\n /* private browsing / storage quota */\n }\n}\n\nfunction loadFromCacheStorage(apiKey: string): RemoteConfig | null {\n try {\n const raw = localStorage.getItem(cacheKey(apiKey));\n if (!raw) return null;\n return JSON.parse(raw) as RemoteConfig;\n } catch {\n return null;\n }\n}\n\nfunction isFresh(config: RemoteConfig): boolean {\n if (!config.cachedAt) return false;\n return Date.now() - config.cachedAt < config.ttl;\n}\n\n// ── Public API ────────────────────────────────────────────────────────────────\n\n/**\n * Fetches the remote config with full fallback chain.\n * Never rejects — always returns a usable config.\n */\nexport async function fetchConfig(\n apiKey: string,\n locale: string,\n endpointOverride?: string,\n): Promise<RemoteConfig> {\n // 1. localStorage — fresh\n const cached = loadFromCacheStorage(apiKey);\n if (cached && isFresh(cached)) return cached;\n\n // 2. Remote CDN (with timeout)\n const endpoint = endpointOverride ?? DEFAULT_CDN;\n try {\n const url = new URL(endpoint);\n url.searchParams.set('key', apiKey);\n url.searchParams.set('locale', locale);\n\n const res = await fetch(url.toString(), {\n headers: { Accept: 'application/json' },\n signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),\n });\n\n if (res.ok) {\n const data = (await res.json()) as RemoteConfig;\n data.cachedAt = Date.now();\n saveToCacheStorage(apiKey, data);\n return data;\n }\n } catch {\n /* network error, CSP block, timeout — fall through */\n }\n\n // 3. localStorage — stale (better than nothing)\n if (cached) return cached;\n\n // 4. Bundled default\n return { ...DEFAULT_CONFIG, locale };\n}\n\nexport function getConfig(): RemoteConfig | null {\n // Re-exported from index so callers can inspect the live config\n // (populated asynchronously after init)\n try {\n const { getState } = require('./state') as typeof import('./state');\n return getState().config;\n } catch {\n return null;\n }\n}\n","// DisclosElement — base class for all Disclos Custom Elements\n// Handles config-aware rendering and IntersectionObserver-based visibility tracking.\nimport { getState } from '../core/state';\nimport { CONFIG_LOADED_EVENT } from '../core/init';\nimport type { RemoteConfig } from '../core/types';\n\nexport abstract class DisclosElement extends HTMLElement {\n private _observer: IntersectionObserver | null = null;\n private _disclosed = false;\n private readonly _onConfigLoaded: EventListener = () => this._update();\n\n connectedCallback(): void {\n if (!this.shadowRoot) this.attachShadow({ mode: 'open' });\n this._update();\n this._trackVisibility();\n window.addEventListener(CONFIG_LOADED_EVENT, this._onConfigLoaded);\n }\n\n disconnectedCallback(): void {\n this._observer?.disconnect();\n window.removeEventListener(CONFIG_LOADED_EVENT, this._onConfigLoaded);\n }\n\n attributeChangedCallback(): void {\n if (this.shadowRoot) this._update();\n }\n\n /** Subclasses implement this to produce Shadow DOM HTML */\n protected abstract _html(config: RemoteConfig | null): string;\n\n /** Called once when the element becomes ≥50% visible in the viewport */\n protected _onVisible(): void {\n // Default: no-op. Subclasses override to fire disclosure_shown events.\n }\n\n protected getConfig(): RemoteConfig | null {\n return getState().config;\n }\n\n private _update(): void {\n if (!this.shadowRoot) return;\n this.shadowRoot.innerHTML = this._html(this.getConfig());\n }\n\n private _trackVisibility(): void {\n if (typeof IntersectionObserver === 'undefined') {\n // Fallback for environments without IntersectionObserver (tests, old browsers)\n if (!this._disclosed) {\n this._disclosed = true;\n this._onVisible();\n }\n return;\n }\n\n this._observer = new IntersectionObserver(\n ([entry]) => {\n if (entry?.isIntersecting && !this._disclosed) {\n this._disclosed = true;\n this._onVisible();\n }\n },\n { threshold: 0.5 },\n );\n this._observer.observe(this);\n }\n}\n","// Disclos.init() — non-blocking bootstrap for the entire SDK\nimport { getState, setState } from './state';\nimport { fetchConfig } from './config';\nimport type { InitOptions } from './types';\n\nconst CONFIG_LOADED_EVENT = 'disclos:config-loaded';\n\n/**\n * Initialises the SDK. Safe to call multiple times (idempotent after first call).\n *\n * - Sets up the API key, aiSystemId, locale, and options\n * - Creates the event batcher\n * - Kicks off a non-blocking config fetch from the CDN\n * - Drains any localStorage event queue from previous page sessions\n * - Registers all Custom Elements (idempotent)\n *\n * Returns immediately; config fetch happens in the background.\n */\nexport async function init(options: InitOptions): Promise<void> {\n const state = getState();\n\n if (state.initialized) {\n if (state.debug) console.warn('[Disclos] Already initialized — ignoring duplicate init()');\n return;\n }\n\n if (!options.apiKey) throw new Error('[Disclos] apiKey is required');\n if (!options.aiSystemId) throw new Error('[Disclos] aiSystemId is required');\n\n // Lazy-import to preserve tree-shaking for log-only consumers\n const [{ EventBatcher }, { drainQueue }, { registerElements }] = await Promise.all([\n import('../log/batch'),\n import('../log/queue'),\n import('../components/register'),\n ]);\n\n setState({\n initialized: true,\n apiKey: options.apiKey,\n aiSystemId: options.aiSystemId,\n locale: options.locale ?? 'en',\n debug: options.debug ?? false,\n logContent: options.logContent ?? false,\n options,\n batcher: new EventBatcher(options),\n });\n\n // Register Custom Elements — safe to call multiple times\n registerElements();\n\n // Background config fetch — never blocks init()\n void fetchConfig(options.apiKey, options.locale ?? 'en', options.configEndpoint)\n .then((config) => {\n setState({ config });\n // Notify all mounted DisclosElement components to re-render with live text\n if (typeof window !== 'undefined') {\n window.dispatchEvent(new CustomEvent(CONFIG_LOADED_EVENT, { detail: config }));\n }\n if (options.debug) console.debug('[Disclos] Config loaded:', config);\n })\n .catch((err: unknown) => {\n if (options.debug) console.error('[Disclos] Config fetch error:', err);\n });\n\n // Drain any events queued from failed sends in previous page sessions\n void drainQueue().catch((err: unknown) => {\n if (options.debug) console.warn('[Disclos] Queue drain error:', err);\n });\n}\n\nexport { CONFIG_LOADED_EVENT };\n"]}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { DisclosElement } from './chunk-YJEYWPLR.mjs';
|
|
2
|
+
import { init_state, getState } from './chunk-BHR3367P.mjs';
|
|
3
|
+
|
|
4
|
+
// src/components/trust-page.ts
|
|
5
|
+
init_state();
|
|
6
|
+
var STYLES = `
|
|
7
|
+
:host {
|
|
8
|
+
display: block;
|
|
9
|
+
font-family: var(--disclos-font, system-ui, -apple-system, sans-serif);
|
|
10
|
+
color: var(--disclos-text, #111827);
|
|
11
|
+
max-width: var(--disclos-max-width, 860px);
|
|
12
|
+
margin: 0 auto;
|
|
13
|
+
padding: var(--disclos-padding, 2rem 1rem);
|
|
14
|
+
box-sizing: border-box;
|
|
15
|
+
}
|
|
16
|
+
.header { border-bottom: 2px solid #e5e7eb; padding-bottom: 1.5rem; margin-bottom: 2rem; }
|
|
17
|
+
.title { font-size: 1.75rem; font-weight: 700; margin: 0 0 0.5rem; }
|
|
18
|
+
.subtitle { color: #6b7280; margin: 0; font-size: 0.95rem; }
|
|
19
|
+
.system-grid { display: grid; gap: 1rem; }
|
|
20
|
+
.system-card {
|
|
21
|
+
border: 1px solid #e5e7eb; border-radius: 10px; padding: 1.25rem;
|
|
22
|
+
background: #fafafa;
|
|
23
|
+
}
|
|
24
|
+
.system-name { font-weight: 600; font-size: 1.05rem; margin: 0 0 0.5rem; }
|
|
25
|
+
.system-meta { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 0.75rem; }
|
|
26
|
+
.badge {
|
|
27
|
+
font-size: 0.72rem; font-weight: 500; padding: 2px 8px; border-radius: 99px;
|
|
28
|
+
background: #e0e7ff; color: #3730a3;
|
|
29
|
+
}
|
|
30
|
+
.badge.risk-high { background: #fee2e2; color: #991b1b; }
|
|
31
|
+
.badge.risk-limited { background: #fef3c7; color: #92400e; }
|
|
32
|
+
.badge.risk-minimal { background: #d1fae5; color: #065f46; }
|
|
33
|
+
.purpose { font-size: 0.875rem; color: #4b5563; }
|
|
34
|
+
.loading { text-align: center; padding: 3rem; color: #9ca3af; }
|
|
35
|
+
.error { text-align: center; padding: 2rem; color: #ef4444; font-size: 0.9rem; }
|
|
36
|
+
.footer { margin-top: 2rem; padding-top: 1rem; border-top: 1px solid #e5e7eb;
|
|
37
|
+
font-size: 0.75rem; color: #9ca3af; text-align: center; }
|
|
38
|
+
a { color: #2563eb; }
|
|
39
|
+
`;
|
|
40
|
+
var TrustPage = class extends DisclosElement {
|
|
41
|
+
constructor() {
|
|
42
|
+
super(...arguments);
|
|
43
|
+
this._data = null;
|
|
44
|
+
this._error = false;
|
|
45
|
+
this._loading = true;
|
|
46
|
+
}
|
|
47
|
+
static get observedAttributes() {
|
|
48
|
+
return ["ai-system-id"];
|
|
49
|
+
}
|
|
50
|
+
connectedCallback() {
|
|
51
|
+
super.connectedCallback();
|
|
52
|
+
void this._load();
|
|
53
|
+
}
|
|
54
|
+
_html(_config) {
|
|
55
|
+
if (this._loading) {
|
|
56
|
+
return `<style>${STYLES}</style><div class="loading">Loading AI transparency information\u2026</div>`;
|
|
57
|
+
}
|
|
58
|
+
if (this._error || !this._data) {
|
|
59
|
+
return `<style>${STYLES}</style><div class="error">Unable to load transparency information. Please try again later.</div>`;
|
|
60
|
+
}
|
|
61
|
+
const { org, systems } = this._data;
|
|
62
|
+
const systemCards = systems.map(renderSystemCard).join("");
|
|
63
|
+
return `<style>${STYLES}</style>
|
|
64
|
+
<div class="header">
|
|
65
|
+
<h1 class="title">${esc(org.name)} \u2014 AI Transparency</h1>
|
|
66
|
+
<p class="subtitle">Published AI System Inventory under the EU AI Act (Article 50)</p>
|
|
67
|
+
</div>
|
|
68
|
+
<div class="system-grid">${systemCards}</div>
|
|
69
|
+
<div class="footer">
|
|
70
|
+
Transparency information powered by <a href="https://disclos.dev" target="_blank" rel="noopener">Disclos</a>
|
|
71
|
+
\xB7 Last updated ${(/* @__PURE__ */ new Date()).toLocaleDateString()}
|
|
72
|
+
</div>`;
|
|
73
|
+
}
|
|
74
|
+
async _load() {
|
|
75
|
+
const state = getState();
|
|
76
|
+
const aiSystemId = this.getAttribute("ai-system-id") ?? state.aiSystemId;
|
|
77
|
+
try {
|
|
78
|
+
const url = new URL("https://cdn.disclos.dev/v1/trust-page");
|
|
79
|
+
url.searchParams.set("key", state.apiKey);
|
|
80
|
+
if (aiSystemId) url.searchParams.set("aiSystemId", aiSystemId);
|
|
81
|
+
const res = await fetch(url.toString(), { signal: AbortSignal.timeout(5e3) });
|
|
82
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
83
|
+
this._data = await res.json();
|
|
84
|
+
} catch {
|
|
85
|
+
this._error = true;
|
|
86
|
+
} finally {
|
|
87
|
+
this._loading = false;
|
|
88
|
+
if (this.shadowRoot) this.shadowRoot.innerHTML = this._html(this.getConfig());
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
function renderSystemCard(s) {
|
|
93
|
+
const riskClass = s.riskClassification.includes("high") ? "risk-high" : s.riskClassification.includes("limited") ? "risk-limited" : "risk-minimal";
|
|
94
|
+
const techniques = s.aiTechniques.map((t) => `<span class="badge">${esc(t)}</span>`).join("");
|
|
95
|
+
const euBadge = s.euUserExposure ? '<span class="badge">\u{1F1EA}\u{1F1FA} EU users</span>' : "";
|
|
96
|
+
return `
|
|
97
|
+
<div class="system-card" role="article">
|
|
98
|
+
<p class="system-name">${esc(s.name)}</p>
|
|
99
|
+
<div class="system-meta">
|
|
100
|
+
<span class="badge ${riskClass}">${esc(s.riskClassification.replace(/_/g, " "))}</span>
|
|
101
|
+
<span class="badge">${esc(s.role)}</span>
|
|
102
|
+
${techniques}
|
|
103
|
+
${euBadge}
|
|
104
|
+
</div>
|
|
105
|
+
${s.purpose ? `<p class="purpose">${esc(s.purpose)}</p>` : ""}
|
|
106
|
+
</div>`;
|
|
107
|
+
}
|
|
108
|
+
function esc(s) {
|
|
109
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
110
|
+
}
|
|
111
|
+
if (!customElements.get("disclos-trust-page")) {
|
|
112
|
+
customElements.define("disclos-trust-page", TrustPage);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export { TrustPage };
|
|
116
|
+
//# sourceMappingURL=chunk-UU6VG7CJ.mjs.map
|
|
117
|
+
//# sourceMappingURL=chunk-UU6VG7CJ.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/trust-page.ts"],"names":[],"mappings":"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","file":"chunk-UU6VG7CJ.mjs","sourcesContent":["// <disclos-trust-page> — drop-in AI transparency page component\n// Lazy-fetches the customer's published AI System Inventory from the CDN.\n// Renders a polished, responsive, accessible page — no framework required.\nimport { DisclosElement } from './base';\nimport { getState } from '../core/state';\nimport type { RemoteConfig } from '../core/types';\n\nconst STYLES = `\n:host {\n display: block;\n font-family: var(--disclos-font, system-ui, -apple-system, sans-serif);\n color: var(--disclos-text, #111827);\n max-width: var(--disclos-max-width, 860px);\n margin: 0 auto;\n padding: var(--disclos-padding, 2rem 1rem);\n box-sizing: border-box;\n}\n.header { border-bottom: 2px solid #e5e7eb; padding-bottom: 1.5rem; margin-bottom: 2rem; }\n.title { font-size: 1.75rem; font-weight: 700; margin: 0 0 0.5rem; }\n.subtitle { color: #6b7280; margin: 0; font-size: 0.95rem; }\n.system-grid { display: grid; gap: 1rem; }\n.system-card {\n border: 1px solid #e5e7eb; border-radius: 10px; padding: 1.25rem;\n background: #fafafa;\n}\n.system-name { font-weight: 600; font-size: 1.05rem; margin: 0 0 0.5rem; }\n.system-meta { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 0.75rem; }\n.badge {\n font-size: 0.72rem; font-weight: 500; padding: 2px 8px; border-radius: 99px;\n background: #e0e7ff; color: #3730a3;\n}\n.badge.risk-high { background: #fee2e2; color: #991b1b; }\n.badge.risk-limited { background: #fef3c7; color: #92400e; }\n.badge.risk-minimal { background: #d1fae5; color: #065f46; }\n.purpose { font-size: 0.875rem; color: #4b5563; }\n.loading { text-align: center; padding: 3rem; color: #9ca3af; }\n.error { text-align: center; padding: 2rem; color: #ef4444; font-size: 0.9rem; }\n.footer { margin-top: 2rem; padding-top: 1rem; border-top: 1px solid #e5e7eb;\n font-size: 0.75rem; color: #9ca3af; text-align: center; }\na { color: #2563eb; }\n`;\n\nexport class TrustPage extends DisclosElement {\n private _data: TrustPageData | null = null;\n private _error = false;\n private _loading = true;\n\n static get observedAttributes(): string[] {\n return ['ai-system-id'];\n }\n\n connectedCallback(): void {\n super.connectedCallback();\n void this._load();\n }\n\n protected _html(_config: RemoteConfig | null): string {\n if (this._loading) {\n return `<style>${STYLES}</style><div class=\"loading\">Loading AI transparency information…</div>`;\n }\n if (this._error || !this._data) {\n return `<style>${STYLES}</style><div class=\"error\">Unable to load transparency information. Please try again later.</div>`;\n }\n\n const { org, systems } = this._data;\n const systemCards = systems.map(renderSystemCard).join('');\n\n return `<style>${STYLES}</style>\n<div class=\"header\">\n <h1 class=\"title\">${esc(org.name)} — AI Transparency</h1>\n <p class=\"subtitle\">Published AI System Inventory under the EU AI Act (Article 50)</p>\n</div>\n<div class=\"system-grid\">${systemCards}</div>\n<div class=\"footer\">\n Transparency information powered by <a href=\"https://disclos.dev\" target=\"_blank\" rel=\"noopener\">Disclos</a>\n · Last updated ${new Date().toLocaleDateString()}\n</div>`;\n }\n\n private async _load(): Promise<void> {\n const state = getState();\n const aiSystemId = this.getAttribute('ai-system-id') ?? state.aiSystemId;\n\n try {\n const url = new URL('https://cdn.disclos.dev/v1/trust-page');\n url.searchParams.set('key', state.apiKey);\n if (aiSystemId) url.searchParams.set('aiSystemId', aiSystemId);\n\n const res = await fetch(url.toString(), { signal: AbortSignal.timeout(5_000) });\n if (!res.ok) throw new Error(`HTTP ${res.status}`);\n this._data = (await res.json()) as TrustPageData;\n } catch {\n this._error = true;\n } finally {\n this._loading = false;\n // Trigger re-render\n if (this.shadowRoot) this.shadowRoot.innerHTML = this._html(this.getConfig());\n }\n }\n}\n\n// ── Data types ────────────────────────────────────────────────────────────────\n\ninterface TrustPageData {\n org: { name: string };\n systems: Array<{\n name: string;\n purpose: string;\n riskClassification: string;\n role: string;\n aiTechniques: string[];\n euUserExposure: boolean;\n }>;\n}\n\n// ── Helpers ───────────────────────────────────────────────────────────────────\n\nfunction renderSystemCard(s: TrustPageData['systems'][number]): string {\n const riskClass = s.riskClassification.includes('high')\n ? 'risk-high'\n : s.riskClassification.includes('limited')\n ? 'risk-limited'\n : 'risk-minimal';\n const techniques = s.aiTechniques.map((t) => `<span class=\"badge\">${esc(t)}</span>`).join('');\n const euBadge = s.euUserExposure ? '<span class=\"badge\">🇪🇺 EU users</span>' : '';\n\n return `\n<div class=\"system-card\" role=\"article\">\n <p class=\"system-name\">${esc(s.name)}</p>\n <div class=\"system-meta\">\n <span class=\"badge ${riskClass}\">${esc(s.riskClassification.replace(/_/g, ' '))}</span>\n <span class=\"badge\">${esc(s.role)}</span>\n ${techniques}\n ${euBadge}\n </div>\n ${s.purpose ? `<p class=\"purpose\">${esc(s.purpose)}</p>` : ''}\n</div>`;\n}\n\nfunction esc(s: string): string {\n return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');\n}\n\nif (!customElements.get('disclos-trust-page')) {\n customElements.define('disclos-trust-page', TrustPage);\n}\n"]}
|