@nocobase/plugin-workflow-javascript 2.1.34 → 2.1.35

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.
@@ -13,11 +13,11 @@ module.exports = {
13
13
  "antd-style": "3.7.1",
14
14
  "@formily/antd-v5": "1.2.3",
15
15
  "@ant-design/icons": "5.6.1",
16
- "@nocobase/client": "2.1.34",
17
- "@nocobase/plugin-workflow": "2.1.34",
16
+ "@nocobase/client": "2.1.35",
17
+ "@nocobase/plugin-workflow": "2.1.35",
18
18
  "antd": "5.24.2",
19
- "@nocobase/flow-engine": "2.1.34",
19
+ "@nocobase/flow-engine": "2.1.35",
20
20
  "react-i18next": "11.18.6",
21
21
  "winston": "3.13.0",
22
- "@nocobase/server": "2.1.34"
22
+ "@nocobase/server": "2.1.35"
23
23
  };
@@ -1 +1 @@
1
- {"name":"joi","description":"Object schema validation","version":"17.13.3","repository":"git://github.com/hapijs/joi","main":"lib/index.js","types":"lib/index.d.ts","browser":"dist/joi-browser.min.js","files":["lib/**/*","dist/*"],"keywords":["schema","validation"],"dependencies":{"@hapi/hoek":"^9.3.0","@hapi/topo":"^5.1.0","@sideway/address":"^4.1.5","@sideway/formula":"^3.0.1","@sideway/pinpoint":"^2.0.0"},"devDependencies":{"@hapi/bourne":"2.x.x","@hapi/code":"8.x.x","@hapi/joi-legacy-test":"npm:@hapi/joi@15.x.x","@hapi/lab":"^25.1.3","@types/node":"^14.18.63","typescript":"4.3.x"},"scripts":{"prepublishOnly":"cd browser && npm install && npm run build","test":"lab -t 100 -a @hapi/code -L -Y","test-cov-html":"lab -r html -o coverage.html -a @hapi/code"},"license":"BSD-3-Clause","_lastModified":"2026-08-01T16:25:47.064Z"}
1
+ {"name":"joi","description":"Object schema validation","version":"17.13.3","repository":"git://github.com/hapijs/joi","main":"lib/index.js","types":"lib/index.d.ts","browser":"dist/joi-browser.min.js","files":["lib/**/*","dist/*"],"keywords":["schema","validation"],"dependencies":{"@hapi/hoek":"^9.3.0","@hapi/topo":"^5.1.0","@sideway/address":"^4.1.5","@sideway/formula":"^3.0.1","@sideway/pinpoint":"^2.0.0"},"devDependencies":{"@hapi/bourne":"2.x.x","@hapi/code":"8.x.x","@hapi/joi-legacy-test":"npm:@hapi/joi@15.x.x","@hapi/lab":"^25.1.3","@types/node":"^14.18.63","typescript":"4.3.x"},"scripts":{"prepublishOnly":"cd browser && npm install && npm run build","test":"lab -t 100 -a @hapi/code -L -Y","test-cov-html":"lab -r html -o coverage.html -a @hapi/code"},"license":"BSD-3-Clause","_lastModified":"2026-08-05T07:47:36.988Z"}
@@ -1 +1 @@
1
- {"name":"winston-transport","description":"Base stream implementations for winston@3 and up.","version":"4.7.0","main":"index.js","browser":"dist/index.js","scripts":{"lint":"eslint test/*.js index.js --resolve-plugins-relative-to ./node_modules/@dabh/eslint-config-populist","pretest":"npm run lint && npm run build","test":"nyc mocha test/*.test.js","report":"nyc report --reporter=lcov","build":"rimraf dist && babel *.js -d ./dist","prepublishOnly":"npm run build"},"repository":{"type":"git","url":"git@github.com:winstonjs/winston-transport.git"},"keywords":["winston","transport","winston3"],"author":"Charlie Robbins <charlie.robbins@gmail.com>","license":"MIT","bugs":{"url":"https://github.com/winstonjs/winston-transport/issues"},"homepage":"https://github.com/winstonjs/winston-transport#readme","dependencies":{"logform":"^2.3.2","readable-stream":"^3.6.0","triple-beam":"^1.3.0"},"devDependencies":{"@types/node":"^20.8.6","abstract-winston-transport":">=0.5.1","assume":"^2.3.0","babel-cli":"^6.26.0","babel-preset-env":"^1.7.0","deep-equal":"^2.0.5","eslint":"^8.8.0","@dabh/eslint-config-populist":"^5.0.0","mocha":"^10.0.0","nyc":"^15.1.0","rimraf":"^5.0.5","winston-compat":"^0.1.5"},"engines":{"node":">= 12.0.0"},"_lastModified":"2026-08-01T16:25:47.786Z"}
1
+ {"name":"winston-transport","description":"Base stream implementations for winston@3 and up.","version":"4.7.0","main":"index.js","browser":"dist/index.js","scripts":{"lint":"eslint test/*.js index.js --resolve-plugins-relative-to ./node_modules/@dabh/eslint-config-populist","pretest":"npm run lint && npm run build","test":"nyc mocha test/*.test.js","report":"nyc report --reporter=lcov","build":"rimraf dist && babel *.js -d ./dist","prepublishOnly":"npm run build"},"repository":{"type":"git","url":"git@github.com:winstonjs/winston-transport.git"},"keywords":["winston","transport","winston3"],"author":"Charlie Robbins <charlie.robbins@gmail.com>","license":"MIT","bugs":{"url":"https://github.com/winstonjs/winston-transport/issues"},"homepage":"https://github.com/winstonjs/winston-transport#readme","dependencies":{"logform":"^2.3.2","readable-stream":"^3.6.0","triple-beam":"^1.3.0"},"devDependencies":{"@types/node":"^20.8.6","abstract-winston-transport":">=0.5.1","assume":"^2.3.0","babel-cli":"^6.26.0","babel-preset-env":"^1.7.0","deep-equal":"^2.0.5","eslint":"^8.8.0","@dabh/eslint-config-populist":"^5.0.0","mocha":"^10.0.0","nyc":"^15.1.0","rimraf":"^5.0.5","winston-compat":"^0.1.5"},"engines":{"node":">= 12.0.0"},"_lastModified":"2026-08-05T07:47:37.647Z"}
@@ -108,7 +108,7 @@ ${source ?? ""}
108
108
  const runResult = context.evalCode(wrappedSource, "script.js");
