@syntrologie/adapt-chatbot 2.29.0 → 2.30.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.
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Editor-session token for draft template verification.
3
+ *
4
+ * In editor mode the backend can verify submitted uiTemplates against the
5
+ * SERVER-SIDE draft of the plan an editor token is bound to (runtime-backend
6
+ * `config_verify/draft.py`) instead of requiring a released GrowthBook
7
+ * config. The chat surfaces attach the token as `X-Syntro-Editor-Token` on
8
+ * the /templates boot publish and every /stream turn; outside editor mode
9
+ * no header is sent and the release-only contract stands.
10
+ *
11
+ * Token source, in order:
12
+ * 1. The page's `editor_source` URL param — the same base64url payload the
13
+ * editor-sdk boots from ({token, api_base}). Read lazily per request so
14
+ * there is no load-order dependency on the editor bundle.
15
+ * 2. `window.__SYNTRO_EDITOR_PARAMS__` — the editor-sdk's injected params,
16
+ * which survive SPA navigations that drop the query string.
17
+ *
18
+ * This is deliberately NOT a workspace-auth channel (that is `runtime.token`,
19
+ * BUG-1785360157). The editor token is an ADDITIVE capability the server
20
+ * validates independently; sending a stale/invalid one is harmless.
21
+ */
22
+ export declare function readEditorToken(): string | undefined;
23
+ //# sourceMappingURL=editorToken.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"editorToken.d.ts","sourceRoot":"","sources":["../src/editorToken.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,eAAe,IAAI,MAAM,GAAG,SAAS,CAoBpD"}
@@ -5,10 +5,11 @@
5
5
  * `packages/runtime-sdk/src/overlays/fetcher.ts` for the sibling pattern
6
6
  * — no shared HTTP client, no axios, no fetch wrapper).
7
7
  *
8
- * Auth: forwards the SDK token from `window.__SYNTRO_CONFIG__.token`
9
- * as a Bearer header, plus the runtime's visitor ids (`X-Distinct-Id` /
10
- * `X-Syntro-Session`) so the backend rehydrates mounts under the same
11
- * session-keyed Redis state the chat persisted to.
8
+ * Auth: forwards the caller-supplied SDK token (from the runtime handle,
9
+ * the single source `Syntro.init` populates BUG-1785360157: never a
10
+ * window global) as a Bearer header, plus the runtime's visitor ids
11
+ * (`X-Distinct-Id` / `X-Syntro-Session`) so the backend rehydrates
12
+ * mounts under the same session-keyed Redis state the chat persisted to.
12
13
  *
13
14
  * 404 contract: the backend returns 404 only when the workspace's SDK
14
15
  * token doesn't resolve to a workspace. The SDK treats 404 as
@@ -22,7 +23,9 @@ export interface FetchMountedElementsOptions {
22
23
  * `/api/adaptive/mounted_elements`). Tests + multi-environment
23
24
  * deploys use this. */
24
25
  endpoint?: string;
25
- /** SDK token. Defaults to `window.__SYNTRO_CONFIG__.token`. */
26
+ /** SDK token from the runtime handle (`runtime.token`). Absent →
27
+ * unauthenticated request; the backend 401s and the caller's null
28
+ * contract kicks in. No window-global fallback (BUG-1785360157). */
26
29
  token?: string;
27
30
  /** Custom fetch implementation — used by tests to mock the network. */
28
31
  fetchImpl?: typeof fetch;
