@nocobase/plugin-flow-engine 2.3.0-alpha.1 → 2.3.0-beta.11

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.
Files changed (67) hide show
  1. package/dist/ai/ai-employees/nathan/prompt.md +2 -0
  2. package/dist/ai/ai-employees/nathan/skills/frontend-developer/SKILLS.md +1 -0
  3. package/dist/ai/ai-employees/nathan/skills/frontend-developer/tools/patchJSCode.js +2 -2
  4. package/dist/ai/docs/runjs/context/ai.md +194 -4
  5. package/dist/externalVersion.js +9 -9
  6. package/dist/locale/en-US.json +2 -0
  7. package/dist/locale/index.d.ts +4 -0
  8. package/dist/locale/zh-CN.json +2 -0
  9. package/dist/node_modules/@ant-design/icons-svg/package.json +1 -1
  10. package/dist/node_modules/acorn/package.json +1 -1
  11. package/dist/node_modules/acorn-jsx/package.json +1 -1
  12. package/dist/node_modules/acorn-walk/package.json +1 -1
  13. package/dist/node_modules/ses/package.json +1 -1
  14. package/dist/node_modules/zod/package.json +1 -1
  15. package/dist/server/flow-surfaces/builder.js +5 -0
  16. package/dist/server/flow-surfaces/catalog.js +27 -8
  17. package/dist/server/flow-surfaces/configure-options.js +17 -1
  18. package/dist/server/flow-surfaces/field-binding-registry.js +9 -8
  19. package/dist/server/flow-surfaces/runjs-authoring/ast/parser.d.ts +10 -3
  20. package/dist/server/flow-surfaces/runjs-authoring/ast/parser.js +90 -8
  21. package/dist/server/flow-surfaces/runjs-authoring/ast/source.d.ts +2 -2
  22. package/dist/server/flow-surfaces/runjs-authoring/ast/source.js +7 -69
  23. package/dist/server/flow-surfaces/runjs-authoring/ast/static-bindings.d.ts +5 -5
  24. package/dist/server/flow-surfaces/runjs-authoring/ast/static-bindings.js +56 -23
  25. package/dist/server/flow-surfaces/runjs-authoring/ast/static-values.d.ts +1 -1
  26. package/dist/server/flow-surfaces/runjs-authoring/ast/static-values.js +4 -2
  27. package/dist/server/flow-surfaces/service-utils.d.ts +1 -0
  28. package/dist/server/flow-surfaces/service-utils.js +17 -0
  29. package/dist/server/flow-surfaces/service.js +9 -0
  30. package/dist/server/index.d.ts +2 -0
  31. package/dist/server/index.js +7 -0
  32. package/dist/server/plugin.d.ts +13 -0
  33. package/dist/server/plugin.js +90 -3
  34. package/dist/server/repository.d.ts +12 -0
  35. package/dist/server/repository.js +39 -2
  36. package/dist/server/template/context-keys.d.ts +14 -0
  37. package/dist/server/template/context-keys.js +86 -0
  38. package/dist/server/template/contexts.d.ts +5 -8
  39. package/dist/server/template/contexts.js +43 -51
  40. package/dist/server/template/resolver.d.ts +5 -13
  41. package/dist/server/template/resolver.js +188 -257
  42. package/dist/server/template/variable-expression.d.ts +72 -0
  43. package/dist/server/template/variable-expression.js +597 -0
  44. package/dist/server/variables/allow-list.d.ts +49 -0
  45. package/dist/server/variables/allow-list.js +546 -0
  46. package/dist/server/variables/form-item-record-slot-resolvers.d.ts +10 -0
  47. package/dist/server/variables/form-item-record-slot-resolvers.js +297 -0
  48. package/dist/server/variables/record-bindings.d.ts +42 -0
  49. package/dist/server/variables/record-bindings.js +196 -0
  50. package/dist/server/variables/record-projection.d.ts +10 -0
  51. package/dist/server/variables/record-projection.js +140 -0
  52. package/dist/server/variables/record-slot-policy.d.ts +23 -0
  53. package/dist/server/variables/record-slot-policy.js +100 -0
  54. package/dist/server/variables/record-slot-resolvers.d.ts +46 -0
  55. package/dist/server/variables/record-slot-resolvers.js +115 -0
  56. package/dist/server/variables/records.d.ts +49 -2
  57. package/dist/server/variables/records.js +309 -18
  58. package/dist/server/variables/registry.d.ts +33 -10
  59. package/dist/server/variables/registry.js +197 -362
  60. package/dist/server/variables/resolve.d.ts +20 -2
  61. package/dist/server/variables/resolve.js +85 -13
  62. package/dist/server/variables/runjs-variable-dependencies.d.ts +23 -0
  63. package/dist/server/variables/runjs-variable-dependencies.js +542 -0
  64. package/dist/server/variables/selects.js +6 -3
  65. package/dist/server/variables/utils.d.ts +3 -6
  66. package/dist/server/variables/utils.js +50 -111
  67. package/package.json +2 -2
