@ansight/capacitor 1.3.0-preview.9 → 1.4.0-preview.3
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 +116 -29
- package/android/build.gradle +2 -2
- package/android/src/main/kotlin/ai/ansight/capacitor/AnsightCapacitorPlugin.kt +75 -22
- package/dist/esm/definitions.d.ts +74 -10
- 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 +73 -23
- 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 +113 -5
- 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 +1096 -28
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +1096 -28
- package/dist/plugin.js.map +1 -1
- package/dist/standalone.js +1099 -31
- package/dist/standalone.js.map +1 -1
- package/ios/Sources/AnsightCapacitorPlugin/AnsightCapacitorPlugin.swift +77 -22
- package/package.json +1 -1
package/dist/standalone.js
CHANGED
|
@@ -700,6 +700,19 @@
|
|
|
700
700
|
element.id ??
|
|
701
701
|
undefined)?.trim() || undefined);
|
|
702
702
|
}
|
|
703
|
+
const tapRoles = new Set([
|
|
704
|
+
"button",
|
|
705
|
+
"checkbox",
|
|
706
|
+
"combobox",
|
|
707
|
+
"link",
|
|
708
|
+
"menuitem",
|
|
709
|
+
"menuitemcheckbox",
|
|
710
|
+
"menuitemradio",
|
|
711
|
+
"option",
|
|
712
|
+
"radio",
|
|
713
|
+
"switch",
|
|
714
|
+
"tab",
|
|
715
|
+
]);
|
|
703
716
|
function semanticRole(element) {
|
|
704
717
|
const declared = element.getAttribute("role")?.trim().toLowerCase();
|
|
705
718
|
if (declared)
|
|
@@ -731,24 +744,54 @@
|
|
|
731
744
|
if (!allowActions)
|
|
732
745
|
return [];
|
|
733
746
|
const actions = [];
|
|
747
|
+
const htmlElement = element;
|
|
748
|
+
const role = semanticRole(element);
|
|
734
749
|
if (["A", "BUTTON", "SUMMARY"].includes(element.tagName) ||
|
|
735
|
-
element instanceof HTMLInputElement
|
|
750
|
+
element instanceof HTMLInputElement ||
|
|
751
|
+
tapRoles.has(role) ||
|
|
752
|
+
element.hasAttribute("onclick") ||
|
|
753
|
+
typeof htmlElement.onclick === "function") {
|
|
736
754
|
actions.push("tap");
|
|
737
755
|
}
|
|
738
756
|
if (element instanceof HTMLInputElement ||
|
|
739
757
|
element instanceof HTMLTextAreaElement ||
|
|
740
|
-
element instanceof HTMLSelectElement
|
|
758
|
+
element instanceof HTMLSelectElement ||
|
|
759
|
+
htmlElement.isContentEditable) {
|
|
741
760
|
actions.push("typeText", "focus");
|
|
742
761
|
}
|
|
743
|
-
else if (
|
|
762
|
+
else if (htmlElement.tabIndex >= 0) {
|
|
744
763
|
actions.push("focus");
|
|
745
764
|
}
|
|
746
|
-
if (
|
|
747
|
-
|
|
765
|
+
if (htmlElement.scrollHeight > htmlElement.clientHeight ||
|
|
766
|
+
htmlElement.scrollWidth > htmlElement.clientWidth) {
|
|
748
767
|
actions.push("scroll", "swipe");
|
|
749
768
|
}
|
|
750
769
|
return [...new Set(actions)];
|
|
751
770
|
}
|
|
771
|
+
function positiveFinite(value) {
|
|
772
|
+
const parsed = Number(value);
|
|
773
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : undefined;
|
|
774
|
+
}
|
|
775
|
+
function createDomCoordinateSpace(browserWindow = typeof window === "undefined"
|
|
776
|
+
? undefined
|
|
777
|
+
: window, documentElement = typeof document === "undefined"
|
|
778
|
+
? null
|
|
779
|
+
: document.documentElement) {
|
|
780
|
+
const width = positiveFinite(browserWindow?.innerWidth) ??
|
|
781
|
+
positiveFinite(documentElement?.clientWidth);
|
|
782
|
+
const height = positiveFinite(browserWindow?.innerHeight) ??
|
|
783
|
+
positiveFinite(documentElement?.clientHeight);
|
|
784
|
+
if (width === undefined || height === undefined)
|
|
785
|
+
return undefined;
|
|
786
|
+
return { x: 0, y: 0, width, height, source: "dom.viewport" };
|
|
787
|
+
}
|
|
788
|
+
function normalizeDomAction(action) {
|
|
789
|
+
if (action === "tap")
|
|
790
|
+
return "click";
|
|
791
|
+
if (action === "typeText")
|
|
792
|
+
return "setValue";
|
|
793
|
+
return String(action ?? "");
|
|
794
|
+
}
|
|
752
795
|
function computedColorToArgbHex(value) {
|
|
753
796
|
const normalized = value.trim().toLowerCase();
|
|
754
797
|
if (!normalized)
|
|
@@ -897,8 +940,7 @@
|
|
|
897
940
|
name: "Get DOM document",
|
|
898
941
|
description: "Returns the accessible HTML DOM tree rendered inside the Capacitor WebView.",
|
|
899
942
|
category: "UI",
|
|
900
|
-
|
|
901
|
-
security: { level: "low", summary: "Reads the current app DOM." },
|
|
943
|
+
policy: "read",
|
|
902
944
|
}, async () => {
|
|
903
945
|
const root = document.documentElement;
|
|
904
946
|
const limits = {
|
|
@@ -913,6 +955,7 @@
|
|
|
913
955
|
platform: "web",
|
|
914
956
|
source: options.source,
|
|
915
957
|
adapter: "@ansight/capacitor",
|
|
958
|
+
coordinateSpace: createDomCoordinateSpace(),
|
|
916
959
|
capturedAtUtc: new Date().toISOString(),
|
|
917
960
|
types: typeRegistry.types,
|
|
918
961
|
truncated: limits.count >= limits.maxNodes,
|
|
@@ -924,7 +967,7 @@
|
|
|
924
967
|
name: "Inspect DOM node",
|
|
925
968
|
description: "Returns the current state of a DOM node captured by dom.get_document.",
|
|
926
969
|
category: "UI",
|
|
927
|
-
|
|
970
|
+
policy: "read",
|
|
928
971
|
argumentsSchema: {
|
|
929
972
|
type: "object",
|
|
930
973
|
required: ["nodeId"],
|
|
@@ -947,6 +990,7 @@
|
|
|
947
990
|
platform: "web",
|
|
948
991
|
source: options.source,
|
|
949
992
|
adapter: "@ansight/capacitor",
|
|
993
|
+
coordinateSpace: createDomCoordinateSpace(),
|
|
950
994
|
capturedAtUtc: new Date().toISOString(),
|
|
951
995
|
types: typeRegistry.types,
|
|
952
996
|
node,
|
|
@@ -957,7 +1001,7 @@
|
|
|
957
1001
|
name: "Query DOM",
|
|
958
1002
|
description: "Finds DOM nodes using a CSS selector.",
|
|
959
1003
|
category: "UI",
|
|
960
|
-
|
|
1004
|
+
policy: "read",
|
|
961
1005
|
argumentsSchema: {
|
|
962
1006
|
type: "object",
|
|
963
1007
|
required: ["selector"],
|
|
@@ -985,22 +1029,21 @@
|
|
|
985
1029
|
registrations.push(registerTool({
|
|
986
1030
|
id: "dom.invoke_action",
|
|
987
1031
|
name: "Invoke DOM action",
|
|
988
|
-
description: "
|
|
1032
|
+
description: "Taps, focuses, blurs, or enters text in a DOM node.",
|
|
989
1033
|
category: "UI",
|
|
990
|
-
|
|
1034
|
+
policy: "write",
|
|
991
1035
|
argumentsSchema: {
|
|
992
1036
|
type: "object",
|
|
993
1037
|
required: ["nodeId", "action"],
|
|
994
1038
|
properties: {
|
|
995
1039
|
nodeId: { type: "string" },
|
|
996
|
-
action: {
|
|
1040
|
+
action: {
|
|
1041
|
+
type: "string",
|
|
1042
|
+
enum: ["tap", "typeText", "click", "focus", "blur", "setValue"],
|
|
1043
|
+
},
|
|
997
1044
|
value: { type: "string" },
|
|
998
1045
|
},
|
|
999
1046
|
},
|
|
1000
|
-
security: {
|
|
1001
|
-
level: "high",
|
|
1002
|
-
summary: "Can interact with controls inside the app WebView.",
|
|
1003
|
-
},
|
|
1004
1047
|
}, ({ nodeId: id, action, value }) => {
|
|
1005
1048
|
const element = findElement(id);
|
|
1006
1049
|
if (!element) {
|
|
@@ -1010,17 +1053,24 @@
|
|
|
1010
1053
|
errorCode: "dom_node_not_found",
|
|
1011
1054
|
};
|
|
1012
1055
|
}
|
|
1013
|
-
|
|
1056
|
+
const normalizedAction = normalizeDomAction(action);
|
|
1057
|
+
if (normalizedAction === "click")
|
|
1014
1058
|
element.click();
|
|
1015
|
-
else if (
|
|
1059
|
+
else if (normalizedAction === "focus")
|
|
1016
1060
|
element.focus();
|
|
1017
|
-
else if (
|
|
1061
|
+
else if (normalizedAction === "blur")
|
|
1018
1062
|
element.blur();
|
|
1019
|
-
else if (
|
|
1063
|
+
else if (normalizedAction === "setValue" &&
|
|
1020
1064
|
(element instanceof HTMLInputElement ||
|
|
1021
1065
|
element instanceof HTMLTextAreaElement ||
|
|
1022
|
-
element instanceof HTMLSelectElement
|
|
1023
|
-
|
|
1066
|
+
element instanceof HTMLSelectElement ||
|
|
1067
|
+
element.isContentEditable)) {
|
|
1068
|
+
if (element.isContentEditable) {
|
|
1069
|
+
element.textContent = value ?? "";
|
|
1070
|
+
}
|
|
1071
|
+
else {
|
|
1072
|
+
element.value = value ?? "";
|
|
1073
|
+
}
|
|
1024
1074
|
element.dispatchEvent(new Event("input", { bubbles: true }));
|
|
1025
1075
|
element.dispatchEvent(new Event("change", { bubbles: true }));
|
|
1026
1076
|
}
|
|
@@ -1031,7 +1081,7 @@
|
|
|
1031
1081
|
errorCode: "dom_action_unsupported",
|
|
1032
1082
|
};
|
|
1033
1083
|
}
|
|
1034
|
-
return successful({ nodeId: id, action }, `DOM action '${action}' invoked.`);
|
|
1084
|
+
return successful({ nodeId: id, action, performedAction: normalizedAction }, `DOM action '${action}' invoked.`);
|
|
1035
1085
|
}));
|
|
1036
1086
|
}
|
|
1037
1087
|
return {
|
|
@@ -1203,6 +1253,50 @@
|
|
|
1203
1253
|
};
|
|
1204
1254
|
return this;
|
|
1205
1255
|
}
|
|
1256
|
+
withNetworkCapture(options = {}) {
|
|
1257
|
+
this.options.networkCapture = { ...options };
|
|
1258
|
+
return this;
|
|
1259
|
+
}
|
|
1260
|
+
withNetworkRequestBodies(maximumBodyBytes) {
|
|
1261
|
+
if (typeof this.options.networkCapture !== "object")
|
|
1262
|
+
return this;
|
|
1263
|
+
const current = this.options.networkCapture;
|
|
1264
|
+
this.options.networkCapture = {
|
|
1265
|
+
...current,
|
|
1266
|
+
captureRequestBody: true,
|
|
1267
|
+
...(maximumBodyBytes == null ? {} : { maximumBodyBytes }),
|
|
1268
|
+
};
|
|
1269
|
+
return this;
|
|
1270
|
+
}
|
|
1271
|
+
withoutNetworkRequestBodies() {
|
|
1272
|
+
if (typeof this.options.networkCapture !== "object")
|
|
1273
|
+
return this;
|
|
1274
|
+
const current = this.options.networkCapture;
|
|
1275
|
+
this.options.networkCapture = { ...current, captureRequestBody: false };
|
|
1276
|
+
return this;
|
|
1277
|
+
}
|
|
1278
|
+
withNetworkResponseBodies(maximumBodyBytes) {
|
|
1279
|
+
if (typeof this.options.networkCapture !== "object")
|
|
1280
|
+
return this;
|
|
1281
|
+
const current = this.options.networkCapture;
|
|
1282
|
+
this.options.networkCapture = {
|
|
1283
|
+
...current,
|
|
1284
|
+
captureResponseBody: true,
|
|
1285
|
+
...(maximumBodyBytes == null ? {} : { maximumBodyBytes }),
|
|
1286
|
+
};
|
|
1287
|
+
return this;
|
|
1288
|
+
}
|
|
1289
|
+
withoutNetworkResponseBodies() {
|
|
1290
|
+
if (typeof this.options.networkCapture !== "object")
|
|
1291
|
+
return this;
|
|
1292
|
+
const current = this.options.networkCapture;
|
|
1293
|
+
this.options.networkCapture = { ...current, captureResponseBody: false };
|
|
1294
|
+
return this;
|
|
1295
|
+
}
|
|
1296
|
+
withoutNetworkCapture() {
|
|
1297
|
+
this.options.networkCapture = false;
|
|
1298
|
+
return this;
|
|
1299
|
+
}
|
|
1206
1300
|
withToolGuard(toolGuard) {
|
|
1207
1301
|
this.options.toolGuard = toolGuard;
|
|
1208
1302
|
return this;
|
|
@@ -1370,6 +1464,871 @@
|
|
|
1370
1464
|
return new AnsightOptionsBuilder(options);
|
|
1371
1465
|
}
|
|
1372
1466
|
|
|
1467
|
+
const networkRequestSchema = "ansight.network-request.v1";
|
|
1468
|
+
const redactedNetworkValue = "<redacted>";
|
|
1469
|
+
const maximumHeaderCount = 128;
|
|
1470
|
+
const maximumHeaderValueLength = 4096;
|
|
1471
|
+
const maximumErrorMessageLength = 4096;
|
|
1472
|
+
const maximumUrlLength = 16384;
|
|
1473
|
+
const defaultMaximumBodyBytes = 64 * 1024;
|
|
1474
|
+
const sensitiveHeaderNames = new Set([
|
|
1475
|
+
"authorization",
|
|
1476
|
+
"cookie",
|
|
1477
|
+
"proxy-authorization",
|
|
1478
|
+
"set-cookie",
|
|
1479
|
+
"x-api-key",
|
|
1480
|
+
"x-auth-token",
|
|
1481
|
+
]);
|
|
1482
|
+
const sensitiveQueryNames = new Set([
|
|
1483
|
+
"access_token",
|
|
1484
|
+
"accesskey",
|
|
1485
|
+
"access_key",
|
|
1486
|
+
"api_key",
|
|
1487
|
+
"apikey",
|
|
1488
|
+
"auth",
|
|
1489
|
+
"authorization",
|
|
1490
|
+
"client_secret",
|
|
1491
|
+
"code",
|
|
1492
|
+
"credential",
|
|
1493
|
+
"credentials",
|
|
1494
|
+
"id_token",
|
|
1495
|
+
"jwt",
|
|
1496
|
+
"key",
|
|
1497
|
+
"password",
|
|
1498
|
+
"passwd",
|
|
1499
|
+
"refresh_token",
|
|
1500
|
+
"sas",
|
|
1501
|
+
"sastoken",
|
|
1502
|
+
"secret",
|
|
1503
|
+
"secret_key",
|
|
1504
|
+
"security_token",
|
|
1505
|
+
"session_token",
|
|
1506
|
+
"sig",
|
|
1507
|
+
"signature",
|
|
1508
|
+
"token",
|
|
1509
|
+
]);
|
|
1510
|
+
const azureSasFingerprintNames = new Set([
|
|
1511
|
+
"se",
|
|
1512
|
+
"skoid",
|
|
1513
|
+
"sp",
|
|
1514
|
+
"sr",
|
|
1515
|
+
"srt",
|
|
1516
|
+
"ss",
|
|
1517
|
+
"sv",
|
|
1518
|
+
]);
|
|
1519
|
+
const azureSasQueryNames = new Set([
|
|
1520
|
+
"epk",
|
|
1521
|
+
"erk",
|
|
1522
|
+
"rscc",
|
|
1523
|
+
"rscd",
|
|
1524
|
+
"rsce",
|
|
1525
|
+
"rscl",
|
|
1526
|
+
"rsct",
|
|
1527
|
+
"saoid",
|
|
1528
|
+
"scid",
|
|
1529
|
+
"se",
|
|
1530
|
+
"sig",
|
|
1531
|
+
"si",
|
|
1532
|
+
"sip",
|
|
1533
|
+
"ske",
|
|
1534
|
+
"skoid",
|
|
1535
|
+
"sks",
|
|
1536
|
+
"skt",
|
|
1537
|
+
"sktid",
|
|
1538
|
+
"skv",
|
|
1539
|
+
"snapshot",
|
|
1540
|
+
"sp",
|
|
1541
|
+
"spk",
|
|
1542
|
+
"spr",
|
|
1543
|
+
"sr",
|
|
1544
|
+
"srk",
|
|
1545
|
+
"srt",
|
|
1546
|
+
"ss",
|
|
1547
|
+
"st",
|
|
1548
|
+
"suoid",
|
|
1549
|
+
"tn",
|
|
1550
|
+
"versionid",
|
|
1551
|
+
"sv",
|
|
1552
|
+
]);
|
|
1553
|
+
function truncate(value, maximumLength) {
|
|
1554
|
+
const text = String(value);
|
|
1555
|
+
return text.length <= maximumLength
|
|
1556
|
+
? text
|
|
1557
|
+
: `${text.slice(0, maximumLength)}…`;
|
|
1558
|
+
}
|
|
1559
|
+
function normalizeRequired(value, fallback, maximumLength) {
|
|
1560
|
+
const normalized = value == null ? "" : String(value).trim();
|
|
1561
|
+
return truncate(normalized || fallback, maximumLength);
|
|
1562
|
+
}
|
|
1563
|
+
function normalizeOptional(value, maximumLength) {
|
|
1564
|
+
if (value == null)
|
|
1565
|
+
return undefined;
|
|
1566
|
+
const normalized = String(value).trim();
|
|
1567
|
+
return normalized ? truncate(normalized, maximumLength) : undefined;
|
|
1568
|
+
}
|
|
1569
|
+
function lowercaseSet(values) {
|
|
1570
|
+
return new Set((values ?? []).map((value) => value.toLowerCase()));
|
|
1571
|
+
}
|
|
1572
|
+
function isSensitiveHeader(name, options) {
|
|
1573
|
+
const lowered = name.toLowerCase();
|
|
1574
|
+
if (sensitiveHeaderNames.has(lowered) ||
|
|
1575
|
+
lowercaseSet(options.additionalSensitiveHeaderNames).has(lowered)) {
|
|
1576
|
+
return true;
|
|
1577
|
+
}
|
|
1578
|
+
const compact = lowered.replaceAll("-", "");
|
|
1579
|
+
return (compact.includes("token") ||
|
|
1580
|
+
compact.includes("secret") ||
|
|
1581
|
+
compact.includes("apikey"));
|
|
1582
|
+
}
|
|
1583
|
+
function headerEntries(headers) {
|
|
1584
|
+
if (!headers)
|
|
1585
|
+
return [];
|
|
1586
|
+
if (Array.isArray(headers)) {
|
|
1587
|
+
return headers.flatMap((header) => {
|
|
1588
|
+
if (Array.isArray(header))
|
|
1589
|
+
return [[header[0], header[1]]];
|
|
1590
|
+
if (header && typeof header === "object") {
|
|
1591
|
+
const value = header;
|
|
1592
|
+
return [[value.name, value.value]];
|
|
1593
|
+
}
|
|
1594
|
+
return [];
|
|
1595
|
+
});
|
|
1596
|
+
}
|
|
1597
|
+
if (typeof headers.forEach === "function") {
|
|
1598
|
+
const entries = [];
|
|
1599
|
+
headers.forEach((value, name) => entries.push([name, value]));
|
|
1600
|
+
return entries;
|
|
1601
|
+
}
|
|
1602
|
+
return typeof headers === "object" ? Object.entries(headers) : [];
|
|
1603
|
+
}
|
|
1604
|
+
function sanitizeHeaders(headers, options) {
|
|
1605
|
+
return headerEntries(headers)
|
|
1606
|
+
.filter(([name]) => name != null && String(name).trim())
|
|
1607
|
+
.slice(0, maximumHeaderCount)
|
|
1608
|
+
.map(([rawName, rawValue]) => {
|
|
1609
|
+
const name = normalizeRequired(rawName, "Header", 256);
|
|
1610
|
+
return {
|
|
1611
|
+
name,
|
|
1612
|
+
value: isSensitiveHeader(name, options)
|
|
1613
|
+
? redactedNetworkValue
|
|
1614
|
+
: normalizeRequired(rawValue, "", maximumHeaderValueLength),
|
|
1615
|
+
};
|
|
1616
|
+
});
|
|
1617
|
+
}
|
|
1618
|
+
function sanitizeQuery(query, options) {
|
|
1619
|
+
const appSensitive = lowercaseSet(options.additionalSensitiveQueryParameterNames);
|
|
1620
|
+
const pairs = query.split("&");
|
|
1621
|
+
const decodedNames = new Set(pairs.map((pair) => decodeQueryName(pair).toLowerCase()));
|
|
1622
|
+
const hasAzureSas = decodedNames.has("sig") &&
|
|
1623
|
+
[...azureSasFingerprintNames].some((name) => decodedNames.has(name));
|
|
1624
|
+
const hasAwsSignature = decodedNames.has("x-amz-signature");
|
|
1625
|
+
const hasGoogleSignature = decodedNames.has("x-goog-signature");
|
|
1626
|
+
const hasCloudFrontSignature = decodedNames.has("signature") &&
|
|
1627
|
+
["key-pair-id", "policy", "expires"].some((name) => decodedNames.has(name));
|
|
1628
|
+
const hasLegacyGoogleSignature = decodedNames.has("signature") && decodedNames.has("googleaccessid");
|
|
1629
|
+
const hasAlibabaSignature = (decodedNames.has("signature") && decodedNames.has("ossaccesskeyid")) ||
|
|
1630
|
+
decodedNames.has("x-oss-signature");
|
|
1631
|
+
return pairs
|
|
1632
|
+
.map((pair) => {
|
|
1633
|
+
const equalsIndex = pair.indexOf("=");
|
|
1634
|
+
const encodedName = equalsIndex < 0 ? pair : pair.slice(0, equalsIndex);
|
|
1635
|
+
const decodedName = decodeQueryName(pair);
|
|
1636
|
+
const lowered = decodedName.toLowerCase();
|
|
1637
|
+
const providerSensitive = (hasAzureSas && azureSasQueryNames.has(lowered)) ||
|
|
1638
|
+
(hasAwsSignature && lowered.startsWith("x-amz-")) ||
|
|
1639
|
+
(hasGoogleSignature && lowered.startsWith("x-goog-")) ||
|
|
1640
|
+
(hasCloudFrontSignature &&
|
|
1641
|
+
[
|
|
1642
|
+
"signature",
|
|
1643
|
+
"key-pair-id",
|
|
1644
|
+
"policy",
|
|
1645
|
+
"expires",
|
|
1646
|
+
"hash-algorithm",
|
|
1647
|
+
].includes(lowered)) ||
|
|
1648
|
+
(hasLegacyGoogleSignature &&
|
|
1649
|
+
["signature", "googleaccessid", "expires"].includes(lowered)) ||
|
|
1650
|
+
(hasAlibabaSignature &&
|
|
1651
|
+
(lowered.startsWith("x-oss-") ||
|
|
1652
|
+
["signature", "ossaccesskeyid", "security-token"].includes(lowered)));
|
|
1653
|
+
return providerSensitive ||
|
|
1654
|
+
sensitiveQueryNames.has(lowered) ||
|
|
1655
|
+
appSensitive.has(lowered)
|
|
1656
|
+
? `${encodedName}=${encodeURIComponent(redactedNetworkValue)}`
|
|
1657
|
+
: pair;
|
|
1658
|
+
})
|
|
1659
|
+
.join("&");
|
|
1660
|
+
}
|
|
1661
|
+
function decodeQueryName(pair) {
|
|
1662
|
+
const equalsIndex = pair.indexOf("=");
|
|
1663
|
+
const encodedName = equalsIndex < 0 ? pair : pair.slice(0, equalsIndex);
|
|
1664
|
+
try {
|
|
1665
|
+
return decodeURIComponent(encodedName.replaceAll("+", " "));
|
|
1666
|
+
}
|
|
1667
|
+
catch {
|
|
1668
|
+
return encodedName;
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
function sanitizeUrl(value, options) {
|
|
1672
|
+
let normalized = normalizeRequired(value, "<unknown>", maximumUrlLength);
|
|
1673
|
+
normalized = normalized.replace(/^(https?:\/\/)[^/@]+@/i, `$1${redactedNetworkValue}@`);
|
|
1674
|
+
const queryIndex = normalized.indexOf("?");
|
|
1675
|
+
if (queryIndex < 0)
|
|
1676
|
+
return truncate(normalized, maximumUrlLength);
|
|
1677
|
+
const fragmentIndex = normalized.indexOf("#", queryIndex);
|
|
1678
|
+
if (options.includeQueryString === false) {
|
|
1679
|
+
return truncate(normalized.slice(0, queryIndex) +
|
|
1680
|
+
(fragmentIndex < 0 ? "" : normalized.slice(fragmentIndex)), maximumUrlLength);
|
|
1681
|
+
}
|
|
1682
|
+
const queryEnd = fragmentIndex < 0 ? normalized.length : fragmentIndex;
|
|
1683
|
+
return truncate(normalized.slice(0, queryIndex + 1) +
|
|
1684
|
+
sanitizeQuery(normalized.slice(queryIndex + 1, queryEnd), options) +
|
|
1685
|
+
(fragmentIndex < 0 ? "" : normalized.slice(fragmentIndex)), maximumUrlLength);
|
|
1686
|
+
}
|
|
1687
|
+
function sanitizeErrorMessage(value, options) {
|
|
1688
|
+
const normalized = normalizeOptional(value, maximumErrorMessageLength);
|
|
1689
|
+
if (!normalized)
|
|
1690
|
+
return undefined;
|
|
1691
|
+
return truncate(normalized
|
|
1692
|
+
.replace(/(access_token|api_key|apikey|auth|authorization|code|key|password|passwd|secret|signature|token)(\s*=\s*)([^&\s,;]+)/gi, `$1$2${redactedNetworkValue}`)
|
|
1693
|
+
.replace(/https?:\/\/[^\s"'<>]+/gi, (url) => sanitizeUrl(url, options)), maximumErrorMessageLength);
|
|
1694
|
+
}
|
|
1695
|
+
function normalizeTimestamp(value, fallback) {
|
|
1696
|
+
const date = new Date(value == null ? fallback : String(value));
|
|
1697
|
+
return Number.isFinite(date.valueOf()) ? date.toISOString() : fallback;
|
|
1698
|
+
}
|
|
1699
|
+
function generateId(globalObject) {
|
|
1700
|
+
if (typeof globalObject.crypto?.randomUUID === "function") {
|
|
1701
|
+
return globalObject.crypto.randomUUID().replaceAll("-", "");
|
|
1702
|
+
}
|
|
1703
|
+
return `${Date.now().toString(36)}${Math.random().toString(36).slice(2)}`;
|
|
1704
|
+
}
|
|
1705
|
+
function normalizeSize(value) {
|
|
1706
|
+
const number = Number(value);
|
|
1707
|
+
return Number.isFinite(number) && number >= 0
|
|
1708
|
+
? Math.round(number)
|
|
1709
|
+
: undefined;
|
|
1710
|
+
}
|
|
1711
|
+
function maximumBodyBytes(options) {
|
|
1712
|
+
const configured = Number(options.maximumBodyBytes);
|
|
1713
|
+
const value = Number.isFinite(configured)
|
|
1714
|
+
? Math.round(configured)
|
|
1715
|
+
: defaultMaximumBodyBytes;
|
|
1716
|
+
return Math.max(0, value);
|
|
1717
|
+
}
|
|
1718
|
+
function sanitizeSensitiveText(value, options) {
|
|
1719
|
+
return value
|
|
1720
|
+
.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}`)
|
|
1721
|
+
.replace(/https?:\/\/[^\s"'<>]+/gi, (url) => sanitizeUrl(url, options));
|
|
1722
|
+
}
|
|
1723
|
+
function truncateUtf8(bytes, maximum) {
|
|
1724
|
+
let length = Math.min(bytes.length, maximum);
|
|
1725
|
+
const decoder = new TextDecoder("utf-8", { fatal: true });
|
|
1726
|
+
while (length > 0) {
|
|
1727
|
+
try {
|
|
1728
|
+
decoder.decode(bytes.slice(0, length));
|
|
1729
|
+
return bytes.slice(0, length);
|
|
1730
|
+
}
|
|
1731
|
+
catch {
|
|
1732
|
+
length -= 1;
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
return new Uint8Array();
|
|
1736
|
+
}
|
|
1737
|
+
function bytesToBase64$1(bytes) {
|
|
1738
|
+
let binary = "";
|
|
1739
|
+
for (const byte of bytes)
|
|
1740
|
+
binary += String.fromCharCode(byte);
|
|
1741
|
+
return btoa(binary);
|
|
1742
|
+
}
|
|
1743
|
+
function base64ToBytes(value) {
|
|
1744
|
+
const binary = atob(value);
|
|
1745
|
+
return Uint8Array.from(binary, (character) => character.charCodeAt(0));
|
|
1746
|
+
}
|
|
1747
|
+
function normalizeBody(body, options) {
|
|
1748
|
+
const maximum = maximumBodyBytes(options);
|
|
1749
|
+
if (!body || maximum <= 0)
|
|
1750
|
+
return undefined;
|
|
1751
|
+
const encoding = body.encoding?.toLowerCase();
|
|
1752
|
+
let bytes;
|
|
1753
|
+
try {
|
|
1754
|
+
if (encoding === "utf8") {
|
|
1755
|
+
bytes = new TextEncoder().encode(sanitizeSensitiveText(body.data, options));
|
|
1756
|
+
}
|
|
1757
|
+
else if (encoding === "base64" && options.captureBinaryBodies === true) {
|
|
1758
|
+
bytes = base64ToBytes(body.data);
|
|
1759
|
+
}
|
|
1760
|
+
else {
|
|
1761
|
+
return undefined;
|
|
1762
|
+
}
|
|
1763
|
+
}
|
|
1764
|
+
catch {
|
|
1765
|
+
return undefined;
|
|
1766
|
+
}
|
|
1767
|
+
const originalLength = bytes.length;
|
|
1768
|
+
const captured = encoding === "utf8"
|
|
1769
|
+
? truncateUtf8(bytes, maximum)
|
|
1770
|
+
: bytes.slice(0, maximum);
|
|
1771
|
+
const totalBytes = normalizeSize(body.totalBytes);
|
|
1772
|
+
return {
|
|
1773
|
+
contentType: normalizeOptional(body.contentType, 512),
|
|
1774
|
+
encoding,
|
|
1775
|
+
data: encoding === "base64"
|
|
1776
|
+
? bytesToBase64$1(captured)
|
|
1777
|
+
: new TextDecoder().decode(captured),
|
|
1778
|
+
capturedBytes: captured.length,
|
|
1779
|
+
totalBytes,
|
|
1780
|
+
truncated: body.truncated ||
|
|
1781
|
+
originalLength > captured.length ||
|
|
1782
|
+
(totalBytes != null && totalBytes > captured.length),
|
|
1783
|
+
};
|
|
1784
|
+
}
|
|
1785
|
+
function normalizeRecord(input, options, globalObject) {
|
|
1786
|
+
const now = new Date().toISOString();
|
|
1787
|
+
const startedAtUtc = normalizeTimestamp(input.startedAtUtc, now);
|
|
1788
|
+
const completedAtUtc = normalizeTimestamp(input.completedAtUtc, startedAtUtc);
|
|
1789
|
+
const duration = Number(input.durationMilliseconds);
|
|
1790
|
+
return {
|
|
1791
|
+
schema: networkRequestSchema,
|
|
1792
|
+
id: normalizeRequired(input.id, generateId(globalObject), 128),
|
|
1793
|
+
source: normalizeRequired(input.source, "unknown", 128),
|
|
1794
|
+
startedAtUtc,
|
|
1795
|
+
completedAtUtc: completedAtUtc < startedAtUtc ? startedAtUtc : completedAtUtc,
|
|
1796
|
+
durationMilliseconds: Number.isFinite(duration) && duration >= 0 ? duration : 0,
|
|
1797
|
+
method: normalizeRequired(input.method, "GET", 32).toUpperCase(),
|
|
1798
|
+
url: sanitizeUrl(input.url, options),
|
|
1799
|
+
protocol: normalizeOptional(input.protocol, 64),
|
|
1800
|
+
requestHeaders: options.includeRequestHeaders === false
|
|
1801
|
+
? []
|
|
1802
|
+
: sanitizeHeaders(input.requestHeaders, options),
|
|
1803
|
+
requestBodySizeBytes: options.includeBodySizes === false
|
|
1804
|
+
? undefined
|
|
1805
|
+
: normalizeSize(input.requestBodySizeBytes),
|
|
1806
|
+
requestBody: options.captureRequestBody !== false
|
|
1807
|
+
? normalizeBody(input.requestBody, options)
|
|
1808
|
+
: undefined,
|
|
1809
|
+
statusCode: Number.isInteger(Number(input.statusCode)) &&
|
|
1810
|
+
Number(input.statusCode) >= 100 &&
|
|
1811
|
+
Number(input.statusCode) <= 999
|
|
1812
|
+
? Number(input.statusCode)
|
|
1813
|
+
: undefined,
|
|
1814
|
+
reasonPhrase: normalizeOptional(input.reasonPhrase, 512),
|
|
1815
|
+
responseHeaders: options.includeResponseHeaders === false
|
|
1816
|
+
? []
|
|
1817
|
+
: sanitizeHeaders(input.responseHeaders, options),
|
|
1818
|
+
responseBodySizeBytes: options.includeBodySizes === false
|
|
1819
|
+
? undefined
|
|
1820
|
+
: normalizeSize(input.responseBodySizeBytes),
|
|
1821
|
+
responseBody: options.captureResponseBody !== false
|
|
1822
|
+
? normalizeBody(input.responseBody, options)
|
|
1823
|
+
: undefined,
|
|
1824
|
+
errorType: normalizeOptional(input.errorType, 512),
|
|
1825
|
+
errorMessage: sanitizeErrorMessage(input.errorMessage, options),
|
|
1826
|
+
};
|
|
1827
|
+
}
|
|
1828
|
+
function sanitizeNetworkRequest(input, options = {}, globalObject = globalThis) {
|
|
1829
|
+
try {
|
|
1830
|
+
let normalized = normalizeRecord(input, options, globalObject);
|
|
1831
|
+
if (options.urlSanitizer) {
|
|
1832
|
+
normalized = normalizeRecord({ ...normalized, url: options.urlSanitizer(normalized.url) }, options, globalObject);
|
|
1833
|
+
}
|
|
1834
|
+
if (options.requestSanitizer) {
|
|
1835
|
+
const transformed = options.requestSanitizer(normalized);
|
|
1836
|
+
if (transformed == null)
|
|
1837
|
+
return null;
|
|
1838
|
+
normalized = normalizeRecord(transformed, options, globalObject);
|
|
1839
|
+
}
|
|
1840
|
+
return normalized;
|
|
1841
|
+
}
|
|
1842
|
+
catch {
|
|
1843
|
+
return null;
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1846
|
+
function parseContentLength(headers) {
|
|
1847
|
+
const entry = headerEntries(headers).find(([name]) => String(name).toLowerCase() === "content-length");
|
|
1848
|
+
return entry ? normalizeSize(entry[1]) : undefined;
|
|
1849
|
+
}
|
|
1850
|
+
function headerValue(headers, wantedName) {
|
|
1851
|
+
const entry = headerEntries(headers).find(([name]) => String(name).toLowerCase() === wantedName);
|
|
1852
|
+
return entry == null ? undefined : String(entry[1]);
|
|
1853
|
+
}
|
|
1854
|
+
function isTextContentType(contentType) {
|
|
1855
|
+
if (!contentType)
|
|
1856
|
+
return true;
|
|
1857
|
+
const mediaType = contentType.split(";", 1)[0].trim().toLowerCase();
|
|
1858
|
+
return (mediaType.startsWith("text/") ||
|
|
1859
|
+
mediaType.endsWith("+json") ||
|
|
1860
|
+
mediaType.endsWith("+xml") ||
|
|
1861
|
+
[
|
|
1862
|
+
"application/json",
|
|
1863
|
+
"application/xml",
|
|
1864
|
+
"application/graphql",
|
|
1865
|
+
"application/javascript",
|
|
1866
|
+
"application/x-www-form-urlencoded",
|
|
1867
|
+
].includes(mediaType));
|
|
1868
|
+
}
|
|
1869
|
+
function bodyFromBytes(bytes, totalBytes, contentType, options) {
|
|
1870
|
+
const binary = !isTextContentType(contentType);
|
|
1871
|
+
if (binary && options.captureBinaryBodies !== true)
|
|
1872
|
+
return undefined;
|
|
1873
|
+
const maximum = maximumBodyBytes(options);
|
|
1874
|
+
if (maximum <= 0)
|
|
1875
|
+
return undefined;
|
|
1876
|
+
const captured = binary
|
|
1877
|
+
? bytes.slice(0, maximum)
|
|
1878
|
+
: truncateUtf8(bytes, maximum);
|
|
1879
|
+
return {
|
|
1880
|
+
contentType,
|
|
1881
|
+
encoding: binary ? "base64" : "utf8",
|
|
1882
|
+
data: binary ? bytesToBase64$1(captured) : new TextDecoder().decode(captured),
|
|
1883
|
+
capturedBytes: captured.length,
|
|
1884
|
+
totalBytes,
|
|
1885
|
+
truncated: bytes.length > captured.length ||
|
|
1886
|
+
(totalBytes != null && totalBytes > captured.length),
|
|
1887
|
+
};
|
|
1888
|
+
}
|
|
1889
|
+
function bodyFromValue(value, headers, options) {
|
|
1890
|
+
if (value == null || options.captureRequestBody === false)
|
|
1891
|
+
return undefined;
|
|
1892
|
+
const contentType = headerValue(headers, "content-type");
|
|
1893
|
+
if (typeof value === "string" || value instanceof URLSearchParams) {
|
|
1894
|
+
const bytes = new TextEncoder().encode(String(value));
|
|
1895
|
+
return bodyFromBytes(bytes, bytes.length, contentType ||
|
|
1896
|
+
(value instanceof URLSearchParams
|
|
1897
|
+
? "application/x-www-form-urlencoded"
|
|
1898
|
+
: undefined), options);
|
|
1899
|
+
}
|
|
1900
|
+
if (value instanceof ArrayBuffer) {
|
|
1901
|
+
const bytes = new Uint8Array(value);
|
|
1902
|
+
return bodyFromBytes(bytes, bytes.length, contentType, options);
|
|
1903
|
+
}
|
|
1904
|
+
if (ArrayBuffer.isView(value)) {
|
|
1905
|
+
const bytes = new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
|
|
1906
|
+
return bodyFromBytes(bytes, bytes.length, contentType, options);
|
|
1907
|
+
}
|
|
1908
|
+
return undefined;
|
|
1909
|
+
}
|
|
1910
|
+
async function bodyFromFetchResponse(response, headers, options, shouldContinue = () => true) {
|
|
1911
|
+
if (!shouldContinue() || options.captureResponseBody === false)
|
|
1912
|
+
return undefined;
|
|
1913
|
+
const contentType = headerValue(headers, "content-type");
|
|
1914
|
+
if (!isTextContentType(contentType) && options.captureBinaryBodies !== true) {
|
|
1915
|
+
return undefined;
|
|
1916
|
+
}
|
|
1917
|
+
const totalBytes = parseContentLength(headers);
|
|
1918
|
+
const maximum = maximumBodyBytes(options);
|
|
1919
|
+
if (maximum <= 0)
|
|
1920
|
+
return undefined;
|
|
1921
|
+
const clone = response.clone();
|
|
1922
|
+
if (clone.body) {
|
|
1923
|
+
const reader = clone.body.getReader();
|
|
1924
|
+
const chunks = [];
|
|
1925
|
+
let capturedLength = 0;
|
|
1926
|
+
let observedLength = 0;
|
|
1927
|
+
try {
|
|
1928
|
+
while (capturedLength <= maximum) {
|
|
1929
|
+
if (!shouldContinue()) {
|
|
1930
|
+
await reader.cancel().catch(() => undefined);
|
|
1931
|
+
return undefined;
|
|
1932
|
+
}
|
|
1933
|
+
const result = await reader.read();
|
|
1934
|
+
if (!shouldContinue()) {
|
|
1935
|
+
await reader.cancel().catch(() => undefined);
|
|
1936
|
+
return undefined;
|
|
1937
|
+
}
|
|
1938
|
+
if (result.done)
|
|
1939
|
+
break;
|
|
1940
|
+
const chunk = result.value;
|
|
1941
|
+
observedLength += chunk.length;
|
|
1942
|
+
const remaining = maximum - capturedLength;
|
|
1943
|
+
if (remaining > 0) {
|
|
1944
|
+
const kept = chunk.slice(0, remaining);
|
|
1945
|
+
chunks.push(kept);
|
|
1946
|
+
capturedLength += kept.length;
|
|
1947
|
+
}
|
|
1948
|
+
if (observedLength > maximum) {
|
|
1949
|
+
await reader.cancel().catch(() => undefined);
|
|
1950
|
+
break;
|
|
1951
|
+
}
|
|
1952
|
+
}
|
|
1953
|
+
}
|
|
1954
|
+
finally {
|
|
1955
|
+
reader.releaseLock();
|
|
1956
|
+
}
|
|
1957
|
+
const joined = new Uint8Array(capturedLength);
|
|
1958
|
+
let offset = 0;
|
|
1959
|
+
for (const chunk of chunks) {
|
|
1960
|
+
joined.set(chunk, offset);
|
|
1961
|
+
offset += chunk.length;
|
|
1962
|
+
}
|
|
1963
|
+
return bodyFromBytes(joined, totalBytes ?? observedLength, contentType, options);
|
|
1964
|
+
}
|
|
1965
|
+
if (totalBytes == null || totalBytes > maximum)
|
|
1966
|
+
return undefined;
|
|
1967
|
+
const bytes = new Uint8Array(await clone.arrayBuffer());
|
|
1968
|
+
if (!shouldContinue())
|
|
1969
|
+
return undefined;
|
|
1970
|
+
return bodyFromBytes(bytes, totalBytes, contentType, options);
|
|
1971
|
+
}
|
|
1972
|
+
function parseXhrResponseHeaders(value) {
|
|
1973
|
+
return value
|
|
1974
|
+
.trim()
|
|
1975
|
+
.split(/[\r\n]+/)
|
|
1976
|
+
.flatMap((line) => {
|
|
1977
|
+
const separator = line.indexOf(":");
|
|
1978
|
+
return separator < 0
|
|
1979
|
+
? []
|
|
1980
|
+
: [
|
|
1981
|
+
{
|
|
1982
|
+
name: line.slice(0, separator),
|
|
1983
|
+
value: line.slice(separator + 1),
|
|
1984
|
+
},
|
|
1985
|
+
];
|
|
1986
|
+
});
|
|
1987
|
+
}
|
|
1988
|
+
function monotonicNow(globalObject) {
|
|
1989
|
+
return typeof globalObject.performance?.now === "function"
|
|
1990
|
+
? globalObject.performance.now()
|
|
1991
|
+
: Date.now();
|
|
1992
|
+
}
|
|
1993
|
+
function installBrowserNetworkCapture(capture, options = {}, sourcePrefix = "capacitor", globalObject = globalThis) {
|
|
1994
|
+
const cleanups = [];
|
|
1995
|
+
let active = true;
|
|
1996
|
+
let fetchInvocationDepth = 0;
|
|
1997
|
+
if (options.captureFetch !== false &&
|
|
1998
|
+
typeof globalObject.fetch === "function") {
|
|
1999
|
+
const originalFetch = globalObject.fetch;
|
|
2000
|
+
const wrappedFetch = function (input, init) {
|
|
2001
|
+
const startedAtUtc = new Date().toISOString();
|
|
2002
|
+
const started = monotonicNow(globalObject);
|
|
2003
|
+
const inputRequest = typeof input === "object" && "headers" in input && "method" in input
|
|
2004
|
+
? input
|
|
2005
|
+
: undefined;
|
|
2006
|
+
const requestHeaders = headerEntries(inputRequest?.headers).concat(headerEntries(init?.headers));
|
|
2007
|
+
const requestBody = bodyFromValue(init?.body, requestHeaders, options);
|
|
2008
|
+
const method = init?.method || inputRequest?.method || "GET";
|
|
2009
|
+
const url = typeof input === "string" ? input : inputRequest?.url || String(input);
|
|
2010
|
+
let promise;
|
|
2011
|
+
fetchInvocationDepth += 1;
|
|
2012
|
+
try {
|
|
2013
|
+
promise = originalFetch(input, init);
|
|
2014
|
+
}
|
|
2015
|
+
catch (error) {
|
|
2016
|
+
fetchInvocationDepth -= 1;
|
|
2017
|
+
const request = sanitizeNetworkRequest({
|
|
2018
|
+
source: `${sourcePrefix}.fetch`,
|
|
2019
|
+
startedAtUtc,
|
|
2020
|
+
completedAtUtc: new Date().toISOString(),
|
|
2021
|
+
durationMilliseconds: monotonicNow(globalObject) - started,
|
|
2022
|
+
method,
|
|
2023
|
+
url,
|
|
2024
|
+
requestHeaders: sanitizeHeaders(requestHeaders, {}),
|
|
2025
|
+
requestBodySizeBytes: parseContentLength(requestHeaders) ?? requestBody?.totalBytes,
|
|
2026
|
+
requestBody,
|
|
2027
|
+
errorType: error instanceof Error ? error.name : "Error",
|
|
2028
|
+
errorMessage: error instanceof Error ? error.message : String(error),
|
|
2029
|
+
}, options, globalObject);
|
|
2030
|
+
if (active && request)
|
|
2031
|
+
Promise.resolve(capture(request)).catch(() => undefined);
|
|
2032
|
+
throw error;
|
|
2033
|
+
}
|
|
2034
|
+
fetchInvocationDepth -= 1;
|
|
2035
|
+
return promise.then((response) => {
|
|
2036
|
+
if (!active)
|
|
2037
|
+
return response;
|
|
2038
|
+
const responseHeaders = headerEntries(response.headers);
|
|
2039
|
+
const responseRecord = {
|
|
2040
|
+
source: `${sourcePrefix}.fetch`,
|
|
2041
|
+
startedAtUtc,
|
|
2042
|
+
completedAtUtc: new Date().toISOString(),
|
|
2043
|
+
durationMilliseconds: monotonicNow(globalObject) - started,
|
|
2044
|
+
method,
|
|
2045
|
+
url: response.url || url,
|
|
2046
|
+
requestHeaders: sanitizeHeaders(requestHeaders, {}),
|
|
2047
|
+
requestBodySizeBytes: parseContentLength(requestHeaders) ?? requestBody?.totalBytes,
|
|
2048
|
+
requestBody,
|
|
2049
|
+
statusCode: response.status,
|
|
2050
|
+
reasonPhrase: response.statusText,
|
|
2051
|
+
responseHeaders: sanitizeHeaders(responseHeaders, {}),
|
|
2052
|
+
responseBodySizeBytes: parseContentLength(responseHeaders),
|
|
2053
|
+
};
|
|
2054
|
+
return bodyFromFetchResponse(response, responseHeaders, options, () => active).then((responseBody) => {
|
|
2055
|
+
const request = sanitizeNetworkRequest({
|
|
2056
|
+
...responseRecord,
|
|
2057
|
+
responseBody,
|
|
2058
|
+
responseBodySizeBytes: responseRecord.responseBodySizeBytes ??
|
|
2059
|
+
responseBody?.totalBytes,
|
|
2060
|
+
}, options, globalObject);
|
|
2061
|
+
if (active && request)
|
|
2062
|
+
void Promise.resolve(capture(request)).catch(() => undefined);
|
|
2063
|
+
return response;
|
|
2064
|
+
}, () => {
|
|
2065
|
+
const request = sanitizeNetworkRequest(responseRecord, options, globalObject);
|
|
2066
|
+
if (active && request)
|
|
2067
|
+
void Promise.resolve(capture(request)).catch(() => undefined);
|
|
2068
|
+
return response;
|
|
2069
|
+
});
|
|
2070
|
+
}, (error) => {
|
|
2071
|
+
const request = sanitizeNetworkRequest({
|
|
2072
|
+
source: `${sourcePrefix}.fetch`,
|
|
2073
|
+
startedAtUtc,
|
|
2074
|
+
completedAtUtc: new Date().toISOString(),
|
|
2075
|
+
durationMilliseconds: monotonicNow(globalObject) - started,
|
|
2076
|
+
method,
|
|
2077
|
+
url,
|
|
2078
|
+
requestHeaders: sanitizeHeaders(requestHeaders, {}),
|
|
2079
|
+
requestBodySizeBytes: parseContentLength(requestHeaders) ?? requestBody?.totalBytes,
|
|
2080
|
+
requestBody,
|
|
2081
|
+
errorType: error instanceof Error ? error.name : "Error",
|
|
2082
|
+
errorMessage: error instanceof Error ? error.message : String(error),
|
|
2083
|
+
}, options, globalObject);
|
|
2084
|
+
if (active && request)
|
|
2085
|
+
Promise.resolve(capture(request)).catch(() => undefined);
|
|
2086
|
+
throw error;
|
|
2087
|
+
});
|
|
2088
|
+
};
|
|
2089
|
+
globalObject.fetch = wrappedFetch;
|
|
2090
|
+
cleanups.push(() => {
|
|
2091
|
+
if (globalObject.fetch === wrappedFetch)
|
|
2092
|
+
globalObject.fetch = originalFetch;
|
|
2093
|
+
});
|
|
2094
|
+
}
|
|
2095
|
+
const Xhr = globalObject.XMLHttpRequest;
|
|
2096
|
+
if (options.captureXmlHttpRequest !== false && Xhr?.prototype) {
|
|
2097
|
+
const states = new WeakMap();
|
|
2098
|
+
const prototype = Xhr.prototype;
|
|
2099
|
+
const originalOpen = prototype.open;
|
|
2100
|
+
const originalSend = prototype.send;
|
|
2101
|
+
const originalSetRequestHeader = prototype.setRequestHeader;
|
|
2102
|
+
const wrappedOpen = function (method, url, ...rest) {
|
|
2103
|
+
states.set(this, {
|
|
2104
|
+
method,
|
|
2105
|
+
url: String(url),
|
|
2106
|
+
requestHeaders: [],
|
|
2107
|
+
suppressed: fetchInvocationDepth > 0,
|
|
2108
|
+
});
|
|
2109
|
+
Reflect.apply(originalOpen, this, [method, url, ...rest]);
|
|
2110
|
+
};
|
|
2111
|
+
const wrappedSetRequestHeader = function (name, value) {
|
|
2112
|
+
states.get(this)?.requestHeaders.push({ name, value });
|
|
2113
|
+
Reflect.apply(originalSetRequestHeader, this, [name, value]);
|
|
2114
|
+
};
|
|
2115
|
+
const wrappedSend = function (body) {
|
|
2116
|
+
const state = states.get(this);
|
|
2117
|
+
if (!state || state.suppressed) {
|
|
2118
|
+
Reflect.apply(originalSend, this, [body]);
|
|
2119
|
+
return;
|
|
2120
|
+
}
|
|
2121
|
+
state.startedAtUtc = new Date().toISOString();
|
|
2122
|
+
state.started = monotonicNow(globalObject);
|
|
2123
|
+
state.requestBody = bodyFromValue(body, state.requestHeaders, options);
|
|
2124
|
+
let failure;
|
|
2125
|
+
const markFailure = (event) => {
|
|
2126
|
+
failure = event.type;
|
|
2127
|
+
};
|
|
2128
|
+
const complete = () => {
|
|
2129
|
+
if (!active)
|
|
2130
|
+
return;
|
|
2131
|
+
let responseHeaders = [];
|
|
2132
|
+
try {
|
|
2133
|
+
responseHeaders = parseXhrResponseHeaders(this.getAllResponseHeaders());
|
|
2134
|
+
}
|
|
2135
|
+
catch {
|
|
2136
|
+
// Some WebViews throw before response headers exist.
|
|
2137
|
+
}
|
|
2138
|
+
let responseBody;
|
|
2139
|
+
try {
|
|
2140
|
+
const responseType = this.responseType || "text";
|
|
2141
|
+
const responseOptions = {
|
|
2142
|
+
...options,
|
|
2143
|
+
captureRequestBody: options.captureResponseBody,
|
|
2144
|
+
};
|
|
2145
|
+
if (responseType === "text") {
|
|
2146
|
+
responseBody = bodyFromValue(this.responseText, responseHeaders, responseOptions);
|
|
2147
|
+
}
|
|
2148
|
+
else if (responseType === "arraybuffer") {
|
|
2149
|
+
responseBody = bodyFromValue(this.response, responseHeaders, responseOptions);
|
|
2150
|
+
}
|
|
2151
|
+
}
|
|
2152
|
+
catch {
|
|
2153
|
+
// Response data is not readable for every XHR response type.
|
|
2154
|
+
}
|
|
2155
|
+
const request = sanitizeNetworkRequest({
|
|
2156
|
+
source: `${sourcePrefix}.xhr`,
|
|
2157
|
+
startedAtUtc: state.startedAtUtc,
|
|
2158
|
+
completedAtUtc: new Date().toISOString(),
|
|
2159
|
+
durationMilliseconds: monotonicNow(globalObject) - (state.started ?? 0),
|
|
2160
|
+
method: state.method,
|
|
2161
|
+
url: this.responseURL || state.url,
|
|
2162
|
+
requestHeaders: state.requestHeaders,
|
|
2163
|
+
requestBodySizeBytes: parseContentLength(state.requestHeaders) ??
|
|
2164
|
+
state.requestBody?.totalBytes,
|
|
2165
|
+
requestBody: state.requestBody,
|
|
2166
|
+
statusCode: this.status || undefined,
|
|
2167
|
+
reasonPhrase: this.statusText,
|
|
2168
|
+
responseHeaders,
|
|
2169
|
+
responseBodySizeBytes: parseContentLength(responseHeaders) ?? responseBody?.totalBytes,
|
|
2170
|
+
responseBody,
|
|
2171
|
+
errorType: failure,
|
|
2172
|
+
errorMessage: failure ? `XMLHttpRequest ${failure}` : undefined,
|
|
2173
|
+
}, options, globalObject);
|
|
2174
|
+
if (request)
|
|
2175
|
+
Promise.resolve(capture(request)).catch(() => undefined);
|
|
2176
|
+
};
|
|
2177
|
+
this.addEventListener("error", markFailure);
|
|
2178
|
+
this.addEventListener("abort", markFailure);
|
|
2179
|
+
this.addEventListener("timeout", markFailure);
|
|
2180
|
+
this.addEventListener("loadend", complete, { once: true });
|
|
2181
|
+
Reflect.apply(originalSend, this, [body]);
|
|
2182
|
+
};
|
|
2183
|
+
prototype.open = wrappedOpen;
|
|
2184
|
+
prototype.setRequestHeader = wrappedSetRequestHeader;
|
|
2185
|
+
prototype.send = wrappedSend;
|
|
2186
|
+
cleanups.push(() => {
|
|
2187
|
+
if (prototype.open === wrappedOpen)
|
|
2188
|
+
prototype.open = originalOpen;
|
|
2189
|
+
if (prototype.send === wrappedSend)
|
|
2190
|
+
prototype.send = originalSend;
|
|
2191
|
+
if (prototype.setRequestHeader === wrappedSetRequestHeader) {
|
|
2192
|
+
prototype.setRequestHeader = originalSetRequestHeader;
|
|
2193
|
+
}
|
|
2194
|
+
});
|
|
2195
|
+
}
|
|
2196
|
+
let removed = false;
|
|
2197
|
+
return {
|
|
2198
|
+
remove() {
|
|
2199
|
+
if (removed)
|
|
2200
|
+
return;
|
|
2201
|
+
removed = true;
|
|
2202
|
+
active = false;
|
|
2203
|
+
for (const cleanup of cleanups.reverse())
|
|
2204
|
+
cleanup();
|
|
2205
|
+
},
|
|
2206
|
+
};
|
|
2207
|
+
}
|
|
2208
|
+
|
|
2209
|
+
const ANSIGHT_CAPACITOR_SDK_VERSION = "1.4.0-preview.3";
|
|
2210
|
+
const COMPILED_CAPACITOR_CORE_VERSION = "8.4.2";
|
|
2211
|
+
const CAPACITOR_GROUP = "capacitor";
|
|
2212
|
+
const LOCALIZATION_GROUP = "localization";
|
|
2213
|
+
function normalized(value) {
|
|
2214
|
+
if (value == null)
|
|
2215
|
+
return undefined;
|
|
2216
|
+
const result = String(value).trim();
|
|
2217
|
+
return result || undefined;
|
|
2218
|
+
}
|
|
2219
|
+
function canonicalizeLocale(value) {
|
|
2220
|
+
const locale = normalized(value)?.replace(/_/g, "-");
|
|
2221
|
+
if (!locale)
|
|
2222
|
+
return undefined;
|
|
2223
|
+
try {
|
|
2224
|
+
return Intl.getCanonicalLocales(locale)[0] ?? locale;
|
|
2225
|
+
}
|
|
2226
|
+
catch {
|
|
2227
|
+
return locale;
|
|
2228
|
+
}
|
|
2229
|
+
}
|
|
2230
|
+
function parseLocale(locale) {
|
|
2231
|
+
const parts = (locale ?? "").split("-").filter(Boolean);
|
|
2232
|
+
const language = parts[0]?.toLowerCase();
|
|
2233
|
+
const region = parts.find((part, index) => index > 0 && (/^[A-Za-z]{2}$/.test(part) || /^\d{3}$/.test(part)));
|
|
2234
|
+
return { language, region: region?.toUpperCase() };
|
|
2235
|
+
}
|
|
2236
|
+
function webViewDetails(platform, nativePlatform, userAgent) {
|
|
2237
|
+
const agent = userAgent ?? "";
|
|
2238
|
+
if (nativePlatform && platform === "ios") {
|
|
2239
|
+
return {
|
|
2240
|
+
engine: "wkWebView",
|
|
2241
|
+
version: /AppleWebKit\/([^\s]+)/.exec(agent)?.[1],
|
|
2242
|
+
};
|
|
2243
|
+
}
|
|
2244
|
+
if (nativePlatform && platform === "android") {
|
|
2245
|
+
return {
|
|
2246
|
+
engine: "chromiumWebView",
|
|
2247
|
+
version: /(?:Chrome|Chromium)\/([^\s]+)/.exec(agent)?.[1],
|
|
2248
|
+
};
|
|
2249
|
+
}
|
|
2250
|
+
if (/Firefox\/([^\s]+)/.test(agent)) {
|
|
2251
|
+
return { engine: "gecko", version: /Firefox\/([^\s]+)/.exec(agent)?.[1] };
|
|
2252
|
+
}
|
|
2253
|
+
if (/(?:Chrome|Chromium)\/([^\s]+)/.test(agent)) {
|
|
2254
|
+
return {
|
|
2255
|
+
engine: "chromium",
|
|
2256
|
+
version: /(?:Chrome|Chromium)\/([^\s]+)/.exec(agent)?.[1],
|
|
2257
|
+
};
|
|
2258
|
+
}
|
|
2259
|
+
if (/AppleWebKit\/([^\s]+)/.test(agent)) {
|
|
2260
|
+
return {
|
|
2261
|
+
engine: "webkit",
|
|
2262
|
+
version: /AppleWebKit\/([^\s]+)/.exec(agent)?.[1],
|
|
2263
|
+
};
|
|
2264
|
+
}
|
|
2265
|
+
return { engine: "unknown" };
|
|
2266
|
+
}
|
|
2267
|
+
function currentCapacitorSessionEnvironment(platform, nativePlatform) {
|
|
2268
|
+
let resolved;
|
|
2269
|
+
try {
|
|
2270
|
+
resolved = Intl.DateTimeFormat().resolvedOptions();
|
|
2271
|
+
}
|
|
2272
|
+
catch {
|
|
2273
|
+
resolved = undefined;
|
|
2274
|
+
}
|
|
2275
|
+
return {
|
|
2276
|
+
platform,
|
|
2277
|
+
nativePlatform,
|
|
2278
|
+
userAgent: typeof navigator === "undefined" ? undefined : navigator.userAgent,
|
|
2279
|
+
locale: resolved?.locale ??
|
|
2280
|
+
(typeof navigator === "undefined" ? undefined : navigator.language),
|
|
2281
|
+
timeZone: resolved?.timeZone,
|
|
2282
|
+
utcOffsetMinutes: -new Date().getTimezoneOffset(),
|
|
2283
|
+
};
|
|
2284
|
+
}
|
|
2285
|
+
function createAutomaticSessionProperties(environment) {
|
|
2286
|
+
const platform = normalized(environment.platform) ?? "unknown";
|
|
2287
|
+
const userAgent = normalized(environment.userAgent);
|
|
2288
|
+
const webView = webViewDetails(platform, environment.nativePlatform, userAgent);
|
|
2289
|
+
const locale = canonicalizeLocale(environment.locale);
|
|
2290
|
+
const parsedLocale = parseLocale(locale);
|
|
2291
|
+
const capacitor = {
|
|
2292
|
+
sdkVersion: ANSIGHT_CAPACITOR_SDK_VERSION,
|
|
2293
|
+
capacitorVersion: "8.x",
|
|
2294
|
+
compiledCapacitorVersion: COMPILED_CAPACITOR_CORE_VERSION,
|
|
2295
|
+
platform,
|
|
2296
|
+
runtimeLanguage: "javascript",
|
|
2297
|
+
executionMode: environment.nativePlatform ? "native" : "web",
|
|
2298
|
+
webViewEngine: webView.engine,
|
|
2299
|
+
};
|
|
2300
|
+
if (webView.version)
|
|
2301
|
+
capacitor.webViewEngineVersion = webView.version;
|
|
2302
|
+
if (userAgent)
|
|
2303
|
+
capacitor.userAgent = userAgent;
|
|
2304
|
+
const localization = {
|
|
2305
|
+
utcOffsetMinutes: String(environment.utcOffsetMinutes ?? -new Date().getTimezoneOffset()),
|
|
2306
|
+
};
|
|
2307
|
+
if (locale)
|
|
2308
|
+
localization.locale = locale;
|
|
2309
|
+
if (parsedLocale.language)
|
|
2310
|
+
localization.language = parsedLocale.language;
|
|
2311
|
+
if (parsedLocale.region)
|
|
2312
|
+
localization.region = parsedLocale.region;
|
|
2313
|
+
if (normalized(environment.timeZone)) {
|
|
2314
|
+
localization.timeZone = String(environment.timeZone).trim();
|
|
2315
|
+
}
|
|
2316
|
+
return {
|
|
2317
|
+
[CAPACITOR_GROUP]: capacitor,
|
|
2318
|
+
[LOCALIZATION_GROUP]: localization,
|
|
2319
|
+
};
|
|
2320
|
+
}
|
|
2321
|
+
function mergeSessionProperties(automaticProperties, customProperties) {
|
|
2322
|
+
const merged = Object.fromEntries(Object.entries(automaticProperties).map(([group, properties]) => [
|
|
2323
|
+
group,
|
|
2324
|
+
{ ...properties },
|
|
2325
|
+
]));
|
|
2326
|
+
for (const [group, properties] of Object.entries(customProperties ?? {})) {
|
|
2327
|
+
merged[group] = { ...(merged[group] ?? {}), ...properties };
|
|
2328
|
+
}
|
|
2329
|
+
return merged;
|
|
2330
|
+
}
|
|
2331
|
+
|
|
1373
2332
|
const AnsightNative = registerPlugin("Ansight");
|
|
1374
2333
|
const toolHandlers = new Map();
|
|
1375
2334
|
const artifactProviders = new Map();
|
|
@@ -1380,6 +2339,9 @@
|
|
|
1380
2339
|
let lifecycleCleanup;
|
|
1381
2340
|
let artifactToolRegistrations = [];
|
|
1382
2341
|
let domToolRegistration;
|
|
2342
|
+
let networkCaptureSubscription;
|
|
2343
|
+
let networkCaptureRegistration;
|
|
2344
|
+
let networkConnectionListener;
|
|
1383
2345
|
function normalizePairingPayload(payload) {
|
|
1384
2346
|
if (payload == null)
|
|
1385
2347
|
return payload;
|
|
@@ -1387,11 +2349,19 @@
|
|
|
1387
2349
|
}
|
|
1388
2350
|
function normalizeOptions(input) {
|
|
1389
2351
|
const options = JSON.parse(JSON.stringify(input));
|
|
2352
|
+
options.customProperties = mergeSessionProperties(automaticSessionProperties(), options.customProperties);
|
|
1390
2353
|
delete options.domTools;
|
|
1391
2354
|
delete options.errorCapture;
|
|
1392
2355
|
delete options.lifecycle;
|
|
2356
|
+
delete options.networkCapture;
|
|
1393
2357
|
return options;
|
|
1394
2358
|
}
|
|
2359
|
+
function automaticSessionProperties() {
|
|
2360
|
+
return createAutomaticSessionProperties(currentCapacitorSessionEnvironment(Capacitor.getPlatform(), Capacitor.isNativePlatform()));
|
|
2361
|
+
}
|
|
2362
|
+
function automaticSessionPropertyValue(group, key) {
|
|
2363
|
+
return automaticSessionProperties()[group]?.[key];
|
|
2364
|
+
}
|
|
1395
2365
|
function normalizeToolResult(value) {
|
|
1396
2366
|
if (value && typeof value === "object" && "success" in value) {
|
|
1397
2367
|
return value;
|
|
@@ -1441,11 +2411,13 @@
|
|
|
1441
2411
|
}
|
|
1442
2412
|
async function afterConnectionChange(operation) {
|
|
1443
2413
|
const result = await operation();
|
|
2414
|
+
await refreshNetworkCaptureConnection();
|
|
1444
2415
|
await emitHostConnectionStatus();
|
|
1445
2416
|
return result;
|
|
1446
2417
|
}
|
|
1447
2418
|
async function initialize(options = {}) {
|
|
1448
2419
|
const result = await AnsightNative.initialize(normalizeOptions(options));
|
|
2420
|
+
await configureNetworkCapture(options.networkCapture);
|
|
1449
2421
|
if (options.lifecycle !== false)
|
|
1450
2422
|
startLifecycleTracking();
|
|
1451
2423
|
if (options.errorCapture) {
|
|
@@ -1459,6 +2431,7 @@
|
|
|
1459
2431
|
}
|
|
1460
2432
|
async function initializeAndActivate(options = {}) {
|
|
1461
2433
|
const result = await AnsightNative.initializeAndActivate(normalizeOptions(options));
|
|
2434
|
+
await configureNetworkCapture(options.networkCapture);
|
|
1462
2435
|
if (options.lifecycle !== false)
|
|
1463
2436
|
startLifecycleTracking();
|
|
1464
2437
|
if (options.errorCapture) {
|
|
@@ -1483,6 +2456,80 @@
|
|
|
1483
2456
|
return AnsightNative.recordEvent(typeof input === "string" ? { label: input } : input);
|
|
1484
2457
|
}
|
|
1485
2458
|
const recordEvent = event;
|
|
2459
|
+
async function recordNetworkRequest(input, sanitizationOptions = {}) {
|
|
2460
|
+
const request = sanitizeNetworkRequest(input, sanitizationOptions);
|
|
2461
|
+
if (!request) {
|
|
2462
|
+
return {
|
|
2463
|
+
success: false,
|
|
2464
|
+
message: "Network request capture was suppressed by the sanitizer.",
|
|
2465
|
+
};
|
|
2466
|
+
}
|
|
2467
|
+
return AnsightNative.recordNetworkRequest(request);
|
|
2468
|
+
}
|
|
2469
|
+
function installNetworkCapture(options = {}) {
|
|
2470
|
+
uninstallNetworkCapture();
|
|
2471
|
+
const registration = { options };
|
|
2472
|
+
networkCaptureRegistration = registration;
|
|
2473
|
+
ensureNetworkConnectionListener();
|
|
2474
|
+
void refreshNetworkCaptureConnection();
|
|
2475
|
+
return {
|
|
2476
|
+
remove() {
|
|
2477
|
+
if (networkCaptureRegistration === registration) {
|
|
2478
|
+
uninstallNetworkCapture();
|
|
2479
|
+
}
|
|
2480
|
+
},
|
|
2481
|
+
};
|
|
2482
|
+
}
|
|
2483
|
+
function uninstallNetworkCapture() {
|
|
2484
|
+
networkCaptureRegistration = undefined;
|
|
2485
|
+
const listener = networkConnectionListener;
|
|
2486
|
+
networkConnectionListener = undefined;
|
|
2487
|
+
if (listener)
|
|
2488
|
+
void listener.then((value) => value.remove());
|
|
2489
|
+
detachNetworkCapture();
|
|
2490
|
+
}
|
|
2491
|
+
function detachNetworkCapture() {
|
|
2492
|
+
networkCaptureSubscription?.remove();
|
|
2493
|
+
networkCaptureSubscription = undefined;
|
|
2494
|
+
}
|
|
2495
|
+
async function refreshNetworkCaptureConnection() {
|
|
2496
|
+
const registration = networkCaptureRegistration;
|
|
2497
|
+
if (!registration) {
|
|
2498
|
+
detachNetworkCapture();
|
|
2499
|
+
return;
|
|
2500
|
+
}
|
|
2501
|
+
try {
|
|
2502
|
+
const status = await AnsightNative.hostConnectionStatus();
|
|
2503
|
+
if (networkCaptureRegistration !== registration)
|
|
2504
|
+
return;
|
|
2505
|
+
applyNetworkConnectionStatus(status);
|
|
2506
|
+
}
|
|
2507
|
+
catch {
|
|
2508
|
+
if (networkCaptureRegistration === registration)
|
|
2509
|
+
detachNetworkCapture();
|
|
2510
|
+
}
|
|
2511
|
+
}
|
|
2512
|
+
function ensureNetworkConnectionListener() {
|
|
2513
|
+
networkConnectionListener ??= AnsightNative.addListener("ansightHostConnectionStatus", applyNetworkConnectionStatus);
|
|
2514
|
+
}
|
|
2515
|
+
function applyNetworkConnectionStatus(status) {
|
|
2516
|
+
const registration = networkCaptureRegistration;
|
|
2517
|
+
if (!registration || status.isConnected !== true) {
|
|
2518
|
+
detachNetworkCapture();
|
|
2519
|
+
return;
|
|
2520
|
+
}
|
|
2521
|
+
networkCaptureSubscription ??= installBrowserNetworkCapture((request) => AnsightNative.recordNetworkRequest(request), registration.options);
|
|
2522
|
+
}
|
|
2523
|
+
async function configureNetworkCapture(value) {
|
|
2524
|
+
uninstallNetworkCapture();
|
|
2525
|
+
if (!value)
|
|
2526
|
+
return;
|
|
2527
|
+
networkCaptureRegistration = {
|
|
2528
|
+
options: typeof value === "object" ? value : {},
|
|
2529
|
+
};
|
|
2530
|
+
ensureNetworkConnectionListener();
|
|
2531
|
+
await refreshNetworkCaptureConnection();
|
|
2532
|
+
}
|
|
1486
2533
|
const recordCrashCandidate = (input) => AnsightNative.recordCrashCandidate(input);
|
|
1487
2534
|
const screenViewed = (name, details = {}) => AnsightNative.screenViewed({ name, details });
|
|
1488
2535
|
const trackRoute = screenViewed;
|
|
@@ -1538,12 +2585,25 @@
|
|
|
1538
2585
|
const captureScreenFrame = (options = {}) => AnsightNative.captureScreenFrame(options);
|
|
1539
2586
|
const enableTouchCapture = () => AnsightNative.enableTouchCapture();
|
|
1540
2587
|
const disableTouchCapture = () => AnsightNative.disableTouchCapture();
|
|
1541
|
-
const updateSessionProperties = (properties) => AnsightNative.updateSessionProperties({
|
|
2588
|
+
const updateSessionProperties = (properties) => AnsightNative.updateSessionProperties({
|
|
2589
|
+
properties: mergeSessionProperties(automaticSessionProperties(), properties),
|
|
2590
|
+
});
|
|
1542
2591
|
const updateCustomProperties = updateSessionProperties;
|
|
1543
|
-
const clearSessionProperties = () => AnsightNative.
|
|
2592
|
+
const clearSessionProperties = () => AnsightNative.updateSessionProperties({
|
|
2593
|
+
properties: automaticSessionProperties(),
|
|
2594
|
+
});
|
|
1544
2595
|
const clearCustomProperties = clearSessionProperties;
|
|
1545
2596
|
const registerCustomProperty = (group, key, value) => AnsightNative.registerCustomProperty({ group, key, value });
|
|
1546
|
-
const removeCustomProperty = (group, key) =>
|
|
2597
|
+
const removeCustomProperty = (group, key) => {
|
|
2598
|
+
const automaticValue = automaticSessionPropertyValue(group, key);
|
|
2599
|
+
return automaticValue == null
|
|
2600
|
+
? AnsightNative.removeCustomProperty({ group, key })
|
|
2601
|
+
: AnsightNative.registerCustomProperty({
|
|
2602
|
+
group,
|
|
2603
|
+
key,
|
|
2604
|
+
value: automaticValue,
|
|
2605
|
+
});
|
|
2606
|
+
};
|
|
1547
2607
|
function addHostConnectionStatusListener(listener, options = {}) {
|
|
1548
2608
|
hostConnectionListeners.add(listener);
|
|
1549
2609
|
if (options.emitCurrent !== false)
|
|
@@ -1630,7 +2690,7 @@
|
|
|
1630
2690
|
name: "Query JavaScript artifacts",
|
|
1631
2691
|
description: "Lists artifacts exposed by Capacitor JavaScript providers.",
|
|
1632
2692
|
category: "Artifacts",
|
|
1633
|
-
|
|
2693
|
+
policy: "read",
|
|
1634
2694
|
}, async (_args, context) => {
|
|
1635
2695
|
const definitions = [];
|
|
1636
2696
|
for (const provider of artifactProviders.values()) {
|
|
@@ -1661,7 +2721,7 @@
|
|
|
1661
2721
|
name: "Request JavaScript artifact",
|
|
1662
2722
|
description: "Creates an artifact through a Capacitor JavaScript provider.",
|
|
1663
2723
|
category: "Artifacts",
|
|
1664
|
-
|
|
2724
|
+
policy: "read",
|
|
1665
2725
|
argumentsSchema: {
|
|
1666
2726
|
type: "object",
|
|
1667
2727
|
required: ["providerId", "artifactId"],
|
|
@@ -1894,6 +2954,10 @@
|
|
|
1894
2954
|
recordMetric,
|
|
1895
2955
|
event,
|
|
1896
2956
|
recordEvent,
|
|
2957
|
+
recordNetworkRequest,
|
|
2958
|
+
installNetworkCapture,
|
|
2959
|
+
uninstallNetworkCapture,
|
|
2960
|
+
sanitizeNetworkRequest,
|
|
1897
2961
|
screenViewed,
|
|
1898
2962
|
trackRoute,
|
|
1899
2963
|
setAppLifecycleState,
|
|
@@ -1955,10 +3019,9 @@
|
|
|
1955
3019
|
platform: Capacitor.getPlatform(),
|
|
1956
3020
|
};
|
|
1957
3021
|
|
|
1958
|
-
|
|
1959
|
-
|
|
3022
|
+
function createStandaloneOptions(overrides = {}) {
|
|
3023
|
+
return createOptionsBuilder(overrides)
|
|
1960
3024
|
.withAnsightDefaults()
|
|
1961
|
-
.withAllToolAccess()
|
|
1962
3025
|
.withVisualTreeTools()
|
|
1963
3026
|
.withFileSystemTools()
|
|
1964
3027
|
.withDatabaseTools()
|
|
@@ -1966,7 +3029,12 @@
|
|
|
1966
3029
|
.withReflectionTools()
|
|
1967
3030
|
.withDomTools()
|
|
1968
3031
|
.withErrorCapture()
|
|
3032
|
+
.withToolGuard(overrides.toolGuard ?? "readOnly")
|
|
1969
3033
|
.build();
|
|
3034
|
+
}
|
|
3035
|
+
|
|
3036
|
+
if (typeof window !== "undefined") {
|
|
3037
|
+
const options = createStandaloneOptions(globalThis.__ANSIGHT_CAPACITOR_STANDALONE_OPTIONS__ ?? {});
|
|
1970
3038
|
void Ansight.initializeAndActivate(options).catch((error) => {
|
|
1971
3039
|
console.error("[Ansight Capacitor]", error);
|
|
1972
3040
|
});
|