109
109
  const promiseHandle = context.unwrapResult(runResult);
110
110
  try {
111
- while (true) {
111
+ for (; ; ) {
112
112
  const state = context.getPromiseState(promiseHandle);
113
113
  if (state.type === "fulfilled") {
114
114
  const valueHandle = state.value;
@@ -138,7 +138,14 @@ ${source ?? ""}
138
138
  runtime.dispose();
139
139
  }
140
140
  }
141
- main().then((result) => {
141
+ function flushOutput() {
142
+ const flush = (stream) => new Promise((resolve, reject) => {
143
+ stream.write("", (error) => error ? reject(error) : resolve());
144
+ });
145
+ return Promise.all([flush(process.stdout), flush(process.stderr)]);
146
+ }
147
+ main().then(async (result) => {
148
+ await flushOutput();
142
149
  parentPort.postMessage({ type: "result", result });
143
150
  }).catch((error) => {
144
151
  throw error;
@@ -46,6 +46,9 @@ var import_winston = __toESM(require("winston"));
46
46
  var import_joi = __toESM(require("joi"));
47
47
  var import_plugin_workflow = require("@nocobase/plugin-workflow");
48
48
  var import_cache_logger = require("./cache-logger");
49
+ function isWorkerResult(message) {
50
+ return typeof message === "object" && message !== null && "type" in message && message.type === "result";
51
+ }
49
52
  class ScriptInstruction extends import_plugin_workflow.Instruction {
50
53
  /**
51
54
  * Returns the worker script path based on whether WORKFLOW_SCRIPT_MODULES is configured.
@@ -58,45 +61,54 @@ class ScriptInstruction extends import_plugin_workflow.Instruction {
58
61
  }
59
62
  static async run(source, args, options) {
60
63
  const { logger, timeout, signal } = options;
61
- let result;
62
64
  const worker = new import_node_worker_threads.Worker(this.workerScript, {
63
65
  workerData: { source, args, options: timeout ? { timeout } : {} }
64
66
  });
65
- const abortListener = () => {
66
- worker.terminate();
67
- };
68
- signal == null ? void 0 : signal.addEventListener("abort", abortListener, { once: true });
69
- worker.on("message", (message) => {
70
- if (message.type === "result") {
71
- result = message.result;
72
- }
73
- });
74
67
  worker.stdout.on("data", (data) => {
75
68
  logger.info(data.toString());
76
69
  });
77
70
  worker.stderr.on("data", (data) => {
78
71
  logger.error(data.toString());
79
72
  });
80
- const excution = new Promise((resolve, reject) => {
81
- worker.on("error", (error) => {
82
- reject(error);
83
- });
84
- const stdoutPromise = (0, import_node_events.once)(worker.stdout, "close");
85
- const stderrPromise = (0, import_node_events.once)(worker.stderr, "close");
86
- worker.on("exit", (code) => {
87
- Promise.all([stdoutPromise, stderrPromise]).then(() => {
88
- if (code !== 0) {
89
- reject(new Error(`Worker stopped with exit code ${code}`));
90
- }
91
- resolve(result);
92
- }).catch(reject);
93
- });
73
+ const outputClosed = Promise.all([(0, import_node_events.once)(worker.stdout, "close"), (0, import_node_events.once)(worker.stderr, "close")]);
74
+ const outcomePromise = new Promise((resolve) => {
75
+ const finish = (outcome2) => {
76
+ worker.removeListener("message", messageListener);
77
+ worker.removeListener("error", errorListener);
78
+ worker.removeListener("exit", exitListener);
79
+ signal == null ? void 0 : signal.removeEventListener("abort", abortListener);
80
+ resolve(outcome2);
81
+ };
82
+ const messageListener = (message) => {
83
+ if (isWorkerResult(message)) {
84
+ finish({ type: "result", result: message.result });
85
+ }
86
+ };
87
+ const errorListener = (error) => {
88
+ finish({ type: "error", error });
89
+ };
90
+ const exitListener = (code) => {
91
+ finish({ type: "exit", code });
92
+ };
93
+ const abortListener = () => {
94
+ finish({ type: "aborted" });
95
+ };
96
+ worker.on("message", messageListener);
97
+ worker.once("error", errorListener);
98
+ worker.once("exit", exitListener);
99
+ signal == null ? void 0 : signal.addEventListener("abort", abortListener, { once: true });
100
+ if (signal == null ? void 0 : signal.aborted) {
101
+ abortListener();
102
+ }
94
103
  });
104
+ const outcome = await outcomePromise;
95
105
  try {
96
- await excution;
106
+ if (outcome.type !== "exit") {
107
+ await worker.terminate();
108
+ }
109
+ await outputClosed;
97
110
  } catch (e) {
98
- signal == null ? void 0 : signal.removeEventListener("abort", abortListener);
99
- if (signal == null ? void 0 : signal.aborted) {
111
+ if (outcome.type === "aborted" || (signal == null ? void 0 : signal.aborted)) {
100
112
  throw signal.reason instanceof Error ? signal.reason : new import_plugin_workflow.WorkflowTimeoutError();
101
113
  }
102
114
  return {
@@ -104,10 +116,24 @@ class ScriptInstruction extends import_plugin_workflow.Instruction {
104
116
  result: e instanceof Error ? e.message : String(e)
105
117
  };
106
118
  }
107
- signal == null ? void 0 : signal.removeEventListener("abort", abortListener);
119
+ if (outcome.type === "aborted") {
120
+ throw (signal == null ? void 0 : signal.reason) instanceof Error ? signal.reason : new import_plugin_workflow.WorkflowTimeoutError();
121
+ }
122
+ if (outcome.type === "error") {
123
+ return {
124
+ status: import_plugin_workflow.JOB_STATUS.ERROR,
125
+ result: outcome.error.message
126
+ };
127
+ }
128
+ if (outcome.type === "exit" && outcome.code !== 0) {
129
+ return {
130
+ status: import_plugin_workflow.JOB_STATUS.ERROR,
131
+ result: `Worker stopped with exit code ${outcome.code}`
132
+ };
133
+ }
108
134
  return {
109
135
  status: import_plugin_workflow.JOB_STATUS.RESOLVED,
110
- result
136
+ result: outcome.type === "result" ? outcome.result : void 0
111
137
  };
112
138
  }
113
139
  configSchema = import_joi.default.object({
@@ -151,11 +177,17 @@ class ScriptInstruction extends import_plugin_workflow.Instruction {
151
177
  upstreamId: (prevJob == null ? void 0 : prevJob.id) ?? null
152
178
  });
153
179
  processor.logger.info(`script (#${node.id}) has been started, waiting for response...`);
154
- await processor.exit();
180
+ const abortHandle = processor.createBackgroundAbortHandle();
181
+ try {
182
+ await processor.exit();
183
+ } catch (error) {
184
+ abortHandle.dispose();
185
+ throw error;
186
+ }
155
187
  const jobResult = {
156
188
  status: import_plugin_workflow.JOB_STATUS.PENDING
157
189
  };
158
- this.constructor.run(content, _args, { timeout, logger: processor.logger, signal: options == null ? void 0 : options.signal }).then((res) => {
190
+ this.constructor.run(content, _args, { timeout, logger: processor.logger, signal: abortHandle.signal }).then((res) => {
159
191
  if (res.status === import_plugin_workflow.JOB_STATUS.RESOLVED) {
160
192
  processor.logger.info(`script (#${node.id}) get result success`);
161
193
  jobResult.status = import_plugin_workflow.JOB_STATUS.RESOLVED;
@@ -178,6 +210,7 @@ class ScriptInstruction extends import_plugin_workflow.Instruction {
178
210
  jobResult.status = import_plugin_workflow.JOB_STATUS.ERROR;
179
211
  jobResult.result = message;
180
212
  }).finally(() => {
213
+ abortHandle.dispose();
181
214
  processor.logger.debug(`script (#${node.id}) ended, resume workflow...`);
182
215
  setImmediate(async () => {
183
216
  const job = await this.workflow.db.getRepository("jobs").findOne({ filterByTk: id });
package/dist/server/Vm.js CHANGED
@@ -105,7 +105,14 @@ async function main() {
105
105
  const result = script.runInNewContext(context, { timeout: options.timeout });
106
106
  return result;
107
107
  }
108
- main().then((result) => {
108
+ function flushOutput() {
109
+ const flush = (stream) => new Promise((resolve, reject) => {
110
+ stream.write("", (error) => error ? reject(error) : resolve());
111
+ });
112
+ return Promise.all([flush(process.stdout), flush(process.stderr)]);
113
+ }
114
+ main().then(async (result) => {
115
+ await flushOutput();
109
116
  parentPort.postMessage({ type: "result", result });
110
117
  }).catch((error) => {
111
118
  throw error;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nocobase/plugin-workflow-javascript",
3
- "version": "2.1.34",
3
+ "version": "2.1.35",
4
4
  "displayName": "Workflow: JavaScript",
5
5
  "displayName.zh-CN": "工作流:JavaScript 节点",
6
6
  "description": "Execute a piece of JavaScript in an isolated Node.js environment.",
@@ -33,5 +33,5 @@
33
33
  "Workflow"
34
34
  ],
35
35
  "license": "Apache-2.0",
36
- "gitHead": "6d4dfdfbde69698ed1c2ed54108a8f6736e56e10"
36
+ "gitHead": "d844133f9bd61a3506a3be1af25a1cb06dafbc6f"
37
37
  }