@stubber/virtual-worker 1.6.0 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.env_dev
CHANGED
|
@@ -4,8 +4,8 @@ import { create_error_technical } from "#app/functions/create_error_technical.js
|
|
|
4
4
|
import { create_success } from "#app/functions/create_success.js";
|
|
5
5
|
import { get_chromium_page } from "../../helpers/get_chromium_page.js";
|
|
6
6
|
import * as playwright from "playwright";
|
|
7
|
+
import { upload_files } from "../file-server/upload_files.js";
|
|
7
8
|
|
|
8
|
-
const DEFAULT_TIMEOUT_MS = 30000;
|
|
9
9
|
const MAX_SERIALIZATION_DEPTH = 6;
|
|
10
10
|
const MAX_SERIALIZATION_KEYS = 100;
|
|
11
11
|
const async_function_constructor = async function () {}.constructor;
|
|
@@ -29,7 +29,6 @@ const async_function_constructor = async function () {}.constructor;
|
|
|
29
29
|
* @param {Object} params
|
|
30
30
|
* @param {string} params.code - The Playwright code to execute
|
|
31
31
|
* @param {Object} [params.args] - Optional arguments to pass to the code
|
|
32
|
-
* @param {number} [params.timeout_ms] - Optional timeout for code execution in milliseconds (default: 30000)
|
|
33
32
|
*
|
|
34
33
|
*
|
|
35
34
|
*/
|
|
@@ -46,17 +45,12 @@ export const browser_execute = async (params, stubber_context) => {
|
|
|
46
45
|
const page = page_result.payload;
|
|
47
46
|
const context = page.context();
|
|
48
47
|
const browser = context.browser();
|
|
49
|
-
const timeout_ms = normalize_timeout(params.timeout_ms);
|
|
50
48
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
message: "timeout_ms must be a non-negative number",
|
|
54
|
-
details: { timeout_ms: params.timeout_ms },
|
|
55
|
-
});
|
|
56
|
-
}
|
|
49
|
+
const logs = [];
|
|
50
|
+
const attachments = [];
|
|
57
51
|
|
|
58
52
|
try {
|
|
59
|
-
const
|
|
53
|
+
const uploadFile = create_upload_file(stubber_context, attachments);
|
|
60
54
|
const execution_console = create_execution_console(logs);
|
|
61
55
|
const execution = run_user_code(params.code, {
|
|
62
56
|
page,
|
|
@@ -66,6 +60,7 @@ export const browser_execute = async (params, stubber_context) => {
|
|
|
66
60
|
params,
|
|
67
61
|
args: params.args || {},
|
|
68
62
|
console: execution_console,
|
|
63
|
+
uploadFile,
|
|
69
64
|
setTimeout,
|
|
70
65
|
clearTimeout,
|
|
71
66
|
setInterval,
|
|
@@ -78,7 +73,7 @@ export const browser_execute = async (params, stubber_context) => {
|
|
|
78
73
|
AbortSignal,
|
|
79
74
|
});
|
|
80
75
|
|
|
81
|
-
const raw_result = await
|
|
76
|
+
const raw_result = await Promise.resolve(execution);
|
|
82
77
|
const result = serialize_for_payload(raw_result);
|
|
83
78
|
|
|
84
79
|
return create_success({
|
|
@@ -86,13 +81,44 @@ export const browser_execute = async (params, stubber_context) => {
|
|
|
86
81
|
payload: {
|
|
87
82
|
result,
|
|
88
83
|
logs,
|
|
84
|
+
attachments,
|
|
89
85
|
},
|
|
90
86
|
});
|
|
91
87
|
} catch (error) {
|
|
92
|
-
|
|
88
|
+
const technical_error = create_error_technical(error);
|
|
89
|
+
technical_error.error.details.logs = logs;
|
|
90
|
+
technical_error.error.details.attachments = attachments;
|
|
91
|
+
return technical_error;
|
|
93
92
|
}
|
|
94
93
|
};
|
|
95
94
|
|
|
95
|
+
const create_upload_file = (stubber_context, attachments) => {
|
|
96
|
+
return async (screenshot_path) => {
|
|
97
|
+
if (!screenshot_path) {
|
|
98
|
+
return create_error_conceptual({ message: "No screenshot path provided for upload" });
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const upload_result = await upload_files({ files: [screenshot_path] }, stubber_context);
|
|
102
|
+
if (!upload_result.success) {
|
|
103
|
+
return upload_result;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const uploaded_files = upload_result.payload.uploaded_files;
|
|
107
|
+
const file_info = uploaded_files.length > 0 ? uploaded_files[0] : null;
|
|
108
|
+
|
|
109
|
+
if (file_info && attachments) {
|
|
110
|
+
attachments.push(file_info);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return create_success({
|
|
114
|
+
message: "Screenshot uploaded successfully",
|
|
115
|
+
payload: {
|
|
116
|
+
file_info,
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
};
|
|
120
|
+
};
|
|
121
|
+
|
|
96
122
|
/**
|
|
97
123
|
* @param {string} code
|
|
98
124
|
* @param {object} execution_scope
|
|
@@ -105,48 +131,6 @@ const run_user_code = (code, execution_scope) => {
|
|
|
105
131
|
return execute(...parameter_values);
|
|
106
132
|
};
|
|
107
133
|
|
|
108
|
-
/**
|
|
109
|
-
* @param {unknown} timeout_ms
|
|
110
|
-
* @returns {number|null}
|
|
111
|
-
*/
|
|
112
|
-
const normalize_timeout = (timeout_ms) => {
|
|
113
|
-
if (!timeout_ms) {
|
|
114
|
-
return DEFAULT_TIMEOUT_MS;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
const normalized = Number(timeout_ms);
|
|
118
|
-
|
|
119
|
-
if (Number.isNaN(normalized) || normalized < 0) {
|
|
120
|
-
return null;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
return normalized;
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* @param {Promise<unknown>} promise
|
|
128
|
-
* @param {number} timeout_ms
|
|
129
|
-
*/
|
|
130
|
-
const with_timeout = async (promise, timeout_ms) => {
|
|
131
|
-
if (timeout_ms === 0) {
|
|
132
|
-
return await promise;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
let timeout_id;
|
|
136
|
-
|
|
137
|
-
const timeout_promise = new Promise((_, reject) => {
|
|
138
|
-
timeout_id = setTimeout(() => {
|
|
139
|
-
reject(new Error(`Playwright code execution timed out after ${timeout_ms}ms`));
|
|
140
|
-
}, timeout_ms);
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
try {
|
|
144
|
-
return await Promise.race([promise, timeout_promise]);
|
|
145
|
-
} finally {
|
|
146
|
-
clearTimeout(timeout_id);
|
|
147
|
-
}
|
|
148
|
-
};
|
|
149
|
-
|
|
150
134
|
/**
|
|
151
135
|
* @param {Array<{ level: string, args: unknown[] }>} logs
|
|
152
136
|
*/
|
|
@@ -168,9 +152,6 @@ const create_execution_console = (logs) => {
|
|
|
168
152
|
const log_execution = (level, args, logs) => {
|
|
169
153
|
const serialized_args = args.map((arg) => serialize_for_payload(arg));
|
|
170
154
|
logs.push({ level, args: serialized_args });
|
|
171
|
-
|
|
172
|
-
const logger = console[level] || console.log;
|
|
173
|
-
logger("[browser_execute]", ...serialized_args);
|
|
174
155
|
};
|
|
175
156
|
|
|
176
157
|
/**
|
|
@@ -72,11 +72,14 @@ export const upload_files = async (params, _stubber) => {
|
|
|
72
72
|
});
|
|
73
73
|
|
|
74
74
|
if (!response.ok) {
|
|
75
|
-
let error_payload
|
|
75
|
+
let error_payload;
|
|
76
|
+
|
|
77
|
+
const raw = await response.text();
|
|
78
|
+
|
|
76
79
|
try {
|
|
77
|
-
error_payload =
|
|
78
|
-
} catch
|
|
79
|
-
error_payload = { raw_error:
|
|
80
|
+
error_payload = JSON.parse(raw);
|
|
81
|
+
} catch {
|
|
82
|
+
error_payload = { raw_error: raw };
|
|
80
83
|
}
|
|
81
84
|
|
|
82
85
|
return create_error_conceptual({
|
|
@@ -41,6 +41,7 @@ export const get_chromium_page = async (params, stubber_context) => {
|
|
|
41
41
|
headless: headless === true || headless === "true",
|
|
42
42
|
// eslint-disable-next-line id-match
|
|
43
43
|
slowMo: slow_mo,
|
|
44
|
+
// executablePath: "/usr/bin/google-chrome",
|
|
44
45
|
});
|
|
45
46
|
browser.on("disconnected", () => {
|
|
46
47
|
console.log("Chromium browser disconnected. Cleaning up browser instance.");
|
|
@@ -25,7 +25,7 @@ stubber-virtual-worker-apikey: {{apiKey}}
|
|
|
25
25
|
"args": {
|
|
26
26
|
"selector": "h1"
|
|
27
27
|
},
|
|
28
|
-
"code": "const title = await page.title()
|
|
28
|
+
"code": "const title = await page.title();const headings = await page.locator(args.selector).allInnerTexts();const screenshotPath = `./screenshot-${Date.now()}.png`;await page.screenshot({ path: screenshotPath, fullPage: true });const upload = await uploadScreenshot(screenshotPath);console.log({ title, headings, upload });return {title,headings,url: page.url(),screenshotPath};"
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
}
|