@flusys/nestjs-entity-builder 9.1.2 → 9.2.0
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/README.md +15 -9
- package/config/message-keys.d.ts +26 -0
- package/controllers/entity-definition.controller.d.ts +1 -0
- package/controllers/field-definition.controller.d.ts +1 -0
- package/controllers/flow-definition.controller.d.ts +1 -0
- package/dtos/definition-bundle.dto.d.ts +1 -0
- package/dtos/entity-definition.dto.d.ts +1 -2
- package/fesm/21.js +26 -0
- package/fesm/458.js +6 -1
- package/fesm/677.js +372 -107
- package/fesm/857.js +2 -1
- package/fesm/870.js +580 -247
- package/fesm/897.js +164 -22
- package/fesm/946.js +5 -1
- package/fesm/dtos/index.js +11 -0
- package/fesm/guards/index.js +1 -1
- package/fesm/index.js +20 -2
- package/fesm/services/index.js +12 -2
- package/flow-engine/flow-input.validator.d.ts +2 -1
- package/flow-engine/flow-run.types.d.ts +1 -0
- package/flow-engine/flow.types.d.ts +17 -0
- package/interfaces/definition-bundle.interface.d.ts +2 -1
- package/package.json +3 -3
- package/services/definition-bundle.diff.d.ts +6 -0
- package/services/definition-bundle.service.d.ts +10 -2
- package/services/entity-flow-scaffold.d.ts +2 -1
- package/services/entity-permission.service.d.ts +1 -0
- package/services/flow-definition.service.d.ts +1 -1
- package/services/flow-runtime.service.d.ts +1 -0
- package/services/generic-entity.service.d.ts +1 -0
- package/services/schema-change-executor.service.d.ts +1 -0
- package/services/schema-dialect-adapter.service.d.ts +2 -0
package/fesm/677.js
CHANGED
|
@@ -725,6 +725,128 @@ function writeOptions(state) {
|
|
|
725
725
|
publishEvents: false
|
|
726
726
|
} : {};
|
|
727
727
|
}
|
|
728
|
+
/** A get_all request's own query: what a `fromRequest` query reads. A list body has none. */ function requestQuery(state) {
|
|
729
|
+
return Array.isArray(state.input) ? {} : state.input;
|
|
730
|
+
}
|
|
731
|
+
/** A request's filter the way the API controller reads it: a value matches as equal, a list as one of its items - never an operator the caller sent. */ function requestFilter(filter) {
|
|
732
|
+
return Object.fromEntries(Object.entries(filter ?? {}).map(([key, value])=>[
|
|
733
|
+
key,
|
|
734
|
+
{
|
|
735
|
+
op: Array.isArray(value) ? 'in' : 'eq',
|
|
736
|
+
value
|
|
737
|
+
}
|
|
738
|
+
]));
|
|
739
|
+
}
|
|
740
|
+
/** Only the fields a request's `select` names, `id` always kept; every field when it names none. */ function selectFields(rows, select) {
|
|
741
|
+
if (!select?.length) return rows;
|
|
742
|
+
const kept = new Set([
|
|
743
|
+
'id',
|
|
744
|
+
...select
|
|
745
|
+
]);
|
|
746
|
+
return rows.map((row)=>Object.fromEntries(Object.entries(row).filter(([key])=>kept.has(key))));
|
|
747
|
+
}
|
|
748
|
+
async function runQuery(node, cfg, env, state) {
|
|
749
|
+
const ctx = evaluationContext(state, env);
|
|
750
|
+
const service = await env.entityService(cfg.entityCode, state.qr);
|
|
751
|
+
const request = cfg.fromRequest ? requestQuery(state) : {};
|
|
752
|
+
const filter = {
|
|
753
|
+
...requestFilter(request.filter),
|
|
754
|
+
...await mapFilter(node, cfg.filter, env, state, 'skip')
|
|
755
|
+
};
|
|
756
|
+
const searched = cfg.search ? await env.ruleEngine.resolveExpression(cfg.search, ctx) : cfg.fromRequest ? state.request['query']?.['q'] : undefined;
|
|
757
|
+
const search = typeof searched === 'string' && searched ? searched : undefined;
|
|
758
|
+
const sort = cfg.sort ? {
|
|
759
|
+
[cfg.sort.field]: cfg.sort.direction === 'DESC' ? 'DESC' : 'ASC'
|
|
760
|
+
} : request.sort;
|
|
761
|
+
const page = request.pagination?.currentPage ?? 0;
|
|
762
|
+
const pageSize = Math.min(request.pagination?.pageSize ?? cfg.limit ?? 50, flow_types/* .FLOW_LIMITS.MAX_QUERY_LIMIT */.Or.MAX_QUERY_LIMIT);
|
|
763
|
+
const withDeleted = request.withDeleted === true ? {
|
|
764
|
+
withDeleted: true
|
|
765
|
+
} : {};
|
|
766
|
+
const { data, total } = await service.getAll(search, {
|
|
767
|
+
filter,
|
|
768
|
+
sort,
|
|
769
|
+
pagination: {
|
|
770
|
+
currentPage: page,
|
|
771
|
+
pageSize
|
|
772
|
+
},
|
|
773
|
+
...withDeleted
|
|
774
|
+
}, readOptions(state));
|
|
775
|
+
return {
|
|
776
|
+
output: {
|
|
777
|
+
items: selectFields(data, request.select),
|
|
778
|
+
total,
|
|
779
|
+
page,
|
|
780
|
+
pageSize
|
|
781
|
+
}
|
|
782
|
+
};
|
|
783
|
+
}
|
|
784
|
+
/** A Respond step's body: as built (raw), or the API controller envelope around it. */ async function respondBody(node, cfg, env, state) {
|
|
785
|
+
const ctx = evaluationContext(state, env);
|
|
786
|
+
const format = cfg.format ?? 'raw';
|
|
787
|
+
const built = async ()=>cfg.bodyExpression ? env.ruleEngine.resolveExpression(cfg.bodyExpression, ctx) : mapValues(cfg.body, env, state);
|
|
788
|
+
if (format === 'raw') return built();
|
|
789
|
+
const variables = await mapValues(cfg.messageVariables, env, state);
|
|
790
|
+
const envelope = {
|
|
791
|
+
success: cfg.statusCode < 400,
|
|
792
|
+
message: cfg.message ?? '',
|
|
793
|
+
messageKey: cfg.messageKey ?? '',
|
|
794
|
+
...Object.keys(variables).length ? {
|
|
795
|
+
messageVariables: variables
|
|
796
|
+
} : {}
|
|
797
|
+
};
|
|
798
|
+
if (format === 'message') return envelope;
|
|
799
|
+
if (format === 'single') return {
|
|
800
|
+
...envelope,
|
|
801
|
+
data: await built()
|
|
802
|
+
};
|
|
803
|
+
const value = await built();
|
|
804
|
+
if (value !== null && value !== undefined && !Array.isArray(value)) throw new flow_errors/* .FlowKeyedError */.Hp(message_keys/* .FLOW_ERROR_MESSAGES.RESPOND_DATA_NOT_LIST */.zr.RESPOND_DATA_NOT_LIST, {
|
|
805
|
+
node: (0,flow_types/* .nodeLabel */.dA)(node)
|
|
806
|
+
});
|
|
807
|
+
const data = value ?? [];
|
|
808
|
+
const count = async (name, fallback)=>{
|
|
809
|
+
const expression = cfg[name];
|
|
810
|
+
if (expression === undefined) return fallback;
|
|
811
|
+
const resolved = await env.ruleEngine.resolveExpression(expression, ctx);
|
|
812
|
+
if (resolved === null || resolved === undefined || resolved === '') return fallback;
|
|
813
|
+
const n = Number(resolved);
|
|
814
|
+
if (!Number.isInteger(n) || n < 0) throw new flow_errors/* .FlowKeyedError */.Hp(message_keys/* .FLOW_ERROR_MESSAGES.RESPOND_META_INVALID */.zr.RESPOND_META_INVALID, {
|
|
815
|
+
node: (0,flow_types/* .nodeLabel */.dA)(node),
|
|
816
|
+
name
|
|
817
|
+
});
|
|
818
|
+
return n;
|
|
819
|
+
};
|
|
820
|
+
if (format === 'bulk') {
|
|
821
|
+
const total = await count('total', Array.isArray(state.input) ? state.input.length : data.length);
|
|
822
|
+
return {
|
|
823
|
+
...envelope,
|
|
824
|
+
data,
|
|
825
|
+
meta: {
|
|
826
|
+
count: data.length,
|
|
827
|
+
total,
|
|
828
|
+
failed: Math.max(total - data.length, 0)
|
|
829
|
+
}
|
|
830
|
+
};
|
|
831
|
+
}
|
|
832
|
+
const pagination = requestQuery(state).pagination;
|
|
833
|
+
const total = await count('total', data.length);
|
|
834
|
+
const page = await count('page', pagination?.currentPage ?? 0);
|
|
835
|
+
const pageSize = await count('pageSize', pagination?.pageSize ?? data.length);
|
|
836
|
+
const totalPages = pageSize > 0 ? Math.ceil(total / pageSize) : 1;
|
|
837
|
+
return {
|
|
838
|
+
...envelope,
|
|
839
|
+
data,
|
|
840
|
+
meta: {
|
|
841
|
+
total,
|
|
842
|
+
page,
|
|
843
|
+
pageSize,
|
|
844
|
+
count: data.length,
|
|
845
|
+
hasMore: page < totalPages - 1,
|
|
846
|
+
totalPages
|
|
847
|
+
}
|
|
848
|
+
};
|
|
849
|
+
}
|
|
728
850
|
function readOptions(state) {
|
|
729
851
|
return {
|
|
730
852
|
queryRunner: state.qr
|
|
@@ -1407,8 +1529,11 @@ const nobody = (extra = {})=>({
|
|
|
1407
1529
|
const id = asId(await env.ruleEngine.resolveExpression(cfg.id, ctx));
|
|
1408
1530
|
const service = await env.entityService(cfg.entityCode, state.qr);
|
|
1409
1531
|
try {
|
|
1532
|
+
const record = await service.findById(id, readOptions(state));
|
|
1410
1533
|
return {
|
|
1411
|
-
output:
|
|
1534
|
+
output: cfg.fromRequest ? selectFields([
|
|
1535
|
+
record
|
|
1536
|
+
], requestQuery(state).select)[0] : record
|
|
1412
1537
|
};
|
|
1413
1538
|
} catch (error) {
|
|
1414
1539
|
if (error instanceof common_.NotFoundException && cfg.onNotFound === 'null') return {
|
|
@@ -1418,29 +1543,7 @@ const nobody = (extra = {})=>({
|
|
|
1418
1543
|
}
|
|
1419
1544
|
}
|
|
1420
1545
|
case 'entity_query':
|
|
1421
|
-
|
|
1422
|
-
const cfg = c;
|
|
1423
|
-
const service = await env.entityService(cfg.entityCode, state.qr);
|
|
1424
|
-
const filter = await mapFilter(node, cfg.filter, env, state, 'skip');
|
|
1425
|
-
const search = cfg.search ? await env.ruleEngine.resolveExpression(cfg.search, ctx) : undefined;
|
|
1426
|
-
const limit = Math.min(cfg.limit ?? 50, flow_types/* .FLOW_LIMITS.MAX_QUERY_LIMIT */.Or.MAX_QUERY_LIMIT);
|
|
1427
|
-
const { data, total } = await service.getAll(typeof search === 'string' && search ? search : undefined, {
|
|
1428
|
-
filter,
|
|
1429
|
-
sort: cfg.sort ? {
|
|
1430
|
-
[cfg.sort.field]: cfg.sort.direction === 'DESC' ? 'DESC' : 'ASC'
|
|
1431
|
-
} : undefined,
|
|
1432
|
-
pagination: {
|
|
1433
|
-
currentPage: 0,
|
|
1434
|
-
pageSize: limit
|
|
1435
|
-
}
|
|
1436
|
-
}, readOptions(state));
|
|
1437
|
-
return {
|
|
1438
|
-
output: {
|
|
1439
|
-
items: data,
|
|
1440
|
-
total
|
|
1441
|
-
}
|
|
1442
|
-
};
|
|
1443
|
-
}
|
|
1546
|
+
return runQuery(node, c, env, state);
|
|
1444
1547
|
case 'commit':
|
|
1445
1548
|
{
|
|
1446
1549
|
const reasonKey = state.mode === 'dry_run' ? message_keys/* .FLOW_SKIP_MESSAGES.COMMIT_DRY_RUN */.CB.COMMIT_DRY_RUN : !state.qr ? message_keys/* .FLOW_SKIP_MESSAGES.COMMIT_NO_TRANSACTION */.CB.COMMIT_NO_TRANSACTION : !state.ownsTransaction ? message_keys/* .FLOW_SKIP_MESSAGES.COMMIT_JOINED */.CB.COMMIT_JOINED : null;
|
|
@@ -1542,7 +1645,7 @@ const nobody = (extra = {})=>({
|
|
|
1542
1645
|
case 'respond':
|
|
1543
1646
|
{
|
|
1544
1647
|
const cfg = c;
|
|
1545
|
-
const body =
|
|
1648
|
+
const body = await respondBody(node, cfg, env, state);
|
|
1546
1649
|
return {
|
|
1547
1650
|
output: body,
|
|
1548
1651
|
respond: {
|
|
@@ -2203,19 +2306,29 @@ function conditionProblem(node, options) {
|
|
|
2203
2306
|
const warnings = [];
|
|
2204
2307
|
const err = (message)=>errors.push(message);
|
|
2205
2308
|
if (!_flow_types_js__rspack_import_5/* .FLOW_SLUG_PATTERN.test */.YD.test(flow.slug ?? '')) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_7/* .FLOW_VALIDATION_MESSAGES.SLUG_INVALID */.qj.SLUG_INVALID));
|
|
2206
|
-
const
|
|
2207
|
-
const
|
|
2208
|
-
if (!
|
|
2209
|
-
if (
|
|
2309
|
+
const allNodes = Array.isArray(flow.nodes) ? flow.nodes : [];
|
|
2310
|
+
const allEdges = Array.isArray(flow.edges) ? flow.edges : [];
|
|
2311
|
+
if (!allNodes.length) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_7/* .FLOW_VALIDATION_MESSAGES.NO_NODES */.qj.NO_NODES));
|
|
2312
|
+
if (allNodes.length > _flow_types_js__rspack_import_5/* .FLOW_LIMITS.MAX_NODES */.Or.MAX_NODES) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_7/* .FLOW_VALIDATION_MESSAGES.TOO_MANY_NODES */.qj.TOO_MANY_NODES, {
|
|
2210
2313
|
max: _flow_types_js__rspack_import_5/* .FLOW_LIMITS.MAX_NODES */.Or.MAX_NODES
|
|
2211
2314
|
}));
|
|
2212
|
-
if (
|
|
2315
|
+
if (allEdges.length > _flow_types_js__rspack_import_5/* .FLOW_LIMITS.MAX_EDGES */.Or.MAX_EDGES) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_7/* .FLOW_VALIDATION_MESSAGES.TOO_MANY_EDGES */.qj.TOO_MANY_EDGES, {
|
|
2213
2316
|
max: _flow_types_js__rspack_import_5/* .FLOW_LIMITS.MAX_EDGES */.Or.MAX_EDGES
|
|
2214
2317
|
}));
|
|
2215
|
-
if (errors.length && (!
|
|
2318
|
+
if (errors.length && (!allNodes.length || allNodes.length > _flow_types_js__rspack_import_5/* .FLOW_LIMITS.MAX_NODES */.Or.MAX_NODES || allEdges.length > _flow_types_js__rspack_import_5/* .FLOW_LIMITS.MAX_EDGES */.Or.MAX_EDGES)) return {
|
|
2216
2319
|
errors,
|
|
2217
2320
|
warnings
|
|
2218
2321
|
};
|
|
2322
|
+
const isEntry = (item)=>!!item && typeof item === 'object';
|
|
2323
|
+
const nodes = allNodes.filter(isEntry);
|
|
2324
|
+
const edges = allEdges.filter(isEntry);
|
|
2325
|
+
if (nodes.length < allNodes.length) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_7/* .FLOW_VALIDATION_MESSAGES.NODE_ID_INVALID */.qj.NODE_ID_INVALID, {
|
|
2326
|
+
id: undefined
|
|
2327
|
+
}));
|
|
2328
|
+
if (edges.length < allEdges.length) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_7/* .FLOW_VALIDATION_MESSAGES.EDGE_DANGLING */.qj.EDGE_DANGLING, {
|
|
2329
|
+
from: undefined,
|
|
2330
|
+
to: undefined
|
|
2331
|
+
}));
|
|
2219
2332
|
const byId = new Map();
|
|
2220
2333
|
for (const node of nodes){
|
|
2221
2334
|
if (!_flow_types_js__rspack_import_5/* .FLOW_NODE_ID_PATTERN.test */.z6.test(node?.id ?? '')) {
|
|
@@ -2313,7 +2426,7 @@ function conditionProblem(node, options) {
|
|
|
2313
2426
|
}
|
|
2314
2427
|
/** The entities a step reads or writes: its own, its child inserts' and those its lookups read. */ function entitiesOf(node) {
|
|
2315
2428
|
const codes = collectLookupEntities(node.config);
|
|
2316
|
-
if (node.type.startsWith('entity_') && typeof node.config?.['entityCode'] === 'string') codes.add(node.config['entityCode']);
|
|
2429
|
+
if (String(node.type).startsWith('entity_') && typeof node.config?.['entityCode'] === 'string') codes.add(node.config['entityCode']);
|
|
2317
2430
|
const children = node.type === 'entity_insert' && Array.isArray(node.config?.['children']) ? node.config['children'] : [];
|
|
2318
2431
|
for (const child of children)if (typeof child?.entityCode === 'string') codes.add(child.entityCode);
|
|
2319
2432
|
return [
|
|
@@ -2343,6 +2456,17 @@ function conditionProblem(node, options) {
|
|
|
2343
2456
|
}));
|
|
2344
2457
|
}
|
|
2345
2458
|
if (endpoint.authMode === 'public' && steps.some((n)=>(0,_flow_types_js__rspack_import_5/* .isMessageNode */.SE)(n.type))) warnOnce((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_7/* .FLOW_VALIDATION_MESSAGES.PUBLIC_MESSAGE */.qj.PUBLIC_MESSAGE));
|
|
2459
|
+
for (const n of steps){
|
|
2460
|
+
if (n.config?.['fromRequest'] !== true) continue;
|
|
2461
|
+
if (n.type === 'entity_query' && endpoint.contract !== 'get_all' && endpoint.contract !== 'get_by_ids') warnOnce((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_7/* .FLOW_VALIDATION_MESSAGES.NODE_QUERY_NOT_GET_ALL */.qj.NODE_QUERY_NOT_GET_ALL, {
|
|
2462
|
+
node: (0,_flow_types_js__rspack_import_5/* .nodeLabel */.dA)(n),
|
|
2463
|
+
endpoint: label
|
|
2464
|
+
}));
|
|
2465
|
+
if (n.type === 'entity_get' && endpoint.contract !== 'get_by_id') warnOnce((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_7/* .FLOW_VALIDATION_MESSAGES.NODE_GET_NOT_GET_BY_ID */.qj.NODE_GET_NOT_GET_BY_ID, {
|
|
2466
|
+
node: (0,_flow_types_js__rspack_import_5/* .nodeLabel */.dA)(n),
|
|
2467
|
+
endpoint: label
|
|
2468
|
+
}));
|
|
2469
|
+
}
|
|
2346
2470
|
// A URL callers reach without signing in has no user: user checks deny them, and its record steps are open to anyone who can call it.
|
|
2347
2471
|
if (!_flow_types_js__rspack_import_5/* .KEYLESS_AUTH_MODES.has */.d7.has(endpoint.authMode)) continue;
|
|
2348
2472
|
if (steps.some((n)=>(n.type === 'permission_check' || n.type === 'company_branch_check') && n.config?.['subject'] !== 'user' || usesPermissionFunction(n.config))) warnOnce((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_7/* .FLOW_VALIDATION_MESSAGES.PERMISSION_WITHOUT_USER */.qj.PERMISSION_WITHOUT_USER));
|
|
@@ -2624,6 +2748,10 @@ function validateNodeConfig(node, flow, context, err, warn) {
|
|
|
2624
2748
|
template: {
|
|
2625
2749
|
list: _config_message_keys_js__rspack_import_7/* .FLOW_SUBJECT_MESSAGES.TEMPLATE_VALUES */.bc.TEMPLATE_VALUES,
|
|
2626
2750
|
item: _config_message_keys_js__rspack_import_7/* .FLOW_SUBJECT_MESSAGES.TEMPLATE_VALUE */.bc.TEMPLATE_VALUE
|
|
2751
|
+
},
|
|
2752
|
+
messageVariable: {
|
|
2753
|
+
list: _config_message_keys_js__rspack_import_7/* .FLOW_SUBJECT_MESSAGES.MESSAGE_VARIABLES */.bc.MESSAGE_VARIABLES,
|
|
2754
|
+
item: _config_message_keys_js__rspack_import_7/* .FLOW_SUBJECT_MESSAGES.MESSAGE_VARIABLE */.bc.MESSAGE_VARIABLE
|
|
2627
2755
|
}
|
|
2628
2756
|
};
|
|
2629
2757
|
const optionalExpr = (value, what)=>{
|
|
@@ -2665,10 +2793,24 @@ function validateNodeConfig(node, flow, context, err, warn) {
|
|
|
2665
2793
|
else if (c.apiKey !== undefined && !(0,_flow_api_key_js__rspack_import_6/* .looksLikeApiKey */.Jb)(c.apiKey) && !(0,_flow_types_js__rspack_import_5/* .isStoredApiKey */.xA)(c.apiKey)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_7/* .FLOW_VALIDATION_MESSAGES.TRIGGER_API_KEY_INVALID */.qj.TRIGGER_API_KEY_INVALID, at));
|
|
2666
2794
|
// Field errors are named after the URL (`<path>: <field>`) once a flow has several.
|
|
2667
2795
|
const path = (0,_flow_types_js__rspack_import_5/* .triggerPath */.um)(node);
|
|
2796
|
+
const prefix = path ? `${path}: ` : '';
|
|
2668
2797
|
if (c.bodyType !== undefined && !_flow_types_js__rspack_import_5/* .FLOW_BODY_TYPES.includes */.Y3.includes(c.bodyType)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_7/* .FLOW_VALIDATION_MESSAGES.BODY_TYPE_UNKNOWN */.qj.BODY_TYPE_UNKNOWN, {
|
|
2669
2798
|
type: String(c.bodyType)
|
|
2670
2799
|
}));
|
|
2671
|
-
|
|
2800
|
+
const declared = Array.isArray(c.inputSchema) ? c.inputSchema : [];
|
|
2801
|
+
if (c.contract !== undefined && !_flow_types_js__rspack_import_5/* .FLOW_REQUEST_CONTRACTS.includes */.j_.includes(c.contract)) {
|
|
2802
|
+
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_7/* .FLOW_VALIDATION_MESSAGES.TRIGGER_CONTRACT_INVALID */.qj.TRIGGER_CONTRACT_INVALID, {
|
|
2803
|
+
...at,
|
|
2804
|
+
contract: String(c.contract)
|
|
2805
|
+
}));
|
|
2806
|
+
} else {
|
|
2807
|
+
// A declared field may not take the name of one the request type already brings.
|
|
2808
|
+
const reserved = new Set((0,_flow_types_js__rspack_import_5/* .contractFields */._h)(c.contract ?? 'custom').map((f)=>f.name));
|
|
2809
|
+
for (const field of declared)if (reserved.has(field?.name)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_7/* .FLOW_VALIDATION_MESSAGES.INPUT_NAME_RESERVED */.qj.INPUT_NAME_RESERVED, {
|
|
2810
|
+
name: `${prefix}${field.name}`
|
|
2811
|
+
}));
|
|
2812
|
+
}
|
|
2813
|
+
validateInputFields(declared, prefix, 1, err);
|
|
2672
2814
|
break;
|
|
2673
2815
|
}
|
|
2674
2816
|
case 'validate':
|
|
@@ -2809,6 +2951,7 @@ function validateNodeConfig(node, flow, context, err, warn) {
|
|
|
2809
2951
|
case 'entity_get':
|
|
2810
2952
|
entity(c.entityCode);
|
|
2811
2953
|
expr(c.id, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_7/* .FLOW_SUBJECT_MESSAGES.THE_RECORD_ID */.bc.THE_RECORD_ID));
|
|
2954
|
+
if (c.fromRequest !== undefined && typeof c.fromRequest !== 'boolean') err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_7/* .FLOW_VALIDATION_MESSAGES.NODE_QUERY_FROM_REQUEST_INVALID */.qj.NODE_QUERY_FROM_REQUEST_INVALID, at));
|
|
2812
2955
|
break;
|
|
2813
2956
|
case 'entity_query':
|
|
2814
2957
|
entity(c.entityCode);
|
|
@@ -2824,6 +2967,7 @@ function validateNodeConfig(node, flow, context, err, warn) {
|
|
|
2824
2967
|
max: _flow_types_js__rspack_import_5/* .FLOW_LIMITS.MAX_QUERY_LIMIT */.Or.MAX_QUERY_LIMIT
|
|
2825
2968
|
}));
|
|
2826
2969
|
}
|
|
2970
|
+
if (c.fromRequest !== undefined && typeof c.fromRequest !== 'boolean') err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_7/* .FLOW_VALIDATION_MESSAGES.NODE_QUERY_FROM_REQUEST_INVALID */.qj.NODE_QUERY_FROM_REQUEST_INVALID, at));
|
|
2827
2971
|
break;
|
|
2828
2972
|
case 'call_flow':
|
|
2829
2973
|
if (typeof c.flowSlug !== 'string' || !_flow_types_js__rspack_import_5/* .FLOW_SLUG_PATTERN.test */.YD.test(c.flowSlug)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_7/* .FLOW_VALIDATION_MESSAGES.NODE_CHOOSE_FLOW */.qj.NODE_CHOOSE_FLOW, at));
|
|
@@ -2909,8 +3053,28 @@ function validateNodeConfig(node, flow, context, err, warn) {
|
|
|
2909
3053
|
{
|
|
2910
3054
|
const status = c.statusCode;
|
|
2911
3055
|
if (!(Number.isInteger(status) && status >= 200 && status <= 599)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_7/* .FLOW_VALIDATION_MESSAGES.NODE_STATUS_2XX_5XX */.qj.NODE_STATUS_2XX_5XX, at));
|
|
2912
|
-
|
|
2913
|
-
if (
|
|
3056
|
+
const format = c.format ?? 'raw';
|
|
3057
|
+
if (!_flow_types_js__rspack_import_5/* .FLOW_RESPONSE_FORMATS.includes */.A4.includes(format)) {
|
|
3058
|
+
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_7/* .FLOW_VALIDATION_MESSAGES.NODE_RESPOND_FORMAT_INVALID */.qj.NODE_RESPOND_FORMAT_INVALID, {
|
|
3059
|
+
...at,
|
|
3060
|
+
format: String(format)
|
|
3061
|
+
}));
|
|
3062
|
+
break;
|
|
3063
|
+
}
|
|
3064
|
+
const what = (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(format === 'raw' ? _config_message_keys_js__rspack_import_7/* .FLOW_SUBJECT_MESSAGES.THE_RESPONSE */.bc.THE_RESPONSE : _config_message_keys_js__rspack_import_7/* .FLOW_SUBJECT_MESSAGES.THE_DATA */.bc.THE_DATA);
|
|
3065
|
+
if (format !== 'message') {
|
|
3066
|
+
exprMap(c.body, KIND.response);
|
|
3067
|
+
if (c.bodyExpression !== undefined) expr(c.bodyExpression, what);
|
|
3068
|
+
}
|
|
3069
|
+
if (format === 'raw') break;
|
|
3070
|
+
if (typeof c.message !== 'string' || !c.message.trim() || typeof c.messageKey !== 'string' || !c.messageKey.trim()) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_7/* .FLOW_VALIDATION_MESSAGES.NODE_RESPOND_MESSAGE_REQUIRED */.qj.NODE_RESPOND_MESSAGE_REQUIRED, at));
|
|
3071
|
+
exprMap(c.messageVariables, KIND.messageVariable);
|
|
3072
|
+
if ((format === 'list' || format === 'bulk') && c.bodyExpression === undefined) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_7/* .FLOW_VALIDATION_MESSAGES.NODE_RESPOND_LIST_VALUE_REQUIRED */.qj.NODE_RESPOND_LIST_VALUE_REQUIRED, at));
|
|
3073
|
+
if (format === 'list' || format === 'bulk') optionalExpr(c.total, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_7/* .FLOW_SUBJECT_MESSAGES.THE_TOTAL */.bc.THE_TOTAL));
|
|
3074
|
+
if (format === 'list') {
|
|
3075
|
+
optionalExpr(c.page, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_7/* .FLOW_SUBJECT_MESSAGES.THE_PAGE */.bc.THE_PAGE));
|
|
3076
|
+
optionalExpr(c.pageSize, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_7/* .FLOW_SUBJECT_MESSAGES.THE_PAGE_SIZE */.bc.THE_PAGE_SIZE));
|
|
3077
|
+
}
|
|
2914
3078
|
break;
|
|
2915
3079
|
}
|
|
2916
3080
|
case 'commit':
|
|
@@ -3369,26 +3533,28 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
3369
3533
|
},
|
|
3370
3534
|
6390(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
3371
3535
|
/* import */ var _flusys_nestjs_shared_utils__rspack_import_0 = __webpack_require__(9216);
|
|
3372
|
-
/* import */ var
|
|
3373
|
-
/* import */ var
|
|
3536
|
+
/* import */ var _config_message_keys_js__rspack_import_4 = __webpack_require__(5732);
|
|
3537
|
+
/* import */ var _enums_field_type_enum_js__rspack_import_3 = __webpack_require__(9614);
|
|
3374
3538
|
/* import */ var _services_field_value_validator_js__rspack_import_1 = __webpack_require__(3525);
|
|
3539
|
+
/* import */ var _flow_types_js__rspack_import_2 = __webpack_require__(6256);
|
|
3540
|
+
|
|
3375
3541
|
|
|
3376
3542
|
|
|
3377
3543
|
|
|
3378
3544
|
|
|
3379
3545
|
const TYPE_MAP = {
|
|
3380
|
-
string:
|
|
3381
|
-
text:
|
|
3382
|
-
number:
|
|
3383
|
-
integer:
|
|
3384
|
-
boolean:
|
|
3385
|
-
date:
|
|
3386
|
-
datetime:
|
|
3387
|
-
email:
|
|
3388
|
-
uuid:
|
|
3389
|
-
object:
|
|
3390
|
-
array:
|
|
3391
|
-
choice:
|
|
3546
|
+
string: _enums_field_type_enum_js__rspack_import_3/* .FieldType.TEXT */.P.TEXT,
|
|
3547
|
+
text: _enums_field_type_enum_js__rspack_import_3/* .FieldType.LONG_TEXT */.P.LONG_TEXT,
|
|
3548
|
+
number: _enums_field_type_enum_js__rspack_import_3/* .FieldType.DECIMAL */.P.DECIMAL,
|
|
3549
|
+
integer: _enums_field_type_enum_js__rspack_import_3/* .FieldType.INTEGER */.P.INTEGER,
|
|
3550
|
+
boolean: _enums_field_type_enum_js__rspack_import_3/* .FieldType.BOOLEAN */.P.BOOLEAN,
|
|
3551
|
+
date: _enums_field_type_enum_js__rspack_import_3/* .FieldType.DATE */.P.DATE,
|
|
3552
|
+
datetime: _enums_field_type_enum_js__rspack_import_3/* .FieldType.DATETIME */.P.DATETIME,
|
|
3553
|
+
email: _enums_field_type_enum_js__rspack_import_3/* .FieldType.EMAIL */.P.EMAIL,
|
|
3554
|
+
uuid: _enums_field_type_enum_js__rspack_import_3/* .FieldType.RELATION */.P.RELATION,
|
|
3555
|
+
object: _enums_field_type_enum_js__rspack_import_3/* .FieldType.JSON */.P.JSON,
|
|
3556
|
+
array: _enums_field_type_enum_js__rspack_import_3/* .FieldType.JSON */.P.JSON,
|
|
3557
|
+
choice: _enums_field_type_enum_js__rspack_import_3/* .FieldType.SINGLE_SELECT */.P.SINGLE_SELECT
|
|
3392
3558
|
};
|
|
3393
3559
|
const isPlainObject = (v)=>typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
3394
3560
|
/**
|
|
@@ -3407,13 +3573,89 @@ const isPlainObject = (v)=>typeof v === 'object' && v !== null && !Array.isArray
|
|
|
3407
3573
|
};
|
|
3408
3574
|
return checkFields(schema, source, '');
|
|
3409
3575
|
}
|
|
3576
|
+
const FIELD_NAME = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
3577
|
+
const OPEN_CONTRACTS = new Set([
|
|
3578
|
+
'update',
|
|
3579
|
+
'update_many'
|
|
3580
|
+
]);
|
|
3581
|
+
const QUERY_CONTRACTS = new Set([
|
|
3582
|
+
'get_all',
|
|
3583
|
+
'get_by_id',
|
|
3584
|
+
'get_by_ids'
|
|
3585
|
+
]);
|
|
3586
|
+
/**
|
|
3587
|
+
* Checks a request body against a Request step, the way its API controller endpoint's DTO would: a
|
|
3588
|
+
* delete `id` sent as one id is read as a list and a get_by_ids `select` may be comma-separated; `sort`
|
|
3589
|
+
* values must be ASC / DESC and `select` names plain field names. An update / update_many with no
|
|
3590
|
+
* declared fields keeps the rest of the body, with only its `id` checked.
|
|
3591
|
+
*/ function validateEndpointInput(endpoint, body) {
|
|
3592
|
+
const { contract } = endpoint;
|
|
3593
|
+
const source = normalizeBody(contract, body);
|
|
3594
|
+
const result = validateFlowInput(endpoint.inputSchema, source, endpoint.bodyType);
|
|
3595
|
+
if (OPEN_CONTRACTS.has(contract) && endpoint.inputSchema.length === (0,_flow_types_js__rspack_import_2/* .contractFields */._h)(contract).length) result.values = keepRest(source, result.values);
|
|
3596
|
+
if (QUERY_CONTRACTS.has(contract) && !Array.isArray(result.values)) result.errors.push(...contractErrors(result.values));
|
|
3597
|
+
return result;
|
|
3598
|
+
}
|
|
3599
|
+
function normalizeBody(contract, body) {
|
|
3600
|
+
if (!isPlainObject(body)) return body;
|
|
3601
|
+
const source = body;
|
|
3602
|
+
if (contract === 'delete' && typeof source['id'] === 'string') return {
|
|
3603
|
+
...source,
|
|
3604
|
+
id: [
|
|
3605
|
+
source['id']
|
|
3606
|
+
]
|
|
3607
|
+
};
|
|
3608
|
+
if (contract === 'get_by_ids' && typeof source['select'] === 'string') {
|
|
3609
|
+
return {
|
|
3610
|
+
...source,
|
|
3611
|
+
select: source['select'].split(',').map((name)=>name.trim()).filter(Boolean)
|
|
3612
|
+
};
|
|
3613
|
+
}
|
|
3614
|
+
return body;
|
|
3615
|
+
}
|
|
3616
|
+
function keepRest(source, values) {
|
|
3617
|
+
if (Array.isArray(values)) return values.map((item, i)=>isPlainObject(item) && Array.isArray(source) && isPlainObject(source[i]) ? {
|
|
3618
|
+
...source[i],
|
|
3619
|
+
...item
|
|
3620
|
+
} : item);
|
|
3621
|
+
return isPlainObject(source) ? {
|
|
3622
|
+
...source,
|
|
3623
|
+
...values
|
|
3624
|
+
} : values;
|
|
3625
|
+
}
|
|
3626
|
+
function contractErrors(values) {
|
|
3627
|
+
const errors = [];
|
|
3628
|
+
const sort = values['sort'];
|
|
3629
|
+
if (isPlainObject(sort)) {
|
|
3630
|
+
for (const [field, direction] of Object.entries(sort)){
|
|
3631
|
+
if (!FIELD_NAME.test(field) || direction !== 'ASC' && direction !== 'DESC') errors.push({
|
|
3632
|
+
field: `sort.${field}`,
|
|
3633
|
+
...(0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_4/* .FLOW_MESSAGES.INPUT_SORT_INVALID */.wu.INPUT_SORT_INVALID, {
|
|
3634
|
+
field
|
|
3635
|
+
})
|
|
3636
|
+
});
|
|
3637
|
+
}
|
|
3638
|
+
}
|
|
3639
|
+
const select = values['select'];
|
|
3640
|
+
if (Array.isArray(select)) {
|
|
3641
|
+
select.forEach((field, i)=>{
|
|
3642
|
+
if (typeof field !== 'string' || !FIELD_NAME.test(field)) errors.push({
|
|
3643
|
+
field: `select[${i}]`,
|
|
3644
|
+
...(0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_4/* .FLOW_MESSAGES.INPUT_SELECT_INVALID */.wu.INPUT_SELECT_INVALID, {
|
|
3645
|
+
field: String(field)
|
|
3646
|
+
})
|
|
3647
|
+
});
|
|
3648
|
+
});
|
|
3649
|
+
}
|
|
3650
|
+
return errors;
|
|
3651
|
+
}
|
|
3410
3652
|
function checkList(schema, body) {
|
|
3411
3653
|
if (!Array.isArray(body)) return {
|
|
3412
3654
|
values: [],
|
|
3413
3655
|
errors: [
|
|
3414
3656
|
{
|
|
3415
3657
|
field: 'body',
|
|
3416
|
-
...(0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
3658
|
+
...(0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_4/* .FLOW_MESSAGES.INPUT_BODY_NOT_LIST */.wu.INPUT_BODY_NOT_LIST)
|
|
3417
3659
|
}
|
|
3418
3660
|
]
|
|
3419
3661
|
};
|
|
@@ -3428,7 +3670,7 @@ function checkList(schema, body) {
|
|
|
3428
3670
|
values.push(item);
|
|
3429
3671
|
errors.push({
|
|
3430
3672
|
field: `[${i}]`,
|
|
3431
|
-
...(0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
3673
|
+
...(0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_4/* .FLOW_MESSAGES.INPUT_BODY_ITEM_NOT_OBJECT */.wu.INPUT_BODY_ITEM_NOT_OBJECT, {
|
|
3432
3674
|
index: i + 1
|
|
3433
3675
|
})
|
|
3434
3676
|
});
|
|
@@ -3448,7 +3690,7 @@ function toValidatable(field, code, label) {
|
|
|
3448
3690
|
return {
|
|
3449
3691
|
code,
|
|
3450
3692
|
label,
|
|
3451
|
-
fieldType: TYPE_MAP[field.type] ??
|
|
3693
|
+
fieldType: TYPE_MAP[field.type] ?? _enums_field_type_enum_js__rspack_import_3/* .FieldType.TEXT */.P.TEXT,
|
|
3452
3694
|
nullable: !field.required,
|
|
3453
3695
|
defaultValue: field.default ?? null,
|
|
3454
3696
|
selectOptions: field.type === 'choice' ? field.options ?? [] : null,
|
|
@@ -3503,7 +3745,7 @@ function checkValue(field, supplied, raw, path, label) {
|
|
|
3503
3745
|
errors: [
|
|
3504
3746
|
{
|
|
3505
3747
|
field: path,
|
|
3506
|
-
...(0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
3748
|
+
...(0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_4/* .FIELD_VALIDATION_MESSAGES.MUST_BE_OBJECT */.KE.MUST_BE_OBJECT, {
|
|
3507
3749
|
label
|
|
3508
3750
|
})
|
|
3509
3751
|
}
|
|
@@ -3528,7 +3770,7 @@ function checkValue(field, supplied, raw, path, label) {
|
|
|
3528
3770
|
errors: [
|
|
3529
3771
|
{
|
|
3530
3772
|
field: path,
|
|
3531
|
-
...(0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
3773
|
+
...(0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_4/* .FIELD_VALIDATION_MESSAGES.MUST_BE_LIST */.KE.MUST_BE_LIST, {
|
|
3532
3774
|
label
|
|
3533
3775
|
})
|
|
3534
3776
|
}
|
|
@@ -3561,7 +3803,7 @@ function checkValue(field, supplied, raw, path, label) {
|
|
|
3561
3803
|
}
|
|
3562
3804
|
|
|
3563
3805
|
__webpack_require__.d(__webpack_exports__, {
|
|
3564
|
-
|
|
3806
|
+
G: () => (validateEndpointInput)
|
|
3565
3807
|
});
|
|
3566
3808
|
|
|
3567
3809
|
|
|
@@ -4070,7 +4312,12 @@ class EntityBuilderDataSourceProvider extends _flusys_nestjs_shared_modules__rsp
|
|
|
4070
4312
|
// buildMetadatas() is `protected` in TypeORM's public .d.ts (a compile-time-only
|
|
4071
4313
|
// restriction, not enforced by the JS runtime) but is the only way to rebuild
|
|
4072
4314
|
// entityMetadatas from options.entities after DataSource.initialize() has run.
|
|
4073
|
-
|
|
4315
|
+
try {
|
|
4316
|
+
await dataSource.buildMetadatas();
|
|
4317
|
+
} catch (error) {
|
|
4318
|
+
if (perDsMap.get(schema.options.name) === schema) perDsMap.delete(schema.options.name);
|
|
4319
|
+
throw error;
|
|
4320
|
+
}
|
|
4074
4321
|
});
|
|
4075
4322
|
this.statics.rebuildLocks.set(dataSource, next.catch(()=>undefined));
|
|
4076
4323
|
await next;
|
|
@@ -4414,6 +4661,7 @@ function _ts_param(paramIndex, decorator) {
|
|
|
4414
4661
|
|
|
4415
4662
|
const defaultFlowPermissionCode = (slug)=>`entity_builder.flow.${slug}.execute`;
|
|
4416
4663
|
/** The rule a `permission` URL asks callers to pass: its own, or the flow's execute permission. */ const flowPermissions = (endpoint, slug)=>endpoint.permissions ?? (0,_flow_engine_flow_permission_logic_js__rspack_import_13/* .permissionAction */.s)(defaultFlowPermissionCode(slug));
|
|
4664
|
+
/** A `permission` URL without a rule of its own: it asks for the flow's execute permission, which publishing registers. */ const asksExecutePermission = (endpoint)=>endpoint.authMode === 'permission' && !endpoint.permissions;
|
|
4417
4665
|
const flowNotFound = ()=>new _nestjs_common__rspack_import_4.NotFoundException({
|
|
4418
4666
|
message: 'Flow not found.',
|
|
4419
4667
|
messageKey: _config_message_keys_js__rspack_import_14/* .FLOW_MESSAGES.NOT_FOUND */.wu.NOT_FOUND
|
|
@@ -4722,7 +4970,7 @@ class FlowDefinitionService extends _flusys_nestjs_shared_classes__rspack_import
|
|
|
4722
4970
|
} finally{
|
|
4723
4971
|
await qr.release().catch(()=>undefined);
|
|
4724
4972
|
}
|
|
4725
|
-
await this.
|
|
4973
|
+
await this.invalidateCache();
|
|
4726
4974
|
await this.provisionPermissions([
|
|
4727
4975
|
existing
|
|
4728
4976
|
]);
|
|
@@ -4788,18 +5036,9 @@ class FlowDefinitionService extends _flusys_nestjs_shared_classes__rspack_import
|
|
|
4788
5036
|
draft: flow.draft,
|
|
4789
5037
|
updatedById: user?.id ?? null
|
|
4790
5038
|
});
|
|
4791
|
-
await this.
|
|
5039
|
+
await this.invalidateCache();
|
|
4792
5040
|
return flow;
|
|
4793
5041
|
}
|
|
4794
|
-
async clearCaches(flow) {
|
|
4795
|
-
if (!this.isCacheable) return;
|
|
4796
|
-
await Promise.all([
|
|
4797
|
-
this.clearCacheForAll(),
|
|
4798
|
-
this.clearCacheForId([
|
|
4799
|
-
flow
|
|
4800
|
-
])
|
|
4801
|
-
]);
|
|
4802
|
-
}
|
|
4803
5042
|
async beforeDeleteOperation(dto, user, _qr) {
|
|
4804
5043
|
const ids = Array.isArray(dto.id) ? dto.id : [
|
|
4805
5044
|
dto.id
|
|
@@ -4819,7 +5058,7 @@ class FlowDefinitionService extends _flusys_nestjs_shared_classes__rspack_import
|
|
|
4819
5058
|
const actions = new Map();
|
|
4820
5059
|
for (const flow of flows){
|
|
4821
5060
|
for (const endpoint of (0,_flow_engine_flow_types_js__rspack_import_11/* .flowEndpoints */.Xr)(flow)){
|
|
4822
|
-
if (endpoint
|
|
5061
|
+
if (!asksExecutePermission(endpoint)) continue;
|
|
4823
5062
|
const code = defaultFlowPermissionCode(flow.slug);
|
|
4824
5063
|
if (!actions.has(code)) actions.set(code, endpoint.path ? `Run ${flow.name} (${endpoint.path})` : `Run ${flow.name}`);
|
|
4825
5064
|
}
|
|
@@ -4891,6 +5130,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
4891
5130
|
Er: defaultFlowPermissionCode,
|
|
4892
5131
|
HF: isPublished,
|
|
4893
5132
|
YW: flowNotFound,
|
|
5133
|
+
b$: asksExecutePermission,
|
|
4894
5134
|
j4: flowPermissions,
|
|
4895
5135
|
lw: workingCopy
|
|
4896
5136
|
});
|
|
@@ -5187,7 +5427,7 @@ class FlowUrlError extends flow_errors/* .FlowKeyedError */.Hp {
|
|
|
5187
5427
|
}
|
|
5188
5428
|
if (url.protocol !== 'http:' && url.protocol !== 'https:') throw new FlowUrlError(message_keys/* .FLOW_ERROR_MESSAGES.URL_PROTOCOL */.zr.URL_PROTOCOL);
|
|
5189
5429
|
if (url.username || url.password) throw new FlowUrlError(message_keys/* .FLOW_ERROR_MESSAGES.URL_CREDENTIALS */.zr.URL_CREDENTIALS);
|
|
5190
|
-
const host = url.hostname.replace(/^\[|\]$/g, '');
|
|
5430
|
+
const host = url.hostname.replace(/^\[|\]$/g, '').replace(/\.+$/, '');
|
|
5191
5431
|
if (!allowPrivate) {
|
|
5192
5432
|
if (host === 'localhost' || host.endsWith('.localhost') || host.endsWith('.internal') || host.endsWith('.local')) {
|
|
5193
5433
|
throw new FlowUrlError(message_keys/* .FLOW_ERROR_MESSAGES.URL_PRIVATE */.zr.URL_PRIVATE);
|
|
@@ -5560,7 +5800,7 @@ class FlowExecutorService {
|
|
|
5560
5800
|
}, `Flow '${slug}' has no URL '${endpoint ?? ''}'.`);
|
|
5561
5801
|
}
|
|
5562
5802
|
await this.assertMayCall(flow, start, parent, env);
|
|
5563
|
-
const checked = (0,flow_input_validator/* .
|
|
5803
|
+
const checked = (0,flow_input_validator/* .validateEndpointInput */.G)(start, input);
|
|
5564
5804
|
if (checked.errors.length) {
|
|
5565
5805
|
throw new flow_errors/* .FlowHttpError */.hk(400, 'Validation failed', checked.errors, {
|
|
5566
5806
|
messageKey: message_keys/* .FLOW_MESSAGES.INPUT_INVALID */.wu.INPUT_INVALID,
|
|
@@ -5802,16 +6042,17 @@ FlowExecutorService = _ts_decorate([
|
|
|
5802
6042
|
|
|
5803
6043
|
},
|
|
5804
6044
|
2300(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
5805
|
-
/* import */ var
|
|
5806
|
-
/* import */ var
|
|
5807
|
-
/* import */ var
|
|
5808
|
-
/* import */ var
|
|
5809
|
-
/* import */ var
|
|
5810
|
-
/* import */ var
|
|
5811
|
-
/* import */ var
|
|
5812
|
-
/* import */ var
|
|
5813
|
-
/* import */ var
|
|
5814
|
-
/* import */ var
|
|
6045
|
+
/* import */ var _flusys_nestjs_shared_utils__rspack_import_0 = __webpack_require__(9216);
|
|
6046
|
+
/* import */ var _nestjs_common__rspack_import_1 = __webpack_require__(6157);
|
|
6047
|
+
/* import */ var typeorm__rspack_import_2 = __webpack_require__(7158);
|
|
6048
|
+
/* import */ var _config_message_keys_js__rspack_import_10 = __webpack_require__(5732);
|
|
6049
|
+
/* import */ var _entities_flow_definition_entity_js__rspack_import_3 = __webpack_require__(3770);
|
|
6050
|
+
/* import */ var _flow_engine_flow_input_validator_js__rspack_import_4 = __webpack_require__(6390);
|
|
6051
|
+
/* import */ var _flow_engine_flow_types_js__rspack_import_5 = __webpack_require__(6256);
|
|
6052
|
+
/* import */ var _entity_builder_datasource_provider_js__rspack_import_6 = __webpack_require__(424);
|
|
6053
|
+
/* import */ var _flow_definition_service_js__rspack_import_7 = __webpack_require__(5229);
|
|
6054
|
+
/* import */ var _flow_execution_service_js__rspack_import_8 = __webpack_require__(7810);
|
|
6055
|
+
/* import */ var _flow_executor_service_js__rspack_import_9 = __webpack_require__(3908);
|
|
5815
6056
|
function _ts_decorate(decorators, target, key, desc) {
|
|
5816
6057
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
5817
6058
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
@@ -5845,6 +6086,7 @@ function _ts_param(paramIndex, decorator) {
|
|
|
5845
6086
|
|
|
5846
6087
|
|
|
5847
6088
|
|
|
6089
|
+
|
|
5848
6090
|
const HIDDEN_HEADERS = new Set([
|
|
5849
6091
|
'authorization',
|
|
5850
6092
|
'cookie',
|
|
@@ -5908,7 +6150,7 @@ const inputRejected = (errors)=>({
|
|
|
5908
6150
|
body: {
|
|
5909
6151
|
success: false,
|
|
5910
6152
|
message: 'Validation failed',
|
|
5911
|
-
messageKey:
|
|
6153
|
+
messageKey: _config_message_keys_js__rspack_import_10/* .FLOW_MESSAGES.INPUT_INVALID */.wu.INPUT_INVALID,
|
|
5912
6154
|
errors
|
|
5913
6155
|
},
|
|
5914
6156
|
trace: [],
|
|
@@ -5926,24 +6168,27 @@ class FlowRuntimeService {
|
|
|
5926
6168
|
this.definitions = definitions;
|
|
5927
6169
|
}
|
|
5928
6170
|
/** A flow never published is not live yet: it looks the same as an unknown one. */ async findActive(slug) {
|
|
5929
|
-
return (await this.provider.getRepository(
|
|
6171
|
+
return (await this.provider.getRepository(_entities_flow_definition_entity_js__rspack_import_3/* .FlowDefinition */.G)).findOne({
|
|
5930
6172
|
where: {
|
|
5931
6173
|
slug,
|
|
5932
6174
|
isActive: true,
|
|
5933
|
-
deletedAt: (0,
|
|
5934
|
-
version: (0,
|
|
6175
|
+
deletedAt: (0,typeorm__rspack_import_2.IsNull)(),
|
|
6176
|
+
version: (0,typeorm__rspack_import_2.MoreThan)(0)
|
|
5935
6177
|
}
|
|
5936
6178
|
});
|
|
5937
6179
|
}
|
|
6180
|
+
/** The tenant of this request ('' for a single database): tenant databases cloned from one template share flow ids. */ tenantScope() {
|
|
6181
|
+
return (0,_flusys_nestjs_shared_utils__rspack_import_0.cacheTenantId)(this.provider) ?? '';
|
|
6182
|
+
}
|
|
5938
6183
|
/** The public entry: a caller hit `POST api-flows/:slug` or `POST api-flows/:slug/:endpoint`. */ async handle(flow, endpoint, body, caller, user) {
|
|
5939
6184
|
const startedAt = new Date();
|
|
5940
|
-
const checked = (0,
|
|
6185
|
+
const checked = (0,_flow_engine_flow_input_validator_js__rspack_import_4/* .validateEndpointInput */.G)(endpoint, body);
|
|
5941
6186
|
if (checked.errors.length) {
|
|
5942
6187
|
const result = inputRejected(checked.errors);
|
|
5943
6188
|
await this.logWebhook(flow, endpoint, body, result, startedAt, user, caller);
|
|
5944
6189
|
return result;
|
|
5945
6190
|
}
|
|
5946
|
-
const result = await this.executor.run((0,
|
|
6191
|
+
const result = await this.executor.run((0,_flow_definition_service_js__rspack_import_7/* .toFlowSettings */.RK)(flow), {
|
|
5947
6192
|
mode: 'live',
|
|
5948
6193
|
user,
|
|
5949
6194
|
input: checked.values,
|
|
@@ -5963,17 +6208,17 @@ class FlowRuntimeService {
|
|
|
5963
6208
|
}
|
|
5964
6209
|
if (dto.definition) {
|
|
5965
6210
|
// The designer's current draft, even for a saved flow: `flow` above is kept only to attribute the run.
|
|
5966
|
-
settings = (0,
|
|
6211
|
+
settings = (0,_flow_definition_service_js__rspack_import_7/* .toFlowSettings */.RK)(dto.definition);
|
|
5967
6212
|
} else if (flow) {
|
|
5968
|
-
settings = (0,
|
|
6213
|
+
settings = (0,_flow_definition_service_js__rspack_import_7/* .toFlowSettings */.RK)(flow);
|
|
5969
6214
|
} else {
|
|
5970
|
-
throw new
|
|
6215
|
+
throw new _nestjs_common__rspack_import_1.BadRequestException({
|
|
5971
6216
|
message: 'Send a flowId or a definition to test.',
|
|
5972
|
-
messageKey:
|
|
6217
|
+
messageKey: _config_message_keys_js__rspack_import_10/* .FLOW_MESSAGES.NOTHING_TO_TEST */.wu.NOTHING_TO_TEST
|
|
5973
6218
|
});
|
|
5974
6219
|
}
|
|
5975
6220
|
const mode = dto.mode ?? 'dry_run';
|
|
5976
|
-
const endpoint = (0,
|
|
6221
|
+
const endpoint = (0,_flow_engine_flow_types_js__rspack_import_5/* .findEndpoint */.vS)(settings, dto.endpoint);
|
|
5977
6222
|
// Checked before anything runs.
|
|
5978
6223
|
await this.definitions.assertMayTest(settings, endpoint, user, {
|
|
5979
6224
|
mode,
|
|
@@ -5981,9 +6226,9 @@ class FlowRuntimeService {
|
|
|
5981
6226
|
saved: !!flow
|
|
5982
6227
|
});
|
|
5983
6228
|
if (!endpoint) {
|
|
5984
|
-
throw new
|
|
6229
|
+
throw new _nestjs_common__rspack_import_1.BadRequestException({
|
|
5985
6230
|
message: `This flow has no URL '${dto.endpoint ?? ''}'.`,
|
|
5986
|
-
messageKey:
|
|
6231
|
+
messageKey: _config_message_keys_js__rspack_import_10/* .FLOW_MESSAGES.ENDPOINT_NOT_FOUND */.wu.ENDPOINT_NOT_FOUND,
|
|
5987
6232
|
messageVariables: {
|
|
5988
6233
|
endpoint: dto.endpoint ?? ''
|
|
5989
6234
|
}
|
|
@@ -5991,9 +6236,9 @@ class FlowRuntimeService {
|
|
|
5991
6236
|
}
|
|
5992
6237
|
const validation = await this.definitions.validate(settings);
|
|
5993
6238
|
if (validation.errors.length) {
|
|
5994
|
-
throw new
|
|
6239
|
+
throw new _nestjs_common__rspack_import_1.BadRequestException({
|
|
5995
6240
|
message: 'The flow has problems.',
|
|
5996
|
-
messageKey:
|
|
6241
|
+
messageKey: _config_message_keys_js__rspack_import_10/* .FLOW_MESSAGES.INVALID */.wu.INVALID,
|
|
5997
6242
|
errors: validation.errors.map((error)=>({
|
|
5998
6243
|
field: 'flow',
|
|
5999
6244
|
...error
|
|
@@ -6003,7 +6248,7 @@ class FlowRuntimeService {
|
|
|
6003
6248
|
const startedAt = new Date();
|
|
6004
6249
|
const simulated = simulatedCaller(caller, dto.request);
|
|
6005
6250
|
const body = dto.input ?? (endpoint.bodyType === 'list' ? [] : {});
|
|
6006
|
-
const checked = (0,
|
|
6251
|
+
const checked = (0,_flow_engine_flow_input_validator_js__rspack_import_4/* .validateEndpointInput */.G)(endpoint, body);
|
|
6007
6252
|
const result = checked.errors.length ? inputRejected(checked.errors) : await this.executor.run(settings, {
|
|
6008
6253
|
mode,
|
|
6009
6254
|
user,
|
|
@@ -6050,19 +6295,19 @@ class FlowRuntimeService {
|
|
|
6050
6295
|
}
|
|
6051
6296
|
}
|
|
6052
6297
|
FlowRuntimeService = _ts_decorate([
|
|
6053
|
-
(0,
|
|
6054
|
-
scope:
|
|
6298
|
+
(0,_nestjs_common__rspack_import_1.Injectable)({
|
|
6299
|
+
scope: _nestjs_common__rspack_import_1.Scope.REQUEST
|
|
6055
6300
|
}),
|
|
6056
|
-
_ts_param(0, (0,
|
|
6057
|
-
_ts_param(1, (0,
|
|
6058
|
-
_ts_param(2, (0,
|
|
6059
|
-
_ts_param(3, (0,
|
|
6301
|
+
_ts_param(0, (0,_nestjs_common__rspack_import_1.Inject)(_entity_builder_datasource_provider_js__rspack_import_6/* .EntityBuilderDataSourceProvider */.D)),
|
|
6302
|
+
_ts_param(1, (0,_nestjs_common__rspack_import_1.Inject)(_flow_executor_service_js__rspack_import_9/* .FlowExecutorService */.F)),
|
|
6303
|
+
_ts_param(2, (0,_nestjs_common__rspack_import_1.Inject)(_flow_execution_service_js__rspack_import_8/* .FlowExecutionService */.A)),
|
|
6304
|
+
_ts_param(3, (0,_nestjs_common__rspack_import_1.Inject)(_flow_definition_service_js__rspack_import_7/* .FlowDefinitionService */.Tk)),
|
|
6060
6305
|
_ts_metadata("design:type", Function),
|
|
6061
6306
|
_ts_metadata("design:paramtypes", [
|
|
6062
|
-
typeof
|
|
6063
|
-
typeof
|
|
6064
|
-
typeof
|
|
6065
|
-
typeof
|
|
6307
|
+
typeof _entity_builder_datasource_provider_js__rspack_import_6/* .EntityBuilderDataSourceProvider */.D === "undefined" ? Object : _entity_builder_datasource_provider_js__rspack_import_6/* .EntityBuilderDataSourceProvider */.D,
|
|
6308
|
+
typeof _flow_executor_service_js__rspack_import_9/* .FlowExecutorService */.F === "undefined" ? Object : _flow_executor_service_js__rspack_import_9/* .FlowExecutorService */.F,
|
|
6309
|
+
typeof _flow_execution_service_js__rspack_import_8/* .FlowExecutionService */.A === "undefined" ? Object : _flow_execution_service_js__rspack_import_8/* .FlowExecutionService */.A,
|
|
6310
|
+
typeof _flow_definition_service_js__rspack_import_7/* .FlowDefinitionService */.Tk === "undefined" ? Object : _flow_definition_service_js__rspack_import_7/* .FlowDefinitionService */.Tk
|
|
6066
6311
|
])
|
|
6067
6312
|
], FlowRuntimeService);
|
|
6068
6313
|
|
|
@@ -6508,6 +6753,7 @@ const TEXT_FIELD_TYPES = new Set([
|
|
|
6508
6753
|
async getAll(search, query, options = {}) {
|
|
6509
6754
|
const repository = await this.repositoryFor(options.queryRunner);
|
|
6510
6755
|
let builder = repository.createQueryBuilder(this.entityCode);
|
|
6756
|
+
if (query.withDeleted) builder.withDeleted();
|
|
6511
6757
|
if (query.filter) {
|
|
6512
6758
|
builder = this.applyFilter(builder, query.filter);
|
|
6513
6759
|
}
|
|
@@ -6950,6 +7196,23 @@ class SchemaDialectAdapterService {
|
|
|
6950
7196
|
});
|
|
6951
7197
|
}
|
|
6952
7198
|
}
|
|
7199
|
+
/** Takes `lockKey` for the connection's session (it outlives any transaction) without waiting: false when another session holds it. */ async tryAcquireSessionLock(queryRunner, lockKey, driver) {
|
|
7200
|
+
const rows = driver === 'postgres' ? await queryRunner.query('SELECT pg_try_advisory_lock(hashtext($1)) AS acquired', [
|
|
7201
|
+
lockKey
|
|
7202
|
+
]) : await queryRunner.query('SELECT GET_LOCK(?, 0) AS acquired', [
|
|
7203
|
+
this.lockName(lockKey)
|
|
7204
|
+
]);
|
|
7205
|
+
const acquired = rows?.[0]?.acquired;
|
|
7206
|
+
return acquired === true || Number(acquired) === 1;
|
|
7207
|
+
}
|
|
7208
|
+
/** Must run before the connection goes back to the pool, or the lock stays with it. */ async releaseSessionLock(queryRunner, lockKey, driver) {
|
|
7209
|
+
if (driver === 'postgres') await queryRunner.query('SELECT pg_advisory_unlock(hashtext($1))', [
|
|
7210
|
+
lockKey
|
|
7211
|
+
]);
|
|
7212
|
+
else await queryRunner.query('SELECT RELEASE_LOCK(?)', [
|
|
7213
|
+
this.lockName(lockKey)
|
|
7214
|
+
]);
|
|
7215
|
+
}
|
|
6953
7216
|
async releaseEntityLock(queryRunner, lockKey, driver) {
|
|
6954
7217
|
if (driver === 'postgres') {
|
|
6955
7218
|
// pg_advisory_xact_lock is transaction-scoped - released automatically on commit/rollback.
|
|
@@ -7030,7 +7293,10 @@ class SchemaRegistryService {
|
|
|
7030
7293
|
id: entityDefinitionId
|
|
7031
7294
|
}
|
|
7032
7295
|
});
|
|
7296
|
+
const cacheKey = this.cacheKey(entityDefinitionId);
|
|
7033
7297
|
if (!definition) {
|
|
7298
|
+
// Dropped, possibly on another instance: its schema is never asked for again.
|
|
7299
|
+
SchemaRegistryService.cache.delete(cacheKey);
|
|
7034
7300
|
throw new _nestjs_common__rspack_import_1.NotFoundException({
|
|
7035
7301
|
message: `Entity definition '${entityDefinitionId}' not found.`,
|
|
7036
7302
|
messageKey: _config_message_keys_js__rspack_import_8/* .ENTITY_DEFINITION_MESSAGES.NOT_FOUND */.pL.NOT_FOUND,
|
|
@@ -7039,7 +7305,6 @@ class SchemaRegistryService {
|
|
|
7039
7305
|
}
|
|
7040
7306
|
});
|
|
7041
7307
|
}
|
|
7042
|
-
const cacheKey = this.cacheKey(entityDefinitionId);
|
|
7043
7308
|
const cached = SchemaRegistryService.cache.get(cacheKey);
|
|
7044
7309
|
if (cached && cached.version === definition.schemaVersion) {
|
|
7045
7310
|
return cached.schema;
|