@@ -1 +1 @@
1
- {"version":3,"file":"fetcher.d.ts","sourceRoot":"","sources":["../../src/elements/fetcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAIvD,MAAM,WAAW,2BAA2B;IAC1C;;4BAEwB;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,+DAA+D;IAC/D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uEAAuE;IACvE,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,oDAAoD;IACpD,MAAM,CAAC,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;CAChC;AAED;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,GAAE,2BAAgC,GACxC,OAAO,CAAC,uBAAuB,GAAG,IAAI,CAAC,CA2DzC"}
1
+ {"version":3,"file":"fetcher.d.ts","sourceRoot":"","sources":["../../src/elements/fetcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAIvD,MAAM,WAAW,2BAA2B;IAC1C;;4BAEwB;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;yEAEqE;IACrE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uEAAuE;IACvE,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,oDAAoD;IACpD,MAAM,CAAC,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;CAChC;AAED;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,GAAE,2BAAgC,GACxC,OAAO,CAAC,uBAAuB,GAAG,IAAI,CAAC,CA2DzC"}
package/dist/runtime.js CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  decodeMutationEnvelope,
10
10
  fetchMountedElements,
11
11
  renderFallbackHtml
12
- } from "./chunk-ZXV4GXMO.js";
12
+ } from "./chunk-A3TIGA4G.js";
13
13
  import {
14
14
  pickPersona
15
15
  } from "./chunk-FXHYE6FY.js";
@@ -361,13 +361,31 @@ var ChatSession = class {
361
361
  };
362
362
  var chatSession = new ChatSession();
363
363
 
364
+ // src/editorToken.ts
365
+ function readEditorToken() {
366
+ if (typeof window === "undefined") return void 0;
367
+ try {
368
+ const raw = new URLSearchParams(window.location.search).get("editor_source");
369
+ if (raw) {
370
+ const b64 = raw.replace(/-/g, "+").replace(/_/g, "/");
371
+ const parsed = JSON.parse(atob(b64));
372
+ if (typeof parsed.token === "string" && parsed.token.length > 0) return parsed.token;
373
+ }
374
+ } catch {
375
+ }
376
+ try {
377
+ const params = window.__SYNTRO_EDITOR_PARAMS__;
378
+ if (typeof params?.token === "string" && params.token.length > 0) return params.token;
379
+ } catch {
380
+ }
381
+ return void 0;
382
+ }
383
+
364
384
  // src/ChatTransport.ts
365
385
  var SESSION_READ_DEADLINE_MS = 6e4;
366
386
  var FALLBACK_DEBOUNCE_MS = 1500;
