capacitor-gleap-plugin 18.1.0 → 19.0.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.
Files changed (43) hide show
  1. package/CapacitorGleapPlugin.podspec +7 -2
  2. package/Package.swift +31 -0
  3. package/README.md +247 -759
  4. package/android/build.gradle +1 -1
  5. package/android/src/main/java/io/gleapplugins/capacitor/GleapPlugin.java +184 -37
  6. package/dist/docs.json +267 -3893
  7. package/dist/esm/definitions.d.ts +145 -3
  8. package/dist/esm/definitions.js.map +1 -1
  9. package/dist/esm/index.js +9 -1
  10. package/dist/esm/index.js.map +1 -1
  11. package/dist/esm/logs/body.d.ts +58 -0
  12. package/dist/esm/logs/body.js +303 -0
  13. package/dist/esm/logs/body.js.map +1 -0
  14. package/dist/esm/logs/consoleCapture.d.ts +29 -0
  15. package/dist/esm/logs/consoleCapture.js +189 -0
  16. package/dist/esm/logs/consoleCapture.js.map +1 -0
  17. package/dist/esm/logs/format.d.ts +16 -0
  18. package/dist/esm/logs/format.js +394 -0
  19. package/dist/esm/logs/format.js.map +1 -0
  20. package/dist/esm/logs/networkCapture.d.ts +65 -0
  21. package/dist/esm/logs/networkCapture.js +654 -0
  22. package/dist/esm/logs/networkCapture.js.map +1 -0
  23. package/dist/esm/logs/redaction.d.ts +54 -0
  24. package/dist/esm/logs/redaction.js +388 -0
  25. package/dist/esm/logs/redaction.js.map +1 -0
  26. package/dist/esm/logs/webViewLogs.d.ts +70 -0
  27. package/dist/esm/logs/webViewLogs.js +297 -0
  28. package/dist/esm/logs/webViewLogs.js.map +1 -0
  29. package/dist/esm/logs/zone.d.ts +5 -0
  30. package/dist/esm/logs/zone.js +15 -0
  31. package/dist/esm/logs/zone.js.map +1 -0
  32. package/dist/esm/web.d.ts +37 -2
  33. package/dist/esm/web.js +34 -0
  34. package/dist/esm/web.js.map +1 -1
  35. package/dist/plugin.cjs.js +2254 -1
  36. package/dist/plugin.cjs.js.map +1 -1
  37. package/dist/plugin.js +2254 -1
  38. package/dist/plugin.js.map +1 -1
  39. package/ios/{Plugin → Sources/GleapPlugin}/GleapPlugin.swift +195 -12
  40. package/package.json +18 -4
  41. package/ios/Plugin/GleapPlugin.h +0 -10
  42. package/ios/Plugin/GleapPlugin.m +0 -68
  43. package/ios/Plugin/Info.plist +0 -24
