donobu 2.18.4 → 2.19.0

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 (215) hide show
  1. package/dist/apis/FlowsApi.d.ts +4 -0
  2. package/dist/apis/FlowsApi.d.ts.map +1 -1
  3. package/dist/apis/FlowsApi.js +15 -1
  4. package/dist/apis/FlowsApi.js.map +1 -1
  5. package/dist/apis/SpecialFlowsApi.d.ts.map +1 -1
  6. package/dist/apis/SpecialFlowsApi.js +11 -9
  7. package/dist/apis/SpecialFlowsApi.js.map +1 -1
  8. package/dist/assets/control-panel.js +7 -1
  9. package/dist/assets/generated/parameter-schemas.json +44 -0
  10. package/dist/assets/generated/version +1 -1
  11. package/dist/assets/page-interactions-tracker.js +27 -30
  12. package/dist/bindings/PageInteractionTracker.d.ts.map +1 -1
  13. package/dist/bindings/PageInteractionTracker.js +1 -1
  14. package/dist/bindings/PageInteractionTracker.js.map +1 -1
  15. package/dist/esm/apis/FlowsApi.d.ts +4 -0
  16. package/dist/esm/apis/FlowsApi.d.ts.map +1 -1
  17. package/dist/esm/apis/FlowsApi.js +15 -1
  18. package/dist/esm/apis/FlowsApi.js.map +1 -1
  19. package/dist/esm/apis/SpecialFlowsApi.d.ts.map +1 -1
  20. package/dist/esm/apis/SpecialFlowsApi.js +11 -9
  21. package/dist/esm/apis/SpecialFlowsApi.js.map +1 -1
  22. package/dist/esm/assets/control-panel.js +7 -1
  23. package/dist/esm/assets/generated/parameter-schemas.json +44 -0
  24. package/dist/esm/assets/generated/version +1 -1
  25. package/dist/esm/assets/page-interactions-tracker.js +27 -30
  26. package/dist/esm/bindings/PageInteractionTracker.d.ts.map +1 -1
  27. package/dist/esm/bindings/PageInteractionTracker.js +1 -1
  28. package/dist/esm/bindings/PageInteractionTracker.js.map +1 -1
  29. package/dist/esm/lib/testExtension.d.ts.map +1 -1
  30. package/dist/esm/lib/testExtension.js +20 -19
  31. package/dist/esm/lib/testExtension.js.map +1 -1
  32. package/dist/esm/managers/AdminApiController.d.ts.map +1 -1
  33. package/dist/esm/managers/AdminApiController.js +1 -0
  34. package/dist/esm/managers/AdminApiController.js.map +1 -1
  35. package/dist/esm/managers/CodeGenerator.d.ts +47 -1
  36. package/dist/esm/managers/CodeGenerator.d.ts.map +1 -1
  37. package/dist/esm/managers/CodeGenerator.js +211 -19
  38. package/dist/esm/managers/CodeGenerator.js.map +1 -1
  39. package/dist/esm/managers/ControlPanel.d.ts.map +1 -1
  40. package/dist/esm/managers/ControlPanel.js +7 -5
  41. package/dist/esm/managers/ControlPanel.js.map +1 -1
  42. package/dist/esm/managers/DonobuFlow.d.ts +3 -4
  43. package/dist/esm/managers/DonobuFlow.d.ts.map +1 -1
  44. package/dist/esm/managers/DonobuFlow.js +57 -44
  45. package/dist/esm/managers/DonobuFlow.js.map +1 -1
  46. package/dist/esm/managers/DonobuFlowsManager.d.ts +58 -34
  47. package/dist/esm/managers/DonobuFlowsManager.d.ts.map +1 -1
  48. package/dist/esm/managers/DonobuFlowsManager.js +217 -64
  49. package/dist/esm/managers/DonobuFlowsManager.js.map +1 -1
  50. package/dist/esm/managers/FlowDependencyAnalyzer.d.ts +40 -0
  51. package/dist/esm/managers/FlowDependencyAnalyzer.d.ts.map +1 -0
  52. package/dist/esm/managers/FlowDependencyAnalyzer.js +236 -0
  53. package/dist/esm/managers/FlowDependencyAnalyzer.js.map +1 -0
  54. package/dist/esm/managers/ProjectStructureGenerator.d.ts +62 -0
  55. package/dist/esm/managers/ProjectStructureGenerator.d.ts.map +1 -0
  56. package/dist/esm/managers/ProjectStructureGenerator.js +234 -0
  57. package/dist/esm/managers/ProjectStructureGenerator.js.map +1 -0
  58. package/dist/esm/managers/ToolManager.d.ts.map +1 -1
  59. package/dist/esm/managers/ToolManager.js +4 -2
  60. package/dist/esm/managers/ToolManager.js.map +1 -1
  61. package/dist/esm/models/FlowMetadata.d.ts +52 -0
  62. package/dist/esm/models/FlowMetadata.d.ts.map +1 -1
  63. package/dist/esm/persistence/flows/FlowsPersistence.d.ts +11 -9
  64. package/dist/esm/persistence/flows/FlowsPersistence.d.ts.map +1 -1
  65. package/dist/esm/persistence/flows/FlowsPersistenceAwsS3.d.ts +4 -5
  66. package/dist/esm/persistence/flows/FlowsPersistenceAwsS3.d.ts.map +1 -1
  67. package/dist/esm/persistence/flows/FlowsPersistenceAwsS3.js +76 -77
  68. package/dist/esm/persistence/flows/FlowsPersistenceAwsS3.js.map +1 -1
  69. package/dist/esm/persistence/flows/FlowsPersistenceFactoryImpl.js +2 -2
  70. package/dist/esm/persistence/flows/FlowsPersistenceFactoryImpl.js.map +1 -1
  71. package/dist/esm/persistence/flows/FlowsPersistenceFilesystem.d.ts +7 -7
  72. package/dist/esm/persistence/flows/FlowsPersistenceFilesystem.d.ts.map +1 -1
  73. package/dist/esm/persistence/flows/FlowsPersistenceFilesystem.js +51 -60
  74. package/dist/esm/persistence/flows/FlowsPersistenceFilesystem.js.map +1 -1
  75. package/dist/esm/persistence/flows/FlowsPersistenceGoogleCloudStorage.d.ts +4 -5
  76. package/dist/esm/persistence/flows/FlowsPersistenceGoogleCloudStorage.d.ts.map +1 -1
  77. package/dist/esm/persistence/flows/FlowsPersistenceGoogleCloudStorage.js +40 -41
  78. package/dist/esm/persistence/flows/FlowsPersistenceGoogleCloudStorage.js.map +1 -1
  79. package/dist/esm/persistence/flows/FlowsPersistenceSqlite.d.ts +4 -4
  80. package/dist/esm/persistence/flows/FlowsPersistenceSqlite.d.ts.map +1 -1
  81. package/dist/esm/persistence/flows/FlowsPersistenceSqlite.js +40 -40
  82. package/dist/esm/persistence/flows/FlowsPersistenceSqlite.js.map +1 -1
  83. package/dist/esm/persistence/flows/FlowsPersistenceSupabase.d.ts +4 -5
  84. package/dist/esm/persistence/flows/FlowsPersistenceSupabase.d.ts.map +1 -1
  85. package/dist/esm/persistence/flows/FlowsPersistenceSupabase.js +37 -37
  86. package/dist/esm/persistence/flows/FlowsPersistenceSupabase.js.map +1 -1
  87. package/dist/esm/persistence/flows/FlowsPersistenceVolatile.d.ts +7 -7
  88. package/dist/esm/persistence/flows/FlowsPersistenceVolatile.d.ts.map +1 -1
  89. package/dist/esm/persistence/flows/FlowsPersistenceVolatile.js +35 -33
  90. package/dist/esm/persistence/flows/FlowsPersistenceVolatile.js.map +1 -1
  91. package/dist/esm/tools/AssertPageTool.d.ts +34 -0
  92. package/dist/esm/tools/AssertPageTool.d.ts.map +1 -0
  93. package/dist/esm/tools/AssertPageTool.js +156 -0
  94. package/dist/esm/tools/AssertPageTool.js.map +1 -0
  95. package/dist/esm/tools/AssertTool.js +1 -1
  96. package/dist/esm/tools/AssertTool.js.map +1 -1
  97. package/dist/esm/tools/ClickTool.d.ts.map +1 -1
  98. package/dist/esm/tools/ClickTool.js +3 -0
  99. package/dist/esm/tools/ClickTool.js.map +1 -1
  100. package/dist/esm/tools/DetectBrokenLinksTool.js +1 -1
  101. package/dist/esm/tools/DetectBrokenLinksTool.js.map +1 -1
  102. package/dist/esm/tools/ExtractGoogleStreetviewEntityDataTool.js +1 -1
  103. package/dist/esm/tools/ExtractGoogleStreetviewEntityDataTool.js.map +1 -1
  104. package/dist/esm/tools/ExtractPaymentProviderKeyTool.d.ts +47 -1
  105. package/dist/esm/tools/ExtractPaymentProviderKeyTool.d.ts.map +1 -1
  106. package/dist/esm/tools/ExtractPaymentProviderKeyTool.js +160 -25
  107. package/dist/esm/tools/ExtractPaymentProviderKeyTool.js.map +1 -1
  108. package/dist/esm/tools/SolveMfaChallenge.d.ts.map +1 -1
  109. package/dist/esm/tools/SolveMfaChallenge.js.map +1 -1
  110. package/dist/esm/utils/BrowserUtils.d.ts +52 -0
  111. package/dist/esm/utils/BrowserUtils.d.ts.map +1 -0
  112. package/dist/esm/utils/BrowserUtils.js +340 -0
  113. package/dist/esm/utils/BrowserUtils.js.map +1 -0
  114. package/dist/esm/utils/PlaywrightUtils.d.ts +15 -11
  115. package/dist/esm/utils/PlaywrightUtils.d.ts.map +1 -1
  116. package/dist/esm/utils/PlaywrightUtils.js +110 -122
  117. package/dist/esm/utils/PlaywrightUtils.js.map +1 -1
  118. package/dist/lib/autoTest.d.ts +2 -0
  119. package/dist/lib/autoTest.d.ts.map +1 -0
  120. package/dist/lib/autoTest.js +17 -0
  121. package/dist/lib/autoTest.js.map +1 -0
  122. package/dist/lib/testExtension.d.ts.map +1 -1
  123. package/dist/lib/testExtension.js +20 -19
  124. package/dist/lib/testExtension.js.map +1 -1
  125. package/dist/managers/AdminApiController.d.ts.map +1 -1
  126. package/dist/managers/AdminApiController.js +1 -0
  127. package/dist/managers/AdminApiController.js.map +1 -1
  128. package/dist/managers/CodeGenerator.d.ts +47 -1
  129. package/dist/managers/CodeGenerator.d.ts.map +1 -1
  130. package/dist/managers/CodeGenerator.js +211 -19
  131. package/dist/managers/CodeGenerator.js.map +1 -1
  132. package/dist/managers/ControlPanel.d.ts.map +1 -1
  133. package/dist/managers/ControlPanel.js +7 -5
  134. package/dist/managers/ControlPanel.js.map +1 -1
  135. package/dist/managers/DonobuFlow.d.ts +3 -4
  136. package/dist/managers/DonobuFlow.d.ts.map +1 -1
  137. package/dist/managers/DonobuFlow.js +57 -44
  138. package/dist/managers/DonobuFlow.js.map +1 -1
  139. package/dist/managers/DonobuFlowsManager.d.ts +58 -34
  140. package/dist/managers/DonobuFlowsManager.d.ts.map +1 -1
  141. package/dist/managers/DonobuFlowsManager.js +217 -64
  142. package/dist/managers/DonobuFlowsManager.js.map +1 -1
  143. package/dist/managers/FlowDependencyAnalyzer.d.ts +40 -0
  144. package/dist/managers/FlowDependencyAnalyzer.d.ts.map +1 -0
  145. package/dist/managers/FlowDependencyAnalyzer.js +236 -0
  146. package/dist/managers/FlowDependencyAnalyzer.js.map +1 -0
  147. package/dist/managers/ProjectStructureGenerator.d.ts +62 -0
  148. package/dist/managers/ProjectStructureGenerator.d.ts.map +1 -0
  149. package/dist/managers/ProjectStructureGenerator.js +234 -0
  150. package/dist/managers/ProjectStructureGenerator.js.map +1 -0
  151. package/dist/managers/ToolManager.d.ts.map +1 -1
  152. package/dist/managers/ToolManager.js +4 -2
  153. package/dist/managers/ToolManager.js.map +1 -1
  154. package/dist/models/BrowserFramework.d.ts +2 -12
  155. package/dist/models/BrowserFramework.d.ts.map +1 -1
  156. package/dist/models/BrowserFramework.js +91 -66
  157. package/dist/models/BrowserFramework.js.map +1 -1
  158. package/dist/models/FlowMetadata.d.ts +52 -0
  159. package/dist/models/FlowMetadata.d.ts.map +1 -1
  160. package/dist/persistence/flows/FlowsPersistence.d.ts +11 -9
  161. package/dist/persistence/flows/FlowsPersistence.d.ts.map +1 -1
  162. package/dist/persistence/flows/FlowsPersistenceAwsS3.d.ts +4 -5
  163. package/dist/persistence/flows/FlowsPersistenceAwsS3.d.ts.map +1 -1
  164. package/dist/persistence/flows/FlowsPersistenceAwsS3.js +76 -77
  165. package/dist/persistence/flows/FlowsPersistenceAwsS3.js.map +1 -1
  166. package/dist/persistence/flows/FlowsPersistenceFactoryImpl.js +2 -2
  167. package/dist/persistence/flows/FlowsPersistenceFactoryImpl.js.map +1 -1
  168. package/dist/persistence/flows/FlowsPersistenceFilesystem.d.ts +7 -7
  169. package/dist/persistence/flows/FlowsPersistenceFilesystem.d.ts.map +1 -1
  170. package/dist/persistence/flows/FlowsPersistenceFilesystem.js +51 -60
  171. package/dist/persistence/flows/FlowsPersistenceFilesystem.js.map +1 -1
  172. package/dist/persistence/flows/FlowsPersistenceGoogleCloudStorage.d.ts +4 -5
  173. package/dist/persistence/flows/FlowsPersistenceGoogleCloudStorage.d.ts.map +1 -1
  174. package/dist/persistence/flows/FlowsPersistenceGoogleCloudStorage.js +40 -41
  175. package/dist/persistence/flows/FlowsPersistenceGoogleCloudStorage.js.map +1 -1
  176. package/dist/persistence/flows/FlowsPersistenceSqlite.d.ts +4 -4
  177. package/dist/persistence/flows/FlowsPersistenceSqlite.d.ts.map +1 -1
  178. package/dist/persistence/flows/FlowsPersistenceSqlite.js +40 -40
  179. package/dist/persistence/flows/FlowsPersistenceSqlite.js.map +1 -1
  180. package/dist/persistence/flows/FlowsPersistenceSupabase.d.ts +4 -5
  181. package/dist/persistence/flows/FlowsPersistenceSupabase.d.ts.map +1 -1
  182. package/dist/persistence/flows/FlowsPersistenceSupabase.js +37 -37
  183. package/dist/persistence/flows/FlowsPersistenceSupabase.js.map +1 -1
  184. package/dist/persistence/flows/FlowsPersistenceVolatile.d.ts +7 -7
  185. package/dist/persistence/flows/FlowsPersistenceVolatile.d.ts.map +1 -1
  186. package/dist/persistence/flows/FlowsPersistenceVolatile.js +35 -33
  187. package/dist/persistence/flows/FlowsPersistenceVolatile.js.map +1 -1
  188. package/dist/tools/AssertPageTool.d.ts +34 -0
  189. package/dist/tools/AssertPageTool.d.ts.map +1 -0
  190. package/dist/tools/AssertPageTool.js +156 -0
  191. package/dist/tools/AssertPageTool.js.map +1 -0
  192. package/dist/tools/AssertTool.js +1 -1
  193. package/dist/tools/AssertTool.js.map +1 -1
  194. package/dist/tools/ClickTool.d.ts.map +1 -1
  195. package/dist/tools/ClickTool.js +3 -0
  196. package/dist/tools/ClickTool.js.map +1 -1
  197. package/dist/tools/DetectBrokenLinksTool.js +1 -1
  198. package/dist/tools/DetectBrokenLinksTool.js.map +1 -1
  199. package/dist/tools/ExtractGoogleStreetviewEntityDataTool.js +1 -1
  200. package/dist/tools/ExtractGoogleStreetviewEntityDataTool.js.map +1 -1
  201. package/dist/tools/ExtractPaymentProviderKeyTool.d.ts +47 -1
  202. package/dist/tools/ExtractPaymentProviderKeyTool.d.ts.map +1 -1
  203. package/dist/tools/ExtractPaymentProviderKeyTool.js +160 -25
  204. package/dist/tools/ExtractPaymentProviderKeyTool.js.map +1 -1
  205. package/dist/tools/SolveMfaChallenge.d.ts.map +1 -1
  206. package/dist/tools/SolveMfaChallenge.js.map +1 -1
  207. package/dist/utils/BrowserUtils.d.ts +52 -0
  208. package/dist/utils/BrowserUtils.d.ts.map +1 -0
  209. package/dist/utils/BrowserUtils.js +340 -0
  210. package/dist/utils/BrowserUtils.js.map +1 -0
  211. package/dist/utils/PlaywrightUtils.d.ts +15 -11
  212. package/dist/utils/PlaywrightUtils.d.ts.map +1 -1
  213. package/dist/utils/PlaywrightUtils.js +110 -122
  214. package/dist/utils/PlaywrightUtils.js.map +1 -1
  215. package/package.json +1 -1
