@intuned/browser-dev 2.2.3-unify-sdks.20

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 (195) hide show
  1. package/.babelrc +21 -0
  2. package/.eslintignore +10 -0
  3. package/.eslintrc.js +39 -0
  4. package/LICENSE +43 -0
  5. package/dist/ai-extractors/AnthropicClient/index.js +23 -0
  6. package/dist/ai-extractors/export.d.js +5 -0
  7. package/dist/ai-extractors/export.d.ts +422 -0
  8. package/dist/ai-extractors/extractStructuredData.js +79 -0
  9. package/dist/ai-extractors/extractionHelpers/extractStructuredDataUsingAi/constants.js +7 -0
  10. package/dist/ai-extractors/extractionHelpers/extractStructuredDataUsingAi/errors.js +42 -0
  11. package/dist/ai-extractors/extractionHelpers/extractStructuredDataUsingAi/extractStructuredDataUsingClaude.js +149 -0
  12. package/dist/ai-extractors/extractionHelpers/extractStructuredDataUsingAi/extractStructuredDataUsingGoogle.js +37 -0
  13. package/dist/ai-extractors/extractionHelpers/extractStructuredDataUsingAi/extractStructuredDataUsingOpenAi.js +144 -0
  14. package/dist/ai-extractors/extractionHelpers/extractStructuredDataUsingAi/extractStrucutredDataUsingAiInstance.js +123 -0
  15. package/dist/ai-extractors/extractionHelpers/extractStructuredDataUsingAi/index.js +55 -0
  16. package/dist/ai-extractors/extractionHelpers/extractStructuredDataUsingAi/isItemTableHeaderOrFooter.js +96 -0
  17. package/dist/ai-extractors/extractionHelpers/extractStructuredDataUsingAi/screenshotHelpers.js +55 -0
  18. package/dist/ai-extractors/extractionHelpers/extractStructuredDataUsingAi/types.js +5 -0
  19. package/dist/ai-extractors/extractionHelpers/extractStructuredDataUsingAi/utils.js +53 -0
  20. package/dist/ai-extractors/extractionHelpers/types.js +5 -0
  21. package/dist/ai-extractors/fileExtractors.js +176 -0
  22. package/dist/ai-extractors/index.js +31 -0
  23. package/dist/ai-extractors/jsonSchema.d.js +5 -0
  24. package/dist/ai-extractors/jsonSchema.d.ts +49 -0
  25. package/dist/ai-extractors/openAiClients/index.js +23 -0
  26. package/dist/ai-extractors/validators.js +239 -0
  27. package/dist/browser/ai/export.d.js +3 -0
  28. package/dist/browser/ai/export.d.ts +587 -0
  29. package/dist/browser/ai/extractMarkdown.js +15 -0
  30. package/dist/browser/ai/extractStructuredData.js +231 -0
  31. package/dist/browser/ai/extractStructuredDataUsingAi.js +140 -0
  32. package/dist/browser/ai/extractionHelpers/screenshotHelpers.js +55 -0
  33. package/dist/browser/ai/extractionHelpers/validateSchema.js +148 -0
  34. package/dist/browser/ai/index.d.ts +587 -0
  35. package/dist/browser/ai/index.js +19 -0
  36. package/dist/browser/ai/isPageLoaded.js +67 -0
  37. package/dist/browser/ai/prompt.js +39 -0
  38. package/dist/browser/ai/tests/testCheckAllTypesAreStrings.spec.js +143 -0
  39. package/dist/browser/ai/tests/testExtractStructuredData.spec.js +622 -0
  40. package/dist/browser/ai/tools/index.js +48 -0
  41. package/dist/browser/ai/types/errors.js +67 -0
  42. package/dist/browser/ai/types/models.js +45 -0
  43. package/dist/browser/ai/types/types.js +48 -0
  44. package/dist/browser/ai/validators.js +136 -0
  45. package/dist/common/Logger/index.js +60 -0
  46. package/dist/common/Logger/types.js +5 -0
  47. package/dist/common/SdkError.js +50 -0
  48. package/dist/common/aiModelsValidations.js +50 -0
  49. package/dist/common/browser_scripts.js +2596 -0
  50. package/dist/common/ensureBrowserScripts.js +17 -0
  51. package/dist/common/environmentVariables.js +16 -0
  52. package/dist/common/eventTracking/getAiTrackingHeaders.js +31 -0
  53. package/dist/common/eventTracking/getFileTrackingHeaders.js +23 -0
  54. package/dist/common/extendedTest.js +148 -0
  55. package/dist/common/extractionHelpers.js +19 -0
  56. package/dist/common/formatZodError.js +18 -0
  57. package/dist/common/fuzzySearch/fuzzySearch.test.js +250 -0
  58. package/dist/common/fuzzySearch/levenshtein-search.js +298 -0
  59. package/dist/common/fuzzySearch/utils.js +23 -0
  60. package/dist/common/getModelProvider.js +18 -0
  61. package/dist/common/getSimplifiedHtml.js +122 -0
  62. package/dist/common/hashObject.js +32 -0
  63. package/dist/common/html2markdown/convertElementToMarkdown.js +469 -0
  64. package/dist/common/html2markdown/index.js +19 -0
  65. package/dist/common/jwtTokenManager.js +18 -0
  66. package/dist/common/loadRuntime.js +16 -0
  67. package/dist/common/locatorHelpers.js +41 -0
  68. package/dist/common/matching/collectStrings.js +32 -0
  69. package/dist/common/matching/levenshtein.js +40 -0
  70. package/dist/common/matching/matching.js +317 -0
  71. package/dist/common/matching/types.js +1 -0
  72. package/dist/common/noEmpty.js +9 -0
  73. package/dist/common/saveSnapshotWithExamples.js +60 -0
  74. package/dist/common/tests/testEnsureBrowserScript.spec.js +31 -0
  75. package/dist/common/xpathMapping.js +107 -0
  76. package/dist/helpers/downloadFile.js +125 -0
  77. package/dist/helpers/export.d.js +1 -0
  78. package/dist/helpers/export.d.ts +1294 -0
  79. package/dist/helpers/extractMarkdown.js +35 -0
  80. package/dist/helpers/filterEmptyValues.js +54 -0
  81. package/dist/helpers/gotoUrl.js +93 -0
  82. package/dist/helpers/index.d.ts +1294 -0
  83. package/dist/helpers/index.js +115 -0
  84. package/dist/helpers/processDate.js +25 -0
  85. package/dist/helpers/resolveUrl.js +63 -0
  86. package/dist/helpers/sanitizeHtml.js +73 -0
  87. package/dist/helpers/saveFileToS3.js +46 -0
  88. package/dist/helpers/scrollToLoadContent.js +50 -0
  89. package/dist/helpers/tests/extendedTest.js +130 -0
  90. package/dist/helpers/tests/testDownloadFile.spec.js +197 -0
  91. package/dist/helpers/tests/testFilterEmptyValues.spec.js +151 -0
  92. package/dist/helpers/tests/testGoToUrl.spec.js +37 -0
  93. package/dist/helpers/tests/testIsPageLoaded.spec.js +285 -0
  94. package/dist/helpers/tests/testProcessDate.spec.js +13 -0
  95. package/dist/helpers/tests/testResolveUrl.spec.js +341 -0
  96. package/dist/helpers/tests/testSanitizeHtml.spec.js +330 -0
  97. package/dist/helpers/tests/testSimplifyHtml.spec.js +251 -0
  98. package/dist/helpers/tests/testValidateDataUsingSchema.spec.js +380 -0
  99. package/dist/helpers/tests/testWaitForDomSettled.spec.js +169 -0
  100. package/dist/helpers/tests/testWaitForNetworkIdle.spec.js +115 -0
  101. package/dist/helpers/types/Attachment.js +81 -0
  102. package/dist/helpers/types/CustomTypeRegistry.js +48 -0
  103. package/dist/helpers/types/RunEnvironment.js +18 -0
  104. package/dist/helpers/types/ValidationError.js +17 -0
  105. package/dist/helpers/types/index.js +51 -0
  106. package/dist/helpers/uploadFileToS3.js +153 -0
  107. package/dist/helpers/utils/getS3Client.js +21 -0
  108. package/dist/helpers/utils/index.js +73 -0
  109. package/dist/helpers/utils/isDownload.js +10 -0
  110. package/dist/helpers/utils/isGenerateCodeMode.js +9 -0
  111. package/dist/helpers/utils/isLocator.js +9 -0
  112. package/dist/helpers/utils/jwtTokenManager.js +18 -0
  113. package/dist/helpers/validateDataUsingSchema.js +119 -0
  114. package/dist/helpers/waitForDomSettled.js +182 -0
  115. package/dist/helpers/waitForNetworkIdle.js +191 -0
  116. package/dist/index.d.js +82 -0
  117. package/dist/index.d.ts +11 -0
  118. package/dist/index.js +84 -0
  119. package/dist/intunedServices/ApiGateway/aiApiGateway.js +87 -0
  120. package/dist/intunedServices/ApiGateway/factory.js +13 -0
  121. package/dist/intunedServices/ApiGateway/providers/Anthropic.js +26 -0
  122. package/dist/intunedServices/ApiGateway/providers/Gemini.js +29 -0
  123. package/dist/intunedServices/ApiGateway/providers/OpenAI.js +29 -0
  124. package/dist/intunedServices/ApiGateway/tests/testApiGateway.spec.js +221 -0
  125. package/dist/intunedServices/ApiGateway/types.js +11 -0
  126. package/dist/intunedServices/cache/cache.js +61 -0
  127. package/dist/intunedServices/cache/index.js +12 -0
  128. package/dist/intunedServices/cache/tests/testCache.spec.js +117 -0
  129. package/dist/optimized-extractors/common/buildExamplesPrompt.js +12 -0
  130. package/dist/optimized-extractors/common/buildImagesFromPage.js +55 -0
  131. package/dist/optimized-extractors/common/extractStructuredDataUsingClaude.js +149 -0
  132. package/dist/optimized-extractors/common/extractStructuredDataUsingGoogle.js +37 -0
  133. package/dist/optimized-extractors/common/extractStructuredDataUsingOpenAi.js +145 -0
  134. package/dist/optimized-extractors/common/extractStrucutredDataUsingAiInstance.js +122 -0
  135. package/dist/optimized-extractors/common/findTableHeaders.js +175 -0
  136. package/dist/optimized-extractors/common/index.js +55 -0
  137. package/dist/optimized-extractors/common/isTableHeaderOrFooter.js +97 -0
  138. package/dist/optimized-extractors/common/matching/matching.js +212 -0
  139. package/dist/optimized-extractors/common/matching/matching.test.js +655 -0
  140. package/dist/optimized-extractors/common/matching/types.js +18 -0
  141. package/dist/optimized-extractors/common/matching/utils.js +184 -0
  142. package/dist/optimized-extractors/common/utils.js +58 -0
  143. package/dist/optimized-extractors/export.d.js +5 -0
  144. package/dist/optimized-extractors/export.d.ts +397 -0
  145. package/dist/optimized-extractors/extractArray.js +120 -0
  146. package/dist/optimized-extractors/extractObject.js +104 -0
  147. package/dist/optimized-extractors/index.d.ts +397 -0
  148. package/dist/optimized-extractors/index.js +31 -0
  149. package/dist/optimized-extractors/listExtractionHelpers/__tests__/dynamicListExtractor.spec.js +312 -0
  150. package/dist/optimized-extractors/listExtractionHelpers/__tests__/findSetOfXpathsToCreateAnArrayExtractor.test.js +22 -0
  151. package/dist/optimized-extractors/listExtractionHelpers/__tests__/getContainerElement.test.js +21 -0
  152. package/dist/optimized-extractors/listExtractionHelpers/__tests__/partOfSameArrayXpath.test.js +42 -0
  153. package/dist/optimized-extractors/listExtractionHelpers/__tests__/verifyThatAllXpathsArePartOfSameArray.test.js +9 -0
  154. package/dist/optimized-extractors/listExtractionHelpers/dynamicListExtractor.js +152 -0
  155. package/dist/optimized-extractors/listExtractionHelpers/errors.js +46 -0
  156. package/dist/optimized-extractors/listExtractionHelpers/getListMatches.js +14 -0
  157. package/dist/optimized-extractors/listExtractionHelpers/runAiExtraction.js +240 -0
  158. package/dist/optimized-extractors/listExtractionHelpers/typesAndSchema.js +5 -0
  159. package/dist/optimized-extractors/listExtractionHelpers/utils/extractPropertiesUsingGPTFromArray.js +277 -0
  160. package/dist/optimized-extractors/listExtractionHelpers/utils/extractStructuredListUsingAi.js +44 -0
  161. package/dist/optimized-extractors/listExtractionHelpers/utils/getListContainerXpath.js +94 -0
  162. package/dist/optimized-extractors/listExtractionHelpers/utils/getRelativeContainerXpathSelector.js +20 -0
  163. package/dist/optimized-extractors/listExtractionHelpers/utils/getSimplifiedHtmlPerListItem.js +21 -0
  164. package/dist/optimized-extractors/listExtractionHelpers/utils/tablesUtils.js +48 -0
  165. package/dist/optimized-extractors/listExtractionHelpers/utils/validateOptions.js +52 -0
  166. package/dist/optimized-extractors/models/anthropicModel.js +23 -0
  167. package/dist/optimized-extractors/models/openaiModel.js +23 -0
  168. package/dist/optimized-extractors/objectExtractionHelpers/AIExtractors.js +73 -0
  169. package/dist/optimized-extractors/objectExtractionHelpers/__tests__/checksumUtils.test.js +103 -0
  170. package/dist/optimized-extractors/objectExtractionHelpers/__tests__/testObjectExtractorFromLocator.spec.js +107 -0
  171. package/dist/optimized-extractors/objectExtractionHelpers/__tests__/testObjectExtractorFromPage.spec.js +107 -0
  172. package/dist/optimized-extractors/objectExtractionHelpers/calculateObjectExampleHash.js +28 -0
  173. package/dist/optimized-extractors/objectExtractionHelpers/captureSnapshot.js +26 -0
  174. package/dist/optimized-extractors/objectExtractionHelpers/checksumUtils.js +32 -0
  175. package/dist/optimized-extractors/objectExtractionHelpers/constants.js +7 -0
  176. package/dist/optimized-extractors/objectExtractionHelpers/dynamicObjectExtractor.js +106 -0
  177. package/dist/optimized-extractors/objectExtractionHelpers/errors.js +42 -0
  178. package/dist/optimized-extractors/objectExtractionHelpers/findDomMatches.js +54 -0
  179. package/dist/optimized-extractors/objectExtractionHelpers/getSimplifiedHtml.js +122 -0
  180. package/dist/optimized-extractors/objectExtractionHelpers/typesAndSchemas.js +5 -0
  181. package/dist/optimized-extractors/objectExtractionHelpers/validateDynamicObjectExtractorOptions.js +52 -0
  182. package/dist/optimized-extractors/types/aiModelsValidation.js +45 -0
  183. package/dist/optimized-extractors/types/errors.js +42 -0
  184. package/dist/optimized-extractors/types/jsonSchema.d.js +5 -0
  185. package/dist/optimized-extractors/types/jsonSchema.d.ts +50 -0
  186. package/dist/optimized-extractors/types/types.js +5 -0
  187. package/dist/optimized-extractors/validators.js +152 -0
  188. package/dist/vite-env.d.js +1 -0
  189. package/dist/vite-env.d.ts +9 -0
  190. package/docs.md +14 -0
  191. package/how-to-run-tests.md +10 -0
  192. package/intuned-runtime-setup.md +13 -0
  193. package/package.json +124 -0
  194. package/tsconfig.eslint.json +5 -0
  195. package/tsconfig.json +26 -0
