@nocobase/plugin-flow-engine 2.0.0-beta.2 → 2.0.0-beta.20

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,14 +8,14 @@
8
8
  */
9
9
 
10
10
  module.exports = {
11
- "@nocobase/client": "2.0.0-beta.2",
11
+ "@nocobase/client": "2.0.0-beta.20",
12
12
  "lodash": "4.17.21",
13
- "@nocobase/database": "2.0.0-beta.2",
14
- "@nocobase/data-source-manager": "2.0.0-beta.2",
15
- "@nocobase/resourcer": "2.0.0-beta.2",
16
- "@nocobase/server": "2.0.0-beta.2",
17
- "@nocobase/utils": "2.0.0-beta.2",
18
- "@nocobase/cache": "2.0.0-beta.2",
19
- "@nocobase/plugin-localization": "2.0.0-beta.2",
20
- "@nocobase/actions": "2.0.0-beta.2"
13
+ "@nocobase/database": "2.0.0-beta.20",
14
+ "@nocobase/data-source-manager": "2.0.0-beta.20",
15
+ "@nocobase/resourcer": "2.0.0-beta.20",
16
+ "@nocobase/server": "2.0.0-beta.20",
17
+ "@nocobase/utils": "2.0.0-beta.20",
18
+ "@nocobase/cache": "2.0.0-beta.20",
19
+ "@nocobase/plugin-localization": "2.0.0-beta.20",
20
+ "@nocobase/actions": "2.0.0-beta.20"
21
21
  };