@@ -0,0 +1,340 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.BrowserUtils = void 0;
7
+ const playwright_1 = require("playwright");
8
+ const JsonUtils_1 = require("./JsonUtils");
9
+ const InvalidParamValueException_1 = require("../exceptions/InvalidParamValueException");
10
+ const path_1 = __importDefault(require("path"));
11
+ const envVars_1 = require("../envVars");
12
+ const Logger_1 = require("./Logger");
13
+ class BrowserUtils {
14
+ /**
15
+ * Loads all the pre-canned browser device configurations from the local
16
+ * filesystem.
17
+ *
18
+ * The returned map keys the devices by their name (ex: 'Desktop Firefox').
19
+ *
20
+ * See `assets/devices.json` for details.
21
+ */
22
+ static getSupportedDevices() {
23
+ const rawDevices = JsonUtils_1.JsonUtils.readResourceAsJson(path_1.default.join('devices.json'));
24
+ if (!rawDevices) {
25
+ throw new Error('Failed to load devices configuration');
26
+ }
27
+ return new Map(Object.entries(rawDevices));
28
+ }
29
+ static async create(browserConfig, outputDir, storageState) {
30
+ const type = browserConfig.using.type;
31
+ let browser;
32
+ let browserContext;
33
+ switch (type) {
34
+ case 'device': {
35
+ ({ browser, browserContext } = await BrowserUtils.forDevice(browserConfig.using.deviceName ?? BrowserUtils.DEFAULT_DEVICE_NAME, browserConfig.using.headless ?? false, outputDir, storageState));
36
+ BrowserUtils.patchClose(browserContext, () => browser.close());
37
+ break;
38
+ }
39
+ case 'remoteInstance': {
40
+ ({ browser, browserContext } = await BrowserUtils.forRemoteBrowser(browserConfig.using.url, outputDir, storageState));
41
+ BrowserUtils.patchClose(browserContext, () => browser.close());
42
+ break;
43
+ }
44
+ case 'browserBase': {
45
+ let browserBaseData;
46
+ ({ browser, browserContext, browserBaseData } =
47
+ await BrowserUtils.forBrowserBase(browserConfig.using.sessionArgs, outputDir, storageState));
48
+ BrowserUtils.patchClose(browserContext, async () => {
49
+ try {
50
+ await browser.close();
51
+ }
52
+ catch (_error) {
53
+ // Ignore, the browser may have already been closed and that is fine.
54
+ }
55
+ const body = {
56
+ projectId: browserBaseData.projectId,
57
+ status: 'REQUEST_RELEASE',
58
+ };
59
+ const password = process.env[envVars_1.ENV_VAR_NAMES.BROWSERBASE_API_KEY] ?? '';
60
+ const options = {
61
+ method: 'POST',
62
+ headers: {
63
+ 'X-BB-API-Key': password,
64
+ 'Content-Type': 'application/json',
65
+ },
66
+ body: JSON.stringify(body),
67
+ };
68
+ try {
69
+ await fetch(`https://api.browserbase.com/v1/sessions/${browserBaseData.id}`, options);
70
+ }
71
+ catch (error) {
72
+ // Ignore, BrowserBase sessions expire automatically anyway.
73
+ Logger_1.appLogger.warn('Failed to release BrowserBase session', error);
74
+ }
75
+ });
76
+ break;
77
+ }
78
+ default: {
79
+ throw new InvalidParamValueException_1.InvalidParamValueException('type', type);
80
+ }
81
+ }
82
+ await BrowserUtils.attachSessionStorageToBrowserContext(browserContext, storageState);
83
+ return browserContext;
84
+ }
85
+ /**
86
+ * Gets the browser storage state including cookies, localStorage, and sessionStorage.
87
+ *
88
+ * @param browserContext The browser context to extract storage state from.
89
+ * @returns A promise that resolves to the complete browser storage state.
90
+ */
91
+ static async getBrowserStorageState(browserContext) {
92
+ let result;
93
+ try {
94
+ // First get the standard storage state (cookies and localStorage)
95
+ result = await browserContext.storageState({
96
+ indexedDB: true,
97
+ });
98
+ }
99
+ catch (error) {
100
+ Logger_1.appLogger.warn('Failed to get storage state with indexedDB, falling back to cookies only', error);
101
+ result = await browserContext.storageState({
102
+ indexedDB: false,
103
+ });
104
+ }
105
+ // Get all pages in the context
106
+ const pages = browserContext.pages();
107
+ // Process each page to collect sessionStorage data
108
+ for (const page of pages) {
109
+ try {
110
+ // Get the origin for the current page
111
+ const pageOrigin = new URL(page.url()).origin;
112
+ // Find if we already have an entry for this origin
113
+ let originEntry = result.origins.find((entry) => entry.origin === pageOrigin);
114
+ // If not, create a new entry
115
+ if (!originEntry) {
116
+ originEntry = {
117
+ origin: pageOrigin,
118
+ localStorage: [],
119
+ sessionStorage: [],
120
+ };
121
+ result.origins.push(originEntry);
122
+ }
123
+ else if (!('sessionStorage' in originEntry)) {
124
+ // If the entry exists but doesn't have sessionStorage yet, add the property
125
+ originEntry.sessionStorage = [];
126
+ }
127
+ // Extract sessionStorage from the page
128
+ const sessionStorageItems = await page.evaluate(() => {
129
+ const items = [];
130
+ for (let i = 0; i < sessionStorage.length; i++) {
131
+ const name = sessionStorage.key(i);
132
+ if (name) {
133
+ items.push({
134
+ name,
135
+ value: sessionStorage.getItem(name) || '',
136
+ });
137
+ }
138
+ }
139
+ return items;
140
+ });
141
+ // Add sessionStorage items to the origin entry
142
+ originEntry.sessionStorage = sessionStorageItems;
143
+ }
144
+ catch (error) {
145
+ Logger_1.appLogger.warn(`Failed to extract sessionStorage for page: ${page.url()}`, error);
146
+ // Skip pages that might have navigation errors or are about:blank.
147
+ continue;
148
+ }
149
+ }
150
+ return result;
151
+ }
152
+ /**
153
+ * Connects to an existing Chromium browser using the Chrome DevTools Protocol (CDP) at the given
154
+ * URL.
155
+ */
156
+ static async forRemoteBrowser(remoteBrowserInstanceUrl, outputDir, storageState) {
157
+ try {
158
+ const browser = await playwright_1.chromium.connectOverCDP(remoteBrowserInstanceUrl);
159
+ try {
160
+ const contextOptions = {
161
+ recordVideo: { dir: outputDir },
162
+ };
163
+ if (storageState) {
164
+ contextOptions.storageState = storageState;
165
+ }
166
+ return {
167
+ browser: browser,
168
+ browserContext: await browser.newContext(contextOptions),
169
+ };
170
+ }
171
+ catch (error) {
172
+ await browser.close();
173
+ throw error;
174
+ }
175
+ }
176
+ catch (_) {
177
+ throw new InvalidParamValueException_1.InvalidParamValueException('remoteBrowserInstanceUrl', remoteBrowserInstanceUrl);
178
+ }
179
+ }
180
+ /**
181
+ * If {@link storageState} is present, must be an object conforming to what is returned by
182
+ * {@link BrowserContext.storageState()}.
183
+ */
184
+ static async forDevice(deviceName, headless, outputDir, storageState) {
185
+ const device = BrowserUtils.getSupportedDevices().get(deviceName);
186
+ if (!device) {
187
+ throw new InvalidParamValueException_1.InvalidParamValueException('deviceName', deviceName);
188
+ }
189
+ const contextOptions = {
190
+ userAgent: device.userAgent,
191
+ recordVideo: {
192
+ dir: outputDir,
193
+ size: {
194
+ width: device.viewport?.width ?? 1280,
195
+ height: device.viewport?.height ?? 720,
196
+ },
197
+ },
198
+ viewport: {
199
+ width: device.viewport?.width ?? 1280,
200
+ height: device.viewport?.height ?? 720,
201
+ },
202
+ screen: {
203
+ width: device.screen?.width ?? device.viewport?.width ?? 1280,
204
+ height: device.screen?.height ?? device.viewport?.height ?? 720,
205
+ },
206
+ deviceScaleFactor: device.deviceScaleFactor ?? 1.0,
207
+ isMobile: device.isMobile ?? false,
208
+ hasTouch: device.hasTouch ?? false,
209
+ };
210
+ if (storageState) {
211
+ contextOptions.storageState = storageState;
212
+ }
213
+ const launchOptions = {
214
+ headless,
215
+ args: [
216
+ '--ignore-certificate-errors',
217
+ '--disable-blink-features=AutomationControlled',
218
+ ],
219
+ };
220
+ let browser;
221
+ switch (device.defaultBrowserType.toLowerCase()) {
222
+ case 'firefox':
223
+ browser = await playwright_1.firefox.launch(launchOptions);
224
+ break;
225
+ case 'chromium':
226
+ browser = await playwright_1.chromium.launch(launchOptions);
227
+ break;
228
+ case 'chrome':
229
+ browser = await playwright_1.chromium.launch({
230
+ ...launchOptions,
231
+ channel: 'chrome',
232
+ });
233
+ break;
234
+ case 'webkit':
235
+ case 'ios':
236
+ browser = await playwright_1.webkit.launch(launchOptions);
237
+ break;
238
+ default:
239
+ throw new InvalidParamValueException_1.InvalidParamValueException('browserType', device.defaultBrowserType);
240
+ }
241
+ try {
242
+ const browserContext = await browser.newContext(contextOptions);
243
+ return { browser, browserContext };
244
+ }
245
+ catch (error) {
246
+ await browser.close();
247
+ throw error;
248
+ }
249
+ }
250
+ /**
251
+ * Creates a BrowserBase session. Using this method requires the
252
+ * BROWSERBASE_API_KEY environment variable to be set.
253
+ *
254
+ * The returned browserBaseData object conforms to the response of the session
255
+ * creation API endpoint. See...
256
+ * https://docs.browserbase.com/reference/api/create-a-session#response-id
257
+ */
258
+ static async forBrowserBase(sessionArgs, outputDir, storageState) {
259
+ const browserBaseData = await BrowserUtils.establishBrowserBaseSession(sessionArgs);
260
+ const browser = await playwright_1.chromium.connectOverCDP(browserBaseData.connectUrl);
261
+ const contextOptions = {
262
+ recordVideo: { dir: outputDir },
263
+ };
264
+ if (storageState) {
265
+ contextOptions.storageState = storageState;
266
+ }
267
+ return {
268
+ browser: browser,
269
+ browserContext: await browser.newContext(contextOptions),
270
+ browserBaseData: browserBaseData,
271
+ };
272
+ }
273
+ /**
274
+ * Establishes a BrowserBase session. The returned structure matches the
275
+ * response structore from the BrowserBase session API. See...
276
+ * https://docs.browserbase.com/reference/api/create-a-session#response-id
277
+ */
278
+ static async establishBrowserBaseSession(sessionArgs) {
279
+ const password = process.env[envVars_1.ENV_VAR_NAMES.BROWSERBASE_API_KEY];
280
+ if (!password) {
281
+ throw new InvalidParamValueException_1.InvalidParamValueException(envVars_1.ENV_VAR_NAMES.BROWSERBASE_API_KEY, null);
282
+ }
283
+ const options = {
284
+ method: 'POST',
285
+ headers: { 'X-BB-API-Key': password, 'Content-Type': 'application/json' },
286
+ body: JSON.stringify(sessionArgs),
287
+ };
288
+ const browserBaseData = await fetch('https://api.browserbase.com/v1/sessions', options).then((response) => response.json());
289
+ if (browserBaseData.error) {
290
+ throw new InvalidParamValueException_1.InvalidParamValueException(envVars_1.ENV_VAR_NAMES.BROWSERBASE_API_KEY, '(redacted)', `${browserBaseData.error}: ${browserBaseData.message}`);
291
+ }
292
+ return browserBaseData;
293
+ }
294
+ static async attachSessionStorageToBrowserContext(browserContext, storageState) {
295
+ // Add init script to restore sessionStorage if storage state is provided
296
+ if (storageState && storageState.origins) {
297
+ // Transform the storage state to map origins to their sessionStorage
298
+ const sessionStorageByOrigin = {};
299
+ for (const origin of storageState.origins) {
300
+ if (origin.sessionStorage && origin.sessionStorage.length > 0) {
301
+ // Create a key-value map for this origin's sessionStorage
302
+ const sessionStorageMap = {};
303
+ for (const item of origin.sessionStorage) {
304
+ sessionStorageMap[item.name] = item.value;
305
+ }
306
+ sessionStorageByOrigin[origin.origin] = sessionStorageMap;
307
+ }
308
+ }
309
+ // Add the init script to restore sessionStorage based on the page's origin
310
+ await browserContext.addInitScript((storageData) => {
311
+ // Get current origin
312
+ const currentOrigin = window.location.origin;
313
+ // Check if we have sessionStorage data for this origin
314
+ if (storageData[currentOrigin]) {
315
+ // Restore the sessionStorage items
316
+ for (const [key, value] of Object.entries(storageData[currentOrigin])) {
317
+ window.sessionStorage.setItem(key, value);
318
+ }
319
+ console.log(`Restored ${Object.keys(storageData[currentOrigin]).length} sessionStorage items for ${currentOrigin}`);
320
+ }
321
+ }, sessionStorageByOrigin);
322
+ }
323
+ }
324
+ static patchClose(ctx, extra) {
325
+ const original = ctx.close.bind(ctx);
326
+ ctx.close = async (...args) => {
327
+ try {
328
+ await original(...args);
329
+ }
330
+ catch { }
331
+ try {
332
+ await extra();
333
+ }
334
+ catch { }
335
+ };
336
+ }
337
+ }
338
+ exports.BrowserUtils = BrowserUtils;
339
+ BrowserUtils.DEFAULT_DEVICE_NAME = 'Desktop Chromium';
340
+ //# sourceMappingURL=BrowserUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BrowserUtils.js","sourceRoot":"","sources":["../../../src/utils/BrowserUtils.ts"],"names":[],"mappings":"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"}
@@ -28,7 +28,21 @@ export declare class PlaywrightUtils {
28
28
  * Note that if the Donobu control panel is present in the page, it will be
29
29
  * excluded from the screenshot.
30
30
  */
31
- static takeScreenshot(page: Page, type?: 'png' | 'jpeg'): Promise<Buffer>;
31
+ static takeViewportScreenshot(page: Page, type?: 'png' | 'jpeg'): Promise<Buffer>;
32
+ /**
33
+ * Captures up to three screenshots of the given page.
34
+ *
35
+ * - `viewport` : exact current viewport
36
+ * - `aboveViewport` : up to half-viewport preview just above the fold (cropped to exclude main viewport)
37
+ * - `belowViewport` : up to half-viewport preview just below the fold (cropped to exclude main viewport)
38
+ *
39
+ * All images are returned as JPEG buffers.
40
+ */
41
+ static takePageScreenshots(page: Page): Promise<{
42
+ aboveViewport: Buffer | null;
43
+ viewport: Buffer;
44
+ belowViewport: Buffer | null;
45
+ }>;
32
46
  /**
33
47
  * Generate valid selectors for the given element. The generated selectors are
34
48
  * in a priority order based on their ability to identify the given element.
@@ -59,15 +73,5 @@ export declare class PlaywrightUtils {
59
73
  * it is logged and ignored. If page is null, this function has no effect.
60
74
  */
61
75
  static waitForPageStability(page: Page | null): Promise<void>;
62
- /**
63
- * Takes a screenshot of the webpage as if it were scrolled down by one viewport.
64
- * If the page cannot be scrolled as a whole, tries to find and scroll individual
65
- * scrollable elements on the page. After taking the screenshot, it reverts to
66
- * the original scroll position.
67
- *
68
- * @param page The Playwright Page to take a screenshot of
69
- * @returns An image buffer of the scrolled down view, or undefined if scrolling isn't possible
70
- */
71
- static getScrolledDownScreenShot(page: Page): Promise<Buffer | undefined>;
72
76
  }