@@ -0,0 +1,49 @@
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
+ import type { ResourcerContext } from '@nocobase/resourcer';
10
+ import { type FlowModelNodeSnapshot } from '../repository';
11
+ import { type AnalyzeTemplateMode, type AnalyzedTemplate, type ResolvePathPolicy } from '../template/variable-expression';
12
+ import type { JSONValue } from '../template/resolver';
13
+ import { type RecordBindingPlan } from './record-bindings';
14
+ import { type RecordSlotPolicies } from './record-slot-policy';
15
+ type AuthorizationResultBase = {
16
+ contextParams: Readonly<Record<string, unknown>>;
17
+ flowModelUid?: string;
18
+ policy: ResolvePathPolicy;
19
+ recordSlotPolicies: RecordSlotPolicies;
20
+ };
21
+ export type AuthorizationResult = AuthorizationResultBase & ({
22
+ allowed: true;
23
+ analysis: AnalyzedTemplate;
24
+ bindingPlan: RecordBindingPlan;
25
+ } | {
26
+ allowed: false;
27
+ analysis?: AnalyzedTemplate;
28
+ });
29
+ export type TemplateAnalysisResult = {
30
+ ok: true;
31
+ analysis: AnalyzedTemplate;
32
+ } | {
33
+ ok: false;
34
+ errorType: string;
35
+ };
36
+ export declare function analyzeVariableTemplateSafely(template: unknown, options?: Readonly<{
37
+ mode?: AnalyzeTemplateMode;
38
+ }>): TemplateAnalysisResult;
39
+ export declare function clearVariableAllowListCache(app?: object): object;
40
+ export declare function hasRecordContextParams(value: unknown): boolean;
41
+ export declare function sanitizeContextParams(value?: Record<string, unknown>): Record<string, unknown>;
42
+ export declare function resolveFlowModelNodeFromRequestRd(ctx: ResourcerContext, rd?: string | number): Promise<FlowModelNodeSnapshot>;
43
+ export declare function authorizeVariablesResolve(ctx: ResourcerContext, options: {
44
+ contractRd?: string | number;
45
+ contextParams?: Record<string, unknown>;
46
+ rd?: string | number;
47
+ template: JSONValue;
48
+ }): Promise<AuthorizationResult>;
49
+ export {};
@@ -0,0 +1,546 @@
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 allow_list_exports = {};
28
+ __export(allow_list_exports, {
29
+ analyzeVariableTemplateSafely: () => analyzeVariableTemplateSafely,
30
+ authorizeVariablesResolve: () => authorizeVariablesResolve,
31
+ clearVariableAllowListCache: () => clearVariableAllowListCache,
32
+ hasRecordContextParams: () => hasRecordContextParams,
33
+ resolveFlowModelNodeFromRequestRd: () => resolveFlowModelNodeFromRequestRd,
34
+ sanitizeContextParams: () => sanitizeContextParams
35
+ });
36
+ module.exports = __toCommonJS(allow_list_exports);
37
+ var import_utils = require("@nocobase/utils");
38
+ var import_variable_expression = require("../template/variable-expression");
39
+ var import_record_bindings = require("./record-bindings");
40
+ var import_record_slot_policy = require("./record-slot-policy");
41
+ var import_registry = require("./registry");
42
+ var import_runjs_variable_dependencies = require("./runjs-variable-dependencies");
43
+ function analyzeVariableTemplateSafely(template, options = {}) {
44
+ let analysis;
45
+ try {
46
+ analysis = (0, import_variable_expression.analyzeVariableTemplate)(template, options);
47
+ } catch (error) {
48
+ return { ok: false, errorType: error instanceof Error ? error.name : typeof error };
49
+ }
50
+ return { ok: true, analysis };
51
+ }
52
+ const MAX_FLOW_MODEL_ANCESTORS = 64;
53
+ function clearVariableAllowListCache(app) {
54
+ return app;
55
+ }
56
+ function isObject(value) {
57
+ return !!value && typeof value === "object" && !Array.isArray(value);
58
+ }
59
+ function readFormAssignRulesVariableSource(node) {
60
+ const stepParams = isObject(node.options.stepParams) ? node.options.stepParams : null;
61
+ const formModelSettings = stepParams && isObject(stepParams.formModelSettings) ? stepParams.formModelSettings : null;
62
+ return formModelSettings && Object.prototype.hasOwnProperty.call(formModelSettings, "assignRules") ? formModelSettings.assignRules : void 0;
63
+ }
64
+ function hasFlowModelUse(node) {
65
+ const use = node.options.use;
66
+ return typeof use === "string" && !!use.trim();
67
+ }
68
+ function matchesVariableContractType(node, type) {
69
+ const marker = node.options.variableContractType;
70
+ if (typeof marker === "undefined") return void 0;
71
+ return isObject(marker) && marker.type === type && marker.use === node.options.use;
72
+ }
73
+ function isFormGridNode(node) {
74
+ const use = node.options.use;
75
+ const markerMatches = matchesVariableContractType(node, "formGrid");
76
+ return node.subKey === "grid" && hasFlowModelUse(node) && (markerMatches === true || typeof markerMatches === "undefined" && typeof use === "string" && use.endsWith("GridModel"));
77
+ }
78
+ function getReferenceFormUseTemplate(node) {
79
+ const stepParams = isObject(node.options.stepParams) ? node.options.stepParams : null;
80
+ const referenceSettings = stepParams && isObject(stepParams.referenceSettings) ? stepParams.referenceSettings : null;
81
+ return referenceSettings && isObject(referenceSettings.useTemplate) ? referenceSettings.useTemplate : null;
82
+ }
83
+ function isReferenceFormGridNode(node) {
84
+ const use = node.options.use;
85
+ return isFormGridNode(node) && typeof use === "string" && use.endsWith("ReferenceFormGridModel");
86
+ }
87
+ function getReferenceFormGridTargetUid(node) {
88
+ const useTemplate = getReferenceFormUseTemplate(node);
89
+ const templateUid = useTemplate && typeof useTemplate.templateUid === "string" ? useTemplate.templateUid.trim() : "";
90
+ if (!useTemplate || !templateUid) return "";
91
+ const targetPath = typeof useTemplate.targetPath === "string" ? useTemplate.targetPath.trim() : "";
92
+ if (targetPath && targetPath !== "subModels.grid") return "";
93
+ return typeof useTemplate.targetUid === "string" ? useTemplate.targetUid.trim() : "";
94
+ }
95
+ function isFormAssignRulesOwnerNode(node) {
96
+ const use = node.options.use;
97
+ const markerMatches = matchesVariableContractType(node, "form");
98
+ return hasFlowModelUse(node) && (markerMatches === true || typeof markerMatches === "undefined" && typeof use === "string" && (use.endsWith("FormModel") || use.endsWith("FormBlockModel")));
99
+ }
100
+ function isFormAssignRulesContractPair(formNode, gridNode) {
101
+ return isFormAssignRulesOwnerNode(formNode) && isFormGridNode(gridNode) && gridNode.parentId === formNode.uid;
102
+ }
103
+ function isFormAssignRulesRunJsValuePath(pathTail) {
104
+ return pathTail.length === 3 && pathTail[0] === "value" && /^\d+$/.test(pathTail[1]) && pathTail[2] === "value";
105
+ }
106
+ function isRecordParams(value) {
107
+ return isObject(value) && typeof value.collection === "string" && Object.prototype.hasOwnProperty.call(value, "filterByTk") && (typeof value.dataSourceKey === "undefined" || typeof value.dataSourceKey === "string") && (typeof value.associationName === "undefined" || typeof value.associationName === "string") && (typeof value.fields === "undefined" || Array.isArray(value.fields) && value.fields.every((field) => typeof field === "string")) && (typeof value.appends === "undefined" || Array.isArray(value.appends) && value.appends.every((append) => typeof append === "string"));
108
+ }
109
+ function hasRecordContextParams(value) {
110
+ if (isRecordParams(value)) return true;
111
+ if (Array.isArray(value)) return value.some((item) => hasRecordContextParams(item));
112
+ if (!isObject(value)) return false;
113
+ return Object.values(value).some((item) => hasRecordContextParams(item));
114
+ }
115
+ function sanitizeContextParams(value = {}) {
116
+ const sanitizeStringArray = (input) => Array.isArray(input) && input.every((item) => typeof item === "string") ? input : void 0;
117
+ const sanitize = (input) => {
118
+ if (isRecordParams(input)) {
119
+ const { associationName, collection, filterByTk, dataSourceKey, sourceId } = input;
120
+ const fields = sanitizeStringArray(input.fields);
121
+ const appends = sanitizeStringArray(input.appends);
122
+ return {
123
+ associationName,
124
+ collection,
125
+ filterByTk,
126
+ dataSourceKey,
127
+ sourceId,
128
+ ...fields ? { fields } : {},
129
+ ...appends ? { appends } : {}
130
+ };
131
+ }
132
+ if (Array.isArray(input)) return input.map((item) => sanitize(item));
133
+ if (!isObject(input)) return input;
134
+ const output = {};
135
+ for (const [key, child] of Object.entries(input)) output[key] = sanitize(child);
136
+ return output;
137
+ };
138
+ return sanitize(value);
139
+ }
140
+ function getRequestState(ctx) {
141
+ const request = ctx;
142
+ if (!request.state) request.state = {};
143
+ return request.state;
144
+ }
145
+ function getFlowModelRepository(ctx) {
146
+ return ctx.db.getCollection("flowModels").repository;
147
+ }
148
+ async function getFlowModelNode(ctx, flowModelUid) {
149
+ const state = getRequestState(ctx);
150
+ const cacheKey = "__variableResolveFlowModelCache";
151
+ const cache = state[cacheKey] || /* @__PURE__ */ new Map();
152
+ state[cacheKey] = cache;
153
+ if (cache.has(flowModelUid)) return await cache.get(flowModelUid) || null;
154
+ const load = getFlowModelRepository(ctx).findModelNodeSnapshotById(flowModelUid);
155
+ cache.set(flowModelUid, load);
156
+ const model = await load;
157
+ cache.set(flowModelUid, model);
158
+ return model;
159
+ }
160
+ async function getFlowModelChildNode(ctx, parentUid, subKey) {
161
+ const state = getRequestState(ctx);
162
+ const cacheKey = "__variableResolveFlowModelChildCache";
163
+ const cache = state[cacheKey] || /* @__PURE__ */ new Map();
164
+ state[cacheKey] = cache;
165
+ const childCacheKey = JSON.stringify([parentUid, subKey]);
166
+ if (cache.has(childCacheKey)) return await cache.get(childCacheKey) || null;
167
+ const load = getFlowModelRepository(ctx).findModelNodeSnapshotByParentId(parentUid, { subKey });
168
+ cache.set(childCacheKey, load);
169
+ const child = await load;
170
+ cache.set(childCacheKey, child);
171
+ return child;
172
+ }
173
+ async function loadFlowModelAncestors(ctx, currentNode) {
174
+ const ancestors = [];
175
+ const seen = /* @__PURE__ */ new Set([currentNode.uid]);
176
+ let parentId = currentNode.parentId;
177
+ while (parentId) {
178
+ if (seen.has(parentId) || ancestors.length >= MAX_FLOW_MODEL_ANCESTORS) {
179
+ throw new Error("Invalid FlowModel ancestor chain");
180
+ }
181
+ seen.add(parentId);
182
+ const parent = await getFlowModelNode(ctx, parentId);
183
+ if (!parent) throw new Error("Missing FlowModel ancestor");
184
+ ancestors.push(parent);
185
+ parentId = parent.parentId;
186
+ }
187
+ return Object.freeze(ancestors);
188
+ }
189
+ async function loadFlowModelAncestorUids(ctx, currentNode) {
190
+ try {
191
+ return new Set((await loadFlowModelAncestors(ctx, currentNode)).map((ancestor) => ancestor.uid));
192
+ } catch {
193
+ return null;
194
+ }
195
+ }
196
+ async function resolveFormAssignRulesVariableSource(ctx, contractNode) {
197
+ const fromGrid = readFormAssignRulesVariableSource(contractNode);
198
+ if (typeof fromGrid !== "undefined") return fromGrid;
199
+ if (!contractNode.parentId) return void 0;
200
+ const formNode = await getFlowModelNode(ctx, contractNode.parentId);
201
+ return formNode && isFormAssignRulesContractPair(formNode, contractNode) ? readFormAssignRulesVariableSource(formNode) : void 0;
202
+ }
203
+ function readFormLinkageRulesSource(node) {
204
+ const steps = isObject(node.options.stepParams) ? node.options.stepParams : null;
205
+ const events = steps && isObject(steps.eventSettings) ? steps.eventSettings : null;
206
+ return { stepParams: { eventSettings: { linkageRules: events == null ? void 0 : events.linkageRules } } };
207
+ }
208
+ async function collectFormLinkageRuleSources(ctx, form) {
209
+ const grid = await getFlowModelChildNode(ctx, form.uid, "grid");
210
+ if (!grid || !isFormAssignRulesContractPair(form, grid)) return [];
211
+ if (!isReferenceFormGridNode(grid)) return [readFormLinkageRulesSource(grid)];
212
+ const targetUid = getReferenceFormGridTargetUid(grid);
213
+ const target = targetUid ? await getFlowModelNode(ctx, targetUid) : null;
214
+ if (!target || !isFormAssignRulesOwnerNode(target)) return [];
215
+ const targetGrid = await getFlowModelChildNode(ctx, target.uid, "grid");
216
+ if (!targetGrid || !isFormAssignRulesContractPair(target, targetGrid) || isReferenceFormGridNode(targetGrid)) {
217
+ return [];
218
+ }
219
+ return [readFormLinkageRulesSource(target), readFormLinkageRulesSource(targetGrid)];
220
+ }
221
+ function createRecordSlotCompilerOptions(ctx, currentNode) {
222
+ let ancestors;
223
+ return {
224
+ app: ctx.app,
225
+ ctx,
226
+ currentNode,
227
+ getCollection: (dataSourceKey, collection) => {
228
+ var _a, _b, _c;
229
+ return dataSourceKey === "main" ? ctx.db.getCollection(collection) : (_c = (_b = (_a = ctx.app.dataSourceManager.get(dataSourceKey)) == null ? void 0 : _a.collectionManager) == null ? void 0 : _b.getCollection) == null ? void 0 : _c.call(_b, collection);
230
+ },
231
+ loadAncestors: currentNode ? () => {
232
+ ancestors ||= loadFlowModelAncestors(ctx, currentNode);
233
+ return ancestors;
234
+ } : void 0
235
+ };
236
+ }
237
+ async function getFlowModelVariableContract(ctx, contractNode, runtimeNode, source) {
238
+ const state = getRequestState(ctx);
239
+ const cacheKey = "__variableResolveContractCache";
240
+ const cache = state[cacheKey] || /* @__PURE__ */ new Map();
241
+ state[cacheKey] = cache;
242
+ const contractCacheKey = JSON.stringify([source, contractNode.uid, runtimeNode.uid]);
243
+ if (cache.has(contractCacheKey)) return await cache.get(contractCacheKey) || null;
244
+ const load = createFlowModelVariableContractFromNode(ctx, contractNode, runtimeNode, source);
245
+ cache.set(contractCacheKey, load);
246
+ const contract = await load;
247
+ cache.set(contractCacheKey, contract);
248
+ return contract;
249
+ }
250
+ async function createFlowModelVariableContractFromNode(ctx, contractNode, runtimeNode, source) {
251
+ const sources = [];
252
+ if (source === "formAssignRules") {
253
+ sources.push(await resolveFormAssignRulesVariableSource(ctx, contractNode) ?? {});
254
+ } else {
255
+ const nodes = contractNode.uid === runtimeNode.uid ? [contractNode] : [contractNode, runtimeNode];
256
+ for (const node of nodes) {
257
+ sources.push(node.options);
258
+ if (isFormAssignRulesOwnerNode(node)) {
259
+ sources.push(...await collectFormLinkageRuleSources(ctx, node));
260
+ }
261
+ }
262
+ }
263
+ const paths = [];
264
+ for (const variableSource of sources) {
265
+ const item = (0, import_runjs_variable_dependencies.prepareFlowModelVariableSource)(
266
+ variableSource,
267
+ source === "formAssignRules" ? { isRunJsValuePath: isFormAssignRulesRunJsValuePath } : void 0
268
+ );
269
+ if (!item.ok) continue;
270
+ const contractSource = item.runJsTemplates.length ? [item.templateSource, ...item.runJsTemplates] : item.templateSource;
271
+ const result = analyzeVariableTemplateSafely(contractSource, { mode: "flow-model" });
272
+ if (result.ok) paths.push(...result.analysis.paths);
273
+ }
274
+ const analysis = { ...(0, import_variable_expression.analyzeVariableTemplate)({}, { mode: "flow-model" }), paths };
275
+ return await (0, import_record_slot_policy.createFlowModelVariableContract)(analysis, createRecordSlotCompilerOptions(ctx, runtimeNode));
276
+ }
277
+ function getCurrentRoleNames(ctx) {
278
+ const state = ctx.state;
279
+ const roleNames = /* @__PURE__ */ new Set();
280
+ const currentRoles = state == null ? void 0 : state.currentRoles;
281
+ if (Array.isArray(currentRoles)) {
282
+ currentRoles.forEach((roleName) => {
283
+ if (typeof roleName === "string" && roleName) roleNames.add(roleName);
284
+ });
285
+ }
286
+ if (typeof (state == null ? void 0 : state.currentRole) === "string" && state.currentRole) roleNames.add(state.currentRole);
287
+ return Array.from(roleNames);
288
+ }
289
+ async function readCurrentRoleAllowsConfigure(ctx) {
290
+ const roleNames = getCurrentRoleNames(ctx);
291
+ if (!roleNames.length) return false;
292
+ if (roleNames.includes("root")) return true;
293
+ const acl = ctx.app.acl;
294
+ if (roleNames.some((roleName) => {
295
+ var _a, _b, _c, _d;
296
+ return ((_d = (_c = (_b = (_a = acl == null ? void 0 : acl.getRole) == null ? void 0 : _a.call(acl, roleName)) == null ? void 0 : _b.getStrategy) == null ? void 0 : _c.call(_b)) == null ? void 0 : _d.allowConfigure) === true;
297
+ })) return true;
298
+ const roles = await ctx.db.getRepository("roles").find({
299
+ filter: { name: roleNames },
300
+ fields: ["name", "allowConfigure"]
301
+ });
302
+ return roles.some(
303
+ (role) => typeof (role == null ? void 0 : role.get) === "function" ? role.get("allowConfigure") === true : (role == null ? void 0 : role.allowConfigure) === true
304
+ );
305
+ }
306
+ async function currentRoleAllowsConfigure(ctx) {
307
+ const state = getRequestState(ctx);
308
+ const cacheKey = "__variableResolveRoleAllowsConfigure";
309
+ const cached = state[cacheKey];
310
+ if (typeof cached === "boolean") return cached;
311
+ if (cached instanceof Promise) return await cached;
312
+ const pending = readCurrentRoleAllowsConfigure(ctx);
313
+ state[cacheKey] = pending;
314
+ const allowed = await pending;
315
+ state[cacheKey] = allowed;
316
+ return allowed;
317
+ }
318
+ function getRequestBearerToken(ctx) {
319
+ var _a, _b;
320
+ const contextWithBearerToken = ctx;
321
+ const token = (_a = contextWithBearerToken.getBearerToken) == null ? void 0 : _a.call(contextWithBearerToken);
322
+ if (token) return token;
323
+ const authorization = typeof ctx.get === "function" ? ctx.get("authorization") || ctx.get("Authorization") : void 0;
324
+ if (typeof authorization !== "string") return "";
325
+ return ((_b = authorization.match(/^Bearer\s+(.+)$/i)) == null ? void 0 : _b[1]) || "";
326
+ }
327
+ function getCurrentRequestRdSessionId(ctx) {
328
+ const state = getRequestState(ctx);
329
+ const cacheKey = "__variableResolveRdSessionId";
330
+ const cached = state[cacheKey];
331
+ if (typeof cached === "string") return cached;
332
+ const sessionId = (0, import_utils.getFlowModelRdSessionId)((0, import_utils.decodeJwtSessionPayload)(getRequestBearerToken(ctx)));
333
+ state[cacheKey] = sessionId;
334
+ return sessionId;
335
+ }
336
+ function resolveFlowModelUidFromRequestRd(ctx, rd) {
337
+ if (typeof rd !== "string" || !rd) return "";
338
+ const state = getRequestState(ctx);
339
+ const cacheKey = "__variableResolveRdUidCache";
340
+ const cache = state[cacheKey] || /* @__PURE__ */ new Map();
341
+ state[cacheKey] = cache;
342
+ if (cache.has(rd)) return cache.get(rd) || "";
343
+ const flowModelUid = (0, import_utils.resolveFlowModelUidFromRd)(rd, getCurrentRequestRdSessionId(ctx)) || "";
344
+ cache.set(rd, flowModelUid);
345
+ return flowModelUid;
346
+ }
347
+ async function resolveFlowModelNodeFromRequestRd(ctx, rd) {
348
+ const flowModelUid = resolveFlowModelUidFromRequestRd(ctx, rd);
349
+ return flowModelUid ? getFlowModelNode(ctx, flowModelUid) : null;
350
+ }
351
+ async function resolveFormAssignRulesContractNode(ctx, runtimeNode, contractModelUid) {
352
+ const contractNode = await getFlowModelNode(ctx, contractModelUid);
353
+ if (!contractNode || !contractNode.parentId || !isFormGridNode(contractNode)) return null;
354
+ const formNode = await getFlowModelNode(ctx, contractNode.parentId);
355
+ if (!formNode || !isFormAssignRulesContractPair(formNode, contractNode)) return null;
356
+ if (isReferenceFormGridNode(contractNode)) {
357
+ const targetUid = getReferenceFormGridTargetUid(contractNode);
358
+ if (!targetUid) return null;
359
+ const targetFormNode = await getFlowModelNode(ctx, targetUid);
360
+ if (!targetFormNode) return null;
361
+ const targetGridNode = await getFlowModelChildNode(ctx, targetFormNode.uid, "grid");
362
+ if (!targetGridNode || !isFormAssignRulesContractPair(targetFormNode, targetGridNode) || isReferenceFormGridNode(targetGridNode)) {
363
+ return null;
364
+ }
365
+ const targetVariableSource = await resolveFormAssignRulesVariableSource(ctx, targetGridNode);
366
+ let contractSourceNode = targetGridNode;
367
+ if (typeof targetVariableSource === "undefined") {
368
+ if (typeof readFormAssignRulesVariableSource(formNode) === "undefined") return null;
369
+ contractSourceNode = formNode;
370
+ }
371
+ const directlyRelated = runtimeNode.uid === contractNode.uid || runtimeNode.uid === formNode.uid || runtimeNode.uid === targetGridNode.uid || runtimeNode.uid === targetFormNode.uid;
372
+ if (directlyRelated) return contractSourceNode;
373
+ const ancestorUids2 = await loadFlowModelAncestorUids(ctx, runtimeNode);
374
+ return (ancestorUids2 == null ? void 0 : ancestorUids2.has(contractNode.uid)) === true || (ancestorUids2 == null ? void 0 : ancestorUids2.has(targetGridNode.uid)) === true ? contractSourceNode : null;
375
+ }
376
+ if (typeof await resolveFormAssignRulesVariableSource(ctx, contractNode) === "undefined") return null;
377
+ if (runtimeNode.uid === contractNode.uid || runtimeNode.uid === formNode.uid) return contractNode;
378
+ const ancestorUids = await loadFlowModelAncestorUids(ctx, runtimeNode);
379
+ return (ancestorUids == null ? void 0 : ancestorUids.has(contractNode.uid)) === true ? contractNode : null;
380
+ }
381
+ async function resolveReferenceBlockContractNode(ctx, runtimeNode, contractModelUid) {
382
+ const reference = await getFlowModelNode(ctx, contractModelUid);
383
+ if ((reference == null ? void 0 : reference.options.use) !== "ReferenceBlockModel") return null;
384
+ let current = reference;
385
+ const seen = /* @__PURE__ */ new Set([reference.uid]);
386
+ for (let depth = 0; depth < 20; depth++) {
387
+ const steps = isObject(current.options.stepParams) ? current.options.stepParams : null;
388
+ const settings = steps && isObject(steps.referenceSettings) ? steps.referenceSettings : null;
389
+ const target = settings && isObject(settings.target) ? settings.target : null;
390
+ const targetUid = typeof (target == null ? void 0 : target.targetUid) === "string" ? target.targetUid.trim() : "";
391
+ if (!targetUid || seen.has(targetUid)) return null;
392
+ seen.add(targetUid);
393
+ const node = await getFlowModelNode(ctx, targetUid);
394
+ if (!node) return null;
395
+ if (node.options.use !== "ReferenceBlockModel") return node.uid === runtimeNode.uid ? reference : null;
396
+ current = node;
397
+ }
398
+ return null;
399
+ }
400
+ function createPolicy(allowAll = false, allowedPaths = /* @__PURE__ */ new Set(), unrestrictedVariables = /* @__PURE__ */ new Set()) {
401
+ return { allowAll, allowedPaths, unrestrictedVariables };
402
+ }
403
+ function denied(analysis, contextParams, policy, recordSlotPolicies, flowModelUid) {
404
+ return { allowed: false, analysis, contextParams, flowModelUid, policy, recordSlotPolicies };
405
+ }
406
+ async function createRecordBindingPlan(ctx, contextParams, usage, recordSlotPolicies) {
407
+ return await (0, import_record_bindings.planRecordBindings)({ contextParams, koaCtx: ctx, policies: recordSlotPolicies, usage });
408
+ }
409
+ function recordBindingPlanAllowed(plan) {
410
+ return plan.rejections.length === 0 && plan.bindings.every(import_registry.isSafeRecordBinding);
411
+ }
412
+ async function authorizeVariablesResolve(ctx, options) {
413
+ var _a;
414
+ let contextParams = sanitizeContextParams(options.contextParams || {});
415
+ const flowModelUid = resolveFlowModelUidFromRequestRd(ctx, options.rd);
416
+ const hasContractRd = typeof options.contractRd !== "undefined";
417
+ const contractModelUid = hasContractRd ? resolveFlowModelUidFromRequestRd(ctx, options.contractRd) : flowModelUid;
418
+ const unrestrictedVariables = /* @__PURE__ */ new Set();
419
+ let policy = createPolicy(false, /* @__PURE__ */ new Set(), unrestrictedVariables);
420
+ let recordSlotPolicies = /* @__PURE__ */ new Map();
421
+ const result = analyzeVariableTemplateSafely(options.template, { mode: "untrusted-request" });
422
+ if (!result.ok) {
423
+ contextParams = sanitizeContextParams((0, import_registry.sanitizeRegisteredVariableContextParams)(contextParams));
424
+ return {
425
+ allowed: false,
426
+ contextParams: (await createRecordBindingPlan(ctx, contextParams, {})).contextParams,
427
+ flowModelUid: flowModelUid || void 0,
428
+ policy,
429
+ recordSlotPolicies
430
+ };
431
+ }
432
+ const { analysis } = result;
433
+ if (!analysis.supported) {
434
+ contextParams = sanitizeContextParams((0, import_registry.sanitizeRegisteredVariableContextParams)(contextParams));
435
+ return denied(
436
+ analysis,
437
+ (await createRecordBindingPlan(ctx, contextParams, analysis.usage)).contextParams,
438
+ policy,
439
+ recordSlotPolicies,
440
+ flowModelUid || void 0
441
+ );
442
+ }
443
+ const flowModelRequiredVars = /* @__PURE__ */ new Set();
444
+ for (const [varName, usedPaths] of Object.entries(analysis.usage)) {
445
+ const def = import_registry.variables.get(varName);
446
+ const validation = await ((_a = def == null ? void 0 : def.validateContextParams) == null ? void 0 : _a.call(def, {
447
+ contextParams,
448
+ flowModelUid: flowModelUid || void 0,
449
+ koaCtx: ctx,
450
+ usage: usedPaths,
451
+ varName
452
+ })) || {};
453
+ contextParams = sanitizeContextParams((validation == null ? void 0 : validation.contextParams) || contextParams);
454
+ if ((validation == null ? void 0 : validation.allowed) === false) {
455
+ contextParams = sanitizeContextParams((0, import_registry.sanitizeRegisteredVariableContextParams)(contextParams));
456
+ return denied(
457
+ analysis,
458
+ (await createRecordBindingPlan(ctx, contextParams, analysis.usage)).contextParams,
459
+ policy,
460
+ recordSlotPolicies,
461
+ flowModelUid || void 0
462
+ );
463
+ }
464
+ if ((validation == null ? void 0 : validation.requireFlowModel) === false) unrestrictedVariables.add(varName);
465
+ else flowModelRequiredVars.add(varName);
466
+ }
467
+ contextParams = sanitizeContextParams((0, import_registry.sanitizeRegisteredVariableContextParams)(contextParams));
468
+ let bindingPlan = await createRecordBindingPlan(ctx, contextParams, analysis.usage);
469
+ const configureRole = await currentRoleAllowsConfigure(ctx);
470
+ const currentNode = flowModelUid ? await getFlowModelNode(ctx, flowModelUid) : null;
471
+ if (configureRole) {
472
+ policy = createPolicy(true, /* @__PURE__ */ new Set(), unrestrictedVariables);
473
+ recordSlotPolicies = await (0, import_record_slot_policy.compileRecordSlotPolicies)(
474
+ analysis,
475
+ createRecordSlotCompilerOptions(ctx, currentNode || void 0)
476
+ );
477
+ bindingPlan = await createRecordBindingPlan(ctx, contextParams, analysis.usage, recordSlotPolicies);
478
+ return recordBindingPlanAllowed(bindingPlan) ? {
479
+ allowed: true,
480
+ analysis,
481
+ bindingPlan,
482
+ contextParams: bindingPlan.contextParams,
483
+ ...currentNode ? { flowModelUid: currentNode.uid } : {},
484
+ policy,
485
+ recordSlotPolicies
486
+ } : denied(analysis, bindingPlan.contextParams, policy, recordSlotPolicies, flowModelUid || void 0);
487
+ }
488
+ if (flowModelRequiredVars.size > 0 && !flowModelUid) {
489
+ return denied(analysis, bindingPlan.contextParams, policy, recordSlotPolicies);
490
+ }
491
+ let contractNode = currentNode;
492
+ let contractSource = "node";
493
+ if (hasContractRd) {
494
+ const reference = currentNode && contractModelUid ? await resolveReferenceBlockContractNode(ctx, currentNode, contractModelUid) : null;
495
+ contractNode = reference || (currentNode && contractModelUid ? await resolveFormAssignRulesContractNode(ctx, currentNode, contractModelUid) : null);
496
+ contractSource = reference ? "node" : "formAssignRules";
497
+ if (!contractNode) {
498
+ return denied(analysis, bindingPlan.contextParams, policy, recordSlotPolicies, flowModelUid || void 0);
499
+ }
500
+ }
501
+ const contract = contractNode && currentNode ? await getFlowModelVariableContract(ctx, contractNode, currentNode, contractSource) : null;
502
+ const allowedPaths = (contract == null ? void 0 : contract.allowedPaths) || null;
503
+ recordSlotPolicies = (contract == null ? void 0 : contract.recordSlots) || /* @__PURE__ */ new Map();
504
+ policy = createPolicy(false, allowedPaths || /* @__PURE__ */ new Set(), unrestrictedVariables);
505
+ if (flowModelRequiredVars.size > 0 && !allowedPaths) {
506
+ return denied(analysis, bindingPlan.contextParams, policy, recordSlotPolicies, flowModelUid || void 0);
507
+ }
508
+ for (const path of analysis.paths) {
509
+ if (unrestrictedVariables.has(path.varName)) continue;
510
+ if (!(allowedPaths == null ? void 0 : allowedPaths.has(path.canonicalKey))) {
511
+ return denied(analysis, bindingPlan.contextParams, policy, recordSlotPolicies, flowModelUid || void 0);
512
+ }
513
+ }
514
+ if (unrestrictedVariables.size) {
515
+ const requestPolicies = await (0, import_record_slot_policy.compileRecordSlotPolicies)(
516
+ analysis,
517
+ createRecordSlotCompilerOptions(ctx, currentNode || void 0)
518
+ );
519
+ const mergedPolicies = new Map(recordSlotPolicies);
520
+ for (const path of analysis.paths) {
521
+ if (!unrestrictedVariables.has(path.varName)) continue;
522
+ const requestPolicy = requestPolicies.get(path.canonicalKey);
523
+ if (requestPolicy) mergedPolicies.set(path.canonicalKey, requestPolicy);
524
+ }
525
+ recordSlotPolicies = mergedPolicies;
526
+ }
527
+ bindingPlan = await createRecordBindingPlan(ctx, contextParams, analysis.usage, recordSlotPolicies);
528
+ return recordBindingPlanAllowed(bindingPlan) ? {
529
+ allowed: true,
530
+ analysis,
531
+ bindingPlan,
532
+ contextParams: bindingPlan.contextParams,
533
+ flowModelUid: flowModelUid || void 0,
534
+ policy,
535
+ recordSlotPolicies
536
+ } : denied(analysis, bindingPlan.contextParams, policy, recordSlotPolicies, flowModelUid || void 0);
537
+ }
538
+ // Annotate the CommonJS export names for ESM import in node:
539
+ 0 && (module.exports = {
540
+ analyzeVariableTemplateSafely,
541
+ authorizeVariablesResolve,
542
+ clearVariableAllowListCache,
543
+ hasRecordContextParams,
544
+ resolveFlowModelNodeFromRequestRd,
545
+ sanitizeContextParams
546
+ });
@@ -0,0 +1,10 @@
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
+ import type { RecordSlotResolverRegistration } from './record-slot-resolvers';
10
+ export declare function createFormItemRecordSlotResolvers(): readonly RecordSlotResolverRegistration[];