@syntrologie/adapt-chatbot 2.26.0 → 2.27.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/ChatAssistantLit.d.ts +42 -12
- package/dist/ChatAssistantLit.d.ts.map +1 -1
- package/dist/ChatAssistantLit.js +1 -1
- package/dist/{chunk-O7RWNUVU.js → chunk-W457NMGD.js} +104 -17
- package/dist/{chunk-O7RWNUVU.js.map → chunk-W457NMGD.js.map} +2 -2
- package/dist/runtime.js +1 -1
- package/package.json +1 -1
|
@@ -11,13 +11,21 @@
|
|
|
11
11
|
* `window.__SYNTRO_CONFIG__.token` (set by runtime-config.js) — we read
|
|
12
12
|
* it at mount time and forward it via `Authorization: Bearer` header.
|
|
13
13
|
*
|
|
14
|
-
* 2. Cloudflare Turnstile bot-check token. When
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
14
|
+
* 2. Cloudflare Turnstile bot-check token (two-phase). When
|
|
15
|
+
* `TURNSTILE_SITEKEY` is set:
|
|
16
|
+
* a. Try invisible first — passive fingerprints, no UI. Clean
|
|
17
|
+
* traffic resolves in milliseconds. Token forwarded via
|
|
18
|
+
* `CF-Turnstile-Token`.
|
|
19
|
+
* b. If CF declines to grant silently (datacenter IP, automation
|
|
20
|
+
* signals, strict-privacy browser), render a visible managed
|
|
21
|
+
* widget inside the chat container so CF can present the
|
|
22
|
+
* "I am human" checkbox. On solve, swap to the chat UI.
|
|
23
|
+
* c. If both phases fail, fall through with no token; backend
|
|
24
|
+
* enforcement returns 403 and the existing fallback card
|
|
25
|
+
* renders. The widget mode must be `managed` on the CF side
|
|
26
|
+
* for the visible escalation to work — see
|
|
27
|
+
* cloudflare/turnstile/main.tf in syntro-infra.
|
|
28
|
+
* If sitekey is empty, this step is skipped entirely.
|
|
21
29
|
*
|
|
22
30
|
* 3. Fallback card. If the first agent run fails (Cloudflare Turnstile
|
|
23
31
|
* bot-check failure, CORS / network error, or a server-side rejection),
|
|
@@ -37,6 +45,28 @@ export interface ChatAssistantLitProps {
|
|
|
37
45
|
runtime: ChatbotWidgetRuntime;
|
|
38
46
|
tileId?: string;
|
|
39
47
|
}
|
|
48
|
+
export interface AcquireTurnstileOptions {
|
|
49
|
+
/**
|
|
50
|
+
* Widget size. `invisible` for the silent first attempt; `flexible`
|
|
51
|
+
* (or `normal`) for the visible managed checkbox after silent failure.
|
|
52
|
+
*/
|
|
53
|
+
size: 'invisible' | 'flexible' | 'normal' | 'compact';
|
|
54
|
+
/**
|
|
55
|
+
* Where to mount the widget. For `invisible` this is an off-screen
|
|
56
|
+
* host; for the visible sizes it must be a container that's actually
|
|
57
|
+
* in the layout so CF can render the challenge UI. When omitted, an
|
|
58
|
+
* off-screen div is created and removed automatically (suitable for
|
|
59
|
+
* `invisible` only — visible sizes need a real host).
|
|
60
|
+
*/
|
|
61
|
+
host?: HTMLElement;
|
|
62
|
+
/**
|
|
63
|
+
* Cancels an in-flight acquisition. On abort, the promise resolves to
|
|
64
|
+
* `null`, the CF widget is removed from the registry, and any owned
|
|
65
|
+
* host is torn down. Required for cleanup-during-challenge — without
|
|
66
|
+
* it, a user dismissing the tile mid-checkbox leaks the widget.
|
|
67
|
+
*/
|
|
68
|
+
signal?: AbortSignal;
|
|
69
|
+
}
|
|
40
70
|
/**
|
|
41
71
|
* Acquire a Cloudflare Turnstile token. Returns null when:
|
|
42
72
|
* • TURNSTILE_SITEKEY is empty (Turnstile disabled at build time)
|
|
@@ -44,14 +74,14 @@ export interface ChatAssistantLitProps {
|
|
|
44
74
|
* • the render callback doesn't fire within TURNSTILE_ACQUIRE_TIMEOUT_MS
|
|
45
75
|
* • Cloudflare returns an error-callback (e.g., rate-limited, bad sitekey)
|
|
46
76
|
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* the
|
|
77
|
+
* Calls `turnstile.remove(widgetId)` on settle so CF's internal widget
|
|
78
|
+
* registry doesn't leak across re-mounts (CF will otherwise log
|
|
79
|
+
* `Cannot find Widget ...` when subsequent renders look up the old
|
|
80
|
+
* widget by id and find the host gone).
|
|
51
81
|
*
|
|
52
82
|
* Exported for tests; the production code path goes through `mount()`.
|
|
53
83
|
*/
|
|
54
|
-
export declare function acquireTurnstileToken(): Promise<string | null>;
|
|
84
|
+
export declare function acquireTurnstileToken(opts?: AcquireTurnstileOptions): Promise<string | null>;
|
|
55
85
|
export declare const ChatAssistantLitMountable: {
|
|
56
86
|
mount(container: HTMLElement, mountConfig?: Record<string, unknown>): () => void;
|
|
57
87
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatAssistantLit.d.ts","sourceRoot":"","sources":["../src/ChatAssistantLit.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"ChatAssistantLit.d.ts","sourceRoot":"","sources":["../src/ChatAssistantLit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAGH,OAAO,mBAAmB,CAAC;AAK3B,OAAO,KAAK,EAAE,aAAa,EAAmB,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEvF,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,aAAa,CAAC;IACtB,OAAO,EAAE,oBAAoB,CAAC;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAqGD,MAAM,WAAW,uBAAuB;IACtC;;;OAGG;IACH,IAAI,EAAE,WAAW,GAAG,UAAU,GAAG,QAAQ,GAAG,SAAS,CAAC;IACtD;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,GAAE,uBAA+C,GACpD,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAkFxB;AAqGD,eAAO,MAAM,yBAAyB;qBACnB,WAAW,gBAAgB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAwPpE,CAAC"}
|
package/dist/ChatAssistantLit.js
CHANGED
|
@@ -10741,7 +10741,7 @@ function loadTurnstileScript() {
|
|
|
10741
10741
|
document.head.appendChild(script);
|
|
10742
10742
|
});
|
|
10743
10743
|
}
|
|
10744
|
-
async function acquireTurnstileToken() {
|
|
10744
|
+
async function acquireTurnstileToken(opts = { size: "invisible" }) {
|
|
10745
10745
|
if (!TURNSTILE_SITEKEY) return null;
|
|
10746
10746
|
if (typeof window === "undefined" || typeof document === "undefined") return null;
|
|
10747
10747
|
let turnstile;
|
|
@@ -10755,24 +10755,44 @@ async function acquireTurnstileToken() {
|
|
|
10755
10755
|
} catch {
|
|
10756
10756
|
return null;
|
|
10757
10757
|
}
|
|
10758
|
+
const ownsHost = !opts.host;
|
|
10759
|
+
const host = opts.host ?? (() => {
|
|
10760
|
+
const h = document.createElement("div");
|
|
10761
|
+
h.style.cssText = "position:absolute;top:-9999px;left:-9999px;width:0;height:0;overflow:hidden;";
|
|
10762
|
+
h.setAttribute("data-adaptive-chatbot-turnstile-host", "true");
|
|
10763
|
+
document.body.appendChild(h);
|
|
10764
|
+
return h;
|
|
10765
|
+
})();
|
|
10758
10766
|
return new Promise((resolve) => {
|
|
10759
|
-
const host = document.createElement("div");
|
|
10760
|
-
host.style.cssText = "position:absolute;top:-9999px;left:-9999px;width:0;height:0;overflow:hidden;";
|
|
10761
|
-
host.setAttribute("data-adaptive-chatbot-turnstile-host", "true");
|
|
10762
|
-
document.body.appendChild(host);
|
|
10763
10767
|
let settled = false;
|
|
10768
|
+
let widgetId = null;
|
|
10764
10769
|
const settle = (value) => {
|
|
10765
10770
|
if (settled) return;
|
|
10766
10771
|
settled = true;
|
|
10767
10772
|
clearTimeout(timer);
|
|
10768
|
-
|
|
10773
|
+
if (typeof widgetId === "string") {
|
|
10774
|
+
try {
|
|
10775
|
+
turnstile.remove?.(widgetId);
|
|
10776
|
+
} catch {
|
|
10777
|
+
}
|
|
10778
|
+
}
|
|
10779
|
+
if (ownsHost) {
|
|
10780
|
+
setTimeout(() => host.remove(), 0);
|
|
10781
|
+
}
|
|
10769
10782
|
resolve(value);
|
|
10770
10783
|
};
|
|
10771
10784
|
const timer = setTimeout(() => settle(null), TURNSTILE_ACQUIRE_TIMEOUT_MS);
|
|
10785
|
+
if (opts.signal) {
|
|
10786
|
+
if (opts.signal.aborted) {
|
|
10787
|
+
settle(null);
|
|
10788
|
+
return;
|
|
10789
|
+
}
|
|
10790
|
+
opts.signal.addEventListener("abort", () => settle(null), { once: true });
|
|
10791
|
+
}
|
|
10772
10792
|
try {
|
|
10773
|
-
turnstile.render(host, {
|
|
10793
|
+
widgetId = turnstile.render(host, {
|
|
10774
10794
|
sitekey: TURNSTILE_SITEKEY,
|
|
10775
|
-
size:
|
|
10795
|
+
size: opts.size,
|
|
10776
10796
|
callback: (token) => settle(token),
|
|
10777
10797
|
"error-callback": () => settle(null),
|
|
10778
10798
|
"timeout-callback": () => settle(null),
|
|
@@ -10833,8 +10853,10 @@ function renderFallbackHtml(fallback) {
|
|
|
10833
10853
|
return ">";
|
|
10834
10854
|
case '"':
|
|
10835
10855
|
return """;
|
|
10836
|
-
|
|
10856
|
+
case "'":
|
|
10837
10857
|
return "'";
|
|
10858
|
+
default:
|
|
10859
|
+
return ch;
|
|
10838
10860
|
}
|
|
10839
10861
|
});
|
|
10840
10862
|
const ctaHtml = ctaHref && /^https?:\/\//.test(ctaHref) ? `<a href="${escapeHtml(ctaHref)}" target="_blank" rel="noopener noreferrer" style="${ctaStyle}">${escapeHtml(ctaLabel)}</a>` : "";
|
|
@@ -10893,6 +10915,7 @@ var ChatAssistantLitMountable = {
|
|
|
10893
10915
|
}
|
|
10894
10916
|
};
|
|
10895
10917
|
let hadTurnstileToken = null;
|
|
10918
|
+
let botCheckOutcome = "disabled";
|
|
10896
10919
|
const swapToFallback = (reason) => {
|
|
10897
10920
|
if (isUnmounted || hasSucceeded || fallbackRendered) return;
|
|
10898
10921
|
fallbackRendered = true;
|
|
@@ -10900,7 +10923,8 @@ var ChatAssistantLitMountable = {
|
|
|
10900
10923
|
const payload = {
|
|
10901
10924
|
tileId: resolvedTileId,
|
|
10902
10925
|
reason,
|
|
10903
|
-
hadTurnstileToken
|
|
10926
|
+
hadTurnstileToken,
|
|
10927
|
+
botCheckOutcome
|
|
10904
10928
|
};
|
|
10905
10929
|
runtime.events.publish("chatbot.fallback_rendered", payload);
|
|
10906
10930
|
console.warn("[adaptive-chatbot] fallback rendered", payload);
|
|
@@ -10946,14 +10970,45 @@ var ChatAssistantLitMountable = {
|
|
|
10946
10970
|
});
|
|
10947
10971
|
container.appendChild(el);
|
|
10948
10972
|
};
|
|
10973
|
+
let visiblePanel = null;
|
|
10974
|
+
const acquireAbort = new AbortController();
|
|
10975
|
+
const acquireWithEscalation = async () => {
|
|
10976
|
+
const silent = await acquireTurnstileToken({
|
|
10977
|
+
size: "invisible",
|
|
10978
|
+
signal: acquireAbort.signal
|
|
10979
|
+
});
|
|
10980
|
+
if (isUnmounted) return null;
|
|
10981
|
+
if (silent !== null) {
|
|
10982
|
+
botCheckOutcome = "invisible_succeeded";
|
|
10983
|
+
return silent;
|
|
10984
|
+
}
|
|
10985
|
+
visiblePanel = renderVerifyPanel(container);
|
|
10986
|
+
const widgetHost = visiblePanel.querySelector(
|
|
10987
|
+
'[data-adaptive-chatbot-turnstile-host="true"]'
|
|
10988
|
+
);
|
|
10989
|
+
if (!widgetHost) return null;
|
|
10990
|
+
const interactive = await acquireTurnstileToken({
|
|
10991
|
+
size: "flexible",
|
|
10992
|
+
host: widgetHost,
|
|
10993
|
+
signal: acquireAbort.signal
|
|
10994
|
+
});
|
|
10995
|
+
if (isUnmounted) return null;
|
|
10996
|
+
visiblePanel.remove();
|
|
10997
|
+
visiblePanel = null;
|
|
10998
|
+
if (interactive !== null) {
|
|
10999
|
+
botCheckOutcome = "visible_succeeded";
|
|
11000
|
+
return interactive;
|
|
11001
|
+
}
|
|
11002
|
+
botCheckOutcome = "visible_failed";
|
|
11003
|
+
console.warn(
|
|
11004
|
+
"[adaptive-chatbot] turnstile token acquisition failed (visible challenge also rejected) \u2014 connecting without a bot-check token; backend may 403"
|
|
11005
|
+
);
|
|
11006
|
+
return null;
|
|
11007
|
+
};
|
|
10949
11008
|
if (TURNSTILE_SITEKEY) {
|
|
10950
|
-
void
|
|
11009
|
+
void acquireWithEscalation().then((cft) => {
|
|
11010
|
+
if (isUnmounted) return;
|
|
10951
11011
|
hadTurnstileToken = cft !== null;
|
|
10952
|
-
if (!hadTurnstileToken) {
|
|
10953
|
-
console.warn(
|
|
10954
|
-
"[adaptive-chatbot] turnstile token acquisition failed \u2014 connecting without a bot-check token; backend may 403"
|
|
10955
|
-
);
|
|
10956
|
-
}
|
|
10957
11012
|
setupTransport(cft);
|
|
10958
11013
|
});
|
|
10959
11014
|
} else {
|
|
@@ -10962,10 +11017,15 @@ var ChatAssistantLitMountable = {
|
|
|
10962
11017
|
return () => {
|
|
10963
11018
|
isUnmounted = true;
|
|
10964
11019
|
clearTimers();
|
|
11020
|
+
acquireAbort.abort();
|
|
10965
11021
|
if (unsubscribe) {
|
|
10966
11022
|
unsubscribe();
|
|
10967
11023
|
unsubscribe = null;
|
|
10968
11024
|
}
|
|
11025
|
+
if (visiblePanel) {
|
|
11026
|
+
visiblePanel.remove();
|
|
11027
|
+
visiblePanel = null;
|
|
11028
|
+
}
|
|
10969
11029
|
if (!fallbackRendered) {
|
|
10970
11030
|
transport?.disconnect();
|
|
10971
11031
|
el.remove();
|
|
@@ -10973,6 +11033,33 @@ var ChatAssistantLitMountable = {
|
|
|
10973
11033
|
};
|
|
10974
11034
|
}
|
|
10975
11035
|
};
|
|
11036
|
+
function renderVerifyPanel(container) {
|
|
11037
|
+
const panel = document.createElement("div");
|
|
11038
|
+
panel.setAttribute("data-adaptive-chatbot-turnstile-visible", "true");
|
|
11039
|
+
panel.style.cssText = [
|
|
11040
|
+
"display:flex",
|
|
11041
|
+
"flex-direction:column",
|
|
11042
|
+
"align-items:center",
|
|
11043
|
+
"justify-content:center",
|
|
11044
|
+
"gap:14px",
|
|
11045
|
+
"padding:20px",
|
|
11046
|
+
"height:100%",
|
|
11047
|
+
"width:100%",
|
|
11048
|
+
"background:var(--sc-content-background,'transparent')",
|
|
11049
|
+
"color:var(--sc-content-text-color,'#1a1a1a')",
|
|
11050
|
+
"font-family:var(--sc-font-family,'system-ui')",
|
|
11051
|
+
"text-align:center"
|
|
11052
|
+
].join(";");
|
|
11053
|
+
const heading = document.createElement("div");
|
|
11054
|
+
heading.style.cssText = "font-size:14px;font-weight:500;line-height:1.4;";
|
|
11055
|
+
heading.textContent = "Quick check before we start chatting";
|
|
11056
|
+
const widgetHost = document.createElement("div");
|
|
11057
|
+
widgetHost.setAttribute("data-adaptive-chatbot-turnstile-host", "true");
|
|
11058
|
+
panel.appendChild(heading);
|
|
11059
|
+
panel.appendChild(widgetHost);
|
|
11060
|
+
container.appendChild(panel);
|
|
11061
|
+
return panel;
|
|
11062
|
+
}
|
|
10976
11063
|
|
|
10977
11064
|
export {
|
|
10978
11065
|
acquireTurnstileToken,
|
|
@@ -10997,4 +11084,4 @@ fast-json-patch/module/duplex.mjs:
|
|
|
10997
11084
|
* MIT license
|
|
10998
11085
|
*)
|
|
10999
11086
|
*/
|
|
11000
|
-
//# sourceMappingURL=chunk-
|
|
11087
|
+
//# sourceMappingURL=chunk-W457NMGD.js.map
|