73
77
  //# sourceMappingURL=PlaywrightUtils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"PlaywrightUtils.d.ts","sourceRoot":"","sources":["../../../src/utils/PlaywrightUtils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAUlD;;;GAGG;AACH,qBAAa,eAAe;IAC1B;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,iCAAiC,CACkB;IAE3E;;;;;OAKG;IACH,gBAAuB,oCAAoC,SACmB;IAE9E;;;;;;;;OAQG;WACiB,cAAc,CAChC,IAAI,EAAE,IAAI,EACV,IAAI,GAAE,KAAK,GAAG,MAAe,GAC5B,OAAO,CAAC,MAAM,CAAC;IAgBlB;;;;;;OAMG;WACiB,iBAAiB,CAAC,OAAO,EAAE;QAC7C,QAAQ,EAAE,CAAC,YAAY,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;KAC/C,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAMrB;;;;;OAKG;WACiB,wBAAwB,CAC1C,cAAc,EAAE,cAAc,GAC7B,OAAO,CAAC,IAAI,CAAC;IAWhB;;;OAGG;WACW,iBAAiB,CAAC,KAAK,EAAE,GAAG,GAAG,OAAO;WAkBhC,4BAA4B,IAAI,OAAO,CAAC,IAAI,CAAC;WAI7C,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAgDnE;;;;OAIG;WACiB,oBAAoB,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAwB1E;;;;;;;;OAQG;WACiB,yBAAyB,CAC3C,IAAI,EAAE,IAAI,GACT,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;CA4I/B"}
