@stubber/virtual-worker 1.3.0 → 1.4.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.
@@ -0,0 +1,74 @@
1
+ import { create_success } from "#app/functions/create_success.js";
2
+ import * as z from "zod";
3
+
4
+ const return_data_schema = z.object({
5
+ // eslint-disable-next-line id-match
6
+ contentType: z.string(),
7
+ body: z.any(),
8
+ status: z.number(),
9
+ // eslint-disable-next-line id-match
10
+ statusText: z.string(),
11
+ });
12
+
13
+ const params_schema = z.looseObject({
14
+ apiurl: z.string(),
15
+ options: z.looseObject({}).optional(),
16
+ timeout_seconds: z.number().optional(),
17
+ __apicall_params: z
18
+ .looseObject({})
19
+ .optional()
20
+ .describe("apicall params as originally passed to the apicall task on core"),
21
+ });
22
+
23
+ /**
24
+ * Run an arbitrary CLI command and return stdout/stderr.
25
+ * @param {z.infer<typeof params_schema>} params
26
+ */
27
+ export const api_proxy = async (params, _stubber) => {
28
+ let { apiurl, options, timeout_seconds, __apicall_params } = params || {};
29
+
30
+ const timeout = (timeout_seconds || __apicall_params?.timeout_seconds || 15) * 1000;
31
+
32
+ if (!options) {
33
+ options = {};
34
+ }
35
+
36
+ // console.log("timeout", timeout);
37
+
38
+ options.signal = AbortSignal.timeout(timeout);
39
+
40
+ const response = await fetch(apiurl, options);
41
+
42
+ const content_type = response.headers.get("content-type") || "";
43
+ let body;
44
+ if (content_type.includes("application/json")) {
45
+ body = await response.json();
46
+ } else if (content_type.includes("multipart/form-data")) {
47
+ body = await response.formData();
48
+ } else if (content_type.includes("application/octet-stream")) {
49
+ body = await response.blob();
50
+ } else {
51
+ body = await response.text();
52
+ }
53
+ const status = response.status;
54
+ const status_text = response.statusText;
55
+
56
+ /** @type {z.infer<typeof return_data_schema>} */
57
+ const result = {
58
+ // eslint-disable-next-line id-match
59
+ contentType: content_type,
60
+ body: body || undefined,
61
+ status,
62
+ // eslint-disable-next-line id-match
63
+ statusText: status_text,
64
+ };
65
+
66
+ const success = response.ok;
67
+
68
+ return {
69
+ success,
70
+ payload: {
71
+ apiresult: result,
72
+ },
73
+ };
74
+ };
@@ -53,7 +53,7 @@ export const browser_screenshot = async (params, stubber_context) => {
53
53
 
54
54
  return create_success({
55
55
  message: "Screenshot captured successfully",
56
- payload: { screenshot: { path: screenshot_options.path, file_info } },
56
+ payload: { screenshot: { path: screenshot_options.path, file_info }, attachments: file_info ? [file_info] : [] },
57
57
  });
58
58
  } catch (error) {
59
59
  return create_error_technical(error);
@@ -98,6 +98,13 @@ export const upload_files = async (params, _stubber) => {
98
98
  };
99
99
  }
100
100
 
101
+ let attachments = [];
102
+
103
+ if (payload.uploaded_files) {
104
+ attachments = payload.uploaded_files;
105
+ payload.attachments = attachments;
106
+ }
107
+
101
108
  return create_success({
102
109
  message: "Files uploaded successfully",
103
110
  payload,
@@ -12,6 +12,8 @@ import { cli_run } from "./cli/cli_run.js";
12
12
  import { upload_files } from "./file-server/upload_files.js";
13
13
  import { download_files } from "./file-server/download_files.js";
14
14
 
15
+ import { api_proxy } from "./api_proxy/api_proxy.js";
16
+
15
17
  const all_commands = {
16
18
  browser_click,
17
19
  browser_extract_data,
@@ -27,6 +29,8 @@ const all_commands = {
27
29
 
28
30
  upload_files,
29
31
  download_files,
32
+
33
+ api_proxy,
30
34
  };
31
35
 
32
36
  export { all_commands };
@@ -71,6 +71,17 @@ export const run_commands = async (task, _stubber) => {
71
71
  }
72
72
  }
73
73
 
74
+ // move command attachments to the task level
75
+ const command_attachments = payload.commands[command_name]?.payload?.attachments;
76
+ if (command_attachments && Array.isArray(command_attachments)) {
77
+ if (!payload.attachments) {
78
+ payload.attachments = [];
79
+ }
80
+ payload.attachments.push(...command_attachments);
81
+ // remove attachments from command payload
82
+ delete payload.commands[command_name].payload.attachments;
83
+ }
84
+
74
85
  if (!payload.commands[command_name].success && !command.continue_on_error) {
75
86
  important_command_failed = true;
76
87
  break; // Stop execution if continue_on_error is falsy
@@ -22,12 +22,16 @@ export const get_chromium_page = async (params, stubber_context) => {
22
22
  return create_error_conceptual({ message: "session_id is required to get a Chromium page." });
23
23
  }
24
24
 
25
+ const slow_mo = params?.slow_mo || process.env.SLOW_MO || 0;
26
+
27
+ // console.log(`get_chromium_page: session_id=${session_id}, slow_mo=${slow_mo}`);
28
+
25
29
  // Launch the browser once and reuse it
26
30
  if (!browser) {
27
31
  browser = await chromium.launch({
28
32
  headless: false,
29
33
  // eslint-disable-next-line id-match
30
- slowMo: params?.slow_mo || 0,
34
+ slowMo: slow_mo,
31
35
  });
32
36
  }
33
37
 
@@ -15,7 +15,7 @@ router.post(["/virtual_worker_task", "/virtual_worker_send_commands"], async (re
15
15
  const payload = task_payload_schema.parse(req.body);
16
16
  const task = payload.task;
17
17
 
18
- console.log("Received task:", task.task_name, "of type:", task.tasktype, "with params:", task.params);
18
+ console.log("Received task:", task.task_name, "of type:", task.tasktype);
19
19
 
20
20
  const result = await virtual_worker_task(task);
21
21
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stubber/virtual-worker",
3
- "version": "1.3.0",
3
+ "version": "1.4.1",
4
4
  "description": "Template to easily create a node app and keep development standards",
5
5
  "main": "app.js",
6
6
  "directories": {