@@ -1 +1 @@
1
- {"name":"ses","version":"1.14.0","description":"Hardened JavaScript for Fearless Cooperation","keywords":["lockdown","harden","Compartment","assert","security","confinement","isolation","object capabilities","ocaps","secure execution","third-party code","prototype pollution","supply-chain attack","plugin"],"author":"Agoric","license":"Apache-2.0","homepage":"https://github.com/Agoric/SES-shim/tree/master/packages/ses#readme","repository":{"type":"git","url":"git+https://github.com/endojs/endo.git","directory":"packages/ses"},"bugs":{"url":"https://github.com/endojs/endo/issues"},"type":"module","main":"./dist/ses.cjs","module":"./index.js","unpkg":"./dist/ses.umd.js","types":"./types.d.ts","exports":{".":{"import":{"types":"./types.d.ts","xs":"./src-xs/index.js","default":"./index.js"},"require":{"types":"./dist/types.d.cts","default":"./dist/ses.cjs"}},"./lockdown":{"import":{"types":"./types.d.ts","default":"./index.js"},"require":{"types":"./dist/types.d.cts","default":"./dist/ses.cjs"}},"./hermes":{"require":{"types":"./dist/types.d.cts","default":"./dist/ses-hermes.cjs"}},"./tools.js":"./tools.js","./assert-shim.js":"./assert-shim.js","./lockdown-shim.js":{"xs":"./src-xs/lockdown-shim.js","default":"./lockdown-shim.js"},"./compartment-shim.js":{"xs":"./src-xs/compartment-shim.js","default":"./compartment-shim.js"},"./console-shim.js":"./console-shim.js","./package.json":"./package.json"},"scripts":{"build:vanilla":"node scripts/bundle.js","build:hermes":"node scripts/bundle.js hermes","build":"yarn build:vanilla && yarn build:hermes","clean":"rm -rf dist","cover":"c8 ava","demo":"python3 -m http.server","lint":"yarn lint:types && yarn lint:eslint","lint-fix":"eslint --fix .","lint:eslint":"eslint .","lint:types":"tsc","prepare":"npm run clean && npm run build","qt":"ava","test":"tsd && ava","test:hermes":"./scripts/hermes-test.sh","test:xs":"xst dist/ses.umd.js test/_lockdown-safe.js && node scripts/generate-test-xs.js && xst tmp/test-xs.js && rm -rf tmp","postpack":"git clean -fX \"*.d.ts*\" \"*.d.cts*\" \"*.d.mts*\" \"*.tsbuildinfo\""},"dependencies":{"@endo/cache-map":"^1.1.0","@endo/env-options":"^1.1.11","@endo/immutable-arraybuffer":"^1.1.2"},"devDependencies":{"@babel/generator":"^7.26.3","@babel/parser":"~7.26.2","@babel/traverse":"~7.25.9","@babel/types":"~7.26.0","@endo/compartment-mapper":"^1.6.3","@endo/module-source":"^1.3.3","@endo/test262-runner":"^0.1.48","@types/babel__traverse":"^7.20.5","ava":"^6.1.3","babel-eslint":"^10.1.0","c8":"^7.14.0","core-js":"^3.31.0","eslint":"^8.57.1","eslint-config-airbnb-base":"^15.0.0","eslint-config-prettier":"^9.1.0","eslint-plugin-eslint-comments":"^3.2.0","eslint-plugin-import":"^2.31.0","hermes-engine-cli":"^0.12.0","prettier":"^3.5.3","terser":"^5.16.6","tsd":"^0.31.2","typescript":"~5.8.3"},"files":["./*.d.ts","./*.js","./*.map","LICENSE*","SECURITY*","dist","lib","src","tools"],"publishConfig":{"access":"public"},"eslintConfig":{"extends":["plugin:@endo/ses"]},"ava":{"files":["test/**/*.test.*"],"timeout":"2m"},"typeCoverage":{"atLeast":81.17},"gitHead":"9815aea9541f241389d2135c6097a7442bdffa17","_lastModified":"2026-01-04T03:43:16.826Z"}
1
+ {"name":"ses","version":"1.14.0","description":"Hardened JavaScript for Fearless Cooperation","keywords":["lockdown","harden","Compartment","assert","security","confinement","isolation","object capabilities","ocaps","secure execution","third-party code","prototype pollution","supply-chain attack","plugin"],"author":"Agoric","license":"Apache-2.0","homepage":"https://github.com/Agoric/SES-shim/tree/master/packages/ses#readme","repository":{"type":"git","url":"git+https://github.com/endojs/endo.git","directory":"packages/ses"},"bugs":{"url":"https://github.com/endojs/endo/issues"},"type":"module","main":"./dist/ses.cjs","module":"./index.js","unpkg":"./dist/ses.umd.js","types":"./types.d.ts","exports":{".":{"import":{"types":"./types.d.ts","xs":"./src-xs/index.js","default":"./index.js"},"require":{"types":"./dist/types.d.cts","default":"./dist/ses.cjs"}},"./lockdown":{"import":{"types":"./types.d.ts","default":"./index.js"},"require":{"types":"./dist/types.d.cts","default":"./dist/ses.cjs"}},"./hermes":{"require":{"types":"./dist/types.d.cts","default":"./dist/ses-hermes.cjs"}},"./tools.js":"./tools.js","./assert-shim.js":"./assert-shim.js","./lockdown-shim.js":{"xs":"./src-xs/lockdown-shim.js","default":"./lockdown-shim.js"},"./compartment-shim.js":{"xs":"./src-xs/compartment-shim.js","default":"./compartment-shim.js"},"./console-shim.js":"./console-shim.js","./package.json":"./package.json"},"scripts":{"build:vanilla":"node scripts/bundle.js","build:hermes":"node scripts/bundle.js hermes","build":"yarn build:vanilla && yarn build:hermes","clean":"rm -rf dist","cover":"c8 ava","demo":"python3 -m http.server","lint":"yarn lint:types && yarn lint:eslint","lint-fix":"eslint --fix .","lint:eslint":"eslint .","lint:types":"tsc","prepare":"npm run clean && npm run build","qt":"ava","test":"tsd && ava","test:hermes":"./scripts/hermes-test.sh","test:xs":"xst dist/ses.umd.js test/_lockdown-safe.js && node scripts/generate-test-xs.js && xst tmp/test-xs.js && rm -rf tmp","postpack":"git clean -fX \"*.d.ts*\" \"*.d.cts*\" \"*.d.mts*\" \"*.tsbuildinfo\""},"dependencies":{"@endo/cache-map":"^1.1.0","@endo/env-options":"^1.1.11","@endo/immutable-arraybuffer":"^1.1.2"},"devDependencies":{"@babel/generator":"^7.26.3","@babel/parser":"~7.26.2","@babel/traverse":"~7.25.9","@babel/types":"~7.26.0","@endo/compartment-mapper":"^1.6.3","@endo/module-source":"^1.3.3","@endo/test262-runner":"^0.1.48","@types/babel__traverse":"^7.20.5","ava":"^6.1.3","babel-eslint":"^10.1.0","c8":"^7.14.0","core-js":"^3.31.0","eslint":"^8.57.1","eslint-config-airbnb-base":"^15.0.0","eslint-config-prettier":"^9.1.0","eslint-plugin-eslint-comments":"^3.2.0","eslint-plugin-import":"^2.31.0","hermes-engine-cli":"^0.12.0","prettier":"^3.5.3","terser":"^5.16.6","tsd":"^0.31.2","typescript":"~5.8.3"},"files":["./*.d.ts","./*.js","./*.map","LICENSE*","SECURITY*","dist","lib","src","tools"],"publishConfig":{"access":"public"},"eslintConfig":{"extends":["plugin:@endo/ses"]},"ava":{"files":["test/**/*.test.*"],"timeout":"2m"},"typeCoverage":{"atLeast":81.17},"gitHead":"9815aea9541f241389d2135c6097a7442bdffa17","_lastModified":"2026-02-05T04:38:23.535Z"}
@@ -78,14 +78,18 @@ async function replacePlaceholders(input, ctx) {
78
78
  async function evaluate(expr, ctx) {
79
79
  try {
80
80
  const raw = expr.trim();
81
- const dotOnly = raw.match(/^ctx\.([a-zA-Z_$][a-zA-Z0-9_$]*(?:\.[a-zA-Z_$][a-zA-Z0-9_$]*)*)$/);
81
+ const dotOnly = raw.match(
82
+ /^ctx\.([a-zA-Z_$][a-zA-Z0-9_$]*)(?:\.([a-zA-Z_$][a-zA-Z0-9_$-]*(?:\.[a-zA-Z_$][a-zA-Z0-9_$-]*)*))?$/
83
+ );
82
84
  if (dotOnly) {
83
- const path = dotOnly[1];
84
- const segs = path.split(".");
85
- const first = segs.shift();
85
+ const first = dotOnly[1];
86
+ const rest = dotOnly[2];
86
87
  const base = await ctx[first];
87
- if (!segs.length) return base;
88
- return await asyncGetValuesByPath(base, segs.join("."));
88
+ if (!rest) return base;
89
+ const resolved = await asyncGetValuesByPath(base, rest);
90
+ if (typeof resolved !== "undefined" || !rest.includes("-")) {
91
+ return resolved;
92
+ }
89
93
  }
90
94
  const transformed = preprocessExpression(raw);
91
95
  const compartment = new Compartment({
@@ -0,0 +1,38 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+ type FilterTargetKey = string | string[] | undefined;
10
+ /**
11
+ * 为了:
12
+ * - 关联加载/缓存:fields 模式下确保包含主键
13
+ * - filterByTk 为数组时:尽量包含 filterTargetKey,以便按输入顺序对齐结果
14
+ *
15
+ * 该函数只返回“建议追加”的 key 字段(不会决定是否追加,由调用方根据是否启用 fields 决定)。
16
+ */
17
+ export declare function getExtraKeyFieldsForSelect(filterByTk: unknown, options: {
18
+ filterTargetKey?: FilterTargetKey;
19
+ pkAttr?: string;
20
+ pkIsValid?: boolean;
21
+ rawAttributes?: Record<string, unknown>;
22
+ }): string[];
23
+ export declare function mergeFieldsWithExtras(fields?: string[], extras?: string[]): string[] | undefined;
24
+ /**
25
+ * 根据 filterByTk 类型(单值/数组)查询并返回 JSON 数据:
26
+ * - 单值:返回 object | undefined
27
+ * - 数组:返回 array(空数组时返回 [],不会退化为无条件查询)
28
+ */
29
+ export declare function fetchRecordOrRecordsJson(repo: any, params: {
30
+ filterByTk: unknown;
31
+ preferFullRecord?: boolean;
32
+ fields?: string[];
33
+ appends?: string[];
34
+ filterTargetKey?: FilterTargetKey;
35
+ pkAttr?: string;
36
+ pkIsValid?: boolean;
37
+ }): Promise<unknown>;
38
+ export {};
@@ -0,0 +1,120 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+
10
+ var __defProp = Object.defineProperty;
11
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
+ var __getOwnPropNames = Object.getOwnPropertyNames;
13
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
14
+ var __export = (target, all) => {
15
+ for (var name in all)
16
+ __defProp(target, name, { get: all[name], enumerable: true });
17
+ };
18
+ var __copyProps = (to, from, except, desc) => {
19
+ if (from && typeof from === "object" || typeof from === "function") {
20
+ for (let key of __getOwnPropNames(from))
21
+ if (!__hasOwnProp.call(to, key) && key !== except)
22
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
23
+ }
24
+ return to;
25
+ };
26
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
27
+ var records_exports = {};
28
+ __export(records_exports, {
29
+ fetchRecordOrRecordsJson: () => fetchRecordOrRecordsJson,
30
+ getExtraKeyFieldsForSelect: () => getExtraKeyFieldsForSelect,
31
+ mergeFieldsWithExtras: () => mergeFieldsWithExtras
32
+ });
33
+ module.exports = __toCommonJS(records_exports);
34
+ function uniqStrings(list) {
35
+ return Array.from(new Set(list));
36
+ }
37
+ function isPrimitiveTkArray(arr) {
38
+ return arr.every((v) => typeof v === "string" || typeof v === "number");
39
+ }
40
+ function getOrderKey(options) {
41
+ if (typeof options.filterTargetKey === "string") return options.filterTargetKey;
42
+ if (options.pkIsValid && options.pkAttr) return options.pkAttr;
43
+ return void 0;
44
+ }
45
+ function getExtraKeyFieldsForSelect(filterByTk, options) {
46
+ const extra = [];
47
+ if (options.pkIsValid && options.pkAttr) {
48
+ extra.push(options.pkAttr);
49
+ }
50
+ if (Array.isArray(filterByTk) && filterByTk.length > 0) {
51
+ const tkKeys = typeof options.filterTargetKey === "string" ? [options.filterTargetKey] : Array.isArray(options.filterTargetKey) ? options.filterTargetKey : [];
52
+ if (options.rawAttributes) {
53
+ for (const k of tkKeys) {
54
+ if (k && Object.prototype.hasOwnProperty.call(options.rawAttributes, k)) {
55
+ extra.push(k);
56
+ }
57
+ }
58
+ }
59
+ }
60
+ return uniqStrings(extra);
61
+ }
62
+ function mergeFieldsWithExtras(fields, extras = []) {
63
+ if (!Array.isArray(fields) || fields.length === 0 || extras.length === 0) return fields;
64
+ return uniqStrings([...fields, ...extras]);
65
+ }
66
+ function toJsonArray(rows) {
67
+ if (!Array.isArray(rows)) return [];
68
+ return rows.map((r) => (r == null ? void 0 : r.toJSON) ? r.toJSON() : r);
69
+ }
70
+ function reorderRecordsByFilterByTk(records, filterByTk, options) {
71
+ if (!Array.isArray(filterByTk) || filterByTk.length === 0) return records;
72
+ if (!isPrimitiveTkArray(filterByTk)) return records;
73
+ const orderKey = getOrderKey(options);
74
+ if (!orderKey) return records;
75
+ const map = /* @__PURE__ */ new Map();
76
+ for (const rec of records || []) {
77
+ const k = rec == null ? void 0 : rec[orderKey];
78
+ if (typeof k !== "undefined" && k !== null) {
79
+ map.set(String(k), rec);
80
+ }
81
+ }
82
+ const ordered = [];
83
+ const used = /* @__PURE__ */ new Set();
84
+ for (const tk of filterByTk) {
85
+ const k = String(tk);
86
+ const rec = map.get(k);
87
+ if (typeof rec !== "undefined") {
88
+ ordered.push(rec);
89
+ used.add(k);
90
+ }
91
+ }
92
+ for (const rec of records || []) {
93
+ const k = rec == null ? void 0 : rec[orderKey];
94
+ const ks = typeof k === "undefined" || k === null ? void 0 : String(k);
95
+ if (!ks || used.has(ks)) continue;
96
+ ordered.push(rec);
97
+ }
98
+ return ordered;
99
+ }
100
+ async function fetchRecordOrRecordsJson(repo, params) {
101
+ const { filterByTk, preferFullRecord, fields, appends } = params;
102
+ if (Array.isArray(filterByTk)) {
103
+ if (filterByTk.length === 0) return [];
104
+ const rows = await repo.find(
105
+ preferFullRecord ? { filterByTk } : { filterByTk, fields, appends }
106
+ );
107
+ const jsonArr = toJsonArray(rows);
108
+ return reorderRecordsByFilterByTk(jsonArr, filterByTk, params);
109
+ }
110
+ const rec = await repo.findOne(
111
+ preferFullRecord ? { filterByTk } : { filterByTk, fields, appends }
112
+ );
113
+ return rec ? rec.toJSON() : void 0;
114
+ }
115
+ // Annotate the CommonJS export names for ESM import in node:
116
+ 0 && (module.exports = {
117
+ fetchRecordOrRecordsJson,
118
+ getExtraKeyFieldsForSelect,
119
+ mergeFieldsWithExtras
120
+ });
@@ -44,6 +44,7 @@ var import_lodash = __toESM(require("lodash"));
44
44
  var import_contexts = require("../template/contexts");
45
45
  var import_utils = require("@nocobase/utils");
46
46
  var import_selects = require("./selects");
47
+ var import_records = require("./records");
47
48
  class VariableRegistry {
48
49
  vars = /* @__PURE__ */ new Map();
49
50
  register(def) {
@@ -129,7 +130,7 @@ function inferSelectsFromUsage(paths = [], _params) {
129
130
  const generatedFields = fieldSet.size ? Array.from(fieldSet) : void 0;
130
131
  return { generatedAppends, generatedFields };
131
132
  }
132
- async function fetchRecordWithRequestCache(koaCtx, dataSourceKey, collection, filterByTk, fields, appends, preferFullRecord, associationName, sourceId) {
133
+ async function fetchRecordWithRequestCache(koaCtx, dataSourceKey, collection, filterByTk, fields, appends, strictSelects, preferFullRecord, associationName, sourceId) {
133
134
  var _a, _b, _c, _d, _e;
134
135
  try {
135
136
  const log = (_b = (_a = koaCtx.app) == null ? void 0 : _a.logger) == null ? void 0 : _b.child({
@@ -150,8 +151,17 @@ async function fetchRecordWithRequestCache(koaCtx, dataSourceKey, collection, fi
150
151
  const modelInfo = (_c = repo.collection) == null ? void 0 : _c.model;
151
152
  const pkAttr = modelInfo == null ? void 0 : modelInfo.primaryKeyAttribute;
152
153
  const pkIsValid = pkAttr && (modelInfo == null ? void 0 : modelInfo.rawAttributes) && Object.prototype.hasOwnProperty.call(modelInfo.rawAttributes, pkAttr);
153
- const fieldsWithPk = Array.isArray(fields) && fields.length > 0 && pkIsValid ? Array.from(/* @__PURE__ */ new Set([...fields, pkAttr])) : fields;
154
- const cacheKeyFields = preferFullRecord && pkIsValid ? void 0 : Array.isArray(fieldsWithPk) ? [...fieldsWithPk].sort() : void 0;
154
+ const collectionInfo = repo == null ? void 0 : repo.collection;
155
+ const filterTargetKey = collectionInfo == null ? void 0 : collectionInfo.filterTargetKey;
156
+ const extraKeys = (0, import_records.getExtraKeyFieldsForSelect)(filterByTk, {
157
+ filterTargetKey,
158
+ pkAttr,
159
+ pkIsValid,
160
+ rawAttributes: (modelInfo == null ? void 0 : modelInfo.rawAttributes) || void 0
161
+ });
162
+ const effectiveExtras = strictSelects && Array.isArray(extraKeys) && extraKeys.length ? extraKeys.filter((k) => k === pkAttr) : extraKeys;
163
+ const fieldsWithExtras = (0, import_records.mergeFieldsWithExtras)(fields, effectiveExtras);
164
+ const cacheKeyFields = preferFullRecord && pkIsValid ? void 0 : Array.isArray(fieldsWithExtras) ? [...fieldsWithExtras].sort() : void 0;
155
165
  const cacheKeyAppends = preferFullRecord ? void 0 : Array.isArray(appends) ? [...appends].sort() : void 0;
156
166
  const keyObj = {
157
167
  ds: dataSourceKey || "main",
@@ -168,40 +178,41 @@ async function fetchRecordWithRequestCache(koaCtx, dataSourceKey, collection, fi
168
178
  if (cache.has(key)) {
169
179
  return cache.get(key);
170
180
  }
171
- const needFields = !preferFullRecord && Array.isArray(fieldsWithPk) ? [...new Set(fieldsWithPk)] : void 0;
172
- const needAppends = !preferFullRecord && Array.isArray(appends) ? new Set(appends) : void 0;
173
- for (const [cacheKey, cacheVal] of cache.entries()) {
174
- const parsed = JSON.parse(cacheKey);
175
- if (!parsed || parsed.ds !== keyObj.ds || parsed.c !== keyObj.c || parsed.tk !== keyObj.tk || parsed.assoc !== keyObj.assoc || parsed.sid !== keyObj.sid)
176
- continue;
177
- const cachedFields = new Set(parsed.f || []);
178
- const cachedAppends = new Set(parsed.a || []);
179
- const fieldCoveredByAppends = (fieldPath) => {
180
- const p = String(fieldPath || "");
181
- for (const a of cachedAppends) {
182
- if (!a) continue;
183
- if (p === a || p.startsWith(a + ".")) return true;
181
+ if (!strictSelects) {
182
+ const needFields = !preferFullRecord && Array.isArray(fieldsWithExtras) ? [...new Set(fieldsWithExtras)] : void 0;
183
+ const needAppends = !preferFullRecord && Array.isArray(appends) ? new Set(appends) : void 0;
184
+ for (const [cacheKey, cacheVal] of cache.entries()) {
185
+ const parsed = JSON.parse(cacheKey);
186
+ if (!parsed || parsed.ds !== keyObj.ds || parsed.c !== keyObj.c || !import_lodash.default.isEqual(parsed.tk, keyObj.tk) || parsed.assoc !== keyObj.assoc || !import_lodash.default.isEqual(parsed.sid, keyObj.sid))
187
+ continue;
188
+ const cachedFields = new Set(parsed.f || []);
189
+ const cachedAppends = new Set(parsed.a || []);
190
+ const fieldCoveredByAppends = (fieldPath) => {
191
+ const p = String(fieldPath || "");
192
+ for (const a of cachedAppends) {
193
+ if (!a) continue;
194
+ if (p === a || p.startsWith(a + ".")) return true;
195
+ }
196
+ return false;
197
+ };
198
+ const fieldsOk = needFields ? needFields.every((f) => cachedFields.has(f) || fieldCoveredByAppends(f)) : parsed.f === void 0;
199
+ const appendsOk = !needAppends || [...needAppends].every((a) => cachedAppends.has(a));
200
+ const fullOk = preferFullRecord ? parsed.full === true : true;
201
+ if (fieldsOk && appendsOk && fullOk) {
202
+ return cacheVal;
184
203
  }
185
- return false;
186
- };
187
- const fieldsOk = needFields ? needFields.every((f) => cachedFields.has(f) || fieldCoveredByAppends(f)) : parsed.f === void 0;
188
- const appendsOk = !needAppends || [...needAppends].every((a) => cachedAppends.has(a));
189
- const fullOk = preferFullRecord ? parsed.full === true : true;
190
- if (fieldsOk && appendsOk && fullOk) {
191
- return cacheVal;
192
204
  }
193
205
  }
194
206
  }
195
- const rec = await repo.findOne(
196
- preferFullRecord ? {
197
- filterByTk
198
- } : {
199
- filterByTk,
200
- fields: fieldsWithPk,
201
- appends
202
- }
203
- );
204
- const json = rec ? rec.toJSON() : void 0;
207
+ const json = await (0, import_records.fetchRecordOrRecordsJson)(repo, {
208
+ filterByTk,
209
+ preferFullRecord,
210
+ fields: fieldsWithExtras,
211
+ appends,
212
+ filterTargetKey,
213
+ pkAttr,
214
+ pkIsValid
215
+ });
205
216
  if (cache) cache.set(key, json);
206
217
  return json;
207
218
  } catch (e) {
@@ -233,12 +244,37 @@ function attachGenericRecordVariables(flowCtx, koaCtx, usage, contextParams) {
233
244
  for (const varName of Object.keys(usage)) {
234
245
  const usedPaths = usage[varName] || [];
235
246
  const topParams = import_lodash.default.get(contextParams, varName);
247
+ const deepRecordMap = /* @__PURE__ */ new Map();
248
+ const cp = contextParams;
249
+ if (cp && typeof cp === "object") {
250
+ const cpRec = cp;
251
+ for (const key of Object.keys(cpRec)) {
252
+ if (!key || key !== varName && !key.startsWith(`${varName}.`)) continue;
253
+ if (key === varName) continue;
254
+ const val = cpRec[key];
255
+ if (!isRecordParams(val)) continue;
256
+ const relative = key.slice(varName.length + 1);
257
+ if (!relative) continue;
258
+ deepRecordMap.set(relative, val);
259
+ }
260
+ }
236
261
  if (isRecordParams(topParams)) {
237
- const { generatedAppends, generatedFields } = inferSelectsFromUsage(usedPaths, topParams);
238
- const hasDirectRefTop = (usedPaths || []).some((p) => p === "");
262
+ const usedPathsForBase = deepRecordMap.size ? (usedPaths || []).filter((p) => {
263
+ if (!p) return true;
264
+ for (const relative of deepRecordMap.keys()) {
265
+ if (!relative) continue;
266
+ if (p === relative || p.startsWith(relative + ".") || p.startsWith(relative + "[")) return false;
267
+ }
268
+ return true;
269
+ }) : usedPaths || [];
270
+ const hasDirectRefTop = usedPathsForBase.some((p) => p === "");
239
271
  flowCtx.defineProperty(varName, {
240
272
  get: async () => {
241
273
  const dataSourceKey = (topParams == null ? void 0 : topParams.dataSourceKey) || "main";
274
+ const strictSelects = Array.isArray(topParams == null ? void 0 : topParams.fields) || Array.isArray(topParams == null ? void 0 : topParams.appends);
275
+ let { generatedAppends, generatedFields } = inferSelectsFromUsage(usedPathsForBase, topParams);
276
+ if (Array.isArray(topParams == null ? void 0 : topParams.fields)) generatedFields = topParams.fields;
277
+ if (Array.isArray(topParams == null ? void 0 : topParams.appends)) generatedAppends = topParams.appends;
242
278
  const fixed = (0, import_selects.adjustSelectsForCollection)(
243
279
  koaCtx,
244
280
  dataSourceKey,
@@ -246,17 +282,69 @@ function attachGenericRecordVariables(flowCtx, koaCtx, usage, contextParams) {
246
282
  generatedFields,
247
283
  generatedAppends
248
284
  );
249
- return await fetchRecordWithRequestCache(
285
+ const base = await fetchRecordWithRequestCache(
250
286
  koaCtx,
251
287
  dataSourceKey,
252
288
  topParams.collection,
253
289
  topParams.filterByTk,
254
290
  fixed.fields,
255
291
  fixed.appends,
292
+ strictSelects,
256
293
  hasDirectRefTop,
257
294
  topParams.associationName,
258
295
  topParams.sourceId
259
296
  );
297
+ if (!deepRecordMap.size) return base;
298
+ const merged = base && typeof base === "object" && !Array.isArray(base) ? { ...base } : {};
299
+ const setClonedPath = (obj, path, value) => {
300
+ const segs = String(path || "").split(".").filter(Boolean);
301
+ if (!segs.length) return;
302
+ if (segs.length === 1) {
303
+ obj[segs[0]] = value;
304
+ return;
305
+ }
306
+ let cur = obj;
307
+ for (let i = 0; i < segs.length - 1; i++) {
308
+ const seg = segs[i];
309
+ const prev = cur[seg];
310
+ const next = prev && typeof prev === "object" && !Array.isArray(prev) ? { ...prev } : {};
311
+ cur[seg] = next;
312
+ cur = next;
313
+ }
314
+ cur[segs[segs.length - 1]] = value;
315
+ };
316
+ const buildNestedPromise = (recordParams, relative) => {
317
+ const subPaths = (usedPaths || []).map((p) => p === relative ? "" : p.startsWith(relative + ".") ? p.slice(relative.length + 1) : "").filter((x) => x !== "");
318
+ const hasDirectRef = (usedPaths || []).some((p) => p === relative);
319
+ const dataSourceKey2 = (recordParams == null ? void 0 : recordParams.dataSourceKey) || "main";
320
+ const strictSelects2 = Array.isArray(recordParams == null ? void 0 : recordParams.fields) || Array.isArray(recordParams == null ? void 0 : recordParams.appends);
321
+ let { generatedAppends: generatedAppends2, generatedFields: generatedFields2 } = inferSelectsFromUsage(subPaths, recordParams);
322
+ if (Array.isArray(recordParams == null ? void 0 : recordParams.fields)) generatedFields2 = recordParams.fields;
323
+ if (Array.isArray(recordParams == null ? void 0 : recordParams.appends)) generatedAppends2 = recordParams.appends;
324
+ const fixed2 = (0, import_selects.adjustSelectsForCollection)(
325
+ koaCtx,
326
+ dataSourceKey2,
327
+ recordParams.collection,
328
+ generatedFields2,
329
+ generatedAppends2
330
+ );
331
+ return fetchRecordWithRequestCache(
332
+ koaCtx,
333
+ dataSourceKey2,
334
+ recordParams.collection,
335
+ recordParams.filterByTk,
336
+ fixed2.fields,
337
+ fixed2.appends,
338
+ strictSelects2,
339
+ hasDirectRef,
340
+ recordParams.associationName,
341
+ recordParams.sourceId
342
+ );
343
+ };
344
+ for (const [relative, recordParams] of deepRecordMap.entries()) {
345
+ setClonedPath(merged, relative, buildNestedPromise(recordParams, relative));
346
+ }
347
+ return merged;
260
348
  },
261
349
  cache: true
262
350
  });
@@ -295,27 +383,16 @@ function attachGenericRecordVariables(flowCtx, koaCtx, usage, contextParams) {
295
383
  const dotted = (contextParams || {})[`${varName}.${seg}`] ?? (idx ? (contextParams || {})[`${varName}.${idx}`] : void 0);
296
384
  return isRecordParams(nestedObj) || isRecordParams(dotted);
297
385
  });
298
- const deepRecordMap = /* @__PURE__ */ new Map();
299
- const cp = contextParams;
300
- if (cp && typeof cp === "object") {
301
- const cpRec = cp;
302
- for (const key of Object.keys(cpRec)) {
303
- if (!key || key !== varName && !key.startsWith(`${varName}.`)) continue;
304
- if (key === varName) continue;
305
- const val = cpRec[key];
306
- if (!isRecordParams(val)) continue;
307
- const relative = key.slice(varName.length + 1);
308
- if (!relative) continue;
309
- deepRecordMap.set(relative, val);
310
- }
311
- }
312
386
  if (!oneLevelRecordChildren.length && deepRecordMap.size === 0) continue;
313
387
  flowCtx.defineProperty(varName, {
314
388
  get: () => {
315
389
  const root = new import_contexts.ServerBaseContext();
316
390
  const definedFirstLevel = /* @__PURE__ */ new Set();
317
391
  const defineRecordGetter = (container, key, recordParams, subPaths = [], preferFull) => {
318
- const { generatedAppends, generatedFields } = inferSelectsFromUsage(subPaths, recordParams);
392
+ const strictSelects = Array.isArray(recordParams == null ? void 0 : recordParams.fields) || Array.isArray(recordParams == null ? void 0 : recordParams.appends);
393
+ let { generatedAppends, generatedFields } = inferSelectsFromUsage(subPaths, recordParams);
394
+ if (Array.isArray(recordParams == null ? void 0 : recordParams.fields)) generatedFields = recordParams.fields;
395
+ if (Array.isArray(recordParams == null ? void 0 : recordParams.appends)) generatedAppends = recordParams.appends;
319
396
  container.defineProperty(key, {
320
397
  get: async () => {
321
398
  const dataSourceKey = (recordParams == null ? void 0 : recordParams.dataSourceKey) || "main";
@@ -333,6 +410,7 @@ function attachGenericRecordVariables(flowCtx, koaCtx, usage, contextParams) {
333
410
  recordParams.filterByTk,
334
411
  fixed.fields,
335
412
  fixed.appends,
413
+ strictSelects,
336
414
  preferFull || ((subPaths == null ? void 0 : subPaths.length) ?? 0) === 0,
337
415
  recordParams.associationName,
338
416
  recordParams.sourceId
@@ -416,6 +494,7 @@ function registerBuiltInVariables(reg) {
416
494
  uid,
417
495
  generatedFields,
418
496
  generatedAppends,
497
+ false,
419
498
  void 0,
420
499
  void 0,
421
500
  void 0
@@ -31,16 +31,30 @@ __export(utils_exports, {
31
31
  module.exports = __toCommonJS(utils_exports);
32
32
  var import_registry = require("./registry");
33
33
  var import_selects = require("./selects");
34
+ var import_records = require("./records");
34
35
  async function prefetchRecordsForResolve(koaCtx, items) {
35
- var _a, _b, _c, _d, _e, _f, _g;
36
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
36
37
  try {
37
38
  const log = (_b = (_a = koaCtx.app) == null ? void 0 : _a.logger) == null ? void 0 : _b.child({ module: "plugin-flow-engine", submodule: "variables.prefetch" });
38
39
  const groupMap = /* @__PURE__ */ new Map();
39
- const ensureGroup = (dataSourceKey, collection, filterByTk) => {
40
- const groupKey = JSON.stringify({ ds: dataSourceKey, collection, tk: filterByTk });
40
+ const ensureGroup = (dataSourceKey, collection, filterByTk, strictSelects, opts) => {
41
+ const groupKey = JSON.stringify({
42
+ ds: dataSourceKey,
43
+ collection,
44
+ tk: filterByTk,
45
+ f: Array.isArray(opts == null ? void 0 : opts.fields) ? [...opts.fields].sort() : void 0,
46
+ a: Array.isArray(opts == null ? void 0 : opts.appends) ? [...opts.appends].sort() : void 0
47
+ });
41
48
  let group = groupMap.get(groupKey);
42
49
  if (!group) {
43
- group = { dataSourceKey, collection, filterByTk, fields: /* @__PURE__ */ new Set(), appends: /* @__PURE__ */ new Set() };
50
+ group = {
51
+ dataSourceKey,
52
+ collection,
53
+ filterByTk,
54
+ strictSelects,
55
+ fields: /* @__PURE__ */ new Set(),
56
+ appends: /* @__PURE__ */ new Set()
57
+ };
44
58
  groupMap.set(groupKey, group);
45
59
  }
46
60
  return group;
@@ -69,7 +83,19 @@ async function prefetchRecordsForResolve(koaCtx, items) {
69
83
  const collection = recordParams == null ? void 0 : recordParams.collection;
70
84
  const filterByTk = recordParams == null ? void 0 : recordParams.filterByTk;
71
85
  if (!collection || typeof filterByTk === "undefined") continue;
72
- const group = ensureGroup(dataSourceKey, collection, filterByTk);
86
+ const explicitFields = recordParams == null ? void 0 : recordParams.fields;
87
+ const explicitAppends = recordParams == null ? void 0 : recordParams.appends;
88
+ const hasExplicit = Array.isArray(explicitFields) || Array.isArray(explicitAppends);
89
+ const group = ensureGroup(dataSourceKey, collection, filterByTk, hasExplicit, {
90
+ fields: hasExplicit ? explicitFields : void 0,
91
+ appends: hasExplicit ? explicitAppends : void 0
92
+ });
93
+ if (hasExplicit) {
94
+ const fixed2 = (0, import_selects.adjustSelectsForCollection)(koaCtx, dataSourceKey, collection, explicitFields, explicitAppends);
95
+ (_c = fixed2.fields) == null ? void 0 : _c.forEach((f) => group.fields.add(f));
96
+ (_d = fixed2.appends) == null ? void 0 : _d.forEach((a) => group.appends.add(a));
97
+ continue;
98
+ }
73
99
  let { generatedAppends, generatedFields } = (0, import_registry.inferSelectsFromUsage)(remainders);
74
100
  const fixed = (0, import_selects.adjustSelectsForCollection)(koaCtx, dataSourceKey, collection, generatedFields, generatedAppends);
75
101
  generatedFields = fixed.fields;
@@ -83,23 +109,37 @@ async function prefetchRecordsForResolve(koaCtx, items) {
83
109
  if (stateObj && !stateObj["__varResolveBatchCache"]) {
84
110
  stateObj["__varResolveBatchCache"] = /* @__PURE__ */ new Map();
85
111
  }
86
- const cache = (_c = koaCtx.state) == null ? void 0 : _c["__varResolveBatchCache"];
87
- for (const { dataSourceKey, collection, filterByTk, fields, appends } of groupMap.values()) {
112
+ const cache = (_e = koaCtx.state) == null ? void 0 : _e["__varResolveBatchCache"];
113
+ for (const { dataSourceKey, collection, filterByTk, strictSelects, fields, appends } of groupMap.values()) {
88
114
  try {
89
115
  const ds = koaCtx.app.dataSourceManager.get(dataSourceKey);
90
116
  const cm = ds.collectionManager;
91
117
  if (!(cm == null ? void 0 : cm.db)) continue;
92
118
  const repo = cm.db.getRepository(collection);
93
- const modelInfo = (_d = repo.collection) == null ? void 0 : _d.model;
119
+ const collectionInfo = repo == null ? void 0 : repo.collection;
120
+ const filterTargetKey = collectionInfo == null ? void 0 : collectionInfo.filterTargetKey;
121
+ const modelInfo = (_f = repo.collection) == null ? void 0 : _f.model;
94
122
  const pkAttr = modelInfo == null ? void 0 : modelInfo.primaryKeyAttribute;
95
- const pkIsValid = pkAttr && (modelInfo == null ? void 0 : modelInfo.rawAttributes) && Object.prototype.hasOwnProperty.call(modelInfo.rawAttributes, pkAttr);
96
- if (fields.size && pkIsValid) {
97
- fields.add(pkAttr);
98
- }
99
- const fld = fields.size ? Array.from(fields).sort() : void 0;
123
+ const rawAttributes = (modelInfo == null ? void 0 : modelInfo.rawAttributes) || void 0;
124
+ const pkIsValid = !!(pkAttr && rawAttributes && Object.prototype.hasOwnProperty.call(rawAttributes, pkAttr));
125
+ const fldBase = fields.size ? Array.from(fields).sort() : void 0;
126
+ const extraKeys = (0, import_records.getExtraKeyFieldsForSelect)(filterByTk, {
127
+ filterTargetKey,
128
+ pkAttr,
129
+ pkIsValid,
130
+ rawAttributes
131
+ });
132
+ const effectiveExtras = strictSelects && Array.isArray(extraKeys) && extraKeys.length ? extraKeys.filter((k) => k === pkAttr) : extraKeys;
133
+ const fld = (0, import_records.mergeFieldsWithExtras)(fldBase, effectiveExtras);
100
134
  const app = appends.size ? Array.from(appends).sort() : void 0;
101
- const rec = await repo.findOne({ filterByTk, fields: fld, appends: app });
102
- const json = rec ? rec.toJSON() : void 0;
135
+ const json = await (0, import_records.fetchRecordOrRecordsJson)(repo, {
136
+ filterByTk,
137
+ fields: fld,
138
+ appends: app,
139
+ filterTargetKey,
140
+ pkAttr,
141
+ pkIsValid
142
+ });
103
143
  if (cache) {
104
144
  const key = JSON.stringify({ ds: dataSourceKey, c: collection, tk: filterByTk, f: fld, a: app });
105
145
  cache.set(key, json);
@@ -114,7 +154,7 @@ async function prefetchRecordsForResolve(koaCtx, items) {
114
154
  }
115
155
  }
116
156
  } catch (e) {
117
- (_g = (_f = (_e = koaCtx.app) == null ? void 0 : _e.logger) == null ? void 0 : _f.child({ module: "plugin-flow-engine", submodule: "variables.prefetch" })) == null ? void 0 : _g.debug("[variables.resolve] prefetch fatal error", { error: (e == null ? void 0 : e.message) || String(e) });
157
+ (_i = (_h = (_g = koaCtx.app) == null ? void 0 : _g.logger) == null ? void 0 : _h.child({ module: "plugin-flow-engine", submodule: "variables.prefetch" })) == null ? void 0 : _i.debug("[variables.resolve] prefetch fatal error", { error: (e == null ? void 0 : e.message) || String(e) });
118
158
  }
119
159
  }
120
160
  // Annotate the CommonJS export names for ESM import in node:
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "displayName.zh-CN": "前端流引擎",
5
5
  "description": "",
6
6
  "description.zh-CN": "",
7
- "version": "2.0.0-beta.2",
7
+ "version": "2.0.0-beta.20",
8
8
  "main": "./dist/server/index.js",
9
9
  "license": "AGPL-3.0",
10
10
  "devDependencies": {
@@ -24,5 +24,5 @@
24
24
  "@nocobase/test": "2.x",
25
25
  "@nocobase/utils": "2.x"
26
26
  },
27
- "gitHead": "b77a33ee933ae6e09d2d5dce017ca15d8552d57b"
27
+ "gitHead": "f4ab788fc6c17915157617026dfbba6f0d78eaac"
28
28
  }