@tachybase/module-workflow 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/dist/client/components/ColletionTreeSelect.d.ts +16 -0
- package/dist/client/components/EnabledStatusFilter.d.ts +2 -0
- package/dist/client/components/index.d.ts +1 -0
- package/dist/client/features/script/Script.instruction.d.ts +136 -0
- package/dist/client/features/script/ScriptCodeEditor.d.ts +9 -0
- package/dist/client/features/script/SyncRemoteCodeButton.d.ts +6 -0
- package/dist/client/features/trigger-instruction/TriggerInstruction.d.ts +164 -5
- package/dist/client/index.js +85 -59
- package/dist/client/nodes/select.d.ts +235 -0
- package/dist/externalVersion.js +9 -9
- package/dist/locale/en-US.json +47 -1
- package/dist/locale/es-ES.json +17 -1
- package/dist/locale/fr-FR.json +16 -0
- package/dist/locale/ja-JP.json +17 -1
- package/dist/locale/ko_KR.json +17 -1
- package/dist/locale/pt-BR.json +17 -1
- package/dist/locale/ru-RU.json +18 -2
- package/dist/locale/tr-TR.json +18 -2
- package/dist/locale/zh-CN.json +50 -1
- package/dist/node_modules/@babel/core/lib/index.js +77 -77
- package/dist/node_modules/@babel/core/node_modules/.bin/parser +4 -4
- package/dist/node_modules/@babel/core/package.json +1 -1
- package/dist/node_modules/@babel/preset-env/lib/index.js +88 -88
- package/dist/node_modules/@babel/preset-env/package.json +1 -1
- package/dist/node_modules/@babel/preset-react/lib/index.js +80 -80
- package/dist/node_modules/@babel/preset-react/package.json +1 -1
- package/dist/node_modules/@babel/preset-typescript/lib/index.js +77 -77
- package/dist/node_modules/@babel/preset-typescript/package.json +1 -1
- package/dist/node_modules/cron-parser/package.json +1 -1
- package/dist/node_modules/form-data/package.json +1 -1
- package/dist/node_modules/jsonata/package.json +1 -1
- package/dist/node_modules/lru-cache/package.json +1 -1
- package/dist/node_modules/mime-types/package.json +1 -1
- package/dist/node_modules/qrcode/package.json +1 -1
- package/dist/server/Plugin.js +57 -1
- package/dist/server/actions/executions.d.ts +3 -3
- package/dist/server/actions/executions.js +33 -33
- package/dist/server/actions/index.js +3 -2
- package/dist/server/actions/nodes.d.ts +13 -6
- package/dist/server/actions/nodes.js +160 -34
- package/dist/server/actions/workflows.d.ts +9 -9
- package/dist/server/actions/workflows.helpers.d.ts +6 -6
- package/dist/server/actions/workflows.helpers.js +14 -14
- package/dist/server/actions/workflows.js +85 -85
- package/dist/server/features/interception/RequestInterceptionTrigger.d.ts +1 -1
- package/dist/server/features/interception/RequestInterceptionTrigger.js +12 -12
- package/dist/server/features/manual/actions.d.ts +1 -1
- package/dist/server/features/manual/actions.js +12 -12
- package/dist/server/features/notice/actions.js +19 -19
- package/dist/server/features/notice/plugin.js +0 -3
- package/dist/server/features/omni-trigger/CustomActionTrigger.d.ts +2 -2
- package/dist/server/features/omni-trigger/CustomActionTrigger.js +27 -27
- package/dist/server/features/script/script.instruction.js +146 -4
- package/dist/server/features/trigger-instruction/TriggerInstruction.d.ts +4 -0
- package/dist/server/features/trigger-instruction/TriggerInstruction.js +71 -5
- package/dist/server/instructions/SelectInstruction.d.ts +13 -0
- package/dist/server/instructions/SelectInstruction.js +126 -0
- package/dist/server/services/remote-code-fetcher.d.ts +48 -0
- package/dist/server/services/remote-code-fetcher.js +370 -0
- package/dist/server/utils/get-remote-code-fetcher.d.ts +7 -0
- package/dist/server/utils/get-remote-code-fetcher.js +39 -0
- package/package.json +12 -12
- package/dist/server/features/trigger-instruction/index.d.ts +0 -0
- package/dist/server/features/trigger-instruction/index.js +0 -0
|
@@ -47,20 +47,20 @@ class CustomActionInterceptionError extends Error {
|
|
|
47
47
|
const _OmniTrigger = class _OmniTrigger extends import_triggers.default {
|
|
48
48
|
constructor(workflow) {
|
|
49
49
|
super(workflow);
|
|
50
|
-
this.triggerAction = async (
|
|
50
|
+
this.triggerAction = async (ctx, next) => {
|
|
51
51
|
const {
|
|
52
52
|
params: { filterByTk, values, triggerWorkflows = "", filter, resourceName, actionName }
|
|
53
|
-
} =
|
|
53
|
+
} = ctx.action;
|
|
54
54
|
if (actionName !== "trigger" || resourceName === "workflows") {
|
|
55
55
|
return next();
|
|
56
56
|
}
|
|
57
|
-
const { currentUser, currentRole } =
|
|
57
|
+
const { currentUser, currentRole } = ctx.state;
|
|
58
58
|
const { model: UserModel } = this.workflow.db.getCollection("users");
|
|
59
59
|
const userInfo = {
|
|
60
60
|
user: UserModel.build(currentUser).desensitize(),
|
|
61
61
|
roleName: currentRole
|
|
62
62
|
};
|
|
63
|
-
const dataSourceHeader =
|
|
63
|
+
const dataSourceHeader = ctx.get("x-data-source");
|
|
64
64
|
const jointCollectionName = (0, import_server.joinCollectionName)(dataSourceHeader, resourceName);
|
|
65
65
|
const triggerWorkflowsMap = /* @__PURE__ */ new Map();
|
|
66
66
|
const triggerWorkflowsArray = [];
|
|
@@ -92,7 +92,7 @@ const _OmniTrigger = class _OmniTrigger extends import_triggers.default {
|
|
|
92
92
|
const [dataSourceName, collectionName] = (0, import_server.parseCollectionName)(workflow.config.collection);
|
|
93
93
|
const dataPath = triggerWorkflowsMap.get(workflow.key);
|
|
94
94
|
const event = [workflow];
|
|
95
|
-
const { repository } =
|
|
95
|
+
const { repository } = ctx.tego.dataSourceManager.dataSources.get(dataSourceName).collectionManager.getCollection(collectionName);
|
|
96
96
|
const formData = dataPath ? import_lodash.default.get(values, dataPath) : values;
|
|
97
97
|
let data = formData;
|
|
98
98
|
if (filterByTk != null) {
|
|
@@ -116,9 +116,9 @@ const _OmniTrigger = class _OmniTrigger extends import_triggers.default {
|
|
|
116
116
|
(workflow.sync ? syncGroup : asyncGroup).push(event);
|
|
117
117
|
}
|
|
118
118
|
for (const event of syncGroup) {
|
|
119
|
-
const processor = await this.workflow.trigger(event[0], event[1], { httpContext:
|
|
119
|
+
const processor = await this.workflow.trigger(event[0], event[1], { httpContext: ctx });
|
|
120
120
|
if (!processor) {
|
|
121
|
-
return
|
|
121
|
+
return ctx.throw(500);
|
|
122
122
|
}
|
|
123
123
|
const { lastSavedJob, nodesMap } = processor;
|
|
124
124
|
const lastNode = nodesMap.get(lastSavedJob == null ? void 0 : lastSavedJob.nodeId);
|
|
@@ -130,34 +130,34 @@ const _OmniTrigger = class _OmniTrigger extends import_triggers.default {
|
|
|
130
130
|
}
|
|
131
131
|
if (processor.execution.status < import_constants.EXECUTION_STATUS.STARTED) {
|
|
132
132
|
if ((lastNode == null ? void 0 : lastNode.type) !== "end") {
|
|
133
|
-
return
|
|
133
|
+
return ctx.throw(
|
|
134
134
|
500,
|
|
135
|
-
|
|
135
|
+
ctx.t("Workflow on your action failed, please contact the administrator", { ns: "workflow" })
|
|
136
136
|
);
|
|
137
137
|
}
|
|
138
138
|
const err = new CustomActionInterceptionError("Request is intercepted by workflow");
|
|
139
139
|
err.status = 400;
|
|
140
|
-
err.messages =
|
|
141
|
-
return
|
|
140
|
+
err.messages = ctx.state.messages;
|
|
141
|
+
return ctx.throw(err.status, err);
|
|
142
142
|
}
|
|
143
|
-
return
|
|
143
|
+
return ctx.throw(500, "Workflow on your action hangs, please contact the administrator");
|
|
144
144
|
}
|
|
145
145
|
for (const event of asyncGroup) {
|
|
146
146
|
this.workflow.trigger(event[0], event[1]);
|
|
147
147
|
}
|
|
148
148
|
await next();
|
|
149
149
|
};
|
|
150
|
-
this.middleware = async (
|
|
150
|
+
this.middleware = async (ctx, next) => {
|
|
151
151
|
const {
|
|
152
152
|
resourceName,
|
|
153
153
|
actionName,
|
|
154
154
|
params: { triggerWorkflows, beforeWorkflows }
|
|
155
|
-
} =
|
|
155
|
+
} = ctx.action;
|
|
156
156
|
if (beforeWorkflows) {
|
|
157
|
-
await this.trigger(
|
|
157
|
+
await this.trigger(ctx, beforeWorkflows, "before");
|
|
158
158
|
}
|
|
159
159
|
if (resourceName === "workflows" && actionName === "trigger") {
|
|
160
|
-
return this.triggerAction(
|
|
160
|
+
return this.triggerAction(ctx, next);
|
|
161
161
|
}
|
|
162
162
|
await next();
|
|
163
163
|
if (!triggerWorkflows) {
|
|
@@ -166,7 +166,7 @@ const _OmniTrigger = class _OmniTrigger extends import_triggers.default {
|
|
|
166
166
|
if (!["create", "update"].includes(actionName)) {
|
|
167
167
|
return;
|
|
168
168
|
}
|
|
169
|
-
return this.trigger(
|
|
169
|
+
return this.trigger(ctx, triggerWorkflows);
|
|
170
170
|
};
|
|
171
171
|
this.workflow.app.resourcer.registerActionHandler("trigger", this.triggerAction);
|
|
172
172
|
this.workflow.app.acl.allow("*", "trigger", "loggedIn");
|
|
@@ -181,13 +181,13 @@ const _OmniTrigger = class _OmniTrigger extends import_triggers.default {
|
|
|
181
181
|
);
|
|
182
182
|
workflow.app.resourcer.use(this.middleware, { tag: "workflowTrigger", after: "acl" });
|
|
183
183
|
}
|
|
184
|
-
async trigger(
|
|
184
|
+
async trigger(ctx, workflowList, order = "after") {
|
|
185
185
|
if (!workflowList) {
|
|
186
186
|
return;
|
|
187
187
|
}
|
|
188
|
-
const { values } =
|
|
189
|
-
const dataSourceHeader =
|
|
190
|
-
const { currentUser, currentRole } =
|
|
188
|
+
const { values } = ctx.action.params;
|
|
189
|
+
const dataSourceHeader = ctx.get("x-data-source") || "main";
|
|
190
|
+
const { currentUser, currentRole } = ctx.state;
|
|
191
191
|
const { model: UserModel } = this.workflow.db.getCollection("users");
|
|
192
192
|
const userInfo = {
|
|
193
193
|
user: UserModel.build(currentUser).desensitize(),
|
|
@@ -210,19 +210,19 @@ const _OmniTrigger = class _OmniTrigger extends import_triggers.default {
|
|
|
210
210
|
const [dataSourceName, collectionName] = (0, import_server.parseCollectionName)(collection);
|
|
211
211
|
const trigger = triggers.find((trigger2) => trigger2[0] === workflow.key);
|
|
212
212
|
const event = [workflow];
|
|
213
|
-
if (
|
|
213
|
+
if (ctx.action.resourceName !== "workflows") {
|
|
214
214
|
if (order === "before") {
|
|
215
|
-
event.push({ data:
|
|
215
|
+
event.push({ data: ctx.action.params, ...userInfo });
|
|
216
216
|
(workflow.sync ? syncGroup : asyncGroup).push(event);
|
|
217
217
|
continue;
|
|
218
218
|
}
|
|
219
|
-
if (!
|
|
219
|
+
if (!ctx.body) {
|
|
220
220
|
continue;
|
|
221
221
|
}
|
|
222
222
|
if (dataSourceName !== dataSourceHeader) {
|
|
223
223
|
continue;
|
|
224
224
|
}
|
|
225
|
-
const { body: data } =
|
|
225
|
+
const { body: data } = ctx;
|
|
226
226
|
for (const row of Array.isArray(data) ? data : [data]) {
|
|
227
227
|
let payload = row;
|
|
228
228
|
if (trigger[1]) {
|
|
@@ -251,7 +251,7 @@ const _OmniTrigger = class _OmniTrigger extends import_triggers.default {
|
|
|
251
251
|
event.push({ data: (0, import_utils.toJSON)(payload), ...userInfo });
|
|
252
252
|
}
|
|
253
253
|
} else {
|
|
254
|
-
const { model, repository } =
|
|
254
|
+
const { model, repository } = ctx.tego.dataSourceManager.dataSources.get(dataSourceName).collectionManager.getCollection(collectionName);
|
|
255
255
|
let data = trigger[1] ? (0, import_lodash.get)(values, trigger[1]) : values;
|
|
256
256
|
const pk = (0, import_lodash.get)(data, model.primaryKeyAttribute);
|
|
257
257
|
if (appends.length && pk != null) {
|
|
@@ -265,7 +265,7 @@ const _OmniTrigger = class _OmniTrigger extends import_triggers.default {
|
|
|
265
265
|
(workflow.sync ? syncGroup : asyncGroup).push(event);
|
|
266
266
|
}
|
|
267
267
|
for (const event of syncGroup) {
|
|
268
|
-
await this.workflow.trigger(event[0], event[1], { httpContext:
|
|
268
|
+
await this.workflow.trigger(event[0], event[1], { httpContext: ctx });
|
|
269
269
|
}
|
|
270
270
|
for (const event of asyncGroup) {
|
|
271
271
|
this.workflow.trigger(event[0], event[1]);
|
|
@@ -38,9 +38,151 @@ var import_jsonata = __toESM(require("jsonata"));
|
|
|
38
38
|
var import_lodash = __toESM(require("lodash"));
|
|
39
39
|
var import_qrcode = __toESM(require("qrcode"));
|
|
40
40
|
var import__ = require("../..");
|
|
41
|
+
var import_get_remote_code_fetcher = require("../../utils/get-remote-code-fetcher");
|
|
41
42
|
class ScriptInstruction extends import__.Instruction {
|
|
42
43
|
async run(node, input, processor) {
|
|
43
|
-
const {
|
|
44
|
+
const {
|
|
45
|
+
sourceArray,
|
|
46
|
+
type,
|
|
47
|
+
code = "",
|
|
48
|
+
model,
|
|
49
|
+
codeSource = "local",
|
|
50
|
+
codeType,
|
|
51
|
+
codeUrl,
|
|
52
|
+
codeBranch = "main",
|
|
53
|
+
codeAuthType,
|
|
54
|
+
codeAuthToken,
|
|
55
|
+
codeAuthUsername
|
|
56
|
+
} = node.config;
|
|
57
|
+
let actualCode = code;
|
|
58
|
+
if (codeSource === "remote" && codeUrl && codeType) {
|
|
59
|
+
try {
|
|
60
|
+
const app = processor.options.plugin.app;
|
|
61
|
+
const remoteCodeFetcher = (0, import_get_remote_code_fetcher.getRemoteCodeFetcher)(app);
|
|
62
|
+
if (remoteCodeFetcher) {
|
|
63
|
+
const codeCache = node.config.codeCache;
|
|
64
|
+
if (codeCache == null ? void 0 : codeCache.content) {
|
|
65
|
+
app.logger.info(`[Workflow Node ${node.id}] Using cached remote code from database`);
|
|
66
|
+
actualCode = codeCache.content;
|
|
67
|
+
} else {
|
|
68
|
+
app.logger.info(
|
|
69
|
+
`[Workflow Node ${node.id}] No cache found, fetching remote code from ${codeUrl} (type: ${codeType}, branch: ${codeBranch || "main"})`
|
|
70
|
+
);
|
|
71
|
+
actualCode = await remoteCodeFetcher.fetchCode(
|
|
72
|
+
codeUrl,
|
|
73
|
+
codeType,
|
|
74
|
+
codeBranch || "main",
|
|
75
|
+
// 使用配置的分支,默认为 'main'
|
|
76
|
+
void 0,
|
|
77
|
+
// codePath - 使用默认值
|
|
78
|
+
codeAuthType,
|
|
79
|
+
codeAuthToken,
|
|
80
|
+
codeAuthUsername
|
|
81
|
+
);
|
|
82
|
+
const nodeRepo = app.db.getRepository("flow_nodes");
|
|
83
|
+
await nodeRepo.update({
|
|
84
|
+
filterByTk: node.id,
|
|
85
|
+
values: {
|
|
86
|
+
config: {
|
|
87
|
+
...node.config,
|
|
88
|
+
codeCache: {
|
|
89
|
+
content: actualCode,
|
|
90
|
+
timestamp: Date.now()
|
|
91
|
+
// 保留 timestamp 用于记录,但不用于验证
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
app.logger.info(`[Workflow Node ${node.id}] Remote code fetched and cached successfully`);
|
|
97
|
+
}
|
|
98
|
+
} else {
|
|
99
|
+
const codeCache = node.config.codeCache;
|
|
100
|
+
if (codeCache == null ? void 0 : codeCache.content) {
|
|
101
|
+
app.logger.info(`[Workflow Node ${node.id}] Using cached remote code from database (fallback mode)`);
|
|
102
|
+
actualCode = codeCache.content;
|
|
103
|
+
} else {
|
|
104
|
+
const http = require("node:http");
|
|
105
|
+
const https = require("node:https");
|
|
106
|
+
const { URL } = require("node:url");
|
|
107
|
+
const urlObj = new URL(codeUrl);
|
|
108
|
+
const client = urlObj.protocol === "https:" ? https : http;
|
|
109
|
+
app.logger.info(
|
|
110
|
+
`[Workflow Node ${node.id}] No cache found, fetching remote code via HTTP (type: ${codeType}, branch: ${codeBranch || "main"})`
|
|
111
|
+
);
|
|
112
|
+
actualCode = await new Promise((resolve, reject) => {
|
|
113
|
+
const headers = {
|
|
114
|
+
"User-Agent": "TegoWorkflow/1.0"
|
|
115
|
+
};
|
|
116
|
+
if (codeAuthType === "token" && codeAuthToken) {
|
|
117
|
+
headers["Authorization"] = `Bearer ${codeAuthToken}`;
|
|
118
|
+
} else if (codeAuthType === "basic" && codeAuthUsername && codeAuthToken) {
|
|
119
|
+
const credentials = Buffer.from(`${codeAuthUsername}:${codeAuthToken}`).toString("base64");
|
|
120
|
+
headers["Authorization"] = `Basic ${credentials}`;
|
|
121
|
+
}
|
|
122
|
+
const request = client.get(
|
|
123
|
+
{
|
|
124
|
+
hostname: urlObj.hostname,
|
|
125
|
+
port: urlObj.port || (urlObj.protocol === "https:" ? 443 : 80),
|
|
126
|
+
path: urlObj.pathname + urlObj.search,
|
|
127
|
+
headers,
|
|
128
|
+
timeout: 1e4
|
|
129
|
+
},
|
|
130
|
+
(res) => {
|
|
131
|
+
if (res.statusCode !== 200) {
|
|
132
|
+
reject(new Error(`Failed to fetch: HTTP ${res.statusCode}`));
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
let data2 = "";
|
|
136
|
+
res.on("data", (chunk) => {
|
|
137
|
+
data2 += chunk;
|
|
138
|
+
});
|
|
139
|
+
res.on("end", () => {
|
|
140
|
+
resolve(data2);
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
);
|
|
144
|
+
request.on("error", reject);
|
|
145
|
+
request.on("timeout", () => {
|
|
146
|
+
request.destroy();
|
|
147
|
+
reject(new Error("Request timeout"));
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
const nodeRepo = app.db.getRepository("flow_nodes");
|
|
151
|
+
await nodeRepo.update({
|
|
152
|
+
filterByTk: node.id,
|
|
153
|
+
values: {
|
|
154
|
+
config: {
|
|
155
|
+
...node.config,
|
|
156
|
+
codeCache: {
|
|
157
|
+
content: actualCode,
|
|
158
|
+
timestamp: Date.now()
|
|
159
|
+
// 保留 timestamp 用于记录,但不用于验证
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
app.logger.info(`[Workflow Node ${node.id}] Remote code fetched and cached successfully (fallback mode)`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
} catch (error) {
|
|
168
|
+
const app = processor.options.plugin.app;
|
|
169
|
+
app.logger.error("Failed to fetch remote code for script node", {
|
|
170
|
+
error: error instanceof Error ? error.message : String(error),
|
|
171
|
+
nodeId: node.id,
|
|
172
|
+
codeUrl
|
|
173
|
+
});
|
|
174
|
+
const codeCache = node.config.codeCache;
|
|
175
|
+
if (codeCache == null ? void 0 : codeCache.content) {
|
|
176
|
+
app.logger.warn(`[Workflow Node ${node.id}] Remote fetch failed, using cached code as fallback`);
|
|
177
|
+
actualCode = codeCache.content;
|
|
178
|
+
} else if (!code) {
|
|
179
|
+
throw new Error(`Failed to fetch remote code: ${error instanceof Error ? error.message : String(error)}`);
|
|
180
|
+
} else {
|
|
181
|
+
app.logger.warn(`[Workflow Node ${node.id}] Remote code fetch failed, falling back to local code`);
|
|
182
|
+
actualCode = code;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
44
186
|
let data = {};
|
|
45
187
|
switch (sourceArray.length) {
|
|
46
188
|
case 0: {
|
|
@@ -74,13 +216,13 @@ class ScriptInstruction extends import__.Instruction {
|
|
|
74
216
|
let result = {};
|
|
75
217
|
switch (type) {
|
|
76
218
|
case "jsonata":
|
|
77
|
-
result = await convertByJSONata(
|
|
219
|
+
result = await convertByJSONata(actualCode, data);
|
|
78
220
|
break;
|
|
79
221
|
case "js":
|
|
80
|
-
result = await convertByJsCode(
|
|
222
|
+
result = await convertByJsCode(actualCode, data);
|
|
81
223
|
break;
|
|
82
224
|
case "ts":
|
|
83
|
-
result = await convertByTsCode(
|
|
225
|
+
result = await convertByTsCode(actualCode, data, processor);
|
|
84
226
|
break;
|
|
85
227
|
default:
|
|
86
228
|
}
|
|
@@ -30,12 +30,13 @@ __export(TriggerInstruction_exports, {
|
|
|
30
30
|
TriggerInstruction: () => TriggerInstruction
|
|
31
31
|
});
|
|
32
32
|
module.exports = __toCommonJS(TriggerInstruction_exports);
|
|
33
|
+
var import_lodash = __toESM(require("lodash"));
|
|
33
34
|
var import_constants = require("../../constants");
|
|
34
35
|
var import_instructions = __toESM(require("../../instructions"));
|
|
35
36
|
class TriggerInstruction extends import_instructions.default {
|
|
36
37
|
async run(node, input, processor) {
|
|
37
38
|
var _a;
|
|
38
|
-
const workflowKey = node.config
|
|
39
|
+
const { workflowKey, sourceArray = [], model } = node.config;
|
|
39
40
|
const wfRepo = this.workflow.db.getRepository("workflows");
|
|
40
41
|
const wf = await wfRepo.findOne({ filter: { key: workflowKey, enabled: true } });
|
|
41
42
|
if (!wf) {
|
|
@@ -52,8 +53,41 @@ class TriggerInstruction extends import_instructions.default {
|
|
|
52
53
|
);
|
|
53
54
|
}
|
|
54
55
|
try {
|
|
56
|
+
let triggerData = input.result;
|
|
57
|
+
if (sourceArray && sourceArray.length > 0) {
|
|
58
|
+
let data = {};
|
|
59
|
+
switch (sourceArray.length) {
|
|
60
|
+
case 0: {
|
|
61
|
+
data = {};
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
case 1: {
|
|
65
|
+
const keyName = sourceArray[0]["keyName"];
|
|
66
|
+
const sourcePath = sourceArray[0]["sourcePath"];
|
|
67
|
+
const rawData = processor.getParsedValue(sourcePath, node.id);
|
|
68
|
+
if (keyName) {
|
|
69
|
+
data = {
|
|
70
|
+
[keyName]: rawData
|
|
71
|
+
};
|
|
72
|
+
} else {
|
|
73
|
+
data = rawData;
|
|
74
|
+
}
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
default: {
|
|
78
|
+
data = sourceArray.reduce(
|
|
79
|
+
(cookedData, { keyName, sourcePath }) => ({
|
|
80
|
+
...cookedData,
|
|
81
|
+
[keyName]: processor.getParsedValue(sourcePath, node.id)
|
|
82
|
+
}),
|
|
83
|
+
{}
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
triggerData = data;
|
|
88
|
+
}
|
|
55
89
|
if (wf.sync) {
|
|
56
|
-
const p = await this.workflow.trigger(wf,
|
|
90
|
+
const p = await this.workflow.trigger(wf, triggerData, processor.options);
|
|
57
91
|
if (!p) {
|
|
58
92
|
return {
|
|
59
93
|
status: import_constants.JOB_STATUS.FAILED,
|
|
@@ -67,12 +101,20 @@ class TriggerInstruction extends import_instructions.default {
|
|
|
67
101
|
result: `Sub-workflow execution failed: ${lastSavedJob.result}`
|
|
68
102
|
};
|
|
69
103
|
}
|
|
104
|
+
let result = lastSavedJob == null ? void 0 : lastSavedJob.result;
|
|
105
|
+
if (typeof result === "object" && result && (model == null ? void 0 : model.length)) {
|
|
106
|
+
if (Array.isArray(result)) {
|
|
107
|
+
result = result.map((item) => this.mapModel(item, model));
|
|
108
|
+
} else {
|
|
109
|
+
result = this.mapModel(result, model);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
70
112
|
return {
|
|
71
113
|
status: import_constants.JOB_STATUS.RESOLVED,
|
|
72
|
-
result
|
|
114
|
+
result
|
|
73
115
|
};
|
|
74
116
|
} else {
|
|
75
|
-
this.workflow.trigger(wf,
|
|
117
|
+
this.workflow.trigger(wf, triggerData, {
|
|
76
118
|
...processor.options,
|
|
77
119
|
parentNode: node.id,
|
|
78
120
|
parent: processor.execution
|
|
@@ -89,8 +131,32 @@ class TriggerInstruction extends import_instructions.default {
|
|
|
89
131
|
};
|
|
90
132
|
}
|
|
91
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* 将数据按照 model 配置进行字段映射
|
|
136
|
+
*/
|
|
137
|
+
mapModel(data, model) {
|
|
138
|
+
if (typeof data !== "object" || data === null) {
|
|
139
|
+
throw new Error("Invalid data: data should be a non-null object");
|
|
140
|
+
}
|
|
141
|
+
const result = model.reduce((acc, { path, alias }) => {
|
|
142
|
+
const key = alias ?? path.replace(/\./g, "_");
|
|
143
|
+
const value = import_lodash.default.get(data, path);
|
|
144
|
+
acc[key] = value;
|
|
145
|
+
return acc;
|
|
146
|
+
}, {});
|
|
147
|
+
return result;
|
|
148
|
+
}
|
|
92
149
|
async resume(node, prevJob, processor) {
|
|
93
|
-
|
|
150
|
+
const { model } = node.config;
|
|
151
|
+
let result = prevJob.result;
|
|
152
|
+
if (typeof result === "object" && result && (model == null ? void 0 : model.length)) {
|
|
153
|
+
if (Array.isArray(result)) {
|
|
154
|
+
result = result.map((item) => this.mapModel(item, model));
|
|
155
|
+
} else {
|
|
156
|
+
result = this.mapModel(result, model);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
prevJob.set("result", result);
|
|
94
160
|
prevJob.set("status", prevJob.status);
|
|
95
161
|
return prevJob;
|
|
96
162
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import Instruction from '.';
|
|
2
|
+
import type Processor from '../Processor';
|
|
3
|
+
import type { FlowNodeModel } from '../types';
|
|
4
|
+
export declare class SelectInstruction extends Instruction {
|
|
5
|
+
run(node: FlowNodeModel, input: any, processor: Processor): Promise<{
|
|
6
|
+
result: any;
|
|
7
|
+
status: -1;
|
|
8
|
+
} | {
|
|
9
|
+
result: any;
|
|
10
|
+
status: 1;
|
|
11
|
+
}>;
|
|
12
|
+
}
|
|
13
|
+
export default SelectInstruction;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
+
var SelectInstruction_exports = {};
|
|
29
|
+
__export(SelectInstruction_exports, {
|
|
30
|
+
SelectInstruction: () => SelectInstruction,
|
|
31
|
+
default: () => SelectInstruction_default
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(SelectInstruction_exports);
|
|
34
|
+
var import_server = require("@tego/server");
|
|
35
|
+
var import_lodash = require("lodash");
|
|
36
|
+
var import__ = __toESM(require("."));
|
|
37
|
+
var import_constants = require("../constants");
|
|
38
|
+
var import_utils = require("../utils");
|
|
39
|
+
class SelectInstruction extends import__.default {
|
|
40
|
+
async run(node, input, processor) {
|
|
41
|
+
var _a, _b, _c, _d;
|
|
42
|
+
const { collection, multiple, isTree, params = {}, failOnEmpty = false } = node.config;
|
|
43
|
+
const otherOptions = {};
|
|
44
|
+
if (isTree) {
|
|
45
|
+
otherOptions.tree = true;
|
|
46
|
+
}
|
|
47
|
+
const [dataSourceName, collectionName] = (0, import_server.parseCollectionName)(collection);
|
|
48
|
+
const { repository, fields } = this.workflow.app.dataSourceManager.dataSources.get(dataSourceName).collectionManager.getCollection(collectionName);
|
|
49
|
+
const { page, pageSize, sort = [], paginate = true, ...options } = processor.getParsedValue(params, node.id);
|
|
50
|
+
const appends = ((_a = options.summary) == null ? void 0 : _a.includes(".")) ? [options.summary] : [];
|
|
51
|
+
if (options.summary && !((_b = options.summary) == null ? void 0 : _b.includes("."))) {
|
|
52
|
+
if (["belongsTo", "hasOne", "hasMany", "belongsToMany"].includes((_c = fields.get(options.summary)) == null ? void 0 : _c.type)) {
|
|
53
|
+
appends.push(options.summary);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
let pageArgs = paginate ? import_server.utils.pageArgsToLimitArgs(page, pageSize) : {};
|
|
57
|
+
const data = await (multiple ? repository.find : repository.findOne).call(repository, {
|
|
58
|
+
...options,
|
|
59
|
+
...otherOptions,
|
|
60
|
+
...pageArgs,
|
|
61
|
+
sort: sort.filter((item) => item.field).map((item) => {
|
|
62
|
+
var _a2;
|
|
63
|
+
return `${((_a2 = item.direction) == null ? void 0 : _a2.toLowerCase()) === "desc" ? "-" : ""}${item.field}`;
|
|
64
|
+
}),
|
|
65
|
+
appends,
|
|
66
|
+
transaction: this.workflow.useDataSourceTransaction(dataSourceName, processor.transaction)
|
|
67
|
+
});
|
|
68
|
+
let result;
|
|
69
|
+
const summary = ((_d = options.summary) == null ? void 0 : _d.length) ? options.summary.split(".") : null;
|
|
70
|
+
if (summary) {
|
|
71
|
+
if ((0, import_lodash.isArray)(data)) {
|
|
72
|
+
result = [];
|
|
73
|
+
data.forEach((item) => {
|
|
74
|
+
const filteredValue = findField(item, summary[0], 0, summary, multiple, true);
|
|
75
|
+
const value = (0, import_lodash.isArray)(filteredValue) ? filteredValue : [filteredValue];
|
|
76
|
+
result.push(...value);
|
|
77
|
+
});
|
|
78
|
+
} else {
|
|
79
|
+
result = findField(data, summary[0], 0, summary, multiple, true);
|
|
80
|
+
}
|
|
81
|
+
result = (0, import_lodash.isArray)(result) ? multiple ? result : result[0] : result;
|
|
82
|
+
}
|
|
83
|
+
if (failOnEmpty && (multiple ? !data.length : !data)) {
|
|
84
|
+
return {
|
|
85
|
+
result: summary ? result : data,
|
|
86
|
+
status: import_constants.JOB_STATUS.FAILED
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
result: (0, import_utils.toJSON)(summary ? result : data),
|
|
91
|
+
status: import_constants.JOB_STATUS.RESOLVED
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
var SelectInstruction_default = SelectInstruction;
|
|
96
|
+
const findField = (record, field, index, summary, multiple, isOne) => {
|
|
97
|
+
if (record == null) {
|
|
98
|
+
return void 0;
|
|
99
|
+
}
|
|
100
|
+
if (!multiple && !isOne) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
let isOneField = isOne;
|
|
104
|
+
const current = record[field];
|
|
105
|
+
if (index === summary.length - 1) {
|
|
106
|
+
if (!multiple && isOne) {
|
|
107
|
+
isOneField = false;
|
|
108
|
+
}
|
|
109
|
+
return current;
|
|
110
|
+
}
|
|
111
|
+
const nextField = summary[index + 1];
|
|
112
|
+
if (Array.isArray(current)) {
|
|
113
|
+
const results = [];
|
|
114
|
+
current.forEach((item) => {
|
|
115
|
+
const v = findField(item, nextField, index + 1, summary, multiple, isOneField);
|
|
116
|
+
if (v === void 0) return;
|
|
117
|
+
results.push(v);
|
|
118
|
+
});
|
|
119
|
+
return results;
|
|
120
|
+
}
|
|
121
|
+
return findField(current, nextField, index + 1, summary, multiple, isOneField);
|
|
122
|
+
};
|
|
123
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
124
|
+
0 && (module.exports = {
|
|
125
|
+
SelectInstruction
|
|
126
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 远程代码获取服务(Workflow 模块专用)
|
|
3
|
+
* 支持从 CDN 和 Git 仓库获取代码
|
|
4
|
+
*/
|
|
5
|
+
export declare class WorkflowRemoteCodeFetcher {
|
|
6
|
+
private logger;
|
|
7
|
+
/**
|
|
8
|
+
* 从 CDN 获取代码
|
|
9
|
+
* @param url 代码 URL
|
|
10
|
+
* @param timeout 超时时间(毫秒)
|
|
11
|
+
* @param authType 认证类型: 'none' | 'token' | 'basic'
|
|
12
|
+
* @param authToken Bearer Token 或 Basic Auth 的密码
|
|
13
|
+
* @param authUsername Basic Auth 的用户名
|
|
14
|
+
*/
|
|
15
|
+
private fetchFromCDN;
|
|
16
|
+
/**
|
|
17
|
+
* 检测 URL 是否已经是 Raw 文件 URL(可以直接访问)
|
|
18
|
+
*/
|
|
19
|
+
private isRawFileUrl;
|
|
20
|
+
/**
|
|
21
|
+
* 从 URL 中解析分支和文件路径
|
|
22
|
+
*/
|
|
23
|
+
private parseGitUrl;
|
|
24
|
+
/**
|
|
25
|
+
* 从 Git 仓库获取代码(通过 Raw 文件 URL)
|
|
26
|
+
*/
|
|
27
|
+
private fetchFromGit;
|
|
28
|
+
/**
|
|
29
|
+
* 获取远程代码
|
|
30
|
+
* @param codeUrl 代码地址
|
|
31
|
+
* @param codeType 代码类型:'cdn' 或 'git'
|
|
32
|
+
* @param codeBranch Git 分支名称(仅 Git 类型需要)
|
|
33
|
+
* @param codePath Git 文件路径(仅 Git 类型需要)
|
|
34
|
+
* @param authType 认证类型: 'none' | 'token' | 'basic'
|
|
35
|
+
* @param authToken Bearer Token 或 Basic Auth 的密码
|
|
36
|
+
* @param authUsername Basic Auth 的用户名
|
|
37
|
+
*/
|
|
38
|
+
fetchCode(codeUrl: string, codeType: 'cdn' | 'git', codeBranch?: string, codePath?: string, authType?: string, authToken?: string, authUsername?: string): Promise<string>;
|
|
39
|
+
/**
|
|
40
|
+
* 检查缓存是否有效(默认缓存 1 小时)
|
|
41
|
+
* @param cache 缓存对象,包含 content 和 timestamp
|
|
42
|
+
* @param maxAge 最大缓存时间(毫秒),默认 1 小时 (3600000ms)
|
|
43
|
+
*/
|
|
44
|
+
isCacheValid(cache: {
|
|
45
|
+
content: string;
|
|
46
|
+
timestamp: number;
|
|
47
|
+
} | null, maxAge?: number): boolean;
|
|
48
|
+
}
|