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