@@ -0,0 +1,317 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.filterAndRankMatches = filterAndRankMatches;
7
+ exports.isMatchExact = isMatchExact;
8
+ exports.matchStringsWithDomContent = matchStringsWithDomContent;
9
+ exports.matchStringsWithDomContentInBrowser = matchStringsWithDomContentInBrowser;
10
+ exports.normalizeSpacing = normalizeSpacing;
11
+ exports.rankMatch = rankMatch;
12
+ exports.removePunctuationAndSpaces = removePunctuationAndSpaces;
13
+ exports.replaceWithBestMatches = replaceWithBestMatches;
14
+ exports.selectBestMatch = selectBestMatch;
15
+ var _utils = require("../../helpers/utils");
16
+ const logger = {
17
+ info: message => console.info(message),
18
+ warning: message => console.warn(message),
19
+ error: message => console.error(message)
20
+ };
21
+ function normalizeSpacing({
22
+ text
23
+ }) {
24
+ let normalized = text.replace(/\n/g, " ").replace(/\t/g, " ");
25
+ normalized = normalized.split(/\s+/).join(" ");
26
+ return normalized.trim();
27
+ }
28
+ function isMatchExact({
29
+ data,
30
+ value
31
+ }) {
32
+ if (data === "" || value === "") {
33
+ return [false, ""];
34
+ }
35
+ const normalizedData = normalizeSpacing({
36
+ text: data
37
+ });
38
+ const normalizedValue = normalizeSpacing({
39
+ text: value
40
+ });
41
+ return [normalizedData.toLowerCase() === normalizedValue.toLowerCase(), normalizedValue];
42
+ }
43
+ function removePunctuationAndSpaces({
44
+ s
45
+ }) {
46
+ const punctuation = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~";
47
+ return s.split("").filter(c => !punctuation.includes(c) && c !== " ").join("");
48
+ }
49
+ function rankMatch({
50
+ original,
51
+ match
52
+ }) {
53
+ try {
54
+ const normalizedOriginal = normalizeSpacing({
55
+ text: original
56
+ }).toLowerCase();
57
+ const normalizedMatch = normalizeSpacing({
58
+ text: match
59
+ }).toLowerCase();
60
+ const ratio = calculateSimilarityRatio(normalizedOriginal, normalizedMatch);
61
+ const lenOriginal = normalizedOriginal.length;
62
+ if (lenOriginal > 20 && ratio > 0.85) {
63
+ return "HIGH";
64
+ }
65
+ const normalizedOriginalNoPunct = removePunctuationAndSpaces({
66
+ s: normalizedOriginal
67
+ });
68
+ const normalizedMatchNoPunct = removePunctuationAndSpaces({
69
+ s: normalizedMatch
70
+ });
71
+ if (normalizedOriginalNoPunct === normalizedMatchNoPunct) {
72
+ return "HIGH";
73
+ }
74
+ return "LOW";
75
+ } catch (error) {
76
+ logger.warning("Error in rankMatch, falling back to simple comparison");
77
+ const normalizedOriginal = removePunctuationAndSpaces({
78
+ s: normalizeSpacing({
79
+ text: original
80
+ }).toLowerCase()
81
+ });
82
+ const normalizedMatch = removePunctuationAndSpaces({
83
+ s: normalizeSpacing({
84
+ text: match
85
+ }).toLowerCase()
86
+ });
87
+ if (normalizedOriginal === normalizedMatch) {
88
+ return "HIGH";
89
+ }
90
+ return "LOW";
91
+ }
92
+ }
93
+ function calculateSimilarityRatio(str1, str2) {
94
+ const longer = str1.length > str2.length ? str1 : str2;
95
+ const shorter = str1.length > str2.length ? str2 : str1;
96
+ if (longer.length === 0) {
97
+ return 1.0;
98
+ }
99
+ return (longer.length - editDistance(longer, shorter)) / longer.length;
100
+ }
101
+ function editDistance(str1, str2) {
102
+ const matrix = Array(str2.length + 1).fill(null).map(() => Array(str1.length + 1).fill(null));
103
+ for (let i = 0; i <= str1.length; i++) matrix[0][i] = i;
104
+ for (let j = 0; j <= str2.length; j++) matrix[j][0] = j;
105
+ for (let j = 1; j <= str2.length; j++) {
106
+ for (let i = 1; i <= str1.length; i++) {
107
+ if (str1[i - 1] === str2[j - 1]) {
108
+ matrix[j][i] = matrix[j - 1][i - 1];
109
+ } else {
110
+ matrix[j][i] = Math.min(matrix[j - 1][i - 1] + 1, matrix[j][i - 1] + 1, matrix[j - 1][i] + 1);
111
+ }
112
+ }
113
+ }
114
+ return matrix[str2.length][str1.length];
115
+ }
116
+ function selectBestMatch({
117
+ original,
118
+ matches
119
+ }) {
120
+ const exactMatches = matches.filter(match => match.match_mode !== "fuzzy");
121
+ if (exactMatches.length > 0) {
122
+ const bestMatch = exactMatches[0];
123
+ return {
124
+ matchText: bestMatch.matched_value,
125
+ matchXpath: bestMatch.xpath,
126
+ matchType: bestMatch.match_source === "direct_text_node" ? "direct-text" : bestMatch.match_source === "attribute" ? {
127
+ attribute: "unknown"
128
+ } : "all-text"
129
+ };
130
+ }
131
+ const fuzzyMatches = matches.filter(match => match.match_mode === "fuzzy");
132
+ const rankedFuzzyMatches = fuzzyMatches.map(match => ({
133
+ match,
134
+ rank: rankMatch({
135
+ original,
136
+ match: match.matched_value
137
+ })
138
+ }));
139
+ const highRankedMatches = rankedFuzzyMatches.filter(item => item.rank === "HIGH");
140
+ const filteredFuzzyMatches = highRankedMatches.map(item => item.match);
141
+ if (filteredFuzzyMatches.length > 0) {
142
+ const sortedFuzzyMatches = filteredFuzzyMatches.sort((a, b) => (a.fuzzy_distance || Infinity) - (b.fuzzy_distance || Infinity));
143
+ const bestMatch = sortedFuzzyMatches[0];
144
+ return {
145
+ matchText: bestMatch.matched_value,
146
+ matchXpath: bestMatch.xpath,
147
+ matchType: bestMatch.match_source === "direct_text_node" ? "direct-text" : bestMatch.match_source === "attribute" ? {
148
+ attribute: "unknown"
149
+ } : "all-text"
150
+ };
151
+ }
152
+ return null;
153
+ }
154
+ async function matchStringsWithDomContent({
155
+ pageObject,
156
+ stringsList,
157
+ container = null
158
+ }) {
159
+ try {
160
+ await (0, _utils.ensureBrowserScripts)(pageObject);
161
+ let handle;
162
+ if (container) {
163
+ handle = container;
164
+ } else {
165
+ handle = await pageObject.locator("html").elementHandle();
166
+ }
167
+ const matches = await pageObject.evaluate(async args => {
168
+ const [container, searchTexts] = args;
169
+ try {
170
+ if (typeof window.__INTUNED__ !== "undefined" && typeof window.__INTUNED__.matchStringsWithDomContent === "function") {
171
+ return await window.__INTUNED__.matchStringsWithDomContent(container, searchTexts);
172
+ } else {
173
+ return searchTexts.reduce((acc, text) => {
174
+ acc[text] = [];
175
+ return acc;
176
+ }, {});
177
+ }
178
+ } catch (error) {
179
+ console.error("Error matching strings with DOM content:", error);
180
+ return searchTexts.reduce((acc, text) => {
181
+ acc[text] = [];
182
+ return acc;
183
+ }, {});
184
+ }
185
+ }, [handle, stringsList]);
186
+ return matches;
187
+ } catch (error) {
188
+ logger.warning(`Error matching strings with DOM content: ${error}`);
189
+ return stringsList.reduce((acc, string) => {
190
+ acc[string] = [];
191
+ return acc;
192
+ }, {});
193
+ }
194
+ }
195
+ async function replaceWithBestMatches({
196
+ stringsToMatch,
197
+ pageObject,
198
+ container = null
199
+ }) {
200
+ const matchesMap = await matchStringsWithDomContent({
201
+ pageObject,
202
+ stringsList: stringsToMatch,
203
+ container
204
+ });
205
+ const replacements = {};
206
+ const xpathMapping = {};
207
+ for (const [string, matches] of Object.entries(matchesMap)) {
208
+ const bestMatch = matches.length > 0 ? selectBestMatch({
209
+ original: string,
210
+ matches
211
+ }) : null;
212
+ replacements[string] = bestMatch;
213
+ if (bestMatch) {
214
+ xpathMapping[bestMatch.matchText] = [{
215
+ xpath: bestMatch.matchXpath,
216
+ matchType: bestMatch.matchType
217
+ }];
218
+ }
219
+ }
220
+ return {
221
+ replacements,
222
+ xpathMapping
223
+ };
224
+ }
225
+ async function filterAndRankMatches(frame, matches) {
226
+ const filteredMatches = matches.filter(match => {
227
+ const xpath = match.xpath;
228
+ return !(xpath.includes("[name()='svg']/") || xpath.includes("/path") || xpath.includes("/style"));
229
+ });
230
+ async function getVisibility(match) {
231
+ try {
232
+ const locator = frame.locator(`xpath=${match.xpath}`);
233
+ return await locator.isVisible({
234
+ timeout: 100
235
+ });
236
+ } catch {
237
+ return false;
238
+ }
239
+ }
240
+ const visibilityResults = await Promise.all(filteredMatches.map(match => getVisibility(match)));
241
+ const modeOrder = {
242
+ full: 3,
243
+ partial: 2,
244
+ fuzzy: 1
245
+ };
246
+ const sourceOrder = {
247
+ direct_text_node: 3,
248
+ text_content: 2,
249
+ attribute: 1
250
+ };
251
+ function sortKey(match, visible) {
252
+ const modeKey = modeOrder[match.match_mode.toLowerCase()] || 0;
253
+ const sourceKey = sourceOrder[match.match_source.toLowerCase()] || 0;
254
+ const visibleKey = visible ? 1 : 0;
255
+ let partialScore = 0;
256
+ if (match.match_mode.toLowerCase() === "partial" && match.matched_source_value && match.matched_value) {
257
+ const extraChars = match.matched_source_value.length - match.matched_value.length;
258
+ if (extraChars === 0) {
259
+ partialScore = 1;
260
+ } else {
261
+ partialScore = 1 / extraChars;
262
+ }
263
+ }
264
+ return modeKey + sourceKey + visibleKey + partialScore;
265
+ }
266
+ const matchesWithVisibility = filteredMatches.map((match, index) => ({
267
+ match,
268
+ visible: visibilityResults[index]
269
+ }));
270
+ const sortedMatchesWithVisibility = matchesWithVisibility.sort((a, b) => sortKey(b.match, b.visible) - sortKey(a.match, a.visible));
271
+ const sortedMatches = sortedMatchesWithVisibility.map(item => item.match);
272
+ const seenXpaths = new Set();
273
+ const uniqueMatches = [];
274
+ for (const match of sortedMatches) {
275
+ if (seenXpaths.has(match.xpath)) {
276
+ continue;
277
+ }
278
+ seenXpaths.add(match.xpath);
279
+ uniqueMatches.push(match);
280
+ }
281
+ return uniqueMatches;
282
+ }
283
+ async function matchStringsWithDomContentInBrowser(frame, stringsList, container = null) {
284
+ let handle;
285
+ if (container) {
286
+ handle = await container.elementHandle();
287
+ } else {
288
+ handle = await frame.locator("html").elementHandle();
289
+ }
290
+ logger.info(`Searching for ${stringsList.length} strings in the DOM, ${stringsList}`);
291
+ const matches = await frame.evaluate(async args => {
292
+ const [container, searchTexts] = args;
293
+ const result = await window.__INTUNED__.matchStringsWithDomContent(container, searchTexts);
294
+ return result;
295
+ }, [handle, stringsList]);
296
+ let frames = [];
297
+ if ("childFrames" in frame) {
298
+ frames = frame.childFrames();
299
+ } else if ("frames" in frame) {
300
+ frames = frame.frames();
301
+ }
302
+ for (const subframe of frames) {
303
+ try {
304
+ const frameMatches = await matchStringsWithDomContentInBrowser(subframe, stringsList, null);
305
+ for (const [string, stringMatches] of Object.entries(frameMatches)) {
306
+ if (string in matches) {
307
+ matches[string].extend(stringMatches);
308
+ } else {
309
+ matches[string] = stringMatches;
310
+ }
311
+ }
312
+ } catch {
313
+ continue;
314
+ }
315
+ }
316
+ return matches;
317
+ }
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = noEmpty;
7
+ function noEmpty(value) {
8
+ return value !== null && value !== undefined;
9
+ }
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.__saveSnapshotWithExamples = __saveSnapshotWithExamples;
7
+ exports.__saveSnapshotWithExamplesFromPage = __saveSnapshotWithExamplesFromPage;
8
+ var _clientS = require("@aws-sdk/client-s3");
9
+ var z = _interopRequireWildcard(require("zod"));
10
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
11
+ function shouldSkipCaptureSnapshots() {
12
+ return process.env.DISABLE_CAPTURE_EXAMPLE === "true";
13
+ }
14
+ async function __saveSnapshotWithExamplesFromPage(page, snapshotName, examples, s3Configs) {
15
+ const html = await page.content();
16
+ const url = page.url();
17
+ return __saveSnapshotWithExamples(snapshotName, examples, html, url, s3Configs);
18
+ }
19
+ async function __saveSnapshotWithExamples(snapshotName, examples, html, url, s3Configs) {
20
+ if (shouldSkipCaptureSnapshots()) {
21
+ return;
22
+ }
23
+ const origin = new URL(url).origin;
24
+ const defaultConfigs = {
25
+ accessKeyId: process.env.SNAPSHOT_S3_ACCESS_KEY_ID,
26
+ bucket: process.env.SNAPSHOT_S3_BUCKET,
27
+ folderName: process.env.SNAPSHOT_S3_FOLDER,
28
+ region: process.env.SNAPSHOT_S3_REGION,
29
+ secretAccessKey: process.env.SNAPSHOT_S3_SECRET_ACCESS_KEY
30
+ };
31
+ const schema = z.record(z.string(), z.any());
32
+ const parsedConfigs = schema.safeParse({
33
+ ...defaultConfigs,
34
+ ...s3Configs
35
+ });
36
+ if (parsedConfigs.success === false) {
37
+ return;
38
+ }
39
+ const configs = parsedConfigs.data;
40
+ const folderPath = `${configs.folderName}`;
41
+ const client = new _clientS.S3Client({
42
+ region: configs.region,
43
+ credentials: {
44
+ accessKeyId: configs.accessKeyId,
45
+ secretAccessKey: configs.secretAccessKey
46
+ }
47
+ });
48
+ const snapshotJson = {
49
+ origin,
50
+ html,
51
+ examples
52
+ };
53
+ await client.send(new _clientS.PutObjectCommand({
54
+ Bucket: configs.bucket,
55
+ Key: `${folderPath}/${snapshotName}.json`,
56
+ Body: JSON.stringify(snapshotJson),
57
+ ContentType: "application/json"
58
+ }));
59
+ console.log("Snapshot saved successfully.", snapshotName);
60
+ }
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+
3
+ var _extendedTest = require("../extendedTest");
4
+ var _ensureBrowserScripts = require("../ensureBrowserScripts");
5
+ var _playwright = require("playwright");
6
+ var _dotenv = require("dotenv");
7
+ (0, _dotenv.config)();
8
+ (0, _extendedTest.describe)("goToUrl E2E Tests", () => {
9
+ let browser;
10
+ let page;
11
+ (0, _extendedTest.beforeAll)(async () => {
12
+ browser = await _playwright.chromium.launch({
13
+ headless: false
14
+ });
15
+ });
16
+ (0, _extendedTest.afterAll)(async () => {
17
+ await browser.close();
18
+ });
19
+ (0, _extendedTest.beforeEach)(async () => {
20
+ page = await browser.newPage();
21
+ });
22
+ (0, _extendedTest.afterEach)(async () => {
23
+ await page.close();
24
+ });
25
+ (0, _extendedTest.describe)("ensureBrowserScripts", () => {
26
+ (0, _extendedTest.test)("should ensure browser scripts are loaded", async () => {
27
+ await (0, _ensureBrowserScripts.ensureBrowserScripts)(page);
28
+ (0, _extendedTest.expect)(await page.evaluate("typeof window.__INTUNED__")).toBe("object");
29
+ });
30
+ });
31
+ });
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.createXPathMapping = createXPathMapping;
7
+ exports.validateXPathMapping = validateXPathMapping;
8
+ var _ensureBrowserScripts = require("./ensureBrowserScripts");
9
+ async function validateXPathMapping(page, cachedMapping, prefix) {
10
+ try {
11
+ for (const [expectedText, entries] of Object.entries(cachedMapping)) {
12
+ for (const entry of entries) {
13
+ const {
14
+ xpath,
15
+ matchType
16
+ } = entry;
17
+ const elementExists = await page.evaluate(({
18
+ xpath,
19
+ prefix
20
+ }) => {
21
+ const element = document.evaluate(prefix ? `${prefix}/${xpath}` : xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
22
+ return element !== null;
23
+ }, {
24
+ xpath,
25
+ prefix
26
+ });
27
+ if (!elementExists) {
28
+ return false;
29
+ }
30
+ const actualText = await page.evaluate(({
31
+ xpath,
32
+ prefix,
33
+ matchType
34
+ }) => {
35
+ const element = document.evaluate(prefix ? `${prefix}/${xpath}` : xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
36
+ if (!element) return "";
37
+ if (matchType === "direct-text") {
38
+ let directText = "";
39
+ for (const child of element.childNodes) {
40
+ if (child.nodeType === Node.TEXT_NODE) {
41
+ directText += child.textContent || "";
42
+ }
43
+ }
44
+ return directText.trim();
45
+ } else if (matchType === "all-text") {
46
+ var _element$textContent;
47
+ return ((_element$textContent = element.textContent) === null || _element$textContent === void 0 ? void 0 : _element$textContent.trim()) || "";
48
+ } else if (typeof matchType === "object" && matchType.attribute) {
49
+ return element.getAttribute(matchType.attribute) || "";
50
+ }
51
+ return "";
52
+ }, {
53
+ xpath,
54
+ prefix,
55
+ matchType
56
+ });
57
+ if (actualText !== expectedText) {
58
+ return false;
59
+ }
60
+ }
61
+ }
62
+ return true;
63
+ } catch (error) {
64
+ return false;
65
+ }
66
+ }
67
+ async function createXPathMapping(page, extractedData) {
68
+ const xpathMapping = {};
69
+ let uniqueValues = [];
70
+ await (0, _ensureBrowserScripts.ensureBrowserScripts)(page);
71
+ if (Array.isArray(extractedData)) {
72
+ if (extractedData.length > 0 && typeof extractedData[0] === "string") {
73
+ uniqueValues = [...new Set(extractedData)];
74
+ } else {
75
+ uniqueValues = [...new Set(extractedData.flatMap(obj => Object.values(obj)))];
76
+ }
77
+ } else if (extractedData && typeof extractedData === "object") {
78
+ uniqueValues = [...new Set(Object.values(extractedData).filter(value => value !== null))];
79
+ }
80
+ for (const value of uniqueValues) {
81
+ xpathMapping[value] = [];
82
+ const strategies = [{
83
+ locatorFn: () => page.getByText(value, {
84
+ exact: true
85
+ }),
86
+ matchType: "all-text"
87
+ }];
88
+ for (const strategy of strategies) {
89
+ const locators = strategy.locatorFn();
90
+ const count = await locators.count();
91
+ for (let i = 0; i < count; i++) {
92
+ const locator = locators.nth(i);
93
+ const xpath = await locator.evaluate(el => {
94
+ return window.__INTUNED__.getElementXPath(el);
95
+ });
96
+ const existingEntry = xpathMapping[value].find(entry => entry.xpath === xpath);
97
+ if (!existingEntry) {
98
+ xpathMapping[value].push({
99
+ xpath,
100
+ matchType: strategy.matchType
101
+ });
102
+ }
103
+ }
104
+ }
105
+ }
106
+ return xpathMapping;
107
+ }
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.downloadFile = void 0;
7
+ var _asyncMutex = require("async-mutex");
8
+ var _utils = require("./utils/");
9
+ var _resolveUrl = require("./resolveUrl");
10
+ const downloadMutex = new _asyncMutex.Mutex();
11
+ function isValidURL(string) {
12
+ try {
13
+ new URL(string);
14
+ return true;
15
+ } catch (_) {
16
+ return false;
17
+ }
18
+ }
19
+ async function getAbsoluteUrl(page, url) {
20
+ try {
21
+ const url_locator = page.locator(`a[href='${url}']`);
22
+ if ((await url_locator.count()) > 0) {
23
+ const href = await url_locator.evaluate(element => element.href);
24
+ return href;
25
+ }
26
+ } catch (error) {
27
+ console.error("Error getting absolute URL:", error);
28
+ }
29
+ const absUrl = await (0, _resolveUrl.resolveUrl)({
30
+ url,
31
+ page
32
+ });
33
+ return absUrl;
34
+ }
35
+ const downloadFile = async options => {
36
+ const {
37
+ page,
38
+ trigger,
39
+ timeoutInMs
40
+ } = options;
41
+ let pageToDownloadFrom = page;
42
+ let shouldClosePage = false;
43
+ let downloadPromise;
44
+ let isInvalidUrl = false;
45
+ const isUrlTrigger = trigger => {
46
+ return typeof trigger === "string";
47
+ };
48
+ const isCallableTrigger = trigger => {
49
+ return typeof trigger === "function";
50
+ };
51
+ const isLocatorTrigger = trigger => {
52
+ return typeof trigger === "object" && trigger !== null && "click" in trigger;
53
+ };
54
+ if (isUrlTrigger(trigger)) {
55
+ pageToDownloadFrom = await page.context().newPage();
56
+ shouldClosePage = true;
57
+ }
58
+ let action;
59
+ let absoluteUrl;
60
+ const release = await downloadMutex.acquire();
61
+ try {
62
+ downloadPromise = pageToDownloadFrom.waitForEvent("download", {
63
+ timeout: (timeoutInMs ?? 5000) + 1000
64
+ });
65
+ if (isUrlTrigger(trigger)) {
66
+ absoluteUrl = await getAbsoluteUrl(page, trigger);
67
+ if (!isValidURL(absoluteUrl)) {
68
+ isInvalidUrl = true;
69
+ console.warn(`Url is not valid, the download might not be triggered correctly. ${absoluteUrl}`);
70
+ }
71
+ try {
72
+ action = await pageToDownloadFrom.goto(absoluteUrl);
73
+ if (!action) {
74
+ throw new Error(`Failed to navigate to ${absoluteUrl}`);
75
+ }
76
+ const contentType = action.headers()["content-type"];
77
+ if (contentType && contentType.startsWith("image/")) {
78
+ await pageToDownloadFrom.evaluate(fullURL => {
79
+ const link = document.createElement("a");
80
+ link.href = fullURL;
81
+ link.download = "";
82
+ document.body.appendChild(link);
83
+ link.click();
84
+ document.body.removeChild(link);
85
+ }, absoluteUrl);
86
+ downloadPromise.catch(() => {
87
+ console.error(`Download was cancelled for URL: ${absoluteUrl}`);
88
+ });
89
+ }
90
+ } catch (error) {
91
+ console.error("Error during download:", error);
92
+ }
93
+ } else if (isCallableTrigger(trigger)) {
94
+ action = await trigger(page);
95
+ } else if (isLocatorTrigger(trigger)) {
96
+ action = await trigger.click();
97
+ }
98
+ const download = await downloadPromise;
99
+ if ((0, _utils.isGenerateCodeMode)()) {
100
+ download.cancel();
101
+ }
102
+ return download;
103
+ } catch (error) {
104
+ if (isUrlTrigger(trigger) && !isInvalidUrl) {
105
+ const notFoundPatterns = ["404", "not found", "page not found", "page doesn't exist", "page does not exist", "resource not found"];
106
+ for (const pattern of notFoundPatterns) {
107
+ if ((await pageToDownloadFrom.getByText(pattern).count()) > 0) {
108
+ throw new Error(`Download timeout for url:${trigger}. Page appears to be a 404 page.`);
109
+ }
110
+ }
111
+ } else if (error instanceof Error && isLocatorTrigger(trigger)) {
112
+ throw new Error(`Failed to download file: ${error.message} Download was never triggered`);
113
+ } else if (error instanceof Error && isCallableTrigger(trigger)) {
114
+ throw new Error(`Failed to download file: ${error.message} Download was never triggered`);
115
+ } else if (isInvalidUrl) {
116
+ throw new Error(`Failed to download file: ${error.message} Url is not valid, the download did not trigger correctly.`);
117
+ }
118
+ } finally {
119
+ if (shouldClosePage) {
120
+ await pageToDownloadFrom.close();
121
+ }
122
+ release();
123
+ }
124
+ };
125
+ exports.downloadFile = downloadFile;
@@ -0,0 +1 @@
1
+ "use strict";