@ansight/capacitor 1.3.0-preview.10 → 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 +53 -1
- 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/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/plugin.cjs.js +1021 -3
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +1021 -3
- package/dist/plugin.js.map +1 -1
- package/dist/standalone.js +1017 -3
- 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
|
@@ -562,6 +562,50 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
562
562
|
};
|
|
563
563
|
return this;
|
|
564
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
|
+
}
|
|
565
609
|
withToolGuard(toolGuard) {
|
|
566
610
|
this.options.toolGuard = toolGuard;
|
|
567
611
|
return this;
|
|
@@ -729,6 +773,871 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
729
773
|
return new AnsightOptionsBuilder(options);
|
|
730
774
|
}
|
|
731
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
|
+
|
|
732
1641
|
const AnsightNative = core.registerPlugin("Ansight");
|
|
733
1642
|
const toolHandlers = new Map();
|
|
734
1643
|
const artifactProviders = new Map();
|
|
@@ -739,6 +1648,9 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
739
1648
|
let lifecycleCleanup;
|
|
740
1649
|
let artifactToolRegistrations = [];
|
|
741
1650
|
let domToolRegistration;
|
|
1651
|
+
let networkCaptureSubscription;
|
|
1652
|
+
let networkCaptureRegistration;
|
|
1653
|
+
let networkConnectionListener;
|
|
742
1654
|
function normalizePairingPayload(payload) {
|
|
743
1655
|
if (payload == null)
|
|
744
1656
|
return payload;
|
|
@@ -746,11 +1658,19 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
746
1658
|
}
|
|
747
1659
|
function normalizeOptions(input) {
|
|
748
1660
|
const options = JSON.parse(JSON.stringify(input));
|
|
1661
|
+
options.customProperties = mergeSessionProperties(automaticSessionProperties(), options.customProperties);
|
|
749
1662
|
delete options.domTools;
|
|
750
1663
|
delete options.errorCapture;
|
|
751
1664
|
delete options.lifecycle;
|
|
1665
|
+
delete options.networkCapture;
|
|
752
1666
|
return options;
|
|
753
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
|
+
}
|
|
754
1674
|
function normalizeToolResult(value) {
|
|
755
1675
|
if (value && typeof value === "object" && "success" in value) {
|
|
756
1676
|
return value;
|
|
@@ -800,11 +1720,13 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
800
1720
|
}
|
|
801
1721
|
async function afterConnectionChange(operation) {
|
|
802
1722
|
const result = await operation();
|
|
1723
|
+
await refreshNetworkCaptureConnection();
|
|
803
1724
|
await emitHostConnectionStatus();
|
|
804
1725
|
return result;
|
|
805
1726
|
}
|
|
806
1727
|
async function initialize(options = {}) {
|
|
807
1728
|
const result = await AnsightNative.initialize(normalizeOptions(options));
|
|
1729
|
+
await configureNetworkCapture(options.networkCapture);
|
|
808
1730
|
if (options.lifecycle !== false)
|
|
809
1731
|
startLifecycleTracking();
|
|
810
1732
|
if (options.errorCapture) {
|
|
@@ -818,6 +1740,7 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
818
1740
|
}
|
|
819
1741
|
async function initializeAndActivate(options = {}) {
|
|
820
1742
|
const result = await AnsightNative.initializeAndActivate(normalizeOptions(options));
|
|
1743
|
+
await configureNetworkCapture(options.networkCapture);
|
|
821
1744
|
if (options.lifecycle !== false)
|
|
822
1745
|
startLifecycleTracking();
|
|
823
1746
|
if (options.errorCapture) {
|
|
@@ -842,6 +1765,80 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
842
1765
|
return AnsightNative.recordEvent(typeof input === "string" ? { label: input } : input);
|
|
843
1766
|
}
|
|
844
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
|
+
}
|
|
845
1842
|
const recordCrashCandidate = (input) => AnsightNative.recordCrashCandidate(input);
|
|
846
1843
|
const screenViewed = (name, details = {}) => AnsightNative.screenViewed({ name, details });
|
|
847
1844
|
const trackRoute = screenViewed;
|
|
@@ -897,12 +1894,25 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
897
1894
|
const captureScreenFrame = (options = {}) => AnsightNative.captureScreenFrame(options);
|
|
898
1895
|
const enableTouchCapture = () => AnsightNative.enableTouchCapture();
|
|
899
1896
|
const disableTouchCapture = () => AnsightNative.disableTouchCapture();
|
|
900
|
-
const updateSessionProperties = (properties) => AnsightNative.updateSessionProperties({
|
|
1897
|
+
const updateSessionProperties = (properties) => AnsightNative.updateSessionProperties({
|
|
1898
|
+
properties: mergeSessionProperties(automaticSessionProperties(), properties),
|
|
1899
|
+
});
|
|
901
1900
|
const updateCustomProperties = updateSessionProperties;
|
|
902
|
-
const clearSessionProperties = () => AnsightNative.
|
|
1901
|
+
const clearSessionProperties = () => AnsightNative.updateSessionProperties({
|
|
1902
|
+
properties: automaticSessionProperties(),
|
|
1903
|
+
});
|
|
903
1904
|
const clearCustomProperties = clearSessionProperties;
|
|
904
1905
|
const registerCustomProperty = (group, key, value) => AnsightNative.registerCustomProperty({ group, key, value });
|
|
905
|
-
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
|
+
};
|
|
906
1916
|
function addHostConnectionStatusListener(listener, options = {}) {
|
|
907
1917
|
hostConnectionListeners.add(listener);
|
|
908
1918
|
if (options.emitCurrent !== false)
|
|
@@ -1253,6 +2263,10 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
1253
2263
|
recordMetric,
|
|
1254
2264
|
event,
|
|
1255
2265
|
recordEvent,
|
|
2266
|
+
recordNetworkRequest,
|
|
2267
|
+
installNetworkCapture,
|
|
2268
|
+
uninstallNetworkCapture,
|
|
2269
|
+
sanitizeNetworkRequest,
|
|
1256
2270
|
screenViewed,
|
|
1257
2271
|
trackRoute,
|
|
1258
2272
|
setAppLifecycleState,
|
|
@@ -1350,6 +2364,7 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
1350
2364
|
exports.initializeAndActivate = initializeAndActivate;
|
|
1351
2365
|
exports.installDomTools = installDomTools;
|
|
1352
2366
|
exports.installErrorHandlers = installErrorHandlers;
|
|
2367
|
+
exports.installNetworkCapture = installNetworkCapture;
|
|
1353
2368
|
exports.isFramesPerSecondEnabled = isFramesPerSecondEnabled;
|
|
1354
2369
|
exports.listRegisteredArtifactProviders = listRegisteredArtifactProviders;
|
|
1355
2370
|
exports.listRegisteredTools = listRegisteredTools;
|
|
@@ -1359,6 +2374,7 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
1359
2374
|
exports.recordCrashCandidate = recordCrashCandidate;
|
|
1360
2375
|
exports.recordEvent = recordEvent;
|
|
1361
2376
|
exports.recordMetric = recordMetric;
|
|
2377
|
+
exports.recordNetworkRequest = recordNetworkRequest;
|
|
1362
2378
|
exports.recordedEvents = recordedEvents;
|
|
1363
2379
|
exports.recordedMetrics = recordedMetrics;
|
|
1364
2380
|
exports.registerArtifactProvider = registerArtifactProvider;
|
|
@@ -1367,6 +2383,7 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
1367
2383
|
exports.registerMetricChannel = registerMetricChannel;
|
|
1368
2384
|
exports.registerTool = registerTool;
|
|
1369
2385
|
exports.removeCustomProperty = removeCustomProperty;
|
|
2386
|
+
exports.sanitizeNetworkRequest = sanitizeNetworkRequest;
|
|
1370
2387
|
exports.savePairingConfig = savePairingConfig;
|
|
1371
2388
|
exports.scanPairingQrCode = scanPairingQrCode;
|
|
1372
2389
|
exports.screenViewed = screenViewed;
|
|
@@ -1380,6 +2397,7 @@ var capacitorAnsight = (function (exports, core) {
|
|
|
1380
2397
|
exports.stopLifecycleTracking = stopLifecycleTracking;
|
|
1381
2398
|
exports.trackRoute = trackRoute;
|
|
1382
2399
|
exports.uninstallDomTools = uninstallDomTools;
|
|
2400
|
+
exports.uninstallNetworkCapture = uninstallNetworkCapture;
|
|
1383
2401
|
exports.unregisterArtifactProvider = unregisterArtifactProvider;
|
|
1384
2402
|
exports.unregisterTool = unregisterTool;
|
|
1385
2403
|
exports.updateCustomProperties = updateCustomProperties;
|