@ansight/capacitor 1.3.0-preview.1 → 1.3.0-preview.11
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/AnsightCapacitor.podspec +1 -1
- package/Package.swift +1 -1
- package/README.md +63 -0
- package/android/build.gradle +2 -2
- package/android/src/main/kotlin/ai/ansight/capacitor/AnsightCapacitorPlugin.kt +79 -4
- package/dist/esm/definitions.d.ts +101 -2
- package/dist/esm/definitions.d.ts.map +1 -1
- package/dist/esm/dom.d.ts.map +1 -1
- package/dist/esm/dom.js +91 -8
- package/dist/esm/dom.js.map +1 -1
- package/dist/esm/index.d.ts +20 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +131 -3
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/network.d.ts +6 -0
- package/dist/esm/network.d.ts.map +1 -0
- package/dist/esm/network.js +742 -0
- package/dist/esm/network.js.map +1 -0
- package/dist/esm/options.d.ts +14 -2
- package/dist/esm/options.d.ts.map +1 -1
- package/dist/esm/options.js +73 -1
- package/dist/esm/options.js.map +1 -1
- package/dist/esm/session-properties.d.ts +16 -0
- package/dist/esm/session-properties.d.ts.map +1 -0
- package/dist/esm/session-properties.js +123 -0
- package/dist/esm/session-properties.js.map +1 -0
- package/dist/plugin.cjs.js +1162 -12
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +1162 -12
- package/dist/plugin.js.map +1 -1
- package/dist/standalone.js +1157 -12
- package/dist/standalone.js.map +1 -1
- package/ios/Sources/AnsightCapacitorPlugin/AnsightCapacitorPlugin.swift +81 -3
- package/package.json +1 -1
package/dist/plugin.js
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
var capacitorAnsight = (function (exports, core) {
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
+
function createTypeRegistry() {
|
|
5
|
+
return { idsByTypeName: new Map(), types: [] };
|
|
6
|
+
}
|
|
7
|
+
function registerType(registry, typeName) {
|
|
8
|
+
const existingTypeId = registry.idsByTypeName.get(typeName);
|
|
9
|
+
if (existingTypeId !== undefined)
|
|
10
|
+
return existingTypeId;
|
|
11
|
+
const typeId = registry.types.length;
|
|
12
|
+
registry.types.push(typeName);
|
|
13
|
+
registry.idsByTypeName.set(typeName, typeId);
|
|
14
|
+
return typeId;
|
|
15
|
+
}
|
|
4
16
|
const nodeIds = new WeakMap();
|
|
5
17
|
let nextNodeId = 1;
|
|
6
18
|
function nodeId(element) {
|
|
@@ -47,6 +59,55 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
47
59
|
element.id ??
|
|
48
60
|
undefined)?.trim() || undefined);
|
|
49
61
|
}
|
|
62
|
+
function semanticRole(element) {
|
|
63
|
+
const declared = element.getAttribute("role")?.trim().toLowerCase();
|
|
64
|
+
if (declared)
|
|
65
|
+
return declared;
|
|
66
|
+
if (element instanceof HTMLButtonElement)
|
|
67
|
+
return "button";
|
|
68
|
+
if (element instanceof HTMLInputElement) {
|
|
69
|
+
if (element.type === "checkbox")
|
|
70
|
+
return "checkbox";
|
|
71
|
+
if (element.type === "radio")
|
|
72
|
+
return "radio";
|
|
73
|
+
if (element.type === "range")
|
|
74
|
+
return "slider";
|
|
75
|
+
if (["button", "submit", "reset"].includes(element.type))
|
|
76
|
+
return "button";
|
|
77
|
+
return "textbox";
|
|
78
|
+
}
|
|
79
|
+
if (element instanceof HTMLTextAreaElement)
|
|
80
|
+
return "textbox";
|
|
81
|
+
if (element instanceof HTMLSelectElement)
|
|
82
|
+
return "combobox";
|
|
83
|
+
if (element.tagName === "A")
|
|
84
|
+
return "link";
|
|
85
|
+
if (/^H[1-6]$/.test(element.tagName))
|
|
86
|
+
return "heading";
|
|
87
|
+
return "view";
|
|
88
|
+
}
|
|
89
|
+
function supportedActions(element, allowActions) {
|
|
90
|
+
if (!allowActions)
|
|
91
|
+
return [];
|
|
92
|
+
const actions = [];
|
|
93
|
+
if (["A", "BUTTON", "SUMMARY"].includes(element.tagName) ||
|
|
94
|
+
element instanceof HTMLInputElement) {
|
|
95
|
+
actions.push("tap");
|
|
96
|
+
}
|
|
97
|
+
if (element instanceof HTMLInputElement ||
|
|
98
|
+
element instanceof HTMLTextAreaElement ||
|
|
99
|
+
element instanceof HTMLSelectElement) {
|
|
100
|
+
actions.push("typeText", "focus");
|
|
101
|
+
}
|
|
102
|
+
else if (element.tabIndex >= 0) {
|
|
103
|
+
actions.push("focus");
|
|
104
|
+
}
|
|
105
|
+
if (element.scrollHeight >
|
|
106
|
+
element.clientHeight) {
|
|
107
|
+
actions.push("scroll", "swipe");
|
|
108
|
+
}
|
|
109
|
+
return [...new Set(actions)];
|
|
110
|
+
}
|
|
50
111
|
function computedColorToArgbHex(value) {
|
|
51
112
|
const normalized = value.trim().toLowerCase();
|
|
52
113
|
if (!normalized)
|
|
@@ -112,7 +173,7 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
112
173
|
const normalized = value?.replace(/\s+/g, " ").trim();
|
|
113
174
|
return normalized ? normalized.slice(0, 240) : undefined;
|
|
114
175
|
}
|
|
115
|
-
function captureNode(element, options, depth, limits) {
|
|
176
|
+
function captureNode(element, options, depth, limits, typeRegistry) {
|
|
116
177
|
if (limits.count >= limits.maxNodes || depth > limits.maxDepth)
|
|
117
178
|
return null;
|
|
118
179
|
const style = getComputedStyle(element);
|
|
@@ -122,17 +183,23 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
122
183
|
return null;
|
|
123
184
|
limits.count += 1;
|
|
124
185
|
const children = Array.from(element.children)
|
|
125
|
-
.map((child) => captureNode(child, options, depth + 1, limits))
|
|
186
|
+
.map((child) => captureNode(child, options, depth + 1, limits, typeRegistry))
|
|
126
187
|
.filter((child) => child !== null);
|
|
127
188
|
const htmlElement = element;
|
|
128
189
|
const disabled = element.hasAttribute("disabled") ||
|
|
129
190
|
element.getAttribute("aria-disabled") === "true";
|
|
130
191
|
const parsedOpacity = Number.parseFloat(style.opacity);
|
|
131
|
-
|
|
192
|
+
const parsedZIndex = Number.parseFloat(style.zIndex);
|
|
193
|
+
const actions = supportedActions(element, options.allowActions);
|
|
194
|
+
const label = accessibleLabel(element, options.includeText);
|
|
195
|
+
const node = {
|
|
132
196
|
id: nodeId(element),
|
|
133
|
-
|
|
197
|
+
typeId: registerType(typeRegistry, element.tagName.toLowerCase()),
|
|
134
198
|
automationId: automationId(element),
|
|
135
|
-
label
|
|
199
|
+
label,
|
|
200
|
+
role: semanticRole(element),
|
|
201
|
+
supportedActions: actions,
|
|
202
|
+
interactable: visible && !disabled && actions.length > 0,
|
|
136
203
|
visible,
|
|
137
204
|
enabled: !disabled,
|
|
138
205
|
focusable: htmlElement.tabIndex >= 0 ||
|
|
@@ -157,12 +224,15 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
157
224
|
id: element.id || undefined,
|
|
158
225
|
role: element.getAttribute("role") ?? undefined,
|
|
159
226
|
className: element.getAttribute("class") ?? undefined,
|
|
160
|
-
value: options.includeText ? displayedValue(element) : undefined,
|
|
161
227
|
checked: element instanceof HTMLInputElement ? element.checked : undefined,
|
|
162
228
|
attributes: options.includeAttributes ? attributes(element) : undefined,
|
|
163
229
|
},
|
|
164
230
|
children,
|
|
165
231
|
};
|
|
232
|
+
if (Number.isFinite(parsedZIndex) && parsedZIndex !== 0) {
|
|
233
|
+
node.z = parsedZIndex;
|
|
234
|
+
}
|
|
235
|
+
return node;
|
|
166
236
|
}
|
|
167
237
|
function findElement(id) {
|
|
168
238
|
return Array.from(document.querySelectorAll("*")).find((element) => nodeId(element) === id);
|
|
@@ -195,12 +265,15 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
195
265
|
maxNodes: options.maxNodes,
|
|
196
266
|
count: 0,
|
|
197
267
|
};
|
|
198
|
-
const
|
|
268
|
+
const typeRegistry = createTypeRegistry();
|
|
269
|
+
const tree = captureNode(root, options, 0, limits, typeRegistry);
|
|
199
270
|
return successful({
|
|
271
|
+
format: "ansight.dom.visual-tree.compact.v2",
|
|
200
272
|
platform: "web",
|
|
201
273
|
source: options.source,
|
|
202
274
|
adapter: "@ansight/capacitor",
|
|
203
275
|
capturedAtUtc: new Date().toISOString(),
|
|
276
|
+
types: typeRegistry.types,
|
|
204
277
|
truncated: limits.count >= limits.maxNodes,
|
|
205
278
|
root: tree,
|
|
206
279
|
}, "DOM document captured.");
|
|
@@ -226,7 +299,17 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
226
299
|
};
|
|
227
300
|
}
|
|
228
301
|
const limits = { maxDepth: 0, maxNodes: 1, count: 0 };
|
|
229
|
-
|
|
302
|
+
const typeRegistry = createTypeRegistry();
|
|
303
|
+
const node = captureNode(element, options, 0, limits, typeRegistry);
|
|
304
|
+
return successful({
|
|
305
|
+
format: "ansight.dom.visual-tree.compact.v2",
|
|
306
|
+
platform: "web",
|
|
307
|
+
source: options.source,
|
|
308
|
+
adapter: "@ansight/capacitor",
|
|
309
|
+
capturedAtUtc: new Date().toISOString(),
|
|
310
|
+
types: typeRegistry.types,
|
|
311
|
+
node,
|
|
312
|
+
}, "DOM node captured.");
|
|
230
313
|
}),
|
|
231
314
|
registerTool({
|
|
232
315
|
id: "dom.query_selector",
|
|
@@ -333,6 +416,8 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
333
416
|
retentionPeriodSeconds: 120,
|
|
334
417
|
enableFramesPerSecond: true,
|
|
335
418
|
enableBatteryLevel: false,
|
|
419
|
+
enableOpenFileHandleTracking: false,
|
|
420
|
+
enableJniReferenceCountTracking: false,
|
|
336
421
|
sessionJpegCapture: {
|
|
337
422
|
intervalMilliseconds: 2000,
|
|
338
423
|
quality: 60,
|
|
@@ -375,6 +460,22 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
375
460
|
this.options.enableBatteryLevel = false;
|
|
376
461
|
return this;
|
|
377
462
|
}
|
|
463
|
+
withOpenFileHandleTracking() {
|
|
464
|
+
this.options.enableOpenFileHandleTracking = true;
|
|
465
|
+
return this;
|
|
466
|
+
}
|
|
467
|
+
withoutOpenFileHandleTracking() {
|
|
468
|
+
this.options.enableOpenFileHandleTracking = false;
|
|
469
|
+
return this;
|
|
470
|
+
}
|
|
471
|
+
withJniReferenceCountTracking() {
|
|
472
|
+
this.options.enableJniReferenceCountTracking = true;
|
|
473
|
+
return this;
|
|
474
|
+
}
|
|
475
|
+
withoutJniReferenceCountTracking() {
|
|
476
|
+
this.options.enableJniReferenceCountTracking = false;
|
|
477
|
+
return this;
|
|
478
|
+
}
|
|
378
479
|
withRetentionPeriodSeconds(value) {
|
|
379
480
|
this.options.retentionPeriodSeconds = value;
|
|
380
481
|
return this;
|
|
@@ -413,7 +514,7 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
413
514
|
this.options.defaultMemoryChannels = current;
|
|
414
515
|
return this;
|
|
415
516
|
}
|
|
416
|
-
withSessionJpegCapture(optionsOrIntervalMilliseconds = {}, quality = 60, maxWidth = 480, captureGpuBackedSurfaces = true, mode = "screenshotOnly") {
|
|
517
|
+
withSessionJpegCapture(optionsOrIntervalMilliseconds = {}, quality = 60, maxWidth = 480, captureGpuBackedSurfaces = true, mode = "screenshotOnly", captureKeyboardPresence = false) {
|
|
417
518
|
this.options.sessionJpegCapture =
|
|
418
519
|
typeof optionsOrIntervalMilliseconds === "number"
|
|
419
520
|
? {
|
|
@@ -422,11 +523,13 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
422
523
|
maxWidth,
|
|
423
524
|
captureGpuBackedSurfaces,
|
|
424
525
|
mode,
|
|
526
|
+
captureKeyboardPresence,
|
|
425
527
|
}
|
|
426
528
|
: {
|
|
427
529
|
intervalMilliseconds: 2000,
|
|
428
530
|
quality: 60,
|
|
429
531
|
maxWidth: 480,
|
|
532
|
+
captureKeyboardPresence: false,
|
|
430
533
|
mode: "screenshotOnly",
|
|
431
534
|
...optionsOrIntervalMilliseconds,
|
|
432
535
|
};
|
|
@@ -444,6 +547,14 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
444
547
|
this.options.touchCapture = false;
|
|
445
548
|
return this;
|
|
446
549
|
}
|
|
550
|
+
withCrashCapture(options = {}) {
|
|
551
|
+
this.options.crashCapture = { ...options, enabled: true };
|
|
552
|
+
return this;
|
|
553
|
+
}
|
|
554
|
+
withoutCrashCapture() {
|
|
555
|
+
this.options.crashCapture = false;
|
|
556
|
+
return this;
|
|
557
|
+
}
|
|
447
558
|
withLifecycleCapture(options = {}) {
|
|
448
559
|
this.options.lifecycleCapture = {
|
|
449
560
|
...options,
|
|
@@ -451,6 +562,50 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
451
562
|
};
|
|
452
563
|
return this;
|
|
453
564
|
}
|
|
565
|
+
withNetworkCapture(options = {}) {
|
|
566
|
+
this.options.networkCapture = { ...options };
|
|
567
|
+
return this;
|
|
568
|
+
}
|
|
569
|
+
withNetworkRequestBodies(maximumBodyBytes) {
|
|
570
|
+
if (typeof this.options.networkCapture !== "object")
|
|
571
|
+
return this;
|
|
572
|
+
const current = this.options.networkCapture;
|
|
573
|
+
this.options.networkCapture = {
|
|
574
|
+
...current,
|
|
575
|
+
captureRequestBody: true,
|
|
576
|
+
...(maximumBodyBytes == null ? {} : { maximumBodyBytes }),
|
|
577
|
+
};
|
|
578
|
+
return this;
|
|
579
|
+
}
|
|
580
|
+
withoutNetworkRequestBodies() {
|
|
581
|
+
if (typeof this.options.networkCapture !== "object")
|
|
582
|
+
return this;
|
|
583
|
+
const current = this.options.networkCapture;
|
|
584
|
+
this.options.networkCapture = { ...current, captureRequestBody: false };
|
|
585
|
+
return this;
|
|
586
|
+
}
|
|
587
|
+
withNetworkResponseBodies(maximumBodyBytes) {
|
|
588
|
+
if (typeof this.options.networkCapture !== "object")
|
|
589
|
+
return this;
|
|
590
|
+
const current = this.options.networkCapture;
|
|
591
|
+
this.options.networkCapture = {
|
|
592
|
+
...current,
|
|
593
|
+
captureResponseBody: true,
|
|
594
|
+
...(maximumBodyBytes == null ? {} : { maximumBodyBytes }),
|
|
595
|
+
};
|
|
596
|
+
return this;
|
|
597
|
+
}
|
|
598
|
+
withoutNetworkResponseBodies() {
|
|
599
|
+
if (typeof this.options.networkCapture !== "object")
|
|
600
|
+
return this;
|
|
601
|
+
const current = this.options.networkCapture;
|
|
602
|
+
this.options.networkCapture = { ...current, captureResponseBody: false };
|
|
603
|
+
return this;
|
|
604
|
+
}
|
|
605
|
+
withoutNetworkCapture() {
|
|
606
|
+
this.options.networkCapture = false;
|
|
607
|
+
return this;
|
|
608
|
+
}
|
|
454
609
|
withToolGuard(toolGuard) {
|
|
455
610
|
this.options.toolGuard = toolGuard;
|
|
456
611
|
return this;
|
|
@@ -618,6 +773,871 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
618
773
|
return new AnsightOptionsBuilder(options);
|
|
619
774
|
}
|
|
620
775
|
|
|
776
|
+
const networkRequestSchema = "ansight.network-request.v1";
|
|
777
|
+
const redactedNetworkValue = "<redacted>";
|
|
778
|
+
const maximumHeaderCount = 128;
|
|
779
|
+
const maximumHeaderValueLength = 4096;
|
|
780
|
+
const maximumErrorMessageLength = 4096;
|
|
781
|
+
const maximumUrlLength = 16384;
|
|
782
|
+
const defaultMaximumBodyBytes = 64 * 1024;
|
|
783
|
+
const sensitiveHeaderNames = new Set([
|
|
784
|
+
"authorization",
|
|
785
|
+
"cookie",
|
|
786
|
+
"proxy-authorization",
|
|
787
|
+
"set-cookie",
|
|
788
|
+
"x-api-key",
|
|
789
|
+
"x-auth-token",
|
|
790
|
+
]);
|
|
791
|
+
const sensitiveQueryNames = new Set([
|
|
792
|
+
"access_token",
|
|
793
|
+
"accesskey",
|
|
794
|
+
"access_key",
|
|
795
|
+
"api_key",
|
|
796
|
+
"apikey",
|
|
797
|
+
"auth",
|
|
798
|
+
"authorization",
|
|
799
|
+
"client_secret",
|
|
800
|
+
"code",
|
|
801
|
+
"credential",
|
|
802
|
+
"credentials",
|
|
803
|
+
"id_token",
|
|
804
|
+
"jwt",
|
|
805
|
+
"key",
|
|
806
|
+
"password",
|
|
807
|
+
"passwd",
|
|
808
|
+
"refresh_token",
|
|
809
|
+
"sas",
|
|
810
|
+
"sastoken",
|
|
811
|
+
"secret",
|
|
812
|
+
"secret_key",
|
|
813
|
+
"security_token",
|
|
814
|
+
"session_token",
|
|
815
|
+
"sig",
|
|
816
|
+
"signature",
|
|
817
|
+
"token",
|
|
818
|
+
]);
|
|
819
|
+
const azureSasFingerprintNames = new Set([
|
|
820
|
+
"se",
|
|
821
|
+
"skoid",
|
|
822
|
+
"sp",
|
|
823
|
+
"sr",
|
|
824
|
+
"srt",
|
|
825
|
+
"ss",
|
|
826
|
+
"sv",
|
|
827
|
+
]);
|
|
828
|
+
const azureSasQueryNames = new Set([
|
|
829
|
+
"epk",
|
|
830
|
+
"erk",
|
|
831
|
+
"rscc",
|
|
832
|
+
"rscd",
|
|
833
|
+
"rsce",
|
|
834
|
+
"rscl",
|
|
835
|
+
"rsct",
|
|
836
|
+
"saoid",
|
|
837
|
+
"scid",
|
|
838
|
+
"se",
|
|
839
|
+
"sig",
|
|
840
|
+
"si",
|
|
841
|
+
"sip",
|
|
842
|
+
"ske",
|
|
843
|
+
"skoid",
|
|
844
|
+
"sks",
|
|
845
|
+
"skt",
|
|
846
|
+
"sktid",
|
|
847
|
+
"skv",
|
|
848
|
+
"snapshot",
|
|
849
|
+
"sp",
|
|
850
|
+
"spk",
|
|
851
|
+
"spr",
|
|
852
|
+
"sr",
|
|
853
|
+
"srk",
|
|
854
|
+
"srt",
|
|
855
|
+
"ss",
|
|
856
|
+
"st",
|
|
857
|
+
"suoid",
|
|
858
|
+
"tn",
|
|
859
|
+
"versionid",
|
|
860
|
+
"sv",
|
|
861
|
+
]);
|
|
862
|
+
function truncate(value, maximumLength) {
|
|
863
|
+
const text = String(value);
|
|
864
|
+
return text.length <= maximumLength
|
|
865
|
+
? text
|
|
866
|
+
: `${text.slice(0, maximumLength)}…`;
|
|
867
|
+
}
|
|
868
|
+
function normalizeRequired(value, fallback, maximumLength) {
|
|
869
|
+
const normalized = value == null ? "" : String(value).trim();
|
|
870
|
+
return truncate(normalized || fallback, maximumLength);
|
|
871
|
+
}
|
|
872
|
+
function normalizeOptional(value, maximumLength) {
|
|
873
|
+
if (value == null)
|
|
874
|
+
return undefined;
|
|
875
|
+
const normalized = String(value).trim();
|
|
876
|
+
return normalized ? truncate(normalized, maximumLength) : undefined;
|
|
877
|
+
}
|
|
878
|
+
function lowercaseSet(values) {
|
|
879
|
+
return new Set((values ?? []).map((value) => value.toLowerCase()));
|
|
880
|
+
}
|
|
881
|
+
function isSensitiveHeader(name, options) {
|
|
882
|
+
const lowered = name.toLowerCase();
|
|
883
|
+
if (sensitiveHeaderNames.has(lowered) ||
|
|
884
|
+
lowercaseSet(options.additionalSensitiveHeaderNames).has(lowered)) {
|
|
885
|
+
return true;
|
|
886
|
+
}
|
|
887
|
+
const compact = lowered.replaceAll("-", "");
|
|
888
|
+
return (compact.includes("token") ||
|
|
889
|
+
compact.includes("secret") ||
|
|
890
|
+
compact.includes("apikey"));
|
|
891
|
+
}
|
|
892
|
+
function headerEntries(headers) {
|
|
893
|
+
if (!headers)
|
|
894
|
+
return [];
|
|
895
|
+
if (Array.isArray(headers)) {
|
|
896
|
+
return headers.flatMap((header) => {
|
|
897
|
+
if (Array.isArray(header))
|
|
898
|
+
return [[header[0], header[1]]];
|
|
899
|
+
if (header && typeof header === "object") {
|
|
900
|
+
const value = header;
|
|
901
|
+
return [[value.name, value.value]];
|
|
902
|
+
}
|
|
903
|
+
return [];
|
|
904
|
+
});
|
|
905
|
+
}
|
|
906
|
+
if (typeof headers.forEach === "function") {
|
|
907
|
+
const entries = [];
|
|
908
|
+
headers.forEach((value, name) => entries.push([name, value]));
|
|
909
|
+
return entries;
|
|
910
|
+
}
|
|
911
|
+
return typeof headers === "object" ? Object.entries(headers) : [];
|
|
912
|
+
}
|
|
913
|
+
function sanitizeHeaders(headers, options) {
|
|
914
|
+
return headerEntries(headers)
|
|
915
|
+
.filter(([name]) => name != null && String(name).trim())
|
|
916
|
+
.slice(0, maximumHeaderCount)
|
|
917
|
+
.map(([rawName, rawValue]) => {
|
|
918
|
+
const name = normalizeRequired(rawName, "Header", 256);
|
|
919
|
+
return {
|
|
920
|
+
name,
|
|
921
|
+
value: isSensitiveHeader(name, options)
|
|
922
|
+
? redactedNetworkValue
|
|
923
|
+
: normalizeRequired(rawValue, "", maximumHeaderValueLength),
|
|
924
|
+
};
|
|
925
|
+
});
|
|
926
|
+
}
|
|
927
|
+
function sanitizeQuery(query, options) {
|
|
928
|
+
const appSensitive = lowercaseSet(options.additionalSensitiveQueryParameterNames);
|
|
929
|
+
const pairs = query.split("&");
|
|
930
|
+
const decodedNames = new Set(pairs.map((pair) => decodeQueryName(pair).toLowerCase()));
|
|
931
|
+
const hasAzureSas = decodedNames.has("sig") &&
|
|
932
|
+
[...azureSasFingerprintNames].some((name) => decodedNames.has(name));
|
|
933
|
+
const hasAwsSignature = decodedNames.has("x-amz-signature");
|
|
934
|
+
const hasGoogleSignature = decodedNames.has("x-goog-signature");
|
|
935
|
+
const hasCloudFrontSignature = decodedNames.has("signature") &&
|
|
936
|
+
["key-pair-id", "policy", "expires"].some((name) => decodedNames.has(name));
|
|
937
|
+
const hasLegacyGoogleSignature = decodedNames.has("signature") && decodedNames.has("googleaccessid");
|
|
938
|
+
const hasAlibabaSignature = (decodedNames.has("signature") && decodedNames.has("ossaccesskeyid")) ||
|
|
939
|
+
decodedNames.has("x-oss-signature");
|
|
940
|
+
return pairs
|
|
941
|
+
.map((pair) => {
|
|
942
|
+
const equalsIndex = pair.indexOf("=");
|
|
943
|
+
const encodedName = equalsIndex < 0 ? pair : pair.slice(0, equalsIndex);
|
|
944
|
+
const decodedName = decodeQueryName(pair);
|
|
945
|
+
const lowered = decodedName.toLowerCase();
|
|
946
|
+
const providerSensitive = (hasAzureSas && azureSasQueryNames.has(lowered)) ||
|
|
947
|
+
(hasAwsSignature && lowered.startsWith("x-amz-")) ||
|
|
948
|
+
(hasGoogleSignature && lowered.startsWith("x-goog-")) ||
|
|
949
|
+
(hasCloudFrontSignature &&
|
|
950
|
+
[
|
|
951
|
+
"signature",
|
|
952
|
+
"key-pair-id",
|
|
953
|
+
"policy",
|
|
954
|
+
"expires",
|
|
955
|
+
"hash-algorithm",
|
|
956
|
+
].includes(lowered)) ||
|
|
957
|
+
(hasLegacyGoogleSignature &&
|
|
958
|
+
["signature", "googleaccessid", "expires"].includes(lowered)) ||
|
|
959
|
+
(hasAlibabaSignature &&
|
|
960
|
+
(lowered.startsWith("x-oss-") ||
|
|
961
|
+
["signature", "ossaccesskeyid", "security-token"].includes(lowered)));
|
|
962
|
+
return providerSensitive ||
|
|
963
|
+
sensitiveQueryNames.has(lowered) ||
|
|
964
|
+
appSensitive.has(lowered)
|
|
965
|
+
? `${encodedName}=${encodeURIComponent(redactedNetworkValue)}`
|
|
966
|
+
: pair;
|
|
967
|
+
})
|
|
968
|
+
.join("&");
|
|
969
|
+
}
|
|
970
|
+
function decodeQueryName(pair) {
|
|
971
|
+
const equalsIndex = pair.indexOf("=");
|
|
972
|
+
const encodedName = equalsIndex < 0 ? pair : pair.slice(0, equalsIndex);
|
|
973
|
+
try {
|
|
974
|
+
return decodeURIComponent(encodedName.replaceAll("+", " "));
|
|
975
|
+
}
|
|
976
|
+
catch {
|
|
977
|
+
return encodedName;
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
function sanitizeUrl(value, options) {
|
|
981
|
+
let normalized = normalizeRequired(value, "<unknown>", maximumUrlLength);
|
|
982
|
+
normalized = normalized.replace(/^(https?:\/\/)[^/@]+@/i, `$1${redactedNetworkValue}@`);
|
|
983
|
+
const queryIndex = normalized.indexOf("?");
|
|
984
|
+
if (queryIndex < 0)
|
|
985
|
+
return truncate(normalized, maximumUrlLength);
|
|
986
|
+
const fragmentIndex = normalized.indexOf("#", queryIndex);
|
|
987
|
+
if (options.includeQueryString === false) {
|
|
988
|
+
return truncate(normalized.slice(0, queryIndex) +
|
|
989
|
+
(fragmentIndex < 0 ? "" : normalized.slice(fragmentIndex)), maximumUrlLength);
|
|
990
|
+
}
|
|
991
|
+
const queryEnd = fragmentIndex < 0 ? normalized.length : fragmentIndex;
|
|
992
|
+
return truncate(normalized.slice(0, queryIndex + 1) +
|
|
993
|
+
sanitizeQuery(normalized.slice(queryIndex + 1, queryEnd), options) +
|
|
994
|
+
(fragmentIndex < 0 ? "" : normalized.slice(fragmentIndex)), maximumUrlLength);
|
|
995
|
+
}
|
|
996
|
+
function sanitizeErrorMessage(value, options) {
|
|
997
|
+
const normalized = normalizeOptional(value, maximumErrorMessageLength);
|
|
998
|
+
if (!normalized)
|
|
999
|
+
return undefined;
|
|
1000
|
+
return truncate(normalized
|
|
1001
|
+
.replace(/(access_token|api_key|apikey|auth|authorization|code|key|password|passwd|secret|signature|token)(\s*=\s*)([^&\s,;]+)/gi, `$1$2${redactedNetworkValue}`)
|
|
1002
|
+
.replace(/https?:\/\/[^\s"'<>]+/gi, (url) => sanitizeUrl(url, options)), maximumErrorMessageLength);
|
|
1003
|
+
}
|
|
1004
|
+
function normalizeTimestamp(value, fallback) {
|
|
1005
|
+
const date = new Date(value == null ? fallback : String(value));
|
|
1006
|
+
return Number.isFinite(date.valueOf()) ? date.toISOString() : fallback;
|
|
1007
|
+
}
|
|
1008
|
+
function generateId(globalObject) {
|
|
1009
|
+
if (typeof globalObject.crypto?.randomUUID === "function") {
|
|
1010
|
+
return globalObject.crypto.randomUUID().replaceAll("-", "");
|
|
1011
|
+
}
|
|
1012
|
+
return `${Date.now().toString(36)}${Math.random().toString(36).slice(2)}`;
|
|
1013
|
+
}
|
|
1014
|
+
function normalizeSize(value) {
|
|
1015
|
+
const number = Number(value);
|
|
1016
|
+
return Number.isFinite(number) && number >= 0
|
|
1017
|
+
? Math.round(number)
|
|
1018
|
+
: undefined;
|
|
1019
|
+
}
|
|
1020
|
+
function maximumBodyBytes(options) {
|
|
1021
|
+
const configured = Number(options.maximumBodyBytes);
|
|
1022
|
+
const value = Number.isFinite(configured)
|
|
1023
|
+
? Math.round(configured)
|
|
1024
|
+
: defaultMaximumBodyBytes;
|
|
1025
|
+
return Math.max(0, value);
|
|
1026
|
+
}
|
|
1027
|
+
function sanitizeSensitiveText(value, options) {
|
|
1028
|
+
return value
|
|
1029
|
+
.replace(/(access_token|accesskey|access_key|api_key|apikey|auth|authorization|client_secret|code|credential|credentials|id_token|jwt|key|password|passwd|refresh_token|sas|sastoken|secret|secret_key|security_token|session_token|sig|signature|token)(["']?\s*[:=]\s*["']?)([^&\s,;}"']+)/gi, `$1$2${redactedNetworkValue}`)
|
|
1030
|
+
.replace(/https?:\/\/[^\s"'<>]+/gi, (url) => sanitizeUrl(url, options));
|
|
1031
|
+
}
|
|
1032
|
+
function truncateUtf8(bytes, maximum) {
|
|
1033
|
+
let length = Math.min(bytes.length, maximum);
|
|
1034
|
+
const decoder = new TextDecoder("utf-8", { fatal: true });
|
|
1035
|
+
while (length > 0) {
|
|
1036
|
+
try {
|
|
1037
|
+
decoder.decode(bytes.slice(0, length));
|
|
1038
|
+
return bytes.slice(0, length);
|
|
1039
|
+
}
|
|
1040
|
+
catch {
|
|
1041
|
+
length -= 1;
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
return new Uint8Array();
|
|
1045
|
+
}
|
|
1046
|
+
function bytesToBase64$1(bytes) {
|
|
1047
|
+
let binary = "";
|
|
1048
|
+
for (const byte of bytes)
|
|
1049
|
+
binary += String.fromCharCode(byte);
|
|
1050
|
+
return btoa(binary);
|
|
1051
|
+
}
|
|
1052
|
+
function base64ToBytes(value) {
|
|
1053
|
+
const binary = atob(value);
|
|
1054
|
+
return Uint8Array.from(binary, (character) => character.charCodeAt(0));
|
|
1055
|
+
}
|
|
1056
|
+
function normalizeBody(body, options) {
|
|
1057
|
+
const maximum = maximumBodyBytes(options);
|
|
1058
|
+
if (!body || maximum <= 0)
|
|
1059
|
+
return undefined;
|
|
1060
|
+
const encoding = body.encoding?.toLowerCase();
|
|
1061
|
+
let bytes;
|
|
1062
|
+
try {
|
|
1063
|
+
if (encoding === "utf8") {
|
|
1064
|
+
bytes = new TextEncoder().encode(sanitizeSensitiveText(body.data, options));
|
|
1065
|
+
}
|
|
1066
|
+
else if (encoding === "base64" && options.captureBinaryBodies === true) {
|
|
1067
|
+
bytes = base64ToBytes(body.data);
|
|
1068
|
+
}
|
|
1069
|
+
else {
|
|
1070
|
+
return undefined;
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
catch {
|
|
1074
|
+
return undefined;
|
|
1075
|
+
}
|
|
1076
|
+
const originalLength = bytes.length;
|
|
1077
|
+
const captured = encoding === "utf8"
|
|
1078
|
+
? truncateUtf8(bytes, maximum)
|
|
1079
|
+
: bytes.slice(0, maximum);
|
|
1080
|
+
const totalBytes = normalizeSize(body.totalBytes);
|
|
1081
|
+
return {
|
|
1082
|
+
contentType: normalizeOptional(body.contentType, 512),
|
|
1083
|
+
encoding,
|
|
1084
|
+
data: encoding === "base64"
|
|
1085
|
+
? bytesToBase64$1(captured)
|
|
1086
|
+
: new TextDecoder().decode(captured),
|
|
1087
|
+
capturedBytes: captured.length,
|
|
1088
|
+
totalBytes,
|
|
1089
|
+
truncated: body.truncated ||
|
|
1090
|
+
originalLength > captured.length ||
|
|
1091
|
+
(totalBytes != null && totalBytes > captured.length),
|
|
1092
|
+
};
|
|
1093
|
+
}
|
|
1094
|
+
function normalizeRecord(input, options, globalObject) {
|
|
1095
|
+
const now = new Date().toISOString();
|
|
1096
|
+
const startedAtUtc = normalizeTimestamp(input.startedAtUtc, now);
|
|
1097
|
+
const completedAtUtc = normalizeTimestamp(input.completedAtUtc, startedAtUtc);
|
|
1098
|
+
const duration = Number(input.durationMilliseconds);
|
|
1099
|
+
return {
|
|
1100
|
+
schema: networkRequestSchema,
|
|
1101
|
+
id: normalizeRequired(input.id, generateId(globalObject), 128),
|
|
1102
|
+
source: normalizeRequired(input.source, "unknown", 128),
|
|
1103
|
+
startedAtUtc,
|
|
1104
|
+
completedAtUtc: completedAtUtc < startedAtUtc ? startedAtUtc : completedAtUtc,
|
|
1105
|
+
durationMilliseconds: Number.isFinite(duration) && duration >= 0 ? duration : 0,
|
|
1106
|
+
method: normalizeRequired(input.method, "GET", 32).toUpperCase(),
|
|
1107
|
+
url: sanitizeUrl(input.url, options),
|
|
1108
|
+
protocol: normalizeOptional(input.protocol, 64),
|
|
1109
|
+
requestHeaders: options.includeRequestHeaders === false
|
|
1110
|
+
? []
|
|
1111
|
+
: sanitizeHeaders(input.requestHeaders, options),
|
|
1112
|
+
requestBodySizeBytes: options.includeBodySizes === false
|
|
1113
|
+
? undefined
|
|
1114
|
+
: normalizeSize(input.requestBodySizeBytes),
|
|
1115
|
+
requestBody: options.captureRequestBody !== false
|
|
1116
|
+
? normalizeBody(input.requestBody, options)
|
|
1117
|
+
: undefined,
|
|
1118
|
+
statusCode: Number.isInteger(Number(input.statusCode)) &&
|
|
1119
|
+
Number(input.statusCode) >= 100 &&
|
|
1120
|
+
Number(input.statusCode) <= 999
|
|
1121
|
+
? Number(input.statusCode)
|
|
1122
|
+
: undefined,
|
|
1123
|
+
reasonPhrase: normalizeOptional(input.reasonPhrase, 512),
|
|
1124
|
+
responseHeaders: options.includeResponseHeaders === false
|
|
1125
|
+
? []
|
|
1126
|
+
: sanitizeHeaders(input.responseHeaders, options),
|
|
1127
|
+
responseBodySizeBytes: options.includeBodySizes === false
|
|
1128
|
+
? undefined
|
|
1129
|
+
: normalizeSize(input.responseBodySizeBytes),
|
|
1130
|
+
responseBody: options.captureResponseBody !== false
|
|
1131
|
+
? normalizeBody(input.responseBody, options)
|
|
1132
|
+
: undefined,
|
|
1133
|
+
errorType: normalizeOptional(input.errorType, 512),
|
|
1134
|
+
errorMessage: sanitizeErrorMessage(input.errorMessage, options),
|
|
1135
|
+
};
|
|
1136
|
+
}
|
|
1137
|
+
function sanitizeNetworkRequest(input, options = {}, globalObject = globalThis) {
|
|
1138
|
+
try {
|
|
1139
|
+
let normalized = normalizeRecord(input, options, globalObject);
|
|
1140
|
+
if (options.urlSanitizer) {
|
|
1141
|
+
normalized = normalizeRecord({ ...normalized, url: options.urlSanitizer(normalized.url) }, options, globalObject);
|
|
1142
|
+
}
|
|
1143
|
+
if (options.requestSanitizer) {
|
|
1144
|
+
const transformed = options.requestSanitizer(normalized);
|
|
1145
|
+
if (transformed == null)
|
|
1146
|
+
return null;
|
|
1147
|
+
normalized = normalizeRecord(transformed, options, globalObject);
|
|
1148
|
+
}
|
|
1149
|
+
return normalized;
|
|
1150
|
+
}
|
|
1151
|
+
catch {
|
|
1152
|
+
return null;
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
function parseContentLength(headers) {
|
|
1156
|
+
const entry = headerEntries(headers).find(([name]) => String(name).toLowerCase() === "content-length");
|
|
1157
|
+
return entry ? normalizeSize(entry[1]) : undefined;
|
|
1158
|
+
}
|
|
1159
|
+
function headerValue(headers, wantedName) {
|
|
1160
|
+
const entry = headerEntries(headers).find(([name]) => String(name).toLowerCase() === wantedName);
|
|
1161
|
+
return entry == null ? undefined : String(entry[1]);
|
|
1162
|
+
}
|
|
1163
|
+
function isTextContentType(contentType) {
|
|
1164
|
+
if (!contentType)
|
|
1165
|
+
return true;
|
|
1166
|
+
const mediaType = contentType.split(";", 1)[0].trim().toLowerCase();
|
|
1167
|
+
return (mediaType.startsWith("text/") ||
|
|
1168
|
+
mediaType.endsWith("+json") ||
|
|
1169
|
+
mediaType.endsWith("+xml") ||
|
|
1170
|
+
[
|
|
1171
|
+
"application/json",
|
|
1172
|
+
"application/xml",
|
|
1173
|
+
"application/graphql",
|
|
1174
|
+
"application/javascript",
|
|
1175
|
+
"application/x-www-form-urlencoded",
|
|
1176
|
+
].includes(mediaType));
|
|
1177
|
+
}
|
|
1178
|
+
function bodyFromBytes(bytes, totalBytes, contentType, options) {
|
|
1179
|
+
const binary = !isTextContentType(contentType);
|
|
1180
|
+
if (binary && options.captureBinaryBodies !== true)
|
|
1181
|
+
return undefined;
|
|
1182
|
+
const maximum = maximumBodyBytes(options);
|
|
1183
|
+
if (maximum <= 0)
|
|
1184
|
+
return undefined;
|
|
1185
|
+
const captured = binary
|
|
1186
|
+
? bytes.slice(0, maximum)
|
|
1187
|
+
: truncateUtf8(bytes, maximum);
|
|
1188
|
+
return {
|
|
1189
|
+
contentType,
|
|
1190
|
+
encoding: binary ? "base64" : "utf8",
|
|
1191
|
+
data: binary ? bytesToBase64$1(captured) : new TextDecoder().decode(captured),
|
|
1192
|
+
capturedBytes: captured.length,
|
|
1193
|
+
totalBytes,
|
|
1194
|
+
truncated: bytes.length > captured.length ||
|
|
1195
|
+
(totalBytes != null && totalBytes > captured.length),
|
|
1196
|
+
};
|
|
1197
|
+
}
|
|
1198
|
+
function bodyFromValue(value, headers, options) {
|
|
1199
|
+
if (value == null || options.captureRequestBody === false)
|
|
1200
|
+
return undefined;
|
|
1201
|
+
const contentType = headerValue(headers, "content-type");
|
|
1202
|
+
if (typeof value === "string" || value instanceof URLSearchParams) {
|
|
1203
|
+
const bytes = new TextEncoder().encode(String(value));
|
|
1204
|
+
return bodyFromBytes(bytes, bytes.length, contentType ||
|
|
1205
|
+
(value instanceof URLSearchParams
|
|
1206
|
+
? "application/x-www-form-urlencoded"
|
|
1207
|
+
: undefined), options);
|
|
1208
|
+
}
|
|
1209
|
+
if (value instanceof ArrayBuffer) {
|
|
1210
|
+
const bytes = new Uint8Array(value);
|
|
1211
|
+
return bodyFromBytes(bytes, bytes.length, contentType, options);
|
|
1212
|
+
}
|
|
1213
|
+
if (ArrayBuffer.isView(value)) {
|
|
1214
|
+
const bytes = new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
|
|
1215
|
+
return bodyFromBytes(bytes, bytes.length, contentType, options);
|
|
1216
|
+
}
|
|
1217
|
+
return undefined;
|
|
1218
|
+
}
|
|
1219
|
+
async function bodyFromFetchResponse(response, headers, options, shouldContinue = () => true) {
|
|
1220
|
+
if (!shouldContinue() || options.captureResponseBody === false)
|
|
1221
|
+
return undefined;
|
|
1222
|
+
const contentType = headerValue(headers, "content-type");
|
|
1223
|
+
if (!isTextContentType(contentType) && options.captureBinaryBodies !== true) {
|
|
1224
|
+
return undefined;
|
|
1225
|
+
}
|
|
1226
|
+
const totalBytes = parseContentLength(headers);
|
|
1227
|
+
const maximum = maximumBodyBytes(options);
|
|
1228
|
+
if (maximum <= 0)
|
|
1229
|
+
return undefined;
|
|
1230
|
+
const clone = response.clone();
|
|
1231
|
+
if (clone.body) {
|
|
1232
|
+
const reader = clone.body.getReader();
|
|
1233
|
+
const chunks = [];
|
|
1234
|
+
let capturedLength = 0;
|
|
1235
|
+
let observedLength = 0;
|
|
1236
|
+
try {
|
|
1237
|
+
while (capturedLength <= maximum) {
|
|
1238
|
+
if (!shouldContinue()) {
|
|
1239
|
+
await reader.cancel().catch(() => undefined);
|
|
1240
|
+
return undefined;
|
|
1241
|
+
}
|
|
1242
|
+
const result = await reader.read();
|
|
1243
|
+
if (!shouldContinue()) {
|
|
1244
|
+
await reader.cancel().catch(() => undefined);
|
|
1245
|
+
return undefined;
|
|
1246
|
+
}
|
|
1247
|
+
if (result.done)
|
|
1248
|
+
break;
|
|
1249
|
+
const chunk = result.value;
|
|
1250
|
+
observedLength += chunk.length;
|
|
1251
|
+
const remaining = maximum - capturedLength;
|
|
1252
|
+
if (remaining > 0) {
|
|
1253
|
+
const kept = chunk.slice(0, remaining);
|
|
1254
|
+
chunks.push(kept);
|
|
1255
|
+
capturedLength += kept.length;
|
|
1256
|
+
}
|
|
1257
|
+
if (observedLength > maximum) {
|
|
1258
|
+
await reader.cancel().catch(() => undefined);
|
|
1259
|
+
break;
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
finally {
|
|
1264
|
+
reader.releaseLock();
|
|
1265
|
+
}
|
|
1266
|
+
const joined = new Uint8Array(capturedLength);
|
|
1267
|
+
let offset = 0;
|
|
1268
|
+
for (const chunk of chunks) {
|
|
1269
|
+
joined.set(chunk, offset);
|
|
1270
|
+
offset += chunk.length;
|
|
1271
|
+
}
|
|
1272
|
+
return bodyFromBytes(joined, totalBytes ?? observedLength, contentType, options);
|
|
1273
|
+
}
|
|
1274
|
+
if (totalBytes == null || totalBytes > maximum)
|
|
1275
|
+
return undefined;
|
|
1276
|
+
const bytes = new Uint8Array(await clone.arrayBuffer());
|
|
1277
|
+
if (!shouldContinue())
|
|
1278
|
+
return undefined;
|
|
1279
|
+
return bodyFromBytes(bytes, totalBytes, contentType, options);
|
|
1280
|
+
}
|
|
1281
|
+
function parseXhrResponseHeaders(value) {
|
|
1282
|
+
return value
|
|
1283
|
+
.trim()
|
|
1284
|
+
.split(/[\r\n]+/)
|
|
1285
|
+
.flatMap((line) => {
|
|
1286
|
+
const separator = line.indexOf(":");
|
|
1287
|
+
return separator < 0
|
|
1288
|
+
? []
|
|
1289
|
+
: [
|
|
1290
|
+
{
|
|
1291
|
+
name: line.slice(0, separator),
|
|
1292
|
+
value: line.slice(separator + 1),
|
|
1293
|
+
},
|
|
1294
|
+
];
|
|
1295
|
+
});
|
|
1296
|
+
}
|
|
1297
|
+
function monotonicNow(globalObject) {
|
|
1298
|
+
return typeof globalObject.performance?.now === "function"
|
|
1299
|
+
? globalObject.performance.now()
|
|
1300
|
+
: Date.now();
|
|
1301
|
+
}
|
|
1302
|
+
function installBrowserNetworkCapture(capture, options = {}, sourcePrefix = "capacitor", globalObject = globalThis) {
|
|
1303
|
+
const cleanups = [];
|
|
1304
|
+
let active = true;
|
|
1305
|
+
let fetchInvocationDepth = 0;
|
|
1306
|
+
if (options.captureFetch !== false &&
|
|
1307
|
+
typeof globalObject.fetch === "function") {
|
|
1308
|
+
const originalFetch = globalObject.fetch;
|
|
1309
|
+
const wrappedFetch = function (input, init) {
|
|
1310
|
+
const startedAtUtc = new Date().toISOString();
|
|
1311
|
+
const started = monotonicNow(globalObject);
|
|
1312
|
+
const inputRequest = typeof input === "object" && "headers" in input && "method" in input
|
|
1313
|
+
? input
|
|
1314
|
+
: undefined;
|
|
1315
|
+
const requestHeaders = headerEntries(inputRequest?.headers).concat(headerEntries(init?.headers));
|
|
1316
|
+
const requestBody = bodyFromValue(init?.body, requestHeaders, options);
|
|
1317
|
+
const method = init?.method || inputRequest?.method || "GET";
|
|
1318
|
+
const url = typeof input === "string" ? input : inputRequest?.url || String(input);
|
|
1319
|
+
let promise;
|
|
1320
|
+
fetchInvocationDepth += 1;
|
|
1321
|
+
try {
|
|
1322
|
+
promise = originalFetch(input, init);
|
|
1323
|
+
}
|
|
1324
|
+
catch (error) {
|
|
1325
|
+
fetchInvocationDepth -= 1;
|
|
1326
|
+
const request = sanitizeNetworkRequest({
|
|
1327
|
+
source: `${sourcePrefix}.fetch`,
|
|
1328
|
+
startedAtUtc,
|
|
1329
|
+
completedAtUtc: new Date().toISOString(),
|
|
1330
|
+
durationMilliseconds: monotonicNow(globalObject) - started,
|
|
1331
|
+
method,
|
|
1332
|
+
url,
|
|
1333
|
+
requestHeaders: sanitizeHeaders(requestHeaders, {}),
|
|
1334
|
+
requestBodySizeBytes: parseContentLength(requestHeaders) ?? requestBody?.totalBytes,
|
|
1335
|
+
requestBody,
|
|
1336
|
+
errorType: error instanceof Error ? error.name : "Error",
|
|
1337
|
+
errorMessage: error instanceof Error ? error.message : String(error),
|
|
1338
|
+
}, options, globalObject);
|
|
1339
|
+
if (active && request)
|
|
1340
|
+
Promise.resolve(capture(request)).catch(() => undefined);
|
|
1341
|
+
throw error;
|
|
1342
|
+
}
|
|
1343
|
+
fetchInvocationDepth -= 1;
|
|
1344
|
+
return promise.then((response) => {
|
|
1345
|
+
if (!active)
|
|
1346
|
+
return response;
|
|
1347
|
+
const responseHeaders = headerEntries(response.headers);
|
|
1348
|
+
const responseRecord = {
|
|
1349
|
+
source: `${sourcePrefix}.fetch`,
|
|
1350
|
+
startedAtUtc,
|
|
1351
|
+
completedAtUtc: new Date().toISOString(),
|
|
1352
|
+
durationMilliseconds: monotonicNow(globalObject) - started,
|
|
1353
|
+
method,
|
|
1354
|
+
url: response.url || url,
|
|
1355
|
+
requestHeaders: sanitizeHeaders(requestHeaders, {}),
|
|
1356
|
+
requestBodySizeBytes: parseContentLength(requestHeaders) ?? requestBody?.totalBytes,
|
|
1357
|
+
requestBody,
|
|
1358
|
+
statusCode: response.status,
|
|
1359
|
+
reasonPhrase: response.statusText,
|
|
1360
|
+
responseHeaders: sanitizeHeaders(responseHeaders, {}),
|
|
1361
|
+
responseBodySizeBytes: parseContentLength(responseHeaders),
|
|
1362
|
+
};
|
|
1363
|
+
return bodyFromFetchResponse(response, responseHeaders, options, () => active).then((responseBody) => {
|
|
1364
|
+
const request = sanitizeNetworkRequest({
|
|
1365
|
+
...responseRecord,
|
|
1366
|
+
responseBody,
|
|
1367
|
+
responseBodySizeBytes: responseRecord.responseBodySizeBytes ??
|
|
1368
|
+
responseBody?.totalBytes,
|
|
1369
|
+
}, options, globalObject);
|
|
1370
|
+
if (active && request)
|
|
1371
|
+
void Promise.resolve(capture(request)).catch(() => undefined);
|
|
1372
|
+
return response;
|
|
1373
|
+
}, () => {
|
|
1374
|
+
const request = sanitizeNetworkRequest(responseRecord, options, globalObject);
|
|
1375
|
+
if (active && request)
|
|
1376
|
+
void Promise.resolve(capture(request)).catch(() => undefined);
|
|
1377
|
+
return response;
|
|
1378
|
+
});
|
|
1379
|
+
}, (error) => {
|
|
1380
|
+
const request = sanitizeNetworkRequest({
|
|
1381
|
+
source: `${sourcePrefix}.fetch`,
|
|
1382
|
+
startedAtUtc,
|
|
1383
|
+
completedAtUtc: new Date().toISOString(),
|
|
1384
|
+
durationMilliseconds: monotonicNow(globalObject) - started,
|
|
1385
|
+
method,
|
|
1386
|
+
url,
|
|
1387
|
+
requestHeaders: sanitizeHeaders(requestHeaders, {}),
|
|
1388
|
+
requestBodySizeBytes: parseContentLength(requestHeaders) ?? requestBody?.totalBytes,
|
|
1389
|
+
requestBody,
|
|
1390
|
+
errorType: error instanceof Error ? error.name : "Error",
|
|
1391
|
+
errorMessage: error instanceof Error ? error.message : String(error),
|
|
1392
|
+
}, options, globalObject);
|
|
1393
|
+
if (active && request)
|
|
1394
|
+
Promise.resolve(capture(request)).catch(() => undefined);
|
|
1395
|
+
throw error;
|
|
1396
|
+
});
|
|
1397
|
+
};
|
|
1398
|
+
globalObject.fetch = wrappedFetch;
|
|
1399
|
+
cleanups.push(() => {
|
|
1400
|
+
if (globalObject.fetch === wrappedFetch)
|
|
1401
|
+
globalObject.fetch = originalFetch;
|
|
1402
|
+
});
|
|
1403
|
+
}
|
|
1404
|
+
const Xhr = globalObject.XMLHttpRequest;
|
|
1405
|
+
if (options.captureXmlHttpRequest !== false && Xhr?.prototype) {
|
|
1406
|
+
const states = new WeakMap();
|
|
1407
|
+
const prototype = Xhr.prototype;
|
|
1408
|
+
const originalOpen = prototype.open;
|
|
1409
|
+
const originalSend = prototype.send;
|
|
1410
|
+
const originalSetRequestHeader = prototype.setRequestHeader;
|
|
1411
|
+
const wrappedOpen = function (method, url, ...rest) {
|
|
1412
|
+
states.set(this, {
|
|
1413
|
+
method,
|
|
1414
|
+
url: String(url),
|
|
1415
|
+
requestHeaders: [],
|
|
1416
|
+
suppressed: fetchInvocationDepth > 0,
|
|
1417
|
+
});
|
|
1418
|
+
Reflect.apply(originalOpen, this, [method, url, ...rest]);
|
|
1419
|
+
};
|
|
1420
|
+
const wrappedSetRequestHeader = function (name, value) {
|
|
1421
|
+
states.get(this)?.requestHeaders.push({ name, value });
|
|
1422
|
+
Reflect.apply(originalSetRequestHeader, this, [name, value]);
|
|
1423
|
+
};
|
|
1424
|
+
const wrappedSend = function (body) {
|
|
1425
|
+
const state = states.get(this);
|
|
1426
|
+
if (!state || state.suppressed) {
|
|
1427
|
+
Reflect.apply(originalSend, this, [body]);
|
|
1428
|
+
return;
|
|
1429
|
+
}
|
|
1430
|
+
state.startedAtUtc = new Date().toISOString();
|
|
1431
|
+
state.started = monotonicNow(globalObject);
|
|
1432
|
+
state.requestBody = bodyFromValue(body, state.requestHeaders, options);
|
|
1433
|
+
let failure;
|
|
1434
|
+
const markFailure = (event) => {
|
|
1435
|
+
failure = event.type;
|
|
1436
|
+
};
|
|
1437
|
+
const complete = () => {
|
|
1438
|
+
if (!active)
|
|
1439
|
+
return;
|
|
1440
|
+
let responseHeaders = [];
|
|
1441
|
+
try {
|
|
1442
|
+
responseHeaders = parseXhrResponseHeaders(this.getAllResponseHeaders());
|
|
1443
|
+
}
|
|
1444
|
+
catch {
|
|
1445
|
+
// Some WebViews throw before response headers exist.
|
|
1446
|
+
}
|
|
1447
|
+
let responseBody;
|
|
1448
|
+
try {
|
|
1449
|
+
const responseType = this.responseType || "text";
|
|
1450
|
+
const responseOptions = {
|
|
1451
|
+
...options,
|
|
1452
|
+
captureRequestBody: options.captureResponseBody,
|
|
1453
|
+
};
|
|
1454
|
+
if (responseType === "text") {
|
|
1455
|
+
responseBody = bodyFromValue(this.responseText, responseHeaders, responseOptions);
|
|
1456
|
+
}
|
|
1457
|
+
else if (responseType === "arraybuffer") {
|
|
1458
|
+
responseBody = bodyFromValue(this.response, responseHeaders, responseOptions);
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
catch {
|
|
1462
|
+
// Response data is not readable for every XHR response type.
|
|
1463
|
+
}
|
|
1464
|
+
const request = sanitizeNetworkRequest({
|
|
1465
|
+
source: `${sourcePrefix}.xhr`,
|
|
1466
|
+
startedAtUtc: state.startedAtUtc,
|
|
1467
|
+
completedAtUtc: new Date().toISOString(),
|
|
1468
|
+
durationMilliseconds: monotonicNow(globalObject) - (state.started ?? 0),
|
|
1469
|
+
method: state.method,
|
|
1470
|
+
url: this.responseURL || state.url,
|
|
1471
|
+
requestHeaders: state.requestHeaders,
|
|
1472
|
+
requestBodySizeBytes: parseContentLength(state.requestHeaders) ??
|
|
1473
|
+
state.requestBody?.totalBytes,
|
|
1474
|
+
requestBody: state.requestBody,
|
|
1475
|
+
statusCode: this.status || undefined,
|
|
1476
|
+
reasonPhrase: this.statusText,
|
|
1477
|
+
responseHeaders,
|
|
1478
|
+
responseBodySizeBytes: parseContentLength(responseHeaders) ?? responseBody?.totalBytes,
|
|
1479
|
+
responseBody,
|
|
1480
|
+
errorType: failure,
|
|
1481
|
+
errorMessage: failure ? `XMLHttpRequest ${failure}` : undefined,
|
|
1482
|
+
}, options, globalObject);
|
|
1483
|
+
if (request)
|
|
1484
|
+
Promise.resolve(capture(request)).catch(() => undefined);
|
|
1485
|
+
};
|
|
1486
|
+
this.addEventListener("error", markFailure);
|
|
1487
|
+
this.addEventListener("abort", markFailure);
|
|
1488
|
+
this.addEventListener("timeout", markFailure);
|
|
1489
|
+
this.addEventListener("loadend", complete, { once: true });
|
|
1490
|
+
Reflect.apply(originalSend, this, [body]);
|
|
1491
|
+
};
|
|
1492
|
+
prototype.open = wrappedOpen;
|
|
1493
|
+
prototype.setRequestHeader = wrappedSetRequestHeader;
|
|
1494
|
+
prototype.send = wrappedSend;
|
|
1495
|
+
cleanups.push(() => {
|
|
1496
|
+
if (prototype.open === wrappedOpen)
|
|
1497
|
+
prototype.open = originalOpen;
|
|
1498
|
+
if (prototype.send === wrappedSend)
|
|
1499
|
+
prototype.send = originalSend;
|
|
1500
|
+
if (prototype.setRequestHeader === wrappedSetRequestHeader) {
|
|
1501
|
+
prototype.setRequestHeader = originalSetRequestHeader;
|
|
1502
|
+
}
|
|
1503
|
+
});
|
|
1504
|
+
}
|
|
1505
|
+
let removed = false;
|
|
1506
|
+
return {
|
|
1507
|
+
remove() {
|
|
1508
|
+
if (removed)
|
|
1509
|
+
return;
|
|
1510
|
+
removed = true;
|
|
1511
|
+
active = false;
|
|
1512
|
+
for (const cleanup of cleanups.reverse())
|
|
1513
|
+
cleanup();
|
|
1514
|
+
},
|
|
1515
|
+
};
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1518
|
+
const ANSIGHT_CAPACITOR_SDK_VERSION = "1.3.0-preview.11";
|
|
1519
|
+
const COMPILED_CAPACITOR_CORE_VERSION = "8.4.2";
|
|
1520
|
+
const CAPACITOR_GROUP = "capacitor";
|
|
1521
|
+
const LOCALIZATION_GROUP = "localization";
|
|
1522
|
+
function normalized(value) {
|
|
1523
|
+
if (value == null)
|
|
1524
|
+
return undefined;
|
|
1525
|
+
const result = String(value).trim();
|
|
1526
|
+
return result || undefined;
|
|
1527
|
+
}
|
|
1528
|
+
function canonicalizeLocale(value) {
|
|
1529
|
+
const locale = normalized(value)?.replace(/_/g, "-");
|
|
1530
|
+
if (!locale)
|
|
1531
|
+
return undefined;
|
|
1532
|
+
try {
|
|
1533
|
+
return Intl.getCanonicalLocales(locale)[0] ?? locale;
|
|
1534
|
+
}
|
|
1535
|
+
catch {
|
|
1536
|
+
return locale;
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
function parseLocale(locale) {
|
|
1540
|
+
const parts = (locale ?? "").split("-").filter(Boolean);
|
|
1541
|
+
const language = parts[0]?.toLowerCase();
|
|
1542
|
+
const region = parts.find((part, index) => index > 0 && (/^[A-Za-z]{2}$/.test(part) || /^\d{3}$/.test(part)));
|
|
1543
|
+
return { language, region: region?.toUpperCase() };
|
|
1544
|
+
}
|
|
1545
|
+
function webViewDetails(platform, nativePlatform, userAgent) {
|
|
1546
|
+
const agent = userAgent ?? "";
|
|
1547
|
+
if (nativePlatform && platform === "ios") {
|
|
1548
|
+
return {
|
|
1549
|
+
engine: "wkWebView",
|
|
1550
|
+
version: /AppleWebKit\/([^\s]+)/.exec(agent)?.[1],
|
|
1551
|
+
};
|
|
1552
|
+
}
|
|
1553
|
+
if (nativePlatform && platform === "android") {
|
|
1554
|
+
return {
|
|
1555
|
+
engine: "chromiumWebView",
|
|
1556
|
+
version: /(?:Chrome|Chromium)\/([^\s]+)/.exec(agent)?.[1],
|
|
1557
|
+
};
|
|
1558
|
+
}
|
|
1559
|
+
if (/Firefox\/([^\s]+)/.test(agent)) {
|
|
1560
|
+
return { engine: "gecko", version: /Firefox\/([^\s]+)/.exec(agent)?.[1] };
|
|
1561
|
+
}
|
|
1562
|
+
if (/(?:Chrome|Chromium)\/([^\s]+)/.test(agent)) {
|
|
1563
|
+
return {
|
|
1564
|
+
engine: "chromium",
|
|
1565
|
+
version: /(?:Chrome|Chromium)\/([^\s]+)/.exec(agent)?.[1],
|
|
1566
|
+
};
|
|
1567
|
+
}
|
|
1568
|
+
if (/AppleWebKit\/([^\s]+)/.test(agent)) {
|
|
1569
|
+
return {
|
|
1570
|
+
engine: "webkit",
|
|
1571
|
+
version: /AppleWebKit\/([^\s]+)/.exec(agent)?.[1],
|
|
1572
|
+
};
|
|
1573
|
+
}
|
|
1574
|
+
return { engine: "unknown" };
|
|
1575
|
+
}
|
|
1576
|
+
function currentCapacitorSessionEnvironment(platform, nativePlatform) {
|
|
1577
|
+
let resolved;
|
|
1578
|
+
try {
|
|
1579
|
+
resolved = Intl.DateTimeFormat().resolvedOptions();
|
|
1580
|
+
}
|
|
1581
|
+
catch {
|
|
1582
|
+
resolved = undefined;
|
|
1583
|
+
}
|
|
1584
|
+
return {
|
|
1585
|
+
platform,
|
|
1586
|
+
nativePlatform,
|
|
1587
|
+
userAgent: typeof navigator === "undefined" ? undefined : navigator.userAgent,
|
|
1588
|
+
locale: resolved?.locale ??
|
|
1589
|
+
(typeof navigator === "undefined" ? undefined : navigator.language),
|
|
1590
|
+
timeZone: resolved?.timeZone,
|
|
1591
|
+
utcOffsetMinutes: -new Date().getTimezoneOffset(),
|
|
1592
|
+
};
|
|
1593
|
+
}
|
|
1594
|
+
function createAutomaticSessionProperties(environment) {
|
|
1595
|
+
const platform = normalized(environment.platform) ?? "unknown";
|
|
1596
|
+
const userAgent = normalized(environment.userAgent);
|
|
1597
|
+
const webView = webViewDetails(platform, environment.nativePlatform, userAgent);
|
|
1598
|
+
const locale = canonicalizeLocale(environment.locale);
|
|
1599
|
+
const parsedLocale = parseLocale(locale);
|
|
1600
|
+
const capacitor = {
|
|
1601
|
+
sdkVersion: ANSIGHT_CAPACITOR_SDK_VERSION,
|
|
1602
|
+
capacitorVersion: "8.x",
|
|
1603
|
+
compiledCapacitorVersion: COMPILED_CAPACITOR_CORE_VERSION,
|
|
1604
|
+
platform,
|
|
1605
|
+
runtimeLanguage: "javascript",
|
|
1606
|
+
executionMode: environment.nativePlatform ? "native" : "web",
|
|
1607
|
+
webViewEngine: webView.engine,
|
|
1608
|
+
};
|
|
1609
|
+
if (webView.version)
|
|
1610
|
+
capacitor.webViewEngineVersion = webView.version;
|
|
1611
|
+
if (userAgent)
|
|
1612
|
+
capacitor.userAgent = userAgent;
|
|
1613
|
+
const localization = {
|
|
1614
|
+
utcOffsetMinutes: String(environment.utcOffsetMinutes ?? -new Date().getTimezoneOffset()),
|
|
1615
|
+
};
|
|
1616
|
+
if (locale)
|
|
1617
|
+
localization.locale = locale;
|
|
1618
|
+
if (parsedLocale.language)
|
|
1619
|
+
localization.language = parsedLocale.language;
|
|
1620
|
+
if (parsedLocale.region)
|
|
1621
|
+
localization.region = parsedLocale.region;
|
|
1622
|
+
if (normalized(environment.timeZone)) {
|
|
1623
|
+
localization.timeZone = String(environment.timeZone).trim();
|
|
1624
|
+
}
|
|
1625
|
+
return {
|
|
1626
|
+
[CAPACITOR_GROUP]: capacitor,
|
|
1627
|
+
[LOCALIZATION_GROUP]: localization,
|
|
1628
|
+
};
|
|
1629
|
+
}
|
|
1630
|
+
function mergeSessionProperties(automaticProperties, customProperties) {
|
|
1631
|
+
const merged = Object.fromEntries(Object.entries(automaticProperties).map(([group, properties]) => [
|
|
1632
|
+
group,
|
|
1633
|
+
{ ...properties },
|
|
1634
|
+
]));
|
|
1635
|
+
for (const [group, properties] of Object.entries(customProperties ?? {})) {
|
|
1636
|
+
merged[group] = { ...(merged[group] ?? {}), ...properties };
|
|
1637
|
+
}
|
|
1638
|
+
return merged;
|
|
1639
|
+
}
|
|
1640
|
+
|
|
621
1641
|
const AnsightNative = core.registerPlugin("Ansight");
|
|
622
1642
|
const toolHandlers = new Map();
|
|
623
1643
|
const artifactProviders = new Map();
|
|
@@ -628,6 +1648,9 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
628
1648
|
let lifecycleCleanup;
|
|
629
1649
|
let artifactToolRegistrations = [];
|
|
630
1650
|
let domToolRegistration;
|
|
1651
|
+
let networkCaptureSubscription;
|
|
1652
|
+
let networkCaptureRegistration;
|
|
1653
|
+
let networkConnectionListener;
|
|
631
1654
|
function normalizePairingPayload(payload) {
|
|
632
1655
|
if (payload == null)
|
|
633
1656
|
return payload;
|
|
@@ -635,11 +1658,19 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
635
1658
|
}
|
|
636
1659
|
function normalizeOptions(input) {
|
|
637
1660
|
const options = JSON.parse(JSON.stringify(input));
|
|
1661
|
+
options.customProperties = mergeSessionProperties(automaticSessionProperties(), options.customProperties);
|
|
638
1662
|
delete options.domTools;
|
|
639
1663
|
delete options.errorCapture;
|
|
640
1664
|
delete options.lifecycle;
|
|
1665
|
+
delete options.networkCapture;
|
|
641
1666
|
return options;
|
|
642
1667
|
}
|
|
1668
|
+
function automaticSessionProperties() {
|
|
1669
|
+
return createAutomaticSessionProperties(currentCapacitorSessionEnvironment(core.Capacitor.getPlatform(), core.Capacitor.isNativePlatform()));
|
|
1670
|
+
}
|
|
1671
|
+
function automaticSessionPropertyValue(group, key) {
|
|
1672
|
+
return automaticSessionProperties()[group]?.[key];
|
|
1673
|
+
}
|
|
643
1674
|
function normalizeToolResult(value) {
|
|
644
1675
|
if (value && typeof value === "object" && "success" in value) {
|
|
645
1676
|
return value;
|
|
@@ -689,11 +1720,13 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
689
1720
|
}
|
|
690
1721
|
async function afterConnectionChange(operation) {
|
|
691
1722
|
const result = await operation();
|
|
1723
|
+
await refreshNetworkCaptureConnection();
|
|
692
1724
|
await emitHostConnectionStatus();
|
|
693
1725
|
return result;
|
|
694
1726
|
}
|
|
695
1727
|
async function initialize(options = {}) {
|
|
696
1728
|
const result = await AnsightNative.initialize(normalizeOptions(options));
|
|
1729
|
+
await configureNetworkCapture(options.networkCapture);
|
|
697
1730
|
if (options.lifecycle !== false)
|
|
698
1731
|
startLifecycleTracking();
|
|
699
1732
|
if (options.errorCapture) {
|
|
@@ -707,6 +1740,7 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
707
1740
|
}
|
|
708
1741
|
async function initializeAndActivate(options = {}) {
|
|
709
1742
|
const result = await AnsightNative.initializeAndActivate(normalizeOptions(options));
|
|
1743
|
+
await configureNetworkCapture(options.networkCapture);
|
|
710
1744
|
if (options.lifecycle !== false)
|
|
711
1745
|
startLifecycleTracking();
|
|
712
1746
|
if (options.errorCapture) {
|
|
@@ -731,6 +1765,81 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
731
1765
|
return AnsightNative.recordEvent(typeof input === "string" ? { label: input } : input);
|
|
732
1766
|
}
|
|
733
1767
|
const recordEvent = event;
|
|
1768
|
+
async function recordNetworkRequest(input, sanitizationOptions = {}) {
|
|
1769
|
+
const request = sanitizeNetworkRequest(input, sanitizationOptions);
|
|
1770
|
+
if (!request) {
|
|
1771
|
+
return {
|
|
1772
|
+
success: false,
|
|
1773
|
+
message: "Network request capture was suppressed by the sanitizer.",
|
|
1774
|
+
};
|
|
1775
|
+
}
|
|
1776
|
+
return AnsightNative.recordNetworkRequest(request);
|
|
1777
|
+
}
|
|
1778
|
+
function installNetworkCapture(options = {}) {
|
|
1779
|
+
uninstallNetworkCapture();
|
|
1780
|
+
const registration = { options };
|
|
1781
|
+
networkCaptureRegistration = registration;
|
|
1782
|
+
ensureNetworkConnectionListener();
|
|
1783
|
+
void refreshNetworkCaptureConnection();
|
|
1784
|
+
return {
|
|
1785
|
+
remove() {
|
|
1786
|
+
if (networkCaptureRegistration === registration) {
|
|
1787
|
+
uninstallNetworkCapture();
|
|
1788
|
+
}
|
|
1789
|
+
},
|
|
1790
|
+
};
|
|
1791
|
+
}
|
|
1792
|
+
function uninstallNetworkCapture() {
|
|
1793
|
+
networkCaptureRegistration = undefined;
|
|
1794
|
+
const listener = networkConnectionListener;
|
|
1795
|
+
networkConnectionListener = undefined;
|
|
1796
|
+
if (listener)
|
|
1797
|
+
void listener.then((value) => value.remove());
|
|
1798
|
+
detachNetworkCapture();
|
|
1799
|
+
}
|
|
1800
|
+
function detachNetworkCapture() {
|
|
1801
|
+
networkCaptureSubscription?.remove();
|
|
1802
|
+
networkCaptureSubscription = undefined;
|
|
1803
|
+
}
|
|
1804
|
+
async function refreshNetworkCaptureConnection() {
|
|
1805
|
+
const registration = networkCaptureRegistration;
|
|
1806
|
+
if (!registration) {
|
|
1807
|
+
detachNetworkCapture();
|
|
1808
|
+
return;
|
|
1809
|
+
}
|
|
1810
|
+
try {
|
|
1811
|
+
const status = await AnsightNative.hostConnectionStatus();
|
|
1812
|
+
if (networkCaptureRegistration !== registration)
|
|
1813
|
+
return;
|
|
1814
|
+
applyNetworkConnectionStatus(status);
|
|
1815
|
+
}
|
|
1816
|
+
catch {
|
|
1817
|
+
if (networkCaptureRegistration === registration)
|
|
1818
|
+
detachNetworkCapture();
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1821
|
+
function ensureNetworkConnectionListener() {
|
|
1822
|
+
networkConnectionListener ??= AnsightNative.addListener("ansightHostConnectionStatus", applyNetworkConnectionStatus);
|
|
1823
|
+
}
|
|
1824
|
+
function applyNetworkConnectionStatus(status) {
|
|
1825
|
+
const registration = networkCaptureRegistration;
|
|
1826
|
+
if (!registration || status.isConnected !== true) {
|
|
1827
|
+
detachNetworkCapture();
|
|
1828
|
+
return;
|
|
1829
|
+
}
|
|
1830
|
+
networkCaptureSubscription ??= installBrowserNetworkCapture((request) => AnsightNative.recordNetworkRequest(request), registration.options);
|
|
1831
|
+
}
|
|
1832
|
+
async function configureNetworkCapture(value) {
|
|
1833
|
+
uninstallNetworkCapture();
|
|
1834
|
+
if (!value)
|
|
1835
|
+
return;
|
|
1836
|
+
networkCaptureRegistration = {
|
|
1837
|
+
options: typeof value === "object" ? value : {},
|
|
1838
|
+
};
|
|
1839
|
+
ensureNetworkConnectionListener();
|
|
1840
|
+
await refreshNetworkCaptureConnection();
|
|
1841
|
+
}
|
|
1842
|
+
const recordCrashCandidate = (input) => AnsightNative.recordCrashCandidate(input);
|
|
734
1843
|
const screenViewed = (name, details = {}) => AnsightNative.screenViewed({ name, details });
|
|
735
1844
|
const trackRoute = screenViewed;
|
|
736
1845
|
const setAppLifecycleState = (state) => AnsightNative.setAppLifecycleState({ state });
|
|
@@ -785,12 +1894,25 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
785
1894
|
const captureScreenFrame = (options = {}) => AnsightNative.captureScreenFrame(options);
|
|
786
1895
|
const enableTouchCapture = () => AnsightNative.enableTouchCapture();
|
|
787
1896
|
const disableTouchCapture = () => AnsightNative.disableTouchCapture();
|
|
788
|
-
const updateSessionProperties = (properties) => AnsightNative.updateSessionProperties({
|
|
1897
|
+
const updateSessionProperties = (properties) => AnsightNative.updateSessionProperties({
|
|
1898
|
+
properties: mergeSessionProperties(automaticSessionProperties(), properties),
|
|
1899
|
+
});
|
|
789
1900
|
const updateCustomProperties = updateSessionProperties;
|
|
790
|
-
const clearSessionProperties = () => AnsightNative.
|
|
1901
|
+
const clearSessionProperties = () => AnsightNative.updateSessionProperties({
|
|
1902
|
+
properties: automaticSessionProperties(),
|
|
1903
|
+
});
|
|
791
1904
|
const clearCustomProperties = clearSessionProperties;
|
|
792
1905
|
const registerCustomProperty = (group, key, value) => AnsightNative.registerCustomProperty({ group, key, value });
|
|
793
|
-
const removeCustomProperty = (group, key) =>
|
|
1906
|
+
const removeCustomProperty = (group, key) => {
|
|
1907
|
+
const automaticValue = automaticSessionPropertyValue(group, key);
|
|
1908
|
+
return automaticValue == null
|
|
1909
|
+
? AnsightNative.removeCustomProperty({ group, key })
|
|
1910
|
+
: AnsightNative.registerCustomProperty({
|
|
1911
|
+
group,
|
|
1912
|
+
key,
|
|
1913
|
+
value: automaticValue,
|
|
1914
|
+
});
|
|
1915
|
+
};
|
|
794
1916
|
function addHostConnectionStatusListener(listener, options = {}) {
|
|
795
1917
|
hostConnectionListeners.add(listener);
|
|
796
1918
|
if (options.emitCurrent !== false)
|
|
@@ -1036,6 +2158,18 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
1036
2158
|
const onError = (eventValue) => {
|
|
1037
2159
|
if (!captureErrors)
|
|
1038
2160
|
return;
|
|
2161
|
+
void recordCrashCandidate({
|
|
2162
|
+
runtime: "capacitor-javascript",
|
|
2163
|
+
kind: "unhandled_javascript_error",
|
|
2164
|
+
message: eventValue.message,
|
|
2165
|
+
stack: eventValue.error instanceof Error ? eventValue.error.stack : undefined,
|
|
2166
|
+
fatal: false,
|
|
2167
|
+
metadata: JSON.stringify({
|
|
2168
|
+
filename: eventValue.filename,
|
|
2169
|
+
line: eventValue.lineno,
|
|
2170
|
+
column: eventValue.colno,
|
|
2171
|
+
}),
|
|
2172
|
+
}).catch(() => undefined);
|
|
1039
2173
|
void event({
|
|
1040
2174
|
label: eventValue.message || "Unhandled JavaScript error",
|
|
1041
2175
|
type: "Exception",
|
|
@@ -1053,6 +2187,13 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
1053
2187
|
if (!captureRejections)
|
|
1054
2188
|
return;
|
|
1055
2189
|
const reason = eventValue.reason;
|
|
2190
|
+
void recordCrashCandidate({
|
|
2191
|
+
runtime: "capacitor-javascript",
|
|
2192
|
+
kind: "unhandled_promise_rejection",
|
|
2193
|
+
message: reason instanceof Error ? reason.message : String(reason),
|
|
2194
|
+
stack: reason instanceof Error ? reason.stack : undefined,
|
|
2195
|
+
fatal: false,
|
|
2196
|
+
}).catch(() => undefined);
|
|
1056
2197
|
void event({
|
|
1057
2198
|
label: reason instanceof Error
|
|
1058
2199
|
? reason.message
|
|
@@ -1122,6 +2263,10 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
1122
2263
|
recordMetric,
|
|
1123
2264
|
event,
|
|
1124
2265
|
recordEvent,
|
|
2266
|
+
recordNetworkRequest,
|
|
2267
|
+
installNetworkCapture,
|
|
2268
|
+
uninstallNetworkCapture,
|
|
2269
|
+
sanitizeNetworkRequest,
|
|
1125
2270
|
screenViewed,
|
|
1126
2271
|
trackRoute,
|
|
1127
2272
|
setAppLifecycleState,
|
|
@@ -1219,14 +2364,17 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
1219
2364
|
exports.initializeAndActivate = initializeAndActivate;
|
|
1220
2365
|
exports.installDomTools = installDomTools;
|
|
1221
2366
|
exports.installErrorHandlers = installErrorHandlers;
|
|
2367
|
+
exports.installNetworkCapture = installNetworkCapture;
|
|
1222
2368
|
exports.isFramesPerSecondEnabled = isFramesPerSecondEnabled;
|
|
1223
2369
|
exports.listRegisteredArtifactProviders = listRegisteredArtifactProviders;
|
|
1224
2370
|
exports.listRegisteredTools = listRegisteredTools;
|
|
1225
2371
|
exports.metric = metric;
|
|
1226
2372
|
exports.notifyHostConnectionConfigChanged = notifyHostConnectionConfigChanged;
|
|
1227
2373
|
exports.openSession = openSession;
|
|
2374
|
+
exports.recordCrashCandidate = recordCrashCandidate;
|
|
1228
2375
|
exports.recordEvent = recordEvent;
|
|
1229
2376
|
exports.recordMetric = recordMetric;
|
|
2377
|
+
exports.recordNetworkRequest = recordNetworkRequest;
|
|
1230
2378
|
exports.recordedEvents = recordedEvents;
|
|
1231
2379
|
exports.recordedMetrics = recordedMetrics;
|
|
1232
2380
|
exports.registerArtifactProvider = registerArtifactProvider;
|
|
@@ -1235,6 +2383,7 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
1235
2383
|
exports.registerMetricChannel = registerMetricChannel;
|
|
1236
2384
|
exports.registerTool = registerTool;
|
|
1237
2385
|
exports.removeCustomProperty = removeCustomProperty;
|
|
2386
|
+
exports.sanitizeNetworkRequest = sanitizeNetworkRequest;
|
|
1238
2387
|
exports.savePairingConfig = savePairingConfig;
|
|
1239
2388
|
exports.scanPairingQrCode = scanPairingQrCode;
|
|
1240
2389
|
exports.screenViewed = screenViewed;
|
|
@@ -1248,6 +2397,7 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
1248
2397
|
exports.stopLifecycleTracking = stopLifecycleTracking;
|
|
1249
2398
|
exports.trackRoute = trackRoute;
|
|
1250
2399
|
exports.uninstallDomTools = uninstallDomTools;
|
|
2400
|
+
exports.uninstallNetworkCapture = uninstallNetworkCapture;
|
|
1251
2401
|
exports.unregisterArtifactProvider = unregisterArtifactProvider;
|
|
1252
2402
|
exports.unregisterTool = unregisterTool;
|
|
1253
2403
|
exports.updateCustomProperties = updateCustomProperties;
|