1
+ {"version":3,"file":"PlaywrightUtils.d.ts","sourceRoot":"","sources":["../../../src/utils/PlaywrightUtils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAUlD;;;GAGG;AACH,qBAAa,eAAe;IAC1B;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,iCAAiC,CACkB;IAE3E;;;;;OAKG;IACH,gBAAuB,oCAAoC,SACmB;IAE9E;;;;;;;;OAQG;WACiB,sBAAsB,CACxC,IAAI,EAAE,IAAI,EACV,IAAI,GAAE,KAAK,GAAG,MAAe,GAC5B,OAAO,CAAC,MAAM,CAAC;IAgBlB;;;;;;;;OAQG;WACiB,mBAAmB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC;QAC3D,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;QAC7B,QAAQ,EAAE,MAAM,CAAC;QACjB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;KAC9B,CAAC;IA8HF;;;;;;OAMG;WACiB,iBAAiB,CAAC,OAAO,EAAE;QAC7C,QAAQ,EAAE,CAAC,YAAY,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;KAC/C,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAMrB;;;;;OAKG;WACiB,wBAAwB,CAC1C,cAAc,EAAE,cAAc,GAC7B,OAAO,CAAC,IAAI,CAAC;IAWhB;;;OAGG;WACW,iBAAiB,CAAC,KAAK,EAAE,GAAG,GAAG,OAAO;WAkBhC,4BAA4B,IAAI,OAAO,CAAC,IAAI,CAAC;WAI7C,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAgDnE;;;;OAIG;WACiB,oBAAoB,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;CAuB3E"}
@@ -26,7 +26,7 @@ class PlaywrightUtils {
26
26
  * Note that if the Donobu control panel is present in the page, it will be
27
27
  * excluded from the screenshot.
28
28
  */
29
- static async takeScreenshot(page, type = 'jpeg') {
29
+ static async takeViewportScreenshot(page, type = 'jpeg') {
30
30
  try {
31
31
  const style = `#${ControlPanel_1.ControlPanel.DONOBU_CONTROL_PANEL_ELEMENT_ID} { display: none !important; }`;
32
32
  return await page.screenshot({
@@ -43,6 +43,115 @@ class PlaywrightUtils {
43
43
  }
44
44
  }
45
45
  }
46
+ /**
47
+ * Captures up to three screenshots of the given page.
48
+ *
49
+ * - `viewport` : exact current viewport
50
+ * - `aboveViewport` : up to half-viewport preview just above the fold (cropped to exclude main viewport)
51
+ * - `belowViewport` : up to half-viewport preview just below the fold (cropped to exclude main viewport)
52
+ *
53
+ * All images are returned as JPEG buffers.
54
+ */
55
+ static async takePageScreenshots(page) {
56
+ const screenshotStyleOverride = `#${ControlPanel_1.ControlPanel.DONOBU_CONTROL_PANEL_ELEMENT_ID} { display: none !important; }`;
57
+ // Take the screenshot of the current viewport immediately – this is always available.
58
+ const viewportBuffer = await PlaywrightUtils.takeViewportScreenshot(page, 'jpeg');
59
+ // If the viewport size is not available we cannot reliably scroll.
60
+ const viewportSize = page.viewportSize();
61
+ if (!viewportSize) {
62
+ return {
63
+ aboveViewport: null,
64
+ viewport: viewportBuffer,
65
+ belowViewport: null,
66
+ };
67
+ }
68
+ const viewportHeight = viewportSize.height;
69
+ const halfViewport = Math.floor(viewportHeight / 2);
70
+ // Capture original scroll position & page dimensions so we can both
71
+ // determine if we *can* scroll and later restore state.
72
+ const { originalScrollY, scrollHeight } = await page.evaluate(() => {
73
+ return {
74
+ originalScrollY: window.scrollY || window.pageYOffset || 0,
75
+ scrollHeight: document.documentElement.scrollHeight ||
76
+ document.body.scrollHeight ||
77
+ 0,
78
+ };
79
+ });
80
+ let aboveBuffer = null;
81
+ let belowBuffer = null;
82
+ // Always wrap scrolling logic with try/finally so that we restore the
83
+ // initial scroll position even when an unexpected error occurs.
84
+ try {
85
+ /************************************************************
86
+ * Capture the area *above* the current viewport ("just above the fold")
87
+ ************************************************************/
88
+ if (originalScrollY > 0) {
89
+ const targetY = Math.max(0, originalScrollY - halfViewport);
90
+ await page.evaluate((y) => window.scrollTo(0, y), targetY);
91
+ // Give the browser a tiny bit of time – many sites throttle paint.
92
+ await page.waitForTimeout(100);
93
+ // Calculate the non-overlapping portion to capture
94
+ const overlapPixels = Math.max(0, targetY + viewportHeight - originalScrollY);
95
+ const cropHeight = viewportHeight - overlapPixels;
96
+ if (cropHeight > 0) {
97
+ // Use Playwright's clip parameter to capture only the non-overlapping portion
98
+ aboveBuffer = await page.screenshot({
99
+ style: screenshotStyleOverride,
100
+ type: 'jpeg',
101
+ clip: {
102
+ x: 0,
103
+ y: 0,
104
+ width: viewportSize.width,
105
+ height: cropHeight,
106
+ },
107
+ });
108
+ }
109
+ }
110
+ /************************************************************
111
+ * Capture the area *below* the current viewport ("just below the fold")
112
+ ************************************************************/
113
+ if (originalScrollY + viewportHeight < scrollHeight) {
114
+ const targetY = Math.min(scrollHeight - viewportHeight, originalScrollY + halfViewport);
115
+ await page.evaluate((y) => window.scrollTo(0, y), targetY);
116
+ await page.waitForTimeout(100);
117
+ // Calculate the non-overlapping portion to capture
118
+ const overlapPixels = Math.max(0, originalScrollY + viewportHeight - targetY);
119
+ const cropY = overlapPixels;
120
+ const cropHeight = viewportHeight - overlapPixels;
121
+ if (cropHeight > 0) {
122
+ // Use Playwright's clip parameter to capture only the non-overlapping portion
123
+ belowBuffer = await page.screenshot({
124
+ style: screenshotStyleOverride,
125
+ type: 'jpeg',
126
+ clip: {
127
+ x: 0,
128
+ y: cropY,
129
+ width: viewportSize.width,
130
+ height: cropHeight,
131
+ },
132
+ });
133
+ }
134
+ }
135
+ }
136
+ finally {
137
+ // Always attempt to restore the page to its initial scroll position so
138
+ // that callers see *no* side‑effects.
139
+ try {
140
+ if ((await page.evaluate(() => window.scrollY)) !== originalScrollY) {
141
+ await page.evaluate((y) => window.scrollTo(0, y), originalScrollY);
142
+ await page.waitForTimeout(50);
143
+ }
144
+ }
145
+ catch (restoreError) {
146
+ Logger_1.appLogger.error(`Failed to restore scroll position for page ${page.url()}`, restoreError);
147
+ }
148
+ }
149
+ return {
150
+ aboveViewport: aboveBuffer,
151
+ viewport: viewportBuffer,
152
+ belowViewport: belowBuffer,
153
+ };
154
+ }
46
155
  /**
47
156
  * Generate valid selectors for the given element. The generated selectors are
48
157
  * in a priority order based on their ability to identify the given element.
@@ -156,127 +265,6 @@ class PlaywrightUtils {
156
265
  }
157
266
  }
158
267
  }
159
- /**
160
- * Takes a screenshot of the webpage as if it were scrolled down by one viewport.
161
- * If the page cannot be scrolled as a whole, tries to find and scroll individual
162
- * scrollable elements on the page. After taking the screenshot, it reverts to
163
- * the original scroll position.
164
- *
165
- * @param page The Playwright Page to take a screenshot of
166
- * @returns An image buffer of the scrolled down view, or undefined if scrolling isn't possible
167
- */
168
- static async getScrolledDownScreenShot(page) {
169
- try {
170
- // Get the current scroll position and viewport height
171
- const { scrollX, scrollY, viewportHeight } = await page.evaluate(() => {
172
- return {
173
- scrollX: window.scrollX,
174
- scrollY: window.scrollY,
175
- viewportHeight: window.innerHeight,
176
- };
177
- });
178
- // Step 1: Try to scroll the window down by one viewport
179
- await page.evaluate((viewportHeight) => {
180
- window.scrollBy(0, viewportHeight);
181
- }, viewportHeight);
182
- // Check if the page actually scrolled
183
- const newScrollY = await page.evaluate(() => window.scrollY);
184
- // If the window scrolled successfully, take the screenshot and return
185
- if (newScrollY > scrollY) {
186
- // Take the screenshot
187
- const screenshot = await PlaywrightUtils.takeScreenshot(page);
188
- // Scroll back to the original position
189
- await page.evaluate(([x, y]) => {
190
- window.scrollTo(x, y);
191
- }, [scrollX, scrollY]);
192
- return screenshot;
193
- }
194
- // Step 2: If window didn't scroll, try to find scrollable elements
195
- const didScrollElement = await page.evaluate(() => {
196
- // Find all potentially scrollable elements
197
- function findScrollableElements() {
198
- const allElements = document.querySelectorAll('*');
199
- const scrollableElements = [];
200
- allElements.forEach((el) => {
201
- const style = window.getComputedStyle(el);
202
- const overflowY = style.getPropertyValue('overflow-y');
203
- const overflowX = style.getPropertyValue('overflow-x');
204
- const overflow = style.getPropertyValue('overflow');
205
- // Check if the element has scrollable properties
206
- if (overflowY === 'auto' ||
207
- overflowY === 'scroll' ||
208
- overflowX === 'auto' ||
209
- overflowX === 'scroll' ||
210
- overflow === 'auto' ||
211
- overflow === 'scroll') {
212
- // Additional check to see if the element actually has content to scroll
213
- const scrollHeight = el.scrollHeight;
214
- const clientHeight = el.clientHeight;
215
- if (scrollHeight > clientHeight) {
216
- scrollableElements.push({
217
- element: el,
218
- area: el.clientWidth * el.clientHeight, // Calculate area for sorting
219
- scrollTop: el.scrollTop, // Save original scroll position
220
- });
221
- }
222
- }
223
- });
224
- return scrollableElements;
225
- }
226
- // Find and sort scrollable elements by size (largest first)
227
- const scrollableElements = findScrollableElements().sort((a, b) => b.area - a.area);
228
- let didScroll = false;
229
- // Try to scroll each element until one successfully scrolls
230
- for (const { element } of scrollableElements) {
231
- const originalScrollTop = element.scrollTop;
232
- // Try to scroll down by the element's client height
233
- element.scrollTop += element.clientHeight;
234
- // Check if scrolling was successful
235
- if (element.scrollTop > originalScrollTop) {
236
- didScroll = true;
237
- // Save the element in the window object so we can access it later
238
- // @ts-ignore
239
- window.__lastScrolledElement = element;
240
- // @ts-ignore
241
- window.__lastScrolledElementOriginalPosition = originalScrollTop;
242
- break;
243
- }
244
- }
245
- return didScroll;
246
- });
247
- // If no element could be scrolled, return undefined
248
- if (!didScrollElement) {
249
- return undefined;
250
- }
251
- // Take a screenshot after scrolling the element
252
- const screenshot = await PlaywrightUtils.takeScreenshot(page);
253
- // Restore the original scroll position of the element
254
- await page.evaluate(() => {
255
- if (
256
- // @ts-ignore
257
- window.__lastScrolledElement &&
258
- // @ts-ignore
259
- window.__lastScrolledElementOriginalPosition !== undefined) {
260
- // @ts-ignore
261
- window.__lastScrolledElement.scrollTop = window.__lastScrolledElementOriginalPosition;
262
- // Clean up
263
- // @ts-ignore
264
- delete window.__lastScrolledElement;
265
- // @ts-ignore
266
- delete window.__lastScrolledElementOriginalPosition;
267
- }
268
- });
269
- return screenshot;
270
- }
271
- catch (error) {
272
- if (PlaywrightUtils.isPageClosedError(error)) {
273
- throw new PageClosedException_1.PageClosedException();
274
- }
275
- else {
276
- throw error;
277
- }
278
- }
279
- }
280
268
  }
281
269
  exports.PlaywrightUtils = PlaywrightUtils;
282
270
  /**