@@ -0,0 +1,70 @@
1
+ import type { GleapConsoleLogEntry, GleapLogConfig, GleapNetworkLogEntry } from '../definitions';
2
+ /** Pushes are batched: at most one per channel every PUSH_DELAY_MS. */
3
+ export declare const PUSH_DELAY_MS = 500;
4
+ export interface LogTarget {
5
+ attachConsoleLogs(options: {
6
+ logs: GleapConsoleLogEntry[];
7
+ }): Promise<unknown>;
8
+ attachNetworkLogs(options: {
9
+ logs: GleapNetworkLogEntry[];
10
+ }): Promise<unknown>;
11
+ addListener(eventName: 'logConfigLoaded', listenerFunc: (config: GleapLogConfig) => void): Promise<unknown>;
12
+ }
13
+ /**
14
+ * Captures console output and fetch/XHR traffic inside the WebView of a native (iOS / Android) app
15
+ * and hands them to the native SDK, which attaches them to tickets. The native SDKs cannot see
16
+ * either: WebView requests do not go through URLSession / OkHttp, and console output only reaches
17
+ * the native log in debug builds.
18
+ */
19
+ export declare class WebViewLogCapture {
20
+ private readonly win;
21
+ private readonly target;
22
+ private readonly platform;
23
+ private consoleCapture;
24
+ private readonly networkCapture;
25
+ private readonly consoleChannel;
26
+ private readonly networkChannel;
27
+ private isNetworkEnabled;
28
+ private remoteProps;
29
+ private localProps;
30
+ private remoteBlacklist;
31
+ private localBlacklist;
32
+ private rules;
33
+ private rulesVersion;
34
+ private redactedEntries;
35
+ constructor(win: Window, target: LogTarget, platform: string);
36
+ start(): void;
37
+ /**
38
+ * Android debug builds (Capacitor's loggingBehavior) write the WebView console to logcat, which the
39
+ * Android SDK already reads: capturing it here too would log every line twice. On iOS, Capacitor
40
+ * prints it to stdout as "⚡️ [level] - message"; the iOS SDK drops those lines for Capacitor apps
41
+ * (application type CAPACITOR, set in initialize), so iOS always captures here.
42
+ */
43
+ private nativeLogsConsole;
44
+ private listenForConfig;
45
+ applyRemoteConfig(config: GleapLogConfig | null | undefined): void;
46
+ setLocalPropsToIgnore(props: unknown): void;
47
+ setLocalBlacklist(blacklist: unknown): void;
48
+ /** disableConsoleLogOverwrite(): restore the console and drop what was recorded (also natively). */
49
+ disableConsole(): void;
50
+ onInitialize(): void;
51
+ /** Pushes pending changes now (before a plugin call that can produce a report). */
52
+ flushNow(): void;
53
+ private updateRules;
54
+ private canPush;
55
+ private markDirty;
56
+ private flushChannel;
57
+ private onPushFailed;
58
+ /** Redacted copies of the buffered entries; unchanged entries reuse their previous copy. */
59
+ private buildNetworkLogs;
60
+ }
61
+ /**
62
+ * Starts the WebView log capture on iOS and Android (not on web, where the JavaScript SDK records
63
+ * the console and network itself). Safe to call more than once.
64
+ */
65
+ export declare function installWebViewLogCapture(target: LogTarget): WebViewLogCapture | null;
66
+ /**
67
+ * Wraps the registered plugin so the calls that affect the WebView capture reach it before they go
68
+ * to native. Every other call passes through unchanged.
69
+ */
70
+ export declare function wrapPluginWithLogCapture<T extends object>(plugin: T, capture: WebViewLogCapture): T;
@@ -0,0 +1,297 @@
1
+ import { Capacitor } from '@capacitor/core';
2
+ import { ConsoleCapture } from './consoleCapture';
3
+ import { NetworkCapture } from './networkCapture';
4
+ import { createRedactionRules, isBlacklistedUrl, redactNetworkLogEntryOrStrip } from './redaction';
5
+ import { runOutsideZone } from './zone';
6
+ /** Pushes are batched: at most one per channel every PUSH_DELAY_MS. */
7
+ export const PUSH_DELAY_MS = 500;
8
+ /** A channel stops pushing after this many failed pushes in a row (e.g. an outdated native plugin). */
9
+ const MAX_FAILED_PUSHES = 3;
10
+ const GLOBAL_KEY = '__gleapWebViewLogCapture';
11
+ /** Plugin calls that can lead to a report: the latest logs are pushed right before them. */
12
+ const FLUSH_BEFORE_METHODS = [
13
+ 'sendSilentCrashReport',
14
+ 'open',
15
+ 'startFeedbackFlow',
16
+ 'startClassicForm',
17
+ 'startConversation',
18
+ 'openConversation',
19
+ 'openConversations',
20
+ 'startBot',
21
+ ];
22
+ const createChannel = (name) => ({
23
+ name,
24
+ isDirty: false,
25
+ timer: null,
26
+ failures: 0,
27
+ isStopped: false,
28
+ hasPushedLogs: false,
29
+ });
30
+ const toStringArray = (value) => Array.isArray(value) ? value.filter((item) => typeof item === 'string') : [];
31
+ /**
32
+ * Captures console output and fetch/XHR traffic inside the WebView of a native (iOS / Android) app
33
+ * and hands them to the native SDK, which attaches them to tickets. The native SDKs cannot see
34
+ * either: WebView requests do not go through URLSession / OkHttp, and console output only reaches
35
+ * the native log in debug builds.
36
+ */
37
+ export class WebViewLogCapture {
38
+ constructor(win, target, platform) {
39
+ this.win = win;
40
+ this.target = target;
41
+ this.platform = platform;
42
+ this.consoleCapture = null;
43
+ this.consoleChannel = createChannel('console');
44
+ this.networkChannel = createChannel('network');
45
+ this.isNetworkEnabled = false;
46
+ this.remoteProps = [];
47
+ this.localProps = [];
48
+ this.remoteBlacklist = [];
49
+ this.localBlacklist = [];
50
+ this.rules = createRedactionRules([], []);
51
+ this.rulesVersion = 0;
52
+ this.redactedEntries = new Map();
53
+ this.networkCapture = new NetworkCapture(win, () => this.markDirty(this.networkChannel));
54
+ }
55
+ start() {
56
+ if (!this.nativeLogsConsole()) {
57
+ this.consoleCapture = new ConsoleCapture(this.win, () => this.markDirty(this.consoleChannel));
58
+ this.consoleCapture.install();
59
+ }
60
+ // The hooks go in now, but requests are only recorded once the project config says network
61
+ // logs are enabled (like the JavaScript SDK), so nothing is held in memory before that.
62
+ this.networkCapture.install();
63
+ this.listenForConfig();
64
+ }
65
+ /**
66
+ * Android debug builds (Capacitor's loggingBehavior) write the WebView console to logcat, which the
67
+ * Android SDK already reads: capturing it here too would log every line twice. On iOS, Capacitor
68
+ * prints it to stdout as "⚡️ [level] - message"; the iOS SDK drops those lines for Capacitor apps
69
+ * (application type CAPACITOR, set in initialize), so iOS always captures here.
70
+ */
71
+ nativeLogsConsole() {
72
+ const capacitor = this.win.Capacitor;
73
+ return this.platform === 'android' && !!capacitor && capacitor.isLoggingEnabled === true;
74
+ }
75
+ listenForConfig() {
76
+ try {
77
+ const handle = this.target.addListener('logConfigLoaded', (config) => this.applyRemoteConfig(config));
78
+ if (handle && typeof handle.catch === 'function') {
79
+ handle.catch(() => undefined);
80
+ }
81
+ }
82
+ catch (e) {
83
+ // The native side predates the event: network logs stay off.
84
+ }
85
+ }
86
+ applyRemoteConfig(config) {
87
+ try {
88
+ if (!config || typeof config !== 'object') {
89
+ return;
90
+ }
91
+ this.remoteProps = toStringArray(config.networkLogPropsToIgnore);
92
+ this.remoteBlacklist = toStringArray(config.networkLogBlacklist);
93
+ this.updateRules();
94
+ this.isNetworkEnabled = config.enableNetworkLogs === true;
95
+ this.networkCapture.setActive(this.isNetworkEnabled);
96
+ this.markDirty(this.networkChannel);
97
+ }
98
+ catch (e) {
99
+ // Ignore.
100
+ }
101
+ }
102
+ setLocalPropsToIgnore(props) {
103
+ this.localProps = toStringArray(props);
104
+ this.updateRules();
105
+ }
106
+ setLocalBlacklist(blacklist) {
107
+ this.localBlacklist = toStringArray(blacklist);
108
+ this.updateRules();
109
+ }
110
+ /** disableConsoleLogOverwrite(): restore the console and drop what was recorded (also natively). */
111
+ disableConsole() {
112
+ try {
113
+ if (this.consoleCapture) {
114
+ this.consoleCapture.uninstall();
115
+ this.consoleCapture = null;
116
+ }
117
+ this.markDirty(this.consoleChannel);
118
+ this.flushChannel(this.consoleChannel);
119
+ }
120
+ catch (e) {
121
+ // Ignore.
122
+ }
123
+ }
124
+ onInitialize() {
125
+ this.markDirty(this.consoleChannel);
126
+ this.markDirty(this.networkChannel);
127
+ }
128
+ /** Pushes pending changes now (before a plugin call that can produce a report). */
129
+ flushNow() {
130
+ try {
131
+ this.flushChannel(this.consoleChannel);
132
+ this.flushChannel(this.networkChannel);
133
+ }
134
+ catch (e) {
135
+ // Ignore.
136
+ }
137
+ }
138
+ updateRules() {
139
+ this.rules = createRedactionRules([...this.remoteProps, ...this.localProps], [...this.remoteBlacklist, ...this.localBlacklist]);
140
+ this.rulesVersion++;
141
+ this.markDirty(this.networkChannel);
142
+ }
143
+ canPush(channel) {
144
+ if (channel.isStopped) {
145
+ return false;
146
+ }
147
+ if (channel.name === 'network') {
148
+ return this.isNetworkEnabled || channel.hasPushedLogs;
149
+ }
150
+ return true;
151
+ }
152
+ markDirty(channel) {
153
+ channel.isDirty = true;
154
+ if (channel.timer !== null || !this.canPush(channel)) {
155
+ return;
156
+ }
157
+ try {
158
+ channel.timer = runOutsideZone(() => setTimeout(() => {
159
+ channel.timer = null;
160
+ this.flushChannel(channel);
161
+ }, PUSH_DELAY_MS));
162
+ }
163
+ catch (e) {
164
+ channel.timer = null;
165
+ }
166
+ }
167
+ flushChannel(channel) {
168
+ if (channel.timer !== null) {
169
+ clearTimeout(channel.timer);
170
+ channel.timer = null;
171
+ }
172
+ if (!channel.isDirty || !this.canPush(channel)) {
173
+ return;
174
+ }
175
+ channel.isDirty = false;
176
+ let push;
177
+ if (channel.name === 'console') {
178
+ const logs = this.consoleCapture ? this.consoleCapture.getEntries() : [];
179
+ if (logs.length === 0 && !channel.hasPushedLogs) {
180
+ return;
181
+ }
182
+ channel.hasPushedLogs = logs.length > 0;
183
+ push = runOutsideZone(() => this.target.attachConsoleLogs({ logs }));
184
+ }
185
+ else {
186
+ const logs = this.isNetworkEnabled ? this.buildNetworkLogs() : [];
187
+ if (logs.length === 0 && !channel.hasPushedLogs) {
188
+ return;
189
+ }
190
+ channel.hasPushedLogs = logs.length > 0;
191
+ push = runOutsideZone(() => this.target.attachNetworkLogs({ logs }));
192
+ }
193
+ try {
194
+ Promise.resolve(push).then(() => {
195
+ channel.failures = 0;
196
+ }, () => this.onPushFailed(channel));
197
+ }
198
+ catch (e) {
199
+ this.onPushFailed(channel);
200
+ }
201
+ }
202
+ onPushFailed(channel) {
203
+ channel.failures++;
204
+ if (channel.failures >= MAX_FAILED_PUSHES) {
205
+ channel.isStopped = true;
206
+ return;
207
+ }
208
+ this.markDirty(channel);
209
+ }
210
+ /** Redacted copies of the buffered entries; unchanged entries reuse their previous copy. */
211
+ buildNetworkLogs() {
212
+ const logs = [];
213
+ const cache = new Map();
214
+ for (const snapshot of this.networkCapture.getSnapshots()) {
215
+ let cached = this.redactedEntries.get(snapshot.id);
216
+ if (!cached || cached.version !== snapshot.version || cached.rulesVersion !== this.rulesVersion) {
217
+ cached = {
218
+ version: snapshot.version,
219
+ rulesVersion: this.rulesVersion,
220
+ entry: isBlacklistedUrl(snapshot.entry.url, this.rules)
221
+ ? null
222
+ : redactNetworkLogEntryOrStrip(snapshot.entry, this.rules),
223
+ };
224
+ }
225
+ cache.set(snapshot.id, cached);
226
+ if (cached.entry) {
227
+ logs.push(cached.entry);
228
+ }
229
+ }
230
+ this.redactedEntries = cache;
231
+ return logs;
232
+ }
233
+ }
234
+ /**
235
+ * Starts the WebView log capture on iOS and Android (not on web, where the JavaScript SDK records
236
+ * the console and network itself). Safe to call more than once.
237
+ */
238
+ export function installWebViewLogCapture(target) {
239
+ try {
240
+ if (typeof window === 'undefined' || !Capacitor.isNativePlatform()) {
241
+ return null;
242
+ }
243
+ const win = window;
244
+ const existing = win[GLOBAL_KEY];
245
+ if (existing) {
246
+ return existing;
247
+ }
248
+ const capture = new WebViewLogCapture(window, target, Capacitor.getPlatform());
249
+ win[GLOBAL_KEY] = capture;
250
+ capture.start();
251
+ return capture;
252
+ }
253
+ catch (e) {
254
+ return null;
255
+ }
256
+ }
257
+ /**
258
+ * Wraps the registered plugin so the calls that affect the WebView capture reach it before they go
259
+ * to native. Every other call passes through unchanged.
260
+ */
261
+ export function wrapPluginWithLogCapture(plugin, capture) {
262
+ return new Proxy(plugin, {
263
+ get(target, property, receiver) {
264
+ const value = Reflect.get(target, property, receiver);
265
+ if (typeof property !== 'string' || typeof value !== 'function') {
266
+ return value;
267
+ }
268
+ const method = value;
269
+ const before = (hook) => (...args) => {
270
+ try {
271
+ const options = args[0];
272
+ hook(options && typeof options === 'object' ? options : {});
273
+ }
274
+ catch (e) {
275
+ // Never break the plugin call.
276
+ }
277
+ return method(...args);
278
+ };
279
+ switch (property) {
280
+ case 'initialize':
281
+ return before(() => capture.onInitialize());
282
+ case 'setNetworkLogPropsToIgnore':
283
+ return before((options) => capture.setLocalPropsToIgnore(options.propsToIgnore));
284
+ case 'setNetworkLogsBlacklist':
285
+ return before((options) => capture.setLocalBlacklist(options.blacklist));
286
+ case 'disableConsoleLogOverwrite':
287
+ return before(() => capture.disableConsole());
288
+ default:
289
+ if (FLUSH_BEFORE_METHODS.indexOf(property) > -1) {
290
+ return before(() => capture.flushNow());
291
+ }
292
+ return value;
293
+ }
294
+ },
295
+ });
296
+ }
297
+ //# sourceMappingURL=webViewLogs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webViewLogs.js","sourceRoot":"","sources":["../../../src/logs/webViewLogs.ts"],"names":[],"mappings":"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","sourcesContent":["import { Capacitor } from '@capacitor/core';\n\nimport type { GleapConsoleLogEntry, GleapLogConfig, GleapNetworkLogEntry } from '../definitions';\n\nimport { ConsoleCapture } from './consoleCapture';\nimport { NetworkCapture } from './networkCapture';\nimport type { RedactionRules } from './redaction';\nimport { createRedactionRules, isBlacklistedUrl, redactNetworkLogEntryOrStrip } from './redaction';\nimport { runOutsideZone } from './zone';\n\n/** Pushes are batched: at most one per channel every PUSH_DELAY_MS. */\nexport const PUSH_DELAY_MS = 500;\n/** A channel stops pushing after this many failed pushes in a row (e.g. an outdated native plugin). */\nconst MAX_FAILED_PUSHES = 3;\nconst GLOBAL_KEY = '__gleapWebViewLogCapture';\n\n/** Plugin calls that can lead to a report: the latest logs are pushed right before them. */\nconst FLUSH_BEFORE_METHODS = [\n 'sendSilentCrashReport',\n 'open',\n 'startFeedbackFlow',\n 'startClassicForm',\n 'startConversation',\n 'openConversation',\n 'openConversations',\n 'startBot',\n];\n\nexport interface LogTarget {\n attachConsoleLogs(options: { logs: GleapConsoleLogEntry[] }): Promise<unknown>;\n attachNetworkLogs(options: { logs: GleapNetworkLogEntry[] }): Promise<unknown>;\n addListener(eventName: 'logConfigLoaded', listenerFunc: (config: GleapLogConfig) => void): Promise<unknown>;\n}\n\ninterface Channel {\n name: 'console' | 'network';\n isDirty: boolean;\n timer: ReturnType<typeof setTimeout> | null;\n failures: number;\n isStopped: boolean;\n /** Whether native currently holds a non-empty list (so an empty list must be pushed to clear it). */\n hasPushedLogs: boolean;\n}\n\ninterface CachedEntry {\n version: number;\n rulesVersion: number;\n entry: GleapNetworkLogEntry | null;\n}\n\nconst createChannel = (name: Channel['name']): Channel => ({\n name,\n isDirty: false,\n timer: null,\n failures: 0,\n isStopped: false,\n hasPushedLogs: false,\n});\n\nconst toStringArray = (value: unknown): string[] =>\n Array.isArray(value) ? value.filter((item): item is string => typeof item === 'string') : [];\n\n/**\n * Captures console output and fetch/XHR traffic inside the WebView of a native (iOS / Android) app\n * and hands them to the native SDK, which attaches them to tickets. The native SDKs cannot see\n * either: WebView requests do not go through URLSession / OkHttp, and console output only reaches\n * the native log in debug builds.\n */\nexport class WebViewLogCapture {\n private consoleCapture: ConsoleCapture | null = null;\n private readonly networkCapture: NetworkCapture;\n private readonly consoleChannel = createChannel('console');\n private readonly networkChannel = createChannel('network');\n private isNetworkEnabled = false;\n private remoteProps: string[] = [];\n private localProps: string[] = [];\n private remoteBlacklist: string[] = [];\n private localBlacklist: string[] = [];\n private rules: RedactionRules = createRedactionRules([], []);\n private rulesVersion = 0;\n private redactedEntries = new Map<number, CachedEntry>();\n\n constructor(\n private readonly win: Window,\n private readonly target: LogTarget,\n private readonly platform: string,\n ) {\n this.networkCapture = new NetworkCapture(win, () => this.markDirty(this.networkChannel));\n }\n\n start(): void {\n if (!this.nativeLogsConsole()) {\n this.consoleCapture = new ConsoleCapture(this.win, () => this.markDirty(this.consoleChannel));\n this.consoleCapture.install();\n }\n // The hooks go in now, but requests are only recorded once the project config says network\n // logs are enabled (like the JavaScript SDK), so nothing is held in memory before that.\n this.networkCapture.install();\n this.listenForConfig();\n }\n\n /**\n * Android debug builds (Capacitor's loggingBehavior) write the WebView console to logcat, which the\n * Android SDK already reads: capturing it here too would log every line twice. On iOS, Capacitor\n * prints it to stdout as \"⚡️ [level] - message\"; the iOS SDK drops those lines for Capacitor apps\n * (application type CAPACITOR, set in initialize), so iOS always captures here.\n */\n private nativeLogsConsole(): boolean {\n const capacitor = (\n this.win as unknown as {\n Capacitor?: { isLoggingEnabled?: unknown };\n }\n ).Capacitor;\n return this.platform === 'android' && !!capacitor && capacitor.isLoggingEnabled === true;\n }\n\n private listenForConfig(): void {\n try {\n const handle = this.target.addListener('logConfigLoaded', (config) => this.applyRemoteConfig(config));\n if (handle && typeof handle.catch === 'function') {\n handle.catch(() => undefined);\n }\n } catch (e) {\n // The native side predates the event: network logs stay off.\n }\n }\n\n applyRemoteConfig(config: GleapLogConfig | null | undefined): void {\n try {\n if (!config || typeof config !== 'object') {\n return;\n }\n this.remoteProps = toStringArray(config.networkLogPropsToIgnore);\n this.remoteBlacklist = toStringArray(config.networkLogBlacklist);\n this.updateRules();\n this.isNetworkEnabled = config.enableNetworkLogs === true;\n this.networkCapture.setActive(this.isNetworkEnabled);\n this.markDirty(this.networkChannel);\n } catch (e) {\n // Ignore.\n }\n }\n\n setLocalPropsToIgnore(props: unknown): void {\n this.localProps = toStringArray(props);\n this.updateRules();\n }\n\n setLocalBlacklist(blacklist: unknown): void {\n this.localBlacklist = toStringArray(blacklist);\n this.updateRules();\n }\n\n /** disableConsoleLogOverwrite(): restore the console and drop what was recorded (also natively). */\n disableConsole(): void {\n try {\n if (this.consoleCapture) {\n this.consoleCapture.uninstall();\n this.consoleCapture = null;\n }\n this.markDirty(this.consoleChannel);\n this.flushChannel(this.consoleChannel);\n } catch (e) {\n // Ignore.\n }\n }\n\n onInitialize(): void {\n this.markDirty(this.consoleChannel);\n this.markDirty(this.networkChannel);\n }\n\n /** Pushes pending changes now (before a plugin call that can produce a report). */\n flushNow(): void {\n try {\n this.flushChannel(this.consoleChannel);\n this.flushChannel(this.networkChannel);\n } catch (e) {\n // Ignore.\n }\n }\n\n private updateRules(): void {\n this.rules = createRedactionRules(\n [...this.remoteProps, ...this.localProps],\n [...this.remoteBlacklist, ...this.localBlacklist],\n );\n this.rulesVersion++;\n this.markDirty(this.networkChannel);\n }\n\n private canPush(channel: Channel): boolean {\n if (channel.isStopped) {\n return false;\n }\n if (channel.name === 'network') {\n return this.isNetworkEnabled || channel.hasPushedLogs;\n }\n return true;\n }\n\n private markDirty(channel: Channel): void {\n channel.isDirty = true;\n if (channel.timer !== null || !this.canPush(channel)) {\n return;\n }\n try {\n channel.timer = runOutsideZone(() =>\n setTimeout(() => {\n channel.timer = null;\n this.flushChannel(channel);\n }, PUSH_DELAY_MS),\n );\n } catch (e) {\n channel.timer = null;\n }\n }\n\n private flushChannel(channel: Channel): void {\n if (channel.timer !== null) {\n clearTimeout(channel.timer);\n channel.timer = null;\n }\n if (!channel.isDirty || !this.canPush(channel)) {\n return;\n }\n channel.isDirty = false;\n\n let push: Promise<unknown>;\n if (channel.name === 'console') {\n const logs = this.consoleCapture ? this.consoleCapture.getEntries() : [];\n if (logs.length === 0 && !channel.hasPushedLogs) {\n return;\n }\n channel.hasPushedLogs = logs.length > 0;\n push = runOutsideZone(() => this.target.attachConsoleLogs({ logs }));\n } else {\n const logs = this.isNetworkEnabled ? this.buildNetworkLogs() : [];\n if (logs.length === 0 && !channel.hasPushedLogs) {\n return;\n }\n channel.hasPushedLogs = logs.length > 0;\n push = runOutsideZone(() => this.target.attachNetworkLogs({ logs }));\n }\n\n try {\n Promise.resolve(push).then(\n () => {\n channel.failures = 0;\n },\n () => this.onPushFailed(channel),\n );\n } catch (e) {\n this.onPushFailed(channel);\n }\n }\n\n private onPushFailed(channel: Channel): void {\n channel.failures++;\n if (channel.failures >= MAX_FAILED_PUSHES) {\n channel.isStopped = true;\n return;\n }\n this.markDirty(channel);\n }\n\n /** Redacted copies of the buffered entries; unchanged entries reuse their previous copy. */\n private buildNetworkLogs(): GleapNetworkLogEntry[] {\n const logs: GleapNetworkLogEntry[] = [];\n const cache = new Map<number, CachedEntry>();\n for (const snapshot of this.networkCapture.getSnapshots()) {\n let cached = this.redactedEntries.get(snapshot.id);\n if (!cached || cached.version !== snapshot.version || cached.rulesVersion !== this.rulesVersion) {\n cached = {\n version: snapshot.version,\n rulesVersion: this.rulesVersion,\n entry: isBlacklistedUrl(snapshot.entry.url, this.rules)\n ? null\n : redactNetworkLogEntryOrStrip(snapshot.entry, this.rules),\n };\n }\n cache.set(snapshot.id, cached);\n if (cached.entry) {\n logs.push(cached.entry);\n }\n }\n this.redactedEntries = cache;\n return logs;\n }\n}\n\n/**\n * Starts the WebView log capture on iOS and Android (not on web, where the JavaScript SDK records\n * the console and network itself). Safe to call more than once.\n */\nexport function installWebViewLogCapture(target: LogTarget): WebViewLogCapture | null {\n try {\n if (typeof window === 'undefined' || !Capacitor.isNativePlatform()) {\n return null;\n }\n const win = window as unknown as { [GLOBAL_KEY]?: WebViewLogCapture };\n const existing = win[GLOBAL_KEY];\n if (existing) {\n return existing;\n }\n const capture = new WebViewLogCapture(window, target, Capacitor.getPlatform());\n win[GLOBAL_KEY] = capture;\n capture.start();\n return capture;\n } catch (e) {\n return null;\n }\n}\n\n/**\n * Wraps the registered plugin so the calls that affect the WebView capture reach it before they go\n * to native. Every other call passes through unchanged.\n */\nexport function wrapPluginWithLogCapture<T extends object>(plugin: T, capture: WebViewLogCapture): T {\n return new Proxy(plugin, {\n get(target, property, receiver) {\n const value = Reflect.get(target, property, receiver);\n if (typeof property !== 'string' || typeof value !== 'function') {\n return value;\n }\n const method = value as (...args: unknown[]) => unknown;\n const before =\n (hook: (options: { [key: string]: unknown }) => void) =>\n (...args: unknown[]) => {\n try {\n const options = args[0];\n hook(options && typeof options === 'object' ? (options as { [key: string]: unknown }) : {});\n } catch (e) {\n // Never break the plugin call.\n }\n return method(...args);\n };\n\n switch (property) {\n case 'initialize':\n return before(() => capture.onInitialize());\n case 'setNetworkLogPropsToIgnore':\n return before((options) => capture.setLocalPropsToIgnore(options.propsToIgnore));\n case 'setNetworkLogsBlacklist':\n return before((options) => capture.setLocalBlacklist(options.blacklist));\n case 'disableConsoleLogOverwrite':\n return before(() => capture.disableConsole());\n default:\n if (FLUSH_BEFORE_METHODS.indexOf(property) > -1) {\n return before(() => capture.flushNow());\n }\n return value;\n }\n },\n });\n}\n"]}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Runs fn in zone.js' root zone when zone.js is loaded (Angular / Ionic apps), so the plugin's
3
+ * timers and body reads do not trigger Angular change detection. Without zone.js it just runs fn.
4
+ */
5
+ export declare function runOutsideZone<T>(fn: () => T): T;
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Runs fn in zone.js' root zone when zone.js is loaded (Angular / Ionic apps), so the plugin's
3
+ * timers and body reads do not trigger Angular change detection. Without zone.js it just runs fn.
4
+ */
5
+ export function runOutsideZone(fn) {
6
+ const zone = typeof globalThis !== 'undefined'
7
+ ? globalThis.Zone
8
+ : undefined;
9
+ const root = zone === null || zone === void 0 ? void 0 : zone.root;
10
+ if (root && typeof root.run === 'function') {
11
+ return root.run(fn);
12
+ }
13
+ return fn();
14
+ }
15
+ //# sourceMappingURL=zone.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zone.js","sourceRoot":"","sources":["../../../src/logs/zone.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAI,EAAW;IAC3C,MAAM,IAAI,GACR,OAAO,UAAU,KAAK,WAAW;QAC/B,CAAC,CAAE,UAAiE,CAAC,IAAI;QACzE,CAAC,CAAC,SAAS,CAAC;IAChB,MAAM,IAAI,GAAG,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,IAAI,CAAC;IACxB,IAAI,IAAI,IAAI,OAAO,IAAI,CAAC,GAAG,KAAK,UAAU,EAAE;QAC1C,OAAQ,IAA0C,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;KAC5D;IACD,OAAO,EAAE,EAAE,CAAC;AACd,CAAC","sourcesContent":["/**\n * Runs fn in zone.js' root zone when zone.js is loaded (Angular / Ionic apps), so the plugin's\n * timers and body reads do not trigger Angular change detection. Without zone.js it just runs fn.\n */\nexport function runOutsideZone<T>(fn: () => T): T {\n const zone =\n typeof globalThis !== 'undefined'\n ? (globalThis as unknown as { Zone?: { root?: { run?: unknown } } }).Zone\n : undefined;\n const root = zone?.root;\n if (root && typeof root.run === 'function') {\n return (root as { run: (callback: () => T) => T }).run(fn);\n }\n return fn();\n}\n"]}
package/dist/esm/web.d.ts CHANGED
@@ -86,6 +86,11 @@ export declare class GleapWeb extends WebPlugin implements GleapPlugin {
86
86
  }): Promise<{
87
87
  conversationsOpened: boolean;
88
88
  }>;
