capacitor-gleap-plugin 18.1.0 → 19.0.1

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 +298 -759
  4. package/android/build.gradle +1 -1
  5. package/android/src/main/java/io/gleapplugins/capacitor/GleapPlugin.java +202 -37
  6. package/dist/docs.json +288 -3893
  7. package/dist/esm/definitions.d.ts +162 -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 +42 -2
  33. package/dist/esm/web.js +38 -0
  34. package/dist/esm/web.js.map +1 -1
  35. package/dist/plugin.cjs.js +2258 -1
  36. package/dist/plugin.cjs.js.map +1 -1
  37. package/dist/plugin.js +2258 -1
  38. package/dist/plugin.js.map +1 -1
  39. package/ios/{Plugin → Sources/GleapPlugin}/GleapPlugin.swift +219 -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,16 @@ 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
+ }>;
94
+ openProtectedFileFromUrl(_options: {
95
+ url: string;
96
+ }): Promise<{
97
+ opened: boolean;
98
+ }>;
89
99
  showSurvey(options: {
90
100
  surveyId: string;
91
101
  format?: 'survey' | 'survey_full' | undefined;
@@ -107,10 +117,17 @@ export declare class GleapWeb extends WebPlugin implements GleapPlugin {
107
117
  }): Promise<{
108
118
  envDataDisabled: boolean;
109
119
  }>;
120
+ setColorScheme(options: {
121
+ colorScheme: 'auto' | 'light' | 'dark';
122
+ lightBackgroundColor?: string;
123
+ darkBackgroundColor?: string;
124
+ }): Promise<{
125
+ colorScheme: string;
126
+ }>;
110
127
  identify(options: {
111
128
  userId: string;
112
129
  userHash?: string | undefined;
113
- customData?: Object | undefined;
130
+ customData?: Record<string, any> | undefined;
114
131
  name?: string | undefined;
115
132
  email?: string | undefined;
116
133
  phone?: string | undefined;
@@ -133,7 +150,7 @@ export declare class GleapWeb extends WebPlugin implements GleapPlugin {
133
150
  sla?: number | undefined;
134
151
  plan?: string | undefined;
135
152
  value?: number | undefined;
136
- customData?: Object | undefined;
153
+ customData?: Record<string, any> | undefined;
137
154
  }): Promise<{
138
155
  identify: boolean;
139
156
  }>;
@@ -147,6 +164,12 @@ export declare class GleapWeb extends WebPlugin implements GleapPlugin {
147
164
  }): Promise<{
148
165
  propsToIgnoreSet: boolean;
149
166
  }>;
167
+ attachNetworkLogs(): Promise<{
168
+ networkLogsAttached: boolean;
169
+ }>;
170
+ attachConsoleLogs(): Promise<{
171
+ consoleLogsAttached: boolean;
172
+ }>;
150
173
  setEnvDataPropsToIgnore(options: {
151
174
  propsToIgnore: string[];
152
175
  }): Promise<{
@@ -250,6 +273,23 @@ export declare class GleapWeb extends WebPlugin implements GleapPlugin {
250
273
  open(): Promise<{
251
274
  openedWidget: boolean;
252
275
  }>;
276
+ openChecklists(options: {
277
+ showBackButton?: boolean | undefined;
278
+ }): Promise<{
279
+ opened: boolean;
280
+ }>;
281
+ openChecklist(options: {
282
+ checklistId: string;
283
+ showBackButton?: boolean | undefined;
284
+ }): Promise<{
285
+ opened: boolean;
286
+ }>;
287
+ startChecklist(options: {
288
+ outboundId: string;
289
+ showBackButton?: boolean | undefined;
290
+ }): Promise<{
291
+ opened: boolean;
292
+ }>;
253
293
  openFeatureRequests(options: {
254
294
  showBackButton?: boolean | undefined;
255
295
  }): Promise<{
package/dist/esm/web.js CHANGED
@@ -160,6 +160,14 @@ 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
+ }
167
+ // The JavaScript SDK opens `?gleapFile=` links itself on page load.
168
+ async openProtectedFileFromUrl(_options) {
169
+ return { opened: false };
170
+ }
163
171
  async showSurvey(options) {
164
172
  Gleap.showSurvey(options.surveyId, options.format);
165
173
  return { opened: true };
@@ -178,6 +186,16 @@ export class GleapWeb extends WebPlugin {
178
186
  Gleap.setDisableEnvData((_a = options.disableEnvData) !== null && _a !== void 0 ? _a : false);
179
187
  return { envDataDisabled: true };
180
188
  }
189
+ async setColorScheme(options) {
190
+ if (!(options === null || options === void 0 ? void 0 : options.colorScheme)) {
191
+ throw new Error('No colorScheme provided');
192
+ }
193
+ Gleap.setColorScheme(options.colorScheme, {
194
+ lightBackgroundColor: options.lightBackgroundColor,
195
+ darkBackgroundColor: options.darkBackgroundColor,
196
+ });
197
+ return { colorScheme: options.colorScheme };
198
+ }
181
199
  async identify(options) {
182
200
  var userData = {
183
201
  name: options.name,
@@ -211,6 +229,14 @@ export class GleapWeb extends WebPlugin {
211
229
  Gleap.setNetworkLogPropsToIgnore(options.propsToIgnore);
212
230
  return { propsToIgnoreSet: true };
213
231
  }
232
+ async attachNetworkLogs() {
233
+ // The JavaScript SDK records the page's requests itself on web.
234
+ return { networkLogsAttached: false };
235
+ }
236
+ async attachConsoleLogs() {
237
+ // The JavaScript SDK records the page's console itself on web.
238
+ return { consoleLogsAttached: false };
239
+ }
214
240
  async setEnvDataPropsToIgnore(options) {
215
241
  Gleap.setEnvDataPropsToIgnore(options.propsToIgnore);
216
242
  return { envDataPropsToIgnoreSet: true };
@@ -290,6 +316,18 @@ export class GleapWeb extends WebPlugin {
290
316
  Gleap.open();
291
317
  return { openedWidget: true };
292
318
  }
319
+ async openChecklists(options) {
320
+ Gleap.openChecklists(options.showBackButton);
321
+ return { opened: true };
322
+ }
323
+ async openChecklist(options) {
324
+ Gleap.openChecklist(options.checklistId, options.showBackButton);
325
+ return { opened: true };
326
+ }
327
+ async startChecklist(options) {
328
+ Gleap.startChecklist(options.outboundId, options.showBackButton);
329
+ return { opened: true };
330
+ }
293
331
  async openFeatureRequests(options) {
294
332
  Gleap.openFeatureRequests(options.showBackButton);
295
333
  return { openedFeatureRequests: true };