@nocobase/plugin-workflow-javascript 3.0.0-alpha.5 → 3.0.0-alpha.7

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.
@@ -8,13 +8,13 @@
8
8
  */
9
9
 
10
10
  module.exports = {
11
- "@nocobase/client": "3.0.0-alpha.5",
12
- "@nocobase/plugin-workflow": "3.0.0-alpha.5",
13
- "@nocobase/flow-engine": "3.0.0-alpha.5",
11
+ "@nocobase/client": "3.0.0-alpha.7",
12
+ "@nocobase/plugin-workflow": "3.0.0-alpha.7",
13
+ "@nocobase/flow-engine": "3.0.0-alpha.7",
14
14
  "react-i18next": "11.18.6",
15
- "@nocobase/client-v2": "3.0.0-alpha.5",
15
+ "@nocobase/client-v2": "3.0.0-alpha.7",
16
16
  "winston": "3.13.0",
17
- "@nocobase/server": "3.0.0-alpha.5",
17
+ "@nocobase/server": "3.0.0-alpha.7",
18
18
  "antd": "5.24.2",
19
19
  "@emotion/css": "11.13.0",
20
20
  "react": "18.2.0",
@@ -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-01T20:53:36.413Z"}
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-05T22:32:43.463Z"}
@@ -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-01T20:53:37.127Z"}
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-05T22:32:44.175Z"}
@@ -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({
@@ -150,11 +176,17 @@ class ScriptInstruction extends import_plugin_workflow.Instruction {
150
176
  upstreamId: (prevJob == null ? void 0 : prevJob.id) ?? null
151
177
  });
152
178
  processor.logger.info(`script (#${node.id}) has been started, waiting for response...`);
153
- await processor.exit();
179
+ const abortHandle = processor.createBackgroundAbortHandle();
180
+ try {
181
+ await processor.exit();
182
+ } catch (error) {
183
+ abortHandle.dispose();
184
+ throw error;
185
+ }
154
186
  const jobResult = {
155
187
  status: import_plugin_workflow.JOB_STATUS.PENDING
156
188
  };
157
- this.constructor.run(content, _args, { timeout, logger: processor.logger, signal: options == null ? void 0 : options.signal }).then((res) => {
189
+ this.constructor.run(content, _args, { timeout, logger: processor.logger, signal: abortHandle.signal }).then((res) => {
158
190
  if (res.status === import_plugin_workflow.JOB_STATUS.RESOLVED) {
159
191
  processor.logger.info(`script (#${node.id}) get result success`);
160
192
  jobResult.status = import_plugin_workflow.JOB_STATUS.RESOLVED;
@@ -177,6 +209,7 @@ class ScriptInstruction extends import_plugin_workflow.Instruction {
177
209
  jobResult.status = import_plugin_workflow.JOB_STATUS.ERROR;
178
210
  jobResult.result = message;
179
211
  }).finally(() => {
212
+ abortHandle.dispose();
180
213
  processor.logger.debug(`script (#${node.id}) ended, resume workflow...`);
181
214
  setImmediate(async () => {
182
215
  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": "3.0.0-alpha.5",
3
+ "version": "3.0.0-alpha.7",
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.",
@@ -35,5 +35,5 @@
35
35
  "Workflow"
36
36
  ],
37
37
  "license": "Apache-2.0",
38
- "gitHead": "82c7ed1cdb2f247c190582e34ee37f154cac0968"
38
+ "gitHead": "19cd28c710f3b3c614ebe2fd7d5a415d527ee559"
39
39
  }