@ansight/capacitor 1.3.0-preview.10 → 1.3.0-preview.12
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 +112 -25
- package/android/build.gradle +2 -2
- package/android/src/main/kotlin/ai/ansight/capacitor/AnsightCapacitorPlugin.kt +21 -0
- package/dist/esm/definitions.d.ts +70 -0
- package/dist/esm/definitions.d.ts.map +1 -1
- package/dist/esm/dom.d.ts +11 -0
- package/dist/esm/dom.d.ts.map +1 -1
- package/dist/esm/dom.js +69 -14
- package/dist/esm/dom.js.map +1 -1
- package/dist/esm/index.d.ts +10 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +111 -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 +7 -1
- package/dist/esm/options.d.ts.map +1 -1
- package/dist/esm/options.js +44 -0
- 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/esm/standalone-options.d.ts +3 -0
- package/dist/esm/standalone-options.d.ts.map +1 -0
- package/dist/esm/standalone-options.js +15 -0
- package/dist/esm/standalone-options.js.map +1 -0
- package/dist/esm/standalone.d.ts.map +1 -1
- package/dist/esm/standalone.js +2 -11
- package/dist/esm/standalone.js.map +1 -1
- package/dist/plugin.cjs.js +1090 -17
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +1090 -17
- package/dist/plugin.js.map +1 -1
- package/dist/standalone.js +1093 -20
- package/dist/standalone.js.map +1 -1
- package/ios/Sources/AnsightCapacitorPlugin/AnsightCapacitorPlugin.swift +28 -0
- package/package.json +1 -1
package/dist/plugin.js
CHANGED
|
@@ -59,6 +59,19 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
59
59
|
element.id ??
|
|
60
60
|
undefined)?.trim() || undefined);
|
|
61
61
|
}
|
|
62
|
+
const tapRoles = new Set([
|
|
63
|
+
"button",
|
|
64
|
+
"checkbox",
|
|
65
|
+
"combobox",
|
|
66
|
+
"link",
|
|
67
|
+
"menuitem",
|
|
68
|
+
"menuitemcheckbox",
|
|
69
|
+
"menuitemradio",
|
|
70
|
+
"option",
|
|
71
|
+
"radio",
|
|
72
|
+
"switch",
|
|
73
|
+
"tab",
|
|
74
|
+
]);
|
|
62
75
|
function semanticRole(element) {
|
|
63
76
|
const declared = element.getAttribute("role")?.trim().toLowerCase();
|
|
64
77
|
if (declared)
|
|
@@ -90,24 +103,54 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
90
103
|
if (!allowActions)
|
|
91
104
|
return [];
|
|
92
105
|
const actions = [];
|
|
106
|
+
const htmlElement = element;
|
|
107
|
+
const role = semanticRole(element);
|
|
93
108
|
if (["A", "BUTTON", "SUMMARY"].includes(element.tagName) ||
|
|
94
|
-
element instanceof HTMLInputElement
|
|
109
|
+
element instanceof HTMLInputElement ||
|
|
110
|
+
tapRoles.has(role) ||
|
|
111
|
+
element.hasAttribute("onclick") ||
|
|
112
|
+
typeof htmlElement.onclick === "function") {
|
|
95
113
|
actions.push("tap");
|
|
96
114
|
}
|
|
97
115
|
if (element instanceof HTMLInputElement ||
|
|
98
116
|
element instanceof HTMLTextAreaElement ||
|
|
99
|
-
element instanceof HTMLSelectElement
|
|
117
|
+
element instanceof HTMLSelectElement ||
|
|
118
|
+
htmlElement.isContentEditable) {
|
|
100
119
|
actions.push("typeText", "focus");
|
|
101
120
|
}
|
|
102
|
-
else if (
|
|
121
|
+
else if (htmlElement.tabIndex >= 0) {
|
|
103
122
|
actions.push("focus");
|
|
104
123
|
}
|
|
105
|
-
if (
|
|
106
|
-
|
|
124
|
+
if (htmlElement.scrollHeight > htmlElement.clientHeight ||
|
|
125
|
+
htmlElement.scrollWidth > htmlElement.clientWidth) {
|
|
107
126
|
actions.push("scroll", "swipe");
|
|
108
127
|
}
|
|
109
128
|
return [...new Set(actions)];
|
|
110
129
|
}
|
|
130
|
+
function positiveFinite(value) {
|
|
131
|
+
const parsed = Number(value);
|
|
132
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : undefined;
|
|
133
|
+
}
|
|
134
|
+
function createDomCoordinateSpace(browserWindow = typeof window === "undefined"
|
|
135
|
+
? undefined
|
|
136
|
+
: window, documentElement = typeof document === "undefined"
|
|
137
|
+
? null
|
|
138
|
+
: document.documentElement) {
|
|
139
|
+
const width = positiveFinite(browserWindow?.innerWidth) ??
|
|
140
|
+
positiveFinite(documentElement?.clientWidth);
|
|
141
|
+
const height = positiveFinite(browserWindow?.innerHeight) ??
|
|
142
|
+
positiveFinite(documentElement?.clientHeight);
|
|
143
|
+
if (width === undefined || height === undefined)
|
|
144
|
+
return undefined;
|
|
145
|
+
return { x: 0, y: 0, width, height, source: "dom.viewport" };
|
|
146
|
+
}
|
|
147
|
+
function normalizeDomAction(action) {
|
|
148
|
+
if (action === "tap")
|
|
149
|
+
return "click";
|
|
150
|
+
if (action === "typeText")
|
|
151
|
+
return "setValue";
|
|
152
|
+
return String(action ?? "");
|
|
153
|
+
}
|
|
111
154
|
function computedColorToArgbHex(value) {
|
|
112
155
|
const normalized = value.trim().toLowerCase();
|
|
113
156
|
if (!normalized)
|
|
@@ -272,6 +315,7 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
272
315
|
platform: "web",
|
|
273
316
|
source: options.source,
|
|
274
317
|
adapter: "@ansight/capacitor",
|
|
318
|
+
coordinateSpace: createDomCoordinateSpace(),
|
|
275
319
|
capturedAtUtc: new Date().toISOString(),
|
|
276
320
|
types: typeRegistry.types,
|
|
277
321
|
truncated: limits.count >= limits.maxNodes,
|
|
@@ -306,6 +350,7 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
306
350
|
platform: "web",
|
|
307
351
|
source: options.source,
|
|
308
352
|
adapter: "@ansight/capacitor",
|
|
353
|
+
coordinateSpace: createDomCoordinateSpace(),
|
|
309
354
|
capturedAtUtc: new Date().toISOString(),
|
|
310
355
|
types: typeRegistry.types,
|
|
311
356
|
node,
|
|
@@ -344,7 +389,7 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
344
389
|
registrations.push(registerTool({
|
|
345
390
|
id: "dom.invoke_action",
|
|
346
391
|
name: "Invoke DOM action",
|
|
347
|
-
description: "
|
|
392
|
+
description: "Taps, focuses, blurs, or enters text in a DOM node.",
|
|
348
393
|
category: "UI",
|
|
349
394
|
scope: "write",
|
|
350
395
|
argumentsSchema: {
|
|
@@ -352,7 +397,10 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
352
397
|
required: ["nodeId", "action"],
|
|
353
398
|
properties: {
|
|
354
399
|
nodeId: { type: "string" },
|
|
355
|
-
action: {
|
|
400
|
+
action: {
|
|
401
|
+
type: "string",
|
|
402
|
+
enum: ["tap", "typeText", "click", "focus", "blur", "setValue"],
|
|
403
|
+
},
|
|
356
404
|
value: { type: "string" },
|
|
357
405
|
},
|
|
358
406
|
},
|
|
@@ -369,17 +417,24 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
369
417
|
errorCode: "dom_node_not_found",
|
|
370
418
|
};
|
|
371
419
|
}
|
|
372
|
-
|
|
420
|
+
const normalizedAction = normalizeDomAction(action);
|
|
421
|
+
if (normalizedAction === "click")
|
|
373
422
|
element.click();
|
|
374
|
-
else if (
|
|
423
|
+
else if (normalizedAction === "focus")
|
|
375
424
|
element.focus();
|
|
376
|
-
else if (
|
|
425
|
+
else if (normalizedAction === "blur")
|
|
377
426
|
element.blur();
|
|
378
|
-
else if (
|
|
427
|
+
else if (normalizedAction === "setValue" &&
|
|
379
428
|
(element instanceof HTMLInputElement ||
|
|
380
429
|
element instanceof HTMLTextAreaElement ||
|
|
381
|
-
element instanceof HTMLSelectElement
|
|
382
|
-
|
|
430
|
+
element instanceof HTMLSelectElement ||
|
|
431
|
+
element.isContentEditable)) {
|
|
432
|
+
if (element.isContentEditable) {
|
|
433
|
+
element.textContent = value ?? "";
|
|
434
|
+
}
|
|
435
|
+
else {
|
|
436
|
+
element.value = value ?? "";
|
|
437
|
+
}
|
|
383
438
|
element.dispatchEvent(new Event("input", { bubbles: true }));
|
|
384
439
|
element.dispatchEvent(new Event("change", { bubbles: true }));
|
|
385
440
|
}
|
|
@@ -390,7 +445,7 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
390
445
|
errorCode: "dom_action_unsupported",
|
|
391
446
|
};
|
|
392
447
|
}
|
|
393
|
-
return successful({ nodeId: id, action }, `DOM action '${action}' invoked.`);
|
|
448
|
+
return successful({ nodeId: id, action, performedAction: normalizedAction }, `DOM action '${action}' invoked.`);
|
|
394
449
|
}));
|
|
395
450
|
}
|
|
396
451
|
return {
|
|
@@ -562,6 +617,50 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
562
617
|
};
|
|
563
618
|
return this;
|
|
564
619
|
}
|
|
620
|
+
withNetworkCapture(options = {}) {
|
|
621
|
+
this.options.networkCapture = { ...options };
|
|
622
|
+
return this;
|
|
623
|
+
}
|
|
624
|
+
withNetworkRequestBodies(maximumBodyBytes) {
|
|
625
|
+
if (typeof this.options.networkCapture !== "object")
|
|
626
|
+
return this;
|
|
627
|
+
const current = this.options.networkCapture;
|
|
628
|
+
this.options.networkCapture = {
|
|
629
|
+
...current,
|
|
630
|
+
captureRequestBody: true,
|
|
631
|
+
...(maximumBodyBytes == null ? {} : { maximumBodyBytes }),
|
|
632
|
+
};
|
|
633
|
+
return this;
|
|
634
|
+
}
|
|
635
|
+
withoutNetworkRequestBodies() {
|
|
636
|
+
if (typeof this.options.networkCapture !== "object")
|
|
637
|
+
return this;
|
|
638
|
+
const current = this.options.networkCapture;
|
|
639
|
+
this.options.networkCapture = { ...current, captureRequestBody: false };
|
|
640
|
+
return this;
|
|
641
|
+
}
|
|
642
|
+
withNetworkResponseBodies(maximumBodyBytes) {
|
|
643
|
+
if (typeof this.options.networkCapture !== "object")
|
|
644
|
+
return this;
|
|
645
|
+
const current = this.options.networkCapture;
|
|
646
|
+
this.options.networkCapture = {
|
|
647
|
+
...current,
|
|
648
|
+
captureResponseBody: true,
|
|
649
|
+
...(maximumBodyBytes == null ? {} : { maximumBodyBytes }),
|
|
650
|
+
};
|
|
651
|
+
return this;
|
|
652
|
+
}
|
|
653
|
+
withoutNetworkResponseBodies() {
|
|
654
|
+
if (typeof this.options.networkCapture !== "object")
|
|
655
|
+
return this;
|
|
656
|
+
const current = this.options.networkCapture;
|
|
657
|
+
this.options.networkCapture = { ...current, captureResponseBody: false };
|
|
658
|
+
return this;
|
|
659
|
+
}
|
|
660
|
+
withoutNetworkCapture() {
|
|
661
|
+
this.options.networkCapture = false;
|
|
662
|
+
return this;
|
|
663
|
+
}
|
|
565
664
|
withToolGuard(toolGuard) {
|
|
566
665
|
this.options.toolGuard = toolGuard;
|
|
567
666
|
return this;
|
|
@@ -729,6 +828,871 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
729
828
|
return new AnsightOptionsBuilder(options);
|
|
730
829
|
}
|
|
731
830
|
|
|
831
|
+
const networkRequestSchema = "ansight.network-request.v1";
|
|
832
|
+
const redactedNetworkValue = "<redacted>";
|
|
833
|
+
const maximumHeaderCount = 128;
|
|
834
|
+
const maximumHeaderValueLength = 4096;
|
|
835
|
+
const maximumErrorMessageLength = 4096;
|
|
836
|
+
const maximumUrlLength = 16384;
|
|
837
|
+
const defaultMaximumBodyBytes = 64 * 1024;
|
|
838
|
+
const sensitiveHeaderNames = new Set([
|
|
839
|
+
"authorization",
|
|
840
|
+
"cookie",
|
|
841
|
+
"proxy-authorization",
|
|
842
|
+
"set-cookie",
|
|
843
|
+
"x-api-key",
|
|
844
|
+
"x-auth-token",
|
|
845
|
+
]);
|
|
846
|
+
const sensitiveQueryNames = new Set([
|
|
847
|
+
"access_token",
|
|
848
|
+
"accesskey",
|
|
849
|
+
"access_key",
|
|
850
|
+
"api_key",
|
|
851
|
+
"apikey",
|
|
852
|
+
"auth",
|
|
853
|
+
"authorization",
|
|
854
|
+
"client_secret",
|
|
855
|
+
"code",
|
|
856
|
+
"credential",
|
|
857
|
+
"credentials",
|
|
858
|
+
"id_token",
|
|
859
|
+
"jwt",
|
|
860
|
+
"key",
|
|
861
|
+
"password",
|
|
862
|
+
"passwd",
|
|
863
|
+
"refresh_token",
|
|
864
|
+
"sas",
|
|
865
|
+
"sastoken",
|
|
866
|
+
"secret",
|
|
867
|
+
"secret_key",
|
|
868
|
+
"security_token",
|
|
869
|
+
"session_token",
|
|
870
|
+
"sig",
|
|
871
|
+
"signature",
|
|
872
|
+
"token",
|
|
873
|
+
]);
|
|
874
|
+
const azureSasFingerprintNames = new Set([
|
|
875
|
+
"se",
|
|
876
|
+
"skoid",
|
|
877
|
+
"sp",
|
|
878
|
+
"sr",
|
|
879
|
+
"srt",
|
|
880
|
+
"ss",
|
|
881
|
+
"sv",
|
|
882
|
+
]);
|
|
883
|
+
const azureSasQueryNames = new Set([
|
|
884
|
+
"epk",
|
|
885
|
+
"erk",
|
|
886
|
+
"rscc",
|
|
887
|
+
"rscd",
|
|
888
|
+
"rsce",
|
|
889
|
+
"rscl",
|
|
890
|
+
"rsct",
|
|
891
|
+
"saoid",
|
|
892
|
+
"scid",
|
|
893
|
+
"se",
|
|
894
|
+
"sig",
|
|
895
|
+
"si",
|
|
896
|
+
"sip",
|
|
897
|
+
"ske",
|
|
898
|
+
"skoid",
|
|
899
|
+
"sks",
|
|
900
|
+
"skt",
|
|
901
|
+
"sktid",
|
|
902
|
+
"skv",
|
|
903
|
+
"snapshot",
|
|
904
|
+
"sp",
|
|
905
|
+
"spk",
|
|
906
|
+
"spr",
|
|
907
|
+
"sr",
|
|
908
|
+
"srk",
|
|
909
|
+
"srt",
|
|
910
|
+
"ss",
|
|
911
|
+
"st",
|
|
912
|
+
"suoid",
|
|
913
|
+
"tn",
|
|
914
|
+
"versionid",
|
|
915
|
+
"sv",
|
|
916
|
+
]);
|
|
917
|
+
function truncate(value, maximumLength) {
|
|
918
|
+
const text = String(value);
|
|
919
|
+
return text.length <= maximumLength
|
|
920
|
+
? text
|
|
921
|
+
: `${text.slice(0, maximumLength)}…`;
|
|
922
|
+
}
|
|
923
|
+
function normalizeRequired(value, fallback, maximumLength) {
|
|
924
|
+
const normalized = value == null ? "" : String(value).trim();
|
|
925
|
+
return truncate(normalized || fallback, maximumLength);
|
|
926
|
+
}
|
|
927
|
+
function normalizeOptional(value, maximumLength) {
|
|
928
|
+
if (value == null)
|
|
929
|
+
return undefined;
|
|
930
|
+
const normalized = String(value).trim();
|
|
931
|
+
return normalized ? truncate(normalized, maximumLength) : undefined;
|
|
932
|
+
}
|
|
933
|
+
function lowercaseSet(values) {
|
|
934
|
+
return new Set((values ?? []).map((value) => value.toLowerCase()));
|
|
935
|
+
}
|
|
936
|
+
function isSensitiveHeader(name, options) {
|
|
937
|
+
const lowered = name.toLowerCase();
|
|
938
|
+
if (sensitiveHeaderNames.has(lowered) ||
|
|
939
|
+
lowercaseSet(options.additionalSensitiveHeaderNames).has(lowered)) {
|
|
940
|
+
return true;
|
|
941
|
+
}
|
|
942
|
+
const compact = lowered.replaceAll("-", "");
|
|
943
|
+
return (compact.includes("token") ||
|
|
944
|
+
compact.includes("secret") ||
|
|
945
|
+
compact.includes("apikey"));
|
|
946
|
+
}
|
|
947
|
+
function headerEntries(headers) {
|
|
948
|
+
if (!headers)
|
|
949
|
+
return [];
|
|
950
|
+
if (Array.isArray(headers)) {
|
|
951
|
+
return headers.flatMap((header) => {
|
|
952
|
+
if (Array.isArray(header))
|
|
953
|
+
return [[header[0], header[1]]];
|
|
954
|
+
if (header && typeof header === "object") {
|
|
955
|
+
const value = header;
|
|
956
|
+
return [[value.name, value.value]];
|
|
957
|
+
}
|
|
958
|
+
return [];
|
|
959
|
+
});
|
|
960
|
+
}
|
|
961
|
+
if (typeof headers.forEach === "function") {
|
|
962
|
+
const entries = [];
|
|
963
|
+
headers.forEach((value, name) => entries.push([name, value]));
|
|
964
|
+
return entries;
|
|
965
|
+
}
|
|
966
|
+
return typeof headers === "object" ? Object.entries(headers) : [];
|
|
967
|
+
}
|
|
968
|
+
function sanitizeHeaders(headers, options) {
|
|
969
|
+
return headerEntries(headers)
|
|
970
|
+
.filter(([name]) => name != null && String(name).trim())
|
|
971
|
+
.slice(0, maximumHeaderCount)
|
|
972
|
+
.map(([rawName, rawValue]) => {
|
|
973
|
+
const name = normalizeRequired(rawName, "Header", 256);
|
|
974
|
+
return {
|
|
975
|
+
name,
|
|
976
|
+
value: isSensitiveHeader(name, options)
|
|
977
|
+
? redactedNetworkValue
|
|
978
|
+
: normalizeRequired(rawValue, "", maximumHeaderValueLength),
|
|
979
|
+
};
|
|
980
|
+
});
|
|
981
|
+
}
|
|
982
|
+
function sanitizeQuery(query, options) {
|
|
983
|
+
const appSensitive = lowercaseSet(options.additionalSensitiveQueryParameterNames);
|
|
984
|
+
const pairs = query.split("&");
|
|
985
|
+
const decodedNames = new Set(pairs.map((pair) => decodeQueryName(pair).toLowerCase()));
|
|
986
|
+
const hasAzureSas = decodedNames.has("sig") &&
|
|
987
|
+
[...azureSasFingerprintNames].some((name) => decodedNames.has(name));
|
|
988
|
+
const hasAwsSignature = decodedNames.has("x-amz-signature");
|
|
989
|
+
const hasGoogleSignature = decodedNames.has("x-goog-signature");
|
|
990
|
+
const hasCloudFrontSignature = decodedNames.has("signature") &&
|
|
991
|
+
["key-pair-id", "policy", "expires"].some((name) => decodedNames.has(name));
|
|
992
|
+
const hasLegacyGoogleSignature = decodedNames.has("signature") && decodedNames.has("googleaccessid");
|
|
993
|
+
const hasAlibabaSignature = (decodedNames.has("signature") && decodedNames.has("ossaccesskeyid")) ||
|
|
994
|
+
decodedNames.has("x-oss-signature");
|
|
995
|
+
return pairs
|
|
996
|
+
.map((pair) => {
|
|
997
|
+
const equalsIndex = pair.indexOf("=");
|
|
998
|
+
const encodedName = equalsIndex < 0 ? pair : pair.slice(0, equalsIndex);
|
|
999
|
+
const decodedName = decodeQueryName(pair);
|
|
1000
|
+
const lowered = decodedName.toLowerCase();
|
|
1001
|
+
const providerSensitive = (hasAzureSas && azureSasQueryNames.has(lowered)) ||
|
|
1002
|
+
(hasAwsSignature && lowered.startsWith("x-amz-")) ||
|
|
1003
|
+
(hasGoogleSignature && lowered.startsWith("x-goog-")) ||
|
|
1004
|
+
(hasCloudFrontSignature &&
|
|
1005
|
+
[
|
|
1006
|
+
"signature",
|
|
1007
|
+
"key-pair-id",
|
|
1008
|
+
"policy",
|
|
1009
|
+
"expires",
|
|
1010
|
+
"hash-algorithm",
|
|
1011
|
+
].includes(lowered)) ||
|
|
1012
|
+
(hasLegacyGoogleSignature &&
|
|
1013
|
+
["signature", "googleaccessid", "expires"].includes(lowered)) ||
|
|
1014
|
+
(hasAlibabaSignature &&
|
|
1015
|
+
(lowered.startsWith("x-oss-") ||
|
|
1016
|
+
["signature", "ossaccesskeyid", "security-token"].includes(lowered)));
|
|
1017
|
+
return providerSensitive ||
|
|
1018
|
+
sensitiveQueryNames.has(lowered) ||
|
|
1019
|
+
appSensitive.has(lowered)
|
|
1020
|
+
? `${encodedName}=${encodeURIComponent(redactedNetworkValue)}`
|
|
1021
|
+
: pair;
|
|
1022
|
+
})
|
|
1023
|
+
.join("&");
|
|
1024
|
+
}
|
|
1025
|
+
function decodeQueryName(pair) {
|
|
1026
|
+
const equalsIndex = pair.indexOf("=");
|
|
1027
|
+
const encodedName = equalsIndex < 0 ? pair : pair.slice(0, equalsIndex);
|
|
1028
|
+
try {
|
|
1029
|
+
return decodeURIComponent(encodedName.replaceAll("+", " "));
|
|
1030
|
+
}
|
|
1031
|
+
catch {
|
|
1032
|
+
return encodedName;
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
function sanitizeUrl(value, options) {
|
|
1036
|
+
let normalized = normalizeRequired(value, "<unknown>", maximumUrlLength);
|
|
1037
|
+
normalized = normalized.replace(/^(https?:\/\/)[^/@]+@/i, `$1${redactedNetworkValue}@`);
|
|
1038
|
+
const queryIndex = normalized.indexOf("?");
|
|
1039
|
+
if (queryIndex < 0)
|
|
1040
|
+
return truncate(normalized, maximumUrlLength);
|
|
1041
|
+
const fragmentIndex = normalized.indexOf("#", queryIndex);
|
|
1042
|
+
if (options.includeQueryString === false) {
|
|
1043
|
+
return truncate(normalized.slice(0, queryIndex) +
|
|
1044
|
+
(fragmentIndex < 0 ? "" : normalized.slice(fragmentIndex)), maximumUrlLength);
|
|
1045
|
+
}
|
|
1046
|
+
const queryEnd = fragmentIndex < 0 ? normalized.length : fragmentIndex;
|
|
1047
|
+
return truncate(normalized.slice(0, queryIndex + 1) +
|
|
1048
|
+
sanitizeQuery(normalized.slice(queryIndex + 1, queryEnd), options) +
|
|
1049
|
+
(fragmentIndex < 0 ? "" : normalized.slice(fragmentIndex)), maximumUrlLength);
|
|
1050
|
+
}
|
|
1051
|
+
function sanitizeErrorMessage(value, options) {
|
|
1052
|
+
const normalized = normalizeOptional(value, maximumErrorMessageLength);
|
|
1053
|
+
if (!normalized)
|
|
1054
|
+
return undefined;
|
|
1055
|
+
return truncate(normalized
|
|
1056
|
+
.replace(/(access_token|api_key|apikey|auth|authorization|code|key|password|passwd|secret|signature|token)(\s*=\s*)([^&\s,;]+)/gi, `$1$2${redactedNetworkValue}`)
|
|
1057
|
+
.replace(/https?:\/\/[^\s"'<>]+/gi, (url) => sanitizeUrl(url, options)), maximumErrorMessageLength);
|
|
1058
|
+
}
|
|
1059
|
+
function normalizeTimestamp(value, fallback) {
|
|
1060
|
+
const date = new Date(value == null ? fallback : String(value));
|
|
1061
|
+
return Number.isFinite(date.valueOf()) ? date.toISOString() : fallback;
|
|
1062
|
+
}
|
|
1063
|
+
function generateId(globalObject) {
|
|
1064
|
+
if (typeof globalObject.crypto?.randomUUID === "function") {
|
|
1065
|
+
return globalObject.crypto.randomUUID().replaceAll("-", "");
|
|
1066
|
+
}
|
|
1067
|
+
return `${Date.now().toString(36)}${Math.random().toString(36).slice(2)}`;
|
|
1068
|
+
}
|
|
1069
|
+
function normalizeSize(value) {
|
|
1070
|
+
const number = Number(value);
|
|
1071
|
+
return Number.isFinite(number) && number >= 0
|
|
1072
|
+
? Math.round(number)
|
|
1073
|
+
: undefined;
|
|
1074
|
+
}
|
|
1075
|
+
function maximumBodyBytes(options) {
|
|
1076
|
+
const configured = Number(options.maximumBodyBytes);
|
|
1077
|
+
const value = Number.isFinite(configured)
|
|
1078
|
+
? Math.round(configured)
|
|
1079
|
+
: defaultMaximumBodyBytes;
|
|
1080
|
+
return Math.max(0, value);
|
|
1081
|
+
}
|
|
1082
|
+
function sanitizeSensitiveText(value, options) {
|
|
1083
|
+
return value
|
|
1084
|
+
.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}`)
|
|
1085
|
+
.replace(/https?:\/\/[^\s"'<>]+/gi, (url) => sanitizeUrl(url, options));
|
|
1086
|
+
}
|
|
1087
|
+
function truncateUtf8(bytes, maximum) {
|
|
1088
|
+
let length = Math.min(bytes.length, maximum);
|
|
1089
|
+
const decoder = new TextDecoder("utf-8", { fatal: true });
|
|
1090
|
+
while (length > 0) {
|
|
1091
|
+
try {
|
|
1092
|
+
decoder.decode(bytes.slice(0, length));
|
|
1093
|
+
return bytes.slice(0, length);
|
|
1094
|
+
}
|
|
1095
|
+
catch {
|
|
1096
|
+
length -= 1;
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
return new Uint8Array();
|
|
1100
|
+
}
|
|
1101
|
+
function bytesToBase64$1(bytes) {
|
|
1102
|
+
let binary = "";
|
|
1103
|
+
for (const byte of bytes)
|
|
1104
|
+
binary += String.fromCharCode(byte);
|
|
1105
|
+
return btoa(binary);
|
|
1106
|
+
}
|
|
1107
|
+
function base64ToBytes(value) {
|
|
1108
|
+
const binary = atob(value);
|
|
1109
|
+
return Uint8Array.from(binary, (character) => character.charCodeAt(0));
|
|
1110
|
+
}
|
|
1111
|
+
function normalizeBody(body, options) {
|
|
1112
|
+
const maximum = maximumBodyBytes(options);
|
|
1113
|
+
if (!body || maximum <= 0)
|
|
1114
|
+
return undefined;
|
|
1115
|
+
const encoding = body.encoding?.toLowerCase();
|
|
1116
|
+
let bytes;
|
|
1117
|
+
try {
|
|
1118
|
+
if (encoding === "utf8") {
|
|
1119
|
+
bytes = new TextEncoder().encode(sanitizeSensitiveText(body.data, options));
|
|
1120
|
+
}
|
|
1121
|
+
else if (encoding === "base64" && options.captureBinaryBodies === true) {
|
|
1122
|
+
bytes = base64ToBytes(body.data);
|
|
1123
|
+
}
|
|
1124
|
+
else {
|
|
1125
|
+
return undefined;
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
catch {
|
|
1129
|
+
return undefined;
|
|
1130
|
+
}
|
|
1131
|
+
const originalLength = bytes.length;
|
|
1132
|
+
const captured = encoding === "utf8"
|
|
1133
|
+
? truncateUtf8(bytes, maximum)
|
|
1134
|
+
: bytes.slice(0, maximum);
|
|
1135
|
+
const totalBytes = normalizeSize(body.totalBytes);
|
|
1136
|
+
return {
|
|
1137
|
+
contentType: normalizeOptional(body.contentType, 512),
|
|
1138
|
+
encoding,
|
|
1139
|
+
data: encoding === "base64"
|
|
1140
|
+
? bytesToBase64$1(captured)
|
|
1141
|
+
: new TextDecoder().decode(captured),
|
|
1142
|
+
capturedBytes: captured.length,
|
|
1143
|
+
totalBytes,
|
|
1144
|
+
truncated: body.truncated ||
|
|
1145
|
+
originalLength > captured.length ||
|
|
1146
|
+
(totalBytes != null && totalBytes > captured.length),
|
|
1147
|
+
};
|
|
1148
|
+
}
|
|
1149
|
+
function normalizeRecord(input, options, globalObject) {
|
|
1150
|
+
const now = new Date().toISOString();
|
|
1151
|
+
const startedAtUtc = normalizeTimestamp(input.startedAtUtc, now);
|
|
1152
|
+
const completedAtUtc = normalizeTimestamp(input.completedAtUtc, startedAtUtc);
|
|
1153
|
+
const duration = Number(input.durationMilliseconds);
|
|
1154
|
+
return {
|
|
1155
|
+
schema: networkRequestSchema,
|
|
1156
|
+
id: normalizeRequired(input.id, generateId(globalObject), 128),
|
|
1157
|
+
source: normalizeRequired(input.source, "unknown", 128),
|
|
1158
|
+
startedAtUtc,
|
|
1159
|
+
completedAtUtc: completedAtUtc < startedAtUtc ? startedAtUtc : completedAtUtc,
|
|
1160
|
+
durationMilliseconds: Number.isFinite(duration) && duration >= 0 ? duration : 0,
|
|
1161
|
+
method: normalizeRequired(input.method, "GET", 32).toUpperCase(),
|
|
1162
|
+
url: sanitizeUrl(input.url, options),
|
|
1163
|
+
protocol: normalizeOptional(input.protocol, 64),
|
|
1164
|
+
requestHeaders: options.includeRequestHeaders === false
|
|
1165
|
+
? []
|
|
1166
|
+
: sanitizeHeaders(input.requestHeaders, options),
|
|
1167
|
+
requestBodySizeBytes: options.includeBodySizes === false
|
|
1168
|
+
? undefined
|
|
1169
|
+
: normalizeSize(input.requestBodySizeBytes),
|
|
1170
|
+
requestBody: options.captureRequestBody !== false
|
|
1171
|
+
? normalizeBody(input.requestBody, options)
|
|
1172
|
+
: undefined,
|
|
1173
|
+
statusCode: Number.isInteger(Number(input.statusCode)) &&
|
|
1174
|
+
Number(input.statusCode) >= 100 &&
|
|
1175
|
+
Number(input.statusCode) <= 999
|
|
1176
|
+
? Number(input.statusCode)
|
|
1177
|
+
: undefined,
|
|
1178
|
+
reasonPhrase: normalizeOptional(input.reasonPhrase, 512),
|
|
1179
|
+
responseHeaders: options.includeResponseHeaders === false
|
|
1180
|
+
? []
|
|
1181
|
+
: sanitizeHeaders(input.responseHeaders, options),
|
|
1182
|
+
responseBodySizeBytes: options.includeBodySizes === false
|
|
1183
|
+
? undefined
|
|
1184
|
+
: normalizeSize(input.responseBodySizeBytes),
|
|
1185
|
+
responseBody: options.captureResponseBody !== false
|
|
1186
|
+
? normalizeBody(input.responseBody, options)
|
|
1187
|
+
: undefined,
|
|
1188
|
+
errorType: normalizeOptional(input.errorType, 512),
|
|
1189
|
+
errorMessage: sanitizeErrorMessage(input.errorMessage, options),
|
|
1190
|
+
};
|
|
1191
|
+
}
|
|
1192
|
+
function sanitizeNetworkRequest(input, options = {}, globalObject = globalThis) {
|
|
1193
|
+
try {
|
|
1194
|
+
let normalized = normalizeRecord(input, options, globalObject);
|
|
1195
|
+
if (options.urlSanitizer) {
|
|
1196
|
+
normalized = normalizeRecord({ ...normalized, url: options.urlSanitizer(normalized.url) }, options, globalObject);
|
|
1197
|
+
}
|
|
1198
|
+
if (options.requestSanitizer) {
|
|
1199
|
+
const transformed = options.requestSanitizer(normalized);
|
|
1200
|
+
if (transformed == null)
|
|
1201
|
+
return null;
|
|
1202
|
+
normalized = normalizeRecord(transformed, options, globalObject);
|
|
1203
|
+
}
|
|
1204
|
+
return normalized;
|
|
1205
|
+
}
|
|
1206
|
+
catch {
|
|
1207
|
+
return null;
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
function parseContentLength(headers) {
|
|
1211
|
+
const entry = headerEntries(headers).find(([name]) => String(name).toLowerCase() === "content-length");
|
|
1212
|
+
return entry ? normalizeSize(entry[1]) : undefined;
|
|
1213
|
+
}
|
|
1214
|
+
function headerValue(headers, wantedName) {
|
|
1215
|
+
const entry = headerEntries(headers).find(([name]) => String(name).toLowerCase() === wantedName);
|
|
1216
|
+
return entry == null ? undefined : String(entry[1]);
|
|
1217
|
+
}
|
|
1218
|
+
function isTextContentType(contentType) {
|
|
1219
|
+
if (!contentType)
|
|
1220
|
+
return true;
|
|
1221
|
+
const mediaType = contentType.split(";", 1)[0].trim().toLowerCase();
|
|
1222
|
+
return (mediaType.startsWith("text/") ||
|
|
1223
|
+
mediaType.endsWith("+json") ||
|
|
1224
|
+
mediaType.endsWith("+xml") ||
|
|
1225
|
+
[
|
|
1226
|
+
"application/json",
|
|
1227
|
+
"application/xml",
|
|
1228
|
+
"application/graphql",
|
|
1229
|
+
"application/javascript",
|
|
1230
|
+
"application/x-www-form-urlencoded",
|
|
1231
|
+
].includes(mediaType));
|
|
1232
|
+
}
|
|
1233
|
+
function bodyFromBytes(bytes, totalBytes, contentType, options) {
|
|
1234
|
+
const binary = !isTextContentType(contentType);
|
|
1235
|
+
if (binary && options.captureBinaryBodies !== true)
|
|
1236
|
+
return undefined;
|
|
1237
|
+
const maximum = maximumBodyBytes(options);
|
|
1238
|
+
if (maximum <= 0)
|
|
1239
|
+
return undefined;
|
|
1240
|
+
const captured = binary
|
|
1241
|
+
? bytes.slice(0, maximum)
|
|
1242
|
+
: truncateUtf8(bytes, maximum);
|
|
1243
|
+
return {
|
|
1244
|
+
contentType,
|
|
1245
|
+
encoding: binary ? "base64" : "utf8",
|
|
1246
|
+
data: binary ? bytesToBase64$1(captured) : new TextDecoder().decode(captured),
|
|
1247
|
+
capturedBytes: captured.length,
|
|
1248
|
+
totalBytes,
|
|
1249
|
+
truncated: bytes.length > captured.length ||
|
|
1250
|
+
(totalBytes != null && totalBytes > captured.length),
|
|
1251
|
+
};
|
|
1252
|
+
}
|
|
1253
|
+
function bodyFromValue(value, headers, options) {
|
|
1254
|
+
if (value == null || options.captureRequestBody === false)
|
|
1255
|
+
return undefined;
|
|
1256
|
+
const contentType = headerValue(headers, "content-type");
|
|
1257
|
+
if (typeof value === "string" || value instanceof URLSearchParams) {
|
|
1258
|
+
const bytes = new TextEncoder().encode(String(value));
|
|
1259
|
+
return bodyFromBytes(bytes, bytes.length, contentType ||
|
|
1260
|
+
(value instanceof URLSearchParams
|
|
1261
|
+
? "application/x-www-form-urlencoded"
|
|
1262
|
+
: undefined), options);
|
|
1263
|
+
}
|
|
1264
|
+
if (value instanceof ArrayBuffer) {
|
|
1265
|
+
const bytes = new Uint8Array(value);
|
|
1266
|
+
return bodyFromBytes(bytes, bytes.length, contentType, options);
|
|
1267
|
+
}
|
|
1268
|
+
if (ArrayBuffer.isView(value)) {
|
|
1269
|
+
const bytes = new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
|
|
1270
|
+
return bodyFromBytes(bytes, bytes.length, contentType, options);
|
|
1271
|
+
}
|
|
1272
|
+
return undefined;
|
|
1273
|
+
}
|
|
1274
|
+
async function bodyFromFetchResponse(response, headers, options, shouldContinue = () => true) {
|
|
1275
|
+
if (!shouldContinue() || options.captureResponseBody === false)
|
|
1276
|
+
return undefined;
|
|
1277
|
+
const contentType = headerValue(headers, "content-type");
|
|
1278
|
+
if (!isTextContentType(contentType) && options.captureBinaryBodies !== true) {
|
|
1279
|
+
return undefined;
|
|
1280
|
+
}
|
|
1281
|
+
const totalBytes = parseContentLength(headers);
|
|
1282
|
+
const maximum = maximumBodyBytes(options);
|
|
1283
|
+
if (maximum <= 0)
|
|
1284
|
+
return undefined;
|
|
1285
|
+
const clone = response.clone();
|
|
1286
|
+
if (clone.body) {
|
|
1287
|
+
const reader = clone.body.getReader();
|
|
1288
|
+
const chunks = [];
|
|
1289
|
+
let capturedLength = 0;
|
|
1290
|
+
let observedLength = 0;
|
|
1291
|
+
try {
|
|
1292
|
+
while (capturedLength <= maximum) {
|
|
1293
|
+
if (!shouldContinue()) {
|
|
1294
|
+
await reader.cancel().catch(() => undefined);
|
|
1295
|
+
return undefined;
|
|
1296
|
+
}
|
|
1297
|
+
const result = await reader.read();
|
|
1298
|
+
if (!shouldContinue()) {
|
|
1299
|
+
await reader.cancel().catch(() => undefined);
|
|
1300
|
+
return undefined;
|
|
1301
|
+
}
|
|
1302
|
+
if (result.done)
|
|
1303
|
+
break;
|
|
1304
|
+
const chunk = result.value;
|
|
1305
|
+
observedLength += chunk.length;
|
|
1306
|
+
const remaining = maximum - capturedLength;
|
|
1307
|
+
if (remaining > 0) {
|
|
1308
|
+
const kept = chunk.slice(0, remaining);
|
|
1309
|
+
chunks.push(kept);
|
|
1310
|
+
capturedLength += kept.length;
|
|
1311
|
+
}
|
|
1312
|
+
if (observedLength > maximum) {
|
|
1313
|
+
await reader.cancel().catch(() => undefined);
|
|
1314
|
+
break;
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
finally {
|
|
1319
|
+
reader.releaseLock();
|
|
1320
|
+
}
|
|
1321
|
+
const joined = new Uint8Array(capturedLength);
|
|
1322
|
+
let offset = 0;
|
|
1323
|
+
for (const chunk of chunks) {
|
|
1324
|
+
joined.set(chunk, offset);
|
|
1325
|
+
offset += chunk.length;
|
|
1326
|
+
}
|
|
1327
|
+
return bodyFromBytes(joined, totalBytes ?? observedLength, contentType, options);
|
|
1328
|
+
}
|
|
1329
|
+
if (totalBytes == null || totalBytes > maximum)
|
|
1330
|
+
return undefined;
|
|
1331
|
+
const bytes = new Uint8Array(await clone.arrayBuffer());
|
|
1332
|
+
if (!shouldContinue())
|
|
1333
|
+
return undefined;
|
|
1334
|
+
return bodyFromBytes(bytes, totalBytes, contentType, options);
|
|
1335
|
+
}
|
|
1336
|
+
function parseXhrResponseHeaders(value) {
|
|
1337
|
+
return value
|
|
1338
|
+
.trim()
|
|
1339
|
+
.split(/[\r\n]+/)
|
|
1340
|
+
.flatMap((line) => {
|
|
1341
|
+
const separator = line.indexOf(":");
|
|
1342
|
+
return separator < 0
|
|
1343
|
+
? []
|
|
1344
|
+
: [
|
|
1345
|
+
{
|
|
1346
|
+
name: line.slice(0, separator),
|
|
1347
|
+
value: line.slice(separator + 1),
|
|
1348
|
+
},
|
|
1349
|
+
];
|
|
1350
|
+
});
|
|
1351
|
+
}
|
|
1352
|
+
function monotonicNow(globalObject) {
|
|
1353
|
+
return typeof globalObject.performance?.now === "function"
|
|
1354
|
+
? globalObject.performance.now()
|
|
1355
|
+
: Date.now();
|
|
1356
|
+
}
|
|
1357
|
+
function installBrowserNetworkCapture(capture, options = {}, sourcePrefix = "capacitor", globalObject = globalThis) {
|
|
1358
|
+
const cleanups = [];
|
|
1359
|
+
let active = true;
|
|
1360
|
+
let fetchInvocationDepth = 0;
|
|
1361
|
+
if (options.captureFetch !== false &&
|
|
1362
|
+
typeof globalObject.fetch === "function") {
|
|
1363
|
+
const originalFetch = globalObject.fetch;
|
|
1364
|
+
const wrappedFetch = function (input, init) {
|
|
1365
|
+
const startedAtUtc = new Date().toISOString();
|
|
1366
|
+
const started = monotonicNow(globalObject);
|
|
1367
|
+
const inputRequest = typeof input === "object" && "headers" in input && "method" in input
|
|
1368
|
+
? input
|
|
1369
|
+
: undefined;
|
|
1370
|
+
const requestHeaders = headerEntries(inputRequest?.headers).concat(headerEntries(init?.headers));
|
|
1371
|
+
const requestBody = bodyFromValue(init?.body, requestHeaders, options);
|
|
1372
|
+
const method = init?.method || inputRequest?.method || "GET";
|
|
1373
|
+
const url = typeof input === "string" ? input : inputRequest?.url || String(input);
|
|
1374
|
+
let promise;
|
|
1375
|
+
fetchInvocationDepth += 1;
|
|
1376
|
+
try {
|
|
1377
|
+
promise = originalFetch(input, init);
|
|
1378
|
+
}
|
|
1379
|
+
catch (error) {
|
|
1380
|
+
fetchInvocationDepth -= 1;
|
|
1381
|
+
const request = sanitizeNetworkRequest({
|
|
1382
|
+
source: `${sourcePrefix}.fetch`,
|
|
1383
|
+
startedAtUtc,
|
|
1384
|
+
completedAtUtc: new Date().toISOString(),
|
|
1385
|
+
durationMilliseconds: monotonicNow(globalObject) - started,
|
|
1386
|
+
method,
|
|
1387
|
+
url,
|
|
1388
|
+
requestHeaders: sanitizeHeaders(requestHeaders, {}),
|
|
1389
|
+
requestBodySizeBytes: parseContentLength(requestHeaders) ?? requestBody?.totalBytes,
|
|
1390
|
+
requestBody,
|
|
1391
|
+
errorType: error instanceof Error ? error.name : "Error",
|
|
1392
|
+
errorMessage: error instanceof Error ? error.message : String(error),
|
|
1393
|
+
}, options, globalObject);
|
|
1394
|
+
if (active && request)
|
|
1395
|
+
Promise.resolve(capture(request)).catch(() => undefined);
|
|
1396
|
+
throw error;
|
|
1397
|
+
}
|
|
1398
|
+
fetchInvocationDepth -= 1;
|
|
1399
|
+
return promise.then((response) => {
|
|
1400
|
+
if (!active)
|
|
1401
|
+
return response;
|
|
1402
|
+
const responseHeaders = headerEntries(response.headers);
|
|
1403
|
+
const responseRecord = {
|
|
1404
|
+
source: `${sourcePrefix}.fetch`,
|
|
1405
|
+
startedAtUtc,
|
|
1406
|
+
completedAtUtc: new Date().toISOString(),
|
|
1407
|
+
durationMilliseconds: monotonicNow(globalObject) - started,
|
|
1408
|
+
method,
|
|
1409
|
+
url: response.url || url,
|
|
1410
|
+
requestHeaders: sanitizeHeaders(requestHeaders, {}),
|
|
1411
|
+
requestBodySizeBytes: parseContentLength(requestHeaders) ?? requestBody?.totalBytes,
|
|
1412
|
+
requestBody,
|
|
1413
|
+
statusCode: response.status,
|
|
1414
|
+
reasonPhrase: response.statusText,
|
|
1415
|
+
responseHeaders: sanitizeHeaders(responseHeaders, {}),
|
|
1416
|
+
responseBodySizeBytes: parseContentLength(responseHeaders),
|
|
1417
|
+
};
|
|
1418
|
+
return bodyFromFetchResponse(response, responseHeaders, options, () => active).then((responseBody) => {
|
|
1419
|
+
const request = sanitizeNetworkRequest({
|
|
1420
|
+
...responseRecord,
|
|
1421
|
+
responseBody,
|
|
1422
|
+
responseBodySizeBytes: responseRecord.responseBodySizeBytes ??
|
|
1423
|
+
responseBody?.totalBytes,
|
|
1424
|
+
}, options, globalObject);
|
|
1425
|
+
if (active && request)
|
|
1426
|
+
void Promise.resolve(capture(request)).catch(() => undefined);
|
|
1427
|
+
return response;
|
|
1428
|
+
}, () => {
|
|
1429
|
+
const request = sanitizeNetworkRequest(responseRecord, options, globalObject);
|
|
1430
|
+
if (active && request)
|
|
1431
|
+
void Promise.resolve(capture(request)).catch(() => undefined);
|
|
1432
|
+
return response;
|
|
1433
|
+
});
|
|
1434
|
+
}, (error) => {
|
|
1435
|
+
const request = sanitizeNetworkRequest({
|
|
1436
|
+
source: `${sourcePrefix}.fetch`,
|
|
1437
|
+
startedAtUtc,
|
|
1438
|
+
completedAtUtc: new Date().toISOString(),
|
|
1439
|
+
durationMilliseconds: monotonicNow(globalObject) - started,
|
|
1440
|
+
method,
|
|
1441
|
+
url,
|
|
1442
|
+
requestHeaders: sanitizeHeaders(requestHeaders, {}),
|
|
1443
|
+
requestBodySizeBytes: parseContentLength(requestHeaders) ?? requestBody?.totalBytes,
|
|
1444
|
+
requestBody,
|
|
1445
|
+
errorType: error instanceof Error ? error.name : "Error",
|
|
1446
|
+
errorMessage: error instanceof Error ? error.message : String(error),
|
|
1447
|
+
}, options, globalObject);
|
|
1448
|
+
if (active && request)
|
|
1449
|
+
Promise.resolve(capture(request)).catch(() => undefined);
|
|
1450
|
+
throw error;
|
|
1451
|
+
});
|
|
1452
|
+
};
|
|
1453
|
+
globalObject.fetch = wrappedFetch;
|
|
1454
|
+
cleanups.push(() => {
|
|
1455
|
+
if (globalObject.fetch === wrappedFetch)
|
|
1456
|
+
globalObject.fetch = originalFetch;
|
|
1457
|
+
});
|
|
1458
|
+
}
|
|
1459
|
+
const Xhr = globalObject.XMLHttpRequest;
|
|
1460
|
+
if (options.captureXmlHttpRequest !== false && Xhr?.prototype) {
|
|
1461
|
+
const states = new WeakMap();
|
|
1462
|
+
const prototype = Xhr.prototype;
|
|
1463
|
+
const originalOpen = prototype.open;
|
|
1464
|
+
const originalSend = prototype.send;
|
|
1465
|
+
const originalSetRequestHeader = prototype.setRequestHeader;
|
|
1466
|
+
const wrappedOpen = function (method, url, ...rest) {
|
|
1467
|
+
states.set(this, {
|
|
1468
|
+
method,
|
|
1469
|
+
url: String(url),
|
|
1470
|
+
requestHeaders: [],
|
|
1471
|
+
suppressed: fetchInvocationDepth > 0,
|
|
1472
|
+
});
|
|
1473
|
+
Reflect.apply(originalOpen, this, [method, url, ...rest]);
|
|
1474
|
+
};
|
|
1475
|
+
const wrappedSetRequestHeader = function (name, value) {
|
|
1476
|
+
states.get(this)?.requestHeaders.push({ name, value });
|
|
1477
|
+
Reflect.apply(originalSetRequestHeader, this, [name, value]);
|
|
1478
|
+
};
|
|
1479
|
+
const wrappedSend = function (body) {
|
|
1480
|
+
const state = states.get(this);
|
|
1481
|
+
if (!state || state.suppressed) {
|
|
1482
|
+
Reflect.apply(originalSend, this, [body]);
|
|
1483
|
+
return;
|
|
1484
|
+
}
|
|
1485
|
+
state.startedAtUtc = new Date().toISOString();
|
|
1486
|
+
state.started = monotonicNow(globalObject);
|
|
1487
|
+
state.requestBody = bodyFromValue(body, state.requestHeaders, options);
|
|
1488
|
+
let failure;
|
|
1489
|
+
const markFailure = (event) => {
|
|
1490
|
+
failure = event.type;
|
|
1491
|
+
};
|
|
1492
|
+
const complete = () => {
|
|
1493
|
+
if (!active)
|
|
1494
|
+
return;
|
|
1495
|
+
let responseHeaders = [];
|
|
1496
|
+
try {
|
|
1497
|
+
responseHeaders = parseXhrResponseHeaders(this.getAllResponseHeaders());
|
|
1498
|
+
}
|
|
1499
|
+
catch {
|
|
1500
|
+
// Some WebViews throw before response headers exist.
|
|
1501
|
+
}
|
|
1502
|
+
let responseBody;
|
|
1503
|
+
try {
|
|
1504
|
+
const responseType = this.responseType || "text";
|
|
1505
|
+
const responseOptions = {
|
|
1506
|
+
...options,
|
|
1507
|
+
captureRequestBody: options.captureResponseBody,
|
|
1508
|
+
};
|
|
1509
|
+
if (responseType === "text") {
|
|
1510
|
+
responseBody = bodyFromValue(this.responseText, responseHeaders, responseOptions);
|
|
1511
|
+
}
|
|
1512
|
+
else if (responseType === "arraybuffer") {
|
|
1513
|
+
responseBody = bodyFromValue(this.response, responseHeaders, responseOptions);
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
catch {
|
|
1517
|
+
// Response data is not readable for every XHR response type.
|
|
1518
|
+
}
|
|
1519
|
+
const request = sanitizeNetworkRequest({
|
|
1520
|
+
source: `${sourcePrefix}.xhr`,
|
|
1521
|
+
startedAtUtc: state.startedAtUtc,
|
|
1522
|
+
completedAtUtc: new Date().toISOString(),
|
|
1523
|
+
durationMilliseconds: monotonicNow(globalObject) - (state.started ?? 0),
|
|
1524
|
+
method: state.method,
|
|
1525
|
+
url: this.responseURL || state.url,
|
|
1526
|
+
requestHeaders: state.requestHeaders,
|
|
1527
|
+
requestBodySizeBytes: parseContentLength(state.requestHeaders) ??
|
|
1528
|
+
state.requestBody?.totalBytes,
|
|
1529
|
+
requestBody: state.requestBody,
|
|
1530
|
+
statusCode: this.status || undefined,
|
|
1531
|
+
reasonPhrase: this.statusText,
|
|
1532
|
+
responseHeaders,
|
|
1533
|
+
responseBodySizeBytes: parseContentLength(responseHeaders) ?? responseBody?.totalBytes,
|
|
1534
|
+
responseBody,
|
|
1535
|
+
errorType: failure,
|
|
1536
|
+
errorMessage: failure ? `XMLHttpRequest ${failure}` : undefined,
|
|
1537
|
+
}, options, globalObject);
|
|
1538
|
+
if (request)
|
|
1539
|
+
Promise.resolve(capture(request)).catch(() => undefined);
|
|
1540
|
+
};
|
|
1541
|
+
this.addEventListener("error", markFailure);
|
|
1542
|
+
this.addEventListener("abort", markFailure);
|
|
1543
|
+
this.addEventListener("timeout", markFailure);
|
|
1544
|
+
this.addEventListener("loadend", complete, { once: true });
|
|
1545
|
+
Reflect.apply(originalSend, this, [body]);
|
|
1546
|
+
};
|
|
1547
|
+
prototype.open = wrappedOpen;
|
|
1548
|
+
prototype.setRequestHeader = wrappedSetRequestHeader;
|
|
1549
|
+
prototype.send = wrappedSend;
|
|
1550
|
+
cleanups.push(() => {
|
|
1551
|
+
if (prototype.open === wrappedOpen)
|
|
1552
|
+
prototype.open = originalOpen;
|
|
1553
|
+
if (prototype.send === wrappedSend)
|
|
1554
|
+
prototype.send = originalSend;
|
|
1555
|
+
if (prototype.setRequestHeader === wrappedSetRequestHeader) {
|
|
1556
|
+
prototype.setRequestHeader = originalSetRequestHeader;
|
|
1557
|
+
}
|
|
1558
|
+
});
|
|
1559
|
+
}
|
|
1560
|
+
let removed = false;
|
|
1561
|
+
return {
|
|
1562
|
+
remove() {
|
|
1563
|
+
if (removed)
|
|
1564
|
+
return;
|
|
1565
|
+
removed = true;
|
|
1566
|
+
active = false;
|
|
1567
|
+
for (const cleanup of cleanups.reverse())
|
|
1568
|
+
cleanup();
|
|
1569
|
+
},
|
|
1570
|
+
};
|
|
1571
|
+
}
|
|
1572
|
+
|
|
1573
|
+
const ANSIGHT_CAPACITOR_SDK_VERSION = "1.3.0-preview.12";
|
|
1574
|
+
const COMPILED_CAPACITOR_CORE_VERSION = "8.4.2";
|
|
1575
|
+
const CAPACITOR_GROUP = "capacitor";
|
|
1576
|
+
const LOCALIZATION_GROUP = "localization";
|
|
1577
|
+
function normalized(value) {
|
|
1578
|
+
if (value == null)
|
|
1579
|
+
return undefined;
|
|
1580
|
+
const result = String(value).trim();
|
|
1581
|
+
return result || undefined;
|
|
1582
|
+
}
|
|
1583
|
+
function canonicalizeLocale(value) {
|
|
1584
|
+
const locale = normalized(value)?.replace(/_/g, "-");
|
|
1585
|
+
if (!locale)
|
|
1586
|
+
return undefined;
|
|
1587
|
+
try {
|
|
1588
|
+
return Intl.getCanonicalLocales(locale)[0] ?? locale;
|
|
1589
|
+
}
|
|
1590
|
+
catch {
|
|
1591
|
+
return locale;
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
function parseLocale(locale) {
|
|
1595
|
+
const parts = (locale ?? "").split("-").filter(Boolean);
|
|
1596
|
+
const language = parts[0]?.toLowerCase();
|
|
1597
|
+
const region = parts.find((part, index) => index > 0 && (/^[A-Za-z]{2}$/.test(part) || /^\d{3}$/.test(part)));
|
|
1598
|
+
return { language, region: region?.toUpperCase() };
|
|
1599
|
+
}
|
|
1600
|
+
function webViewDetails(platform, nativePlatform, userAgent) {
|
|
1601
|
+
const agent = userAgent ?? "";
|
|
1602
|
+
if (nativePlatform && platform === "ios") {
|
|
1603
|
+
return {
|
|
1604
|
+
engine: "wkWebView",
|
|
1605
|
+
version: /AppleWebKit\/([^\s]+)/.exec(agent)?.[1],
|
|
1606
|
+
};
|
|
1607
|
+
}
|
|
1608
|
+
if (nativePlatform && platform === "android") {
|
|
1609
|
+
return {
|
|
1610
|
+
engine: "chromiumWebView",
|
|
1611
|
+
version: /(?:Chrome|Chromium)\/([^\s]+)/.exec(agent)?.[1],
|
|
1612
|
+
};
|
|
1613
|
+
}
|
|
1614
|
+
if (/Firefox\/([^\s]+)/.test(agent)) {
|
|
1615
|
+
return { engine: "gecko", version: /Firefox\/([^\s]+)/.exec(agent)?.[1] };
|
|
1616
|
+
}
|
|
1617
|
+
if (/(?:Chrome|Chromium)\/([^\s]+)/.test(agent)) {
|
|
1618
|
+
return {
|
|
1619
|
+
engine: "chromium",
|
|
1620
|
+
version: /(?:Chrome|Chromium)\/([^\s]+)/.exec(agent)?.[1],
|
|
1621
|
+
};
|
|
1622
|
+
}
|
|
1623
|
+
if (/AppleWebKit\/([^\s]+)/.test(agent)) {
|
|
1624
|
+
return {
|
|
1625
|
+
engine: "webkit",
|
|
1626
|
+
version: /AppleWebKit\/([^\s]+)/.exec(agent)?.[1],
|
|
1627
|
+
};
|
|
1628
|
+
}
|
|
1629
|
+
return { engine: "unknown" };
|
|
1630
|
+
}
|
|
1631
|
+
function currentCapacitorSessionEnvironment(platform, nativePlatform) {
|
|
1632
|
+
let resolved;
|
|
1633
|
+
try {
|
|
1634
|
+
resolved = Intl.DateTimeFormat().resolvedOptions();
|
|
1635
|
+
}
|
|
1636
|
+
catch {
|
|
1637
|
+
resolved = undefined;
|
|
1638
|
+
}
|
|
1639
|
+
return {
|
|
1640
|
+
platform,
|
|
1641
|
+
nativePlatform,
|
|
1642
|
+
userAgent: typeof navigator === "undefined" ? undefined : navigator.userAgent,
|
|
1643
|
+
locale: resolved?.locale ??
|
|
1644
|
+
(typeof navigator === "undefined" ? undefined : navigator.language),
|
|
1645
|
+
timeZone: resolved?.timeZone,
|
|
1646
|
+
utcOffsetMinutes: -new Date().getTimezoneOffset(),
|
|
1647
|
+
};
|
|
1648
|
+
}
|
|
1649
|
+
function createAutomaticSessionProperties(environment) {
|
|
1650
|
+
const platform = normalized(environment.platform) ?? "unknown";
|
|
1651
|
+
const userAgent = normalized(environment.userAgent);
|
|
1652
|
+
const webView = webViewDetails(platform, environment.nativePlatform, userAgent);
|
|
1653
|
+
const locale = canonicalizeLocale(environment.locale);
|
|
1654
|
+
const parsedLocale = parseLocale(locale);
|
|
1655
|
+
const capacitor = {
|
|
1656
|
+
sdkVersion: ANSIGHT_CAPACITOR_SDK_VERSION,
|
|
1657
|
+
capacitorVersion: "8.x",
|
|
1658
|
+
compiledCapacitorVersion: COMPILED_CAPACITOR_CORE_VERSION,
|
|
1659
|
+
platform,
|
|
1660
|
+
runtimeLanguage: "javascript",
|
|
1661
|
+
executionMode: environment.nativePlatform ? "native" : "web",
|
|
1662
|
+
webViewEngine: webView.engine,
|
|
1663
|
+
};
|
|
1664
|
+
if (webView.version)
|
|
1665
|
+
capacitor.webViewEngineVersion = webView.version;
|
|
1666
|
+
if (userAgent)
|
|
1667
|
+
capacitor.userAgent = userAgent;
|
|
1668
|
+
const localization = {
|
|
1669
|
+
utcOffsetMinutes: String(environment.utcOffsetMinutes ?? -new Date().getTimezoneOffset()),
|
|
1670
|
+
};
|
|
1671
|
+
if (locale)
|
|
1672
|
+
localization.locale = locale;
|
|
1673
|
+
if (parsedLocale.language)
|
|
1674
|
+
localization.language = parsedLocale.language;
|
|
1675
|
+
if (parsedLocale.region)
|
|
1676
|
+
localization.region = parsedLocale.region;
|
|
1677
|
+
if (normalized(environment.timeZone)) {
|
|
1678
|
+
localization.timeZone = String(environment.timeZone).trim();
|
|
1679
|
+
}
|
|
1680
|
+
return {
|
|
1681
|
+
[CAPACITOR_GROUP]: capacitor,
|
|
1682
|
+
[LOCALIZATION_GROUP]: localization,
|
|
1683
|
+
};
|
|
1684
|
+
}
|
|
1685
|
+
function mergeSessionProperties(automaticProperties, customProperties) {
|
|
1686
|
+
const merged = Object.fromEntries(Object.entries(automaticProperties).map(([group, properties]) => [
|
|
1687
|
+
group,
|
|
1688
|
+
{ ...properties },
|
|
1689
|
+
]));
|
|
1690
|
+
for (const [group, properties] of Object.entries(customProperties ?? {})) {
|
|
1691
|
+
merged[group] = { ...(merged[group] ?? {}), ...properties };
|
|
1692
|
+
}
|
|
1693
|
+
return merged;
|
|
1694
|
+
}
|
|
1695
|
+
|
|
732
1696
|
const AnsightNative = core.registerPlugin("Ansight");
|
|
733
1697
|
const toolHandlers = new Map();
|
|
734
1698
|
const artifactProviders = new Map();
|
|
@@ -739,6 +1703,9 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
739
1703
|
let lifecycleCleanup;
|
|
740
1704
|
let artifactToolRegistrations = [];
|
|
741
1705
|
let domToolRegistration;
|
|
1706
|
+
let networkCaptureSubscription;
|
|
1707
|
+
let networkCaptureRegistration;
|
|
1708
|
+
let networkConnectionListener;
|
|
742
1709
|
function normalizePairingPayload(payload) {
|
|
743
1710
|
if (payload == null)
|
|
744
1711
|
return payload;
|
|
@@ -746,11 +1713,19 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
746
1713
|
}
|
|
747
1714
|
function normalizeOptions(input) {
|
|
748
1715
|
const options = JSON.parse(JSON.stringify(input));
|
|
1716
|
+
options.customProperties = mergeSessionProperties(automaticSessionProperties(), options.customProperties);
|
|
749
1717
|
delete options.domTools;
|
|
750
1718
|
delete options.errorCapture;
|
|
751
1719
|
delete options.lifecycle;
|
|
1720
|
+
delete options.networkCapture;
|
|
752
1721
|
return options;
|
|
753
1722
|
}
|
|
1723
|
+
function automaticSessionProperties() {
|
|
1724
|
+
return createAutomaticSessionProperties(currentCapacitorSessionEnvironment(core.Capacitor.getPlatform(), core.Capacitor.isNativePlatform()));
|
|
1725
|
+
}
|
|
1726
|
+
function automaticSessionPropertyValue(group, key) {
|
|
1727
|
+
return automaticSessionProperties()[group]?.[key];
|
|
1728
|
+
}
|
|
754
1729
|
function normalizeToolResult(value) {
|
|
755
1730
|
if (value && typeof value === "object" && "success" in value) {
|
|
756
1731
|
return value;
|
|
@@ -800,11 +1775,13 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
800
1775
|
}
|
|
801
1776
|
async function afterConnectionChange(operation) {
|
|
802
1777
|
const result = await operation();
|
|
1778
|
+
await refreshNetworkCaptureConnection();
|
|
803
1779
|
await emitHostConnectionStatus();
|
|
804
1780
|
return result;
|
|
805
1781
|
}
|
|
806
1782
|
async function initialize(options = {}) {
|
|
807
1783
|
const result = await AnsightNative.initialize(normalizeOptions(options));
|
|
1784
|
+
await configureNetworkCapture(options.networkCapture);
|
|
808
1785
|
if (options.lifecycle !== false)
|
|
809
1786
|
startLifecycleTracking();
|
|
810
1787
|
if (options.errorCapture) {
|
|
@@ -818,6 +1795,7 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
818
1795
|
}
|
|
819
1796
|
async function initializeAndActivate(options = {}) {
|
|
820
1797
|
const result = await AnsightNative.initializeAndActivate(normalizeOptions(options));
|
|
1798
|
+
await configureNetworkCapture(options.networkCapture);
|
|
821
1799
|
if (options.lifecycle !== false)
|
|
822
1800
|
startLifecycleTracking();
|
|
823
1801
|
if (options.errorCapture) {
|
|
@@ -842,6 +1820,80 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
842
1820
|
return AnsightNative.recordEvent(typeof input === "string" ? { label: input } : input);
|
|
843
1821
|
}
|
|
844
1822
|
const recordEvent = event;
|
|
1823
|
+
async function recordNetworkRequest(input, sanitizationOptions = {}) {
|
|
1824
|
+
const request = sanitizeNetworkRequest(input, sanitizationOptions);
|
|
1825
|
+
if (!request) {
|
|
1826
|
+
return {
|
|
1827
|
+
success: false,
|
|
1828
|
+
message: "Network request capture was suppressed by the sanitizer.",
|
|
1829
|
+
};
|
|
1830
|
+
}
|
|
1831
|
+
return AnsightNative.recordNetworkRequest(request);
|
|
1832
|
+
}
|
|
1833
|
+
function installNetworkCapture(options = {}) {
|
|
1834
|
+
uninstallNetworkCapture();
|
|
1835
|
+
const registration = { options };
|
|
1836
|
+
networkCaptureRegistration = registration;
|
|
1837
|
+
ensureNetworkConnectionListener();
|
|
1838
|
+
void refreshNetworkCaptureConnection();
|
|
1839
|
+
return {
|
|
1840
|
+
remove() {
|
|
1841
|
+
if (networkCaptureRegistration === registration) {
|
|
1842
|
+
uninstallNetworkCapture();
|
|
1843
|
+
}
|
|
1844
|
+
},
|
|
1845
|
+
};
|
|
1846
|
+
}
|
|
1847
|
+
function uninstallNetworkCapture() {
|
|
1848
|
+
networkCaptureRegistration = undefined;
|
|
1849
|
+
const listener = networkConnectionListener;
|
|
1850
|
+
networkConnectionListener = undefined;
|
|
1851
|
+
if (listener)
|
|
1852
|
+
void listener.then((value) => value.remove());
|
|
1853
|
+
detachNetworkCapture();
|
|
1854
|
+
}
|
|
1855
|
+
function detachNetworkCapture() {
|
|
1856
|
+
networkCaptureSubscription?.remove();
|
|
1857
|
+
networkCaptureSubscription = undefined;
|
|
1858
|
+
}
|
|
1859
|
+
async function refreshNetworkCaptureConnection() {
|
|
1860
|
+
const registration = networkCaptureRegistration;
|
|
1861
|
+
if (!registration) {
|
|
1862
|
+
detachNetworkCapture();
|
|
1863
|
+
return;
|
|
1864
|
+
}
|
|
1865
|
+
try {
|
|
1866
|
+
const status = await AnsightNative.hostConnectionStatus();
|
|
1867
|
+
if (networkCaptureRegistration !== registration)
|
|
1868
|
+
return;
|
|
1869
|
+
applyNetworkConnectionStatus(status);
|
|
1870
|
+
}
|
|
1871
|
+
catch {
|
|
1872
|
+
if (networkCaptureRegistration === registration)
|
|
1873
|
+
detachNetworkCapture();
|
|
1874
|
+
}
|
|
1875
|
+
}
|
|
1876
|
+
function ensureNetworkConnectionListener() {
|
|
1877
|
+
networkConnectionListener ??= AnsightNative.addListener("ansightHostConnectionStatus", applyNetworkConnectionStatus);
|
|
1878
|
+
}
|
|
1879
|
+
function applyNetworkConnectionStatus(status) {
|
|
1880
|
+
const registration = networkCaptureRegistration;
|
|
1881
|
+
if (!registration || status.isConnected !== true) {
|
|
1882
|
+
detachNetworkCapture();
|
|
1883
|
+
return;
|
|
1884
|
+
}
|
|
1885
|
+
networkCaptureSubscription ??= installBrowserNetworkCapture((request) => AnsightNative.recordNetworkRequest(request), registration.options);
|
|
1886
|
+
}
|
|
1887
|
+
async function configureNetworkCapture(value) {
|
|
1888
|
+
uninstallNetworkCapture();
|
|
1889
|
+
if (!value)
|
|
1890
|
+
return;
|
|
1891
|
+
networkCaptureRegistration = {
|
|
1892
|
+
options: typeof value === "object" ? value : {},
|
|
1893
|
+
};
|
|
1894
|
+
ensureNetworkConnectionListener();
|
|
1895
|
+
await refreshNetworkCaptureConnection();
|
|
1896
|
+
}
|
|
845
1897
|
const recordCrashCandidate = (input) => AnsightNative.recordCrashCandidate(input);
|
|
846
1898
|
const screenViewed = (name, details = {}) => AnsightNative.screenViewed({ name, details });
|
|
847
1899
|
const trackRoute = screenViewed;
|
|
@@ -897,12 +1949,25 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
897
1949
|
const captureScreenFrame = (options = {}) => AnsightNative.captureScreenFrame(options);
|
|
898
1950
|
const enableTouchCapture = () => AnsightNative.enableTouchCapture();
|
|
899
1951
|
const disableTouchCapture = () => AnsightNative.disableTouchCapture();
|
|
900
|
-
const updateSessionProperties = (properties) => AnsightNative.updateSessionProperties({
|
|
1952
|
+
const updateSessionProperties = (properties) => AnsightNative.updateSessionProperties({
|
|
1953
|
+
properties: mergeSessionProperties(automaticSessionProperties(), properties),
|
|
1954
|
+
});
|
|
901
1955
|
const updateCustomProperties = updateSessionProperties;
|
|
902
|
-
const clearSessionProperties = () => AnsightNative.
|
|
1956
|
+
const clearSessionProperties = () => AnsightNative.updateSessionProperties({
|
|
1957
|
+
properties: automaticSessionProperties(),
|
|
1958
|
+
});
|
|
903
1959
|
const clearCustomProperties = clearSessionProperties;
|
|
904
1960
|
const registerCustomProperty = (group, key, value) => AnsightNative.registerCustomProperty({ group, key, value });
|
|
905
|
-
const removeCustomProperty = (group, key) =>
|
|
1961
|
+
const removeCustomProperty = (group, key) => {
|
|
1962
|
+
const automaticValue = automaticSessionPropertyValue(group, key);
|
|
1963
|
+
return automaticValue == null
|
|
1964
|
+
? AnsightNative.removeCustomProperty({ group, key })
|
|
1965
|
+
: AnsightNative.registerCustomProperty({
|
|
1966
|
+
group,
|
|
1967
|
+
key,
|
|
1968
|
+
value: automaticValue,
|
|
1969
|
+
});
|
|
1970
|
+
};
|
|
906
1971
|
function addHostConnectionStatusListener(listener, options = {}) {
|
|
907
1972
|
hostConnectionListeners.add(listener);
|
|
908
1973
|
if (options.emitCurrent !== false)
|
|
@@ -1253,6 +2318,10 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
1253
2318
|
recordMetric,
|
|
1254
2319
|
event,
|
|
1255
2320
|
recordEvent,
|
|
2321
|
+
recordNetworkRequest,
|
|
2322
|
+
installNetworkCapture,
|
|
2323
|
+
uninstallNetworkCapture,
|
|
2324
|
+
sanitizeNetworkRequest,
|
|
1256
2325
|
screenViewed,
|
|
1257
2326
|
trackRoute,
|
|
1258
2327
|
setAppLifecycleState,
|
|
@@ -1350,6 +2419,7 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
1350
2419
|
exports.initializeAndActivate = initializeAndActivate;
|
|
1351
2420
|
exports.installDomTools = installDomTools;
|
|
1352
2421
|
exports.installErrorHandlers = installErrorHandlers;
|
|
2422
|
+
exports.installNetworkCapture = installNetworkCapture;
|
|
1353
2423
|
exports.isFramesPerSecondEnabled = isFramesPerSecondEnabled;
|
|
1354
2424
|
exports.listRegisteredArtifactProviders = listRegisteredArtifactProviders;
|
|
1355
2425
|
exports.listRegisteredTools = listRegisteredTools;
|
|
@@ -1359,6 +2429,7 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
1359
2429
|
exports.recordCrashCandidate = recordCrashCandidate;
|
|
1360
2430
|
exports.recordEvent = recordEvent;
|
|
1361
2431
|
exports.recordMetric = recordMetric;
|
|
2432
|
+
exports.recordNetworkRequest = recordNetworkRequest;
|
|
1362
2433
|
exports.recordedEvents = recordedEvents;
|
|
1363
2434
|
exports.recordedMetrics = recordedMetrics;
|
|
1364
2435
|
exports.registerArtifactProvider = registerArtifactProvider;
|
|
@@ -1367,6 +2438,7 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
1367
2438
|
exports.registerMetricChannel = registerMetricChannel;
|
|
1368
2439
|
exports.registerTool = registerTool;
|
|
1369
2440
|
exports.removeCustomProperty = removeCustomProperty;
|
|
2441
|
+
exports.sanitizeNetworkRequest = sanitizeNetworkRequest;
|
|
1370
2442
|
exports.savePairingConfig = savePairingConfig;
|
|
1371
2443
|
exports.scanPairingQrCode = scanPairingQrCode;
|
|
1372
2444
|
exports.screenViewed = screenViewed;
|
|
@@ -1380,6 +2452,7 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
1380
2452
|
exports.stopLifecycleTracking = stopLifecycleTracking;
|
|
1381
2453
|
exports.trackRoute = trackRoute;
|
|
1382
2454
|
exports.uninstallDomTools = uninstallDomTools;
|
|
2455
|
+
exports.uninstallNetworkCapture = uninstallNetworkCapture;
|
|
1383
2456
|
exports.unregisterArtifactProvider = unregisterArtifactProvider;
|
|
1384
2457
|
exports.unregisterTool = unregisterTool;
|
|
1385
2458
|
exports.updateCustomProperties = updateCustomProperties;
|