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.
- package/CapacitorGleapPlugin.podspec +7 -2
- package/Package.swift +31 -0
- package/README.md +307 -761
- package/android/build.gradle +1 -1
- package/android/src/main/java/io/gleapplugins/capacitor/GleapPlugin.java +228 -37
- package/dist/docs.json +323 -3907
- package/dist/esm/definitions.d.ts +168 -3
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/index.js +9 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/logs/body.d.ts +58 -0
- package/dist/esm/logs/body.js +303 -0
- package/dist/esm/logs/body.js.map +1 -0
- package/dist/esm/logs/consoleCapture.d.ts +29 -0
- package/dist/esm/logs/consoleCapture.js +189 -0
- package/dist/esm/logs/consoleCapture.js.map +1 -0
- package/dist/esm/logs/format.d.ts +16 -0
- package/dist/esm/logs/format.js +394 -0
- package/dist/esm/logs/format.js.map +1 -0
- package/dist/esm/logs/networkCapture.d.ts +65 -0
- package/dist/esm/logs/networkCapture.js +654 -0
- package/dist/esm/logs/networkCapture.js.map +1 -0
- package/dist/esm/logs/redaction.d.ts +54 -0
- package/dist/esm/logs/redaction.js +388 -0
- package/dist/esm/logs/redaction.js.map +1 -0
- package/dist/esm/logs/webViewLogs.d.ts +70 -0
- package/dist/esm/logs/webViewLogs.js +297 -0
- package/dist/esm/logs/webViewLogs.js.map +1 -0
- package/dist/esm/logs/zone.d.ts +5 -0
- package/dist/esm/logs/zone.js +15 -0
- package/dist/esm/logs/zone.js.map +1 -0
- package/dist/esm/web.d.ts +47 -2
- package/dist/esm/web.js +43 -0
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +2263 -1
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +2263 -1
- package/dist/plugin.js.map +1 -1
- package/ios/{Plugin → Sources/GleapPlugin}/GleapPlugin.swift +222 -12
- package/package.json +27 -6
- package/ios/Plugin/GleapPlugin.h +0 -10
- package/ios/Plugin/GleapPlugin.m +0 -66
- 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,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?:
|
|
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?:
|
|
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 };
|