367
- function readSyntroToken() {
368
- if (typeof window === "undefined") return void 0;
369
- const cfg = window.__SYNTRO_CONFIG__;
370
- const token = cfg?.token;
387
+ function readRuntimeToken(runtime2) {
388
+ const token = runtime2?.token;
371
389
  return typeof token === "string" && token.length > 0 ? token : void 0;
372
390
  }
373
391
  function debug(...args) {
@@ -649,7 +667,7 @@ var ChatTransport = class {
649
667
  const baseUrl = this._config.backendUrl.replace(/\/$/, "");
650
668
  const url = `${baseUrl}/api/adaptive/session`;
651
669
  const headers = {};
652
- const token = readSyntroToken();
670
+ const token = readRuntimeToken(this._config?.runtime);
653
671
  if (token) headers.Authorization = `Bearer ${token}`;
654
672
  const cft = await this._acquireTurnstileWithChallenge();
655
673
  if (cft) headers["CF-Turnstile-Token"] = cft;
@@ -932,11 +950,13 @@ var ChatTransport = class {
932
950
  if (this._config === null) return false;
933
951
  const baseUrl = this._config.backendUrl.replace(/\/$/, "");
934
952
  const streamUrl = `${baseUrl}/api/adaptive/stream`;
935
- const token = readSyntroToken();
953
+ const token = readRuntimeToken(this._config?.runtime);
936
954
  const buildHeaders = () => {
937
955
  const h = {};
938
956
  if (token) h.Authorization = `Bearer ${token}`;
939
957
  if (cft) h["CF-Turnstile-Token"] = cft;
958
+ const editorToken = readEditorToken();
959
+ if (editorToken) h["X-Syntro-Editor-Token"] = editorToken;
940
960
  const lidSlot = this._pendingLidSlot ?? this._config?.activeLidSlot;
941
961
  if (typeof lidSlot === "string" && lidSlot.length > 0) {
942
962
  h["X-Active-Lid-Slot"] = lidSlot;
@@ -1814,7 +1834,7 @@ function hydrateOnce(runtime2, backendUrl) {
1814
1834
  const store = getOrCreateElementStore(runtime2);
1815
1835
  const trimmed = backendUrl.replace(/\/$/, "");
1816
1836
  const endpoint = trimmed ? `${trimmed}/api/adaptive/mounted_elements` : "/api/adaptive/mounted_elements";
1817
- fetchMountedElements({ endpoint }).then((response) => {
1837
+ fetchMountedElements({ endpoint, token: runtime2.token }).then((response) => {
1818
1838
  if (!response) return;
1819
1839
  void store.hydrate(response.mounted_elements);
1820
1840
  });
@@ -1866,7 +1886,7 @@ function wireNudgeSurface(runtime2, backendUrl) {
1866
1886
  const store = getOrCreateElementStore(runtime2);
1867
1887
  const trimmed = backendUrl.replace(/\/$/, "");
1868
1888
  const endpoint = trimmed ? `${trimmed}/api/adaptive/mounted_elements` : "/api/adaptive/mounted_elements";
1869
- void fetchMountedElements({ endpoint }).then((response) => {
1889
+ void fetchMountedElements({ endpoint, token: runtime2.token }).then((response) => {
1870
1890
  if (!response) return;
1871
1891
  void store.hydrate(response.mounted_elements);
1872
1892
  });
@@ -1905,7 +1925,7 @@ function configureTransportIfPossible(cfg) {
1905
1925
  const elementsActive = cfg.elementsEnabled === true && cfg.uiTemplates != null;
1906
1926
  refreshTemplateWidgetMap(elementsActive ? cfg.uiTemplates : void 0);
1907
1927
  const forwardedProps = elementsActive ? { elementsEnabled: true, uiTemplates: cfg.uiTemplates } : void 0;
1908
- if (elementsActive) publishTemplatesIfPossible(backendUrl, cfg.uiTemplates);
1928
+ if (elementsActive) publishTemplatesIfPossible(backendUrl, cfg.uiTemplates, cfg.runtime?.token);
1909
1929
  const runtime2 = cfg.runtime;
1910
1930
  const onElementMutation = elementsActive ? (mutations) => {
1911
1931
  void getOrCreateElementStore(runtime2).apply(mutations);
@@ -1929,14 +1949,14 @@ function configureTransportIfPossible(cfg) {
1929
1949
  startObserverIfPossible(cfg);
1930
1950
  }
1931
1951
  var _templatesPublished = false;
1932
- function publishTemplatesIfPossible(backendUrl, uiTemplates) {
1952
+ function publishTemplatesIfPossible(backendUrl, uiTemplates, token) {
1933
1953
  if (_templatesPublished || typeof window === "undefined") return;
1934
1954
  if (!uiTemplates || typeof uiTemplates !== "object") return;
1935
1955
  _templatesPublished = true;
1936
- const cfg = window.__SYNTRO_CONFIG__;
1937
- const token = typeof cfg?.token === "string" && cfg.token.length > 0 ? cfg.token : void 0;
1938
1956
  const headers = { "Content-Type": "application/json" };
1939
1957
  if (token) headers.Authorization = `Bearer ${token}`;
1958
+ const editorToken = readEditorToken();
1959
+ if (editorToken) headers["X-Syntro-Editor-Token"] = editorToken;
1940
1960
  const trimmed = backendUrl.replace(/\/$/, "");
1941
1961
  void fetch(`${trimmed}/api/adaptive/templates`, {
1942
1962
  method: "POST",
@@ -1992,8 +2012,8 @@ function startObserverIfPossible(cfg) {
1992
2012
  const getDistinctId = () => runtimeId("getDistinctId");
1993
2013
  const getSessionId = () => runtimeId("getSessionId");
1994
2014
  const token = () => {
1995
- const c = window.__SYNTRO_CONFIG__;
1996
- return typeof c?.token === "string" ? c.token : "";
2015
+ const t = runtimeRef.token;
2016
+ return typeof t === "string" ? t : "";
1997
2017
  };
1998
2018
  const enrich = buildObserverEnrich(runtimeRef);
1999
2019
  const handle = startObserver({ url, token, getDistinctId, getSessionId, enrich });