@ansight/capacitor 1.3.0-preview.10 → 1.3.0-preview.12

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