@nocobase/plugin-flow-engine 3.0.0-alpha.5 → 3.0.0-alpha.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/externalVersion.js +9 -9
- package/dist/node_modules/@ant-design/icons-svg/package.json +1 -1
- package/dist/node_modules/acorn/package.json +1 -1
- package/dist/node_modules/acorn-jsx/package.json +1 -1
- package/dist/node_modules/acorn-walk/package.json +1 -1
- package/dist/node_modules/ses/package.json +1 -1
- package/dist/node_modules/zod/package.json +1 -1
- package/dist/server/flow-surfaces/builder.js +5 -0
- package/dist/server/flow-surfaces/catalog.js +27 -8
- package/dist/server/flow-surfaces/configure-options.js +17 -1
- package/dist/server/flow-surfaces/service-utils.d.ts +1 -0
- package/dist/server/flow-surfaces/service-utils.js +17 -0
- package/dist/server/flow-surfaces/service.js +9 -0
- package/dist/server/index.d.ts +2 -0
- package/dist/server/index.js +7 -0
- package/dist/server/plugin.d.ts +11 -0
- package/dist/server/plugin.js +85 -3
- package/dist/server/repository.d.ts +8 -0
- package/dist/server/repository.js +29 -0
- package/dist/server/template/context-keys.d.ts +14 -0
- package/dist/server/template/context-keys.js +86 -0
- package/dist/server/template/contexts.d.ts +5 -8
- package/dist/server/template/contexts.js +43 -51
- package/dist/server/template/resolver.d.ts +5 -13
- package/dist/server/template/resolver.js +188 -257
- package/dist/server/template/variable-expression.d.ts +72 -0
- package/dist/server/template/variable-expression.js +597 -0
- package/dist/server/variables/allow-list.d.ts +48 -0
- package/dist/server/variables/allow-list.js +374 -0
- package/dist/server/variables/form-item-record-slot-resolvers.d.ts +10 -0
- package/dist/server/variables/form-item-record-slot-resolvers.js +280 -0
- package/dist/server/variables/record-bindings.d.ts +42 -0
- package/dist/server/variables/record-bindings.js +196 -0
- package/dist/server/variables/record-projection.d.ts +10 -0
- package/dist/server/variables/record-projection.js +140 -0
- package/dist/server/variables/record-slot-policy.d.ts +23 -0
- package/dist/server/variables/record-slot-policy.js +100 -0
- package/dist/server/variables/record-slot-resolvers.d.ts +46 -0
- package/dist/server/variables/record-slot-resolvers.js +115 -0
- package/dist/server/variables/records.d.ts +47 -1
- package/dist/server/variables/records.js +279 -5
- package/dist/server/variables/registry.d.ts +33 -10
- package/dist/server/variables/registry.js +197 -362
- package/dist/server/variables/resolve.d.ts +18 -2
- package/dist/server/variables/resolve.js +79 -13
- package/dist/server/variables/runjs-variable-dependencies.d.ts +21 -0
- package/dist/server/variables/runjs-variable-dependencies.js +313 -0
- package/dist/server/variables/utils.d.ts +3 -6
- package/dist/server/variables/utils.js +50 -111
- package/package.json +2 -2
|
@@ -7,15 +7,31 @@
|
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
9
|
import type { ResourcerContext } from '@nocobase/resourcer';
|
|
10
|
+
import { type AnalyzedTemplate, type ResolvePathPolicy } from '../template/variable-expression';
|
|
10
11
|
import { JSONValue } from '../template/resolver';
|
|
11
|
-
type
|
|
12
|
+
import { type RecordBindingPlan } from './record-bindings';
|
|
13
|
+
export type ResolveBatchItem = {
|
|
12
14
|
id?: string | number;
|
|
13
15
|
template: JSONValue;
|
|
14
16
|
contextParams?: Record<string, unknown>;
|
|
15
17
|
};
|
|
18
|
+
export type AnalyzedResolveBatchItem = ResolveBatchItem & {
|
|
19
|
+
analysis: AnalyzedTemplate;
|
|
20
|
+
bindingPlan: RecordBindingPlan;
|
|
21
|
+
policy: ResolvePathPolicy;
|
|
22
|
+
};
|
|
16
23
|
export declare function resolveVariablesTemplate(ctx: ResourcerContext, template: JSONValue, contextParams?: Record<string, unknown>): Promise<any>;
|
|
24
|
+
export declare function resolveFlowModelVariablesTemplate(ctx: ResourcerContext, options: {
|
|
25
|
+
contextParams?: Record<string, unknown>;
|
|
26
|
+
rd?: string | number;
|
|
27
|
+
template: JSONValue;
|
|
28
|
+
}): Promise<any>;
|
|
29
|
+
export declare function resolveAnalyzedVariablesTemplate(ctx: ResourcerContext, analysis: AnalyzedTemplate, policy: ResolvePathPolicy, bindingPlan: RecordBindingPlan): Promise<any>;
|
|
17
30
|
export declare function resolveVariablesBatch(ctx: ResourcerContext, items: ResolveBatchItem[]): Promise<{
|
|
18
31
|
id?: string | number;
|
|
19
32
|
data: unknown;
|
|
20
33
|
}[]>;
|
|
21
|
-
export {
|
|
34
|
+
export declare function resolveAnalyzedVariablesBatch(ctx: ResourcerContext, items: AnalyzedResolveBatchItem[]): Promise<{
|
|
35
|
+
id?: string | number;
|
|
36
|
+
data: unknown;
|
|
37
|
+
}[]>;
|
|
@@ -26,15 +26,26 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
26
26
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
27
27
|
var resolve_exports = {};
|
|
28
28
|
__export(resolve_exports, {
|
|
29
|
+
resolveAnalyzedVariablesBatch: () => resolveAnalyzedVariablesBatch,
|
|
30
|
+
resolveAnalyzedVariablesTemplate: () => resolveAnalyzedVariablesTemplate,
|
|
31
|
+
resolveFlowModelVariablesTemplate: () => resolveFlowModelVariablesTemplate,
|
|
29
32
|
resolveVariablesBatch: () => resolveVariablesBatch,
|
|
30
33
|
resolveVariablesTemplate: () => resolveVariablesTemplate
|
|
31
34
|
});
|
|
32
35
|
module.exports = __toCommonJS(resolve_exports);
|
|
33
36
|
var import_contexts = require("../template/contexts");
|
|
34
37
|
var import_resolver = require("../template/resolver");
|
|
38
|
+
var import_allow_list = require("./allow-list");
|
|
39
|
+
var import_record_bindings = require("./record-bindings");
|
|
35
40
|
var import_registry = require("./registry");
|
|
41
|
+
var import_record_slot_policy = require("./record-slot-policy");
|
|
36
42
|
var import_utils = require("./utils");
|
|
37
43
|
const GLOBAL_CONTEXT_KEY = Symbol.for("nocobase.flow-engine.variables.global-context");
|
|
44
|
+
const REQUEST_BOUND_RESOLVE_POLICY = {
|
|
45
|
+
allowAll: true,
|
|
46
|
+
allowedPaths: /* @__PURE__ */ new Set(),
|
|
47
|
+
unrestrictedVariables: /* @__PURE__ */ new Set()
|
|
48
|
+
};
|
|
38
49
|
function getGlobalContext(ctx) {
|
|
39
50
|
var _a, _b;
|
|
40
51
|
const app = ctx.app;
|
|
@@ -44,36 +55,91 @@ function getGlobalContext(ctx) {
|
|
|
44
55
|
return app[GLOBAL_CONTEXT_KEY];
|
|
45
56
|
}
|
|
46
57
|
async function resolveVariablesTemplate(ctx, template, contextParams = {}) {
|
|
47
|
-
|
|
48
|
-
|
|
58
|
+
const result = (0, import_allow_list.analyzeVariableTemplateSafely)(template, { mode: "untrusted-request" });
|
|
59
|
+
if (!result.ok) return template;
|
|
60
|
+
const bindingPlan = await createRequestBoundRecordBindingPlan(ctx, result.analysis, contextParams);
|
|
61
|
+
return resolveAnalyzedVariablesTemplate(ctx, result.analysis, REQUEST_BOUND_RESOLVE_POLICY, bindingPlan);
|
|
62
|
+
}
|
|
63
|
+
async function resolveFlowModelVariablesTemplate(ctx, options) {
|
|
64
|
+
if (!await (0, import_allow_list.resolveFlowModelNodeFromRequestRd)(ctx, options.rd)) return;
|
|
65
|
+
const authorization = await (0, import_allow_list.authorizeVariablesResolve)(ctx, options);
|
|
66
|
+
if (!authorization.allowed || !authorization.flowModelUid) return;
|
|
67
|
+
const resolved = await resolveAnalyzedVariablesTemplate(
|
|
68
|
+
ctx,
|
|
69
|
+
authorization.analysis,
|
|
70
|
+
authorization.policy,
|
|
71
|
+
authorization.bindingPlan
|
|
72
|
+
);
|
|
73
|
+
const remaining = (0, import_allow_list.analyzeVariableTemplateSafely)(resolved, { mode: "untrusted-request" });
|
|
74
|
+
if (!remaining.ok || remaining.analysis.paths.length) return;
|
|
75
|
+
return resolved;
|
|
76
|
+
}
|
|
77
|
+
async function createRequestBoundRecordBindingPlan(ctx, analysis, contextParams) {
|
|
78
|
+
const policies = await (0, import_record_slot_policy.compileRecordSlotPolicies)(analysis, { app: ctx.app, ctx });
|
|
79
|
+
return (0, import_record_bindings.planRecordBindings)({
|
|
80
|
+
contextParams,
|
|
81
|
+
koaCtx: ctx,
|
|
82
|
+
policies,
|
|
83
|
+
usage: analysis.usage
|
|
84
|
+
});
|
|
49
85
|
}
|
|
50
|
-
async function
|
|
86
|
+
async function resolveAnalyzedVariablesTemplate(ctx, analysis, policy, bindingPlan) {
|
|
87
|
+
await (0, import_utils.prefetchRecordsForResolve)(ctx, bindingPlan.bindings);
|
|
88
|
+
return resolveAnalyzedVariablesTemplateWithPrefetchedRecords(ctx, analysis, policy, bindingPlan);
|
|
89
|
+
}
|
|
90
|
+
async function resolveAnalyzedVariablesTemplateWithPrefetchedRecords(ctx, analysis, policy, bindingPlan) {
|
|
51
91
|
const requestCtx = new import_contexts.HttpRequestContext(ctx);
|
|
52
92
|
requestCtx.delegate(getGlobalContext(ctx));
|
|
53
|
-
await import_registry.variables.
|
|
54
|
-
return (0, import_resolver.
|
|
93
|
+
await import_registry.variables.attachUsedVariablesFromPlan(requestCtx, ctx, analysis.usage, bindingPlan);
|
|
94
|
+
return (0, import_resolver.resolveAnalyzedJsonTemplate)(analysis, requestCtx, policy);
|
|
55
95
|
}
|
|
56
96
|
async function resolveVariablesBatch(ctx, items) {
|
|
97
|
+
var _a;
|
|
98
|
+
const analyzedItems = [];
|
|
99
|
+
const results = [];
|
|
100
|
+
for (const [index, item] of items.entries()) {
|
|
101
|
+
const result = (0, import_allow_list.analyzeVariableTemplateSafely)((item == null ? void 0 : item.template) ?? {}, { mode: "untrusted-request" });
|
|
102
|
+
if (!result.ok) {
|
|
103
|
+
results[index] = { id: item == null ? void 0 : item.id, data: (item == null ? void 0 : item.template) ?? {} };
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
analyzedItems.push({
|
|
107
|
+
...item,
|
|
108
|
+
id: index,
|
|
109
|
+
analysis: result.analysis,
|
|
110
|
+
bindingPlan: await createRequestBoundRecordBindingPlan(ctx, result.analysis, item.contextParams || {}),
|
|
111
|
+
policy: REQUEST_BOUND_RESOLVE_POLICY
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
const resolvedItems = await resolveAnalyzedVariablesBatch(ctx, analyzedItems);
|
|
115
|
+
for (const item of resolvedItems) {
|
|
116
|
+
const index = Number(item.id);
|
|
117
|
+
results[index] = { id: (_a = items[index]) == null ? void 0 : _a.id, data: item.data };
|
|
118
|
+
}
|
|
119
|
+
return results.filter((item) => !!item);
|
|
120
|
+
}
|
|
121
|
+
async function resolveAnalyzedVariablesBatch(ctx, items) {
|
|
57
122
|
await (0, import_utils.prefetchRecordsForResolve)(
|
|
58
123
|
ctx,
|
|
59
|
-
items.
|
|
60
|
-
template: (item == null ? void 0 : item.template) ?? {},
|
|
61
|
-
contextParams: (item == null ? void 0 : item.contextParams) || {}
|
|
62
|
-
}))
|
|
124
|
+
items.flatMap((item) => item.bindingPlan.bindings)
|
|
63
125
|
);
|
|
64
126
|
const results = [];
|
|
65
127
|
for (const item of items) {
|
|
66
|
-
const data = await
|
|
128
|
+
const data = await resolveAnalyzedVariablesTemplateWithPrefetchedRecords(
|
|
67
129
|
ctx,
|
|
68
|
-
|
|
69
|
-
|
|
130
|
+
item.analysis,
|
|
131
|
+
item.policy,
|
|
132
|
+
item.bindingPlan
|
|
70
133
|
);
|
|
71
|
-
results.push({ id: item
|
|
134
|
+
results.push({ id: item.id, data });
|
|
72
135
|
}
|
|
73
136
|
return results;
|
|
74
137
|
}
|
|
75
138
|
// Annotate the CommonJS export names for ESM import in node:
|
|
76
139
|
0 && (module.exports = {
|
|
140
|
+
resolveAnalyzedVariablesBatch,
|
|
141
|
+
resolveAnalyzedVariablesTemplate,
|
|
142
|
+
resolveFlowModelVariablesTemplate,
|
|
77
143
|
resolveVariablesBatch,
|
|
78
144
|
resolveVariablesTemplate
|
|
79
145
|
});
|
|
@@ -0,0 +1,21 @@
|
|
|
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
|
+
export type PreparedFlowModelVariableSource = Readonly<{
|
|
10
|
+
ok: true;
|
|
11
|
+
runJsTemplates: readonly string[];
|
|
12
|
+
templateSource: unknown;
|
|
13
|
+
}> | Readonly<{
|
|
14
|
+
ok: false;
|
|
15
|
+
}>;
|
|
16
|
+
export declare const MAX_FLOW_MODEL_VARIABLE_SOURCE_DEPTH = 128;
|
|
17
|
+
export declare const MAX_FLOW_MODEL_VARIABLE_SOURCE_NODES = 10000;
|
|
18
|
+
export declare const MAX_FLOW_MODEL_VARIABLE_STRING_LENGTH: number;
|
|
19
|
+
export declare const MAX_FLOW_MODEL_VARIABLE_TOTAL_STRING_LENGTH: number;
|
|
20
|
+
export declare function prepareFlowModelVariableSource(value: unknown): PreparedFlowModelVariableSource;
|
|
21
|
+
export declare function collectPersistedRunJsVariableTemplates(value: unknown): string[];
|
|
@@ -0,0 +1,313 @@
|
|
|
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 runjs_variable_dependencies_exports = {};
|
|
28
|
+
__export(runjs_variable_dependencies_exports, {
|
|
29
|
+
MAX_FLOW_MODEL_VARIABLE_SOURCE_DEPTH: () => MAX_FLOW_MODEL_VARIABLE_SOURCE_DEPTH,
|
|
30
|
+
MAX_FLOW_MODEL_VARIABLE_SOURCE_NODES: () => MAX_FLOW_MODEL_VARIABLE_SOURCE_NODES,
|
|
31
|
+
MAX_FLOW_MODEL_VARIABLE_STRING_LENGTH: () => MAX_FLOW_MODEL_VARIABLE_STRING_LENGTH,
|
|
32
|
+
MAX_FLOW_MODEL_VARIABLE_TOTAL_STRING_LENGTH: () => MAX_FLOW_MODEL_VARIABLE_TOTAL_STRING_LENGTH,
|
|
33
|
+
collectPersistedRunJsVariableTemplates: () => collectPersistedRunJsVariableTemplates,
|
|
34
|
+
prepareFlowModelVariableSource: () => prepareFlowModelVariableSource
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(runjs_variable_dependencies_exports);
|
|
37
|
+
var import_bindings = require("../flow-surfaces/runjs-authoring/ast/bindings");
|
|
38
|
+
var import_source = require("../flow-surfaces/runjs-authoring/ast/source");
|
|
39
|
+
var import_static_bindings = require("../flow-surfaces/runjs-authoring/ast/static-bindings");
|
|
40
|
+
var import_static_values = require("../flow-surfaces/runjs-authoring/ast/static-values");
|
|
41
|
+
var import_parser = require("../flow-surfaces/runjs-authoring/ast/parser");
|
|
42
|
+
var import_walk = require("../flow-surfaces/runjs-authoring/ast/walk");
|
|
43
|
+
var import_constants = require("../flow-surfaces/runjs-authoring/runtime/constants");
|
|
44
|
+
var import_variable_expression = require("../template/variable-expression");
|
|
45
|
+
const RUNJS_VALUE_KEYS = /* @__PURE__ */ new Set(["code", "version"]);
|
|
46
|
+
const RUNJS_PATH_SUFFIXES = /* @__PURE__ */ new Set(["stepParams.jsSettings.runJs", "stepParams.clickSettings.runJs"]);
|
|
47
|
+
const MUTATING_CTX_METHODS = /* @__PURE__ */ new Set(["__defineGetter__", "__defineSetter__"]);
|
|
48
|
+
const MAX_FLOW_MODEL_VARIABLE_SOURCE_DEPTH = 128;
|
|
49
|
+
const MAX_FLOW_MODEL_VARIABLE_SOURCE_NODES = 1e4;
|
|
50
|
+
const MAX_FLOW_MODEL_VARIABLE_STRING_LENGTH = 256 * 1024;
|
|
51
|
+
const MAX_FLOW_MODEL_VARIABLE_TOTAL_STRING_LENGTH = 1024 * 1024;
|
|
52
|
+
function getEnumerableDataEntries(value) {
|
|
53
|
+
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
54
|
+
const entries = [];
|
|
55
|
+
for (const key of Object.keys(descriptors)) {
|
|
56
|
+
const descriptor = descriptors[key];
|
|
57
|
+
if (!descriptor.enumerable) continue;
|
|
58
|
+
if (!Object.prototype.hasOwnProperty.call(descriptor, "value")) {
|
|
59
|
+
throw new TypeError("FlowModel variable source must not contain accessors");
|
|
60
|
+
}
|
|
61
|
+
entries.push([key, descriptor.value]);
|
|
62
|
+
}
|
|
63
|
+
return { descriptors, entries };
|
|
64
|
+
}
|
|
65
|
+
function readPersistedRunJsValue(entries) {
|
|
66
|
+
if (!entries.length || entries.some(([key]) => !RUNJS_VALUE_KEYS.has(key))) return;
|
|
67
|
+
const values = new Map(entries);
|
|
68
|
+
const code = values.get("code");
|
|
69
|
+
const version = values.get("version");
|
|
70
|
+
if (typeof code !== "string" || version != null && typeof version !== "string") return;
|
|
71
|
+
return { code, version };
|
|
72
|
+
}
|
|
73
|
+
function isPersistedRunJsPath(pathTail) {
|
|
74
|
+
return RUNJS_PATH_SUFFIXES.has(pathTail.join("."));
|
|
75
|
+
}
|
|
76
|
+
function createTraversalContainer(input, descriptors) {
|
|
77
|
+
var _a;
|
|
78
|
+
if (!Array.isArray(input)) return /* @__PURE__ */ Object.create(null);
|
|
79
|
+
const length = (_a = descriptors.length) == null ? void 0 : _a.value;
|
|
80
|
+
if (!Number.isInteger(length) || length < 0 || length > MAX_FLOW_MODEL_VARIABLE_SOURCE_NODES) {
|
|
81
|
+
throw new RangeError("FlowModel variable source array exceeds its limit");
|
|
82
|
+
}
|
|
83
|
+
return new Array(length);
|
|
84
|
+
}
|
|
85
|
+
function defineTraversalValue(parent, key, value) {
|
|
86
|
+
Object.defineProperty(parent, key, {
|
|
87
|
+
configurable: true,
|
|
88
|
+
enumerable: true,
|
|
89
|
+
value,
|
|
90
|
+
writable: true
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
function functionBindsCtxParameter(node, cache) {
|
|
94
|
+
if (!(0, import_bindings.isAstFunctionLike)(node)) return false;
|
|
95
|
+
const objectNode = node;
|
|
96
|
+
const cached = cache.get(objectNode);
|
|
97
|
+
if (typeof cached === "boolean") return cached;
|
|
98
|
+
let bindsCtx = false;
|
|
99
|
+
for (const parameter of node.params || []) {
|
|
100
|
+
(0, import_static_values.collectAstPatternBindingIdentifiers)(parameter, (name) => {
|
|
101
|
+
if (name === "ctx") bindsCtx = true;
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
cache.set(objectNode, bindsCtx);
|
|
105
|
+
return bindsCtx;
|
|
106
|
+
}
|
|
107
|
+
function hasCtxParameterInFunctionAncestors(ancestors, cache) {
|
|
108
|
+
return ancestors.some((ancestor) => functionBindsCtxParameter(ancestor, cache));
|
|
109
|
+
}
|
|
110
|
+
function isDirectCtxGetVarMember(node, identifierBindings) {
|
|
111
|
+
const member = (0, import_bindings.unwrapAstChainExpression)(node);
|
|
112
|
+
return (member == null ? void 0 : member.type) === "MemberExpression" && (0, import_static_values.isUnshadowedCtxIdentifier)(member.object, identifierBindings) && (0, import_static_values.getAstStaticPropertyName)(member) === "getVar";
|
|
113
|
+
}
|
|
114
|
+
function isCtxRootedMember(node, identifierBindings) {
|
|
115
|
+
const member = (0, import_bindings.unwrapAstChainExpression)(node);
|
|
116
|
+
if ((member == null ? void 0 : member.type) !== "MemberExpression") return false;
|
|
117
|
+
const root = (0, import_static_values.getAstMemberRootIdentifier)(member);
|
|
118
|
+
return (root == null ? void 0 : root.name) === "ctx" && !(0, import_static_values.hasAstActiveBinding)("ctx", root.index, identifierBindings);
|
|
119
|
+
}
|
|
120
|
+
function isCtxMutationTarget(target, identifierBindings) {
|
|
121
|
+
const node = (0, import_bindings.unwrapAstChainExpression)(target);
|
|
122
|
+
if (!node) return false;
|
|
123
|
+
if (node.type === "Identifier") return (0, import_static_values.isUnshadowedCtxIdentifier)(node, identifierBindings);
|
|
124
|
+
if (node.type === "MemberExpression") return isCtxRootedMember(node, identifierBindings);
|
|
125
|
+
if (node.type === "AssignmentPattern") return isCtxMutationTarget(node.left, identifierBindings);
|
|
126
|
+
if (node.type === "RestElement") return isCtxMutationTarget(node.argument, identifierBindings);
|
|
127
|
+
if (node.type === "ArrayPattern") {
|
|
128
|
+
return (node.elements || []).some((element) => isCtxMutationTarget(element, identifierBindings));
|
|
129
|
+
}
|
|
130
|
+
if (node.type !== "ObjectPattern") return false;
|
|
131
|
+
return (node.properties || []).some((propertyValue) => {
|
|
132
|
+
const property = propertyValue;
|
|
133
|
+
if ((property == null ? void 0 : property.type) === "RestElement") {
|
|
134
|
+
return isCtxMutationTarget(property.argument, identifierBindings);
|
|
135
|
+
}
|
|
136
|
+
return (property == null ? void 0 : property.type) === "Property" && isCtxMutationTarget(property.value, identifierBindings);
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
function isNonReferenceIdentifier(node, parent) {
|
|
140
|
+
if (!parent) return false;
|
|
141
|
+
if (parent.type === "MemberExpression" && parent.property === node && !parent.computed) return true;
|
|
142
|
+
if (parent.type === "Property" && parent.key === node && !parent.computed && !parent.shorthand) return true;
|
|
143
|
+
if ((parent.type === "MethodDefinition" || parent.type === "PropertyDefinition") && parent.key === node && !parent.computed) {
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
return (parent.type === "LabeledStatement" || parent.type === "BreakStatement" || parent.type === "ContinueStatement") && parent.value === node;
|
|
147
|
+
}
|
|
148
|
+
function hasUnsafeCtxUsage(ast, identifierBindings) {
|
|
149
|
+
let unsafe = false;
|
|
150
|
+
(0, import_walk.walkAstAncestor)(ast, {
|
|
151
|
+
Identifier(node, ancestors) {
|
|
152
|
+
if (!(0, import_static_values.isUnshadowedCtxIdentifier)(node, identifierBindings)) return;
|
|
153
|
+
const parent = ancestors[ancestors.length - 2];
|
|
154
|
+
if (isNonReferenceIdentifier(node, parent)) return;
|
|
155
|
+
if ((parent == null ? void 0 : parent.type) === "MemberExpression" && (0, import_bindings.unwrapAstChainExpression)(parent.object) === node) return;
|
|
156
|
+
unsafe = true;
|
|
157
|
+
},
|
|
158
|
+
WithStatement() {
|
|
159
|
+
unsafe = true;
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
return unsafe;
|
|
163
|
+
}
|
|
164
|
+
function hasCtxMutation(ast, identifierBindings) {
|
|
165
|
+
let mutated = false;
|
|
166
|
+
(0, import_walk.walkAstSimple)(ast, {
|
|
167
|
+
AssignmentExpression(node) {
|
|
168
|
+
if (isCtxMutationTarget(node.left, identifierBindings)) mutated = true;
|
|
169
|
+
},
|
|
170
|
+
CallExpression(node) {
|
|
171
|
+
const callee = (0, import_bindings.unwrapAstChainExpression)(node.callee);
|
|
172
|
+
if ((callee == null ? void 0 : callee.type) === "MemberExpression" && MUTATING_CTX_METHODS.has((0, import_static_values.getAstStaticPropertyName)(callee)) && isCtxRootedMember(callee, identifierBindings)) {
|
|
173
|
+
mutated = true;
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
ForInStatement(node) {
|
|
177
|
+
if (isCtxMutationTarget(node.left, identifierBindings)) mutated = true;
|
|
178
|
+
},
|
|
179
|
+
ForOfStatement(node) {
|
|
180
|
+
if (isCtxMutationTarget(node.left, identifierBindings)) mutated = true;
|
|
181
|
+
},
|
|
182
|
+
UnaryExpression(node) {
|
|
183
|
+
if (node.operator === "delete" && isCtxMutationTarget(node.argument, identifierBindings)) {
|
|
184
|
+
mutated = true;
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
UpdateExpression(node) {
|
|
188
|
+
if (isCtxMutationTarget(node.argument, identifierBindings)) mutated = true;
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
return mutated;
|
|
192
|
+
}
|
|
193
|
+
function createValidatedGetVarTemplate(value, code) {
|
|
194
|
+
var _a;
|
|
195
|
+
const path = (_a = (0, import_static_values.resolveAstStaticStringValue)(value, code)) == null ? void 0 : _a.trim();
|
|
196
|
+
if (!path) return;
|
|
197
|
+
const template = `{{${path}}}`;
|
|
198
|
+
const analysis = (0, import_variable_expression.analyzeVariableTemplate)(template, { mode: "flow-model" });
|
|
199
|
+
if (analysis.errors.length !== 0 || analysis.paths.length !== 1 || analysis.value.kind !== "string") return;
|
|
200
|
+
if (analysis.value.expressions.length !== 1) return;
|
|
201
|
+
const expression = analysis.value.expressions[0];
|
|
202
|
+
const variablePath = expression.paths[0];
|
|
203
|
+
if (!variablePath || !expression.supported || expression.paths.length !== 1 || expression.expressionSpan.start !== 2 || expression.expressionSpan.end !== 2 + path.length || expression.placeholderSpan.start !== 0 || expression.placeholderSpan.end !== template.length || variablePath.span.start !== 2 || variablePath.span.end !== 2 + path.length) {
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
return `{{ ${path} }}`;
|
|
207
|
+
}
|
|
208
|
+
function extractStaticGetVarTemplates(code) {
|
|
209
|
+
const parsed = (0, import_parser.parseRunJsAuthoringAst)(code);
|
|
210
|
+
if (!parsed.ast) return [];
|
|
211
|
+
const identifierBindings = (0, import_static_bindings.collectAstIdentifierBindingsFromAst)(parsed.ast, code);
|
|
212
|
+
if (hasUnsafeCtxUsage(parsed.ast, identifierBindings) || hasCtxMutation(parsed.ast, identifierBindings)) {
|
|
213
|
+
return [];
|
|
214
|
+
}
|
|
215
|
+
const functionCtxParameterCache = /* @__PURE__ */ new WeakMap();
|
|
216
|
+
const templates = /* @__PURE__ */ new Set();
|
|
217
|
+
(0, import_walk.walkAstAncestor)(parsed.ast, {
|
|
218
|
+
CallExpression(node, ancestors) {
|
|
219
|
+
var _a;
|
|
220
|
+
const callee = (0, import_bindings.unwrapAstChainExpression)(node.callee);
|
|
221
|
+
if ((callee == null ? void 0 : callee.type) !== "MemberExpression" || !(0, import_static_values.isUnshadowedCtxIdentifier)(callee.object, identifierBindings) || (0, import_static_values.getAstStaticPropertyName)(callee) !== "getVar" || hasCtxParameterInFunctionAncestors(ancestors, functionCtxParameterCache)) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
const template = createValidatedGetVarTemplate((_a = node.arguments) == null ? void 0 : _a[0], code);
|
|
225
|
+
if (template) templates.add(template);
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
return Array.from(templates);
|
|
229
|
+
}
|
|
230
|
+
function prepareFlowModelVariableSource(value) {
|
|
231
|
+
var _a;
|
|
232
|
+
try {
|
|
233
|
+
const templates = /* @__PURE__ */ new Set();
|
|
234
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
235
|
+
const root = /* @__PURE__ */ Object.create(null);
|
|
236
|
+
const stack = [{ depth: 0, input: value, key: "value", parent: root, pathTail: [] }];
|
|
237
|
+
let scheduledNodes = 1;
|
|
238
|
+
let sourceCount = 0;
|
|
239
|
+
let totalStringLength = 0;
|
|
240
|
+
let totalSourceLength = 0;
|
|
241
|
+
while (stack.length) {
|
|
242
|
+
const frame = stack.pop();
|
|
243
|
+
if (!frame) break;
|
|
244
|
+
const { depth, input, key, parent, pathTail } = frame;
|
|
245
|
+
if (!input || typeof input !== "object") {
|
|
246
|
+
if (typeof input === "string") {
|
|
247
|
+
totalStringLength += input.length;
|
|
248
|
+
if (input.length > MAX_FLOW_MODEL_VARIABLE_STRING_LENGTH || totalStringLength > MAX_FLOW_MODEL_VARIABLE_TOTAL_STRING_LENGTH) {
|
|
249
|
+
return { ok: false };
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
defineTraversalValue(parent, key, input);
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
if (seen.has(input)) return { ok: false };
|
|
256
|
+
seen.add(input);
|
|
257
|
+
const { descriptors, entries } = getEnumerableDataEntries(input);
|
|
258
|
+
for (const [entryKey] of entries) {
|
|
259
|
+
totalStringLength += entryKey.length;
|
|
260
|
+
if (entryKey.length > MAX_FLOW_MODEL_VARIABLE_STRING_LENGTH || totalStringLength > MAX_FLOW_MODEL_VARIABLE_TOTAL_STRING_LENGTH) {
|
|
261
|
+
return { ok: false };
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
const runJs = !Array.isArray(input) && isPersistedRunJsPath(pathTail) ? readPersistedRunJsValue(entries) : void 0;
|
|
265
|
+
const output = createTraversalContainer(input, descriptors);
|
|
266
|
+
defineTraversalValue(parent, key, output);
|
|
267
|
+
if (runJs) {
|
|
268
|
+
scheduledNodes += entries.length;
|
|
269
|
+
sourceCount += 1;
|
|
270
|
+
totalStringLength += runJs.code.length + (((_a = runJs.version) == null ? void 0 : _a.length) || 0);
|
|
271
|
+
totalSourceLength += runJs.code.length;
|
|
272
|
+
if (scheduledNodes > MAX_FLOW_MODEL_VARIABLE_SOURCE_NODES || runJs.code.length > MAX_FLOW_MODEL_VARIABLE_STRING_LENGTH || runJs.version != null && runJs.version.length > MAX_FLOW_MODEL_VARIABLE_STRING_LENGTH || totalStringLength > MAX_FLOW_MODEL_VARIABLE_TOTAL_STRING_LENGTH || sourceCount > import_constants.MAX_RUNJS_SOURCES_PER_REQUEST || runJs.code.length > import_constants.MAX_RUNJS_SOURCE_LENGTH || totalSourceLength > import_constants.MAX_RUNJS_TOTAL_SOURCE_LENGTH) {
|
|
273
|
+
return { ok: false };
|
|
274
|
+
}
|
|
275
|
+
for (const [entryKey, entryValue] of entries) {
|
|
276
|
+
const preparedEntryValue = entryKey === "code" ? runJs.version === "v2" ? "" : (0, import_source.maskJavaScriptComments)(runJs.code) : entryValue;
|
|
277
|
+
defineTraversalValue(output, entryKey, preparedEntryValue);
|
|
278
|
+
}
|
|
279
|
+
extractStaticGetVarTemplates(runJs.code).forEach((template) => templates.add(template));
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
282
|
+
if (entries.length && depth >= MAX_FLOW_MODEL_VARIABLE_SOURCE_DEPTH) return { ok: false };
|
|
283
|
+
scheduledNodes += entries.length;
|
|
284
|
+
if (scheduledNodes > MAX_FLOW_MODEL_VARIABLE_SOURCE_NODES) return { ok: false };
|
|
285
|
+
for (let index = entries.length - 1; index >= 0; index -= 1) {
|
|
286
|
+
const [entryKey, entryValue] = entries[index];
|
|
287
|
+
stack.push({
|
|
288
|
+
depth: depth + 1,
|
|
289
|
+
input: entryValue,
|
|
290
|
+
key: entryKey,
|
|
291
|
+
parent: output,
|
|
292
|
+
pathTail: [...pathTail, entryKey].slice(-3)
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
return { ok: true, runJsTemplates: Array.from(templates), templateSource: root.value };
|
|
297
|
+
} catch {
|
|
298
|
+
return { ok: false };
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
function collectPersistedRunJsVariableTemplates(value) {
|
|
302
|
+
const prepared = prepareFlowModelVariableSource(value);
|
|
303
|
+
return prepared.ok ? Array.from(prepared.runJsTemplates) : [];
|
|
304
|
+
}
|
|
305
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
306
|
+
0 && (module.exports = {
|
|
307
|
+
MAX_FLOW_MODEL_VARIABLE_SOURCE_DEPTH,
|
|
308
|
+
MAX_FLOW_MODEL_VARIABLE_SOURCE_NODES,
|
|
309
|
+
MAX_FLOW_MODEL_VARIABLE_STRING_LENGTH,
|
|
310
|
+
MAX_FLOW_MODEL_VARIABLE_TOTAL_STRING_LENGTH,
|
|
311
|
+
collectPersistedRunJsVariableTemplates,
|
|
312
|
+
prepareFlowModelVariableSource
|
|
313
|
+
});
|
|
@@ -7,11 +7,8 @@
|
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
9
|
import type { ResourcerContext } from '@nocobase/resourcer';
|
|
10
|
-
import type {
|
|
10
|
+
import type { AuthorizedRecordBinding } from './record-bindings';
|
|
11
11
|
/**
|
|
12
|
-
*
|
|
12
|
+
* Merge record selects for one resolve request and populate the request cache once per target.
|
|
13
13
|
*/
|
|
14
|
-
export declare function prefetchRecordsForResolve(koaCtx: ResourcerContext,
|
|
15
|
-
template: JSONValue;
|
|
16
|
-
contextParams?: Record<string, unknown>;
|
|
17
|
-
}>): Promise<void>;
|
|
14
|
+
export declare function prefetchRecordsForResolve(koaCtx: ResourcerContext, bindings: readonly AuthorizedRecordBinding[]): Promise<void>;
|