Skip to content

Commit 6a33ec9

Browse files
authored
Merge pull request #154 from GleapSDK/kai/auto-detect-host-app-dark-light--a815aa69
Release 19.0.0: console/network logs, dark / light mode, 429 and WebSocket backoff
2 parents 4f31677 + a36eab2 commit 6a33ec9

31 files changed

Lines changed: 4504 additions & 546 deletions

‎CHANGELOG.md‎

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,19 @@
11
# Changelog
22

3-
## 18.2.0
4-
Added an expand/collapse window option for the web messenger. End users can switch the widget between the compact window and a larger one (690px wide, as tall as the browser window allows) with a new button in the messenger header; the choice is remembered per browser (localStorage key `gleap-widget-widget-expanded`). The button is on by default and can be turned off per project in the widget settings ("Allow users to expand the messenger"). It is not shown on the full-screen mobile layout (viewport ≤ 450px) or for surveys. The expanded state is independent of the wider news/article view and survives navigation.
3+
## 19.0.0
4+
Added widget color schemes, so the widget can match the host app's dark/light mode. Turn it on in the dashboard (Widget → Look & feel → Adapt to dark / light mode, delivered as `colorScheme` in the flow config) or at runtime with `Gleap.setColorScheme("auto" | "light" | "dark", options?)`, which overrides the dashboard (until the first call, the dashboard setting applies):
5+
`"auto"` follows the host app and switches live when it changes. It looks at theme markers on `<html>`/`<body>` (classes like `dark`/`light`, attributes like `data-theme`, `data-bs-theme`, `data-color-scheme`, `data-mode`), then the page's CSS `color-scheme`, then the page background, and finally the OS `prefers-color-scheme`.
6+
`"light"` / `"dark"` force a scheme, e.g. from your app's own theme toggle. Any other value is treated as `"auto"`.
7+
`Gleap.setColorScheme` only takes effect when "Adapt to dark / light mode" is enabled in the dashboard. While it is disabled (`colorScheme` missing or `"default"`), the widget is never themed, whatever the runtime scheme or backgrounds.
8+
The dashboard colors are the light palette. Dark mode uses the dark colors set in the dashboard: header colors (`darkHeaderColor`, `darkHeaderColor2`, `darkHeaderColor3`), UI color (`darkColor`) and background (`darkBackgroundColor`); a color without a dark value keeps its light one. Dark mode also uses the dark logo, header background image and composer glow set in the dashboard (`darkLogo`, `darkBgImage`, `darkAurora`); an empty dark logo/image means none in dark mode, and configs without these fields keep the light ones. Without any dark colors the widget keeps its normal colors, even when the host app is dark. The launcher, notifications, messenger, modals, AI chatbar and checklists all switch palettes, live. The runtime `{ lightBackgroundColor, darkBackgroundColor }` options (#rgb/#rrggbb) override the background of the respective scheme; a runtime `darkBackgroundColor` also enables dark mode on its own. Button color is unchanged.
9+
The active scheme also applies to the AI chatbar (its style switches to the matching light/dark variant), to open modals, and to `<gleap-checklist>` elements without an explicit `dark` attribute. Product tour popovers now follow a dark widget background instead of staying white (their text was unreadable on dark backgrounds).
10+
Can be called before or after `Gleap.initialize`.
11+
Console logs are more complete and readable. The SDK no longer replaces `window.console` with a copy: it wraps `log`, `info`, `warn`, `error`, `debug` and `assert` (logged only when the assertion fails) in place and always calls the original method. `Gleap.disableConsoleLogOverwrite()` restores only the methods Gleap still owns, so a tool that wrapped the console after Gleap keeps working. Arguments are formatted instead of concatenated: objects and arrays are logged as compact JSON (four levels deep, circular references marked) instead of `[object Object]`, errors with their stack, DOM elements as `<tag#id.class>`, Maps and Sets summarized, and `%s`, `%d`, `%i`, `%f`, `%o`, `%O` and `%j` substitutions are applied (`%c` styles are dropped). Uncaught errors and unhandled promise rejections are now logged as errors. An entry is cut at 1,000 characters (5,000 for errors) and marked `… [truncated]`.
12+
Network logs no longer hold responses in memory. The logger copied every `text/*` response and read the copy in full, so a server-sent events stream was buffered for the lifetime of the page and its connection stayed open after the app closed it. Streaming responses (`text/event-stream`, NDJSON, gRPC, `multipart/x-mixed-replace`) are now never read, other text responses are read from a copy up to 150 KB and the copy is then cancelled, and binary responses are not read at all (`[binary body omitted]`). Status, status text and response headers are recorded as soon as the headers arrive.
13+
Network log entries are more accurate. URLs are logged absolute and methods upper case. Request headers passed as a `Headers` object (logged as `{}` before), a list of pairs or a `Request` are recorded, and request bodies from `URLSearchParams`, `FormData` (text fields plus file names and sizes), blobs, typed arrays and `Request` objects are logged as text. Failed requests (network error, abort, timeout) carry the error, e.g. `TypeError: Failed to fetch`. XHR requests now record response headers, log `json` responses as JSON instead of `<json>`, report aborts and timeouts, and a reused XHR no longer adds another set of listeners on every `open()`. Resource timing entries have the correct time, and requests made with a relative URL are no longer listed twice. Requests to blacklisted URLs, the SDK's own included, no longer take one of the buffered request slots.
14+
Network log privacy settings apply more thoroughly. Props to ignore (from the dashboard and `Gleap.setNetworkLogPropsToIgnore`) are matched case-insensitively and removed from request and response headers, from JSON bodies at any depth (a dotted prop such as `user.password` also matches that path from the root), from form bodies and from URL query parameters. A body that is not valid JSON is no longer re-encoded as a JSON string. `Authorization`, `Proxy-Authorization`, `Cookie` and `Set-Cookie` header values are always replaced with `[REDACTED]`. The same rules and the URL blacklist now also apply to logs attached with `Gleap.attachNetworkLogs`. `setNetworkLogPropsToIgnore` and `setNetworkLogsBlacklist` replace their previous list instead of appending to it, the dashboard settings are replaced on every config refresh instead of piling up, and both lists apply together.
15+
Fixed: the event stream (`/sessions/events`, which delivers `trackEvent`s, page views and session starts) could keep hitting an overloaded API and lost events. Each request carried the whole queue, which was emptied as soon as it went out, so the events of a failed request (429, 5xx, network error) were lost; after three failures it only paused until a fixed one-minute reset, a request that never answered blocked the stream, and an event whose data cannot be sent as JSON stopped it for good. Requests now only go out with a session, one at a time, give up after 30 s, and carry the oldest 100 events or about 256 KB at most; the rest follows right after a delivered request. After a 408, a 429, a 5xx, a network error or a timeout the events stay queued (any other error answer, e.g. 400 or 413, drops them, so they cannot hold back the queue) and the next request waits 3 s, then 6, 12, 24, 48 and at most 60 s (±20 % jitter), or longer when the answer has a `Retry-After` (seconds or an HTTP date, up to 5 minutes). Any 2xx answer delivers exactly the events it carried (events tracked in the meantime wait for the next request) and brings back the normal 2.5 s interval. The queue keeps at most 500 events; a session start is kept and the oldest other events make room. An event whose data cannot be sent as JSON is dropped instead of holding back the others.
16+
Fixed: the real-time connection (WebSocket) reconnected every 5 s after it dropped, forever and from every open tab in step, also while the browser was offline, and a reconnect still pending when the session changed (e.g. after `identify`) closed the new connection. Reconnects now wait 1 s, then 2, 4, 8, 16, 32 and at most 60 s (±20 % jitter). The wait starts over only after a connection stayed open for 10 s or received a message, so a server that accepts and closes connections right away is not retried every second. Only one reconnect is ever pending, and a new connection cancels it. While the browser is offline no reconnect is attempted; when it is back online the SDK reconnects right away. `Gleap.destroy()` now also closes the connection. The event stream only sends while connected, so its events stay queued until the connection is back.
517

618
## 18.1.2
719
Screenshots keep the layout around blocked elements. 18.1.1 replaced a blocked element with an empty placeholder of its size, and content after it could move, so drawings on the screenshot, which are in page coordinates, marked the wrong content: the margins of the element's first and last child that collapse through its edges were lost (a `<p>` in a blocked `<div>` moved everything after it up by its margins), a blocked `display: contents` element disappeared, a blocked table cell lost its `colspan` and `rowspan`, a blocked table row or row group took its cells' share of the column widths with it, and under a CSS transform or zoom the placeholder was scaled a second time.

‎README.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,14 @@ Gleap.setRegion("us");
4747
Gleap.initialize("SDK-TOKEN");
4848
```
4949

50+
### Dark mode (optional)
51+
52+
The widget can match your app's dark/light mode. Enable "Adapt to dark / light mode" in the dashboard (Widget → Look & feel) and set the dark colors there: header colors, UI color and background. In dark mode the widget uses these dark colors, plus the dark logo, header image and composer glow set in the dashboard; without dark colors it keeps its normal colors. Override the scheme at runtime, e.g. from your own theme toggle (only takes effect while "Adapt to dark / light mode" is enabled in the dashboard; until you call it, the dashboard setting applies):
53+
54+
```
55+
Gleap.setColorScheme("auto"); // follows your app; or "light" / "dark" to force a mode
56+
```
57+
5058
Congrats, you are now all set! Report your first bug by using the feedback button.
5159

5260
## 🤝 Need help?

‎build/browser/index.js‎

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎build/browser/index.js.map‎

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎build/cjs/index.js‎

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎build/cjs/index.js.map‎

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎build/esm/index.mjs‎

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

‎build/esm/index.mjs.map‎

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎demo/main.js‎

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,6 @@ Gleap.setFrameUrl('http://0.0.0.0:3001');
44
Gleap.setApiUrl('http://0.0.0.0:9000');
55
Gleap.setWSApiUrl('ws://0.0.0.0:9000');
66

7-
Gleap.initialize('ogWhNhuiZcGWrva5nlDS8l7a78OfaLlV');
7+
// Gleap.setColorScheme('dark');
88

9-
// Gleap.showAiChatbar();
10-
// Gleap.hideAiChatbar();
11-
12-
// setTimeout(() => {
13-
// Gleap.startBot("6908b32c145ee7d9aa226782");
14-
// }, 1000);
15-
16-
Gleap.identify('5355062', {
17-
email: 'luca@gleap.io',
18-
name: 'Tobias',
19-
company: { id: 'acme-inc', name: 'Acme Inc.' },
20-
});
9+
Gleap.initialize('1sfbVtAFgVNWfKxXiR3jaEIgiFze5eB1');

‎index.d.ts‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,28 @@ export namespace Gleap {
237237
function close(): void;
238238
function hide(): void;
239239
function setUseCookies(useCookies: boolean): void;
240+
/**
241+
* Sets the widget's color scheme, overriding the dashboard's "Color scheme"
242+
* setting, which applies until this is called. Only takes effect when "Adapt
243+
* to dark / light mode" is enabled in the dashboard; while it is disabled the
244+
* widget is never themed. "auto" follows the host app's dark/light mode (theme
245+
* classes/attributes like `class="dark"` or `data-theme="dark"`, the CSS
246+
* color-scheme, the page background, then the OS preference) and switches
247+
* live. "light"/"dark" force a scheme. Any other value (including the former
248+
* "default") is treated as "auto". Dark mode uses the dark colors set in the
249+
* dashboard (header colors, UI color, background) and the dark logo, header
250+
* image and composer glow set there; without dark colors the widget keeps
251+
* its normal colors.
252+
*/
253+
function setColorScheme(
254+
colorScheme: "auto" | "light" | "dark",
255+
options?: {
256+
/** #rrggbb background used in light mode. Defaults to the dashboard background. */
257+
lightBackgroundColor?: string;
258+
/** #rrggbb background used in dark mode. Defaults to the dashboard's dark background. Also enables dark mode without dark colors in the dashboard. */
259+
darkBackgroundColor?: string;
260+
}
261+
): void;
240262
function setEnvironment(environment: "dev" | "staging" | "prod"): void;
241263
/**
242264
* Env data keys (e.g. "currentUrl", "userAgent") that are removed before a

0 commit comments

Comments
 (0)