89
+ openConversations(options: {
90
+ showBackButton?: boolean | undefined;
91
+ }): Promise<{
92
+ conversationsOpened: boolean;
93
+ }>;
89
94
  showSurvey(options: {
90
95
  surveyId: string;
91
96
  format?: 'survey' | 'survey_full' | undefined;
@@ -107,10 +112,17 @@ export declare class GleapWeb extends WebPlugin implements GleapPlugin {
107
112
  }): Promise<{
108
113
  envDataDisabled: boolean;
109
114
  }>;
115
+ setColorScheme(options: {
116
+ colorScheme: 'auto' | 'light' | 'dark';
117
+ lightBackgroundColor?: string;
118
+ darkBackgroundColor?: string;
119
+ }): Promise<{
120
+ colorScheme: string;
121
+ }>;
110
122
  identify(options: {
111
123
  userId: string;
112
124
  userHash?: string | undefined;
113
- customData?: Object | undefined;
125
+ customData?: Record<string, any> | undefined;
114
126
  name?: string | undefined;
115
127
  email?: string | undefined;
116
128
  phone?: string | undefined;
@@ -133,7 +145,7 @@ export declare class GleapWeb extends WebPlugin implements GleapPlugin {
133
145
  sla?: number | undefined;
134
146
  plan?: string | undefined;
135
147
  value?: number | undefined;
136
- customData?: Object | undefined;
148
+ customData?: Record<string, any> | undefined;
137
149
  }): Promise<{
138
150
  identify: boolean;
139
151
  }>;
@@ -147,6 +159,12 @@ export declare class GleapWeb extends WebPlugin implements GleapPlugin {
147
159
  }): Promise<{
148
160
  propsToIgnoreSet: boolean;
149
161
  }>;
162
+ attachNetworkLogs(): Promise<{
163
+ networkLogsAttached: boolean;
164
+ }>;
165
+ attachConsoleLogs(): Promise<{
166
+ consoleLogsAttached: boolean;
167
+ }>;
150
168
  setEnvDataPropsToIgnore(options: {
151
169
  propsToIgnore: string[];
152
170
  }): Promise<{
@@ -250,6 +268,23 @@ export declare class GleapWeb extends WebPlugin implements GleapPlugin {
250
268
  open(): Promise<{
251
269
  openedWidget: boolean;
252
270
  }>;
271
+ openChecklists(options: {
272
+ showBackButton?: boolean | undefined;
273
+ }): Promise<{
274
+ opened: boolean;
275
+ }>;
276
+ openChecklist(options: {
277
+ checklistId: string;
278
+ showBackButton?: boolean | undefined;
279
+ }): Promise<{
280
+ opened: boolean;
281
+ }>;
282
+ startChecklist(options: {
283
+ outboundId: string;
284
+ showBackButton?: boolean | undefined;
285
+ }): Promise<{
286
+ opened: boolean;
287
+ }>;
253
288
  openFeatureRequests(options: {
254
289
  showBackButton?: boolean | undefined;
255
290
  }): Promise<{
package/dist/esm/web.js CHANGED
@@ -160,6 +160,10 @@ export class GleapWeb extends WebPlugin {
160
160
  Gleap.openConversations(options.showBackButton);
161
161
  return { conversationsOpened: true };
162
162
  }
163
+ async openConversations(options) {
164
+ Gleap.openConversations(options.showBackButton);
165
+ return { conversationsOpened: true };
166
+ }
163
167
  async showSurvey(options) {
164
168
  Gleap.showSurvey(options.surveyId, options.format);
165
169
  return { opened: true };
@@ -178,6 +182,16 @@ export class GleapWeb extends WebPlugin {
178
182
  Gleap.setDisableEnvData((_a = options.disableEnvData) !== null && _a !== void 0 ? _a : false);
179
183
  return { envDataDisabled: true };
180
184
  }
185
+ async setColorScheme(options) {
186
+ if (!(options === null || options === void 0 ? void 0 : options.colorScheme)) {
187
+ throw new Error('No colorScheme provided');
188
+ }
189
+ Gleap.setColorScheme(options.colorScheme, {
190
+ lightBackgroundColor: options.lightBackgroundColor,
191
+ darkBackgroundColor: options.darkBackgroundColor,
192
+ });
193
+ return { colorScheme: options.colorScheme };
194
+ }
181
195
  async identify(options) {
182
196
  var userData = {
183
197
  name: options.name,
@@ -211,6 +225,14 @@ export class GleapWeb extends WebPlugin {
211
225
  Gleap.setNetworkLogPropsToIgnore(options.propsToIgnore);
212
226
  return { propsToIgnoreSet: true };
213
227
  }
228
+ async attachNetworkLogs() {
229
+ // The JavaScript SDK records the page's requests itself on web.
230
+ return { networkLogsAttached: false };
231
+ }
232
+ async attachConsoleLogs() {
233
+ // The JavaScript SDK records the page's console itself on web.
234
+ return { consoleLogsAttached: false };
235
+ }
214
236
  async setEnvDataPropsToIgnore(options) {
215
237
  Gleap.setEnvDataPropsToIgnore(options.propsToIgnore);
216
238
  return { envDataPropsToIgnoreSet: true };
@@ -290,6 +312,18 @@ export class GleapWeb extends WebPlugin {
290
312
  Gleap.open();
291
313
  return { openedWidget: true };
292
314
  }
315
+ async openChecklists(options) {
316
+ Gleap.openChecklists(options.showBackButton);
317
+ return { opened: true };
318
+ }
319
+ async openChecklist(options) {
320
+ Gleap.openChecklist(options.checklistId, options.showBackButton);
321
+ return { opened: true };
322
+ }
323
+ async startChecklist(options) {
324
+ Gleap.startChecklist(options.outboundId, options.showBackButton);
325
+ return { opened: true };
326
+ }
293
327
  async openFeatureRequests(options) {
294
328
  Gleap.openFeatureRequests(options.showBackButton);
295
329
  return { openedFeatureRequests: true };