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