capacitor-gleap-plugin 18.0.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 +307 -761
  4. package/android/build.gradle +1 -1
  5. package/android/src/main/java/io/gleapplugins/capacitor/GleapPlugin.java +228 -37
  6. package/dist/docs.json +323 -3907
  7. package/dist/esm/definitions.d.ts +168 -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 +47 -2
  33. package/dist/esm/web.js +43 -0
  34. package/dist/esm/web.js.map +1 -1
  35. package/dist/plugin.cjs.js +2263 -1
  36. package/dist/plugin.cjs.js.map +1 -1
  37. package/dist/plugin.js +2263 -1
  38. package/dist/plugin.js.map +1 -1
  39. package/ios/{Plugin → Sources/GleapPlugin}/GleapPlugin.swift +222 -12
  40. package/package.json +27 -6
  41. package/ios/Plugin/GleapPlugin.h +0 -10
  42. package/ios/Plugin/GleapPlugin.m +0 -66
  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;
@@ -102,10 +107,22 @@ export declare class GleapWeb extends WebPlugin implements GleapPlugin {
102
107
  }): Promise<{
103
108
  inAppNotificationsDisabled: boolean;
104
109
  }>;
110
+ setDisableEnvData(options: {
111
+ disableEnvData: boolean;
112
+ }): Promise<{
113
+ envDataDisabled: boolean;
114
+ }>;
115
+ setColorScheme(options: {
116
+ colorScheme: 'auto' | 'light' | 'dark';
117
+ lightBackgroundColor?: string;
118
+ darkBackgroundColor?: string;
119
+ }): Promise<{
120
+ colorScheme: string;
121
+ }>;
105
122
  identify(options: {
106
123
  userId: string;
107
124
  userHash?: string | undefined;
108
- customData?: Object | undefined;
125
+ customData?: Record<string, any> | undefined;
109
126
  name?: string | undefined;
110
127
  email?: string | undefined;
111
128
  phone?: string | undefined;
@@ -128,7 +145,7 @@ export declare class GleapWeb extends WebPlugin implements GleapPlugin {
128
145
  sla?: number | undefined;
129
146
  plan?: string | undefined;
130
147
  value?: number | undefined;
131
- customData?: Object | undefined;
148
+ customData?: Record<string, any> | undefined;
132
149
  }): Promise<{
133
150
  identify: boolean;
134
151
  }>;
@@ -142,6 +159,17 @@ export declare class GleapWeb extends WebPlugin implements GleapPlugin {
142
159
  }): Promise<{
143
160
  propsToIgnoreSet: boolean;
144
161
  }>;
162
+ attachNetworkLogs(): Promise<{
163
+ networkLogsAttached: boolean;
164
+ }>;
165
+ attachConsoleLogs(): Promise<{
166
+ consoleLogsAttached: boolean;
167
+ }>;
168
+ setEnvDataPropsToIgnore(options: {
169
+ propsToIgnore: string[];
170
+ }): Promise<{
171
+ envDataPropsToIgnoreSet: boolean;
172
+ }>;
145
173
  setTags(options: {
146
174
  tags: string[];
147
175
  }): Promise<{
@@ -240,6 +268,23 @@ export declare class GleapWeb extends WebPlugin implements GleapPlugin {
240
268
  open(): Promise<{
241
269
  openedWidget: boolean;
242
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
+ }>;
243
288
  openFeatureRequests(options: {
244
289
  showBackButton?: boolean | undefined;
245
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 };
@@ -173,6 +177,21 @@ export class GleapWeb extends WebPlugin {
173
177
  Gleap.setDisableInAppNotifications((_a = options.disableInAppNotifications) !== null && _a !== void 0 ? _a : false);
174
178
  return { inAppNotificationsDisabled: true };
175
179
  }
180
+ async setDisableEnvData(options) {
181
+ var _a;
182
+ Gleap.setDisableEnvData((_a = options.disableEnvData) !== null && _a !== void 0 ? _a : false);
183
+ return { envDataDisabled: true };
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
+ }
176
195
  async identify(options) {
177
196
  var userData = {
178
197
  name: options.name,
@@ -206,6 +225,18 @@ export class GleapWeb extends WebPlugin {
206
225
  Gleap.setNetworkLogPropsToIgnore(options.propsToIgnore);
207
226
  return { propsToIgnoreSet: true };
208
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
+ }
236
+ async setEnvDataPropsToIgnore(options) {
237
+ Gleap.setEnvDataPropsToIgnore(options.propsToIgnore);
238
+ return { envDataPropsToIgnoreSet: true };
239
+ }
209
240
  async setTags(options) {
210
241
  Gleap.setTags(options.tags);
211
242
  return { tagsSet: true };
@@ -281,6 +312,18 @@ export class GleapWeb extends WebPlugin {
281
312
  Gleap.open();
282
313
  return { openedWidget: true };
283
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
+ }
284
327
  async openFeatureRequests(options) {
285
328
  Gleap.openFeatureRequests(options.showBackButton);
286
329
  return { openedFeatureRequests: true };